#include "ppf.h"
#include "psxdma.h"
+/* logging */
+#if 0
+#define CDR_LOG SysPrintf
+#else
+#define CDR_LOG(...)
+#endif
+#if 0
+#define CDR_LOG_I SysPrintf
+#else
+#define CDR_LOG_I(...)
+#endif
+#if 0
+#define CDR_LOG_IO SysPrintf
+#else
+#define CDR_LOG_IO(...)
+#endif
+//#define CDR_LOG_CMD_IRQ
+
cdrStruct cdr;
static unsigned char *pTransfer;
// so (PSXCLK / 75) = cdr read time (linuzappz)
#define cdReadTime (PSXCLK / 75)
+// for cdr.Seeked
+enum seeked_state {
+ SEEK_PENDING = 0,
+ SEEK_DONE = 1,
+ SEEK_DOING_CMD = 2,
+};
+
static struct CdrStat stat;
-static unsigned int msf2sec(char *msf) {
+static unsigned int msf2sec(u8 *msf) {
return ((msf[0] * 60 + msf[1]) * 75) + msf[2];
}
-static void sec2msf(unsigned int s, char *msf) {
+static void sec2msf(unsigned int s, u8 *msf) {
msf[0] = s / 75 / 60;
s = s - msf[0] * 75 * 60;
msf[1] = s / 75;
msf[2] = s;
}
-
+// cdrInterrupt
#define CDR_INT(eCycle) { \
psxRegs.interrupt |= (1 << PSXINT_CDR); \
psxRegs.intCycle[PSXINT_CDR].cycle = eCycle; \
new_dyna_set_event(PSXINT_CDR, eCycle); \
}
+// cdrReadInterrupt
#define CDREAD_INT(eCycle) { \
psxRegs.interrupt |= (1 << PSXINT_CDREAD); \
psxRegs.intCycle[PSXINT_CDREAD].cycle = eCycle; \
new_dyna_set_event(PSXINT_CDREAD, eCycle); \
}
+// cdrLidSeekInterrupt
#define CDRLID_INT(eCycle) { \
psxRegs.interrupt |= (1 << PSXINT_CDRLID); \
psxRegs.intCycle[PSXINT_CDRLID].cycle = eCycle; \
new_dyna_set_event(PSXINT_CDRLID, eCycle); \
}
-#define CDRPLAY_INT(eCycle) { \
+// cdrPlayInterrupt
+#define CDRMISC_INT(eCycle) { \
psxRegs.interrupt |= (1 << PSXINT_CDRPLAY); \
psxRegs.intCycle[PSXINT_CDRPLAY].cycle = eCycle; \
psxRegs.intCycle[PSXINT_CDRPLAY].sCycle = psxRegs.cycle; \
}
}
-
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 )
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;
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]);
-#endif
cdr.RErr = CDR_readTrack(cdr.Prev);
}
-void AddIrqQueue(unsigned char irq, unsigned long ecycle) {
+static void AddIrqQueue(unsigned char irq, unsigned long ecycle) {
+ if (cdr.Irq != 0 && cdr.Irq != 0xff)
+ CDR_LOG_I("cdr: override cmd %02x -> %02x\n", cdr.Irq, irq);
+
cdr.Irq = irq;
cdr.eCycle = ecycle;
- // Doom: Force rescheduling
- // - Fixes boot
CDR_INT(ecycle);
}
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
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
// update subq
ReadTrack( cdr.SetSectorPlay );
-#ifdef CDR_LOG
CDR_LOG( "CDDA SUB - %X:%X:%X\n",
subq->AbsoluteAddress[0], subq->AbsoluteAddress[1], subq->AbsoluteAddress[2] );
-#endif
/*
CDDA Autopause
Tomb Raider 1 ($7)
*/
+ // .. + 1 is probably wrong, but deals with corrupted subq + good checksum
+ // (how does real thing handle those?)
if( cdr.CurTrack + 1 == btoi( subq->TrackNumber ) )
track_changed = 1;
} 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
track_changed = fake_subq_change;
fake_subq_change = 0;
}
if ((cdr.Mode & MODE_AUTOPAUSE) && track_changed) {
-#ifdef CDR_LOG
CDR_LOG( "CDDA STOP\n" );
-#endif
// Magic the Gathering
// - looping territory cdda
StopCdda();
}
- if (cdr.Mode & MODE_REPORT) {
+ else if (cdr.Mode & MODE_REPORT) {
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 );
+
+ // breaks when .sub doesn't have index 0 for some reason (bad rip?)
+ //cdr.CurTrack = btoi( subq->TrackNumber );
if (subq->AbsoluteAddress[2] & 0xf)
return;
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
if (fake_subq_real[2] & 0xf)
return;
}
}
+// also handles seek
void cdrPlayInterrupt()
{
- if( !cdr.Play ) return;
+ if (cdr.Seeked == SEEK_DOING_CMD) {
+ if (cdr.Stat) {
+ CDR_LOG_I("cdrom: seek stat hack\n");
+ CDRMISC_INT(0x1000);
+ return;
+ }
+ SetResultSize(1);
+ cdr.StatP |= STATUS_ROTATING;
+ cdr.StatP &= ~STATUS_SEEK;
+ cdr.Result[0] = cdr.StatP;
+ if (cdr.Irq == 0 || cdr.Irq == 0xff) {
+ cdr.Stat = Complete;
+ if (cdr.Reg2 != 0x18)
+ psxHu32ref(0x1070) |= SWAP32(0x4);
+ }
+
+ cdr.Seeked = SEEK_PENDING;
+ CDRMISC_INT(cdReadTime * 20); // ???
+ return;
+ }
+ else if (cdr.Seeked == SEEK_PENDING) {
+ cdr.Seeked = SEEK_DONE;
+ if (!cdr.Play && !cdr.Reading) {
+ memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
+ Find_CurTrack();
+ ReadTrack(cdr.SetSector);
+ }
+ }
+
+ 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 );
+
+ CDRMISC_INT( cdReadTime );
if (!cdr.Irq && !cdr.Stat && (cdr.Mode & MODE_CDDA) && (cdr.Mode & (MODE_AUTOPAUSE|MODE_REPORT)))
cdrPlayInterrupt_Autopause();
// Reschedule IRQ
if (cdr.Stat) {
- CDR_INT( 0x100 );
+ CDR_LOG_I("cdrom: stat hack: %02x %x\n", cdr.Irq, cdr.Stat);
+ CDR_INT(0x1000);
return;
}
case CdlPlay:
fake_subq_change = 0;
- if( cdr.Seeked == FALSE ) {
+ if (cdr.Seeked == SEEK_PENDING) {
+ // XXX: wrong, should seek instead..
memcpy( cdr.SetSectorPlay, cdr.SetSector, 4 );
- cdr.Seeked = TRUE;
+ cdr.Seeked = SEEK_DONE;
}
/*
// 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 );
}
{
// 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.SetSectorPlay[2] = cdr.ResultTD[0];
// reset data
- Set_Track();
+ //Set_Track();
Find_CurTrack();
ReadTrack( cdr.SetSectorPlay );
// BIOS player - set flag again
cdr.Play = TRUE;
- CDRPLAY_INT( cdReadTime );
+ CDRMISC_INT( cdReadTime );
break;
case CdlForward:
break;
case CdlSeekL:
+ case CdlSeekP:
SetResultSize(1);
cdr.StatP |= STATUS_ROTATING;
cdr.Result[0] = cdr.StatP;
Rockman X5 = 0.5-4x
- fix capcom logo
*/
- AddIrqQueue(CdlSeekL + 0x20, cdReadTime * 4);
- break;
-
- case CdlSeekL + 0x20:
- SetResultSize(1);
- 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:
- SetResultSize(1);
- 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:
- SetResultSize(1);
- 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 );
+ CDRMISC_INT(cdr.Seeked == SEEK_DONE ? 0x800 : cdReadTime * 4);
+ cdr.Seeked = SEEK_DOING_CMD;
break;
case CdlTest:
if (buf != NULL)
memcpy(cdr.Transfer, buf, 8);
}
-
-
+
/*
Duke Nukem: Land of the Babes - seek then delay read for one frame
- fixes cutscenes
C-12 - Final Resistance - doesn't like seek
*/
- if (!cdr.Seeked) {
- cdr.Seeked = TRUE;
-
+ if (cdr.Seeked != SEEK_DONE) {
cdr.StatP |= STATUS_SEEK;
cdr.StatP &= ~STATUS_READ;
psxHu32ref(0x1070) |= SWAP32((u32)0x4);
}
-#ifdef CDR_LOG
- CDR_LOG("cdrInterrupt() Log: CDR Interrupt IRQ %x\n", Irq);
+#ifdef CDR_LOG_CMD_IRQ
+ SysPrintf("cdrInterrupt() Log: CDR Interrupt IRQ %d %02x: ",
+ cdr.Stat != NoIntr && cdr.Reg2 != 0x18, Irq);
+ for (i = 0; i < cdr.ResultC; i++)
+ SysPrintf("%02x ", cdr.Result[i]);
+ SysPrintf("\n");
#endif
}
return;
if (cdr.Irq || cdr.Stat) {
- CDREAD_INT(0x100);
+ CDR_LOG_I("cdrom: read stat hack %02x %x\n", cdr.Irq, cdr.Stat);
+ CDREAD_INT(0x1000);
return;
}
-#ifdef CDR_LOG
- CDR_LOG("cdrReadInterrupt() Log: KEY END");
-#endif
-
cdr.OCUP = 1;
SetResultSize(1);
cdr.StatP |= STATUS_READ|STATUS_ROTATING;
cdr.StatP &= ~STATUS_SEEK;
cdr.Result[0] = cdr.StatP;
+ cdr.Seeked = SEEK_DONE;
ReadTrack( cdr.SetSector );
cdr.RErr = -1;
if (cdr.RErr == -1) {
-#ifdef CDR_LOG
- fprintf(emuLog, "cdrReadInterrupt() Log: err\n");
-#endif
+ CDR_LOG_I("cdrReadInterrupt() Log: err\n");
memset(cdr.Transfer, 0, DATA_SIZE);
cdr.Stat = DiskError;
cdr.Result[0] |= STATUS_ERROR;
CheckPPFCache(cdr.Transfer, cdr.Prev[0], cdr.Prev[1], cdr.Prev[2]);
-#ifdef CDR_LOG
- fprintf(emuLog, "cdrReadInterrupt() Log: cdr.Transfer %x:%x:%x\n", cdr.Transfer[0], cdr.Transfer[1], cdr.Transfer[2]);
-#endif
+ CDR_LOG("cdrReadInterrupt() Log: cdr.Transfer %x:%x:%x\n", cdr.Transfer[0], cdr.Transfer[1], cdr.Transfer[2]);
if ((!cdr.Muted) && (cdr.Mode & MODE_STRSND) && (!Config.Xa) && (cdr.FirstSector != -1)) { // CD-XA
// Firemen 2: Multi-XA files - briefings, cutscenes
// 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, 0x2000);
AddIrqQueue(CdlPause, 0x2000);
}
// What means the 0x10 and the 0x08 bits? I only saw it used by the bios
cdr.Ctrl |= 0x18;
-#ifdef CDR_LOG
- CDR_LOG("cdrRead0() Log: CD0 Read: %x\n", cdr.Ctrl);
-#endif
+ CDR_LOG_IO("cdr r0: %02x\n", cdr.Ctrl);
return psxHu8(0x1800) = cdr.Ctrl;
}
*/
void cdrWrite0(unsigned char rt) {
-#ifdef CDR_LOG
- CDR_LOG("cdrWrite0() Log: CD0 write: %x\n", rt);
-#endif
+ CDR_LOG_IO("cdr w0: %02x\n", rt);
+
cdr.Ctrl = (rt & 3) | (cdr.Ctrl & ~3);
}
} else {
psxHu8(0x1801) = 0;
}
-#ifdef CDR_LOG
- CDR_LOG("cdrRead1() Log: CD1 Read: %x\n", psxHu8(0x1801));
-#endif
+ CDR_LOG_IO("cdr r1: %02x\n", psxHu8(0x1801));
+
return psxHu8(0x1801);
}
void cdrWrite1(unsigned char rt) {
- char set_loc[3];
+ u8 set_loc[3];
int i;
-#ifdef CDR_LOG
- CDR_LOG("cdrWrite1() Log: CD1 write: %x (%s)\n", rt, CmdName[rt]);
-#endif
-
+ CDR_LOG_IO("cdr w1: %02x\n", rt);
// Tekken: CDXA fade-out
if( (cdr.Ctrl & 3) == 3 ) {
cdr.Cmd = rt;
cdr.OCUP = 0;
-#ifdef CDRCMD_DEBUG
+#ifdef CDR_LOG_CMD_IRQ
SysPrintf("cdrWrite1() Log: CD1 write: %x (%s)", rt, CmdName[rt]);
if (cdr.ParamC) {
SysPrintf(" Param[%d] = {", cdr.ParamC);
StopReading();
for (i = 0; i < 3; i++)
set_loc[i] = btoi(cdr.Param[i]);
+
i = abs(msf2sec(cdr.SetSector) - msf2sec(set_loc));
if (i > 16)
- cdr.Seeked = FALSE;
+ cdr.Seeked = SEEK_PENDING;
+
memcpy(cdr.SetSector, set_loc, 3);
cdr.SetSector[3] = 0;
- /*
- 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, 0x800);
case CdlReset:
case CdlInit:
+ cdr.Seeked = SEEK_DONE;
StopCdda();
StopReading();
cdr.Ctrl |= 0x80;
break;
case CdlSetmode:
-#ifdef CDR_LOG
CDR_LOG("cdrWrite1() Log: Setmode %x\n", cdr.Param[0]);
-#endif
+
cdr.Mode = cdr.Param[0];
cdr.Ctrl |= 0x80;
cdr.Stat = NoIntr;
default:
cdr.ParamP = 0;
cdr.ParamC = 0;
-#ifdef CDR_LOG
- CDR_LOG("cdrWrite1() Log: Unknown command: %x\n", cdr.Cmd);
-#endif
+ CDR_LOG_I("cdrWrite1() Log: Unknown command: %x\n", cdr.Cmd);
return;
}
if (cdr.Stat != NoIntr) {
ret = *pTransfer++;
}
-#ifdef CDR_LOG
- CDR_LOG("cdrRead2() Log: CD2 Read: %x\n", ret);
-#endif
+ CDR_LOG_IO("cdr r2: %02x\n", ret);
return ret;
}
void cdrWrite2(unsigned char rt) {
-#ifdef CDR_LOG
- CDR_LOG("cdrWrite2() Log: CD2 write: %x\n", rt);
-#endif
+ CDR_LOG_IO("cdr w2: %02x\n", rt);
// Tekken: CDXA fade-out
if( (cdr.Ctrl & 3) == 2 ) {
} else {
psxHu8(0x1803) = 0;
}
-#ifdef CDR_LOG
- CDR_LOG("cdrRead3() Log: CD3 Read: %x\n", psxHu8(0x1803));
-#endif
+
+ CDR_LOG_IO("cdr r3: %02x\n", psxHu8(0x1803));
return psxHu8(0x1803);
}
void cdrWrite3(unsigned char rt) {
-#ifdef CDR_LOG
- CDR_LOG("cdrWrite3() Log: CD3 write: %x\n", rt);
-#endif
+ CDR_LOG_IO("cdr w3: %02x\n", rt);
// 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
}
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);
+ CDR_LOG_I("-- resched %d -> %d\n", left, time);
CDREAD_INT(time);
}
}
int size;
u8 *ptr;
-#ifdef CDR_LOG
CDR_LOG("psxDma3() Log: *** DMA 3 *** %x addr = %x size = %x\n", chcr, madr, bcr);
-#endif
switch (chcr) {
case 0x11000000:
case 0x11400100:
if (cdr.Readed == 0) {
-#ifdef CDR_LOG
CDR_LOG("psxDma3() Log: *** DMA 3 *** NOT READY\n");
-#endif
break;
}
ptr = (u8 *)PSXM(madr);
if (ptr == NULL) {
-#ifdef CPU_LOG
CDR_LOG("psxDma3() Log: *** DMA 3 *** NULL Pointer!\n");
-#endif
break;
}
return;
default:
-#ifdef CDR_LOG
CDR_LOG("psxDma3() Log: Unknown cddma %x\n", chcr);
-#endif
break;
}
cdr.AttenuatorRight[1] = 0x00;
}
-int cdrFreeze(gzFile f, int Mode) {
+int cdrFreeze(void *f, int Mode) {
u32 tmp;
if( Mode == 0 ) {