Data flow improvements in pseudo code generator
This commit is contained in:
128
h8536/render.py
128
h8536/render.py
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user