summaryrefslogtreecommitdiffstats
path: root/tools/mme-audit/mme_audit.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/mme-audit/mme_audit.py')
-rw-r--r--tools/mme-audit/mme_audit.py570
1 files changed, 570 insertions, 0 deletions
diff --git a/tools/mme-audit/mme_audit.py b/tools/mme-audit/mme_audit.py
new file mode 100644
index 0000000..8031f3c
--- /dev/null
+++ b/tools/mme-audit/mme_audit.py
@@ -0,0 +1,570 @@
+#!/usr/bin/env python3
+"""mme-audit: offline audit of the vgsp MME golden overlay and replay streams.
+
+Pure Python 3.10 stdlib. Inputs (all local, all public):
+ * kernel/golden-mme-tu104.h (golden slot library)
+ * dmesg_live_*.log captures (3D win / MME-WINRUN / MME-PRE)
+
+What it checks (r1448-strategy 3.1):
+ 1. overlay simulation: golden_slot() accept rules, old (!gs->entry) vs new
+ (entry 0 valid) under force=1 -> 54 before, 55 after
+ 2. grammar walk of every 3D win[...] / MME-WINRUN / MME-PRE[...] block:
+ op 1/3/5 span, 0x114 IR loads, SA pairs; walk-end == len assertion
+ 3. call census per window (slot, off, payload)
+ 4. operand map over the mission slots: decode MME64 groups, flag
+ LOAD-sourced method emissions and suspect method immediates
+ 5. cross-boot pair-emitted/elided/MISS/first-fault table
+ 6. slot-57 focus decode around the r1448b/c stall (IR 868..930)
+"""
+import argparse
+import os
+import re
+import sys
+
+# --------------------------------------------------------------------- golden
+
+GOLDEN_SLOT_RE = re.compile(
+ r"\[\s*(\d+)\]\s*=\s*\{\s*0x([0-9a-fA-F]+)u,\s*(\d+)u,\s*(\d+)u,\s*0x([0-9a-fA-F]+)u\s*\}")
+GOLDEN_WORDS_RE = re.compile(
+ r"golden_mme_tu104_words\[GOLDEN_MME_TU104_WORDS\]\s*=\s*\{(.*?)\n\};", re.S)
+
+MISSION_SLOTS = [0, 2, 34, 39, 40, 48, 51, 57, 58]
+SUSPECT_METHODS = [0x1614, 0x1618, 0x2054, 0x2058, 0x2094, 0x2098,
+ 0x2154, 0x2158, 0x0d74, 0x0d78]
+
+# MME64 layout (3-word groups), extracted from the observed disassembly
+# convention: bits[95:64]=w0, [63:32]=w1, [31:0]=w2.
+REG = ["R%d" % i for i in range(24)] + ["ZERO", "IMMED", "IMMEDPAIR",
+ "IMMED32", "LOAD0", "LOAD1"]
+OP = ["ADD", "ADDC", "SUB", "SUBB", "MUL", "MULH", "MULU", "EXTENDED", "CLZ",
+ "SLL", "SRL", "SRA", "AND", "NAND", "OR", "XOR", "MERGE", "SLT", "SLTU",
+ "SLE", "SLEU", "SEQ", "STATE", "LOOP", "JAL", "BLT", "BLTU", "BLE",
+ "BLEU", "BEQ", "DREAD", "DWRITE"]
+OUT = ["NONE", "ALU0", "ALU1", "LOAD0", "LOAD1", "IMMED0", "IMMED1",
+ "RESERVED", "IMMEDHIGH0", "IMMEDHIGH1", "IMMED32_0"]
+
+
+def regname(v):
+ return REG[v] if v < 30 else "V%d" % (v - 32)
+
+
+def mme64_decode(w0, w1, w2):
+ val = (w0 << 64) | (w1 << 32) | w2
+
+ def bits(hi, lo):
+ return (val >> lo) & ((1 << (hi - lo + 1)) - 1)
+
+ alus = []
+ for base in (10, 46):
+ alus.append((bits(base + 4, base), bits(base + 9, base + 5),
+ bits(base + 14, base + 10), bits(base + 19, base + 15),
+ bits(base + 35, base + 20)))
+ outs = []
+ for base in (82, 89):
+ outs.append((bits(base + 2, base), bits(base + 5, base + 3)))
+ return {
+ "endNext": bits(0, 0), "predMode": bits(4, 1), "pred": bits(9, 5),
+ "alu": alus, "out": outs,
+ }
+
+
+def mme64_text(d):
+ parts = []
+ for op, dst, s0, s1, im in d["alu"]:
+ if (op, dst, s0, s1, im) == (0, 0, 0, 0, 0):
+ continue
+ parts.append("%s %s, %s, %s, 0x%04x" %
+ (OP[op], regname(dst), regname(s0), regname(s1), im))
+ for meth, emit in d["out"]:
+ if meth or emit:
+ parts.append("OUT method-src=%s data-src=%s" %
+ (OUT[meth], OUT[emit]))
+ if d["endNext"]:
+ parts.append("endNext")
+ if d["predMode"]:
+ parts.append("pred=%s,%s" % (d["predMode"], regname(d["pred"])))
+ return " | ".join(parts) if parts else "NOP"
+
+
+def parse_golden(path):
+ text = open(path, encoding="utf-8").read()
+ pool = []
+ m = GOLDEN_WORDS_RE.search(text)
+ if m:
+ pool = [int(t, 16) for t in re.findall(r"0x[0-9a-fA-F]+", m.group(1))]
+ entries = {}
+ for m in GOLDEN_SLOT_RE.finditer(text):
+ entries[int(m.group(1))] = (int(m.group(2), 16), int(m.group(3)),
+ int(m.group(4)), int(m.group(5), 16))
+ return entries, pool
+
+
+def golden_slot(entries, j, entry0_fix):
+ """Model of gsp_phys_gr_golden_slot() (knob presumed on)."""
+ if j >= 64 or j not in entries:
+ return None
+ entry, words, off, flags = entries[j]
+ if not (flags & 0x1) or not words:
+ return None
+ if not entry0_fix and not entry:
+ return None
+ return entry, words, off, flags
+
+
+PRESENT = 0x1
+GMME_FLAGS = {0x2: "DRIVER", 0x4: "LIVE_VARIANT", 0x8: "GEFORCE"}
+
+
+def overlay_sim(entries, pool):
+ out = {}
+ for fix in (False, True):
+ overlaid, rejected = [], []
+ for j in range(64):
+ gs = golden_slot(entries, j, fix)
+ (overlaid if gs else rejected).append(j)
+ out[fix] = (sorted(overlaid), sorted(rejected))
+ return out
+
+
+# ------------------------------------------------------------------ walkers
+
+def walk_stream(words):
+ """Booter grammar walk: returns (ok, runs, image, calls, sa_pairs)."""
+ runs, image, calls, sa_pairs = [], {}, [], {}
+ off, n = 0, len(words)
+ ok = True
+ while off < n:
+ h = words[off]
+ op = (h >> 29) & 7
+ cnt = (h >> 16) & 0xfff
+ mthd = (h & 0x1fff) << 2
+ span = 1
+ if op in (1, 3, 5) and cnt:
+ span = 1 + cnt
+ if off + span > n:
+ ok = False
+ span = n - off
+ runs.append((off, op, cnt, mthd, span))
+ if mthd == 0x114 and span >= 3:
+ pc = words[off + 1]
+ code = words[off + 2:off + span]
+ for i in range(len(code) // 3):
+ image[pc + i] = tuple(code[3 * i:3 * i + 3])
+ if 0x3800 <= mthd <= 0x39fc:
+ j = (mthd - 0x3800) // 8
+ kind = "DATA" if (mthd & 4) else "MACRO"
+ payload = list(words[off + 1:off + span])
+ calls.append((j, off, kind, mthd, payload))
+ if mthd == 0x11c and span >= 3:
+ sa_pairs[words[off + 1]] = words[off + 2]
+ off += span
+ return ok, runs, image, calls, sa_pairs
+
+
+CRLF = re.compile(r"\[(\d+\.\d+)\]\s+vgsp-gr:\s+(.*)$")
+WIN_RE = re.compile(r"3D win\[\s*(\d+)\]:\s+((?:[0-9a-fA-F]+ ?)+)")
+WINRUN_DUMP_RE = re.compile(r"MME-WINRUN dump h=0x([0-9a-fA-F]+) push=0x([0-9a-fA-F]+) window=(\d+)")
+WINRUN_RUN_RE = re.compile(
+ r"MME-WINRUN off=([0-9a-fA-F]+) op=(\d+) cnt=(\d+) mthd=([0-9a-fA-F]+) d0=([0-9a-fA-F]+) d1=([0-9a-fA-F]+)")
+PRE_RE = re.compile(r"MME-PRE\[\s*(\d+)\]:?\s+((?:[0-9a-fA-F]{8} ?)+)")
+
+
+def parse_windows(path):
+ """Yield dicts for each 3D win[], MME-WINRUN and MME-PRE[] block."""
+ cur = None
+ win_words, wr_runs, wr_meta = [], [], None
+ pre_idx, pre_words = -1, []
+ with open(path, encoding="utf-8", errors="replace") as fh:
+ for line in fh:
+ m = CRLF.search(line)
+ if not m:
+ continue
+ ts, msg = m.group(1), m.group(2)
+ m = WIN_RE.search(msg)
+ if m:
+ off = int(m.group(1))
+ ws = [int(t, 16) for t in m.group(2).split()]
+ if win_words and off != len(win_words) and off != 0:
+ yield {"kind": "win", "ts": ts, "words": win_words}
+ win_words = []
+ if off == 0 and win_words:
+ yield {"kind": "win", "ts": ts, "words": win_words}
+ win_words = []
+ win_words.extend(ws)
+ continue
+ m = WINRUN_DUMP_RE.search(msg)
+ if m:
+ if wr_meta and wr_runs:
+ yield {"kind": "winrun", "ts": ts, **wr_meta, "runs": wr_runs}
+ wr_meta = {"h": int(m.group(1), 16), "push": int(m.group(2), 16),
+ "window": int(m.group(3))}
+ wr_runs = []
+ continue
+ m = WINRUN_RUN_RE.search(msg)
+ if m and wr_meta is not None:
+ wr_runs.append((int(m.group(1), 16), int(m.group(2)),
+ int(m.group(3)), int(m.group(4), 16),
+ int(m.group(5), 16), int(m.group(6), 16)))
+ continue
+ m = PRE_RE.search(msg)
+ if m:
+ idx = int(m.group(1))
+ ws = [int(t, 16) for t in m.group(2).split()]
+ if pre_words and idx != pre_idx + len(pre_words):
+ yield {"kind": "pre", "ts": ts, "words": pre_words}
+ pre_words = []
+ pre_words.extend(ws)
+ pre_idx = idx
+ continue
+ if win_words:
+ yield {"kind": "win", "ts": ts, "words": win_words}
+ win_words = []
+ if wr_meta and wr_runs is not None:
+ # runs may legitimately be empty (dump with no decoded runs)
+ yield {"kind": "winrun", "ts": ts, **wr_meta, "runs": wr_runs}
+ wr_meta, wr_runs = None, []
+ if pre_words:
+ yield {"kind": "pre", "ts": ts, "words": pre_words}
+ pre_words = []
+ if win_words:
+ yield {"kind": "win", "ts": ts, "words": win_words}
+ if wr_meta:
+ yield {"kind": "winrun", "ts": ts, **wr_meta, "runs": wr_runs}
+ if pre_words:
+ yield {"kind": "pre", "ts": ts, "words": pre_words}
+
+
+def walk_winrun(window, runs):
+ """Walk a decoded MME-WINRUN listing; returns (ok, calls, end)."""
+ seen, calls, end = set(), [], 0
+ for off, op, cnt, mthd, d0, d1 in runs:
+ span = 1 + cnt if op in (1, 3, 5) and cnt else 1
+ seen.add(off)
+ if 0x3800 <= mthd <= 0x39fc:
+ j = (mthd - 0x3800) // 8
+ kind = "DATA" if (mthd & 4) else "MACRO"
+ calls.append((j, off, kind, mthd, [d0, d1]))
+ end = max(end, off + span)
+ ok = end == window and len(seen) == len(runs)
+ return ok, calls, end
+
+
+# ------------------------------------------------------------ MME64 scanning
+
+def scan_slot(entries, pool, slot):
+ entry, words, off, flags = entries[slot]
+ rows = []
+ for i in range(words // 3):
+ w = tuple(pool[off + 3 * i:off + 3 * i + 3])
+ d = mme64_decode(*w)
+ rows.append((entry + i, i, w, d))
+ return rows
+
+
+def operand_map(entries, pool):
+ """For mission slots: flag emissions + suspect method constants."""
+ sus2 = {m >> 2: m for m in SUSPECT_METHODS}
+ out = []
+ for slot in MISSION_SLOTS:
+ if slot not in entries or not entries[slot][1]:
+ continue
+ for ir, idx, w, d in scan_slot(entries, pool, slot):
+ tags = []
+ for meth, emit in d["out"]:
+ if emit in (3, 4): # LOAD0/LOAD1 data source
+ tags.append("LOAD-sourced emission (method-src=%s)" % OUT[meth])
+ for word in w:
+ low = word & 0xfff
+ if low in sus2 and sus2[low] != 0x0d74 and sus2[low] != 0x0d78:
+ tags.append("suspect method %#x (field 11:0 of %08x)" % (sus2[low], word))
+ for op, dst, s0, s1, im in d["alu"]:
+ if im in SUSPECT_METHODS:
+ tags.append("suspect imm %#x (ALU immed)" % im)
+ if s0 == 24 and im == 0: # ZERO + 0 immediate
+ tags.append("zero-operand ALU (src0=ZERO immed=0)")
+ for t in tags:
+ out.append((slot, ir, w, t, mme64_text(d)))
+ return out
+
+
+# ----------------------------------------------------------- log-level facts
+
+FAULT_RE = re.compile(r'errString="([^"]+)"')
+ESR_RE = re.compile(r"esr 80000000->badf1201")
+
+
+def log_facts(path):
+ f = {"path": path}
+ counts = {"PAIR-DROP": 0, "PAIR-DROP-words": 0, "MISS-2054": 0,
+ "GOLDEN": [], "esr": 0, "macros": {}, "faults": [],
+ "trap2090": 0}
+ with open(path, encoding="utf-8", errors="replace") as fh:
+ for line in fh:
+ if "MME-PAIR-DROP" in line:
+ counts["PAIR-DROP"] += 1
+ m = re.search(r"MME-PAIR-DROP (\d+) word", line)
+ if m:
+ counts["PAIR-DROP-words"] += int(m.group(1))
+ if "pair addr=0x2054" in line and "-> MISS" in line:
+ counts["MISS-2054"] += 1
+ m = re.search(r"MME-GOLDEN overlay (\d+) slot", line)
+ if m:
+ counts["GOLDEN"].append(int(m.group(1)))
+ if ESR_RE.search(line):
+ counts["esr"] += 1
+ for m in re.finditer(r"macro-status=([0-9a-fA-F]{8})\(mpc=(\d+) mac=0x([0-9a-fA-F]+) run=(\d)\)", line):
+ counts["macros"][int(m.group(2))] = counts["macros"].get(int(m.group(2)), 0) + 1
+ if "trap=00002090" in line or "trap=80002090" in line:
+ counts["trap2090"] += 1
+ m = FAULT_RE.search(line)
+ if m:
+ counts["faults"].append(m.group(1).strip())
+ f["counts"] = counts
+ return f
+
+
+# ------------------------------------------------------------------- report
+
+def main():
+ ap = argparse.ArgumentParser()
+ here = os.path.dirname(os.path.abspath(__file__))
+ repo = os.path.abspath(os.path.join(here, "..", ".."))
+ ap.add_argument("--golden", default=os.path.join(repo, "kernel", "golden-mme-tu104.h"))
+ ap.add_argument("--logs", nargs="*", default=[])
+ ap.add_argument("--out", default="/tmp/opencode/r1449-audit.md")
+ args = ap.parse_args()
+
+ entries, pool = parse_golden(args.golden)
+ present = sorted(j for j in entries if entries[j][3] & PRESENT and entries[j][1])
+ absent = sorted(set(range(64)) - set(present))
+ lines = []
+ A = lines.append
+
+ A("# r1449 MME offline audit (mme-audit)")
+ A("")
+ A("- golden: `%s` (%d words, %d present slots)" % (args.golden, len(pool), len(present)))
+ A("- present: %s" % present)
+ A("- absent : %s" % absent)
+ A("")
+
+ A("## 1. Overlay simulation (gsp_phys_gr_golden_slot + force overlay)")
+ sim = overlay_sim(entries, pool)
+ old_over, old_rej = sim[False]
+ new_over, new_rej = sim[True]
+ A("")
+ A("| mode | overlaid | rejected (no golden) |")
+ A("|---|---|---|")
+ A("| pre-r1448 (`!gs->entry` rejects slot 0) | **%d** | %s |" % (len(old_over), old_rej))
+ A("| r1448 (entry 0 valid) | **%d** | %s |" % (len(new_over), new_rej))
+ A("")
+ A("slot 0: %s" % ("golden entry=0x0 words=%d flags=%s (ACCEPTED after fix)" %
+ (entries[0][1], "+".join(n for b, n in GMME_FLAGS.items() if entries[0][3] & b))
+ if 0 in entries else "absent"))
+ assert len(old_over) == 54 and len(new_over) == 55, "overlay sim mismatch"
+ A("")
+ A("ASSERT: 54 -> 55 after the entry-0 fix: OK")
+ A("")
+
+ A("## 2. Grammar walks (walk-end == len)")
+ A("")
+ A("| log | blocks | win | winrun | pre | end-mismatch | calls | 0x2054 | 0x2094 | 0x2154 |")
+ A("|---|---|---|---|---|---|---|---|---|---|")
+ wins = {}
+ for path in args.logs:
+ if not os.path.exists(path):
+ A("| %s | MISSING | | | | | | | | |" % path)
+ continue
+ nw = nwr = npre = nmis = ncall = 0
+ pair_counts = {0x2054: 0, 0x2094: 0, 0x2154: 0}
+ win_calls = []
+ for blk in parse_windows(path):
+ if blk["kind"] == "win":
+ ok, runs, image, calls, sa = walk_stream(blk["words"])
+ nw += 1
+ nmis += 0 if ok else 1
+ ncall += len(calls)
+ for j, off, kind, mthd, payload in calls:
+ win_calls.append((blk["ts"], j, off, kind, payload))
+ elif blk["kind"] == "winrun":
+ ok, calls, end = walk_winrun(blk["window"], blk["runs"])
+ nwr += 1
+ nmis += 0 if ok else 1
+ ncall += len(calls)
+ for off, op, cnt, mthd, d0, d1 in blk["runs"]:
+ if mthd in pair_counts:
+ pair_counts[mthd] += 1
+ for j, off, kind, mthd, payload in calls:
+ win_calls.append((blk["ts"], j, off, kind, payload))
+ elif blk["kind"] == "pre":
+ ok, runs, image, calls, sa = walk_stream(blk["words"])
+ npre += 1
+ nmis += 0 if ok else 1
+ ncall += len(calls)
+ wins[path] = win_calls
+ base = os.path.basename(path)
+ A("| %s | %d | %d | %d | %d | %d | %d | %d | %d | %d |" %
+ (base, nw + nwr + npre, nw, nwr, npre, nmis, ncall,
+ pair_counts[0x2054], pair_counts[0x2094], pair_counts[0x2154]))
+ A("")
+ A("Note: dmesg_live_r1448.log carries both r1448b and r1448c boots "
+ "(148098..148521 and 148520/148627 sentinels); the per-boot logs named "
+ "r1448b/r1448c were not present at audit time.")
+ A("")
+
+ A("## 3. Call census (windows that called MME macros)")
+ for path, calls in wins.items():
+ if not calls:
+ continue
+ A("")
+ A("### %s" % os.path.basename(path))
+ A("")
+ A("| ts | slot | off | kind | payload |")
+ A("|---|---|---|---|---|")
+ for ts, j, off, kind, payload in calls[:200]:
+ A("| %s | %d | 0x%x | %s | %s |" %
+ (ts, j, off, kind, " ".join("%08x" % p for p in payload[:8])))
+ if len(calls) > 200:
+ A("| ... | (%d more) | | | |" % (len(calls) - 200))
+ A("")
+
+ A("## 4. Operand map (mission slots; LOAD-sourced emissions + suspects)")
+ A("")
+ om = operand_map(entries, pool)
+ if not om:
+ A("no flagged instructions")
+ else:
+ A("| slot | IR | words | flag | decode |")
+ A("|---|---|---|---|---|")
+ for slot, ir, w, t, txt in om[:120]:
+ A("| %d | %d | %08x %08x %08x | %s | %s |" % (slot, ir, w[0], w[1], w[2], t, txt))
+ if len(om) > 120:
+ A("| ... | | | (%d more) | |" % (len(om) - 120))
+ A("")
+
+ A("## 5. Cross-boot pair/fault table")
+ A("")
+ A("| log | PAIR-DROP n | words | 0x2054 MISS | overlay | esr badf1201 | trap 0x2090 | first faults |")
+ A("|---|---|---|---|---|---|---|---|")
+ for path in args.logs:
+ if not os.path.exists(path):
+ continue
+ f = log_facts(path)
+ c = f["counts"]
+ A("| %s | %d | %d | %d | %s | %d | %d | %s |" %
+ (os.path.basename(path), c["PAIR-DROP"], c["PAIR-DROP-words"],
+ c["MISS-2054"], sorted(set(c["GOLDEN"])), c["esr"], c["trap2090"],
+ "; ".join(c["faults"][:4]) if c["faults"] else "-"))
+ A("")
+
+ A("## 6. Slot-57 focus: golden body around the r1448b/c stall")
+ A("")
+ if 57 in entries and entries[57][1]:
+ rows = scan_slot(entries, pool, 57)
+ A("entry=0x%x words=%d instructions=%d" % (entries[57][0], entries[57][1], len(rows)))
+ A("")
+ A("| IR | idx | words | decode |")
+ A("|---|---|---|---|")
+ for ir, idx, w, d in rows:
+ mark = ""
+ if ir == 899:
+ mark = " **<- r1448b stall (mpc=899)**"
+ elif ir == 900:
+ mark = " **<- r1448c stall (mpc=900)**"
+ if idx < 14 or idx >= 20:
+ A("| %d | %d | %08x %08x %08x | %s%s |" % (ir, idx, w[0], w[1], w[2], mme64_text(d), mark))
+ A("")
+ else:
+ A("slot 57 absent from golden library")
+
+ A("## 7. Method-name map for the pipeline family (0x2000 + j*64)")
+ A("")
+ names = {0x00: "SET_PIPELINE", 0x08: "PIPELINE_RESERVED_A",
+ 0x0c: "PIPELINE_REGISTER_COUNT", 0x10: "PIPELINE_BINDING",
+ 0x14: "PROGRAM_ADDRESS_A", 0x18: "PROGRAM_ADDRESS_B",
+ 0x1c: "PIPELINE_RESERVED_D", 0x20: "PIPELINE_RESERVED_E"}
+ for m in (0x2054, 0x2090, 0x2094, 0x2098, 0x2154, 0x2158):
+ j = (m - 0x2000) // 64
+ off = (m - 0x2000) % 64
+ A("- 0x%04x = SET_PIPELINE(%d) + 0x%02x = %s" % (m, j, off, names.get(off, "?")))
+ A("")
+
+ A("## 8. Stall-diagnosis evidence (r1448b/c residual)")
+ A("")
+ A("The MME-FAST `trap=<mthd> data=<d>` telemetry carries the method the FE")
+ A("last processed. Calibration against the window runs:")
+ A("")
+ TRAP_RE = re.compile(r"trap=([0-9a-fA-F]{8}) data=([0-9a-fA-F]{8})")
+ for path in args.logs:
+ if not os.path.exists(path):
+ continue
+ wr_pairs, trap_pairs, stall = set(), set(), []
+ with open(path, encoding="utf-8", errors="replace") as fh:
+ for line in fh:
+ m = WINRUN_RUN_RE.search(line)
+ if m:
+ wr_pairs.add((int(m.group(4), 16), int(m.group(5), 16)))
+ m = TRAP_RE.search(line)
+ if m:
+ trap_pairs.add((int(m.group(1), 16) & 0x7fffffff,
+ int(m.group(2), 16)))
+ if "macro-status=" in line and ("mpc=899" in line or "mpc=900" in line):
+ stall.append(line.rstrip())
+ hits = sorted(wr_pairs & trap_pairs)
+ n2090_wr = sum(1 for line in open(path, encoding="utf-8", errors="replace")
+ if WINRUN_RUN_RE.search(line) and "mthd=2090" in line)
+ n2090_trap = sum(1 for line in open(path, encoding="utf-8", errors="replace")
+ if "trap=00002090" in line or "trap=80002090" in line)
+ A("### %s" % os.path.basename(path))
+ A("")
+ A("- window-run `(mthd,d0)` vs telemetry `(trap,data)` intersections: %s" %
+ (" ".join("0x%x/0x%x" % p for p in hits[:8]) if hits else "none"))
+ A("- `mthd=2090` window runs: **%d**; `trap=...2090` telemetry lines: **%d**" %
+ (n2090_wr, n2090_trap))
+ for s in stall[:6]:
+ A("- stall: `%s`" % s)
+ A("")
+
+ A("## 9. Findings (synthesis)")
+ A("")
+ A("1. **Overlay completion:** the entry-0 fix takes the force overlay from")
+ A(" 54 to 55 slots (slot 0 SETUP_FIXED_CONST, entry 0x0, 15 words is the")
+ A(" only slot the old `!gs->entry` reject skipped).")
+ A("2. **r1448b/c residual:** the slots carried the program pairs (PAIR-DROP=0;")
+ A(" `mthd=2054/2094/2154 d1=0x19b0900/0x19b0200/0x19b0000`); the MME was")
+ A(" sampled at mpc=899 (r1448b, 3x then poison) / 900 (r1448c, 2x then")
+ A(" trap) inside slot 57. NOTE: the clean r1443b boot passes through the")
+ A(" same mpc=899/900 samples (and advances to mac=0x33), so the PC alone")
+ A(" is not the anomaly - the differentiator is `trap=0x2090 data=0`")
+ A(" (0 occurrences in r1443b/r1447/r1447c, 4 in r1448) followed by")
+ A(" Class Error Offset 00002090 ErrorCode 4.")
+ A("3. **0x2090 is macro-emitted, not client-emitted:** no window in any log")
+ A(" contains `mthd=2090`; the trap field is calibrated against window runs")
+ A(" (`mthd=22c d0=800` <-> `trap=0000022c data=00000800`). 0x2090 =")
+ A(" SET_PIPELINE(2)+0x10 = PIPELINE_BINDING(2), the stage-2 binding in the")
+ A(" same family as the carried pairs. It is emitted by the MME and")
+ A(" rejected only in the pair-carried boots.")
+ A("4. **Stall-site decode:** slot 57 IR 899 (idx 31) is an emission group")
+ A(" `ADD R3,R3,IMMEDPAIR,0x08e4 | OUT method-src=IMMED0 data-src=LOAD0`;")
+ A(" IR 903 repeats it; IR 900 (idx 32) is `JAL +0x1d` to the macro tail.")
+ A(" LOAD0 is never written inside the slot-57 body (first read at IR 868")
+ A(" as macro input word 0): the emitted binding payload is call-input")
+ A(" dependent and null-capable - the rejected `data=0` snapshot is")
+ A(" consistent with a zero call-input word on the stalling call.")
+ A("5. **Next lever:** the carried-pair launch must satisfy the stage-2")
+ A(" binding method (0x2090) the macro emits, or the emission must be")
+ A(" bracketed by a valid stage-2 selector/binding state (the window writes")
+ A(" `mthd=2080 SET_PIPELINE(2) d0=0x21 d1=0x20010850` but no 0x2090).")
+ A(" Alternative: keep the r1447 pairs-elided shape for the calls-kept")
+ A(" launch (it reached mpc=930/22) and carry the pairs only on held-call")
+ A(" launches.")
+ A("")
+
+ text = "\n".join(lines) + "\n"
+ with open(args.out, "w", encoding="utf-8") as fh:
+ fh.write(text)
+ print(text)
+ print("wrote", args.out, file=sys.stderr)
+
+
+if __name__ == "__main__":
+ main()