static unsigned char *pTransfer;
/* CD-ROM magic numbers */
-#define CdlSync 0
+#define CdlSync 0 /* nocash documentation : "Uh, actually, returns error code 40h = Invalid Command...?" */
#define CdlNop 1
#define CdlSetloc 2
#define CdlPlay 3
#define CdlStandby 7
#define CdlStop 8
#define CdlPause 9
-#define CdlInit 10
+#define CdlReset 10
#define CdlMute 11
#define CdlDemute 12
#define CdlSetfilter 13
#define CdlSetmode 14
-#define CdlGetmode 15
+#define CdlGetparam 15
#define CdlGetlocL 16
#define CdlGetlocP 17
#define CdlReadT 18
#define CdlTest 25
#define CdlID 26
#define CdlReadS 27
-#define CdlReset 28
+#define CdlInit 28
#define CdlGetQ 29
#define CdlReadToc 30
char *CmdName[0x100]= {
"CdlSync", "CdlNop", "CdlSetloc", "CdlPlay",
"CdlForward", "CdlBackward", "CdlReadN", "CdlStandby",
- "CdlStop", "CdlPause", "CdlInit", "CdlMute",
- "CdlDemute", "CdlSetfilter", "CdlSetmode", "CdlGetmode",
+ "CdlStop", "CdlPause", "CdlReset", "CdlMute",
+ "CdlDemute", "CdlSetfilter", "CdlSetmode", "CdlGetparam",
"CdlGetlocL", "CdlGetlocP", "CdlReadT", "CdlGetTN",
"CdlGetTD", "CdlSeekL", "CdlSeekP", "CdlSetclock",
"CdlGetclock", "CdlTest", "CdlID", "CdlReadS",
- "CdlReset", NULL, "CDlReadToc", NULL
+ "CdlInit", NULL, "CDlReadToc", NULL
};
unsigned char Test04[] = { 0 };
StopCdda();
}
- else if (cdr.Mode & MODE_REPORT) {
+ else if (((cdr.Mode & MODE_REPORT) || cdr.FastForward || cdr.FastBackward)) {
cdr.Result[0] = cdr.StatP;
cdr.Result[1] = cdr.subq.Track;
cdr.Seeked = SEEK_DONE;
if (cdr.Irq == 0) {
cdr.Stat = Complete;
+ cdr.RErr = 1;
setIrq();
}
cdr.Irq = 0;
switch (Irq) {
- case CdlSync:
- // TOOD: sometimes/always return error?
- break;
-
case CdlNop:
if (cdr.DriveState != DRIVESTATE_LID_OPEN)
cdr.StatP &= ~STATUS_SHELLOPEN;
do_CdlPlay:
case CdlPlay:
StopCdda();
- if (cdr.Seeked == SEEK_PENDING) {
- // XXX: wrong, should seek instead..
- cdr.Seeked = SEEK_DONE;
- }
+ /* It would set it to SEEK_DONE*/
+ cdr.Seeked = SEEK_PENDING;
+
+ cdr.FastBackward = 0;
+ cdr.FastForward = 0;
+
if (cdr.SetlocPending) {
memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
cdr.SetlocPending = 0;
case CdlForward:
// TODO: error 80 if stopped
cdr.Stat = Complete;
-
+ cdr.RErr = 1;
// GameShark CD Player: Calls 2x + Play 2x
- if( cdr.FastForward == 0 ) cdr.FastForward = 2;
- else cdr.FastForward++;
-
+ cdr.FastForward = 1;
cdr.FastBackward = 0;
break;
cdr.Stat = Complete;
// GameShark CD Player: Calls 2x + Play 2x
- if( cdr.FastBackward == 0 ) cdr.FastBackward = 2;
- else cdr.FastBackward++;
-
+ cdr.FastBackward =1;
cdr.FastForward = 0;
break;
case CdlStandby + 0x100:
cdr.Stat = Complete;
+ cdr.RErr = 1;
break;
case CdlStop:
cdr.StatP &= ~STATUS_ROTATING;
cdr.Result[0] = cdr.StatP;
cdr.Stat = Complete;
+ cdr.RErr = 1;
break;
case CdlPause:
cdr.StatP &= ~STATUS_READ;
cdr.Result[0] = cdr.StatP;
cdr.Stat = Complete;
+ cdr.RErr = 1;
break;
- case CdlInit:
- AddIrqQueue(CdlInit + 0x100, cdReadTime * 6);
+ case CdlReset:
+ cdr.Muted = FALSE;
+ cdr.Mode = 0x20; /* Needed for This is Football 2, Pooh's Party and possibly others. */
+ AddIrqQueue(CdlReset + 0x100, 4100000);
no_busy_error = 1;
start_rotating = 1;
break;
- case CdlInit + 0x100:
+ case CdlReset + 0x100:
cdr.Stat = Complete;
+ cdr.RErr = 1;
break;
case CdlMute:
no_busy_error = 1;
break;
- case CdlGetmode:
- SetResultSize(6);
+ case CdlGetparam:
+ SetResultSize(5);
cdr.Result[1] = cdr.Mode;
- cdr.Result[2] = cdr.File;
- cdr.Result[3] = cdr.Channel;
- cdr.Result[4] = 0;
- cdr.Result[5] = 0;
+ cdr.Result[2] = 0;
+ cdr.Result[3] = cdr.File;
+ cdr.Result[4] = cdr.Channel;
no_busy_error = 1;
break;
case CdlReadT + 0x100:
cdr.Stat = Complete;
+ cdr.RErr = 1;
break;
case CdlGetTN:
cdr.Result[0] = cdr.StatP;
cdr.Result[1] = itob(cdr.ResultTD[2]);
cdr.Result[2] = itob(cdr.ResultTD[1]);
- cdr.Result[3] = itob(cdr.ResultTD[0]);
+ /* According to Nocash's documentation, the function doesn't care about ff.
+ * This can be seen also in Mednafen's implementation. */
+ //cdr.Result[3] = itob(cdr.ResultTD[0]);
}
break;
/* This adds the string "PCSX" in Playstation bios boot screen */
memcpy((char *)&cdr.Result[4], "PCSX", 4);
cdr.Stat = Complete;
+ cdr.RErr = 1;
break;
- case CdlReset:
+ case CdlInit:
// yes, it really sets STATUS_SHELLOPEN
cdr.StatP |= STATUS_SHELLOPEN;
cdr.DriveState = DRIVESTATE_RESCAN_CD;
break;
case CdlGetQ:
- // TODO?
- CDR_LOG_I("got CdlGetQ\n");
+ no_busy_error = 1;
break;
case CdlReadToc:
case CdlReadToc + 0x100:
cdr.Stat = Complete;
+ cdr.RErr = 1;
no_busy_error = 1;
break;
case CdlReadS:
if (cdr.SetlocPending) {
seekTime = abs(msf2sec(cdr.SetSectorPlay) - msf2sec(cdr.SetSector)) * (cdReadTime / 200);
- if(seekTime > 1000000) seekTime = 1000000;
+ /*
+ * Gameblabla :
+ * It was originally set to 1000000 for Driver, however it is not high enough for Worms Pinball
+ * and was unreliable for that game.
+ * I also tested it against Mednafen and Driver's titlescreen music starts 25 frames later, not immediatly.
+ *
+ * Obviously, this isn't perfect but right now, it should be a bit better.
+ * Games to test this against if you change that setting :
+ * - Driver (titlescreen music delay and retry mission)
+ * - Worms Pinball (Will either not boot or crash in the memory card screen)
+ * - Viewpoint (short pauses if the delay in the ingame music is too long)
+ *
+ * It seems that 3386880 * 5 is too much for Driver's titlescreen and it starts skipping.
+ * However, 1000000 is not enough for Worms Pinball to reliably boot.
+ */
+ if(seekTime > 3386880 * 2) seekTime = 3386880 * 2;
memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
cdr.SetlocPending = 0;
cdr.m_locationChanged = TRUE;
C-12 - Final Resistance - doesn't like seek
*/
- if (cdr.Seeked != SEEK_DONE) {
- 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) + seekTime);
- } else {
- cdr.StatP |= STATUS_READ;
- cdr.StatP &= ~STATUS_SEEK;
-
- CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime * 1);
- }
+ /*
+ By nicolasnoble from PCSX Redux :
+ "It LOOKS like this logic is wrong, therefore disabling it with `&& false` for now.
+ For "PoPoLoCrois Monogatari II", the game logic will soft lock and will never issue GetLocP to detect
+ the end of its XA streams, as it seems to assume ReadS will not return a status byte with the SEEK
+ flag set. I think the reasonning is that since it's invalid to call GetLocP while seeking, the game
+ tries to protect itself against errors by preventing from issuing a GetLocP while it knows the
+ last status was "seek". But this makes the logic just softlock as it'll never get a notification
+ about the fact the drive is done seeking and the read actually started.
+ In other words, this state machine here is probably wrong in assuming the response to ReadS/ReadN is
+ done right away. It's rather when it's done seeking, and the read has actually started. This probably
+ requires a bit more work to make sure seek delays are processed properly.
+ Checked with a few games, this seems to work fine."
+
+ Gameblabla additional notes :
+ This still needs the "+ seekTime" that PCSX Redux doesn't have for the Driver "retry" mission error.
+ */
+ cdr.StatP |= STATUS_READ;
+ cdr.StatP &= ~STATUS_SEEK;
+ CDREAD_INT(((cdr.Mode & 0x80) ? (cdReadTime) : cdReadTime * 2) + seekTime);
cdr.Result[0] = cdr.StatP;
start_rotating = 1;
break;
+ case CdlSync:
default:
CDR_LOG_I("Invalid command: %02x\n", Irq);
error = ERROR_INVALIDCMD;
buf = CDR_getBuffer();
if (buf == NULL)
- cdr.RErr = -1;
+ cdr.RErr = 0;
- if (cdr.RErr == -1) {
+ if (cdr.RErr == 0) {
CDR_LOG_I("cdrReadInterrupt() Log: err\n");
memset(cdr.Transfer, 0, DATA_SIZE);
cdr.Stat = DiskError;
switch (cdr.Cmd) {
case CdlSetloc:
- for (i = 0; i < 3; i++)
- set_loc[i] = btoi(cdr.Param[i]);
+ CDR_LOG("CDROM setloc command (%02X, %02X, %02X)\n", cdr.Param[0], cdr.Param[1], cdr.Param[2]);
- i = msf2sec(cdr.SetSectorPlay);
- i = abs(i - msf2sec(set_loc));
- if (i > 16)
- cdr.Seeked = SEEK_PENDING;
+ // MM must be BCD, SS must be BCD and <0x60, FF must be BCD and <0x75
+ if (((cdr.Param[0] & 0x0F) > 0x09) || (cdr.Param[0] > 0x99) || ((cdr.Param[1] & 0x0F) > 0x09) || (cdr.Param[1] >= 0x60) || ((cdr.Param[2] & 0x0F) > 0x09) || (cdr.Param[2] >= 0x75))
+ {
+ CDR_LOG("Invalid/out of range seek to %02X:%02X:%02X\n", cdr.Param[0], cdr.Param[1], cdr.Param[2]);
+ }
+ else
+ {
+ for (i = 0; i < 3; i++)
+ {
+ set_loc[i] = btoi(cdr.Param[i]);
+ }
- memcpy(cdr.SetSector, set_loc, 3);
- cdr.SetSector[3] = 0;
- cdr.SetlocPending = 1;
+ i = msf2sec(cdr.SetSectorPlay);
+ i = abs(i - msf2sec(set_loc));
+ if (i > 16)
+ cdr.Seeked = SEEK_PENDING;
+
+ memcpy(cdr.SetSector, set_loc, 3);
+ cdr.SetSector[3] = 0;
+ cdr.SetlocPending = 1;
+ }
break;
case CdlReadN:
StopReading();
break;
- case CdlReset:
case CdlInit:
+ case CdlReset:
cdr.Seeked = SEEK_DONE;
StopCdda();
StopReading();