#define cdReadTime (PSXCLK / 75)
static struct CdrStat stat;
-static struct SubQ *subq;
static unsigned int msf2sec(char *msf) {
return ((msf[0] * 60 + msf[1]) * 75) + msf[2];
new_dyna_set_event(PSXINT_CDRLID, eCycle); \
}
+#define CDRPLAY_INT(eCycle) { \
+ psxRegs.interrupt |= (1 << PSXINT_CDRPLAY); \
+ psxRegs.intCycle[PSXINT_CDRPLAY].cycle = eCycle; \
+ psxRegs.intCycle[PSXINT_CDRPLAY].sCycle = psxRegs.cycle; \
+ new_dyna_set_event(PSXINT_CDRPLAY, eCycle); \
+}
+
#define StartReading(type, eCycle) { \
cdr.Reading = type; \
cdr.FirstSector = 1; \
i = stat.Status;
if (CDR_getStatus(&stat) != -1)
{
- if (stat.Type == 0xff)
- cdr.Stat = DiskError;
+ // BIOS hangs + BIOS error messages
+ //if (stat.Type == 0xff)
+ //cdr.Stat = DiskError;
// case now open
- else if (stat.Status & STATUS_SHELLOPEN)
+ if (stat.Status & STATUS_SHELLOPEN)
{
// Vib Ribbon: pre-CD swap
StopCdda();
static u8 fake_subq_local[3], fake_subq_real[3], fake_subq_index, fake_subq_change;
-void Create_Fake_Subq()
+static void Create_Fake_Subq()
{
u8 temp_cur[3], temp_next[3], temp_start[3], pregap;
int diff;
}
+static void cdrPlayInterrupt_Autopause()
+{
+ struct SubQ *subq = (struct SubQ *)CDR_getBufferSub();
+ if (subq != NULL ) {
+#ifdef CDR_LOG
+ CDR_LOG( "CDDA SUB - %X:%X:%X\n",
+ subq->AbsoluteAddress[0], subq->AbsoluteAddress[1], subq->AbsoluteAddress[2] );
+#endif
+
+ /*
+ CDDA Autopause
+
+ Silhouette Mirage ($3)
+ Tomb Raider 1 ($7)
+ */
+
+ if( cdr.CurTrack >= btoi( subq->TrackNumber ) )
+ return;
+ } else {
+ Create_Fake_Subq();
+#ifdef CDR_LOG___0
+ CDR_LOG( "CDDA FAKE SUB - %d:%d:%d\n",
+ fake_subq_real[0], fake_subq_real[1], fake_subq_real[2] );
+#endif
+
+ if( !fake_subq_change )
+ return;
+
+ fake_subq_change = 0;
+ }
+
+ if (cdr.Mode & MODE_AUTOPAUSE) {
+#ifdef CDR_LOG
+ CDR_LOG( "CDDA STOP\n" );
+#endif
+
+ // Magic the Gathering
+ // - looping territory cdda
+
+ // ...?
+ //cdr.ResultReady = 1;
+ //cdr.Stat = DataReady;
+ cdr.Stat = DataEnd;
+ psxHu32ref(0x1070) |= SWAP32((u32)0x4);
+
+ StopCdda();
+ }
+ if (cdr.Mode & MODE_REPORT) {
+ // rearmed note: PCSX-Reloaded does this for every sector,
+ // but we try to get away with only track change here.
+ memset( cdr.Result, 0, 8 );
+ cdr.Result[0] |= 0x10;
+
+ if (subq != NULL) {
+#ifdef CDR_LOG
+ CDR_LOG( "REPPLAY SUB - %X:%X:%X\n",
+ subq->AbsoluteAddress[0], subq->AbsoluteAddress[1], subq->AbsoluteAddress[2] );
+#endif
+ cdr.CurTrack = btoi( subq->TrackNumber );
+
+ // BIOS CD Player: data already BCD format
+ cdr.Result[1] = subq->TrackNumber;
+ cdr.Result[2] = subq->IndexNumber;
+
+ cdr.Result[3] = subq->AbsoluteAddress[0];
+ cdr.Result[4] = subq->AbsoluteAddress[1];
+ cdr.Result[5] = subq->AbsoluteAddress[2];
+ } else {
+#ifdef CDR_LOG___0
+ CDR_LOG( "REPPLAY FAKE - %d:%d:%d\n",
+ fake_subq_real[0], fake_subq_real[1], fake_subq_real[2] );
+#endif
+
+ // track # / index #
+ cdr.Result[1] = itob(cdr.CurTrack);
+ cdr.Result[2] = itob(fake_subq_index);
+ // absolute
+ cdr.Result[3] = itob( fake_subq_real[0] );
+ cdr.Result[4] = itob( fake_subq_real[1] );
+ cdr.Result[5] = itob( fake_subq_real[2] );
+ }
+
+ // Rayman: Logo freeze (resultready + dataready)
+ cdr.ResultReady = 1;
+ cdr.Stat = DataReady;
+
+ SetResultSize(8);
+ psxHu32ref(0x1070) |= SWAP32((u32)0x4);
+ }
+}
+
+void cdrPlayInterrupt()
+{
+ if( !cdr.Play ) return;
+
+#ifdef CDR_LOG
+ CDR_LOG( "CDDA - %d:%d:%d\n",
+ cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2] );
+#endif
+ CDRPLAY_INT( cdReadTime );
+
+ if (!cdr.Irq && !cdr.Stat && (cdr.Mode & MODE_CDDA) && (cdr.Mode & (MODE_AUTOPAUSE|MODE_REPORT)))
+ cdrPlayInterrupt_Autopause();
+
+ cdr.SetSectorPlay[2]++;
+ if (cdr.SetSectorPlay[2] == 75) {
+ cdr.SetSectorPlay[2] = 0;
+ cdr.SetSectorPlay[1]++;
+ if (cdr.SetSectorPlay[1] == 60) {
+ cdr.SetSectorPlay[1] = 0;
+ cdr.SetSectorPlay[0]++;
+ }
+ }
+
+ //Check_Shell(0);
+}
+
void cdrInterrupt() {
int i;
unsigned char Irq = cdr.Irq;
+ struct SubQ *subq;
// Reschedule IRQ
if (cdr.Stat) {
Wild 9: skip PREGAP + starting accurate SubQ
- plays tracks without retry play
*/
+ /* unneeded with correct cdriso?
Set_Track();
+ */
Find_CurTrack();
ReadTrack( cdr.SetSectorPlay );
-
// GameShark CD Player: Calls 2x + Play 2x
if( cdr.FastBackward || cdr.FastForward ) {
if( cdr.FastForward ) cdr.FastForward--;
// BIOS player - set flag again
cdr.Play = TRUE;
- // TODO?
- // CDRPLAY_INT( cdReadTime );
+ CDRPLAY_INT( cdReadTime );
break;
case CdlForward:
cdr.Result[0] = cdr.StatP;
cdr.Stat = Acknowledge;
- AddIrqQueue(CdlPause + 0x20, 0x800);
+ /*
+ Gundam Battle Assault 2: much slower (*)
+ - Fixes boot, gameplay
+
+ Hokuto no Ken 2: slower
+ - Fixes intro + subtitles
+
+ InuYasha - Feudal Fairy Tale: slower
+ - Fixes battles
+ */
+ AddIrqQueue(CdlPause + 0x20, cdReadTime * 3);
cdr.Ctrl |= 0x80;
break;
}
}
} else {
- if( cdr.Play == FALSE ) Create_Fake_Subq();
+ if( cdr.Play == FALSE || !(cdr.Mode & MODE_CDDA) || !(cdr.Mode & (MODE_AUTOPAUSE|MODE_REPORT)) )
+ Create_Fake_Subq();
// track # / index #
}
// redump.org - wipe time
- /*if( !cdr.Play && CheckSBI(cdr.Result+5) ) {
+ if( !cdr.Play && CheckSBI(cdr.Result+5) ) {
memset( cdr.Result+2, 0, 6 );
}
- */
cdr.Stat = Acknowledge;
break;
// - fixes cutscene speech
{
u8 *buf = CDR_getBuffer();
- memcpy(cdr.Transfer, buf, 8);
+ if (buf != NULL)
+ memcpy(cdr.Transfer, buf, 8);
}
int ret = xa_decode_sector(&cdr.Xa, cdr.Transfer+4, cdr.FirstSector);
if (!ret) {
+ // only handle attenuator basic channel switch for now
+ if (cdr.Xa.stereo) {
+ int i;
+ if ((cdr.AttenuatorLeft[0] | cdr.AttenuatorLeft[1])
+ && !(cdr.AttenuatorRight[0] | cdr.AttenuatorRight[1]))
+ {
+ for (i = 0; i < cdr.Xa.nsamples; i++)
+ cdr.Xa.pcm[i*2 + 1] = cdr.Xa.pcm[i*2];
+ }
+ else if (!(cdr.AttenuatorLeft[0] | cdr.AttenuatorLeft[1])
+ && (cdr.AttenuatorRight[0] | cdr.AttenuatorRight[1]))
+ {
+ for (i = 0; i < cdr.Xa.nsamples; i++)
+ cdr.Xa.pcm[i*2] = cdr.Xa.pcm[i*2 + 1];
+ }
+ }
+
SPU_playADPCMchannel(&cdr.Xa);
cdr.FirstSector = 0;
-
+#if 0
// Crash Team Racing: music, speech
+ // - done using cdda decoded buffer (spu irq)
+ // - don't do here
// signal ADPCM data ready
psxHu32ref(0x1070) |= SWAP32((u32)0x200);
+#endif
}
else cdr.FirstSector = -1;
}
// Tekken: CDXA fade-out
if( (cdr.Ctrl & 3) == 3 ) {
- //cdr.AttenuatorRight[0] = rt;
+ cdr.AttenuatorRight[0] = rt;
}
/*
GameShark CD Player: save time for resume
- Twisted Metal - World Tour: don't save times for DATA reads
- - Only get 1 chance to do this right
- */
- if( cdr.Play && CDR_getStatus(&stat) != -1 ) {
- cdr.SetSectorPlay[0] = stat.Time[0];
- cdr.SetSectorPlay[1] = stat.Time[1];
- cdr.SetSectorPlay[2] = stat.Time[2];
- }
+ Twisted Metal - World Tour: don't mix Setloc / CdlPlay cursors
+ */
StopCdda();
StopReading();
cdr.Ctrl |= 0x80;
cdr.Stat = NoIntr;
- /*
- Gundam Battle Assault 2: much slower (*)
- - Fixes boot, gameplay
-
- Hokuto no Ken 2: slower
- - Fixes intro + subtitles
-
- InuYasha - Feudal Fairy Tale: slower
- - Fixes battles
- */
- AddIrqQueue(cdr.Cmd, cdReadTime * 3);
+ AddIrqQueue(cdr.Cmd, 0x800);
break;
case CdlReset:
// Tekken: CDXA fade-out
if( (cdr.Ctrl & 3) == 2 ) {
- //cdr.AttenuatorLeft[0] = rt;
+ cdr.AttenuatorLeft[0] = rt;
}
else if( (cdr.Ctrl & 3) == 3 ) {
- //cdr.AttenuatorRight[1] = rt;
+ cdr.AttenuatorRight[1] = rt;
}
#ifdef CDR_LOG
CDR_LOG("cdrWrite3() Log: CD3 write: %x\n", rt);
#endif
-/*
+
// Tekken: CDXA fade-out
if( (cdr.Ctrl & 3) == 2 ) {
cdr.AttenuatorLeft[1] = rt;
cdr.AttenuatorRight[0], cdr.AttenuatorRight[1] );
#endif
}
-*/
+
// GameShark CDX CD Player: Irq timing mania
if( rt == 0 &&
return;
}
+ // XA streaming - incorrect timing because of this reschedule
+ // - Final Fantasy Tactics
+ // - various other games
+
if (cdr.Reading && !cdr.ResultReady) {
- CDREAD_INT((cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime);
+ int left = psxRegs.intCycle[PSXINT_CDREAD].sCycle + psxRegs.intCycle[PSXINT_CDREAD].cycle - psxRegs.cycle;
+ int time = (cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime;
+ if (Config.CdrReschedule != 2)
+ if (left < time / 2 || Config.CdrReschedule) { // rearmed guesswork hack
+ //printf("-- resched %d -> %d\n", left, time);
+ CDREAD_INT(time);
+ }
}
return;
void psxDma3(u32 madr, u32 bcr, u32 chcr) {
u32 cdsize;
+ int size;
u8 *ptr;
#ifdef CDR_LOG
- CdlPlay
- Spams DMA3 and gets buffer overrun
*/
-
- if( (cdr.pTransfer-cdr.Transfer) + cdsize > 2352 )
- {
- // avoid crash - probably should wrap here
- //memcpy(ptr, cdr.pTransfer, cdsize);
- }
- else
+ size = CD_FRAMESIZE_RAW - (cdr.pTransfer - cdr.Transfer);
+ if (size > cdsize)
+ size = cdsize;
+ if (size > 0)
{
- memcpy(ptr, cdr.pTransfer, cdsize);
+ memcpy(ptr, cdr.pTransfer, size);
}
psxCpu->Clear(madr, cdsize / 4);
void cdrDmaInterrupt()
{
- HW_DMA3_CHCR &= SWAP32(~0x01000000);
- DMA_INTERRUPT(3);
+ if (HW_DMA3_CHCR & SWAP32(0x01000000))
+ {
+ HW_DMA3_CHCR &= SWAP32(~0x01000000);
+ DMA_INTERRUPT(3);
+ }
}
void cdrReset() {
cdr.CurTrack = 1;
cdr.File = 1;
cdr.Channel = 1;
+
+ // BIOS player - default values
+ cdr.AttenuatorLeft[0] = 0x80;
+ cdr.AttenuatorLeft[1] = 0x00;
+ cdr.AttenuatorRight[0] = 0x80;
+ cdr.AttenuatorRight[1] = 0x00;
}
int cdrFreeze(gzFile f, int Mode) {