mirror of
https://github.com/N64Recomp/N64ModernRuntime.git
synced 2026-05-10 19:01:53 +00:00
Implement RSP callbacks
This commit is contained in:
parent
0df06daf44
commit
57b83acb69
5 changed files with 101 additions and 34 deletions
|
|
@ -1,21 +1,11 @@
|
||||||
#ifndef __RSP_H__
|
#ifndef __RSP_H__
|
||||||
#define __RSP_H__
|
#define __RSP_H__
|
||||||
|
|
||||||
#include "rsp_vu.h"
|
|
||||||
#include "recomp.h"
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
enum class RspExitReason {
|
#include "rsp_vu.h"
|
||||||
Invalid,
|
#include "recomp.h"
|
||||||
Broke,
|
#include "ultramodern/rsp_stuff.hpp"
|
||||||
ImemOverrun,
|
|
||||||
UnhandledJumpTarget,
|
|
||||||
Unsupported
|
|
||||||
};
|
|
||||||
|
|
||||||
extern uint8_t dmem[];
|
|
||||||
extern uint16_t rspReciprocals[512];
|
|
||||||
extern uint16_t rspInverseSquareRoots[512];
|
|
||||||
|
|
||||||
#define RSP_MEM_B(offset, addr) \
|
#define RSP_MEM_B(offset, addr) \
|
||||||
(*reinterpret_cast<int8_t*>(dmem + (0xFFF & (((offset) + (addr)) ^ 3))))
|
(*reinterpret_cast<int8_t*>(dmem + (0xFFF & (((offset) + (addr)) ^ 3))))
|
||||||
|
|
@ -61,7 +51,7 @@ static inline void RSP_MEM_H_STORE(uint32_t offset, uint32_t addr, uint32_t val)
|
||||||
|
|
||||||
#define RSP_ADD32(a, b) \
|
#define RSP_ADD32(a, b) \
|
||||||
((int32_t)((a) + (b)))
|
((int32_t)((a) + (b)))
|
||||||
|
|
||||||
#define RSP_SUB32(a, b) \
|
#define RSP_SUB32(a, b) \
|
||||||
((int32_t)((a) - (b)))
|
((int32_t)((a) - (b)))
|
||||||
|
|
||||||
|
|
|
||||||
24
ultramodern/include/ultramodern/rsp_stuff.hpp
Normal file
24
ultramodern/include/ultramodern/rsp_stuff.hpp
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef __RSP_STUFF_HPP__
|
||||||
|
#define __RSP_STUFF_HPP__
|
||||||
|
|
||||||
|
// TODO: rename
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
// 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];
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
#ifndef __USER_CALLBACKS_HPP__
|
#ifndef __USER_CALLBACKS_HPP__
|
||||||
#define __USER_CALLBACKS_HPP__
|
#define __USER_CALLBACKS_HPP__
|
||||||
|
|
||||||
|
#include "rsp_stuff.hpp"
|
||||||
|
#include "ultra64.h"
|
||||||
|
|
||||||
namespace ultramodern {
|
namespace ultramodern {
|
||||||
struct UserCallbacks {
|
struct UserCallbacks {
|
||||||
// TODO: Do we want those functions to take a generic `void *arg` for user data?
|
// TODO: Do we want those functions to take a generic `void *arg` for user data?
|
||||||
|
|
@ -17,12 +20,41 @@ namespace ultramodern {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show an OS dialog with the given `msg`.
|
* Show an OS dialog with the given `msg`.
|
||||||
* `msg` is non-NULL.
|
* `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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
void register_user_callbacks(UserCallbacks& callbacks);
|
void register_user_callbacks(UserCallbacks& callbacks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const UserCallbacks& get_user_callbacks();
|
const UserCallbacks& get_user_callbacks();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
#include "rt64_layer.h"
|
#include "rt64_layer.h"
|
||||||
#include "user_callbacks.hpp"
|
#include "user_callbacks.hpp"
|
||||||
|
#include "rsp_stuff.hpp"
|
||||||
|
|
||||||
struct SpTaskAction {
|
struct SpTaskAction {
|
||||||
OSTask task;
|
OSTask task;
|
||||||
|
|
@ -196,12 +197,6 @@ uint8_t dmem[0x1000];
|
||||||
uint16_t rspReciprocals[512];
|
uint16_t rspReciprocals[512];
|
||||||
uint16_t rspInverseSquareRoots[512];
|
uint16_t rspInverseSquareRoots[512];
|
||||||
|
|
||||||
#if 0
|
|
||||||
using RspUcodeFunc = RspExitReason(uint8_t* rdram);
|
|
||||||
extern RspUcodeFunc njpgdspMain;
|
|
||||||
extern RspUcodeFunc aspMain;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// From Ares emulator. For license details, see rsp_vu.h
|
// From Ares emulator. For license details, see rsp_vu.h
|
||||||
void rsp_constants_init() {
|
void rsp_constants_init() {
|
||||||
rspReciprocals[0] = u16(~0);
|
rspReciprocals[0] = u16(~0);
|
||||||
|
|
@ -219,19 +214,23 @@ void rsp_constants_init() {
|
||||||
rspInverseSquareRoots[index] = u16(b >> 1);
|
rspInverseSquareRoots[index] = u16(b >> 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if 0
|
|
||||||
// Runs a recompiled RSP microcode
|
// Runs a recompiled RSP microcode
|
||||||
void run_rsp_microcode(uint8_t* rdram, const OSTask* task, RspUcodeFunc* ucode_func) {
|
void run_rsp_microcode(uint8_t* rdram, const OSTask* task, RspUcodeFunc* ucode_func) {
|
||||||
// Load the OSTask into DMEM
|
// Load the OSTask into DMEM
|
||||||
memcpy(&dmem[0xFC0], task, sizeof(OSTask));
|
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
|
// Load the ucode data into DMEM
|
||||||
dma_rdram_to_dmem(rdram, 0x0000, task->t.ucode_data, 0xF80 - 1);
|
user_callbacks.dma_rdram_to_dmem(rdram, 0x0000, task->t.ucode_data, 0xF80 - 1);
|
||||||
|
|
||||||
// Run the ucode
|
// Run the ucode
|
||||||
RspExitReason exit_reason = ucode_func(rdram);
|
RspExitReason exit_reason = ucode_func(rdram);
|
||||||
// Ensure that the ucode exited correctly
|
// Ensure that the ucode exited correctly
|
||||||
assert(exit_reason == RspExitReason::Broke);
|
assert(exit_reason == RspExitReason::Broke);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
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");
|
||||||
|
|
@ -240,6 +239,8 @@ void task_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_r
|
||||||
// Notify the caller thread that this thread is ready.
|
// Notify the caller thread that this thread is ready.
|
||||||
thread_ready->signal();
|
thread_ready->signal();
|
||||||
|
|
||||||
|
auto& user_callbacks = ultramodern::get_user_callbacks();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// Wait until an RSP task has been sent
|
// Wait until an RSP task has been sent
|
||||||
OSTask* task;
|
OSTask* task;
|
||||||
|
|
@ -249,16 +250,12 @@ void task_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_r
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the correct function based on the task type
|
// Ask the user what the correct ucode function is this.
|
||||||
if (task->t.type == M_AUDTASK) {
|
assert(user_callbacks.get_rsp_microcode != nullptr);
|
||||||
#if 0
|
RspUcodeFunc* ucode_func = user_callbacks.get_rsp_microcode(task->t.type, task);
|
||||||
run_rsp_microcode(rdram, task, aspMain);
|
|
||||||
#endif
|
if (ucode_func != nullptr) {
|
||||||
}
|
run_rsp_microcode(rdram, task, ucode_func);
|
||||||
else if (task->t.type == M_NJPEGTASK) {
|
|
||||||
#if 0
|
|
||||||
run_rsp_microcode(rdram, task, njpgdspMain);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, "Unknown task type: %" PRIu32 "\n", task->t.type);
|
fprintf(stderr, "Unknown task type: %" PRIu32 "\n", task->t.type);
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,35 @@
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
#include "ultramodern/user_callbacks.hpp"
|
#include "ultramodern/user_callbacks.hpp"
|
||||||
|
|
||||||
static ultramodern::UserCallbacks s_user_callbacks {};
|
static ultramodern::UserCallbacks s_user_callbacks {};
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ultramodern::UserCallbacks& ultramodern::get_user_callbacks() {
|
const ultramodern::UserCallbacks& ultramodern::get_user_callbacks() {
|
||||||
|
if (!s_callbacks_initialized) {
|
||||||
|
fprintf(stderr, "%s: User callbacks have not been initialized.\n", __func__);
|
||||||
|
assert(false);
|
||||||
|
std::quick_exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
return s_user_callbacks;
|
return s_user_callbacks;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue