183. Jmp indirect

подключить опкод JMP indirect $6C.

Урок 183 из 356 · tests/chapter_01_cpu/test_183_JMP_indirect.py

Предусловия: на шаге 180 был добавлен `indirect, а на шаге 181 — jmp. На этом шаге внесите следующие изменения в emulator/cpu/opcodes.py`:

from emulator.cpu.instructions import jmp
from emulator.cpu.addressing_modes import indirect

def jmp_indirect(cpu: CPU):
    addr = indirect(cpu)
    jmp(cpu, addr)

OPCODE_TABLE = {
    # existing entries...
    0x6C: jmp_indirect,
}

Опкод

0x6C -> JMP ($hhhh)

Цель

создать jmp_indirect(cpu), использовать indirect(cpu), затем jmp(cpu, addr).

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

JMP indirect использует операнд как указатель на целевой адрес.

Пример

6C 00 02 means JMP ($0200)

Если

memory[$0200] = $34
memory[$0201] = $12

Тогда

PC = $1234

Важно

indirect(cpu) уже возвращает конечный целевой адрес. Обработчик опкода не должен повторно читать память по этому возвращённому адресу.

Ошибка NES/6502

Если указатель заканчивается на $FF, старший байт оборачивается внутри той же страницы:

JMP ($02FF) reads high byte from $0200, not $0300.

Зачем нужен этот шаг

`addressing_modes.indirect считывает операнд-указатель, разыменовывает его с учётом поведения 6502 на границе страницы и возвращает конечный адрес; jmp затем присваивает его. Инварианты: обработчик не выполняет дополнительного чтения по целевому адресу, сохраняет флаги/регистры/стек/память и отображает только $6C. Заблуждение: значение, возвращённое indirect`, не является ещё одним указателем.

За рамками шага: реализация или изменение `addressing_modes.indirect` относится к шагу 180. JSR начинается с шага 184; RTS и прерывания рассматриваются в последующих шагах.

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

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