Files
TeslaRel410/emulator/RIO-NOTES.md
T
CydandClaude Fable 5 7670d40b37 VDB heads: 4-head cockpit layout (VPX_COCKPIT=1), drop exploratory windows
- VPX_COCKPIT=1 places the four VGA heads as borderless windows:
  Division main 800x600 @ 0,0; radar (win0) 640x480 @ 800,0; MFD heads
  win3/win4 640x480 @ 1440,0 / 2080,0 (heads 3+4 are driver-spanned
  into one 1280x480 canvas). VPX_MAIN / VPX_WIN<g> = x,y[,w,h]
  overrides any window without a rebuild; default debug layout kept.
- Remove exploratory win1/win2 (bits 0-7 via static palettes); keep the
  0/3/4 numbering so win<g>.bmp dump names stay stable.
- Sync commit copy with the build tree: per-head palette decode in
  pal_draw() and device-side BMP capture (VPX_DUMPDIR).
- RIO-NOTES: document the PCSPAK DISABLE_AND_DIE patch (error-3 crash
  on RIO resets); restore the terrain-shadow section heading it ate.
- Add gauge_rio{,_log}.conf launch configs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 22:30:33 -05:00

6.0 KiB
Raw Blame History

RIO cockpit controls — passthrough tuning (Phase 5+)

The RIO (Remote Input/Output) is the cockpit control board on COM1 (the plasma display is COM2, handled later). DOSBox-X talks to a real RIO through serial1=directserial realport:COM1 (game_rio.conf). On this host the RIO is a Prolific USB-to-Serial adapter enumerated as COM1.

The analog-poll latency problem (solved)

The initial RIO check request tolerates latency and passed easily. But the runtime control loop (L4CTRL.CPP:1145) sends an analog request every cycle and, if the reply doesn't return inside its window, logs LBE4ControlsManager::Execute, lost RIO analog request and re-requests. The board itself refuses/drops comms if the ACK is late by more than a few milliseconds — a hard real-time deadline.

Empirical result (2026-07-03): a slower CPU made the RIO fail sooner. So the dominant latency was how fast the game processes the RIO packet and emits the ACK, not the serial wiring. The fix:

[cpu]
core=dynamic     ; recompiler — many x faster than the 'normal' interpreter
cputype=pentium
cycles=max       ; full host speed

With core=dynamic + cycles=max the RIO stays in sync (the user confirmed "the rio behaved"). Notes:

  • cycles=fixed 20000 / 150000 and core=normal were all too slow — the RIO dropped comms, faster at lower speeds.
  • The DOSBox-X serial path is already low-latency on transmit (directserial.cpp transmitByte calls SERIAL_sendchar immediately).
  • Prolific PL2303 has no adjustable LatencyTimer registry value (unlike FTDI); an FTDI adapter set to 1 ms latency would be the lowest-latency host option if ever needed.

Receive-latency fork options (2026-07-03)

Even with the fast CPU, intermittent timeouts remained and the game would drop into its 15-second analog retry fallback — the source shows limit = 15.0; // 0.2 in L4CTRL.CPP, so the shipped binary re-requests very slowly once replies stop arriving ("the polling is really slow"). Two emulator receive latencies were fixed with new directserial options:

  • rxpollus:<us> (501000, stock 1000): host-port receive poll tick. Stock DOSBox-X discovers inbound bytes on a 1 ms tick; 100 µs discovers them ~10× sooner. First validated result: the sim advanced and the camera moved in the render window.
  • rxburst:<n> (164): stock DOSBox re-serializes each received byte at emulated wire speed (~1 ms/byte at 9600) even though the bytes already paid their wire time on the physical cable and sit in the host buffer — a 15-byte analog reply gained ~14 ms of artificial latency, single-handedly blowing the RIO's few-ms ACK window. rxburst:16 delivers buffered bytes 16× faster.

game_rio.conf uses realport:COM1 rxpollus:100 rxburst:16.

The crash-to-desktop: PCSPAK's DISABLE_AND_DIE (patched)

The recurring hard fault (Exception 0E, write to 0xFFFFFFFF-ish, e.g. at BTL4OPT CODE+0x7D1D1 with EAX=3) is deliberate: the RIO serial packet driver (CODE/RP/MUNGA_L4/PCSPAK.ASM) was shipped built with DIE_ON_ERROR equ 1, which compiles a DISABLE_AND_DIE <code> debugging macro at 12 error sites — it retracts the UART IRQ, EOIs the PIC, and then "crashes loudly" by writing the error code to address 0xFFFFFFFF.

Our crash is error 3 (PCSPAK.ASM:1630): a byte ≥ 0x80 found in the TX ring body (the protocol reserves high-bit bytes for commands). It gets hit via the ACK/NAK-interrupt → restart path — exactly what physical RIO resets and timeout storms exercise. On clean pod serial timing this never fired; on a USB-serial rig with resets it does.

The source's release configuration (DIE_ON_ERROR equ 0) makes the macro empty and the code recovers (the next instruction masks the byte with and al,7Fh and continues). We reproduce that intended behavior by patching all 12 die sequences (50 52 BA FF FF FF FF B8 xx 00 00 00 89 02 → NOPs) in the working image's BTL4OPT.EXE. Original preserved as BTL4OPT.EXE.orig. Error-code map (from PCSPAK.ASM): 0/1/2 rx framing states, 3 tx body >0x7F, 4/5 tx state.

Crash-on-advance fixed: arena terrain shadows

With the RIO in sync the sim advances and the game crashed dereferencing the mech terrain shadow renderable: *_TSHD.BGF live only in VIDEO/GEO/ARENA/ + …/POLAR/, which the object search path misses, so thr_tshd.bgf failed to load and left a null renderable that the moving sim eventually touched. Fix: the 11 *_TSHD.BGF files are copied from ARENA/ into VIDEO/GEO/ in the working image (reversible, one file each). After the fix the game runs sustained (500+ frames, no crash).

Next wall: mission content (a game-data issue, not protocol/RIO)

With the RIO feeding real input, the simulation advances — and then the game faults:

32loader runtime error: Unhandled exception
Exception 0E at 00FF:0040223B
Module 'BTL4OPT.EXE' section 'CODE' offset 0000123B
[..] 8B 4D 0C (mov ecx,[ebp+0C])  8B 11 (mov edx,[ecx])   ECX=2
The instruction referenced illegal address 00000002

A near-null pointer (2) dereference: a function got 2 where an object pointer was expected. This is downstream of the failed content load logged just before it:

Entity -1:63 class:42 couldn't figure out how to MakeEntityRenderables
L4VIDEO.cpp couldn't load object thr_tshd.bgf

thr_tshd.bgf exists in VIDEO/GEO/ARENA/ and VIDEO/GEO/POLAR/, but not the top VIDEO/GEO/. The game builds its object search path from objectpath entries in the mission notation file (L4VIDEO.CPP:1852), i.e. from the .egg. The shipped test.egg is only mission parameters and does not set up the arena object path, so arena-specific objects aren't found; the entity gets a broken renderable and the sim eventually dereferences it.

To progress past this needs a real mission/arena .egg (or an object path manually pointed at the selected arena's VIDEO/GEO/<ARENA> subdir). That is content/mission configuration, separate from the VPX protocol, the renderer, and the RIO — all of which now work.