267. CPU.step devuelve ciclos
Hacer que CPU.step() devuelva los ciclos base de instrucción.
Lección 267 de 356 · tests/chapter_04_ppu_timing_and_vblank/test_267_cpu_step_returns_cycles.py
Referencia
https://www.nesdev.org/wiki/Visual6502wiki/6502_all_256_OpcodesArchivos a actualizar
emulator/cpu/cpu.pyPor qué existe este paso
El emulador ahora tiene una tabla OPCODE_CYCLES independiente. El siguiente puente de temporización es que CPU.step() devuelva el conteo de ciclos base del opcode que ejecutó.
Esto prepara la forma futura de Console.step():
cpu_cycles = cpu.step()
ppu.step(cpu_cycles * 3)
console.consume_nmi_if_requested()¿Qué es un conteo de ciclos base de instrucción? Un conteo de ciclos base de instrucción es el número normal de ciclos de CPU que un opcode toma antes de que se añadan penalizaciones dinámicas.
Ejemplos mínimos
NOP implied opcode $EA -> 2 cycles
LDA immediate opcode $A9 -> 2 cycles
JSR absolute opcode $20 -> 6 cyclesConcepto erróneo común
Los ciclos no son lo mismo que los bytes leídos. JSR ocupa 3 bytes pero toma 6 ciclos. No cuentes ciclos dentro de fetch_byte().
Ejemplo de implementación sugerido
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]Por qué esto evita una gran refactorización
OPCODE_TABLE sigue siendo el mapeo existente de opcode a manejador. OPCODE_CYCLES es una tabla de metadatos paralela. Las pruebas antiguas de comportamiento de instrucciones deberían seguir pasando porque CPU.step() sigue ejecutando el mismo manejador.
Limitación importante
Esto devuelve solo ciclos base. La temporización dinámica está intencionalmente fuera de alcance aquí:
branch taken penalties
branch page-cross penalties
indexed load page-cross penaltiesEsos deberían modelarse después como un paso separado.
Fuera de alcance
- refactorizar OPCODE_TABLE en entradas de dataclass
- añadir ciclos a fetch_byte()
- Console.step()
- avance de la PPU por ciclos de CPU * 3
- ciclos extra dinámicos
Ejecutar esta lección
uv run pytest tests/chapter_04_ppu_timing_and_vblank/test_267_cpu_step_returns_cycles.py -v