CDROM: Add timing for speed changes/adjust seek timing

This makes the BIOS take longer to load the executable off the disc,
giving the sound effects longer to fade out and reducing the overlap
with the game.
This commit is contained in:
Connor McLaughlin 2020-04-11 00:40:39 +10:00
parent 809b9f89ca
commit 05e4e7d262
3 changed files with 43 additions and 23 deletions

View file

@ -50,6 +50,7 @@ void CDROM::SoftReset()
m_secondary_status.bits = 0; m_secondary_status.bits = 0;
m_secondary_status.motor_on = HasMedia(); m_secondary_status.motor_on = HasMedia();
m_mode.bits = 0; m_mode.bits = 0;
m_current_double_speed = false;
m_interrupt_enable_register = INTERRUPT_REGISTER_MASK; m_interrupt_enable_register = INTERRUPT_REGISTER_MASK;
m_interrupt_flag_register = 0; m_interrupt_flag_register = 0;
m_pending_async_interrupt = 0; m_pending_async_interrupt = 0;
@ -111,6 +112,7 @@ bool CDROM::DoState(StateWrapper& sw)
sw.Do(&m_status.bits); sw.Do(&m_status.bits);
sw.Do(&m_secondary_status.bits); sw.Do(&m_secondary_status.bits);
sw.Do(&m_mode.bits); sw.Do(&m_mode.bits);
sw.Do(&m_current_double_speed);
sw.Do(&m_interrupt_enable_register); sw.Do(&m_interrupt_enable_register);
sw.Do(&m_interrupt_flag_register); sw.Do(&m_interrupt_flag_register);
sw.Do(&m_pending_async_interrupt); sw.Do(&m_pending_async_interrupt);
@ -526,7 +528,7 @@ void CDROM::UpdateInterruptRequest()
m_interrupt_controller->InterruptRequest(InterruptController::IRQ::CDROM); m_interrupt_controller->InterruptRequest(InterruptController::IRQ::CDROM);
} }
TickCount CDROM::GetAckDelayForCommand(Command command) const TickCount CDROM::GetAckDelayForCommand(Command command)
{ {
if (command == Command::Init) if (command == Command::Init)
{ {
@ -541,27 +543,36 @@ TickCount CDROM::GetAckDelayForCommand(Command command) const
return HasMedia() ? default_ack_delay_with_disc : default_ack_delay_no_disc; return HasMedia() ? default_ack_delay_with_disc : default_ack_delay_no_disc;
} }
TickCount CDROM::GetTicksForRead() const TickCount CDROM::GetTicksForRead()
{ {
return m_mode.double_speed ? (MASTER_CLOCK / 150) : (MASTER_CLOCK / 75); return m_mode.double_speed ? (MASTER_CLOCK / 150) : (MASTER_CLOCK / 75);
} }
TickCount CDROM::GetTicksForSeek() const TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba)
{ {
const CDImage::LBA current_lba = m_secondary_status.motor_on ? m_reader.GetLastReadSector() : 0; const CDImage::LBA current_lba = m_secondary_status.motor_on ? m_last_requested_sector : 0;
const CDImage::LBA new_lba = m_setloc_position.ToLBA();
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));
// const TickCount ticks = static_cast<TickCount>(20000 + lba_diff * 100);
// Formula from Mednafen. // Formula from Mednafen.
TickCount ticks = std::max<TickCount>(20000, lba_diff * MASTER_CLOCK * 1000 / (72 * 60 * 75) / 1000); TickCount ticks = std::max<TickCount>(20000, lba_diff * MASTER_CLOCK * 1000 / (72 * 60 * 75) / 1000);
if (!m_secondary_status.motor_on) if (!m_secondary_status.motor_on)
ticks += MASTER_CLOCK; ticks += MASTER_CLOCK;
else if (m_drive_state == DriveState::Idle) // paused
ticks += 1237952 << (BoolToUInt8(!m_mode.double_speed));
if (lba_diff >= 2550) if (lba_diff >= 2550)
ticks += static_cast<TickCount>(u64(MASTER_CLOCK) * 300 / 1000); ticks += static_cast<TickCount>(u64(MASTER_CLOCK) * 300 / 1000);
else if (m_drive_state == DriveState::Idle) // paused
ticks += 1237952 << (BoolToUInt8(!m_mode.double_speed));
else if (lba_diff >= 3 && lba_diff < 12)
ticks += MASTER_CLOCK / (75 << (BoolToUInt8(!m_mode.double_speed)) << 2);
if (m_mode.double_speed != m_current_double_speed)
{
Log_DevPrintf("Switched from %s to %s speed", m_current_double_speed ? "double" : "single",
m_mode.double_speed ? "double" : "single");
m_current_double_speed = m_mode.double_speed;
// Approximate time for the motor to change speed?
ticks += static_cast<u32>(static_cast<double>(MASTER_CLOCK) * 1.5);
}
Log_DevPrintf("Seek time for %u LBAs: %d", lba_diff, ticks); Log_DevPrintf("Seek time for %u LBAs: %d", lba_diff, ticks);
return ticks; return ticks;
@ -631,7 +642,7 @@ void CDROM::ExecuteCommand()
SendACKAndStat(); SendACKAndStat();
m_drive_state = DriveState::ReadingID; m_drive_state = DriveState::ReadingID;
m_drive_event->Schedule(18000); m_drive_event->Schedule(GetTicksForSeek(0) + GetTicksForRead());
EndCommand(); EndCommand();
return; return;
@ -818,7 +829,7 @@ void CDROM::ExecuteCommand()
SendACKAndStat(); SendACKAndStat();
m_drive_state = DriveState::Resetting; m_drive_state = DriveState::Resetting;
m_drive_event->Schedule(80000); m_drive_event->Schedule(400000);
EndCommand(); EndCommand();
return; return;
@ -837,7 +848,7 @@ void CDROM::ExecuteCommand()
SendACKAndStat(); SendACKAndStat();
m_drive_state = DriveState::Resetting; m_drive_state = DriveState::Resetting;
m_drive_event->Schedule(80000); m_drive_event->Schedule(MASTER_CLOCK);
} }
EndCommand(); EndCommand();
@ -1218,7 +1229,8 @@ void CDROM::BeginSeeking(bool logical, bool read_after_seek, bool play_after_see
Log_DebugPrintf("Seeking to [%02u:%02u:%02u] (LBA %u) (%s)", m_setloc_position.minute, m_setloc_position.second, Log_DebugPrintf("Seeking to [%02u:%02u:%02u] (LBA %u) (%s)", m_setloc_position.minute, m_setloc_position.second,
m_setloc_position.frame, m_setloc_position.ToLBA(), logical ? "logical" : "physical"); m_setloc_position.frame, m_setloc_position.ToLBA(), logical ? "logical" : "physical");
const TickCount seek_time = GetTicksForSeek(); const CDImage::LBA seek_lba = m_setloc_position.ToLBA();
const TickCount seek_time = GetTicksForSeek(seek_lba);
m_secondary_status.ClearActiveBits(); m_secondary_status.ClearActiveBits();
m_secondary_status.motor_on = true; m_secondary_status.motor_on = true;
@ -1227,7 +1239,7 @@ void CDROM::BeginSeeking(bool logical, bool read_after_seek, bool play_after_see
m_drive_state = logical ? DriveState::SeekingLogical : DriveState::SeekingPhysical; m_drive_state = logical ? DriveState::SeekingLogical : DriveState::SeekingPhysical;
m_drive_event->SetIntervalAndSchedule(seek_time); m_drive_event->SetIntervalAndSchedule(seek_time);
m_last_requested_sector = m_setloc_position.ToLBA(); m_last_requested_sector = seek_lba;
m_reader.QueueReadSector(m_last_requested_sector); m_reader.QueueReadSector(m_last_requested_sector);
} }
@ -1394,12 +1406,19 @@ void CDROM::DoIDRead()
{ {
flags_byte |= (1 << 6); // Disc Missing flags_byte |= (1 << 6); // Disc Missing
} }
else if (m_system->GetSettings().cdrom_region_check && else
(m_disc_region == DiscRegion::Other ||
m_system->GetRegion() != System::GetConsoleRegionForDiscRegion(m_disc_region)))
{ {
stat_byte |= STAT_ID_ERROR; // this is where it would get read from the start of the disc?
flags_byte |= (1 << 7); // Unlicensed m_last_requested_sector = 0;
m_reader.QueueReadSector(m_last_requested_sector);
if (m_system->GetSettings().cdrom_region_check &&
(m_disc_region == DiscRegion::Other ||
m_system->GetRegion() != System::GetConsoleRegionForDiscRegion(m_disc_region)))
{
stat_byte |= STAT_ID_ERROR;
flags_byte |= (1 << 7); // Unlicensed
}
} }
m_async_response_fifo.Clear(); m_async_response_fifo.Clear();

View file

@ -210,9 +210,9 @@ private:
void UpdateStatusRegister(); void UpdateStatusRegister();
void UpdateInterruptRequest(); void UpdateInterruptRequest();
TickCount GetAckDelayForCommand(Command command) const; TickCount GetAckDelayForCommand(Command command);
TickCount GetTicksForRead() const; TickCount GetTicksForRead();
TickCount GetTicksForSeek() const; TickCount GetTicksForSeek(CDImage::LBA new_lba);
void BeginCommand(Command command); // also update status register void BeginCommand(Command command); // also update status register
void EndCommand(); // also updates status register void EndCommand(); // also updates status register
void AbortCommand(); void AbortCommand();
@ -253,6 +253,7 @@ private:
StatusRegister m_status = {}; StatusRegister m_status = {};
SecondaryStatusRegister m_secondary_status = {}; SecondaryStatusRegister m_secondary_status = {};
ModeRegister m_mode = {}; ModeRegister m_mode = {};
bool m_current_double_speed = false;
u8 m_interrupt_enable_register = INTERRUPT_REGISTER_MASK; u8 m_interrupt_enable_register = INTERRUPT_REGISTER_MASK;
u8 m_interrupt_flag_register = 0; u8 m_interrupt_flag_register = 0;

View file

@ -2,4 +2,4 @@
#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 = 21; static constexpr u32 SAVE_STATE_VERSION = 22;