062. Instruction sbc
Add the core SBC instruction.
Lesson 62 of 356 · tests/chapter_01_cpu/test_062_instruction_sbc.py
File to update
emulator/cpu/instructions.pySymbol to add
instructions.sbcWhy this step exists
SBC introduces subtraction as a value-based core instruction before any opcode is wired. The 6502 Carry flag means "no borrow", so subtraction can use addition of the operand's eight-bit complement plus Carry.
Complete example implementation
# 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_8Important invariants
- Carry set subtracts only
value; Carry clear subtracts one extra - A is reduced to the final eight-bit result
- Carry is set exactly when no borrow occurs
- Zero and Negative follow the final eight-bit result
- Overflow follows signed subtraction, not unsigned borrow
Common misconception
Python's raw ~value is negative because integers are unbounded. Mask it with & 0xFF before addition; also do not treat Carry as a conventional borrow bit.
Out of scope
- every SBC opcode handler and opcode-table entry
- fetching operands or selecting addressing modes inside
sbc - decimal-mode arithmetic and cycle timing
Reference
https://www.nesdev.org/wiki/Instruction_reference#SBC
Run this lesson
uv run pytest tests/chapter_01_cpu/test_062_instruction_sbc.py -v