mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-26 23:55:40 +00:00
CDROM: Improve simulation of seek timing
This commit is contained in:
parent
2c19c7ce57
commit
67344070ea
|
@ -264,6 +264,7 @@ bool CDROM::DoState(StateWrapper& sw)
|
||||||
sw.Do(&m_seek_end_lba);
|
sw.Do(&m_seek_end_lba);
|
||||||
sw.DoEx(&m_physical_lba, 49, m_current_lba);
|
sw.DoEx(&m_physical_lba, 49, m_current_lba);
|
||||||
sw.DoEx(&m_physical_lba_update_tick, 49, static_cast<u32>(0));
|
sw.DoEx(&m_physical_lba_update_tick, 49, static_cast<u32>(0));
|
||||||
|
sw.DoEx(&m_physical_lba_update_carry, 54, static_cast<u32>(0));
|
||||||
sw.Do(&m_setloc_pending);
|
sw.Do(&m_setloc_pending);
|
||||||
sw.Do(&m_read_after_seek);
|
sw.Do(&m_read_after_seek);
|
||||||
sw.Do(&m_play_after_seek);
|
sw.Do(&m_play_after_seek);
|
||||||
|
@ -779,7 +780,9 @@ TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba, bool ignore_speed_change)
|
||||||
else
|
else
|
||||||
UpdatePhysicalPosition(false);
|
UpdatePhysicalPosition(false);
|
||||||
|
|
||||||
const TickCount tps = System::MASTER_CLOCK;
|
const u32 ticks_per_sector =
|
||||||
|
m_mode.double_speed ? static_cast<u32>(System::MASTER_CLOCK / 150) : static_cast<u32>(System::MASTER_CLOCK / 75);
|
||||||
|
const u32 ticks_per_second = static_cast<u32>(System::MASTER_CLOCK);
|
||||||
const CDImage::LBA current_lba = m_secondary_status.motor_on ? (IsSeeking() ? m_seek_end_lba : m_physical_lba) : 0;
|
const CDImage::LBA current_lba = m_secondary_status.motor_on ? (IsSeeking() ? m_seek_end_lba : m_physical_lba) : 0;
|
||||||
const u32 lba_diff = static_cast<u32>((new_lba > current_lba) ? (new_lba - current_lba) : (current_lba - new_lba));
|
const u32 lba_diff = static_cast<u32>((new_lba > current_lba) ? (new_lba - current_lba) : (current_lba - new_lba));
|
||||||
|
|
||||||
|
@ -794,22 +797,33 @@ TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba, bool ignore_speed_change)
|
||||||
|
|
||||||
if (lba_diff < 32)
|
if (lba_diff < 32)
|
||||||
{
|
{
|
||||||
ticks += static_cast<u32>(GetTicksForRead()) * std::min<u32>(BASE_SECTORS_PER_TRACK, lba_diff);
|
ticks += ticks_per_sector * std::min<u32>(5u, lba_diff);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// This is a very inaccurate model.
|
// This is a still not a very accurate model, but it's roughly in line with the behavior of hardware tests.
|
||||||
// TODO: Use the actual time for track jumps.
|
const float disc_distance = 0.2323384936f * std::log(static_cast<float>((new_lba / 4500) + 1u));
|
||||||
|
|
||||||
// 1000ms for the whole disc
|
float seconds;
|
||||||
ticks += std::max<u32>(
|
if (lba_diff <= CDImage::FRAMES_PER_SECOND)
|
||||||
20000, static_cast<u32>(((static_cast<u64>(lba_diff) * static_cast<u64>(tps) * static_cast<u64>(1000)) /
|
{
|
||||||
(72 * CDImage::FRAMES_PER_MINUTE)) /
|
// 30ms + (diff * 30ms) + (disc distance * 30ms)
|
||||||
1000));
|
seconds = 0.03f + ((static_cast<float>(lba_diff) / static_cast<float>(CDImage::FRAMES_PER_SECOND)) * 0.03f) +
|
||||||
|
(disc_distance * 0.03f);
|
||||||
|
}
|
||||||
|
else if (lba_diff <= CDImage::FRAMES_PER_MINUTE)
|
||||||
|
{
|
||||||
|
// 150ms + (diff * 30ms) + (disc distance * 50ms)
|
||||||
|
seconds = 0.15f + ((static_cast<float>(lba_diff) / static_cast<float>(CDImage::FRAMES_PER_MINUTE)) * 0.03f) +
|
||||||
|
(disc_distance * 0.05f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 200ms + (diff * 500ms)
|
||||||
|
seconds = 0.2f + ((static_cast<float>(lba_diff) / static_cast<float>(72 * CDImage::FRAMES_PER_MINUTE)) * 0.4f);
|
||||||
|
}
|
||||||
|
|
||||||
// 300ms for non-short seeks (1 minute)
|
ticks += static_cast<u32>(seconds * static_cast<float>(ticks_per_second));
|
||||||
if (lba_diff >= CDImage::FRAMES_PER_MINUTE)
|
|
||||||
ticks += static_cast<u32>((u64(tps) * 300) / 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_drive_state == DriveState::ChangingSpeedOrTOCRead && !ignore_speed_change)
|
if (m_drive_state == DriveState::ChangingSpeedOrTOCRead && !ignore_speed_change)
|
||||||
|
@ -818,12 +832,13 @@ TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba, bool ignore_speed_change)
|
||||||
const TickCount remaining_change_ticks = m_drive_event->GetTicksUntilNextExecution();
|
const TickCount remaining_change_ticks = m_drive_event->GetTicksUntilNextExecution();
|
||||||
ticks += remaining_change_ticks;
|
ticks += remaining_change_ticks;
|
||||||
|
|
||||||
Log_DevPrintf("Seek time for %u LBAs: %d (%d for speed change/implicit TOC read)", lba_diff, ticks,
|
Log_DevPrintf("Seek time for %u LBAs: %d (%.3f ms) (%d for speed change/implicit TOC read)", lba_diff, ticks,
|
||||||
remaining_change_ticks);
|
(static_cast<float>(ticks) / static_cast<float>(ticks_per_second)) * 1000.0f, remaining_change_ticks);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log_DevPrintf("Seek time for %u LBAs: %d", lba_diff, ticks);
|
Log_DevPrintf("Seek time for %u LBAs: %d (%.3f ms)", lba_diff, ticks,
|
||||||
|
(static_cast<float>(ticks) / static_cast<float>(ticks_per_second)) * 1000.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_settings.cdrom_seek_speedup > 1)
|
if (g_settings.cdrom_seek_speedup > 1)
|
||||||
|
@ -849,7 +864,7 @@ TickCount CDROM::GetTicksForTOCRead()
|
||||||
if (!HasMedia())
|
if (!HasMedia())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return System::GetTicksPerSecond();
|
return System::GetTicksPerSecond() / 2u;
|
||||||
}
|
}
|
||||||
|
|
||||||
CDImage::LBA CDROM::GetNextSectorToBeRead()
|
CDImage::LBA CDROM::GetNextSectorToBeRead()
|
||||||
|
@ -1109,7 +1124,7 @@ void CDROM::ExecuteCommand(TickCount ticks_late)
|
||||||
|
|
||||||
m_async_command_parameter = session;
|
m_async_command_parameter = session;
|
||||||
m_drive_state = DriveState::ChangingSession;
|
m_drive_state = DriveState::ChangingSession;
|
||||||
m_drive_event->Schedule(System::GetTicksPerSecond() / 2); // half a second
|
m_drive_event->Schedule(GetTicksForTOCRead());
|
||||||
}
|
}
|
||||||
|
|
||||||
EndCommand();
|
EndCommand();
|
||||||
|
@ -1863,6 +1878,7 @@ void CDROM::UpdatePositionWhileSeeking()
|
||||||
m_current_lba = current_lba;
|
m_current_lba = current_lba;
|
||||||
m_physical_lba = current_lba;
|
m_physical_lba = current_lba;
|
||||||
m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter();
|
m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter();
|
||||||
|
m_physical_lba_update_carry = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDROM::UpdatePhysicalPosition(bool update_logical)
|
void CDROM::UpdatePhysicalPosition(bool update_logical)
|
||||||
|
@ -1874,15 +1890,31 @@ void CDROM::UpdatePhysicalPosition(bool update_logical)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 diff = ticks - m_physical_lba_update_tick;
|
const u32 ticks_per_read = GetTicksForRead();
|
||||||
const u32 sector_diff = diff / GetTicksForRead();
|
const u32 diff = ticks - m_physical_lba_update_tick + m_physical_lba_update_carry;
|
||||||
|
const u32 sector_diff = diff / ticks_per_read;
|
||||||
|
const u32 carry = diff % ticks_per_read;
|
||||||
if (sector_diff > 0)
|
if (sector_diff > 0)
|
||||||
{
|
{
|
||||||
const CDImage::LBA hold_offset = m_last_sector_header_valid ? 2 : 0;
|
CDImage::LBA hold_offset;
|
||||||
const CDImage::LBA sectors_per_track = BASE_SECTORS_PER_TRACK + hold_offset;
|
CDImage::LBA sectors_per_track;
|
||||||
|
|
||||||
|
// hardware tests show that it holds much closer to the target sector in logical mode
|
||||||
|
if (m_last_sector_header_valid)
|
||||||
|
{
|
||||||
|
hold_offset = 2;
|
||||||
|
sectors_per_track = 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hold_offset = 0;
|
||||||
|
sectors_per_track =
|
||||||
|
static_cast<CDImage::LBA>(7.0f + 2.811844405f * std::log(static_cast<float>(m_current_lba / 4500u) + 1u));
|
||||||
|
}
|
||||||
|
|
||||||
const CDImage::LBA hold_position = m_current_lba + hold_offset;
|
const CDImage::LBA hold_position = m_current_lba + hold_offset;
|
||||||
const CDImage::LBA base =
|
const CDImage::LBA base =
|
||||||
(hold_position >= sectors_per_track) ? (hold_position - sectors_per_track) : hold_position;
|
(hold_position >= (sectors_per_track - 1)) ? (hold_position - (sectors_per_track - 1)) : hold_position;
|
||||||
if (m_physical_lba < base)
|
if (m_physical_lba < base)
|
||||||
m_physical_lba = base;
|
m_physical_lba = base;
|
||||||
|
|
||||||
|
@ -1915,6 +1947,7 @@ void CDROM::UpdatePhysicalPosition(bool update_logical)
|
||||||
}
|
}
|
||||||
|
|
||||||
m_physical_lba_update_tick = ticks;
|
m_physical_lba_update_tick = ticks;
|
||||||
|
m_physical_lba_update_carry = carry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1933,6 +1966,7 @@ void CDROM::SetHoldPosition(CDImage::LBA lba, bool update_subq)
|
||||||
m_current_lba = lba;
|
m_current_lba = lba;
|
||||||
m_physical_lba = lba;
|
m_physical_lba = lba;
|
||||||
m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter();
|
m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter();
|
||||||
|
m_physical_lba_update_carry = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDROM::DoShellOpenComplete(TickCount ticks_late)
|
void CDROM::DoShellOpenComplete(TickCount ticks_late)
|
||||||
|
@ -2000,6 +2034,7 @@ bool CDROM::CompleteSeek()
|
||||||
m_current_lba = m_reader.GetLastReadSector();
|
m_current_lba = m_reader.GetLastReadSector();
|
||||||
m_physical_lba = m_current_lba;
|
m_physical_lba = m_current_lba;
|
||||||
m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter();
|
m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter();
|
||||||
|
m_physical_lba_update_carry = 0;
|
||||||
return seek_okay;
|
return seek_okay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2174,6 +2209,7 @@ void CDROM::DoSectorRead()
|
||||||
m_current_lba = m_reader.GetLastReadSector();
|
m_current_lba = m_reader.GetLastReadSector();
|
||||||
m_physical_lba = m_current_lba;
|
m_physical_lba = m_current_lba;
|
||||||
m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter();
|
m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter();
|
||||||
|
m_physical_lba_update_carry = 0;
|
||||||
|
|
||||||
const CDImage::SubChannelQ& subq = m_reader.GetSectorSubQ();
|
const CDImage::SubChannelQ& subq = m_reader.GetSectorSubQ();
|
||||||
const bool subq_valid = subq.IsCRCValid();
|
const bool subq_valid = subq.IsCRCValid();
|
||||||
|
|
|
@ -83,10 +83,7 @@ private:
|
||||||
MOTOR_ON_RESPONSE_TICKS = 400000,
|
MOTOR_ON_RESPONSE_TICKS = 400000,
|
||||||
|
|
||||||
MAX_FAST_FORWARD_RATE = 12,
|
MAX_FAST_FORWARD_RATE = 12,
|
||||||
FAST_FORWARD_RATE_STEP = 4,
|
FAST_FORWARD_RATE_STEP = 4
|
||||||
|
|
||||||
// Actually varies depending the distance into the disc.
|
|
||||||
BASE_SECTORS_PER_TRACK = 9,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr u8 INTERRUPT_REGISTER_MASK = 0x1F;
|
static constexpr u8 INTERRUPT_REGISTER_MASK = 0x1F;
|
||||||
|
@ -342,6 +339,7 @@ private:
|
||||||
CDImage::LBA m_seek_end_lba{};
|
CDImage::LBA m_seek_end_lba{};
|
||||||
CDImage::LBA m_physical_lba{}; // current position of the disc with respect to time
|
CDImage::LBA m_physical_lba{}; // current position of the disc with respect to time
|
||||||
u32 m_physical_lba_update_tick = 0;
|
u32 m_physical_lba_update_tick = 0;
|
||||||
|
u32 m_physical_lba_update_carry = 0;
|
||||||
bool m_setloc_pending = false;
|
bool m_setloc_pending = false;
|
||||||
bool m_read_after_seek = false;
|
bool m_read_after_seek = false;
|
||||||
bool m_play_after_seek = false;
|
bool m_play_after_seek = false;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
static constexpr u32 SAVE_STATE_MAGIC = 0x43435544;
|
static constexpr u32 SAVE_STATE_MAGIC = 0x43435544;
|
||||||
static constexpr u32 SAVE_STATE_VERSION = 53;
|
static constexpr u32 SAVE_STATE_VERSION = 54;
|
||||||
static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42;
|
static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42;
|
||||||
|
|
||||||
static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);
|
static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);
|
||||||
|
|
Loading…
Reference in a new issue