diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index bd69afeb80..99bc5ced18 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -83,6 +83,7 @@ set(SRCS ActionReplay.cpp HW/DSPLLE/DSPLLE.cpp HW/DSPLLE/DSPLLETools.cpp HW/DVDInterface.cpp + HW/DVDThread.cpp HW/EXI_Channel.cpp HW/EXI.cpp HW/EXI_Device.cpp diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index 5e54a4fab7..05af583ed2 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -115,6 +115,7 @@ + @@ -325,6 +326,7 @@ + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 92d88bc479..a374defc07 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -315,6 +315,9 @@ HW %28Flipper/Hollywood%29\DI - Drive Interface + + HW %28Flipper/Hollywood%29\DI - Drive Interface + HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes @@ -850,6 +853,9 @@ HW %28Flipper/Hollywood%29\DI - Drive Interface + + HW %28Flipper/Hollywood%29\DI - Drive Interface + HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes diff --git a/Source/Core/Core/HW/DVDInterface.cpp b/Source/Core/Core/HW/DVDInterface.cpp index e0356ec12a..a60c21f7b9 100644 --- a/Source/Core/Core/HW/DVDInterface.cpp +++ b/Source/Core/Core/HW/DVDInterface.cpp @@ -19,6 +19,7 @@ #include "Core/Movie.h" #include "Core/HW/AudioInterface.h" #include "Core/HW/DVDInterface.h" +#include "Core/HW/DVDThread.h" #include "Core/HW/Memmap.h" #include "Core/HW/MMIO.h" #include "Core/HW/ProcessorInterface.h" @@ -220,22 +221,6 @@ union UDICFG UDICFG(u32 _hex) {Hex = _hex;} }; -struct DVDReadCommand -{ - bool is_valid; - - u64 DVD_offset; - u32 output_address; - u32 length; - bool decrypt; - - DIInterruptType interrupt_type; - - // Used to notify emulated software after executing command. - // Pointers don't work with savestates, so CoreTiming events are used instead - int callback_event_type; -}; - static std::unique_ptr s_inserted_volume; // STATE_TO_SAVE @@ -249,8 +234,6 @@ static UDICR m_DICR; static UDIIMMBUF m_DIIMMBUF; static UDICFG m_DICFG; -static DVDReadCommand current_read_command; - static u32 AudioPos; static u32 CurrentStart; static u32 CurrentLength; @@ -263,7 +246,6 @@ static bool g_bDiscInside = false; bool g_bStream = false; static bool g_bStopAtTrackEnd = false; static int finish_execute_command = 0; -static int finish_execute_read_command = 0; static int dtk = 0; static u64 g_last_read_offset; @@ -284,8 +266,8 @@ void UpdateInterrupts(); void GenerateDIInterrupt(DIInterruptType _DVDInterrupt); void WriteImmediate(u32 value, u32 output_address, bool write_to_DIIMMBUF); -DVDReadCommand ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32 output_length, - bool decrypt, DIInterruptType* interrupt_type, u64* ticks_until_completion); +bool ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32 output_length, bool decrypt, + int callback_event_type, DIInterruptType* interrupt_type, u64* ticks_until_completion); u64 SimulateDiscReadTime(u64 offset, u32 length); s64 CalculateRawDiscReadTime(u64 offset, s64 length); @@ -301,8 +283,6 @@ void DoState(PointerWrap &p) p.Do(m_DIIMMBUF); p.DoPOD(m_DICFG); - p.Do(current_read_command); - p.Do(NextStart); p.Do(AudioPos); p.Do(NextLength); @@ -318,6 +298,8 @@ void DoState(PointerWrap &p) p.Do(g_last_read_time); p.Do(g_bStopAtTrackEnd); + + DVDThread::DoState(p); } static void FinishExecuteCommand(u64 userdata, int cyclesLate) @@ -330,30 +312,6 @@ static void FinishExecuteCommand(u64 userdata, int cyclesLate) } } -static void FinishExecuteReadCommand(u64 userdata, int cyclesLate) -{ - if (!current_read_command.is_valid) - { - PanicAlert("DVDInterface: There is no command to execute!"); - } - else - { - // Here is the actual disc reading - if (!DVDRead(current_read_command.DVD_offset, current_read_command.output_address, - current_read_command.length, current_read_command.decrypt)) - { - PanicAlertT("Can't read from DVD_Plugin - DVD-Interface: Fatal Error"); - } - } - - // The command is marked as invalid because it shouldn't be used again - current_read_command.is_valid = false; - - // The final step is to notify the emulated software that the command has been executed - CoreTiming::ScheduleEvent_Immediate(current_read_command.callback_event_type, - current_read_command.interrupt_type); -} - static u32 ProcessDTKSamples(short *tempPCM, u32 num_samples) { u32 samples_processed = 0; @@ -417,6 +375,8 @@ static void DTKStreamingCallback(u64 userdata, int cyclesLate) void Init() { + DVDThread::Start(); + m_DISR.Hex = 0; m_DICVR.Hex = 1; // Disc Channel relies on cover being open when no disc is inserted m_DICMDBUF[0].Hex = 0; @@ -429,8 +389,6 @@ void Init() m_DICFG.Hex = 0; m_DICFG.CONFIG = 1; // Disable bootrom descrambler - current_read_command.is_valid = false; - AudioPos = 0; NextStart = 0; NextLength = 0; @@ -449,7 +407,6 @@ void Init() insertDisc = CoreTiming::RegisterEvent("InsertDisc", InsertDiscCallback); finish_execute_command = CoreTiming::RegisterEvent("FinishExecuteCommand", FinishExecuteCommand); - finish_execute_read_command = CoreTiming::RegisterEvent("FinishExecuteReadCommand", FinishExecuteReadCommand); dtk = CoreTiming::RegisterEvent("StreamingTimer", DTKStreamingCallback); CoreTiming::ScheduleEvent(0, dtk); @@ -457,6 +414,7 @@ void Init() void Shutdown() { + DVDThread::Stop(); s_inserted_volume.reset(); } @@ -687,19 +645,21 @@ void WriteImmediate(u32 value, u32 output_address, bool write_to_DIIMMBUF) Memory::Write_U32(value, output_address); } -// If the returned DVDReadCommand has is_valid set to true, -// FinishExecuteReadCommand must be used to finish executing it -DVDReadCommand ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32 output_length, - bool decrypt, DIInterruptType* interrupt_type, u64* ticks_until_completion) +// Iff false is returned, ScheduleEvent must be used to finish executing the command +bool ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32 output_length, bool decrypt, + int callback_event_type, DIInterruptType* interrupt_type, u64* ticks_until_completion) { - DVDReadCommand command; - if (!g_bDiscInside) { + // Disc read fails g_ErrorCode = ERROR_NO_DISK | ERROR_COVER_H; *interrupt_type = INT_DEINT; - command.is_valid = false; - return command; + return false; + } + else + { + // Disc read succeeds + *interrupt_type = INT_TCINT; } if (DVD_length > output_length) @@ -714,13 +674,9 @@ DVDReadCommand ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_le else *ticks_until_completion = SimulateDiscReadTime(DVD_offset, DVD_length); - *interrupt_type = INT_TCINT; - command.is_valid = true; - command.DVD_offset = DVD_offset; - command.output_address = output_address; - command.length = DVD_length; - command.decrypt = decrypt; - return command; + DVDThread::StartRead(DVD_offset, output_address, DVD_length, decrypt, + callback_event_type, (int)*ticks_until_completion); + return true; } // When the command has finished executing, callback_event_type @@ -731,8 +687,7 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr { DIInterruptType interrupt_type = INT_TCINT; u64 ticks_until_completion = SystemTimers::GetTicksPerSecond() / 15000; - DVDReadCommand read_command; - read_command.is_valid = false; + bool command_handled_by_thread = false; bool GCAM = (SConfig::GetInstance().m_SIDevice[0] == SIDEVICE_AM_BASEBOARD) && (SConfig::GetInstance().m_EXIDevice[2] == EXIDEVICE_AM_BASEBOARD); @@ -777,15 +732,15 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr // Only seems to be used from WII_IPC, not through direct access case DVDLowReadDiskID: INFO_LOG(DVDINTERFACE, "DVDLowReadDiskID"); - read_command = ExecuteReadCommand(0, output_address, 0x20, output_length, - false, &interrupt_type, &ticks_until_completion); + command_handled_by_thread = ExecuteReadCommand(0, output_address, 0x20, output_length, false, + callback_event_type, &interrupt_type, &ticks_until_completion); break; // Only used from WII_IPC. This is the only read command that decrypts data case DVDLowRead: INFO_LOG(DVDINTERFACE, "DVDLowRead: DVDAddr: 0x%09" PRIx64 ", Size: 0x%x", (u64)command_2 << 2, command_1); - read_command = ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length, - true, &interrupt_type, &ticks_until_completion); + command_handled_by_thread = ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length, true, + callback_event_type, &interrupt_type, &ticks_until_completion); break; // Probably only used by Wii @@ -864,8 +819,8 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr (command_2 > 0x7ed40000 && command_2 < 0x7ed40008) || (((command_2 + command_1) > 0x7ed40000) && (command_2 + command_1) < 0x7ed40008))) { - read_command = ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length, - false, &interrupt_type, &ticks_until_completion); + command_handled_by_thread = ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length, false, + callback_event_type, &interrupt_type, &ticks_until_completion); } else { @@ -961,15 +916,15 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr } } - read_command = ExecuteReadCommand(iDVDOffset, output_address, command_2, output_length, - false, &interrupt_type, &ticks_until_completion); + command_handled_by_thread = ExecuteReadCommand(iDVDOffset, output_address, command_2, output_length, false, + callback_event_type, &interrupt_type, &ticks_until_completion); } break; case 0x40: // Read DiscID INFO_LOG(DVDINTERFACE, "Read DiscID %08x", Memory::Read_U32(output_address)); - read_command = ExecuteReadCommand(0, output_address, 0x20, output_length, - false, &interrupt_type, &ticks_until_completion); + command_handled_by_thread = ExecuteReadCommand(0, output_address, 0x20, output_length, false, + callback_event_type, &interrupt_type, &ticks_until_completion); break; default: @@ -1304,23 +1259,10 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr break; } - // The command will finish executing after a delay, + // The command will finish executing after a delay // to simulate the speed of a real disc drive - if (read_command.is_valid) - { - // We schedule a FinishExecuteReadCommand (which will call the actual callback - // once it's done) so that the data transfer isn't completed too early. - // Most games don't care about it, but if it's done wrong, Resident Evil 3 - // plays some extra noise when playing the menu selection sound effect. - read_command.callback_event_type = callback_event_type; - read_command.interrupt_type = interrupt_type; - current_read_command = read_command; - CoreTiming::ScheduleEvent((int)ticks_until_completion, finish_execute_read_command); - } - else - { + if (!command_handled_by_thread) CoreTiming::ScheduleEvent((int)ticks_until_completion, callback_event_type, interrupt_type); - } } // Simulates the timing aspects of reading data from a disc. diff --git a/Source/Core/Core/HW/DVDThread.cpp b/Source/Core/Core/HW/DVDThread.cpp new file mode 100644 index 0000000000..1182b6c1ee --- /dev/null +++ b/Source/Core/Core/HW/DVDThread.cpp @@ -0,0 +1,75 @@ +// Copyright 2015 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include + +#include "Common/ChunkFile.h" +#include "Common/CommonTypes.h" +#include "Common/MsgHandler.h" + +#include "Core/CoreTiming.h" +#include "Core/HW/DVDInterface.h" +#include "Core/HW/DVDThread.h" + +#include "DiscIO/Volume.h" + +namespace DVDThread +{ + +static void FinishRead(u64 userdata, int cyclesLate); +static int s_finish_read; + +static u64 s_dvd_offset; +static u32 s_output_address; +static u32 s_length; +static bool s_decrypt; + +// Used to notify emulated software after executing command. +// Pointers don't work with savestates, so CoreTiming events are used instead +static int s_callback_event_type; + +void Start() +{ + s_finish_read = CoreTiming::RegisterEvent("FinishReadDVDThread", FinishRead); +} + +void Stop() +{ + +} + +void DoState(PointerWrap &p) +{ + p.Do(s_dvd_offset); + p.Do(s_output_address); + p.Do(s_length); + p.Do(s_decrypt); + p.Do(s_callback_event_type); +} + +void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt, + int callback_event_type, int ticks_until_completion) +{ + s_dvd_offset = dvd_offset; + s_output_address = output_address; + s_length = length; + s_decrypt = decrypt; + s_callback_event_type = callback_event_type; + CoreTiming::ScheduleEvent(ticks_until_completion, s_finish_read); +} + +static void FinishRead(u64 userdata, int cyclesLate) +{ + // Here is the actual disc reading + if (!DVDInterface::DVDRead(s_dvd_offset, s_output_address, s_length, s_decrypt)) + { + PanicAlertT("The disc could not be read (at 0x%" PRIx64 " - 0x%" PRIx64 ").", + s_dvd_offset, s_dvd_offset + s_length); + } + + // Notify the emulated software that the command has been executed + CoreTiming::ScheduleEvent_Immediate(s_callback_event_type, DVDInterface::INT_TCINT); +} + +} diff --git a/Source/Core/Core/HW/DVDThread.h b/Source/Core/Core/HW/DVDThread.h new file mode 100644 index 0000000000..0aa5f296cb --- /dev/null +++ b/Source/Core/Core/HW/DVDThread.h @@ -0,0 +1,20 @@ +// Copyright 2015 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "Common/ChunkFile.h" +#include "Common/CommonTypes.h" + +namespace DVDThread +{ + +void Start(); +void Stop(); +void DoState(PointerWrap &p); + +void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt, + int callback_event_type, int ticks_until_completion); + +} diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 9a0711e6c2..c14c9dc9ef 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -68,7 +68,7 @@ static Common::Event g_compressAndDumpStateSyncEvent; static std::thread g_save_thread; // Don't forget to increase this after doing changes on the savestate system -static const u32 STATE_VERSION = 48; // Last changed in PR 3108 +static const u32 STATE_VERSION = 49; // Last changed in PR 2149 // Maps savestate versions to Dolphin versions. // Versions after 42 don't need to be added to this list,