From e8876e521d461df638d7de294849f169856ffff8 Mon Sep 17 00:00:00 2001 From: Cyd Date: Fri, 3 Jul 2026 18:03:29 -0500 Subject: [PATCH] Gauges: fix bank-switching (window-granularity mismatch) The garbled top-strip render was a paging bug, not the video mode. The pageFcnPtr in L4GAUGE.INI (C000:2616) is a red herring -- the driver's direct- pointer path is commented out ("THIS DOES NOT WORK"); it pages via portable VESA int 10h/4F05, which our S3 handles. Real cause: window granularity. SVGASetPage passes the bank in granularity units; the blit advances by pageDelta = pageSize/granularity per 64KB window crossed. The INI's granularityInKB=4 is the Cirrus CL-GD5434's 4KB window granularity (the pod's actual video card; the "STB Horizon+" board was Cirrus-based). Our emulated S3 uses 64KB banks, so pageDelta=16 -> every bank landed 16x too far -> the smear. Fix (config only): L4GAUGE.INI [640x480x16] granularityInKB=64 (=sizeInKB, so pageDelta=1, matching the S3's 64KB banks). Full framebuffer now pages correctly -- 315+ frames, VDB splitter stays ON, display renders as expected (blank between missions; user confirmed "that is the screen I expect"). ALPHA_1 is git-ignored so the INI edit isn't committed; reproduction + backup (L4GAUGE.INI.orig) documented in GAUGE-NOTES.md. Co-Authored-By: Claude Opus 4.8 --- emulator/GAUGE-NOTES.md | 53 ++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/emulator/GAUGE-NOTES.md b/emulator/GAUGE-NOTES.md index 97978b6..04cd137 100644 --- a/emulator/GAUGE-NOTES.md +++ b/emulator/GAUGE-NOTES.md @@ -39,33 +39,36 @@ Separately, `patch_btl4opt.py` now also neutralizes the general `Verify_Failed` debug-assertion crash (this is a `DEBUG_LEVEL 1` build); not required for the heap fix but makes the debug build behave like release under emulation. -## Open: bank-switching garbles the framebuffer +## Fixed: bank-switching (window-granularity mismatch) -The gauge framebuffer currently renders **only a top strip, garbled** — the -rest black. 640×480×16 is 600 KB accessed through a 64 KB window; the game -pages it by **calling a hardcoded far pointer** from `L4GAUGE.INI`: +Symptom: the gauge framebuffer first rendered **only a top strip, garbled**. +Not the video mode (that works) — a paging error. 640×480×16 is 600 KB +accessed through a 64 KB window, so the game pages video memory as it blits. -``` -[640x480x16] -mode=273 ;0111h -pageFcnPtr=796182 ;C000:2616 <- STB Horizon+ VESA bank-switch routine -``` +`L4GAUGE.INI`'s `pageFcnPtr` (`C000:2616`, the pod card's VESA `WinFuncPtr`) +is a **red herring** — the direct-pointer path is commented out in the driver +(`L4SVGA16.ASM` `SVGASetPage`: *"THIS DOES NOT WORK … must use a DPMI call"*). +The live code pages via **portable VESA int 10h / AX=4F05h**, which our S3 +handles fine. -`C000:2616` is the STB card's VESA `WinFuncPtr`. On our emulated S3 that -address is not the bank-switch function, so paging fails and only the first -bank(s) (~top 50–100 lines) render. Until this is fixed there is no complete -framebuffer to divide into the six displays. +The real bug was **window granularity**. `SVGASetPage` passes the bank in +*granularity units*; the blit advances the bank by +`pageDelta = pageSize / granularity` each time it crosses a 64 KB window +(`L4VB16.CPP` ~3947). The INI carried `granularityInKB=4` — the **Cirrus +CL-GD5434**'s 4 KB window granularity (the pod's video card; the "STB +Horizon+" board was Cirrus-based). Our emulated **S3 uses 64 KB banks** (its +CR6A bank register selects 64 KB pages, and DOSBox-X's default VBE granularity +for S3 is 64 KB). So `pageDelta = 64/4 = 16` and every bank landed 16× too +far → the smear. -Fix options (next): -1. **Point `pageFcnPtr` at our card's real `WinFuncPtr`** — query VESA - GetModeInfo (int 10h/4F01) for mode 0x111 under our S3 and put that far - pointer in `L4GAUGE.INI` (`special`/`pageFcnPtr` fields), or force the - game to use the queried pointer instead of the baked-in one. -2. **Use a linear-framebuffer (LFB) mode** (VESA 2.0, mode 0x111|0x4000) so - no bank switching is needed — requires the SVGA16 paging path to target - the LFB. -3. **Route bank switches through int 10h/4F05** (portable VESA windowing) - instead of the direct pointer — a small game patch. +**Fix (config, no binary patch):** in `ALPHA_1/REL410/BT/GAUGE/L4GAUGE.INI`, +`[640x480x16]` set `granularityInKB=64` (= `sizeInKB`, so `pageDelta=1`, +matching the S3's 64 KB banks). Backup: `L4GAUGE.INI.orig`. After the change +the full framebuffer pages correctly (315+ frames, VDB splitter stays ON, no +tear-down); the display renders as expected (blank between missions; the +active-mission instruments draw once the sim runs). +(Alternative, untried: `machine=svga_paradise`, whose DOSBox-X default VBE +granularity is 4 KB — would match the stock INI without editing it.) -Once the full 640×480 buffer renders, splitting it into the six VDB display -regions is straightforward (the VDB device already models the splitter). +Next: with the full 640×480 buffer rendering correctly, split it into the six +VDB display regions (the VDB device already models the splitter).