mirror of
https://github.com/libretro/virtualjaguar-libretro.git
synced 2026-11-07 12:47:58 -10:00
fix(cd): JINTCTRL-gated 68K delivery for BUTCH IRQs + [CDDA] diagnostic layer
Two parts, aimed at the CD-DA silence investigation (docs/cd-diagnosis/primal-rage-cdda-diagnosis.md): 1. BUTCH interrupts now also deliver 68K IPL2 when software enables the JERRY external interrupt -- gated on TOMIRQEnabled(IRQ_DSP) && JERRYIRQEnabled(IRQ2_EXTERNAL), mirroring the JERRY timer callbacks, and EDGE-triggered on the condition onset (level delivery per halfline was an IRQ storm that wall-clock-hung four matrix titles). Boot flows leave the enables clear, so boot behavior is unchanged; measured headless: Primal Rage enables JINTCTRL ext (68K $364C) but TOM's DSP int stays off, so it polls the pending bit instead -- delivery stays dormant there, correct per hardware. 2. [CDDA] diagnostic layer (rate-limited LOG_INF, visible in RetroArch device logs): audio-flow DSA commands ($01/$04/$05/$15/$51/$70 with I2CNTRL state), SMODE master/slave switches, JINTCTRL ext-enable edges (with 68K PC), BUTCH IRQ edges with all gate states, BUTCH->SSI sample delivery counter, LRXD read counter (the CD-mix gate signal), and the Primal Rage DSP command mailbox ($F1B274). Remove the layer once CD-DA is resolved. Verified: full suite green, 18/18 BUTCH contract tests, Dragon's Lair / Space Ace 3600-frame bios visual runs unchanged (no error screens, no watchdogs), Primal Rage headless behavior unchanged. Boot matrix runs were confounded by concurrent iOS builds on the same checkout; device testing is the point of this build. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
1 parent
0f8f97012c
commit
c3368396ea
4 files changed
+94
-1
No files matched your search
+57
-1
@@ -25,6 +25,7 @@
|
||||
#include "dsp.h"
|
||||
#include "jaguar.h"
|
||||
#include "jerry.h"
|
||||
#include "tom.h"
|
||||
#include "settings.h"
|
||||
#include "m68000/m68kinterface.h"
|
||||
|
||||
@@ -266,6 +267,7 @@ static bool fifoDataReady = false;
|
||||
// the FIFO. After drain, it refills at I2S rate before the next interrupt.
|
||||
static uint32_t fifoReadCount = 0;
|
||||
static int32_t fifoFillDelay = 0;
|
||||
static bool cdPrevShouldIRQ = false; /* edge detect for 68K EXT delivery */
|
||||
static int32_t fifoRefillAccum = 0; /* hundredths of a tick, error diffusion */
|
||||
|
||||
// Diagnostic counters for CD data path debugging
|
||||
@@ -551,6 +553,7 @@ void CDROMReset(void)
|
||||
fifoReadCount = 0;
|
||||
fifoFillDelay = 0;
|
||||
fifoRefillAccum = 0;
|
||||
cdPrevShouldIRQ = false;
|
||||
dsaQueueHead = 0;
|
||||
dsaQueueTail = 0;
|
||||
dsaQueueCount = 0;
|
||||
@@ -752,9 +755,45 @@ void BUTCHExec(uint32_t cycles)
|
||||
* BIOS hasn't installed its EXT1 trampoline (Hover Strike,
|
||||
* Primal Rage), corrupting the stack with a bogus return address.
|
||||
* Keep the JERRY pending bit (so JINTCTRL reads see it) but skip
|
||||
* the m68k_set_irq dual-delivery path. */
|
||||
* BLIND m68k_set_irq dual-delivery. */
|
||||
GPUSetIRQLine(GPUIRQ_DSP, ASSERT_LINE);
|
||||
|
||||
/* 68K delivery IS required when software asks for it: gate on
|
||||
* JINTCTRL's external-interrupt enable, exactly like the JERRY
|
||||
* timer IRQs (jerry.c JERRYPIT1Callback). The CD BIOS leaves
|
||||
* the enable clear during boot (no EXT trampoline installed
|
||||
* yet -- blind delivery corrupted the 68K stack in Hover
|
||||
* Strike / Primal Rage), but the CD_jeri/DSP flow ("Jaguar
|
||||
* CD-ROM" doc p.7/p.12: SMODE=$14, just-seek CD_read + CD_ack
|
||||
* for Red Book audio) installs a 68K-side handler and enables
|
||||
* the JERRY external interrupt; CD_ack then waits for that
|
||||
* handler to consume the DSA response. Suspected missing link
|
||||
* for Primal Rage CD-audio (see
|
||||
* docs/cd-diagnosis/primal-rage-cdda-diagnosis.md). */
|
||||
/* Edge-triggered: deliver once per condition onset, not per tick.
|
||||
* Level delivery every halfline is an IRQ storm that starves the
|
||||
* 68K (4 matrix titles regressed to wall-clock hangs when this
|
||||
* was level-triggered). */
|
||||
if (!cdPrevShouldIRQ)
|
||||
{
|
||||
int tomEna = TOMIRQEnabled(IRQ_DSP);
|
||||
int jerEna = JERRYIRQEnabled(IRQ2_EXTERNAL) ? 1 : 0;
|
||||
/* CDDA-DIAG: log every rising edge with gate states so device
|
||||
* logs show WHY delivery did or didn't happen. */
|
||||
static uint32_t cddaEdgeCount = 0;
|
||||
cddaEdgeCount++;
|
||||
if (cddaEdgeCount <= 20 || (cddaEdgeCount % 5000) == 0)
|
||||
LOG_INF("[CDDA] BUTCH IRQ edge #%u tom=%d jerryExt=%d "
|
||||
"fifoReady=%d dsaReady=%d butch=$%08X tick=%u%s\n",
|
||||
cddaEdgeCount, tomEna, jerEna,
|
||||
fifoDataReady, dsaResponseReady, butchWrite,
|
||||
diag_butchExecCalls,
|
||||
(tomEna && jerEna) ? " -> 68K IPL2" : "");
|
||||
if (tomEna && jerEna)
|
||||
m68k_set_irq(2);
|
||||
}
|
||||
}
|
||||
cdPrevShouldIRQ = shouldIRQ;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1209,6 +1248,23 @@ 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.
|
||||
* $01 Play / $02 Stop / $04 Pause / $05 Unpause? / $15 Set Mode /
|
||||
* $51 Mute-Unmute / $70 Set DAC Mode. */
|
||||
{
|
||||
uint8_t hi = (uint8_t)(data >> 8);
|
||||
if (hi == 0x01 || hi == 0x04 || hi == 0x05 || hi == 0x15 ||
|
||||
hi == 0x51 || hi == 0x70)
|
||||
{
|
||||
static uint32_t cddaCmdCount = 0;
|
||||
cddaCmdCount++;
|
||||
if (cddaCmdCount <= 40 || (cddaCmdCount % 500) == 0)
|
||||
LOG_INF("[CDDA] DSA cmd $%04X #%u tick=%u block=%u i2s=$%02X\n",
|
||||
data, cddaCmdCount, diag_butchExecCalls, block,
|
||||
cdRam[I2CNTRL + 3]);
|
||||
}
|
||||
}
|
||||
cdCmd = data;
|
||||
txBufferEmpty = true; // Per MiSTer: set bit 12 on command write
|
||||
CDTracePush(CD_TRACE_DSA_TX, data, block);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "jaguar.h"
|
||||
#include "log.h" /* CDDA-DIAG */
|
||||
|
||||
#include "cdrom.h"
|
||||
#include "perf_counters.h"
|
||||
@@ -653,6 +654,15 @@ uint32_t JaguarReadLong(uint32_t offset, uint32_t who)
|
||||
void JaguarWriteLong(uint32_t offset, uint32_t data, uint32_t who)
|
||||
{
|
||||
uint32_t addr = offset & 0xFFFFFF;
|
||||
/* CDDA-DIAG (Primal Rage): $F1B274 is the game's DSP command mailbox --
|
||||
* cmd 1 enables the DSP ISR's CD-audio mix (r20), cmd 2 disables. The
|
||||
* missing "cmd 1" write is the open question in
|
||||
* docs/cd-diagnosis/primal-rage-cdda-diagnosis.md. Address is game-
|
||||
* specific but the log line is harmless elsewhere (rare false hits at
|
||||
* worst). Remove with the rest of the CDDA-DIAG layer when resolved. */
|
||||
if (addr == 0xF1B274 && data != 0)
|
||||
LOG_INF("[CDDA] DSP mailbox $F1B274 = %08X who=%u 68kpc=$%06X\n",
|
||||
data, who, m68k_get_reg(NULL, M68K_REG_PC));
|
||||
if (addr < 0x800000)
|
||||
{
|
||||
SET32(jaguarMainRAM, addr & 0x1FFFFF, data);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
* produce the output stream. */
|
||||
|
||||
#include "dac.h"
|
||||
#include "log.h" /* CDDA-DIAG */
|
||||
|
||||
#include <string.h>
|
||||
#include "cdrom.h"
|
||||
@@ -277,6 +278,11 @@ void DACWriteWord(uint32_t offset, uint16_t data, uint32_t who)
|
||||
}
|
||||
else if (offset == SMODE + 2)
|
||||
{
|
||||
/* CDDA-DIAG: SMODE master/slave switches are the CD_jeri fingerprint
|
||||
* (doc 06 p.7: slave $14 = CD data flows to the I2S port). Rare. */
|
||||
if ((*smode ^ data) & 0x01)
|
||||
LOG_INF("[CDDA] SMODE $%04X -> $%04X (%s)\n", *smode, data,
|
||||
(data & 0x01) ? "INTERNAL/master" : "slave: CD -> I2S");
|
||||
*smode = data;
|
||||
}
|
||||
}
|
||||
@@ -296,7 +302,15 @@ uint16_t DACReadWord(uint32_t offset, uint32_t who)
|
||||
if (offset == LRXD || offset == RRXD)
|
||||
return 0x0000;
|
||||
else if (offset == LRXD + 2)
|
||||
{
|
||||
/* CDDA-DIAG: the CD-audio mix gate opening shows up as a flood of
|
||||
* LRXD reads from the DSP ISR; near-zero reads = gate closed. */
|
||||
static uint32_t lrxdReads = 0;
|
||||
lrxdReads++;
|
||||
if (lrxdReads <= 5 || (lrxdReads % 100000) == 0)
|
||||
LOG_INF("[CDDA] LRXD read #%u val=$%04X who=%u\n", lrxdReads, lrxd, who);
|
||||
return lrxd;
|
||||
}
|
||||
else if (offset == RRXD + 2)
|
||||
return rrxd;
|
||||
else if (offset == SCLK)
|
||||
|
||||
@@ -321,6 +321,13 @@ void JERRYI2SCallback(void)
|
||||
|
||||
if (ButchIsReadyToSend())//Not sure this is right spot to check...
|
||||
{
|
||||
/* CDDA-DIAG: samples/s delivered from BUTCH to LRXD/RRXD in
|
||||
* slave mode; ~44100/s expected while CD audio should play. */
|
||||
static uint32_t ssiDeliveries = 0;
|
||||
ssiDeliveries++;
|
||||
if (ssiDeliveries <= 3 || (ssiDeliveries % 220500) == 0)
|
||||
LOG_INF("[CDDA] BUTCH->SSI delivery #%u (%us of samples)\n",
|
||||
ssiDeliveries, ssiDeliveries / 44100);
|
||||
// return GetWordFromButchSSI(offset, who);
|
||||
SetSSIWordsXmittedFromButch();
|
||||
DSPSetIRQLine(DSPIRQ_SSI, ASSERT_LINE);
|
||||
@@ -611,6 +618,12 @@ void JERRYWriteWord(uint32_t offset, uint16_t data, uint32_t who/*=UNKNOWN*/)
|
||||
uint16_t oldPending = jerryPendingInterrupt;
|
||||
jerryInterruptMask = data & 0xFF;
|
||||
jerryPendingInterrupt &= ~(data >> 8);
|
||||
/* CDDA-DIAG: JINTCTRL external-int enable edges gate the BUTCH ->
|
||||
* 68K IPL2 delivery (cdrom.c BUTCHExec); rare, log unconditionally. */
|
||||
if ((oldMask ^ jerryInterruptMask) & IRQ2_EXTERNAL)
|
||||
LOG_INF("[CDDA] JINTCTRL ext-int enable %s (J_INT=$%04X who=%u 68kpc=$%06X)\n",
|
||||
(jerryInterruptMask & IRQ2_EXTERNAL) ? "ON" : "OFF",
|
||||
data, who, m68k_get_reg(NULL, M68K_REG_PC));
|
||||
if (oldMask != jerryInterruptMask || oldPending != jerryPendingInterrupt)
|
||||
{
|
||||
JERRY_TRACE("J_INT write word data=$%04X who=%u mask $%02X->$%02X pending $%02X->$%02X%s%s\n",
|
||||
|
||||
Reference in new issue
Block a user