1
0

Emulator learnings folded back into decompiler

This commit is contained in:
Aiden
2026-05-25 19:11:22 +10:00
parent 1fabf6587d
commit d2e7609bbf
16 changed files with 1468 additions and 87 deletions

View File

@@ -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);",