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; }