From 6b62bf961344edd5e9e379325953a99598c36a76 Mon Sep 17 00:00:00 2001 From: Cyd Date: Fri, 3 Jul 2026 18:15:48 -0500 Subject: [PATCH] VDB: fix palette port offsets -- now captures the display color maps The VDB device was only logging the splitter-clock strobe; the gauge code's palette writes were hitting the handler but being dropped. Cause: I mapped the palette register groups at Adam's base offsets (0x300/0x308/0x310, sub 0-3), but per L4VB16.CPP's "+2" convention and L4SVGA16.ASM SVGAWriteFullPalette (mov dx,base; add dx,2 -> write-addr; inc dx -> data) the real registers are at base+2: secondary 0x302-0x305, aux1 0x30A-0x30D, aux2 0x312-0x315, VGA-DAC layout within each (0 mask, 1 read-addr, 2 write-addr, 3 data). With the offsets corrected the device now captures the full palettes -- e.g. "VDB pal0 loaded 768 data bytes" (256 RGB) + pal1 -- the per-display color maps the VDB uses to colorize each of the six monitors. Foundation for reconstructing the individual displays. Co-Authored-By: Claude Opus 4.8 --- emulator/vpx-device/vpxlog.cpp | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/emulator/vpx-device/vpxlog.cpp b/emulator/vpx-device/vpxlog.cpp index 04a00da..cd302cc 100644 --- a/emulator/vpx-device/vpxlog.cpp +++ b/emulator/vpx-device/vpxlog.cpp @@ -1090,12 +1090,18 @@ static bool vdb_splitter_on = false; static int vdb_data_group = -1; static unsigned long vdb_data_count = 0; -static int vdb_group_of(io_port_t off) { /* group index for 0x300/0x308/0x310 */ - if (off <= 3) return 0; - if (off >= 8 && off <= 11) return 1; - if (off >= 16 && off <= 19) return 2; +/* Palette groups sit at Adam's-base + 2 (see L4VB16.CPP / L4SVGA16.ASM): + * secondary 0x302-0x305, aux1 0x30A-0x30D, aux2 0x312-0x315. Within a group + * (VGA-DAC layout): +0 pixel-mask, +1 read-addr, +2 write-addr, +3 data. + * SVGAWriteFullPalette: mov dx,base; add dx,2 (write-addr); out; inc dx + * (data); rep outsb. */ +static int vdb_group_of(io_port_t off) { + if (off >= 2 && off <= 5) return 0; + if (off >= 10 && off <= 13) return 1; + if (off >= 18 && off <= 21) return 2; return -1; } +static int vdb_group_base(int g) { return 2 + 8 * g; } static void vdb_flush_data(void) { if (vpx_fp && vdb_data_group >= 0 && vdb_data_count) { flush_run(); @@ -1118,24 +1124,22 @@ static void vdb_write(Bitu port, Bitu val, Bitu /*iolen*/) { int g = vdb_group_of(off); if (g < 0) return; VDBPalette &p = vdb_pal[g]; - switch (off & 3) { - case 0: /* write-address */ + switch (off - vdb_group_base(g)) { /* 0=mask 1=read-addr 2=write-addr 3=data */ + case 2: /* write-address (index) */ vdb_flush_data(); p.waddr = v; p.sub = 0; - if (vpx_fp) { flush_run(); - fprintf(vpx_fp, "# VDB pal%d write-addr=%u\n", g, v); fflush(vpx_fp); } break; - case 1: /* data: R,G,B triplet with auto-increment */ + case 3: /* data: R,G,B triplet with auto-increment */ p.ram[((unsigned)p.waddr * 3 + p.sub) % 768] = v; if (++p.sub == 3) { p.sub = 0; p.waddr++; } if (vdb_data_group != g) { vdb_flush_data(); vdb_data_group = g; } vdb_data_count++; break; - case 2: /* pixel-mask */ + case 0: /* pixel-mask */ p.mask = v; vdb_note("pixel-mask set"); break; - case 3: /* read-address */ - p.raddr = v; p.sub = 0; vdb_note("read-addr set"); + case 1: /* read-address */ + p.raddr = v; p.sub = 0; break; } } @@ -1143,7 +1147,7 @@ static Bitu vdb_read(Bitu port, Bitu /*iolen*/) { /* the game does not read the VDB; provide DAC-style read-back anyway. */ io_port_t off = (io_port_t)port - VDB_BASE; int g = vdb_group_of(off); - if (g >= 0 && (off & 3) == 1) { + if (g >= 0 && (off - vdb_group_base(g)) == 3) { VDBPalette &p = vdb_pal[g]; unsigned char v = p.ram[((unsigned)p.raddr * 3 + p.sub) % 768]; if (++p.sub == 3) { p.sub = 0; p.raddr++; }