mirror of
https://github.com/Mr-Wiseguy/Zelda64Recomp.git
synced 2024-11-18 03:39:16 +01:00
Prototype quicksave functionality, disabled for now
This commit is contained in:
parent
a25f967094
commit
ecfe2381b0
@ -63,6 +63,8 @@ target_sources(PatchesLib PRIVATE
|
|||||||
${CMAKE_SOURCE_DIR}/RecompiledPatches/patches.c
|
${CMAKE_SOURCE_DIR}/RecompiledPatches/patches.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set_source_files_properties(${CMAKE_SOURCE_DIR}/RecompiledPatches/patches.c PROPERTIES COMPILE_FLAGS -fno-strict-aliasing)
|
||||||
|
|
||||||
# Build patches elf
|
# Build patches elf
|
||||||
add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/patches/patches.elf
|
add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/patches/patches.elf
|
||||||
COMMAND make
|
COMMAND make
|
||||||
@ -119,6 +121,7 @@ set (SOURCES
|
|||||||
|
|
||||||
${CMAKE_SOURCE_DIR}/src/game/input.cpp
|
${CMAKE_SOURCE_DIR}/src/game/input.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/game/controls.cpp
|
${CMAKE_SOURCE_DIR}/src/game/controls.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/src/game/quicksaving.cpp
|
||||||
|
|
||||||
${CMAKE_SOURCE_DIR}/src/ui/ui_renderer.cpp
|
${CMAKE_SOURCE_DIR}/src/ui/ui_renderer.cpp
|
||||||
${CMAKE_SOURCE_DIR}/src/ui/ui_launcher.cpp
|
${CMAKE_SOURCE_DIR}/src/ui/ui_launcher.cpp
|
||||||
|
@ -50,6 +50,10 @@ namespace recomp {
|
|||||||
void handle_events();
|
void handle_events();
|
||||||
|
|
||||||
bool game_input_disabled();
|
bool game_input_disabled();
|
||||||
|
|
||||||
|
// TODO move these
|
||||||
|
void quicksave_save();
|
||||||
|
void quicksave_load();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -48,6 +48,8 @@ DECLARE_FUNC(void, recomp_get_camera_inputs, float* x_out, float* y_out);
|
|||||||
// TODO move these
|
// TODO move these
|
||||||
DECLARE_FUNC(void, recomp_puts, const char* data, u32 size);
|
DECLARE_FUNC(void, recomp_puts, const char* data, u32 size);
|
||||||
DECLARE_FUNC(void, recomp_exit);
|
DECLARE_FUNC(void, recomp_exit);
|
||||||
|
DECLARE_FUNC(void, recomp_handle_quicksave_actions, OSMesgQueue* enter_mq, OSMesgQueue* exit_mq);
|
||||||
|
DECLARE_FUNC(void, recomp_handle_quicksave_actions_main, OSMesgQueue* enter_mq, OSMesgQueue* exit_mq);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
#ifndef __PATCHES_H__
|
#ifndef __PATCHES_H__
|
||||||
#define __PATCHES_H__
|
#define __PATCHES_H__
|
||||||
|
|
||||||
|
// TODO fix renaming symbols in patch recompilation
|
||||||
|
#define osRecvMesg osRecvMesg_recomp
|
||||||
|
#define osSendMesg osSendMesg_recomp
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "rt64_extended_gbi.h"
|
#include "rt64_extended_gbi.h"
|
||||||
|
|
||||||
|
232
patches/quicksave_patches.c
Normal file
232
patches/quicksave_patches.c
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
// Quicksaving is disabled for now
|
||||||
|
|
||||||
|
/* To reenable it, a few changes to the recompiled functions are also needed:
|
||||||
|
|
||||||
|
in Main:
|
||||||
|
L_80174E84:
|
||||||
|
// or $a0, $s3, $zero
|
||||||
|
ctx->r4 = ctx->r19 | 0;
|
||||||
|
// addiu $a1, $sp, 0x38
|
||||||
|
ctx->r5 = ADD32(ctx->r29, 0X38);
|
||||||
|
// jal 0x80087ED0
|
||||||
|
// addiu $a2, $zero, 0x1
|
||||||
|
ctx->r6 = ADD32(0, 0X1);
|
||||||
|
osRecvMesg_recomp(rdram, ctx);
|
||||||
|
+handle_quicksave_actions(rdram, ctx);
|
||||||
|
|
||||||
|
in Graph_ThreadEntry:
|
||||||
|
L_801749C8:
|
||||||
|
+handle_quicksave_actions_main(rdram, ctx);
|
||||||
|
+ctx->r4 = ctx->r17 | 0;
|
||||||
|
// jal 0x80174868
|
||||||
|
// or $a1, $s0, $zero
|
||||||
|
ctx->r5 = ctx->r16 | 0;
|
||||||
|
Graph_Update(rdram, ctx);
|
||||||
|
|
||||||
|
in PadMgr_ThreadEntry:
|
||||||
|
L_801760A0:
|
||||||
|
// or $a1, $s2, $zero
|
||||||
|
ctx->r5 = ctx->r18 | 0;
|
||||||
|
// jal 0x80087ED0
|
||||||
|
// or $a2, $s3, $zero
|
||||||
|
ctx->r6 = ctx->r19 | 0;
|
||||||
|
osRecvMesg_recomp(rdram, ctx);
|
||||||
|
+handle_quicksave_actions(rdram, ctx);
|
||||||
|
|
||||||
|
in AudioMgr_ThreadEntry:
|
||||||
|
L_80172F58:
|
||||||
|
+handle_quicksave_actions(rdram, ctx);
|
||||||
|
+ctx->r4 = ctx->r22 | 0;
|
||||||
|
// or $a1, $s2, $zero
|
||||||
|
ctx->r5 = ctx->r18 | 0;
|
||||||
|
// jal 0x80087ED0
|
||||||
|
// or $a2, $s3, $zero
|
||||||
|
ctx->r6 = ctx->r19 | 0;
|
||||||
|
osRecvMesg_recomp(rdram, ctx);
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
#include "patches.h"
|
||||||
|
#include "input.h"
|
||||||
|
#include "audiomgr.h"
|
||||||
|
|
||||||
|
// ultramodern's message queues can be statically initialized, so we don't actually need to call osCreateMesgQueue for these.
|
||||||
|
OSMesg quicksave_enter_mq_buffer[20];
|
||||||
|
OSMesgQueue quicksave_enter_mq = {
|
||||||
|
.msgCount = ARRAY_COUNT(quicksave_enter_mq_buffer),
|
||||||
|
.msg = quicksave_enter_mq_buffer,
|
||||||
|
.validCount = 0,
|
||||||
|
.first = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
OSMesg quicksave_exit_mq_buffer[20];
|
||||||
|
OSMesgQueue quicksave_exit_mq = {
|
||||||
|
.msgCount = ARRAY_COUNT(quicksave_exit_mq_buffer),
|
||||||
|
.msg = quicksave_exit_mq_buffer,
|
||||||
|
.validCount = 0,
|
||||||
|
.first = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
void handle_quicksave_actions() {
|
||||||
|
recomp_handle_quicksave_actions(&quicksave_enter_mq, &quicksave_exit_mq);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern OSMesgQueue sIrqMgrMsgQueue; // For Main thread
|
||||||
|
s16 main_irq_message = 0; // dummy value for sending a pointer to the main thread
|
||||||
|
|
||||||
|
#define RECOMP_IRQ_QUICKSAVE 0x2A2
|
||||||
|
|
||||||
|
void IrqMgr_ThreadEntry(IrqMgr* irqmgr) {
|
||||||
|
u32 interrupt;
|
||||||
|
u32 stop;
|
||||||
|
|
||||||
|
interrupt = 0;
|
||||||
|
stop = 0;
|
||||||
|
while (stop == 0) {
|
||||||
|
if (stop) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
osRecvMesg(&irqmgr->irqQueue, (OSMesg*)&interrupt, OS_MESG_BLOCK);
|
||||||
|
switch (interrupt) {
|
||||||
|
case 0x29A:
|
||||||
|
IrqMgr_HandleRetrace(irqmgr);
|
||||||
|
break;
|
||||||
|
case 0x29D:
|
||||||
|
IrqMgr_HandlePreNMI(irqmgr);
|
||||||
|
break;
|
||||||
|
case 0x29F:
|
||||||
|
IrqMgr_HandlePRENMI450(irqmgr);
|
||||||
|
break;
|
||||||
|
case 0x2A0:
|
||||||
|
IrqMgr_HandlePRENMI480(irqmgr);
|
||||||
|
break;
|
||||||
|
case 0x2A1:
|
||||||
|
IrqMgr_HandlePRENMI500(irqmgr);
|
||||||
|
break;
|
||||||
|
case RECOMP_IRQ_QUICKSAVE:
|
||||||
|
handle_quicksave_actions();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern IrqMgr gIrqMgr;
|
||||||
|
|
||||||
|
#define RSP_DONE_MSG 667
|
||||||
|
#define RDP_DONE_MSG 668
|
||||||
|
#define ENTRY_MSG 670
|
||||||
|
#define RDP_AUDIO_CANCEL_MSG 671
|
||||||
|
#define RSP_GFX_CANCEL_MSG 672
|
||||||
|
#define RECOMP_QUICKSAVE_ACTION 673 // @recomp
|
||||||
|
|
||||||
|
|
||||||
|
void Sched_ThreadEntry(void* arg) {
|
||||||
|
s32 msg = 0;
|
||||||
|
SchedContext* sched = (SchedContext*)arg;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
osRecvMesg(&sched->interruptQ, (OSMesg*)&msg, OS_MESG_BLOCK);
|
||||||
|
|
||||||
|
// Check if it's a message from another thread or the OS
|
||||||
|
switch (msg) {
|
||||||
|
case RDP_AUDIO_CANCEL_MSG:
|
||||||
|
Sched_HandleAudioCancel(sched);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case RSP_GFX_CANCEL_MSG:
|
||||||
|
Sched_HandleGfxCancel(sched);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case ENTRY_MSG:
|
||||||
|
Sched_HandleEntry(sched);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case RSP_DONE_MSG:
|
||||||
|
Sched_HandleRSPDone(sched);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case RDP_DONE_MSG:
|
||||||
|
Sched_HandleRDPDone(sched);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case RECOMP_QUICKSAVE_ACTION:
|
||||||
|
handle_quicksave_actions();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's a message from the IrqMgr
|
||||||
|
switch (((OSScMsg*)msg)->type) {
|
||||||
|
case OS_SC_RETRACE_MSG:
|
||||||
|
Sched_HandleRetrace(sched);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case OS_SC_PRE_NMI_MSG:
|
||||||
|
Sched_HandleReset(sched);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case OS_SC_NMI_MSG:
|
||||||
|
Sched_HandleStop(sched);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern PadMgr* sPadMgrInstance;
|
||||||
|
s16 padmgr_dummy_message = 0;
|
||||||
|
|
||||||
|
extern AudioMgr sAudioMgr;
|
||||||
|
s16 audiomgr_dummy_message = 0;
|
||||||
|
|
||||||
|
extern OSMesgQueue sDmaMgrMsgQueue;
|
||||||
|
#define RECOMP_DMAMGR_QUICKSAVE_MESSAGE 1
|
||||||
|
|
||||||
|
void DmaMgr_ThreadEntry(void* a0) {
|
||||||
|
OSMesg msg;
|
||||||
|
DmaRequest* req;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
osRecvMesg(&sDmaMgrMsgQueue, &msg, OS_MESG_BLOCK);
|
||||||
|
|
||||||
|
if (msg == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg == (OSMesg)RECOMP_DMAMGR_QUICKSAVE_MESSAGE) {
|
||||||
|
handle_quicksave_actions();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
req = (DmaRequest*)msg;
|
||||||
|
|
||||||
|
DmaMgr_ProcessMsg(req);
|
||||||
|
if (req->notifyQueue) {
|
||||||
|
osSendMesg(req->notifyQueue, req->notifyMsg, OS_MESG_NOBLOCK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern SchedContext gSchedContext;
|
||||||
|
|
||||||
|
void handle_quicksave_actions_main() {
|
||||||
|
recomp_handle_quicksave_actions_main(&quicksave_enter_mq, &quicksave_exit_mq);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wake_threads_for_quicksave_action() {
|
||||||
|
// Wake up the Main thread
|
||||||
|
osSendMesg(&sIrqMgrMsgQueue, &main_irq_message, OS_MESG_BLOCK);
|
||||||
|
// Wake up the IrqMgr thread
|
||||||
|
osSendMesg(&gIrqMgr.irqQueue, (OSMesg)RECOMP_IRQ_QUICKSAVE, OS_MESG_BLOCK);
|
||||||
|
// Wake up the PadMgr thread
|
||||||
|
osSendMesg(&sPadMgrInstance->interruptQueue, &padmgr_dummy_message, OS_MESG_BLOCK);
|
||||||
|
// Wake up the AudioMgr thread
|
||||||
|
osSendMesg(&sAudioMgr.interruptQueue, &audiomgr_dummy_message, OS_MESG_BLOCK);
|
||||||
|
// Wake up the DmaMgr thread
|
||||||
|
osSendMesg(&sDmaMgrMsgQueue, (OSMesg)RECOMP_DMAMGR_QUICKSAVE_MESSAGE, OS_MESG_BLOCK);
|
||||||
|
// Wake up the Sched thread
|
||||||
|
osSendMesg(&gSchedContext.interruptQ, (OSMesg)RECOMP_QUICKSAVE_ACTION, OS_MESG_BLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -5,3 +5,7 @@ recomp_get_item_inputs = 0x81000000;
|
|||||||
recomp_puts = 0x81000004;
|
recomp_puts = 0x81000004;
|
||||||
recomp_get_camera_inputs = 0x81000008;
|
recomp_get_camera_inputs = 0x81000008;
|
||||||
recomp_exit = 0x8100000C;
|
recomp_exit = 0x8100000C;
|
||||||
|
recomp_handle_quicksave_actions = 0x81000010;
|
||||||
|
recomp_handle_quicksave_actions_main = 0x81000014;
|
||||||
|
osRecvMesg_recomp = 0x81000018;
|
||||||
|
osSendMesg_recomp = 0x8100001C;
|
||||||
|
@ -210,6 +210,24 @@ void recomp::poll_inputs() {
|
|||||||
InputState.cur_controllers.push_back(controller);
|
InputState.cur_controllers.push_back(controller);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Quicksaving is disabled for now and will likely have more limited functionality
|
||||||
|
// when restored, rather than allowing saving and loading at any point in time.
|
||||||
|
#if 0
|
||||||
|
if (InputState.keys) {
|
||||||
|
static bool save_was_held = false;
|
||||||
|
static bool load_was_held = false;
|
||||||
|
bool save_is_held = InputState.keys[SDL_SCANCODE_F5] != 0;
|
||||||
|
bool load_is_held = InputState.keys[SDL_SCANCODE_F7] != 0;
|
||||||
|
if (save_is_held && !save_was_held) {
|
||||||
|
recomp::quicksave_save();
|
||||||
|
}
|
||||||
|
else if (load_is_held && !load_was_held) {
|
||||||
|
recomp::quicksave_load();
|
||||||
|
}
|
||||||
|
save_was_held = save_is_held;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool controller_button_state(int32_t input_id) {
|
bool controller_button_state(int32_t input_id) {
|
||||||
|
121
src/game/quicksaving.cpp
Normal file
121
src/game/quicksaving.cpp
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
// Quicksaving is disabled for now
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
#include "recomp_helpers.h"
|
||||||
|
#include "recomp_input.h"
|
||||||
|
#include "../ultramodern/ultramodern.hpp"
|
||||||
|
|
||||||
|
enum class QuicksaveAction {
|
||||||
|
None,
|
||||||
|
Save,
|
||||||
|
Load
|
||||||
|
};
|
||||||
|
|
||||||
|
std::atomic<QuicksaveAction> cur_quicksave_action = QuicksaveAction::None;
|
||||||
|
|
||||||
|
void recomp::quicksave_save() {
|
||||||
|
cur_quicksave_action.store(QuicksaveAction::Save);
|
||||||
|
}
|
||||||
|
|
||||||
|
void recomp::quicksave_load() {
|
||||||
|
cur_quicksave_action.store(QuicksaveAction::Load);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t saved_rdram[ultramodern::rdram_size];
|
||||||
|
|
||||||
|
thread_local recomp_context saved_context;
|
||||||
|
|
||||||
|
void save_context(recomp_context* ctx) {
|
||||||
|
saved_context = *ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_context(recomp_context* ctx) {
|
||||||
|
*ctx = saved_context;
|
||||||
|
|
||||||
|
// Restore the pointer to the odd floats for correctly handling mips3 float mode.
|
||||||
|
if (ctx->mips3_float_mode) {
|
||||||
|
// FR = 1, odd single floats point to their own registers
|
||||||
|
ctx->f_odd = &ctx->f1.u32l;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// FR = 0, odd single floats point to the upper half of the previous register
|
||||||
|
ctx->f_odd = &ctx->f0.u32h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void recomp_handle_quicksave_actions(uint8_t* rdram, recomp_context* ctx) {
|
||||||
|
QuicksaveAction action = cur_quicksave_action.load();
|
||||||
|
|
||||||
|
if (action != QuicksaveAction::None) {
|
||||||
|
PTR(OSMesgQueue) quicksave_enter_mq = _arg<0, PTR(OSMesgQueue)>(rdram, ctx);
|
||||||
|
PTR(OSMesgQueue) quicksave_exit_mq = _arg<1, PTR(OSMesgQueue)>(rdram, ctx);
|
||||||
|
|
||||||
|
printf("saving context for thread %d\n", TO_PTR(OSThread, ultramodern::this_thread())->id);
|
||||||
|
|
||||||
|
// Save or load the thread's context as needed based on the action.
|
||||||
|
if (action == QuicksaveAction::Save) {
|
||||||
|
save_context(ctx);
|
||||||
|
}
|
||||||
|
else if (action == QuicksaveAction::Load) {
|
||||||
|
load_context(ctx);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tell the main thread that one of the other permanent threads is ready for performing a quicksave action.
|
||||||
|
osSendMesg(rdram, quicksave_enter_mq, NULLPTR, OS_MESG_NOBLOCK);
|
||||||
|
// Wait for the main thread to signal that other permanent threads are safe to continue.
|
||||||
|
osRecvMesg(rdram, quicksave_exit_mq, NULLPTR, OS_MESG_BLOCK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void wake_threads_for_quicksave_action(uint8_t* rdram, recomp_context* ctx);
|
||||||
|
|
||||||
|
extern "C" void recomp_handle_quicksave_actions_main(uint8_t* rdram, recomp_context* ctx) {
|
||||||
|
QuicksaveAction action = cur_quicksave_action.load();
|
||||||
|
|
||||||
|
if (action != QuicksaveAction::None) {
|
||||||
|
PTR(OSMesgQueue) quicksave_enter_mq = _arg<0, PTR(OSMesgQueue)>(rdram, ctx);
|
||||||
|
PTR(OSMesgQueue) quicksave_exit_mq = _arg<1, PTR(OSMesgQueue)>(rdram, ctx);
|
||||||
|
|
||||||
|
wake_threads_for_quicksave_action(rdram, ctx);
|
||||||
|
|
||||||
|
// Wait for all other permanent threads (hence the minus 1) to signal that they're ready for a quicksave action.
|
||||||
|
for (uint32_t i = 0; i < ultramodern::permanent_thread_count() - 1; i++) {
|
||||||
|
osRecvMesg(rdram, quicksave_enter_mq, NULLPTR, OS_MESG_BLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow any temporary threads to complete by lowering this thread's priority to 0.
|
||||||
|
// TODO this won't cause all temporary threads to complete if any are blocked by permanent threads
|
||||||
|
// or events like timers. Situations like that will need to be handed on a case-by-case basis for a given game.
|
||||||
|
if (ultramodern::temporary_thread_count() != 0) {
|
||||||
|
OSPri old_pri = osGetThreadPri(rdram, NULLPTR);
|
||||||
|
osSetThreadPri(rdram, NULLPTR, 0);
|
||||||
|
|
||||||
|
osSetThreadPri(rdram, NULLPTR, old_pri);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == QuicksaveAction::Save) {
|
||||||
|
std::copy(rdram, rdram + ultramodern::rdram_size, saved_rdram);
|
||||||
|
}
|
||||||
|
else if (action == QuicksaveAction::Load) {
|
||||||
|
std::copy(saved_rdram, saved_rdram + ultramodern::rdram_size, rdram);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Quicksave action complete\n");
|
||||||
|
|
||||||
|
cur_quicksave_action.store(QuicksaveAction::None);
|
||||||
|
|
||||||
|
// Tell all other permanent threads that they're good to continue.
|
||||||
|
for (uint32_t i = 0; i < ultramodern::permanent_thread_count() - 1; i++) {
|
||||||
|
osSendMesg(rdram, quicksave_exit_mq, NULLPTR, OS_MESG_BLOCK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -175,9 +175,9 @@ EXPORT extern "C" void init() {
|
|||||||
// Load overlays in the first 1MB
|
// Load overlays in the first 1MB
|
||||||
load_overlays(0x1000, (int32_t)entrypoint, 1024 * 1024);
|
load_overlays(0x1000, (int32_t)entrypoint, 1024 * 1024);
|
||||||
|
|
||||||
// Allocate rdram_buffer (16MB to give room for any extra addressable data used by recomp)
|
// Allocate rdram_buffer
|
||||||
rdram_buffer = std::make_unique<uint8_t[]>(16 * 1024 * 1024);
|
rdram_buffer = std::make_unique<uint8_t[]>(ultramodern::rdram_size);
|
||||||
std::memset(rdram_buffer.get(), 0, 8 * 1024 * 1024);
|
std::memset(rdram_buffer.get(), 0, ultramodern::rdram_size);
|
||||||
|
|
||||||
// Initial 1MB DMA (rom address 0x1000 = physical address 0x10001000)
|
// Initial 1MB DMA (rom address 0x1000 = physical address 0x10001000)
|
||||||
do_rom_read(rdram_buffer.get(), entrypoint, 0x10001000, 0x100000);
|
do_rom_read(rdram_buffer.get(), entrypoint, 0x10001000, 0x100000);
|
||||||
|
@ -150,6 +150,9 @@ void scheduler_func() {
|
|||||||
thread_queue_t running_thread_queue{};
|
thread_queue_t running_thread_queue{};
|
||||||
OSThread* cur_running_thread = nullptr;
|
OSThread* cur_running_thread = nullptr;
|
||||||
|
|
||||||
|
ultramodern::set_native_thread_name("Scheduler Thread");
|
||||||
|
ultramodern::set_native_thread_priority(ultramodern::ThreadPriority::Critical);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
OSThread* old_running_thread = cur_running_thread;
|
OSThread* old_running_thread = cur_running_thread;
|
||||||
scheduler_context.action_count.wait(0);
|
scheduler_context.action_count.wait(0);
|
||||||
|
@ -114,6 +114,9 @@ void ultramodern::set_native_thread_priority(ThreadPriority pri) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
std::atomic_int temporary_threads = 0;
|
||||||
|
std::atomic_int permanent_threads = 0;
|
||||||
|
|
||||||
static void _thread_func(RDRAM_ARG PTR(OSThread) self_, PTR(thread_func_t) entrypoint, PTR(void) arg) {
|
static void _thread_func(RDRAM_ARG PTR(OSThread) self_, PTR(thread_func_t) entrypoint, PTR(void) arg) {
|
||||||
OSThread *self = TO_PTR(OSThread, self_);
|
OSThread *self = TO_PTR(OSThread, self_);
|
||||||
debug_printf("[Thread] Thread created: %d\n", self->id);
|
debug_printf("[Thread] Thread created: %d\n", self->id);
|
||||||
@ -124,6 +127,14 @@ static void _thread_func(RDRAM_ARG PTR(OSThread) self_, PTR(thread_func_t) entry
|
|||||||
ultramodern::set_native_thread_name("Game Thread " + std::to_string(self->id));
|
ultramodern::set_native_thread_name("Game Thread " + std::to_string(self->id));
|
||||||
ultramodern::set_native_thread_priority(ultramodern::ThreadPriority::High);
|
ultramodern::set_native_thread_priority(ultramodern::ThreadPriority::High);
|
||||||
|
|
||||||
|
// TODO fix these being hardcoded (this is only used for quicksaving)
|
||||||
|
if ((self->id == 2 && self->priority == 5) || self->id == 13) { // slowly, flashrom
|
||||||
|
temporary_threads.fetch_add(1);
|
||||||
|
}
|
||||||
|
else if (self->id != 1 && self->id != 2) { // ignore idle and fault
|
||||||
|
permanent_threads.fetch_add(1);
|
||||||
|
}
|
||||||
|
|
||||||
// Set initialized to false to indicate that this thread can be started.
|
// Set initialized to false to indicate that this thread can be started.
|
||||||
self->context->initialized.store(true);
|
self->context->initialized.store(true);
|
||||||
self->context->initialized.notify_all();
|
self->context->initialized.notify_all();
|
||||||
@ -145,6 +156,19 @@ static void _thread_func(RDRAM_ARG PTR(OSThread) self_, PTR(thread_func_t) entry
|
|||||||
|
|
||||||
// Dispose of this thread after it completes.
|
// Dispose of this thread after it completes.
|
||||||
ultramodern::cleanup_thread(self);
|
ultramodern::cleanup_thread(self);
|
||||||
|
|
||||||
|
// TODO fix these being hardcoded (this is only used for quicksaving)
|
||||||
|
if ((self->id == 2 && self->priority == 5) || self->id == 13) { // slowly, flashrom
|
||||||
|
temporary_threads.fetch_sub(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ultramodern::permanent_thread_count() {
|
||||||
|
return permanent_threads.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ultramodern::temporary_thread_count() {
|
||||||
|
return temporary_threads.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void osStartThread(RDRAM_ARG PTR(OSThread) t_) {
|
extern "C" void osStartThread(RDRAM_ARG PTR(OSThread) t_) {
|
||||||
|
@ -46,6 +46,7 @@ namespace ultramodern {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// We need a place in rdram to hold the PI handles, so pick an address in extended rdram
|
// We need a place in rdram to hold the PI handles, so pick an address in extended rdram
|
||||||
|
constexpr uint32_t rdram_size = 1024 * 1024 * 16; // 16MB to give extra room for anything custom
|
||||||
constexpr int32_t cart_handle = 0x80800000;
|
constexpr int32_t cart_handle = 0x80800000;
|
||||||
constexpr int32_t flash_handle = (int32_t)(cart_handle + sizeof(OSPiHandle));
|
constexpr int32_t flash_handle = (int32_t)(cart_handle + sizeof(OSPiHandle));
|
||||||
constexpr uint32_t save_size = 1024 * 1024 / 8; // Maximum save size, 1Mbit for flash
|
constexpr uint32_t save_size = 1024 * 1024 / 8; // Maximum save size, 1Mbit for flash
|
||||||
@ -68,6 +69,8 @@ void pause_self(RDRAM_ARG1);
|
|||||||
void halt_self(RDRAM_ARG1);
|
void halt_self(RDRAM_ARG1);
|
||||||
void stop_thread(OSThread *t);
|
void stop_thread(OSThread *t);
|
||||||
void cleanup_thread(OSThread *t);
|
void cleanup_thread(OSThread *t);
|
||||||
|
uint32_t permanent_thread_count();
|
||||||
|
uint32_t temporary_thread_count();
|
||||||
|
|
||||||
enum class ThreadPriority {
|
enum class ThreadPriority {
|
||||||
Low,
|
Low,
|
||||||
|
Loading…
Reference in New Issue
Block a user