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

@@ -17,6 +17,7 @@ KEY_STATE_ADDRESSES: tuple[int, ...] = (
0xF9B5,
0xF9B9,
0xF9C0,
0xF9C1,
0xF9C3,
0xF9C5,
0xF9C6,
@@ -51,6 +52,7 @@ def analyze_serial_gate(payload: dict[str, Any]) -> JsonObject:
"queue_send_gate_loc_BAF2": _queue_send_gate(by_address),
"resend_gate_path": _resend_gate_path(by_address),
"rx_session_maintenance": _rx_session_maintenance(by_address),
"timer_tick_evidence": _timer_tick_evidence(payload, by_address),
}
access_summary = _state_access_summary(instructions, labels)
@@ -94,6 +96,11 @@ def format_text_report(analysis: dict[str, Any]) -> str:
lines.append(f" {summary}")
for item in section.get("items", []):
lines.append(f" - {item['address_hex']}: {item['text']}")
roles = section.get("candidate_timer_roles", [])
if roles:
lines.append(" Candidate timer roles:")
for role in roles:
lines.append(f" - {role['address_hex']}: {role['role']}")
lines.extend(["", "State address readers/writers:"])
for entry in analysis.get("state_accesses", []):
@@ -266,6 +273,53 @@ def _rx_session_maintenance(by_address: dict[int, JsonObject]) -> JsonObject:
}
def _timer_tick_evidence(payload: dict[str, Any], by_address: dict[int, JsonObject]) -> JsonObject:
vector = _vector_entry(payload, 0x0062, "frt1_ocia")
handler = _int_field(vector, "target") if vector else None
if handler is None:
handler = 0xBEEA
addresses = [handler, 0xBEEE, 0xBEF4, 0xBEF8, 0xBEFE, 0xBF02, 0xBF08]
has_vector = vector is not None and _int_field(vector, "target") == handler
has_handler_clear = _instruction_mentions(by_address.get(handler), ("FRT1_TCSR", "#5"))
decrement_addresses = (0xBEF4, 0xBEFE, 0xBF08)
has_decrements = all(
address in by_address and _access_kind(by_address[address], state_address) == "read_write"
for address, state_address in zip(decrement_addresses, (0xF9C0, 0xF9C1, 0xF9C6))
)
return {
"title": "FRT1 OCIA periodic tick countdowns",
"present": bool((has_vector or has_handler_clear) and has_decrements),
"summary": (
"Static evidence links vector H'0062 to the FRT1 OCIA handler at H'BEEA; the handler "
"clears FRT1_TCSR.OCFA and conditionally decrements H'F9C0, H'F9C1, and H'F9C6."
),
"vector_address_hex": h16(0x0062),
"handler_address_hex": h16(handler),
"vector_target_label": str(vector.get("target_label", "")) if vector else "",
"items": _items(by_address, addresses),
"candidate_timer_roles": [
{
"address": 0xF9C0,
"address_hex": h16(0xF9C0),
"role": "candidate post-TX/report delay countdown",
"evidence_address_hex": h16(0xBEF4),
},
{
"address": 0xF9C1,
"address_hex": h16(0xF9C1),
"role": "candidate secondary delay countdown",
"evidence_address_hex": h16(0xBEFE),
},
{
"address": 0xF9C6,
"address_hex": h16(0xF9C6),
"role": "candidate periodic report/heartbeat countdown",
"evidence_address_hex": h16(0xBF08),
},
],
}
def _state_access_summary(instructions: list[JsonObject], labels: dict[int, str]) -> list[JsonObject]:
result: list[JsonObject] = []
for state_address in KEY_STATE_ADDRESSES:
@@ -333,6 +387,32 @@ def _has_all(by_address: dict[int, JsonObject], addresses: tuple[int, ...]) -> b
return all(address in by_address for address in addresses)
def _vector_entry(payload: dict[str, Any], address: int, name: str) -> JsonObject | None:
vectors = payload.get("vectors", [])
if not isinstance(vectors, list):
return None
for vector in vectors:
if not isinstance(vector, dict):
continue
if _int_field(vector, "address") == address or str(vector.get("name", "")).lower() == name:
return vector
return None
def _int_field(payload: JsonObject | None, key: str, default: int | None = None) -> int | None:
if not isinstance(payload, dict):
return default
value = payload.get(key)
return value if isinstance(value, int) else default
def _instruction_mentions(ins: JsonObject | None, fragments: tuple[str, ...]) -> bool:
if not isinstance(ins, dict):
return False
text = f"{ins.get('text', '')} {ins.get('operands', '')} {ins.get('comment', '')}".upper()
return all(fragment.upper() in text for fragment in fragments)
def _text(by_address: dict[int, JsonObject], address: int) -> str:
return str(by_address.get(address, {}).get("text", "<missing>"))