183. Jmp indirect
wire JMP indirect opcode $6C.
Lesson 183 of 356 · tests/chapter_01_cpu/test_183_JMP_indirect.py
Prerequisites: step 180 added `indirect and step 181 added jmp. In this step, add these changes to 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,
}Opcode
0x6C -> JMP ($hhhh)Goal
create jmp_indirect(cpu), use indirect(cpu), then jmp(cpu, addr).
Student guidance
JMP indirect uses the operand as a pointer to the target address.
Example
6C 00 02 means JMP ($0200)If
memory[$0200] = $34
memory[$0201] = $12Then
PC = $1234Important
indirect(cpu) already returns the final target address. The opcode handler must not read memory again at that returned address.
NES/6502 bug
If the pointer ends in $FF, the high byte wraps inside the same page:
JMP ($02FF) reads high byte from $0200, not $0300.Why this step exists
`addressing_modes.indirect consumes the pointer operand, follows it with the 6502 page-boundary behavior, and returns the final target; jmp then assigns it. Invariants: the handler performs no extra target read, preserves flags/registers/stack/memory, and maps only $6C. Misconception: the value returned by indirect` is not another pointer.
Out of scope: implementing or changing `addressing_modes.indirect` belongs to step 180. JSR starts at step 184; RTS and interrupts are later steps.
Run this lesson
uv run pytest tests/chapter_01_cpu/test_183_JMP_indirect.py -v