From 02f67a801e56b4965f6ef3dada386680c9a5f155 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin <stenzek@gmail.com> Date: Sun, 29 Mar 2020 17:41:31 +1000 Subject: [PATCH] CDROM: Fix behavior of stat bit 5 according to hardware tests --- src/core/cdrom.cpp | 89 +++++++++++++++++++++-------------- src/core/cdrom.h | 13 +++-- src/core/save_state_version.h | 2 +- 3 files changed, 60 insertions(+), 44 deletions(-) diff --git a/src/core/cdrom.cpp b/src/core/cdrom.cpp index 50e4d5798..a7c67a58a 100644 --- a/src/core/cdrom.cpp +++ b/src/core/cdrom.cpp @@ -61,7 +61,9 @@ void CDROM::SoftReset() m_filter_channel_number = 0; std::memset(&m_last_sector_header, 0, sizeof(m_last_sector_header)); std::memset(&m_last_sector_subheader, 0, sizeof(m_last_sector_subheader)); + m_last_sector_header_valid = false; std::memset(&m_last_subq, 0, sizeof(m_last_subq)); + m_last_subq_valid = false; m_last_cdda_report_frame_nibble = 0xFF; m_cdda_report_delay = 0; @@ -116,7 +118,9 @@ bool CDROM::DoState(StateWrapper& sw) sw.Do(&m_filter_channel_number); sw.DoBytes(&m_last_sector_header, sizeof(m_last_sector_header)); sw.DoBytes(&m_last_sector_subheader, sizeof(m_last_sector_subheader)); + sw.Do(&m_last_sector_header_valid); sw.DoBytes(&m_last_subq, sizeof(m_last_subq)); + sw.Do(&m_last_subq_valid); sw.Do(&m_last_cdda_report_frame_nibble); sw.Do(&m_cdda_report_delay); sw.Do(&m_play_track_number_bcd); @@ -174,6 +178,9 @@ void CDROM::InsertMedia(std::unique_ptr<CDImage> media) // motor automatically spins up m_secondary_status.motor_on = true; + // reading TOC? interestingly this doesn't work for GetlocL though... + m_last_subq_valid = media->Seek(0) && media->ReadSubChannelQ(&m_last_subq); + m_reader.SetMedia(std::move(media)); } @@ -185,6 +192,9 @@ void CDROM::RemoveMedia() Log_InfoPrintf("Removing CD..."); m_reader.RemoveMedia(); + m_last_sector_header_valid = false; + m_last_subq_valid = false; + m_secondary_status.motor_on = false; m_secondary_status.shell_open = true; m_secondary_status.ClearActiveBits(); @@ -821,9 +831,9 @@ void CDROM::ExecuteCommand() case Command::GetlocL: { Log_DebugPrintf("CDROM GetlocL command - header %s [%02X:%02X:%02X]", - m_secondary_status.header_valid ? "valid" : "invalid", m_last_sector_header.minute, + m_last_sector_header_valid ? "valid" : "invalid", m_last_sector_header.minute, m_last_sector_header.second, m_last_sector_header.frame); - if (!m_secondary_status.header_valid) + if (!m_last_sector_header_valid) { SendErrorResponse(STAT_ERROR, 0x80); } @@ -841,19 +851,27 @@ void CDROM::ExecuteCommand() case Command::GetlocP: { - Log_DebugPrintf("CDROM GetlocP command"); - m_response_fifo.Push(m_last_subq.track_number_bcd); - m_response_fifo.Push(m_last_subq.index_number_bcd); - m_response_fifo.Push(m_last_subq.relative_minute_bcd); - m_response_fifo.Push(m_last_subq.relative_second_bcd); - m_response_fifo.Push(m_last_subq.relative_frame_bcd); - m_response_fifo.Push(m_last_subq.absolute_minute_bcd); - m_response_fifo.Push(m_last_subq.absolute_second_bcd); - m_response_fifo.Push(m_last_subq.absolute_frame_bcd); - SetInterrupt(Interrupt::ACK); + Log_DebugPrintf("CDROM GetlocP command - %s", m_last_subq_valid ? "valid" : "invalid"); + if (!m_last_subq_valid) + { + SendErrorResponse(STAT_ERROR, 0x80); + } + else + { + m_response_fifo.Push(m_last_subq.track_number_bcd); + m_response_fifo.Push(m_last_subq.index_number_bcd); + m_response_fifo.Push(m_last_subq.relative_minute_bcd); + m_response_fifo.Push(m_last_subq.relative_second_bcd); + m_response_fifo.Push(m_last_subq.relative_frame_bcd); + m_response_fifo.Push(m_last_subq.absolute_minute_bcd); + m_response_fifo.Push(m_last_subq.absolute_second_bcd); + m_response_fifo.Push(m_last_subq.absolute_frame_bcd); + SetInterrupt(Interrupt::ACK); + } + EndCommand(); + return; } - break; case Command::GetTN: { @@ -1092,6 +1110,7 @@ void CDROM::BeginReading(TickCount ticks_late) m_secondary_status.ClearActiveBits(); m_secondary_status.motor_on = true; + m_secondary_status.reading = true; const TickCount ticks = GetTicksForRead(); m_drive_state = DriveState::Reading; @@ -1160,7 +1179,6 @@ void CDROM::BeginSeeking(bool logical, bool read_after_seek, bool play_after_see const TickCount seek_time = GetTicksForSeek(); m_secondary_status.ClearActiveBits(); - m_secondary_status.header_valid = false; m_secondary_status.motor_on = true; m_secondary_status.seeking = true; @@ -1219,22 +1237,20 @@ void CDROM::DoSeekComplete(TickCount ticks_late) m_last_subq.absolute_second_bcd == seek_ss && m_last_subq.absolute_frame_bcd == seek_ff); if (seek_okay) { - // check for data header for logical seeks - if (logical) + if (m_last_subq.control.data) { - if (!m_last_subq.control.data) + // ensure the location matches up (it should) + ProcessDataSectorHeader(m_reader.GetSectorBuffer().data()); + seek_okay = (m_last_sector_header.minute == seek_mm && m_last_sector_header.second == seek_ss && + m_last_sector_header.frame == seek_ff); + } + else + { + if (logical) { Log_WarningPrintf("Logical seek to non-data sector [%02x:%02x:%02x]", seek_mm, seek_ss, seek_ff); seek_okay = false; } - else - { - ProcessDataSectorHeader(m_reader.GetSectorBuffer().data(), true); - - // ensure the location matches up (it should) - seek_okay = (m_last_sector_header.minute == seek_mm && m_last_sector_header.second == seek_ss && - m_last_sector_header.frame == seek_ff); - } } } } @@ -1263,6 +1279,8 @@ void CDROM::DoSeekComplete(TickCount ticks_late) Log_WarningPrintf("%s seek to [%02u:%02u:%02u] failed", logical ? "Logical" : "Physical", pos.minute, pos.second, pos.frame); SendAsyncErrorResponse(STAT_SEEK_ERROR, 0x04); + m_last_sector_header_valid = false; + m_last_subq_valid = false; } m_setloc_pending = false; @@ -1289,7 +1307,6 @@ void CDROM::DoStopComplete() m_drive_state = DriveState::Idle; m_drive_event->Deactivate(); m_secondary_status.ClearActiveBits(); - m_secondary_status.header_valid = false; m_secondary_status.motor_on = false; m_async_response_fifo.Clear(); @@ -1303,7 +1320,6 @@ void CDROM::DoChangeSessionComplete() m_drive_state = DriveState::Idle; m_drive_event->Deactivate(); m_secondary_status.ClearActiveBits(); - m_secondary_status.header_valid = false; m_secondary_status.motor_on = true; m_async_response_fifo.Clear(); @@ -1399,6 +1415,10 @@ void CDROM::DoSectorRead() return; } } + else + { + ProcessDataSectorHeader(m_reader.GetSectorBuffer().data()); + } if (subq.IsCRCValid()) { @@ -1433,18 +1453,16 @@ void CDROM::DoSectorRead() m_reader.QueueReadSector(m_last_requested_sector); } -void CDROM::ProcessDataSectorHeader(const u8* raw_sector, bool set_valid) +void CDROM::ProcessDataSectorHeader(const u8* raw_sector) { std::memcpy(&m_last_sector_header, &raw_sector[SECTOR_SYNC_SIZE], sizeof(m_last_sector_header)); std::memcpy(&m_last_sector_subheader, &raw_sector[SECTOR_SYNC_SIZE + sizeof(m_last_sector_header)], sizeof(m_last_sector_subheader)); - m_secondary_status.header_valid |= set_valid; + m_last_sector_header_valid = true; } void CDROM::ProcessDataSector(const u8* raw_sector, const CDImage::SubChannelQ& subq) { - ProcessDataSectorHeader(raw_sector, true); - Log_DevPrintf("Read sector %u: mode %u submode 0x%02X into buffer %u", m_last_requested_sector, ZeroExtend32(m_last_sector_header.sector_mode), ZeroExtend32(m_last_sector_subheader.submode.bits), m_current_write_sector_buffer); @@ -1849,8 +1867,8 @@ void CDROM::DrawDebugWindow() ImGui::TextColored(m_status.BUSYSTS ? active_color : inactive_color, "BUSYSTS: %s", m_status.BUSYSTS ? "Yes" : "No"); ImGui::NextColumn(); - ImGui::TextColored(m_secondary_status.header_valid ? active_color : inactive_color, "Header Valid: %s", - m_secondary_status.header_valid ? "Yes" : "No"); + ImGui::TextColored(m_secondary_status.reading ? active_color : inactive_color, "Reading: %s", + m_secondary_status.reading ? "Yes" : "No"); ImGui::NextColumn(); ImGui::TextColored(m_mode.read_raw_sector ? active_color : inactive_color, "Read Raw Sectors: %s", m_mode.read_raw_sector ? "Yes" : "No"); @@ -1902,10 +1920,9 @@ void CDROM::DrawDebugWindow() if (ImGui::CollapsingHeader("CD Audio", ImGuiTreeNodeFlags_DefaultOpen)) { - const bool playing_anything = - (m_secondary_status.header_valid && m_mode.xa_enable) || m_secondary_status.playing_cdda; + const bool playing_anything = (m_secondary_status.reading && m_mode.xa_enable) || m_secondary_status.playing_cdda; ImGui::TextColored(playing_anything ? active_color : inactive_color, "Playing: %s", - (m_secondary_status.header_valid && m_mode.xa_enable) ? + (m_secondary_status.reading && m_mode.xa_enable) ? "XA-ADPCM" : (m_secondary_status.playing_cdda ? "CDDA" : "Disabled")); ImGui::TextColored(m_muted ? inactive_color : active_color, "Muted: %s", m_muted ? "Yes" : "No"); diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 35eb358cd..1dc1940ad 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -143,7 +143,7 @@ private: STAT_SEEK_ERROR = (1 << 2), STAT_ID_ERROR = (1 << 3), STAT_SHELL_OPEN = (1 << 4), - STAT_HEADER_VALID = (1 << 5), + STAT_READING = (1 << 5), STAT_SEEKING = (1 << 6), STAT_PLAYING_CDDA = (1 << 7) }; @@ -156,15 +156,12 @@ private: BitField<u8, bool, 2, 1> seek_error; BitField<u8, bool, 3, 1> id_error; BitField<u8, bool, 4, 1> shell_open; - BitField<u8, bool, 5, 1> header_valid; + BitField<u8, bool, 5, 1> reading; BitField<u8, bool, 6, 1> seeking; BitField<u8, bool, 7, 1> playing_cdda; /// Clears the CDDA/seeking bits. - ALWAYS_INLINE void ClearActiveBits() - { - bits &= ~(STAT_SEEKING | STAT_PLAYING_CDDA); - } + ALWAYS_INLINE void ClearActiveBits() { bits &= ~(STAT_SEEKING | STAT_READING | STAT_PLAYING_CDDA); } }; union ModeRegister @@ -223,7 +220,7 @@ private: void DoIDRead(); void DoTOCRead(); void DoSectorRead(); - void ProcessDataSectorHeader(const u8* raw_sector, bool set_valid); + 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); @@ -264,7 +261,9 @@ private: CDImage::SectorHeader m_last_sector_header{}; CDXA::XASubHeader m_last_sector_subheader{}; + bool m_last_sector_header_valid = false; CDImage::SubChannelQ m_last_subq{}; + bool m_last_subq_valid = false; u8 m_last_cdda_report_frame_nibble = 0xFF; u8 m_cdda_report_delay = 0x00; u8 m_play_track_number_bcd = 0xFF; diff --git a/src/core/save_state_version.h b/src/core/save_state_version.h index 9603eabdc..39a4082e7 100644 --- a/src/core/save_state_version.h +++ b/src/core/save_state_version.h @@ -2,4 +2,4 @@ #include "types.h" static constexpr u32 SAVE_STATE_MAGIC = 0x43435544; -static constexpr u32 SAVE_STATE_VERSION = 16; +static constexpr u32 SAVE_STATE_VERSION = 17;