#!/usr/bin/env python3 """Build one scheduler bootlet that preloads the distinct CLUTs required by several fixture tags. Usage: gs_merge_scheduler_bootlets.py [ ...] """ import os import re import sys HERE = os.path.dirname(os.path.abspath(__file__)) ROOT = os.path.normpath(os.path.join(HERE, "..")) DATA = os.path.join(ROOT, "sim", "data", "top_psmct32_raster_demo") sys.path.insert(0, DATA) import bake RAM_QWORDS = 512 HEADER_QWORDS = 16 FBW = 10 FBPXW = 640 FBH = 480 def read_payload(tag): path = os.path.join(DATA, f"payload_sh3_{tag}.mem") with open(path) as f: lines = f.readlines() header = next((line for line in lines if line.startswith("//")), "") match = re.search(r"QWC=(\d+)", header) if not match: raise ValueError(f"{path}: missing QWC metadata") cbp_match = re.search(r"CBPs \[([^]]*)\]", header) if not cbp_match: raise ValueError(f"{path}: missing CBP metadata") cbps = [int(x.strip()) for x in cbp_match.group(1).split(",") if x.strip()] words = [int(line.strip(), 16) for line in lines if line.strip() and not line.startswith("//")] if len(words) != RAM_QWORDS: raise ValueError(f"{path}: expected {RAM_QWORDS} qwords, got {len(words)}") qwc = int(match.group(1)) if qwc > RAM_QWORDS - HEADER_QWORDS: raise ValueError(f"{path}: QWC {qwc} exceeds payload capacity") return qwc, cbps, words[HEADER_QWORDS:HEADER_QWORDS + qwc] def main(argv): if len(argv) < 4: print(__doc__.strip()) return 2 output_tag, input_tags = argv[1], argv[2:] active = [] seen_cbps = set() for tag in input_tags: qwc, cbps, words = read_payload(tag) for cbp in set(cbps): if cbp in seen_cbps: raise ValueError(f"duplicate relocated CBP {cbp}: fixture {tag} aliases an earlier input") seen_cbps.add(cbp) if len(words) != qwc: raise ValueError(f"payload word count mismatch for {tag}") active.extend(words) if len(active) > RAM_QWORDS - HEADER_QWORDS: raise ValueError(f"combined QWC {len(active)} exceeds {RAM_QWORDS - HEADER_QWORDS}") payload_name = f"payload_sh3_{output_tag}.mem" bios_name = f"bios_sh3_{output_tag}.mem" with open(os.path.join(DATA, payload_name), "w") as f: f.write(f"// combined scheduler CLUT preload tags={input_tags} CBPs={sorted(seen_cbps)} QWC={len(active)}. gitignored.\n") for _ in range(HEADER_QWORDS): f.write("00000000000000000000000000000000\n") for word in active: f.write(f"{word:032x}\n") for _ in range(RAM_QWORDS - HEADER_QWORDS - len(active)): f.write("00000000000000000000000000000000\n") display1_hi = ((FBH - 1) << 12) | (FBPXW - 1) bake.write_bios_mem( bios_name, bake.build_textured_demo_bootlet_disp(len(active), display1_hi, FBW), f"combined scheduler CLUT preload tags={input_tags} QWC={len(active)} DISPLAY1={FBPXW}x{FBH}. gitignored.", ) print(f"[bootlet] emitted {bios_name} + {payload_name}: QWC={len(active)} CBPs={sorted(seen_cbps)}") return 0 if __name__ == "__main__": raise SystemExit(main(sys.argv))