1
0

Data flow improvements in pseudo code generator

This commit is contained in:
Aiden
2026-05-25 14:40:55 +10:00
parent 80819448cf
commit 1d7f00e59c
16 changed files with 105891 additions and 5141 deletions

View File

@@ -4,8 +4,10 @@ import json
from pathlib import Path
from .cycles import cycle_comment
from .dataflow import state_for_instruction
from .dtc import DtcEndpointInfo, DtcRegisterInfo
from .formatting import h16, label_for
from .indirect import indirect_comment_for_instruction, indirect_metadata_for_instruction
from .memory import MEMORY_REGIONS, region_for
from .model import Instruction
from .peripheral_access import (
@@ -15,6 +17,7 @@ from .peripheral_access import (
)
from .rom import Rom
from .sci import sci_comment_for_instruction, sci_json_payload, sci_metadata_for_instruction
from .symbols import symbol_for_address
from .tables import IO_REGISTERS
from .timing import format_timing_summary
from .vectors import DtcVectorEntry
@@ -55,15 +58,66 @@ def _dtc_register_lines(vector_addr: int, entry: DtcVectorEntry, info: DtcRegist
return lines
def _reference_comment(ins: Instruction) -> str:
def _reference_comment(ins: Instruction, symbols: dict[str, object] | None = None) -> str:
parts: list[str] = []
for address in ins.references:
region = region_for(address)
name = IO_REGISTERS.get(address, h16(address))
name = symbol_for_address(symbols, address) or IO_REGISTERS.get(address, h16(address))
parts.append(f"{name} in {region.name}")
return "refs " + ", ".join(parts) if parts else ""
def _symbol_lines(symbols: dict[str, object] | None) -> list[str]:
if not symbols:
return []
entries = symbols.get("symbols", [])
if not isinstance(entries, list) or not entries:
return []
lines = ["; Symbols"]
for item in entries[:80]:
if not isinstance(item, dict):
continue
address = int(item["address"])
width = item.get("width") or "unknown"
line = (
f"; {item['name']:<16} {h16(address)} {item['region']:<18} {item['kind']:<8} "
f"r={item['read_count']} w={item['write_count']} width={width}"
)
if item.get("xref_count"):
line += f" xrefs={item['xref_count']}"
lines.append(line)
if len(entries) > 80:
lines.append(f"; ... {len(entries) - 80} more symbols omitted from listing header")
lines.append("")
return lines
def _known_change_text(change: dict[str, object]) -> str:
after = change.get("after")
if not isinstance(after, dict) or not after.get("known"):
return ""
value = int(after["value"])
width = int(after.get("width", 16))
digits = 2 if width <= 8 else 4
return f"{change['name']}=H'{value:0{digits}X}"
def _dataflow_comment(analysis: dict[str, object] | None, address: int) -> str:
record = state_for_instruction(analysis, address)
if not record:
return ""
changes = record.get("changes")
if not isinstance(changes, list):
return ""
parts = [_known_change_text(change) for change in changes if isinstance(change, dict)]
parts = [part for part in parts if part]
if not parts:
return ""
suffix = " ..." if len(parts) > 4 else ""
return "dataflow " + ", ".join(parts[:4]) + suffix
def format_listing(
rom_path: Path,
rom: Rom,
@@ -78,6 +132,9 @@ def format_listing(
show_cycles: bool = False,
sci_analysis: dict[str, object] | None = None,
peripheral_access: dict[str, object] | None = None,
indirect_flow: dict[str, object] | None = None,
dataflow: dict[str, object] | None = None,
symbols: dict[str, object] | None = None,
) -> str:
lines: list[str] = []
lines.append("; H8/536 ROM disassembly")
@@ -134,6 +191,8 @@ def format_listing(
)
lines.append("")
lines.extend(_symbol_lines(symbols))
if timing_summary:
lines.extend(format_timing_summary(timing_summary))
@@ -150,7 +209,9 @@ def format_listing(
ins.comment,
sci_comment_for_instruction(sci_analysis, address),
peripheral_comment_for_instruction(peripheral_access, address),
_reference_comment(ins) if not ins.comment else "",
indirect_comment_for_instruction(indirect_flow, address),
_dataflow_comment(dataflow, address),
_reference_comment(ins, symbols) if not ins.comment else "",
cycle_comment(ins.cycles) if show_cycles else "",
)
if part
@@ -172,6 +233,9 @@ def write_json(
timing_summary: dict[str, list[dict[str, object]]] | None = None,
sci_analysis: dict[str, object] | None = None,
peripheral_access: dict[str, object] | None = None,
indirect_flow: dict[str, object] | None = None,
dataflow: dict[str, object] | None = None,
symbols: dict[str, object] | None = None,
) -> None:
payload = {
"vectors": [
@@ -194,18 +258,67 @@ def write_json(
"timing_summary": timing_summary or {"blocks": [], "loops": []},
"sci": sci_json_payload(sci_analysis),
"peripheral_access": peripheral_json_payload(peripheral_access),
"indirect_flow": indirect_flow or {"sites": []},
"dataflow": _dataflow_json_payload(dataflow),
"symbols": symbols or {"symbols": [], "by_address": {}},
"instructions": [
_instruction_payload(ins, sci_analysis, peripheral_access)
_instruction_payload(ins, sci_analysis, peripheral_access, indirect_flow, dataflow, symbols)
for ins in (instructions[addr] for addr in sorted(instructions))
],
}
path.write_text(json.dumps(payload, indent=2), encoding="utf-8")
def _dataflow_json_payload(dataflow: dict[str, object] | None) -> dict[str, object]:
if not dataflow:
return {"blocks": [], "registers": [], "control_registers": []}
return {
"blocks": dataflow.get("blocks", []),
"registers": dataflow.get("registers", []),
"control_registers": dataflow.get("control_registers", []),
}
def _compact_known_values(state: object) -> dict[str, dict[str, object]]:
if not isinstance(state, dict):
return {}
compact: dict[str, dict[str, object]] = {}
for group_name in ("registers", "control"):
group = state.get(group_name)
if not isinstance(group, dict):
continue
values = {
name: value
for name, value in group.items()
if isinstance(value, dict) and value.get("known")
}
if values:
compact[group_name] = values
return compact
def _dataflow_instruction_payload(dataflow: dict[str, object] | None, address: int) -> dict[str, object]:
record = state_for_instruction(dataflow, address)
if not record:
return {}
payload: dict[str, object] = {
"block": record.get("block"),
"changes": record.get("changes", []),
"notes": record.get("notes", []),
}
known_after = _compact_known_values(record.get("after"))
if known_after:
payload["known_after"] = known_after
return payload
def _instruction_payload(
ins: Instruction,
sci_analysis: dict[str, object] | None = None,
peripheral_access: dict[str, object] | None = None,
indirect_flow: dict[str, object] | None = None,
dataflow: dict[str, object] | None = None,
symbols: dict[str, object] | None = None,
) -> dict[str, object]:
payload: dict[str, object] = {
"address": ins.address,
@@ -221,6 +334,7 @@ def _instruction_payload(
{
"address": address,
"name": IO_REGISTERS.get(address),
"symbol": symbol_for_address(symbols, address),
"region": region_for(address).name,
"kind": region_for(address).kind,
}
@@ -235,6 +349,12 @@ def _instruction_payload(
peripheral_metadata = peripheral_metadata_for_instruction(peripheral_access, ins.address)
if peripheral_metadata:
payload["peripheral_access"] = peripheral_metadata
indirect_metadata = indirect_metadata_for_instruction(indirect_flow, ins.address)
if indirect_metadata:
payload["indirect_flow"] = indirect_metadata
dataflow_metadata = _dataflow_instruction_payload(dataflow, ins.address)
if dataflow_metadata:
payload["dataflow"] = dataflow_metadata
return payload