Integrated RT64 (not included in repo), sign extended addresses

This commit is contained in:
Mr-Wiseguy 2022-11-19 18:12:47 -05:00
parent 39b67c8468
commit d0c3eb73ec
17 changed files with 185 additions and 92 deletions

5
.gitignore vendored
View file

@ -38,4 +38,7 @@ bld/
[Ll]ogs/ [Ll]ogs/
# Visual Studio 2015/2017 cache/options directory # Visual Studio 2015/2017 cache/options directory
.vs/ .vs/
# RT64 (since it's not public yet)
test/RT64

View file

@ -24,25 +24,35 @@ typedef uint64_t gpr;
((gpr)(int32_t)((a) - (b))) ((gpr)(int32_t)((a) - (b)))
#define MEM_W(offset, reg) \ #define MEM_W(offset, reg) \
(*(int32_t*)(rdram + ((((reg) + (offset))) & 0x3FFFFFF))) (*(int32_t*)(rdram + ((((reg) + (offset))) - 0xFFFFFFFF80000000)))
//(*(int32_t*)(rdram + ((((reg) + (offset))) & 0x3FFFFFF)))
#define MEM_H(offset, reg) \ #define MEM_H(offset, reg) \
(*(int16_t*)(rdram + ((((reg) + (offset)) ^ 2) & 0x3FFFFFF))) (*(int16_t*)(rdram + ((((reg) + (offset)) ^ 2) - 0xFFFFFFFF80000000)))
//(*(int16_t*)(rdram + ((((reg) + (offset)) ^ 2) & 0x3FFFFFF)))
#define MEM_B(offset, reg) \ #define MEM_B(offset, reg) \
(*(int8_t*)(rdram + ((((reg) + (offset)) ^ 3) & 0x3FFFFFF))) (*(int8_t*)(rdram + ((((reg) + (offset)) ^ 3) - 0xFFFFFFFF80000000)))
//(*(int8_t*)(rdram + ((((reg) + (offset)) ^ 3) & 0x3FFFFFF)))
#define MEM_HU(offset, reg) \ #define MEM_HU(offset, reg) \
(*(uint16_t*)(rdram + ((((reg) + (offset)) ^ 2) & 0x3FFFFFF))) (*(uint16_t*)(rdram + ((((reg) + (offset)) ^ 2) - 0xFFFFFFFF80000000)))
//(*(uint16_t*)(rdram + ((((reg) + (offset)) ^ 2) & 0x3FFFFFF)))
#define MEM_BU(offset, reg) \ #define MEM_BU(offset, reg) \
(*(uint8_t*)(rdram + ((((reg) + (offset)) ^ 3) & 0x3FFFFFF))) (*(uint8_t*)(rdram + ((((reg) + (offset)) ^ 3) - 0xFFFFFFFF80000000)))
//(*(uint8_t*)(rdram + ((((reg) + (offset)) ^ 3) & 0x3FFFFFF)))
#define SD(val, offset, reg) { \ #define SD(val, offset, reg) { \
*(uint32_t*)(rdram + ((((reg) + (offset) + 4)) & 0x3FFFFFF)) = (uint32_t)((val) >> 32); \ *(uint32_t*)(rdram + ((((reg) + (offset) + 4)) - 0xFFFFFFFF80000000)) = (uint32_t)((val) >> 0); \
*(uint32_t*)(rdram + ((((reg) + (offset) + 0)) & 0x3FFFFFF)) = (uint32_t)((val) >> 0); \ *(uint32_t*)(rdram + ((((reg) + (offset) + 0)) - 0xFFFFFFFF80000000)) = (uint32_t)((val) >> 32); \
} }
//#define SD(val, offset, reg) { \
// *(uint32_t*)(rdram + ((((reg) + (offset) + 4)) & 0x3FFFFFF)) = (uint32_t)((val) >> 32); \
// *(uint32_t*)(rdram + ((((reg) + (offset) + 0)) & 0x3FFFFFF)) = (uint32_t)((val) >> 0); \
//}
static inline uint64_t load_doubleword(uint8_t* rdram, gpr reg, gpr offset) { static inline uint64_t load_doubleword(uint8_t* rdram, gpr reg, gpr offset) {
uint64_t ret = 0; uint64_t ret = 0;
uint64_t lo = (uint64_t)(uint32_t)MEM_W(reg, offset + 4); uint64_t lo = (uint64_t)(uint32_t)MEM_W(reg, offset + 4);
@ -56,7 +66,8 @@ static inline uint64_t load_doubleword(uint8_t* rdram, gpr reg, gpr offset) {
// TODO proper lwl/lwr/swl/swr // TODO proper lwl/lwr/swl/swr
#define MEM_WL(offset, reg) \ #define MEM_WL(offset, reg) \
(*(int32_t*)(rdram + ((((reg) + (offset))) & 0x3FFFFFF))) (*(int32_t*)(rdram + ((((reg) + (offset))) - 0xFFFFFFFF80000000)))
//(*(int32_t*)(rdram + ((((reg) + (offset))) & 0x3FFFFFF)))
#define S32(val) \ #define S32(val) \
((int32_t)(val)) ((int32_t)(val))
@ -103,6 +114,8 @@ static inline uint64_t load_doubleword(uint8_t* rdram, gpr reg, gpr offset) {
#define NAN_CHECK(val) \ #define NAN_CHECK(val) \
assert(val == val) assert(val == val)
//#define NAN_CHECK(val)
typedef union { typedef union {
double d; double d;
struct { struct {

View file

@ -104,7 +104,7 @@ bool process_instruction(const RecompPort::Context& context, const RecompPort::F
break; break;
// Arithmetic // Arithmetic
case InstrId::cpu_lui: case InstrId::cpu_lui:
print_line("{}{} = {:#X} << 16", ctx_gpr_prefix(rt), rt, imm); print_line("{}{} = S32({:#X} << 16)", ctx_gpr_prefix(rt), rt, imm);
break; break;
case InstrId::cpu_addu: case InstrId::cpu_addu:
{ {

View file

@ -76,7 +76,7 @@
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(ProjectDir)..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(ProjectDir)..;$(ProjectDir)thirdparty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp20</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
@ -91,7 +91,7 @@
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(ProjectDir)..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(ProjectDir)..;$(ProjectDir)thirdparty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp20</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
@ -104,21 +104,28 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile> <ClCompile>
<AdditionalIncludeDirectories>$(ProjectDir)..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(ProjectDir)..;$(ProjectDir)thirdparty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp20</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<AdditionalDependencies>$(ProjectDir)RT64\Debug\RT64.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
<PostBuildEvent>
<Command>XCOPY "$(ProjectDir)RT64\$(Configuration)\*" "$(TargetDir)" /S /Y</Command>
</PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile> <ClCompile>
<AdditionalIncludeDirectories>$(ProjectDir)..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(ProjectDir)..;$(ProjectDir)thirdparty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp20</LanguageStandard> <LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
</Link> </Link>
<PostBuildEvent>
<Command>XCOPY "$(ProjectDir)RT64\$(Configuration)\*" "$(TargetDir)" /S /Y</Command>
</PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="funcs\adjust_texture_table.c" /> <ClCompile Include="funcs\adjust_texture_table.c" />
@ -2005,6 +2012,7 @@
<ClCompile Include="portultra\task_pthreads.cpp" /> <ClCompile Include="portultra\task_pthreads.cpp" />
<ClCompile Include="portultra\task_win32.cpp" /> <ClCompile Include="portultra\task_win32.cpp" />
<ClCompile Include="portultra\threads.cpp" /> <ClCompile Include="portultra\threads.cpp" />
<ClCompile Include="RT64\rt64_layer.cpp" />
<ClCompile Include="src\ai.cpp" /> <ClCompile Include="src\ai.cpp" />
<ClCompile Include="src\cont.cpp" /> <ClCompile Include="src\cont.cpp" />
<ClCompile Include="src\dp.cpp" /> <ClCompile Include="src\dp.cpp" />
@ -2020,7 +2028,11 @@
<ClInclude Include="..\recomp.h" /> <ClInclude Include="..\recomp.h" />
<ClInclude Include="portultra\multilibultra.hpp" /> <ClInclude Include="portultra\multilibultra.hpp" />
<ClInclude Include="portultra\platform_specific.h" /> <ClInclude Include="portultra\platform_specific.h" />
<ClInclude Include="RT64\rt64_layer.h" />
<ClInclude Include="portultra\ultra64.h" /> <ClInclude Include="portultra\ultra64.h" />
<ClInclude Include="thirdparty\blockingconcurrentqueue.h" />
<ClInclude Include="thirdparty\concurrentqueue.h" />
<ClInclude Include="thirdparty\lightweightsemaphore.h" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">

View file

@ -5700,6 +5700,9 @@
<ClCompile Include="portultra\events.cpp"> <ClCompile Include="portultra\events.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="RT64\rt64_layer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="portultra\platform_specific.h"> <ClInclude Include="portultra\platform_specific.h">
@ -5714,5 +5717,17 @@
<ClInclude Include="..\recomp.h"> <ClInclude Include="..\recomp.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="RT64\rt64_layer.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="thirdparty\blockingconcurrentqueue.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="thirdparty\concurrentqueue.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="thirdparty\lightweightsemaphore.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -2,11 +2,25 @@
#include <atomic> #include <atomic>
#include <chrono> #include <chrono>
#include <cinttypes> #include <cinttypes>
#include <variant>
#include <Windows.h>
#include "blockingconcurrentqueue.h"
#include "ultra64.h" #include "ultra64.h"
#include "multilibultra.hpp" #include "multilibultra.hpp"
#include "recomp.h" #include "recomp.h"
struct SpTaskAction {
OSTask task;
};
struct SwapBuffersAction {
int32_t origin;
};
using Action = std::variant<SpTaskAction, SwapBuffersAction>;
static struct { static struct {
struct { struct {
std::thread thread; std::thread thread;
@ -18,8 +32,6 @@ static struct {
std::thread thread; std::thread thread;
PTR(OSMesgQueue) mq = NULLPTR; PTR(OSMesgQueue) mq = NULLPTR;
OSMesg msg = (OSMesg)0; OSMesg msg = (OSMesg)0;
OSTask task;
std::atomic_flag task_queued;
} sp; } sp;
struct { struct {
std::thread thread; std::thread thread;
@ -35,12 +47,12 @@ static struct {
std::thread thread; std::thread thread;
PTR(OSMesgQueue) mq = NULLPTR; PTR(OSMesgQueue) mq = NULLPTR;
OSMesg msg = (OSMesg)0; OSMesg msg = (OSMesg)0;
std::atomic_flag read_queued;
} si; } si;
// The same message queue may be used for multiple events, so share a mutex for all of them // The same message queue may be used for multiple events, so share a mutex for all of them
std::mutex message_mutex; std::mutex message_mutex;
uint8_t* rdram; uint8_t* rdram;
std::chrono::system_clock::time_point start; std::chrono::system_clock::time_point start;
moodycamel::BlockingConcurrentQueue<Action> action_queue{};
} events_context{}; } events_context{};
extern "C" void osSetEventMesg(RDRAM_ARG OSEvent event_id, PTR(OSMesgQueue) mq_, OSMesg msg) { extern "C" void osSetEventMesg(RDRAM_ARG OSEvent event_id, PTR(OSMesgQueue) mq_, OSMesg msg) {
@ -73,8 +85,10 @@ extern "C" void osViSetEvent(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, u32 ret
events_context.vi.retrace_count = retrace_count; events_context.vi.retrace_count = retrace_count;
} }
constexpr uint32_t speed_multiplier = 10;
// N64 CPU counter ticks per millisecond // N64 CPU counter ticks per millisecond
constexpr uint32_t counter_per_ms = 46'875; constexpr uint32_t counter_per_ms = 46'875 * speed_multiplier;
uint64_t duration_to_count(std::chrono::system_clock::duration duration) { uint64_t duration_to_count(std::chrono::system_clock::duration duration) {
uint64_t delta_micros = std::chrono::duration_cast<std::chrono::microseconds>(duration).count(); uint64_t delta_micros = std::chrono::duration_cast<std::chrono::microseconds>(duration).count();
@ -107,7 +121,7 @@ void vi_thread_func() {
while (true) { while (true) {
// Determine the next VI time (more accurate than adding 16ms each VI interrupt) // Determine the next VI time (more accurate than adding 16ms each VI interrupt)
auto next = events_context.start + (total_vis * 1000000us) / 60; auto next = events_context.start + (total_vis * 1000000us) / (60 * speed_multiplier);
//if (next > std::chrono::system_clock::now()) { //if (next > std::chrono::system_clock::now()) {
// printf("Sleeping for %" PRIu64 " us to get from %" PRIu64 " us to %" PRIu64 " us \n", // printf("Sleeping for %" PRIu64 " us to get from %" PRIu64 " us to %" PRIu64 " us \n",
// (next - std::chrono::system_clock::now()) / 1us, // (next - std::chrono::system_clock::now()) / 1us,
@ -118,22 +132,29 @@ void vi_thread_func() {
//} //}
std::this_thread::sleep_until(next); std::this_thread::sleep_until(next);
// Calculate how many VIs have passed // Calculate how many VIs have passed
uint64_t new_total_vis = ((std::chrono::system_clock::now() - events_context.start) * 60 / 1000ms) + 1; uint64_t new_total_vis = ((std::chrono::system_clock::now() - events_context.start) * (60 * speed_multiplier) / 1000ms) + 1;
if (new_total_vis > total_vis + 1) { if (new_total_vis > total_vis + 1) {
printf("Skipped % " PRId64 " frames in VI interupt thread!\n", new_total_vis - total_vis - 1); //printf("Skipped % " PRId64 " frames in VI interupt thread!\n", new_total_vis - total_vis - 1);
} }
total_vis = new_total_vis; total_vis = new_total_vis;
remaining_retraces--; remaining_retraces--;
if (remaining_retraces == 0) { {
std::lock_guard lock{ events_context.message_mutex }; std::lock_guard lock{ events_context.message_mutex };
remaining_retraces = events_context.vi.retrace_count;
uint8_t* rdram = events_context.rdram; uint8_t* rdram = events_context.rdram;
if (remaining_retraces == 0) {
remaining_retraces = events_context.vi.retrace_count;
if (events_context.vi.mq != NULLPTR) { if (events_context.vi.mq != NULLPTR) {
if (osSendMesg(PASS_RDRAM events_context.vi.mq, events_context.vi.msg, OS_MESG_NOBLOCK) == -1) { if (osSendMesg(PASS_RDRAM events_context.vi.mq, events_context.vi.msg, OS_MESG_NOBLOCK) == -1) {
//printf("Game skipped a VI frame!\n"); //printf("Game skipped a VI frame!\n");
}
}
}
if (events_context.ai.mq != NULLPTR) {
if (osSendMesg(PASS_RDRAM events_context.ai.mq, events_context.ai.msg, OS_MESG_NOBLOCK) == -1) {
//printf("Game skipped a AI frame!\n");
} }
} }
} }
@ -152,41 +173,49 @@ 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);
} }
void gfx_thread_func() { void RT64Init(uint8_t* rom, uint8_t* rdram);
void RT64SendDL(uint8_t* rdram, const OSTask* task);
void RT64UpdateScreen(uint32_t vi_origin);
void RT64PumpEvents();
void gfx_thread_func(uint8_t* rdram, uint8_t* rom) {
using namespace std::chrono_literals;
RT64Init(rom, rdram);
while (true) { while (true) {
// Wait for a sp task to be queued // Try to pull an action from the queue
events_context.sp.task_queued.wait(false); Action action;
if (events_context.action_queue.wait_dequeue_timed(action, 1ms)) {
// Grab the task and inform the game that it's free to queue up a new task // Determine the action type and act on it
OSTask current_task = events_context.sp.task; if (const auto* task_action = std::get_if<SpTaskAction>(&action)) {
events_context.sp.task_queued.clear(); if (task_action->task.t.type == M_GFXTASK) {
events_context.sp.task_queued.notify_all(); // (TODO let RT64 do this) Tell the game that the RSP and RDP tasks are complete
RT64SendDL(rdram, &task_action->task);
// Process the task sp_complete();
if (current_task.t.type = M_GFXTASK) { dp_complete();
// TODO interface with RT64 here } else if (task_action->task.t.type == M_AUDTASK) {
sp_complete();
// (TODO let RT64 do this) Tell the game that the RSP and RDP tasks are complete } else {
sp_complete(); fprintf(stderr, "Unknown task type: %" PRIu32 "\n", task_action->task.t.type);
dp_complete(); std::exit(EXIT_FAILURE);
} else if (current_task.t.type == M_AUDTASK) { }
sp_complete(); } else if (const auto* swap_action = std::get_if<SwapBuffersAction>(&action)) {
} else { RT64UpdateScreen(swap_action->origin);
fprintf(stderr, "Unknown task type: %" PRIu32 "\n", current_task.t.type); }
std::exit(EXIT_FAILURE);
} }
// Handle events
RT64PumpEvents();
} }
} }
extern "C" void osViSwapBuffer(RDRAM_ARG PTR(void) frameBufPtr) {
events_context.action_queue.enqueue(SwapBuffersAction{ frameBufPtr + 640 });
}
void Multilibultra::submit_rsp_task(RDRAM_ARG PTR(OSTask) task_) { void Multilibultra::submit_rsp_task(RDRAM_ARG PTR(OSTask) task_) {
OSTask* task = TO_PTR(OSTask, task_); OSTask* task = TO_PTR(OSTask, task_);
// Wait for the sp thread clear the old task events_context.action_queue.enqueue(SpTaskAction{ *task });
events_context.sp.task_queued.wait(true);
// Make a full copy of the task instead of just recording a pointer to it, since that's what osSpTaskLoad does
events_context.sp.task = *task;
events_context.sp.task_queued.test_and_set();
events_context.sp.task_queued.notify_all();
} }
void Multilibultra::send_si_message() { void Multilibultra::send_si_message() {
@ -194,8 +223,8 @@ void Multilibultra::send_si_message() {
osSendMesg(PASS_RDRAM events_context.si.mq, events_context.si.msg, OS_MESG_NOBLOCK); osSendMesg(PASS_RDRAM events_context.si.mq, events_context.si.msg, OS_MESG_NOBLOCK);
} }
void Multilibultra::init_events(uint8_t* rdram) { void Multilibultra::init_events(uint8_t* rdram, uint8_t* rom) {
events_context.rdram = rdram; events_context.rdram = rdram;
events_context.vi.thread = std::thread{ vi_thread_func }; events_context.vi.thread = std::thread{ vi_thread_func };
events_context.sp.thread = std::thread{ gfx_thread_func }; events_context.sp.thread = std::thread{ gfx_thread_func, rdram, rom };
} }

View file

@ -1,9 +1,9 @@
#include "ultra64.h" #include "ultra64.h"
#include "multilibultra.hpp" #include "multilibultra.hpp"
void Multilibultra::preinit(uint8_t* rdram) { void Multilibultra::preinit(uint8_t* rdram, uint8_t* rom) {
Multilibultra::set_main_thread(); Multilibultra::set_main_thread();
Multilibultra::init_events(rdram); Multilibultra::init_events(rdram, rom);
} }
extern "C" void osInitialize() { extern "C" void osInitialize() {

View file

@ -167,7 +167,7 @@ extern "C" s32 osRecvMesg(RDRAM_ARG PTR(OSMesgQueue) mq_, PTR(OSMesg) msg_, s32
} }
} }
if (msg != nullptr) { if (msg_ != NULLPTR) {
*msg = TO_PTR(OSMesg, mq->msg)[mq->first]; *msg = TO_PTR(OSMesg, mq->msg)[mq->first];
} }

View file

@ -17,10 +17,10 @@ struct UltraThreadContext {
namespace Multilibultra { namespace Multilibultra {
void preinit(uint8_t* rdram); void preinit(uint8_t* rdram, uint8_t* rom);
void native_init(); void native_init();
void init_scheduler(); void init_scheduler();
void init_events(uint8_t* rdram); void init_events(uint8_t* rdram, uint8_t* rom);
void native_thread_init(OSThread *t); void native_thread_init(OSThread *t);
void set_self_paused(RDRAM_ARG1); void set_self_paused(RDRAM_ARG1);
void wait_for_resumed(RDRAM_ARG1); void wait_for_resumed(RDRAM_ARG1);

View file

@ -29,7 +29,7 @@ int main(int argc, char** argv) {
#endif #endif
#if 1 #if 1
void run_thread_function(uint8_t* rdram, uint32_t addr, uint32_t sp, uint32_t arg); void run_thread_function(uint8_t* rdram, uint64_t addr, uint64_t sp, uint64_t arg);
#else #else
#define run_thread_function(func, sp, arg) func(arg) #define run_thread_function(func, sp, arg) func(arg)
#endif #endif
@ -66,7 +66,7 @@ extern "C" void osStartThread(RDRAM_ARG PTR(OSThread) t_) {
OSThread* t = TO_PTR(OSThread, t_); OSThread* t = TO_PTR(OSThread, t_);
debug_printf("[os] Start Thread %d\n", t->id); debug_printf("[os] Start Thread %d\n", t->id);
// Wait until the thread is initialized to indicate that it's task_queued to be started. // Wait until the thread is initialized to indicate that it's action_queued to be started.
t->context->initialized.wait(false); t->context->initialized.wait(false);
debug_printf("[os] Thread %d is ready to be started\n", t->id); debug_printf("[os] Thread %d is ready to be started\n", t->id);

View file

@ -25,12 +25,12 @@ typedef uint16_t u16;
typedef int8_t s8; typedef int8_t s8;
typedef uint8_t u8; typedef uint8_t u8;
#define PTR(x) uint32_t #define PTR(x) int32_t
#define RDRAM_ARG uint8_t *rdram, #define RDRAM_ARG uint8_t *rdram,
#define RDRAM_ARG1 uint8_t *rdram #define RDRAM_ARG1 uint8_t *rdram
#define PASS_RDRAM rdram, #define PASS_RDRAM rdram,
#define PASS_RDRAM1 rdram #define PASS_RDRAM1 rdram
#define TO_PTR(type, var) ((type*)(&rdram[var & 0x3FFFFFF])) #define TO_PTR(type, var) ((type*)(&rdram[(uint64_t)var - 0xFFFFFFFF80000000]))
#ifdef __cplusplus #ifdef __cplusplus
#define NULLPTR (PTR(void))0 #define NULLPTR (PTR(void))0
#endif #endif
@ -89,7 +89,7 @@ typedef struct OSThread_t {
OSId id; OSId id;
int32_t pad3; int32_t pad3;
UltraThreadContext* context; // An actual pointer regardless of platform UltraThreadContext* context; // An actual pointer regardless of platform
uint32_t sp; int32_t sp;
} OSThread; } OSThread;
typedef u32 OSEvent; typedef u32 OSEvent;
@ -161,6 +161,7 @@ s32 osJamMesg(RDRAM_ARG PTR(OSMesgQueue), OSMesg, s32);
s32 osRecvMesg(RDRAM_ARG PTR(OSMesgQueue), PTR(OSMesg), s32); s32 osRecvMesg(RDRAM_ARG PTR(OSMesgQueue), PTR(OSMesg), s32);
void osSetEventMesg(RDRAM_ARG OSEvent, PTR(OSMesgQueue), OSMesg); void osSetEventMesg(RDRAM_ARG OSEvent, PTR(OSMesgQueue), OSMesg);
void osViSetEvent(RDRAM_ARG PTR(OSMesgQueue), OSMesg, u32); void osViSetEvent(RDRAM_ARG PTR(OSMesgQueue), OSMesg, u32);
void osViSwapBuffer(RDRAM_ARG PTR(void) frameBufPtr);
u32 osGetCount(); u32 osGetCount();
OSTime osGetTime(); OSTime osGetTime();

View file

@ -1,17 +1,20 @@
#include "recomp.h" #include "recomp.h"
extern "C" void osAiSetFrequency_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osAiSetFrequency_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
; ctx->r2 = ctx->r4;
} }
static uint32_t ai_length = 0;
extern "C" void osAiSetNextBuffer_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osAiSetNextBuffer_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
; ai_length = (uint32_t)ctx->r5;
ctx->r2 = 0;
} }
extern "C" void osAiGetLength_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osAiGetLength_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
; ctx->r2 = ai_length;
} }
extern "C" void osAiGetStatus_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osAiGetStatus_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
; ctx->r2 = 0x80000000;
} }

View file

@ -9,8 +9,24 @@ extern "C" void osContStartReadData_recomp(uint8_t* restrict rdram, recomp_conte
Multilibultra::send_si_message(); Multilibultra::send_si_message();
} }
struct OSContPad {
u16 button;
s8 stick_x; /* -80 <= stick_x <= 80 */
s8 stick_y; /* -80 <= stick_y <= 80 */
u8 errno_;
};
extern "C" void osContGetReadData_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osContGetReadData_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
; int32_t pad = (uint32_t)ctx->r4;
// button
MEM_H(0, pad) = 0;
// stick_x
MEM_B(2, pad) = 0;
// stick_y
MEM_B(3, pad) = 0;
// errno
MEM_B(4, pad) = 0;
} }
extern "C" void osMotorInit_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osMotorInit_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {

View file

@ -16,7 +16,7 @@ extern "C" void osCreatePiManager_recomp(uint8_t* restrict rdram, recomp_context
constexpr uint32_t rom_base = 0xB0000000; constexpr uint32_t rom_base = 0xB0000000;
void do_rom_read(uint8_t* rdram, uint32_t ram_address, uint32_t dev_address, size_t num_bytes) { void do_rom_read(uint8_t* rdram, int32_t ram_address, uint32_t dev_address, size_t num_bytes) {
// TODO use word copies when possible // TODO use word copies when possible
uint8_t* rom_addr = rom.get() + (dev_address | rom_base) - rom_base; uint8_t* rom_addr = rom.get() + (dev_address | rom_base) - rom_base;
for (size_t i = 0; i < num_bytes; i++) { for (size_t i = 0; i < num_bytes; i++) {
@ -30,7 +30,7 @@ extern "C" void osPiStartDma_recomp(uint8_t* restrict rdram, recomp_context* res
uint32_t pri = ctx->r5; uint32_t pri = ctx->r5;
uint32_t direction = ctx->r6; uint32_t direction = ctx->r6;
uint32_t devAddr = ctx->r7; uint32_t devAddr = ctx->r7;
uint32_t dramAddr = MEM_W(0x10, ctx->r29); int32_t dramAddr = MEM_W(0x10, ctx->r29);
uint32_t size = MEM_W(0x14, ctx->r29); uint32_t size = MEM_W(0x14, ctx->r29);
uint32_t mq_ = MEM_W(0x18, ctx->r29); uint32_t mq_ = MEM_W(0x18, ctx->r29);
OSMesgQueue* mq = TO_PTR(OSMesgQueue, mq_); OSMesgQueue* mq = TO_PTR(OSMesgQueue, mq_);

View file

@ -35,8 +35,8 @@ extern "C" recomp_func_t* get_function(uint32_t addr) {
} }
extern "C" void bzero(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void bzero(uint8_t* restrict rdram, recomp_context* restrict ctx) {
uint32_t start_addr = ctx->r4; gpr start_addr = ctx->r4;
uint32_t size = ctx->r5; gpr size = ctx->r5;
for (uint32_t i = 0; i < size; i++) { for (uint32_t i = 0; i < size; i++) {
MEM_B(start_addr, i) = 0; MEM_B(start_addr, i) = 0;
@ -53,7 +53,7 @@ extern "C" void do_break(uint32_t vram) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
void run_thread_function(uint8_t* rdram, uint32_t addr, uint32_t sp, uint32_t arg) { void run_thread_function(uint8_t* rdram, uint64_t addr, uint64_t sp, uint64_t arg) {
recomp_context ctx{}; recomp_context ctx{};
ctx.r29 = sp; ctx.r29 = sp;
ctx.r4 = arg; ctx.r4 = arg;
@ -62,7 +62,7 @@ void run_thread_function(uint8_t* rdram, uint32_t addr, uint32_t sp, uint32_t ar
} }
extern "C" void game_init(uint8_t* restrict rdram, recomp_context* restrict ctx); extern "C" void game_init(uint8_t* restrict rdram, recomp_context* restrict ctx);
void do_rom_read(uint8_t* rdram, uint32_t ram_address, uint32_t dev_address, size_t num_bytes); void do_rom_read(uint8_t* rdram, int32_t ram_address, uint32_t dev_address, size_t num_bytes);
std::unique_ptr<uint8_t[]> rom; std::unique_ptr<uint8_t[]> rom;
size_t rom_size; size_t rom_size;
@ -105,7 +105,7 @@ int main(int argc, char **argv) {
// Get entrypoint from ROM // Get entrypoint from ROM
// TODO fix this for other IPL3 versions // TODO fix this for other IPL3 versions
uint32_t entrypoint = byteswap(*reinterpret_cast<uint32_t*>(rom.get() + 0x8)); int32_t entrypoint = byteswap(*reinterpret_cast<uint32_t*>(rom.get() + 0x8));
// Allocate rdram_buffer // Allocate rdram_buffer
std::unique_ptr<uint8_t[]> rdram_buffer = std::make_unique<uint8_t[]>(8 * 1024 * 1024); std::unique_ptr<uint8_t[]> rdram_buffer = std::make_unique<uint8_t[]>(8 * 1024 * 1024);
@ -134,17 +134,17 @@ int main(int argc, char **argv) {
#endif #endif
// Set up stack pointer // Set up stack pointer
context.r29 = 0x803FFFF0u; context.r29 = 0xFFFFFFFF803FFFF0u;
// Initialize variables normally set by IPL3 // Initialize variables normally set by IPL3
constexpr uint32_t osTvType = 0x80000300; constexpr int32_t osTvType = 0x80000300;
constexpr uint32_t osRomType = 0x80000304; constexpr int32_t osRomType = 0x80000304;
constexpr uint32_t osRomBase = 0x80000308; constexpr int32_t osRomBase = 0x80000308;
constexpr uint32_t osResetType = 0x8000030c; constexpr int32_t osResetType = 0x8000030c;
constexpr uint32_t osCicId = 0x80000310; constexpr int32_t osCicId = 0x80000310;
constexpr uint32_t osVersion = 0x80000314; constexpr int32_t osVersion = 0x80000314;
constexpr uint32_t osMemSize = 0x80000318; constexpr int32_t osMemSize = 0x80000318;
constexpr uint32_t osAppNMIBuffer = 0x8000031c; constexpr int32_t osAppNMIBuffer = 0x8000031c;
uint8_t *rdram = rdram_buffer.get(); uint8_t *rdram = rdram_buffer.get();
MEM_W(osTvType, 0) = 1; // NTSC MEM_W(osTvType, 0) = 1; // NTSC
MEM_W(osRomBase, 0) = 0xB0000000u; // standard rom base MEM_W(osRomBase, 0) = 0xB0000000u; // standard rom base
@ -157,7 +157,7 @@ int main(int argc, char **argv) {
debug_printf("[Recomp] Starting\n"); debug_printf("[Recomp] Starting\n");
Multilibultra::preinit(rdram_buffer.get()); Multilibultra::preinit(rdram_buffer.get(), rom.get());
game_init(rdram_buffer.get(), &context); game_init(rdram_buffer.get(), &context);

View file

@ -10,7 +10,7 @@ extern "C" void osSpTaskStartGo_recomp(uint8_t* restrict rdram, recomp_context*
//printf("[sp] osSpTaskStartGo(0x%08X)\n", (uint32_t)ctx->r4); //printf("[sp] osSpTaskStartGo(0x%08X)\n", (uint32_t)ctx->r4);
OSTask* task = TO_PTR(OSTask, ctx->r4); OSTask* task = TO_PTR(OSTask, ctx->r4);
if (task->t.type == M_GFXTASK) { if (task->t.type == M_GFXTASK) {
printf("[sp] Gfx task: %08X\n", (uint32_t)ctx->r4); //printf("[sp] Gfx task: %08X\n", (uint32_t)ctx->r4);
} else if (task->t.type == M_AUDTASK) { } else if (task->t.type == M_AUDTASK) {
printf("[sp] Audio task: %08X\n", (uint32_t)ctx->r4); printf("[sp] Audio task: %08X\n", (uint32_t)ctx->r4);
} }

View file

@ -1,3 +1,4 @@
#include "../portultra/multilibultra.hpp"
#include "recomp.h" #include "recomp.h"
extern "C" void osCreateViManager_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osCreateViManager_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
@ -21,7 +22,7 @@ extern "C" void osViGetNextFramebuffer_recomp(uint8_t* restrict rdram, recomp_co
} }
extern "C" void osViSwapBuffer_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osViSwapBuffer_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {
; osViSwapBuffer(rdram, ctx->r4);
} }
extern "C" void osViSetMode_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { extern "C" void osViSetMode_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) {