diff --git a/pcsx2/CDVD/CDVD.cpp b/pcsx2/CDVD/CDVD.cpp index d3cc58e9f9..f8d165fdd5 100644 --- a/pcsx2/CDVD/CDVD.cpp +++ b/pcsx2/CDVD/CDVD.cpp @@ -47,17 +47,6 @@ static __fi void SetResultSize(u8 size) cdvd.sDataIn &= ~0x40; } -static void CDVDDMA_INT(u32 eCycle) -{ - if (EmuConfig.Speedhacks.fastCDVD) - { - if (eCycle < Cdvd_FullSeek_Cycles && eCycle > 1) - eCycle *= 0.5f; - } - - PSX_INT(IopEvt_CdvdDMA, eCycle); -} - static void CDVDREAD_INT(u32 eCycle) { // Give it an arbitary FAST value. Good for ~5000kb/s in ULE when copying a file from CDVD to HDD @@ -657,6 +646,53 @@ static bool cdvdIsDVD() return false; } +static uint cdvdRotationalLatency(CDVD_MODE_TYPE mode) +{ + // CAV rotation is constant (minimum speed to maintain exact speed on outer dge + if (cdvd.SpindlCtrl & CDVD_SPINDLE_CAV) + { + float rotationPerSecond = (((mode == MODE_CDROM) ? CD_MIN_ROTATION_X1 : DVD_MIN_ROTATION_X1) * cdvd.Speed) / 60; + float msPerRotation = 1000.0f / rotationPerSecond; + return ((PSXCLK / 1000) * msPerRotation); + } + else + { + int numSectors = 0; + int offset = 0; + //CLV adjusts its speed based on where it is on the disc, so we can take the max RPM and use the sector to work it out + // Sector counts are taken from google for Single layer, Dual layer DVD's and for 700MB CD's + switch (cdvd.Type) + { + case CDVD_TYPE_DETCTDVDS: + case CDVD_TYPE_PS2DVD: + numSectors = 2298496; + break; + case CDVD_TYPE_DETCTDVDD: + numSectors = 4173824 / 2; // Total sectors for both layers, assume half per layer + u32 layer1Start; + s32 dualType; + + // Layer 1 needs an offset as it goes back to the middle of the disc + cdvdReadDvdDualInfo(&dualType, &layer1Start); + if (cdvd.SeekToSector >= layer1Start) + offset = layer1Start; + break; + default: // Pretty much every CD format + numSectors = 360000; + break; + } + + const float sectorSpeed = 1.0f - (((float)(cdvd.SeekToSector - offset) / numSectors) * 0.60f); + + float rotationPerSecond = (((mode == MODE_CDROM) ? CD_MAX_ROTATION_X1 : DVD_MAX_ROTATION_X1) * cdvd.Speed * sectorSpeed) / 60; + float msPerRotation = 1000.0f / rotationPerSecond; + + //DevCon.Warning("Rotations per second %f, msPerRotation cycles per ms %f total cycles per ms %d cycles per rotation %d", rotationPerSecond, msPerRotation, (u32)(PSXCLK / 1000), (u32)((PSXCLK / 1000) * msPerRotation)); + + return ((PSXCLK / 1000) * msPerRotation); + } +} + static uint cdvdBlockReadTime(CDVD_MODE_TYPE mode) { int numSectors = 0; @@ -815,11 +851,11 @@ int cdvdReadSector() if (bcr < cdvd.BlockSize) { CDVD_LOG("READBLOCK: bcr < cdvd.BlockSize; %x < %x", bcr, cdvd.BlockSize); - /*if (HW_DMA3_CHCR & 0x01000000) + if (HW_DMA3_CHCR & 0x01000000) { HW_DMA3_CHCR &= ~0x01000000; psxDmaInterrupt(3); - }*/ + } return -1; } @@ -953,23 +989,6 @@ __fi void cdvdActionInterrupt() psxHu32(0x1070) |= 0x4; } -void cdvdDMAInterrupt() -{ - if (HW_DMA3_CHCR & 0x01000000) - { - HW_DMA3_CHCR &= ~0x01000000; - psxDmaInterrupt(3); - - if (!cdvd.nSectors) - { - // Setting the data ready flag fixes a black screen loading issue in - // Street Fighter Ex3 (NTSC-J version). - cdvd.PwOff |= (1 << Irq_DataReady) | (1 << Irq_CommandComplete); - psxHu32(0x1070) |= 0x4; - cdvd.Ready = CDVD_READY2; - } - } -} // inlined due to being referenced in only one place. __fi void cdvdReadInterrupt() { @@ -1040,13 +1059,8 @@ __fi void cdvdReadInterrupt() // bit and try to read the sector again later. // An arbitrary delay of some number of cycles probably makes more sense here, // but for now it's based on the cdvd.ReadTime value. -- air - int DMATime = (cdvd.BlockSize / 2) * 40; - - CDVDREAD_INT(DMATime + 100); // Bring it back after the DMA has ended to avoid a nasty loop pxAssert((int)cdvd.ReadTime > 0); - - if (HW_DMA3_CHCR & 0x01000000) - CDVDDMA_INT(DMATime); + CDVDREAD_INT(cdvd.ReadTime); // Bring it back after the DMA has ended to avoid a nasty loop return; } @@ -1055,10 +1069,16 @@ __fi void cdvdReadInterrupt() if (--cdvd.nSectors <= 0) { - int DMATime = (cdvd.BlockSize / 2) * 40; - - CDVDDMA_INT(DMATime); - + if (HW_DMA3_CHCR & 0x01000000) + { + HW_DMA3_CHCR &= ~0x01000000; + psxDmaInterrupt(3); + } + // Setting the data ready flag fixes a black screen loading issue in + // Street Fighter Ex3 (NTSC-J version). + cdvd.PwOff |= (1 << Irq_DataReady) | (1 << Irq_CommandComplete); + psxHu32(0x1070) |= 0x4; + cdvd.Ready = CDVD_READY2; cdvd.Status = CDVD_STATUS_PAUSE; // Needed here but could be smth else than Pause (rama) // All done! :D return; @@ -1118,7 +1138,7 @@ static uint cdvdStartSeek(uint newsector, CDVD_MODE_TYPE mode) CDVD_LOG("CdSeek Begin > Contiguous block without seek - delta=%d sectors", delta); // seektime is the time it takes to read to the destination block: - seektime = delta * cdvd.ReadTime; + seektime = cdvd.ReadTime; if (delta == 0) { @@ -1131,10 +1151,17 @@ static uint cdvdStartSeek(uint newsector, CDVD_MODE_TYPE mode) // cdvdReadInterrupt will load a block. So make sure it's properly scheduled // based on sector read speeds: - seektime = cdvd.ReadTime; + //seektime = cdvd.ReadTime; } } + if (delta) + { + int rotationalLatency = cdvdRotationalLatency((CDVD_MODE_TYPE)cdvdIsDVD()); + //DevCon.Warning("%s rotational latency at sector %d is %d cycles", (cdvd.SpindlCtrl & CDVD_SPINDLE_CAV) ? "CAV" : "CLV", cdvd.SeekToSector, rotationalLatency); + seektime += rotationalLatency; + } + return seektime; } diff --git a/pcsx2/CDVD/CDVD_internal.h b/pcsx2/CDVD/CDVD_internal.h index a4ef4a795a..c0d459417a 100644 --- a/pcsx2/CDVD/CDVD_internal.h +++ b/pcsx2/CDVD/CDVD_internal.h @@ -135,6 +135,12 @@ static const uint PSX_DVD_READSPEED = 1382400; // Bytes per second, rough values static const uint CD_SECTORS_PERSECOND = 75; static const uint DVD_SECTORS_PERSECOND = 675; +static const uint CD_MIN_ROTATION_X1 = 214; +static const uint CD_MAX_ROTATION_X1 = 497; + +static const uint DVD_MIN_ROTATION_X1 = 570; +static const uint DVD_MAX_ROTATION_X1 = 1515; + // Legacy Note: FullSeek timing causes many games to load very slow, but it likely not the real problem. // Games breaking with it set to PSXCLK*40 : "wrath unleashed" and "Shijou Saikyou no Deshi Kenichi". diff --git a/pcsx2/IopHw.h b/pcsx2/IopHw.h index b3e4e8e710..063edb4f82 100644 --- a/pcsx2/IopHw.h +++ b/pcsx2/IopHw.h @@ -320,7 +320,6 @@ enum IopEventId IopEvt_CdvdRead, IopEvt_DEV9, IopEvt_USB, - IopEvt_CdvdDMA, }; extern void PSX_INT( IopEventId n, s32 ecycle); diff --git a/pcsx2/R3000A.cpp b/pcsx2/R3000A.cpp index 5a33766e94..4c8074528a 100644 --- a/pcsx2/R3000A.cpp +++ b/pcsx2/R3000A.cpp @@ -178,7 +178,6 @@ static __fi void _psxTestInterrupts() IopTestEvent(IopEvt_SIF2, sif2Interrupt); // SIF2 // Originally controlled by a preprocessor define, now PSX dependent. if (psxHu32(HW_ICFG) & (1 << 3)) IopTestEvent(IopEvt_SIO, sioInterruptR); - IopTestEvent(IopEvt_CdvdDMA, cdvdDMAInterrupt); IopTestEvent(IopEvt_CdvdRead, cdvdReadInterrupt); // Profile-guided Optimization (sorta)