Bring the graphics-dev collaborator's dpl3-revive into the repo as first-class
project code (they've handed it off; it's ours now). This is the proven
Division renderer that our in-process rt_draw has been trying to be.
What's here:
- parser/ B2Z/V2Z/SVT/SCN/SPL/BGF/BMF/BSL decoders (pure Python).
- spec/ reverse-engineered format + the definitive VelociRender wire
protocol (from the original DIVISION source, matches our live
VPX node/action tables exactly).
- source-ref/ read-only copies of the original DIVISION C (BIZREAD.C,
DPLTYPES.H, DPL.H) that define the formats.
- patha/ the "virtual VelociRender board": vrboard.py (24-action protocol
server), vrview.py (numpy software rasterizer, the reference),
vrview_gl.py (moderngl GPU backend, 832x512@60Hz), plus the
run/replay/regress tooling and evidence renders. Drives FLYK/BLADE/
Star Trek demos AND our btl4opt/rpl4opt game binaries.
- viewer/ WebGL archive generators (.py); prebuilt HTML/data regeneratable.
- samples/ small test models/textures.
- bt*.raw.bin real BTL4OPT arena wire captures (kept for offline renderer
testing/regression against OUR game).
.gitignore keeps the multi-hundred-MB demo capture dumps + debug logs +
regeneratable viewer bundles out of history (they stay on disk).
Phase 0 of the integration is validated: their board decodes our bt8 capture
with zero errors (3748 nodes, 507 instances, 4 mechs) and renders our arena
(terrain/dome/sky, correct Division DAC gamma). Plan + status in memory;
integration continues in emulator/RENDERER-COLLAB.md.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
124 lines
5.9 KiB
Markdown
124 lines
5.9 KiB
Markdown
# Capturing real FLYK.EXE link traffic (Path A validation)
|
|
|
|
Goal: run the genuine `FLYK.EXE` under DOSBox-X, have it talk to our Python
|
|
`vrboard` in place of the dead i860 board, and log every byte — to validate the
|
|
message framing against the *shipped* binary and pin the two open items
|
|
(`vr_readpixels` reply layout, and the bit30 `0x40000000` receive-side meaning).
|
|
|
|
## Why a responder, not a passive log
|
|
|
|
`start_velocirender()` streams the transputer `.BTL`, then blocks in
|
|
`startup_handshake()` waiting for **3 iserver transactions from the board**
|
|
(`VR_COMMS.C`). No framed `vr_*` message is sent until that handshake completes. So a
|
|
passive port logger stalls at boot and never sees the interesting scene traffic. The
|
|
link must *respond*. We keep all protocol logic in the tested Python `vrboard` and make
|
|
the emulator side a dumb byte-pipe.
|
|
|
|
## Architecture — socket bridge
|
|
|
|
```
|
|
FLYK.EXE (unmodified, in DOSBox-X)
|
|
│ IN/OUT ports 0x150-0x161 (polled C012, LINKIO.C)
|
|
▼
|
|
DOSBox-X I/O handler (host-level C++, ~40 lines) ── TCP 127.0.0.1:8620 ──► vrserver.py
|
|
▲ │
|
|
└─────────────────────── board→host reply bytes ◄─────────────────────────┘
|
|
(VirtualBoard + full logging → capture.log)
|
|
```
|
|
|
|
The I/O handler runs at **host** level (it's DOSBox-X code, not guest code), so it can
|
|
open a normal host socket. No guest-side driver, no changes to `FLYK.EXE`.
|
|
|
|
## Port map (mirror of LINKIO.C `setLA`)
|
|
|
|
| Port | Dir | Handler action |
|
|
|------|-----|----------------|
|
|
| 0x150 | R (Input Data) | return next board→host byte (from socket recv buffer) |
|
|
| 0x151 | W (Output Data) | send byte to socket (host→board) |
|
|
| 0x152 | R (Input Status) | pump socket; bit0=1 if a byte is available |
|
|
| 0x153 | R (Output Status)| bit0=1 (always ready to accept) |
|
|
| 0x160 | W reset / R fifo | on write send the RESET marker; on read return 1 |
|
|
| 0x161 | W (Analyse) | ignore |
|
|
|
|
## Drop-in DOSBox-X I/O handler (sketch)
|
|
|
|
Add to a new `src/hardware/vrlink.cpp` and call `VRLINK_Init()` from hardware init.
|
|
Adapt the handler signatures to your DOSBox-X version; init Winsock on Windows.
|
|
|
|
```cpp
|
|
// vrlink.cpp -- bridge the C012 link ports (0x150-0x161) to vrserver.py
|
|
#include "inout.h"
|
|
#include <winsock2.h> // Windows; use <sys/socket.h> on *nix
|
|
static SOCKET s = INVALID_SOCKET;
|
|
static unsigned char rxbuf[4096]; static int rxlen=0, rxpos=0;
|
|
|
|
static void connect_board() {
|
|
WSADATA w; WSAStartup(MAKEWORD(2,2), &w);
|
|
s = socket(AF_INET, SOCK_STREAM, 0);
|
|
int one=1; setsockopt(s, IPPROTO_TCP, TCP_NODELAY,(char*)&one,sizeof one);
|
|
sockaddr_in a{}; a.sin_family=AF_INET; a.sin_port=htons(8620);
|
|
a.sin_addr.s_addr=inet_addr("127.0.0.1");
|
|
connect(s,(sockaddr*)&a,sizeof a);
|
|
u_long nb=1; ioctlsocket(s, FIONBIO, &nb); // non-blocking reads
|
|
}
|
|
static void pump() { // fill rxbuf if empty
|
|
if (rxpos<rxlen) return;
|
|
int n=recv(s,(char*)rxbuf,sizeof rxbuf,0);
|
|
if (n>0){ rxlen=n; rxpos=0; } else { rxlen=rxpos=0; }
|
|
}
|
|
static Bitu rd(Bitu port, Bitu){
|
|
switch(port){
|
|
case 0x150: pump(); return rxpos<rxlen ? rxbuf[rxpos++] : 0xFF; // Input Data
|
|
case 0x152: pump(); return rxpos<rxlen ? 1 : 0; // Input Status
|
|
case 0x153: return 1; // Output Status
|
|
case 0x160: return 1; // fifo-ok
|
|
} return 0xFF;
|
|
}
|
|
static void wr(Bitu port, Bitu val, Bitu){
|
|
unsigned char b=(unsigned char)val;
|
|
switch(port){
|
|
case 0x151: send(s,(char*)&b,1,0); break; // Output Data
|
|
case 0x160: send(s,"\x00RSET",5,0); break; // reset marker
|
|
case 0x161: break; // analyse: ignore
|
|
}
|
|
}
|
|
void VRLINK_Init(){
|
|
connect_board();
|
|
for (Bitu p=0x150; p<=0x161; ++p){ IO_RegisterReadHandler(p,rd,IO_MB); IO_RegisterWriteHandler(p,wr,IO_MB); }
|
|
}
|
|
```
|
|
|
|
## Run
|
|
|
|
1. `python vrserver.py` (listens on 127.0.0.1:8620, writes `capture.log`)
|
|
2. Launch DOSBox-X (with the handler built in). Mount the HPDAVE tree, set `DOS4GPATH`
|
|
to `sda4/BIN`, run the app the way `SETSVGA.BAT` + `HLOOP.BAT` do:
|
|
```
|
|
set DOS4GPATH=C:\SDA4\BIN
|
|
call SETSVGA.BAT REM sets DPLARG=/tranny~...~/i860~...~/device~0x150~/video~svga~...
|
|
FLYK.EXE <scene args> REM (see HFLY/HLOOP for the scene/run pair)
|
|
```
|
|
3. Watch `capture.log` — it annotates every reassembled message and reply. Boot should
|
|
walk: RESET → 3 iserver txns → `hspcode`/`860code`/`860data`/`860bss`/`860args`
|
|
(discarded) → `init` → scene `create`/`flush`/`dcs_*`/`set_geom_verts`/
|
|
`set_texmap_texels` → `draw_scene` → `readpixels`.
|
|
|
|
## What the capture proves / pins
|
|
|
|
- **Assembler validation:** every message reassembles with the source-derived framing
|
|
(incl. the mirrored bit30). Any mismatch shows up immediately as a bad length/action.
|
|
- **`vr_readpixels` layout (open item):** the request args and the reply chunking/pixel
|
|
word order the shipped lib expects — the one payload the source snapshot stubs.
|
|
- **bit30 semantics (open item):** whether FLYK's receive path requires `0x40000000` on
|
|
replies (we already set it) or ignores it.
|
|
|
|
Once the capture is clean, swap the stub responder for the real render path
|
|
(`vrboard` → dpl3-revive pipeline) and `vr_readpixels` returns actual frames.
|
|
|
|
## No build environment?
|
|
|
|
If DOSBox-X + a C++ toolchain isn't set up, the alternative is to compile the original
|
|
host comms (`VR_COMMS.C` + `LINKIO.C` + `DPL_HOST.C`, port I/O teed to a file) natively
|
|
and drive it with a `STARTDPL.C`-style scene — same framed output, no emulator. Heavier
|
|
(needs the DPL types to build); the socket bridge above is the lighter path.
|