summaryrefslogtreecommitdiff
path: root/libpcsxcore/cdrom.c
diff options
context:
space:
mode:
authorSND\notaz_cp <SND\notaz_cp@e17a0e51-4ae3-4d35-97c3-1a29b211df97>2013-01-19 00:34:51 +0000
committerSND\notaz_cp <SND\notaz_cp@e17a0e51-4ae3-4d35-97c3-1a29b211df97>2013-01-19 00:34:51 +0000
commite81dceb242a12650a4b259b3cbdc35a9155c9c9e (patch)
treebb79c8ccec91b14965e2c2bb737c6a700a36b8df /libpcsxcore/cdrom.c
parentfeb042205d6bdb61ac240f26992d517dad75b055 (diff)
cdrom: cleanup, support errors, improve timing
most changes verified on real thing git-svn-id: https://pcsxr.svn.codeplex.com/svn/pcsxr@82377 e17a0e51-4ae3-4d35-97c3-1a29b211df97
Diffstat (limited to 'libpcsxcore/cdrom.c')
-rwxr-xr-xlibpcsxcore/cdrom.c260
1 files changed, 121 insertions, 139 deletions
diff --git a/libpcsxcore/cdrom.c b/libpcsxcore/cdrom.c
index 43cdbd4e..94d4fbc2 100755
--- a/libpcsxcore/cdrom.c
+++ b/libpcsxcore/cdrom.c
@@ -75,6 +75,7 @@ cdrStruct cdr;
#define CdlID 26
#define CdlReadS 27
#define CdlReset 28
+#define CdlGetQ 29
#define CdlReadToc 30
char *CmdName[0x100]= {
@@ -123,6 +124,10 @@ unsigned char Test23[] = { 0x43, 0x58, 0x44, 0x32, 0x39 ,0x34, 0x30, 0x51 };
#define STATUS_ROTATING (1<<1) // 0x02
#define STATUS_ERROR (1<<0) // 0x01
+/* Errors */
+#define ERROR_NOT_READY (1<<7) // 0x80
+#define ERROR_INVALIDCMD (1<<6) // 0x40
+#define ERROR_INVALIDARG (1<<5) // 0x20
// 1x = 75 sectors per second
// PSXCLK = 1 sec in the ps
@@ -134,6 +139,7 @@ enum drive_state {
DRIVESTATE_LID_OPEN,
DRIVESTATE_RESCAN_CD,
DRIVESTATE_PREPARE_CD,
+ DRIVESTATE_STOPPED,
};
// for cdr.Seeked
@@ -483,9 +489,16 @@ static void ReadTrack(const u8 *time) {
cdr.subq.Absolute[0], cdr.subq.Absolute[1], cdr.subq.Absolute[2]);
}
-static void AddIrqQueue(unsigned char irq, unsigned long ecycle) {
- if (cdr.Irq != 0)
+static void AddIrqQueue(unsigned short irq, unsigned long ecycle) {
+ if (cdr.Irq != 0) {
+ if (irq == cdr.Irq || irq + 0x100 == cdr.Irq) {
+ cdr.IrqRepeated = 1;
+ CDR_INT(ecycle);
+ return;
+ }
+
CDR_LOG_I("cdr: override cmd %02x -> %02x\n", cdr.Irq, irq);
+ }
cdr.Irq = irq;
cdr.eCycle = ecycle;
@@ -603,8 +616,11 @@ void cdrPlayInterrupt()
}
void cdrInterrupt() {
- int i;
- unsigned char Irq = cdr.Irq;
+ u16 Irq = cdr.Irq;
+ int no_busy_error = 0;
+ int start_rotating = 0;
+ int error = 0;
+ int delay;
// Reschedule IRQ
if (cdr.Stat) {
@@ -612,32 +628,35 @@ void cdrInterrupt() {
return;
}
- cdr.Irq = 0;
cdr.Ctrl &= ~0x80;
+ // default response
+ SetResultSize(1);
+ cdr.Result[0] = cdr.StatP;
+ cdr.Stat = Acknowledge;
+
+ if (cdr.IrqRepeated) {
+ cdr.IrqRepeated = 0;
+ if (cdr.eCycle > psxRegs.cycle) {
+ CDR_INT(cdr.eCycle);
+ goto finish;
+ }
+ }
+
+ cdr.Irq = 0;
+
switch (Irq) {
case CdlSync:
- SetResultSize(1);
- cdr.StatP |= STATUS_ROTATING;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
+ // TOOD: sometimes/always return error?
break;
case CdlNop:
- SetResultSize(1);
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
-
if (cdr.DriveState != DRIVESTATE_LID_OPEN)
cdr.StatP &= ~STATUS_SHELLOPEN;
+ no_busy_error = 1;
break;
case CdlSetloc:
- cdr.CmdProcess = 0;
- SetResultSize(1);
- cdr.StatP |= STATUS_ROTATING;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
break;
case CdlPlay:
@@ -689,30 +708,21 @@ void cdrInterrupt() {
// Vib Ribbon: gameplay checks flag
cdr.StatP &= ~STATUS_SEEK;
-
- cdr.CmdProcess = 0;
- SetResultSize(1);
- cdr.StatP |= STATUS_ROTATING;
cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
cdr.StatP |= STATUS_PLAY;
-
// BIOS player - set flag again
cdr.Play = TRUE;
CDRMISC_INT( cdReadTime );
+ start_rotating = 1;
break;
case CdlForward:
- cdr.CmdProcess = 0;
- SetResultSize(1);
- cdr.StatP |= STATUS_ROTATING;
- cdr.Result[0] = cdr.StatP;
+ // TODO: error 80 if stopped
cdr.Stat = Complete;
-
// GameShark CD Player: Calls 2x + Play 2x
if( cdr.FastForward == 0 ) cdr.FastForward = 2;
else cdr.FastForward++;
@@ -721,13 +731,8 @@ void cdrInterrupt() {
break;
case CdlBackward:
- cdr.CmdProcess = 0;
- SetResultSize(1);
- 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++;
@@ -736,27 +741,34 @@ void cdrInterrupt() {
break;
case CdlStandby:
- cdr.CmdProcess = 0;
- SetResultSize(1);
- cdr.StatP |= STATUS_ROTATING;
- cdr.Result[0] = cdr.StatP;
+ if (cdr.DriveState != DRIVESTATE_STOPPED) {
+ error = ERROR_INVALIDARG;
+ goto set_error;
+ }
+ AddIrqQueue(CdlStandby + 0x100, cdReadTime * 125 / 2);
+ start_rotating = 1;
+ break;
+
+ case CdlStandby + 0x100:
cdr.Stat = Complete;
break;
case CdlStop:
- cdr.CmdProcess = 0;
- SetResultSize(1);
+ delay = 0x800;
+ if (cdr.DriveState == DRIVESTATE_STANDBY)
+ delay = cdReadTime * 30 / 2;
+
+ cdr.DriveState = DRIVESTATE_STOPPED;
+ AddIrqQueue(CdlStop + 0x100, delay);
+ break;
+
+ case CdlStop + 0x100:
cdr.StatP &= ~STATUS_ROTATING;
cdr.Result[0] = cdr.StatP;
cdr.Stat = Complete;
-// cdr.Stat = Acknowledge;
break;
case CdlPause:
- SetResultSize(1);
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
-
/*
Gundam Battle Assault 2: much slower (*)
- Fixes boot, gameplay
@@ -767,80 +779,52 @@ void cdrInterrupt() {
InuYasha - Feudal Fairy Tale: slower
- Fixes battles
*/
- AddIrqQueue(CdlPause + 0x20, cdReadTime * 3);
+ AddIrqQueue(CdlPause + 0x100, cdReadTime * 3);
cdr.Ctrl |= 0x80;
break;
- case CdlPause + 0x20:
- SetResultSize(1);
+ case CdlPause + 0x100:
cdr.StatP &= ~STATUS_READ;
- cdr.StatP |= STATUS_ROTATING;
cdr.Result[0] = cdr.StatP;
cdr.Stat = Complete;
break;
case CdlInit:
- SetResultSize(1);
- cdr.StatP = STATUS_ROTATING;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
-// if (!cdr.Init) {
- AddIrqQueue(CdlInit + 0x20, 0x800);
-// }
- break;
+ AddIrqQueue(CdlInit + 0x100, cdReadTime * 6);
+ no_busy_error = 1;
+ start_rotating = 1;
+ break;
- case CdlInit + 0x20:
- SetResultSize(1);
- cdr.Result[0] = cdr.StatP;
+ case CdlInit + 0x100:
cdr.Stat = Complete;
- cdr.Init = 1;
break;
case CdlMute:
- SetResultSize(1);
- cdr.StatP |= STATUS_ROTATING;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
break;
case CdlDemute:
- SetResultSize(1);
- cdr.StatP |= STATUS_ROTATING;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
break;
case CdlSetfilter:
- SetResultSize(1);
- cdr.StatP |= STATUS_ROTATING;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
break;
case CdlSetmode:
- SetResultSize(1);
- cdr.StatP |= STATUS_ROTATING;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
+ no_busy_error = 1;
break;
case CdlGetmode:
SetResultSize(6);
- 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;
+ no_busy_error = 1;
break;
case CdlGetlocL:
SetResultSize(8);
- for (i = 0; i < 8; i++)
- cdr.Result[i] = cdr.Transfer[i];
- cdr.Stat = Acknowledge;
+ memcpy(cdr.Result, cdr.Transfer, 8);
break;
case CdlGetlocP:
@@ -849,15 +833,20 @@ void cdrInterrupt() {
if (!cdr.Play && !cdr.Reading)
cdr.Result[1] = 0; // HACK?
+ break;
- cdr.Stat = Acknowledge;
+ case CdlReadT: // SetSession?
+ // really long
+ AddIrqQueue(CdlReadT + 0x100, cdReadTime * 290 / 4);
+ start_rotating = 1;
+ break;
+
+ case CdlReadT + 0x100:
+ cdr.Stat = Complete;
break;
case CdlGetTN:
- cdr.CmdProcess = 0;
SetResultSize(3);
- cdr.StatP |= STATUS_ROTATING;
- cdr.Result[0] = cdr.StatP;
if (CDR_getTN(cdr.ResultTN) == -1) {
cdr.Stat = DiskError;
cdr.Result[0] |= STATUS_ERROR;
@@ -869,10 +858,8 @@ void cdrInterrupt() {
break;
case CdlGetTD:
- cdr.CmdProcess = 0;
cdr.Track = btoi(cdr.Param[0]);
SetResultSize(4);
- cdr.StatP |= STATUS_ROTATING;
if (CDR_getTD(cdr.Track, cdr.ResultTD) == -1) {
cdr.Stat = DiskError;
cdr.Result[0] |= STATUS_ERROR;
@@ -887,11 +874,7 @@ void cdrInterrupt() {
case CdlSeekL:
case CdlSeekP:
- SetResultSize(1);
- cdr.StatP |= STATUS_ROTATING;
- cdr.Result[0] = cdr.StatP;
cdr.StatP |= STATUS_SEEK;
- cdr.Stat = Acknowledge;
/*
Crusaders of Might and Magic = 0.5x-4x
@@ -908,10 +891,10 @@ void cdrInterrupt() {
*/
CDRMISC_INT(cdr.Seeked == SEEK_DONE ? 0x800 : cdReadTime * 4);
cdr.Seeked = SEEK_PENDING;
+ start_rotating = 1;
break;
case CdlTest:
- cdr.Stat = Acknowledge;
switch (cdr.Param[0]) {
case 0x20: // System Controller ROM Version
SetResultSize(4);
@@ -926,17 +909,14 @@ void cdrInterrupt() {
memcpy(cdr.Result, Test23, 4);
break;
}
+ no_busy_error = 1;
break;
case CdlID:
- SetResultSize(1);
- cdr.StatP |= STATUS_ROTATING;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
- AddIrqQueue(CdlID + 0x20, 0x800);
+ AddIrqQueue(CdlID + 0x100, 20480);
break;
- case CdlID + 0x20:
+ case CdlID + 0x100:
SetResultSize(8);
cdr.Result[0] = cdr.StatP;
cdr.Result[1] = 0;
@@ -960,40 +940,28 @@ void cdrInterrupt() {
break;
case CdlReset:
- SetResultSize(1);
- cdr.StatP = STATUS_ROTATING;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
+ // yes, it really sets STATUS_SHELLOPEN
+ cdr.StatP |= STATUS_SHELLOPEN;
+ cdr.DriveState = DRIVESTATE_RESCAN_CD;
+ CDRLID_INT(20480);
+ no_busy_error = 1;
+ start_rotating = 1;
break;
- 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;
+ case CdlGetQ:
+ // TODO?
+ CDR_LOG_I("got CdlGetQ\n");
break;
case CdlReadToc:
- SetResultSize(1);
- cdr.StatP |= STATUS_ROTATING;
- cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
- AddIrqQueue(CdlReadToc + 0x20, cdReadTime * 16);
+ AddIrqQueue(CdlReadToc + 0x100, cdReadTime * 180 / 4);
+ no_busy_error = 1;
+ start_rotating = 1;
break;
- case CdlReadToc + 0x20:
- SetResultSize(1);
- cdr.StatP |= STATUS_ROTATING;
- cdr.Result[0] = cdr.StatP;
+ case CdlReadToc + 0x100:
cdr.Stat = Complete;
+ no_busy_error = 1;
break;
case CdlReadN:
@@ -1036,40 +1004,54 @@ void cdrInterrupt() {
CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime) : cdReadTime * 2);
}
- SetResultSize(1);
- cdr.StatP |= STATUS_ROTATING;
cdr.Result[0] = cdr.StatP;
- cdr.Stat = Acknowledge;
+ start_rotating = 1;
break;
default:
- cdr.Stat = Complete;
+ CDR_LOG_I("Invalid command: %02x\n", Irq);
+ error = ERROR_INVALIDCMD;
+ // FALLTHROUGH
+
+ set_error:
+ SetResultSize(2);
+ cdr.Result[0] = cdr.StatP | STATUS_ERROR;
+ cdr.Result[1] = error;
+ cdr.Stat = DiskError;
break;
}
- if (Irq != CdlNop) {
+ if (cdr.DriveState == DRIVESTATE_STOPPED && start_rotating) {
+ cdr.DriveState = DRIVESTATE_STANDBY;
+ cdr.StatP |= STATUS_ROTATING;
+ }
+
+ if (!no_busy_error) {
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.Result[1] = ERROR_NOT_READY;
cdr.Stat = DiskError;
break;
}
}
- cdr.ParamC = 0;
-
+finish:
setIrq();
+ cdr.ParamC = 0;
#ifdef CDR_LOG_CMD_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");
+ {
+ int i;
+ SysPrintf("CDR 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");
+ }
#endif
}