#!/usr/bin/env python3 """Decode a VPX_FIFODUMP capture (Phase 3a). The dump is a sequence of records, each one FIFO burst (the bytes REP OUTSWed to the FIFO port between two outputData tag writes): 'VPXM' u32-LE length, then raw bytes Wire model (VR_COMMS.C velocirender_transmit, FIFO path): each transmit is two bursts -- burst 1 is the 4-byte action word, burst 2 the message data. So records pair up into [action][data] messages. velocirender_packetize splits payloads >508 bytes into multiple transmits with the same action. Usage: decode_fifodump.py [--hex N] [--action A] """ import struct import sys from collections import Counter # DPL3 VR_PROT.H enum -- the Rel4.10 build extends this (0x2D sync etc.); # names beyond the DPL3 enum are provisional and marked with '?'. ACTION_NAMES = { 0: "init", 1: "create", 2: "delete", 3: "flush", 4: "sect_pixel", 5: "sect_vector", 6: "dcs_nest", 7: "dcs_link", 8: "dcs_prune", 9: "draw_scene", 10: "draw_scene_complete", 11: "list_add", 12: "list_remove", 13: "morph", 14: "version", 15: "statistics", 16: "readpixels", 17: "hspcode", 18: "860code", 19: "860data", 20: "860bss", 21: "860args", 22: "set_geom_verts", 23: "set_texmap_texels", 0x2D: "sync(rel410)", } def read_records(path): recs = [] with open(path, "rb") as f: while True: hdr = f.read(8) if len(hdr) < 8: break magic, ln = hdr[:4], struct.unpack(" 4: msgs.append((struct.unpack("= 4: msgs.append((struct.unpack("" n = ACTION_NAMES.get(a) return f"{a}:{n}" if n else f"{a}(0x{a:X})?" def hexdump(b, limit=64): out = [] for i in range(0, min(len(b), limit), 16): row = b[i:i + 16] hx = " ".join(f"{c:02x}" for c in row) tx = "".join(chr(c) if 32 <= c < 127 else "." for c in row) out.append(f" {i:04x} {hx:<48} {tx}") if len(b) > limit: out.append(f" ... {len(b)} bytes total") return "\n".join(out) def floats(b, n=8): k = min(n, len(b) // 4) return " ".join(f"{v:.4g}" for v in struct.unpack(f"<{k}f", b[:k * 4])) def ints(b, n=8): k = min(n, len(b) // 4) return " ".join(f"{v:#x}" for v in struct.unpack(f"<{k}I", b[:k * 4])) def main(): path = sys.argv[1] hexn = 0 only = None if "--hex" in sys.argv: hexn = int(sys.argv[sys.argv.index("--hex") + 1]) if "--action" in sys.argv: only = int(sys.argv[sys.argv.index("--action") + 1], 0) recs = read_records(path) msgs = pair_messages(recs) print(f"{len(recs)} burst records -> {len(msgs)} messages\n") counts = Counter() sizes = Counter() for a, d in msgs: counts[a] += 1 sizes[a] += len(d) print("action count total-bytes sizes") persize = {} for a, d in msgs: persize.setdefault(a, Counter())[len(d)] += 1 for a in sorted(counts, key=lambda x: (x is None, x)): sz = ",".join(f"{s}x{c}" if c > 1 else f"{s}" for s, c in sorted(persize[a].items())[:6]) print(f"{aname(a):<26} {counts[a]:>5} {sizes[a]:>11} {sz}") if hexn or only is not None: print() shown = 0 for i, (a, d) in enumerate(msgs): if only is not None and a != only: continue print(f"[{i}] {aname(a)} len={len(d)}") if d: print(" ints: ", ints(d)) print(" floats:", floats(d)) print(hexdump(d, hexn if hexn else 64)) shown += 1 if hexn and shown >= 40 and only is None: print("... (truncated)") break if __name__ == "__main__": main()