287. Console: шаг до следующего кадра
Добавить Console.step_until_next_frame() для пошагового выполнения на уровне кадров.
Урок 287 из 356 · tests/chapter_05_rendering_pipeline/test_287_console_step_until_next_frame.py
Файл для обновления
emulator/console.pyЗачем нужен этот шаг
У Console уже есть метод пошагового выполнения на одну инструкцию
console.step()Это наименьшая операция машинного времени в этом эмуляторе. Она выполняет одну инструкцию CPU, продвигает PPU на количество циклов CPU * 3, а затем обрабатывает любой отложенный NMI.
Ручным исполнителям и будущим фронтендам обычно нужна более крупная операция
run emulation until one full PPU frame completes
then ask for a framebuffer explicitlyНа этом шаге добавляется
console.step_until_next_frame(max_cpu_instructions: int | None = None) -> intПример реализации
def step_until_next_frame(
self,
max_cpu_instructions: int | None = None,
) -> int:
start_frame = self.ppu.frame
executed = 0
while self.ppu.frame == start_frame:
if max_cpu_instructions is not None:
if executed >= max_cpu_instructions:
raise RuntimeError("Frame did not complete before instruction limit")
self.step()
executed += 1
return executedРазница между step() и step_until_next_frame():
step()
executes exactly one CPU instruction
advances PPU by that instruction's cycles * 3
returns CPU cycles for that instruction
step_until_next_frame()
calls step() repeatedly until ppu.frame changes
returns how many CPU instructions were executedПример использования
console.step_until_next_frame()
framebuffer = console.render_background_framebuffer()Почему max_cpu_instructions необязателен: этот параметр не относится к поведению железа NES. Это защитный механизм эмулятора для отладки/тестирования.
При значении None искусственного ограничения по количеству инструкций нет. Это полезно для реального или ручного выполнения:
console.step_until_next_frame()При целочисленном значении помощник выбрасывает исключение, если указанное количество инструкций CPU выполнилось без появления нового кадра. Это полезно для тестов и отладки, поскольку предотвращает бесконечные циклы, если CPU завис, опкод отсутствует или кадр никогда не завершается:
console.step_until_next_frame(max_cpu_instructions=10)Важное разделение
step_until_next_frame()
advances emulation time
render_background_framebuffer()
observes current PPU memory and returns Framebuffer dataНе выполняйте рендеринг автоматически внутри step_until_next_frame().
Вне рамок этого шага
- отображение pygame
- спрайты
- OAMDMA
- точная задержка NMI
- динамические штрафы циклов CPU
- ввод с контроллера
Запустить этот урок
uv run pytest tests/chapter_05_rendering_pipeline/test_287_console_step_until_next_frame.py -v