262. Cpu stack helpers and flag imports

Refactor CPU interrupt support around shared flags and stack helpers.

Lesson 262 of 356 · tests/chapter_04_ppu_timing_and_vblank/test_262_cpu_stack_helpers_and_flag_imports.py

Files to update

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

Why this step exists

Before implementing and testing CPU.interrupt_nmi(), the CPU core needs two small cleanup pieces:

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

This is a refactor/helper step, not the NMI interrupt behavior test yet.

Important context

Older CPU tests often declared local flag constants. That was fine while the CPU chapter was being built incrementally. Now that interrupts need correct status byte handling, the shared source of truth should be:

emulator/cpu/flags_handler.py

Correct status bit layout

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

Stack rule

push:
    write to $0100 | S
    decrement S

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

Suggested implementation example

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)

Why pop_stack is added now: CPU.interrupt_nmi() only needs push_stack, but the matching tests and future CPU interrupt cleanup need a clear pull helper too. Adding both helpers together makes the stack invariant explicit before NMI behavior is tested.

Out of scope

  • CPU.interrupt_nmi() behavior
  • PPU NMI request consumption
  • IRQ/APU/mapper interrupts
  • refactoring every old stack instruction to use these helpers

Run this lesson

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