new experimental TurboCD option
[pcsx_rearmed.git] / libpcsxcore / cdrom.c
index 5da24c8..200dcf9 100644 (file)
@@ -111,7 +111,7 @@ static struct {
        u8 AdpcmActive;
        u32 LastReadSeekCycles;
 
-       u8 unused7;
+       u8 RetryDetected;
 
        u8 DriveState; // enum drive_state
        u8 FastForward;
@@ -576,6 +576,14 @@ static void cdrPlayInterrupt_Autopause()
                cdr.ReportDelay--;
 }
 
+static boolean canDoTurbo(void)
+{
+       u32 c = psxRegs.cycle;
+       return Config.TurboCD && !cdr.RetryDetected && !cdr.AdpcmActive
+               //&& c - psxRegs.intCycle[PSXINT_SPUDMA].sCycle > (u32)cdReadTime * 2
+               && c - psxRegs.intCycle[PSXINT_MDECOUTDMA].sCycle > (u32)cdReadTime * 16;
+}
+
 static int cdrSeekTime(unsigned char *target)
 {
        int diff = msf2sec(cdr.SetSectorPlay) - msf2sec(target);
@@ -583,19 +591,15 @@ static int cdrSeekTime(unsigned char *target)
        int cyclesSinceRS = psxRegs.cycle - cdr.LastReadSeekCycles;
        seekTime = MAX_VALUE(seekTime, 20000);
 
-       // need this stupidly long penalty or else Spyro2 intro desyncs
-       // note: if misapplied this breaks MGS cutscenes among other things
-       if (cdr.DriveState == DRIVESTATE_PAUSED && cyclesSinceRS > cdReadTime * 50)
-               seekTime += cdReadTime * 25;
        // Transformers Beast Wars Transmetals does Setloc(x),SeekL,Setloc(x),ReadN
        // and then wants some slack time
-       else if (cdr.DriveState == DRIVESTATE_PAUSED || cyclesSinceRS < cdReadTime *3/2)
+       if (cdr.DriveState == DRIVESTATE_PAUSED || cyclesSinceRS < cdReadTime *3/2)
                seekTime += cdReadTime;
 
        seekTime = MIN_VALUE(seekTime, PSXCLK * 2 / 3);
-       CDR_LOG("seek: %.2f %.2f (%.2f) st %d\n", (float)seekTime / PSXCLK,
+       CDR_LOG("seek: %.2f %.2f (%.2f) st %d di %d\n", (float)seekTime / PSXCLK,
                (float)seekTime / cdReadTime, (float)cyclesSinceRS / cdReadTime,
-               cdr.DriveState);
+               cdr.DriveState, diff);
        return seekTime;
 }
 
@@ -658,6 +662,11 @@ static void msfiSub(u8 *msfi, u32 count)
        }
 }
 
+static int msfiEq(const u8 *a, const u8 *b)
+{
+       return a[0] == b[0] && a[1] == b[1] && a[2] == b[2];
+}
+
 void cdrPlayReadInterrupt(void)
 {
        int hit = CDR_prefetch(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2]);
@@ -826,6 +835,9 @@ void cdrInterrupt(void) {
                        {
                                for (i = 0; i < 3; i++)
                                        set_loc[i] = btoi(cdr.Param[i]);
+                               cdr.RetryDetected = msfiEq(cdr.SetSector, set_loc)
+                                       && !cdr.SetlocPending;
+                               //cdr.RetryDetected |= msfiEq(cdr.Param, cdr.Transfer);
                                memcpy(cdr.SetSector, set_loc, 3);
                                cdr.SetSector[3] = 0;
                                cdr.SetlocPending = 1;
@@ -975,27 +987,19 @@ void cdrInterrupt(void) {
                        cdr.sectorsRead = 0;
 
                        /*
-                       Gundam Battle Assault 2: much slower (*)
-                       - Fixes boot, gameplay
-
-                       Hokuto no Ken 2: slower
-                       - Fixes intro + subtitles
-
-                       InuYasha - Feudal Fairy Tale: slower
-                       - Fixes battles
+                       Gundam Battle Assault 2
+                       Hokuto no Ken 2
+                       InuYasha - Feudal Fairy Tale
+                       Dance Dance Revolution Konamix
+                       ...
                        */
-                       /* Gameblabla - Tightening the timings (as taken from Duckstation). 
-                        * The timings from Duckstation are based upon hardware tests.
-                        * Mednafen's timing don't work for Gundam Battle Assault 2 in PAL/50hz mode,
-                        * seems to be timing sensitive as it can depend on the CPU's clock speed.
-                        * */
                        if (!(cdr.StatP & (STATUS_PLAY | STATUS_READ)))
                        {
                                second_resp_time = 7000;
                        }
                        else
                        {
-                               second_resp_time = (((cdr.Mode & MODE_SPEED) ? 1 : 2) * 1097107);
+                               second_resp_time = 2 * 1097107;
                        }
                        SetPlaySeekRead(cdr.StatP, 0);
                        DriveStateOld = cdr.DriveState;
@@ -1115,7 +1119,8 @@ void cdrInterrupt(void) {
                        StopReading();
                        SetPlaySeekRead(cdr.StatP, STATUS_SEEK | STATUS_ROTATING);
 
-                       seekTime = cdrSeekTime(cdr.SetSector);
+                       if (!canDoTurbo())
+                               seekTime = cdrSeekTime(cdr.SetSector);
                        memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
                        cdr.DriveState = DRIVESTATE_SEEK;
                        CDR_prefetch(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1],
@@ -1264,6 +1269,8 @@ void cdrInterrupt(void) {
                        cycles += seekTime;
                        if (Config.hacks.cdr_read_timing)
                                cycles = cdrAlignTimingHack(cycles);
+                       else if (canDoTurbo())
+                               cycles = cdReadTime / 2;
                        CDRPLAYREAD_INT(cycles, 1);
 
                        SetPlaySeekRead(cdr.StatP, STATUS_SEEK);
@@ -1399,7 +1406,7 @@ static void cdrReadInterrupt(void)
                        subhdr->file, subhdr->chan, cdr.CurFile, cdr.CurChannel, cdr.FilterFile, cdr.FilterChannel);
                if ((cdr.Mode & MODE_SF) && (subhdr->file != cdr.FilterFile || subhdr->chan != cdr.FilterChannel))
                        break;
-               if (subhdr->chan & 0xe0) { // ?
+               if (subhdr->chan & 0x80) { // ?
                        if (subhdr->chan != 0xff)
                                log_unhandled("adpcm %d:%d\n", subhdr->file, subhdr->chan);
                        break;
@@ -1455,6 +1462,8 @@ unsigned char cdrRead0(void) {
        cdr.Ctrl |= cdr.AdpcmActive << 2;
        cdr.Ctrl |= cdr.ResultReady << 5;
 
+       //cdr.Ctrl &= ~0x40;
+       //if (cdr.FifoOffset != DATA_SIZE)
        cdr.Ctrl |= 0x40; // data fifo not empty
 
        // What means the 0x10 and the 0x08 bits? I only saw it used by the bios
@@ -1654,7 +1663,7 @@ void cdrWrite3(unsigned char rt) {
 }
 
 void psxDma3(u32 madr, u32 bcr, u32 chcr) {
-       u32 cdsize, max_words;
+       u32 cdsize, max_words, cycles;
        int size;
        u8 *ptr;
 
@@ -1700,7 +1709,8 @@ void psxDma3(u32 madr, u32 bcr, u32 chcr) {
                        }
                        psxCpu->Clear(madr, cdsize / 4);
 
-                       set_event(PSXINT_CDRDMA, (cdsize / 4) * 24);
+                       cycles = (cdsize / 4) * 24;
+                       set_event(PSXINT_CDRDMA, cycles);
 
                        HW_DMA3_CHCR &= SWAPu32(~0x10000000);
                        if (chcr & 0x100) {
@@ -1709,8 +1719,10 @@ void psxDma3(u32 madr, u32 bcr, u32 chcr) {
                        }
                        else {
                                // halted
-                               psxRegs.cycle += (cdsize/4) * 24 - 20;
+                               psxRegs.cycle += cycles - 20;
                        }
+                       if (canDoTurbo() && cdr.Reading && cdr.FifoOffset >= 2048)
+                               CDRPLAYREAD_INT(cycles + 4096, 1);
                        return;
 
                default: