diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp index 01728ce014..709be9146f 100644 --- a/Source/Android/jni/MainAndroid.cpp +++ b/Source/Android/jni/MainAndroid.cpp @@ -44,6 +44,7 @@ #include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/Profiler.h" #include "Core/State.h" +#include "Core/System.h" #include "DiscIO/Blob.h" #include "DiscIO/Enums.h" @@ -648,7 +649,7 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ChangeDisc(J { const std::string path = GetJString(env, jFile); __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Change Disc: %s", path.c_str()); - Core::RunAsCPUThread([&path] { DVDInterface::ChangeDisc(path); }); + Core::RunAsCPUThread([&path] { Core::System::GetInstance().GetDVDInterface().ChangeDisc(path); }); } JNIEXPORT jobject JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_GetLogTypeNames(JNIEnv* env, diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 381f1a7e4c..fa272e7f9a 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -317,7 +317,7 @@ static const DiscIO::VolumeDisc* SetDisc(std::unique_ptr dis std::vector auto_disc_change_paths = {}) { const DiscIO::VolumeDisc* pointer = disc.get(); - DVDInterface::SetDisc(std::move(disc), auto_disc_change_paths); + Core::System::GetInstance().GetDVDInterface().SetDisc(std::move(disc), auto_disc_change_paths); return pointer; } @@ -344,7 +344,7 @@ bool CBoot::DVDReadDiscID(Core::System& system, const DiscIO::VolumeDisc& disc, // Transition out of the DiscIdNotRead state (which the drive should be in at this point, // on the assumption that this is only used for the first read) - DVDInterface::SetDriveState(DVDInterface::DriveState::ReadyNoReadsMade); + system.GetDVDInterface().SetDriveState(DVDInterface::DriveState::ReadyNoReadsMade); return true; } diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index 3c99fface2..222490d95c 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -295,11 +295,11 @@ bool CBoot::EmulatedBS2_GC(Core::System& system, const Core::CPUThreadGuard& gua // No known game uses a size other than the default. if (streaming_size == 0) streaming_size = 10; - DVDInterface::AudioBufferConfig(true, streaming_size); + system.GetDVDInterface().AudioBufferConfig(true, streaming_size); } else { - DVDInterface::AudioBufferConfig(false, 0); + system.GetDVDInterface().AudioBufferConfig(false, 0); } const bool ntsc = DiscIO::IsNTSC(SConfig::GetInstance().m_region); diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index 2b4f5be5b3..f2eefe171c 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -126,7 +126,7 @@ void SConfig::SetRunningGameMetadata(const IOS::ES::TMDReader& tmd, DiscIO::Plat // (IOS HLE ES calls us with a TMDReader rather than a volume when launching // a disc game, because ES has no reason to be accessing the disc directly.) if (platform == DiscIO::Platform::WiiWAD || - !DVDInterface::UpdateRunningGameMetadata(tmd_title_id)) + !Core::System::GetInstance().GetDVDInterface().UpdateRunningGameMetadata(tmd_title_id)) { // If not launching a disc game, just read everything from the TMD. SetRunningGameMetadata(tmd.GetGameID(), tmd.GetGameTDBID(), tmd_title_id, tmd.GetTitleVersion(), diff --git a/Source/Core/Core/HW/DVD/DVDInterface.cpp b/Source/Core/Core/HW/DVD/DVDInterface.cpp index e67e0028be..7c5ee10ff6 100644 --- a/Source/Core/Core/HW/DVD/DVDInterface.cpp +++ b/Source/Core/Core/HW/DVD/DVDInterface.cpp @@ -77,185 +77,59 @@ constexpr u32 DI_DMA_CONTROL_REGISTER = 0x1C; constexpr u32 DI_IMMEDIATE_DATA_BUFFER = 0x20; constexpr u32 DI_CONFIG_REGISTER = 0x24; -// DI Status Register -union UDISR -{ - u32 Hex = 0; - - BitField<0, 1, u32> BREAK; // Stop the Device + Interrupt - BitField<1, 1, u32> DEINTMASK; // Access Device Error Int Mask - BitField<2, 1, u32> DEINT; // Access Device Error Int - BitField<3, 1, u32> TCINTMASK; // Transfer Complete Int Mask - BitField<4, 1, u32> TCINT; // Transfer Complete Int - BitField<5, 1, u32> BRKINTMASK; - BitField<6, 1, u32> BRKINT; // w 1: clear brkint - BitField<7, 25, u32> reserved; - - UDISR() = default; - explicit UDISR(u32 hex) : Hex{hex} {} -}; - -// DI Cover Register -union UDICVR -{ - u32 Hex = 0; - - BitField<0, 1, u32> CVR; // 0: Cover closed 1: Cover open - BitField<1, 1, u32> CVRINTMASK; // 1: Interrupt enabled - BitField<2, 1, u32> CVRINT; // r 1: Interrupt requested w 1: Interrupt clear - BitField<3, 29, u32> reserved; - - UDICVR() = default; - explicit UDICVR(u32 hex) : Hex{hex} {} -}; - -// DI DMA Control Register -union UDICR -{ - u32 Hex = 0; - - BitField<0, 1, u32> TSTART; // w:1 start r:0 ready - BitField<1, 1, u32> DMA; // 1: DMA Mode - // 0: Immediate Mode (can only do Access Register Command) - BitField<2, 1, u32> RW; // 0: Read Command (DVD to Memory) 1: Write Command (Memory to DVD) - BitField<3, 29, u32> reserved; -}; - -// DI Config Register -union UDICFG -{ - u32 Hex = 0; - - BitField<0, 8, u32> CONFIG; - BitField<8, 24, u32> reserved; - - UDICFG() = default; - explicit UDICFG(u32 hex) : Hex{hex} {} -}; - -struct DVDInterfaceState::Data -{ - // Hardware registers - UDISR DISR; - UDICVR DICVR; - std::array DICMDBUF{}; - u32 DIMAR = 0; - u32 DILENGTH = 0; - UDICR DICR; - u32 DIIMMBUF = 0; - UDICFG DICFG; - - StreamADPCM::ADPCMDecoder adpcm_decoder; - - // DTK - bool stream = false; - bool stop_at_track_end = false; - u64 audio_position = 0; - u64 current_start = 0; - u32 current_length = 0; - u64 next_start = 0; - u32 next_length = 0; - u32 pending_samples = 0; - bool enable_dtk = false; - u8 dtk_buffer_length = 0; // TODO: figure out how this affects the regular buffer - - // Disc drive state - DriveState drive_state = DriveState::Ready; - DriveError error_code = DriveError::None; - u64 disc_end_offset = 0; - - // Disc drive timing - u64 read_buffer_start_time = 0; - u64 read_buffer_end_time = 0; - u64 read_buffer_start_offset = 0; - u64 read_buffer_end_offset = 0; - - // Disc changing - std::string disc_path_to_insert; - std::vector auto_disc_change_paths; - size_t auto_disc_change_index = 0; - - // Events - CoreTiming::EventType* finish_executing_command = nullptr; - CoreTiming::EventType* auto_change_disc = nullptr; - CoreTiming::EventType* eject_disc = nullptr; - CoreTiming::EventType* insert_disc = nullptr; -}; - -DVDInterfaceState::DVDInterfaceState() : m_data(std::make_unique()) +DVDInterfaceManager::DVDInterfaceManager(Core::System& system) : m_system(system) { } -DVDInterfaceState::~DVDInterfaceState() = default; - -static void AutoChangeDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate); -static void EjectDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate); -static void InsertDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate); -static void FinishExecutingCommandCallback(Core::System& system, u64 userdata, s64 cycles_late); - -static void SetLidOpen(); - -static void UpdateInterrupts(); -static void GenerateDIInterrupt(DIInterruptType dvd_interrupt); - -static bool ExecuteReadCommand(u64 dvd_offset, u32 output_address, u32 dvd_length, - u32 output_length, const DiscIO::Partition& partition, - ReplyType reply_type, DIInterruptType* interrupt_type); +DVDInterfaceManager::~DVDInterfaceManager() = default; static u64 PackFinishExecutingCommandUserdata(ReplyType reply_type, DIInterruptType interrupt_type); -static void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& partition, - u32 output_address, ReplyType reply_type); - -void DoState(PointerWrap& p) +void DVDInterfaceManager::DoState(PointerWrap& p) { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); + p.Do(m_DISR); + p.Do(m_DICVR); + p.DoArray(m_DICMDBUF); + p.Do(m_DIMAR); + p.Do(m_DILENGTH); + p.Do(m_DICR); + p.Do(m_DIIMMBUF); + p.Do(m_DICFG); - p.Do(state.DISR); - p.Do(state.DICVR); - p.DoArray(state.DICMDBUF); - p.Do(state.DIMAR); - p.Do(state.DILENGTH); - p.Do(state.DICR); - p.Do(state.DIIMMBUF); - p.Do(state.DICFG); + p.Do(m_stream); + p.Do(m_stop_at_track_end); + p.Do(m_audio_position); + p.Do(m_current_start); + p.Do(m_current_length); + p.Do(m_next_start); + p.Do(m_next_length); + p.Do(m_pending_samples); + p.Do(m_enable_dtk); + p.Do(m_dtk_buffer_length); - p.Do(state.stream); - p.Do(state.stop_at_track_end); - p.Do(state.audio_position); - p.Do(state.current_start); - p.Do(state.current_length); - p.Do(state.next_start); - p.Do(state.next_length); - p.Do(state.pending_samples); - p.Do(state.enable_dtk); - p.Do(state.dtk_buffer_length); + p.Do(m_drive_state); + p.Do(m_error_code); - p.Do(state.drive_state); - p.Do(state.error_code); + p.Do(m_read_buffer_start_time); + p.Do(m_read_buffer_end_time); + p.Do(m_read_buffer_start_offset); + p.Do(m_read_buffer_end_offset); - p.Do(state.read_buffer_start_time); - p.Do(state.read_buffer_end_time); - p.Do(state.read_buffer_start_offset); - p.Do(state.read_buffer_end_offset); - - p.Do(state.disc_path_to_insert); + p.Do(m_disc_path_to_insert); DVDThread::DoState(p); - state.adpcm_decoder.DoState(p); + m_adpcm_decoder.DoState(p); } -static size_t ProcessDTKSamples(std::vector* temp_pcm, const std::vector& audio_data) +size_t DVDInterfaceManager::ProcessDTKSamples(std::vector* temp_pcm, + const std::vector& audio_data) { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); - size_t samples_processed = 0; size_t bytes_processed = 0; while (samples_processed < temp_pcm->size() / 2 && bytes_processed < audio_data.size()) { - state.adpcm_decoder.DecodeBlock(&(*temp_pcm)[samples_processed * 2], - &audio_data[bytes_processed]); + m_adpcm_decoder.DecodeBlock(&(*temp_pcm)[samples_processed * 2], &audio_data[bytes_processed]); for (size_t i = 0; i < StreamADPCM::SAMPLES_PER_BLOCK * 2; ++i) { // TODO: Fix the mixer so it can accept non-byte-swapped samples. @@ -268,37 +142,35 @@ static size_t ProcessDTKSamples(std::vector* temp_pcm, const std::vector= state.current_start + state.current_length) + if (m_audio_position >= m_current_start + m_current_length) { DEBUG_LOG_FMT(DVDINTERFACE, "AdvanceDTK: NextStart={:08x}, NextLength={:08x}, " "CurrentStart={:08x}, CurrentLength={:08x}, AudioPos={:08x}", - state.next_start, state.next_length, state.current_start, state.current_length, - state.audio_position); + m_next_start, m_next_length, m_current_start, m_current_length, + m_audio_position); - state.audio_position = state.next_start; - state.current_start = state.next_start; - state.current_length = state.next_length; + m_audio_position = m_next_start; + m_current_start = m_next_start; + m_current_length = m_next_length; - if (state.stop_at_track_end) + if (m_stop_at_track_end) { - state.stop_at_track_end = false; - state.stream = false; + m_stop_at_track_end = false; + m_stream = false; break; } - state.adpcm_decoder.ResetFilter(); + m_adpcm_decoder.ResetFilter(); } - state.audio_position += StreamADPCM::ONE_BLOCK_SIZE; + m_audio_position += StreamADPCM::ONE_BLOCK_SIZE; bytes_to_process += StreamADPCM::ONE_BLOCK_SIZE; *samples_to_process += StreamADPCM::SAMPLES_PER_BLOCK; } @@ -306,12 +178,10 @@ static u32 AdvanceDTK(u32 maximum_samples, u32* samples_to_process) return bytes_to_process; } -static void DTKStreamingCallback(DIInterruptType interrupt_type, const std::vector& audio_data, - s64 cycles_late) +void DVDInterfaceManager::DTKStreamingCallback(DIInterruptType interrupt_type, + const std::vector& audio_data, s64 cycles_late) { - auto& system = Core::System::GetInstance(); - auto& state = system.GetDVDInterfaceState().GetData(); - auto& ai = system.GetAudioInterface(); + auto& ai = m_system.GetAudioInterface(); // Actual games always set this to 48 KHz // but let's make sure to use GetAISSampleRateDivisor() @@ -329,31 +199,31 @@ static void DTKStreamingCallback(DIInterruptType interrupt_type, const std::vect if (interrupt_type == DIInterruptType::TCINT) { // Send audio to the mixer. - std::vector temp_pcm(state.pending_samples * 2, 0); + std::vector temp_pcm(m_pending_samples * 2, 0); ProcessDTKSamples(&temp_pcm, audio_data); - SoundStream* sound_stream = system.GetSoundStream(); - sound_stream->GetMixer()->PushStreamingSamples(temp_pcm.data(), state.pending_samples); + SoundStream* sound_stream = m_system.GetSoundStream(); + sound_stream->GetMixer()->PushStreamingSamples(temp_pcm.data(), m_pending_samples); - if (state.stream && ai.IsPlaying()) + if (m_stream && ai.IsPlaying()) { - read_offset = state.audio_position; - read_length = AdvanceDTK(maximum_samples, &state.pending_samples); + read_offset = m_audio_position; + read_length = AdvanceDTK(maximum_samples, &m_pending_samples); } else { read_length = 0; - state.pending_samples = maximum_samples; + m_pending_samples = maximum_samples; } } else { read_length = 0; - state.pending_samples = maximum_samples; + m_pending_samples = maximum_samples; } // Read the next chunk of audio data asynchronously. - s64 ticks_to_dtk = SystemTimers::GetTicksPerSecond() * s64(state.pending_samples) * + s64 ticks_to_dtk = SystemTimers::GetTicksPerSecond() * s64(m_pending_samples) * sample_rate_divisor / Mixer::FIXED_SAMPLE_RATE_DIVIDEND; ticks_to_dtk -= cycles_late; if (read_length > 0) @@ -365,60 +235,56 @@ static void DTKStreamingCallback(DIInterruptType interrupt_type, const std::vect { // There's nothing to read, so using DVDThread is unnecessary. u64 userdata = PackFinishExecutingCommandUserdata(ReplyType::DTK, DIInterruptType::TCINT); - system.GetCoreTiming().ScheduleEvent(ticks_to_dtk, state.finish_executing_command, userdata); + m_system.GetCoreTiming().ScheduleEvent(ticks_to_dtk, m_finish_executing_command, userdata); } } -void Init() +void DVDInterfaceManager::Init() { ASSERT(!IsDiscInside()); DVDThread::Start(); - auto& system = Core::System::GetInstance(); - auto& core_timing = system.GetCoreTiming(); - auto& state = system.GetDVDInterfaceState().GetData(); - - state.DISR.Hex = 0; - state.DICVR.Hex = 1; // Disc Channel relies on cover being open when no disc is inserted - state.DICMDBUF[0] = 0; - state.DICMDBUF[1] = 0; - state.DICMDBUF[2] = 0; - state.DIMAR = 0; - state.DILENGTH = 0; - state.DICR.Hex = 0; - state.DIIMMBUF = 0; - state.DICFG.Hex = 0; - state.DICFG.CONFIG = 1; // Disable bootrom descrambler + m_DISR.Hex = 0; + m_DICVR.Hex = 1; // Disc Channel relies on cover being open when no disc is inserted + m_DICMDBUF[0] = 0; + m_DICMDBUF[1] = 0; + m_DICMDBUF[2] = 0; + m_DIMAR = 0; + m_DILENGTH = 0; + m_DICR.Hex = 0; + m_DIIMMBUF = 0; + m_DICFG.Hex = 0; + m_DICFG.CONFIG = 1; // Disable bootrom descrambler ResetDrive(false); - state.auto_change_disc = core_timing.RegisterEvent("AutoChangeDisc", AutoChangeDiscCallback); - state.eject_disc = core_timing.RegisterEvent("EjectDisc", EjectDiscCallback); - state.insert_disc = core_timing.RegisterEvent("InsertDisc", InsertDiscCallback); + auto& core_timing = m_system.GetCoreTiming(); + m_auto_change_disc = core_timing.RegisterEvent("AutoChangeDisc", AutoChangeDiscCallback); + m_eject_disc = core_timing.RegisterEvent("EjectDisc", EjectDiscCallback); + m_insert_disc = core_timing.RegisterEvent("InsertDisc", InsertDiscCallback); - state.finish_executing_command = + m_finish_executing_command = core_timing.RegisterEvent("FinishExecutingCommand", FinishExecutingCommandCallback); u64 userdata = PackFinishExecutingCommandUserdata(ReplyType::DTK, DIInterruptType::TCINT); - core_timing.ScheduleEvent(0, state.finish_executing_command, userdata); + core_timing.ScheduleEvent(0, m_finish_executing_command, userdata); } // Resets state on the MN102 chip in the drive itself, but not the DI registers exposed on the // emulated device, or any inserted disc. -void ResetDrive(bool spinup) +void DVDInterfaceManager::ResetDrive(bool spinup) { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); - state.stream = false; - state.stop_at_track_end = false; - state.audio_position = 0; - state.next_start = 0; - state.next_length = 0; - state.current_start = 0; - state.current_length = 0; - state.pending_samples = 0; - state.enable_dtk = false; - state.dtk_buffer_length = 0; + m_stream = false; + m_stop_at_track_end = false; + m_audio_position = 0; + m_next_start = 0; + m_next_length = 0; + m_current_start = 0; + m_current_length = 0; + m_pending_samples = 0; + m_enable_dtk = false; + m_dtk_buffer_length = 0; if (!IsDiscInside()) { @@ -443,13 +309,13 @@ void ResetDrive(bool spinup) SetDriveError(DriveError::None); // The buffer is empty at start - state.read_buffer_start_offset = 0; - state.read_buffer_end_offset = 0; - state.read_buffer_start_time = 0; - state.read_buffer_end_time = 0; + m_read_buffer_start_offset = 0; + m_read_buffer_end_offset = 0; + m_read_buffer_start_time = 0; + m_read_buffer_end_time = 0; } -void Shutdown() +void DVDInterfaceManager::Shutdown() { DVDThread::Stop(); } @@ -481,18 +347,18 @@ static u64 GetDiscEndOffset(const DiscIO::VolumeDisc& disc) return DiscIO::DL_DVD_SIZE; } -void SetDisc(std::unique_ptr disc, - std::optional> auto_disc_change_paths = {}) +void DVDInterfaceManager::SetDisc( + std::unique_ptr disc, + std::optional> auto_disc_change_paths = {}) { bool had_disc = IsDiscInside(); bool has_disc = static_cast(disc); - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); if (has_disc) { - state.disc_end_offset = GetDiscEndOffset(*disc); + m_disc_end_offset = GetDiscEndOffset(*disc); if (disc->GetDataSizeType() != DiscIO::DataSizeType::Accurate) - WARN_LOG_FMT(DVDINTERFACE, "Unknown disc size, guessing {0} bytes", state.disc_end_offset); + WARN_LOG_FMT(DVDINTERFACE, "Unknown disc size, guessing {0} bytes", m_disc_end_offset); const DiscIO::BlobReader& blob = disc->GetBlobReader(); @@ -516,8 +382,8 @@ void SetDisc(std::unique_ptr disc, ASSERT_MSG(DISCIO, (*auto_disc_change_paths).size() != 1, "Cannot automatically change between one disc"); - state.auto_disc_change_paths = *auto_disc_change_paths; - state.auto_disc_change_index = 0; + m_auto_disc_change_paths = *auto_disc_change_paths; + m_auto_disc_change_index = 0; } // Assume that inserting a disc requires having an empty disc before @@ -530,66 +396,60 @@ void SetDisc(std::unique_ptr disc, ResetDrive(false); } -bool IsDiscInside() +bool DVDInterfaceManager::IsDiscInside() const { return DVDThread::HasDisc(); } -static void AutoChangeDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate) +void DVDInterfaceManager::AutoChangeDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate) { - AutoChangeDisc(); + system.GetDVDInterface().AutoChangeDisc(); } -static void EjectDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate) +void DVDInterfaceManager::EjectDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate) { - SetDisc(nullptr, {}); + system.GetDVDInterface().SetDisc(nullptr, {}); } -static void InsertDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate) +void DVDInterfaceManager::InsertDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate) { - auto& state = system.GetDVDInterfaceState().GetData(); - std::unique_ptr new_disc = DiscIO::CreateDisc(state.disc_path_to_insert); + auto& di = system.GetDVDInterface(); + std::unique_ptr new_disc = DiscIO::CreateDisc(di.m_disc_path_to_insert); if (new_disc) - SetDisc(std::move(new_disc), {}); + di.SetDisc(std::move(new_disc), {}); else PanicAlertFmtT("The disc that was about to be inserted couldn't be found."); - state.disc_path_to_insert.clear(); + di.m_disc_path_to_insert.clear(); } // Must only be called on the CPU thread -void EjectDisc(EjectCause cause) +void DVDInterfaceManager::EjectDisc(EjectCause cause) { - auto& system = Core::System::GetInstance(); - auto& core_timing = system.GetCoreTiming(); - auto& state = system.GetDVDInterfaceState().GetData(); - core_timing.ScheduleEvent(0, state.eject_disc); + m_system.GetCoreTiming().ScheduleEvent(0, m_eject_disc); if (cause == EjectCause::User) ExpansionInterface::g_rtc_flags[ExpansionInterface::RTCFlag::EjectButton] = true; } // Must only be called on the CPU thread -void ChangeDisc(const std::vector& paths) +void DVDInterfaceManager::ChangeDisc(const std::vector& paths) { ASSERT_MSG(DISCIO, !paths.empty(), "Trying to insert an empty list of discs"); if (paths.size() > 1) { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); - state.auto_disc_change_paths = paths; - state.auto_disc_change_index = 0; + m_auto_disc_change_paths = paths; + m_auto_disc_change_index = 0; } ChangeDisc(paths[0]); } // Must only be called on the CPU thread -void ChangeDisc(const std::string& new_path) +void DVDInterfaceManager::ChangeDisc(const std::string& new_path) { - auto& system = Core::System::GetInstance(); - auto& state = system.GetDVDInterfaceState().GetData(); - if (!state.disc_path_to_insert.empty()) + if (!m_disc_path_to_insert.empty()) { PanicAlertFmtT("A disc is already about to be inserted."); return; @@ -597,45 +457,42 @@ void ChangeDisc(const std::string& new_path) EjectDisc(EjectCause::User); - state.disc_path_to_insert = new_path; - system.GetCoreTiming().ScheduleEvent(SystemTimers::GetTicksPerSecond(), state.insert_disc); + m_disc_path_to_insert = new_path; + m_system.GetCoreTiming().ScheduleEvent(SystemTimers::GetTicksPerSecond(), m_insert_disc); Movie::SignalDiscChange(new_path); - for (size_t i = 0; i < state.auto_disc_change_paths.size(); ++i) + for (size_t i = 0; i < m_auto_disc_change_paths.size(); ++i) { - if (state.auto_disc_change_paths[i] == new_path) + if (m_auto_disc_change_paths[i] == new_path) { - state.auto_disc_change_index = i; + m_auto_disc_change_index = i; return; } } - state.auto_disc_change_paths.clear(); + m_auto_disc_change_paths.clear(); } // Must only be called on the CPU thread -bool AutoChangeDisc() +bool DVDInterfaceManager::AutoChangeDisc() { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); - if (state.auto_disc_change_paths.empty()) + if (m_auto_disc_change_paths.empty()) return false; - state.auto_disc_change_index = - (state.auto_disc_change_index + 1) % state.auto_disc_change_paths.size(); - ChangeDisc(state.auto_disc_change_paths[state.auto_disc_change_index]); + m_auto_disc_change_index = (m_auto_disc_change_index + 1) % m_auto_disc_change_paths.size(); + ChangeDisc(m_auto_disc_change_paths[m_auto_disc_change_index]); return true; } -static void SetLidOpen() +void DVDInterfaceManager::SetLidOpen() { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); - const u32 old_value = state.DICVR.CVR; - state.DICVR.CVR = IsDiscInside() ? 0 : 1; - if (state.DICVR.CVR != old_value) + const u32 old_value = m_DICVR.CVR; + m_DICVR.CVR = IsDiscInside() ? 0 : 1; + if (m_DICVR.CVR != old_value) GenerateDIInterrupt(DIInterruptType::CVRINT); } -bool UpdateRunningGameMetadata(std::optional title_id) +bool DVDInterfaceManager::UpdateRunningGameMetadata(std::optional title_id) { if (!DVDThread::HasDisc()) return false; @@ -643,56 +500,55 @@ bool UpdateRunningGameMetadata(std::optional title_id) return DVDThread::UpdateRunningGameMetadata(IOS::HLE::DIDevice::GetCurrentPartition(), title_id); } -void RegisterMMIO(MMIO::Mapping* mmio, u32 base, bool is_wii) +void DVDInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base, bool is_wii) { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); - mmio->Register(base | DI_STATUS_REGISTER, MMIO::DirectRead(&state.DISR.Hex), + mmio->Register(base | DI_STATUS_REGISTER, MMIO::DirectRead(&m_DISR.Hex), MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { - auto& state_ = system.GetDVDInterfaceState().GetData(); + auto& di = system.GetDVDInterface(); const UDISR tmp_status_reg(val); - state_.DISR.DEINTMASK = tmp_status_reg.DEINTMASK.Value(); - state_.DISR.TCINTMASK = tmp_status_reg.TCINTMASK.Value(); - state_.DISR.BRKINTMASK = tmp_status_reg.BRKINTMASK.Value(); - state_.DISR.BREAK = tmp_status_reg.BREAK.Value(); + di.m_DISR.DEINTMASK = tmp_status_reg.DEINTMASK.Value(); + di.m_DISR.TCINTMASK = tmp_status_reg.TCINTMASK.Value(); + di.m_DISR.BRKINTMASK = tmp_status_reg.BRKINTMASK.Value(); + di.m_DISR.BREAK = tmp_status_reg.BREAK.Value(); if (tmp_status_reg.DEINT) - state_.DISR.DEINT = 0; + di.m_DISR.DEINT = 0; if (tmp_status_reg.TCINT) - state_.DISR.TCINT = 0; + di.m_DISR.TCINT = 0; if (tmp_status_reg.BRKINT) - state_.DISR.BRKINT = 0; + di.m_DISR.BRKINT = 0; - if (state_.DISR.BREAK) + if (di.m_DISR.BREAK) { DEBUG_ASSERT(false); } - UpdateInterrupts(); + di.UpdateInterrupts(); })); - mmio->Register(base | DI_COVER_REGISTER, MMIO::DirectRead(&state.DICVR.Hex), + mmio->Register(base | DI_COVER_REGISTER, MMIO::DirectRead(&m_DICVR.Hex), MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { - auto& state_ = system.GetDVDInterfaceState().GetData(); + auto& di = system.GetDVDInterface(); const UDICVR tmp_cover_reg(val); - state_.DICVR.CVRINTMASK = tmp_cover_reg.CVRINTMASK.Value(); + di.m_DICVR.CVRINTMASK = tmp_cover_reg.CVRINTMASK.Value(); if (tmp_cover_reg.CVRINT) - state_.DICVR.CVRINT = 0; + di.m_DICVR.CVRINT = 0; - UpdateInterrupts(); + di.UpdateInterrupts(); })); // Command registers, which have no special logic - mmio->Register(base | DI_COMMAND_0, MMIO::DirectRead(&state.DICMDBUF[0]), - MMIO::DirectWrite(&state.DICMDBUF[0])); - mmio->Register(base | DI_COMMAND_1, MMIO::DirectRead(&state.DICMDBUF[1]), - MMIO::DirectWrite(&state.DICMDBUF[1])); - mmio->Register(base | DI_COMMAND_2, MMIO::DirectRead(&state.DICMDBUF[2]), - MMIO::DirectWrite(&state.DICMDBUF[2])); + mmio->Register(base | DI_COMMAND_0, MMIO::DirectRead(&m_DICMDBUF[0]), + MMIO::DirectWrite(&m_DICMDBUF[0])); + mmio->Register(base | DI_COMMAND_1, MMIO::DirectRead(&m_DICMDBUF[1]), + MMIO::DirectWrite(&m_DICMDBUF[1])); + mmio->Register(base | DI_COMMAND_2, MMIO::DirectRead(&m_DICMDBUF[2]), + MMIO::DirectWrite(&m_DICMDBUF[2])); // DMA related registers. Mostly direct accesses (+ masking for writes to // handle things like address alignment) and complex write on the DMA @@ -707,101 +563,95 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base, bool is_wii) // address (0x0D006000), although we allow writes to both of these addresses if Dolphin was // started in Wii mode. (Also, normally in Wii mode the DI MMIOs are only written by the // IOS /dev/di module, but we *do* emulate /dev/di writing the DI MMIOs.) - mmio->Register(base | DI_DMA_ADDRESS_REGISTER, MMIO::DirectRead(&state.DIMAR), - MMIO::DirectWrite(&state.DIMAR, is_wii ? ~0x1F : ~0xFC00001F)); - mmio->Register(base | DI_DMA_LENGTH_REGISTER, MMIO::DirectRead(&state.DILENGTH), - MMIO::DirectWrite(&state.DILENGTH, ~0x1F)); - mmio->Register(base | DI_DMA_CONTROL_REGISTER, MMIO::DirectRead(&state.DICR.Hex), + mmio->Register(base | DI_DMA_ADDRESS_REGISTER, MMIO::DirectRead(&m_DIMAR), + MMIO::DirectWrite(&m_DIMAR, is_wii ? ~0x1F : ~0xFC00001F)); + mmio->Register(base | DI_DMA_LENGTH_REGISTER, MMIO::DirectRead(&m_DILENGTH), + MMIO::DirectWrite(&m_DILENGTH, ~0x1F)); + mmio->Register(base | DI_DMA_CONTROL_REGISTER, MMIO::DirectRead(&m_DICR.Hex), MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { - auto& state_ = system.GetDVDInterfaceState().GetData(); - state_.DICR.Hex = val & 7; - if (state_.DICR.TSTART) + auto& di = system.GetDVDInterface(); + di.m_DICR.Hex = val & 7; + if (di.m_DICR.TSTART) { - ExecuteCommand(ReplyType::Interrupt); + di.ExecuteCommand(ReplyType::Interrupt); } })); - mmio->Register(base | DI_IMMEDIATE_DATA_BUFFER, MMIO::DirectRead(&state.DIIMMBUF), - MMIO::DirectWrite(&state.DIIMMBUF)); + mmio->Register(base | DI_IMMEDIATE_DATA_BUFFER, MMIO::DirectRead(&m_DIIMMBUF), + MMIO::DirectWrite(&m_DIIMMBUF)); // DI config register is read only. - mmio->Register(base | DI_CONFIG_REGISTER, MMIO::DirectRead(&state.DICFG.Hex), + mmio->Register(base | DI_CONFIG_REGISTER, MMIO::DirectRead(&m_DICFG.Hex), MMIO::InvalidWrite()); } -static void UpdateInterrupts() +void DVDInterfaceManager::UpdateInterrupts() { - auto& system = Core::System::GetInstance(); - auto& state = system.GetDVDInterfaceState().GetData(); - const bool set_mask = (state.DISR.DEINT & state.DISR.DEINTMASK) != 0 || - (state.DISR.TCINT & state.DISR.TCINTMASK) != 0 || - (state.DISR.BRKINT & state.DISR.BRKINTMASK) != 0 || - (state.DICVR.CVRINT & state.DICVR.CVRINTMASK) != 0; + const bool set_mask = + (m_DISR.DEINT & m_DISR.DEINTMASK) != 0 || (m_DISR.TCINT & m_DISR.TCINTMASK) != 0 || + (m_DISR.BRKINT & m_DISR.BRKINTMASK) != 0 || (m_DICVR.CVRINT & m_DICVR.CVRINTMASK) != 0; - system.GetProcessorInterface().SetInterrupt(ProcessorInterface::INT_CAUSE_DI, set_mask); + m_system.GetProcessorInterface().SetInterrupt(ProcessorInterface::INT_CAUSE_DI, set_mask); // Required for Summoner: A Goddess Reborn - system.GetCoreTiming().ForceExceptionCheck(50); + m_system.GetCoreTiming().ForceExceptionCheck(50); } -static void GenerateDIInterrupt(DIInterruptType dvd_interrupt) +void DVDInterfaceManager::GenerateDIInterrupt(DIInterruptType dvd_interrupt) { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); switch (dvd_interrupt) { case DIInterruptType::DEINT: - state.DISR.DEINT = true; + m_DISR.DEINT = true; break; case DIInterruptType::TCINT: - state.DISR.TCINT = true; + m_DISR.TCINT = true; break; case DIInterruptType::BRKINT: - state.DISR.BRKINT = true; + m_DISR.BRKINT = true; break; case DIInterruptType::CVRINT: - state.DICVR.CVRINT = true; + m_DICVR.CVRINT = true; break; } UpdateInterrupts(); } -void SetInterruptEnabled(DIInterruptType interrupt, bool enabled) +void DVDInterfaceManager::SetInterruptEnabled(DIInterruptType interrupt, bool enabled) { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); switch (interrupt) { case DIInterruptType::DEINT: - state.DISR.DEINTMASK = enabled; + m_DISR.DEINTMASK = enabled; break; case DIInterruptType::TCINT: - state.DISR.TCINTMASK = enabled; + m_DISR.TCINTMASK = enabled; break; case DIInterruptType::BRKINT: - state.DISR.BRKINTMASK = enabled; + m_DISR.BRKINTMASK = enabled; break; case DIInterruptType::CVRINT: - state.DICVR.CVRINTMASK = enabled; + m_DICVR.CVRINTMASK = enabled; break; } } -void ClearInterrupt(DIInterruptType interrupt) +void DVDInterfaceManager::ClearInterrupt(DIInterruptType interrupt) { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); switch (interrupt) { case DIInterruptType::DEINT: - state.DISR.DEINT = false; + m_DISR.DEINT = false; break; case DIInterruptType::TCINT: - state.DISR.TCINT = false; + m_DISR.TCINT = false; break; case DIInterruptType::BRKINT: - state.DISR.BRKINT = false; + m_DISR.BRKINT = false; break; case DIInterruptType::CVRINT: - state.DICVR.CVRINT = false; + m_DICVR.CVRINT = false; break; } } @@ -809,28 +659,27 @@ void ClearInterrupt(DIInterruptType interrupt) // Checks the drive state to make sure a read-like command can be performed. // If false is returned, SetDriveError will have been called, and the caller // should issue a DEINT interrupt. -static bool CheckReadPreconditions() +bool DVDInterfaceManager::CheckReadPreconditions() { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); if (!IsDiscInside()) // Implies CoverOpened or NoMediumPresent { ERROR_LOG_FMT(DVDINTERFACE, "No disc inside."); SetDriveError(DriveError::MediumNotPresent); return false; } - if (state.drive_state == DriveState::DiscChangeDetected) + if (m_drive_state == DriveState::DiscChangeDetected) { ERROR_LOG_FMT(DVDINTERFACE, "Disc changed (motor stopped)."); SetDriveError(DriveError::MediumChanged); return false; } - if (state.drive_state == DriveState::MotorStopped) + if (m_drive_state == DriveState::MotorStopped) { ERROR_LOG_FMT(DVDINTERFACE, "Motor stopped."); SetDriveError(DriveError::MotorStopped); return false; } - if (state.drive_state == DriveState::DiscIdNotRead) + if (m_drive_state == DriveState::DiscIdNotRead) { ERROR_LOG_FMT(DVDINTERFACE, "Disc id not read."); SetDriveError(DriveError::NoDiscID); @@ -840,11 +689,10 @@ static bool CheckReadPreconditions() } // Iff false is returned, ScheduleEvent must be used to finish executing the command -static bool ExecuteReadCommand(u64 dvd_offset, u32 output_address, u32 dvd_length, - u32 output_length, const DiscIO::Partition& partition, - ReplyType reply_type, DIInterruptType* interrupt_type) +bool DVDInterfaceManager::ExecuteReadCommand(u64 dvd_offset, u32 output_address, u32 dvd_length, + u32 output_length, const DiscIO::Partition& partition, + ReplyType reply_type, DIInterruptType* interrupt_type) { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); if (!CheckReadPreconditions()) { // Disc read fails @@ -868,7 +716,7 @@ static bool ExecuteReadCommand(u64 dvd_offset, u32 output_address, u32 dvd_lengt // regular DVD but just before the end of a DVD-R, displaying "Error #001" and failing to boot // if the read succeeds, so it's critical that we set the correct error code for such reads. // See https://wiibrew.org/wiki//dev/di#0x8D_DVDLowUnencryptedRead for details on Error #001. - if (dvd_offset + dvd_length > state.disc_end_offset) + if (dvd_offset + dvd_length > m_disc_end_offset) { SetDriveError(DriveError::BlockOOB); *interrupt_type = DIInterruptType::DEINT; @@ -882,30 +730,27 @@ static bool ExecuteReadCommand(u64 dvd_offset, u32 output_address, u32 dvd_lengt // When the command has finished executing, callback_event_type // will be called using CoreTiming::ScheduleEvent, // with the userdata set to the interrupt type. -void ExecuteCommand(ReplyType reply_type) +void DVDInterfaceManager::ExecuteCommand(ReplyType reply_type) { - auto& system = Core::System::GetInstance(); - auto& state = system.GetDVDInterfaceState().GetData(); DIInterruptType interrupt_type = DIInterruptType::TCINT; bool command_handled_by_thread = false; // DVDLowRequestError needs access to the error code set by the previous command - if (static_cast(state.DICMDBUF[0] >> 24) != DICommand::RequestError) + if (static_cast(m_DICMDBUF[0] >> 24) != DICommand::RequestError) SetDriveError(DriveError::None); - switch (static_cast(state.DICMDBUF[0] >> 24)) + switch (static_cast(m_DICMDBUF[0] >> 24)) { // Used by both GC and Wii case DICommand::Inquiry: { // (shuffle2) Taken from my Wii - auto& memory = system.GetMemory(); - memory.Write_U32(0x00000002, state.DIMAR); // Revision level, device code - memory.Write_U32(0x20060526, state.DIMAR + 4); // Release date - memory.Write_U32(0x41000000, state.DIMAR + 8); // Version + auto& memory = m_system.GetMemory(); + memory.Write_U32(0x00000002, m_DIMAR); // Revision level, device code + memory.Write_U32(0x20060526, m_DIMAR + 4); // Release date + memory.Write_U32(0x41000000, m_DIMAR + 8); // Version - INFO_LOG_FMT(DVDINTERFACE, "DVDLowInquiry (Buffer {:#010x}, {:#x})", state.DIMAR, - state.DILENGTH); + INFO_LOG_FMT(DVDINTERFACE, "DVDLowInquiry (Buffer {:#010x}, {:#x})", m_DIMAR, m_DILENGTH); break; } // GC-only patched drive firmware command, used by libogc @@ -927,33 +772,33 @@ void ExecuteCommand(ReplyType reply_type) // DMA Read from Disc. Only used through direct access on GC; direct use is prohibited by // IOS (which uses it internally) case DICommand::Read: - switch (state.DICMDBUF[0] & 0xFF) + switch (m_DICMDBUF[0] & 0xFF) { case 0x00: // Read Sector { - const u64 dvd_offset = static_cast(state.DICMDBUF[1]) << 2; + const u64 dvd_offset = static_cast(m_DICMDBUF[1]) << 2; INFO_LOG_FMT( DVDINTERFACE, "Read: DVDOffset={:08x}, DMABuffer = {:08x}, SrcLength = {:08x}, DMALength = {:08x}", - dvd_offset, state.DIMAR, state.DICMDBUF[2], state.DILENGTH); + dvd_offset, m_DIMAR, m_DICMDBUF[2], m_DILENGTH); - if (state.drive_state == DriveState::ReadyNoReadsMade) + if (m_drive_state == DriveState::ReadyNoReadsMade) SetDriveState(DriveState::Ready); command_handled_by_thread = - ExecuteReadCommand(dvd_offset, state.DIMAR, state.DICMDBUF[2], state.DILENGTH, - DiscIO::PARTITION_NONE, reply_type, &interrupt_type); + ExecuteReadCommand(dvd_offset, m_DIMAR, m_DICMDBUF[2], m_DILENGTH, DiscIO::PARTITION_NONE, + reply_type, &interrupt_type); } break; case 0x40: // Read DiscID - INFO_LOG_FMT(DVDINTERFACE, "Read DiscID: buffer {:08x}", state.DIMAR); - if (state.drive_state == DriveState::DiscIdNotRead) + INFO_LOG_FMT(DVDINTERFACE, "Read DiscID: buffer {:08x}", m_DIMAR); + if (m_drive_state == DriveState::DiscIdNotRead) { SetDriveState(DriveState::ReadyNoReadsMade); } - else if (state.drive_state == DriveState::ReadyNoReadsMade) + else if (m_drive_state == DriveState::ReadyNoReadsMade) { // The first disc ID reading is required before DTK can be configured. // If the disc ID is read again (or any other read occurs), it no longer can @@ -961,13 +806,12 @@ void ExecuteCommand(ReplyType reply_type) SetDriveState(DriveState::Ready); } - command_handled_by_thread = - ExecuteReadCommand(0, state.DIMAR, 0x20, state.DILENGTH, DiscIO::PARTITION_NONE, - reply_type, &interrupt_type); + command_handled_by_thread = ExecuteReadCommand( + 0, m_DIMAR, 0x20, m_DILENGTH, DiscIO::PARTITION_NONE, reply_type, &interrupt_type); break; default: - ERROR_LOG_FMT(DVDINTERFACE, "Unknown read subcommand: {:08x}", state.DICMDBUF[0]); + ERROR_LOG_FMT(DVDINTERFACE, "Unknown read subcommand: {:08x}", m_DICMDBUF[0]); break; } break; @@ -976,12 +820,12 @@ void ExecuteCommand(ReplyType reply_type) case DICommand::Seek: // Currently unimplemented INFO_LOG_FMT(DVDINTERFACE, "Seek: offset={:09x} (ignoring)", - static_cast(state.DICMDBUF[1]) << 2); + static_cast(m_DICMDBUF[1]) << 2); break; // Wii-exclusive case DICommand::ReadDVDMetadata: - switch ((state.DICMDBUF[0] >> 16) & 0xFF) + switch ((m_DICMDBUF[0] >> 16) & 0xFF) { case 0: ERROR_LOG_FMT(DVDINTERFACE, "DVDLowReadDvdPhysical"); @@ -993,7 +837,7 @@ void ExecuteCommand(ReplyType reply_type) ERROR_LOG_FMT(DVDINTERFACE, "DVDLowReadDvdDiscKey"); break; default: - ERROR_LOG_FMT(DVDINTERFACE, "Unknown 0xAD subcommand in {:08x}", state.DICMDBUF[0]); + ERROR_LOG_FMT(DVDINTERFACE, "Unknown 0xAD subcommand in {:08x}", m_DICMDBUF[0]); break; } SetDriveError(DriveError::InvalidCommand); @@ -1034,11 +878,11 @@ void ExecuteCommand(ReplyType reply_type) // Most (all?) other games have 0x34 0's at the start of the BCA, but don't actually // read it. NSMBW doesn't care about the other 12 bytes (which contain manufacturing data?) - auto& memory = system.GetMemory(); + auto& memory = m_system.GetMemory(); // TODO: Read the .bca file that cleanrip generates, if it exists // memory.CopyToEmu(output_address, bca_data, 0x40); - memory.Memset(state.DIMAR, 0, 0x40); - memory.Write_U8(1, state.DIMAR + 0x33); + memory.Memset(m_DIMAR, 0, 0x40); + memory.Write_U8(1, m_DIMAR + 0x33); break; } // Wii-exclusive @@ -1073,14 +917,14 @@ void ExecuteCommand(ReplyType reply_type) case DICommand::RequestError: { u32 drive_state; - if (state.drive_state == DriveState::Ready) + if (m_drive_state == DriveState::Ready) drive_state = 0; else - drive_state = static_cast(state.drive_state) - 1; + drive_state = static_cast(m_drive_state) - 1; - const u32 result = (drive_state << 24) | static_cast(state.error_code); + const u32 result = (drive_state << 24) | static_cast(m_error_code); INFO_LOG_FMT(DVDINTERFACE, "Requesting error... ({:#010x})", result); - state.DIIMMBUF = result; + m_DIIMMBUF = result; SetDriveError(DriveError::None); break; } @@ -1093,60 +937,60 @@ void ExecuteCommand(ReplyType reply_type) { if (!CheckReadPreconditions()) { - ERROR_LOG_FMT(DVDINTERFACE, "Cannot play audio (command {:08x})", state.DICMDBUF[0]); + ERROR_LOG_FMT(DVDINTERFACE, "Cannot play audio (command {:08x})", m_DICMDBUF[0]); interrupt_type = DIInterruptType::DEINT; break; } - if (!state.enable_dtk) + if (!m_enable_dtk) { ERROR_LOG_FMT( DVDINTERFACE, "Attempted to change playing audio while audio is disabled! ({:08x} {:08x} {:08x})", - state.DICMDBUF[0], state.DICMDBUF[1], state.DICMDBUF[2]); + m_DICMDBUF[0], m_DICMDBUF[1], m_DICMDBUF[2]); SetDriveError(DriveError::NoAudioBuf); interrupt_type = DIInterruptType::DEINT; break; } - if (state.drive_state == DriveState::ReadyNoReadsMade) + if (m_drive_state == DriveState::ReadyNoReadsMade) SetDriveState(DriveState::Ready); - switch ((state.DICMDBUF[0] >> 16) & 0xFF) + switch ((m_DICMDBUF[0] >> 16) & 0xFF) { case 0x00: { - const u64 offset = static_cast(state.DICMDBUF[1]) << 2; - const u32 length = state.DICMDBUF[2]; + const u64 offset = static_cast(m_DICMDBUF[1]) << 2; + const u32 length = m_DICMDBUF[2]; INFO_LOG_FMT(DVDINTERFACE, "(Audio) Start stream: offset: {:08x} length: {:08x}", offset, length); if ((offset == 0) && (length == 0)) { - state.stop_at_track_end = true; + m_stop_at_track_end = true; } - else if (!state.stop_at_track_end) + else if (!m_stop_at_track_end) { - state.next_start = offset; - state.next_length = length; - if (!state.stream) + m_next_start = offset; + m_next_length = length; + if (!m_stream) { - state.current_start = state.next_start; - state.current_length = state.next_length; - state.audio_position = state.current_start; - state.adpcm_decoder.ResetFilter(); - state.stream = true; + m_current_start = m_next_start; + m_current_length = m_next_length; + m_audio_position = m_current_start; + m_adpcm_decoder.ResetFilter(); + m_stream = true; } } break; } case 0x01: INFO_LOG_FMT(DVDINTERFACE, "(Audio) Stop stream"); - state.stop_at_track_end = false; - state.stream = false; + m_stop_at_track_end = false; + m_stream = false; break; default: - ERROR_LOG_FMT(DVDINTERFACE, "Invalid audio command! ({:08x} {:08x} {:08x})", - state.DICMDBUF[0], state.DICMDBUF[1], state.DICMDBUF[2]); + ERROR_LOG_FMT(DVDINTERFACE, "Invalid audio command! ({:08x} {:08x} {:08x})", m_DICMDBUF[0], + m_DICMDBUF[1], m_DICMDBUF[2]); SetDriveError(DriveError::InvalidAudioCommand); interrupt_type = DIInterruptType::DEINT; break; @@ -1164,7 +1008,7 @@ void ExecuteCommand(ReplyType reply_type) break; } - if (!state.enable_dtk) + if (!m_enable_dtk) { ERROR_LOG_FMT(DVDINTERFACE, "Attempted to request audio status while audio is disabled!"); SetDriveError(DriveError::NoAudioBuf); @@ -1172,36 +1016,36 @@ void ExecuteCommand(ReplyType reply_type) break; } - switch (state.DICMDBUF[0] >> 16 & 0xFF) + switch (m_DICMDBUF[0] >> 16 & 0xFF) { case 0x00: // Returns streaming status INFO_LOG_FMT(DVDINTERFACE, "(Audio): Stream Status: Request Audio status " "AudioPos:{:08x}/{:08x} " "CurrentStart:{:08x} CurrentLength:{:08x}", - state.audio_position, state.current_start + state.current_length, - state.current_start, state.current_length); - state.DIIMMBUF = (state.stream ? 1 : 0); + m_audio_position, m_current_start + m_current_length, m_current_start, + m_current_length); + m_DIIMMBUF = (m_stream ? 1 : 0); break; case 0x01: // Returns the current offset INFO_LOG_FMT(DVDINTERFACE, "(Audio): Stream Status: Request Audio status AudioPos:{:08x}", - state.audio_position); - state.DIIMMBUF = static_cast((state.audio_position & 0xffffffffffff8000ull) >> 2); + m_audio_position); + m_DIIMMBUF = static_cast((m_audio_position & 0xffffffffffff8000ull) >> 2); break; case 0x02: // Returns the start offset INFO_LOG_FMT(DVDINTERFACE, "(Audio): Stream Status: Request Audio status CurrentStart:{:08x}", - state.current_start); - state.DIIMMBUF = static_cast(state.current_start >> 2); + m_current_start); + m_DIIMMBUF = static_cast(m_current_start >> 2); break; case 0x03: // Returns the total length INFO_LOG_FMT(DVDINTERFACE, "(Audio): Stream Status: Request Audio status CurrentLength:{:08x}", - state.current_length); - state.DIIMMBUF = state.current_length; + m_current_length); + m_DIIMMBUF = m_current_length; break; default: ERROR_LOG_FMT(DVDINTERFACE, "Invalid audio status command! ({:08x} {:08x} {:08x})", - state.DICMDBUF[0], state.DICMDBUF[1], state.DICMDBUF[2]); + m_DICMDBUF[0], m_DICMDBUF[1], m_DICMDBUF[2]); SetDriveError(DriveError::InvalidAudioCommand); interrupt_type = DIInterruptType::DEINT; break; @@ -1212,13 +1056,12 @@ void ExecuteCommand(ReplyType reply_type) // Used by both GC and Wii case DICommand::StopMotor: { - const bool eject = (state.DICMDBUF[0] & (1 << 17)); - const bool kill = (state.DICMDBUF[0] & (1 << 20)); + const bool eject = (m_DICMDBUF[0] & (1 << 17)); + const bool kill = (m_DICMDBUF[0] & (1 << 20)); INFO_LOG_FMT(DVDINTERFACE, "DVDLowStopMotor{}{}", eject ? " eject" : "", kill ? " kill!" : ""); - if (state.drive_state == DriveState::Ready || - state.drive_state == DriveState::ReadyNoReadsMade || - state.drive_state == DriveState::DiscIdNotRead) + if (m_drive_state == DriveState::Ready || m_drive_state == DriveState::ReadyNoReadsMade || + m_drive_state == DriveState::DiscIdNotRead) { SetDriveState(DriveState::MotorStopped); } @@ -1226,10 +1069,10 @@ void ExecuteCommand(ReplyType reply_type) const bool force_eject = eject && !kill; if (Config::Get(Config::MAIN_AUTO_DISC_CHANGE) && !Movie::IsPlayingInput() && - DVDThread::IsInsertedDiscRunning() && !state.auto_disc_change_paths.empty()) + DVDThread::IsInsertedDiscRunning() && !m_auto_disc_change_paths.empty()) { - system.GetCoreTiming().ScheduleEvent(force_eject ? 0 : SystemTimers::GetTicksPerSecond() / 2, - state.auto_change_disc); + m_system.GetCoreTiming().ScheduleEvent( + force_eject ? 0 : SystemTimers::GetTicksPerSecond() / 2, m_auto_change_disc); OSD::AddMessage("Changing discs automatically...", OSD::Duration::NORMAL); } else if (force_eject) @@ -1255,7 +1098,7 @@ void ExecuteCommand(ReplyType reply_type) break; } - if (state.drive_state == DriveState::Ready) + if (m_drive_state == DriveState::Ready) { ERROR_LOG_FMT(DVDINTERFACE, "Attempted to change DTK configuration after a read has been made!"); @@ -1266,7 +1109,7 @@ void ExecuteCommand(ReplyType reply_type) // Note that this can be called multiple times, as long as the drive is in the ReadyNoReadsMade // state. Calling it does not exit that state. - AudioBufferConfig((state.DICMDBUF[0] >> 16) & 1, state.DICMDBUF[0] & 0xf); + AudioBufferConfig((m_DICMDBUF[0] >> 16) & 1, m_DICMDBUF[0] & 0xf); break; // GC-only patched drive firmware command, used by libogc @@ -1281,7 +1124,7 @@ void ExecuteCommand(ReplyType reply_type) // This will appear as unknown commands, unless the check is re-instated to catch such data. // Can only be used through direct access and only after unlocked. case DICommand::Debug: - ERROR_LOG_FMT(DVDINTERFACE, "Unsupported DVD Drive debug command {:#010x}", state.DICMDBUF[0]); + ERROR_LOG_FMT(DVDINTERFACE, "Unsupported DVD Drive debug command {:#010x}", m_DICMDBUF[0]); SetDriveError(DriveError::InvalidCommand); interrupt_type = DIInterruptType::DEINT; break; @@ -1291,13 +1134,12 @@ void ExecuteCommand(ReplyType reply_type) // Can only be used through direct access. The unlock command doesn't seem to work on the Wii. case DICommand::DebugUnlock: { - if (state.DICMDBUF[0] == 0xFF014D41 && state.DICMDBUF[1] == 0x54534849 && - state.DICMDBUF[2] == 0x54410200) + if (m_DICMDBUF[0] == 0xFF014D41 && m_DICMDBUF[1] == 0x54534849 && m_DICMDBUF[2] == 0x54410200) { INFO_LOG_FMT(DVDINTERFACE, "Unlock test 1 passed"); } - else if (state.DICMDBUF[0] == 0xFF004456 && state.DICMDBUF[1] == 0x442D4741 && - state.DICMDBUF[2] == 0x4D450300) + else if (m_DICMDBUF[0] == 0xFF004456 && m_DICMDBUF[1] == 0x442D4741 && + m_DICMDBUF[2] == 0x4D450300) { INFO_LOG_FMT(DVDINTERFACE, "Unlock test 2 passed"); } @@ -1309,9 +1151,9 @@ void ExecuteCommand(ReplyType reply_type) break; default: - ERROR_LOG_FMT(DVDINTERFACE, "Unknown command {:#010x} (Buffer {:#010x}, {:#x})", - state.DICMDBUF[0], state.DIMAR, state.DILENGTH); - PanicAlertFmtT("Unknown DVD command {0:08x} - fatal error", state.DICMDBUF[0]); + ERROR_LOG_FMT(DVDINTERFACE, "Unknown command {:#010x} (Buffer {:#010x}, {:#x})", m_DICMDBUF[0], + m_DIMAR, m_DILENGTH); + PanicAlertFmtT("Unknown DVD command {0:08x} - fatal error", m_DICMDBUF[0]); SetDriveError(DriveError::InvalidCommand); interrupt_type = DIInterruptType::DEINT; break; @@ -1320,21 +1162,19 @@ void ExecuteCommand(ReplyType reply_type) if (!command_handled_by_thread) { // TODO: Needs testing to determine if MINIMUM_COMMAND_LATENCY_US is accurate for this - system.GetCoreTiming().ScheduleEvent( + m_system.GetCoreTiming().ScheduleEvent( MINIMUM_COMMAND_LATENCY_US * (SystemTimers::GetTicksPerSecond() / 1000000), - state.finish_executing_command, - PackFinishExecutingCommandUserdata(reply_type, interrupt_type)); + m_finish_executing_command, PackFinishExecutingCommandUserdata(reply_type, interrupt_type)); } } -void PerformDecryptingRead(u32 position, u32 length, u32 output_address, - const DiscIO::Partition& partition, ReplyType reply_type) +void DVDInterfaceManager::PerformDecryptingRead(u32 position, u32 length, u32 output_address, + const DiscIO::Partition& partition, + ReplyType reply_type) { - auto& system = Core::System::GetInstance(); - auto& state = system.GetDVDInterfaceState().GetData(); DIInterruptType interrupt_type = DIInterruptType::TCINT; - if (state.drive_state == DriveState::ReadyNoReadsMade) + if (m_drive_state == DriveState::ReadyNoReadsMade) SetDriveState(DriveState::Ready); const bool command_handled_by_thread = @@ -1344,39 +1184,34 @@ void PerformDecryptingRead(u32 position, u32 length, u32 output_address, if (!command_handled_by_thread) { // TODO: Needs testing to determine if MINIMUM_COMMAND_LATENCY_US is accurate for this - system.GetCoreTiming().ScheduleEvent( + m_system.GetCoreTiming().ScheduleEvent( MINIMUM_COMMAND_LATENCY_US * (SystemTimers::GetTicksPerSecond() / 1000000), - state.finish_executing_command, - PackFinishExecutingCommandUserdata(reply_type, interrupt_type)); + m_finish_executing_command, PackFinishExecutingCommandUserdata(reply_type, interrupt_type)); } } -void ForceOutOfBoundsRead(ReplyType reply_type) +void DVDInterfaceManager::ForceOutOfBoundsRead(ReplyType reply_type) { - auto& system = Core::System::GetInstance(); - auto& state = system.GetDVDInterfaceState().GetData(); INFO_LOG_FMT(DVDINTERFACE, "Forcing an out-of-bounds disc read."); - if (state.drive_state == DriveState::ReadyNoReadsMade) + if (m_drive_state == DriveState::ReadyNoReadsMade) SetDriveState(DriveState::Ready); SetDriveError(DriveError::BlockOOB); // TODO: Needs testing to determine if MINIMUM_COMMAND_LATENCY_US is accurate for this const DIInterruptType interrupt_type = DIInterruptType::DEINT; - system.GetCoreTiming().ScheduleEvent( + m_system.GetCoreTiming().ScheduleEvent( MINIMUM_COMMAND_LATENCY_US * (SystemTimers::GetTicksPerSecond() / 1000000), - state.finish_executing_command, - PackFinishExecutingCommandUserdata(reply_type, interrupt_type)); + m_finish_executing_command, PackFinishExecutingCommandUserdata(reply_type, interrupt_type)); } -void AudioBufferConfig(bool enable_dtk, u8 dtk_buffer_length) +void DVDInterfaceManager::AudioBufferConfig(bool enable_dtk, u8 dtk_buffer_length) { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); - state.enable_dtk = enable_dtk; - state.dtk_buffer_length = dtk_buffer_length; - if (state.enable_dtk) - INFO_LOG_FMT(DVDINTERFACE, "DTK enabled: buffer size {}", state.dtk_buffer_length); + m_enable_dtk = enable_dtk; + m_dtk_buffer_length = dtk_buffer_length; + if (m_enable_dtk) + INFO_LOG_FMT(DVDINTERFACE, "DTK enabled: buffer size {}", m_dtk_buffer_length); else INFO_LOG_FMT(DVDINTERFACE, "DTK disabled"); } @@ -1386,30 +1221,28 @@ static u64 PackFinishExecutingCommandUserdata(ReplyType reply_type, DIInterruptT return (static_cast(reply_type) << 32) + static_cast(interrupt_type); } -void FinishExecutingCommandCallback(Core::System& system, u64 userdata, s64 cycles_late) +void DVDInterfaceManager::FinishExecutingCommandCallback(Core::System& system, u64 userdata, + s64 cycles_late) { ReplyType reply_type = static_cast(userdata >> 32); DIInterruptType interrupt_type = static_cast(userdata & 0xFFFFFFFF); - FinishExecutingCommand(reply_type, interrupt_type, cycles_late); + system.GetDVDInterface().FinishExecutingCommand(reply_type, interrupt_type, cycles_late); } -void SetDriveState(DriveState state) +void DVDInterfaceManager::SetDriveState(DriveState state) { - auto& dvd_interface_state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); - dvd_interface_state.drive_state = state; + m_drive_state = state; } -void SetDriveError(DriveError error) +void DVDInterfaceManager::SetDriveError(DriveError error) { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); - state.error_code = error; + m_error_code = error; } -void FinishExecutingCommand(ReplyType reply_type, DIInterruptType interrupt_type, s64 cycles_late, - const std::vector& data) +void DVDInterfaceManager::FinishExecutingCommand(ReplyType reply_type, + DIInterruptType interrupt_type, s64 cycles_late, + const std::vector& data) { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); - // The data parameter contains the requested data iff this was called from DVDThread, and is // empty otherwise. DVDThread is the only source of ReplyType::NoReply and ReplyType::DTK. @@ -1417,12 +1250,12 @@ void FinishExecutingCommand(ReplyType reply_type, DIInterruptType interrupt_type if (reply_type == ReplyType::NoReply) transfer_size = static_cast(data.size()); else if (reply_type == ReplyType::Interrupt || reply_type == ReplyType::IOS) - transfer_size = state.DILENGTH; + transfer_size = m_DILENGTH; if (interrupt_type == DIInterruptType::TCINT) { - state.DIMAR += transfer_size; - state.DILENGTH -= transfer_size; + m_DIMAR += transfer_size; + m_DILENGTH -= transfer_size; } switch (reply_type) @@ -1434,9 +1267,9 @@ void FinishExecutingCommand(ReplyType reply_type, DIInterruptType interrupt_type case ReplyType::Interrupt: { - if (state.DICR.TSTART) + if (m_DICR.TSTART) { - state.DICR.TSTART = 0; + m_DICR.TSTART = 0; GenerateDIInterrupt(interrupt_type); } break; @@ -1458,13 +1291,9 @@ void FinishExecutingCommand(ReplyType reply_type, DIInterruptType interrupt_type // Determines from a given read request how much of the request is buffered, // and how much is required to be read from disc. -static void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& partition, - u32 output_address, ReplyType reply_type) +void DVDInterfaceManager::ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& partition, + u32 output_address, ReplyType reply_type) { - auto& system = Core::System::GetInstance(); - auto& core_timing = system.GetCoreTiming(); - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); - // The drive continues to read 1 MiB beyond the last read position when idle. // If a future read falls within this window, part of the read may be returned // from the buffer. Data can be transferred from the buffer at up to 32 MiB/s. @@ -1474,6 +1303,7 @@ static void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& parti // faster than on real hardware, and if there's too much latency in the wrong // places, the video before the save-file select screen lags. + auto& core_timing = m_system.GetCoreTiming(); const u64 current_time = core_timing.GetTicks(); const u32 ticks_per_second = SystemTimers::GetTicksPerSecond(); const bool wii_disc = DVDThread::GetDiscType() == DiscIO::Platform::WiiDisc; @@ -1506,34 +1336,33 @@ static void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& parti } else { - if (state.read_buffer_start_time == state.read_buffer_end_time) + if (m_read_buffer_start_time == m_read_buffer_end_time) { // No buffer buffer_start = buffer_end = head_position = 0; } else { - buffer_start = state.read_buffer_end_offset > STREAMING_BUFFER_SIZE ? - state.read_buffer_end_offset - STREAMING_BUFFER_SIZE : + buffer_start = m_read_buffer_end_offset > STREAMING_BUFFER_SIZE ? + m_read_buffer_end_offset - STREAMING_BUFFER_SIZE : 0; DEBUG_LOG_FMT(DVDINTERFACE, "Buffer: now={:#x} start time={:#x} end time={:#x}", current_time, - state.read_buffer_start_time, state.read_buffer_end_time); + m_read_buffer_start_time, m_read_buffer_end_time); - if (current_time >= state.read_buffer_end_time) + if (current_time >= m_read_buffer_end_time) { // Buffer is fully read - buffer_end = state.read_buffer_end_offset; + buffer_end = m_read_buffer_end_offset; } else { // The amount of data the buffer contains *right now*, rounded to a DVD ECC block. - buffer_end = - state.read_buffer_start_offset + - Common::AlignDown((current_time - state.read_buffer_start_time) * - (state.read_buffer_end_offset - state.read_buffer_start_offset) / - (state.read_buffer_end_time - state.read_buffer_start_time), - DVD_ECC_BLOCK_SIZE); + buffer_end = m_read_buffer_start_offset + + Common::AlignDown((current_time - m_read_buffer_start_time) * + (m_read_buffer_end_offset - m_read_buffer_start_offset) / + (m_read_buffer_end_time - m_read_buffer_start_time), + DVD_ECC_BLOCK_SIZE); } head_position = buffer_end; @@ -1652,31 +1481,30 @@ static void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& parti if (last_block >= buffer_end) { // Full buffer read - state.read_buffer_start_offset = last_block; + m_read_buffer_start_offset = last_block; } else { // Partial buffer read - state.read_buffer_start_offset = buffer_end; + m_read_buffer_start_offset = buffer_end; } - state.read_buffer_end_offset = last_block + STREAMING_BUFFER_SIZE - BUFFER_BACKWARD_SEEK_LIMIT; + m_read_buffer_end_offset = last_block + STREAMING_BUFFER_SIZE - BUFFER_BACKWARD_SEEK_LIMIT; if (seek) { // If we seek, the block preceding the first accessed block never gets read into the buffer - state.read_buffer_end_offset = - std::max(state.read_buffer_end_offset, first_block + STREAMING_BUFFER_SIZE); + m_read_buffer_end_offset = + std::max(m_read_buffer_end_offset, first_block + STREAMING_BUFFER_SIZE); } // Assume the buffer starts prefetching new blocks right after the end of the last operation - state.read_buffer_start_time = current_time + ticks_until_completion; - state.read_buffer_end_time = - state.read_buffer_start_time + + m_read_buffer_start_time = current_time + ticks_until_completion; + m_read_buffer_end_time = + m_read_buffer_start_time + static_cast(ticks_per_second * - DVDMath::CalculateRawDiscReadTime(state.read_buffer_start_offset, - state.read_buffer_end_offset - - state.read_buffer_start_offset, - wii_disc)); + DVDMath::CalculateRawDiscReadTime( + m_read_buffer_start_offset, + m_read_buffer_end_offset - m_read_buffer_start_offset, wii_disc)); } DEBUG_LOG_FMT(DVDINTERFACE, diff --git a/Source/Core/Core/HW/DVD/DVDInterface.h b/Source/Core/Core/HW/DVD/DVDInterface.h index ef619f0f65..e4a3f29506 100644 --- a/Source/Core/Core/HW/DVD/DVDInterface.h +++ b/Source/Core/Core/HW/DVD/DVDInterface.h @@ -3,14 +3,26 @@ #pragma once +#include #include #include #include #include +#include "Common/BitField.h" #include "Common/CommonTypes.h" +#include "Core/HW/StreamADPCM.h" + class PointerWrap; +namespace Core +{ +class System; +} +namespace CoreTiming +{ +struct EventType; +} namespace DiscIO { class VolumeDisc; @@ -23,23 +35,6 @@ class Mapping; namespace DVDInterface { -class DVDInterfaceState -{ -public: - DVDInterfaceState(); - DVDInterfaceState(const DVDInterfaceState&) = delete; - DVDInterfaceState(DVDInterfaceState&&) = delete; - DVDInterfaceState& operator=(const DVDInterfaceState&) = delete; - DVDInterfaceState& operator=(DVDInterfaceState&&) = delete; - ~DVDInterfaceState(); - - struct Data; - Data& GetData() { return *m_data; } - -private: - std::unique_ptr m_data; -}; - enum class DICommand : u8 { Inquiry = 0x12, @@ -125,48 +120,185 @@ enum class EjectCause Software, }; -void Init(); -void ResetDrive(bool spinup); -void Shutdown(); -void DoState(PointerWrap& p); +class DVDInterfaceManager +{ +public: + explicit DVDInterfaceManager(Core::System& system); + DVDInterfaceManager(const DVDInterfaceManager&) = delete; + DVDInterfaceManager(DVDInterfaceManager&&) = delete; + DVDInterfaceManager& operator=(const DVDInterfaceManager&) = delete; + DVDInterfaceManager& operator=(DVDInterfaceManager&&) = delete; + ~DVDInterfaceManager(); -void RegisterMMIO(MMIO::Mapping* mmio, u32 base, bool is_wii); + void Init(); + void ResetDrive(bool spinup); + void Shutdown(); + void DoState(PointerWrap& p); -void SetDisc(std::unique_ptr disc, - std::optional> auto_disc_change_paths); -bool IsDiscInside(); -void EjectDisc(EjectCause cause); // Must only be called on the CPU thread -void ChangeDisc(const std::vector& paths); // Must only be called on the CPU thread -void ChangeDisc(const std::string& new_path); // Must only be called on the CPU thread -bool AutoChangeDisc(); // Must only be called on the CPU thread + void RegisterMMIO(MMIO::Mapping* mmio, u32 base, bool is_wii); -// This function returns true and calls SConfig::SetRunningGameMetadata(Volume&, Partition&) -// if both of the following conditions are true: -// - A disc is inserted -// - The title_id argument doesn't contain a value, or its value matches the disc's title ID -bool UpdateRunningGameMetadata(std::optional title_id = {}); + void SetDisc(std::unique_ptr disc, + std::optional> auto_disc_change_paths); + bool IsDiscInside() const; + void EjectDisc(EjectCause cause); // Must only be called on the CPU thread + void ChangeDisc(const std::vector& paths); // Must only be called on the CPU thread + void ChangeDisc(const std::string& new_path); // Must only be called on the CPU thread + bool AutoChangeDisc(); // Must only be called on the CPU thread -// Direct access to DI for IOS HLE (simpler to implement than how real IOS accesses DI, -// and lets us skip encrypting/decrypting in some cases) -void ExecuteCommand(ReplyType reply_type); -void PerformDecryptingRead(u32 position, u32 length, u32 output_address, - const DiscIO::Partition& partition, ReplyType reply_type); + // This function returns true and calls SConfig::SetRunningGameMetadata(Volume&, Partition&) + // if both of the following conditions are true: + // - A disc is inserted + // - The title_id argument doesn't contain a value, or its value matches the disc's title ID + bool UpdateRunningGameMetadata(std::optional title_id = {}); -// For circumventing Error #001 in DirectoryBlobs, which may have data in the offsets being checked. -void ForceOutOfBoundsRead(ReplyType reply_type); + // Direct access to DI for IOS HLE (simpler to implement than how real IOS accesses DI, + // and lets us skip encrypting/decrypting in some cases) + void ExecuteCommand(ReplyType reply_type); + void PerformDecryptingRead(u32 position, u32 length, u32 output_address, + const DiscIO::Partition& partition, ReplyType reply_type); -// Exposed for use by emulated BS2; does not perform any checks on drive state -void AudioBufferConfig(bool enable_dtk, u8 dtk_buffer_length); + // For circumventing Error #001 in DirectoryBlobs, which may have data in the offsets being + // checked. + void ForceOutOfBoundsRead(ReplyType reply_type); -void SetDriveState(DriveState state); -void SetDriveError(DriveError error); + // Exposed for use by emulated BS2; does not perform any checks on drive state + void AudioBufferConfig(bool enable_dtk, u8 dtk_buffer_length); -// Used by DVDThread -void FinishExecutingCommand(ReplyType reply_type, DIInterruptType interrupt_type, s64 cycles_late, - const std::vector& data = std::vector()); + void SetDriveState(DriveState state); + void SetDriveError(DriveError error); -// Used by IOS HLE -void SetInterruptEnabled(DIInterruptType interrupt, bool enabled); -void ClearInterrupt(DIInterruptType interrupt); + // Used by DVDThread + void FinishExecutingCommand(ReplyType reply_type, DIInterruptType interrupt_type, s64 cycles_late, + const std::vector& data = std::vector()); + // Used by IOS HLE + void SetInterruptEnabled(DIInterruptType interrupt, bool enabled); + void ClearInterrupt(DIInterruptType interrupt); + +private: + void DTKStreamingCallback(DIInterruptType interrupt_type, const std::vector& audio_data, + s64 cycles_late); + size_t ProcessDTKSamples(std::vector* temp_pcm, const std::vector& audio_data); + u32 AdvanceDTK(u32 maximum_samples, u32* samples_to_process); + + void SetLidOpen(); + void UpdateInterrupts(); + void GenerateDIInterrupt(DIInterruptType dvd_interrupt); + + bool CheckReadPreconditions(); + bool ExecuteReadCommand(u64 dvd_offset, u32 output_address, u32 dvd_length, u32 output_length, + const DiscIO::Partition& partition, ReplyType reply_type, + DIInterruptType* interrupt_type); + void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& partition, u32 output_address, + ReplyType reply_type); + + static void AutoChangeDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate); + static void EjectDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate); + static void InsertDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate); + static void FinishExecutingCommandCallback(Core::System& system, u64 userdata, s64 cycles_late); + + // DI Status Register + union UDISR + { + u32 Hex = 0; + + BitField<0, 1, u32> BREAK; // Stop the Device + Interrupt + BitField<1, 1, u32> DEINTMASK; // Access Device Error Int Mask + BitField<2, 1, u32> DEINT; // Access Device Error Int + BitField<3, 1, u32> TCINTMASK; // Transfer Complete Int Mask + BitField<4, 1, u32> TCINT; // Transfer Complete Int + BitField<5, 1, u32> BRKINTMASK; + BitField<6, 1, u32> BRKINT; // w 1: clear brkint + BitField<7, 25, u32> reserved; + + UDISR() = default; + explicit UDISR(u32 hex) : Hex{hex} {} + }; + + // DI Cover Register + union UDICVR + { + u32 Hex = 0; + + BitField<0, 1, u32> CVR; // 0: Cover closed 1: Cover open + BitField<1, 1, u32> CVRINTMASK; // 1: Interrupt enabled + BitField<2, 1, u32> CVRINT; // r 1: Interrupt requested w 1: Interrupt clear + BitField<3, 29, u32> reserved; + + UDICVR() = default; + explicit UDICVR(u32 hex) : Hex{hex} {} + }; + + // DI DMA Control Register + union UDICR + { + u32 Hex = 0; + + BitField<0, 1, u32> TSTART; // w:1 start r:0 ready + BitField<1, 1, u32> DMA; // 1: DMA Mode + // 0: Immediate Mode (can only do Access Register Command) + BitField<2, 1, u32> RW; // 0: Read Command (DVD to Memory) 1: Write Command (Memory to DVD) + BitField<3, 29, u32> reserved; + }; + + // DI Config Register + union UDICFG + { + u32 Hex = 0; + + BitField<0, 8, u32> CONFIG; + BitField<8, 24, u32> reserved; + + UDICFG() = default; + explicit UDICFG(u32 hex) : Hex{hex} {} + }; + + // Hardware registers + UDISR m_DISR; + UDICVR m_DICVR; + std::array m_DICMDBUF{}; + u32 m_DIMAR = 0; + u32 m_DILENGTH = 0; + UDICR m_DICR; + u32 m_DIIMMBUF = 0; + UDICFG m_DICFG; + + StreamADPCM::ADPCMDecoder m_adpcm_decoder; + + // DTK + bool m_stream = false; + bool m_stop_at_track_end = false; + u64 m_audio_position = 0; + u64 m_current_start = 0; + u32 m_current_length = 0; + u64 m_next_start = 0; + u32 m_next_length = 0; + u32 m_pending_samples = 0; + bool m_enable_dtk = false; + u8 m_dtk_buffer_length = 0; // TODO: figure out how this affects the regular buffer + + // Disc drive state + DriveState m_drive_state = DriveState::Ready; + DriveError m_error_code = DriveError::None; + u64 m_disc_end_offset = 0; + + // Disc drive timing + u64 m_read_buffer_start_time = 0; + u64 m_read_buffer_end_time = 0; + u64 m_read_buffer_start_offset = 0; + u64 m_read_buffer_end_offset = 0; + + // Disc changing + std::string m_disc_path_to_insert; + std::vector m_auto_disc_change_paths; + size_t m_auto_disc_change_index = 0; + + // Events + CoreTiming::EventType* m_finish_executing_command = nullptr; + CoreTiming::EventType* m_auto_change_disc = nullptr; + CoreTiming::EventType* m_eject_disc = nullptr; + CoreTiming::EventType* m_insert_disc = nullptr; + + Core::System& m_system; +}; } // namespace DVDInterface diff --git a/Source/Core/Core/HW/DVD/DVDThread.cpp b/Source/Core/Core/HW/DVD/DVDThread.cpp index 08f35c26bd..3041af262c 100644 --- a/Source/Core/Core/HW/DVD/DVDThread.cpp +++ b/Source/Core/Core/HW/DVD/DVDThread.cpp @@ -379,13 +379,14 @@ static void FinishRead(Core::System& system, u64 id, s64 cycles_late) (system.GetCoreTiming().GetTicks() - request.time_started_ticks) / (SystemTimers::GetTicksPerSecond() / 1000000)); + auto& dvd_interface = system.GetDVDInterface(); DVDInterface::DIInterruptType interrupt; if (buffer.size() != request.length) { PanicAlertFmtT("The disc could not be read (at {0:#x} - {1:#x}).", request.dvd_offset, request.dvd_offset + request.length); - DVDInterface::SetDriveError(DVDInterface::DriveError::ReadError); + dvd_interface.SetDriveError(DVDInterface::DriveError::ReadError); interrupt = DVDInterface::DIInterruptType::DEINT; } else @@ -400,7 +401,7 @@ static void FinishRead(Core::System& system, u64 id, s64 cycles_late) } // Notify the emulated software that the command has been executed - DVDInterface::FinishExecutingCommand(request.reply_type, interrupt, cycles_late, buffer); + dvd_interface.FinishExecutingCommand(request.reply_type, interrupt, cycles_late, buffer); } static void DVDThread() diff --git a/Source/Core/Core/HW/HW.cpp b/Source/Core/Core/HW/HW.cpp index 00e899a7b0..f8eedc7eb1 100644 --- a/Source/Core/Core/HW/HW.cpp +++ b/Source/Core/Core/HW/HW.cpp @@ -50,7 +50,7 @@ void Init(const Sram* override_sram) AddressSpace::Init(); MemoryInterface::Init(); system.GetDSP().Init(Config::Get(Config::MAIN_DSP_HLE)); - DVDInterface::Init(); + system.GetDVDInterface().Init(); system.GetGPFifo().Init(); system.GetCPU().Init(Config::Get(Config::MAIN_CPU_CORE)); SystemTimers::Init(); @@ -72,7 +72,7 @@ void Shutdown() SystemTimers::Shutdown(); system.GetCPU().Shutdown(); - DVDInterface::Shutdown(); + system.GetDVDInterface().Shutdown(); system.GetDSP().Shutdown(); MemoryInterface::Shutdown(); AddressSpace::Shutdown(); @@ -101,7 +101,7 @@ void DoState(PointerWrap& p) p.DoMarker("ProcessorInterface"); system.GetDSP().DoState(p); p.DoMarker("DSP"); - DVDInterface::DoState(p); + system.GetDVDInterface().DoState(p); p.DoMarker("DVDInterface"); system.GetGPFifo().DoState(p); p.DoMarker("GPFifo"); diff --git a/Source/Core/Core/HW/Memmap.cpp b/Source/Core/Core/HW/Memmap.cpp index a97f775ef0..50133c76cd 100644 --- a/Source/Core/Core/HW/Memmap.cpp +++ b/Source/Core/Core/HW/Memmap.cpp @@ -55,14 +55,14 @@ void MemoryManager::InitMMIO(bool is_wii) system.GetProcessorInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C003000); MemoryInterface::RegisterMMIO(m_mmio_mapping.get(), 0x0C004000); system.GetDSP().RegisterMMIO(m_mmio_mapping.get(), 0x0C005000); - DVDInterface::RegisterMMIO(m_mmio_mapping.get(), 0x0C006000, false); + system.GetDVDInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C006000, false); SerialInterface::RegisterMMIO(m_mmio_mapping.get(), 0x0C006400); ExpansionInterface::RegisterMMIO(m_mmio_mapping.get(), 0x0C006800); system.GetAudioInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C006C00); if (is_wii) { IOS::RegisterMMIO(m_mmio_mapping.get(), 0x0D000000); - DVDInterface::RegisterMMIO(m_mmio_mapping.get(), 0x0D006000, true); + system.GetDVDInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006000, true); SerialInterface::RegisterMMIO(m_mmio_mapping.get(), 0x0D006400); ExpansionInterface::RegisterMMIO(m_mmio_mapping.get(), 0x0D006800); system.GetAudioInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006C00); diff --git a/Source/Core/Core/HW/ProcessorInterface.cpp b/Source/Core/Core/HW/ProcessorInterface.cpp index a1540f6851..2c45e56416 100644 --- a/Source/Core/Core/HW/ProcessorInterface.cpp +++ b/Source/Core/Core/HW/ProcessorInterface.cpp @@ -120,7 +120,7 @@ void ProcessorInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base) processor_interface.m_reset_code); if (!SConfig::GetInstance().bWii && ~processor_interface.m_reset_code & 0x4) { - DVDInterface::ResetDrive(true); + system.GetDVDInterface().ResetDrive(true); } })); diff --git a/Source/Core/Core/HW/WII_IPC.cpp b/Source/Core/Core/HW/WII_IPC.cpp index baeb0aa15b..5aba56709d 100644 --- a/Source/Core/Core/HW/WII_IPC.cpp +++ b/Source/Core/Core/HW/WII_IPC.cpp @@ -208,13 +208,13 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) })); mmio->Register(base | GPIOB_OUT, MMIO::DirectRead(&g_gpio_out.m_hex), - MMIO::ComplexWrite([](Core::System&, u32, u32 val) { + MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { g_gpio_out.m_hex = (val & gpio_owner.m_hex) | (g_gpio_out.m_hex & ~gpio_owner.m_hex); if (g_gpio_out[GPIO::DO_EJECT]) { INFO_LOG_FMT(WII_IPC, "Ejecting disc due to GPIO write"); - DVDInterface::EjectDisc(DVDInterface::EjectCause::Software); + system.GetDVDInterface().EjectDisc(DVDInterface::EjectCause::Software); } // SENSOR_BAR is checked by WiimoteEmu::CameraLogic // TODO: AVE, SLOT_LED @@ -223,9 +223,9 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) MMIO::ComplexWrite([](Core::System&, u32, u32 val) { gpio_dir.m_hex = (val & gpio_owner.m_hex) | (gpio_dir.m_hex & ~gpio_owner.m_hex); })); - mmio->Register(base | GPIOB_IN, MMIO::ComplexRead([](Core::System&, u32) { + mmio->Register(base | GPIOB_IN, MMIO::ComplexRead([](Core::System& system, u32) { Common::Flags gpio_in; - gpio_in[GPIO::SLOT_IN] = DVDInterface::IsDiscInside(); + gpio_in[GPIO::SLOT_IN] = system.GetDVDInterface().IsDiscInside(); return gpio_in.m_hex; }), MMIO::Nop()); @@ -241,13 +241,13 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) // go through the HW_GPIOB registers if the corresponding bit is set in the HW_GPIO_OWNER // register. mmio->Register(base | GPIO_OUT, MMIO::DirectRead(&g_gpio_out.m_hex), - MMIO::ComplexWrite([](Core::System&, u32, u32 val) { + MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { g_gpio_out.m_hex = (g_gpio_out.m_hex & gpio_owner.m_hex) | (val & ~gpio_owner.m_hex); if (g_gpio_out[GPIO::DO_EJECT]) { INFO_LOG_FMT(WII_IPC, "Ejecting disc due to GPIO write"); - DVDInterface::EjectDisc(DVDInterface::EjectCause::Software); + system.GetDVDInterface().EjectDisc(DVDInterface::EjectCause::Software); } // SENSOR_BAR is checked by WiimoteEmu::CameraLogic // TODO: AVE, SLOT_LED @@ -256,15 +256,15 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) MMIO::ComplexWrite([](Core::System&, u32, u32 val) { gpio_dir.m_hex = (gpio_dir.m_hex & gpio_owner.m_hex) | (val & ~gpio_owner.m_hex); })); - mmio->Register(base | GPIO_IN, MMIO::ComplexRead([](Core::System&, u32) { + mmio->Register(base | GPIO_IN, MMIO::ComplexRead([](Core::System& system, u32) { Common::Flags gpio_in; - gpio_in[GPIO::SLOT_IN] = DVDInterface::IsDiscInside(); + gpio_in[GPIO::SLOT_IN] = system.GetDVDInterface().IsDiscInside(); return gpio_in.m_hex; }), MMIO::Nop()); mmio->Register(base | HW_RESETS, MMIO::DirectRead(&resets), - MMIO::ComplexWrite([](Core::System&, u32, u32 val) { + MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { // A reset occurs when the corresponding bit is cleared const bool di_reset_triggered = (resets & 0x400) && !(val & 0x400); resets = val; @@ -273,7 +273,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) // The GPIO *disables* spinning up the drive const bool spinup = !g_gpio_out[GPIO::DI_SPIN]; INFO_LOG_FMT(WII_IPC, "Resetting DI {} spinup", spinup ? "with" : "without"); - DVDInterface::ResetDrive(spinup); + system.GetDVDInterface().ResetDrive(spinup); } })); diff --git a/Source/Core/Core/IOS/DI/DI.cpp b/Source/Core/Core/IOS/DI/DI.cpp index c839337572..b393977c0b 100644 --- a/Source/Core/Core/IOS/DI/DI.cpp +++ b/Source/Core/Core/IOS/DI/DI.cpp @@ -214,8 +214,8 @@ std::optional DIDevice::StartIOCtl(const IOCtlRequest& reque return DIResult::SecurityError; } m_last_length = position; // An actual mistake in IOS - DVDInterface::PerformDecryptingRead(position, length, request.buffer_out, m_current_partition, - DVDInterface::ReplyType::IOS); + system.GetDVDInterface().PerformDecryptingRead( + position, length, request.buffer_out, m_current_partition, DVDInterface::ReplyType::IOS); return {}; } case DIIoctl::DVDLowWaitForCoverClose: @@ -274,12 +274,12 @@ std::optional DIDevice::StartIOCtl(const IOCtlRequest& reque } case DIIoctl::DVDLowMaskCoverInterrupt: INFO_LOG_FMT(IOS_DI, "DVDLowMaskCoverInterrupt"); - DVDInterface::SetInterruptEnabled(DVDInterface::DIInterruptType::CVRINT, false); + system.GetDVDInterface().SetInterruptEnabled(DVDInterface::DIInterruptType::CVRINT, false); DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_DI_INTERRUPT_MASK_COMMAND); return DIResult::Success; case DIIoctl::DVDLowClearCoverInterrupt: DEBUG_LOG_FMT(IOS_DI, "DVDLowClearCoverInterrupt"); - DVDInterface::ClearInterrupt(DVDInterface::DIInterruptType::CVRINT); + system.GetDVDInterface().ClearInterrupt(DVDInterface::DIInterruptType::CVRINT); return DIResult::Success; case DIIoctl::DVDLowUnmaskStatusInterrupts: INFO_LOG_FMT(IOS_DI, "DVDLowUnmaskStatusInterrupts"); @@ -287,13 +287,15 @@ std::optional DIDevice::StartIOCtl(const IOCtlRequest& reque // Dummied out return DIResult::Success; case DIIoctl::DVDLowGetCoverStatus: + { // TODO: handle resetting case - INFO_LOG_FMT(IOS_DI, "DVDLowGetCoverStatus: Disc {}Inserted", - DVDInterface::IsDiscInside() ? "" : "Not "); - return WriteIfFits(request, DVDInterface::IsDiscInside() ? 2 : 1); + const bool is_disc_inside = system.GetDVDInterface().IsDiscInside(); + INFO_LOG_FMT(IOS_DI, "DVDLowGetCoverStatus: Disc {}Inserted", is_disc_inside ? "" : "Not "); + return WriteIfFits(request, is_disc_inside ? 2 : 1); + } case DIIoctl::DVDLowUnmaskCoverInterrupt: INFO_LOG_FMT(IOS_DI, "DVDLowUnmaskCoverInterrupt"); - DVDInterface::SetInterruptEnabled(DVDInterface::DIInterruptType::CVRINT, true); + system.GetDVDInterface().SetInterruptEnabled(DVDInterface::DIInterruptType::CVRINT, true); DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_DI_INTERRUPT_MASK_COMMAND); return DIResult::Success; case DIIoctl::DVDLowReset: @@ -362,7 +364,7 @@ std::optional DIDevice::StartIOCtl(const IOCtlRequest& reque DIMAR = request.buffer_out; m_last_length = length; DILENGTH = length; - DVDInterface::ForceOutOfBoundsRead(DVDInterface::ReplyType::IOS); + system.GetDVDInterface().ForceOutOfBoundsRead(DVDInterface::ReplyType::IOS); return {}; } else @@ -579,7 +581,7 @@ std::optional DIDevice::StartDMATransfer(u32 command_length, m_last_length = command_length; DILENGTH = command_length; - DVDInterface::ExecuteCommand(DVDInterface::ReplyType::IOS); + Core::System::GetInstance().GetDVDInterface().ExecuteCommand(DVDInterface::ReplyType::IOS); // Reply will be posted when done by FinishIOCtl. return {}; } @@ -597,7 +599,7 @@ std::optional DIDevice::StartImmediateTransfer(const IOCtlRe m_executing_command->m_copy_diimmbuf = write_to_buf; - DVDInterface::ExecuteCommand(DVDInterface::ReplyType::IOS); + Core::System::GetInstance().GetDVDInterface().ExecuteCommand(DVDInterface::ReplyType::IOS); // Reply will be posted when done by FinishIOCtl. return {}; } @@ -814,12 +816,13 @@ void DIDevice::ResetDIRegisters() { // Clear transfer complete and error interrupts (normally r/z, but here we just directly write // zero) - DVDInterface::ClearInterrupt(DVDInterface::DIInterruptType::TCINT); - DVDInterface::ClearInterrupt(DVDInterface::DIInterruptType::DEINT); + auto& di = Core::System::GetInstance().GetDVDInterface(); + di.ClearInterrupt(DVDInterface::DIInterruptType::TCINT); + di.ClearInterrupt(DVDInterface::DIInterruptType::DEINT); // Enable transfer complete and error interrupts, and disable cover interrupt - DVDInterface::SetInterruptEnabled(DVDInterface::DIInterruptType::TCINT, true); - DVDInterface::SetInterruptEnabled(DVDInterface::DIInterruptType::DEINT, true); - DVDInterface::SetInterruptEnabled(DVDInterface::DIInterruptType::CVRINT, false); + di.SetInterruptEnabled(DVDInterface::DIInterruptType::TCINT, true); + di.SetInterruptEnabled(DVDInterface::DIInterruptType::DEINT, true); + di.SetInterruptEnabled(DVDInterface::DIInterruptType::CVRINT, false); // Close the current partition, if there is one ChangePartition(DiscIO::PARTITION_NONE); } diff --git a/Source/Core/Core/IOS/MIOS.cpp b/Source/Core/Core/IOS/MIOS.cpp index d19374364d..ecd7a992a4 100644 --- a/Source/Core/Core/IOS/MIOS.cpp +++ b/Source/Core/Core/IOS/MIOS.cpp @@ -42,7 +42,7 @@ static void ReinitHardware() // HACK However, resetting DI will reset the DTK config, which is set by the system menu // (and not by MIOS), causing games that use DTK to break. Perhaps MIOS doesn't actually // reset DI fully, in such a way that the DTK config isn't cleared? - // DVDInterface::ResetDrive(true); + // system.GetDVDInterface().ResetDrive(true); PowerPC::Reset(); Wiimote::ResetAllWiimotes(); // Note: this is specific to Dolphin and is required because we initialised it in Wii mode. @@ -99,7 +99,7 @@ bool Load() memory.Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE); NOTICE_LOG_FMT(IOS, "IPL ready."); SConfig::GetInstance().m_is_mios = true; - DVDInterface::UpdateRunningGameMetadata(); + system.GetDVDInterface().UpdateRunningGameMetadata(); SConfig::OnNewTitleLoad(guard); return true; } diff --git a/Source/Core/Core/Movie.cpp b/Source/Core/Core/Movie.cpp index 8a7a9fd94b..e4f7a61bca 100644 --- a/Source/Core/Core/Movie.cpp +++ b/Source/Core/Core/Movie.cpp @@ -1274,9 +1274,9 @@ void PlayController(GCPadStatus* PadStatus, int controllerID) if (s_padState.disc) { Core::RunAsCPUThread([] { - if (!DVDInterface::AutoChangeDisc()) + auto& system = Core::System::GetInstance(); + if (!system.GetDVDInterface().AutoChangeDisc()) { - auto& system = Core::System::GetInstance(); system.GetCPU().Break(); PanicAlertFmtT("Change the disc to {0}", s_discChange); } diff --git a/Source/Core/Core/System.cpp b/Source/Core/Core/System.cpp index 6f99d23773..4fa9da9f0c 100644 --- a/Source/Core/Core/System.cpp +++ b/Source/Core/Core/System.cpp @@ -36,8 +36,8 @@ namespace Core struct System::Impl { explicit Impl(System& system) - : m_audio_interface(system), m_core_timing(system), m_dsp(system), m_gp_fifo(system), - m_ppc_state(PowerPC::ppcState) + : m_audio_interface(system), m_core_timing(system), m_dsp(system), m_dvd_interface(system), + m_gp_fifo(system), m_ppc_state(PowerPC::ppcState) { } @@ -50,7 +50,7 @@ struct System::Impl CommandProcessor::CommandProcessorManager m_command_processor; CPU::CPUManager m_cpu; DSP::DSPManager m_dsp; - DVDInterface::DVDInterfaceState m_dvd_interface_state; + DVDInterface::DVDInterfaceManager m_dvd_interface; DVDThread::DVDThreadState m_dvd_thread_state; ExpansionInterface::ExpansionInterfaceState m_expansion_interface_state; Fifo::FifoManager m_fifo; @@ -138,9 +138,9 @@ DSP::DSPManager& System::GetDSP() const return m_impl->m_dsp; } -DVDInterface::DVDInterfaceState& System::GetDVDInterfaceState() const +DVDInterface::DVDInterfaceManager& System::GetDVDInterface() const { - return m_impl->m_dvd_interface_state; + return m_impl->m_dvd_interface; } DVDThread::DVDThreadState& System::GetDVDThreadState() const diff --git a/Source/Core/Core/System.h b/Source/Core/Core/System.h index 4ab7247fc3..4e2a86e12a 100644 --- a/Source/Core/Core/System.h +++ b/Source/Core/Core/System.h @@ -33,7 +33,7 @@ class DSPManager; } namespace DVDInterface { -class DVDInterfaceState; +class DVDInterfaceManager; } namespace DVDThread { @@ -127,7 +127,7 @@ public: CoreTiming::CoreTimingManager& GetCoreTiming() const; CommandProcessor::CommandProcessorManager& GetCommandProcessor() const; DSP::DSPManager& GetDSP() const; - DVDInterface::DVDInterfaceState& GetDVDInterfaceState() const; + DVDInterface::DVDInterfaceManager& GetDVDInterface() const; DVDThread::DVDThreadState& GetDVDThreadState() const; ExpansionInterface::ExpansionInterfaceState& GetExpansionInterfaceState() const; Fifo::FifoManager& GetFifo() const; diff --git a/Source/Core/DolphinQt/GameList/GameList.cpp b/Source/Core/DolphinQt/GameList/GameList.cpp index 69afc13a74..107addf802 100644 --- a/Source/Core/DolphinQt/GameList/GameList.cpp +++ b/Source/Core/DolphinQt/GameList/GameList.cpp @@ -52,6 +52,7 @@ #include "Core/HW/EXI/EXI.h" #include "Core/HW/EXI/EXI_Device.h" #include "Core/HW/WiiSave.h" +#include "Core/System.h" #include "Core/WiiUtils.h" #include "DiscIO/Blob.h" @@ -852,7 +853,9 @@ void GameList::ChangeDisc() if (!game) return; - Core::RunAsCPUThread([file_path = game->GetFilePath()] { DVDInterface::ChangeDisc(file_path); }); + Core::RunAsCPUThread([file_path = game->GetFilePath()] { + Core::System::GetInstance().GetDVDInterface().ChangeDisc(file_path); + }); } QAbstractItemView* GameList::GetActiveView() const diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 59fc19f6a3..604400f1c3 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -746,12 +746,15 @@ void MainWindow::ChangeDisc() std::vector paths = StringListToStdVector(PromptFileNames()); if (!paths.empty()) - Core::RunAsCPUThread([&paths] { DVDInterface::ChangeDisc(paths); }); + Core::RunAsCPUThread( + [&paths] { Core::System::GetInstance().GetDVDInterface().ChangeDisc(paths); }); } void MainWindow::EjectDisc() { - Core::RunAsCPUThread([] { DVDInterface::EjectDisc(DVDInterface::EjectCause::User); }); + Core::RunAsCPUThread([] { + Core::System::GetInstance().GetDVDInterface().EjectDisc(DVDInterface::EjectCause::User); + }); } void MainWindow::OpenUserFolder()