From 63d0c7f85a4a125fb032a50582df4c7de8d8074c Mon Sep 17 00:00:00 2001 From: Angie Date: Sat, 25 May 2024 19:22:53 -0400 Subject: [PATCH] Move most RSP stuff to librecomp --- librecomp/include/recomp_game.h | 3 +- librecomp/include/rsp.h | 41 ++++++++++++- librecomp/src/recomp.cpp | 9 ++- librecomp/src/rsp.cpp | 61 +++++++++++++++++++ ultramodern/include/ultramodern/rsp_stuff.hpp | 41 ++----------- .../include/ultramodern/ultramodern.hpp | 4 +- ultramodern/src/events.cpp | 11 +--- ultramodern/src/rsp.cpp | 51 +++------------- ultramodern/src/ultrainit.cpp | 4 +- 9 files changed, 131 insertions(+), 94 deletions(-) create mode 100644 librecomp/src/rsp.cpp diff --git a/librecomp/include/recomp_game.h b/librecomp/include/recomp_game.h index 1791f71..af4abea 100644 --- a/librecomp/include/recomp_game.h +++ b/librecomp/include/recomp_game.h @@ -5,6 +5,7 @@ #include #include "recomp.h" +#include "rsp.h" #include namespace recomp { @@ -38,7 +39,7 @@ namespace recomp { void set_rom_contents(std::vector&& new_rom); void do_rom_read(uint8_t* rdram, gpr ram_address, uint32_t physical_addr, size_t num_bytes); void do_rom_pio(uint8_t* rdram, gpr ram_address, uint32_t physical_addr); - void start(ultramodern::WindowHandle window_handle, const ultramodern::audio_callbacks_t& audio_callbacks, const ultramodern::input_callbacks_t& input_callbacks, const ultramodern::gfx_callbacks_t& gfx_callbacks, const ultramodern::rsp::callbacks_t& rsp_callbacks, const ultramodern::events::callbacks_t& thread_callbacks, const ultramodern::error_handling::callbacks_t& error_handling_callbacks_); + void start(ultramodern::WindowHandle window_handle, const recomp::rsp::callbacks_t& rsp_callbacks, const ultramodern::audio_callbacks_t& audio_callbacks, const ultramodern::input_callbacks_t& input_callbacks, const ultramodern::gfx_callbacks_t& gfx_callbacks, const ultramodern::events::callbacks_t& thread_callbacks, const ultramodern::error_handling::callbacks_t& error_handling_callbacks_); void start_game(const std::u8string& game_id); void message_box(const char* message); std::filesystem::path get_app_folder_path(); diff --git a/librecomp/include/rsp.h b/librecomp/include/rsp.h index a6b7107..b980403 100644 --- a/librecomp/include/rsp.h +++ b/librecomp/include/rsp.h @@ -5,7 +5,23 @@ #include "rsp_vu.h" #include "recomp.h" -#include "ultramodern/rsp_stuff.hpp" +#include "ultramodern/ultra64.h" + +// TODO: Move these to recomp namespace? + +enum class RspExitReason { + Invalid, + Broke, + ImemOverrun, + UnhandledJumpTarget, + Unsupported +}; + +using RspUcodeFunc = RspExitReason(uint8_t* rdram); + +extern uint8_t dmem[]; +extern uint16_t rspReciprocals[512]; +extern uint16_t rspInverseSquareRoots[512]; #define RSP_MEM_B(offset, addr) \ (*reinterpret_cast(dmem + (0xFFF & (((offset) + (addr)) ^ 3)))) @@ -81,4 +97,27 @@ static inline void dma_dmem_to_rdram(uint8_t* rdram, uint32_t dmem_addr, uint32_ } } +namespace recomp { + namespace rsp { + struct callbacks_t { + using get_rsp_microcode_t = RspUcodeFunc*(const OSTask* task); + + /** + * Return a function pointer to the corresponding RSP microcode function for the given `task_type`. + * + * The full OSTask (`task` parameter) is passed in case the `task_type` number is not enough information to distinguish out the exact microcode function. + * + * This function is allowed to return `nullptr` if no microcode matches the specified task. In this case a message will be printed to stderr and the program will exit. + */ + get_rsp_microcode_t* get_rsp_microcode; + }; + + void set_callbacks(const callbacks_t& callbacks); + + void constants_init(); + + bool run_microcode(uint8_t* rdram, const OSTask* task); + } +} + #endif diff --git a/librecomp/src/recomp.cpp b/librecomp/src/recomp.cpp index 4952b36..fe1448b 100644 --- a/librecomp/src/recomp.cpp +++ b/librecomp/src/recomp.cpp @@ -425,10 +425,15 @@ void ultramodern::quit() { current_game.reset(); } -void recomp::start(ultramodern::WindowHandle window_handle, const ultramodern::audio_callbacks_t& audio_callbacks, const ultramodern::input_callbacks_t& input_callbacks, const ultramodern::gfx_callbacks_t& gfx_callbacks_, const ultramodern::rsp::callbacks_t& rsp_callbacks_, const ultramodern::events::callbacks_t& thread_callbacks_, const ultramodern::error_handling::callbacks_t& error_handling_callbacks_) { +void recomp::start(ultramodern::WindowHandle window_handle, const recomp::rsp::callbacks_t& rsp_callbacks, const ultramodern::audio_callbacks_t& audio_callbacks, const ultramodern::input_callbacks_t& input_callbacks, const ultramodern::gfx_callbacks_t& gfx_callbacks_, const ultramodern::events::callbacks_t& thread_callbacks_, const ultramodern::error_handling::callbacks_t& error_handling_callbacks_) { recomp::check_all_stored_roms(); - ultramodern::set_callbacks(audio_callbacks, input_callbacks, gfx_callbacks_, rsp_callbacks_, thread_callbacks_, error_handling_callbacks_); + recomp::rsp::set_callbacks(rsp_callbacks); + + ultramodern::set_callbacks(ultramodern::rsp::callbacks_t { + .init = recomp::rsp::constants_init, + .run_microcode = recomp::rsp::run_microcode, + }, audio_callbacks, input_callbacks, gfx_callbacks_, thread_callbacks_, error_handling_callbacks_); set_input_callbacks(input_callbacks); diff --git a/librecomp/src/rsp.cpp b/librecomp/src/rsp.cpp new file mode 100644 index 0000000..6d754f6 --- /dev/null +++ b/librecomp/src/rsp.cpp @@ -0,0 +1,61 @@ +#include +#include +#include + +#include "rsp.h" + +static recomp::rsp::callbacks_t rsp_callbacks {}; + +void recomp::rsp::set_callbacks(const callbacks_t& callbacks) { + rsp_callbacks = callbacks; +} + +uint8_t dmem[0x1000]; +uint16_t rspReciprocals[512]; +uint16_t rspInverseSquareRoots[512]; + +// From Ares emulator. For license details, see rsp_vu.h +void recomp::rsp::constants_init() { + rspReciprocals[0] = u16(~0); + for (u16 index = 1; index < 512; index++) { + u64 a = index + 512; + u64 b = (u64(1) << 34) / a; + rspReciprocals[index] = u16((b + 1) >> 8); + } + + for (u16 index = 0; index < 512; index++) { + u64 a = (index + 512) >> ((index % 2 == 1) ? 1 : 0); + u64 b = 1 << 17; + //find the largest b where b < 1.0 / sqrt(a) + while (a * (b + 1) * (b + 1) < (u64(1) << 44)) b++; + rspInverseSquareRoots[index] = u16(b >> 1); + } +} + +// Runs a recompiled RSP microcode +bool recomp::rsp::run_microcode(uint8_t* rdram, const OSTask* task) { + assert(rsp_callbacks.get_rsp_microcode != nullptr); + RspUcodeFunc* ucode_func = rsp_callbacks.get_rsp_microcode(task); + + if (ucode_func == nullptr) { + return false; + } + + // Load the OSTask into DMEM + memcpy(&dmem[0xFC0], task, sizeof(OSTask)); + + // Load the ucode data into DMEM + dma_rdram_to_dmem(rdram, 0x0000, task->t.ucode_data, 0xF80 - 1); + + // Run the ucode + RspExitReason exit_reason = ucode_func(rdram); + + // Ensure that the ucode exited correctly + if (exit_reason != RspExitReason::Broke) { + fprintf(stderr, "RSP ucode %" PRIu32 " exited unexpectedly. exit_reason: %i\n", task->t.type, exit_reason); + assert(exit_reason == RspExitReason::Broke); + return false; + } + + return true; +} diff --git a/ultramodern/include/ultramodern/rsp_stuff.hpp b/ultramodern/include/ultramodern/rsp_stuff.hpp index a5a1486..dbcde01 100644 --- a/ultramodern/include/ultramodern/rsp_stuff.hpp +++ b/ultramodern/include/ultramodern/rsp_stuff.hpp @@ -9,49 +9,20 @@ // TODO: Move these to ultramodern namespace? -enum class RspExitReason { - Invalid, - Broke, - ImemOverrun, - UnhandledJumpTarget, - Unsupported -}; - -using RspUcodeFunc = RspExitReason(uint8_t* rdram); - -extern uint8_t dmem[]; -extern uint16_t rspReciprocals[512]; -extern uint16_t rspInverseSquareRoots[512]; - namespace ultramodern { namespace rsp { struct callbacks_t { - using dma_rdram_to_dmem_t = void(uint8_t* rdram, uint32_t dmem_addr, uint32_t dram_addr, uint32_t rd_len); - using get_rsp_microcode_t = RspUcodeFunc*(uint32_t task_type, OSTask* task); + using init_t = void(); + using run_microcode_t = bool(RDRAM_ARG const OSTask* task); - /** - * Simulate a DMA copy from RDRAM (CPU) to DMEM (RSP). - * - * This function should fill the ultramodern's `dmem` by reading from the `rdram` parameter. - */ - dma_rdram_to_dmem_t* dma_rdram_to_dmem; - - /** - * Return a function pointer to the corresponding RSP microcode function for the given `task_type`. - * - * The full OSTask (`task` parameter) is passed in case the `task_type` number is not enough information to distinguish out the exact microcode function. - * - * This function is allowed to return `nullptr` if no microcode matches the specified task. In this case a message will be printed to stderr and the program will exit. - */ - get_rsp_microcode_t* get_rsp_microcode; + init_t* init; + run_microcode_t* run_microcode; }; void set_callbacks(const callbacks_t& callbacks); - void constants_init(); - - RspUcodeFunc* get_microcode(uint32_t task_type, OSTask* task); - void run_microcode(uint8_t* rdram, const OSTask* task, RspUcodeFunc* ucode_func); + void init(); + bool run_microcode(RDRAM_ARG const OSTask* task); }; } // namespace ultramodern diff --git a/ultramodern/include/ultramodern/ultramodern.hpp b/ultramodern/include/ultramodern/ultramodern.hpp index 9f73eaa..1c0cd2d 100644 --- a/ultramodern/include/ultramodern/ultramodern.hpp +++ b/ultramodern/include/ultramodern/ultramodern.hpp @@ -173,11 +173,11 @@ void join_saving_thread(); void set_audio_callbacks(const audio_callbacks_t& callbacks); /** - * Register all the callbacks required by `ultramodern`. + * Register all the callbacks used by `ultramodern`, most of them being optional. * * It must be called only once and it must be called before `ultramodern::preinit`. */ -void set_callbacks(const audio_callbacks_t& audio_callbacks, const input_callbacks_t& input_callbacks, const gfx_callbacks_t& gfx_callbacks_, const rsp::callbacks_t& rsp_callbacks_, const events::callbacks_t& thread_callbacks, const error_handling::callbacks_t& error_handling_callbacks); +void set_callbacks(const rsp::callbacks_t& rsp_callbacks, const audio_callbacks_t& audio_callbacks, const input_callbacks_t& input_callbacks, const gfx_callbacks_t& gfx_callbacks, const events::callbacks_t& thread_callbacks, const error_handling::callbacks_t& error_handling_callbacks); } // namespace ultramodern #define MIN(a, b) ((a) < (b) ? (a) : (b)) diff --git a/ultramodern/src/events.cpp b/ultramodern/src/events.cpp index c74ef43..be5668a 100644 --- a/ultramodern/src/events.cpp +++ b/ultramodern/src/events.cpp @@ -213,14 +213,9 @@ void task_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_r return; } - // Ask the user what the correct ucode function is this. - RspUcodeFunc* ucode_func = ultramodern::rsp::get_microcode(task->t.type, task); - if (ucode_func != nullptr) { - ultramodern::rsp::run_microcode(rdram, task, ucode_func); - } - else { - fprintf(stderr, "Unknown task type: %" PRIu32 "\n", task->t.type); + if (!ultramodern::rsp::run_microcode(PASS_RDRAM task)) { + fprintf(stderr, "Failed to execute task type: %" PRIu32 "\n", task->t.type); assert(false); std::quick_exit(EXIT_FAILURE); } @@ -290,7 +285,7 @@ void gfx_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_re threads_callbacks.gfx_init_callback(); } - ultramodern::rsp::constants_init(); + ultramodern::rsp::init(); // Notify the caller thread that this thread is ready. thread_ready->signal(); diff --git a/ultramodern/src/rsp.cpp b/ultramodern/src/rsp.cpp index 65087b4..f056f03 100644 --- a/ultramodern/src/rsp.cpp +++ b/ultramodern/src/rsp.cpp @@ -3,55 +3,20 @@ #include "rsp_stuff.hpp" +static ultramodern::rsp::callbacks_t rsp_callbacks {}; -static ultramodern::rsp::callbacks_t rsp_callbacks; - -void ultramodern::rsp::set_callbacks(const ultramodern::rsp::callbacks_t& callbacks) { +void ultramodern::rsp::set_callbacks(const callbacks_t& callbacks) { rsp_callbacks = callbacks; } - -uint8_t dmem[0x1000]; -uint16_t rspReciprocals[512]; -uint16_t rspInverseSquareRoots[512]; - -// From Ares emulator. For license details, see rsp_vu.h -void ultramodern::rsp::constants_init() { - rspReciprocals[0] = u16(~0); - for (u16 index = 1; index < 512; index++) { - u64 a = index + 512; - u64 b = (u64(1) << 34) / a; - rspReciprocals[index] = u16((b + 1) >> 8); - } - - for (u16 index = 0; index < 512; index++) { - u64 a = (index + 512) >> ((index % 2 == 1) ? 1 : 0); - u64 b = 1 << 17; - //find the largest b where b < 1.0 / sqrt(a) - while (a * (b + 1) * (b + 1) < (u64(1) << 44)) b++; - rspInverseSquareRoots[index] = u16(b >> 1); +void ultramodern::rsp::init() { + if (rsp_callbacks.init != nullptr) { + rsp_callbacks.init(); } } -RspUcodeFunc* ultramodern::rsp::get_microcode(uint32_t task_type, OSTask* task) { - assert(rsp_callbacks.get_rsp_microcode != nullptr); +bool ultramodern::rsp::run_microcode(RDRAM_ARG const OSTask* task) { + assert(rsp_callbacks.run_microcode != nullptr); - return rsp_callbacks.get_rsp_microcode(task_type, task); + return rsp_callbacks.run_microcode(PASS_RDRAM task); } - -// Runs a recompiled RSP microcode -void ultramodern::rsp::run_microcode(uint8_t* rdram, const OSTask* task, RspUcodeFunc* ucode_func) { - // Load the OSTask into DMEM - memcpy(&dmem[0xFC0], task, sizeof(OSTask)); - - assert(rsp_callbacks.dma_rdram_to_dmem != nullptr); - - // Load the ucode data into DMEM - rsp_callbacks.dma_rdram_to_dmem(rdram, 0x0000, task->t.ucode_data, 0xF80 - 1); - - // Run the ucode - RspExitReason exit_reason = ucode_func(rdram); - // Ensure that the ucode exited correctly - assert(exit_reason == RspExitReason::Broke); -} - diff --git a/ultramodern/src/ultrainit.cpp b/ultramodern/src/ultrainit.cpp index 0674708..9dd19a2 100644 --- a/ultramodern/src/ultrainit.cpp +++ b/ultramodern/src/ultrainit.cpp @@ -2,17 +2,17 @@ #include "ultramodern.hpp" void ultramodern::set_callbacks( + const rsp::callbacks_t& rsp_callbacks, const audio_callbacks_t& audio_callbacks, const input_callbacks_t& input_callbacks, const gfx_callbacks_t& gfx_callbacks, - const rsp::callbacks_t& rsp_callbacks, const events::callbacks_t& thread_callbacks, const error_handling::callbacks_t& error_handling_callbacks ) { + ultramodern::rsp::set_callbacks(rsp_callbacks); ultramodern::set_audio_callbacks(audio_callbacks); (void)input_callbacks; // nothing yet (void)gfx_callbacks; // nothing yet - ultramodern::rsp::set_callbacks(rsp_callbacks); ultramodern::events::set_callbacks(thread_callbacks); ultramodern::error_handling::set_callbacks(error_handling_callbacks); }