VDB-NOTES: full board documentation (RE from driver + HLE; physical sample exists)

Comprehensive VWE Video Display/splitter Board writeup: what it is (dumb ISA
splitter tapping the companion Cirrus Logic SVGA feature connector), the
definitive I/O register map from L4SVGA16.ASM (Secondary 0x302 / Aux1 0x30A /
Aux2 0x312, each +0 mask/+1 read/+2 write/+3 data, 6-bit DAC; clock divider
0x319 off / 0x31A on), the byte-lane split (low byte->Secondary, high
byte->Aux1/Aux2 -> separate VGA heads -> octopus cable -> 5 mono MFDs + color
radar), the driver's bitMask+channelEnable CLUT-build trick that packs multiple
displays into one framebuffer, the pixel-mask flash + Secondary-only fade, our
emulation, the OPEN RP decode problem, and a physical-sample verification
checklist (port-decoder PAL, 3 RAMDACs, octopus pinout, Cirrus chip id).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-09 15:28:24 -05:00
co-authored by Claude Fable 5
parent e1b43fb6d5
commit 2261dd804a
+134
View File
@@ -0,0 +1,134 @@
# The VDB — VWE Video Display/Splitter Board
Reverse-engineered from the shared MUNGA_L4 driver (`CODE/RP/MUNGA_L4/
L4SVGA16.ASM` + `L4VB16.CPP`/`.HPP`) and the pod emulator's HLE
(`emulator/vpx-device/vpxlog.cpp`). **A physical VDB sample + its companion
Cirrus Logic SVGA card exist** (operator, 2026-07-10) — see the hardware
verification checklist at the end. This board is IDENTICAL between BattleTech
and Red Planet (shared driver); only the game-side display layout differs.
## What it is
An ISA card that **taps the companion Cirrus Logic SVGA card's pixel output**
off the VGA feature connector and fans that ONE framebuffer out to the six
secondary cockpit displays (5 mono MFDs + 1 color radar) via three RAMDAC-like
palette groups. It is a DUMB splitter: no framebuffer of its own, no
compute — it re-clocks the SVGA pixel stream and routes byte-lanes through
palette CLUTs to separate VGA heads. "Adam's port decoder design" (Adam G.,
VWE hardware) per the driver comments.
The game renders cockpit gauges to the Cirrus SVGA in a **640x480x16bpp**
mode (VBE mode 0x111; `L4GAUGE=640x480x16`). The Division/VPX card is separate
(the out-the-window 3D). So the SVGA framebuffer the VDB taps = GAUGES ONLY.
## Register map (definitive, from L4SVGA16.ASM)
I/O 0x300-0x31A. Three palette groups, each a 6-bit VGA-DAC-style CLUT. The
driver's port table (`L4VB16.CPP` ~3685) passes the group base as **base+2**:
```
Group base(+2) mask read-addr write-addr data
NativePalette 0x3C6 (the Cirrus's own VGA DAC — 0x3C6/0x3C8/0x3C9)
SecondaryPalette 0x302 0x302 0x303 0x304 0x305
AuxiliaryPal1 0x30A 0x30A 0x30B 0x30C 0x30D
AuxiliaryPal2 0x312 0x312 0x313 0x314 0x315
Clock divider: 0x319 write = high-color divider OFF (VWE_HC_OFF)
0x31A write = high-color divider ON (VWE_HC_ON) (any value)
```
Per-group offsets (VGA-DAC layout): **+0 pixel-mask, +1 read-address,
+2 write-address, +3 data** (auto-incrementing R,G,B triplets). DAC is
**6-bit**: `SVGAWriteFullPalette` does `shr al,2` (8→6) on write,
`SVGAReadFullPalette` does `shl al,2` (6→8) on read. Palette load =
set write-addr to 0, then `rep outsb` 256*3 bytes. Mask write = one `out`
to base+0. The game only WRITES the VDB (fire-and-forget, no status/ACK);
reads return DAC read-back.
## How the split works (the dumb part)
**High-color clock divider (0x31A on):** in 16bpp mode each pixel is two
bytes. The divider clocks the LOW byte and HIGH byte of each pixel into
SEPARATE palette lanes → separate heads. So:
- **LOW byte (bits 0-7) -> Secondary palette (0x302 group) -> one head**
- **HIGH byte (bits 8-15) -> Aux1/Aux2 palettes -> the other heads**
Each head is a physical VGA output off the splitter; an "octopus" cable fans
the (up to) three head signals to the six cockpit displays. Decode confirmed
live for BT: radar = low byte via Secondary; the 5 mono MFDs = high byte via
Aux1/Aux2 color channels. [[vdb-three-vga-head-decode]]
## How the game packs multiple displays into one framebuffer
The card is dumb, but the DRIVER is clever about loading the CLUTs so several
displays share the same pixels. Each cockpit display (`L4GraphicsPort`) has:
- **`bitMask`** — which framebuffer pixel BITS belong to this display.
- **`channelEnable`** — which DAC color channel it drives: Red / Green / Blue
/ AllChannels (+ ...TransparentZero variants that leave index 0 undefined).
`BuildSecondaryPalette` (low byte = `bitMask & 0xFF`) and
`BuildAuxiliaryPalette` (high byte = `(bitMask>>8) & 0xFF`) walk the display's
bits with a `BitWrangler` and write that display's color/ramp into its channel
of the shared 256-entry CLUT. So N mono displays coexist in one byte-lane by
owning disjoint bit groups and different color channels; the CLUT decodes each
combination back to the right per-display brightness. `BuildAuxiliaryPalette`
generates a linear brightness RAMP across the display's bit values (mono
MFD = beam intensity); `BuildSecondaryPalette` copies source colors (color
radar).
## Palette flash + fade (the pixel-mask cycling)
`SVGA16::UpdatePalette` (`L4VB16.CPP` ~4196): each palette can FLASH by
cycling its **pixel-mask** through `mask[]` states at `flashRate` (this is the
`0x302` mask writes seen cycling e.g. 0x3F/0x7F/0xBF/0xFF — a blink, NOT index
decode). **Only the Secondary palette is allowed to FADE** (its RGB scaled
over time). So the pixel-mask register is used as a per-display blink control,
not (usually) as a decode gate.
## Our emulation (vpxlog.cpp)
`vdb_write`/`vdb_read` mirror the register map (`VDB_BASE=0x300`,
`vdb_group_of`/`vdb_group_base`); `vdb_pal[0/1/2]` = Secondary/Aux1/Aux2.
`pal_draw` reads the live Cirrus framebuffer (`vga.mem.linear` at
`vga.config.real_start`, 640x480, stride 1280) and for each pixel looks up
the low byte via pal0 and high byte via pal1/pal2 (one color channel per mono
head, pentapus split). 6-bit DAC expanded to 8-bit. `VDB_PALDUMP=<prefix>`
dumps each group's 768-byte CLUT; pixel-mask writes now log their value; masks
default 0xFF; `VDB_APPLYMASK=1` ANDs the index with the mask (correct DAC
emulation, default off = BT-identical).
## RP vs BT — the OPEN decode problem (2026-07-10)
Same board, same driver. Captured live for RP (VDB_PALDUMP): framebuffer
identical (mode 0x111, 640x480); **Secondary/pal0 loads ALL ZEROS** (BT drives
it as the dynamic color radar) -> our radar head is black; Aux1=green,
Aux2=RGB are driven; the RP MFD heads decode as SPARSE fragments in the top
strip. So under the shared mechanism, RP simply puts NO display in the low
byte (Secondary empty is legitimate), and its high-byte MFD content is not
landing where our BT-tuned head/channel split expects.
**Operator's steer: the card is dumb, so the fix is glaringly simple** — not
a driver-logic difference. Leading suspects to check next (empirically, like
the first BT pass): (a) the framebuffer PAGE/`real_start` — is RP double-
buffering so we read a stale/wrong SVGA page? (`SVGASetPage` exists); (b) the
device DUMP path stopped writing win*.bmp for RP (fires in pal_draw) — worth
finding why, it may reveal the head-render path isn't running the same;
(c) which bit groups/channels RP's displays actually claim (dump a BT vs RP
Aux palette side-by-side; the ramp/channel structure shows the bit layout);
(d) confirm the low/high byte order and the 640x480 vs a smaller gauge region
(top-strip content hints RP may draw gauges in fewer rows).
## Physical-sample verification checklist (have the board + Cirrus card)
Photograph and record for the archive:
- **Splitter board**: the port-decoder PAL/GAL (mark/part#) at 0x300-0x31A;
the THREE RAMDAC chips (part#, are they real Bt476/Bt478-class or a Cirrus
DAC?) and how their pixel-mask/addr/data pins map to 0x302/0x30A/0x312; the
high-color-divider logic tied to 0x319/0x31A; the feature-connector tap.
- **Octopus cable**: pinout — which of the 3 head outputs feeds which of the
6 cockpit displays (confirms the pentapus win5-9 + radar mapping).
- **Companion Cirrus Logic card**: exact chip (CL-GD54xx?) + BIOS, to pin the
640x480x16 mode/pitch and the feature-connector timing the divider assumes.
- Any onboard ROM/PAL dump (like the RIO EPROM) for full preservation.
Related: [[vdb-three-vga-head-decode]], [[tesla-cockpit-emulator-state]].