Intial commit
This commit is contained in:
84
h8536/cli.py
Normal file
84
h8536/cli.py
Normal file
@@ -0,0 +1,84 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
from .analysis import collect_labels, linear_sweep, trace
|
||||
from .decoder import H8536Decoder
|
||||
from .formatting import parse_int
|
||||
from .render import format_listing, write_json
|
||||
from .rom import Rom
|
||||
from .vectors import read_dtc_vectors_max, read_dtc_vectors_min, read_vectors_max, read_vectors_min
|
||||
|
||||
|
||||
def default_end(data: bytes) -> int:
|
||||
last = 0
|
||||
for idx, value in enumerate(data):
|
||||
if value != 0xFF:
|
||||
last = idx
|
||||
return min(len(data), ((last + 0x100) // 0x100) * 0x100)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Disassemble/decompile a Hitachi H8/536 ROM image.")
|
||||
parser.add_argument("rom", nargs="?", default="ROM/M27C512@DIP28_1.BIN", type=Path, help="ROM binary to decode")
|
||||
parser.add_argument("--out", type=Path, default=Path("build/rom_decompiled.asm"), help="assembly listing output")
|
||||
parser.add_argument("--json", type=Path, default=None, help="optional structured JSON output")
|
||||
parser.add_argument("--mode", choices=("min", "max"), default="min", help="CPU/vector mode; this ROM appears to be min")
|
||||
parser.add_argument("--start", type=parse_int, default=0x0000, help="decode lower address limit")
|
||||
parser.add_argument("--end", type=parse_int, default=None, help="decode upper address limit, exclusive")
|
||||
parser.add_argument("--entry", type=parse_int, action="append", default=[], help="extra entry point to trace")
|
||||
parser.add_argument("--br", type=parse_int, default=None, help="optional BR value for @aa:8 short absolute operands")
|
||||
parser.add_argument("--linear", action="store_true", help="linear-sweep the selected range instead of tracing from vectors")
|
||||
args = parser.parse_args()
|
||||
|
||||
data = args.rom.read_bytes()
|
||||
rom = Rom(data)
|
||||
end = args.end if args.end is not None else default_end(data)
|
||||
|
||||
vectors = read_vectors_min(rom) if args.mode == "min" else read_vectors_max(rom)
|
||||
dtc_vectors = read_dtc_vectors_min(rom) if args.mode == "min" else read_dtc_vectors_max(rom)
|
||||
starts = [target for _name, target in vectors.values()] + args.entry
|
||||
|
||||
labels: dict[int, str] = {}
|
||||
decoder = H8536Decoder(rom, br=args.br, labels=labels)
|
||||
decoder.br = args.br
|
||||
if args.linear:
|
||||
instructions = linear_sweep(decoder, args.start, end)
|
||||
else:
|
||||
instructions = trace(decoder, starts, args.start, end)
|
||||
|
||||
labels.update(collect_labels(instructions.values(), vectors))
|
||||
decoder.labels = labels
|
||||
|
||||
# Re-decode now that labels are known, so operands can use stable symbols.
|
||||
decoder.br = args.br
|
||||
if args.linear:
|
||||
instructions = linear_sweep(decoder, args.start, end)
|
||||
else:
|
||||
instructions = trace(decoder, starts, args.start, end)
|
||||
labels.update(collect_labels(instructions.values(), vectors))
|
||||
|
||||
args.out.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.out.write_text(
|
||||
format_listing(
|
||||
args.rom,
|
||||
rom,
|
||||
instructions,
|
||||
vectors,
|
||||
labels,
|
||||
args.mode,
|
||||
traced=not args.linear,
|
||||
dtc_vectors=dtc_vectors,
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
if args.json:
|
||||
args.json.parent.mkdir(parents=True, exist_ok=True)
|
||||
write_json(args.json, instructions, vectors, labels, dtc_vectors=dtc_vectors)
|
||||
|
||||
invalid = sum(1 for ins in instructions.values() if not ins.valid)
|
||||
print(f"wrote {args.out} ({len(instructions)} items, {invalid} invalid/data bytes)")
|
||||
if args.json:
|
||||
print(f"wrote {args.json}")
|
||||
return 0
|
||||
Reference in New Issue
Block a user