262. Helpers de pila de la CPU e importación de flags

Refactorizar el soporte de interrupciones de la CPU en torno a flags compartidos y helpers de pila.

Lección 262 de 356 · tests/chapter_04_ppu_timing_and_vblank/test_262_cpu_stack_helpers_and_flag_imports.py

Archivos a actualizar

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

Por qué existe este paso

Antes de implementar y probar CPU.interrupt_nmi(), el núcleo de la CPU necesita dos pequeñas piezas de limpieza:

1. CPU should import status flag constants from flags_handler.py.
2. CPU should expose stack helpers for interrupt code:
    push_stack(value)
    pop_stack() -> int

Este es un paso de refactorización/helpers, no la prueba del comportamiento de la interrupción NMI todavía.

Contexto importante

Las pruebas antiguas de la CPU a menudo declaraban constantes de flags locales. Eso estaba bien mientras el capítulo de la CPU se construía de forma incremental. Ahora que las interrupciones necesitan un manejo correcto del byte de estado, la fuente de verdad compartida debe ser:

emulator/cpu/flags_handler.py

Disposición correcta de los bits de estado

CARRY_FLAG      = 1 << 0
ZERO_FLAG       = 1 << 1
INTERRUPT_FLAG  = 1 << 2
DECIMAL_FLAG    = 1 << 3
B_FLAG          = 1 << 4
ONE_FLAG        = 1 << 5
OVERFLOW_FLAG   = 1 << 6
NEGATIVE_FLAG   = 1 << 7

Regla de la pila

push:
    write to $0100 | S
    decrement S

pop/pull:
    increment S
    read from $0100 | S

Ejemplo de implementación sugerido

from emulator.cpu.flags_handler import (
    B_FLAG,
    INTERRUPT_FLAG,
    NEGATIVE_FLAG,
    ONE_FLAG,
    ZERO_FLAG,
)

STACK_BASE = 0x0100

class CPU:
    ...

    def push_stack(self, value: int) -> None:
        self.bus.write(STACK_BASE | self.s, value & 0xFF)
        self.s = (self.s - 1) & 0xFF

    def pop_stack(self) -> int:
        self.s = (self.s + 1) & 0xFF
        return self.bus.read(STACK_BASE | self.s)

Por qué se añade pop_stack ahora: CPU.interrupt_nmi() solo necesita push_stack, pero las pruebas correspondientes y la futura limpieza de interrupciones de la CPU necesitan también un helper de extracción claro. Añadir ambos helpers juntos hace explícita la invariante de la pila antes de probar el comportamiento de NMI.

Fuera de alcance

  • Comportamiento de CPU.interrupt_nmi()
  • consumo de la solicitud NMI de la PPU
  • interrupciones IRQ/APU/mapper
  • refactorización de cada instrucción antigua de pila para usar estos helpers

Ejecutar esta lección

uv run pytest tests/chapter_04_ppu_timing_and_vblank/test_262_cpu_stack_helpers_and_flag_imports.py -v