Parse the AX command list in the AX thread

This commit is contained in:
Pierre Bourdon 2012-11-14 06:15:55 +01:00
parent 9e813502ac
commit 7535c6d903
2 changed files with 119 additions and 13 deletions

View File

@ -20,7 +20,7 @@
CUCode_NewAX::CUCode_NewAX(DSPHLE* dsp_hle, u32 crc)
: IUCode(dsp_hle, crc)
, m_cmdlist_addr(0)
, m_cmdlist_size(0)
, m_axthread(&CUCode_NewAX::AXThread, this)
{
m_rMailHandler.PushMail(DSP_INIT);
@ -29,7 +29,7 @@ CUCode_NewAX::CUCode_NewAX(DSPHLE* dsp_hle, u32 crc)
CUCode_NewAX::~CUCode_NewAX()
{
m_cmdlist_addr = (u32)-1; // Special value to signal end
m_cmdlist_size = (u16)-1; // Special value to signal end
NotifyAXThread();
m_axthread.join();
@ -42,16 +42,16 @@ void CUCode_NewAX::AXThread()
{
{
std::unique_lock<std::mutex> lk(m_cmdlist_mutex);
while (m_cmdlist_addr == 0)
while (m_cmdlist_size == 0)
m_cmdlist_cv.wait(lk);
}
if (m_cmdlist_addr == (u32)-1) // End of thread signal
if (m_cmdlist_size == (u16)-1) // End of thread signal
break;
m_processing.lock();
HandleCommandList(m_cmdlist_addr);
m_cmdlist_addr = 0;
HandleCommandList();
m_cmdlist_size = 0;
// Signal end of processing
m_rMailHandler.PushMail(DSP_YIELD);
@ -66,15 +66,78 @@ void CUCode_NewAX::NotifyAXThread()
m_cmdlist_cv.notify_one();
}
void CUCode_NewAX::HandleCommandList(u32 addr)
void CUCode_NewAX::HandleCommandList()
{
WARN_LOG(DSPHLE, "TODO: HandleCommandList(%08x)", addr);
u16 pb_addr_hi, pb_addr_lo;
u32 pb_addr = 0;
u32 curr_idx = 0;
bool end = false;
while (!end)
{
u16 cmd = m_cmdlist[curr_idx++];
switch (cmd)
{
// A lot of these commands are unknown, or unused in this AX HLE.
// We still need to skip their arguments using "curr_idx += N".
case CMD_STUDIO_ADDR: curr_idx += 2; break;
case CMD_UNK_01: curr_idx += 5; break;
case CMD_PB_ADDR:
pb_addr_hi = m_cmdlist[curr_idx++];
pb_addr_lo = m_cmdlist[curr_idx++];
pb_addr = (pb_addr_hi << 16) | pb_addr_lo;
WARN_LOG(DSPHLE, "PB addr: %08x", pb_addr);
break;
case CMD_PROCESS:
ProcessPB(pb_addr);
break;
case CMD_UNK_04: curr_idx += 4; break;
case CMD_UNK_05: curr_idx += 4; break;
case CMD_UNK_06: curr_idx += 2; break;
case CMD_SBUFFER_ADDR: curr_idx += 2; break;
case CMD_UNK_08: curr_idx += 10; break; // TODO: check
case CMD_UNK_09: curr_idx += 2; break;
case CMD_COMPRESSOR_TABLE_ADDR: curr_idx += 2; break;
case CMD_UNK_0B: break; // TODO: check other versions
case CMD_UNK_0C: break; // TODO: check other versions
case CMD_UNK_0D: curr_idx += 2; break;
case CMD_UNK_0E: curr_idx += 4; break;
case CMD_END:
end = true;
break;
case CMD_UNK_10: curr_idx += 4; break;
case CMD_UNK_11: curr_idx += 2; break;
case CMD_UNK_12: curr_idx += 1; break;
case CMD_UNK_13: curr_idx += 12; break;
default:
ERROR_LOG(DSPHLE, "Unknown command in AX cmdlist: %04x", cmd);
end = true;
break;
}
}
}
void CUCode_NewAX::ProcessPB(u32 pb_addr)
{
NOTICE_LOG(DSPHLE, "TODO: process pb %08x", pb_addr);
}
void CUCode_NewAX::HandleMail(u32 mail)
{
// Indicates if the next message is a command list address.
static bool next_is_cmdlist = false;
static u16 cmdlist_size = 0;
bool set_next_is_cmdlist = false;
// Wait for DSP processing to be done before answering any mail. This is
@ -84,7 +147,7 @@ void CUCode_NewAX::HandleMail(u32 mail)
if (next_is_cmdlist)
{
m_cmdlist_addr = mail;
CopyCmdList(mail, cmdlist_size);
NotifyAXThread();
}
else if (m_UploadSetupInProgress)
@ -97,7 +160,7 @@ void CUCode_NewAX::HandleMail(u32 mail)
m_rMailHandler.PushMail(DSP_RESUME);
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
}
else if (mail == MAIL_NEWUCODE)
else if (mail == MAIL_NEW_UCODE)
{
soundStream->GetMixer()->SetHLEReady(false);
m_UploadSetupInProgress = true;
@ -115,6 +178,7 @@ void CUCode_NewAX::HandleMail(u32 mail)
{
// A command list address is going to be sent next.
set_next_is_cmdlist = true;
cmdlist_size = (u16)(mail & ~MAIL_CMDLIST_MASK);
}
else
{
@ -125,6 +189,19 @@ void CUCode_NewAX::HandleMail(u32 mail)
next_is_cmdlist = set_next_is_cmdlist;
}
void CUCode_NewAX::CopyCmdList(u32 addr, u16 size)
{
if (size >= (sizeof (m_cmdlist) / sizeof (u16)))
{
ERROR_LOG(DSPHLE, "Command list at %08x is too large: size=%d", addr, size);
return;
}
for (u32 i = 0; i < size; ++i, addr += 2)
m_cmdlist[i] = HLEMemory_Read_U16(addr);
m_cmdlist_size = size;
}
void CUCode_NewAX::MixAdd(short* out_buffer, int nsamples)
{
// nsamples * 2 for left and right audio channel

View File

@ -36,7 +36,7 @@ private:
enum MailType
{
MAIL_RESUME = 0xCDD10000,
MAIL_NEWUCODE = 0xCDD10001,
MAIL_NEW_UCODE = 0xCDD10001,
MAIL_RESET = 0xCDD10002,
MAIL_CONTINUE = 0xCDD10003,
@ -45,9 +45,34 @@ private:
MAIL_CMDLIST_MASK = 0xFFFF0000
};
enum CmdType
{
CMD_STUDIO_ADDR = 0x00,
CMD_UNK_01 = 0x01,
CMD_PB_ADDR = 0x02,
CMD_PROCESS = 0x03,
CMD_UNK_04 = 0x04,
CMD_UNK_05 = 0x05,
CMD_UNK_06 = 0x06,
CMD_SBUFFER_ADDR = 0x07,
CMD_UNK_08 = 0x08,
CMD_UNK_09 = 0x09,
CMD_COMPRESSOR_TABLE_ADDR = 0x0A,
CMD_UNK_0B = 0x0B,
CMD_UNK_0C = 0x0C,
CMD_UNK_0D = 0x0D,
CMD_UNK_0E = 0x0E,
CMD_END = 0x0F,
CMD_UNK_10 = 0x10,
CMD_UNK_11 = 0x11,
CMD_UNK_12 = 0x12,
CMD_UNK_13 = 0x13,
};
// Volatile because it's set by HandleMail and accessed in
// HandleCommandList, which are running in two different threads.
volatile u32 m_cmdlist_addr;
volatile u16 m_cmdlist[512];
volatile u32 m_cmdlist_size;
std::thread m_axthread;
@ -56,12 +81,16 @@ private:
std::condition_variable m_cmdlist_cv;
std::mutex m_cmdlist_mutex;
// Copy a command list from memory to our temp buffer
void CopyCmdList(u32 addr, u16 size);
// Send a notification to the AX thread to tell him a new cmdlist addr is
// available for processing.
void NotifyAXThread();
void AXThread();
void HandleCommandList(u32 addr);
void HandleCommandList();
void ProcessPB(u32 pb_addr);
};
#endif // !_UCODE_NEWAX_H