mirror of
https://github.com/N64Recomp/N64ModernRuntime.git
synced 2026-05-11 11:22:05 +00:00
Move most RSP stuff to librecomp
This commit is contained in:
parent
06a8c5070a
commit
63d0c7f85a
9 changed files with 131 additions and 94 deletions
|
|
@ -5,6 +5,7 @@
|
|||
#include <filesystem>
|
||||
|
||||
#include "recomp.h"
|
||||
#include "rsp.h"
|
||||
#include <ultramodern/ultramodern.hpp>
|
||||
|
||||
namespace recomp {
|
||||
|
|
@ -38,7 +39,7 @@ namespace recomp {
|
|||
void set_rom_contents(std::vector<uint8_t>&& 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();
|
||||
|
|
|
|||
|
|
@ -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<int8_t*>(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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
61
librecomp/src/rsp.cpp
Normal file
61
librecomp/src/rsp.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cinttypes>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue