185. Jsr absolute
wire JSR absolute opcode $20.
Lesson 185 of 356 · tests/chapter_01_cpu/test_185_JSR_absolute.py
Prerequisite: step 184 added `jsr. In this step, add these changes in emulator/cpu/opcodes.py`:
from emulator.cpu.instructions import jsr
from emulator.cpu.addressing_modes import absolute
def jsr_absolute(cpu: CPU):
addr = absolute(cpu)
jsr(cpu, addr)
OPCODE_TABLE = {
# existing entries...
0x20: jsr_absolute,
}Opcode
0x20 -> JSR $hhhhGoal
create jsr_absolute(cpu), use absolute(cpu), then jsr(cpu, addr).
Student guidance
JSR absolute uses a 16-bit little-endian operand as the subroutine address.
Example
20 34 12 -> JSR $1234Execution steps
1. CPU.step() fetches opcode 0x20.
2. absolute(cpu) fetches operand bytes 34 12 and returns $1234.
3. PC now points to the next instruction, $8003 in these tests.
4. jsr(cpu, $1234) pushes return address $8002.
5. PC becomes $1234.Common mistake
Do not call jmp(cpu, addr). JSR must push the return address first.
Why this step exists
`absolute consumes the two-byte target, leaving PC at the next instruction so jsr` can push PC-minus-one and jump. Invariants: one step consumes opcode plus operand, pushes high then low, decrements S twice, changes PC to the target, and preserves status. Misconception: sharing JMP's addressing mode does not make JSR a plain jump.
Out of scope: `rts` and opcode $60 are steps 186-187. BRK, RTI, and later general stack helpers are not part of this transition.
Run this lesson
uv run pytest tests/chapter_01_cpu/test_185_JSR_absolute.py -v