Files
CydandClaude Fable 5 e3c090695d Phase 1 complete: captured VPX boot conversation from shipped binary
Built DOSBox-X from source with a custom VPX link-adapter logging
device (vpx-device/vpxlog.cpp) and captured the game's outbound boot
sequence. Findings:

- Register map confirmed against LINKIO.C: outputData 0x151,
  outputStatus 0x153 (polled bit0), resetRoot 0x160, analyseRoot 0x161.
- Reset preamble captured exactly (analyse=0, reset 0->1->0 + status inits).
- The game streams 85298 bytes to outputData that are BYTE-FOR-BYTE
  identical to VRENDMON.BTL; first byte 0xF0 = transputer boot-from-link
  primary-bootstrap length. Protocol stage 1 (reset + monitor download)
  fully characterized; no hidden bulk/interrupt path.
- Production cockpit dump ALPHA_1 added (git-ignored): its BT is v1.1.0.6
  with a VRENDMON.BTL byte-identical to the captured stream, so this
  result reflects the exact cockpit software. ALPHA_1 is the reference
  image going forward (carries RP + production pod/network boot chain).

Adds analyze_capture.py, capture.conf, PHASE1-RESULTS.md. DOSBox-X
source tree and capture artifacts are git-ignored.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 22:46:20 -05:00

68 lines
2.6 KiB
Python

"""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)")