267. Cpu step returns cycles
Make CPU.step() return base instruction cycles.
Lesson 267 of 356 · tests/chapter_04_ppu_timing_and_vblank/test_267_cpu_step_returns_cycles.py
Reference
https://www.nesdev.org/wiki/Visual6502wiki/6502_all_256_OpcodesFiles to update
emulator/cpu/cpu.pyWhy this step exists
The emulator now has a standalone OPCODE_CYCLES table. The next timing bridge is for CPU.step() to return the base cycle count for the opcode it executed.
This prepares the future Console.step() shape:
cpu_cycles = cpu.step()
ppu.step(cpu_cycles * 3)
console.consume_nmi_if_requested()What is a base instruction cycle count? A base instruction cycle count is the normal number of CPU cycles an opcode takes before dynamic penalties are added.
Minimal examples
NOP implied opcode $EA -> 2 cycles
LDA immediate opcode $A9 -> 2 cycles
JSR absolute opcode $20 -> 6 cyclesCommon misconception
Cycles are not the same as bytes fetched. JSR is 3 bytes but takes 6 cycles. Do not count cycles inside fetch_byte().
Suggested implementation example
from emulator.cpu.opcodes import OPCODE_CYCLES, OPCODE_TABLE
class CPU:
...
def step(self) -> int:
opcode = self.fetch_byte()
handler = OPCODE_TABLE.get(opcode)
if handler is None:
raise NotImplementedError(f"Opcode {opcode:02X} not implemented")
handler(self)
return OPCODE_CYCLES[opcode]Why this avoids a large refactor
OPCODE_TABLE remains the existing opcode -> handler mapping. OPCODE_CYCLES is a parallel metadata table. Old instruction behavior tests should continue to pass because CPU.step() still executes the same handler.
Important limitation
This returns base cycles only. Dynamic timing is intentionally out of scope here:
branch taken penalties
branch page-cross penalties
indexed load page-cross penaltiesThose should be modeled later as a separate step.
Out of scope
- refactoring OPCODE_TABLE into dataclass entries
- adding cycles to fetch_byte()
- Console.step()
- PPU advancement by CPU cycles * 3
- dynamic extra cycles
Run this lesson
uv run pytest tests/chapter_04_ppu_timing_and_vblank/test_267_cpu_step_returns_cycles.py -v