1
0

more serial improvements

This commit is contained in:
Aiden
2026-05-25 16:32:58 +10:00
parent 6ceed81765
commit 56829b6e0b
10 changed files with 16843 additions and 122 deletions

View File

@@ -7,6 +7,7 @@ from .model import Instruction
SCI1_TDR_ADDRESS = 0xFEDB
SCI1_SSR_ADDRESS = 0xFEDC
SCI1_RDR_ADDRESS = 0xFEDD
TX_BUFFER_START = 0xF858
TX_CHECKSUM_ADDRESS = 0xF85D
@@ -24,6 +25,7 @@ RX_INDEX_ADDRESS = 0xF9C3
RX_INTERBYTE_TIMEOUT_ADDRESS = 0xF9C1
RX_COMPLETE_TIMER_ADDRESS = 0xF9C5
RX_FRAME_LENGTH = 6
RX_ERROR_LATCH_ADDRESS = 0xFAA4
_BUFFER_DATA_END = TX_CHECKSUM_ADDRESS - 1
_MIN_BUFFER_REFERENCES = 3
@@ -265,6 +267,41 @@ def _collect_rx_evidence(ordered: list[Instruction]) -> list[dict[str, object]]:
),
)
rdrf_before_rdr = _rx_rdrf_clear_before_rdr_read(ordered)
if rdrf_before_rdr:
evidence.append(
_evidence(
"rx_rdrf_clear_before_rdr_read",
rdrf_before_rdr,
summary=(
"ROM clears SCI1 SSR.RDRF before reading SCI1_RDR; preserve this observed "
"ordering even though the manual describes the canonical RDR-read then "
"RDRF-clear sequence"
),
manual_references=[
"Manual/0900766b802125d0.md:16652 RDRF clear sequence reads RDR before clearing RDRF",
"Manual/0900766b802125d0.md:16926 canonical receive flag clear sequence",
],
),
)
eri_fallthrough = _rx_eri_fallthrough_sequence(ordered)
if eri_fallthrough:
evidence.append(
_evidence(
"rx_eri_falls_through_to_rxi",
eri_fallthrough,
summary=(
"SCI1 ERI latches FAA4.bit7, clears ORER/FER/PER, then falls through into "
"the same RXI byte-capture path"
),
manual_references=[
"Manual/0900766b802125d0.md:16703 FER/PER transfer errored data to RDR; ORER does not",
"Manual/0900766b802125d0.md:16936 ERI is requested on ORER, FER, or PER",
],
),
)
indexed_stores = [ins for ins in ordered if _is_indexed_capture_store(ins)]
if indexed_stores:
evidence.append(
@@ -435,6 +472,17 @@ def _rx_candidate_from_evidence(evidence: list[dict[str, object]]) -> dict[str,
key: list(evidence_by_key[key]["addresses"])
for key in _RX_REQUIRED_EVIDENCE
}
optional_evidence_keys = [
key
for key in (
"rx_rdrf_clear_before_rdr_read",
"rx_eri_falls_through_to_rxi",
)
if key in evidence_by_key
]
for key in optional_evidence_keys:
evidence_addresses[key] = list(evidence_by_key[key]["addresses"])
return {
"id": "sci1_rx_frame_f868_len6_candidate",
"kind": "candidate_sci1_rx_frame",
@@ -469,13 +517,18 @@ def _rx_candidate_from_evidence(evidence: list[dict[str, object]]) -> dict[str,
"caveat": "candidate frame means six consecutive bytes within the observed RX timing/state machine, not a proven delimited packet",
"required_evidence_count": len(_RX_REQUIRED_EVIDENCE),
"observed_evidence_count": len(_RX_REQUIRED_EVIDENCE),
"optional_evidence_count": len(optional_evidence_keys),
"missing_evidence": [],
"evidence_addresses": evidence_addresses,
"evidence_addresses_hex": {
key: [h16(address) for address in addresses]
for key, addresses in evidence_addresses.items()
},
"evidence": [evidence_by_key[key] for key in _RX_REQUIRED_EVIDENCE],
"evidence": [
evidence_by_key[key]
for key in [*_RX_REQUIRED_EVIDENCE, *optional_evidence_keys]
],
"rx_error_handling": _rx_error_handling_candidate(evidence_by_key),
"short_comment": (
f"candidate/evidence-supported SCI1 {RX_FRAME_LENGTH}-byte RX frame; "
f"capture {h16(RX_CAPTURE_START)}-{h16(RX_CAPTURE_END)}, validate "
@@ -708,6 +761,100 @@ def _rx_xor_checksum_validation(ordered: list[Instruction]) -> list[Instruction]
return []
def _rx_rdrf_clear_before_rdr_read(ordered: list[Instruction]) -> list[Instruction]:
for index, ins in enumerate(ordered):
if not _is_bclr_bit(ins, SCI1_SSR_ADDRESS, 6):
continue
window = ordered[index + 1:index + 5]
for candidate in window:
if _mnemonic_root(candidate.mnemonic) in {"RTE", "RTS"}:
break
if _is_read_from_address(candidate, SCI1_RDR_ADDRESS):
return [ins, candidate]
return []
def _rx_eri_fallthrough_sequence(ordered: list[Instruction]) -> list[Instruction]:
for index, ins in enumerate(ordered):
if not _is_bset_bit(ins, RX_ERROR_LATCH_ADDRESS, 7):
continue
window = ordered[index:index + 18]
if any(_mnemonic_root(candidate.mnemonic) in {"RTE", "RTS"} for candidate in window[:6]):
continue
error_clears: list[Instruction] = []
for bit in (5, 4, 3):
clear = next(
(
candidate for candidate in window
if _is_bclr_bit(candidate, SCI1_SSR_ADDRESS, bit)
),
None,
)
if clear is not None:
error_clears.append(clear)
if len(error_clears) != 3:
continue
after_error = [
candidate for candidate in window
if candidate.address > max(clear.address for clear in error_clears)
]
byte_path = _rx_rdrf_clear_before_rdr_read(after_error)
if byte_path:
return _dedupe_instructions([ins, *error_clears, *byte_path])
return []
def _rx_error_handling_candidate(evidence_by_key: Mapping[str, dict[str, object]]) -> dict[str, object] | None:
fallthrough = evidence_by_key.get("rx_eri_falls_through_to_rxi")
clear_order = evidence_by_key.get("rx_rdrf_clear_before_rdr_read")
if fallthrough is None and clear_order is None:
return None
evidence_items = [
item for item in (fallthrough, clear_order) if isinstance(item, Mapping)
]
evidence_addresses = _dedupe_ints(
int(address)
for item in evidence_items
for address in item.get("addresses", [])
if isinstance(address, int)
)
return {
"kind": "sci1_rx_error_handling_candidate",
"error_latch_address": RX_ERROR_LATCH_ADDRESS,
"error_latch_address_hex": h16(RX_ERROR_LATCH_ADDRESS),
"error_latch_bit": 7,
"fallthrough_to_rx_byte_path": fallthrough is not None,
"rdrf_clear_before_rdr_read": clear_order is not None,
"summary": (
"SCI1 ERI appears to mark a physical receive error and continue into the RXI "
"byte-capture path; the RXI path clears RDRF before reading RDR in the ROM order."
),
"manual_caveat": (
"Manual text distinguishes ORER from FER/PER data transfer into RDR and describes "
"the normal RDR-read then RDRF-clear ordering; this output preserves the observed ROM order."
),
"evidence_addresses": evidence_addresses,
"evidence_addresses_hex": [h16(address) for address in evidence_addresses],
"confidence": "candidate-medium" if fallthrough else "candidate-low",
}
def _is_bclr_bit(ins: Instruction, address: int, bit: int) -> bool:
return (
_mnemonic_root(ins.mnemonic) == "BCLR"
and _is_write_to_address(ins, address)
and _immediate_source_value(ins.operands) == bit
)
def _is_bset_bit(ins: Instruction, address: int, bit: int) -> bool:
return (
_mnemonic_root(ins.mnemonic) == "BSET"
and _is_write_to_address(ins, address)
and _immediate_source_value(ins.operands) == bit
)
def _is_read_from_address(ins: Instruction, address: int) -> bool:
source, destination = _source_destination_operands(ins.operands)
if _operand_mentions_address(source, address):
@@ -792,6 +939,17 @@ def _dedupe_instructions(instructions: list[Instruction]) -> list[Instruction]:
return output
def _dedupe_ints(values: Iterable[int]) -> list[int]:
output: list[int] = []
seen: set[int] = set()
for value in values:
if value in seen:
continue
seen.add(value)
output.append(value)
return output
def _instruction_sequence(
instructions: Mapping[int, Instruction] | Iterable[Instruction],
) -> list[Instruction]:
@@ -837,9 +995,12 @@ def _operand_mentions_address(operand: str, address: int) -> bool:
operand_upper = operand.upper().replace(" ", "")
names = {
SCI1_TDR_ADDRESS: ("SCI1_TDR",),
SCI1_SSR_ADDRESS: ("SCI1_SSR",),
SCI1_RDR_ADDRESS: ("SCI1_RDR",),
TX_BUFFER_START: ("TX_BUFFER",),
TX_CHECKSUM_ADDRESS: ("TX_CHECKSUM",),
TX_INDEX_ADDRESS: ("TX_INDEX",),
RX_ERROR_LATCH_ADDRESS: ("RX_ERROR_LATCH",),
}
if any(name in operand_upper for name in names.get(address, ())):
return True