The frame-1 extent bug traced to four `pftrunc.sd fN,f0,fX` ops (P=1)
converting the region bounds through the A-pipe -- our fix/ftrunc was
scalar-only (MAME's core never implemented the pipelined form: "pipelined
not functional yet"). The drains then retired neighboring values (the
homogeneous w=1.0f as raw bits -> y1=0x3F800000>>7=8323072 -> ~8.3M phantom
tile rows = the 49K uniform bins / 4096 same-page descriptors).
Pipe stages now carry (value, rp, raw): pipelined ftrunc/fix push the
truncated integer BITS (64-bit pair for .sd results), and _retire() writes
raw entries back verbatim instead of re-encoding floats. Extent probe after
fix: x0=y0=x1=y1=0 (sane empty bound), single visit instead of a hot loop.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
unhooked; draw_scene #1 runs with 41K IGC board accesses
The functional pipe model is replaced with exact i860 semantics, validated
against MAME's i860 core (src_opers[] and insn_dualop/insn_fadd_sub verbatim):
- Precision bits: SOURCE = bit8, RESULT = bit7 (swapped from our old reading;
.ds is invalid except famov). For DUAL ops: sp = multiplier source prec,
rp = adder source prec AND all results.
- Dual ops (sub 0x00-0x1f): bit10 selects PFAM (fdest <- A-pipe retire) vs
PFMAM (fdest <- M-pipe retire) -- NOT "pipelined". FLAGM operands (the
A-pipe entries in the DPC table) read the M-pipe in the PFMAM family.
T-loads on DPC 2,3,6,7,8,0xb,0xc; K-loads on DPC 1,3,5,7 (from fsrc1 at
mul precision; T from the M-pipe last stage).
- fdest BYPASS: pipelined ops whose source register equals fdest read the
retiring pipe value instead of the stale register (dual mul: op2 only;
dual add + scalar pipelined fadd/fmul: both operands).
- Pipe stages carry (value, result-precision); push rounds to single when
rp=0 (exact magic-constant float->int bit games); retire encodes with the
pusher's precision. Adder = 3 stages; multiplier = 2 (double) / 3 (single);
pfld = 3-stage load pipe; graphics fiadd/fisub = 1-stage pipe, 64-bit .dd.
ACCEPTANCE: (1) the firmware's own Newton-Raphson integer divide now computes
16/16 = 1 through the pipes -- the intdiv hook is retired (authentic
execution); (2) draw_scene #1 from the snapshot executes real render phases:
coefficient fld.d bursts, 0x800-byte queue-page initialization, tile enqueue,
and the first region flush -- 40,959 IGC/board MMIO accesses (previously 0).
Frame still running at the profiling time budget (~240M steps in).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
VR_COMMS.C boot_860() shows the host boots the render board by streaming the
whole .MNG over the wire: args860 ("i860 50MHz and kicking"), a 40-byte
code860 packet holding the 7-word header {csize,dsize,bsize,cstart,dstart,
bstart,entry}, then the code/data/bss segments. cap7's preamble is therefore
a complete firmware image -- and a DIFFERENT BUILD than sda4/RPLIVE/VREND.MNG
(text 0x31440 vs 0x39ec0), which explains the residual global-address
mismatches (version skew) when replaying cap7 against the sda4 build.
The wire header also confirms the link layout from the protocol itself:
cstart=0xf0400000, dstart=0x00001000, bstart=0x0001f4a0, entry=0xf0400000.
Note the streamed "bss" content is NOT zeros (10685/14272 nonzero bytes).
extract_capfw.py reassembles the image (capfw7.mng + capfw7.bss, committed);
it boots in emu860 to 0xf040062c then needs op 0x0d (new ctrl-reg variant).
run_to_draw.py = marathon runner with board-stream dump.
Next: re-derive the hook addresses (main/dN_receive/allocator/...) for the
capture build and replay cap7 against its own firmware, version-matched.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
processes the full wire boot incl. the downloaded PAZ/sfx module
ISA fixes, all derived from the toolchain's own .S<->.O pairs (AS860.ZIP:
OPTFLOAT/TRISTRIP/ZBUF32, plus DNC.O) and the firmware's linked COFF header:
- DATA_BASE = 0x1000 DEFINITIVE: VREND.MNG carries its original COFF header in
the file tail (.data vaddr 0x1000, .bss 0x1f940, entry 0xf0400000).
- Integer loads: even opcodes are register-indexed (EA = src2 + src1); op 4/5
size flag = instr bit0 (0 = ld.s 16-bit, 1 = ld.l 32-bit); ld.b/ld.s
sign-extend.
- Integer stores: st.s/st.l selected by offset bit0, same split-offset rule.
- FP loads/stores: FP register lives in the DEST field for both fld and fst
(fst does NOT use the integer split-store encoding); flag bits: bit0 =
auto-increment (base <- EA), bit1 1=.l/0=.d, bit2 = .q; .d/.q span register
pairs/quads. ~450 fld.d + ~300 fst.d were previously read/written 32-bit.
- bla (op 0x2d, was misdecoded as shrd): branch-on-LCC-and-add with the
sign-dependent LCC rule (src1<0 -> signed sum >= 0), so spent countdown
loops terminate. 335 bla instructions in the firmware.
- CORE ESCAPE (op 0x13): sub-op 1 = lock, 2 = calli, 7 = unlock. Previously
everything decoded as calli, so every spinlock acquire jumped to address 0 --
this was the phantom "exit stub" behind most earlier derails.
- f2b: IEEE overflow -> +/-inf instead of raising.
emu_main.py (new): runs the firmware's OWN main() (0xf0403f10) and feeds real
wire captures through a hooked dN_receive, so init/do_init/dispatch/handlers
all execute authentically. Provides the transputer-monitor environment
(processor id, DRAM region descriptors in the shared control block, sbrk/
shared-block seed slots) and hooks only the link primitives (bla busy-wait,
dN_mynode/dN_nodes/dN_receive/dN_send, putchar path, spinlocks, page allocator
+ virt->phys translator pending Tier-2 VRENDMON).
KEY DISCOVERY: the capture's args860/code860/data860/bss860 preamble is the
host DOWNLOADING an additional i860 module (the PAZ/sfx renderer layer, banner
"i860 50MHz") which installs the runtime handler tables and system objects.
Feeding it through the firmware's own handlers, the module loads and makes the
first IGC board-register writes. State: 834+ wire commands processed (module
download + init + create); first draw_scene sits at command 1568.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Env-gated hooks to continue the create()/jump-table investigation without
changing default behavior:
- EMU_DATA_BASE (default 0): overrides I860.DATA_BASE for the .data link base.
- EMU_INDEXED=1 (default off): makes EVEN integer load opcodes register-indexed
(EA = base + index), per the ground-truth `ld.l r30(r31),r31` in VR_REMOT.S.
Sweep finding (EMU_INDEXED=1): create() RETURNS at DATA_BASE=0xff0 making real
subroutine calls, confirming register-indexed loads + a ~0x1000 data base are
correct. Residual: do_init derails to (DATA_BASE+0x30) for base >= 0xfe0 while
create needs >= ~0xfe0 -- a single flat base can't satisfy both yet, pointing
to a segment/relocation nuance (or a separate do_init jump-table derail).
Details + repro in the tier-0 memory. Default behavior unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Worked the full-render marathon by tracing faults in the real VREND.MNG
firmware and matching them to the ground-truth AS860 assembly (VR_REMOT.S)
and C source (VR_REMOT.C). Six interpreter bugs found and fixed:
1. subs/subu direction: computed src2-src1; must be src1-src2 with
CC=(src1<src2). Corrupted every subtraction, compare and bounds-check.
2. logical CC: all i860 logicals (and/andnot/or/xor + .h) set CC=(result==0).
Had wrongly limited it to the AND family, so the `xor 0x0,rN,r0; bnc`
zero-test idiom spun forever.
3. STORE encoding (the big one): i860 stores encode the SOURCE register in
bits 15:11 (src1), not the dest field, and SPLIT the 16-bit offset across
bits 20:16 (high) + bits 10:0 (low). The old decode saved the wrong
register to the wrong offset, so function prologues never stored r1 and
every `bri r1` return jumped to 0.
4. ld.b/st.b: op 0x00/0x01 = ld.b, op 0x03 = st.b (byte). Proven by byte-scan
loops (r5 advanced by 1) and a save/restore pair at 0xf042b418 -> b430.
5. Mem page-span: r16/r32/w16/w32 crashed on 64KB page boundaries; now fall
back to byte access across the boundary.
6. fmlow.dd (FP subop 0x21): the i860 has no integer multiply, so ints are
ixfr'd into FP regs, multiplied via fmlow.dd, and fxfr'd back. Implemented
as a 32x32 -> 64 multiply across the destination register pair.
emu_replay.py now runs the source-accurate init sequence: velocirender_init
on the init(0) command, then do_init before the first real command. Result:
boot idles at 0xf0400590; velocirender_init returns; do_init runs to
completion (~9200 steps of real allocator / name-table / scene-root setup).
Remaining blocker (documented in the tier-0 memory): create()'s switch needs
register-indexed integer loads (VR_REMOT.S: `ld.l r30(r31),r31`) together
with the correct .data link base (~0x1000, not 0) -- the two errors currently
cancel for the immediate paths but break the indexed jump-table dispatch.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Feeds the real captured VelociRender wire (dpl3-revive/patha/*.raw.bin, from the
soft-renderer work) to the firmware's own command handlers in emu860 -- the path
to building a scene and rendering a frame with the board's own code.
- Parses captures via vrboard's Assembler (skips the .BTL boot, frames
action+payload). cap7 = a clean small scene (17 zones / 22 instances / 24
geometry / 1 view).
- Calls each command's handler directly with the payload pointer in r16 --
verified valid: create's prologue reads [r16+0]=type, [r16+4]=handle, i.e. the
raw wire layout (no CCB wrapping needed). Bypasses the un-emulated transputer.
- Confirmed WIRE-action -> handler map by function identity (create/flush/
dcs_link/list_add/draw_scene/statistics/set_texmap_texels).
Two blockers identified for a full frame (documented in the memory + README):
1. The dispatch jump table is indexed by an INTERNAL command code, not the
wire action (velocirender_input remaps wire->internal first, e.g. draw=9
->12, flush=3->30); the high-frequency per-frame commands (0x09, 0x1d
artics, 0x2a) still need that remap reversed.
2. init(0) must run first to set up the allocator/name-table/scene-root --
cold create() faults without it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
emu860.py -- an i860 interpreter (reuses the dis860 decoder) that executes the
real Division firmware. This is the foundation of the preservation-grade
emulator (run the board's own code, vs the GL bridge which interprets the wire).
- Boots VREND.MNG cleanly: i860 init (psr/dirbase/fsr), enables the MMU, then
idle-spins at 0xf0400590 waiting for a transputer interrupt (init complete).
Board-config regs modelled (0xfffff720=2, 0xfffff70c=1) via map_control().
- Call harness (cpu.call): invoke firmware functions directly, bypassing the
(un-emulated) transputer that normally drives the CCB.
- Correct memory map: .data/.bss linked LOW (DATA_BASE=0), so globals resolve.
- FP unit with double precision (register pairs): fadd/fsub/fmul/famov/frcp/
frsqr/fix/ftrunc/fgt/feq/fxfr/fiadd/fisub.
- Delay slots, control regs, sparse MMIO memory with trap/logging, tail-trace
and stopat debug aids.
draw_scene now runs real code (incl. a double int->float conversion) until it
needs accumulated scene state -- next step is replaying a captured wire command
sequence through the command dispatcher (jump table @0x47cb8) so the scene
builds and draw_scene emits the IGC coefficient stream (Tier-1 handoff).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Predator/IR vision: reverse-engineered from the original firmware and
confirmed by the build team -- it is the Division board's TEXTURE-VALUE RAMP
mode (a "check your texture maps" diagnostic the devs hijacked), NOT a
grayscale squash or a false-colour palette. Located in VREND.MNG (effect
handler @0xe6c0, wire action 0x1b, type -1 ON / -2 OFF); ramp colours from
VR_DRAW.C. Renderer reworked to match: vrview_gl now does the 4-ramp
lerp(color0,color1,luminance(texel)) in the mesh pass (grayscale+defog
removed). Live-rendered on a new night-clear arena egg; crew A/B verdict
pending.
Firmware-decomp toolchain (emulator/firmware-decomp/), all built from the
project's own artifacts and validated:
- coff860.py i860 COFF reader (symbols/sections), names match AS860 source
- derive860.py derives the i860 opcode map from matched .S<->.O pairs
- dis860.py i860 disassembler (98% on clean ground truth; proven on
VREND.MNG -- velocirender_statistics decodes correctly)
- sigmatch860.py reloc-invariant signature matcher onto the stripped image
- i860-encoding.md / FIRMWARE-SYMBOLS.txt / README.md
PVISION-IMPLEMENTATION-GUIDE.md: self-contained hand-off for the BT411 team.
HARDWARE-ARCHITECTURE.md + hardware-photos/ (15 board shots): the Division
VelociRender card is a 2-board stack driving a 3-processor pipeline --
INMOS IMS T425-J25S (comms/control, runs vrendmon.btl) + Intel i860 XP-50 (FP
geometry, runs vrender.mng) + Division PXPL IGC 5.2 ASIC with ~48x PXPL EMC
5.1 (UNC Pixel-Planes-5 SIMD array; "EMC" = the firmware's configEMCs) +
Analog Devices ADV7150 RAMDAC + NTSC. Plus the VWE Video Distribution Board
(P/N 1404: AMD MACH130 + 3x Brooktree Bt477) for the 3-VGA-head cockpit split.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- IR / predator-vision thermal: the cockpit IR button toggles it via the
wire (dpl_Effect on action 0x1b, mode -1 ON / -2 OFF -> board.pvision).
vrview_gl present pass remaps scene luminance to a thermal palette
(default heat/Predator; mono|green|amber via VRVIEW_PVISION_PALETTE;
VRVIEW_PVISION / bridge 'v' key force it on). Exact palette + HUD-exempt
pending crew review.
- Texture filter default flipped to bilinear (operator preference); the
i860 board itself point-sampled, so VRVIEW_FILTER=nearest reverts. (A CRT
present-pass bleed/scanline prototype was built and rejected; removed.)
- Searchlight: no code needed -- night A/B proved it is a VIEW-FOG push-back
(fog near 5->60, far 400->500 on), already rendered by the existing view
fog path. Not a light cone. Added TESTNITE.EGG (arena1/night/fog) +
gauge_arena_night_pipe.conf for the test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fresh extract of the final TeslaPod410.zip (renderer bundled) to C:\Games,
configured via configure.ps1, launched end-to-end on the co-located rig --
user-verified working as expected.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A fresh extract has net_*.conf.tmpl but no rendered confs until postinstall/
configure.ps1 runs; the old "pass --conf" error led straight to renaming the
template by hand (which then breaks configure: the tokens never substitute
and the tmpl is no longer found). Detect the sitting .tmpl and point at the
real fix.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
render-bridge/freeze.ps1: PyInstaller onefile of live_bridge.py + Dave's
vrboard/vrview/vrview_gl (+glcontext collected for moderngl) -> dist\
renderer.exe (~33 MB). GL backend live-verified from a pure-dist launch
(no --root/--renderer overrides) on 2026-07-10. package.ps1 bundles the
frozen exe automatically when present; DEPLOYMENT-PLAN's renderer OPEN
item is resolved. Ignore the build-artifact dirs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Retire the bundled-silent-installer requirement: postinstall now detects an
existing Npcap service and moves on, warns clearly when absent, and still
honors a bundled deploy\npcap.exe if one is shipped. package.ps1 no longer
flags the missing bundle as a warning.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
configure.ps1: bay-IP pick now filters to Up physical adapters and fails
loudly on multiple candidates instead of coin-tossing by InterfaceMetric;
-BayIp forces the choice (and permits binding a virtual adapter on a dev
rig); -ConsoleIp sets WATTCP gateway/nameserver (default: the bay IP --
needs only to be a live on-subnet host, the console DIALS the pod);
-Root is validated up front.
DEPLOYMENT-PLAN: record the four first-smoke-test findings (2026-07-10,
end-to-end egg->mission achieved): SendToRxAdapters on the pod NIC, host
must not hold the game IP, NIC checksum offload silently kills co-located
console->pod IP (ARP works, TCP silent -- disable offload+LSO), and bt/rp
require sound + a packaged renderer (closes the renderer OPEN item: ship one).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
--no-sound strips VWE_AWE32, the FAST (28Hz SOS) clock never ticks, and
BTL4OPT hangs forever in the RIO-reset busy-wait (L4RIO.cpp SetDTR loop on
a frozen Now()) -- looks exactly like a vRIO/serial failure but isn't.
Root-caused during the 2026-07-10 dist smoke test. Only safe with a
SLOW-clock conf (setenv arg2=s). Warn at launch + document in usage/README.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Real-NE2000 semantics: accept only own-MAC unicast + broadcast (multicast
excluded -- the guest stack is unicast+ARP only), and drop npcap's loopback
of our own injected frames. Without it, a live-LAN host download floods the
emulated NIC at wire rate (65k+ frames/min) and wedges netnub before boot
("discarding..."). Filter failure is non-fatal: logs and runs unfiltered.
Also log the first 12 unicast accepts/drops with the live PAR registers.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Complete arg surface of the single installed entry-point -- mode selector
(bt/rp + recognized-unsupported), feature toggles, window placement, path
overrides, diagnostics, and the exit codes the console reads back (game
ExitCodeID passed through; 2=bad args; 3=mode not yet wired).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- net-boot/loop_rp.bat: GO.BAT-style netnub loop for RP (mirror of loop.bat,
retargeted to rpl4opt). deploy/net_rp.conf.tmpl now calls it instead of the
single-shot netnub + DOS pause -- the deployable runs in a loop until the
supervisor kills DOSBox (per operator: no single-shot in the product).
- DLL closure resolved: dosbox-x.exe is a 182MB STATIC build -- import table is
only Windows system DLLs, delay-import table empty, libpng/SDL/zlib embedded.
Nothing to bundle; wpcap.dll comes from the Npcap install. package.ps1's "no
DLLs" case is now informational, and the plan/README note the static build.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Network-agnostic, air-gapped pod install for the two DOSBox titles (BT/RP 4.10),
fitting the existing TeslaConsole/TeslaLauncher pod-bay architecture.
emulator/DEPLOYMENT-PLAN.md
Full design: bridge on the one NIC (pods form a source-proven P2P TCP mesh, so
NAT/slirp is out); launcher keeps the bay IP, the DOSBox guest bridges at
bayIP+100 (egg/mesh/game endpoint); two-edit +100 convention (postinstall +
console DOSBox flag); static, air-gapped, <=32 pods.
emulator/pod-launch/ (C# net8 supervising entry-point)
Creates a Job Object (KILL_ON_JOB_CLOSE), launches DOSBox-X + the render bridge
into it and blocks -- kill this process and both die (kernel-enforced, even on
a hard TerminateProcess of a hung session; verified). Mode dispatch: bt/rp
wired (also serve camera + live mission-review via egg hostType); review +
diagnostics recognized but fail clean until their DOS launch args are known.
emulator/deploy/ (install side)
postinstall.bat (thin elevated wrapper) + configure.ps1 (NIC detect, realnic
bind as a contiguous letter-leading GUID fragment, game IP = bayIP+100, stable
MAC, render net_*.conf templates, stamp WATTCP.CFG my_ip) + tokenized conf
templates + package.ps1 (assemble the zip). Render/bind/stamp + packaging
verified against a scratch tree.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Real-pod deployment launcher for the original VDB + octopus 4-head wiring:
VPX_COCKPIT borderless head windows (radar/win0 800,0; 3-color MFD/win4 1440,0;
2-color MFD/win3 2080,0; all 640x480) + the GL bridge as the main out-the-window
view (0,0, 800x600 via new BRIDGE_W/BRIDGE_H in live_bridge.py). Editable RECTS
at the top of the script for other rigs.
focus_dosbox.ps1 restores the deployment window state: renderer -> always-on-top
(WS_EX_TOPMOST, game view never covered) + DOSBox-X -> 10,10 with foreground
focus (keeps the emu thread at foreground priority so the RIO doesn't starve).
Coexist cleanly: topmost renderer stays above the focused-but-non-topmost DOSBox.
pod_deploy calls it last; re-run anytime the stack is disturbed. LAUNCH.md
documents both.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Documents L4VIDEO/VIDEOFORMAT/L4GAUGE/L4PLASMA/L4TIMER/L4SOUND/L4CONTROLS/L4DPLCFG/L4EYES/DPLARG (values, meanings, which are getenv-read vs batch-only, the L4VIDEO two-script gotcha) + the VPX_/VWE_/VDB_/VRVIEW_ host vars.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
RP's cockpit displays decoded near-empty (top-strip only, a copy off-screen at
VRAM 0x100000) while BT's were full. Root cause was NOT the VDB decode (byte
split/palettes/stride all correct, proven by BT) but an SVGA bank-switch
GRANULARITY mismatch: RP's REL410/RP/GAUGE/L4GAUGE.INI [640x480x16] used
granularityInKB=4 vs BT's 64 on the same STB Horizon+ (CL-GD5434). DOSBox-X's
CL-GD5434 bank emulation handles 64KB granularity (BT full) but mishandles the
4KB-granular paged gauge writes, scattering them off-screen.
FIX (config, no rebuild): RP L4GAUGE.INI granularityInKB 4->64 (matches BT,
same card). VERIFIED live: VRAM content scan went from 0x0+0x100000 (top-strip
+ off-screen) to the FULL framebuffer 0x0..0x90000 populated; radar +
upper-center MFD confirmed correct, rest under reference check.
Also commits the VDB diagnostic tooling that found it (vpxlog.cpp, all
default-off): VDB_SCAN (VRAM content locator -- decisive), VDB_PALDUMP,
pixel-mask value logging, VDB_REALSTRIDE + live mode/stride/start logging,
VDB_BASE read-base override, VDB_APPLYMASK DAC-mask honoring. Full writeup in
VDB-NOTES.md.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Operator documented the physical VDB + companion card: Jaton KY2-JAX-CVGA54PCI
(Cirrus CL-GD5434) feeds a 26-pin feature-connector ribbon to an AMD/Lattice
MACH130-15JC CPLD (the ISA 0x300-0x31A port decoder + hardwired byte-lane
splitter), which drives 3x Brooktree Bt477KPJ80 RAMDACs -> one VGA stream to
the color radar + a DB25 fan-out to the 5 mono MFDs. Confirms the RE (3 DACs =
3 palette groups; Bt477 6-bit DAC = the driver's shr al,2). A component tied in
parallel to the PC front-panel reset (remote reboot or VDB known-state on
reset) is under operator research. Also: RP uses the FULL 640x480 on all 6
displays (so our top-strip decode = a framebuffer READ bug, stride/page, not
sparse RP content).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comprehensive VWE Video Display/splitter Board writeup: what it is (dumb ISA
splitter tapping the companion Cirrus Logic SVGA feature connector), the
definitive I/O register map from L4SVGA16.ASM (Secondary 0x302 / Aux1 0x30A /
Aux2 0x312, each +0 mask/+1 read/+2 write/+3 data, 6-bit DAC; clock divider
0x319 off / 0x31A on), the byte-lane split (low byte->Secondary, high
byte->Aux1/Aux2 -> separate VGA heads -> octopus cable -> 5 mono MFDs + color
radar), the driver's bitMask+channelEnable CLUT-build trick that packs multiple
displays into one framebuffer, the pixel-mask flash + Secondary-only fade, our
emulation, the OPEN RP decode problem, and a physical-sample verification
checklist (port-decoder PAL, 3 RAMDACs, octopus pinout, Cirrus chip id).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
RP's high-frequency checkerboard track floor aliases/moires without mipmaps
(reads as "flashing geometry" in motion; user's texture-interpolation call).
vrview_gl _tex() now builds mipmaps + trilinear/anisotropic filtering under
VRVIEW_MIPMAP=1 (keeps point-sample look up close; off by default = authentic
i860, BT-identical). launch_pod.ps1 gains -Mipmap so it's set at BOOT -- never
restart the bridge mid-mission (GL-context churn starves the RIO ACK deadline).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
RP experiment finding: RP runs on the BT pod emulator (shared MUNGA stack) but
its cockpit VDB heads mis-decode. Root causes captured live (VDB_PALDUMP +
vpxresp log): (1) framebuffer identical to BT (mode 0x111, 640x480); (2) RP
loads pal0 (BT's dynamic color-radar palette) as ALL ZEROS -> radar head black;
(3) RP actively drives the VGA-DAC pixel-mask register that BT leaves at 0xFF,
and pal_draw ignored it -> likely the MFD garble.
Device change: pixel-mask writes now log their VALUE on change
("# VDB pixel-mask[gN] = 0xXX"); pal_draw ANDs the palette index with the
group mask under VDB_APPLYMASK=1 (default off = BT-identical); masks default to
0xFF in vdb_reset so an un-driven group still decodes. Built clean under MINGW64.
Also: Mac Console 4.10 retired from regular use (host .NET console is the daily
driver); tap2_mirror.py PARKED with revive notes for console A/B only. The
SendToRxAdapters registry stays set (serves the .NET host console).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Red Planet 4.10 checks in to the console, accepts the egg, launches, RIO drives it, AWE sound plays -- the whole BT pod stack (VPX board, netnub, RIO, sound, plasma, IRQ10 NIC) carries over unchanged. Main out-the-window render is flyable; VDB secondary heads black/frozen (RP inits the VDB differently) and the renderer needs RP-specific work.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Answering "why doesn't the binary honor the 30s -- it exits in a few seconds":
disassembled the StopMission close in all four BTL4OPT builds (BTLIVE May-96,
BTRAVINE Sep-96, BTDAVE, Rel410) -- BYTE-IDENTICAL, so nothing regressed. The
dispatched (outer) handler is a re-entrant two-stage close: first StopMission
schedules itself +~3s (3.0f) and returns; the +3s re-entry runs cleanup then
calls the inner L4Application handler which lights the egress lamps and
schedules a +30s LightsOut/exit (30.0f). The 30s is scheduled after teardown
begins, so the exe is recycled by GO.BAT before it fires -- observed egress
window = ~3.4s = the 3.0f stage. The operator's remembered ~20-30s "lights on"
is entry lighting (floor lamp on game-ready->drop, 21s measured) + the
between-games boot gap, not a post-mission hold. Corrects my earlier
"authentic 30s hold" note. Tools: scratchpad btdis2.py + stopmission_cmp3.py.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Disassembled BTL4OPT.EXE StopMissionMessageHandler (@0x47b864): it turns
the RIO egress lamps on (the "LightsOut"-named routine, flag=1) and
schedules the lights-out/exit for now + 30.0*timebase + 0.5 (30.0f const
@0x47b8e4). So the customer-egress window is a hardcoded ~30s timer in
the GAME, not the console and not any INI/env value -- exactly matching
the operator's memory (StopMission -> floor lights on -> ~30s hold ->
lights off -> exit -> BAT restart). Answers "the delay must be somewhere":
it is compiled in. Noted the reconcile-with-3.4s-measured task (the
tapped 154.9s sweep was likely teardown; a 90s+ tap past mission end
settles wall-time). Disasm helper: scratchpad btdis2.py.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Measured Console 4.10 through the mirror: mission end to lights-off is
3.4s, identical to the TeslaConsole, with the Mac printer spooling to a
file. No egress-delay key exists in any console INI. Best explanation
for the remembered venue window: the console closes after spooling the
score sheet, and on period hardware that was a 9600-baud serial print
taking tens of seconds -- the floor lights stayed on for the print
duration. The hold itself is genuinely console-gated (pod holds
indefinitely when no close arrives).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
With SendToRxAdapters serving the host .NET console, the SheepShaver Mac
console was deaf (pod frames go up instead of out to TAP members). The
mirror daemon turns TAP2's free application side into a userspace bridge
port: pod frames destined for the Mac are written into TAP2 (bridge
forwards them to TAP1/SheepShaver), and a reader thread drains the
unicasts the bridge's poisoned MAC table steers into TAP2 and re-injects
them where the pod's pcap hears them. Loop guards: no pod-sourced
re-injection + short frame-hash dedup. Verified live: Console 4.10
readied the pod through the mirror while the .NET console path stayed
intact -- operator can now alternate between the 1996 Mac console and
the modern one without touching the driver config.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
RIO tap capture of a full TeslaConsole mission cycle: LampFloor 0x3E +
entry cluster (0x16/0x17/0x1e) bright at game-ready (customer entry),
off at mission drop, bright again at mission end (the state=2 hold),
all swept off the moment StopMission arrives, then game exit. The
egress window is purely the gap between mission end and the console's
StopMission send (measured 3.4s with TeslaConsole vs Console 4.10's
proper customer-exit delay) -- not a game timer, not the exit code.
Confirms the operator's remembered sequence byte for byte and pins the
TeslaSuite fix: a configurable delay before StopMission.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Wire + source answer to "what happens after the mission ends": the game
fades to the black hold, commands the RIO egress lamps (T 84 LampRequest
caught on the serial tap), and holds while its StateResponse to the
console's 1/s StateQuery flips to state 2. The hold ends only when the
console sends Application__StopMissionMessage with an ExitCodeID -- a
full remote-operations menu (run game/test patterns/ResetRIO/Norton/
SoftwareReset/camera/mission review) that the game hands to netnub as
its exit code for the pod loop to dispatch. The egress-hold length is
entirely the console's decision. Also documented the seat-trim-inside-
hull z-fighting lookalike (not a render bug).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The TeslaSuite console connected near-instantly over the new host
bridge, queued and ran a real 2-minute mission on the DOSBox pod, and
the mission exited on time. Wire-logged recycle: clean FIN/RST teardown
at mission end, console SYN-retrying 11s later, riding through dead-air
and connection-refused (pre-TCP_LISTEN) phases, reconnected 54s after
teardown with zero operator interaction. Modern console + net_loop.conf
pod = fully autonomous mission loop.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>