262. Вспомогательные функции стека CPU и импорты флагов
Отрефакторить поддержку прерываний CPU вокруг общих флагов и вспомогательных функций стека.
Урок 262 из 356 · tests/chapter_04_ppu_timing_and_vblank/test_262_cpu_stack_helpers_and_flag_imports.py
Файлы для обновления
emulator/cpu/cpu.py
emulator/cpu/flags_handler.pyЗачем нужен этот шаг
Перед реализацией и тестированием CPU.interrupt_nmi() ядру CPU нужны два небольших шага очистки:
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Это шаг рефакторинга и вспомогательных функций, а ещё не тест поведения прерывания NMI.
Важный контекст
Старые тесты CPU часто объявляли локальные константы флагов. Это было допустимо, пока глава о CPU строилась постепенно. Теперь, когда прерываниям нужна корректная обработка байта состояния, общим источником истины должно стать:
emulator/cpu/flags_handler.pyКорректная раскладка битов состояния
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Правило стека
push:
write to $0100 | S
decrement S
pop/pull:
increment S
read from $0100 | SПример предлагаемой реализации
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)Почему pop_stack добавляется сейчас: CPU.interrupt_nmi() нужна только push_stack, но соответствующим тестам и будущей чистке кода прерываний CPU также понадобится явная вспомогательная функция для извлечения из стека. Добавление обеих вспомогательных функций сразу делает инвариант стека явным ещё до тестирования поведения NMI.
Выходит за рамки
- поведение CPU.interrupt_nmi()
- обработка запроса NMI от PPU
- прерывания IRQ/APU/маппера
- перевод всех старых стековых инструкций на эти вспомогательные функции
Запустить этот урок
uv run pytest tests/chapter_04_ppu_timing_and_vblank/test_262_cpu_stack_helpers_and_flag_imports.py -v