"""Analyze a VPX link-adapter capture (emulator/vpxlog.txt) from the Phase 1 logging device: summarize the access pattern, reconstruct the outbound byte stream, and check it against the transputer monitor / i860 renderer files. Usage: python analyze_capture.py [vpxlog.txt] [image_dir] """ import sys, os from collections import OrderedDict log_path = sys.argv[1] if len(sys.argv) > 1 else "vpxlog.txt" image_dir = sys.argv[2] if len(sys.argv) > 2 else "image" events = [] # (seq, dir, reg, value, run) sent = bytearray() # bytes written to outputData, in order for line in open(log_path): line = line.strip() if not line or line.startswith("#"): continue parts = line.split() seq, d, reg, val = parts[0], parts[1], parts[2], parts[3] run = int(parts[4][1:]) if len(parts) > 4 and parts[4].startswith("x") else 1 events.append((seq, d, reg, int(val, 16), run)) if d == "W" and reg == "outputData": sent.extend([int(val, 16)] * run) # access summary counts = OrderedDict() for _, d, reg, _, run in events: counts[(d, reg)] = counts.get((d, reg), 0) + run print("=== access summary (run-length expanded) ===") for (d, reg), n in sorted(counts.items(), key=lambda x: -x[1]): print(f" {d} {reg:<13} {n}") # reset preamble (writes before the first outputData byte) print("\n=== reset preamble (up to first payload byte) ===") for seq, d, reg, val, run in events: if d == "W" and reg == "outputData": break print(f" {seq} {d} {reg:<13} 0x{val:02X}" + (f" x{run}" if run > 1 else "")) print(f"\n=== outbound stream: {len(sent)} bytes ===") def match(name): p = os.path.join(image_dir, name) if not os.path.exists(p): return f" {name}: (not found)" data = open(p, "rb").read() if bytes(sent) == data: return f" {name}: {len(data)} bytes EXACT MATCH (whole stream)" if bytes(sent[:len(data)]) == data: return f" {name}: {len(data)} bytes MATCHES stream prefix (stream continues)" # first difference for i, (a, b) in enumerate(zip(sent, data)): if a != b: return f" {name}: {len(data)} bytes differs at offset {i} (sent 0x{a:02X} vs 0x{b:02X})" return f" {name}: {len(data)} bytes (stream is a prefix of file)" print("=== compare outbound stream to boot files ===") for f in ("VRENDMON.BTL", "VRNOSTEX.MNG", "VREND.MNG"): print(match(f)) if sent[:1]: n = sent[0] print(f"\n=== transputer boot-from-link ===") print(f" first byte 0x{sent[0]:02X} ({sent[0]}) = primary-bootstrap length " f"(a standard bootable .BTL transputer image)")