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 executedstep() 和 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