268. Console.step() продвигает PPU
Заставить Console.step() продвигать время PPU на основе тактов CPU.
Урок 268 из 356 · tests/chapter_04_ppu_timing_and_vblank/test_268_console_step_advances_ppu.py
Справочные материалы
https://www.nesdev.org/wiki/CPU
https://www.nesdev.org/wiki/PPU_rendering#Line-by-line_timingФайл для обновления
emulator/console.pyЗачем нужен этот шаг
В эмуляторе теперь есть части, необходимые для связи времени CPU со временем PPU
CPU.step() returns base CPU cycles
PPU.step(cycles) advances PPU timing counters
Console.consume_nmi_if_requested() connects PPU NMI requests to CPU NMIConsole.step() — это то место, где эти части становятся одним шагом на уровне машины.
Что такое шаг на уровне машины? Шаг на уровне машины означает совместное продвижение нескольких эмулируемых микросхем согласно их тактовой взаимосвязи.
Минимальное правило синхронизации NES
1 CPU cycle = 3 PPU cyclesМинимальный пример
CPU executes NOP
NOP takes 2 CPU cycles
PPU advances 2 * 3 = 6 PPU cyclesРаспространённое заблуждение
Не заставляйте CPU.step() вызывать PPU.step(). CPU не должен владеть видеосинхронизацией. Console владеет координацией между микросхемами.
Пример предлагаемой реализации
@dataclass
class Console:
cpu: CPU
ppu: PPU
def consume_nmi_if_requested(self) -> None:
if not self.ppu.nmi_requested:
return
self.ppu.nmi_requested = False
self.cpu.interrupt_nmi()
def step(self) -> int:
# This is base timing only. Later steps can add branch penalties,
# NMI latency, DMA stalls, and other timing details.
cpu_cycles = self.cpu.step()
self.ppu.step(cpu_cycles * 3)
self.consume_nmi_if_requested()
return cpu_cyclesВажное ограничение
Это по-прежнему упрощённая синхронизация. CPU.step() сейчас возвращает только базовые такты.
Последующие улучшения могут учитывать
branch taken extra cycles
branch page-cross extra cycles
indexed addressing page-cross extra cycles
NMI latency
OAM DMA stallsВыходит за рамки
- динамические штрафы тактов CPU
- задержка NMI с точностью до точки
- OAM DMA
- рендеринг пикселей
- цикл pygame/фронтенда
- ввод с контроллеров
Запустить этот урок
uv run pytest tests/chapter_04_ppu_timing_and_vblank/test_268_console_step_advances_ppu.py -v