184. jsr 指令
添加与寻址方式无关的 JSR 行为。
第 184 / 356 · tests/chapter_01_cpu/test_184_instruction_jsr.py
在本步骤中,向 `emulator/cpu/instructions.py::jsr` 添加以下内容:
指令
JSR -> Jump to Subroutine目标
在 instructions.py 中实现 jsr(cpu, addr)。
学习指引
JSR 与 JMP 类似,但它还会把返回地址保存到栈上,以便 RTS 之后能够返回。
重要细节
- 栈位于 $0100 页。
- S 只是栈地址的低字节。
- 先压入高字节,再压入低字节。
- 每次压栈后 S 递减。
- 在 jsr(cpu, addr) 执行时,PC 已经指向下一条指令。
- JSR 压入的是 PC - 1,因为 RTS 会对取出的返回地址加一。
示例实现结构
return_addr = (cpu.pc - 1) & 0xFFFF
high = (return_addr >> 8) & 0xFF
low = return_addr & 0xFF
cpu.bus.write(0x0100 | cpu.s, high)
cpu.s = (cpu.s - 1) & 0xFF
cpu.bus.write(0x0100 | cpu.s, low)
cpu.s = (cpu.s - 1) & 0xFF
cpu.pc = addr & 0xFFFF本步骤存在的原因
操作数解码已经把 PC 移过了 JSR 本身,而 6502 的栈协议要求存入的地址比未来 RTS 的继续执行地址小 1。不变量:写入顺序为先高字节后低字节,地址为 `$0100 | S`;每次写入后 S 递减并回绕;PC 与传入地址均为 16 位;标志位与其他寄存器保持不变。常见误解:压入当前 PC,或先压入低字节,都会产生与之不兼容的返回帧。
本步骤范围之外:在第 185 步之前,不导入操作码、不添加 `jsr_absolute 处理函数,也不添加 $20 的表项。rts` 直到第 186 步才存在;这里虽然说明了“PC 减一”的约定,但不能在此实现。
运行本课
uv run pytest tests/chapter_01_cpu/test_184_instruction_jsr.py -v