Merge pull request #2149 from JosJuice/async-disc-io
Read disc data asynchronously in a new thread
This commit is contained in:
commit
24c7d23073
|
@ -2,6 +2,7 @@
|
|||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonPaths.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
|
@ -32,6 +33,15 @@
|
|||
#include "DiscIO/NANDContentLoader.h"
|
||||
#include "DiscIO/VolumeCreator.h"
|
||||
|
||||
bool CBoot::DVDRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt)
|
||||
{
|
||||
std::vector<u8> buffer(length);
|
||||
if (!DVDInterface::GetVolume().Read(dvd_offset, length, buffer.data(), decrypt))
|
||||
return false;
|
||||
Memory::CopyToEmu(output_address, buffer.data(), length);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CBoot::Load_FST(bool _bIsWii)
|
||||
{
|
||||
if (!DVDInterface::VolumeIsValid())
|
||||
|
@ -40,7 +50,7 @@ void CBoot::Load_FST(bool _bIsWii)
|
|||
const DiscIO::IVolume& volume = DVDInterface::GetVolume();
|
||||
|
||||
// copy first 20 bytes of disc to start of Mem 1
|
||||
DVDInterface::DVDRead(/*offset*/0, /*address*/0, /*length*/0x20, false);
|
||||
DVDRead(/*offset*/0, /*address*/0, /*length*/0x20, false);
|
||||
|
||||
// copy of game id
|
||||
Memory::Write_U32(Memory::Read_U32(0x0000), 0x3180);
|
||||
|
@ -57,7 +67,7 @@ void CBoot::Load_FST(bool _bIsWii)
|
|||
Memory::Write_U32(arenaHigh, 0x00000034);
|
||||
|
||||
// load FST
|
||||
DVDInterface::DVDRead(fstOffset, arenaHigh, fstSize, _bIsWii);
|
||||
DVDRead(fstOffset, arenaHigh, fstSize, _bIsWii);
|
||||
Memory::Write_U32(arenaHigh, 0x00000038);
|
||||
Memory::Write_U32(maxFstSize, 0x0000003c);
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ public:
|
|||
std::string* title_id = nullptr);
|
||||
|
||||
private:
|
||||
static bool DVDRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt);
|
||||
static void RunFunction(u32 _iAddr);
|
||||
|
||||
static void UpdateDebugger_MapLoaded();
|
||||
|
|
|
@ -59,7 +59,7 @@ bool CBoot::EmulatedBS2_GC(bool skipAppLoader)
|
|||
|
||||
// It's possible to boot DOL and ELF files without a disc inserted
|
||||
if (DVDInterface::VolumeIsValid())
|
||||
DVDInterface::DVDRead(/*offset*/0x00000000, /*address*/0x00000000, 0x20, false); // write disc info
|
||||
DVDRead(/*offset*/0x00000000, /*address*/0x00000000, 0x20, false); // write disc info
|
||||
|
||||
PowerPC::HostWrite_U32(0x0D15EA5E, 0x80000020); // Booted from bootrom. 0xE5207C22 = booted from jtag
|
||||
PowerPC::HostWrite_U32(Memory::REALRAM_SIZE, 0x80000028); // Physical Memory Size (24MB on retail)
|
||||
|
@ -98,7 +98,7 @@ bool CBoot::EmulatedBS2_GC(bool skipAppLoader)
|
|||
INFO_LOG(BOOT, "GC BS2: Not running apploader!");
|
||||
return false;
|
||||
}
|
||||
DVDInterface::DVDRead(iAppLoaderOffset + 0x20, 0x01200000, iAppLoaderSize, false);
|
||||
DVDRead(iAppLoaderOffset + 0x20, 0x01200000, iAppLoaderSize, false);
|
||||
|
||||
// Setup pointers like real BS2 does
|
||||
if (SConfig::GetInstance().bNTSC)
|
||||
|
@ -149,7 +149,7 @@ bool CBoot::EmulatedBS2_GC(bool skipAppLoader)
|
|||
u32 iDVDOffset = PowerPC::Read_U32(0x8130000c);
|
||||
|
||||
INFO_LOG(MASTER_LOG, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset, iRamAddress, iLength);
|
||||
DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength, false);
|
||||
DVDRead(iDVDOffset, iRamAddress, iLength, false);
|
||||
|
||||
} while (PowerPC::ppcState.gpr[3] != 0x00);
|
||||
|
||||
|
@ -256,7 +256,7 @@ bool CBoot::SetupWiiMemory(DiscIO::IVolume::ECountry country)
|
|||
|
||||
// When booting a WAD or the system menu, there will probably not be a disc inserted
|
||||
if (DVDInterface::VolumeIsValid())
|
||||
DVDInterface::DVDRead(0x00000000, 0x00000000, 0x20, false); // Game Code
|
||||
DVDRead(0x00000000, 0x00000000, 0x20, false); // Game Code
|
||||
|
||||
Memory::Write_U32(0x0D15EA5E, 0x00000020); // Another magic word
|
||||
Memory::Write_U32(0x00000001, 0x00000024); // Unknown
|
||||
|
@ -333,10 +333,10 @@ bool CBoot::EmulatedBS2_Wii()
|
|||
if (DVDInterface::VolumeIsValid() && DVDInterface::GetVolume().GetVolumeType() == DiscIO::IVolume::WII_DISC)
|
||||
{
|
||||
// This is some kind of consistency check that is compared to the 0x00
|
||||
// values as the game boots. This location keep the 4 byte ID for as long
|
||||
// values as the game boots. This location keeps the 4 byte ID for as long
|
||||
// as the game is running. The 6 byte ID at 0x00 is overwritten sometime
|
||||
// after this check during booting.
|
||||
DVDInterface::DVDRead(0, 0x3180, 4, true);
|
||||
DVDRead(0, 0x3180, 4, true);
|
||||
|
||||
// Set up MSR and the BAT SPR registers.
|
||||
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
|
||||
|
@ -376,7 +376,7 @@ bool CBoot::EmulatedBS2_Wii()
|
|||
ERROR_LOG(BOOT, "Invalid apploader. Probably your image is corrupted.");
|
||||
return false;
|
||||
}
|
||||
DVDInterface::DVDRead(iAppLoaderOffset + 0x20, 0x01200000, iAppLoaderSize, true);
|
||||
DVDRead(iAppLoaderOffset + 0x20, 0x01200000, iAppLoaderSize, true);
|
||||
|
||||
//call iAppLoaderEntry
|
||||
DEBUG_LOG(BOOT, "Call iAppLoaderEntry");
|
||||
|
@ -414,7 +414,7 @@ bool CBoot::EmulatedBS2_Wii()
|
|||
u32 iDVDOffset = PowerPC::Read_U32(0x8130000c) << 2;
|
||||
|
||||
INFO_LOG(BOOT, "DVDRead: offset: %08x memOffset: %08x length: %i", iDVDOffset, iRamAddress, iLength);
|
||||
DVDInterface::DVDRead(iDVDOffset, iRamAddress, iLength, true);
|
||||
DVDRead(iDVDOffset, iRamAddress, iLength, true);
|
||||
} while (PowerPC::ppcState.gpr[3] != 0x00);
|
||||
|
||||
// iAppLoaderClose
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -115,6 +115,7 @@
|
|||
<ClCompile Include="HW\DSPLLE\DSPLLETools.cpp" />
|
||||
<ClCompile Include="HW\DSPLLE\DSPSymbols.cpp" />
|
||||
<ClCompile Include="HW\DVDInterface.cpp" />
|
||||
<ClCompile Include="HW\DVDThread.cpp" />
|
||||
<ClCompile Include="HW\EXI.cpp" />
|
||||
<ClCompile Include="HW\EXI_Channel.cpp" />
|
||||
<ClCompile Include="HW\EXI_Device.cpp" />
|
||||
|
@ -325,6 +326,7 @@
|
|||
<ClInclude Include="HW\DSPLLE\DSPLLETools.h" />
|
||||
<ClInclude Include="HW\DSPLLE\DSPSymbols.h" />
|
||||
<ClInclude Include="HW\DVDInterface.h" />
|
||||
<ClInclude Include="HW\DVDThread.h" />
|
||||
<ClInclude Include="HW\EXI.h" />
|
||||
<ClInclude Include="HW\EXI_Channel.h" />
|
||||
<ClInclude Include="HW\EXI_Device.h" />
|
||||
|
|
|
@ -315,6 +315,9 @@
|
|||
<ClCompile Include="HW\DVDInterface.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DI - Drive Interface</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\DVDThread.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DI - Drive Interface</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HW\DSPHLE\UCodes\AX.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClCompile>
|
||||
|
@ -850,6 +853,9 @@
|
|||
<ClInclude Include="HW\DVDInterface.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DI - Drive Interface</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\DVDThread.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DI - Drive Interface</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\DSPHLE\UCodes\AX.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -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<DiscIO::IVolume> 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,32 +312,11 @@ 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)
|
||||
{
|
||||
// TODO: Read audio data using the DVD thread instead of blocking on it?
|
||||
DVDThread::WaitUntilIdle();
|
||||
|
||||
u32 samples_processed = 0;
|
||||
do
|
||||
{
|
||||
|
@ -417,6 +378,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 +392,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 +410,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 +417,7 @@ void Init()
|
|||
|
||||
void Shutdown()
|
||||
{
|
||||
DVDThread::Stop();
|
||||
s_inserted_volume.reset();
|
||||
}
|
||||
|
||||
|
@ -467,12 +428,14 @@ const DiscIO::IVolume& GetVolume()
|
|||
|
||||
bool SetVolumeName(const std::string& disc_path)
|
||||
{
|
||||
DVDThread::WaitUntilIdle();
|
||||
s_inserted_volume = std::unique_ptr<DiscIO::IVolume>(DiscIO::CreateVolumeFromFilename(disc_path));
|
||||
return VolumeIsValid();
|
||||
}
|
||||
|
||||
bool SetVolumeDirectory(const std::string& full_path, bool is_wii, const std::string& apploader_path, const std::string& DOL_path)
|
||||
{
|
||||
DVDThread::WaitUntilIdle();
|
||||
s_inserted_volume = std::unique_ptr<DiscIO::IVolume>(DiscIO::CreateVolumeFromDirectory(full_path, is_wii, apploader_path, DOL_path));
|
||||
return VolumeIsValid();
|
||||
}
|
||||
|
@ -501,9 +464,9 @@ bool IsDiscInside()
|
|||
// that the userdata string exists when called
|
||||
void EjectDiscCallback(u64 userdata, int cyclesLate)
|
||||
{
|
||||
// Empty the drive
|
||||
SetDiscInside(false);
|
||||
DVDThread::WaitUntilIdle();
|
||||
s_inserted_volume.reset();
|
||||
SetDiscInside(false);
|
||||
}
|
||||
|
||||
void InsertDiscCallback(u64 userdata, int cyclesLate)
|
||||
|
@ -551,13 +514,9 @@ void SetLidOpen(bool _bOpen)
|
|||
GenerateDIInterrupt(INT_CVRINT);
|
||||
}
|
||||
|
||||
bool DVDRead(u64 _iDVDOffset, u32 _iRamAddress, u32 _iLength, bool decrypt)
|
||||
{
|
||||
return s_inserted_volume->Read(_iDVDOffset, _iLength, Memory::GetPointer(_iRamAddress), decrypt);
|
||||
}
|
||||
|
||||
bool ChangePartition(u64 offset)
|
||||
{
|
||||
DVDThread::WaitUntilIdle();
|
||||
return s_inserted_volume->ChangePartition(offset);
|
||||
}
|
||||
|
||||
|
@ -687,19 +646,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 +675,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 +688,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 +733,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 +820,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 +917,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 +1260,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.
|
||||
|
|
|
@ -105,7 +105,6 @@ bool IsDiscInside();
|
|||
void ChangeDisc(const std::string& fileName);
|
||||
|
||||
// DVD Access Functions
|
||||
bool DVDRead(u64 _iDVDOffset, u32 _iRamAddress, u32 _iLength, bool decrypt);
|
||||
extern bool g_bStream;
|
||||
bool ChangePartition(u64 offset);
|
||||
void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_address, u32 output_length,
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cinttypes>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Event.h"
|
||||
#include "Common/Flag.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/Thread.h"
|
||||
#include "Common/Timer.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
#include "Core/Core.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/HW/DVDInterface.h"
|
||||
#include "Core/HW/DVDThread.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/HW/SystemTimers.h"
|
||||
|
||||
#include "DiscIO/Volume.h"
|
||||
|
||||
namespace DVDThread
|
||||
{
|
||||
|
||||
static void DVDThread();
|
||||
|
||||
static void FinishRead(u64 userdata, int cyclesLate);
|
||||
static int s_finish_read;
|
||||
|
||||
static std::thread s_dvd_thread;
|
||||
static Common::Event s_dvd_thread_start_working;
|
||||
static Common::Event s_dvd_thread_done_working;
|
||||
static Common::Flag s_dvd_thread_exiting(false);
|
||||
|
||||
static std::vector<u8> s_dvd_buffer;
|
||||
static u64 s_time_read_started;
|
||||
static bool s_dvd_success;
|
||||
|
||||
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;
|
||||
|
||||
// The following time variables are only used for logging
|
||||
static u64 s_realtime_started_us;
|
||||
static u64 s_realtime_done_us;
|
||||
|
||||
void Start()
|
||||
{
|
||||
s_finish_read = CoreTiming::RegisterEvent("FinishReadDVDThread", FinishRead);
|
||||
_assert_(!s_dvd_thread.joinable());
|
||||
s_dvd_thread = std::thread(DVDThread);
|
||||
}
|
||||
|
||||
void Stop()
|
||||
{
|
||||
_assert_(s_dvd_thread.joinable());
|
||||
|
||||
// The DVD thread will return if s_DVD_thread_exiting
|
||||
// is set when it starts working
|
||||
s_dvd_thread_exiting.Set();
|
||||
s_dvd_thread_start_working.Set();
|
||||
|
||||
s_dvd_thread.join();
|
||||
|
||||
s_dvd_thread_exiting.Clear();
|
||||
}
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
WaitUntilIdle();
|
||||
|
||||
// TODO: Savestates can be smaller if s_DVD_buffer is not saved
|
||||
p.Do(s_dvd_buffer);
|
||||
p.Do(s_time_read_started);
|
||||
p.Do(s_dvd_success);
|
||||
|
||||
p.Do(s_dvd_offset);
|
||||
p.Do(s_output_address);
|
||||
p.Do(s_length);
|
||||
p.Do(s_decrypt);
|
||||
p.Do(s_callback_event_type);
|
||||
|
||||
// s_realtime_started_us and s_realtime_done_us aren't savestated
|
||||
// because they rely on the current system's time.
|
||||
// This means that loading a savestate might cause
|
||||
// incorrect times to be logged once.
|
||||
}
|
||||
|
||||
void WaitUntilIdle()
|
||||
{
|
||||
_assert_(Core::IsCPUThread());
|
||||
|
||||
// Wait until DVD thread isn't working
|
||||
s_dvd_thread_done_working.Wait();
|
||||
|
||||
// Set the event again so that we still know that the DVD thread isn't working
|
||||
s_dvd_thread_done_working.Set();
|
||||
}
|
||||
|
||||
void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt,
|
||||
int callback_event_type, int ticks_until_completion)
|
||||
{
|
||||
_assert_(Core::IsCPUThread());
|
||||
|
||||
s_dvd_thread_done_working.Wait();
|
||||
|
||||
s_dvd_offset = dvd_offset;
|
||||
s_output_address = output_address;
|
||||
s_length = length;
|
||||
s_decrypt = decrypt;
|
||||
s_callback_event_type = callback_event_type;
|
||||
|
||||
s_time_read_started = CoreTiming::GetTicks();
|
||||
s_realtime_started_us = Common::Timer::GetTimeUs();
|
||||
|
||||
s_dvd_thread_start_working.Set();
|
||||
|
||||
CoreTiming::ScheduleEvent(ticks_until_completion, s_finish_read);
|
||||
}
|
||||
|
||||
static void FinishRead(u64 userdata, int cyclesLate)
|
||||
{
|
||||
WaitUntilIdle();
|
||||
|
||||
DEBUG_LOG(DVDINTERFACE, "Disc has been read. Real time: %" PRIu64 " us. "
|
||||
"Real time including delay: %" PRIu64 " us. Emulated time including delay: %" PRIu64 " us.",
|
||||
s_realtime_done_us - s_realtime_started_us,
|
||||
Common::Timer::GetTimeUs() - s_realtime_started_us,
|
||||
(CoreTiming::GetTicks() - s_time_read_started) / (SystemTimers::GetTicksPerSecond() / 1000 / 1000));
|
||||
|
||||
if (s_dvd_success)
|
||||
Memory::CopyToEmu(s_output_address, s_dvd_buffer.data(), s_length);
|
||||
else
|
||||
PanicAlertT("The disc could not be read (at 0x%" PRIx64 " - 0x%" PRIx64 ").",
|
||||
s_dvd_offset, s_dvd_offset + s_length);
|
||||
|
||||
// This will make the buffer take less space in savestates.
|
||||
// Reducing the size doesn't change the amount of reserved memory,
|
||||
// so this doesn't lead to extra memory allocations.
|
||||
s_dvd_buffer.resize(0);
|
||||
|
||||
// Notify the emulated software that the command has been executed
|
||||
CoreTiming::ScheduleEvent_Immediate(s_callback_event_type, DVDInterface::INT_TCINT);
|
||||
}
|
||||
|
||||
static void DVDThread()
|
||||
{
|
||||
Common::SetCurrentThreadName("DVD thread");
|
||||
|
||||
while (true)
|
||||
{
|
||||
s_dvd_thread_done_working.Set();
|
||||
|
||||
s_dvd_thread_start_working.Wait();
|
||||
|
||||
if (s_dvd_thread_exiting.IsSet())
|
||||
return;
|
||||
|
||||
s_dvd_buffer.resize(s_length);
|
||||
|
||||
s_dvd_success = DVDInterface::GetVolume().Read(s_dvd_offset, s_length, s_dvd_buffer.data(), s_decrypt);
|
||||
|
||||
s_realtime_done_us = Common::Timer::GetTimeUs();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
// 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 WaitUntilIdle();
|
||||
void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt,
|
||||
int callback_event_type, int ticks_until_completion);
|
||||
|
||||
}
|
|
@ -247,8 +247,8 @@ bool AreMemoryBreakpointsActivated()
|
|||
static inline bool ValidCopyRange(u32 address, size_t size)
|
||||
{
|
||||
return (GetPointer(address) != nullptr &&
|
||||
GetPointer(address + u32(size)) != nullptr &&
|
||||
size < EXRAM_SIZE); // Make sure we don't have a range spanning seperate 2 banks
|
||||
GetPointer(address + u32(size) - 1) != nullptr &&
|
||||
size < EXRAM_SIZE); // Make sure we don't have a range spanning 2 separate banks
|
||||
}
|
||||
|
||||
void CopyFromEmu(void* data, u32 address, size_t size)
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue