JMP

From C64-Wiki
Jump to navigationJump to search

JMP (short for "JuMP") is the mnemonic for a machine language instruction which unconditionally transfers program execution to the specified address. To those familiar with BASIC programming; this is the machine language equivalent to GOTO.

Vectors and indirectly addressed JuMPs[edit]

JMP is the only instruction in the 65xx instruction set which supports the purely indirect addressing mode, and this indirect JMP provides for the use of vectors: While the user has no easy access to modify the contents of either BASIC or KERNAL ROM, both these parts of the system makes ample use of vectors, set in RAM that the user can modify. This allows the user to "divert" parts of BASIC or KERNAL to custom routines.

JMP-ing into a subroutine[edit]

Normally, subroutines are called with a JSR, but consider some routine that prints out a message, e.g. fetched from a table of several messages. After printing all characters of the messages, a carriage return control character is to be printed, before the message routine ends in an RTS. The "standard way" to print the this would be:

LDA #13      Print carriage return
JSR CHROUT   using CHROUT
RTS          Message done -- return to caller.

but since the call to a subroutine (the JSR CHROUT) is immediately followed by an RTS, there is the option of saving a byte and 9 machine cycles by JuMP-ing directly into the subroutine:

LDA #13      Print carriage return
JMP CHROUT   Leave this routine through CHROUT

This will first print out the required character, but when the CPU encounters the "final RTS" at the end of the CHROUT routine, this serves to return from not just CHROUT, but of the entire message-printing routine.

Emulating JMP (addr,X)[edit]

The JMP (addr,X) instruction is present in later 65xx processors (65C02, 65C802/65C816). It behaves like JMP (addr), except it fetches the 16-bit value from addr+X. This is a common way to realize a table-driven jump.
The least-problematic way to implement this is using RTI:

; Jump to address stored at addr+X
LDA addr+1,x ; high byte first
PHA
LDA addr,x
PHA
PHP ; RTI expects processor flags on top
RTI

The RTS version is faster, but slightly more tricky, because it adds one to the address it pulls from the stack. This requires that every entry in the jump table have one subtracted from it. This could be done by the code, but it's tedious because the low byte must be decremented first, while the high byte needs to be pushed first. Thus, it's preferable to simply subtract one from each entry in the assembly source text:

; Jump to address stored at addr+X
LDA table+1,x
PHA
LDA table,x
PHA
RTS
table: .word action0-1, action1-1, action2-1 ; ...

The benefit of the RTS version is that it's three clock cycles faster than the RTI version, due to not having to push the flags. The disadvantage is that you must adjust every table entry by -1.

Addressing modes[edit]

Opcode Addressing
mode
Assembler
format
Length
in bytes
Number of
cycles
Dec Hex
76 4C Absolute JMP nnnn 3 3
108 6C Indirect JMP (nnnn) 3 5

JMP supports 2 different addressing modes, as shown in the table at right. In the assembler formats listed, nnnn is a two-byte (16-bit) address.

CPU flags[edit]

JMP does not affect any of the CPU's status flags.