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.motor_on = HasMedia();
m_mode.bits = 0;
m_current_double_speed = false;
m_interrupt_enable_register = INTERRUPT_REGISTER_MASK;
m_interrupt_flag_register = 0;
m_pending_async_interrupt = 0;
@ -111,6 +112,7 @@ bool CDROM::DoState(StateWrapper& sw)
sw.Do(&m_status.bits);
sw.Do(&m_secondary_status.bits);
sw.Do(&m_mode.bits);
sw.Do(&m_current_double_speed);
sw.Do(&m_interrupt_enable_register);
sw.Do(&m_interrupt_flag_register);
sw.Do(&m_pending_async_interrupt);
@ -526,7 +528,7 @@ void CDROM::UpdateInterruptRequest()
m_interrupt_controller->InterruptRequest(InterruptController::IRQ::CDROM);
}
TickCount CDROM::GetAckDelayForCommand(Command command) const
TickCount CDROM::GetAckDelayForCommand(Command command)
{
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;
}
TickCount CDROM::GetTicksForRead() const
TickCount CDROM::GetTicksForRead()
{
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 new_lba = m_setloc_position.ToLBA();
const CDImage::LBA current_lba = m_secondary_status.motor_on ? m_last_requested_sector : 0;
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.
TickCount ticks = std::max<TickCount>(20000, lba_diff * MASTER_CLOCK * 1000 / (72 * 60 * 75) / 1000);
if (!m_secondary_status.motor_on)
ticks += MASTER_CLOCK;
else if (m_drive_state == DriveState::Idle) // paused
ticks += 1237952 << (BoolToUInt8(!m_mode.double_speed));
if (lba_diff >= 2550)
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);
return ticks;
@ -631,7 +642,7 @@ void CDROM::ExecuteCommand()
SendACKAndStat();
m_drive_state = DriveState::ReadingID;
m_drive_event->Schedule(18000);
m_drive_event->Schedule(GetTicksForSeek(0) + GetTicksForRead());
EndCommand();
return;
@ -818,7 +829,7 @@ void CDROM::ExecuteCommand()
SendACKAndStat();
m_drive_state = DriveState::Resetting;
m_drive_event->Schedule(80000);
m_drive_event->Schedule(400000);
EndCommand();
return;
@ -837,7 +848,7 @@ void CDROM::ExecuteCommand()
SendACKAndStat();
m_drive_state = DriveState::Resetting;
m_drive_event->Schedule(80000);
m_drive_event->Schedule(MASTER_CLOCK);
}
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,
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.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_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);
}
@ -1394,13 +1406,20 @@ void CDROM::DoIDRead()
{
flags_byte |= (1 << 6); // Disc Missing
}
else if (m_system->GetSettings().cdrom_region_check &&
else
{
// this is where it would get read from the start of the disc?
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.Push(stat_byte);

View File

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

View File

@ -2,4 +2,4 @@
#include "types.h"
static constexpr u32 SAVE_STATE_MAGIC = 0x43435544;
static constexpr u32 SAVE_STATE_VERSION = 21;
static constexpr u32 SAVE_STATE_VERSION = 22;