Emulator: VDB heads mirror plain-VGA modes (analog splitter pass-through)
The VDB is an analog splitter: the game's packed-16bpp trick routes the two framebuffer bytes through the board palettes at 0x300/8/10, but any plain VGA mode passes the S3's own DAC signal to every head -- no VDB register traffic at all. The VGL_LABS test suite draws its secondary-display patterns in 640x480x8 and programs nothing at 0x300-0x31A (verified from a full session log), so the packed-only decode showed black heads. pal_draw now branches: M_LIN8 decodes through the VGA DAC (full color on the color heads, single-wire luminance on the mono MFD windows); 16bpp keeps the packed VDB-palette decode. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1384,6 +1384,18 @@ static void pal_draw(HDC dc, int g, int cw, int ch, bool dump) {
|
||||
fflush(vpx_fp);
|
||||
}
|
||||
}
|
||||
/* The VDB is an ANALOG splitter: the game's packed-16bpp trick routes the
|
||||
* two framebuffer bytes through the BOARD's palettes (0x300/8/10), but any
|
||||
* plain VGA mode (the VGL_LABS test suite draws its secondary-display
|
||||
* patterns in 640x480x8) passes through the S3's OWN DAC and every head
|
||||
* simply mirrors that signal -- no VDB register traffic at all (verified
|
||||
* 2026-07-17: TSTALL programs nothing at 0x300-0x31A). Model both: 16bpp
|
||||
* = packed decode via vdb_pal; 8bpp = VGA-DAC mirror, with the mono MFD
|
||||
* heads showing their single color wire's luminance. */
|
||||
const bool lin8 = (vga.mode == M_LIN8);
|
||||
if (lin8) stride = (vga.draw.address_add >= (Bitu)W &&
|
||||
vga.draw.address_add <= (Bitu)W * 4)
|
||||
? vga.draw.address_add : (Bitu)W;
|
||||
if (fb) {
|
||||
/* win0 = framebuffer LOW byte (bits 0-7) through pal0; win3/win4 =
|
||||
* framebuffer HIGH byte (bits 8-15) through pal1/pal2. All as 8-bit
|
||||
@@ -1393,22 +1405,32 @@ static void pal_draw(HDC dc, int g, int cw, int ch, bool dump) {
|
||||
for (int y = 0; y < H; y++) {
|
||||
Bitu ofs = start + (Bitu)y * stride;
|
||||
unsigned char *d = &img[(size_t)y * W * 3];
|
||||
for (int x = 0; x < W; x++, ofs += 2, d += 3) {
|
||||
uint16_t px = *(const uint16_t *)(fb + (ofs & mask));
|
||||
unsigned idx; int pg, chn = -1;
|
||||
if (g <= 2) { idx = px & 0xFFu; pg = g; } /* bits 0-7 via pal0/1/2 */
|
||||
else if (g <= 4) { idx = (px >> 8u) & 0xFFu; pg = g - 2; } /* bits 8-15 via pal1/2 */
|
||||
else { idx = (px >> 8u) & 0xFFu; /* wins 5-9: one mono MFD */
|
||||
pg = (g <= 6) ? 1 : 2; /* = one color wire of a */
|
||||
chn = (g <= 6) ? g - 5 : g - 7; } /* head (pentapus split) */
|
||||
if (apply_mask) idx &= vdb_pal[pg].mask;
|
||||
const unsigned char *e = &vdb_pal[pg].ram[idx * 3u];
|
||||
if (chn < 0) {
|
||||
d[0] = (unsigned char)((e[0] << 2) | (e[0] >> 4)); /* 6-bit DAC -> 8-bit R */
|
||||
d[1] = (unsigned char)((e[1] << 2) | (e[1] >> 4)); /* G */
|
||||
d[2] = (unsigned char)((e[2] << 2) | (e[2] >> 4)); /* B */
|
||||
for (int x = 0; x < W; x++, ofs += (lin8 ? 1 : 2), d += 3) {
|
||||
unsigned char e6[3]; int chn = -1;
|
||||
if (g > 4) chn = (g <= 6) ? g - 5 : g - 7; /* mono wire # */
|
||||
if (lin8) {
|
||||
/* analog mirror: byte -> the VGA's own DAC */
|
||||
unsigned idx = fb[ofs & mask];
|
||||
e6[0] = (unsigned char)vga.dac.rgb[idx].red;
|
||||
e6[1] = (unsigned char)vga.dac.rgb[idx].green;
|
||||
e6[2] = (unsigned char)vga.dac.rgb[idx].blue;
|
||||
} else {
|
||||
unsigned char v = (unsigned char)((e[chn] << 2) | (e[chn] >> 4));
|
||||
uint16_t px = *(const uint16_t *)(fb + (ofs & mask));
|
||||
unsigned idx; int pg;
|
||||
if (g <= 2) { idx = px & 0xFFu; pg = g; } /* bits 0-7 via pal0/1/2 */
|
||||
else if (g <= 4) { idx = (px >> 8u) & 0xFFu; pg = g - 2; } /* bits 8-15 via pal1/2 */
|
||||
else { idx = (px >> 8u) & 0xFFu; /* wins 5-9: one mono MFD */
|
||||
pg = (g <= 6) ? 1 : 2; } /* = one wire of a head */
|
||||
if (apply_mask) idx &= vdb_pal[pg].mask;
|
||||
const unsigned char *e = &vdb_pal[pg].ram[idx * 3u];
|
||||
e6[0] = e[0]; e6[1] = e[1]; e6[2] = e[2];
|
||||
}
|
||||
if (chn < 0) {
|
||||
d[0] = (unsigned char)((e6[0] << 2) | (e6[0] >> 4)); /* 6-bit DAC -> 8-bit R */
|
||||
d[1] = (unsigned char)((e6[1] << 2) | (e6[1] >> 4)); /* G */
|
||||
d[2] = (unsigned char)((e6[2] << 2) | (e6[2] >> 4)); /* B */
|
||||
} else {
|
||||
unsigned char v = (unsigned char)((e6[chn] << 2) | (e6[chn] >> 4));
|
||||
d[0] = (unsigned char)(v >> 3); /* mono MFD: green-phosphor tube, */
|
||||
d[1] = v; /* wire level = beam brightness */
|
||||
d[2] = (unsigned char)(v >> 3);
|
||||
|
||||
Reference in New Issue
Block a user