Jumping to subroutines
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:
JSR Label1 ; Execute the "subroutine" located at Label1 (current bank)
LDA #$03 ; The RTS in Label1 will return to this line
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
RTSis now an
The opcode JSR will get assembled as
JSR $XXXXby 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.
LDA #$03 ; Ignored
STA $00 ; Ignored
RTS ; Ignored
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:
JSR Label1 ; Jump to subroutine "Label1"
RTS ; Label2 returns here. The code ends here.
JMP Label2 ; Jump to Label2
RTS ; This DOESN'T return to Label1. Instead, it returns to the RTS above.
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.