more serial improvements
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user