diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp index 64d27ffbd1..1e966d2d0a 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp @@ -50,8 +50,10 @@ void CUCode_AXWii::HandleCommandList() u16 addr2_hi, addr2_lo; u16 volume; + u32 pb_addr = 0; + // WARN_LOG(DSPHLE, "Command list:"); -// for (u32 i = 0; m_cmdlist[i] != CMD_END; ++i) +// for (u32 i = 0; m_cmdlist[i] != CMD_END_OLD; ++i) // WARN_LOG(DSPHLE, "%04x", m_cmdlist[i]); // WARN_LOG(DSPHLE, "-------------"); @@ -61,78 +63,160 @@ void CUCode_AXWii::HandleCommandList() { u16 cmd = m_cmdlist[curr_idx++]; - switch (cmd) + if (m_old_axwii) { - // 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_ADD_TO_LR: - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - AddToLR(HILO_TO_32(addr)); - break; - - case CMD_UNK_02: curr_idx += 2; break; - case CMD_UNK_03: curr_idx += 2; break; - - case CMD_PROCESS: - addr_hi = m_cmdlist[curr_idx++]; - addr_lo = m_cmdlist[curr_idx++]; - ProcessPBList(HILO_TO_32(addr)); - break; - - case CMD_MIX_AUXA: - case CMD_MIX_AUXB: - case CMD_MIX_AUXC: - volume = m_cmdlist[curr_idx++]; - 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), volume); - break; - - // These two go together and manipulate some AUX buffers. - case CMD_UNK_08: curr_idx += 13; break; - case CMD_UNK_09: curr_idx += 13; break; - - // TODO(delroth): figure this one out, it's used by almost every - // game I've tested so far. - case CMD_UNK_0A: curr_idx += 4; break; - - case CMD_OUTPUT: - volume = m_cmdlist[curr_idx++]; - 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), volume); - break; - - case CMD_UNK_0C: curr_idx += 5; break; - - case CMD_WM_OUTPUT: + switch (cmd) { - u32 addresses[4] = { - (u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1], - (u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3], - (u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5], - (u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7], - }; - curr_idx += 8; - OutputWMSamples(addresses); - break; - } + // 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_END: - end = true; - break; + case CMD_SETUP_OLD: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + SetupProcessing(HILO_TO_32(addr)); + break; + + case CMD_ADD_TO_LR_OLD: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + AddToLR(HILO_TO_32(addr)); + break; + + case CMD_UNK_02_OLD: curr_idx += 2; break; + case CMD_UNK_03_OLD: curr_idx += 2; break; + + case CMD_PB_ADDR_OLD: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + pb_addr = HILO_TO_32(addr); + break; + + case CMD_PROCESS_OLD: + ProcessPBList(pb_addr); + break; + + case CMD_MIX_AUXA_OLD: + case CMD_MIX_AUXB_OLD: + case CMD_MIX_AUXC_OLD: + volume = m_cmdlist[curr_idx++]; + 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_OLD, HILO_TO_32(addr), HILO_TO_32(addr2), volume); + break; + + // These two go together and manipulate some AUX buffers. + case CMD_UNK_09_OLD: curr_idx += 13; break; + case CMD_UNK_0A_OLD: curr_idx += 13; break; + + // TODO(delroth): figure this one out, it's used by almost every + // game I've tested so far. + case CMD_UNK_0B_OLD: curr_idx += 4; break; + + case CMD_OUTPUT_OLD: + 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), 0x8000); + break; + + case CMD_UNK_0D_OLD: curr_idx += 5; break; + + case CMD_WM_OUTPUT_OLD: + { + u32 addresses[4] = { + (u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1], + (u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3], + (u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5], + (u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7], + }; + curr_idx += 8; + OutputWMSamples(addresses); + break; + } + + case CMD_END_OLD: + end = true; + break; + } + } + else + { + 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_ADD_TO_LR: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + AddToLR(HILO_TO_32(addr)); + break; + + case CMD_UNK_02: curr_idx += 2; break; + case CMD_UNK_03: curr_idx += 2; break; + + case CMD_PROCESS: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + ProcessPBList(HILO_TO_32(addr)); + break; + + case CMD_MIX_AUXA: + case CMD_MIX_AUXB: + case CMD_MIX_AUXC: + volume = m_cmdlist[curr_idx++]; + 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), volume); + break; + + // These two go together and manipulate some AUX buffers. + case CMD_UNK_08: curr_idx += 13; break; + case CMD_UNK_09: curr_idx += 13; break; + + // TODO(delroth): figure this one out, it's used by almost every + // game I've tested so far. + case CMD_UNK_0A: curr_idx += 4; break; + + case CMD_OUTPUT: + volume = m_cmdlist[curr_idx++]; + 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), volume); + break; + + case CMD_UNK_0C: curr_idx += 5; break; + + case CMD_WM_OUTPUT: + { + u32 addresses[4] = { + (u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1], + (u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3], + (u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5], + (u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7], + }; + curr_idx += 8; + OutputWMSamples(addresses); + break; + } + + case CMD_END: + end = true; + break; + } } } } @@ -244,7 +328,8 @@ void CUCode_AXWii::GenerateVolumeRamp(u16* output, u16 vol1, u16 vol2, size_t nv } } -bool CUCode_AXWii::ExtractUpdatesFields(AXPBWii& pb, u16* num_updates, u16* updates) +bool CUCode_AXWii::ExtractUpdatesFields(AXPBWii& pb, u16* num_updates, u16* updates, + u32* updates_addr) { u16* pb_mem = (u16*)&pb; @@ -260,6 +345,8 @@ bool CUCode_AXWii::ExtractUpdatesFields(AXPBWii& pb, u16* num_updates, u16* upda u32 addr = HILO_TO_32(addr); u16* ptr = (u16*)HLEMemory_Get_Pointer(addr); + *updates_addr = addr; + // Copy the updates data and change the offset to match a PB without // updates data. u32 updates_count = num_updates[0] + num_updates[1] + num_updates[2]; @@ -276,11 +363,26 @@ bool CUCode_AXWii::ExtractUpdatesFields(AXPBWii& pb, u16* num_updates, u16* upda } // Remove the updates data from the PB - memmove(pb_mem + 41, pb_mem + 45, sizeof (pb) - 2 * 45); + memmove(pb_mem + 41, pb_mem + 46, sizeof (pb) - 2 * 46); return true; } +void CUCode_AXWii::ReinjectUpdatesFields(AXPBWii& pb, u16* num_updates, u32 updates_addr) +{ + u16* pb_mem = (u16*)&pb; + + // Make some space + memmove(pb_mem + 46, pb_mem + 41, sizeof (pb) - 2 * 46); + + // Reinsert previous values + pb_mem[41] = num_updates[0]; + pb_mem[42] = num_updates[1]; + pb_mem[43] = num_updates[2]; + pb_mem[44] = updates_addr >> 16; + pb_mem[45] = updates_addr & 0xFFFF; +} + void CUCode_AXWii::ProcessPBList(u32 pb_addr) { AXPBWii pb; @@ -315,7 +417,8 @@ void CUCode_AXWii::ProcessPBList(u32 pb_addr) u16 num_updates[3]; u16 updates[1024]; - if (ExtractUpdatesFields(pb, num_updates, updates)) + u32 updates_addr; + if (ExtractUpdatesFields(pb, num_updates, updates, &updates_addr)) { for (int curr_ms = 0; curr_ms < 3; ++curr_ms) { @@ -328,6 +431,7 @@ void CUCode_AXWii::ProcessPBList(u32 pb_addr) for (u32 i = 0; i < sizeof (buffers.ptrs) / sizeof (buffers.ptrs[0]); ++i) buffers.ptrs[i] += 32; } + ReinjectUpdatesFields(pb, num_updates, updates_addr); } else { diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.h index ce09b14674..e5ba319787 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.h +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.h @@ -52,8 +52,11 @@ protected: u16 m_last_main_volume; u16 m_last_aux_volumes[3]; - // If needed, extract the updates related fields from a PB. - bool ExtractUpdatesFields(AXPBWii& pb, u16* num_updates, u16* updates); + // If needed, extract the updates related fields from a PB. We need to + // reinject them afterwards so that the correct PB typs is written to RAM. + bool ExtractUpdatesFields(AXPBWii& pb, u16* num_updates, u16* updates, + u32* updates_addr); + void ReinjectUpdatesFields(AXPBWii& pb, u16* num_updates, u32 updates_addr); // Convert a mixer_control bitfield to our internal representation for that // value. Required because that bitfield has a different meaning in some @@ -91,7 +94,30 @@ private: CMD_OUTPUT = 0x0B, CMD_UNK_0C = 0x0C, CMD_WM_OUTPUT = 0x0D, - CMD_END = 0x0E + CMD_END = 0x0E, + }; + + // A lot of these are similar to the new version, but there is an offset in + // the command ids due to the PB_ADDR command (which was removed from the + // new AXWii). + enum CmdTypeOld + { + CMD_SETUP_OLD = 0x00, + CMD_ADD_TO_LR_OLD = 0x01, + CMD_UNK_02_OLD = 0x02, + CMD_UNK_03_OLD = 0x03, + CMD_PB_ADDR_OLD = 0x04, + CMD_PROCESS_OLD = 0x05, + CMD_MIX_AUXA_OLD = 0x06, + CMD_MIX_AUXB_OLD = 0x07, + CMD_MIX_AUXC_OLD = 0x08, + CMD_UNK_09_OLD = 0x09, + CMD_UNK_0A_OLD = 0x0A, + CMD_UNK_0B_OLD = 0x0B, + CMD_OUTPUT_OLD = 0x0C, // no volume! + CMD_UNK_0D_OLD = 0x0D, + CMD_WM_OUTPUT_OLD = 0x0E, + CMD_END_OLD = 0x0F }; };