From b94fe6f5fb2750b957c9f963d400f8957a84ccf9 Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Tue, 15 Nov 2022 19:55:48 -0500 Subject: [PATCH] Created solution for testing output --- .gitignore | 5 +- test/RecompTest.sln | 31 + test/RecompTest.vcxproj | 2028 ++++++++++ test/RecompTest.vcxproj.filters | 5718 ++++++++++++++++++++++++++++ test/portultra/init.cpp | 7 + test/portultra/main.c | 83 + test/portultra/mesgqueue.cpp | 188 + test/portultra/multilibultra.hpp | 53 + test/portultra/platform_specific.h | 32 + test/portultra/scheduler.cpp | 268 ++ test/portultra/task_pthreads.cpp | 60 + test/portultra/task_win32.cpp | 32 + test/portultra/threads.cpp | 143 + test/portultra/ultra64.h | 133 + test/src/ai.cpp | 17 + test/src/cont.cpp | 25 + test/src/dp.cpp | 5 + test/src/eep.cpp | 21 + test/src/misc_ultra.cpp | 65 + test/src/pi.cpp | 48 + test/src/portultra_translation.cpp | 41 + test/src/recomp.cpp | 169 + test/src/sp.cpp | 22 + test/src/vi.cpp | 33 + 24 files changed, 9225 insertions(+), 2 deletions(-) create mode 100644 test/RecompTest.sln create mode 100644 test/RecompTest.vcxproj create mode 100644 test/RecompTest.vcxproj.filters create mode 100644 test/portultra/init.cpp create mode 100644 test/portultra/main.c create mode 100644 test/portultra/mesgqueue.cpp create mode 100644 test/portultra/multilibultra.hpp create mode 100644 test/portultra/platform_specific.h create mode 100644 test/portultra/scheduler.cpp create mode 100644 test/portultra/task_pthreads.cpp create mode 100644 test/portultra/task_win32.cpp create mode 100644 test/portultra/threads.cpp create mode 100644 test/portultra/ultra64.h create mode 100644 test/src/ai.cpp create mode 100644 test/src/cont.cpp create mode 100644 test/src/dp.cpp create mode 100644 test/src/eep.cpp create mode 100644 test/src/misc_ultra.cpp create mode 100644 test/src/pi.cpp create mode 100644 test/src/portultra_translation.cpp create mode 100644 test/src/recomp.cpp create mode 100644 test/src/sp.cpp create mode 100644 test/src/vi.cpp diff --git a/.gitignore b/.gitignore index a1a87fa..f7679ff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,12 @@ # VSCode file settings .vscode/settings.json -# Input elf files +# Input elf and rom files *.elf +*.z64 # Output C files -out/ +test/funcs # Linux build output build/ diff --git a/test/RecompTest.sln b/test/RecompTest.sln new file mode 100644 index 0000000..76cae31 --- /dev/null +++ b/test/RecompTest.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.32929.386 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RecompTest", "RecompTest.vcxproj", "{73819ED8-8A5B-4554-B3F3-60257A43F296}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {73819ED8-8A5B-4554-B3F3-60257A43F296}.Debug|x64.ActiveCfg = Debug|x64 + {73819ED8-8A5B-4554-B3F3-60257A43F296}.Debug|x64.Build.0 = Debug|x64 + {73819ED8-8A5B-4554-B3F3-60257A43F296}.Debug|x86.ActiveCfg = Debug|Win32 + {73819ED8-8A5B-4554-B3F3-60257A43F296}.Debug|x86.Build.0 = Debug|Win32 + {73819ED8-8A5B-4554-B3F3-60257A43F296}.Release|x64.ActiveCfg = Release|x64 + {73819ED8-8A5B-4554-B3F3-60257A43F296}.Release|x64.Build.0 = Release|x64 + {73819ED8-8A5B-4554-B3F3-60257A43F296}.Release|x86.ActiveCfg = Release|Win32 + {73819ED8-8A5B-4554-B3F3-60257A43F296}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DD740FE2-99F7-4C80-B124-06D14447F873} + EndGlobalSection +EndGlobal diff --git a/test/RecompTest.vcxproj b/test/RecompTest.vcxproj new file mode 100644 index 0000000..638a52d --- /dev/null +++ b/test/RecompTest.vcxproj @@ -0,0 +1,2028 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {73819ED8-8A5B-4554-B3F3-60257A43F296} + Win32Proj + 10.0 + + + + Application + true + v142 + + + Application + false + v142 + + + Application + true + v142 + + + Application + false + v142 + + + + + + + + + + + + + + + + + + + + + true + + + true + + + + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + ProgramDatabase + Disabled + $(ProjectDir)..;%(AdditionalIncludeDirectories) + stdcpp20 + + + MachineX86 + true + Console + + + + + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + ProgramDatabase + $(ProjectDir)..;%(AdditionalIncludeDirectories) + stdcpp20 + + + MachineX86 + true + Console + true + true + + + + + $(ProjectDir)..;%(AdditionalIncludeDirectories) + stdcpp20 + + + Console + + + + + $(ProjectDir)..;%(AdditionalIncludeDirectories) + stdcpp20 + + + Console + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/RecompTest.vcxproj.filters b/test/RecompTest.vcxproj.filters new file mode 100644 index 0000000..13821f7 --- /dev/null +++ b/test/RecompTest.vcxproj.filters @@ -0,0 +1,5718 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {686e650c-616a-4d1a-84c9-f967294cc727} + + + + + Source Files + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Funcs + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Funcs + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/test/portultra/init.cpp b/test/portultra/init.cpp new file mode 100644 index 0000000..8151a7b --- /dev/null +++ b/test/portultra/init.cpp @@ -0,0 +1,7 @@ +#include "ultra64.h" +#include "multilibultra.hpp" + +extern "C" void osInitialize() { + Multilibultra::init_scheduler(); + Multilibultra::native_init(); +} diff --git a/test/portultra/main.c b/test/portultra/main.c new file mode 100644 index 0000000..968b4d3 --- /dev/null +++ b/test/portultra/main.c @@ -0,0 +1,83 @@ +#if 0 + +#include +#include +#include "ultra64.h" + +#define THREAD_STACK_SIZE 0x1000 + +u8 idle_stack[THREAD_STACK_SIZE] ALIGNED(16); +u8 main_stack[THREAD_STACK_SIZE] ALIGNED(16); +u8 thread3_stack[THREAD_STACK_SIZE] ALIGNED(16); +u8 thread4_stack[THREAD_STACK_SIZE] ALIGNED(16); + +OSThread idle_thread; +OSThread main_thread; +OSThread thread3; +OSThread thread4; + +OSMesgQueue queue; +OSMesg buf[1]; + +void thread3_func(UNUSED void *arg) { + OSMesg val; + printf("Thread3 recv\n"); + fflush(stdout); + osRecvMesg(&queue, &val, OS_MESG_BLOCK); + printf("Thread3 complete: %d\n", (int)(intptr_t)val); + fflush(stdout); +} + +void thread4_func(void *arg) { + printf("Thread4 send %d\n", (int)(intptr_t)arg); + fflush(stdout); + osSendMesg(&queue, arg, OS_MESG_BLOCK); + printf("Thread4 complete\n"); + fflush(stdout); +} + +void main_thread_func(UNUSED void* arg) { + osCreateMesgQueue(&queue, buf, sizeof(buf) / sizeof(buf[0])); + + printf("main thread creating thread 3\n"); + osCreateThread(&thread3, 3, thread3_func, NULL, &thread3_stack[THREAD_STACK_SIZE], 14); + printf("main thread starting thread 3\n"); + osStartThread(&thread3); + + printf("main thread creating thread 4\n"); + osCreateThread(&thread4, 4, thread4_func, (void*)10, &thread4_stack[THREAD_STACK_SIZE], 13); + printf("main thread starting thread 4\n"); + osStartThread(&thread4); + + while (1) { + printf("main thread doin stuff\n"); + sleep(1); + } +} + +void idle_thread_func(UNUSED void* arg) { + printf("idle thread\n"); + printf("creating main thread\n"); + osCreateThread(&main_thread, 2, main_thread_func, NULL, &main_stack[THREAD_STACK_SIZE], 11); + printf("starting main thread\n"); + osStartThread(&main_thread); + + // Set this thread's priority to 0, making it the idle thread + osSetThreadPri(NULL, 0); + + // idle + while (1) { + printf("idle thread doin stuff\n"); + sleep(1); + } +} + +void bootproc(void) { + osInitialize(); + + osCreateThread(&idle_thread, 1, idle_thread_func, NULL, &idle_stack[THREAD_STACK_SIZE], 127); + printf("Starting idle thread\n"); + osStartThread(&idle_thread); +} + +#endif diff --git a/test/portultra/mesgqueue.cpp b/test/portultra/mesgqueue.cpp new file mode 100644 index 0000000..6326fb9 --- /dev/null +++ b/test/portultra/mesgqueue.cpp @@ -0,0 +1,188 @@ +#include +#include + +#include "ultra64.h" +#include "multilibultra.hpp" +#include "recomp.h" + +extern "C" void osCreateMesgQueue(RDRAM_ARG PTR(OSMesgQueue) mq_, PTR(OSMesg) msg, s32 count) { + OSMesgQueue *mq = TO_PTR(OSMesgQueue, mq_); + mq->blocked_on_recv = NULLPTR; + mq->blocked_on_send = NULLPTR; + mq->msgCount = count; + mq->msg = msg; + mq->validCount = 0; + mq->first = 0; +} + +s32 MQ_GET_COUNT(OSMesgQueue *mq) { + return mq->validCount; +} + +s32 MQ_IS_EMPTY(OSMesgQueue *mq) { + return mq->validCount == 0; +} + +s32 MQ_IS_FULL(OSMesgQueue* mq) { + return MQ_GET_COUNT(mq) >= mq->msgCount; +} + +void thread_queue_insert(RDRAM_ARG PTR(OSThread)* queue, PTR(OSThread) toadd_) { + PTR(OSThread)* cur = queue; + OSThread* toadd = TO_PTR(OSThread, toadd_); + while (*cur && TO_PTR(OSThread, *cur)->priority > toadd->priority) { + cur = &TO_PTR(OSThread, *cur)->next; + } + toadd->next = (*cur); + *cur = toadd_; +} + +OSThread* thread_queue_pop(RDRAM_ARG PTR(OSThread)* queue) { + PTR(OSThread) ret = *queue; + *queue = TO_PTR(OSThread, ret)->next; + return TO_PTR(OSThread, ret); +} + +bool thread_queue_empty(RDRAM_ARG PTR(OSThread)* queue) { + return *queue == NULLPTR; +} + +extern "C" s32 osSendMesg(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, s32 flags) { + OSMesgQueue *mq = TO_PTR(OSMesgQueue, mq_); + Multilibultra::disable_preemption(); + + if (flags == OS_MESG_NOBLOCK) { + // If non-blocking, fail if the queue is full + if (MQ_IS_FULL(mq)) { + Multilibultra::enable_preemption(); + return -1; + } + } else { + // Otherwise, yield this thread until the queue has room + while (MQ_IS_FULL(mq)) { + debug_printf("[Message Queue] Thread %d is blocked on send\n", TO_PTR(OSThread, Multilibultra::this_thread())->id); + thread_queue_insert(PASS_RDRAM &mq->blocked_on_send, Multilibultra::this_thread()); + Multilibultra::enable_preemption(); + Multilibultra::pause_self(PASS_RDRAM1); + Multilibultra::disable_preemption(); + } + } + + s32 last = (mq->first + mq->validCount) % mq->msgCount; + TO_PTR(OSMesg, mq->msg)[last] = msg; + mq->validCount++; + + OSThread* to_run = nullptr; + + if (!thread_queue_empty(PASS_RDRAM &mq->blocked_on_recv)) { + to_run = thread_queue_pop(PASS_RDRAM &mq->blocked_on_recv); + } + + Multilibultra::enable_preemption(); + if (to_run) { + debug_printf("[Message Queue] Thread %d is unblocked\n", to_run->id); + OSThread* self = TO_PTR(OSThread, Multilibultra::this_thread()); + if (to_run->priority > self->priority) { + Multilibultra::swap_to_thread(PASS_RDRAM to_run); + } else { + Multilibultra::schedule_running_thread(to_run); + } + } + return 0; +} + +extern "C" s32 osJamMesg(RDRAM_ARG PTR(OSMesgQueue) mq_, OSMesg msg, s32 flags) { + OSMesgQueue *mq = TO_PTR(OSMesgQueue, mq_); + Multilibultra::disable_preemption(); + + if (flags == OS_MESG_NOBLOCK) { + // If non-blocking, fail if the queue is full + if (MQ_IS_FULL(mq)) { + Multilibultra::enable_preemption(); + return -1; + } + } else { + // Otherwise, yield this thread in a loop until the queue is no longer full + while (MQ_IS_FULL(mq)) { + debug_printf("[Message Queue] Thread %d is blocked on jam\n", TO_PTR(OSThread, Multilibultra::this_thread())->id); + thread_queue_insert(PASS_RDRAM &mq->blocked_on_send, Multilibultra::this_thread()); + Multilibultra::enable_preemption(); + Multilibultra::pause_self(PASS_RDRAM1); + Multilibultra::disable_preemption(); + } + } + + mq->first = (mq->first + mq->msgCount - 1) % mq->msgCount; + TO_PTR(OSMesg, mq->msg)[mq->first] = msg; + mq->validCount++; + + OSThread *to_run = nullptr; + + if (!thread_queue_empty(PASS_RDRAM &mq->blocked_on_recv)) { + to_run = thread_queue_pop(PASS_RDRAM &mq->blocked_on_recv); + } + + Multilibultra::enable_preemption(); + if (to_run) { + debug_printf("[Message Queue] Thread %d is unblocked\n", to_run->id); + OSThread *self = TO_PTR(OSThread, Multilibultra::this_thread()); + if (to_run->priority > self->priority) { + Multilibultra::swap_to_thread(PASS_RDRAM to_run); + } else { + Multilibultra::schedule_running_thread(to_run); + } + } + return 0; +} + +extern "C" s32 osRecvMesg(RDRAM_ARG PTR(OSMesgQueue) mq_, PTR(OSMesg) msg_, s32 flags) { + OSMesgQueue *mq = TO_PTR(OSMesgQueue, mq_); + OSMesg *msg = TO_PTR(OSMesg, msg_); + Multilibultra::disable_preemption(); + + if (flags == OS_MESG_NOBLOCK) { + // If non-blocking, fail if the queue is empty + if (MQ_IS_EMPTY(mq)) { + Multilibultra::enable_preemption(); + return -1; + } + } else { + // Otherwise, yield this thread in a loop until the queue is no longer full + while (MQ_IS_EMPTY(mq)) { + debug_printf("[Message Queue] Thread %d is blocked on receive\n", TO_PTR(OSThread, Multilibultra::this_thread())->id); + thread_queue_insert(PASS_RDRAM &mq->blocked_on_recv, Multilibultra::this_thread()); + Multilibultra::enable_preemption(); + Multilibultra::pause_self(PASS_RDRAM1); + Multilibultra::disable_preemption(); + } + } + + if (msg != nullptr) { + *msg = TO_PTR(OSMesg, mq->msg)[mq->first]; + } + + mq->first = (mq->first + 1) % mq->msgCount; + mq->validCount--; + + OSThread *to_run = nullptr; + + if (!thread_queue_empty(PASS_RDRAM &mq->blocked_on_send)) { + to_run = thread_queue_pop(PASS_RDRAM &mq->blocked_on_send); + } + + Multilibultra::enable_preemption(); + if (to_run) { + debug_printf("[Message Queue] Thread %d is unblocked\n", to_run->id); + OSThread *self = TO_PTR(OSThread, Multilibultra::this_thread()); + if (to_run->priority > self->priority) { + Multilibultra::swap_to_thread(PASS_RDRAM to_run); + } else { + Multilibultra::schedule_running_thread(to_run); + } + } + return 0; +} + +extern "C" void osSetEventMesg(RDRAM_ARG OSEvent, PTR(OSMesgQueue), OSMesg) { + +} diff --git a/test/portultra/multilibultra.hpp b/test/portultra/multilibultra.hpp new file mode 100644 index 0000000..dc0bc9a --- /dev/null +++ b/test/portultra/multilibultra.hpp @@ -0,0 +1,53 @@ +#ifndef __MULTILIBULTRA_HPP__ +#define __MULTILIBULTRA_HPP__ + +#include +#include +#include + +#include "ultra64.h" +#include "platform_specific.h" + +struct UltraThreadContext { + std::thread host_thread; + std::atomic_bool running; + std::atomic_bool initialized; +}; + +namespace Multilibultra { + +void native_init(); +void init_scheduler(); +void native_thread_init(OSThread *t); +void set_self_paused(RDRAM_ARG1); +void wait_for_resumed(RDRAM_ARG1); +void swap_to_thread(RDRAM_ARG OSThread *to); +void pause_thread_impl(OSThread *t); +void pause_thread_native_impl(OSThread *t); +void resume_thread_impl(OSThread *t); +void resume_thread_native_impl(OSThread *t); +void schedule_running_thread(OSThread *t); +void stop_thread(OSThread *t); +void pause_self(RDRAM_ARG1); +void cleanup_thread(OSThread *t); +PTR(OSThread) this_thread(); +void disable_preemption(); +void enable_preemption(); +void notify_scheduler(); +void reprioritize_thread(OSThread *t, OSPri pri); +void set_main_thread(); + +class preemption_guard { +public: + preemption_guard(); + ~preemption_guard(); +private: + std::lock_guard lock; +}; + +} // namespace Multilibultra + +#define debug_printf(...) printf(__VA_ARGS__); +//#define debug_printf(...) + +#endif diff --git a/test/portultra/platform_specific.h b/test/portultra/platform_specific.h new file mode 100644 index 0000000..b9d1823 --- /dev/null +++ b/test/portultra/platform_specific.h @@ -0,0 +1,32 @@ +#ifndef __PLATFORM_SPECIFIC_H__ +#define __PLATFORM_SPECIFIC_H__ + +#if defined(__linux__) + +//#include +// +//typedef struct { +// pthread_t t; +// pthread_barrier_t pause_barrier; +// pthread_mutex_t pause_mutex; +// pthread_cond_t pause_cond; +// void (*entrypoint)(void *); +// void *arg; +//} OSThreadNative; + +#elif defined(_WIN32) + +//#include +// +//typedef struct { +// pthread_t t; +// pthread_barrier_t pause_barrier; +// pthread_mutex_t pause_mutex; +// pthread_cond_t pause_cond; +// void (*entrypoint)(void*); +// void* arg; +//} OSThreadNative; + +#endif + +#endif \ No newline at end of file diff --git a/test/portultra/scheduler.cpp b/test/portultra/scheduler.cpp new file mode 100644 index 0000000..52bb7d1 --- /dev/null +++ b/test/portultra/scheduler.cpp @@ -0,0 +1,268 @@ +#include +#include +#include +#include + +#include "multilibultra.hpp" + +class OSThreadComparator { +public: + bool operator() (OSThread *a, OSThread *b) const { + return a->priority < b->priority; + } +}; + +class thread_queue_t : public std::priority_queue, OSThreadComparator> { +public: + // TODO comment this + bool remove(const OSThread* value) { + auto it = std::find(this->c.begin(), this->c.end(), value); + + if (it == this->c.end()) { + return false; + } + + if (it == this->c.begin()) { + // deque the top element + this->pop(); + } else { + // remove element and re-heap + this->c.erase(it); + std::make_heap(this->c.begin(), this->c.end(), this->comp); + } + + return true; + } +}; + +static struct { + std::vector to_schedule; + std::vector to_stop; + std::vector to_cleanup; + std::vector> to_reprioritize; + std::mutex mutex; + // OSThread* running_thread; + std::atomic_int notify_count; + std::atomic_int action_count; + + bool can_preempt; + std::mutex premption_mutex; +} scheduler_context{}; + +void handle_thread_queueing(thread_queue_t& running_thread_queue) { + std::lock_guard lock{scheduler_context.mutex}; + + if (!scheduler_context.to_schedule.empty()) { + OSThread* to_schedule = scheduler_context.to_schedule.back(); + scheduler_context.to_schedule.pop_back(); + scheduler_context.action_count.fetch_sub(1); + debug_printf("[Scheduler] Scheduling thread %d\n", to_schedule->id); + running_thread_queue.push(to_schedule); + } +} + +void handle_thread_stopping(thread_queue_t& running_thread_queue) { + std::lock_guard lock{scheduler_context.mutex}; + + while (!scheduler_context.to_stop.empty()) { + OSThread* to_stop = scheduler_context.to_stop.back(); + scheduler_context.to_stop.pop_back(); + scheduler_context.action_count.fetch_sub(1); + debug_printf("[Scheduler] Stopping thread %d\n", to_stop->id); + running_thread_queue.remove(to_stop); + } +} + +void handle_thread_cleanup(thread_queue_t& running_thread_queue) { + std::lock_guard lock{scheduler_context.mutex}; + + while (!scheduler_context.to_cleanup.empty()) { + OSThread* to_cleanup = scheduler_context.to_cleanup.back(); + scheduler_context.to_cleanup.pop_back(); + scheduler_context.action_count.fetch_sub(1); + + debug_printf("[Scheduler] Destroying thread %d\n", to_cleanup->id); + running_thread_queue.remove(to_cleanup); + to_cleanup->context->host_thread.join(); + delete to_cleanup->context; + } +} + +void handle_thread_reprioritization(thread_queue_t& running_thread_queue) { + std::lock_guard lock{scheduler_context.mutex}; + + while (!scheduler_context.to_reprioritize.empty()) { + const std::pair to_reprioritize = scheduler_context.to_reprioritize.back(); + scheduler_context.to_reprioritize.pop_back(); + scheduler_context.action_count.fetch_sub(1); + + debug_printf("[Scheduler] Reprioritizing thread %d to %d\n", to_reprioritize.first->id, to_reprioritize.second); + running_thread_queue.remove(to_reprioritize.first); + to_reprioritize.first->priority = to_reprioritize.second; + running_thread_queue.push(to_reprioritize.first); + } +} + +void handle_scheduler_notifications() { + std::lock_guard lock{scheduler_context.mutex}; + int32_t notify_count = scheduler_context.notify_count.exchange(0); + if (notify_count) { + debug_printf("Received %d notifications\n", notify_count); + scheduler_context.action_count.fetch_sub(notify_count); + } +} + +void swap_running_thread(thread_queue_t& running_thread_queue, OSThread*& cur_running_thread) { + OSThread* new_running_thread = running_thread_queue.top(); + if (cur_running_thread != new_running_thread) { + if (cur_running_thread && cur_running_thread->state == OSThreadState::RUNNING) { + debug_printf("[Scheduler] Switching execution from thread %d (%d) to thread %d (%d)\n", + cur_running_thread->id, cur_running_thread->priority, + new_running_thread->id, new_running_thread->priority); + Multilibultra::pause_thread_impl(cur_running_thread); + } else { + debug_printf("[Scheduler] Switching execution to thread %d (%d)\n", new_running_thread->id, new_running_thread->priority); + } + Multilibultra::resume_thread_impl(new_running_thread); + cur_running_thread = new_running_thread; + } else if (cur_running_thread && cur_running_thread->state != OSThreadState::RUNNING) { + Multilibultra::resume_thread_impl(cur_running_thread); + } +} + +void scheduler_func() { + thread_queue_t running_thread_queue{}; + OSThread* cur_running_thread = nullptr; + + while (true) { + OSThread* old_running_thread = cur_running_thread; + scheduler_context.action_count.wait(0); + + std::lock_guard lock{scheduler_context.premption_mutex}; + + // Handle notifications + handle_scheduler_notifications(); + + // Handle stopping threads + handle_thread_stopping(running_thread_queue); + + // Handle cleaning up threads + handle_thread_cleanup(running_thread_queue); + + // Handle queueing threads to run + handle_thread_queueing(running_thread_queue); + + // Handle threads that have changed priority + handle_thread_reprioritization(running_thread_queue); + + // Determine which thread to run, stopping the current running thread if necessary + swap_running_thread(running_thread_queue, cur_running_thread); + + std::this_thread::yield(); + if (old_running_thread != cur_running_thread && old_running_thread && cur_running_thread) { + debug_printf("[Scheduler] Swapped from Thread %d (%d) to Thread %d (%d)\n", + old_running_thread->id, old_running_thread->priority, cur_running_thread->id, cur_running_thread->priority); + } + } +} + +extern "C" void do_yield() { + std::this_thread::yield(); +} + +namespace Multilibultra { + +void init_scheduler() { + scheduler_context.can_preempt = true; + std::thread scheduler_thread{scheduler_func}; + scheduler_thread.detach(); +} + +void schedule_running_thread(OSThread *t) { + debug_printf("[Scheduler] Queuing Thread %d to be scheduled\n", t->id); + std::lock_guard lock{scheduler_context.mutex}; + scheduler_context.to_schedule.push_back(t); + scheduler_context.action_count.fetch_add(1); + scheduler_context.action_count.notify_all(); +} + +void swap_to_thread(RDRAM_ARG OSThread *to) { + OSThread *self = TO_PTR(OSThread, Multilibultra::this_thread()); + debug_printf("[Scheduler] Scheduling swap from thread %d to %d\n", self->id, to->id); + { + std::lock_guard lock{scheduler_context.mutex}; + scheduler_context.to_schedule.push_back(to); + Multilibultra::set_self_paused(PASS_RDRAM1); + scheduler_context.action_count.fetch_add(1); + scheduler_context.action_count.notify_all(); + } + Multilibultra::wait_for_resumed(PASS_RDRAM1); +} + +void reprioritize_thread(OSThread *t, OSPri pri) { + debug_printf("[Scheduler] Adjusting Thread %d priority to %d\n", t->id, pri); + std::lock_guard lock{scheduler_context.mutex}; + scheduler_context.to_reprioritize.emplace_back(t, pri); + scheduler_context.action_count.fetch_add(1); + scheduler_context.action_count.notify_all(); +} + +void pause_self(RDRAM_ARG1) { + OSThread *self = TO_PTR(OSThread, Multilibultra::this_thread()); + debug_printf("[Scheduler] Thread %d pausing itself\n", self->id); + { + std::lock_guard lock{scheduler_context.mutex}; + Multilibultra::set_self_paused(PASS_RDRAM1); + scheduler_context.to_stop.push_back(self); + scheduler_context.action_count.fetch_add(1); + scheduler_context.action_count.notify_all(); + } + Multilibultra::wait_for_resumed(PASS_RDRAM1); +} + +void stop_thread(OSThread *t) { + debug_printf("[Scheduler] Queuing Thread %d to be stopped\n", t->id); + { + std::lock_guard lock{scheduler_context.mutex}; + scheduler_context.to_stop.push_back(t); + scheduler_context.action_count.fetch_add(1); + scheduler_context.action_count.notify_all(); + } + Multilibultra::pause_thread_impl(t); +} + +void cleanup_thread(OSThread *t) { + std::lock_guard lock{scheduler_context.mutex}; + scheduler_context.to_cleanup.push_back(t); + scheduler_context.action_count.fetch_add(1); + scheduler_context.action_count.notify_all(); +} + +void disable_preemption() { + scheduler_context.premption_mutex.lock(); + scheduler_context.can_preempt = false; +} + +void enable_preemption() { + scheduler_context.can_preempt = true; + scheduler_context.premption_mutex.unlock(); +} + +// lock's constructor is called first, so can_preempt is set after locking +preemption_guard::preemption_guard() : lock{scheduler_context.premption_mutex} { + scheduler_context.can_preempt = false; +} + +// lock's destructor is called last, so can_preempt is set before unlocking +preemption_guard::~preemption_guard() { + scheduler_context.can_preempt = true; +} + +void notify_scheduler() { + std::lock_guard lock{scheduler_context.mutex}; + scheduler_context.notify_count.fetch_add(1); + scheduler_context.action_count.fetch_add(1); + scheduler_context.action_count.notify_all(); +} + +} diff --git a/test/portultra/task_pthreads.cpp b/test/portultra/task_pthreads.cpp new file mode 100644 index 0000000..667f022 --- /dev/null +++ b/test/portultra/task_pthreads.cpp @@ -0,0 +1,60 @@ +#ifndef _WIN32 + +// #include +// #include +// #include + +#include +#include +#include + +#include "ultra64.h" +#include "multilibultra.hpp" + +constexpr int pause_thread_signum = SIGUSR1; + +// void cleanup_current_thread(OSThread *t) { +// debug_printf("Thread cleanup %d\n", t->id); + +// // delete t->context; +// } + +void sig_handler(int signum, siginfo_t *info, void *context) { + if (signum == pause_thread_signum) { + OSThread *t = Multilibultra::this_thread(); + + debug_printf("[Sig] Thread %d paused\n", t->id); + + // Wait until the thread is marked as running again + t->context->running.wait(false); + + debug_printf("[Sig] Thread %d resumed\n", t->id); + } +} + +void Multilibultra::native_init(void) { + // Set up a signal handler to capture pause signals + struct sigaction sigact; + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = SA_SIGINFO | SA_RESTART; + sigact.sa_sigaction = sig_handler; + + sigaction(pause_thread_signum, &sigact, nullptr); +} + +void Multilibultra::native_thread_init(OSThread *t) { + debug_printf("[Native] Init thread %d\n", t->id); +} + +void Multilibultra::pause_thread_native_impl(OSThread *t) { + debug_printf("[Native] Pause thread %d\n", t->id); + // Send a pause signal to the thread, which will trigger it to wait on its pause barrier in the signal handler + pthread_kill(t->context->host_thread.native_handle(), pause_thread_signum); +} + +void Multilibultra::resume_thread_native_impl(UNUSED OSThread *t) { + debug_printf("[Native] Resume thread %d\n", t->id); + // Nothing to do here +} + +#endif \ No newline at end of file diff --git a/test/portultra/task_win32.cpp b/test/portultra/task_win32.cpp new file mode 100644 index 0000000..833024d --- /dev/null +++ b/test/portultra/task_win32.cpp @@ -0,0 +1,32 @@ +#include + +#include "ultra64.h" +#include "multilibultra.hpp" + +extern "C" unsigned int sleep(unsigned int seconds) { + Sleep(seconds * 1000); + return 0; +} + +void Multilibultra::native_init(void) { +} + +void Multilibultra::native_thread_init(OSThread *t) { + debug_printf("[Native] Init thread %d\n", t->id); +} + +void Multilibultra::pause_thread_native_impl(OSThread *t) { + debug_printf("[Native] Pause thread %d\n", t->id); + // Pause the thread via the win32 API + SuspendThread(t->context->host_thread.native_handle()); + // Perform a synchronous action to ensure that the thread is suspended + // see: https://devblogs.microsoft.com/oldnewthing/20150205-00/?p=44743 + CONTEXT threadContext; + GetThreadContext(t->context->host_thread.native_handle(), &threadContext); +} + +void Multilibultra::resume_thread_native_impl(UNUSED OSThread *t) { + debug_printf("[Native] Resume thread %d\n", t->id); + // Resume the thread + ResumeThread(t->context->host_thread.native_handle()); +} diff --git a/test/portultra/threads.cpp b/test/portultra/threads.cpp new file mode 100644 index 0000000..63b45b6 --- /dev/null +++ b/test/portultra/threads.cpp @@ -0,0 +1,143 @@ +#include +#include + +#include "ultra64.h" +#include "multilibultra.hpp" + +extern "C" void bootproc(); + +thread_local bool is_main_thread = false; +thread_local PTR(OSThread) thread_self = NULLPTR; + +void Multilibultra::set_main_thread() { + is_main_thread = true; +} + +#if 0 +int main(int argc, char** argv) { + Multilibultra::set_main_thread(); + + bootproc(); +} +#endif + +#if 1 +void run_thread_function(uint8_t* rdram, uint32_t addr, uint32_t sp, uint32_t arg); +#else +#define run_thread_function(func, sp, arg) func(arg) +#endif + +static void _thread_func(RDRAM_ARG PTR(OSThread) self_, PTR(thread_func_t) entrypoint, PTR(void) arg) { + OSThread *self = TO_PTR(OSThread, self_); + debug_printf("[Thread] Thread created: %d\n", self->id); + thread_self = self_; + + // Perform any necessary native thread initialization. + Multilibultra::native_thread_init(self); + + // Set initialized to false to indicate that this thread can be started. + self->context->initialized.store(true); + self->context->initialized.notify_all(); + + debug_printf("[Thread] Thread waiting to be started: %d\n", self->id); + + // Wait until the thread is marked as running. + Multilibultra::set_self_paused(PASS_RDRAM1); + Multilibultra::wait_for_resumed(PASS_RDRAM1); + + debug_printf("[Thread] Thread started: %d\n", self->id); + + // Run the thread's function with the provided argument. + run_thread_function(PASS_RDRAM entrypoint, self->sp, arg); + + // Dispose of this thread after it completes. + Multilibultra::cleanup_thread(self); +} + +extern "C" void osStartThread(RDRAM_ARG PTR(OSThread) t) { + debug_printf("[os] Start Thread %d\n", TO_PTR(OSThread, t)->id); + + // Wait until the thread is initialized to indicate that it's ready to be started. + TO_PTR(OSThread, t)->context->initialized.wait(false); + + debug_printf("[os] Thread %d is ready to be started\n", TO_PTR(OSThread, t)->id); + + if (thread_self && (TO_PTR(OSThread, t)->priority > TO_PTR(OSThread, thread_self)->priority)) { + Multilibultra::swap_to_thread(PASS_RDRAM TO_PTR(OSThread, t)); + } else { + Multilibultra::schedule_running_thread(TO_PTR(OSThread, t)); + } + + // The main thread "becomes" the first thread started, so join on it and exit after it completes. + if (is_main_thread) { + TO_PTR(OSThread, t)->context->host_thread.join(); + std::exit(EXIT_SUCCESS); + } +} + +extern "C" void osCreateThread(RDRAM_ARG PTR(OSThread) t_, OSId id, PTR(thread_func_t) entrypoint, PTR(void) arg, PTR(void) sp, OSPri pri) { + debug_printf("[os] Create Thread %d\n", id); + OSThread *t = TO_PTR(OSThread, t_); + + t->next = NULLPTR; + t->priority = pri; + t->id = id; + t->state = OSThreadState::PAUSED; + t->sp = sp; + + // Spawn a new thread, which will immediately pause itself and wait until it's been started. + t->context = new UltraThreadContext{}; + t->context->initialized.store(false); + t->context->running.store(false); + + t->context->host_thread = std::thread{_thread_func, PASS_RDRAM t_, entrypoint, arg}; +} + +extern "C" void osSetThreadPri(RDRAM_ARG PTR(OSThread) t, OSPri pri) { + if (t == NULLPTR) { + t = thread_self; + } + bool pause_self = false; + if (pri > TO_PTR(OSThread, thread_self)->priority) { + pause_self = true; + Multilibultra::set_self_paused(PASS_RDRAM1); + } else if (t == thread_self && pri < TO_PTR(OSThread, thread_self)->priority) { + pause_self = true; + Multilibultra::set_self_paused(PASS_RDRAM1); + } + Multilibultra::reprioritize_thread(TO_PTR(OSThread, t), pri); + if (pause_self) { + Multilibultra::wait_for_resumed(PASS_RDRAM1); + } +} + +// TODO yield thread, need a stable priority queue in the scheduler + +void Multilibultra::set_self_paused(RDRAM_ARG1) { + debug_printf("[Thread] Thread pausing itself: %d\n", TO_PTR(OSThread, thread_self)->id); + TO_PTR(OSThread, thread_self)->state = OSThreadState::PAUSED; + TO_PTR(OSThread, thread_self)->context->running.store(false); + TO_PTR(OSThread, thread_self)->context->running.notify_all(); +} + +void Multilibultra::wait_for_resumed(RDRAM_ARG1) { + TO_PTR(OSThread, thread_self)->context->running.wait(false); +} + +void Multilibultra::pause_thread_impl(OSThread* t) { + t->state = OSThreadState::PREEMPTED; + t->context->running.store(false); + t->context->running.notify_all(); + Multilibultra::pause_thread_native_impl(t); +} + +void Multilibultra::resume_thread_impl(OSThread *t) { + t->state = OSThreadState::RUNNING; + t->context->running.store(true); + t->context->running.notify_all(); + Multilibultra::resume_thread_native_impl(t); +} + +PTR(OSThread) Multilibultra::this_thread() { + return thread_self; +} diff --git a/test/portultra/ultra64.h b/test/portultra/ultra64.h new file mode 100644 index 0000000..fb444d5 --- /dev/null +++ b/test/portultra/ultra64.h @@ -0,0 +1,133 @@ +#ifndef __ULTRA64_MULTILIBULTRA_H__ +#define __ULTRA64_MULTILIBULTRA_H__ + +#include +#include "platform_specific.h" + +#ifdef __cplusplus +#include +#endif + +#ifdef __GNUC__ +#define UNUSED __attribute__((unused)) +#define ALIGNED(x) __attribute__((aligned(x))) +#else +#define UNUSED +#define ALIGNED(x) +#endif + +typedef int64_t s64; +typedef uint64_t u64; +typedef int32_t s32; +typedef uint32_t u32; +typedef int16_t s16; +typedef uint16_t u16; +typedef int8_t s8; +typedef uint8_t u8; + +#define PTR(x) uint32_t +#define RDRAM_ARG uint8_t *rdram, +#define RDRAM_ARG1 uint8_t *rdram +#define PASS_RDRAM rdram, +#define PASS_RDRAM1 rdram +#define TO_PTR(type, var) ((type*)(&rdram[var & 0x3FFFFFF])) +#ifdef __cplusplus +#define NULLPTR (PTR(void))0 +#endif + +#ifndef NULL +#define NULL (PTR(void) 0) +#endif + +#define OS_MESG_NOBLOCK 0 +#define OS_MESG_BLOCK 1 + +typedef s32 OSPri; +typedef s32 OSId; + +///////////// +// Structs // +///////////// + +typedef struct UltraThreadContext UltraThreadContext; + +typedef enum { + RUNNING, + PAUSED, + PREEMPTED +} OSThreadState; + +typedef struct OSThread_t { + PTR(struct OSThread_t) next; // Next thread in the given queue + OSPri priority; + uint32_t pad1; + uint32_t pad2; + uint16_t flags; // These two are swapped to reflect rdram byteswapping + uint16_t state; + OSId id; + int32_t pad3; + UltraThreadContext* context; // An actual pointer regardless of platform + uint32_t sp; +} OSThread; + +typedef u32 OSEvent; +typedef PTR(void) OSMesg; + +// This union holds C++ members along with a padding array. Those members are guarded by an ifdef for C++ +// so that they don't cause compilation errors in C. The padding array reserves the necessary space to +// hold the atomic members in C and a static assert is used to ensure that the union is large enough. +// typedef union UltraQueueContext { +// u64 pad[1]; +// #ifdef __cplusplus +// struct { +// } atomics; +// // Construct pad instead of the atomics, which get constructed in-place in osCreateMesgQueue +// UltraQueueContext() : pad{} {} +// #endif +// } UltraQueueContext; + +// #ifdef __cplusplus +// static_assert(sizeof(UltraQueueContext::pad) == sizeof(UltraQueueContext), +// "UltraQueueContext does not have enough padding to hold C++ members!"); +// #endif + +typedef struct OSMesgQueue { + PTR(OSThread) blocked_on_recv; /* Linked list of threads blocked on receiving from this queue */ + PTR(OSThread) blocked_on_send; /* Linked list of threads blocked on sending to this queue */ + s32 validCount; /* Number of messages in the queue */ + s32 first; /* Index of the first message in the ring buffer */ + s32 msgCount; /* Size of message buffer */ + PTR(OSMesg) msg; /* Pointer to circular buffer to store messages */ +} OSMesgQueue; + +/////////////// +// Functions // +/////////////// + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void osInitialize(void); + +typedef void (thread_func_t)(PTR(void)); + +void osCreateThread(RDRAM_ARG PTR(OSThread) t, OSId id, PTR(thread_func_t) entry, PTR(void) arg, PTR(void) sp, OSPri p); +void osStartThread(RDRAM_ARG PTR(OSThread) t); +void osSetThreadPri(RDRAM_ARG PTR(OSThread) t, OSPri pri); + +s32 MQ_GET_COUNT(RDRAM_ARG PTR(OSMesgQueue)); +s32 MQ_IS_EMPTY(RDRAM_ARG PTR(OSMesgQueue)); +s32 MQ_IS_FULL(RDRAM_ARG PTR(OSMesgQueue)); + +void osCreateMesgQueue(RDRAM_ARG PTR(OSMesgQueue), PTR(OSMesg), s32); +s32 osSendMesg(RDRAM_ARG PTR(OSMesgQueue), OSMesg, s32); +s32 osJamMesg(RDRAM_ARG PTR(OSMesgQueue), OSMesg, s32); +s32 osRecvMesg(RDRAM_ARG PTR(OSMesgQueue), PTR(OSMesg), s32); +void osSetEventMesg(RDRAM_ARG OSEvent, PTR(OSMesgQueue), OSMesg); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/test/src/ai.cpp b/test/src/ai.cpp new file mode 100644 index 0000000..f3a8343 --- /dev/null +++ b/test/src/ai.cpp @@ -0,0 +1,17 @@ +#include "recomp.h" + +extern "C" void osAiSetFrequency_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osAiSetNextBuffer_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osAiGetLength_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osAiGetStatus_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} \ No newline at end of file diff --git a/test/src/cont.cpp b/test/src/cont.cpp new file mode 100644 index 0000000..bf0d309 --- /dev/null +++ b/test/src/cont.cpp @@ -0,0 +1,25 @@ +#include "recomp.h" + +extern "C" void osContInit_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osContStartReadData_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osContGetReadData_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osMotorInit_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osMotorStart_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osMotorStop_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} diff --git a/test/src/dp.cpp b/test/src/dp.cpp new file mode 100644 index 0000000..bb7bb1d --- /dev/null +++ b/test/src/dp.cpp @@ -0,0 +1,5 @@ +#include "recomp.h" + +extern "C" void osDpSetNextBuffer_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} diff --git a/test/src/eep.cpp b/test/src/eep.cpp new file mode 100644 index 0000000..7c509da --- /dev/null +++ b/test/src/eep.cpp @@ -0,0 +1,21 @@ +#include "recomp.h" + +extern "C" void osEepromProbe_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osEepromWrite_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osEepromLongWrite_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osEepromRead_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osEepromLongRead_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} diff --git a/test/src/misc_ultra.cpp b/test/src/misc_ultra.cpp new file mode 100644 index 0000000..5115771 --- /dev/null +++ b/test/src/misc_ultra.cpp @@ -0,0 +1,65 @@ +#ifdef _WIN32 +#include +#endif + +#include +#include "recomp.h" + +extern uint64_t start_time; + + +extern "C" void osVirtualToPhysical_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + uint32_t virtual_addr = ctx->r4; + // TODO handle TLB mappings + ctx->r2 = virtual_addr - 0x80000000; +} + +extern "C" void osInvalDCache_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osInvalICache_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osWritebackDCache_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osWritebackDCacheAll_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +// Ticks per second +constexpr uint32_t counter_rate = 46'875'000; + +extern "C" void osGetCount_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + // TODO move this to a more appropriate place + int32_t count = 0; +#ifdef _WIN32 + SYSTEMTIME st; + FILETIME ft; + GetSystemTime(&st); + SystemTimeToFileTime(&st, &ft); + + uint64_t cur_time = ((uint64_t)ft.dwHighDateTime << 32) + ft.dwLowDateTime; + uint64_t delta_100ns = cur_time - start_time; + + count = (delta_100ns * counter_rate) / (1'000'000'000 / 100); +#endif + + ctx->r2 = count; + ; +} + +extern "C" void osSetIntMask_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void __osDisableInt_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void __osRestoreInt_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} diff --git a/test/src/pi.cpp b/test/src/pi.cpp new file mode 100644 index 0000000..65db5d9 --- /dev/null +++ b/test/src/pi.cpp @@ -0,0 +1,48 @@ +#include +#include "recomp.h" +#include "../portultra/ultra64.h" + +extern std::unique_ptr rom; +extern size_t rom_size; + +extern "C" void osCartRomInit_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osCreatePiManager_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +constexpr uint32_t rom_base = 0xB0000000; + +extern "C" void osPiStartDma_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + uint32_t mb = ctx->r4; + uint32_t pri = ctx->r5; + uint32_t direction = ctx->r6; + uint32_t devAddr = ctx->r7; + uint32_t dramAddr = MEM_W(0x10, ctx->r29); + uint32_t size = MEM_W(0x14, ctx->r29); + uint32_t mq_ = MEM_W(0x18, ctx->r29); + OSMesgQueue* mq = TO_PTR(OSMesgQueue, mq_); + + printf("[pi] DMA from 0x%08X into 0x%08X of size 0x%08X\n", devAddr, dramAddr, size); + + // TODO asynchronous transfer (will require preemption in the scheduler) + // TODO this won't handle unaligned DMA + memcpy(rdram + (dramAddr & 0x3FFFFFF), rom.get() + (devAddr | rom_base) - rom_base, size); + + // Send a message to the mq to indicate that the transfer completed + osSendMesg(rdram, mq_, 0, OS_MESG_NOBLOCK); +} + +extern "C" void osEPiStartDma_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osPiGetStatus_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { + ctx->r2 = 0; +} + +extern "C" void osPiRawStartDma_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { + ; +} \ No newline at end of file diff --git a/test/src/portultra_translation.cpp b/test/src/portultra_translation.cpp new file mode 100644 index 0000000..17d5fdb --- /dev/null +++ b/test/src/portultra_translation.cpp @@ -0,0 +1,41 @@ +#include "../portultra/ultra64.h" +#include "recomp.h" + +extern "C" void osInitialize_recomp(uint8_t * restrict rdram, recomp_context * restrict ctx) { + osInitialize(); +} + +extern "C" void osCreateThread_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + //printf("Creating thread 0x%08X\n", (uint32_t)ctx->r4); + osCreateThread(rdram, (uint32_t)ctx->r4, (OSId)ctx->r5, (uint32_t)ctx->r6, (uint32_t)ctx->r7, + (uint32_t)MEM_W(0x10, ctx->r29), (OSPri)MEM_W(0x14, ctx->r29)); +} + +extern "C" void osStartThread_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + //printf("Starting thread 0x%08X\n", (uint32_t)ctx->r4); + osStartThread(rdram, (uint32_t)ctx->r4); +} + +extern "C" void osSetThreadPri_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + osSetThreadPri(rdram, (uint32_t)ctx->r4, (OSPri)ctx->r5); +} + +extern "C" void osCreateMesgQueue_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + osCreateMesgQueue(rdram, (uint32_t)ctx->r4, (uint32_t)ctx->r5, (s32)ctx->r6); +} + +extern "C" void osRecvMesg_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ctx->r2 = osRecvMesg(rdram, (uint32_t)ctx->r4, (uint32_t)ctx->r5, (s32)ctx->r6); +} + +extern "C" void osSendMesg_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ctx->r2 = osSendMesg(rdram, (uint32_t)ctx->r4, (OSMesg)ctx->r5, (s32)ctx->r6); +} + +extern "C" void osJamMesg_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ctx->r2 = osJamMesg(rdram, (uint32_t)ctx->r4, (OSMesg)ctx->r5, (s32)ctx->r6); +} + +extern "C" void osSetEventMesg_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + osSetEventMesg(rdram, (OSEvent)ctx->r4, (uint32_t)ctx->r5, (OSMesg)ctx->r6); +} diff --git a/test/src/recomp.cpp b/test/src/recomp.cpp new file mode 100644 index 0000000..2e5a61e --- /dev/null +++ b/test/src/recomp.cpp @@ -0,0 +1,169 @@ +#ifdef _WIN32 +#include +#endif +#include +#include +#include +#include +#include +#include +#include "recomp.h" +#include "../portultra/multilibultra.hpp" + +#ifdef _MSC_VER +inline uint32_t byteswap(uint32_t val) { + return _byteswap_ulong(val); +} +#else +constexpr uint32_t byteswap(uint32_t val) { + return __builtin_bswap32(val); +} +#endif + +void test_func(uint8_t* restrict rdram, recomp_context* restrict ctx) { + printf("in test_func\n"); + exit(EXIT_FAILURE); +} + +extern std::pair funcs[]; +extern const size_t num_funcs; + +std::unordered_map func_map{}; + +extern "C" recomp_func_t* get_function(uint32_t addr) { + auto func_find = func_map.find(addr); + if (func_find == func_map.end()) { + fprintf(stderr, "Failed to find function at 0x%08X\n", addr); + std::exit(EXIT_FAILURE); + } + return func_find->second; +} + +extern "C" void bzero(uint8_t* restrict rdram, recomp_context* restrict ctx) { + uint32_t start_addr = ctx->r4; + uint32_t size = ctx->r5; + + for (uint32_t i = 0; i < size; i++) { + MEM_B(start_addr, i) = 0; + } +} + +extern "C" void switch_error(const char* func, uint32_t vram, uint32_t jtbl) { + printf("Switch-case out of bounds in %s at 0x%08X for jump table at 0x%08X\n", func, vram, jtbl); + exit(EXIT_FAILURE); +} + +extern "C" void do_break(uint32_t vram) { + printf("Encountered break at original vram 0x%08X\n", vram); + exit(EXIT_FAILURE); +} + +void run_thread_function(uint8_t* rdram, uint32_t addr, uint32_t sp, uint32_t arg) { + recomp_context ctx{}; + ctx.r29 = sp; + recomp_func_t* func = get_function(addr); + func(rdram, &ctx); +} + +extern "C" void game_init(uint8_t* restrict rdram, recomp_context* restrict ctx); + +std::unique_ptr rom; +size_t rom_size; + +uint64_t start_time; + +int main(int argc, char **argv) { + if (argc != 2) { + printf("Usage: %s [baserom]\n", argv[0]); + exit(EXIT_SUCCESS); + } + + { + std::basic_ifstream rom_file{ argv[1], std::ios::binary }; + + size_t iobuf_size = 0x100000; + std::unique_ptr iobuf = std::make_unique(iobuf_size); + rom_file.rdbuf()->pubsetbuf(iobuf.get(), iobuf_size); + + if (!rom_file) { + fprintf(stderr, "Failed to open rom: %s\n", argv[1]); + exit(EXIT_FAILURE); + } + + rom_file.seekg(0, std::ios::end); + rom_size = rom_file.tellg(); + rom_file.seekg(0, std::ios::beg); + + rom = std::make_unique(rom_size); + + rom_file.read(rom.get(), rom_size); + } + + // Byteswap the rom + for (size_t rom_addr = 0; rom_addr < rom_size; rom_addr += 4) { + uint32_t word = *reinterpret_cast(rom.get() + rom_addr); + word = byteswap(word); + *reinterpret_cast(rom.get() + rom_addr) = word; + } + + // Get entrypoint from ROM + // TODO fix this for other IPL3 versions + uint32_t entrypoint = *reinterpret_cast(rom.get() + 0x8); + + // Allocate rdram_buffer + std::unique_ptr rdram_buffer = std::make_unique(8 * 1024 * 1024); + std::memset(rdram_buffer.get(), 0, 8 * 1024 * 1024); + recomp_context context{}; + + // Initial 1MB DMA + std::copy_n(rom.get() + 0x1000, 0x100000, rdram_buffer.get() + entrypoint - 0x80000000); + + // Initialize function address map + for (size_t i = 0; i < num_funcs; i++) { + func_map[funcs[i].first] = funcs[i].second; + } + + // TODO move this to a more appropriate place +#ifdef _WIN32 + { + SYSTEMTIME st; + FILETIME ft; + GetSystemTime(&st); + SystemTimeToFileTime(&st, &ft); + + start_time = ((uint64_t)ft.dwHighDateTime << 32) + ft.dwLowDateTime; + } +#endif + + // Set up stack pointer + context.r29 = 0x803FFFF0u; + + // Initialize variables normally set by IPL3 + constexpr uint32_t osTvType = 0x80000300; + constexpr uint32_t osRomType = 0x80000304; + constexpr uint32_t osRomBase = 0x80000308; + constexpr uint32_t osResetType = 0x8000030c; + constexpr uint32_t osCicId = 0x80000310; + constexpr uint32_t osVersion = 0x80000314; + constexpr uint32_t osMemSize = 0x80000318; + constexpr uint32_t osAppNMIBuffer = 0x8000031c; + uint8_t *rdram = rdram_buffer.get(); + MEM_W(osTvType, 0) = 1; // NTSC + MEM_W(osRomBase, 0) = 0xB0000000u; // standard rom base + MEM_W(osResetType, 0) = 0; // cold reset + MEM_W(osMemSize, 0) = 8 * 1024 * 1024; // 8MB + + // Clear bss + // TODO run the entrypoint instead + memset(rdram_buffer.get() + 0XAF860, 0, 0xC00A0u - 0XAF860); + + printf("[Recomp] Starting\n"); + + Multilibultra::set_main_thread(); + + game_init(rdram_buffer.get(), &context); + + printf("[Recomp] Quitting\n"); + + return EXIT_SUCCESS; +} diff --git a/test/src/sp.cpp b/test/src/sp.cpp new file mode 100644 index 0000000..b5b40b7 --- /dev/null +++ b/test/src/sp.cpp @@ -0,0 +1,22 @@ +#include +#include "recomp.h" + +extern "C" void osSpTaskLoad_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osSpTaskStartGo_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + printf("[sp] osSpTaskStartGo(0x%08X)\n", (uint32_t)ctx->r4); +} + +extern "C" void osSpTaskYield_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osSpTaskYielded_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void __osSpSetPc_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} diff --git a/test/src/vi.cpp b/test/src/vi.cpp new file mode 100644 index 0000000..17c8921 --- /dev/null +++ b/test/src/vi.cpp @@ -0,0 +1,33 @@ +#include "recomp.h" + +extern "C" void osCreateViManager_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osViBlack_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osViSetSpecialFeatures_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osViGetCurrentFramebuffer_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osViGetNextFramebuffer_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osViSwapBuffer_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osViSetMode_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +} + +extern "C" void osViSetEvent_recomp(uint8_t* restrict rdram, recomp_context* restrict ctx) { + ; +}