Jumping to subroutines
Last updated
Last updated
What if you want to use the same code twice, but you don't want to write, for example, the exact same 200 lines of codes again? You can turn code into "subroutines" and use jumping opcodes to run these subroutines. There are four jumping opcodes in total.
There's a difference between "subroutine" and "code" in this tutorial, as you'll see in the coming paragraphs.
There are two opcodes which pretty much act like a function call in higher-level programming languages.
These opcodes call a piece of code, then continue executing code below said opcode. Here is an example of the usage of JSR:
This code will store $01 into $7E0001, will store $03 into $7E0000 AND execute the codes at Label1 at the current bank, so it also stores $02 into $7E0002.
JSL has the same purpose as JSR, except it can jump everywhere. Above example can also be applied to JSL, except that the RTS
is now an RTL
.
The opcode JSR will get assembled as JSR $XXXX
by the assembler (because labels get turned into addresses), but you shouldn't worry about that. Furthermore, because JSR uses an absolute address as its parameter, it is limited to its current bank. Changing the data bank register doesn't affect JSR.
The opcode JSL will get assembled as JSL $XXXXXX
, instead.
When you call a subroutine, you also need a way to return back to your original code. For that, there are two return opcodes.
Code called by JSR and JSL should end with RTS and RTL, respectively.
If you'd like to control the code flow rather than doing a function call, you will use regular jumps instead.
What JMP and JML do is jumping to another location and executing the code there, ignoring everything after the JMP/JML opcode. The RTS in Label1 does NOT jump back to LDA #$03. Instead, it just finishes the current subroutine it was in.
JMP is limited to the current bank, like JSR. JML can jump anywhere like JSL. JMPs and JMLs don't have a return instruction, but you can still use an RTS or RTL to return from a JMP/JMP depending on the current situation. Example:
It is good practice to put a blank line after a JMP or JML, so the reader knows that the program flow changes from that point on.
The Data Bank does NOT get updated when you use a JSL or JML. You will have to do that yourself.
Remember how JSL/JML can jump everywhere? They can even jump to RAM, which implies code can be executed in RAM. You can write values to RAM which can be interpreted as code which can be executed.
Opcode
Full name
Explanation
JSR
Jump to subroutine
Jumps to a subroutine using an absolute address
JSL
Jump to subroutine long
Jumps to a subroutine using a long address
Opcode
Full name
Explanation
RTS
Return from subroutine
Returns from a JSR
RTL
Return from subroutine long
Returns from a JSL
Opcode
Full name
Explanation
JMP
Jump
Jumps to code using an absolute address
JML
Jump long
Jumps to code using a long address