mirror of https://github.com/PCSX2/pcsx2.git
CDVD: Better simulate RPM changes going in to CLV
- Fix bugs with rotational latency [SAVEVERSION+]
This commit is contained in:
parent
be7d4c3c93
commit
5f11ba0445
|
@ -817,14 +817,16 @@ static int cdvdTrayStateDetecting()
|
|||
else
|
||||
return CDVD_TYPE_DETCT; //Detecting any kind of disc existing
|
||||
}
|
||||
static u32 cdvdRotationalLatency(CDVD_MODE_TYPE mode)
|
||||
static u32 cdvdRotationTime(CDVD_MODE_TYPE mode)
|
||||
{
|
||||
// CAV rotation is constant (minimum speed to maintain exact speed on outer dge
|
||||
if (cdvd.SpindlCtrl & CDVD_SPINDLE_CAV)
|
||||
{
|
||||
const float rotationPerSecond = static_cast<float>(((mode == MODE_CDROM) ? CD_MIN_ROTATION_X1 : DVD_MIN_ROTATION_X1) * cdvd.Speed) / 60.0f;
|
||||
// Calculate rotations per second from RPM
|
||||
const float rotationPerSecond = static_cast<float>(((mode == MODE_CDROM) ? CD_MAX_ROTATION_X1 : DVD_MAX_ROTATION_X1) * cdvd.Speed) / 60.0f;
|
||||
// Calculate MS per rotation by dividing 1 second of milliseconds by the number of rotations.
|
||||
const float msPerRotation = 1000.0f / rotationPerSecond;
|
||||
|
||||
// Calculate how many cycles 1 millisecond takes in IOP clocks, multiply by the time for 1 rotation.
|
||||
return ((PSXCLK / 1000) * msPerRotation);
|
||||
}
|
||||
else
|
||||
|
@ -852,9 +854,10 @@ static u32 cdvdRotationalLatency(CDVD_MODE_TYPE mode)
|
|||
numSectors = 360000;
|
||||
break;
|
||||
}
|
||||
const float sectorSpeed = (((float)(cdvd.SeekToSector - offset) / numSectors) * 0.60f) + 0.40f;
|
||||
// CLV speeds are reversed, so the centre is the fastest position.
|
||||
const float sectorSpeed = (1.0f - (((float)(cdvd.SeekToSector - offset) / numSectors) * 0.60f)) + 0.40f;
|
||||
|
||||
const float rotationPerSecond = static_cast<float>(((mode == MODE_CDROM) ? CD_MAX_ROTATION_X1 : DVD_MAX_ROTATION_X1) * cdvd.Speed * sectorSpeed) / 60.0f;
|
||||
const float rotationPerSecond = static_cast<float>(((mode == MODE_CDROM) ? CD_MAX_ROTATION_X1 : DVD_MAX_ROTATION_X1) * std::min(static_cast<float>(cdvd.Speed), (mode == MODE_CDROM) ? 10.3f : 1.6f) * sectorSpeed) / 60.0f;
|
||||
const 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);
|
||||
|
@ -897,7 +900,7 @@ static uint cdvdBlockReadTime(CDVD_MODE_TYPE mode)
|
|||
}
|
||||
|
||||
// CLV Read Speed is constant
|
||||
float cycles = static_cast<float>(PSXCLK) / static_cast<float>(((mode == MODE_CDROM) ? CD_SECTORS_PERSECOND : DVD_SECTORS_PERSECOND) * cdvd.Speed);
|
||||
float cycles = static_cast<float>(PSXCLK) / static_cast<float>(((mode == MODE_CDROM) ? CD_SECTORS_PERSECOND : DVD_SECTORS_PERSECOND) * std::min(static_cast<float>(cdvd.Speed), (mode == MODE_CDROM) ? 10.3f : 1.6f));
|
||||
|
||||
return static_cast<int>(cycles);
|
||||
}
|
||||
|
@ -916,6 +919,7 @@ void cdvdReset()
|
|||
cdvd.BlockSize = 2064;
|
||||
cdvd.Action = cdvdAction_None;
|
||||
cdvd.ReadTime = cdvdBlockReadTime(MODE_DVDROM);
|
||||
cdvd.RotSpeed = cdvdRotationTime(MODE_DVDROM);
|
||||
|
||||
// If we are recording, always use the same RTC setting
|
||||
// for games that use the RTC to seed their RNG -- this is very important to be the same everytime!
|
||||
|
@ -1350,12 +1354,12 @@ __fi void cdvdReadInterrupt()
|
|||
}
|
||||
|
||||
// Returns the number of IOP cycles until the event completes.
|
||||
static uint cdvdStartSeek(uint newsector, CDVD_MODE_TYPE mode)
|
||||
static uint cdvdStartSeek(uint newsector, CDVD_MODE_TYPE mode, bool transition_to_CLV)
|
||||
{
|
||||
cdvd.SeekToSector = newsector;
|
||||
|
||||
uint delta = abs((s32)(cdvd.SeekToSector - cdvd.Sector));
|
||||
uint seektime;
|
||||
uint seektime = 0;
|
||||
bool isSeeking = cdvd.nCommand == N_CD_SEEK;
|
||||
|
||||
cdvdUpdateReady(CDVD_DRIVE_BUSY);
|
||||
|
@ -1366,7 +1370,20 @@ static uint cdvdStartSeek(uint newsector, CDVD_MODE_TYPE mode)
|
|||
// So In the case where it's seeking to data it will be Spinning (0x2) not reading (0x8) and Seeking (0x10, but because seeking is also spinning 0x2 is also set))
|
||||
// Update - Apparently all that was rubbish and some games don't like it. WRC was the one in this scenario which hated SEEK |ZPAUSE, so just putting it back to pause for now.
|
||||
// We should really run some tests for this behaviour.
|
||||
int drive_speed_change_cycles = 0;
|
||||
const int old_rotspeed = cdvd.RotSpeed;
|
||||
cdvd.RotSpeed = cdvdRotationTime(mode);
|
||||
|
||||
cdvd.ReadTime = cdvdBlockReadTime(mode);
|
||||
|
||||
if (cdvd.Spinning && transition_to_CLV)
|
||||
{
|
||||
const float old_rpm = (static_cast<float>(PSXCLK) / static_cast<float>(old_rotspeed)) * 60.0f;
|
||||
const float new_rpm = (static_cast<float>(PSXCLK) / static_cast<float>(cdvd.RotSpeed)) * 60.0f;
|
||||
// A rough cycles per RPM change based on 333ms for a full spin up.
|
||||
drive_speed_change_cycles = (PSXCLK / 1000) * (0.054950495049505f * std::abs(new_rpm - old_rpm));
|
||||
psxRegs.interrupt &= ~(1 << IopEvt_CdvdSectorReady);
|
||||
}
|
||||
cdvdUpdateStatus(CDVD_STATUS_SEEK);
|
||||
|
||||
if (!cdvd.Spinning)
|
||||
|
@ -1395,12 +1412,12 @@ static uint cdvdStartSeek(uint newsector, CDVD_MODE_TYPE mode)
|
|||
}
|
||||
isSeeking = true;
|
||||
}
|
||||
else
|
||||
else if(!drive_speed_change_cycles)
|
||||
{
|
||||
CDVD_LOG("CdSeek Begin > Contiguous block without seek - delta=%d sectors", delta);
|
||||
|
||||
// if delta > 0 it will read a new sector so the readInterrupt will account for this.
|
||||
seektime = 0;
|
||||
|
||||
isSeeking = false;
|
||||
|
||||
if (delta == 0)
|
||||
|
@ -1444,10 +1461,12 @@ static uint cdvdStartSeek(uint newsector, CDVD_MODE_TYPE mode)
|
|||
}
|
||||
}
|
||||
|
||||
seektime += drive_speed_change_cycles;
|
||||
|
||||
// Only do this on reads, the seek kind of accounts for this and then it reads the sectors after
|
||||
if ((delta || cdvd.Action == cdvdAction_Seek) && !isSeeking && !cdvd.nextSectorsBuffered)
|
||||
{
|
||||
const u32 rotationalLatency = cdvdRotationalLatency((CDVD_MODE_TYPE)cdvdIsDVD());
|
||||
const u32 rotationalLatency = cdvdRotationTime((CDVD_MODE_TYPE)cdvdIsDVD()) / 2; // Half it to average the rotational latency.
|
||||
//DevCon.Warning("%s rotational latency at sector %d is %d cycles", (cdvd.SpindlCtrl & CDVD_SPINDLE_CAV) ? "CAV" : "CLV", cdvd.SeekToSector, rotationalLatency);
|
||||
seektime += rotationalLatency + cdvd.ReadTime;
|
||||
CDVDSECTORREADY_INT(seektime);
|
||||
|
@ -1466,7 +1485,6 @@ static uint cdvdStartSeek(uint newsector, CDVD_MODE_TYPE mode)
|
|||
{
|
||||
CDVDSECTORREADY_INT(seektime);
|
||||
}
|
||||
|
||||
// Clear the action on the following command, so we can rotate after seek.
|
||||
if (cdvd.nCommand != N_CD_SEEK)
|
||||
cdvd.Action = cdvdAction_None;
|
||||
|
@ -1832,8 +1850,7 @@ static void cdvdWrite04(u8 rt)
|
|||
// spinup times if needed.
|
||||
cdvdUpdateReady(CDVD_DRIVE_BUSY);
|
||||
DevCon.Warning("CdStandby : %d", rt);
|
||||
cdvd.ReadTime = cdvdBlockReadTime((CDVD_MODE_TYPE)cdvdIsDVD());
|
||||
CDVD_INT(cdvdStartSeek(0, MODE_DVDROM));
|
||||
CDVD_INT(cdvdStartSeek(0, static_cast<CDVD_MODE_TYPE>(cdvdIsDVD()), false));
|
||||
// Might not seek, but makes sense since it does move to the inner most track
|
||||
// It's only temporary until the interrupt anyway when it sets itself ready
|
||||
cdvdUpdateStatus(CDVD_STATUS_SEEK);
|
||||
|
@ -1864,8 +1881,7 @@ static void cdvdWrite04(u8 rt)
|
|||
|
||||
case N_CD_SEEK: // CdSeek
|
||||
cdvdUpdateReady(CDVD_DRIVE_BUSY);
|
||||
cdvd.ReadTime = cdvdBlockReadTime((CDVD_MODE_TYPE)cdvdIsDVD());
|
||||
CDVD_INT(cdvdStartSeek(*(uint*)(cdvd.NCMDParam + 0), (CDVD_MODE_TYPE)cdvdIsDVD()));
|
||||
CDVD_INT(cdvdStartSeek(*reinterpret_cast<uint*>(cdvd.NCMDParam + 0), static_cast<CDVD_MODE_TYPE>(cdvdIsDVD()), false));
|
||||
cdvdUpdateStatus(CDVD_STATUS_SEEK);
|
||||
cdvd.Action = cdvdAction_Seek;
|
||||
break;
|
||||
|
@ -1924,12 +1940,6 @@ static void cdvdWrite04(u8 rt)
|
|||
break;
|
||||
}
|
||||
|
||||
if ((cdvd.SpindlCtrl & CDVD_SPINDLE_CAV) != (oldSpindleCtrl & CDVD_SPINDLE_CAV) || oldSpeed != cdvd.Speed)
|
||||
{
|
||||
CDVD_LOG("CdRead > Speed change, adding delay");
|
||||
cdvd.Spinning = false;
|
||||
}
|
||||
|
||||
if (cdvdIsDVD() && cdvd.NCMDParam[10] != 0)
|
||||
{
|
||||
ParamError = true;
|
||||
|
@ -1973,7 +1983,7 @@ static void cdvdWrite04(u8 rt)
|
|||
cdvd.Action = cdvdAction_Error;
|
||||
cdvdUpdateStatus(CDVD_STATUS_SEEK);
|
||||
cdvdUpdateReady(CDVD_DRIVE_BUSY);
|
||||
CDVD_INT(cdvdRotationalLatency((CDVD_MODE_TYPE)cdvdIsDVD()));
|
||||
CDVD_INT(cdvdRotationTime((CDVD_MODE_TYPE)cdvdIsDVD()));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1984,9 +1994,8 @@ static void cdvdWrite04(u8 rt)
|
|||
Console.WriteLn(Color_Gray, "CDRead: Reading Sector %07d (%03d Blocks of Size %d) at Speed=%dx(%s) Spindle=%x",
|
||||
cdvd.SeekToSector, cdvd.nSectors, cdvd.BlockSize, cdvd.Speed, (cdvd.SpindlCtrl & CDVD_SPINDLE_CAV) ? "CAV" : "CLV", cdvd.SpindlCtrl);
|
||||
|
||||
cdvd.ReadTime = cdvdBlockReadTime((CDVD_MODE_TYPE)cdvdIsDVD());
|
||||
CDVDREAD_INT(cdvdStartSeek(cdvd.SeekToSector, (CDVD_MODE_TYPE)cdvdIsDVD()));
|
||||
|
||||
CDVDREAD_INT(cdvdStartSeek(cdvd.SeekToSector, static_cast<CDVD_MODE_TYPE>(cdvdIsDVD()), !(cdvd.SpindlCtrl & CDVD_SPINDLE_CAV) && (oldSpindleCtrl & CDVD_SPINDLE_CAV)));
|
||||
cdvdUpdateReady(CDVD_DRIVE_BUSY);
|
||||
// Read-ahead by telling CDVD about the track now.
|
||||
// This helps improve performance on actual from-cd emulation
|
||||
// (ie, not using the hard drive)
|
||||
|
@ -2050,12 +2059,6 @@ static void cdvdWrite04(u8 rt)
|
|||
break;
|
||||
}
|
||||
|
||||
if ((cdvd.SpindlCtrl & CDVD_SPINDLE_CAV) != (oldSpindleCtrl & CDVD_SPINDLE_CAV) || oldSpeed != cdvd.Speed)
|
||||
{
|
||||
CDVD_LOG("CdRead > Speed change, adding delay");
|
||||
cdvd.Spinning = false;
|
||||
}
|
||||
|
||||
switch (cdvd.NCMDParam[10])
|
||||
{
|
||||
case 1:
|
||||
|
@ -2090,9 +2093,8 @@ static void cdvdWrite04(u8 rt)
|
|||
Console.WriteLn(Color_Gray, "CdAudioRead: Reading Sector %07d (%03d Blocks of Size %d) at Speed=%dx(%s) Spindle=%x",
|
||||
cdvd.Sector, cdvd.nSectors, cdvd.BlockSize, cdvd.Speed, (cdvd.SpindlCtrl & CDVD_SPINDLE_CAV) ? "CAV" : "CLV", cdvd.SpindlCtrl);
|
||||
|
||||
cdvd.ReadTime = cdvdBlockReadTime(MODE_CDROM);
|
||||
CDVDREAD_INT(cdvdStartSeek(cdvd.SeekToSector, MODE_CDROM));
|
||||
|
||||
CDVDREAD_INT(cdvdStartSeek(cdvd.SeekToSector, MODE_CDROM, !(cdvd.SpindlCtrl& CDVD_SPINDLE_CAV) && (oldSpindleCtrl& CDVD_SPINDLE_CAV)));
|
||||
cdvdUpdateReady(CDVD_DRIVE_BUSY);
|
||||
// Read-ahead by telling CDVD about the track now.
|
||||
// This helps improve performance on actual from-cd emulation
|
||||
// (ie, not using the hard drive)
|
||||
|
@ -2153,12 +2155,6 @@ static void cdvdWrite04(u8 rt)
|
|||
break;
|
||||
}
|
||||
|
||||
if ((cdvd.SpindlCtrl & CDVD_SPINDLE_CAV) != (oldSpindleCtrl & CDVD_SPINDLE_CAV) || oldSpeed != cdvd.Speed)
|
||||
{
|
||||
CDVD_LOG("DvdRead > Speed change, adding delay");
|
||||
cdvd.Spinning = false;
|
||||
}
|
||||
|
||||
if (cdvd.NCMDParam[10] != 0)
|
||||
ParamError = true;
|
||||
|
||||
|
@ -2182,7 +2178,7 @@ static void cdvdWrite04(u8 rt)
|
|||
cdvd.Action = cdvdAction_Error;
|
||||
cdvdUpdateStatus(CDVD_STATUS_SEEK);
|
||||
cdvdUpdateReady(CDVD_DRIVE_BUSY);
|
||||
CDVD_INT(cdvdRotationalLatency((CDVD_MODE_TYPE)cdvdIsDVD()));
|
||||
CDVD_INT(cdvdRotationTime((CDVD_MODE_TYPE)cdvdIsDVD()));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2193,9 +2189,8 @@ static void cdvdWrite04(u8 rt)
|
|||
Console.WriteLn(Color_Gray, "DvdRead: Reading Sector %07d (%03d Blocks of Size %d) at Speed=%dx(%s) SpindleCtrl=%x",
|
||||
cdvd.SeekToSector, cdvd.nSectors, cdvd.BlockSize, cdvd.Speed, (cdvd.SpindlCtrl & CDVD_SPINDLE_CAV) ? "CAV" : "CLV", cdvd.SpindlCtrl);
|
||||
|
||||
cdvd.ReadTime = cdvdBlockReadTime(MODE_DVDROM);
|
||||
CDVDREAD_INT(cdvdStartSeek(cdvd.SeekToSector, MODE_DVDROM));
|
||||
|
||||
CDVDREAD_INT(cdvdStartSeek(cdvd.SeekToSector, MODE_DVDROM, !(cdvd.SpindlCtrl & CDVD_SPINDLE_CAV) && (oldSpindleCtrl& CDVD_SPINDLE_CAV)));
|
||||
cdvdUpdateReady(CDVD_DRIVE_BUSY);
|
||||
// Read-ahead by telling CDVD about the track now.
|
||||
// This helps improve performance on actual from-cd emulation
|
||||
// (ie, not using the hard drive)
|
||||
|
|
|
@ -167,6 +167,7 @@ struct cdvdStruct
|
|||
u32 SeekToSector; // Holds the destination sector during seek operations.
|
||||
u32 MaxSector; // Current disc max sector.
|
||||
u32 ReadTime; // Avg. time to read one block of data (in Iop cycles)
|
||||
u32 RotSpeed; // Rotational Speed
|
||||
bool Spinning; // indicates if the Cdvd is spinning or needs a spinup delay
|
||||
cdvdTrayTimer Tray;
|
||||
u8 nextSectorsBuffered;
|
||||
|
|
|
@ -151,16 +151,13 @@ static const uint tbl_ContigiousSeekDelta[3] =
|
|||
16, // dual-layer DVD-ROM [currently unused]
|
||||
};
|
||||
|
||||
// Note: DVD read times are modified to be faster, because games seem to be a lot more
|
||||
// concerned with accurate(ish) seek delays and less concerned with actual block read speeds.
|
||||
// Translation: it's a minor speedhack :D
|
||||
|
||||
static const uint PSX_CD_READSPEED = 153600; // Bytes per second, rough values from outer CD (CAV).
|
||||
static const uint PSX_DVD_READSPEED = 1382400; // Bytes per second, rough values from outer DVD (CAV).
|
||||
|
||||
static const uint CD_SECTORS_PERSECOND = 75;
|
||||
static const uint DVD_SECTORS_PERSECOND = 675;
|
||||
|
||||
// Rotations per minute.
|
||||
static const uint CD_MIN_ROTATION_X1 = 214;
|
||||
static const uint CD_MAX_ROTATION_X1 = 497;
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ enum class FreezeAction
|
|||
// [SAVEVERSION+]
|
||||
// This informs the auto updater that the users savestates will be invalidated.
|
||||
|
||||
static const u32 g_SaveVersion = (0x9A42 << 16) | 0x0000;
|
||||
static const u32 g_SaveVersion = (0x9A43 << 16) | 0x0000;
|
||||
|
||||
|
||||
// the freezing data between submodules and core
|
||||
|
|
Loading…
Reference in New Issue