1
0
This commit is contained in:
Aiden
2026-05-27 21:37:50 +10:00
parent 21f0e455ee
commit 4364d0ed48
54 changed files with 30241 additions and 191 deletions

View File

@@ -278,6 +278,7 @@ def _declarations(tx_candidate: JsonObject | None, rx_candidate: JsonObject | No
"typedef uint8_t u8;",
"typedef uint16_t u16;",
"",
"#define BIT(n) (1u << (n))",
"extern volatile u8 MEM8[0x10000];",
"",
f"#define {channel}_SCR MEM8[{_c_hex(scr)}]",
@@ -424,6 +425,7 @@ def _semantics_lines(
lines.extend(_command_effect_comment_lines(protocol.get("command_effects"), opts, prefix=" * "))
lines.extend(_response_schema_comment_lines(_schema_list(protocol), opts, prefix=" * "))
lines.extend(_table_map_comment_lines(_table_map_list(protocol), opts, prefix=" * "))
lines.extend(_panel_selector_comment_lines(protocol.get("panel_selector_semantics"), opts, prefix=" * "))
lines.extend(_state_variable_comment_lines(protocol.get("state_variable_candidates"), opts, prefix=" * "))
lines.extend(_retry_error_comment_lines(protocol.get("retry_error_model"), opts, prefix=" * "))
lines.extend(_gate_queue_comment_lines(protocol.get("gate_queue_model"), opts, prefix=" * "))
@@ -466,6 +468,8 @@ def _semantics_lines(
)
lines.extend(_gate_queue_predicate_function_lines(protocol.get("gate_queue_model")))
lines.extend(_timer_architecture_function_lines(protocol))
lines.extend(_panel_selector_function_lines(protocol.get("panel_selector_semantics")))
lines.extend(_panel_selector_provisional_function_lines(protocol.get("panel_selector_semantics")))
lines.extend(
[
"void sci1_process_candidate_protocol_command(void)",
@@ -474,6 +478,8 @@ def _semantics_lines(
" u16 logical_index = sci1_rx_candidate_logical_index();",
" u16 value = sci1_rx_candidate_value();",
"",
" sci1_candidate_panel_selector_annotation(logical_index, value);",
"",
],
)
lines.extend(_command_dispatch_switch_lines(commands, opts))
@@ -644,6 +650,70 @@ def _table_map_comment_lines(
return lines
def _panel_selector_comment_lines(
value: object,
opts: SerialPseudocodeOptions,
*,
prefix: str,
) -> list[str]:
selectors = _object_list(value)
if not selectors:
return []
lines = [f"{prefix}panel selector semantics:"]
for selector in selectors[:6]:
selector_hex = selector.get("selector_hex") or _selector_hex(selector.get("selector"))
name = selector.get("name") or "panel_selector"
current = selector.get("current_word_address_hex") or "current table"
dispatch = selector.get("dispatch_handler") or "dispatch unknown"
summary = _comment_text(str(selector.get("summary") or "bench/ROM selector annotation"))
lines.append(f"{prefix}- {selector_hex} {name}: {summary}")
lines.append(f"{prefix} current word: {current}; dispatch: {dispatch}")
for effect in _object_list(selector.get("effects"))[:4]:
mask = effect.get("mask_hex") or _selector_hex(effect.get("mask"))
effect_name = effect.get("name") or "effect"
when_set = _comment_text(str(effect.get("when_set") or "set"))
bits = ", ".join(str(item) for item in effect.get("ram_bits", []))
suffix = f"; RAM {bits}" if bits else ""
lines.append(f"{prefix} {mask} -> {effect_name}: {when_set}{suffix}")
meanings = []
for meaning in _object_list(selector.get("value_meanings"))[:4]:
value_hex = meaning.get("value_hex") or _selector_hex(meaning.get("value"))
label = _comment_text(str(meaning.get("meaning") or "known panel value"))
meanings.append(f"{value_hex} {label}")
if meanings:
lines.append(f"{prefix} observed values: {'; '.join(meanings)}")
state_machine = selector.get("state_machine")
if isinstance(state_machine, dict):
name_candidate = state_machine.get("name_candidate") or "selector_state_machine_candidate"
summary = _comment_text(str(state_machine.get("summary") or "bench-proven selector state-machine candidate"))
lines.append(f"{prefix} state machine: {name_candidate}: {summary}")
active = state_machine.get("active_report_frame")
clear = state_machine.get("clear_report_frame")
ack = state_machine.get("ack_frame")
mirror_active = state_machine.get("active_mirror_frame")
mirror_clear = state_machine.get("clear_mirror_frame")
if active or clear or ack:
lines.append(
f"{prefix} frames: active report {active or '?'}; clear report {clear or '?'}; "
f"ACK {ack or '?'}; mirror active {mirror_active or '?'}; mirror clear {mirror_clear or '?'}"
)
triggers = []
for trigger in _object_list(selector.get("local_triggers"))[:3]:
source = trigger.get("source") or trigger.get("handler") or "local path"
summary = _comment_text(str(trigger.get("summary") or "local trigger candidate"))
name_candidate = trigger.get("name_candidate")
prefix_text = f"{name_candidate} " if name_candidate else ""
triggers.append(f"{prefix_text}{source}: {summary}")
if triggers:
lines.append(f"{prefix} local trigger candidates: {'; '.join(triggers)}")
evidence = ", ".join(str(item) for item in selector.get("evidence", []) if item)
if opts.include_evidence and evidence:
lines.append(f"{prefix} evidence: {_comment_text(evidence)}")
if len(selectors) > 6:
lines.append(f"{prefix}- ... {len(selectors) - 6} more panel selector annotations")
return lines
def _state_variable_comment_lines(
value: object,
opts: SerialPseudocodeOptions,
@@ -955,6 +1025,121 @@ def _timer_architecture_function_lines(protocol: JsonObject) -> list[str]:
)
def _panel_selector_function_lines(value: object) -> list[str]:
selectors = _object_list(value)
if not selectors:
return [
"static void sci1_candidate_panel_selector_annotation(u16 logical_index, u16 value)",
"{",
" (void)logical_index;",
" (void)value;",
"}",
"",
]
lines = [
"static void sci1_candidate_panel_selector_annotation(u16 logical_index, u16 value)",
"{",
" /* Known bench/ROM selector labels. This helper is commentary for the decompile. */",
" switch (logical_index) {",
]
for selector in selectors:
selector_value = selector.get("selector")
if not isinstance(selector_value, int):
continue
selector_hex = selector.get("selector_hex") or f"0x{selector_value:04X}"
name = _comment_text(str(selector.get("name") or "panel selector"))
current = selector.get("current_word_address_hex") or "current table"
dispatch = selector.get("dispatch_handler") or "dispatch unknown"
lines.append(f" case 0x{selector_value & 0x01FF:04X}u:")
lines.append(f" /* {selector_hex} {name}; current word {current}; {dispatch}. */")
for effect in _object_list(selector.get("effects")):
mask = effect.get("mask")
if not isinstance(mask, int):
continue
effect_name = _comment_text(str(effect.get("name") or "panel effect"))
when_set = _comment_text(str(effect.get("when_set") or "set"))
when_clear = _comment_text(str(effect.get("when_clear") or "clear"))
lines.append(f" if ((value & 0x{mask & 0xFFFF:04X}u) != 0u) {{")
lines.append(f" /* {effect_name}: {when_set}. */")
lines.append(" } else {")
lines.append(f" /* {effect_name}: {when_clear}. */")
lines.append(" }")
for meaning in _object_list(selector.get("value_meanings")):
known_value = meaning.get("value")
if not isinstance(known_value, int):
continue
label = _comment_text(str(meaning.get("meaning") or "known panel value"))
lines.append(f" if (value == 0x{known_value & 0xFFFF:04X}u) {{")
lines.append(f" /* {label}. */")
lines.append(" }")
lines.append(" break;")
lines.extend(
[
" default:",
" break;",
" }",
"}",
"",
],
)
return lines
def _panel_selector_provisional_function_lines(value: object) -> list[str]:
selectors = _object_list(value)
lines: list[str] = []
for selector in selectors:
selector_value = selector.get("selector")
if not isinstance(selector_value, int):
continue
state_machine = selector.get("state_machine")
if not isinstance(state_machine, dict):
continue
for trigger in _object_list(selector.get("local_triggers")):
name = str(trigger.get("name_candidate") or "").strip()
if not name:
continue
handler = _comment_text(str(trigger.get("handler") or "handler unknown"))
source = _comment_text(str(trigger.get("source") or "source unknown"))
gate = _comment_text(str(trigger.get("gate") or "gate unknown"))
current_bit = _comment_text(str(trigger.get("current_state_bit") or "current state bit unknown"))
summary = _comment_text(str(trigger.get("summary") or "local trigger candidate"))
active_value = _int_from_object(trigger.get("active_value"), 0x4000)
clear_value = _int_from_object(trigger.get("clear_value"), 0x0000)
active_report = _comment_text(str(state_machine.get("active_report_frame") or "active report unknown"))
clear_report = _comment_text(str(state_machine.get("clear_report_frame") or "clear report unknown"))
ack_frame = _comment_text(str(state_machine.get("ack_frame") or "ACK unknown"))
active_mirror = _comment_text(str(state_machine.get("active_mirror_frame") or "active mirror unknown"))
clear_mirror = _comment_text(str(state_machine.get("clear_mirror_frame") or "clear mirror unknown"))
safe_name = _safe_identifier(name)
lines.extend(
[
f"void {safe_name}(void)",
"{",
f" /* Provisional name for ROM {handler}: {summary} */",
f" /* Source {source}; gate {gate}; current state {current_bit}. */",
" if ((MEM8[0xF6DBu] & BIT(7)) == 0u) {",
" return;",
" }",
" if (MEM8[0xF731u] > 3u) {",
" return;",
" }",
"",
" if ((MEM8[0xF791u] & BIT(5)) == 0u) {",
f" /* Requests selector 0x{selector_value & 0x01FF:04X}=0x{active_value & 0xFFFF:04X}: {active_report}. */",
f" /* CCU should ACK {ack_frame}, then mirror {active_mirror}. */",
" } else {",
f" /* Requests selector 0x{selector_value & 0x01FF:04X}=0x{clear_value & 0xFFFF:04X}: {clear_report}. */",
f" /* CCU should ACK {ack_frame}, then mirror {clear_mirror}. */",
" }",
"}",
"",
],
)
return lines
def _timer_tick_function_lines(function_name: str, counters: list[JsonObject], summary: str) -> list[str]:
lines = [
f"void {function_name}(void)",
@@ -1130,6 +1315,16 @@ def _command_hex(value: object) -> str:
return "?"
def _selector_hex(value: object) -> str:
if isinstance(value, int):
return f"0x{value & 0xFFFF:04X}"
return "?"
def _int_from_object(value: object, default: int) -> int:
return value if isinstance(value, int) else default
def _tx_functions(candidate: JsonObject, opts: SerialPseudocodeOptions) -> list[str]:
length = _int_field(candidate, "frame_length", 6)
seed = _int_field(candidate, "checksum_seed", 0x5A)
@@ -1386,3 +1581,7 @@ def _safe_identifier(value: str) -> str:
def _comment_text(text: str) -> str:
return text.replace("*/", "* /").replace("\r", " ").replace("\n", " ")
if __name__ == "__main__":
raise SystemExit(main())