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