EMualtor im
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .lcd import LCD_E_CLOCK_DATA, LCD_E_CLOCK_STATUS
|
||||
from .p9_bus import P9_ACK_BIT
|
||||
from .p9_bus import P9_ACK_BIT, P9_STROBE_BIT, P9Bus, P9StrobeEvent
|
||||
|
||||
__all__ = [
|
||||
"LCD_E_CLOCK_DATA",
|
||||
"LCD_E_CLOCK_STATUS",
|
||||
"P9_ACK_BIT",
|
||||
"P9_STROBE_BIT",
|
||||
"P9Bus",
|
||||
"P9StrobeEvent",
|
||||
]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
LCD_E_CLOCK_DATA = 0xF200
|
||||
LCD_E_CLOCK_STATUS = 0xF201
|
||||
LCD_E_CLOCK_STATUS = 0xF200
|
||||
LCD_E_CLOCK_DATA = 0xF201
|
||||
|
||||
@@ -1,4 +1,80 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Iterable
|
||||
|
||||
|
||||
P9_ACK_BIT = 0x80
|
||||
P9_STROBE_BIT = 0x02
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class P9StrobeEvent:
|
||||
edge: str
|
||||
ddr: int
|
||||
dr: int
|
||||
data_bit: int
|
||||
bit7_output: bool
|
||||
|
||||
|
||||
class P9Bus:
|
||||
"""Small model for the ROM's P9 bit-banged serial handshake."""
|
||||
|
||||
def __init__(self, ddr: int = 0x00, dr: int = 0x00, input_bits: Iterable[int] = ()) -> None:
|
||||
self.ddr = ddr & 0xFF
|
||||
self.dr_latch = dr & 0xFF
|
||||
self.input_bits: list[int] = [1 if bit else 0 for bit in input_bits]
|
||||
self.default_input_bit = 0
|
||||
self.strobe_edges: list[P9StrobeEvent] = []
|
||||
self.transmitted_bits: list[int] = []
|
||||
self.byte_candidates: list[int] = []
|
||||
|
||||
def write_ddr(self, value: int) -> int:
|
||||
self.ddr = value & 0xFF
|
||||
return self.ddr
|
||||
|
||||
def write_dr(self, value: int) -> int:
|
||||
previous = self.dr_latch
|
||||
self.dr_latch = value & 0xFF
|
||||
|
||||
previous_strobe = bool(previous & P9_STROBE_BIT)
|
||||
current_strobe = bool(self.dr_latch & P9_STROBE_BIT)
|
||||
if previous_strobe != current_strobe:
|
||||
edge = "rising" if current_strobe else "falling"
|
||||
data_bit = 1 if self.dr_latch & P9_ACK_BIT else 0
|
||||
bit7_output = bool(self.ddr & P9_ACK_BIT)
|
||||
self.strobe_edges.append(P9StrobeEvent(edge, self.ddr, self.dr_latch, data_bit, bit7_output))
|
||||
if edge == "rising" and bit7_output:
|
||||
self._record_transmitted_bit(data_bit)
|
||||
|
||||
return self.dr_latch
|
||||
|
||||
def read_ddr(self) -> int:
|
||||
return self.ddr
|
||||
|
||||
def read_dr(self) -> int:
|
||||
value = self.dr_latch
|
||||
if not (self.ddr & P9_ACK_BIT):
|
||||
if self.input_bits:
|
||||
input_bit = self.input_bits.pop(0)
|
||||
else:
|
||||
input_bit = self.default_input_bit
|
||||
if input_bit:
|
||||
value |= P9_ACK_BIT
|
||||
else:
|
||||
value &= ~P9_ACK_BIT
|
||||
return value & 0xFF
|
||||
|
||||
def queue_input_bits(self, bits: Iterable[int]) -> None:
|
||||
self.input_bits.extend(1 if bit else 0 for bit in bits)
|
||||
|
||||
def set_default_input_bit(self, bit: int) -> None:
|
||||
self.default_input_bit = 1 if bit else 0
|
||||
|
||||
def _record_transmitted_bit(self, bit: int) -> None:
|
||||
self.transmitted_bits.append(bit)
|
||||
if len(self.transmitted_bits) % 8 == 0:
|
||||
byte = 0
|
||||
for data_bit in self.transmitted_bits[-8:]:
|
||||
byte = (byte << 1) | data_bit
|
||||
self.byte_candidates.append(byte)
|
||||
|
||||
Reference in New Issue
Block a user