062. Instruction sbc

Añadir la instrucción central SBC.

Lección 62 de 356 · tests/chapter_01_cpu/test_062_instruction_sbc.py

Archivo a actualizar

emulator/cpu/instructions.py

Símbolo a añadir

instructions.sbc

Por qué existe este paso

SBC introduce la resta como instrucción central basada en valores antes de conectar ningún opcode. En el 6502, la flag de Carry significa "sin préstamo", por lo que la resta puede implementarse como la suma del complemento de ocho bits del operando más Carry.

Implementación de ejemplo completa

# 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

Invariantes importantes

  • con Carry activado se resta solo value; con Carry desactivado se resta uno adicional
  • A se reduce al resultado final de ocho bits
  • Carry se activa exactamente cuando no se produce préstamo
  • Zero y Negative siguen el resultado final de ocho bits
  • Overflow sigue la resta con signo, no el préstamo sin signo

Concepto erróneo común

El ~value sin procesar de Python es negativo porque los enteros no tienen límite. Enmascáralo con & 0xFF antes de sumar; tampoco trates Carry como un bit de préstamo convencional.

Fuera de alcance

  • todos los manejadores de opcode de SBC y las entradas de la tabla de opcodes
  • obtener operandos o seleccionar modos de direccionamiento dentro de sbc
  • la aritmética en modo decimal y la temporización de ciclos

Referencia

https://www.nesdev.org/wiki/Instruction_reference#SBC

Ejecutar esta lección

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