Merge pull request #10892 from Pokechu22/dsp-hle-aesnd-more-versions

DSPHLE: Support EDuke32 Wii libaesnd uCode
This commit is contained in:
Admiral H. Curtiss 2022-07-26 11:36:18 +02:00 committed by GitHub
commit c7752f80e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 109 additions and 50 deletions

View File

@ -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

View File

@ -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<s16, NUM_OUTPUT_SAMPLES * 2> m_output_buffer{};
bool m_has_shown_unsupported_sample_format_warning = false;
};
} // namespace DSP::HLE

View File

@ -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)

View File

@ -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();

View File

@ -284,16 +284,17 @@ std::unique_ptr<UCodeInterface> UCodeFactory(u32 crc, DSPHLE* dsphle, bool wii)
INFO_LOG_FMT(DSPHLE, "CRC {:08x}: Wii - AXWii chosen", crc);
return std::make_unique<AXWiiUCode>(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<ASndUCode>(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<AESndUCode>(dsphle, crc);