1
0

Emualtor improements

This commit is contained in:
Aiden
2026-05-25 18:55:50 +10:00
parent 05e1237acc
commit 1fabf6587d
10 changed files with 413 additions and 15 deletions

View File

@@ -11,6 +11,9 @@ from .constants import (
SCI1_SSR,
SCI1_TDR,
SCI_SCR_TE,
SCI_SSR_FER,
SCI_SSR_ORER,
SCI_SSR_PER,
SCI_SSR_RDRF,
SCI_SSR_TDRE,
)
@@ -34,6 +37,8 @@ class SCI1:
- SCR bit 7 TIE, bit 6 RIE, bit 5 TE, bit 4 RE.
- SSR bit 7 TDRE, bit 6 RDRF, bits 5..3 ORER/FER/PER.
- Software normally writes TDR after TDRE=1, then clears SSR.TDRE.
- SSR status flags are R/(W)*: writing 0 clears a latched flag, while
writing 1 leaves the hardware-owned flag unchanged.
"""
smr: int = 0x00
@@ -47,6 +52,8 @@ class SCI1:
tx_frames: list[bytes] = field(default_factory=list)
_frame_buffer: bytearray = field(default_factory=bytearray)
tx_ready_delay: int = 0
tx_ready_ticks: int = 2
_tx_ready_pending: bool = False
def read(self, address: int) -> int:
if address == SCI1_SMR:
@@ -75,10 +82,7 @@ class SCI1:
self.tdr = value
self._write_tdr(value)
elif address == SCI1_SSR:
# The real SSR is R/(W)*: writable zeroes clear latched flags after
# the required read sequence. This scaffold applies zero bits
# directly so ROM BCLR/BSET style accesses can be modeled.
self.ssr = value
self._write_ssr(value)
elif address == SCI1_RDR:
self.rdr = value
else:
@@ -92,10 +96,14 @@ class SCI1:
if len(self._frame_buffer) == len(HEARTBEAT_FRAME):
self.tx_frames.append(bytes(self._frame_buffer))
self._frame_buffer.clear()
self.ssr |= SCI_SSR_TDRE
self.tx_ready_delay = 2
self.tx_ready_delay = max(0, self.tx_ready_ticks)
self._tx_ready_pending = True
self.tx_events.append(SciTxEvent(SCI1_TDR, value, self.scr, self.ssr, emitted))
def _write_ssr(self, value: int) -> None:
writable_zero_flags = SCI_SSR_TDRE | SCI_SSR_RDRF | SCI_SSR_ORER | SCI_SSR_FER | SCI_SSR_PER
self.ssr = (self.ssr & (writable_zero_flags & value)) | (value & ~writable_zero_flags)
def inject_rx(self, value: int) -> None:
self.rdr = value & 0xFF
self.ssr |= SCI_SSR_RDRF
@@ -104,7 +112,8 @@ class SCI1:
return HEARTBEAT_FRAME in self.tx_frames
def tick(self) -> None:
if self.tx_ready_delay:
if self._tx_ready_pending and self.tx_ready_delay:
self.tx_ready_delay -= 1
if self.tx_ready_delay == 0:
self.ssr |= SCI_SSR_TDRE
if self._tx_ready_pending and self.tx_ready_delay == 0 and not (self.ssr & SCI_SSR_TDRE):
self.ssr |= SCI_SSR_TDRE
self._tx_ready_pending = False