summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
authorMai <mai.iam2048@gmail.com>2023-03-10 16:51:19 -0500
committerGitHub <noreply@github.com>2023-03-10 16:51:19 -0500
commit00a6f8c82c8631b8a53feaedad930057cdd8cc0d (patch)
tree4fdb88180e5aa5064250b7371b94f1f87d98e502 /Source
parent3ec32c5aa5e48e99c415d50ae816d517057feee0 (diff)
parentd31733ce6431fa6fd16f2d2bbdb747e447c0c1aa (diff)
Merge pull request #11637 from AdmiralCurtiss/dvd-class
HW/DVD: Refactor DVDInterface and DVDThread to classes.
Diffstat (limited to 'Source')
-rw-r--r--Source/Android/jni/MainAndroid.cpp3
-rw-r--r--Source/Core/Core/Boot/Boot.cpp4
-rw-r--r--Source/Core/Core/Boot/Boot_BS2Emu.cpp4
-rw-r--r--Source/Core/Core/ConfigManager.cpp2
-rw-r--r--Source/Core/Core/HW/DVD/DVDInterface.cpp874
-rw-r--r--Source/Core/Core/HW/DVD/DVDInterface.h238
-rw-r--r--Source/Core/Core/HW/DVD/DVDThread.cpp275
-rw-r--r--Source/Core/Core/HW/DVD/DVDThread.h155
-rw-r--r--Source/Core/Core/HW/HW.cpp6
-rw-r--r--Source/Core/Core/HW/Memmap.cpp4
-rw-r--r--Source/Core/Core/HW/ProcessorInterface.cpp2
-rw-r--r--Source/Core/Core/HW/WII_IPC.cpp20
-rw-r--r--Source/Core/Core/IOS/DI/DI.cpp46
-rw-r--r--Source/Core/Core/IOS/DI/DI.h4
-rw-r--r--Source/Core/Core/IOS/MIOS.cpp4
-rw-r--r--Source/Core/Core/Movie.cpp4
-rw-r--r--Source/Core/Core/System.cpp16
-rw-r--r--Source/Core/Core/System.h15
-rw-r--r--Source/Core/DolphinQt/GameList/GameList.cpp5
-rw-r--r--Source/Core/DolphinQt/MainWindow.cpp6
20 files changed, 823 insertions, 864 deletions
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..01f7c6cc22 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<DiscIO::VolumeDisc> dis
std::vector<std::string> 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(DVD::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..e930eee371 100644
--- a/Source/Core/Core/HW/DVD/DVDInterface.cpp
+++ b/Source/Core/Core/HW/DVD/DVDInterface.cpp
@@ -63,7 +63,7 @@ constexpr u64 DVD_ECC_BLOCK_SIZE = 16 * DVD_SECTOR_SIZE;
// is already buffered. Measured in bytes per second.
constexpr u64 BUFFER_TRANSFER_RATE = 32 * 1024 * 1024;
-namespace DVDInterface
+namespace DVD
{
// internal hardware addresses
constexpr u32 DI_STATUS_REGISTER = 0x00;
@@ -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<u32, 3> 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<std::string> 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<Data>())
+DVDInterface::DVDInterface(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);
+DVDInterface::~DVDInterface() = 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 DVDInterface::DoState(PointerWrap& p)
{
- auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();
-
- 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(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(state.drive_state);
- p.Do(state.error_code);
-
- 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);
-
- DVDThread::DoState(p);
-
- state.adpcm_decoder.DoState(p);
+ 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(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(m_drive_state);
+ p.Do(m_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(m_disc_path_to_insert);
+
+ m_system.GetDVDThread().DoState(p);
+
+ m_adpcm_decoder.DoState(p);
}
-static size_t ProcessDTKSamples(std::vector<s16>* temp_pcm, const std::vector<u8>& audio_data)
+size_t DVDInterface::ProcessDTKSamples(std::vector<s16>* temp_pcm,
+ const std::vector<u8>& 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<s16>* temp_pcm, const std::vector<u8
return samples_processed;
}
-static u32 AdvanceDTK(u32 maximum_samples, u32* samples_to_process)
+u32 DVDInterface::AdvanceDTK(u32 maximum_samples, u32* samples_to_process)
{
- auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();
-
u32 bytes_to_process = 0;
*samples_to_process = 0;
while (*samples_to_process < maximum_samples)
{
- if (state.audio_position >= 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<u8>& audio_data,
- s64 cycles_late)
+void DVDInterface::DTKStreamingCallback(DIInterruptType interrupt_type,
+ const std::vector<u8>& 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,96 +199,92 @@ static void DTKStreamingCallback(DIInterruptType interrupt_type, const std::vect
if (interrupt_type == DIInterruptType::TCINT)
{
// Send audio to the mixer.
- std::vector<s16> temp_pcm(state.pending_samples * 2, 0);
+ std::vector<s16> 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)
{
- DVDThread::StartRead(read_offset, read_length, DiscIO::PARTITION_NONE, ReplyType::DTK,
- ticks_to_dtk);
+ m_system.GetDVDThread().StartRead(read_offset, read_length, DiscIO::PARTITION_NONE,
+ ReplyType::DTK, ticks_to_dtk);
}
else
{
// 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 DVDInterface::Init()
{
ASSERT(!IsDiscInside());
- DVDThread::Start();
-
- auto& system = Core::System::GetInstance();
- auto& core_timing = system.GetCoreTiming();
- auto& state = system.GetDVDInterfaceState().GetData();
+ m_system.GetDVDThread().Start();
- 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 DVDInterface::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,15 +309,15 @@ 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 DVDInterface::Shutdown()
{
- DVDThread::Stop();
+ m_system.GetDVDThread().Stop();
}
static u64 GetDiscEndOffset(const DiscIO::VolumeDisc& disc)
@@ -481,18 +347,17 @@ static u64 GetDiscEndOffset(const DiscIO::VolumeDisc& disc)
return DiscIO::DL_DVD_SIZE;
}
-void SetDisc(std::unique_ptr<DiscIO::VolumeDisc> disc,
- std::optional<std::vector<std::string>> auto_disc_change_paths = {})
+void DVDInterface::SetDisc(std::unique_ptr<DiscIO::VolumeDisc> disc,
+ std::optional<std::vector<std::string>> auto_disc_change_paths = {})
{
bool had_disc = IsDiscInside();
bool has_disc = static_cast<bool>(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,80 +381,74 @@ void SetDisc(std::unique_ptr<DiscIO::VolumeDisc> 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
if (had_disc != has_disc)
ExpansionInterface::g_rtc_flags[ExpansionInterface::RTCFlag::DiscChanged] = true;
- DVDThread::SetDisc(std::move(disc));
+ m_system.GetDVDThread().SetDisc(std::move(disc));
SetLidOpen();
ResetDrive(false);
}
-bool IsDiscInside()
+bool DVDInterface::IsDiscInside() const
{
- return DVDThread::HasDisc();
+ return m_system.GetDVDThread().HasDisc();
}
-static void AutoChangeDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate)
+void DVDInterface::AutoChangeDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate)
{
- AutoChangeDisc();
+ system.GetDVDInterface().AutoChangeDisc();
}
-static void EjectDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate)
+void DVDInterface::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 DVDInterface::InsertDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate)
{
- auto& state = system.GetDVDInterfaceState().GetData();
- std::unique_ptr<DiscIO::VolumeDisc> new_disc = DiscIO::CreateDisc(state.disc_path_to_insert);
+ auto& di = system.GetDVDInterface();
+ std::unique_ptr<DiscIO::VolumeDisc> 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 DVDInterface::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<std::string>& paths)
+void DVDInterface::ChangeDisc(const std::vector<std::string>& 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 DVDInterface::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,102 +456,100 @@ 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 DVDInterface::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 DVDInterface::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<u64> title_id)
+bool DVDInterface::UpdateRunningGameMetadata(std::optional<u64> title_id)
{
- if (!DVDThread::HasDisc())
+ auto& dvd_thread = m_system.GetDVDThread();
+
+ if (!dvd_thread.HasDisc())
return false;
- return DVDThread::UpdateRunningGameMetadata(IOS::HLE::DIDevice::GetCurrentPartition(), title_id);
+ return dvd_thread.UpdateRunningGameMetadata(IOS::HLE::DIDevice::GetCurrentPartition(), title_id);
}
-void RegisterMMIO(MMIO::Mapping* mmio, u32 base, bool is_wii)
+void DVDInterface::RegisterMMIO(MMIO::Mapping* mmio, u32 base, bool is_wii)
{
- auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData();
- mmio->Register(base | DI_STATUS_REGISTER, MMIO::DirectRead<u32>(&state.DISR.Hex),
+ mmio->Register(base | DI_STATUS_REGISTER, MMIO::DirectRead<u32>(&m_DISR.Hex),
MMIO::ComplexWrite<u32>([](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<u32>(&state.DICVR.Hex),
+ mmio->Register(base | DI_COVER_REGISTER, MMIO::DirectRead<u32>(&m_DICVR.Hex),
MMIO::ComplexWrite<u32>([](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<u32>(&state.DICMDBUF[0]),
- MMIO::DirectWrite<u32>(&state.DICMDBUF[0]));
- mmio->Register(base | DI_COMMAND_1, MMIO::DirectRead<u32>(&state.DICMDBUF[1]),
- MMIO::DirectWrite<u32>(&state.DICMDBUF[1]));
- mmio->Register(base | DI_COMMAND_2, MMIO::DirectRead<u32>(&state.DICMDBUF[2]),
- MMIO::DirectWrite<u32>(&state.DICMDBUF[2]));
+ mmio->Register(base | DI_COMMAND_0, MMIO::DirectRead<u32>(&m_DICMDBUF[0]),
+ MMIO::DirectWrite<u32>(&m_DICMDBUF[0]));
+ mmio->Register(base | DI_COMMAND_1, MMIO::DirectRead<u32>(&m_DICMDBUF[1]),
+ MMIO::DirectWrite<u32>(&m_DICMDBUF[1]));
+ mmio->Register(base | DI_COMMAND_2, MMIO::DirectRead<u32>(&m_DICMDBUF[2]),
+ MMIO::DirectWrite<u32>(&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 +564,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<u32>(&state.DIMAR),
- MMIO::DirectWrite<u32>(&state.DIMAR, is_wii ? ~0x1F : ~0xFC00001F));
- mmio->Register(base | DI_DMA_LENGTH_REGISTER, MMIO::DirectRead<u32>(&state.DILENGTH),
- MMIO::DirectWrite<u32>(&state.DILENGTH, ~0x1F));
- mmio->Register(base | DI_DMA_CONTROL_REGISTER, MMIO::DirectRead<u32>(&state.DICR.Hex),
+ mmio->Register(base | DI_DMA_ADDRESS_REGISTER, MMIO::DirectRead<u32>(&m_DIMAR),
+ MMIO::DirectWrite<u32>(&m_DIMAR, is_wii ? ~0x1F : ~0xFC00001F));
+ mmio->Register(base | DI_DMA_LENGTH_REGISTER, MMIO::DirectRead<u32>(&m_DILENGTH),
+ MMIO::DirectWrite<u32>(&m_DILENGTH, ~0x1F));
+ mmio->Register(base | DI_DMA_CONTROL_REGISTER, MMIO::DirectRead<u32>(&m_DICR.Hex),
MMIO::ComplexWrite<u32>([](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<u32>(&state.DIIMMBUF),
- MMIO::DirectWrite<u32>(&state.DIIMMBUF));
+ mmio->Register(base | DI_IMMEDIATE_DATA_BUFFER, MMIO::DirectRead<u32>(&m_DIIMMBUF),
+ MMIO::DirectWrite<u32>(&m_DIIMMBUF));
// DI config register is read only.
- mmio->Register(base | DI_CONFIG_REGISTER, MMIO::DirectRead<u32>(&state.DICFG.Hex),
+ mmio->Register(base | DI_CONFIG_REGISTER, MMIO::DirectRead<u32>(&m_DICFG.Hex),
MMIO::InvalidWrite<u32>());
}
-static void UpdateInterrupts()
+void DVDInterface::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 DVDInterface::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 DVDInterface::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 DVDInterface::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 +660,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 DVDInterface::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 +690,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 DVDInterface::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 +717,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 +731,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 DVDInterface::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<DICommand>(state.DICMDBUF[0] >> 24) != DICommand::RequestError)
+ if (static_cast<DICommand>(m_DICMDBUF[0] >> 24) != DICommand::RequestError)
SetDriveError(DriveError::None);
- switch (static_cast<DICommand>(state.DICMDBUF[0] >> 24))
+ switch (static_cast<DICommand>(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 +773,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<u64>(state.DICMDBUF[1]) << 2;
+ const u64 dvd_offset = static_cast<u64>(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 +807,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 +821,12 @@ void ExecuteCommand(ReplyType reply_type)
case DICommand::Seek:
// Currently unimplemented
INFO_LOG_FMT(DVDINTERFACE, "Seek: offset={:09x} (ignoring)",
- static_cast<u64>(state.DICMDBUF[1]) << 2);
+ static_cast<u64>(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 +838,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 +879,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 +918,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<u32>(state.drive_state) - 1;
+ drive_state = static_cast<u32>(m_drive_state) - 1;
- const u32 result = (drive_state << 24) | static_cast<u32>(state.error_code);
+ const u32 result = (drive_state << 24) | static_cast<u32>(m_error_code);
INFO_LOG_FMT(DVDINTERFACE, "Requesting error... ({:#010x})", result);
- state.DIIMMBUF = result;
+ m_DIIMMBUF = result;
SetDriveError(DriveError::None);
break;
}
@@ -1093,60 +938,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<u64>(state.DICMDBUF[1]) << 2;
- const u32 length = state.DICMDBUF[2];
+ const u64 offset = static_cast<u64>(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 +1009,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 +1017,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<u32>((state.audio_position & 0xffffffffffff8000ull) >> 2);
+ m_audio_position);
+ m_DIIMMBUF = static_cast<u32>((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<u32>(state.current_start >> 2);
+ m_current_start);
+ m_DIIMMBUF = static_cast<u32>(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 +1057,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 +1070,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())
+ m_system.GetDVDThread().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 +1099,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 +1110,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 +1125,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 +1135,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 +1152,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 +1163,18 @@ 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 DVDInterface::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 DVDInterface::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 DVDInterface::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,27 @@ static u64 PackFinishExecutingCommandUserdata(ReplyType reply_type, DIInterruptT
return (static_cast<u64>(reply_type) << 32) + static_cast<u32>(interrupt_type);
}
-void FinishExecutingCommandCallback(Core::System& system, u64 userdata, s64 cycles_late)
+void DVDInterface::FinishExecutingCommandCallback(Core::System& system, u64 userdata,
+ s64 cycles_late)
{
ReplyType reply_type = static_cast<ReplyType>(userdata >> 32);
DIInterruptType interrupt_type = static_cast<DIInterruptType>(userdata & 0xFFFFFFFF);
- FinishExecutingCommand(reply_type, interrupt_type, cycles_late);
+ system.GetDVDInterface().FinishExecutingCommand(reply_type, interrupt_type, cycles_late);
}
-void SetDriveState(DriveState state)
+void DVDInterface::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 DVDInterface::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<u8>& data)
+void DVDInterface::FinishExecutingCommand(ReplyType reply_type, DIInterruptType interrupt_type,
+ s64 cycles_late, const std::vector<u8>& 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 +1249,12 @@ void FinishExecutingCommand(ReplyType reply_type, DIInterruptType interrupt_type
if (reply_type == ReplyType::NoReply)
transfer_size = static_cast<u32>(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 +1266,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 +1290,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 DVDInterface::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,9 +1302,11 @@ 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;
+ auto& dvd_thread = m_system.GetDVDThread();
+ const bool wii_disc = dvd_thread.GetDiscType() == DiscIO::Platform::WiiDisc;
// Whether we have performed a seek.
bool seek = false;
@@ -1493,7 +1323,7 @@ static void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& parti
// The variable dvd_offset tracks the actual offset on the DVD
// that the disc drive starts reading at, which differs in two ways:
// It's rounded to a whole ECC block and never uses Wii partition addressing.
- u64 dvd_offset = DVDThread::PartitionOffsetToRawOffset(offset, partition);
+ u64 dvd_offset = dvd_thread.PartitionOffsetToRawOffset(offset, partition);
dvd_offset = Common::AlignDown(dvd_offset, DVD_ECC_BLOCK_SIZE);
const u64 first_block = dvd_offset;
@@ -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;
@@ -1559,7 +1388,7 @@ static void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& parti
u32 buffered_blocks = 0;
u32 unbuffered_blocks = 0;
- const u32 bytes_per_chunk = partition != DiscIO::PARTITION_NONE && DVDThread::HasWiiHashes() ?
+ const u32 bytes_per_chunk = partition != DiscIO::PARTITION_NONE && dvd_thread.HasWiiHashes() ?
DiscIO::VolumeWii::BLOCK_DATA_SIZE :
DVD_ECC_BLOCK_SIZE;
@@ -1620,7 +1449,7 @@ static void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& parti
// Schedule this read to complete at the appropriate time
const ReplyType chunk_reply_type = chunk_length == length ? reply_type : ReplyType::NoReply;
- DVDThread::StartReadToEmulatedRAM(output_address, offset, chunk_length, partition,
+ dvd_thread.StartReadToEmulatedRAM(output_address, offset, chunk_length, partition,
chunk_reply_type, ticks_until_completion);
// Advance the read window
@@ -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<u64>(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,
@@ -1686,4 +1514,4 @@ static void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& parti
ticks_until_completion * 1000000 / SystemTimers::GetTicksPerSecond());
}
-} // namespace DVDInterface
+} // namespace DVD
diff --git a/Source/Core/Core/HW/DVD/DVDInterface.h b/Source/Core/Core/HW/DVD/DVDInterface.h
index ef619f0f65..0a320361d5 100644
--- a/Source/Core/Core/HW/DVD/DVDInterface.h
+++ b/Source/Core/Core/HW/DVD/DVDInterface.h
@@ -3,14 +3,26 @@
#pragma once
+#include <array>
#include <memory>
#include <optional>
#include <string>
#include <vector>
+#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;
@@ -21,25 +33,8 @@ namespace MMIO
class Mapping;
}
-namespace DVDInterface
+namespace DVD
{
-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<Data> 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 DVDInterface
+{
+public:
+ explicit DVDInterface(Core::System& system);
+ DVDInterface(const DVDInterface&) = delete;
+ DVDInterface(DVDInterface&&) = delete;
+ DVDInterface& operator=(const DVDInterface&) = delete;
+ DVDInterface& operator=(DVDInterface&&) = delete;
+ ~DVDInterface();
+
+ void Init();
+ void ResetDrive(bool spinup);
+ void Shutdown();
+ void DoState(PointerWrap& p);
-void RegisterMMIO(MMIO::Mapping* mmio, u32 base, bool is_wii);
+ void RegisterMMIO(MMIO::Mapping* mmio, u32 base, bool is_wii);
-void SetDisc(std::unique_ptr<DiscIO::VolumeDisc> disc,
- std::optional<std::vector<std::string>> auto_disc_change_paths);
-bool IsDiscInside();
-void EjectDisc(EjectCause cause); // Must only be called on the CPU thread
-void ChangeDisc(const std::vector<std::string>& 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 SetDisc(std::unique_ptr<DiscIO::VolumeDisc> disc,
+ std::optional<std::vector<std::string>> auto_disc_change_paths);
+ bool IsDiscInside() const;
+ void EjectDisc(EjectCause cause); // Must only be called on the CPU thread
+ void ChangeDisc(const std::vector<std::string>& 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
-// 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<u64> title_id = {});
+ // 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<u64> title_id = {});
-// 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);
+ // 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);
-// For circumventing Error #001 in DirectoryBlobs, which may have data in the offsets being checked.
-void ForceOutOfBoundsRead(ReplyType reply_type);
+ // For circumventing Error #001 in DirectoryBlobs, which may have data in the offsets being
+ // checked.
+ void ForceOutOfBoundsRead(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);
+ // Exposed for use by emulated BS2; does not perform any checks on drive state
+ void AudioBufferConfig(bool enable_dtk, u8 dtk_buffer_length);
+
+ void SetDriveState(DriveState state);
+ void SetDriveError(DriveError error);
+
+ // Used by DVDThread
+ void FinishExecutingCommand(ReplyType reply_type, DIInterruptType interrupt_type, s64 cycles_late,
+ const std::vector<u8>& data = std::vector<u8>());
+
+ // Used by IOS HLE
+ void SetInterruptEnabled(DIInterruptType interrupt, bool enabled);
+ void ClearInterrupt(DIInterruptType interrupt);
+
+private:
+ void DTKStreamingCallback(DIInterruptType interrupt_type, const std::vector<u8>& audio_data,
+ s64 cycles_late);
+ size_t ProcessDTKSamples(std::vector<s16>* temp_pcm, const std::vector<u8>& audio_data);
+ u32 AdvanceDTK(u32 maximum_samples, u32* samples_to_process);
-void SetDriveState(DriveState state);
-void SetDriveError(DriveError error);
+ void SetLidOpen();
+ void UpdateInterrupts();
+ void GenerateDIInterrupt(DIInterruptType dvd_interrupt);
-// Used by DVDThread
-void FinishExecutingCommand(ReplyType reply_type, DIInterruptType interrupt_type, s64 cycles_late,
- const std::vector<u8>& data = std::vector<u8>());
+ 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);
-// Used by IOS HLE
-void SetInterruptEnabled(DIInterruptType interrupt, bool enabled);
-void ClearInterrupt(DIInterruptType interrupt);
+ 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);
-} // namespace DVDInterface
+ // 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<u32, 3> 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<std::string> 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 DVD
diff --git a/Source/Core/Core/HW/DVD/DVDThread.cpp b/Source/Core/Core/HW/DVD/DVDThread.cpp
index 08f35c26bd..d861bba2eb 100644
--- a/Source/Core/Core/HW/DVD/DVDThread.cpp
+++ b/Source/Core/Core/HW/DVD/DVDThread.cpp
@@ -34,122 +34,58 @@
#include "DiscIO/Enums.h"
#include "DiscIO/Volume.h"
-namespace DVDThread
+namespace DVD
{
-struct ReadRequest
-{
- bool copy_to_ram = false;
- u32 output_address = 0;
- u64 dvd_offset = 0;
- u32 length = 0;
- DiscIO::Partition partition{};
-
- // This determines which code DVDInterface will run to reply
- // to the emulated software. We can't use callbacks,
- // because function pointers can't be stored in savestates.
- DVDInterface::ReplyType reply_type = DVDInterface::ReplyType::NoReply;
-
- // IDs are used to uniquely identify a request. They must not be
- // identical to IDs of any other requests that currently exist, but
- // it's fine to re-use IDs of requests that have existed in the past.
- u64 id = 0;
-
- // Only used for logging
- u64 time_started_ticks = 0;
- u64 realtime_started_us = 0;
- u64 realtime_done_us = 0;
-};
-
-using ReadResult = std::pair<ReadRequest, std::vector<u8>>;
-
-static void StartDVDThread(DVDThreadState::Data& state);
-static void StopDVDThread(DVDThreadState::Data& state);
-
-static void DVDThread();
-static void WaitUntilIdle();
-
-static void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offset, u32 length,
- const DiscIO::Partition& partition,
- DVDInterface::ReplyType reply_type, s64 ticks_until_completion);
-
-static void FinishRead(Core::System& system, u64 id, s64 cycles_late);
-
-struct DVDThreadState::Data
-{
- CoreTiming::EventType* finish_read = nullptr;
-
- u64 next_id = 0;
-
- std::thread dvd_thread;
- Common::Event request_queue_expanded; // Is set by CPU thread
- Common::Event result_queue_expanded; // Is set by DVD thread
- Common::Flag dvd_thread_exiting = Common::Flag(false); // Is set by CPU thread
-
- Common::SPSCQueue<ReadRequest, false> request_queue;
- Common::SPSCQueue<ReadResult, false> result_queue;
- std::map<u64, ReadResult> result_map;
-
- std::unique_ptr<DiscIO::Volume> disc;
-
- FileMonitor::FileLogger file_logger;
-};
-
-DVDThreadState::DVDThreadState() : m_data(std::make_unique<Data>())
+DVDThread::DVDThread(Core::System& system) : m_system(system)
{
}
-DVDThreadState::~DVDThreadState() = default;
+DVDThread::~DVDThread() = default;
-void Start()
+void DVDThread::Start()
{
- auto& system = Core::System::GetInstance();
- auto& state = system.GetDVDThreadState().GetData();
+ m_finish_read = m_system.GetCoreTiming().RegisterEvent("FinishReadDVDThread", GlobalFinishRead);
- state.finish_read = system.GetCoreTiming().RegisterEvent("FinishReadDVDThread", FinishRead);
-
- state.request_queue_expanded.Reset();
- state.result_queue_expanded.Reset();
- state.request_queue.Clear();
- state.result_queue.Clear();
+ m_request_queue_expanded.Reset();
+ m_result_queue_expanded.Reset();
+ m_request_queue.Clear();
+ m_result_queue.Clear();
// This is reset on every launch for determinism, but it doesn't matter
// much, because this will never get exposed to the emulated game.
- state.next_id = 0;
+ m_next_id = 0;
- StartDVDThread(state);
+ StartDVDThread();
}
-static void StartDVDThread(DVDThreadState::Data& state)
+void DVDThread::StartDVDThread()
{
- ASSERT(!state.dvd_thread.joinable());
- state.dvd_thread_exiting.Clear();
- state.dvd_thread = std::thread(DVDThread);
+ ASSERT(!m_dvd_thread.joinable());
+ m_dvd_thread_exiting.Clear();
+ m_dvd_thread = std::thread(&DVDThread::DVDThreadMain, this);
}
-void Stop()
+void DVDThread::Stop()
{
- auto& state = Core::System::GetInstance().GetDVDThreadState().GetData();
- StopDVDThread(state);
- state.disc.reset();
+ StopDVDThread();
+ m_disc.reset();
}
-static void StopDVDThread(DVDThreadState::Data& state)
+void DVDThread::StopDVDThread()
{
- ASSERT(state.dvd_thread.joinable());
+ ASSERT(m_dvd_thread.joinable());
// By setting dvd_thread_exiting, we ask the DVD thread to cleanly exit.
// In case the request queue is empty, we need to set request_queue_expanded
// so that the DVD thread will wake up and check dvd_thread_exiting.
- state.dvd_thread_exiting.Set();
- state.request_queue_expanded.Set();
+ m_dvd_thread_exiting.Set();
+ m_request_queue_expanded.Set();
- state.dvd_thread.join();
+ m_dvd_thread.join();
}
-void DoState(PointerWrap& p)
+void DVDThread::DoState(PointerWrap& p)
{
- auto& state = Core::System::GetInstance().GetDVDThreadState().GetData();
-
// By waiting for the DVD thread to be done working, we ensure
// that request_queue will be empty and that the DVD thread
// won't be touching anything while this function runs.
@@ -159,14 +95,14 @@ void DoState(PointerWrap& p)
// PointerWrap::Do supports std::map but not Common::SPSCQueue.
// This won't affect the behavior of FinishRead.
ReadResult result;
- while (state.result_queue.Pop(result))
- state.result_map.emplace(result.first.id, std::move(result));
+ while (m_result_queue.Pop(result))
+ m_result_map.emplace(result.first.id, std::move(result));
// Both queues are now empty, so we don't need to savestate them.
- p.Do(state.result_map);
- p.Do(state.next_id);
+ p.Do(m_result_map);
+ p.Do(m_next_id);
- // state.disc isn't savestated (because it points to files on the
+ // m_disc isn't savestated (because it points to files on the
// local system). Instead, we check that the status of the disc
// is the same as when the savestate was made. This won't catch
// cases of having the wrong disc inserted, though.
@@ -178,7 +114,7 @@ void DoState(PointerWrap& p)
if (had_disc)
PanicAlertFmtT("An inserted disc was expected but not found.");
else
- state.disc.reset();
+ m_disc.reset();
}
// TODO: Savestates can be smaller if the buffers of results aren't saved,
@@ -192,123 +128,108 @@ void DoState(PointerWrap& p)
// was made. Handling that properly may be more effort than it's worth.
}
-void SetDisc(std::unique_ptr<DiscIO::Volume> disc)
+void DVDThread::SetDisc(std::unique_ptr<DiscIO::Volume> disc)
{
- auto& state = Core::System::GetInstance().GetDVDThreadState().GetData();
-
WaitUntilIdle();
- state.disc = std::move(disc);
+ m_disc = std::move(disc);
}
-bool HasDisc()
+bool DVDThread::HasDisc() const
{
- auto& state = Core::System::GetInstance().GetDVDThreadState().GetData();
- return state.disc != nullptr;
+ return m_disc != nullptr;
}
-bool HasWiiHashes()
+bool DVDThread::HasWiiHashes() const
{
// HasWiiHashes is thread-safe, so calling WaitUntilIdle isn't necessary.
- auto& state = Core::System::GetInstance().GetDVDThreadState().GetData();
- return state.disc->HasWiiHashes();
+ return m_disc->HasWiiHashes();
}
-DiscIO::Platform GetDiscType()
+DiscIO::Platform DVDThread::GetDiscType() const
{
// GetVolumeType is thread-safe, so calling WaitUntilIdle isn't necessary.
- auto& state = Core::System::GetInstance().GetDVDThreadState().GetData();
- return state.disc->GetVolumeType();
+ return m_disc->GetVolumeType();
}
-u64 PartitionOffsetToRawOffset(u64 offset, const DiscIO::Partition& partition)
+u64 DVDThread::PartitionOffsetToRawOffset(u64 offset, const DiscIO::Partition& partition)
{
// PartitionOffsetToRawOffset is thread-safe, so calling WaitUntilIdle isn't necessary.
- auto& state = Core::System::GetInstance().GetDVDThreadState().GetData();
- return state.disc->PartitionOffsetToRawOffset(offset, partition);
+ return m_disc->PartitionOffsetToRawOffset(offset, partition);
}
-IOS::ES::TMDReader GetTMD(const DiscIO::Partition& partition)
+IOS::ES::TMDReader DVDThread::GetTMD(const DiscIO::Partition& partition)
{
- auto& state = Core::System::GetInstance().GetDVDThreadState().GetData();
WaitUntilIdle();
- return state.disc->GetTMD(partition);
+ return m_disc->GetTMD(partition);
}
-IOS::ES::TicketReader GetTicket(const DiscIO::Partition& partition)
+IOS::ES::TicketReader DVDThread::GetTicket(const DiscIO::Partition& partition)
{
- auto& state = Core::System::GetInstance().GetDVDThreadState().GetData();
WaitUntilIdle();
- return state.disc->GetTicket(partition);
+ return m_disc->GetTicket(partition);
}
-bool IsInsertedDiscRunning()
+bool DVDThread::IsInsertedDiscRunning()
{
- auto& state = Core::System::GetInstance().GetDVDThreadState().GetData();
-
- if (!state.disc)
+ if (!m_disc)
return false;
WaitUntilIdle();
- return SConfig::GetInstance().GetGameID() == state.disc->GetGameID();
+ return SConfig::GetInstance().GetGameID() == m_disc->GetGameID();
}
-bool UpdateRunningGameMetadata(const DiscIO::Partition& partition, std::optional<u64> title_id)
+bool DVDThread::UpdateRunningGameMetadata(const DiscIO::Partition& partition,
+ std::optional<u64> title_id)
{
- auto& state = Core::System::GetInstance().GetDVDThreadState().GetData();
-
- if (!state.disc)
+ if (!m_disc)
return false;
WaitUntilIdle();
if (title_id)
{
- const std::optional<u64> volume_title_id = state.disc->GetTitleID(partition);
+ const std::optional<u64> volume_title_id = m_disc->GetTitleID(partition);
if (!volume_title_id || *volume_title_id != *title_id)
return false;
}
- SConfig::GetInstance().SetRunningGameMetadata(*state.disc, partition);
+ SConfig::GetInstance().SetRunningGameMetadata(*m_disc, partition);
return true;
}
-void WaitUntilIdle()
+void DVDThread::WaitUntilIdle()
{
ASSERT(Core::IsCPUThread());
- auto& state = Core::System::GetInstance().GetDVDThreadState().GetData();
-
- while (!state.request_queue.Empty())
- state.result_queue_expanded.Wait();
+ while (!m_request_queue.Empty())
+ m_result_queue_expanded.Wait();
- StopDVDThread(state);
- StartDVDThread(state);
+ StopDVDThread();
+ StartDVDThread();
}
-void StartRead(u64 dvd_offset, u32 length, const DiscIO::Partition& partition,
- DVDInterface::ReplyType reply_type, s64 ticks_until_completion)
+void DVDThread::StartRead(u64 dvd_offset, u32 length, const DiscIO::Partition& partition,
+ DVD::ReplyType reply_type, s64 ticks_until_completion)
{
StartReadInternal(false, 0, dvd_offset, length, partition, reply_type, ticks_until_completion);
}
-void StartReadToEmulatedRAM(u32 output_address, u64 dvd_offset, u32 length,
- const DiscIO::Partition& partition, DVDInterface::ReplyType reply_type,
- s64 ticks_until_completion)
+void DVDThread::StartReadToEmulatedRAM(u32 output_address, u64 dvd_offset, u32 length,
+ const DiscIO::Partition& partition,
+ DVD::ReplyType reply_type, s64 ticks_until_completion)
{
StartReadInternal(true, output_address, dvd_offset, length, partition, reply_type,
ticks_until_completion);
}
-static void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offset, u32 length,
- const DiscIO::Partition& partition,
- DVDInterface::ReplyType reply_type, s64 ticks_until_completion)
+void DVDThread::StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offset, u32 length,
+ const DiscIO::Partition& partition, DVD::ReplyType reply_type,
+ s64 ticks_until_completion)
{
ASSERT(Core::IsCPUThread());
- auto& system = Core::System::GetInstance();
- auto& core_timing = system.GetCoreTiming();
- auto& state = system.GetDVDThreadState().GetData();
+ auto& core_timing = m_system.GetCoreTiming();
ReadRequest request;
@@ -319,22 +240,25 @@ static void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offs
request.partition = partition;
request.reply_type = reply_type;
- u64 id = state.next_id++;
+ u64 id = m_next_id++;
request.id = id;
request.time_started_ticks = core_timing.GetTicks();
request.realtime_started_us = Common::Timer::NowUs();
- state.request_queue.Push(std::move(request));
- state.request_queue_expanded.Set();
+ m_request_queue.Push(std::move(request));
+ m_request_queue_expanded.Set();
- core_timing.ScheduleEvent(ticks_until_completion, state.finish_read, id);
+ core_timing.ScheduleEvent(ticks_until_completion, m_finish_read, id);
}
-static void FinishRead(Core::System& system, u64 id, s64 cycles_late)
+void DVDThread::GlobalFinishRead(Core::System& system, u64 id, s64 cycles_late)
{
- auto& state = system.GetDVDThreadState().GetData();
+ system.GetDVDThread().FinishRead(id, cycles_late);
+}
+void DVDThread::FinishRead(u64 id, s64 cycles_late)
+{
// We can't simply pop result_queue and always get the ReadResult
// we want, because the DVD thread may add ReadResults to the queue
// in a different order than we want to get them. What we do instead
@@ -346,23 +270,23 @@ static void FinishRead(Core::System& system, u64 id, s64 cycles_late)
// When this function is called again later, it will check the map for
// the wanted ReadResult before it starts searching through the queue.
ReadResult result;
- auto it = state.result_map.find(id);
- if (it != state.result_map.end())
+ auto it = m_result_map.find(id);
+ if (it != m_result_map.end())
{
result = std::move(it->second);
- state.result_map.erase(it);
+ m_result_map.erase(it);
}
else
{
while (true)
{
- while (!state.result_queue.Pop(result))
- state.result_queue_expanded.Wait();
+ while (!m_result_queue.Pop(result))
+ m_result_queue_expanded.Wait();
if (result.first.id == id)
break;
else
- state.result_map.emplace(result.first.id, std::move(result));
+ m_result_map.emplace(result.first.id, std::move(result));
}
}
// We have now obtained the right ReadResult.
@@ -376,63 +300,62 @@ static void FinishRead(Core::System& system, u64 id, s64 cycles_late)
"Emulated time including delay: {} us.",
request.realtime_done_us - request.realtime_started_us,
Common::Timer::NowUs() - request.realtime_started_us,
- (system.GetCoreTiming().GetTicks() - request.time_started_ticks) /
+ (m_system.GetCoreTiming().GetTicks() - request.time_started_ticks) /
(SystemTimers::GetTicksPerSecond() / 1000000));
- DVDInterface::DIInterruptType interrupt;
+ auto& dvd_interface = m_system.GetDVDInterface();
+ DVD::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);
- interrupt = DVDInterface::DIInterruptType::DEINT;
+ dvd_interface.SetDriveError(DVD::DriveError::ReadError);
+ interrupt = DVD::DIInterruptType::DEINT;
}
else
{
if (request.copy_to_ram)
{
- auto& memory = system.GetMemory();
+ auto& memory = m_system.GetMemory();
memory.CopyToEmu(request.output_address, buffer.data(), request.length);
}
- interrupt = DVDInterface::DIInterruptType::TCINT;
+ interrupt = DVD::DIInterruptType::TCINT;
}
// 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()
+void DVDThread::DVDThreadMain()
{
- auto& state = Core::System::GetInstance().GetDVDThreadState().GetData();
-
Common::SetCurrentThreadName("DVD thread");
while (true)
{
- state.request_queue_expanded.Wait();
+ m_request_queue_expanded.Wait();
- if (state.dvd_thread_exiting.IsSet())
+ if (m_dvd_thread_exiting.IsSet())
return;
ReadRequest request;
- while (state.request_queue.Pop(request))
+ while (m_request_queue.Pop(request))
{
- state.file_logger.Log(*state.disc, request.partition, request.dvd_offset);
+ m_file_logger.Log(*m_disc, request.partition, request.dvd_offset);
std::vector<u8> buffer(request.length);
- if (!state.disc->Read(request.dvd_offset, request.length, buffer.data(), request.partition))
+ if (!m_disc->Read(request.dvd_offset, request.length, buffer.data(), request.partition))
buffer.resize(0);
request.realtime_done_us = Common::Timer::NowUs();
- state.result_queue.Push(ReadResult(std::move(request), std::move(buffer)));
- state.result_queue_expanded.Set();
+ m_result_queue.Push(ReadResult(std::move(request), std::move(buffer)));
+ m_result_queue_expanded.Set();
- if (state.dvd_thread_exiting.IsSet())
+ if (m_dvd_thread_exiting.IsSet())
return;
}
}
}
-} // namespace DVDThread
+} // namespace DVD
diff --git a/Source/Core/Core/HW/DVD/DVDThread.h b/Source/Core/Core/HW/DVD/DVDThread.h
index 66ffa246ee..6f9e23f37d 100644
--- a/Source/Core/Core/HW/DVD/DVDThread.h
+++ b/Source/Core/Core/HW/DVD/DVDThread.h
@@ -3,21 +3,35 @@
#pragma once
+#include <map>
#include <memory>
#include <optional>
+#include <thread>
+#include <utility>
#include <vector>
#include "Common/CommonTypes.h"
+#include "Common/Event.h"
+#include "Common/Flag.h"
+#include "Common/SPSCQueue.h"
+
+#include "Core/HW/DVD/DVDInterface.h"
+#include "Core/HW/DVD/FileMonitor.h"
+
+#include "DiscIO/Volume.h"
class PointerWrap;
-namespace DiscIO
+namespace Core
{
-struct Partition;
+class System;
}
-
-namespace DVDInterface
+namespace CoreTiming
{
-enum class ReplyType : u32;
+struct EventType;
+}
+namespace DiscIO
+{
+struct Partition;
}
namespace DiscIO
@@ -32,48 +46,103 @@ class TMDReader;
class TicketReader;
} // namespace IOS::ES
-namespace DVDThread
+namespace DVD
{
-class DVDThreadState
+enum class ReplyType : u32;
+
+class DVDThread
{
public:
- DVDThreadState();
- DVDThreadState(const DVDThreadState&) = delete;
- DVDThreadState(DVDThreadState&&) = delete;
- DVDThreadState& operator=(const DVDThreadState&) = delete;
- DVDThreadState& operator=(DVDThreadState&&) = delete;
- ~DVDThreadState();
+ explicit DVDThread(Core::System& system);
+ DVDThread(const DVDThread&) = delete;
+ DVDThread(DVDThread&&) = delete;
+ DVDThread& operator=(const DVDThread&) = delete;
+ DVDThread& operator=(DVDThread&&) = delete;
+ ~DVDThread();
- struct Data;
- Data& GetData() { return *m_data; }
+ void Start();
+ void Stop();
+ void DoState(PointerWrap& p);
+
+ void SetDisc(std::unique_ptr<DiscIO::Volume> disc);
+ bool HasDisc() const;
+
+ bool HasWiiHashes() const;
+ DiscIO::Platform GetDiscType() const;
+ u64 PartitionOffsetToRawOffset(u64 offset, const DiscIO::Partition& partition);
+ IOS::ES::TMDReader GetTMD(const DiscIO::Partition& partition);
+ IOS::ES::TicketReader GetTicket(const DiscIO::Partition& partition);
+ bool IsInsertedDiscRunning();
+ // 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(const DiscIO::Partition& partition,
+ std::optional<u64> title_id = {});
+
+ void StartRead(u64 dvd_offset, u32 length, const DiscIO::Partition& partition,
+ DVD::ReplyType reply_type, s64 ticks_until_completion);
+ void StartReadToEmulatedRAM(u32 output_address, u64 dvd_offset, u32 length,
+ const DiscIO::Partition& partition, DVD::ReplyType reply_type,
+ s64 ticks_until_completion);
private:
- std::unique_ptr<Data> m_data;
-};
+ void StartDVDThread();
+ void StopDVDThread();
+ void WaitUntilIdle();
-void Start();
-void Stop();
-void DoState(PointerWrap& p);
-
-void SetDisc(std::unique_ptr<DiscIO::Volume> disc);
-bool HasDisc();
-
-bool HasWiiHashes();
-DiscIO::Platform GetDiscType();
-u64 PartitionOffsetToRawOffset(u64 offset, const DiscIO::Partition& partition);
-IOS::ES::TMDReader GetTMD(const DiscIO::Partition& partition);
-IOS::ES::TicketReader GetTicket(const DiscIO::Partition& partition);
-bool IsInsertedDiscRunning();
-// 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(const DiscIO::Partition& partition,
- std::optional<u64> title_id = {});
-
-void StartRead(u64 dvd_offset, u32 length, const DiscIO::Partition& partition,
- DVDInterface::ReplyType reply_type, s64 ticks_until_completion);
-void StartReadToEmulatedRAM(u32 output_address, u64 dvd_offset, u32 length,
- const DiscIO::Partition& partition, DVDInterface::ReplyType reply_type,
- s64 ticks_until_completion);
-} // namespace DVDThread
+ void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offset, u32 length,
+ const DiscIO::Partition& partition, DVD::ReplyType reply_type,
+ s64 ticks_until_completion);
+
+ static void GlobalFinishRead(Core::System& system, u64 id, s64 cycles_late);
+ void FinishRead(u64 id, s64 cycles_late);
+
+ void DVDThreadMain();
+
+ struct ReadRequest
+ {
+ bool copy_to_ram = false;
+ u32 output_address = 0;
+ u64 dvd_offset = 0;
+ u32 length = 0;
+ DiscIO::Partition partition{};
+
+ // This determines which code DVDInterface will run to reply
+ // to the emulated software. We can't use callbacks,
+ // because function pointers can't be stored in savestates.
+ DVD::ReplyType reply_type = DVD::ReplyType::NoReply;
+
+ // IDs are used to uniquely identify a request. They must not be
+ // identical to IDs of any other requests that currently exist, but
+ // it's fine to re-use IDs of requests that have existed in the past.
+ u64 id = 0;
+
+ // Only used for logging
+ u64 time_started_ticks = 0;
+ u64 realtime_started_us = 0;
+ u64 realtime_done_us = 0;
+ };
+
+ using ReadResult = std::pair<ReadRequest, std::vector<u8>>;
+
+ CoreTiming::EventType* m_finish_read = nullptr;
+
+ u64 m_next_id = 0;
+
+ std::thread m_dvd_thread;
+ Common::Event m_request_queue_expanded; // Is set by CPU thread
+ Common::Event m_result_queue_expanded; // Is set by DVD thread
+ Common::Flag m_dvd_thread_exiting = Common::Flag(false); // Is set by CPU thread
+
+ Common::SPSCQueue<ReadRequest, false> m_request_queue;
+ Common::SPSCQueue<ReadResult, false> m_result_queue;
+ std::map<u64, ReadResult> m_result_map;
+
+ std::unique_ptr<DiscIO::Volume> m_disc;
+
+ FileMonitor::FileLogger m_file_logger;
+
+ Core::System& m_system;
+};
+} // namespace DVD
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..24e1c0a3be 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<u32>(&g_gpio_out.m_hex),
- MMIO::ComplexWrite<u32>([](Core::System&, u32, u32 val) {
+ MMIO::ComplexWrite<u32>([](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(DVD::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<u32>([](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<u32>([](Core::System&, u32) {
+ mmio->Register(base | GPIOB_IN, MMIO::ComplexRead<u32>([](Core::System& system, u32) {
Common::Flags<GPIO> gpio_in;
- gpio_in[GPIO::SLOT_IN] = DVDInterface::IsDiscInside();
+ gpio_in[GPIO::SLOT_IN] = system.GetDVDInterface().IsDiscInside();
return gpio_in.m_hex;
}),
MMIO::Nop<u32>());
@@ -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<u32>(&g_gpio_out.m_hex),
- MMIO::ComplexWrite<u32>([](Core::System&, u32, u32 val) {
+ MMIO::ComplexWrite<u32>([](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(DVD::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<u32>([](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<u32>([](Core::System&, u32) {
+ mmio->Register(base | GPIO_IN, MMIO::ComplexRead<u32>([](Core::System& system, u32) {
Common::Flags<GPIO> gpio_in;
- gpio_in[GPIO::SLOT_IN] = DVDInterface::IsDiscInside();
+ gpio_in[GPIO::SLOT_IN] = system.GetDVDInterface().IsDiscInside();
return gpio_in.m_hex;
}),
MMIO::Nop<u32>());
mmio->Register(base | HW_RESETS, MMIO::DirectRead<u32>(&resets),
- MMIO::ComplexWrite<u32>([](Core::System&, u32, u32 val) {
+ MMIO::ComplexWrite<u32>([](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..a270e7351a 100644
--- a/Source/Core/Core/IOS/DI/DI.cpp
+++ b/Source/Core/Core/IOS/DI/DI.cpp
@@ -214,8 +214,8 @@ std::optional<DIDevice::DIResult> 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, DVD::ReplyType::IOS);
return {};
}
case DIIoctl::DVDLowWaitForCoverClose:
@@ -274,12 +274,12 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
}
case DIIoctl::DVDLowMaskCoverInterrupt:
INFO_LOG_FMT(IOS_DI, "DVDLowMaskCoverInterrupt");
- DVDInterface::SetInterruptEnabled(DVDInterface::DIInterruptType::CVRINT, false);
+ system.GetDVDInterface().SetInterruptEnabled(DVD::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(DVD::DIInterruptType::CVRINT);
return DIResult::Success;
case DIIoctl::DVDLowUnmaskStatusInterrupts:
INFO_LOG_FMT(IOS_DI, "DVDLowUnmaskStatusInterrupts");
@@ -287,13 +287,15 @@ std::optional<DIDevice::DIResult> 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(DVD::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::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
DIMAR = request.buffer_out;
m_last_length = length;
DILENGTH = length;
- DVDInterface::ForceOutOfBoundsRead(DVDInterface::ReplyType::IOS);
+ system.GetDVDInterface().ForceOutOfBoundsRead(DVD::ReplyType::IOS);
return {};
}
else
@@ -579,7 +581,7 @@ std::optional<DIDevice::DIResult> DIDevice::StartDMATransfer(u32 command_length,
m_last_length = command_length;
DILENGTH = command_length;
- DVDInterface::ExecuteCommand(DVDInterface::ReplyType::IOS);
+ Core::System::GetInstance().GetDVDInterface().ExecuteCommand(DVD::ReplyType::IOS);
// Reply will be posted when done by FinishIOCtl.
return {};
}
@@ -597,7 +599,7 @@ std::optional<DIDevice::DIResult> DIDevice::StartImmediateTransfer(const IOCtlRe
m_executing_command->m_copy_diimmbuf = write_to_buf;
- DVDInterface::ExecuteCommand(DVDInterface::ReplyType::IOS);
+ Core::System::GetInstance().GetDVDInterface().ExecuteCommand(DVD::ReplyType::IOS);
// Reply will be posted when done by FinishIOCtl.
return {};
}
@@ -612,15 +614,15 @@ static std::shared_ptr<DIDevice> GetDevice()
return std::static_pointer_cast<DIDevice>(di);
}
-void DIDevice::InterruptFromDVDInterface(DVDInterface::DIInterruptType interrupt_type)
+void DIDevice::InterruptFromDVDInterface(DVD::DIInterruptType interrupt_type)
{
DIResult result;
switch (interrupt_type)
{
- case DVDInterface::DIInterruptType::TCINT:
+ case DVD::DIInterruptType::TCINT:
result = DIResult::Success;
break;
- case DVDInterface::DIInterruptType::DEINT:
+ case DVD::DIInterruptType::DEINT:
result = DIResult::DriveError;
break;
default:
@@ -739,11 +741,12 @@ std::optional<IPCReply> DIDevice::IOCtlV(const IOCtlVRequest& request)
INFO_LOG_FMT(IOS_DI, "DVDLowOpenPartition: partition_offset {:#011x}", partition_offset);
// Read TMD to the buffer
- const ES::TMDReader tmd = DVDThread::GetTMD(m_current_partition);
+ auto& dvd_thread = system.GetDVDThread();
+ const ES::TMDReader tmd = dvd_thread.GetTMD(m_current_partition);
const std::vector<u8>& raw_tmd = tmd.GetBytes();
memory.CopyToEmu(request.io_vectors[0].address, raw_tmd.data(), raw_tmd.size());
- ReturnCode es_result = m_ios.GetES()->DIVerify(tmd, DVDThread::GetTicket(m_current_partition));
+ ReturnCode es_result = m_ios.GetES()->DIVerify(tmd, dvd_thread.GetTicket(m_current_partition));
memory.Write_U32(es_result, request.io_vectors[1].address);
return_value = DIResult::Success;
@@ -814,12 +817,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(DVD::DIInterruptType::TCINT);
+ di.ClearInterrupt(DVD::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(DVD::DIInterruptType::TCINT, true);
+ di.SetInterruptEnabled(DVD::DIInterruptType::DEINT, true);
+ di.SetInterruptEnabled(DVD::DIInterruptType::CVRINT, false);
// Close the current partition, if there is one
ChangePartition(DiscIO::PARTITION_NONE);
}
diff --git a/Source/Core/Core/IOS/DI/DI.h b/Source/Core/Core/IOS/DI/DI.h
index f2d5307f68..9b8acb37b9 100644
--- a/Source/Core/Core/IOS/DI/DI.h
+++ b/Source/Core/Core/IOS/DI/DI.h
@@ -15,7 +15,7 @@
class CBoot;
class PointerWrap;
-namespace DVDInterface
+namespace DVD
{
enum class DIInterruptType : int;
}
@@ -40,7 +40,7 @@ class DIDevice : public Device
public:
DIDevice(Kernel& ios, const std::string& device_name);
- static void InterruptFromDVDInterface(DVDInterface::DIInterruptType interrupt_type);
+ static void InterruptFromDVDInterface(DVD::DIInterruptType interrupt_type);
static DiscIO::Partition GetCurrentPartition();
void DoState(PointerWrap& p) override;
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..40260b8b9d 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_dvd_thread(system), m_gp_fifo(system), m_ppc_state(PowerPC::ppcState)
{
}
@@ -50,8 +50,8 @@ struct System::Impl
CommandProcessor::CommandProcessorManager m_command_processor;
CPU::CPUManager m_cpu;
DSP::DSPManager m_dsp;
- DVDInterface::DVDInterfaceState m_dvd_interface_state;
- DVDThread::DVDThreadState m_dvd_thread_state;
+ DVD::DVDInterface m_dvd_interface;
+ DVD::DVDThread m_dvd_thread;
ExpansionInterface::ExpansionInterfaceState m_expansion_interface_state;
Fifo::FifoManager m_fifo;
GeometryShaderManager m_geometry_shader_manager;
@@ -138,14 +138,14 @@ DSP::DSPManager& System::GetDSP() const
return m_impl->m_dsp;
}
-DVDInterface::DVDInterfaceState& System::GetDVDInterfaceState() const
+DVD::DVDInterface& System::GetDVDInterface() const
{
- return m_impl->m_dvd_interface_state;
+ return m_impl->m_dvd_interface;
}
-DVDThread::DVDThreadState& System::GetDVDThreadState() const
+DVD::DVDThread& System::GetDVDThread() const
{
- return m_impl->m_dvd_thread_state;
+ return m_impl->m_dvd_thread;
}
ExpansionInterface::ExpansionInterfaceState& System::GetExpansionInterfaceState() const
diff --git a/Source/Core/Core/System.h b/Source/Core/Core/System.h
index 4ab7247fc3..847d108124 100644
--- a/Source/Core/Core/System.h
+++ b/Source/Core/Core/System.h
@@ -31,14 +31,11 @@ namespace DSP
{
class DSPManager;
}
-namespace DVDInterface
+namespace DVD
{
-class DVDInterfaceState;
-}
-namespace DVDThread
-{
-class DVDThreadState;
-}
+class DVDInterface;
+class DVDThread;
+} // namespace DVD
namespace ExpansionInterface
{
class ExpansionInterfaceState;
@@ -127,8 +124,8 @@ public:
CoreTiming::CoreTimingManager& GetCoreTiming() const;
CommandProcessor::CommandProcessorManager& GetCommandProcessor() const;
DSP::DSPManager& GetDSP() const;
- DVDInterface::DVDInterfaceState& GetDVDInterfaceState() const;
- DVDThread::DVDThreadState& GetDVDThreadState() const;
+ DVD::DVDInterface& GetDVDInterface() const;
+ DVD::DVDThread& GetDVDThread() const;
ExpansionInterface::ExpansionInterfaceState& GetExpansionInterfaceState() const;
Fifo::FifoManager& GetFifo() const;
GeometryShaderManager& GetGeometryShaderManager() 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..ac34999c4d 100644
--- a/Source/Core/DolphinQt/MainWindow.cpp
+++ b/Source/Core/DolphinQt/MainWindow.cpp
@@ -746,12 +746,14 @@ void MainWindow::ChangeDisc()
std::vector<std::string> 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(DVD::EjectCause::User); });
}
void MainWindow::OpenUserFolder()