from __future__ import annotations import argparse from pathlib import Path from ..formatting import h16, parse_int from .memory import describe_regions from .runner import H8536Emulator def discover_rom_path(root: Path) -> Path | None: candidates = [ root / "ROM" / "M27C512@DIP28_1.BIN", root / "rom.bin", ] candidates.extend(sorted((root / "ROM").glob("*.BIN")) if (root / "ROM").exists() else []) candidates.extend(sorted((root / "ROM").glob("*.bin")) if (root / "ROM").exists() else []) for candidate in candidates: if candidate.is_file(): return candidate return None def load_rom(path: Path | None = None, root: Path | None = None) -> tuple[bytes, Path]: root = root if root is not None else Path.cwd() rom_path = path if path is not None else discover_rom_path(root) if rom_path is None: raise FileNotFoundError( "could not discover ROM bytes; pass --rom PATH, expected ROM/M27C512@DIP28_1.BIN or another ROM/*.BIN" ) return rom_path.read_bytes(), rom_path def build_arg_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser(description="Minimal H8/536 emulation harness scaffold") parser.add_argument("--rom", type=Path, help="ROM image path; defaults to ROM/M27C512@DIP28_1.BIN when present") parser.add_argument("--max-steps", type=int, default=64, help="maximum CPU steps to execute") parser.add_argument("--trace", action="store_true", help="print decoded/executed instruction trace") parser.add_argument("--stop-on-heartbeat", action="store_true", help="stop only when 00 00 00 00 80 DA is emitted through SCI1 TDR") parser.add_argument("--memory-map", action="store_true", help="print the scaffolded memory map before running") parser.add_argument("--interval-steps", type=int, default=2048, help="rough step period for the scaffolded timer interrupt") parser.add_argument("--frt2-ocia-steps", type=int, default=1024, help="rough step period for the scaffolded FRT2 OCIA interrupt") parser.add_argument("--p9-fast-path", action="store_true", help="shortcut known P9 bit-banged transfer routines for exploration") parser.add_argument("--p9-fast-input", type=parse_int, default=0xFF, help="default byte returned by the P9 fast-path read routine") return parser def main(argv: list[str] | None = None) -> int: args = build_arg_parser().parse_args(argv) try: rom_bytes, rom_path = load_rom(args.rom) except FileNotFoundError as exc: print(str(exc)) return 2 emulator = H8536Emulator( rom_bytes, interval_steps=args.interval_steps, frt2_ocia_steps=args.frt2_ocia_steps, p9_fast_path_enabled=args.p9_fast_path, p9_fast_default_input_byte=args.p9_fast_input, ) print(f"rom={rom_path}") print(f"reset_vector={h16(emulator.reset_vector())}") if args.memory_map: print(describe_regions()) report = emulator.run(args.max_steps, trace=args.trace, stop_on_heartbeat=args.stop_on_heartbeat) if args.trace: for line in report.trace: print(line) for line in report.summary_lines(): print(line) if not report.heartbeat_seen: print("heartbeat_status=not reached; no heartbeat is reported unless bytes are emitted via SCI1_TDR") return 0