From 68ca9b6f15aa9ac275a5ceb6d6eba272bf5decad Mon Sep 17 00:00:00 2001 From: Cyd Date: Thu, 9 Jul 2026 14:53:22 -0500 Subject: [PATCH] VDB: honor the VGA-DAC pixel-mask (RP drives it; BT left it 0xFF); park Mac mirror RP experiment finding: RP runs on the BT pod emulator (shared MUNGA stack) but its cockpit VDB heads mis-decode. Root causes captured live (VDB_PALDUMP + vpxresp log): (1) framebuffer identical to BT (mode 0x111, 640x480); (2) RP loads pal0 (BT's dynamic color-radar palette) as ALL ZEROS -> radar head black; (3) RP actively drives the VGA-DAC pixel-mask register that BT leaves at 0xFF, and pal_draw ignored it -> likely the MFD garble. Device change: pixel-mask writes now log their VALUE on change ("# VDB pixel-mask[gN] = 0xXX"); pal_draw ANDs the palette index with the group mask under VDB_APPLYMASK=1 (default off = BT-identical); masks default to 0xFF in vdb_reset so an un-driven group still decodes. Built clean under MINGW64. Also: Mac Console 4.10 retired from regular use (host .NET console is the daily driver); tap2_mirror.py PARKED with revive notes for console A/B only. The SendToRxAdapters registry stays set (serves the .NET host console). Co-Authored-By: Claude Fable 5 --- emulator/NET-NOTES.md | 8 ++++++++ emulator/net-tools/tap2_mirror.py | 12 +++++++++++- emulator/vpx-device/vpxlog.cpp | 20 +++++++++++++++++++- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/emulator/NET-NOTES.md b/emulator/NET-NOTES.md index b62fba3..20d1be0 100644 --- a/emulator/NET-NOTES.md +++ b/emulator/NET-NOTES.md @@ -533,6 +533,14 @@ Revert: `Remove-ItemProperty ... -Name SendToRxAdapters` + service bounce + pod relaunch. Host connect/disconnect churns netnub (exit + ~60s relaunch) -- expected. +**MAC CONSOLE RETIRED / MIRROR PARKED (2026-07-10, operator decision):** the +SheepShaver Mac Console 4.10 is no longer in regular use -- the host-side .NET +TeslaConsole is the daily driver (direct pod link, no mirror). tap2_mirror.py +is PARKED, kept only for running the Mac console alongside the .NET one for +console A/B testing; revive per its header + the section below. The +SendToRxAdapters registry stays SET (it serves the .NET host console). Nothing +to revert unless a Mac-console A/B is needed. + **BOTH CONSOLES AT ONCE — WORKING (2026-07-10, `net-tools/tap2_mirror.py`):** keep SendToRxAdapters set (host console works) and run the mirror daemon, which turns TAP2's free application side into a userspace diff --git a/emulator/net-tools/tap2_mirror.py b/emulator/net-tools/tap2_mirror.py index 8c8eb3e..f0ff73a 100644 --- a/emulator/net-tools/tap2_mirror.py +++ b/emulator/net-tools/tap2_mirror.py @@ -1,5 +1,15 @@ #!/usr/bin/env python3 -"""Pod->Mac mirror for the SendToRx era: with Npcap's SendToRxAdapters set +"""[PARKED 2026-07-10] The SheepShaver/Mac Console 4.10 is retired from +regular use -- the modern host-side .NET TeslaConsole is the daily driver +(it talks to the pod directly via the bridge IP + SendToRxAdapters; no +mirror needed). Keep this tool for the ONE case it exists for: running the +1996 Mac console ALONGSIDE the .NET console for A/B testing. To revive: start +a pod, then `pythonw net-tools/tap2_mirror.py`, and bring up SheepShaver + +Console 4.10 (see NET-NOTES.md "BOTH CONSOLES AT ONCE"). Verified working +2026-07-09 (Console 4.10 ran a full mission through it). Constants at top +(pod NE2000 MAC, TAP2 GUID) may need refreshing if the adapters change. +---------------------------------------------------------------------------- +Pod->Mac mirror for the SendToRx era: with Npcap's SendToRxAdapters set on the Network Bridge (so the host .NET console hears the pod), the pod's injected frames no longer reach the TAP members -- SheepShaver goes deaf. Every other path still works. This daemon closes the one missing hop: diff --git a/emulator/vpx-device/vpxlog.cpp b/emulator/vpx-device/vpxlog.cpp index 24788d7..a334289 100644 --- a/emulator/vpx-device/vpxlog.cpp +++ b/emulator/vpx-device/vpxlog.cpp @@ -1326,6 +1326,10 @@ static void write_bmp(const char *path, const unsigned char *rgb, int W, int H) static void pal_draw(HDC dc, int g, int cw, int ch, bool dump) { const int W = 640, H = 480; static unsigned char img[640 * 480 * 3]; + /* VDB_APPLYMASK=1: AND the palette index with the group's VGA-DAC + * pixel-mask (default 0xFF = no-op). RP drives this mask actively where + * BT leaves it 0xFF, so honoring it may unscramble RP's MFD heads. */ + static const bool apply_mask = getenv("VDB_APPLYMASK") != NULL; const uint8_t *fb = vga.mem.linear; Bitu mask = vga.draw.linear_mask ? vga.draw.linear_mask : (vga.mem.memsize ? vga.mem.memsize - 1 : 0); @@ -1348,6 +1352,7 @@ static void pal_draw(HDC dc, int g, int cw, int ch, bool dump) { 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 */ @@ -2533,7 +2538,17 @@ static void vdb_write(Bitu port, Bitu val, Bitu /*iolen*/) { vdb_data_count++; break; case 0: /* pixel-mask */ - p.mask = v; vdb_note("pixel-mask set"); + /* RP drives this VGA-DAC pixel-mask register actively (BT leaves + * it at 0xFF); log the VALUE on change so we can see how RP gates + * the palette index, and honor it in pal_draw under VDB_APPLYMASK. */ + if (v != p.mask) { + p.mask = v; + if (vpx_fp) { vdb_flush_data(); flush_run(); + fprintf(vpx_fp, "# VDB pixel-mask[g%d] = 0x%02X\n", g, v); + fflush(vpx_fp); } + } else { + p.mask = v; + } break; case 1: /* read-address */ p.raddr = v; p.sub = 0; @@ -2554,6 +2569,9 @@ static Bitu vdb_read(Bitu port, Bitu /*iolen*/) { } static void vdb_reset(void) { memset(vdb_pal, 0, sizeof vdb_pal); + /* pixel-mask defaults to 0xFF (no gating) so an un-set group decodes + * normally; the game overwrites it if it drives the mask (RP does). */ + for (int g = 0; g < 3; g++) vdb_pal[g].mask = 0xFF; vdb_splitter_on = false; vdb_data_group = -1; vdb_data_count = 0; }