267. CPU.step() возвращает такты
Заставить CPU.step() возвращать базовые такты инструкции.
Урок 267 из 356 · tests/chapter_04_ppu_timing_and_vblank/test_267_cpu_step_returns_cycles.py
Справочник
https://www.nesdev.org/wiki/Visual6502wiki/6502_all_256_OpcodesФайлы для обновления
emulator/cpu/cpu.pyЗачем нужен этот шаг
В эмуляторе теперь есть отдельная таблица OPCODE_CYCLES. Следующий элемент синхронизации — возвращение CPU.step() базового числа тактов выполненного им опкода.
Это готовит будущий вид Console.step():
cpu_cycles = cpu.step()
ppu.step(cpu_cycles * 3)
console.consume_nmi_if_requested()Что такое базовое число тактов инструкции? Базовое число тактов инструкции — это обычное число тактов CPU, которое занимает опкод до добавления динамических штрафов.
Минимальные примеры
NOP implied opcode $EA -> 2 cycles
LDA immediate opcode $A9 -> 2 cycles
JSR absolute opcode $20 -> 6 cyclesРаспространённое заблуждение
Такты — не то же самое, что считанные байты. JSR занимает 3 байта, но требует 6 тактов. Не считайте такты внутри fetch_byte().
Пример предлагаемой реализации
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]Почему это позволяет избежать большого рефакторинга
OPCODE_TABLE остаётся существующим отображением опкод -> обработчик. OPCODE_CYCLES — параллельная таблица метаданных. Старые тесты поведения инструкций должны продолжать проходить, потому что CPU.step() по-прежнему выполняет тот же обработчик.
Важное ограничение
Здесь возвращаются только базовые такты. Динамическая синхронизация намеренно выходит за рамки:
branch taken penalties
branch page-cross penalties
indexed load page-cross penaltiesОни должны быть смоделированы позже отдельным шагом.
Выходит за рамки
- переделка OPCODE_TABLE в записи dataclasses
- добавление тактов в fetch_byte()
- Console.step()
- продвижение PPU на такты CPU * 3
- динамические дополнительные такты
Запустить этот урок
uv run pytest tests/chapter_04_ppu_timing_and_vblank/test_267_cpu_step_returns_cycles.py -v