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:
@@ -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,
|
||||
|
||||
@@ -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 4–6 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 0x150–0x157 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 | Low–Medium | 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 0–2 are the discovery-heavy half; 3 is the largest single block of
|
||||
work; 4–6 are integration. For one experienced developer:
|
||||
|
||||
- Phase 0–1: ~1–2 weeks
|
||||
- Phase 2: ~2–4 weeks
|
||||
- Phase 3: ~4–8 weeks
|
||||
- Phase 4–6: ~3–5 weeks combined
|
||||
- Phase 7: ~1–2 weeks
|
||||
|
||||
Total: roughly **3–5 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 23–16 → 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`
|
||||
Reference in New Issue
Block a user