diff --git a/README.md b/README.md index 61a36a4..d69f200 100644 --- a/README.md +++ b/README.md @@ -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, diff --git a/emulator/PLAN.md b/emulator/PLAN.md new file mode 100644 index 0000000..d174553 --- /dev/null +++ b/emulator/PLAN.md @@ -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`