mirror of
https://github.com/N64Recomp/N64ModernRuntime.git
synced 2026-05-10 19:01:53 +00:00
move RSP callbacks (and related RSP stuff) to its own file
This commit is contained in:
parent
57b83acb69
commit
0da09d45c1
7 changed files with 99 additions and 76 deletions
|
|
@ -14,12 +14,15 @@ add_library(ultramodern STATIC
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/events.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/events.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/mesgqueue.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/mesgqueue.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/misc_ultra.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/misc_ultra.cpp"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/rsp.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/rt64_layer.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/rt64_layer.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/scheduling.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/scheduling.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/task_win32.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/task_win32.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/threadqueue.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/threadqueue.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/threads.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/threads.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/timer.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/timer.cpp"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/ultrainit.cpp"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/user_callbacks.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(ultramodern PUBLIC
|
target_include_directories(ultramodern PUBLIC
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "ultra64.h"
|
||||||
|
|
||||||
// TODO: Move these to ultramodern namespace?
|
// TODO: Move these to ultramodern namespace?
|
||||||
|
|
||||||
enum class RspExitReason {
|
enum class RspExitReason {
|
||||||
|
|
@ -21,4 +23,37 @@ extern uint8_t dmem[];
|
||||||
extern uint16_t rspReciprocals[512];
|
extern uint16_t rspReciprocals[512];
|
||||||
extern uint16_t rspInverseSquareRoots[512];
|
extern uint16_t rspInverseSquareRoots[512];
|
||||||
|
|
||||||
|
namespace ultramodern {
|
||||||
|
namespace rsp {
|
||||||
|
struct rsp_callbacks_t {
|
||||||
|
/**
|
||||||
|
* Simulate a DMA copy from RDRAM (CPU) to DMEM (RSP).
|
||||||
|
*
|
||||||
|
* This function should fill the ultramodern's `dmem` by reading from the `rdram` parameter.
|
||||||
|
*
|
||||||
|
* IMPORTANTE: This callback is required and must be non-`nullptr` when initializing the user callbacks.
|
||||||
|
*/
|
||||||
|
void (*dma_rdram_to_dmem)(uint8_t* rdram, uint32_t dmem_addr, uint32_t dram_addr, uint32_t rd_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* IMPORTANTE: This callback is required and must be non-`nullptr` when initializing the user callbacks.
|
||||||
|
*/
|
||||||
|
RspUcodeFunc* (*get_rsp_microcode)(uint32_t task_type, OSTask* task);
|
||||||
|
};
|
||||||
|
|
||||||
|
void set_callbacks(const rsp_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);
|
||||||
|
};
|
||||||
|
} // namespace ultramodern
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,7 @@ struct gfx_callbacks_t {
|
||||||
create_window_t* create_window;
|
create_window_t* create_window;
|
||||||
update_gfx_t* update_gfx;
|
update_gfx_t* update_gfx;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool is_game_started();
|
bool is_game_started();
|
||||||
void quit();
|
void quit();
|
||||||
void join_event_threads();
|
void join_event_threads();
|
||||||
|
|
|
||||||
|
|
@ -23,28 +23,6 @@ namespace ultramodern {
|
||||||
* `msg` is non-`nullptr`.
|
* `msg` is non-`nullptr`.
|
||||||
*/
|
*/
|
||||||
void (*message_box)(const char* msg);
|
void (*message_box)(const char* msg);
|
||||||
|
|
||||||
// RSP
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simulate a DMA copy from RDRAM (CPU) to DMEM (RSP).
|
|
||||||
*
|
|
||||||
* This function should fill the ultramodern's `dmem` by reading from the `rdram` parameter.
|
|
||||||
*
|
|
||||||
* IMPORTANTE: This callback is required and must be non-`nullptr` when initializing the user callbacks.
|
|
||||||
*/
|
|
||||||
void (*dma_rdram_to_dmem)(uint8_t* rdram, uint32_t dmem_addr, uint32_t dram_addr, uint32_t rd_len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* IMPORTANTE: This callback is required and must be non-`nullptr` when initializing the user callbacks.
|
|
||||||
*/
|
|
||||||
RspUcodeFunc* (*get_rsp_microcode)(uint32_t task_type, OSTask* task);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -193,45 +193,6 @@ void dp_complete() {
|
||||||
osSendMesg(PASS_RDRAM events_context.dp.mq, events_context.dp.msg, OS_MESG_NOBLOCK);
|
osSendMesg(PASS_RDRAM events_context.dp.mq, events_context.dp.msg, OS_MESG_NOBLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t dmem[0x1000];
|
|
||||||
uint16_t rspReciprocals[512];
|
|
||||||
uint16_t rspInverseSquareRoots[512];
|
|
||||||
|
|
||||||
// From Ares emulator. For license details, see rsp_vu.h
|
|
||||||
void 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
|
|
||||||
void run_rsp_microcode(uint8_t* rdram, const OSTask* task, RspUcodeFunc* ucode_func) {
|
|
||||||
// Load the OSTask into DMEM
|
|
||||||
memcpy(&dmem[0xFC0], task, sizeof(OSTask));
|
|
||||||
|
|
||||||
auto& user_callbacks = ultramodern::get_user_callbacks();
|
|
||||||
assert(user_callbacks.dma_rdram_to_dmem != nullptr);
|
|
||||||
|
|
||||||
// Load the ucode data into DMEM
|
|
||||||
user_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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void task_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_ready) {
|
void task_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_ready) {
|
||||||
ultramodern::set_native_thread_name("SP Task Thread");
|
ultramodern::set_native_thread_name("SP Task Thread");
|
||||||
ultramodern::set_native_thread_priority(ultramodern::ThreadPriority::Normal);
|
ultramodern::set_native_thread_priority(ultramodern::ThreadPriority::Normal);
|
||||||
|
|
@ -251,11 +212,10 @@ void task_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_r
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ask the user what the correct ucode function is this.
|
// Ask the user what the correct ucode function is this.
|
||||||
assert(user_callbacks.get_rsp_microcode != nullptr);
|
RspUcodeFunc* ucode_func = ultramodern::rsp::get_microcode(task->t.type, task);
|
||||||
RspUcodeFunc* ucode_func = user_callbacks.get_rsp_microcode(task->t.type, task);
|
|
||||||
|
|
||||||
if (ucode_func != nullptr) {
|
if (ucode_func != nullptr) {
|
||||||
run_rsp_microcode(rdram, task, ucode_func);
|
ultramodern::rsp::run_microcode(rdram, task, ucode_func);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, "Unknown task type: %" PRIu32 "\n", task->t.type);
|
fprintf(stderr, "Unknown task type: %" PRIu32 "\n", task->t.type);
|
||||||
|
|
@ -330,7 +290,7 @@ void gfx_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_re
|
||||||
user_callbacks.update_supported_options();
|
user_callbacks.update_supported_options();
|
||||||
}
|
}
|
||||||
|
|
||||||
rsp_constants_init();
|
ultramodern::rsp::constants_init();
|
||||||
|
|
||||||
// Notify the caller thread that this thread is ready.
|
// Notify the caller thread that this thread is ready.
|
||||||
thread_ready->signal();
|
thread_ready->signal();
|
||||||
|
|
|
||||||
57
ultramodern/src/rsp.cpp
Normal file
57
ultramodern/src/rsp.cpp
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "rsp_stuff.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
static ultramodern::rsp::rsp_callbacks_t rsp_callbacks;
|
||||||
|
|
||||||
|
void ultramodern::rsp::set_callbacks(const ultramodern::rsp::rsp_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RspUcodeFunc* ultramodern::rsp::get_microcode(uint32_t task_type, OSTask* task) {
|
||||||
|
assert(rsp_callbacks.get_rsp_microcode != nullptr);
|
||||||
|
|
||||||
|
return rsp_callbacks.get_rsp_microcode(task_type, 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -10,17 +10,6 @@ static bool s_callbacks_initialized = false;
|
||||||
void ultramodern::register_user_callbacks(UserCallbacks& callbacks) {
|
void ultramodern::register_user_callbacks(UserCallbacks& callbacks) {
|
||||||
s_user_callbacks = callbacks;
|
s_user_callbacks = callbacks;
|
||||||
|
|
||||||
if (s_user_callbacks.dma_rdram_to_dmem == nullptr) {
|
|
||||||
fprintf(stderr, "%s: `dma_rdram_to_dmem` is a required callback, it can't be `nullptr`\n", __func__);
|
|
||||||
assert(false);
|
|
||||||
std::quick_exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
if (s_user_callbacks.get_rsp_microcode == nullptr) {
|
|
||||||
fprintf(stderr, "%s: `get_rsp_microcode` is a required callback, it can't be `nullptr`\n", __func__);
|
|
||||||
assert(false);
|
|
||||||
std::quick_exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
s_callbacks_initialized = true;
|
s_callbacks_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue