052. 标志位处理函数重构

引入一个用于访问处理器状态标志位的公共辅助函数。

52 / 356 · tests/chapter_01_cpu/test_052_flags_handler_refactor.py

要创建/更新的文件

emulator/cpu/flags_handler.py
emulator/cpu/cpu.py

要创建/更新的符号

FlagsHandler
CPU.flags
CPU.__post_init__

为什么需要这一步

现有的 CPU 辅助函数只覆盖 Zero 和 Negative。下一条算术指令还需要 Carry 和 Overflow,因此状态位的访问被集中到一个对象中,由它修改 CPU 所拥有的 p 寄存器。现有的 CPU._update_zero_and_negative_flags 保持原样,继续供较早的指令使用。

完整示例实现

# emulator/cpu/flags_handler.py
from __future__ import annotations
from dataclasses import dataclass
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from emulator.cpu.cpu import CPU

CARRY_FLAG = 1 << 0
ZERO_FLAG = 1 << 1
ONE_FLAG = 1 << 5
OVERFLOW_FLAG = 1 << 6
NEGATIVE_FLAG = 1 << 7

@dataclass
class FlagsHandler:
    cpu: CPU

    def set_zero_flag(self, enabled: bool):
        if enabled:
            self.cpu.p |= ZERO_FLAG
        else:
            self.cpu.p &= ~ZERO_FLAG

    def set_negative_flag(self, enabled: bool):
        if enabled:
            self.cpu.p |= NEGATIVE_FLAG
        else:
            self.cpu.p &= ~NEGATIVE_FLAG

    def set_overflow_flag(self, enabled: bool):
        if enabled:
            self.cpu.p |= OVERFLOW_FLAG
        else:
            self.cpu.p &= ~OVERFLOW_FLAG

    def set_carry_flag(self, enabled: bool):
        if enabled:
            self.cpu.p |= CARRY_FLAG
        else:
            self.cpu.p &= ~CARRY_FLAG

    def set_one_flag(self, enabled: bool):
        if enabled:
            self.cpu.p |= ONE_FLAG
        else:
            self.cpu.p &= ~ONE_FLAG

    def get_zero_flag(self) -> bool:
        return bool(self.cpu.p & ZERO_FLAG)

    def get_negative_flag(self) -> bool:
        return bool(self.cpu.p & NEGATIVE_FLAG)

    def get_overflow_flag(self) -> bool:
        return bool(self.cpu.p & OVERFLOW_FLAG)

    def get_carry_flag(self) -> bool:
        return bool(self.cpu.p & CARRY_FLAG)

    def get_one_flag(self) -> bool:
        return bool(self.cpu.p & ONE_FLAG)

# emulator/cpu/cpu.py
from dataclasses import dataclass, field
from emulator.cpu.flags_handler import FlagsHandler

@dataclass
class CPU:
    bus: CpuBus
    flags: FlagsHandler = field(init=False)

    def __post_init__(self):
        self.flags = FlagsHandler(self)

    # Keep the existing registers, fetch/reset/step methods, and
    # _update_zero_and_negative_flags implementation unchanged.

重要不变量

  • cpu.p 仍然是唯一的处理器状态值
  • 每个 setter 只修改自己的位,并同时支持置位和清零
  • 每个 getter 都返回一个 bool
  • 每个 CPU 都拥有一个处理函数,其 cpu 引用指回该 CPU 自身
  • 旧的 Zero/Negative CPU 辅助函数仍可调用

常见误区

不要给 FlagsHandler 单独的状态字节,也不要替换旧的 CPU 辅助函数;那会拆分状态,或者破坏较早测试中引入的指令。

范围之外

  • ADC,它在测试 053 中首次使用这些公共辅助函数
  • Break、禁止中断以及十进制的辅助函数
  • 栈与中断行为

运行本课

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