diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/AESnd.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/AESnd.cpp index 34c2308468..122044dda6 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/AESnd.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/AESnd.cpp @@ -26,19 +26,6 @@ constexpr u32 MAIL_GET_PB_ADDRESS = MAIL_PREFIX | 0x0080; constexpr u32 MAIL_SEND_SAMPLES = MAIL_PREFIX | 0x0100; constexpr u32 MAIL_TERMINATE = MAIL_PREFIX | 0xdead; -// June 5, 2010 version (padded to 0x03e0 bytes) - initial release -// First included with libogc 1.8.4 on October 3, 2010: https://devkitpro.org/viewtopic.php?t=2249 -// https://github.com/devkitPro/libogc/blob/b5fdbdb069c45584aa4dfd950a136a8db9b1144c/libaesnd/dspcode/dspmixer.s -constexpr u32 HASH_2010 = 0x008366af; -// April 11, 2012 version (padded to 0x03e0 bytes) - swapped input channels -// First included with libogc 1.8.11 on April 22, 2012: https://devkitpro.org/viewtopic.php?t=3094 -// https://github.com/devkitPro/libogc/commit/8f188e12b6a3d8b5a0d49a109fe6a3e4e1702aab -constexpr u32 HASH_2012 = 0x078066ab; -// June 14, 2020 version (0x03e6 bytes) - added unsigned formats -// First included with libogc 2.1.0 on June 15, 2020: https://devkitpro.org/viewtopic.php?t=9079 -// https://github.com/devkitPro/libogc/commit/eac8fe2c29aa790d552dd6166a1fb195dfdcb825 -constexpr u32 HASH_2020 = 0x84c680a9; - constexpr u32 VOICE_MONO8 = 0x00000000; constexpr u32 VOICE_STEREO8 = 0x00000001; constexpr u32 VOICE_MONO16 = 0x00000002; @@ -81,6 +68,16 @@ constexpr u32 ACCELERATOR_GAIN_8_BIT = 0x0100; // Multiply samples by 0x800/2048 = 1 (for ACCELERATOR_FORMAT_16_BIT) constexpr u32 ACCELERATOR_GAIN_16_BIT = 0x0800; +bool AESndUCode::SwapLeftRight() const +{ + return m_crc == HASH_2012 || m_crc == HASH_EDUKE32 || m_crc == HASH_2020; +} + +bool AESndUCode::UseNewFlagMasks() const +{ + return m_crc == HASH_EDUKE32 || m_crc == HASH_2020; +} + AESndUCode::AESndUCode(DSPHLE* dsphle, u32 crc) : UCodeInterface(dsphle, crc) { } @@ -136,25 +133,25 @@ void AESndUCode::HandleMail(u32 mail) switch (mail) { case MAIL_PROCESS_FIRST_VOICE: - DEBUG_LOG_FMT(DSPHLE, "ASndUCode - MAIL_PROCESS_FIRST_VOICE"); + DEBUG_LOG_FMT(DSPHLE, "AESndUCode - MAIL_PROCESS_FIRST_VOICE"); DMAInParameterBlock(); // dma_pb_block m_output_buffer.fill(0); DoMixing(); // fall through to dsp_mixer // Mail is handled by DoMixing() break; case MAIL_PROCESS_NEXT_VOICE: - DEBUG_LOG_FMT(DSPHLE, "ASndUCode - MAIL_PROCESS_NEXT_VOICE"); + DEBUG_LOG_FMT(DSPHLE, "AESndUCode - MAIL_PROCESS_NEXT_VOICE"); DMAInParameterBlock(); // dma_pb_block DoMixing(); // jump to dsp_mixer // Mail is handled by DoMixing() break; case MAIL_GET_PB_ADDRESS: - DEBUG_LOG_FMT(DSPHLE, "ASndUCode - MAIL_GET_PB_ADDRESS"); + DEBUG_LOG_FMT(DSPHLE, "AESndUCode - MAIL_GET_PB_ADDRESS"); m_next_mail_is_parameter_block_addr = true; // No mail is sent in response break; case MAIL_SEND_SAMPLES: - DEBUG_LOG_FMT(DSPHLE, "ASndUCode - MAIL_SEND_SAMPLES"); + DEBUG_LOG_FMT(DSPHLE, "AESndUCode - MAIL_SEND_SAMPLES"); // send_samples for (u32 i = 0; i < NUM_OUTPUT_SAMPLES * 2; i++) { @@ -163,8 +160,31 @@ void AESndUCode::HandleMail(u32 mail) m_mail_handler.PushMail(DSP_SYNC, true); break; case MAIL_TERMINATE: - INFO_LOG_FMT(DSPHLE, "ASndUCode - MAIL_TERMINATE: {:08x}", mail); - // This doesn't actually change the state of the system. + INFO_LOG_FMT(DSPHLE, "AESndUCode - MAIL_TERMINATE: {:08x}", mail); + if (true) // currently no mainline libogc uCode has this issue fixed + { + // The relevant code looks like this: + // + // lrs $acc1.m,@CMBL + // ... + // cmpi $acc1.m,#0xdead + // jeq task_terminate + // + // The cmpi instruction always sign-extends, so it will compare $acc1 with 0xff'dead'0000. + // However, recv_cmd runs in set16 mode, so the load to $acc1 will produce 0x00'dead'0000. + // This means that the comparison never succeeds, and no mail is sent in response to + // MAIL_TERMINATE. This means that __dsp_donecallback is never called (since that's + // normally called in response to DSP_DONE), so __aesnddspinit is never cleared, so + // AESND_Reset never returns, resulting in a hang. We always send the mail to avoid this + // hang. (It's possible to exit without calling AESND_Reset, so most homebrew probably + // isn't affected by this bug in the first place.) + // + // A fix exists, but has not yet been added to mainline libogc: + // https://github.com/extremscorner/libogc2/commit/38edc9db93232faa612f680c91be1eb4d95dd1c6 + WARN_LOG_FMT(DSPHLE, "AESndUCode - MAIL_TERMINATE is broken in this version of the " + "uCode; this will hang on real hardware or with DSP LLE"); + } + // This doesn't actually change the state of the DSP code. m_mail_handler.PushMail(DSP_DONE, true); break; default: @@ -248,8 +268,8 @@ void AESndUCode::SetUpAccelerator(u16 format, [[maybe_unused]] u16 gain) void AESndUCode::DoMixing() { - const u32 pause_flag = (m_crc == HASH_2020) ? VOICE_PAUSE_NEW : VOICE_PAUSE_OLD; - const u32 format_mask = (m_crc == HASH_2020) ? VOICE_FORMAT_MASK_NEW : VOICE_FORMAT_MASK_OLD; + const u32 pause_flag = UseNewFlagMasks() ? VOICE_PAUSE_NEW : VOICE_PAUSE_OLD; + const u32 format_mask = UseNewFlagMasks() ? VOICE_FORMAT_MASK_NEW : VOICE_FORMAT_MASK_OLD; // dsp_mixer const bool paused = (m_parameter_block.flags & pause_flag) != 0; const bool running = (m_parameter_block.flags & VOICE_RUNNING) != 0; @@ -259,6 +279,22 @@ void AESndUCode::DoMixing() // no_change_buffer const u32 voice_format = m_parameter_block.flags & format_mask; const bool is_16_bit = (voice_format & VOICE_16_BIT_FLAG) != 0; + if (m_crc == HASH_EDUKE32) + { + if (voice_format != VOICE_STEREO8 && voice_format != VOICE_STEREO16 && + voice_format != VOICE_STEREO8_UNSIGNED) + { + // The EDuke32 Wii version does not support 16-but unsigned stereo, and also has broken + // handling of all mono formats. + if (!m_has_shown_unsupported_sample_format_warning) + { + m_has_shown_unsupported_sample_format_warning = true; + PanicAlertFmt("EDuke32 Wii aesndlib uCode does not correctly handle this sample format: " + "{} (flags: {:08x})", + voice_format, m_parameter_block.flags); + } + } + } // select_format table const u16 accelerator_format = is_16_bit ? ACCELERATOR_FORMAT_16_BIT : ACCELERATOR_FORMAT_8_BIT; const u16 accelerator_gain = is_16_bit ? ACCELERATOR_GAIN_16_BIT : ACCELERATOR_GAIN_8_BIT; @@ -363,7 +399,7 @@ void AESndUCode::DoMixing() new_l ^= 0x8000; break; } - if (m_crc == HASH_2012 || m_crc == HASH_2020) + if (SwapLeftRight()) { // The 2012 version swapped the left and right input channels so that left comes first, // and then right. Before, right came before left. The 2012 version didn't update comments diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/AESnd.h b/Source/Core/Core/HW/DSPHLE/UCodes/AESnd.h index a13046be94..5991d3c027 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/AESnd.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/AESnd.h @@ -23,12 +23,32 @@ public: void Update() override; void DoState(PointerWrap& p) override; + // June 5, 2010 version (padded to 0x03e0 bytes) - initial release + // First included with libogc 1.8.4 on October 3, 2010: https://devkitpro.org/viewtopic.php?t=2249 + // https://github.com/devkitPro/libogc/blob/b5fdbdb069c45584aa4dfd950a136a8db9b1144c/libaesnd/dspcode/dspmixer.s + static constexpr u32 HASH_2010 = 0x008366af; + // April 11, 2012 version (padded to 0x03e0 bytes) - swapped input channels + // First included with libogc 1.8.11 on April 22, 2012: https://devkitpro.org/viewtopic.php?t=3094 + // https://github.com/devkitPro/libogc/commit/8f188e12b6a3d8b5a0d49a109fe6a3e4e1702aab + static constexpr u32 HASH_2012 = 0x078066ab; + // Modified version used by EDuke32 Wii (padded to 0x03e0 bytes) - added unsigned 8-bit formats; + // broke the mono formats. The patch is based on the 2010 version, but it also includes the 2012 + // input channel swap change. https://dukeworld.duke4.net/eduke32/wii/library_source_code/ + static constexpr u32 HASH_EDUKE32 = 0x5ad4d933; + // June 14, 2020 version (0x03e6 bytes) - added unsigned formats + // First included with libogc 2.1.0 on June 15, 2020: https://devkitpro.org/viewtopic.php?t=9079 + // https://github.com/devkitPro/libogc/commit/eac8fe2c29aa790d552dd6166a1fb195dfdcb825 + static constexpr u32 HASH_2020 = 0x84c680a9; + private: void DMAInParameterBlock(); void DMAOutParameterBlock(); void SetUpAccelerator(u16 format, u16 gain); void DoMixing(); + bool SwapLeftRight() const; + bool UseNewFlagMasks() const; + // Copied from libaesnd/aesndlib.c's aesndpb_t (specifically the first 64 bytes) #pragma pack(1) struct ParameterBlock @@ -70,5 +90,7 @@ private: static constexpr u32 NUM_OUTPUT_SAMPLES = 96; std::array m_output_buffer{}; + + bool m_has_shown_unsupported_sample_format_warning = false; }; } // namespace DSP::HLE diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/ASnd.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/ASnd.cpp index e033d276d7..d00e82be03 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/ASnd.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/ASnd.cpp @@ -52,27 +52,6 @@ constexpr u32 NEW_FLAGS_SAMPLE_FORMAT_MASK = 7; constexpr u32 FLAGS_SAMPLE_FORMAT_BYTES_MASK = 0xffff0000; constexpr u32 FLAGS_SAMPLE_FORMAT_BYTES_SHIFT = 16; -// November 14, 2008 version (padded to 0x05a0 bytes) - initial release -// https://github.com/devkitPro/libogc/compare/c76d8b851fafc11b0a5debc0b40842929d5a5825~...353a44f038e75e5982eb550173ec8127ab35e3e3 -constexpr u32 HASH_2008 = 0x8d69a19b; -// February 5, 2009 version (padded to 0x05c0 bytes) - added MAIL_TERMINATE -// https://github.com/devkitPro/libogc/compare/1925217ffb4c97cbee5cf21fa3c0231029b340e2~...3b1f018dbe372859a43bff8560e2525f6efa4433 -constexpr u32 HASH_2009 = 0xcc2fd441; -// June 11, 2011 version (padded to 0x0620 bytes) - added new sample formats, which shifted flags -// Note that the source include in the repo does not match the compiled binary exactly; the compiled -// version differs by using asl instead of lsl, $acc1 instead of $acc0, and $ac0.l instead of $ac0.m -// in various locations, as well as having the "jmp out_samp" line uncommented in stereo_16bits_le. -// None of these result in a behavior difference, from the source, though. -// Note that gcdsptool was also updated, which results in some differences in the source that don't -// actually correspond to different instructions (e.g. s40 was renamed to s16) -// https://github.com/devkitPro/libogc/commit/b1b8ecab3af3745c8df0b401abd512bdf5fcc011 -constexpr u32 HASH_2011 = 0xa81582e2; -// June 12, 2020 version (0x0606 bytes) - libogc switched to compiling the ucode at build time -// instead of including a pre-compiled version in the repo, so this now corresponds to the code -// provided in the repo. There appear to be no behavior differences from the 2011 version. -// https://github.com/devkitPro/libogc/compare/bfb705fe1607a3031d18b65d603975b68a1cffd4~...d20f9bdcfb43260c6c759f4fb98d724931443f93 -constexpr u32 HASH_2020 = 0xdbbeeb61; - constexpr u32 SAMPLE_RATE = 48000; ASndUCode::ASndUCode(DSPHLE* dsphle, u32 crc) : UCodeInterface(dsphle, crc) diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/ASnd.h b/Source/Core/Core/HW/DSPHLE/UCodes/ASnd.h index 45ef40c0e0..419d19d92d 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/ASnd.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/ASnd.h @@ -23,6 +23,27 @@ public: void Update() override; void DoState(PointerWrap& p) override; + // November 14, 2008 version (padded to 0x05a0 bytes) - initial release + // https://github.com/devkitPro/libogc/compare/c76d8b851fafc11b0a5debc0b40842929d5a5825~...353a44f038e75e5982eb550173ec8127ab35e3e3 + static constexpr u32 HASH_2008 = 0x8d69a19b; + // February 5, 2009 version (padded to 0x05c0 bytes) - added MAIL_TERMINATE + // https://github.com/devkitPro/libogc/compare/1925217ffb4c97cbee5cf21fa3c0231029b340e2~...3b1f018dbe372859a43bff8560e2525f6efa4433 + static constexpr u32 HASH_2009 = 0xcc2fd441; + // June 11, 2011 version (padded to 0x0620 bytes) - added new sample formats, which shifted flags + // Note that the source include in the repo does not match the compiled binary exactly; the + // compiled version differs by using asl instead of lsl, $acc1 instead of $acc0, and $ac0.l + // instead of $ac0.m in various locations, as well as having the "jmp out_samp" line uncommented + // in stereo_16bits_le. None of these result in a behavior difference, from the source, though. + // Note that gcdsptool was also updated, which results in some differences in the source that + // don't actually correspond to different instructions (e.g. s40 was renamed to s16) + // https://github.com/devkitPro/libogc/commit/b1b8ecab3af3745c8df0b401abd512bdf5fcc011 + static constexpr u32 HASH_2011 = 0xa81582e2; + // June 12, 2020 version (0x0606 bytes) - libogc switched to compiling the ucode at build time + // instead of including a pre-compiled version in the repo, so this now corresponds to the code + // provided in the repo. There appear to be no behavior differences from the 2011 version. + // https://github.com/devkitPro/libogc/compare/bfb705fe1607a3031d18b65d603975b68a1cffd4~...d20f9bdcfb43260c6c759f4fb98d724931443f93 + static constexpr u32 HASH_2020 = 0xdbbeeb61; + private: void DMAInVoiceData(); void DMAOutVoiceData(); diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.cpp index 94a594aec7..72c387ed5e 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.cpp @@ -284,16 +284,17 @@ std::unique_ptr UCodeFactory(u32 crc, DSPHLE* dsphle, bool wii) INFO_LOG_FMT(DSPHLE, "CRC {:08x}: Wii - AXWii chosen", crc); return std::make_unique(dsphle, crc); - case 0x8d69a19b: - case 0xcc2fd441: - case 0xa81582e2: - case 0xdbbeeb61: + case ASndUCode::HASH_2008: + case ASndUCode::HASH_2009: + case ASndUCode::HASH_2011: + case ASndUCode::HASH_2020: INFO_LOG_FMT(DSPHLE, "CRC {:08x}: ASnd chosen (Homebrew)", crc); return std::make_unique(dsphle, crc); - case 0x008366af: - case 0x078066ab: - case 0x84c680a9: + case AESndUCode::HASH_2010: + case AESndUCode::HASH_2012: + case AESndUCode::HASH_EDUKE32: + case AESndUCode::HASH_2020: INFO_LOG_FMT(DSPHLE, "CRC {:08x}: AESnd chosen (Homebrew)", crc); return std::make_unique(dsphle, crc);