188. Обработчик флагов: флаги Interrupt и Break

добавить вспомогательные функции для флагов I, B и неиспользуемого бита.

Урок 188 из 356 · tests/chapter_01_cpu/test_188_flags_handler_interrupt_and_break_flags.py

На этом шаге определите Break как бит 4 и неиспользуемый бит записываемого статуса как бит 5. Добавьте в `emulator/cpu/flags_handler.py`:

INTERRUPT_FLAG = 1 << 2
B_FLAG = 1 << 4
ONE_FLAG = 1 << 5

def set_interrupt_disable_flag(self, enabled: bool):
    if enabled:
        self.cpu.p |= INTERRUPT_FLAG
    else:
        self.cpu.p &= ~INTERRUPT_FLAG

def set_break_flag(self, enabled: bool):
    if enabled:
        self.cpu.p |= B_FLAG
    else:
        self.cpu.p &= ~B_FLAG

def set_one_flag(self, enabled: bool):
    if enabled:
        self.cpu.p |= ONE_FLAG
    else:
        self.cpu.p &= ~ONE_FLAG

def get_interrupt_disable_flag(self) -> bool:
    return bool(self.cpu.p & INTERRUPT_FLAG)

def get_break_flag(self) -> bool:
    return bool(self.cpu.p & B_FLAG)

def get_one_flag(self) -> bool:
    return bool(self.cpu.p & ONE_FLAG)

Зачем нужен этот шаг

Мы готовимся к реализации BRK.

BRK — это инструкция программного прерывания. Для её чёткой реализации CPU нужны вспомогательные функции для двух флагов статуса:

I flag -> Interrupt Disable, bit 2
B flag -> Break, bit 4
ONE flag -> unused/status bit 5 used in pushed status bytes

BRK потребует их, потому что

  • она устанавливает флаг Interrupt Disable после входа в обработчик прерывания
  • она записывает байт статуса с установленным флагом Break

Цель проектирования

Сосредоточить битовые манипуляции внутри FlagsHandler, а не разбрасывать сырые побитовые операции с cpu.p по коду инструкций.

Важная терминология

Interrupt Disable flag:
    When set, maskable IRQ interrupts are disabled.

Break flag:
    Used to mark that the pushed status byte came from BRK.

Частая ошибка

Не путайте опкод BRK с флагом Break.

BRK opcode: 0x00, the instruction byte in memory
B flag:     bit 4 inside the status byte pushed to the stack
ONE flag:   bit 5, usually set in pushed status bytes

Обоснование: именованные сеттеры централизуют независимые операции чтения-изменения-записи над P, а геттеры предоставляют булевы значения. Инварианты: каждый сеттер изменяет только свой бит; I, B, ONE и все существующие флаги остаются независимыми. Заблуждение: B и всегда единичный бит записываемого статуса — это не один и тот же бит, и опкод $00 тоже не является ни одним из них.

За рамками шага: этот шаг не реализует BRK и не определяет, когда биты устанавливаются; это шаги 189–190. RTI/PHP/PLP, поведение NMI и вспомогательные функции стека CPU относятся к последующим шагам.

Запустить этот урок

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