184. Instrucción jsr

añadir el comportamiento de JSR independiente del modo de direccionamiento.

Lección 184 de 356 · tests/chapter_01_cpu/test_184_instruction_jsr.py

En este paso, añade `emulator/cpu/instructions.py::jsr`:

Instrucción

JSR -> Jump to Subroutine

Objetivo

implementar jsr(cpu, addr) en instructions.py.

Guía para el estudiante

JSR es como JMP, pero además guarda una dirección de retorno en la pila para que RTS pueda volver más tarde.

Detalles importantes

  • La pila reside en la página $0100.
  • S es solo el byte bajo de la dirección de la pila.
  • Se apila primero el byte alto, luego el byte bajo.
  • S se decrementa después de cada apilamiento.
  • En el momento de jsr(cpu, addr), PC ya apunta a la siguiente instrucción.
  • JSR apila PC - 1 porque RTS incrementa la dirección de retorno desapilada.

Forma de implementación de ejemplo

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

Por qué existe este paso

La decodificación del operando ya ha avanzado PC más allá de JSR, mientras que el protocolo de pila del 6502 almacena un valor menos que la dirección de continuación para un futuro RTS. Invariantes: las escrituras se producen primero el byte alto y luego el bajo en `$0100 | S`; S se decrementa y se envuelve tras cada escritura; PC y la dirección proporcionada son de 16 bits; las flags y el resto de registros se preservan. Concepto erróneo: apilar el PC actual, o apilar primero el byte bajo, produce un marco de retorno incompatible.

Fuera de alcance: no hay importación de opcode, manejador `jsr_absolute, ni entrada en la tabla para $20 hasta el paso 185. rts` no existe hasta el paso 186; explica la convención de PC-menos-uno, pero no debe implementarse aquí.

Ejecutar esta lección

uv run pytest tests/chapter_01_cpu/test_184_instruction_jsr.py -v