#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_SIZE_2048 (0<<4) // 0x00
#define MODE_SF (1<<3) // 0x08 channel on/off
#define MODE_REPORT (1<<2) // 0x04
#define MODE_AUTOPAUSE (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)
#define cdReadTime (PSXCLK / 75)
+enum drive_state {
+ DRIVESTATE_STANDBY = 0,
+ DRIVESTATE_LID_OPEN,
+ DRIVESTATE_RESCAN_CD,
+ DRIVESTATE_PREPARE_CD,
+};
+
// for cdr.Seeked
enum seeked_state {
SEEK_PENDING = 0,
psxHu32ref(0x1070) |= SWAP32((u32)0x4);
}
+// timing used in this function was taken from tests on real hardware
+// (yes it's slow, but you probably don't want to modify it)
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)
+ switch (cdr.DriveState) {
+ default:
+ case DRIVESTATE_STANDBY:
cdr.StatP &= ~STATUS_SEEK;
- cdr.LidCheck = 0;
- }
-}
-
-static void Check_Shell( int Irq )
-{
- // check case open/close
- if (cdr.LidCheck > 0)
- {
- CDR_LOG( "LidCheck\n" );
+ if (CDR_getStatus(&stat) == -1)
+ return;
- // $20 = check lid state
- if( cdr.LidCheck == 0x20 )
+ if (stat.Status & STATUS_SHELLOPEN)
{
- u32 i;
-
- i = stat.Status;
- if (CDR_getStatus(&stat) != -1)
- {
- // BIOS hangs + BIOS error messages
- //if (stat.Type == 0xff)
- //cdr.Stat = DiskError;
-
- // case now open
- 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;
-
- setIrq();
+ StopCdda();
+ cdr.DriveState = DRIVESTATE_LID_OPEN;
+ CDRLID_INT(0x800);
+ }
+ break;
- // begin close-seek-ready cycle
- CDRLID_INT( cdReadTime * 3 );
- cdr.LidCheck = 0x30;
+ case DRIVESTATE_LID_OPEN:
+ if (CDR_getStatus(&stat) == -1)
+ stat.Status &= ~STATUS_SHELLOPEN;
+ // 02, 12, 10
+ if (!(cdr.StatP & STATUS_SHELLOPEN)) {
+ StopReading();
+ cdr.StatP |= STATUS_SHELLOPEN;
- // GameShark Lite: Wants -exactly- $42, then $02
- // GS CDX 3.3: Wants $11/$80, $13/$80, $01/$00
- }
+ // could generate error irq here, but real hardware
+ // only sometimes does that
+ // (not done when lots of commands are sent?)
- // case still closed - wait for recheck
- else
- {
- CDRLID_INT( cdReadTime * 3 );
- cdr.LidCheck = 0x10;
- }
- }
+ CDRLID_INT(cdReadTime * 30);
+ break;
}
+ else if (cdr.StatP & STATUS_ROTATING) {
+ cdr.StatP &= ~STATUS_ROTATING;
+ }
+ else if (!(stat.Status & STATUS_SHELLOPEN)) {
+ // closed now
+ CheckCdrom();
+ // cdr.StatP STATUS_SHELLOPEN is "sticky"
+ // and is only cleared by CdlNop
- // 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;
+ cdr.DriveState = DRIVESTATE_RESCAN_CD;
+ CDRLID_INT(cdReadTime * 105);
+ break;
+ }
+ // recheck for close
+ CDRLID_INT(cdReadTime * 3);
+ break;
- // GS CDX: special return value
- if( cdr.StatP & STATUS_SHELLOPEN )
- {
- cdr.Result[1] = 0x80;
- }
+ case DRIVESTATE_RESCAN_CD:
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.DriveState = DRIVESTATE_PREPARE_CD;
+ // this is very long on real hardware, over 6 seconds
+ // make it a bit faster here...
+ CDRLID_INT(cdReadTime * 150);
+ break;
- if( cdr.Stat == NoIntr )
- cdr.Stat = Acknowledge;
+ case DRIVESTATE_PREPARE_CD:
+ cdr.StatP |= STATUS_SEEK;
- setIrq();
- }
+ cdr.DriveState = DRIVESTATE_STANDBY;
+ CDRLID_INT(cdReadTime * 26);
+ break;
}
}
SetResultSize(1);
cdr.StatP |= STATUS_ROTATING;
cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
+ cdr.Stat = Acknowledge;
break;
case CdlNop:
cdr.Result[0] = cdr.StatP;
cdr.Stat = Acknowledge;
- if (cdr.LidCheck == 0) cdr.LidCheck = 0x20;
+ if (cdr.DriveState != DRIVESTATE_LID_OPEN)
+ cdr.StatP &= ~STATUS_SHELLOPEN;
break;
case CdlSetloc:
cdr.Result[0] = cdr.StatP;
cdr.Stat = Complete;
// cdr.Stat = Acknowledge;
-
- if (cdr.LidCheck == 0) cdr.LidCheck = 0x20;
break;
case CdlPause:
break;
case CdlGetTN:
- // 5-Star Racing: don't stop CDDA
- //
- // Vib Ribbon: CD swap
- StopReading();
-
cdr.CmdProcess = 0;
SetResultSize(3);
cdr.StatP |= STATUS_ROTATING;
case CdlID + 0x20:
SetResultSize(8);
+ cdr.Result[0] = cdr.StatP;
+ cdr.Result[1] = 0;
+ cdr.Result[2] = 0;
+ cdr.Result[3] = 0;
- 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
+ // 0x10 - audio | 0x40 - disk missing | 0x80 - unlicensed
+ if (CDR_getStatus(&stat) == -1 || stat.Type == 0 || stat.Type == 0xff) {
+ cdr.Result[1] = 0xc0;
}
else {
- if (stat.Type == 2) {
- // Music CD
- cdr.Result[0] = 0x08;
- cdr.Result[1] = 0x10;
-
+ if (stat.Type == 2)
+ cdr.Result[1] |= 0x10;
+ if (CdromId[0] == '\0')
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[0] |= (cdr.Result[1] >> 4) & 0x08;
- cdr.Result[2] = 0x00;
- cdr.Result[3] = 0x00;
strncpy((char *)&cdr.Result[4], "PCSX", 4);
cdr.Stat = Complete;
break;
cdr.StatP |= STATUS_ROTATING;
cdr.Result[0] = cdr.StatP;
cdr.Stat = Acknowledge;
- AddIrqQueue(CdlReadToc + 0x20, 0x800);
+ AddIrqQueue(CdlReadToc + 0x20, cdReadTime * 16);
break;
case CdlReadToc + 0x20:
break;
}
- Check_Shell( Irq );
+ if (Irq != CdlNop) {
+ switch (cdr.DriveState) {
+ case DRIVESTATE_LID_OPEN:
+ case DRIVESTATE_RESCAN_CD:
+ case DRIVESTATE_PREPARE_CD:
+ SetResultSize(2);
+ cdr.Result[0] = cdr.StatP | STATUS_ERROR;
+ cdr.Result[1] = 0x80;
+ cdr.Stat = DiskError;
+ break;
+ }
+ }
cdr.ParamC = 0;
setIrq();
#ifdef CDR_LOG_CMD_IRQ
- SysPrintf("cdrInterrupt() Log: CDR Interrupt IRQ %d %02x: ",
- cdr.Stat != NoIntr && cdr.Reg2 != 0x18, Irq);
+ SysPrintf("IRQ %d cmd %02x stat %02x: ",
+ !!(cdr.Stat & cdr.Reg2), Irq, cdr.Stat);
for (i = 0; i < cdr.ResultC; i++)
SysPrintf("%02x ", cdr.Result[i]);
SysPrintf("\n");
cdr.Channel = cdr.Transfer[4 + 1];
}
- if ((cdr.Transfer[4 + 2] & 0x4) &&
+ if((cdr.Transfer[4 + 2] & 0x4) &&
(cdr.Transfer[4 + 1] == cdr.Channel) &&
- (cdr.Transfer[4 + 0] == cdr.File)) {
+ (cdr.Transfer[4 + 0] == cdr.File)) {
int ret = xa_decode_sector(&cdr.Xa, cdr.Transfer+4, cdr.FirstSector);
if (!ret) {
-
cdrAttenuate(cdr.Xa.pcm, cdr.Xa.nsamples, cdr.Xa.stereo);
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
- setIrq();
-#endif
}
else cdr.FirstSector = -1;
}
// update for CdlGetlocP
ReadTrack(cdr.SetSector);
-
- Check_Shell(0);
}
/*
cdr.OCUP = 0;
#ifdef CDR_LOG_CMD_IRQ
- SysPrintf("cdrWrite1() Log: CD1 write: %x (%s)", rt, CmdName[rt]);
+ SysPrintf("CD1 write: %x (%s)", rt, CmdName[rt]);
if (cdr.ParamC) {
SysPrintf(" Param[%d] = {", cdr.ParamC);
for (i = 0; i < cdr.ParamC; i++)
// Vib Ribbon: try same track again
StopCdda();
-#if 0
- 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);
- }
- }
- }
-#endif
// Vib Ribbon - decoded buffer IRQ for CDDA reading
// - fixes ribbon timing + music CD mode
- //TODO?
//CDRDBUF_INT( PSXCLK / 44100 * 0x100 );
cdr.Play = TRUE;
// - fix boot
if( cdsize == 0 )
{
- switch (cdr.Mode & 0x30) {
- case 0x00: cdsize = 2048; break;
- case MODE_SIZE_2328: cdsize = 2328; break;
+ switch (cdr.Mode & (MODE_SIZE_2340|MODE_SIZE_2328)) {
case MODE_SIZE_2340: cdsize = 2340; break;
+ case MODE_SIZE_2328: cdsize = 2328; break;
+ default:
+ case MODE_SIZE_2048: cdsize = 2048; break;
}
}
cdr.CurTrack = 1;
cdr.File = 1;
cdr.Channel = 1;
+ cdr.Reg2 = 0x1f;
+ cdr.Stat = NoIntr;
+ cdr.DriveState = DRIVESTATE_STANDBY;
pTransfer = cdr.Transfer;
// BIOS player - default values
}
void LidInterrupt() {
- cdr.LidCheck = 0x20; // start checker
-
getCdInfo();
-
StopCdda();
- 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);
- }
+ cdrLidSeekInterrupt();
}