184. Инструкция jsr

добавить независимое от режима адресации поведение JSR.

Урок 184 из 356 · tests/chapter_01_cpu/test_184_instruction_jsr.py

На этом шаге добавьте `emulator/cpu/instructions.py::jsr`:

Инструкция

JSR -> Jump to Subroutine

Цель

реализовать jsr(cpu, addr) в instructions.py.

Рекомендации

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. Инварианты: записи выполняются сначала старший, затем младший байт по адресу `$0100 | S`; S уменьшается и оборачивается после каждой записи; PC и переданный адрес — 16-битные; флаги и остальные регистры сохраняются. Заблуждение: запись текущего PC или запись младшего байта первым создаёт несовместимый кадр возврата.

За рамками шага: импорт опкода, обработчик `jsr_absolute и запись $20 в таблице — шаг 185. rts` появляется только на шаге 186; там объясняется соглашение PC-минус-один, но реализовывать её здесь не нужно.

Запустить этот урок

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