262. CPU 栈辅助函数与标志位导入
围绕共享标志位和栈辅助函数重构 CPU 的中断支持。
第 262 / 356 · tests/chapter_04_ppu_timing_and_vblank/test_262_cpu_stack_helpers_and_flag_imports.py
需要更新的文件
emulator/cpu/cpu.py
emulator/cpu/flags_handler.py此步骤存在的原因
在实现并测试 CPU.interrupt_nmi() 之前,CPU 核心需要先完成两处小的清理工作:
1. CPU should import status flag constants from flags_handler.py.
2. CPU should expose stack helpers for interrupt code:
push_stack(value)
pop_stack() -> int这是一次重构/辅助函数的准备步骤,还不是 NMI 中断行为本身的测试。
重要背景
早期的 CPU 测试常常各自声明局部的标志位常量。在 CPU 章节逐步搭建的阶段,这样做没有问题。但现在中断需要正确处理状态字节,共享的唯一可信来源应该是:
emulator/cpu/flags_handler.py正确的状态位布局
CARRY_FLAG = 1 << 0
ZERO_FLAG = 1 << 1
INTERRUPT_FLAG = 1 << 2
DECIMAL_FLAG = 1 << 3
B_FLAG = 1 << 4
ONE_FLAG = 1 << 5
OVERFLOW_FLAG = 1 << 6
NEGATIVE_FLAG = 1 << 7栈操作规则
push:
write to $0100 | S
decrement S
pop/pull:
increment S
read from $0100 | S建议的实现示例
from emulator.cpu.flags_handler import (
B_FLAG,
INTERRUPT_FLAG,
NEGATIVE_FLAG,
ONE_FLAG,
ZERO_FLAG,
)
STACK_BASE = 0x0100
class CPU:
...
def push_stack(self, value: int) -> None:
self.bus.write(STACK_BASE | self.s, value & 0xFF)
self.s = (self.s - 1) & 0xFF
def pop_stack(self) -> int:
self.s = (self.s + 1) & 0xFF
return self.bus.read(STACK_BASE | self.s)为什么现在要加入 pop_stack:CPU.interrupt_nmi() 本身只需要 push_stack,但配套的测试以及后续 CPU 中断相关的清理工作也需要一个清晰的出栈辅助函数。把这两个辅助函数一起加入,可以在测试 NMI 行为之前就明确栈的不变量。
不在本步骤范围内
- CPU.interrupt_nmi() 的行为
- 消费 PPU 的 NMI 请求
- IRQ/APU/映射器中断
- 把所有旧的栈相关指令都重构为使用这些辅助函数
运行本课
uv run pytest tests/chapter_04_ppu_timing_and_vblank/test_262_cpu_stack_helpers_and_flag_imports.py -v