Add VPX emulation implementation plan for Windows 10 cockpits

emulator/PLAN.md: run the unported DOS Rel 4.10 games in the
surviving cockpits via a DOSBox-X fork with an HLE device
impersonating the Division VPX board at its C012/B004 link
interface (I/O port 0x150 per BTLIVE SETENV.BAT), rendering the
frame stream in OpenGL. Cockpit RIO (COM1) and plasma (COM2) pass
through to the game's original serial drivers (L4RIO.CPP).
Eight phases with acceptance criteria, evidence table, protocol
appendices, risks, and test strategy. Gauge displays deferred.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-02 19:09:33 -05:00
co-authored by Claude Fable 5
parent 326d29b72a
commit f7ebde2e0b
2 changed files with 267 additions and 0 deletions
+5
View File
@@ -8,6 +8,11 @@ two games that ran on the **Tesla**-generation simulator cockpits built by
This repository is an archival snapshot. The tree is preserved byte-for-byte as
found (see `.gitattributes` — no line-ending conversion is applied).
See [emulator/PLAN.md](emulator/PLAN.md) for the implementation plan to run
these games on the surviving cockpits' Windows 10 computers via a VPX-board
HLE device in DOSBox-X, with the cockpit RIO (COM1) and plasma display (COM2)
passed through to the game's original drivers.
See [HISTORY.md](HISTORY.md) for findings from a recovered VWE developer hard
drive that accompanies this tree (excluded from the repo), including Division
renderer source, runnable game builds, unreleased prototypes (Star Trek,
+262
View File
@@ -0,0 +1,262 @@
# Tesla Rel 4.10 on Windows 10 — VPX Emulation Implementation Plan
## Goal
Run the unported DOS versions of **Tesla:BattleTech** and **Tesla:Red Planet**
(release 4.10) inside the surviving cockpits, whose computers now run
Windows 10. The games are complete on disk (`sda4/BTLIVE`, `sda4/RPLIVE`
executables, resources, content), but they render through **Division Ltd.'s
VPX board**, hardware that no longer exists in the pods. Everything else the
games need still exists or is emulatable.
The approach: a customized DOS emulator whose main addition is a
**high-level-emulation (HLE) device that impersonates the VPX board** at its
host interface and renders with modern GPU APIs. The cockpit's real RIO
(COM1) and plasma display (COM2) are passed through to the physical serial
ports so the game's own drivers operate the actual cockpit hardware.
```
┌─ Windows 10 cockpit PC ─────────────────────────────────────────────┐
│ ┌─ DOSBox-X (custom fork) ─────────────────────────────────────┐ │
│ │ BTL4 game EXE (DOS, Borland 32-bit, unmodified) │ │
│ │ ├─ I/O port 0x150..0x153 ──► VPX HLE device ── OpenGL ─────┼─► main display
│ │ ├─ COM1 ── serial passthrough ─────────────────────────────┼─► RIO (cockpit controls)
│ │ ├─ COM2 ── serial passthrough ─────────────────────────────┼─► plasma display
│ │ ├─ SB16 emulation ── host audio ───────────────────────────┼─► cockpit speakers
│ │ ├─ NE2000 emulation ── pcap/slirp ─────────────────────────┼─► pod-to-pod network
│ │ └─ emulated VGA (DOS console; later: gauges) ──► window │ │
│ └───────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────┘
```
## Why this is feasible — the evidence
Every load-bearing fact below was verified against files in this repository
and the Glaze drive dump (`sda4/`):
| Fact | Evidence |
|---|---|
| Host↔board link is an INMOS **C012 link adapter, IMS B004-style**: polled byte FIFO on 46 I/O ports, no host interrupts, no host DMA | `sda4/DPL3/LINKIO.C` ("simple polled PC / DOS interface, a la IMS B004", `setLA()`, `INPUT_READY`/`OUTPUT_READY` status bits) |
| The link adapter sits at **I/O port 0x150** in the shipped install | `sda4/BTLIVE/SETENV.BAT`: `DPLARG=... /device~0x150~ ...` |
| Boot sequence: host loads a transputer monitor, then i860 code segments, over the link | `DPLARG=/tranny~.\vrendmon.btl~/i860~.\vrnostex.mng~...`; `sda4/DPL3/VR_COMMS.C` (`i860_segment`, `vr_860code_action`, `vr_860data_action`) |
| Message protocol on the link: ≤1023-byte packets, 32-bit length/route word (sender/target id, iserver flag, broadcast id 0xff) | `sda4/DPL3/VR_COMMS.C` header comment + `send_protocol()` |
| Frame sync is **polled over the link** ("frame ack"), not interrupt-driven | `sda4/DPL3/VR_COMMS.C` (`frame ack` handling, `velocirender_inputstatus`) |
| The board-side renderer's behavior is documented **in source** | `sda4/DPL3/VRENDER/` (C + i860 asm, `PXPL5SUP/`, `DMA.TXT` tile-loop description, register maps `DIVPXMAP.H`, `DMAENGN.H`) |
| Triangle/command encodings | `CODE/*/MUNGA_L4/LIBDPL/dpl/vpx/TRICODER.H`, `VR_PROT.H`, `DPL_VPX.H` |
| The game natively drives the **RIO on COM1** | `CODE/RP/MUNGA_L4/L4RIO.CPP` + `L4RIO.HPP` (complete driver source); `L4CTRL.CPP` accepts `L4CONTROLS=RIO` / `RIO:COM1` |
| Plasma display on COM2, optional subsystems | `sda4/VGL_LABS/BOOTPOD.*` (`L4PLASMA=com2`, `L4SOUND`, `L4GAUGE`, `L4INTERCOM` all optional) |
| Keyboard fallback for controls exists (dev "office/cart" config) | `BOOTPOD.*`: `L4CONTROLS=THRUSTMASTER,KEYBOARD` |
| Complete runnable game installs | `sda4/BTLIVE/`, `sda4/RPLIVE/` (EXEs, `BTL4.RES`, content, `BT.BAT`/`BTGO.BAT`/`BTNET.BAT` launch modes) |
| Renderer configuration is data-driven from files we have | `sda4/BTLIVE/BTDPL.INI` (fog/lights per arena/time/weather, particle defs, cache lists) |
| All geometry/material/texture formats already decoded and re-rendered | `restoration/divformats.py`, `restoration/vwe-archive.html` |
| Audio: HMI SOS on SB16 | `sda4/VGL_LABS/AUTOEXEC.POD` (`SET BLASTER=A220 I5 D1 H5 P330 T6`) |
| Networking: WATTCP/BOOTP over a packet driver | `CODE/*/MUNGA_L4/NETNUB/` |
Note the pods ran **two** sound cards (`AWE_FRONT` at A220, `AWE_REAR` at
A240 per `AUTOEXEC.POD`). Phase 6 targets one emulated SB16; rear-channel
audio is deferred alongside the gauges.
## Platform choice
**Fork DOSBox-X** (Windows builds, active project, GPL):
- Built-in **serial passthrough** to real COM ports (`serial1=directserial realport:COM1`) — the RIO and plasma work through the game's own drivers with no new code.
- Built-in SB16, game port, NE2000 (pcap + slirp backends).
- Runs Borland DPMI/32RTM protected-mode DOS apps well; cycle throttling for a game that expects a Pentium Pro.
- Clean I/O-port device API for the custom VPX device; access to host OpenGL.
Alternative considered: **86Box** (full PCI/Pentium machine emulation).
Better absolute fidelity, but heavier, harder to bolt a GL-rendering device
into, and per-cycle emulation costs more than we need. DOSBox-X is the right
tradeoff; nothing in the plan precludes porting the VPX device to 86Box
later.
## Phases
### Phase 0 — Groundwork (repo + environment)
- [ ] Create `emulator/` build tree; vendor a pinned DOSBox-X source snapshot
(submodule or subtree) and stand up a Windows build (Visual Studio).
- [ ] Assemble a clean game image: `BTLIVE` copied into a DOSBox-X mounted
directory; replicate `AUTOEXEC.POD` environment (`SET BLASTER=…`,
`L4CONTROLS=KEYBOARD` initially, `VIDEOFORMAT=svga`).
- [ ] Boot the game unmodified and record how far it gets (expected: DPL
init fails at the missing link adapter).
- **Acceptance:** documented baseline failure mode; build reproducible.
### Phase 1 — Interface discovery (logging stub)
- [ ] Add a DOSBox-X device claiming I/O ports 0x1500x157 that logs every
read/write with timestamps and returns configurable status bits.
- [ ] Drive the game through init; capture the full port trace. Compare
against `LINKIO.C` semantics (C012 register order: input data, input
status, output data, output status, + reset/analyse) and identify the
exact register map and any block-transfer (`outsw`) usage.
- [ ] Verify the trace against `VR_COMMS.C`'s expected send sequence
(reset → tranny boot → i860 code/data segments → version handshake).
- **Acceptance:** annotated trace of the complete boot conversation; the
register map and framing confirmed from the *shipped binary*, not
just the DPL3 sources (guards against protocol drift between the
DPL3 snapshot and the LIBDPL.LIB actually linked into Rel 4.10).
### Phase 2 — Link + boot protocol emulation
- [ ] Implement the C012 FIFO state machine (status bits, byte in/out,
reset/analyse behavior) with correct "always ready" pacing.
- [ ] Implement transputer bootstrap acceptance: consume `VRENDMON.BTL`,
emit whatever readiness bytes the monitor protocol expects (normative
reference: `VR_COMMS.C` boot path; the `.BTL` content itself is
discarded — we impersonate, not execute).
- [ ] Accept i860 code/data segment uploads (`vrnostex.mng` /
`vrendmon`-loaded `vrend*.btl` variants); discard content; ACK.
- [ ] Implement the message layer: 32-bit length/route word, ≤1023-byte
payloads, iserver vs. renderer messages, broadcast id 0xff.
- [ ] Answer version/status queries with values captured from `VR_PROT.H` /
`DIVVERS.H` conventions; iterate until DPL init returns success.
- **Acceptance:** game completes `dpl` startup with `/device 0x150` and
proceeds to resource loading; its console shows the same startup
banner sequence the INI/logs imply.
### Phase 3 — Frame-stream renderer (the core)
- [ ] Decode the per-frame message stream: matrices/viewpoint, object and
geometry references, material/texture state, light/fog/clip setup,
and the `TRICODER.H` triangle encoding. Normative references:
`VR_PROT.H`, `DPL_VPX.H`, `DPL.H`/`DPL_HOST.C` (what the host sends),
`VRENDER/*.c` (how the board consumed it).
- [ ] Texture uploads: SVT/BSL texel formats are already decoded in
`restoration/divformats.py`; port that logic to C++ (incl. 4-bit
mono bit-slice textures with material color modulation).
- [ ] OpenGL backend in the device: double-buffered FBO, Division shading
model (ambient/diffuse/emissive, RGB shading ramps, per-vertex
"cooked" colors, linear fog with per-material fog immunity) —
semantics already validated visually by `restoration/vwe-archive.html`.
- [ ] Present in a dedicated borderless window (target: the cockpit's main
projector output), independent of the DOSBox-X VGA window.
- [ ] **Capture/replay harness:** every session can dump the raw link
byte-stream; a standalone tool replays dumps into the renderer
without DOSBox-X. This makes renderer work testable in isolation and
lets us regression-test against golden frames.
- **Acceptance:** attract mode / mission renders recognizably; golden-frame
comparisons against the scene-archive renderer for the same content.
### Phase 4 — Frame pacing and sync
- [ ] Implement the frame-ack poll exactly as the game expects (respond as
the board would at ~30 Hz; configurable). `RETRACE n` in scene data
implies frame-rate divisors — honor them.
- [ ] Tune DOSBox-X cycle settings for Pentium-Pro-class throughput; verify
game simulation speed against the 30 Hz assumption in game code.
- **Acceptance:** stable 30 fps, no spiral-of-death when the host GPU is
momentarily slow; timing feels correct in motion.
### Phase 5 — Cockpit I/O: RIO and plasma
- [ ] `serial1=directserial realport:COM1` (RIO), `serial2=…COM2` (plasma);
set `L4CONTROLS=RIO:COM1`, `L4PLASMA=com2`.
- [ ] Validate against `L4RIO.CPP` expectations (framing, polling rate,
shared-data messages). Risk is low — the game's own driver does the
talking — but latency through the emulated UART must be measured;
if polled-UART overhead hurts, add a fast path.
- [ ] Keyboard fallback (`L4CONTROLS=KEYBOARD`) retained for bench testing.
- **Acceptance:** cockpit sticks/pedals/buttons drive the game; plasma
shows its normal content.
### Phase 6 — Audio and network
- [ ] SB16 at A220/I5/D1 (matches `AUTOEXEC.POD` front card); confirm HMI
SOS drivers initialize and stream. Rear card (A240) deferred.
- [ ] NetNub: NE2000 emulation + packet driver, bridged via pcap so two
cockpits (or a cockpit and a test PC) see each other; stand up the
BOOTP expectations WATTCP has (`NetNub/include/BOOTP.H`).
- **Acceptance:** sound effects + MIDI play; two instances complete a
networked mission handshake.
### Phase 7 — Deployment hardening
- [ ] Per-pod configuration file (COM mapping, display selection, pod id,
game selection BT/RP) mirroring the old `VGL_LABS` per-pod setup.
- [ ] Autostart: boot-to-game like the original pods (`BOOTPOD.BAT`
equivalent as a Windows service/scheduled task), watchdog restart.
- [ ] Error logging (`PREFMODE=ERRORLOG` existed in the original scripts —
keep the spirit: never strand a pod on a DOS prompt).
- **Acceptance:** power-on → attract mode with no operator interaction.
### Phase 8 — Deferred (tracked, not in critical path)
- **Gauge displays:** original pods drove six instrument displays from the
S3 card while the Division board drove the main view. Options, in
ascending fidelity: (a) run with `L4GAUGE=` empty (supported by the game);
(b) present the emulated VGA/VESA output in a window on a secondary
monitor; (c) split/route to the physical gauge displays. Decide after
Phase 5 when the real display topology is measured.
- **Rear audio channel** (second SB16/AWE at A240).
- **Intercom** (`L4INTERCOM`).
- **NTSC video mode** (`/video~ntsc`): only if a pod's projector chain
still wants NTSC; SVGA path is primary.
## Risks and mitigations
| Risk | Likelihood | Mitigation |
|---|---|---|
| Protocol drift: Rel 4.10's LIBDPL differs from the DPL3 sources | Medium | Phase 1 derives the real protocol from the shipped binary's port trace; DPL3RLS + dated `VREND/` drops bracket the era |
| Undocumented bulk-transfer mode (`outsw`, `ok_to_fifo`) | Medium | Still plain port I/O; the trace will show it; implement what's observed |
| Game validates renderer version/capabilities strictly | Medium | Answer with values from `VR_PROT.H`/`DIVVERS.H`; iterate from the game's error messages (it prints useful diagnostics per `VR_COMMS.C` style) |
| Hidden second link adapter / interrupt use | Low | `LINKIO.C` is fully polled; the trace will falsify this cheaply |
| RIO protocol quirks under emulated UART timing | LowMedium | Driver source is in-repo (`L4RIO.CPP`); real hardware available for testing |
| DPMI/32RTM incompatibility in DOSBox-X | Low | Known-good app class; 86Box as fallback platform |
| Performance (parsing + GL per frame) | Very low | 1996 scene complexity; thousands of triangles |
## Test strategy
1. **Unit:** protocol framing round-trip tests against `VR_COMMS.C`
semantics; TRICODER decode against hand-built vectors.
2. **Replay:** captured link-stream dumps replayed into the standalone
renderer; golden-image diffs (allowing rasterizer tolerance).
3. **Cross-check:** the same models rendered by `restoration/` tools vs.
the emulator renderer must agree on geometry/material interpretation.
4. **Hardware-in-loop:** bench PC + real RIO on COM1 before cockpit time;
cockpit sessions scripted with a checklist (controls, plasma, audio,
network, endurance run).
## Sequencing and effort
Phases 02 are the discovery-heavy half; 3 is the largest single block of
work; 46 are integration. For one experienced developer:
- Phase 01: ~12 weeks
- Phase 2: ~24 weeks
- Phase 3: ~48 weeks
- Phase 46: ~35 weeks combined
- Phase 7: ~12 weeks
Total: roughly **35 months** of focused work to "playable in a cockpit,"
with the gauge displays intentionally out of scope until after that
milestone.
## Appendix A — C012/B004 register model (from `LINKIO.C`)
Base address `LA` (0x150 in the shipped configuration):
| Offset | Register | Behavior |
|---|---|---|
| +0 | input data | read one byte from board→host FIFO |
| +1 | output data | write one byte host→board |
| +2 | input status | bit 0 = byte available |
| +3 | output status | bit 0 = ready to accept |
| +4/+5 | reset / analyse | board reset & debug lines (per B004 convention; exact offsets to be confirmed in Phase 1 trace) |
## Appendix B — message framing (from `VR_COMMS.C`)
Every message begins with a 32-bit length/route word:
- bit 31 set → iserver-class message (boot/loader); clear → renderer message
- bits 2316 → sender id (to host) / target id (from host); 0xff = broadcast
- low bits → payload byte count (≤1023 for renderer messages)
Boot order (from `DPLARG` and `VR_COMMS.C`): board reset → transputer
bootstrap (`VRENDMON.BTL`) → i860 code segment → i860 data segment →
version handshake → texture/geometry environment setup → frame loop
(commands + triangles, then frame-ack poll).
## Appendix C — primary sources
- Host link layer: `sda4/DPL3/LINKIO.C`, `sda4/DPL3/VR_COMMS.C`
- Protocol constants: `CODE/*/MUNGA_L4/LIBDPL/dpl/vpx/VR_PROT.H`,
`TRICODER.H`, `DPL_VPX.H`, `DPL_MEM.H`
- Host library behavior: `sda4/DPL3/DPL.C`, `DPL_HOST.C`, `DPL_LOAD.C`
- Board-side renderer (normative for HLE behavior): `sda4/DPL3/VRENDER/`
- Shipped boot config: `sda4/BTLIVE/SETENV.BAT` (`DPLARG`), `BTDPL.INI`
- Cockpit I/O: `CODE/RP/MUNGA_L4/L4RIO.CPP`/`.HPP`, `L4CTRL.CPP`,
`sda4/VGL_LABS/BOOTPOD.*`, `AUTOEXEC.POD`
- Data formats (already reimplemented): `restoration/divformats.py`