fix(log): gate SUBCODE diagnostics + comment/citation accuracy

Pre-tag scrutiny pass, code half (brief items 1-7, 13):

- cdrom.c: [SUBCODE] read/write/BUTCH-enable diagnostics LOG_INF ->
  LOG_DBG, matching the #274 CDDA demotion class (3 sites; the brief
  named 2, the BUTCH int-enable site is the same class).
- cdrom.c: the CDDA-DIAG comment claimed "log unconditionally" while
  the code rate-limits to the first 40 plus every 500th; fix the
  comment to describe what the code does.
- bus_arbiter: bus_arbiter_dram_cost() has no callers outside
  bus_arbiter.c and is not in any export list -- make it static and
  drop the header declaration.
- analyze_cd_roms.py: drop the hardcoded absolute ROM path in favour
  of argv[1] / JAGUAR_ROMS_PRIVATE / test/roms/private, and normalize
  the Unicode box-drawing comment banners to plain ASCII.
- Replace unresolvable citations (/private/tmp/..., .superpowers/...)
  and bare "Task N" agent-process references in source comments with
  in-repo doc citations or the symptom being tested.
- Normalize em-dashes to "--" in every user-facing / log string added
  this cycle (core option descriptions, CD + boot log strings, test
  diagnostics), matching the files' pre-existing convention.

No behaviour change. Build clean, c89-lint clean, test_dram_timing
passes (0 failures).

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
Joseph MattielloandClaude Fable 5 committed 2026-08-03 05:13:31 -04:00
1 parent 7e5b05de8d
commit 7db5de7f20
25 files changed
+97 -98

No files matched your search

+4 -4
View File
@@ -248,7 +248,7 @@ struct retro_core_option_v2_definition option_defs_us[] = {
"virtualjaguar_bios",
"BIOS (Cartridges)",
NULL,
"Which BIOS a CARTRIDGE boots with. 'HLE' has the core emulate the BIOS setup and services itself, which lets most commercial titles boot faster and skips the boot animation. 'Real' runs the actual Jaguar boot ROM, which some titles require. The boot ROM is built into the core, so neither setting needs a file — unlike the CD BIOS, the console boot ROM is never loaded from the system directory. Ignored for CD content: there, 'CD Boot Mode' decides and turns the boot ROM on or off to match.",
"Which BIOS a CARTRIDGE boots with. 'HLE' has the core emulate the BIOS setup and services itself, which lets most commercial titles boot faster and skips the boot animation. 'Real' runs the actual Jaguar boot ROM, which some titles require. The boot ROM is built into the core, so neither setting needs a file -- unlike the CD BIOS, the console boot ROM is never loaded from the system directory. Ignored for CD content: there, 'CD Boot Mode' decides and turns the boot ROM on or off to match.",
NULL,
"bios_boot",
{
@@ -276,7 +276,7 @@ struct retro_core_option_v2_definition option_defs_us[] = {
"virtualjaguar_cd_bios_type",
"CD BIOS Type (Restart)",
NULL,
"Which CD BIOS the real-BIOS boot path uses. 'Retail' is the standard consumer BIOS; 'Developer' is the dev-kit BIOS, which applies less strict disc checks and can boot images the retail BIOS refuses. Both are built into the core, so no files are required. CD BIOS ROM files in the system directory are preferred over the embedded images, and this selection picks which file wins when both types are present. Only has an effect when 'CD Boot Mode' is 'Real BIOS' or 'Auto' — the HLE boot path never runs a CD BIOS.",
"Which CD BIOS the real-BIOS boot path uses. 'Retail' is the standard consumer BIOS; 'Developer' is the dev-kit BIOS, which applies less strict disc checks and can boot images the retail BIOS refuses. Both are built into the core, so no files are required. CD BIOS ROM files in the system directory are preferred over the embedded images, and this selection picks which file wins when both types are present. Only has an effect when 'CD Boot Mode' is 'Real BIOS' or 'Auto' -- the HLE boot path never runs a CD BIOS.",
NULL,
"cdrom",
{
@@ -290,7 +290,7 @@ struct retro_core_option_v2_definition option_defs_us[] = {
"virtualjaguar_cd_boot_mode",
"CD Boot Mode (Restart)",
NULL,
"How Jaguar CD discs boot. This OVERRIDES the 'BIOS (Cartridges)' setting for CD content. 'HLE' emulates the CD BIOS services directly and runs with the console boot ROM off — fastest and the most broadly compatible. 'Real BIOS' runs an actual CD BIOS and forces the boot ROM on: more faithful, still experimental. It prefers a CD BIOS ROM file from the system directory (searched under several common names, and in Atari - Jaguar / Atari - Jaguar CD / jaguar / jaguarcd sub-folders) and otherwise uses the embedded image chosen by 'CD BIOS Type', so no files are required. 'Auto' is currently identical to 'Real BIOS'. If a real-BIOS mode is chosen but no CD BIOS can be staged at all, the core falls back to HLE rather than failing.",
"How Jaguar CD discs boot. This OVERRIDES the 'BIOS (Cartridges)' setting for CD content. 'HLE' emulates the CD BIOS services directly and runs with the console boot ROM off -- fastest and the most broadly compatible. 'Real BIOS' runs an actual CD BIOS and forces the boot ROM on: more faithful, still experimental. It prefers a CD BIOS ROM file from the system directory (searched under several common names, and in Atari - Jaguar / Atari - Jaguar CD / jaguar / jaguarcd sub-folders) and otherwise uses the embedded image chosen by 'CD BIOS Type', so no files are required. 'Auto' is currently identical to 'Real BIOS'. If a real-BIOS mode is chosen but no CD BIOS can be staged at all, the core falls back to HLE rather than failing.",
NULL,
"cdrom",
{
@@ -322,7 +322,7 @@ struct retro_core_option_v2_definition option_defs_us[] = {
"virtualjaguar_memory_track",
"Memory Track (Restart)",
NULL,
"Emulate the Memory Track save cartridge alongside the CD unit, as on real hardware. CD games detect it and save settings, progress and high scores to its 128 KB NVRAM (stored in the save file). Disable to emulate a console without the cartridge — games will warn that game information cannot be saved.",
"Emulate the Memory Track save cartridge alongside the CD unit, as on real hardware. CD games detect it and save settings, progress and high scores to its 128 KB NVRAM (stored in the save file). Disable to emulate a console without the cartridge -- games will warn that game information cannot be saved.",
NULL,
"cdrom",
{
+11 -10
View File
@@ -442,7 +442,7 @@ static uint16_t DSAQueuePop(void)
/* --- CD trace ring: records DSA traffic + seek/FIFO state transitions ---
*
* Diagnostic-only instrumentation for Task 5's boot-hang triage (see
* Diagnostic-only instrumentation for CD boot-hang triage (see
* docs/cd-boot-matrix.md). Never touches savestates -- all of this is
* reset to empty on CDROMReset() the same as the other diag_* counters,
* never serialized.
@@ -923,7 +923,7 @@ void BUTCHExec(uint32_t cycles)
}
}
CD_LOG("BUTCHExec: seek complete block=%u (MSF %02u:%02u:%02u) — queued $0100, FIFO+playback active\n",
CD_LOG("BUTCHExec: seek complete block=%u (MSF %02u:%02u:%02u) -- queued $0100, FIFO+playback active\n",
block, min, sec, frm);
}
}
@@ -943,7 +943,7 @@ void BUTCHExec(uint32_t cycles)
fifoDataReady = true;
fifoReadCount = 0;
CDTracePush(CD_TRACE_FIFO_FILL, 0, block);
CD_LOG("BUTCHExec: FIFO half-full — ready for GPU ISR\n");
CD_LOG("BUTCHExec: FIFO half-full -- ready for GPU ISR\n");
}
else if (fifoFillDelay == 0 && cdPlaying && (!i2sDataEnabled || !FIFOFeedAllowed()))
{
@@ -1196,7 +1196,7 @@ uint16_t CDROMReadWord(uint32_t offset, uint32_t who/*=UNKNOWN*/)
cdPlaying = true;
if (FIFOFeedAllowed())
fifoDataReady = true;
CD_LOG("Play Title response consumed — playback and FIFO now active\n");
CD_LOG("Play Title response consumed -- playback and FIFO now active\n");
}
else if ((cdCmd & 0xFF00) == 0x0200) // Stop CD
{
@@ -1266,7 +1266,7 @@ TOC: 2 10 00 b 00:00:00 00 54:26:17 <-- Track #11
fifoDataReady = true;
fifoReadCount = 0;
}
CD_LOG("Seek response $0100 consumed (direct) — cdPlaying=true\n");
CD_LOG("Seek response $0100 consumed (direct) -- cdPlaying=true\n");
}
else if ((cdCmd & 0xFF00) == 0x1400) // Read "full" session TOC
{
@@ -1474,7 +1474,7 @@ TOC: 2 10 00 b 00:00:00 00 54:26:17 <-- Track #11
static uint32_t subReads = 0;
subReads++;
if (subReads <= 40 || (subReads % 10000) == 0)
LOG_INF("[SUBCODE] read %s+%u -> $%04X who=%u 68kpc=$%06X\n",
LOG_DBG("[SUBCODE] read %s+%u -> $%04X who=%u 68kpc=$%06X\n",
(offset >= SB_TIME) ? "SB_TIME" :
(offset >= SUBDATB) ? "SUBDATB" :
(offset >= SUBDATA) ? "SUBDATA" : "SBCNTRL",
@@ -1534,7 +1534,7 @@ void CDROMWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
{
static uint16_t prevSubEna = 0;
if ((prevSubEna ^ data) & 0x0C)
LOG_INF("[SUBCODE] BUTCH int enables $%02X -> $%02X (frame=%d match=%d) who=%u 68kpc=$%06X\n",
LOG_DBG("[SUBCODE] BUTCH int enables $%02X -> $%02X (frame=%d match=%d) who=%u 68kpc=$%06X\n",
prevSubEna & 0x7F, data & 0x7F,
(data >> 2) & 1, (data >> 3) & 1, who,
m68k_get_reg(NULL, M68K_REG_PC));
@@ -1567,7 +1567,7 @@ void CDROMWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
static uint32_t subWrites = 0;
subWrites++;
if (subWrites <= 40 || (subWrites % 10000) == 0)
LOG_INF("[SUBCODE] write %s+%u = $%04X who=%u 68kpc=$%06X\n",
LOG_DBG("[SUBCODE] write %s+%u = $%04X who=%u 68kpc=$%06X\n",
(offset >= SB_TIME) ? "SB_TIME" :
(offset >= SUBDATB) ? "SUBDATB" :
(offset >= SUBDATA) ? "SUBDATA" : "SBCNTRL",
@@ -1599,8 +1599,9 @@ void CDROMWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
if (offset == DS_DATA)
{
CD_LOG("DS_DATA write: cmd=0x%04X\n", data);
/* CDDA-DIAG: audio-flow commands, rare -- log unconditionally so
* device RetroArch logs show the play sequence without a wedge dump.
/* CDDA-DIAG: audio-flow commands, rare -- log the first 40 and
* then every 500th so device RetroArch logs show the play sequence
* without a wedge dump, while a stuck game cannot flood the log.
* $01 Play / $02 Stop / $04 Pause / $05 Unpause? / $15 Set Mode /
* $51 Mute-Unmute / $70 Set DAC Mode. */
{
+1 -1
View File
@@ -45,7 +45,7 @@ void CDROMDiagGetCounters(uint32_t *butchExec,
uint32_t *globalDisabled,
uint32_t *hleBytes);
/* --- CD trace ring (Task 4 instrumentation, see cdrom.c) ---
/* --- CD trace ring (diagnostic instrumentation, see cdrom.c) ---
* Diagnostic only; never touches savestates. */
/* Enable/disable the trace ring. Called from libretro.c's check_variables()
+1 -1
View File
@@ -81,7 +81,7 @@ static bool bios_instruction_hook(uint32_t m68kPC)
if (loadAddr != 0x080000)
{
LOG_INF("[CD-BOOTSTUB] Boot stub loads at $%06X, not $080000 — "
LOG_INF("[CD-BOOTSTUB] Boot stub loads at $%06X, not $080000 -- "
"installing trampoline at $080000\n", loadAddr);
/* JMP loadAddr (4EF9 xxxx xxxx) */
jaguarMainRAM[0x080000] = 0x4E;
+15 -15
View File
@@ -395,7 +395,7 @@ static uint32_t HLERawStreamAlignOffset(uint32_t startLBA, uint32_t destAddr,
uint32_t relOff = s * 2352 + i; /* run start in the stream */
uint32_t mis = (destAddr + relOff) & 3;
HLE_LOG("align scan: %s run (%u) at LBA %u off %u "
"(stream off %u, dest misalign %u) — shift %u\n",
"(stream off %u, dest misalign %u) -- shift %u\n",
what, run, startLBA + s, i, relOff, mis,
(mis == 2) ? 2u : 0u);
return (mis == 2) ? 2u : 0u;
@@ -471,7 +471,7 @@ static uint32_t HLERawStreamAlignOffset(uint32_t startLBA, uint32_t destAddr,
uint32_t relOff = s2 * 2352 + i;
uint32_t mis = (destAddr + relOff) & 3;
HLE_LOG("align scan: %s run (%u) at LBA %u off %u "
"(stream off %u, dest misalign %u) — shift %u\n",
"(stream off %u, dest misalign %u) -- shift %u\n",
what, run, startLBA + s2, i, relOff, mis,
(mis == 2) ? 2u : 0u);
return (mis == 2) ? 2u : 0u;
@@ -544,7 +544,7 @@ static void HLEHandleCDRead(void)
* stale or garbage values in re-seek mode) and stomp memory. */
if (reseekOnly)
{
HLE_LOG("CD_read: re-seek only (D0 bit31 set, D0=$%08X) — "
HLE_LOG("CD_read: re-seek only (D0 bit31 set, D0=$%08X) -- "
"skipping data transfer\n", d0);
/* A just-seek repositions the drive and leaves it playing — this is
* the documented CDDA-play API ("call CD_read with the Just Seek bit
@@ -581,7 +581,7 @@ static void HLEHandleCDRead(void)
if (hleStream.active && d0 == hleStream.sigD0 && d1 == hleStream.sigD1 &&
a0 == hleStream.sigA0 && a1 == hleStream.sigA1)
{
HLE_LOG("CD_read: identical re-issue while streaming ($%06X/$%06X done) — "
HLE_LOG("CD_read: identical re-issue while streaming ($%06X/$%06X done) -- "
"keeping in-flight transfer\n",
hleStream.written, hleStream.total);
return;
@@ -601,14 +601,14 @@ static void HLEHandleCDRead(void)
min, sec, frm, lba, destAddr, a1, byteCount);
/* HLE_READ trace event: carries the requested LBA (in the `block`
* field) so Task 5's wrong-LBA hypothesis can be checked against the
* field) so the wrong-LBA hypothesis can be checked against the
* HLE path too, not just the real-BIOS/BUTCHExec path. No-op when the
* trace ring is disabled (CDTracePush's off-mode short-circuit). */
CDTraceHLERead(lba, (uint16_t)(byteCount > 0xFFFF ? 0xFFFF : byteCount));
if (destAddr == 0 || destAddr >= 0x200000)
{
HLE_LOG("CD_read: invalid dest=$%06X — skipping\n", destAddr);
HLE_LOG("CD_read: invalid dest=$%06X -- skipping\n", destAddr);
hle_read_pending = false;
return;
}
@@ -696,7 +696,7 @@ static void HLEHandleCDRead(void)
uint32_t gameData = CDIntfGetSession2GameDataLBA();
if (gameData > 0)
{
HLE_LOG("CD_read: LBA %u outside session-2 range [%u..%u) — "
HLE_LOG("CD_read: LBA %u outside session-2 range [%u..%u) -- "
"redirecting to game data LBA %u\n",
lba, s2first, discTotal, gameData);
startLBA = gameData;
@@ -728,7 +728,7 @@ static void HLEHandleCDRead(void)
scanOff = HLERawStreamAlignOffset(startLBA, destAddr, d1,
d1 != a1 && (d1 >> 16) != 0);
HLE_LOG("CD_read: non-match ISR mode ($3072=$%02X, D1=$%08X A1=$%06X) "
"— streaming raw from LBA %u offset %u\n",
"-- streaming raw from LBA %u offset %u\n",
jaguarMainRAM[0x3072], d1, a1, startLBA, scanOff);
foundSentinel = true; /* short-circuit the scan loop */
phase_starts[0] = startLBA;
@@ -748,7 +748,7 @@ static void HLEHandleCDRead(void)
* mastered sync run — Myst's movie/JSND loads, handled above.) */
if ((d1 >> 16) == 0)
{
HLE_LOG("CD_read: D1=$%08X is a counter/ID — skipping sentinel scan, "
HLE_LOG("CD_read: D1=$%08X is a counter/ID -- skipping sentinel scan, "
"streaming raw from LBA %u\n", d1, startLBA);
scanLBA = startLBA;
scanOff = 0;
@@ -928,7 +928,7 @@ static void HLEHandleCDRead(void)
* proceed past its poll loop; whatever code runs at the zeroed
* destination (ORI.B #0,D0 = NOP-like) generates enough PC
* diversity for the smoke test to pass. */
HLE_LOG("CD_read: sentinel NOT found after redirect — "
HLE_LOG("CD_read: sentinel NOT found after redirect -- "
"zeroing dest $%06X-$%06X and signalling completion\n",
destAddr, destAddr + byteCount - 1);
for (i = 0; i < ((byteCount + 3u) & ~3u) &&
@@ -945,7 +945,7 @@ static void HLEHandleCDRead(void)
scanLBA = startLBA;
scanOff = HLERawStreamAlignOffset(startLBA, destAddr, d1,
d1 != a1 && (d1 >> 16) != 0);
HLE_LOG("CD_read: sentinel NOT found — reading raw from LBA %u "
HLE_LOG("CD_read: sentinel NOT found -- reading raw from LBA %u "
"offset %u\n", startLBA, scanOff);
}
@@ -1174,7 +1174,7 @@ static void HLEStreamFinish(void)
* data area (CD_poll) alone, matching the real GPU CD ISR — see the
* $F1B4C8 note at the top of this file. */
HLE_LOG("CD_read: transfer complete — %u bytes (%u sectors) "
HLE_LOG("CD_read: transfer complete -- %u bytes (%u sectors) "
"to $%06X-$%06X\n",
byteCount, (byteCount + 2351) / 2352, destAddr,
hle_read_end_addr - 1);
@@ -1577,7 +1577,7 @@ bool JaguarCDHLEBoot(void)
if (!CDIntfIsImageLoaded())
{
LOG_ERR("[CD-HLE] No disc image loaded — HLE boot aborted\n");
LOG_ERR("[CD-HLE] No disc image loaded -- HLE boot aborted\n");
HLEParkOnHalt();
return false;
}
@@ -1671,7 +1671,7 @@ bool JaguarCDHLEBoot(void)
hle_active = true;
LOG_INF("[CD-HLE] Boot complete — PC=$%06X SP=$%06X\n",
LOG_INF("[CD-HLE] Boot complete -- PC=$%06X SP=$%06X\n",
loadAddr, 0x200000);
return true;
}
@@ -1794,7 +1794,7 @@ static bool hle_strategy_boot(const struct retro_game_info *info)
if (!JaguarCDHLEBoot())
{
LOG_ERR("[CD-HLE] HLE boot failed — falling back to diagnostic screen\n");
LOG_ERR("[CD-HLE] HLE boot failed -- falling back to diagnostic screen\n");
return false;
}
+1 -1
View File
@@ -78,7 +78,7 @@ void bus_arbiter_update_memcon(uint16_t memcon1)
busArbiter.dram_refresh_clks = dram_refresh_table[dramspeed];
}
uint32_t bus_arbiter_dram_cost(uint32_t addr)
static uint32_t bus_arbiter_dram_cost(uint32_t addr)
{
/* GPU local RAM: 0xF03000-0xF03FFF — no bus transaction */
if (addr >= 0xF03000 && addr <= 0xF03FFF)
+2 -5
View File
@@ -32,7 +32,8 @@
* table indexed by DRAMSPEED: { 7, 7, 5, 3 }.
* This model uses the row-miss cost as an average DRAM access cost
* (2 + row-miss) since GPU/68K access patterns are not tracked for
* page-hit/page-miss state — see bus_arbiter_dram_cost().
* page-hit/page-miss state -- see the DRAM cost model in
* bus_arbiter.c.
*/
#ifndef BUS_ARBITER_H
#define BUS_ARBITER_H
@@ -126,10 +127,6 @@ uint32_t bus_arbiter_op_take(void);
* contention_scale. */
uint32_t bus_arbiter_refresh_clocks(uint32_t elapsed_sysclks);
/* Return DRAM access cost in system clocks for a given address.
* Local GPU/DSP RAM returns 0 (no bus transaction). */
uint32_t bus_arbiter_dram_cost(uint32_t addr);
/* Cost (in system clocks, scaled) the master pays for one access to
* `addr`. 0 for local RAM. */
uint32_t bus_arbiter_charge_access(int master, uint32_t addr);
+2 -2
View File
@@ -271,8 +271,8 @@ void CrashDetectFrameTick(const uint32_t *fb, unsigned w, unsigned h)
* evaluate this at all.
*
* Deliberately broader than "SEEK_START without SEEK_DONE": comparing
* fifoDrains instead of seekDones catches both failure shapes Task 5
* needs to tell apart -- (a) the seek-completion response never
* fifoDrains instead of seekDones catches both CD seek-wedge shapes
* that need telling apart -- (a) the seek-completion response never
* arrives (seekDones stays behind seekStarts, so fifoDrains obviously
* never advances either), and (b) the seek completes fine but the
* FIFO continuation dies afterward (seekDones catches up, fifoDrains
+6 -6
View File
@@ -30,7 +30,7 @@ void ResolveBootConfig(struct BootConfig *cfg,
{
cfg->showBootROM = userWantsBIOS;
cfg->strategy = &cd_boot_strategy_cart;
LOG_INF("[BOOT] Cart game — showBootROM=%d\n", cfg->showBootROM);
LOG_INF("[BOOT] Cart game -- showBootROM=%d\n", cfg->showBootROM);
return;
}
@@ -48,7 +48,7 @@ void ResolveBootConfig(struct BootConfig *cfg,
cfg->showBootROM = true;
cfg->strategy = &cd_boot_strategy_bios;
if (!userWantsBIOS)
LOG_INF("[BOOT] CD game, mode=BIOS — boot ROM forced on "
LOG_INF("[BOOT] CD game, mode=BIOS -- boot ROM forced on "
"(required by real CD BIOS path)\n");
LOG_INF("[BOOT] CD game, mode=BIOS (BIOS image staged)\n");
}
@@ -56,7 +56,7 @@ void ResolveBootConfig(struct BootConfig *cfg,
{
cfg->showBootROM = false;
cfg->strategy = &cd_boot_strategy_hle;
LOG_WRN("[BOOT] CD game, mode=BIOS but no BIOS file found — "
LOG_WRN("[BOOT] CD game, mode=BIOS but no BIOS file found -- "
"falling back to HLE\n");
}
break;
@@ -68,15 +68,15 @@ void ResolveBootConfig(struct BootConfig *cfg,
cfg->showBootROM = true;
cfg->strategy = &cd_boot_strategy_bios;
if (!userWantsBIOS)
LOG_INF("[BOOT] CD game, mode=AUTO — boot ROM forced on "
LOG_INF("[BOOT] CD game, mode=AUTO -- boot ROM forced on "
"(required by real CD BIOS path)\n");
LOG_INF("[BOOT] CD game, mode=AUTO — using real BIOS\n");
LOG_INF("[BOOT] CD game, mode=AUTO -- using real BIOS\n");
}
else
{
cfg->showBootROM = false;
cfg->strategy = &cd_boot_strategy_hle;
LOG_INF("[BOOT] CD game, mode=AUTO — no BIOS, using HLE\n");
LOG_INF("[BOOT] CD game, mode=AUTO -- no BIOS, using HLE\n");
}
break;
}
+2 -2
View File
@@ -1,7 +1,7 @@
/*
* mister_ground_truth.h — Expected hardware values extracted from MiSTer FPGA RTL.
* mister_ground_truth.h -- Expected hardware values extracted from MiSTer FPGA RTL.
*
* Source: /private/tmp/Jaguar_MiSTer/rtl/
* Source: MiSTer-devel/Jaguar_MiSTer repository, rtl/
* These constants define the correct behavior according to real hardware
* as implemented in the MiSTer Jaguar FPGA core.
*/
+1 -1
View File
@@ -335,7 +335,7 @@ int main(int argc, char *argv[])
RUN_TEST(blit_dstd_write_read);
/* Operations — fill hangs in headless (blitter never returns from B_CMD write) */
SKIP_TEST(blit_fill_operation, "hangs in headless — blitter execution never completes");
SKIP_TEST(blit_fill_operation, "hangs in headless -- blitter execution never completes");
/* Intensity/Z registers */
RUN_TEST(blit_iinc_write_read);
+1 -1
View File
@@ -803,7 +803,7 @@ int main(int argc, char *argv[])
printf(" $DFFF12 (I2CNTRL) = $%04X\n", p_CDROMReadWord(0xDFFF12, 0));
}
else
printf(" (CDROMReadWord not available — cannot read BUTCH/CD registers)\n");
printf(" (CDROMReadWord not available -- cannot read BUTCH/CD registers)\n");
if (p_JERRYReadWord)
{
+2 -2
View File
@@ -1,7 +1,7 @@
/*
* test_cd_fifo_stream.c -- CD FIFO stream delivery contract test (Task 7).
* test_cd_fifo_stream.c -- CD FIFO stream delivery contract test.
*
* Closes the gap the Task 6D report named: the TOC contract test proves the
* Closes the gap left by test_cd_toc_contract.c: that test proves the
* injected table matches CDIntf, but NOT that a seek delivers the right disc
* BYTES to RAM. This test does the end-to-end byte-compare:
*
+1 -1
View File
@@ -1,7 +1,7 @@
/*
* test_cd_hle_idempotent.c -- HLE CD_read idempotency regression test.
*
* Encodes the contract established in Task 6C: the BIOS CD_read service is a
* Encodes the CD_read idempotency contract: the BIOS CD_read service is a
* discrete, self-contained read. D0 (packed MSF) fully specifies the source
* position; when a boot stub / game re-issues a byte-identical CD_read (same
* D0/D1/A0/A1), real hardware re-seeks to the SAME position and reproduces the
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* test_cd_second_transfer.c -- CD second-transfer liveness contract (Task 8).
* test_cd_second_transfer.c -- CD second-transfer liveness contract.
*
* test_cd_fifo_stream proves the FIRST boot-stub load delivers byte-exact
* payload. This test covers the next failure class: the SECOND (and every
+3 -3
View File
@@ -1,5 +1,5 @@
/*
* test_cd_toc_contract.c -- $2C00 TOC table contract test (Task 6D).
* test_cd_toc_contract.c -- $2C00 TOC table contract test.
*
* After a real-BIOS CD boot reaches the boot-stub / TOC injection point,
* this reads the actual $2C00 table out of main RAM and runs BOTH game
@@ -8,8 +8,8 @@
* from real game boot stubs and the CD BIOS's own $2C00 TOC builder — a
* 68K routine in the BIOS ROM at $808BE8 that polls BUTCH DSA responses
* directly (not the DSP code the BIOS uploads to $F1B000, which handles
* drive-level transport); see docs/cd-boot-matrix.md and
* .superpowers/sdd/task-6d-report.md for the layout derivation.
* drive-level transport); see the "$2C00 TOC track-indexed layout" section
* of docs/cd-boot-matrix.md for the layout derivation.
*
* SCOPE: this is a table-format contract test, not an end-to-end boot test.
* The Primal Rage MSF assertion below compares the injected table against
+1 -1
View File
@@ -63,7 +63,7 @@ static int run_case(int argc, char **argv, const char *rom,
get_host = (get_host_t)harness_dlsym(&cfg, "JLinkGetTCPHost");
if (!get_host)
{
fprintf(stderr, "JLinkGetTCPHost not exported — build with "
fprintf(stderr, "JLinkGetTCPHost not exported -- build with "
"TEST_EXPORTS=1\n");
harness_shutdown(&cfg);
return 0;
+2 -2
View File
@@ -302,7 +302,7 @@ int main(int argc, char **argv)
dac_size = dac_save(dac_v3);
check(dac_size == EXPECTED_DAC_BLOCK_SIZE, "dac_block_size",
"DACStateSave wrote %lu bytes, expected %d "
"(a DAC field was added/reordered — re-derive the size and the "
"(a DAC field was added/reordered -- re-derive the size and the "
"i2sNonZeroCount offset in this test)",
(unsigned long)dac_size, EXPECTED_DAC_BLOCK_SIZE);
if (dac_size != EXPECTED_DAC_BLOCK_SIZE) {
@@ -495,7 +495,7 @@ int main(int argc, char **argv)
check(try_load_patched(unser, state_v3, state_size, STATE_OFF_VERSION,
1u, scratch) == false,
"v1_state_rejected",
"version 1 is below STATE_MIN_VERSION (%d) — the v1->v2 layout "
"version 1 is below STATE_MIN_VERSION (%d) -- the v1->v2 layout "
"change shipped in v2.3.0", STATE_MIN_VERSION);
check(try_load_patched(unser, state_v3, state_size, STATE_OFF_VERSION,
+1 -1
View File
@@ -68,7 +68,7 @@ int main(int argc, char **argv)
jerry_rw = (jerry_rw_t)harness_dlsym(&cfg, "JERRYReadWord");
if (!jerry_ww || !jerry_rw)
{
fprintf(stderr, "JERRY dispatch symbols not exported — "
fprintf(stderr, "JERRY dispatch symbols not exported -- "
"build with TEST_EXPORTS=1\n");
return 1;
}
+31 -30
View File
@@ -12,7 +12,7 @@ import sys
import os
from collections import defaultdict
# ── BIOS Jump Table Addresses ──────────────────────────────────────────────
# --- BIOS Jump Table Addresses ---
BIOS_FUNCTIONS = {
0x3006: "CD_init",
0x300C: "CD_ack",
@@ -29,7 +29,7 @@ BIOS_FUNCTIONS = {
# Extend with more known BIOS entry points seen in code
BIOS_RANGE = range(0x3000, 0x3E00)
# ── 68K Instruction Patterns ──────────────────────────────────────────────
# --- 68K Instruction Patterns ---
# Register names
DREGS = ["D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7"]
@@ -78,7 +78,7 @@ class M68KDisassembler:
info = {}
# ── JSR ────────────────────────────────────────────────────────
# --- JSR ---
# 4E80-4EBF: JSR <ea>
if (w & 0xFFC0) == 0x4E80:
mode = (w >> 3) & 7
@@ -116,7 +116,7 @@ class M68KDisassembler:
ea = decode_ea_mode(mode, reg)
return f"JSR {ea}", 2 if mode < 5 else 4, info
# ── JMP ────────────────────────────────────────────────────────
# --- JMP ---
if (w & 0xFFC0) == 0x4EC0:
mode = (w >> 3) & 7
reg = w & 7
@@ -139,7 +139,7 @@ class M68KDisassembler:
ea = decode_ea_mode(mode, reg)
return f"JMP {ea}", 2 if mode < 5 else 4, info
# ── BSR ────────────────────────────────────────────────────────
# --- BSR ---
if (w & 0xFF00) == 0x6100:
disp = w & 0xFF
if disp == 0:
@@ -157,7 +157,7 @@ class M68KDisassembler:
info = {"type": "BSR", "target": target}
return f"BSR.B $%06X" % target, 2, info
# ── MOVEQ ─────────────────────────────────────────────────────
# --- MOVEQ ---
if (w & 0xF100) == 0x7000:
dreg = (w >> 9) & 7
imm = w & 0xFF
@@ -166,7 +166,7 @@ class M68KDisassembler:
info = {"type": "MOVEQ", "reg": f"D{dreg}", "value": imm & 0xFF}
return f"MOVEQ #$%02X,D{dreg}" % (imm & 0xFF), 2, info
# ── MOVE.L #imm,Dn (or An) ────────────────────────────────────
# --- MOVE.L #imm,Dn (or An) ---
# 2x3C = MOVE.L #imm,Dn (opcode 0010 xxx0 0011 1100)
if (w & 0xF1FF) == 0x203C:
dreg = (w >> 9) & 7
@@ -175,7 +175,7 @@ class M68KDisassembler:
info = {"type": "MOVE.L_IMM", "reg": f"D{dreg}", "value": imm}
return f"MOVE.L #$%08X,D{dreg}" % imm, 6, info
# ── MOVE.W #imm (to various) ──────────────────────────────────
# --- MOVE.W #imm (to various) ---
# 303C = MOVE.W #imm,D0 (etc)
if (w & 0xF1FF) == 0x303C:
dreg = (w >> 9) & 7
@@ -184,7 +184,7 @@ class M68KDisassembler:
info = {"type": "MOVE.W_IMM", "reg": f"D{dreg}", "value": imm}
return f"MOVE.W #$%04X,D{dreg}" % imm, 4, info
# ── MOVE.B #imm ───────────────────────────────────────────────
# --- MOVE.B #imm ---
if (w & 0xF1FF) == 0x103C:
dreg = (w >> 9) & 7
imm = self.read16(offset + 2)
@@ -192,7 +192,7 @@ class M68KDisassembler:
info = {"type": "MOVE.B_IMM", "reg": f"D{dreg}", "value": imm & 0xFF}
return f"MOVE.B #$%02X,D{dreg}" % (imm & 0xFF), 4, info
# ── LEA addr,An ───────────────────────────────────────────────
# --- LEA addr,An ---
# LEA (abs.l),An = 41F9/43F9/45F9/47F9/49F9/4BF9/4DF9/4FF9
if (w & 0xF1FF) == 0x41F9:
areg = (w >> 9) & 7
@@ -213,7 +213,7 @@ class M68KDisassembler:
info = {"type": "LEA_W", "reg": f"A{areg}", "value": addr32}
return f"LEA ($%04X).w,A{areg}" % addr, 4, info
# ── MOVEA.L ────────────────────────────────────────────────────
# --- MOVEA.L ---
# 207C = MOVEA.L #imm,A0; 227C = A1; etc.
if (w & 0xF1FF) == 0x207C:
areg = (w >> 9) & 7
@@ -222,7 +222,7 @@ class M68KDisassembler:
info = {"type": "MOVEA.L", "reg": f"A{areg}", "value": imm}
return f"MOVEA.L #$%08X,A{areg}" % imm, 6, info
# ── MOVE.L abs,abs (23FC = MOVE.L #imm,abs.l) ────────────────
# --- MOVE.L abs,abs (23FC = MOVE.L #imm,abs.l) ---
if w == 0x23FC:
imm = self.read32(offset + 2)
addr = self.read32(offset + 6)
@@ -230,7 +230,7 @@ class M68KDisassembler:
info = {"type": "MOVE.L_ABS", "value": imm, "addr": addr}
return f"MOVE.L #$%08X,($%08X).l" % (imm, addr), 10, info
# ── MOVE.W #imm,abs.l (33FC) ────────────────────────────────
# --- MOVE.W #imm,abs.l (33FC) ---
if w == 0x33FC:
imm = self.read16(offset + 2)
addr = self.read32(offset + 4)
@@ -238,7 +238,7 @@ class M68KDisassembler:
info = {"type": "MOVE.W_ABS", "value": imm, "addr": addr}
return f"MOVE.W #$%04X,($%08X).l" % (imm, addr), 8, info
# ── ADDA.L #imm,An (D1FC) ────────────────────────────────────
# --- ADDA.L #imm,An (D1FC) ---
if (w & 0xF1FF) == 0xD1FC:
areg = (w >> 9) & 7
imm = self.read32(offset + 2)
@@ -246,7 +246,7 @@ class M68KDisassembler:
info = {"type": "ADDA.L", "reg": f"A{areg}", "value": imm}
return f"ADDA.L #$%08X,A{areg}" % imm, 6, info
# ── MOVE.L Dn/An,abs (23Cx) ──────────────────────────────────
# --- MOVE.L Dn/An,abs (23Cx) ---
if (w & 0xFFC0) == 0x23C0:
sreg = w & 0xF
addr = self.read32(offset + 2)
@@ -255,25 +255,25 @@ class M68KDisassembler:
info = {"type": "MOVE_REG_ABS", "reg": rname, "addr": addr}
return f"MOVE.L {rname},($%08X).l" % addr, 6, info
# ── RTS ────────────────────────────────────────────────────────
# --- RTS ---
if w == 0x4E75:
return "RTS", 2, {"type": "RTS"}
# ── NOP ────────────────────────────────────────────────────────
# --- NOP ---
if w == 0x4E71:
return "NOP", 2, {"type": "NOP"}
# ── RTE ────────────────────────────────────────────────────────
# --- RTE ---
if w == 0x4E73:
return "RTE", 2, {"type": "RTE"}
# ── SR manipulation ────────────────────────────────────────────
# --- SR manipulation ---
if w == 0x46FC:
imm = self.read16(offset + 2)
if imm is not None:
return f"MOVE #$%04X,SR" % imm, 4, {"type": "MOVE_SR"}
# ── Bcc / BRA ─────────────────────────────────────────────────
# --- Bcc / BRA ---
cond_names = {0:"BRA",1:"BSR",2:"BHI",3:"BLS",4:"BCC",5:"BCS",
6:"BNE",7:"BEQ",8:"BVC",9:"BVS",10:"BPL",11:"BMI",
12:"BGE",13:"BLT",14:"BGT",15:"BLE"}
@@ -294,7 +294,7 @@ class M68KDisassembler:
target = (self.base + offset + 2 + disp) & 0xFFFFFFFF
return f"{cname}.B $%06X" % target, 2, {"type": "BCC", "target": target}
# ── Fallback ──────────────────────────────────────────────────
# --- Fallback ---
return f"DC.W $%04X" % w, 2, {"type": "unknown", "word": w}
@@ -310,7 +310,7 @@ def analyze_file(filepath):
print(f"Size: {size} bytes ({size:#x})")
print(f"{'='*78}")
# ── Determine load address and file type ──────────────────────────
# --- Determine load address and file type ---
# Check first bytes for header patterns
first4 = struct.unpack(">I", data[:4])[0] if len(data) >= 4 else 0
first2 = struct.unpack(">H", data[:2])[0] if len(data) >= 2 else 0
@@ -372,7 +372,7 @@ def analyze_file(filepath):
if entry_point is not None:
print(f"Entry point: ${entry_point:08X}")
# ── Scan for BIOS jump table references ──────────────────────────
# --- Scan for BIOS jump table references ---
disasm = M68KDisassembler(data, load_addr)
bios_calls = []
all_instructions = []
@@ -409,7 +409,7 @@ def analyze_file(filepath):
offset += size
# ── Print BIOS call summary ──────────────────────────────────────
# --- Print BIOS call summary ---
print(f"\nBIOS Jump Table Calls Found: {len(bios_calls)}")
print("-" * 70)
@@ -440,14 +440,14 @@ def analyze_file(filepath):
marker = ">>>" if i == idx else " "
print(f" {marker} ${a:06X}: {t}")
# ── BUTCH register references ────────────────────────────────────
# --- BUTCH register references ---
if butch_refs:
print(f"\nBUTCH Register References: {len(butch_refs)}")
print("-" * 70)
for o, a, t, info in butch_refs:
print(f" ${a:06X}: {t}")
# ── Scan for raw 16-bit values matching BIOS addresses ───────────
# --- Scan for raw 16-bit values matching BIOS addresses ---
# Also find them as data references (not instructions)
raw_bios_refs = []
for off in range(0, len(data) - 1, 2):
@@ -466,7 +466,7 @@ def analyze_file(filepath):
for off, val, name in raw_bios_refs:
print(f" offset ${off:06X} (addr ${load_addr+off:06X}): ${val:04X} = {name}")
# ── First 32 instructions ────────────────────────────────────────
# --- First 32 instructions ---
print(f"\nFirst 40 Instructions (entry point):")
print("-" * 70)
for i, (o, a, t, s, inf) in enumerate(all_instructions[:40]):
@@ -604,7 +604,8 @@ def scan_for_jump_table_at(data, base_addr, offset, name):
def main():
rom_dir = "/Users/jmattiello/Workspace/Provenance/virtualjaguar-libretro/test/roms/private"
rom_dir = (sys.argv[1] if len(sys.argv) > 1
else os.environ.get("JAGUAR_ROMS_PRIVATE", "test/roms/private"))
files = [
"CDBYPASS (Symmetry of TNG 2003).prg",
@@ -628,7 +629,7 @@ def main():
analyze_cd_read_patterns(bios_calls, instructions, fname)
analyze_bypass_mechanism(instructions, fname)
# ── Cross-reference summary ──────────────────────────────────────
# --- Cross-reference summary ---
print(f"\n{'='*78}")
print("CROSS-REFERENCE SUMMARY: BIOS Function Usage")
print(f"{'='*78}")
@@ -647,7 +648,7 @@ def main():
for fname, addr in usages:
print(f" {fname} @ ${addr:06X}")
# ── Final analysis ───────────────────────────────────────────────
# --- Final analysis ---
print(f"\n{'='*78}")
print("CALLING CONVENTION SUMMARY")
print(f"{'='*78}")
+2 -2
View File
@@ -99,7 +99,7 @@ fi
# The harnesses dlsym() CDROMDiagGetCounters; a plain `make` (no
# TEST_EXPORTS=1) relinks against the slim production export list and
# silently drops it (bit Task 2 of this plan -- see task-2-report.md).
# silently drops it, and every dlsym-based assertion then reports SKIP.
if command -v nm >/dev/null 2>&1; then
if ! nm -gU "$DYLIB" 2>/dev/null | grep -q CDROMDiagGetCounters; then
echo "$DYLIB is missing test-export symbols -- rebuilding with TEST_EXPORTS=1..." >&2
@@ -384,7 +384,7 @@ pc_summary_of() {
#
# The 9 CUE titles are exactly the set test_cd_hle_boot / test_cd_bios_boot
# already discover by default (VJ_TEST_CD_EXTS defaults to "cue") -- this
# matches the Task 2 per-title baseline one-for-one. CDI (baldies.cdi) and
# matches the recorded per-title baseline one-for-one. CDI (baldies.cdi) and
# one loose ISO (Primal Rage) are opt-in via VJ_TEST_CD_EXTS, per
# test/cd_assertions.h's own documented rationale (CDI parser has a known
# crasher; ISO boot is a documented, permanent limitation -- ISO images
+1 -1
View File
@@ -975,7 +975,7 @@ static int convert_parsed(Disc *d, const char *inPath, const char *outPath,
if (d->numSessions > 2)
WARN("more than 2 sessions: this core's parser clamps numSessions to 2\n");
if (d->numSessions == 1)
INFO("note: single session — a bootable Jaguar CD needs 2 sessions\n");
INFO("note: single session -- a bootable Jaguar CD needs 2 sessions\n");
INFO("writing %s\n", outPath);
if (write_cdi(d, outPath) != 0)
+1 -1
View File
@@ -190,7 +190,7 @@ int main(int argc, char **argv)
run_frame = (retro_run_t)harness_dlsym(&cfg, "retro_run");
if (!jerry_ww || !jerry_rw || !jlink_connected || !rx_total || !run_frame)
{
fprintf(stderr, "[%s] symbols missing — build with TEST_EXPORTS=1\n",
fprintf(stderr, "[%s] symbols missing -- build with TEST_EXPORTS=1\n",
role);
return 1;
}
+1 -1
View File
@@ -142,7 +142,7 @@ int main(int argc, char **argv)
fprintf(stderr, "[%s] jlink mode after load = %d\n", role, jlink_mode());
if (!jerry_ww || !jerry_rw || !jlink_connected || !run_frame)
{
fprintf(stderr, "[%s] symbols missing — build with TEST_EXPORTS=1\n", role);
fprintf(stderr, "[%s] symbols missing -- build with TEST_EXPORTS=1\n", role);
return 1;
}
+3 -3
View File
@@ -1,7 +1,7 @@
/* test/tools/test_audio_gaps.c — detect audio-effect "stutter" (RMS
/* test/tools/test_audio_gaps.c -- detect audio-effect "stutter" (RMS
* collapses) during Doom's attract demo, comparing virtualjaguar_dram_timing
* on vs off (Task 6, user report 2026-08-02: demo sfx stutter with the
* option enabled, in-game audio fine, no stutter with the option off).
* on vs off (user report 2026-08-02: demo sfx stutter with the option
* enabled, in-game audio fine, no stutter with the option off).
*
* Method: watch gametic ($04080C, same field used by test_doom_ticrate.c)
* for the first attract-demo start (0 -> nonzero transition), reset the