From eae959238edf17de3ac9a963c209603c1bc8b1e3 Mon Sep 17 00:00:00 2001 From: Techjar Date: Sat, 21 Dec 2019 05:56:03 -0500 Subject: [PATCH] HW/DSPHLE: Fix struct aliasing undefined behavior in AX ucode This fixes Old AX Wii games having no audio when compiled under VS2019. This also includes some minor code cleanup and moving a function to avoid duplication. --- Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp | 19 ++-------------- Source/Core/Core/HW/DSPHLE/UCodes/AX.h | 22 ++++++++++++++++++- Source/Core/Core/HW/DSPHLE/UCodes/AXWii.cpp | 24 ++++++++++++++------- 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp index 481805b879..65c526e56d 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/AX.cpp @@ -279,21 +279,6 @@ void AXUCode::HandleCommandList() } } -void AXUCode::ApplyUpdatesForMs(int curr_ms, u16* pb, u16* num_updates, u16* updates) -{ - u32 start_idx = 0; - for (int i = 0; i < curr_ms; ++i) - start_idx += num_updates[i]; - - for (u32 i = start_idx; i < start_idx + num_updates[curr_ms]; ++i) - { - u16 update_off = Common::swap16(updates[2 * i]); - u16 update_val = Common::swap16(updates[2 * i + 1]); - - pb[update_off] = update_val; - } -} - AXMixControl AXUCode::ConvertMixerControl(u32 mixer_control) { u32 ret = 0; @@ -428,7 +413,7 @@ void AXUCode::ProcessPBList(u32 pb_addr) { // Samples per millisecond. In theory DSP sampling rate can be changed from // 32KHz to 48KHz, but AX always process at 32KHz. - const u32 spms = 32; + constexpr u32 spms = 32; AXPB pb; @@ -445,7 +430,7 @@ void AXUCode::ProcessPBList(u32 pb_addr) for (int curr_ms = 0; curr_ms < 5; ++curr_ms) { - ApplyUpdatesForMs(curr_ms, (u16*)&pb, pb.updates.num_updates, updates); + ApplyUpdatesForMs(curr_ms, pb, pb.updates.num_updates, updates); ProcessVoice(pb, buffers, spms, ConvertMixerControl(pb.mixer_control), m_coeffs_available ? m_coeffs : nullptr); diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/AX.h b/Source/Core/Core/HW/DSPHLE/UCodes/AX.h index 2803162834..494d3f4dde 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/AX.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/AX.h @@ -12,7 +12,9 @@ #pragma once +#include "Common/BitUtils.h" #include "Common/CommonTypes.h" +#include "Common/Swap.h" #include "Core/HW/DSPHLE/UCodes/UCodes.h" namespace DSP::HLE @@ -108,7 +110,25 @@ protected: AXMixControl ConvertMixerControl(u32 mixer_control); // Apply updates to a PB. Generic, used in AX GC and AX Wii. - void ApplyUpdatesForMs(int curr_ms, u16* pb, u16* num_updates, u16* updates); + template + void ApplyUpdatesForMs(int curr_ms, PBType& pb, u16* num_updates, u16* updates) + { + auto pb_mem = Common::BitCastToArray(pb); + + u32 start_idx = 0; + for (int i = 0; i < curr_ms; ++i) + start_idx += num_updates[i]; + + for (u32 i = start_idx; i < start_idx + num_updates[curr_ms]; ++i) + { + u16 update_off = Common::swap16(updates[2 * i]); + u16 update_val = Common::swap16(updates[2 * i + 1]); + + pb_mem[update_off] = update_val; + } + + Common::BitCastFromArray(pb_mem, pb); + } virtual void HandleCommandList(); void SignalWorkEnd(); diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/AXWii.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/AXWii.cpp index 8e94982875..9cf79823a8 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/AXWii.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/AXWii.cpp @@ -385,13 +385,13 @@ void AXWiiUCode::GenerateVolumeRamp(u16* output, u16 vol1, u16 vol2, size_t nval bool AXWiiUCode::ExtractUpdatesFields(AXPBWii& pb, u16* num_updates, u16* updates, u32* updates_addr) { - u16* pb_mem = (u16*)&pb; + auto pb_mem = Common::BitCastToArray(pb); if (!m_old_axwii) return false; // Copy the num_updates field. - memcpy(num_updates, pb_mem + 41, 6); + memcpy(num_updates, &pb_mem[41], 6); // Get the address of the updates data u16 addr_hi = pb_mem[44]; @@ -417,17 +417,19 @@ bool AXWiiUCode::ExtractUpdatesFields(AXPBWii& pb, u16* num_updates, u16* update } // Remove the updates data from the PB - memmove(pb_mem + 41, pb_mem + 46, sizeof(pb) - 2 * 46); + memmove(&pb_mem[41], &pb_mem[46], sizeof(pb) - 2 * 46); + + Common::BitCastFromArray(pb_mem, pb); return true; } void AXWiiUCode::ReinjectUpdatesFields(AXPBWii& pb, u16* num_updates, u32 updates_addr) { - u16* pb_mem = (u16*)&pb; + auto pb_mem = Common::BitCastToArray(pb); // Make some space - memmove(pb_mem + 46, pb_mem + 41, sizeof(pb) - 2 * 46); + memmove(&pb_mem[46], &pb_mem[41], sizeof(pb) - 2 * 46); // Reinsert previous values pb_mem[41] = num_updates[0]; @@ -435,10 +437,16 @@ void AXWiiUCode::ReinjectUpdatesFields(AXPBWii& pb, u16* num_updates, u32 update pb_mem[43] = num_updates[2]; pb_mem[44] = updates_addr >> 16; pb_mem[45] = updates_addr & 0xFFFF; + + Common::BitCastFromArray(pb_mem, pb); } void AXWiiUCode::ProcessPBList(u32 pb_addr) { + // Samples per millisecond. In theory DSP sampling rate can be changed from + // 32KHz to 48KHz, but AX always process at 32KHz. + constexpr u32 spms = 32; + AXPBWii pb; while (pb_addr) @@ -460,13 +468,13 @@ void AXWiiUCode::ProcessPBList(u32 pb_addr) { for (int curr_ms = 0; curr_ms < 3; ++curr_ms) { - ApplyUpdatesForMs(curr_ms, (u16*)&pb, num_updates, updates); - ProcessVoice(pb, buffers, 32, ConvertMixerControl(HILO_TO_32(pb.mixer_control)), + ApplyUpdatesForMs(curr_ms, pb, num_updates, updates); + ProcessVoice(pb, buffers, spms, ConvertMixerControl(HILO_TO_32(pb.mixer_control)), m_coeffs_available ? m_coeffs : nullptr); // Forward the buffers for (auto& ptr : buffers.ptrs) - ptr += 32; + ptr += spms; } ReinjectUpdatesFields(pb, num_updates, updates_addr); }