diff --git a/src/core/bus.cpp b/src/core/bus.cpp index acff4fb70..e9200aa10 100644 --- a/src/core/bus.cpp +++ b/src/core/bus.cpp @@ -1145,23 +1145,23 @@ ALWAYS_INLINE static TickCount DoCDROMAccess(u32 offset, u32& value) { case MemoryAccessSize::Word: { - const u32 b0 = ZeroExtend32(g_cdrom.ReadRegister(offset)); - const u32 b1 = ZeroExtend32(g_cdrom.ReadRegister(offset + 1u)); - const u32 b2 = ZeroExtend32(g_cdrom.ReadRegister(offset + 2u)); - const u32 b3 = ZeroExtend32(g_cdrom.ReadRegister(offset + 3u)); + const u32 b0 = ZeroExtend32(CDROM::ReadRegister(offset)); + const u32 b1 = ZeroExtend32(CDROM::ReadRegister(offset + 1u)); + const u32 b2 = ZeroExtend32(CDROM::ReadRegister(offset + 2u)); + const u32 b3 = ZeroExtend32(CDROM::ReadRegister(offset + 3u)); value = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); } case MemoryAccessSize::HalfWord: { - const u32 lsb = ZeroExtend32(g_cdrom.ReadRegister(offset)); - const u32 msb = ZeroExtend32(g_cdrom.ReadRegister(offset + 1u)); + const u32 lsb = ZeroExtend32(CDROM::ReadRegister(offset)); + const u32 msb = ZeroExtend32(CDROM::ReadRegister(offset + 1u)); value = lsb | (msb << 8); } case MemoryAccessSize::Byte: default: - value = ZeroExtend32(g_cdrom.ReadRegister(offset)); + value = ZeroExtend32(CDROM::ReadRegister(offset)); } return m_cdrom_access_time[static_cast(size)]; @@ -1172,23 +1172,23 @@ ALWAYS_INLINE static TickCount DoCDROMAccess(u32 offset, u32& value) { case MemoryAccessSize::Word: { - g_cdrom.WriteRegister(offset, Truncate8(value & 0xFFu)); - g_cdrom.WriteRegister(offset + 1u, Truncate8((value >> 8) & 0xFFu)); - g_cdrom.WriteRegister(offset + 2u, Truncate8((value >> 16) & 0xFFu)); - g_cdrom.WriteRegister(offset + 3u, Truncate8((value >> 24) & 0xFFu)); + CDROM::WriteRegister(offset, Truncate8(value & 0xFFu)); + CDROM::WriteRegister(offset + 1u, Truncate8((value >> 8) & 0xFFu)); + CDROM::WriteRegister(offset + 2u, Truncate8((value >> 16) & 0xFFu)); + CDROM::WriteRegister(offset + 3u, Truncate8((value >> 24) & 0xFFu)); } break; case MemoryAccessSize::HalfWord: { - g_cdrom.WriteRegister(offset, Truncate8(value & 0xFFu)); - g_cdrom.WriteRegister(offset + 1u, Truncate8((value >> 8) & 0xFFu)); + CDROM::WriteRegister(offset, Truncate8(value & 0xFFu)); + CDROM::WriteRegister(offset + 1u, Truncate8((value >> 8) & 0xFFu)); } break; case MemoryAccessSize::Byte: default: - g_cdrom.WriteRegister(offset, Truncate8(value)); + CDROM::WriteRegister(offset, Truncate8(value)); break; } diff --git a/src/core/cdrom.cpp b/src/core/cdrom.cpp index 26003e665..e3f18474b 100644 --- a/src/core/cdrom.cpp +++ b/src/core/cdrom.cpp @@ -2,8 +2,12 @@ // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "cdrom.h" +#include "cdrom_async_reader.h" #include "common/align.h" +#include "common/bitfield.h" +#include "common/fifo_queue.h" #include "common/file_system.h" +#include "common/heap_array.h" #include "common/log.h" #include "common/platform.h" #include "dma.h" @@ -15,14 +19,343 @@ #include "spu.h" #include "system.h" #include "util/cd_image.h" +#include "util/cd_xa.h" #include "util/state_wrapper.h" #include +#include Log_SetChannel(CDROM); #if defined(CPU_X64) #include #endif +namespace CDROM { +enum : u32 +{ + RAW_SECTOR_OUTPUT_SIZE = CDImage::RAW_SECTOR_SIZE - CDImage::SECTOR_SYNC_SIZE, + DATA_SECTOR_OUTPUT_SIZE = CDImage::DATA_SECTOR_SIZE, + SECTOR_SYNC_SIZE = CDImage::SECTOR_SYNC_SIZE, + SECTOR_HEADER_SIZE = CDImage::SECTOR_HEADER_SIZE, + XA_RESAMPLE_RING_BUFFER_SIZE = 32, + XA_RESAMPLE_ZIGZAG_TABLE_SIZE = 29, + XA_RESAMPLE_NUM_ZIGZAG_TABLES = 7, + + PARAM_FIFO_SIZE = 16, + RESPONSE_FIFO_SIZE = 16, + DATA_FIFO_SIZE = RAW_SECTOR_OUTPUT_SIZE, + NUM_SECTOR_BUFFERS = 8, + AUDIO_FIFO_SIZE = 44100 * 2, + AUDIO_FIFO_LOW_WATERMARK = 10, + + INIT_TICKS = 400000, + ID_READ_TICKS = 33868, + MOTOR_ON_RESPONSE_TICKS = 400000, + + MAX_FAST_FORWARD_RATE = 12, + FAST_FORWARD_RATE_STEP = 4 +}; + +static constexpr u8 INTERRUPT_REGISTER_MASK = 0x1F; + +enum class Interrupt : u8 +{ + DataReady = 0x01, + Complete = 0x02, + ACK = 0x03, + DataEnd = 0x04, + Error = 0x05 +}; + +enum class Command : u16 +{ + Sync = 0x00, + Getstat = 0x01, + Setloc = 0x02, + Play = 0x03, + Forward = 0x04, + Backward = 0x05, + ReadN = 0x06, + MotorOn = 0x07, + Stop = 0x08, + Pause = 0x09, + Init = 0x0A, + Mute = 0x0B, + Demute = 0x0C, + Setfilter = 0x0D, + Setmode = 0x0E, + Getmode = 0x0F, + GetlocL = 0x10, + GetlocP = 0x11, + ReadT = 0x12, + GetTN = 0x13, + GetTD = 0x14, + SeekL = 0x15, + SeekP = 0x16, + SetClock = 0x17, + GetClock = 0x18, + Test = 0x19, + GetID = 0x1A, + ReadS = 0x1B, + Reset = 0x1C, + GetQ = 0x1D, + ReadTOC = 0x1E, + VideoCD = 0x1F, + + None = 0xFFFF +}; + +enum class DriveState : u8 +{ + Idle, + ShellOpening, + UNUSED_Resetting, + SeekingPhysical, + SeekingLogical, + UNUSED_ReadingID, + UNUSED_ReadingTOC, + Reading, + Playing, + UNUSED_Pausing, + UNUSED_Stopping, + ChangingSession, + SpinningUp, + SeekingImplicit, + ChangingSpeedOrTOCRead +}; + +union StatusRegister +{ + u8 bits; + BitField index; + BitField ADPBUSY; + BitField PRMEMPTY; + BitField PRMWRDY; + BitField RSLRRDY; + BitField DRQSTS; + BitField BUSYSTS; +}; + +enum StatBits : u8 +{ + STAT_ERROR = (1 << 0), + STAT_MOTOR_ON = (1 << 1), + STAT_SEEK_ERROR = (1 << 2), + STAT_ID_ERROR = (1 << 3), + STAT_SHELL_OPEN = (1 << 4), + STAT_READING = (1 << 5), + STAT_SEEKING = (1 << 6), + STAT_PLAYING_CDDA = (1 << 7) +}; + +enum ErrorReason : u8 +{ + ERROR_REASON_INVALID_ARGUMENT = 0x10, + ERROR_REASON_INCORRECT_NUMBER_OF_PARAMETERS = 0x20, + ERROR_REASON_INVALID_COMMAND = 0x40, + ERROR_REASON_NOT_READY = 0x80 +}; + +union SecondaryStatusRegister +{ + u8 bits; + BitField error; + BitField motor_on; + BitField seek_error; + BitField id_error; + BitField shell_open; + BitField reading; + BitField seeking; + BitField playing_cdda; + + /// Clears the CDDA/seeking bits. + ALWAYS_INLINE void ClearActiveBits() { bits &= ~(STAT_SEEKING | STAT_READING | STAT_PLAYING_CDDA); } + + /// Sets the bits for seeking. + ALWAYS_INLINE void SetSeeking() + { + bits = (bits & ~(STAT_READING | STAT_PLAYING_CDDA)) | (STAT_MOTOR_ON | STAT_SEEKING); + } + + /// Sets the bits for reading/playing. + ALWAYS_INLINE void SetReadingBits(bool audio) + { + bits = (bits & ~(STAT_SEEKING | STAT_READING | STAT_PLAYING_CDDA)) | + ((audio) ? (STAT_MOTOR_ON | STAT_PLAYING_CDDA) : (STAT_MOTOR_ON | STAT_READING)); + } +}; + +union ModeRegister +{ + u8 bits; + BitField cdda; + BitField auto_pause; + BitField report_audio; + BitField xa_filter; + BitField ignore_bit; + BitField read_raw_sector; + BitField xa_enable; + BitField double_speed; +}; + +union RequestRegister +{ + u8 bits; + BitField SMEN; + BitField BFWR; + BitField BFRD; +}; + +static void SoftReset(TickCount ticks_late); + +static bool IsDriveIdle(); +static bool IsMotorOn(); +static bool IsSeeking(); +static bool IsReadingOrPlaying(); +static bool CanReadMedia(); +static bool HasPendingCommand(); +static bool HasPendingInterrupt(); +static bool HasPendingAsyncInterrupt(); +static void AddCDAudioFrame(s16 left, s16 right); + +static s32 ApplyVolume(s16 sample, u8 volume); +static s16 SaturateVolume(s32 volume); + +static void SetInterrupt(Interrupt interrupt); +static void SetAsyncInterrupt(Interrupt interrupt); +static void ClearAsyncInterrupt(); +static void DeliverAsyncInterrupt(); +static void SendACKAndStat(); +static void SendErrorResponse(u8 stat_bits = STAT_ERROR, u8 reason = 0x80); +static void SendAsyncErrorResponse(u8 stat_bits = STAT_ERROR, u8 reason = 0x80); +static void UpdateStatusRegister(); +static void UpdateInterruptRequest(); +static bool HasPendingDiscEvent(); + +static TickCount GetAckDelayForCommand(Command command); +static TickCount GetTicksForSpinUp(); +static TickCount GetTicksForIDRead(); +static TickCount GetTicksForRead(); +static TickCount GetTicksForSeek(CDImage::LBA new_lba, bool ignore_speed_change = false); +static TickCount GetTicksForStop(bool motor_was_on); +static TickCount GetTicksForSpeedChange(); +static TickCount GetTicksForTOCRead(); +static CDImage::LBA GetNextSectorToBeRead(); +static bool CompleteSeek(); + +static void BeginCommand(Command command); // also update status register +static void EndCommand(); // also updates status register +static void ExecuteCommand(void*, TickCount ticks, TickCount ticks_late); +static void ExecuteTestCommand(u8 subcommand); +static void ExecuteCommandSecondResponse(void*, TickCount ticks, TickCount ticks_late); +static void QueueCommandSecondResponse(Command command, TickCount ticks); +static void ClearCommandSecondResponse(); +static void UpdateCommandEvent(); +static void ExecuteDrive(void*, TickCount ticks, TickCount ticks_late); +static void ClearDriveState(); +static void BeginReading(TickCount ticks_late = 0, bool after_seek = false); +static void BeginPlaying(u8 track, TickCount ticks_late = 0, bool after_seek = false); +static void DoShellOpenComplete(TickCount ticks_late); +static void DoSeekComplete(TickCount ticks_late); +static void DoStatSecondResponse(); +static void DoChangeSessionComplete(); +static void DoSpinUpComplete(); +static void DoSpeedChangeOrImplicitTOCReadComplete(); +static void DoIDRead(); +static void DoSectorRead(); +static void ProcessDataSectorHeader(const u8* raw_sector); +static void ProcessDataSector(const u8* raw_sector, const CDImage::SubChannelQ& subq); +static void ProcessXAADPCMSector(const u8* raw_sector, const CDImage::SubChannelQ& subq); +static void ProcessCDDASector(const u8* raw_sector, const CDImage::SubChannelQ& subq); +static void StopReadingWithDataEnd(); +static void StartMotor(); +static void StopMotor(); +static void BeginSeeking(bool logical, bool read_after_seek, bool play_after_seek); +static void UpdatePositionWhileSeeking(); +static void UpdatePhysicalPosition(bool update_logical); +static void SetHoldPosition(CDImage::LBA lba, bool update_subq); +static void ResetCurrentXAFile(); +static void ResetAudioDecoder(); +static void LoadDataFIFO(); +static void ClearSectorBuffers(); + +template +static void ResampleXAADPCM(const s16* frames_in, u32 num_frames_in); + +static std::unique_ptr s_command_event; +static std::unique_ptr s_command_second_response_event; +static std::unique_ptr s_drive_event; + +static Command s_command = Command::None; +static Command s_command_second_response = Command::None; +static DriveState s_drive_state = DriveState::Idle; +static DiscRegion s_disc_region = DiscRegion::Other; + +static StatusRegister s_status = {}; +static SecondaryStatusRegister s_secondary_status = {}; +static ModeRegister s_mode = {}; + +static u8 s_interrupt_enable_register = INTERRUPT_REGISTER_MASK; +static u8 s_interrupt_flag_register = 0; +static u8 s_pending_async_interrupt = 0; + +static CDImage::Position s_setloc_position = {}; +static CDImage::LBA s_requested_lba{}; +static CDImage::LBA s_current_lba{}; // this is the hold position +static CDImage::LBA s_seek_start_lba{}; +static CDImage::LBA s_seek_end_lba{}; +static CDImage::LBA s_physical_lba{}; // current position of the disc with respect to time +static u32 s_physical_lba_update_tick = 0; +static u32 s_physical_lba_update_carry = 0; +static bool s_setloc_pending = false; +static bool s_read_after_seek = false; +static bool s_play_after_seek = false; + +static bool s_muted = false; +static bool s_adpcm_muted = false; + +static u8 s_xa_filter_file_number = 0; +static u8 s_xa_filter_channel_number = 0; +static u8 s_xa_current_file_number = 0; +static u8 s_xa_current_channel_number = 0; +static u8 s_xa_current_set = false; + +static CDImage::SectorHeader s_last_sector_header{}; +static CDXA::XASubHeader s_last_sector_subheader{}; +static bool s_last_sector_header_valid = false; +static CDImage::SubChannelQ s_last_subq{}; +static u8 s_last_cdda_report_frame_nibble = 0xFF; +static u8 s_play_track_number_bcd = 0xFF; +static u8 s_async_command_parameter = 0x00; +static s8 s_fast_forward_rate = 0; + +static std::array, 2> s_cd_audio_volume_matrix{}; +static std::array, 2> s_next_cd_audio_volume_matrix{}; + +static std::array s_xa_last_samples{}; +static std::array, 2> s_xa_resample_ring_buffer{}; +static u8 s_xa_resample_p = 0; +static u8 s_xa_resample_sixstep = 6; + +static InlineFIFOQueue s_param_fifo; +static InlineFIFOQueue s_response_fifo; +static InlineFIFOQueue s_async_response_fifo; +static HeapFIFOQueue s_data_fifo; + +struct SectorBuffer +{ + HeapArray data; + u32 size; +}; + +static u32 s_current_read_sector_buffer = 0; +static u32 s_current_write_sector_buffer = 0; +static std::array s_sector_buffers; + +static CDROMAsyncReader m_reader; + +// two 16-bit samples packed in 32-bits +static HeapFIFOQueue s_audio_fifo; + static constexpr std::array s_drive_state_names = { {"Idle", "Opening Shell", "Resetting", "Seeking (Physical)", "Seeking (Logical)", "Reading ID", "Reading TOC", "Reading", "Playing", "Pausing", "Stopping", "Changing Session", "Spinning Up", "Seeking (Implicit)", @@ -74,28 +407,15 @@ static std::array s_command_info = {{ {"Unknown", 0}, {"Unknown", 0}, {nullptr, 0} // Unknown }}; -CDROM g_cdrom; - -CDROM::CDROM() = default; - -CDROM::~CDROM() = default; +} // namespace CDROM void CDROM::Initialize() { - m_command_event = TimingEvents::CreateTimingEvent( - "CDROM Command Event", 1, 1, - [](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); }, - this, false); + s_command_event = + TimingEvents::CreateTimingEvent("CDROM Command Event", 1, 1, &CDROM::ExecuteCommand, nullptr, false); + s_command_second_response_event = TimingEvents::CreateTimingEvent( + "CDROM Command Second Response Event", 1, 1, &CDROM::ExecuteCommandSecondResponse, nullptr, false); + s_drive_event = TimingEvents::CreateTimingEvent("CDROM Drive Event", 1, 1, &CDROM::ExecuteDrive, nullptr, false); if (g_settings.cdrom_readahead_sectors > 0) m_reader.StartThread(g_settings.cdrom_readahead_sectors); @@ -105,65 +425,65 @@ void CDROM::Initialize() void CDROM::Shutdown() { - m_command_event.reset(); - m_command_second_response_event.reset(); - m_drive_event.reset(); + s_command_event.reset(); + s_command_second_response_event.reset(); + s_drive_event.reset(); m_reader.StopThread(); m_reader.RemoveMedia(); } void CDROM::Reset() { - m_command = Command::None; - m_command_event->Deactivate(); + s_command = Command::None; + s_command_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_interrupt_enable_register = INTERRUPT_REGISTER_MASK; - m_interrupt_flag_register = 0; - m_pending_async_interrupt = 0; - m_setloc_position = {}; - m_seek_start_lba = 0; - m_seek_end_lba = 0; - m_setloc_pending = false; - m_read_after_seek = false; - m_play_after_seek = false; - m_muted = false; - m_adpcm_muted = false; - m_xa_filter_file_number = 0; - m_xa_filter_channel_number = 0; - m_xa_current_file_number = 0; - m_xa_current_channel_number = 0; - m_xa_current_set = false; - 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_cdda_report_frame_nibble = 0xFF; + s_status.bits = 0; + s_secondary_status.bits = 0; + s_secondary_status.motor_on = CanReadMedia(); + s_secondary_status.shell_open = !CanReadMedia(); + s_mode.bits = 0; + s_mode.read_raw_sector = true; + s_interrupt_enable_register = INTERRUPT_REGISTER_MASK; + s_interrupt_flag_register = 0; + s_pending_async_interrupt = 0; + s_setloc_position = {}; + s_seek_start_lba = 0; + s_seek_end_lba = 0; + s_setloc_pending = false; + s_read_after_seek = false; + s_play_after_seek = false; + s_muted = false; + s_adpcm_muted = false; + s_xa_filter_file_number = 0; + s_xa_filter_channel_number = 0; + s_xa_current_file_number = 0; + s_xa_current_channel_number = 0; + s_xa_current_set = false; + std::memset(&s_last_sector_header, 0, sizeof(s_last_sector_header)); + std::memset(&s_last_sector_subheader, 0, sizeof(s_last_sector_subheader)); + s_last_sector_header_valid = false; + std::memset(&s_last_subq, 0, sizeof(s_last_subq)); + s_last_cdda_report_frame_nibble = 0xFF; - m_next_cd_audio_volume_matrix[0][0] = 0x80; - m_next_cd_audio_volume_matrix[0][1] = 0x00; - m_next_cd_audio_volume_matrix[1][0] = 0x00; - m_next_cd_audio_volume_matrix[1][1] = 0x80; - m_cd_audio_volume_matrix = m_next_cd_audio_volume_matrix; + s_next_cd_audio_volume_matrix[0][0] = 0x80; + s_next_cd_audio_volume_matrix[0][1] = 0x00; + s_next_cd_audio_volume_matrix[1][0] = 0x00; + s_next_cd_audio_volume_matrix[1][1] = 0x80; + s_cd_audio_volume_matrix = s_next_cd_audio_volume_matrix; ResetAudioDecoder(); - m_param_fifo.Clear(); - m_response_fifo.Clear(); - m_async_response_fifo.Clear(); - m_data_fifo.Clear(); + s_param_fifo.Clear(); + s_response_fifo.Clear(); + s_async_response_fifo.Clear(); + s_data_fifo.Clear(); - m_current_read_sector_buffer = 0; - m_current_write_sector_buffer = 0; + s_current_read_sector_buffer = 0; + s_current_write_sector_buffer = 0; for (u32 i = 0; i < NUM_SECTOR_BUFFERS; i++) { - m_sector_buffers[i].data.fill(0); - m_sector_buffers[i].size = 0; + s_sector_buffers[i].data.fill(0); + s_sector_buffers[i].size = 0; } UpdateStatusRegister(); @@ -173,36 +493,36 @@ void CDROM::Reset() void CDROM::SoftReset(TickCount ticks_late) { - const bool was_double_speed = m_mode.double_speed; + const bool was_double_speed = s_mode.double_speed; ClearCommandSecondResponse(); ClearDriveState(); - 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_pending_async_interrupt = 0; - m_setloc_position = {}; - m_setloc_pending = false; - m_read_after_seek = false; - m_play_after_seek = false; - m_muted = false; - m_adpcm_muted = false; - m_last_cdda_report_frame_nibble = 0xFF; + s_secondary_status.bits = 0; + s_secondary_status.motor_on = CanReadMedia(); + s_secondary_status.shell_open = !CanReadMedia(); + s_mode.bits = 0; + s_mode.read_raw_sector = true; + s_pending_async_interrupt = 0; + s_setloc_position = {}; + s_setloc_pending = false; + s_read_after_seek = false; + s_play_after_seek = false; + s_muted = false; + s_adpcm_muted = false; + s_last_cdda_report_frame_nibble = 0xFF; ResetAudioDecoder(); - m_param_fifo.Clear(); - m_async_response_fifo.Clear(); - m_data_fifo.Clear(); + s_param_fifo.Clear(); + s_async_response_fifo.Clear(); + s_data_fifo.Clear(); - m_current_read_sector_buffer = 0; - m_current_write_sector_buffer = 0; + s_current_read_sector_buffer = 0; + s_current_write_sector_buffer = 0; for (u32 i = 0; i < NUM_SECTOR_BUFFERS; i++) { - m_sector_buffers[i].data.fill(0); - m_sector_buffers[i].size = 0; + s_sector_buffers[i].data.fill(0); + s_sector_buffers[i].size = 0; } UpdateStatusRegister(); @@ -210,107 +530,127 @@ void CDROM::SoftReset(TickCount ticks_late) if (HasMedia()) { const TickCount speed_change_ticks = was_double_speed ? GetTicksForSpeedChange() : 0; - const TickCount seek_ticks = (m_current_lba != 0) ? GetTicksForSeek(0) : 0; + const TickCount seek_ticks = (s_current_lba != 0) ? GetTicksForSeek(0) : 0; const TickCount total_ticks = std::max(speed_change_ticks + seek_ticks, INIT_TICKS) - ticks_late; Log_DevPrintf("CDROM init total disc ticks = %d (speed change = %d, seek = %d)", total_ticks, speed_change_ticks, seek_ticks); - if (m_current_lba != 0) + if (s_current_lba != 0) { - m_drive_state = DriveState::SeekingImplicit; - m_drive_event->SetIntervalAndSchedule(total_ticks); - m_requested_lba = 0; - m_reader.QueueReadSector(m_requested_lba); - m_seek_start_lba = m_current_lba; - m_seek_end_lba = 0; + s_drive_state = DriveState::SeekingImplicit; + s_drive_event->SetIntervalAndSchedule(total_ticks); + s_requested_lba = 0; + m_reader.QueueReadSector(s_requested_lba); + s_seek_start_lba = s_current_lba; + s_seek_end_lba = 0; } else { - m_drive_state = DriveState::ChangingSpeedOrTOCRead; - m_drive_event->Schedule(total_ticks); + s_drive_state = DriveState::ChangingSpeedOrTOCRead; + s_drive_event->Schedule(total_ticks); } } } 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); - sw.Do(&m_mode.bits); + sw.Do(&s_command); + sw.DoEx(&s_command_second_response, 53, Command::None); + sw.Do(&s_drive_state); + sw.Do(&s_status.bits); + sw.Do(&s_secondary_status.bits); + sw.Do(&s_mode.bits); - bool current_double_speed = m_mode.double_speed; + bool current_double_speed = s_mode.double_speed; sw.Do(¤t_double_speed); - sw.Do(&m_interrupt_enable_register); - sw.Do(&m_interrupt_flag_register); - sw.Do(&m_pending_async_interrupt); - sw.DoPOD(&m_setloc_position); - sw.Do(&m_current_lba); - sw.Do(&m_seek_start_lba); - sw.Do(&m_seek_end_lba); - sw.DoEx(&m_physical_lba, 49, m_current_lba); - sw.DoEx(&m_physical_lba_update_tick, 49, static_cast(0)); - sw.DoEx(&m_physical_lba_update_carry, 54, static_cast(0)); - sw.Do(&m_setloc_pending); - sw.Do(&m_read_after_seek); - sw.Do(&m_play_after_seek); - sw.Do(&m_muted); - sw.Do(&m_adpcm_muted); - sw.Do(&m_xa_filter_file_number); - sw.Do(&m_xa_filter_channel_number); - sw.Do(&m_xa_current_file_number); - sw.Do(&m_xa_current_channel_number); - sw.Do(&m_xa_current_set); - 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_cdda_report_frame_nibble); - sw.Do(&m_play_track_number_bcd); - sw.Do(&m_async_command_parameter); + sw.Do(&s_interrupt_enable_register); + sw.Do(&s_interrupt_flag_register); + sw.Do(&s_pending_async_interrupt); + sw.DoPOD(&s_setloc_position); + sw.Do(&s_current_lba); + sw.Do(&s_seek_start_lba); + sw.Do(&s_seek_end_lba); + sw.DoEx(&s_physical_lba, 49, s_current_lba); + sw.DoEx(&s_physical_lba_update_tick, 49, static_cast(0)); + sw.DoEx(&s_physical_lba_update_carry, 54, static_cast(0)); + sw.Do(&s_setloc_pending); + sw.Do(&s_read_after_seek); + sw.Do(&s_play_after_seek); + sw.Do(&s_muted); + sw.Do(&s_adpcm_muted); + sw.Do(&s_xa_filter_file_number); + sw.Do(&s_xa_filter_channel_number); + sw.Do(&s_xa_current_file_number); + sw.Do(&s_xa_current_channel_number); + sw.Do(&s_xa_current_set); + sw.DoBytes(&s_last_sector_header, sizeof(s_last_sector_header)); + sw.DoBytes(&s_last_sector_subheader, sizeof(s_last_sector_subheader)); + sw.Do(&s_last_sector_header_valid); + sw.DoBytes(&s_last_subq, sizeof(s_last_subq)); + sw.Do(&s_last_cdda_report_frame_nibble); + sw.Do(&s_play_track_number_bcd); + sw.Do(&s_async_command_parameter); - sw.DoEx(&m_fast_forward_rate, 49, static_cast(0)); + sw.DoEx(&s_fast_forward_rate, 49, static_cast(0)); - sw.Do(&m_cd_audio_volume_matrix); - sw.Do(&m_next_cd_audio_volume_matrix); - sw.Do(&m_xa_last_samples); - sw.Do(&m_xa_resample_ring_buffer); - sw.Do(&m_xa_resample_p); - sw.Do(&m_xa_resample_sixstep); - sw.Do(&m_param_fifo); - sw.Do(&m_response_fifo); - sw.Do(&m_async_response_fifo); - sw.Do(&m_data_fifo); + sw.Do(&s_cd_audio_volume_matrix); + sw.Do(&s_next_cd_audio_volume_matrix); + sw.Do(&s_xa_last_samples); + sw.Do(&s_xa_resample_ring_buffer); + sw.Do(&s_xa_resample_p); + sw.Do(&s_xa_resample_sixstep); + sw.Do(&s_param_fifo); + sw.Do(&s_response_fifo); + sw.Do(&s_async_response_fifo); + sw.Do(&s_data_fifo); - sw.Do(&m_current_read_sector_buffer); - sw.Do(&m_current_write_sector_buffer); + sw.Do(&s_current_read_sector_buffer); + sw.Do(&s_current_write_sector_buffer); for (u32 i = 0; i < NUM_SECTOR_BUFFERS; i++) { - sw.Do(&m_sector_buffers[i].data); - sw.Do(&m_sector_buffers[i].size); + sw.Do(&s_sector_buffers[i].data); + sw.Do(&s_sector_buffers[i].size); } - sw.Do(&m_audio_fifo); - sw.Do(&m_requested_lba); + sw.Do(&s_audio_fifo); + sw.Do(&s_requested_lba); if (sw.IsReading()) { if (m_reader.HasMedia()) - m_reader.QueueReadSector(m_requested_lba); + m_reader.QueueReadSector(s_requested_lba); UpdateCommandEvent(); - m_drive_event->SetState(!IsDriveIdle()); + s_drive_event->SetState(!IsDriveIdle()); // Time will get fixed up later. - m_command_second_response_event->SetState(m_command_second_response != Command::None); + s_command_second_response_event->SetState(s_command_second_response != Command::None); } return !sw.HasError(); } -bool CDROM::IsMediaPS1Disc() const +bool CDROM::HasMedia() +{ + return m_reader.HasMedia(); +} + +const std::string& CDROM::GetMediaFileName() +{ + return m_reader.GetMediaFileName(); +} + +const CDImage* CDROM::GetMedia() +{ + return m_reader.GetMedia(); +} + +DiscRegion CDROM::GetDiscRegion() +{ + return s_disc_region; +} + +bool CDROM::IsMediaPS1Disc() { if (!m_reader.HasMedia()) return false; @@ -322,12 +662,38 @@ bool CDROM::IsMediaPS1Disc() const return true; } -bool CDROM::DoesMediaRegionMatchConsole() const +bool CDROM::DoesMediaRegionMatchConsole() { if (!g_settings.cdrom_region_check) return true; - return System::GetRegion() == System::GetConsoleRegionForDiscRegion(m_disc_region); + return System::GetRegion() == System::GetConsoleRegionForDiscRegion(s_disc_region); +} + +bool CDROM::IsDriveIdle() +{ + return s_drive_state == DriveState::Idle; +} + +bool CDROM::IsMotorOn() +{ + return s_secondary_status.motor_on; +} + +bool CDROM::IsSeeking() +{ + return (s_drive_state == DriveState::SeekingLogical || s_drive_state == DriveState::SeekingPhysical || + s_drive_state == DriveState::SeekingImplicit); +} + +bool CDROM::IsReadingOrPlaying() +{ + return (s_drive_state == DriveState::Reading || s_drive_state == DriveState::Playing); +} + +bool CDROM::CanReadMedia() +{ + return (s_drive_state != DriveState::ShellOpening && m_reader.HasMedia()); } void CDROM::InsertMedia(std::unique_ptr media) @@ -336,12 +702,12 @@ void CDROM::InsertMedia(std::unique_ptr media) RemoveMedia(true); // set the region from the system area of the disc - m_disc_region = System::GetRegionForImage(media.get()); - Log_InfoPrintf("Inserting new media, disc region: %s, console region: %s", Settings::GetDiscRegionName(m_disc_region), + s_disc_region = System::GetRegionForImage(media.get()); + Log_InfoPrintf("Inserting new media, disc region: %s, console region: %s", Settings::GetDiscRegionName(s_disc_region), Settings::GetConsoleRegionName(System::GetRegion())); // motor automatically spins up - if (m_drive_state != DriveState::ShellOpening) + if (s_drive_state != DriveState::ShellOpening) StartMotor(); m_reader.SetMedia(std::move(media)); @@ -361,18 +727,18 @@ std::unique_ptr CDROM::RemoveMedia(bool for_disc_swap) Log_InfoPrintf("Removing CD..."); std::unique_ptr image = m_reader.RemoveMedia(); - m_last_sector_header_valid = false; + s_last_sector_header_valid = false; - m_secondary_status.motor_on = false; - m_secondary_status.shell_open = true; - m_secondary_status.ClearActiveBits(); - m_disc_region = DiscRegion::Other; + s_secondary_status.motor_on = false; + s_secondary_status.shell_open = true; + s_secondary_status.ClearActiveBits(); + s_disc_region = DiscRegion::Other; // If the drive was doing anything, we need to abort the command. ClearDriveState(); ClearCommandSecondResponse(); - m_command = Command::None; - m_command_event->Deactivate(); + s_command = Command::None; + s_command_event->Deactivate(); // The console sends an interrupt when the shell is opened regardless of whether a command was executing. if (HasPendingAsyncInterrupt()) @@ -382,8 +748,8 @@ std::unique_ptr CDROM::RemoveMedia(bool for_disc_swap) // Begin spin-down timer, we can't swap the new disc in immediately for some games (e.g. Metal Gear Solid). if (for_disc_swap) { - m_drive_state = DriveState::ShellOpening; - m_drive_event->SetIntervalAndSchedule(stop_ticks); + s_drive_state = DriveState::ShellOpening; + s_drive_event->SetIntervalAndSchedule(stop_ticks); } return image; @@ -425,14 +791,14 @@ void CDROM::SetReadaheadSectors(u32 readahead_sectors) m_reader.StopThread(); if (HasMedia()) - m_reader.QueueReadSector(m_requested_lba); + m_reader.QueueReadSector(s_requested_lba); } void CDROM::CPUClockChanged() { // reschedule the disc read event if (IsReadingOrPlaying()) - m_drive_event->SetInterval(GetTicksForRead()); + s_drive_event->SetInterval(GetTicksForRead()); } u8 CDROM::ReadRegister(u32 offset) @@ -440,18 +806,18 @@ u8 CDROM::ReadRegister(u32 offset) switch (offset) { case 0: // status register - Log_TracePrintf("CDROM read status register -> 0x%08X", m_status.bits); - return m_status.bits; + Log_TracePrintf("CDROM read status register -> 0x%08X", s_status.bits); + return s_status.bits; case 1: // always response FIFO { - if (m_response_fifo.IsEmpty()) + if (s_response_fifo.IsEmpty()) { Log_DevPrint("Response FIFO empty on read"); return 0x00; } - const u8 value = m_response_fifo.Pop(); + const u8 value = s_response_fifo.Pop(); UpdateStatusRegister(); Log_DebugPrintf("CDROM read response FIFO -> 0x%08X", ZeroExtend32(value)); return value; @@ -459,7 +825,7 @@ u8 CDROM::ReadRegister(u32 offset) case 2: // always data FIFO { - const u8 value = m_data_fifo.Pop(); + const u8 value = s_data_fifo.Pop(); UpdateStatusRegister(); Log_DebugPrintf("CDROM read data FIFO -> 0x%08X", ZeroExtend32(value)); return value; @@ -467,15 +833,15 @@ u8 CDROM::ReadRegister(u32 offset) case 3: { - if (m_status.index & 1) + if (s_status.index & 1) { - const u8 value = m_interrupt_flag_register | ~INTERRUPT_REGISTER_MASK; + const u8 value = s_interrupt_flag_register | ~INTERRUPT_REGISTER_MASK; Log_DebugPrintf("CDROM read interrupt flag register -> 0x%02X", ZeroExtend32(value)); return value; } else { - const u8 value = m_interrupt_enable_register | ~INTERRUPT_REGISTER_MASK; + const u8 value = s_interrupt_enable_register | ~INTERRUPT_REGISTER_MASK; Log_DebugPrintf("CDROM read interrupt enable register -> 0x%02X", ZeroExtend32(value)); return value; } @@ -484,7 +850,7 @@ u8 CDROM::ReadRegister(u32 offset) } Log_ErrorPrintf("Unknown CDROM register read: offset=0x%02X, index=%d", offset, - ZeroExtend32(m_status.index.GetValue())); + ZeroExtend32(s_status.index.GetValue())); Panic("Unknown CDROM register"); return 0; } @@ -494,11 +860,11 @@ void CDROM::WriteRegister(u32 offset, u8 value) if (offset == 0) { Log_TracePrintf("CDROM status register <- 0x%02X", value); - m_status.bits = (m_status.bits & static_cast(~3)) | (value & u8(3)); + s_status.bits = (s_status.bits & static_cast(~3)) | (value & u8(3)); return; } - const u32 reg = (m_status.index * 3u) + (offset - 1); + const u32 reg = (s_status.index * 3u) + (offset - 1); switch (reg) { case 0: @@ -510,13 +876,13 @@ void CDROM::WriteRegister(u32 offset, u8 value) case 1: { - if (m_param_fifo.IsFull()) + if (s_param_fifo.IsFull()) { Log_WarningPrintf("Parameter FIFO overflow"); - m_param_fifo.RemoveOne(); + s_param_fifo.RemoveOne(); } - m_param_fifo.Push(value); + s_param_fifo.Push(value); UpdateStatusRegister(); return; } @@ -539,7 +905,7 @@ void CDROM::WriteRegister(u32 offset, u8 value) else { Log_DebugPrintf("Clearing data FIFO"); - m_data_fifo.Clear(); + s_data_fifo.Clear(); } UpdateStatusRegister(); @@ -555,7 +921,7 @@ void CDROM::WriteRegister(u32 offset, u8 value) case 4: { Log_DebugPrintf("Interrupt enable register <- 0x%02X", value); - m_interrupt_enable_register = value & INTERRUPT_REGISTER_MASK; + s_interrupt_enable_register = value & INTERRUPT_REGISTER_MASK; UpdateInterruptRequest(); return; } @@ -563,8 +929,8 @@ void CDROM::WriteRegister(u32 offset, u8 value) case 5: { Log_DebugPrintf("Interrupt flag register <- 0x%02X", value); - m_interrupt_flag_register &= ~(value & INTERRUPT_REGISTER_MASK); - if (m_interrupt_flag_register == 0) + s_interrupt_flag_register &= ~(value & INTERRUPT_REGISTER_MASK); + if (s_interrupt_flag_register == 0) { if (HasPendingAsyncInterrupt()) DeliverAsyncInterrupt(); @@ -575,7 +941,7 @@ void CDROM::WriteRegister(u32 offset, u8 value) // Bit 6 clears the parameter FIFO. if (value & 0x40) { - m_param_fifo.Clear(); + s_param_fifo.Clear(); UpdateStatusRegister(); } @@ -591,28 +957,28 @@ void CDROM::WriteRegister(u32 offset, u8 value) case 7: { Log_DebugPrintf("Audio volume for left-to-left output <- 0x%02X", value); - m_next_cd_audio_volume_matrix[0][0] = value; + s_next_cd_audio_volume_matrix[0][0] = value; return; } case 8: { Log_DebugPrintf("Audio volume for left-to-right output <- 0x%02X", value); - m_next_cd_audio_volume_matrix[0][1] = value; + s_next_cd_audio_volume_matrix[0][1] = value; return; } case 9: { Log_DebugPrintf("Audio volume for right-to-right output <- 0x%02X", value); - m_next_cd_audio_volume_matrix[1][1] = value; + s_next_cd_audio_volume_matrix[1][1] = value; return; } case 10: { Log_DebugPrintf("Audio volume for right-to-left output <- 0x%02X", value); - m_next_cd_audio_volume_matrix[1][0] = value; + s_next_cd_audio_volume_matrix[1][0] = value; return; } @@ -621,25 +987,25 @@ void CDROM::WriteRegister(u32 offset, u8 value) Log_DebugPrintf("Audio volume apply changes <- 0x%02X", value); const bool adpcm_muted = ConvertToBoolUnchecked(value & u8(0x01)); - if (adpcm_muted != m_adpcm_muted || - (value & 0x20 && std::memcmp(m_cd_audio_volume_matrix.data(), m_next_cd_audio_volume_matrix.data(), - sizeof(m_cd_audio_volume_matrix)) != 0)) + if (adpcm_muted != s_adpcm_muted || + (value & 0x20 && std::memcmp(s_cd_audio_volume_matrix.data(), s_next_cd_audio_volume_matrix.data(), + sizeof(s_cd_audio_volume_matrix)) != 0)) { if (HasPendingDiscEvent()) - m_drive_event->InvokeEarly(); + s_drive_event->InvokeEarly(); SPU::GeneratePendingSamples(); } - m_adpcm_muted = adpcm_muted; + s_adpcm_muted = adpcm_muted; if (value & 0x20) - m_cd_audio_volume_matrix = m_next_cd_audio_volume_matrix; + s_cd_audio_volume_matrix = s_next_cd_audio_volume_matrix; return; } default: { Log_ErrorPrintf("Unknown CDROM register write: offset=0x%02X, index=%d, reg=%u, value=0x%02X", offset, - m_status.index.GetValue(), reg, value); + s_status.index.GetValue(), reg, value); return; } } @@ -647,57 +1013,72 @@ void CDROM::WriteRegister(u32 offset, u8 value) void CDROM::DMARead(u32* words, u32 word_count) { - const u32 words_in_fifo = m_data_fifo.GetSize() / 4; + const u32 words_in_fifo = s_data_fifo.GetSize() / 4; if (words_in_fifo < word_count) { Log_ErrorPrintf("DMA read on empty/near-empty data FIFO"); std::memset(words + words_in_fifo, 0, sizeof(u32) * (word_count - words_in_fifo)); } - const u32 bytes_to_read = std::min(word_count * sizeof(u32), m_data_fifo.GetSize()); - m_data_fifo.PopRange(reinterpret_cast(words), bytes_to_read); + const u32 bytes_to_read = std::min(word_count * sizeof(u32), s_data_fifo.GetSize()); + s_data_fifo.PopRange(reinterpret_cast(words), bytes_to_read); +} + +bool CDROM::HasPendingCommand() +{ + return s_command != Command::None; +} + +bool CDROM::HasPendingInterrupt() +{ + return s_interrupt_flag_register != 0; +} + +bool CDROM::HasPendingAsyncInterrupt() +{ + return s_pending_async_interrupt != 0; } void CDROM::SetInterrupt(Interrupt interrupt) { - m_interrupt_flag_register = static_cast(interrupt); + s_interrupt_flag_register = static_cast(interrupt); UpdateInterruptRequest(); } void CDROM::SetAsyncInterrupt(Interrupt interrupt) { - if (m_interrupt_flag_register == static_cast(interrupt)) + if (s_interrupt_flag_register == static_cast(interrupt)) { Log_DevPrintf("Not setting async interrupt %u because there is already one unacknowledged", static_cast(interrupt)); - m_async_response_fifo.Clear(); + s_async_response_fifo.Clear(); return; } - Assert(m_pending_async_interrupt == 0); - m_pending_async_interrupt = static_cast(interrupt); + Assert(s_pending_async_interrupt == 0); + s_pending_async_interrupt = static_cast(interrupt); if (!HasPendingInterrupt()) DeliverAsyncInterrupt(); } void CDROM::ClearAsyncInterrupt() { - m_pending_async_interrupt = 0; - m_async_response_fifo.Clear(); + s_pending_async_interrupt = 0; + s_async_response_fifo.Clear(); } void CDROM::DeliverAsyncInterrupt() { - Assert(m_pending_async_interrupt != 0 && !HasPendingInterrupt()); - Log_DebugPrintf("Delivering async interrupt %u", m_pending_async_interrupt); + Assert(s_pending_async_interrupt != 0 && !HasPendingInterrupt()); + Log_DebugPrintf("Delivering async interrupt %u", s_pending_async_interrupt); - if (m_pending_async_interrupt == static_cast(Interrupt::DataReady)) - m_current_read_sector_buffer = m_current_write_sector_buffer; + if (s_pending_async_interrupt == static_cast(Interrupt::DataReady)) + s_current_read_sector_buffer = s_current_write_sector_buffer; - m_response_fifo.Clear(); - m_response_fifo.PushFromQueue(&m_async_response_fifo); - m_interrupt_flag_register = m_pending_async_interrupt; - m_pending_async_interrupt = 0; + s_response_fifo.Clear(); + s_response_fifo.PushFromQueue(&s_async_response_fifo); + s_interrupt_flag_register = s_pending_async_interrupt; + s_pending_async_interrupt = 0; UpdateInterruptRequest(); UpdateStatusRegister(); UpdateCommandEvent(); @@ -705,47 +1086,47 @@ void CDROM::DeliverAsyncInterrupt() void CDROM::SendACKAndStat() { - m_response_fifo.Push(m_secondary_status.bits); + s_response_fifo.Push(s_secondary_status.bits); SetInterrupt(Interrupt::ACK); } void CDROM::SendErrorResponse(u8 stat_bits /* = STAT_ERROR */, u8 reason /* = 0x80 */) { - m_response_fifo.Push(m_secondary_status.bits | stat_bits); - m_response_fifo.Push(reason); + s_response_fifo.Push(s_secondary_status.bits | stat_bits); + s_response_fifo.Push(reason); SetInterrupt(Interrupt::Error); } void CDROM::SendAsyncErrorResponse(u8 stat_bits /* = STAT_ERROR */, u8 reason /* = 0x80 */) { - m_async_response_fifo.Push(m_secondary_status.bits | stat_bits); - m_async_response_fifo.Push(reason); + s_async_response_fifo.Push(s_secondary_status.bits | stat_bits); + s_async_response_fifo.Push(reason); SetAsyncInterrupt(Interrupt::Error); } void CDROM::UpdateStatusRegister() { - m_status.ADPBUSY = false; - m_status.PRMEMPTY = m_param_fifo.IsEmpty(); - m_status.PRMWRDY = !m_param_fifo.IsFull(); - m_status.RSLRRDY = !m_response_fifo.IsEmpty(); - m_status.DRQSTS = !m_data_fifo.IsEmpty(); - m_status.BUSYSTS = HasPendingCommand(); + s_status.ADPBUSY = false; + s_status.PRMEMPTY = s_param_fifo.IsEmpty(); + s_status.PRMWRDY = !s_param_fifo.IsFull(); + s_status.RSLRRDY = !s_response_fifo.IsEmpty(); + s_status.DRQSTS = !s_data_fifo.IsEmpty(); + s_status.BUSYSTS = HasPendingCommand(); - g_dma.SetRequest(DMA::Channel::CDROM, m_status.DRQSTS); + g_dma.SetRequest(DMA::Channel::CDROM, s_status.DRQSTS); } void CDROM::UpdateInterruptRequest() { - if ((m_interrupt_flag_register & m_interrupt_enable_register) == 0) + if ((s_interrupt_flag_register & s_interrupt_enable_register) == 0) return; g_interrupt_controller.InterruptRequest(InterruptController::IRQ::CDROM); } -bool CDROM::HasPendingDiscEvent() const +bool CDROM::HasPendingDiscEvent() { - return (m_drive_event->IsActive() && m_drive_event->GetTicksUntilNextExecution() <= 0); + return (s_drive_event->IsActive() && s_drive_event->GetTicksUntilNextExecution() <= 0); } TickCount CDROM::GetAckDelayForCommand(Command command) @@ -772,8 +1153,8 @@ TickCount CDROM::GetTicksForSpinUp() TickCount CDROM::GetTicksForIDRead() { TickCount ticks = ID_READ_TICKS; - if (m_drive_state == DriveState::SpinningUp) - ticks += m_drive_event->GetTicksUntilNextExecution(); + if (s_drive_state == DriveState::SpinningUp) + ticks += s_drive_event->GetTicksUntilNextExecution(); return ticks; } @@ -782,10 +1163,10 @@ TickCount CDROM::GetTicksForRead() { const TickCount tps = System::GetTicksPerSecond(); - if (g_settings.cdrom_read_speedup > 1 && !m_mode.cdda && !m_mode.xa_enable && m_mode.double_speed) + if (g_settings.cdrom_read_speedup > 1 && !s_mode.cdda && !s_mode.xa_enable && s_mode.double_speed) return tps / (150 * g_settings.cdrom_read_speedup); - return m_mode.double_speed ? (tps / 150) : (tps / 75); + return s_mode.double_speed ? (tps / 150) : (tps / 75); } TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba, bool ignore_speed_change) @@ -797,22 +1178,22 @@ TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba, bool ignore_speed_change) u32 ticks = static_cast(MIN_TICKS); if (IsSeeking()) - ticks += m_drive_event->GetTicksUntilNextExecution(); + ticks += s_drive_event->GetTicksUntilNextExecution(); else UpdatePhysicalPosition(false); const u32 ticks_per_sector = - m_mode.double_speed ? static_cast(System::MASTER_CLOCK / 150) : static_cast(System::MASTER_CLOCK / 75); + s_mode.double_speed ? static_cast(System::MASTER_CLOCK / 150) : static_cast(System::MASTER_CLOCK / 75); const u32 ticks_per_second = static_cast(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 = IsMotorOn() ? (IsSeeking() ? s_seek_end_lba : s_physical_lba) : 0; const u32 lba_diff = static_cast((new_lba > current_lba) ? (new_lba - current_lba) : (current_lba - new_lba)); // Motor spin-up time. - if (!m_secondary_status.motor_on) + if (!IsMotorOn()) { ticks += - (m_drive_state == DriveState::SpinningUp) ? m_drive_event->GetTicksUntilNextExecution() : GetTicksForSpinUp(); - if (m_drive_state == DriveState::ShellOpening || m_drive_state == DriveState::SpinningUp) + (s_drive_state == DriveState::SpinningUp) ? s_drive_event->GetTicksUntilNextExecution() : GetTicksForSpinUp(); + if (s_drive_state == DriveState::ShellOpening || s_drive_state == DriveState::SpinningUp) ClearDriveState(); } @@ -848,10 +1229,10 @@ TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba, bool ignore_speed_change) ticks += static_cast(seconds * static_cast(ticks_per_second)); } - if (m_drive_state == DriveState::ChangingSpeedOrTOCRead && !ignore_speed_change) + if (s_drive_state == DriveState::ChangingSpeedOrTOCRead && !ignore_speed_change) { // we're still reading the TOC, so add that time in - const TickCount remaining_change_ticks = m_drive_event->GetTicksUntilNextExecution(); + const TickCount remaining_change_ticks = s_drive_event->GetTicksUntilNextExecution(); ticks += remaining_change_ticks; Log_DevPrintf("Seek time for %u LBAs: %d (%.3f ms) (%d for speed change/implicit TOC read)", lba_diff, ticks, @@ -871,14 +1252,14 @@ TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba, bool ignore_speed_change) TickCount CDROM::GetTicksForStop(bool motor_was_on) { - return System::ScaleTicksToOverclock(motor_was_on ? (m_mode.double_speed ? 25000000 : 13000000) : 7000); + return System::ScaleTicksToOverclock(motor_was_on ? (s_mode.double_speed ? 25000000 : 13000000) : 7000); } TickCount CDROM::GetTicksForSpeedChange() { static constexpr u32 ticks_single_to_double = static_cast(0.8 * static_cast(System::MASTER_CLOCK)); static constexpr u32 ticks_double_to_single = static_cast(1.0 * static_cast(System::MASTER_CLOCK)); - return System::ScaleTicksToOverclock(m_mode.double_speed ? ticks_single_to_double : ticks_double_to_single); + return System::ScaleTicksToOverclock(s_mode.double_speed ? ticks_single_to_double : ticks_double_to_single); } TickCount CDROM::GetTicksForTOCRead() @@ -892,7 +1273,7 @@ TickCount CDROM::GetTicksForTOCRead() CDImage::LBA CDROM::GetNextSectorToBeRead() { if (!IsReadingOrPlaying()) - return m_current_lba; + return s_current_lba; m_reader.WaitForReadToComplete(); return m_reader.GetLastReadSector(); @@ -912,81 +1293,74 @@ void CDROM::BeginCommand(Command command) // behavior is not correct. So, let's use a heuristic; if the number of parameters of the "old" command is // greater than the "new" command, empty the FIFO, which will return the error when the command executes. // Otherwise, override the command with the new one. - if (s_command_info[static_cast(m_command)].expected_parameters > + if (s_command_info[static_cast(s_command)].expected_parameters > s_command_info[static_cast(command)].expected_parameters) { Log_WarningPrintf("Ignoring command 0x%02X (%s) and emptying FIFO as 0x%02x (%s) is still pending", static_cast(command), s_command_info[static_cast(command)].name, - static_cast(m_command), s_command_info[static_cast(m_command)].name); - m_param_fifo.Clear(); + static_cast(s_command), s_command_info[static_cast(s_command)].name); + s_param_fifo.Clear(); return; } - Log_WarningPrintf("Cancelling pending command 0x%02X (%s) for new command 0x%02X (%s)", static_cast(m_command), - s_command_info[static_cast(m_command)].name, static_cast(command), + Log_WarningPrintf("Cancelling pending command 0x%02X (%s) for new command 0x%02X (%s)", static_cast(s_command), + s_command_info[static_cast(s_command)].name, static_cast(command), s_command_info[static_cast(command)].name); // subtract the currently-elapsed ack ticks from the new command - if (m_command_event->IsActive()) + if (s_command_event->IsActive()) { - const TickCount elapsed_ticks = m_command_event->GetInterval() - m_command_event->GetTicksUntilNextExecution(); + const TickCount elapsed_ticks = s_command_event->GetInterval() - s_command_event->GetTicksUntilNextExecution(); ack_delay = std::max(ack_delay - elapsed_ticks, 1); - m_command_event->Deactivate(); + s_command_event->Deactivate(); } } - if (m_command_second_response != Command::None) + if (s_command_second_response != Command::None) { Log_WarningPrintf("Cancelling pending command 0x%02X (%s) second response", - static_cast(m_command_second_response), - s_command_info[static_cast(m_command_second_response)].name); + static_cast(s_command_second_response), + s_command_info[static_cast(s_command_second_response)].name); ClearCommandSecondResponse(); } - m_command = command; - m_command_event->SetIntervalAndSchedule(ack_delay); + s_command = command; + s_command_event->SetIntervalAndSchedule(ack_delay); UpdateCommandEvent(); UpdateStatusRegister(); } void CDROM::EndCommand() { - m_param_fifo.Clear(); + s_param_fifo.Clear(); - m_command = Command::None; - m_command_event->Deactivate(); + s_command = Command::None; + s_command_event->Deactivate(); UpdateStatusRegister(); } -void CDROM::AbortCommand() +void CDROM::ExecuteCommand(void*, TickCount ticks, TickCount ticks_late) { - m_command = Command::None; - m_command_event->Deactivate(); - UpdateStatusRegister(); -} - -void CDROM::ExecuteCommand(TickCount ticks_late) -{ - const CommandInfo& ci = s_command_info[static_cast(m_command)]; - 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) + const CommandInfo& ci = s_command_info[static_cast(s_command)]; + Log_DevPrintf("CDROM executing command 0x%02X (%s), stat = 0x%02X", static_cast(s_command), ci.name, + s_secondary_status.bits); + if (s_param_fifo.GetSize() < ci.expected_parameters) { - Log_WarningPrintf("Too few parameters for command 0x%02X (%s), expecting %u got %u", static_cast(m_command), - ci.name, ci.expected_parameters, m_param_fifo.GetSize()); + Log_WarningPrintf("Too few parameters for command 0x%02X (%s), expecting %u got %u", static_cast(s_command), + ci.name, ci.expected_parameters, s_param_fifo.GetSize()); SendErrorResponse(STAT_ERROR, ERROR_REASON_INCORRECT_NUMBER_OF_PARAMETERS); EndCommand(); return; } - if (!m_response_fifo.IsEmpty()) + if (!s_response_fifo.IsEmpty()) { Log_DebugPrintf("Response FIFO not empty on command begin"); - m_response_fifo.Clear(); + s_response_fifo.Clear(); } - switch (m_command) + switch (s_command) { case Command::Getstat: { @@ -997,7 +1371,7 @@ void CDROM::ExecuteCommand(TickCount ticks_late) // shell open bit is cleared after sending the status if (CanReadMedia()) - m_secondary_status.shell_open = false; + s_secondary_status.shell_open = false; EndCommand(); return; @@ -1005,7 +1379,7 @@ void CDROM::ExecuteCommand(TickCount ticks_late) case Command::Test: { - const u8 subcommand = m_param_fifo.Pop(); + const u8 subcommand = s_param_fifo.Pop(); ExecuteTestCommand(subcommand); return; } @@ -1048,12 +1422,12 @@ void CDROM::ExecuteCommand(TickCount ticks_late) case Command::Setfilter: { - const u8 file = m_param_fifo.Peek(0); - const u8 channel = m_param_fifo.Peek(1); + const u8 file = s_param_fifo.Peek(0); + const u8 channel = s_param_fifo.Peek(1); Log_DebugPrintf("CDROM setfilter command 0x%02X 0x%02X", ZeroExtend32(file), ZeroExtend32(channel)); - m_xa_filter_file_number = file; - m_xa_filter_channel_number = channel; - m_xa_current_set = false; + s_xa_filter_file_number = file; + s_xa_filter_channel_number = channel; + s_xa_current_set = false; SendACKAndStat(); EndCommand(); return; @@ -1061,41 +1435,41 @@ void CDROM::ExecuteCommand(TickCount ticks_late) case Command::Setmode: { - const u8 mode = m_param_fifo.Peek(0); - const bool speed_change = (mode & 0x80) != (m_mode.bits & 0x80); + const u8 mode = s_param_fifo.Peek(0); + const bool speed_change = (mode & 0x80) != (s_mode.bits & 0x80); Log_DevPrintf("CDROM setmode command 0x%02X", ZeroExtend32(mode)); - m_mode.bits = mode; + s_mode.bits = mode; SendACKAndStat(); EndCommand(); if (speed_change) { - if (m_drive_state == DriveState::ChangingSpeedOrTOCRead) + if (s_drive_state == DriveState::ChangingSpeedOrTOCRead) { // cancel the speed change if it's less than a quarter complete - if (m_drive_event->GetTicksUntilNextExecution() >= (GetTicksForSpeedChange() / 4)) + if (s_drive_event->GetTicksUntilNextExecution() >= (GetTicksForSpeedChange() / 4)) { Log_DevPrintf("Cancelling speed change event"); ClearDriveState(); } } - else if (m_drive_state != DriveState::SeekingImplicit && m_drive_state != DriveState::ShellOpening) + else if (s_drive_state != DriveState::SeekingImplicit && s_drive_state != DriveState::ShellOpening) { // if we're seeking or reading, we need to add time to the current seek/read const TickCount change_ticks = GetTicksForSpeedChange(); - if (m_drive_state != DriveState::Idle) + if (s_drive_state != DriveState::Idle) { Log_DevPrintf("Drive is %s, delaying event by %d ticks for speed change to %s-speed", - s_drive_state_names[static_cast(m_drive_state)], change_ticks, - m_mode.double_speed ? "double" : "single"); - m_drive_event->Delay(change_ticks); + s_drive_state_names[static_cast(s_drive_state)], change_ticks, + s_mode.double_speed ? "double" : "single"); + s_drive_event->Delay(change_ticks); } else { Log_DevPrintf("Drive is idle, speed change takes %d ticks", change_ticks); - m_drive_state = DriveState::ChangingSpeedOrTOCRead; - m_drive_event->Schedule(change_ticks); + s_drive_state = DriveState::ChangingSpeedOrTOCRead; + s_drive_event->Schedule(change_ticks); } } } @@ -1105,9 +1479,9 @@ void CDROM::ExecuteCommand(TickCount ticks_late) case Command::Setloc: { - const u8 mm = m_param_fifo.Peek(0); - const u8 ss = m_param_fifo.Peek(1); - const u8 ff = m_param_fifo.Peek(2); + const u8 mm = s_param_fifo.Peek(0); + const u8 ss = s_param_fifo.Peek(1); + const u8 ff = s_param_fifo.Peek(2); Log_DevPrintf("CDROM setloc command (%02X, %02X, %02X)", mm, ss, ff); // MM must be BCD, SS must be BCD and <0x60, FF must be BCD and <0x75 @@ -1121,10 +1495,10 @@ void CDROM::ExecuteCommand(TickCount ticks_late) { SendACKAndStat(); - m_setloc_position.minute = PackedBCDToBinary(mm); - m_setloc_position.second = PackedBCDToBinary(ss); - m_setloc_position.frame = PackedBCDToBinary(ff); - m_setloc_pending = true; + s_setloc_position.minute = PackedBCDToBinary(mm); + s_setloc_position.second = PackedBCDToBinary(ss); + s_setloc_position.frame = PackedBCDToBinary(ff); + s_setloc_pending = true; } EndCommand(); @@ -1134,7 +1508,7 @@ void CDROM::ExecuteCommand(TickCount ticks_late) case Command::SeekL: case Command::SeekP: { - const bool logical = (m_command == Command::SeekL); + const bool logical = (s_command == Command::SeekL); Log_DebugPrintf("CDROM %s command", logical ? "SeekL" : "SeekP"); if (IsSeeking()) @@ -1156,10 +1530,10 @@ void CDROM::ExecuteCommand(TickCount ticks_late) case Command::ReadT: { - const u8 session = m_param_fifo.Peek(0); + const u8 session = s_param_fifo.Peek(0); Log_DebugPrintf("CDROM ReadT command, session=%u", session); - if (!CanReadMedia() || m_drive_state == DriveState::Reading || m_drive_state == DriveState::Playing) + if (!CanReadMedia() || s_drive_state == DriveState::Reading || s_drive_state == DriveState::Playing) { SendErrorResponse(STAT_ERROR, ERROR_REASON_NOT_READY); } @@ -1171,9 +1545,9 @@ void CDROM::ExecuteCommand(TickCount ticks_late) { SendACKAndStat(); - m_async_command_parameter = session; - m_drive_state = DriveState::ChangingSession; - m_drive_event->Schedule(GetTicksForTOCRead()); + s_async_command_parameter = session; + s_drive_state = DriveState::ChangingSession; + s_drive_event->Schedule(GetTicksForTOCRead()); } EndCommand(); @@ -1188,7 +1562,7 @@ void CDROM::ExecuteCommand(TickCount ticks_late) { SendErrorResponse(STAT_ERROR, ERROR_REASON_NOT_READY); } - else if ((!IsMediaPS1Disc() || !DoesMediaRegionMatchConsole()) && !m_mode.cdda) + else if ((!IsMediaPS1Disc() || !DoesMediaRegionMatchConsole()) && !s_mode.cdda) { SendErrorResponse(STAT_ERROR, ERROR_REASON_INVALID_COMMAND); } @@ -1196,12 +1570,12 @@ void CDROM::ExecuteCommand(TickCount ticks_late) { SendACKAndStat(); - if ((!m_setloc_pending || m_setloc_position.ToLBA() == GetNextSectorToBeRead()) && - (m_drive_state == DriveState::Reading || (IsSeeking() && m_read_after_seek))) + if ((!s_setloc_pending || s_setloc_position.ToLBA() == GetNextSectorToBeRead()) && + (s_drive_state == DriveState::Reading || (IsSeeking() && s_read_after_seek))) { Log_DevPrintf("Ignoring read command with %s setloc, already reading/reading after seek", - m_setloc_pending ? "pending" : "same"); - m_setloc_pending = false; + s_setloc_pending ? "pending" : "same"); + s_setloc_pending = false; } else { @@ -1218,7 +1592,7 @@ void CDROM::ExecuteCommand(TickCount ticks_late) case Command::Play: { - const u8 track = m_param_fifo.IsEmpty() ? 0 : PackedBCDToBinary(m_param_fifo.Peek(0)); + const u8 track = s_param_fifo.IsEmpty() ? 0 : PackedBCDToBinary(s_param_fifo.Peek(0)); Log_DebugPrintf("CDROM play command, track=%u", track); if (!CanReadMedia()) @@ -1229,11 +1603,11 @@ void CDROM::ExecuteCommand(TickCount ticks_late) { SendACKAndStat(); - if (track == 0 && (!m_setloc_pending || m_setloc_position.ToLBA() == GetNextSectorToBeRead()) && - (m_drive_state == DriveState::Playing || (IsSeeking() && m_play_after_seek))) + if (track == 0 && (!s_setloc_pending || s_setloc_position.ToLBA() == GetNextSectorToBeRead()) && + (s_drive_state == DriveState::Playing || (IsSeeking() && s_play_after_seek))) { Log_DevPrintf("Ignoring play command with no/same setloc, already playing/playing after seek"); - m_fast_forward_rate = 0; + s_fast_forward_rate = 0; } else { @@ -1250,7 +1624,7 @@ void CDROM::ExecuteCommand(TickCount ticks_late) case Command::Forward: { - if (m_drive_state != DriveState::Playing || !CanReadMedia()) + if (s_drive_state != DriveState::Playing || !CanReadMedia()) { SendErrorResponse(STAT_ERROR, ERROR_REASON_NOT_READY); } @@ -1258,11 +1632,11 @@ void CDROM::ExecuteCommand(TickCount ticks_late) { SendACKAndStat(); - if (m_fast_forward_rate < 0) - m_fast_forward_rate = 0; + if (s_fast_forward_rate < 0) + s_fast_forward_rate = 0; - m_fast_forward_rate += static_cast(FAST_FORWARD_RATE_STEP); - m_fast_forward_rate = std::min(m_fast_forward_rate, static_cast(MAX_FAST_FORWARD_RATE)); + s_fast_forward_rate += static_cast(FAST_FORWARD_RATE_STEP); + s_fast_forward_rate = std::min(s_fast_forward_rate, static_cast(MAX_FAST_FORWARD_RATE)); } EndCommand(); @@ -1271,7 +1645,7 @@ void CDROM::ExecuteCommand(TickCount ticks_late) case Command::Backward: { - if (m_drive_state != DriveState::Playing || !CanReadMedia()) + if (s_drive_state != DriveState::Playing || !CanReadMedia()) { SendErrorResponse(STAT_ERROR, ERROR_REASON_NOT_READY); } @@ -1279,11 +1653,11 @@ void CDROM::ExecuteCommand(TickCount ticks_late) { SendACKAndStat(); - if (m_fast_forward_rate > 0) - m_fast_forward_rate = 0; + if (s_fast_forward_rate > 0) + s_fast_forward_rate = 0; - m_fast_forward_rate -= static_cast(FAST_FORWARD_RATE_STEP); - m_fast_forward_rate = std::max(m_fast_forward_rate, -static_cast(MAX_FAST_FORWARD_RATE)); + s_fast_forward_rate -= static_cast(FAST_FORWARD_RATE_STEP); + s_fast_forward_rate = std::max(s_fast_forward_rate, -static_cast(MAX_FAST_FORWARD_RATE)); } EndCommand(); @@ -1294,25 +1668,25 @@ void CDROM::ExecuteCommand(TickCount ticks_late) { 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; + const bool was_reading = (s_drive_state == DriveState::Reading || s_drive_state == DriveState::Playing); + const TickCount pause_time = was_reading ? (s_mode.double_speed ? 2000000 : 1000000) : 7000; - if (m_drive_state == DriveState::SeekingLogical || m_drive_state == DriveState::SeekingPhysical) + if (s_drive_state == DriveState::SeekingLogical || s_drive_state == DriveState::SeekingPhysical) { // TODO: On console, this returns an error. But perhaps only during the coarse/fine seek part? Needs more // 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_read_after_seek = false; - m_play_after_seek = false; + Log_WarningPrintf("CDROM Pause command while seeking from %u to %u - jumping to seek target", s_seek_start_lba, + s_seek_end_lba); + s_read_after_seek = false; + s_play_after_seek = false; CompleteSeek(); } else { // Stop reading. - m_drive_state = DriveState::Idle; - m_drive_event->Deactivate(); - m_secondary_status.ClearActiveBits(); + s_drive_state = DriveState::Idle; + s_drive_event->Deactivate(); + s_secondary_status.ClearActiveBits(); } // Reset audio buffer here - control room cutscene audio repeats in Dino Crisis otherwise. @@ -1326,7 +1700,7 @@ void CDROM::ExecuteCommand(TickCount ticks_late) case Command::Stop: { - const TickCount stop_time = GetTicksForStop(m_secondary_status.motor_on); + const TickCount stop_time = GetTicksForStop(IsMotorOn()); SendACKAndStat(); StopMotor(); @@ -1340,7 +1714,7 @@ void CDROM::ExecuteCommand(TickCount ticks_late) { Log_DebugPrintf("CDROM init command"); - if (m_command_second_response == Command::Init) + if (s_command_second_response == Command::Init) { // still pending EndCommand(); @@ -1362,7 +1736,7 @@ void CDROM::ExecuteCommand(TickCount ticks_late) case Command::MotorOn: { Log_DebugPrintf("CDROM motor on command"); - if (m_secondary_status.motor_on) + if (IsMotorOn()) { SendErrorResponse(STAT_ERROR, ERROR_REASON_INCORRECT_NUMBER_OF_PARAMETERS); } @@ -1371,7 +1745,7 @@ void CDROM::ExecuteCommand(TickCount ticks_late) SendACKAndStat(); // still pending? - if (m_command_second_response != Command::MotorOn) + if (s_command_second_response != Command::MotorOn) { if (CanReadMedia()) StartMotor(); @@ -1388,7 +1762,7 @@ void CDROM::ExecuteCommand(TickCount ticks_late) case Command::Mute: { Log_DebugPrintf("CDROM mute command"); - m_muted = true; + s_muted = true; SendACKAndStat(); EndCommand(); } @@ -1397,7 +1771,7 @@ void CDROM::ExecuteCommand(TickCount ticks_late) case Command::Demute: { Log_DebugPrintf("CDROM demute command"); - m_muted = false; + s_muted = false; SendACKAndStat(); EndCommand(); } @@ -1405,21 +1779,21 @@ void CDROM::ExecuteCommand(TickCount ticks_late) case Command::GetlocL: { - if (!m_last_sector_header_valid) + if (!s_last_sector_header_valid) { - Log_DevPrintf("CDROM GetlocL command - header invalid, status 0x%02X", m_secondary_status.bits); + Log_DevPrintf("CDROM GetlocL command - header invalid, status 0x%02X", s_secondary_status.bits); SendErrorResponse(STAT_ERROR, ERROR_REASON_NOT_READY); } else { UpdatePhysicalPosition(true); - Log_DebugPrintf("CDROM GetlocL command - [%02X:%02X:%02X]", m_last_sector_header.minute, - m_last_sector_header.second, m_last_sector_header.frame); + Log_DebugPrintf("CDROM GetlocL command - [%02X:%02X:%02X]", s_last_sector_header.minute, + s_last_sector_header.second, s_last_sector_header.frame); - m_response_fifo.PushRange(reinterpret_cast(&m_last_sector_header), sizeof(m_last_sector_header)); - m_response_fifo.PushRange(reinterpret_cast(&m_last_sector_subheader), - sizeof(m_last_sector_subheader)); + s_response_fifo.PushRange(reinterpret_cast(&s_last_sector_header), sizeof(s_last_sector_header)); + s_response_fifo.PushRange(reinterpret_cast(&s_last_sector_subheader), + sizeof(s_last_sector_subheader)); SetInterrupt(Interrupt::ACK); } @@ -1442,18 +1816,18 @@ void CDROM::ExecuteCommand(TickCount ticks_late) UpdatePhysicalPosition(false); Log_DevPrintf("CDROM GetlocP command - T%02x I%02x R[%02x:%02x:%02x] A[%02x:%02x:%02x]", - m_last_subq.track_number_bcd, m_last_subq.index_number_bcd, m_last_subq.relative_minute_bcd, - m_last_subq.relative_second_bcd, m_last_subq.relative_frame_bcd, m_last_subq.absolute_minute_bcd, - m_last_subq.absolute_second_bcd, m_last_subq.absolute_frame_bcd); + s_last_subq.track_number_bcd, s_last_subq.index_number_bcd, s_last_subq.relative_minute_bcd, + s_last_subq.relative_second_bcd, s_last_subq.relative_frame_bcd, s_last_subq.absolute_minute_bcd, + s_last_subq.absolute_second_bcd, s_last_subq.absolute_frame_bcd); - 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); + s_response_fifo.Push(s_last_subq.track_number_bcd); + s_response_fifo.Push(s_last_subq.index_number_bcd); + s_response_fifo.Push(s_last_subq.relative_minute_bcd); + s_response_fifo.Push(s_last_subq.relative_second_bcd); + s_response_fifo.Push(s_last_subq.relative_frame_bcd); + s_response_fifo.Push(s_last_subq.absolute_minute_bcd); + s_response_fifo.Push(s_last_subq.absolute_second_bcd); + s_response_fifo.Push(s_last_subq.absolute_frame_bcd); SetInterrupt(Interrupt::ACK); } @@ -1469,9 +1843,9 @@ void CDROM::ExecuteCommand(TickCount ticks_late) Log_DevPrintf("GetTN -> %u %u", m_reader.GetMedia()->GetFirstTrackNumber(), m_reader.GetMedia()->GetLastTrackNumber()); - m_response_fifo.Push(m_secondary_status.bits); - m_response_fifo.Push(BinaryToBCD(Truncate8(m_reader.GetMedia()->GetFirstTrackNumber()))); - m_response_fifo.Push(BinaryToBCD(Truncate8(m_reader.GetMedia()->GetLastTrackNumber()))); + s_response_fifo.Push(s_secondary_status.bits); + s_response_fifo.Push(BinaryToBCD(Truncate8(m_reader.GetMedia()->GetFirstTrackNumber()))); + s_response_fifo.Push(BinaryToBCD(Truncate8(m_reader.GetMedia()->GetLastTrackNumber()))); SetInterrupt(Interrupt::ACK); } else @@ -1486,8 +1860,8 @@ void CDROM::ExecuteCommand(TickCount ticks_late) case Command::GetTD: { Log_DebugPrintf("CDROM GetTD command"); - Assert(m_param_fifo.GetSize() >= 1); - const u8 track = PackedBCDToBinary(m_param_fifo.Peek()); + Assert(s_param_fifo.GetSize() >= 1); + const u8 track = PackedBCDToBinary(s_param_fifo.Peek()); if (!CanReadMedia()) { @@ -1505,9 +1879,9 @@ void CDROM::ExecuteCommand(TickCount ticks_late) else pos = m_reader.GetMedia()->GetTrackStartMSFPosition(track); - m_response_fifo.Push(m_secondary_status.bits); - m_response_fifo.Push(BinaryToBCD(Truncate8(pos.minute))); - m_response_fifo.Push(BinaryToBCD(Truncate8(pos.second))); + s_response_fifo.Push(s_secondary_status.bits); + s_response_fifo.Push(BinaryToBCD(Truncate8(pos.minute))); + s_response_fifo.Push(BinaryToBCD(Truncate8(pos.second))); Log_DevPrintf("GetTD %u -> %u %u", track, pos.minute, pos.second); SetInterrupt(Interrupt::ACK); @@ -1521,11 +1895,11 @@ void CDROM::ExecuteCommand(TickCount ticks_late) { Log_DebugPrintf("CDROM Getmode command"); - m_response_fifo.Push(m_secondary_status.bits); - m_response_fifo.Push(m_mode.bits); - m_response_fifo.Push(0); - m_response_fifo.Push(m_xa_filter_file_number); - m_response_fifo.Push(m_xa_filter_channel_number); + s_response_fifo.Push(s_secondary_status.bits); + s_response_fifo.Push(s_mode.bits); + s_response_fifo.Push(0); + s_response_fifo.Push(s_xa_filter_file_number); + s_response_fifo.Push(s_xa_filter_channel_number); SetInterrupt(Interrupt::ACK); EndCommand(); } @@ -1546,16 +1920,16 @@ void CDROM::ExecuteCommand(TickCount ticks_late) SendErrorResponse(STAT_ERROR, ERROR_REASON_INVALID_COMMAND); // According to nocash this doesn't clear the parameter FIFO. - m_command = Command::None; - m_command_event->Deactivate(); + s_command = Command::None; + s_command_event->Deactivate(); UpdateStatusRegister(); } break; default: { - Log_ErrorPrintf("Unknown CDROM command 0x%04X with %u parameters, please report", static_cast(m_command), - m_param_fifo.GetSize()); + Log_ErrorPrintf("Unknown CDROM command 0x%04X with %u parameters, please report", static_cast(s_command), + s_param_fifo.GetSize()); SendErrorResponse(STAT_ERROR, ERROR_REASON_INVALID_COMMAND); EndCommand(); } @@ -1570,8 +1944,8 @@ void CDROM::ExecuteTestCommand(u8 subcommand) case 0x04: // Reset SCEx counters { Log_DebugPrintf("Reset SCEx counters"); - m_secondary_status.motor_on = true; - m_response_fifo.Push(m_secondary_status.bits); + s_secondary_status.motor_on = true; + s_response_fifo.Push(s_secondary_status.bits); SetInterrupt(Interrupt::ACK); EndCommand(); return; @@ -1580,9 +1954,9 @@ void CDROM::ExecuteTestCommand(u8 subcommand) case 0x05: // Read SCEx counters { Log_DebugPrintf("Read SCEx counters"); - m_response_fifo.Push(m_secondary_status.bits); - m_response_fifo.Push(0); // # of TOC reads? - m_response_fifo.Push(0); // # of SCEx strings received + s_response_fifo.Push(s_secondary_status.bits); + s_response_fifo.Push(0); // # of TOC reads? + s_response_fifo.Push(0); // # of SCEx strings received SetInterrupt(Interrupt::ACK); EndCommand(); return; @@ -1593,7 +1967,7 @@ void CDROM::ExecuteTestCommand(u8 subcommand) Log_DebugPrintf("Get CDROM BIOS Date/Version"); static constexpr u8 response[] = {0x95, 0x05, 0x16, 0xC1}; - m_response_fifo.PushRange(response, countof(response)); + s_response_fifo.PushRange(response, countof(response)); SetInterrupt(Interrupt::ACK); EndCommand(); return; @@ -1608,14 +1982,14 @@ void CDROM::ExecuteTestCommand(u8 subcommand) case ConsoleRegion::NTSC_J: { static constexpr u8 response[] = {'f', 'o', 'r', ' ', 'J', 'a', 'p', 'a', 'n'}; - m_response_fifo.PushRange(response, countof(response)); + s_response_fifo.PushRange(response, countof(response)); } break; case ConsoleRegion::PAL: { static constexpr u8 response[] = {'f', 'o', 'r', ' ', 'E', 'u', 'r', 'o', 'p', 'e'}; - m_response_fifo.PushRange(response, countof(response)); + s_response_fifo.PushRange(response, countof(response)); } break; @@ -1623,7 +1997,7 @@ void CDROM::ExecuteTestCommand(u8 subcommand) default: { static constexpr u8 response[] = {'f', 'o', 'r', ' ', 'U', '/', 'C'}; - m_response_fifo.PushRange(response, countof(response)); + s_response_fifo.PushRange(response, countof(response)); } break; } @@ -1635,7 +2009,7 @@ void CDROM::ExecuteTestCommand(u8 subcommand) default: { - Log_ErrorPrintf("Unknown test command 0x%02X, %u parameters", subcommand, m_param_fifo.GetSize()); + Log_ErrorPrintf("Unknown test command 0x%02X, %u parameters", subcommand, s_param_fifo.GetSize()); SendErrorResponse(STAT_ERROR, ERROR_REASON_INVALID_COMMAND); EndCommand(); return; @@ -1643,9 +2017,9 @@ void CDROM::ExecuteTestCommand(u8 subcommand) } } -void CDROM::ExecuteCommandSecondResponse(TickCount ticks_late) +void CDROM::ExecuteCommandSecondResponse(void*, TickCount ticks, TickCount ticks_late) { - switch (m_command_second_response) + switch (s_command_second_response) { case Command::GetID: DoIDRead(); @@ -1660,21 +2034,21 @@ void CDROM::ExecuteCommandSecondResponse(TickCount ticks_late) break; } - m_command_second_response = Command::None; - m_command_second_response_event->Deactivate(); + s_command_second_response = Command::None; + s_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); + s_command_second_response = command; + s_command_second_response_event->Schedule(ticks); } void CDROM::ClearCommandSecondResponse() { - m_command_second_response_event->Deactivate(); - m_command_second_response = Command::None; + s_command_second_response_event->Deactivate(); + s_command_second_response = Command::None; } void CDROM::UpdateCommandEvent() @@ -1683,18 +2057,18 @@ void CDROM::UpdateCommandEvent() // so deactivate it until the interrupt is acknowledged if (!HasPendingCommand() || HasPendingInterrupt()) { - m_command_event->Deactivate(); + s_command_event->Deactivate(); return; } else if (HasPendingCommand()) { - m_command_event->Activate(); + s_command_event->Activate(); } } -void CDROM::ExecuteDrive(TickCount ticks_late) +void CDROM::ExecuteDrive(void*, TickCount ticks, TickCount ticks_late) { - switch (m_drive_state) + switch (s_drive_state) { case DriveState::ShellOpening: DoShellOpenComplete(ticks_late); @@ -1745,7 +2119,7 @@ void CDROM::ExecuteDrive(TickCount ticks_late) case DriveState::UNUSED_Pausing: { ClearDriveState(); - m_secondary_status.ClearActiveBits(); + s_secondary_status.ClearActiveBits(); DoStatSecondResponse(); } break; @@ -1766,15 +2140,15 @@ void CDROM::ExecuteDrive(TickCount ticks_late) void CDROM::ClearDriveState() { - m_drive_state = DriveState::Idle; - m_drive_event->Deactivate(); + s_drive_state = DriveState::Idle; + s_drive_event->Deactivate(); } void CDROM::BeginReading(TickCount ticks_late /* = 0 */, bool after_seek /* = false */) { ClearSectorBuffers(); - if (!after_seek && m_setloc_pending) + if (!after_seek && s_setloc_pending) { BeginSeeking(true, true, false); return; @@ -1785,40 +2159,40 @@ void CDROM::BeginReading(TickCount ticks_late /* = 0 */, bool after_seek /* = fa if (IsSeeking()) { Log_DevPrintf("Read command while seeking, scheduling read after seek %u -> %u finishes in %d ticks", - m_seek_start_lba, m_seek_end_lba, m_drive_event->GetTicksUntilNextExecution()); + s_seek_start_lba, s_seek_end_lba, s_drive_event->GetTicksUntilNextExecution()); // Implicit seeks won't trigger the read, so swap it for a logical. - if (m_drive_state == DriveState::SeekingImplicit) - m_drive_state = DriveState::SeekingLogical; + if (s_drive_state == DriveState::SeekingImplicit) + s_drive_state = DriveState::SeekingLogical; - m_read_after_seek = true; - m_play_after_seek = false; + s_read_after_seek = true; + s_play_after_seek = false; return; } - Log_DebugPrintf("Starting reading @ LBA %u", m_current_lba); + Log_DebugPrintf("Starting reading @ LBA %u", s_current_lba); const TickCount ticks = GetTicksForRead(); - const TickCount first_sector_ticks = ticks + (after_seek ? 0 : GetTicksForSeek(m_current_lba)) - ticks_late; + const TickCount first_sector_ticks = ticks + (after_seek ? 0 : GetTicksForSeek(s_current_lba)) - ticks_late; ResetAudioDecoder(); - m_drive_state = DriveState::Reading; - m_drive_event->SetInterval(ticks); - m_drive_event->Schedule(first_sector_ticks); - m_current_read_sector_buffer = 0; - m_current_write_sector_buffer = 0; + s_drive_state = DriveState::Reading; + s_drive_event->SetInterval(ticks); + s_drive_event->Schedule(first_sector_ticks); + s_current_read_sector_buffer = 0; + s_current_write_sector_buffer = 0; - m_requested_lba = m_current_lba; - m_reader.QueueReadSector(m_requested_lba); + s_requested_lba = s_current_lba; + m_reader.QueueReadSector(s_requested_lba); } void CDROM::BeginPlaying(u8 track, TickCount ticks_late /* = 0 */, bool after_seek /* = false */) { Log_DebugPrintf("Starting playing CDDA track %x", track); - m_last_cdda_report_frame_nibble = 0xFF; - m_play_track_number_bcd = track; - m_fast_forward_rate = 0; + s_last_cdda_report_frame_nibble = 0xFF; + s_play_track_number_bcd = track; + s_fast_forward_rate = 0; // if track zero, start from current position if (track != 0) @@ -1830,83 +2204,83 @@ void CDROM::BeginPlaying(u8 track, TickCount ticks_late /* = 0 */, bool after_se track = Truncate8(m_reader.GetMedia()->GetTrackNumber()); } - m_setloc_position = m_reader.GetMedia()->GetTrackStartMSFPosition(track); - m_setloc_pending = true; + s_setloc_position = m_reader.GetMedia()->GetTrackStartMSFPosition(track); + s_setloc_pending = true; } - if (m_setloc_pending) + if (s_setloc_pending) { BeginSeeking(false, false, true); return; } const TickCount ticks = GetTicksForRead(); - const TickCount first_sector_ticks = ticks + (after_seek ? 0 : GetTicksForSeek(m_current_lba, true)) - ticks_late; + const TickCount first_sector_ticks = ticks + (after_seek ? 0 : GetTicksForSeek(s_current_lba, true)) - ticks_late; ClearSectorBuffers(); ResetAudioDecoder(); - m_drive_state = DriveState::Playing; - m_drive_event->SetInterval(ticks); - m_drive_event->Schedule(first_sector_ticks); - m_current_read_sector_buffer = 0; - m_current_write_sector_buffer = 0; + s_drive_state = DriveState::Playing; + s_drive_event->SetInterval(ticks); + s_drive_event->Schedule(first_sector_ticks); + s_current_read_sector_buffer = 0; + s_current_write_sector_buffer = 0; - m_requested_lba = m_current_lba; - m_reader.QueueReadSector(m_requested_lba); + s_requested_lba = s_current_lba; + m_reader.QueueReadSector(s_requested_lba); } void CDROM::BeginSeeking(bool logical, bool read_after_seek, bool play_after_seek) { - if (!m_setloc_pending) + if (!s_setloc_pending) Log_WarningPrintf("Seeking without setloc set"); - m_read_after_seek = read_after_seek; - m_play_after_seek = play_after_seek; + s_read_after_seek = read_after_seek; + s_play_after_seek = play_after_seek; // TODO: Pending should stay set on seek command. - m_setloc_pending = false; + s_setloc_pending = false; - 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"); + Log_DebugPrintf("Seeking to [%02u:%02u:%02u] (LBA %u) (%s)", s_setloc_position.minute, s_setloc_position.second, + s_setloc_position.frame, s_setloc_position.ToLBA(), logical ? "logical" : "physical"); - const CDImage::LBA seek_lba = m_setloc_position.ToLBA(); + const CDImage::LBA seek_lba = s_setloc_position.ToLBA(); const TickCount seek_time = GetTicksForSeek(seek_lba, play_after_seek); - m_secondary_status.SetSeeking(); - m_last_sector_header_valid = false; + s_secondary_status.SetSeeking(); + s_last_sector_header_valid = false; ResetAudioDecoder(); - m_drive_state = logical ? DriveState::SeekingLogical : DriveState::SeekingPhysical; - m_drive_event->SetIntervalAndSchedule(seek_time); + s_drive_state = logical ? DriveState::SeekingLogical : DriveState::SeekingPhysical; + s_drive_event->SetIntervalAndSchedule(seek_time); - m_seek_start_lba = m_current_lba; - m_seek_end_lba = seek_lba; - m_requested_lba = seek_lba; - m_reader.QueueReadSector(m_requested_lba); + s_seek_start_lba = s_current_lba; + s_seek_end_lba = seek_lba; + s_requested_lba = seek_lba; + m_reader.QueueReadSector(s_requested_lba); } void CDROM::UpdatePositionWhileSeeking() { DebugAssert(IsSeeking()); - const float completed_frac = 1.0f - (static_cast(m_drive_event->GetTicksUntilNextExecution()) / - static_cast(m_drive_event->GetInterval())); + const float completed_frac = 1.0f - (static_cast(s_drive_event->GetTicksUntilNextExecution()) / + static_cast(s_drive_event->GetInterval())); CDImage::LBA current_lba; - if (m_seek_end_lba > m_seek_start_lba) + if (s_seek_end_lba > s_seek_start_lba) { current_lba = - m_seek_start_lba + + s_seek_start_lba + std::max( - static_cast(static_cast(m_seek_end_lba - m_seek_start_lba) * completed_frac), 1); + static_cast(static_cast(s_seek_end_lba - s_seek_start_lba) * completed_frac), 1); } - else if (m_seek_end_lba < m_seek_start_lba) + else if (s_seek_end_lba < s_seek_start_lba) { current_lba = - m_seek_start_lba - + s_seek_start_lba - std::max( - static_cast(static_cast(m_seek_start_lba - m_seek_end_lba) * completed_frac), 1); + static_cast(static_cast(s_seek_start_lba - s_seek_end_lba) * completed_frac), 1); } else { @@ -1914,7 +2288,7 @@ void CDROM::UpdatePositionWhileSeeking() return; } - Log_DevPrintf("Update position while seeking from %u to %u - %u (%.2f)", m_seek_start_lba, m_seek_end_lba, + Log_DevPrintf("Update position while seeking from %u to %u - %u (%.2f)", s_seek_start_lba, s_seek_end_lba, current_lba, completed_frac); // access the image directly since we want to preserve the cached data for the seek complete @@ -1922,28 +2296,28 @@ void CDROM::UpdatePositionWhileSeeking() 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; + s_last_subq = subq; - m_current_lba = current_lba; - m_physical_lba = current_lba; - m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter(); - m_physical_lba_update_carry = 0; + s_current_lba = current_lba; + s_physical_lba = current_lba; + s_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter(); + s_physical_lba_update_carry = 0; } void CDROM::UpdatePhysicalPosition(bool update_logical) { const u32 ticks = TimingEvents::GetGlobalTickCounter(); - if (IsSeeking() || IsReadingOrPlaying() || !m_secondary_status.motor_on) + if (IsSeeking() || IsReadingOrPlaying() || !IsMotorOn()) { // If we're seeking+reading the first sector (no stat bits set), we need to return the set/current lba, not the last // physical LBA. Failing to do so may result in a track-jumped position getting returned in GetlocP, which causes // Mad Panic Coaster to go into a seek+play loop. - if ((m_secondary_status.bits & (STAT_READING | STAT_PLAYING_CDDA | STAT_MOTOR_ON)) == STAT_MOTOR_ON && - m_current_lba != m_physical_lba) + if ((s_secondary_status.bits & (STAT_READING | STAT_PLAYING_CDDA | STAT_MOTOR_ON)) == STAT_MOTOR_ON && + s_current_lba != s_physical_lba) { - Log_WarningPrintf("Jumping to hold position [%u->%u] while %s first sector", m_physical_lba, m_current_lba, - (m_drive_state == DriveState::Reading) ? "reading" : "playing"); - SetHoldPosition(m_current_lba, true); + Log_WarningPrintf("Jumping to hold position [%u->%u] while %s first sector", s_physical_lba, s_current_lba, + (s_drive_state == DriveState::Reading) ? "reading" : "playing"); + SetHoldPosition(s_current_lba, true); } // Otherwise, this gets updated by the read event. @@ -1951,7 +2325,7 @@ void CDROM::UpdatePhysicalPosition(bool update_logical) } const u32 ticks_per_read = GetTicksForRead(); - const u32 diff = ticks - m_physical_lba_update_tick + m_physical_lba_update_carry; + const u32 diff = ticks - s_physical_lba_update_tick + s_physical_lba_update_carry; const u32 sector_diff = diff / ticks_per_read; const u32 carry = diff % ticks_per_read; if (sector_diff > 0) @@ -1960,7 +2334,7 @@ void CDROM::UpdatePhysicalPosition(bool update_logical) 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) + if (s_last_sector_header_valid) { hold_offset = 2; sectors_per_track = 4; @@ -1969,27 +2343,27 @@ void CDROM::UpdatePhysicalPosition(bool update_logical) { hold_offset = 0; sectors_per_track = - static_cast(7.0f + 2.811844405f * std::log(static_cast(m_current_lba / 4500u) + 1u)); + static_cast(7.0f + 2.811844405f * std::log(static_cast(s_current_lba / 4500u) + 1u)); } - const CDImage::LBA hold_position = m_current_lba + hold_offset; + const CDImage::LBA hold_position = s_current_lba + hold_offset; const CDImage::LBA base = (hold_position >= (sectors_per_track - 1)) ? (hold_position - (sectors_per_track - 1)) : hold_position; - if (m_physical_lba < base) - m_physical_lba = base; + if (s_physical_lba < base) + s_physical_lba = base; - const CDImage::LBA old_offset = m_physical_lba - base; + const CDImage::LBA old_offset = s_physical_lba - base; const CDImage::LBA new_offset = (old_offset + sector_diff) % sectors_per_track; const CDImage::LBA new_physical_lba = base + new_offset; #ifdef _DEBUG - const CDImage::Position old_pos(CDImage::Position::FromLBA(m_physical_lba)); + const CDImage::Position old_pos(CDImage::Position::FromLBA(s_physical_lba)); const CDImage::Position new_pos(CDImage::Position::FromLBA(new_physical_lba)); Log_DevPrintf("Tick diff %u, sector diff %u, old pos %02u:%02u:%02u, new pos %02u:%02u:%02u", diff, sector_diff, old_pos.minute, old_pos.second, old_pos.frame, new_pos.minute, new_pos.second, new_pos.frame); #endif - if (m_physical_lba != new_physical_lba) + if (s_physical_lba != new_physical_lba) { - m_physical_lba = new_physical_lba; + s_physical_lba = new_physical_lba; CDImage::SubChannelQ subq; CDROMAsyncReader::SectorBuffer raw_sector; @@ -2000,33 +2374,33 @@ void CDROM::UpdatePhysicalPosition(bool update_logical) else { if (subq.IsCRCValid()) - m_last_subq = subq; + s_last_subq = subq; if (update_logical) ProcessDataSectorHeader(raw_sector.data()); } - m_physical_lba_update_tick = ticks; - m_physical_lba_update_carry = carry; + s_physical_lba_update_tick = ticks; + s_physical_lba_update_carry = carry; } } } void CDROM::SetHoldPosition(CDImage::LBA lba, bool update_subq) { - if (update_subq && m_physical_lba != lba && CanReadMedia()) + if (update_subq && s_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; + s_last_subq = subq; } - m_current_lba = lba; - m_physical_lba = lba; - m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter(); - m_physical_lba_update_carry = 0; + s_current_lba = lba; + s_physical_lba = lba; + s_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter(); + s_physical_lba_update_carry = 0; } void CDROM::DoShellOpenComplete(TickCount ticks_late) @@ -2040,7 +2414,7 @@ void CDROM::DoShellOpenComplete(TickCount ticks_late) bool CDROM::CompleteSeek() { - const bool logical = (m_drive_state == DriveState::SeekingLogical); + const bool logical = (s_drive_state == DriveState::SeekingLogical); ClearDriveState(); bool seek_okay = m_reader.WaitForReadToComplete(); @@ -2050,7 +2424,7 @@ bool CDROM::CompleteSeek() if (subq.IsCRCValid()) { // seek and update sub-q for ReadP command - m_last_subq = subq; + s_last_subq = subq; const auto [seek_mm, seek_ss, seek_ff] = CDImage::Position::FromLBA(m_reader.GetLastReadSector()).ToBCD(); seek_okay = (subq.IsCRCValid() && subq.absolute_minute_bcd == seek_mm && subq.absolute_second_bcd == seek_ss && subq.absolute_frame_bcd == seek_ff); @@ -2061,8 +2435,8 @@ bool CDROM::CompleteSeek() if (logical) { 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); + seek_okay = (s_last_sector_header.minute == seek_mm && s_last_sector_header.second == seek_ss && + s_last_sector_header.frame == seek_ff); } } else @@ -2070,14 +2444,14 @@ bool CDROM::CompleteSeek() if (logical) { Log_WarningPrintf("Logical seek to non-data sector [%02x:%02x:%02x]%s", seek_mm, seek_ss, seek_ff, - m_read_after_seek ? ", reading after seek" : ""); + s_read_after_seek ? ", reading after seek" : ""); // If CDDA mode isn't enabled and we're reading an audio sector, we need to fail the seek. // Test cases: // - Wizard's Harmony does a logical seek to an audio sector, and expects it to succeed. // - Vib-ribbon starts a read at an audio sector, and expects it to fail. - if (m_read_after_seek) - seek_okay = m_mode.cdda; + if (s_read_after_seek) + seek_okay = s_mode.cdda; } } @@ -2089,35 +2463,35 @@ bool CDROM::CompleteSeek() } } - m_current_lba = m_reader.GetLastReadSector(); + s_current_lba = m_reader.GetLastReadSector(); } - m_physical_lba = m_current_lba; - m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter(); - m_physical_lba_update_carry = 0; + s_physical_lba = s_current_lba; + s_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter(); + s_physical_lba_update_carry = 0; return seek_okay; } void CDROM::DoSeekComplete(TickCount ticks_late) { - const bool logical = (m_drive_state == DriveState::SeekingLogical); + const bool logical = (s_drive_state == DriveState::SeekingLogical); const bool seek_okay = CompleteSeek(); if (seek_okay) { // seek complete, transition to play/read if requested // INT2 is not sent on play/read - if (m_read_after_seek) + if (s_read_after_seek) { BeginReading(ticks_late, true); } - else if (m_play_after_seek) + else if (s_play_after_seek) { BeginPlaying(0, ticks_late, true); } else { - m_secondary_status.ClearActiveBits(); - m_async_response_fifo.Push(m_secondary_status.bits); + s_secondary_status.ClearActiveBits(); + s_async_response_fifo.Push(s_secondary_status.bits); SetAsyncInterrupt(Interrupt::Complete); } } @@ -2127,14 +2501,14 @@ void CDROM::DoSeekComplete(TickCount ticks_late) Log_WarningPrintf("%s seek to [%02u:%02u:%02u] failed", logical ? "Logical" : "Physical", pos.minute, pos.second, pos.frame); - m_secondary_status.ClearActiveBits(); + s_secondary_status.ClearActiveBits(); SendAsyncErrorResponse(STAT_SEEK_ERROR, 0x04); - m_last_sector_header_valid = false; + s_last_sector_header_valid = false; } - m_setloc_pending = false; - m_read_after_seek = false; - m_play_after_seek = false; + s_setloc_pending = false; + s_read_after_seek = false; + s_play_after_seek = false; UpdateStatusRegister(); } @@ -2147,8 +2521,8 @@ void CDROM::DoStatSecondResponse() return; } - m_async_response_fifo.Clear(); - m_async_response_fifo.Push(m_secondary_status.bits); + s_async_response_fifo.Clear(); + s_async_response_fifo.Push(s_secondary_status.bits); SetAsyncInterrupt(Interrupt::Complete); } @@ -2156,13 +2530,13 @@ void CDROM::DoChangeSessionComplete() { Log_DebugPrintf("Changing session complete"); ClearDriveState(); - m_secondary_status.ClearActiveBits(); - m_secondary_status.motor_on = true; + s_secondary_status.ClearActiveBits(); + s_secondary_status.motor_on = true; - m_async_response_fifo.Clear(); - if (m_async_command_parameter == 0x01) + s_async_response_fifo.Clear(); + if (s_async_command_parameter == 0x01) { - m_async_response_fifo.Push(m_secondary_status.bits); + s_async_response_fifo.Push(s_secondary_status.bits); SetAsyncInterrupt(Interrupt::Complete); } else @@ -2175,27 +2549,27 @@ void CDROM::DoChangeSessionComplete() void CDROM::DoSpinUpComplete() { Log_DebugPrintf("Spinup complete"); - m_drive_state = DriveState::Idle; - m_drive_event->Deactivate(); - m_secondary_status.ClearActiveBits(); - m_secondary_status.motor_on = true; + s_drive_state = DriveState::Idle; + s_drive_event->Deactivate(); + s_secondary_status.ClearActiveBits(); + s_secondary_status.motor_on = true; } void CDROM::DoSpeedChangeOrImplicitTOCReadComplete() { Log_DebugPrintf("Speed change/implicit TOC read complete"); - m_drive_state = DriveState::Idle; - m_drive_event->Deactivate(); + s_drive_state = DriveState::Idle; + s_drive_event->Deactivate(); } void CDROM::DoIDRead() { Log_DebugPrintf("ID read complete"); - m_secondary_status.ClearActiveBits(); - m_secondary_status.motor_on = CanReadMedia(); + s_secondary_status.ClearActiveBits(); + s_secondary_status.motor_on = CanReadMedia(); // TODO: Audio CD. - u8 stat_byte = m_secondary_status.bits; + u8 stat_byte = s_secondary_status.bits; u8 flags_byte = 0; if (!CanReadMedia()) { @@ -2216,16 +2590,16 @@ void CDROM::DoIDRead() } } - m_async_response_fifo.Clear(); - m_async_response_fifo.Push(stat_byte); - m_async_response_fifo.Push(flags_byte); - m_async_response_fifo.Push(0x20); // TODO: Disc type from TOC - m_async_response_fifo.Push(0x00); // TODO: Session info? + s_async_response_fifo.Clear(); + s_async_response_fifo.Push(stat_byte); + s_async_response_fifo.Push(flags_byte); + s_async_response_fifo.Push(0x20); // TODO: Disc type from TOC + s_async_response_fifo.Push(0x00); // TODO: Session info? static constexpr u32 REGION_STRING_LENGTH = 4; static constexpr std::array, static_cast(DiscRegion::Count)> region_strings = {{{'S', 'C', 'E', 'I'}, {'S', 'C', 'E', 'A'}, {'S', 'C', 'E', 'E'}, {0, 0, 0, 0}}}; - m_async_response_fifo.PushRange(region_strings[static_cast(m_disc_region)].data(), REGION_STRING_LENGTH); + s_async_response_fifo.PushRange(region_strings[static_cast(s_disc_region)].data(), REGION_STRING_LENGTH); SetAsyncInterrupt((flags_byte != 0) ? Interrupt::Error : Interrupt::Complete); } @@ -2233,33 +2607,33 @@ void CDROM::DoIDRead() void CDROM::StopReadingWithDataEnd() { ClearAsyncInterrupt(); - m_async_response_fifo.Push(m_secondary_status.bits); + s_async_response_fifo.Push(s_secondary_status.bits); SetAsyncInterrupt(Interrupt::DataEnd); - m_secondary_status.ClearActiveBits(); + s_secondary_status.ClearActiveBits(); ClearDriveState(); } void CDROM::StartMotor() { - if (m_drive_state == DriveState::SpinningUp) + if (s_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()); + s_drive_state = DriveState::SpinningUp; + s_drive_event->Schedule(GetTicksForSpinUp()); } void CDROM::StopMotor() { - m_secondary_status.ClearActiveBits(); - m_secondary_status.motor_on = false; + s_secondary_status.ClearActiveBits(); + s_secondary_status.motor_on = false; ClearDriveState(); SetHoldPosition(0, false); - m_last_sector_header_valid = false; // TODO: correct? + s_last_sector_header_valid = false; // TODO: correct? } void CDROM::DoSectorRead() @@ -2269,23 +2643,23 @@ void CDROM::DoSectorRead() if (!m_reader.WaitForReadToComplete()) Panic("Sector read failed"); - m_current_lba = m_reader.GetLastReadSector(); - m_physical_lba = m_current_lba; - m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter(); - m_physical_lba_update_carry = 0; + s_current_lba = m_reader.GetLastReadSector(); + s_physical_lba = s_current_lba; + s_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter(); + s_physical_lba_update_carry = 0; - m_secondary_status.SetReadingBits(m_drive_state == DriveState::Playing); + s_secondary_status.SetReadingBits(s_drive_state == DriveState::Playing); const CDImage::SubChannelQ& subq = m_reader.GetSectorSubQ(); const bool subq_valid = subq.IsCRCValid(); if (subq_valid) { - m_last_subq = subq; + s_last_subq = subq; } else { - const CDImage::Position pos(CDImage::Position::FromLBA(m_current_lba)); - Log_DevPrintf("Sector %u [%02u:%02u:%02u] has invalid subchannel Q", m_current_lba, pos.minute, pos.second, + const CDImage::Position pos(CDImage::Position::FromLBA(s_current_lba)); + Log_DevPrintf("Sector %u [%02u:%02u:%02u] has invalid subchannel Q", s_current_lba, pos.minute, pos.second, pos.frame); } @@ -2300,16 +2674,16 @@ void CDROM::DoSectorRead() const bool is_data_sector = subq.IsData(); if (!is_data_sector) { - if (m_play_track_number_bcd == 0) + if (s_play_track_number_bcd == 0) { // track number was not specified, but we've found the track now - m_play_track_number_bcd = subq.track_number_bcd; - Log_DebugPrintf("Setting playing track number to %u", m_play_track_number_bcd); + s_play_track_number_bcd = subq.track_number_bcd; + Log_DebugPrintf("Setting playing track number to %u", s_play_track_number_bcd); } - else if (m_mode.auto_pause && subq.track_number_bcd != m_play_track_number_bcd) + else if (s_mode.auto_pause && subq.track_number_bcd != s_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 start 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)", s_last_subq.track_number_bcd, s_current_lba); StopReadingWithDataEnd(); return; } @@ -2319,51 +2693,51 @@ void CDROM::DoSectorRead() ProcessDataSectorHeader(m_reader.GetSectorBuffer().data()); } - u32 next_sector = m_current_lba + 1u; - if (is_data_sector && m_drive_state == DriveState::Reading) + u32 next_sector = s_current_lba + 1u; + if (is_data_sector && s_drive_state == DriveState::Reading) { ProcessDataSector(m_reader.GetSectorBuffer().data(), subq); } else if (!is_data_sector && - (m_drive_state == DriveState::Playing || (m_drive_state == DriveState::Reading && m_mode.cdda))) + (s_drive_state == DriveState::Playing || (s_drive_state == DriveState::Reading && s_mode.cdda))) { ProcessCDDASector(m_reader.GetSectorBuffer().data(), subq); - if (m_fast_forward_rate != 0) - next_sector = m_current_lba + SignExtend32(m_fast_forward_rate); + if (s_fast_forward_rate != 0) + next_sector = s_current_lba + SignExtend32(s_fast_forward_rate); } - else if (m_drive_state != DriveState::Reading && m_drive_state != DriveState::Playing) + else if (s_drive_state != DriveState::Reading && s_drive_state != DriveState::Playing) { Panic("Not reading or playing"); } else { - Log_WarningPrintf("Skipping sector %u as it is a %s sector and we're not %s", m_current_lba, + Log_WarningPrintf("Skipping sector %u as it is a %s sector and we're not %s", s_current_lba, is_data_sector ? "data" : "audio", is_data_sector ? "reading" : "playing"); } - m_requested_lba = next_sector; - m_reader.QueueReadSector(m_requested_lba); + s_requested_lba = next_sector; + m_reader.QueueReadSector(s_requested_lba); } 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_last_sector_header_valid = true; + std::memcpy(&s_last_sector_header, &raw_sector[SECTOR_SYNC_SIZE], sizeof(s_last_sector_header)); + std::memcpy(&s_last_sector_subheader, &raw_sector[SECTOR_SYNC_SIZE + sizeof(s_last_sector_header)], + sizeof(s_last_sector_subheader)); + s_last_sector_header_valid = true; } void CDROM::ProcessDataSector(const u8* raw_sector, const CDImage::SubChannelQ& subq) { - const u32 sb_num = (m_current_write_sector_buffer + 1) % NUM_SECTOR_BUFFERS; - Log_DevPrintf("Read sector %u: mode %u submode 0x%02X into buffer %u", m_current_lba, - ZeroExtend32(m_last_sector_header.sector_mode), ZeroExtend32(m_last_sector_subheader.submode.bits), + const u32 sb_num = (s_current_write_sector_buffer + 1) % NUM_SECTOR_BUFFERS; + Log_DevPrintf("Read sector %u: mode %u submode 0x%02X into buffer %u", s_current_lba, + ZeroExtend32(s_last_sector_header.sector_mode), ZeroExtend32(s_last_sector_subheader.submode.bits), sb_num); - if (m_mode.xa_enable && m_last_sector_header.sector_mode == 2) + if (s_mode.xa_enable && s_last_sector_header.sector_mode == 2) { - if (m_last_sector_subheader.submode.realtime && m_last_sector_subheader.submode.audio) + if (s_last_sector_subheader.submode.realtime && s_last_sector_subheader.submode.audio) { ProcessXAADPCMSector(raw_sector, subq); @@ -2373,17 +2747,17 @@ void CDROM::ProcessDataSector(const u8* raw_sector, const CDImage::SubChannelQ& } // TODO: How does XA relate to this buffering? - SectorBuffer* sb = &m_sector_buffers[sb_num]; + SectorBuffer* sb = &s_sector_buffers[sb_num]; if (sb->size > 0) { Log_DevPrintf("Sector buffer %u was not read, previous sector dropped", - (m_current_write_sector_buffer - 1) % NUM_SECTOR_BUFFERS); + (s_current_write_sector_buffer - 1) % NUM_SECTOR_BUFFERS); } - if (m_mode.ignore_bit) - Log_WarningPrintf("SetMode.4 bit set on read of sector %u", m_current_lba); + if (s_mode.ignore_bit) + Log_WarningPrintf("SetMode.4 bit set on read of sector %u", s_current_lba); - if (m_mode.read_raw_sector) + if (s_mode.read_raw_sector) { std::memcpy(sb->data.data(), raw_sector + SECTOR_SYNC_SIZE, RAW_SECTOR_OUTPUT_SIZE); sb->size = RAW_SECTOR_OUTPUT_SIZE; @@ -2391,9 +2765,9 @@ void CDROM::ProcessDataSector(const u8* raw_sector, const CDImage::SubChannelQ& else { // TODO: This should actually depend on the mode... - if (m_last_sector_header.sector_mode != 2) + if (s_last_sector_header.sector_mode != 2) { - Log_WarningPrintf("Ignoring non-mode2 sector at %u", m_current_lba); + Log_WarningPrintf("Ignoring non-mode2 sector at %u", s_current_lba); return; } @@ -2401,7 +2775,7 @@ void CDROM::ProcessDataSector(const u8* raw_sector, const CDImage::SubChannelQ& sb->size = DATA_SECTOR_OUTPUT_SIZE; } - m_current_write_sector_buffer = sb_num; + s_current_write_sector_buffer = sb_num; // Deliver to CPU if (HasPendingAsyncInterrupt()) @@ -2412,12 +2786,12 @@ void CDROM::ProcessDataSector(const u8* raw_sector, const CDImage::SubChannelQ& if (HasPendingInterrupt()) { - const u32 sectors_missed = (m_current_write_sector_buffer - m_current_read_sector_buffer) % NUM_SECTOR_BUFFERS; + const u32 sectors_missed = (s_current_write_sector_buffer - s_current_read_sector_buffer) % NUM_SECTOR_BUFFERS; if (sectors_missed > 1) Log_WarningPrintf("Interrupt not processed in time, missed %u sectors", sectors_missed - 1); } - m_async_response_fifo.Push(m_secondary_status.bits); + s_async_response_fifo.Push(s_secondary_status.bits); SetAsyncInterrupt(Interrupt::DataReady); } @@ -2453,22 +2827,49 @@ static s16 ZigZagInterpolate(const s16* ringbuf, const s16* table, u8 p) return static_cast(std::clamp(sum, -0x8000, 0x7FFF)); } +std::tuple CDROM::GetAudioFrame() +{ + const u32 frame = s_audio_fifo.IsEmpty() ? 0u : s_audio_fifo.Pop(); + const s16 left = static_cast(Truncate16(frame)); + const s16 right = static_cast(Truncate16(frame >> 16)); + const s16 left_out = SaturateVolume(ApplyVolume(left, s_cd_audio_volume_matrix[0][0]) + + ApplyVolume(right, s_cd_audio_volume_matrix[1][0])); + const s16 right_out = SaturateVolume(ApplyVolume(left, s_cd_audio_volume_matrix[0][1]) + + ApplyVolume(right, s_cd_audio_volume_matrix[1][1])); + return std::tuple(left_out, right_out); +} + +void CDROM::AddCDAudioFrame(s16 left, s16 right) +{ + s_audio_fifo.Push(ZeroExtend32(static_cast(left)) | (ZeroExtend32(static_cast(right)) << 16)); +} + +s32 CDROM::ApplyVolume(s16 sample, u8 volume) +{ + return s32(sample) * static_cast(ZeroExtend32(volume)) >> 7; +} + +s16 CDROM::SaturateVolume(s32 volume) +{ + return static_cast((volume < -0x8000) ? -0x8000 : ((volume > 0x7FFF) ? 0x7FFF : volume)); +} + template void CDROM::ResampleXAADPCM(const s16* frames_in, u32 num_frames_in) { // Since the disc reads and SPU are running at different speeds, we might be _slightly_ behind, which is fine, since // the SPU will over-read in the next batch to catch up. - if (m_audio_fifo.GetSize() > AUDIO_FIFO_LOW_WATERMARK) + if (s_audio_fifo.GetSize() > AUDIO_FIFO_LOW_WATERMARK) { Log_DevPrintf("Dropping %u XA frames because audio FIFO still has %u frames", num_frames_in, - m_audio_fifo.GetSize()); + s_audio_fifo.GetSize()); return; } - s16* left_ringbuf = m_xa_resample_ring_buffer[0].data(); - s16* right_ringbuf = m_xa_resample_ring_buffer[1].data(); - u8 p = m_xa_resample_p; - u8 sixstep = m_xa_resample_sixstep; + s16* left_ringbuf = s_xa_resample_ring_buffer[0].data(); + s16* right_ringbuf = s_xa_resample_ring_buffer[1].data(); + u8 p = s_xa_resample_p; + u8 sixstep = s_xa_resample_sixstep; for (u32 in_sample_index = 0; in_sample_index < num_frames_in; in_sample_index++) { const s16 left = *(frames_in++); @@ -2500,96 +2901,96 @@ void CDROM::ResampleXAADPCM(const s16* frames_in, u32 num_frames_in) } } - m_xa_resample_p = p; - m_xa_resample_sixstep = sixstep; + s_xa_resample_p = p; + s_xa_resample_sixstep = sixstep; } void CDROM::ResetCurrentXAFile() { - m_xa_current_channel_number = 0; - m_xa_current_file_number = 0; - m_xa_current_set = false; + s_xa_current_channel_number = 0; + s_xa_current_file_number = 0; + s_xa_current_set = false; } void CDROM::ResetAudioDecoder() { ResetCurrentXAFile(); - m_xa_last_samples.fill(0); + s_xa_last_samples.fill(0); for (u32 i = 0; i < 2; i++) { - m_xa_resample_ring_buffer[i].fill(0); - m_xa_resample_p = 0; - m_xa_resample_sixstep = 6; + s_xa_resample_ring_buffer[i].fill(0); + s_xa_resample_p = 0; + s_xa_resample_sixstep = 6; } - m_audio_fifo.Clear(); + s_audio_fifo.Clear(); } void CDROM::ProcessXAADPCMSector(const u8* raw_sector, const CDImage::SubChannelQ& subq) { // Check for automatic ADPCM filter. - if (m_mode.xa_filter && (m_last_sector_subheader.file_number != m_xa_filter_file_number || - m_last_sector_subheader.channel_number != m_xa_filter_channel_number)) + if (s_mode.xa_filter && (s_last_sector_subheader.file_number != s_xa_filter_file_number || + s_last_sector_subheader.channel_number != s_xa_filter_channel_number)) { - Log_DebugPrintf("Skipping sector due to filter mismatch (expected %u/%u got %u/%u)", m_xa_filter_file_number, - m_xa_filter_channel_number, m_last_sector_subheader.file_number, - m_last_sector_subheader.channel_number); + Log_DebugPrintf("Skipping sector due to filter mismatch (expected %u/%u got %u/%u)", s_xa_filter_file_number, + s_xa_filter_channel_number, s_last_sector_subheader.file_number, + s_last_sector_subheader.channel_number); return; } // Track the current file being played. If this is not set by the filter, it'll be set by the first file/sector which // is read. Fixes audio in Tomb Raider III menu. - if (!m_xa_current_set) + if (!s_xa_current_set) { // Some games (Taxi 2 and Blues Blues) have junk audio sectors with a channel number of 255. // We need to skip them otherwise it ends up playing the incorrect file. // TODO: Verify with a hardware test. - if (m_last_sector_subheader.channel_number == 255 && (!m_mode.xa_filter || m_xa_filter_channel_number != 255)) + if (s_last_sector_subheader.channel_number == 255 && (!s_mode.xa_filter || s_xa_filter_channel_number != 255)) { Log_WarningPrintf("Skipping XA file with file number %u and channel number %u (submode 0x%02X coding 0x%02X)", - m_last_sector_subheader.file_number, m_last_sector_subheader.channel_number, - m_last_sector_subheader.submode.bits, m_last_sector_subheader.codinginfo.bits); + s_last_sector_subheader.file_number, s_last_sector_subheader.channel_number, + s_last_sector_subheader.submode.bits, s_last_sector_subheader.codinginfo.bits); return; } - m_xa_current_file_number = m_last_sector_subheader.file_number; - m_xa_current_channel_number = m_last_sector_subheader.channel_number; - m_xa_current_set = true; + s_xa_current_file_number = s_last_sector_subheader.file_number; + s_xa_current_channel_number = s_last_sector_subheader.channel_number; + s_xa_current_set = true; } - else if (m_last_sector_subheader.file_number != m_xa_current_file_number || - m_last_sector_subheader.channel_number != m_xa_current_channel_number) + else if (s_last_sector_subheader.file_number != s_xa_current_file_number || + s_last_sector_subheader.channel_number != s_xa_current_channel_number) { - Log_DebugPrintf("Skipping sector due to current file mismatch (expected %u/%u got %u/%u)", m_xa_current_file_number, - m_xa_current_channel_number, m_last_sector_subheader.file_number, - m_last_sector_subheader.channel_number); + Log_DebugPrintf("Skipping sector due to current file mismatch (expected %u/%u got %u/%u)", s_xa_current_file_number, + s_xa_current_channel_number, s_last_sector_subheader.file_number, + s_last_sector_subheader.channel_number); return; } // Reset current file on EOF, and play the file in the next sector. - if (m_last_sector_subheader.submode.eof) + if (s_last_sector_subheader.submode.eof) ResetCurrentXAFile(); std::array sample_buffer; - CDXA::DecodeADPCMSector(raw_sector, sample_buffer.data(), m_xa_last_samples.data()); + CDXA::DecodeADPCMSector(raw_sector, sample_buffer.data(), s_xa_last_samples.data()); // Only send to SPU if we're not muted. - if (m_muted || m_adpcm_muted || g_settings.cdrom_mute_cd_audio) + if (s_muted || s_adpcm_muted || g_settings.cdrom_mute_cd_audio) return; SPU::GeneratePendingSamples(); - if (m_last_sector_subheader.codinginfo.IsStereo()) + if (s_last_sector_subheader.codinginfo.IsStereo()) { - const u32 num_samples = m_last_sector_subheader.codinginfo.GetSamplesPerSector() / 2; - if (m_last_sector_subheader.codinginfo.IsHalfSampleRate()) + const u32 num_samples = s_last_sector_subheader.codinginfo.GetSamplesPerSector() / 2; + if (s_last_sector_subheader.codinginfo.IsHalfSampleRate()) ResampleXAADPCM(sample_buffer.data(), num_samples); else ResampleXAADPCM(sample_buffer.data(), num_samples); } else { - const u32 num_samples = m_last_sector_subheader.codinginfo.GetSamplesPerSector(); - if (m_last_sector_subheader.codinginfo.IsHalfSampleRate()) + const u32 num_samples = s_last_sector_subheader.codinginfo.GetSamplesPerSector(); + if (s_last_sector_subheader.codinginfo.IsHalfSampleRate()) ResampleXAADPCM(sample_buffer.data(), num_samples); else ResampleXAADPCM(sample_buffer.data(), num_samples); @@ -2635,40 +3036,40 @@ static s16 GetPeakVolume(const u8* raw_sector, u8 channel) void CDROM::ProcessCDDASector(const u8* raw_sector, const CDImage::SubChannelQ& subq) { // For CDDA sectors, the whole sector contains the audio data. - Log_DevPrintf("Read sector %u as CDDA", m_current_lba); + Log_DevPrintf("Read sector %u as CDDA", s_current_lba); // The reporting doesn't happen if we're reading with the CDDA mode bit set. - if (m_drive_state == DriveState::Playing && m_mode.report_audio) + if (s_drive_state == DriveState::Playing && s_mode.report_audio) { const u8 frame_nibble = subq.absolute_frame_bcd >> 4; - if (m_last_cdda_report_frame_nibble != frame_nibble) + if (s_last_cdda_report_frame_nibble != frame_nibble) { - m_last_cdda_report_frame_nibble = frame_nibble; + s_last_cdda_report_frame_nibble = frame_nibble; ClearAsyncInterrupt(); - m_async_response_fifo.Push(m_secondary_status.bits); - m_async_response_fifo.Push(subq.track_number_bcd); - m_async_response_fifo.Push(subq.index_number_bcd); + s_async_response_fifo.Push(s_secondary_status.bits); + s_async_response_fifo.Push(subq.track_number_bcd); + s_async_response_fifo.Push(subq.index_number_bcd); if (subq.absolute_frame_bcd & 0x10) { - m_async_response_fifo.Push(subq.relative_minute_bcd); - m_async_response_fifo.Push(0x80 | subq.relative_second_bcd); - m_async_response_fifo.Push(subq.relative_frame_bcd); + s_async_response_fifo.Push(subq.relative_minute_bcd); + s_async_response_fifo.Push(0x80 | subq.relative_second_bcd); + s_async_response_fifo.Push(subq.relative_frame_bcd); } else { - m_async_response_fifo.Push(subq.absolute_minute_bcd); - m_async_response_fifo.Push(subq.absolute_second_bcd); - m_async_response_fifo.Push(subq.absolute_frame_bcd); + s_async_response_fifo.Push(subq.absolute_minute_bcd); + s_async_response_fifo.Push(subq.absolute_second_bcd); + s_async_response_fifo.Push(subq.absolute_frame_bcd); } const u8 channel = subq.absolute_second_bcd & 1u; const s16 peak_volume = std::min(GetPeakVolume(raw_sector, channel), 32767); const u16 peak_value = (ZeroExtend16(channel) << 15) | peak_volume; - m_async_response_fifo.Push(Truncate8(peak_value)); // peak low - m_async_response_fifo.Push(Truncate8(peak_value >> 8)); // peak high + s_async_response_fifo.Push(Truncate8(peak_value)); // peak low + s_async_response_fifo.Push(Truncate8(peak_value >> 8)); // peak high SetAsyncInterrupt(Interrupt::DataReady); Log_DevPrintf("CDDA report at track[%02x] index[%02x] rel[%02x:%02x:%02x] abs[%02x:%02x:%02x] peak[%u:%d]", @@ -2679,18 +3080,18 @@ void CDROM::ProcessCDDASector(const u8* raw_sector, const CDImage::SubChannelQ& } // Apply volume when pushing sectors to SPU. - if (m_muted || g_settings.cdrom_mute_cd_audio) + if (s_muted || g_settings.cdrom_mute_cd_audio) return; SPU::GeneratePendingSamples(); constexpr bool is_stereo = true; constexpr u32 num_samples = CDImage::RAW_SECTOR_SIZE / sizeof(s16) / (is_stereo ? 2 : 1); - const u32 remaining_space = m_audio_fifo.GetSpace(); + const u32 remaining_space = s_audio_fifo.GetSpace(); if (remaining_space < num_samples) { Log_WarningPrintf("Dropping %u frames from audio FIFO", num_samples - remaining_space); - m_audio_fifo.Remove(num_samples - remaining_space); + s_audio_fifo.Remove(num_samples - remaining_space); } const u8* sector_ptr = raw_sector; @@ -2706,32 +3107,32 @@ void CDROM::ProcessCDDASector(const u8* raw_sector, const CDImage::SubChannelQ& void CDROM::LoadDataFIFO() { - if (!m_data_fifo.IsEmpty()) + if (!s_data_fifo.IsEmpty()) { Log_DevPrintf("Load data fifo when not empty"); return; } // any data to load? - SectorBuffer& sb = m_sector_buffers[m_current_read_sector_buffer]; + SectorBuffer& sb = s_sector_buffers[s_current_read_sector_buffer]; if (sb.size == 0) { Log_WarningPrintf("Attempting to load empty sector buffer"); - m_data_fifo.PushRange(sb.data.data(), RAW_SECTOR_OUTPUT_SIZE); + s_data_fifo.PushRange(sb.data.data(), RAW_SECTOR_OUTPUT_SIZE); } else { - m_data_fifo.PushRange(sb.data.data(), sb.size); + s_data_fifo.PushRange(sb.data.data(), sb.size); sb.size = 0; } - Log_DebugPrintf("Loaded %u bytes to data FIFO from buffer %u", m_data_fifo.GetSize(), m_current_read_sector_buffer); + Log_DebugPrintf("Loaded %u bytes to data FIFO from buffer %u", s_data_fifo.GetSize(), s_current_read_sector_buffer); - SectorBuffer& next_sb = m_sector_buffers[m_current_write_sector_buffer]; + SectorBuffer& next_sb = s_sector_buffers[s_current_write_sector_buffer]; if (next_sb.size > 0) { - Log_DevPrintf("Sending additional INT1 for missed sector in buffer %u", m_current_write_sector_buffer); - m_async_response_fifo.Push(m_secondary_status.bits); + Log_DevPrintf("Sending additional INT1 for missed sector in buffer %u", s_current_write_sector_buffer); + s_async_response_fifo.Push(s_secondary_status.bits); SetAsyncInterrupt(Interrupt::DataReady); } } @@ -2739,7 +3140,7 @@ void CDROM::LoadDataFIFO() void CDROM::ClearSectorBuffers() { for (u32 i = 0; i < NUM_SECTOR_BUFFERS; i++) - m_sector_buffers[i].size = 0; + s_sector_buffers[i].size = 0; } void CDROM::DrawDebugWindow() @@ -2761,7 +3162,7 @@ void CDROM::DrawDebugWindow() if (m_reader.HasMedia()) { const CDImage* media = m_reader.GetMedia(); - const CDImage::Position disc_position = CDImage::Position::FromLBA(m_current_lba); + const CDImage::Position disc_position = CDImage::Position::FromLBA(s_current_lba); if (media->HasSubImages()) { @@ -2784,13 +3185,13 @@ void CDROM::DrawDebugWindow() else { const CDImage::Position track_position = CDImage::Position::FromLBA( - m_current_lba - media->GetTrackStartPosition(static_cast(media->GetTrackNumber()))); + s_current_lba - media->GetTrackStartPosition(static_cast(media->GetTrackNumber()))); ImGui::Text("Track Position: Number[%u] MSF[%02u:%02u:%02u] LBA[%u]", media->GetTrackNumber(), track_position.minute, track_position.second, track_position.frame, track_position.ToLBA()); } - ImGui::Text("Last Sector: %02X:%02X:%02X (Mode %u)", m_last_sector_header.minute, m_last_sector_header.second, - m_last_sector_header.frame, m_last_sector_header.sector_mode); + ImGui::Text("Last Sector: %02X:%02X:%02X (Mode %u)", s_last_sector_header.minute, s_last_sector_header.second, + s_last_sector_header.frame, s_last_sector_header.sector_mode); } else { @@ -2809,78 +3210,78 @@ void CDROM::DrawDebugWindow() ImGui::Text("Mode Status"); ImGui::NextColumn(); - ImGui::TextColored(m_status.ADPBUSY ? active_color : inactive_color, "ADPBUSY: %s", - m_status.ADPBUSY ? "Yes" : "No"); + ImGui::TextColored(s_status.ADPBUSY ? active_color : inactive_color, "ADPBUSY: %s", + s_status.ADPBUSY ? "Yes" : "No"); ImGui::NextColumn(); - ImGui::TextColored(m_secondary_status.error ? active_color : inactive_color, "Error: %s", - m_secondary_status.error ? "Yes" : "No"); + ImGui::TextColored(s_secondary_status.error ? active_color : inactive_color, "Error: %s", + s_secondary_status.error ? "Yes" : "No"); ImGui::NextColumn(); - ImGui::TextColored(m_mode.cdda ? active_color : inactive_color, "CDDA: %s", m_mode.cdda ? "Yes" : "No"); + ImGui::TextColored(s_mode.cdda ? active_color : inactive_color, "CDDA: %s", s_mode.cdda ? "Yes" : "No"); ImGui::NextColumn(); - ImGui::TextColored(m_status.PRMEMPTY ? active_color : inactive_color, "PRMEMPTY: %s", - m_status.PRMEMPTY ? "Yes" : "No"); + ImGui::TextColored(s_status.PRMEMPTY ? active_color : inactive_color, "PRMEMPTY: %s", + s_status.PRMEMPTY ? "Yes" : "No"); ImGui::NextColumn(); - ImGui::TextColored(m_secondary_status.motor_on ? active_color : inactive_color, "Motor On: %s", - m_secondary_status.motor_on ? "Yes" : "No"); + ImGui::TextColored(s_secondary_status.motor_on ? active_color : inactive_color, "Motor On: %s", + s_secondary_status.motor_on ? "Yes" : "No"); ImGui::NextColumn(); - ImGui::TextColored(m_mode.auto_pause ? active_color : inactive_color, "Auto Pause: %s", - m_mode.auto_pause ? "Yes" : "No"); + ImGui::TextColored(s_mode.auto_pause ? active_color : inactive_color, "Auto Pause: %s", + s_mode.auto_pause ? "Yes" : "No"); ImGui::NextColumn(); - ImGui::TextColored(m_status.PRMWRDY ? active_color : inactive_color, "PRMWRDY: %s", - m_status.PRMWRDY ? "Yes" : "No"); + ImGui::TextColored(s_status.PRMWRDY ? active_color : inactive_color, "PRMWRDY: %s", + s_status.PRMWRDY ? "Yes" : "No"); ImGui::NextColumn(); - ImGui::TextColored(m_secondary_status.seek_error ? active_color : inactive_color, "Seek Error: %s", - m_secondary_status.seek_error ? "Yes" : "No"); + ImGui::TextColored(s_secondary_status.seek_error ? active_color : inactive_color, "Seek Error: %s", + s_secondary_status.seek_error ? "Yes" : "No"); ImGui::NextColumn(); - ImGui::TextColored(m_mode.report_audio ? active_color : inactive_color, "Report Audio: %s", - m_mode.report_audio ? "Yes" : "No"); + ImGui::TextColored(s_mode.report_audio ? active_color : inactive_color, "Report Audio: %s", + s_mode.report_audio ? "Yes" : "No"); ImGui::NextColumn(); - ImGui::TextColored(m_status.RSLRRDY ? active_color : inactive_color, "RSLRRDY: %s", - m_status.RSLRRDY ? "Yes" : "No"); + ImGui::TextColored(s_status.RSLRRDY ? active_color : inactive_color, "RSLRRDY: %s", + s_status.RSLRRDY ? "Yes" : "No"); ImGui::NextColumn(); - ImGui::TextColored(m_secondary_status.id_error ? active_color : inactive_color, "ID Error: %s", - m_secondary_status.id_error ? "Yes" : "No"); + ImGui::TextColored(s_secondary_status.id_error ? active_color : inactive_color, "ID Error: %s", + s_secondary_status.id_error ? "Yes" : "No"); ImGui::NextColumn(); - ImGui::TextColored(m_mode.xa_filter ? active_color : inactive_color, "XA Filter: %s (File %u Channel %u)", - m_mode.xa_filter ? "Yes" : "No", m_xa_filter_file_number, m_xa_filter_channel_number); + ImGui::TextColored(s_mode.xa_filter ? active_color : inactive_color, "XA Filter: %s (File %u Channel %u)", + s_mode.xa_filter ? "Yes" : "No", s_xa_filter_file_number, s_xa_filter_channel_number); ImGui::NextColumn(); - ImGui::TextColored(m_status.DRQSTS ? active_color : inactive_color, "DRQSTS: %s", m_status.DRQSTS ? "Yes" : "No"); + ImGui::TextColored(s_status.DRQSTS ? active_color : inactive_color, "DRQSTS: %s", s_status.DRQSTS ? "Yes" : "No"); ImGui::NextColumn(); - ImGui::TextColored(m_secondary_status.shell_open ? active_color : inactive_color, "Shell Open: %s", - m_secondary_status.shell_open ? "Yes" : "No"); + ImGui::TextColored(s_secondary_status.shell_open ? active_color : inactive_color, "Shell Open: %s", + s_secondary_status.shell_open ? "Yes" : "No"); ImGui::NextColumn(); - ImGui::TextColored(m_mode.ignore_bit ? active_color : inactive_color, "Ignore Bit: %s", - m_mode.ignore_bit ? "Yes" : "No"); + ImGui::TextColored(s_mode.ignore_bit ? active_color : inactive_color, "Ignore Bit: %s", + s_mode.ignore_bit ? "Yes" : "No"); ImGui::NextColumn(); - ImGui::TextColored(m_status.BUSYSTS ? active_color : inactive_color, "BUSYSTS: %s", - m_status.BUSYSTS ? "Yes" : "No"); + ImGui::TextColored(s_status.BUSYSTS ? active_color : inactive_color, "BUSYSTS: %s", + s_status.BUSYSTS ? "Yes" : "No"); ImGui::NextColumn(); - ImGui::TextColored(m_secondary_status.reading ? active_color : inactive_color, "Reading: %s", - m_secondary_status.reading ? "Yes" : "No"); + ImGui::TextColored(s_secondary_status.reading ? active_color : inactive_color, "Reading: %s", + s_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"); + ImGui::TextColored(s_mode.read_raw_sector ? active_color : inactive_color, "Read Raw Sectors: %s", + s_mode.read_raw_sector ? "Yes" : "No"); ImGui::NextColumn(); ImGui::NextColumn(); - ImGui::TextColored(m_secondary_status.seeking ? active_color : inactive_color, "Seeking: %s", - m_secondary_status.seeking ? "Yes" : "No"); + ImGui::TextColored(s_secondary_status.seeking ? active_color : inactive_color, "Seeking: %s", + s_secondary_status.seeking ? "Yes" : "No"); ImGui::NextColumn(); - ImGui::TextColored(m_mode.xa_enable ? active_color : inactive_color, "XA Enable: %s", - m_mode.xa_enable ? "Yes" : "No"); + ImGui::TextColored(s_mode.xa_enable ? active_color : inactive_color, "XA Enable: %s", + s_mode.xa_enable ? "Yes" : "No"); ImGui::NextColumn(); ImGui::NextColumn(); - ImGui::TextColored(m_secondary_status.playing_cdda ? active_color : inactive_color, "Playing CDDA: %s", - m_secondary_status.playing_cdda ? "Yes" : "No"); + ImGui::TextColored(s_secondary_status.playing_cdda ? active_color : inactive_color, "Playing CDDA: %s", + s_secondary_status.playing_cdda ? "Yes" : "No"); ImGui::NextColumn(); - ImGui::TextColored(m_mode.double_speed ? active_color : inactive_color, "Double Speed: %s", - m_mode.double_speed ? "Yes" : "No"); + ImGui::TextColored(s_mode.double_speed ? active_color : inactive_color, "Double Speed: %s", + s_mode.double_speed ? "Yes" : "No"); ImGui::NextColumn(); ImGui::Columns(1); @@ -2889,8 +3290,8 @@ void CDROM::DrawDebugWindow() if (HasPendingCommand()) { 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); + s_command_info[static_cast(s_command)].name, static_cast(s_command), + s_command_event->IsActive() ? s_command_event->GetTicksUntilNextExecution() : 0); } else { @@ -2904,39 +3305,39 @@ void CDROM::DrawDebugWindow() else { ImGui::TextColored(active_color, "Drive: %s (%d ticks remaining)", - s_drive_state_names[static_cast(m_drive_state)], - m_drive_event->IsActive() ? m_drive_event->GetTicksUntilNextExecution() : 0); + s_drive_state_names[static_cast(s_drive_state)], + s_drive_event->IsActive() ? s_drive_event->GetTicksUntilNextExecution() : 0); } - ImGui::Text("Interrupt Enable Register: 0x%02X", m_interrupt_enable_register); - ImGui::Text("Interrupt Flag Register: 0x%02X", m_interrupt_flag_register); + ImGui::Text("Interrupt Enable Register: 0x%02X", s_interrupt_enable_register); + ImGui::Text("Interrupt Flag Register: 0x%02X", s_interrupt_flag_register); } if (ImGui::CollapsingHeader("CD Audio", ImGuiTreeNodeFlags_DefaultOpen)) { - if (m_drive_state == DriveState::Reading && m_mode.xa_enable) + if (s_drive_state == DriveState::Reading && s_mode.xa_enable) { - ImGui::TextColored(active_color, "Playing: XA-ADPCM (File %u / Channel %u)", m_xa_current_file_number, - m_xa_current_channel_number); + ImGui::TextColored(active_color, "Playing: XA-ADPCM (File %u / Channel %u)", s_xa_current_file_number, + s_xa_current_channel_number); } - else if (m_drive_state == DriveState::Playing) + else if (s_drive_state == DriveState::Playing) { - ImGui::TextColored(active_color, "Playing: CDDA (Track %x)", m_last_subq.track_number_bcd); + ImGui::TextColored(active_color, "Playing: CDDA (Track %x)", s_last_subq.track_number_bcd); } else { ImGui::TextColored(inactive_color, "Playing: Inactive"); } - ImGui::TextColored(m_muted ? inactive_color : active_color, "Muted: %s", m_muted ? "Yes" : "No"); - ImGui::Text("Left Output: Left Channel=%02X (%u%%), Right Channel=%02X (%u%%)", m_cd_audio_volume_matrix[0][0], - ZeroExtend32(m_cd_audio_volume_matrix[0][0]) * 100 / 0x80, m_cd_audio_volume_matrix[1][0], - ZeroExtend32(m_cd_audio_volume_matrix[1][0]) * 100 / 0x80); - ImGui::Text("Right Output: Left Channel=%02X (%u%%), Right Channel=%02X (%u%%)", m_cd_audio_volume_matrix[0][1], - ZeroExtend32(m_cd_audio_volume_matrix[0][1]) * 100 / 0x80, m_cd_audio_volume_matrix[1][1], - ZeroExtend32(m_cd_audio_volume_matrix[1][1]) * 100 / 0x80); + ImGui::TextColored(s_muted ? inactive_color : active_color, "Muted: %s", s_muted ? "Yes" : "No"); + ImGui::Text("Left Output: Left Channel=%02X (%u%%), Right Channel=%02X (%u%%)", s_cd_audio_volume_matrix[0][0], + ZeroExtend32(s_cd_audio_volume_matrix[0][0]) * 100 / 0x80, s_cd_audio_volume_matrix[1][0], + ZeroExtend32(s_cd_audio_volume_matrix[1][0]) * 100 / 0x80); + ImGui::Text("Right Output: Left Channel=%02X (%u%%), Right Channel=%02X (%u%%)", s_cd_audio_volume_matrix[0][1], + ZeroExtend32(s_cd_audio_volume_matrix[0][1]) * 100 / 0x80, s_cd_audio_volume_matrix[1][1], + ZeroExtend32(s_cd_audio_volume_matrix[1][1]) * 100 / 0x80); - ImGui::Text("Audio FIFO Size: %u frames", m_audio_fifo.GetSize()); + ImGui::Text("Audio FIFO Size: %u frames", s_audio_fifo.GetSize()); } ImGui::End(); diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 30835c514..a75c4785c 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -2,414 +2,45 @@ // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once -#include "cdrom_async_reader.h" -#include "common/bitfield.h" -#include "common/fifo_queue.h" -#include "common/heap_array.h" #include "types.h" -#include "util/cd_image.h" -#include "util/cd_xa.h" -#include +#include #include -#include #include -#include - -class ProgressCallback; +class CDImage; class StateWrapper; -class TimingEvent; -class CDROM final -{ -public: - CDROM(); - ~CDROM(); +namespace CDROM { - void Initialize(); - void Shutdown(); - void Reset(); - bool DoState(StateWrapper& sw); +void Initialize(); +void Shutdown(); +void Reset(); +bool DoState(StateWrapper& sw); - bool HasMedia() const { return m_reader.HasMedia(); } - const std::string& GetMediaFileName() const { return m_reader.GetMediaFileName(); } - const CDImage* GetMedia() const { return m_reader.GetMedia(); } - DiscRegion GetDiscRegion() const { return m_disc_region; } - bool IsMediaPS1Disc() const; - bool DoesMediaRegionMatchConsole() const; +bool HasMedia(); +const std::string& GetMediaFileName(); +const CDImage* GetMedia(); +DiscRegion GetDiscRegion(); +bool IsMediaPS1Disc(); +bool DoesMediaRegionMatchConsole(); - void InsertMedia(std::unique_ptr media); - std::unique_ptr RemoveMedia(bool for_disc_swap); - bool PrecacheMedia(); +void InsertMedia(std::unique_ptr media); +std::unique_ptr RemoveMedia(bool for_disc_swap); +bool PrecacheMedia(); - void CPUClockChanged(); +void CPUClockChanged(); - // I/O - u8 ReadRegister(u32 offset); - void WriteRegister(u32 offset, u8 value); - void DMARead(u32* words, u32 word_count); +// I/O +u8 ReadRegister(u32 offset); +void WriteRegister(u32 offset, u8 value); +void DMARead(u32* words, u32 word_count); - // Render statistics debug window. - void DrawDebugWindow(); +// Render statistics debug window. +void DrawDebugWindow(); - void SetReadaheadSectors(u32 readahead_sectors); +void SetReadaheadSectors(u32 readahead_sectors); - /// Reads a frame from the audio FIFO, used by the SPU. - ALWAYS_INLINE std::tuple GetAudioFrame() - { - const u32 frame = m_audio_fifo.IsEmpty() ? 0u : m_audio_fifo.Pop(); - const s16 left = static_cast(Truncate16(frame)); - const s16 right = static_cast(Truncate16(frame >> 16)); - const s16 left_out = SaturateVolume(ApplyVolume(left, m_cd_audio_volume_matrix[0][0]) + - ApplyVolume(right, m_cd_audio_volume_matrix[1][0])); - const s16 right_out = SaturateVolume(ApplyVolume(left, m_cd_audio_volume_matrix[0][1]) + - ApplyVolume(right, m_cd_audio_volume_matrix[1][1])); - return std::tuple(left_out, right_out); - } +/// Reads a frame from the audio FIFO, used by the SPU. +std::tuple GetAudioFrame(); -private: - enum : u32 - { - RAW_SECTOR_OUTPUT_SIZE = CDImage::RAW_SECTOR_SIZE - CDImage::SECTOR_SYNC_SIZE, - DATA_SECTOR_OUTPUT_SIZE = CDImage::DATA_SECTOR_SIZE, - SECTOR_SYNC_SIZE = CDImage::SECTOR_SYNC_SIZE, - SECTOR_HEADER_SIZE = CDImage::SECTOR_HEADER_SIZE, - XA_RESAMPLE_RING_BUFFER_SIZE = 32, - XA_RESAMPLE_ZIGZAG_TABLE_SIZE = 29, - XA_RESAMPLE_NUM_ZIGZAG_TABLES = 7, - - PARAM_FIFO_SIZE = 16, - RESPONSE_FIFO_SIZE = 16, - DATA_FIFO_SIZE = RAW_SECTOR_OUTPUT_SIZE, - NUM_SECTOR_BUFFERS = 8, - AUDIO_FIFO_SIZE = 44100 * 2, - AUDIO_FIFO_LOW_WATERMARK = 10, - - INIT_TICKS = 400000, - ID_READ_TICKS = 33868, - MOTOR_ON_RESPONSE_TICKS = 400000, - - MAX_FAST_FORWARD_RATE = 12, - FAST_FORWARD_RATE_STEP = 4 - }; - - static constexpr u8 INTERRUPT_REGISTER_MASK = 0x1F; - - enum class Interrupt : u8 - { - DataReady = 0x01, - Complete = 0x02, - ACK = 0x03, - DataEnd = 0x04, - Error = 0x05 - }; - - enum class Command : u16 - { - Sync = 0x00, - Getstat = 0x01, - Setloc = 0x02, - Play = 0x03, - Forward = 0x04, - Backward = 0x05, - ReadN = 0x06, - MotorOn = 0x07, - Stop = 0x08, - Pause = 0x09, - Init = 0x0A, - Mute = 0x0B, - Demute = 0x0C, - Setfilter = 0x0D, - Setmode = 0x0E, - Getmode = 0x0F, - GetlocL = 0x10, - GetlocP = 0x11, - ReadT = 0x12, - GetTN = 0x13, - GetTD = 0x14, - SeekL = 0x15, - SeekP = 0x16, - SetClock = 0x17, - GetClock = 0x18, - Test = 0x19, - GetID = 0x1A, - ReadS = 0x1B, - Reset = 0x1C, - GetQ = 0x1D, - ReadTOC = 0x1E, - VideoCD = 0x1F, - - None = 0xFFFF - }; - - enum class DriveState : u8 - { - Idle, - ShellOpening, - UNUSED_Resetting, - SeekingPhysical, - SeekingLogical, - UNUSED_ReadingID, - UNUSED_ReadingTOC, - Reading, - Playing, - UNUSED_Pausing, - UNUSED_Stopping, - ChangingSession, - SpinningUp, - SeekingImplicit, - ChangingSpeedOrTOCRead - }; - - union StatusRegister - { - u8 bits; - BitField index; - BitField ADPBUSY; - BitField PRMEMPTY; - BitField PRMWRDY; - BitField RSLRRDY; - BitField DRQSTS; - BitField BUSYSTS; - }; - - enum StatBits : u8 - { - STAT_ERROR = (1 << 0), - STAT_MOTOR_ON = (1 << 1), - STAT_SEEK_ERROR = (1 << 2), - STAT_ID_ERROR = (1 << 3), - STAT_SHELL_OPEN = (1 << 4), - STAT_READING = (1 << 5), - STAT_SEEKING = (1 << 6), - STAT_PLAYING_CDDA = (1 << 7) - }; - - enum ErrorReason : u8 - { - ERROR_REASON_INVALID_ARGUMENT = 0x10, - ERROR_REASON_INCORRECT_NUMBER_OF_PARAMETERS = 0x20, - ERROR_REASON_INVALID_COMMAND = 0x40, - ERROR_REASON_NOT_READY = 0x80 - }; - - union SecondaryStatusRegister - { - u8 bits; - BitField error; - BitField motor_on; - BitField seek_error; - BitField id_error; - BitField shell_open; - BitField reading; - BitField seeking; - BitField playing_cdda; - - /// Clears the CDDA/seeking bits. - ALWAYS_INLINE void ClearActiveBits() { bits &= ~(STAT_SEEKING | STAT_READING | STAT_PLAYING_CDDA); } - - /// Sets the bits for seeking. - ALWAYS_INLINE void SetSeeking() - { - bits = (bits & ~(STAT_READING | STAT_PLAYING_CDDA)) | (STAT_MOTOR_ON | STAT_SEEKING); - } - - /// Sets the bits for reading/playing. - ALWAYS_INLINE void SetReadingBits(bool audio) - { - bits = (bits & ~(STAT_SEEKING | STAT_READING | STAT_PLAYING_CDDA)) | - ((audio) ? (STAT_MOTOR_ON | STAT_PLAYING_CDDA) : (STAT_MOTOR_ON | STAT_READING)); - } - }; - - union ModeRegister - { - u8 bits; - BitField cdda; - BitField auto_pause; - BitField report_audio; - BitField xa_filter; - BitField ignore_bit; - BitField read_raw_sector; - BitField xa_enable; - BitField double_speed; - }; - - union RequestRegister - { - u8 bits; - BitField SMEN; - BitField BFWR; - BitField BFRD; - }; - - void SoftReset(TickCount ticks_late); - - 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::SeekingImplicit); - } - ALWAYS_INLINE bool IsReadingOrPlaying() const - { - return (m_drive_state == DriveState::Reading || m_drive_state == DriveState::Playing); - } - ALWAYS_INLINE bool CanReadMedia() const { return (m_drive_state != DriveState::ShellOpening && m_reader.HasMedia()); } - ALWAYS_INLINE bool HasPendingCommand() const { return m_command != Command::None; } - ALWAYS_INLINE bool HasPendingInterrupt() const { return m_interrupt_flag_register != 0; } - ALWAYS_INLINE bool HasPendingAsyncInterrupt() const { return m_pending_async_interrupt != 0; } - ALWAYS_INLINE void AddCDAudioFrame(s16 left, s16 right) - { - m_audio_fifo.Push(ZeroExtend32(static_cast(left)) | (ZeroExtend32(static_cast(right)) << 16)); - } - ALWAYS_INLINE static constexpr s32 ApplyVolume(s16 sample, u8 volume) - { - return s32(sample) * static_cast(ZeroExtend32(volume)) >> 7; - } - - ALWAYS_INLINE static constexpr s16 SaturateVolume(s32 volume) - { - return static_cast((volume < -0x8000) ? -0x8000 : ((volume > 0x7FFF) ? 0x7FFF : volume)); - } - - void SetInterrupt(Interrupt interrupt); - void SetAsyncInterrupt(Interrupt interrupt); - void ClearAsyncInterrupt(); - void DeliverAsyncInterrupt(); - void SendACKAndStat(); - void SendErrorResponse(u8 stat_bits = STAT_ERROR, u8 reason = 0x80); - void SendAsyncErrorResponse(u8 stat_bits = STAT_ERROR, u8 reason = 0x80); - void UpdateStatusRegister(); - void UpdateInterruptRequest(); - bool HasPendingDiscEvent() const; - - TickCount GetAckDelayForCommand(Command command); - TickCount GetTicksForSpinUp(); - TickCount GetTicksForIDRead(); - TickCount GetTicksForRead(); - TickCount GetTicksForSeek(CDImage::LBA new_lba, bool ignore_speed_change = false); - TickCount GetTicksForStop(bool motor_was_on); - TickCount GetTicksForSpeedChange(); - TickCount GetTicksForTOCRead(); - CDImage::LBA GetNextSectorToBeRead(); - bool CompleteSeek(); - - void BeginCommand(Command command); // also update status register - void EndCommand(); // also updates status register - void AbortCommand(); - 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 DoSeekComplete(TickCount ticks_late); - void DoStatSecondResponse(); - void DoChangeSessionComplete(); - void DoSpinUpComplete(); - void DoSpeedChangeOrImplicitTOCReadComplete(); - void DoIDRead(); - 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 UpdatePhysicalPosition(bool update_logical); - void SetHoldPosition(CDImage::LBA lba, bool update_subq); - void ResetCurrentXAFile(); - void ResetAudioDecoder(); - void LoadDataFIFO(); - void ClearSectorBuffers(); - - template - 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; - - StatusRegister m_status = {}; - SecondaryStatusRegister m_secondary_status = {}; - ModeRegister m_mode = {}; - - u8 m_interrupt_enable_register = INTERRUPT_REGISTER_MASK; - u8 m_interrupt_flag_register = 0; - u8 m_pending_async_interrupt = 0; - - CDImage::Position m_setloc_position = {}; - CDImage::LBA m_requested_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{}; // current position of the disc with respect to time - u32 m_physical_lba_update_tick = 0; - u32 m_physical_lba_update_carry = 0; - bool m_setloc_pending = false; - bool m_read_after_seek = false; - bool m_play_after_seek = false; - - bool m_muted = false; - bool m_adpcm_muted = false; - - u8 m_xa_filter_file_number = 0; - u8 m_xa_filter_channel_number = 0; - u8 m_xa_current_file_number = 0; - u8 m_xa_current_channel_number = 0; - u8 m_xa_current_set = false; - - CDImage::SectorHeader m_last_sector_header{}; - CDXA::XASubHeader m_last_sector_subheader{}; - bool m_last_sector_header_valid = false; - CDImage::SubChannelQ m_last_subq{}; - u8 m_last_cdda_report_frame_nibble = 0xFF; - u8 m_play_track_number_bcd = 0xFF; - u8 m_async_command_parameter = 0x00; - s8 m_fast_forward_rate = 0; - - std::array, 2> m_cd_audio_volume_matrix{}; - std::array, 2> m_next_cd_audio_volume_matrix{}; - - std::array m_xa_last_samples{}; - std::array, 2> m_xa_resample_ring_buffer{}; - u8 m_xa_resample_p = 0; - u8 m_xa_resample_sixstep = 6; - - InlineFIFOQueue m_param_fifo; - InlineFIFOQueue m_response_fifo; - InlineFIFOQueue m_async_response_fifo; - HeapFIFOQueue m_data_fifo; - - struct SectorBuffer - { - HeapArray data; - u32 size; - }; - - u32 m_current_read_sector_buffer = 0; - u32 m_current_write_sector_buffer = 0; - std::array m_sector_buffers; - - CDROMAsyncReader m_reader; - - // two 16-bit samples packed in 32-bits - HeapFIFOQueue m_audio_fifo; -}; - -extern CDROM g_cdrom; +} // namespace CDROM diff --git a/src/core/dma.cpp b/src/core/dma.cpp index b041a6c30..2050d10ca 100644 --- a/src/core/dma.cpp +++ b/src/core/dma.cpp @@ -590,7 +590,7 @@ TickCount DMA::TransferDeviceToMemory(Channel channel, u32 address, u32 incremen break; case Channel::CDROM: - g_cdrom.DMARead(dest_pointer, word_count); + CDROM::DMARead(dest_pointer, word_count); break; case Channel::SPU: diff --git a/src/core/spu.cpp b/src/core/spu.cpp index 68c8508b4..5a22c67b3 100644 --- a/src/core/spu.cpp +++ b/src/core/spu.cpp @@ -3,6 +3,8 @@ #include "spu.h" #include "cdrom.h" +#include "common/bitfield.h" +#include "common/fifo_queue.h" #include "common/file_system.h" #include "common/log.h" #include "dma.h" @@ -13,6 +15,7 @@ #include "util/audio_stream.h" #include "util/state_wrapper.h" #include "util/wav_writer.h" +#include Log_SetChannel(SPU); // Enable to dump all voices of the SPU audio individually. @@ -2291,7 +2294,7 @@ void SPU::Execute(void* param, TickCount ticks, TickCount ticks_late) UpdateNoise(); // Mix in CD audio. - const auto [cd_audio_left, cd_audio_right] = g_cdrom.GetAudioFrame(); + const auto [cd_audio_left, cd_audio_right] = CDROM::GetAudioFrame(); if (s_SPUCNT.cd_audio_enable) { const s32 cd_audio_volume_left = ApplyVolume(s32(cd_audio_left), s_cd_audio_volume_left); diff --git a/src/core/spu.h b/src/core/spu.h index 87f42a23e..1bbcee772 100644 --- a/src/core/spu.h +++ b/src/core/spu.h @@ -2,12 +2,8 @@ // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once -#include "common/bitfield.h" -#include "common/fifo_queue.h" -#include "system.h" #include "types.h" #include -#include class StateWrapper; diff --git a/src/core/system.cpp b/src/core/system.cpp index 0ce6bddcf..7e8d01fc0 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -42,6 +42,7 @@ #include "texture_replacements.h" #include "timers.h" #include "util/audio_stream.h" +#include "util/cd_image.h" #include "util/ini_settings_interface.h" #include "util/iso_reader.h" #include "util/state_wrapper.h" @@ -262,7 +263,7 @@ ConsoleRegion System::GetRegion() DiscRegion System::GetDiscRegion() { - return g_cdrom.GetDiscRegion(); + return CDROM::GetDiscRegion(); } bool System::IsPALRegion() @@ -280,7 +281,7 @@ void System::UpdateOverclock() g_ticks_per_second = ScaleTicksToOverclock(MASTER_CLOCK); s_max_slice_ticks = ScaleTicksToOverclock(MASTER_CLOCK / 10); SPU::CPUClockChanged(); - g_cdrom.CPUClockChanged(); + CDROM::CPUClockChanged(); g_gpu->CPUClockChanged(); g_timers.CPUClocksChanged(); UpdateThrottlePeriod(); @@ -1250,9 +1251,9 @@ bool System::BootSystem(SystemBootParameters parameters) // Insert CD, and apply fastboot patch if enabled. if (media) - g_cdrom.InsertMedia(std::move(media)); - if (g_cdrom.HasMedia() && (parameters.override_fast_boot.has_value() ? parameters.override_fast_boot.value() : - g_settings.bios_patch_fast_boot)) + CDROM::InsertMedia(std::move(media)); + if (CDROM::HasMedia() && (parameters.override_fast_boot.has_value() ? parameters.override_fast_boot.value() : + g_settings.bios_patch_fast_boot)) { if (bios_info && bios_info->patch_compatible) BIOS::PatchBIOSFastBoot(Bus::g_bios, Bus::BIOS_SIZE); @@ -1295,7 +1296,7 @@ bool System::BootSystem(SystemBootParameters parameters) } if (parameters.load_image_to_ram || g_settings.cdrom_load_image_to_ram) - g_cdrom.PrecacheMedia(); + CDROM::PrecacheMedia(); if (g_settings.audio_dump_on_boot) StartDumpingAudio(); @@ -1388,7 +1389,7 @@ bool System::Initialize(bool force_software_renderer) g_dma.Initialize(); g_interrupt_controller.Initialize(); - g_cdrom.Initialize(); + CDROM::Initialize(); g_pad.Initialize(); g_timers.Initialize(); SPU::Initialize(); @@ -1454,7 +1455,7 @@ void System::DestroySystem() SPU::Shutdown(); g_timers.Shutdown(); g_pad.Shutdown(); - g_cdrom.Shutdown(); + CDROM::Shutdown(); g_gpu.reset(); g_interrupt_controller.Shutdown(); g_dma.Shutdown(); @@ -1651,7 +1652,7 @@ bool System::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_di if (!gpu_result) return false; - if (!sw.DoMarker("CDROM") || !g_cdrom.DoState(sw)) + if (!sw.DoMarker("CDROM") || !CDROM::DoState(sw)) return false; if (!sw.DoMarker("Pad") || !g_pad.DoState(sw)) @@ -1741,7 +1742,7 @@ void System::InternalReset() g_dma.Reset(); g_interrupt_controller.Reset(); g_gpu->Reset(true); - g_cdrom.Reset(); + CDROM::Reset(); g_pad.Reset(); g_timers.Reset(); SPU::Reset(); @@ -1826,7 +1827,7 @@ bool System::DoLoadState(ByteStream* state, bool force_software_renderer, bool u return false; } - std::unique_ptr old_media = g_cdrom.RemoveMedia(false); + std::unique_ptr old_media = CDROM::RemoveMedia(false); if (old_media && old_media->GetFileName() == media_filename) { Log_InfoPrintf("Re-using same media '%s'", media_filename.c_str()); @@ -1881,16 +1882,16 @@ bool System::DoLoadState(ByteStream* state, bool force_software_renderer, bool u ClearMemorySaveStates(); - g_cdrom.Reset(); + CDROM::Reset(); if (media) { - g_cdrom.InsertMedia(std::move(media)); + CDROM::InsertMedia(std::move(media)); if (g_settings.cdrom_load_image_to_ram) - g_cdrom.PrecacheMedia(); + CDROM::PrecacheMedia(); } else { - g_cdrom.RemoveMedia(false); + CDROM::RemoveMedia(false); } // ensure the correct card is loaded @@ -1956,12 +1957,12 @@ bool System::InternalSaveState(ByteStream* state, u32 screenshot_size /* = 256 * StringUtil::Strlcpy(header.title, s_running_game_title.c_str(), sizeof(header.title)); StringUtil::Strlcpy(header.serial, s_running_game_serial.c_str(), sizeof(header.serial)); - if (g_cdrom.HasMedia()) + if (CDROM::HasMedia()) { - const std::string& media_filename = g_cdrom.GetMediaFileName(); + const std::string& media_filename = CDROM::GetMediaFileName(); header.offset_to_media_filename = static_cast(state->GetPosition()); header.media_filename_length = static_cast(media_filename.length()); - header.media_subimage_index = g_cdrom.GetMedia()->HasSubImages() ? g_cdrom.GetMedia()->GetCurrentSubImage() : 0; + header.media_subimage_index = CDROM::GetMedia()->HasSubImages() ? CDROM::GetMedia()->GetCurrentSubImage() : 0; if (!media_filename.empty() && !state->Write2(media_filename.data(), header.media_filename_length)) return false; } @@ -2203,7 +2204,8 @@ void System::RunFrames() void System::UpdatePerformanceCounters() { const float frame_time = static_cast(s_frame_timer.GetTimeMillisecondsAndReset()); - s_minimum_frame_time_accumulator = (s_minimum_frame_time_accumulator == 0.0f) ? frame_time : std::min(s_minimum_frame_time_accumulator, frame_time); + s_minimum_frame_time_accumulator = + (s_minimum_frame_time_accumulator == 0.0f) ? frame_time : std::min(s_minimum_frame_time_accumulator, frame_time); s_average_frame_time_accumulator += frame_time; s_maximum_frame_time_accumulator = std::max(s_maximum_frame_time_accumulator, frame_time); s_frame_time_history[s_frame_time_history_pos] = frame_time; @@ -2884,15 +2886,15 @@ bool System::DumpSPURAM(const char* filename) bool System::HasMedia() { - return g_cdrom.HasMedia(); + return CDROM::HasMedia(); } std::string System::GetMediaFileName() { - if (!g_cdrom.HasMedia()) + if (!CDROM::HasMedia()) return {}; - return g_cdrom.GetMediaFileName(); + return CDROM::GetMediaFileName(); } bool System::InsertMedia(const char* path) @@ -2907,11 +2909,11 @@ bool System::InsertMedia(const char* path) } UpdateRunningGame(path, image.get(), false); - g_cdrom.InsertMedia(std::move(image)); + CDROM::InsertMedia(std::move(image)); Log_InfoPrintf("Inserted media from %s (%s, %s)", s_running_game_path.c_str(), s_running_game_serial.c_str(), s_running_game_title.c_str()); if (g_settings.cdrom_load_image_to_ram) - g_cdrom.PrecacheMedia(); + CDROM::PrecacheMedia(); Host::AddFormattedOSDMessage(10.0f, Host::TranslateString("OSDMessage", "Inserted disc '%s' (%s)."), s_running_game_title.c_str(), s_running_game_serial.c_str()); @@ -2928,7 +2930,7 @@ bool System::InsertMedia(const char* path) void System::RemoveMedia() { - g_cdrom.RemoveMedia(false); + CDROM::RemoveMedia(false); ClearMemorySaveStates(); } @@ -3034,25 +3036,25 @@ bool System::CheckForSBIFile(CDImage* image) bool System::HasMediaSubImages() { - const CDImage* cdi = g_cdrom.GetMedia(); + const CDImage* cdi = CDROM::GetMedia(); return cdi ? cdi->HasSubImages() : false; } u32 System::GetMediaSubImageCount() { - const CDImage* cdi = g_cdrom.GetMedia(); + const CDImage* cdi = CDROM::GetMedia(); return cdi ? cdi->GetSubImageCount() : 0; } u32 System::GetMediaSubImageIndex() { - const CDImage* cdi = g_cdrom.GetMedia(); + const CDImage* cdi = CDROM::GetMedia(); return cdi ? cdi->GetCurrentSubImage() : 0; } u32 System::GetMediaSubImageIndexForTitle(const std::string_view& title) { - const CDImage* cdi = g_cdrom.GetMedia(); + const CDImage* cdi = CDROM::GetMedia(); if (!cdi) return 0; @@ -3068,7 +3070,7 @@ u32 System::GetMediaSubImageIndexForTitle(const std::string_view& title) std::string System::GetMediaSubImageTitle(u32 index) { - const CDImage* cdi = g_cdrom.GetMedia(); + const CDImage* cdi = CDROM::GetMedia(); if (!cdi) return {}; @@ -3077,10 +3079,10 @@ std::string System::GetMediaSubImageTitle(u32 index) bool System::SwitchMediaSubImage(u32 index) { - if (!g_cdrom.HasMedia()) + if (!CDROM::HasMedia()) return false; - std::unique_ptr image = g_cdrom.RemoveMedia(true); + std::unique_ptr image = CDROM::RemoveMedia(true); Assert(image); Common::Error error; @@ -3089,14 +3091,14 @@ bool System::SwitchMediaSubImage(u32 index) Host::AddFormattedOSDMessage(10.0f, Host::TranslateString("OSDMessage", "Failed to switch to subimage %u in '%s': %s."), index + 1u, image->GetFileName().c_str(), error.GetCodeAndMessage().GetCharArray()); - g_cdrom.InsertMedia(std::move(image)); + CDROM::InsertMedia(std::move(image)); return false; } Host::AddFormattedOSDMessage(20.0f, Host::TranslateString("OSDMessage", "Switched to sub-image %s (%u) in '%s'."), image->GetSubImageMetadata(index, "title").c_str(), index + 1u, image->GetMetadata("title").c_str()); - g_cdrom.InsertMedia(std::move(image)); + CDROM::InsertMedia(std::move(image)); ClearMemorySaveStates(); return true; @@ -3272,7 +3274,7 @@ void System::CheckForSettingsChanges(const Settings& old_settings) } if (g_settings.cdrom_readahead_sectors != old_settings.cdrom_readahead_sectors) - g_cdrom.SetReadaheadSectors(g_settings.cdrom_readahead_sectors); + CDROM::SetReadaheadSectors(g_settings.cdrom_readahead_sectors); if (g_settings.memory_card_types != old_settings.memory_card_types || g_settings.memory_card_paths != old_settings.memory_card_paths || diff --git a/src/frontend-common/common_host.cpp b/src/frontend-common/common_host.cpp index 930ad332a..387e790f7 100644 --- a/src/frontend-common/common_host.cpp +++ b/src/frontend-common/common_host.cpp @@ -482,7 +482,7 @@ void ImGuiManager::RenderDebugWindows() if (g_settings.debugging.show_gpu_state) g_gpu->DrawDebugStateWindow(); if (g_settings.debugging.show_cdrom_state) - g_cdrom.DrawDebugWindow(); + CDROM::DrawDebugWindow(); if (g_settings.debugging.show_timers_state) g_timers.DrawDebugStateWindow(); if (g_settings.debugging.show_spu_state)