void CUCode_AX::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 // safe to do because it matches what the DSP does on real hardware: there // is no interrupt when a mail from CPU is received. m_processing.lock(); if (next_is_cmdlist) { CopyCmdList(mail, cmdlist_size); StartWorking(); NotifyAXThread(); } else if (m_UploadSetupInProgress) { PrepareBootUCode(mail); } else if (mail == MAIL_RESUME) { // Acknowledge the resume request m_rMailHandler.PushMail(DSP_RESUME); DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); } else if (mail == MAIL_NEW_UCODE) { soundStream->GetMixer()->SetHLEReady(false); m_UploadSetupInProgress = true; } else if (mail == MAIL_RESET) { m_DSPHLE->SetUCode(UCODE_ROM); } else if (mail == MAIL_CONTINUE) { // We don't have to do anything here - the CPU does not wait for a ACK // and sends a cmdlist mail just after. } else if ((mail & MAIL_CMDLIST_MASK) == MAIL_CMDLIST) { // A command list address is going to be sent next. set_next_is_cmdlist = true; cmdlist_size = (u16)(mail & ~MAIL_CMDLIST_MASK); } else { ERROR_LOG(DSPHLE, "Unknown mail sent to AX::HandleMail: %08x", mail); } m_processing.unlock(); next_is_cmdlist = set_next_is_cmdlist; }
void AXUCode::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; if (next_is_cmdlist) { CopyCmdList(mail, cmdlist_size); HandleCommandList(); m_cmdlist_size = 0; SignalWorkEnd(); } else if (m_upload_setup_in_progress) { PrepareBootUCode(mail); } else if (mail == MAIL_RESUME) { // Acknowledge the resume request m_mail_handler.PushMail(DSP_RESUME); DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); } else if (mail == MAIL_NEW_UCODE) { m_upload_setup_in_progress = true; } else if (mail == MAIL_RESET) { m_dsphle->SetUCode(UCODE_ROM); } else if (mail == MAIL_CONTINUE) { // We don't have to do anything here - the CPU does not wait for a ACK // and sends a cmdlist mail just after. } else if ((mail & MAIL_CMDLIST_MASK) == MAIL_CMDLIST) { // A command list address is going to be sent next. set_next_is_cmdlist = true; cmdlist_size = (u16)(mail & ~MAIL_CMDLIST_MASK); } else { ERROR_LOG(DSPHLE, "Unknown mail sent to AX::HandleMail: %08x", mail); } next_is_cmdlist = set_next_is_cmdlist; }
void CUCode_AX::HandleCommandList() { // Temp variables for addresses computation u16 addr_hi, addr_lo; u16 addr2_hi, addr2_lo; u16 size; u32 pb_addr = 0; #if 0 WARN_LOG(DSPHLE, "Command list:"); for (u32 i = 0; m_cmdlist[i] != CMD_END; ++i) WARN_LOG(DSPHLE, "%04x", m_cmdlist[i]); WARN_LOG(DSPHLE, "-------------"); #endif u32 curr_idx = 0; bool end = false; while (!end) { u16 cmd = m_cmdlist[curr_idx++]; switch (cmd) { // Some of these commands are unknown, or unused in this AX HLE. // We still need to skip their arguments using "curr_idx += N". case CMD_SETUP: addr_hi = m_cmdlist[curr_idx++]; addr_lo = m_cmdlist[curr_idx++]; SetupProcessing(HILO_TO_32(addr)); break; case CMD_DL_AND_VOL_MIX: { addr_hi = m_cmdlist[curr_idx++]; addr_lo = m_cmdlist[curr_idx++]; u16 vol_main = m_cmdlist[curr_idx++]; u16 vol_auxa = m_cmdlist[curr_idx++]; u16 vol_auxb = m_cmdlist[curr_idx++]; DownloadAndMixWithVolume(HILO_TO_32(addr), vol_main, vol_auxa, vol_auxb); break; } case CMD_PB_ADDR: addr_hi = m_cmdlist[curr_idx++]; addr_lo = m_cmdlist[curr_idx++]; pb_addr = HILO_TO_32(addr); break; case CMD_PROCESS: ProcessPBList(pb_addr); break; case CMD_MIX_AUXA: case CMD_MIX_AUXB: // These two commands are handled almost the same internally. addr_hi = m_cmdlist[curr_idx++]; addr_lo = m_cmdlist[curr_idx++]; addr2_hi = m_cmdlist[curr_idx++]; addr2_lo = m_cmdlist[curr_idx++]; MixAUXSamples(cmd - CMD_MIX_AUXA, HILO_TO_32(addr), HILO_TO_32(addr2)); break; case CMD_UPLOAD_LRS: addr_hi = m_cmdlist[curr_idx++]; addr_lo = m_cmdlist[curr_idx++]; UploadLRS(HILO_TO_32(addr)); break; case CMD_SET_LR: addr_hi = m_cmdlist[curr_idx++]; addr_lo = m_cmdlist[curr_idx++]; SetMainLR(HILO_TO_32(addr)); break; case CMD_UNK_08: curr_idx += 10; break; // TODO: check case CMD_MIX_AUXB_NOWRITE: addr_hi = m_cmdlist[curr_idx++]; addr_lo = m_cmdlist[curr_idx++]; MixAUXSamples(false, 0, HILO_TO_32(addr)); 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_MORE: addr_hi = m_cmdlist[curr_idx++]; addr_lo = m_cmdlist[curr_idx++]; size = m_cmdlist[curr_idx++]; CopyCmdList(HILO_TO_32(addr), size); curr_idx = 0; break; case CMD_OUTPUT: addr_hi = m_cmdlist[curr_idx++]; addr_lo = m_cmdlist[curr_idx++]; addr2_hi = m_cmdlist[curr_idx++]; addr2_lo = m_cmdlist[curr_idx++]; OutputSamples(HILO_TO_32(addr2), HILO_TO_32(addr)); break; case CMD_END: end = true; break; case CMD_MIX_AUXB_LR: addr_hi = m_cmdlist[curr_idx++]; addr_lo = m_cmdlist[curr_idx++]; addr2_hi = m_cmdlist[curr_idx++]; addr2_lo = m_cmdlist[curr_idx++]; MixAUXBLR(HILO_TO_32(addr), HILO_TO_32(addr2)); break; case CMD_UNK_11: curr_idx += 2; break; case CMD_UNK_12: { u16 samp_val = m_cmdlist[curr_idx++]; u16 idx = m_cmdlist[curr_idx++]; addr_hi = m_cmdlist[curr_idx++]; addr_lo = m_cmdlist[curr_idx++]; // TODO (void)samp_val; (void)idx; break; } // Send the contents of MAIN LRS, AUXA LRS and AUXB S to RAM, and // mix data to MAIN LR and AUXB LR. case CMD_SEND_AUX_AND_MIX: { // Address for Main + AUXA LRS upload u16 main_auxa_up_hi = m_cmdlist[curr_idx++]; u16 main_auxa_up_lo = m_cmdlist[curr_idx++]; // Address for AUXB S upload u16 auxb_s_up_hi = m_cmdlist[curr_idx++]; u16 auxb_s_up_lo = m_cmdlist[curr_idx++]; // Address to read data for Main L u16 main_l_dl_hi = m_cmdlist[curr_idx++]; u16 main_l_dl_lo = m_cmdlist[curr_idx++]; // Address to read data for Main R u16 main_r_dl_hi = m_cmdlist[curr_idx++]; u16 main_r_dl_lo = m_cmdlist[curr_idx++]; // Address to read data for AUXB L u16 auxb_l_dl_hi = m_cmdlist[curr_idx++]; u16 auxb_l_dl_lo = m_cmdlist[curr_idx++]; // Address to read data for AUXB R u16 auxb_r_dl_hi = m_cmdlist[curr_idx++]; u16 auxb_r_dl_lo = m_cmdlist[curr_idx++]; SendAUXAndMix(HILO_TO_32(main_auxa_up), HILO_TO_32(auxb_s_up), HILO_TO_32(main_l_dl), HILO_TO_32(main_r_dl), HILO_TO_32(auxb_l_dl), HILO_TO_32(auxb_r_dl)); break; } default: ERROR_LOG(DSPHLE, "Unknown command in AX cmdlist: %04x", cmd); end = true; break; } } }