diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/AX.h b/Source/Core/Core/HW/DSPHLE/UCodes/AX.h index 52adc73b63..4755002521 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/AX.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/AX.h @@ -74,17 +74,9 @@ public: void DoState(PointerWrap& p) override; protected: - enum MailType - { - MAIL_RESUME = 0xCDD10000, - MAIL_NEW_UCODE = 0xCDD10001, - MAIL_RESET = 0xCDD10002, - MAIL_CONTINUE = 0xCDD10003, - - // CPU sends 0xBABE0000 | cmdlist_size to the DSP - MAIL_CMDLIST = 0xBABE0000, - MAIL_CMDLIST_MASK = 0xFFFF0000 - }; + // CPU sends 0xBABE0000 | cmdlist_size to the DSP + static constexpr u32 MAIL_CMDLIST = 0xBABE0000; + static constexpr u32 MAIL_CMDLIST_MASK = 0xFFFF0000; // 32 * 5 because 32 samples per millisecond, for max 5 milliseconds. int m_samples_main_left[32 * 5]{}; diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/GBA.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/GBA.cpp index 6704a489ec..b734d16d4c 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/GBA.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/GBA.cpp @@ -114,14 +114,14 @@ void GBAUCode::HandleMail(u32 mail) calc_done = true; m_mail_handler.PushMail(DSP_DONE); } - else if ((mail >> 16 == 0xcdd1) && calc_done) + else if (((mail & TASK_MAIL_MASK) == TASK_MAIL_TO_DSP) && calc_done) { - switch (mail & 0xffff) + switch (mail) { - case 1: + case MAIL_NEW_UCODE: m_upload_setup_in_progress = true; break; - case 2: + case MAIL_RESET: m_dsphle->SetUCode(UCODE_ROM); break; default: diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.h b/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.h index 0ca71dea01..408c1e1239 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.h +++ b/Source/Core/Core/HW/DSPHLE/UCodes/UCodes.h @@ -61,15 +61,50 @@ protected: CMailHandler& m_mail_handler; - enum EDSP_Codes : u32 - { - DSP_INIT = 0xDCD10000, - DSP_RESUME = 0xDCD10001, - DSP_YIELD = 0xDCD10002, - DSP_DONE = 0xDCD10003, - DSP_SYNC = 0xDCD10004, - DSP_FRAME_END = 0xDCD10005, - }; + static constexpr u32 TASK_MAIL_MASK = 0xFFFF'0000; + // Task-management mails, used for uCode switching. The DSP sends mail with 0xDCD1 in the high + // word to the CPU to report its status. The CPU reacts in different ways for different mails. + // Also, Zelda uCode titles use a slightly different handler compared to AX uCode titles. Libogc's + // mail handler is based on the AX one. + static constexpr u32 TASK_MAIL_TO_CPU = 0xDCD1'0000; + // Triggers a callback. No response is sent. + static constexpr u32 DSP_INIT = TASK_MAIL_TO_CPU | 0x0000; + // Triggers a callback. No response is sent. + static constexpr u32 DSP_RESUME = TASK_MAIL_TO_CPU | 0x0001; + // If the current task is canceled by the CPU, the CPU processes this mail as if it were DSP_DONE + // instead. Otherwise, it is handled differently for Zelda uCode games and AX games. + // On Zelda uCode, the CPU will always respond with MAIL_NEW_UCODE. + // On AX uCode, the CPU will respond with MAIL_NEW_UCODE if it has a new task, and otherwise + // will use MAIL_CONTINUE. + static constexpr u32 DSP_YIELD = TASK_MAIL_TO_CPU | 0x0002; + // Triggers a callback. The response is handled differently for Zelda uCode games and AX games. + // On Zelda uCode, the CPU will always respond with MAIL_NEW_UCODE. + // On AX uCode, the CPU will respond with MAIL_NEW_UCODE if there is a new task, and otherwise + // will use MAIL_RESET if the finished task was the only task. + static constexpr u32 DSP_DONE = TASK_MAIL_TO_CPU | 0x0003; + // Triggers a callback. No response is sent. + static constexpr u32 DSP_SYNC = TASK_MAIL_TO_CPU | 0x0004; + // Used by Zelda uCode only. Zelda uCode titles (or at least Super Mario Sunshine and Super Mario + // Galaxy) will log "Audio Yield Start", send MAIL_NEW_UCODE, and then log "Audio Yield Finish" if + // they have a task to execute (e.g. the card uCode), and otherwise will send MAIL_CONTINUE. + static constexpr u32 DSP_FRAME_END = TASK_MAIL_TO_CPU | 0x0005; + + // The CPU will send a mail prefixed with 0xCDD1 in the high word in response. + static constexpr u32 TASK_MAIL_TO_DSP = 0xCDD1'0000; + // On AX, this sends DSP_RESUME and then returns to normal execution. On Zelda, this immediately + // HALTs. Other uCodes (e.g. Card, GBA) do not implement (and instead ignore) this mail. + // This mail does not seem to be sent in practice. + static constexpr u32 MAIL_RESUME = TASK_MAIL_TO_DSP | 0x0000; + // Starts populating info for a new uCode (see PrepareBootUCode and m_upload_setup_in_progress). + // The current uCode's state can optionally be saved, although the Card and GBA uCode do not + // support this (as there is no reason to reload their old state). + static constexpr u32 MAIL_NEW_UCODE = TASK_MAIL_TO_DSP | 0x0001; + // Immediately switches to ROM uCode. Implemented by the Zelda uCode, but the Zelda uCode task + // handler doesn't seem to send it. + static constexpr u32 MAIL_RESET = TASK_MAIL_TO_DSP | 0x0002; + // Jumps back to the main loop. Not implemented by all uCode (in particular Card and GBA which do + // not have a main loop). + static constexpr u32 MAIL_CONTINUE = TASK_MAIL_TO_DSP | 0x0003; // UCode is forwarding mails to PrepareBootUCode // UCode only needs to set this to true, UCodeInterface will set to false when done! diff --git a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp index 7cfab59596..a3bf46fb9f 100644 --- a/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp +++ b/Source/Core/Core/HW/DSPHLE/UCodes/Zelda.cpp @@ -201,14 +201,16 @@ void ZeldaUCode::HandleMailDefault(u32 mail) case MailState::WAITING: if (mail & 0x80000000) { - if ((mail >> 16) != 0xCDD1) + if ((mail & TASK_MAIL_MASK) != TASK_MAIL_TO_DSP) { - PanicAlertFmt("Rendering end mail without prefix CDD1: {:08x}", mail); + WARN_LOG_FMT(DSPHLE, "Received rendering end mail without prefix CDD1: {:08x}", mail); + mail = TASK_MAIL_TO_DSP | (mail & ~TASK_MAIL_MASK); + // The actual uCode does not check for the CDD1 prefix. } - switch (mail & 0xFFFF) + switch (mail) { - case 1: + case MAIL_NEW_UCODE: m_cmd_can_execute = true; RunPendingCommands(); NOTICE_LOG_FMT(DSPHLE, "UCode being replaced."); @@ -216,13 +218,13 @@ void ZeldaUCode::HandleMailDefault(u32 mail) SetMailState(MailState::WAITING); break; - case 2: + case MAIL_RESET: NOTICE_LOG_FMT(DSPHLE, "UCode being rebooted to ROM."); SetMailState(MailState::HALTED); m_dsphle->SetUCode(UCODE_ROM); break; - case 3: + case MAIL_CONTINUE: m_cmd_can_execute = true; RunPendingCommands(); break; @@ -230,7 +232,7 @@ void ZeldaUCode::HandleMailDefault(u32 mail) default: NOTICE_LOG_FMT(DSPHLE, "Unknown end rendering action. Halting."); [[fallthrough]]; - case 0: + case MAIL_RESUME: NOTICE_LOG_FMT(DSPHLE, "UCode asked to halt. Stopping any processing."); SetMailState(MailState::HALTED); break;