012. 重构零标志位与负标志位

提取共享的零标志位与负标志位更新。

12 / 356 · tests/chapter_01_cpu/test_012_refactor_zero_and_negative_flags.py

要更新的文件

emulator/cpu/cpu.py

位置

CPU._update_zero_and_negative_flags
CPU.step, existing $A9 and $AD branches

为什么需要这一步

目前立即寻址和绝对寻址的 LDA 重复着完全相同的标志位修改。一个辅助函数即可把这条不变量在一处落实为可执行代码,并显式接收结果值,使后续指令无需依赖累加器 A 就能复用它。

完整示例实现

ZERO_FLAG = 1 << 1
NEGATIVE_FLAG = 1 << 7


class CPU:
    def _update_zero_and_negative_flags(self, value: int) -> None:
        if value == 0:
            self.p |= ZERO_FLAG
        else:
            self.p &= ~ZERO_FLAG

        if value & NEGATIVE_FLAG:
            self.p |= NEGATIVE_FLAG
        else:
            self.p &= ~NEGATIVE_FLAG

    def step(self) -> None:
        opcode = self.fetch_byte()

        if opcode == 0xA9:
            self.a = self.fetch_byte()
        elif opcode == 0xAD:
            address = self.fetch_word()
            self.a = self.bus.read(address)
        else:
            raise NotImplementedError(
                f"Opcode {opcode:02X} not implemented"
            )

        self._update_zero_and_negative_flags(self.a)

重要不变量

  • 标志位由接收到的值推导而来,而不是隐式地由 cpu.a 推导
  • 只有 Z 和 N 会改变
  • 重构后现有的 LDA 行为保持不变

常见误解

重构不是改变行为的许可。测试 010–011 仍然是行为契约;这一步只是把其中的机制集中化。

范围之外

  • 将寻址逻辑移出 CPU.step
  • 将 LDA 行为移入 instructions.py

运行本课

uv run pytest tests/chapter_01_cpu/test_012_refactor_zero_and_negative_flags.py -v