#include "cdrom.h"
#include "ppf.h"
+#include "psxdma.h"
cdrStruct cdr;
unsigned char Test22[] = { 0x66, 0x6F, 0x72, 0x20, 0x45, 0x75, 0x72, 0x6F };
unsigned char Test23[] = { 0x43, 0x58, 0x44, 0x32, 0x39 ,0x34, 0x30, 0x51 };
+// cdr.Stat:
+#define NoIntr 0
+#define DataReady 1
+#define Complete 2
+#define Acknowledge 3
+#define DataEnd 4
+#define DiskError 5
+
+/* Modes flags */
+#define MODE_SPEED (1<<7) // 0x80
+#define MODE_STRSND (1<<6) // 0x40 ADPCM on/off
+#define MODE_SIZE_2340 (1<<5) // 0x20
+#define MODE_SIZE_2328 (1<<4) // 0x10
+#define MODE_SF (1<<3) // 0x08 channel on/off
+#define MODE_REPORT (1<<2) // 0x04
+#define MODE_AUTOPAUSE (1<<1) // 0x02
+#define MODE_CDDA (1<<0) // 0x01
+
+/* Status flags */
+#define STATUS_PLAY (1<<7) // 0x80
+#define STATUS_SEEK (1<<6) // 0x40
+#define STATUS_READ (1<<5) // 0x20
+#define STATUS_SHELLOPEN (1<<4) // 0x10
+#define STATUS_UNKNOWN3 (1<<3) // 0x08
+#define STATUS_UNKNOWN2 (1<<2) // 0x04
+#define STATUS_ROTATING (1<<1) // 0x02
+#define STATUS_ERROR (1<<0) // 0x01
+
+
+
// 1x = 75 sectors per second
// PSXCLK = 1 sec in the ps
// so (PSXCLK / 75) = cdr read time (linuzappz)
static struct CdrStat stat;
static struct SubQ *subq;
+static unsigned int msf2sec(char *msf) {
+ return ((msf[0] * 60 + msf[1]) * 75) + msf[2];
+}
+
+static void sec2msf(unsigned int s, char *msf) {
+ msf[0] = s / 75 / 60;
+ s = s - msf[0] * 75 * 60;
+ msf[1] = s / 75;
+ s = s - msf[1] * 75;
+ msf[2] = s;
+}
+
+
#define CDR_INT(eCycle) { \
psxRegs.interrupt |= (1 << PSXINT_CDR); \
psxRegs.intCycle[PSXINT_CDR].cycle = eCycle; \
new_dyna_set_event(PSXINT_CDREAD, eCycle); \
}
+#define CDRLID_INT(eCycle) { \
+ psxRegs.interrupt |= (1 << PSXINT_CDRLID); \
+ psxRegs.intCycle[PSXINT_CDRLID].cycle = eCycle; \
+ psxRegs.intCycle[PSXINT_CDRLID].sCycle = psxRegs.cycle; \
+ new_dyna_set_event(PSXINT_CDRLID, eCycle); \
+}
+
#define StartReading(type, eCycle) { \
cdr.Reading = type; \
cdr.FirstSector = 1; \
cdr.Reading = 0; \
psxRegs.interrupt &= ~(1 << PSXINT_CDREAD); \
} \
- cdr.StatP &= ~0x20;\
+ cdr.StatP &= ~STATUS_READ;\
}
#define StopCdda() { \
if (cdr.Play) { \
if (!Config.Cdda) CDR_stop(); \
- cdr.StatP &= ~0x80; \
+ cdr.StatP &= ~STATUS_PLAY; \
cdr.Play = FALSE; \
+ cdr.FastForward = 0; \
+ cdr.FastBackward = 0; \
+ /*SPU_registerCallback( SPUirq );*/ \
} \
}
cdr.ResultReady = 1; \
}
-static void ReadTrack() {
- cdr.Prev[0] = itob(cdr.SetSector[0]);
- cdr.Prev[1] = itob(cdr.SetSector[1]);
- cdr.Prev[2] = itob(cdr.SetSector[2]);
+
+void cdrLidSeekInterrupt()
+{
+ // turn back on checking
+ if( cdr.LidCheck == 0x10 )
+ {
+ cdr.LidCheck = 0;
+ }
+
+ // official lid close
+ else if( cdr.LidCheck == 0x30 )
+ {
+ // GS CDX 3.3: $13
+ cdr.StatP |= STATUS_ROTATING;
+
+
+ // GS CDX 3.3 - ~50 getlocp tries
+ CDRLID_INT( cdReadTime * 3 );
+ cdr.LidCheck = 0x40;
+ }
+
+ // turn off ready
+ else if( cdr.LidCheck == 0x40 )
+ {
+ // GS CDX 3.3: $01
+ cdr.StatP &= ~STATUS_SHELLOPEN;
+ cdr.StatP &= ~STATUS_ROTATING;
+
+
+ // GS CDX 3.3 - ~50 getlocp tries
+ CDRLID_INT( cdReadTime * 3 );
+ cdr.LidCheck = 0x50;
+ }
+
+ // now seek
+ else if( cdr.LidCheck == 0x50 )
+ {
+ // GameShark Lite: Start seeking ($42)
+ cdr.StatP |= STATUS_SEEK;
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.StatP &= ~STATUS_ERROR;
+
+
+ CDRLID_INT( cdReadTime * 3 );
+ cdr.LidCheck = 0x60;
+ }
+
+ // done = cd ready
+ else if( cdr.LidCheck == 0x60 )
+ {
+ // GameShark Lite: Seek detection done ($02)
+ cdr.StatP &= ~STATUS_SEEK;
+
+ cdr.LidCheck = 0;
+ }
+}
+
+
+static void Check_Shell( int Irq )
+{
+ // check case open/close
+ if (cdr.LidCheck > 0)
+ {
+#ifdef CDR_LOG
+ CDR_LOG( "LidCheck\n" );
+#endif
+
+ // $20 = check lid state
+ if( cdr.LidCheck == 0x20 )
+ {
+ u32 i;
+
+ i = stat.Status;
+ if (CDR_getStatus(&stat) != -1)
+ {
+ if (stat.Type == 0xff)
+ cdr.Stat = DiskError;
+
+ // case now open
+ else if (stat.Status & STATUS_SHELLOPEN)
+ {
+ // Vib Ribbon: pre-CD swap
+ StopCdda();
+
+
+ // GameShark Lite: Death if DiskError happens
+ //
+ // Vib Ribbon: Needs DiskError for CD swap
+
+ if (Irq != CdlNop)
+ {
+ cdr.Stat = DiskError;
+
+ cdr.StatP |= STATUS_ERROR;
+ cdr.Result[0] |= STATUS_ERROR;
+ }
+
+ // GameShark Lite: Wants -exactly- $10
+ cdr.StatP |= STATUS_SHELLOPEN;
+ cdr.StatP &= ~STATUS_ROTATING;
+
+
+ CDRLID_INT( cdReadTime * 3 );
+ cdr.LidCheck = 0x10;
+
+
+ // GS CDX 3.3 = $11
+ }
+
+ // case just closed
+ else if ( i & STATUS_SHELLOPEN )
+ {
+ cdr.StatP |= STATUS_ROTATING;
+
+ CheckCdrom();
+
+
+ if( cdr.Stat == NoIntr )
+ cdr.Stat = Acknowledge;
+
+ psxHu32ref(0x1070) |= SWAP32((u32)0x4);
+
+
+ // begin close-seek-ready cycle
+ CDRLID_INT( cdReadTime * 3 );
+ cdr.LidCheck = 0x30;
+
+
+ // GameShark Lite: Wants -exactly- $42, then $02
+ // GS CDX 3.3: Wants $11/$80, $13/$80, $01/$00
+ }
+
+ // case still closed - wait for recheck
+ else
+ {
+ CDRLID_INT( cdReadTime * 3 );
+ cdr.LidCheck = 0x10;
+ }
+ }
+ }
+
+
+ // GS CDX: clear all values but #1,#2
+ if( (cdr.LidCheck >= 0x30) || (cdr.StatP & STATUS_SHELLOPEN) )
+ {
+ SetResultSize(16);
+ memset( cdr.Result, 0, 16 );
+
+ cdr.Result[0] = cdr.StatP;
+
+
+ // GS CDX: special return value
+ if( cdr.StatP & STATUS_SHELLOPEN )
+ {
+ cdr.Result[1] = 0x80;
+ }
+
+
+ if( cdr.Stat == NoIntr )
+ cdr.Stat = Acknowledge;
+
+ psxHu32ref(0x1070) |= SWAP32((u32)0x4);
+ }
+ }
+}
+
+
+void Find_CurTrack() {
+ cdr.CurTrack = 0;
+
+ if (CDR_getTN(cdr.ResultTN) != -1) {
+ int lcv;
+
+ for( lcv = 1; lcv <= cdr.ResultTN[1]; lcv++ ) {
+ if (CDR_getTD((u8)(lcv), cdr.ResultTD) != -1) {
+ u32 sect1, sect2;
+
+#ifdef CDR_LOG___0
+ CDR_LOG( "curtrack %d %d %d | %d %d %d | %d\n",
+ cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2],
+ cdr.ResultTD[2], cdr.ResultTD[1], cdr.ResultTD[0],
+ cdr.CurTrack );
+#endif
+
+ // find next track boundary - only need m:s accuracy
+ sect1 = cdr.SetSectorPlay[0] * 60 * 75 + cdr.SetSectorPlay[1] * 75;
+ sect2 = cdr.ResultTD[2] * 60 * 75 + cdr.ResultTD[1] * 75;
+
+ // Twisted Metal 4 - psx cdda pregap (2-sec)
+ // - fix in-game music
+ sect2 -= 75 * 2;
+
+ if( sect1 >= sect2 ) {
+ cdr.CurTrack++;
+ continue;
+ }
+ }
+
+ break;
+ }
+ }
+}
+
+static void ReadTrack( u8 *time ) {
+ cdr.Prev[0] = itob( time[0] );
+ cdr.Prev[1] = itob( time[1] );
+ cdr.Prev[2] = itob( time[2] );
#ifdef CDR_LOG
CDR_LOG("ReadTrack() Log: KEY *** %x:%x:%x\n", cdr.Prev[0], cdr.Prev[1], cdr.Prev[2]);
cdr.RErr = CDR_readTrack(cdr.Prev);
}
-// cdr.Stat:
-#define NoIntr 0
-#define DataReady 1
-#define Complete 2
-#define Acknowledge 3
-#define DataEnd 4
-#define DiskError 5
void AddIrqQueue(unsigned char irq, unsigned long ecycle) {
cdr.Irq = irq;
- if (cdr.Stat) {
- cdr.eCycle = ecycle;
+ cdr.eCycle = ecycle;
+
+ // Doom: Force rescheduling
+ // - Fixes boot
+ CDR_INT(ecycle);
+}
+
+
+void Set_Track()
+{
+ if (CDR_getTN(cdr.ResultTN) != -1) {
+ int lcv;
+
+ for( lcv = 1; lcv < cdr.ResultTN[1]; lcv++ ) {
+ if (CDR_getTD((u8)(lcv), cdr.ResultTD) != -1) {
+#ifdef CDR_LOG___0
+ CDR_LOG( "settrack %d %d %d | %d %d %d | %d\n",
+ cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2],
+ cdr.ResultTD[2], cdr.ResultTD[1], cdr.ResultTD[0],
+ cdr.CurTrack );
+#endif
+
+ // check if time matches track start (only need min, sec accuracy)
+ // - m:s:f vs f:s:m
+ if( cdr.SetSectorPlay[0] == cdr.ResultTD[2] &&
+ cdr.SetSectorPlay[1] == cdr.ResultTD[1] ) {
+ // skip pregap frames
+ if( cdr.SetSectorPlay[2] < cdr.ResultTD[0] )
+ cdr.SetSectorPlay[2] = cdr.ResultTD[0];
+
+ break;
+ }
+ else if( cdr.SetSectorPlay[0] < cdr.ResultTD[2] )
+ break;
+ }
+ }
+ }
+}
+
+
+static u8 fake_subq_local[3], fake_subq_real[3], fake_subq_index, fake_subq_change;
+void Create_Fake_Subq()
+{
+ u8 temp_cur[3], temp_next[3], temp_start[3], pregap;
+ int diff;
+
+ if (CDR_getTN(cdr.ResultTN) == -1) return;
+ if( cdr.CurTrack+1 <= cdr.ResultTN[1] ) {
+ pregap = 150;
+ if( CDR_getTD(cdr.CurTrack+1, cdr.ResultTD) == -1 ) return;
+ } else {
+ // last track - cd size
+ pregap = 0;
+ if( CDR_getTD(0, cdr.ResultTD) == -1 ) return;
+ }
+
+ if( cdr.Play == TRUE ) {
+ temp_cur[0] = cdr.SetSectorPlay[0];
+ temp_cur[1] = cdr.SetSectorPlay[1];
+ temp_cur[2] = cdr.SetSectorPlay[2];
+ } else {
+ temp_cur[0] = btoi( cdr.Prev[0] );
+ temp_cur[1] = btoi( cdr.Prev[1] );
+ temp_cur[2] = btoi( cdr.Prev[2] );
+ }
+
+ fake_subq_real[0] = temp_cur[0];
+ fake_subq_real[1] = temp_cur[1];
+ fake_subq_real[2] = temp_cur[2];
+
+ temp_next[0] = cdr.ResultTD[2];
+ temp_next[1] = cdr.ResultTD[1];
+ temp_next[2] = cdr.ResultTD[0];
+
+
+ // flag- next track
+ if( msf2sec(temp_cur) >= msf2sec( temp_next )-pregap ) {
+ fake_subq_change = 1;
+
+ cdr.CurTrack++;
+
+ // end cd
+ if( pregap == 0 ) StopCdda();
+ }
+
+ //////////////////////////////////////////////////
+ //////////////////////////////////////////////////
+
+ // repair
+ if( cdr.CurTrack <= cdr.ResultTN[1] ) {
+ if( CDR_getTD(cdr.CurTrack, cdr.ResultTD) == -1 ) return;
+ } else {
+ // last track - cd size
+ if( CDR_getTD(0, cdr.ResultTD) == -1 ) return;
+ }
+
+ temp_start[0] = cdr.ResultTD[2];
+ temp_start[1] = cdr.ResultTD[1];
+ temp_start[2] = cdr.ResultTD[0];
+
+
+#ifdef CDR_LOG
+ CDR_LOG( "CDDA FAKE SUB - %d:%d:%d / %d:%d:%d / %d:%d:%d\n",
+ temp_cur[0], temp_cur[1], temp_cur[2],
+ temp_start[0], temp_start[1], temp_start[2],
+ temp_next[0], temp_next[1], temp_next[2]);
+#endif
+
+
+
+ // local time - pregap / real
+ diff = msf2sec(temp_cur) - msf2sec( temp_start );
+ if( diff < 0 ) {
+ fake_subq_index = 0;
+
+ sec2msf( -diff, fake_subq_local );
} else {
- CDR_INT(ecycle);
+ fake_subq_index = 1;
+
+ sec2msf( diff, fake_subq_local );
}
}
+
void cdrInterrupt() {
int i;
unsigned char Irq = cdr.Irq;
+ // Reschedule IRQ
if (cdr.Stat) {
- CDR_INT(0x1000);
+ CDR_INT( 0x100 );
return;
}
switch (Irq) {
case CdlSync:
SetResultSize(1);
- cdr.StatP |= 0x2;
+ cdr.StatP |= STATUS_ROTATING;
cdr.Result[0] = cdr.StatP;
cdr.Stat = Acknowledge;
break;
SetResultSize(1);
cdr.Result[0] = cdr.StatP;
cdr.Stat = Acknowledge;
- i = stat.Status;
- if (CDR_getStatus(&stat) != -1) {
- if (stat.Type == 0xff) cdr.Stat = DiskError;
- if (stat.Status & 0x10) {
- cdr.Stat = DiskError;
- cdr.Result[0] |= 0x11;
- cdr.Result[0] &= ~0x02;
- }
- else if (i & 0x10) {
- cdr.StatP |= 0x2;
- cdr.Result[0] |= 0x2;
- CheckCdrom();
- }
- }
+
+ if (cdr.LidCheck == 0) cdr.LidCheck = 0x20;
break;
case CdlSetloc:
cdr.CmdProcess = 0;
SetResultSize(1);
- cdr.StatP |= 0x2;
+ cdr.StatP |= STATUS_ROTATING;
cdr.Result[0] = cdr.StatP;
cdr.Stat = Acknowledge;
break;
case CdlPlay:
+ fake_subq_change = 0;
+
+ if( cdr.Seeked == FALSE ) {
+ memcpy( cdr.SetSectorPlay, cdr.SetSector, 4 );
+ cdr.Seeked = TRUE;
+ }
+
+ /*
+ Rayman: detect track changes
+ - fixes logo freeze
+
+ Twisted Metal 2: skip PREGAP + starting accurate SubQ
+ - plays tracks without retry play
+
+ Wild 9: skip PREGAP + starting accurate SubQ
+ - plays tracks without retry play
+ */
+ Set_Track();
+ Find_CurTrack();
+ ReadTrack( cdr.SetSectorPlay );
+
+
+ // GameShark CD Player: Calls 2x + Play 2x
+ if( cdr.FastBackward || cdr.FastForward ) {
+ if( cdr.FastForward ) cdr.FastForward--;
+ if( cdr.FastBackward ) cdr.FastBackward--;
+
+ if( cdr.FastBackward == 0 && cdr.FastForward == 0 ) {
+ 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];
+ }
+ }
+ }
+
+
+ if (!Config.Cdda) {
+ // BIOS CD Player
+ // - Pause player, hit Track 01/02/../xx (Setloc issued!!)
+
+ // GameShark CD Player: Resume play
+ if( cdr.ParamC == 0 ) {
+#ifdef CDR_LOG___0
+ CDR_LOG( "PLAY Resume @ %d:%d:%d\n",
+ cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2] );
+#endif
+
+ //CDR_play( cdr.SetSectorPlay );
+ }
+ else
+ {
+ // BIOS CD Player: Resume play
+ if( cdr.Param[0] == 0 ) {
+#ifdef CDR_LOG___0
+ CDR_LOG( "PLAY Resume T0 @ %d:%d:%d\n",
+ cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2] );
+#endif
+
+ //CDR_play( cdr.SetSectorPlay );
+ }
+ else {
+#ifdef CDR_LOG___0
+ CDR_LOG( "PLAY Resume Td @ %d:%d:%d\n",
+ cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2] );
+#endif
+
+ // BIOS CD Player: Allow track replaying
+ StopCdda();
+
+
+ cdr.CurTrack = btoi( cdr.Param[0] );
+
+ if (CDR_getTN(cdr.ResultTN) != -1) {
+ // check last track
+ if (cdr.CurTrack > cdr.ResultTN[1])
+ cdr.CurTrack = cdr.ResultTN[1];
+
+ if (CDR_getTD((u8)(cdr.CurTrack), cdr.ResultTD) != -1) {
+ cdr.SetSectorPlay[0] = cdr.ResultTD[2];
+ cdr.SetSectorPlay[1] = cdr.ResultTD[1];
+ cdr.SetSectorPlay[2] = cdr.ResultTD[0];
+
+ // reset data
+ Set_Track();
+ Find_CurTrack();
+ ReadTrack( cdr.SetSectorPlay );
+
+ //CDR_play(cdr.SetSectorPlay);
+ }
+ }
+ }
+ }
+ }
+
+
+ // Vib Ribbon: gameplay checks flag
+ cdr.StatP &= ~STATUS_SEEK;
+
+
cdr.CmdProcess = 0;
SetResultSize(1);
- cdr.StatP |= 0x2;
+ cdr.StatP |= STATUS_ROTATING;
cdr.Result[0] = cdr.StatP;
cdr.Stat = Acknowledge;
- cdr.StatP |= 0x80;
-// if ((cdr.Mode & 0x5) == 0x5) AddIrqQueue(REPPLAY, cdReadTime);
+
+ cdr.StatP |= STATUS_PLAY;
+
+
+ // BIOS player - set flag again
+ cdr.Play = TRUE;
+
+ // TODO?
+ // CDRPLAY_INT( cdReadTime );
break;
- case CdlForward:
+ case CdlForward:
cdr.CmdProcess = 0;
SetResultSize(1);
- cdr.StatP |= 0x2;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Complete;
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.Result[0] = cdr.StatP;
+ cdr.Stat = Complete;
+
+
+ // GameShark CD Player: Calls 2x + Play 2x
+ if( cdr.FastForward == 0 ) cdr.FastForward = 2;
+ else cdr.FastForward++;
+
+ cdr.FastBackward = 0;
break;
- case CdlBackward:
+ case CdlBackward:
cdr.CmdProcess = 0;
SetResultSize(1);
- cdr.StatP |= 0x2;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Complete;
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.Result[0] = cdr.StatP;
+ cdr.Stat = Complete;
+
+
+ // GameShark CD Player: Calls 2x + Play 2x
+ if( cdr.FastBackward == 0 ) cdr.FastBackward = 2;
+ else cdr.FastBackward++;
+
+ cdr.FastForward = 0;
break;
- case CdlStandby:
+ case CdlStandby:
cdr.CmdProcess = 0;
SetResultSize(1);
- cdr.StatP |= 0x2;
+ cdr.StatP |= STATUS_ROTATING;
cdr.Result[0] = cdr.StatP;
cdr.Stat = Complete;
break;
case CdlStop:
cdr.CmdProcess = 0;
SetResultSize(1);
- cdr.StatP &= ~0x2;
+ cdr.StatP &= ~STATUS_ROTATING;
cdr.Result[0] = cdr.StatP;
cdr.Stat = Complete;
// cdr.Stat = Acknowledge;
- // check case open/close -shalma
- i = stat.Status;
- if (CDR_getStatus(&stat) != -1) {
- if (stat.Type == 0xff) cdr.Stat = DiskError;
- if (stat.Status & 0x10) {
- cdr.Stat = DiskError;
- cdr.Result[0] |= 0x11;
- cdr.Result[0] &= ~0x02;
- }
- else if (i & 0x10) {
- cdr.StatP |= 0x2;
- cdr.Result[0] |= 0x2;
- CheckCdrom();
- }
- }
+ if (cdr.LidCheck == 0) cdr.LidCheck = 0x20;
break;
case CdlPause:
SetResultSize(1);
cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
- AddIrqQueue(CdlPause + 0x20, 0x1000);
+ cdr.Stat = Acknowledge;
+
+ AddIrqQueue(CdlPause + 0x20, 0x800);
cdr.Ctrl |= 0x80;
break;
case CdlPause + 0x20:
SetResultSize(1);
- cdr.StatP &= ~0x20;
- cdr.StatP |= 0x2;
+ cdr.StatP &= ~STATUS_READ;
+ cdr.StatP |= STATUS_ROTATING;
cdr.Result[0] = cdr.StatP;
- cdr.Stat = Complete;
+ cdr.Stat = Complete;
break;
- case CdlInit:
+ case CdlInit:
SetResultSize(1);
- cdr.StatP = 0x2;
+ cdr.StatP = STATUS_ROTATING;
cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
+ cdr.Stat = Acknowledge;
// if (!cdr.Init) {
- AddIrqQueue(CdlInit + 0x20, 0x1000);
+ AddIrqQueue(CdlInit + 0x20, 0x800);
// }
break;
case CdlInit + 0x20:
SetResultSize(1);
cdr.Result[0] = cdr.StatP;
- cdr.Stat = Complete;
+ cdr.Stat = Complete;
cdr.Init = 1;
break;
- case CdlMute:
+ case CdlMute:
SetResultSize(1);
- cdr.StatP |= 0x2;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.Result[0] = cdr.StatP;
+ cdr.Stat = Acknowledge;
break;
- case CdlDemute:
+ case CdlDemute:
SetResultSize(1);
- cdr.StatP |= 0x2;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.Result[0] = cdr.StatP;
+ cdr.Stat = Acknowledge;
break;
- case CdlSetfilter:
+ case CdlSetfilter:
SetResultSize(1);
- cdr.StatP |= 0x2;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
- break;
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.Result[0] = cdr.StatP;
+ cdr.Stat = Acknowledge;
+ break;
case CdlSetmode:
SetResultSize(1);
- cdr.StatP |= 0x2;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
- break;
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.Result[0] = cdr.StatP;
+ cdr.Stat = Acknowledge;
+ break;
- case CdlGetmode:
+ case CdlGetmode:
SetResultSize(6);
- cdr.StatP |= 0x2;
- cdr.Result[0] = cdr.StatP;
- cdr.Result[1] = cdr.Mode;
- cdr.Result[2] = cdr.File;
- cdr.Result[3] = cdr.Channel;
- cdr.Result[4] = 0;
- cdr.Result[5] = 0;
- cdr.Stat = Acknowledge;
- break;
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.Result[0] = cdr.StatP;
+ cdr.Result[1] = cdr.Mode;
+ cdr.Result[2] = cdr.File;
+ cdr.Result[3] = cdr.Channel;
+ cdr.Result[4] = 0;
+ cdr.Result[5] = 0;
+ cdr.Stat = Acknowledge;
+ break;
- case CdlGetlocL:
+ case CdlGetlocL:
SetResultSize(8);
-// for (i = 0; i < 8; i++)
-// cdr.Result[i] = itob(cdr.Transfer[i]);
- for (i = 0; i < 8; i++)
+ for (i = 0; i < 8; i++)
cdr.Result[i] = cdr.Transfer[i];
- cdr.Stat = Acknowledge;
- break;
+ cdr.Stat = Acknowledge;
+ break;
case CdlGetlocP:
- SetResultSize(8);
+ // GameShark CDX CD Player: uses 17 bytes output (wraps around)
+ SetResultSize(17);
+ memset( cdr.Result, 0, 16 );
+
subq = (struct SubQ *)CDR_getBufferSub();
if (subq != NULL) {
memcpy(cdr.Result + 2, subq->TrackRelativeAddress, 3);
memcpy(cdr.Result + 5, subq->AbsoluteAddress, 3);
- // subQ integrity check
+
+ // subQ integrity check - data only (skip audio)
+ if( subq->TrackNumber == 1 && stat.Type == 0x01 ) {
if (calcCrc((u8 *)subq + 12, 10) != (((u16)subq->CRC[0] << 8) | subq->CRC[1])) {
memset(cdr.Result + 2, 0, 3 + 3); // CRC wrong, wipe out time data
}
+ }
} else {
- cdr.Result[0] = 1;
- cdr.Result[1] = 1;
+ if( cdr.Play == FALSE ) Create_Fake_Subq();
- cdr.Result[2] = btoi(cdr.Prev[0]);
- cdr.Result[3] = btoi(cdr.Prev[1]) - 2;
- cdr.Result[4] = cdr.Prev[2];
- // m:s adjustment
- if ((s8)cdr.Result[3] < 0) {
- cdr.Result[3] += 60;
- cdr.Result[2] -= 1;
- }
+ // track # / index #
+ cdr.Result[0] = itob(cdr.CurTrack);
+ cdr.Result[1] = itob(fake_subq_index);
- cdr.Result[2] = itob(cdr.Result[2]);
- cdr.Result[3] = itob(cdr.Result[3]);
+ // local
+ cdr.Result[2] = itob( fake_subq_local[0] );
+ cdr.Result[3] = itob( fake_subq_local[1] );
+ cdr.Result[4] = itob( fake_subq_local[2] );
- memcpy(cdr.Result + 5, cdr.Prev, 3);
+ // absolute
+ cdr.Result[5] = itob( fake_subq_real[0] );
+ cdr.Result[6] = itob( fake_subq_real[1] );
+ cdr.Result[7] = itob( fake_subq_real[2] );
}
+ // redump.org - wipe time
+ /*if( !cdr.Play && CheckSBI(cdr.Result+5) ) {
+ memset( cdr.Result+2, 0, 6 );
+ }
+ */
+
cdr.Stat = Acknowledge;
break;
- case CdlGetTN:
+ case CdlGetTN:
+ // 5-Star Racing: don't stop CDDA
+ //
+ // Vib Ribbon: CD swap
+ StopReading();
+
cdr.CmdProcess = 0;
SetResultSize(3);
- cdr.StatP |= 0x2;
- cdr.Result[0] = cdr.StatP;
- if (CDR_getTN(cdr.ResultTN) == -1) {
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.Result[0] = cdr.StatP;
+ if (CDR_getTN(cdr.ResultTN) == -1) {
cdr.Stat = DiskError;
- cdr.Result[0] |= 0x01;
- } else {
- cdr.Stat = Acknowledge;
- cdr.Result[1] = itob(cdr.ResultTN[0]);
- cdr.Result[2] = itob(cdr.ResultTN[1]);
- }
- break;
+ cdr.Result[0] |= STATUS_ERROR;
+ } else {
+ cdr.Stat = Acknowledge;
+ cdr.Result[1] = itob(cdr.ResultTN[0]);
+ cdr.Result[2] = itob(cdr.ResultTN[1]);
+ }
+ break;
- case CdlGetTD:
+ case CdlGetTD:
cdr.CmdProcess = 0;
cdr.Track = btoi(cdr.Param[0]);
SetResultSize(4);
- cdr.StatP |= 0x2;
+ cdr.StatP |= STATUS_ROTATING;
if (CDR_getTD(cdr.Track, cdr.ResultTD) == -1) {
cdr.Stat = DiskError;
- cdr.Result[0] |= 0x01;
+ cdr.Result[0] |= STATUS_ERROR;
} else {
cdr.Stat = Acknowledge;
cdr.Result[0] = cdr.StatP;
}
break;
- case CdlSeekL:
+ case CdlSeekL:
SetResultSize(1);
- cdr.StatP |= 0x2;
- cdr.Result[0] = cdr.StatP;
- cdr.StatP |= 0x40;
- cdr.Stat = Acknowledge;
- cdr.Seeked = TRUE;
- AddIrqQueue(CdlSeekL + 0x20, 0x1000);
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.Result[0] = cdr.StatP;
+ cdr.StatP |= STATUS_SEEK;
+ cdr.Stat = Acknowledge;
+
+ /*
+ Crusaders of Might and Magic = 0.5x-4x
+ - fix cutscene speech start
+
+ Eggs of Steel = 2x-?
+ - fix new game
+
+ Medievil = ?-4x
+ - fix cutscene speech
+
+ Rockman X5 = 0.5-4x
+ - fix capcom logo
+ */
+ AddIrqQueue(CdlSeekL + 0x20, cdReadTime * 4);
break;
- case CdlSeekL + 0x20:
+ case CdlSeekL + 0x20:
SetResultSize(1);
- cdr.StatP |= 0x2;
- cdr.StatP &= ~0x40;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Complete;
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.StatP &= ~STATUS_SEEK;
+ cdr.Result[0] = cdr.StatP;
+ cdr.Seeked = TRUE;
+ cdr.Stat = Complete;
+
+
+ // Mega Man Legends 2: must update read cursor for getlocp
+ ReadTrack( cdr.SetSector );
break;
- case CdlSeekP:
+ case CdlSeekP:
SetResultSize(1);
- cdr.StatP |= 0x2;
- cdr.Result[0] = cdr.StatP;
- cdr.StatP |= 0x40;
- cdr.Stat = Acknowledge;
- AddIrqQueue(CdlSeekP + 0x20, 0x1000);
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.Result[0] = cdr.StatP;
+ cdr.StatP |= STATUS_SEEK;
+ cdr.Stat = Acknowledge;
+ AddIrqQueue(CdlSeekP + 0x20, cdReadTime * 1);
break;
- case CdlSeekP + 0x20:
+ case CdlSeekP + 0x20:
SetResultSize(1);
- cdr.StatP |= 0x2;
- cdr.StatP &= ~0x40;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Complete;
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.StatP &= ~STATUS_SEEK;
+ cdr.Result[0] = cdr.StatP;
+ cdr.Stat = Complete;
+ cdr.Seeked = TRUE;
+
+ // GameShark Music Player
+ memcpy( cdr.SetSectorPlay, cdr.SetSector, 4 );
+
+ // Tomb Raider 2: must update read cursor for getlocp
+ Find_CurTrack();
+ ReadTrack( cdr.SetSectorPlay );
break;
case CdlTest:
- cdr.Stat = Acknowledge;
- switch (cdr.Param[0]) {
- case 0x20: // System Controller ROM Version
+ cdr.Stat = Acknowledge;
+ switch (cdr.Param[0]) {
+ case 0x20: // System Controller ROM Version
SetResultSize(4);
memcpy(cdr.Result, Test20, 4);
break;
SetResultSize(8);
memcpy(cdr.Result, Test23, 4);
break;
- }
+ }
break;
- case CdlID:
+ case CdlID:
SetResultSize(1);
- cdr.StatP |= 0x2;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
- AddIrqQueue(CdlID + 0x20, 0x1000);
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.Result[0] = cdr.StatP;
+ cdr.Stat = Acknowledge;
+ AddIrqQueue(CdlID + 0x20, 0x800);
break;
case CdlID + 0x20:
SetResultSize(8);
- if (CDR_getStatus(&stat) == -1) {
- cdr.Result[0] = 0x00; // 0x08 and cdr.Result[1]|0x10 : audio cd, enters cd player
- cdr.Result[1] = 0x00; // 0x80 leads to the menu in the bios, else loads CD
- }
- else {
- if (stat.Type == 2) {
- cdr.Result[0] = 0x08;
- cdr.Result[1] = 0x10;
- }
- else {
- cdr.Result[0] = 0x00;
- cdr.Result[1] = 0x00;
- }
- }
- cdr.Result[1] |= 0x80;
+
+ if (CDR_getStatus(&stat) == -1) {
+ cdr.Result[0] = 0x00; // 0x08 and cdr.Result[1]|0x10 : audio cd, enters cd player
+ cdr.Result[1] = 0x80; // 0x80 leads to the menu in the bios, else loads CD
+ }
+ else {
+ if (stat.Type == 2) {
+ // Music CD
+ cdr.Result[0] = 0x08;
+ cdr.Result[1] = 0x10;
+
+ cdr.Result[1] |= 0x80;
+ }
+ else {
+ // Data CD
+ if (CdromId[0] == '\0') {
+ cdr.Result[0] = 0x00;
+ cdr.Result[1] = 0x80;
+ }
+ else {
+ cdr.Result[0] = 0x08;
+ cdr.Result[1] = 0x00;
+ }
+ }
+ }
+
cdr.Result[2] = 0x00;
cdr.Result[3] = 0x00;
strncpy((char *)&cdr.Result[4], "PCSX", 4);
case CdlReset:
SetResultSize(1);
- cdr.StatP = 0x2;
+ cdr.StatP = STATUS_ROTATING;
cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
+ cdr.Stat = Acknowledge;
break;
- case CdlReadToc:
+ case CdlReadT:
+ SetResultSize(1);
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.Result[0] = cdr.StatP;
+ cdr.Stat = Acknowledge;
+ AddIrqQueue(CdlReadT + 0x20, 0x800);
+ break;
+
+ case CdlReadT + 0x20:
+ SetResultSize(1);
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.Result[0] = cdr.StatP;
+ cdr.Stat = Complete;
+ break;
+
+ case CdlReadToc:
SetResultSize(1);
- cdr.StatP |= 0x2;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
- AddIrqQueue(CdlReadToc + 0x20, 0x1000);
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.Result[0] = cdr.StatP;
+ cdr.Stat = Acknowledge;
+ AddIrqQueue(CdlReadToc + 0x20, 0x800);
break;
- case CdlReadToc + 0x20:
+ case CdlReadToc + 0x20:
SetResultSize(1);
- cdr.StatP |= 0x2;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Complete;
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.Result[0] = cdr.StatP;
+ cdr.Stat = Complete;
break;
case AUTOPAUSE:
StopCdda();
StopReading();
cdr.OCUP = 0;
- cdr.StatP&=~0x20;
+ cdr.StatP&=~0x20;
cdr.StatP|= 0x2;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = DataEnd;
+ cdr.Result[0] = cdr.StatP;
+ cdr.Stat = DataEnd;
*/ AddIrqQueue(CdlPause, 0x800);
break;
case READ_ACK:
if (!cdr.Reading) return;
- SetResultSize(1);
- cdr.StatP |= 0x2;
- cdr.Result[0] = cdr.StatP;
+
+ // Fighting Force 2 - update subq time immediately
+ // - fixes new game
+ ReadTrack( cdr.SetSector );
+
+
+ // Crusaders of Might and Magic - update getlocl now
+ // - fixes cutscene speech
+ {
+ u8 *buf = CDR_getBuffer();
+ memcpy(cdr.Transfer, buf, 8);
+ }
+
+
+ /*
+ Duke Nukem: Land of the Babes - seek then delay read for one frame
+ - fixes cutscenes
+ */
+
if (!cdr.Seeked) {
cdr.Seeked = TRUE;
- cdr.StatP |= 0x40;
- }
- cdr.StatP |= 0x20;
- cdr.Stat = Acknowledge;
-// CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime);
- CDREAD_INT(0x80000);
- break;
+ cdr.StatP |= STATUS_SEEK;
+ cdr.StatP &= ~STATUS_READ;
+
+ // Crusaders of Might and Magic - use short time
+ // - fix cutscene speech (startup)
+
+ // ??? - use more accurate seek time later
+ CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime * 1);
+ } else {
+ cdr.StatP |= STATUS_READ;
+ cdr.StatP &= ~STATUS_SEEK;
+
+ CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime * 1);
+ }
- case REPPLAY_ACK:
- cdr.Stat = Acknowledge;
- cdr.Result[0] = cdr.StatP;
SetResultSize(1);
- AddIrqQueue(REPPLAY, cdReadTime);
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.Result[0] = cdr.StatP;
+ cdr.Stat = Acknowledge;
break;
- case REPPLAY:
- if ((cdr.Mode & 5) != 5) break;
-/* if (CDR_getStatus(&stat) == -1) {
- cdr.Result[0] = 0;
- cdr.Result[1] = 0;
- cdr.Result[2] = 0;
- cdr.Result[3] = 0;
- cdr.Result[4] = 0;
- cdr.Result[5] = 0;
- cdr.Result[6] = 0;
- cdr.Result[7] = 0;
- } else memcpy(cdr.Result, &stat.Track, 8);
- cdr.Stat = 1;
- SetResultSize(8);
- AddIrqQueue(REPPLAY_ACK, cdReadTime);
-*/ break;
-
case 0xff:
return;
break;
}
+ Check_Shell( Irq );
+
if (cdr.Stat != NoIntr && cdr.Reg2 != 0x18) {
psxHu32ref(0x1070) |= SWAP32((u32)0x4);
}
if (!cdr.Reading)
return;
- if (cdr.Stat) {
- CDREAD_INT(0x1000);
+ if (cdr.Irq || cdr.Stat) {
+ CDREAD_INT(0x100);
return;
}
CDR_LOG("cdrReadInterrupt() Log: KEY END");
#endif
- cdr.OCUP = 1;
+ cdr.OCUP = 1;
SetResultSize(1);
- cdr.StatP |= 0x22;
- cdr.StatP &= ~0x40;
- cdr.Result[0] = cdr.StatP;
+ cdr.StatP |= STATUS_READ|STATUS_ROTATING;
+ cdr.StatP &= ~STATUS_SEEK;
+ cdr.Result[0] = cdr.StatP;
- ReadTrack();
+ ReadTrack( cdr.SetSector );
buf = CDR_getBuffer();
if (buf == NULL)
#endif
memset(cdr.Transfer, 0, DATA_SIZE);
cdr.Stat = DiskError;
- cdr.Result[0] |= 0x01;
+ cdr.Result[0] |= STATUS_ERROR;
CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime);
return;
}
memcpy(cdr.Transfer, buf, DATA_SIZE);
CheckPPFCache(cdr.Transfer, cdr.Prev[0], cdr.Prev[1], cdr.Prev[2]);
- cdr.Stat = DataReady;
#ifdef CDR_LOG
fprintf(emuLog, "cdrReadInterrupt() Log: cdr.Transfer %x:%x:%x\n", cdr.Transfer[0], cdr.Transfer[1], cdr.Transfer[2]);
#endif
- if ((!cdr.Muted) && (cdr.Mode & 0x40) && (!Config.Xa) && (cdr.FirstSector != -1)) { // CD-XA
+ if ((!cdr.Muted) && (cdr.Mode & MODE_STRSND) && (!Config.Xa) && (cdr.FirstSector != -1)) { // CD-XA
+ // Firemen 2: Multi-XA files - briefings, cutscenes
+ if( cdr.FirstSector == 1 && (cdr.Mode & MODE_SF)==0 ) {
+ cdr.File = cdr.Transfer[4 + 0];
+ cdr.Channel = cdr.Transfer[4 + 1];
+ }
+
if ((cdr.Transfer[4 + 2] & 0x4) &&
- ((cdr.Mode & 0x8) ? (cdr.Transfer[4 + 1] == cdr.Channel) : 1) &&
+ (cdr.Transfer[4 + 1] == cdr.Channel) &&
(cdr.Transfer[4 + 0] == cdr.File)) {
int ret = xa_decode_sector(&cdr.Xa, cdr.Transfer+4, cdr.FirstSector);
if (!ret) {
SPU_playADPCMchannel(&cdr.Xa);
cdr.FirstSector = 0;
+
+
+ // Crash Team Racing: music, speech
+
+ // signal ADPCM data ready
+ psxHu32ref(0x1070) |= SWAP32((u32)0x200);
}
else cdr.FirstSector = -1;
}
}
cdr.SetSector[2]++;
- if (cdr.SetSector[2] == 75) {
- cdr.SetSector[2] = 0;
- cdr.SetSector[1]++;
- if (cdr.SetSector[1] == 60) {
- cdr.SetSector[1] = 0;
- cdr.SetSector[0]++;
- }
- }
-
- cdr.Readed = 0;
-
- if ((cdr.Transfer[4 + 2] & 0x80) && (cdr.Mode & 0x2)) { // EOF
+ if (cdr.SetSector[2] == 75) {
+ cdr.SetSector[2] = 0;
+ cdr.SetSector[1]++;
+ if (cdr.SetSector[1] == 60) {
+ cdr.SetSector[1] = 0;
+ cdr.SetSector[0]++;
+ }
+ }
+
+ cdr.Readed = 0;
+
+ // G-Police: Don't autopause ADPCM even if mode set (music)
+ if ((cdr.Transfer[4 + 2] & 0x80) && (cdr.Mode & MODE_AUTOPAUSE) &&
+ (cdr.Transfer[4 + 2] & 0x4) != 0x4 ) { // EOF
#ifdef CDR_LOG
CDR_LOG("cdrReadInterrupt() Log: Autopausing read\n");
#endif
-// AddIrqQueue(AUTOPAUSE, 0x1000);
- AddIrqQueue(CdlPause, 0x1000);
+// AddIrqQueue(AUTOPAUSE, 0x2000);
+ AddIrqQueue(CdlPause, 0x2000);
}
else {
- CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime);
+ CDREAD_INT((cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime);
+ }
+
+ /*
+ Croc 2: $40 - only FORM1 (*)
+ Judge Dredd: $C8 - only FORM1 (*)
+ Sim Theme Park - no adpcm at all (zero)
+ */
+
+ if( (cdr.Mode & MODE_STRSND) == 0 || (cdr.Transfer[4+2] & 0x4) != 0x4 ) {
+ cdr.Stat = DataReady;
+ } else {
+ // Breath of Fire 3 - fix inn sleeping
+ // Rockman X5 - no music restart problem
+ cdr.Stat = NoIntr;
}
psxHu32ref(0x1070) |= SWAP32((u32)0x4);
+
+ Check_Shell(0);
}
/*
#endif
cdr.Ctrl = rt | (cdr.Ctrl & ~0x3);
- if (rt == 0) {
+ if (rt == 0) {
cdr.ParamP = 0;
cdr.ParamC = 0;
cdr.ResultReady = 0;
unsigned char cdrRead1(void) {
if (cdr.ResultReady) { // && cdr.Ctrl & 0x1) {
- psxHu8(0x1801) = cdr.Result[cdr.ResultP++];
+ // GameShark CDX CD Player: uses 17 bytes output (wraps around)
+ psxHu8(0x1801) = cdr.Result[cdr.ResultP & 0xf];
+ cdr.ResultP++;
if (cdr.ResultP == cdr.ResultC)
cdr.ResultReady = 0;
} else {
#ifdef CDR_LOG
CDR_LOG("cdrWrite1() Log: CD1 write: %x (%s)\n", rt, CmdName[rt]);
#endif
+
+
+ // Tekken: CDXA fade-out
+ if( (cdr.Ctrl & 3) == 3 ) {
+ //cdr.AttenuatorRight[0] = rt;
+ }
+
+
// psxHu8(0x1801) = rt;
- cdr.Cmd = rt;
+ cdr.Cmd = rt;
cdr.OCUP = 0;
#ifdef CDRCMD_DEBUG
if (cdr.Ctrl & 0x1) return;
- switch (cdr.Cmd) {
+ switch (cdr.Cmd) {
case CdlSync:
- cdr.Ctrl |= 0x80;
+ cdr.Ctrl |= 0x80;
cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
+ AddIrqQueue(cdr.Cmd, 0x800);
break;
case CdlNop:
- cdr.Ctrl |= 0x80;
+ cdr.Ctrl |= 0x80;
cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
+
+ // Twisted Metal 3 - fix music
+ AddIrqQueue(cdr.Cmd, 0x800);
break;
case CdlSetloc:
- StopReading();
- cdr.Seeked = FALSE;
- for (i = 0; i < 3; i++)
- cdr.SetSector[i] = btoi(cdr.Param[i]);
+ StopReading();
+ cdr.Seeked = FALSE;
+ for (i = 0; i < 3; i++)
+ cdr.SetSector[i] = btoi(cdr.Param[i]);
cdr.SetSector[3] = 0;
-/* if ((cdr.SetSector[0] | cdr.SetSector[1] | cdr.SetSector[2]) == 0) {
- *(u32 *)cdr.SetSector = *(u32 *)cdr.SetSectorSeek;
- }*/
- cdr.Ctrl |= 0x80;
+
+ /*
+ if ((cdr.SetSector[0] | cdr.SetSector[1] | cdr.SetSector[2]) == 0) {
+ *(u32 *)cdr.SetSector = *(u32 *)cdr.SetSectorSeek;
+ }*/
+
+ cdr.Ctrl |= 0x80;
cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
+ AddIrqQueue(cdr.Cmd, 0x800);
break;
case CdlPlay:
- if (!cdr.SetSector[0] & !cdr.SetSector[1] & !cdr.SetSector[2]) {
- if (CDR_getTN(cdr.ResultTN) != -1) {
- if (cdr.CurTrack > cdr.ResultTN[1])
- cdr.CurTrack = cdr.ResultTN[1];
- if (CDR_getTD((unsigned char)(cdr.CurTrack), cdr.ResultTD) != -1) {
- int tmp = cdr.ResultTD[2];
- cdr.ResultTD[2] = cdr.ResultTD[0];
- cdr.ResultTD[0] = tmp;
- if (!Config.Cdda) CDR_play(cdr.ResultTD);
- }
- }
- } else if (!Config.Cdda) {
- CDR_play(cdr.SetSector);
+ // Vib Ribbon: try same track again
+ StopCdda();
+
+ if (!cdr.SetSector[0] & !cdr.SetSector[1] & !cdr.SetSector[2]) {
+ if (CDR_getTN(cdr.ResultTN) != -1) {
+ if (cdr.CurTrack > cdr.ResultTN[1])
+ cdr.CurTrack = cdr.ResultTN[1];
+ if (CDR_getTD((unsigned char)(cdr.CurTrack), cdr.ResultTD) != -1) {
+ int tmp = cdr.ResultTD[2];
+ cdr.ResultTD[2] = cdr.ResultTD[0];
+ cdr.ResultTD[0] = tmp;
+ if (!Config.Cdda) CDR_play(cdr.ResultTD);
+ }
}
- cdr.Play = TRUE;
- cdr.Ctrl |= 0x80;
- cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
+ } else if (!Config.Cdda) {
+ CDR_play(cdr.SetSector);
+ }
+
+ // Vib Ribbon - decoded buffer IRQ for CDDA reading
+ // - fixes ribbon timing + music CD mode
+ //TODO?
+ //CDRDBUF_INT( PSXCLK / 44100 * 0x100 );
+
+
+ cdr.Play = TRUE;
+
+ cdr.StatP |= STATUS_SEEK;
+ cdr.StatP &= ~STATUS_ROTATING;
+
+ cdr.Ctrl |= 0x80;
+ cdr.Stat = NoIntr;
+ AddIrqQueue(cdr.Cmd, 0x800);
break;
case CdlForward:
- if (cdr.CurTrack < 0xaa)
- cdr.CurTrack++;
- cdr.Ctrl |= 0x80;
+ //if (cdr.CurTrack < 0xaa)
+ // cdr.CurTrack++;
+ cdr.Ctrl |= 0x80;
cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
+ AddIrqQueue(cdr.Cmd, 0x800);
break;
case CdlBackward:
- if (cdr.CurTrack > 1)
- cdr.CurTrack--;
- cdr.Ctrl |= 0x80;
- cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
+ //if (cdr.CurTrack > 1)
+ //cdr.CurTrack--;
+ cdr.Ctrl |= 0x80;
+ cdr.Stat = NoIntr;
+ AddIrqQueue(cdr.Cmd, 0x800);
break;
case CdlReadN:
- cdr.Irq = 0;
- StopReading();
- cdr.Ctrl|= 0x80;
- cdr.Stat = NoIntr;
- StartReading(1, 0x1000);
- break;
+ cdr.Irq = 0;
+ StopReading();
+ cdr.Ctrl|= 0x80;
+ cdr.Stat = NoIntr;
+ StartReading(1, 0x800);
+ break;
case CdlStandby:
- StopCdda();
- StopReading();
- cdr.Ctrl |= 0x80;
- cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
+ StopCdda();
+ StopReading();
+ cdr.Ctrl |= 0x80;
+ cdr.Stat = NoIntr;
+ AddIrqQueue(cdr.Cmd, 0x800);
break;
case CdlStop:
- StopCdda();
- StopReading();
- cdr.Ctrl |= 0x80;
- cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
+ // GameShark CD Player: Reset CDDA to track start
+ 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];
+
+ Find_CurTrack();
+
+
+ // grab time for current track
+ CDR_getTD((u8)(cdr.CurTrack), cdr.ResultTD);
+
+ cdr.SetSectorPlay[0] = cdr.ResultTD[2];
+ cdr.SetSectorPlay[1] = cdr.ResultTD[1];
+ cdr.SetSectorPlay[2] = cdr.ResultTD[0];
+ }
+
+ StopCdda();
+ StopReading();
+
+ cdr.Ctrl |= 0x80;
+ cdr.Stat = NoIntr;
+ AddIrqQueue(cdr.Cmd, 0x800);
break;
case CdlPause:
- StopCdda();
- StopReading();
- cdr.Ctrl |= 0x80;
- cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x80000);
- break;
+ /*
+ 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];
+ }
- case CdlReset:
+ 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);
+ break;
+
+ case CdlReset:
case CdlInit:
- StopCdda();
- StopReading();
- cdr.Ctrl |= 0x80;
- cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
+ StopCdda();
+ StopReading();
+ cdr.Ctrl |= 0x80;
+ cdr.Stat = NoIntr;
+ AddIrqQueue(cdr.Cmd, 0x800);
break;
case CdlMute:
cdr.Muted = TRUE;
- cdr.Ctrl |= 0x80;
+ cdr.Ctrl |= 0x80;
cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
+ AddIrqQueue(cdr.Cmd, 0x800);
+
+ // Duke Nukem - Time to Kill
+ // - do not directly set cd-xa volume
+ //SPU_writeRegister( H_CDLeft, 0x0000 );
+ //SPU_writeRegister( H_CDRight, 0x0000 );
break;
case CdlDemute:
cdr.Muted = FALSE;
- cdr.Ctrl |= 0x80;
+ cdr.Ctrl |= 0x80;
cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
+ AddIrqQueue(cdr.Cmd, 0x800);
+
+ // Duke Nukem - Time to Kill
+ // - do not directly set cd-xa volume
+ //SPU_writeRegister( H_CDLeft, 0x7f00 );
+ //SPU_writeRegister( H_CDRight, 0x7f00 );
break;
case CdlSetfilter:
cdr.File = cdr.Param[0];
cdr.Channel = cdr.Param[1];
- cdr.Ctrl |= 0x80;
+ cdr.Ctrl |= 0x80;
cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
+ AddIrqQueue(cdr.Cmd, 0x800);
break;
case CdlSetmode:
#ifdef CDR_LOG
- CDR_LOG("cdrWrite1() Log: Setmode %x\n", cdr.Param[0]);
+ CDR_LOG("cdrWrite1() Log: Setmode %x\n", cdr.Param[0]);
#endif
cdr.Mode = cdr.Param[0];
- cdr.Ctrl |= 0x80;
+ cdr.Ctrl |= 0x80;
cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
+ AddIrqQueue(cdr.Cmd, 0x800);
+
+ // Squaresoft on PlayStation 1998 Collector's CD Vol. 1
+ // - fixes choppy movie sound
+ if( cdr.Play && (cdr.Mode & MODE_CDDA) == 0 )
+ StopCdda();
break;
case CdlGetmode:
- cdr.Ctrl |= 0x80;
+ cdr.Ctrl |= 0x80;
cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
+ AddIrqQueue(cdr.Cmd, 0x800);
break;
case CdlGetlocL:
- cdr.Ctrl |= 0x80;
- cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
- break;
+ cdr.Ctrl |= 0x80;
+ cdr.Stat = NoIntr;
+
+ // Crusaders of Might and Magic - cutscene speech
+ AddIrqQueue(cdr.Cmd, 0x800);
+ break;
case CdlGetlocP:
- cdr.Ctrl |= 0x80;
- cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
+ cdr.Ctrl |= 0x80;
+ cdr.Stat = NoIntr;
+
+ // GameShark CDX / Lite Player: pretty narrow time window
+ // - doesn't always work due to time inprecision
+ //AddIrqQueue(cdr.Cmd, 0x28);
+
+ // Tomb Raider 2 - cdda
+ AddIrqQueue(cdr.Cmd, 0x40);
break;
case CdlGetTN:
- cdr.Ctrl |= 0x80;
- cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
- break;
+ cdr.Ctrl |= 0x80;
+ cdr.Stat = NoIntr;
+ //AddIrqQueue(cdr.Cmd, 0x800);
+
+ // GameShark CDX CD Player: very long time
+ AddIrqQueue(cdr.Cmd, 0x100000);
+ break;
case CdlGetTD:
- cdr.Ctrl |= 0x80;
+ cdr.Ctrl |= 0x80;
cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
+ AddIrqQueue(cdr.Cmd, 0x800);
break;
case CdlSeekL:
// ((u32 *)cdr.SetSectorSeek)[0] = ((u32 *)cdr.SetSector)[0];
- cdr.Ctrl |= 0x80;
- cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
- break;
+ cdr.Ctrl |= 0x80;
+ cdr.Stat = NoIntr;
+ AddIrqQueue(cdr.Cmd, 0x800);
+
+ StopCdda();
+ StopReading();
+
+ break;
case CdlSeekP:
// ((u32 *)cdr.SetSectorSeek)[0] = ((u32 *)cdr.SetSector)[0];
- cdr.Ctrl |= 0x80;
+ cdr.Ctrl |= 0x80;
cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
+
+ // Tomb Raider 2 - reset cdda
+ StopCdda();
+ StopReading();
+
+ AddIrqQueue(cdr.Cmd, 0x800);
break;
+ // Destruction Derby: read TOC? GetTD after this
+ case CdlReadT:
+ cdr.Ctrl |= 0x80;
+ cdr.Stat = NoIntr;
+ AddIrqQueue(cdr.Cmd, 0x800);
+ break;
+
case CdlTest:
- cdr.Ctrl |= 0x80;
+ cdr.Ctrl |= 0x80;
cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
+ AddIrqQueue(cdr.Cmd, 0x800);
break;
case CdlID:
- cdr.Ctrl |= 0x80;
+ cdr.Ctrl |= 0x80;
cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
+ AddIrqQueue(cdr.Cmd, 0x800);
break;
case CdlReadS:
- cdr.Irq = 0;
- StopReading();
- cdr.Ctrl |= 0x80;
- cdr.Stat = NoIntr;
- StartReading(2, 0x1000);
- break;
+ cdr.Irq = 0;
+ StopReading();
+ cdr.Ctrl |= 0x80;
+ cdr.Stat = NoIntr;
+ StartReading(2, 0x800);
+ break;
case CdlReadToc:
- cdr.Ctrl |= 0x80;
+ cdr.Ctrl |= 0x80;
cdr.Stat = NoIntr;
- AddIrqQueue(cdr.Cmd, 0x1000);
+ AddIrqQueue(cdr.Cmd, 0x800);
break;
default:
#ifdef CDR_LOG
- CDR_LOG("cdrWrite1() Log: Unknown command: %x\n", cdr.Cmd);
+ CDR_LOG("cdrWrite1() Log: Unknown command: %x\n", cdr.Cmd);
#endif
- return;
- }
+ return;
+ }
if (cdr.Stat != NoIntr) {
psxHu32ref(0x1070) |= SWAP32((u32)0x4);
}
#ifdef CDR_LOG
CDR_LOG("cdrWrite2() Log: CD2 write: %x\n", rt);
#endif
- if (cdr.Ctrl & 0x1) {
+
+ // Tekken: CDXA fade-out
+ if( (cdr.Ctrl & 3) == 2 ) {
+ //cdr.AttenuatorLeft[0] = rt;
+ }
+ else if( (cdr.Ctrl & 3) == 3 ) {
+ //cdr.AttenuatorRight[1] = rt;
+ }
+
+
+ if (cdr.Ctrl & 0x1) {
switch (rt) {
case 0x07:
- cdr.ParamP = 0;
+ cdr.ParamP = 0;
cdr.ParamC = 0;
cdr.ResultReady = 1; //0;
cdr.Ctrl &= ~3; //cdr.Ctrl = 0;
cdr.Reg2 = rt;
break;
}
- } else if (!(cdr.Ctrl & 0x1) && cdr.ParamP < 8) {
+ } else if (!(cdr.Ctrl & 0x1) && cdr.ParamP < 8) {
cdr.Param[cdr.ParamP++] = rt;
cdr.ParamC++;
}
#ifdef CDR_LOG
CDR_LOG("cdrWrite3() Log: CD3 write: %x\n", rt);
#endif
- if (rt == 0x07 && cdr.Ctrl & 0x1) {
+/*
+ // Tekken: CDXA fade-out
+ if( (cdr.Ctrl & 3) == 2 ) {
+ cdr.AttenuatorLeft[1] = rt;
+ }
+ else if( (cdr.Ctrl & 3) == 3 && rt == 0x20 ) {
+#ifdef CDR_LOG
+ CDR_LOG( "CD-XA Volume: %X %X | %X %X\n",
+ cdr.AttenuatorLeft[0], cdr.AttenuatorLeft[1],
+ cdr.AttenuatorRight[0], cdr.AttenuatorRight[1] );
+#endif
+ }
+*/
+
+ // GameShark CDX CD Player: Irq timing mania
+ if( rt == 0 &&
+ cdr.Irq != 0 && cdr.Irq != 0xff &&
+ cdr.ResultReady == 0 ) {
+
+ // GS CDX: ~0x28 cycle timing - way too precise
+ if( cdr.Irq == CdlGetlocP ) {
+ cdrInterrupt();
+
+ psxRegs.interrupt &= ~(1 << PSXINT_CDR);
+ }
+ }
+
+
+ if (rt == 0x07 && cdr.Ctrl & 0x1) {
cdr.Stat = 0;
if (cdr.Irq == 0xff) {
cdr.Irq = 0;
return;
}
- if (cdr.Irq)
- CDR_INT(cdr.eCycle);
- if (cdr.Reading && !cdr.ResultReady)
- CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime);
+
+ if (cdr.Reading && !cdr.ResultReady) {
+ CDREAD_INT((cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime);
+ }
return;
}
+
if (rt == 0x80 && !(cdr.Ctrl & 0x1) && cdr.Readed == 0) {
cdr.Readed = 1;
cdr.pTransfer = cdr.Transfer;
switch (cdr.Mode & 0x30) {
- case 0x10:
+ case MODE_SIZE_2328:
case 0x00:
cdr.pTransfer += 12;
break;
+
+ case MODE_SIZE_2340:
+ cdr.pTransfer += 0;
+ break;
+
default:
break;
}
cdsize = (bcr & 0xffff) * 4;
+ // Ape Escape: bcr = 0001 / 0000
+ // - fix boot
+ if( cdsize == 0 )
+ {
+ switch (cdr.Mode & 0x30) {
+ case 0x00: cdsize = 2048; break;
+ case MODE_SIZE_2328: cdsize = 2328; break;
+ case MODE_SIZE_2340: cdsize = 2340; break;
+ }
+ }
+
+
ptr = (u8 *)PSXM(madr);
if (ptr == NULL) {
#ifdef CPU_LOG
#endif
break;
}
- memcpy(ptr, cdr.pTransfer, cdsize);
+
+ /*
+ GS CDX: Enhancement CD crash
+ - Setloc 0:0:0
+ - 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
+ {
+ memcpy(ptr, cdr.pTransfer, cdsize);
+ }
+
psxCpu->Clear(madr, cdsize / 4);
cdr.pTransfer += cdsize;
- break;
+
+
+ // burst vs normal
+ if( chcr == 0x11400100 ) {
+ CDRDMA_INT( (cdsize/4) / 4 );
+ }
+ else if( chcr == 0x11000000 ) {
+ CDRDMA_INT( (cdsize/4) * 1 );
+ }
+ return;
+
default:
#ifdef CDR_LOG
CDR_LOG("psxDma3() Log: Unknown cddma %x\n", chcr);
DMA_INTERRUPT(3);
}
+void cdrDmaInterrupt()
+{
+ HW_DMA3_CHCR &= SWAP32(~0x01000000);
+ DMA_INTERRUPT(3);
+}
+
void cdrReset() {
memset(&cdr, 0, sizeof(cdr));
cdr.CurTrack = 1;
cdr.File = 1;
cdr.Channel = 1;
- memset(&stat, 0, sizeof(stat));
}
int cdrFreeze(gzFile f, int Mode) {
uintptr_t tmp;
- gzfreeze(&cdr, sizeof(cdr));
+ if( Mode == 0 ) {
+ StopCdda();
+ }
+
+ gzfreeze(&cdr, sizeof(cdr));
+
if (Mode == 1)
tmp = cdr.pTransfer - cdr.Transfer;
return 0;
}
+
+void LidInterrupt() {
+ cdr.LidCheck = 0x20; // start checker
+
+ CDRLID_INT( cdReadTime * 3 );
+
+ // generate interrupt if none active - open or close
+ if (cdr.Irq == 0 || cdr.Irq == 0xff) {
+ cdr.Ctrl |= 0x80;
+ cdr.Stat = NoIntr;
+ AddIrqQueue(CdlNop, 0x800);
+ }
+}