# 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 // Windows; use 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 (rxpos0){ rxlen=n; rxpos=0; } else { rxlen=rxpos=0; } } static Bitu rd(Bitu port, Bitu){ switch(port){ case 0x150: pump(); return rxpos 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.