Emulator learnings folded back into decompiler
This commit is contained in:
@@ -301,11 +301,17 @@ def _declarations(tx_candidate: JsonObject | None, rx_candidate: JsonObject | No
|
||||
tx_start = _int_field(tx_candidate, "buffer_start", 0xF858)
|
||||
tx_index = _int_field(tx_candidate, "tx_index_address", 0xF9C2)
|
||||
length = _int_field(tx_candidate, "frame_length", 6)
|
||||
checksum_index = max(length - 1, 0)
|
||||
lines.extend(
|
||||
[
|
||||
f"#define TX_FRAME_LENGTH {length}u",
|
||||
f"#define SCI1_TX_FRAME_LENGTH {length}u",
|
||||
f"#define SCI1_TX_FRAME_BASE {_c_hex(tx_start)}",
|
||||
"#define SCI1_TX_FRAME_BYTE(n) MEM8[(u16)(SCI1_TX_FRAME_BASE + (n))]",
|
||||
f"#define SCI1_TX_FRAME_CHECKSUM SCI1_TX_FRAME_BYTE({checksum_index}u)",
|
||||
f"#define SCI1_TX_INDEX MEM8[{_c_hex(tx_index)}]",
|
||||
"#define TX_FRAME_LENGTH SCI1_TX_FRAME_LENGTH",
|
||||
f"#define TX_FRAME(n) MEM8[(u16)({_c_hex(tx_start)} + (n))]",
|
||||
f"#define TX_INDEX MEM8[{_c_hex(tx_index)}]",
|
||||
"#define TX_INDEX SCI1_TX_INDEX",
|
||||
"",
|
||||
],
|
||||
)
|
||||
@@ -407,6 +413,7 @@ def _semantics_lines(
|
||||
lines.extend(_gate_queue_comment_lines(protocol.get("gate_queue_model"), opts, prefix=" * "))
|
||||
lines.extend(_tx_report_comment_lines(protocol.get("tx_report_model"), opts, prefix=" * "))
|
||||
lines.extend(_periodic_resend_comment_lines(protocol.get("periodic_resend_model"), opts, prefix=" * "))
|
||||
lines.extend(_timer_architecture_comment_lines(protocol, opts, prefix=" * "))
|
||||
lines.append(" */")
|
||||
lines.append("")
|
||||
|
||||
@@ -442,6 +449,7 @@ def _semantics_lines(
|
||||
],
|
||||
)
|
||||
lines.extend(_gate_queue_predicate_function_lines(protocol.get("gate_queue_model")))
|
||||
lines.extend(_timer_architecture_function_lines(protocol))
|
||||
lines.extend(
|
||||
[
|
||||
"void sci1_process_candidate_protocol_command(void)",
|
||||
@@ -741,6 +749,123 @@ def _periodic_resend_comment_lines(
|
||||
return lines
|
||||
|
||||
|
||||
def _timer_architecture_comment_lines(
|
||||
protocol: JsonObject,
|
||||
opts: SerialPseudocodeOptions,
|
||||
*,
|
||||
prefix: str,
|
||||
) -> list[str]:
|
||||
model = _timer_architecture_model(protocol)
|
||||
if not model:
|
||||
return []
|
||||
|
||||
vector = str(model.get("vector_address_hex") or "H'BEEA")
|
||||
source = str(model.get("source") or "FRT1 OCIA")
|
||||
lines = [f"{prefix}interrupt/timer architecture candidate:"]
|
||||
lines.append(
|
||||
f"{prefix}- {source} {vector} appears to be a periodic tick ISR for serial gate/cadence counters.",
|
||||
)
|
||||
counters = _timer_counter_models(model)
|
||||
for counter in counters:
|
||||
address = counter.get("address_hex") or _h(_int_field(counter, "address", 0))
|
||||
name = counter.get("name_candidate") or "counter_candidate"
|
||||
role = _comment_text(str(counter.get("role") or counter.get("summary") or "candidate decrementing counter"))
|
||||
lines.append(f"{prefix}- {address} {name}: {role}")
|
||||
evidence = _hex_join(model.get("evidence_addresses_hex"))
|
||||
if opts.include_evidence and evidence:
|
||||
lines.append(f"{prefix}- evidence: {evidence}")
|
||||
return lines
|
||||
|
||||
|
||||
def _timer_architecture_function_lines(protocol: JsonObject) -> list[str]:
|
||||
model = _timer_architecture_model(protocol)
|
||||
if not model:
|
||||
return []
|
||||
counters = _timer_counter_models(model)
|
||||
if not counters:
|
||||
return []
|
||||
|
||||
lines = [
|
||||
"void frt1_ocia_candidate_tick_isr(void)",
|
||||
"{",
|
||||
" /* Candidate periodic tick at H'BEEA: decrement nonzero serial gate/cadence counters. */",
|
||||
]
|
||||
for counter in counters:
|
||||
address = _int_field(counter, "address", 0)
|
||||
if address == 0:
|
||||
continue
|
||||
name = _safe_identifier(str(counter.get("name_candidate") or f"counter_{address:04X}")).upper()
|
||||
lines.extend(
|
||||
[
|
||||
f" /* {name}: {_comment_text(str(counter.get('role') or counter.get('summary') or 'candidate counter'))} */",
|
||||
f" if (MEM8[{_c_hex(address)}] != 0u) {{",
|
||||
f" MEM8[{_c_hex(address)}] = (u8)(MEM8[{_c_hex(address)}] - 1u);",
|
||||
" }",
|
||||
"",
|
||||
],
|
||||
)
|
||||
lines.extend(["}", ""])
|
||||
return lines
|
||||
|
||||
|
||||
def _timer_architecture_model(protocol: JsonObject) -> JsonObject:
|
||||
model = protocol.get("timer_interrupt_model")
|
||||
if isinstance(model, dict):
|
||||
return model
|
||||
if isinstance(protocol.get("gate_queue_model"), dict) or isinstance(protocol.get("periodic_resend_model"), dict):
|
||||
return {
|
||||
"source": "FRT1 OCIA",
|
||||
"vector_address_hex": "H'BEEA",
|
||||
"counters": [
|
||||
{
|
||||
"address": 0xF9C0,
|
||||
"address_hex": "H'F9C0",
|
||||
"name_candidate": "tx_report_gate_counter_candidate",
|
||||
"role": "candidate gate counter used before entering the report builder.",
|
||||
},
|
||||
{
|
||||
"address": 0xF9C1,
|
||||
"address_hex": "H'F9C1",
|
||||
"name_candidate": "rx_interbyte_timeout_candidate",
|
||||
"role": "candidate RX interbyte timeout counter.",
|
||||
},
|
||||
{
|
||||
"address": 0xF9C6,
|
||||
"address_hex": "H'F9C6",
|
||||
"name_candidate": "periodic_resend_cadence_counter_candidate",
|
||||
"role": "candidate periodic resend/heartbeat cadence counter.",
|
||||
},
|
||||
],
|
||||
}
|
||||
return {}
|
||||
|
||||
|
||||
def _timer_counter_models(model: JsonObject) -> list[JsonObject]:
|
||||
counters = _object_list(model.get("counters"))
|
||||
if counters:
|
||||
return counters
|
||||
return [
|
||||
{
|
||||
"address": 0xF9C0,
|
||||
"address_hex": "H'F9C0",
|
||||
"name_candidate": "tx_report_gate_counter_candidate",
|
||||
"role": "candidate gate counter used before entering the report builder.",
|
||||
},
|
||||
{
|
||||
"address": 0xF9C1,
|
||||
"address_hex": "H'F9C1",
|
||||
"name_candidate": "rx_interbyte_timeout_candidate",
|
||||
"role": "candidate RX interbyte timeout counter.",
|
||||
},
|
||||
{
|
||||
"address": 0xF9C6,
|
||||
"address_hex": "H'F9C6",
|
||||
"name_candidate": "periodic_resend_cadence_counter_candidate",
|
||||
"role": "candidate periodic resend/heartbeat cadence counter.",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def _command_effect_switch_lines(command: JsonObject) -> list[str]:
|
||||
effects = _object_list(command.get("effects"))[:3]
|
||||
lines = []
|
||||
@@ -835,6 +960,7 @@ def _tx_functions(candidate: JsonObject, opts: SerialPseudocodeOptions) -> list[
|
||||
" /* wait for transmit data register empty */",
|
||||
" }",
|
||||
"",
|
||||
" /* First byte is sent synchronously; TIE enables TXI for the remaining bytes. */",
|
||||
" SCI1_TDR = TX_FRAME(0);",
|
||||
" TX_INDEX = 1u;",
|
||||
" SCI1_SSR &= (u8)~SCI_SSR_TDRE;",
|
||||
@@ -843,6 +969,11 @@ def _tx_functions(candidate: JsonObject, opts: SerialPseudocodeOptions) -> list[
|
||||
"",
|
||||
"void sci1_txi_candidate_isr(void)",
|
||||
"{",
|
||||
" /* TXI runs after hardware reasserts SSR.TDRE for the next transmit byte. */",
|
||||
" if ((SCI1_SSR & SCI_SSR_TDRE) == 0u) {",
|
||||
" return;",
|
||||
" }",
|
||||
"",
|
||||
" if (TX_INDEX < TX_FRAME_LENGTH) {",
|
||||
" SCI1_TDR = TX_FRAME(TX_INDEX);",
|
||||
" TX_INDEX = (u8)(TX_INDEX + 1u);",
|
||||
|
||||
Reference in New Issue
Block a user