062. SBC 指令
添加核心 SBC 指令。
第 62 / 356 · tests/chapter_01_cpu/test_062_instruction_sbc.py
要更新的文件
emulator/cpu/instructions.py要添加的符号
instructions.sbc为什么需要这一步
SBC 在接入任何操作码之前,先把减法作为一种基于数值的核心指令引入。6502 的 Carry 标志表示“无借位”,因此减法可以通过将操作数的八位补码与 Carry 相加来实现。
完整示例实现
# emulator/cpu/instructions.py
def sbc(cpu: CPU, value: int):
carry = int(cpu.flags.get_carry_flag())
a = cpu.a
value_inverted = (~value) & 0xFF
result = a + value_inverted + carry
result_8 = result & 0xFF
cpu.flags.set_carry_flag(result > 0xFF)
cpu.flags.set_zero_flag(result_8 == 0)
cpu.flags.set_negative_flag((result_8 & 0x80) != 0)
overflow = ((result_8 ^ a) & (result_8 ^ value_inverted)) & 0x80
cpu.flags.set_overflow_flag(overflow != 0)
cpu.a = result_8重要不变量
- Carry 置位时只减去
value;Carry 清零时会多减一 - A 被缩减为最终的八位结果
- 当且仅当无借位时 Carry 才被置位
- Zero 和 Negative 反映最终的八位结果
- Overflow 反映有符号减法,而非无符号借位
常见误解
Python 中 ~value 的原始结果是一个负数,因为整数没有位数限制。相加之前要用 & 0xFF 对它做掩码处理;另外,不要把 Carry 当作常规的借位比特。
范围之外
- 每个 SBC 操作码处理函数和操作码表条目
- 在
sbc内部取操作数或选择寻址模式 - 十进制模式运算和周期时序
参考
https://www.nesdev.org/wiki/Instruction_reference#SBC
运行本课
uv run pytest tests/chapter_01_cpu/test_062_instruction_sbc.py -v