CDROM: Handle repeated SeekL to same target
Fixes more lockups in Resident Evil 3.
This commit is contained in:
parent
e683c89770
commit
c25c0067af
|
@ -74,6 +74,8 @@ enum : u32
|
|||
|
||||
static constexpr u8 INTERRUPT_REGISTER_MASK = 0x1F;
|
||||
|
||||
static constexpr TickCount MIN_SEEK_TICKS = 30000;
|
||||
|
||||
enum class Interrupt : u8
|
||||
{
|
||||
DataReady = 0x01,
|
||||
|
@ -1557,10 +1559,8 @@ u32 CDROM::GetSectorsPerTrack(CDImage::LBA lba)
|
|||
|
||||
TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba, bool ignore_speed_change)
|
||||
{
|
||||
static constexpr TickCount MIN_TICKS = 30000;
|
||||
|
||||
if (g_settings.cdrom_seek_speedup == 0)
|
||||
return MIN_TICKS;
|
||||
return System::ScaleTicksToOverclock(MIN_SEEK_TICKS);
|
||||
|
||||
u32 ticks = 0;
|
||||
|
||||
|
@ -1630,7 +1630,7 @@ TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba, bool ignore_speed_change)
|
|||
}
|
||||
|
||||
if (g_settings.cdrom_seek_speedup > 1)
|
||||
ticks = std::max<u32>(ticks / g_settings.cdrom_seek_speedup, MIN_TICKS);
|
||||
ticks = std::max<u32>(ticks / g_settings.cdrom_seek_speedup, MIN_SEEK_TICKS);
|
||||
|
||||
if (s_state.drive_state == DriveState::ChangingSpeedOrTOCRead && !ignore_speed_change)
|
||||
{
|
||||
|
@ -2789,7 +2789,23 @@ void CDROM::BeginSeeking(bool logical, bool read_after_seek, bool play_after_see
|
|||
logical ? "logical" : "physical");
|
||||
|
||||
const CDImage::LBA seek_lba = s_state.setloc_position.ToLBA();
|
||||
const TickCount seek_time = GetTicksForSeek(seek_lba, play_after_seek);
|
||||
TickCount seek_time;
|
||||
|
||||
// Yay for edge cases. If we repeatedly send SeekL to the same target before a new sector is read, it should complete
|
||||
// nearly instantly, because it's looking for a valid target of -2. See the note in CompleteSeek(). We gate this with
|
||||
// the seek target in case another read happened in the interim. Test case: Resident Evil 3.
|
||||
if (logical && !read_after_seek && s_state.current_subq_lba == (seek_lba - SUBQ_SECTOR_SKEW) &&
|
||||
s_state.seek_end_lba == seek_lba &&
|
||||
(System::GetGlobalTickCounter() - s_state.subq_lba_update_tick) < static_cast<GlobalTicks>(GetTicksForRead()))
|
||||
{
|
||||
DEV_COLOR_LOG(StrongCyan, "Completing seek instantly due to not passing target {}.",
|
||||
LBAToMSFString(seek_lba - SUBQ_SECTOR_SKEW));
|
||||
seek_time = MIN_SEEK_TICKS;
|
||||
}
|
||||
else
|
||||
{
|
||||
seek_time = GetTicksForSeek(seek_lba, play_after_seek);
|
||||
}
|
||||
|
||||
ClearCommandSecondResponse();
|
||||
ClearAsyncInterrupt();
|
||||
|
|
Loading…
Reference in New Issue