DVDInterface: Prepare for reading DTK data in DVDThread
This commit is contained in:
parent
aabb17b7c9
commit
28bfd52d3a
|
@ -239,7 +239,6 @@ static bool s_disc_inside = false;
|
|||
static bool s_stream = false;
|
||||
static bool s_stop_at_track_end = false;
|
||||
static CoreTiming::EventType* s_finish_executing_command;
|
||||
static CoreTiming::EventType* s_dtk;
|
||||
|
||||
static u64 s_last_read_offset;
|
||||
static u64 s_last_read_time;
|
||||
|
@ -260,8 +259,9 @@ void GenerateDIInterrupt(DIInterruptType _DVDInterrupt);
|
|||
|
||||
void WriteImmediate(u32 value, u32 output_address, bool reply_to_ios);
|
||||
bool ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32 output_length,
|
||||
bool decrypt, bool reply_to_ios, DIInterruptType* interrupt_type,
|
||||
u64* ticks_until_completion);
|
||||
bool decrypt, ReplyType reply_type, DIInterruptType* interrupt_type);
|
||||
|
||||
u64 PackFinishExecutingCommandUserdata(ReplyType reply_type, DIInterruptType interrupt_type);
|
||||
|
||||
u64 SimulateDiscReadTime(u64 offset, u32 length);
|
||||
s64 CalculateRawDiscReadTime(u64 offset, s64 length);
|
||||
|
@ -355,7 +355,7 @@ static u32 ProcessDTKSamples(short* tempPCM, u32 num_samples)
|
|||
return samples_processed;
|
||||
}
|
||||
|
||||
static void DTKStreamingCallback(u64 userdata, s64 cyclesLate)
|
||||
static void DTKStreamingCallback(const std::vector<u8>& audio_data, s64 cycles_late)
|
||||
{
|
||||
// Send audio to the mixer.
|
||||
static const int NUM_SAMPLES = 48000 / 2000 * 7; // 3.5ms of 48kHz samples
|
||||
|
@ -373,7 +373,8 @@ static void DTKStreamingCallback(u64 userdata, s64 cyclesLate)
|
|||
g_sound_stream->GetMixer()->PushStreamingSamples(tempPCM, samples_processed);
|
||||
|
||||
int ticks_to_dtk = int(SystemTimers::GetTicksPerSecond() * u64(samples_processed) / 48000);
|
||||
CoreTiming::ScheduleEvent(ticks_to_dtk - cyclesLate, s_dtk);
|
||||
u64 userdata = PackFinishExecutingCommandUserdata(ReplyType::DTK, DIInterruptType::INT_TCINT);
|
||||
CoreTiming::ScheduleEvent(ticks_to_dtk - cycles_late, s_finish_executing_command, userdata);
|
||||
}
|
||||
|
||||
void Init()
|
||||
|
@ -413,9 +414,9 @@ void Init()
|
|||
|
||||
s_finish_executing_command =
|
||||
CoreTiming::RegisterEvent("FinishExecutingCommand", FinishExecutingCommandCallback);
|
||||
s_dtk = CoreTiming::RegisterEvent("StreamingTimer", DTKStreamingCallback);
|
||||
|
||||
CoreTiming::ScheduleEvent(0, s_dtk);
|
||||
u64 userdata = PackFinishExecutingCommandUserdata(ReplyType::DTK, DIInterruptType::INT_TCINT);
|
||||
CoreTiming::ScheduleEvent(0, s_finish_executing_command, userdata);
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
|
@ -647,8 +648,7 @@ void WriteImmediate(u32 value, u32 output_address, bool reply_to_ios)
|
|||
|
||||
// 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, bool reply_to_ios, DIInterruptType* interrupt_type,
|
||||
u64* ticks_until_completion)
|
||||
bool decrypt, ReplyType reply_type, DIInterruptType* interrupt_type)
|
||||
{
|
||||
if (!s_disc_inside)
|
||||
{
|
||||
|
@ -665,32 +665,34 @@ bool ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32
|
|||
|
||||
if (DVD_length > output_length)
|
||||
{
|
||||
WARN_LOG(
|
||||
DVDINTERFACE,
|
||||
"Detected attempt to read more data from the DVD than fit inside the out buffer. Clamp.");
|
||||
WARN_LOG(DVDINTERFACE, "Detected an attempt to read more data from the DVD "
|
||||
"than what fits inside the out buffer. Clamping.");
|
||||
DVD_length = output_length;
|
||||
}
|
||||
|
||||
u64 ticks_until_completion;
|
||||
if (SConfig::GetInstance().bFastDiscSpeed)
|
||||
{
|
||||
// An optional hack to speed up loading times
|
||||
*ticks_until_completion =
|
||||
ticks_until_completion =
|
||||
output_length * (SystemTimers::GetTicksPerSecond() / BUFFER_TRANSFER_RATE);
|
||||
}
|
||||
else
|
||||
*ticks_until_completion = SimulateDiscReadTime(DVD_offset, DVD_length);
|
||||
{
|
||||
ticks_until_completion = SimulateDiscReadTime(DVD_offset, DVD_length);
|
||||
}
|
||||
|
||||
DVDThread::StartRead(DVD_offset, output_address, DVD_length, decrypt, reply_to_ios,
|
||||
(int)*ticks_until_completion);
|
||||
DVDThread::StartReadToEmulatedRAM(output_address, DVD_offset, DVD_length, decrypt, reply_type,
|
||||
ticks_until_completion);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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(u32 command_0, u32 command_1, u32 command_2, u32 output_address,
|
||||
u32 output_length, bool reply_to_ios)
|
||||
{
|
||||
ReplyType reply_type = reply_to_ios ? ReplyType::IOS_HLE : ReplyType::Interrupt;
|
||||
DIInterruptType interrupt_type = INT_TCINT;
|
||||
u64 ticks_until_completion = SystemTimers::GetTicksPerSecond() / 15000;
|
||||
s64 ticks_until_completion = SystemTimers::GetTicksPerSecond() / 15000;
|
||||
bool command_handled_by_thread = false;
|
||||
|
||||
// DVDLowRequestError needs access to the error code set by the previous command
|
||||
|
@ -715,9 +717,8 @@ 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");
|
||||
command_handled_by_thread =
|
||||
ExecuteReadCommand(0, output_address, 0x20, output_length, false, reply_to_ios,
|
||||
&interrupt_type, &ticks_until_completion);
|
||||
command_handled_by_thread = ExecuteReadCommand(0, output_address, 0x20, output_length, false,
|
||||
reply_type, &interrupt_type);
|
||||
break;
|
||||
|
||||
// Only used from WII_IPC. This is the only read command that decrypts data
|
||||
|
@ -726,7 +727,7 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
|
|||
command_1);
|
||||
command_handled_by_thread =
|
||||
ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length, true,
|
||||
reply_to_ios, &interrupt_type, &ticks_until_completion);
|
||||
reply_type, &interrupt_type);
|
||||
break;
|
||||
|
||||
// Probably only used by Wii
|
||||
|
@ -808,7 +809,7 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
|
|||
{
|
||||
command_handled_by_thread =
|
||||
ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length, false,
|
||||
reply_to_ios, &interrupt_type, &ticks_until_completion);
|
||||
reply_type, &interrupt_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -856,17 +857,15 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
|
|||
", DMABuffer = %08x, SrcLength = %08x, DMALength = %08x",
|
||||
iDVDOffset, output_address, command_2, output_length);
|
||||
|
||||
command_handled_by_thread =
|
||||
ExecuteReadCommand(iDVDOffset, output_address, command_2, output_length, false,
|
||||
reply_to_ios, &interrupt_type, &ticks_until_completion);
|
||||
command_handled_by_thread = ExecuteReadCommand(
|
||||
iDVDOffset, output_address, command_2, output_length, false, reply_type, &interrupt_type);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x40: // Read DiscID
|
||||
INFO_LOG(DVDINTERFACE, "Read DiscID %08x", Memory::Read_U32(output_address));
|
||||
command_handled_by_thread =
|
||||
ExecuteReadCommand(0, output_address, 0x20, output_length, false, reply_to_ios,
|
||||
&interrupt_type, &ticks_until_completion);
|
||||
command_handled_by_thread = ExecuteReadCommand(0, output_address, 0x20, output_length, false,
|
||||
reply_type, &interrupt_type);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1083,33 +1082,52 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
|
|||
// to simulate the speed of a real disc drive
|
||||
if (!command_handled_by_thread)
|
||||
{
|
||||
u64 userdata = (static_cast<u64>(reply_to_ios) << 32) + static_cast<u32>(interrupt_type);
|
||||
CoreTiming::ScheduleEvent((int)ticks_until_completion, s_finish_executing_command, userdata);
|
||||
CoreTiming::ScheduleEvent(ticks_until_completion, s_finish_executing_command,
|
||||
PackFinishExecutingCommandUserdata(reply_type, interrupt_type));
|
||||
}
|
||||
}
|
||||
|
||||
u64 PackFinishExecutingCommandUserdata(ReplyType reply_type, DIInterruptType interrupt_type)
|
||||
{
|
||||
return (static_cast<u64>(reply_type) << 32) + static_cast<u32>(interrupt_type);
|
||||
}
|
||||
|
||||
void FinishExecutingCommandCallback(u64 userdata, s64 cycles_late)
|
||||
{
|
||||
bool reply_to_ios = userdata >> 32 != 0;
|
||||
ReplyType reply_type = static_cast<ReplyType>(userdata >> 32);
|
||||
DIInterruptType interrupt_type = static_cast<DIInterruptType>(userdata & 0xFFFFFFFF);
|
||||
FinishExecutingCommand(reply_to_ios, interrupt_type);
|
||||
FinishExecutingCommand(reply_type, interrupt_type, cycles_late);
|
||||
}
|
||||
|
||||
void FinishExecutingCommand(bool reply_to_ios, DIInterruptType interrupt_type)
|
||||
void FinishExecutingCommand(ReplyType reply_type, DIInterruptType interrupt_type, s64 cycles_late,
|
||||
const std::vector<u8>& data)
|
||||
{
|
||||
if (reply_to_ios)
|
||||
switch (reply_type)
|
||||
{
|
||||
case ReplyType::Interrupt:
|
||||
{
|
||||
if (s_DICR.TSTART)
|
||||
{
|
||||
s_DICR.TSTART = 0;
|
||||
s_DILENGTH.Length = 0;
|
||||
GenerateDIInterrupt(interrupt_type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ReplyType::IOS_HLE:
|
||||
{
|
||||
std::shared_ptr<IWII_IPC_HLE_Device> di = WII_IPC_HLE_Interface::GetDeviceByName("/dev/di");
|
||||
if (di)
|
||||
std::static_pointer_cast<CWII_IPC_HLE_Device_di>(di)->FinishIOCtl(interrupt_type);
|
||||
|
||||
// If di == nullptr, IOS was probably shut down, so the command shouldn't be completed
|
||||
break;
|
||||
}
|
||||
else if (s_DICR.TSTART)
|
||||
|
||||
case ReplyType::DTK:
|
||||
{
|
||||
s_DICR.TSTART = 0;
|
||||
s_DILENGTH.Length = 0;
|
||||
GenerateDIInterrupt(interrupt_type);
|
||||
DTKStreamingCallback(data, cycles_late);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
|
@ -92,6 +93,13 @@ enum DIInterruptType : int
|
|||
INT_CVRINT = 3,
|
||||
};
|
||||
|
||||
enum class ReplyType : u32
|
||||
{
|
||||
Interrupt,
|
||||
IOS_HLE,
|
||||
DTK
|
||||
};
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
void DoState(PointerWrap& p);
|
||||
|
@ -115,6 +123,7 @@ void ChangeDiscAsCPU(const std::string& new_path); // Can only be called by th
|
|||
bool ChangePartition(u64 offset);
|
||||
void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_address,
|
||||
u32 output_length, bool reply_to_ios);
|
||||
void FinishExecutingCommand(bool reply_to_ios, DIInterruptType interrupt_type);
|
||||
void FinishExecutingCommand(ReplyType reply_type, DIInterruptType interrupt_type, s64 cycles_late,
|
||||
const std::vector<u8>& data = std::vector<u8>());
|
||||
|
||||
} // end of namespace DVDInterface
|
||||
|
|
|
@ -32,14 +32,16 @@ namespace DVDThread
|
|||
{
|
||||
struct ReadRequest
|
||||
{
|
||||
u64 dvd_offset;
|
||||
bool copy_to_ram;
|
||||
u32 output_address;
|
||||
u64 dvd_offset;
|
||||
u32 length;
|
||||
bool decrypt;
|
||||
|
||||
// This determines which function will be used as a callback.
|
||||
// We can't have a function pointer here, because they can't be in savestates.
|
||||
bool reply_to_ios;
|
||||
// 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;
|
||||
|
||||
// IDs are used to uniquely identify a request. They must not be
|
||||
// identical to IDs of any other requests that currently exist, but
|
||||
|
@ -56,6 +58,10 @@ using ReadResult = std::pair<ReadRequest, std::vector<u8>>;
|
|||
|
||||
static void DVDThread();
|
||||
|
||||
static void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offset, u32 length,
|
||||
bool decrypt, DVDInterface::ReplyType reply_type,
|
||||
s64 ticks_until_completion);
|
||||
|
||||
static void FinishRead(u64 id, s64 cycles_late);
|
||||
static CoreTiming::EventType* s_finish_read;
|
||||
|
||||
|
@ -143,18 +149,32 @@ void WaitUntilIdle()
|
|||
s_dvd_thread_done_working.Set();
|
||||
}
|
||||
|
||||
void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt, bool reply_to_ios,
|
||||
int ticks_until_completion)
|
||||
void StartRead(u64 dvd_offset, u32 length, bool decrypt, DVDInterface::ReplyType reply_type,
|
||||
s64 ticks_until_completion)
|
||||
{
|
||||
StartReadInternal(false, 0, dvd_offset, length, decrypt, reply_type, ticks_until_completion);
|
||||
}
|
||||
|
||||
void StartReadToEmulatedRAM(u32 output_address, u64 dvd_offset, u32 length, bool decrypt,
|
||||
DVDInterface::ReplyType reply_type, s64 ticks_until_completion)
|
||||
{
|
||||
StartReadInternal(true, output_address, dvd_offset, length, decrypt, reply_type,
|
||||
ticks_until_completion);
|
||||
}
|
||||
|
||||
void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offset, u32 length,
|
||||
bool decrypt, DVDInterface::ReplyType reply_type, s64 ticks_until_completion)
|
||||
{
|
||||
_assert_(Core::IsCPUThread());
|
||||
|
||||
ReadRequest request;
|
||||
|
||||
request.dvd_offset = dvd_offset;
|
||||
request.copy_to_ram = copy_to_ram;
|
||||
request.output_address = output_address;
|
||||
request.dvd_offset = dvd_offset;
|
||||
request.length = length;
|
||||
request.decrypt = decrypt;
|
||||
request.reply_to_ios = reply_to_ios;
|
||||
request.reply_type = reply_type;
|
||||
|
||||
u64 id = s_next_id++;
|
||||
request.id = id;
|
||||
|
@ -213,14 +233,20 @@ static void FinishRead(u64 id, s64 cycles_late)
|
|||
(CoreTiming::GetTicks() - request.time_started_ticks) /
|
||||
(SystemTimers::GetTicksPerSecond() / 1000000));
|
||||
|
||||
if (!buffer.empty())
|
||||
Memory::CopyToEmu(request.output_address, buffer.data(), request.length);
|
||||
else
|
||||
if (buffer.empty())
|
||||
{
|
||||
PanicAlertT("The disc could not be read (at 0x%" PRIx64 " - 0x%" PRIx64 ").",
|
||||
request.dvd_offset, request.dvd_offset + request.length);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (request.copy_to_ram)
|
||||
Memory::CopyToEmu(request.output_address, buffer.data(), request.length);
|
||||
}
|
||||
|
||||
// Notify the emulated software that the command has been executed
|
||||
DVDInterface::FinishExecutingCommand(request.reply_to_ios, DVDInterface::INT_TCINT);
|
||||
DVDInterface::FinishExecutingCommand(request.reply_type, DVDInterface::INT_TCINT, cycles_late,
|
||||
buffer);
|
||||
}
|
||||
|
||||
static void DVDThread()
|
||||
|
|
|
@ -4,9 +4,14 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
class PointerWrap;
|
||||
namespace DVDInterface
|
||||
{
|
||||
enum class ReplyType : u32;
|
||||
}
|
||||
|
||||
namespace DVDThread
|
||||
{
|
||||
void Start();
|
||||
|
@ -14,6 +19,8 @@ void Stop();
|
|||
void DoState(PointerWrap& p);
|
||||
|
||||
void WaitUntilIdle();
|
||||
void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt, bool reply_to_ios,
|
||||
int ticks_until_completion);
|
||||
void StartRead(u64 dvd_offset, u32 length, bool decrypt, DVDInterface::ReplyType reply_type,
|
||||
s64 ticks_until_completion);
|
||||
void StartReadToEmulatedRAM(u32 output_address, u64 dvd_offset, u32 length, bool decrypt,
|
||||
DVDInterface::ReplyType reply_type, s64 ticks_until_completion);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue