102. Instrucción rol

implementar ROL dirigido a memoria.

Lección 102 de 356 · tests/chapter_01_cpu/test_102_instruction_rol.py

En este paso, añade únicamente la primitiva de memoria de ROL. El comportamiento con el acumulador llega en la lección 103, y la exposición como opcode corresponde a las lecciones 104-108.

Implementación de ejemplo completa en la ubicación de producción

`emulator/cpu/instructions.py::rol`::

def rol(cpu: CPU, addr: int):
    value = cpu.bus.read(addr)
    old_carry = int(cpu.flags.get_carry_flag())

    result = (value << 1) | old_carry
    result_8 = result & 0xFF

    # Set flags

    cpu.flags.set_carry_flag((value & 0b1000_0000) != 0)
    cpu.flags.set_zero_flag(result_8 == 0)
    cpu.flags.set_negative_flag((result_8 & 0b1000_0000) != 0)

    cpu.bus.write(addr, result_8)

Por qué existe este paso

Una única primitiva de lectura/modificación/escritura independiente del direccionamiento permite que todo opcode de memoria reutilice la misma semántica de rotación y de banderas.

Invariantes: captura Carry antes de cambiar las banderas; el antiguo Carry entra en el bit 0, el antiguo bit 7 pasa a ser Carry, el resultado almacenado se enmascara a ocho bits, y Zero y Negative se derivan de ese resultado almacenado. Se lee y se escribe exactamente una dirección de destino; A no cambia.

Concepto erróneo: ROL no es ASL. Inserta el antiguo Carry en lugar de insertar siempre cero, y Carry debe provenir del valor original, no de `result_8`.

Fuera de alcance: el ROL de acumulador es la lección 103, los adaptadores de opcode/direccionamiento son 104-108, y ROR empieza en la lección 109; el comportamiento del bus a nivel de ciclo llegó más adelante.

Ejecutar esta lección

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