052. Refactorización del manejador de banderas
Introducir un ayudante público para el acceso a las banderas del registro de estado del procesador.
Lección 52 de 356 · tests/chapter_01_cpu/test_052_flags_handler_refactor.py
Archivos a crear/actualizar
emulator/cpu/flags_handler.py
emulator/cpu/cpu.pySímbolos a crear/actualizar
FlagsHandler
CPU.flags
CPU.__post_init__Por qué existe este paso
El ayudante existente de CPU solo cubre Zero y Negative. La siguiente instrucción aritmética también necesita Carry y Overflow, así que el acceso a los bits de estado se recoge en un objeto que muta el registro p, propiedad de la CPU. El CPU._update_zero_and_negative_flags existente se mantiene intacto para las instrucciones anteriores.
Implementación de ejemplo completa
# emulator/cpu/flags_handler.py
from __future__ import annotations
from dataclasses import dataclass
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from emulator.cpu.cpu import CPU
CARRY_FLAG = 1 << 0
ZERO_FLAG = 1 << 1
ONE_FLAG = 1 << 5
OVERFLOW_FLAG = 1 << 6
NEGATIVE_FLAG = 1 << 7
@dataclass
class FlagsHandler:
cpu: CPU
def set_zero_flag(self, enabled: bool):
if enabled:
self.cpu.p |= ZERO_FLAG
else:
self.cpu.p &= ~ZERO_FLAG
def set_negative_flag(self, enabled: bool):
if enabled:
self.cpu.p |= NEGATIVE_FLAG
else:
self.cpu.p &= ~NEGATIVE_FLAG
def set_overflow_flag(self, enabled: bool):
if enabled:
self.cpu.p |= OVERFLOW_FLAG
else:
self.cpu.p &= ~OVERFLOW_FLAG
def set_carry_flag(self, enabled: bool):
if enabled:
self.cpu.p |= CARRY_FLAG
else:
self.cpu.p &= ~CARRY_FLAG
def set_one_flag(self, enabled: bool):
if enabled:
self.cpu.p |= ONE_FLAG
else:
self.cpu.p &= ~ONE_FLAG
def get_zero_flag(self) -> bool:
return bool(self.cpu.p & ZERO_FLAG)
def get_negative_flag(self) -> bool:
return bool(self.cpu.p & NEGATIVE_FLAG)
def get_overflow_flag(self) -> bool:
return bool(self.cpu.p & OVERFLOW_FLAG)
def get_carry_flag(self) -> bool:
return bool(self.cpu.p & CARRY_FLAG)
def get_one_flag(self) -> bool:
return bool(self.cpu.p & ONE_FLAG)
# emulator/cpu/cpu.py
from dataclasses import dataclass, field
from emulator.cpu.flags_handler import FlagsHandler
@dataclass
class CPU:
bus: CpuBus
flags: FlagsHandler = field(init=False)
def __post_init__(self):
self.flags = FlagsHandler(self)
# Keep the existing registers, fetch/reset/step methods, and
# _update_zero_and_negative_flags implementation unchanged.Invariantes importantes
cpu.psigue siendo el único valor de estado del procesador- cada setter cambia solo su propio bit y admite tanto activar como desactivar
- cada getter devuelve un bool
- cada CPU posee un manejador cuya referencia
cpuapunta de vuelta a esa CPU - el antiguo ayudante Zero/Negative de CPU sigue siendo invocable
Concepto erróneo habitual
No le des a FlagsHandler un byte de estado independiente ni reemplaces el antiguo ayudante de CPU; eso dividiría el estado o rompería las instrucciones introducidas en tests anteriores.
Fuera de alcance
- ADC, que consume por primera vez estos ayudantes públicos en el test 053
- los ayudantes de Break, interrupt-disable y decimal
- el comportamiento de pila e interrupciones
Ejecutar esta lección
uv run pytest tests/chapter_01_cpu/test_052_flags_handler_refactor.py -v