Fixed some libultra thread implementation issues, fixed flash implementation not getting detected by the game

This commit is contained in:
Mr-Wiseguy 2023-02-21 01:26:05 -05:00
parent ba37150ed1
commit d994bd381d
8 changed files with 17001 additions and 13 deletions

View File

@ -167,7 +167,12 @@ XCOPY "$(ProjectDir)lib\SDL2-2.24.0\lib\$(Platform)\SDL2.dll" "$(TargetDir)" /S
</PostBuildEvent> </PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="portultra\audio.cpp" /> <ClCompile Include="portultra\audio.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">MaxSpeed</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Default</BasicRuntimeChecks>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Default</BasicRuntimeChecks>
</ClCompile>
<ClCompile Include="portultra\events.cpp" /> <ClCompile Include="portultra\events.cpp" />
<ClCompile Include="portultra\mesgqueue.cpp" /> <ClCompile Include="portultra\mesgqueue.cpp" />
<ClCompile Include="portultra\misc_ultra.cpp" /> <ClCompile Include="portultra\misc_ultra.cpp" />

View File

@ -97,6 +97,7 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>NotUsing</PrecompiledHeader>
<EnableParallelCodeGeneration>true</EnableParallelCodeGeneration> <EnableParallelCodeGeneration>true</EnableParallelCodeGeneration>
<MultiProcessorCompilation>true</MultiProcessorCompilation> <MultiProcessorCompilation>true</MultiProcessorCompilation>
<ExceptionHandling>SyncCThrow</ExceptionHandling>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem> <SubSystem>
@ -118,6 +119,7 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation> <MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>false</WholeProgramOptimization> <WholeProgramOptimization>false</WholeProgramOptimization>
<PrecompiledHeaderFile /> <PrecompiledHeaderFile />
<ExceptionHandling>SyncCThrow</ExceptionHandling>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem> <SubSystem>
@ -136,6 +138,7 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>NotUsing</PrecompiledHeader>
<EnableParallelCodeGeneration>true</EnableParallelCodeGeneration> <EnableParallelCodeGeneration>true</EnableParallelCodeGeneration>
<MultiProcessorCompilation>true</MultiProcessorCompilation> <MultiProcessorCompilation>true</MultiProcessorCompilation>
<ExceptionHandling>SyncCThrow</ExceptionHandling>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem> <SubSystem>
@ -157,6 +160,7 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation> <MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>false</WholeProgramOptimization> <WholeProgramOptimization>false</WholeProgramOptimization>
<PrecompiledHeaderFile /> <PrecompiledHeaderFile />
<ExceptionHandling>SyncCThrow</ExceptionHandling>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem> <SubSystem>

File diff suppressed because it is too large Load Diff

View File

@ -73,7 +73,7 @@ void handle_thread_stopping(thread_queue_t& running_thread_queue) {
} }
} }
void handle_thread_cleanup(thread_queue_t& running_thread_queue) { void handle_thread_cleanup(thread_queue_t& running_thread_queue, OSThread*& cur_running_thread) {
std::lock_guard lock{scheduler_context.mutex}; std::lock_guard lock{scheduler_context.mutex};
while (!scheduler_context.to_cleanup.empty()) { while (!scheduler_context.to_cleanup.empty()) {
@ -83,8 +83,20 @@ void handle_thread_cleanup(thread_queue_t& running_thread_queue) {
debug_printf("[Scheduler] Destroying thread %d\n", to_cleanup->id); debug_printf("[Scheduler] Destroying thread %d\n", to_cleanup->id);
running_thread_queue.remove(to_cleanup); running_thread_queue.remove(to_cleanup);
// If the cleaned up thread was the running thread, schedule a new one to run.
if (to_cleanup == cur_running_thread) {
// If there's a thread queued to run, set it as the new running thread.
if (!running_thread_queue.empty()) {
cur_running_thread = running_thread_queue.top();
}
// Otherwise, set the running thread to null so the next thread that can be run gets started.
else {
cur_running_thread = nullptr;
}
}
to_cleanup->context->host_thread.join(); to_cleanup->context->host_thread.join();
delete to_cleanup->context; delete to_cleanup->context;
to_cleanup->context = nullptr;
} }
} }
@ -153,7 +165,7 @@ void scheduler_func() {
handle_thread_stopping(running_thread_queue); handle_thread_stopping(running_thread_queue);
// Handle cleaning up threads // Handle cleaning up threads
handle_thread_cleanup(running_thread_queue); handle_thread_cleanup(running_thread_queue, cur_running_thread);
// Handle queueing threads to run // Handle queueing threads to run
handle_thread_queueing(running_thread_queue); handle_thread_queueing(running_thread_queue);

View File

@ -41,6 +41,8 @@ void run_thread_function(uint8_t* rdram, uint64_t addr, uint64_t sp, uint64_t ar
#define run_thread_function(func, sp, arg) func(arg) #define run_thread_function(func, sp, arg) func(arg)
#endif #endif
struct thread_terminated : std::exception {};
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);
@ -72,8 +74,12 @@ static void _thread_func(RDRAM_ARG PTR(OSThread) self_, PTR(thread_func_t) entry
debug_printf("[Thread] Thread started: %d\n", self->id); debug_printf("[Thread] Thread started: %d\n", self->id);
try {
// Run the thread's function with the provided argument. // Run the thread's function with the provided argument.
run_thread_function(PASS_RDRAM entrypoint, self->sp, arg); run_thread_function(PASS_RDRAM entrypoint, self->sp, arg);
} catch (thread_terminated& terminated) {
}
// Dispose of this thread after it completes. // Dispose of this thread after it completes.
Multilibultra::cleanup_thread(self); Multilibultra::cleanup_thread(self);
@ -110,6 +116,7 @@ extern "C" void osCreateThread(RDRAM_ARG PTR(OSThread) t_, OSId id, PTR(thread_f
t->id = id; t->id = id;
t->state = OSThreadState::PAUSED; t->state = OSThreadState::PAUSED;
t->sp = sp - 0x10; // Set up the first stack frame t->sp = sp - 0x10; // Set up the first stack frame
t->destroyed = false;
// Spawn a new thread, which will immediately pause itself and wait until it's been started. // Spawn a new thread, which will immediately pause itself and wait until it's been started.
t->context = new UltraThreadContext{}; t->context = new UltraThreadContext{};
@ -124,7 +131,16 @@ extern "C" void osStopThread(RDRAM_ARG PTR(OSThread) t_) {
} }
extern "C" void osDestroyThread(RDRAM_ARG PTR(OSThread) t_) { extern "C" void osDestroyThread(RDRAM_ARG PTR(OSThread) t_) {
assert(false); // Check if the thread is destroying itself (arg is null or thread_self)
if (t_ == NULLPTR || t_ == thread_self) {
throw thread_terminated{};
}
// Otherwise, mark the target thread as destroyed. Next time it reaches a stopping point,
// it'll check this and terminate itself instead of pausing.
else {
OSThread* t = TO_PTR(OSThread, t_);
t->destroyed = true;
}
} }
extern "C" void osSetThreadPri(RDRAM_ARG PTR(OSThread) t, OSPri pri) { extern "C" void osSetThreadPri(RDRAM_ARG PTR(OSThread) t, OSPri pri) {
@ -168,8 +184,16 @@ void Multilibultra::set_self_paused(RDRAM_ARG1) {
TO_PTR(OSThread, thread_self)->context->running.notify_all(); TO_PTR(OSThread, thread_self)->context->running.notify_all();
} }
void check_destroyed(OSThread* t) {
if (t->destroyed) {
throw thread_terminated{};
}
}
void Multilibultra::wait_for_resumed(RDRAM_ARG1) { void Multilibultra::wait_for_resumed(RDRAM_ARG1) {
check_destroyed(TO_PTR(OSThread, thread_self));
TO_PTR(OSThread, thread_self)->context->running.wait(false); TO_PTR(OSThread, thread_self)->context->running.wait(false);
check_destroyed(TO_PTR(OSThread, thread_self));
} }
void Multilibultra::pause_thread_impl(OSThread* t) { void Multilibultra::pause_thread_impl(OSThread* t) {

View File

@ -163,11 +163,6 @@ extern "C" OSTime osGetTime() {
extern "C" int osSetTimer(RDRAM_ARG PTR(OSTimer) t_, OSTime countdown, OSTime interval, PTR(OSMesgQueue) mq, OSMesg msg) { extern "C" int osSetTimer(RDRAM_ARG PTR(OSTimer) t_, OSTime countdown, OSTime interval, PTR(OSMesgQueue) mq, OSMesg msg) {
OSTimer* t = TO_PTR(OSTimer, t_); OSTimer* t = TO_PTR(OSTimer, t_);
// HACK: Skip the RCP timeout detection
if ((countdown == 140625000 || countdown == 1500000) && (uintptr_t)msg == 666) {
return 0;
}
// Determine the time when this timer will trigger off // Determine the time when this timer will trigger off
if (countdown == 0) { if (countdown == 0) {
// Set the timestamp based on the interval // Set the timestamp based on the interval

View File

@ -93,6 +93,7 @@ typedef struct OSThread_t {
int32_t pad3; int32_t pad3;
UltraThreadContext* context; // An actual pointer regardless of platform UltraThreadContext* context; // An actual pointer regardless of platform
int32_t sp; int32_t sp;
bool destroyed;
} OSThread; } OSThread;
typedef u32 OSEvent; typedef u32 OSEvent;

View File

@ -31,8 +31,9 @@ extern "C" void osFlashReadId_recomp(uint8_t * rdram, recomp_context * ctx) {
PTR(u32) flash_type = ctx->r4; PTR(u32) flash_type = ctx->r4;
PTR(u32) flash_maker = ctx->r5; PTR(u32) flash_maker = ctx->r5;
MEM_B(0, flash_type) = 0; // Mimic a real flash chip's type and maker, as some games actually check if one is present.
MEM_B(0, flash_maker) = 0; MEM_W(0, flash_type) = 0x11118001;
MEM_W(0, flash_maker) = 0x00C2001E;
} }
extern "C" void osFlashClearStatus_recomp(uint8_t * rdram, recomp_context * ctx) { extern "C" void osFlashClearStatus_recomp(uint8_t * rdram, recomp_context * ctx) {