cdrom: cleanup various hacks
[pcsx_rearmed.git] / libpcsxcore / cdrom.c
index a150db6..eebd8ed 100644 (file)
 #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;
 
 /* CD-ROM magic numbers */
 #define CdlSync        0
@@ -59,12 +78,6 @@ cdrStruct cdr;
 #define CdlReset       28
 #define CdlReadToc     30
 
-#define AUTOPAUSE      249
-#define READ_ACK       250
-#define READ           251
-#define REPPLAY_ACK    252
-#define REPPLAY        253
-#define ASYNC          254
 /* don't set 255, it's reserved */
 
 char *CmdName[0x100]= {
@@ -119,13 +132,20 @@ unsigned char Test23[] = { 0x43, 0x58, 0x44, 0x32, 0x39 ,0x34, 0x30, 0x51 };
 // 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;
@@ -133,7 +153,7 @@ static void sec2msf(unsigned int s, char *msf) {
        msf[2] = s;
 }
 
-
+// cdrInterrupt
 #define CDR_INT(eCycle) { \
        psxRegs.interrupt |= (1 << PSXINT_CDR); \
        psxRegs.intCycle[PSXINT_CDR].cycle = eCycle; \
@@ -141,6 +161,7 @@ static void sec2msf(unsigned int s, char *msf) {
        new_dyna_set_event(PSXINT_CDR, eCycle); \
 }
 
+// cdrReadInterrupt
 #define CDREAD_INT(eCycle) { \
        psxRegs.interrupt |= (1 << PSXINT_CDREAD); \
        psxRegs.intCycle[PSXINT_CDREAD].cycle = eCycle; \
@@ -148,6 +169,7 @@ static void sec2msf(unsigned int s, char *msf) {
        new_dyna_set_event(PSXINT_CDREAD, eCycle); \
 }
 
+// cdrLidSeekInterrupt
 #define CDRLID_INT(eCycle) { \
        psxRegs.interrupt |= (1 << PSXINT_CDRLID); \
        psxRegs.intCycle[PSXINT_CDRLID].cycle = eCycle; \
@@ -155,20 +177,14 @@ static void sec2msf(unsigned int s, char *msf) {
        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; \
        new_dyna_set_event(PSXINT_CDRPLAY, eCycle); \
 }
 
-#define StartReading(type, eCycle) { \
-       cdr.Reading = type; \
-       cdr.FirstSector = 1; \
-       cdr.Readed = 0xff; \
-       AddIrqQueue(READ_ACK, eCycle); \
-}
-
 #define StopReading() { \
        if (cdr.Reading) { \
                cdr.Reading = 0; \
@@ -189,11 +205,16 @@ static void sec2msf(unsigned int s, char *msf) {
 }
 
 #define SetResultSize(size) { \
-    cdr.ResultP = 0; \
+       cdr.ResultP = 0; \
        cdr.ResultC = size; \
        cdr.ResultReady = 1; \
 }
 
+static void setIrq(void)
+{
+       if (cdr.Stat & cdr.Reg2)
+               psxHu32ref(0x1070) |= SWAP32((u32)0x4);
+}
 
 void cdrLidSeekInterrupt()
 {
@@ -251,15 +272,12 @@ void cdrLidSeekInterrupt()
        }
 }
 
-
 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 )
@@ -315,8 +333,7 @@ static void Check_Shell( int Irq )
                                        if( cdr.Stat == NoIntr )
                                                cdr.Stat = Acknowledge;
 
-                                       psxHu32ref(0x1070) |= SWAP32((u32)0x4);
-
+                                       setIrq();
 
                                        // begin close-seek-ready cycle
                                        CDRLID_INT( cdReadTime * 3 );
@@ -356,12 +373,11 @@ static void Check_Shell( int Irq )
                        if( cdr.Stat == NoIntr )
                                cdr.Stat = Acknowledge;
 
-                       psxHu32ref(0x1070) |= SWAP32((u32)0x4);
+                       setIrq();
                }
        }
 }
 
-
 void Find_CurTrack() {
        cdr.CurTrack = 0;
 
@@ -372,12 +388,10 @@ void Find_CurTrack() {
                        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;
@@ -403,19 +417,18 @@ static void ReadTrack( u8 *time ) {
        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);
 }
 
@@ -427,12 +440,10 @@ void Set_Track()
 
                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
@@ -513,12 +524,10 @@ static void Create_Fake_Subq()
        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
 
 
 
@@ -539,11 +548,13 @@ static void Create_Fake_Subq()
 static void cdrPlayInterrupt_Autopause()
 {
        struct SubQ *subq = (struct SubQ *)CDR_getBufferSub();
+       int track_changed = 0;
        if (subq != NULL ) {
-#ifdef CDR_LOG
+               // update subq
+               ReadTrack( cdr.SetSectorPlay );
+
                CDR_LOG( "CDDA SUB - %X:%X:%X\n",
                        subq->AbsoluteAddress[0], subq->AbsoluteAddress[1], subq->AbsoluteAddress[2] );
-#endif
 
                /*
                CDDA Autopause
@@ -552,25 +563,21 @@ static void cdrPlayInterrupt_Autopause()
                Tomb Raider 1 ($7)
                */
 
-               if( cdr.CurTrack >= btoi( subq->TrackNumber ) )
-                       return;
+               // .. + 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
-
-               if( !fake_subq_change )
-                       return;
 
+               track_changed = fake_subq_change;
                fake_subq_change = 0;
        }
 
-       if (cdr.Mode & MODE_AUTOPAUSE) {
-#ifdef CDR_LOG
+       if ((cdr.Mode & MODE_AUTOPAUSE) && track_changed) {
                CDR_LOG( "CDDA STOP\n" );
-#endif
 
                // Magic the Gathering
                // - looping territory cdda
@@ -579,23 +586,22 @@ static void cdrPlayInterrupt_Autopause()
                //cdr.ResultReady = 1;
                //cdr.Stat = DataReady;
                cdr.Stat = DataEnd;
-               psxHu32ref(0x1070) |= SWAP32((u32)0x4);
+               setIrq();
 
                StopCdda();
        }
-       if (cdr.Mode & MODE_REPORT) {
-               // rearmed note: PCSX-Reloaded does this for every sector,
-               // but we try to get away with only track change here.
-               memset( cdr.Result, 0, 8 );
-               cdr.Result[0] |= 0x10;
-
+       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[0] = cdr.StatP;
                        // BIOS CD Player: data already BCD format
                        cdr.Result[1] = subq->TrackNumber;
                        cdr.Result[2] = subq->IndexNumber;
@@ -604,11 +610,13 @@ static void cdrPlayInterrupt_Autopause()
                        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;
+
+                       cdr.Result[0] = cdr.StatP;
                        // track # / index #
                        cdr.Result[1] = itob(cdr.CurTrack);
                        cdr.Result[2] = itob(fake_subq_index);
@@ -623,19 +631,47 @@ static void cdrPlayInterrupt_Autopause()
                cdr.Stat = DataReady;
 
                SetResultSize(8);
-               psxHu32ref(0x1070) |= SWAP32((u32)0x4);
+               setIrq();
        }
 }
 
+// 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;
+                       setIrq();
+               }
+
+               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();
@@ -660,7 +696,8 @@ void cdrInterrupt() {
 
        // 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;
        }
 
@@ -694,9 +731,10 @@ void cdrInterrupt() {
                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;
                        }
 
                        /*
@@ -736,10 +774,8 @@ void cdrInterrupt() {
 
                                // 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 );
                                }
@@ -747,18 +783,14 @@ void cdrInterrupt() {
                                {
                                        // 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();
@@ -777,7 +809,7 @@ void cdrInterrupt() {
                                                                cdr.SetSectorPlay[2] = cdr.ResultTD[0];
 
                                                                // reset data
-                                                               Set_Track();
+                                                               //Set_Track();
                                                                Find_CurTrack();
                                                                ReadTrack( cdr.SetSectorPlay );
 
@@ -805,7 +837,7 @@ void cdrInterrupt() {
                        // BIOS player - set flag again
                        cdr.Play = TRUE;
 
-                       CDRPLAY_INT( cdReadTime );
+                       CDRMISC_INT( cdReadTime );
                        break;
 
                case CdlForward:
@@ -956,6 +988,10 @@ void cdrInterrupt() {
                        subq = (struct SubQ *)CDR_getBufferSub();
 
                        if (subq != NULL) {
+                               if( cdr.Play && (cdr.Mode & MODE_CDDA) && !(cdr.Mode & (MODE_AUTOPAUSE|MODE_REPORT)) )
+                                       // update subq
+                                       ReadTrack( cdr.SetSectorPlay );
+
                                cdr.Result[0] = subq->TrackNumber;
                                cdr.Result[1] = subq->IndexNumber;
                                memcpy(cdr.Result + 2, subq->TrackRelativeAddress, 3);
@@ -1034,6 +1070,7 @@ void cdrInterrupt() {
                        break;
 
                case CdlSeekL:
+               case CdlSeekP:
                        SetResultSize(1);
                        cdr.StatP |= STATUS_ROTATING;
                        cdr.Result[0] = cdr.StatP;
@@ -1053,45 +1090,8 @@ void cdrInterrupt() {
                        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:
@@ -1191,20 +1191,8 @@ void cdrInterrupt() {
                        cdr.Stat = Complete;
                        break;
 
-               case AUTOPAUSE:
-                       cdr.OCUP = 0;
-/*                     SetResultSize(1);
-                       StopCdda();
-                       StopReading();
-                       cdr.OCUP = 0;
-                       cdr.StatP&=~0x20;
-                       cdr.StatP|= 0x2;
-                       cdr.Result[0] = cdr.StatP;
-                       cdr.Stat = DataEnd;
-*/                     AddIrqQueue(CdlPause, 0x800);
-                       break;
-
-               case READ_ACK:
+               case CdlReadN:
+               case CdlReadS:
                        if (!cdr.Reading) return;
 
 
@@ -1220,17 +1208,14 @@ void cdrInterrupt() {
                                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;
 
@@ -1262,12 +1247,16 @@ void cdrInterrupt() {
 
        Check_Shell( Irq );
 
-       if (cdr.Stat != NoIntr && cdr.Reg2 != 0x18) {
-               psxHu32ref(0x1070) |= SWAP32((u32)0x4);
-       }
+       cdr.ParamC = 0;
+
+       setIrq();
 
-#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
 }
 
@@ -1278,19 +1267,17 @@ void cdrReadInterrupt() {
                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 );
 
@@ -1299,9 +1286,7 @@ void cdrReadInterrupt() {
                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;
@@ -1313,9 +1298,7 @@ void cdrReadInterrupt() {
        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
@@ -1356,7 +1339,7 @@ void cdrReadInterrupt() {
                                // - don't do here
 
                                // signal ADPCM data ready
-                               psxHu32ref(0x1070) |= SWAP32((u32)0x200);
+                               setIrq();
 #endif
                        }
                        else cdr.FirstSector = -1;
@@ -1378,10 +1361,9 @@ void cdrReadInterrupt() {
        // 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);
        }
        else {
@@ -1401,15 +1383,14 @@ void cdrReadInterrupt() {
                // Rockman X5 - no music restart problem
                cdr.Stat = NoIntr;
        }
-       psxHu32ref(0x1070) |= SWAP32((u32)0x4);
+       setIrq();
 
        Check_Shell(0);
 }
 
 /*
 cdrRead0:
-       bit 0 - 0 REG1 command send / 1 REG1 data read
-       bit 1 - 0 data transfer finish / 1 data transfer ready/in progress
+       bit 0,1 - mode
        bit 2 - unknown
        bit 3 - unknown
        bit 4 - unknown
@@ -1432,67 +1413,51 @@ unsigned char cdrRead0(void) {
        // 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;
 }
 
-/*
-cdrWrite0:
-       0 - to send a command / 1 - to get the result
-*/
-
 void cdrWrite0(unsigned char rt) {
-#ifdef CDR_LOG
-       CDR_LOG("cdrWrite0() Log: CD0 write: %x\n", rt);
-#endif
-       cdr.Ctrl = rt | (cdr.Ctrl & ~0x3);
+       CDR_LOG_IO("cdr w0: %02x\n", rt);
 
-       if (rt == 0) {
-               cdr.ParamP = 0;
-               cdr.ParamC = 0;
-               cdr.ResultReady = 0;
-       }
+       cdr.Ctrl = (rt & 3) | (cdr.Ctrl & ~3);
 }
 
 unsigned char cdrRead1(void) {
-    if (cdr.ResultReady) { // && cdr.Ctrl & 0x1) {
-               // GameShark CDX CD Player: uses 17 bytes output (wraps around)
+       if ((cdr.ResultP & 0xf) < cdr.ResultC)
                psxHu8(0x1801) = cdr.Result[cdr.ResultP & 0xf];
-               cdr.ResultP++;
-               if (cdr.ResultP == cdr.ResultC)
-                       cdr.ResultReady = 0;
-       } else {
+       else
                psxHu8(0x1801) = 0;
-       }
-#ifdef CDR_LOG
-       CDR_LOG("cdrRead1() Log: CD1 Read: %x\n", psxHu8(0x1801));
-#endif
+       cdr.ResultP++;
+       if (cdr.ResultP == cdr.ResultC)
+               cdr.ResultReady = 0;
+
+       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.AttenuatorRight[0] = rt;
+       switch (cdr.Ctrl & 3) {
+       case 0:
+               break;
+       case 3:
+               cdr.AttenuatorRight[1] = rt;
+               return;
+       default:
+               return;
        }
 
-
-//     psxHu8(0x1801) = rt;
        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);
@@ -1504,44 +1469,40 @@ void cdrWrite1(unsigned char rt) {
        }
 #endif
 
-       if (cdr.Ctrl & 0x1) return;
+       cdr.ResultReady = 0;
+       cdr.Ctrl |= 0x80;
+       // cdr.Stat = NoIntr; 
+       AddIrqQueue(cdr.Cmd, 0x800);
 
        switch (cdr.Cmd) {
-       case CdlSync:
-               cdr.Ctrl |= 0x80;
-               cdr.Stat = NoIntr; 
-               AddIrqQueue(cdr.Cmd, 0x800);
-               break;
-
-       case CdlNop:
-               cdr.Ctrl |= 0x80;
-               cdr.Stat = NoIntr; 
-
-               // Twisted Metal 3 - fix music
-               AddIrqQueue(cdr.Cmd, 0x800);
-               break;
+       case CdlSync:
+       case CdlNop:
+       case CdlForward:
+       case CdlBackward:
+       case CdlReadT:
+       case CdlTest:
+       case CdlID:
+       case CdlReadToc:
+       case CdlGetmode:
+       case CdlGetlocL:
+       case CdlGetlocP:
+       case CdlGetTD:
+               break;
 
-       case CdlSetloc:
+       case CdlSetloc:
                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;
-               memcpy(cdr.SetSector, set_loc, 3);
-               cdr.SetSector[3] = 0;
+                       cdr.Seeked = SEEK_PENDING;
 
-               /*
-                  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);
-               break;
+               memcpy(cdr.SetSector, set_loc, 3);
+               cdr.SetSector[3] = 0;
+               break;
 
-       case CdlPlay:
+       case CdlPlay:
                // Vib Ribbon: try same track again
                StopCdda();
 
@@ -1565,50 +1526,25 @@ void cdrWrite1(unsigned char rt) {
                //TODO?
                //CDRDBUF_INT( PSXCLK / 44100 * 0x100 );
 
-
                cdr.Play = TRUE;
 
                cdr.StatP |= STATUS_SEEK;
                cdr.StatP &= ~STATUS_ROTATING;
+               break;
 
-               cdr.Ctrl |= 0x80;
-               cdr.Stat = NoIntr; 
-               AddIrqQueue(cdr.Cmd, 0x800);
-               break;
-
-       case CdlForward:
-               //if (cdr.CurTrack < 0xaa)
-               //      cdr.CurTrack++;
-               cdr.Ctrl |= 0x80;
-               cdr.Stat = NoIntr; 
-               AddIrqQueue(cdr.Cmd, 0x800);
-               break;
-
-       case CdlBackward:
-               //if (cdr.CurTrack > 1)
-               //cdr.CurTrack--;
-               cdr.Ctrl |= 0x80;
-               cdr.Stat = NoIntr; 
-               AddIrqQueue(cdr.Cmd, 0x800);
-               break;
-
-       case CdlReadN:
-               cdr.Irq = 0;
+       case CdlReadN:
                StopReading();
-               cdr.Ctrl|= 0x80;
-               cdr.Stat = NoIntr; 
-               StartReading(1, 0x800);
+               cdr.Reading = 1;
+               cdr.FirstSector = 1;
+               cdr.Readed = 0xff;
                break;
 
-       case CdlStandby:
+       case CdlStandby:
                StopCdda();
                StopReading();
-               cdr.Ctrl |= 0x80;
-               cdr.Stat = NoIntr;
-               AddIrqQueue(cdr.Cmd, 0x800);
-               break;
+               break;
 
-       case CdlStop:
+       case CdlStop:
                // GameShark CD Player: Reset CDDA to track start
                if( cdr.Play && CDR_getStatus(&stat) != -1 ) {
                        cdr.SetSectorPlay[0] = stat.Time[0];
@@ -1617,7 +1553,6 @@ void cdrWrite1(unsigned char rt) {
 
                        Find_CurTrack();
 
-
                        // grab time for current track
                        CDR_getTD((u8)(cdr.CurTrack), cdr.ResultTD);
 
@@ -1628,13 +1563,9 @@ void cdrWrite1(unsigned char rt) {
 
                StopCdda();
                StopReading();
+               break;
 
-               cdr.Ctrl |= 0x80;
-               cdr.Stat = NoIntr;
-               AddIrqQueue(cdr.Cmd, 0x800);
-               break;
-
-       case CdlPause:
+       case CdlPause:
                /*
                   GameShark CD Player: save time for resume
 
@@ -1643,61 +1574,41 @@ void cdrWrite1(unsigned char rt) {
 
                StopCdda();
                StopReading();
-               cdr.Ctrl |= 0x80;
-               cdr.Stat = NoIntr;
-
-               AddIrqQueue(cdr.Cmd, 0x800);
                break;
 
        case CdlReset:
-       case CdlInit:
+       case CdlInit:
+               cdr.Seeked = SEEK_DONE;
                StopCdda();
                StopReading();
-               cdr.Ctrl |= 0x80;
-               cdr.Stat = NoIntr; 
-               AddIrqQueue(cdr.Cmd, 0x800);
-               break;
-
-       case CdlMute:
-               cdr.Muted = TRUE;
-               cdr.Ctrl |= 0x80;
-               cdr.Stat = NoIntr; 
-               AddIrqQueue(cdr.Cmd, 0x800);
+               break;
 
+       case CdlMute:
+               cdr.Muted = TRUE;
                        // Duke Nukem - Time to Kill
                        // - do not directly set cd-xa volume
                        //SPU_writeRegister( H_CDLeft, 0x0000 );
                        //SPU_writeRegister( H_CDRight, 0x0000 );
-               break;
+               break;
 
-       case CdlDemute:
-               cdr.Muted = FALSE;
-               cdr.Ctrl |= 0x80;
-               cdr.Stat = NoIntr; 
-               AddIrqQueue(cdr.Cmd, 0x800);
+       case CdlDemute:
+               cdr.Muted = FALSE;
 
                        // Duke Nukem - Time to Kill
                        // - do not directly set cd-xa volume
                        //SPU_writeRegister( H_CDLeft, 0x7f00 );
                        //SPU_writeRegister( H_CDRight, 0x7f00 );
-               break;
+               break;
 
        case CdlSetfilter:
                cdr.File = cdr.Param[0];
                cdr.Channel = cdr.Param[1];
-               cdr.Ctrl |= 0x80;
-               cdr.Stat = NoIntr; 
-               AddIrqQueue(cdr.Cmd, 0x800);
                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; 
-               AddIrqQueue(cdr.Cmd, 0x800);
 
                // Squaresoft on PlayStation 1998 Collector's CD Vol. 1
                // - fixes choppy movie sound
@@ -1705,116 +1616,32 @@ void cdrWrite1(unsigned char rt) {
                        StopCdda();
                break;
 
-       case CdlGetmode:
-               cdr.Ctrl |= 0x80;
-               cdr.Stat = NoIntr; 
-               AddIrqQueue(cdr.Cmd, 0x800);
-               break;
-
-       case CdlGetlocL:
-               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; 
-
-               // 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);
-
-               // rearmed: the above works in pcsxr-svn, but breaks here
-               // (TOCA world touring cars), perhaps some other code is not merged yet
-               AddIrqQueue(cdr.Cmd, 0x1000);
-               break;
-
        case CdlGetTN:
-               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.Stat = NoIntr; 
-               AddIrqQueue(cdr.Cmd, 0x800);
-               break;
-
        case CdlSeekL:
-//                     ((u32 *)cdr.SetSectorSeek)[0] = ((u32 *)cdr.SetSector)[0];
-               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.Stat = NoIntr; 
-
                // 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.Stat = NoIntr; 
-               AddIrqQueue(cdr.Cmd, 0x800);
-               break;
-
-       case CdlID:
-               cdr.Ctrl |= 0x80;
-               cdr.Stat = NoIntr; 
-               AddIrqQueue(cdr.Cmd, 0x800);
-               break;
-
        case CdlReadS:
-               cdr.Irq = 0;
                StopReading();
-               cdr.Ctrl |= 0x80;
-               cdr.Stat = NoIntr; 
-               StartReading(2, 0x800);
+               cdr.Reading = 2;
+               cdr.FirstSector = 1;
+               cdr.Readed = 0xff;
                break;
 
-       case CdlReadToc:
-               cdr.Ctrl |= 0x80;
-               cdr.Stat = NoIntr; 
-               AddIrqQueue(cdr.Cmd, 0x800);
-               break;
-
-       default:
-#ifdef CDR_LOG
-               CDR_LOG("cdrWrite1() Log: Unknown command: %x\n", cdr.Cmd);
-#endif
+       default:
+               cdr.ParamC = 0;
+               CDR_LOG_I("cdrWrite1() Log: Unknown command: %x\n", cdr.Cmd);
                return;
        }
-       if (cdr.Stat != NoIntr) {
-               psxHu32ref(0x1070) |= SWAP32((u32)0x4);
-       }
 }
 
 unsigned char cdrRead2(void) {
@@ -1823,98 +1650,69 @@ unsigned char cdrRead2(void) {
        if (cdr.Readed == 0) {
                ret = 0;
        } else {
-               ret = *cdr.pTransfer++;
+               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 ) {
+       switch (cdr.Ctrl & 3) {
+       case 0:
+               if (cdr.ParamC < 8) // FIXME: size and wrapping
+                       cdr.Param[cdr.ParamC++] = rt;
+               return;
+       case 1:
+               cdr.Reg2 = rt;
+               setIrq();
+               return;
+       case 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.ParamC = 0;
-                               cdr.ResultReady = 1; //0;
-                               cdr.Ctrl &= ~3; //cdr.Ctrl = 0;
-                               break;
-
-                       default:
-                               cdr.Reg2 = rt;
-                               break;
-               }
-       } else if (!(cdr.Ctrl & 0x1) && cdr.ParamP < 8) {
-               cdr.Param[cdr.ParamP++] = rt;
-               cdr.ParamC++;
+               return;
+       case 3:
+               cdr.AttenuatorRight[0] = rt;
+               return;
        }
 }
 
 unsigned char cdrRead3(void) {
-       if (cdr.Stat) {
-               if (cdr.Ctrl & 0x1)
-                       psxHu8(0x1803) = cdr.Stat | 0xE0;
-               else
-                       psxHu8(0x1803) = 0xff;
-       } else {
-               psxHu8(0x1803) = 0;
-       }
-#ifdef CDR_LOG
-       CDR_LOG("cdrRead3() Log: CD3 Read: %x\n", psxHu8(0x1803));
-#endif
+       if (cdr.Ctrl & 0x1)
+               psxHu8(0x1803) = cdr.Stat | 0xE0;
+       else
+               psxHu8(0x1803) = cdr.Reg2 | 0xE0;
+
+       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
-
-       // Tekken: CDXA fade-out
-       if( (cdr.Ctrl & 3) == 2 ) {
+       CDR_LOG_IO("cdr w3: %02x\n", rt);
+
+       switch (cdr.Ctrl & 3) {
+       case 0:
+               goto transfer;
+       case 1:
+               break; // irq
+       case 2:
                cdr.AttenuatorLeft[1] = rt;
-       }
-       else if( (cdr.Ctrl & 3) == 3 && rt == 0x20 ) {
-#ifdef CDR_LOG
+               return;
+       case 3:
+               if (rt == 0x20)
                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);
-               }
+               return;
        }
 
+       cdr.Stat &= ~rt;
 
-       if (rt == 0x07 && cdr.Ctrl & 0x1) {
-               cdr.Stat = 0;
+       if (rt & 0x40)
+               cdr.ParamC = 0;
 
+       if (rt == 0x07) {
                if (cdr.Irq == 0xff) {
                        cdr.Irq = 0;
                        return;
@@ -1929,26 +1727,26 @@ void cdrWrite3(unsigned char rt) {
                        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);
                        }
                }
-
-               return;
        }
+       return;
 
-       if (rt == 0x80 && !(cdr.Ctrl & 0x1) && cdr.Readed == 0) {
+transfer:
+       if ((rt & 0x80) && cdr.Readed == 0) {
                cdr.Readed = 1;
-               cdr.pTransfer = cdr.Transfer;
+               pTransfer = cdr.Transfer;
 
                switch (cdr.Mode & 0x30) {
                        case MODE_SIZE_2328:
                        case 0x00:
-                               cdr.pTransfer += 12;
+                               pTransfer += 12;
                                break;
 
                        case MODE_SIZE_2340:
-                               cdr.pTransfer += 0;
+                               pTransfer += 0;
                                break;
 
                        default:
@@ -1962,17 +1760,13 @@ void psxDma3(u32 madr, u32 bcr, u32 chcr) {
        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;
                        }
 
@@ -1992,9 +1786,7 @@ void psxDma3(u32 madr, u32 bcr, u32 chcr) {
 
                        ptr = (u8 *)PSXM(madr);
                        if (ptr == NULL) {
-#ifdef CPU_LOG
                                CDR_LOG("psxDma3() Log: *** DMA 3 *** NULL Pointer!\n");
-#endif
                                break;
                        }
 
@@ -2004,16 +1796,16 @@ void psxDma3(u32 madr, u32 bcr, u32 chcr) {
                        - CdlPlay
                        - Spams DMA3 and gets buffer overrun
                        */
-                       size = CD_FRAMESIZE_RAW - (cdr.pTransfer - cdr.Transfer);
+                       size = CD_FRAMESIZE_RAW - (pTransfer - cdr.Transfer);
                        if (size > cdsize)
                                size = cdsize;
                        if (size > 0)
                        {
-                               memcpy(ptr, cdr.pTransfer, size);
+                               memcpy(ptr, pTransfer, size);
                        }
 
                        psxCpu->Clear(madr, cdsize / 4);
-                       cdr.pTransfer += cdsize;
+                       pTransfer += cdsize;
 
 
                        // burst vs normal
@@ -2026,9 +1818,7 @@ void psxDma3(u32 madr, u32 bcr, u32 chcr) {
                        return;
 
                default:
-#ifdef CDR_LOG
                        CDR_LOG("psxDma3() Log: Unknown cddma %x\n", chcr);
-#endif
                        break;
        }
 
@@ -2050,17 +1840,17 @@ void cdrReset() {
        cdr.CurTrack = 1;
        cdr.File = 1;
        cdr.Channel = 1;
+       pTransfer = cdr.Transfer;
 
        // BIOS player - default values
        cdr.AttenuatorLeft[0] = 0x80;
        cdr.AttenuatorLeft[1] = 0x00;
-       cdr.AttenuatorRight[0] = 0x80;
-       cdr.AttenuatorRight[1] = 0x00;
+       cdr.AttenuatorRight[0] = 0x00;
+       cdr.AttenuatorRight[1] = 0x80;
 }
 
-int cdrFreeze(gzFile f, int Mode) {
-       uintptr_t tmp;
-
+int cdrFreeze(void *f, int Mode) {
+       u32 tmp;
 
        if( Mode == 0 ) {
                StopCdda();
@@ -2068,13 +1858,19 @@ int cdrFreeze(gzFile f, int Mode) {
        
        gzfreeze(&cdr, sizeof(cdr));
        
-       if (Mode == 1)
-               tmp = cdr.pTransfer - cdr.Transfer;
+       if (Mode == 1) {
+               cdr.ParamP = cdr.ParamC;
+               tmp = pTransfer - cdr.Transfer;
+       }
 
        gzfreeze(&tmp, sizeof(tmp));
 
-       if (Mode == 0)
-               cdr.pTransfer = cdr.Transfer + tmp;
+       if (Mode == 0) {
+               pTransfer = cdr.Transfer + tmp;
+
+               if (cdr.Play && !Config.Cdda)
+                       CDR_play(cdr.SetSectorPlay);
+       }
 
        return 0;
 }