188. 标志位处理:中断标志与 Break 标志
添加 I、B 以及未使用位的标志位辅助函数。
第 188 / 356 · tests/chapter_01_cpu/test_188_flags_handler_interrupt_and_break_flags.py
在本步骤中,将 Break 定义为第 4 位,将压栈状态字中未使用的位定义为第 5 位。向 `emulator/cpu/flags_handler.py` 添加:
INTERRUPT_FLAG = 1 << 2
B_FLAG = 1 << 4
ONE_FLAG = 1 << 5
def set_interrupt_disable_flag(self, enabled: bool):
if enabled:
self.cpu.p |= INTERRUPT_FLAG
else:
self.cpu.p &= ~INTERRUPT_FLAG
def set_break_flag(self, enabled: bool):
if enabled:
self.cpu.p |= B_FLAG
else:
self.cpu.p &= ~B_FLAG
def set_one_flag(self, enabled: bool):
if enabled:
self.cpu.p |= ONE_FLAG
else:
self.cpu.p &= ~ONE_FLAG
def get_interrupt_disable_flag(self) -> bool:
return bool(self.cpu.p & INTERRUPT_FLAG)
def get_break_flag(self) -> bool:
return bool(self.cpu.p & B_FLAG)
def get_one_flag(self) -> bool:
return bool(self.cpu.p & ONE_FLAG)本步骤存在的原因
我们正在为实现 BRK 做准备。
BRK 是一条软件中断指令。为了清晰地实现它,CPU 需要针对两个状态标志位提供辅助函数:
I flag -> Interrupt Disable, bit 2
B flag -> Break, bit 4
ONE flag -> unused/status bit 5 used in pushed status bytesBRK 需要它们,原因是
- 进入中断处理程序后,它会设置中断禁止标志
- 它会压入一个已设置 Break 标志的状态字节
设计目标
把位操作集中封装在 FlagsHandler 内部,而不是把对 cpu.p 的原始位操作分散到各条指令代码中。
重要术语
Interrupt Disable flag:
When set, maskable IRQ interrupts are disabled.
Break flag:
Used to mark that the pushed status byte came from BRK.常见错误
不要把 BRK 操作码与 Break 标志混淆。
BRK opcode: 0x00, the instruction byte in memory
B flag: bit 4 inside the status byte pushed to the stack
ONE flag: bit 5, usually set in pushed status bytes设计依据:具名的设置函数把对 P 的独立读-改-写操作集中起来,取值函数则以布尔值形式对外暴露。不变量:每个设置函数只改变各自对应的位;I、B、ONE 以及所有已有标志位彼此独立。常见误解:B 与压栈状态字中始终为一的那一位并不是同一位,操作码 $00 也不是它们中的任何一个。
本步骤范围之外:本步骤不实现 BRK,也不决定这些位何时被设置,那属于第 189-190 步。RTI/PHP/PLP、NMI 行为以及 CPU 栈辅助函数仍属于后续工作。
运行本课
uv run pytest tests/chapter_01_cpu/test_188_flags_handler_interrupt_and_break_flags.py -v