diff --git a/src/core/cdrom.cpp b/src/core/cdrom.cpp index 35ae863a1..ab2d9cdde 100644 --- a/src/core/cdrom.cpp +++ b/src/core/cdrom.cpp @@ -80,8 +80,14 @@ void CDROM::Initialize() { m_command_event = TimingEvents::CreateTimingEvent( "CDROM Command Event", 1, 1, - [](void* param, TickCount ticks, TickCount ticks_late) { static_cast(param)->ExecuteCommand(); }, this, - false); + [](void* param, TickCount ticks, TickCount ticks_late) { static_cast(param)->ExecuteCommand(ticks_late); }, + this, false); + m_command_second_response_event = TimingEvents::CreateTimingEvent( + "CDROM Command Second Response Event", 1, 1, + [](void* param, TickCount ticks, TickCount ticks_late) { + static_cast(param)->ExecuteCommandSecondResponse(ticks_late); + }, + this, false); m_drive_event = TimingEvents::CreateTimingEvent( "CDROM Drive Event", 1, 1, [](void* param, TickCount ticks, TickCount ticks_late) { static_cast(param)->ExecuteDrive(ticks_late); }, @@ -105,32 +111,26 @@ void CDROM::Reset() { SoftReset(); - // this should be reading sector 0 - m_reader.WaitForReadToComplete(); - if (m_reader.GetSectorSubQ().IsCRCValid()) - m_last_subq = m_reader.GetSectorSubQ(); + SetHoldPosition(0, true); } void CDROM::SoftReset() { m_command = Command::None; m_command_event->Deactivate(); - m_drive_state = DriveState::Idle; - m_drive_event->Deactivate(); + ClearCommandSecondResponse(); + ClearDriveState(); m_status.bits = 0; m_secondary_status.bits = 0; m_secondary_status.motor_on = CanReadMedia(); m_secondary_status.shell_open = !CanReadMedia(); m_mode.bits = 0; + m_mode.read_raw_sector = true; m_current_double_speed = false; m_interrupt_enable_register = INTERRUPT_REGISTER_MASK; m_interrupt_flag_register = 0; m_pending_async_interrupt = 0; m_setloc_position = {}; - m_current_lba = 0; - ResetPhysicalPosition(); - if (m_reader.HasMedia()) - m_reader.QueueReadSector(m_current_lba); m_seek_start_lba = 0; m_seek_end_lba = 0; m_setloc_pending = false; @@ -175,6 +175,7 @@ void CDROM::SoftReset() bool CDROM::DoState(StateWrapper& sw) { sw.Do(&m_command); + sw.DoEx(&m_command_second_response, 53, Command::None); sw.Do(&m_drive_state); sw.Do(&m_status.bits); sw.Do(&m_secondary_status.bits); @@ -276,19 +277,10 @@ void CDROM::InsertMedia(std::unique_ptr media) // motor automatically spins up if (m_drive_state != DriveState::ShellOpening) - { - m_drive_state = DriveState::SpinningUp; - m_drive_event->Schedule(System::GetTicksPerSecond()); - } - - // reading TOC? interestingly this doesn't work for GetlocL though... - CDImage::SubChannelQ subq; - if (media->Seek(0) && media->ReadRawSector(nullptr, &subq) && subq.IsCRCValid()) - m_last_subq = subq; + StartMotor(); m_reader.SetMedia(std::move(media)); - m_current_lba = 0; - ResetPhysicalPosition(); + SetHoldPosition(0, true); } std::unique_ptr CDROM::RemoveMedia(bool force /* = false */) @@ -309,10 +301,10 @@ std::unique_ptr CDROM::RemoveMedia(bool force /* = false */) m_disc_region = DiscRegion::Other; // If the drive was doing anything, we need to abort the command. - m_drive_state = DriveState::Idle; + ClearDriveState(); + ClearCommandSecondResponse(); m_command = Command::None; m_command_event->Deactivate(); - m_drive_event->Deactivate(); // The console sends an interrupt when the shell is opened regardless of whether a command was executing. if (HasPendingAsyncInterrupt()) @@ -675,6 +667,21 @@ TickCount CDROM::GetAckDelayForCommand(Command command) return CanReadMedia() ? default_ack_delay_with_disc : default_ack_delay_no_disc; } +TickCount CDROM::GetTicksForSpinUp() +{ + // 1 second + return System::GetTicksPerSecond(); +} + +TickCount CDROM::GetTicksForIDRead() +{ + TickCount ticks = ID_READ_TICKS; + if (m_drive_state == DriveState::SpinningUp) + ticks += m_drive_event->GetTicksUntilNextExecution(); + + return ticks; +} + TickCount CDROM::GetTicksForRead() { const TickCount tps = System::GetTicksPerSecond(); @@ -705,12 +712,10 @@ TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba) // Motor spin-up time. if (!m_secondary_status.motor_on) { - ticks += (m_drive_state == DriveState::SpinningUp) ? m_drive_event->GetTicksUntilNextExecution() : tps; + ticks += + (m_drive_state == DriveState::SpinningUp) ? m_drive_event->GetTicksUntilNextExecution() : GetTicksForSpinUp(); if (m_drive_state == DriveState::ShellOpening || m_drive_state == DriveState::SpinningUp) - { - m_drive_state = DriveState::Idle; - m_drive_event->Deactivate(); - } + ClearDriveState(); } if (lba_diff >= 2550) @@ -810,10 +815,11 @@ void CDROM::AbortCommand() UpdateStatusRegister(); } -void CDROM::ExecuteCommand() +void CDROM::ExecuteCommand(TickCount ticks_late) { const CommandInfo& ci = s_command_info[static_cast(m_command)]; - Log_DevPrintf("CDROM executing command 0x%02X (%s)", static_cast(m_command), ci.name); + Log_DevPrintf("CDROM executing command 0x%02X (%s), stat = 0x%02X", static_cast(m_command), ci.name, + m_secondary_status.bits); if (m_param_fifo.GetSize() < ci.expected_parameters) { Log_WarningPrintf("Too few parameters for command 0x%02X (%s), expecting %u got %u", static_cast(m_command), @@ -864,9 +870,7 @@ void CDROM::ExecuteCommand() else { SendACKAndStat(); - - m_drive_state = DriveState::ReadingID; - m_drive_event->Schedule(GetTicksForSeek(0) + GetTicksForRead()); + QueueCommandSecondResponse(Command::GetID, GetTicksForIDRead()); } EndCommand(); @@ -883,9 +887,8 @@ void CDROM::ExecuteCommand() else { SendACKAndStat(); - - m_drive_state = DriveState::ReadingTOC; - m_drive_event->Schedule(System::GetTicksPerSecond() / 2); // half a second + SetHoldPosition(0, true); + QueueCommandSecondResponse(Command::ReadTOC, System::GetTicksPerSecond() / 2); // half a second } EndCommand(); @@ -1090,6 +1093,8 @@ void CDROM::ExecuteCommand() case Command::Pause: { + SendACKAndStat(); + const bool was_reading = (m_drive_state == DriveState::Reading || m_drive_state == DriveState::Playing); const TickCount pause_time = was_reading ? (m_mode.double_speed ? 2000000 : 1000000) : 7000; @@ -1099,20 +1104,22 @@ void CDROM::ExecuteCommand() // hardware tests. Log_WarningPrintf("CDROM Pause command while seeking from %u to %u - jumping to seek target", m_seek_start_lba, m_seek_end_lba); - m_drive_event->Deactivate(); m_read_after_seek = false; m_play_after_seek = false; CompleteSeek(); } - - Log_DebugPrintf("CDROM pause command"); - SendACKAndStat(); + else + { + // Stop reading. + m_drive_state = DriveState::Idle; + m_drive_event->Deactivate(); + m_secondary_status.ClearActiveBits(); + } // Reset audio buffer here - control room cutscene audio repeats in Dino Crisis otherwise. ResetAudioDecoder(); - m_drive_state = DriveState::Pausing; - m_drive_event->Schedule(pause_time); + QueueCommandSecondResponse(Command::Pause, pause_time); EndCommand(); return; @@ -1121,11 +1128,10 @@ void CDROM::ExecuteCommand() case Command::Stop: { const TickCount stop_time = GetTicksForStop(m_secondary_status.motor_on); - Log_DebugPrintf("CDROM stop command"); SendACKAndStat(); - m_drive_state = DriveState::Stopping; - m_drive_event->Schedule(stop_time); + StopMotor(); + QueueCommandSecondResponse(Command::Stop, stop_time); EndCommand(); return; @@ -1136,15 +1142,27 @@ void CDROM::ExecuteCommand() Log_DebugPrintf("CDROM reset command"); SendACKAndStat(); + if (m_command_second_response == Command::Reset) + { + // still pending + EndCommand(); + return; + } + if (IsSeeking()) UpdatePositionWhileSeeking(); - m_drive_state = DriveState::Resetting; - m_drive_event->SetIntervalAndSchedule(BASE_RESET_TICKS + ((m_current_lba != 0) ? GetTicksForSeek(0) : 0)); - m_seek_start_lba = m_current_lba; - m_seek_end_lba = 0; + SoftReset(); - EndCommand(); + if (m_current_lba != 0) + { + m_drive_state = DriveState::SeekingImplicit; + m_drive_event->SetIntervalAndSchedule(((m_current_lba != 0) ? GetTicksForSeek(0) : 0)); + m_seek_start_lba = m_current_lba; + m_seek_end_lba = 0; + } + + QueueCommandSecondResponse(Command::Reset, RESET_TICKS); return; } break; @@ -1160,8 +1178,14 @@ void CDROM::ExecuteCommand() { SendACKAndStat(); - m_drive_state = DriveState::Resetting; - m_drive_event->Schedule(System::GetTicksPerSecond()); + // still pending? + if (m_command_second_response != Command::MotorOn) + { + if (CanReadMedia()) + StartMotor(); + + QueueCommandSecondResponse(Command::MotorOn, MOTOR_ON_RESPONSE_TICKS); + } } EndCommand(); @@ -1427,6 +1451,40 @@ void CDROM::ExecuteTestCommand(u8 subcommand) } } +void CDROM::ExecuteCommandSecondResponse(TickCount ticks_late) +{ + switch (m_command_second_response) + { + case Command::GetID: + DoIDRead(); + break; + + case Command::ReadTOC: + case Command::Pause: + case Command::Reset: + case Command::MotorOn: + case Command::Stop: + DoStatSecondResponse(); + break; + } + + m_command_second_response = Command::None; + m_command_second_response_event->Deactivate(); +} + +void CDROM::QueueCommandSecondResponse(Command command, TickCount ticks) +{ + ClearCommandSecondResponse(); + m_command_second_response = command; + m_command_second_response_event->Schedule(ticks); +} + +void CDROM::ClearCommandSecondResponse() +{ + m_command_second_response_event->Deactivate(); + m_command_second_response = Command::None; +} + void CDROM::UpdateCommandEvent() { // if there's a pending interrupt, we can't execute the command yet @@ -1446,10 +1504,6 @@ void CDROM::ExecuteDrive(TickCount ticks_late) { switch (m_drive_state) { - case DriveState::Resetting: - DoResetComplete(ticks_late); - break; - case DriveState::ShellOpening: DoShellOpenComplete(ticks_late); break; @@ -1459,20 +1513,8 @@ void CDROM::ExecuteDrive(TickCount ticks_late) DoSeekComplete(ticks_late); break; - case DriveState::Pausing: - DoPauseComplete(); - break; - - case DriveState::Stopping: - DoStopComplete(); - break; - - case DriveState::ReadingID: - DoIDRead(); - break; - - case DriveState::ReadingTOC: - DoTOCRead(); + case DriveState::SeekingImplicit: + CompleteSeek(); break; case DriveState::Reading: @@ -1488,12 +1530,50 @@ void CDROM::ExecuteDrive(TickCount ticks_late) DoSpinUpComplete(); break; + // old states, no longer used, but kept for save state compatibility + case DriveState::UNUSED_ReadingID: + { + ClearDriveState(); + DoIDRead(); + } + break; + + case DriveState::UNUSED_Resetting: + case DriveState::UNUSED_ReadingTOC: + { + ClearDriveState(); + DoStatSecondResponse(); + } + break; + + case DriveState::UNUSED_Pausing: + { + ClearDriveState(); + m_secondary_status.ClearActiveBits(); + DoStatSecondResponse(); + } + break; + + case DriveState::UNUSED_Stopping: + { + ClearDriveState(); + StopMotor(); + DoStatSecondResponse(); + } + break; + case DriveState::Idle: default: break; } } +void CDROM::ClearDriveState() +{ + m_drive_state = DriveState::Idle; + m_drive_event->Deactivate(); +} + void CDROM::BeginReading(TickCount ticks_late /* = 0 */, bool after_seek /* = false */) { ClearSectorBuffers(); @@ -1642,19 +1722,14 @@ void CDROM::UpdatePositionWhileSeeking() // access the image directly since we want to preserve the cached data for the seek complete CDImage::SubChannelQ subq; - if (m_reader.ReadSectorUncached(current_lba, &subq, nullptr) && subq.IsCRCValid()) - { + if (!m_reader.ReadSectorUncached(current_lba, &subq, nullptr)) + Log_ErrorPrintf("Failed to read subq for sector %u for physical position", current_lba); + else if (subq.IsCRCValid()) m_last_subq = subq; - m_current_lba = current_lba; - ResetPhysicalPosition(); - } -} -void CDROM::ResetPhysicalPosition() -{ - const u32 ticks = TimingEvents::GetGlobalTickCounter(); - m_physical_lba = m_current_lba; - m_physical_lba_update_tick = ticks; + m_current_lba = current_lba; + m_physical_lba = current_lba; + m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter(); } void CDROM::UpdatePhysicalPosition() @@ -1701,58 +1776,35 @@ void CDROM::UpdatePhysicalPosition() } } +void CDROM::SetHoldPosition(CDImage::LBA lba, bool update_subq) +{ + if (update_subq && m_physical_lba != lba && CanReadMedia()) + { + CDImage::SubChannelQ subq; + if (!m_reader.ReadSectorUncached(lba, &subq, nullptr)) + Log_ErrorPrintf("Failed to read subq for sector %u for physical position", lba); + else if (subq.IsCRCValid()) + m_last_subq = subq; + } + + m_current_lba = lba; + m_physical_lba = lba; + m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter(); +} + void CDROM::DoShellOpenComplete(TickCount ticks_late) { // media is now readable (if any) - m_drive_state = DriveState::Idle; - m_drive_event->Deactivate(); + ClearDriveState(); - if (m_reader.HasMedia()) - { - m_drive_state = DriveState::SpinningUp; - m_drive_event->Schedule(System::GetTicksPerSecond()); - } -} - -void CDROM::DoResetComplete(TickCount ticks_late) -{ - m_drive_state = DriveState::Idle; - m_drive_event->Deactivate(); - - m_secondary_status.bits = 0; - m_secondary_status.motor_on = CanReadMedia(); - m_mode.bits = 0; - m_mode.read_raw_sector = true; - m_data_fifo.Clear(); - - if (!CanReadMedia()) - { - Log_DevPrintf("CDROM reset - no disc"); - m_secondary_status.shell_open = true; - SendAsyncErrorResponse(STAT_ERROR, 0x08); - return; - } - - m_current_lba = 0; - ResetPhysicalPosition(); - m_reader.QueueReadSector(0); - - m_async_response_fifo.Clear(); - m_async_response_fifo.Push(m_secondary_status.bits); - SetAsyncInterrupt(Interrupt::Complete); - - if (!CanReadMedia()) - { - m_secondary_status.motor_on = false; - m_secondary_status.shell_open = true; - } + if (CanReadMedia()) + StartMotor(); } bool CDROM::CompleteSeek() { const bool logical = (m_drive_state == DriveState::SeekingLogical); - m_drive_state = DriveState::Idle; - m_drive_event->Deactivate(); + ClearDriveState(); m_secondary_status.ClearActiveBits(); bool seek_okay = m_reader.WaitForReadToComplete(); @@ -1803,7 +1855,8 @@ bool CDROM::CompleteSeek() } m_current_lba = m_reader.GetLastReadSector(); - ResetPhysicalPosition(); + m_physical_lba = m_current_lba; + m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter(); return seek_okay; } @@ -1844,25 +1897,14 @@ void CDROM::DoSeekComplete(TickCount ticks_late) UpdateStatusRegister(); } -void CDROM::DoPauseComplete() +void CDROM::DoStatSecondResponse() { - Log_DebugPrintf("Pause complete"); - m_drive_state = DriveState::Idle; - m_drive_event->Deactivate(); - m_secondary_status.ClearActiveBits(); - - m_async_response_fifo.Clear(); - m_async_response_fifo.Push(m_secondary_status.bits); - SetAsyncInterrupt(Interrupt::Complete); -} - -void CDROM::DoStopComplete() -{ - Log_DebugPrintf("Stop complete"); - m_drive_state = DriveState::Idle; - m_drive_event->Deactivate(); - m_secondary_status.ClearActiveBits(); - m_secondary_status.motor_on = false; + // Mainly for Reset/MotorOn. + if (!CanReadMedia()) + { + SendAsyncErrorResponse(STAT_ERROR, 0x08); + return; + } m_async_response_fifo.Clear(); m_async_response_fifo.Push(m_secondary_status.bits); @@ -1872,8 +1914,7 @@ void CDROM::DoStopComplete() void CDROM::DoChangeSessionComplete() { Log_DebugPrintf("Changing session complete"); - m_drive_state = DriveState::Idle; - m_drive_event->Deactivate(); + ClearDriveState(); m_secondary_status.ClearActiveBits(); m_secondary_status.motor_on = true; @@ -1902,8 +1943,6 @@ void CDROM::DoSpinUpComplete() void CDROM::DoIDRead() { Log_DebugPrintf("ID read complete"); - m_drive_state = DriveState::Idle; - m_drive_event->Deactivate(); m_secondary_status.ClearActiveBits(); m_secondary_status.motor_on = CanReadMedia(); @@ -1917,11 +1956,6 @@ void CDROM::DoIDRead() } else { - // this is where it would get read from the start of the disc? - m_current_lba = 0; - ResetPhysicalPosition(); - m_reader.QueueReadSector(0); - if (!IsMediaPS1Disc()) { stat_byte |= STAT_ID_ERROR; @@ -1948,17 +1982,6 @@ void CDROM::DoIDRead() SetAsyncInterrupt((flags_byte != 0) ? Interrupt::Error : Interrupt::Complete); } -void CDROM::DoTOCRead() -{ - Log_DebugPrintf("TOC read complete"); - m_drive_state = DriveState::Idle; - m_drive_event->Deactivate(); - - m_async_response_fifo.Clear(); - m_async_response_fifo.Push(m_secondary_status.bits); - SetAsyncInterrupt(Interrupt::Complete); -} - void CDROM::StopReadingWithDataEnd() { ClearAsyncInterrupt(); @@ -1966,8 +1989,29 @@ void CDROM::StopReadingWithDataEnd() SetAsyncInterrupt(Interrupt::DataEnd); m_secondary_status.ClearActiveBits(); - m_drive_state = DriveState::Idle; - m_drive_event->Deactivate(); + ClearDriveState(); +} + +void CDROM::StartMotor() +{ + if (m_drive_state == DriveState::SpinningUp) + { + Log_DevPrintf("Starting motor - already spinning up"); + return; + } + + Log_DevPrintf("Starting motor"); + m_drive_state = DriveState::SpinningUp; + m_drive_event->Schedule(GetTicksForSpinUp()); +} + +void CDROM::StopMotor() +{ + m_secondary_status.ClearActiveBits(); + m_secondary_status.motor_on = false; + ClearDriveState(); + SetHoldPosition(0, false); + m_last_sector_header_valid = false; // TODO: correct? } void CDROM::DoSectorRead() @@ -1978,7 +2022,8 @@ void CDROM::DoSectorRead() Panic("Sector read failed"); m_current_lba = m_reader.GetLastReadSector(); - ResetPhysicalPosition(); + m_physical_lba = m_current_lba; + m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter(); const CDImage::SubChannelQ& subq = m_reader.GetSectorSubQ(); const bool subq_valid = subq.IsCRCValid(); @@ -1997,7 +2042,7 @@ void CDROM::DoSectorRead() { Log_DevPrintf("Read reached lead-out area of disc at LBA %u, stopping", m_reader.GetLastReadSector()); StopReadingWithDataEnd(); - m_secondary_status.motor_on = false; + StopMotor(); return; } @@ -2013,7 +2058,7 @@ void CDROM::DoSectorRead() else if (m_mode.auto_pause && subq.track_number_bcd != m_play_track_number_bcd) { // we don't want to update the position if the track changes, so we check it before reading the actual sector. - Log_DevPrintf("Auto pause at the end of track %02x (LBA %u)", m_last_subq.track_number_bcd, m_current_lba); + Log_DevPrintf("Auto pause at the start of track %02x (LBA %u)", m_last_subq.track_number_bcd, m_current_lba); StopReadingWithDataEnd(); return; } @@ -2506,9 +2551,9 @@ void CDROM::DrawDebugWindow() if (ImGui::CollapsingHeader("Status/Mode", ImGuiTreeNodeFlags_DefaultOpen)) { - static constexpr std::array drive_state_names = { + static constexpr std::array drive_state_names = { {"Idle", "Opening Shell", "Resetting", "Seeking (Physical)", "Seeking (Logical)", "Reading ID", "Reading TOC", - "Reading", "Playing", "Pausing", "Stopping", "Changing Session", "Spinning Up"}}; + "Reading", "Playing", "Pausing", "Stopping", "Changing Session", "Spinning Up", "Seeking (Implicit)"}}; ImGui::Columns(3); @@ -2598,7 +2643,8 @@ void CDROM::DrawDebugWindow() if (HasPendingCommand()) { - ImGui::TextColored(active_color, "Command: 0x%02X (%d ticks remaining)", static_cast(m_command), + ImGui::TextColored(active_color, "Command: %s (0x%02X) (%d ticks remaining)", + s_command_info[static_cast(m_command)].name, static_cast(m_command), m_command_event->IsActive() ? m_command_event->GetTicksUntilNextExecution() : 0); } else diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 399232c05..c2b40a49e 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -78,7 +78,9 @@ private: AUDIO_FIFO_SIZE = 44100 * 2, AUDIO_FIFO_LOW_WATERMARK = 10, - BASE_RESET_TICKS = 400000, + RESET_TICKS = 400000, + ID_READ_TICKS = 33868, + MOTOR_ON_RESPONSE_TICKS = 400000, MAX_FAST_FORWARD_RATE = 12, FAST_FORWARD_RATE_STEP = 4 @@ -137,17 +139,18 @@ private: { Idle, ShellOpening, - Resetting, + UNUSED_Resetting, SeekingPhysical, SeekingLogical, - ReadingID, - ReadingTOC, + UNUSED_ReadingID, + UNUSED_ReadingTOC, Reading, Playing, - Pausing, - Stopping, + UNUSED_Pausing, + UNUSED_Stopping, ChangingSession, - SpinningUp + SpinningUp, + SeekingImplicit }; union StatusRegister @@ -222,10 +225,11 @@ private: void SoftReset(); ALWAYS_INLINE bool IsDriveIdle() const { return m_drive_state == DriveState::Idle; } + ALWAYS_INLINE bool IsMotorOn() const { return m_secondary_status.motor_on; } ALWAYS_INLINE bool IsSeeking() const { return (m_drive_state == DriveState::SeekingLogical || m_drive_state == DriveState::SeekingPhysical || - m_drive_state == DriveState::Resetting); + m_drive_state == DriveState::SeekingImplicit); } ALWAYS_INLINE bool IsReadingOrPlaying() const { @@ -261,6 +265,8 @@ private: bool HasPendingDiscEvent() const; TickCount GetAckDelayForCommand(Command command); + TickCount GetTicksForSpinUp(); + TickCount GetTicksForIDRead(); TickCount GetTicksForRead(); TickCount GetTicksForSeek(CDImage::LBA new_lba); TickCount GetTicksForStop(bool motor_was_on); @@ -270,31 +276,34 @@ private: void BeginCommand(Command command); // also update status register void EndCommand(); // also updates status register void AbortCommand(); - void ExecuteCommand(); + void ExecuteCommand(TickCount ticks_late); void ExecuteTestCommand(u8 subcommand); + void ExecuteCommandSecondResponse(TickCount ticks_late); + void QueueCommandSecondResponse(Command command, TickCount ticks); + void ClearCommandSecondResponse(); void UpdateCommandEvent(); void ExecuteDrive(TickCount ticks_late); + void ClearDriveState(); void BeginReading(TickCount ticks_late = 0, bool after_seek = false); void BeginPlaying(u8 track, TickCount ticks_late = 0, bool after_seek = false); void DoShellOpenComplete(TickCount ticks_late); - void DoResetComplete(TickCount ticks_late); void DoSeekComplete(TickCount ticks_late); - void DoPauseComplete(); - void DoStopComplete(); + void DoStatSecondResponse(); void DoChangeSessionComplete(); void DoSpinUpComplete(); void DoIDRead(); - void DoTOCRead(); void DoSectorRead(); void ProcessDataSectorHeader(const u8* raw_sector); void ProcessDataSector(const u8* raw_sector, const CDImage::SubChannelQ& subq); void ProcessXAADPCMSector(const u8* raw_sector, const CDImage::SubChannelQ& subq); void ProcessCDDASector(const u8* raw_sector, const CDImage::SubChannelQ& subq); void StopReadingWithDataEnd(); + void StartMotor(); + void StopMotor(); void BeginSeeking(bool logical, bool read_after_seek, bool play_after_seek); void UpdatePositionWhileSeeking(); - void ResetPhysicalPosition(); void UpdatePhysicalPosition(); + void SetHoldPosition(CDImage::LBA lba, bool update_subq); void ResetCurrentXAFile(); void ResetAudioDecoder(); void LoadDataFIFO(); @@ -304,9 +313,11 @@ private: void ResampleXAADPCM(const s16* frames_in, u32 num_frames_in); std::unique_ptr m_command_event; + std::unique_ptr m_command_second_response_event; std::unique_ptr m_drive_event; Command m_command = Command::None; + Command m_command_second_response = Command::None; DriveState m_drive_state = DriveState::Idle; DiscRegion m_disc_region = DiscRegion::Other; @@ -320,10 +331,10 @@ private: u8 m_pending_async_interrupt = 0; CDImage::Position m_setloc_position = {}; - CDImage::LBA m_current_lba{}; + CDImage::LBA m_current_lba{}; // this is the hold position CDImage::LBA m_seek_start_lba{}; CDImage::LBA m_seek_end_lba{}; - CDImage::LBA m_physical_lba{}; + CDImage::LBA m_physical_lba{}; // current position of the disc with respect to time u32 m_physical_lba_update_tick = 0; bool m_setloc_pending = false; bool m_read_after_seek = false; diff --git a/src/core/save_state_version.h b/src/core/save_state_version.h index 2a6d64da8..c4e47bdc3 100644 --- a/src/core/save_state_version.h +++ b/src/core/save_state_version.h @@ -2,7 +2,7 @@ #include "types.h" static constexpr u32 SAVE_STATE_MAGIC = 0x43435544; -static constexpr u32 SAVE_STATE_VERSION = 52; +static constexpr u32 SAVE_STATE_VERSION = 53; static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42; static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);