From 5fc6f59821c43b105b915b2aff4c98f58803125e Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 2 Feb 2016 00:40:38 +0300 Subject: [PATCH 01/19] Partial commit: Preview --- .travis.yml | 2 +- README.md | 6 +- appveyor.yml | 2 +- rpcs3.sln | 243 +--- rpcs3/CMakeLists.txt | 19 +- rpcs3/D3D12GSRender.vcxproj | 5 - rpcs3/VKGSRender.vcxproj | 47 +- rpcs3/emucore.vcxproj | 637 +++++------ rpcs3/emucore.vcxproj.filters | 1987 +++++++++++++++------------------ rpcs3/rpcs3.vcxproj | 47 +- rpcs3/rpcs3.vcxproj.filters | 90 +- rpcs3/rpcs3qt/glviewer.cpp | 3 +- rpcs3/rpcs3qt/main.cpp | 2 + rpcs3/stdafx.cpp | 8 - rpcs3/stdafx.h | 172 +-- rpcs3/stdafx_d3d12.h | 6 +- rpcs3/stdafx_gui.h | 26 +- rpcs3_debug.props | 3 - rpcs3_default.props | 18 +- rpcs3_release.props | 1 - 20 files changed, 1327 insertions(+), 1997 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6bb94decea..703ff4cf34 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,7 +53,7 @@ before_install: fi; before_script: - - git submodule update --init asmjit 3rdparty/ffmpeg 3rdparty/pugixml 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers + - git submodule update --init asmjit 3rdparty/ffmpeg 3rdparty/pugixml 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers Utilities/yaml-cpp - mkdir build - cd build - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cmake ..; else cmake .. -DLLVM_DIR=/usr/local/opt/llvm36/lib/llvm-3.6/share/llvm/cmake; fi diff --git a/README.md b/README.md index 3d8efc9641..e6bdefceda 100644 --- a/README.md +++ b/README.md @@ -37,9 +37,11 @@ __Mac OSX__ ### Building -To initialize the repository don't forget to execute `git submodule update --init` to pull the wxWidgets source. +To initialize the repository don't forget to execute `git submodule update --init` to pull the submodules. * __Windows__: -Open the *.SLN* file, and press *Build* > *Clean Solution*, then *Build Solution*. *Rebuild* may not work correctly. +1) Open the *.SLN* file. +2) Build the projects in *__BUILD_BEFORE* folder: right-click on every project > *Build*. +3) Press *BUILD* > *Build Solution* or *Rebuild Solution*. * __Linux & Mac OSX__: If you want to build with LLVM, then LLVM 3.6.2 is required. `cd rpcs3 && cmake CMakeLists.txt && make && cd ../` then run with `cd bin && ./rpcs3`. diff --git a/appveyor.yml b/appveyor.yml index 65603cd216..8ce9345d6d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,7 +14,7 @@ branches: before_build: # until git for win 2.5 release with commit checkout - - git submodule update --init 3rdparty/ffmpeg 3rdparty/pugixml asmjit rsx_program_decompiler 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers + - git submodule update --init 3rdparty/ffmpeg 3rdparty/pugixml asmjit 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers Utilities/yaml-cpp - 7z x wxWidgets.7z -aos -oC:\rpcs3\wxWidgets > null - 7z x zlib.7z -aos -oC:\rpcs3\ > null - if %configuration%==Release (cmake -G "Visual Studio 14 Win64" -DZLIB_ROOT=C:/rpcs3/zlib/) diff --git a/rpcs3.sln b/rpcs3.sln index 180ae13212..89f3bf4ee3 100644 --- a/rpcs3.sln +++ b/rpcs3.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 +VisualStudioVersion = 14.0.25123.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpcs3", "rpcs3\rpcs3.vcxproj", "{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}" ProjectSection(ProjectDependencies) = postProject @@ -161,11 +161,6 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "asmjit", "asmjit", "{E2A982F2-4B1A-48B1-8D77-A17A589C58D7}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "emucore", "rpcs3\emucore.vcxproj", "{C4A10229-4712-4BD2-B63E-50D93C67A038}" - ProjectSection(ProjectDependencies) = postProject - {8BC303AB-25BE-4276-8E57-73F171B2D672} = {8BC303AB-25BE-4276-8E57-73F171B2D672} - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "llvm", "llvm", "{C8068CE9-D626-4FEA-BEE7-893F06A25BF3}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "llvm_build", "llvm_build\llvm_build.vcxproj", "{8BC303AB-25BE-4276-8E57-73F171B2D672}" EndProject @@ -209,8 +204,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "zlib", "zlib", "{F0C19EFA-E EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "3rdparty\libpng\projects\vstudio\zlib\zlib.vcxproj", "{60F89955-91C6-3A36-8000-13C592FEC2DF}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Vulkan", "Vulkan", "{09AD61F7-97FE-4FF8-8F7F-63FEA9B746F4}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Vulkan-build", "Vulkan\Vulkan-build\Vulkan-build.vcxproj", "{58B40697-B15E-429E-B325-D52C28AEBCBF}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glslang-build", "Vulkan\glslang-build\glslang-build.vcxproj", "{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}" @@ -221,17 +214,19 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VKGSRender", "rpcs3\VKGSRen {8F85B6CC-250F-4ACA-A617-E820A74E3E3C} = {8F85B6CC-250F-4ACA-A617-E820A74E3E3C} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PPULLVMRecompiler", "rpcs3\PPULLVMRecompiler.vcxproj", "{304A6E8B-A311-4EC5-8045-BFA8D08175CE}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webview", "wxWidgets\build\msw\wx_webview.vcxproj", "{A8E8442A-078A-5FC5-B495-8D71BA77EE6E}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "yaml-cpp", "yaml-cpp", "{DDF904CA-2771-441A-8629-5DF2EB922A79}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "__BUILD_BEFORE", "__BUILD_BEFORE", "{B0AC29FD-7B01-4B5E-9C8D-0A081E4C5668}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yaml-cpp", "Utilities\yaml-cpp.vcxproj", "{FDC361C5-7734-493B-8CFB-037308B35122}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug - LLVM|x64 = Debug - LLVM|x64 Debug - MemLeak|x64 = Debug - MemLeak|x64 Debug|x64 = Debug|x64 - DLL Debug|x64 = DLL Debug|x64 - DLL Release|x64 = DLL Release|x64 Release - LLVM|x64 = Release - LLVM|x64 Release|x64 = Release|x64 EndGlobalSection @@ -242,10 +237,6 @@ Global {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug|x64.ActiveCfg = Debug|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug|x64.Build.0 = Debug|x64 - {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.DLL Debug|x64.ActiveCfg = Debug|x64 - {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.DLL Debug|x64.Build.0 = Debug|x64 - {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.DLL Release|x64.ActiveCfg = Release|x64 - {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.DLL Release|x64.Build.0 = Release|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release|x64.ActiveCfg = Release|x64 @@ -256,10 +247,6 @@ Global {24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug - MemLeak|x64.Build.0 = Debug|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug|x64.ActiveCfg = Debug|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug|x64.Build.0 = Debug|x64 - {24C45343-FD20-5C92-81C1-35A2AE841E79}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {24C45343-FD20-5C92-81C1-35A2AE841E79}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {24C45343-FD20-5C92-81C1-35A2AE841E79}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {24C45343-FD20-5C92-81C1-35A2AE841E79}.DLL Release|x64.Build.0 = DLL Release|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Release - LLVM|x64.ActiveCfg = Release|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Release - LLVM|x64.Build.0 = Release|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Release|x64.ActiveCfg = Release|x64 @@ -270,10 +257,6 @@ Global {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Debug - MemLeak|x64.Build.0 = Debug|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Debug|x64.ActiveCfg = Debug|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Debug|x64.Build.0 = Debug|x64 - {A16D3832-0F42-57CE-8F48-50E06649ADE8}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {A16D3832-0F42-57CE-8F48-50E06649ADE8}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {A16D3832-0F42-57CE-8F48-50E06649ADE8}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {A16D3832-0F42-57CE-8F48-50E06649ADE8}.DLL Release|x64.Build.0 = DLL Release|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Release - LLVM|x64.ActiveCfg = Release|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Release - LLVM|x64.Build.0 = Release|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Release|x64.ActiveCfg = Release|x64 @@ -284,10 +267,6 @@ Global {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug - MemLeak|x64.Build.0 = Debug|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug|x64.ActiveCfg = Debug|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug|x64.Build.0 = Debug|x64 - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.DLL Release|x64.Build.0 = DLL Release|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release - LLVM|x64.ActiveCfg = Release|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release - LLVM|x64.Build.0 = Release|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release|x64.ActiveCfg = Release|x64 @@ -298,10 +277,6 @@ Global {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug - MemLeak|x64.Build.0 = Debug|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug|x64.ActiveCfg = Debug|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug|x64.Build.0 = Debug|x64 - {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.DLL Release|x64.Build.0 = DLL Release|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release - LLVM|x64.ActiveCfg = Release|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release - LLVM|x64.Build.0 = Release|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release|x64.ActiveCfg = Release|x64 @@ -312,10 +287,6 @@ Global {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Debug - MemLeak|x64.Build.0 = Debug|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Debug|x64.ActiveCfg = Debug|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Debug|x64.Build.0 = Debug|x64 - {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.DLL Release|x64.Build.0 = DLL Release|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Release - LLVM|x64.ActiveCfg = Release|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Release - LLVM|x64.Build.0 = Release|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Release|x64.ActiveCfg = Release|x64 @@ -326,10 +297,6 @@ Global {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Debug - MemLeak|x64.Build.0 = Debug|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Debug|x64.ActiveCfg = Debug|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Debug|x64.Build.0 = Debug|x64 - {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.DLL Release|x64.Build.0 = DLL Release|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Release - LLVM|x64.ActiveCfg = Release|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Release - LLVM|x64.Build.0 = Release|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Release|x64.ActiveCfg = Release|x64 @@ -338,13 +305,8 @@ Global {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - LLVM|x64.Build.0 = Debug|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - MemLeak|x64.Build.0 = Debug|x64 - {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - MemLeak|x64.Deploy.0 = Debug|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug|x64.ActiveCfg = Debug|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug|x64.Build.0 = Debug|x64 - {33CC42F9-7756-5587-863C-8D4461B7C5DD}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {33CC42F9-7756-5587-863C-8D4461B7C5DD}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {33CC42F9-7756-5587-863C-8D4461B7C5DD}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {33CC42F9-7756-5587-863C-8D4461B7C5DD}.DLL Release|x64.Build.0 = DLL Release|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Release - LLVM|x64.ActiveCfg = Release|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Release - LLVM|x64.Build.0 = Release|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Release|x64.ActiveCfg = Release|x64 @@ -355,10 +317,6 @@ Global {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Debug - MemLeak|x64.Build.0 = Debug|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Debug|x64.ActiveCfg = Debug|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Debug|x64.Build.0 = Debug|x64 - {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.DLL Release|x64.Build.0 = DLL Release|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Release - LLVM|x64.ActiveCfg = Release|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Release - LLVM|x64.Build.0 = Release|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Release|x64.ActiveCfg = Release|x64 @@ -369,10 +327,6 @@ Global {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Debug - MemLeak|x64.Build.0 = Debug|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Debug|x64.ActiveCfg = Debug|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Debug|x64.Build.0 = Debug|x64 - {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.DLL Release|x64.Build.0 = DLL Release|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Release - LLVM|x64.ActiveCfg = Release|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Release - LLVM|x64.Build.0 = Release|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Release|x64.ActiveCfg = Release|x64 @@ -383,10 +337,6 @@ Global {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Debug - MemLeak|x64.Build.0 = Debug|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Debug|x64.ActiveCfg = Debug|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Debug|x64.Build.0 = Debug|x64 - {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.DLL Release|x64.Build.0 = DLL Release|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Release - LLVM|x64.ActiveCfg = Release|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Release - LLVM|x64.Build.0 = Release|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Release|x64.ActiveCfg = Release|x64 @@ -397,10 +347,6 @@ Global {7FB0902D-8579-5DCE-B883-DAF66A885005}.Debug - MemLeak|x64.Build.0 = Debug|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Debug|x64.ActiveCfg = Debug|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Debug|x64.Build.0 = Debug|x64 - {7FB0902D-8579-5DCE-B883-DAF66A885005}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {7FB0902D-8579-5DCE-B883-DAF66A885005}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {7FB0902D-8579-5DCE-B883-DAF66A885005}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {7FB0902D-8579-5DCE-B883-DAF66A885005}.DLL Release|x64.Build.0 = DLL Release|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Release - LLVM|x64.ActiveCfg = Release|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Release - LLVM|x64.Build.0 = Release|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Release|x64.ActiveCfg = Release|x64 @@ -411,10 +357,6 @@ Global {A1A8355B-0988-528E-9CC2-B971D6266669}.Debug - MemLeak|x64.Build.0 = Debug|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Debug|x64.ActiveCfg = Debug|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Debug|x64.Build.0 = Debug|x64 - {A1A8355B-0988-528E-9CC2-B971D6266669}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {A1A8355B-0988-528E-9CC2-B971D6266669}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {A1A8355B-0988-528E-9CC2-B971D6266669}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {A1A8355B-0988-528E-9CC2-B971D6266669}.DLL Release|x64.Build.0 = DLL Release|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Release - LLVM|x64.ActiveCfg = Release|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Release - LLVM|x64.Build.0 = Release|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Release|x64.ActiveCfg = Release|x64 @@ -425,10 +367,6 @@ Global {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Debug - MemLeak|x64.Build.0 = Debug|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Debug|x64.ActiveCfg = Debug|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Debug|x64.Build.0 = Debug|x64 - {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.DLL Release|x64.Build.0 = DLL Release|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Release - LLVM|x64.ActiveCfg = Release|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Release - LLVM|x64.Build.0 = Release|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Release|x64.ActiveCfg = Release|x64 @@ -439,10 +377,6 @@ Global {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Debug - MemLeak|x64.Build.0 = Debug|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Debug|x64.ActiveCfg = Debug|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Debug|x64.Build.0 = Debug|x64 - {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.DLL Release|x64.Build.0 = DLL Release|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Release - LLVM|x64.ActiveCfg = Release|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Release - LLVM|x64.Build.0 = Release|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Release|x64.ActiveCfg = Release|x64 @@ -453,10 +387,6 @@ Global {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Debug - MemLeak|x64.Build.0 = Debug|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Debug|x64.ActiveCfg = Debug|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Debug|x64.Build.0 = Debug|x64 - {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.DLL Release|x64.Build.0 = DLL Release|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Release - LLVM|x64.ActiveCfg = Release|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Release - LLVM|x64.Build.0 = Release|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Release|x64.ActiveCfg = Release|x64 @@ -467,10 +397,6 @@ Global {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Debug - MemLeak|x64.Build.0 = Debug|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Debug|x64.ActiveCfg = Debug|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Debug|x64.Build.0 = Debug|x64 - {75596CE6-5AE7-55C9-B890-C07B0A657A83}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {75596CE6-5AE7-55C9-B890-C07B0A657A83}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {75596CE6-5AE7-55C9-B890-C07B0A657A83}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {75596CE6-5AE7-55C9-B890-C07B0A657A83}.DLL Release|x64.Build.0 = DLL Release|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Release - LLVM|x64.ActiveCfg = Release|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Release - LLVM|x64.Build.0 = Release|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Release|x64.ActiveCfg = Release|x64 @@ -481,10 +407,6 @@ Global {8B867186-A0B5-5479-B824-E176EDD27C40}.Debug - MemLeak|x64.Build.0 = Debug|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Debug|x64.ActiveCfg = Debug|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Debug|x64.Build.0 = Debug|x64 - {8B867186-A0B5-5479-B824-E176EDD27C40}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {8B867186-A0B5-5479-B824-E176EDD27C40}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {8B867186-A0B5-5479-B824-E176EDD27C40}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {8B867186-A0B5-5479-B824-E176EDD27C40}.DLL Release|x64.Build.0 = DLL Release|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Release - LLVM|x64.ActiveCfg = Release|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Release - LLVM|x64.Build.0 = Release|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Release|x64.ActiveCfg = Release|x64 @@ -495,10 +417,6 @@ Global {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Debug - MemLeak|x64.Build.0 = Debug|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Debug|x64.ActiveCfg = Debug|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Debug|x64.Build.0 = Debug|x64 - {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.DLL Release|x64.Build.0 = DLL Release|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Release - LLVM|x64.ActiveCfg = Release|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Release - LLVM|x64.Build.0 = Release|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Release|x64.ActiveCfg = Release|x64 @@ -509,10 +427,6 @@ Global {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Debug - MemLeak|x64.Build.0 = Debug|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Debug|x64.ActiveCfg = Debug|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Debug|x64.Build.0 = Debug|x64 - {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.DLL Release|x64.Build.0 = DLL Release|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Release - LLVM|x64.ActiveCfg = Release|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Release - LLVM|x64.Build.0 = Release|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Release|x64.ActiveCfg = Release|x64 @@ -523,10 +437,6 @@ Global {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Debug - MemLeak|x64.Build.0 = Debug|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Debug|x64.ActiveCfg = Debug|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Debug|x64.Build.0 = Debug|x64 - {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.DLL Release|x64.Build.0 = DLL Release|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Release - LLVM|x64.ActiveCfg = Release|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Release - LLVM|x64.Build.0 = Release|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Release|x64.ActiveCfg = Release|x64 @@ -537,10 +447,6 @@ Global {23E1C437-A951-5943-8639-A17F3CF2E606}.Debug - MemLeak|x64.Build.0 = Debug|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Debug|x64.ActiveCfg = Debug|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Debug|x64.Build.0 = Debug|x64 - {23E1C437-A951-5943-8639-A17F3CF2E606}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {23E1C437-A951-5943-8639-A17F3CF2E606}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {23E1C437-A951-5943-8639-A17F3CF2E606}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {23E1C437-A951-5943-8639-A17F3CF2E606}.DLL Release|x64.Build.0 = DLL Release|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Release - LLVM|x64.ActiveCfg = Release|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Release - LLVM|x64.Build.0 = Release|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Release|x64.ActiveCfg = Release|x64 @@ -551,10 +457,6 @@ Global {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Debug - MemLeak|x64.Build.0 = Debug|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Debug|x64.ActiveCfg = Debug|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Debug|x64.Build.0 = Debug|x64 - {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.DLL Release|x64.Build.0 = DLL Release|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release - LLVM|x64.ActiveCfg = Release|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release - LLVM|x64.Build.0 = Release|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release|x64.ActiveCfg = Release|x64 @@ -565,10 +467,6 @@ Global {AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Debug|x64.ActiveCfg = Debug|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Debug|x64.Build.0 = Debug|x64 - {AC40FF01-426E-4838-A317-66354CEFAE88}.DLL Debug|x64.ActiveCfg = Debug|x64 - {AC40FF01-426E-4838-A317-66354CEFAE88}.DLL Debug|x64.Build.0 = Debug|x64 - {AC40FF01-426E-4838-A317-66354CEFAE88}.DLL Release|x64.ActiveCfg = Release|x64 - {AC40FF01-426E-4838-A317-66354CEFAE88}.DLL Release|x64.Build.0 = Release|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Release|x64.ActiveCfg = Release|x64 @@ -579,24 +477,14 @@ Global {C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug|x64.ActiveCfg = Debug|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug|x64.Build.0 = Debug|x64 - {C4A10229-4712-4BD2-B63E-50D93C67A038}.DLL Debug|x64.ActiveCfg = Debug|x64 - {C4A10229-4712-4BD2-B63E-50D93C67A038}.DLL Debug|x64.Build.0 = Debug|x64 - {C4A10229-4712-4BD2-B63E-50D93C67A038}.DLL Release|x64.ActiveCfg = Release|x64 - {C4A10229-4712-4BD2-B63E-50D93C67A038}.DLL Release|x64.Build.0 = Release|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Release|x64.ActiveCfg = Release|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Release|x64.Build.0 = Release|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - LLVM|x64.ActiveCfg = Debug|x64 - {8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - LLVM|x64.Build.0 = Debug|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug|x64.ActiveCfg = Debug|x64 - {8BC303AB-25BE-4276-8E57-73F171B2D672}.DLL Debug|x64.ActiveCfg = Debug|x64 - {8BC303AB-25BE-4276-8E57-73F171B2D672}.DLL Debug|x64.Build.0 = Debug|x64 - {8BC303AB-25BE-4276-8E57-73F171B2D672}.DLL Release|x64.ActiveCfg = Release|x64 - {8BC303AB-25BE-4276-8E57-73F171B2D672}.DLL Release|x64.Build.0 = Release|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Release - LLVM|x64.ActiveCfg = Release|x64 - {8BC303AB-25BE-4276-8E57-73F171B2D672}.Release - LLVM|x64.Build.0 = Release|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Release|x64.ActiveCfg = Release|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug - LLVM|x64.Build.0 = Debug|x64 @@ -604,10 +492,6 @@ Global {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug - MemLeak|x64.Build.0 = Debug|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug|x64.ActiveCfg = Debug|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug|x64.Build.0 = Debug|x64 - {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.DLL Release|x64.Build.0 = DLL Release|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release - LLVM|x64.ActiveCfg = Release|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release - LLVM|x64.Build.0 = Release|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release|x64.ActiveCfg = Release|x64 @@ -618,10 +502,6 @@ Global {00D36322-6188-4A66-B514-3B3F183E998D}.Debug - MemLeak|x64.Build.0 = Debug|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Debug|x64.ActiveCfg = Debug|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Debug|x64.Build.0 = Debug|x64 - {00D36322-6188-4A66-B514-3B3F183E998D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {00D36322-6188-4A66-B514-3B3F183E998D}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {00D36322-6188-4A66-B514-3B3F183E998D}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {00D36322-6188-4A66-B514-3B3F183E998D}.DLL Release|x64.Build.0 = DLL Release|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Release - LLVM|x64.ActiveCfg = Release|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Release - LLVM|x64.Build.0 = Release|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Release|x64.ActiveCfg = Release|x64 @@ -632,24 +512,14 @@ Global {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Debug|x64.ActiveCfg = Debug|x64 {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Debug|x64.Build.0 = Debug|x64 - {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.DLL Debug|x64.ActiveCfg = Debug|x64 - {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.DLL Debug|x64.Build.0 = Debug|x64 - {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.DLL Release|x64.ActiveCfg = Release|x64 - {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.DLL Release|x64.Build.0 = Release|x64 {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Release|x64.ActiveCfg = Release|x64 {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Release|x64.Build.0 = Release|x64 {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug - LLVM|x64.ActiveCfg = Debug|x64 - {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug - LLVM|x64.Build.0 = Debug|x64 {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug|x64.ActiveCfg = Debug|x64 - {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.DLL Debug|x64.ActiveCfg = Debug|x64 - {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.DLL Debug|x64.Build.0 = Debug|x64 - {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.DLL Release|x64.ActiveCfg = Release|x64 - {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.DLL Release|x64.Build.0 = Release|x64 {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Release - LLVM|x64.ActiveCfg = Release|x64 - {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Release - LLVM|x64.Build.0 = Release|x64 {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Release|x64.ActiveCfg = Release|x64 {3384223A-6D97-4799-9862-359F85312892}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64 {3384223A-6D97-4799-9862-359F85312892}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64 @@ -657,10 +527,6 @@ Global {3384223A-6D97-4799-9862-359F85312892}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {3384223A-6D97-4799-9862-359F85312892}.Debug|x64.ActiveCfg = Debug|x64 {3384223A-6D97-4799-9862-359F85312892}.Debug|x64.Build.0 = Debug|x64 - {3384223A-6D97-4799-9862-359F85312892}.DLL Debug|x64.ActiveCfg = Debug|x64 - {3384223A-6D97-4799-9862-359F85312892}.DLL Debug|x64.Build.0 = Debug|x64 - {3384223A-6D97-4799-9862-359F85312892}.DLL Release|x64.ActiveCfg = Release|x64 - {3384223A-6D97-4799-9862-359F85312892}.DLL Release|x64.Build.0 = Release|x64 {3384223A-6D97-4799-9862-359F85312892}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {3384223A-6D97-4799-9862-359F85312892}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {3384223A-6D97-4799-9862-359F85312892}.Release|x64.ActiveCfg = Release|x64 @@ -671,10 +537,6 @@ Global {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Debug - MemLeak|x64.Build.0 = Debug|x64 {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Debug|x64.ActiveCfg = Debug|x64 {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Debug|x64.Build.0 = Debug|x64 - {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.DLL Debug|x64.ActiveCfg = Debug|x64 - {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.DLL Debug|x64.Build.0 = Debug|x64 - {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.DLL Release|x64.ActiveCfg = Release|x64 - {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.DLL Release|x64.Build.0 = Release|x64 {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Release - LLVM|x64.ActiveCfg = Release|x64 {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Release - LLVM|x64.Build.0 = Release|x64 {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Release|x64.ActiveCfg = Release|x64 @@ -685,10 +547,6 @@ Global {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Debug - MemLeak|x64.Build.0 = Debug|x64 {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Debug|x64.ActiveCfg = Debug|x64 {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Debug|x64.Build.0 = Debug|x64 - {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.DLL Debug|x64.ActiveCfg = Debug|x64 - {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.DLL Debug|x64.Build.0 = Debug|x64 - {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.DLL Release|x64.ActiveCfg = Release|x64 - {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.DLL Release|x64.Build.0 = Release|x64 {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Release - LLVM|x64.ActiveCfg = Release|x64 {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Release - LLVM|x64.Build.0 = Release|x64 {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Release|x64.ActiveCfg = Release|x64 @@ -699,10 +557,6 @@ Global {78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug|x64.ActiveCfg = Debug|x64 {78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug|x64.Build.0 = Debug|x64 - {78CB2F39-B809-4A06-8329-8C0A19119D3D}.DLL Debug|x64.ActiveCfg = Debug|x64 - {78CB2F39-B809-4A06-8329-8C0A19119D3D}.DLL Debug|x64.Build.0 = Debug|x64 - {78CB2F39-B809-4A06-8329-8C0A19119D3D}.DLL Release|x64.ActiveCfg = Release|x64 - {78CB2F39-B809-4A06-8329-8C0A19119D3D}.DLL Release|x64.Build.0 = Release|x64 {78CB2F39-B809-4A06-8329-8C0A19119D3D}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {78CB2F39-B809-4A06-8329-8C0A19119D3D}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {78CB2F39-B809-4A06-8329-8C0A19119D3D}.Release|x64.ActiveCfg = Release|x64 @@ -713,10 +567,6 @@ Global {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug|x64.ActiveCfg = Debug|x64 {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug|x64.Build.0 = Debug|x64 - {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.DLL Debug|x64.ActiveCfg = Debug|x64 - {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.DLL Debug|x64.Build.0 = Debug|x64 - {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.DLL Release|x64.ActiveCfg = Release|x64 - {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.DLL Release|x64.Build.0 = Release|x64 {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release|x64.ActiveCfg = Release|x64 @@ -727,10 +577,6 @@ Global {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug - MemLeak|x64.Build.0 = Debug Library|x64 {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.ActiveCfg = Debug Library|x64 {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.Build.0 = Debug Library|x64 - {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.DLL Debug|x64.ActiveCfg = Debug|x64 - {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.DLL Debug|x64.Build.0 = Debug|x64 - {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.DLL Release|x64.ActiveCfg = Release|x64 - {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.DLL Release|x64.Build.0 = Release|x64 {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release - LLVM|x64.ActiveCfg = Release Library|x64 {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release - LLVM|x64.Build.0 = Release Library|x64 {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.ActiveCfg = Release Library|x64 @@ -741,84 +587,50 @@ Global {60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug - MemLeak|x64.Build.0 = Debug Library|x64 {60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug|x64.ActiveCfg = Debug Library|x64 {60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug|x64.Build.0 = Debug Library|x64 - {60F89955-91C6-3A36-8000-13C592FEC2DF}.DLL Debug|x64.ActiveCfg = Debug Library|x64 - {60F89955-91C6-3A36-8000-13C592FEC2DF}.DLL Debug|x64.Build.0 = Debug Library|x64 - {60F89955-91C6-3A36-8000-13C592FEC2DF}.DLL Release|x64.ActiveCfg = Release Library|x64 - {60F89955-91C6-3A36-8000-13C592FEC2DF}.DLL Release|x64.Build.0 = Release Library|x64 {60F89955-91C6-3A36-8000-13C592FEC2DF}.Release - LLVM|x64.ActiveCfg = Release Library|x64 {60F89955-91C6-3A36-8000-13C592FEC2DF}.Release - LLVM|x64.Build.0 = Release Library|x64 {60F89955-91C6-3A36-8000-13C592FEC2DF}.Release|x64.ActiveCfg = Release Library|x64 {60F89955-91C6-3A36-8000-13C592FEC2DF}.Release|x64.Build.0 = Release Library|x64 {58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug - LLVM|x64.ActiveCfg = Debug|x64 - {58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug - LLVM|x64.Build.0 = Debug|x64 {58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 - {58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug - MemLeak|x64.Build.0 = Debug|x64 {58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug|x64.ActiveCfg = Debug|x64 - {58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug|x64.Build.0 = Debug|x64 - {58B40697-B15E-429E-B325-D52C28AEBCBF}.DLL Debug|x64.ActiveCfg = Debug|x64 - {58B40697-B15E-429E-B325-D52C28AEBCBF}.DLL Debug|x64.Build.0 = Debug|x64 - {58B40697-B15E-429E-B325-D52C28AEBCBF}.DLL Release|x64.ActiveCfg = Release|x64 - {58B40697-B15E-429E-B325-D52C28AEBCBF}.DLL Release|x64.Build.0 = Release|x64 {58B40697-B15E-429E-B325-D52C28AEBCBF}.Release - LLVM|x64.ActiveCfg = Release|x64 - {58B40697-B15E-429E-B325-D52C28AEBCBF}.Release - LLVM|x64.Build.0 = Release|x64 {58B40697-B15E-429E-B325-D52C28AEBCBF}.Release|x64.ActiveCfg = Release|x64 - {58B40697-B15E-429E-B325-D52C28AEBCBF}.Release|x64.Build.0 = Release|x64 {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug - LLVM|x64.ActiveCfg = Debug|x64 - {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug - LLVM|x64.Build.0 = Debug|x64 {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 - {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug - MemLeak|x64.Build.0 = Debug|x64 {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug|x64.ActiveCfg = Debug|x64 - {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug|x64.Build.0 = Debug|x64 - {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.DLL Debug|x64.ActiveCfg = Debug|x64 - {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.DLL Debug|x64.Build.0 = Debug|x64 - {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.DLL Release|x64.ActiveCfg = Release|x64 - {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.DLL Release|x64.Build.0 = Release|x64 {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Release - LLVM|x64.ActiveCfg = Release|x64 - {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Release - LLVM|x64.Build.0 = Release|x64 {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Release|x64.ActiveCfg = Release|x64 - {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Release|x64.Build.0 = Release|x64 - {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - LLVM|x64.ActiveCfg = Debug|x64 - {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - LLVM|x64.Build.0 = Debug|x64 - {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 - {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - MemLeak|x64.Build.0 = Debug|x64 + {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64 + {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64 + {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64 + {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug|x64.ActiveCfg = Debug|x64 {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug|x64.Build.0 = Debug|x64 - {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.DLL Debug|x64.ActiveCfg = Debug|x64 - {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.DLL Debug|x64.Build.0 = Debug|x64 - {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.DLL Release|x64.ActiveCfg = Release|x64 - {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.DLL Release|x64.Build.0 = Release|x64 - {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release - LLVM|x64.ActiveCfg = Release|x64 - {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release - LLVM|x64.Build.0 = Release|x64 + {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 + {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release|x64.ActiveCfg = Release|x64 {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release|x64.Build.0 = Release|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Debug|x64.ActiveCfg = Debug|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Debug|x64.Build.0 = Debug|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.DLL Debug|x64.ActiveCfg = Debug|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.DLL Debug|x64.Build.0 = Debug|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.DLL Release|x64.ActiveCfg = Release|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.DLL Release|x64.Build.0 = Release|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Release|x64.ActiveCfg = Release|x64 - {304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Release|x64.Build.0 = Release|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug - LLVM|x64.Build.0 = Debug|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug - MemLeak|x64.Build.0 = Debug|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug|x64.ActiveCfg = Debug|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug|x64.Build.0 = Debug|x64 - {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.DLL Debug|x64.ActiveCfg = DLL Debug|x64 - {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.DLL Debug|x64.Build.0 = DLL Debug|x64 - {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.DLL Release|x64.ActiveCfg = DLL Release|x64 - {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.DLL Release|x64.Build.0 = DLL Release|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Release - LLVM|x64.ActiveCfg = Release|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Release - LLVM|x64.Build.0 = Release|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Release|x64.ActiveCfg = Release|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Release|x64.Build.0 = Release|x64 + {FDC361C5-7734-493B-8CFB-037308B35122}.Debug - LLVM|x64.ActiveCfg = Debug|x64 + {FDC361C5-7734-493B-8CFB-037308B35122}.Debug - LLVM|x64.Build.0 = Debug|x64 + {FDC361C5-7734-493B-8CFB-037308B35122}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 + {FDC361C5-7734-493B-8CFB-037308B35122}.Debug - MemLeak|x64.Build.0 = Debug|x64 + {FDC361C5-7734-493B-8CFB-037308B35122}.Debug|x64.ActiveCfg = Debug|x64 + {FDC361C5-7734-493B-8CFB-037308B35122}.Debug|x64.Build.0 = Debug|x64 + {FDC361C5-7734-493B-8CFB-037308B35122}.Release - LLVM|x64.ActiveCfg = Release|x64 + {FDC361C5-7734-493B-8CFB-037308B35122}.Release - LLVM|x64.Build.0 = Release|x64 + {FDC361C5-7734-493B-8CFB-037308B35122}.Release|x64.ActiveCfg = Release|x64 + {FDC361C5-7734-493B-8CFB-037308B35122}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -848,8 +660,7 @@ Global {74827EBD-93DC-5110-BA95-3F2AB029B6B0} = {5812E712-6213-4372-B095-9EB9BAA1F2DF} {AC40FF01-426E-4838-A317-66354CEFAE88} = {E2A982F2-4B1A-48B1-8D77-A17A589C58D7} {C4A10229-4712-4BD2-B63E-50D93C67A038} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2} - {C8068CE9-D626-4FEA-BEE7-893F06A25BF3} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2} - {8BC303AB-25BE-4276-8E57-73F171B2D672} = {C8068CE9-D626-4FEA-BEE7-893F06A25BF3} + {8BC303AB-25BE-4276-8E57-73F171B2D672} = {B0AC29FD-7B01-4B5E-9C8D-0A081E4C5668} {01F4CE10-2CFB-41A8-B41F-E54337868A1D} = {5812E712-6213-4372-B095-9EB9BAA1F2DF} {00D36322-6188-4A66-B514-3B3F183E998D} = {5812E712-6213-4372-B095-9EB9BAA1F2DF} {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2} @@ -859,10 +670,10 @@ Global {30A05C4D-F5FD-421C-A864-17A64BDEAA75} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2} {D6973076-9317-4EF2-A0B8-B7A18AC0713E} = {A17D34F1-7E3E-4841-818D-3B7C6F5AF829} {60F89955-91C6-3A36-8000-13C592FEC2DF} = {F0C19EFA-EDD0-43F2-97C1-18E865E96B4E} - {58B40697-B15E-429E-B325-D52C28AEBCBF} = {09AD61F7-97FE-4FF8-8F7F-63FEA9B746F4} - {8F85B6CC-250F-4ACA-A617-E820A74E3E3C} = {09AD61F7-97FE-4FF8-8F7F-63FEA9B746F4} + {58B40697-B15E-429E-B325-D52C28AEBCBF} = {B0AC29FD-7B01-4B5E-9C8D-0A081E4C5668} + {8F85B6CC-250F-4ACA-A617-E820A74E3E3C} = {B0AC29FD-7B01-4B5E-9C8D-0A081E4C5668} {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2} - {304A6E8B-A311-4EC5-8045-BFA8D08175CE} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2} {A8E8442A-078A-5FC5-B495-8D71BA77EE6E} = {5812E712-6213-4372-B095-9EB9BAA1F2DF} + {FDC361C5-7734-493B-8CFB-037308B35122} = {DDF904CA-2771-441A-8629-5DF2EB922A79} EndGlobalSection EndGlobal diff --git a/rpcs3/CMakeLists.txt b/rpcs3/CMakeLists.txt index acb109e08e..a84ea142f2 100644 --- a/rpcs3/CMakeLists.txt +++ b/rpcs3/CMakeLists.txt @@ -112,8 +112,8 @@ ${LLVM_INCLUDE_DIRS} "${RPCS3_SRC_DIR}/Loader" "${RPCS3_SRC_DIR}/Crypto" "${RPCS3_SRC_DIR}/.." +"${RPCS3_SRC_DIR}/../Utilities/yaml-cpp/include" "${RPCS3_SRC_DIR}/../asmjit/src/asmjit" -"${RPCS3_SRC_DIR}/../3rdparty/glm" "${RPCS3_SRC_DIR}/../3rdparty/libpng" "${RPCS3_SRC_DIR}/../3rdparty/GSL/include" "${RPCS3_SRC_DIR}/../rsx_program_decompiler/rsx_decompiler" @@ -165,17 +165,10 @@ endforeach() file( GLOB_RECURSE RPCS3_SRC -"${RPCS3_SRC_DIR}/rpcs3.cpp" -"${RPCS3_SRC_DIR}/config.cpp" -"${RPCS3_SRC_DIR}/stb_image.cpp" -"${RPCS3_SRC_DIR}/../Utilities/GNU.cpp" -"${RPCS3_SRC_DIR}/Emu/*" -"${RPCS3_SRC_DIR}/Gui/*" -"${RPCS3_SRC_DIR}/Loader/*" -"${RPCS3_SRC_DIR}/Crypto/*" -"${RPCS3_SRC_DIR}/../Utilities/*" -"${RPCS3_SRC_DIR}/../rsx_program_decompiler/rsx_decompiler/*" -"${RPCS3_SRC_DIR}/../rsx_program_decompiler/shader_code/*" +"${RPCS3_SRC_DIR}/*.cpp" +"${RPCS3_SRC_DIR}/../Utilities/*.cpp" +"${RPCS3_SRC_DIR}/../rsx_program_decompiler/rsx_decompiler/*.cpp" +"${RPCS3_SRC_DIR}/../rsx_program_decompiler/shader_code/*.cpp" ) if(APPLE) @@ -224,4 +217,4 @@ else() endif() set_target_properties(rpcs3 PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${RPCS3_SRC_DIR}/stdafx.h") -cotire(rpcs3) \ No newline at end of file +cotire(rpcs3) diff --git a/rpcs3/D3D12GSRender.vcxproj b/rpcs3/D3D12GSRender.vcxproj index a610917e18..d1c7dcd40f 100644 --- a/rpcs3/D3D12GSRender.vcxproj +++ b/rpcs3/D3D12GSRender.vcxproj @@ -61,11 +61,6 @@ - - - true - - diff --git a/rpcs3/VKGSRender.vcxproj b/rpcs3/VKGSRender.vcxproj index f632daf5a2..023a74e01b 100644 --- a/rpcs3/VKGSRender.vcxproj +++ b/rpcs3/VKGSRender.vcxproj @@ -92,54 +92,9 @@ - - - - - Level3 - Disabled - _DEBUG;_LIB;%(PreprocessorDefinitions) - ..\Vulkan\Vulkan-LoaderAndValidationLayers\include;..\Vulkan\glslang\glslang\Public;%(AdditionalIncludeDirectories) - true - - - Windows - - - - - Level3 - - - MaxSpeed - true - true - NDEBUG;_LIB;%(PreprocessorDefinitions) - ..\Vulkan\Vulkan-LoaderAndValidationLayers\include;..\Vulkan\glslang\glslang\Public;%(AdditionalIncludeDirectories) - true - - - Windows - true - true - - - + ..\Vulkan\Vulkan-LoaderAndValidationLayers\include;..\Vulkan\glslang\glslang\Public;%(AdditionalIncludeDirectories) - true - - - - - ..\Vulkan\Vulkan-LoaderAndValidationLayers\include;..\Vulkan\glslang\glslang\Public;%(AdditionalIncludeDirectories) - true - - - - - ..\Vulkan\Vulkan-LoaderAndValidationLayers\include;..\Vulkan\glslang\glslang\Public;%(AdditionalIncludeDirectories) - true diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 1b29045549..0984a75514 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -58,103 +58,206 @@ - - - ..\llvm\include;..\llvm_build\include; - - - - - ..\llvm\include;..\llvm_build\include; - - - - - ..\llvm\include;..\llvm_build\include; - - - - - ..\llvm\include;..\llvm_build\include; - - - + + Use ..\llvm\include;..\llvm_build\include; - - - - - + + NotUsing + + + NotUsing + + - - - + + NotUsing + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - true - true - true - true - true - + - - true - true - true - true - true - + - - - - - - - - - - - - - - - - - + + NotUsing + + + NotUsing + + + NotUsing + NotUsing - + + NotUsing + - - + + NotUsing + @@ -217,168 +320,24 @@ - - + + - - - - - - - - - - - - - - - - - - - - - + + + $(IntDir)OldMemory.obj + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -393,14 +352,12 @@ - - - + - - + + @@ -410,7 +367,6 @@ - @@ -422,12 +378,12 @@ - - + + @@ -485,64 +441,127 @@ - - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - + - - - - - - - - - - - - - - - - - - + - - - - @@ -556,7 +575,6 @@ - @@ -569,110 +587,25 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + {d6973076-9317-4ef2-a0b8-b7a18ac0713e} + + + {ac40ff01-426e-4838-a317-66354cefae88} + + + {fdc361c5-7734-493b-8cfb-037308b35122} + + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index a8b1e1e296..78b9808d91 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -15,21 +15,9 @@ {ad58328f-b041-41e0-ad17-dbad7d193051} - - {d79d0db9-c3fc-480a-9979-175b82ffecf7} - - - {269371f1-45b7-4ca9-a4a7-376e6e62a8ba} - - - {4317ac27-38e4-4f8d-9bac-496f9b00f615} - {1df5b438-f263-4ff4-9b86-a9ea368f2106} - - {b26b6b08-a8ce-4bb5-8339-c5352a23ce96} - {28902cf4-4fa6-428b-ab94-6b410fd5077f} @@ -51,15 +39,6 @@ {fcac6852-b45f-4cf2-afee-cf56bcea14e5} - - {13d20086-2188-425a-9856-0440fe6f79f2} - - - {93b1cff1-0158-4327-a437-e9abcac8d724} - - - {1d9e6fc4-9a79-4329-a8b5-081e24822aaa} - {6674e2ab-90cd-47de-a852-d21643ab18c2} @@ -75,6 +54,21 @@ {2a8841dc-bce0-41bb-9fcb-5bf1f8dda213} + + {93b1cff1-0158-4327-a437-e9abcac8d724} + + + {1d9e6fc4-9a79-4329-a8b5-081e24822aaa} + + + {13d20086-2188-425a-9856-0440fe6f79f2} + + + {269371f1-45b7-4ca9-a4a7-376e6e62a8ba} + + + {4317ac27-38e4-4f8d-9bac-496f9b00f615} + @@ -104,251 +98,23 @@ Emu - - Emu\SysCalls - - - Emu\SysCalls - - - Emu\SysCalls - - - Emu\SysCalls - - - Emu\SysCalls - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\Io - - - Emu\Io - - - Emu\Io - - - Emu\FS - - - Emu\FS - - - Emu\FS - - - Emu\FS - - - Emu\FS - - - Emu\FS - - - Emu\FS - - - Emu\FS - - - Emu\FS - - - Emu\FS - - - Emu\FS - - - Emu\HDD - - Emu\CPU\Cell - - - Emu\CPU\Cell + Emu\Cell - Emu\CPU\Cell + Emu\Cell - Emu\CPU\Cell + Emu\Cell - Emu\CPU\Cell + Emu\Cell Emu\CPU - - Emu\CPU - - Emu\CPU\ARMv7 - - - Emu\Audio + Emu\ARMv7 Emu\Audio @@ -359,15 +125,6 @@ Emu\Memory - - Loader - - - Loader - - - Loader - Loader @@ -380,78 +137,9 @@ Utilities - - Emu\SysCalls - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - Utilities - - Emu\SysCalls\Modules - - - Emu\GPU\RSX - Emu\GPU\RSX @@ -464,242 +152,209 @@ Emu\GPU\RSX - - Emu\SysCalls\lv2 - Utilities - - Utilities - - - Utilities - Utilities Crypto - - Emu\SysCalls\Modules - - Emu\CPU\ARMv7 + Emu\ARMv7 - Emu\CPU\ARMv7 - - - Emu\CPU\ARMv7 + Emu\ARMv7 - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules Utilities - - Emu\SysCalls\Modules - - - Emu\CPU\ARMv7 - - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules - - - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules Emu\GPU\RSX - - Emu\SysCalls\Modules - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\Modules - - Emu\CPU\Cell + Emu\Cell - Emu\CPU\Cell + Emu\Cell Utilities @@ -713,185 +368,20 @@ Emu\GPU\RSX\Common - - Emu\SysCalls\lv2 - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - Utilities - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu - - - Utilities - Utilities - Emu\CPU\Cell + Emu\Cell - Emu\CPU\Cell + Emu\Cell - Emu\CPU\Cell - - - Utilities + Emu\Cell Emu\GPU\RSX\Common @@ -902,16 +392,6 @@ Emu\GPU\RSX\Null - - Utilities - - - - Emu - - - Emu - Emu\GPU\RSX @@ -933,6 +413,438 @@ Emu\GPU\RSX\Common + + Emu\Cell + + + Emu\Cell + + + Emu\ARMv7 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell + + + Emu\Cell + + + Emu\Cell + + + Emu\Cell\Modules + + + Emu\ARMv7 + + + Emu\ARMv7\Modules + + + Utilities + + + Emu + @@ -965,306 +877,78 @@ Emu - - Emu\SysCalls - - - Emu\SysCalls - - - Emu\SysCalls - - - Emu\SysCalls - - - Emu\SysCalls - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\Io - Emu\Io - - Emu\Io - Emu\Io - - Emu\Io - Emu\Io - - Emu\FS - - - Emu\FS - - - Emu\FS - - - Emu\FS - - - Emu\FS - - - Emu\FS - - - Emu\FS - - - Emu\FS - - - Emu\FS - - - Emu\FS - - - Emu\FS - - - Emu\HDD - - Emu\CPU\Cell - - - Emu\CPU\Cell + Emu\Cell - Emu\CPU\Cell - - - Emu\CPU\Cell - - - Emu\CPU\Cell + Emu\Cell - Emu\CPU\Cell - - - Emu\CPU\Cell + Emu\Cell - Emu\CPU\Cell + Emu\Cell - Emu\CPU\Cell + Emu\Cell - Emu\CPU\Cell + Emu\Cell - Emu\CPU\Cell + Emu\Cell - Emu\CPU\Cell + Emu\Cell - Emu\CPU\Cell + Emu\Cell - Emu\CPU\Cell + Emu\Cell - Emu\CPU\Cell + Emu\Cell - Emu\CPU\Cell - - - Emu\CPU + Emu\Cell Emu\CPU - - Emu\CPU - Emu\CPU - - Emu\CPU - - - Emu\CPU\ARMv7 - - Emu\CPU\ARMv7 + Emu\ARMv7 - Emu\CPU\ARMv7 + Emu\ARMv7 - Emu\CPU\ARMv7 + Emu\ARMv7 - Emu\CPU\ARMv7 + Emu\ARMv7 Emu\Audio - - Emu\Audio - Emu\Memory Emu\Memory - - Loader - - - Loader - - - Loader - Loader @@ -1283,84 +967,15 @@ Utilities - - Emu\SysCalls - Emu - - Emu\SysCalls - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\lv2 - Utilities Emu\GPU\RSX\Null - - Emu\GPU\RSX - Emu\GPU\RSX @@ -1382,9 +997,6 @@ Emu\GPU\RSX - - Emu\SysCalls\lv2 - Utilities @@ -1400,18 +1012,9 @@ Emu\Io\Null - - Utilities - - - Utilities - Utilities - - Utilities - Loader @@ -1433,15 +1036,9 @@ Header Files - - Emu\SysCalls - Crypto - - Emu\CPU\ARMv7 - Utilities @@ -1451,65 +1048,32 @@ Emu\Audio - - Emu\SysCalls\Modules - - - Emu\CPU\ARMv7 - - Emu\CPU\ARMv7 + Emu\ARMv7 - Emu\CPU\ARMv7\Modules - - - Emu\CPU\ARMv7 + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\CPU\Cell - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\Modules - - - Emu\CPU\Cell + Emu\ARMv7\Modules Utilities @@ -1526,215 +1090,170 @@ Emu\GPU\RSX\Common - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules + Emu\ARMv7\Modules - Emu\CPU\ARMv7\Modules - - - Emu\CPU\ARMv7\Modules - - - Emu\SysCalls\lv2 - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules + Emu\ARMv7\Modules Utilities - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules - Utilities - - Emu\SysCalls\lv2 - - Emu\CPU\Cell + Emu\Cell Utilities - Emu\CPU\Cell + Emu\Cell - Emu\CPU\Cell - - - Emu\SysCalls\Modules - - - Emu\SysCalls\Modules + Emu\Cell Utilities @@ -1751,22 +1270,9 @@ Utilities - - Utilities - - - Utilities - Utilities - - - Emu - - - Emu - Utilities @@ -1779,11 +1285,308 @@ Emu\GPU\RSX\Common - - Header Files - Emu\GPU\RSX\Common + + Utilities + + + Utilities + + + Loader + + + Emu\ARMv7 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\lv2 + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell\Modules + + + Emu\Cell + + + Emu\Cell + + + Emu\Cell + + + Emu\Cell + + + Emu\ARMv7 + + + Emu\ARMv7 + + + Emu\ARMv7\Modules + + + Header Files + + + Utilities + + + Emu + \ No newline at end of file diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 838e6867bd..21b2611725 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -87,11 +87,8 @@ %windir%\sysnative\cmd.exe /c "$(SolutionDir)\Utilities\git-version-gen.cmd" Updating git-version.h - - false - - ..\3rdparty\XAudio2_7;..\Vulkan\Vulkan-LoaderAndValidationLayers\include;..\Vulkan\glslang\glslang\Public;%(AdditionalIncludeDirectories) + ..\wxWidgets\include\msvc;..\wxWidgets\include;..\3rdparty\XAudio2_7;..\Vulkan\Vulkan-LoaderAndValidationLayers\include;..\Vulkan\glslang\glslang\Public;%(AdditionalIncludeDirectories) ..\Vulkan\glslang-build\SPIRV\Debug;..\Vulkan\glslang-build\OGLCompilersDLL\Debug;..\Vulkan\glslang-build\glslang\OSDependent\Windows\Debug;..\Vulkan\Vulkan-build\loader\Debug;..\Vulkan\glslang-build\glslang\Debug;..\3rdparty\OpenAL\libs\Win64;%(AdditionalLibraryDirectories) @@ -99,56 +96,60 @@ ..\Vulkan\glslang-build\SPIRV\Debug;..\Vulkan\glslang-build\OGLCompilersDLL\Debug;..\Vulkan\glslang-build\glslang\OSDependent\Windows\Debug;..\Vulkan\Vulkan-build\loader\Debug;..\Vulkan\glslang-build\glslang\Debug;..\3rdparty\OpenAL\libs\Win64;%(AdditionalLibraryDirectories) ..\Vulkan\glslang-build\SPIRV\Release;..\Vulkan\glslang-build\OGLCompilersDLL\Release;..\Vulkan\glslang-build\glslang\OSDependent\Windows\Release;..\Vulkan\Vulkan-build\loader\Release;..\Vulkan\glslang-build\glslang\Release;..\3rdparty\OpenAL\libs\Win64;%(AdditionalLibraryDirectories) ..\Vulkan\glslang-build\SPIRV\Release;..\Vulkan\glslang-build\OGLCompilersDLL\Release;..\Vulkan\glslang-build\glslang\OSDependent\Windows\Release;..\Vulkan\Vulkan-build\loader\Release;..\Vulkan\glslang-build\glslang\Release;..\3rdparty\OpenAL\libs\Win64;%(AdditionalLibraryDirectories) + ..\wxWidgets\lib\vc_x64_lib;%(AdditionalLibraryDirectories) + wxmsw31ud_adv.lib;wxbase31ud.lib;wxmsw31ud_core.lib;wxmsw31ud_aui.lib;wxtiffd.lib;wxjpegd.lib;wxpngd.lib;wxzlibd.lib;%(AdditionalDependencies) + wxmsw31ud_adv.lib;wxbase31ud.lib;wxmsw31ud_core.lib;wxmsw31ud_aui.lib;wxtiffd.lib;wxjpegd.lib;wxpngd.lib;wxzlibd.lib;%(AdditionalDependencies) + wxmsw31ud_adv.lib;wxbase31ud.lib;wxmsw31ud_core.lib;wxmsw31ud_aui.lib;wxtiffd.lib;wxjpegd.lib;wxpngd.lib;wxzlibd.lib;%(AdditionalDependencies) + wxmsw31u_adv.lib;wxbase31u.lib;wxmsw31u_core.lib;wxmsw31u_aui.lib;wxtiff.lib;wxjpeg.lib;wxpng.lib;wxzlib.lib;%(AdditionalDependencies) + wxmsw31u_adv.lib;wxbase31u.lib;wxmsw31u_core.lib;wxmsw31u_aui.lib;wxtiff.lib;wxjpeg.lib;wxpng.lib;wxzlib.lib;%(AdditionalDependencies) VKstatic.1.lib;glslang.lib;OSDependent.lib;OGLCompiler.lib;SPIRV.lib;%(AdditionalDependencies) + Windows + true + 0x10000 + false + true - - + + - - + + - + - - + + - - - - - - - @@ -156,7 +157,6 @@ - @@ -169,11 +169,13 @@ - - + + + + @@ -188,9 +190,6 @@ {30a05c4d-f5fd-421c-a864-17a64bdeaa75} - - {304a6e8b-a311-4ec5-8045-bfa8d08175ce} - {3ee5f075-b546-42c4-b6a8-e3ccef38b78d} diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index f4b9821357..efdd23231d 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -10,15 +10,15 @@ {6da015d7-ee99-4d6b-9588-42414b63ee0e} - - {ce9ce942-07dd-4cbc-9b76-0f754c363eda} - {b30572ce-b602-4c10-ad69-bd3f1c8a0144} {47155d25-741d-42c0-8850-f22aafca082a} + + {ce9ce942-07dd-4cbc-9b76-0f754c363eda} + @@ -30,12 +30,6 @@ Gui - - Gui - - - Gui - Gui @@ -45,12 +39,6 @@ Gui - - Gui - - - Gui - Gui @@ -78,18 +66,9 @@ Gui - - Io\XInput - - - Gui - Gui - - Gui - Gui @@ -105,6 +84,27 @@ Gui + + Gui + + + Io\Basic + + + Io\XInput + + + Io\Basic + + + Io\Basic + + + Gui + + + Gui + @@ -113,15 +113,9 @@ Utilities - - Gui - Gui - - Gui - Gui @@ -140,12 +134,6 @@ Gui - - Gui - - - Gui - rpcs3 @@ -176,33 +164,15 @@ Gui - - Io\Windows - - - Io\Windows - - - Io\Windows - - - Io\XInput - rpcs3 - - Gui - Gui Gui - - Gui - Gui @@ -222,6 +192,18 @@ Gui + + Io\XInput + + + Io\Basic + + + Io\Basic + + + Io\Basic + diff --git a/rpcs3/rpcs3qt/glviewer.cpp b/rpcs3/rpcs3qt/glviewer.cpp index f05546ef04..280b9a9fb0 100644 --- a/rpcs3/rpcs3qt/glviewer.cpp +++ b/rpcs3/rpcs3qt/glviewer.cpp @@ -1,3 +1,4 @@ +#ifdef QT_UI #include "glviewer.h" #include #include @@ -53,4 +54,4 @@ void GLViewer::cleanup() { m_renderer = 0; } } - +#endif diff --git a/rpcs3/rpcs3qt/main.cpp b/rpcs3/rpcs3qt/main.cpp index 5bc3c32cc9..97bd997c9b 100644 --- a/rpcs3/rpcs3qt/main.cpp +++ b/rpcs3/rpcs3qt/main.cpp @@ -1,5 +1,6 @@ // Qt5.2+ frontend implementation for rpcs3. Known to work on Windows, Linux, Mac // by Sacha Refshauge +#ifdef QT_UI #include #include #include "glviewer.h" @@ -14,3 +15,4 @@ int main(int argc, char *argv[]) return app.exec(); Q_UNUSED(engine) } +#endif diff --git a/rpcs3/stdafx.cpp b/rpcs3/stdafx.cpp index 1ce5959c46..fd4f341c7b 100644 --- a/rpcs3/stdafx.cpp +++ b/rpcs3/stdafx.cpp @@ -1,9 +1 @@ #include "stdafx.h" - -#ifdef _MSC_VER -#pragma comment(lib, "avcodec.lib") -#pragma comment(lib, "avformat.lib") -#pragma comment(lib, "avutil.lib") -#pragma comment(lib, "swresample.lib") -#pragma comment(lib, "swscale.lib") -#endif diff --git a/rpcs3/stdafx.h b/rpcs3/stdafx.h index 3ebd3f0a83..726d8025de 100644 --- a/rpcs3/stdafx.h +++ b/rpcs3/stdafx.h @@ -20,192 +20,46 @@ #pragma warning( disable : 4351 ) #include +#include #include -#include #include #include #include #include -#include +#include #include #include #include #include #include -#include -#include #include -#include #include #include -#include #include -#include #include -#include -#include -#include -#include #include +#include "Utilities/types.h" + #include +#define GSL_THROW_ON_CONTRACT_VIOLATION #include #include +#undef Expects +#undef Ensures + using namespace std::string_literals; using namespace std::chrono_literals; -#include "Utilities/GNU.h" - -#define CHECK_SIZE(type, size) static_assert(sizeof(type) == size, "Invalid " #type " type size") -#define CHECK_ALIGN(type, align) static_assert(alignof(type) == align, "Invalid " #type " type alignment") -#define CHECK_MAX_SIZE(type, size) static_assert(sizeof(type) <= size, #type " type size is too big") -#define CHECK_SIZE_ALIGN(type, size, align) CHECK_SIZE(type, size); CHECK_ALIGN(type, align) -#define CHECK_ASCENDING(constexpr_array) static_assert(::is_ascending(constexpr_array), #constexpr_array " is not sorted in ascending order") - -#ifndef _MSC_VER -using u128 = __uint128_t; -#endif - -CHECK_SIZE_ALIGN(u128, 16, 16); - -#include "Utilities/types.h" - -// bool type replacement for PS3/PSV -class b8 -{ - std::uint8_t m_value; - -public: - b8(const bool value) - : m_value(value) - { - } - - operator bool() const - { - return m_value != 0; - } -}; - -CHECK_SIZE_ALIGN(b8, 1, 1); - -template::value>> -inline T align(const T& value, u64 align) -{ - return static_cast((value + (align - 1)) & ~(align - 1)); -} - -// copy null-terminated string from std::string to char array with truncation -template -inline void strcpy_trunc(char(&dst)[N], const std::string& src) -{ - const std::size_t count = src.size() >= N ? N - 1 : src.size(); - std::memcpy(dst, src.c_str(), count); - dst[count] = '\0'; -} - -// copy null-terminated string from char array to char array with truncation -template -inline void strcpy_trunc(char(&dst)[N], const char(&src)[N2]) -{ - const std::size_t count = N2 >= N ? N - 1 : N2; - std::memcpy(dst, src, count); - dst[count] = '\0'; -} - -// returns true if all array elements are unique and sorted in ascending order -template -constexpr bool is_ascending(const T(&array)[N], std::size_t from = 0) -{ - return from >= N - 1 ? true : array[from] < array[from + 1] ? is_ascending(array, from + 1) : false; -} - -// get (first) array element equal to `value` or nullptr if not found -template -constexpr const T* static_search(const T(&array)[N], const T2& value, std::size_t from = 0) -{ - return from >= N ? nullptr : array[from] == value ? array + from : static_search(array, value, from + 1); -} - -// bool wrapper for restricting bool result conversions -struct explicit_bool_t -{ - const bool value; - - constexpr explicit_bool_t(bool value) - : value(value) - { - } - - explicit constexpr operator bool() const - { - return value; - } -}; - -template -struct triplet_t -{ - T1 first; - T2 second; - T3 third; - - constexpr bool operator ==(const T1& right) const - { - return first == right; - } -}; - -// return 32 bit sizeof() to avoid widening/narrowing conversions with size_t -#define SIZE_32(type) static_cast(sizeof(type)) - -// return 32 bit alignof() to avoid widening/narrowing conversions with size_t -#define ALIGN_32(type) static_cast(alignof(type)) - -// return 32 bit .size() for container -template -inline auto size32(const T& container) -> decltype(static_cast(container.size())) -{ - const auto size = container.size(); - return size >= 0 && size <= UINT32_MAX ? static_cast(size) : throw std::length_error(__FUNCTION__); -} - -// return 32 bit size for an array -template -constexpr u32 size32(const T(&)[Size]) -{ - return Size >= 0 && Size <= UINT32_MAX ? static_cast(Size) : throw std::length_error(__FUNCTION__); -} - -// return 32 bit offsetof() -#define OFFSET_32(type, x) static_cast(reinterpret_cast(&reinterpret_cast(reinterpret_cast(0ull)->x))) - -#define CONCATENATE_DETAIL(x, y) x ## y -#define CONCATENATE(x, y) CONCATENATE_DETAIL(x, y) - -#define SWITCH(expr) for (const auto& CONCATENATE(_switch_, __LINE__) = (expr);;) { const auto& _switch_ = CONCATENATE(_switch_, __LINE__); -#define CCASE(value) } constexpr std::remove_reference_t CONCATENATE(_value_, __LINE__) = value; if (_switch_ == CONCATENATE(_value_, __LINE__)) { -#define VCASE(value) } if (_switch_ == (value)) { -#define DEFAULT } /* must be the last one */ - -#define WRAP_EXPR(expr) [&]{ return expr; } -#define COPY_EXPR(expr) [=]{ return expr; } -#define PURE_EXPR(expr) [] { return expr; } -#define EXCEPTION(text, ...) fmt::exception(__FILE__, __LINE__, __FUNCTION__, text, ##__VA_ARGS__) -#define VM_CAST(value) vm::impl_cast(value, __FILE__, __LINE__, __FUNCTION__) -#define IS_INTEGRAL(t) (std::is_integral::value || std::is_same, u128>::value) -#define IS_INTEGER(t) (std::is_integral::value || std::is_enum::value || std::is_same, u128>::value) -#define IS_BINARY_COMPARABLE(t1, t2) (IS_INTEGER(t1) && IS_INTEGER(t2) && sizeof(t1) == sizeof(t2)) -#define CHECK_ASSERTION(expr) if (expr) {} else throw EXCEPTION("Assertion failed: %s", #expr) -#define CHECK_SUCCESS(expr) if (s32 _r = (expr)) throw EXCEPTION("Failure: %s -> 0x%x", #expr, _r) - -// Some forward declarations for the ID manager -template struct id_traits; +// Obsolete, throw fmt::exception directly. Use 'HERE' macro, if necessary. +#define EXCEPTION(format_str, ...) fmt::exception("%s(): " format_str HERE, __FUNCTION__, ##__VA_ARGS__) #define _PRGNAME_ "RPCS3" -#define _PRGVER_ "0.0.0.6" +#define _PRGVER_ "0.0.0.9" +#include "Utilities/Macro.h" +#include "Utilities/Platform.h" #include "Utilities/BEType.h" #include "Utilities/Atomic.h" #include "Utilities/StrFmt.h" diff --git a/rpcs3/stdafx_d3d12.h b/rpcs3/stdafx_d3d12.h index 19f78b3671..7943cd42b9 100644 --- a/rpcs3/stdafx_d3d12.h +++ b/rpcs3/stdafx_d3d12.h @@ -6,9 +6,9 @@ #include #include -#include "Emu\RSX\D3D12\D3D12Utils.h" -#include "Emu\RSX\D3D12\D3D12Formats.h" -#include "Emu\RSX\D3D12\D3D12GSRender.h" +#include "Emu/RSX/D3D12/D3D12Utils.h" +#include "Emu/RSX/D3D12/D3D12Formats.h" +#include "Emu/RSX/D3D12/D3D12GSRender.h" #pragma comment(lib, "d2d1") #pragma comment(lib, "DXGI") diff --git a/rpcs3/stdafx_gui.h b/rpcs3/stdafx_gui.h index 158a599ba9..249bf765c4 100644 --- a/rpcs3/stdafx_gui.h +++ b/rpcs3/stdafx_gui.h @@ -2,8 +2,6 @@ #include "restore_new.h" -#ifndef QT_UI - #ifdef _MSC_VER #pragma warning(push, 0) #else @@ -49,6 +47,28 @@ #ifdef _MSC_VER #pragma warning(pop) #endif -#endif #include "define_new_memleakdetect.h" + +namespace fmt +{ + // Convert a null-terminated wxString to a std::string encoded in utf8 + inline std::string ToUTF8(const wxString& right) + { + return static_cast(right.utf8_str()); + } + + // Convert a null-terminated std::string encoded in utf8 to a wxString + inline wxString FromUTF8(const std::string& right) + { + return wxString::FromUTF8(right.c_str()); + } +} + +#include "yaml-cpp/yaml.h" + +// Global GUI config +extern YAML::Node g_gui_cfg; + +// Save global GUI config +extern void save_gui_cfg(); diff --git a/rpcs3_debug.props b/rpcs3_debug.props index c631bcd1a6..feeca7c633 100644 --- a/rpcs3_debug.props +++ b/rpcs3_debug.props @@ -12,9 +12,6 @@ Disabled MultiThreadedDebugDLL - - wxmsw31ud_adv.lib;wxbase31ud.lib;wxmsw31ud_core.lib;wxmsw31ud_aui.lib;wxtiffd.lib;wxjpegd.lib;wxpngd.lib;wxzlibd.lib;%(AdditionalDependencies) - \ No newline at end of file diff --git a/rpcs3_default.props b/rpcs3_default.props index 676f2ede1a..18c630eb11 100644 --- a/rpcs3_default.props +++ b/rpcs3_default.props @@ -3,7 +3,7 @@ - .\;..\;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;..\wxWidgets\src\zlib;..\3rdparty\ffmpeg\WindowsInclude;..\3rdparty\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);..\3rdparty\minidx12\Include;..\3rdparty\glm;..\3rdparty\GSL\include;..\3rdparty\libpng;..\3rdparty\GL;..\3rdparty\stblib;..\3rdparty\OpenAL\include;..\3rdparty\pugixml\src + .\;..\;..\asmjit\src\asmjit;..\Utilities\yaml-cpp\include;..\wxWidgets\src\zlib;..\3rdparty\ffmpeg\WindowsInclude;..\3rdparty\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);..\3rdparty\minidx12\Include;..\3rdparty\GSL\include;..\3rdparty\libpng;..\3rdparty\GL;..\3rdparty\stblib;..\3rdparty\OpenAL\include;..\3rdparty\pugixml\src $(SolutionDir)lib\$(Configuration)-$(Platform)\ $(SolutionDir)lib\$(Configuration)-$(Platform)\;$(UniversalCRT_LibraryPath_x64);$(LibraryPath) $(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)\ @@ -17,20 +17,12 @@ Level3 false true - Use - $(Platform)\$(Configuration).pch - $(Platform)\$(Configuration).pdb - /FS %(AdditionalOptions) + NotUsing - Windows - true - odbc32.lib;odbccp32.lib;comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;rpcrt4.lib;libpng.lib;%(AdditionalDependencies) - true - ..\wxWidgets\lib\vc_x64_lib;..\3rdparty\ffmpeg\Windows\x86_64\lib;..\lib\ - 0x10000 - false + ws2_32.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib + ..\3rdparty\ffmpeg\Windows\x86_64\lib - \ No newline at end of file + diff --git a/rpcs3_release.props b/rpcs3_release.props index 73dcfcf2be..c8c37df680 100644 --- a/rpcs3_release.props +++ b/rpcs3_release.props @@ -12,7 +12,6 @@ MultiThreadedDLL - wxmsw31u_adv.lib;wxbase31u.lib;wxmsw31u_core.lib;wxmsw31u_aui.lib;wxtiff.lib;wxjpeg.lib;wxpng.lib;wxzlib.lib;%(AdditionalDependencies) true true From 250ce635271cf033606e4195c9288ad2cf37414f Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 2 Feb 2016 00:55:43 +0300 Subject: [PATCH 02/19] Partial commit: Utilities --- Utilities/Atomic.h | 1487 ++++++++++++++++----------- Utilities/AutoPause.cpp | 134 +-- Utilities/AutoPause.h | 30 +- Utilities/BEType.h | 453 ++++---- Utilities/BitField.h | 204 +++- Utilities/Config.cpp | 203 ++++ Utilities/Config.h | 523 ++++++++++ Utilities/File.cpp | 1319 +++++++++++++++--------- Utilities/File.h | 403 ++++---- Utilities/Log.cpp | 90 +- Utilities/Log.h | 68 +- Utilities/Macro.h | 79 ++ Utilities/{GNU.cpp => Platform.cpp} | 2 +- Utilities/{GNU.h => Platform.h} | 291 ++---- Utilities/Semaphore.cpp | 4 +- Utilities/Semaphore.h | 2 +- Utilities/SharedMutex.cpp | 103 -- Utilities/SharedMutex.h | 199 +++- Utilities/SleepQueue.cpp | 55 - Utilities/SleepQueue.h | 76 +- Utilities/StrFmt.cpp | 159 +-- Utilities/StrFmt.h | 244 ++--- Utilities/Thread.cpp | 212 ++-- Utilities/Thread.h | 536 +++------- Utilities/VirtualMemory.cpp | 12 +- Utilities/config_context.cpp | 172 ---- Utilities/config_context.h | 164 --- Utilities/convert.h | 279 ----- Utilities/rPlatform.cpp | 41 - Utilities/rPlatform.h | 40 - Utilities/rTime.cpp | 235 ----- Utilities/rTime.h | 102 -- Utilities/types.h | 672 +++++++++++- Utilities/wxWidgets/setup.h | 2 +- Utilities/yaml-cpp.vcxproj | 99 ++ Utilities/yaml-cpp.vcxproj.filters | 92 ++ Utilities/yaml-cpp.vcxproj.user | 4 + 37 files changed, 4783 insertions(+), 4007 deletions(-) create mode 100644 Utilities/Config.cpp create mode 100644 Utilities/Config.h create mode 100644 Utilities/Macro.h rename Utilities/{GNU.cpp => Platform.cpp} (98%) rename Utilities/{GNU.h => Platform.h} (58%) delete mode 100644 Utilities/SharedMutex.cpp delete mode 100644 Utilities/SleepQueue.cpp delete mode 100644 Utilities/config_context.cpp delete mode 100644 Utilities/config_context.h delete mode 100644 Utilities/convert.h delete mode 100644 Utilities/rPlatform.cpp delete mode 100644 Utilities/rPlatform.h delete mode 100644 Utilities/rTime.cpp delete mode 100644 Utilities/rTime.h create mode 100644 Utilities/yaml-cpp.vcxproj create mode 100644 Utilities/yaml-cpp.vcxproj.filters create mode 100644 Utilities/yaml-cpp.vcxproj.user diff --git a/Utilities/Atomic.h b/Utilities/Atomic.h index 49948c2744..b7591b556a 100644 --- a/Utilities/Atomic.h +++ b/Utilities/Atomic.h @@ -1,696 +1,979 @@ #pragma once -#if defined(__GNUG__) +#include "types.h" -template inline std::enable_if_t sync_val_compare_and_swap(volatile T* dest, T2 comp, T2 exch) +// Helper class, provides access to compiler-specific atomic intrinsics +template +struct atomic_storage { - return __sync_val_compare_and_swap(dest, comp, exch); -} + static_assert(sizeof(T) <= 16 && sizeof(T) == alignof(T), "atomic_storage<> error: invalid type"); -template inline std::enable_if_t sync_bool_compare_and_swap(volatile T* dest, T2 comp, T2 exch) -{ - return __sync_bool_compare_and_swap(dest, comp, exch); -} + /* First part: Non-MSVC intrinsics */ -template inline std::enable_if_t sync_lock_test_and_set(volatile T* dest, T2 value) -{ - return __sync_lock_test_and_set(dest, value); -} - -template inline std::enable_if_t sync_fetch_and_add(volatile T* dest, T2 value) -{ - return __sync_fetch_and_add(dest, value); -} - -template inline std::enable_if_t sync_fetch_and_sub(volatile T* dest, T2 value) -{ - return __sync_fetch_and_sub(dest, value); -} - -template inline std::enable_if_t sync_fetch_and_or(volatile T* dest, T2 value) -{ - return __sync_fetch_and_or(dest, value); -} - -template inline std::enable_if_t sync_fetch_and_and(volatile T* dest, T2 value) -{ - return __sync_fetch_and_and(dest, value); -} - -template inline std::enable_if_t sync_fetch_and_xor(volatile T* dest, T2 value) -{ - return __sync_fetch_and_xor(dest, value); -} - -#elif defined(_MSC_VER) - -// atomic compare and swap functions - -inline u8 sync_val_compare_and_swap(volatile u8* dest, u8 comp, u8 exch) -{ - return _InterlockedCompareExchange8((volatile char*)dest, exch, comp); -} - -inline u16 sync_val_compare_and_swap(volatile u16* dest, u16 comp, u16 exch) -{ - return _InterlockedCompareExchange16((volatile short*)dest, exch, comp); -} - -inline u32 sync_val_compare_and_swap(volatile u32* dest, u32 comp, u32 exch) -{ - return _InterlockedCompareExchange((volatile long*)dest, exch, comp); -} - -inline u64 sync_val_compare_and_swap(volatile u64* dest, u64 comp, u64 exch) -{ - return _InterlockedCompareExchange64((volatile long long*)dest, exch, comp); -} - -inline u128 sync_val_compare_and_swap(volatile u128* dest, u128 comp, u128 exch) -{ - _InterlockedCompareExchange128((volatile long long*)dest, exch.hi, exch.lo, (long long*)&comp); - return comp; -} - -inline bool sync_bool_compare_and_swap(volatile u8* dest, u8 comp, u8 exch) -{ - return (u8)_InterlockedCompareExchange8((volatile char*)dest, exch, comp) == comp; -} - -inline bool sync_bool_compare_and_swap(volatile u16* dest, u16 comp, u16 exch) -{ - return (u16)_InterlockedCompareExchange16((volatile short*)dest, exch, comp) == comp; -} - -inline bool sync_bool_compare_and_swap(volatile u32* dest, u32 comp, u32 exch) -{ - return (u32)_InterlockedCompareExchange((volatile long*)dest, exch, comp) == comp; -} - -inline bool sync_bool_compare_and_swap(volatile u64* dest, u64 comp, u64 exch) -{ - return (u64)_InterlockedCompareExchange64((volatile long long*)dest, exch, comp) == comp; -} - -inline bool sync_bool_compare_and_swap(volatile u128* dest, u128 comp, u128 exch) -{ - return _InterlockedCompareExchange128((volatile long long*)dest, exch.hi, exch.lo, (long long*)&comp) != 0; -} - -// atomic exchange functions - -inline u8 sync_lock_test_and_set(volatile u8* dest, u8 value) -{ - return _InterlockedExchange8((volatile char*)dest, value); -} - -inline u16 sync_lock_test_and_set(volatile u16* dest, u16 value) -{ - return _InterlockedExchange16((volatile short*)dest, value); -} - -inline u32 sync_lock_test_and_set(volatile u32* dest, u32 value) -{ - return _InterlockedExchange((volatile long*)dest, value); -} - -inline u64 sync_lock_test_and_set(volatile u64* dest, u64 value) -{ - return _InterlockedExchange64((volatile long long*)dest, value); -} - -inline u128 sync_lock_test_and_set(volatile u128* dest, u128 value) -{ - while (true) - { - u128 old; - old.lo = dest->lo; - old.hi = dest->hi; - - if (sync_bool_compare_and_swap(dest, old, value)) return old; - } -} - -// atomic add functions - -inline u8 sync_fetch_and_add(volatile u8* dest, u8 value) -{ - return _InterlockedExchangeAdd8((volatile char*)dest, value); -} - -inline u16 sync_fetch_and_add(volatile u16* dest, u16 value) -{ - return _InterlockedExchangeAdd16((volatile short*)dest, value); -} - -inline u32 sync_fetch_and_add(volatile u32* dest, u32 value) -{ - return _InterlockedExchangeAdd((volatile long*)dest, value); -} - -inline u64 sync_fetch_and_add(volatile u64* dest, u64 value) -{ - return _InterlockedExchangeAdd64((volatile long long*)dest, value); -} - -inline u128 sync_fetch_and_add(volatile u128* dest, u128 value) -{ - while (true) - { - u128 old; - old.lo = dest->lo; - old.hi = dest->hi; - - if (sync_bool_compare_and_swap(dest, old, old + value)) return old; - } -} - -// atomic sub functions - -inline u8 sync_fetch_and_sub(volatile u8* dest, u8 value) -{ - return _InterlockedExchangeAdd8((volatile char*)dest, -(char)value); -} - -inline u16 sync_fetch_and_sub(volatile u16* dest, u16 value) -{ - return _InterlockedExchangeAdd16((volatile short*)dest, -(short)value); -} - -inline u32 sync_fetch_and_sub(volatile u32* dest, u32 value) -{ - return _InterlockedExchangeAdd((volatile long*)dest, -(long)value); -} - -inline u64 sync_fetch_and_sub(volatile u64* dest, u64 value) -{ - return _InterlockedExchangeAdd64((volatile long long*)dest, -(long long)value); -} - -inline u128 sync_fetch_and_sub(volatile u128* dest, u128 value) -{ - while (true) - { - u128 old; - old.lo = dest->lo; - old.hi = dest->hi; - - if (sync_bool_compare_and_swap(dest, old, old - value)) return old; - } -} - -// atomic `bitwise or` functions - -inline u8 sync_fetch_and_or(volatile u8* dest, u8 value) -{ - return _InterlockedOr8((volatile char*)dest, value); -} - -inline u16 sync_fetch_and_or(volatile u16* dest, u16 value) -{ - return _InterlockedOr16((volatile short*)dest, value); -} - -inline u32 sync_fetch_and_or(volatile u32* dest, u32 value) -{ - return _InterlockedOr((volatile long*)dest, value); -} - -inline u64 sync_fetch_and_or(volatile u64* dest, u64 value) -{ - return _InterlockedOr64((volatile long long*)dest, value); -} - -inline u128 sync_fetch_and_or(volatile u128* dest, u128 value) -{ - while (true) - { - u128 old; - old.lo = dest->lo; - old.hi = dest->hi; - - if (sync_bool_compare_and_swap(dest, old, old | value)) return old; - } -} - -// atomic `bitwise and` functions - -inline u8 sync_fetch_and_and(volatile u8* dest, u8 value) -{ - return _InterlockedAnd8((volatile char*)dest, value); -} - -inline u16 sync_fetch_and_and(volatile u16* dest, u16 value) -{ - return _InterlockedAnd16((volatile short*)dest, value); -} - -inline u32 sync_fetch_and_and(volatile u32* dest, u32 value) -{ - return _InterlockedAnd((volatile long*)dest, value); -} - -inline u64 sync_fetch_and_and(volatile u64* dest, u64 value) -{ - return _InterlockedAnd64((volatile long long*)dest, value); -} - -inline u128 sync_fetch_and_and(volatile u128* dest, u128 value) -{ - while (true) - { - u128 old; - old.lo = dest->lo; - old.hi = dest->hi; - - if (sync_bool_compare_and_swap(dest, old, old & value)) return old; - } -} - -// atomic `bitwise xor` functions - -inline u8 sync_fetch_and_xor(volatile u8* dest, u8 value) -{ - return _InterlockedXor8((volatile char*)dest, value); -} - -inline u16 sync_fetch_and_xor(volatile u16* dest, u16 value) -{ - return _InterlockedXor16((volatile short*)dest, value); -} - -inline u32 sync_fetch_and_xor(volatile u32* dest, u32 value) -{ - return _InterlockedXor((volatile long*)dest, value); -} - -inline u64 sync_fetch_and_xor(volatile u64* dest, u64 value) -{ - return _InterlockedXor64((volatile long long*)dest, value); -} - -inline u128 sync_fetch_and_xor(volatile u128* dest, u128 value) -{ - while (true) - { - u128 old; - old.lo = dest->lo; - old.hi = dest->hi; - - if (sync_bool_compare_and_swap(dest, old, old ^ value)) return old; - } -} - -#endif /* _MSC_VER */ - -template struct atomic_storage -{ - static_assert(!Size, "Invalid atomic type"); -}; - -template struct atomic_storage -{ - using type = u8; -}; - -template struct atomic_storage -{ - using type = u16; -}; - -template struct atomic_storage -{ - using type = u32; -}; - -template struct atomic_storage -{ - using type = u64; -}; - -template struct atomic_storage -{ - using type = u128; -}; - -template using atomic_storage_t = typename atomic_storage::type; - -// atomic result wrapper; implements special behaviour for void result type -template struct atomic_op_result_t -{ - RT result; - - template atomic_op_result_t(T func, VT& var, Args&&... args) - : result(std::move(func(var, std::forward(args)...))) +#ifndef _MSC_VER + static inline bool compare_exchange(T& dest, T& comp, T exch) { + return __atomic_compare_exchange(&dest, &comp, &exch, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } - RT move() + static inline T load(const T& dest) { - return std::move(result); + T result; + __atomic_load(&dest, &result, __ATOMIC_SEQ_CST); + return result; + } + + static inline void store(T& dest, T value) + { + __atomic_store(&dest, &value, __ATOMIC_SEQ_CST); + } + + static inline T exchange(T& dest, T value) + { + T result; + __atomic_exchange(&dest, &value, &result, __ATOMIC_SEQ_CST); + return result; + } + + static inline T fetch_add(T& dest, T value) + { + return __atomic_fetch_add(&dest, value, __ATOMIC_SEQ_CST); + } + + static inline T add_fetch(T& dest, T value) + { + return __atomic_add_fetch(&dest, value, __ATOMIC_SEQ_CST); + } + + static inline T fetch_sub(T& dest, T value) + { + return __atomic_fetch_sub(&dest, value, __ATOMIC_SEQ_CST); + } + + static inline T sub_fetch(T& dest, T value) + { + return __atomic_sub_fetch(&dest, value, __ATOMIC_SEQ_CST); + } + + static inline T fetch_and(T& dest, T value) + { + return __atomic_fetch_and(&dest, value, __ATOMIC_SEQ_CST); + } + + static inline T and_fetch(T& dest, T value) + { + return __atomic_and_fetch(&dest, value, __ATOMIC_SEQ_CST); + } + + static inline T fetch_xor(T& dest, T value) + { + return __atomic_fetch_xor(&dest, value, __ATOMIC_SEQ_CST); + } + + static inline T xor_fetch(T& dest, T value) + { + return __atomic_xor_fetch(&dest, value, __ATOMIC_SEQ_CST); + } + + static inline T fetch_or(T& dest, T value) + { + return __atomic_fetch_or(&dest, value, __ATOMIC_SEQ_CST); + } + + static inline T or_fetch(T& dest, T value) + { + return __atomic_or_fetch(&dest, value, __ATOMIC_SEQ_CST); + } +#endif + + /* Second part: MSVC-specific */ + +#ifdef _MSC_VER + static inline T add_fetch(T& dest, T value) + { + return atomic_storage::fetch_add(dest, value) + value; + } + + static inline T fetch_sub(T& dest, T value) + { + return atomic_storage::fetch_add(dest, 0 - value); + } + + static inline T sub_fetch(T& dest, T value) + { + return atomic_storage::fetch_add(dest, 0 - value) - value; + } + + static inline T and_fetch(T& dest, T value) + { + return atomic_storage::fetch_and(dest, value) & value; + } + + static inline T or_fetch(T& dest, T value) + { + return atomic_storage::fetch_or(dest, value) | value; + } + + static inline T xor_fetch(T& dest, T value) + { + return atomic_storage::fetch_xor(dest, value) ^ value; + } +#endif + + /* Third part: fallbacks, may be hidden by subsequent atomic_storage<> specializations */ + + static inline T fetch_inc(T& dest) + { + return atomic_storage::fetch_add(dest, 1); + } + + static inline T inc_fetch(T& dest) + { + return atomic_storage::add_fetch(dest, 1); + } + + static inline T fetch_dec(T& dest) + { + return atomic_storage::fetch_sub(dest, 1); + } + + static inline T dec_fetch(T& dest) + { + return atomic_storage::sub_fetch(dest, 1); + } + + static inline bool bts(T& dest, uint bit) + { + const T mask = static_cast(1) << bit; + return (atomic_storage::fetch_or(dest, mask) & mask) != 0; + } + + static inline bool btr(T& dest, uint bit) + { + const T mask = static_cast(1) << bit; + return (atomic_storage::fetch_and(dest, ~mask) & mask) != 0; + } + + static inline bool btc(T& dest, uint bit) + { + const T mask = static_cast(1) << bit; + return (atomic_storage::fetch_xor(dest, mask) & mask) != 0; } }; -// void specialization: result is the initial value of the first arg -template struct atomic_op_result_t -{ - VT result; +/* The rest: ugly MSVC intrinsics + possibly __asm__ implementations (TODO) */ - template atomic_op_result_t(T func, VT& var, Args&&... args) - : result(var) +template +struct atomic_storage : atomic_storage +{ +#ifdef _MSC_VER + static inline bool compare_exchange(T& dest, T& comp, T exch) { - func(var, std::forward(args)...); + char v = *(char*)∁ + char r = _InterlockedCompareExchange8((volatile char*)&dest, (char&)exch, v); + comp = (T&)r; + return r == v; } - VT move() + static inline T load(const T& dest) { - return std::move(result); + char value = *(const volatile char*)&dest; + _ReadWriteBarrier(); + return (T&)value; + } + + static inline void store(T& dest, T value) + { + _InterlockedExchange8((volatile char*)&dest, (char&)value); + } + + static inline T exchange(T& dest, T value) + { + char r = _InterlockedExchange8((volatile char*)&dest, (char&)value); + return (T&)r; + } + + static inline T fetch_add(T& dest, T value) + { + char r = _InterlockedExchangeAdd8((volatile char*)&dest, (char&)value); + return (T&)r; + } + + static inline T fetch_and(T& dest, T value) + { + char r = _InterlockedAnd8((volatile char*)&dest, (char&)value); + return (T&)r; + } + + static inline T fetch_or(T& dest, T value) + { + char r = _InterlockedOr8((volatile char*)&dest, (char&)value); + return (T&)r; + } + + static inline T fetch_xor(T& dest, T value) + { + char r = _InterlockedXor8((volatile char*)&dest, (char&)value); + return (T&)r; + } +#endif +}; + +template +struct atomic_storage : atomic_storage +{ +#ifdef _MSC_VER + static inline bool compare_exchange(T& dest, T& comp, T exch) + { + short v = *(short*)∁ + short r = _InterlockedCompareExchange16((volatile short*)&dest, (short&)exch, v); + comp = (T&)r; + return r == v; + } + + static inline T load(const T& dest) + { + short value = *(const volatile short*)&dest; + _ReadWriteBarrier(); + return (T&)value; + } + + static inline void store(T& dest, T value) + { + _InterlockedExchange16((volatile short*)&dest, (short&)value); + } + + static inline T exchange(T& dest, T value) + { + short r = _InterlockedExchange16((volatile short*)&dest, (short&)value); + return (T&)r; + } + + static inline T fetch_add(T& dest, T value) + { + short r = _InterlockedExchangeAdd16((volatile short*)&dest, (short&)value); + return (T&)r; + } + + static inline T fetch_and(T& dest, T value) + { + short r = _InterlockedAnd16((volatile short*)&dest, (short&)value); + return (T&)r; + } + + static inline T fetch_or(T& dest, T value) + { + short r = _InterlockedOr16((volatile short*)&dest, (short&)value); + return (T&)r; + } + + static inline T fetch_xor(T& dest, T value) + { + short r = _InterlockedXor16((volatile short*)&dest, (short&)value); + return (T&)r; + } + + static inline T inc_fetch(T& dest) + { + short r = _InterlockedIncrement16((volatile short*)&dest); + return (T&)r; + } + + static inline T dec_fetch(T& dest) + { + short r = _InterlockedDecrement16((volatile short*)&dest); + return (T&)r; + } +#endif +}; + +template +struct atomic_storage : atomic_storage +{ +#ifdef _MSC_VER + static inline bool compare_exchange(T& dest, T& comp, T exch) + { + long v = *(long*)∁ + long r = _InterlockedCompareExchange((volatile long*)&dest, (long&)exch, v); + comp = (T&)r; + return r == v; + } + + static inline T load(const T& dest) + { + long value = *(const volatile long*)&dest; + _ReadWriteBarrier(); + return (T&)value; + } + + static inline void store(T& dest, T value) + { + _InterlockedExchange((volatile long*)&dest, (long&)value); + } + + static inline T exchange(T& dest, T value) + { + long r = _InterlockedExchange((volatile long*)&dest, (long&)value); + return (T&)r; + } + + static inline T fetch_add(T& dest, T value) + { + long r = _InterlockedExchangeAdd((volatile long*)&dest, (long&)value); + return (T&)r; + } + + static inline T fetch_and(T& dest, T value) + { + long r = _InterlockedAnd((volatile long*)&dest, (long&)value); + return (T&)r; + } + + static inline T fetch_or(T& dest, T value) + { + long r = _InterlockedOr((volatile long*)&dest, (long&)value); + return (T&)r; + } + + static inline T fetch_xor(T& dest, T value) + { + long r = _InterlockedXor((volatile long*)&dest, (long&)value); + return (T&)r; + } + + static inline T inc_fetch(T& dest) + { + long r = _InterlockedIncrement((volatile long*)&dest); + return (T&)r; + } + + static inline T dec_fetch(T& dest) + { + long r = _InterlockedDecrement((volatile long*)&dest); + return (T&)r; + } + + static inline bool bts(T& dest, uint bit) + { + return _interlockedbittestandset((volatile long*)&dest, bit) != 0; + } + + static inline bool btr(T& dest, uint bit) + { + return _interlockedbittestandreset((volatile long*)&dest, bit) != 0; + } +#endif +}; + +template +struct atomic_storage : atomic_storage +{ +#ifdef _MSC_VER + static inline bool compare_exchange(T& dest, T& comp, T exch) + { + llong v = *(llong*)∁ + llong r = _InterlockedCompareExchange64((volatile llong*)&dest, (llong&)exch, v); + comp = (T&)r; + return r == v; + } + + static inline T load(const T& dest) + { + llong value = *(const volatile llong*)&dest; + _ReadWriteBarrier(); + return (T&)value; + } + + static inline void store(T& dest, T value) + { + _InterlockedExchange64((volatile llong*)&dest, (llong&)value); + } + + static inline T exchange(T& dest, T value) + { + llong r = _InterlockedExchange64((volatile llong*)&dest, (llong&)value); + return (T&)r; + } + + static inline T fetch_add(T& dest, T value) + { + llong r = _InterlockedExchangeAdd64((volatile llong*)&dest, (llong&)value); + return (T&)r; + } + + static inline T fetch_and(T& dest, T value) + { + llong r = _InterlockedAnd64((volatile llong*)&dest, (llong&)value); + return (T&)r; + } + + static inline T fetch_or(T& dest, T value) + { + llong r = _InterlockedOr64((volatile llong*)&dest, (llong&)value); + return (T&)r; + } + + static inline T fetch_xor(T& dest, T value) + { + llong r = _InterlockedXor64((volatile llong*)&dest, (llong&)value); + return (T&)r; + } + + static inline T inc_fetch(T& dest) + { + llong r = _InterlockedIncrement64((volatile llong*)&dest); + return (T&)r; + } + + static inline T dec_fetch(T& dest) + { + llong r = _InterlockedDecrement64((volatile llong*)&dest); + return (T&)r; + } + + static inline bool bts(T& dest, uint bit) + { + return _interlockedbittestandset64((volatile llong*)&dest, bit) != 0; + } + + static inline bool btr(T& dest, uint bit) + { + return _interlockedbittestandreset64((volatile llong*)&dest, bit) != 0; + } +#endif +}; + +template +struct atomic_storage : atomic_storage +{ +#ifdef _MSC_VER + static inline bool compare_exchange(T& dest, T& comp, T exch) + { + llong* _exch = (llong*)&exch; + return _InterlockedCompareExchange128((volatile llong*)&dest, _exch[1], _exch[0], (llong*)&comp) != 0; + } + + static inline T load(const T& dest) + { + llong result[2]; + _InterlockedCompareExchange128((volatile llong*)&dest, 0, 0, result); + return *(T*)+result; + } + + static inline void store(T& dest, T value) + { + llong lo = *(llong*)&value; + llong hi = *((llong*)&value + 1); + llong cmp[2]{ *(volatile llong*)&dest, *((volatile llong*)&dest + 1) }; + while (!_InterlockedCompareExchange128((volatile llong*)&dest, hi, lo, cmp)); + } + + static inline T exchange(T& dest, T value) + { + llong lo = *(llong*)&value; + llong hi = *((llong*)&value + 1); + llong cmp[2]{ *(volatile llong*)&dest, *((volatile llong*)&dest + 1) }; + while (!_InterlockedCompareExchange128((volatile llong*)&dest, hi, lo, cmp)); + return *(T*)+cmp; + } +#endif +}; + +template +struct atomic_add +{ + auto operator()(T1& lhs, const T2& rhs) const + { + return lhs += rhs; } }; -// member function specialization -template struct atomic_op_result_t +template +struct atomic_add::value && std::is_convertible::value>> { - RT result; + static constexpr auto fetch_op = &atomic_storage::fetch_add; + static constexpr auto op_fetch = &atomic_storage::add_fetch; + static constexpr auto atomic_op = &atomic_storage::add_fetch; +}; - template atomic_op_result_t(RT(CT::*func)(FArgs...), VT& var, Args&&... args) - : result(std::move((var.*func)(std::forward(args)...))) +template +struct atomic_sub +{ + auto operator()(T1& lhs, const T2& rhs) const { - } - - RT move() - { - return std::move(result); + return lhs -= rhs; } }; -// member function void specialization -template struct atomic_op_result_t +template +struct atomic_sub::value && std::is_convertible::value>> { - VT result; + static constexpr auto fetch_op = &atomic_storage::fetch_sub; + static constexpr auto op_fetch = &atomic_storage::sub_fetch; + static constexpr auto atomic_op = &atomic_storage::sub_fetch; +}; - template atomic_op_result_t(void(CT::*func)(FArgs...), VT& var, Args&&... args) - : result(var) +template +struct atomic_pre_inc +{ + auto operator()(T& v) const { - (var.*func)(std::forward(args)...); + return ++v; + } +}; + +template +struct atomic_pre_inc::value>> +{ + static constexpr auto atomic_op = &atomic_storage::inc_fetch; +}; + +template +struct atomic_post_inc +{ + auto operator()(T& v) const + { + return v++; + } +}; + +template +struct atomic_post_inc::value>> +{ + static constexpr auto atomic_op = &atomic_storage::fetch_inc; +}; + +template +struct atomic_pre_dec +{ + auto operator()(T& v) const + { + return --v; + } +}; + +template +struct atomic_pre_dec::value>> +{ + static constexpr auto atomic_op = &atomic_storage::dec_fetch; +}; + +template +struct atomic_post_dec +{ + auto operator()(T& v) const + { + return v--; + } +}; + +template +struct atomic_post_dec::value>> +{ + static constexpr auto atomic_op = &atomic_storage::fetch_dec; +}; + +template +struct atomic_and +{ + auto operator()(T1& lhs, const T2& rhs) const + { + return lhs &= rhs; + } +}; + +template +struct atomic_and::value && std::is_convertible::value>> +{ + static constexpr auto fetch_op = &atomic_storage::fetch_and; + static constexpr auto op_fetch = &atomic_storage::and_fetch; + static constexpr auto atomic_op = &atomic_storage::and_fetch; +}; + +template +struct atomic_or +{ + auto operator()(T1& lhs, const T2& rhs) const + { + return lhs |= rhs; + } +}; + +template +struct atomic_or::value && std::is_convertible::value>> +{ + static constexpr auto fetch_op = &atomic_storage::fetch_or; + static constexpr auto op_fetch = &atomic_storage::or_fetch; + static constexpr auto atomic_op = &atomic_storage::or_fetch; +}; + +template +struct atomic_xor +{ + auto operator()(T1& lhs, const T2& rhs) const + { + return lhs ^= rhs; + } +}; + +template +struct atomic_xor::value && std::is_convertible::value>> +{ + static constexpr auto fetch_op = &atomic_storage::fetch_xor; + static constexpr auto op_fetch = &atomic_storage::xor_fetch; + static constexpr auto atomic_op = &atomic_storage::xor_fetch; +}; + +template +struct atomic_test_and_set +{ + bool operator()(T1& lhs, const T2& rhs) const + { + return lhs.test_and_set(rhs); + } +}; + +template +struct atomic_test_and_set::value && std::is_convertible::value>> +{ + static inline bool op(T1& lhs, const T2& rhs) + { + return (atomic_storage::fetch_or(lhs, rhs) & rhs) != 0; } - VT move() + static constexpr auto fetch_op = &op; + static constexpr auto op_fetch = &op; + static constexpr auto atomic_op = &op; +}; + +template +struct atomic_test_and_reset +{ + bool operator()(T1& lhs, const T2& rhs) const { - return std::move(result); + return lhs.test_and_reset(rhs); } }; +template +struct atomic_test_and_reset::value && std::is_convertible::value>> +{ + static inline bool op(T1& lhs, const T2& rhs) + { + return (atomic_storage::fetch_and(lhs, ~rhs) & rhs) != 0; + } + + static constexpr auto fetch_op = &op; + static constexpr auto op_fetch = &op; + static constexpr auto atomic_op = &op; +}; + +template +struct atomic_test_and_complement +{ + bool operator()(T1& lhs, const T2& rhs) const + { + return lhs.test_and_complement(rhs); + } +}; + +template +struct atomic_test_and_complement::value && std::is_convertible::value>> +{ + static inline bool op(T1& lhs, const T2& rhs) + { + return (atomic_storage::fetch_xor(lhs, rhs) & rhs) != 0; + } + + static constexpr auto fetch_op = &op; + static constexpr auto op_fetch = &op; + static constexpr auto atomic_op = &op; +}; + // Atomic type with lock-free and standard layout guarantees (and appropriate limitations) -template class atomic_t +template +class atomic_t { - using type = std::remove_cv_t; - using stype = atomic_storage_t; - using storage = atomic_storage; + using type = typename std::remove_cv::type; - static_assert(alignof(type) <= alignof(stype), "atomic_t<> error: unexpected alignment"); + static_assert(alignof(type) == sizeof(type), "atomic_t<> error: unexpected alignment, use alignas() if necessary"); - stype m_data; - - template static inline void write_relaxed(volatile T2& data, const T2& value) - { - data = value; - } - - static inline void write_relaxed(volatile u128& data, const u128& value) - { - sync_lock_test_and_set(&data, value); - } - - template static inline T2 read_relaxed(const volatile T2& data) - { - return data; - } - - static inline u128 read_relaxed(const volatile u128& value) - { - return sync_val_compare_and_swap(const_cast(&value), u128{0}, u128{0}); - } + type m_data; public: - static inline const stype to_subtype(const type& value) - { - return reinterpret_cast(value); - } - - static inline const type from_subtype(const stype value) - { - return reinterpret_cast(value); - } - atomic_t() = default; atomic_t(const atomic_t&) = delete; - atomic_t(type value) - : m_data(to_subtype(value)) - { - } - atomic_t& operator =(const atomic_t&) = delete; - atomic_t& operator =(type value) - { - return write_relaxed(m_data, to_subtype(value)), *this; - } + // Define simple type + using simple_type = simple_t; - operator type() const volatile + explicit constexpr atomic_t(const type& value) + : m_data(value) { - return from_subtype(read_relaxed(m_data)); - } - - // Unsafe direct access - stype* raw_data() - { - return reinterpret_cast(&m_data); } // Unsafe direct access type& raw() { - return reinterpret_cast(m_data); + return m_data; } // Atomically compare data with cmp, replace with exch if equal, return previous data value anyway - type compare_and_swap(const type& cmp, const type& exch) volatile + simple_type compare_and_swap(const type& cmp, const type& exch) { - return from_subtype(sync_val_compare_and_swap(&m_data, to_subtype(cmp), to_subtype(exch))); + type old = cmp; + atomic_storage::compare_exchange(m_data, old, exch); + return old; } // Atomically compare data with cmp, replace with exch if equal, return true if data was replaced - bool compare_and_swap_test(const type& cmp, const type& exch) volatile + bool compare_and_swap_test(const type& cmp, const type& exch) { - return sync_bool_compare_and_swap(&m_data, to_subtype(cmp), to_subtype(exch)); + type old = cmp; + return atomic_storage::compare_exchange(m_data, old, exch); } - // Atomically replace data with exch, return previous data value - type exchange(const type& exch) volatile + // Atomic operation; returns old value, discards function result value + template> + type fetch_op(F&& func, const Args&... args) { - return from_subtype(sync_lock_test_and_set(&m_data, to_subtype(exch))); - } + type _new, old = atomic_storage::load(m_data); - // Atomically read data, possibly without memory barrier (not for 128 bit) - type load() const volatile - { - return from_subtype(read_relaxed(m_data)); - } - - // Atomically write data, possibly without memory barrier (not for 128 bit) - void store(const type& value) volatile - { - write_relaxed(m_data, to_subtype(value)); - } - - // Perform an atomic operation on data (func is either pointer to member function or callable object with a T& first arg); - // Returns the result of the callable object call or previous (old) value of the atomic variable if the return type is void - template> auto atomic_op(F func, Args&&... args) volatile -> decltype(atomic_op_result_t::result) - { while (true) { - // Read the old value from memory - const stype old = read_relaxed(m_data); + func(_new = old, args...); - // Copy the old value - stype _new = old; - - // Call atomic op for the local copy of the old value and save the return value of the function - atomic_op_result_t result(func, reinterpret_cast(_new), args...); - - // Atomically compare value with `old`, replace with `_new` and return on success - if (sync_bool_compare_and_swap(&m_data, old, _new)) return result.move(); + if (atomic_storage::compare_exchange(m_data, old, _new)) return old; } } - // Atomic bitwise OR, returns previous data - type _or(const type& right) volatile + // Helper overload for calling optimized implementation + template> + type fetch_op(F&&, const Args&... args) { - return from_subtype(sync_fetch_and_or(&m_data, to_subtype(right))); + return F::fetch_op(m_data, args...); } - // Atomic bitwise AND, returns previous data - type _and(const type& right) volatile + // Atomic operation; returns new value, discards function result value + template> + type op_fetch(F&& func, const Args&... args) { - return from_subtype(sync_fetch_and_and(&m_data, to_subtype(right))); + type _new, old = atomic_storage::load(m_data); + + while (true) + { + func(_new = old, args...); + + if (atomic_storage::compare_exchange(m_data, old, _new)) return _new; + } } - // Atomic bitwise AND NOT (inverts right argument), returns previous data - type _and_not(const type& right) volatile + // Helper overload for calling optimized implementation + template> + type op_fetch(F&&, const Args&... args) { - return from_subtype(sync_fetch_and_and(&m_data, ~to_subtype(right))); + return F::op_fetch(m_data, args...); } - // Atomic bitwise XOR, returns previous data - type _xor(const type& right) volatile + // Atomic operation; returns function result value + template, typename = std::enable_if_t::value>> + RT atomic_op(F&& func, const Args&... args) { - return from_subtype(sync_fetch_and_xor(&m_data, to_subtype(right))); + type _new, old = atomic_storage::load(m_data); + + while (true) + { + RT&& result = func(_new = old, args...); + + if (atomic_storage::compare_exchange(m_data, old, _new)) return std::move(result); + } } - type operator |=(const type& right) volatile + // Overload for void return type + template, typename = std::enable_if_t::value>> + void atomic_op(F&& func, const Args&... args) { - return from_subtype(sync_fetch_and_or(&m_data, to_subtype(right)) | to_subtype(right)); + type _new, old = atomic_storage::load(m_data); + + while (true) + { + func(_new = old, args...); + + if (atomic_storage::compare_exchange(m_data, old, _new)) return; + } } - type operator &=(const type& right) volatile + // Helper overload for calling optimized implementation + template> + auto atomic_op(F&&, const Args&... args) { - return from_subtype(sync_fetch_and_and(&m_data, to_subtype(right)) & to_subtype(right)); + return F::atomic_op(m_data, args...); } - type operator ^=(const type& right) volatile + // Atomically read data + type load() const { - return from_subtype(sync_fetch_and_xor(&m_data, to_subtype(right)) ^ to_subtype(right)); + return atomic_storage::load(m_data); + } + + // Atomically read data + operator simple_type() const + { + return atomic_storage::load(m_data); + } + + // Atomically write data + void store(const type& rhs) + { + atomic_storage::store(m_data, rhs); + } + + type operator =(const type& rhs) + { + atomic_storage::store(m_data, rhs); + return rhs; + } + + // Atomically replace data with value, return previous data value + type exchange(const type& rhs) + { + return atomic_storage::exchange(m_data, rhs); + } + + template + type fetch_add(const T2& rhs) + { + return fetch_op(atomic_add{}, rhs); + } + + template + type add_fetch(const T2& rhs) + { + return op_fetch(atomic_add{}, rhs); + } + + template + auto operator +=(const T2& rhs) + { + return atomic_op(atomic_add{}, rhs); + } + + template + type fetch_sub(const T2& rhs) + { + return fetch_op(atomic_sub{}, rhs); + } + + template + type sub_fetch(const T2& rhs) + { + return op_fetch(atomic_sub{}, rhs); + } + + template + auto operator -=(const T2& rhs) + { + return atomic_op(atomic_sub{}, rhs); + } + + template + type fetch_and(const T2& rhs) + { + return fetch_op(atomic_and{}, rhs); + } + + template + type and_fetch(const T2& rhs) + { + return op_fetch(atomic_and{}, rhs); + } + + template + auto operator &=(const T2& rhs) + { + return atomic_op(atomic_and{}, rhs); + } + + template + type fetch_or(const T2& rhs) + { + return fetch_op(atomic_or{}, rhs); + } + + template + type or_fetch(const T2& rhs) + { + return op_fetch(atomic_or{}, rhs); + } + + template + auto operator |=(const T2& rhs) + { + return atomic_op(atomic_or{}, rhs); + } + + template + type fetch_xor(const T2& rhs) + { + return fetch_op(atomic_xor{}, rhs); + } + + template + type xor_fetch(const T2& rhs) + { + return op_fetch(atomic_xor{}, rhs); + } + + template + auto operator ^=(const T2& rhs) + { + return atomic_op(atomic_xor{}, rhs); + } + + auto operator ++() + { + return atomic_op(atomic_pre_inc{}); + } + + auto operator --() + { + return atomic_op(atomic_pre_dec{}); + } + + auto operator ++(int) + { + return atomic_op(atomic_post_inc{}); + } + + auto operator --(int) + { + return atomic_op(atomic_post_dec{}); + } + + template + auto test(const T2& rhs) const + { + return load().test(rhs); + } + + template + auto test_and_set(const T2& rhs) + { + return atomic_op(atomic_test_and_set{}, rhs); + } + + template + auto test_and_reset(const T2& rhs) + { + return atomic_op(atomic_test_and_reset{}, rhs); + } + + template + auto test_and_complement(const T2& rhs) + { + return atomic_op(atomic_test_and_complement{}, rhs); } }; - -template inline std::enable_if_t operator ++(atomic_t& left) -{ - return left.from_subtype(sync_fetch_and_add(left.raw_data(), 1) + 1); -} - -template inline std::enable_if_t operator --(atomic_t& left) -{ - return left.from_subtype(sync_fetch_and_sub(left.raw_data(), 1) - 1); -} - -template inline std::enable_if_t operator ++(atomic_t& left, int) -{ - return left.from_subtype(sync_fetch_and_add(left.raw_data(), 1)); -} - -template inline std::enable_if_t operator --(atomic_t& left, int) -{ - return left.from_subtype(sync_fetch_and_sub(left.raw_data(), 1)); -} - -template inline std::enable_if_t::value, T> operator +=(atomic_t& left, const T2& right) -{ - return left.from_subtype(sync_fetch_and_add(left.raw_data(), right) + right); -} - -template inline std::enable_if_t::value, T> operator -=(atomic_t& left, const T2& right) -{ - return left.from_subtype(sync_fetch_and_sub(left.raw_data(), right) - right); -} - -template inline std::enable_if_t> operator ++(atomic_t>& left) -{ - return left.from_subtype(sync_fetch_and_add(left.raw_data(), 1) + 1); -} - -template inline std::enable_if_t> operator --(atomic_t>& left) -{ - return left.from_subtype(sync_fetch_and_sub(left.raw_data(), 1) - 1); -} - -template inline std::enable_if_t> operator ++(atomic_t>& left, int) -{ - return left.from_subtype(sync_fetch_and_add(left.raw_data(), 1)); -} - -template inline std::enable_if_t> operator --(atomic_t>& left, int) -{ - return left.from_subtype(sync_fetch_and_sub(left.raw_data(), 1)); -} - -template inline std::enable_if_t::value, nse_t> operator +=(atomic_t>& left, const T2& right) -{ - return left.from_subtype(sync_fetch_and_add(left.raw_data(), right) + right); -} - -template inline std::enable_if_t::value, nse_t> operator -=(atomic_t>& left, const T2& right) -{ - return left.from_subtype(sync_fetch_and_sub(left.raw_data(), right) - right); -} - -template inline std::enable_if_t> operator ++(atomic_t>& left) -{ - return left.atomic_op([](se_t& value) -> se_t - { - return ++value; - }); -} - -template inline std::enable_if_t> operator --(atomic_t>& left) -{ - return left.atomic_op([](se_t& value) -> se_t - { - return --value; - }); -} - -template inline std::enable_if_t> operator ++(atomic_t>& left, int) -{ - return left.atomic_op([](se_t& value) -> se_t - { - return value++; - }); -} - -template inline std::enable_if_t> operator --(atomic_t>& left, int) -{ - return left.atomic_op([](se_t& value) -> se_t - { - return value--; - }); -} - -template inline std::enable_if_t::value, se_t> operator +=(atomic_t>& left, const T2& right) -{ - return left.atomic_op([&](se_t& value) -> se_t - { - return value += right; - }); -} - -template inline std::enable_if_t::value, se_t> operator -=(atomic_t>& left, const T2& right) -{ - return left.atomic_op([&](se_t& value) -> se_t - { - return value -= right; - }); -} - -// Atomic BE Type (for PS3 virtual memory) -template using atomic_be_t = atomic_t>; - -// Atomic LE Type (for PSV virtual memory) -template using atomic_le_t = atomic_t>; - -// Algorithm for std::atomic; similar to atomic_t::atomic_op() -template> auto atomic_op(std::atomic& var, F func, Args&&... args) -> decltype(atomic_op_result_t::result) -{ - auto old = var.load(); - - while (true) - { - auto _new = old; - - atomic_op_result_t result(func, _new, args...); - - if (var.compare_exchange_strong(old, _new)) return result.move(); - } -} diff --git a/Utilities/AutoPause.cpp b/Utilities/AutoPause.cpp index 35608d3300..5fc5125975 100644 --- a/Utilities/AutoPause.cpp +++ b/Utilities/AutoPause.cpp @@ -1,57 +1,29 @@ #include "stdafx.h" -#include "AutoPause.h" -#include "Utilities/Log.h" -#include "Utilities/File.h" +#include "Config.h" #include "Emu/System.h" -#include "Emu/state.h" +#include "AutoPause.h" -using namespace Debug; +cfg::bool_entry g_cfg_debug_autopause_syscall(cfg::root.misc, "Auto Pause at System Call"); +cfg::bool_entry g_cfg_debug_autopause_func_call(cfg::root.misc, "Auto Pause at Function Call"); -std::unique_ptr g_autopause; - -AutoPause& AutoPause::getInstance(void) +debug::autopause& debug::autopause::get_instance() { - if (!g_autopause) + // Use magic static + static autopause instance; + return instance; +} + +// Load Auto Pause Configuration from file "pause.bin" +void debug::autopause::reload(void) +{ + auto& instance = get_instance(); + + instance.m_pause_function.clear(); + instance.m_pause_syscall.clear(); + + // TODO: better format, possibly a config entry + if (fs::file list{ fs::get_config_dir() + "pause.bin" }) { - g_autopause.reset(new AutoPause); - } - - return *g_autopause; -} - -//Still use binary format. Default Setting should be "disable all auto pause". -AutoPause::AutoPause(void) -{ - m_pause_function.reserve(16); - m_pause_syscall.reserve(16); - initialized = false; - //Reload(false, false); - Reload(); -} - -//Notice: I would not allow to write the binary to file in this command. -AutoPause::~AutoPause(void) -{ - initialized = false; - m_pause_function.clear(); - m_pause_syscall.clear(); - m_pause_function_enable = false; - m_pause_syscall_enable = false; -} - -//Load Auto Pause Configuration from file "pause.bin" -//This would be able to create in a GUI window. -void AutoPause::Reload(void) -{ - if (fs::is_file(fs::get_config_dir() + "pause.bin")) - { - m_pause_function.clear(); - m_pause_function.reserve(16); - m_pause_syscall.clear(); - m_pause_syscall.reserve(16); - - fs::file list(fs::get_config_dir() + "pause.bin"); - //System calls ID and Function calls ID are all u32 iirc. u32 num; size_t fmax = list.size(); size_t fcur = 0; @@ -64,60 +36,38 @@ void AutoPause::Reload(void) if (num < 1024) { - //Less than 1024 - be regarded as a system call. - //emplace_back may not cause reductant move/copy operation. - m_pause_syscall.emplace_back(num); - LOG_WARNING(HLE, "Auto Pause: Find System Call ID 0x%x", num); + instance.m_pause_syscall.emplace(num); + LOG_WARNING(HLE, "Set autopause at syscall %lld", num); } else { - m_pause_function.emplace_back(num); - LOG_WARNING(HLE, "Auto Pause: Find Function Call ID 0x%x", num); + instance.m_pause_function.emplace(num); + LOG_WARNING(HLE, "Set autopause at function 0x%08x", num); } } } - - m_pause_syscall_enable = rpcs3::config.misc.debug.auto_pause_syscall.value(); - m_pause_function_enable = rpcs3::config.misc.debug.auto_pause_func_call.value(); - initialized = true; } -void AutoPause::TryPause(u32 code) +bool debug::autopause::pause_syscall(u64 code) { - if (code < 1024) + if (g_cfg_debug_autopause_syscall && get_instance().m_pause_syscall.count(code) != 0) { - //Would first check Enable setting. Then the list length. - if ((!m_pause_syscall_enable) - || (m_pause_syscall.size() <= 0)) - { - return; - } - - for (u32 i = 0; i < m_pause_syscall.size(); ++i) - { - if (code == m_pause_syscall[i]) - { - Emu.Pause(); - LOG_ERROR(HLE, "Auto Pause Triggered: System call 0x%x", code); // Used Error - } - } + Emu.Pause(); + LOG_SUCCESS(HLE, "Autopause triggered at syscall %lld", code); + return true; } - else - { - //Well similiar.. Seperate the list caused by possible setting difference. - if ((!m_pause_function_enable) - || (m_pause_function.size() <= 0)) - { - return; - } - for (u32 i = 0; i < m_pause_function.size(); ++i) - { - if (code == m_pause_function[i]) - { - Emu.Pause(); - LOG_ERROR(HLE, "Auto Pause Triggered: Function call 0x%x", code); // Used Error - } - } - } + return false; +} + +bool debug::autopause::pause_function(u32 code) +{ + if (g_cfg_debug_autopause_func_call && get_instance().m_pause_function.count(code) != 0) + { + Emu.Pause(); + LOG_SUCCESS(HLE, "Autopause triggered at function 0x%08x", code); + return true; + } + + return false; } diff --git a/Utilities/AutoPause.h b/Utilities/AutoPause.h index cf871b46cb..13a2f0c133 100644 --- a/Utilities/AutoPause.h +++ b/Utilities/AutoPause.h @@ -1,24 +1,20 @@ #pragma once -//Regarded as a Debugger Enchantment -namespace Debug { - //To store the pause function/call id, and let those pause there. - //Would be with a GUI to configure those. - struct AutoPause +// Regarded as a Debugger Enchantment +namespace debug +{ + // To store the pause function/call id, and let those pause there. + // Would be with a GUI to configure those. + class autopause { - std::vector m_pause_syscall; - std::vector m_pause_function; - bool initialized; - bool m_pause_syscall_enable; - bool m_pause_function_enable; + std::unordered_set m_pause_syscall; + std::unordered_set m_pause_function; - AutoPause(); - ~AutoPause(); + static autopause& get_instance(); public: - static AutoPause& getInstance(void); - void Reload(void); - - void TryPause(u32 code); + static void reload(); + static bool pause_syscall(u64 code); + static bool pause_function(u32 code); }; -} \ No newline at end of file +} diff --git a/Utilities/BEType.h b/Utilities/BEType.h index 80c8256a2f..d5b51b99c7 100644 --- a/Utilities/BEType.h +++ b/Utilities/BEType.h @@ -1,16 +1,14 @@ #pragma once -#ifdef _MSC_VER -#include -#else -#include -#endif +#include "types.h" +#include "Platform.h" -#define IS_LE_MACHINE // only draft - -union v128 +union alignas(16) v128 { - template class masked_array_t // array type accessed as (index ^ M) + char _bytes[16]; + + template + struct masked_array_t // array type accessed as (index ^ M) { T m_data[N]; @@ -24,24 +22,11 @@ union v128 { return m_data[index ^ M]; } - - T& at(std::size_t index) - { - return (index ^ M) < N ? m_data[index ^ M] : throw std::out_of_range(__FUNCTION__); - } - - const T& at(std::size_t index) const - { - return (index ^ M) < N ? m_data[index ^ M] : throw std::out_of_range(__FUNCTION__); - } }; -#ifdef IS_LE_MACHINE +#if IS_LE_MACHINE == 1 template using normal_array_t = masked_array_t; template using reversed_array_t = masked_array_t; -#else - template using normal_array_t = masked_array_t; - template using reversed_array_t = masked_array_t; #endif normal_array_t _u64; @@ -73,7 +58,7 @@ union v128 __m128i vi; __m128d vd; - class bit_array_128 + struct bit_array_128 { u64 m_data[2]; @@ -125,36 +110,18 @@ union v128 // Index 0 returns the MSB and index 127 returns the LSB bit_element operator [](u32 index) { -#ifdef IS_LE_MACHINE +#if IS_LE_MACHINE == 1 return bit_element(m_data[1 - (index >> 6)], 0x8000000000000000ull >> (index & 0x3F)); -#else - return bit_element(m_data[index >> 6], 0x8000000000000000ull >> (index & 0x3F)); #endif } // Index 0 returns the MSB and index 127 returns the LSB bool operator [](u32 index) const { -#ifdef IS_LE_MACHINE +#if IS_LE_MACHINE == 1 return (m_data[1 - (index >> 6)] & (0x8000000000000000ull >> (index & 0x3F))) != 0; -#else - return (m_data[index >> 6] & (0x8000000000000000ull >> (index & 0x3F))) != 0; #endif } - - bit_element at(u32 index) - { - if (index >= 128) throw std::out_of_range(__FUNCTION__); - - return operator[](index); - } - - bool at(u32 index) const - { - if (index >= 128) throw std::out_of_range(__FUNCTION__); - - return operator[](index); - } } _bit; @@ -320,16 +287,6 @@ union v128 return _u64[0] != right._u64[0] || _u64[1] != right._u64[1]; } - bool is_any_1() const // check if any bit is 1 - { - return _u64[0] || _u64[1]; - } - - bool is_any_0() const // check if any bit is 0 - { - return ~_u64[0] || ~_u64[1]; - } - // result = (~left) & (right) static inline v128 andnot(const v128& left, const v128& right) { @@ -345,15 +302,8 @@ union v128 std::string to_hex() const; std::string to_xyzw() const; - - static inline v128 byteswap(const v128 val) - { - return fromV(_mm_shuffle_epi8(val.vi, _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15))); - } }; -CHECK_SIZE_ALIGN(v128, 16, 16); - inline v128 operator |(const v128& left, const v128& right) { return v128::fromV(_mm_or_si128(left.vi, right.vi)); @@ -374,21 +324,21 @@ inline v128 operator ~(const v128& other) return v128::from64(~other._u64[0], ~other._u64[1]); } -template struct se_storage +#define IS_INTEGER(t) (std::is_integral::value || std::is_enum::value) +#define IS_BINARY_COMPARABLE(t1, t2) (IS_INTEGER(t1) && IS_INTEGER(t2) && sizeof(t1) == sizeof(t2)) + +template +struct se_storage { static_assert(!Size, "Bad se_storage<> type"); }; -template struct se_storage +template +struct se_storage { using type = u16; - [[deprecated]] static constexpr u16 _swap(u16 src) // for reference - { - return (src >> 8) | (src << 8); - } - - static inline u16 swap(u16 src) + static constexpr u16 swap(u16 src) { #if defined(__GNUG__) return __builtin_bswap16(src); @@ -409,16 +359,12 @@ template struct se_storage } }; -template struct se_storage +template +struct se_storage { using type = u32; - [[deprecated]] static constexpr u32 _swap(u32 src) // for reference - { - return (src >> 24) | (src << 24) | ((src >> 8) & 0x0000ff00) | ((src << 8) & 0x00ff0000); - } - - static inline u32 swap(u32 src) + static constexpr u32 swap(u32 src) { #if defined(__GNUG__) return __builtin_bswap32(src); @@ -439,22 +385,12 @@ template struct se_storage } }; -template struct se_storage +template +struct se_storage { using type = u64; - [[deprecated]] static constexpr u64 _swap(u64 src) // for reference - { - return (src >> 56) | (src << 56) | - ((src >> 40) & 0x000000000000ff00) | - ((src >> 24) & 0x0000000000ff0000) | - ((src >> 8) & 0x00000000ff000000) | - ((src << 8) & 0x000000ff00000000) | - ((src << 24) & 0x0000ff0000000000) | - ((src << 40) & 0x00ff000000000000); - } - - static inline u64 swap(u64 src) + static constexpr u64 swap(u64 src) { #if defined(__GNUG__) return __builtin_bswap64(src); @@ -475,25 +411,32 @@ template struct se_storage } }; -template struct se_storage +template +struct se_storage { using type = v128; + static inline v128 swap(const v128& src) + { + return v128::fromV(_mm_shuffle_epi8(src.vi, _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15))); + } + static inline v128 to(const T& src) { - return v128::byteswap(reinterpret_cast(src)); + return swap(reinterpret_cast(src)); } static inline T from(const v128& src) { - const v128 result = v128::byteswap(src); + const v128 result = swap(src); return reinterpret_cast(result); } }; template using se_storage_t = typename se_storage::type; -template struct se_convert +template +struct se_convert { using type_from = std::remove_cv_t; using type_to = std::remove_cv_t; @@ -515,10 +458,12 @@ template struct se_convert static struct se_raw_tag_t {} constexpr se_raw{}; -template class se_t; +template +class se_t; -// se_t with switched endianness -template class se_t +// Switched endianness +template +class se_t { using type = typename std::remove_cv::type; using stype = se_storage_t; @@ -526,14 +471,13 @@ template class se_t stype m_data; - static_assert(!std::is_union::value && !std::is_class::value || std::is_same::value || std::is_same::value, "se_t<> error: invalid type (struct or union)"); static_assert(!std::is_pointer::value, "se_t<> error: invalid type (pointer)"); static_assert(!std::is_reference::value, "se_t<> error: invalid type (reference)"); static_assert(!std::is_array::value, "se_t<> error: invalid type (array)"); - //static_assert(!std::is_enum::value, "se_t<> error: invalid type (enumeration), use integral type instead"); - static_assert(alignof(type) == alignof(stype), "se_t<> error: unexpected alignment"); + static_assert(sizeof(type) == alignof(type), "se_t<> error: unexpected alignment"); - template struct bool_converter + template + struct bool_converter { static inline bool to_bool(const se_t& value) { @@ -541,7 +485,8 @@ template class se_t } }; - template struct bool_converter::value>> + template + struct bool_converter::value>> { static inline bool to_bool(const se_t& value) { @@ -559,7 +504,7 @@ public: { } - // construct directly from raw data (don't use) + // Construct directly from raw data (don't use) constexpr se_t(const stype& raw_value, const se_raw_tag_t&) : m_data(raw_value) { @@ -570,7 +515,7 @@ public: return storage::from(m_data); } - // access underlying raw data (don't use) + // Access underlying raw data (don't use) constexpr const stype& raw_data() const noexcept { return m_data; @@ -583,78 +528,96 @@ public: return m_data = storage::to(value), *this; } + using simple_type = simple_t; + operator type() const { return storage::from(m_data); } - // optimization + // Optimization explicit operator bool() const { return bool_converter::to_bool(*this); } - // optimization - template std::enable_if_t operator &=(const se_t& right) + // Optimization + template + std::enable_if_t operator &=(const se_t& right) { return m_data &= right.raw_data(), *this; } - // optimization - template std::enable_if_t::value, se_t&> operator &=(CT right) + // Optimization + template + std::enable_if_t::value && std::is_convertible::value, se_t&> operator &=(CT right) { return m_data &= storage::to(right), *this; } - // optimization - template std::enable_if_t operator |=(const se_t& right) + // Optimization + template + std::enable_if_t operator |=(const se_t& right) { return m_data |= right.raw_data(), *this; } - // optimization - template std::enable_if_t::value, se_t&> operator |=(CT right) + // Optimization + template + std::enable_if_t::value && std::is_convertible::value, se_t&> operator |=(CT right) { return m_data |= storage::to(right), *this; } - // optimization - template std::enable_if_t operator ^=(const se_t& right) + // Optimization + template + std::enable_if_t operator ^=(const se_t& right) { return m_data ^= right.raw_data(), *this; } - // optimization - template std::enable_if_t::value, se_t&> operator ^=(CT right) + // Optimization + template + std::enable_if_t::value && std::is_convertible::value, se_t&> operator ^=(CT right) { return m_data ^= storage::to(right), *this; } }; -// se_t with native endianness -template class se_t +// Native endianness +template +class se_t { using type = typename std::remove_cv::type; - type m_data; - - static_assert(!std::is_union::value && !std::is_class::value || std::is_same::value || std::is_same::value, "se_t<> error: invalid type (struct or union)"); static_assert(!std::is_pointer::value, "se_t<> error: invalid type (pointer)"); static_assert(!std::is_reference::value, "se_t<> error: invalid type (reference)"); static_assert(!std::is_array::value, "se_t<> error: invalid type (array)"); - //static_assert(!std::is_enum::value, "se_t<> error: invalid type (enumeration), use integral type instead"); + static_assert(sizeof(type) == alignof(type), "se_t<> error: unexpected alignment"); + + type m_data; public: se_t() = default; - se_t(const se_t&) = default; - constexpr se_t(type value) : m_data(value) { } - type value() const + // Construct directly from raw data (don't use) + constexpr se_t(const type& raw_value, const se_raw_tag_t&) + : m_data(raw_value) + { + } + + constexpr type value() const + { + return m_data; + } + + // Access underlying raw data (don't use) + constexpr const type& raw_data() const noexcept { return m_data; } @@ -666,22 +629,27 @@ public: return m_data = value, *this; } - operator type() const + using simple_type = simple_t; + + constexpr operator type() const { return m_data; } - template std::enable_if_t::value, se_t&> operator &=(const CT& right) + template + std::enable_if_t::value && std::is_convertible::value, se_t&> operator &=(const CT& right) { return m_data &= right, *this; } - template std::enable_if_t::value, se_t&> operator |=(const CT& right) + template + std::enable_if_t::value && std::is_convertible::value, se_t&> operator |=(const CT& right) { return m_data |= right, *this; } - template std::enable_if_t::value, se_t&> operator ^=(const CT& right) + template + std::enable_if_t::value && std::is_convertible::value, se_t&> operator ^=(const CT& right) { return m_data ^= right, *this; } @@ -690,49 +658,57 @@ public: // se_t with native endianness (alias) template using nse_t = se_t; -template inline se_t& operator +=(se_t& left, const T1& right) +template +inline se_t& operator +=(se_t& left, const T1& right) { auto value = left.value(); return left = (value += right); } -template inline se_t& operator -=(se_t& left, const T1& right) +template +inline se_t& operator -=(se_t& left, const T1& right) { auto value = left.value(); return left = (value -= right); } -template inline se_t& operator *=(se_t& left, const T1& right) +template +inline se_t& operator *=(se_t& left, const T1& right) { auto value = left.value(); return left = (value *= right); } -template inline se_t& operator /=(se_t& left, const T1& right) +template +inline se_t& operator /=(se_t& left, const T1& right) { auto value = left.value(); return left = (value /= right); } -template inline se_t& operator %=(se_t& left, const T1& right) +template +inline se_t& operator %=(se_t& left, const T1& right) { auto value = left.value(); return left = (value %= right); } -template inline se_t& operator <<=(se_t& left, const T1& right) +template +inline se_t& operator <<=(se_t& left, const T1& right) { auto value = left.value(); return left = (value <<= right); } -template inline se_t& operator >>=(se_t& left, const T1& right) +template +inline se_t& operator >>=(se_t& left, const T1& right) { auto value = left.value(); return left = (value >>= right); } -template inline se_t operator ++(se_t& left, int) +template +inline se_t operator ++(se_t& left, int) { auto value = left.value(); auto result = value++; @@ -740,7 +716,8 @@ template inline se_t operator ++(se_t& left, return result; } -template inline se_t operator --(se_t& left, int) +template +inline se_t operator --(se_t& left, int) { auto value = left.value(); auto result = value--; @@ -748,193 +725,205 @@ template inline se_t operator --(se_t& left, return result; } -template inline se_t& operator ++(se_t& right) +template +inline se_t& operator ++(se_t& right) { auto value = right.value(); return right = ++value; } -template inline se_t& operator --(se_t& right) +template +inline se_t& operator --(se_t& right) { auto value = right.value(); return right = --value; } -// optimization -template inline std::enable_if_t operator ==(const se_t& left, const se_t& right) +// Optimization +template +inline std::enable_if_t operator ==(const se_t& left, const se_t& right) { return left.raw_data() == right.raw_data(); } -// optimization -template inline std::enable_if_t= sizeof(T2), bool> operator ==(const se_t& left, T2 right) +// Optimization +template +inline std::enable_if_t::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2), bool> operator ==(const se_t& left, T2 right) { return left.raw_data() == se_storage::to(right); } -// optimization -template inline std::enable_if_t operator ==(T1 left, const se_t& right) +// Optimization +template +inline std::enable_if_t::value && sizeof(T1) <= sizeof(T2), bool> operator ==(T1 left, const se_t& right) { return se_storage::to(left) == right.raw_data(); } -// optimization -template inline std::enable_if_t operator !=(const se_t& left, const se_t& right) +// Optimization +template +inline std::enable_if_t operator !=(const se_t& left, const se_t& right) { return left.raw_data() != right.raw_data(); } -// optimization -template inline std::enable_if_t= sizeof(T2), bool> operator !=(const se_t& left, T2 right) +// Optimization +template +inline std::enable_if_t::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2), bool> operator !=(const se_t& left, T2 right) { return left.raw_data() != se_storage::to(right); } -// optimization -template inline std::enable_if_t operator !=(T1 left, const se_t& right) +// Optimization +template +inline std::enable_if_t::value && sizeof(T1) <= sizeof(T2), bool> operator !=(T1 left, const se_t& right) { return se_storage::to(left) != right.raw_data(); } -// optimization -template inline std::enable_if_t= 4, se_t> operator &(const se_t& left, const se_t& right) +// Optimization +template +inline std::enable_if_t= 4, se_t> operator &(const se_t& left, const se_t& right) { return{ left.raw_data() & right.raw_data(), se_raw }; } -// optimization -template inline std::enable_if_t= sizeof(T2) && sizeof(T1) >= 4, se_t> operator &(const se_t& left, T2 right) +// Optimization +template +inline std::enable_if_t::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t> operator &(const se_t& left, T2 right) { return{ left.raw_data() & se_storage::to(right), se_raw }; } -// optimization -template inline std::enable_if_t= 4, se_t> operator &(T1 left, const se_t& right) +// Optimization +template +inline std::enable_if_t::value && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t> operator &(T1 left, const se_t& right) { return{ se_storage::to(left) & right.raw_data(), se_raw }; } -// optimization -template inline std::enable_if_t= 4, se_t> operator |(const se_t& left, const se_t& right) +// Optimization +template +inline std::enable_if_t= 4, se_t> operator |(const se_t& left, const se_t& right) { return{ left.raw_data() | right.raw_data(), se_raw }; } -// optimization -template inline std::enable_if_t= sizeof(T2) && sizeof(T1) >= 4, se_t> operator |(const se_t& left, T2 right) +// Optimization +template +inline std::enable_if_t::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t> operator |(const se_t& left, T2 right) { return{ left.raw_data() | se_storage::to(right), se_raw }; } -// optimization -template inline std::enable_if_t= 4, se_t> operator |(T1 left, const se_t& right) +// Optimization +template +inline std::enable_if_t::value && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t> operator |(T1 left, const se_t& right) { return{ se_storage::to(left) | right.raw_data(), se_raw }; } -// optimization -template inline std::enable_if_t= 4, se_t> operator ^(const se_t& left, const se_t& right) +// Optimization +template +inline std::enable_if_t= 4, se_t> operator ^(const se_t& left, const se_t& right) { return{ left.raw_data() ^ right.raw_data(), se_raw }; } -// optimization -template inline std::enable_if_t= sizeof(T2) && sizeof(T1) >= 4, se_t> operator ^(const se_t& left, T2 right) +// Optimization +template +inline std::enable_if_t::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t> operator ^(const se_t& left, T2 right) { return{ left.raw_data() ^ se_storage::to(right), se_raw }; } -// optimization -template inline std::enable_if_t= 4, se_t> operator ^(T1 left, const se_t& right) +// Optimization +template +inline std::enable_if_t::value && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t> operator ^(T1 left, const se_t& right) { return{ se_storage::to(left) ^ right.raw_data(), se_raw }; } -// optimization -template inline std::enable_if_t= 4, se_t> operator ~(const se_t& right) +// Optimization +template +inline std::enable_if_t::value && sizeof(T) >= 4, se_t> operator ~(const se_t& right) { return{ ~right.raw_data(), se_raw }; } -#ifdef IS_LE_MACHINE +#if IS_LE_MACHINE == 1 template using be_t = se_t; template using le_t = se_t; -#else -template using be_t = se_t; -template using le_t = se_t; #endif - -template struct to_se +// Type converter: converts native endianness arithmetic/enum types to appropriate se_t<> type +template +struct to_se { + // Convert arithmetic and enum types using type = typename std::conditional::value || std::is_enum::value, se_t, T>::type; }; -template struct to_se::value>> // move const qualifier -{ - using type = const typename to_se::type; -}; - -template struct to_se::value && !std::is_const::value>> // move volatile qualifier -{ - using type = volatile typename to_se::type; -}; - -template struct to_se -{ - using type = typename to_se::type[]; -}; - -template struct to_se -{ - using type = typename to_se::type[N]; -}; - -template struct to_se { using type = se_t; }; template struct to_se { using type = se_t; }; template struct to_se { using type = bool; }; template struct to_se { using type = char; }; template struct to_se { using type = u8; }; template struct to_se { using type = s8; }; -#ifdef IS_LE_MACHINE +template +struct to_se::value>> +{ + // Move const qualifier + using type = const typename to_se::type; +}; + +template +struct to_se::value && !std::is_const::value>> +{ + // Move volatile qualifier + using type = volatile typename to_se::type; +}; + +template +struct to_se +{ + // Move array qualifier + using type = typename to_se::type[]; +}; + +template +struct to_se +{ + // Move array qualifier + using type = typename to_se::type[N]; +}; + +// BE/LE aliases for to_se<> +#if IS_LE_MACHINE == 1 template using to_be_t = typename to_se::type; template using to_le_t = typename to_se::type; -#else -template using to_be_t = typename to_se::type; -template using to_le_t = typename to_se::type; #endif +// BE/LE aliases for atomic_t +#if IS_LE_MACHINE == 1 +template using atomic_be_t = atomic_t>; +template using atomic_le_t = atomic_t>; +#endif -template struct to_ne +namespace fmt { - using type = T; -}; + // Formatting for BE/LE data + template + struct unveil, void> + { + using result_type = typename unveil::result_type; -template struct to_ne> -{ - using type = typename std::remove_cv::type; -}; + static inline result_type get_value(const se_t& arg) + { + return unveil::get_value(arg); + } + }; +} -template struct to_ne::value>> // move const qualifier -{ - using type = const typename to_ne::type; -}; - -template struct to_ne::value && !std::is_const::value>> // move volatile qualifier -{ - using type = volatile typename to_ne::type; -}; - -template struct to_ne -{ - using type = typename to_ne::type[]; -}; - -template struct to_ne -{ - using type = typename to_ne::type[N]; -}; - -// restore native endianness for T: returns T for be_t or le_t, T otherwise -template using to_ne_t = typename to_ne::type; +#undef IS_BINARY_COMPARABLE +#undef IS_INTEGER diff --git a/Utilities/BitField.h b/Utilities/BitField.h index 7c7ad0704f..ef03e0ab8a 100644 --- a/Utilities/BitField.h +++ b/Utilities/BitField.h @@ -1,73 +1,106 @@ #pragma once -// BitField access helper class (N bits from I position), intended to be put in union -template class bf_t +#include "types.h" + +template +struct bf_base { - // Checks - static_assert(I < sizeof(T) * 8, "bf_t<> error: I out of bounds"); - static_assert(N < sizeof(T) * 8, "bf_t<> error: N out of bounds"); - static_assert(I + N <= sizeof(T) * 8, "bf_t<> error: values out of bounds"); + using type = T; + using vtype = simple_t; - // Underlying data type - using type = typename std::remove_cv::type; + // Datatype bitsize + static constexpr uint bitmax = sizeof(T) * CHAR_BIT; static_assert(N - 1 < bitmax, "bf_base<> error: N out of bounds"); + + // Field bitsize + static constexpr uint bitsize = N; - // Underlying value type (native endianness) - using vtype = typename to_ne::type; + // Value mask + static constexpr vtype vmask = static_cast(~std::make_unsigned_t{} >> (bitmax - bitsize)); - // Mask of size N - constexpr static vtype s_mask = (static_cast(1) << N) - 1; - - // Underlying data member +protected: type m_data; +}; - // Conversion operator helper (uses SFINAE) - template struct converter {}; +// Bitfield accessor (N bits from I position, 0 is LSB) +template +struct bf_t : bf_base +{ + using type = typename bf_t::type; + using vtype = typename bf_t::vtype; - template struct converter::value>> + // Field offset + static constexpr uint bitpos = I; static_assert(bitpos + N <= bf_t::bitmax, "bf_t<> error: I out of bounds"); + + // Get bitmask of size N, at I pos + static constexpr vtype data_mask() + { + return bf_t::vmask << bitpos; + } + + // Bitfield extraction helper + template + struct extract_impl + { + static_assert(!sizeof(T2), "bf_t<> error: Invalid type"); + }; + + template + struct extract_impl::value>> { // Load unsigned value - static inline T2 convert(const type& data) + static constexpr T2 extract(const T& data) { - return (data >> I) & s_mask; + return (data >> bitpos) & bf_t::vmask; } }; - template struct converter::value>> + template + struct extract_impl::value>> { // Load signed value (sign-extended) - static inline T2 convert(const type& data) + static constexpr T2 extract(const T& data) { - return data << (sizeof(T) * 8 - I - N) >> (sizeof(T) * 8 - N); + return data << (bf_t::bitmax - bitpos - N) >> (bf_t::bitmax - N); } }; -public: - // Assignment operator (store bitfield value) - bf_t& operator =(vtype value) + // Bitfield extraction + static constexpr vtype extract(const T& data) { - m_data = (m_data & ~(s_mask << I)) | (value & s_mask) << I; - return *this; + return extract_impl::extract(data); } - // Conversion operator (load bitfield value) - operator vtype() const + // Bitfield insertion + static constexpr vtype insert(vtype value) { - return converter::convert(m_data); + return (value & bf_t::vmask) << bitpos; } - // Get raw data with mask applied - type unshifted() const + // Load bitfield value + constexpr operator vtype() const { - return (m_data & (s_mask << I)); + return extract(this->m_data); } - // Optimized bool conversion - explicit operator bool() const + // Load raw data with mask applied + constexpr T unshifted() const + { + return this->m_data & data_mask(); + } + + // Optimized bool conversion (must be removed if inappropriate) + explicit constexpr operator bool() const { return unshifted() != 0; } - // Postfix increment operator + // Store bitfield value + bf_t& operator =(vtype value) + { + this->m_data = (this->m_data & ~data_mask()) | insert(value); + return *this; + } + vtype operator ++(int) { vtype result = *this; @@ -75,13 +108,11 @@ public: return result; } - // Prefix increment operator bf_t& operator ++() { return *this = *this + 1; } - // Postfix decrement operator vtype operator --(int) { vtype result = *this; @@ -89,52 +120,125 @@ public: return result; } - // Prefix decrement operator bf_t& operator --() { return *this = *this - 1; } - // Addition assignment operator bf_t& operator +=(vtype right) { return *this = *this + right; } - // Subtraction assignment operator bf_t& operator -=(vtype right) { return *this = *this - right; } - // Multiplication assignment operator bf_t& operator *=(vtype right) { return *this = *this * right; } - // Bitwise AND assignment operator bf_t& operator &=(vtype right) { - m_data &= (right & s_mask) << I; + this->m_data &= (right & bf_t::vmask) << bitpos; return *this; } - // Bitwise OR assignment operator bf_t& operator |=(vtype right) { - m_data |= (right & s_mask) << I; + this->m_data |= (right & bf_t::vmask) << bitpos; return *this; } - // Bitwise XOR assignment operator bf_t& operator ^=(vtype right) { - m_data ^= (right & s_mask) << I; + this->m_data ^= (right & bf_t::vmask) << bitpos; return *this; } }; -template using bf_be_t = bf_t, I, N>; +// Field pack (concatenated from left to right) +template +struct cf_t : bf_base::bitsize> +{ + using type = typename cf_t::type; + using vtype = typename cf_t::vtype; -template using bf_le_t = bf_t, I, N>; + // Get disjunction of all "data" masks of concatenated values + static constexpr vtype data_mask() + { + return F::data_mask() | cf_t::data_mask(); + } + + // Extract all bitfields and concatenate + static constexpr vtype extract(const type& data) + { + return F::extract(data) << cf_t::bitsize | cf_t::extract(data); + } + + // Split bitfields and insert them + static constexpr vtype insert(vtype value) + { + return F::insert(value >> cf_t::bitsize) | cf_t::insert(value); + } + + // Load value + constexpr operator vtype() const + { + return extract(this->m_data); + } + + // Store value + cf_t& operator =(vtype value) + { + this->m_data = (this->m_data & ~data_mask()) | insert(value); + return *this; + } +}; + +// Empty field pack (recursion terminator) +template<> +struct cf_t +{ + static constexpr uint bitsize = 0; + + static constexpr uint data_mask() + { + return 0; + } + + template + static constexpr auto extract(const T& data) -> decltype(+T()) + { + return 0; + } + + template + static constexpr T insert(T value) + { + return 0; + } +}; + +// Fixed field (provides constant values in field pack) +template +struct ff_t : bf_base +{ + using type = typename ff_t::type; + using vtype = typename ff_t::vtype; + + // Return constant value + static constexpr vtype extract(const type& data) + { + static_assert((V & ff_t::vmask) == V, "ff_t<> error: V out of bounds"); + return V; + } + + // Get value + operator vtype() const + { + return V; + } +}; diff --git a/Utilities/Config.cpp b/Utilities/Config.cpp new file mode 100644 index 0000000000..e7368683c3 --- /dev/null +++ b/Utilities/Config.cpp @@ -0,0 +1,203 @@ +#include "stdafx.h" +#include "Config.h" + +#include "yaml-cpp/yaml.h" + +namespace cfg +{ + _log::channel cfg("CFG", _log::level::notice); + + entry_base::entry_base(type _type) + : m_type(_type) + { + if (_type != type::node) + { + throw std::logic_error("Invalid root node"); + } + } + + entry_base::entry_base(type _type, node& owner, const std::string& name) + : m_type(_type) + { + if (!owner.m_nodes.emplace(name, this).second) + { + throw std::logic_error("Node already exists"); + } + } + + entry_base& entry_base::operator[](const std::string& name) const + { + if (m_type == type::node) + { + return *static_cast(*this).m_nodes.at(name); + } + + throw std::logic_error("Invalid node type"); + } + + entry_base& entry_base::operator[](const char* name) const + { + if (m_type == type::node) + { + return *static_cast(*this).m_nodes.at(name); + } + + throw std::logic_error("Invalid node type"); + } + + // Emit YAML + static void encode(YAML::Emitter& out, const class entry_base& rhs); + + // Incrementally load config entries from YAML::Node. + // The config value is preserved if the corresponding YAML node doesn't exist. + static void decode(const YAML::Node& data, class entry_base& rhs); +} + +bool cfg::try_to_int64(s64* out, const std::string& value, s64 min, s64 max) +{ + // TODO: this could be rewritten without exceptions (but it should be as safe as possible and provide logs) + s64 result; + std::size_t pos; + + try + { + result = std::stoll(value, &pos, 0 /* Auto-detect numeric base */); + } + catch (const std::exception& e) + { + if (out) cfg.error("cfg::try_to_int('%s'): exception: %s", value, e.what()); + return false; + } + + if (pos != value.size()) + { + if (out) cfg.error("cfg::try_to_int('%s'): unexpected characters (pos=%zu)", value, pos); + return false; + } + + if (result < min || result > max) + { + if (out) cfg.error("cfg::try_to_int('%s'): out of bounds (%lld..%lld)", value, min, max); + return false; + } + + if (out) *out = result; + return true; +} + +void cfg::encode(YAML::Emitter& out, const cfg::entry_base& rhs) +{ + switch (rhs.get_type()) + { + case type::node: + { + out << YAML::BeginMap; + for (const auto& np : static_cast(rhs).get_nodes()) + { + out << YAML::Key << np.first; + out << YAML::Value; encode(out, *np.second); + } + + out << YAML::EndMap; + return; + } + case type::set: + { + out << YAML::BeginSeq; + for (const auto& str : static_cast(rhs).get_set()) + { + out << str; + } + + out << YAML::EndSeq; + return; + } + } + + out << rhs.to_string(); +} + +void cfg::decode(const YAML::Node& data, cfg::entry_base& rhs) +{ + switch (rhs.get_type()) + { + case type::node: + { + if (data.IsScalar() || data.IsSequence()) + { + return; // ??? + } + + for (const auto& pair : data) + { + if (!pair.first.IsScalar()) continue; + + // Find the key among existing nodes + const auto name = pair.first.Scalar(); + const auto found = static_cast(rhs).get_nodes().find(name); + + if (found != static_cast(rhs).get_nodes().cend()) + { + decode(pair.second, *found->second); + } + else + { + // ??? + } + } + + break; + } + case type::set: + { + std::vector values; + + if (YAML::convert::decode(data, values)) + { + rhs.from_list(std::move(values)); + } + + break; + } + default: + { + std::string value; + + if (YAML::convert::decode(data, value)) + { + rhs.from_string(value); + } + + break; // ??? + } + } +} + +std::string cfg::node::to_string() const +{ + YAML::Emitter out; + cfg::encode(out, *this); + + return{ out.c_str(), out.size() }; +} + +bool cfg::node::from_string(const std::string& value) +{ + cfg::decode(YAML::Load(value), *this); + return true; +} + +void cfg::node::from_default() +{ + for (auto& node : m_nodes) + { + node.second->from_default(); + } +} + +cfg::root_node& cfg::get_root() +{ + // Magic static + static root_node root; + return root; +} diff --git a/Utilities/Config.h b/Utilities/Config.h new file mode 100644 index 0000000000..203e959a30 --- /dev/null +++ b/Utilities/Config.h @@ -0,0 +1,523 @@ +#pragma once + +#include "Utilities/Atomic.h" +#include +#include + +namespace cfg +{ + // Convert string to signed integer + bool try_to_int64(s64* out, const std::string& value, s64 min, s64 max); + + // Config tree entry type. + enum class type : uint + { + node = 0, // cfg::node type + boolean, // cfg::bool_entry type + fixed_map, // cfg::map_entry type + enumeration, // cfg::enum_entry type + integer, // cfg::int_entry type + string, // cfg::string_entry type + set, // cfg::set_entry type + }; + + // Config tree entry abstract base class + class entry_base + { + const type m_type; + + protected: + // Ownerless entry constructor + entry_base(type _type); + + // Owned entry constructor + entry_base(type _type, class node& owner, const std::string& name); + + public: + // Disallow copy/move constructors and assignments + entry_base(const entry_base&) = delete; + + // Get type + type get_type() const { return m_type; } + + // Access child node (must exist) + entry_base& operator [](const std::string& name) const; entry_base& operator [](const char* name) const; + + // Reset defaults + virtual void from_default() = 0; + + // Convert to string (optional) + virtual std::string to_string() const + { + return{}; + } + + // Try to convert from string (optional) + virtual bool from_string(const std::string&) + { + throw std::logic_error("from_string() not specified"); + } + + // Get string list (optional) + virtual std::vector to_list() const + { + return{}; + } + + // Set multiple values. Implementation-specific, optional. + virtual bool from_list(std::vector&&) + { + throw std::logic_error("from_list() not specified"); + } + }; + + // Config tree node which contains another nodes + class node : public entry_base + { + std::map m_nodes; + + friend class entry_base; + + public: + // Root node constructor + node() + : entry_base(type::node) + { + } + + // Registered node constructor + node(node& owner, const std::string& name) + : entry_base(type::node, owner, name) + { + } + + // Get child nodes + const std::map& get_nodes() const + { + return m_nodes; + } + + // Serialize node + std::string to_string() const override; + + // Deserialize node + bool from_string(const std::string& value) override; + + // Set default values + void from_default() override; + }; + + struct bool_entry final : public entry_base + { + atomic_t value; + + const bool def; + + bool_entry(node& owner, const std::string& name, bool def = false) + : entry_base(type::boolean, owner, name) + , value(def) + , def(def) + { + } + + explicit operator bool() const + { + return value.load(); + } + + bool_entry& operator =(bool value) + { + value = value; + return *this; + } + + void from_default() override + { + value = def; + } + + std::string to_string() const override + { + return value.load() ? "true" : "false"; + } + + bool from_string(const std::string& value) override + { + if (value == "false") + this->value = false; + else if (value == "true") + this->value = true; + else + return false; + + return true; + } + }; + + // Value node with fixed set of possible values, each maps to a value of type T. + template + struct map_entry final : public entry_base + { + using init_type = std::initializer_list>; + using map_type = std::unordered_map; + using list_type = std::vector; + using value_type = typename map_type::value_type; + + static map_type make_map(init_type init) + { + map_type map(init.size()); + + for (const auto& v : init) + { + // Ensure elements are unique + ASSERT(map.emplace(v.first, v.second).second); + } + + return map; + } + + static list_type make_list(init_type init) + { + list_type list; list.reserve(init.size()); + + for (const auto& v : init) + { + list.emplace_back(v.first); + } + + return list; + } + + public: + const map_type map; + const list_type list; // Element list sorted in original order + const value_type& def; // Pointer to the default value + + private: + atomic_t m_value; + + public: + map_entry(node& owner, const std::string& name, const std::string& def, init_type init) + : entry_base(type::fixed_map, owner, name) + , map(make_map(init)) + , list(make_list(init)) + , def(*map.find(def)) + , m_value(&this->def) + { + } + + map_entry(node& owner, const std::string& name, std::size_t def_index, init_type init) + : map_entry(owner, name, def_index < init.size() ? (init.begin() + def_index)->first : throw std::logic_error("Invalid default value index"), init) + { + } + + map_entry(node& owner, const std::string& name, init_type init) + : map_entry(owner, name, 0, init) + { + } + + const T& get() const + { + return m_value.load()->second; + } + + void from_default() override + { + m_value = &def; + } + + std::string to_string() const override + { + return m_value.load()->first; + } + + bool from_string(const std::string& value) override + { + const auto found = map.find(value); + + if (found == map.end()) + { + return false; + } + else + { + m_value = &*found; + return true; + } + } + + std::vector to_list() const override + { + return list; + } + }; + + // Value node with fixed set of possible values, each maps to an enum value of type T. + template + class enum_entry final : public entry_base + { + // Value or reference + std::conditional_t&, atomic_t> m_value; + + public: + const T def; + + enum_entry(node& owner, const std::string& name, std::conditional_t&, T> value) + : entry_base(type::enumeration, owner, name) + , m_value(value) + , def(value) + { + } + + operator T() const + { + return m_value.load(); + } + + enum_entry& operator =(T value) + { + m_value = value; + return *this; + } + + void from_default() override + { + m_value = def; + } + + std::string to_string() const override + { + for (const auto& pair : bijective::map) + { + if (pair.first == m_value) + { + return pair.second; + } + } + + return{}; // TODO: ??? + } + + bool from_string(const std::string& value) override + { + for (const auto& pair : bijective::map) + { + if (pair.second == value) + { + m_value = pair.first; + return true; + } + } + + return false; + } + + std::vector to_list() const override + { + std::vector result; + + for (const auto& pair : bijective::map) + { + result.emplace_back(pair.second); + } + + return result; + } + }; + + // Signed 32/64-bit integer entry with custom Min/Max range. + template + class int_entry final : public entry_base + { + static_assert(Min < Max, "Invalid cfg::int_entry range"); + + // Prefer 32 bit type if possible + using int_type = std::conditional_t= INT32_MIN && Max <= INT32_MAX, s32, s64>; + + atomic_t m_value; + + public: + const int_type def; + + int_entry(node& owner, const std::string& name, int_type def = std::min(Max, std::max(Min, 0))) + : entry_base(type::integer, owner, name) + , m_value(def) + , def(def) + { + } + + operator int_type() const + { + return m_value.load(); + } + + int_entry& operator =(int_type value) + { + if (value < Min || value > Max) + { + throw fmt::exception("Value out of the valid range: %lld" HERE, s64{ value }); + } + + m_value = value; + return *this; + } + + void from_default() override + { + m_value = def; + } + + std::string to_string() const override + { + return std::to_string(m_value.load()); + } + + bool from_string(const std::string& value) override + { + s64 result; + if (try_to_int64(&result, value, Min, Max)) + { + m_value = static_cast(result); + return true; + } + + return false; + } + }; + + // Alias for 32 bit int + using int32_entry = int_entry; + + // Alias for 64 bit int + using int64_entry = int_entry; + + // Simple string entry with mutex + class string_entry final : public entry_base + { + mutable std::mutex m_mutex; + std::string m_value; + + public: + const std::string def; + + string_entry(node& owner, const std::string& name, const std::string& def = {}) + : entry_base(type::string, owner, name) + , m_value(def) + , def(def) + { + } + + operator std::string() const + { + std::lock_guard lock(m_mutex); + return m_value; + } + + std::string get() const + { + return *this; + } + + string_entry& operator =(const std::string& value) + { + std::lock_guard lock(m_mutex); + m_value = value; + return *this; + } + + std::size_t size() const + { + std::lock_guard lock(m_mutex); + return m_value.size(); + } + + void from_default() override + { + *this = def; + } + + std::string to_string() const override + { + std::lock_guard lock(m_mutex); + return m_value; + } + + bool from_string(const std::string& value) override + { + *this = value; + return true; + } + }; + + // Simple set entry with mutex (TODO: template for various types) + class set_entry final : public entry_base + { + mutable std::mutex m_mutex; + + std::set m_set; + + public: + // Default value is empty list in current implementation + set_entry(node& owner, const std::string& name) + : entry_base(type::set, owner, name) + { + } + + std::set get_set() const + { + std::lock_guard lock(m_mutex); + + return m_set; + } + + void set_set(std::set&& set) + { + std::lock_guard lock(m_mutex); + m_set = std::move(set); + } + + void from_default() override + { + std::lock_guard lock(m_mutex); + m_set = {}; + } + + std::vector to_list() const override + { + std::lock_guard lock(m_mutex); + + return{ m_set.begin(), m_set.end() }; + } + + bool from_list(std::vector&& list) override + { + std::lock_guard lock(m_mutex); + m_set = { std::make_move_iterator(list.begin()), std::make_move_iterator(list.end()) }; + + return true; + } + }; + + // Root type with some predefined nodes. Don't change it, this is not mandatory for adding nodes. + struct root_node : node + { + node core { *this, "Core" }; + node vfs { *this, "VFS" }; + node log { *this, "Log" }; + node video { *this, "Video" }; + node audio { *this, "Audio" }; + node io { *this, "Input/Output" }; + node sys { *this, "System" }; + node net { *this, "Net" }; + node misc { *this, "Miscellaneous" }; + }; + + // Get global configuration root instance + extern root_node& get_root(); + + // Global configuration root instance (cached reference) + static root_node& root = get_root(); +} + +// Registered log channel +#define LOG_CHANNEL(name) _log::channel name(#name, _log::level::notice); namespace _log { cfg::enum_entry<_log::level, true> name(cfg::root.log, #name, ::name.enabled); } diff --git a/Utilities/File.cpp b/Utilities/File.cpp index 9d3d4571e3..7581ccbde4 100644 --- a/Utilities/File.cpp +++ b/Utilities/File.cpp @@ -1,5 +1,8 @@ -#include "stdafx.h" #include "File.h" +#include "StrFmt.h" +#include "Macro.h" +#include "SharedMutex.h" +#include #ifdef _WIN32 @@ -12,13 +15,13 @@ static std::unique_ptr to_wchar(const std::string& source) { const auto buf_size = source.size() + 1; // size + null terminator - const int size = source.size() < INT_MAX ? static_cast(buf_size) : throw EXCEPTION("Invalid source length (0x%llx)", source.size()); + const int size = source.size() < INT_MAX ? static_cast(buf_size) : throw fmt::exception("to_wchar(): invalid source length (0x%llx)", source.size()); std::unique_ptr buffer(new wchar_t[buf_size]); // allocate buffer assuming that length is the max possible size if (!MultiByteToWideChar(CP_UTF8, 0, source.c_str(), size, buffer.get(), size)) { - throw EXCEPTION("MultiByteToWideChar() failed (0x%x).", GetLastError()); + throw fmt::exception("to_wchar(): MultiByteToWideChar() failed: error %u.", GetLastError()); } return buffer; @@ -28,7 +31,7 @@ static void to_utf8(std::string& result, const wchar_t* source) { const auto length = std::wcslen(source); - const int buf_size = length <= INT_MAX / 3 ? static_cast(length) * 3 + 1 : throw EXCEPTION("Invalid source length (0x%llx)", length); + const int buf_size = length <= INT_MAX / 3 ? static_cast(length) * 3 + 1 : throw fmt::exception("to_utf8(): invalid source length (0x%llx)", length); result.resize(buf_size); // set max possible length for utf-8 + null terminator @@ -38,7 +41,7 @@ static void to_utf8(std::string& result, const wchar_t* source) } else { - throw EXCEPTION("WideCharToMultiByte() failed (0x%x).", GetLastError()); + throw fmt::exception("to_utf8(): WideCharToMultiByte() failed: error %u.", GetLastError()); } } @@ -85,6 +88,68 @@ static time_t to_time(const FILETIME& ft) #endif +namespace fs +{ + class device_manager final + { + mutable shared_mutex m_mutex; + + std::unordered_map> m_map; + + public: + std::shared_ptr get_device(const std::string& name); + std::shared_ptr set_device(const std::string& name, const std::shared_ptr&); + }; + + static device_manager& get_device_manager() + { + // Use magic static + static device_manager instance; + return instance; + } +} + +safe_buffers std::shared_ptr fs::device_manager::get_device(const std::string& name) +{ + reader_lock lock(m_mutex); + + const auto found = m_map.find(name); + + if (found == m_map.end()) + { + return nullptr; + } + + return found->second; +} + +safe_buffers std::shared_ptr fs::device_manager::set_device(const std::string& name, const std::shared_ptr& device) +{ + std::lock_guard lock(m_mutex); + + return m_map[name] = device; +} + +safe_buffers std::shared_ptr fs::get_virtual_device(const std::string& path) +{ + // Every virtual device path must have "//" at the beginning + if (path.size() > 2 && reinterpret_cast(path.front()) == '//') + { + return get_device_manager().get_device(path.substr(0, path.find_first_of('/', 2))); + } + + return nullptr; +} + +safe_buffers std::shared_ptr fs::set_virtual_device(const std::string& name, const std::shared_ptr& device) +{ + Expects(name.size() > 2); + Expects(name[0] == '/'); + Expects(name[1] == '/'); + + return get_device_manager().set_device(name, device); +} + std::string fs::get_parent_dir(const std::string& path) { // Search upper bound (set to the last character, npos for empty string) @@ -112,32 +177,37 @@ std::string fs::get_parent_dir(const std::string& path) static const auto test_get_parent_dir = []() -> bool { // Success: - CHECK_ASSERTION(fs::get_parent_dir("/x/y///") == "/x"); - CHECK_ASSERTION(fs::get_parent_dir("/x/y/") == "/x"); - CHECK_ASSERTION(fs::get_parent_dir("/x/y") == "/x"); - CHECK_ASSERTION(fs::get_parent_dir("x:/y") == "x:"); - CHECK_ASSERTION(fs::get_parent_dir("//x/y") == "//x"); + ASSERT(fs::get_parent_dir("/x/y///") == "/x"); + ASSERT(fs::get_parent_dir("/x/y/") == "/x"); + ASSERT(fs::get_parent_dir("/x/y") == "/x"); + ASSERT(fs::get_parent_dir("x:/y") == "x:"); + ASSERT(fs::get_parent_dir("//x/y") == "//x"); // Failure: - CHECK_ASSERTION(fs::get_parent_dir("").empty()); - CHECK_ASSERTION(fs::get_parent_dir("x/").empty()); - CHECK_ASSERTION(fs::get_parent_dir("x").empty()); - CHECK_ASSERTION(fs::get_parent_dir("x///").empty()); - CHECK_ASSERTION(fs::get_parent_dir("/x/").empty()); - CHECK_ASSERTION(fs::get_parent_dir("/x").empty()); - CHECK_ASSERTION(fs::get_parent_dir("/").empty()); - CHECK_ASSERTION(fs::get_parent_dir("//").empty()); - CHECK_ASSERTION(fs::get_parent_dir("//x").empty()); - CHECK_ASSERTION(fs::get_parent_dir("//x/").empty()); - CHECK_ASSERTION(fs::get_parent_dir("///").empty()); - CHECK_ASSERTION(fs::get_parent_dir("///x").empty()); - CHECK_ASSERTION(fs::get_parent_dir("///x/").empty()); + ASSERT(fs::get_parent_dir("").empty()); + ASSERT(fs::get_parent_dir("x/").empty()); + ASSERT(fs::get_parent_dir("x").empty()); + ASSERT(fs::get_parent_dir("x///").empty()); + ASSERT(fs::get_parent_dir("/x/").empty()); + ASSERT(fs::get_parent_dir("/x").empty()); + ASSERT(fs::get_parent_dir("/").empty()); + ASSERT(fs::get_parent_dir("//").empty()); + ASSERT(fs::get_parent_dir("//x").empty()); + ASSERT(fs::get_parent_dir("//x/").empty()); + ASSERT(fs::get_parent_dir("///").empty()); + ASSERT(fs::get_parent_dir("///x").empty()); + ASSERT(fs::get_parent_dir("///x/").empty()); return false; }(); bool fs::stat(const std::string& path, stat_t& info) { + if (auto device = get_virtual_device(path)) + { + return device->stat(path, info); + } + #ifdef _WIN32 WIN32_FILE_ATTRIBUTE_DATA attrs; if (!GetFileAttributesExW(to_wchar(path).get(), GetFileExInfoStandard, &attrs)) @@ -147,7 +217,7 @@ bool fs::stat(const std::string& path, stat_t& info) { case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x (%s).", error, path); + default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } return false; @@ -179,6 +249,12 @@ bool fs::stat(const std::string& path, stat_t& info) bool fs::exists(const std::string& path) { + if (auto device = get_virtual_device(path)) + { + stat_t info; + return device->stat(path, info); + } + #ifdef _WIN32 if (GetFileAttributesW(to_wchar(path).get()) == INVALID_FILE_ATTRIBUTES) { @@ -187,7 +263,7 @@ bool fs::exists(const std::string& path) { case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x (%s).", error, path); + default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } return false; @@ -202,6 +278,23 @@ bool fs::exists(const std::string& path) bool fs::is_file(const std::string& path) { + if (auto device = get_virtual_device(path)) + { + stat_t info; + if (!device->stat(path, info)) + { + return false; + } + + if (info.is_directory) + { + errno = EEXIST; + return false; + } + + return true; + } + #ifdef _WIN32 const DWORD attrs = GetFileAttributesW(to_wchar(path).get()); if (attrs == INVALID_FILE_ATTRIBUTES) @@ -211,7 +304,7 @@ bool fs::is_file(const std::string& path) { case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x (%s).", error, path); + default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } return false; @@ -240,6 +333,23 @@ bool fs::is_file(const std::string& path) bool fs::is_dir(const std::string& path) { + if (auto device = get_virtual_device(path)) + { + stat_t info; + if (!device->stat(path, info)) + { + return false; + } + + if (info.is_directory == false) + { + errno = EEXIST; + return false; + } + + return true; + } + #ifdef _WIN32 const DWORD attrs = GetFileAttributesW(to_wchar(path).get()); if (attrs == INVALID_FILE_ATTRIBUTES) @@ -249,7 +359,7 @@ bool fs::is_dir(const std::string& path) { case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x (%s).", error, path); + default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } return false; @@ -277,6 +387,11 @@ bool fs::is_dir(const std::string& path) bool fs::create_dir(const std::string& path) { + if (auto device = get_virtual_device(path)) + { + return device->create_dir(path); + } + #ifdef _WIN32 if (!CreateDirectoryW(to_wchar(path).get(), NULL)) { @@ -285,7 +400,7 @@ bool fs::create_dir(const std::string& path) { case ERROR_ALREADY_EXISTS: errno = EEXIST; break; case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x (%s).", error, path); + default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } return false; @@ -311,6 +426,11 @@ bool fs::create_path(const std::string& path) bool fs::remove_dir(const std::string& path) { + if (auto device = get_virtual_device(path)) + { + return device->remove_dir(path); + } + #ifdef _WIN32 if (!RemoveDirectoryW(to_wchar(path).get())) { @@ -318,7 +438,7 @@ bool fs::remove_dir(const std::string& path) switch (DWORD error = GetLastError()) { case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x (%s).", error, path); + default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } return false; @@ -332,6 +452,18 @@ bool fs::remove_dir(const std::string& path) bool fs::rename(const std::string& from, const std::string& to) { + const auto device = get_virtual_device(from); + + if (device != get_virtual_device(to)) + { + throw fmt::exception("fs::rename() between different devices not implemented.\nFrom: %s\nTo: %s", from, to); + } + + if (device) + { + return device->rename(from, to); + } + #ifdef _WIN32 if (!MoveFileW(to_wchar(from).get(), to_wchar(to).get())) { @@ -339,7 +471,7 @@ bool fs::rename(const std::string& from, const std::string& to) switch (DWORD error = GetLastError()) { case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x.\nFrom: %s\nTo: %s", error, from, to); + default: throw fmt::exception("Unknown Win32 error: %u.\nFrom: %s\nTo: %s" HERE, error, from, to); } return false; @@ -353,6 +485,13 @@ bool fs::rename(const std::string& from, const std::string& to) bool fs::copy_file(const std::string& from, const std::string& to, bool overwrite) { + const auto device = get_virtual_device(from); + + if (device != get_virtual_device(to) || device) // TODO + { + throw fmt::exception("fs::copy_file() for virtual devices not implemented.\nFrom: %s\nTo: %s", from, to); + } + #ifdef _WIN32 if (!CopyFileW(to_wchar(from).get(), to_wchar(to).get(), !overwrite)) { @@ -360,7 +499,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit switch (DWORD error = GetLastError()) { case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x.\nFrom: %s\nTo: %s", error, from, to); + default: throw fmt::exception("Unknown Win32 error: %u.\nFrom: %s\nTo: %s" HERE, error, from, to); } return false; @@ -413,6 +552,11 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit bool fs::remove_file(const std::string& path) { + if (auto device = get_virtual_device(path)) + { + return device->remove(path); + } + #ifdef _WIN32 if (!DeleteFileW(to_wchar(path).get())) { @@ -421,7 +565,7 @@ bool fs::remove_file(const std::string& path) { case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x (%s).", error, path); + default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } return false; @@ -435,6 +579,11 @@ bool fs::remove_file(const std::string& path) bool fs::truncate_file(const std::string& path, u64 length) { + if (auto device = get_virtual_device(path)) + { + return device->trunc(path, length); + } + #ifdef _WIN32 // Open the file const auto handle = CreateFileW(to_wchar(path).get(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); @@ -445,7 +594,7 @@ bool fs::truncate_file(const std::string& path, u64 length) { case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x (%s).", error, path); + default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } return false; @@ -461,7 +610,7 @@ bool fs::truncate_file(const std::string& path, u64 length) switch (DWORD error = GetLastError()) { case ERROR_NEGATIVE_SEEK: errno = EINVAL; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x (length=0x%llx).", error, length); + default: throw fmt::exception("Unknown Win32 error: %u (length=0x%llx)." HERE, error, length); } CloseHandle(handle); @@ -475,51 +624,55 @@ bool fs::truncate_file(const std::string& path, u64 length) #endif } -fs::file::~file() +void fs::file::xnull() const { - if (m_fd != null) - { -#ifdef _WIN32 - CloseHandle((HANDLE)m_fd); -#else - ::close(m_fd); -#endif - } + throw std::logic_error("fs::file is null"); } -bool fs::file::open(const std::string& path, u32 mode) +void fs::file::xfail() const { - this->close(); + throw fmt::exception("Unexpected fs::file error %d", errno); +} -#ifdef _WIN32 - DWORD access = 0; - switch (mode & (fom::read | fom::write | fom::append)) +bool fs::file::open(const std::string& path, mset mode) +{ + if (auto device = get_virtual_device(path)) { - case fom::read: access |= GENERIC_READ; break; - case fom::read | fom::append: access |= GENERIC_READ; break; - case fom::write: access |= GENERIC_WRITE; break; - case fom::write | fom::append: access |= FILE_APPEND_DATA; break; - case fom::read | fom::write: access |= GENERIC_READ | GENERIC_WRITE; break; - case fom::read | fom::write | fom::append: access |= GENERIC_READ | FILE_APPEND_DATA; break; - } + if (auto&& _file = device->open(path, mode)) + { + m_file = std::move(_file); + return true; + } - DWORD disp = 0; - switch (mode & (fom::create | fom::trunc | fom::excl)) - { - case 0: disp = OPEN_EXISTING; break; - case fom::create: disp = OPEN_ALWAYS; break; - case fom::trunc: disp = TRUNCATE_EXISTING; break; - case fom::create | fom::trunc: disp = CREATE_ALWAYS; break; - case fom::create | fom::excl: disp = CREATE_NEW; break; - case fom::create | fom::excl | fom::trunc: disp = CREATE_NEW; break; - default: - errno = EINVAL; return false; } - m_fd = (std::intptr_t)CreateFileW(to_wchar(path).get(), access, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, disp, FILE_ATTRIBUTE_NORMAL, NULL); +#ifdef _WIN32 + DWORD access = 0; + if (mode & fs::read) access |= GENERIC_READ; + if (mode & fs::write) access |= mode & fs::append ? FILE_APPEND_DATA : GENERIC_WRITE; - if (m_fd == null) + DWORD disp = 0; + if (mode & fs::create) + { + disp = + mode & fs::excl ? CREATE_NEW : + mode & fs::trunc ? CREATE_ALWAYS : OPEN_ALWAYS; + } + else + { + if (mode & fs::excl) + { + errno = EINVAL; + return false; + } + + disp = mode & fs::trunc ? TRUNCATE_EXISTING : OPEN_EXISTING; + } + + const HANDLE handle = CreateFileW(to_wchar(path).get(), access, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, disp, FILE_ATTRIBUTE_NORMAL, NULL); + + if (handle == INVALID_HANDLE_VALUE) { // TODO: convert Win32 error code to errno switch (DWORD error = GetLastError()) @@ -527,457 +680,639 @@ bool fs::file::open(const std::string& path, u32 mode) case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; case ERROR_FILE_EXISTS: errno = EEXIST; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x (%s).", error, path); + default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); } return false; } - return true; + class windows_file final : public file_base + { + const HANDLE m_handle; + + public: + windows_file(HANDLE handle) + : m_handle(handle) + { + } + + ~windows_file() override + { + CloseHandle(m_handle); + } + + stat_t stat() override + { + FILE_BASIC_INFO basic_info; + if (!GetFileInformationByHandleEx(m_handle, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO))) + { + // TODO: convert Win32 error code to errno + switch (DWORD error = GetLastError()) + { + case 0: + default: throw fmt::exception("Win32 error: %u." HERE, error); + } + } + + stat_t info; + info.is_directory = (basic_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + info.is_writable = (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0; + info.size = this->size(); + info.atime = to_time(basic_info.LastAccessTime); + info.mtime = to_time(basic_info.ChangeTime); + info.ctime = to_time(basic_info.CreationTime); + + return info; + } + + bool trunc(u64 length) override + { + LARGE_INTEGER old, pos; + + pos.QuadPart = 0; + if (!SetFilePointerEx(m_handle, pos, &old, FILE_CURRENT)) // get old position + { + // TODO: convert Win32 error code to errno + switch (DWORD error = GetLastError()) + { + case 0: + default: throw fmt::exception("Unknown Win32 error: %u." HERE, error); + } + + return false; + } + + pos.QuadPart = length; + if (!SetFilePointerEx(m_handle, pos, NULL, FILE_BEGIN)) // set new position + { + // TODO: convert Win32 error code to errno + switch (DWORD error = GetLastError()) + { + case ERROR_NEGATIVE_SEEK: errno = EINVAL; break; + default: throw fmt::exception("Unknown Win32 error: %u." HERE, error); + } + + return false; + } + + const BOOL result = SetEndOfFile(m_handle); // change file size + + if (!result) + { + // TODO: convert Win32 error code to errno + switch (DWORD error = GetLastError()) + { + case 0: + default: throw fmt::exception("Unknown Win32 error: %u." HERE, error); + } + } + + if (!SetFilePointerEx(m_handle, old, NULL, FILE_BEGIN) && result) // restore position + { + if (DWORD error = GetLastError()) + { + throw fmt::exception("Win32 error: %u." HERE, error); + } + } + + return result != FALSE; + } + + u64 read(void* buffer, u64 count) override + { + // TODO (call ReadFile multiple times if count is too big) + const int size = ::narrow(count, "Too big count" HERE); + Expects(size >= 0); + + DWORD nread; + if (!ReadFile(m_handle, buffer, size, &nread, NULL)) + { + switch (DWORD error = GetLastError()) + { + case 0: + default: throw fmt::exception("Win32 error: %u." HERE, error); + } + } + + return nread; + } + + u64 write(const void* buffer, u64 count) override + { + // TODO (call WriteFile multiple times if count is too big) + const int size = ::narrow(count, "Too big count" HERE); + Expects(size >= 0); + + DWORD nwritten; + if (!WriteFile(m_handle, buffer, size, &nwritten, NULL)) + { + switch (DWORD error = GetLastError()) + { + case 0: + default: throw fmt::exception("Win32 error: %u." HERE, error); + } + } + + return nwritten; + } + + u64 seek(s64 offset, seek_mode whence) override + { + LARGE_INTEGER pos; + pos.QuadPart = offset; + + const DWORD mode = + whence == seek_set ? FILE_BEGIN : + whence == seek_cur ? FILE_CURRENT : + whence == seek_end ? FILE_END : + throw fmt::exception("Invalid whence (0x%x)" HERE, whence); + + if (!SetFilePointerEx(m_handle, pos, &pos, mode)) + { + switch (DWORD error = GetLastError()) + { + case 0: + default: throw fmt::exception("Win32 error: %u." HERE, error); + } + } + + return pos.QuadPart; + } + + u64 size() override + { + LARGE_INTEGER size; + if (!GetFileSizeEx(m_handle, &size)) + { + switch (DWORD error = GetLastError()) + { + case 0: + default: throw fmt::exception("Win32 error: %u." HERE, error); + } + } + + return size.QuadPart; + } + }; + + m_file = std::make_unique(handle); #else int flags = 0; - switch (mode & (fom::read | fom::write)) + if (mode & fs::read && mode & fs::write) flags |= O_RDWR; + else if (mode & fs::read) flags |= O_RDONLY; + else if (mode & fs::write) flags |= O_WRONLY; + + if (mode & fs::append) flags |= O_APPEND; + if (mode & fs::create) flags |= O_CREAT; + if (mode & fs::trunc) flags |= O_TRUNC; + if (mode & fs::excl) flags |= O_EXCL; + + const int fd = ::open(path.c_str(), flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + + if (fd == -1) { - case fom::read: flags |= O_RDONLY; break; - case fom::write: flags |= O_WRONLY; break; - case fom::read | fom::write: flags |= O_RDWR; break; - } - - if (mode & fom::append) flags |= O_APPEND; - if (mode & fom::create) flags |= O_CREAT; - if (mode & fom::trunc) flags |= O_TRUNC; - if (mode & fom::excl) flags |= O_EXCL; - - m_fd = ::open(path.c_str(), flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - - return m_fd != null; -#endif -} - -bool fs::file::trunc(u64 size) const -{ -#ifdef _WIN32 - LARGE_INTEGER old, pos; - - pos.QuadPart = 0; - if (!SetFilePointerEx((HANDLE)m_fd, pos, &old, FILE_CURRENT)) // get old position - { - switch (DWORD error = GetLastError()) - { - case ERROR_INVALID_HANDLE: errno = EBADF; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x.", error); - } - + // TODO: errno return false; } - pos.QuadPart = size; - if (!SetFilePointerEx((HANDLE)m_fd, pos, NULL, FILE_BEGIN)) // set new position + class unix_file final : public file_base { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) + const int m_fd; + + public: + unix_file(int fd) + : m_fd(fd) { - case ERROR_NEGATIVE_SEEK: errno = EINVAL; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x.", error); } - return false; - } - - const BOOL result = SetEndOfFile((HANDLE)m_fd); // change file size - - if (!result) - { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) + ~unix_file() override { - case 0: - default: throw EXCEPTION("Unknown Win32 error: 0x%x.", error); - } - } - - if (!SetFilePointerEx((HANDLE)m_fd, old, NULL, FILE_BEGIN) && result) // restore position - { - if (DWORD error = GetLastError()) - { - throw EXCEPTION("Unknown Win32 error: 0x%x.", error); - } - } - - return result != FALSE; -#else - return !::ftruncate(m_fd, size); -#endif -} - -bool fs::file::stat(stat_t& info) const -{ -#ifdef _WIN32 - FILE_BASIC_INFO basic_info; - if (!GetFileInformationByHandleEx((HANDLE)m_fd, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO))) - { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_INVALID_HANDLE: errno = EBADF; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x.", error); + ::close(m_fd); } - return false; - } - - info.is_directory = (basic_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; - info.is_writable = (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0; - info.size = this->size(); - info.atime = to_time(basic_info.LastAccessTime); - info.mtime = to_time(basic_info.ChangeTime); - info.ctime = to_time(basic_info.CreationTime); -#else - struct ::stat file_info; - if (::fstat(m_fd, &file_info) < 0) - { - return false; - } - - info.is_directory = S_ISDIR(file_info.st_mode); - info.is_writable = file_info.st_mode & 0200; // HACK: approximation - info.size = file_info.st_size; - info.atime = file_info.st_atime; - info.mtime = file_info.st_mtime; - info.ctime = file_info.st_ctime; -#endif - - return true; -} - -void fs::file::close() -{ - if (m_fd == null) - { - return /*true*/; - } - - const auto fd = m_fd; - m_fd = null; - -#ifdef _WIN32 - if (!CloseHandle((HANDLE)fd)) - { - throw EXCEPTION("CloseHandle() failed (fd=0x%llx, 0x%x)", fd, GetLastError()); - } -#else - if (::close(fd) != 0) - { - throw EXCEPTION("close() failed (fd=0x%llx, errno=%d)", fd, errno); - } -#endif -} - -u64 fs::file::read(void* buffer, u64 count) const -{ - // TODO (call ReadFile multiple times if count is too big) - const int size = count <= INT_MAX ? static_cast(count) : throw EXCEPTION("Invalid count (0x%llx)", count); - -#ifdef _WIN32 - DWORD nread; - if (!ReadFile((HANDLE)m_fd, buffer, size, &nread, NULL)) - { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) + stat_t stat() override { - case ERROR_INVALID_HANDLE: errno = EBADF; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x.", error); + struct ::stat file_info; + if (::fstat(m_fd, &file_info) != 0) + { + switch (int error = errno) + { + case 0: + default: throw fmt::exception("Unknown error: %d." HERE, error); + } + } + + stat_t info; + info.is_directory = S_ISDIR(file_info.st_mode); + info.is_writable = file_info.st_mode & 0200; // HACK: approximation + info.size = file_info.st_size; + info.atime = file_info.st_atime; + info.mtime = file_info.st_mtime; + info.ctime = file_info.st_ctime; + + return info; } - return -1; - } - - return nread; -#else - return ::read(m_fd, buffer, size); -#endif -} - -u64 fs::file::write(const void* buffer, u64 count) const -{ - // TODO (call WriteFile multiple times if count is too big) - const int size = count <= INT_MAX ? static_cast(count) : throw EXCEPTION("Invalid count (0x%llx)", count); - -#ifdef _WIN32 - DWORD nwritten; - if (!WriteFile((HANDLE)m_fd, buffer, size, &nwritten, NULL)) - { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) + bool trunc(u64 length) override { - case ERROR_INVALID_HANDLE: errno = EBADF; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x.", error); - } + if (::ftruncate(m_fd, length) != 0) + { + switch (int error = errno) + { + case 0: + default: throw fmt::exception("Unknown error: %d." HERE, error); + } - return -1; - } + return false; + } - return nwritten; -#else - return ::write(m_fd, buffer, size); -#endif -} - -u64 fs::file::seek(s64 offset, seek_mode whence) const -{ -#ifdef _WIN32 - LARGE_INTEGER pos; - pos.QuadPart = offset; - - DWORD mode; - switch (whence) - { - case seek_set: mode = FILE_BEGIN; break; - case seek_cur: mode = FILE_CURRENT; break; - case seek_end: mode = FILE_END; break; - default: - { - errno = EINVAL; - return -1; - } - } - - if (!SetFilePointerEx((HANDLE)m_fd, pos, &pos, mode)) - { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_INVALID_HANDLE: errno = EBADF; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x.", error); - } - - return -1; - } - - return pos.QuadPart; -#else - int mode; - switch (whence) - { - case seek_set: mode = SEEK_SET; break; - case seek_cur: mode = SEEK_CUR; break; - case seek_end: mode = SEEK_END; break; - default: - { - errno = EINVAL; - return -1; - } - } - - return ::lseek(m_fd, offset, mode); -#endif -} - -u64 fs::file::size() const -{ -#ifdef _WIN32 - LARGE_INTEGER size; - if (!GetFileSizeEx((HANDLE)m_fd, &size)) - { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_INVALID_HANDLE: errno = EBADF; break; - default: throw EXCEPTION("Unknown Win32 error: 0x%x.", error); - } - - return -1; - } - - return size.QuadPart; -#else - struct ::stat file_info; - if (::fstat(m_fd, &file_info) != 0) - { - return -1; - } - - return file_info.st_size; -#endif -} - -fs::dir::~dir() -{ - if (m_path) - { -#ifdef _WIN32 - if (m_dd != -1) FindClose((HANDLE)m_dd); -#else - ::closedir((DIR*)m_dd); -#endif - } -} - -void fs::file_read_map::reset(const file& f) -{ - reset(); - - if (f) - { -#ifdef _WIN32 - const HANDLE handle = ::CreateFileMapping((HANDLE)f.m_fd, NULL, PAGE_READONLY, 0, 0, NULL); - m_ptr = (char*)::MapViewOfFile(handle, FILE_MAP_READ, 0, 0, 0); - m_size = f.size(); - ::CloseHandle(handle); -#else - m_ptr = (char*)::mmap(nullptr, m_size = f.size(), PROT_READ, MAP_SHARED, f.m_fd, 0); - if (m_ptr == (void*)-1) m_ptr = nullptr; -#endif - } -} - -void fs::file_read_map::reset() -{ - if (m_ptr) - { -#ifdef _WIN32 - ::UnmapViewOfFile(m_ptr); -#else - ::munmap(m_ptr, m_size); -#endif - } -} - -bool fs::dir::open(const std::string& dirname) -{ - this->close(); - -#ifdef _WIN32 - if (!is_dir(dirname)) - { - return false; - } - - m_dd = -1; -#else - const auto ptr = ::opendir(dirname.c_str()); - if (!ptr) - { - return false; - } - - m_dd = reinterpret_cast(ptr); -#endif - - m_path.reset(new char[dirname.size() + 1]); - std::memcpy(m_path.get(), dirname.c_str(), dirname.size() + 1); - - return true; -} - -void fs::dir::close() -{ - if (!m_path) - { - return /*true*/; - } - - m_path.reset(); - -#ifdef _WIN32 - CHECK_ASSERTION(m_dd == -1 || FindClose((HANDLE)m_dd)); -#else - CHECK_ASSERTION(!::closedir((DIR*)m_dd)); -#endif -} - -bool fs::dir::read(std::string& name, stat_t& info) -{ - if (!m_path) - { - errno = EINVAL; - return false; - } - -#ifdef _WIN32 - const bool is_first = m_dd == -1; - - WIN32_FIND_DATAW found; - - if (is_first) - { - m_dd = (std::intptr_t)FindFirstFileW(to_wchar(m_path.get() + "/*"s).get(), &found); - } - - if (is_first && m_dd == -1 || !is_first && !FindNextFileW((HANDLE)m_dd, &found)) - { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_NO_MORE_FILES: - { - name.clear(); return true; } - default: throw EXCEPTION("Unknown Win32 error: 0x%x.", error); + u64 read(void* buffer, u64 count) override + { + const auto result = ::read(m_fd, buffer, count); + if (result == -1) + { + switch (int error = errno) + { + case 0: + default: throw fmt::exception("Unknown error: %d." HERE, error); + } + } + + return result; } - return false; - } + u64 write(const void* buffer, u64 count) override + { + const auto result = ::write(m_fd, buffer, count); + if (result == -1) + { + switch (int error = errno) + { + case 0: + default: throw fmt::exception("Unknown error: %d." HERE, error); + } + } - to_utf8(name, found.cFileName); + return result; + } - info.is_directory = (found.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; - info.is_writable = (found.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0; - info.size = ((u64)found.nFileSizeHigh << 32) | (u64)found.nFileSizeLow; - info.atime = to_time(found.ftLastAccessTime); - info.mtime = to_time(found.ftLastWriteTime); - info.ctime = to_time(found.ftCreationTime); -#else - const auto found = ::readdir((DIR*)m_dd); - if (!found) - { - name.clear(); - return true; - } + u64 seek(s64 offset, seek_mode whence) override + { + const int mode = + whence == seek_set ? SEEK_SET : + whence == seek_cur ? SEEK_CUR : + whence == seek_end ? SEEK_END : + throw fmt::exception("Invalid whence (0x%x)" HERE, whence); - struct ::stat file_info; - if (::fstatat(::dirfd((DIR*)m_dd), found->d_name, &file_info, 0) != 0) - { - return false; - } + const auto result = ::lseek(m_fd, offset, mode); + if (result == -1) + { + switch (int error = errno) + { + case 0: + default: throw fmt::exception("Unknown error: %d." HERE, error); + } + } - name = found->d_name; + return result; + } - info.is_directory = S_ISDIR(file_info.st_mode); - info.is_writable = file_info.st_mode & 0200; // HACK: approximation - info.size = file_info.st_size; - info.atime = file_info.st_atime; - info.mtime = file_info.st_mtime; - info.ctime = file_info.st_ctime; + u64 size() override + { + struct ::stat file_info; + if (::fstat(m_fd, &file_info) != 0) + { + switch (int error = errno) + { + case 0: + default: throw fmt::exception("Unknown error: %d." HERE, error); + } + } + + return file_info.st_size; + } + }; + + m_file = std::make_unique(fd); #endif return true; } -bool fs::dir::first(std::string& name, stat_t& info) +fs::file::file(const void* ptr, std::size_t size) { + class memory_stream final : public file_base + { + u64 m_pos = 0; + u64 m_size; + + public: + const char* const ptr; + + memory_stream(const void* ptr, std::size_t size) + : m_size(size) + , ptr(static_cast(ptr)) + { + } + + fs::stat_t stat() override + { + throw std::logic_error("memory_stream doesn't support stat()"); + } + + bool trunc(u64 length) override + { + throw std::logic_error("memory_stream doesn't support trunc()"); + } + + u64 read(void* buffer, u64 count) override + { + const u64 start = m_pos; + const u64 end = seek(count, fs::seek_cur); + const u64 read_size = end >= start ? end - start : throw std::logic_error("memory_stream::read(): overflow"); + std::memcpy(buffer, ptr + start, read_size); + return read_size; + } + + u64 write(const void* buffer, u64 count) override + { + throw std::logic_error("memory_stream is not writable"); + } + + u64 seek(s64 offset, fs::seek_mode whence) override + { + return m_pos = + whence == fs::seek_set ? std::min(offset, m_size) : + whence == fs::seek_cur ? std::min(offset + m_pos, m_size) : + whence == fs::seek_end ? std::min(offset + m_size, m_size) : + throw std::logic_error("memory_stream::seek(): invalid whence"); + } + + u64 size() override + { + return m_size; + } + }; + + m_file = std::make_unique(ptr, size); +} + +fs::file::file(std::vector& vec) +{ + class vector_stream final : public file_base + { + u64 m_pos = 0; + + public: + std::vector& vec; + + vector_stream(std::vector& vec) + : vec(vec) + { + } + + fs::stat_t stat() override + { + throw std::logic_error("vector_stream doesn't support stat()"); + } + + bool trunc(u64 length) override + { + vec.resize(length); + return true; + } + + u64 read(void* buffer, u64 count) override + { + const u64 start = m_pos; + const u64 end = seek(count, fs::seek_cur); + const u64 read_size = end >= start ? end - start : throw std::logic_error("vector_stream::read(): overflow"); + std::memcpy(buffer, vec.data() + start, read_size); + return read_size; + } + + u64 write(const void* buffer, u64 count) override + { + throw std::logic_error("TODO: vector_stream doesn't support write()"); + } + + u64 seek(s64 offset, fs::seek_mode whence) override + { + return m_pos = + whence == fs::seek_set ? std::min(offset, vec.size()) : + whence == fs::seek_cur ? std::min(offset + m_pos, vec.size()) : + whence == fs::seek_end ? std::min(offset + vec.size(), vec.size()) : + throw std::logic_error("vector_stream::seek(): invalid whence"); + } + + u64 size() override + { + return vec.size(); + } + }; + + m_file = std::make_unique(vec); +} + +//void fs::file_read_map::reset(const file& f) +//{ +// reset(); +// +// if (f) +// { +//#ifdef _WIN32 +// const HANDLE handle = ::CreateFileMapping((HANDLE)f.m_fd, NULL, PAGE_READONLY, 0, 0, NULL); +// m_ptr = (char*)::MapViewOfFile(handle, FILE_MAP_READ, 0, 0, 0); +// m_size = f.size(); +// ::CloseHandle(handle); +//#else +// m_ptr = (char*)::mmap(nullptr, m_size = f.size(), PROT_READ, MAP_SHARED, f.m_fd, 0); +// if (m_ptr == (void*)-1) m_ptr = nullptr; +//#endif +// } +//} +// +//void fs::file_read_map::reset() +//{ +// if (m_ptr) +// { +//#ifdef _WIN32 +// ::UnmapViewOfFile(m_ptr); +//#else +// ::munmap(m_ptr, m_size); +//#endif +// } +//} + +void fs::dir::xnull() const +{ + throw std::logic_error("fs::dir is null"); +} + +bool fs::dir::open(const std::string& path) +{ + if (auto device = get_virtual_device(path)) + { + if (auto&& _dir = device->open_dir(path)) + { + m_dir = std::move(_dir); + return true; + } + + return false; + } + #ifdef _WIN32 - if (m_path && m_dd != -1) + WIN32_FIND_DATAW found; + const auto handle = FindFirstFileW(to_wchar(path + "/*").get(), &found); + + if (handle == INVALID_HANDLE_VALUE) { - CHECK_ASSERTION(FindClose((HANDLE)m_dd)); - m_dd = -1; + // TODO: convert Win32 error code to errno + switch (DWORD error = GetLastError()) + { + case ERROR_FILE_NOT_FOUND: errno = ENOENT; break; + case ERROR_PATH_NOT_FOUND: errno = ENOENT; break; + default: throw fmt::exception("Unknown Win32 error: %u." HERE, error); + } + + return false; } + + class windows_dir final : public dir_base + { + const HANDLE m_handle; + + std::vector m_entries; + std::size_t m_pos = 0; + + void add_entry(const WIN32_FIND_DATAW& found) + { + dir_entry info; + + to_utf8(info.name, found.cFileName); + info.is_directory = (found.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + info.is_writable = (found.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0; + info.size = ((u64)found.nFileSizeHigh << 32) | (u64)found.nFileSizeLow; + info.atime = to_time(found.ftLastAccessTime); + info.mtime = to_time(found.ftLastWriteTime); + info.ctime = to_time(found.ftCreationTime); + + m_entries.emplace_back(std::move(info)); + } + + public: + windows_dir(HANDLE handle, const WIN32_FIND_DATAW& found) + : m_handle(handle) + { + add_entry(found); + } + + ~windows_dir() + { + FindClose(m_handle); + } + + bool read(dir_entry& out) override + { + if (m_pos == m_entries.size()) + { + WIN32_FIND_DATAW found; + if (!FindNextFileW(m_handle, &found)) + { + switch (DWORD error = GetLastError()) + { + case ERROR_NO_MORE_FILES: return false; + default: throw fmt::exception("Unknown Win32 error: %u." HERE, error); + } + } + + add_entry(found); + } + + out = m_entries[m_pos++]; + return true; + } + + void rewind() override + { + m_pos = 0; + } + }; + + m_dir = std::make_unique(handle, found); #else - if (m_path) + ::DIR* const ptr = ::opendir(path.c_str()); + + if (!ptr) { - ::rewinddir((DIR*)m_dd); + // TODO: errno + return false; } + + class unix_dir final : public dir_base + { + ::DIR* m_dd; + + public: + unix_dir(::DIR* dd) + : m_dd(dd) + { + } + + ~unix_dir() override + { + ::closedir(m_dd); + } + + bool read(dir_entry& info) override + { + const auto found = ::readdir(m_dd); + if (!found) + { + return false; + } + + struct ::stat file_info; + if (::fstatat(::dirfd(m_dd), found->d_name, &file_info, 0) != 0) + { + switch (int error = errno) + { + case 0: + default: throw fmt::exception("Unknown error: %d." HERE, error); + } + } + + info.name = found->d_name; + info.is_directory = S_ISDIR(file_info.st_mode); + info.is_writable = file_info.st_mode & 0200; // HACK: approximation + info.size = file_info.st_size; + info.atime = file_info.st_atime; + info.mtime = file_info.st_mtime; + info.ctime = file_info.st_ctime; + + return true; + } + + void rewind() override + { + ::rewinddir(m_dd); + } + }; + + m_dir = std::make_unique(ptr); #endif - return read(name, info); + return true; } const std::string& fs::get_config_dir() { - // Use magic static for dir initialization + // Use magic static static const std::string s_dir = [] { #ifdef _WIN32 @@ -1009,7 +1344,7 @@ const std::string& fs::get_config_dir() const std::string& fs::get_executable_dir() { - // Use magic static for dir initialization + // Use magic static static const std::string s_dir = [] { std::string dir; @@ -1018,7 +1353,7 @@ const std::string& fs::get_executable_dir() wchar_t buf[2048]; if (GetModuleFileName(NULL, buf, ::size32(buf)) - 1 >= ::size32(buf) - 1) { - MessageBoxA(0, fmt::format("GetModuleFileName() failed (0x%x).", GetLastError()).c_str(), "fs::get_config_dir()", MB_ICONERROR); + MessageBoxA(0, fmt::format("GetModuleFileName() failed: error %u.", GetLastError()).c_str(), "fs::get_config_dir()", MB_ICONERROR); return dir; // empty } @@ -1055,3 +1390,51 @@ const std::string& fs::get_executable_dir() return s_dir; } + +void fs::remove_all(const std::string& path) +{ + for (const auto& entry : dir(path)) + { + if (entry.name == "." || entry.name == "..") + { + continue; + } + + if (entry.is_directory == false) + { + remove_file(path + '/' + entry.name); + } + + if (entry.is_directory == true) + { + remove_all(path + '/' + entry.name); + } + } + + remove_dir(path); +} + +u64 fs::get_dir_size(const std::string& path) +{ + u64 result = 0; + + for (const auto entry : dir(path)) + { + if (entry.name == "." || entry.name == "..") + { + continue; + } + + if (entry.is_directory == false) + { + result += entry.size; + } + + if (entry.is_directory == true) + { + result += get_dir_size(path + '/' + entry.name); + } + } + + return result; +} diff --git a/Utilities/File.h b/Utilities/File.h index 36af62704f..7a0605b872 100644 --- a/Utilities/File.h +++ b/Utilities/File.h @@ -1,29 +1,47 @@ #pragma once -namespace fom // file open mode -{ - enum open_mode : u32 - { - read = 1 << 0, // enable reading - write = 1 << 1, // enable writing - append = 1 << 2, // enable appending (always write to the end of file) - create = 1 << 3, // create file if it doesn't exist - trunc = 1 << 4, // clear opened file if it's not empty - excl = 1 << 5, // failure if the file already exists (used with `create`) +#include +#include +#include +#include - rewrite = write | create | trunc, - }; -}; +#include "types.h" namespace fs { - enum seek_mode : u32 // file seek mode + // File open mode flags + enum struct open_mode : u32 + { + read, + write, + append, + create, + trunc, + excl, + }; + + constexpr mset read = open_mode::read; // Enable reading + constexpr mset write = open_mode::write; // Enable writing + constexpr mset append = open_mode::append; // Always append to the end of the file + constexpr mset create = open_mode::create; // Create file if it doesn't exist + constexpr mset trunc = open_mode::trunc; // Clear opened file if it's not empty + constexpr mset excl = open_mode::excl; // Failure if the file already exists (used with `create`) + + constexpr mset rewrite = write + create + trunc; + + // File seek mode + enum class seek_mode : u32 { seek_set, seek_cur, seek_end, }; + constexpr auto seek_set = seek_mode::seek_set; // From beginning + constexpr auto seek_cur = seek_mode::seek_cur; // From current position + constexpr auto seek_end = seek_mode::seek_end; // From end + + // File attributes (TODO) struct stat_t { bool is_directory; @@ -34,7 +52,57 @@ namespace fs s64 ctime; }; - // Get parent directory for the path (returns empty string on failure) + // File handle base + struct file_base + { + virtual ~file_base() = default; + + virtual stat_t stat() = 0; + virtual bool trunc(u64 length) = 0; + virtual u64 read(void* buffer, u64 size) = 0; + virtual u64 write(const void* buffer, u64 size) = 0; + virtual u64 seek(s64 offset, seek_mode whence) = 0; + virtual u64 size() = 0; + }; + + // Directory entry (TODO) + struct dir_entry : stat_t + { + std::string name; + }; + + // Directory handle base + struct dir_base + { + virtual ~dir_base() = default; + + virtual bool read(dir_entry&) = 0; + virtual void rewind() = 0; + }; + + // Virtual device + struct device_base + { + virtual ~device_base() = default; + + virtual bool stat(const std::string& path, stat_t& info) = 0; + virtual bool remove_dir(const std::string& path) = 0; + virtual bool create_dir(const std::string& path) = 0; + virtual bool rename(const std::string& from, const std::string& to) = 0; + virtual bool remove(const std::string& path) = 0; + virtual bool trunc(const std::string& path, u64 length) = 0; + + virtual std::unique_ptr open(const std::string& path, mset mode) = 0; + virtual std::unique_ptr open_dir(const std::string& path) = 0; + }; + + // Get virtual device for specified path (nullptr for real path) + std::shared_ptr get_virtual_device(const std::string& path); + + // Set virtual device with specified name (nullptr for deletion) + std::shared_ptr set_virtual_device(const std::string& root_name, const std::shared_ptr&); + + // Try to get parent directory (returns empty string on failure) std::string get_parent_dir(const std::string& path); // Get file information @@ -72,77 +140,105 @@ namespace fs class file final { - using handle_type = std::intptr_t; + std::unique_ptr m_file; - constexpr static handle_type null = -1; - - handle_type m_fd = null; - - friend class file_read_map; - friend class file_write_map; + [[noreturn]] void xnull() const; + [[noreturn]] void xfail() const; public: + // Default constructor file() = default; - explicit file(const std::string& path, u32 mode = fom::read) + // Open file with specified mode + explicit file(const std::string& path, mset mode = ::fs::read) { open(path, mode); } - file(file&& other) - : m_fd(other.m_fd) - { - other.m_fd = null; - } + // Open file with specified mode + bool open(const std::string& path, mset mode = ::fs::read); - file& operator =(file&& right) - { - std::swap(m_fd, right.m_fd); - return *this; - } + // Open memory for read + explicit file(const void* ptr, std::size_t size); - ~file(); - - // Check whether the handle is valid (opened file) - bool is_opened() const - { - return m_fd != null; - } + // Open vector + explicit file(std::vector& vec); // Check whether the handle is valid (opened file) explicit operator bool() const { - return is_opened(); + return m_file.operator bool(); } - // Open specified file with specified mode - bool open(const std::string& path, u32 mode = fom::read); + // Close the file explicitly + void close() + { + m_file.reset(); + } + + void reset(std::unique_ptr&& ptr) + { + m_file = std::move(ptr); + } + + std::unique_ptr release() + { + return std::move(m_file); + } // Change file size (possibly appending zero bytes) - bool trunc(u64 size) const; + bool trunc(u64 length) const + { + if (!m_file) xnull(); + return m_file->trunc(length); + } // Get file information - bool stat(stat_t& info) const; - - // Close the file explicitly (destructor automatically closes the file) - void close(); + stat_t stat() const + { + if (!m_file) xnull(); + return m_file->stat(); + } // Read the data from the file and return the amount of data written in buffer - u64 read(void* buffer, u64 count) const; + u64 read(void* buffer, u64 count) const + { + if (!m_file) xnull(); + return m_file->read(buffer, count); + } // Write the data to the file and return the amount of data actually written - u64 write(const void* buffer, u64 count) const; + u64 write(const void* buffer, u64 count) const + { + if (!m_file) xnull(); + return m_file->write(buffer, count); + } - // Move file pointer - u64 seek(s64 offset, seek_mode whence = seek_set) const; + // Change current position, returns previous position + u64 seek(s64 offset, seek_mode whence = seek_set) const + { + if (!m_file) xnull(); + return m_file->seek(offset, whence); + } // Get file size - u64 size() const; + u64 size() const + { + if (!m_file) xnull(); + return m_file->size(); + } + + // Get current position + u64 pos() const + { + if (!m_file) xnull(); + return m_file->seek(0, seek_cur); + } // Write std::string unconditionally const file& write(const std::string& str) const { - CHECK_ASSERTION(write(str.data(), str.size()) == str.size()); + if (write(str.data(), str.size()) != str.size()) xfail(); return *this; } @@ -150,7 +246,7 @@ namespace fs template std::enable_if_t::value && !std::is_pointer::value, const file&> write(const T& data) const { - CHECK_ASSERTION(write(std::addressof(data), sizeof(T)) == sizeof(T)); + if (write(std::addressof(data), sizeof(T)) != sizeof(T)) xfail(); return *this; } @@ -158,7 +254,7 @@ namespace fs template std::enable_if_t::value && !std::is_pointer::value, const file&> write(const std::vector& vec) const { - CHECK_ASSERTION(write(vec.data(), vec.size() * sizeof(T)) == vec.size() * sizeof(T)); + if (write(vec.data(), vec.size() * sizeof(T)) != vec.size() * sizeof(T)) xfail(); return *this; } @@ -187,7 +283,7 @@ namespace fs std::enable_if_t::value && !std::is_pointer::value, T> read() const { T result; - CHECK_ASSERTION(read(result)); + if (!read(result)) xfail(); return result; } @@ -196,7 +292,7 @@ namespace fs { std::string result; result.resize(size()); - CHECK_ASSERTION(seek(0) != -1 && read(result)); + if (seek(0), !read(result)) xfail(); return result; } @@ -206,164 +302,69 @@ namespace fs { std::vector result; result.resize(size() / sizeof(T)); - CHECK_ASSERTION(seek(0) != -1 && read(result)); + if (seek(0), !read(result)) xfail(); return result; } }; - // TODO - class file_read_map final - { - char* m_ptr = nullptr; - u64 m_size; - - public: - file_read_map() = default; - - file_read_map(file_read_map&& right) - : m_ptr(right.m_ptr) - , m_size(right.m_size) - { - right.m_ptr = 0; - } - - file_read_map& operator =(file_read_map&& right) - { - std::swap(m_ptr, right.m_ptr); - std::swap(m_size, right.m_size); - return *this; - } - - file_read_map(const file& f) - { - reset(f); - } - - ~file_read_map() - { - reset(); - } - - // Open file mapping - void reset(const file& f); - - // Close file mapping - void reset(); - - // Get pointer - operator const char*() const - { - return m_ptr; - } - }; - - // TODO - class file_write_map final - { - char* m_ptr = nullptr; - u64 m_size; - - public: - file_write_map() = default; - - file_write_map(file_write_map&& right) - : m_ptr(right.m_ptr) - , m_size(right.m_size) - { - right.m_ptr = 0; - } - - file_write_map& operator =(file_write_map&& right) - { - std::swap(m_ptr, right.m_ptr); - std::swap(m_size, right.m_size); - return *this; - } - - file_write_map(const file& f) - { - reset(f); - } - - ~file_write_map() - { - reset(); - } - - // Open file mapping - void reset(const file& f); - - // Close file mapping - void reset(); - - // Get pointer - operator char*() const - { - return m_ptr; - } - }; - class dir final { - std::unique_ptr m_path; - std::intptr_t m_dd; // handle (aux) + std::unique_ptr m_dir; + + [[noreturn]] void xnull() const; public: dir() = default; - explicit dir(const std::string& dirname) + // Open dir handle + explicit dir(const std::string& path) { - open(dirname); + open(path); } - dir(dir&& other) - : m_dd(other.m_dd) - , m_path(std::move(other.m_path)) - { - } - - dir& operator =(dir&& right) - { - std::swap(m_dd, right.m_dd); - std::swap(m_path, right.m_path); - return *this; - } - - ~dir(); - - // Check whether the handle is valid (opened directory) - bool is_opened() const - { - return m_path.operator bool(); - } + // Open specified directory + bool open(const std::string& path); // Check whether the handle is valid (opened directory) explicit operator bool() const { - return is_opened(); + return m_dir.operator bool(); } - // Open specified directory - bool open(const std::string& dirname); - - // Close the directory explicitly (destructor automatically closes the directory) - void close(); - - // Get next directory entry (UTF-8 name and file stat) - bool read(std::string& name, stat_t& info); - - bool first(std::string& name, stat_t& info); - - struct entry + // Close the directory explicitly + void close() { - std::string name; - stat_t info; - }; + m_dir.reset(); + } + + void reset(std::unique_ptr&& ptr) + { + m_dir = std::move(ptr); + } + + std::unique_ptr release() + { + return std::move(m_dir); + } + + // Get next directory entry + bool read(dir_entry& out) const + { + if (!m_dir) xnull(); + return m_dir->read(out); + } + + // Reset to the beginning + void rewind() const + { + if (!m_dir) xnull(); + return m_dir->rewind(); + } class iterator { - entry m_entry; dir* m_parent; + dir_entry m_entry; public: enum class mode @@ -382,20 +383,16 @@ namespace fs if (mode_ == mode::from_first) { - m_parent->first(m_entry.name, m_entry.info); - } - else - { - m_parent->read(m_entry.name, m_entry.info); + m_parent->rewind(); } - if (m_entry.name.empty()) + if (!m_parent->read(m_entry)) { m_parent = nullptr; } } - entry& operator *() + dir_entry& operator *() { return m_entry; } @@ -414,7 +411,7 @@ namespace fs iterator begin() { - return{ this }; + return{ m_dir ? this : nullptr }; } iterator end() @@ -428,4 +425,10 @@ namespace fs // Get executable directory const std::string& get_executable_dir(); + + // Delete directory and all its contents recursively + void remove_all(const std::string& path); + + // Get size of all files recursively + u64 get_dir_size(const std::string& path); } diff --git a/Utilities/Log.cpp b/Utilities/Log.cpp index d86e235c62..08d6d7197e 100644 --- a/Utilities/Log.cpp +++ b/Utilities/Log.cpp @@ -1,26 +1,17 @@ -#include "stdafx.h" -#include "Thread.h" -#include "File.h" -#include "Log.h" - -#ifdef _WIN32 -#include -#endif +#include "Log.h" namespace _log { - logger& get_logger() + static file_listener& get_logger() { - // Use magic static for global logger instance - static logger instance; - return instance; + // Use magic static + static file_listener logger("RPCS3.log"); + return logger; } - file_listener g_log_file(_PRGNAME_ ".log"); - file_writer g_tty_file("TTY.log"); - channel GENERAL("", level::notice); + channel GENERAL(nullptr, level::notice); channel LOADER("LDR", level::notice); channel MEMORY("MEM", level::notice); channel RSX("RSX", level::notice); @@ -28,72 +19,29 @@ namespace _log channel PPU("PPU", level::notice); channel SPU("SPU", level::notice); channel ARMv7("ARMv7"); -} -_log::listener::listener() -{ - // Register self - get_logger().add_listener(this); -} - -_log::listener::~listener() -{ - // Unregister self - get_logger().remove_listener(this); -} - -_log::channel::channel(const std::string& name, _log::level init_level) - : name{ name } - , enabled{ init_level } -{ - // TODO: register config property "name" associated with "enabled" member -} - -void _log::logger::add_listener(_log::listener* listener) -{ - std::lock_guard lock(m_mutex); - - m_listeners.emplace(listener); -} - -void _log::logger::remove_listener(_log::listener* listener) -{ - std::lock_guard lock(m_mutex); - - m_listeners.erase(listener); -} - -void _log::logger::broadcast(const _log::channel& ch, _log::level sev, const std::string& text) const -{ - reader_lock lock(m_mutex); - - for (auto listener : m_listeners) - { - listener->log(ch, sev, text); - } + thread_local std::string(*g_tls_make_prefix)(const channel&, level, const std::string&) = nullptr; } void _log::broadcast(const _log::channel& ch, _log::level sev, const std::string& text) { - get_logger().broadcast(ch, sev, text); + get_logger().log(ch, sev, text); } +[[noreturn]] extern void catch_all_exceptions(); + _log::file_writer::file_writer(const std::string& name) { try { - if (!m_file.open(fs::get_config_dir() + name, fom::rewrite | fom::append)) + if (!m_file.open(fs::get_config_dir() + name, fs::rewrite + fs::append)) { - throw EXCEPTION("Can't create log file %s (error %d)", name, errno); + throw fmt::exception("Can't create log file %s (error %d)", name, errno); } } - catch (const fmt::exception& e) + catch (...) { -#ifdef _WIN32 - MessageBoxA(0, e.what(), "_log::file_writer() failed", MB_ICONERROR); -#else - std::printf("_log::file_writer() failed: %s\n", e.what()); -#endif + catch_all_exceptions(); } } @@ -104,7 +52,7 @@ void _log::file_writer::log(const std::string& text) std::size_t _log::file_writer::size() const { - return m_file.seek(0, fs::seek_cur); + return m_file.pos(); } void _log::file_listener::log(const _log::channel& ch, _log::level sev, const std::string& text) @@ -126,14 +74,14 @@ void _log::file_listener::log(const _log::channel& ch, _log::level sev, const st // TODO: print time? - if (auto t = thread_ctrl::get_current()) + if (auto func = g_tls_make_prefix) { msg += '{'; - msg += t->get_name(); + msg += func(ch, sev, text); msg += "} "; } - - if (ch.name.size()) + + if (ch.name) { msg += ch.name; msg += sev == level::todo ? " TODO: " : ": "; diff --git a/Utilities/Log.h b/Utilities/Log.h index 11ef6c6c21..5f319ae480 100644 --- a/Utilities/Log.h +++ b/Utilities/Log.h @@ -1,6 +1,9 @@ #pragma once -#include "SharedMutex.h" +#include "types.h" +#include "Atomic.h" +#include "File.h" +#include "StrFmt.h" namespace _log { @@ -19,40 +22,24 @@ namespace _log struct channel; struct listener; - // Log manager - class logger final - { - mutable shared_mutex m_mutex; - - std::set m_listeners; - - public: - // Register listener - void add_listener(listener* listener); - - // Unregister listener - void remove_listener(listener* listener); - - // Send log message to all listeners - void broadcast(const channel& ch, level sev, const std::string& text) const; - }; - // Send log message to global logger instance void broadcast(const channel& ch, level sev, const std::string& text); - // Log channel (source) + // Log channel struct channel { - // Channel prefix (also used for identification) - const std::string name; + // Channel prefix (added to every log message) + const char* const name; // The lowest logging level enabled for this channel (used for early filtering) - std::atomic enabled; + atomic_t enabled; - // Initialization (max level enabled by default) - channel(const std::string& name, level = level::trace); - - virtual ~channel() = default; + // Constant initialization: name and initial log level + constexpr channel(const char* name, level enabled = level::trace) + : name{ name } + , enabled{ enabled } + { + } // Log without formatting force_inline void log(level sev, const std::string& text) const @@ -71,7 +58,7 @@ namespace _log #define GEN_LOG_METHOD(_sev)\ template\ - force_inline void _sev(const char* fmt, const Args&... args)\ + force_inline void _sev(const char* fmt, const Args&... args) const\ {\ return format(level::_sev, fmt, args...);\ } @@ -90,9 +77,9 @@ namespace _log // Log listener (destination) struct listener { - listener(); + listener() = default; - virtual ~listener(); + virtual ~listener() = default; virtual void log(const channel& ch, level sev, const std::string& text) = 0; }; @@ -126,9 +113,6 @@ namespace _log virtual void log(const channel& ch, level sev, const std::string& text) override; }; - // Global variable for RPCS3.log - extern file_listener g_log_file; - // Global variable for TTY.log extern file_writer g_tty_file; @@ -142,8 +126,26 @@ namespace _log extern channel PPU; extern channel SPU; extern channel ARMv7; + + extern thread_local std::string(*g_tls_make_prefix)(const channel&, level, const std::string&); } +template<> +struct bijective<_log::level, const char*> +{ + static constexpr std::pair<_log::level, const char*> map[] + { + { _log::level::always, "Nothing" }, + { _log::level::fatal, "Fatal" }, + { _log::level::error, "Error" }, + { _log::level::todo, "TODO" }, + { _log::level::success, "Success" }, + { _log::level::warning, "Warning" }, + { _log::level::notice, "Notice" }, + { _log::level::trace, "Trace" }, + }; +}; + // Legacy: #define LOG_SUCCESS(ch, fmt, ...) _log::ch.success(fmt, ##__VA_ARGS__) diff --git a/Utilities/Macro.h b/Utilities/Macro.h new file mode 100644 index 0000000000..d8fdc67f92 --- /dev/null +++ b/Utilities/Macro.h @@ -0,0 +1,79 @@ +#pragma once + +#include +#include + +template::value>> +constexpr T align(const T& value, std::uint64_t align) +{ + return static_cast((value + (align - 1)) & ~(align - 1)); +} + +template +constexpr To narrow_impl(const To& result, const From& value, const char* message) +{ + return static_cast(result) != value ? throw std::runtime_error(message) : result; +} + +// Narrow cast (similar to gsl::narrow) with fixed message +template +constexpr auto narrow(const From& value, const char* fixed_msg = "::narrow() failed") -> decltype(static_cast(static_cast(std::declval()))) +{ + return narrow_impl(static_cast(value), value, fixed_msg); +} + +// Return 32 bit .size() for container +template +constexpr auto size32(const CT& container, const char* fixed_msg = "::size32() failed") -> decltype(static_cast(container.size())) +{ + return narrow(container.size(), fixed_msg); +} + +// Return 32 bit size for an array +template +constexpr std::uint32_t size32(const T(&)[Size]) +{ + static_assert(Size <= UINT32_MAX, "size32() error: too big"); + return static_cast(Size); +} + +#define CHECK_SIZE(type, size) static_assert(sizeof(type) == size, "Invalid " #type " type size") +#define CHECK_ALIGN(type, align) static_assert(alignof(type) == align, "Invalid " #type " type alignment") +#define CHECK_MAX_SIZE(type, size) static_assert(sizeof(type) <= size, #type " type size is too big") +#define CHECK_SIZE_ALIGN(type, size, align) CHECK_SIZE(type, size); CHECK_ALIGN(type, align) + +// Return 32 bit sizeof() to avoid widening/narrowing conversions with size_t +#define SIZE_32(type) static_cast(sizeof(type)) + +// Return 32 bit alignof() to avoid widening/narrowing conversions with size_t +#define ALIGN_32(type) static_cast(alignof(type)) + +// Return 32 bit custom offsetof() +#define OFFSET_32(type, x) static_cast(reinterpret_cast(&reinterpret_cast(reinterpret_cast(0ull)->x))) + +// Sometimes to avoid writing std::remove_cv_t<>, example: std::is_same +#define CV const volatile + +#define CONCATENATE_DETAIL(x, y) x ## y +#define CONCATENATE(x, y) CONCATENATE_DETAIL(x, y) + +#define STRINGIZE_DETAIL(x) #x +#define STRINGIZE(x) STRINGIZE_DETAIL(x) + +// Macro set, allows to hide "return" in simple lambda expressions. +#define WRAP_EXPR(expr, ...) [&](__VA_ARGS__) { return expr; } +#define COPY_EXPR(expr, ...) [=](__VA_ARGS__) { return expr; } +#define PURE_EXPR(expr, ...) [] (__VA_ARGS__) { return expr; } + +#define HERE "\n(in file " __FILE__ ":" STRINGIZE(__LINE__) ")" + +// Ensure that the expression is evaluated to true. Always evaluated and allowed to have side effects (unlike assert() macro). +#define ASSERT(expr) if (!(expr)) throw std::runtime_error("Assertion failed: " #expr HERE) + +// Expects() and Ensures() are intended to check function arguments and results. +// Expressions are not guaranteed to evaluate. Redefinition with ASSERT macro for better unification. +#define Expects ASSERT +#define Ensures ASSERT + +#define DECLARE(static_member) decltype(static_member) static_member +#define STR_CASE(value) case value: return #value diff --git a/Utilities/GNU.cpp b/Utilities/Platform.cpp similarity index 98% rename from Utilities/GNU.cpp rename to Utilities/Platform.cpp index 29467b205f..9f2672997e 100644 --- a/Utilities/GNU.cpp +++ b/Utilities/Platform.cpp @@ -1,4 +1,4 @@ -#include "GNU.h" +#include "Platform.h" #ifdef __APPLE__ #include diff --git a/Utilities/GNU.h b/Utilities/Platform.h similarity index 58% rename from Utilities/GNU.h rename to Utilities/Platform.h index 268318e568..18d9297e24 100644 --- a/Utilities/GNU.h +++ b/Utilities/Platform.h @@ -1,17 +1,22 @@ #pragma once +#include +#include #include -#if defined(_MSC_VER) && _MSC_VER <= 1800 -#define thread_local __declspec(thread) -#elif __APPLE__ -#define thread_local __thread +#define IS_LE_MACHINE 1 +#define IS_BE_MACHINE 0 + +#ifdef _MSC_VER +#include +#else +#include #endif -#if defined(_MSC_VER) -#define never_inline __declspec(noinline) -#else -#define never_inline __attribute__((noinline)) +// Some platforms don't support thread_local well yet. +#ifndef _MSC_VER +#define thread_local __thread +#define __assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0) #endif #if defined(_MSC_VER) @@ -20,20 +25,21 @@ #define safe_buffers #endif +#if defined(_MSC_VER) +#define never_inline __declspec(noinline) +#else +#define never_inline __attribute__((noinline)) +#endif + #if defined(_MSC_VER) #define force_inline __forceinline #else #define force_inline __attribute__((always_inline)) inline #endif -#if defined(_MSC_VER) && _MSC_VER <= 1800 -#define alignas(x) _CRT_ALIGN(x) -#endif - #if defined(__GNUG__) #include -#include #define _fpclass(x) std::fpclassify(x) #define INFINITE 0xFFFFFFFF @@ -59,170 +65,6 @@ int clock_gettime(clockid_t clk_id, struct timespec *tp); #endif /* __APPLE__ */ #endif /* __GNUG__ */ -#if defined(_MSC_VER) - -// Unsigned 128-bit integer implementation -struct alignas(16) u128 -{ - std::uint64_t lo, hi; - - u128() = default; - - u128(const u128&) = default; - - u128(std::uint64_t l) - : lo(l) - , hi(0) - { - } - - u128 operator +(const u128& r) const - { - u128 value; - _addcarry_u64(_addcarry_u64(0, r.lo, lo, &value.lo), r.hi, hi, &value.hi); - return value; - } - - friend u128 operator +(const u128& l, std::uint64_t r) - { - u128 value; - _addcarry_u64(_addcarry_u64(0, r, l.lo, &value.lo), l.hi, 0, &value.hi); - return value; - } - - friend u128 operator +(std::uint64_t l, const u128& r) - { - u128 value; - _addcarry_u64(_addcarry_u64(0, r.lo, l, &value.lo), 0, r.hi, &value.hi); - return value; - } - - u128 operator -(const u128& r) const - { - u128 value; - _subborrow_u64(_subborrow_u64(0, r.lo, lo, &value.lo), r.hi, hi, &value.hi); - return value; - } - - friend u128 operator -(const u128& l, std::uint64_t r) - { - u128 value; - _subborrow_u64(_subborrow_u64(0, r, l.lo, &value.lo), 0, l.hi, &value.hi); - return value; - } - - friend u128 operator -(std::uint64_t l, const u128& r) - { - u128 value; - _subborrow_u64(_subborrow_u64(0, r.lo, l, &value.lo), r.hi, 0, &value.hi); - return value; - } - - u128 operator +() const - { - return *this; - } - - u128 operator -() const - { - u128 value; - _subborrow_u64(_subborrow_u64(0, lo, 0, &value.lo), hi, 0, &value.hi); - return value; - } - - u128& operator ++() - { - _addcarry_u64(_addcarry_u64(0, 1, lo, &lo), 0, hi, &hi); - return *this; - } - - u128 operator ++(int) - { - u128 value = *this; - _addcarry_u64(_addcarry_u64(0, 1, lo, &lo), 0, hi, &hi); - return value; - } - - u128& operator --() - { - _subborrow_u64(_subborrow_u64(0, 1, lo, &lo), 0, hi, &hi); - return *this; - } - - u128 operator --(int) - { - u128 value = *this; - _subborrow_u64(_subborrow_u64(0, 1, lo, &lo), 0, hi, &hi); - return value; - } - - u128 operator ~() const - { - u128 value; - value.lo = ~lo; - value.hi = ~hi; - return value; - } - - u128 operator &(const u128& r) const - { - u128 value; - value.lo = lo & r.lo; - value.hi = hi & r.hi; - return value; - } - - u128 operator |(const u128& r) const - { - u128 value; - value.lo = lo | r.lo; - value.hi = hi | r.hi; - return value; - } - - u128 operator ^(const u128& r) const - { - u128 value; - value.lo = lo ^ r.lo; - value.hi = hi ^ r.hi; - return value; - } - - u128& operator +=(const u128& r) - { - _addcarry_u64(_addcarry_u64(0, r.lo, lo, &lo), r.hi, hi, &hi); - return *this; - } - - u128& operator +=(uint64_t r) - { - _addcarry_u64(_addcarry_u64(0, r, lo, &lo), 0, hi, &hi); - return *this; - } - - u128& operator &=(const u128& r) - { - lo &= r.lo; - hi &= r.hi; - return *this; - } - - u128& operator |=(const u128& r) - { - lo |= r.lo; - hi |= r.hi; - return *this; - } - - u128& operator ^=(const u128& r) - { - lo ^= r.lo; - hi ^= r.hi; - return *this; - } -}; -#endif - inline std::uint32_t cntlz32(std::uint32_t arg) { #if defined(_MSC_VER) @@ -243,7 +85,67 @@ inline std::uint64_t cntlz64(std::uint64_t arg) #endif } -// compare 16 packed unsigned bytes (greater than) +template +struct add_flags_result_t +{ + T result; + bool carry; + //bool overflow; + bool zero; + bool sign; + + add_flags_result_t() = default; + + // Straighforward ADD with flags + add_flags_result_t(T a, T b) + : result(a + b) + , carry(result < a) + //, overflow((result ^ ~(a ^ b)) >> (sizeof(T) * 8 - 1) != 0) + , zero(result == 0) + , sign(result >> (sizeof(T) * 8 - 1) != 0) + { + } + + // Straighforward ADC with flags + add_flags_result_t(T a, T b, bool c) + : add_flags_result_t(a, b) + { + add_flags_result_t r(result, c); + result = r.result; + carry |= r.carry; + //overflow |= r.overflow; + zero = r.zero; + sign = r.sign; + } +}; + +inline add_flags_result_t add32_flags(std::uint32_t a, std::uint32_t b) +{ + //add_flags_result_t r; + //r.carry = _addcarry_u32(0, a, b, &r.result) != 0; + //r.zero = r.result == 0; + //r.sign = r.result >> 31; + //return r; + + return{ a, b }; +} + +inline add_flags_result_t add32_flags(std::uint32_t a, std::uint32_t b, bool c) +{ + return{ a, b, c }; +} + +inline add_flags_result_t add64_flags(std::uint64_t a, std::uint64_t b) +{ + return{ a, b }; +} + +inline add_flags_result_t add64_flags(std::uint64_t a, std::uint64_t b, bool c) +{ + return{ a, b, c }; +} + +// Compare 16 packed unsigned bytes (greater than) inline __m128i sse_cmpgt_epu8(__m128i A, __m128i B) { // (A xor 0x80) > (B xor 0x80) @@ -290,3 +192,36 @@ inline __m128 sse_log2_ps(__m128 A) const auto x8 = _mm_cvtepi32_ps(_mm_sub_epi32(_mm_srli_epi32(_mm_castps_si128(x0), 23), _mm_set1_epi32(127))); return _mm_add_ps(_mm_mul_ps(_mm_mul_ps(_mm_mul_ps(_mm_mul_ps(x5, x6), x7), x4), _c), _mm_add_ps(_mm_mul_ps(x4, _c), x8)); } + +// Helper function, used by ""_u16, ""_u32, ""_u64 +constexpr std::uint8_t to_u8(char c) +{ + return static_cast(c); +} + +// Convert 2-byte string to u16 value like reinterpret_cast does +constexpr std::uint16_t operator""_u16(const char* s, std::size_t length) +{ + return length != 2 ? throw s : +#if IS_LE_MACHINE == 1 + to_u8(s[1]) << 8 | to_u8(s[0]); +#endif +} + +// Convert 4-byte string to u32 value like reinterpret_cast does +constexpr std::uint32_t operator""_u32(const char* s, std::size_t length) +{ + return length != 4 ? throw s : +#if IS_LE_MACHINE == 1 + to_u8(s[3]) << 24 | to_u8(s[2]) << 16 | to_u8(s[1]) << 8 | to_u8(s[0]); +#endif +} + +// Convert 8-byte string to u64 value like reinterpret_cast does +constexpr std::uint64_t operator""_u64(const char* s, std::size_t length) +{ + return length != 8 ? throw s : +#if IS_LE_MACHINE == 1 + static_cast(to_u8(s[7]) << 24 | to_u8(s[6]) << 16 | to_u8(s[5]) << 8 | to_u8(s[4])) << 32 | to_u8(s[3]) << 24 | to_u8(s[2]) << 16 | to_u8(s[1]) << 8 | to_u8(s[0]); +#endif +} diff --git a/Utilities/Semaphore.cpp b/Utilities/Semaphore.cpp index ed3d419e12..e6ea21b123 100644 --- a/Utilities/Semaphore.cpp +++ b/Utilities/Semaphore.cpp @@ -10,7 +10,7 @@ bool semaphore_t::try_wait() } // try to decrement m_value atomically - const auto old = m_var.atomic_op([](sync_var_t& var) + const auto old = m_var.fetch_op([](sync_var_t& var) { if (var.value) { @@ -36,7 +36,7 @@ bool semaphore_t::try_post() } // try to increment m_value atomically - const auto old = m_var.atomic_op([&](sync_var_t& var) + const auto old = m_var.fetch_op([&](sync_var_t& var) { if (var.value < max_value) { diff --git a/Utilities/Semaphore.h b/Utilities/Semaphore.h index 8ed96f4275..ea3c2c4e5c 100644 --- a/Utilities/Semaphore.h +++ b/Utilities/Semaphore.h @@ -8,7 +8,7 @@ class semaphore_t // semaphore condition variable std::condition_variable m_cv; - struct sync_var_t + struct alignas(8) sync_var_t { u32 value; // current semaphore value u32 waiters; // current amount of waiters diff --git a/Utilities/SharedMutex.cpp b/Utilities/SharedMutex.cpp deleted file mode 100644 index 728e4e4437..0000000000 --- a/Utilities/SharedMutex.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "stdafx.h" -#include "SharedMutex.h" - -void shared_mutex::impl_lock_shared(u32 old_value) -{ - // Throw if reader count breaks the "second" limit (it should be impossible) - CHECK_ASSERTION((old_value & SM_READER_COUNT) != SM_READER_COUNT); - - std::unique_lock lock(m_mutex); - - // Notify non-zero reader queue size - m_ctrl |= SM_READER_QUEUE; - - // Compensate incorrectly increased reader count - if ((--m_ctrl & SM_READER_COUNT) == 0 && m_wq_size) - { - // Notify current exclusive owner (condition passed) - m_ocv.notify_one(); - } - - CHECK_ASSERTION(++m_rq_size); - - // Obtain the reader lock - while (!atomic_op(m_ctrl, op_lock_shared)) - { - m_rcv.wait(lock); - } - - CHECK_ASSERTION(m_rq_size--); - - if (m_rq_size == 0) - { - m_ctrl &= ~SM_READER_QUEUE; - } -} - -void shared_mutex::impl_unlock_shared(u32 new_value) -{ - // Throw if reader count was zero - CHECK_ASSERTION((new_value & SM_READER_COUNT) != SM_READER_COUNT); - - // Mutex cannot be unlocked before notification because m_ctrl has been changed outside - std::lock_guard lock(m_mutex); - - if (m_wq_size && (new_value & SM_READER_COUNT) == 0) - { - // Notify current exclusive owner that the latest reader is gone - m_ocv.notify_one(); - } - else if (m_rq_size) - { - m_rcv.notify_one(); - } -} - -void shared_mutex::impl_lock_excl(u32 value) -{ - std::unique_lock lock(m_mutex); - - // Notify non-zero writer queue size - m_ctrl |= SM_WRITER_QUEUE; - - CHECK_ASSERTION(++m_wq_size); - - // Obtain the writer lock - while (!atomic_op(m_ctrl, op_lock_excl)) - { - m_wcv.wait(lock); - } - - // Wait for remaining readers - while ((m_ctrl & SM_READER_COUNT) != 0) - { - m_ocv.wait(lock); - } - - CHECK_ASSERTION(m_wq_size--); - - if (m_wq_size == 0) - { - m_ctrl &= ~SM_WRITER_QUEUE; - } -} - -void shared_mutex::impl_unlock_excl(u32 value) -{ - // Throw if was not locked exclusively - CHECK_ASSERTION(value & SM_WRITER_LOCK); - - // Mutex cannot be unlocked before notification because m_ctrl has been changed outside - std::lock_guard lock(m_mutex); - - if (m_wq_size) - { - // Notify next exclusive owner - m_wcv.notify_one(); - } - else if (m_rq_size) - { - // Notify all readers - m_rcv.notify_all(); - } -} diff --git a/Utilities/SharedMutex.h b/Utilities/SharedMutex.h index 961ef1dd23..361f94f2ee 100644 --- a/Utilities/SharedMutex.h +++ b/Utilities/SharedMutex.h @@ -1,49 +1,156 @@ #pragma once +#include +#include +#include +#include +#include + +#include "Atomic.h" + //! An attempt to create effective implementation of "shared mutex", lock-free in optimistic case. //! All locking and unlocking may be done by single LOCK XADD or LOCK CMPXCHG instructions. //! MSVC implementation of std::shared_timed_mutex seems suboptimal. //! std::shared_mutex is not available until C++17. class shared_mutex final { - enum : u32 - { - SM_WRITER_LOCK = 1u << 31, // Exclusive lock flag, must be MSB - SM_WRITER_QUEUE = 1u << 30, // Flag set if m_wq_size != 0 - SM_READER_QUEUE = 1u << 29, // Flag set if m_rq_size != 0 + using ctrl_type = u32; - SM_READER_COUNT = SM_READER_QUEUE - 1, // Valid reader count bit mask - SM_READER_MAX = 1u << 24, // Max reader count + enum : ctrl_type + { + SM_WRITER_LOCK = 1u << 31, // Exclusive lock flag, must be MSB + SM_WAITERS_BIT = 1u << 30, // Flag set if m_wq_size or m_rq_size is non-zero + SM_INVALID_BIT = 1u << 29, // Unreachable reader count bit (may be set by incorrect unlock_shared() call) + + SM_READER_MASK = SM_WAITERS_BIT - 1, // Valid reader count bit mask + SM_READER_MAX = 1u << 24, // Max reader count }; - std::atomic m_ctrl{}; // Control atomic variable: reader count | SM_* flags - std::thread::id m_owner{}; // Current exclusive owner (TODO: implement only for debug mode?) + atomic_t m_ctrl{}; // Control atomic variable: reader count | SM_* flags std::mutex m_mutex; - u32 m_rq_size{}; // Reader queue size (threads waiting on m_rcv) - u32 m_wq_size{}; // Writer queue size (threads waiting on m_wcv+m_ocv) + std::size_t m_rq_size{}; // Reader queue size (threads waiting on m_rcv) + std::size_t m_wq_size{}; // Writer queue size (threads waiting on m_wcv and m_ocv) std::condition_variable m_rcv; // Reader queue std::condition_variable m_wcv; // Writer queue std::condition_variable m_ocv; // For current exclusive owner - static bool op_lock_shared(u32& ctrl) + void lock_shared_hard() { - // Check writer flags and reader limit - return (ctrl & ~SM_READER_QUEUE) < SM_READER_MAX ? ctrl++, true : false; + std::unique_lock lock(m_mutex); + + // Validate + if ((m_ctrl & SM_INVALID_BIT) != 0) throw std::runtime_error("shared_mutex::lock_shared(): Invalid bit"); + if ((m_ctrl & SM_READER_MASK) == 0) throw std::runtime_error("shared_mutex::lock_shared(): No readers"); + + // Notify non-zero reader queue size + m_ctrl |= SM_WAITERS_BIT, m_rq_size++; + + // Fix excess reader count + if ((--m_ctrl & SM_READER_MASK) == 0 && m_wq_size) + { + // Notify exclusive owner + m_ocv.notify_one(); + } + + // Obtain the reader lock + while (true) + { + const auto ctrl = m_ctrl.load(); + + // Check writers and reader limit + if (m_wq_size || (ctrl & ~SM_WAITERS_BIT) >= SM_READER_MAX) + { + m_rcv.wait(lock); + continue; + } + + if (m_ctrl.compare_and_swap_test(ctrl, ctrl + 1)) + { + break; + } + } + + if (!--m_rq_size && !m_wq_size) + { + m_ctrl &= ~SM_WAITERS_BIT; + } } - static bool op_lock_excl(u32& ctrl) + void unlock_shared_notify() { - // Test and set writer lock - return (ctrl & SM_WRITER_LOCK) == 0 ? ctrl |= SM_WRITER_LOCK, true : false; + // Mutex is locked for reliable notification because m_ctrl has been changed outside + std::lock_guard lock(m_mutex); + + if ((m_ctrl & SM_READER_MASK) == 0 && m_wq_size) + { + // Notify exclusive owner + m_ocv.notify_one(); + } + else if (m_rq_size) + { + // Notify other readers + m_rcv.notify_one(); + } } - void impl_lock_shared(u32 old_ctrl); - void impl_unlock_shared(u32 new_ctrl); - void impl_lock_excl(u32 ctrl); - void impl_unlock_excl(u32 ctrl); + void lock_hard() + { + std::unique_lock lock(m_mutex); + + // Validate + if ((m_ctrl & SM_INVALID_BIT) != 0) throw std::runtime_error("shared_mutex::lock(): Invalid bit"); + + // Notify non-zero writer queue size + m_ctrl |= SM_WAITERS_BIT, m_wq_size++; + + // Obtain the writer lock + while (true) + { + const auto ctrl = m_ctrl.load(); + + if (ctrl & SM_WRITER_LOCK) + { + m_wcv.wait(lock); + continue; + } + + if (m_ctrl.compare_and_swap_test(ctrl, ctrl | SM_WRITER_LOCK)) + { + break; + } + } + + // Wait for remaining readers + while ((m_ctrl & SM_READER_MASK) != 0) + { + m_ocv.wait(lock); + } + + if (!--m_wq_size && !m_rq_size) + { + m_ctrl &= ~SM_WAITERS_BIT; + } + } + + void unlock_notify() + { + // Mutex is locked for reliable notification because m_ctrl has been changed outside + std::lock_guard lock(m_mutex); + + if (m_wq_size) + { + // Notify next exclusive owner + m_wcv.notify_one(); + } + else if (m_rq_size) + { + // Notify all readers + m_rcv.notify_all(); + } + } public: shared_mutex() = default; @@ -51,65 +158,49 @@ public: // Lock in shared mode void lock_shared() { - const u32 old_ctrl = m_ctrl++; - - // Check flags and reader limit - if (old_ctrl >= SM_READER_MAX) + if (m_ctrl++ >= SM_READER_MAX) { - impl_lock_shared(old_ctrl); + lock_shared_hard(); } } // Try to lock in shared mode bool try_lock_shared() { - return atomic_op(m_ctrl, [](u32& ctrl) - { - // Check flags and reader limit - return ctrl < SM_READER_MAX ? ctrl++, true : false; - }); + auto ctrl = m_ctrl.load(); + + return ctrl < SM_READER_MAX && m_ctrl.compare_and_swap_test(ctrl, ctrl + 1); } // Unlock in shared mode void unlock_shared() { - const u32 new_ctrl = --m_ctrl; - - // Check if notification required - if (new_ctrl >= SM_READER_MAX) + if (m_ctrl-- >= SM_READER_MAX) { - impl_unlock_shared(new_ctrl); - } - } - - // Lock exclusively - void lock() - { - u32 value = 0; - - if (!m_ctrl.compare_exchange_strong(value, SM_WRITER_LOCK)) - { - impl_lock_excl(value); + unlock_shared_notify(); } } // Try to lock exclusively bool try_lock() { - u32 value = 0; + return m_ctrl.compare_and_swap_test(0, SM_WRITER_LOCK); + } - return m_ctrl.compare_exchange_strong(value, SM_WRITER_LOCK); + // Lock exclusively + void lock() + { + if (m_ctrl.compare_and_swap_test(0, SM_WRITER_LOCK)) return; + + lock_hard(); } // Unlock exclusively void unlock() { - const u32 value = m_ctrl.fetch_add(SM_WRITER_LOCK); - - // Check if notification required - if (value != SM_WRITER_LOCK) + if (m_ctrl.fetch_sub(SM_WRITER_LOCK) != SM_WRITER_LOCK) { - impl_unlock_excl(value); + unlock_notify(); } } }; diff --git a/Utilities/SleepQueue.cpp b/Utilities/SleepQueue.cpp deleted file mode 100644 index d7f432cea6..0000000000 --- a/Utilities/SleepQueue.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "stdafx.h" -#include "Emu/CPU/CPUThread.h" - -#include "SleepQueue.h" - -void sleep_queue_entry_t::add_entry() -{ - m_queue.emplace_back(std::static_pointer_cast(m_thread.shared_from_this())); -} - -void sleep_queue_entry_t::remove_entry() -{ - for (auto it = m_queue.begin(); it != m_queue.end(); it++) - { - if (it->get() == &m_thread) - { - m_queue.erase(it); - return; - } - } -} - -bool sleep_queue_entry_t::find() const -{ - for (auto it = m_queue.begin(); it != m_queue.end(); it++) - { - if (it->get() == &m_thread) - { - return true; - } - } - - return false; -} - -sleep_queue_entry_t::sleep_queue_entry_t(sleep_entry_t& cpu, sleep_queue_t& queue) - : m_thread(cpu) - , m_queue(queue) -{ - add_entry(); - cpu.sleep(); -} - -sleep_queue_entry_t::sleep_queue_entry_t(sleep_entry_t& cpu, sleep_queue_t& queue, const defer_sleep_t&) - : m_thread(cpu) - , m_queue(queue) -{ - cpu.sleep(); -} - -sleep_queue_entry_t::~sleep_queue_entry_t() -{ - remove_entry(); - m_thread.awake(); -} diff --git a/Utilities/SleepQueue.h b/Utilities/SleepQueue.h index e66a284c65..fc97baad52 100644 --- a/Utilities/SleepQueue.h +++ b/Utilities/SleepQueue.h @@ -1,45 +1,75 @@ #pragma once -using sleep_entry_t = class CPUThread; -using sleep_queue_t = std::deque>; +#include -static struct defer_sleep_t {} const defer_sleep{}; +// Tag used in sleep_entry<> constructor +static struct defer_sleep_tag {} constexpr defer_sleep{}; -// automatic object handling a thread entry in the sleep queue -class sleep_queue_entry_t final +// Define sleep queue as std::deque with T* pointers, T - thread type +template using sleep_queue = std::deque; + +// Automatic object handling a thread pointer (T*) in the sleep queue +// Sleep is called in the constructor (if not null) +// Awake is called in the destructor (if not null) +// Sleep queue is actually std::deque with pointers, be careful about the lifetime +template +class sleep_entry final { - sleep_entry_t& m_thread; - sleep_queue_t& m_queue; - - void add_entry(); - void remove_entry(); - bool find() const; + sleep_queue& m_queue; + T& m_thread; public: - // add specified thread to the sleep queue - sleep_queue_entry_t(sleep_entry_t& entry, sleep_queue_t& queue); + // Constructor; enter() not called + sleep_entry(sleep_queue& queue, T& entry, const defer_sleep_tag&) + : m_queue(queue) + , m_thread(entry) + { + if (Sleep) (m_thread.*Sleep)(); + } - // don't add specified thread to the sleep queue - sleep_queue_entry_t(sleep_entry_t& entry, sleep_queue_t& queue, const defer_sleep_t&); + // Constructor; calls enter() + sleep_entry(sleep_queue& queue, T& entry) + : sleep_entry(queue, entry, defer_sleep) + { + enter(); + } - // removes specified thread from the sleep queue if added - ~sleep_queue_entry_t(); + // Destructor; calls leave() + ~sleep_entry() + { + leave(); + if (Awake) (m_thread.*Awake)(); + } - // add thread to the sleep queue + // Add thread to the sleep queue void enter() { - add_entry(); + for (auto t : m_queue) + { + if (t == &m_thread) + { + // Already exists, is it an error? + return; + } + } + + m_queue.emplace_back(&m_thread); } - // remove thread from the sleep queue + // Remove thread from the sleep queue void leave() { - remove_entry(); + auto it = std::find(m_queue.begin(), m_queue.end(), &m_thread); + + if (it != m_queue.end()) + { + m_queue.erase(it); + } } - // check whether the thread exists in the sleep queue + // Check whether the thread exists in the sleep queue explicit operator bool() const { - return find(); + return std::find(m_queue.begin(), m_queue.end(), &m_thread) != m_queue.end(); } }; diff --git a/Utilities/StrFmt.cpp b/Utilities/StrFmt.cpp index 8e67616579..1b7df25a4d 100644 --- a/Utilities/StrFmt.cpp +++ b/Utilities/StrFmt.cpp @@ -1,9 +1,5 @@ -#include "stdafx.h" -#pragma warning(push) -#pragma message("TODO: remove wx dependency: ") -#pragma warning(disable : 4996) -#include -#pragma warning(pop) +#include "StrFmt.h" +#include "BEType.h" std::string v128::to_hex() const { @@ -19,7 +15,7 @@ std::string fmt::to_hex(u64 value, u64 count) { if (count - 1 >= 16) { - throw EXCEPTION("Invalid count: 0x%llx", count); + throw exception("fmt::to_hex(): invalid count: 0x%llx", count); } count = std::max(count, 16 - cntlz64(value) / 4); @@ -78,8 +74,6 @@ std::string fmt::to_sdec(s64 svalue) return std::string(&res[first], sizeof(res) - first); } -//extern const std::string fmt::placeholder = "???"; - std::string fmt::replace_first(const std::string& src, const std::string& from, const std::string& to) { auto pos = src.find(from); @@ -104,83 +98,6 @@ std::string fmt::replace_all(const std::string &src, const std::string& from, co return target; } -//TODO: move this wx Stuff somewhere else -//convert a wxString to a std::string encoded in utf8 -//CAUTION, only use this to interface with wxWidgets classes -std::string fmt::ToUTF8(const wxString& right) -{ - auto ret = std::string(((const char *)right.utf8_str())); - return ret; -} - -//convert a std::string encoded in utf8 to a wxString -//CAUTION, only use this to interface with wxWidgets classes -wxString fmt::FromUTF8(const std::string& right) -{ - auto ret = wxString::FromUTF8(right.c_str()); - return ret; -} - -//TODO: remove this after every snippet that uses it is gone -//WARNING: not fully compatible with CmpNoCase from wxString -int fmt::CmpNoCase(const std::string& a, const std::string& b) -{ - if (a.length() != b.length()) - { - return -1; - } - else - { - return std::equal(a.begin(), - a.end(), - b.begin(), - [](const char& a, const char& b){return ::tolower(a) == ::tolower(b); }) - ? 0 : -1; - } -} - -//TODO: remove this after every snippet that uses it is gone -//WARNING: not fully compatible with CmpNoCase from wxString -void fmt::Replace(std::string &str, const std::string &searchterm, const std::string& replaceterm) -{ - size_t cursor = 0; - do - { - cursor = str.find(searchterm, cursor); - if (cursor != std::string::npos) - { - str.replace(cursor, searchterm.size(), replaceterm); - cursor += replaceterm.size(); - } - else - { - break; - } - } while (true); -} - -std::vector fmt::rSplit(const std::string& source, const std::string& delim) -{ - std::vector ret; - size_t cursor = 0; - do - { - size_t prevcurs = cursor; - cursor = source.find(delim, cursor); - if (cursor != std::string::npos) - { - ret.push_back(source.substr(prevcurs,cursor-prevcurs)); - cursor += delim.size(); - } - else - { - ret.push_back(source.substr(prevcurs)); - break; - } - } while (true); - return ret; -} - std::vector fmt::split(const std::string& source, std::initializer_list separators, bool is_skip_empty) { std::vector result; @@ -222,21 +139,7 @@ std::string fmt::trim(const std::string& source, const std::string& values) return source.substr(begin, source.find_last_not_of(values) + 1); } -std::string fmt::tolower(std::string source) -{ - std::transform(source.begin(), source.end(), source.begin(), ::tolower); - - return source; -} - -std::string fmt::toupper(std::string source) -{ - std::transform(source.begin(), source.end(), source.begin(), ::toupper); - - return source; -} - -std::string fmt::escape(std::string source) +std::string fmt::escape(const std::string& source, std::initializer_list more) { const std::pair escape_list[] = { @@ -244,20 +147,66 @@ std::string fmt::escape(std::string source) { "\a", "\\a" }, { "\b", "\\b" }, { "\f", "\\f" }, - { "\n", "\\n\n" }, + { "\n", "\\n" }, { "\r", "\\r" }, { "\t", "\\t" }, { "\v", "\\v" }, }; - source = fmt::replace_all(source, escape_list); + std::string result = fmt::replace_all(source, escape_list); for (char c = 0; c < 32; c++) { - if (c != '\n') source = fmt::replace_all(source, std::string(1, c), fmt::format("\\x%02X", c)); + result = fmt::replace_all(result, std::string(1, c), fmt::format("\\x%02X", c)); } - return source; + for (char c : more) + { + result = fmt::replace_all(result, std::string(1, c), fmt::format("\\x%02X", c)); + } + + return result; +} + +std::string fmt::unescape(const std::string& source) +{ + std::string result; + + for (auto it = source.begin(); it != source.end();) + { + const char bs = *it++; + + if (bs == '\\' && it != source.end()) + { + switch (const char code = *it++) + { + case 'a': result += '\a'; break; + case 'b': result += '\b'; break; + case 'f': result += '\f'; break; + case 'n': result += '\n'; break; + case 'r': result += '\r'; break; + case 't': result += '\t'; break; + case 'v': result += '\v'; break; + case 'x': + { + // Detect hexadecimal character code (TODO) + if (source.end() - it >= 2) + { + result += std::stoi(std::string{ *it++, *it++ }, 0, 16); + } + + } + // Octal/unicode not supported + default: result += code; + } + } + else + { + result += bs; + } + } + + return result; } bool fmt::match(const std::string &source, const std::string &mask) diff --git a/Utilities/StrFmt.h b/Utilities/StrFmt.h index 02f544a58b..d88a4a7cef 100644 --- a/Utilities/StrFmt.h +++ b/Utilities/StrFmt.h @@ -1,95 +1,38 @@ #pragma once -class wxString; +#include +#include +#include +#include +#include + +#include "Platform.h" +#include "types.h" #if defined(_MSC_VER) && _MSC_VER <= 1800 #define snprintf _snprintf #endif +// Copy null-terminated string from std::string to char array with truncation +template +inline void strcpy_trunc(char(&dst)[N], const std::string& src) +{ + const std::size_t count = src.size() >= N ? N - 1 : src.size(); + std::memcpy(dst, src.c_str(), count); + dst[count] = '\0'; +} + +// Copy null-terminated string from char array to another char array with truncation +template +inline void strcpy_trunc(char(&dst)[N], const char(&src)[N2]) +{ + const std::size_t count = N2 >= N ? N - 1 : N2; + std::memcpy(dst, src, count); + dst[count] = '\0'; +} + namespace fmt { - //struct empty_t{}; - - //extern const std::string placeholder; - - template - std::string AfterLast(const std::string& source, T searchstr) - { - size_t search_pos = source.rfind(searchstr); - search_pos = search_pos == std::string::npos ? 0 : search_pos; - return source.substr(search_pos); - } - - template - std::string BeforeLast(const std::string& source, T searchstr) - { - size_t search_pos = source.rfind(searchstr); - search_pos = search_pos == std::string::npos ? 0 : search_pos; - return source.substr(0, search_pos); - } - - template - std::string AfterFirst(const std::string& source, T searchstr) - { - size_t search_pos = source.find(searchstr); - search_pos = search_pos == std::string::npos ? 0 : search_pos; - return source.substr(search_pos); - } - - template - std::string BeforeFirst(const std::string& source, T searchstr) - { - size_t search_pos = source.find(searchstr); - search_pos = search_pos == std::string::npos ? 0 : search_pos; - return source.substr(0, search_pos); - } - - // write `fmt` from `pos` to the first occurence of `fmt::placeholder` to - // the stream `os`. Then write `arg` to to the stream. If there's no - // `fmt::placeholder` after `pos` everything in `fmt` after pos is written - // to `os`. Then `arg` is written to `os` after appending a space character - //template - //empty_t write(const std::string &fmt, std::ostream &os, std::string::size_type &pos, T &&arg) - //{ - // std::string::size_type ins = fmt.find(placeholder, pos); - - // if (ins == std::string::npos) - // { - // os.write(fmt.data() + pos, fmt.size() - pos); - // os << ' ' << arg; - - // pos = fmt.size(); - // } - // else - // { - // os.write(fmt.data() + pos, ins - pos); - // os << arg; - - // pos = ins + placeholder.size(); - // } - // return{}; - //} - - // typesafe version of a sprintf-like function. Returns the printed to - // string. To mark positions where the arguments are supposed to be - // inserted use `fmt::placeholder`. If there's not enough placeholders - // the rest of the arguments are appended at the end, seperated by spaces - //template - //std::string SFormat(const std::string &fmt, Args&& ... parameters) - //{ - // std::ostringstream os; - // std::string::size_type pos = 0; - // std::initializer_list { write(fmt, os, pos, parameters)... }; - - // if (!fmt.empty()) - // { - // os.write(fmt.data() + pos, fmt.size() - pos); - // } - - // std::string result = os.str(); - // return result; - //} - std::string replace_first(const std::string& src, const std::string& from, const std::string& to); std::string replace_all(const std::string &src, const std::string& from, const std::string& to); @@ -145,7 +88,8 @@ namespace fmt std::string to_udec(u64 value); std::string to_sdec(s64 value); - template::value> struct unveil + template + struct unveil { using result_type = T; @@ -155,37 +99,41 @@ namespace fmt } }; - template<> struct unveil + template<> + struct unveil { using result_type = const char* const; - force_inline static result_type get_value(const char* const& arg) + static result_type get_value(const char* const& arg) { return arg; } }; - template struct unveil + template + struct unveil { using result_type = const char* const; - force_inline static result_type get_value(const char(&arg)[N]) + static result_type get_value(const char(&arg)[N]) { return arg; } }; - template<> struct unveil + template<> + struct unveil { using result_type = const char*; - force_inline static result_type get_value(const std::string& arg) + static result_type get_value(const std::string& arg) { return arg.c_str(); } }; - template struct unveil + template + struct unveil::value>> { using result_type = std::underlying_type_t; @@ -195,31 +143,13 @@ namespace fmt } }; - template struct unveil, false> - { - using result_type = typename unveil::result_type; - - force_inline static result_type get_value(const se_t& arg) - { - return unveil::get_value(arg); - } - }; - template force_inline typename unveil::result_type do_unveil(const T& arg) { return unveil::get_value(arg); } - // Formatting function with special functionality: - // - // std::string is forced to .c_str() - // be_t<> is forced to .value() (fmt::do_unveil reverts byte order automatically) - // - // External specializations for fmt::do_unveil (can be found in another headers): - // vm::ptr, vm::bptr, ... (fmt::do_unveil) (vm_ptr.h) (with appropriate address type, using .addr() can be avoided) - // vm::ref, vm::bref, ... (fmt::do_unveil) (vm_ref.h) - // + // Formatting function with special functionality (fmt::unveil) template safe_buffers std::string format(const char* fmt, const Args&... args) { @@ -256,51 +186,28 @@ namespace fmt } } - struct exception : public std::exception + // Create exception of type T (std::runtime_error by default) with formatting + template + never_inline safe_buffers T exception(const char* fmt, const Args&... args) noexcept(noexcept(T{ fmt })) { - std::unique_ptr message; + return T{ format(fmt, do_unveil(args)...).c_str() }; + } - template never_inline safe_buffers exception(const char* file, int line, const char* func, const char* text, Args... args) noexcept - { - const std::string data = format(text, args...) + format("\n(in file %s:%d, in function %s)", file, line, func); + // Create exception of type T (std::runtime_error by default) without formatting + template + safe_buffers T exception(const char* msg) noexcept(noexcept(T{ msg })) + { + return T{ msg }; + } - message.reset(new char[data.size() + 1]); - - std::memcpy(message.get(), data.c_str(), data.size() + 1); - } - - exception(const exception& other) noexcept - { - const std::size_t size = std::strlen(other.message.get()); - - message.reset(new char[size + 1]); - - std::memcpy(message.get(), other.message.get(), size + 1); - } - - virtual const char* what() const noexcept override - { - return message.get(); - } - }; - - //convert a wxString to a std::string encoded in utf8 - //CAUTION, only use this to interface with wxWidgets classes - std::string ToUTF8(const wxString& right); - - //convert a std::string encoded in utf8 to a wxString - //CAUTION, only use this to interface with wxWidgets classes - wxString FromUTF8(const std::string& right); - - //TODO: remove this after every snippet that uses it is gone - //WARNING: not fully compatible with CmpNoCase from wxString - int CmpNoCase(const std::string& a, const std::string& b); - - //TODO: remove this after every snippet that uses it is gone - //WARNING: not fully compatible with Replace from wxString - void Replace(std::string &str, const std::string &searchterm, const std::string& replaceterm); - - std::vector rSplit(const std::string& source, const std::string& delim); + // Narrow cast (similar to gsl::narrow) with exception message formatting + template + inline auto narrow(const char* format_str, const From& value, const Args&... args) -> decltype(static_cast(static_cast(std::declval()))) + { + const auto result = static_cast(value); + if (static_cast(result) != value) throw fmt::exception(format_str, fmt::do_unveil(value), fmt::do_unveil(args)...); + return result; + } std::vector split(const std::string& source, std::initializer_list separators, bool is_skip_empty = true); std::string trim(const std::string& source, const std::string& values = " \t"); @@ -352,8 +259,35 @@ namespace fmt return result; } - std::string tolower(std::string source); - std::string toupper(std::string source); - std::string escape(std::string source); + template + std::string to_lower(IT _begin, IT _end) + { + std::string result; result.resize(_end - _begin); + std::transform(_begin, _end, result.begin(), ::tolower); + return result; + } + + template + std::string to_lower(const T& string) + { + return to_lower(std::begin(string), std::end(string)); + } + + template + std::string to_upper(IT _begin, IT _end) + { + std::string result; result.resize(_end - _begin); + std::transform(_begin, _end, result.begin(), ::toupper); + return result; + } + + template + std::string to_upper(const T& string) + { + return to_upper(std::begin(string), std::end(string)); + } + + std::string escape(const std::string& source, std::initializer_list more = {}); + std::string unescape(const std::string& source); bool match(const std::string &source, const std::string &mask); } diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 61619466a3..1fd83ba5b0 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1,11 +1,8 @@ #include "stdafx.h" -#include "Log.h" +#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" -#include "Emu/CPU/CPUThreadManager.h" -#include "Emu/CPU/CPUThread.h" +#include "Emu/IdManager.h" #include "Emu/Cell/RawSPUThread.h" -#include "Emu/SysCalls/SysCalls.h" #include "Thread.h" #ifdef _WIN32 @@ -21,10 +18,19 @@ static void report_fatal_error(const std::string& msg) { + std::string _msg = msg + "\n" + "HOW TO REPORT ERRORS:\n" + "1) Check the FAQ, readme, other sources. Please ensure that your hardware and software configuration is compliant.\n" + "2) You must provide FULL information: how to reproduce the error (your actions), RPCS3.log file, other *.log files whenever requested.\n" + "3) Please ensure that your software (game) is 'Playable' or close. Please note that 'Non-playable' games will be ignored.\n" + "4) If the software (game) is not 'Playable', please ensure that this error is unexpected, i.e. it didn't happen before or similar.\n" + "Please, don't send incorrect reports. Thanks for understanding.\n"; + #ifdef _WIN32 - MessageBoxA(0, msg.c_str(), "Fatal error", MB_ICONERROR); // TODO: unicode message + _msg += "Press (Ctrl+C) to copy this message."; + MessageBoxA(0, _msg.c_str(), "Fatal error", MB_ICONERROR); // TODO: unicode message #else - std::printf("Fatal error: %s\nPlease report this error to the developers.\n", msg.c_str()); + std::printf("Fatal error: \n%s", _msg.c_str()); #endif } @@ -34,9 +40,9 @@ static void report_fatal_error(const std::string& msg) { throw; } - catch (const std::exception& ex) + catch (const std::exception& e) { - report_fatal_error("Unhandled exception: "s + ex.what()); + report_fatal_error("Unhandled exception of type '"s + typeid(e).name() + "': "s + e.what()); } catch (...) { @@ -775,8 +781,7 @@ size_t get_x64_access_size(x64_context* context, x64_op_t op, x64_reg_t reg, siz if (op == X64OP_CMPXCHG) { - // detect whether this instruction can't actually modify memory to avoid breaking reservation; - // this may theoretically cause endless loop, but it shouldn't be a problem if only load_sync() generates such instruction + // Detect whether the instruction can't actually modify memory to avoid breaking reservation u64 cmp, exch; if (!get_x64_reg_value(context, reg, d_size, i_size, cmp) || !get_x64_reg_value(context, X64R_RAX, d_size, i_size, exch)) { @@ -843,7 +848,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) // check if address is RawSPU MMIO register if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET) { - auto thread = Emu.GetCPU().GetRawSPUThread((addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET); + auto thread = idm::get((addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET); if (!thread) { @@ -1051,10 +1056,10 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) switch (d_size) { - case 1: reg_value = sync_lock_test_and_set((u8*)vm::base_priv(addr), (u8)reg_value); break; - case 2: reg_value = sync_lock_test_and_set((u16*)vm::base_priv(addr), (u16)reg_value); break; - case 4: reg_value = sync_lock_test_and_set((u32*)vm::base_priv(addr), (u32)reg_value); break; - case 8: reg_value = sync_lock_test_and_set((u64*)vm::base_priv(addr), (u64)reg_value); break; + case 1: reg_value = ((atomic_t*)vm::base_priv(addr))->exchange((u8)reg_value); break; + case 2: reg_value = ((atomic_t*)vm::base_priv(addr))->exchange((u16)reg_value); break; + case 4: reg_value = ((atomic_t*)vm::base_priv(addr))->exchange((u32)reg_value); break; + case 8: reg_value = ((atomic_t*)vm::base_priv(addr))->exchange((u64)reg_value); break; default: return false; } @@ -1074,10 +1079,10 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) switch (d_size) { - case 1: old_value = sync_val_compare_and_swap((u8*)vm::base_priv(addr), (u8)cmp_value, (u8)reg_value); break; - case 2: old_value = sync_val_compare_and_swap((u16*)vm::base_priv(addr), (u16)cmp_value, (u16)reg_value); break; - case 4: old_value = sync_val_compare_and_swap((u32*)vm::base_priv(addr), (u32)cmp_value, (u32)reg_value); break; - case 8: old_value = sync_val_compare_and_swap((u64*)vm::base_priv(addr), (u64)cmp_value, (u64)reg_value); break; + case 1: old_value = ((atomic_t*)vm::base_priv(addr))->compare_and_swap((u8)cmp_value, (u8)reg_value); break; + case 2: old_value = ((atomic_t*)vm::base_priv(addr))->compare_and_swap((u16)cmp_value, (u16)reg_value); break; + case 4: old_value = ((atomic_t*)vm::base_priv(addr))->compare_and_swap((u32)cmp_value, (u32)reg_value); break; + case 8: old_value = ((atomic_t*)vm::base_priv(addr))->compare_and_swap((u64)cmp_value, (u64)reg_value); break; default: return false; } @@ -1097,10 +1102,10 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) switch (d_size) { - case 1: value &= sync_fetch_and_and((u8*)vm::base_priv(addr), (u8)value); break; - case 2: value &= sync_fetch_and_and((u16*)vm::base_priv(addr), (u16)value); break; - case 4: value &= sync_fetch_and_and((u32*)vm::base_priv(addr), (u32)value); break; - case 8: value &= sync_fetch_and_and((u64*)vm::base_priv(addr), (u64)value); break; + case 1: value = *(atomic_t*)vm::base_priv(addr) &= (u8)value; break; + case 2: value = *(atomic_t*)vm::base_priv(addr) &= (u16)value; break; + case 4: value = *(atomic_t*)vm::base_priv(addr) &= (u32)value; break; + case 8: value = *(atomic_t*)vm::base_priv(addr) &= (u64)value; break; default: return false; } @@ -1126,14 +1131,14 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) // TODO: allow recovering from a page fault as a feature of PS3 virtual memory } -// Throw virtual memory access violation exception -[[noreturn]] void throw_access_violation(const char* cause, u32 address) // Don't change function definition +[[noreturn]] static void throw_access_violation(const char* cause, u64 addr) { - throw EXCEPTION("Access violation %s location 0x%08x", cause, address); + vm::throw_access_violation(addr, cause); + std::abort(); } // Modify context in order to convert hardware exception to C++ exception -void prepare_throw_access_violation(x64_context* context, const char* cause, u32 address) +static void prepare_throw_access_violation(x64_context* context, const char* cause, u32 address) { // Set throw_access_violation() call args (old register values are lost) ARG1(context) = (u64)cause; @@ -1151,14 +1156,17 @@ static LONG exception_handler(PEXCEPTION_POINTERS pExp) const u64 addr64 = pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::base(0); const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0; - if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && addr64 < 0x100000000ull && thread_ctrl::get_current() && handle_access_violation((u32)addr64, is_writing, pExp->ContextRecord)) + if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && addr64 < 0x100000000ull) { - return EXCEPTION_CONTINUE_EXECUTION; - } - else - { - return EXCEPTION_CONTINUE_SEARCH; + vm::g_tls_fault_count++; + + if (thread_ctrl::get_current() && handle_access_violation((u32)addr64, is_writing, pExp->ContextRecord)) + { + return EXCEPTION_CONTINUE_EXECUTION; + } } + + return EXCEPTION_CONTINUE_SEARCH; } static LONG exception_filter(PEXCEPTION_POINTERS pExp) @@ -1170,8 +1178,9 @@ static LONG exception_filter(PEXCEPTION_POINTERS pExp) const u64 addr64 = pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::base(0); const auto cause = pExp->ExceptionRecord->ExceptionInformation[0] != 0 ? "writing" : "reading"; - if (addr64 < 0x100000000ull) + if (!(vm::g_tls_fault_count & (1ull << 63)) && addr64 < 0x100000000ull) { + vm::g_tls_fault_count |= (1ull << 63); // Setup throw_access_violation() call on the context prepare_throw_access_violation(pExp->ContextRecord, cause, (u32)addr64); return EXCEPTION_CONTINUE_EXECUTION; @@ -1190,33 +1199,23 @@ static LONG exception_filter(PEXCEPTION_POINTERS pExp) } msg += fmt::format("Instruction address: %p.\n", pExp->ContextRecord->Rip); - msg += fmt::format("Image base: %p.", GetModuleHandle(NULL)); + msg += fmt::format("Image base: %p.\n", GetModuleHandle(NULL)); + + if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION) + { + msg += "\n" + "Illegal instruction exception occured.\n" + "Note that your CPU must support SSSE3 extension.\n"; + } // TODO: print registers and the callstack - // Exception specific messages - if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) - { - msg += "\n\nAn internal access violation has occured." - "\nPlease only report this error to the developers, if you're an advanced user and have obtained a stack trace."; - } - else if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION) - { - msg += "\n\nAn internal illegal instruction exception has occured." - "\nRPCS3 requires a modern x86-64 CPU that supports SSSE3 (and SSE4.1 for PPU LLVM recompiler)." - "\nPlease make sure that your CPU supports these extensions."; - } - else - { - msg += "\n\nAn unknown internal exception has occured. Please report this to the developers.\nYou can press (Ctrl+C) to copy this message."; - } - // Report fatal error report_fatal_error(msg); return EXCEPTION_CONTINUE_SEARCH; } -const bool g_exception_handler_set = []() -> bool +const bool s_exception_handler_set = []() -> bool { if (!AddVectoredExceptionHandler(1, (PVECTORED_EXCEPTION_HANDLER)exception_handler)) { @@ -1248,12 +1247,12 @@ static void signal_handler(int sig, siginfo_t* info, void* uct) const u64 addr64 = (u64)info->si_addr - (u64)vm::base(0); const auto cause = is_writing ? "writing" : "reading"; - // TODO: Exception specific informative messages - - if (addr64 < 0x100000000ull && thread_ctrl::get_current()) + if (addr64 < 0x100000000ull) { + vm::g_tls_fault_count++; + // Try to process access violation - if (!handle_access_violation((u32)addr64, is_writing, context)) + if (!thread_ctrl::get_current() || !handle_access_violation((u32)addr64, is_writing, context)) { // Setup throw_access_violation() call on the context prepare_throw_access_violation(context, cause, (u32)addr64); @@ -1267,7 +1266,7 @@ static void signal_handler(int sig, siginfo_t* info, void* uct) } } -const bool g_exception_handler_set = []() -> bool +const bool s_exception_handler_set = []() -> bool { struct ::sigaction sa; sa.sa_flags = SA_SIGINFO; @@ -1285,17 +1284,33 @@ const bool g_exception_handler_set = []() -> bool #endif -thread_local thread_ctrl* thread_ctrl::g_tls_this_thread = nullptr; +const bool s_self_test = []() -> bool +{ + // Find ret instruction + if ((*(u8*)throw_access_violation & 0xF6) == 0xC2) + { + std::abort(); + } + + return true; +}(); + +thread_local DECLARE(thread_ctrl::g_tls_this_thread) = nullptr; // TODO -std::atomic g_thread_count{ 0 }; +atomic_t g_thread_count{ 0 }; void thread_ctrl::initialize() { - SetCurrentThreadDebugName(g_tls_this_thread->m_name().c_str()); + SetCurrentThreadDebugName(g_tls_this_thread->m_name.c_str()); + + _log::g_tls_make_prefix = [](const auto&, auto, const auto&) + { + return g_tls_this_thread->m_name; + }; // TODO - g_thread_count++; + ++g_thread_count; } void thread_ctrl::finalize() noexcept @@ -1304,79 +1319,36 @@ void thread_ctrl::finalize() noexcept vm::reservation_free(); // TODO - g_thread_count--; + --g_thread_count; // Call atexit functions - for (const auto& func : decltype(m_atexit)(std::move(g_tls_this_thread->m_atexit))) - { - func(); - } + g_tls_this_thread->m_atexit.exec(); } -thread_ctrl::~thread_ctrl() -{ - m_thread.detach(); - - if (m_future.valid()) - { - try - { - m_future.get(); - } - catch (...) - { - catch_all_exceptions(); - } - } -} - -std::string thread_ctrl::get_name() const -{ - CHECK_ASSERTION(m_name); - - return m_name(); -} - -std::string named_thread_t::get_name() const +std::string named_thread::get_name() const { return fmt::format("('%s') Unnamed Thread", typeid(*this).name()); } -void named_thread_t::start() +void named_thread::start() { - CHECK_ASSERTION(!m_thread); + Expects(!m_thread); // Get shared_ptr instance (will throw if called from the constructor or the object has been created incorrectly) - auto ptr = shared_from_this(); - - // Make name getter - auto name = [wptr = std::weak_ptr(ptr), type = &typeid(*this)]() - { - // Return actual name if available - if (const auto ptr = wptr.lock()) - { - return ptr->get_name(); - } - else - { - return fmt::format("('%s') Deleted Thread", type->name()); - } - }; + auto&& ptr = shared_from_this(); // Run thread - m_thread = thread_ctrl::spawn(std::move(name), [thread = std::move(ptr)]() + m_thread = thread_ctrl::spawn(get_name(), [thread = std::move(ptr)]() { try { LOG_TRACE(GENERAL, "Thread started"); - thread->on_task(); - LOG_TRACE(GENERAL, "Thread ended"); } catch (const std::exception& e) { - LOG_FATAL(GENERAL, "Exception: %s", e.what()); + LOG_FATAL(GENERAL, "%s thrown: %s", typeid(e).name(), e.what()); Emu.Pause(); } catch (EmulationStopped) @@ -1388,9 +1360,9 @@ void named_thread_t::start() }); } -void named_thread_t::join() +void named_thread::join() { - CHECK_ASSERTION(m_thread != nullptr); + Expects(m_thread); try { @@ -1403,11 +1375,3 @@ void named_thread_t::join() throw; } } - -const std::function SQUEUE_ALWAYS_EXIT = [](){ return true; }; -const std::function SQUEUE_NEVER_EXIT = [](){ return false; }; - -bool squeue_test_exit() -{ - return Emu.IsStopped(); -} diff --git a/Utilities/Thread.h b/Utilities/Thread.h index 557a83d7a0..f8d098dfda 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -1,24 +1,96 @@ #pragma once +#include +#include +#include +#include +#include +#include + +#include "Platform.h" + // Will report exception and call std::abort() if put in catch(...) [[noreturn]] void catch_all_exceptions(); +// Simple list of void() functors +class task_stack +{ + struct task_base + { + std::unique_ptr next; + + virtual ~task_base() = default; + + virtual void exec() + { + if (next) + { + next->exec(); + } + } + }; + + std::unique_ptr m_stack; + + never_inline void push(std::unique_ptr task) + { + m_stack.swap(task->next); + m_stack.swap(task); + } + +public: + template + void push(F&& func) + { + struct task_t : task_base + { + std::remove_reference_t func; + + task_t(F&& func) + : func(std::forward(func)) + { + } + + void exec() override + { + func(); + task_base::exec(); + } + }; + + return push(std::unique_ptr{ new task_t(std::forward(func)) }); + } + + void reset() + { + m_stack.reset(); + } + + void exec() const + { + if (m_stack) + { + m_stack->exec(); + } + } +}; + // Thread control class class thread_ctrl final { static thread_local thread_ctrl* g_tls_this_thread; - // Name getter - std::function m_name; + // Fixed name + std::string m_name; // Thread handle (be careful) std::thread m_thread; - // Thread result - std::future m_future; + // Thread result (exception) + std::exception_ptr m_exception; // Functions scheduled at thread exit - std::deque> m_atexit; + task_stack m_atexit; // Called at the thread start static void initialize(); @@ -27,24 +99,41 @@ class thread_ctrl final static void finalize() noexcept; public: - template - thread_ctrl(T&& name) - : m_name(std::forward(name)) + template + thread_ctrl(N&& name) + : m_name(std::forward(name)) { } // Disable copy/move constructors and operators thread_ctrl(const thread_ctrl&) = delete; - ~thread_ctrl(); + ~thread_ctrl() + { + if (m_thread.joinable()) + { + m_thread.detach(); + } + } // Get thread name - std::string get_name() const; + const std::string& get_name() const + { + return m_name; + } - // Get future result (may throw) + // Get thread result (may throw) void join() { - return m_future.get(); + if (m_thread.joinable()) + { + m_thread.join(); + } + + if (auto&& e = std::move(m_exception)) + { + std::rethrow_exception(e); + } } // Get current thread (may be nullptr) @@ -54,12 +143,10 @@ public: } // Register function at thread exit (for the current thread) - template - static inline void at_exit(T&& func) + template + static inline void at_exit(F&& func) { - CHECK_ASSERTION(g_tls_this_thread); - - g_tls_this_thread->m_atexit.emplace_front(std::forward(func)); + return g_tls_this_thread->m_atexit.push(std::forward(func)); } // Named thread factory @@ -68,12 +155,9 @@ public: { auto ctrl = std::make_shared(std::forward(name)); - std::promise promise; - - ctrl->m_future = promise.get_future(); - - ctrl->m_thread = std::thread([ctrl, task = std::forward(func)](std::promise promise) + ctrl->m_thread = std::thread([ctrl, task = std::forward(func)]() { + // Initialize TLS variable g_tls_this_thread = ctrl.get(); try @@ -81,21 +165,21 @@ public: initialize(); task(); finalize(); - promise.set_value(); } catch (...) { finalize(); - promise.set_exception(std::current_exception()); - } - }, std::move(promise)); + // Set exception + ctrl->m_exception = std::current_exception(); + } + }); return ctrl; } }; -class named_thread_t : public std::enable_shared_from_this +class named_thread : public std::enable_shared_from_this { // Pointer to managed resource (shared with actual thread) std::shared_ptr m_thread; @@ -107,6 +191,27 @@ public: // Thread mutex for external use (can be used with `cv`) std::mutex mutex; + // Lock mutex, notify condition variable + void safe_notify() + { + // Lock for reliable notification, condition is assumed to be changed externally + std::unique_lock lock(mutex); + + cv.notify_one(); + } + + // ID initialization + virtual void on_init() + { + start(); + } + + // ID finalization + virtual void on_stop() + { + join(); + } + protected: // Thread task (called in the thread) virtual void on_task() = 0; @@ -114,19 +219,13 @@ protected: // Thread finalization (called after on_task) virtual void on_exit() {} - // ID initialization (called through id_aux_initialize) - virtual void on_id_aux_initialize() { start(); } - - // ID finalization (called through id_aux_finalize) - virtual void on_id_aux_finalize() { join(); } - public: - named_thread_t() = default; + named_thread() = default; - virtual ~named_thread_t() = default; + virtual ~named_thread() = default; // Deleted copy/move constructors + copy/move operators - named_thread_t(const named_thread_t&) = delete; + named_thread(const named_thread&) = delete; // Get thread name virtual std::string get_name() const; @@ -134,377 +233,40 @@ public: // Start thread (cannot be called from the constructor: should throw bad_weak_ptr in such case) void start(); - // Join thread (get future result) + // Join thread (get thread result) void join(); - // Check whether the thread is not in "empty state" - bool is_started() const { return m_thread.operator bool(); } + // Get thread_ctrl + const thread_ctrl* get_thread_ctrl() const + { + return m_thread.get(); + } // Compare with the current thread - bool is_current() const { CHECK_ASSERTION(m_thread); return thread_ctrl::get_current() == m_thread.get(); } - - // Get thread_ctrl - const thread_ctrl* get_thread_ctrl() const { return m_thread.get(); } - - friend void id_aux_initialize(named_thread_t* ptr) { ptr->on_id_aux_initialize(); } - friend void id_aux_finalize(named_thread_t* ptr) { ptr->on_id_aux_finalize(); } + bool is_current() const + { + return m_thread && thread_ctrl::get_current() == m_thread.get(); + } }; // Wrapper for named thread, joins automatically in the destructor, can only be used in function scope -class scope_thread_t final +class scope_thread final { std::shared_ptr m_thread; public: template - scope_thread_t(N&& name, F&& func) + scope_thread(N&& name, F&& func) : m_thread(thread_ctrl::spawn(std::forward(name), std::forward(func))) { } // Deleted copy/move constructors + copy/move operators - scope_thread_t(const scope_thread_t&) = delete; + scope_thread(const scope_thread&) = delete; // Destructor with exceptions allowed - ~scope_thread_t() noexcept(false) + ~scope_thread() noexcept(false) { m_thread->join(); } }; - -extern const std::function SQUEUE_ALWAYS_EXIT; -extern const std::function SQUEUE_NEVER_EXIT; - -bool squeue_test_exit(); - -template -class squeue_t -{ - struct squeue_sync_var_t - { - struct - { - u32 position : 31; - u32 pop_lock : 1; - }; - struct - { - u32 count : 31; - u32 push_lock : 1; - }; - }; - - atomic_t m_sync; - - mutable std::mutex m_rcv_mutex; - mutable std::mutex m_wcv_mutex; - mutable std::condition_variable m_rcv; - mutable std::condition_variable m_wcv; - - T m_data[sq_size]; - - enum squeue_sync_var_result : u32 - { - SQSVR_OK = 0, - SQSVR_LOCKED = 1, - SQSVR_FAILED = 2, - }; - -public: - squeue_t() - : m_sync(squeue_sync_var_t{}) - { - } - - u32 get_max_size() const - { - return sq_size; - } - - bool is_full() const - { - return m_sync.load().count == sq_size; - } - - bool push(const T& data, const std::function& test_exit) - { - u32 pos = 0; - - while (u32 res = m_sync.atomic_op([&pos](squeue_sync_var_t& sync) -> u32 - { - assert(sync.count <= sq_size); - assert(sync.position < sq_size); - - if (sync.push_lock) - { - return SQSVR_LOCKED; - } - if (sync.count == sq_size) - { - return SQSVR_FAILED; - } - - sync.push_lock = 1; - pos = sync.position + sync.count; - return SQSVR_OK; - })) - { - if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit())) - { - return false; - } - - std::unique_lock wcv_lock(m_wcv_mutex); - m_wcv.wait_for(wcv_lock, std::chrono::milliseconds(1)); - } - - m_data[pos >= sq_size ? pos - sq_size : pos] = data; - - m_sync.atomic_op([](squeue_sync_var_t& sync) - { - assert(sync.count <= sq_size); - assert(sync.position < sq_size); - assert(sync.push_lock); - sync.push_lock = 0; - sync.count++; - }); - - m_rcv.notify_one(); - m_wcv.notify_one(); - return true; - } - - bool push(const T& data, const volatile bool* do_exit) - { - return push(data, [do_exit](){ return do_exit && *do_exit; }); - } - - force_inline bool push(const T& data) - { - return push(data, SQUEUE_NEVER_EXIT); - } - - force_inline bool try_push(const T& data) - { - return push(data, SQUEUE_ALWAYS_EXIT); - } - - bool pop(T& data, const std::function& test_exit) - { - u32 pos = 0; - - while (u32 res = m_sync.atomic_op([&pos](squeue_sync_var_t& sync) -> u32 - { - assert(sync.count <= sq_size); - assert(sync.position < sq_size); - - if (!sync.count) - { - return SQSVR_FAILED; - } - if (sync.pop_lock) - { - return SQSVR_LOCKED; - } - - sync.pop_lock = 1; - pos = sync.position; - return SQSVR_OK; - })) - { - if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit())) - { - return false; - } - - std::unique_lock rcv_lock(m_rcv_mutex); - m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1)); - } - - data = m_data[pos]; - - m_sync.atomic_op([](squeue_sync_var_t& sync) - { - assert(sync.count <= sq_size); - assert(sync.position < sq_size); - assert(sync.pop_lock); - sync.pop_lock = 0; - sync.position++; - sync.count--; - if (sync.position == sq_size) - { - sync.position = 0; - } - }); - - m_rcv.notify_one(); - m_wcv.notify_one(); - return true; - } - - bool pop(T& data, const volatile bool* do_exit) - { - return pop(data, [do_exit](){ return do_exit && *do_exit; }); - } - - force_inline bool pop(T& data) - { - return pop(data, SQUEUE_NEVER_EXIT); - } - - force_inline bool try_pop(T& data) - { - return pop(data, SQUEUE_ALWAYS_EXIT); - } - - bool peek(T& data, u32 start_pos, const std::function& test_exit) - { - assert(start_pos < sq_size); - u32 pos = 0; - - while (u32 res = m_sync.atomic_op([&pos, start_pos](squeue_sync_var_t& sync) -> u32 - { - assert(sync.count <= sq_size); - assert(sync.position < sq_size); - - if (sync.count <= start_pos) - { - return SQSVR_FAILED; - } - if (sync.pop_lock) - { - return SQSVR_LOCKED; - } - - sync.pop_lock = 1; - pos = sync.position + start_pos; - return SQSVR_OK; - })) - { - if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit())) - { - return false; - } - - std::unique_lock rcv_lock(m_rcv_mutex); - m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1)); - } - - data = m_data[pos >= sq_size ? pos - sq_size : pos]; - - m_sync.atomic_op([](squeue_sync_var_t& sync) - { - assert(sync.count <= sq_size); - assert(sync.position < sq_size); - assert(sync.pop_lock); - sync.pop_lock = 0; - }); - - m_rcv.notify_one(); - return true; - } - - bool peek(T& data, u32 start_pos, const volatile bool* do_exit) - { - return peek(data, start_pos, [do_exit](){ return do_exit && *do_exit; }); - } - - force_inline bool peek(T& data, u32 start_pos = 0) - { - return peek(data, start_pos, SQUEUE_NEVER_EXIT); - } - - force_inline bool try_peek(T& data, u32 start_pos = 0) - { - return peek(data, start_pos, SQUEUE_ALWAYS_EXIT); - } - - class squeue_data_t - { - T* const m_data; - const u32 m_pos; - const u32 m_count; - - squeue_data_t(T* data, u32 pos, u32 count) - : m_data(data) - , m_pos(pos) - , m_count(count) - { - } - - public: - T& operator [] (u32 index) - { - assert(index < m_count); - index += m_pos; - index = index < sq_size ? index : index - sq_size; - return m_data[index]; - } - }; - - void process(void(*proc)(squeue_data_t data)) - { - u32 pos, count; - - while (m_sync.atomic_op([&pos, &count](squeue_sync_var_t& sync) -> u32 - { - assert(sync.count <= sq_size); - assert(sync.position < sq_size); - - if (sync.pop_lock || sync.push_lock) - { - return SQSVR_LOCKED; - } - - pos = sync.position; - count = sync.count; - sync.pop_lock = 1; - sync.push_lock = 1; - return SQSVR_OK; - })) - { - std::unique_lock rcv_lock(m_rcv_mutex); - m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1)); - } - - proc(squeue_data_t(m_data, pos, count)); - - m_sync.atomic_op([](squeue_sync_var_t& sync) - { - assert(sync.count <= sq_size); - assert(sync.position < sq_size); - assert(sync.pop_lock && sync.push_lock); - sync.pop_lock = 0; - sync.push_lock = 0; - }); - - m_wcv.notify_one(); - m_rcv.notify_one(); - } - - void clear() - { - while (m_sync.atomic_op([](squeue_sync_var_t& sync) -> u32 - { - assert(sync.count <= sq_size); - assert(sync.position < sq_size); - - if (sync.pop_lock || sync.push_lock) - { - return SQSVR_LOCKED; - } - - sync.pop_lock = 1; - sync.push_lock = 1; - return SQSVR_OK; - })) - { - std::unique_lock rcv_lock(m_rcv_mutex); - m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1)); - } - - m_sync.exchange({}); - m_wcv.notify_one(); - m_rcv.notify_one(); - } -}; diff --git a/Utilities/VirtualMemory.cpp b/Utilities/VirtualMemory.cpp index 5a2d00e901..e0b2b2ed61 100644 --- a/Utilities/VirtualMemory.cpp +++ b/Utilities/VirtualMemory.cpp @@ -17,10 +17,10 @@ namespace memory_helper { #ifdef _WIN32 void* ret = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS); - CHECK_ASSERTION(ret != NULL); + Ensures(ret != NULL); #else void* ret = mmap(nullptr, size, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); - CHECK_ASSERTION(ret != 0); + Ensures(ret != 0); #endif return ret; } @@ -28,18 +28,18 @@ namespace memory_helper void commit_page_memory(void* pointer, size_t page_size) { #ifdef _WIN32 - CHECK_ASSERTION(VirtualAlloc((u8*)pointer, page_size, MEM_COMMIT, PAGE_READWRITE) != NULL); + ASSERT(VirtualAlloc((u8*)pointer, page_size, MEM_COMMIT, PAGE_READWRITE) != NULL); #else - CHECK_ASSERTION(mprotect((u8*)pointer, page_size, PROT_READ | PROT_WRITE) != -1); + ASSERT(mprotect((u8*)pointer, page_size, PROT_READ | PROT_WRITE) != -1); #endif } void free_reserved_memory(void* pointer, size_t size) { #ifdef _WIN32 - CHECK_ASSERTION(VirtualFree(pointer, 0, MEM_RELEASE) != 0); + ASSERT(VirtualFree(pointer, 0, MEM_RELEASE) != 0); #else - CHECK_ASSERTION(munmap(pointer, size) == 0); + ASSERT(munmap(pointer, size) == 0); #endif } } diff --git a/Utilities/config_context.cpp b/Utilities/config_context.cpp deleted file mode 100644 index 69b953d19d..0000000000 --- a/Utilities/config_context.cpp +++ /dev/null @@ -1,172 +0,0 @@ -#include "stdafx.h" -#include "config_context.h" -#include "StrFmt.h" -#include -#include - -void config_context_t::group::init() -{ - if(!m_cfg->m_groups[full_name()]) - m_cfg->m_groups[full_name()] = this; -} - -config_context_t::group::group(config_context_t* cfg, const std::string& name) - : m_cfg(cfg) - , m_name(name) - , m_parent(nullptr) -{ - init(); -} - -config_context_t::group::group(group* parent, const std::string& name) - : m_cfg(parent->m_cfg) - , m_name(name) - , m_parent(parent) -{ - init(); -} - -void config_context_t::group::set_parent(config_context_t* cfg) -{ - m_cfg = cfg; - init(); -} - -std::string config_context_t::group::name() const -{ - return m_name; -} - -std::string config_context_t::group::full_name() const -{ - if (m_parent) - return m_parent->full_name() + "/" + m_name; - - return m_name; -} - -void config_context_t::assign(const config_context_t& rhs) -{ - for (auto &rhs_g : rhs.m_groups) - { - auto g = m_groups.at(rhs_g.first); - - for (auto rhs_e : rhs_g.second->entries) - { - if (g->entries[rhs_e.first]) - g->entries[rhs_e.first]->value_from(rhs_e.second); - else - g->add_entry(rhs_e.first, rhs_e.second->string_value()); - } - } -} - -void config_context_t::deserialize(std::istream& stream) -{ - set_defaults(); - - uint line_index = 0; - std::string line; - group *current_group = nullptr; - - while (std::getline(stream, line)) - { - ++line_index; - line = fmt::trim(line); - - if (line.empty()) - continue; - - if (line.front() == '[' && line.back() == ']') - { - std::string group_name = line.substr(1, line.length() - 2); - - auto found = m_groups.find(group_name); - - if (found == m_groups.end()) - { - std::cerr << line_index << ": group '" << group_name << "' not exists. ignored" << std::endl; - current_group = nullptr; - continue; - } - - current_group = found->second; - continue; - } - - if (current_group == nullptr) - { - std::cerr << line_index << ": line '" << line << "' ignored, no group." << std::endl; - continue; - } - - auto name_value = fmt::split(line, { "=" }); - switch (name_value.size()) - { - case 1: - { - if (current_group->entries[fmt::trim(name_value[0])]) - current_group->entries[fmt::trim(name_value[0])]->string_value({}); - - else - current_group->add_entry(fmt::trim(name_value[0]), std::string{}); - } - break; - - default: - std::cerr << line_index << ": line '" << line << "' has more than one symbol '='. used only first" << std::endl; - case 2: - { - if (current_group->entries[fmt::trim(name_value[0])]) - current_group->entries[fmt::trim(name_value[0])]->string_value(fmt::trim(name_value[1])); - - else - current_group->add_entry(fmt::trim(name_value[0]), fmt::trim(name_value[1])); - } - break; - - } - } -} - -void config_context_t::serialize(std::ostream& stream) const -{ - for (auto &g : m_groups) - { - stream << "[" + g.first + "]" << std::endl; - - for (auto &e : g.second->entries) - { - stream << e.first << "=" << e.second->string_value() << std::endl; - } - - stream << std::endl; - } -} - -void config_context_t::set_defaults() -{ - for (auto &g : m_groups) - { - for (auto &e : g.second->entries) - { - e.second->to_default(); - } - } -} - -std::string config_context_t::to_string() const -{ - std::ostringstream result; - - serialize(result); - - return result.str(); -} - -void config_context_t::from_string(const std::string& str) -{ - std::istringstream source(str); - - deserialize(source); -} diff --git a/Utilities/config_context.h b/Utilities/config_context.h deleted file mode 100644 index 3263a38532..0000000000 --- a/Utilities/config_context.h +++ /dev/null @@ -1,164 +0,0 @@ -#pragma once -#include -#include -#include "convert.h" - -class config_context_t -{ -public: - class entry_base; - -protected: - class group - { - group* m_parent; - config_context_t* m_cfg; - std::string m_name; - std::vector> m_entries; - - void init(); - - public: - std::unordered_map entries; - - group(config_context_t* cfg, const std::string& name); - group(group* parent, const std::string& name); - void set_parent(config_context_t* cfg); - - std::string name() const; - std::string full_name() const; - - template - void add_entry(const std::string& name, const T& def_value) - { - m_entries.emplace_back(std::make_unique>(this, name, def_value)); - } - - template - T get_entry_value(const std::string& name, const T& def_value) - { - if (!entries[name]) - add_entry(name, def_value); - - return convert::to(entries[name]->string_value()); - } - - template - void set_entry_value(const std::string& name, const T& value) - { - if (entries[name]) - entries[name]->string_value(convert::to(value)); - - else - add_entry(name, value); - } - - friend config_context_t; - }; - -public: - class entry_base - { - public: - virtual ~entry_base() = default; - virtual std::string name() = 0; - virtual void to_default() = 0; - virtual std::string string_value() = 0; - virtual void string_value(const std::string& value) = 0; - virtual void value_from(const entry_base* rhs) = 0; - }; - - template - class entry : public entry_base - { - T m_default_value; - T m_value; - group* m_parent; - std::string m_name; - - public: - entry(group* parent, const std::string& name, const T& default_value) - : m_parent(parent) - , m_name(name) - , m_default_value(default_value) - , m_value(default_value) - { - if(!parent->entries[name]) - parent->entries[name] = this; - } - - T default_value() const - { - return m_default_value; - } - - T value() const - { - return m_value; - } - - void value(const T& new_value) - { - m_value = new_value; - } - - std::string name() override - { - return m_name; - } - - void to_default() override - { - value(default_value()); - } - - std::string string_value() override - { - return convert::to(value()); - } - - void string_value(const std::string &new_value) override - { - value(convert::to(new_value)); - } - - void value_from(const entry_base* rhs) override - { - value(static_cast(rhs)->value()); - } - - entry& operator = (const T& new_value) - { - value(new_value); - return *this; - } - - template - entry& operator = (const T2& new_value) - { - value(static_cast(new_value)); - return *this; - } - - explicit operator const T&() const - { - return m_value; - } - }; - -private: - std::unordered_map m_groups; - -public: - config_context_t() = default; - - void assign(const config_context_t& rhs); - - void serialize(std::ostream& stream) const; - void deserialize(std::istream& stream); - - void set_defaults(); - - std::string to_string() const; - void from_string(const std::string&); -}; diff --git a/Utilities/convert.h b/Utilities/convert.h deleted file mode 100644 index b190737fcb..0000000000 --- a/Utilities/convert.h +++ /dev/null @@ -1,279 +0,0 @@ -#pragma once -#include -#include "types.h" - -namespace convert -{ - template - struct to_impl_t; - - template - struct to_impl_t - { - static Type func(const Type& value) - { - return value; - } - }; - - template<> - struct to_impl_t - { - static std::string func(bool value) - { - return value ? "true" : "false"; - } - }; - - template<> - struct to_impl_t - { - static bool func(const std::string& value) - { - return value == "true" ? true : value == "false" ? false : throw std::invalid_argument(__FUNCTION__); - } - }; - - template<> - struct to_impl_t - { - static std::string func(signed char value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(unsigned char value) - { - return std::to_string(value); - } - }; - - - template<> - struct to_impl_t - { - static std::string func(short value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(unsigned short value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(int value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(unsigned int value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(long value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(unsigned long value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(long long value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(unsigned long long value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(float value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(double value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(long double value) - { - return std::to_string(value); - } - }; - - template<> - struct to_impl_t - { - static std::string func(size2i value) - { - return std::to_string(value.width) + "x" + std::to_string(value.height); - } - }; - - template<> - struct to_impl_t - { - static std::string func(position2i value) - { - return std::to_string(value.x) + ":" + std::to_string(value.y); - } - }; - - template<> - struct to_impl_t - { - static int func(const std::string& value) - { - return std::stoi(value); - } - }; - - template<> - struct to_impl_t - { - static unsigned int func(const std::string& value) - { - return (unsigned long)std::stoul(value); - } - }; - - template<> - struct to_impl_t - { - static long func(const std::string& value) - { - return std::stol(value); - } - }; - - template<> - struct to_impl_t - { - static unsigned long func(const std::string& value) - { - return std::stoul(value); - } - }; - - template<> - struct to_impl_t - { - static long long func(const std::string& value) - { - return std::stoll(value); - } - }; - - template<> - struct to_impl_t - { - static unsigned long long func(const std::string& value) - { - return std::stoull(value); - } - }; - - template<> - struct to_impl_t - { - static float func(const std::string& value) - { - return std::stof(value); - } - }; - - template<> - struct to_impl_t - { - static double func(const std::string& value) - { - return std::stod(value); - } - }; - - template<> - struct to_impl_t - { - static long double func(const std::string& value) - { - return std::stold(value); - } - }; - - template<> - struct to_impl_t - { - static size2i func(const std::string& value) - { - const auto& data = fmt::split(value, { "x" }); - return { std::stoi(data[0]), std::stoi(data[1]) }; - } - }; - - template<> - struct to_impl_t - { - static position2i func(const std::string& value) - { - const auto& data = fmt::split(value, { ":" }); - return { std::stoi(data[0]), std::stoi(data[1]) }; - } - }; - - template - ReturnType to(FromType value) - { - return to_impl_t, std::remove_all_extents_t>::func(value); - } -} diff --git a/Utilities/rPlatform.cpp b/Utilities/rPlatform.cpp deleted file mode 100644 index 53f7e783d7..0000000000 --- a/Utilities/rPlatform.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "stdafx.h" -#include "restore_new.h" -#include "Utilities/Log.h" -#pragma warning(push) -#pragma message("TODO: remove wx dependency: ") -#pragma warning(disable : 4996) -#include -#pragma warning(pop) -#include "define_new_memleakdetect.h" - -#ifndef _WIN32 -#include -#endif - -#include "rPlatform.h" - -rImage::rImage() -{ - handle = static_cast(new wxImage()); -} - -rImage::~rImage() -{ - delete static_cast(handle); -} - -void rImage::Create(int width, int height, void *data, void *alpha) -{ - static_cast(handle)->Create(width, height, static_cast(data), static_cast(alpha)); -} -void rImage::SaveFile(const std::string& name, rImageType type) -{ - if (type == rBITMAP_TYPE_PNG) - { - static_cast(handle)->SaveFile(fmt::FromUTF8(name),wxBITMAP_TYPE_PNG); - } - else - { - throw EXCEPTION("unsupported type"); - } -} diff --git a/Utilities/rPlatform.h b/Utilities/rPlatform.h deleted file mode 100644 index 09308edb53..0000000000 --- a/Utilities/rPlatform.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -/********************************************************************** -*********** RSX Debugger -************************************************************************/ - -struct RSXDebuggerProgram -{ - u32 id; - u32 vp_id; - u32 fp_id; - std::string vp_shader; - std::string fp_shader; - bool modified; - - RSXDebuggerProgram() - : modified(false) - { - } -}; - -extern std::vector m_debug_programs; - -/********************************************************************** -*********** Image stuff -************************************************************************/ -enum rImageType -{ - rBITMAP_TYPE_PNG -}; -struct rImage -{ - rImage(); - rImage(const rImage &) = delete; - ~rImage(); - void Create(int width , int height, void *data, void *alpha); - void SaveFile(const std::string& name, rImageType type); - - void *handle; -}; diff --git a/Utilities/rTime.cpp b/Utilities/rTime.cpp deleted file mode 100644 index 9687141302..0000000000 --- a/Utilities/rTime.cpp +++ /dev/null @@ -1,235 +0,0 @@ -#include "stdafx.h" -#include "rTime.h" -#pragma warning(push) -#pragma message("TODO: remove wx dependency: ") -#pragma warning(disable : 4996) -#include -#pragma warning(pop) - -std::string rDefaultDateTimeFormat = "%c"; - -rTimeSpan::rTimeSpan() -{ - handle = static_cast(new wxTimeSpan()); -} - -rTimeSpan::~rTimeSpan() -{ - delete static_cast(handle); -} - -rTimeSpan::rTimeSpan(const rTimeSpan& other) - -{ - handle = static_cast(new wxTimeSpan(*static_cast(other.handle))); - -} - -rTimeSpan::rTimeSpan(int a, int b , int c, int d) -{ - handle = static_cast(new wxTimeSpan(a,b,c,d)); -} - - -rDateSpan::rDateSpan() -{ - handle = static_cast(new wxDateSpan()); -} - -rDateSpan::~rDateSpan() -{ - delete static_cast(handle); -} - -rDateSpan::rDateSpan(const rDateSpan& other) -{ - handle = static_cast(new wxDateSpan(*static_cast(other.handle))); -} - -rDateSpan::rDateSpan(int a, int b, int c, int d) -{ - handle = static_cast(new wxDateSpan(a,b,c,d)); -} - -rDateTime::rDateTime() -{ - handle = static_cast(new wxDateTime()); -} - -rDateTime::~rDateTime() -{ - delete static_cast(handle); -} - -rDateTime::rDateTime(const rDateTime& other) -{ - handle = static_cast(new wxDateTime(*static_cast(other.handle))); -} - -rDateTime::rDateTime(const time_t& time) -{ - handle = static_cast(new wxDateTime(time)); -} - -rDateTime::rDateTime(u16 day, rDateTime::Month month, u16 year, u16 hour, u16 minute, u16 second, u32 millisecond) -{ - handle = static_cast(new wxDateTime(day,(wxDateTime::Month)month,year,hour,minute,second,millisecond)); -} - -rDateTime rDateTime::UNow() -{ - rDateTime time; - delete static_cast(time.handle); - time.handle = static_cast(new wxDateTime(wxDateTime::UNow())); - - return time; -} - -rDateTime rDateTime::FromUTC(bool val) -{ - rDateTime time(*this); - void *temp = time.handle; - - time.handle = static_cast(new wxDateTime(static_cast(temp)->FromTimezone(wxDateTime::GMT0, val))); - delete static_cast(temp); - - return time; -} - -rDateTime rDateTime::ToUTC(bool val) -{ - rDateTime time(*this); - void *temp = time.handle; - - time.handle = static_cast(new wxDateTime(static_cast(temp)->ToTimezone(wxDateTime::GMT0, val))); - delete static_cast(temp); - - return time; -} - -time_t rDateTime::GetTicks() -{ - return static_cast(handle)->GetTicks(); -} - -void rDateTime::Add(const rTimeSpan& span) -{ - static_cast(handle)->Add(*static_cast(span.handle)); -} - -void rDateTime::Add(const rDateSpan& span) -{ - static_cast(handle)->Add(*static_cast(span.handle)); -} - -wxDateTime::TimeZone convertTZ(rDateTime::rTimeZone tz) -{ - switch (tz) - { - case rDateTime::Local: - return wxDateTime::Local; - case rDateTime::GMT0: - return wxDateTime::GMT0; - case rDateTime::UTC: - return wxDateTime::UTC; - default: - throw EXCEPTION("WRONG DATETIME"); - } -} - -std::string rDateTime::Format(const std::string &format, const rTimeZone &tz) const -{ - return fmt::ToUTF8(static_cast(handle)->Format(fmt::FromUTF8(format),convertTZ(tz))); -} - -void rDateTime::ParseDateTime(const char* format) -{ - static_cast(handle)->ParseDateTime(format); -} - -u32 rDateTime::GetAsDOS() -{ - return static_cast(handle)->GetAsDOS(); -} - -rDateTime &rDateTime::SetFromDOS(u32 fromdos) -{ - static_cast(handle)->SetFromDOS(fromdos); - return *this; -} - -bool rDateTime::IsLeapYear(int year, rDateTime::Calender cal) -{ - if (cal == Gregorian) - { - return wxDateTime::IsLeapYear(year, wxDateTime::Gregorian); - } - else - { - return wxDateTime::IsLeapYear(year, wxDateTime::Julian); - } -} - -int rDateTime::GetNumberOfDays(rDateTime::Month month, int year, rDateTime::Calender cal) -{ - if (cal == Gregorian) - { - return wxDateTime::GetNumberOfDays(static_cast(month), year, wxDateTime::Gregorian); - } - else - { - return wxDateTime::GetNumberOfDays(static_cast(month), year, wxDateTime::Julian); - } -} - -void rDateTime::SetToWeekDay(rDateTime::WeekDay day, int n, rDateTime::Month month, int year) -{ - static_cast(handle)->SetToWeekDay( - static_cast(day) - , n - , static_cast(month) - , year - ); -} - -int rDateTime::GetWeekDay() -{ - return static_cast(handle)->GetWeekDay(); -} - -u16 rDateTime::GetYear(rDateTime::TZ timezone) -{ - return static_cast(handle)->GetYear(convertTZ(timezone)); -} - -u16 rDateTime::GetMonth(rDateTime::TZ timezone) -{ - return static_cast(handle)->GetMonth(convertTZ(timezone)); -} - -u16 rDateTime::GetDay(rDateTime::TZ timezone) -{ - return static_cast(handle)->GetDay(convertTZ(timezone)); -} - -u16 rDateTime::GetHour(rDateTime::TZ timezone) -{ - return static_cast(handle)->GetHour(convertTZ(timezone)); -} - -u16 rDateTime::GetMinute(rDateTime::TZ timezone) -{ - return static_cast(handle)->GetMinute(convertTZ(timezone)); -} - -u16 rDateTime::GetSecond(rDateTime::TZ timezone) -{ - return static_cast(handle)->GetSecond(convertTZ(timezone)); -} - -u32 rDateTime::GetMillisecond(rDateTime::TZ timezone) -{ - return static_cast(handle)->GetMillisecond(convertTZ(timezone)); -} - - diff --git a/Utilities/rTime.h b/Utilities/rTime.h deleted file mode 100644 index 9c39c46b30..0000000000 --- a/Utilities/rTime.h +++ /dev/null @@ -1,102 +0,0 @@ -#pragma once - -extern std::string rDefaultDateTimeFormat; - - -struct rTimeSpan -{ - rTimeSpan(); - ~rTimeSpan(); - rTimeSpan(const rTimeSpan& other); - rTimeSpan(int, int, int, int); - - void *handle; -}; - -struct rDateSpan -{ - rDateSpan(); - ~rDateSpan(); - rDateSpan(const rDateSpan& other); - rDateSpan(int, int, int, int); - - void *handle; -}; - -struct rDateTime -{ - enum TZ - { - Local, GMT0,UTC - }; - enum Calender - { - Gregorian, Julian - }; - - using rTimeZone = TZ; - - enum WeekDay - { - Sun = 0, - Mon, - Tue, - Wed, - Thu, - Fri, - Sat, - Inv_WeekDay - }; - - enum Month { - Jan = 0, - Feb = 1, - Mar = 2, - Apr = 3, - May = 4, - Jun = 5, - Jul = 6, - Aug = 7, - Sep = 8, - Oct = 9, - Nov = 10, - Dec = 11, - Inv_Month = 12 - }; - - rDateTime(); - ~rDateTime(); - rDateTime(const rDateTime& other); - rDateTime(const time_t &time); - rDateTime(u16 day, rDateTime::Month month, u16 year, u16 hour, u16 minute, u16 second, u32 millisecond); - - static rDateTime UNow(); - rDateTime FromUTC(bool val); - rDateTime ToUTC(bool val); - time_t GetTicks(); - void Add(const rTimeSpan& span); - void Add(const rDateSpan& span); - void Close(); - std::string Format(const std::string &format = rDefaultDateTimeFormat, const rTimeZone &tz = Local) const; - - void ParseDateTime(const char* format); - - u32 GetAsDOS(); - rDateTime &SetFromDOS(u32 fromdos); - - static bool IsLeapYear(int year, rDateTime::Calender cal); - static int GetNumberOfDays(rDateTime::Month month, int year, rDateTime::Calender cal); - void SetToWeekDay(rDateTime::WeekDay day, int n, rDateTime::Month month, int year); - int GetWeekDay(); - - u16 GetYear( rDateTime::TZ timezone); - u16 GetMonth(rDateTime::TZ timezone); - u16 GetDay(rDateTime::TZ timezone); - u16 GetHour(rDateTime::TZ timezone); - u16 GetMinute(rDateTime::TZ timezone); - u16 GetSecond(rDateTime::TZ timezone); - u32 GetMillisecond(rDateTime::TZ timezone); - - void *handle; -}; - diff --git a/Utilities/types.h b/Utilities/types.h index ab011c2e3c..dd2f76e0a3 100644 --- a/Utilities/types.h +++ b/Utilities/types.h @@ -1,16 +1,21 @@ #pragma once +#include #include +#include +#include +#include #include #include -#include +#include "Platform.h" + +using schar = signed char; using uchar = unsigned char; using ushort = unsigned short; using uint = unsigned int; using ulong = unsigned long; using ullong = unsigned long long; - using llong = long long; using u8 = std::uint8_t; @@ -23,6 +28,350 @@ using s16 = std::int16_t; using s32 = std::int32_t; using s64 = std::int64_t; +// Specialization with static constexpr pair map[] member expected +template +struct bijective; + +template +struct atomic_storage; + +template +struct atomic_add; + +template +struct atomic_sub; + +template +struct atomic_and; + +template +struct atomic_or; + +template +struct atomic_xor; + +template +struct atomic_pre_inc; + +template +struct atomic_post_inc; + +template +struct atomic_pre_dec; + +template +struct atomic_post_dec; + +template +struct atomic_test_and_set; + +template +struct atomic_test_and_reset; + +template +struct atomic_test_and_complement; + +template +class atomic_t; + +namespace fmt +{ + template + struct unveil; +} + +// TODO: replace with std::void_t when available +namespace void_details +{ + template + struct make_void + { + using type = void; + }; +} + +template using void_t = typename void_details::make_void::type; + +// Extract T::simple_type if available, remove cv qualifiers +template +struct simple_type_helper +{ + using type = typename std::remove_cv::type; +}; + +template +struct simple_type_helper> +{ + using type = typename T::simple_type; +}; + +template using simple_t = typename simple_type_helper::type; + +// Bool type equivalent +class b8 +{ + std::uint8_t m_value; + +public: + b8() = default; + + constexpr b8(bool value) + : m_value(value) + { + } + + constexpr operator bool() const + { + return m_value != 0; + } +}; + +// Bool wrapper for restricting bool result conversions +struct explicit_bool_t +{ + const bool value; + + constexpr explicit_bool_t(bool value) + : value(value) + { + } + + explicit constexpr operator bool() const + { + return value; + } +}; + +#ifndef _MSC_VER +using u128 = __uint128_t; +using s128 = __int128_t; +#else + +#include "intrin.h" + +// Unsigned 128-bit integer implementation (TODO) +struct alignas(16) u128 +{ + std::uint64_t lo, hi; + + u128() = default; + + constexpr u128(std::uint64_t l) + : lo(l) + , hi(0) + { + } + + friend u128 operator +(const u128& l, const u128& r) + { + u128 value; + _addcarry_u64(_addcarry_u64(0, r.lo, l.lo, &value.lo), r.hi, l.hi, &value.hi); + return value; + } + + friend u128 operator +(const u128& l, std::uint64_t r) + { + u128 value; + _addcarry_u64(_addcarry_u64(0, r, l.lo, &value.lo), l.hi, 0, &value.hi); + return value; + } + + friend u128 operator +(std::uint64_t l, const u128& r) + { + u128 value; + _addcarry_u64(_addcarry_u64(0, r.lo, l, &value.lo), 0, r.hi, &value.hi); + return value; + } + + friend u128 operator -(const u128& l, const u128& r) + { + u128 value; + _subborrow_u64(_subborrow_u64(0, r.lo, l.lo, &value.lo), r.hi, l.hi, &value.hi); + return value; + } + + friend u128 operator -(const u128& l, std::uint64_t r) + { + u128 value; + _subborrow_u64(_subborrow_u64(0, r, l.lo, &value.lo), 0, l.hi, &value.hi); + return value; + } + + friend u128 operator -(std::uint64_t l, const u128& r) + { + u128 value; + _subborrow_u64(_subborrow_u64(0, r.lo, l, &value.lo), r.hi, 0, &value.hi); + return value; + } + + u128 operator +() const + { + return *this; + } + + u128 operator -() const + { + u128 value; + _subborrow_u64(_subborrow_u64(0, lo, 0, &value.lo), hi, 0, &value.hi); + return value; + } + + u128& operator ++() + { + _addcarry_u64(_addcarry_u64(0, 1, lo, &lo), 0, hi, &hi); + return *this; + } + + u128 operator ++(int) + { + u128 value = *this; + _addcarry_u64(_addcarry_u64(0, 1, lo, &lo), 0, hi, &hi); + return value; + } + + u128& operator --() + { + _subborrow_u64(_subborrow_u64(0, 1, lo, &lo), 0, hi, &hi); + return *this; + } + + u128 operator --(int) + { + u128 value = *this; + _subborrow_u64(_subborrow_u64(0, 1, lo, &lo), 0, hi, &hi); + return value; + } + + u128 operator ~() const + { + u128 value; + value.lo = ~lo; + value.hi = ~hi; + return value; + } + + friend u128 operator &(const u128& l, const u128& r) + { + u128 value; + value.lo = l.lo & r.lo; + value.hi = l.hi & r.hi; + return value; + } + + friend u128 operator |(const u128& l, const u128& r) + { + u128 value; + value.lo = l.lo | r.lo; + value.hi = l.hi | r.hi; + return value; + } + + friend u128 operator ^(const u128& l, const u128& r) + { + u128 value; + value.lo = l.lo ^ r.lo; + value.hi = l.hi ^ r.hi; + return value; + } + + u128& operator +=(const u128& r) + { + _addcarry_u64(_addcarry_u64(0, r.lo, lo, &lo), r.hi, hi, &hi); + return *this; + } + + u128& operator +=(uint64_t r) + { + _addcarry_u64(_addcarry_u64(0, r, lo, &lo), 0, hi, &hi); + return *this; + } + + u128& operator &=(const u128& r) + { + lo &= r.lo; + hi &= r.hi; + return *this; + } + + u128& operator |=(const u128& r) + { + lo |= r.lo; + hi |= r.hi; + return *this; + } + + u128& operator ^=(const u128& r) + { + lo ^= r.lo; + hi ^= r.hi; + return *this; + } +}; + +// Signed 128-bit integer implementation (TODO) +struct alignas(16) s128 +{ + std::uint64_t lo; + std::int64_t hi; + + s128() = default; + + constexpr s128(std::int64_t l) + : hi(l >> 63) + , lo(l) + { + } + + constexpr s128(std::uint64_t l) + : hi(0) + , lo(l) + { + } +}; +#endif + +namespace std +{ + /* Let's hack. */ + + template<> + struct is_integral : true_type + { + }; + + template<> + struct is_integral : true_type + { + }; + + template<> + struct make_unsigned + { + using type = u128; + }; + + template<> + struct make_unsigned + { + using type = u128; + }; + + template<> + struct make_signed + { + using type = s128; + }; + + template<> + struct make_signed + { + using type = s128; + }; +} + +static_assert(std::is_arithmetic::value && std::is_integral::value && alignof(u128) == 16 && sizeof(u128) == 16, "Wrong u128 implementation"); +static_assert(std::is_arithmetic::value && std::is_integral::value && alignof(s128) == 16 && sizeof(s128) == 16, "Wrong s128 implementation"); + union alignas(2) f16 { u16 _u16; @@ -55,6 +404,313 @@ struct ignore } }; +// Allows to define integer convertible to multiple enum types +template +struct multicast : multicast +{ + static_assert(std::is_enum::value, "multicast<> error: invalid conversion type (enum type expected)"); + + multicast() = default; + + template + constexpr multicast(const UT& value) + : multicast(value) + , m_value{ value } // Forbid narrowing + { + } + + constexpr operator T() const + { + // Cast to enum type + return static_cast(m_value); + } + +private: + std::underlying_type_t m_value; +}; + +// Recursion terminator +template<> +struct multicast +{ + multicast() = default; + + template + constexpr multicast(const UT& value) + { + } +}; + +// Small bitset for enum class types with available values [0, bitsize). +// T must be either enum type or convertible to (registered with via simple_t). +// Internal representation is single value of type T. +template +struct mset +{ + using type = simple_t; + using under = std::underlying_type_t; + + static constexpr auto bitsize = sizeof(type) * CHAR_BIT; + + mset() = default; + + constexpr mset(type _enum_const) + : m_value(static_cast(shift(_enum_const))) + { + } + + constexpr mset(under raw_value, const std::nothrow_t&) + : m_value(static_cast(raw_value)) + { + } + + // Get underlying value + constexpr under _value() const + { + return static_cast(m_value); + } + + explicit constexpr operator bool() const + { + return _value() ? true : false; + } + + mset& operator +=(mset rhs) + { + return *this = { _value() | rhs._value(), std::nothrow }; + } + + mset& operator -=(mset rhs) + { + return *this = { _value() & ~rhs._value(), std::nothrow }; + } + + mset& operator &=(mset rhs) + { + return *this = { _value() & rhs._value(), std::nothrow }; + } + + mset& operator ^=(mset rhs) + { + return *this = { _value() ^ rhs._value(), std::nothrow }; + } + + friend constexpr mset operator +(mset lhs, mset rhs) + { + return{ lhs._value() | rhs._value(), std::nothrow }; + } + + friend constexpr mset operator -(mset lhs, mset rhs) + { + return{ lhs._value() & ~rhs._value(), std::nothrow }; + } + + friend constexpr mset operator &(mset lhs, mset rhs) + { + return{ lhs._value() & rhs._value(), std::nothrow }; + } + + friend constexpr mset operator ^(mset lhs, mset rhs) + { + return{ lhs._value() ^ rhs._value(), std::nothrow }; + } + + bool test(mset rhs) const + { + const under v = _value(); + const under s = rhs._value(); + return (v & s) != 0; + } + + bool test_and_set(mset rhs) + { + const under v = _value(); + const under s = rhs._value(); + *this = { v | s, std::nothrow }; + return (v & s) != 0; + } + + bool test_and_reset(mset rhs) + { + const under v = _value(); + const under s = rhs._value(); + *this = { v & ~s, std::nothrow }; + return (v & s) != 0; + } + + bool test_and_complement(mset rhs) + { + const under v = _value(); + const under s = rhs._value(); + *this = { v ^ s, std::nothrow }; + return (v & s) != 0; + } + +private: + [[noreturn]] static under xrange() + { + throw std::out_of_range("mset<>: bit out of range"); + } + + static constexpr under shift(const T& value) + { + return static_cast(value) < bitsize ? static_cast(1) << static_cast(value) : xrange(); + } + + T m_value; +}; + +template +constexpr RT to_mset() +{ + return RT{}; +} + +// Fold enum constants into mset<> +template::value, mset, T>> +constexpr RT to_mset(Arg&& _enum_const, Args&&... args) +{ + return RT{ std::forward(_enum_const) } + to_mset(std::forward(args)...); +} + +template +struct atomic_add, CT, std::enable_if_t::value>> +{ + using under = typename mset::under; + + static force_inline mset op1(mset& left, mset right) + { + return{ atomic_storage::fetch_or(reinterpret_cast(left), right._value()), std::nothrow }; + } + + static constexpr auto fetch_op = &op1; + + static force_inline mset op2(mset& left, mset right) + { + return{ atomic_storage::or_fetch(reinterpret_cast(left), right._value()), std::nothrow }; + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_sub, CT, std::enable_if_t::value>> +{ + using under = typename mset::under; + + static force_inline mset op1(mset& left, mset right) + { + return{ atomic_storage::fetch_and(reinterpret_cast(left), ~right._value()), std::nothrow }; + } + + static constexpr auto fetch_op = &op1; + + static force_inline mset op2(mset& left, mset right) + { + return{ atomic_storage::and_fetch(reinterpret_cast(left), ~right._value()), std::nothrow }; + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_and, CT, std::enable_if_t::value>> +{ + using under = typename mset::under; + + static force_inline mset op1(mset& left, mset right) + { + return{ atomic_storage::fetch_and(reinterpret_cast(left), right._value()), std::nothrow }; + } + + static constexpr auto fetch_op = &op1; + + static force_inline mset op2(mset& left, mset right) + { + return{ atomic_storage::and_fetch(reinterpret_cast(left), right._value()), std::nothrow }; + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_xor, CT, std::enable_if_t::value>> +{ + using under = typename mset::under; + + static force_inline mset op1(mset& left, mset right) + { + return{ atomic_storage::fetch_xor(reinterpret_cast(left), right._value()), std::nothrow }; + } + + static constexpr auto fetch_op = &op1; + + static force_inline mset op2(mset& left, mset right) + { + return{ atomic_storage::xor_fetch(reinterpret_cast(left), right._value()), std::nothrow }; + } + + static constexpr auto op_fetch = &op2; + static constexpr auto atomic_op = &op2; +}; + +template +struct atomic_test_and_set, T, std::enable_if_t::value>> +{ + using under = typename mset::under; + + static force_inline bool _op(mset& left, const T& value) + { + return atomic_storage::bts(reinterpret_cast(left), static_cast(value)); + } + + static constexpr auto atomic_op = &_op; +}; + +template +struct atomic_test_and_reset, T, std::enable_if_t::value>> +{ + using under = typename mset::under; + + static force_inline bool _op(mset& left, const T& value) + { + return atomic_storage::btr(reinterpret_cast(left), static_cast(value)); + } + + static constexpr auto atomic_op = &_op; +}; + +template +struct atomic_test_and_complement, T, std::enable_if_t::value>> +{ + using under = typename mset::under; + + static force_inline bool _op(mset& left, const T& value) + { + return atomic_storage::btc(reinterpret_cast(left), static_cast(value)); + } + + static constexpr auto atomic_op = &_op; +}; + +template +T2 bijective_find(const T& left, const DT& def = {}) +{ + for (const auto& pair : bijective::map) + { + if (pair.first == left) + { + return pair.second; + } + } + + return def; +} + + template struct size2_base { @@ -1088,15 +1744,3 @@ using color2d = color2_base; using color1i = color1_base; using color1f = color1_base; using color1d = color1_base; - -namespace std -{ - template<> - struct hash<::position2i> - { - size_t operator()(const ::position2i& position) const - { - return (static_cast(position.x) << 32) | position.y; - } - }; -} diff --git a/Utilities/wxWidgets/setup.h b/Utilities/wxWidgets/setup.h index 9cfcf48126..ff342b42ac 100644 --- a/Utilities/wxWidgets/setup.h +++ b/Utilities/wxWidgets/setup.h @@ -300,7 +300,7 @@ // Recommended setting: 0 as the options below already provide a relatively // good level of interoperability and changing this option arguably isn't worth // diverging from the official builds of the library. -#define wxUSE_STL 0 +#define wxUSE_STL 1 // This is not a real option but is used as the default value for // wxUSE_STD_IOSTREAM, wxUSE_STD_STRING and wxUSE_STD_CONTAINERS_COMPATIBLY. diff --git a/Utilities/yaml-cpp.vcxproj b/Utilities/yaml-cpp.vcxproj new file mode 100644 index 0000000000..5eae51ce94 --- /dev/null +++ b/Utilities/yaml-cpp.vcxproj @@ -0,0 +1,99 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {FDC361C5-7734-493B-8CFB-037308B35122} + yamlcpp + 8.1 + + + + StaticLibrary + Unicode + v140 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Utilities/yaml-cpp.vcxproj.filters b/Utilities/yaml-cpp.vcxproj.filters new file mode 100644 index 0000000000..7b035827f8 --- /dev/null +++ b/Utilities/yaml-cpp.vcxproj.filters @@ -0,0 +1,92 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + 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 + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/Utilities/yaml-cpp.vcxproj.user b/Utilities/yaml-cpp.vcxproj.user new file mode 100644 index 0000000000..abe8dd8961 --- /dev/null +++ b/Utilities/yaml-cpp.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From 2553e45d76025120b14b9559e80b74a078c029b7 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 2 Feb 2016 00:47:09 +0300 Subject: [PATCH 03/19] Partial commit: Loader --- rpcs3/Loader/ELF.h | 348 ++++++++++++++++++ rpcs3/Loader/ELF32.cpp | 453 ------------------------ rpcs3/Loader/ELF32.h | 139 -------- rpcs3/Loader/ELF64.cpp | 737 --------------------------------------- rpcs3/Loader/ELF64.h | 164 --------- rpcs3/Loader/Loader.cpp | 130 ------- rpcs3/Loader/Loader.h | 131 ------- rpcs3/Loader/PSF.cpp | 42 +-- rpcs3/Loader/PSF.h | 27 +- rpcs3/Loader/TROPUSR.cpp | 87 ++--- rpcs3/Loader/TROPUSR.h | 10 +- rpcs3/Loader/TRP.cpp | 47 +-- rpcs3/Loader/TRP.h | 20 +- 13 files changed, 450 insertions(+), 1885 deletions(-) create mode 100644 rpcs3/Loader/ELF.h delete mode 100644 rpcs3/Loader/ELF32.cpp delete mode 100644 rpcs3/Loader/ELF32.h delete mode 100644 rpcs3/Loader/ELF64.cpp delete mode 100644 rpcs3/Loader/ELF64.h delete mode 100644 rpcs3/Loader/Loader.cpp delete mode 100644 rpcs3/Loader/Loader.h diff --git a/rpcs3/Loader/ELF.h b/rpcs3/Loader/ELF.h new file mode 100644 index 0000000000..3430fc1d2d --- /dev/null +++ b/rpcs3/Loader/ELF.h @@ -0,0 +1,348 @@ +#pragma once + +#include "../../Utilities/File.h" + +enum class elf_os : u8 +{ + none = 0, + + lv2 = 0x66, +}; + +enum class elf_type : u16 +{ + none = 0, + rel = 1, + exec = 2, + dyn = 3, + core = 4, + + prx = 0xffa4, + + psv1 = 0xfe00, // ET_SCE_EXEC + psv2 = 0xfe04, // ET_SCE_RELEXEC (vitasdk) +}; + +enum class elf_machine : u16 +{ + ppc64 = 0x15, + spu = 0x17, + arm = 0x28, + mips = 0x08, +}; + +template class en_t, typename sz_t> +struct elf_ehdr +{ + nse_t e_magic; + u8 e_class; + u8 e_data; + u8 e_curver; + elf_os e_os_abi; + u8 e_abi_ver; + u8 e_pad[7]; + en_t e_type; + en_t e_machine; + en_t e_version; + en_t e_entry; + en_t e_phoff; + en_t e_shoff; + en_t e_flags; + en_t e_ehsize; + en_t e_phentsize; + en_t e_phnum; + en_t e_shentsize; + en_t e_shnum; + en_t e_shstrndx; +}; + +template class en_t, typename sz_t> +struct elf_phdr +{ + static_assert(!sizeof(sz_t), "Invalid elf size type (must be u32 or u64)"); +}; + +template class en_t> +struct elf_phdr +{ + en_t p_type; + en_t p_flags; + en_t p_offset; + en_t p_vaddr; + en_t p_paddr; + en_t p_filesz; + en_t p_memsz; + en_t p_align; +}; + +template class en_t> +struct elf_phdr +{ + en_t p_type; + en_t p_offset; + en_t p_vaddr; + en_t p_paddr; + en_t p_filesz; + en_t p_memsz; + en_t p_flags; + en_t p_align; +}; + +template class en_t, typename sz_t> +struct elf_prog final : elf_phdr +{ + std::vector bin; + + using base = elf_phdr; + + elf_prog() = default; + + elf_prog(u32 type, u32 flags, sz_t vaddr, sz_t memsz, sz_t align, std::vector&& bin) + : bin(std::move(bin)) + { + base::p_type = type; + base::p_flags = flags; + base::p_vaddr = vaddr; + base::p_memsz = memsz; + base::p_align = align; + base::p_filesz = static_cast(bin.size()); + base::p_paddr = 0; + base::p_offset = -1; + } +}; + +template class en_t, typename sz_t> +struct elf_shdr +{ + en_t sh_name; + en_t sh_type; + en_t sh_flags; + en_t sh_addr; + en_t sh_offset; + en_t sh_size; + en_t sh_link; + en_t sh_info; + en_t sh_addralign; + en_t sh_entsize; +}; + +// Default elf_loader::load() return type, specialized to change. +template +struct elf_load_result +{ + using type = void; +}; + +// ELF loader errors +enum class elf_error +{ + ok = 0, + + stream, + stream_header, + stream_phdrs, + stream_shdrs, + stream_data, + + header_magic, + header_version, + header_class, + header_machine, + header_endianness, + header_type, + header_os, +}; + +// ELF loader error information +template<> +struct bijective +{ + static constexpr std::pair map[] + { + { elf_error::ok, "" }, + + { elf_error::stream, "Invalid stream" }, + { elf_error::stream_header, "Failed to read ELF header" }, + { elf_error::stream_phdrs, "Failed to read ELF program headers" }, + { elf_error::stream_shdrs, "Failed to read ELF section headers" }, + { elf_error::stream_data, "Failed to read ELF program data" }, + + { elf_error::header_magic, "Not an ELF" }, + { elf_error::header_version, "Invalid or unsupported ELF format" }, + { elf_error::header_class, "Invalid ELF class" }, + { elf_error::header_machine, "Invalid ELF machine" }, + { elf_error::header_endianness, "Invalid ELF data (endianness)" }, + { elf_error::header_type, "Invalid ELF type" }, + { elf_error::header_os, "Invalid ELF OS ABI" }, + }; +}; + +// ELF loader with specified parameters. +// en_t: endianness (specify le_t or be_t) +// sz_t: size (specify u32 for ELF32, u64 for ELF64) +template class en_t, typename sz_t, elf_machine Machine, elf_os OS, elf_type Type> +class elf_loader +{ + elf_error m_error{}; + + elf_error error(elf_error e) + { + return m_error = e; + } + +public: + using ehdr_t = elf_ehdr; + using phdr_t = elf_phdr; + using shdr_t = elf_shdr; + using prog_t = elf_prog; + + ehdr_t header{}; + + std::vector progs; + std::vector shdrs; + +public: + elf_loader() = default; + + elf_loader(const fs::file& stream, u64 offset = 0) + { + open(stream, offset); + } + + elf_error open(const fs::file& stream, u64 offset = 0) + { + // Check stream + if (!stream) + return error(elf_error::stream); + + // Read ELF header + stream.seek(offset); + if (!stream.read(header)) + return error(elf_error::stream_header); + + // Check magic + if (header.e_magic != "\177ELF"_u32) + return error(elf_error::header_magic); + + // Check class + if (header.e_class != (std::is_same::value ? 1 : 2)) + return error(elf_error::header_class); + + // Check endianness + if (header.e_data != (std::is_same, le_t>::value ? 1 : 2)) + return error(elf_error::header_endianness); + + // Check machine + if (header.e_machine != Machine) + return error(elf_error::header_machine); + + // Check OS only if specified (hack) + if (OS != elf_os::none && header.e_os_abi != OS) + return error(elf_error::header_os); + + // Check type only if specified (hack) + if (Type != elf_type::none && header.e_type != Type) + return error(elf_error::header_type); + + // Check version and other params + if (header.e_curver != 1 || header.e_version != 1 || header.e_ehsize != sizeof(ehdr_t)) + return error(elf_error::header_version); + + if (header.e_phnum && header.e_phentsize != sizeof(phdr_t)) + return error(elf_error::header_version); + + if (header.e_shnum && header.e_shentsize != sizeof(shdr_t)) + return error(elf_error::header_version); + + // Load program headers + std::vector _phdrs(header.e_phnum); + stream.seek(offset + header.e_phoff); + if (!stream.read(_phdrs)) + return error(elf_error::stream_phdrs); + + shdrs.resize(header.e_shnum); + stream.seek(offset + header.e_shoff); + if (!stream.read(shdrs)) + return error(elf_error::stream_shdrs); + + progs.clear(); + progs.reserve(_phdrs.size()); + for (const auto& hdr : _phdrs) + { + progs.emplace_back(); + + static_cast(progs.back()) = hdr; + progs.back().bin.resize(hdr.p_filesz); + stream.seek(offset + hdr.p_offset); + if (!stream.read(progs.back().bin)) + return error(elf_error::stream_data); + } + + shdrs.shrink_to_fit(); + progs.shrink_to_fit(); + + return m_error = elf_error::ok; + } + + void save(const fs::file& stream) const + { + // Write header + ehdr_t header{}; + header.e_magic = "\177ELF"_u32; + header.e_class = std::is_same::value ? 1 : 2; + header.e_data = std::is_same, le_t>::value ? 1 : 2; + header.e_curver = 1; + header.e_os_abi = OS != elf_os::none ? OS : this->header.e_os_abi; + header.e_abi_ver = this->header.e_abi_ver; + header.e_type = Type != elf_type::none ? Type : this->header.e_type; + header.e_machine = Machine; + header.e_version = 1; + header.e_entry = this->header.e_entry; + header.e_phoff = SIZE_32(ehdr_t); + header.e_shoff = SIZE_32(ehdr_t) + SIZE_32(phdr_t) * ::size32(progs); + header.e_flags = this->header.e_flags; + header.e_ehsize = SIZE_32(ehdr_t); + header.e_phentsize = SIZE_32(phdr_t); + header.e_phnum = ::size32(progs); + header.e_shentsize = SIZE_32(shdr_t); + header.e_shnum = ::size32(shdrs); + header.e_shstrndx = this->header.e_shstrndx; + stream.write(header); + + sz_t off = header.e_shoff + SIZE_32(shdr_t) * ::size32(shdrs); + + for (phdr_t phdr : progs) + { + phdr.p_offset = std::exchange(off, off + phdr.p_filesz); + stream.write(phdr); + } + + for (shdr_t shdr : shdrs) + { + // TODO? + stream.write(shdr); + } + + // Write data + for (const auto& prog : progs) + { + stream.write(prog.bin); + } + } + + // Return error code + operator elf_error() const + { + return m_error; + } + + // Format-specific loader function (must be specialized) + typename elf_load_result::type load() const; +}; + +using ppu_exec_loader = elf_loader; +using ppu_prx_loader = elf_loader; +using spu_exec_loader = elf_loader; +using arm_exec_loader = elf_loader; + +template<> struct elf_load_result { using type = std::shared_ptr; }; diff --git a/rpcs3/Loader/ELF32.cpp b/rpcs3/Loader/ELF32.cpp deleted file mode 100644 index dc3b3db9f5..0000000000 --- a/rpcs3/Loader/ELF32.cpp +++ /dev/null @@ -1,453 +0,0 @@ -#include "stdafx.h" -#include "ELF32.h" -#include "Emu/FS/vfsStream.h" -#include "Emu/Memory/Memory.h" -#include "Emu/Cell/SPUThread.h" -#include "Emu/ARMv7/ARMv7Thread.h" -#include "Emu/ARMv7/ARMv7Decoder.h" -#include "Emu/ARMv7/PSVFuncList.h" -#include "Emu/System.h" -#include "Emu/state.h" - -extern void armv7_init_tls(); - -namespace loader -{ - namespace handlers - { - handler::error_code elf32::init(vfsStream& stream) - { - m_ehdr = {}; - m_phdrs.clear(); - m_shdrs.clear(); - - error_code res = handler::init(stream); - - if (res != ok) - { - return res; - } - - m_stream->Read(&m_ehdr, sizeof(ehdr)); - - if (!m_ehdr.check()) - { - return bad_file; - } - - if (m_ehdr.data_le.e_phnum && (m_ehdr.is_le() ? m_ehdr.data_le.e_phentsize != sizeof(phdr) : m_ehdr.data_be.e_phentsize != sizeof(phdr))) - { - return broken_file; - } - - if (m_ehdr.data_le.e_shnum && (m_ehdr.is_le() ? m_ehdr.data_le.e_shentsize != sizeof(shdr) : m_ehdr.data_be.e_shentsize != sizeof(shdr))) - { - return broken_file; - } - - LOG_WARNING(LOADER, "m_ehdr.e_type = 0x%x", m_ehdr.is_le() ? m_ehdr.data_le.e_type : m_ehdr.data_be.e_type.value()); - - if (m_ehdr.data_le.e_phnum) - { - m_phdrs.resize(m_ehdr.is_le() ? m_ehdr.data_le.e_phnum : m_ehdr.data_be.e_phnum.value()); - m_stream->Seek(handler::get_stream_offset() + (m_ehdr.is_le() ? m_ehdr.data_le.e_phoff : m_ehdr.data_be.e_phoff.value())); - size_t size = (m_ehdr.is_le() ? m_ehdr.data_le.e_phnum : m_ehdr.data_be.e_phnum.value()) * sizeof(phdr); - - if (m_stream->Read(m_phdrs.data(), size) != size) - return broken_file; - } - - if (m_ehdr.data_le.e_shnum) - { - m_shdrs.resize(m_ehdr.is_le() ? m_ehdr.data_le.e_shnum : m_ehdr.data_be.e_shnum.value()); - m_stream->Seek(handler::get_stream_offset() + (m_ehdr.is_le() ? m_ehdr.data_le.e_shoff : m_ehdr.data_be.e_shoff.value())); - size_t size = (m_ehdr.is_le() ? m_ehdr.data_le.e_shnum : m_ehdr.data_be.e_shnum.value()) * sizeof(shdr); - - if (m_stream->Read(m_shdrs.data(), size) != size) - return broken_file; - } - - return ok; - } - - handler::error_code elf32::load() - { - Elf_Machine machine; - switch (machine = (Elf_Machine)(u16)(m_ehdr.is_le() ? m_ehdr.data_le.e_machine : m_ehdr.data_be.e_machine.value())) - { - case MACHINE_MIPS: vm::psp::init(); break; - case MACHINE_ARM: vm::psv::init(); break; - case MACHINE_SPU: vm::ps3::init(); break; - - default: - return bad_version; - } - - error_code res = load_data(0); - - if (res != ok) - return res; - - switch (machine) - { - case MACHINE_MIPS: break; - case MACHINE_ARM: - { - struct psv_libc_param_t - { - u32 size; // 0x0000001c - u32 unk1; // 0x00000000 - - vm::lptr sceLibcHeapSize; - vm::lptr sceLibcHeapSizeDefault; - vm::lptr sceLibcHeapExtendedAlloc; - vm::lptr sceLibcHeapDelayedAlloc; - - u32 unk2; - u32 unk3; - - vm::lptr __sce_libcmallocreplace; - vm::lptr __sce_libcnewreplace; - }; - - struct psv_process_param_t - { - u32 size; // 0x00000030 - u32 unk1; // 'PSP2' - u32 unk2; // 0x00000005 - u32 unk3; - - vm::lcptr sceUserMainThreadName; - vm::lptr sceUserMainThreadPriority; - vm::lptr sceUserMainThreadStackSize; - vm::lptr sceUserMainThreadAttribute; - vm::lcptr sceProcessName; - vm::lptr sce_process_preload_disabled; - vm::lptr sceUserMainThreadCpuAffinityMask; - - vm::lptr __sce_libcparam; - }; - - initialize_psv_modules(); - - auto armv7_thr_stop_data = vm::ptr::make(vm::alloc(3 * 4, vm::main)); - armv7_thr_stop_data[0] = 0xf870; // HACK instruction (Thumb) - armv7_thr_stop_data[1] = SFI_HLE_RETURN; - Emu.SetCPUThreadStop(armv7_thr_stop_data.addr()); - - u32 entry = 0; // actual entry point (ELFs entry point is ignored) - u32 fnid_addr = 0; - u32 code_start = 0; - u32 code_end = 0; - u32 vnid_addr = 0; - std::unordered_map vnid_list; - - vm::ptr proc_param = vm::null; - - for (auto& shdr : m_shdrs) - { - // get secton name - //auto name = vm::cptr::make(sname_base + shdr.data_le.sh_name); - - m_stream->Seek(handler::get_stream_offset() + m_shdrs[m_ehdr.data_le.e_shstrndx].data_le.sh_offset + shdr.data_le.sh_name); - std::string name; - char c; - while (m_stream->SRead(c) && c) - { - name.push_back(c); - } - - if (!strcmp(name.c_str(), ".text")) - { - LOG_NOTICE(LOADER, ".text analysis..."); - - code_start = shdr.data_le.sh_addr; - code_end = shdr.data_le.sh_size + code_start; - } - else if (!strcmp(name.c_str(), ".sceExport.rodata")) - { - LOG_NOTICE(LOADER, ".sceExport.rodata analysis..."); - - auto enid = vm::cptr::make(shdr.data_le.sh_addr); - auto edata = vm::cptr::make(enid.addr() + shdr.data_le.sh_size / 2); - - for (u32 j = 0; j < shdr.data_le.sh_size / 8; j++) - { - switch (const u32 nid = enid[j]) - { - case 0x935cd196: // set entry point - { - entry = edata[j]; - break; - } - - case 0x6c2224ba: // __sce_moduleinfo - { - // currently nothing, but it should theoretically be the root of analysis instead of section name comparison - break; - } - - case 0x70fba1e7: // __sce_process_param - { - proc_param.set(edata[j]); - break; - } - - default: - { - LOG_ERROR(LOADER, "Unknown export 0x%08x (addr=0x%08x)", nid, edata[j]); - } - } - } - } - else if (!strcmp(name.c_str(), ".sceFNID.rodata")) - { - LOG_NOTICE(LOADER, ".sceFNID.rodata analysis..."); - - fnid_addr = shdr.data_le.sh_addr; - } - else if (!strcmp(name.c_str(), ".sceFStub.rodata")) - { - LOG_NOTICE(LOADER, ".sceFStub.rodata analysis..."); - - if (!fnid_addr) - { - LOG_ERROR(LOADER, ".sceFNID.rodata address not found, unable to process imports"); - continue; - } - - auto fnid = vm::cptr::make(fnid_addr); - auto fstub = vm::cptr::make(shdr.data_le.sh_addr); - - for (u32 j = 0; j < shdr.data_le.sh_size / 4; j++) - { - const u32 nid = fnid[j]; - const u32 addr = fstub[j]; - - u32 index; - - if (auto func = get_psv_func_by_nid(nid, &index)) - { - if (func->module) - { - LOG_NOTICE(LOADER, "Imported function '%s' in module '%s' (nid=0x%08x, addr=0x%x)", func->name, func->module->name, nid, addr); - } - else - { - LOG_NOTICE(LOADER, "Imported function '%s' (nid=0x%08x, addr=0x%x)", func->name, nid, addr); - } - } - else - { - LOG_ERROR(LOADER, "Unknown function 0x%08x (addr=0x%x)", nid, addr); - - // TODO: set correct name if possible - index = add_psv_func(psv_func(nid, 0, nullptr, "UNKNOWN", nullptr)); - } - - vm::psv::write32(addr, 0xe0700090 | (index & 0xfff0) << 4 | (index & 0xf)); // HACK instruction (ARM) - - code_end = std::min(addr, code_end); - } - } - else if (!strcmp(name.c_str(), ".sceVNID.rodata")) - { - LOG_NOTICE(LOADER, ".sceVNID.rodata analysis..."); - - vnid_addr = shdr.data_le.sh_addr; - } - else if (!strcmp(name.c_str(), ".sceVStub.rodata")) - { - LOG_NOTICE(LOADER, ".sceVStub.rodata analysis..."); - - if (!vnid_addr) - { - if (shdr.data_le.sh_size) - { - LOG_ERROR(LOADER, ".sceVNID.rodata address not found, unable to process imports"); - } - continue; - } - - auto vnid = vm::cptr::make(vnid_addr); - auto vstub = vm::cptr::make(shdr.data_le.sh_addr); - - for (u32 j = 0; j < shdr.data_le.sh_size / 4; j++) - { - const u32 nid = vnid[j]; - const u32 addr = vstub[j]; - - LOG_ERROR(LOADER, "Unknown object 0x%08x (ref_addr=0x%x)", nid, addr); - - // TODO: find imported object (vtable, typeinfo or something), assign it to vnid_list[addr] - } - } - else if (!strcmp(name.c_str(), ".tbss")) - { - LOG_NOTICE(LOADER, ".tbss analysis..."); - const u32 img_addr = shdr.data_le.sh_addr; // start address of TLS initialization image - const u32 img_size = (&shdr)[1].data_le.sh_addr - img_addr; // calculate its size as the difference between sections - const u32 tls_size = shdr.data_le.sh_size; // full size of TLS - - LOG_WARNING(LOADER, "TLS: img_addr=0x%08x, img_size=0x%x, tls_size=0x%x", img_addr, img_size, tls_size); - Emu.SetTLSData(img_addr, img_size, tls_size); - } - else if (!strcmp(name.c_str(), ".sceRefs.rodata")) - { - LOG_NOTICE(LOADER, ".sceRefs.rodata analysis..."); - - u32 data = 0; - - for (auto code = vm::cptr::make(shdr.data_le.sh_addr); code.addr() < shdr.data_le.sh_addr + shdr.data_le.sh_size; code++) - { - switch (*code) - { - case 0x000000ff: // save address for future use - { - data = *++code; - break; - } - case 0x0000002f: // movw r*,# instruction is replaced - { - if (!data) // probably, imported object - { - auto found = vnid_list.find(code.addr()); - if (found != vnid_list.end()) - { - data = found->second; - } - } - - if (!data) - { - LOG_ERROR(LOADER, ".sceRefs: movw writing failed (ref_addr=0x%x, addr=0x%x)", code, code[1]); - } - else - { - LOG_NOTICE(LOADER, ".sceRefs: movw written at 0x%x (ref_addr=0x%x, data=0x%x)", code[1], code, data); - } - - const u32 addr = *++code; - vm::psv::write16(addr + 0, vm::psv::read16(addr + 0) | (data & 0x800) >> 1 | (data & 0xf000) >> 12); - vm::psv::write16(addr + 2, vm::psv::read16(addr + 2) | (data & 0x700) << 4 | (data & 0xff)); - break; - } - case 0x00000030: // movt r*,# instruction is replaced - { - if (!data) - { - LOG_ERROR(LOADER, ".sceRefs: movt writing failed (ref_addr=0x%x, addr=0x%x)", code, code[1]); - } - else - { - LOG_NOTICE(LOADER, ".sceRefs: movt written at 0x%x (ref_addr=0x%x, data=0x%x)", code[1], code, data); - } - - const u32 addr = *++code; - vm::psv::write16(addr + 0, vm::psv::read16(addr + 0) | (data & 0x8000000) >> 17 | (data & 0xf0000000) >> 28); - vm::psv::write16(addr + 2, vm::psv::read16(addr + 2) | (data & 0x7000000) >> 12 | (data & 0xff0000) >> 16); - break; - } - case 0x00000000: - { - data = 0; - - LOG_TRACE(LOADER, ".sceRefs: zero code found"); - break; - } - default: - { - LOG_ERROR(LOADER, "Unknown code in .sceRefs section (0x%08x)", *code); - } - } - } - } - } - - LOG_NOTICE(LOADER, "__sce_process_param(addr=0x%x) analysis...", proc_param); - - if (proc_param->size != 0x30 || proc_param->unk1 != *(u32*)"PSP2" || proc_param->unk2 != 5) - { - LOG_ERROR(LOADER, "__sce_process_param: unexpected data found (size=0x%x, 0x%x, 0x%x, 0x%x)", proc_param->size, proc_param->unk1, proc_param->unk2, proc_param->unk3); - } - - LOG_NOTICE(LOADER, "*** &sceUserMainThreadName = 0x%x", proc_param->sceUserMainThreadName); - LOG_NOTICE(LOADER, "*** &sceUserMainThreadPriority = 0x%x", proc_param->sceUserMainThreadPriority); - LOG_NOTICE(LOADER, "*** &sceUserMainThreadStackSize = 0x%x", proc_param->sceUserMainThreadStackSize); - LOG_NOTICE(LOADER, "*** &sceUserMainThreadAttribute = 0x%x", proc_param->sceUserMainThreadAttribute); - LOG_NOTICE(LOADER, "*** &sceProcessName = 0x%x", proc_param->sceProcessName); - LOG_NOTICE(LOADER, "*** &sce_process_preload_disabled = 0x%x", proc_param->sce_process_preload_disabled); - LOG_NOTICE(LOADER, "*** &sceUserMainThreadCpuAffinityMask = 0x%x", proc_param->sceUserMainThreadCpuAffinityMask); - - auto libc_param = proc_param->__sce_libcparam; - - LOG_NOTICE(LOADER, "__sce_libcparam(addr=0x%x) analysis...", libc_param); - - if (libc_param->size != 0x1c || libc_param->unk1) - { - LOG_ERROR(LOADER, "__sce_libcparam: unexpected data found (size=0x%x, 0x%x, 0x%x)", libc_param->size, libc_param->unk1, libc_param->unk2); - } - - LOG_NOTICE(LOADER, "*** &sceLibcHeapSize = 0x%x", libc_param->sceLibcHeapSize); - LOG_NOTICE(LOADER, "*** &sceLibcHeapSizeDefault = 0x%x", libc_param->sceLibcHeapSizeDefault); - LOG_NOTICE(LOADER, "*** &sceLibcHeapExtendedAlloc = 0x%x", libc_param->sceLibcHeapExtendedAlloc); - LOG_NOTICE(LOADER, "*** &sceLibcHeapDelayedAlloc = 0x%x", libc_param->sceLibcHeapDelayedAlloc); - - armv7_init_tls(); - armv7_decoder_initialize(code_start, code_end); - - const std::string& thread_name = proc_param->sceUserMainThreadName ? proc_param->sceUserMainThreadName.get_ptr() : "main_thread"; - const u32 stack_size = proc_param->sceUserMainThreadStackSize ? proc_param->sceUserMainThreadStackSize->value() : 256 * 1024; - const u32 priority = proc_param->sceUserMainThreadPriority ? proc_param->sceUserMainThreadPriority->value() : 160; - - armv7_thread(entry, thread_name, stack_size, priority).args({ Emu.GetPath(), "-emu" }).run(); - break; - } - case MACHINE_SPU: spu_thread(m_ehdr.is_le() ? m_ehdr.data_le.e_entry : m_ehdr.data_be.e_entry.value(), "main_thread").args({ Emu.GetPath()/*, "-emu"*/ }).run(); break; - } - - return ok; - } - - handler::error_code elf32::load_data(u32 offset, bool skip_writeable) - { - Elf_Machine machine = (Elf_Machine)(u16)(m_ehdr.is_le() ? m_ehdr.data_le.e_machine : m_ehdr.data_be.e_machine.value()); - - for (auto &phdr : m_phdrs) - { - u32 memsz = m_ehdr.is_le() ? phdr.data_le.p_memsz : phdr.data_be.p_memsz.value(); - u32 filesz = m_ehdr.is_le() ? phdr.data_le.p_filesz : phdr.data_be.p_filesz.value(); - u32 vaddr = offset + (m_ehdr.is_le() ? phdr.data_le.p_vaddr : phdr.data_be.p_vaddr.value()); - u32 offset = m_ehdr.is_le() ? phdr.data_le.p_offset : phdr.data_be.p_offset.value(); - - switch (m_ehdr.is_le() ? phdr.data_le.p_type : phdr.data_be.p_type.value()) - { - case 0x00000001: //LOAD - if (phdr.data_le.p_memsz) - { - if (machine == MACHINE_ARM && !vm::falloc(vaddr, memsz, vm::main)) - { - LOG_ERROR(LOADER, "%s(): AllocFixed(0x%llx, 0x%x) failed", __FUNCTION__, vaddr, memsz); - - return loading_error; - } - - if (skip_writeable == true && (phdr.data_be.p_flags & 2/*PF_W*/) != 0) - { - continue; - } - - if (filesz) - { - m_stream->Seek(handler::get_stream_offset() + offset); - m_stream->Read(vm::base(vaddr), filesz); - } - } - break; - } - } - - return ok; - } - } -} diff --git a/rpcs3/Loader/ELF32.h b/rpcs3/Loader/ELF32.h deleted file mode 100644 index 76cc910ec2..0000000000 --- a/rpcs3/Loader/ELF32.h +++ /dev/null @@ -1,139 +0,0 @@ -#pragma once -#include "Loader.h" - -struct vfsStream; - -namespace loader -{ - namespace handlers - { - class elf32 : public handler - { - public: - struct ehdr - { - u32 e_magic; - u8 e_class; - u8 e_data; - u8 e_curver; - u8 e_os_abi; - - union - { - struct - { - u64 e_abi_ver; - u16 e_type; - u16 e_machine; - u32 e_version; - u32 e_entry; - u32 e_phoff; - u32 e_shoff; - u32 e_flags; - u16 e_ehsize; - u16 e_phentsize; - u16 e_phnum; - u16 e_shentsize; - u16 e_shnum; - u16 e_shstrndx; - } data_le; - - struct - { - be_t e_abi_ver; - be_t e_type; - be_t e_machine; - be_t e_version; - be_t e_entry; - be_t e_phoff; - be_t e_shoff; - be_t e_flags; - be_t e_ehsize; - be_t e_phentsize; - be_t e_phnum; - be_t e_shentsize; - be_t e_shnum; - be_t e_shstrndx; - } data_be; - }; - - bool is_le() const { return e_data == 1; } - bool check() const { return e_magic == 0x464C457F; } - }; - - struct shdr - { - union - { - struct - { - u32 sh_name; - u32 sh_type; - u32 sh_flags; - u32 sh_addr; - u32 sh_offset; - u32 sh_size; - u32 sh_link; - u32 sh_info; - u32 sh_addralign; - u32 sh_entsize; - } data_le; - - struct - { - be_t sh_name; - be_t sh_type; - be_t sh_flags; - be_t sh_addr; - be_t sh_offset; - be_t sh_size; - be_t sh_link; - be_t sh_info; - be_t sh_addralign; - be_t sh_entsize; - } data_be; - }; - }; - - struct phdr - { - union - { - struct - { - u32 p_type; - u32 p_offset; - u32 p_vaddr; - u32 p_paddr; - u32 p_filesz; - u32 p_memsz; - u32 p_flags; - u32 p_align; - } data_le; - - struct - { - be_t p_type; - be_t p_offset; - be_t p_vaddr; - be_t p_paddr; - be_t p_filesz; - be_t p_memsz; - be_t p_flags; - be_t p_align; - } data_be; - }; - }; - - ehdr m_ehdr; - std::vector m_phdrs; - std::vector m_shdrs; - - error_code init(vfsStream& stream) override; - error_code load() override; - error_code load_data(u32 offset, bool skip_writeable = false); - - virtual ~elf32() = default; - }; - } -} diff --git a/rpcs3/Loader/ELF64.cpp b/rpcs3/Loader/ELF64.cpp deleted file mode 100644 index 288aeb61a5..0000000000 --- a/rpcs3/Loader/ELF64.cpp +++ /dev/null @@ -1,737 +0,0 @@ -#include "stdafx.h" -#include "Emu/FS/vfsStream.h" -#include "Emu/FS/vfsFile.h" -#include "Emu/FS/vfsDir.h" -#include "Emu/Memory/Memory.h" -#include "Emu/IdManager.h" -#include "Emu/System.h" -#include "Emu/state.h" -#include "Emu/SysCalls/SysCalls.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/SysCalls/ModuleManager.h" -#include "Emu/SysCalls/lv2/sys_prx.h" -#include "Emu/Cell/PPUInstrTable.h" -#include "ELF64.h" - -using namespace PPU_instr; - -namespace loader -{ - namespace handlers - { - handler::error_code elf64::init(vfsStream& stream) - { - m_ehdr = {}; - m_sprx_module_info = {}; - m_sprx_function_info = {}; - - m_phdrs.clear(); - m_shdrs.clear(); - - m_sprx_segments_info.clear(); - m_sprx_import_info.clear(); - m_sprx_export_info.clear(); - - error_code res = handler::init(stream); - - if (res != ok) - { - return res; - } - - m_stream->Read(&m_ehdr, sizeof(ehdr)); - - if (!m_ehdr.check()) - { - return bad_file; - } - - if (m_ehdr.e_phnum && m_ehdr.e_phentsize != sizeof(phdr)) - { - return broken_file; - } - - if (m_ehdr.e_shnum && m_ehdr.e_shentsize != sizeof(shdr)) - { - return broken_file; - } - - if (m_ehdr.e_machine != MACHINE_PPC64 && m_ehdr.e_machine != MACHINE_SPU) - { - LOG_ERROR(LOADER, "Unknown elf64 machine type: 0x%x", m_ehdr.e_machine); - return bad_version; - } - - if (m_ehdr.e_phnum) - { - m_phdrs.resize(m_ehdr.e_phnum); - m_stream->Seek(handler::get_stream_offset() + m_ehdr.e_phoff); - if (m_stream->Read(m_phdrs.data(), m_ehdr.e_phnum * sizeof(phdr)) != m_ehdr.e_phnum * sizeof(phdr)) - return broken_file; - } - - if (m_ehdr.e_shnum) - { - m_shdrs.resize(m_ehdr.e_shnum); - m_stream->Seek(handler::get_stream_offset() + m_ehdr.e_shoff); - if (m_stream->Read(m_shdrs.data(), m_ehdr.e_shnum * sizeof(shdr)) != m_ehdr.e_shnum * sizeof(shdr)) - return broken_file; - } - - if (is_sprx()) - { - m_stream->Seek(handler::get_stream_offset() + m_phdrs[0].p_paddr.addr()); - m_stream->Read(&m_sprx_module_info, sizeof(sprx_module_info)); - - //m_stream->Seek(handler::get_stream_offset() + m_phdrs[1].p_vaddr.addr()); - //m_stream->Read(&m_sprx_function_info, sizeof(sprx_function_info)); - } - - return ok; - } - - handler::error_code elf64::load_sprx(sprx_info& info) - { - for (auto &phdr : m_phdrs) - { - switch ((u32)phdr.p_type) - { - case 0x1: //load - { - if (phdr.p_memsz) - { - sprx_segment_info segment; - segment.size = phdr.p_memsz; - segment.size_file = phdr.p_filesz; - - segment.begin.set(vm::alloc(segment.size, vm::main)); - - if (!segment.begin) - { - LOG_ERROR(LOADER, "%s() sprx: vm::alloc(0x%x) failed", __FUNCTION__, segment.size); - - return loading_error; - } - - segment.initial_addr = phdr.p_vaddr; - LOG_WARNING(LOADER, "segment addr=0x%x, initial addr = 0x%x", segment.begin.addr(), segment.initial_addr.addr()); - - if (phdr.p_filesz) - { - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset); - m_stream->Read(segment.begin.get_ptr(), phdr.p_filesz); - } - - if (phdr.p_paddr) - { - sys_prx_module_info_t module_info; - m_stream->Seek(handler::get_stream_offset() + phdr.p_paddr.addr()); - m_stream->Read(&module_info, sizeof(module_info)); - - info.name = std::string(module_info.name, 28); - info.rtoc = module_info.toc + segment.begin.addr(); - - LOG_WARNING(LOADER, "%s (rtoc=0x%x):", info.name, info.rtoc); - - sys_prx_library_info_t lib; - for (u32 e = module_info.exports_start.addr(); - e < module_info.exports_end.addr(); - e += lib.size ? lib.size : sizeof(sys_prx_library_info_t)) - { - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + e); - m_stream->Read(&lib, sizeof(lib)); - - std::string modulename; - if (lib.name_addr) - { - char name[27]; - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.name_addr); - m_stream->Read(name, sizeof(name)); - modulename = name; - LOG_WARNING(LOADER, "**** Exported: %s", name); - } - - auto &module = info.modules[modulename]; - - LOG_WARNING(LOADER, "**** 0x%x - 0x%x - 0x%x", (u32)lib.unk4, (u32)lib.unk5, (u32)lib.unk6); - - for (u16 i = 0, end = lib.num_func; i < end; ++i) - { - be_t fnid, fstub; - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.fnid_addr + i * sizeof(fnid)); - m_stream->Read(&fnid, sizeof(fnid)); - - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.fstub_addr + i * sizeof(fstub)); - m_stream->Read(&fstub, sizeof(fstub)); - - module.exports[fnid] = fstub; - - //LOG_NOTICE(LOADER, "Exported function '%s' in '%s' module (LLE)", get_ps3_function_name(fnid), module_name); - LOG_WARNING(LOADER, "**** %s: [%s] -> 0x%x", modulename, get_ps3_function_name(fnid), (u32)fstub); - } - } - - for (u32 i = module_info.imports_start; - i < module_info.imports_end; - i += lib.size ? lib.size : sizeof(sys_prx_library_info_t)) - { - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + i); - m_stream->Read(&lib, sizeof(lib)); - - std::string modulename; - if (lib.name_addr) - { - char name[27]; - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.name_addr); - m_stream->Read(name, sizeof(name)); - modulename = name; - LOG_WARNING(LOADER, "**** Imported: %s", name); - } - - auto &module = info.modules[modulename]; - - LOG_WARNING(LOADER, "**** 0x%x - 0x%x - 0x%x", (u32)lib.unk4, (u32)lib.unk5, (u32)lib.unk6); - - for (u16 i = 0, end = lib.num_func; i < end; ++i) - { - be_t fnid, fstub; - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.fnid_addr + i * sizeof(fnid)); - m_stream->Read(&fnid, sizeof(fnid)); - - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.fstub_addr + i * sizeof(fstub)); - m_stream->Read(&fstub, sizeof(fstub)); - - module.imports[fnid] = fstub; - - LOG_WARNING(LOADER, "**** %s: [%s] -> 0x%x", modulename, get_ps3_function_name(fnid), (u32)fstub); - } - } - } - - info.segments.push_back(segment); - } - - break; - } - - case 0x700000a4: //relocation - { - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset); - - for (uint i = 0; i < phdr.p_filesz; i += sizeof(sys_prx_relocation_info_t)) - { - sys_prx_relocation_info_t rel; - m_stream->Read(&rel, sizeof(rel)); - - u32 ADDR = info.segments[rel.index_addr].begin.addr() + rel.offset; - - switch ((u32)rel.type) - { - case 1: - LOG_NOTICE(LOADER, "**** RELOCATION(1): 0x%x <- 0x%x", ADDR, (u32)(info.segments[rel.index_value].begin.addr() + rel.ptr.addr())); - *vm::ptr::make(ADDR) = info.segments[rel.index_value].begin.addr() + rel.ptr.addr(); - break; - - case 4: - LOG_NOTICE(LOADER, "**** RELOCATION(4): 0x%x <- 0x%x", ADDR, (u16)(rel.ptr.addr())); - *vm::ptr::make(ADDR) = (u16)(u64)rel.ptr.addr(); - break; - - case 5: - LOG_NOTICE(LOADER, "**** RELOCATION(5): 0x%x <- 0x%x", ADDR, (u16)(info.segments[rel.index_value].begin.addr() >> 16)); - *vm::ptr::make(ADDR) = info.segments[rel.index_value].begin.addr() >> 16; - break; - - case 6: - LOG_WARNING(LOADER, "**** RELOCATION(6): 0x%x <- 0x%x", ADDR, (u16)(info.segments[1].begin.addr() >> 16)); - *vm::ptr::make(ADDR) = info.segments[1].begin.addr() >> 16; - break; - - default: - LOG_ERROR(LOADER, "unknown prx relocation type (0x%x)", (u32)rel.type); - return bad_relocation_type; - } - } - - break; - } - } - } - - for (auto &m : info.modules) - { - for (auto &e : m.second.exports) - { - u32 stub = e.second; - - for (auto &s : info.segments) - { - if (stub >= s.initial_addr.addr() && stub < s.initial_addr.addr() + s.size_file) - { - stub += s.begin.addr() - s.initial_addr.addr(); - break; - } - } - - assert(e.second != stub); - e.second = stub; - } - - for (auto &i : m.second.imports) - { - u32 stub = i.second; - - for (auto &s : info.segments) - { - if (stub >= s.initial_addr.addr() && stub < s.initial_addr.addr() + s.size_file) - { - stub += s.begin.addr() - s.initial_addr.addr(); - break; - } - } - - assert(i.second != stub); - i.second = stub; - } - } - - return ok; - } - - handler::error_code elf64::load() - { - if (is_sprx()) - { - sprx_info info; - return load_sprx(info); - } - - //store elf to memory - vm::ps3::init(); - Emu.GetModuleManager().Init(); - - error_code res = alloc_memory(0); - if (res != ok) - { - return res; - } - - std::vector start_funcs; - std::vector stop_funcs; - std::vector exit_funcs; - - //load modules - vfsDir lle_dir("/dev_flash/sys/external"); - - for (const auto module : lle_dir) - { - if (module->flags & DirEntry_TypeDir) - { - continue; - } - - if (rpcs3::state.config.core.load_liblv2.value()) - { - if (module->name != "liblv2.sprx") - { - continue; - } - } - - elf64 sprx_handler; - - vfsFile fsprx(lle_dir.GetPath() + "/" + module->name); - - if (fsprx.IsOpened()) - { - sprx_handler.init(fsprx); - - if (sprx_handler.is_sprx()) - { - if (!rpcs3::state.config.core.load_liblv2.value()) - { - if (rpcs3::config.lle.get_entry_value(sprx_handler.sprx_get_module_name(), false) == false) - { - continue; - } - } - - LOG_WARNING(LOADER, "Loading LLE library '%s'", sprx_handler.sprx_get_module_name().c_str()); - - sprx_info info; - sprx_handler.load_sprx(info); - - for (auto &m : info.modules) - { - if (m.first == "") - { - for (auto &e : m.second.exports) - { - auto code = vm::cptr::make(vm::check_addr(e.second, 8) ? vm::read32(e.second).value() : 0); - - bool is_empty = !code || (code[0] == 0x38600000 && code[1] == BLR()); - - if (!code) - { - LOG_ERROR(LOADER, "bad OPD of special function 0x%08x in '%s' library (0x%x)", e.first, info.name.c_str(), code); - } - - switch (e.first) - { - case 0xbc9a0086: - { - if (!is_empty) - { - LOG_ERROR(LOADER, "start func found in '%s' library (0x%x)", info.name.c_str(), code); - start_funcs.push_back(e.second); - } - break; - } - - case 0xab779874: - { - if (!is_empty) - { - LOG_ERROR(LOADER, "stop func found in '%s' library (0x%x)", info.name.c_str(), code); - stop_funcs.push_back(e.second); - } - break; - } - - case 0x3ab9a95e: - { - if (!is_empty) - { - LOG_ERROR(LOADER, "exit func found in '%s' library (0x%x)", info.name.c_str(), code); - exit_funcs.push_back(e.second); - } - break; - } - - default: LOG_ERROR(LOADER, "unknown special func 0x%08x in '%s' library (0x%x)", e.first, info.name.c_str(), code); break; - } - } - - continue; - } - - Module<>* module = Emu.GetModuleManager().GetModuleByName(m.first.c_str()); - - if (!module) - { - LOG_ERROR(LOADER, "Unknown module '%s' in '%s' library", m.first.c_str(), info.name.c_str()); - } - - for (auto& f : m.second.exports) - { - const u32 nid = f.first; - const u32 addr = f.second; - - u32 index; - - auto func = get_ppu_func_by_nid(nid, &index); - - if (!func) - { - index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr, nullptr, vm::ptr::make(addr))); - } - else - { - func->lle_func.set(addr); - - if (func->flags & MFF_FORCED_HLE) - { - u32 i_addr = 0; - - if (!vm::check_addr(addr, 8) || !vm::check_addr(i_addr = vm::read32(addr), 4)) - { - LOG_ERROR(LOADER, "Failed to inject code for exported function '%s' (opd=0x%x, 0x%x)", get_ps3_function_name(nid), addr, i_addr); - } - else - { - vm::write32(i_addr, HACK(index | EIF_PERFORM_BLR)); - } - } - } - } - - for (auto& f : m.second.imports) - { - const u32 nid = f.first; - const u32 addr = f.second; - - u32 index; - - auto func = get_ppu_func_by_nid(nid, &index); - - if (!func) - { - LOG_ERROR(LOADER, "Unknown function '%s' (0x%x)", get_ps3_function_name(nid), addr); - - index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr, nullptr)); - } - else - { - LOG_NOTICE(LOADER, "Imported function '%s' (0x%x)", get_ps3_function_name(nid), addr); - } - - if (!patch_ppu_import(addr, index)) - { - LOG_ERROR(LOADER, "Failed to inject code for function '%s' (0x%x)", get_ps3_function_name(nid), addr); - } - } - } - } - } - } - - res = load_data(0); - if (res != ok) - return res; - - //initialize process - auto rsx_callback_data = vm::ptr::make(vm::alloc(4 * 4, vm::main)); - *rsx_callback_data++ = (rsx_callback_data + 1).addr(); - Emu.SetRSXCallback(rsx_callback_data.addr()); - - rsx_callback_data[0] = ADDI(r11, 0, 0x3ff); - rsx_callback_data[1] = SC(0); - rsx_callback_data[2] = BLR(); - - auto ppu_thr_stop_data = vm::ptr::make(vm::alloc(2 * 4, vm::main)); - ppu_thr_stop_data[0] = SC(3); - ppu_thr_stop_data[1] = BLR(); - Emu.SetCPUThreadStop(ppu_thr_stop_data.addr()); - - Emu.GetModuleManager().Alloc(); - - static const int branch_size = 8 * 4; - - auto make_branch = [](vm::ptr& ptr, u32 addr) - { - u32 stub = vm::read32(addr); - u32 rtoc = vm::read32(addr + 4); - - *ptr++ = LI_(r0, 0); - *ptr++ = ORI(r0, r0, stub & 0xffff); - *ptr++ = ORIS(r0, r0, stub >> 16); - *ptr++ = LI_(r2, 0); - *ptr++ = ORI(r2, r2, rtoc & 0xffff); - *ptr++ = ORIS(r2, r2, rtoc >> 16); - *ptr++ = MTCTR(r0); - *ptr++ = BCTRL(); - }; - - auto entry = vm::ptr::make(vm::alloc(56 + branch_size * (start_funcs.size() + 1), vm::main)); - - const auto OPD = entry; - - // make initial OPD - *entry++ = OPD.addr() + 8; - *entry++ = 0xdeadbeef; - - // save initialization args - *entry++ = MR(r14, r3); - *entry++ = MR(r15, r4); - *entry++ = MR(r16, r5); - *entry++ = MR(r17, r6); - *entry++ = MR(r18, r11); - *entry++ = MR(r19, r12); - - for (auto &f : start_funcs) - { - make_branch(entry, f); - } - - // restore initialization args - *entry++ = MR(r3, r14); - *entry++ = MR(r4, r15); - *entry++ = MR(r5, r16); - *entry++ = MR(r6, r17); - *entry++ = MR(r11, r18); - *entry++ = MR(r12, r19); - - // branch to initialization - make_branch(entry, m_ehdr.e_entry); - - const auto decoder_cache = fxm::make(); - - for (u32 page = 0; page < 0x20000000; page += 4096) - { - // TODO: scan only executable areas - if (vm::check_addr(page, 4096)) - { - decoder_cache->initialize(page, 4096); - } - } - - ppu_thread main_thread(OPD.addr(), "main_thread"); - - main_thread.args({ Emu.GetPath()/*, "-emu"*/ }).run(); - main_thread.gpr(11, OPD.addr()).gpr(12, Emu.GetMallocPageSize()); - - return ok; - } - - handler::error_code elf64::alloc_memory(u64 offset) - { - for (auto &phdr : m_phdrs) - { - switch (phdr.p_type.value()) - { - case 0x00000001: //LOAD - { - if (phdr.p_memsz) - { - if (!vm::falloc(phdr.p_vaddr.addr(), phdr.p_memsz, vm::main)) - { - LOG_ERROR(LOADER, "%s(): AllocFixed(0x%llx, 0x%llx) failed", __FUNCTION__, phdr.p_vaddr.addr(), phdr.p_memsz); - - return loading_error; - } - } - break; - } - } - } - - return ok; - } - - handler::error_code elf64::load_data(u64 offset) - { - for (auto &phdr : m_phdrs) - { - switch (phdr.p_type.value()) - { - case 0x00000001: //LOAD - { - if (phdr.p_memsz) - { - if (phdr.p_filesz) - { - m_stream->Seek(handler::get_stream_offset() + phdr.p_offset); - m_stream->Read(phdr.p_vaddr.get_ptr(), phdr.p_filesz); - - if (rpcs3::state.config.core.hook_st_func.value()) - { - hook_ppu_funcs(vm::static_ptr_cast(phdr.p_vaddr), phdr.p_filesz / 4); - } - } - } - break; - } - - case 0x00000007: //TLS - { - Emu.SetTLSData(phdr.p_vaddr.addr(), phdr.p_filesz, phdr.p_memsz); - break; - } - - case 0x60000001: //LOOS+1 - { - if (phdr.p_filesz) - { - struct process_param_t - { - be_t size; - be_t magic; - be_t version; - be_t sdk_version; - be_t primary_prio; - be_t primary_stacksize; - be_t malloc_pagesize; - be_t ppc_seg; - //be_t crash_dump_param_addr; - }; - - const auto& info = *(process_param_t*)phdr.p_vaddr.get_ptr(); - - if (info.size < sizeof(process_param_t)) - { - LOG_WARNING(LOADER, "Bad process_param size! [0x%x : 0x%x]", info.size, SIZE_32(process_param_t)); - } - if (info.magic != 0x13bcc5f6) - { - LOG_ERROR(LOADER, "Bad process_param magic! [0x%x]", info.magic); - } - else - { - LOG_NOTICE(LOADER, "*** sdk version: 0x%x", info.sdk_version); - LOG_NOTICE(LOADER, "*** primary prio: %d", info.primary_prio); - LOG_NOTICE(LOADER, "*** primary stacksize: 0x%x", info.primary_stacksize); - LOG_NOTICE(LOADER, "*** malloc pagesize: 0x%x", info.malloc_pagesize); - LOG_NOTICE(LOADER, "*** ppc seg: 0x%x", info.ppc_seg); - //LOG_NOTICE(LOADER, "*** crash dump param addr: 0x%x", info.crash_dump_param_addr); - - Emu.SetParams(info.sdk_version, info.malloc_pagesize, std::max(info.primary_stacksize, 0x4000), info.primary_prio); - } - } - break; - } - - case 0x60000002: //LOOS+2 - { - if (phdr.p_filesz) - { - const sys_proc_prx_param& proc_prx_param = *(sys_proc_prx_param*)phdr.p_vaddr.get_ptr(); - - if (proc_prx_param.magic != 0x1b434cec) - { - LOG_ERROR(LOADER, "Bad magic! (0x%x)", proc_prx_param.magic); - break; - } - - for (auto stub = proc_prx_param.libstubstart; stub < proc_prx_param.libstubend; ++stub) - { - const std::string module_name = stub->s_modulename.get_ptr(); - - Module<>* module = Emu.GetModuleManager().GetModuleByName(module_name.c_str()); - - if (!module) - { - LOG_ERROR(LOADER, "Unknown module '%s'", module_name.c_str()); - } - - for (u32 i = 0; i < stub->s_imports; ++i) - { - const u32 nid = stub->s_nid[i]; - const u32 addr = stub->s_text[i]; - - u32 index; - - auto func = get_ppu_func_by_nid(nid, &index); - - if (!func) - { - LOG_ERROR(LOADER, "Unknown function '%s' in '%s' module (0x%x)", get_ps3_function_name(nid), module_name, addr); - - index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr, nullptr)); - } - else - { - const bool is_lle = func->lle_func && !(func->flags & MFF_FORCED_HLE); - - LOG_NOTICE(LOADER, "Imported %sfunction '%s' in '%s' module (0x%x)", is_lle ? "LLE " : "", get_ps3_function_name(nid), module_name, addr); - } - - if (!patch_ppu_import(addr, index)) - { - LOG_ERROR(LOADER, "Failed to inject code at address 0x%x", addr); - } - } - } - } - break; - } - default: - { - LOG_ERROR(LOADER, "Unknown phdr type (0x%08x)", phdr.p_type); - } - } - } - - return ok; - } - } -} diff --git a/rpcs3/Loader/ELF64.h b/rpcs3/Loader/ELF64.h deleted file mode 100644 index bb0120ecd5..0000000000 --- a/rpcs3/Loader/ELF64.h +++ /dev/null @@ -1,164 +0,0 @@ -#pragma once -#include "Loader.h" - -struct vfsStream; - -namespace loader -{ - namespace handlers - { - class elf64 : public handler - { - public: - struct ehdr - { - be_t e_magic; - u8 e_class; - u8 e_data; - u8 e_curver; - u8 e_os_abi; - be_t e_abi_ver; - be_t e_type; - be_t e_machine; - be_t e_version; - be_t e_entry; - be_t e_phoff; - be_t e_shoff; - be_t e_flags; - be_t e_ehsize; - be_t e_phentsize; - be_t e_phnum; - be_t e_shentsize; - be_t e_shnum; - be_t e_shstrndx; - - bool check() const { return e_magic == 0x7F454C46; } - } m_ehdr; - - struct phdr - { - be_t p_type; - be_t p_flags; - be_t p_offset; - _ptr_base> p_vaddr; - _ptr_base> p_paddr; - be_t p_filesz; - be_t p_memsz; - be_t p_align; - }; - - struct shdr - { - be_t sh_name; - be_t sh_type; - be_t sh_flags; - _ptr_base> sh_addr; - be_t sh_offset; - be_t sh_size; - be_t sh_link; - be_t sh_info; - be_t sh_addralign; - be_t sh_entsize; - }; - - struct sprx_module_info - { - be_t attr; - u8 version[2]; - char name[28]; - be_t toc_addr; - be_t export_start; - be_t export_end; - be_t import_start; - be_t import_end; - } m_sprx_module_info; - - struct sprx_export_info - { - u8 size; - u8 padding; - be_t version; - be_t attr; - be_t func_count; - be_t vars_count; - be_t tls_vars_count; - be_t hash_info; - be_t tls_hash_info; - u8 reserved[2]; - be_t lib_name_offset; - be_t nid_offset; - be_t stub_offset; - }; - - struct sprx_import_info - { - u8 size; - u8 unused; - be_t version; - be_t attr; - be_t func_count; - be_t vars_count; - be_t tls_vars_count; - u8 reserved[4]; - be_t lib_name_offset; - be_t nid_offset; - be_t stub_offset; - //... - }; - - struct sprx_function_info - { - be_t name_table_offset; - be_t entry_table_offset; - be_t padding; - } m_sprx_function_info; - - struct sprx_lib_info - { - std::string name; - }; - - struct sprx_segment_info - { - _ptr_base begin; - u32 size; - u32 size_file; - _ptr_base initial_addr; - std::vector modules; - }; - - struct sprx_info - { - std::string name; - u32 rtoc; - - struct module_info - { - std::unordered_map exports; - std::unordered_map imports; - }; - - std::unordered_map modules; - std::vector segments; - }; - - std::vector m_phdrs; - std::vector m_shdrs; - - std::vector m_sprx_segments_info; - std::vector m_sprx_import_info; - std::vector m_sprx_export_info; - - public: - virtual ~elf64() = default; - - error_code init(vfsStream& stream) override; - error_code load() override; - error_code alloc_memory(u64 offset); - error_code load_data(u64 offset); - error_code load_sprx(sprx_info& info); - bool is_sprx() const { return m_ehdr.e_type == 0xffa4; } - std::string sprx_get_module_name() const { return m_sprx_module_info.name; } - }; - } -} diff --git a/rpcs3/Loader/Loader.cpp b/rpcs3/Loader/Loader.cpp deleted file mode 100644 index dcc0e2d5f7..0000000000 --- a/rpcs3/Loader/Loader.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include "stdafx.h" -#include "Loader.h" -#include "PSF.h" -#include "Emu/FS/vfsLocalFile.h" - -namespace loader -{ - bool loader::load(vfsStream& stream) - { - for (auto i : m_handlers) - { - i->set_status(i->init(stream)); - if (i->get_status() == handler::ok) - { - i->set_status(i->load()); - if (i->get_status() == handler::ok) - { - return true; - } - - LOG_NOTICE(LOADER, "loader::load() failed: %s", i->get_error_code().c_str()); - } - else - { - LOG_NOTICE(LOADER, "loader::init() failed: %s", i->get_error_code().c_str()); - stream.Seek(i->get_stream_offset()); - } - } - - return false; - } - - handler::error_code handler::init(vfsStream& stream) - { - m_stream_offset = stream.Tell(); - m_stream = &stream; - - return ok; - } -}; - -static const u64 g_spu_offset = 0x10000; - -const std::string Ehdr_DataToString(const u8 data) -{ - if(data > 1) return fmt::format("%d's complement, big endian", data); - if(data < 1) return "Data is not found"; - - return fmt::format("%d's complement, little endian", data); -} - -const std::string Ehdr_TypeToString(const u16 type) -{ - switch(type) - { - case 0: return "NULL"; - case 2: return "EXEC (Executable file)"; - }; - - return fmt::format("Unknown (%d)", type); -} - -const std::string Ehdr_OS_ABIToString(const u8 os_abi) -{ - switch(os_abi) - { - case 0x0 : return "UNIX System V"; - case 0x66: return "Cell OS LV-2"; - }; - - return fmt::format("Unknown (0x%x)", os_abi); -} - -const std::string Ehdr_MachineToString(const u16 machine) -{ - switch(machine) - { - case MACHINE_MIPS: return "MIPS"; - case MACHINE_PPC64: return "PowerPC64"; - case MACHINE_SPU: return "SPU"; - case MACHINE_ARM: return "ARM"; - }; - - return fmt::format("Unknown (0x%x)", machine); -} - -const std::string Phdr_FlagsToString(u32 flags) -{ - enum {ppu_R = 0x1, ppu_W = 0x2, ppu_E = 0x4}; - enum {spu_E = 0x1, spu_W = 0x2, spu_R = 0x4}; - enum {rsx_R = 0x1, rsx_W = 0x2, rsx_E = 0x4}; - -#define FLAGS_TO_STRING(f) \ - std::string(f & f##_R ? "R" : "-") + \ - std::string(f & f##_W ? "W" : "-") + \ - std::string(f & f##_E ? "E" : "-") - - const u8 ppu = flags & 0xf; - const u8 spu = (flags >> 0x14) & 0xf; - const u8 rsx = (flags >> 0x18) & 0xf; - - std::string ret; - ret += fmt::format("[0x%x] ", flags); - - flags &= ~ppu; - flags &= ~spu << 0x14; - flags &= ~rsx << 0x18; - - if(flags != 0) return fmt::format("Unknown %s PPU[0x%x] SPU[0x%x] RSX[0x%x]", ret.c_str(), ppu, spu, rsx); - - ret += "PPU[" + FLAGS_TO_STRING(ppu) + "] "; - ret += "SPU[" + FLAGS_TO_STRING(spu) + "] "; - ret += "RSX[" + FLAGS_TO_STRING(rsx) + "]"; - - return ret; -} - -const std::string Phdr_TypeToString(const u32 type) -{ - switch(type) - { - case 0x00000001: return "LOAD"; - case 0x00000004: return "NOTE"; - case 0x00000007: return "TLS"; - case 0x60000001: return "LOOS+1"; - case 0x60000002: return "LOOS+2"; - }; - - return fmt::format("Unknown (0x%x)", type); -} diff --git a/rpcs3/Loader/Loader.h b/rpcs3/Loader/Loader.h deleted file mode 100644 index 0b6834ccbd..0000000000 --- a/rpcs3/Loader/Loader.h +++ /dev/null @@ -1,131 +0,0 @@ -#pragma once -#include "Emu/Memory/vm.h" - -struct vfsFileBase; -struct vfsStream; - -#ifdef _DEBUG - //#define LOADER_DEBUG -#endif - -enum Elf_Machine -{ - MACHINE_Unknown, - MACHINE_MIPS = 0x08, - MACHINE_PPC64 = 0x15, - MACHINE_SPU = 0x17, - MACHINE_ARM = 0x28 -}; - -enum ShdrType -{ - SHT_NULL, - SHT_PROGBITS, - SHT_SYMTAB, - SHT_STRTAB, - SHT_RELA, - SHT_HASH, - SHT_DYNAMIC, - SHT_NOTE, - SHT_NOBITS, - SHT_REL, - SHT_SHLIB, - SHT_DYNSYM -}; - -enum ShdrFlag -{ - SHF_WRITE = 0x1, - SHF_ALLOC = 0x2, - SHF_EXECINSTR = 0x4, - SHF_MASKPROC = 0xf0000000 -}; - -const std::string Ehdr_DataToString(const u8 data); -const std::string Ehdr_TypeToString(const u16 type); -const std::string Ehdr_OS_ABIToString(const u8 os_abi); -const std::string Ehdr_MachineToString(const u16 machine); -const std::string Phdr_FlagsToString(u32 flags); -const std::string Phdr_TypeToString(const u32 type); - -namespace loader -{ - class handler - { - u64 m_stream_offset; - - protected: - vfsStream* m_stream; - - public: - enum error_code - { - bad_version = -1, - bad_file = -2, - broken_file = -3, - loading_error = -4, - bad_relocation_type = -5, - ok = 0 - }; - - virtual ~handler() = default; - - virtual error_code init(vfsStream& stream); - virtual error_code load() = 0; - u64 get_stream_offset() const - { - return m_stream_offset; - } - - void set_status(const error_code& code) - { - m_status = code; - } - - error_code get_status() const - { - return m_status; - } - - const std::string get_error_code() const - { - switch (m_status) - { - case bad_version: return "Bad version"; - case bad_file: return "Bad file"; - case broken_file: return "Broken file"; - case loading_error: return "Loading error"; - case bad_relocation_type: return "Bad relocation type"; - case ok: return "Ok"; - - default: return "Unknown error code"; - } - } - - protected: - error_code m_status; - }; - - class loader - { - std::vector m_handlers; - - public: - ~loader() - { - for (auto &h : m_handlers) - { - delete h; - } - } - - void register_handler(handler* handler) - { - m_handlers.push_back(handler); - } - - bool load(vfsStream& stream); - }; - - using namespace vm; -} diff --git a/rpcs3/Loader/PSF.cpp b/rpcs3/Loader/PSF.cpp index 3a9c5838b4..7292b2079f 100644 --- a/rpcs3/Loader/PSF.cpp +++ b/rpcs3/Loader/PSF.cpp @@ -3,7 +3,7 @@ namespace psf { - _log::channel log("PSF"); + _log::channel log("PSF", _log::level::notice); struct header_t { @@ -25,26 +25,26 @@ namespace psf const std::string& entry::as_string() const { - CHECK_ASSERTION(m_type == format::string || m_type == format::array); + Expects(m_type == format::string || m_type == format::array); return m_value_string; } u32 entry::as_integer() const { - CHECK_ASSERTION(m_type == format::integer); + Expects(m_type == format::integer); return m_value_integer; } entry& entry::operator =(const std::string& value) { - CHECK_ASSERTION(m_type == format::string || m_type == format::array); + Expects(m_type == format::string || m_type == format::array); m_value_string = value; return *this; } entry& entry::operator =(u32 value) { - CHECK_ASSERTION(m_type == format::integer); + Expects(m_type == format::integer); m_value_integer = value; return *this; } @@ -61,10 +61,10 @@ namespace psf return SIZE_32(u32); } - throw EXCEPTION("Invalid format (0x%x)", m_type); + throw fmt::exception("Invalid format (0x%x)" HERE, m_type); } - registry load(const std::vector& data) + registry load_object(const std::vector& data) { registry result; @@ -75,18 +75,18 @@ namespace psf } // Check size - CHECK_ASSERTION(data.size() >= sizeof(header_t)); - CHECK_ASSERTION((std::uintptr_t)data.data() % 8 == 0); + Expects(data.size() >= sizeof(header_t)); + Expects((std::uintptr_t)data.data() % 8 == 0); // Get header const header_t& header = reinterpret_cast(data[0]); // Check magic and version - CHECK_ASSERTION(header.magic == *(u32*)"\0PSF"); - CHECK_ASSERTION(header.version == 0x101); - CHECK_ASSERTION(sizeof(header_t) + header.entries_num * sizeof(def_table_t) <= header.off_key_table); - CHECK_ASSERTION(header.off_key_table <= header.off_data_table); - CHECK_ASSERTION(header.off_data_table <= data.size()); + Expects(header.magic == "\0PSF"_u32); + Expects(header.version == 0x101); + Expects(sizeof(header_t) + header.entries_num * sizeof(def_table_t) <= header.off_key_table); + Expects(header.off_key_table <= header.off_data_table); + Expects(header.off_data_table <= data.size()); // Get indices (alignment should be fine) const def_table_t* indices = reinterpret_cast(data.data() + sizeof(header_t)); @@ -94,7 +94,7 @@ namespace psf // Load entries for (u32 i = 0; i < header.entries_num; ++i) { - CHECK_ASSERTION(indices[i].key_off < header.off_data_table - header.off_key_table); + Expects(indices[i].key_off < header.off_data_table - header.off_key_table); // Get key name range const auto name_ptr = data.begin() + header.off_key_table + indices[i].key_off; @@ -103,10 +103,10 @@ namespace psf // Get name (must be unique) std::string key(name_ptr, name_end); - CHECK_ASSERTION(result.count(key) == 0); - CHECK_ASSERTION(indices[i].param_len <= indices[i].param_max); - CHECK_ASSERTION(indices[i].data_off < data.size() - header.off_data_table); - CHECK_ASSERTION(indices[i].param_max < data.size() - indices[i].data_off); + Expects(result.count(key) == 0); + Expects(indices[i].param_len <= indices[i].param_max); + Expects(indices[i].data_off < data.size() - header.off_data_table); + Expects(indices[i].param_max < data.size() - indices[i].data_off); // Get data pointer const auto value_ptr = data.begin() + header.off_data_table + indices[i].data_off; @@ -147,7 +147,7 @@ namespace psf return result; } - std::vector save(const registry& psf) + std::vector save_object(const registry& psf) { std::vector indices; indices.reserve(psf.size()); @@ -175,7 +175,7 @@ namespace psf // Generate header header_t header; - header.magic = *(u32*)"\0PSF"; + header.magic = "\0PSF"_u32; header.version = 0x101; header.off_key_table = gsl::narrow(sizeof(header_t) + sizeof(def_table_t) * psf.size()); header.off_data_table = gsl::narrow(header.off_key_table + key_offset); diff --git a/rpcs3/Loader/PSF.h b/rpcs3/Loader/PSF.h index 0a03d76caf..ed360ed2b8 100644 --- a/rpcs3/Loader/PSF.h +++ b/rpcs3/Loader/PSF.h @@ -1,5 +1,7 @@ #pragma once +#include + namespace psf { enum class format : u16 @@ -23,8 +25,8 @@ namespace psf , m_max_size(max_size) , m_value_string(value) { - CHECK_ASSERTION(type == format::string || type == format::array); - CHECK_ASSERTION(max_size); + Expects(type == format::string || type == format::array); + Expects(max_size); } // Construct integer entry, assign the value @@ -49,11 +51,24 @@ namespace psf // Define PSF registry as a sorted map of entries: using registry = std::map; - // Load PSF registry from binary data - registry load(const std::vector&); + // Load PSF registry from SFO binary data + registry load_object(const std::vector&); - // Convert PSF registry to binary format - std::vector save(const registry&); + // Load PSF registry from SFO file, if opened + inline registry load_object(const fs::file& f) + { + if (f) + { + return load_object(f.to_vector()); + } + else + { + return registry{}; + } + } + + // Convert PSF registry to SFO binary format + std::vector save_object(const registry&); // Get string value or default value std::string get_string(const registry& psf, const std::string& key, const std::string& def = {}); diff --git a/rpcs3/Loader/TROPUSR.cpp b/rpcs3/Loader/TROPUSR.cpp index 00f8473846..bd3e859a41 100644 --- a/rpcs3/Loader/TROPUSR.cpp +++ b/rpcs3/Loader/TROPUSR.cpp @@ -1,52 +1,41 @@ #include "stdafx.h" #include "Utilities/rXml.h" -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFileBase.h" #include "Emu/System.h" #include "TROPUSR.h" -TROPUSRLoader::TROPUSRLoader() -{ - m_file = NULL; - memset(&m_header, 0, sizeof(m_header)); -} - -TROPUSRLoader::~TROPUSRLoader() -{ - Close(); -} - bool TROPUSRLoader::Load(const std::string& filepath, const std::string& configpath) { - if (m_file) - { - Close(); - } + const std::string& path = vfs::get(filepath); - if (!Emu.GetVFS().ExistsFile(filepath)) + if (!fs::is_file(path)) { Generate(filepath, configpath); } - m_file = Emu.GetVFS().OpenFile(filepath, fom::read); - LoadHeader(); - LoadTableHeaders(); - LoadTables(); + if (!m_file.open(path, fs::read)) + { + return false; + } - Close(); + if (!LoadHeader() || !LoadTableHeaders() || !LoadTables()) + { + return false; + } + + m_file.release(); return true; } bool TROPUSRLoader::LoadHeader() { - if (!m_file->IsOpened()) + if (!m_file) { return false; } - m_file->Seek(0); + m_file.seek(0); - if (m_file->Read(&m_header, sizeof(TROPUSRHeader)) != sizeof(TROPUSRHeader)) + if (!m_file.read(m_header)) { return false; } @@ -56,18 +45,18 @@ bool TROPUSRLoader::LoadHeader() bool TROPUSRLoader::LoadTableHeaders() { - if (!m_file->IsOpened()) + if (!m_file) { return false; } - m_file->Seek(0x30); + m_file.seek(0x30); m_tableHeaders.clear(); m_tableHeaders.resize(m_header.tables_count); for (TROPUSRTableHeader& tableHeader : m_tableHeaders) { - if (m_file->Read(&tableHeader, sizeof(TROPUSRTableHeader)) != sizeof(TROPUSRTableHeader)) + if (!m_file.read(tableHeader)) return false; } @@ -76,14 +65,14 @@ bool TROPUSRLoader::LoadTableHeaders() bool TROPUSRLoader::LoadTables() { - if (!m_file->IsOpened()) + if (!m_file) { return false; } for (const TROPUSRTableHeader& tableHeader : m_tableHeaders) { - m_file->Seek(tableHeader.offset); + m_file.seek(tableHeader.offset); if (tableHeader.type == 4) { @@ -92,7 +81,7 @@ bool TROPUSRLoader::LoadTables() for (auto& entry : m_table4) { - if (m_file->Read(&entry, sizeof(TROPUSREntry4)) != sizeof(TROPUSREntry4)) + if (!m_file.read(entry)) return false; } } @@ -104,7 +93,7 @@ bool TROPUSRLoader::LoadTables() for (auto& entry : m_table6) { - if (m_file->Read(&entry, sizeof(TROPUSREntry6)) != sizeof(TROPUSREntry6)) + if (!m_file.read(entry)) return false; } } @@ -118,39 +107,39 @@ bool TROPUSRLoader::LoadTables() // TODO: TROPUSRLoader::Save deletes the TROPUSR and creates it again. This is probably very slow. bool TROPUSRLoader::Save(const std::string& filepath) { - if (m_file) + if (!m_file.open(vfs::get(filepath), fs::rewrite)) { - Close(); + return false; } - m_file = Emu.GetVFS().OpenFile(filepath, fom::rewrite); - m_file->Write(&m_header, sizeof(TROPUSRHeader)); + m_file.write(m_header); for (const TROPUSRTableHeader& tableHeader : m_tableHeaders) { - m_file->Write(&tableHeader, sizeof(TROPUSRTableHeader)); + m_file.write(tableHeader); } for (const auto& entry : m_table4) { - m_file->Write(&entry, sizeof(TROPUSREntry4)); + m_file.write(entry); } for (const auto& entry : m_table6) { - m_file->Write(&entry, sizeof(TROPUSREntry6)); + m_file.write(entry); } - m_file->Close(); - + m_file.release(); return true; } bool TROPUSRLoader::Generate(const std::string& filepath, const std::string& configpath) { - std::string path; + const std::string& path = vfs::get(configpath); + + // TODO: rXmlDocument can open only real file + ASSERT(!fs::get_virtual_device(path)); rXmlDocument doc; - Emu.GetVFS().GetDevice(configpath.c_str(), path); doc.Load(path); m_table4.clear(); @@ -238,13 +227,3 @@ bool TROPUSRLoader::UnlockTrophy(u32 id, u64 timestamp1, u64 timestamp2) return true; } - -void TROPUSRLoader::Close() -{ - if (m_file) - { - m_file->Close(); - delete m_file; - m_file = nullptr; - } -} diff --git a/rpcs3/Loader/TROPUSR.h b/rpcs3/Loader/TROPUSR.h index e3d2921aae..128b5b0064 100644 --- a/rpcs3/Loader/TROPUSR.h +++ b/rpcs3/Loader/TROPUSR.h @@ -1,7 +1,5 @@ #pragma once -struct vfsStream; - struct TROPUSRHeader { be_t magic; // 81 8F 54 AD @@ -56,8 +54,8 @@ struct TROPUSREntry6 class TROPUSRLoader { - vfsStream* m_file; - TROPUSRHeader m_header; + fs::file m_file; + TROPUSRHeader m_header{}; std::vector m_tableHeaders; std::vector m_table4; @@ -69,12 +67,8 @@ class TROPUSRLoader virtual bool LoadTables(); public: - TROPUSRLoader(); - ~TROPUSRLoader(); - virtual bool Load(const std::string& filepath, const std::string& configpath); virtual bool Save(const std::string& filepath); - virtual void Close(); virtual u32 GetTrophiesCount(); diff --git a/rpcs3/Loader/TRP.cpp b/rpcs3/Loader/TRP.cpp index 2a8123cf55..28cfc3b108 100644 --- a/rpcs3/Loader/TRP.cpp +++ b/rpcs3/Loader/TRP.cpp @@ -1,42 +1,34 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFile.h" #include "TRP.h" -TRPLoader::TRPLoader(vfsStream& f) : trp_f(f) +TRPLoader::TRPLoader(const fs::file& f) + : trp_f(f) { } -TRPLoader::~TRPLoader() +bool TRPLoader::Install(const std::string& dest, bool show) { - Close(); -} - -bool TRPLoader::Install(std::string dest, bool show) -{ - if (!trp_f.IsOpened()) + if (!trp_f) { return false; } - if (!dest.empty() && dest.back() != '/') + const std::string& local_path = vfs::get(dest); + + if (!fs::create_dir(local_path) && errno != EEXIST) { - dest += '/'; + return false; } - if (!Emu.GetVFS().ExistsDir(dest)) - { - Emu.GetVFS().CreateDir(dest); - } + std::vector buffer; buffer.reserve(65536); for (const TRPEntry& entry : m_entries) { - char* buffer = new char [(u32)entry.size]; - trp_f.Seek(entry.offset); - trp_f.Read(buffer, entry.size); - vfsFile(dest + entry.name, fom::rewrite).Write(buffer, entry.size); - delete[] buffer; + trp_f.seek(entry.offset); + buffer.resize(entry.size); + if (!trp_f.read(buffer)) continue; // ??? + fs::file(local_path + '/' + entry.name, fs::rewrite).write(buffer); } return true; @@ -44,14 +36,14 @@ bool TRPLoader::Install(std::string dest, bool show) bool TRPLoader::LoadHeader(bool show) { - if (!trp_f.IsOpened()) + if (!trp_f) { return false; } - trp_f.Seek(0); + trp_f.seek(0); - if (trp_f.Read(&m_header, sizeof(TRPHeader)) != sizeof(TRPHeader)) + if (!trp_f.read(m_header)) { return false; } @@ -71,7 +63,7 @@ bool TRPLoader::LoadHeader(bool show) for (u32 i = 0; i < m_header.trp_files_count; i++) { - if (trp_f.Read(&m_entries[i], sizeof(TRPEntry)) != sizeof(TRPEntry)) + if (!trp_f.read(m_entries[i])) { return false; } @@ -123,8 +115,3 @@ void TRPLoader::RenameEntry(const char *oldname, const char *newname) } } } - -void TRPLoader::Close() -{ - trp_f.Close(); -} diff --git a/rpcs3/Loader/TRP.h b/rpcs3/Loader/TRP.h index f2818ad525..46c687058a 100644 --- a/rpcs3/Loader/TRP.h +++ b/rpcs3/Loader/TRP.h @@ -1,7 +1,5 @@ #pragma once -struct vfsStream; - struct TRPHeader { be_t trp_magic; @@ -23,21 +21,19 @@ struct TRPEntry char padding[12]; }; -class TRPLoader +class TRPLoader final { - vfsStream& trp_f; + const fs::file& trp_f; TRPHeader m_header; std::vector m_entries; public: - TRPLoader(vfsStream& f); - ~TRPLoader(); - virtual bool Install(std::string dest, bool show = false); - virtual bool LoadHeader(bool show = false); + TRPLoader(const fs::file& f); - virtual bool ContainsEntry(const char *filename); - virtual void RemoveEntry(const char *filename); - virtual void RenameEntry(const char *oldname, const char *newname); + bool Install(const std::string& dest, bool show = false); + bool LoadHeader(bool show = false); - virtual void Close(); + bool ContainsEntry(const char *filename); + void RemoveEntry(const char *filename); + void RenameEntry(const char *oldname, const char *newname); }; From 7e30a0f46407a801aa8fa5218f203d498c31c8bd Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Mon, 21 Mar 2016 22:42:14 +0300 Subject: [PATCH 04/19] Partial commit: Modules --- rpcs3/Emu/Cell/Modules/libmixer.cpp | 654 +++++++++ .../Emu/{SysCalls => Cell}/Modules/libmixer.h | 0 .../{SysCalls => Cell}/Modules/libsnd3.cpp | 107 +- .../Emu/{SysCalls => Cell}/Modules/libsnd3.h | 2 - .../{SysCalls => Cell}/Modules/libsynth2.cpp | 41 +- .../{SysCalls => Cell}/Modules/libsynth2.h | 2 - .../Emu/{SysCalls => Cell}/Modules/sceNp.cpp | 61 +- rpcs3/Emu/{SysCalls => Cell}/Modules/sceNp.h | 0 .../Emu/{SysCalls => Cell}/Modules/sceNp2.cpp | 7 +- rpcs3/Emu/{SysCalls => Cell}/Modules/sceNp2.h | 0 .../{SysCalls => Cell}/Modules/sceNpClans.cpp | 7 +- .../{SysCalls => Cell}/Modules/sceNpClans.h | 0 .../Modules/sceNpCommerce2.cpp | 7 +- .../Modules/sceNpCommerce2.h | 0 .../{SysCalls => Cell}/Modules/sceNpSns.cpp | 6 +- .../Emu/{SysCalls => Cell}/Modules/sceNpSns.h | 0 .../Modules/sceNpTrophy.cpp | 48 +- .../{SysCalls => Cell}/Modules/sceNpTrophy.h | 0 .../{SysCalls => Cell}/Modules/sceNpTus.cpp | 7 +- .../Emu/{SysCalls => Cell}/Modules/sceNpTus.h | 0 .../{SysCalls => Cell}/Modules/sceNpUtil.cpp | 7 +- .../{SysCalls => Cell}/Modules/sceNpUtil.h | 0 .../Modules/sysPrxForUser.cpp | 143 +- .../Modules/sysPrxForUser.h | 0 .../{SysCalls => Cell}/Modules/sys_game.cpp | 26 +- .../{SysCalls => Cell}/Modules/sys_heap.cpp | 7 +- .../Emu/{SysCalls => Cell}/Modules/sys_io.cpp | 6 +- rpcs3/Emu/Cell/Modules/sys_libc.cpp | 24 + .../Modules/sys_libc_.cpp} | 56 +- .../{SysCalls => Cell}/Modules/sys_lv2dbg.cpp | 7 +- .../{SysCalls => Cell}/Modules/sys_lv2dbg.h | 16 +- .../Modules/sys_lwcond_.cpp | 18 +- .../Modules/sys_lwmutex_.cpp | 15 +- .../Modules/sys_mempool.cpp | 5 +- .../Modules/sys_mmapper_.cpp | 7 +- .../{SysCalls => Cell}/Modules/sys_net.cpp | 12 +- .../Emu/{SysCalls => Cell}/Modules/sys_net.h | 0 .../Modules/sys_ppu_thread_.cpp | 41 +- .../{SysCalls => Cell}/Modules/sys_prx_.cpp | 7 +- .../Modules/sys_spinlock.cpp | 5 +- .../{SysCalls => Cell}/Modules/sys_spu_.cpp | 58 +- rpcs3/Emu/SysCalls/ModuleManager.cpp | 343 ----- rpcs3/Emu/SysCalls/ModuleManager.h | 20 - rpcs3/Emu/SysCalls/Modules.cpp | 576 -------- rpcs3/Emu/SysCalls/Modules.h | 185 --- rpcs3/Emu/SysCalls/Modules/libmixer.cpp | 1198 ----------------- 46 files changed, 1021 insertions(+), 2710 deletions(-) create mode 100644 rpcs3/Emu/Cell/Modules/libmixer.cpp rename rpcs3/Emu/{SysCalls => Cell}/Modules/libmixer.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/libsnd3.cpp (71%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/libsnd3.h (97%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/libsynth2.cpp (75%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/libsynth2.h (92%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sceNp.cpp (95%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sceNp.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sceNp2.cpp (98%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sceNp2.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sceNpClans.cpp (98%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sceNpClans.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sceNpCommerce2.cpp (98%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sceNpCommerce2.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sceNpSns.cpp (92%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sceNpSns.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sceNpTrophy.cpp (92%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sceNpTrophy.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sceNpTus.cpp (98%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sceNpTus.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sceNpUtil.cpp (83%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sceNpUtil.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sysPrxForUser.cpp (51%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sysPrxForUser.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sys_game.cpp (91%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sys_heap.cpp (95%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sys_io.cpp (88%) create mode 100644 rpcs3/Emu/Cell/Modules/sys_libc.cpp rename rpcs3/Emu/{SysCalls/Modules/sys_libc.cpp => Cell/Modules/sys_libc_.cpp} (83%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sys_lv2dbg.cpp (97%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sys_lv2dbg.h (95%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sys_lwcond_.cpp (94%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sys_lwmutex_.cpp (94%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sys_mempool.cpp (97%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sys_mmapper_.cpp (76%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sys_net.cpp (97%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sys_net.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sys_ppu_thread_.cpp (72%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sys_prx_.cpp (90%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sys_spinlock.cpp (92%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/sys_spu_.cpp (78%) delete mode 100644 rpcs3/Emu/SysCalls/ModuleManager.cpp delete mode 100644 rpcs3/Emu/SysCalls/ModuleManager.h delete mode 100644 rpcs3/Emu/SysCalls/Modules.cpp delete mode 100644 rpcs3/Emu/SysCalls/Modules.h delete mode 100644 rpcs3/Emu/SysCalls/Modules/libmixer.cpp diff --git a/rpcs3/Emu/Cell/Modules/libmixer.cpp b/rpcs3/Emu/Cell/Modules/libmixer.cpp new file mode 100644 index 0000000000..ac5b0ed831 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/libmixer.cpp @@ -0,0 +1,654 @@ +#include "stdafx.h" +#include "Emu/System.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" + +#include "cellAudio.h" +#include "libmixer.h" + +LOG_CHANNEL(libmixer); + +// TODO: use fxm +SurMixerConfig g_surmx; + +std::vector g_ssp; + +s32 cellAANAddData(u32 aan_handle, u32 aan_port, u32 offset, vm::ptr addr, u32 samples) +{ + libmixer.trace("cellAANAddData(aan_handle=0x%x, aan_port=0x%x, offset=0x%x, addr=*0x%x, samples=%d)", aan_handle, aan_port, offset, addr, samples); + + u32 type = aan_port >> 16; + u32 port = aan_port & 0xffff; + + switch (type) + { + case CELL_SURMIXER_CHSTRIP_TYPE1A: + if (port >= g_surmx.ch_strips_1) type = 0; break; + case CELL_SURMIXER_CHSTRIP_TYPE2A: + if (port >= g_surmx.ch_strips_2) type = 0; break; + case CELL_SURMIXER_CHSTRIP_TYPE6A: + if (port >= g_surmx.ch_strips_6) type = 0; break; + case CELL_SURMIXER_CHSTRIP_TYPE8A: + if (port >= g_surmx.ch_strips_8) type = 0; break; + default: + type = 0; break; + } + + if (aan_handle != 0x11111111 || samples != 256 || !type || offset != 0) + { + libmixer.error("cellAANAddData(aan_handle=0x%x, aan_port=0x%x, offset=0x%x, addr=*0x%x, samples=%d): invalid parameters", aan_handle, aan_port, offset, addr, samples); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + std::lock_guard lock(g_surmx.mutex); + + if (type == CELL_SURMIXER_CHSTRIP_TYPE1A) + { + // mono upmixing + for (u32 i = 0; i < samples; i++) + { + const float center = addr[i]; + g_surmx.mixdata[i * 8 + 0] += center; + g_surmx.mixdata[i * 8 + 1] += center; + } + } + else if (type == CELL_SURMIXER_CHSTRIP_TYPE2A) + { + // stereo upmixing + for (u32 i = 0; i < samples; i++) + { + const float left = addr[i * 2 + 0]; + const float right = addr[i * 2 + 1]; + g_surmx.mixdata[i * 8 + 0] += left; + g_surmx.mixdata[i * 8 + 1] += right; + } + } + else if (type == CELL_SURMIXER_CHSTRIP_TYPE6A) + { + // 5.1 upmixing + for (u32 i = 0; i < samples; i++) + { + const float left = addr[i * 6 + 0]; + const float right = addr[i * 6 + 1]; + const float center = addr[i * 6 + 2]; + const float low_freq = addr[i * 6 + 3]; + const float rear_left = addr[i * 6 + 4]; + const float rear_right = addr[i * 6 + 5]; + g_surmx.mixdata[i * 8 + 0] += left; + g_surmx.mixdata[i * 8 + 1] += right; + g_surmx.mixdata[i * 8 + 2] += center; + g_surmx.mixdata[i * 8 + 3] += low_freq; + g_surmx.mixdata[i * 8 + 4] += rear_left; + g_surmx.mixdata[i * 8 + 5] += rear_right; + } + } + else if (type == CELL_SURMIXER_CHSTRIP_TYPE8A) + { + // 7.1 + for (u32 i = 0; i < samples * 8; i++) + { + g_surmx.mixdata[i] += addr[i]; + } + } + + return CELL_OK; +} + +s32 cellAANConnect(u32 receive, u32 receivePortNo, u32 source, u32 sourcePortNo) +{ + libmixer.warning("cellAANConnect(receive=0x%x, receivePortNo=0x%x, source=0x%x, sourcePortNo=0x%x)", + receive, receivePortNo, source, sourcePortNo); + + std::lock_guard lock(g_surmx.mutex); + + if (source >= g_ssp.size() || !g_ssp[source].m_created) + { + libmixer.error("cellAANConnect(): invalid source (%d)", source); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + g_ssp[source].m_connected = true; + + return CELL_OK; +} + +s32 cellAANDisconnect(u32 receive, u32 receivePortNo, u32 source, u32 sourcePortNo) +{ + libmixer.warning("cellAANDisconnect(receive=0x%x, receivePortNo=0x%x, source=0x%x, sourcePortNo=0x%x)", + receive, receivePortNo, source, sourcePortNo); + + std::lock_guard lock(g_surmx.mutex); + + if (source >= g_ssp.size() || !g_ssp[source].m_created) + { + libmixer.error("cellAANDisconnect(): invalid source (%d)", source); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + g_ssp[source].m_connected = false; + + return CELL_OK; +} + +s32 cellSSPlayerCreate(vm::ptr handle, vm::ptr config) +{ + libmixer.warning("cellSSPlayerCreate(handle=*0x%x, config=*0x%x)", handle, config); + + if (config->outputMode != 0 || config->channels - 1 >= 2) + { + libmixer.error("cellSSPlayerCreate(config.outputMode=%d, config.channels=%d): invalid parameters", config->outputMode, config->channels); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + std::lock_guard lock(g_surmx.mutex); + + SSPlayer p; + p.m_created = true; + p.m_connected = false; + p.m_active = false; + p.m_channels = config->channels; + + g_ssp.push_back(p); + *handle = (u32)g_ssp.size() - 1; + return CELL_OK; +} + +s32 cellSSPlayerRemove(u32 handle) +{ + libmixer.warning("cellSSPlayerRemove(handle=0x%x)", handle); + + std::lock_guard lock(g_surmx.mutex); + + if (handle >= g_ssp.size() || !g_ssp[handle].m_created) + { + libmixer.error("cellSSPlayerRemove(): SSPlayer not found (%d)", handle); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + g_ssp[handle].m_active = false; + g_ssp[handle].m_created = false; + g_ssp[handle].m_connected = false; + + return CELL_OK; +} + +s32 cellSSPlayerSetWave(u32 handle, vm::ptr waveInfo, vm::ptr commonInfo) +{ + libmixer.warning("cellSSPlayerSetWave(handle=0x%x, waveInfo=*0x%x, commonInfo=*0x%x)", handle, waveInfo, commonInfo); + + std::lock_guard lock(g_surmx.mutex); + + if (handle >= g_ssp.size() || !g_ssp[handle].m_created) + { + libmixer.error("cellSSPlayerSetWave(): SSPlayer not found (%d)", handle); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + // TODO: check parameters + + g_ssp[handle].m_addr = waveInfo->addr; + g_ssp[handle].m_samples = waveInfo->samples; + g_ssp[handle].m_loop_start = waveInfo->loopStartOffset - 1; + g_ssp[handle].m_loop_mode = commonInfo ? (u32)commonInfo->loopMode : CELL_SSPLAYER_ONESHOT; + g_ssp[handle].m_position = waveInfo->startOffset - 1; + + return CELL_OK; +} + +s32 cellSSPlayerPlay(u32 handle, vm::ptr info) +{ + libmixer.warning("cellSSPlayerPlay(handle=0x%x, info=*0x%x)", handle, info); + + std::lock_guard lock(g_surmx.mutex); + + if (handle >= g_ssp.size() || !g_ssp[handle].m_created) + { + libmixer.error("cellSSPlayerPlay(): SSPlayer not found (%d)", handle); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + // TODO: check parameters + + g_ssp[handle].m_active = true; + g_ssp[handle].m_level = info->level; + g_ssp[handle].m_speed = info->speed; + g_ssp[handle].m_x = info->position.x; + g_ssp[handle].m_y = info->position.y; + g_ssp[handle].m_z = info->position.z; + + return CELL_OK; +} + +s32 cellSSPlayerStop(u32 handle, u32 mode) +{ + libmixer.warning("cellSSPlayerStop(handle=0x%x, mode=0x%x)", handle, mode); + + std::lock_guard lock(g_surmx.mutex); + + if (handle >= g_ssp.size() || !g_ssp[handle].m_created) + { + libmixer.error("cellSSPlayerStop(): SSPlayer not found (%d)", handle); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + // TODO: transition to stop state + + g_ssp[handle].m_active = false; + + return CELL_OK; +} + +s32 cellSSPlayerSetParam(u32 handle, vm::ptr info) +{ + libmixer.warning("cellSSPlayerSetParam(handle=0x%x, info=*0x%x)", handle, info); + + std::lock_guard lock(g_surmx.mutex); + + if (handle >= g_ssp.size() || !g_ssp[handle].m_created) + { + libmixer.error("cellSSPlayerSetParam(): SSPlayer not found (%d)", handle); + return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; + } + + // TODO: check parameters + + g_ssp[handle].m_level = info->level; + g_ssp[handle].m_speed = info->speed; + g_ssp[handle].m_x = info->position.x; + g_ssp[handle].m_y = info->position.y; + g_ssp[handle].m_z = info->position.z; + + return CELL_OK; +} + +s32 cellSSPlayerGetState(u32 handle) +{ + libmixer.warning("cellSSPlayerGetState(handle=0x%x)", handle); + + std::lock_guard lock(g_surmx.mutex); + + if (handle >= g_ssp.size() || !g_ssp[handle].m_created) + { + libmixer.warning("cellSSPlayerGetState(): SSPlayer not found (%d)", handle); + return CELL_SSPLAYER_STATE_ERROR; + } + + if (g_ssp[handle].m_active) + { + return CELL_SSPLAYER_STATE_ON; + } + + return CELL_SSPLAYER_STATE_OFF; +} + +s32 cellSurMixerCreate(vm::cptr config) +{ + libmixer.warning("cellSurMixerCreate(config=*0x%x)", config); + + const auto g_audio = fxm::get(); + + const auto port = g_audio->open_port(); + + if (!port) + { + return CELL_LIBMIXER_ERROR_FULL; + } + + g_surmx.audio_port = port->number; + g_surmx.priority = config->priority; + g_surmx.ch_strips_1 = config->chStrips1; + g_surmx.ch_strips_2 = config->chStrips2; + g_surmx.ch_strips_6 = config->chStrips6; + g_surmx.ch_strips_8 = config->chStrips8; + + port->channel = 8; + port->block = 16; + port->attr = 0; + port->size = port->channel * port->block * AUDIO_SAMPLES * sizeof(float); + port->tag = 0; + port->level = 1.0f; + port->level_set.store({ 1.0f, 0.0f }); + + libmixer.warning("*** audio port opened (port=%d)", g_surmx.audio_port); + + g_surmx.mixcount = 0; + g_surmx.cb = vm::null; + + g_ssp.clear(); + + libmixer.warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", config->chStrips1, config->chStrips2, config->chStrips6, config->chStrips8); + + const auto ppu = idm::make_ptr("Surmixer Thread"); + ppu->prio = 1001; + ppu->stack_size = 0x10000; + ppu->custom_task = [g_audio](PPUThread& ppu) + { + audio_port& port = g_audio->ports[g_surmx.audio_port]; + + while (port.state != audio_port_state::closed) + { + CHECK_EMU_STATUS; + + if (g_surmx.mixcount > (port.tag + 0)) // adding positive value (1-15): preemptive buffer filling (hack) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + continue; + } + + if (port.state == audio_port_state::started) + { + //u64 stamp0 = get_system_time(); + + memset(g_surmx.mixdata, 0, sizeof(g_surmx.mixdata)); + if (g_surmx.cb) + { + g_surmx.cb(ppu, g_surmx.cb_arg, (u32)g_surmx.mixcount, 256); + } + + //u64 stamp1 = get_system_time(); + + { + std::lock_guard lock(g_surmx.mutex); + + for (auto& p : g_ssp) if (p.m_active && p.m_created) + { + auto v = vm::ptrl::make(p.m_addr); // 16-bit LE audio data + float left = 0.0f; + float right = 0.0f; + float speed = fabs(p.m_speed); + float fpos = 0.0f; + for (s32 i = 0; i < 256; i++) if (p.m_active) + { + u32 pos = p.m_position; + s32 pos_inc = 0; + if (p.m_speed > 0.0f) // select direction + { + pos_inc = 1; + } + else if (p.m_speed < 0.0f) + { + pos_inc = -1; + } + s32 shift = i - (int)fpos; // change playback speed (simple and rough) + if (shift > 0) + { + // slow playback + pos_inc = 0; // duplicate one sample at this time + fpos += 1.0f; + fpos += speed; + } + else if (shift < 0) + { + // fast playback + i--; // mix two sample into one at this time + fpos -= 1.0f; + } + else + { + fpos += speed; + } + p.m_position += (u32)pos_inc; + if (p.m_channels == 1) // get mono data + { + left = right = (float)v[pos] / 0x8000 * p.m_level; + } + else if (p.m_channels == 2) // get stereo data + { + left = (float)v[pos * 2 + 0] / 0x8000 * p.m_level; + right = (float)v[pos * 2 + 1] / 0x8000 * p.m_level; + } + if (p.m_connected) // mix + { + // TODO: m_x, m_y, m_z ignored + g_surmx.mixdata[i * 8 + 0] += left; + g_surmx.mixdata[i * 8 + 1] += right; + } + if ((p.m_position == p.m_samples && p.m_speed > 0.0f) || + (p.m_position == ~0 && p.m_speed < 0.0f)) // loop or stop + { + if (p.m_loop_mode == CELL_SSPLAYER_LOOP_ON) + { + p.m_position = p.m_loop_start; + } + else if (p.m_loop_mode == CELL_SSPLAYER_ONESHOT_CONT) + { + p.m_position -= (u32)pos_inc; // restore position + } + else // oneshot + { + p.m_active = false; + p.m_position = p.m_loop_start; // TODO: check value + } + } + } + } + } + + //u64 stamp2 = get_system_time(); + + auto buf = vm::_ptr(port.addr.addr() + (g_surmx.mixcount % port.block) * port.channel * AUDIO_SAMPLES * sizeof(float)); + + for (auto& mixdata : g_surmx.mixdata) + { + // reverse byte order + *buf++ = mixdata; + } + + //u64 stamp3 = get_system_time(); + + //ConLog.Write("Libmixer perf: start=%lld (cb=%lld, ssp=%lld, finalize=%lld)", stamp0 - m_config.start_time, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2); + } + + g_surmx.mixcount++; + } + + idm::remove(ppu.id); + }; + + ppu->cpu_init(); + ppu->state -= cpu_state::stop; + ppu->safe_notify(); + + return CELL_OK; +} + +s32 cellSurMixerGetAANHandle(vm::ptr handle) +{ + libmixer.warning("cellSurMixerGetAANHandle(handle=*0x%x) -> %d", handle, 0x11111111); + *handle = 0x11111111; + return CELL_OK; +} + +s32 cellSurMixerChStripGetAANPortNo(vm::ptr port, u32 type, u32 index) +{ + libmixer.warning("cellSurMixerChStripGetAANPortNo(port=*0x%x, type=0x%x, index=0x%x) -> 0x%x", port, type, index, (type << 16) | index); + *port = (type << 16) | index; + return CELL_OK; +} + +s32 cellSurMixerSetNotifyCallback(vm::ptr func, vm::ptr arg) +{ + libmixer.warning("cellSurMixerSetNotifyCallback(func=*0x%x, arg=*0x%x)", func, arg); + + if (g_surmx.cb) + { + throw EXCEPTION("Callback already set"); + } + + g_surmx.cb = func; + g_surmx.cb_arg = arg; + + return CELL_OK; +} + +s32 cellSurMixerRemoveNotifyCallback(vm::ptr func) +{ + libmixer.warning("cellSurMixerRemoveNotifyCallback(func=*0x%x)", func); + + if (g_surmx.cb != func) + { + throw EXCEPTION("Callback not set"); + } + + g_surmx.cb = vm::null; + + return CELL_OK; +} + +s32 cellSurMixerStart() +{ + libmixer.warning("cellSurMixerStart()"); + + const auto g_audio = fxm::get(); + + if (g_surmx.audio_port >= AUDIO_PORT_COUNT) + { + return CELL_LIBMIXER_ERROR_NOT_INITIALIZED; + } + + g_audio->ports[g_surmx.audio_port].state.compare_and_swap(audio_port_state::opened, audio_port_state::started); + + return CELL_OK; +} + +s32 cellSurMixerSetParameter(u32 param, float value) +{ + libmixer.todo("cellSurMixerSetParameter(param=0x%x, value=%f)", param, value); + return CELL_OK; +} + +s32 cellSurMixerFinalize() +{ + libmixer.warning("cellSurMixerFinalize()"); + + const auto g_audio = fxm::get(); + + if (g_surmx.audio_port >= AUDIO_PORT_COUNT) + { + return CELL_LIBMIXER_ERROR_NOT_INITIALIZED; + } + + g_audio->ports[g_surmx.audio_port].state.compare_and_swap(audio_port_state::opened, audio_port_state::closed); + + return CELL_OK; +} + +s32 cellSurMixerSurBusAddData(u32 busNo, u32 offset, vm::ptr addr, u32 samples) +{ + if (busNo < 8 && samples == 256 && offset == 0) + { + libmixer.trace("cellSurMixerSurBusAddData(busNo=%d, offset=0x%x, addr=0x%x, samples=%d)", busNo, offset, addr, samples); + } + else + { + libmixer.todo("cellSurMixerSurBusAddData(busNo=%d, offset=0x%x, addr=0x%x, samples=%d)", busNo, offset, addr, samples); + return CELL_OK; + } + + std::lock_guard lock(g_surmx.mutex); + + for (u32 i = 0; i < samples; i++) + { + // reverse byte order and mix + g_surmx.mixdata[i * 8 + busNo] += addr[i]; + } + + return CELL_OK; +} + +s32 cellSurMixerChStripSetParameter(u32 type, u32 index, vm::ptr param) +{ + libmixer.todo("cellSurMixerChStripSetParameter(type=%d, index=%d, param=*0x%x)", type, index, param); + return CELL_OK; +} + +s32 cellSurMixerPause(u32 type) +{ + libmixer.warning("cellSurMixerPause(type=%d)", type); + + const auto g_audio = fxm::get(); + + if (g_surmx.audio_port >= AUDIO_PORT_COUNT) + { + return CELL_LIBMIXER_ERROR_NOT_INITIALIZED; + } + + g_audio->ports[g_surmx.audio_port].state.compare_and_swap(audio_port_state::started, audio_port_state::opened); + + return CELL_OK; +} + +s32 cellSurMixerGetCurrentBlockTag(vm::ptr tag) +{ + libmixer.trace("cellSurMixerGetCurrentBlockTag(tag=*0x%x)", tag); + + *tag = g_surmx.mixcount; + return CELL_OK; +} + +s32 cellSurMixerGetTimestamp(u64 tag, vm::ptr stamp) +{ + libmixer.trace("cellSurMixerGetTimestamp(tag=0x%llx, stamp=*0x%x)", tag, stamp); + + const auto g_audio = fxm::get(); + *stamp = g_audio->start_time + (tag) * 256000000 / 48000; // ??? + return CELL_OK; +} + +void cellSurMixerBeep(u32 arg) +{ + libmixer.todo("cellSurMixerBeep(arg=%d)", arg); + return; +} + +f32 cellSurMixerUtilGetLevelFromDB(f32 dB) +{ + libmixer.todo("cellSurMixerUtilGetLevelFromDB(dB=%f)", dB); + throw EXCEPTION("TODO"); +} + +f32 cellSurMixerUtilGetLevelFromDBIndex(s32 index) +{ + libmixer.todo("cellSurMixerUtilGetLevelFromDBIndex(index=%d)", index); + throw EXCEPTION("TODO"); +} + +f32 cellSurMixerUtilNoteToRatio(u8 refNote, u8 note) +{ + libmixer.todo("cellSurMixerUtilNoteToRatio(refNote=%d, note=%d)", refNote, note); + throw EXCEPTION("TODO"); +} + +DECLARE(ppu_module_manager::libmixer)("libmixer", []() +{ + REG_FUNC(libmixer, cellAANAddData); + REG_FUNC(libmixer, cellAANConnect); + REG_FUNC(libmixer, cellAANDisconnect); + + REG_FUNC(libmixer, cellSurMixerCreate); + REG_FUNC(libmixer, cellSurMixerGetAANHandle); + REG_FUNC(libmixer, cellSurMixerChStripGetAANPortNo); + REG_FUNC(libmixer, cellSurMixerSetNotifyCallback); + REG_FUNC(libmixer, cellSurMixerRemoveNotifyCallback); + REG_FUNC(libmixer, cellSurMixerStart); + REG_FUNC(libmixer, cellSurMixerSetParameter); + REG_FUNC(libmixer, cellSurMixerFinalize); + REG_FUNC(libmixer, cellSurMixerSurBusAddData); + REG_FUNC(libmixer, cellSurMixerChStripSetParameter); + REG_FUNC(libmixer, cellSurMixerPause); + REG_FUNC(libmixer, cellSurMixerGetCurrentBlockTag); + REG_FUNC(libmixer, cellSurMixerGetTimestamp); + REG_FUNC(libmixer, cellSurMixerBeep); + + REG_FUNC(libmixer, cellSSPlayerCreate); + REG_FUNC(libmixer, cellSSPlayerRemove); + REG_FUNC(libmixer, cellSSPlayerSetWave); + REG_FUNC(libmixer, cellSSPlayerPlay); + REG_FUNC(libmixer, cellSSPlayerStop); + REG_FUNC(libmixer, cellSSPlayerSetParam); + REG_FUNC(libmixer, cellSSPlayerGetState); + + REG_FUNC(libmixer, cellSurMixerUtilGetLevelFromDB); + REG_FUNC(libmixer, cellSurMixerUtilGetLevelFromDBIndex); + REG_FUNC(libmixer, cellSurMixerUtilNoteToRatio); +}); diff --git a/rpcs3/Emu/SysCalls/Modules/libmixer.h b/rpcs3/Emu/Cell/Modules/libmixer.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/libmixer.h rename to rpcs3/Emu/Cell/Modules/libmixer.h diff --git a/rpcs3/Emu/SysCalls/Modules/libsnd3.cpp b/rpcs3/Emu/Cell/Modules/libsnd3.cpp similarity index 71% rename from rpcs3/Emu/SysCalls/Modules/libsnd3.cpp rename to rpcs3/Emu/Cell/Modules/libsnd3.cpp index 74e5f84fbe..861039754d 100644 --- a/rpcs3/Emu/SysCalls/Modules/libsnd3.cpp +++ b/rpcs3/Emu/Cell/Modules/libsnd3.cpp @@ -1,9 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "libsnd3.h" +LOG_CHANNEL(libsnd3); + s32 cellSnd3Init(u32 maxVoice, u32 samples, vm::ptr queue) { UNIMPLEMENTED_FUNC(libsnd3); @@ -290,56 +291,56 @@ s32 cellSnd3SMFGetKeyOnID(u32 smfID, u32 midiChannel, vm::ptr keyOnID) } -Module<> libsnd3("libsnd3", []() +DECLARE(ppu_module_manager::libsnd3)("libsnd3", []() { - REG_SUB(libsnd3,, cellSnd3Init); - REG_SUB(libsnd3,, cellSnd3Exit); - REG_SUB(libsnd3,, cellSnd3Note2Pitch); - REG_SUB(libsnd3,, cellSnd3Pitch2Note); - REG_SUB(libsnd3,, cellSnd3SetOutputMode); - REG_SUB(libsnd3,, cellSnd3Synthesis); - REG_SUB(libsnd3,, cellSnd3SynthesisEx); - REG_SUB(libsnd3,, cellSnd3BindSoundData); - REG_SUB(libsnd3,, cellSnd3UnbindSoundData); - REG_SUB(libsnd3,, cellSnd3NoteOnByTone); - REG_SUB(libsnd3,, cellSnd3KeyOnByTone); - REG_SUB(libsnd3,, cellSnd3VoiceNoteOnByTone); - REG_SUB(libsnd3,, cellSnd3VoiceKeyOnByTone); - REG_SUB(libsnd3,, cellSnd3VoiceSetReserveMode); - REG_SUB(libsnd3,, cellSnd3VoiceSetSustainHold); - REG_SUB(libsnd3,, cellSnd3VoiceKeyOff); - REG_SUB(libsnd3,, cellSnd3VoiceSetPitch); - REG_SUB(libsnd3,, cellSnd3VoiceSetVelocity); - REG_SUB(libsnd3,, cellSnd3VoiceSetPanpot); - REG_SUB(libsnd3,, cellSnd3VoiceSetPanpotEx); - REG_SUB(libsnd3,, cellSnd3VoiceSetPitchBend); - REG_SUB(libsnd3,, cellSnd3VoiceAllKeyOff); - REG_SUB(libsnd3,, cellSnd3VoiceGetEnvelope); - REG_SUB(libsnd3,, cellSnd3VoiceGetStatus); - REG_SUB(libsnd3,, cellSnd3KeyOffByID); - REG_SUB(libsnd3,, cellSnd3GetVoice); - REG_SUB(libsnd3,, cellSnd3GetVoiceByID); - REG_SUB(libsnd3,, cellSnd3NoteOn); - REG_SUB(libsnd3,, cellSnd3NoteOff); - REG_SUB(libsnd3,, cellSnd3SetSustainHold); - REG_SUB(libsnd3,, cellSnd3SetEffectType); - REG_SUB(libsnd3,, cellSnd3SMFBind); - REG_SUB(libsnd3,, cellSnd3SMFUnbind); - REG_SUB(libsnd3,, cellSnd3SMFPlay); - REG_SUB(libsnd3,, cellSnd3SMFPlayEx); - REG_SUB(libsnd3,, cellSnd3SMFPause); - REG_SUB(libsnd3,, cellSnd3SMFResume); - REG_SUB(libsnd3,, cellSnd3SMFStop); - REG_SUB(libsnd3,, cellSnd3SMFAddTempo); - REG_SUB(libsnd3,, cellSnd3SMFGetTempo); - REG_SUB(libsnd3,, cellSnd3SMFSetPlayVelocity); - REG_SUB(libsnd3,, cellSnd3SMFGetPlayVelocity); - REG_SUB(libsnd3,, cellSnd3SMFSetPlayPanpot); - REG_SUB(libsnd3,, cellSnd3SMFSetPlayPanpotEx); - REG_SUB(libsnd3,, cellSnd3SMFGetPlayPanpot); - REG_SUB(libsnd3,, cellSnd3SMFGetPlayPanpotEx); - REG_SUB(libsnd3,, cellSnd3SMFGetPlayStatus); - REG_SUB(libsnd3,, cellSnd3SMFSetPlayChannel); - REG_SUB(libsnd3,, cellSnd3SMFGetPlayChannel); - REG_SUB(libsnd3,, cellSnd3SMFGetKeyOnID); + REG_FUNC(libsnd3, cellSnd3Init); + REG_FUNC(libsnd3, cellSnd3Exit); + REG_FUNC(libsnd3, cellSnd3Note2Pitch); + REG_FUNC(libsnd3, cellSnd3Pitch2Note); + REG_FUNC(libsnd3, cellSnd3SetOutputMode); + REG_FUNC(libsnd3, cellSnd3Synthesis); + REG_FUNC(libsnd3, cellSnd3SynthesisEx); + REG_FUNC(libsnd3, cellSnd3BindSoundData); + REG_FUNC(libsnd3, cellSnd3UnbindSoundData); + REG_FUNC(libsnd3, cellSnd3NoteOnByTone); + REG_FUNC(libsnd3, cellSnd3KeyOnByTone); + REG_FUNC(libsnd3, cellSnd3VoiceNoteOnByTone); + REG_FUNC(libsnd3, cellSnd3VoiceKeyOnByTone); + REG_FUNC(libsnd3, cellSnd3VoiceSetReserveMode); + REG_FUNC(libsnd3, cellSnd3VoiceSetSustainHold); + REG_FUNC(libsnd3, cellSnd3VoiceKeyOff); + REG_FUNC(libsnd3, cellSnd3VoiceSetPitch); + REG_FUNC(libsnd3, cellSnd3VoiceSetVelocity); + REG_FUNC(libsnd3, cellSnd3VoiceSetPanpot); + REG_FUNC(libsnd3, cellSnd3VoiceSetPanpotEx); + REG_FUNC(libsnd3, cellSnd3VoiceSetPitchBend); + REG_FUNC(libsnd3, cellSnd3VoiceAllKeyOff); + REG_FUNC(libsnd3, cellSnd3VoiceGetEnvelope); + REG_FUNC(libsnd3, cellSnd3VoiceGetStatus); + REG_FUNC(libsnd3, cellSnd3KeyOffByID); + REG_FUNC(libsnd3, cellSnd3GetVoice); + REG_FUNC(libsnd3, cellSnd3GetVoiceByID); + REG_FUNC(libsnd3, cellSnd3NoteOn); + REG_FUNC(libsnd3, cellSnd3NoteOff); + REG_FUNC(libsnd3, cellSnd3SetSustainHold); + REG_FUNC(libsnd3, cellSnd3SetEffectType); + REG_FUNC(libsnd3, cellSnd3SMFBind); + REG_FUNC(libsnd3, cellSnd3SMFUnbind); + REG_FUNC(libsnd3, cellSnd3SMFPlay); + REG_FUNC(libsnd3, cellSnd3SMFPlayEx); + REG_FUNC(libsnd3, cellSnd3SMFPause); + REG_FUNC(libsnd3, cellSnd3SMFResume); + REG_FUNC(libsnd3, cellSnd3SMFStop); + REG_FUNC(libsnd3, cellSnd3SMFAddTempo); + REG_FUNC(libsnd3, cellSnd3SMFGetTempo); + REG_FUNC(libsnd3, cellSnd3SMFSetPlayVelocity); + REG_FUNC(libsnd3, cellSnd3SMFGetPlayVelocity); + REG_FUNC(libsnd3, cellSnd3SMFSetPlayPanpot); + REG_FUNC(libsnd3, cellSnd3SMFSetPlayPanpotEx); + REG_FUNC(libsnd3, cellSnd3SMFGetPlayPanpot); + REG_FUNC(libsnd3, cellSnd3SMFGetPlayPanpotEx); + REG_FUNC(libsnd3, cellSnd3SMFGetPlayStatus); + REG_FUNC(libsnd3, cellSnd3SMFSetPlayChannel); + REG_FUNC(libsnd3, cellSnd3SMFGetPlayChannel); + REG_FUNC(libsnd3, cellSnd3SMFGetKeyOnID); }); diff --git a/rpcs3/Emu/SysCalls/Modules/libsnd3.h b/rpcs3/Emu/Cell/Modules/libsnd3.h similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/libsnd3.h rename to rpcs3/Emu/Cell/Modules/libsnd3.h index 978d8b9a77..5afd3024b4 100644 --- a/rpcs3/Emu/SysCalls/Modules/libsnd3.h +++ b/rpcs3/Emu/Cell/Modules/libsnd3.h @@ -51,5 +51,3 @@ struct CellSnd3RequestQueueCtx vm::bptr rearQueue; be_t rearQueueSize; }; - -extern Module<> libsnd3; diff --git a/rpcs3/Emu/SysCalls/Modules/libsynth2.cpp b/rpcs3/Emu/Cell/Modules/libsynth2.cpp similarity index 75% rename from rpcs3/Emu/SysCalls/Modules/libsynth2.cpp rename to rpcs3/Emu/Cell/Modules/libsynth2.cpp index ad341c25c9..532932a2d7 100644 --- a/rpcs3/Emu/SysCalls/Modules/libsynth2.cpp +++ b/rpcs3/Emu/Cell/Modules/libsynth2.cpp @@ -1,9 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "libsynth2.h" +LOG_CHANNEL(libsynth2); + s32 cellSoundSynth2Config(s16 param, s32 value) { libsynth2.todo("cellSoundSynth2Config(param=%d, value=%d)", param, value); @@ -104,23 +105,23 @@ u16 cellSoundSynth2Pitch2Note(u16 center_note, u16 center_fine, u16 pitch) } -Module<> libsynth2("libsynth2", []() +DECLARE(ppu_module_manager::libsynth2)("libsynth2", []() { - REG_SUB(libsynth2,, cellSoundSynth2Config); - REG_SUB(libsynth2,, cellSoundSynth2Init); - REG_SUB(libsynth2,, cellSoundSynth2Exit); - REG_SUB(libsynth2,, cellSoundSynth2SetParam); - REG_SUB(libsynth2,, cellSoundSynth2GetParam); - REG_SUB(libsynth2,, cellSoundSynth2SetSwitch); - REG_SUB(libsynth2,, cellSoundSynth2GetSwitch); - REG_SUB(libsynth2,, cellSoundSynth2SetAddr); - REG_SUB(libsynth2,, cellSoundSynth2GetAddr); - REG_SUB(libsynth2,, cellSoundSynth2SetEffectAttr); - REG_SUB(libsynth2,, cellSoundSynth2SetEffectMode); - REG_SUB(libsynth2,, cellSoundSynth2SetCoreAttr); - REG_SUB(libsynth2,, cellSoundSynth2Generate); - REG_SUB(libsynth2,, cellSoundSynth2VoiceTrans); - REG_SUB(libsynth2,, cellSoundSynth2VoiceTransStatus); - REG_SUB(libsynth2,, cellSoundSynth2Note2Pitch); - REG_SUB(libsynth2,, cellSoundSynth2Pitch2Note); + REG_FUNC(libsynth2, cellSoundSynth2Config); + REG_FUNC(libsynth2, cellSoundSynth2Init); + REG_FUNC(libsynth2, cellSoundSynth2Exit); + REG_FUNC(libsynth2, cellSoundSynth2SetParam); + REG_FUNC(libsynth2, cellSoundSynth2GetParam); + REG_FUNC(libsynth2, cellSoundSynth2SetSwitch); + REG_FUNC(libsynth2, cellSoundSynth2GetSwitch); + REG_FUNC(libsynth2, cellSoundSynth2SetAddr); + REG_FUNC(libsynth2, cellSoundSynth2GetAddr); + REG_FUNC(libsynth2, cellSoundSynth2SetEffectAttr); + REG_FUNC(libsynth2, cellSoundSynth2SetEffectMode); + REG_FUNC(libsynth2, cellSoundSynth2SetCoreAttr); + REG_FUNC(libsynth2, cellSoundSynth2Generate); + REG_FUNC(libsynth2, cellSoundSynth2VoiceTrans); + REG_FUNC(libsynth2, cellSoundSynth2VoiceTransStatus); + REG_FUNC(libsynth2, cellSoundSynth2Note2Pitch); + REG_FUNC(libsynth2, cellSoundSynth2Pitch2Note); }); diff --git a/rpcs3/Emu/SysCalls/Modules/libsynth2.h b/rpcs3/Emu/Cell/Modules/libsynth2.h similarity index 92% rename from rpcs3/Emu/SysCalls/Modules/libsynth2.h rename to rpcs3/Emu/Cell/Modules/libsynth2.h index 6b972ad7cf..cd2ce07f89 100644 --- a/rpcs3/Emu/SysCalls/Modules/libsynth2.h +++ b/rpcs3/Emu/Cell/Modules/libsynth2.h @@ -17,5 +17,3 @@ struct CellSoundSynth2EffectAttr be_t delay; be_t feedback; }; - -extern Module<> libsynth2; diff --git a/rpcs3/Emu/SysCalls/Modules/sceNp.cpp b/rpcs3/Emu/Cell/Modules/sceNp.cpp similarity index 95% rename from rpcs3/Emu/SysCalls/Modules/sceNp.cpp rename to rpcs3/Emu/Cell/Modules/sceNp.cpp index d3204c22f3..80c682eeed 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNp.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNp.cpp @@ -1,16 +1,12 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/SysCalls/lv2/sys_process.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsDir.h" +#include "Emu/Cell/lv2/sys_process.h" #include "Crypto/unedat.h" #include "sceNp.h" -extern Module<> sceNp; +LOG_CHANNEL(sceNp); s32 sceNpInit(u32 poolsize, vm::ptr poolptr) { @@ -42,9 +38,11 @@ s32 sceNpTerm() s32 npDrmIsAvailable(u32 k_licensee_addr, vm::cptr drm_path) { - if (!Emu.GetVFS().ExistsFile(drm_path.get_ptr())) + const std::string& enc_drm_path = drm_path.get_ptr(); + + if (!fs::is_file(vfs::get(enc_drm_path))) { - sceNp.warning("npDrmIsAvailable(): '%s' not found", drm_path.get_ptr()); + sceNp.warning("npDrmIsAvailable(): '%s' not found", enc_drm_path); return CELL_ENOENT; } @@ -60,49 +58,40 @@ s32 npDrmIsAvailable(u32 k_licensee_addr, vm::cptr drm_path) } } - sceNp.warning("npDrmIsAvailable(): Found DRM license file at %s", drm_path.get_ptr()); - sceNp.warning("npDrmIsAvailable(): Using k_licensee 0x%s", k_licensee_str.c_str()); + sceNp.warning("npDrmIsAvailable(): Found DRM license file at %s", enc_drm_path); + sceNp.warning("npDrmIsAvailable(): Using k_licensee 0x%s", k_licensee_str); // Set the necessary file paths. - std::string drm_file_name = fmt::AfterLast(drm_path.get_ptr(), '/'); + const std::string& drm_file_name = enc_drm_path.substr(enc_drm_path.find_last_of('/') + 1); // TODO: Make more explicit what this actually does (currently it copies "XXXXXXXX" from drm_path (== "/dev_hdd0/game/XXXXXXXXX/*" assumed) - std::string titleID(&drm_path[15], 9); + const std::string& drm_file_dir = enc_drm_path.substr(15); + const std::string& title_id = drm_file_dir.substr(0, drm_file_dir.find_first_of('/')); - // TODO: These shouldn't use current dir - std::string enc_drm_path = drm_path.get_ptr(); - std::string dec_drm_path = "/dev_hdd1/cache/" + drm_file_name; - std::string pf_str("00000001"); // TODO: Allow multiple profiles. Use default for now. - std::string rap_path("/dev_hdd0/home/" + pf_str + "/exdata/"); + const std::string& dec_drm_path = "/dev_hdd1/cache/" + drm_file_name; + + std::string rap_lpath = vfs::get("/dev_hdd0/home/00000001/exdata/"); // TODO: Allow multiple profiles. Use default for now. // Search for a compatible RAP file. - for (const auto entry : vfsDir(rap_path)) + for (const auto& entry : fs::dir(rap_lpath)) { - if (entry->name.find(titleID) != std::string::npos) + if (entry.name.find(title_id) != -1) { - rap_path += entry->name; + rap_lpath += entry.name; break; } } - if (rap_path.back() == '/') + if (rap_lpath.back() == '/') { - sceNp.warning("npDrmIsAvailable(): Can't find RAP file for '%s' (titleID='%s')", drm_path.get_ptr(), titleID); - rap_path.clear(); + sceNp.warning("npDrmIsAvailable(): Can't find RAP file for %s", enc_drm_path); + rap_lpath.clear(); } - // Decrypt this EDAT using the supplied k_licensee and matching RAP file. - std::string enc_drm_path_local, dec_drm_path_local, rap_path_local; + const std::string& enc_drm_path_local = vfs::get(enc_drm_path); + const std::string& dec_drm_path_local = vfs::get(dec_drm_path); - Emu.GetVFS().GetDevice(enc_drm_path, enc_drm_path_local); - Emu.GetVFS().GetDevice(dec_drm_path, dec_drm_path_local); - - if (rap_path.size()) - { - Emu.GetVFS().GetDevice(rap_path, rap_path_local); - } - - if (DecryptEDAT(enc_drm_path_local, dec_drm_path_local, 8, rap_path_local, k_licensee, false) >= 0) + if (DecryptEDAT(enc_drm_path_local, dec_drm_path_local, 8, rap_lpath, k_licensee, false) >= 0) { // If decryption succeeds, replace the encrypted file with it. fs::remove_file(enc_drm_path_local); @@ -1526,7 +1515,7 @@ s32 _Z32_sce_np_sysutil_cxml_prepare_docPN16sysutil_cxmlutil11FixedMemoryERN4cxm } -Module<> sceNp("sceNp", []() +DECLARE(ppu_module_manager::sceNp)("sceNp", []() { REG_FUNC(sceNp, sceNpInit); REG_FUNC(sceNp, sceNpTerm); diff --git a/rpcs3/Emu/SysCalls/Modules/sceNp.h b/rpcs3/Emu/Cell/Modules/sceNp.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/sceNp.h rename to rpcs3/Emu/Cell/Modules/sceNp.h diff --git a/rpcs3/Emu/SysCalls/Modules/sceNp2.cpp b/rpcs3/Emu/Cell/Modules/sceNp2.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/sceNp2.cpp rename to rpcs3/Emu/Cell/Modules/sceNp2.cpp index 0c6cf5260b..c424aaf877 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNp2.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNp2.cpp @@ -1,11 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "sceNp.h" #include "sceNp2.h" -extern Module<> sceNp2; +LOG_CHANNEL(sceNp2); s32 sceNp2Init(u32 poolsize, vm::ptr poolptr) { @@ -384,7 +383,7 @@ s32 sceNpMatching2RegisterRoomMessageCallback() } -Module<> sceNp2("sceNp2", []() +DECLARE(ppu_module_manager::sceNp2)("sceNp2", []() { REG_FUNC(sceNp2, sceNpMatching2DestroyContext); REG_FUNC(sceNp2, sceNpMatching2LeaveLobby); diff --git a/rpcs3/Emu/SysCalls/Modules/sceNp2.h b/rpcs3/Emu/Cell/Modules/sceNp2.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/sceNp2.h rename to rpcs3/Emu/Cell/Modules/sceNp2.h diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpClans.cpp b/rpcs3/Emu/Cell/Modules/sceNpClans.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/sceNpClans.cpp rename to rpcs3/Emu/Cell/Modules/sceNpClans.cpp index 2bf714ad12..e3d7daca27 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNpClans.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpClans.cpp @@ -1,12 +1,11 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "sceNp.h" #include "sceNpClans.h" -extern Module<> sceNpClans; +LOG_CHANNEL(sceNpClans); s32 sceNpClansInit(vm::ptr commId, vm::ptr passphrase, vm::ptr pool, vm::ptr poolSize, u32 flags) { @@ -255,7 +254,7 @@ s32 sceNpClansRemoveChallenge() return CELL_OK; } -Module<> sceNpClans("sceNpClans", []() +DECLARE(ppu_module_manager::sceNpClans)("sceNpClans", []() { REG_FUNC(sceNpClans, sceNpClansInit); REG_FUNC(sceNpClans, sceNpClansTerm); diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpClans.h b/rpcs3/Emu/Cell/Modules/sceNpClans.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/sceNpClans.h rename to rpcs3/Emu/Cell/Modules/sceNpClans.h diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpCommerce2.cpp b/rpcs3/Emu/Cell/Modules/sceNpCommerce2.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/sceNpCommerce2.cpp rename to rpcs3/Emu/Cell/Modules/sceNpCommerce2.cpp index c1bdbf23d9..ba8f47ce7e 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNpCommerce2.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpCommerce2.cpp @@ -1,10 +1,9 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "sceNpCommerce2.h" -extern Module<> sceNpCommerce2; +LOG_CHANNEL(sceNpCommerce2); s32 sceNpCommerce2ExecuteStoreBrowse() { @@ -315,7 +314,7 @@ s32 sceNpCommerce2DoServiceListFinishAsync() throw EXCEPTION(""); } -Module<> sceNpCommerce2("sceNpCommerce2", []() +DECLARE(ppu_module_manager::sceNpCommerce2)("sceNpCommerce2", []() { REG_FUNC(sceNpCommerce2, sceNpCommerce2ExecuteStoreBrowse); REG_FUNC(sceNpCommerce2, sceNpCommerce2GetStoreBrowseUserdata); diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpCommerce2.h b/rpcs3/Emu/Cell/Modules/sceNpCommerce2.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/sceNpCommerce2.h rename to rpcs3/Emu/Cell/Modules/sceNpCommerce2.h diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpSns.cpp b/rpcs3/Emu/Cell/Modules/sceNpSns.cpp similarity index 92% rename from rpcs3/Emu/SysCalls/Modules/sceNpSns.cpp rename to rpcs3/Emu/Cell/Modules/sceNpSns.cpp index 26b61aed15..15dc2c7153 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNpSns.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpSns.cpp @@ -1,9 +1,9 @@ #include "stdafx.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "sceNpSns.h" -extern Module<> sceNpSns; +LOG_CHANNEL(sceNpSns); s32 sceNpSnsFbInit(vm::ptr params) { @@ -66,7 +66,7 @@ s32 sceNpSnsFbLoadThrottle() } -Module<> sceNpSns("sceNpSns", []() +DECLARE(ppu_module_manager::sceNpSns)("sceNpSns", []() { REG_FUNC(sceNpSns, sceNpSnsFbInit); REG_FUNC(sceNpSns, sceNpSnsFbTerm); diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpSns.h b/rpcs3/Emu/Cell/Modules/sceNpSns.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/sceNpSns.h rename to rpcs3/Emu/Cell/Modules/sceNpSns.h diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpTrophy.cpp b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp similarity index 92% rename from rpcs3/Emu/SysCalls/Modules/sceNpTrophy.cpp rename to rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp index 98756e976c..a0848e2621 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNpTrophy.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp @@ -1,33 +1,29 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/IdManager.h" #include "Emu/System.h" -#include "Emu/state.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" #include "Utilities/rXml.h" #include "Loader/TRP.h" #include "Loader/TROPUSR.h" -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsDir.h" -#include "Emu/FS/vfsFileBase.h" + #include "sceNp.h" #include "sceNpTrophy.h" -extern Module<> sceNpTrophy; +LOG_CHANNEL(sceNpTrophy); struct trophy_context_t { - const u32 id = idm::get_last_id(); + const u32 id{}; std::string trp_name; - std::unique_ptr trp_stream; + fs::file trp_stream; std::unique_ptr tropusr; }; struct trophy_handle_t { - const u32 id = idm::get_last_id(); + const u32 id{}; }; // Functions @@ -103,10 +99,10 @@ s32 sceNpTrophyCreateContext(vm::ptr context, vm::cptrdata, commId->num); // open trophy pack file - std::unique_ptr stream(Emu.GetVFS().OpenFile("/app_home/../TROPDIR/" + name + "/TROPHY.TRP", fom::read)); + fs::file stream(vfs::get("/app_home/../TROPDIR/" + name + "/TROPHY.TRP")); // check if exists and opened - if (!stream || !stream->IsOpened()) + if (!stream) { return SCE_NP_TROPHY_ERROR_CONF_DOES_NOT_EXIST; } @@ -158,7 +154,7 @@ s32 sceNpTrophyRegisterContext(PPUThread& CPU, u32 context, u32 handle, vm::ptr< return SCE_NP_TROPHY_ERROR_UNKNOWN_HANDLE; } - TRPLoader trp(*ctxt->trp_stream); + TRPLoader trp(ctxt->trp_stream); if (!trp.LoadHeader()) { sceNpTrophy.error("sceNpTrophyRegisterContext(): SCE_NP_TROPHY_ERROR_ILLEGAL_UPDATE"); @@ -169,7 +165,7 @@ s32 sceNpTrophyRegisterContext(PPUThread& CPU, u32 context, u32 handle, vm::ptr< const size_t kTargetBufferLength = 31; char target[kTargetBufferLength + 1]; target[kTargetBufferLength] = 0; - strcpy_trunc(target, fmt::format("TROP_%02d.SFM", rpcs3::config.system.language.value())); + strcpy_trunc(target, fmt::format("TROP_%02d.SFM", /*rpcs3::config.system.language.value()*/0)); if (trp.ContainsEntry(target)) { @@ -191,7 +187,7 @@ s32 sceNpTrophyRegisterContext(PPUThread& CPU, u32 context, u32 handle, vm::ptr< for (s32 i = 0; i <= 18; i++) { strcpy_trunc(target, fmt::format("TROP_%02d.SFM", i)); - if (i != rpcs3::config.system.language.value()) + if (i != /*rpcs3::config.system.language.value()*/0) { trp.RemoveEntry(target); } @@ -237,7 +233,7 @@ s32 sceNpTrophyGetRequiredDiskSpace(u32 context, u32 handle, vm::ptr reqspa } // TODO: This is not accurate. It's just an approximation of the real value - *reqspace = ctxt->trp_stream->GetSize(); + *reqspace = ctxt->trp_stream.size(); return CELL_OK; } @@ -267,9 +263,12 @@ s32 sceNpTrophyGetGameInfo(u32 context, u32 handle, vm::ptrtrp_name + "/TROPCONF.SFM"); + + // TODO: rXmlDocument can open only real file + ASSERT(!fs::get_virtual_device(path)); rXmlDocument doc; - Emu.GetVFS().GetDevice("/dev_hdd0/home/00000001/trophy/" + ctxt->trp_name + "/TROPCONF.SFM", path); // TODO: Get the path of the current user doc.Load(path); std::string titleName; @@ -394,9 +393,12 @@ s32 sceNpTrophyGetTrophyInfo(u32 context, u32 handle, s32 trophyId, vm::ptrtrp_name + "/TROPCONF.SFM", path); // TODO: Get the path of the current user + // TODO: Get the path of the current user + const std::string& path = vfs::get("/dev_hdd0/home/00000001/trophy/" + ctxt->trp_name + "/TROPCONF.SFM"); + + // TODO: rXmlDocument can open only real file + ASSERT(!fs::get_virtual_device(path)); + rXmlDocument doc; doc.Load(path); std::string name; @@ -455,7 +457,7 @@ s32 sceNpTrophyGetTrophyIcon(u32 context, u32 handle, s32 trophyId, vm::ptr sceNpTrophy("sceNpTrophy", []() +DECLARE(ppu_module_manager::sceNpTrophy)("sceNpTrophy", []() { REG_FUNC(sceNpTrophy, sceNpTrophyGetGameProgress); REG_FUNC(sceNpTrophy, sceNpTrophyRegisterContext); diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpTrophy.h b/rpcs3/Emu/Cell/Modules/sceNpTrophy.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/sceNpTrophy.h rename to rpcs3/Emu/Cell/Modules/sceNpTrophy.h diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpTus.cpp b/rpcs3/Emu/Cell/Modules/sceNpTus.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/sceNpTus.cpp rename to rpcs3/Emu/Cell/Modules/sceNpTus.cpp index 4eb33b0cee..1ee55bf9f6 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNpTus.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpTus.cpp @@ -1,11 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "sceNp.h" #include "sceNpTus.h" -extern Module<> sceNpTus; +LOG_CHANNEL(sceNpTus); s32 sceNpTusInit() { @@ -333,7 +332,7 @@ s32 sceNpTusDeleteMultiSlotDataVUserAsync() return CELL_OK; } -Module<> sceNpTus("sceNpTus", []() +DECLARE(ppu_module_manager::sceNpTus)("sceNpTus", []() { REG_FUNC(sceNpTus, sceNpTusInit); REG_FUNC(sceNpTus, sceNpTusTerm); diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpTus.h b/rpcs3/Emu/Cell/Modules/sceNpTus.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/sceNpTus.h rename to rpcs3/Emu/Cell/Modules/sceNpTus.h diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpUtil.cpp b/rpcs3/Emu/Cell/Modules/sceNpUtil.cpp similarity index 83% rename from rpcs3/Emu/SysCalls/Modules/sceNpUtil.cpp rename to rpcs3/Emu/Cell/Modules/sceNpUtil.cpp index a0ad31b011..0dc924f80a 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNpUtil.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpUtil.cpp @@ -1,11 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "sceNp.h" #include "sceNpUtil.h" -extern Module<> sceNpUtil; +LOG_CHANNEL(sceNpUtil); s32 sceNpUtilBandwidthTestInitStart(u32 prio, size_t stack) { @@ -31,7 +30,7 @@ s32 sceNpUtilBandwidthTestAbort() return CELL_OK; } -Module<> sceNpUtil("sceNpUtil", []() +DECLARE(ppu_module_manager::sceNpUtil)("sceNpUtil", []() { REG_FUNC(sceNpUtil, sceNpUtilBandwidthTestInitStart); REG_FUNC(sceNpUtil, sceNpUtilBandwidthTestShutdown); diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpUtil.h b/rpcs3/Emu/Cell/Modules/sceNpUtil.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/sceNpUtil.h rename to rpcs3/Emu/Cell/Modules/sceNpUtil.h diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp similarity index 51% rename from rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp rename to rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp index ca24e0bd8a..7140e8b37e 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/Cell/Modules/sysPrxForUser.cpp @@ -1,80 +1,84 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/SysCalls/lv2/sys_interrupt.h" -#include "Emu/SysCalls/lv2/sys_process.h" +#include "Emu/Cell/lv2/sys_interrupt.h" +#include "Emu/Cell/lv2/sys_process.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +LOG_CHANNEL(sysPrxForUser); extern u64 get_system_time(); -#define TLS_MAX 128 +vm::gvar sys_prx_version; // ??? + #define TLS_SYS 0x30 -u32 g_tls_start; // start of TLS memory area -u32 g_tls_size; +u32 g_tls_size = 0; // Size of TLS area per thread +u32 g_tls_addr = 0; // Start of TLS memory area +u32 g_tls_max = 0; // Max number of threads -std::array, TLS_MAX> g_tls_owners; +std::unique_ptr[]> g_tls_map; // I'd like to make it std::vector but it won't work -void sys_initialize_tls() +u32 ppu_alloc_tls() { - sysPrxForUser.trace("sys_initialize_tls()"); -} - -u32 ppu_get_tls(u32 thread) -{ - if (!g_tls_start) + for (u32 i = 0; i < g_tls_max; i++) { - g_tls_size = Emu.GetTLSMemsz() + TLS_SYS; - g_tls_start = vm::alloc(g_tls_size * TLS_MAX, vm::main); // memory for up to TLS_MAX threads - LOG_NOTICE(MEMORY, "Thread Local Storage initialized (g_tls_start=0x%x, user_size=0x%x)\n*** TLS segment addr: 0x%08x\n*** TLS segment size: 0x%08x", - g_tls_start, Emu.GetTLSMemsz(), Emu.GetTLSAddr(), Emu.GetTLSFilesz()); - } - - if (!thread) - { - return 0; - } - - for (u32 i = 0; i < TLS_MAX; i++) - { - if (g_tls_owners[i] == thread) + if (g_tls_map[i].exchange(true) == false) { - return g_tls_start + i * g_tls_size + TLS_SYS; // if already initialized, return TLS address - } - } - - for (u32 i = 0; i < TLS_MAX; i++) - { - u32 old = 0; - if (g_tls_owners[i].compare_exchange_strong(old, thread)) - { - const u32 addr = g_tls_start + i * g_tls_size + TLS_SYS; // get TLS address - std::memset(vm::base(addr - TLS_SYS), 0, TLS_SYS); // initialize system area with zeros - std::memcpy(vm::base(addr), vm::base(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // initialize from TLS image - std::memset(vm::base(addr + Emu.GetTLSFilesz()), 0, Emu.GetTLSMemsz() - Emu.GetTLSFilesz()); // fill the rest with zeros + const u32 addr = g_tls_addr + i * g_tls_size; // Calculate TLS address + std::memset(vm::base(addr), 0, TLS_SYS); // Clear system area (TODO) + std::memcpy(vm::base(addr + TLS_SYS), vm::base(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // Copy TLS image + std::memset(vm::base(addr + TLS_SYS + Emu.GetTLSFilesz()), 0, Emu.GetTLSMemsz() - Emu.GetTLSFilesz()); // Clear the rest return addr; } } - throw EXCEPTION("Out of TLS memory"); + sysPrxForUser.error("ppu_alloc_tls(): out of TLS memory (max=%zu)", g_tls_max); + return 0; } -void ppu_free_tls(u32 thread) +void ppu_free_tls(u32 addr) { - for (auto& v : g_tls_owners) + // Calculate TLS position + const u32 i = (addr - g_tls_addr) / g_tls_size; + + if (addr < g_tls_addr || i >= g_tls_max || (addr - g_tls_addr) % g_tls_size) { - u32 old = thread; - if (v.compare_exchange_strong(old, 0)) - { - return; - } + sysPrxForUser.error("ppu_free_tls(0x%x): invalid address", addr); + return; } - LOG_ERROR(MEMORY, "TLS deallocation failed (thread=0x%x)", thread); + if (g_tls_map[i].exchange(false) == false) + { + sysPrxForUser.error("ppu_free_tls(0x%x): deallocation failed", addr); + return; + } +} + +void sys_initialize_tls(PPUThread& ppu, u64 main_thread_id, u32 tls_seg_addr, u32 tls_seg_size, u32 tls_mem_size) +{ + sysPrxForUser.notice("sys_initialize_tls(thread_id=0x%llx, addr=*0x%x, size=0x%x, mem_size=0x%x)", main_thread_id, tls_seg_addr, tls_seg_size, tls_mem_size); + + // Uninitialized TLS expected. + if (ppu.GPR[13] != 0) return; + + // Initialize TLS memory + g_tls_size = Emu.GetTLSMemsz() + TLS_SYS; + g_tls_addr = vm::alloc(0x20000, vm::main) + 0x30; + g_tls_max = (0xffd0 / g_tls_size) + (0x10000 / g_tls_size); + g_tls_map = std::make_unique[]>(g_tls_max); + + // Allocate TLS for main thread + ppu.GPR[13] = ppu_alloc_tls() + 0x7000 + TLS_SYS; + + sysPrxForUser.notice("TLS initialized (addr=0x%x, size=0x%x, max=0x%zu)", g_tls_addr - 0x30, g_tls_size, g_tls_max); + + // TODO + g_spu_printf_agcb = vm::null; + g_spu_printf_dgcb = vm::null; + g_spu_printf_atcb = vm::null; + g_spu_printf_dtcb = vm::null; } s64 sys_time_get_system_time() @@ -86,21 +90,32 @@ s64 sys_time_get_system_time() s64 _sys_process_atexitspawn() { - sysPrxForUser.trace("_sys_process_atexitspawn()"); + sysPrxForUser.todo("_sys_process_atexitspawn()"); return CELL_OK; } s64 _sys_process_at_Exitspawn() { - sysPrxForUser.trace("_sys_process_at_Exitspawn"); + sysPrxForUser.todo("_sys_process_at_Exitspawn"); return CELL_OK; } s32 sys_interrupt_thread_disestablish(PPUThread& ppu, u32 ih) { - sysPrxForUser.todo("sys_interrupt_thread_disestablish(ih=0x%x)", ih); + sysPrxForUser.notice("sys_interrupt_thread_disestablish(ih=0x%x)", ih); - return _sys_interrupt_thread_disestablish(ppu, ih, vm::var{}); + vm::var r13; + + // Call the syscall + if (s32 res = _sys_interrupt_thread_disestablish(ppu, ih, r13)) + { + return res; + } + + // Deallocate TLS + ppu_free_tls(vm::cast(*r13, HERE) - 0x7030); + + return CELL_OK; } s32 sys_process_is_stack(u32 p) @@ -166,20 +181,8 @@ extern void sysPrxForUser_sys_spu_init(); extern void sysPrxForUser_sys_game_init(); extern void sysPrxForUser_sys_libc_init(); -Module<> sysPrxForUser("sysPrxForUser", []() +DECLARE(ppu_module_manager::sysPrxForUser)("sysPrxForUser", []() { - g_tls_start = 0; - - for (auto& v : g_tls_owners) - { - v = 0; - } - - // Setup random number generator - srand(time(NULL)); - - //REG_VARIABLE(sysPrxForUser, sys_prx_version); // 0x7df066cf - sysPrxForUser_sys_lwmutex_init(); sysPrxForUser_sys_lwcond_init(); sysPrxForUser_sys_ppu_thread_init(); @@ -192,6 +195,8 @@ Module<> sysPrxForUser("sysPrxForUser", []() sysPrxForUser_sys_game_init(); sysPrxForUser_sys_libc_init(); + REG_VAR(sysPrxForUser, sys_prx_version); // 0x7df066cf + REG_FUNC(sysPrxForUser, sys_initialize_tls); REG_FUNC(sysPrxForUser, sys_time_get_system_time); diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h b/rpcs3/Emu/Cell/Modules/sysPrxForUser.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h rename to rpcs3/Emu/Cell/Modules/sysPrxForUser.h diff --git a/rpcs3/Emu/SysCalls/Modules/sys_game.cpp b/rpcs3/Emu/Cell/Modules/sys_game.cpp similarity index 91% rename from rpcs3/Emu/SysCalls/Modules/sys_game.cpp rename to rpcs3/Emu/Cell/Modules/sys_game.cpp index 413cd98b5c..1c2d47b368 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_game.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_game.cpp @@ -1,12 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/FS/VFS.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +extern _log::channel sysPrxForUser; void sys_game_process_exitspawn(vm::cptr path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags) { @@ -70,18 +68,11 @@ void sys_game_process_exitspawn(vm::cptr path, u32 argv_addr, u32 envp_add Emu.Pause(); sysPrxForUser.success("Process finished"); - Emu.CallAfter([=]() + Emu.CallAfter([=, path = vfs::get(_path)]() { Emu.Stop(); - - std::string real_path; - - Emu.GetVFS().GetDevice(_path.c_str(), real_path); - - Emu.BootGame(real_path, true); + Emu.BootGame(path, true); }); - - return; } void sys_game_process_exitspawn2(vm::cptr path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags) @@ -146,15 +137,10 @@ void sys_game_process_exitspawn2(vm::cptr path, u32 argv_addr, u32 envp_ad Emu.Pause(); sysPrxForUser.success("Process finished"); - Emu.CallAfter([=]() + Emu.CallAfter([=, path = vfs::get(_path)]() { Emu.Stop(); - - std::string real_path; - - Emu.GetVFS().GetDevice(_path.c_str(), real_path); - - Emu.BootGame(real_path, true); + Emu.BootGame(path, true); }); return; diff --git a/rpcs3/Emu/SysCalls/Modules/sys_heap.cpp b/rpcs3/Emu/Cell/Modules/sys_heap.cpp similarity index 95% rename from rpcs3/Emu/SysCalls/Modules/sys_heap.cpp rename to rpcs3/Emu/Cell/Modules/sys_heap.cpp index cec953fdf1..13b344fd2f 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_heap.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_heap.cpp @@ -1,12 +1,11 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/IdManager.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +extern _log::channel sysPrxForUser; struct HeapInfo { diff --git a/rpcs3/Emu/SysCalls/Modules/sys_io.cpp b/rpcs3/Emu/Cell/Modules/sys_io.cpp similarity index 88% rename from rpcs3/Emu/SysCalls/Modules/sys_io.cpp rename to rpcs3/Emu/Cell/Modules/sys_io.cpp index eb7888f151..11d2202e5d 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_io.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_io.cpp @@ -1,7 +1,7 @@ #include "stdafx.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> sys_io; +LOG_CHANNEL(sys_io); extern void cellPad_init(); extern void cellKb_init(); @@ -39,7 +39,7 @@ s32 sys_config_unregister_service() } -Module<> sys_io("sys_io", []() +DECLARE(ppu_module_manager::sys_io)("sys_io", []() { cellPad_init(); cellKb_init(); diff --git a/rpcs3/Emu/Cell/Modules/sys_libc.cpp b/rpcs3/Emu/Cell/Modules/sys_libc.cpp new file mode 100644 index 0000000000..74fabd32b0 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/sys_libc.cpp @@ -0,0 +1,24 @@ +#include "stdafx.h" +#include "Emu/System.h" +#include "Emu/Cell/PPUModule.h" +#include "Emu/Cell/PPUOpcodes.h" + +LOG_CHANNEL(sys_libc); + +namespace sys_libc_func +{ + void memcpy(vm::ptr dst, vm::cptr src, u32 size) + { + sys_libc.trace("memcpy(dst=*0x%x, src=*0x%x, size=0x%x)", dst, src, size); + + ::memcpy(dst.get_ptr(), src.get_ptr(), size); + } +} + +// Define macro for namespace +#define REG_FUNC_(name) REG_FNID(sys_libc, ppu_generate_id(#name), sys_libc_func::name) + +DECLARE(ppu_module_manager::sys_libc)("sys_libc", []() +{ + REG_FUNC_(memcpy); +}); diff --git a/rpcs3/Emu/SysCalls/Modules/sys_libc.cpp b/rpcs3/Emu/Cell/Modules/sys_libc_.cpp similarity index 83% rename from rpcs3/Emu/SysCalls/Modules/sys_libc.cpp rename to rpcs3/Emu/Cell/Modules/sys_libc_.cpp index 0045cdf423..61f91faee2 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_libc.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_libc_.cpp @@ -1,12 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/Cell/PPUInstrTable.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> sys_libc; +extern _log::channel sysPrxForUser; -std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count, u32 f_count, u32 v_count) +// TODO +static std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count) { std::string result; @@ -33,7 +31,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count, u32 f_c if (*fmt == '*') { fmt++; - return context.get_next_gpr_arg(g_count, f_count, v_count); + return context.get_next_arg(g_count); } while (*fmt - '0' < 10) @@ -57,7 +55,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count, u32 f_c if (*++fmt == '*') { fmt++; - return context.get_next_gpr_arg(g_count, f_count, v_count); + return context.get_next_arg(g_count); } while (*fmt - '0' < 10) @@ -81,7 +79,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count, u32 f_c case 'i': { // signed decimal - const s64 value = context.get_next_gpr_arg(g_count, f_count, v_count); + const s64 value = context.get_next_arg(g_count); if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break; @@ -92,7 +90,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count, u32 f_c case 'X': { // hexadecimal - const u64 value = context.get_next_gpr_arg(g_count, f_count, v_count); + const u64 value = context.get_next_arg(g_count); if (plus_sign || minus_sign || space_sign || prec) break; @@ -101,7 +99,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count, u32 f_c result += cf == 'x' ? "0x" : "0X"; } - const std::string& hex = cf == 'x' ? fmt::to_hex(value) : fmt::toupper(fmt::to_hex(value)); + const std::string& hex = cf == 'x' ? fmt::to_hex(value) : fmt::to_upper(fmt::to_hex(value)); if (hex.length() >= width) { @@ -120,7 +118,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count, u32 f_c case 's': { // string - auto string = vm::cptr::make(context.get_next_gpr_arg(g_count, f_count, v_count)); + auto string = vm::cptr::make(context.get_next_arg(g_count)); if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break; @@ -130,7 +128,7 @@ std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count, u32 f_c case 'u': { // unsigned decimal - const u64 value = context.get_next_gpr_arg(g_count, f_count, v_count); + const u64 value = context.get_next_arg(g_count); if (plus_sign || minus_sign || space_sign || number_sign || zero_padding || width || prec) break; @@ -149,18 +147,6 @@ std::string ps3_fmt(PPUThread& context, vm::cptr fmt, u32 g_count, u32 f_c return result; } -namespace sys_libc_func -{ - void memcpy(vm::ptr dst, vm::cptr src, u32 size) - { - sys_libc.trace("memcpy(dst=*0x%x, src=*0x%x, size=0x%x)", dst, src, size); - - ::memcpy(dst.get_ptr(), src.get_ptr(), size); - } -} - -extern Module<> sysPrxForUser; - vm::ptr _sys_memset(vm::ptr dst, s32 value, u32 size) { sysPrxForUser.trace("_sys_memset(dst=*0x%x, value=%d, size=0x%x)", dst, value, size); @@ -328,7 +314,7 @@ s32 _sys_snprintf(PPUThread& ppu, vm::ptr dst, u32 count, vm::cptr f { sysPrxForUser.warning("_sys_snprintf(dst=*0x%x, count=%d, fmt=*0x%x, ...)", dst, count, fmt); - std::string result = ps3_fmt(ppu, fmt, va_args.g_count, va_args.f_count, va_args.v_count); + std::string result = ps3_fmt(ppu, fmt, va_args.count); sysPrxForUser.warning("*** '%s' -> '%s'", fmt.get_ptr(), result); @@ -350,7 +336,7 @@ s32 _sys_printf(PPUThread& ppu, vm::cptr fmt, ppu_va_args_t va_args) { sysPrxForUser.warning("_sys_printf(fmt=*0x%x, ...)", fmt); - _log::g_tty_file.log(ps3_fmt(ppu, fmt, va_args.g_count, va_args.f_count, va_args.v_count)); + _log::g_tty_file.log(ps3_fmt(ppu, fmt, va_args.count)); return CELL_OK; } @@ -414,19 +400,3 @@ void sysPrxForUser_sys_libc_init() REG_FUNC(sysPrxForUser, _sys_qsort); } - -Module<> sys_libc("sys_libc", []() -{ - using namespace PPU_instr; - - REG_SUB(sys_libc, sys_libc_func, memcpy, - SP_I(CMPLDI(cr7, r5, 7)), - SP_I(CLRLDI(r3, r3, 32)), - SP_I(CLRLDI(r4, r4, 32)), - SP_I(MR(r11, r3)), - SP_I(BGT(cr7, XXX & 0xff)), - SP_I(CMPDI(r5, 0)), - OPT_SP_I(MR(r9, r3)), - { SPET_MASKED_OPCODE, 0x4d820020, 0xffffffff }, - ); -}); diff --git a/rpcs3/Emu/SysCalls/Modules/sys_lv2dbg.cpp b/rpcs3/Emu/Cell/Modules/sys_lv2dbg.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/sys_lv2dbg.cpp rename to rpcs3/Emu/Cell/Modules/sys_lv2dbg.cpp index c2c0fbf4bf..791e29ceed 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_lv2dbg.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_lv2dbg.cpp @@ -1,12 +1,11 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "sys_lv2dbg.h" -extern Module<> sys_lv2dbg; +LOG_CHANNEL(sys_lv2dbg); s32 sys_dbg_read_ppu_thread_context(u64 id, vm::ptr ppu_context) { @@ -190,7 +189,7 @@ s32 sys_dbg_set_mask_to_ppu_exception_handler(u64 mask, u64 flags) throw EXCEPTION(""); } -Module<> sys_lv2dbg("sys_lv2dbg", [] +DECLARE(ppu_module_manager::sys_lv2dbg)("sys_lv2dbg", [] { REG_FUNC(sys_lv2dbg, sys_dbg_read_ppu_thread_context); REG_FUNC(sys_lv2dbg, sys_dbg_read_spu_thread_context); diff --git a/rpcs3/Emu/SysCalls/Modules/sys_lv2dbg.h b/rpcs3/Emu/Cell/Modules/sys_lv2dbg.h similarity index 95% rename from rpcs3/Emu/SysCalls/Modules/sys_lv2dbg.h rename to rpcs3/Emu/Cell/Modules/sys_lv2dbg.h index 5661690945..e9a30c19fd 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_lv2dbg.h +++ b/rpcs3/Emu/Cell/Modules/sys_lv2dbg.h @@ -1,13 +1,13 @@ #pragma once -#include "Emu/SysCalls/lv2/sys_mutex.h" -#include "Emu/SysCalls/lv2/sys_cond.h" -#include "Emu/SysCalls/lv2/sys_rwlock.h" -#include "Emu/SysCalls/lv2/sys_event.h" -#include "Emu/SysCalls/lv2/sys_semaphore.h" -#include "Emu/SysCalls/lv2/sys_lwmutex.h" -#include "Emu/SysCalls/lv2/sys_lwcond.h" -#include "Emu/SysCalls/lv2/sys_event_flag.h" +#include "Emu/Cell/lv2/sys_mutex.h" +#include "Emu/Cell/lv2/sys_cond.h" +#include "Emu/Cell/lv2/sys_rwlock.h" +#include "Emu/Cell/lv2/sys_event.h" +#include "Emu/Cell/lv2/sys_semaphore.h" +#include "Emu/Cell/lv2/sys_lwmutex.h" +#include "Emu/Cell/lv2/sys_lwcond.h" +#include "Emu/Cell/lv2/sys_event_flag.h" namespace vm { using namespace ps3; } diff --git a/rpcs3/Emu/SysCalls/Modules/sys_lwcond_.cpp b/rpcs3/Emu/Cell/Modules/sys_lwcond_.cpp similarity index 94% rename from rpcs3/Emu/SysCalls/Modules/sys_lwcond_.cpp rename to rpcs3/Emu/Cell/Modules/sys_lwcond_.cpp index 8f6577dec7..d3bf78062c 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_lwcond_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_lwcond_.cpp @@ -1,15 +1,13 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/IdManager.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/SysCalls/lv2/sys_sync.h" -#include "Emu/SysCalls/lv2/sys_lwmutex.h" -#include "Emu/SysCalls/lv2/sys_lwcond.h" +#include "Emu/Cell/lv2/sys_lwmutex.h" +#include "Emu/Cell/lv2/sys_lwcond.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +extern _log::channel sysPrxForUser; s32 sys_lwcond_create(vm::ptr lwcond, vm::ptr lwmutex, vm::ptr attr) { @@ -47,7 +45,7 @@ s32 sys_lwcond_signal(PPUThread& ppu, vm::ptr lwcond) //return _sys_lwcond_signal(lwcond->lwcond_queue, 0, -1, 2); } - if (lwmutex->vars.owner.load() == ppu.get_id()) + if (lwmutex->vars.owner.load() == ppu.id) { // if owns the mutex lwmutex->all_info++; @@ -105,7 +103,7 @@ s32 sys_lwcond_signal_all(PPUThread& ppu, vm::ptr lwcond) //return _sys_lwcond_signal_all(lwcond->lwcond_queue, lwmutex->sleep_queue, 2); } - if (lwmutex->vars.owner.load() == ppu.get_id()) + if (lwmutex->vars.owner.load() == ppu.id) { // if owns the mutex, call the syscall const s32 res = _sys_lwcond_signal_all(lwcond->lwcond_queue, lwmutex->sleep_queue, 1); @@ -162,7 +160,7 @@ s32 sys_lwcond_signal_to(PPUThread& ppu, vm::ptr lwcond, u32 ppu_t //return _sys_lwcond_signal(lwcond->lwcond_queue, 0, ppu_thread_id, 2); } - if (lwmutex->vars.owner.load() == ppu.get_id()) + if (lwmutex->vars.owner.load() == ppu.id) { // if owns the mutex lwmutex->all_info++; @@ -212,7 +210,7 @@ s32 sys_lwcond_wait(PPUThread& ppu, vm::ptr lwcond, u64 timeout) { sysPrxForUser.trace("sys_lwcond_wait(lwcond=*0x%x, timeout=0x%llx)", lwcond, timeout); - const be_t tid = ppu.get_id(); + const be_t tid = ppu.id; const vm::ptr lwmutex = lwcond->lwmutex; diff --git a/rpcs3/Emu/SysCalls/Modules/sys_lwmutex_.cpp b/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp similarity index 94% rename from rpcs3/Emu/SysCalls/Modules/sys_lwmutex_.cpp rename to rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp index 347c180077..7e2e9fad4c 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_lwmutex_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp @@ -2,13 +2,12 @@ #include "Emu/Memory/Memory.h" #include "Emu/IdManager.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/SysCalls/lv2/sys_sync.h" -#include "Emu/SysCalls/lv2/sys_lwmutex.h" +#include "Emu/Cell/lv2/sys_lwmutex.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +extern _log::channel sysPrxForUser; s32 sys_lwmutex_create(vm::ptr lwmutex, vm::ptr attr) { @@ -45,7 +44,7 @@ s32 sys_lwmutex_destroy(PPUThread& ppu, vm::ptr lwmutex) sysPrxForUser.trace("sys_lwmutex_destroy(lwmutex=*0x%x)", lwmutex); // check to prevent recursive locking in the next call - if (lwmutex->vars.owner.load() == ppu.get_id()) + if (lwmutex->vars.owner.load() == ppu.id) { return CELL_EBUSY; } @@ -75,7 +74,7 @@ s32 sys_lwmutex_lock(PPUThread& ppu, vm::ptr lwmutex, u64 timeout { sysPrxForUser.trace("sys_lwmutex_lock(lwmutex=*0x%x, timeout=0x%llx)", lwmutex, timeout); - const be_t tid = ppu.get_id(); + const be_t tid = ppu.id; // try to lock lightweight mutex const be_t old_owner = lwmutex->vars.owner.compare_and_swap(lwmutex_free, tid); @@ -169,7 +168,7 @@ s32 sys_lwmutex_trylock(PPUThread& ppu, vm::ptr lwmutex) { sysPrxForUser.trace("sys_lwmutex_trylock(lwmutex=*0x%x)", lwmutex); - const be_t tid = ppu.get_id(); + const be_t tid = ppu.id; // try to lock lightweight mutex const be_t old_owner = lwmutex->vars.owner.compare_and_swap(lwmutex_free, tid); @@ -236,7 +235,7 @@ s32 sys_lwmutex_unlock(PPUThread& ppu, vm::ptr lwmutex) { sysPrxForUser.trace("sys_lwmutex_unlock(lwmutex=*0x%x)", lwmutex); - const be_t tid = ppu.get_id(); + const be_t tid = ppu.id; // check owner if (lwmutex->vars.owner.load() != tid) diff --git a/rpcs3/Emu/SysCalls/Modules/sys_mempool.cpp b/rpcs3/Emu/Cell/Modules/sys_mempool.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/sys_mempool.cpp rename to rpcs3/Emu/Cell/Modules/sys_mempool.cpp index 60851eacb8..99763b4b1f 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_mempool.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_mempool.cpp @@ -1,12 +1,11 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +extern _log::channel sysPrxForUser; using sys_mempool_t = u32; diff --git a/rpcs3/Emu/SysCalls/Modules/sys_mmapper_.cpp b/rpcs3/Emu/Cell/Modules/sys_mmapper_.cpp similarity index 76% rename from rpcs3/Emu/SysCalls/Modules/sys_mmapper_.cpp rename to rpcs3/Emu/Cell/Modules/sys_mmapper_.cpp index 5a2c59c300..37830aea71 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_mmapper_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_mmapper_.cpp @@ -1,12 +1,11 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/SysCalls/lv2/sys_mmapper.h" +#include "Emu/Cell/lv2/sys_mmapper.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +extern _log::channel sysPrxForUser; void sysPrxForUser_sys_mmapper_init() { diff --git a/rpcs3/Emu/SysCalls/Modules/sys_net.cpp b/rpcs3/Emu/Cell/Modules/sys_net.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/sys_net.cpp rename to rpcs3/Emu/Cell/Modules/sys_net.cpp index 35456c6a65..9ebd8d7e4b 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_net.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_net.cpp @@ -1,6 +1,5 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "sys_net.h" @@ -9,7 +8,6 @@ #define _WIN32_WINNT 0x0601 #include #include -#pragma comment(lib, "ws2_32.lib") #else #include #include @@ -18,7 +16,7 @@ #include #endif -extern Module<> libnet; +LOG_CHANNEL(libnet); // We map host sockets to sequential IDs to return as FDs because syscalls using // socketselect(), etc. expect socket FDs to be under 1024. @@ -622,10 +620,10 @@ namespace sys_net } } -// define additional macro for specific namespace -#define REG_FUNC_(name) add_ppu_func(ModuleFunc(get_function_id(#name), 0, &libnet, #name, BIND_FUNC(sys_net::name))) +// Define macro for namespace +#define REG_FUNC_(name) REG_FNID(sys_net, ppu_generate_id(#name), sys_net::name) -Module<> libnet("sys_net", []() +DECLARE(ppu_module_manager::libnet)("sys_net", []() { REG_FUNC_(accept); REG_FUNC_(bind); diff --git a/rpcs3/Emu/SysCalls/Modules/sys_net.h b/rpcs3/Emu/Cell/Modules/sys_net.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/sys_net.h rename to rpcs3/Emu/Cell/Modules/sys_net.h diff --git a/rpcs3/Emu/SysCalls/Modules/sys_ppu_thread_.cpp b/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp similarity index 72% rename from rpcs3/Emu/SysCalls/Modules/sys_ppu_thread_.cpp rename to rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp index a22edcc521..f339fa8407 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_ppu_thread_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp @@ -1,28 +1,35 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/SysCalls/lv2/sys_ppu_thread.h" +#include "Emu/Cell/lv2/sys_ppu_thread.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +extern _log::channel sysPrxForUser; + +extern u32 ppu_alloc_tls(); +extern void ppu_free_tls(u32 addr); s32 sys_ppu_thread_create(vm::ptr thread_id, u32 entry, u64 arg, s32 prio, u32 stacksize, u64 flags, vm::cptr threadname) { - sysPrxForUser.warning("sys_ppu_thread_create(thread_id=*0x%x, entry=0x%x, arg=0x%llx, prio=%d, stacksize=0x%x, flags=0x%llx, threadname=*0x%x)", thread_id, entry, arg, prio, stacksize, flags, threadname); + sysPrxForUser.warning("sys_ppu_thread_create(thread_id=*0x%x, entry=0x%x, arg=0x%llx, prio=%d, stacksize=0x%x, flags=0x%llx, threadname=*0x%x)", + thread_id, entry, arg, prio, stacksize, flags, threadname); - // (allocate TLS) - // (return CELL_ENOMEM if failed) - // ... + // Allocate TLS + const u32 tls_addr = ppu_alloc_tls(); - // call the syscall - if (s32 res = _sys_ppu_thread_create(thread_id, vm::make_var(ppu_thread_param_t{ entry, 0 }), arg, 0, prio, stacksize, flags, threadname)) + if (!tls_addr) + { + return CELL_ENOMEM; + } + + // Call the syscall + if (s32 res = _sys_ppu_thread_create(thread_id, vm::make_var(ppu_thread_param_t{ entry, tls_addr + 0x7030 }), arg, 0, prio, stacksize, flags, threadname)) { return res; } - // run the thread + // Run the thread return flags & SYS_PPU_THREAD_CREATE_INTERRUPT ? CELL_OK : sys_ppu_thread_start(static_cast(*thread_id)); } @@ -30,7 +37,7 @@ s32 sys_ppu_thread_get_id(PPUThread& ppu, vm::ptr thread_id) { sysPrxForUser.trace("sys_ppu_thread_get_id(thread_id=*0x%x)", thread_id); - *thread_id = ppu.get_id(); + *thread_id = ppu.id; return CELL_OK; } @@ -40,13 +47,15 @@ void sys_ppu_thread_exit(PPUThread& ppu, u64 val) sysPrxForUser.trace("sys_ppu_thread_exit(val=0x%llx)", val); // (call registered atexit functions) - // (deallocate TLS) // ... + + // Deallocate TLS + ppu_free_tls(vm::cast(ppu.GPR[13], HERE) - 0x7030); - if (ppu.hle_code == 0xaff080a4) + if (ppu.GPR[3] == val && !ppu.custom_task) { - // Change sys_ppu_thread_exit code to the syscall code - ppu.hle_code = ~41; + // Change sys_ppu_thread_exit code to the syscall code (hack) + ppu.GPR[11] = 41; } // Call the syscall diff --git a/rpcs3/Emu/SysCalls/Modules/sys_prx_.cpp b/rpcs3/Emu/Cell/Modules/sys_prx_.cpp similarity index 90% rename from rpcs3/Emu/SysCalls/Modules/sys_prx_.cpp rename to rpcs3/Emu/Cell/Modules/sys_prx_.cpp index 0ad64dc4ad..1b2fac8523 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_prx_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_prx_.cpp @@ -1,12 +1,11 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/SysCalls/lv2/sys_prx.h" +#include "Emu/Cell/lv2/sys_prx.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +extern _log::channel sysPrxForUser; s64 sys_prx_exitspawn_with_level() { diff --git a/rpcs3/Emu/SysCalls/Modules/sys_spinlock.cpp b/rpcs3/Emu/Cell/Modules/sys_spinlock.cpp similarity index 92% rename from rpcs3/Emu/SysCalls/Modules/sys_spinlock.cpp rename to rpcs3/Emu/Cell/Modules/sys_spinlock.cpp index 50bc095695..42397477b7 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_spinlock.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_spinlock.cpp @@ -1,11 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +extern _log::channel sysPrxForUser; void sys_spinlock_initialize(vm::ptr> lock) { diff --git a/rpcs3/Emu/SysCalls/Modules/sys_spu_.cpp b/rpcs3/Emu/Cell/Modules/sys_spu_.cpp similarity index 78% rename from rpcs3/Emu/SysCalls/Modules/sys_spu_.cpp rename to rpcs3/Emu/Cell/Modules/sys_spu_.cpp index 4d859a9739..3d2c0e6863 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_spu_.cpp +++ b/rpcs3/Emu/Cell/Modules/sys_spu_.cpp @@ -1,15 +1,13 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "Emu/Cell/RawSPUThread.h" -#include "Emu/SysCalls/lv2/sys_spu.h" -#include "Emu/FS/vfsFile.h" +#include "Emu/Cell/lv2/sys_spu.h" #include "Crypto/unself.h" #include "sysPrxForUser.h" -extern Module<> sysPrxForUser; +extern _log::channel sysPrxForUser; extern u64 get_system_time(); @@ -30,17 +28,38 @@ s32 sys_spu_elf_get_segments(u32 elf_img, vm::ptr segments, s32 return CELL_OK; } -s32 sys_spu_image_import(vm::ptr img, u32 src, u32 type) +s32 sys_spu_image_import(vm::ptr img, u32 src, u32 type) { sysPrxForUser.warning("sys_spu_image_import(img=*0x%x, src=0x%x, type=%d)", img, src, type); - return spu_image_import(*img, src, type); + u32 entry, offset = LoadSpuImage(fs::file(vm::base(src), 0 - src), entry); + + img->type = SYS_SPU_IMAGE_TYPE_USER; + img->entry_point = entry; + img->segs.set(offset); // TODO: writing actual segment info + img->nsegs = 1; // wrong value + + return CELL_OK; } -s32 sys_spu_image_close(vm::ptr img) +s32 sys_spu_image_close(vm::ptr img) { - sysPrxForUser.todo("sys_spu_image_close(img=*0x%x)", img); + sysPrxForUser.warning("sys_spu_image_close(img=*0x%x)", img); + if (img->type == SYS_SPU_IMAGE_TYPE_USER) + { + //_sys_free(img->segs.addr()); + } + else if (img->type == SYS_SPU_IMAGE_TYPE_KERNEL) + { + //return syscall_158(img); + } + else + { + return CELL_EINVAL; + } + + ASSERT(vm::dealloc(img->segs.addr(), vm::main)); // Current rough implementation return CELL_OK; } @@ -49,10 +68,10 @@ s32 sys_raw_spu_load(s32 id, vm::cptr path, vm::ptr entry) sysPrxForUser.warning("sys_raw_spu_load(id=%d, path=*0x%x, entry=*0x%x)", id, path, entry); sysPrxForUser.warning("*** path = '%s'", path.get_ptr()); - vfsFile f(path.get_ptr()); - if (!f.IsOpened()) + const fs::file f(vfs::get(path.get_ptr())); + if (!f) { - sysPrxForUser.error("sys_raw_spu_load error: '%s' not found!", path.get_ptr()); + sysPrxForUser.error("sys_raw_spu_load() error: '%s' not found!", path.get_ptr()); return CELL_ENOENT; } @@ -61,12 +80,10 @@ s32 sys_raw_spu_load(s32 id, vm::cptr path, vm::ptr entry) if (hdr.CheckMagic()) { - sysPrxForUser.error("sys_raw_spu_load error: '%s' is encrypted! Decrypt SELF and try again.", path.get_ptr()); - Emu.Pause(); - return CELL_ENOENT; + throw fmt::exception("sys_raw_spu_load() error: '%s' is encrypted! Try to decrypt it manually and try again.", path.get_ptr()); } - f.Seek(0); + f.seek(0); u32 _entry; LoadSpuImage(f, _entry, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id); @@ -76,7 +93,7 @@ s32 sys_raw_spu_load(s32 id, vm::cptr path, vm::ptr entry) return CELL_OK; } -s32 sys_raw_spu_image_load(PPUThread& ppu, s32 id, vm::ptr img) +s32 sys_raw_spu_image_load(PPUThread& ppu, s32 id, vm::ptr img) { sysPrxForUser.warning("sys_raw_spu_image_load(id=%d, img=*0x%x)", id, img); @@ -84,7 +101,7 @@ s32 sys_raw_spu_image_load(PPUThread& ppu, s32 id, vm::ptr img) const auto stamp0 = get_system_time(); - std::memcpy(vm::base(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id), vm::base(img->addr), 256 * 1024); + std::memcpy(vm::base(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id), img->segs.get_ptr(), 256 * 1024); const auto stamp1 = get_system_time(); @@ -173,11 +190,6 @@ s32 _sys_spu_printf_detach_thread(PPUThread& ppu, u32 thread) void sysPrxForUser_sys_spu_init() { - g_spu_printf_agcb = vm::null; - g_spu_printf_dgcb = vm::null; - g_spu_printf_atcb = vm::null; - g_spu_printf_dtcb = vm::null; - REG_FUNC(sysPrxForUser, sys_spu_elf_get_information); REG_FUNC(sysPrxForUser, sys_spu_elf_get_segments); REG_FUNC(sysPrxForUser, sys_spu_image_import); diff --git a/rpcs3/Emu/SysCalls/ModuleManager.cpp b/rpcs3/Emu/SysCalls/ModuleManager.cpp deleted file mode 100644 index 06b3a66917..0000000000 --- a/rpcs3/Emu/SysCalls/ModuleManager.cpp +++ /dev/null @@ -1,343 +0,0 @@ -#include "stdafx.h" -#include "Modules.h" -#include "ModuleManager.h" - -extern Module<> cellAdec; -extern Module<> cellAtrac; -extern Module<> cellAtracMulti; -extern Module<> cellAudio; -extern Module<> cellAvconfExt; -extern Module<> cellBGDL; -extern Module<> cellCamera; -extern Module<> cellCelp8Enc; -extern Module<> cellCelpEnc; -extern Module<> cellDaisy; -extern Module<> cellDmux; -extern Module<> cellFiber; -extern Module<> cellFont; -extern Module<> cellFontFT; -extern Module<> cellFs; -extern Module<> cellGame; -extern Module<> cellGameExec; -extern Module<> cellGcmSys; -extern Module<> cellGem; -extern Module<> cellGifDec; -extern Module<> cellHttp; -extern Module<> cellHttps; -extern Module<> cellHttpUtil; -extern Module<> cellImeJp; -extern Module<> cellJpgDec; -extern Module<> cellJpgEnc; -extern Module<> cellKey2char; -extern Module<> cellL10n; -extern Module<> cellMic; -extern Module<> cellMusic; -extern Module<> cellMusicDecode; -extern Module<> cellMusicExport; -extern Module<> cellNetCtl; -extern Module<> cellOskDialog; -extern Module<> cellOvis; -extern Module<> cellPamf; -extern Module<> cellPhotoDecode; -extern Module<> cellPhotoExport; -extern Module<> cellPhotoImportUtil; -extern Module<> cellPngDec; -extern Module<> cellPngEnc; -extern Module<> cellPrint; -extern Module<> cellRec; -extern Module<> cellRemotePlay; -extern Module<> cellResc; -extern Module<> cellRtc; -extern Module<> cellRudp; -extern Module<> cellSail; -extern Module<> cellSailRec; -extern Module<> cellSaveData; -extern Module<> cellMinisSaveData; -extern Module<> cellScreenshot; -extern Module<> cellSearch; -extern Module<> cellSheap; -extern Module<> cellSpudll; -extern Module<> cellSpurs; -extern Module<> cellSpursJq; -extern Module<> cellSsl; -extern Module<> cellSubdisplay; -extern Module<> cellSync; -extern Module cellSync2; -extern Module<> cellSysconf; -extern Module<> cellSysmodule; -extern Module<> cellSysutil; -extern Module<> cellSysutilAp; -extern Module<> cellSysutilAvc; -extern Module<> cellSysutilAvc2; -extern Module<> cellSysutilMisc; -extern Module<> cellUsbd; -extern Module<> cellUsbPspcm; -extern Module<> cellUserInfo; -extern Module<> cellVdec; -extern Module<> cellVideoExport; -extern Module<> cellVideoUpload; -extern Module<> cellVoice; -extern Module<> cellVpost; -extern Module<> libmixer; -extern Module<> libsnd3; -extern Module<> libsynth2; -extern Module<> sceNp; -extern Module<> sceNp2; -extern Module<> sceNpClans; -extern Module<> sceNpCommerce2; -extern Module<> sceNpSns; -extern Module<> sceNpTrophy; -extern Module<> sceNpTus; -extern Module<> sceNpUtil; -extern Module<> sys_io; -extern Module<> libnet; -extern Module<> sysPrxForUser; -extern Module<> sys_libc; -extern Module<> sys_lv2dbg; - -struct ModuleInfo -{ - const s32 id; // -1 if the module doesn't have corresponding CELL_SYSMODULE_* id - const char* const name; - Module<>* const module; - - explicit operator bool() const - { - return module != nullptr; - } - - operator Module<>*() const - { - return module; - } - - Module<>* operator ->() const - { - return module; - } -} -const g_module_list[] = -{ - { 0x0000, "sys_net", &libnet }, - { 0x0001, "cellHttp", &cellHttp }, - { 0x0002, "cellHttpUtil", &cellHttpUtil }, - { 0x0003, "cellSsl", &cellSsl }, - { 0x0004, "cellHttps", &cellHttps }, - { 0x0005, "libvdec", &cellVdec }, - { 0x0006, "cellAdec", &cellAdec }, - { 0x0007, "cellDmux", &cellDmux }, - { 0x0008, "cellVpost", &cellVpost }, - { 0x0009, "cellRtc", &cellRtc }, - { 0x000a, "cellSpurs", &cellSpurs }, - { 0x000b, "cellOvis", &cellOvis }, - { 0x000c, "cellSheap", &cellSheap }, - { 0x000d, "cellSync", &cellSync }, - { 0x000e, "sys_fs", &cellFs }, - { 0x000f, "cellJpgDec", &cellJpgDec }, - { 0x0010, "cellGcmSys", &cellGcmSys }, - { 0x0011, "cellAudio", &cellAudio }, - { 0x0012, "cellPamf", &cellPamf }, - { 0x0013, "cellAtrac", &cellAtrac }, - { 0x0014, "cellNetCtl", &cellNetCtl }, - { 0x0015, "cellSysutil", &cellSysutil }, - { 0x0016, "sceNp", &sceNp }, - { 0x0017, "sys_io", &sys_io }, - { 0x0018, "cellPngDec", &cellPngDec }, - { 0x0019, "cellFont", &cellFont }, - { 0x001a, "cellFontFT", &cellFontFT }, - { 0x001b, "cell_FreeType2", nullptr }, - { 0x001c, "cellUsbd", &cellUsbd }, - { 0x001d, "cellSail", &cellSail }, - { 0x001e, "cellL10n", &cellL10n }, - { 0x001f, "cellResc", &cellResc }, - { 0x0020, "cellDaisy", &cellDaisy }, - { 0x0021, "cellKey2char", &cellKey2char }, - { 0x0022, "cellMic", &cellMic }, - { 0x0023, "cellCamera", &cellCamera }, - { 0x0024, "cellVdecMpeg2", nullptr }, - { 0x0025, "cellVdecAvc", nullptr }, - { 0x0026, "cellAdecLpcm", nullptr }, - { 0x0027, "cellAdecAc3", nullptr }, - { 0x0028, "cellAdecAtx", nullptr }, - { 0x0029, "cellAdecAt3", nullptr }, - { 0x002a, "cellDmuxPamf", nullptr }, - { 0x002b, "?", nullptr }, - { 0x002c, "?", nullptr }, - { 0x002d, "?", nullptr }, - { 0x002e, "sys_lv2dbg", &sys_lv2dbg }, - { 0x002f, "cellSysutilAvcExt", &cellSysutilAvc }, - { 0x0030, "cellUsbPspcm", &cellUsbPspcm }, - { 0x0031, "cellSysutilAvconfExt", &cellAvconfExt }, - { 0x0032, "cellUserInfo", &cellUserInfo }, - { 0x0033, "cellSaveData", &cellSaveData }, - { 0x0034, "cellSubDisplay", &cellSubdisplay }, - { 0x0035, "cellRec", &cellRec }, - { 0x0036, "cellVideoExportUtility", &cellVideoExport }, - { 0x0037, "cellGameExec", &cellGameExec }, - { 0x0038, "sceNp2", &sceNp2 }, - { 0x0039, "cellSysutilAp", &cellSysutilAp }, - { 0x003a, "sceNpClans", &sceNpClans }, - { 0x003b, "cellOskExtUtility", &cellOskDialog }, - { 0x003c, "cellVdecDivx", nullptr }, - { 0x003d, "cellJpgEnc", &cellJpgEnc }, - { 0x003e, "cellGame", &cellGame }, - { 0x003f, "cellBGDLUtility", &cellBGDL }, - { 0x0040, "cell_FreeType2", nullptr }, - { 0x0041, "cellVideoUpload", &cellVideoUpload }, - { 0x0042, "cellSysconfExtUtility", &cellSysconf }, - { 0x0043, "cellFiber", &cellFiber }, - { 0x0044, "sceNpCommerce2", &sceNpCommerce2 }, - { 0x0045, "sceNpTus", &sceNpTus }, - { 0x0046, "cellVoice", &cellVoice }, - { 0x0047, "cellAdecCelp8", nullptr }, - { 0x0048, "cellCelp8Enc", &cellCelp8Enc }, - { 0x0049, "cellSysutilMisc", &cellSysutilMisc }, - { 0x004a, "cellMusicUtility", &cellMusic }, // 2 - { 0x004e, "cellScreenShotUtility", &cellScreenshot }, - { 0x004f, "cellMusicDecodeUtility", &cellMusicDecode }, - { 0x0050, "cellSpursJq", &cellSpursJq }, - { 0x0052, "cellPngEnc", &cellPngEnc }, - { 0x0053, "cellMusicDecodeUtility", &cellMusicDecode }, // 2 - { 0x0055, "cellSync2", &cellSync2 }, - { 0x0056, "sceNpUtil", &sceNpUtil }, - { 0x0057, "cellRudp", &cellRudp }, - { 0x0059, "sceNpSns", &sceNpSns }, - { 0x005a, "libgem", &cellGem }, - { 0xf00a, "cellCelpEnc", &cellCelpEnc }, - { 0xf010, "cellGifDec", &cellGifDec }, - { 0xf019, "cellAdecCelp", nullptr }, - { 0xf01b, "cellAdecM2bc", nullptr }, - { 0xf01d, "cellAdecM4aac", nullptr }, - { 0xf01e, "cellAdecMp3", nullptr }, - { 0xf023, "cellImeJpUtility", &cellImeJp }, - { 0xf028, "cellMusicUtility", &cellMusic }, - { 0xf029, "cellPhotoUtility", &cellPhotoExport }, - { 0xf02a, "cellPrintUtility", &cellPrint }, - { 0xf02b, "cellPhotoImportUtil", &cellPhotoImportUtil }, - { 0xf02c, "cellMusicExportUtility", &cellMusicExport }, - { 0xf02e, "cellPhotoDecodeUtil", &cellPhotoDecode }, - { 0xf02f, "cellSearchUtility", &cellSearch }, - { 0xf030, "cellSysutilAvc2", &cellSysutilAvc2 }, - { 0xf034, "cellSailRec", &cellSailRec }, - { 0xf035, "sceNpTrophy", &sceNpTrophy }, - { 0xf053, "cellAdecAt3multi", nullptr }, - { 0xf054, "cellAtracMulti", &cellAtracMulti }, - - { -1, "cellSysmodule", &cellSysmodule }, - { -1, "libmixer", &libmixer }, - { -1, "sysPrxForUser", &sysPrxForUser }, - { -1, "sys_libc", &sys_libc }, - { -1, "cellMinisSaveData", &cellMinisSaveData }, - { -1, "cellSpudll", &cellSpudll }, - { -1, "cellRemotePlay", &cellRemotePlay }, - { -1, "libsnd3", &libsnd3 }, - { -1, "libsynth2", &libsynth2 }, -}; - -void ModuleManager::Init() -{ - if (m_init) - { - Close(); - } - - clear_ppu_functions(); - - std::unordered_set*> processed; - - for (auto& module : g_module_list) - { - if (module && processed.emplace(module).second) - { - module->Init(); - } - } - - m_init = true; -} - -ModuleManager::ModuleManager() -{ -} - -ModuleManager::~ModuleManager() -{ - Close(); -} - -void ModuleManager::Close() -{ - if (!m_init) - { - return; - } - - std::unordered_set*> processed; - - for (auto& module : g_module_list) - { - if (module && module->on_stop && processed.emplace(module).second) - { - module->on_stop(); - } - } - - m_init = false; -} - -void ModuleManager::Alloc() -{ - if (!m_init) - { - return; - } - - std::unordered_set*> processed; - - for (auto& module : g_module_list) - { - if (module && module->on_alloc && processed.emplace(module).second) - { - module->on_alloc(); - } - } -} - -Module<>* ModuleManager::GetModuleByName(const char* name) -{ - for (auto& module : g_module_list) - { - if (!strcmp(name, module.name)) - { - return module; - } - } - - return nullptr; -} - -Module<>* ModuleManager::GetModuleById(u16 id) -{ - for (auto& module : g_module_list) - { - if (module.id == id) - { - return module; - } - } - - return nullptr; -} - -bool ModuleManager::CheckModuleId(u16 id) -{ - for (auto& module : g_module_list) - { - if (module.id == id) - { - return true; - } - } - - return false; -} diff --git a/rpcs3/Emu/SysCalls/ModuleManager.h b/rpcs3/Emu/SysCalls/ModuleManager.h deleted file mode 100644 index 593f278b3a..0000000000 --- a/rpcs3/Emu/SysCalls/ModuleManager.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -template class Module; - -class ModuleManager -{ - bool m_init = false; - -public: - ModuleManager(); - ~ModuleManager(); - - void Init(); - void Close(); - void Alloc(); - - static Module* GetModuleByName(const char* name); - static Module* GetModuleById(u16 id); - static bool CheckModuleId(u16 id); -}; diff --git a/rpcs3/Emu/SysCalls/Modules.cpp b/rpcs3/Emu/SysCalls/Modules.cpp deleted file mode 100644 index 744dfc95bb..0000000000 --- a/rpcs3/Emu/SysCalls/Modules.cpp +++ /dev/null @@ -1,576 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/state.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/SysCalls/SysCalls.h" -#include "Crypto/sha1.h" -#include "ModuleManager.h" -#include "Emu/Cell/PPUInstrTable.h" - -std::vector g_ppu_func_list; -std::vector g_ppu_func_subs; -std::vector g_ps3_var_list; - -u32 add_ppu_func(ModuleFunc func) -{ - if (g_ppu_func_list.empty()) - { - // prevent relocations if the array growths, must be sizeof(ModuleFunc) * 0x8000 ~~ about 1 MB of memory - g_ppu_func_list.reserve(0x8000); - } - - for (auto& f : g_ppu_func_list) - { - if (f.id == func.id) - { - // if NIDs overlap or if the same function is added twice - throw EXCEPTION("FNID already exists: 0x%08x (%s)", f.id, f.name); - } - } - - g_ppu_func_list.emplace_back(std::move(func)); - return (u32)g_ppu_func_list.size() - 1; -} - -void add_variable(u32 nid, Module<>* module, const char* name, u32(*addr)()) -{ - if (g_ps3_var_list.empty()) - { - g_ps3_var_list.reserve(0x4000); // as g_ppu_func_list - } - - for (auto& v : g_ps3_var_list) - { - if (v.id == nid) - { - throw EXCEPTION("VNID already exists: 0x%08x (%s)", nid, name); - } - } - - g_ps3_var_list.emplace_back(ModuleVariable{ nid, module, name, addr }); -} - -ModuleVariable* get_variable_by_nid(u32 nid) -{ - for (auto& v : g_ps3_var_list) - { - if (v.id == nid) - { - return &v; - } - } - - return nullptr; -} - -u32 add_ppu_func_sub(StaticFunc func) -{ - g_ppu_func_subs.emplace_back(func); - return func.index; -} - -u32 add_ppu_func_sub(const std::initializer_list& ops, const char* name, Module<>* module, ppu_func_caller func) -{ - StaticFunc sf; - sf.index = add_ppu_func(ModuleFunc(get_function_id(name), 0, module, name, func)); - sf.name = name; - sf.found = 0; - sf.ops = ops; - - return add_ppu_func_sub(std::move(sf)); -} - -ModuleFunc* get_ppu_func_by_nid(u32 nid, u32* out_index) -{ - for (auto& f : g_ppu_func_list) - { - if (f.id == nid) - { - if (out_index) - { - *out_index = (u32)(&f - g_ppu_func_list.data()); - } - - return &f; - } - } - - return nullptr; -} - -ModuleFunc* get_ppu_func_by_index(u32 index) -{ - index &= ~EIF_FLAGS; - - if (index >= g_ppu_func_list.size()) - { - return nullptr; - } - - return &g_ppu_func_list[index]; -} - -void execute_ppu_func_by_index(PPUThread& ppu, u32 index) -{ - if (auto func = get_ppu_func_by_index(index)) - { - // save RTOC if necessary - if (index & EIF_SAVE_RTOC) - { - vm::write64(VM_CAST(ppu.GPR[1] + 0x28), ppu.GPR[2]); - } - - // save old syscall/NID value - const auto last_code = ppu.hle_code; - - // branch directly to the LLE function - if (index & EIF_USE_BRANCH) - { - // for example, FastCall2 can't work with functions which do user level context switch - - if (last_code) - { - throw EXCEPTION("This function cannot be called from the callback: %s (0x%llx)", get_ps3_function_name(func->id), func->id); - } - - if (!func->lle_func) - { - throw EXCEPTION("LLE function not set: %s (0x%llx)", get_ps3_function_name(func->id), func->id); - } - - if (func->flags & MFF_FORCED_HLE) - { - throw EXCEPTION("Forced HLE enabled: %s (0x%llx)", get_ps3_function_name(func->id), func->id); - } - - LOG_TRACE(HLE, "Branch to LLE function: %s (0x%llx)", get_ps3_function_name(func->id), func->id); - - if (index & EIF_PERFORM_BLR) - { - throw EXCEPTION("TODO: Branch with link: %s (0x%llx)", get_ps3_function_name(func->id), func->id); - // CPU.LR = CPU.PC + 4; - } - - const auto data = vm::_ptr(func->lle_func.addr()); - ppu.PC = data[0] - 4; - ppu.GPR[2] = data[1]; // set rtoc - - return; - } - - // change current syscall/NID value - ppu.hle_code = func->id; - - if (func->lle_func && !(func->flags & MFF_FORCED_HLE)) - { - // call LLE function if available - - const auto data = vm::_ptr(func->lle_func.addr()); - const u32 pc = data[0]; - const u32 rtoc = data[1]; - - LOG_TRACE(HLE, "LLE function called: %s", get_ps3_function_name(func->id)); - - ppu.fast_call(pc, rtoc); - - LOG_TRACE(HLE, "LLE function finished: %s -> 0x%llx", get_ps3_function_name(func->id), ppu.GPR[3]); - } - else if (func->func) - { - LOG_TRACE(HLE, "HLE function called: %s", get_ps3_function_name(func->id)); - - func->func(ppu); - - LOG_TRACE(HLE, "HLE function finished: %s -> 0x%llx", get_ps3_function_name(func->id), ppu.GPR[3]); - } - else - { - LOG_TODO(HLE, "Unimplemented function: %s -> CELL_OK", get_ps3_function_name(func->id)); - ppu.GPR[3] = 0; - } - - if (index & EIF_PERFORM_BLR) - { - // return if necessary - ppu.PC = VM_CAST(ppu.LR & ~3) - 4; - } - - // execute module-specific error check - if ((s64)ppu.GPR[3] < 0 && func->module && func->module->on_error) - { - func->module->on_error(ppu.GPR[3], func); - } - - ppu.hle_code = last_code; - } - else - { - throw EXCEPTION("Invalid function index (0x%x)", index); - } -} - -void clear_ppu_functions() -{ - g_ppu_func_list.clear(); - g_ppu_func_subs.clear(); - g_ps3_var_list.clear(); -} - -u32 get_function_id(const char* name) -{ - const char* suffix = "\x67\x59\x65\x99\x04\x25\x04\x90\x56\x64\x27\x49\x94\x89\x74\x1A"; // Symbol name suffix - u8 output[20]; - - // Compute SHA-1 hash - sha1_context ctx; - - sha1_starts(&ctx); - sha1_update(&ctx, (const u8*)name, strlen(name)); - sha1_update(&ctx, (const u8*)suffix, strlen(suffix)); - sha1_finish(&ctx, output); - - return (u32&)output[0]; -} - -void hook_ppu_func(vm::ptr base, u32 pos, u32 size) -{ - using namespace PPU_instr; - - for (auto& sub : g_ppu_func_subs) - { - bool found = sub.ops.size() != 0; - - for (u32 k = pos, x = 0; x + 1 <= sub.ops.size(); k++, x++) - { - if (k >= size) - { - found = false; - break; - } - - // skip NOP - if (base[k] == 0x60000000) - { - x--; - continue; - } - - const be_t data = sub.ops[x].data; - const be_t mask = sub.ops[x].mask; - - const bool match = (base[k] & mask) == data; - - switch (sub.ops[x].type) - { - case SPET_MASKED_OPCODE: - { - // masked pattern - if (!match) - { - found = false; - } - - break; - } - case SPET_OPTIONAL_MASKED_OPCODE: - { - // optional masked pattern - if (!match) - { - k--; - } - - break; - } - case SPET_LABEL: - { - const u32 addr = (base + k--).addr(); - const u32 lnum = data; - const auto label = sub.labels.find(lnum); - - if (label == sub.labels.end()) // register the label - { - sub.labels[lnum] = addr; - } - else if (label->second != addr) // or check registered label - { - found = false; - } - - break; - } - case SPET_BRANCH_TO_LABEL: - { - if (!match) - { - found = false; - break; - } - - const auto addr = (base[k] & 2 ? 0 : (base + k).addr()) + ((s32)base[k] << cntlz32(mask) >> (cntlz32(mask) + 2)); - const auto lnum = sub.ops[x].num; - const auto label = sub.labels.find(lnum); - - if (label == sub.labels.end()) // register the label - { - sub.labels[lnum] = addr; - } - else if (label->second != addr) // or check registered label - { - found = false; - } - - break; - } - //case SPET_BRANCH_TO_FUNC: - //{ - // if (!match) - // { - // found = false; - // break; - // } - - // const auto addr = (base[k] & 2 ? 0 : (base + k).addr()) + ((s32)base[k] << cntlz32(mask) >> (cntlz32(mask) + 2)); - // const auto nid = sub.ops[x].num; - // // TODO: recursive call - //} - default: - { - throw EXCEPTION("Unknown search pattern type (%d)", sub.ops[x].type); - } - } - - if (!found) - { - break; - } - } - - if (found) - { - LOG_SUCCESS(LOADER, "Function '%s' hooked (addr=*0x%x)", sub.name, base + pos); - sub.found++; - base[pos] = HACK(sub.index | EIF_PERFORM_BLR); - } - - if (sub.labels.size()) - { - sub.labels.clear(); - } - } -} - -void hook_ppu_funcs(vm::ptr base, u32 size) -{ - using namespace PPU_instr; - - // TODO: optimize search - for (u32 i = 0; i < size; i++) - { - // skip NOP - if (base[i] == 0x60000000) - { - continue; - } - - hook_ppu_func(base, i, size); - } - - // check functions - for (u32 i = 0; i < g_ppu_func_subs.size(); i++) - { - if (g_ppu_func_subs[i].found > 1) - { - LOG_ERROR(LOADER, "Function '%s' hooked %u times", g_ppu_func_subs[i].found); - } - } -} - -bool patch_ppu_import(u32 addr, u32 index) -{ - const auto data = vm::cptr::make(addr); - - using namespace PPU_instr; - - if (index >= g_ppu_func_list.size()) - { - return false; - } - - const u32 imm = (g_ppu_func_list[index].flags & MFF_NO_RETURN) && !(g_ppu_func_list[index].flags & MFF_FORCED_HLE) - ? index | EIF_USE_BRANCH - : index | EIF_PERFORM_BLR; - - // check different patterns: - - if (vm::check_addr(addr, 32) && - (data[0] & 0xffff0000) == LI_(r12, 0) && - (data[1] & 0xffff0000) == ORIS(r12, r12, 0) && - (data[2] & 0xffff0000) == LWZ(r12, r12, 0) && - data[3] == STD(r2, r1, 0x28) && - data[4] == LWZ(r0, r12, 0) && - data[5] == LWZ(r2, r12, 4) && - data[6] == MTCTR(r0) && - data[7] == BCTR()) - { - vm::write32(addr, HACK(imm | EIF_SAVE_RTOC)); - return true; - } - - if (vm::check_addr(addr, 12) && - (data[0] & 0xffff0000) == LI_(r0, 0) && - (data[1] & 0xffff0000) == ORIS(r0, r0, 0) && - (data[2] & 0xfc000003) == B(0, 0, 0)) - { - const auto sub = vm::cptr::make(addr + 8 + ((s32)data[2] << 6 >> 8 << 2)); - - if (vm::check_addr(sub.addr(), 60) && - sub[0x0] == STDU(r1, r1, -0x80) && - sub[0x1] == STD(r2, r1, 0x70) && - sub[0x2] == MR(r2, r0) && - sub[0x3] == MFLR(r0) && - sub[0x4] == STD(r0, r1, 0x90) && - sub[0x5] == LWZ(r2, r2, 0) && - sub[0x6] == LWZ(r0, r2, 0) && - sub[0x7] == LWZ(r2, r2, 4) && - sub[0x8] == MTCTR(r0) && - sub[0x9] == BCTRL() && - sub[0xa] == LD(r2, r1, 0x70) && - sub[0xb] == ADDI(r1, r1, 0x80) && - sub[0xc] == LD(r0, r1, 0x10) && - sub[0xd] == MTLR(r0) && - sub[0xe] == BLR()) - { - vm::write32(addr, HACK(imm)); - return true; - } - } - - if (vm::check_addr(addr, 64) && - data[0x0] == MFLR(r0) && - data[0x1] == STD(r0, r1, 0x10) && - data[0x2] == STDU(r1, r1, -0x80) && - data[0x3] == STD(r2, r1, 0x70) && - (data[0x4] & 0xffff0000) == LI_(r2, 0) && - (data[0x5] & 0xffff0000) == ORIS(r2, r2, 0) && - data[0x6] == LWZ(r2, r2, 0) && - data[0x7] == LWZ(r0, r2, 0) && - data[0x8] == LWZ(r2, r2, 4) && - data[0x9] == MTCTR(r0) && - data[0xa] == BCTRL() && - data[0xb] == LD(r2, r1, 0x70) && - data[0xc] == ADDI(r1, r1, 0x80) && - data[0xd] == LD(r0, r1, 0x10) && - data[0xe] == MTLR(r0) && - data[0xf] == BLR()) - { - vm::write32(addr, HACK(imm)); - return true; - } - - if (vm::check_addr(addr, 64) && - data[0x0] == MFLR(r0) && - data[0x1] == STD(r0, r1, 0x10) && - data[0x2] == STDU(r1, r1, -0x80) && - data[0x3] == STD(r2, r1, 0x70) && - (data[0x4] & 0xffff0000) == LIS(r12, 0) && - (data[0x5] & 0xffff0000) == LWZ(r12, r12, 0) && - data[0x6] == LWZ(r0, r12, 0) && - data[0x7] == LWZ(r2, r12, 4) && - data[0x8] == MTCTR(r0) && - data[0x9] == BCTRL() && - data[0xa] == LD(r2, r1, 0x70) && - data[0xb] == ADDI(r1, r1, 0x80) && - data[0xc] == LD(r0, r1, 0x10) && - data[0xd] == MTLR(r0) && - data[0xe] == BLR()) - { - vm::write32(addr, HACK(imm)); - return true; - } - - if (vm::check_addr(addr, 56) && - (data[0x0] & 0xffff0000) == LI_(r12, 0) && - (data[0x1] & 0xffff0000) == ORIS(r12, r12, 0) && - (data[0x2] & 0xffff0000) == LWZ(r12, r12, 0) && - data[0x3] == STD(r2, r1, 0x28) && - data[0x4] == MFLR(r0) && - data[0x5] == STD(r0, r1, 0x20) && - data[0x6] == LWZ(r0, r12, 0) && - data[0x7] == LWZ(r2, r12, 4) && - data[0x8] == MTCTR(r0) && - data[0x9] == BCTRL() && - data[0xa] == LD(r0, r1, 0x20) && - data[0xb] == MTLR(r0) && - data[0xc] == LD(r2, r1, 0x28) && - data[0xd] == BLR()) - { - vm::write32(addr, HACK(imm)); - return true; - } - - //vm::write32(addr, HACK(imm)); - return false; -} - -Module<>::Module(const std::string& name, void(*init)()) - : _log::channel(name, _log::level::notice) - , m_is_loaded(false) - , m_init(init) -{ -} - -Module<>::~Module() -{ -} - -void Module<>::Init() -{ - on_load = nullptr; - on_unload = nullptr; - on_stop = nullptr; - on_error = nullptr; - - m_init(); -} - -void Module<>::Load() -{ - if (IsLoaded()) - { - return; - } - - if (on_load) - { - on_load(); - } - - SetLoaded(true); -} - -void Module<>::Unload() -{ - if (!IsLoaded()) - { - return; - } - - if (on_unload) - { - on_unload(); - } - - SetLoaded(false); -} - -void Module<>::SetLoaded(bool loaded) -{ - m_is_loaded = loaded; -} - -bool Module<>::IsLoaded() const -{ - return m_is_loaded; -} diff --git a/rpcs3/Emu/SysCalls/Modules.h b/rpcs3/Emu/SysCalls/Modules.h deleted file mode 100644 index 656ea1a0f3..0000000000 --- a/rpcs3/Emu/SysCalls/Modules.h +++ /dev/null @@ -1,185 +0,0 @@ -#pragma once - -#include "Emu/SysCalls/SC_FUNC.h" -#include "Emu/SysCalls/CB_FUNC.h" -#include "ErrorCodes.h" - -namespace vm { using namespace ps3; } - -template class Module; - -struct ModuleFunc -{ - u32 id; - u32 flags; - Module<>* module; - const char* name; - ppu_func_caller func; - vm::ptr lle_func; - - ModuleFunc() - { - } - - ModuleFunc(u32 id, u32 flags, Module<>* module, const char* name, ppu_func_caller func, vm::ptr lle_func = vm::null) - : id(id) - , flags(flags) - , module(module) - , name(name) - , func(func) - , lle_func(lle_func) - { - } -}; - -struct ModuleVariable -{ - u32 id; - Module<>* module; - const char* name; - u32(*retrieve_addr)(); -}; - -enum : u32 -{ - SPET_MASKED_OPCODE, - SPET_OPTIONAL_MASKED_OPCODE, - SPET_LABEL, - SPET_BRANCH_TO_LABEL, - SPET_BRANCH_TO_FUNC, -}; - -struct SearchPatternEntry -{ - u32 type; - be_t data; - be_t mask; - u32 num; // supplement info -}; - -struct StaticFunc -{ - u32 index; - const char* name; - std::vector ops; - u32 found; - std::unordered_map labels; -}; - -template<> class Module : public _log::channel -{ - friend class ModuleManager; - - bool m_is_loaded; - void(*m_init)(); - -protected: - std::function on_alloc; - -public: - Module(const std::string& name, void(*init)()); - - Module(const Module&) = delete; // Delete copy/move constructors and copy/move operators - - ~Module(); - - std::function on_load; - std::function on_unload; - std::function on_stop; - std::function on_error; - - void Init(); - void Load(); - void Unload(); - - void SetLoaded(bool loaded = true); - bool IsLoaded() const; -}; - -// Module<> with an instance of specified type in PS3 memory -template class Module : public Module -{ - u32 m_addr; - -public: - Module(const char* name, void(*init)()) - : Module(name, init) - { - on_alloc = [this] - { - static_assert(std::is_trivially_destructible::value, "Module<> instance must be trivially destructible"); - //static_assert(std::is_trivially_copy_assignable::value, "Module<> instance must be trivially copy-assignable"); - - // Allocate module instance and call the default constructor -#include "restore_new.h" - new(vm::base(m_addr = vm::alloc(sizeof(T), vm::main))) T(); -#include "define_new_memleakdetect.h" - }; - } - - T* operator ->() const - { - return vm::_ptr(m_addr); - } -}; - -u32 add_ppu_func(ModuleFunc func); -void add_variable(u32 nid, Module<>* module, const char* name, u32(*addr)()); -ModuleFunc* get_ppu_func_by_nid(u32 nid, u32* out_index = nullptr); -ModuleFunc* get_ppu_func_by_index(u32 index); -ModuleVariable* get_variable_by_nid(u32 nid); -void execute_ppu_func_by_index(PPUThread& ppu, u32 id); -extern std::string get_ps3_function_name(u64 fid); -void clear_ppu_functions(); -u32 get_function_id(const char* name); - -u32 add_ppu_func_sub(StaticFunc sf); -u32 add_ppu_func_sub(const std::initializer_list& ops, const char* name, Module<>* module, ppu_func_caller func); - -void hook_ppu_funcs(vm::ptr base, u32 size); - -bool patch_ppu_import(u32 addr, u32 index); - -// Variable associated with registered HLE function -template struct ppu_func_by_func { static u32 index; }; - -template u32 ppu_func_by_func::index = 0xffffffffu; - -template> inline RT call_ppu_func(PPUThread& ppu, Args&&... args) -{ - const auto mfunc = get_ppu_func_by_index(ppu_func_by_func::index); - - if (mfunc && mfunc->lle_func && (mfunc->flags & MFF_FORCED_HLE) == 0 && (mfunc->flags & MFF_NO_RETURN) == 0) - { - const u32 pc = vm::read32(mfunc->lle_func.addr()); - const u32 rtoc = vm::read32(mfunc->lle_func.addr() + 4); - - return cb_call(ppu, pc, rtoc, std::forward(args)...); - } - else - { - return Func(std::forward(args)...); - } -} - -// Call specified function directly if LLE is not available, call LLE equivalent in callback style otherwise -#define CALL_FUNC(ppu, func, ...) call_ppu_func(ppu, __VA_ARGS__) - -#define REG_FNID(module, nid, func, ...) (ppu_func_by_func::index = add_ppu_func(ModuleFunc(nid, { __VA_ARGS__ }, &module, #func, BIND_FUNC(func)))) - -#define REG_FUNC(module, func, ...) REG_FNID(module, get_function_id(#func), func, __VA_ARGS__) - -#define REG_VNID(module, nid, var) add_variable(nid, &module, #var, []{ return vm::get_addr(&module->var); }) - -#define REG_VARIABLE(module, var) REG_VNID(module, get_function_id(#var), var) - -#define REG_SUB(module, ns, name, ...) add_ppu_func_sub({ __VA_ARGS__ }, #name, &module, BIND_FUNC(ns::name)) - -#define SP_OP(type, op, sup) []() { s32 XXX = 0; SearchPatternEntry res = { (type), (op), 0, (sup) }; XXX = -1; res.mask = (op) ^ ~res.data; return res; }() -#define SP_I(op) SP_OP(SPET_MASKED_OPCODE, op, 0) -#define OPT_SP_I(op) SP_OP(SPET_OPTIONAL_MASKED_OPCODE, op, 0) -#define SET_LABEL(label) { SPET_LABEL, (label) } -#define SP_LABEL_BR(op, label) SP_OP(SPET_BRANCH_TO_LABEL, op, label) -#define SP_CALL(op, name) SP_OP(SPET_BRANCH_TO_FUNC, op, get_function_id(#name)) - -#define UNIMPLEMENTED_FUNC(module) module.todo("%s", __FUNCTION__) diff --git a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp deleted file mode 100644 index 47e482aff5..0000000000 --- a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp +++ /dev/null @@ -1,1198 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/Cell/PPUInstrTable.h" - -#include "cellAudio.h" -#include "libmixer.h" - -extern Module<> libmixer; - -SurMixerConfig g_surmx; - -std::vector g_ssp; - -s32 cellAANAddData(u32 aan_handle, u32 aan_port, u32 offset, vm::ptr addr, u32 samples) -{ - libmixer.trace("cellAANAddData(aan_handle=0x%x, aan_port=0x%x, offset=0x%x, addr=*0x%x, samples=%d)", aan_handle, aan_port, offset, addr, samples); - - u32 type = aan_port >> 16; - u32 port = aan_port & 0xffff; - - switch (type) - { - case CELL_SURMIXER_CHSTRIP_TYPE1A: - if (port >= g_surmx.ch_strips_1) type = 0; break; - case CELL_SURMIXER_CHSTRIP_TYPE2A: - if (port >= g_surmx.ch_strips_2) type = 0; break; - case CELL_SURMIXER_CHSTRIP_TYPE6A: - if (port >= g_surmx.ch_strips_6) type = 0; break; - case CELL_SURMIXER_CHSTRIP_TYPE8A: - if (port >= g_surmx.ch_strips_8) type = 0; break; - default: - type = 0; break; - } - - if (aan_handle != 0x11111111 || samples != 256 || !type || offset != 0) - { - libmixer.error("cellAANAddData(aan_handle=0x%x, aan_port=0x%x, offset=0x%x, addr=*0x%x, samples=%d): invalid parameters", aan_handle, aan_port, offset, addr, samples); - return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; - } - - std::lock_guard lock(g_surmx.mutex); - - if (type == CELL_SURMIXER_CHSTRIP_TYPE1A) - { - // mono upmixing - for (u32 i = 0; i < samples; i++) - { - const float center = addr[i]; - g_surmx.mixdata[i * 8 + 0] += center; - g_surmx.mixdata[i * 8 + 1] += center; - } - } - else if (type == CELL_SURMIXER_CHSTRIP_TYPE2A) - { - // stereo upmixing - for (u32 i = 0; i < samples; i++) - { - const float left = addr[i * 2 + 0]; - const float right = addr[i * 2 + 1]; - g_surmx.mixdata[i * 8 + 0] += left; - g_surmx.mixdata[i * 8 + 1] += right; - } - } - else if (type == CELL_SURMIXER_CHSTRIP_TYPE6A) - { - // 5.1 upmixing - for (u32 i = 0; i < samples; i++) - { - const float left = addr[i * 6 + 0]; - const float right = addr[i * 6 + 1]; - const float center = addr[i * 6 + 2]; - const float low_freq = addr[i * 6 + 3]; - const float rear_left = addr[i * 6 + 4]; - const float rear_right = addr[i * 6 + 5]; - g_surmx.mixdata[i * 8 + 0] += left; - g_surmx.mixdata[i * 8 + 1] += right; - g_surmx.mixdata[i * 8 + 2] += center; - g_surmx.mixdata[i * 8 + 3] += low_freq; - g_surmx.mixdata[i * 8 + 4] += rear_left; - g_surmx.mixdata[i * 8 + 5] += rear_right; - } - } - else if (type == CELL_SURMIXER_CHSTRIP_TYPE8A) - { - // 7.1 - for (u32 i = 0; i < samples * 8; i++) - { - g_surmx.mixdata[i] += addr[i]; - } - } - - return CELL_OK; -} - -s32 cellAANConnect(u32 receive, u32 receivePortNo, u32 source, u32 sourcePortNo) -{ - libmixer.warning("cellAANConnect(receive=0x%x, receivePortNo=0x%x, source=0x%x, sourcePortNo=0x%x)", - receive, receivePortNo, source, sourcePortNo); - - std::lock_guard lock(g_surmx.mutex); - - if (source >= g_ssp.size() || !g_ssp[source].m_created) - { - libmixer.error("cellAANConnect(): invalid source (%d)", source); - return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; - } - - g_ssp[source].m_connected = true; - - return CELL_OK; -} - -s32 cellAANDisconnect(u32 receive, u32 receivePortNo, u32 source, u32 sourcePortNo) -{ - libmixer.warning("cellAANDisconnect(receive=0x%x, receivePortNo=0x%x, source=0x%x, sourcePortNo=0x%x)", - receive, receivePortNo, source, sourcePortNo); - - std::lock_guard lock(g_surmx.mutex); - - if (source >= g_ssp.size() || !g_ssp[source].m_created) - { - libmixer.error("cellAANDisconnect(): invalid source (%d)", source); - return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; - } - - g_ssp[source].m_connected = false; - - return CELL_OK; -} - -s32 cellSSPlayerCreate(vm::ptr handle, vm::ptr config) -{ - libmixer.warning("cellSSPlayerCreate(handle=*0x%x, config=*0x%x)", handle, config); - - if (config->outputMode != 0 || config->channels - 1 >= 2) - { - libmixer.error("cellSSPlayerCreate(config.outputMode=%d, config.channels=%d): invalid parameters", config->outputMode, config->channels); - return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; - } - - std::lock_guard lock(g_surmx.mutex); - - SSPlayer p; - p.m_created = true; - p.m_connected = false; - p.m_active = false; - p.m_channels = config->channels; - - g_ssp.push_back(p); - *handle = (u32)g_ssp.size() - 1; - return CELL_OK; -} - -s32 cellSSPlayerRemove(u32 handle) -{ - libmixer.warning("cellSSPlayerRemove(handle=0x%x)", handle); - - std::lock_guard lock(g_surmx.mutex); - - if (handle >= g_ssp.size() || !g_ssp[handle].m_created) - { - libmixer.error("cellSSPlayerRemove(): SSPlayer not found (%d)", handle); - return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; - } - - g_ssp[handle].m_active = false; - g_ssp[handle].m_created = false; - g_ssp[handle].m_connected = false; - - return CELL_OK; -} - -s32 cellSSPlayerSetWave(u32 handle, vm::ptr waveInfo, vm::ptr commonInfo) -{ - libmixer.warning("cellSSPlayerSetWave(handle=0x%x, waveInfo=*0x%x, commonInfo=*0x%x)", handle, waveInfo, commonInfo); - - std::lock_guard lock(g_surmx.mutex); - - if (handle >= g_ssp.size() || !g_ssp[handle].m_created) - { - libmixer.error("cellSSPlayerSetWave(): SSPlayer not found (%d)", handle); - return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; - } - - // TODO: check parameters - - g_ssp[handle].m_addr = waveInfo->addr; - g_ssp[handle].m_samples = waveInfo->samples; - g_ssp[handle].m_loop_start = waveInfo->loopStartOffset - 1; - g_ssp[handle].m_loop_mode = commonInfo ? (u32)commonInfo->loopMode : CELL_SSPLAYER_ONESHOT; - g_ssp[handle].m_position = waveInfo->startOffset - 1; - - return CELL_OK; -} - -s32 cellSSPlayerPlay(u32 handle, vm::ptr info) -{ - libmixer.warning("cellSSPlayerPlay(handle=0x%x, info=*0x%x)", handle, info); - - std::lock_guard lock(g_surmx.mutex); - - if (handle >= g_ssp.size() || !g_ssp[handle].m_created) - { - libmixer.error("cellSSPlayerPlay(): SSPlayer not found (%d)", handle); - return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; - } - - // TODO: check parameters - - g_ssp[handle].m_active = true; - g_ssp[handle].m_level = info->level; - g_ssp[handle].m_speed = info->speed; - g_ssp[handle].m_x = info->position.x; - g_ssp[handle].m_y = info->position.y; - g_ssp[handle].m_z = info->position.z; - - return CELL_OK; -} - -s32 cellSSPlayerStop(u32 handle, u32 mode) -{ - libmixer.warning("cellSSPlayerStop(handle=0x%x, mode=0x%x)", handle, mode); - - std::lock_guard lock(g_surmx.mutex); - - if (handle >= g_ssp.size() || !g_ssp[handle].m_created) - { - libmixer.error("cellSSPlayerStop(): SSPlayer not found (%d)", handle); - return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; - } - - // TODO: transition to stop state - - g_ssp[handle].m_active = false; - - return CELL_OK; -} - -s32 cellSSPlayerSetParam(u32 handle, vm::ptr info) -{ - libmixer.warning("cellSSPlayerSetParam(handle=0x%x, info=*0x%x)", handle, info); - - std::lock_guard lock(g_surmx.mutex); - - if (handle >= g_ssp.size() || !g_ssp[handle].m_created) - { - libmixer.error("cellSSPlayerSetParam(): SSPlayer not found (%d)", handle); - return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; - } - - // TODO: check parameters - - g_ssp[handle].m_level = info->level; - g_ssp[handle].m_speed = info->speed; - g_ssp[handle].m_x = info->position.x; - g_ssp[handle].m_y = info->position.y; - g_ssp[handle].m_z = info->position.z; - - return CELL_OK; -} - -s32 cellSSPlayerGetState(u32 handle) -{ - libmixer.warning("cellSSPlayerGetState(handle=0x%x)", handle); - - std::lock_guard lock(g_surmx.mutex); - - if (handle >= g_ssp.size() || !g_ssp[handle].m_created) - { - libmixer.warning("cellSSPlayerGetState(): SSPlayer not found (%d)", handle); - return CELL_SSPLAYER_STATE_ERROR; - } - - if (g_ssp[handle].m_active) - { - return CELL_SSPLAYER_STATE_ON; - } - - return CELL_SSPLAYER_STATE_OFF; -} - -s32 cellSurMixerCreate(vm::cptr config) -{ - libmixer.warning("cellSurMixerCreate(config=*0x%x)", config); - - g_surmx.audio_port = g_audio.open_port(); - - if (!~g_surmx.audio_port) - { - return CELL_LIBMIXER_ERROR_FULL; - } - - g_surmx.priority = config->priority; - g_surmx.ch_strips_1 = config->chStrips1; - g_surmx.ch_strips_2 = config->chStrips2; - g_surmx.ch_strips_6 = config->chStrips6; - g_surmx.ch_strips_8 = config->chStrips8; - - AudioPortConfig& port = g_audio.ports[g_surmx.audio_port]; - - port.channel = 8; - port.block = 16; - port.attr = 0; - port.addr = g_audio.buffer + AUDIO_PORT_OFFSET * g_surmx.audio_port; - port.read_index_addr = g_audio.indexes + sizeof(u64) * g_surmx.audio_port; - port.size = port.channel * port.block * AUDIO_SAMPLES * sizeof(float); - port.tag = 0; - port.level = 1.0f; - port.level_set.store({ 1.0f, 0.0f }); - - libmixer.warning("*** audio port opened (port=%d)", g_surmx.audio_port); - - g_surmx.mixcount = 0; - g_surmx.cb = vm::null; - - g_ssp.clear(); - - libmixer.warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", config->chStrips1, config->chStrips2, config->chStrips6, config->chStrips8); - - const auto ppu = idm::make_ptr("Surmixer Thread"); - ppu->prio = 1001; - ppu->stack_size = 0x10000; - ppu->custom_task = [](PPUThread& ppu) - { - AudioPortConfig& port = g_audio.ports[g_surmx.audio_port]; - - while (port.state != AUDIO_PORT_STATE_CLOSED) - { - CHECK_EMU_STATUS; - - if (g_surmx.mixcount > (port.tag + 0)) // adding positive value (1-15): preemptive buffer filling (hack) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - continue; - } - - if (port.state == AUDIO_PORT_STATE_STARTED) - { - //u64 stamp0 = get_system_time(); - - memset(g_surmx.mixdata, 0, sizeof(g_surmx.mixdata)); - if (g_surmx.cb) - { - g_surmx.cb(ppu, g_surmx.cb_arg, (u32)g_surmx.mixcount, 256); - } - - //u64 stamp1 = get_system_time(); - - { - std::lock_guard lock(g_surmx.mutex); - - for (auto& p : g_ssp) if (p.m_active && p.m_created) - { - auto v = vm::ptrl::make(p.m_addr); // 16-bit LE audio data - float left = 0.0f; - float right = 0.0f; - float speed = fabs(p.m_speed); - float fpos = 0.0f; - for (s32 i = 0; i < 256; i++) if (p.m_active) - { - u32 pos = p.m_position; - s32 pos_inc = 0; - if (p.m_speed > 0.0f) // select direction - { - pos_inc = 1; - } - else if (p.m_speed < 0.0f) - { - pos_inc = -1; - } - s32 shift = i - (int)fpos; // change playback speed (simple and rough) - if (shift > 0) - { - // slow playback - pos_inc = 0; // duplicate one sample at this time - fpos += 1.0f; - fpos += speed; - } - else if (shift < 0) - { - // fast playback - i--; // mix two sample into one at this time - fpos -= 1.0f; - } - else - { - fpos += speed; - } - p.m_position += (u32)pos_inc; - if (p.m_channels == 1) // get mono data - { - left = right = (float)v[pos] / 0x8000 * p.m_level; - } - else if (p.m_channels == 2) // get stereo data - { - left = (float)v[pos * 2 + 0] / 0x8000 * p.m_level; - right = (float)v[pos * 2 + 1] / 0x8000 * p.m_level; - } - if (p.m_connected) // mix - { - // TODO: m_x, m_y, m_z ignored - g_surmx.mixdata[i * 8 + 0] += left; - g_surmx.mixdata[i * 8 + 1] += right; - } - if ((p.m_position == p.m_samples && p.m_speed > 0.0f) || - (p.m_position == ~0 && p.m_speed < 0.0f)) // loop or stop - { - if (p.m_loop_mode == CELL_SSPLAYER_LOOP_ON) - { - p.m_position = p.m_loop_start; - } - else if (p.m_loop_mode == CELL_SSPLAYER_ONESHOT_CONT) - { - p.m_position -= (u32)pos_inc; // restore position - } - else // oneshot - { - p.m_active = false; - p.m_position = p.m_loop_start; // TODO: check value - } - } - } - } - } - - //u64 stamp2 = get_system_time(); - - auto buf = vm::_ptr(port.addr + (g_surmx.mixcount % port.block) * port.channel * AUDIO_SAMPLES * sizeof(float)); - - for (auto& mixdata : g_surmx.mixdata) - { - // reverse byte order - *buf++ = mixdata; - } - - //u64 stamp3 = get_system_time(); - - //ConLog.Write("Libmixer perf: start=%lld (cb=%lld, ssp=%lld, finalize=%lld)", stamp0 - m_config.start_time, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2); - } - - g_surmx.mixcount++; - } - - idm::remove(ppu.get_id()); - }; - - ppu->run(); - ppu->exec(); - - return CELL_OK; -} - -s32 cellSurMixerGetAANHandle(vm::ptr handle) -{ - libmixer.warning("cellSurMixerGetAANHandle(handle=*0x%x) -> %d", handle, 0x11111111); - *handle = 0x11111111; - return CELL_OK; -} - -s32 cellSurMixerChStripGetAANPortNo(vm::ptr port, u32 type, u32 index) -{ - libmixer.warning("cellSurMixerChStripGetAANPortNo(port=*0x%x, type=0x%x, index=0x%x) -> 0x%x", port, type, index, (type << 16) | index); - *port = (type << 16) | index; - return CELL_OK; -} - -s32 cellSurMixerSetNotifyCallback(vm::ptr func, vm::ptr arg) -{ - libmixer.warning("cellSurMixerSetNotifyCallback(func=*0x%x, arg=*0x%x)", func, arg); - - if (g_surmx.cb) - { - throw EXCEPTION("Callback already set"); - } - - g_surmx.cb = func; - g_surmx.cb_arg = arg; - - return CELL_OK; -} - -s32 cellSurMixerRemoveNotifyCallback(vm::ptr func) -{ - libmixer.warning("cellSurMixerRemoveNotifyCallback(func=*0x%x)", func); - - if (g_surmx.cb != func) - { - throw EXCEPTION("Callback not set"); - } - - g_surmx.cb = vm::null; - - return CELL_OK; -} - -s32 cellSurMixerStart() -{ - libmixer.warning("cellSurMixerStart()"); - - if (g_surmx.audio_port >= AUDIO_PORT_COUNT) - { - return CELL_LIBMIXER_ERROR_NOT_INITIALIZED; - } - - g_audio.ports[g_surmx.audio_port].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_STARTED); - - return CELL_OK; -} - -s32 cellSurMixerSetParameter(u32 param, float value) -{ - libmixer.todo("cellSurMixerSetParameter(param=0x%x, value=%f)", param, value); - return CELL_OK; -} - -s32 cellSurMixerFinalize() -{ - libmixer.warning("cellSurMixerFinalize()"); - - if (g_surmx.audio_port >= AUDIO_PORT_COUNT) - { - return CELL_LIBMIXER_ERROR_NOT_INITIALIZED; - } - - g_audio.ports[g_surmx.audio_port].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_CLOSED); - - return CELL_OK; -} - -s32 cellSurMixerSurBusAddData(u32 busNo, u32 offset, vm::ptr addr, u32 samples) -{ - if (busNo < 8 && samples == 256 && offset == 0) - { - libmixer.trace("cellSurMixerSurBusAddData(busNo=%d, offset=0x%x, addr=0x%x, samples=%d)", busNo, offset, addr, samples); - } - else - { - libmixer.todo("cellSurMixerSurBusAddData(busNo=%d, offset=0x%x, addr=0x%x, samples=%d)", busNo, offset, addr, samples); - return CELL_OK; - } - - std::lock_guard lock(g_surmx.mutex); - - for (u32 i = 0; i < samples; i++) - { - // reverse byte order and mix - g_surmx.mixdata[i * 8 + busNo] += addr[i]; - } - - return CELL_OK; -} - -s32 cellSurMixerChStripSetParameter(u32 type, u32 index, vm::ptr param) -{ - libmixer.todo("cellSurMixerChStripSetParameter(type=%d, index=%d, param=*0x%x)", type, index, param); - return CELL_OK; -} - -s32 cellSurMixerPause(u32 type) -{ - libmixer.warning("cellSurMixerPause(type=%d)", type); - - if (g_surmx.audio_port >= AUDIO_PORT_COUNT) - { - return CELL_LIBMIXER_ERROR_NOT_INITIALIZED; - } - - g_audio.ports[g_surmx.audio_port].state.compare_and_swap(AUDIO_PORT_STATE_STARTED, AUDIO_PORT_STATE_OPENED); - - return CELL_OK; -} - -s32 cellSurMixerGetCurrentBlockTag(vm::ptr tag) -{ - libmixer.trace("cellSurMixerGetCurrentBlockTag(tag=*0x%x)", tag); - - *tag = g_surmx.mixcount; - return CELL_OK; -} - -s32 cellSurMixerGetTimestamp(u64 tag, vm::ptr stamp) -{ - libmixer.trace("cellSurMixerGetTimestamp(tag=0x%llx, stamp=*0x%x)", tag, stamp); - - *stamp = g_audio.start_time + (tag) * 256000000 / 48000; // ??? - return CELL_OK; -} - -void cellSurMixerBeep(u32 arg) -{ - libmixer.todo("cellSurMixerBeep(arg=%d)", arg); - return; -} - -float cellSurMixerUtilGetLevelFromDB(float dB) -{ - libmixer.todo("cellSurMixerUtilGetLevelFromDB(dB=%f)", dB); - throw EXCEPTION(""); -} - -float cellSurMixerUtilGetLevelFromDBIndex(s32 index) -{ - libmixer.todo("cellSurMixerUtilGetLevelFromDBIndex(index=%d)", index); - throw EXCEPTION(""); -} - -float cellSurMixerUtilNoteToRatio(u8 refNote, u8 note) -{ - libmixer.todo("cellSurMixerUtilNoteToRatio(refNote=%d, note=%d)", refNote, note); - throw EXCEPTION(""); -} - -Module<> libmixer("libmixer", []() -{ - g_surmx.audio_port = ~0; - - libmixer.on_stop = []() - { - g_ssp.clear(); - }; - - using namespace PPU_instr; - - REG_SUB(libmixer,, cellAANAddData, - { SPET_MASKED_OPCODE, 0x7c691b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0802a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf821ff91, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf8010080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c802378, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7caa2b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x81690000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c050378, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7cc43378, 0xffffffff }, - { SPET_OPTIONAL_MASKED_OPCODE, 0x78630020, 0xffffffff }, // clrldi r3,r3,32 - { SPET_MASKED_OPCODE, 0x7d465378, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x812b0030, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x80090000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf8410028, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0903a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x80490004, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800421, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xe8410028, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xe8010080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c6307b4, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0803a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38210070, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800020, 0xffffffff }, - ); - - REG_SUB(libmixer,, cellAANConnect, - { SPET_MASKED_OPCODE, 0xf821ff71, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0802a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f830000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf80100a0, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x3c008031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c691b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c8a2378, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x60000003, 0xffffffff }, - SP_LABEL_BR(BNE(cr7, XXX), 0x24), - SET_LABEL(0x24), - { SPET_MASKED_OPCODE, 0x7c0307b4, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xe80100a0, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38210090, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0803a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800020, 0xffffffff }, - SET_LABEL(0x38), - { SPET_MASKED_OPCODE, 0x2f850000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78630020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38810070, 0xffffffff }, - SP_LABEL_BR(BEQ(cr7, XXX), 0x38), - { SPET_MASKED_OPCODE, 0x81690000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38000001, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x91210074, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x90a10070, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x90c10078, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x9141007c, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x812b0018, 0xffffffff }, // - { SPET_MASKED_OPCODE, 0x90010080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x80090000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf8410028, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0903a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x80490004, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800421, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xe8410028, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c601b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0307b4, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xe80100a0, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38210090, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0803a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800020, 0xffffffff }, - ); - - REG_SUB(libmixer,, cellAANDisconnect, - { SPET_MASKED_OPCODE, 0xf821ff71, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0802a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f830000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf80100a0, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x3c008031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c691b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c8a2378, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x60000003, 0xffffffff }, - SP_LABEL_BR(BNE(cr7, XXX), 0x24), - SET_LABEL(0x24), - { SPET_MASKED_OPCODE, 0x7c0307b4, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xe80100a0, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38210090, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0803a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800020, 0xffffffff }, - SET_LABEL(0x38), - { SPET_MASKED_OPCODE, 0x2f850000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78630020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38810070, 0xffffffff }, - SP_LABEL_BR(BEQ(cr7, XXX), 0x38), - { SPET_MASKED_OPCODE, 0x81690000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38000001, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x91210074, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x90a10070, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x90c10078, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x9141007c, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x812b001c, 0xffffffff }, // - { SPET_MASKED_OPCODE, 0x90010080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x80090000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf8410028, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0903a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x80490004, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800421, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xe8410028, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c601b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0307b4, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xe80100a0, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38210090, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0803a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800020, 0xffffffff }, - ); - - REG_SUB(libmixer,, cellSurMixerCreate, - { SPET_MASKED_OPCODE, 0x2f830000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0802a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf821ff51, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfbc100a0, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfb210078, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfb410080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfb610088, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfb810090, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfba10098, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfbe100a8, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf80100c0, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c7e1b78, 0xffffffff }, - SP_LABEL_BR(BNE(cr7, XXX), 0x6c), - { SPET_MASKED_OPCODE, 0x3fe08031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x63ff0003, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xe80100c0, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7fe307b4, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xeb210078, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xeb410080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0803a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xeb610088, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xeb810090, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xeba10098, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xebc100a0, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xebe100a8, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x382100b0, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800020, 0xffffffff }, - SET_LABEL(0x6c), - ); - - REG_SUB(libmixer,, cellSurMixerGetAANHandle, - SP_I(LWZ(r10, r2, XXX)), - { SPET_MASKED_OPCODE, 0x3d607fce, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x616bfffe, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x812a0018, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7d2afe70, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x91230000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7d404a78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c005050, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c00fe70, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c035838, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x3c638031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38630002, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c6307b4, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800020, 0xffffffff }, - ); - - REG_SUB(libmixer,, cellSurMixerChStripGetAANPortNo, - SP_I(LWZ(r9, r2, XXX)), - { SPET_MASKED_OPCODE, 0x7c661b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x3c608031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78c60020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78840020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x60630002, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x80090018, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78a50020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f800000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4d9e0020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78030020, 0xffffffff }, - SP_I(B(XXX, 0, 0)), - ); - - REG_SUB(libmixer,, cellSurMixerSetNotifyCallback, - SP_I(LWZ(r10, r2, XXX)), - { SPET_MASKED_OPCODE, 0x7c0802a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf821ff81, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf8010090, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c6b1b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x3c608031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x812a0018, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c882378, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x60630003, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f890000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f0b0000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x409e0000, 0xffffff00 }, // bne - { SPET_MASKED_OPCODE, 0x3c608031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x60630002, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xe8010090, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c6307b4, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38210080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0803a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x419aff00, 0xffffff00 }, // beq - SP_I(LWZ(r0, r10, XXX)), - { SPET_MASKED_OPCODE, 0x79290020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38810070, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f800000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7d234b78, 0xffffffff } - ); - - REG_SUB(libmixer,, cellSurMixerRemoveNotifyCallback, - SP_I(LWZ(r11, r2, XXX)), - { SPET_MASKED_OPCODE, 0x7c0802a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf821ff81, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf8010090, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c6a1b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x3d208031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x806b0018, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x61290002, 0xffffffff }, // ori - { SPET_MASKED_OPCODE, 0x2f830000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x409e0000, 0xffff0000 }, // bne - { SPET_MASKED_OPCODE, 0xe8010090, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7d2307b4, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38210080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0803a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800020, 0xffffffff } - ); - - REG_SUB(libmixer,, cellSurMixerStart, - { SPET_MASKED_OPCODE, 0xf821ff71, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0802a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfbc10080, 0xffffffff }, - SP_I(LWZ(r30, r2, XXX)), - { SPET_MASKED_OPCODE, 0xf80100a0, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfba10078, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfbe10088, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x801e0018, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f800000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x40000000, 0xf0000000 }, // bne - { SPET_MASKED_OPCODE, 0x3fe08031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x63ff0002, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xe80100a0, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7fe307b4, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xeba10078, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xebc10080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0803a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xebe10088, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38210090, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800020, 0xffffffff } - ); - - REG_SUB(libmixer,, cellSurMixerSetParameter, - { SPET_MASKED_OPCODE, 0xf821ff81, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0802a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfbc10070, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfc000890, 0xffffffff }, - SP_I(LWZ(r30, r2, XXX)), - { SPET_MASKED_OPCODE, 0x3d208031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf8010090, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfbe10078, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x61290002, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c7f1b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x801e0018, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f800000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x409e0000, 0xffff0000 }, // bne - { SPET_MASKED_OPCODE, 0xe8010090, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7d2307b4, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xebc10070, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xebe10078, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0803a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38210080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x801e001c, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2b03001f, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f800000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x419c0000, 0xffff0000 }, // blt - { SPET_MASKED_OPCODE, 0x2b83002b, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x40990000, 0xffff0000 }, // ble - { SPET_MASKED_OPCODE, 0x409d0000, 0xffff0000 }, // ble - ); - - REG_SUB(libmixer,, cellSurMixerFinalize, - { SPET_MASKED_OPCODE, 0xf821ff91, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0802a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf8010080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4bfffd00, 0xffffff00 }, // bl - { SPET_MASKED_OPCODE, 0xe8010080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38600000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38210070, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0803a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf821ff71, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0802a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfba10078, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x80000000, 0xf0000000 }, // lwz - { SPET_MASKED_OPCODE, 0xf80100a0, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x817d0018, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7d635b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x812b0000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x81490000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x800a0000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf8410028, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0903a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x804a0004, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800421, 0xffffffff } - ); - - REG_SUB(libmixer,, cellSurMixerSurBusAddData, - SP_I(LWZ(r10, r2, XXX)), - { SPET_MASKED_OPCODE, 0x7c0802a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf821ff91, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf8010080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c601b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x3d208031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x806a0018, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c8b2378, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7cc73378, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f830000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x61290002, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x409e0000, 0xffff0000 }, // bne - { SPET_MASKED_OPCODE, 0xe8010080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7d2307b4, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38210070, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0803a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78a40020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78050020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x800a001c, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78680020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f800000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7d034378, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x79660020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78e70020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x419c0000, 0xffff0000 } // blt - ); - - REG_SUB(libmixer,, cellSurMixerChStripSetParameter, - SP_I(LWZ(r8, r2, XXX)), - { SPET_MASKED_OPCODE, 0x7c6b1b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x3c608031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c8a2378, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7ca62b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x60630002, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x81280018, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f890000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4d9e0000, 0xffff0000 }, // beqlr - { SPET_MASKED_OPCODE, 0x8008001c, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x79640020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x79450020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f800000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78c60020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4d9c0020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x79230020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x40000000, 0xf0000000 } // b - ); - - REG_SUB(libmixer,, cellSurMixerPause, - SP_I(LWZ(r10, r2, XXX)), - { SPET_MASKED_OPCODE, 0x7c0802a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf821ff81, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf8010090, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x3d208031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfbe10078, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x800a0018, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c7f1b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfbc10070, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f800000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x61290002, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x409e0000, 0xffff0000 }, // bne - { SPET_MASKED_OPCODE, 0xe8010090, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7d2307b4, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xebc10070, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xebe10078, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0803a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38210080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x800a001c, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2b030002, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f800000, 0xffffffff } - ); - - REG_SUB(libmixer,, cellSurMixerGetCurrentBlockTag, - SP_I(LWZ(r11, r2, XXX)), - { SPET_MASKED_OPCODE, 0x3d208031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x61290002, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x880b0020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f800000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x419e0000, 0xffff0000 }, // beq - { SPET_MASKED_OPCODE, 0xe80b0028, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x39200000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf8030000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7d2307b4, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800020, 0xffffffff } - ); - - REG_SUB(libmixer,, cellSurMixerGetTimestamp, - SP_I(LWZ(r11, r2, XXX)), - { SPET_MASKED_OPCODE, 0x7c0802a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf821ff91, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf8010080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c852378, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x3d208031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x880b0020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c641b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78a50020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f800000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x61290002, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x40de0000, 0xffff0000 }, // bne- - { SPET_MASKED_OPCODE, 0xe8010080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7d2307b4, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38210070, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0803a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x806b04d8, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x40000000, 0xf0000000 } // bl - ); - - REG_SUB(libmixer,, cellSurMixerBeep, - SP_I(LWZ(r9, r2, XXX)), - { SPET_MASKED_OPCODE, 0x7c641b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x80690018, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f830000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4d9e0000, 0xffff0000 }, // beqlr - { SPET_MASKED_OPCODE, 0x8009001c, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78630020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78840020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f800000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4d9c0020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x40000000, 0xf0000000 } // b - ); - - REG_SUB(libmixer,, cellSSPlayerCreate, - { SPET_MASKED_OPCODE, 0xf821ff51, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0802a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f840000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf80100c0, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x3c008031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfb210078, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfb410080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfb610088, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfb810090, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfba10098, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfbc100a0, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfbe100a8, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c9a2378, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c791b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x60000003, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x419e0000, 0xffff0000 }, // beq - { SPET_MASKED_OPCODE, 0x83000000, 0xff000000 }, // lwz - { SPET_MASKED_OPCODE, 0x3b800000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x381b0064, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x901b0018, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x5780103a, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38800010, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0007b4, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38a01c70, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7fc0da14, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38c00000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x83be0024, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f9d0000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7ba30020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x41de0000, 0xffff0000 }, // beq- - { SPET_MASKED_OPCODE, 0x40000000, 0xf0000000 } // bl - ); - - REG_SUB(libmixer,, cellSSPlayerRemove, - { SPET_MASKED_OPCODE, 0x7c641b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0802a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x3c608031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f840000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf821ff51, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfb010070, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfb210078, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfb410080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfb610088, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfb810090, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfba10098, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfbc100a0, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfbe100a8, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf80100c0, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x60630003, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x419e0000, 0xffff0000 }, // beq - { SPET_MASKED_OPCODE, 0x81240000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78830020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x83440004, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x83240008, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7b5b0020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x81690000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x800b0000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf8410028, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0903a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x804b0004, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800421, 0xffffffff } - ); - - REG_SUB(libmixer,, cellSSPlayerSetWave, - { SPET_MASKED_OPCODE, 0x7c601b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78840020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f800000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x3c608031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78a50020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x419e0000, 0xffff0000 }, // beq - { SPET_MASKED_OPCODE, 0x78030020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x40000000, 0xf0000000 }, // b - { SPET_MASKED_OPCODE, 0x60630003, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800020, 0xffffffff } - ); - - REG_SUB(libmixer,, cellSSPlayerPlay, - { SPET_MASKED_OPCODE, 0x7c601b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x3c608031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f800000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x60630003, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78840020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4d9e0020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78030020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x40000000, 0xf0000000 }, // b - { SPET_MASKED_OPCODE, 0xf821ff81, 0xffffffff }, // next func - { SPET_MASKED_OPCODE, 0x7c0802a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfbe10078, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c7f1b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x81000000, 0xff000000 }, // lwz - { SPET_MASKED_OPCODE, 0xf8010090, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x39400000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38630010, 0xffffffff } - ); - - REG_SUB(libmixer,, cellSSPlayerStop, - { SPET_MASKED_OPCODE, 0xf821ff91, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0802a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f830000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf8010080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x3c008031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78630020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x60000003, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x419e0000, 0xffff0000 }, // beq - { SPET_MASKED_OPCODE, 0x78840020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x40000000, 0xf0000000 }, // bl - { SPET_MASKED_OPCODE, 0x38000000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0307b4, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xe8010080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x38210070, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x7c0803a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4e800020, 0xffffffff } - ); - - REG_SUB(libmixer,, cellSSPlayerSetParam, - { SPET_MASKED_OPCODE, 0x7c601b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x3c608031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f800000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x60630003, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78840020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4d9e0020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78030020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x40000000, 0xf0000000 }, // b - { SPET_MASKED_OPCODE, 0xf821ff71, 0xffffffff }, // next func - { SPET_MASKED_OPCODE, 0x7c0802a6, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x3d608031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xf80100a0, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x80030068, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x616b0002, 0xffffffff }, - { SPET_MASKED_OPCODE, 0xfbc10080, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f800000, 0xffffffff } - ); - - REG_SUB(libmixer,, cellSSPlayerGetState, - { SPET_MASKED_OPCODE, 0x7c601b78, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x3c608031, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x2f800000, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x60630003, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x4d9e0020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x78030020, 0xffffffff }, - { SPET_MASKED_OPCODE, 0x40000000, 0xf0000000 }, // b - ); - - REG_SUB(libmixer,, cellSurMixerUtilGetLevelFromDB); - REG_SUB(libmixer,, cellSurMixerUtilGetLevelFromDBIndex); - REG_SUB(libmixer,, cellSurMixerUtilNoteToRatio); -}); From 5637c223639d42fc5c86d9ed06c86ec59a778b13 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Mon, 21 Mar 2016 22:43:03 +0300 Subject: [PATCH 05/19] Partial commit: Modules (cell) --- .../{SysCalls => Cell}/Modules/cellAdec.cpp | 14 +- .../Emu/{SysCalls => Cell}/Modules/cellAdec.h | 0 .../{SysCalls => Cell}/Modules/cellAtrac.cpp | 7 +- .../{SysCalls => Cell}/Modules/cellAtrac.h | 2 - .../Modules/cellAtracMulti.cpp | 7 +- .../Modules/cellAtracMulti.h | 2 - rpcs3/Emu/Cell/Modules/cellAudio.cpp | 956 ++++++++ .../{SysCalls => Cell}/Modules/cellAudio.h | 66 +- .../{SysCalls => Cell}/Modules/cellAudioIn.h | 0 .../Modules/cellAudioOut.cpp | 5 +- .../{SysCalls => Cell}/Modules/cellAudioOut.h | 0 .../Modules/cellAvconfExt.cpp | 59 +- .../{SysCalls => Cell}/Modules/cellBgdl.cpp | 15 +- .../{SysCalls => Cell}/Modules/cellCamera.cpp | 43 +- .../{SysCalls => Cell}/Modules/cellCamera.h | 0 .../Modules/cellCelp8Enc.cpp | 7 +- .../Modules/cellCelpEnc.cpp | 7 +- .../{SysCalls => Cell}/Modules/cellDaisy.cpp | 7 +- .../{SysCalls => Cell}/Modules/cellDmux.cpp | 26 +- .../Emu/{SysCalls => Cell}/Modules/cellDmux.h | 6 +- .../{SysCalls => Cell}/Modules/cellFiber.cpp | 99 +- .../{SysCalls => Cell}/Modules/cellFiber.h | 0 .../{SysCalls => Cell}/Modules/cellFont.cpp | 17 +- .../Emu/{SysCalls => Cell}/Modules/cellFont.h | 0 .../{SysCalls => Cell}/Modules/cellFontFT.cpp | 7 +- .../{SysCalls => Cell}/Modules/cellFontFT.h | 0 .../Emu/{SysCalls => Cell}/Modules/cellFs.cpp | 232 +- rpcs3/Emu/{SysCalls => Cell}/Modules/cellFs.h | 0 .../{SysCalls => Cell}/Modules/cellGame.cpp | 133 +- .../Emu/{SysCalls => Cell}/Modules/cellGame.h | 0 .../Modules/cellGameExec.cpp | 7 +- .../{SysCalls => Cell}/Modules/cellGcmSys.cpp | 171 +- .../{SysCalls => Cell}/Modules/cellGcmSys.h | 3 - .../{SysCalls => Cell}/Modules/cellGem.cpp | 81 +- .../Emu/{SysCalls => Cell}/Modules/cellGem.h | 0 .../{SysCalls => Cell}/Modules/cellGifDec.cpp | 26 +- .../{SysCalls => Cell}/Modules/cellGifDec.h | 0 .../{SysCalls => Cell}/Modules/cellHttp.cpp | 10 +- .../Modules/cellHttpUtil.cpp | 7 +- .../{SysCalls => Cell}/Modules/cellImejp.cpp | 89 +- .../{SysCalls => Cell}/Modules/cellJpgDec.cpp | 26 +- .../{SysCalls => Cell}/Modules/cellJpgDec.h | 0 .../{SysCalls => Cell}/Modules/cellJpgEnc.cpp | 7 +- .../Emu/{SysCalls => Cell}/Modules/cellKb.cpp | 61 +- rpcs3/Emu/{SysCalls => Cell}/Modules/cellKb.h | 0 .../Modules/cellKey2char.cpp | 7 +- .../{SysCalls => Cell}/Modules/cellL10n.cpp | 11 +- .../Emu/{SysCalls => Cell}/Modules/cellL10n.h | 0 .../{SysCalls => Cell}/Modules/cellMic.cpp | 12 +- .../Emu/{SysCalls => Cell}/Modules/cellMic.h | 0 .../{SysCalls => Cell}/Modules/cellMouse.cpp | 74 +- .../{SysCalls => Cell}/Modules/cellMouse.h | 6 + .../Modules/cellMsgDialog.cpp | 29 +- .../Modules/cellMsgDialog.h | 0 .../{SysCalls => Cell}/Modules/cellMusic.cpp | 52 +- .../{SysCalls => Cell}/Modules/cellMusic.h | 0 .../Modules/cellMusicDecode.cpp | 47 +- .../Modules/cellMusicExport.cpp | 17 +- rpcs3/Emu/Cell/Modules/cellNetCtl.cpp | 211 ++ .../{SysCalls => Cell}/Modules/cellNetCtl.h | 16 +- .../Modules/cellOskDialog.cpp | 43 +- .../{SysCalls => Cell}/Modules/cellOvis.cpp | 9 +- .../{SysCalls => Cell}/Modules/cellPad.cpp | 146 +- .../Emu/{SysCalls => Cell}/Modules/cellPad.h | 0 .../{SysCalls => Cell}/Modules/cellPamf.cpp | 35 +- .../Emu/{SysCalls => Cell}/Modules/cellPamf.h | 339 +++ .../Modules/cellPhotoDecode.cpp | 15 +- .../Modules/cellPhotoExport.cpp | 25 +- .../Modules/cellPhotoImport.cpp | 7 +- .../Emu/{SysCalls => Cell}/Modules/cellPng.h | 0 .../{SysCalls => Cell}/Modules/cellPngDec.cpp | 19 +- .../{SysCalls => Cell}/Modules/cellPngDec.h | 0 .../{SysCalls => Cell}/Modules/cellPngEnc.cpp | 7 +- .../{SysCalls => Cell}/Modules/cellPrint.cpp | 35 +- .../{SysCalls => Cell}/Modules/cellRec.cpp | 7 +- .../Modules/cellRemotePlay.cpp | 7 +- rpcs3/Emu/Cell/Modules/cellResc.cpp | 180 ++ .../Emu/{SysCalls => Cell}/Modules/cellResc.h | 43 - rpcs3/Emu/Cell/Modules/cellRtc.cpp | 295 +++ .../Emu/{SysCalls => Cell}/Modules/cellRtc.h | 0 .../{SysCalls => Cell}/Modules/cellRudp.cpp | 9 +- .../Emu/{SysCalls => Cell}/Modules/cellRudp.h | 0 .../{SysCalls => Cell}/Modules/cellSail.cpp | 17 +- .../Emu/{SysCalls => Cell}/Modules/cellSail.h | 8 +- .../Modules/cellSailRec.cpp | 7 +- .../Modules/cellSaveData.cpp | 170 +- .../{SysCalls => Cell}/Modules/cellSaveData.h | 0 .../Modules/cellScreenshot.cpp | 16 +- .../Modules/cellScreenshot.h | 0 .../{SysCalls => Cell}/Modules/cellSearch.cpp | 48 +- .../{SysCalls => Cell}/Modules/cellSearch.h | 0 .../{SysCalls => Cell}/Modules/cellSheap.cpp | 7 +- .../{SysCalls => Cell}/Modules/cellSpudll.cpp | 7 +- .../{SysCalls => Cell}/Modules/cellSpurs.cpp | 81 +- .../{SysCalls => Cell}/Modules/cellSpurs.h | 1837 ++++++++------- .../Modules/cellSpursJq.cpp | 14 +- .../{SysCalls => Cell}/Modules/cellSpursJq.h | 0 rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp | 1986 +++++++++++++++++ .../{SysCalls => Cell}/Modules/cellSsl.cpp | 7 +- .../Modules/cellStorage.cpp | 5 +- .../Modules/cellSubdisplay.cpp | 7 +- .../Modules/cellSubdisplay.h | 0 .../{SysCalls => Cell}/Modules/cellSync.cpp | 248 +- .../Emu/{SysCalls => Cell}/Modules/cellSync.h | 141 +- .../{SysCalls => Cell}/Modules/cellSync2.cpp | 34 +- .../{SysCalls => Cell}/Modules/cellSync2.h | 0 .../Modules/cellSysconf.cpp | 11 +- .../Modules/cellSysmodule.cpp | 578 +++-- .../Modules/cellSysutil.cpp | 136 +- .../{SysCalls => Cell}/Modules/cellSysutil.h | 7 +- .../Modules/cellSysutilAp.cpp | 7 +- .../Modules/cellSysutilAvc.cpp | 9 +- .../Modules/cellSysutilAvc2.cpp | 19 +- .../Modules/cellSysutilAvc2.h | 0 .../Modules/cellSysutilMisc.cpp | 7 +- .../{SysCalls => Cell}/Modules/cellUsbd.cpp | 7 +- .../Emu/{SysCalls => Cell}/Modules/cellUsbd.h | 0 .../Modules/cellUsbpspcm.cpp | 7 +- .../Modules/cellUserInfo.cpp | 27 +- .../{SysCalls => Cell}/Modules/cellUserInfo.h | 20 +- .../{SysCalls => Cell}/Modules/cellVdec.cpp | 50 +- .../Emu/{SysCalls => Cell}/Modules/cellVdec.h | 0 rpcs3/Emu/Cell/Modules/cellVideoExport.cpp | 45 + rpcs3/Emu/Cell/Modules/cellVideoOut.cpp | 239 ++ rpcs3/Emu/Cell/Modules/cellVideoOut.h | 262 +++ rpcs3/Emu/Cell/Modules/cellVideoUpload.cpp | 14 + .../{SysCalls => Cell}/Modules/cellVoice.cpp | 7 +- .../{SysCalls => Cell}/Modules/cellVpost.cpp | 7 +- .../{SysCalls => Cell}/Modules/cellVpost.h | 0 .../Modules/cellWebBrowser.cpp | 5 +- .../Modules/cellWebBrowser.h | 0 rpcs3/Emu/SysCalls/Modules/cellAudio.cpp | 1027 --------- rpcs3/Emu/SysCalls/Modules/cellNetCtl.cpp | 455 ---- rpcs3/Emu/SysCalls/Modules/cellResc.cpp | 1287 ----------- rpcs3/Emu/SysCalls/Modules/cellRtc.cpp | 488 ---- rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp | 1715 -------------- .../Emu/SysCalls/Modules/cellVideoExport.cpp | 46 - rpcs3/Emu/SysCalls/Modules/cellVideoOut.cpp | 206 -- rpcs3/Emu/SysCalls/Modules/cellVideoOut.h | 282 --- .../Emu/SysCalls/Modules/cellVideoUpload.cpp | 15 - 140 files changed, 7290 insertions(+), 8243 deletions(-) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellAdec.cpp (98%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellAdec.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellAtrac.cpp (98%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellAtrac.h (98%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellAtracMulti.cpp (98%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellAtracMulti.h (98%) create mode 100644 rpcs3/Emu/Cell/Modules/cellAudio.cpp rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellAudio.h (76%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellAudioIn.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellAudioOut.cpp (98%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellAudioOut.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellAvconfExt.cpp (63%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellBgdl.cpp (69%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellCamera.cpp (92%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellCamera.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellCelp8Enc.cpp (91%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellCelpEnc.cpp (91%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellDaisy.cpp (98%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellDmux.cpp (98%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellDmux.h (99%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellFiber.cpp (61%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellFiber.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellFont.cpp (98%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellFont.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellFontFT.cpp (85%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellFontFT.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellFs.cpp (79%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellFs.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellGame.cpp (83%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellGame.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellGameExec.cpp (89%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellGcmSys.cpp (89%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellGcmSys.h (87%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellGem.cpp (69%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellGem.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellGifDec.cpp (94%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellGifDec.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellHttp.cpp (98%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellHttpUtil.cpp (95%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellImejp.cpp (62%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellJpgDec.cpp (94%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellJpgDec.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellJpgEnc.cpp (92%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellKb.cpp (81%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellKb.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellKey2char.cpp (88%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellL10n.cpp (99%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellL10n.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellMic.cpp (97%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellMic.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellMouse.cpp (71%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellMouse.h (93%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellMsgDialog.cpp (94%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellMsgDialog.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellMusic.cpp (61%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellMusic.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellMusicDecode.cpp (65%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellMusicExport.cpp (72%) create mode 100644 rpcs3/Emu/Cell/Modules/cellNetCtl.cpp rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellNetCtl.h (97%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellOskDialog.cpp (68%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellOvis.cpp (82%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellPad.cpp (85%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellPad.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellPamf.cpp (95%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellPamf.h (59%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellPhotoDecode.cpp (72%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellPhotoExport.cpp (70%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellPhotoImport.cpp (89%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellPng.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellPngDec.cpp (98%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellPngDec.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellPngEnc.cpp (91%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellPrint.cpp (66%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellRec.cpp (83%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellRemotePlay.cpp (87%) create mode 100644 rpcs3/Emu/Cell/Modules/cellResc.cpp rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellResc.h (68%) create mode 100644 rpcs3/Emu/Cell/Modules/cellRtc.cpp rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellRtc.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellRudp.cpp (97%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellRudp.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSail.cpp (98%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSail.h (99%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSailRec.cpp (97%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSaveData.cpp (80%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSaveData.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellScreenshot.cpp (59%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellScreenshot.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSearch.cpp (60%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSearch.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSheap.cpp (95%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSpudll.cpp (75%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSpurs.cpp (98%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSpurs.h (96%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSpursJq.cpp (97%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSpursJq.h (100%) create mode 100644 rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSsl.cpp (93%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellStorage.cpp (79%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSubdisplay.cpp (92%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSubdisplay.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSync.cpp (79%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSync.h (58%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSync2.cpp (89%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSync2.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSysconf.cpp (58%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSysmodule.cpp (53%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSysutil.cpp (76%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSysutil.h (97%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSysutilAp.cpp (87%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSysutilAvc.cpp (96%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSysutilAvc2.cpp (94%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSysutilAvc2.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellSysutilMisc.cpp (86%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellUsbd.cpp (96%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellUsbd.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellUsbpspcm.cpp (96%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellUserInfo.cpp (69%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellUserInfo.h (73%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellVdec.cpp (96%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellVdec.h (100%) create mode 100644 rpcs3/Emu/Cell/Modules/cellVideoExport.cpp create mode 100644 rpcs3/Emu/Cell/Modules/cellVideoOut.cpp create mode 100644 rpcs3/Emu/Cell/Modules/cellVideoOut.h create mode 100644 rpcs3/Emu/Cell/Modules/cellVideoUpload.cpp rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellVoice.cpp (97%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellVpost.cpp (97%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellVpost.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellWebBrowser.cpp (98%) rename rpcs3/Emu/{SysCalls => Cell}/Modules/cellWebBrowser.h (100%) delete mode 100644 rpcs3/Emu/SysCalls/Modules/cellAudio.cpp delete mode 100644 rpcs3/Emu/SysCalls/Modules/cellNetCtl.cpp delete mode 100644 rpcs3/Emu/SysCalls/Modules/cellResc.cpp delete mode 100644 rpcs3/Emu/SysCalls/Modules/cellRtc.cpp delete mode 100644 rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp delete mode 100644 rpcs3/Emu/SysCalls/Modules/cellVideoExport.cpp delete mode 100644 rpcs3/Emu/SysCalls/Modules/cellVideoOut.cpp delete mode 100644 rpcs3/Emu/SysCalls/Modules/cellVideoOut.h delete mode 100644 rpcs3/Emu/SysCalls/Modules/cellVideoUpload.cpp diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp b/rpcs3/Emu/Cell/Modules/cellAdec.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellAdec.cpp rename to rpcs3/Emu/Cell/Modules/cellAdec.cpp index 3a1234f6ae..ba9b76fe19 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAdec.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" extern std::mutex g_mutex_avcodec_open2; @@ -16,7 +15,7 @@ extern "C" #include "cellPamf.h" #include "cellAdec.h" -extern Module<> cellAdec; +LOG_CHANNEL(cellAdec); AudioDecoder::AudioDecoder(s32 type, u32 addr, u32 size, vm::ptr func, u32 arg) : type(type) @@ -467,8 +466,9 @@ void adecOpen(u32 adec_id) // TODO: call from the constructor }; - adec.adecCb->run(); - adec.adecCb->exec(); + adec.adecCb->cpu_init(); + adec.adecCb->state -= cpu_state::stop; + adec.adecCb->safe_notify(); } bool adecCheckType(s32 type) @@ -572,7 +572,7 @@ s32 cellAdecClose(u32 handle) std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } - idm::remove(adec->adecCb->get_id()); + idm::remove(adec->adecCb->id); idm::remove(handle); return CELL_OK; } @@ -863,7 +863,7 @@ s32 cellAdecGetPcmItem(u32 handle, vm::pptr pcmItem) return CELL_OK; } -Module<> cellAdec("cellAdec", []() +DECLARE(ppu_module_manager::cellAdec)("cellAdec", []() { REG_FUNC(cellAdec, cellAdecQueryAttr); REG_FUNC(cellAdec, cellAdecOpen); diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.h b/rpcs3/Emu/Cell/Modules/cellAdec.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellAdec.h rename to rpcs3/Emu/Cell/Modules/cellAdec.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellAtrac.cpp b/rpcs3/Emu/Cell/Modules/cellAtrac.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellAtrac.cpp rename to rpcs3/Emu/Cell/Modules/cellAtrac.cpp index 977aa05480..d251fe9bcb 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAtrac.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAtrac.cpp @@ -1,10 +1,11 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellAtrac.h" +LOG_CHANNEL(cellAtrac); + s32 cellAtracSetDataAndGetMemSize(vm::ptr pHandle, vm::ptr pucBufferAddr, u32 uiReadByte, u32 uiBufferByte, vm::ptr puiWorkMemByte) { cellAtrac.warning("cellAtracSetDataAndGetMemSize(pHandle=*0x%x, pucBufferAddr=*0x%x, uiReadByte=0x%x, uiBufferByte=0x%x, puiWorkMemByte=*0x%x)", pHandle, pucBufferAddr, uiReadByte, uiBufferByte, puiWorkMemByte); @@ -194,7 +195,7 @@ s32 cellAtracGetInternalErrorInfo(vm::ptr pHandle, vm::ptr return CELL_OK; } -Module<> cellAtrac("cellAtrac", []() +DECLARE(ppu_module_manager::cellAtrac)("cellAtrac", []() { REG_FUNC(cellAtrac, cellAtracSetDataAndGetMemSize); diff --git a/rpcs3/Emu/SysCalls/Modules/cellAtrac.h b/rpcs3/Emu/Cell/Modules/cellAtrac.h similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellAtrac.h rename to rpcs3/Emu/Cell/Modules/cellAtrac.h index 391c838959..e9cca6f3bf 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAtrac.h +++ b/rpcs3/Emu/Cell/Modules/cellAtrac.h @@ -57,5 +57,3 @@ struct CellAtracExtRes vm::ptr pSpurs; u8 priority[8]; }; - -extern Module<> cellAtrac; diff --git a/rpcs3/Emu/SysCalls/Modules/cellAtracMulti.cpp b/rpcs3/Emu/Cell/Modules/cellAtracMulti.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellAtracMulti.cpp rename to rpcs3/Emu/Cell/Modules/cellAtracMulti.cpp index 5e8c78596d..75e1263f62 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAtracMulti.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAtracMulti.cpp @@ -1,10 +1,11 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellAtracMulti.h" +LOG_CHANNEL(cellAtracMulti); + s32 cellAtracMultiSetDataAndGetMemSize(vm::ptr pHandle, vm::ptr pucBufferAddr, u32 uiReadByte, u32 uiBufferByte, u32 uiOutputChNum, vm::ptr piTrackArray, vm::ptr puiWorkMemByte) { cellAtracMulti.warning("cellAtracMultiSetDataAndGetMemSize(pHandle=*0x%x, pucBufferAddr=*0x%x, uiReadByte=0x%x, uiBufferByte=0x%x, uiOutputChNum=%d, piTrackArray=*0x%x, puiWorkMemByte=*0x%x)", @@ -202,7 +203,7 @@ s32 cellAtracMultiGetInternalErrorInfo(vm::ptr pHandle, vm return CELL_OK; } -Module<> cellAtracMulti("cellAtrac", []() +DECLARE(ppu_module_manager::cellAtracMulti)("cellAtracMulti", []() { REG_FUNC(cellAtracMulti, cellAtracMultiSetDataAndGetMemSize); diff --git a/rpcs3/Emu/SysCalls/Modules/cellAtracMulti.h b/rpcs3/Emu/Cell/Modules/cellAtracMulti.h similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellAtracMulti.h rename to rpcs3/Emu/Cell/Modules/cellAtracMulti.h index d2807ae34c..51d5b7d889 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAtracMulti.h +++ b/rpcs3/Emu/Cell/Modules/cellAtracMulti.h @@ -58,5 +58,3 @@ struct CellAtracMultiExtRes vm::ptr pSpurs; u8 priority[8]; }; - -extern Module<> cellAtracMulti; diff --git a/rpcs3/Emu/Cell/Modules/cellAudio.cpp b/rpcs3/Emu/Cell/Modules/cellAudio.cpp new file mode 100644 index 0000000000..d5239f2557 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellAudio.cpp @@ -0,0 +1,956 @@ +#include "stdafx.h" +#include "Emu/System.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" + +#include "Emu/Cell/lv2/sys_event.h" +#include "Emu/Audio/AudioDumper.h" +#include "Emu/Audio/AudioThread.h" +#include "cellAudio.h" + +LOG_CHANNEL(cellAudio); + +cfg::bool_entry g_cfg_audio_dump_to_file(cfg::root.audio, "Dump to file"); +cfg::bool_entry g_cfg_audio_convert_to_u16(cfg::root.audio, "Convert to 16 bit"); + +void audio_config::on_task() +{ + for (u32 i = 0; i < AUDIO_PORT_COUNT; i++) + { + ports[i].number = i; + ports[i].addr = m_buffer + AUDIO_PORT_OFFSET * i; + ports[i].index = m_indexes + i; + } + + AudioDumper m_dump(g_cfg_audio_dump_to_file ? 2 : 0); // Init AudioDumper for 2 channels if enabled + + float buf2ch[2 * BUFFER_SIZE]{}; // intermediate buffer for 2 channels + float buf8ch[8 * BUFFER_SIZE]{}; // intermediate buffer for 8 channels + + static const size_t out_buffer_size = 8 * BUFFER_SIZE; // output buffer for 8 channels + + std::unique_ptr out_buffer[BUFFER_NUM]; + + for (u32 i = 0; i < BUFFER_NUM; i++) + { + out_buffer[i].reset(new float[out_buffer_size] {}); + } + + const auto audio = Emu.GetCallbacks().get_audio(); + audio->Open(buf8ch, out_buffer_size * (g_cfg_audio_convert_to_u16 ? 2 : 4)); + + while (fxm::check() && !Emu.IsStopped()) + { + if (Emu.IsPaused()) + { + std::this_thread::sleep_for(1ms); // hack + continue; + } + + const u64 stamp0 = get_system_time(); + + const u64 time_pos = stamp0 - start_time - Emu.GetPauseTime(); + + // TODO: send beforemix event (in ~2,6 ms before mixing) + + // precise time of sleeping: 5,(3) ms (or 256/48000 sec) + const u64 expected_time = m_counter * AUDIO_SAMPLES * 1000000 / 48000; + if (expected_time >= time_pos) + { + std::this_thread::sleep_for(1ms); // hack + continue; + } + + m_counter++; + + const u32 out_pos = m_counter % BUFFER_NUM; + + bool first_mix = true; + + // mixing: + for (auto& port : ports) + { + if (port.state != audio_port_state::started) continue; + + const u32 block_size = port.channel * AUDIO_SAMPLES; + const u32 position = port.tag % port.block; // old value + const u32 buf_addr = port.addr.addr() + position * block_size * sizeof(float); + + auto buf = vm::_ptr(buf_addr); + + static const float k = 1.0f; // may be 1.0f + const float& m = port.level; + + auto step_volume = [](audio_port& port) // part of cellAudioSetPortLevel functionality + { + const auto param = port.level_set.load(); + + if (param.inc != 0.0f) + { + port.level += param.inc; + const bool dec = param.inc < 0.0f; + + if ((!dec && param.value - port.level <= 0.0f) || (dec && param.value - port.level >= 0.0f)) + { + port.level = param.value; + port.level_set.compare_and_swap(param, { param.value, 0.0f }); + } + } + }; + + if (port.channel == 2) + { + if (first_mix) + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + step_volume(port); + + // reverse byte order + const float left = buf[i + 0] * m; + const float right = buf[i + 1] * m; + + buf2ch[i + 0] = left; + buf2ch[i + 1] = right; + + buf8ch[i * 4 + 0] = left; + buf8ch[i * 4 + 1] = right; + buf8ch[i * 4 + 2] = 0.0f; + buf8ch[i * 4 + 3] = 0.0f; + buf8ch[i * 4 + 4] = 0.0f; + buf8ch[i * 4 + 5] = 0.0f; + buf8ch[i * 4 + 6] = 0.0f; + buf8ch[i * 4 + 7] = 0.0f; + } + first_mix = false; + } + else + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + step_volume(port); + + const float left = buf[i + 0] * m; + const float right = buf[i + 1] * m; + + buf2ch[i + 0] += left; + buf2ch[i + 1] += right; + + buf8ch[i * 4 + 0] += left; + buf8ch[i * 4 + 1] += right; + } + } + } + else if (port.channel == 8) + { + if (first_mix) + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + step_volume(port); + + const float left = buf[i * 4 + 0] * m; + const float right = buf[i * 4 + 1] * m; + const float center = buf[i * 4 + 2] * m; + const float low_freq = buf[i * 4 + 3] * m; + const float rear_left = buf[i * 4 + 4] * m; + const float rear_right = buf[i * 4 + 5] * m; + const float side_left = buf[i * 4 + 6] * m; + const float side_right = buf[i * 4 + 7] * m; + + const float mid = (center + low_freq) * 0.708f; + buf2ch[i + 0] = (left + rear_left + side_left + mid) * k; + buf2ch[i + 1] = (right + rear_right + side_right + mid) * k; + + buf8ch[i * 4 + 0] = left; + buf8ch[i * 4 + 1] = right; + buf8ch[i * 4 + 2] = center; + buf8ch[i * 4 + 3] = low_freq; + buf8ch[i * 4 + 4] = rear_left; + buf8ch[i * 4 + 5] = rear_right; + buf8ch[i * 4 + 6] = side_left; + buf8ch[i * 4 + 7] = side_right; + } + first_mix = false; + } + else + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + step_volume(port); + + const float left = buf[i * 4 + 0] * m; + const float right = buf[i * 4 + 1] * m; + const float center = buf[i * 4 + 2] * m; + const float low_freq = buf[i * 4 + 3] * m; + const float rear_left = buf[i * 4 + 4] * m; + const float rear_right = buf[i * 4 + 5] * m; + const float side_left = buf[i * 4 + 6] * m; + const float side_right = buf[i * 4 + 7] * m; + + const float mid = (center + low_freq) * 0.708f; + buf2ch[i + 0] += (left + rear_left + side_left + mid) * k; + buf2ch[i + 1] += (right + rear_right + side_right + mid) * k; + + buf8ch[i * 4 + 0] += left; + buf8ch[i * 4 + 1] += right; + buf8ch[i * 4 + 2] += center; + buf8ch[i * 4 + 3] += low_freq; + buf8ch[i * 4 + 4] += rear_left; + buf8ch[i * 4 + 5] += rear_right; + buf8ch[i * 4 + 6] += side_left; + buf8ch[i * 4 + 7] += side_right; + } + } + } + else + { + throw EXCEPTION("Unknown channel count (port=%u, channel=%d)", port.number, port.channel); + } + + memset(buf, 0, block_size * sizeof(float)); + } + + + if (!first_mix) + { + // copy output data (2 ch) + //for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i++) + //{ + // out_buffer[out_pos][i] = buf2ch[i]; + //} + + // copy output data (8 ch) + for (u32 i = 0; i < (sizeof(buf8ch) / sizeof(float)); i++) + { + out_buffer[out_pos][i] = buf8ch[i]; + } + } + + const u64 stamp1 = get_system_time(); + + if (first_mix) + { + memset(out_buffer[out_pos].get(), 0, out_buffer_size * sizeof(float)); + } + + if (g_cfg_audio_convert_to_u16) + { + // convert the data from float to u16 with clipping: + // 2x MULPS + // 2x MAXPS (optional) + // 2x MINPS (optional) + // 2x CVTPS2DQ (converts float to s32) + // PACKSSDW (converts s32 to s16 with signed saturation) + + u16 buf_u16[out_buffer_size]; + for (size_t i = 0; i < out_buffer_size; i += 8) + { + const auto scale = _mm_set1_ps(0x8000); + (__m128i&)(buf_u16[i]) = _mm_packs_epi32( + _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(out_buffer[out_pos].get() + i), scale)), + _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(out_buffer[out_pos].get() + i + 4), scale))); + } + + audio->AddData(buf_u16, out_buffer_size * sizeof(u16)); + } + else + { + audio->AddData(out_buffer[out_pos].get(), out_buffer_size * sizeof(float)); + } + + const u64 stamp2 = get_system_time(); + + { + // update indices: + + for (u32 i = 0; i < AUDIO_PORT_COUNT; i++) + { + audio_port& port = ports[i]; + + if (port.state != audio_port_state::started) continue; + + u32 position = port.tag % port.block; // old value + port.counter = m_counter; + port.tag++; // absolute index of block that will be read + m_indexes[i] = (position + 1) % port.block; // write new value + } + + // send aftermix event (normal audio event) + + LV2_LOCK; + + std::lock_guard lock(mutex); + + for (u64 key : keys) + { + if (auto&& queue = lv2_event_queue_t::find(key)) + { + if (queue->events() < queue->size) + queue->push(lv2_lock, 0, 0, 0, 0); // TODO: check arguments + } + } + } + + const u64 stamp3 = get_system_time(); + + switch (m_dump.GetCh()) + { + case 2: m_dump.WriteData(&buf2ch, sizeof(buf2ch)); break; // write file data (2 ch) + case 8: m_dump.WriteData(&buf8ch, sizeof(buf8ch)); break; // write file data (8 ch) + } + + cellAudio.trace("Audio perf: start=%d (access=%d, AddData=%d, events=%d, dump=%d)", + time_pos, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3); + } +} + +s32 cellAudioInit() +{ + cellAudio.warning("cellAudioInit()"); + + // Start audio thread + const auto g_audio = fxm::make(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_ALREADY_INIT; + } + + return CELL_OK; +} + +s32 cellAudioQuit() +{ + cellAudio.warning("cellAudioQuit()"); + + // Stop audio thread + const auto g_audio = fxm::withdraw(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + return CELL_OK; +} + +s32 cellAudioPortOpen(vm::ptr audioParam, vm::ptr portNum) +{ + cellAudio.warning("cellAudioPortOpen(audioParam=*0x%x, portNum=*0x%x)", audioParam, portNum); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (!audioParam || !portNum) + { + return CELL_AUDIO_ERROR_PARAM; + } + + const u64 channel = audioParam->nChannel; + const u64 block = audioParam->nBlock; + const u64 attr = audioParam->attr; + + // check attributes + if (channel != CELL_AUDIO_PORT_2CH && + channel != CELL_AUDIO_PORT_8CH && + channel) + { + return CELL_AUDIO_ERROR_PARAM; + } + + if (block != CELL_AUDIO_BLOCK_8 && + block != CELL_AUDIO_BLOCK_16 && + block != 2 && + block != 4 && + block != 32) + { + return CELL_AUDIO_ERROR_PARAM; + } + + // list unsupported flags + if (attr & CELL_AUDIO_PORTATTR_BGM) + { + cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_BGM"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_SECONDARY) + { + cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_SECONDARY"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_0) + { + cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_0"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_1) + { + cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_1"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_2) + { + cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_2"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_3) + { + cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_3"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_NO_ROUTE) + { + cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_NO_ROUTE"); + } + if (attr & 0xFFFFFFFFF0EFEFEEULL) + { + cellAudio.todo("cellAudioPortOpen(): unknown attributes (0x%llx)", attr); + } + + // Open audio port + const auto port = g_audio->open_port(); + + if (!port) + { + return CELL_AUDIO_ERROR_PORT_FULL; + } + + port->channel = ::narrow(channel); + port->block = ::narrow(block); + port->attr = attr; + port->size = ::narrow(channel * block * AUDIO_SAMPLES * sizeof(f32)); + port->tag = 0; + + if (attr & CELL_AUDIO_PORTATTR_INITLEVEL) + { + port->level = audioParam->level; + } + else + { + port->level = 1.0f; + } + + port->level_set.store({ port->level, 0.0f }); + + *portNum = port->number; + return CELL_OK; +} + +s32 cellAudioGetPortConfig(u32 portNum, vm::ptr portConfig) +{ + cellAudio.warning("cellAudioGetPortConfig(portNum=%d, portConfig=*0x%x)", portNum, portConfig); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (!portConfig || portNum >= AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + audio_port& port = g_audio->ports[portNum]; + + portConfig->readIndexAddr = port.index; + + switch (auto state = port.state.load()) + { + case audio_port_state::closed: portConfig->status = CELL_AUDIO_STATUS_CLOSE; break; + case audio_port_state::opened: portConfig->status = CELL_AUDIO_STATUS_READY; break; + case audio_port_state::started: portConfig->status = CELL_AUDIO_STATUS_RUN; break; + default: throw fmt::exception("Invalid port state (%d: %d)", portNum, state); + } + + portConfig->nChannel = port.channel; + portConfig->nBlock = port.block; + portConfig->portSize = port.size; + portConfig->portAddr = port.addr.addr(); + return CELL_OK; +} + +s32 cellAudioPortStart(u32 portNum) +{ + cellAudio.warning("cellAudioPortStart(portNum=%d)", portNum); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + switch (auto state = g_audio->ports[portNum].state.compare_and_swap(audio_port_state::opened, audio_port_state::started)) + { + case audio_port_state::closed: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case audio_port_state::started: return CELL_AUDIO_ERROR_PORT_ALREADY_RUN; + case audio_port_state::opened: return CELL_OK; + default: throw fmt::exception("Invalid port state (%d: %d)", portNum, state); + } +} + +s32 cellAudioPortClose(u32 portNum) +{ + cellAudio.warning("cellAudioPortClose(portNum=%d)", portNum); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + switch (auto state = g_audio->ports[portNum].state.exchange(audio_port_state::closed)) + { + case audio_port_state::closed: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case audio_port_state::started: return CELL_OK; + case audio_port_state::opened: return CELL_OK; + default: throw fmt::exception("Invalid port state (%d: %d)", portNum, state); + } +} + +s32 cellAudioPortStop(u32 portNum) +{ + cellAudio.warning("cellAudioPortStop(portNum=%d)", portNum); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + switch (auto state = g_audio->ports[portNum].state.compare_and_swap(audio_port_state::started, audio_port_state::opened)) + { + case audio_port_state::closed: return CELL_AUDIO_ERROR_PORT_NOT_RUN; + case audio_port_state::started: return CELL_OK; + case audio_port_state::opened: return CELL_AUDIO_ERROR_PORT_NOT_RUN; + default: throw fmt::exception("Invalid port state (%d: %d)", portNum, state); + } +} + +s32 cellAudioGetPortTimestamp(u32 portNum, u64 tag, vm::ptr stamp) +{ + cellAudio.trace("cellAudioGetPortTimestamp(portNum=%d, tag=0x%llx, stamp=*0x%x)", portNum, tag, stamp); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + audio_port& port = g_audio->ports[portNum]; + + if (port.state == audio_port_state::closed) + { + return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + } + + // TODO: check tag (CELL_AUDIO_ERROR_TAG_NOT_FOUND error) + + *stamp = g_audio->start_time + Emu.GetPauseTime() + (port.counter + (tag - port.tag)) * 256000000 / 48000; + + return CELL_OK; +} + +s32 cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, vm::ptr tag) +{ + cellAudio.trace("cellAudioGetPortBlockTag(portNum=%d, blockNo=0x%llx, tag=*0x%x)", portNum, blockNo, tag); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + audio_port& port = g_audio->ports[portNum]; + + if (port.state == audio_port_state::closed) + { + return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + } + + if (blockNo >= port.block) + { + return CELL_AUDIO_ERROR_PARAM; + } + + u64 tag_base = port.tag; + if (tag_base % port.block > blockNo) + { + tag_base &= ~(port.block - 1); + tag_base += port.block; + } + else + { + tag_base &= ~(port.block - 1); + } + *tag = tag_base + blockNo; + + return CELL_OK; +} + +s32 cellAudioSetPortLevel(u32 portNum, float level) +{ + cellAudio.trace("cellAudioSetPortLevel(portNum=%d, level=%f)", portNum, level); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + audio_port& port = g_audio->ports[portNum]; + + if (port.state == audio_port_state::closed) + { + return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + } + + if (level >= 0.0f) + { + port.level_set.exchange({ level, (port.level - level) / 624.0f }); + } + else + { + cellAudio.todo("cellAudioSetPortLevel(%d): negative level value (%f)", portNum, level); + } + + return CELL_OK; +} + +s32 cellAudioCreateNotifyEventQueue(vm::ptr id, vm::ptr key) +{ + cellAudio.warning("cellAudioCreateNotifyEventQueue(id=*0x%x, key=*0x%x)", id, key); + + for (u64 k = 0; k < 100; k++) + { + const u64 key_value = 0x80004d494f323221ull + k; + + // Create an event queue "bruteforcing" an available key + if (auto&& queue = lv2_event_queue_t::make(SYS_SYNC_FIFO, SYS_PPU_QUEUE, 0, key_value, 32)) + { + *id = queue->id; + *key = key_value; + + return CELL_OK; + } + } + + return CELL_AUDIO_ERROR_EVENT_QUEUE; +} + +s32 cellAudioCreateNotifyEventQueueEx(vm::ptr id, vm::ptr key, u32 iFlags) +{ + cellAudio.todo("cellAudioCreateNotifyEventQueueEx(id=*0x%x, key=*0x%x, iFlags=0x%x)", id, key, iFlags); + + if (iFlags & ~CELL_AUDIO_CREATEEVENTFLAG_SPU) + { + return CELL_AUDIO_ERROR_PARAM; + } + + // TODO + + return CELL_AUDIO_ERROR_EVENT_QUEUE; +} + +s32 cellAudioSetNotifyEventQueue(u64 key) +{ + cellAudio.warning("cellAudioSetNotifyEventQueue(key=0x%llx)", key); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + std::lock_guard lock(g_audio->mutex); + + for (auto k : g_audio->keys) // check for duplicates + { + if (k == key) + { + return CELL_AUDIO_ERROR_TRANS_EVENT; + } + } + + g_audio->keys.emplace_back(key); + + return CELL_OK; +} + +s32 cellAudioSetNotifyEventQueueEx(u64 key, u32 iFlags) +{ + cellAudio.todo("cellAudioSetNotifyEventQueueEx(key=0x%llx, iFlags=0x%x)", key, iFlags); + + // TODO + + return CELL_OK; +} + +s32 cellAudioRemoveNotifyEventQueue(u64 key) +{ + cellAudio.warning("cellAudioRemoveNotifyEventQueue(key=0x%llx)", key); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + std::lock_guard lock(g_audio->mutex); + + for (auto i = g_audio->keys.begin(); i != g_audio->keys.end(); i++) + { + if (*i == key) + { + g_audio->keys.erase(i); + + return CELL_OK; + } + } + + return CELL_AUDIO_ERROR_TRANS_EVENT; +} + +s32 cellAudioRemoveNotifyEventQueueEx(u64 key, u32 iFlags) +{ + cellAudio.todo("cellAudioRemoveNotifyEventQueueEx(key=0x%llx, iFlags=0x%x)", key, iFlags); + + // TODO + + return CELL_OK; +} + +s32 cellAudioAddData(u32 portNum, vm::ptr src, u32 samples, float volume) +{ + cellAudio.trace("cellAudioAddData(portNum=%d, src=*0x%x, samples=%d, volume=%f)", portNum, src, samples, volume); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT || !src || !src.aligned()) + { + return CELL_AUDIO_ERROR_PARAM; + } + + if (samples != 256) + { + // despite the docs, seems that only fixed value is supported + cellAudio.error("cellAudioAddData(): invalid samples value (%d)", samples); + return CELL_AUDIO_ERROR_PARAM; + } + + const audio_port& port = g_audio->ports[portNum]; + + const auto dst = vm::ptr::make(port.addr.addr() + u32(port.tag % port.block) * port.channel * 256 * SIZE_32(float)); + + for (u32 i = 0; i < samples * port.channel; i++) + { + dst[i] += src[i] * volume; // mix all channels + } + + return CELL_OK; +} + +s32 cellAudioAdd2chData(u32 portNum, vm::ptr src, u32 samples, float volume) +{ + cellAudio.trace("cellAudioAdd2chData(portNum=%d, src=*0x%x, samples=%d, volume=%f)", portNum, src, samples, volume); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT || !src || !src.aligned()) + { + return CELL_AUDIO_ERROR_PARAM; + } + + if (samples != 256) + { + // despite the docs, seems that only fixed value is supported + cellAudio.error("cellAudioAdd2chData(): invalid samples value (%d)", samples); + return CELL_AUDIO_ERROR_PARAM; + } + + const audio_port& port = g_audio->ports[portNum]; + + const auto dst = vm::ptr::make(port.addr.addr() + s32(port.tag % port.block) * port.channel * 256 * SIZE_32(float)); + + if (port.channel == 2) + { + cellAudio.error("cellAudioAdd2chData(portNum=%d): port.channel = 2", portNum); + } + else if (port.channel == 6) + { + for (u32 i = 0; i < samples; i++) + { + dst[i * 6 + 0] += src[i * 2 + 0] * volume; // mix L ch + dst[i * 6 + 1] += src[i * 2 + 1] * volume; // mix R ch + //dst[i * 6 + 2] += 0.0f; // center + //dst[i * 6 + 3] += 0.0f; // LFE + //dst[i * 6 + 4] += 0.0f; // rear L + //dst[i * 6 + 5] += 0.0f; // rear R + } + } + else if (port.channel == 8) + { + for (u32 i = 0; i < samples; i++) + { + dst[i * 8 + 0] += src[i * 2 + 0] * volume; // mix L ch + dst[i * 8 + 1] += src[i * 2 + 1] * volume; // mix R ch + //dst[i * 8 + 2] += 0.0f; // center + //dst[i * 8 + 3] += 0.0f; // LFE + //dst[i * 8 + 4] += 0.0f; // rear L + //dst[i * 8 + 5] += 0.0f; // rear R + //dst[i * 8 + 6] += 0.0f; // side L + //dst[i * 8 + 7] += 0.0f; // side R + } + } + else + { + cellAudio.error("cellAudioAdd2chData(portNum=%d): invalid port.channel value (%d)", portNum, port.channel); + } + + return CELL_OK; +} + +s32 cellAudioAdd6chData(u32 portNum, vm::ptr src, float volume) +{ + cellAudio.trace("cellAudioAdd6chData(portNum=%d, src=*0x%x, volume=%f)", portNum, src, volume); + + const auto g_audio = fxm::get(); + + if (!g_audio) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT || !src || !src.aligned()) + { + return CELL_AUDIO_ERROR_PARAM; + } + + const audio_port& port = g_audio->ports[portNum]; + + const auto dst = vm::ptr::make(port.addr.addr() + s32(port.tag % port.block) * port.channel * 256 * SIZE_32(float)); + + if (port.channel == 2 || port.channel == 6) + { + cellAudio.error("cellAudioAdd2chData(portNum=%d): port.channel = %d", portNum, port.channel); + } + else if (port.channel == 8) + { + for (u32 i = 0; i < 256; i++) + { + dst[i * 8 + 0] += src[i * 6 + 0] * volume; // mix L ch + dst[i * 8 + 1] += src[i * 6 + 1] * volume; // mix R ch + dst[i * 8 + 2] += src[i * 6 + 2] * volume; // mix center + dst[i * 8 + 3] += src[i * 6 + 3] * volume; // mix LFE + dst[i * 8 + 4] += src[i * 6 + 4] * volume; // mix rear L + dst[i * 8 + 5] += src[i * 6 + 5] * volume; // mix rear R + //dst[i * 8 + 6] += 0.0f; // side L + //dst[i * 8 + 7] += 0.0f; // side R + } + } + else + { + cellAudio.error("cellAudioAdd6chData(portNum=%d): invalid port.channel value (%d)", portNum, port.channel); + } + + return CELL_OK; +} + +s32 cellAudioMiscSetAccessoryVolume(u32 devNum, float volume) +{ + cellAudio.todo("cellAudioMiscSetAccessoryVolume(devNum=%d, volume=%f)", devNum, volume); + return CELL_OK; +} + +s32 cellAudioSendAck(u64 data3) +{ + cellAudio.todo("cellAudioSendAck(data3=0x%llx)", data3); + return CELL_OK; +} + +s32 cellAudioSetPersonalDevice(s32 iPersonalStream, s32 iDevice) +{ + cellAudio.todo("cellAudioSetPersonalDevice(iPersonalStream=%d, iDevice=%d)", iPersonalStream, iDevice); + return CELL_OK; +} + +s32 cellAudioUnsetPersonalDevice(s32 iPersonalStream) +{ + cellAudio.todo("cellAudioUnsetPersonalDevice(iPersonalStream=%d)", iPersonalStream); + return CELL_OK; +} + +DECLARE(ppu_module_manager::cellAudio)("cellAudio", []() +{ + REG_FUNC(cellAudio, cellAudioInit); + REG_FUNC(cellAudio, cellAudioPortClose); + REG_FUNC(cellAudio, cellAudioPortStop); + REG_FUNC(cellAudio, cellAudioGetPortConfig); + REG_FUNC(cellAudio, cellAudioPortStart); + REG_FUNC(cellAudio, cellAudioQuit); + REG_FUNC(cellAudio, cellAudioPortOpen); + REG_FUNC(cellAudio, cellAudioSetPortLevel); + REG_FUNC(cellAudio, cellAudioCreateNotifyEventQueue); + REG_FUNC(cellAudio, cellAudioCreateNotifyEventQueueEx); + REG_FUNC(cellAudio, cellAudioMiscSetAccessoryVolume); + REG_FUNC(cellAudio, cellAudioSetNotifyEventQueue); + REG_FUNC(cellAudio, cellAudioSetNotifyEventQueueEx); + REG_FUNC(cellAudio, cellAudioGetPortTimestamp); + REG_FUNC(cellAudio, cellAudioAdd2chData); + REG_FUNC(cellAudio, cellAudioAdd6chData); + REG_FUNC(cellAudio, cellAudioAddData); + REG_FUNC(cellAudio, cellAudioGetPortBlockTag); + REG_FUNC(cellAudio, cellAudioRemoveNotifyEventQueue); + REG_FUNC(cellAudio, cellAudioRemoveNotifyEventQueueEx); + REG_FUNC(cellAudio, cellAudioSendAck); + REG_FUNC(cellAudio, cellAudioSetPersonalDevice); + REG_FUNC(cellAudio, cellAudioUnsetPersonalDevice); +}); diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.h b/rpcs3/Emu/Cell/Modules/cellAudio.h similarity index 76% rename from rpcs3/Emu/SysCalls/Modules/cellAudio.h rename to rpcs3/Emu/Cell/Modules/cellAudio.h index dd184d6e2a..e64a65f9ca 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.h +++ b/rpcs3/Emu/Cell/Modules/cellAudio.h @@ -1,5 +1,7 @@ #pragma once +#include "Utilities/Thread.h" + namespace vm { using namespace ps3; } // Error codes @@ -66,7 +68,7 @@ struct CellAudioPortParam struct CellAudioPortConfig { - be_t readIndexAddr; + vm::bptr readIndexAddr; be_t status; be_t nChannel; be_t nBlock; @@ -83,36 +85,31 @@ enum : u32 AUDIO_SAMPLES = CELL_AUDIO_BLOCK_SAMPLES, }; -enum AudioState : u32 +extern u64 get_system_time(); + +enum class audio_port_state : u32 { - AUDIO_STATE_NOT_INITIALIZED, - AUDIO_STATE_INITIALIZED, - AUDIO_STATE_FINALIZED, + closed, + opened, + started, }; -enum AudioPortState : u32 +struct audio_port { - AUDIO_PORT_STATE_CLOSED, - AUDIO_PORT_STATE_OPENED, - AUDIO_PORT_STATE_STARTED, -}; + atomic_t state{ audio_port_state::closed }; -struct AudioPortConfig -{ - atomic_t state; - - std::mutex mutex; + u32 number; + vm::ptr addr{}; + vm::ptr index{}; u32 channel; u32 block; u64 attr; u64 tag; u64 counter; // copy of global counter - u32 addr; - u32 read_index_addr; u32 size; - struct level_set_t + struct alignas(8) level_set_t { float value; float inc; @@ -122,31 +119,36 @@ struct AudioPortConfig atomic_t level_set; }; -struct AudioConfig final // custom structure +class audio_config final : public named_thread { - atomic_t state; + void on_task() override; - std::mutex mutex; + std::string get_name() const override { return "Audio Thread"; } + + vm::var> m_buffer{ AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT }; + vm::var> m_indexes{ AUDIO_PORT_COUNT }; + + u64 m_counter{}; + +public: + const u64 start_time = get_system_time(); + + std::array ports; - AudioPortConfig ports[AUDIO_PORT_COUNT]; - u32 buffer; // 1 MB memory for audio ports - u32 indexes; // current block indexes and other info - u64 counter; - u64 start_time; std::vector keys; - u32 open_port() + ~audio_config() noexcept = default; + + audio_port* open_port() { for (u32 i = 0; i < AUDIO_PORT_COUNT; i++) { - if (ports[i].state.compare_and_swap_test(AUDIO_PORT_STATE_CLOSED, AUDIO_PORT_STATE_OPENED)) + if (ports[i].state.compare_and_swap_test(audio_port_state::closed, audio_port_state::opened)) { - return i; + return &ports[i]; } } - return ~0; + return nullptr; } }; - -extern AudioConfig g_audio; diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudioIn.h b/rpcs3/Emu/Cell/Modules/cellAudioIn.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellAudioIn.h rename to rpcs3/Emu/Cell/Modules/cellAudioIn.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudioOut.cpp b/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellAudioOut.cpp rename to rpcs3/Emu/Cell/Modules/cellAudioOut.cpp index 0734bee4b8..d294bbd776 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudioOut.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAudioOut.cpp @@ -1,10 +1,9 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellAudioOut.h" -extern Module<> cellSysutil; +extern _log::channel cellSysutil; s32 cellAudioOutGetSoundAvailability(u32 audioOut, u32 type, u32 fs, u32 option) { diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudioOut.h b/rpcs3/Emu/Cell/Modules/cellAudioOut.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellAudioOut.h rename to rpcs3/Emu/Cell/Modules/cellAudioOut.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellAvconfExt.cpp b/rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp similarity index 63% rename from rpcs3/Emu/SysCalls/Modules/cellAvconfExt.cpp rename to rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp index c34df3052d..7a005dc34a 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAvconfExt.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp @@ -1,15 +1,14 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/state.h" +#include "Emu/System.h" +#include "Emu/Cell/PPUModule.h" #include "cellAudioIn.h" #include "cellAudioOut.h" #include "cellVideoOut.h" -extern Module<> cellAvconfExt; +LOG_CHANNEL(cellAvconfExt); -f32 g_gamma; +vm::gvar g_gamma; // TODO s32 cellAudioOutUnregisterDevice() { @@ -50,7 +49,7 @@ s32 cellVideoOutGetGamma(u32 videoOut, vm::ptr gamma) return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; } - *gamma = g_gamma; + *gamma = *g_gamma; return CELL_OK; } @@ -79,7 +78,7 @@ s32 cellVideoOutSetGamma(u32 videoOut, f32 gamma) return CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER; } - g_gamma = gamma; + *g_gamma = gamma; return CELL_OK; } @@ -127,34 +126,32 @@ s32 cellVideoOutGetScreenSize(u32 videoOut, vm::ptr screenSize) // float diagonal = roundf(sqrtf((powf(wxGetDisplaySizeMM().GetWidth(), 2) + powf(wxGetDisplaySizeMM().GetHeight(), 2))) * 0.0393f); #endif - if (rpcs3::config.rsx._3dtv.value()) - { - *screenSize = 24.0f; - return CELL_OK; - } - return CELL_VIDEO_OUT_ERROR_VALUE_IS_NOT_SET; } -Module<> cellAvconfExt("cellAvconfExt", []() +DECLARE(ppu_module_manager::cellAvconfExt)("cellSysutilAvconfExt", []() { - g_gamma = 1.0f; + REG_VNID(cellSysutilAvconfExt, 0x00000000, g_gamma, [] + { + // Test + *g_gamma = 1.0f; + }); - REG_FUNC(cellAvconfExt, cellAudioOutUnregisterDevice); - REG_FUNC(cellAvconfExt, cellAudioOutGetDeviceInfo2); - REG_FUNC(cellAvconfExt, cellVideoOutSetXVColor); - REG_FUNC(cellAvconfExt, cellVideoOutSetupDisplay); - REG_FUNC(cellAvconfExt, cellAudioInGetDeviceInfo); - REG_FUNC(cellAvconfExt, cellVideoOutConvertCursorColor); - REG_FUNC(cellAvconfExt, cellVideoOutGetGamma); - REG_FUNC(cellAvconfExt, cellAudioInGetAvailableDeviceInfo); - REG_FUNC(cellAvconfExt, cellAudioOutGetAvailableDeviceInfo); - REG_FUNC(cellAvconfExt, cellVideoOutSetGamma); - REG_FUNC(cellAvconfExt, cellAudioOutRegisterDevice); - REG_FUNC(cellAvconfExt, cellAudioOutSetDeviceMode); - REG_FUNC(cellAvconfExt, cellAudioInSetDeviceMode); - REG_FUNC(cellAvconfExt, cellAudioInRegisterDevice); - REG_FUNC(cellAvconfExt, cellAudioInUnregisterDevice); - REG_FUNC(cellAvconfExt, cellVideoOutGetScreenSize); + REG_FUNC(cellSysutilAvconfExt, cellAudioOutUnregisterDevice); + REG_FUNC(cellSysutilAvconfExt, cellAudioOutGetDeviceInfo2); + REG_FUNC(cellSysutilAvconfExt, cellVideoOutSetXVColor); + REG_FUNC(cellSysutilAvconfExt, cellVideoOutSetupDisplay); + REG_FUNC(cellSysutilAvconfExt, cellAudioInGetDeviceInfo); + REG_FUNC(cellSysutilAvconfExt, cellVideoOutConvertCursorColor); + REG_FUNC(cellSysutilAvconfExt, cellVideoOutGetGamma); + REG_FUNC(cellSysutilAvconfExt, cellAudioInGetAvailableDeviceInfo); + REG_FUNC(cellSysutilAvconfExt, cellAudioOutGetAvailableDeviceInfo); + REG_FUNC(cellSysutilAvconfExt, cellVideoOutSetGamma); + REG_FUNC(cellSysutilAvconfExt, cellAudioOutRegisterDevice); + REG_FUNC(cellSysutilAvconfExt, cellAudioOutSetDeviceMode); + REG_FUNC(cellSysutilAvconfExt, cellAudioInSetDeviceMode); + REG_FUNC(cellSysutilAvconfExt, cellAudioInRegisterDevice); + REG_FUNC(cellSysutilAvconfExt, cellAudioInUnregisterDevice); + REG_FUNC(cellSysutilAvconfExt, cellVideoOutGetScreenSize); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellBgdl.cpp b/rpcs3/Emu/Cell/Modules/cellBgdl.cpp similarity index 69% rename from rpcs3/Emu/SysCalls/Modules/cellBgdl.cpp rename to rpcs3/Emu/Cell/Modules/cellBgdl.cpp index b57d7befa1..b83c0fa791 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellBgdl.cpp +++ b/rpcs3/Emu/Cell/Modules/cellBgdl.cpp @@ -1,9 +1,8 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellBGDL; +LOG_CHANNEL(cellBGDL); // Return Codes enum @@ -40,10 +39,10 @@ s32 cellBGDLGetMode() return CELL_OK; } -Module<> cellBGDL("cellBGDL", []() +DECLARE(ppu_module_manager::cellBGDL)("cellBGDLUtility", []() { - REG_FUNC(cellBGDL, cellBGDLGetInfo); - REG_FUNC(cellBGDL, cellBGDLGetInfo2); - REG_FUNC(cellBGDL, cellBGDLSetMode); - REG_FUNC(cellBGDL, cellBGDLGetMode); + REG_FUNC(cellBGDLUtility, cellBGDLGetInfo); + REG_FUNC(cellBGDLUtility, cellBGDLGetInfo2); + REG_FUNC(cellBGDLUtility, cellBGDLSetMode); + REG_FUNC(cellBGDLUtility, cellBGDLGetMode); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellCamera.cpp b/rpcs3/Emu/Cell/Modules/cellCamera.cpp similarity index 92% rename from rpcs3/Emu/SysCalls/Modules/cellCamera.cpp rename to rpcs3/Emu/Cell/Modules/cellCamera.cpp index e0c194ebac..6a2c491a43 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellCamera.cpp +++ b/rpcs3/Emu/Cell/Modules/cellCamera.cpp @@ -1,13 +1,25 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/IdManager.h" #include "Emu/System.h" -#include "Emu/state.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellCamera.h" -extern Module<> cellCamera; +LOG_CHANNEL(cellCamera); + +cfg::map_entry g_cfg_camera(cfg::root.io, "Camera", +{ + { "Null", false }, + { "Fake", true }, +}); + +cfg::map_entry g_cfg_camera_type(cfg::root.io, "Camera type", +{ + { "Unknown", CELL_CAMERA_TYPE_UNKNOWN }, + { "EyeToy", CELL_CAMERA_EYETOY }, + { "PS Eye", CELL_CAMERA_EYETOY2 }, + { "UVC 1.1", CELL_CAMERA_USBVIDEOCLASS }, +}); static const char* get_camera_attr_name(s32 value) { @@ -82,7 +94,7 @@ s32 cellCameraInit() { cellCamera.warning("cellCameraInit()"); - if (rpcs3::config.io.camera.value() == io_camera_state::null) + if (!g_cfg_camera.get()) { return CELL_CAMERA_ERROR_DEVICE_NOT_FOUND; } @@ -94,9 +106,9 @@ s32 cellCameraInit() return CELL_CAMERA_ERROR_ALREADY_INIT; } - switch (rpcs3::config.io.camera_type.value()) + switch (g_cfg_camera_type.get()) { - case io_camera_type::eye_toy: + case CELL_CAMERA_EYETOY: { camera->attr[CELL_CAMERA_SATURATION] = { 164 }; camera->attr[CELL_CAMERA_BRIGHTNESS] = { 96 }; @@ -115,7 +127,7 @@ s32 cellCameraInit() } break; - case io_camera_type::play_station_eye: + case CELL_CAMERA_EYETOY2: { camera->attr[CELL_CAMERA_SATURATION] = { 64 }; camera->attr[CELL_CAMERA_BRIGHTNESS] = { 8 }; @@ -191,14 +203,7 @@ s32 cellCameraGetType(s32 dev_num, vm::ptr type) return CELL_CAMERA_ERROR_NOT_INIT; } - switch (rpcs3::config.io.camera_type.value()) - { - case io_camera_type::eye_toy: *type = CELL_CAMERA_EYETOY; break; - case io_camera_type::play_station_eye: *type = CELL_CAMERA_EYETOY2; break; - case io_camera_type::usb_video_class_1_1: *type = CELL_CAMERA_USBVIDEOCLASS; break; - default: *type = CELL_CAMERA_TYPE_UNKNOWN; break; - } - + *type = g_cfg_camera_type.get(); return CELL_OK; } @@ -212,12 +217,12 @@ s32 cellCameraIsAttached(s32 dev_num) { cellCamera.warning("cellCameraIsAttached(dev_num=%d)", dev_num); - if (rpcs3::config.io.camera.value() == io_camera_state::connected) + if (g_cfg_camera.get()) { return 1; } - return CELL_OK; // CELL_OK means that no camera is attached + return 0; // It's not CELL_OK lol } s32 cellCameraIsOpen(s32 dev_num) @@ -381,7 +386,7 @@ s32 cellCameraRemoveNotifyEventQueue2(u64 key) return CELL_OK; } -Module<> cellCamera("cellCamera", []() +DECLARE(ppu_module_manager::cellCamera)("cellCamera", []() { REG_FUNC(cellCamera, cellCameraInit); REG_FUNC(cellCamera, cellCameraEnd); diff --git a/rpcs3/Emu/SysCalls/Modules/cellCamera.h b/rpcs3/Emu/Cell/Modules/cellCamera.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellCamera.h rename to rpcs3/Emu/Cell/Modules/cellCamera.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellCelp8Enc.cpp b/rpcs3/Emu/Cell/Modules/cellCelp8Enc.cpp similarity index 91% rename from rpcs3/Emu/SysCalls/Modules/cellCelp8Enc.cpp rename to rpcs3/Emu/Cell/Modules/cellCelp8Enc.cpp index b5e29f813a..bb0b24b9ef 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellCelp8Enc.cpp +++ b/rpcs3/Emu/Cell/Modules/cellCelp8Enc.cpp @@ -1,9 +1,8 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellCelp8Enc; +LOG_CHANNEL(cellCelp8Enc); // Return Codes enum @@ -70,7 +69,7 @@ s32 cellCelp8EncGetAu() return CELL_OK; } -Module<> cellCelp8Enc("cellCelp8Enc", []() +DECLARE(ppu_module_manager::cellCelp8Enc)("cellCelp8Enc", []() { REG_FUNC(cellCelp8Enc, cellCelp8EncQueryAttr); REG_FUNC(cellCelp8Enc, cellCelp8EncOpen); diff --git a/rpcs3/Emu/SysCalls/Modules/cellCelpEnc.cpp b/rpcs3/Emu/Cell/Modules/cellCelpEnc.cpp similarity index 91% rename from rpcs3/Emu/SysCalls/Modules/cellCelpEnc.cpp rename to rpcs3/Emu/Cell/Modules/cellCelpEnc.cpp index 2f2dd2c9ef..bb551877bb 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellCelpEnc.cpp +++ b/rpcs3/Emu/Cell/Modules/cellCelpEnc.cpp @@ -1,9 +1,8 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellCelpEnc; +LOG_CHANNEL(cellCelpEnc); // Return Codes enum @@ -70,7 +69,7 @@ s32 cellCelpEncGetAu() return CELL_OK; } -Module<> cellCelpEnc("cellCelpEnc", []() +DECLARE(ppu_module_manager::cellCelpEnc)("cellCelpEnc", []() { REG_FUNC(cellCelpEnc, cellCelpEncQueryAttr); REG_FUNC(cellCelpEnc, cellCelpEncOpen); diff --git a/rpcs3/Emu/SysCalls/Modules/cellDaisy.cpp b/rpcs3/Emu/Cell/Modules/cellDaisy.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellDaisy.cpp rename to rpcs3/Emu/Cell/Modules/cellDaisy.cpp index 8556089ea2..bd82c4d31b 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDaisy.cpp +++ b/rpcs3/Emu/Cell/Modules/cellDaisy.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellDaisy; +LOG_CHANNEL(cellDaisy); s32 _ZN4cell5Daisy17LFQueue2PushCloseEPNS0_8LFQueue2EPFiPvjE() { @@ -265,7 +264,7 @@ s32 _QN4cell5Daisy22ScatterGatherInterlock7releaseEv() } -Module<> cellDaisy("cellDaisy", []() +DECLARE(ppu_module_manager::cellDaisy)("cellDaisy", []() { REG_FUNC(cellDaisy, _ZN4cell5Daisy17LFQueue2PushCloseEPNS0_8LFQueue2EPFiPvjE); REG_FUNC(cellDaisy, _ZN4cell5Daisy21LFQueue2GetPopPointerEPNS0_8LFQueue2EPij); diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/Cell/Modules/cellDmux.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellDmux.cpp rename to rpcs3/Emu/Cell/Modules/cellDmux.cpp index 5a2cbf2135..0c755b197d 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/Cell/Modules/cellDmux.cpp @@ -1,13 +1,12 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellPamf.h" #include "cellDmux.h" -extern Module<> cellDmux; +LOG_CHANNEL(cellDmux); PesHeader::PesHeader(DemuxerStream& stream) : pts(CODEC_TS_INVALID) @@ -80,7 +79,6 @@ PesHeader::PesHeader(DemuxerStream& stream) ElementaryStream::ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr cbFunc, u32 cbArg, u32 spec) : dmux(dmux) - , id(idm::get_last_id()) , memAddr(align(addr, 128)) , memSize(size - (addr - memAddr)) , fidMajor(fidMajor) @@ -112,8 +110,7 @@ bool ElementaryStream::is_full(u32 space) u32 first = 0; if (!entries.peek(first, 0, &dmux->is_closed) || !first) { - assert(!"es::is_full() error: entries.Peek() failed"); - return false; + throw std::runtime_error("entries.peek() failed" HERE); } else if (first >= put) { @@ -145,7 +142,7 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra u32 addr; { std::lock_guard lock(m_mutex); - assert(!is_full(size)); + ASSERT(!is_full(size)); if (put + size + 128 > memAddr + memSize) { @@ -185,10 +182,8 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra put_count++; } - if (!entries.push(addr, &dmux->is_closed)) - { - assert(!"es::push_au() error: entries.Push() failed"); - } + + ASSERT(entries.push(addr, &dmux->is_closed)); } void ElementaryStream::push(DemuxerStream& stream, u32 size) @@ -762,8 +757,9 @@ void dmuxOpen(u32 dmux_id) // TODO: call from the constructor dmux.is_finished = true; }; - dmux.dmuxCb->run(); - dmux.dmuxCb->exec(); + dmux.dmuxCb->cpu_init(); + dmux.dmuxCb->state -= cpu_state::stop; + dmux.dmuxCb->safe_notify(); } s32 cellDmuxQueryAttr(vm::cptr type, vm::ptr attr) @@ -872,7 +868,7 @@ s32 cellDmuxClose(u32 handle) std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } - idm::remove(dmux->dmuxCb->get_id()); + idm::remove(dmux->dmuxCb->id); idm::remove(handle); return CELL_OK; } @@ -1178,7 +1174,7 @@ s32 cellDmuxFlushEs(u32 esHandle) return CELL_OK; } -Module<> cellDmux("cellDmux", []() +DECLARE(ppu_module_manager::cellDmux)("cellDmux", []() { REG_FUNC(cellDmux, cellDmuxQueryAttr); REG_FUNC(cellDmux, cellDmuxQueryAttr2); diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.h b/rpcs3/Emu/Cell/Modules/cellDmux.h similarity index 99% rename from rpcs3/Emu/SysCalls/Modules/cellDmux.h rename to rpcs3/Emu/Cell/Modules/cellDmux.h index 407cdad56e..3341718e61 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.h +++ b/rpcs3/Emu/Cell/Modules/cellDmux.h @@ -405,8 +405,8 @@ public: u32 id; volatile bool is_finished; volatile bool is_closed; - std::atomic is_running; - std::atomic is_working; + atomic_t is_running; + atomic_t is_working; std::shared_ptr dmuxCb; @@ -440,7 +440,7 @@ public: ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr cbFunc, u32 cbArg, u32 spec); Demuxer* dmux; - const u32 id; + const u32 id{}; const u32 memAddr; const u32 memSize; const u32 fidMajor; diff --git a/rpcs3/Emu/SysCalls/Modules/cellFiber.cpp b/rpcs3/Emu/Cell/Modules/cellFiber.cpp similarity index 61% rename from rpcs3/Emu/SysCalls/Modules/cellFiber.cpp rename to rpcs3/Emu/Cell/Modules/cellFiber.cpp index 906b8d5184..ba744dc37a 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellFiber.cpp +++ b/rpcs3/Emu/Cell/Modules/cellFiber.cpp @@ -1,11 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellFiber.h" -extern Module<> cellFiber; +LOG_CHANNEL(cellFiber); s32 _cellFiberPpuInitialize() { @@ -291,59 +290,59 @@ s32 cellFiberPpuUtilWorkerControlInitializeWithAttribute() return CELL_OK; } -Module<> cellFiber("cellFiber", []() +DECLARE(ppu_module_manager::cellFiber)("cellFiber", []() { - REG_FUNC(cellFiber, _cellFiberPpuInitialize, MFF_NO_RETURN); + REG_FUNC(cellFiber, _cellFiberPpuInitialize); - REG_FUNC(cellFiber, _cellFiberPpuSchedulerAttributeInitialize, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuInitializeScheduler, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuFinalizeScheduler, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuRunFibers, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuCheckFlags, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuHasRunnableFiber, MFF_NO_RETURN); + REG_FUNC(cellFiber, _cellFiberPpuSchedulerAttributeInitialize); + REG_FUNC(cellFiber, cellFiberPpuInitializeScheduler); + REG_FUNC(cellFiber, cellFiberPpuFinalizeScheduler); + REG_FUNC(cellFiber, cellFiberPpuRunFibers); + REG_FUNC(cellFiber, cellFiberPpuCheckFlags); + REG_FUNC(cellFiber, cellFiberPpuHasRunnableFiber); - REG_FUNC(cellFiber, _cellFiberPpuAttributeInitialize, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuCreateFiber, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuExit, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuYield, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuJoinFiber, MFF_NO_RETURN); + REG_FUNC(cellFiber, _cellFiberPpuAttributeInitialize); + REG_FUNC(cellFiber, cellFiberPpuCreateFiber); + REG_FUNC(cellFiber, cellFiberPpuExit); + REG_FUNC(cellFiber, cellFiberPpuYield); + REG_FUNC(cellFiber, cellFiberPpuJoinFiber); REG_FUNC(cellFiber, cellFiberPpuSelf); - REG_FUNC(cellFiber, cellFiberPpuSendSignal, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuWaitSignal, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuWaitFlag, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuGetScheduler, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuSetPriority, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuCheckStackLimit, MFF_NO_RETURN); + REG_FUNC(cellFiber, cellFiberPpuSendSignal); + REG_FUNC(cellFiber, cellFiberPpuWaitSignal); + REG_FUNC(cellFiber, cellFiberPpuWaitFlag); + REG_FUNC(cellFiber, cellFiberPpuGetScheduler); + REG_FUNC(cellFiber, cellFiberPpuSetPriority); + REG_FUNC(cellFiber, cellFiberPpuCheckStackLimit); - REG_FUNC(cellFiber, _cellFiberPpuContextAttributeInitialize, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuContextInitialize, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuContextFinalize, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuContextRun, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuContextSwitch, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuContextSelf, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuContextReturnToThread, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuContextCheckStackLimit, MFF_NO_RETURN); + REG_FUNC(cellFiber, _cellFiberPpuContextAttributeInitialize); + REG_FUNC(cellFiber, cellFiberPpuContextInitialize); + REG_FUNC(cellFiber, cellFiberPpuContextFinalize); + REG_FUNC(cellFiber, cellFiberPpuContextRun); + REG_FUNC(cellFiber, cellFiberPpuContextSwitch); + REG_FUNC(cellFiber, cellFiberPpuContextSelf); + REG_FUNC(cellFiber, cellFiberPpuContextReturnToThread); + REG_FUNC(cellFiber, cellFiberPpuContextCheckStackLimit); - REG_FUNC(cellFiber, cellFiberPpuContextRunScheduler, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuContextEnterScheduler, MFF_NO_RETURN); + REG_FUNC(cellFiber, cellFiberPpuContextRunScheduler); + REG_FUNC(cellFiber, cellFiberPpuContextEnterScheduler); - REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceInitialize, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceFinalize, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceStart, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceStop, MFF_NO_RETURN); + REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceInitialize); + REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceFinalize); + REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceStart); + REG_FUNC(cellFiber, cellFiberPpuSchedulerTraceStop); - REG_FUNC(cellFiber, _cellFiberPpuUtilWorkerControlAttributeInitialize, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlRunFibers, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlInitialize, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlSetPollingMode, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlJoinFiber, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlDisconnectEventQueue, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlSendSignal, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlConnectEventQueueToSpurs, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlFinalize, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlWakeup, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlCreateFiber, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlShutdown, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlCheckFlags, MFF_NO_RETURN); - REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlInitializeWithAttribute, MFF_NO_RETURN); + REG_FUNC(cellFiber, _cellFiberPpuUtilWorkerControlAttributeInitialize); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlRunFibers); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlInitialize); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlSetPollingMode); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlJoinFiber); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlDisconnectEventQueue); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlSendSignal); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlConnectEventQueueToSpurs); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlFinalize); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlWakeup); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlCreateFiber); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlShutdown); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlCheckFlags); + REG_FUNC(cellFiber, cellFiberPpuUtilWorkerControlInitializeWithAttribute); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellFiber.h b/rpcs3/Emu/Cell/Modules/cellFiber.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellFiber.h rename to rpcs3/Emu/Cell/Modules/cellFiber.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellFont.cpp b/rpcs3/Emu/Cell/Modules/cellFont.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellFont.cpp rename to rpcs3/Emu/Cell/Modules/cellFont.cpp index adae60dc89..0d3f10c2a5 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellFont.cpp +++ b/rpcs3/Emu/Cell/Modules/cellFont.cpp @@ -1,15 +1,14 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/System.h" +#include "Emu/Cell/PPUModule.h" // Defines STB_TRUETYPE_IMPLEMENTATION *once* before including stb_truetype.h (as noted in stb_truetype.h's comments) #define STB_TRUETYPE_IMPLEMENTATION #include -#include "Emu/FS/vfsFile.h" #include "cellFont.h" -extern Module<> cellFont; +LOG_CHANNEL(cellFont); // Functions s32 cellFontInitializeWithRevision(u64 revisionFlags, vm::ptr config) @@ -68,15 +67,15 @@ s32 cellFontOpenFontFile(vm::ptr library, vm::cptr fontPa { cellFont.warning("cellFontOpenFontFile(library=*0x%x, fontPath=*0x%x, subNum=%d, uniqueId=%d, font=*0x%x)", library, fontPath, subNum, uniqueId, font); - vfsFile f(fontPath.get_ptr()); - if (!f.IsOpened()) + fs::file f(vfs::get(fontPath.get_ptr())); + if (!f) { return CELL_FONT_ERROR_FONT_OPEN_FAILED; } - u32 fileSize = (u32)f.GetSize(); + u32 fileSize = ::size32(f); u32 bufferAddr = vm::alloc(fileSize, vm::main); // Freed in cellFontCloseFont - f.Read(vm::base(bufferAddr), fileSize); + f.read(vm::base(bufferAddr), fileSize); s32 ret = cellFontOpenFontMemory(library, bufferAddr, fileSize, subNum, uniqueId, font); font->origin = CELL_FONT_OPEN_FONT_FILE; @@ -742,7 +741,7 @@ s32 cellFontGraphicsGetLineRGBA() } -Module<> cellFont("cellFont", []() +DECLARE(ppu_module_manager::cellFont)("cellFont", []() { REG_FUNC(cellFont, cellFontSetFontsetOpenMode); REG_FUNC(cellFont, cellFontSetFontOpenMode); diff --git a/rpcs3/Emu/SysCalls/Modules/cellFont.h b/rpcs3/Emu/Cell/Modules/cellFont.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellFont.h rename to rpcs3/Emu/Cell/Modules/cellFont.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellFontFT.cpp b/rpcs3/Emu/Cell/Modules/cellFontFT.cpp similarity index 85% rename from rpcs3/Emu/SysCalls/Modules/cellFontFT.cpp rename to rpcs3/Emu/Cell/Modules/cellFontFT.cpp index 5afe132d5e..5821d440c6 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellFontFT.cpp +++ b/rpcs3/Emu/Cell/Modules/cellFontFT.cpp @@ -1,10 +1,9 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellFontFT.h" -extern Module<> cellFontFT; +LOG_CHANNEL(cellFontFT); s32 cellFontInitLibraryFreeTypeWithRevision(u64 revisionFlags, vm::ptr config, vm::pptr lib) { @@ -27,7 +26,7 @@ s32 cellFontFTGetInitializedRevisionFlags() return CELL_OK; } -Module<> cellFontFT("cellFontFT", []() +DECLARE(ppu_module_manager::cellFontFT)("cellFontFT", []() { REG_FUNC(cellFontFT, cellFontInitLibraryFreeTypeWithRevision); REG_FUNC(cellFontFT, cellFontFTGetRevisionFlags); diff --git a/rpcs3/Emu/SysCalls/Modules/cellFontFT.h b/rpcs3/Emu/Cell/Modules/cellFontFT.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellFontFT.h rename to rpcs3/Emu/Cell/Modules/cellFontFT.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellFs.cpp b/rpcs3/Emu/Cell/Modules/cellFs.cpp similarity index 79% rename from rpcs3/Emu/SysCalls/Modules/cellFs.cpp rename to rpcs3/Emu/Cell/Modules/cellFs.cpp index 37154ae03b..ee85879eff 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellFs.cpp +++ b/rpcs3/Emu/Cell/Modules/cellFs.cpp @@ -1,18 +1,12 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/SysCalls/Callback.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFile.h" -#include "Emu/FS/vfsDir.h" - -#include "Emu/SysCalls/lv2/sys_fs.h" +#include "Emu/Cell/lv2/sys_fs.h" #include "cellFs.h" -extern Module<> cellFs; +LOG_CHANNEL(cellFs); s32 cellFsOpen(vm::cptr path, s32 flags, vm::ptr fd, vm::cptr arg, u64 size) { @@ -222,20 +216,22 @@ s32 cellFsGetDirectoryEntries(u32 fd, vm::ptr entries, u32 for (; count < entries_size; count++) { - if (const auto info = directory->dir->Read()) + fs::dir_entry info; + + if (directory->dir.read(info)) { - entries[count].attribute.mode = info->flags & DirEntry_TypeDir ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666; + entries[count].attribute.mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666; entries[count].attribute.uid = 1; // ??? entries[count].attribute.gid = 1; // ??? - entries[count].attribute.atime = info->access_time; - entries[count].attribute.mtime = info->modify_time; - entries[count].attribute.ctime = info->create_time; - entries[count].attribute.size = info->size; + entries[count].attribute.atime = info.atime; + entries[count].attribute.mtime = info.mtime; + entries[count].attribute.ctime = info.ctime; + entries[count].attribute.size = info.size; entries[count].attribute.blksize = 4096; // ??? - entries[count].entry_name.d_type = info->flags & DirEntry_TypeFile ? CELL_FS_TYPE_REGULAR : CELL_FS_TYPE_DIRECTORY; - entries[count].entry_name.d_namlen = u8(std::min(info->name.length(), CELL_FS_MAX_FS_FILE_NAME_LENGTH)); - strcpy_trunc(entries[count].entry_name.d_name, info->name); + entries[count].entry_name.d_type = info.is_directory ? CELL_FS_TYPE_DIRECTORY : CELL_FS_TYPE_REGULAR; + entries[count].entry_name.d_namlen = u8(std::min(info.name.size(), CELL_FS_MAX_FS_FILE_NAME_LENGTH)); + strcpy_trunc(entries[count].entry_name.d_name, info.name); } else { @@ -263,13 +259,11 @@ s32 cellFsReadWithOffset(u32 fd, u64 offset, vm::ptr buf, u64 buffer_size, std::lock_guard lock(file->mutex); - const auto old_position = file->file->Tell(); + const auto old_pos = file->file.pos(); file->file.seek(offset); - CHECK_ASSERTION(file->file->Seek(offset) != -1); + const auto read = file->file.read(buf.get_ptr(), buffer_size); - const auto read = file->file->Read(buf.get_ptr(), buffer_size); - - CHECK_ASSERTION(file->file->Seek(old_position) != -1); + ASSERT(file->file.seek(old_pos) == old_pos); if (nread) { @@ -294,13 +288,11 @@ s32 cellFsWriteWithOffset(u32 fd, u64 offset, vm::cptr buf, u64 data_size, std::lock_guard lock(file->mutex); - const auto old_position = file->file->Tell(); + const auto old_pos = file->file.pos(); file->file.seek(offset); - CHECK_ASSERTION(file->file->Seek(offset) != -1); + const auto written = file->file.write(buf.get_ptr(), data_size); - const auto written = file->file->Write(buf.get_ptr(), data_size); - - CHECK_ASSERTION(file->file->Seek(old_position) != -1); + ASSERT(file->file.seek(old_pos) == old_pos); if (nwrite) { @@ -489,12 +481,12 @@ s32 cellFsStReadStart(u32 fd, u64 offset, u64 size) } } - offset = std::min(file->file->GetSize(), offset); - size = std::min(file->file->GetSize() - offset, size); + offset = std::min(file->file.size(), offset); + size = std::min(file->file.size() - offset, size); file->st_read_size = size; - file->st_thread = thread_ctrl::spawn(PURE_EXPR("FS ST Thread"s), [=]() + file->st_thread = thread_ctrl::spawn("FS ST Thread", [=]() { std::unique_lock lock(file->mutex); @@ -504,13 +496,13 @@ s32 cellFsStReadStart(u32 fd, u64 offset, u64 size) if (file->st_total_read - file->st_copied <= file->st_ringbuf_size - file->st_block_size && file->st_total_read < file->st_read_size) { // get buffer position - const u32 position = VM_CAST(file->st_buffer + file->st_total_read % file->st_ringbuf_size); + const u32 position = vm::cast(file->st_buffer + file->st_total_read % file->st_ringbuf_size, HERE); // read data - auto old = file->file->Tell(); - CHECK_ASSERTION(file->file->Seek(offset + file->st_total_read) != -1); - auto res = file->file->Read(vm::base(position), file->st_block_size); - CHECK_ASSERTION(file->file->Seek(old) != -1); + auto old = file->file.pos(); + file->file.seek(offset + file->st_total_read); + auto res = file->file.read(vm::base(position), file->st_block_size); + ASSERT(file->file.seek(old) == old); // notify file->st_total_read += res; @@ -594,7 +586,7 @@ s32 cellFsStRead(u32 fd, vm::ptr buf, u64 size, vm::ptr rsize) } const u64 copied = file->st_copied; - const u32 position = VM_CAST(file->st_buffer + copied % file->st_ringbuf_size); + const u32 position = vm::cast(file->st_buffer + copied % file->st_ringbuf_size, HERE); const u64 total_read = file->st_total_read; const u64 copy_size = (*rsize = std::min(size, total_read - copied)); // write rsize @@ -628,7 +620,7 @@ s32 cellFsStReadGetCurrentAddr(u32 fd, vm::ptr addr, vm::ptr size) } const u64 copied = file->st_copied; - const u32 position = VM_CAST(file->st_buffer + copied % file->st_ringbuf_size); + const u32 position = vm::cast(file->st_buffer + copied % file->st_ringbuf_size, HERE); const u64 total_read = file->st_total_read; if ((*size = std::min(file->st_ringbuf_size - (position - file->st_buffer), total_read - copied))) @@ -752,23 +744,23 @@ bool sdata_check(u32 version, u32 flags, u64 filesizeInput, u64 filesizeTmp) s32 sdata_unpack(const std::string& packed_file, const std::string& unpacked_file) { - std::shared_ptr packed_stream(Emu.GetVFS().OpenFile(packed_file, fom::read)); - std::shared_ptr unpacked_stream(Emu.GetVFS().OpenFile(unpacked_file, fom::rewrite)); + fs::file packed_stream(vfs::get(packed_file)); + fs::file unpacked_stream(vfs::get(unpacked_file), fs::rewrite); - if (!packed_stream || !packed_stream->IsOpened()) + if (!packed_stream) { - cellFs.error("File '%s' not found!", packed_file.c_str()); + cellFs.error("File '%s' not found!", packed_file); return CELL_ENOENT; } - if (!unpacked_stream || !unpacked_stream->IsOpened()) + if (!unpacked_stream) { - cellFs.error("File '%s' couldn't be created!", unpacked_file.c_str()); + cellFs.error("File '%s' couldn't be created!", unpacked_file); return CELL_ENOENT; } char buffer[10200]; - packed_stream->Read(buffer, 256); + packed_stream.read(buffer, 256); u32 format = *(be_t*)&buffer[0]; if (format != 0x4E504400) // "NPD\x00" { @@ -780,7 +772,7 @@ s32 sdata_unpack(const std::string& packed_file, const std::string& unpacked_fil u32 flags = *(be_t*)&buffer[0x80]; u32 blockSize = *(be_t*)&buffer[0x84]; u64 filesizeOutput = *(be_t*)&buffer[0x88]; - u64 filesizeInput = packed_stream->GetSize(); + u64 filesizeInput = packed_stream.size(); u32 blockCount = (u32)((filesizeOutput + blockSize - 1) / blockSize); // SDATA file is compressed @@ -804,20 +796,18 @@ s32 sdata_unpack(const std::string& packed_file, const std::string& unpacked_fil if (flags & 0x20) { - CHECK_ASSERTION(packed_stream->Seek(0x100) != -1); + ASSERT(packed_stream.seek(0x100) == 0x100); } else { - CHECK_ASSERTION(packed_stream->Seek(startOffset) != -1); + ASSERT(packed_stream.seek(startOffset) == startOffset); } for (u32 i = 0; i < blockCount; i++) { if (flags & 0x20) { - s64 cur; - CHECK_ASSERTION((cur = packed_stream->Tell()) != -1); - CHECK_ASSERTION(packed_stream->Seek(cur + t1) != -1); + packed_stream.seek(t1, fs::seek_cur); } if (!(blockCount - i - 1)) @@ -825,8 +815,8 @@ s32 sdata_unpack(const std::string& packed_file, const std::string& unpacked_fil blockSize = (u32)(filesizeOutput - i * blockSize); } - packed_stream->Read(buffer + 256, blockSize); - unpacked_stream->Write(buffer + 256, blockSize); + packed_stream.read(buffer + 256, blockSize); + unpacked_stream.write(buffer + 256, blockSize); } } @@ -891,13 +881,13 @@ void fsAio(vm::ptr aio, bool write, s32 xid, fs_aio_cb_t func) { std::lock_guard lock(file->mutex); - const auto old_position = file->file->Tell(); + const auto old_pos = file->file.pos(); file->file.seek(aio->offset); - CHECK_ASSERTION(file->file->Seek(aio->offset) != -1); + result = write + ? file->file.write(aio->buf.get_ptr(), aio->size) + : file->file.read(aio->buf.get_ptr(), aio->size); - result = write ? file->file->Write(aio->buf.get_ptr(), aio->size) : file->file->Read(aio->buf.get_ptr(), aio->size); - - CHECK_ASSERTION(file->file->Seek(old_position) != -1); + ASSERT(file->file.seek(old_pos) == old_pos); } // should be executed directly by FS AIO thread @@ -927,7 +917,7 @@ s32 cellFsAioFinish(vm::cptr mount_point) return CELL_OK; } -std::atomic g_fs_aio_id; +atomic_t g_fs_aio_id; s32 cellFsAioRead(vm::ptr aio, vm::ptr id, fs_aio_cb_t func) { @@ -937,7 +927,7 @@ s32 cellFsAioRead(vm::ptr aio, vm::ptr id, fs_aio_cb_t func) const s32 xid = (*id = ++g_fs_aio_id); - thread_ctrl::spawn(PURE_EXPR("FS AIO Read Thread"s), COPY_EXPR(fsAio(aio, false, xid, func))); + thread_ctrl::spawn("FS AIO Read Thread", COPY_EXPR(fsAio(aio, false, xid, func))); return CELL_OK; } @@ -950,7 +940,7 @@ s32 cellFsAioWrite(vm::ptr aio, vm::ptr id, fs_aio_cb_t func) const s32 xid = (*id = ++g_fs_aio_id); - thread_ctrl::spawn(PURE_EXPR("FS AIO Write Thread"s), COPY_EXPR(fsAio(aio, true, xid, func))); + thread_ctrl::spawn("FS AIO Write Thread", COPY_EXPR(fsAio(aio, true, xid, func))); return CELL_OK; } @@ -1051,66 +1041,64 @@ s32 cellFsUnregisterL10nCallbacks() } -Module<> cellFs("cellFs", []() +DECLARE(ppu_module_manager::cellFs)("sys_fs", []() { - g_fs_aio_id = 1; - - REG_FUNC(cellFs, cellFsOpen); - REG_FUNC(cellFs, cellFsSdataOpen); - REG_FUNC(cellFs, cellFsSdataOpenByFd); - REG_FUNC(cellFs, cellFsRead, MFF_PERFECT); - REG_FUNC(cellFs, cellFsWrite, MFF_PERFECT); - REG_FUNC(cellFs, cellFsClose, MFF_PERFECT); - REG_FUNC(cellFs, cellFsOpendir); - REG_FUNC(cellFs, cellFsReaddir, MFF_PERFECT); - REG_FUNC(cellFs, cellFsClosedir, MFF_PERFECT); - REG_FUNC(cellFs, cellFsStat); - REG_FUNC(cellFs, cellFsFstat, MFF_PERFECT); - REG_FUNC(cellFs, cellFsMkdir); - REG_FUNC(cellFs, cellFsRename); - REG_FUNC(cellFs, cellFsChmod); - REG_FUNC(cellFs, cellFsFsync); - REG_FUNC(cellFs, cellFsRmdir); - REG_FUNC(cellFs, cellFsUnlink); - REG_FUNC(cellFs, cellFsLseek, MFF_PERFECT); - REG_FUNC(cellFs, cellFsFtruncate, MFF_PERFECT); - REG_FUNC(cellFs, cellFsTruncate); - REG_FUNC(cellFs, cellFsFGetBlockSize, MFF_PERFECT); - REG_FUNC(cellFs, cellFsAioInit); - REG_FUNC(cellFs, cellFsAioFinish); - REG_FUNC(cellFs, cellFsAioRead); - REG_FUNC(cellFs, cellFsAioWrite); - REG_FUNC(cellFs, cellFsAioCancel); - REG_FUNC(cellFs, cellFsGetBlockSize); - REG_FUNC(cellFs, cellFsGetFreeSize); - REG_FUNC(cellFs, cellFsReadWithOffset); - REG_FUNC(cellFs, cellFsWriteWithOffset); - REG_FUNC(cellFs, cellFsGetDirectoryEntries); - REG_FUNC(cellFs, cellFsStReadInit); - REG_FUNC(cellFs, cellFsStReadFinish); - REG_FUNC(cellFs, cellFsStReadGetRingBuf); - REG_FUNC(cellFs, cellFsStReadGetStatus); - REG_FUNC(cellFs, cellFsStReadGetRegid); - REG_FUNC(cellFs, cellFsStReadStart); - REG_FUNC(cellFs, cellFsStReadStop); - REG_FUNC(cellFs, cellFsStRead); - REG_FUNC(cellFs, cellFsStReadGetCurrentAddr); - REG_FUNC(cellFs, cellFsStReadPutCurrentAddr); - REG_FUNC(cellFs, cellFsStReadWait); - REG_FUNC(cellFs, cellFsStReadWaitCallback); - REG_FUNC(cellFs, cellFsSetDefaultContainer); - REG_FUNC(cellFs, cellFsSetIoBufferFromDefaultContainer); - REG_FUNC(cellFs, cellFsUtime); - REG_FUNC(cellFs, cellFsArcadeHddSerialNumber); - REG_FUNC(cellFs, cellFsAllocateFileAreaWithInitialData); - REG_FUNC(cellFs, cellFsAllocateFileAreaByFdWithoutZeroFill); - REG_FUNC(cellFs, cellFsSetIoBuffer); - REG_FUNC(cellFs, cellFsAllocateFileAreaByFdWithInitialData); - REG_FUNC(cellFs, cellFsTruncate2); - REG_FUNC(cellFs, cellFsChangeFileSizeWithoutAllocation); - REG_FUNC(cellFs, cellFsAllocateFileAreaWithoutZeroFill); - REG_FUNC(cellFs, cellFsChangeFileSizeByFdWithoutAllocation); - REG_FUNC(cellFs, cellFsSetDiscReadRetrySetting); - REG_FUNC(cellFs, cellFsRegisterConversionCallback); - REG_FUNC(cellFs, cellFsUnregisterL10nCallbacks); + REG_FUNC(sys_fs, cellFsOpen); + REG_FUNC(sys_fs, cellFsSdataOpen); + REG_FUNC(sys_fs, cellFsSdataOpenByFd); + REG_FUNC(sys_fs, cellFsRead, MFF_PERFECT); + REG_FUNC(sys_fs, cellFsWrite, MFF_PERFECT); + REG_FUNC(sys_fs, cellFsClose, MFF_PERFECT); + REG_FUNC(sys_fs, cellFsOpendir); + REG_FUNC(sys_fs, cellFsReaddir, MFF_PERFECT); + REG_FUNC(sys_fs, cellFsClosedir, MFF_PERFECT); + REG_FUNC(sys_fs, cellFsStat); + REG_FUNC(sys_fs, cellFsFstat, MFF_PERFECT); + REG_FUNC(sys_fs, cellFsMkdir); + REG_FUNC(sys_fs, cellFsRename); + REG_FUNC(sys_fs, cellFsChmod); + REG_FUNC(sys_fs, cellFsFsync); + REG_FUNC(sys_fs, cellFsRmdir); + REG_FUNC(sys_fs, cellFsUnlink); + REG_FUNC(sys_fs, cellFsLseek, MFF_PERFECT); + REG_FUNC(sys_fs, cellFsFtruncate, MFF_PERFECT); + REG_FUNC(sys_fs, cellFsTruncate); + REG_FUNC(sys_fs, cellFsFGetBlockSize, MFF_PERFECT); + REG_FUNC(sys_fs, cellFsAioInit); + REG_FUNC(sys_fs, cellFsAioFinish); + REG_FUNC(sys_fs, cellFsAioRead); + REG_FUNC(sys_fs, cellFsAioWrite); + REG_FUNC(sys_fs, cellFsAioCancel); + REG_FUNC(sys_fs, cellFsGetBlockSize); + REG_FUNC(sys_fs, cellFsGetFreeSize); + REG_FUNC(sys_fs, cellFsReadWithOffset); + REG_FUNC(sys_fs, cellFsWriteWithOffset); + REG_FUNC(sys_fs, cellFsGetDirectoryEntries); + REG_FUNC(sys_fs, cellFsStReadInit); + REG_FUNC(sys_fs, cellFsStReadFinish); + REG_FUNC(sys_fs, cellFsStReadGetRingBuf); + REG_FUNC(sys_fs, cellFsStReadGetStatus); + REG_FUNC(sys_fs, cellFsStReadGetRegid); + REG_FUNC(sys_fs, cellFsStReadStart); + REG_FUNC(sys_fs, cellFsStReadStop); + REG_FUNC(sys_fs, cellFsStRead); + REG_FUNC(sys_fs, cellFsStReadGetCurrentAddr); + REG_FUNC(sys_fs, cellFsStReadPutCurrentAddr); + REG_FUNC(sys_fs, cellFsStReadWait); + REG_FUNC(sys_fs, cellFsStReadWaitCallback); + REG_FUNC(sys_fs, cellFsSetDefaultContainer); + REG_FUNC(sys_fs, cellFsSetIoBufferFromDefaultContainer); + REG_FUNC(sys_fs, cellFsUtime); + REG_FUNC(sys_fs, cellFsArcadeHddSerialNumber); + REG_FUNC(sys_fs, cellFsAllocateFileAreaWithInitialData); + REG_FUNC(sys_fs, cellFsAllocateFileAreaByFdWithoutZeroFill); + REG_FUNC(sys_fs, cellFsSetIoBuffer); + REG_FUNC(sys_fs, cellFsAllocateFileAreaByFdWithInitialData); + REG_FUNC(sys_fs, cellFsTruncate2); + REG_FUNC(sys_fs, cellFsChangeFileSizeWithoutAllocation); + REG_FUNC(sys_fs, cellFsAllocateFileAreaWithoutZeroFill); + REG_FUNC(sys_fs, cellFsChangeFileSizeByFdWithoutAllocation); + REG_FUNC(sys_fs, cellFsSetDiscReadRetrySetting); + REG_FUNC(sys_fs, cellFsRegisterConversionCallback); + REG_FUNC(sys_fs, cellFsUnregisterL10nCallbacks); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellFs.h b/rpcs3/Emu/Cell/Modules/cellFs.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellFs.h rename to rpcs3/Emu/Cell/Modules/cellFs.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellGame.cpp b/rpcs3/Emu/Cell/Modules/cellGame.cpp similarity index 83% rename from rpcs3/Emu/SysCalls/Modules/cellGame.cpp rename to rpcs3/Emu/Cell/Modules/cellGame.cpp index 08a535e449..0230547d47 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGame.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGame.cpp @@ -1,17 +1,15 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFile.h" -#include "Loader/PSF.h" #include "cellSysutil.h" #include "cellMsgDialog.h" #include "cellGame.h" -extern Module<> cellGame; +#include + +LOG_CHANNEL(cellGame); // Normal content directory (if is_temporary is not involved): // contentInfo = dir @@ -40,7 +38,7 @@ struct content_permission_t final { if (is_temporary) { - Emu.GetVFS().DeleteAll("/dev_hdd1/game/" + dir); + fs::remove_all(vfs::get("/dev_hdd1/game/" + dir)); } } }; @@ -56,7 +54,6 @@ s32 cellHddGameCheck(PPUThread& ppu, u32 version, vm::cptr dirName, u32 er return CELL_HDDGAME_ERROR_PARAM; } - vm::var param; vm::var result; vm::var get; vm::var set; @@ -71,14 +68,17 @@ s32 cellHddGameCheck(PPUThread& ppu, u32 version, vm::cptr dirName, u32 er strcpy_trunc(get->contentInfoPath, "/dev_hdd0/game/" + dir); strcpy_trunc(get->hddGamePath, "/dev_hdd0/game/" + dir + "/USRDIR"); - if (!Emu.GetVFS().ExistsDir("/dev_hdd0/game/" + dir)) + const std::string& local_dir = vfs::get("/dev_hdd0/game/" + dir); + + if (!fs::is_dir(local_dir)) { get->isNewData = CELL_HDDGAME_ISNEWDATA_NODIR; + get->getParam = {}; } else { // TODO: Is cellHddGameCheck really responsible for writing the information in get->getParam ? (If not, delete this else) - const auto& psf = psf::load(vfsFile("/dev_hdd0/game/" + dir + "/PARAM.SFO").VRead()); + const auto& psf = psf::load_object(fs::file(local_dir +"/PARAM.SFO")); get->getParam.parentalLevel = psf.at("PARENTAL_LEVEL").as_integer(); get->getParam.attribute = psf.at("ATTRIBUTE").as_integer(); @@ -159,16 +159,9 @@ s32 cellGameBootCheck(vm::ptr type, vm::ptr attributes, vm::ptrsysSizeKB = 0; } - const auto& psf = psf::load(vfsFile("/app_home/../PARAM.SFO").VRead()); + // According to testing (in debug mode) cellGameBootCheck doesn't return an error code, when PARAM.SFO doesn't exist. + const std::string& category = psf::get_string(Emu.GetPSF(), "CATEGORY"); - if (psf.empty()) - { - // According to testing (in debug mode) cellGameBootCheck doesn't return an error code, when PARAM.SFO doesn't exist. - cellGame.error("cellGameBootCheck(): Cannot read PARAM.SFO."); - return CELL_GAME_RET_OK; - } - - const std::string& category = psf.at("CATEGORY").as_string(); if (category == "DG") { *type = CELL_GAME_GAMETYPE_DISC; @@ -182,22 +175,20 @@ s32 cellGameBootCheck(vm::ptr type, vm::ptr attributes, vm::ptr("/dev_hdd0/game/" + titleId, false)) + if (!fxm::make("/dev_hdd0/game/" + Emu.GetTitleID(), false)) { return CELL_GAME_ERROR_BUSY; } } else if (category == "GD") { - const std::string& titleId = psf.at("TITLE_ID").as_string(); *type = CELL_GAME_GAMETYPE_DISC; *attributes = CELL_GAME_ATTRIBUTE_PATCH; // TODO - if (dirName) strcpy_trunc(*dirName, titleId); // ??? + if (dirName) strcpy_trunc(*dirName, Emu.GetTitleID()); // ??? if (!fxm::make("/dev_bdvd/PS3_GAME", false)) { @@ -206,7 +197,7 @@ s32 cellGameBootCheck(vm::ptr type, vm::ptr attributes, vm::ptr size, vm::ptr reserved size->sysSizeKB = 0; } - const auto& psf = psf::load(vfsFile("/app_home/../PARAM.SFO").VRead()); - - if (psf.empty() || psf.at("CATEGORY").as_string() != "GD") + if (psf::get_string(Emu.GetPSF(), "CATEGORY") != "GD") { cellGame.error("cellGamePatchCheck(): CELL_GAME_ERROR_NOTPATCH"); return CELL_GAME_ERROR_NOTPATCH; } - if (!fxm::make("/dev_hdd0/game/" + psf.at("TITLE_ID").as_string(), false)) + if (!fxm::make("/dev_hdd0/game/" + Emu.GetTitleID(), false)) { return CELL_GAME_ERROR_BUSY; } @@ -262,35 +251,18 @@ s32 cellGameDataCheck(u32 type, vm::cptr dirName, vm::ptrsysSizeKB = 0; } - if (type == CELL_GAME_GAMETYPE_DISC) + // TODO: not sure what should be checked there + const std::string& dir = type == CELL_GAME_GAMETYPE_DISC ? "/dev_bdvd/PS3_GAME"s : "/dev_hdd0/game/"s + dirName.get_ptr(); + + if (!fs::is_dir(vfs::get(dir))) { - // TODO: not sure what should be checked there - - if (!Emu.GetVFS().ExistsDir("/dev_bdvd/PS3_GAME")) - { - cellGame.warning("cellGameDataCheck(): /dev_bdvd/PS3_GAME not found"); - return CELL_GAME_RET_NONE; - } - - if (!fxm::make("/dev_bdvd/PS3_GAME", false)) - { - return CELL_GAME_ERROR_BUSY; - } + cellGame.warning("cellGameDataCheck(): '%s' directory not found", dir.c_str()); + return CELL_GAME_RET_NONE; } - else + + if (!fxm::make(dir, false)) { - const std::string dir = "/dev_hdd0/game/"s + dirName.get_ptr(); - - if (!Emu.GetVFS().ExistsDir(dir)) - { - cellGame.warning("cellGameDataCheck(): '%s' directory not found", dir.c_str()); - return CELL_GAME_RET_NONE; - } - - if (!fxm::make(dir, false)) - { - return CELL_GAME_ERROR_BUSY; - } + return CELL_GAME_ERROR_BUSY; } return CELL_GAME_RET_OK; @@ -314,19 +286,21 @@ s32 cellGameContentPermit(vm::ptr contentInfoPath, vm: if (path_set->is_temporary) { - const std::string dir = "/dev_hdd0/game/" + path_set->dir; + const std::string& dir = "/dev_hdd0/game/" + path_set->dir; - // make temporary directory persistent - if (Emu.GetVFS().Rename("/dev_hdd1/game/" + path_set->dir, dir)) + // Make temporary directory persistent + fs::remove_all(vfs::get(dir)); + + if (fs::rename(vfs::get("/dev_hdd1/game/" + path_set->dir), vfs::get(dir))) { - cellGame.success("cellGameContentPermit(): '%s' directory created", dir); + cellGame.success("cellGameContentPermit(): created directory %s", dir); } else { - throw EXCEPTION("Cannot create gamedata directory"); + throw fmt::exception("cellGameContentPermit(): failed to rename to %s", dir); } - // prevent deleting directory + // Disable deletion path_set->is_temporary = false; strcpy_trunc(*contentInfoPath, dir); @@ -353,17 +327,15 @@ s32 cellGameDataCheckCreate2(PPUThread& ppu, u32 version, vm::cptr dirName // TODO: output errors (errDialog) - const std::string dir = "/dev_hdd0/game/"s + dirName.get_ptr(); + const std::string& dir = "/dev_hdd0/game/"s + dirName.get_ptr(); - if (!Emu.GetVFS().ExistsDir(dir)) + if (!fs::is_dir(vfs::get(dir))) { - cellGame.todo("cellGameDataCheckCreate2(): creating directory '%s'", dir.c_str()); + cellGame.todo("cellGameDataCheckCreate2(): should create directory %s", dir); // TODO: create data return CELL_GAMEDATA_RET_OK; } - const auto& psf = psf::load(vfsFile("/app_home/../PARAM.SFO").VRead()); - vm::var cbResult; vm::var cbGet; vm::var cbSet; @@ -385,10 +357,10 @@ s32 cellGameDataCheckCreate2(PPUThread& ppu, u32 version, vm::cptr dirName cbGet->sysSizeKB = 0; cbGet->getParam.attribute = CELL_GAMEDATA_ATTR_NORMAL; - cbGet->getParam.parentalLevel = psf.at("PARENTAL_LEVEL").as_integer(); - strcpy_trunc(cbGet->getParam.dataVersion, psf.at("APP_VER").as_string()); - strcpy_trunc(cbGet->getParam.titleId, psf.at("TITLE_ID").as_string()); - strcpy_trunc(cbGet->getParam.title, psf.at("TITLE").as_string()); + cbGet->getParam.parentalLevel = Emu.GetPSF().at("PARENTAL_LEVEL").as_integer(); + strcpy_trunc(cbGet->getParam.dataVersion, Emu.GetPSF().at("APP_VER").as_string()); + strcpy_trunc(cbGet->getParam.titleId, Emu.GetPSF().at("TITLE_ID").as_string()); + strcpy_trunc(cbGet->getParam.title, Emu.GetPSF().at("TITLE").as_string()); // TODO: write lang titles funcStat(ppu, cbResult, cbGet, cbSet); @@ -446,15 +418,15 @@ s32 cellGameCreateGameData(vm::ptr init, vm::ptr value) { cellGame.warning("cellGameGetParamInt(id=%d, value=*0x%x)", id, value); - const auto& psf = psf::load(vfsFile("/app_home/../PARAM.SFO").VRead()); - std::string key; switch(id) @@ -498,7 +468,7 @@ s32 cellGameGetParamInt(u32 id, vm::ptr value) return CELL_GAME_ERROR_INVALID_ID; } - *value = psf.at(key).as_integer(); + *value = Emu.GetPSF().at(key).as_integer(); return CELL_OK; } @@ -506,9 +476,8 @@ s32 cellGameGetParamString(u32 id, vm::ptr buf, u32 bufsize) { cellGame.warning("cellGameGetParamString(id=%d, buf=*0x%x, bufsize=%d)", id, buf, bufsize); - const auto& psf = psf::load(vfsFile("/app_home/../PARAM.SFO").VRead()); - std::string key; + switch(id) { case CELL_GAME_PARAMID_TITLE: key = "TITLE"; break; // TODO: Is this value correct? @@ -542,7 +511,7 @@ s32 cellGameGetParamString(u32 id, vm::ptr buf, u32 bufsize) return CELL_GAME_ERROR_INVALID_ID; } - const std::string& value = psf.at(key).as_string().substr(0, bufsize - 1); + const std::string& value = Emu.GetPSF().at(key).as_string().substr(0, bufsize - 1); std::copy_n(value.c_str(), value.size() + 1, buf.get_ptr()); @@ -666,8 +635,6 @@ s32 cellGameUnregisterDiscChangeCallback() void cellSysutil_GameData_init() { - extern Module<> cellSysutil; - REG_FUNC(cellSysutil, cellHddGameCheck); REG_FUNC(cellSysutil, cellHddGameCheck2); REG_FUNC(cellSysutil, cellHddGameGetSizeKB); @@ -688,7 +655,7 @@ void cellSysutil_GameData_init() REG_FUNC(cellSysutil, cellGameUnregisterDiscChangeCallback); } -Module<> cellGame("cellGame", []() +DECLARE(ppu_module_manager::cellGame)("cellGame", []() { REG_FUNC(cellGame, cellGameBootCheck); REG_FUNC(cellGame, cellGamePatchCheck); diff --git a/rpcs3/Emu/SysCalls/Modules/cellGame.h b/rpcs3/Emu/Cell/Modules/cellGame.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellGame.h rename to rpcs3/Emu/Cell/Modules/cellGame.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellGameExec.cpp b/rpcs3/Emu/Cell/Modules/cellGameExec.cpp similarity index 89% rename from rpcs3/Emu/SysCalls/Modules/cellGameExec.cpp rename to rpcs3/Emu/Cell/Modules/cellGameExec.cpp index 01f08d5e30..9367db8796 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGameExec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGameExec.cpp @@ -1,10 +1,9 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellGame.h" -extern Module<> cellGameExec; +LOG_CHANNEL(cellGameExec); s32 cellGameSetExitParam() { @@ -45,7 +44,7 @@ s32 cellGameGetBootGameInfo(vm::ptr type, vm::ptr dirName, vm::ptr cellGameExec("cellGameExec", []() +DECLARE(ppu_module_manager::cellGameExec)("cellGameExec", []() { REG_FUNC(cellGameExec, cellGameSetExitParam); REG_FUNC(cellGameExec, cellGameGetHomeDataExportPath); diff --git a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp similarity index 89% rename from rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp rename to rpcs3/Emu/Cell/Modules/cellGcmSys.cpp index 3f14986a60..f1e856df33 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGcmSys.cpp @@ -1,17 +1,16 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" -#include "sysPrxForUser.h" - -//#include "Emu/RSX/GCM.h" -#include "Emu/RSX/GSManager.h" +#include "Emu/Cell/PPUOpcodes.h" +#include "Emu/Memory/Memory.h" #include "Emu/RSX/GSRender.h" -//#include "Emu/SysCalls/lv2/sys_process.h" #include "cellGcmSys.h" -extern Module<> cellGcmSys; +LOG_CHANNEL(cellGcmSys); + +extern s32 cellGcmCallback(vm::ptr context, u32 count); const u32 tiled_pitches[] = { 0x00000000, 0x00000200, 0x00000300, 0x00000400, @@ -101,8 +100,7 @@ vm::ptr cellGcmGetReportDataAddressLocation(u32 index, u32 lo cellGcmSys.error("cellGcmGetReportDataAddressLocation: Wrong main index (%d)", index); return vm::null; } - // TODO: It seems m_report_main_addr is not initialized - return vm::ptr::make(Emu.GetGSManager().GetRender().report_main_addr + index * 0x10); + return vm::ptr::make(RSXIOMem.RealAddr(index * 0x10)); } cellGcmSys.error("cellGcmGetReportDataAddressLocation: Wrong location (%d)", location); @@ -200,8 +198,7 @@ u64 cellGcmGetTimeStampLocation(u32 index, u32 location) cellGcmSys.error("cellGcmGetTimeStampLocation: Wrong main index (%d)", index); return 0; } - // TODO: It seems m_report_main_addr is not initialized - return vm::read64(Emu.GetGSManager().GetRender().report_main_addr + index * 0x10); + return vm::read64(RSXIOMem.RealAddr(index * 0x10)); } cellGcmSys.error("cellGcmGetTimeStampLocation: Wrong location (%d)", location); @@ -257,8 +254,7 @@ s32 cellGcmBindTile(u8 index) return CELL_GCM_ERROR_INVALID_VALUE; } - auto& tile = Emu.GetGSManager().GetRender().tiles[index]; - tile.binded = true; + fxm::get()->tiles[index].binded = true; return CELL_OK; } @@ -273,8 +269,7 @@ s32 cellGcmBindZcull(u8 index) return CELL_GCM_ERROR_INVALID_VALUE; } - auto& zcull = Emu.GetGSManager().GetRender().zculls[index]; - zcull.binded = true; + fxm::get()->zculls[index].binded = true; return CELL_OK; } @@ -290,7 +285,7 @@ s32 cellGcmGetConfiguration(vm::ptr config) s32 cellGcmGetFlipStatus() { - s32 status = Emu.GetGSManager().GetRender().flip_status; + s32 status = fxm::get()->flip_status; cellGcmSys.trace("cellGcmGetFlipStatus() -> %d", status); @@ -328,6 +323,11 @@ s32 _cellGcmInitBody(vm::pptr context, u32 cmdSize, u32 ioSi { cellGcmSys.warning("_cellGcmInitBody(context=**0x%x, cmdSize=0x%x, ioSize=0x%x, ioAddress=0x%x)", context, cmdSize, ioSize, ioAddress); + current_config.ioAddress = 0; + current_config.localAddress = 0; + local_size = 0; + local_addr = 0; + if (!local_size && !local_addr) { local_size = 0xf900000; // TODO: Get sdk_version in _cellGcmFunc15 and pass it to gcmGetLocalMemorySize @@ -369,15 +369,19 @@ s32 _cellGcmInitBody(vm::pptr context, u32 cmdSize, u32 ioSi g_defaultCommandBufferBegin = ioAddress; g_defaultCommandBufferFragmentCount = cmdSize / (32 * 1024); + gcm_info.context_addr = vm::alloc(0x1000, vm::main); + gcm_info.control_addr = vm::alloc(0x1000, vm::main); + gcm_info.label_addr = vm::alloc(0x1000, vm::main); // ??? + current_context.begin.set(g_defaultCommandBufferBegin + 4096); // 4 kb reserved at the beginning current_context.end.set(g_defaultCommandBufferBegin + 32 * 1024 - 4); // 4b at the end for jump current_context.current = current_context.begin; - current_context.callback.set(Emu.GetRSXCallback() - 4); + current_context.callback.set(gcm_info.context_addr + 0x40); - gcm_info.context_addr = vm::alloc(0x1000, vm::main); - gcm_info.control_addr = gcm_info.context_addr + 0x40; - - gcm_info.label_addr = vm::alloc(0x1000, vm::main); // ??? + vm::write32(gcm_info.context_addr + 0x40, gcm_info.context_addr + 0x48); + vm::write32(gcm_info.context_addr + 0x44, 0xabadcafe); + vm::write32(gcm_info.context_addr + 0x48, ppu_instructions::HACK(FIND_FUNC(cellGcmCallback))); + vm::write32(gcm_info.context_addr + 0x4c, ppu_instructions::BLR()); vm::_ref(gcm_info.context_addr) = current_context; context->set(gcm_info.context_addr); @@ -387,16 +391,16 @@ s32 _cellGcmInitBody(vm::pptr context, u32 cmdSize, u32 ioSi ctrl.get = 0; ctrl.ref = -1; - auto& render = Emu.GetGSManager().GetRender(); - render.ctxt_addr = context.addr(); - render.gcm_buffers.set(vm::alloc(sizeof(CellGcmDisplayInfo) * 8, vm::main)); - render.zculls_addr = vm::alloc(sizeof(CellGcmZcullInfo) * 8, vm::main); - render.tiles_addr = vm::alloc(sizeof(CellGcmTileInfo) * 15, vm::main); - render.gcm_buffers_count = 0; - render.gcm_current_buffer = 0; - render.main_mem_addr = 0; - render.label_addr = gcm_info.label_addr; - render.init(g_defaultCommandBufferBegin, cmdSize, gcm_info.control_addr, local_addr); + const auto render = fxm::get(); + render->ctxt_addr = context.addr(); + render->gcm_buffers.set(vm::alloc(sizeof(CellGcmDisplayInfo) * 8, vm::main)); + render->zculls_addr = vm::alloc(sizeof(CellGcmZcullInfo) * 8, vm::main); + render->tiles_addr = vm::alloc(sizeof(CellGcmTileInfo) * 15, vm::main); + render->gcm_buffers_count = 0; + render->gcm_current_buffer = 0; + render->main_mem_addr = 0; + render->label_addr = gcm_info.label_addr; + render->init(g_defaultCommandBufferBegin, cmdSize, gcm_info.control_addr, local_addr); return CELL_OK; } @@ -405,7 +409,7 @@ s32 cellGcmResetFlipStatus() { cellGcmSys.trace("cellGcmResetFlipStatus()"); - Emu.GetGSManager().GetRender().flip_status = CELL_GCM_DISPLAY_FLIP_STATUS_WAITING; + fxm::get()->flip_status = CELL_GCM_DISPLAY_FLIP_STATUS_WAITING; return CELL_OK; } @@ -419,7 +423,7 @@ s32 cellGcmSetDebugOutputLevel(s32 level) case CELL_GCM_DEBUG_LEVEL0: case CELL_GCM_DEBUG_LEVEL1: case CELL_GCM_DEBUG_LEVEL2: - Emu.GetGSManager().GetRender().debug_level = level; + fxm::get()->debug_level = level; break; default: return CELL_EINVAL; @@ -438,16 +442,18 @@ s32 cellGcmSetDisplayBuffer(u32 id, u32 offset, u32 pitch, u32 width, u32 height return CELL_EINVAL; } - auto buffers = Emu.GetGSManager().GetRender().gcm_buffers; + const auto render = fxm::get(); + + auto buffers = render->gcm_buffers; buffers[id].offset = offset; buffers[id].pitch = pitch; buffers[id].width = width; buffers[id].height = height; - if (id + 1 > Emu.GetGSManager().GetRender().gcm_buffers_count) + if (id + 1 > render->gcm_buffers_count) { - Emu.GetGSManager().GetRender().gcm_buffers_count = id + 1; + render->gcm_buffers_count = id + 1; } return CELL_OK; @@ -457,7 +463,7 @@ void cellGcmSetFlipHandler(vm::ptr handler) { cellGcmSys.warning("cellGcmSetFlipHandler(handler=*0x%x)", handler); - Emu.GetGSManager().GetRender().flip_handler = handler; + fxm::get()->flip_handler = handler; } s32 cellGcmSetFlipMode(u32 mode) @@ -469,7 +475,7 @@ s32 cellGcmSetFlipMode(u32 mode) case CELL_GCM_DISPLAY_HSYNC: case CELL_GCM_DISPLAY_VSYNC: case CELL_GCM_DISPLAY_HSYNC_WITH_NOISE: - Emu.GetGSManager().GetRender().flip_mode = mode; + fxm::get()->flip_mode = mode; break; default: @@ -483,7 +489,7 @@ void cellGcmSetFlipStatus() { cellGcmSys.warning("cellGcmSetFlipStatus()"); - Emu.GetGSManager().GetRender().flip_status = 0; + fxm::get()->flip_status = 0; } s32 cellGcmSetPrepareFlip(PPUThread& ppu, vm::ptr ctxt, u32 id) @@ -541,14 +547,22 @@ s32 cellGcmSetSecondVFrequency(u32 freq) { cellGcmSys.warning("cellGcmSetSecondVFrequency(level=%d)", freq); + const auto render = fxm::get(); + switch (freq) { case CELL_GCM_DISPLAY_FREQUENCY_59_94HZ: - Emu.GetGSManager().GetRender().frequency_mode = freq; Emu.GetGSManager().GetRender().fps_limit = 59.94; break; + render->frequency_mode = freq; + render->fps_limit = 59.94; + break; case CELL_GCM_DISPLAY_FREQUENCY_SCANOUT: - Emu.GetGSManager().GetRender().frequency_mode = freq; cellGcmSys.todo("Unimplemented display frequency: Scanout"); break; + render->frequency_mode = freq; + cellGcmSys.todo("Unimplemented display frequency: Scanout"); + break; case CELL_GCM_DISPLAY_FREQUENCY_DISABLE: - Emu.GetGSManager().GetRender().frequency_mode = freq; cellGcmSys.todo("Unimplemented display frequency: Disabled"); break; + render->frequency_mode = freq; + cellGcmSys.todo("Unimplemented display frequency: Disabled"); + break; default: cellGcmSys.error("Improper display frequency specified!"); return CELL_OK; } @@ -583,7 +597,9 @@ s32 cellGcmSetTileInfo(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u cellGcmSys.error("cellGcmSetTileInfo: bad compression mode! (%d)", comp); } - auto& tile = Emu.GetGSManager().GetRender().tiles[index]; + const auto render = fxm::get(); + + auto& tile = render->tiles[index]; tile.location = location; tile.offset = offset; tile.size = size; @@ -592,7 +608,7 @@ s32 cellGcmSetTileInfo(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u tile.base = base; tile.bank = bank; - vm::_ptr(Emu.GetGSManager().GetRender().tiles_addr)[index] = tile.pack(); + vm::_ptr(render->tiles_addr)[index] = tile.pack(); return CELL_OK; } @@ -600,7 +616,7 @@ void cellGcmSetUserHandler(vm::ptr handler) { cellGcmSys.warning("cellGcmSetUserHandler(handler=*0x%x)", handler); - Emu.GetGSManager().GetRender().user_handler = handler; + fxm::get()->user_handler = handler; } s32 cellGcmSetUserCommand() @@ -612,7 +628,7 @@ void cellGcmSetVBlankHandler(vm::ptr handler) { cellGcmSys.warning("cellGcmSetVBlankHandler(handler=*0x%x)", handler); - Emu.GetGSManager().GetRender().vblank_handler = handler; + fxm::get()->vblank_handler = handler; } s32 cellGcmSetWaitFlip(vm::ptr ctxt) @@ -640,7 +656,9 @@ s32 cellGcmSetZcull(u8 index, u32 offset, u32 width, u32 height, u32 cullStart, return CELL_GCM_ERROR_INVALID_VALUE; } - auto& zcull = Emu.GetGSManager().GetRender().zculls[index]; + const auto render = fxm::get(); + + auto& zcull = render->zculls[index]; zcull.offset = offset; zcull.width = width; zcull.height = height; @@ -653,7 +671,7 @@ s32 cellGcmSetZcull(u8 index, u32 offset, u32 width, u32 height, u32 cullStart, zcull.sRef = sRef; zcull.sMask = sMask; - vm::_ptr(Emu.GetGSManager().GetRender().zculls_addr)[index] = zcull.pack(); + vm::_ptr(render->zculls_addr)[index] = zcull.pack(); return CELL_OK; } @@ -667,8 +685,7 @@ s32 cellGcmUnbindTile(u8 index) return CELL_GCM_ERROR_INVALID_VALUE; } - auto& tile = Emu.GetGSManager().GetRender().tiles[index]; - tile.binded = false; + fxm::get()->tiles[index].binded = false; return CELL_OK; } @@ -683,8 +700,7 @@ s32 cellGcmUnbindZcull(u8 index) return CELL_EINVAL; } - auto& zcull = Emu.GetGSManager().GetRender().zculls[index]; - zcull.binded = false; + fxm::get()->zculls[index].binded = false; return CELL_OK; } @@ -692,32 +708,30 @@ s32 cellGcmUnbindZcull(u8 index) u32 cellGcmGetTileInfo() { cellGcmSys.warning("cellGcmGetTileInfo()"); - return Emu.GetGSManager().GetRender().tiles_addr; + return fxm::get()->tiles_addr; } u32 cellGcmGetZcullInfo() { cellGcmSys.warning("cellGcmGetZcullInfo()"); - return Emu.GetGSManager().GetRender().zculls_addr; + return fxm::get()->zculls_addr; } u32 cellGcmGetDisplayInfo() { - cellGcmSys.warning("cellGcmGetDisplayInfo() = 0x%x", Emu.GetGSManager().GetRender().gcm_buffers.addr()); - return Emu.GetGSManager().GetRender().gcm_buffers.addr(); + cellGcmSys.warning("cellGcmGetDisplayInfo()"); + return fxm::get()->gcm_buffers.addr(); } s32 cellGcmGetCurrentDisplayBufferId(vm::ptr id) { cellGcmSys.warning("cellGcmGetCurrentDisplayBufferId(id=*0x%x)", id); - if (Emu.GetGSManager().GetRender().gcm_current_buffer > UINT8_MAX) + if ((*id = fxm::get()->gcm_current_buffer) > UINT8_MAX) { throw EXCEPTION("Unexpected"); } - *id = Emu.GetGSManager().GetRender().gcm_current_buffer; - return CELL_OK; } @@ -748,7 +762,7 @@ u64 cellGcmGetLastFlipTime() { cellGcmSys.trace("cellGcmGetLastFlipTime()"); - return Emu.GetGSManager().GetRender().last_flip_time; + return fxm::get()->last_flip_time; } u64 cellGcmGetLastSecondVTime() @@ -761,7 +775,7 @@ u64 cellGcmGetVBlankCount() { cellGcmSys.trace("cellGcmGetVBlankCount()"); - return Emu.GetGSManager().GetRender().vblank_count; + return fxm::get()->vblank_count; } s32 cellGcmSysGetLastVBlankTime() @@ -896,6 +910,8 @@ s32 gcmMapEaIoAddress(u32 ea, u32 io, u32 size, bool is_strict) { if ((ea & 0xFFFFF) || (io & 0xFFFFF) || (size & 0xFFFFF)) return CELL_GCM_ERROR_FAILURE; + const auto render = fxm::get(); + // Check if the mapping was successfull if (RSXIOMem.Map(ea, size, io)) { @@ -904,7 +920,7 @@ s32 gcmMapEaIoAddress(u32 ea, u32 io, u32 size, bool is_strict) { offsetTable.ioAddress[(ea >> 20) + i] = (io >> 20) + i; offsetTable.eaAddress[(io >> 20) + i] = (ea >> 20) + i; - Emu.GetGSManager().GetRender().strict_ordering[(io >> 20) + i] = is_strict; + render->strict_ordering[(io >> 20) + i] = is_strict; } } else @@ -927,7 +943,7 @@ s32 cellGcmMapEaIoAddressWithFlags(u32 ea, u32 io, u32 size, u32 flags) { cellGcmSys.warning("cellGcmMapEaIoAddressWithFlags(ea=0x%x, io=0x%x, size=0x%x, flags=0x%x)", ea, io, size, flags); - assert(flags == 2 /*CELL_GCM_IOMAP_FLAG_STRICT_ORDERING*/); + ASSERT(flags == 2 /*CELL_GCM_IOMAP_FLAG_STRICT_ORDERING*/); return gcmMapEaIoAddress(ea, io, size, true); } @@ -958,6 +974,8 @@ s32 cellGcmMapMainMemory(u32 ea, u32 size, vm::ptr offset) u32 io = RSXIOMem.Map(ea, size); + const auto render = fxm::get(); + //check if the mapping was successfull if (RSXIOMem.RealAddr(io) == ea) { @@ -966,7 +984,7 @@ s32 cellGcmMapMainMemory(u32 ea, u32 size, vm::ptr offset) { offsetTable.ioAddress[(ea >> 20) + i] = (u16)((io >> 20) + i); offsetTable.eaAddress[(io >> 20) + i] = (u16)((ea >> 20) + i); - Emu.GetGSManager().GetRender().strict_ordering[(io >> 20) + i] = false; + render->strict_ordering[(io >> 20) + i] = false; } *offset = io; @@ -977,7 +995,7 @@ s32 cellGcmMapMainMemory(u32 ea, u32 size, vm::ptr offset) return CELL_GCM_ERROR_NO_IO_PAGE_TABLE; } - Emu.GetGSManager().GetRender().main_mem_addr = Emu.GetGSManager().GetRender().ioAddress; + render->main_mem_addr = render->ioAddress; return CELL_OK; } @@ -1117,7 +1135,7 @@ s32 cellGcmSetCursorImageOffset(u32 offset) void cellGcmSetDefaultCommandBuffer() { cellGcmSys.warning("cellGcmSetDefaultCommandBuffer()"); - vm::write32(Emu.GetGSManager().GetRender().ctxt_addr, gcm_info.context_addr); + vm::write32(fxm::get()->ctxt_addr, gcm_info.context_addr); } s32 cellGcmSetDefaultCommandBufferAndSegmentWordSize() @@ -1174,7 +1192,9 @@ s32 cellGcmSetTile(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u8 co cellGcmSys.error("cellGcmSetTile: bad compression mode! (%d)", comp); } - auto& tile = Emu.GetGSManager().GetRender().tiles[index]; + const auto render = fxm::get(); + + auto& tile = render->tiles[index]; tile.location = location; tile.offset = offset; tile.size = size; @@ -1183,7 +1203,7 @@ s32 cellGcmSetTile(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u8 co tile.base = base; tile.bank = bank; - vm::_ptr(Emu.GetGSManager().GetRender().tiles_addr)[index] = tile.pack(); + vm::_ptr(render->tiles_addr)[index] = tile.pack(); return CELL_OK; } @@ -1247,7 +1267,7 @@ static std::pair getNextCommandBufferBeginEnd(u32 current) static u32 getOffsetFromAddress(u32 address) { const u32 upper = offsetTable.ioAddress[address >> 20]; // 12 bits - assert(upper != 0xFFFF); + Expects(upper != 0xFFFF); return (upper << 20) | (address & 0xFFFFF); } @@ -1269,7 +1289,6 @@ static bool isInCommandBufferExcept(u32 getPos, u32 bufferBegin, u32 bufferEnd) return true; } -// TODO: Avoid using syscall 1023 for calling this function s32 cellGcmCallback(vm::ptr context, u32 count) { cellGcmSys.trace("cellGcmCallback(context=*0x%x, count=0x%x)", context, count); @@ -1306,13 +1325,8 @@ s32 cellGcmCallback(vm::ptr context, u32 count) //---------------------------------------------------------------------------- -Module<> cellGcmSys("cellGcmSys", []() +DECLARE(ppu_module_manager::cellGcmSys)("cellGcmSys", []() { - current_config.ioAddress = 0; - current_config.localAddress = 0; - local_size = 0; - local_addr = 0; - // Data Retrieval REG_FUNC(cellGcmSys, cellGcmGetCurrentField); REG_FUNC(cellGcmSys, cellGcmGetLabelAddress); @@ -1419,4 +1433,7 @@ Module<> cellGcmSys("cellGcmSys", []() REG_FUNC(cellGcmSys, cellGcmGpadGetStatus); REG_FUNC(cellGcmSys, cellGcmGpadNotifyCaptureSurface); REG_FUNC(cellGcmSys, cellGcmGpadCaptureSnapshot); + + // Special + REG_FNID(cellGcmSys, 0x00000000, cellGcmCallback); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.h b/rpcs3/Emu/Cell/Modules/cellGcmSys.h similarity index 87% rename from rpcs3/Emu/SysCalls/Modules/cellGcmSys.h rename to rpcs3/Emu/Cell/Modules/cellGcmSys.h index 58f7a7dc1a..1c4109cbcb 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.h +++ b/rpcs3/Emu/Cell/Modules/cellGcmSys.h @@ -22,6 +22,3 @@ struct CellGcmOffsetTable // Auxiliary functions s32 gcmMapEaIoAddress(u32 ea, u32 io, u32 size, bool is_strict); - -// Syscall -s32 cellGcmCallback(vm::ptr context, u32 count); diff --git a/rpcs3/Emu/SysCalls/Modules/cellGem.cpp b/rpcs3/Emu/Cell/Modules/cellGem.cpp similarity index 69% rename from rpcs3/Emu/SysCalls/Modules/cellGem.cpp rename to rpcs3/Emu/Cell/Modules/cellGem.cpp index a2e3910fad..f10e41ea58 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGem.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGem.cpp @@ -1,11 +1,10 @@ #include "stdafx.h" #include "Emu/IdManager.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellGem.h" -extern Module<> cellGem; +LOG_CHANNEL(cellGem); struct gem_t { @@ -273,43 +272,43 @@ s32 cellGemWriteExternalPort() return CELL_OK; } -Module<> cellGem("cellGem", []() +DECLARE(ppu_module_manager::cellGem)("libgem", []() { - REG_FUNC(cellGem, cellGemCalibrate); - REG_FUNC(cellGem, cellGemClearStatusFlags); - REG_FUNC(cellGem, cellGemConvertVideoFinish); - REG_FUNC(cellGem, cellGemConvertVideoStart); - REG_FUNC(cellGem, cellGemEnableCameraPitchAngleCorrection); - REG_FUNC(cellGem, cellGemEnableMagnetometer); - REG_FUNC(cellGem, cellGemEnd); - REG_FUNC(cellGem, cellGemFilterState); - REG_FUNC(cellGem, cellGemForceRGB); - REG_FUNC(cellGem, cellGemGetAccelerometerPositionInDevice); - REG_FUNC(cellGem, cellGemGetAllTrackableHues); - REG_FUNC(cellGem, cellGemGetCameraState); - REG_FUNC(cellGem, cellGemGetEnvironmentLightingColor); - REG_FUNC(cellGem, cellGemGetHuePixels); - REG_FUNC(cellGem, cellGemGetImageState); - REG_FUNC(cellGem, cellGemGetInertialState); - REG_FUNC(cellGem, cellGemGetInfo); - REG_FUNC(cellGem, cellGemGetMemorySize); - REG_FUNC(cellGem, cellGemGetRGB); - REG_FUNC(cellGem, cellGemGetRumble); - REG_FUNC(cellGem, cellGemGetState); - REG_FUNC(cellGem, cellGemGetStatusFlags); - REG_FUNC(cellGem, cellGemGetTrackerHue); - REG_FUNC(cellGem, cellGemHSVtoRGB); - REG_FUNC(cellGem, cellGemInit); - REG_FUNC(cellGem, cellGemInvalidateCalibration); - REG_FUNC(cellGem, cellGemIsTrackableHue); - REG_FUNC(cellGem, cellGemPrepareCamera); - REG_FUNC(cellGem, cellGemPrepareVideoConvert); - REG_FUNC(cellGem, cellGemReadExternalPortDeviceInfo); - REG_FUNC(cellGem, cellGemReset); - REG_FUNC(cellGem, cellGemSetRumble); - REG_FUNC(cellGem, cellGemSetYaw); - REG_FUNC(cellGem, cellGemTrackHues); - REG_FUNC(cellGem, cellGemUpdateFinish); - REG_FUNC(cellGem, cellGemUpdateStart); - REG_FUNC(cellGem, cellGemWriteExternalPort); + REG_FUNC(libgem, cellGemCalibrate); + REG_FUNC(libgem, cellGemClearStatusFlags); + REG_FUNC(libgem, cellGemConvertVideoFinish); + REG_FUNC(libgem, cellGemConvertVideoStart); + REG_FUNC(libgem, cellGemEnableCameraPitchAngleCorrection); + REG_FUNC(libgem, cellGemEnableMagnetometer); + REG_FUNC(libgem, cellGemEnd); + REG_FUNC(libgem, cellGemFilterState); + REG_FUNC(libgem, cellGemForceRGB); + REG_FUNC(libgem, cellGemGetAccelerometerPositionInDevice); + REG_FUNC(libgem, cellGemGetAllTrackableHues); + REG_FUNC(libgem, cellGemGetCameraState); + REG_FUNC(libgem, cellGemGetEnvironmentLightingColor); + REG_FUNC(libgem, cellGemGetHuePixels); + REG_FUNC(libgem, cellGemGetImageState); + REG_FUNC(libgem, cellGemGetInertialState); + REG_FUNC(libgem, cellGemGetInfo); + REG_FUNC(libgem, cellGemGetMemorySize); + REG_FUNC(libgem, cellGemGetRGB); + REG_FUNC(libgem, cellGemGetRumble); + REG_FUNC(libgem, cellGemGetState); + REG_FUNC(libgem, cellGemGetStatusFlags); + REG_FUNC(libgem, cellGemGetTrackerHue); + REG_FUNC(libgem, cellGemHSVtoRGB); + REG_FUNC(libgem, cellGemInit); + REG_FUNC(libgem, cellGemInvalidateCalibration); + REG_FUNC(libgem, cellGemIsTrackableHue); + REG_FUNC(libgem, cellGemPrepareCamera); + REG_FUNC(libgem, cellGemPrepareVideoConvert); + REG_FUNC(libgem, cellGemReadExternalPortDeviceInfo); + REG_FUNC(libgem, cellGemReset); + REG_FUNC(libgem, cellGemSetRumble); + REG_FUNC(libgem, cellGemSetYaw); + REG_FUNC(libgem, cellGemTrackHues); + REG_FUNC(libgem, cellGemUpdateFinish); + REG_FUNC(libgem, cellGemUpdateStart); + REG_FUNC(libgem, cellGemWriteExternalPort); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellGem.h b/rpcs3/Emu/Cell/Modules/cellGem.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellGem.h rename to rpcs3/Emu/Cell/Modules/cellGem.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp b/rpcs3/Emu/Cell/Modules/cellGifDec.cpp similarity index 94% rename from rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp rename to rpcs3/Emu/Cell/Modules/cellGifDec.cpp index 4cef65232d..64c10ca7cf 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGifDec.cpp @@ -1,19 +1,15 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" // STB_IMAGE_IMPLEMENTATION is already defined in stb_image.cpp #include -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFileBase.h" -#include "Emu/SysCalls/lv2/sys_fs.h" - +#include "Emu/Cell/lv2/sys_fs.h" #include "cellGifDec.h" -extern Module<> cellGifDec; +LOG_CHANNEL(cellGifDec); // cellGifDec aliases (only for cellGifDec.cpp) using PPMainHandle = vm::pptr; @@ -61,11 +57,11 @@ s32 cellGifDecOpen(PMainHandle mainHandle, PPSubHandle subHandle, PSrc src, POpe case CELL_GIFDEC_FILE: { // Get file descriptor and size - std::shared_ptr file_s(Emu.GetVFS().OpenFile(src->fileName.get_ptr(), fom::read)); + fs::file file_s(vfs::get(src->fileName.get_ptr())); if (!file_s) return CELL_GIFDEC_ERROR_OPEN_FILE; - current_subHandle.fd = idm::make(file_s, 0, 0); - current_subHandle.fileSize = file_s->GetSize(); + current_subHandle.fileSize = file_s.size(); + current_subHandle.fd = idm::make(std::move(file_s), 0, 0); break; } } @@ -102,8 +98,8 @@ s32 cellGifDecReadHeader(PMainHandle mainHandle, PSubHandle subHandle, PInfo inf case CELL_GIFDEC_FILE: { auto file = idm::get(fd); - file->file->Seek(0); - file->file->Read(buffer, sizeof(buffer)); + file->file.seek(0); + file->file.read(buffer, sizeof(buffer)); break; } } @@ -186,8 +182,8 @@ s32 cellGifDecDecodeData(PMainHandle mainHandle, PSubHandle subHandle, vm::ptr(fd); - file->file->Seek(0); - file->file->Read(gif.get(), fileSize); + file->file.seek(0); + file->file.read(gif.get(), fileSize); break; } } @@ -300,7 +296,7 @@ s32 cellGifDecDestroy(PMainHandle mainHandle) return CELL_OK; } -Module<> cellGifDec("cellGifDec", []() +DECLARE(ppu_module_manager::cellGifDec)("cellGifDec", []() { REG_FUNC(cellGifDec, cellGifDecCreate); REG_FUNC(cellGifDec, cellGifDecExtCreate); diff --git a/rpcs3/Emu/SysCalls/Modules/cellGifDec.h b/rpcs3/Emu/Cell/Modules/cellGifDec.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellGifDec.h rename to rpcs3/Emu/Cell/Modules/cellGifDec.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellHttp.cpp b/rpcs3/Emu/Cell/Modules/cellHttp.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellHttp.cpp rename to rpcs3/Emu/Cell/Modules/cellHttp.cpp index ee6a48fcbc..46328b1cf7 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellHttp.cpp +++ b/rpcs3/Emu/Cell/Modules/cellHttp.cpp @@ -1,9 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellHttp; -extern Module<> cellHttps; +LOG_CHANNEL(cellHttp); s32 cellHttpInit() { @@ -599,7 +597,7 @@ s32 cellHttpClientSetSslIdDestroyCallback() return CELL_OK; } -Module<> cellHttp("cellHttp", []() +DECLARE(ppu_module_manager::cellHttp)("cellHttp", []() { REG_FUNC(cellHttp, cellHttpInit); REG_FUNC(cellHttp, cellHttpEnd); @@ -713,7 +711,7 @@ Module<> cellHttp("cellHttp", []() REG_FUNC(cellHttp, cellHttpClientSetSslIdDestroyCallback); }); -Module<> cellHttps("cellHttps", []() +DECLARE(ppu_module_manager::cellHttps)("cellHttps", []() { // cellHttps doesn't have functions (cellHttpsInit belongs to cellHttp, for example) }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellHttpUtil.cpp b/rpcs3/Emu/Cell/Modules/cellHttpUtil.cpp similarity index 95% rename from rpcs3/Emu/SysCalls/Modules/cellHttpUtil.cpp rename to rpcs3/Emu/Cell/Modules/cellHttpUtil.cpp index 4625593b15..35c7c5328c 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellHttpUtil.cpp +++ b/rpcs3/Emu/Cell/Modules/cellHttpUtil.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellHttpUtil; +LOG_CHANNEL(cellHttpUtil); s32 cellHttpUtilParseUri() { @@ -124,7 +123,7 @@ s32 cellHttpUtilBase64Decoder() return CELL_OK; } -Module<> cellHttpUtil("cellHttpUtil", []() +DECLARE(ppu_module_manager::cellHttpUtil)("cellHttpUtil", []() { REG_FUNC(cellHttpUtil, cellHttpUtilParseUri); REG_FUNC(cellHttpUtil, cellHttpUtilParseUriPath); diff --git a/rpcs3/Emu/SysCalls/Modules/cellImejp.cpp b/rpcs3/Emu/Cell/Modules/cellImejp.cpp similarity index 62% rename from rpcs3/Emu/SysCalls/Modules/cellImejp.cpp rename to rpcs3/Emu/Cell/Modules/cellImejp.cpp index d1959b36c9..278103fd3f 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellImejp.cpp +++ b/rpcs3/Emu/Cell/Modules/cellImejp.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellImeJp; +LOG_CHANNEL(cellImeJp); // Return Codes enum @@ -262,50 +261,50 @@ s32 cellImeJpConfirmPrediction() return CELL_OK; } -Module<> cellImeJp("cellImeJp", []() +DECLARE(ppu_module_manager::cellImeJp)("cellImeJpUtility", []() { - REG_FUNC(cellImeJp, cellImeJpOpen); - REG_FUNC(cellImeJp, cellImeJpOpen2); - REG_FUNC(cellImeJp, cellImeJpOpen3); - REG_FUNC(cellImeJp, cellImeJpClose); + REG_FUNC(cellImeJpUtility, cellImeJpOpen); + REG_FUNC(cellImeJpUtility, cellImeJpOpen2); + REG_FUNC(cellImeJpUtility, cellImeJpOpen3); + REG_FUNC(cellImeJpUtility, cellImeJpClose); - REG_FUNC(cellImeJp, cellImeJpSetKanaInputMode); - REG_FUNC(cellImeJp, cellImeJpSetInputCharType); - REG_FUNC(cellImeJp, cellImeJpSetFixInputMode); - REG_FUNC(cellImeJp, cellImeJpAllowExtensionCharacters); - REG_FUNC(cellImeJp, cellImeJpReset); + REG_FUNC(cellImeJpUtility, cellImeJpSetKanaInputMode); + REG_FUNC(cellImeJpUtility, cellImeJpSetInputCharType); + REG_FUNC(cellImeJpUtility, cellImeJpSetFixInputMode); + REG_FUNC(cellImeJpUtility, cellImeJpAllowExtensionCharacters); + REG_FUNC(cellImeJpUtility, cellImeJpReset); - REG_FUNC(cellImeJp, cellImeJpGetStatus); + REG_FUNC(cellImeJpUtility, cellImeJpGetStatus); - REG_FUNC(cellImeJp, cellImeJpEnterChar); - REG_FUNC(cellImeJp, cellImeJpEnterCharExt); - REG_FUNC(cellImeJp, cellImeJpEnterString); - REG_FUNC(cellImeJp, cellImeJpEnterStringExt); - REG_FUNC(cellImeJp, cellImeJpModeCaretRight); - REG_FUNC(cellImeJp, cellImeJpModeCaretLeft); - REG_FUNC(cellImeJp, cellImeJpBackspaceWord); - REG_FUNC(cellImeJp, cellImeJpDeleteWord); - REG_FUNC(cellImeJp, cellImeJpAllDeleteConvertString); - REG_FUNC(cellImeJp, cellImeJpConvertForward); - REG_FUNC(cellImeJp, cellImeJpConvertBackward); - REG_FUNC(cellImeJp, cellImeJpCurrentPartConfirm); - REG_FUNC(cellImeJp, cellImeJpAllConfirm); - REG_FUNC(cellImeJp, cellImeJpConvertCancel); - REG_FUNC(cellImeJp, cellImeJpAllConvertCancel); - REG_FUNC(cellImeJp, cellImeJpExtendConvertArea); - REG_FUNC(cellImeJp, cellImeJpShortenConvertArea); - REG_FUNC(cellImeJp, cellImeJpTemporalConfirm); - REG_FUNC(cellImeJp, cellImeJpPostConvert); - REG_FUNC(cellImeJp, cellImeJpMoveFocusClause); - REG_FUNC(cellImeJp, cellImeJpGetFocusTop); - REG_FUNC(cellImeJp, cellImeJpGetFocusLength); - REG_FUNC(cellImeJp, cellImeJpGetConfirmYomiString); - REG_FUNC(cellImeJp, cellImeJpGetConfirmString); - REG_FUNC(cellImeJp, cellImeJpGetConvertYomiString); - REG_FUNC(cellImeJp, cellImeJpGetConvertString); - REG_FUNC(cellImeJp, cellImeJpGetCandidateListSize); - REG_FUNC(cellImeJp, cellImeJpGetCandidateList); - REG_FUNC(cellImeJp, cellImeJpGetCandidateSelect); - REG_FUNC(cellImeJp, cellImeJpGetPredictList); - REG_FUNC(cellImeJp, cellImeJpConfirmPrediction); + REG_FUNC(cellImeJpUtility, cellImeJpEnterChar); + REG_FUNC(cellImeJpUtility, cellImeJpEnterCharExt); + REG_FUNC(cellImeJpUtility, cellImeJpEnterString); + REG_FUNC(cellImeJpUtility, cellImeJpEnterStringExt); + REG_FUNC(cellImeJpUtility, cellImeJpModeCaretRight); + REG_FUNC(cellImeJpUtility, cellImeJpModeCaretLeft); + REG_FUNC(cellImeJpUtility, cellImeJpBackspaceWord); + REG_FUNC(cellImeJpUtility, cellImeJpDeleteWord); + REG_FUNC(cellImeJpUtility, cellImeJpAllDeleteConvertString); + REG_FUNC(cellImeJpUtility, cellImeJpConvertForward); + REG_FUNC(cellImeJpUtility, cellImeJpConvertBackward); + REG_FUNC(cellImeJpUtility, cellImeJpCurrentPartConfirm); + REG_FUNC(cellImeJpUtility, cellImeJpAllConfirm); + REG_FUNC(cellImeJpUtility, cellImeJpConvertCancel); + REG_FUNC(cellImeJpUtility, cellImeJpAllConvertCancel); + REG_FUNC(cellImeJpUtility, cellImeJpExtendConvertArea); + REG_FUNC(cellImeJpUtility, cellImeJpShortenConvertArea); + REG_FUNC(cellImeJpUtility, cellImeJpTemporalConfirm); + REG_FUNC(cellImeJpUtility, cellImeJpPostConvert); + REG_FUNC(cellImeJpUtility, cellImeJpMoveFocusClause); + REG_FUNC(cellImeJpUtility, cellImeJpGetFocusTop); + REG_FUNC(cellImeJpUtility, cellImeJpGetFocusLength); + REG_FUNC(cellImeJpUtility, cellImeJpGetConfirmYomiString); + REG_FUNC(cellImeJpUtility, cellImeJpGetConfirmString); + REG_FUNC(cellImeJpUtility, cellImeJpGetConvertYomiString); + REG_FUNC(cellImeJpUtility, cellImeJpGetConvertString); + REG_FUNC(cellImeJpUtility, cellImeJpGetCandidateListSize); + REG_FUNC(cellImeJpUtility, cellImeJpGetCandidateList); + REG_FUNC(cellImeJpUtility, cellImeJpGetCandidateSelect); + REG_FUNC(cellImeJpUtility, cellImeJpGetPredictList); + REG_FUNC(cellImeJpUtility, cellImeJpConfirmPrediction); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp b/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp similarity index 94% rename from rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp rename to rpcs3/Emu/Cell/Modules/cellJpgDec.cpp index 0c5ded73b9..3fcb2a967e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp @@ -1,19 +1,15 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" // STB_IMAGE_IMPLEMENTATION is already defined in stb_image.cpp #include -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFileBase.h" -#include "Emu/SysCalls/lv2/sys_fs.h" - +#include "Emu/Cell/lv2/sys_fs.h" #include "cellJpgDec.h" -extern Module<> cellJpgDec; +LOG_CHANNEL(cellJpgDec); s32 cellJpgDecCreate(u32 mainHandle, u32 threadInParam, u32 threadOutParam) { @@ -51,11 +47,11 @@ s32 cellJpgDecOpen(u32 mainHandle, vm::ptr subHandle, vm::ptr file_s(Emu.GetVFS().OpenFile(src->fileName.get_ptr(), fom::read)); + fs::file file_s(vfs::get(src->fileName.get_ptr())); if (!file_s) return CELL_JPGDEC_ERROR_OPEN_FILE; - current_subHandle.fd = idm::make(file_s, 0, 0); - current_subHandle.fileSize = file_s->GetSize(); + current_subHandle.fileSize = file_s.size(); + current_subHandle.fd = idm::make(std::move(file_s), 0, 0); break; } } @@ -115,8 +111,8 @@ s32 cellJpgDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr case CELL_JPGDEC_FILE: { auto file = idm::get(fd); - file->file->Seek(0); - file->file->Read(buffer.get(), fileSize); + file->file.seek(0); + file->file.read(buffer.get(), fileSize); break; } } @@ -194,8 +190,8 @@ s32 cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr data, vm::cp case CELL_JPGDEC_FILE: { auto file = idm::get(fd); - file->file->Seek(0); - file->file->Read(jpg.get(), fileSize); + file->file.seek(0); + file->file.read(jpg.get(), fileSize); break; } } @@ -357,7 +353,7 @@ s32 cellJpgDecExtSetParameter() } -Module<> cellJpgDec("cellJpgDec", []() +DECLARE(ppu_module_manager::cellJpgDec)("cellJpgDec", []() { REG_FUNC(cellJpgDec, cellJpgDecCreate); REG_FUNC(cellJpgDec, cellJpgDecExtCreate); diff --git a/rpcs3/Emu/SysCalls/Modules/cellJpgDec.h b/rpcs3/Emu/Cell/Modules/cellJpgDec.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellJpgDec.h rename to rpcs3/Emu/Cell/Modules/cellJpgDec.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellJpgEnc.cpp b/rpcs3/Emu/Cell/Modules/cellJpgEnc.cpp similarity index 92% rename from rpcs3/Emu/SysCalls/Modules/cellJpgEnc.cpp rename to rpcs3/Emu/Cell/Modules/cellJpgEnc.cpp index 2b91af18b4..605a04e930 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellJpgEnc.cpp +++ b/rpcs3/Emu/Cell/Modules/cellJpgEnc.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellJpgEnc; +LOG_CHANNEL(cellJpgEnc); // Error Codes enum @@ -75,7 +74,7 @@ s32 cellJpgEncReset() return CELL_OK; } -Module<> cellJpgEnc("cellJpgEnc", []() +DECLARE(ppu_module_manager::cellJpgEnc)("cellJpgEnc", []() { REG_FUNC(cellJpgEnc, cellJpgEncQueryAttr); REG_FUNC(cellJpgEnc, cellJpgEncOpen); diff --git a/rpcs3/Emu/SysCalls/Modules/cellKb.cpp b/rpcs3/Emu/Cell/Modules/cellKb.cpp similarity index 81% rename from rpcs3/Emu/SysCalls/Modules/cellKb.cpp rename to rpcs3/Emu/Cell/Modules/cellKb.cpp index bab63108c2..a4647993b1 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellKb.cpp +++ b/rpcs3/Emu/Cell/Modules/cellKb.cpp @@ -1,35 +1,37 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/Io/Keyboard.h" +#include "Emu/Io/KeyboardHandler.h" #include "cellKb.h" -extern Module<> sys_io; +extern _log::channel sys_io; s32 cellKbInit(u32 max_connect) { sys_io.warning("cellKbInit(max_connect=%d)", max_connect); - if (Emu.GetKeyboardManager().IsInited()) - return CELL_KB_ERROR_ALREADY_INITIALIZED; if (max_connect > 7) return CELL_KB_ERROR_INVALID_PARAMETER; - Emu.GetKeyboardManager().Init(max_connect); + const auto handler = fxm::import(PURE_EXPR(Emu.GetCallbacks().get_kb_handler())); + + if (!handler) + return CELL_KB_ERROR_ALREADY_INITIALIZED; + + handler->Init(max_connect); return CELL_OK; } s32 cellKbEnd() { - sys_io.trace("cellKbEnd()"); + sys_io.notice("cellKbEnd()"); - if (!Emu.GetKeyboardManager().IsInited()) + if (!fxm::remove()) return CELL_KB_ERROR_UNINITIALIZED; - Emu.GetKeyboardManager().Close(); return CELL_OK; } @@ -37,10 +39,12 @@ s32 cellKbClearBuf(u32 port_no) { sys_io.trace("cellKbClearBuf(port_no=%d)", port_no); - if (!Emu.GetKeyboardManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_KB_ERROR_UNINITIALIZED; - if (port_no >= Emu.GetKeyboardManager().GetKeyboards().size()) + if (port_no >= handler->GetKeyboards().size()) return CELL_KB_ERROR_INVALID_PARAMETER; //? @@ -98,10 +102,12 @@ s32 cellKbGetInfo(vm::ptr info) { sys_io.trace("cellKbGetInfo(info=*0x%x)", info); - if (!Emu.GetKeyboardManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_KB_ERROR_UNINITIALIZED; - const KbInfo& current_info = Emu.GetKeyboardManager().GetInfo(); + const KbInfo& current_info = handler->GetInfo(); info->max_connect = current_info.max_connect; info->now_connect = current_info.now_connect; info->info = current_info.info; @@ -118,14 +124,17 @@ s32 cellKbRead(u32 port_no, vm::ptr data) { sys_io.trace("cellKbRead(port_no=%d, data=*0x%x)", port_no, data); - const std::vector& keyboards = Emu.GetKeyboardManager().GetKeyboards(); - if (!Emu.GetKeyboardManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_KB_ERROR_UNINITIALIZED; + const std::vector& keyboards = handler->GetKeyboards(); + if (port_no >= keyboards.size()) return CELL_KB_ERROR_INVALID_PARAMETER; - KbData& current_data = Emu.GetKeyboardManager().GetData(port_no); + KbData& current_data = handler->GetData(port_no); data->led = current_data.led; data->mkey = current_data.mkey; data->len = std::min((u32)current_data.len, CELL_KB_MAX_KEYCODES); @@ -144,10 +153,12 @@ s32 cellKbSetCodeType(u32 port_no, u32 type) { sys_io.trace("cellKbSetCodeType(port_no=%d,type=%d)", port_no, type); - if (!Emu.GetKeyboardManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_KB_ERROR_UNINITIALIZED; - KbConfig& current_config = Emu.GetKeyboardManager().GetConfig(port_no); + KbConfig& current_config = handler->GetConfig(port_no); current_config.code_type = type; return CELL_OK; } @@ -162,10 +173,12 @@ s32 cellKbSetReadMode(u32 port_no, u32 rmode) { sys_io.trace("cellKbSetReadMode(port_no=%d,rmode=%d)", port_no, rmode); - if (!Emu.GetKeyboardManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_KB_ERROR_UNINITIALIZED; - KbConfig& current_config = Emu.GetKeyboardManager().GetConfig(port_no); + KbConfig& current_config = handler->GetConfig(port_no); current_config.read_mode = rmode; return CELL_OK; @@ -175,10 +188,12 @@ s32 cellKbGetConfiguration(u32 port_no, vm::ptr config) { sys_io.trace("cellKbGetConfiguration(port_no=%d, config=*0x%x)", port_no, config); - if (!Emu.GetKeyboardManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_KB_ERROR_UNINITIALIZED; - const KbConfig& current_config = Emu.GetKeyboardManager().GetConfig(port_no); + const KbConfig& current_config = handler->GetConfig(port_no); config->arrange = current_config.arrange; config->read_mode = current_config.read_mode; config->code_type = current_config.code_type; diff --git a/rpcs3/Emu/SysCalls/Modules/cellKb.h b/rpcs3/Emu/Cell/Modules/cellKb.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellKb.h rename to rpcs3/Emu/Cell/Modules/cellKb.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellKey2char.cpp b/rpcs3/Emu/Cell/Modules/cellKey2char.cpp similarity index 88% rename from rpcs3/Emu/SysCalls/Modules/cellKey2char.cpp rename to rpcs3/Emu/Cell/Modules/cellKey2char.cpp index 72979257f6..3a51a3c347 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellKey2char.cpp +++ b/rpcs3/Emu/Cell/Modules/cellKey2char.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellKey2char; +LOG_CHANNEL(cellKey2char); // Return Codes enum @@ -46,7 +45,7 @@ s32 cellKey2CharSetArrangement() return CELL_OK; } -Module<> cellKey2char("cellKey2char", []() +DECLARE(ppu_module_manager::cellKey2char)("cellKey2char", []() { REG_FUNC(cellKey2char, cellKey2CharOpen); REG_FUNC(cellKey2char, cellKey2CharClose); diff --git a/rpcs3/Emu/SysCalls/Modules/cellL10n.cpp b/rpcs3/Emu/Cell/Modules/cellL10n.cpp similarity index 99% rename from rpcs3/Emu/SysCalls/Modules/cellL10n.cpp rename to rpcs3/Emu/Cell/Modules/cellL10n.cpp index ad209aecfc..73ec6cad6c 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellL10n.cpp +++ b/rpcs3/Emu/Cell/Modules/cellL10n.cpp @@ -1,9 +1,8 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #ifdef _WIN32 -#include +#include #endif #ifdef _MSC_VER @@ -15,7 +14,7 @@ typedef const char *HostCode; #include "cellL10n.h" -extern Module<> cellL10n; +LOG_CHANNEL(cellL10n); // Translate code id to code name. some codepage may has another name. // If this makes your compilation fail, try replace the string code with one in "iconv -l" @@ -1061,7 +1060,7 @@ s32 UTF8toBIG5() s32 UTF16stoUTF8s(vm::cptr utf16, vm::ref utf16_len, vm::ptr utf8, vm::ref utf8_len) { - cellL10n.error("UTF16stoUTF8s(utf16=*0x%x, utf16_len=*0x%x, utf8=*0x%x, utf8_len=*0x%x)", utf16, utf16_len, utf8, utf8_len); + cellL10n.error("UTF16stoUTF8s(utf16=*0x%x, utf16_len=*0x%x, utf8=*0x%x, utf8_len=*0x%x)", utf16, utf16_len.addr(), utf8, utf8_len.addr()); const u32 max_len = utf8_len; utf8_len = 0; @@ -1170,7 +1169,7 @@ s32 UTF8stoUCS2s() } -Module<> cellL10n("cellL10n", []() +DECLARE(ppu_module_manager::cellL10n)("cellL10n", []() { REG_FUNC(cellL10n, UCS2toEUCJP); REG_FUNC(cellL10n, l10n_convert); diff --git a/rpcs3/Emu/SysCalls/Modules/cellL10n.h b/rpcs3/Emu/Cell/Modules/cellL10n.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellL10n.h rename to rpcs3/Emu/Cell/Modules/cellL10n.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellMic.cpp b/rpcs3/Emu/Cell/Modules/cellMic.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/cellMic.cpp rename to rpcs3/Emu/Cell/Modules/cellMic.cpp index e5e3a9bce5..b0cd2b8ba7 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMic.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMic.cpp @@ -1,11 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellMic.h" -extern Module<> cellMic; +LOG_CHANNEL(cellMic); s32 cellMicInit() { @@ -260,13 +259,12 @@ s32 cellMicGetDeviceIdentifier() return CELL_OK; } -Module<> cellMic("cellMic", []() +DECLARE(ppu_module_manager::cellMic)("cellMic", []() { REG_FUNC(cellMic, cellMicInit); REG_FUNC(cellMic, cellMicEnd); REG_FUNC(cellMic, cellMicOpen); REG_FUNC(cellMic, cellMicClose); - REG_FUNC(cellMic, cellMicGetDeviceGUID); REG_FUNC(cellMic, cellMicGetType); REG_FUNC(cellMic, cellMicIsAttached); @@ -276,16 +274,13 @@ Module<> cellMic("cellMic", []() REG_FUNC(cellMic, cellMicGetSignalAttr); REG_FUNC(cellMic, cellMicSetSignalAttr); REG_FUNC(cellMic, cellMicGetSignalState); - REG_FUNC(cellMic, cellMicStart); REG_FUNC(cellMic, cellMicRead); REG_FUNC(cellMic, cellMicStop); REG_FUNC(cellMic, cellMicReset); - REG_FUNC(cellMic, cellMicSetNotifyEventQueue); REG_FUNC(cellMic, cellMicSetNotifyEventQueue2); REG_FUNC(cellMic, cellMicRemoveNotifyEventQueue); - REG_FUNC(cellMic, cellMicOpenEx); REG_FUNC(cellMic, cellMicStartEx); REG_FUNC(cellMic, cellMicGetFormatRaw); @@ -295,7 +290,6 @@ Module<> cellMic("cellMic", []() REG_FUNC(cellMic, cellMicReadRaw); REG_FUNC(cellMic, cellMicReadAux); REG_FUNC(cellMic, cellMicReadDsp); - REG_FUNC(cellMic, cellMicGetStatus); REG_FUNC(cellMic, cellMicStopEx); // this function shouldn't exist REG_FUNC(cellMic, cellMicSysShareClose); diff --git a/rpcs3/Emu/SysCalls/Modules/cellMic.h b/rpcs3/Emu/Cell/Modules/cellMic.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellMic.h rename to rpcs3/Emu/Cell/Modules/cellMic.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellMouse.cpp b/rpcs3/Emu/Cell/Modules/cellMouse.cpp similarity index 71% rename from rpcs3/Emu/SysCalls/Modules/cellMouse.cpp rename to rpcs3/Emu/Cell/Modules/cellMouse.cpp index e4aae28a40..e9cea73dc8 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMouse.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMouse.cpp @@ -1,42 +1,45 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/Io/Mouse.h" +#include "Emu/Io/MouseHandler.h" #include "cellMouse.h" -extern Module<> sys_io; +extern _log::channel sys_io; s32 cellMouseInit(u32 max_connect) { sys_io.warning("cellMouseInit(max_connect=%d)", max_connect); - if (Emu.GetMouseManager().IsInited()) - { - return CELL_MOUSE_ERROR_ALREADY_INITIALIZED; - } - if (max_connect > 7) { return CELL_MOUSE_ERROR_INVALID_PARAMETER; } - Emu.GetMouseManager().Init(max_connect); + const auto handler = fxm::import(PURE_EXPR(Emu.GetCallbacks().get_mouse_handler())); + + if (!handler) + { + return CELL_MOUSE_ERROR_ALREADY_INITIALIZED; + } + + handler->Init(max_connect); return CELL_OK; } - s32 cellMouseClearBuf(u32 port_no) { sys_io.trace("cellMouseClearBuf(port_no=%d)", port_no); - if (!Emu.GetMouseManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) { return CELL_MOUSE_ERROR_UNINITIALIZED; } - if (port_no >= Emu.GetMouseManager().GetMice().size()) + if (port_no >= handler->GetMice().size()) { return CELL_MOUSE_ERROR_INVALID_PARAMETER; } @@ -48,14 +51,13 @@ s32 cellMouseClearBuf(u32 port_no) s32 cellMouseEnd() { - sys_io.trace("cellMouseEnd()"); + sys_io.notice("cellMouseEnd()"); - if (!Emu.GetMouseManager().IsInited()) + if (!fxm::remove()) { return CELL_MOUSE_ERROR_UNINITIALIZED; } - Emu.GetMouseManager().Close(); return CELL_OK; } @@ -63,12 +65,14 @@ s32 cellMouseGetInfo(vm::ptr info) { sys_io.trace("cellMouseGetInfo(info=*0x%x)", info); - if (!Emu.GetMouseManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) { return CELL_MOUSE_ERROR_UNINITIALIZED; } - const MouseInfo& current_info = Emu.GetMouseManager().GetInfo(); + const MouseInfo& current_info = handler->GetInfo(); info->max_connect = current_info.max_connect; info->now_connect = current_info.now_connect; info->info = current_info.info; @@ -82,12 +86,15 @@ s32 cellMouseGetInfo(vm::ptr info) s32 cellMouseInfoTabletMode(u32 port_no, vm::ptr info) { sys_io.trace("cellMouseInfoTabletMode(port_no=%d, info=*0x%x)", port_no, info); - if (!Emu.GetMouseManager().IsInited()) + + const auto handler = fxm::get(); + + if (!handler) { return CELL_MOUSE_ERROR_UNINITIALIZED; } - if (port_no >= Emu.GetMouseManager().GetMice().size()) + if (port_no >= handler->GetMice().size()) { return CELL_MOUSE_ERROR_INVALID_PARAMETER; } @@ -101,16 +108,20 @@ s32 cellMouseInfoTabletMode(u32 port_no, vm::ptr info) s32 cellMouseGetData(u32 port_no, vm::ptr data) { sys_io.trace("cellMouseGetData(port_no=%d, data=*0x%x)", port_no, data); - if (!Emu.GetMouseManager().IsInited()) + + const auto handler = fxm::get(); + + if (!handler) { return CELL_MOUSE_ERROR_UNINITIALIZED; } - if (port_no >= Emu.GetMouseManager().GetMice().size()) + + if (port_no >= handler->GetMice().size()) { return CELL_MOUSE_ERROR_NO_DEVICE; } - MouseData& current_data = Emu.GetMouseManager().GetData(port_no); + MouseData& current_data = handler->GetData(port_no); data->update = current_data.update; data->buttons = current_data.buttons; data->x_axis = current_data.x_axis; @@ -147,20 +158,21 @@ s32 cellMouseGetTabletDataList(u32 port_no, u32 data_addr) return CELL_OK; } -s32 cellMouseGetRawData(u32 port_no, vm::ptr data) +s32 cellMouseGetRawData(u32 port_no, vm::ptr data) { sys_io.todo("cellMouseGetRawData(port_no=%d, data=*0x%x)", port_no, data); - /*if (!Emu.GetMouseManager().IsInited()) return CELL_MOUSE_ERROR_UNINITIALIZED; - if (port_no >= Emu.GetMouseManager().GetMice().size()) return CELL_MOUSE_ERROR_NO_DEVICE; - CellMouseRawData& current_rawdata = Emu.GetMouseManager().GetRawData(port_no); - data += current_rawdata.len; - for(s32 i=0; i(); + + if (!handler) { - data += current_rawdata.data[i]; + return CELL_MOUSE_ERROR_UNINITIALIZED; } - current_rawdata.len = 0;*/ + if (port_no >= handler->GetMice().size()) + { + return CELL_MOUSE_ERROR_NO_DEVICE; + } return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellMouse.h b/rpcs3/Emu/Cell/Modules/cellMouse.h similarity index 93% rename from rpcs3/Emu/SysCalls/Modules/cellMouse.h rename to rpcs3/Emu/Cell/Modules/cellMouse.h index 3831a6bea3..61b384f18e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMouse.h +++ b/rpcs3/Emu/Cell/Modules/cellMouse.h @@ -51,3 +51,9 @@ struct CellMouseDataList }; static const u32 CELL_MOUSE_MAX_CODES = 64; + +struct CellMouseRawData +{ + be_t len; + u8 data[CELL_MOUSE_MAX_CODES]; +}; diff --git a/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp b/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp similarity index 94% rename from rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp rename to rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp index bbba03473d..9718fa9a95 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMsgDialog.cpp @@ -1,14 +1,14 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/SysCalls/Callback.h" +#include "Emu/Cell/PPUModule.h" #include "cellSysutil.h" #include "cellMsgDialog.h" -extern Module<> cellSysutil; +#include + +extern _log::channel cellSysutil; s32 cellMsgDialogOpen() { @@ -61,7 +61,7 @@ s32 cellMsgDialogOpen2(u32 type, vm::cptr msgString, vm::ptr(WRAP_EXPR(Emu.GetCallbacks().get_msg_dialog())); + const auto dlg = fxm::import(PURE_EXPR(Emu.GetCallbacks().get_msg_dialog())); if (!dlg) { @@ -103,8 +103,21 @@ s32 cellMsgDialogOpen2(u32 type, vm::cptr msgString, vm::ptrCreate(msgString.get_ptr()))).get(); + // Make "shared" promise to workaround std::function limitation + auto spr = std::make_shared>(); + + // Get future + std::future future = spr->get_future(); + + // Run asynchronously in GUI thread + Emu.CallAfter([&, spr = std::move(spr)]() + { + dlg->Create(msgString.get_ptr()); + spr->set_value(); + }); + + // Wait for the "result" + future.get(); return CELL_OK; } @@ -206,7 +219,7 @@ s32 cellMsgDialogClose(f32 delay) const u64 wait_until = get_system_time() + static_cast(std::max(delay, 0.0f) * 1000); - thread_ctrl::spawn(PURE_EXPR("MsgDialog Thread"s), [=]() + thread_ctrl::spawn("MsgDialog Thread", [=]() { while (dlg->state == MsgDialogState::Open && get_system_time() < wait_until) { diff --git a/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.h b/rpcs3/Emu/Cell/Modules/cellMsgDialog.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellMsgDialog.h rename to rpcs3/Emu/Cell/Modules/cellMsgDialog.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellMusic.cpp b/rpcs3/Emu/Cell/Modules/cellMusic.cpp similarity index 61% rename from rpcs3/Emu/SysCalls/Modules/cellMusic.cpp rename to rpcs3/Emu/Cell/Modules/cellMusic.cpp index 38525e4f7d..6fe8cd4146 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMusic.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMusic.cpp @@ -1,13 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Callback.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellMusic.h" -extern Module<> cellMusic; +LOG_CHANNEL(cellMusic); struct music2_t { @@ -144,28 +142,28 @@ s32 cellMusicGetVolume2() } -Module<> cellMusic("cellMusic", []() +DECLARE(ppu_module_manager::cellMusic)("cellMusicUtility", []() { - REG_FUNC(cellMusic, cellMusicGetSelectionContext); - REG_FUNC(cellMusic, cellMusicSetSelectionContext2); - REG_FUNC(cellMusic, cellMusicSetVolume2); - REG_FUNC(cellMusic, cellMusicGetContentsId); - REG_FUNC(cellMusic, cellMusicSetSelectionContext); - REG_FUNC(cellMusic, cellMusicInitialize2SystemWorkload); - REG_FUNC(cellMusic, cellMusicGetPlaybackStatus2); - REG_FUNC(cellMusic, cellMusicGetContentsId2); - REG_FUNC(cellMusic, cellMusicFinalize); - REG_FUNC(cellMusic, cellMusicInitializeSystemWorkload); - REG_FUNC(cellMusic, cellMusicInitialize); - REG_FUNC(cellMusic, cellMusicFinalize2); - REG_FUNC(cellMusic, cellMusicGetSelectionContext2); - REG_FUNC(cellMusic, cellMusicGetVolume); - REG_FUNC(cellMusic, cellMusicGetPlaybackStatus); - REG_FUNC(cellMusic, cellMusicSetPlaybackCommand2); - REG_FUNC(cellMusic, cellMusicSetPlaybackCommand); - REG_FUNC(cellMusic, cellMusicSelectContents2); - REG_FUNC(cellMusic, cellMusicSelectContents); - REG_FUNC(cellMusic, cellMusicInitialize2); - REG_FUNC(cellMusic, cellMusicSetVolume); - REG_FUNC(cellMusic, cellMusicGetVolume2); + REG_FUNC(cellMusicUtility, cellMusicGetSelectionContext); + REG_FUNC(cellMusicUtility, cellMusicSetSelectionContext2); + REG_FUNC(cellMusicUtility, cellMusicSetVolume2); + REG_FUNC(cellMusicUtility, cellMusicGetContentsId); + REG_FUNC(cellMusicUtility, cellMusicSetSelectionContext); + REG_FUNC(cellMusicUtility, cellMusicInitialize2SystemWorkload); + REG_FUNC(cellMusicUtility, cellMusicGetPlaybackStatus2); + REG_FUNC(cellMusicUtility, cellMusicGetContentsId2); + REG_FUNC(cellMusicUtility, cellMusicFinalize); + REG_FUNC(cellMusicUtility, cellMusicInitializeSystemWorkload); + REG_FUNC(cellMusicUtility, cellMusicInitialize); + REG_FUNC(cellMusicUtility, cellMusicFinalize2); + REG_FUNC(cellMusicUtility, cellMusicGetSelectionContext2); + REG_FUNC(cellMusicUtility, cellMusicGetVolume); + REG_FUNC(cellMusicUtility, cellMusicGetPlaybackStatus); + REG_FUNC(cellMusicUtility, cellMusicSetPlaybackCommand2); + REG_FUNC(cellMusicUtility, cellMusicSetPlaybackCommand); + REG_FUNC(cellMusicUtility, cellMusicSelectContents2); + REG_FUNC(cellMusicUtility, cellMusicSelectContents); + REG_FUNC(cellMusicUtility, cellMusicInitialize2); + REG_FUNC(cellMusicUtility, cellMusicSetVolume); + REG_FUNC(cellMusicUtility, cellMusicGetVolume2); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellMusic.h b/rpcs3/Emu/Cell/Modules/cellMusic.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellMusic.h rename to rpcs3/Emu/Cell/Modules/cellMusic.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellMusicDecode.cpp b/rpcs3/Emu/Cell/Modules/cellMusicDecode.cpp similarity index 65% rename from rpcs3/Emu/SysCalls/Modules/cellMusicDecode.cpp rename to rpcs3/Emu/Cell/Modules/cellMusicDecode.cpp index 0d86d8c1d5..dcb43e75a8 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMusicDecode.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMusicDecode.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellMusicDecode; +LOG_CHANNEL(cellMusicDecode); // Return Codes enum @@ -145,27 +144,27 @@ s32 cellMusicDecodeGetContentsId2() } -Module<> cellMusicDecode("cellMusicDecode", []() +DECLARE(ppu_module_manager::cellMusicDecode)("cellMusicDecodeUtility", []() { - REG_FUNC(cellMusicDecode, cellMusicDecodeInitialize); - REG_FUNC(cellMusicDecode, cellMusicDecodeInitializeSystemWorkload); - REG_FUNC(cellMusicDecode, cellMusicDecodeFinalize); - REG_FUNC(cellMusicDecode, cellMusicDecodeSelectContents); - REG_FUNC(cellMusicDecode, cellMusicDecodeSetDecodeCommand); - REG_FUNC(cellMusicDecode, cellMusicDecodeGetDecodeStatus); - REG_FUNC(cellMusicDecode, cellMusicDecodeRead); - REG_FUNC(cellMusicDecode, cellMusicDecodeGetSelectionContext); - REG_FUNC(cellMusicDecode, cellMusicDecodeSetSelectionContext); - REG_FUNC(cellMusicDecode, cellMusicDecodeGetContentsId); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeInitialize); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeInitializeSystemWorkload); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeFinalize); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeSelectContents); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeSetDecodeCommand); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeGetDecodeStatus); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeRead); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeGetSelectionContext); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeSetSelectionContext); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeGetContentsId); - REG_FUNC(cellMusicDecode, cellMusicDecodeInitialize2); - REG_FUNC(cellMusicDecode, cellMusicDecodeInitialize2SystemWorkload); - REG_FUNC(cellMusicDecode, cellMusicDecodeFinalize2); - REG_FUNC(cellMusicDecode, cellMusicDecodeSelectContents2); - REG_FUNC(cellMusicDecode, cellMusicDecodeSetDecodeCommand2); - REG_FUNC(cellMusicDecode, cellMusicDecodeGetDecodeStatus2); - REG_FUNC(cellMusicDecode, cellMusicDecodeRead2); - REG_FUNC(cellMusicDecode, cellMusicDecodeGetSelectionContext2); - REG_FUNC(cellMusicDecode, cellMusicDecodeSetSelectionContext2); - REG_FUNC(cellMusicDecode, cellMusicDecodeGetContentsId2); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeInitialize2); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeInitialize2SystemWorkload); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeFinalize2); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeSelectContents2); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeSetDecodeCommand2); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeGetDecodeStatus2); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeRead2); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeGetSelectionContext2); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeSetSelectionContext2); + REG_FUNC(cellMusicDecodeUtility, cellMusicDecodeGetContentsId2); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellMusicExport.cpp b/rpcs3/Emu/Cell/Modules/cellMusicExport.cpp similarity index 72% rename from rpcs3/Emu/SysCalls/Modules/cellMusicExport.cpp rename to rpcs3/Emu/Cell/Modules/cellMusicExport.cpp index 690188e000..0c614e907e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMusicExport.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMusicExport.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellMusicExport; +LOG_CHANNEL(cellMusicExport); // Return Codes enum @@ -51,11 +50,11 @@ s32 cellMusicExportProgress() return CELL_OK; } -Module<> cellMusicExport("cellMusicExport", []() +DECLARE(ppu_module_manager::cellMusicExport)("cellMusicExportUtility", []() { - REG_FUNC(cellMusicExport, cellMusicExportInitialize); - REG_FUNC(cellMusicExport, cellMusicExportInitialize2); - REG_FUNC(cellMusicExport, cellMusicExportFinalize); - REG_FUNC(cellMusicExport, cellMusicExportFromFile); - REG_FUNC(cellMusicExport, cellMusicExportProgress); + REG_FUNC(cellMusicExportUtility, cellMusicExportInitialize); + REG_FUNC(cellMusicExportUtility, cellMusicExportInitialize2); + REG_FUNC(cellMusicExportUtility, cellMusicExportFinalize); + REG_FUNC(cellMusicExportUtility, cellMusicExportFromFile); + REG_FUNC(cellMusicExportUtility, cellMusicExportProgress); }); diff --git a/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp b/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp new file mode 100644 index 0000000000..361daa9849 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp @@ -0,0 +1,211 @@ +#include "stdafx.h" +#include "Emu/System.h" +#include "Emu/Cell/PPUModule.h" + +#include "cellSysutil.h" +#include "cellNetCtl.h" + +LOG_CHANNEL(cellNetCtl); + +cfg::map_entry g_cfg_net_status(cfg::root.net, "Connection status", +{ + { "Disconnected", CELL_NET_CTL_STATE_Disconnected }, + { "Connecting", CELL_NET_CTL_STATE_Connecting }, + { "Obtaining IP", CELL_NET_CTL_STATE_IPObtaining }, + { "IP Obtained", CELL_NET_CTL_STATE_IPObtained }, +}); + +cfg::string_entry g_cfg_net_ip_address(cfg::root.net, "IP address", "192.168.1.1"); + +s32 cellNetCtlInit() +{ + cellNetCtl.warning("cellNetCtlInit()"); + + return CELL_OK; +} + +s32 cellNetCtlTerm() +{ + cellNetCtl.warning("cellNetCtlTerm()"); + + return CELL_OK; +} + +s32 cellNetCtlGetState(vm::ptr state) +{ + cellNetCtl.trace("cellNetCtlGetState(state=*0x%x)", state); + + *state = g_cfg_net_status.get(); + return CELL_OK; +} + +s32 cellNetCtlAddHandler(vm::ptr handler, vm::ptr arg, vm::ptr hid) +{ + cellNetCtl.todo("cellNetCtlAddHandler(handler=*0x%x, arg=*0x%x, hid=*0x%x)", handler, arg, hid); + + return CELL_OK; +} + +s32 cellNetCtlDelHandler(s32 hid) +{ + cellNetCtl.todo("cellNetCtlDelHandler(hid=0x%x)", hid); + + return CELL_OK; +} + +s32 cellNetCtlGetInfo(s32 code, vm::ptr info) +{ + cellNetCtl.todo("cellNetCtlGetInfo(code=0x%x (%s), info=*0x%x)", code, InfoCodeToName(code), info); + + if (code == CELL_NET_CTL_INFO_MTU) + { + info->mtu = 1500; + } + else if (code == CELL_NET_CTL_INFO_LINK) + { + if (g_cfg_net_status.get() != CELL_NET_CTL_STATE_Disconnected) + { + info->link = CELL_NET_CTL_LINK_CONNECTED; + } + else + { + info->link = CELL_NET_CTL_LINK_DISCONNECTED; + } + } + else if (code == CELL_NET_CTL_INFO_IP_ADDRESS) + { + if (g_cfg_net_status.get() != CELL_NET_CTL_STATE_IPObtained) + { + // 0.0.0.0 seems to be the default address when no ethernet cables are connected to the PS3 + strcpy_trunc(info->ip_address, "0.0.0.0"); + } + else + { + strcpy_trunc(info->ip_address, g_cfg_net_ip_address); + } + } + else if (code == CELL_NET_CTL_INFO_NETMASK) + { + strcpy_trunc(info->netmask, "255.255.255.255"); + } + + return CELL_OK; +} + +s32 cellNetCtlNetStartDialogLoadAsync(vm::ptr param) +{ + cellNetCtl.error("cellNetCtlNetStartDialogLoadAsync(param=*0x%x)", param); + + // TODO: Actually sign into PSN or an emulated network similar to PSN (ESN) + // TODO: Properly open the dialog prompt for sign in + sysutilSendSystemCommand(CELL_SYSUTIL_NET_CTL_NETSTART_LOADED, 0); + sysutilSendSystemCommand(CELL_SYSUTIL_NET_CTL_NETSTART_FINISHED, 0); + + return CELL_OK; +} + +s32 cellNetCtlNetStartDialogAbortAsync() +{ + cellNetCtl.error("cellNetCtlNetStartDialogAbortAsync()"); + + return CELL_OK; +} + +s32 cellNetCtlNetStartDialogUnloadAsync(vm::ptr result) +{ + cellNetCtl.warning("cellNetCtlNetStartDialogUnloadAsync(result=*0x%x)", result); + + result->result = CELL_NET_CTL_ERROR_DIALOG_CANCELED; + sysutilSendSystemCommand(CELL_SYSUTIL_NET_CTL_NETSTART_UNLOADED, 0); + + return CELL_OK; +} + +s32 cellNetCtlGetNatInfo(vm::ptr natInfo) +{ + cellNetCtl.todo("cellNetCtlGetNatInfo(natInfo=*0x%x)", natInfo); + + if (natInfo->size == 0) + { + cellNetCtl.error("cellNetCtlGetNatInfo : CELL_NET_CTL_ERROR_INVALID_SIZE"); + return CELL_NET_CTL_ERROR_INVALID_SIZE; + } + + return CELL_OK; +} + +s32 cellGameUpdateInit() +{ + throw EXCEPTION(""); +} + +s32 cellGameUpdateTerm() +{ + throw EXCEPTION(""); +} + + +s32 cellGameUpdateCheckStartAsync() +{ + throw EXCEPTION(""); +} + +s32 cellGameUpdateCheckFinishAsync() +{ + throw EXCEPTION(""); +} + +s32 cellGameUpdateCheckStartWithoutDialogAsync() +{ + throw EXCEPTION(""); +} + +s32 cellGameUpdateCheckAbort() +{ + throw EXCEPTION(""); +} + +s32 cellGameUpdateCheckStartAsyncEx() +{ + throw EXCEPTION(""); +} + +s32 cellGameUpdateCheckFinishAsyncEx() +{ + throw EXCEPTION(""); +} + +s32 cellGameUpdateCheckStartWithoutDialogAsyncEx() +{ + throw EXCEPTION(""); +} + + +DECLARE(ppu_module_manager::cellNetCtl)("cellNetCtl", []() +{ + REG_FUNC(cellNetCtl, cellNetCtlInit); + REG_FUNC(cellNetCtl, cellNetCtlTerm); + + REG_FUNC(cellNetCtl, cellNetCtlGetState); + REG_FUNC(cellNetCtl, cellNetCtlAddHandler); + REG_FUNC(cellNetCtl, cellNetCtlDelHandler); + + REG_FUNC(cellNetCtl, cellNetCtlGetInfo); + + REG_FUNC(cellNetCtl, cellNetCtlNetStartDialogLoadAsync); + REG_FUNC(cellNetCtl, cellNetCtlNetStartDialogAbortAsync); + REG_FUNC(cellNetCtl, cellNetCtlNetStartDialogUnloadAsync); + + REG_FUNC(cellNetCtl, cellNetCtlGetNatInfo); + + REG_FUNC(cellNetCtl, cellGameUpdateInit); + REG_FUNC(cellNetCtl, cellGameUpdateTerm); + + REG_FUNC(cellNetCtl, cellGameUpdateCheckStartAsync); + REG_FUNC(cellNetCtl, cellGameUpdateCheckFinishAsync); + REG_FUNC(cellNetCtl, cellGameUpdateCheckStartWithoutDialogAsync); + REG_FUNC(cellNetCtl, cellGameUpdateCheckAbort); + REG_FUNC(cellNetCtl, cellGameUpdateCheckStartAsyncEx); + REG_FUNC(cellNetCtl, cellGameUpdateCheckFinishAsyncEx); + REG_FUNC(cellNetCtl, cellGameUpdateCheckStartWithoutDialogAsyncEx); +}); diff --git a/rpcs3/Emu/SysCalls/Modules/cellNetCtl.h b/rpcs3/Emu/Cell/Modules/cellNetCtl.h similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/cellNetCtl.h rename to rpcs3/Emu/Cell/Modules/cellNetCtl.h index 4e08262927..28900f7a56 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellNetCtl.h +++ b/rpcs3/Emu/Cell/Modules/cellNetCtl.h @@ -220,19 +220,19 @@ union CellNetCtlInfo CellNetCtlSSID ssid; be_t wlan_security; be_t auth_8021x_type; - s8 auth_8021x_auth_name[128]; + char auth_8021x_auth_name[128]; u8 rssi; u8 channel; be_t ip_config; - s8 dhcp_hostname[256]; - s8 pppoe_auth_name[128]; + char dhcp_hostname[256]; + char pppoe_auth_name[128]; char ip_address[16]; - s8 netmask[16]; - s8 default_route[16]; - s8 primary_dns[16]; - s8 secondary_dns[16]; + char netmask[16]; + char default_route[16]; + char primary_dns[16]; + char secondary_dns[16]; be_t http_proxy_config; - s8 http_proxy_server[256]; + char http_proxy_server[256]; be_t http_proxy_port; be_t upnp_config; }; diff --git a/rpcs3/Emu/SysCalls/Modules/cellOskDialog.cpp b/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp similarity index 68% rename from rpcs3/Emu/SysCalls/Modules/cellOskDialog.cpp rename to rpcs3/Emu/Cell/Modules/cellOskDialog.cpp index 6a83bd544e..ccc0c51f7f 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellOskDialog.cpp +++ b/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellOskDialog; +LOG_CHANNEL(cellOskDialog); s32 cellOskDialogLoadAsync() { @@ -153,9 +152,6 @@ s32 cellOskDialogExtRegisterForceFinishCallback() void cellSysutil_OskDialog_init() { - extern Module<> cellSysutil; - - // cellOskDialog functions: REG_FUNC(cellSysutil, cellOskDialogLoadAsync); REG_FUNC(cellSysutil, cellOskDialogUnloadAsync); REG_FUNC(cellSysutil, cellOskDialogGetSize); @@ -171,23 +167,22 @@ void cellSysutil_OskDialog_init() REG_FUNC(cellSysutil, cellOskDialogGetInputText); } -Module<> cellOskDialog("cellOskDialog", []() +DECLARE(ppu_module_manager::cellOskDialog)("cellOskExtUtility", []() { - // cellOskDialogExt functions: - REG_FUNC(cellOskDialog, cellOskDialogExtInputDeviceUnlock); - REG_FUNC(cellOskDialog, cellOskDialogExtRegisterKeyboardEventHookCallback); - REG_FUNC(cellOskDialog, cellOskDialogExtAddJapaneseOptionDictionary); - REG_FUNC(cellOskDialog, cellOskDialogExtEnableClipboard); - REG_FUNC(cellOskDialog, cellOskDialogExtSendFinishMessage); - REG_FUNC(cellOskDialog, cellOskDialogExtAddOptionDictionary); - REG_FUNC(cellOskDialog, cellOskDialogExtSetInitialScale); - REG_FUNC(cellOskDialog, cellOskDialogExtInputDeviceLock); - REG_FUNC(cellOskDialog, cellOskDialogExtSetBaseColor); - REG_FUNC(cellOskDialog, cellOskDialogExtRegisterConfirmWordFilterCallback); - REG_FUNC(cellOskDialog, cellOskDialogExtUpdateInputText); - REG_FUNC(cellOskDialog, cellOskDialogExtDisableHalfByteKana); - REG_FUNC(cellOskDialog, cellOskDialogExtSetPointerEnable); - REG_FUNC(cellOskDialog, cellOskDialogExtUpdatePointerDisplayPos); - REG_FUNC(cellOskDialog, cellOskDialogExtEnableHalfByteKana); - REG_FUNC(cellOskDialog, cellOskDialogExtRegisterForceFinishCallback); + REG_FUNC(cellOskExtUtility, cellOskDialogExtInputDeviceUnlock); + REG_FUNC(cellOskExtUtility, cellOskDialogExtRegisterKeyboardEventHookCallback); + REG_FUNC(cellOskExtUtility, cellOskDialogExtAddJapaneseOptionDictionary); + REG_FUNC(cellOskExtUtility, cellOskDialogExtEnableClipboard); + REG_FUNC(cellOskExtUtility, cellOskDialogExtSendFinishMessage); + REG_FUNC(cellOskExtUtility, cellOskDialogExtAddOptionDictionary); + REG_FUNC(cellOskExtUtility, cellOskDialogExtSetInitialScale); + REG_FUNC(cellOskExtUtility, cellOskDialogExtInputDeviceLock); + REG_FUNC(cellOskExtUtility, cellOskDialogExtSetBaseColor); + REG_FUNC(cellOskExtUtility, cellOskDialogExtRegisterConfirmWordFilterCallback); + REG_FUNC(cellOskExtUtility, cellOskDialogExtUpdateInputText); + REG_FUNC(cellOskExtUtility, cellOskDialogExtDisableHalfByteKana); + REG_FUNC(cellOskExtUtility, cellOskDialogExtSetPointerEnable); + REG_FUNC(cellOskExtUtility, cellOskDialogExtUpdatePointerDisplayPos); + REG_FUNC(cellOskExtUtility, cellOskDialogExtEnableHalfByteKana); + REG_FUNC(cellOskExtUtility, cellOskDialogExtRegisterForceFinishCallback); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellOvis.cpp b/rpcs3/Emu/Cell/Modules/cellOvis.cpp similarity index 82% rename from rpcs3/Emu/SysCalls/Modules/cellOvis.cpp rename to rpcs3/Emu/Cell/Modules/cellOvis.cpp index ce14d263d5..49e22da87f 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellOvis.cpp +++ b/rpcs3/Emu/Cell/Modules/cellOvis.cpp @@ -1,10 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -namespace vm { using namespace ps3; } - -extern Module<> cellOvis; +LOG_CHANNEL(cellOvis); // Return Codes enum @@ -38,7 +35,7 @@ s32 cellOvisInvalidateOverlappedSegments() return CELL_OK; } -Module<> cellOvis("cellOvis", []() +DECLARE(ppu_module_manager::cellOvis)("cellOvis", []() { REG_FUNC(cellOvis, cellOvisGetOverlayTableSize); REG_FUNC(cellOvis, cellOvisInitializeOverlayTable); diff --git a/rpcs3/Emu/SysCalls/Modules/cellPad.cpp b/rpcs3/Emu/Cell/Modules/cellPad.cpp similarity index 85% rename from rpcs3/Emu/SysCalls/Modules/cellPad.cpp rename to rpcs3/Emu/Cell/Modules/cellPad.cpp index d691ff3023..f0441cc739 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPad.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPad.cpp @@ -1,37 +1,37 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/Io/Pad.h" +#include "Emu/Io/PadHandler.h" #include "cellPad.h" -extern Module<> sys_io; +extern _log::channel sys_io; s32 cellPadInit(u32 max_connect) { sys_io.warning("cellPadInit(max_connect=%d)", max_connect); - if (Emu.GetPadManager().IsInited()) - return CELL_PAD_ERROR_ALREADY_INITIALIZED; - if (max_connect > CELL_PAD_MAX_PORT_NUM) return CELL_PAD_ERROR_INVALID_PARAMETER; - Emu.GetPadManager().Init(max_connect); + const auto handler = fxm::import(PURE_EXPR(Emu.GetCallbacks().get_pad_handler())); + + if (!handler) + return CELL_PAD_ERROR_ALREADY_INITIALIZED; + + handler->Init(max_connect); return CELL_OK; } s32 cellPadEnd() { - sys_io.trace("cellPadEnd()"); + sys_io.notice("cellPadEnd()"); - if (!Emu.GetPadManager().IsInited()) + if (!fxm::remove()) return CELL_PAD_ERROR_UNINITIALIZED; - Emu.GetPadManager().Close(); - return CELL_OK; } @@ -39,10 +39,12 @@ s32 cellPadClearBuf(u32 port_no) { sys_io.trace("cellPadClearBuf(port_no=%d)", port_no); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; @@ -52,7 +54,7 @@ s32 cellPadClearBuf(u32 port_no) //Set 'm_buffer_cleared' to force a resend of everything //might as well also reset everything in our pad 'buffer' to nothing as well - std::vector& pads = Emu.GetPadManager().GetPads(); + std::vector& pads = handler->GetPads(); Pad& pad = pads[port_no]; pad.m_buffer_cleared = true; @@ -74,18 +76,18 @@ s32 cellPadPeriphGetInfo(vm::ptr info) { sys_io.todo("cellPadPeriphGetInfo(info=*0x%x)", info); - if (!Emu.GetPadManager().IsInited()) - { - return CELL_PAD_ERROR_UNINITIALIZED; - } + const auto handler = fxm::get(); - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + if (!handler) + return CELL_PAD_ERROR_UNINITIALIZED; + + const PadInfo& rinfo = handler->GetInfo(); info->max_connect = rinfo.max_connect; info->now_connect = rinfo.now_connect; info->system_info = rinfo.system_info; - std::vector& pads = Emu.GetPadManager().GetPads(); + std::vector& pads = handler->GetPads(); // TODO: Support other types of controllers for (u32 i = 0; i < CELL_PAD_MAX_PORT_NUM; ++i) @@ -113,12 +115,14 @@ s32 cellPadGetData(u32 port_no, vm::ptr data) { sys_io.trace("cellPadGetData(port_no=%d, data=*0x%x)", port_no, data); - std::vector& pads = Emu.GetPadManager().GetPads(); + const auto handler = fxm::get(); - if (!Emu.GetPadManager().IsInited()) + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + std::vector& pads = handler->GetPads(); + + const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; @@ -297,10 +301,12 @@ s32 cellPadGetDataExtra(u32 port_no, vm::ptr device_type, vm::ptr(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; @@ -314,10 +320,12 @@ s32 cellPadSetActDirect(u32 port_no, vm::ptr param) { sys_io.trace("cellPadSetActDirect(port_no=%d, param=*0x%x)", port_no, param); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; @@ -331,16 +339,18 @@ s32 cellPadGetInfo(vm::ptr info) { sys_io.trace("cellPadGetInfo(info=*0x%x)", info); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); info->max_connect = rinfo.max_connect; info->now_connect = rinfo.now_connect; info->system_info = rinfo.system_info; //Can't have this as const, we need to reset Assign Changes Flag here - std::vector& pads = Emu.GetPadManager().GetPads(); + std::vector& pads = handler->GetPads(); for (u32 i=0; i info) { sys_io.trace("cellPadGetInfo2(info=*0x%x)", info); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); info->max_connect = rinfo.max_connect; info->now_connect = rinfo.now_connect; info->system_info = rinfo.system_info; - std::vector& pads = Emu.GetPadManager().GetPads(); + std::vector& pads = handler->GetPads(); for (u32 i=0; i info) { sys_io.trace("cellPadGetCapabilityInfo(port_no=%d, data_addr:=0x%x)", port_no, info.addr()); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; if (port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; - const std::vector& pads = Emu.GetPadManager().GetPads(); + const std::vector& pads = handler->GetPads(); //Should return the same as device capability mask, psl1ght has it backwards in pad.h info->info[0] = pads[port_no].m_device_capability; @@ -411,17 +425,19 @@ s32 cellPadSetPortSetting(u32 port_no, u32 port_setting) { sys_io.trace("cellPadSetPortSetting(port_no=%d, port_setting=0x%x)", port_no, port_setting); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; if (port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; - std::vector& pads = Emu.GetPadManager().GetPads(); + std::vector& pads = handler->GetPads(); pads[port_no].m_port_setting = port_setting; return CELL_OK; @@ -431,17 +447,19 @@ s32 cellPadInfoPressMode(u32 port_no) { sys_io.trace("cellPadInfoPressMode(port_no=%d)", port_no); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; if (port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; - const std::vector& pads = Emu.GetPadManager().GetPads(); + const std::vector& pads = handler->GetPads(); return (pads[port_no].m_device_capability & CELL_PAD_CAPABILITY_PRESS_MODE) > 0; } @@ -450,17 +468,19 @@ s32 cellPadInfoSensorMode(u32 port_no) { sys_io.trace("cellPadInfoSensorMode(port_no=%d)", port_no); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; if (port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; - const std::vector& pads = Emu.GetPadManager().GetPads(); + const std::vector& pads = handler->GetPads(); return (pads[port_no].m_device_capability & CELL_PAD_CAPABILITY_SENSOR_MODE) > 0; } @@ -469,19 +489,22 @@ s32 cellPadSetPressMode(u32 port_no, u32 mode) { sys_io.trace("cellPadSetPressMode(port_no=%d, mode=%d)", port_no, mode); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; + if (mode != 0 && mode != 1) return CELL_PAD_ERROR_INVALID_PARAMETER; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; if (port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; - std::vector& pads = Emu.GetPadManager().GetPads(); + std::vector& pads = handler->GetPads(); if (mode) pads[port_no].m_port_setting |= CELL_PAD_SETTING_PRESS_ON; @@ -495,19 +518,22 @@ s32 cellPadSetSensorMode(u32 port_no, u32 mode) { sys_io.trace("cellPadSetSensorMode(port_no=%d, mode=%d)", port_no, mode); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; + if (mode != 0 && mode != 1) return CELL_PAD_ERROR_INVALID_PARAMETER; - const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); + const PadInfo& rinfo = handler->GetInfo(); if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; if (port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; - std::vector& pads = Emu.GetPadManager().GetPads(); + std::vector& pads = handler->GetPads(); if (mode) pads[port_no].m_port_setting |= CELL_PAD_SETTING_SENSOR_ON; @@ -521,7 +547,9 @@ s32 cellPadLddRegisterController() { sys_io.todo("cellPadLddRegisterController()"); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; return CELL_OK; @@ -531,7 +559,9 @@ s32 cellPadLddDataInsert(s32 handle, vm::ptr data) { sys_io.todo("cellPadLddDataInsert(handle=%d, data=*0x%x)", handle, data); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; return CELL_OK; @@ -541,7 +571,9 @@ s32 cellPadLddGetPortNo(s32 handle) { sys_io.todo("cellPadLddGetPortNo(handle=%d)", handle); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; return CELL_OK; @@ -551,7 +583,9 @@ s32 cellPadLddUnregisterController(s32 handle) { sys_io.todo("cellPadLddUnregisterController(handle=%d)", handle); - if (!Emu.GetPadManager().IsInited()) + const auto handler = fxm::get(); + + if (!handler) return CELL_PAD_ERROR_UNINITIALIZED; return CELL_OK; diff --git a/rpcs3/Emu/SysCalls/Modules/cellPad.h b/rpcs3/Emu/Cell/Modules/cellPad.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellPad.h rename to rpcs3/Emu/Cell/Modules/cellPad.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp b/rpcs3/Emu/Cell/Modules/cellPamf.cpp similarity index 95% rename from rpcs3/Emu/SysCalls/Modules/cellPamf.cpp rename to rpcs3/Emu/Cell/Modules/cellPamf.cpp index 36f26bcea9..fcd64720b6 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPamf.cpp @@ -1,16 +1,23 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellPamf.h" -extern Module<> cellPamf; +const std::function SQUEUE_ALWAYS_EXIT = []() { return true; }; +const std::function SQUEUE_NEVER_EXIT = []() { return false; }; + +bool squeue_test_exit() +{ + return Emu.IsStopped(); +} + +LOG_CHANNEL(cellPamf); s32 pamfStreamTypeToEsFilterId(u8 type, u8 ch, CellCodecEsFilterId& pEsFilterId) { // convert type and ch to EsFilterId - assert(ch < 16); + Expects(ch < 16); pEsFilterId.supplementalInfo1 = type == CELL_PAMF_STREAM_TYPE_AVC; pEsFilterId.supplementalInfo2 = 0; @@ -110,7 +117,7 @@ s32 pamfStreamTypeToEsFilterId(u8 type, u8 ch, CellCodecEsFilterId& pEsFilterId) u8 pamfGetStreamType(vm::ptr pSelf, u32 stream) { // TODO: get stream type correctly - assert(stream < (u32)pSelf->pAddr->stream_count); + Expects(stream < (u32)pSelf->pAddr->stream_count); auto& header = pSelf->pAddr->stream_headers[stream]; switch (header.type) @@ -131,7 +138,7 @@ u8 pamfGetStreamType(vm::ptr pSelf, u32 stream) u8 pamfGetStreamChannel(vm::ptr pSelf, u32 stream) { // TODO: get stream channel correctly - assert(stream < (u32)pSelf->pAddr->stream_count); + Expects(stream < (u32)pSelf->pAddr->stream_count); auto& header = pSelf->pAddr->stream_headers[stream]; switch (header.type) @@ -139,29 +146,29 @@ u8 pamfGetStreamChannel(vm::ptr pSelf, u32 stream) case 0x1b: // AVC case 0x02: // M2V { - assert((header.fid_major & 0xf0) == 0xe0 && header.fid_minor == 0); + Expects((header.fid_major & 0xf0) == 0xe0 && header.fid_minor == 0); return header.fid_major % 16; } case 0xdc: // ATRAC3PLUS { - assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0); + Expects(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0); return header.fid_minor % 16; } case 0x80: // LPCM { - assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x40); + Expects(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x40); return header.fid_minor % 16; } case 0x81: // AC3 { - assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x30); + Expects(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x30); return header.fid_minor % 16; } case 0xdd: { - assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x20); + Expects(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x20); return header.fid_minor % 16; } } @@ -447,7 +454,7 @@ s32 cellPamfReaderGetEsFilterId(vm::ptr pSelf, vm::ptrstream < (u32)pSelf->pAddr->stream_count); + Expects((u32)pSelf->stream < (u32)pSelf->pAddr->stream_count); auto& header = pSelf->pAddr->stream_headers[pSelf->stream]; pEsFilterId->filterIdMajor = header.fid_major; pEsFilterId->filterIdMinor = header.fid_minor; @@ -460,7 +467,7 @@ s32 cellPamfReaderGetStreamInfo(vm::ptr pSelf, vm::ptr pIn { cellPamf.warning("cellPamfReaderGetStreamInfo(pSelf=*0x%x, pInfo=*0x%x, size=%d)", pSelf, pInfo, size); - assert((u32)pSelf->stream < (u32)pSelf->pAddr->stream_count); + Expects((u32)pSelf->stream < (u32)pSelf->pAddr->stream_count); auto& header = pSelf->pAddr->stream_headers[pSelf->stream]; const u8 type = pamfGetStreamType(pSelf, pSelf->stream); const u8 ch = pamfGetStreamChannel(pSelf, pSelf->stream); @@ -733,7 +740,7 @@ s32 cellPamfEpIteratorMove(vm::ptr pIt, s32 steps, vm::ptr cellPamf("cellPamf", []() +DECLARE(ppu_module_manager::cellPamf)("cellPamf", []() { REG_FUNC(cellPamf, cellPamfGetHeaderSize); REG_FUNC(cellPamf, cellPamfGetHeaderSize2); diff --git a/rpcs3/Emu/SysCalls/Modules/cellPamf.h b/rpcs3/Emu/Cell/Modules/cellPamf.h similarity index 59% rename from rpcs3/Emu/SysCalls/Modules/cellPamf.h rename to rpcs3/Emu/Cell/Modules/cellPamf.h index 823a1b564f..4dd45b3256 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPamf.h +++ b/rpcs3/Emu/Cell/Modules/cellPamf.h @@ -399,3 +399,342 @@ struct CellPamfReader CHECK_SIZE(CellPamfReader, 128); s32 cellPamfReaderInitialize(vm::ptr pSelf, vm::cptr pAddr, u64 fileSize, u32 attribute); + + +extern const std::function SQUEUE_ALWAYS_EXIT; +extern const std::function SQUEUE_NEVER_EXIT; + +bool squeue_test_exit(); + +// TODO: eliminate this boolshit +template +class squeue_t +{ + struct alignas(8) squeue_sync_var_t + { + struct + { + u32 position : 31; + u32 pop_lock : 1; + }; + struct + { + u32 count : 31; + u32 push_lock : 1; + }; + }; + + atomic_t m_sync; + + mutable std::mutex m_rcv_mutex; + mutable std::mutex m_wcv_mutex; + mutable std::condition_variable m_rcv; + mutable std::condition_variable m_wcv; + + T m_data[sq_size]; + + enum squeue_sync_var_result : u32 + { + SQSVR_OK = 0, + SQSVR_LOCKED = 1, + SQSVR_FAILED = 2, + }; + +public: + squeue_t() + : m_sync(squeue_sync_var_t{}) + { + } + + u32 get_max_size() const + { + return sq_size; + } + + bool is_full() const + { + return m_sync.load().count == sq_size; + } + + bool push(const T& data, const std::function& test_exit) + { + u32 pos = 0; + + while (u32 res = m_sync.atomic_op([&pos](squeue_sync_var_t& sync) -> u32 + { + Expects(sync.count <= sq_size); + Expects(sync.position < sq_size); + + if (sync.push_lock) + { + return SQSVR_LOCKED; + } + if (sync.count == sq_size) + { + return SQSVR_FAILED; + } + + sync.push_lock = 1; + pos = sync.position + sync.count; + return SQSVR_OK; + })) + { + if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit())) + { + return false; + } + + std::unique_lock wcv_lock(m_wcv_mutex); + m_wcv.wait_for(wcv_lock, std::chrono::milliseconds(1)); + } + + m_data[pos >= sq_size ? pos - sq_size : pos] = data; + + m_sync.atomic_op([](squeue_sync_var_t& sync) + { + Expects(sync.count <= sq_size); + Expects(sync.position < sq_size); + Expects(sync.push_lock); + sync.push_lock = 0; + sync.count++; + }); + + m_rcv.notify_one(); + m_wcv.notify_one(); + return true; + } + + bool push(const T& data, const volatile bool* do_exit) + { + return push(data, [do_exit]() { return do_exit && *do_exit; }); + } + + force_inline bool push(const T& data) + { + return push(data, SQUEUE_NEVER_EXIT); + } + + force_inline bool try_push(const T& data) + { + return push(data, SQUEUE_ALWAYS_EXIT); + } + + bool pop(T& data, const std::function& test_exit) + { + u32 pos = 0; + + while (u32 res = m_sync.atomic_op([&pos](squeue_sync_var_t& sync) -> u32 + { + Expects(sync.count <= sq_size); + Expects(sync.position < sq_size); + + if (!sync.count) + { + return SQSVR_FAILED; + } + if (sync.pop_lock) + { + return SQSVR_LOCKED; + } + + sync.pop_lock = 1; + pos = sync.position; + return SQSVR_OK; + })) + { + if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit())) + { + return false; + } + + std::unique_lock rcv_lock(m_rcv_mutex); + m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1)); + } + + data = m_data[pos]; + + m_sync.atomic_op([](squeue_sync_var_t& sync) + { + Expects(sync.count <= sq_size); + Expects(sync.position < sq_size); + Expects(sync.pop_lock); + sync.pop_lock = 0; + sync.position++; + sync.count--; + if (sync.position == sq_size) + { + sync.position = 0; + } + }); + + m_rcv.notify_one(); + m_wcv.notify_one(); + return true; + } + + bool pop(T& data, const volatile bool* do_exit) + { + return pop(data, [do_exit]() { return do_exit && *do_exit; }); + } + + force_inline bool pop(T& data) + { + return pop(data, SQUEUE_NEVER_EXIT); + } + + force_inline bool try_pop(T& data) + { + return pop(data, SQUEUE_ALWAYS_EXIT); + } + + bool peek(T& data, u32 start_pos, const std::function& test_exit) + { + Expects(start_pos < sq_size); + u32 pos = 0; + + while (u32 res = m_sync.atomic_op([&pos, start_pos](squeue_sync_var_t& sync) -> u32 + { + Expects(sync.count <= sq_size); + Expects(sync.position < sq_size); + + if (sync.count <= start_pos) + { + return SQSVR_FAILED; + } + if (sync.pop_lock) + { + return SQSVR_LOCKED; + } + + sync.pop_lock = 1; + pos = sync.position + start_pos; + return SQSVR_OK; + })) + { + if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit())) + { + return false; + } + + std::unique_lock rcv_lock(m_rcv_mutex); + m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1)); + } + + data = m_data[pos >= sq_size ? pos - sq_size : pos]; + + m_sync.atomic_op([](squeue_sync_var_t& sync) + { + Expects(sync.count <= sq_size); + Expects(sync.position < sq_size); + Expects(sync.pop_lock); + sync.pop_lock = 0; + }); + + m_rcv.notify_one(); + return true; + } + + bool peek(T& data, u32 start_pos, const volatile bool* do_exit) + { + return peek(data, start_pos, [do_exit]() { return do_exit && *do_exit; }); + } + + force_inline bool peek(T& data, u32 start_pos = 0) + { + return peek(data, start_pos, SQUEUE_NEVER_EXIT); + } + + force_inline bool try_peek(T& data, u32 start_pos = 0) + { + return peek(data, start_pos, SQUEUE_ALWAYS_EXIT); + } + + class squeue_data_t + { + T* const m_data; + const u32 m_pos; + const u32 m_count; + + squeue_data_t(T* data, u32 pos, u32 count) + : m_data(data) + , m_pos(pos) + , m_count(count) + { + } + + public: + T& operator [] (u32 index) + { + Expects(index < m_count); + index += m_pos; + index = index < sq_size ? index : index - sq_size; + return m_data[index]; + } + }; + + void process(void(*proc)(squeue_data_t data)) + { + u32 pos, count; + + while (m_sync.atomic_op([&pos, &count](squeue_sync_var_t& sync) -> u32 + { + Expects(sync.count <= sq_size); + Expects(sync.position < sq_size); + + if (sync.pop_lock || sync.push_lock) + { + return SQSVR_LOCKED; + } + + pos = sync.position; + count = sync.count; + sync.pop_lock = 1; + sync.push_lock = 1; + return SQSVR_OK; + })) + { + std::unique_lock rcv_lock(m_rcv_mutex); + m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1)); + } + + proc(squeue_data_t(m_data, pos, count)); + + m_sync.atomic_op([](squeue_sync_var_t& sync) + { + Expects(sync.count <= sq_size); + Expects(sync.position < sq_size); + Expects(sync.pop_lock && sync.push_lock); + sync.pop_lock = 0; + sync.push_lock = 0; + }); + + m_wcv.notify_one(); + m_rcv.notify_one(); + } + + void clear() + { + while (m_sync.atomic_op([](squeue_sync_var_t& sync) -> u32 + { + Expects(sync.count <= sq_size); + Expects(sync.position < sq_size); + + if (sync.pop_lock || sync.push_lock) + { + return SQSVR_LOCKED; + } + + sync.pop_lock = 1; + sync.push_lock = 1; + return SQSVR_OK; + })) + { + std::unique_lock rcv_lock(m_rcv_mutex); + m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1)); + } + + m_sync.exchange({}); + m_wcv.notify_one(); + m_rcv.notify_one(); + } +}; diff --git a/rpcs3/Emu/SysCalls/Modules/cellPhotoDecode.cpp b/rpcs3/Emu/Cell/Modules/cellPhotoDecode.cpp similarity index 72% rename from rpcs3/Emu/SysCalls/Modules/cellPhotoDecode.cpp rename to rpcs3/Emu/Cell/Modules/cellPhotoDecode.cpp index 8ede8c8388..90f759f1e4 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPhotoDecode.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPhotoDecode.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellPhotoDecode; +LOG_CHANNEL(cellPhotoDecode); // Return Codes enum @@ -56,10 +55,10 @@ s32 cellPhotoDecodeFromFile() return CELL_OK; } -Module<> cellPhotoDecode("cellPhotoDecode", []() +DECLARE(ppu_module_manager::cellPhotoDecode)("cellPhotoDecodeUtil", []() { - REG_FUNC(cellPhotoDecode, cellPhotoDecodeInitialize); - REG_FUNC(cellPhotoDecode, cellPhotoDecodeInitialize2); - REG_FUNC(cellPhotoDecode, cellPhotoDecodeFinalize); - REG_FUNC(cellPhotoDecode, cellPhotoDecodeFromFile); + REG_FUNC(cellPhotoDecodeUtil, cellPhotoDecodeInitialize); + REG_FUNC(cellPhotoDecodeUtil, cellPhotoDecodeInitialize2); + REG_FUNC(cellPhotoDecodeUtil, cellPhotoDecodeFinalize); + REG_FUNC(cellPhotoDecodeUtil, cellPhotoDecodeFromFile); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellPhotoExport.cpp b/rpcs3/Emu/Cell/Modules/cellPhotoExport.cpp similarity index 70% rename from rpcs3/Emu/SysCalls/Modules/cellPhotoExport.cpp rename to rpcs3/Emu/Cell/Modules/cellPhotoExport.cpp index 00b88fabc3..3b9f4a6381 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPhotoExport.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPhotoExport.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellPhotoExport; +LOG_CHANNEL(cellPhotoExport); // Return Codes enum @@ -75,15 +74,15 @@ s32 cellPhotoExportProgress() return CELL_OK; } -Module<> cellPhotoExport("cellPhotoExport", []() +DECLARE(ppu_module_manager::cellPhotoExport)("cellPhotoUtility", []() { - REG_FUNC(cellPhotoExport, cellPhotoInitialize); - REG_FUNC(cellPhotoExport, cellPhotoFinalize); - REG_FUNC(cellPhotoExport, cellPhotoRegistFromFile); - REG_FUNC(cellPhotoExport, cellPhotoExportInitialize); - REG_FUNC(cellPhotoExport, cellPhotoExportInitialize2); - REG_FUNC(cellPhotoExport, cellPhotoExportFinalize); - REG_FUNC(cellPhotoExport, cellPhotoExportFromFile); - REG_FUNC(cellPhotoExport, cellPhotoExportFromFileWithCopy); - REG_FUNC(cellPhotoExport, cellPhotoExportProgress); + REG_FUNC(cellPhotoUtility, cellPhotoInitialize); + REG_FUNC(cellPhotoUtility, cellPhotoFinalize); + REG_FUNC(cellPhotoUtility, cellPhotoRegistFromFile); + REG_FUNC(cellPhotoUtility, cellPhotoExportInitialize); + REG_FUNC(cellPhotoUtility, cellPhotoExportInitialize2); + REG_FUNC(cellPhotoUtility, cellPhotoExportFinalize); + REG_FUNC(cellPhotoUtility, cellPhotoExportFromFile); + REG_FUNC(cellPhotoUtility, cellPhotoExportFromFileWithCopy); + REG_FUNC(cellPhotoUtility, cellPhotoExportProgress); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellPhotoImport.cpp b/rpcs3/Emu/Cell/Modules/cellPhotoImport.cpp similarity index 89% rename from rpcs3/Emu/SysCalls/Modules/cellPhotoImport.cpp rename to rpcs3/Emu/Cell/Modules/cellPhotoImport.cpp index cb4bddb8fb..4bb17ce497 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPhotoImport.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPhotoImport.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellPhotoImportUtil; +LOG_CHANNEL(cellPhotoImportUtil); // Return Codes enum @@ -53,7 +52,7 @@ s32 cellPhotoImport2() return CELL_OK; } -Module<> cellPhotoImportUtil("cellPhotoImport", []() +DECLARE(ppu_module_manager::cellPhotoImportUtil)("cellPhotoImportUtil", []() { REG_FUNC(cellPhotoImportUtil, cellPhotoImport); REG_FUNC(cellPhotoImportUtil, cellPhotoImport2); diff --git a/rpcs3/Emu/SysCalls/Modules/cellPng.h b/rpcs3/Emu/Cell/Modules/cellPng.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellPng.h rename to rpcs3/Emu/Cell/Modules/cellPng.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp b/rpcs3/Emu/Cell/Modules/cellPngDec.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp rename to rpcs3/Emu/Cell/Modules/cellPngDec.cpp index 44ad101ed3..431170548e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPngDec.cpp @@ -1,16 +1,13 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFileBase.h" -#include "Emu/SysCalls/lv2/sys_fs.h" +#include "Emu/Cell/PPUModule.h" +#include "Emu/Cell/lv2/sys_fs.h" #include "png.h" #include "cellPngDec.h" -extern Module<> cellPngDec; +LOG_CHANNEL(cellPngDec); // cellPngDec aliases to improve readability using PPHandle = vm::pptr; @@ -59,7 +56,7 @@ void pngDecReadBuffer(png_structp png_ptr, png_bytep out, png_size_t length) auto file = idm::get(buffer.fd); // Read the data - file->file->Read(out, length); + file->file.read(out, length); } else { @@ -338,7 +335,7 @@ s32 pngDecOpen(PPUThread& ppu, PHandle handle, PPStream png_stream, PSrc source, if (source->srcSelect == CELL_PNGDEC_FILE) { // Open a file stream - std::shared_ptr file_stream(Emu.GetVFS().OpenFile(stream->source.fileName.get_ptr(), fom::read)); + fs::file file_stream(vfs::get(stream->source.fileName.get_ptr())); // Check if opening of the PNG file failed if (!file_stream) @@ -348,14 +345,14 @@ s32 pngDecOpen(PPUThread& ppu, PHandle handle, PPStream png_stream, PSrc source, } // Read the header - if (file_stream->Read(header, 8) != 8) + if (file_stream.read(header, 8) != 8) { cellPngDec.error("PNG header is too small."); return CELL_PNGDEC_ERROR_HEADER; } // Get the file descriptor - buffer->fd = idm::make(file_stream, 0, 0); + buffer->fd = idm::make(std::move(file_stream), 0, 0); // Indicate that we need to read from a file stream buffer->file = true; @@ -852,7 +849,7 @@ s32 cellPngDecGetTextChunk(PHandle handle, PStream stream, vm::ptr textInfo throw EXCEPTION(""); } -Module<> cellPngDec("cellPngDec", []() +DECLARE(ppu_module_manager::cellPngDec)("cellPngDec", []() { REG_FUNC(cellPngDec, cellPngDecGetUnknownChunks); REG_FUNC(cellPngDec, cellPngDecClose); diff --git a/rpcs3/Emu/SysCalls/Modules/cellPngDec.h b/rpcs3/Emu/Cell/Modules/cellPngDec.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellPngDec.h rename to rpcs3/Emu/Cell/Modules/cellPngDec.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellPngEnc.cpp b/rpcs3/Emu/Cell/Modules/cellPngEnc.cpp similarity index 91% rename from rpcs3/Emu/SysCalls/Modules/cellPngEnc.cpp rename to rpcs3/Emu/Cell/Modules/cellPngEnc.cpp index 5317ed0143..a1efb70795 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPngEnc.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPngEnc.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellPngEnc; +LOG_CHANNEL(cellPngEnc); // Error Codes enum @@ -69,7 +68,7 @@ s32 cellPngEncReset() return CELL_OK; } -Module<> cellPngEnc("cellPngEnc", []() +DECLARE(ppu_module_manager::cellPngEnc)("cellPngEnc", []() { REG_FUNC(cellPngEnc, cellPngEncQueryAttr); REG_FUNC(cellPngEnc, cellPngEncOpen); diff --git a/rpcs3/Emu/SysCalls/Modules/cellPrint.cpp b/rpcs3/Emu/Cell/Modules/cellPrint.cpp similarity index 66% rename from rpcs3/Emu/SysCalls/Modules/cellPrint.cpp rename to rpcs3/Emu/Cell/Modules/cellPrint.cpp index c64f0ea728..b0a37969cd 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPrint.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPrint.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellPrint; +LOG_CHANNEL(cellPrint); // Error Codes enum @@ -101,21 +100,21 @@ s32 cellPrintSendBand() return CELL_OK; } -Module<> cellPrint("cellPrint", []() +DECLARE(ppu_module_manager::cellPrint)("cellPrintUtility", []() { - REG_FUNC(cellPrint, cellSysutilPrintInit); - REG_FUNC(cellPrint, cellSysutilPrintShutdown); + REG_FUNC(cellPrintUtility, cellSysutilPrintInit); + REG_FUNC(cellPrintUtility, cellSysutilPrintShutdown); - REG_FUNC(cellPrint, cellPrintLoadAsync); - REG_FUNC(cellPrint, cellPrintLoadAsync2); - REG_FUNC(cellPrint, cellPrintUnloadAsync); - REG_FUNC(cellPrint, cellPrintGetStatus); - REG_FUNC(cellPrint, cellPrintOpenConfig); - REG_FUNC(cellPrint, cellPrintGetPrintableArea); - REG_FUNC(cellPrint, cellPrintStartJob); - REG_FUNC(cellPrint, cellPrintEndJob); - REG_FUNC(cellPrint, cellPrintCancelJob); - REG_FUNC(cellPrint, cellPrintStartPage); - REG_FUNC(cellPrint, cellPrintEndPage); - REG_FUNC(cellPrint, cellPrintSendBand); + REG_FUNC(cellPrintUtility, cellPrintLoadAsync); + REG_FUNC(cellPrintUtility, cellPrintLoadAsync2); + REG_FUNC(cellPrintUtility, cellPrintUnloadAsync); + REG_FUNC(cellPrintUtility, cellPrintGetStatus); + REG_FUNC(cellPrintUtility, cellPrintOpenConfig); + REG_FUNC(cellPrintUtility, cellPrintGetPrintableArea); + REG_FUNC(cellPrintUtility, cellPrintStartJob); + REG_FUNC(cellPrintUtility, cellPrintEndJob); + REG_FUNC(cellPrintUtility, cellPrintCancelJob); + REG_FUNC(cellPrintUtility, cellPrintStartPage); + REG_FUNC(cellPrintUtility, cellPrintEndPage); + REG_FUNC(cellPrintUtility, cellPrintSendBand); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellRec.cpp b/rpcs3/Emu/Cell/Modules/cellRec.cpp similarity index 83% rename from rpcs3/Emu/SysCalls/Modules/cellRec.cpp rename to rpcs3/Emu/Cell/Modules/cellRec.cpp index 4a53e6f145..ce3aa50e99 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellRec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellRec.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellRec; +LOG_CHANNEL(cellRec); s32 cellRecOpen() { @@ -40,7 +39,7 @@ s32 cellRecSetInfo() } -Module<> cellRec("cellRec", []() +DECLARE(ppu_module_manager::cellRec)("cellRec", []() { REG_FUNC(cellRec, cellRecOpen); REG_FUNC(cellRec, cellRecClose); diff --git a/rpcs3/Emu/SysCalls/Modules/cellRemotePlay.cpp b/rpcs3/Emu/Cell/Modules/cellRemotePlay.cpp similarity index 87% rename from rpcs3/Emu/SysCalls/Modules/cellRemotePlay.cpp rename to rpcs3/Emu/Cell/Modules/cellRemotePlay.cpp index ffc5abb825..0c7983bb12 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellRemotePlay.cpp +++ b/rpcs3/Emu/Cell/Modules/cellRemotePlay.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellRemotePlay; +LOG_CHANNEL(cellRemotePlay); s32 cellRemotePlayGetStatus() { @@ -45,7 +44,7 @@ s32 cellRemotePlayBreak() } -Module<> cellRemotePlay("cellRemotePlay", []() +DECLARE(ppu_module_manager::cellRemotePlay)("cellRemotePlay", []() { REG_FUNC(cellRemotePlay, cellRemotePlayGetStatus); REG_FUNC(cellRemotePlay, cellRemotePlaySetComparativeVolume); diff --git a/rpcs3/Emu/Cell/Modules/cellResc.cpp b/rpcs3/Emu/Cell/Modules/cellResc.cpp new file mode 100644 index 0000000000..00e1a5f8f9 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellResc.cpp @@ -0,0 +1,180 @@ +#include "stdafx.h" +#include "Emu/System.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" + +#include "Emu/RSX/GCM.h" +#include "cellResc.h" + +LOG_CHANNEL(cellResc); + +s32 cellRescInit(vm::ptr initConfig) +{ + cellResc.todo("cellRescInit(initConfig=*0x%x)", initConfig); + + return CELL_OK; +} + +void cellRescExit() +{ + cellResc.todo("cellRescExit()"); +} + +s32 cellRescVideoOutResolutionId2RescBufferMode(u32 resolutionId, vm::ptr bufferMode) +{ + cellResc.todo("cellRescVideoOutResolutionId2RescBufferMode(resolutionId=%d, bufferMode=*0x%x)", resolutionId, bufferMode); + + return CELL_OK; +} + +s32 cellRescSetDsts(u32 dstsMode, vm::ptr dsts) +{ + cellResc.todo("cellRescSetDsts(dstsMode=%d, dsts=*0x%x)", dstsMode, dsts); + + return CELL_OK; +} + +s32 cellRescSetDisplayMode(u32 displayMode) +{ + cellResc.todo("cellRescSetDisplayMode(displayMode=%d)", displayMode); + + return CELL_OK; +} + +s32 cellRescAdjustAspectRatio(f32 horizontal, f32 vertical) +{ + cellResc.todo("cellRescAdjustAspectRatio(horizontal=%f, vertical=%f)", horizontal, vertical); + + return CELL_OK; +} + +s32 cellRescSetPalInterpolateDropFlexRatio(f32 ratio) +{ + cellResc.todo("cellRescSetPalInterpolateDropFlexRatio(ratio=%f)", ratio); + + return CELL_OK; +} + +s32 cellRescGetBufferSize(vm::ptr colorBuffers, vm::ptr vertexArray, vm::ptr fragmentShader) +{ + cellResc.todo("cellRescGetBufferSize(colorBuffers=*0x%x, vertexArray=*0x%x, fragmentShader=*0x%x)", colorBuffers, vertexArray, fragmentShader); + + return CELL_OK; +} + +s32 cellRescGetNumColorBuffers(u32 dstMode, u32 palTemporalMode, u32 reserved) +{ + cellResc.todo("cellRescGetNumColorBuffers(dstMode=%d, palTemporalMode=%d, reserved=%d)", dstMode, palTemporalMode, reserved); + + return 2; +} + +s32 cellRescGcmSurface2RescSrc(vm::ptr gcmSurface, vm::ptr rescSrc) +{ + cellResc.todo("cellRescGcmSurface2RescSrc(gcmSurface=*0x%x, rescSrc=*0x%x)", gcmSurface, rescSrc); + + return CELL_OK; +} + +s32 cellRescSetSrc(s32 idx, vm::ptr src) +{ + cellResc.todo("cellRescSetSrc(idx=0x%x, src=*0x%x)", idx, src); + + return CELL_OK; +} + +s32 cellRescSetConvertAndFlip(PPUThread& ppu, vm::ptr cntxt, s32 idx) +{ + cellResc.todo("cellRescSetConvertAndFlip(cntxt=*0x%x, idx=0x%x)", cntxt, idx); + + return CELL_OK; +} + +s32 cellRescSetWaitFlip() +{ + cellResc.todo("cellRescSetWaitFlip()"); + + return CELL_OK; +} + +s32 cellRescSetBufferAddress(vm::ptr colorBuffers, vm::ptr vertexArray, vm::ptr fragmentShader) +{ + cellResc.todo("cellRescSetBufferAddress(colorBuffers=*0x%x, vertexArray=*0x%x, fragmentShader=*0x%x)", colorBuffers, vertexArray, fragmentShader); + + return CELL_OK; +} + +void cellRescSetFlipHandler(vm::ptr handler) +{ + cellResc.todo("cellRescSetFlipHandler(handler=*0x%x)", handler); +} + +void cellRescResetFlipStatus() +{ + cellResc.todo("cellRescResetFlipStatus()"); +} + +s32 cellRescGetFlipStatus() +{ + cellResc.todo("cellRescGetFlipStatus()"); + + return 0; +} + +s32 cellRescGetRegisterCount() +{ + UNIMPLEMENTED_FUNC(cellResc); + return CELL_OK; +} + +u64 cellRescGetLastFlipTime() +{ + cellResc.todo("cellRescGetLastFlipTime()"); + + return 0; +} + +s32 cellRescSetRegisterCount() +{ + UNIMPLEMENTED_FUNC(cellResc); + return CELL_OK; +} + +void cellRescSetVBlankHandler(vm::ptr handler) +{ + cellResc.todo("cellRescSetVBlankHandler(handler=*0x%x)", handler); +} + +s32 cellRescCreateInterlaceTable(u32 ea_addr, f32 srcH, CellRescTableElement depth, s32 length) +{ + cellResc.todo("cellRescCreateInterlaceTable(ea_addr=0x%x, srcH=%f, depth=%d, length=%d)", ea_addr, srcH, depth, length); + + return CELL_OK; +} + + +DECLARE(ppu_module_manager::cellResc)("cellResc", []() +{ + REG_FUNC(cellResc, cellRescSetConvertAndFlip); + REG_FUNC(cellResc, cellRescSetWaitFlip); + REG_FUNC(cellResc, cellRescSetFlipHandler); + REG_FUNC(cellResc, cellRescGcmSurface2RescSrc); + REG_FUNC(cellResc, cellRescGetNumColorBuffers); + REG_FUNC(cellResc, cellRescSetDsts); + REG_FUNC(cellResc, cellRescResetFlipStatus); + REG_FUNC(cellResc, cellRescSetPalInterpolateDropFlexRatio); + REG_FUNC(cellResc, cellRescGetRegisterCount); + REG_FUNC(cellResc, cellRescAdjustAspectRatio); + REG_FUNC(cellResc, cellRescSetDisplayMode); + REG_FUNC(cellResc, cellRescExit); + REG_FUNC(cellResc, cellRescInit); + REG_FUNC(cellResc, cellRescGetBufferSize); + REG_FUNC(cellResc, cellRescGetLastFlipTime); + REG_FUNC(cellResc, cellRescSetSrc); + REG_FUNC(cellResc, cellRescSetRegisterCount); + REG_FUNC(cellResc, cellRescSetBufferAddress); + REG_FUNC(cellResc, cellRescGetFlipStatus); + REG_FUNC(cellResc, cellRescVideoOutResolutionId2RescBufferMode); + REG_FUNC(cellResc, cellRescSetVBlankHandler); + REG_FUNC(cellResc, cellRescCreateInterlaceTable); +}); diff --git a/rpcs3/Emu/SysCalls/Modules/cellResc.h b/rpcs3/Emu/Cell/Modules/cellResc.h similarity index 68% rename from rpcs3/Emu/SysCalls/Modules/cellResc.h rename to rpcs3/Emu/Cell/Modules/cellResc.h index 6fcb438ec8..a4b135d5ac 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellResc.h +++ b/rpcs3/Emu/Cell/Modules/cellResc.h @@ -1,12 +1,7 @@ #pragma once -#define roundup(x,a) (((x)+(a)-1)&(~((a)-1))) -#define SEVIRITY 80.f - namespace vm { using namespace ps3; } -#include "Emu/RSX/GCM.h" - enum { CELL_RESC_ERROR_NOT_INITIALIZED = 0x80210301, @@ -109,41 +104,3 @@ struct CellRescSrc be_t height; be_t offset; }; - -struct RescVertex_t -{ - be_t Px, Py; - be_t u, v; - be_t u2, v2; -}; - -struct CCellRescInternal -{ - CellRescInitConfig m_initConfig; - CellRescSrc m_rescSrc[SRC_BUFFER_NUM]; - u32 m_dstMode; - CellRescDsts m_rescDsts[4], *m_pRescDsts; - CellRescTableElement m_interlaceElement; - - u32 m_colorBuffersEA, m_vertexArrayEA, m_fragmentUcodeEA; - u32 m_bufIdFront; - s32 m_dstWidth, m_dstHeight, m_dstPitch; - u16 m_srcWidthInterlace, m_srcHeightInterlace; - u32 m_dstBufInterval, m_dstOffsets[MAX_DST_BUFFER_NUM]; - s32 m_nVertex; - u32 m_bufIdFrontPrevDrop, m_bufIdPalMidPrev, m_bufIdPalMidNow; - u32 m_interlaceTableEA; - int m_interlaceTableLength; - float m_ratioAdjX, m_ratioAdjY, m_flexRatio; - bool m_bInitialized, m_bNewlyAdjustRatio; - bool m_isDummyFlipped; - u8 m_cgParamIndex[RESC_PARAM_NUM]; - u64 m_commandIdxCaF, m_rcvdCmdIdx; - vm::ptr s_applicationFlipHandler; - vm::ptr s_applicationVBlankHandler; - - CCellRescInternal() - : m_bInitialized(false) - { - } -}; diff --git a/rpcs3/Emu/Cell/Modules/cellRtc.cpp b/rpcs3/Emu/Cell/Modules/cellRtc.cpp new file mode 100644 index 0000000000..8648da34ee --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellRtc.cpp @@ -0,0 +1,295 @@ +#include "stdafx.h" +#include "Emu/Cell/PPUModule.h" + +#include "cellRtc.h" + +LOG_CHANNEL(cellRtc); + +s64 convertToUNIXTime(u16 seconds, u16 minutes, u16 hours, u16 days, s32 years) +{ + return (s64)seconds + (s64)minutes * 60 + (s64)hours * 3600 + (s64)days * 86400 + + (s64)(years - 70) * 31536000 + (s64)((years - 69) / 4) * 86400 - + (s64)((years - 1) / 100) * 86400 + (s64)((years + 299) / 400) * 86400; +} + +u64 convertToWin32FILETIME(u16 seconds, u16 minutes, u16 hours, u16 days, s32 years) +{ + s64 unixtime = convertToUNIXTime(seconds, minutes, hours, days, years); + u64 win32time = u64(unixtime) * u64(10000000) + u64(116444736000000000); + u64 win32filetime = win32time | win32time >> 32; + return win32filetime; +} + +s32 cellRtcGetCurrentTick(vm::ptr pTick) +{ + cellRtc.todo("cellRtcGetCurrentTick(pTick=*0x%x)", pTick); + + return CELL_OK; +} + +s32 cellRtcGetCurrentClock(vm::ptr pClock, s32 iTimeZone) +{ + cellRtc.todo("cellRtcGetCurrentClock(pClock=*0x%x, time_zone=%d)", pClock, iTimeZone); + + return CELL_OK; +} + +s32 cellRtcGetCurrentClockLocalTime(vm::ptr pClock) +{ + cellRtc.todo("cellRtcGetCurrentClockLocalTime(pClock=*0x%x)", pClock); + + return CELL_OK; +} + +s32 cellRtcFormatRfc2822(vm::ptr pszDateTime, vm::ptr pUtc, s32 iTimeZone) +{ + cellRtc.todo("cellRtcFormatRfc2822(pszDateTime=*0x%x, pUtc=*0x%x, time_zone=%d)", pszDateTime, pUtc, iTimeZone); + + return CELL_OK; +} + +s32 cellRtcFormatRfc2822LocalTime(vm::ptr pszDateTime, vm::ptr pUtc) +{ + cellRtc.todo("cellRtcFormatRfc2822LocalTime(pszDateTime=*0x%x, pUtc=*0x%x)", pszDateTime, pUtc); + + return CELL_OK; +} + +s32 cellRtcFormatRfc3339(vm::ptr pszDateTime, vm::ptr pUtc, s32 iTimeZone) +{ + cellRtc.todo("cellRtcFormatRfc3339(pszDateTime=*0x%x, pUtc=*0x%x, iTimeZone=%d)", pszDateTime, pUtc, iTimeZone); + + return CELL_OK; +} + +s32 cellRtcFormatRfc3339LocalTime(vm::ptr pszDateTime, vm::ptr pUtc) +{ + cellRtc.todo("cellRtcFormatRfc3339LocalTime(pszDateTime=*0x%x, pUtc=*0x%x)", pszDateTime, pUtc); + + return CELL_OK; +} + +s32 cellRtcParseDateTime(vm::ptr pUtc, vm::cptr pszDateTime) +{ + cellRtc.todo("cellRtcParseDateTime(pUtc=*0x%x, pszDateTime=*0x%x)", pUtc, pszDateTime); + + return CELL_OK; +} + +s32 cellRtcParseRfc3339(vm::ptr pUtc, vm::cptr pszDateTime) +{ + cellRtc.todo("cellRtcParseRfc3339(pUtc=*0x%x, pszDateTime=*0x%x)", pUtc, pszDateTime); + + return CELL_OK; +} + +s32 cellRtcGetTick(vm::ptr pTime, vm::ptr pTick) +{ + cellRtc.todo("cellRtcGetTick(pTime=*0x%x, pTick=*0x%x)", pTime, pTick); + + + return CELL_OK; +} + +s32 cellRtcSetTick(vm::ptr pTime, vm::ptr pTick) +{ + cellRtc.todo("cellRtcSetTick(pTime=*0x%x, pTick=*0x%x)", pTime, pTick); + + return CELL_OK; +} + +s32 cellRtcTickAddTicks(vm::ptr pTick0, vm::ptr pTick1, s64 lAdd) +{ + cellRtc.todo("cellRtcTickAddTicks(pTick0=*0x%x, pTick1=*0x%x, lAdd=%lld)", pTick0, pTick1, lAdd); + + return CELL_OK; +} + +s32 cellRtcTickAddMicroseconds(vm::ptr pTick0, vm::ptr pTick1, s64 lAdd) +{ + cellRtc.todo("cellRtcTickAddMicroseconds(pTick0=*0x%x, pTick1=*0x%x, lAdd=%lld)", pTick0, pTick1, lAdd); + + return CELL_OK; +} + +s32 cellRtcTickAddSeconds(vm::ptr pTick0, vm::ptr pTick1, s64 lAdd) +{ + cellRtc.todo("cellRtcTickAddSeconds(pTick0=*0x%x, pTick1=*0x%x, lAdd=%lld)", pTick0, pTick1, lAdd); + + return CELL_OK; +} + +s32 cellRtcTickAddMinutes(vm::ptr pTick0, vm::ptr pTick1, s64 lAdd) +{ + cellRtc.todo("cellRtcTickAddMinutes(pTick0=*0x%x, pTick1=*0x%x, lAdd=%lld)", pTick0, pTick1, lAdd); + + return CELL_OK; +} + +s32 cellRtcTickAddHours(vm::ptr pTick0, vm::ptr pTick1, s32 iAdd) +{ + cellRtc.todo("cellRtcTickAddHours(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd); + + return CELL_OK; +} + +s32 cellRtcTickAddDays(vm::ptr pTick0, vm::ptr pTick1, s32 iAdd) +{ + cellRtc.todo("cellRtcTickAddDays(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd); + + return CELL_OK; +} + +s32 cellRtcTickAddWeeks(vm::ptr pTick0, vm::ptr pTick1, s32 iAdd) +{ + cellRtc.todo("cellRtcTickAddWeeks(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd); + + return CELL_OK; +} + +s32 cellRtcTickAddMonths(vm::ptr pTick0, vm::ptr pTick1, s32 iAdd) +{ + cellRtc.todo("cellRtcTickAddMonths(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd); + + return CELL_OK; +} + +s32 cellRtcTickAddYears(vm::ptr pTick0, vm::ptr pTick1, s32 iAdd) +{ + cellRtc.todo("cellRtcTickAddYears(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd); + + return CELL_OK; +} + +s32 cellRtcConvertUtcToLocalTime(vm::ptr pUtc, vm::ptr pLocalTime) +{ + cellRtc.todo("cellRtcConvertUtcToLocalTime(pUtc=*0x%x, pLocalTime=*0x%x)", pUtc, pLocalTime); + + return CELL_OK; +} + +s32 cellRtcConvertLocalTimeToUtc(vm::ptr pLocalTime, vm::ptr pUtc) +{ + cellRtc.todo("cellRtcConvertLocalTimeToUtc(pLocalTime=*0x%x, pUtc=*0x%x)", pLocalTime, pUtc); + + return CELL_OK; +} + +s32 cellRtcGetDosTime(vm::ptr pDateTime, vm::ptr puiDosTime) +{ + cellRtc.todo("cellRtcGetDosTime(pDateTime=*0x%x, puiDosTime=*0x%x)", pDateTime, puiDosTime); + + return CELL_OK; +} + +s32 cellRtcGetTime_t(vm::ptr pDateTime, vm::ptr piTime) +{ + cellRtc.todo("cellRtcGetTime_t(pDateTime=*0x%x, piTime=*0x%x)", pDateTime, piTime); + + return CELL_OK; +} + +s32 cellRtcGetWin32FileTime(vm::ptr pDateTime, vm::ptr pulWin32FileTime) +{ + cellRtc.todo("cellRtcGetWin32FileTime(pDateTime=*0x%x, pulWin32FileTime=*0x%x)", pDateTime, pulWin32FileTime); + + return CELL_OK; +} + +s32 cellRtcSetDosTime(vm::ptr pDateTime, u32 uiDosTime) +{ + cellRtc.todo("cellRtcSetDosTime(pDateTime=*0x%x, uiDosTime=0x%x)", pDateTime, uiDosTime); + + return CELL_OK; +} + +s32 cellRtcSetTime_t(vm::ptr pDateTime, u64 iTime) +{ + cellRtc.todo("cellRtcSetTime_t(pDateTime=*0x%x, iTime=0x%llx)", pDateTime, iTime); + + return CELL_OK; +} + +s32 cellRtcSetWin32FileTime(vm::ptr pDateTime, u64 ulWin32FileTime) +{ + cellRtc.todo("cellRtcSetWin32FileTime(pDateTime=*0x%x, ulWin32FileTime=0x%llx)", pDateTime, ulWin32FileTime); + + return CELL_OK; +} + +s32 cellRtcIsLeapYear(s32 year) +{ + cellRtc.todo("cellRtcIsLeapYear(year=%d)", year); + + return 0; +} + +s32 cellRtcGetDaysInMonth(s32 year, s32 month) +{ + cellRtc.todo("cellRtcGetDaysInMonth(year=%d, month=%d)", year, month); + + return 0; +} + +s32 cellRtcGetDayOfWeek(s32 year, s32 month, s32 day) +{ + cellRtc.todo("cellRtcGetDayOfWeek(year=%d, month=%d, day=%d)", year, month, day); + + return 0; +} + +s32 cellRtcCheckValid(vm::ptr pTime) +{ + cellRtc.todo("cellRtcCheckValid(pTime=*0x%x)", pTime); + + return CELL_OK; +} + +s32 cellRtcCompareTick(vm::ptr pTick0, vm::ptr pTick1) +{ + cellRtc.todo("cellRtcCompareTick(pTick0=*0x%x, pTick1=*0x%x)", pTick0, pTick1); + + return CELL_OK; +} + +DECLARE(ppu_module_manager::cellRtc)("cellRtc", []() +{ + REG_FUNC(cellRtc, cellRtcGetCurrentTick); + REG_FUNC(cellRtc, cellRtcGetCurrentClock); + REG_FUNC(cellRtc, cellRtcGetCurrentClockLocalTime); + + REG_FUNC(cellRtc, cellRtcFormatRfc2822); + REG_FUNC(cellRtc, cellRtcFormatRfc2822LocalTime); + REG_FUNC(cellRtc, cellRtcFormatRfc3339); + REG_FUNC(cellRtc, cellRtcFormatRfc3339LocalTime); + REG_FUNC(cellRtc, cellRtcParseDateTime); + REG_FUNC(cellRtc, cellRtcParseRfc3339); + + REG_FUNC(cellRtc, cellRtcGetTick); + REG_FUNC(cellRtc, cellRtcSetTick); + REG_FUNC(cellRtc, cellRtcTickAddTicks); + REG_FUNC(cellRtc, cellRtcTickAddMicroseconds); + REG_FUNC(cellRtc, cellRtcTickAddSeconds); + REG_FUNC(cellRtc, cellRtcTickAddMinutes); + REG_FUNC(cellRtc, cellRtcTickAddHours); + REG_FUNC(cellRtc, cellRtcTickAddDays); + REG_FUNC(cellRtc, cellRtcTickAddWeeks); + REG_FUNC(cellRtc, cellRtcTickAddMonths); + REG_FUNC(cellRtc, cellRtcTickAddYears); + REG_FUNC(cellRtc, cellRtcConvertUtcToLocalTime); + REG_FUNC(cellRtc, cellRtcConvertLocalTimeToUtc); + + REG_FUNC(cellRtc, cellRtcGetDosTime); + REG_FUNC(cellRtc, cellRtcGetTime_t); + REG_FUNC(cellRtc, cellRtcGetWin32FileTime); + REG_FUNC(cellRtc, cellRtcSetDosTime); + REG_FUNC(cellRtc, cellRtcSetTime_t); + REG_FUNC(cellRtc, cellRtcSetWin32FileTime); + + REG_FUNC(cellRtc, cellRtcIsLeapYear); + REG_FUNC(cellRtc, cellRtcGetDaysInMonth); + REG_FUNC(cellRtc, cellRtcGetDayOfWeek); + REG_FUNC(cellRtc, cellRtcCheckValid); + + REG_FUNC(cellRtc, cellRtcCompareTick); +}); diff --git a/rpcs3/Emu/SysCalls/Modules/cellRtc.h b/rpcs3/Emu/Cell/Modules/cellRtc.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellRtc.h rename to rpcs3/Emu/Cell/Modules/cellRtc.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellRudp.cpp b/rpcs3/Emu/Cell/Modules/cellRudp.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/cellRudp.cpp rename to rpcs3/Emu/Cell/Modules/cellRudp.cpp index f9f22f9710..f72f07fa01 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellRudp.cpp +++ b/rpcs3/Emu/Cell/Modules/cellRudp.cpp @@ -1,12 +1,11 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/IdManager.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" #include "cellRudp.h" -extern Module<> cellRudp; +LOG_CHANNEL(cellRudp); struct rudp_t { @@ -239,7 +238,7 @@ s32 cellRudpProcessEvents() return CELL_OK; } -Module<> cellRudp("cellRudp", []() +DECLARE(ppu_module_manager::cellRudp)("cellRudp", []() { REG_FUNC(cellRudp, cellRudpInit); REG_FUNC(cellRudp, cellRudpEnd); diff --git a/rpcs3/Emu/SysCalls/Modules/cellRudp.h b/rpcs3/Emu/Cell/Modules/cellRudp.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellRudp.h rename to rpcs3/Emu/Cell/Modules/cellRudp.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellSail.cpp b/rpcs3/Emu/Cell/Modules/cellSail.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellSail.cpp rename to rpcs3/Emu/Cell/Modules/cellSail.cpp index bce818099c..8193c663ff 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSail.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSail.cpp @@ -1,14 +1,11 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Callback.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/FS/vfsFile.h" +#include "Emu/Cell/PPUModule.h" #include "cellSail.h" #include "cellPamf.h" -extern Module<> cellSail; +LOG_CHANNEL(cellSail); void playerBoot(vm::ptr pSelf, u64 userParam) { @@ -815,15 +812,13 @@ s32 cellSailPlayerCreateDescriptor(vm::ptr pSelf, s32 streamType std::string uri = pUri.get_ptr(); if (uri.substr(0, 12) == "x-cell-fs://") { - std::string path = uri.substr(12); - vfsFile f; - if (f.Open(path)) + if (fs::file f{ vfs::get(uri.substr(12)) }) { - u64 size = f.GetSize(); + u64 size = f.size(); u32 buffer = vm::alloc(size, vm::main); auto bufPtr = vm::cptr::make(buffer); PamfHeader *buf = const_cast(bufPtr.get_ptr()); - assert(f.Read(buf, size) == size); + ASSERT(f.read(buf, size) == size); u32 sp_ = vm::alloc(sizeof(CellPamfReader), vm::main); auto sp = vm::ptr::make(sp_); u32 reader = cellPamfReaderInitialize(sp, bufPtr, size, 0); @@ -1043,7 +1038,7 @@ s32 cellSailPlayerUnregisterSource() return CELL_OK; } -Module<> cellSail("cellSail", []() +DECLARE(ppu_module_manager::cellSail)("cellSail", []() { REG_FUNC(cellSail, cellSailMemAllocatorInitialize); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSail.h b/rpcs3/Emu/Cell/Modules/cellSail.h similarity index 99% rename from rpcs3/Emu/SysCalls/Modules/cellSail.h rename to rpcs3/Emu/Cell/Modules/cellSail.h index 9bfd158f74..2ba84d26ae 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSail.h +++ b/rpcs3/Emu/Cell/Modules/cellSail.h @@ -674,11 +674,13 @@ union CellSailEvent be_t value; }; -template struct cast_ppu_gpr; +template +struct ppu_gpr_cast_impl; -template<> struct cast_ppu_gpr +template<> +struct ppu_gpr_cast_impl { - static inline u64 to_gpr(const CellSailEvent& event) + static inline u64 to(const CellSailEvent& event) { return event.value; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellSailRec.cpp b/rpcs3/Emu/Cell/Modules/cellSailRec.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/cellSailRec.cpp rename to rpcs3/Emu/Cell/Modules/cellSailRec.cpp index 2777d8d0c9..7840bc8461 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSailRec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSailRec.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellSailRec; +LOG_CHANNEL(cellSailRec); // Error Codes enum @@ -255,7 +254,7 @@ s32 cellSailRecorderDumpImage() return CELL_OK; } -Module<> cellSailRec("cellSailRec", []() +DECLARE(ppu_module_manager::cellSailRec)("cellSailRec", []() { REG_FUNC(cellSailRec, cellSailProfileSetEsAudioParameter); REG_FUNC(cellSailRec, cellSailProfileSetEsVideoParameter); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp similarity index 80% rename from rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp rename to rpcs3/Emu/Cell/Modules/cellSaveData.cpp index 677097c3a3..333b4e86c6 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -1,17 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFile.h" -#include "Emu/FS/vfsDir.h" -#include "Loader/PSF.h" #include "cellSaveData.h" -extern Module<> cellSysutil; -extern Module<> cellSaveData; -extern Module<> cellMinisSaveData; +LOG_CHANNEL(cellSaveData); // cellSaveData aliases (only for cellSaveData.cpp) using PSetList = vm::ptr; @@ -38,7 +31,7 @@ enum : u32 std::mutex g_savedata_mutex; -never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cptr dirName, +static never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cptr dirName, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, u32 unknown, vm::ptr userdata, u32 userId, PFuncDone funcDone) { @@ -61,7 +54,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt vm::var fileSet; // path of the specified user (00000001 by default) - const std::string base_dir = fmt::format("/dev_hdd0/home/%08u/savedata/", userId ? userId : 1u); + const std::string& base_dir = vfs::get(fmt::format("/dev_hdd0/home/%08u/savedata/", userId ? userId : 1u)); result->userdata = userdata; // probably should be assigned only once (allows the callback to change it) @@ -78,16 +71,16 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt const auto prefix_list = fmt::split(setList->dirNamePrefix.get_ptr(), { "|" }); - for (const auto entry : vfsDir(base_dir)) + for (const auto& entry : fs::dir(base_dir)) { - if (entry->flags & DirEntry_TypeFile) + if (entry.is_directory) { continue; } for (const auto& prefix : prefix_list) { - if (entry->name.substr(0, prefix.size()) == prefix) + if (entry.name.substr(0, prefix.size()) == prefix) { // Count the amount of matches and the amount of listed directories if (listGet->dirListNum++ < setBuf->dirListMax) @@ -95,7 +88,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt listGet->dirNum++; // PSF parameters - const auto& psf = psf::load(vfsFile(base_dir + entry->name + "/PARAM.SFO").VRead()); + const auto& psf = psf::load_object(fs::file(base_dir + entry.name + "/PARAM.SFO")); if (psf.empty()) { @@ -111,14 +104,14 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt save_entry2.size = 0; - for (const auto entry2 : vfsDir(base_dir + entry->name)) + for (const auto entry2 : fs::dir(base_dir + entry.name)) { - save_entry2.size += entry2->size; + save_entry2.size += entry2.size; } - save_entry2.atime = entry->access_time; - save_entry2.mtime = entry->modify_time; - save_entry2.ctime = entry->create_time; + save_entry2.atime = entry.atime; + save_entry2.mtime = entry.mtime; + save_entry2.ctime = entry.ctime; //save_entry2.iconBuf = NULL; // TODO: Here should be the PNG buffer //save_entry2.iconBufSize = 0; // TODO: Size of the PNG file save_entry2.isNew = false; @@ -184,7 +177,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt if (result->result < 0) { - cellSysutil.warning("savedata_op(): funcList returned < 0."); + cellSaveData.warning("savedata_op(): funcList returned < 0."); return CELL_SAVEDATA_ERROR_CBRESULT; } @@ -266,7 +259,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt } default: { - cellSysutil.error("savedata_op(): unknown listSet->focusPosition (0x%x)", pos_type); + cellSaveData.error("savedata_op(): unknown listSet->focusPosition (0x%x)", pos_type); return CELL_SAVEDATA_ERROR_PARAM; } } @@ -294,7 +287,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt if (result->result < 0) { - cellSysutil.warning("savedata_op(): funcFixed returned < 0."); + cellSaveData.warning("savedata_op(): funcFixed returned < 0."); return CELL_SAVEDATA_ERROR_CBRESULT; } @@ -339,16 +332,12 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt std::string dir_path = base_dir + save_entry.dirName + "/"; std::string sfo_path = dir_path + "PARAM.SFO"; - auto&& psf = psf::load(vfsFile(sfo_path).VRead()); + auto&& psf = psf::load_object(fs::file(sfo_path)); // Get save stats { - std::string dir_local_path; - - Emu.GetVFS().GetDevice(dir_path, dir_local_path); - - fs::stat_t dir_info; - if (!fs::stat(dir_local_path, dir_info)) + fs::stat_t dir_info{}; + if (!fs::stat(dir_path, dir_info)) { // error } @@ -381,32 +370,32 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt auto file_list = statGet->fileList.get_ptr(); - for (const auto entry : vfsDir(dir_path)) + for (const auto& entry : fs::dir(dir_path)) { // only files, system files ignored, fileNum is limited by setBuf->fileListMax - if (entry->flags & DirEntry_TypeFile && entry->name != "PARAM.SFO" && statGet->fileListNum++ < setBuf->fileListMax) + if (!entry.is_directory && entry.name != "PARAM.SFO" && statGet->fileListNum++ < setBuf->fileListMax) { statGet->fileNum++; auto& file = *file_list++; - if (entry->name == "ICON0.PNG") + if (entry.name == "ICON0.PNG") { file.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON0; } - else if (entry->name == "ICON1.PAM") + else if (entry.name == "ICON1.PAM") { file.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON1; } - else if (entry->name == "PIC1.PNG") + else if (entry.name == "PIC1.PNG") { file.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_PIC1; } - else if (entry->name == "SND0.AT3") + else if (entry.name == "SND0.AT3") { file.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_SND0; } - else if (psf::get_integer(psf, "*" + entry->name)) // let's put the list of protected files in PARAM.SFO (int param = 1 if protected) + else if (psf::get_integer(psf, "*" + entry.name)) // let's put the list of protected files in PARAM.SFO (int param = 1 if protected) { file.fileType = CELL_SAVEDATA_FILETYPE_SECUREFILE; } @@ -415,11 +404,11 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt file.fileType = CELL_SAVEDATA_FILETYPE_NORMALFILE; } - file.size = entry->size; - file.atime = entry->access_time; - file.mtime = entry->modify_time; - file.ctime = entry->create_time; - strcpy_trunc(file.fileName, entry->name); + file.size = entry.size; + file.atime = entry.atime; + file.mtime = entry.mtime; + file.ctime = entry.ctime; + strcpy_trunc(file.fileName, entry.name); } } @@ -428,7 +417,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt if (result->result < 0) { - cellSysutil.warning("savedata_op(): funcStat returned < 0."); + cellSaveData.warning("savedata_op(): funcStat returned 0x%x", result->result); return CELL_SAVEDATA_ERROR_CBRESULT; } @@ -473,19 +462,19 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt case CELL_SAVEDATA_RECREATE_YES: case CELL_SAVEDATA_RECREATE_YES_RESET_OWNER: { - // kill it with fire - for (const auto entry : vfsDir(dir_path)) + // TODO? + for (const auto& entry : fs::dir(dir_path)) { - if (entry->flags & DirEntry_TypeFile) + if (!entry.is_directory) { - Emu.GetVFS().RemoveFile(dir_path + entry->name); + fs::remove_file(dir_path + entry.name); } } if (!statSet->setParam) { // Savedata deleted and setParam is NULL: delete directory and abort operation - if (Emu.GetVFS().RemoveDir(dir_path)) cellSysutil.error("savedata_op(): savedata directory %s deleted", save_entry.dirName); + if (fs::remove_dir(dir_path)) cellSaveData.error("savedata_op(): savedata directory %s deleted", save_entry.dirName); return CELL_OK; } @@ -495,16 +484,17 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt default: { - cellSysutil.error("savedata_op(): unknown statSet->reCreateMode (0x%x)", statSet->reCreateMode); + cellSaveData.error("savedata_op(): unknown statSet->reCreateMode (0x%x)", statSet->reCreateMode); return CELL_SAVEDATA_ERROR_PARAM; } } } // Create save directory if necessary - if (psf.size() && save_entry.isNew && !Emu.GetVFS().CreateDir(dir_path)) + if (psf.size() && save_entry.isNew && !fs::create_dir(dir_path)) { // Let's ignore this error for now + cellSaveData.warning("savedata_op(): failed to create %s", dir_path); } // Enter the loop where the save files are read/created/deleted @@ -518,7 +508,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt if (result->result < 0) { - cellSysutil.warning("savedata_op(): funcFile returned < 0."); + cellSaveData.warning("savedata_op(): funcFile returned < 0."); return CELL_SAVEDATA_ERROR_CBRESULT; } @@ -564,22 +554,18 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt default: { - cellSysutil.error("savedata_op(): unknown fileSet->fileType (0x%x)", type); + cellSaveData.error("savedata_op(): unknown fileSet->fileType (0x%x)", type); return CELL_SAVEDATA_ERROR_PARAM; } } psf.emplace("*" + file_path, fileSet->fileType == CELL_SAVEDATA_FILETYPE_SECUREFILE); - std::string local_path; - - Emu.GetVFS().GetDevice(dir_path + file_path, local_path); - switch (const u32 op = fileSet->fileOperation) { case CELL_SAVEDATA_FILEOP_READ: { - fs::file file(local_path, fom::read); + fs::file file(dir_path + file_path, fs::read); file.seek(fileSet->fileOffset); fileGet->excSize = static_cast(file.read(fileSet->fileBuf.get_ptr(), std::min(fileSet->fileSize, fileSet->fileBufSize))); break; @@ -587,23 +573,23 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt case CELL_SAVEDATA_FILEOP_WRITE: { - fs::file file(local_path, fom::write | fom::create); + fs::file file(dir_path + file_path, fs::write + fs::create); file.seek(fileSet->fileOffset); fileGet->excSize = static_cast(file.write(fileSet->fileBuf.get_ptr(), std::min(fileSet->fileSize, fileSet->fileBufSize))); - file.trunc(file.seek(0, fs::seek_cur)); // truncate + file.trunc(file.pos()); // truncate break; } case CELL_SAVEDATA_FILEOP_DELETE: { - fs::remove_file(local_path); + fs::remove_file(dir_path + file_path); fileGet->excSize = 0; break; } case CELL_SAVEDATA_FILEOP_WRITE_NOTRUNC: { - fs::file file(local_path, fom::write | fom::create); + fs::file file(dir_path + file_path, fs::write + fs::create); file.seek(fileSet->fileOffset); fileGet->excSize = static_cast(file.write(fileSet->fileBuf.get_ptr(), std::min(fileSet->fileSize, fileSet->fileBufSize))); break; @@ -611,7 +597,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt default: { - cellSysutil.error("savedata_op(): unknown fileSet->fileOperation (0x%x)", op); + cellSaveData.error("savedata_op(): unknown fileSet->fileOperation (0x%x)", op); return CELL_SAVEDATA_ERROR_PARAM; } } @@ -620,7 +606,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt // Write PARAM.SFO if (psf.size()) { - vfsFile(sfo_path, fom::rewrite).VWrite(psf::save(psf)); + fs::file(sfo_path, fs::rewrite).write(psf::save_object(psf)); } return CELL_OK; @@ -630,7 +616,7 @@ never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cpt s32 cellSaveDataListSave2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.warning("cellSaveDataListSave2(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.warning("cellSaveDataListSave2(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, setList, setBuf, funcList, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_LIST_SAVE, version, vm::null, 1, setList, setBuf, funcList, vm::null, funcStat, funcFile, container, 2, userdata, 0, vm::null); @@ -639,7 +625,7 @@ s32 cellSaveDataListSave2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf s32 cellSaveDataListLoad2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.warning("cellSaveDataListLoad2(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.warning("cellSaveDataListLoad2(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, setList, setBuf, funcList, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_LIST_LOAD, version, vm::null, 1, setList, setBuf, funcList, vm::null, funcStat, funcFile, container, 2, userdata, 0, vm::null); @@ -648,7 +634,7 @@ s32 cellSaveDataListLoad2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf s32 cellSaveDataListSave(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container) { - cellSysutil.warning("cellSaveDataListSave(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", + cellSaveData.warning("cellSaveDataListSave(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", version, setList, setBuf, funcList, funcStat, funcFile, container); return savedata_op(ppu, SAVEDATA_OP_LIST_SAVE, version, vm::null, 1, setList, setBuf, funcList, vm::null, funcStat, funcFile, container, 2, vm::null, 0, vm::null); @@ -657,7 +643,7 @@ s32 cellSaveDataListSave(PPUThread& ppu, u32 version, PSetList setList, PSetBuf s32 cellSaveDataListLoad(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container) { - cellSysutil.warning("cellSaveDataListLoad(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", + cellSaveData.warning("cellSaveDataListLoad(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", version, setList, setBuf, funcList, funcStat, funcFile, container); return savedata_op(ppu, SAVEDATA_OP_LIST_LOAD, version, vm::null, 1, setList, setBuf, funcList, vm::null, funcStat, funcFile, container, 2, vm::null, 0, vm::null); @@ -667,7 +653,7 @@ s32 cellSaveDataListLoad(PPUThread& ppu, u32 version, PSetList setList, PSetBuf s32 cellSaveDataFixedSave2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.warning("cellSaveDataFixedSave2(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.warning("cellSaveDataFixedSave2(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_FIXED_SAVE, version, vm::null, 1, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 2, userdata, 0, vm::null); @@ -676,7 +662,7 @@ s32 cellSaveDataFixedSave2(PPUThread& ppu, u32 version, PSetList setList, PSetBu s32 cellSaveDataFixedLoad2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.warning("cellSaveDataFixedLoad2(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.warning("cellSaveDataFixedLoad2(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_FIXED_LOAD, version, vm::null, 1, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 2, userdata, 0, vm::null); @@ -685,7 +671,7 @@ s32 cellSaveDataFixedLoad2(PPUThread& ppu, u32 version, PSetList setList, PSetBu s32 cellSaveDataFixedSave(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container) { - cellSysutil.warning("cellSaveDataFixedSave(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", + cellSaveData.warning("cellSaveDataFixedSave(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", version, setList, setBuf, funcFixed, funcStat, funcFile, container); return savedata_op(ppu, SAVEDATA_OP_FIXED_SAVE, version, vm::null, 1, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 2, vm::null, 0, vm::null); @@ -695,7 +681,7 @@ s32 cellSaveDataFixedSave(PPUThread& ppu, u32 version, PSetList setList, PSetBuf s32 cellSaveDataFixedLoad(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container) { - cellSysutil.warning("cellSaveDataFixedLoad(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", + cellSaveData.warning("cellSaveDataFixedLoad(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", version, setList, setBuf, funcFixed, funcStat, funcFile, container); return savedata_op(ppu, SAVEDATA_OP_FIXED_LOAD, version, vm::null, 1, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 2, vm::null, 0, vm::null); @@ -704,7 +690,7 @@ s32 cellSaveDataFixedLoad(PPUThread& ppu, u32 version, PSetList setList, PSetBuf s32 cellSaveDataAutoSave2(PPUThread& ppu, u32 version, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.warning("cellSaveDataAutoSave2(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.warning("cellSaveDataAutoSave2(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, dirName, errDialog, setBuf, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_AUTO_SAVE, version, dirName, errDialog, vm::null, setBuf, vm::null, vm::null, funcStat, funcFile, container, 2, userdata, 0, vm::null); @@ -713,7 +699,7 @@ s32 cellSaveDataAutoSave2(PPUThread& ppu, u32 version, vm::cptr dirName, u s32 cellSaveDataAutoLoad2(PPUThread& ppu, u32 version, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.warning("cellSaveDataAutoLoad2(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.warning("cellSaveDataAutoLoad2(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, dirName, errDialog, setBuf, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_AUTO_LOAD, version, dirName, errDialog, vm::null, setBuf, vm::null, vm::null, funcStat, funcFile, container, 2, userdata, 0, vm::null); @@ -722,7 +708,7 @@ s32 cellSaveDataAutoLoad2(PPUThread& ppu, u32 version, vm::cptr dirName, u s32 cellSaveDataAutoSave(PPUThread& ppu, u32 version, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container) { - cellSysutil.warning("cellSaveDataAutoSave(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", + cellSaveData.warning("cellSaveDataAutoSave(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", version, dirName, errDialog, setBuf, funcStat, funcFile, container); return savedata_op(ppu, SAVEDATA_OP_AUTO_SAVE, version, dirName, errDialog, vm::null, setBuf, vm::null, vm::null, funcStat, funcFile, container, 2, vm::null, 0, vm::null); @@ -731,7 +717,7 @@ s32 cellSaveDataAutoSave(PPUThread& ppu, u32 version, vm::cptr dirName, u3 s32 cellSaveDataAutoLoad(PPUThread& ppu, u32 version, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container) { - cellSysutil.warning("cellSaveDataAutoLoad(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", + cellSaveData.warning("cellSaveDataAutoLoad(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)", version, dirName, errDialog, setBuf, funcStat, funcFile, container); return savedata_op(ppu, SAVEDATA_OP_AUTO_LOAD, version, dirName, errDialog, vm::null, setBuf, vm::null, vm::null, funcStat, funcFile, container, 2, vm::null, 0, vm::null); @@ -739,7 +725,7 @@ s32 cellSaveDataAutoLoad(PPUThread& ppu, u32 version, vm::cptr dirName, u3 s32 cellSaveDataListAutoSave(PPUThread& ppu, u32 version, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.warning("cellSaveDataListAutoSave(version=%d, errDialog=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.warning("cellSaveDataListAutoSave(version=%d, errDialog=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, errDialog, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_LIST_AUTO_SAVE, version, vm::null, errDialog, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 0, userdata, 0, vm::null); @@ -747,7 +733,7 @@ s32 cellSaveDataListAutoSave(PPUThread& ppu, u32 version, u32 errDialog, PSetLis s32 cellSaveDataListAutoLoad(PPUThread& ppu, u32 version, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.warning("cellSaveDataListAutoLoad(version=%d, errDialog=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.warning("cellSaveDataListAutoLoad(version=%d, errDialog=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, errDialog, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_LIST_AUTO_LOAD, version, vm::null, errDialog, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 0, userdata, 0, vm::null); @@ -755,21 +741,21 @@ s32 cellSaveDataListAutoLoad(PPUThread& ppu, u32 version, u32 errDialog, PSetLis s32 cellSaveDataDelete2(u32 container) { - cellSysutil.todo("cellSaveDataDelete2(container=0x%x)", container); + cellSaveData.todo("cellSaveDataDelete2(container=0x%x)", container); return CELL_SAVEDATA_RET_CANCEL; } s32 cellSaveDataDelete(u32 container) { - cellSysutil.todo("cellSaveDataDelete(container=0x%x)", container); + cellSaveData.todo("cellSaveDataDelete(container=0x%x)", container); return CELL_SAVEDATA_RET_CANCEL; } s32 cellSaveDataFixedDelete(PPUThread& ppu, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncDone funcDone, u32 container, vm::ptr userdata) { - cellSysutil.todo("cellSaveDataFixedDelete(setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.todo("cellSaveDataFixedDelete(setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", setList, setBuf, funcFixed, funcDone, container, userdata); return CELL_OK; @@ -777,7 +763,7 @@ s32 cellSaveDataFixedDelete(PPUThread& ppu, PSetList setList, PSetBuf setBuf, PF s32 cellSaveDataUserListSave(PPUThread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.error("cellSaveDataUserListSave(version=%d, userId=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.error("cellSaveDataUserListSave(version=%d, userId=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, userId, setList, setBuf, funcList, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_LIST_SAVE, version, vm::null, 0, setList, setBuf, funcList, vm::null, funcStat, funcFile, container, 6, userdata, userId, vm::null); @@ -785,7 +771,7 @@ s32 cellSaveDataUserListSave(PPUThread& ppu, u32 version, u32 userId, PSetList s s32 cellSaveDataUserListLoad(PPUThread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.error("cellSaveDataUserListLoad(version=%d, userId=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.error("cellSaveDataUserListLoad(version=%d, userId=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, userId, setList, setBuf, funcList, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_LIST_LOAD, version, vm::null, 0, setList, setBuf, funcList, vm::null, funcStat, funcFile, container, 6, userdata, userId, vm::null); @@ -793,7 +779,7 @@ s32 cellSaveDataUserListLoad(PPUThread& ppu, u32 version, u32 userId, PSetList s s32 cellSaveDataUserFixedSave(PPUThread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.error("cellSaveDataUserFixedSave(version=%d, userId=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.error("cellSaveDataUserFixedSave(version=%d, userId=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, userId, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_FIXED_SAVE, version, vm::null, 0, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 6, userdata, userId, vm::null); @@ -801,7 +787,7 @@ s32 cellSaveDataUserFixedSave(PPUThread& ppu, u32 version, u32 userId, PSetList s32 cellSaveDataUserFixedLoad(PPUThread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.error("cellSaveDataUserFixedLoad(version=%d, userId=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.error("cellSaveDataUserFixedLoad(version=%d, userId=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, userId, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_FIXED_LOAD, version, vm::null, 0, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 6, userdata, userId, vm::null); @@ -809,7 +795,7 @@ s32 cellSaveDataUserFixedLoad(PPUThread& ppu, u32 version, u32 userId, PSetList s32 cellSaveDataUserAutoSave(PPUThread& ppu, u32 version, u32 userId, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.error("cellSaveDataUserAutoSave(version=%d, userId=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.error("cellSaveDataUserAutoSave(version=%d, userId=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, userId, dirName, errDialog, setBuf, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_AUTO_SAVE, version, dirName, errDialog, vm::null, setBuf, vm::null, vm::null, funcStat, funcFile, container, 6, userdata, userId, vm::null); @@ -817,7 +803,7 @@ s32 cellSaveDataUserAutoSave(PPUThread& ppu, u32 version, u32 userId, vm::cptr dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.error("cellSaveDataUserAutoLoad(version=%d, userId=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.error("cellSaveDataUserAutoLoad(version=%d, userId=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, userId, dirName, errDialog, setBuf, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_AUTO_LOAD, version, dirName, errDialog, vm::null, setBuf, vm::null, vm::null, funcStat, funcFile, container, 6, userdata, userId, vm::null); @@ -825,7 +811,7 @@ s32 cellSaveDataUserAutoLoad(PPUThread& ppu, u32 version, u32 userId, vm::cptr userdata) { - cellSysutil.error("cellSaveDataUserListAutoSave(version=%d, userId=%d, errDialog=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.error("cellSaveDataUserListAutoSave(version=%d, userId=%d, errDialog=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, userId, errDialog, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_LIST_AUTO_SAVE, version, vm::null, errDialog, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 6, userdata, userId, vm::null); @@ -833,7 +819,7 @@ s32 cellSaveDataUserListAutoSave(PPUThread& ppu, u32 version, u32 userId, u32 er s32 cellSaveDataUserListAutoLoad(PPUThread& ppu, u32 version, u32 userId, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr userdata) { - cellSysutil.error("cellSaveDataUserListAutoLoad(version=%d, userId=%d, errDialog=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.error("cellSaveDataUserListAutoLoad(version=%d, userId=%d, errDialog=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)", version, userId, errDialog, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata); return savedata_op(ppu, SAVEDATA_OP_LIST_AUTO_LOAD, version, vm::null, errDialog, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 6, userdata, userId, vm::null); @@ -841,7 +827,7 @@ s32 cellSaveDataUserListAutoLoad(PPUThread& ppu, u32 version, u32 userId, u32 er s32 cellSaveDataUserFixedDelete(PPUThread& ppu, u32 userId, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncDone funcDone, u32 container, vm::ptr userdata) { - cellSysutil.todo("cellSaveDataUserFixedDelete(userId=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", + cellSaveData.todo("cellSaveDataUserFixedDelete(userId=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", userId, setList, setBuf, funcFixed, funcDone, container, userdata); return CELL_OK; @@ -849,7 +835,7 @@ s32 cellSaveDataUserFixedDelete(PPUThread& ppu, u32 userId, PSetList setList, PS void cellSaveDataEnableOverlay(s32 enable) { - cellSysutil.error("cellSaveDataEnableOverlay(enable=%d)", enable); + cellSaveData.error("cellSaveDataEnableOverlay(enable=%d)", enable); return; } @@ -977,7 +963,7 @@ void cellSysutil_SaveData_init() REG_FUNC(cellSysutil, cellSaveDataAutoSave); } -Module<> cellSaveData("cellSaveData", []() +DECLARE(ppu_module_manager::cellSaveData)("cellSaveData", []() { // libsysutil_savedata functions: REG_FUNC(cellSaveData, cellSaveDataUserGetListItem); @@ -994,7 +980,7 @@ Module<> cellSaveData("cellSaveData", []() REG_FUNC(cellSaveData, cellSaveDataListImport); }); -Module<> cellMinisSaveData("cellMinisSaveData", []() +DECLARE(ppu_module_manager::cellMinisSaveData)("cellMinisSaveData", []() { // libsysutil_savedata_psp functions: //REG_FUNC(cellMinisSaveData, cellMinisSaveDataDelete); // 0x6eb168b3 diff --git a/rpcs3/Emu/SysCalls/Modules/cellSaveData.h b/rpcs3/Emu/Cell/Modules/cellSaveData.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellSaveData.h rename to rpcs3/Emu/Cell/Modules/cellSaveData.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellScreenshot.cpp b/rpcs3/Emu/Cell/Modules/cellScreenshot.cpp similarity index 59% rename from rpcs3/Emu/SysCalls/Modules/cellScreenshot.cpp rename to rpcs3/Emu/Cell/Modules/cellScreenshot.cpp index 95b8e15a40..b062a1d5e8 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellScreenshot.cpp +++ b/rpcs3/Emu/Cell/Modules/cellScreenshot.cpp @@ -1,10 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" + #include "cellScreenshot.h" -extern Module<> cellScreenshot; +LOG_CHANNEL(cellScreenshot); s32 cellScreenShotSetParameter() //const CellScreenShotSetParam *param { @@ -30,10 +30,10 @@ s32 cellScreenShotDisable() return CELL_OK; } -Module<> cellScreenshot("cellScreenshot", []() +DECLARE(ppu_module_manager::cellScreenShot)("cellScreenShotUtility", []() { - REG_FUNC(cellScreenshot, cellScreenShotSetParameter); - REG_FUNC(cellScreenshot, cellScreenShotSetOverlayImage); - REG_FUNC(cellScreenshot, cellScreenShotEnable); - REG_FUNC(cellScreenshot, cellScreenShotDisable); + REG_FUNC(cellScreenShotUtility, cellScreenShotSetParameter); + REG_FUNC(cellScreenShotUtility, cellScreenShotSetOverlayImage); + REG_FUNC(cellScreenShotUtility, cellScreenShotEnable); + REG_FUNC(cellScreenShotUtility, cellScreenShotDisable); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellScreenshot.h b/rpcs3/Emu/Cell/Modules/cellScreenshot.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellScreenshot.h rename to rpcs3/Emu/Cell/Modules/cellScreenshot.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellSearch.cpp b/rpcs3/Emu/Cell/Modules/cellSearch.cpp similarity index 60% rename from rpcs3/Emu/SysCalls/Modules/cellSearch.cpp rename to rpcs3/Emu/Cell/Modules/cellSearch.cpp index 90f264f3f6..6c9e43fc6c 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSearch.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSearch.cpp @@ -1,10 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" + #include "cellSearch.h" -extern Module<> cellSearch; +LOG_CHANNEL(cellSearch); s32 cellSearchInitialize(CellSearchMode mode, u32 container, vm::ptr func, vm::ptr userData) { @@ -130,26 +130,26 @@ s32 cellSearchEnd() return CELL_OK; } -Module<> cellSearch("cellSearch", []() +DECLARE(ppu_module_manager::cellSearch)("cellSearchUtility", []() { - REG_FUNC(cellSearch, cellSearchInitialize); - REG_FUNC(cellSearch, cellSearchFinalize); - REG_FUNC(cellSearch, cellSearchStartListSearch); - REG_FUNC(cellSearch, cellSearchStartContentSearchInList); - REG_FUNC(cellSearch, cellSearchStartContentSearch); - REG_FUNC(cellSearch, cellSearchStartSceneSearchInVideo); - REG_FUNC(cellSearch, cellSearchStartSceneSearch); - REG_FUNC(cellSearch, cellSearchGetContentInfoByOffset); - REG_FUNC(cellSearch, cellSearchGetContentInfoByContentId); - REG_FUNC(cellSearch, cellSearchGetOffsetByContentId); - REG_FUNC(cellSearch, cellSearchGetContentIdByOffset); - REG_FUNC(cellSearch, cellSearchGetContentInfoGameComment); - REG_FUNC(cellSearch, cellSearchGetMusicSelectionContext); - REG_FUNC(cellSearch, cellSearchGetMusicSelectionContextOfSingleTrack); - REG_FUNC(cellSearch, cellSearchGetContentInfoPath); - REG_FUNC(cellSearch, cellSearchGetContentInfoPathMovieThumb); - REG_FUNC(cellSearch, cellSearchPrepareFile); - REG_FUNC(cellSearch, cellSearchGetContentInfoDeveloperData); - REG_FUNC(cellSearch, cellSearchCancel); - REG_FUNC(cellSearch, cellSearchEnd); + REG_FUNC(cellSearchUtility, cellSearchInitialize); + REG_FUNC(cellSearchUtility, cellSearchFinalize); + REG_FUNC(cellSearchUtility, cellSearchStartListSearch); + REG_FUNC(cellSearchUtility, cellSearchStartContentSearchInList); + REG_FUNC(cellSearchUtility, cellSearchStartContentSearch); + REG_FUNC(cellSearchUtility, cellSearchStartSceneSearchInVideo); + REG_FUNC(cellSearchUtility, cellSearchStartSceneSearch); + REG_FUNC(cellSearchUtility, cellSearchGetContentInfoByOffset); + REG_FUNC(cellSearchUtility, cellSearchGetContentInfoByContentId); + REG_FUNC(cellSearchUtility, cellSearchGetOffsetByContentId); + REG_FUNC(cellSearchUtility, cellSearchGetContentIdByOffset); + REG_FUNC(cellSearchUtility, cellSearchGetContentInfoGameComment); + REG_FUNC(cellSearchUtility, cellSearchGetMusicSelectionContext); + REG_FUNC(cellSearchUtility, cellSearchGetMusicSelectionContextOfSingleTrack); + REG_FUNC(cellSearchUtility, cellSearchGetContentInfoPath); + REG_FUNC(cellSearchUtility, cellSearchGetContentInfoPathMovieThumb); + REG_FUNC(cellSearchUtility, cellSearchPrepareFile); + REG_FUNC(cellSearchUtility, cellSearchGetContentInfoDeveloperData); + REG_FUNC(cellSearchUtility, cellSearchCancel); + REG_FUNC(cellSearchUtility, cellSearchEnd); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSearch.h b/rpcs3/Emu/Cell/Modules/cellSearch.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellSearch.h rename to rpcs3/Emu/Cell/Modules/cellSearch.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellSheap.cpp b/rpcs3/Emu/Cell/Modules/cellSheap.cpp similarity index 95% rename from rpcs3/Emu/SysCalls/Modules/cellSheap.cpp rename to rpcs3/Emu/Cell/Modules/cellSheap.cpp index b8bd086ac8..fe8ac83558 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSheap.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSheap.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellSheap; +LOG_CHANNEL(cellSheap); // Return Codes enum @@ -121,7 +120,7 @@ s32 cellKeySheapQueueDelete() return CELL_OK; } -Module<> cellSheap("cellSheap", []() +DECLARE(ppu_module_manager::cellSheap)("cellSheap", []() { REG_FUNC(cellSheap, cellSheapInitialize); REG_FUNC(cellSheap, cellSheapAllocate); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpudll.cpp b/rpcs3/Emu/Cell/Modules/cellSpudll.cpp similarity index 75% rename from rpcs3/Emu/SysCalls/Modules/cellSpudll.cpp rename to rpcs3/Emu/Cell/Modules/cellSpudll.cpp index 026b5be393..5aeaa9ae77 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpudll.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSpudll.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellSpudll; +LOG_CHANNEL(cellSpudll); s32 cellSpudllGetImageSize(vm::ptr psize, vm::cptr so_elf, vm::cptr config) { @@ -14,7 +13,7 @@ s32 cellSpudllHandleConfigSetDefaultValues(vm::ptr cellSpudll("cellSpudll", []() +DECLARE(ppu_module_manager::cellSpudll)("cellSpudll", []() { REG_FUNC(cellSpudll, cellSpudllGetImageSize); REG_FUNC(cellSpudll, cellSpudllHandleConfigSetDefaultValues); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp rename to rpcs3/Emu/Cell/Modules/cellSpurs.cpp index d94ffa27c0..d20b448ce4 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp @@ -1,28 +1,34 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" #include "Emu/IdManager.h" -#include "Emu/Event.h" +#include "Emu/Cell/PPUModule.h" #include "Emu/Cell/SPUThread.h" -#include "Emu/SysCalls/lv2/sys_sync.h" -#include "Emu/SysCalls/lv2/sys_lwmutex.h" -#include "Emu/SysCalls/lv2/sys_lwcond.h" -#include "Emu/SysCalls/lv2/sys_spu.h" -#include "Emu/SysCalls/lv2/sys_ppu_thread.h" -#include "Emu/SysCalls/lv2/sys_memory.h" -#include "Emu/SysCalls/lv2/sys_process.h" -#include "Emu/SysCalls/lv2/sys_semaphore.h" -#include "Emu/SysCalls/lv2/sys_event.h" +#include "Emu/Cell/lv2/sys_lwmutex.h" +#include "Emu/Cell/lv2/sys_lwcond.h" +#include "Emu/Cell/lv2/sys_spu.h" +#include "Emu/Cell/lv2/sys_ppu_thread.h" +#include "Emu/Cell/lv2/sys_memory.h" +#include "Emu/Cell/lv2/sys_process.h" +#include "Emu/Cell/lv2/sys_semaphore.h" +#include "Emu/Cell/lv2/sys_event.h" #include "sysPrxForUser.h" #include "cellSpurs.h" -//---------------------------------------------------------------------------- -// Externs -//---------------------------------------------------------------------------- +LOG_CHANNEL(cellSpurs); -extern Module<> cellSpurs; +// TODO +struct cell_error_t +{ + s32 value; + + explicit operator bool() const + { + return (value < 0); + } +}; + +#define CHECK_SUCCESS(expr) if (cell_error_t error{expr}) throw fmt::exception("Failure: %s -> 0x%x" HERE, #expr, error.value) //---------------------------------------------------------------------------- // Function prototypes @@ -582,7 +588,7 @@ void _spurs::handler_entry(PPUThread& ppu, vm::ptr spurs) if ((spurs->flags1 & SF1_EXIT_IF_NO_WORK) == 0) { - CHECK_ASSERTION(spurs->handlerExiting == 1); + ASSERT(spurs->handlerExiting == 1); return sys_ppu_thread_exit(ppu, 0); } @@ -645,16 +651,16 @@ s32 _spurs::wakeup_shutdown_completion_waiter(PPUThread& ppu, vm::ptr { wklF->hook(ppu, spurs, wid, wklF->hookArg); - CHECK_ASSERTION(wklEvent->load() & 0x01); - CHECK_ASSERTION(wklEvent->load() & 0x02); - CHECK_ASSERTION((wklEvent->load() & 0x20) == 0); - *wklEvent |= 0x20; + ASSERT(wklEvent->load() & 0x01); + ASSERT(wklEvent->load() & 0x02); + ASSERT((wklEvent->load() & 0x20) == 0); + wklEvent->fetch_or(0x20); } s32 rc = CELL_OK; if (!wklF->hook || wklEvent->load() & 0x10) { - CHECK_ASSERTION(wklF->x28 == 2); + ASSERT(wklF->x28 == 2); rc = sys_semaphore_post((u32)wklF->sem, 1); } @@ -665,8 +671,8 @@ void _spurs::event_helper_entry(PPUThread& ppu, vm::ptr spurs) { bool terminate = false; - vm::var events; - vm::var count; + vm::var events(8); + vm::var count; while (!terminate) { @@ -738,7 +744,7 @@ void _spurs::event_helper_entry(PPUThread& ppu, vm::ptr spurs) } else { - CHECK_SUCCESS(data0); + throw fmt::exception("data0=0x%x" HERE, data0); } } } @@ -1021,7 +1027,7 @@ s32 _spurs::initialize(PPUThread& ppu, vm::ptr spurs, u32 revision, u // Import SPURS kernel spurs->spuImg.type = SYS_SPU_IMAGE_TYPE_USER; - spurs->spuImg.addr = vm::alloc(0x40000, vm::main); + spurs->spuImg.segs = { vm::alloc(0x40000, vm::main), vm::addr }; spurs->spuImg.entry_point = isSecond ? CELL_SPURS_KERNEL2_ENTRY_ADDR : CELL_SPURS_KERNEL1_ENTRY_ADDR; spurs->spuImg.nsegs = 1; @@ -2111,8 +2117,8 @@ s32 _spurs::add_workload(vm::ptr spurs, vm::ptr wid, vm::cptrwklCurrentContention[wnum] & 0xf) == 0); - CHECK_ASSERTION((spurs->wklPendingContention[wnum] & 0xf) == 0); + ASSERT((spurs->wklCurrentContention[wnum] & 0xf) == 0); + ASSERT((spurs->wklPendingContention[wnum] & 0xf) == 0); spurs->wklState1[wnum] = 1; spurs->wklStatus1[wnum] = 0; spurs->wklEvent1[wnum] = 0; @@ -2147,8 +2153,8 @@ s32 _spurs::add_workload(vm::ptr spurs, vm::ptr wid, vm::cptrwklCurrentContention[index] & 0xf0) == 0); - CHECK_ASSERTION((spurs->wklPendingContention[index] & 0xf0) == 0); + ASSERT((spurs->wklCurrentContention[index] & 0xf0) == 0); + ASSERT((spurs->wklPendingContention[index] & 0xf0) == 0); spurs->wklState2[index] = 1; spurs->wklStatus2[index] = 0; spurs->wklEvent2[index] = 0; @@ -2183,7 +2189,7 @@ s32 _spurs::add_workload(vm::ptr spurs, vm::ptr wid, vm::cptr 8 ? 8 : maxContention); }); - spurs->wklSignal1._and_not(0x8000 >> index); // clear bit in wklFlag1 + spurs->wklSignal1.fetch_and(~(0x8000 >> index)); // clear bit in wklFlag1 } else { @@ -2192,7 +2198,7 @@ s32 _spurs::add_workload(vm::ptr spurs, vm::ptr wid, vm::cptr 8 ? 8 : maxContention) << 4; }); - spurs->wklSignal2._and_not(0x8000 >> index); // clear bit in wklFlag2 + spurs->wklSignal2.fetch_and(~(0x8000 >> index)); // clear bit in wklFlag2 } spurs->wklFlagReceiver.compare_and_swap(wnum, 0xff); @@ -2227,7 +2233,7 @@ s32 _spurs::add_workload(vm::ptr spurs, vm::ptr wid, vm::cptr> wnum); }); - CHECK_ASSERTION(res_wkl <= 31); + ASSERT(res_wkl <= 31); spurs->wklState(wnum).exchange(2); spurs->sysSrvMsgUpdateWorkload.exchange(0xff); spurs->sysSrvMessage.exchange(0xff); @@ -3160,10 +3166,15 @@ s32 cellSpursEventFlagGetTasksetAddress(vm::ptr eventFlag, v return CELL_SPURS_TASK_ERROR_ALIGN; } - taskset->set(eventFlag->isIwl ? 0u : VM_CAST(eventFlag->addr)); + taskset->set(eventFlag->isIwl ? 0u : vm::cast(eventFlag->addr, HERE)); return CELL_OK; } +static inline s32 SyncErrorToSpursError(const ppu_error_code& res) +{ + return res.value < 0 ? 0x80410900 | (res.value & 0xff) : res.value; +} + s32 _cellSpursLFQueueInitialize(vm::ptr pTasksetOrSpurs, vm::ptr pQueue, vm::cptr buffer, u32 size, u32 depth, u32 direction) { cellSpurs.todo("_cellSpursLFQueueInitialize(pTasksetOrSpurs=*0x%x, pQueue=*0x%x, buffer=*0x%x, size=0x%x, depth=0x%x, direction=%d)", pTasksetOrSpurs, pQueue, buffer, size, depth, direction); @@ -4094,7 +4105,7 @@ s32 cellSpursSemaphoreGetTasksetAddress() return CELL_OK; } -Module<> cellSpurs("cellSpurs", []() +DECLARE(ppu_module_manager::cellSpurs)("cellSpurs", []() { // Core REG_FUNC(cellSpurs, cellSpursInitialize); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h b/rpcs3/Emu/Cell/Modules/cellSpurs.h similarity index 96% rename from rpcs3/Emu/SysCalls/Modules/cellSpurs.h rename to rpcs3/Emu/Cell/Modules/cellSpurs.h index e7698fa9fa..b82f239201 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h +++ b/rpcs3/Emu/Cell/Modules/cellSpurs.h @@ -1,921 +1,916 @@ -#pragma once - -#include "cellSync.h" - -namespace vm { using namespace ps3; } - -struct CellSpurs; -struct CellSpursTaskset; - -// Core return codes. -enum -{ - CELL_SPURS_CORE_ERROR_AGAIN = 0x80410701, - CELL_SPURS_CORE_ERROR_INVAL = 0x80410702, - CELL_SPURS_CORE_ERROR_NOMEM = 0x80410704, - CELL_SPURS_CORE_ERROR_SRCH = 0x80410705, - CELL_SPURS_CORE_ERROR_PERM = 0x80410709, - CELL_SPURS_CORE_ERROR_BUSY = 0x8041070A, - CELL_SPURS_CORE_ERROR_STAT = 0x8041070F, - CELL_SPURS_CORE_ERROR_ALIGN = 0x80410710, - CELL_SPURS_CORE_ERROR_NULL_POINTER = 0x80410711, -}; - -// -enum -{ - CELL_SPURS_POLICY_MODULE_ERROR_AGAIN = 0x80410801, - CELL_SPURS_POLICY_MODULE_ERROR_INVAL = 0x80410802, - CELL_SPURS_POLICY_MODULE_ERROR_NOSYS = 0x80410803, - CELL_SPURS_POLICY_MODULE_ERROR_NOMEM = 0x80410804, - CELL_SPURS_POLICY_MODULE_ERROR_SRCH = 0x80410805, - CELL_SPURS_POLICY_MODULE_ERROR_NOENT = 0x80410806, - CELL_SPURS_POLICY_MODULE_ERROR_NOEXEC = 0x80410807, - CELL_SPURS_POLICY_MODULE_ERROR_DEADLK = 0x80410808, - CELL_SPURS_POLICY_MODULE_ERROR_PERM = 0x80410809, - CELL_SPURS_POLICY_MODULE_ERROR_BUSY = 0x8041080A, - CELL_SPURS_POLICY_MODULE_ERROR_ABORT = 0x8041080C, - CELL_SPURS_POLICY_MODULE_ERROR_FAULT = 0x8041080D, - CELL_SPURS_POLICY_MODULE_ERROR_CHILD = 0x8041080E, - CELL_SPURS_POLICY_MODULE_ERROR_STAT = 0x8041080F, - CELL_SPURS_POLICY_MODULE_ERROR_ALIGN = 0x80410810, - CELL_SPURS_POLICY_MODULE_ERROR_NULL_POINTER = 0x80410811, -}; - -// Task return codes. -enum -{ - CELL_SPURS_TASK_ERROR_AGAIN = 0x80410901, - CELL_SPURS_TASK_ERROR_INVAL = 0x80410902, - CELL_SPURS_TASK_ERROR_NOSYS = 0x80410903, - CELL_SPURS_TASK_ERROR_NOMEM = 0x80410904, - CELL_SPURS_TASK_ERROR_SRCH = 0x80410905, - CELL_SPURS_TASK_ERROR_NOEXEC = 0x80410907, - CELL_SPURS_TASK_ERROR_PERM = 0x80410909, - CELL_SPURS_TASK_ERROR_BUSY = 0x8041090A, - CELL_SPURS_TASK_ERROR_FAULT = 0x8041090D, - CELL_SPURS_TASK_ERROR_ALIGN = 0x80410910, - CELL_SPURS_TASK_ERROR_STAT = 0x8041090F, - CELL_SPURS_TASK_ERROR_NULL_POINTER = 0x80410911, - CELL_SPURS_TASK_ERROR_FATAL = 0x80410914, - CELL_SPURS_TASK_ERROR_SHUTDOWN = 0x80410920, -}; - -enum -{ - CELL_SPURS_JOB_ERROR_AGAIN = 0x80410A01, - CELL_SPURS_JOB_ERROR_INVAL = 0x80410A02, - CELL_SPURS_JOB_ERROR_NOSYS = 0x80410A03, - CELL_SPURS_JOB_ERROR_NOMEM = 0x80410A04, - CELL_SPURS_JOB_ERROR_SRCH = 0x80410A05, - CELL_SPURS_JOB_ERROR_NOENT = 0x80410A06, - CELL_SPURS_JOB_ERROR_NOEXEC = 0x80410A07, - CELL_SPURS_JOB_ERROR_DEADLK = 0x80410A08, - CELL_SPURS_JOB_ERROR_PERM = 0x80410A09, - CELL_SPURS_JOB_ERROR_BUSY = 0x80410A0A, - CELL_SPURS_JOB_ERROR_JOB_DESCRIPTOR = 0x80410A0B, - CELL_SPURS_JOB_ERROR_JOB_DESCRIPTOR_SIZE = 0x80410A0C, - CELL_SPURS_JOB_ERROR_FAULT = 0x80410A0D, - CELL_SPURS_JOB_ERROR_CHILD = 0x80410A0E, - CELL_SPURS_JOB_ERROR_STAT = 0x80410A0F, - CELL_SPURS_JOB_ERROR_ALIGN = 0x80410A10, - CELL_SPURS_JOB_ERROR_NULL_POINTER = 0x80410A11, - CELL_SPURS_JOB_ERROR_MEMORY_CORRUPTED = 0x80410A12, - - CELL_SPURS_JOB_ERROR_MEMORY_SIZE = 0x80410A17, - CELL_SPURS_JOB_ERROR_UNKNOWN_COMMAND = 0x80410A18, - CELL_SPURS_JOB_ERROR_JOBLIST_ALIGNMENT = 0x80410A19, - CELL_SPURS_JOB_ERROR_JOB_ALIGNMENT = 0x80410A1a, - CELL_SPURS_JOB_ERROR_CALL_OVERFLOW = 0x80410A1b, - CELL_SPURS_JOB_ERROR_ABORT = 0x80410A1c, - CELL_SPURS_JOB_ERROR_DMALIST_ELEMENT = 0x80410A1d, - CELL_SPURS_JOB_ERROR_NUM_CACHE = 0x80410A1e, - CELL_SPURS_JOB_ERROR_INVALID_BINARY = 0x80410A1f, -}; - -// SPURS defines. -enum SPURSKernelInterfaces : u32 -{ - CELL_SPURS_MAX_SPU = 8, - CELL_SPURS_MAX_WORKLOAD = 16, - CELL_SPURS_MAX_WORKLOAD2 = 32, - CELL_SPURS_SYS_SERVICE_WORKLOAD_ID = 32, - CELL_SPURS_MAX_PRIORITY = 16, - CELL_SPURS_NAME_MAX_LENGTH = 15, - CELL_SPURS_SIZE = 4096, - CELL_SPURS_SIZE2 = 8192, - CELL_SPURS_INTERRUPT_VECTOR = 0x0, - CELL_SPURS_LOCK_LINE = 0x80, - CELL_SPURS_KERNEL_DMA_TAG_ID = 31, - CELL_SPURS_KERNEL1_ENTRY_ADDR = 0x818, - CELL_SPURS_KERNEL2_ENTRY_ADDR = 0x848, - CELL_SPURS_KERNEL1_EXIT_ADDR = 0x808, - CELL_SPURS_KERNEL2_EXIT_ADDR = 0x838, - CELL_SPURS_KERNEL1_SELECT_WORKLOAD_ADDR = 0x290, - CELL_SPURS_KERNEL2_SELECT_WORKLOAD_ADDR = 0x290, -}; - -enum RangeofEventQueuePortNumbers -{ - CELL_SPURS_STATIC_PORT_RANGE_BOTTOM = 15, - CELL_SPURS_DYNAMIC_PORT_RANGE_TOP = 16, - CELL_SPURS_DYNAMIC_PORT_RANGE_BOTTOM = 63, -}; - -enum SpursAttrFlags : u32 -{ - SAF_NONE = 0x00000000, - SAF_EXIT_IF_NO_WORK = 0x00000001, - SAF_UNKNOWN_FLAG_30 = 0x00000002, - SAF_SECOND_VERSION = 0x00000004, - SAF_UNKNOWN_FLAG_9 = 0x00400000, - SAF_UNKNOWN_FLAG_8 = 0x00800000, - SAF_UNKNOWN_FLAG_7 = 0x01000000, - SAF_SYSTEM_WORKLOAD_ENABLED = 0x02000000, - SAF_SPU_PRINTF_ENABLED = 0x10000000, - SAF_SPU_TGT_EXCLUSIVE_NON_CONTEXT = 0x20000000, - SAF_SPU_MEMORY_CONTAINER_SET = 0x40000000, - SAF_UNKNOWN_FLAG_0 = 0x80000000, -}; - -enum SpursFlags1 : u8 -{ - SF1_NONE = 0x00, - SF1_32_WORKLOADS = 0x40, - SF1_EXIT_IF_NO_WORK = 0x80, -}; - -enum SpursWorkloadConstants : u32 -{ - // Workload states - SPURS_WKL_STATE_NON_EXISTENT = 0, - SPURS_WKL_STATE_PREPARING = 1, - SPURS_WKL_STATE_RUNNABLE = 2, - SPURS_WKL_STATE_SHUTTING_DOWN = 3, - SPURS_WKL_STATE_REMOVABLE = 4, - SPURS_WKL_STATE_INVALID = 5, - - // Image addresses - SPURS_IMG_ADDR_SYS_SRV_WORKLOAD = 0x100, - SPURS_IMG_ADDR_TASKSET_PM = 0x200, -}; - -enum SpursWorkloadGUIDs : u64 -{ - // GUID - SPURS_GUID_SYS_WKL = 0x1BB841BF38F89D33ull, - SPURS_GUID_TASKSET_PM = 0x836E915B2E654143ull, -}; - -enum CellSpursModulePollStatus -{ - CELL_SPURS_MODULE_POLL_STATUS_READYCOUNT = 1, - CELL_SPURS_MODULE_POLL_STATUS_SIGNAL = 2, - CELL_SPURS_MODULE_POLL_STATUS_FLAG = 4 -}; - -enum SpursTraceConstants -{ - // Trace tag types - CELL_SPURS_TRACE_TAG_KERNEL = 0x20, - CELL_SPURS_TRACE_TAG_SERVICE = 0x21, - CELL_SPURS_TRACE_TAG_TASK = 0x22, - CELL_SPURS_TRACE_TAG_JOB = 0x23, - CELL_SPURS_TRACE_TAG_OVIS = 0x24, - CELL_SPURS_TRACE_TAG_LOAD = 0x2a, - CELL_SPURS_TRACE_TAG_MAP = 0x2b, - CELL_SPURS_TRACE_TAG_START = 0x2c, - CELL_SPURS_TRACE_TAG_STOP = 0x2d, - CELL_SPURS_TRACE_TAG_USER = 0x2e, - CELL_SPURS_TRACE_TAG_GUID = 0x2f, - - // Service incident - CELL_SPURS_TRACE_SERVICE_INIT = 0x01, - CELL_SPURS_TRACE_SERVICE_WAIT = 0x02, - CELL_SPURS_TRACE_SERVICE_EXIT = 0x03, - - // Task incident - CELL_SPURS_TRACE_TASK_DISPATCH = 0x01, - CELL_SPURS_TRACE_TASK_YIELD = 0x03, - CELL_SPURS_TRACE_TASK_WAIT = 0x04, - CELL_SPURS_TRACE_TASK_EXIT = 0x05, - - // Trace mode flags - CELL_SPURS_TRACE_MODE_FLAG_WRAP_BUFFER = 0x1, - CELL_SPURS_TRACE_MODE_FLAG_SYNCHRONOUS_START_STOP = 0x2, - CELL_SPURS_TRACE_MODE_FLAG_MASK = 0x3, -}; - -// SPURS task constants -enum SpursTaskConstants -{ - CELL_SPURS_MAX_TASK = 128, - CELL_SPURS_TASK_TOP = 0x3000, - CELL_SPURS_TASK_BOTTOM = 0x40000, - CELL_SPURS_MAX_TASK_NAME_LENGTH = 32, - CELL_SPURS_TASK_ATTRIBUTE_REVISION = 1, - CELL_SPURS_TASKSET_ATTRIBUTE_REVISION = 1, - CELL_SPURS_TASK_EXECUTION_CONTEXT_SIZE = 1024, - CELL_SPURS_TASKSET_PM_ENTRY_ADDR = 0xA00, - CELL_SPURS_TASKSET_PM_SYSCALL_ADDR = 0xA70, - - // Task syscall numbers - CELL_SPURS_TASK_SYSCALL_EXIT = 0, - CELL_SPURS_TASK_SYSCALL_YIELD = 1, - CELL_SPURS_TASK_SYSCALL_WAIT_SIGNAL = 2, - CELL_SPURS_TASK_SYSCALL_POLL = 3, - CELL_SPURS_TASK_SYSCALL_RECV_WKL_FLAG = 4, - - // Task poll status - CELL_SPURS_TASK_POLL_FOUND_TASK = 1, - CELL_SPURS_TASK_POLL_FOUND_WORKLOAD = 2, -}; - -enum CellSpursEventFlagWaitMode -{ - CELL_SPURS_EVENT_FLAG_OR = 0, - CELL_SPURS_EVENT_FLAG_AND = 1, - CELL_SPURS_EVENT_FLAG_WAIT_MODE_LAST = CELL_SPURS_EVENT_FLAG_AND, -}; - -enum CellSpursEventFlagClearMode -{ - CELL_SPURS_EVENT_FLAG_CLEAR_AUTO = 0, - CELL_SPURS_EVENT_FLAG_CLEAR_MANUAL = 1, - CELL_SPURS_EVENT_FLAG_CLEAR_LAST = CELL_SPURS_EVENT_FLAG_CLEAR_MANUAL, -}; - -enum CellSpursEventFlagDirection -{ - CELL_SPURS_EVENT_FLAG_SPU2SPU, - CELL_SPURS_EVENT_FLAG_SPU2PPU, - CELL_SPURS_EVENT_FLAG_PPU2SPU, - CELL_SPURS_EVENT_FLAG_ANY2ANY, - CELL_SPURS_EVENT_FLAG_LAST = CELL_SPURS_EVENT_FLAG_ANY2ANY, -}; - -// Event flag constants -enum SpursEventFlagConstants -{ - CELL_SPURS_EVENT_FLAG_MAX_WAIT_SLOTS = 16, - CELL_SPURS_EVENT_FLAG_INVALID_SPU_PORT = 0xFF, -}; - -struct alignas(16) CellSpursWorkloadFlag -{ - be_t unused0; - be_t unused1; - atomic_be_t flag; -}; - -CHECK_SIZE_ALIGN(CellSpursWorkloadFlag, 16, 16); - -struct CellSpursInfo -{ - be_t nSpus; - be_t spuThreadGroupPriority; - be_t ppuThreadPriority; - bool exitIfNoWork; - bool spurs2; - u8 padding24[2]; - vm::bptr traceBuffer; - be_t padding32; - be_t traceBufferSize; - be_t traceMode; - be_t spuThreadGroup; - be_t spuThreads[8]; - be_t spursHandlerThread0; - be_t spursHandlerThread1; - char namePrefix[16]; - be_t namePrefixLength; - be_t deadlineMissCounter; - be_t deadlineMeetCounter; - u8 padding[164]; -}; - -CHECK_SIZE(CellSpursInfo, 280); - -struct alignas(8) CellSpursAttribute -{ - be_t revision; // 0x0 - be_t sdkVersion; // 0x4 - be_t nSpus; // 0x8 - be_t spuPriority; // 0xC - be_t ppuPriority; // 0x10 - bool exitIfNoWork; // 0x14 - char prefix[15]; // 0x15 (not a NTS) - be_t prefixSize; // 0x24 - be_t flags; // 0x28 (SpursAttrFlags) - be_t container; // 0x2C - be_t unk0; // 0x30 - be_t unk1; // 0x34 - u8 swlPriority[8]; // 0x38 - be_t swlMaxSpu; // 0x40 - be_t swlIsPreem; // 0x44 - u8 padding[440]; -}; - -CHECK_SIZE_ALIGN(CellSpursAttribute, 512, 8); - -using CellSpursShutdownCompletionEventHook = void(vm::ptr spurs, u32 wid, vm::ptr arg); - -struct alignas(16) CellSpursTraceInfo -{ - be_t spuThread[8]; // 0x00 - be_t count[8]; // 0x20 - be_t spuThreadGroup; // 0x40 - be_t numSpus; // 0x44 - u8 padding[56]; -}; - -CHECK_SIZE_ALIGN(CellSpursTraceInfo, 128, 16); - -struct CellSpursTraceHeader -{ - u8 tag; - u8 length; - u8 spu; - u8 workload; - be_t time; -}; - -struct CellSpursTraceControlData -{ - be_t incident; - be_t reserved; -}; - -struct CellSpursTraceServiceData -{ - be_t incident; - be_t reserved; -}; - -struct CellSpursTraceTaskData -{ - be_t incident; - be_t taskId; -}; - -struct CellSpursTraceJobData -{ - u8 reserved[3]; - u8 binLSAhigh8; - be_t jobDescriptor; -}; - -struct CellSpursTraceLoadData -{ - be_t ea; - be_t ls; - be_t size; -}; - -struct CellSpursTraceMapData -{ - be_t offset; - be_t ls; - be_t size; -}; - -struct CellSpursTraceStartData -{ - char module[4]; - be_t level; - be_t ls; -}; - -struct alignas(16) CellSpursTracePacket -{ - CellSpursTraceHeader header; - - union - { - CellSpursTraceControlData control; - CellSpursTraceServiceData service; - CellSpursTraceTaskData task; - CellSpursTraceJobData job; - - CellSpursTraceLoadData load; - CellSpursTraceMapData map; - CellSpursTraceStartData start; - - be_t stop; - be_t user; - be_t guid; - be_t raw; - } - data; -}; - -CHECK_SIZE_ALIGN(CellSpursTracePacket, 16, 16); - -// Core CellSpurs structures -struct alignas(128) CellSpurs -{ - struct _sub_str1 - { - u8 unk0[0x20]; // 0x00 - SPU exception handler 0x08 - SPU exception handler args - be_t sem; // 0x20 - be_t x28; // 0x28 - be_t x2C; // 0x2C - vm::bptr hook; // 0x30 - vm::bptr hookArg; // 0x38 - u8 unk2[0x40]; - }; - - CHECK_SIZE(_sub_str1, 128); - - struct EventPortMux; - - using EventHandlerCallback = void(vm::ptr, u64 data); - - struct EventHandlerListNode - { - vm::bptr next; - be_t data; - vm::bptr handler; - }; - - struct EventPortMux - { - atomic_be_t reqPending; // 0x00 - be_t spuPort; // 0x04 - be_t x08; // 0x08 - be_t x0C; // 0x0C - be_t eventPort; // 0x10 - atomic_t> handlerList; // 0x18 - u8 x20[0x80 - 0x20]; // 0x20 - }; - - CHECK_SIZE(EventPortMux, 128); - - struct WorkloadInfo - { - vm::bcptr addr; // 0x00 Address of the executable - be_t arg; // 0x08 Argument - be_t size; // 0x10 Size of the executable - atomic_t uniqueId; // 0x14 Unique id of the workload. It is the same for all workloads with the same addr. - u8 pad[3]; - u8 priority[8]; // 0x18 Priority of the workload on each SPU - }; - - CHECK_SIZE(WorkloadInfo, 32); - - struct _sub_str4 - { - vm::bcptr nameClass; - vm::bcptr nameInstance; - }; - - atomic_t wklReadyCount1[0x10]; // 0x00 Number of SPUs requested by each workload (0..15 wids). - atomic_t wklIdleSpuCountOrReadyCount2[0x10]; // 0x10 SPURS1: Number of idle SPUs requested by each workload (0..15 wids). SPURS2: Number of SPUs requested by each workload (16..31 wids). - u8 wklCurrentContention[0x10]; // 0x20 Number of SPUs used by each workload. SPURS1: index = wid. SPURS2: packed 4-bit data, index = wid % 16, internal index = wid / 16. - u8 wklPendingContention[0x10]; // 0x30 Number of SPUs that are pending to context switch to the workload. SPURS1: index = wid. SPURS2: packed 4-bit data, index = wid % 16, internal index = wid / 16. - u8 wklMinContention[0x10]; // 0x40 Min SPUs required for each workload. SPURS1: index = wid. SPURS2: Unused. - atomic_t wklMaxContention[0x10]; // 0x50 Max SPUs that may be allocated to each workload. SPURS1: index = wid. SPURS2: packed 4-bit data, index = wid % 16, internal index = wid / 16. - CellSpursWorkloadFlag wklFlag; // 0x60 - atomic_be_t wklSignal1; // 0x70 Bitset for 0..15 wids - atomic_t sysSrvMessage; // 0x72 - u8 spuIdling; // 0x73 - u8 flags1; // 0x74 Type is SpursFlags1 - u8 sysSrvTraceControl; // 0x75 - u8 nSpus; // 0x76 - atomic_t wklFlagReceiver; // 0x77 - atomic_be_t wklSignal2; // 0x78 Bitset for 16..32 wids - u8 x7A[6]; // 0x7A - atomic_t wklState1[0x10]; // 0x80 SPURS_WKL_STATE_* - u8 wklStatus1[0x10]; // 0x90 - atomic_t wklEvent1[0x10]; // 0xA0 - atomic_be_t wklEnabled; // 0xB0 - atomic_be_t wklMskB; // 0xB4 - System service - Available module id - u32 xB8; // 0xB8 - u8 sysSrvExitBarrier; // 0xBC - atomic_t sysSrvMsgUpdateWorkload; // 0xBD - u8 xBE; // 0xBE - u8 sysSrvMsgTerminate; // 0xBF - u8 sysSrvPreemptWklId[8]; // 0xC0 Id of the workload that was preempted by the system workload on each SPU - u8 sysSrvOnSpu; // 0xC8 - u8 spuPort; // 0xC9 - u8 xCA; // 0xCA - u8 xCB; // 0xCB - - struct SrvTraceSyncVar - { - u8 sysSrvTraceInitialised; // 0xCC - u8 sysSrvNotifyUpdateTraceComplete; // 0xCD - u8 sysSrvMsgUpdateTrace; // 0xCE - u8 xCF; - }; - - atomic_t sysSrvTrace; // 0xCC - - atomic_t wklState2[0x10]; // 0xD0 SPURS_WKL_STATE_* - u8 wklStatus2[0x10]; // 0xE0 - atomic_t wklEvent2[0x10]; // 0xF0 - _sub_str1 wklF1[0x10]; // 0x100 - vm::bptr traceBuffer; // 0x900 - be_t traceStartIndex[6]; // 0x908 - u8 unknown7[0x948 - 0x920]; // 0x920 - be_t traceDataSize; // 0x948 - be_t traceMode; // 0x950 - u8 unknown8[0x980 - 0x954]; // 0x954 - be_t semPrv; // 0x980 - be_t unk11; // 0x988 - be_t unk12; // 0x98C - be_t unk13; // 0x990 - u8 unknown4[0xB00 - 0x998]; - WorkloadInfo wklInfo1[0x10]; // 0xB00 - WorkloadInfo wklInfoSysSrv; // 0xD00 - be_t ppu0; // 0xD20 Handler thread - be_t ppu1; // 0xD28 - be_t spuTG; // 0xD30 SPU thread group - be_t spus[8]; // 0xD34 - u8 unknown3[0xD5C - 0xD54]; - be_t eventQueue; // 0xD5C - be_t eventPort; // 0xD60 - atomic_t handlerDirty; // 0xD64 - atomic_t handlerWaiting; // 0xD65 - atomic_t handlerExiting; // 0xD66 - atomic_be_t enableEH; // 0xD68 - be_t exception; // 0xD6C - sys_spu_image spuImg; // 0xD70 - be_t flags; // 0xD80 - be_t spuPriority; // 0xD84 - be_t ppuPriority; // 0xD88 - char prefix[0x0f]; // 0xD8C - u8 prefixSize; // 0xD9B - be_t unk5; // 0xD9C - be_t revision; // 0xDA0 - be_t sdkVersion; // 0xDA4 - atomic_be_t spuPortBits; // 0xDA8 - sys_lwmutex_t mutex; // 0xDB0 - sys_lwcond_t cond; // 0xDC8 - u8 unknown9[0xE00 - 0xDD0]; - _sub_str4 wklH1[0x10]; // 0xE00 - EventPortMux eventPortMux; // 0xF00 - atomic_be_t globalSpuExceptionHandler; // 0xF80 - be_t globalSpuExceptionHandlerArgs; // 0xF88 - u8 unknown6[0x1000 - 0xF90]; - WorkloadInfo wklInfo2[0x10]; // 0x1000 - _sub_str1 wklF2[0x10]; // 0x1200 - _sub_str4 wklH2[0x10]; // 0x1A00 - u8 unknown_[0x2000 - 0x1B00]; - - force_inline atomic_t& wklState(const u32 wid) - { - if (wid & 0x10) - { - return wklState2[wid & 0xf]; - } - else - { - return wklState1[wid & 0xf]; - } - } -}; - -CHECK_SIZE_ALIGN(CellSpurs, 0x2000, 128); - -using CellSpurs2 = CellSpurs; - -struct CellSpursExceptionInfo -{ - be_t spu_thread; - be_t spu_npc; - be_t cause; - be_t option; -}; - -// Exception handler -using CellSpursGlobalExceptionEventHandler = void(vm::ptr spurs, vm::cptr info, u32 id, vm::ptr arg); - -struct CellSpursWorkloadAttribute -{ - be_t revision; - be_t sdkVersion; - vm::bcptr pm; - be_t size; - be_t data; - u8 priority[8]; - be_t minContention; - be_t maxContention; - vm::bcptr nameClass; - vm::bcptr nameInstance; - vm::bptr hook; - vm::bptr hookArg; - u8 padding[456]; -}; - -CHECK_SIZE_ALIGN(CellSpursWorkloadAttribute, 512, 8); - -struct alignas(128) CellSpursEventFlag -{ - struct ControlSyncVar - { - be_t events; // 0x00 Event bits - be_t spuTaskPendingRecv; // 0x02 A bit is set to 1 when the condition of the SPU task using the slot are met and back to 0 when the SPU task unblocks - be_t ppuWaitMask; // 0x04 Wait mask for blocked PPU thread - u8 ppuWaitSlotAndMode; // 0x06 Top 4 bits: Wait slot number of the blocked PPU threa, Bottom 4 bits: Wait mode of the blocked PPU thread - u8 ppuPendingRecv; // 0x07 Set to 1 when the blocked PPU thread's conditions are met and back to 0 when the PPU thread is unblocked - }; - - union - { - atomic_t ctrl; // 0x00 - atomic_be_t events; // 0x00 - }; - - be_t spuTaskUsedWaitSlots; // 0x08 A bit is set to 1 if the wait slot corresponding to the bit is used by an SPU task and 0 otherwise - be_t spuTaskWaitMode; // 0x0A A bit is set to 1 if the wait mode for the SPU task corresponding to the bit is AND and 0 otherwise - u8 spuPort; // 0x0C - u8 isIwl; // 0x0D - u8 direction; // 0x0E - u8 clearMode; // 0x0F - be_t spuTaskWaitMask[16]; // 0x10 Wait mask for blocked SPU tasks - be_t pendingRecvTaskEvents[16]; // 0x30 The value of event flag when the wait condition for the thread/task was met - u8 waitingTaskId[16]; // 0x50 Task id of waiting SPU threads - u8 waitingTaskWklId[16]; // 0x60 Workload id of waiting SPU threads - be_t addr; // 0x70 - be_t eventPortId; // 0x78 - be_t eventQueueId; // 0x7C -}; - -CHECK_SIZE_ALIGN(CellSpursEventFlag, 128, 128); - -using CellSpursLFQueue = CellSyncLFQueue; - -union CellSpursTaskArgument -{ - be_t _u32[4]; - be_t _u64[2]; -}; - -union CellSpursTaskLsPattern -{ - be_t _u32[4]; - be_t _u64[2]; -}; - -struct alignas(16) CellSpursTaskAttribute -{ - u8 reserved[256]; -}; - -CHECK_SIZE_ALIGN(CellSpursTaskAttribute, 256, 16); - -struct alignas(16) CellSpursTaskAttribute2 -{ - be_t revision; - be_t sizeContext; - be_t eaContext; - CellSpursTaskLsPattern lsPattern; - vm::bcptr name; - - u8 reserved[220]; -}; - -CHECK_SIZE_ALIGN(CellSpursTaskAttribute2, 256, 16); - -// Exception handler -using CellSpursTasksetExceptionEventHandler = void(vm::ptr spurs, vm::ptr taskset, u32 idTask, vm::cptr info, vm::ptr arg); - -struct alignas(128) CellSpursTaskExitCode -{ - u8 skip[128]; -}; - -CHECK_SIZE_ALIGN(CellSpursTaskExitCode, 128, 128); - -struct CellSpursTaskInfo -{ - CellSpursTaskLsPattern lsPattern; - CellSpursTaskArgument argument; - vm::bptr eaElf; - vm::bptr eaContext; - be_t sizeContext; - u8 state; - u8 hasSignal; - u8 padding[2]; - vm::bcptr eaTaskExitCode; - u8 guid[8]; - u8 reserved[12]; -}; - -CHECK_SIZE(CellSpursTaskInfo, 72); - -struct CellSpursTasksetInfo -{ - CellSpursTaskInfo taskInfo[CELL_SPURS_MAX_TASK]; - be_t argument; - be_t idWorkload; - be_t idLastScheduledTask; - vm::bcptr name; - vm::bptr exceptionEventHandler; - vm::bptr exceptionEventHandlerArgument; - be_t sizeTaskset; - u8 reserved[112]; -}; - -CHECK_SIZE(CellSpursTasksetInfo, 9360); - -struct alignas(8) CellSpursTasksetAttribute -{ - be_t revision; // 0x00 - be_t sdk_version; // 0x04 - be_t args; // 0x08 - u8 priority[8]; // 0x10 - be_t max_contention; // 0x18 - vm::bcptr name; // 0x1C - be_t taskset_size; // 0x20 - be_t enable_clear_ls; // 0x24 - u8 reserved[472]; -}; - -CHECK_SIZE_ALIGN(CellSpursTasksetAttribute, 512, 8); - -struct alignas(128) CellSpursTaskset -{ - struct TaskInfo - { - CellSpursTaskArgument args; // 0x00 - vm::bcptr elf; // 0x10 - be_t context_save_storage_and_alloc_ls_blocks; // 0x18 This is (context_save_storage_addr | allocated_ls_blocks) - CellSpursTaskLsPattern ls_pattern; // 0x20 - }; - - CHECK_SIZE(TaskInfo, 48); - - be_t running; // 0x00 - be_t ready; // 0x10 - be_t pending_ready; // 0x20 - be_t enabled; // 0x30 - be_t signalled; // 0x40 - be_t waiting; // 0x50 - vm::bptr spurs; // 0x60 - be_t args; // 0x68 - u8 enable_clear_ls; // 0x70 - u8 x71; // 0x71 - u8 wkl_flag_wait_task; // 0x72 - u8 last_scheduled_task; // 0x73 - be_t wid; // 0x74 - be_t x78; // 0x78 - TaskInfo task_info[128]; // 0x80 - vm::bptr exception_handler; // 0x1880 - vm::bptr exception_handler_arg; // 0x1888 - be_t size; // 0x1890 - u32 unk2; // 0x1894 - u32 event_flag_id1; // 0x1898 - u32 event_flag_id2; // 0x189C - u8 unk3[0x60]; // 0x18A0 -}; - -CHECK_SIZE_ALIGN(CellSpursTaskset, 128 * 50, 128); - -struct alignas(128) CellSpursTaskset2 -{ - struct TaskInfo - { - CellSpursTaskArgument args; - vm::bptr elf_addr; - vm::bptr context_save_storage; // This is (context_save_storage_addr | allocated_ls_blocks) - CellSpursTaskLsPattern ls_pattern; - }; - - CHECK_SIZE(TaskInfo, 48); - - be_t running_set[4]; // 0x00 - be_t ready_set[4]; // 0x10 - be_t ready2_set[4]; // 0x20 - TODO: Find out what this is - be_t enabled_set[4]; // 0x30 - be_t signal_received_set[4]; // 0x40 - be_t waiting_set[4]; // 0x50 - vm::bptr spurs; // 0x60 - be_t args; // 0x68 - u8 enable_clear_ls; // 0x70 - u8 x71; // 0x71 - u8 x72; // 0x72 - u8 last_scheduled_task; // 0x73 - be_t wid; // 0x74 - be_t x78; // 0x78 - TaskInfo task_info[128]; // 0x80 - vm::bptr exception_handler; // 0x1880 - vm::bptr exception_handler_arg; // 0x1888 - be_t size; // 0x1890 - u32 unk2; // 0x1894 - u32 event_flag_id1; // 0x1898 - u32 event_flag_id2; // 0x189C - u8 unk3[0x1980 - 0x18A0]; // 0x18A0 - be_t task_exit_code[128]; // 0x1980 - u8 unk4[0x2900 - 0x2180]; // 0x2180 -}; - -CHECK_SIZE_ALIGN(CellSpursTaskset2, 128 * 82, 128); - -struct alignas(16) CellSpursTaskNameBuffer -{ - char taskName[CELL_SPURS_MAX_TASK][CELL_SPURS_MAX_TASK_NAME_LENGTH]; -}; - -struct alignas(8) CellSpursTasksetAttribute2 -{ - be_t revision; // 0x00 - vm::bcptr name; // 0x04 - be_t args; // 0x08 - u8 priority[8]; // 0x10 - be_t max_contention; // 0x18 - be_t enable_clear_ls; // 0x1C - vm::bptr task_name_buffer; // 0x20 - u8 reserved[472]; -}; - -CHECK_SIZE_ALIGN(CellSpursTasksetAttribute2, 512, 8); - -struct alignas(16) CellSpursTaskBinInfo -{ - be_t eaElf; - be_t sizeContext; - be_t reserved; - CellSpursTaskLsPattern lsPattern; -}; - -// The SPURS kernel context. This resides at 0x100 of the LS. -struct SpursKernelContext -{ - u8 tempArea[0x80]; // 0x100 - u8 wklLocContention[0x10]; // 0x180 - u8 wklLocPendingContention[0x10]; // 0x190 - u8 priority[0x10]; // 0x1A0 - u8 x1B0[0x10]; // 0x1B0 - vm::bptr spurs; // 0x1C0 - be_t spuNum; // 0x1C8 - be_t dmaTagId; // 0x1CC - vm::bcptr wklCurrentAddr; // 0x1D0 - be_t wklCurrentUniqueId; // 0x1D8 - be_t wklCurrentId; // 0x1DC - be_t exitToKernelAddr; // 0x1E0 - be_t selectWorkloadAddr; // 0x1E4 - u8 moduleId[2]; // 0x1E8 - u8 sysSrvInitialised; // 0x1EA - u8 spuIdling; // 0x1EB - be_t wklRunnable1; // 0x1EC - be_t wklRunnable2; // 0x1EE - be_t x1F0; // 0x1F0 - be_t x1F4; // 0x1F4 - be_t x1F8; // 0x1F8 - be_t x1FC; // 0x1FC - be_t x200; // 0x200 - be_t x204; // 0x204 - be_t x208; // 0x208 - be_t x20C; // 0x20C - be_t traceBuffer; // 0x210 - be_t traceMsgCount; // 0x218 - be_t traceMaxCount; // 0x21C - u8 wklUniqueId[0x10]; // 0x220 - u8 x230[0x280 - 0x230]; // 0x230 - be_t guid[4]; // 0x280 -}; - -CHECK_SIZE(SpursKernelContext, 0x190); - -// The SPURS taskset policy module context. This resides at 0x2700 of the LS. -struct SpursTasksetContext -{ - u8 tempAreaTaskset[0x80]; // 0x2700 - u8 tempAreaTaskInfo[0x30]; // 0x2780 - be_t x27B0; // 0x27B0 - vm::bptr taskset; // 0x27B8 - be_t kernelMgmtAddr; // 0x27C0 - be_t syscallAddr; // 0x27C4 - be_t x27C8; // 0x27C8 - be_t spuNum; // 0x27CC - be_t dmaTagId; // 0x27D0 - be_t taskId; // 0x27D4 - u8 x27D8[0x2840 - 0x27D8]; // 0x27D8 - u8 moduleId[16]; // 0x2840 - u8 stackArea[0x2C80 - 0x2850]; // 0x2850 - be_t savedContextLr; // 0x2C80 - be_t savedContextSp; // 0x2C90 - be_t savedContextR80ToR127[48]; // 0x2CA0 - be_t savedContextFpscr; // 0x2FA0 - be_t savedWriteTagGroupQueryMask; // 0x2FB0 - be_t savedSpuWriteEventMask; // 0x2FB4 - be_t tasksetMgmtAddr; // 0x2FB8 - be_t guidAddr; // 0x2FBC - be_t x2FC0; // 0x2FC0 - be_t x2FC8; // 0x2FC8 - be_t taskExitCode; // 0x2FD0 - be_t x2FD4; // 0x2FD4 - u8 x2FD8[0x3000 - 0x2FD8]; // 0x2FD8 -}; - -CHECK_SIZE(SpursTasksetContext, 0x900); - -class SpursModuleExit -{ -}; - -inline static s32 SyncErrorToSpursError(s32 res) -{ - return res < 0 ? 0x80410900 | (res & 0xff) : res; -} +#pragma once + +#include "cellSync.h" + +namespace vm { using namespace ps3; } + +struct CellSpurs; +struct CellSpursTaskset; + +// Core return codes. +enum +{ + CELL_SPURS_CORE_ERROR_AGAIN = 0x80410701, + CELL_SPURS_CORE_ERROR_INVAL = 0x80410702, + CELL_SPURS_CORE_ERROR_NOMEM = 0x80410704, + CELL_SPURS_CORE_ERROR_SRCH = 0x80410705, + CELL_SPURS_CORE_ERROR_PERM = 0x80410709, + CELL_SPURS_CORE_ERROR_BUSY = 0x8041070A, + CELL_SPURS_CORE_ERROR_STAT = 0x8041070F, + CELL_SPURS_CORE_ERROR_ALIGN = 0x80410710, + CELL_SPURS_CORE_ERROR_NULL_POINTER = 0x80410711, +}; + +// +enum +{ + CELL_SPURS_POLICY_MODULE_ERROR_AGAIN = 0x80410801, + CELL_SPURS_POLICY_MODULE_ERROR_INVAL = 0x80410802, + CELL_SPURS_POLICY_MODULE_ERROR_NOSYS = 0x80410803, + CELL_SPURS_POLICY_MODULE_ERROR_NOMEM = 0x80410804, + CELL_SPURS_POLICY_MODULE_ERROR_SRCH = 0x80410805, + CELL_SPURS_POLICY_MODULE_ERROR_NOENT = 0x80410806, + CELL_SPURS_POLICY_MODULE_ERROR_NOEXEC = 0x80410807, + CELL_SPURS_POLICY_MODULE_ERROR_DEADLK = 0x80410808, + CELL_SPURS_POLICY_MODULE_ERROR_PERM = 0x80410809, + CELL_SPURS_POLICY_MODULE_ERROR_BUSY = 0x8041080A, + CELL_SPURS_POLICY_MODULE_ERROR_ABORT = 0x8041080C, + CELL_SPURS_POLICY_MODULE_ERROR_FAULT = 0x8041080D, + CELL_SPURS_POLICY_MODULE_ERROR_CHILD = 0x8041080E, + CELL_SPURS_POLICY_MODULE_ERROR_STAT = 0x8041080F, + CELL_SPURS_POLICY_MODULE_ERROR_ALIGN = 0x80410810, + CELL_SPURS_POLICY_MODULE_ERROR_NULL_POINTER = 0x80410811, +}; + +// Task return codes. +enum +{ + CELL_SPURS_TASK_ERROR_AGAIN = 0x80410901, + CELL_SPURS_TASK_ERROR_INVAL = 0x80410902, + CELL_SPURS_TASK_ERROR_NOSYS = 0x80410903, + CELL_SPURS_TASK_ERROR_NOMEM = 0x80410904, + CELL_SPURS_TASK_ERROR_SRCH = 0x80410905, + CELL_SPURS_TASK_ERROR_NOEXEC = 0x80410907, + CELL_SPURS_TASK_ERROR_PERM = 0x80410909, + CELL_SPURS_TASK_ERROR_BUSY = 0x8041090A, + CELL_SPURS_TASK_ERROR_FAULT = 0x8041090D, + CELL_SPURS_TASK_ERROR_ALIGN = 0x80410910, + CELL_SPURS_TASK_ERROR_STAT = 0x8041090F, + CELL_SPURS_TASK_ERROR_NULL_POINTER = 0x80410911, + CELL_SPURS_TASK_ERROR_FATAL = 0x80410914, + CELL_SPURS_TASK_ERROR_SHUTDOWN = 0x80410920, +}; + +enum +{ + CELL_SPURS_JOB_ERROR_AGAIN = 0x80410A01, + CELL_SPURS_JOB_ERROR_INVAL = 0x80410A02, + CELL_SPURS_JOB_ERROR_NOSYS = 0x80410A03, + CELL_SPURS_JOB_ERROR_NOMEM = 0x80410A04, + CELL_SPURS_JOB_ERROR_SRCH = 0x80410A05, + CELL_SPURS_JOB_ERROR_NOENT = 0x80410A06, + CELL_SPURS_JOB_ERROR_NOEXEC = 0x80410A07, + CELL_SPURS_JOB_ERROR_DEADLK = 0x80410A08, + CELL_SPURS_JOB_ERROR_PERM = 0x80410A09, + CELL_SPURS_JOB_ERROR_BUSY = 0x80410A0A, + CELL_SPURS_JOB_ERROR_JOB_DESCRIPTOR = 0x80410A0B, + CELL_SPURS_JOB_ERROR_JOB_DESCRIPTOR_SIZE = 0x80410A0C, + CELL_SPURS_JOB_ERROR_FAULT = 0x80410A0D, + CELL_SPURS_JOB_ERROR_CHILD = 0x80410A0E, + CELL_SPURS_JOB_ERROR_STAT = 0x80410A0F, + CELL_SPURS_JOB_ERROR_ALIGN = 0x80410A10, + CELL_SPURS_JOB_ERROR_NULL_POINTER = 0x80410A11, + CELL_SPURS_JOB_ERROR_MEMORY_CORRUPTED = 0x80410A12, + + CELL_SPURS_JOB_ERROR_MEMORY_SIZE = 0x80410A17, + CELL_SPURS_JOB_ERROR_UNKNOWN_COMMAND = 0x80410A18, + CELL_SPURS_JOB_ERROR_JOBLIST_ALIGNMENT = 0x80410A19, + CELL_SPURS_JOB_ERROR_JOB_ALIGNMENT = 0x80410A1a, + CELL_SPURS_JOB_ERROR_CALL_OVERFLOW = 0x80410A1b, + CELL_SPURS_JOB_ERROR_ABORT = 0x80410A1c, + CELL_SPURS_JOB_ERROR_DMALIST_ELEMENT = 0x80410A1d, + CELL_SPURS_JOB_ERROR_NUM_CACHE = 0x80410A1e, + CELL_SPURS_JOB_ERROR_INVALID_BINARY = 0x80410A1f, +}; + +// SPURS defines. +enum SPURSKernelInterfaces : u32 +{ + CELL_SPURS_MAX_SPU = 8, + CELL_SPURS_MAX_WORKLOAD = 16, + CELL_SPURS_MAX_WORKLOAD2 = 32, + CELL_SPURS_SYS_SERVICE_WORKLOAD_ID = 32, + CELL_SPURS_MAX_PRIORITY = 16, + CELL_SPURS_NAME_MAX_LENGTH = 15, + CELL_SPURS_SIZE = 4096, + CELL_SPURS_SIZE2 = 8192, + CELL_SPURS_INTERRUPT_VECTOR = 0x0, + CELL_SPURS_LOCK_LINE = 0x80, + CELL_SPURS_KERNEL_DMA_TAG_ID = 31, + CELL_SPURS_KERNEL1_ENTRY_ADDR = 0x818, + CELL_SPURS_KERNEL2_ENTRY_ADDR = 0x848, + CELL_SPURS_KERNEL1_EXIT_ADDR = 0x808, + CELL_SPURS_KERNEL2_EXIT_ADDR = 0x838, + CELL_SPURS_KERNEL1_SELECT_WORKLOAD_ADDR = 0x290, + CELL_SPURS_KERNEL2_SELECT_WORKLOAD_ADDR = 0x290, +}; + +enum RangeofEventQueuePortNumbers +{ + CELL_SPURS_STATIC_PORT_RANGE_BOTTOM = 15, + CELL_SPURS_DYNAMIC_PORT_RANGE_TOP = 16, + CELL_SPURS_DYNAMIC_PORT_RANGE_BOTTOM = 63, +}; + +enum SpursAttrFlags : u32 +{ + SAF_NONE = 0x00000000, + SAF_EXIT_IF_NO_WORK = 0x00000001, + SAF_UNKNOWN_FLAG_30 = 0x00000002, + SAF_SECOND_VERSION = 0x00000004, + SAF_UNKNOWN_FLAG_9 = 0x00400000, + SAF_UNKNOWN_FLAG_8 = 0x00800000, + SAF_UNKNOWN_FLAG_7 = 0x01000000, + SAF_SYSTEM_WORKLOAD_ENABLED = 0x02000000, + SAF_SPU_PRINTF_ENABLED = 0x10000000, + SAF_SPU_TGT_EXCLUSIVE_NON_CONTEXT = 0x20000000, + SAF_SPU_MEMORY_CONTAINER_SET = 0x40000000, + SAF_UNKNOWN_FLAG_0 = 0x80000000, +}; + +enum SpursFlags1 : u8 +{ + SF1_NONE = 0x00, + SF1_32_WORKLOADS = 0x40, + SF1_EXIT_IF_NO_WORK = 0x80, +}; + +enum SpursWorkloadConstants : u32 +{ + // Workload states + SPURS_WKL_STATE_NON_EXISTENT = 0, + SPURS_WKL_STATE_PREPARING = 1, + SPURS_WKL_STATE_RUNNABLE = 2, + SPURS_WKL_STATE_SHUTTING_DOWN = 3, + SPURS_WKL_STATE_REMOVABLE = 4, + SPURS_WKL_STATE_INVALID = 5, + + // Image addresses + SPURS_IMG_ADDR_SYS_SRV_WORKLOAD = 0x100, + SPURS_IMG_ADDR_TASKSET_PM = 0x200, +}; + +enum SpursWorkloadGUIDs : u64 +{ + // GUID + SPURS_GUID_SYS_WKL = 0x1BB841BF38F89D33ull, + SPURS_GUID_TASKSET_PM = 0x836E915B2E654143ull, +}; + +enum CellSpursModulePollStatus +{ + CELL_SPURS_MODULE_POLL_STATUS_READYCOUNT = 1, + CELL_SPURS_MODULE_POLL_STATUS_SIGNAL = 2, + CELL_SPURS_MODULE_POLL_STATUS_FLAG = 4 +}; + +enum SpursTraceConstants +{ + // Trace tag types + CELL_SPURS_TRACE_TAG_KERNEL = 0x20, + CELL_SPURS_TRACE_TAG_SERVICE = 0x21, + CELL_SPURS_TRACE_TAG_TASK = 0x22, + CELL_SPURS_TRACE_TAG_JOB = 0x23, + CELL_SPURS_TRACE_TAG_OVIS = 0x24, + CELL_SPURS_TRACE_TAG_LOAD = 0x2a, + CELL_SPURS_TRACE_TAG_MAP = 0x2b, + CELL_SPURS_TRACE_TAG_START = 0x2c, + CELL_SPURS_TRACE_TAG_STOP = 0x2d, + CELL_SPURS_TRACE_TAG_USER = 0x2e, + CELL_SPURS_TRACE_TAG_GUID = 0x2f, + + // Service incident + CELL_SPURS_TRACE_SERVICE_INIT = 0x01, + CELL_SPURS_TRACE_SERVICE_WAIT = 0x02, + CELL_SPURS_TRACE_SERVICE_EXIT = 0x03, + + // Task incident + CELL_SPURS_TRACE_TASK_DISPATCH = 0x01, + CELL_SPURS_TRACE_TASK_YIELD = 0x03, + CELL_SPURS_TRACE_TASK_WAIT = 0x04, + CELL_SPURS_TRACE_TASK_EXIT = 0x05, + + // Trace mode flags + CELL_SPURS_TRACE_MODE_FLAG_WRAP_BUFFER = 0x1, + CELL_SPURS_TRACE_MODE_FLAG_SYNCHRONOUS_START_STOP = 0x2, + CELL_SPURS_TRACE_MODE_FLAG_MASK = 0x3, +}; + +// SPURS task constants +enum SpursTaskConstants +{ + CELL_SPURS_MAX_TASK = 128, + CELL_SPURS_TASK_TOP = 0x3000, + CELL_SPURS_TASK_BOTTOM = 0x40000, + CELL_SPURS_MAX_TASK_NAME_LENGTH = 32, + CELL_SPURS_TASK_ATTRIBUTE_REVISION = 1, + CELL_SPURS_TASKSET_ATTRIBUTE_REVISION = 1, + CELL_SPURS_TASK_EXECUTION_CONTEXT_SIZE = 1024, + CELL_SPURS_TASKSET_PM_ENTRY_ADDR = 0xA00, + CELL_SPURS_TASKSET_PM_SYSCALL_ADDR = 0xA70, + + // Task syscall numbers + CELL_SPURS_TASK_SYSCALL_EXIT = 0, + CELL_SPURS_TASK_SYSCALL_YIELD = 1, + CELL_SPURS_TASK_SYSCALL_WAIT_SIGNAL = 2, + CELL_SPURS_TASK_SYSCALL_POLL = 3, + CELL_SPURS_TASK_SYSCALL_RECV_WKL_FLAG = 4, + + // Task poll status + CELL_SPURS_TASK_POLL_FOUND_TASK = 1, + CELL_SPURS_TASK_POLL_FOUND_WORKLOAD = 2, +}; + +enum CellSpursEventFlagWaitMode +{ + CELL_SPURS_EVENT_FLAG_OR = 0, + CELL_SPURS_EVENT_FLAG_AND = 1, + CELL_SPURS_EVENT_FLAG_WAIT_MODE_LAST = CELL_SPURS_EVENT_FLAG_AND, +}; + +enum CellSpursEventFlagClearMode +{ + CELL_SPURS_EVENT_FLAG_CLEAR_AUTO = 0, + CELL_SPURS_EVENT_FLAG_CLEAR_MANUAL = 1, + CELL_SPURS_EVENT_FLAG_CLEAR_LAST = CELL_SPURS_EVENT_FLAG_CLEAR_MANUAL, +}; + +enum CellSpursEventFlagDirection +{ + CELL_SPURS_EVENT_FLAG_SPU2SPU, + CELL_SPURS_EVENT_FLAG_SPU2PPU, + CELL_SPURS_EVENT_FLAG_PPU2SPU, + CELL_SPURS_EVENT_FLAG_ANY2ANY, + CELL_SPURS_EVENT_FLAG_LAST = CELL_SPURS_EVENT_FLAG_ANY2ANY, +}; + +// Event flag constants +enum SpursEventFlagConstants +{ + CELL_SPURS_EVENT_FLAG_MAX_WAIT_SLOTS = 16, + CELL_SPURS_EVENT_FLAG_INVALID_SPU_PORT = 0xFF, +}; + +struct alignas(16) CellSpursWorkloadFlag +{ + be_t unused0; + be_t unused1; + atomic_be_t flag; +}; + +CHECK_SIZE_ALIGN(CellSpursWorkloadFlag, 16, 16); + +struct CellSpursInfo +{ + be_t nSpus; + be_t spuThreadGroupPriority; + be_t ppuThreadPriority; + bool exitIfNoWork; + bool spurs2; + u8 padding24[2]; + vm::bptr traceBuffer; + be_t padding32; + be_t traceBufferSize; + be_t traceMode; + be_t spuThreadGroup; + be_t spuThreads[8]; + be_t spursHandlerThread0; + be_t spursHandlerThread1; + char namePrefix[16]; + be_t namePrefixLength; + be_t deadlineMissCounter; + be_t deadlineMeetCounter; + u8 padding[164]; +}; + +CHECK_SIZE(CellSpursInfo, 280); + +struct alignas(8) CellSpursAttribute +{ + be_t revision; // 0x0 + be_t sdkVersion; // 0x4 + be_t nSpus; // 0x8 + be_t spuPriority; // 0xC + be_t ppuPriority; // 0x10 + bool exitIfNoWork; // 0x14 + char prefix[15]; // 0x15 (not a NTS) + be_t prefixSize; // 0x24 + be_t flags; // 0x28 (SpursAttrFlags) + be_t container; // 0x2C + be_t unk0; // 0x30 + be_t unk1; // 0x34 + u8 swlPriority[8]; // 0x38 + be_t swlMaxSpu; // 0x40 + be_t swlIsPreem; // 0x44 + u8 padding[440]; +}; + +CHECK_SIZE_ALIGN(CellSpursAttribute, 512, 8); + +using CellSpursShutdownCompletionEventHook = void(vm::ptr spurs, u32 wid, vm::ptr arg); + +struct alignas(16) CellSpursTraceInfo +{ + be_t spuThread[8]; // 0x00 + be_t count[8]; // 0x20 + be_t spuThreadGroup; // 0x40 + be_t numSpus; // 0x44 + u8 padding[56]; +}; + +CHECK_SIZE_ALIGN(CellSpursTraceInfo, 128, 16); + +struct CellSpursTraceHeader +{ + u8 tag; + u8 length; + u8 spu; + u8 workload; + be_t time; +}; + +struct CellSpursTraceControlData +{ + be_t incident; + be_t reserved; +}; + +struct CellSpursTraceServiceData +{ + be_t incident; + be_t reserved; +}; + +struct CellSpursTraceTaskData +{ + be_t incident; + be_t taskId; +}; + +struct CellSpursTraceJobData +{ + u8 reserved[3]; + u8 binLSAhigh8; + be_t jobDescriptor; +}; + +struct CellSpursTraceLoadData +{ + be_t ea; + be_t ls; + be_t size; +}; + +struct CellSpursTraceMapData +{ + be_t offset; + be_t ls; + be_t size; +}; + +struct CellSpursTraceStartData +{ + char module[4]; + be_t level; + be_t ls; +}; + +struct alignas(16) CellSpursTracePacket +{ + CellSpursTraceHeader header; + + union + { + CellSpursTraceControlData control; + CellSpursTraceServiceData service; + CellSpursTraceTaskData task; + CellSpursTraceJobData job; + + CellSpursTraceLoadData load; + CellSpursTraceMapData map; + CellSpursTraceStartData start; + + be_t stop; + be_t user; + be_t guid; + be_t raw; + } + data; +}; + +CHECK_SIZE_ALIGN(CellSpursTracePacket, 16, 16); + +// Core CellSpurs structures +struct alignas(128) CellSpurs +{ + struct _sub_str1 + { + u8 unk0[0x20]; // 0x00 - SPU exception handler 0x08 - SPU exception handler args + be_t sem; // 0x20 + be_t x28; // 0x28 + be_t x2C; // 0x2C + vm::bptr hook; // 0x30 + vm::bptr hookArg; // 0x38 + u8 unk2[0x40]; + }; + + CHECK_SIZE(_sub_str1, 128); + + struct EventPortMux; + + using EventHandlerCallback = void(vm::ptr, u64 data); + + struct EventHandlerListNode + { + vm::bptr next; + be_t data; + vm::bptr handler; + }; + + struct EventPortMux + { + atomic_be_t reqPending; // 0x00 + be_t spuPort; // 0x04 + be_t x08; // 0x08 + be_t x0C; // 0x0C + be_t eventPort; // 0x10 + atomic_t> handlerList; // 0x18 + u8 x20[0x80 - 0x20]; // 0x20 + }; + + CHECK_SIZE(EventPortMux, 128); + + struct WorkloadInfo + { + vm::bcptr addr; // 0x00 Address of the executable + be_t arg; // 0x08 Argument + be_t size; // 0x10 Size of the executable + atomic_t uniqueId; // 0x14 Unique id of the workload. It is the same for all workloads with the same addr. + u8 pad[3]; + u8 priority[8]; // 0x18 Priority of the workload on each SPU + }; + + CHECK_SIZE(WorkloadInfo, 32); + + struct _sub_str4 + { + vm::bcptr nameClass; + vm::bcptr nameInstance; + }; + + atomic_t wklReadyCount1[0x10]; // 0x00 Number of SPUs requested by each workload (0..15 wids). + atomic_t wklIdleSpuCountOrReadyCount2[0x10]; // 0x10 SPURS1: Number of idle SPUs requested by each workload (0..15 wids). SPURS2: Number of SPUs requested by each workload (16..31 wids). + u8 wklCurrentContention[0x10]; // 0x20 Number of SPUs used by each workload. SPURS1: index = wid. SPURS2: packed 4-bit data, index = wid % 16, internal index = wid / 16. + u8 wklPendingContention[0x10]; // 0x30 Number of SPUs that are pending to context switch to the workload. SPURS1: index = wid. SPURS2: packed 4-bit data, index = wid % 16, internal index = wid / 16. + u8 wklMinContention[0x10]; // 0x40 Min SPUs required for each workload. SPURS1: index = wid. SPURS2: Unused. + atomic_t wklMaxContention[0x10]; // 0x50 Max SPUs that may be allocated to each workload. SPURS1: index = wid. SPURS2: packed 4-bit data, index = wid % 16, internal index = wid / 16. + CellSpursWorkloadFlag wklFlag; // 0x60 + atomic_be_t wklSignal1; // 0x70 Bitset for 0..15 wids + atomic_t sysSrvMessage; // 0x72 + u8 spuIdling; // 0x73 + u8 flags1; // 0x74 Type is SpursFlags1 + u8 sysSrvTraceControl; // 0x75 + u8 nSpus; // 0x76 + atomic_t wklFlagReceiver; // 0x77 + atomic_be_t wklSignal2; // 0x78 Bitset for 16..32 wids + u8 x7A[6]; // 0x7A + atomic_t wklState1[0x10]; // 0x80 SPURS_WKL_STATE_* + u8 wklStatus1[0x10]; // 0x90 + atomic_t wklEvent1[0x10]; // 0xA0 + atomic_be_t wklEnabled; // 0xB0 + atomic_be_t wklMskB; // 0xB4 - System service - Available module id + u32 xB8; // 0xB8 + u8 sysSrvExitBarrier; // 0xBC + atomic_t sysSrvMsgUpdateWorkload; // 0xBD + u8 xBE; // 0xBE + u8 sysSrvMsgTerminate; // 0xBF + u8 sysSrvPreemptWklId[8]; // 0xC0 Id of the workload that was preempted by the system workload on each SPU + u8 sysSrvOnSpu; // 0xC8 + u8 spuPort; // 0xC9 + u8 xCA; // 0xCA + u8 xCB; // 0xCB + + struct alignas(4) SrvTraceSyncVar + { + u8 sysSrvTraceInitialised; // 0xCC + u8 sysSrvNotifyUpdateTraceComplete; // 0xCD + u8 sysSrvMsgUpdateTrace; // 0xCE + u8 xCF; + }; + + atomic_t sysSrvTrace; // 0xCC + + atomic_t wklState2[0x10]; // 0xD0 SPURS_WKL_STATE_* + u8 wklStatus2[0x10]; // 0xE0 + atomic_t wklEvent2[0x10]; // 0xF0 + _sub_str1 wklF1[0x10]; // 0x100 + vm::bptr traceBuffer; // 0x900 + be_t traceStartIndex[6]; // 0x908 + u8 unknown7[0x948 - 0x920]; // 0x920 + be_t traceDataSize; // 0x948 + be_t traceMode; // 0x950 + u8 unknown8[0x980 - 0x954]; // 0x954 + be_t semPrv; // 0x980 + be_t unk11; // 0x988 + be_t unk12; // 0x98C + be_t unk13; // 0x990 + u8 unknown4[0xB00 - 0x998]; + WorkloadInfo wklInfo1[0x10]; // 0xB00 + WorkloadInfo wklInfoSysSrv; // 0xD00 + be_t ppu0; // 0xD20 Handler thread + be_t ppu1; // 0xD28 + be_t spuTG; // 0xD30 SPU thread group + be_t spus[8]; // 0xD34 + u8 unknown3[0xD5C - 0xD54]; + be_t eventQueue; // 0xD5C + be_t eventPort; // 0xD60 + atomic_t handlerDirty; // 0xD64 + atomic_t handlerWaiting; // 0xD65 + atomic_t handlerExiting; // 0xD66 + atomic_be_t enableEH; // 0xD68 + be_t exception; // 0xD6C + sys_spu_image_t spuImg; // 0xD70 + be_t flags; // 0xD80 + be_t spuPriority; // 0xD84 + be_t ppuPriority; // 0xD88 + char prefix[0x0f]; // 0xD8C + u8 prefixSize; // 0xD9B + be_t unk5; // 0xD9C + be_t revision; // 0xDA0 + be_t sdkVersion; // 0xDA4 + atomic_be_t spuPortBits; // 0xDA8 + sys_lwmutex_t mutex; // 0xDB0 + sys_lwcond_t cond; // 0xDC8 + u8 unknown9[0xE00 - 0xDD0]; + _sub_str4 wklH1[0x10]; // 0xE00 + EventPortMux eventPortMux; // 0xF00 + atomic_be_t globalSpuExceptionHandler; // 0xF80 + be_t globalSpuExceptionHandlerArgs; // 0xF88 + u8 unknown6[0x1000 - 0xF90]; + WorkloadInfo wklInfo2[0x10]; // 0x1000 + _sub_str1 wklF2[0x10]; // 0x1200 + _sub_str4 wklH2[0x10]; // 0x1A00 + u8 unknown_[0x2000 - 0x1B00]; + + force_inline atomic_t& wklState(const u32 wid) + { + if (wid & 0x10) + { + return wklState2[wid & 0xf]; + } + else + { + return wklState1[wid & 0xf]; + } + } +}; + +CHECK_SIZE_ALIGN(CellSpurs, 0x2000, 128); + +using CellSpurs2 = CellSpurs; + +struct CellSpursExceptionInfo +{ + be_t spu_thread; + be_t spu_npc; + be_t cause; + be_t option; +}; + +// Exception handler +using CellSpursGlobalExceptionEventHandler = void(vm::ptr spurs, vm::cptr info, u32 id, vm::ptr arg); + +struct CellSpursWorkloadAttribute +{ + be_t revision; + be_t sdkVersion; + vm::bcptr pm; + be_t size; + be_t data; + u8 priority[8]; + be_t minContention; + be_t maxContention; + vm::bcptr nameClass; + vm::bcptr nameInstance; + vm::bptr hook; + vm::bptr hookArg; + u8 padding[456]; +}; + +CHECK_SIZE_ALIGN(CellSpursWorkloadAttribute, 512, 8); + +struct alignas(128) CellSpursEventFlag +{ + struct alignas(8) ControlSyncVar + { + be_t events; // 0x00 Event bits + be_t spuTaskPendingRecv; // 0x02 A bit is set to 1 when the condition of the SPU task using the slot are met and back to 0 when the SPU task unblocks + be_t ppuWaitMask; // 0x04 Wait mask for blocked PPU thread + u8 ppuWaitSlotAndMode; // 0x06 Top 4 bits: Wait slot number of the blocked PPU threa, Bottom 4 bits: Wait mode of the blocked PPU thread + u8 ppuPendingRecv; // 0x07 Set to 1 when the blocked PPU thread's conditions are met and back to 0 when the PPU thread is unblocked + }; + + union + { + atomic_t ctrl; // 0x00 + atomic_be_t events; // 0x00 + }; + + be_t spuTaskUsedWaitSlots; // 0x08 A bit is set to 1 if the wait slot corresponding to the bit is used by an SPU task and 0 otherwise + be_t spuTaskWaitMode; // 0x0A A bit is set to 1 if the wait mode for the SPU task corresponding to the bit is AND and 0 otherwise + u8 spuPort; // 0x0C + u8 isIwl; // 0x0D + u8 direction; // 0x0E + u8 clearMode; // 0x0F + be_t spuTaskWaitMask[16]; // 0x10 Wait mask for blocked SPU tasks + be_t pendingRecvTaskEvents[16]; // 0x30 The value of event flag when the wait condition for the thread/task was met + u8 waitingTaskId[16]; // 0x50 Task id of waiting SPU threads + u8 waitingTaskWklId[16]; // 0x60 Workload id of waiting SPU threads + be_t addr; // 0x70 + be_t eventPortId; // 0x78 + be_t eventQueueId; // 0x7C +}; + +CHECK_SIZE_ALIGN(CellSpursEventFlag, 128, 128); + +using CellSpursLFQueue = CellSyncLFQueue; + +union CellSpursTaskArgument +{ + be_t _u32[4]; + be_t _u64[2]; +}; + +union CellSpursTaskLsPattern +{ + be_t _u32[4]; + be_t _u64[2]; +}; + +struct alignas(16) CellSpursTaskAttribute +{ + u8 reserved[256]; +}; + +CHECK_SIZE_ALIGN(CellSpursTaskAttribute, 256, 16); + +struct alignas(16) CellSpursTaskAttribute2 +{ + be_t revision; + be_t sizeContext; + be_t eaContext; + CellSpursTaskLsPattern lsPattern; + vm::bcptr name; + + u8 reserved[220]; +}; + +CHECK_SIZE_ALIGN(CellSpursTaskAttribute2, 256, 16); + +// Exception handler +using CellSpursTasksetExceptionEventHandler = void(vm::ptr spurs, vm::ptr taskset, u32 idTask, vm::cptr info, vm::ptr arg); + +struct alignas(128) CellSpursTaskExitCode +{ + u8 skip[128]; +}; + +CHECK_SIZE_ALIGN(CellSpursTaskExitCode, 128, 128); + +struct CellSpursTaskInfo +{ + CellSpursTaskLsPattern lsPattern; + CellSpursTaskArgument argument; + vm::bptr eaElf; + vm::bptr eaContext; + be_t sizeContext; + u8 state; + u8 hasSignal; + u8 padding[2]; + vm::bcptr eaTaskExitCode; + u8 guid[8]; + u8 reserved[12]; +}; + +CHECK_SIZE(CellSpursTaskInfo, 72); + +struct CellSpursTasksetInfo +{ + CellSpursTaskInfo taskInfo[CELL_SPURS_MAX_TASK]; + be_t argument; + be_t idWorkload; + be_t idLastScheduledTask; + vm::bcptr name; + vm::bptr exceptionEventHandler; + vm::bptr exceptionEventHandlerArgument; + be_t sizeTaskset; + u8 reserved[112]; +}; + +CHECK_SIZE(CellSpursTasksetInfo, 9360); + +struct alignas(8) CellSpursTasksetAttribute +{ + be_t revision; // 0x00 + be_t sdk_version; // 0x04 + be_t args; // 0x08 + u8 priority[8]; // 0x10 + be_t max_contention; // 0x18 + vm::bcptr name; // 0x1C + be_t taskset_size; // 0x20 + be_t enable_clear_ls; // 0x24 + u8 reserved[472]; +}; + +CHECK_SIZE_ALIGN(CellSpursTasksetAttribute, 512, 8); + +struct alignas(128) CellSpursTaskset +{ + struct TaskInfo + { + CellSpursTaskArgument args; // 0x00 + vm::bcptr elf; // 0x10 + be_t context_save_storage_and_alloc_ls_blocks; // 0x18 This is (context_save_storage_addr | allocated_ls_blocks) + CellSpursTaskLsPattern ls_pattern; // 0x20 + }; + + CHECK_SIZE(TaskInfo, 48); + + be_t running; // 0x00 + be_t ready; // 0x10 + be_t pending_ready; // 0x20 + be_t enabled; // 0x30 + be_t signalled; // 0x40 + be_t waiting; // 0x50 + vm::bptr spurs; // 0x60 + be_t args; // 0x68 + u8 enable_clear_ls; // 0x70 + u8 x71; // 0x71 + u8 wkl_flag_wait_task; // 0x72 + u8 last_scheduled_task; // 0x73 + be_t wid; // 0x74 + be_t x78; // 0x78 + TaskInfo task_info[128]; // 0x80 + vm::bptr exception_handler; // 0x1880 + vm::bptr exception_handler_arg; // 0x1888 + be_t size; // 0x1890 + u32 unk2; // 0x1894 + u32 event_flag_id1; // 0x1898 + u32 event_flag_id2; // 0x189C + u8 unk3[0x60]; // 0x18A0 +}; + +CHECK_SIZE_ALIGN(CellSpursTaskset, 128 * 50, 128); + +struct alignas(128) CellSpursTaskset2 +{ + struct TaskInfo + { + CellSpursTaskArgument args; + vm::bptr elf_addr; + vm::bptr context_save_storage; // This is (context_save_storage_addr | allocated_ls_blocks) + CellSpursTaskLsPattern ls_pattern; + }; + + CHECK_SIZE(TaskInfo, 48); + + be_t running_set[4]; // 0x00 + be_t ready_set[4]; // 0x10 + be_t ready2_set[4]; // 0x20 - TODO: Find out what this is + be_t enabled_set[4]; // 0x30 + be_t signal_received_set[4]; // 0x40 + be_t waiting_set[4]; // 0x50 + vm::bptr spurs; // 0x60 + be_t args; // 0x68 + u8 enable_clear_ls; // 0x70 + u8 x71; // 0x71 + u8 x72; // 0x72 + u8 last_scheduled_task; // 0x73 + be_t wid; // 0x74 + be_t x78; // 0x78 + TaskInfo task_info[128]; // 0x80 + vm::bptr exception_handler; // 0x1880 + vm::bptr exception_handler_arg; // 0x1888 + be_t size; // 0x1890 + u32 unk2; // 0x1894 + u32 event_flag_id1; // 0x1898 + u32 event_flag_id2; // 0x189C + u8 unk3[0x1980 - 0x18A0]; // 0x18A0 + be_t task_exit_code[128]; // 0x1980 + u8 unk4[0x2900 - 0x2180]; // 0x2180 +}; + +CHECK_SIZE_ALIGN(CellSpursTaskset2, 128 * 82, 128); + +struct alignas(16) CellSpursTaskNameBuffer +{ + char taskName[CELL_SPURS_MAX_TASK][CELL_SPURS_MAX_TASK_NAME_LENGTH]; +}; + +struct alignas(8) CellSpursTasksetAttribute2 +{ + be_t revision; // 0x00 + vm::bcptr name; // 0x04 + be_t args; // 0x08 + u8 priority[8]; // 0x10 + be_t max_contention; // 0x18 + be_t enable_clear_ls; // 0x1C + vm::bptr task_name_buffer; // 0x20 + u8 reserved[472]; +}; + +CHECK_SIZE_ALIGN(CellSpursTasksetAttribute2, 512, 8); + +struct alignas(16) CellSpursTaskBinInfo +{ + be_t eaElf; + be_t sizeContext; + be_t reserved; + CellSpursTaskLsPattern lsPattern; +}; + +// The SPURS kernel context. This resides at 0x100 of the LS. +struct SpursKernelContext +{ + u8 tempArea[0x80]; // 0x100 + u8 wklLocContention[0x10]; // 0x180 + u8 wklLocPendingContention[0x10]; // 0x190 + u8 priority[0x10]; // 0x1A0 + u8 x1B0[0x10]; // 0x1B0 + vm::bptr spurs; // 0x1C0 + be_t spuNum; // 0x1C8 + be_t dmaTagId; // 0x1CC + vm::bcptr wklCurrentAddr; // 0x1D0 + be_t wklCurrentUniqueId; // 0x1D8 + be_t wklCurrentId; // 0x1DC + be_t exitToKernelAddr; // 0x1E0 + be_t selectWorkloadAddr; // 0x1E4 + u8 moduleId[2]; // 0x1E8 + u8 sysSrvInitialised; // 0x1EA + u8 spuIdling; // 0x1EB + be_t wklRunnable1; // 0x1EC + be_t wklRunnable2; // 0x1EE + be_t x1F0; // 0x1F0 + be_t x1F4; // 0x1F4 + be_t x1F8; // 0x1F8 + be_t x1FC; // 0x1FC + be_t x200; // 0x200 + be_t x204; // 0x204 + be_t x208; // 0x208 + be_t x20C; // 0x20C + be_t traceBuffer; // 0x210 + be_t traceMsgCount; // 0x218 + be_t traceMaxCount; // 0x21C + u8 wklUniqueId[0x10]; // 0x220 + u8 x230[0x280 - 0x230]; // 0x230 + be_t guid[4]; // 0x280 +}; + +CHECK_SIZE(SpursKernelContext, 0x190); + +// The SPURS taskset policy module context. This resides at 0x2700 of the LS. +struct SpursTasksetContext +{ + u8 tempAreaTaskset[0x80]; // 0x2700 + u8 tempAreaTaskInfo[0x30]; // 0x2780 + be_t x27B0; // 0x27B0 + vm::bptr taskset; // 0x27B8 + be_t kernelMgmtAddr; // 0x27C0 + be_t syscallAddr; // 0x27C4 + be_t x27C8; // 0x27C8 + be_t spuNum; // 0x27CC + be_t dmaTagId; // 0x27D0 + be_t taskId; // 0x27D4 + u8 x27D8[0x2840 - 0x27D8]; // 0x27D8 + u8 moduleId[16]; // 0x2840 + u8 stackArea[0x2C80 - 0x2850]; // 0x2850 + be_t savedContextLr; // 0x2C80 + be_t savedContextSp; // 0x2C90 + be_t savedContextR80ToR127[48]; // 0x2CA0 + be_t savedContextFpscr; // 0x2FA0 + be_t savedWriteTagGroupQueryMask; // 0x2FB0 + be_t savedSpuWriteEventMask; // 0x2FB4 + be_t tasksetMgmtAddr; // 0x2FB8 + be_t guidAddr; // 0x2FBC + be_t x2FC0; // 0x2FC0 + be_t x2FC8; // 0x2FC8 + be_t taskExitCode; // 0x2FD0 + be_t x2FD4; // 0x2FD4 + u8 x2FD8[0x3000 - 0x2FD8]; // 0x2FD8 +}; + +CHECK_SIZE(SpursTasksetContext, 0x900); + +class SpursModuleExit +{ +}; diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpursJq.cpp b/rpcs3/Emu/Cell/Modules/cellSpursJq.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/cellSpursJq.cpp rename to rpcs3/Emu/Cell/Modules/cellSpursJq.cpp index 1a943ebccc..b5d85f2d5c 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpursJq.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSpursJq.cpp @@ -1,16 +1,14 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/SysCalls/lv2/sys_sync.h" -#include "Emu/SysCalls/lv2/sys_lwmutex.h" -#include "Emu/SysCalls/lv2/sys_lwcond.h" -#include "Emu/SysCalls/lv2/sys_spu.h" +#include "Emu/Cell/lv2/sys_lwmutex.h" +#include "Emu/Cell/lv2/sys_lwcond.h" +#include "Emu/Cell/lv2/sys_spu.h" #include "cellSpurs.h" #include "cellSpursJq.h" -extern Module<> cellSpursJq; +LOG_CHANNEL(cellSpursJq); s32 cellSpursJobQueueAttributeInitialize() { @@ -390,7 +388,7 @@ s32 cellSpursJobQueueUnsetExceptionEventHandler() return CELL_OK; } -Module<> cellSpursJq("cellSpursJq", []() +DECLARE(ppu_module_manager::cellSpursJq)("cellSpursJq", []() { REG_FUNC(cellSpursJq, cellSpursJobQueueAttributeInitialize); REG_FUNC(cellSpursJq, cellSpursJobQueueAttributeSetMaxGrab); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpursJq.h b/rpcs3/Emu/Cell/Modules/cellSpursJq.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellSpursJq.h rename to rpcs3/Emu/Cell/Modules/cellSpursJq.h diff --git a/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp b/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp new file mode 100644 index 0000000000..eb56cdd302 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp @@ -0,0 +1,1986 @@ +#include "stdafx.h" +#include "Loader/ELF.h" +#include "Emu/System.h" +#include "Emu/Cell/PPUModule.h" + +#include "Emu/Cell/SPUThread.h" +#include "Emu/Cell/lv2/sys_lwmutex.h" +#include "Emu/Cell/lv2/sys_lwcond.h" +#include "Emu/Cell/lv2/sys_spu.h" +#include "cellSpurs.h" + +//---------------------------------------------------------------------------- +// Externs +//---------------------------------------------------------------------------- + +extern _log::channel cellSpurs; + +//---------------------------------------------------------------------------- +// Function prototypes +//---------------------------------------------------------------------------- + +// +// SPURS utility functions +// +static void cellSpursModulePutTrace(CellSpursTracePacket* packet, u32 dmaTagId); +static u32 cellSpursModulePollStatus(SPUThread& spu, u32* status); +static void cellSpursModuleExit(SPUThread& spu); + +static bool spursDma(SPUThread& spu, u32 cmd, u64 ea, u32 lsa, u32 size, u32 tag); +static u32 spursDmaGetCompletionStatus(SPUThread& spu, u32 tagMask); +static u32 spursDmaWaitForCompletion(SPUThread& spu, u32 tagMask, bool waitForAll = true); +static void spursHalt(SPUThread& spu); + +// +// SPURS kernel functions +// +static bool spursKernel1SelectWorkload(SPUThread& spu); +static bool spursKernel2SelectWorkload(SPUThread& spu); +static void spursKernelDispatchWorkload(SPUThread& spu, u64 widAndPollStatus); +static bool spursKernelWorkloadExit(SPUThread& spu); +bool spursKernelEntry(SPUThread& spu); + +// +// SPURS system workload functions +// +static bool spursSysServiceEntry(SPUThread& spu); +// TODO: Exit +static void spursSysServiceIdleHandler(SPUThread& spu, SpursKernelContext* ctxt); +static void spursSysServiceMain(SPUThread& spu, u32 pollStatus); +static void spursSysServiceProcessRequests(SPUThread& spu, SpursKernelContext* ctxt); +static void spursSysServiceActivateWorkload(SPUThread& spu, SpursKernelContext* ctxt); +// TODO: Deactivate workload +static void spursSysServiceUpdateShutdownCompletionEvents(SPUThread& spu, SpursKernelContext* ctxt, u32 wklShutdownBitSet); +static void spursSysServiceTraceSaveCount(SPUThread& spu, SpursKernelContext* ctxt); +static void spursSysServiceTraceUpdate(SPUThread& spu, SpursKernelContext* ctxt, u32 arg2, u32 arg3, u32 forceNotify); +// TODO: Deactivate trace +// TODO: System workload entry +static void spursSysServiceCleanupAfterSystemWorkload(SPUThread& spu, SpursKernelContext* ctxt); + +// +// SPURS taskset policy module functions +// +static bool spursTasksetEntry(SPUThread& spu); +static bool spursTasksetSyscallEntry(SPUThread& spu); +static void spursTasksetResumeTask(SPUThread& spu); +static void spursTasksetStartTask(SPUThread& spu, CellSpursTaskArgument& taskArgs); +static s32 spursTasksetProcessRequest(SPUThread& spu, s32 request, u32* taskId, u32* isWaiting); +static void spursTasksetProcessPollStatus(SPUThread& spu, u32 pollStatus); +static bool spursTasksetPollStatus(SPUThread& spu); +static void spursTasksetExit(SPUThread& spu); +static void spursTasksetOnTaskExit(SPUThread& spu, u64 addr, u32 taskId, s32 exitCode, u64 args); +static s32 spursTasketSaveTaskContext(SPUThread& spu); +static void spursTasksetDispatch(SPUThread& spu); +static s32 spursTasksetProcessSyscall(SPUThread& spu, u32 syscallNum, u32 args); +static void spursTasksetInit(SPUThread& spu, u32 pollStatus); +static s32 spursTasksetLoadElf(SPUThread& spu, u32* entryPoint, u32* lowestLoadAddr, u64 elfAddr, bool skipWriteableSegments); + +//---------------------------------------------------------------------------- +// SPURS utility functions +//---------------------------------------------------------------------------- + +// Output trace information +void cellSpursModulePutTrace(CellSpursTracePacket* packet, u32 dmaTagId) +{ + // TODO: Implement this +} + +// Check for execution right requests +u32 cellSpursModulePollStatus(SPUThread& spu, u32* status) +{ + auto ctxt = vm::_ptr(spu.offset + 0x100); + + spu.gpr[3]._u32[3] = 1; + if (ctxt->spurs->flags1 & SF1_32_WORKLOADS) + { + spursKernel2SelectWorkload(spu); + } + else + { + spursKernel1SelectWorkload(spu); + } + + auto result = spu.gpr[3]._u64[1]; + if (status) + { + *status = (u32)result; + } + + u32 wklId = result >> 32; + return wklId == ctxt->wklCurrentId ? 0 : 1; +} + +// Exit current workload +void cellSpursModuleExit(SPUThread& spu) +{ + auto ctxt = vm::_ptr(spu.offset + 0x100); + spu.pc = ctxt->exitToKernelAddr - 4; + throw SpursModuleExit(); +} + +// Execute a DMA operation +bool spursDma(SPUThread& spu, u32 cmd, u64 ea, u32 lsa, u32 size, u32 tag) +{ + spu.set_ch_value(MFC_LSA, lsa); + spu.set_ch_value(MFC_EAH, (u32)(ea >> 32)); + spu.set_ch_value(MFC_EAL, (u32)(ea)); + spu.set_ch_value(MFC_Size, size); + spu.set_ch_value(MFC_TagID, tag); + spu.set_ch_value(MFC_Cmd, cmd); + + if (cmd == MFC_GETLLAR_CMD || cmd == MFC_PUTLLC_CMD || cmd == MFC_PUTLLUC_CMD) + { + u32 rv; + + rv = spu.get_ch_value(MFC_RdAtomicStat); + auto success = rv ? true : false; + success = cmd == MFC_PUTLLC_CMD ? !success : success; + return success; + } + + return true; +} + +// Get the status of DMA operations +u32 spursDmaGetCompletionStatus(SPUThread& spu, u32 tagMask) +{ + spu.set_ch_value(MFC_WrTagMask, tagMask); + spu.set_ch_value(MFC_WrTagUpdate, MFC_TAG_UPDATE_IMMEDIATE); + return spu.get_ch_value(MFC_RdTagStat); +} + +// Wait for DMA operations to complete +u32 spursDmaWaitForCompletion(SPUThread& spu, u32 tagMask, bool waitForAll) +{ + spu.set_ch_value(MFC_WrTagMask, tagMask); + spu.set_ch_value(MFC_WrTagUpdate, waitForAll ? MFC_TAG_UPDATE_ALL : MFC_TAG_UPDATE_ANY); + return spu.get_ch_value(MFC_RdTagStat); +} + +// Halt the SPU +void spursHalt(SPUThread& spu) +{ + spu.halt(); +} + +//---------------------------------------------------------------------------- +// SPURS kernel functions +//---------------------------------------------------------------------------- + +// Select a workload to run +bool spursKernel1SelectWorkload(SPUThread& spu) +{ + auto ctxt = vm::_ptr(spu.offset + 0x100); + + // The first and only argument to this function is a boolean that is set to false if the function + // is called by the SPURS kernel and set to true if called by cellSpursModulePollStatus. + // If the first argument is true then the shared data is not updated with the result. + const auto isPoll = spu.gpr[3]._u32[3]; + + u32 wklSelectedId; + u32 pollStatus; + + vm::reservation_op(vm::cast(ctxt->spurs.addr(), HERE), 128, [&]() + { + // lock the first 0x80 bytes of spurs + auto spurs = ctxt->spurs.get_ptr_priv(); + + // Calculate the contention (number of SPUs used) for each workload + u8 contention[CELL_SPURS_MAX_WORKLOAD]; + u8 pendingContention[CELL_SPURS_MAX_WORKLOAD]; + for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) + { + contention[i] = spurs->wklCurrentContention[i] - ctxt->wklLocContention[i]; + + // If this is a poll request then the number of SPUs pending to context switch is also added to the contention presumably + // to prevent unnecessary jumps to the kernel + if (isPoll) + { + pendingContention[i] = spurs->wklPendingContention[i] - ctxt->wklLocPendingContention[i]; + if (i != ctxt->wklCurrentId) + { + contention[i] += pendingContention[i]; + } + } + } + + wklSelectedId = CELL_SPURS_SYS_SERVICE_WORKLOAD_ID; + pollStatus = 0; + + // The system service has the highest priority. Select the system service if + // the system service message bit for this SPU is set. + if (spurs->sysSrvMessage & (1 << ctxt->spuNum)) + { + ctxt->spuIdling = 0; + if (!isPoll || ctxt->wklCurrentId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) + { + // Clear the message bit + spurs->sysSrvMessage.raw() &= ~(1 << ctxt->spuNum); + } + } + else + { + // Caclulate the scheduling weight for each workload + u16 maxWeight = 0; + for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) + { + u16 runnable = ctxt->wklRunnable1 & (0x8000 >> i); + u16 wklSignal = spurs->wklSignal1.load() & (0x8000 >> i); + u8 wklFlag = spurs->wklFlag.flag.load() == 0 ? spurs->wklFlagReceiver == i ? 1 : 0 : 0; + u8 readyCount = spurs->wklReadyCount1[i] > CELL_SPURS_MAX_SPU ? CELL_SPURS_MAX_SPU : spurs->wklReadyCount1[i].load(); + u8 idleSpuCount = spurs->wklIdleSpuCountOrReadyCount2[i] > CELL_SPURS_MAX_SPU ? CELL_SPURS_MAX_SPU : spurs->wklIdleSpuCountOrReadyCount2[i].load(); + u8 requestCount = readyCount + idleSpuCount; + + // For a workload to be considered for scheduling: + // 1. Its priority must not be 0 + // 2. The number of SPUs used by it must be less than the max contention for that workload + // 3. The workload should be in runnable state + // 4. The number of SPUs allocated to it must be less than the number of SPUs requested (i.e. readyCount) + // OR the workload must be signalled + // OR the workload flag is 0 and the workload is configured as the wokload flag receiver + if (runnable && ctxt->priority[i] != 0 && spurs->wklMaxContention[i] > contention[i]) + { + if (wklFlag || wklSignal || (readyCount != 0 && requestCount > contention[i])) + { + // The scheduling weight of the workload is formed from the following parameters in decreasing order of priority: + // 1. Wokload signal set or workload flag or ready count > contention + // 2. Priority of the workload on the SPU + // 3. Is the workload the last selected workload + // 4. Minimum contention of the workload + // 5. Number of SPUs that are being used by the workload (lesser the number, more the weight) + // 6. Is the workload executable same as the currently loaded executable + // 7. The workload id (lesser the number, more the weight) + u16 weight = (wklFlag || wklSignal || (readyCount > contention[i])) ? 0x8000 : 0; + weight |= (u16)(ctxt->priority[i] & 0x7F) << 16; + weight |= i == ctxt->wklCurrentId ? 0x80 : 0x00; + weight |= (contention[i] > 0 && spurs->wklMinContention[i] > contention[i]) ? 0x40 : 0x00; + weight |= ((CELL_SPURS_MAX_SPU - contention[i]) & 0x0F) << 2; + weight |= ctxt->wklUniqueId[i] == ctxt->wklCurrentId ? 0x02 : 0x00; + weight |= 0x01; + + // In case of a tie the lower numbered workload is chosen + if (weight > maxWeight) + { + wklSelectedId = i; + maxWeight = weight; + pollStatus = readyCount > contention[i] ? CELL_SPURS_MODULE_POLL_STATUS_READYCOUNT : 0; + pollStatus |= wklSignal ? CELL_SPURS_MODULE_POLL_STATUS_SIGNAL : 0; + pollStatus |= wklFlag ? CELL_SPURS_MODULE_POLL_STATUS_FLAG : 0; + } + } + } + } + + // Not sure what this does. Possibly mark the SPU as idle/in use. + ctxt->spuIdling = wklSelectedId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID ? 1 : 0; + + if (!isPoll || wklSelectedId == ctxt->wklCurrentId) + { + // Clear workload signal for the selected workload + spurs->wklSignal1.raw() &= ~(0x8000 >> wklSelectedId); + spurs->wklSignal2.raw() &= ~(0x80000000u >> wklSelectedId); + + // If the selected workload is the wklFlag workload then pull the wklFlag to all 1s + if (wklSelectedId == spurs->wklFlagReceiver) + { + spurs->wklFlag.flag = -1; + } + } + } + + if (!isPoll) + { + // Called by kernel + // Increment the contention for the selected workload + if (wklSelectedId != CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) + { + contention[wklSelectedId]++; + } + + for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) + { + spurs->wklCurrentContention[i] = contention[i]; + spurs->wklPendingContention[i] = spurs->wklPendingContention[i] - ctxt->wklLocPendingContention[i]; + ctxt->wklLocContention[i] = 0; + ctxt->wklLocPendingContention[i] = 0; + } + + if (wklSelectedId != CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) + { + ctxt->wklLocContention[wklSelectedId] = 1; + } + + ctxt->wklCurrentId = wklSelectedId; + } + else if (wklSelectedId != ctxt->wklCurrentId) + { + // Not called by kernel but a context switch is required + // Increment the pending contention for the selected workload + if (wklSelectedId != CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) + { + pendingContention[wklSelectedId]++; + } + + for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) + { + spurs->wklPendingContention[i] = pendingContention[i]; + ctxt->wklLocPendingContention[i] = 0; + } + + if (wklSelectedId != CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) + { + ctxt->wklLocPendingContention[wklSelectedId] = 1; + } + } + else + { + // Not called by kernel and no context switch is required + for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) + { + spurs->wklPendingContention[i] = spurs->wklPendingContention[i] - ctxt->wklLocPendingContention[i]; + ctxt->wklLocPendingContention[i] = 0; + } + } + + std::memcpy(vm::base(spu.offset + 0x100), spurs, 128); + }); + + u64 result = (u64)wklSelectedId << 32; + result |= pollStatus; + spu.gpr[3]._u64[1] = result; + return true; +} + +// Select a workload to run +bool spursKernel2SelectWorkload(SPUThread& spu) +{ + auto ctxt = vm::_ptr(spu.offset + 0x100); + + // The first and only argument to this function is a boolean that is set to false if the function + // is called by the SPURS kernel and set to true if called by cellSpursModulePollStatus. + // If the first argument is true then the shared data is not updated with the result. + const auto isPoll = spu.gpr[3]._u32[3]; + + u32 wklSelectedId; + u32 pollStatus; + + vm::reservation_op(vm::cast(ctxt->spurs.addr(), HERE), 128, [&]() + { + // lock the first 0x80 bytes of spurs + auto spurs = ctxt->spurs.get_ptr_priv(); + + // Calculate the contention (number of SPUs used) for each workload + u8 contention[CELL_SPURS_MAX_WORKLOAD2]; + u8 pendingContention[CELL_SPURS_MAX_WORKLOAD2]; + for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD2; i++) + { + contention[i] = spurs->wklCurrentContention[i & 0x0F] - ctxt->wklLocContention[i & 0x0F]; + contention[i] = i < CELL_SPURS_MAX_WORKLOAD ? contention[i] & 0x0F : contention[i] >> 4; + + // If this is a poll request then the number of SPUs pending to context switch is also added to the contention presumably + // to prevent unnecessary jumps to the kernel + if (isPoll) + { + pendingContention[i] = spurs->wklPendingContention[i & 0x0F] - ctxt->wklLocPendingContention[i & 0x0F]; + pendingContention[i] = i < CELL_SPURS_MAX_WORKLOAD ? pendingContention[i] & 0x0F : pendingContention[i] >> 4; + if (i != ctxt->wklCurrentId) + { + contention[i] += pendingContention[i]; + } + } + } + + wklSelectedId = CELL_SPURS_SYS_SERVICE_WORKLOAD_ID; + pollStatus = 0; + + // The system service has the highest priority. Select the system service if + // the system service message bit for this SPU is set. + if (spurs->sysSrvMessage & (1 << ctxt->spuNum)) + { + // Not sure what this does. Possibly Mark the SPU as in use. + ctxt->spuIdling = 0; + if (!isPoll || ctxt->wklCurrentId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) + { + // Clear the message bit + spurs->sysSrvMessage.raw() &= ~(1 << ctxt->spuNum); + } + } + else + { + // Caclulate the scheduling weight for each workload + u8 maxWeight = 0; + for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD2; i++) + { + auto j = i & 0x0F; + u16 runnable = i < CELL_SPURS_MAX_WORKLOAD ? ctxt->wklRunnable1 & (0x8000 >> j) : ctxt->wklRunnable2 & (0x8000 >> j); + u8 priority = i < CELL_SPURS_MAX_WORKLOAD ? ctxt->priority[j] & 0x0F : ctxt->priority[j] >> 4; + u8 maxContention = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklMaxContention[j] & 0x0F : spurs->wklMaxContention[j] >> 4; + u16 wklSignal = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklSignal1.load() & (0x8000 >> j) : spurs->wklSignal2.load() & (0x8000 >> j); + u8 wklFlag = spurs->wklFlag.flag.load() == 0 ? spurs->wklFlagReceiver == i ? 1 : 0 : 0; + u8 readyCount = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklReadyCount1[j] : spurs->wklIdleSpuCountOrReadyCount2[j]; + + // For a workload to be considered for scheduling: + // 1. Its priority must be greater than 0 + // 2. The number of SPUs used by it must be less than the max contention for that workload + // 3. The workload should be in runnable state + // 4. The number of SPUs allocated to it must be less than the number of SPUs requested (i.e. readyCount) + // OR the workload must be signalled + // OR the workload flag is 0 and the workload is configured as the wokload receiver + if (runnable && priority > 0 && maxContention > contention[i]) + { + if (wklFlag || wklSignal || readyCount > contention[i]) + { + // The scheduling weight of the workload is equal to the priority of the workload for the SPU. + // The current workload is given a sligtly higher weight presumably to reduce the number of context switches. + // In case of a tie the lower numbered workload is chosen. + u8 weight = priority << 4; + if (ctxt->wklCurrentId == i) + { + weight |= 0x04; + } + + if (weight > maxWeight) + { + wklSelectedId = i; + maxWeight = weight; + pollStatus = readyCount > contention[i] ? CELL_SPURS_MODULE_POLL_STATUS_READYCOUNT : 0; + pollStatus |= wklSignal ? CELL_SPURS_MODULE_POLL_STATUS_SIGNAL : 0; + pollStatus |= wklFlag ? CELL_SPURS_MODULE_POLL_STATUS_FLAG : 0; + } + } + } + } + + // Not sure what this does. Possibly mark the SPU as idle/in use. + ctxt->spuIdling = wklSelectedId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID ? 1 : 0; + + if (!isPoll || wklSelectedId == ctxt->wklCurrentId) + { + // Clear workload signal for the selected workload + spurs->wklSignal1.raw() &= ~(0x8000 >> wklSelectedId); + spurs->wklSignal2.raw() &= ~(0x80000000u >> wklSelectedId); + + // If the selected workload is the wklFlag workload then pull the wklFlag to all 1s + if (wklSelectedId == spurs->wklFlagReceiver) + { + spurs->wklFlag.flag = -1; + } + } + } + + if (!isPoll) + { + // Called by kernel + // Increment the contention for the selected workload + if (wklSelectedId != CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) + { + contention[wklSelectedId]++; + } + + for (auto i = 0; i < (CELL_SPURS_MAX_WORKLOAD2 >> 1); i++) + { + spurs->wklCurrentContention[i] = contention[i] | (contention[i + 0x10] << 4); + spurs->wklPendingContention[i] = spurs->wklPendingContention[i] - ctxt->wklLocPendingContention[i]; + ctxt->wklLocContention[i] = 0; + ctxt->wklLocPendingContention[i] = 0; + } + + ctxt->wklLocContention[wklSelectedId & 0x0F] = wklSelectedId < CELL_SPURS_MAX_WORKLOAD ? 0x01 : wklSelectedId < CELL_SPURS_MAX_WORKLOAD2 ? 0x10 : 0; + ctxt->wklCurrentId = wklSelectedId; + } + else if (wklSelectedId != ctxt->wklCurrentId) + { + // Not called by kernel but a context switch is required + // Increment the pending contention for the selected workload + if (wklSelectedId != CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) + { + pendingContention[wklSelectedId]++; + } + + for (auto i = 0; i < (CELL_SPURS_MAX_WORKLOAD2 >> 1); i++) + { + spurs->wklPendingContention[i] = pendingContention[i] | (pendingContention[i + 0x10] << 4); + ctxt->wklLocPendingContention[i] = 0; + } + + ctxt->wklLocPendingContention[wklSelectedId & 0x0F] = wklSelectedId < CELL_SPURS_MAX_WORKLOAD ? 0x01 : wklSelectedId < CELL_SPURS_MAX_WORKLOAD2 ? 0x10 : 0; + } + else + { + // Not called by kernel and no context switch is required + for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) + { + spurs->wklPendingContention[i] = spurs->wklPendingContention[i] - ctxt->wklLocPendingContention[i]; + ctxt->wklLocPendingContention[i] = 0; + } + } + + std::memcpy(vm::base(spu.offset + 0x100), spurs, 128); + }); + + u64 result = (u64)wklSelectedId << 32; + result |= pollStatus; + spu.gpr[3]._u64[1] = result; + return true; +} + +// SPURS kernel dispatch workload +void spursKernelDispatchWorkload(SPUThread& spu, u64 widAndPollStatus) +{ + auto ctxt = vm::_ptr(spu.offset + 0x100); + auto isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false; + + auto pollStatus = (u32)widAndPollStatus; + auto wid = (u32)(widAndPollStatus >> 32); + + // DMA in the workload info for the selected workload + auto wklInfoOffset = wid < CELL_SPURS_MAX_WORKLOAD ? &ctxt->spurs->wklInfo1[wid] : + wid < CELL_SPURS_MAX_WORKLOAD2 && isKernel2 ? &ctxt->spurs->wklInfo2[wid & 0xf] : + &ctxt->spurs->wklInfoSysSrv; + + std::memcpy(vm::base(spu.offset + 0x3FFE0), wklInfoOffset, 0x20); + + // Load the workload to LS + auto wklInfo = vm::_ptr(spu.offset + 0x3FFE0); + if (ctxt->wklCurrentAddr != wklInfo->addr) + { + switch (wklInfo->addr.addr()) + { + case SPURS_IMG_ADDR_SYS_SRV_WORKLOAD: + spu.RegisterHleFunction(0xA00, spursSysServiceEntry); + break; + case SPURS_IMG_ADDR_TASKSET_PM: + spu.RegisterHleFunction(0xA00, spursTasksetEntry); + break; + default: + std::memcpy(vm::base(spu.offset + 0xA00), wklInfo->addr.get_ptr(), wklInfo->size); + break; + } + + ctxt->wklCurrentAddr = wklInfo->addr; + ctxt->wklCurrentUniqueId = wklInfo->uniqueId; + } + + if (!isKernel2) + { + ctxt->moduleId[0] = 0; + ctxt->moduleId[1] = 0; + } + + // Run workload + spu.gpr[0]._u32[3] = ctxt->exitToKernelAddr; + spu.gpr[1]._u32[3] = 0x3FFB0; + spu.gpr[3]._u32[3] = 0x100; + spu.gpr[4]._u64[1] = wklInfo->arg; + spu.gpr[5]._u32[3] = pollStatus; + spu.pc = 0xA00 - 4; +} + +// SPURS kernel workload exit +bool spursKernelWorkloadExit(SPUThread& spu) +{ + auto ctxt = vm::_ptr(spu.offset + 0x100); + auto isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false; + + // Select next workload to run + spu.gpr[3].clear(); + if (isKernel2) + { + spursKernel2SelectWorkload(spu); + } + else + { + spursKernel1SelectWorkload(spu); + } + + spursKernelDispatchWorkload(spu, spu.gpr[3]._u64[1]); + return false; +} + +// SPURS kernel entry point +bool spursKernelEntry(SPUThread& spu) +{ + while (true) + { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + CHECK_EMU_STATUS; + } + + auto ctxt = vm::_ptr(spu.offset + 0x100); + memset(ctxt, 0, sizeof(SpursKernelContext)); + + // Save arguments + ctxt->spuNum = spu.gpr[3]._u32[3]; + ctxt->spurs.set(spu.gpr[4]._u64[1]); + + auto isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false; + + // Initialise the SPURS context to its initial values + ctxt->dmaTagId = CELL_SPURS_KERNEL_DMA_TAG_ID; + ctxt->wklCurrentUniqueId = 0x20; + ctxt->wklCurrentId = CELL_SPURS_SYS_SERVICE_WORKLOAD_ID; + ctxt->exitToKernelAddr = isKernel2 ? CELL_SPURS_KERNEL2_EXIT_ADDR : CELL_SPURS_KERNEL1_EXIT_ADDR; + ctxt->selectWorkloadAddr = isKernel2 ? CELL_SPURS_KERNEL2_SELECT_WORKLOAD_ADDR : CELL_SPURS_KERNEL1_SELECT_WORKLOAD_ADDR; + if (!isKernel2) + { + ctxt->x1F0 = 0xF0020000; + ctxt->x200 = 0x20000; + ctxt->guid[0] = 0x423A3A02; + ctxt->guid[1] = 0x43F43A82; + ctxt->guid[2] = 0x43F26502; + ctxt->guid[3] = 0x420EB382; + } + else + { + ctxt->guid[0] = 0x43A08402; + ctxt->guid[1] = 0x43FB0A82; + ctxt->guid[2] = 0x435E9302; + ctxt->guid[3] = 0x43A3C982; + } + + // Register SPURS kernel HLE functions + spu.UnregisterHleFunctions(0, 0x40000/*LS_BOTTOM*/); + spu.RegisterHleFunction(isKernel2 ? CELL_SPURS_KERNEL2_ENTRY_ADDR : CELL_SPURS_KERNEL1_ENTRY_ADDR, spursKernelEntry); + spu.RegisterHleFunction(ctxt->exitToKernelAddr, spursKernelWorkloadExit); + spu.RegisterHleFunction(ctxt->selectWorkloadAddr, isKernel2 ? spursKernel2SelectWorkload : spursKernel1SelectWorkload); + + // Start the system service + spursKernelDispatchWorkload(spu, ((u64)CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) << 32); + return false; +} + +//---------------------------------------------------------------------------- +// SPURS system workload functions +//---------------------------------------------------------------------------- + +// Entry point of the system service +bool spursSysServiceEntry(SPUThread& spu) +{ + auto ctxt = vm::_ptr(spu.offset + spu.gpr[3]._u32[3]); + auto arg = spu.gpr[4]._u64[1]; + auto pollStatus = spu.gpr[5]._u32[3]; + + try + { + if (ctxt->wklCurrentId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) + { + spursSysServiceMain(spu, pollStatus); + } + else + { + // TODO: If we reach here it means the current workload was preempted to start the + // system workload. Need to implement this. + } + + cellSpursModuleExit(spu); + } + + catch (SpursModuleExit) + { + } + + return false; +} + +// Wait for an external event or exit the SPURS thread group if no workloads can be scheduled +void spursSysServiceIdleHandler(SPUThread& spu, SpursKernelContext* ctxt) +{ + bool shouldExit; + + std::unique_lock lock(spu.mutex, std::defer_lock); + + while (true) + { + vm::reservation_acquire(vm::base(spu.offset + 0x100), vm::cast(ctxt->spurs.addr(), HERE), 128); + auto spurs = vm::_ptr(spu.offset + 0x100); + + // Find the number of SPUs that are idling in this SPURS instance + u32 nIdlingSpus = 0; + for (u32 i = 0; i < 8; i++) + { + if (spurs->spuIdling & (1 << i)) + { + nIdlingSpus++; + } + } + + bool allSpusIdle = nIdlingSpus == spurs->nSpus ? true : false; + bool exitIfNoWork = spurs->flags1 & SF1_EXIT_IF_NO_WORK ? true : false; + shouldExit = allSpusIdle && exitIfNoWork; + + // Check if any workloads can be scheduled + bool foundReadyWorkload = false; + if (spurs->sysSrvMessage & (1 << ctxt->spuNum)) + { + foundReadyWorkload = true; + } + else + { + if (spurs->flags1 & SF1_32_WORKLOADS) + { + for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD2; i++) + { + u32 j = i & 0x0F; + u16 runnable = i < CELL_SPURS_MAX_WORKLOAD ? ctxt->wklRunnable1 & (0x8000 >> j) : ctxt->wklRunnable2 & (0x8000 >> j); + u8 priority = i < CELL_SPURS_MAX_WORKLOAD ? ctxt->priority[j] & 0x0F : ctxt->priority[j] >> 4; + u8 maxContention = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklMaxContention[j] & 0x0F : spurs->wklMaxContention[j] >> 4; + u8 contention = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklCurrentContention[j] & 0x0F : spurs->wklCurrentContention[j] >> 4; + u16 wklSignal = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklSignal1.load() & (0x8000 >> j) : spurs->wklSignal2.load() & (0x8000 >> j); + u8 wklFlag = spurs->wklFlag.flag.load() == 0 ? spurs->wklFlagReceiver == i ? 1 : 0 : 0; + u8 readyCount = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklReadyCount1[j] : spurs->wklIdleSpuCountOrReadyCount2[j]; + + if (runnable && priority > 0 && maxContention > contention) + { + if (wklFlag || wklSignal || readyCount > contention) + { + foundReadyWorkload = true; + break; + } + } + } + } + else + { + for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) + { + u16 runnable = ctxt->wklRunnable1 & (0x8000 >> i); + u16 wklSignal = spurs->wklSignal1.load() & (0x8000 >> i); + u8 wklFlag = spurs->wklFlag.flag.load() == 0 ? spurs->wklFlagReceiver == i ? 1 : 0 : 0; + u8 readyCount = spurs->wklReadyCount1[i] > CELL_SPURS_MAX_SPU ? CELL_SPURS_MAX_SPU : spurs->wklReadyCount1[i].load(); + u8 idleSpuCount = spurs->wklIdleSpuCountOrReadyCount2[i] > CELL_SPURS_MAX_SPU ? CELL_SPURS_MAX_SPU : spurs->wklIdleSpuCountOrReadyCount2[i].load(); + u8 requestCount = readyCount + idleSpuCount; + + if (runnable && ctxt->priority[i] != 0 && spurs->wklMaxContention[i] > spurs->wklCurrentContention[i]) + { + if (wklFlag || wklSignal || (readyCount != 0 && requestCount > spurs->wklCurrentContention[i])) + { + foundReadyWorkload = true; + break; + } + } + } + } + } + + bool spuIdling = spurs->spuIdling & (1 << ctxt->spuNum) ? true : false; + if (foundReadyWorkload && shouldExit == false) + { + spurs->spuIdling &= ~(1 << ctxt->spuNum); + } + else + { + spurs->spuIdling |= 1 << ctxt->spuNum; + } + + // If all SPUs are idling and the exit_if_no_work flag is set then the SPU thread group must exit. Otherwise wait for external events. + if (spuIdling && shouldExit == false && foundReadyWorkload == false) + { + // The system service blocks by making a reservation and waiting on the lock line reservation lost event. + CHECK_EMU_STATUS; + if (!lock) lock.lock(); + spu.cv.wait_for(lock, std::chrono::milliseconds(1)); + continue; + } + + if (vm::reservation_update(vm::cast(ctxt->spurs.addr(), HERE), vm::base(spu.offset + 0x100), 128) && (shouldExit || foundReadyWorkload)) + { + break; + } + } + + if (shouldExit) + { + // TODO: exit spu thread group + } +} + +// Main function for the system service +void spursSysServiceMain(SPUThread& spu, u32 pollStatus) +{ + auto ctxt = vm::_ptr(spu.offset + 0x100); + + if (!ctxt->spurs.aligned()) + { + LOG_ERROR(SPU, "spursSysServiceMain(): invalid spurs alignment"); + spursHalt(spu); + } + + // Initialise the system service if this is the first time its being started on this SPU + if (ctxt->sysSrvInitialised == 0) + { + ctxt->sysSrvInitialised = 1; + + vm::reservation_acquire(vm::base(spu.offset + 0x100), vm::cast(ctxt->spurs.addr(), HERE), 128); + + vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]() + { + auto spurs = ctxt->spurs.get_ptr_priv(); + + // Halt if already initialised + if (spurs->sysSrvOnSpu & (1 << ctxt->spuNum)) + { + LOG_ERROR(SPU, "spursSysServiceMain(): already initialized"); + spursHalt(spu); + } + + spurs->sysSrvOnSpu |= 1 << ctxt->spuNum; + + std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); + }); + + ctxt->traceBuffer = 0; + ctxt->traceMsgCount = -1; + spursSysServiceTraceUpdate(spu, ctxt, 1, 1, 0); + spursSysServiceCleanupAfterSystemWorkload(spu, ctxt); + + // Trace - SERVICE: INIT + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_SERVICE; + pkt.data.service.incident = CELL_SPURS_TRACE_SERVICE_INIT; + cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); + } + + // Trace - START: Module='SYS ' + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_START; + memcpy(pkt.data.start.module, "SYS ", 4); + pkt.data.start.level = 1; // Policy module + pkt.data.start.ls = 0xA00 >> 2; + cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); + + while (true) + { + CHECK_EMU_STATUS; + // Process requests for the system service + spursSysServiceProcessRequests(spu, ctxt); + + poll: + if (cellSpursModulePollStatus(spu, nullptr)) + { + // Trace - SERVICE: EXIT + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_SERVICE; + pkt.data.service.incident = CELL_SPURS_TRACE_SERVICE_EXIT; + cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); + + // Trace - STOP: GUID + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_STOP; + pkt.data.stop = SPURS_GUID_SYS_WKL; + cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); + + //spursDmaWaitForCompletion(spu, 1 << ctxt->dmaTagId); + break; + } + + // If we reach here it means that either there are more system service messages to be processed + // or there are no workloads that can be scheduled. + + // If the SPU is not idling then process the remaining system service messages + if (ctxt->spuIdling == 0) + { + continue; + } + + // If we reach here it means that the SPU is idling + + // Trace - SERVICE: WAIT + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_SERVICE; + pkt.data.service.incident = CELL_SPURS_TRACE_SERVICE_WAIT; + cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); + + spursSysServiceIdleHandler(spu, ctxt); + CHECK_EMU_STATUS; + + goto poll; + } +} + +// Process any requests +void spursSysServiceProcessRequests(SPUThread& spu, SpursKernelContext* ctxt) +{ + bool updateTrace = false; + bool updateWorkload = false; + bool terminate = false; + + vm::reservation_op(vm::cast(ctxt->spurs.addr() + offsetof(CellSpurs, wklState1), HERE), 128, [&]() + { + auto spurs = ctxt->spurs.get_ptr_priv(); + + // Terminate request + if (spurs->sysSrvMsgTerminate & (1 << ctxt->spuNum)) + { + spurs->sysSrvOnSpu &= ~(1 << ctxt->spuNum); + terminate = true; + } + + // Update workload message + if (spurs->sysSrvMsgUpdateWorkload & (1 << ctxt->spuNum)) + { + spurs->sysSrvMsgUpdateWorkload &= ~(1 << ctxt->spuNum); + updateWorkload = true; + } + + // Update trace message + if (spurs->sysSrvTrace.load().sysSrvMsgUpdateTrace & (1 << ctxt->spuNum)) + { + updateTrace = true; + } + + std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); + }); + + // Process update workload message + if (updateWorkload) + { + spursSysServiceActivateWorkload(spu, ctxt); + } + + // Process update trace message + if (updateTrace) + { + spursSysServiceTraceUpdate(spu, ctxt, 1, 0, 0); + } + + // Process terminate request + if (terminate) + { + // TODO: Rest of the terminate processing + } +} + +// Activate a workload +void spursSysServiceActivateWorkload(SPUThread& spu, SpursKernelContext* ctxt) +{ + auto spurs = vm::_ptr(spu.offset + 0x100); + std::memcpy(vm::base(spu.offset + 0x30000), ctxt->spurs->wklInfo1, 0x200); + if (spurs->flags1 & SF1_32_WORKLOADS) + { + std::memcpy(vm::base(spu.offset + 0x30200), ctxt->spurs->wklInfo2, 0x200); + } + + u32 wklShutdownBitSet = 0; + ctxt->wklRunnable1 = 0; + ctxt->wklRunnable2 = 0; + for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) + { + auto wklInfo1 = vm::_ptr(spu.offset + 0x30000); + + // Copy the priority of the workload for this SPU and its unique id to the LS + ctxt->priority[i] = wklInfo1[i].priority[ctxt->spuNum] == 0 ? 0 : 0x10 - wklInfo1[i].priority[ctxt->spuNum]; + ctxt->wklUniqueId[i] = wklInfo1[i].uniqueId; + + if (spurs->flags1 & SF1_32_WORKLOADS) + { + auto wklInfo2 = vm::_ptr(spu.offset + 0x30200); + + // Copy the priority of the workload for this SPU to the LS + if (wklInfo2[i].priority[ctxt->spuNum]) + { + ctxt->priority[i] |= (0x10 - wklInfo2[i].priority[ctxt->spuNum]) << 4; + } + } + } + + vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]() + { + auto spurs = ctxt->spurs.get_ptr_priv(); + + for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) + { + // Update workload status and runnable flag based on the workload state + auto wklStatus = spurs->wklStatus1[i]; + if (spurs->wklState1[i] == SPURS_WKL_STATE_RUNNABLE) + { + spurs->wklStatus1[i] |= 1 << ctxt->spuNum; + ctxt->wklRunnable1 |= 0x8000 >> i; + } + else + { + spurs->wklStatus1[i] &= ~(1 << ctxt->spuNum); + } + + // If the workload is shutting down and if this is the last SPU from which it is being removed then + // add it to the shutdown bit set + if (spurs->wklState1[i] == SPURS_WKL_STATE_SHUTTING_DOWN) + { + if (((wklStatus & (1 << ctxt->spuNum)) != 0) && (spurs->wklStatus1[i] == 0)) + { + spurs->wklState1[i] = SPURS_WKL_STATE_REMOVABLE; + wklShutdownBitSet |= 0x80000000u >> i; + } + } + + if (spurs->flags1 & SF1_32_WORKLOADS) + { + // Update workload status and runnable flag based on the workload state + wklStatus = spurs->wklStatus2[i]; + if (spurs->wklState2[i] == SPURS_WKL_STATE_RUNNABLE) + { + spurs->wklStatus2[i] |= 1 << ctxt->spuNum; + ctxt->wklRunnable2 |= 0x8000 >> i; + } + else + { + spurs->wklStatus2[i] &= ~(1 << ctxt->spuNum); + } + + // If the workload is shutting down and if this is the last SPU from which it is being removed then + // add it to the shutdown bit set + if (spurs->wklState2[i] == SPURS_WKL_STATE_SHUTTING_DOWN) + { + if (((wklStatus & (1 << ctxt->spuNum)) != 0) && (spurs->wklStatus2[i] == 0)) + { + spurs->wklState2[i] = SPURS_WKL_STATE_REMOVABLE; + wklShutdownBitSet |= 0x8000 >> i; + } + } + } + } + + std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); + }); + + if (wklShutdownBitSet) + { + spursSysServiceUpdateShutdownCompletionEvents(spu, ctxt, wklShutdownBitSet); + } +} + +// Update shutdown completion events +void spursSysServiceUpdateShutdownCompletionEvents(SPUThread& spu, SpursKernelContext* ctxt, u32 wklShutdownBitSet) +{ + // Mark the workloads in wklShutdownBitSet as completed and also generate a bit set of the completed + // workloads that have a shutdown completion hook registered + u32 wklNotifyBitSet; + u8 spuPort; + vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]() + { + auto spurs = ctxt->spurs.get_ptr_priv(); + + wklNotifyBitSet = 0; + spuPort = spurs->spuPort;; + for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) + { + if (wklShutdownBitSet & (0x80000000u >> i)) + { + spurs->wklEvent1[i] |= 0x01; + if (spurs->wklEvent1[i] & 0x02 || spurs->wklEvent1[i] & 0x10) + { + wklNotifyBitSet |= 0x80000000u >> i; + } + } + + if (wklShutdownBitSet & (0x8000 >> i)) + { + spurs->wklEvent2[i] |= 0x01; + if (spurs->wklEvent2[i] & 0x02 || spurs->wklEvent2[i] & 0x10) + { + wklNotifyBitSet |= 0x8000 >> i; + } + } + } + + std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); + }); + + if (wklNotifyBitSet) + { + // TODO: sys_spu_thread_send_event(spuPort, 0, wklNotifyMask); + } +} + +// Update the trace count for this SPU +void spursSysServiceTraceSaveCount(SPUThread& spu, SpursKernelContext* ctxt) +{ + if (ctxt->traceBuffer) + { + auto traceInfo = vm::ptr::make((u32)(ctxt->traceBuffer - (ctxt->spurs->traceStartIndex[ctxt->spuNum] << 4))); + traceInfo->count[ctxt->spuNum] = ctxt->traceMsgCount; + } +} + +// Update trace control +void spursSysServiceTraceUpdate(SPUThread& spu, SpursKernelContext* ctxt, u32 arg2, u32 arg3, u32 forceNotify) +{ + bool notify; + + u8 sysSrvMsgUpdateTrace; + vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]() + { + auto spurs = ctxt->spurs.get_ptr_priv(); + auto& trace = spurs->sysSrvTrace.raw(); + + sysSrvMsgUpdateTrace = trace.sysSrvMsgUpdateTrace; + trace.sysSrvMsgUpdateTrace &= ~(1 << ctxt->spuNum); + trace.sysSrvTraceInitialised &= ~(1 << ctxt->spuNum); + trace.sysSrvTraceInitialised |= arg2 << ctxt->spuNum; + + notify = false; + if (((sysSrvMsgUpdateTrace & (1 << ctxt->spuNum)) != 0) && (spurs->sysSrvTrace.load().sysSrvMsgUpdateTrace == 0) && (spurs->sysSrvTrace.load().sysSrvNotifyUpdateTraceComplete != 0)) + { + trace.sysSrvNotifyUpdateTraceComplete = 0; + notify = true; + } + + if (forceNotify && spurs->sysSrvTrace.load().sysSrvNotifyUpdateTraceComplete != 0) + { + trace.sysSrvNotifyUpdateTraceComplete = 0; + notify = true; + } + + std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); + }); + + // Get trace parameters from CellSpurs and store them in the LS + if (((sysSrvMsgUpdateTrace & (1 << ctxt->spuNum)) != 0) || (arg3 != 0)) + { + vm::reservation_acquire(vm::base(spu.offset + 0x80), ctxt->spurs.ptr(&CellSpurs::traceBuffer).addr(), 128); + auto spurs = vm::_ptr(spu.offset + 0x80 - OFFSET_32(CellSpurs, traceBuffer)); + + if (ctxt->traceMsgCount != 0xFF || spurs->traceBuffer.addr() == 0) + { + spursSysServiceTraceSaveCount(spu, ctxt); + } + else + { + std::memcpy(vm::base(spu.offset + 0x2C00), vm::base(spurs->traceBuffer.addr() & -0x4), 0x80); + auto traceBuffer = vm::_ptr(spu.offset + 0x2C00); + ctxt->traceMsgCount = traceBuffer->count[ctxt->spuNum]; + } + + ctxt->traceBuffer = spurs->traceBuffer.addr() + (spurs->traceStartIndex[ctxt->spuNum] << 4); + ctxt->traceMaxCount = spurs->traceStartIndex[1] - spurs->traceStartIndex[0]; + if (ctxt->traceBuffer == 0) + { + ctxt->traceMsgCount = 0; + } + } + + if (notify) + { + auto spurs = vm::_ptr(spu.offset + 0x2D80 - OFFSET_32(CellSpurs, wklState1)); + sys_spu_thread_send_event(spu, spurs->spuPort, 2, 0); + } +} + +// Restore state after executing the system workload +void spursSysServiceCleanupAfterSystemWorkload(SPUThread& spu, SpursKernelContext* ctxt) +{ + u8 wklId; + + bool do_return = false; + + vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]() + { + auto spurs = ctxt->spurs.get_ptr_priv(); + + if (spurs->sysSrvPreemptWklId[ctxt->spuNum] == 0xFF) + { + do_return = true; + return; + } + + wklId = spurs->sysSrvPreemptWklId[ctxt->spuNum]; + spurs->sysSrvPreemptWklId[ctxt->spuNum] = 0xFF; + + std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); + }); + + if (do_return) return; + + spursSysServiceActivateWorkload(spu, ctxt); + + vm::reservation_op(vm::cast(ctxt->spurs.addr(), HERE), 128, [&]() + { + auto spurs = ctxt->spurs.get_ptr_priv(); + + if (wklId >= CELL_SPURS_MAX_WORKLOAD) + { + spurs->wklCurrentContention[wklId & 0x0F] -= 0x10; + spurs->wklReadyCount1[wklId & 0x0F].raw() -= 1; + } + else + { + spurs->wklCurrentContention[wklId & 0x0F] -= 0x01; + spurs->wklIdleSpuCountOrReadyCount2[wklId & 0x0F].raw() -= 1; + } + + std::memcpy(vm::base(spu.offset + 0x100), spurs, 128); + }); + + // Set the current workload id to the id of the pre-empted workload since cellSpursModulePutTrace + // uses the current worload id to determine the workload to which the trace belongs + auto wklIdSaved = ctxt->wklCurrentId; + ctxt->wklCurrentId = wklId; + + // Trace - STOP: GUID + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_STOP; + pkt.data.stop = SPURS_GUID_SYS_WKL; + cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); + + ctxt->wklCurrentId = wklIdSaved; +} + +//---------------------------------------------------------------------------- +// SPURS taskset policy module functions +//---------------------------------------------------------------------------- + +enum SpursTasksetRequest +{ + SPURS_TASKSET_REQUEST_POLL_SIGNAL = -1, + SPURS_TASKSET_REQUEST_DESTROY_TASK = 0, + SPURS_TASKSET_REQUEST_YIELD_TASK = 1, + SPURS_TASKSET_REQUEST_WAIT_SIGNAL = 2, + SPURS_TASKSET_REQUEST_POLL = 3, + SPURS_TASKSET_REQUEST_WAIT_WKL_FLAG = 4, + SPURS_TASKSET_REQUEST_SELECT_TASK = 5, + SPURS_TASKSET_REQUEST_RECV_WKL_FLAG = 6, +}; + +// Taskset PM entry point +bool spursTasksetEntry(SPUThread& spu) +{ + auto ctxt = vm::_ptr(spu.offset + 0x2700); + auto kernelCtxt = vm::_ptr(spu.offset + spu.gpr[3]._u32[3]); + + auto arg = spu.gpr[4]._u64[1]; + auto pollStatus = spu.gpr[5]._u32[3]; + + // Initialise memory and save args + memset(ctxt, 0, sizeof(*ctxt)); + ctxt->taskset.set(arg); + memcpy(ctxt->moduleId, "SPURSTASK MODULE", sizeof(ctxt->moduleId)); + ctxt->kernelMgmtAddr = spu.gpr[3]._u32[3]; + ctxt->syscallAddr = CELL_SPURS_TASKSET_PM_SYSCALL_ADDR; + ctxt->spuNum = kernelCtxt->spuNum; + ctxt->dmaTagId = kernelCtxt->dmaTagId; + ctxt->taskId = 0xFFFFFFFF; + + // Register SPURS takset policy module HLE functions + spu.UnregisterHleFunctions(CELL_SPURS_TASKSET_PM_ENTRY_ADDR, 0x40000/*LS_BOTTOM*/); + spu.RegisterHleFunction(CELL_SPURS_TASKSET_PM_ENTRY_ADDR, spursTasksetEntry); + spu.RegisterHleFunction(ctxt->syscallAddr, spursTasksetSyscallEntry); + + try + { + // Initialise the taskset policy module + spursTasksetInit(spu, pollStatus); + + // Dispatch + spursTasksetDispatch(spu); + } + catch (SpursModuleExit) + { + } + + return false; +} + +// Entry point into the Taskset PM for task syscalls +bool spursTasksetSyscallEntry(SPUThread& spu) +{ + auto ctxt = vm::_ptr(spu.offset + 0x2700); + + try + { + // Save task context + ctxt->savedContextLr = spu.gpr[0]; + ctxt->savedContextSp = spu.gpr[1]; + for (auto i = 0; i < 48; i++) + { + ctxt->savedContextR80ToR127[i] = spu.gpr[80 + i]; + } + + // Handle the syscall + spu.gpr[3]._u32[3] = spursTasksetProcessSyscall(spu, spu.gpr[3]._u32[3], spu.gpr[4]._u32[3]); + + // Resume the previously executing task if the syscall did not cause a context switch + throw EXCEPTION("Broken (TODO)"); + //if (spu.m_is_branch == false) { + // spursTasksetResumeTask(spu); + //} + } + catch (SpursModuleExit) + { + } + + return false; +} + +// Resume a task +void spursTasksetResumeTask(SPUThread& spu) +{ + auto ctxt = vm::_ptr(spu.offset + 0x2700); + + // Restore task context + spu.gpr[0] = ctxt->savedContextLr; + spu.gpr[1] = ctxt->savedContextSp; + for (auto i = 0; i < 48; i++) + { + spu.gpr[80 + i] = ctxt->savedContextR80ToR127[i]; + } + + spu.pc = spu.gpr[0]._u32[3] - 4; +} + +// Start a task +void spursTasksetStartTask(SPUThread& spu, CellSpursTaskArgument& taskArgs) +{ + auto ctxt = vm::_ptr(spu.offset + 0x2700); + auto taskset = vm::_ptr(spu.offset + 0x2700); + + spu.gpr[2].clear(); + spu.gpr[3] = v128::from64r(taskArgs._u64[0], taskArgs._u64[1]); + spu.gpr[4]._u64[1] = taskset->args; + spu.gpr[4]._u64[0] = taskset->spurs.addr(); + for (auto i = 5; i < 128; i++) + { + spu.gpr[i].clear(); + } + + spu.pc = ctxt->savedContextLr.value()._u32[3] - 4; +} + +// Process a request and update the state of the taskset +s32 spursTasksetProcessRequest(SPUThread& spu, s32 request, u32* taskId, u32* isWaiting) +{ + auto kernelCtxt = vm::_ptr(spu.offset + 0x100); + auto ctxt = vm::_ptr(spu.offset + 0x2700); + + s32 rc = CELL_OK; + s32 numNewlyReadyTasks; + vm::reservation_op(vm::cast(ctxt->taskset.addr(), HERE), 128, [&]() + { + auto taskset = ctxt->taskset.get_ptr_priv(); + + // Verify taskset state is valid + be_t _0(v128::from32(0)); + if ((taskset->waiting & taskset->running) != _0 || (taskset->ready & taskset->pending_ready) != _0 || + ((taskset->running | taskset->ready | taskset->pending_ready | taskset->signalled | taskset->waiting) & ~taskset->enabled) != _0) + { + LOG_ERROR(SPU, "Invalid taskset state"); + spursHalt(spu); + } + + // Find the number of tasks that have become ready since the last iteration + auto newlyReadyTasks = (taskset->signalled | taskset->pending_ready) & ~taskset->ready.value(); + numNewlyReadyTasks = 0; + for (auto i = 0; i < 128; i++) + { + if (newlyReadyTasks._bit[i]) + { + numNewlyReadyTasks++; + } + } + + v128 readyButNotRunning; + u8 selectedTaskId; + v128 running = taskset->running.value(); + v128 waiting = taskset->waiting.value(); + v128 enabled = taskset->enabled.value(); + v128 signalled = (taskset->signalled & (taskset->ready | taskset->pending_ready)); + v128 ready = (taskset->signalled | taskset->ready | taskset->pending_ready); + + switch (request) + { + case SPURS_TASKSET_REQUEST_POLL_SIGNAL: + rc = signalled._bit[ctxt->taskId] ? 1 : 0; + signalled._bit[ctxt->taskId] = false; + break; + case SPURS_TASKSET_REQUEST_DESTROY_TASK: + numNewlyReadyTasks--; + running._bit[ctxt->taskId] = false; + enabled._bit[ctxt->taskId] = false; + signalled._bit[ctxt->taskId] = false; + ready._bit[ctxt->taskId] = false; + break; + case SPURS_TASKSET_REQUEST_YIELD_TASK: + running._bit[ctxt->taskId] = false; + waiting._bit[ctxt->taskId] = true; + break; + case SPURS_TASKSET_REQUEST_WAIT_SIGNAL: + if (signalled._bit[ctxt->taskId] == false) + { + numNewlyReadyTasks--; + running._bit[ctxt->taskId] = false; + waiting._bit[ctxt->taskId] = true; + signalled._bit[ctxt->taskId] = false; + ready._bit[ctxt->taskId] = false; + } + break; + case SPURS_TASKSET_REQUEST_POLL: + readyButNotRunning = ready & ~running; + if (taskset->wkl_flag_wait_task < CELL_SPURS_MAX_TASK) + { + readyButNotRunning = readyButNotRunning & ~(v128::fromBit(taskset->wkl_flag_wait_task)); + } + + rc = readyButNotRunning != _0 ? 1 : 0; + break; + case SPURS_TASKSET_REQUEST_WAIT_WKL_FLAG: + if (taskset->wkl_flag_wait_task == 0x81) + { + // A workload flag is already pending so consume it + taskset->wkl_flag_wait_task = 0x80; + rc = 0; + } + else if (taskset->wkl_flag_wait_task == 0x80) + { + // No tasks are waiting for the workload flag. Mark this task as waiting for the workload flag. + taskset->wkl_flag_wait_task = ctxt->taskId; + running._bit[ctxt->taskId] = false; + waiting._bit[ctxt->taskId] = true; + rc = 1; + numNewlyReadyTasks--; + } + else + { + // Another task is already waiting for the workload signal + rc = CELL_SPURS_TASK_ERROR_BUSY; + } + break; + case SPURS_TASKSET_REQUEST_SELECT_TASK: + readyButNotRunning = ready & ~running; + if (taskset->wkl_flag_wait_task < CELL_SPURS_MAX_TASK) + { + readyButNotRunning = readyButNotRunning & ~(v128::fromBit(taskset->wkl_flag_wait_task)); + } + + // Select a task from the readyButNotRunning set to run. Start from the task after the last scheduled task to ensure fairness. + for (selectedTaskId = taskset->last_scheduled_task + 1; selectedTaskId < 128; selectedTaskId++) + { + if (readyButNotRunning._bit[selectedTaskId]) + { + break; + } + } + + if (selectedTaskId == 128) + { + for (selectedTaskId = 0; selectedTaskId < taskset->last_scheduled_task + 1; selectedTaskId++) + { + if (readyButNotRunning._bit[selectedTaskId]) + { + break; + } + } + + if (selectedTaskId == taskset->last_scheduled_task + 1) + { + selectedTaskId = CELL_SPURS_MAX_TASK; + } + } + + *taskId = selectedTaskId; + *isWaiting = waiting._bit[selectedTaskId < CELL_SPURS_MAX_TASK ? selectedTaskId : 0] ? 1 : 0; + if (selectedTaskId != CELL_SPURS_MAX_TASK) + { + taskset->last_scheduled_task = selectedTaskId; + running._bit[selectedTaskId] = true; + waiting._bit[selectedTaskId] = false; + } + break; + case SPURS_TASKSET_REQUEST_RECV_WKL_FLAG: + if (taskset->wkl_flag_wait_task < CELL_SPURS_MAX_TASK) + { + // There is a task waiting for the workload flag + taskset->wkl_flag_wait_task = 0x80; + rc = 1; + numNewlyReadyTasks++; + } + else + { + // No tasks are waiting for the workload flag + taskset->wkl_flag_wait_task = 0x81; + rc = 0; + } + break; + default: + LOG_ERROR(SPU, "Unknown taskset request"); + spursHalt(spu); + } + + taskset->pending_ready = _0; + taskset->running = running; + taskset->waiting = waiting; + taskset->enabled = enabled; + taskset->signalled = signalled; + taskset->ready = ready; + + std::memcpy(vm::base(spu.offset + 0x2700), taskset, 128); + }); + + // Increment the ready count of the workload by the number of tasks that have become ready + vm::reservation_op(vm::cast(kernelCtxt->spurs.addr(), HERE), 128, [&]() + { + auto spurs = kernelCtxt->spurs.get_ptr_priv(); + + s32 readyCount = kernelCtxt->wklCurrentId < CELL_SPURS_MAX_WORKLOAD ? spurs->wklReadyCount1[kernelCtxt->wklCurrentId].load() : spurs->wklIdleSpuCountOrReadyCount2[kernelCtxt->wklCurrentId & 0x0F].load(); + readyCount += numNewlyReadyTasks; + readyCount = readyCount < 0 ? 0 : readyCount > 0xFF ? 0xFF : readyCount; + + if (kernelCtxt->wklCurrentId < CELL_SPURS_MAX_WORKLOAD) + { + spurs->wklReadyCount1[kernelCtxt->wklCurrentId] = readyCount; + } + else + { + spurs->wklIdleSpuCountOrReadyCount2[kernelCtxt->wklCurrentId & 0x0F] = readyCount; + } + + std::memcpy(vm::base(spu.offset + 0x100), spurs, 128); + }); + + return rc; +} + +// Process pollStatus received from the SPURS kernel +void spursTasksetProcessPollStatus(SPUThread& spu, u32 pollStatus) +{ + if (pollStatus & CELL_SPURS_MODULE_POLL_STATUS_FLAG) + { + spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_RECV_WKL_FLAG, nullptr, nullptr); + } +} + +// Check execution rights +bool spursTasksetPollStatus(SPUThread& spu) +{ + u32 pollStatus; + + if (cellSpursModulePollStatus(spu, &pollStatus)) + { + return true; + } + + spursTasksetProcessPollStatus(spu, pollStatus); + return false; +} + +// Exit the Taskset PM +void spursTasksetExit(SPUThread& spu) +{ + auto ctxt = vm::_ptr(spu.offset + 0x2700); + + // Trace - STOP + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = 0x54; // Its not clear what this tag means exactly but it seems similar to CELL_SPURS_TRACE_TAG_STOP + pkt.data.stop = SPURS_GUID_TASKSET_PM; + cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); + + // Not sure why this check exists. Perhaps to check for memory corruption. + if (memcmp(ctxt->moduleId, "SPURSTASK MODULE", 16) != 0) + { + LOG_ERROR(SPU, "spursTasksetExit(): memory corruption"); + spursHalt(spu); + } + + cellSpursModuleExit(spu); +} + +// Invoked when a task exits +void spursTasksetOnTaskExit(SPUThread& spu, u64 addr, u32 taskId, s32 exitCode, u64 args) +{ + auto ctxt = vm::_ptr(spu.offset + 0x2700); + + std::memcpy(vm::base(spu.offset + 0x10000), vm::base(addr & -0x80), (addr & 0x7F) << 11); + + spu.gpr[3]._u64[1] = ctxt->taskset.addr(); + spu.gpr[4]._u32[3] = taskId; + spu.gpr[5]._u32[3] = exitCode; + spu.gpr[6]._u64[1] = args; + spu.fast_call(0x10000); +} + +// Save the context of a task +s32 spursTasketSaveTaskContext(SPUThread& spu) +{ + auto ctxt = vm::_ptr(spu.offset + 0x2700); + auto taskInfo = vm::_ptr(spu.offset + 0x2780); + + //spursDmaWaitForCompletion(spu, 0xFFFFFFFF); + + if (taskInfo->context_save_storage_and_alloc_ls_blocks == 0) + { + return CELL_SPURS_TASK_ERROR_STAT; + } + + u32 allocLsBlocks = taskInfo->context_save_storage_and_alloc_ls_blocks & 0x7F; + u32 lsBlocks = 0; + v128 ls_pattern = v128::from64r(taskInfo->ls_pattern._u64[0], taskInfo->ls_pattern._u64[1]); + for (auto i = 0; i < 128; i++) + { + if (ls_pattern._bit[i]) + { + lsBlocks++; + } + } + + if (lsBlocks > allocLsBlocks) + { + return CELL_SPURS_TASK_ERROR_STAT; + } + + // Make sure the stack is area is specified in the ls pattern + for (auto i = (ctxt->savedContextSp.value()._u32[3]) >> 11; i < 128; i++) + { + if (ls_pattern._bit[i] == false) + { + return CELL_SPURS_TASK_ERROR_STAT; + } + } + + // Get the processor context + v128 r; + spu.fpscr.Read(r); + ctxt->savedContextFpscr = r; + ctxt->savedSpuWriteEventMask = spu.get_ch_value(SPU_RdEventMask); + ctxt->savedWriteTagGroupQueryMask = spu.get_ch_value(MFC_RdTagMask); + + // Store the processor context + const u32 contextSaveStorage = vm::cast(taskInfo->context_save_storage_and_alloc_ls_blocks & -0x80, HERE); + std::memcpy(vm::base(contextSaveStorage), vm::base(spu.offset + 0x2C80), 0x380); + + // Save LS context + for (auto i = 6; i < 128; i++) + { + if (ls_pattern._bit[i]) + { + // TODO: Combine DMA requests for consecutive blocks into a single request + std::memcpy(vm::base(contextSaveStorage + 0x400 + ((i - 6) << 11)), vm::base(spu.offset + CELL_SPURS_TASK_TOP + ((i - 6) << 11)), 0x800); + } + } + + //spursDmaWaitForCompletion(spu, 1 << ctxt->dmaTagId); + return CELL_OK; +} + +// Taskset dispatcher +void spursTasksetDispatch(SPUThread& spu) +{ + auto ctxt = vm::_ptr(spu.offset + 0x2700); + auto taskset = vm::_ptr(spu.offset + 0x2700); + + u32 taskId; + u32 isWaiting; + spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_SELECT_TASK, &taskId, &isWaiting); + if (taskId >= CELL_SPURS_MAX_TASK) + { + spursTasksetExit(spu); + return; + } + + ctxt->taskId = taskId; + + // DMA in the task info for the selected task + std::memcpy(vm::base(spu.offset + 0x2780), &ctxt->taskset->task_info[taskId], sizeof(CellSpursTaskset::TaskInfo)); + auto taskInfo = vm::_ptr(spu.offset + 0x2780); + auto elfAddr = taskInfo->elf.addr().value(); + taskInfo->elf.set(taskInfo->elf.addr() & 0xFFFFFFFFFFFFFFF8); + + // Trace - Task: Incident=dispatch + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_TASK; + pkt.data.task.incident = CELL_SPURS_TRACE_TASK_DISPATCH; + pkt.data.task.taskId = taskId; + cellSpursModulePutTrace(&pkt, CELL_SPURS_KERNEL_DMA_TAG_ID); + + if (isWaiting == 0) + { + // If we reach here it means that the task is being started and not being resumed + std::memset(vm::base(spu.offset + CELL_SPURS_TASK_TOP), 0, CELL_SPURS_TASK_BOTTOM - CELL_SPURS_TASK_TOP); + ctxt->guidAddr = CELL_SPURS_TASK_TOP; + + u32 entryPoint; + u32 lowestLoadAddr; + if (spursTasksetLoadElf(spu, &entryPoint, &lowestLoadAddr, taskInfo->elf.addr(), false) != CELL_OK) + { + LOG_ERROR(SPU, "spursTaskLoadElf() failed"); + spursHalt(spu); + } + + //spursDmaWaitForCompletion(spu, 1 << ctxt->dmaTagId); + + ctxt->savedContextLr = v128::from32r(entryPoint); + ctxt->guidAddr = lowestLoadAddr; + ctxt->tasksetMgmtAddr = 0x2700; + ctxt->x2FC0 = 0; + ctxt->taskExitCode = isWaiting; + ctxt->x2FD4 = elfAddr & 5; // TODO: Figure this out + + if ((elfAddr & 5) == 1) + { + std::memcpy(vm::base(spu.offset + 0x2FC0), &((CellSpursTaskset2*)(ctxt->taskset.get_ptr()))->task_exit_code[taskId], 0x10); + } + + // Trace - GUID + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_GUID; + pkt.data.guid = 0; // TODO: Put GUID of taskId here + cellSpursModulePutTrace(&pkt, 0x1F); + + if (elfAddr & 2) + { + // TODO: Figure this out + spu.status |= SPU_STATUS_STOPPED_BY_STOP; + throw cpu_state::stop; + } + + spursTasksetStartTask(spu, taskInfo->args); + } + else + { + if (taskset->enable_clear_ls) + { + std::memset(vm::base(spu.offset + CELL_SPURS_TASK_TOP), 0, CELL_SPURS_TASK_BOTTOM - CELL_SPURS_TASK_TOP); + } + + // If the entire LS is saved then there is no need to load the ELF as it will be be saved in the context save area as well + v128 ls_pattern = v128::from64r(taskInfo->ls_pattern._u64[0], taskInfo->ls_pattern._u64[1]); + if (ls_pattern != v128::from64r(0x03FFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull)) + { + // Load the ELF + u32 entryPoint; + if (spursTasksetLoadElf(spu, &entryPoint, nullptr, taskInfo->elf.addr(), true) != CELL_OK) + { + LOG_ERROR(SPU, "spursTasksetLoadElf() failed"); + spursHalt(spu); + } + } + + // Load saved context from main memory to LS + const u32 contextSaveStorage = vm::cast(taskInfo->context_save_storage_and_alloc_ls_blocks & -0x80, HERE); + std::memcpy(vm::base(spu.offset + 0x2C80), vm::base(contextSaveStorage), 0x380); + for (auto i = 6; i < 128; i++) + { + if (ls_pattern._bit[i]) + { + // TODO: Combine DMA requests for consecutive blocks into a single request + std::memcpy(vm::base(spu.offset + CELL_SPURS_TASK_TOP + ((i - 6) << 11)), vm::base(contextSaveStorage + 0x400 + ((i - 6) << 11)), 0x800); + } + } + + //spursDmaWaitForCompletion(spu, 1 << ctxt->dmaTagId); + + // Restore saved registers + spu.fpscr.Write(ctxt->savedContextFpscr.value()); + spu.set_ch_value(MFC_WrTagMask, ctxt->savedWriteTagGroupQueryMask); + spu.set_ch_value(SPU_WrEventMask, ctxt->savedSpuWriteEventMask); + + // Trace - GUID + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_GUID; + pkt.data.guid = 0; // TODO: Put GUID of taskId here + cellSpursModulePutTrace(&pkt, 0x1F); + + if (elfAddr & 2) + { + // TODO: Figure this out + spu.status |= SPU_STATUS_STOPPED_BY_STOP; + throw cpu_state::stop; + } + + spu.gpr[3].clear(); + spursTasksetResumeTask(spu); + } +} + +// Process a syscall request +s32 spursTasksetProcessSyscall(SPUThread& spu, u32 syscallNum, u32 args) +{ + auto ctxt = vm::_ptr(spu.offset + 0x2700); + auto taskset = vm::_ptr(spu.offset + 0x2700); + + // If the 0x10 bit is set in syscallNum then its the 2nd version of the + // syscall (e.g. cellSpursYield2 instead of cellSpursYield) and so don't wait + // for DMA completion + if ((syscallNum & 0x10) == 0) + { + //spursDmaWaitForCompletion(spu, 0xFFFFFFFF); + } + + s32 rc = 0; + u32 incident = 0; + switch (syscallNum & 0x0F) + { + case CELL_SPURS_TASK_SYSCALL_EXIT: + if (ctxt->x2FD4 == 4 || (ctxt->x2FC0 & 0xFFFFFFFF) != 0) + { // TODO: Figure this out + if (ctxt->x2FD4 != 4) + { + spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_DESTROY_TASK, nullptr, nullptr); + } + + const u64 addr = ctxt->x2FD4 == 4 ? taskset->x78 : ctxt->x2FC0; + const u64 args = ctxt->x2FD4 == 4 ? 0 : ctxt->x2FC8.value(); + spursTasksetOnTaskExit(spu, addr, ctxt->taskId, ctxt->taskExitCode, args); + } + + incident = CELL_SPURS_TRACE_TASK_EXIT; + break; + case CELL_SPURS_TASK_SYSCALL_YIELD: + if (spursTasksetPollStatus(spu) || spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_POLL, nullptr, nullptr)) + { + // If we reach here then it means that either another task can be scheduled or another workload can be scheduled + // Save the context of the current task + rc = spursTasketSaveTaskContext(spu); + if (rc == CELL_OK) + { + spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_YIELD_TASK, nullptr, nullptr); + incident = CELL_SPURS_TRACE_TASK_YIELD; + } + } + break; + case CELL_SPURS_TASK_SYSCALL_WAIT_SIGNAL: + if (spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_POLL_SIGNAL, nullptr, nullptr) == 0) + { + rc = spursTasketSaveTaskContext(spu); + if (rc == CELL_OK) + { + if (spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_WAIT_SIGNAL, nullptr, nullptr) == 0) + { + incident = CELL_SPURS_TRACE_TASK_WAIT; + } + } + } + break; + case CELL_SPURS_TASK_SYSCALL_POLL: + rc = spursTasksetPollStatus(spu) ? CELL_SPURS_TASK_POLL_FOUND_WORKLOAD : 0; + rc |= spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_POLL, nullptr, nullptr) ? CELL_SPURS_TASK_POLL_FOUND_TASK : 0; + break; + case CELL_SPURS_TASK_SYSCALL_RECV_WKL_FLAG: + if (args == 0) + { // TODO: Figure this out + LOG_ERROR(SPU, "args == 0"); + //spursHalt(spu); + } + + if (spursTasksetPollStatus(spu) || spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_WAIT_WKL_FLAG, nullptr, nullptr) != 1) + { + rc = spursTasketSaveTaskContext(spu); + if (rc == CELL_OK) + { + incident = CELL_SPURS_TRACE_TASK_WAIT; + } + } + break; + default: + rc = CELL_SPURS_TASK_ERROR_NOSYS; + break; + } + + if (incident) + { + // Trace - TASK + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = CELL_SPURS_TRACE_TAG_TASK; + pkt.data.task.incident = incident; + pkt.data.task.taskId = ctxt->taskId; + cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); + + // Clear the GUID of the task + std::memset(vm::base(spu.offset + ctxt->guidAddr), 0, 0x10); + + if (spursTasksetPollStatus(spu)) + { + spursTasksetExit(spu); + } + else + { + spursTasksetDispatch(spu); + } + } + + return rc; +} + +// Initialise the Taskset PM +void spursTasksetInit(SPUThread& spu, u32 pollStatus) +{ + auto ctxt = vm::_ptr(spu.offset + 0x2700); + auto kernelCtxt = vm::_ptr(spu.offset + 0x100); + + kernelCtxt->moduleId[0] = 'T'; + kernelCtxt->moduleId[1] = 'K'; + + // Trace - START: Module='TKST' + CellSpursTracePacket pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.header.tag = 0x52; // Its not clear what this tag means exactly but it seems similar to CELL_SPURS_TRACE_TAG_START + memcpy(pkt.data.start.module, "TKST", 4); + pkt.data.start.level = 2; + pkt.data.start.ls = 0xA00 >> 2; + cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); + + spursTasksetProcessPollStatus(spu, pollStatus); +} + +// Load an ELF +s32 spursTasksetLoadElf(SPUThread& spu, u32* entryPoint, u32* lowestLoadAddr, u64 elfAddr, bool skipWriteableSegments) +{ + if (elfAddr == 0 || (elfAddr & 0x0F) != 0) + { + return CELL_SPURS_TASK_ERROR_INVAL; + } + + const spu_exec_loader loader(fs::file(vm::base(vm::cast(elfAddr, HERE)), u32(0 - elfAddr))); + + if (loader != elf_error::ok) + { + return CELL_SPURS_TASK_ERROR_NOEXEC; + } + + u32 _lowestLoadAddr = CELL_SPURS_TASK_BOTTOM; + for (const auto& prog : loader.progs) + { + if (prog.p_paddr >= CELL_SPURS_TASK_BOTTOM) + { + break; + } + + if (prog.p_type == 1 /* PT_LOAD */) + { + if (skipWriteableSegments == false || (prog.p_flags & 2 /*PF_W*/ ) == 0) + { + if (prog.p_vaddr < CELL_SPURS_TASK_TOP || prog.p_vaddr + prog.p_memsz > CELL_SPURS_TASK_BOTTOM) + { + return CELL_SPURS_TASK_ERROR_FAULT; + } + + _lowestLoadAddr > prog.p_vaddr ? _lowestLoadAddr = prog.p_vaddr : _lowestLoadAddr; + } + } + } + + for (const auto& prog : loader.progs) + { + if (prog.p_paddr >= CELL_SPURS_TASK_BOTTOM) // ??? + { + break; + } + + if (prog.p_type == 1) + { + if (skipWriteableSegments == false || (prog.p_flags & 2) == 0) + { + std::memcpy(vm::base(spu.offset + prog.p_vaddr), prog.bin.data(), prog.p_filesz); + } + } + } + + *entryPoint = loader.header.e_entry; + if (lowestLoadAddr) *lowestLoadAddr = _lowestLoadAddr; + + return CELL_OK; +} diff --git a/rpcs3/Emu/SysCalls/Modules/cellSsl.cpp b/rpcs3/Emu/Cell/Modules/cellSsl.cpp similarity index 93% rename from rpcs3/Emu/SysCalls/Modules/cellSsl.cpp rename to rpcs3/Emu/Cell/Modules/cellSsl.cpp index eaac5d7760..ab14c7fedd 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSsl.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSsl.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellSsl; +LOG_CHANNEL(cellSsl); s32 cellSslInit() { @@ -88,7 +87,7 @@ s32 cellSslCertGetMd5Fingerprint() return CELL_OK; } -Module<> cellSsl("cellSsl", []() +DECLARE(ppu_module_manager::cellSsl)("cellSsl", []() { REG_FUNC(cellSsl, cellSslInit); REG_FUNC(cellSsl, cellSslEnd); diff --git a/rpcs3/Emu/SysCalls/Modules/cellStorage.cpp b/rpcs3/Emu/Cell/Modules/cellStorage.cpp similarity index 79% rename from rpcs3/Emu/SysCalls/Modules/cellStorage.cpp rename to rpcs3/Emu/Cell/Modules/cellStorage.cpp index 07ce05e6a5..894f33cf4a 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellStorage.cpp +++ b/rpcs3/Emu/Cell/Modules/cellStorage.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellSysutil; +extern _log::channel cellSysutil; s32 cellStorageDataImportMove() { diff --git a/rpcs3/Emu/SysCalls/Modules/cellSubdisplay.cpp b/rpcs3/Emu/Cell/Modules/cellSubdisplay.cpp similarity index 92% rename from rpcs3/Emu/SysCalls/Modules/cellSubdisplay.cpp rename to rpcs3/Emu/Cell/Modules/cellSubdisplay.cpp index 230adbc86f..6f971a4923 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSubdisplay.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSubdisplay.cpp @@ -1,10 +1,9 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellSubdisplay.h" -extern Module<> cellSubdisplay; +LOG_CHANNEL(cellSubdisplay); s32 cellSubDisplayInit() { @@ -74,7 +73,7 @@ s32 cellSubDisplayGetPeerList() return CELL_OK; } -Module<> cellSubdisplay("cellSubdisplay", []() +DECLARE(ppu_module_manager::cellSubdisplay)("cellSubdisplay", []() { REG_FUNC(cellSubdisplay, cellSubDisplayInit); REG_FUNC(cellSubdisplay, cellSubDisplayEnd); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSubdisplay.h b/rpcs3/Emu/Cell/Modules/cellSubdisplay.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellSubdisplay.h rename to rpcs3/Emu/Cell/Modules/cellSubdisplay.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp b/rpcs3/Emu/Cell/Modules/cellSync.cpp similarity index 79% rename from rpcs3/Emu/SysCalls/Modules/cellSync.cpp rename to rpcs3/Emu/Cell/Modules/cellSync.cpp index c01f8d4ddf..83ada37380 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSync.cpp @@ -1,17 +1,32 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/SysCalls/lv2/sys_sync.h" -#include "Emu/SysCalls/lv2/sys_event.h" -#include "Emu/SysCalls/lv2/sys_process.h" -#include "Emu/Event.h" +#include "Emu/Cell/lv2/sys_event.h" +#include "Emu/Cell/lv2/sys_process.h" #include "cellSync.h" -extern Module<> cellSync; +LOG_CHANNEL(cellSync); -s32 cellSyncMutexInitialize(vm::ptr mutex) +namespace _sync +{ + static inline be_t mutex_acquire(mutex& ctrl) + { + return ctrl.acq++; + } + + static inline bool mutex_try_lock(mutex& ctrl) + { + return ctrl.acq++ == ctrl.rel; + } + + static inline void mutex_unlock(mutex& ctrl) + { + ctrl.rel++; + } +} + +ppu_error_code cellSyncMutexInitialize(vm::ptr mutex) { cellSync.trace("cellSyncMutexInitialize(mutex=*0x%x)", mutex); @@ -30,7 +45,7 @@ s32 cellSyncMutexInitialize(vm::ptr mutex) return CELL_OK; } -s32 cellSyncMutexLock(PPUThread& ppu, vm::ptr mutex) +ppu_error_code cellSyncMutexLock(PPUThread& ppu, vm::ptr mutex) { cellSync.trace("cellSyncMutexLock(mutex=*0x%x)", mutex); @@ -45,7 +60,7 @@ s32 cellSyncMutexLock(PPUThread& ppu, vm::ptr mutex) } // increase acq value and remember its old value - const auto order = mutex->ctrl.atomic_op(_sync::mutex::acquire); + const auto order = mutex->ctrl.atomic_op(_sync::mutex_acquire); // wait until rel value is equal to old acq value vm::wait_op(ppu, mutex.addr(), 4, WRAP_EXPR(mutex->ctrl.load().rel == order)); @@ -55,7 +70,7 @@ s32 cellSyncMutexLock(PPUThread& ppu, vm::ptr mutex) return CELL_OK; } -s32 cellSyncMutexTryLock(vm::ptr mutex) +ppu_error_code cellSyncMutexTryLock(vm::ptr mutex) { cellSync.trace("cellSyncMutexTryLock(mutex=*0x%x)", mutex); @@ -69,15 +84,15 @@ s32 cellSyncMutexTryLock(vm::ptr mutex) return CELL_SYNC_ERROR_ALIGN; } - if (!mutex->ctrl.atomic_op(_sync::mutex::try_lock)) + if (!mutex->ctrl.atomic_op(_sync::mutex_try_lock)) { - return CELL_SYNC_ERROR_BUSY; + return NOT_AN_ERROR(CELL_SYNC_ERROR_BUSY); } return CELL_OK; } -s32 cellSyncMutexUnlock(vm::ptr mutex) +ppu_error_code cellSyncMutexUnlock(vm::ptr mutex) { cellSync.trace("cellSyncMutexUnlock(mutex=*0x%x)", mutex); @@ -91,14 +106,14 @@ s32 cellSyncMutexUnlock(vm::ptr mutex) return CELL_SYNC_ERROR_ALIGN; } - mutex->ctrl.atomic_op(_sync::mutex::unlock); + mutex->ctrl.atomic_op(_sync::mutex_unlock); vm::notify_at(mutex); return CELL_OK; } -s32 cellSyncBarrierInitialize(vm::ptr barrier, u16 total_count) +ppu_error_code cellSyncBarrierInitialize(vm::ptr barrier, u16 total_count) { cellSync.trace("cellSyncBarrierInitialize(barrier=*0x%x, total_count=%d)", barrier, total_count); @@ -123,7 +138,7 @@ s32 cellSyncBarrierInitialize(vm::ptr barrier, u16 total_count) return CELL_OK; } -s32 cellSyncBarrierNotify(PPUThread& ppu, vm::ptr barrier) +ppu_error_code cellSyncBarrierNotify(PPUThread& ppu, vm::ptr barrier) { cellSync.trace("cellSyncBarrierNotify(barrier=*0x%x)", barrier); @@ -144,7 +159,7 @@ s32 cellSyncBarrierNotify(PPUThread& ppu, vm::ptr barrier) return CELL_OK; } -s32 cellSyncBarrierTryNotify(vm::ptr barrier) +ppu_error_code cellSyncBarrierTryNotify(vm::ptr barrier) { cellSync.trace("cellSyncBarrierTryNotify(barrier=*0x%x)", barrier); @@ -162,7 +177,7 @@ s32 cellSyncBarrierTryNotify(vm::ptr barrier) if (!barrier->ctrl.atomic_op(_sync::barrier::try_notify)) { - return CELL_SYNC_ERROR_BUSY; + return NOT_AN_ERROR(CELL_SYNC_ERROR_BUSY); } vm::notify_at(barrier); @@ -170,7 +185,7 @@ s32 cellSyncBarrierTryNotify(vm::ptr barrier) return CELL_OK; } -s32 cellSyncBarrierWait(PPUThread& ppu, vm::ptr barrier) +ppu_error_code cellSyncBarrierWait(PPUThread& ppu, vm::ptr barrier) { cellSync.trace("cellSyncBarrierWait(barrier=*0x%x)", barrier); @@ -193,7 +208,7 @@ s32 cellSyncBarrierWait(PPUThread& ppu, vm::ptr barrier) return CELL_OK; } -s32 cellSyncBarrierTryWait(vm::ptr barrier) +ppu_error_code cellSyncBarrierTryWait(vm::ptr barrier) { cellSync.trace("cellSyncBarrierTryWait(barrier=*0x%x)", barrier); @@ -211,7 +226,7 @@ s32 cellSyncBarrierTryWait(vm::ptr barrier) if (!barrier->ctrl.atomic_op(_sync::barrier::try_wait)) { - return CELL_SYNC_ERROR_BUSY; + return NOT_AN_ERROR(CELL_SYNC_ERROR_BUSY); } vm::notify_at(barrier); @@ -219,7 +234,7 @@ s32 cellSyncBarrierTryWait(vm::ptr barrier) return CELL_OK; } -s32 cellSyncRwmInitialize(vm::ptr rwm, vm::ptr buffer, u32 buffer_size) +ppu_error_code cellSyncRwmInitialize(vm::ptr rwm, vm::ptr buffer, u32 buffer_size) { cellSync.trace("cellSyncRwmInitialize(rwm=*0x%x, buffer=*0x%x, buffer_size=0x%x)", rwm, buffer, buffer_size); @@ -248,7 +263,7 @@ s32 cellSyncRwmInitialize(vm::ptr rwm, vm::ptr buffer, u32 bu return CELL_OK; } -s32 cellSyncRwmRead(PPUThread& ppu, vm::ptr rwm, vm::ptr buffer) +ppu_error_code cellSyncRwmRead(PPUThread& ppu, vm::ptr rwm, vm::ptr buffer) { cellSync.trace("cellSyncRwmRead(rwm=*0x%x, buffer=*0x%x)", rwm, buffer); @@ -279,7 +294,7 @@ s32 cellSyncRwmRead(PPUThread& ppu, vm::ptr rwm, vm::ptr buff return CELL_OK; } -s32 cellSyncRwmTryRead(vm::ptr rwm, vm::ptr buffer) +ppu_error_code cellSyncRwmTryRead(vm::ptr rwm, vm::ptr buffer) { cellSync.trace("cellSyncRwmTryRead(rwm=*0x%x, buffer=*0x%x)", rwm, buffer); @@ -296,7 +311,7 @@ s32 cellSyncRwmTryRead(vm::ptr rwm, vm::ptr buffer) // increase `readers` if `writers` is zero if (!rwm->ctrl.atomic_op(_sync::rwlock::try_read_begin)) { - return CELL_SYNC_ERROR_BUSY; + return NOT_AN_ERROR(CELL_SYNC_ERROR_BUSY); } // copy data to buffer @@ -313,7 +328,7 @@ s32 cellSyncRwmTryRead(vm::ptr rwm, vm::ptr buffer) return CELL_OK; } -s32 cellSyncRwmWrite(PPUThread& ppu, vm::ptr rwm, vm::cptr buffer) +ppu_error_code cellSyncRwmWrite(PPUThread& ppu, vm::ptr rwm, vm::cptr buffer) { cellSync.trace("cellSyncRwmWrite(rwm=*0x%x, buffer=*0x%x)", rwm, buffer); @@ -344,7 +359,7 @@ s32 cellSyncRwmWrite(PPUThread& ppu, vm::ptr rwm, vm::cptr bu return CELL_OK; } -s32 cellSyncRwmTryWrite(vm::ptr rwm, vm::cptr buffer) +ppu_error_code cellSyncRwmTryWrite(vm::ptr rwm, vm::cptr buffer) { cellSync.trace("cellSyncRwmTryWrite(rwm=*0x%x, buffer=*0x%x)", rwm, buffer); @@ -361,7 +376,7 @@ s32 cellSyncRwmTryWrite(vm::ptr rwm, vm::cptr buffer) // set `writers` to 1 if `readers` and `writers` are zero if (!rwm->ctrl.compare_and_swap_test({ 0, 0 }, { 0, 1 })) { - return CELL_SYNC_ERROR_BUSY; + return NOT_AN_ERROR(CELL_SYNC_ERROR_BUSY); } // copy data from buffer @@ -375,7 +390,7 @@ s32 cellSyncRwmTryWrite(vm::ptr rwm, vm::cptr buffer) return CELL_OK; } -s32 cellSyncQueueInitialize(vm::ptr queue, vm::ptr buffer, u32 size, u32 depth) +ppu_error_code cellSyncQueueInitialize(vm::ptr queue, vm::ptr buffer, u32 size, u32 depth) { cellSync.trace("cellSyncQueueInitialize(queue=*0x%x, buffer=*0x%x, size=0x%x, depth=0x%x)", queue, buffer, size, depth); @@ -410,7 +425,7 @@ s32 cellSyncQueueInitialize(vm::ptr queue, vm::ptr buffer, u3 return CELL_OK; } -s32 cellSyncQueuePush(PPUThread& ppu, vm::ptr queue, vm::cptr buffer) +ppu_error_code cellSyncQueuePush(PPUThread& ppu, vm::ptr queue, vm::cptr buffer) { cellSync.trace("cellSyncQueuePush(queue=*0x%x, buffer=*0x%x)", queue, buffer); @@ -428,20 +443,20 @@ s32 cellSyncQueuePush(PPUThread& ppu, vm::ptr queue, vm::cptrctrl.atomic_op(_sync::queue::try_push_begin, depth, position))); + vm::wait_op(ppu, queue.addr(), 8, WRAP_EXPR(queue->ctrl.atomic_op(_sync::queue::try_push_begin, depth, &position))); // copy data from the buffer at the position std::memcpy(&queue->buffer[position * queue->size], buffer.get_ptr(), queue->size); // ...push_end - queue->ctrl._and_not({ 0, 0xff000000 }); + queue->ctrl.atomic_op([](_sync::queue& ctrl) { ctrl._push = 0; }); vm::notify_at(queue.ptr(&CellSyncQueue::ctrl)); return CELL_OK; } -s32 cellSyncQueueTryPush(vm::ptr queue, vm::cptr buffer) +ppu_error_code cellSyncQueueTryPush(vm::ptr queue, vm::cptr buffer) { cellSync.trace("cellSyncQueueTryPush(queue=*0x%x, buffer=*0x%x)", queue, buffer); @@ -459,23 +474,23 @@ s32 cellSyncQueueTryPush(vm::ptr queue, vm::cptr buffer) u32 position; - if (!queue->ctrl.atomic_op(_sync::queue::try_push_begin, depth, position)) + if (!queue->ctrl.atomic_op(_sync::queue::try_push_begin, depth, &position)) { - return CELL_SYNC_ERROR_BUSY; + return NOT_AN_ERROR(CELL_SYNC_ERROR_BUSY); } // copy data from the buffer at the position std::memcpy(&queue->buffer[position * queue->size], buffer.get_ptr(), queue->size); // ...push_end - queue->ctrl._and_not({ 0, 0xff000000 }); + queue->ctrl.atomic_op([](_sync::queue& ctrl) { ctrl._push = 0; }); vm::notify_at(queue.ptr(&CellSyncQueue::ctrl)); return CELL_OK; } -s32 cellSyncQueuePop(PPUThread& ppu, vm::ptr queue, vm::ptr buffer) +ppu_error_code cellSyncQueuePop(PPUThread& ppu, vm::ptr queue, vm::ptr buffer) { cellSync.trace("cellSyncQueuePop(queue=*0x%x, buffer=*0x%x)", queue, buffer); @@ -493,20 +508,20 @@ s32 cellSyncQueuePop(PPUThread& ppu, vm::ptr queue, vm::ptr u32 position; - vm::wait_op(ppu, queue.addr(), 8, WRAP_EXPR(queue->ctrl.atomic_op(_sync::queue::try_pop_begin, depth, position))); + vm::wait_op(ppu, queue.addr(), 8, WRAP_EXPR(queue->ctrl.atomic_op(_sync::queue::try_pop_begin, depth, &position))); // copy data at the position to the buffer std::memcpy(buffer.get_ptr(), &queue->buffer[position % depth * queue->size], queue->size); // ...pop_end - queue->ctrl._and_not({ 0xff000000, 0 }); + queue->ctrl.atomic_op([](_sync::queue& ctrl) { ctrl._pop = 0; }); vm::notify_at(queue.ptr(&CellSyncQueue::ctrl)); return CELL_OK; } -s32 cellSyncQueueTryPop(vm::ptr queue, vm::ptr buffer) +ppu_error_code cellSyncQueueTryPop(vm::ptr queue, vm::ptr buffer) { cellSync.trace("cellSyncQueueTryPop(queue=*0x%x, buffer=*0x%x)", queue, buffer); @@ -524,23 +539,23 @@ s32 cellSyncQueueTryPop(vm::ptr queue, vm::ptr buffer) u32 position; - if (!queue->ctrl.atomic_op(_sync::queue::try_pop_begin, depth, position)) + if (!queue->ctrl.atomic_op(_sync::queue::try_pop_begin, depth, &position)) { - return CELL_SYNC_ERROR_BUSY; + return NOT_AN_ERROR(CELL_SYNC_ERROR_BUSY); } // copy data at the position to the buffer std::memcpy(buffer.get_ptr(), &queue->buffer[position % depth * queue->size], queue->size); // ...pop_end - queue->ctrl._and_not({ 0xff000000, 0 }); + queue->ctrl.atomic_op([](_sync::queue& ctrl) { ctrl._pop = 0; }); vm::notify_at(queue.ptr(&CellSyncQueue::ctrl)); return CELL_OK; } -s32 cellSyncQueuePeek(PPUThread& ppu, vm::ptr queue, vm::ptr buffer) +ppu_error_code cellSyncQueuePeek(PPUThread& ppu, vm::ptr queue, vm::ptr buffer) { cellSync.trace("cellSyncQueuePeek(queue=*0x%x, buffer=*0x%x)", queue, buffer); @@ -558,20 +573,20 @@ s32 cellSyncQueuePeek(PPUThread& ppu, vm::ptr queue, vm::ptrctrl.atomic_op(_sync::queue::try_peek_begin, depth, position))); + vm::wait_op(ppu, queue.addr(), 8, WRAP_EXPR(queue->ctrl.atomic_op(_sync::queue::try_peek_begin, depth, &position))); // copy data at the position to the buffer std::memcpy(buffer.get_ptr(), &queue->buffer[position % depth * queue->size], queue->size); // ...peek_end - queue->ctrl._and_not({ 0xff000000, 0 }); + queue->ctrl.atomic_op([](_sync::queue& ctrl) { ctrl._pop = 0; }); vm::notify_at(queue.ptr(&CellSyncQueue::ctrl)); return CELL_OK; } -s32 cellSyncQueueTryPeek(vm::ptr queue, vm::ptr buffer) +ppu_error_code cellSyncQueueTryPeek(vm::ptr queue, vm::ptr buffer) { cellSync.trace("cellSyncQueueTryPeek(queue=*0x%x, buffer=*0x%x)", queue, buffer); @@ -589,23 +604,23 @@ s32 cellSyncQueueTryPeek(vm::ptr queue, vm::ptr buffer) u32 position; - if (!queue->ctrl.atomic_op(_sync::queue::try_peek_begin, depth, position)) + if (!queue->ctrl.atomic_op(_sync::queue::try_peek_begin, depth, &position)) { - return CELL_SYNC_ERROR_BUSY; + return NOT_AN_ERROR(CELL_SYNC_ERROR_BUSY); } // copy data at the position to the buffer std::memcpy(buffer.get_ptr(), &queue->buffer[position % depth * queue->size], queue->size); // ...peek_end - queue->ctrl._and_not({ 0xff000000, 0 }); + queue->ctrl.atomic_op([](_sync::queue& ctrl) { ctrl._pop = 0; }); vm::notify_at(queue.ptr(&CellSyncQueue::ctrl)); return CELL_OK; } -s32 cellSyncQueueSize(vm::ptr queue) +ppu_error_code cellSyncQueueSize(vm::ptr queue) { cellSync.trace("cellSyncQueueSize(queue=*0x%x)", queue); @@ -621,10 +636,10 @@ s32 cellSyncQueueSize(vm::ptr queue) const u32 depth = queue->check_depth(); - return queue->ctrl.load().count & 0xffffff; + return NOT_AN_ERROR(queue->ctrl.load().count & 0xffffff); } -s32 cellSyncQueueClear(PPUThread& ppu, vm::ptr queue) +ppu_error_code cellSyncQueueClear(PPUThread& ppu, vm::ptr queue) { cellSync.trace("cellSyncQueueClear(queue=*0x%x)", queue); @@ -692,7 +707,7 @@ void syncLFQueueInitialize(vm::ptr queue, vm::cptr buffer queue->m_eq_id = 0; } -s32 cellSyncLFQueueInitialize(vm::ptr queue, vm::cptr buffer, u32 size, u32 depth, u32 direction, vm::ptr eaSignal) +ppu_error_code cellSyncLFQueueInitialize(vm::ptr queue, vm::cptr buffer, u32 size, u32 depth, u32 direction, vm::ptr eaSignal) { cellSync.warning("cellSyncLFQueueInitialize(queue=*0x%x, buffer=*0x%x, size=0x%x, depth=0x%x, direction=%d, eaSignal=*0x%x)", queue, buffer, size, depth, direction, eaSignal); @@ -729,7 +744,7 @@ s32 cellSyncLFQueueInitialize(vm::ptr queue, vm::cptr buf if (s32 ret = process_get_sdk_version(process_getpid(), sdk_ver)) { - return ret; + return NOT_AN_ERROR(ret); } if (sdk_ver == -1) @@ -801,7 +816,7 @@ s32 cellSyncLFQueueInitialize(vm::ptr queue, vm::cptr buf return CELL_OK; } -s32 _cellSyncLFQueueGetPushPointer(PPUThread& ppu, vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 useEventQueue) +ppu_error_code _cellSyncLFQueueGetPushPointer(PPUThread& ppu, vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 useEventQueue) { cellSync.warning("_cellSyncLFQueueGetPushPointer(queue=*0x%x, pointer=*0x%x, isBlocking=%d, useEventQueue=%d)", queue, pointer, isBlocking, useEventQueue); @@ -883,21 +898,18 @@ s32 _cellSyncLFQueueGetPushPointer(PPUThread& ppu, vm::ptr queu { if (!push.m_h7 || res) { - return res; + return NOT_AN_ERROR(res); } break; } } - if (s32 res = sys_event_queue_receive(ppu, queue->m_eq_id, vm::null, 0)) - { - throw EXCEPTION(""); - } + ASSERT(sys_event_queue_receive(ppu, queue->m_eq_id, vm::null, 0) == CELL_OK); var1 = 1; } } -s32 _cellSyncLFQueueGetPushPointer2(PPUThread& ppu, vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 useEventQueue) +ppu_error_code _cellSyncLFQueueGetPushPointer2(PPUThread& ppu, vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 useEventQueue) { // arguments copied from _cellSyncLFQueueGetPushPointer cellSync.todo("_cellSyncLFQueueGetPushPointer2(queue=*0x%x, pointer=*0x%x, isBlocking=%d, useEventQueue=%d)", queue, pointer, isBlocking, useEventQueue); @@ -905,7 +917,7 @@ s32 _cellSyncLFQueueGetPushPointer2(PPUThread& ppu, vm::ptr que throw EXCEPTION(""); } -s32 _cellSyncLFQueueCompletePushPointer(PPUThread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal) +ppu_error_code _cellSyncLFQueueCompletePushPointer(PPUThread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal) { cellSync.warning("_cellSyncLFQueueCompletePushPointer(queue=*0x%x, pointer=%d, fpSendSignal=*0x%x)", queue, pointer, fpSendSignal); @@ -983,7 +995,7 @@ s32 _cellSyncLFQueueCompletePushPointer(PPUThread& ppu, vm::ptr if (var9 > 1 && (u32)var8 > 1) { - assert(16 - var2 <= 1); + ASSERT(16 - var2 <= 1); } s32 var11 = (pack >> 10) & 0x1f; @@ -1015,16 +1027,12 @@ s32 _cellSyncLFQueueCompletePushPointer(PPUThread& ppu, vm::ptr if (queue->push2.compare_and_swap_test(old, push2)) { - assert(var2 + var4 < 16); + ASSERT(var2 + var4 < 16); if (var6 != -1) { - bool exch = queue->push3.compare_and_swap_test(old2, push3); - assert(exch); - if (exch) - { - assert(fpSendSignal); - return fpSendSignal(ppu, (u32)queue->m_eaSignal.addr(), var6); - } + ASSERT(queue->push3.compare_and_swap_test(old2, push3)); + ASSERT(fpSendSignal); + return NOT_AN_ERROR(fpSendSignal(ppu, (u32)queue->m_eaSignal.addr(), var6)); } else { @@ -1041,7 +1049,7 @@ s32 _cellSyncLFQueueCompletePushPointer(PPUThread& ppu, vm::ptr } } -s32 _cellSyncLFQueueCompletePushPointer2(PPUThread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal) +ppu_error_code _cellSyncLFQueueCompletePushPointer2(PPUThread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal) { // arguments copied from _cellSyncLFQueueCompletePushPointer cellSync.todo("_cellSyncLFQueueCompletePushPointer2(queue=*0x%x, pointer=%d, fpSendSignal=*0x%x)", queue, pointer, fpSendSignal); @@ -1049,7 +1057,7 @@ s32 _cellSyncLFQueueCompletePushPointer2(PPUThread& ppu, vm::ptr queue, vm::cptr buffer, u32 isBlocking) +ppu_error_code _cellSyncLFQueuePushBody(PPUThread& ppu, vm::ptr queue, vm::cptr buffer, u32 isBlocking) { // cellSyncLFQueuePush has 1 in isBlocking param, cellSyncLFQueueTryPush has 0 cellSync.warning("_cellSyncLFQueuePushBody(queue=*0x%x, buffer=*0x%x, isBlocking=%d)", queue, buffer, isBlocking); @@ -1083,7 +1091,7 @@ s32 _cellSyncLFQueuePushBody(PPUThread& ppu, vm::ptr queue, vm: if (!isBlocking || res != CELL_SYNC_ERROR_AGAIN) { - if (res) return res; + if (res) return NOT_AN_ERROR(res); break; } @@ -1094,7 +1102,7 @@ s32 _cellSyncLFQueuePushBody(PPUThread& ppu, vm::ptr queue, vm: const s32 depth = queue->m_depth; const s32 size = queue->m_size; const s32 pos = *position; - const u32 addr = VM_CAST((u64)((queue->m_buffer.addr() & ~1ull) + size * (pos >= depth ? pos - depth : pos))); + const u32 addr = vm::cast((u64)((queue->m_buffer.addr() & ~1ull) + size * (pos >= depth ? pos - depth : pos)), HERE); std::memcpy(vm::base(addr), buffer.get_ptr(), size); if (queue->m_direction != CELL_SYNC_QUEUE_ANY2ANY) @@ -1107,7 +1115,7 @@ s32 _cellSyncLFQueuePushBody(PPUThread& ppu, vm::ptr queue, vm: } } -s32 _cellSyncLFQueueGetPopPointer(PPUThread& ppu, vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 arg4, u32 useEventQueue) +ppu_error_code _cellSyncLFQueueGetPopPointer(PPUThread& ppu, vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 arg4, u32 useEventQueue) { cellSync.warning("_cellSyncLFQueueGetPopPointer(queue=*0x%x, pointer=*0x%x, isBlocking=%d, arg4=%d, useEventQueue=%d)", queue, pointer, isBlocking, arg4, useEventQueue); @@ -1189,21 +1197,18 @@ s32 _cellSyncLFQueueGetPopPointer(PPUThread& ppu, vm::ptr queue { if (!pop.m_h3 || res) { - return res; + return NOT_AN_ERROR(res); } break; } } - if (s32 res = sys_event_queue_receive(ppu, queue->m_eq_id, vm::null, 0)) - { - throw EXCEPTION(""); - } + ASSERT(sys_event_queue_receive(ppu, queue->m_eq_id, vm::null, 0) == CELL_OK); var1 = 1; } } -s32 _cellSyncLFQueueGetPopPointer2(PPUThread& ppu, vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 useEventQueue) +ppu_error_code _cellSyncLFQueueGetPopPointer2(PPUThread& ppu, vm::ptr queue, vm::ptr pointer, u32 isBlocking, u32 useEventQueue) { // arguments copied from _cellSyncLFQueueGetPopPointer cellSync.todo("_cellSyncLFQueueGetPopPointer2(queue=*0x%x, pointer=*0x%x, isBlocking=%d, useEventQueue=%d)", queue, pointer, isBlocking, useEventQueue); @@ -1211,7 +1216,7 @@ s32 _cellSyncLFQueueGetPopPointer2(PPUThread& ppu, vm::ptr queu throw EXCEPTION(""); } -s32 _cellSyncLFQueueCompletePopPointer(PPUThread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal, u32 noQueueFull) +ppu_error_code _cellSyncLFQueueCompletePopPointer(PPUThread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal, u32 noQueueFull) { // arguments copied from _cellSyncLFQueueCompletePushPointer + unknown argument (noQueueFull taken from LFQueue2CompletePopPointer) cellSync.warning("_cellSyncLFQueueCompletePopPointer(queue=*0x%x, pointer=%d, fpSendSignal=*0x%x, noQueueFull=%d)", queue, pointer, fpSendSignal, noQueueFull); @@ -1294,7 +1299,7 @@ s32 _cellSyncLFQueueCompletePopPointer(PPUThread& ppu, vm::ptr if (var9 > 1 && (u32)var8 > 1) { - assert(16 - var2 <= 1); + ASSERT(16 - var2 <= 1); } s32 var11 = (pack >> 10) & 0x1f; @@ -1324,13 +1329,9 @@ s32 _cellSyncLFQueueCompletePopPointer(PPUThread& ppu, vm::ptr { if (var6 != -1) { - bool exch = queue->pop3.compare_and_swap_test(old2, pop3); - assert(exch); - if (exch) - { - assert(fpSendSignal); - return fpSendSignal(ppu, (u32)queue->m_eaSignal.addr(), var6); - } + ASSERT(queue->pop3.compare_and_swap_test(old2, pop3)); + ASSERT(fpSendSignal); + return NOT_AN_ERROR(fpSendSignal(ppu, (u32)queue->m_eaSignal.addr(), var6)); } else { @@ -1347,7 +1348,7 @@ s32 _cellSyncLFQueueCompletePopPointer(PPUThread& ppu, vm::ptr } } -s32 _cellSyncLFQueueCompletePopPointer2(PPUThread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal, u32 noQueueFull) +ppu_error_code _cellSyncLFQueueCompletePopPointer2(PPUThread& ppu, vm::ptr queue, s32 pointer, vm::ptr fpSendSignal, u32 noQueueFull) { // arguments copied from _cellSyncLFQueueCompletePopPointer cellSync.todo("_cellSyncLFQueueCompletePopPointer2(queue=*0x%x, pointer=%d, fpSendSignal=*0x%x, noQueueFull=%d)", queue, pointer, fpSendSignal, noQueueFull); @@ -1355,7 +1356,7 @@ s32 _cellSyncLFQueueCompletePopPointer2(PPUThread& ppu, vm::ptr throw EXCEPTION(""); } -s32 _cellSyncLFQueuePopBody(PPUThread& ppu, vm::ptr queue, vm::ptr buffer, u32 isBlocking) +ppu_error_code _cellSyncLFQueuePopBody(PPUThread& ppu, vm::ptr queue, vm::ptr buffer, u32 isBlocking) { // cellSyncLFQueuePop has 1 in isBlocking param, cellSyncLFQueueTryPop has 0 cellSync.warning("_cellSyncLFQueuePopBody(queue=*0x%x, buffer=*0x%x, isBlocking=%d)", queue, buffer, isBlocking); @@ -1389,7 +1390,7 @@ s32 _cellSyncLFQueuePopBody(PPUThread& ppu, vm::ptr queue, vm:: if (!isBlocking || res != CELL_SYNC_ERROR_AGAIN) { - if (res) return res; + if (res) return NOT_AN_ERROR(res); break; } @@ -1400,7 +1401,7 @@ s32 _cellSyncLFQueuePopBody(PPUThread& ppu, vm::ptr queue, vm:: const s32 depth = queue->m_depth; const s32 size = queue->m_size; const s32 pos = *position; - const u32 addr = VM_CAST((u64)((queue->m_buffer.addr() & ~1) + size * (pos >= depth ? pos - depth : pos))); + const u32 addr = vm::cast((u64)((queue->m_buffer.addr() & ~1) + size * (pos >= depth ? pos - depth : pos)), HERE); std::memcpy(buffer.get_ptr(), vm::base(addr), size); if (queue->m_direction != CELL_SYNC_QUEUE_ANY2ANY) @@ -1413,7 +1414,7 @@ s32 _cellSyncLFQueuePopBody(PPUThread& ppu, vm::ptr queue, vm:: } } -s32 cellSyncLFQueueClear(vm::ptr queue) +ppu_error_code cellSyncLFQueueClear(vm::ptr queue) { cellSync.warning("cellSyncLFQueueClear(queue=*0x%x)", queue); @@ -1464,7 +1465,7 @@ s32 cellSyncLFQueueClear(vm::ptr queue) return CELL_OK; } -s32 cellSyncLFQueueSize(vm::ptr queue, vm::ptr size) +ppu_error_code cellSyncLFQueueSize(vm::ptr queue, vm::ptr size) { cellSync.warning("cellSyncLFQueueSize(queue=*0x%x, size=*0x%x)", queue, size); @@ -1501,7 +1502,7 @@ s32 cellSyncLFQueueSize(vm::ptr queue, vm::ptr size) } } -s32 cellSyncLFQueueDepth(vm::ptr queue, vm::ptr depth) +ppu_error_code cellSyncLFQueueDepth(vm::ptr queue, vm::ptr depth) { cellSync.trace("cellSyncLFQueueDepth(queue=*0x%x, depth=*0x%x)", queue, depth); @@ -1520,7 +1521,7 @@ s32 cellSyncLFQueueDepth(vm::ptr queue, vm::ptr depth) return CELL_OK; } -s32 _cellSyncLFQueueGetSignalAddress(vm::cptr queue, vm::pptr ppSignal) +ppu_error_code _cellSyncLFQueueGetSignalAddress(vm::cptr queue, vm::pptr ppSignal) { cellSync.trace("_cellSyncLFQueueGetSignalAddress(queue=*0x%x, ppSignal=**0x%x)", queue, ppSignal); @@ -1539,7 +1540,7 @@ s32 _cellSyncLFQueueGetSignalAddress(vm::cptr queue, vm::pptr queue, vm::ptr direction) +ppu_error_code cellSyncLFQueueGetDirection(vm::cptr queue, vm::ptr direction) { cellSync.trace("cellSyncLFQueueGetDirection(queue=*0x%x, direction=*0x%x)", queue, direction); @@ -1558,7 +1559,7 @@ s32 cellSyncLFQueueGetDirection(vm::cptr queue, vm::ptr di return CELL_OK; } -s32 cellSyncLFQueueGetEntrySize(vm::cptr queue, vm::ptr entry_size) +ppu_error_code cellSyncLFQueueGetEntrySize(vm::cptr queue, vm::ptr entry_size) { cellSync.trace("cellSyncLFQueueGetEntrySize(queue=*0x%x, entry_size=*0x%x)", queue, entry_size); @@ -1577,57 +1578,22 @@ s32 cellSyncLFQueueGetEntrySize(vm::cptr queue, vm::ptr en return CELL_OK; } -s32 _cellSyncLFQueueAttachLv2EventQueue(vm::ptr spus, u32 num, vm::ptr queue) +ppu_error_code _cellSyncLFQueueAttachLv2EventQueue(vm::ptr spus, u32 num, vm::ptr queue) { cellSync.todo("_cellSyncLFQueueAttachLv2EventQueue(spus=*0x%x, num=%d, queue=*0x%x)", spus, num, queue); throw EXCEPTION(""); } -s32 _cellSyncLFQueueDetachLv2EventQueue(vm::ptr spus, u32 num, vm::ptr queue) +ppu_error_code _cellSyncLFQueueDetachLv2EventQueue(vm::ptr spus, u32 num, vm::ptr queue) { cellSync.todo("_cellSyncLFQueueDetachLv2EventQueue(spus=*0x%x, num=%d, queue=*0x%x)", spus, num, queue); throw EXCEPTION(""); } -Module<> cellSync("cellSync", []() +DECLARE(ppu_module_manager::cellSync)("cellSync", []() { - // setup error handler - cellSync.on_error = [](s64 value, ModuleFunc* func) - { - // get error name for CELL_SYNC errors - auto get_error = [](u32 code) -> const char* - { - switch (code) - { - case CELL_SYNC_ERROR_AGAIN: return "CELL_SYNC_ERROR_AGAIN"; - case CELL_SYNC_ERROR_INVAL: return "CELL_SYNC_ERROR_INVAL"; - case CELL_SYNC_ERROR_NOSYS: return "CELL_SYNC_ERROR_NOSYS"; - case CELL_SYNC_ERROR_NOMEM: return "CELL_SYNC_ERROR_NOMEM"; - case CELL_SYNC_ERROR_SRCH: return "CELL_SYNC_ERROR_SRCH"; - case CELL_SYNC_ERROR_NOENT: return "CELL_SYNC_ERROR_NOENT"; - case CELL_SYNC_ERROR_NOEXEC: return "CELL_SYNC_ERROR_NOEXEC"; - case CELL_SYNC_ERROR_DEADLK: return "CELL_SYNC_ERROR_DEADLK"; - case CELL_SYNC_ERROR_PERM: return "CELL_SYNC_ERROR_PERM"; - case CELL_SYNC_ERROR_BUSY: return "CELL_SYNC_ERROR_BUSY"; - case CELL_SYNC_ERROR_ABORT: return "CELL_SYNC_ERROR_ABORT"; - case CELL_SYNC_ERROR_FAULT: return "CELL_SYNC_ERROR_FAULT"; - case CELL_SYNC_ERROR_CHILD: return "CELL_SYNC_ERROR_CHILD"; - case CELL_SYNC_ERROR_STAT: return "CELL_SYNC_ERROR_STAT"; - case CELL_SYNC_ERROR_ALIGN: return "CELL_SYNC_ERROR_ALIGN"; - } - - return "???"; - }; - - // analyse error code - if (u32 code = (value & 0xffffff00) == 0x80410100 ? static_cast(value) : 0) - { - cellSync.error("%s() -> %s (0x%x)", func->name, get_error(code), code); - } - }; - REG_FUNC(cellSync, cellSyncMutexInitialize); REG_FUNC(cellSync, cellSyncMutexLock); REG_FUNC(cellSync, cellSyncMutexTryLock); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync.h b/rpcs3/Emu/Cell/Modules/cellSync.h similarity index 58% rename from rpcs3/Emu/SysCalls/Modules/cellSync.h rename to rpcs3/Emu/Cell/Modules/cellSync.h index fbf1e7464b..831ce776d1 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync.h +++ b/rpcs3/Emu/Cell/Modules/cellSync.h @@ -3,53 +3,82 @@ namespace vm { using namespace ps3; } // Return Codes -enum +enum CellSyncError : s32 { - CELL_SYNC_ERROR_AGAIN = 0x80410101, - CELL_SYNC_ERROR_INVAL = 0x80410102, - CELL_SYNC_ERROR_NOSYS = 0x80410103, - CELL_SYNC_ERROR_NOMEM = 0x80410104, - CELL_SYNC_ERROR_SRCH = 0x80410105, - CELL_SYNC_ERROR_NOENT = 0x80410106, - CELL_SYNC_ERROR_NOEXEC = 0x80410107, - CELL_SYNC_ERROR_DEADLK = 0x80410108, - CELL_SYNC_ERROR_PERM = 0x80410109, - CELL_SYNC_ERROR_BUSY = 0x8041010A, - CELL_SYNC_ERROR_ABORT = 0x8041010C, - CELL_SYNC_ERROR_FAULT = 0x8041010D, - CELL_SYNC_ERROR_CHILD = 0x8041010E, - CELL_SYNC_ERROR_STAT = 0x8041010F, - CELL_SYNC_ERROR_ALIGN = 0x80410110, - - CELL_SYNC_ERROR_NULL_POINTER = 0x80410111, - CELL_SYNC_ERROR_NOT_SUPPORTED_THREAD = 0x80410112, - CELL_SYNC_ERROR_SHOTAGE = 0x80410112, - CELL_SYNC_ERROR_NO_NOTIFIER = 0x80410113, - CELL_SYNC_ERROR_UNKNOWNKEY = 0x80410113, - CELL_SYNC_ERROR_NO_SPU_CONTEXT_STORAGE = 0x80410114, + CELL_SYNC_ERROR_AGAIN = ERROR_CODE(0x80410101), + CELL_SYNC_ERROR_INVAL = ERROR_CODE(0x80410102), + CELL_SYNC_ERROR_NOSYS = ERROR_CODE(0x80410103), + CELL_SYNC_ERROR_NOMEM = ERROR_CODE(0x80410104), + CELL_SYNC_ERROR_SRCH = ERROR_CODE(0x80410105), + CELL_SYNC_ERROR_NOENT = ERROR_CODE(0x80410106), + CELL_SYNC_ERROR_NOEXEC = ERROR_CODE(0x80410107), + CELL_SYNC_ERROR_DEADLK = ERROR_CODE(0x80410108), + CELL_SYNC_ERROR_PERM = ERROR_CODE(0x80410109), + CELL_SYNC_ERROR_BUSY = ERROR_CODE(0x8041010A), + CELL_SYNC_ERROR_ABORT = ERROR_CODE(0x8041010C), + CELL_SYNC_ERROR_FAULT = ERROR_CODE(0x8041010D), + CELL_SYNC_ERROR_CHILD = ERROR_CODE(0x8041010E), + CELL_SYNC_ERROR_STAT = ERROR_CODE(0x8041010F), + CELL_SYNC_ERROR_ALIGN = ERROR_CODE(0x80410110), + CELL_SYNC_ERROR_NULL_POINTER = ERROR_CODE(0x80410111), + CELL_SYNC_ERROR_NOT_SUPPORTED_THREAD = ERROR_CODE(0x80410112), + CELL_SYNC_ERROR_NO_NOTIFIER = ERROR_CODE(0x80410113), + CELL_SYNC_ERROR_NO_SPU_CONTEXT_STORAGE = ERROR_CODE(0x80410114), }; +enum CellSyncError1 : s32 +{ + CELL_SYNC_ERROR_SHOTAGE = ERROR_CODE(0x80410112), + CELL_SYNC_ERROR_UNKNOWNKEY = ERROR_CODE(0x80410113), +}; + +template<> +inline const char* ppu_error_code::print(CellSyncError error) +{ + switch (error) + { + STR_CASE(CELL_SYNC_ERROR_AGAIN); + STR_CASE(CELL_SYNC_ERROR_INVAL); + STR_CASE(CELL_SYNC_ERROR_NOSYS); + STR_CASE(CELL_SYNC_ERROR_NOMEM); + STR_CASE(CELL_SYNC_ERROR_SRCH); + STR_CASE(CELL_SYNC_ERROR_NOENT); + STR_CASE(CELL_SYNC_ERROR_NOEXEC); + STR_CASE(CELL_SYNC_ERROR_DEADLK); + STR_CASE(CELL_SYNC_ERROR_PERM); + STR_CASE(CELL_SYNC_ERROR_BUSY); + STR_CASE(CELL_SYNC_ERROR_ABORT); + STR_CASE(CELL_SYNC_ERROR_FAULT); + STR_CASE(CELL_SYNC_ERROR_CHILD); + STR_CASE(CELL_SYNC_ERROR_STAT); + STR_CASE(CELL_SYNC_ERROR_ALIGN); + STR_CASE(CELL_SYNC_ERROR_NULL_POINTER); + STR_CASE(CELL_SYNC_ERROR_NOT_SUPPORTED_THREAD); + STR_CASE(CELL_SYNC_ERROR_NO_NOTIFIER); + STR_CASE(CELL_SYNC_ERROR_NO_SPU_CONTEXT_STORAGE); + } + + return nullptr; +} + +template<> +inline const char* ppu_error_code::print(CellSyncError1 error) +{ + switch (error) + { + STR_CASE(CELL_SYNC_ERROR_SHOTAGE); + STR_CASE(CELL_SYNC_ERROR_UNKNOWNKEY); + } + + return nullptr; +} + namespace _sync { struct alignas(4) mutex // CellSyncMutex control variable { be_t rel; be_t acq; - - static inline be_t acquire(mutex& ctrl) - { - return ctrl.acq++; - } - - static inline bool try_lock(mutex& ctrl) - { - return ctrl.acq++ == ctrl.rel; - } - - static inline void unlock(mutex& ctrl) - { - ctrl.rel++; - } }; } @@ -108,7 +137,7 @@ CHECK_SIZE_ALIGN(CellSyncBarrier, 4, 4); namespace _sync { - struct rwlock // CellSyncRwm control variable + struct alignas(4) rwlock // CellSyncRwm control variable { be_t readers; be_t writers; @@ -160,25 +189,25 @@ CHECK_SIZE_ALIGN(CellSyncRwm, 16, 16); namespace _sync { - struct queue // CellSyncQueue control variable + struct alignas(8) queue // CellSyncQueue control variable { union { be_t x0; - bf_be_t next; - bf_be_t _pop; + bf_t, 0, 24> next; + bf_t, 24, 8> _pop; }; union { be_t x4; - bf_be_t count; - bf_be_t _push; + bf_t, 0, 24> count; + bf_t, 24, 8> _push; }; - static inline bool try_push_begin(queue& ctrl, u32 depth, u32& position) + static inline bool try_push_begin(queue& ctrl, u32 depth, u32* position) { const u32 count = ctrl.count; @@ -187,14 +216,14 @@ namespace _sync return false; } - position = ctrl.next; - ctrl.next = position + 1 != depth ? position + 1 : 0; + *position = ctrl.next; + ctrl.next = *position + 1 != depth ? *position + 1 : 0; ctrl.count = count + 1; ctrl._push = 1; return true; } - static inline bool try_pop_begin(queue& ctrl, u32 depth, u32& position) + static inline bool try_pop_begin(queue& ctrl, u32 depth, u32* position) { const u32 count = ctrl.count; @@ -204,12 +233,12 @@ namespace _sync } ctrl._pop = 1; - position = ctrl.next + depth - count; + *position = ctrl.next + depth - count; ctrl.count = count - 1; return true; } - static inline bool try_peek_begin(queue& ctrl, u32 depth, u32& position) + static inline bool try_peek_begin(queue& ctrl, u32 depth, u32* position) { const u32 count = ctrl.count; @@ -219,7 +248,7 @@ namespace _sync } ctrl._pop = 1; - position = ctrl.next + depth - count; + *position = ctrl.next + depth - count; return true; } @@ -281,7 +310,7 @@ enum CellSyncQueueDirection : u32 // CellSyncLFQueueDirection struct alignas(128) CellSyncLFQueue { - struct pop1_t + struct alignas(8) pop1_t { be_t m_h1; be_t m_h2; @@ -294,13 +323,13 @@ struct alignas(128) CellSyncLFQueue be_t pack; }; - struct pop3_t + struct alignas(4) pop3_t { be_t m_h1; be_t m_h2; }; - struct push1_t + struct alignas(8) push1_t { be_t m_h5; be_t m_h6; @@ -313,7 +342,7 @@ struct alignas(128) CellSyncLFQueue be_t pack; }; - struct push3_t + struct alignas(4) push3_t { be_t m_h5; be_t m_h6; @@ -367,4 +396,4 @@ struct alignas(128) CellSyncLFQueue CHECK_SIZE_ALIGN(CellSyncLFQueue, 128, 128); // Prototypes -s32 cellSyncLFQueueInitialize(vm::ptr queue, vm::cptr buffer, u32 size, u32 depth, u32 direction, vm::ptr eaSignal); +ppu_error_code cellSyncLFQueueInitialize(vm::ptr queue, vm::cptr buffer, u32 size, u32 depth, u32 direction, vm::ptr eaSignal); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync2.cpp b/rpcs3/Emu/Cell/Modules/cellSync2.cpp similarity index 89% rename from rpcs3/Emu/SysCalls/Modules/cellSync2.cpp rename to rpcs3/Emu/Cell/Modules/cellSync2.cpp index b875e2f7ec..145d51ba98 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync2.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSync2.cpp @@ -1,21 +1,17 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellSync2.h" -struct Sync2Instance -{ - CellSync2CallerThreadType gCellSync2CallerThreadTypePpuThread; - CellSync2Notifier gCellSync2NotifierPpuThread; - CellSync2CallerThreadType gCellSync2CallerThreadTypePpuFiber; - CellSync2Notifier gCellSync2NotifierPpuFiber; - CellSync2Notifier gCellSync2NotifierSpursTask; - CellSync2Notifier gCellSync2NotifierSpursJobQueueJob; -}; +LOG_CHANNEL(cellSync2); -extern Module cellSync2; +vm::gvar gCellSync2CallerThreadTypePpuThread; +vm::gvar gCellSync2NotifierPpuThread; +vm::gvar gCellSync2CallerThreadTypePpuFiber; +vm::gvar gCellSync2NotifierPpuFiber; +vm::gvar gCellSync2NotifierSpursTask; +vm::gvar gCellSync2NotifierSpursJobQueueJob; s32 _cellSync2MutexAttributeInitialize(vm::ptr attr, u32 sdkVersion) { @@ -259,14 +255,14 @@ s32 cellSync2QueueGetDepth() return CELL_OK; } -Module cellSync2("cellSync2", []() +DECLARE(ppu_module_manager::cellSync2)("cellSync2", []() { - REG_VARIABLE(cellSync2, gCellSync2CallerThreadTypePpuThread); - REG_VARIABLE(cellSync2, gCellSync2NotifierPpuThread); - REG_VARIABLE(cellSync2, gCellSync2CallerThreadTypePpuFiber); - REG_VARIABLE(cellSync2, gCellSync2NotifierPpuFiber); - REG_VARIABLE(cellSync2, gCellSync2NotifierSpursTask); - REG_VARIABLE(cellSync2, gCellSync2NotifierSpursJobQueueJob); + REG_VAR(cellSync2, gCellSync2CallerThreadTypePpuThread); + REG_VAR(cellSync2, gCellSync2NotifierPpuThread); + REG_VAR(cellSync2, gCellSync2CallerThreadTypePpuFiber); + REG_VAR(cellSync2, gCellSync2NotifierPpuFiber); + REG_VAR(cellSync2, gCellSync2NotifierSpursTask); + REG_VAR(cellSync2, gCellSync2NotifierSpursJobQueueJob); REG_FUNC(cellSync2, _cellSync2MutexAttributeInitialize); REG_FUNC(cellSync2, cellSync2MutexEstimateBufferSize); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync2.h b/rpcs3/Emu/Cell/Modules/cellSync2.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellSync2.h rename to rpcs3/Emu/Cell/Modules/cellSync2.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysconf.cpp b/rpcs3/Emu/Cell/Modules/cellSysconf.cpp similarity index 58% rename from rpcs3/Emu/SysCalls/Modules/cellSysconf.cpp rename to rpcs3/Emu/Cell/Modules/cellSysconf.cpp index 9a3a55f788..3685f8f1ef 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysconf.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysconf.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellSysconf; +LOG_CHANNEL(cellSysconf); s32 cellSysconfAbort() { @@ -21,13 +20,11 @@ s32 cellSysconfBtGetDeviceList() void cellSysutil_Sysconf_init() { - extern Module<> cellSysutil; - REG_FUNC(cellSysutil, cellSysconfAbort); REG_FUNC(cellSysutil, cellSysconfOpen); } -Module<> cellSysconf("cellSysconf", []() +DECLARE(ppu_module_manager::cellSysconf)("cellSysconfExtUtility", []() { - REG_FUNC(cellSysconf, cellSysconfBtGetDeviceList); + REG_FUNC(cellSysconfExtUtility, cellSysconfBtGetDeviceList); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysmodule.cpp b/rpcs3/Emu/Cell/Modules/cellSysmodule.cpp similarity index 53% rename from rpcs3/Emu/SysCalls/Modules/cellSysmodule.cpp rename to rpcs3/Emu/Cell/Modules/cellSysmodule.cpp index f5fe1b2230..c8ffe495d0 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysmodule.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysmodule.cpp @@ -1,221 +1,357 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/SysCalls/ModuleManager.h" -#include "Emu/SysCalls/Modules.h" - -extern Module<> cellSysmodule; - -enum -{ - CELL_SYSMODULE_LOADED = CELL_OK, - CELL_SYSMODULE_ERROR_DUPLICATED = 0x80012001, - CELL_SYSMODULE_ERROR_UNKNOWN = 0x80012002, - CELL_SYSMODULE_ERROR_UNLOADED = 0x80012003, - CELL_SYSMODULE_ERROR_INVALID_MEMCONTAINER = 0x80012004, - CELL_SYSMODULE_ERROR_FATAL = 0x800120ff, -}; - -const char* get_module_id(u16 id) -{ - switch (id) - { - case 0x0000: return "CELL_SYSMODULE_NET"; - case 0x0001: return "CELL_SYSMODULE_HTTP"; - case 0x0002: return "CELL_SYSMODULE_HTTP_UTIL"; - case 0x0003: return "CELL_SYSMODULE_SSL"; - case 0x0004: return "CELL_SYSMODULE_HTTPS"; - case 0x0005: return "CELL_SYSMODULE_VDEC"; - case 0x0006: return "CELL_SYSMODULE_ADEC"; - case 0x0007: return "CELL_SYSMODULE_DMUX"; - case 0x0008: return "CELL_SYSMODULE_VPOST"; - case 0x0009: return "CELL_SYSMODULE_RTC"; - case 0x000a: return "CELL_SYSMODULE_SPURS"; - case 0x000b: return "CELL_SYSMODULE_OVIS"; - case 0x000c: return "CELL_SYSMODULE_SHEAP"; - case 0x000d: return "CELL_SYSMODULE_SYNC"; - case 0x000e: return "CELL_SYSMODULE_FS"; - case 0x000f: return "CELL_SYSMODULE_JPGDEC"; - case 0x0010: return "CELL_SYSMODULE_GCM_SYS"; - case 0x0011: return "CELL_SYSMODULE_AUDIO"; - case 0x0012: return "CELL_SYSMODULE_PAMF"; - case 0x0013: return "CELL_SYSMODULE_ATRAC3PLUS"; - case 0x0014: return "CELL_SYSMODULE_NETCTL"; - case 0x0015: return "CELL_SYSMODULE_SYSUTIL"; - case 0x0016: return "CELL_SYSMODULE_SYSUTIL_NP"; - case 0x0017: return "CELL_SYSMODULE_IO"; - case 0x0018: return "CELL_SYSMODULE_PNGDEC"; - case 0x0019: return "CELL_SYSMODULE_FONT"; - case 0x001a: return "CELL_SYSMODULE_FONTFT"; - case 0x001b: return "CELL_SYSMODULE_FREETYPE"; - case 0x001c: return "CELL_SYSMODULE_USBD"; - case 0x001d: return "CELL_SYSMODULE_SAIL"; - case 0x001e: return "CELL_SYSMODULE_L10N"; - case 0x001f: return "CELL_SYSMODULE_RESC"; - case 0x0020: return "CELL_SYSMODULE_DAISY"; - case 0x0021: return "CELL_SYSMODULE_KEY2CHAR"; - case 0x0022: return "CELL_SYSMODULE_MIC"; - case 0x0023: return "CELL_SYSMODULE_CAMERA"; - case 0x0024: return "CELL_SYSMODULE_VDEC_MPEG2"; - case 0x0025: return "CELL_SYSMODULE_VDEC_AVC"; - case 0x0026: return "CELL_SYSMODULE_ADEC_LPCM"; - case 0x0027: return "CELL_SYSMODULE_ADEC_AC3"; - case 0x0028: return "CELL_SYSMODULE_ADEC_ATX"; - case 0x0029: return "CELL_SYSMODULE_ADEC_AT3"; - case 0x002a: return "CELL_SYSMODULE_DMUX_PAMF"; - case 0x002b: return "CELL_SYSMODULE_VDEC_AL"; - case 0x002c: return "CELL_SYSMODULE_ADEC_AL"; - case 0x002d: return "CELL_SYSMODULE_DMUX_AL"; - case 0x002e: return "CELL_SYSMODULE_LV2DBG"; - case 0x002f: return "CELL_SYSMODULE_SYSUTIL_AVCHAT"; - case 0x0030: return "CELL_SYSMODULE_USBPSPCM"; - case 0x0031: return "CELL_SYSMODULE_AVCONF_EXT"; - case 0x0032: return "CELL_SYSMODULE_SYSUTIL_USERINFO"; - case 0x0033: return "CELL_SYSMODULE_SYSUTIL_SAVEDATA"; - case 0x0034: return "CELL_SYSMODULE_SUBDISPLAY"; - case 0x0035: return "CELL_SYSMODULE_SYSUTIL_REC"; - case 0x0036: return "CELL_SYSMODULE_VIDEO_EXPORT"; - case 0x0037: return "CELL_SYSMODULE_SYSUTIL_GAME_EXEC"; - case 0x0038: return "CELL_SYSMODULE_SYSUTIL_NP2"; - case 0x0039: return "CELL_SYSMODULE_SYSUTIL_AP"; - case 0x003a: return "CELL_SYSMODULE_SYSUTIL_NP_CLANS"; - case 0x003b: return "CELL_SYSMODULE_SYSUTIL_OSK_EXT"; - case 0x003c: return "CELL_SYSMODULE_VDEC_DIVX"; - case 0x003d: return "CELL_SYSMODULE_JPGENC"; - case 0x003e: return "CELL_SYSMODULE_SYSUTIL_GAME"; - case 0x003f: return "CELL_SYSMODULE_BGDL"; - case 0x0040: return "CELL_SYSMODULE_FREETYPE_TT"; - case 0x0041: return "CELL_SYSMODULE_SYSUTIL_VIDEO_UPLOAD"; - case 0x0042: return "CELL_SYSMODULE_SYSUTIL_SYSCONF_EXT"; - case 0x0043: return "CELL_SYSMODULE_FIBER"; - case 0x0044: return "CELL_SYSMODULE_SYSUTIL_NP_COMMERCE2"; - case 0x0045: return "CELL_SYSMODULE_SYSUTIL_NP_TUS"; - case 0x0046: return "CELL_SYSMODULE_VOICE"; - case 0x0047: return "CELL_SYSMODULE_ADEC_CELP8"; - case 0x0048: return "CELL_SYSMODULE_CELP8ENC"; - case 0x0049: return "CELL_SYSMODULE_SYSUTIL_LICENSEAREA"; - case 0x004a: return "CELL_SYSMODULE_SYSUTIL_MUSIC2"; - case 0x004e: return "CELL_SYSMODULE_SYSUTIL_SCREENSHOT"; - case 0x004f: return "CELL_SYSMODULE_SYSUTIL_MUSIC_DECODE"; - case 0x0050: return "CELL_SYSMODULE_SPURS_JQ"; - case 0x0052: return "CELL_SYSMODULE_PNGENC"; - case 0x0053: return "CELL_SYSMODULE_SYSUTIL_MUSIC_DECODE2"; - case 0x0055: return "CELL_SYSMODULE_SYNC2"; - case 0x0056: return "CELL_SYSMODULE_SYSUTIL_NP_UTIL"; - case 0x0057: return "CELL_SYSMODULE_RUDP"; - case 0x0059: return "CELL_SYSMODULE_SYSUTIL_NP_SNS"; - case 0x005a: return "CELL_SYSMODULE_GEM"; - case 0xf00a: return "CELL_SYSMODULE_CELPENC"; - case 0xf010: return "CELL_SYSMODULE_GIFDEC"; - case 0xf019: return "CELL_SYSMODULE_ADEC_CELP"; - case 0xf01b: return "CELL_SYSMODULE_ADEC_M2BC"; - case 0xf01d: return "CELL_SYSMODULE_ADEC_M4AAC"; - case 0xf01e: return "CELL_SYSMODULE_ADEC_MP3"; - case 0xf023: return "CELL_SYSMODULE_IMEJP"; - case 0xf028: return "CELL_SYSMODULE_SYSUTIL_MUSIC"; - case 0xf029: return "CELL_SYSMODULE_PHOTO_EXPORT"; - case 0xf02a: return "CELL_SYSMODULE_PRINT"; - case 0xf02b: return "CELL_SYSMODULE_PHOTO_IMPORT"; - case 0xf02c: return "CELL_SYSMODULE_MUSIC_EXPORT"; - case 0xf02e: return "CELL_SYSMODULE_PHOTO_DECODE"; - case 0xf02f: return "CELL_SYSMODULE_SYSUTIL_SEARCH"; - case 0xf030: return "CELL_SYSMODULE_SYSUTIL_AVCHAT2"; - case 0xf034: return "CELL_SYSMODULE_SAIL_REC"; - case 0xf035: return "CELL_SYSMODULE_SYSUTIL_NP_TROPHY"; - case 0xf054: return "CELL_SYSMODULE_LIBATRAC3MULTI"; - case 0xffff: return "CELL_SYSMODULE_INVALID"; - } - - return "UNKNOWN MODULE"; -} - -s32 cellSysmoduleInitialize() -{ - cellSysmodule.warning("cellSysmoduleInitialize()"); - return CELL_OK; -} - -s32 cellSysmoduleFinalize() -{ - cellSysmodule.warning("cellSysmoduleFinalize()"); - return CELL_OK; -} - -s32 cellSysmoduleSetMemcontainer(u32 ct_id) -{ - cellSysmodule.todo("cellSysmoduleSetMemcontainer(ct_id=0x%x)", ct_id); - return CELL_OK; -} - -s32 cellSysmoduleLoadModule(u16 id) -{ - cellSysmodule.warning("cellSysmoduleLoadModule(id=0x%04x: %s)", id, get_module_id(id)); - - if (!Emu.GetModuleManager().CheckModuleId(id)) - { - return CELL_SYSMODULE_ERROR_UNKNOWN; - } - - if (Module<>* m = Emu.GetModuleManager().GetModuleById(id)) - { - // CELL_SYSMODULE_ERROR_DUPLICATED shouldn't be returned - m->Load(); - } - - return CELL_OK; -} - -s32 cellSysmoduleUnloadModule(u16 id) -{ - cellSysmodule.warning("cellSysmoduleUnloadModule(id=0x%04x: %s)", id, get_module_id(id)); - - if (!Emu.GetModuleManager().CheckModuleId(id)) - { - return CELL_SYSMODULE_ERROR_UNKNOWN; - } - - if (Module<>* m = Emu.GetModuleManager().GetModuleById(id)) - { - if (!m->IsLoaded()) - { - cellSysmodule.error("cellSysmoduleUnloadModule() failed: module not loaded (id=0x%04x)", id); - return CELL_SYSMODULE_ERROR_FATAL; - } - - m->Unload(); - } - - return CELL_OK; -} - -s32 cellSysmoduleIsLoaded(u16 id) -{ - cellSysmodule.warning("cellSysmoduleIsLoaded(id=0x%04x: %s)", id, get_module_id(id)); - - if (!Emu.GetModuleManager().CheckModuleId(id)) - { - cellSysmodule.error("cellSysmoduleIsLoaded(): unknown module (id=0x%04x)", id); - return CELL_SYSMODULE_ERROR_UNKNOWN; - } - - if (Module<>* m = Emu.GetModuleManager().GetModuleById(id)) - { - if (!m->IsLoaded()) - { - cellSysmodule.warning("cellSysmoduleIsLoaded(): module not loaded (id=0x%04x)", id); - return CELL_SYSMODULE_ERROR_UNLOADED; - } - } - - return CELL_SYSMODULE_LOADED; -} - -Module<> cellSysmodule("cellSysmodule", []() -{ - REG_FUNC(cellSysmodule, cellSysmoduleInitialize); - REG_FUNC(cellSysmodule, cellSysmoduleFinalize); - REG_FUNC(cellSysmodule, cellSysmoduleSetMemcontainer); - REG_FUNC(cellSysmodule, cellSysmoduleLoadModule); - REG_FUNC(cellSysmodule, cellSysmoduleUnloadModule); - REG_FUNC(cellSysmodule, cellSysmoduleIsLoaded); -}); +#include "stdafx.h" +#include "Emu/System.h" +#include "Emu/Cell/PPUModule.h" + +LOG_CHANNEL(cellSysmodule); + +enum +{ + CELL_SYSMODULE_LOADED = CELL_OK, + CELL_SYSMODULE_ERROR_DUPLICATED = 0x80012001, + CELL_SYSMODULE_ERROR_UNKNOWN = 0x80012002, + CELL_SYSMODULE_ERROR_UNLOADED = 0x80012003, + CELL_SYSMODULE_ERROR_INVALID_MEMCONTAINER = 0x80012004, + CELL_SYSMODULE_ERROR_FATAL = 0x800120ff, +}; + +static const char* get_module_name(u16 id) +{ + switch (id) + { + case 0x0000: return "sys_net"; + case 0x0001: return "cellHttp"; + case 0x0002: return "cellHttpUtil"; + case 0x0003: return "cellSsl"; + case 0x0004: return "cellHttps"; + case 0x0005: return "libvdec"; + case 0x0006: return "cellAdec"; + case 0x0007: return "cellDmux"; + case 0x0008: return "cellVpost"; + case 0x0009: return "cellRtc"; + case 0x000a: return "cellSpurs"; + case 0x000b: return "cellOvis"; + case 0x000c: return "cellSheap"; + case 0x000d: return "cellSync"; + case 0x000e: return "sys_fs"; + case 0x000f: return "cellJpgDec"; + case 0x0010: return "cellGcmSys"; + case 0x0011: return "cellAudio"; + case 0x0012: return "cellPamf"; + case 0x0013: return "cellAtrac"; + case 0x0014: return "cellNetCtl"; + case 0x0015: return "cellSysutil"; + case 0x0016: return "sceNp"; + case 0x0017: return "sys_io"; + case 0x0018: return "cellPngDec"; + case 0x0019: return "cellFont"; + case 0x001a: return "cellFontFT"; + case 0x001b: return "cell_FreeType2"; + case 0x001c: return "cellUsbd"; + case 0x001d: return "cellSail"; + case 0x001e: return "cellL10n"; + case 0x001f: return "cellResc"; + case 0x0020: return "cellDaisy"; + case 0x0021: return "cellKey2char"; + case 0x0022: return "cellMic"; + case 0x0023: return "cellCamera"; + case 0x0024: return "cellVdecMpeg2"; + case 0x0025: return "cellVdecAvc"; + case 0x0026: return "cellAdecLpcm"; + case 0x0027: return "cellAdecAc3"; + case 0x0028: return "cellAdecAtx"; + case 0x0029: return "cellAdecAt3"; + case 0x002a: return "cellDmuxPamf"; + case 0x002b: return nullptr; + case 0x002c: return nullptr; + case 0x002d: return nullptr; + case 0x002e: return "sys_lv2dbg"; + case 0x002f: return "cellSysutilAvcExt"; + case 0x0030: return "cellUsbPspcm"; + case 0x0031: return "cellSysutilAvconfExt"; + case 0x0032: return "cellUserInfo"; + case 0x0033: return "cellSaveData"; + case 0x0034: return "cellSubDisplay"; + case 0x0035: return "cellRec"; + case 0x0036: return "cellVideoExportUtility"; + case 0x0037: return "cellGameExec"; + case 0x0038: return "sceNp2"; + case 0x0039: return "cellSysutilAp"; + case 0x003a: return "sceNpClans"; + case 0x003b: return "cellOskExtUtility"; + case 0x003c: return "cellVdecDivx"; + case 0x003d: return "cellJpgEnc"; + case 0x003e: return "cellGame"; + case 0x003f: return "cellBGDLUtility"; + case 0x0040: return "cell_FreeType2"; + case 0x0041: return "cellVideoUpload"; + case 0x0042: return "cellSysconfExtUtility"; + case 0x0043: return "cellFiber"; + case 0x0044: return "sceNpCommerce2"; + case 0x0045: return "sceNpTus"; + case 0x0046: return "cellVoice"; + case 0x0047: return "cellAdecCelp8"; + case 0x0048: return "cellCelp8Enc"; + case 0x0049: return "cellSysutilMisc"; + case 0x004a: return "cellMusicUtility"; + case 0x004e: return "cellScreenShotUtility"; + case 0x004f: return "cellMusicDecodeUtility"; + case 0x0050: return "cellSpursJq"; + case 0x0052: return "cellPngEnc"; + case 0x0053: return "cellMusicDecodeUtility"; + case 0x0055: return "cellSync2"; + case 0x0056: return "sceNpUtil"; + case 0x0057: return "cellRudp"; + case 0x0059: return "sceNpSns"; + case 0x005a: return "libgem"; + case 0xf00a: return "cellCelpEnc"; + case 0xf010: return "cellGifDec"; + case 0xf019: return "cellAdecCelp"; + case 0xf01b: return "cellAdecM2bc"; + case 0xf01d: return "cellAdecM4aac"; + case 0xf01e: return "cellAdecMp3"; + case 0xf023: return "cellImeJpUtility"; + case 0xf028: return "cellMusicUtility"; + case 0xf029: return "cellPhotoUtility"; + case 0xf02a: return "cellPrintUtility"; + case 0xf02b: return "cellPhotoImportUtil"; + case 0xf02c: return "cellMusicExportUtility"; + case 0xf02e: return "cellPhotoDecodeUtil"; + case 0xf02f: return "cellSearchUtility"; + case 0xf030: return "cellSysutilAvc2"; + case 0xf034: return "cellSailRec"; + case 0xf035: return "sceNpTrophy"; + case 0xf053: return "cellAdecAt3multi"; + case 0xf054: return "cellAtracMulti"; + } + + return nullptr; +} + +static const char* get_module_id(u16 id) +{ + thread_local static char tls_id_name[8]; // for test + + switch (id) + { + case 0x0000: return "CELL_SYSMODULE_NET"; + case 0x0001: return "CELL_SYSMODULE_HTTP"; + case 0x0002: return "CELL_SYSMODULE_HTTP_UTIL"; + case 0x0003: return "CELL_SYSMODULE_SSL"; + case 0x0004: return "CELL_SYSMODULE_HTTPS"; + case 0x0005: return "CELL_SYSMODULE_VDEC"; + case 0x0006: return "CELL_SYSMODULE_ADEC"; + case 0x0007: return "CELL_SYSMODULE_DMUX"; + case 0x0008: return "CELL_SYSMODULE_VPOST"; + case 0x0009: return "CELL_SYSMODULE_RTC"; + case 0x000a: return "CELL_SYSMODULE_SPURS"; + case 0x000b: return "CELL_SYSMODULE_OVIS"; + case 0x000c: return "CELL_SYSMODULE_SHEAP"; + case 0x000d: return "CELL_SYSMODULE_SYNC"; + case 0x000e: return "CELL_SYSMODULE_FS"; + case 0x000f: return "CELL_SYSMODULE_JPGDEC"; + case 0x0010: return "CELL_SYSMODULE_GCM_SYS"; + case 0x0011: return "CELL_SYSMODULE_AUDIO"; + case 0x0012: return "CELL_SYSMODULE_PAMF"; + case 0x0013: return "CELL_SYSMODULE_ATRAC3PLUS"; + case 0x0014: return "CELL_SYSMODULE_NETCTL"; + case 0x0015: return "CELL_SYSMODULE_SYSUTIL"; + case 0x0016: return "CELL_SYSMODULE_SYSUTIL_NP"; + case 0x0017: return "CELL_SYSMODULE_IO"; + case 0x0018: return "CELL_SYSMODULE_PNGDEC"; + case 0x0019: return "CELL_SYSMODULE_FONT"; + case 0x001a: return "CELL_SYSMODULE_FONTFT"; + case 0x001b: return "CELL_SYSMODULE_FREETYPE"; + case 0x001c: return "CELL_SYSMODULE_USBD"; + case 0x001d: return "CELL_SYSMODULE_SAIL"; + case 0x001e: return "CELL_SYSMODULE_L10N"; + case 0x001f: return "CELL_SYSMODULE_RESC"; + case 0x0020: return "CELL_SYSMODULE_DAISY"; + case 0x0021: return "CELL_SYSMODULE_KEY2CHAR"; + case 0x0022: return "CELL_SYSMODULE_MIC"; + case 0x0023: return "CELL_SYSMODULE_CAMERA"; + case 0x0024: return "CELL_SYSMODULE_VDEC_MPEG2"; + case 0x0025: return "CELL_SYSMODULE_VDEC_AVC"; + case 0x0026: return "CELL_SYSMODULE_ADEC_LPCM"; + case 0x0027: return "CELL_SYSMODULE_ADEC_AC3"; + case 0x0028: return "CELL_SYSMODULE_ADEC_ATX"; + case 0x0029: return "CELL_SYSMODULE_ADEC_AT3"; + case 0x002a: return "CELL_SYSMODULE_DMUX_PAMF"; + case 0x002b: return "CELL_SYSMODULE_VDEC_AL"; + case 0x002c: return "CELL_SYSMODULE_ADEC_AL"; + case 0x002d: return "CELL_SYSMODULE_DMUX_AL"; + case 0x002e: return "CELL_SYSMODULE_LV2DBG"; + case 0x002f: return "CELL_SYSMODULE_SYSUTIL_AVCHAT"; + case 0x0030: return "CELL_SYSMODULE_USBPSPCM"; + case 0x0031: return "CELL_SYSMODULE_AVCONF_EXT"; + case 0x0032: return "CELL_SYSMODULE_SYSUTIL_USERINFO"; + case 0x0033: return "CELL_SYSMODULE_SYSUTIL_SAVEDATA"; + case 0x0034: return "CELL_SYSMODULE_SUBDISPLAY"; + case 0x0035: return "CELL_SYSMODULE_SYSUTIL_REC"; + case 0x0036: return "CELL_SYSMODULE_VIDEO_EXPORT"; + case 0x0037: return "CELL_SYSMODULE_SYSUTIL_GAME_EXEC"; + case 0x0038: return "CELL_SYSMODULE_SYSUTIL_NP2"; + case 0x0039: return "CELL_SYSMODULE_SYSUTIL_AP"; + case 0x003a: return "CELL_SYSMODULE_SYSUTIL_NP_CLANS"; + case 0x003b: return "CELL_SYSMODULE_SYSUTIL_OSK_EXT"; + case 0x003c: return "CELL_SYSMODULE_VDEC_DIVX"; + case 0x003d: return "CELL_SYSMODULE_JPGENC"; + case 0x003e: return "CELL_SYSMODULE_SYSUTIL_GAME"; + case 0x003f: return "CELL_SYSMODULE_BGDL"; + case 0x0040: return "CELL_SYSMODULE_FREETYPE_TT"; + case 0x0041: return "CELL_SYSMODULE_SYSUTIL_VIDEO_UPLOAD"; + case 0x0042: return "CELL_SYSMODULE_SYSUTIL_SYSCONF_EXT"; + case 0x0043: return "CELL_SYSMODULE_FIBER"; + case 0x0044: return "CELL_SYSMODULE_SYSUTIL_NP_COMMERCE2"; + case 0x0045: return "CELL_SYSMODULE_SYSUTIL_NP_TUS"; + case 0x0046: return "CELL_SYSMODULE_VOICE"; + case 0x0047: return "CELL_SYSMODULE_ADEC_CELP8"; + case 0x0048: return "CELL_SYSMODULE_CELP8ENC"; + case 0x0049: return "CELL_SYSMODULE_SYSUTIL_LICENSEAREA"; + case 0x004a: return "CELL_SYSMODULE_SYSUTIL_MUSIC2"; + case 0x004e: return "CELL_SYSMODULE_SYSUTIL_SCREENSHOT"; + case 0x004f: return "CELL_SYSMODULE_SYSUTIL_MUSIC_DECODE"; + case 0x0050: return "CELL_SYSMODULE_SPURS_JQ"; + case 0x0052: return "CELL_SYSMODULE_PNGENC"; + case 0x0053: return "CELL_SYSMODULE_SYSUTIL_MUSIC_DECODE2"; + case 0x0055: return "CELL_SYSMODULE_SYNC2"; + case 0x0056: return "CELL_SYSMODULE_SYSUTIL_NP_UTIL"; + case 0x0057: return "CELL_SYSMODULE_RUDP"; + case 0x0059: return "CELL_SYSMODULE_SYSUTIL_NP_SNS"; + case 0x005a: return "CELL_SYSMODULE_GEM"; + case 0xf00a: return "CELL_SYSMODULE_CELPENC"; + case 0xf010: return "CELL_SYSMODULE_GIFDEC"; + case 0xf019: return "CELL_SYSMODULE_ADEC_CELP"; + case 0xf01b: return "CELL_SYSMODULE_ADEC_M2BC"; + case 0xf01d: return "CELL_SYSMODULE_ADEC_M4AAC"; + case 0xf01e: return "CELL_SYSMODULE_ADEC_MP3"; + case 0xf023: return "CELL_SYSMODULE_IMEJP"; + case 0xf028: return "CELL_SYSMODULE_SYSUTIL_MUSIC"; + case 0xf029: return "CELL_SYSMODULE_PHOTO_EXPORT"; + case 0xf02a: return "CELL_SYSMODULE_PRINT"; + case 0xf02b: return "CELL_SYSMODULE_PHOTO_IMPORT"; + case 0xf02c: return "CELL_SYSMODULE_MUSIC_EXPORT"; + case 0xf02e: return "CELL_SYSMODULE_PHOTO_DECODE"; + case 0xf02f: return "CELL_SYSMODULE_SYSUTIL_SEARCH"; + case 0xf030: return "CELL_SYSMODULE_SYSUTIL_AVCHAT2"; + case 0xf034: return "CELL_SYSMODULE_SAIL_REC"; + case 0xf035: return "CELL_SYSMODULE_SYSUTIL_NP_TROPHY"; + case 0xf054: return "CELL_SYSMODULE_LIBATRAC3MULTI"; + case 0xffff: return "CELL_SYSMODULE_INVALID"; + } + + std::snprintf(tls_id_name, sizeof(tls_id_name), "0x%04X", id); + return tls_id_name; +} + +s32 cellSysmoduleInitialize() +{ + cellSysmodule.warning("cellSysmoduleInitialize()"); + return CELL_OK; +} + +s32 cellSysmoduleFinalize() +{ + cellSysmodule.warning("cellSysmoduleFinalize()"); + return CELL_OK; +} + +s32 cellSysmoduleSetMemcontainer(u32 ct_id) +{ + cellSysmodule.todo("cellSysmoduleSetMemcontainer(ct_id=0x%x)", ct_id); + return CELL_OK; +} + +s32 cellSysmoduleLoadModule(u16 id) +{ + cellSysmodule.warning("cellSysmoduleLoadModule(id=%s)", get_module_id(id)); + + const auto name = get_module_name(id); + + if (!name) + { + cellSysmodule.error("cellSysmoduleLoadModule() failed: unknown module 0x%04X", id); + return CELL_SYSMODULE_ERROR_UNKNOWN; + } + + //if (Module<>* m = Emu.GetModuleManager().GetModuleById(id)) + //{ + // // CELL_SYSMODULE_ERROR_DUPLICATED shouldn't be returned + // m->Load(); + //} + + return CELL_OK; +} + +s32 cellSysmoduleUnloadModule(u16 id) +{ + cellSysmodule.warning("cellSysmoduleUnloadModule(id=%s)", get_module_id(id)); + + const auto name = get_module_name(id); + + if (!name) + { + cellSysmodule.error("cellSysmoduleUnloadModule() failed: unknown module 0x%04X", id); + return CELL_SYSMODULE_ERROR_UNKNOWN; + } + + //if (Module<>* m = Emu.GetModuleManager().GetModuleById(id)) + //{ + // if (!m->IsLoaded()) + // { + // cellSysmodule.error("cellSysmoduleUnloadModule() failed: module not loaded (id=0x%04x)", id); + // return CELL_SYSMODULE_ERROR_FATAL; + // } + + // m->Unload(); + //} + + return CELL_OK; +} + +s32 cellSysmoduleIsLoaded(u16 id) +{ + cellSysmodule.warning("cellSysmoduleIsLoaded(id=%s)", get_module_id(id)); + + const auto name = get_module_name(id); + + if (!name) + { + cellSysmodule.error("cellSysmoduleIsLoaded() failed: unknown module 0x%04X", id); + return CELL_SYSMODULE_ERROR_UNKNOWN; + } + + //if (Module<>* m = Emu.GetModuleManager().GetModuleById(id)) + //{ + // if (!m->IsLoaded()) + // { + // cellSysmodule.warning("cellSysmoduleIsLoaded(): module not loaded (id=0x%04x)", id); + // return CELL_SYSMODULE_ERROR_UNLOADED; + // } + //} + + return CELL_SYSMODULE_LOADED; +} + +s32 cellSysmoduleGetImagesize() +{ + UNIMPLEMENTED_FUNC(cellSysmodule); + return CELL_OK; +} + +s32 cellSysmoduleFetchImage() +{ + UNIMPLEMENTED_FUNC(cellSysmodule); + return CELL_OK; +} + +DECLARE(ppu_module_manager::cellSysmodule)("cellSysmodule", []() +{ + REG_FUNC(cellSysmodule, cellSysmoduleInitialize); + REG_FUNC(cellSysmodule, cellSysmoduleFinalize); + REG_FUNC(cellSysmodule, cellSysmoduleSetMemcontainer); + REG_FUNC(cellSysmodule, cellSysmoduleLoadModule); + REG_FUNC(cellSysmodule, cellSysmoduleUnloadModule); + REG_FUNC(cellSysmodule, cellSysmoduleIsLoaded); + REG_FUNC(cellSysmodule, cellSysmoduleGetImagesize); + REG_FUNC(cellSysmodule, cellSysmoduleFetchImage); +}); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp b/rpcs3/Emu/Cell/Modules/cellSysutil.cpp similarity index 76% rename from rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp rename to rpcs3/Emu/Cell/Modules/cellSysutil.cpp index 048dd4625c..ecf5c77899 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysutil.cpp @@ -1,19 +1,60 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/SysCalls/Callback.h" +#include "Emu/IdManager.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/FS/VFS.h" #include "cellSysutil.h" -extern Module<> cellSysutil; +LOG_CHANNEL(cellSysutil); -std::unique_ptr g_sysutil; +// Temporarily +using sys_callbacks_t = std::array, vm::ptr>, 4>; -const char* get_systemparam_id_name(s32 id) +void sysutilSendSystemCommand(u64 status, u64 param) { + if (const auto g_sys_callback = fxm::get()) + { + for (auto& cb : *g_sys_callback) + { + if (cb.first) + { + Emu.GetCallbackManager().Register([=](PPUThread& ppu) -> s32 + { + // TODO: check it and find the source of the return value (void isn't equal to CELL_OK) + cb.first(ppu, status, param, cb.second); + return CELL_OK; + }); + } + } + } +} + +cfg::map_entry g_cfg_sys_language(cfg::root.sys, "Language", +{ + { "Japanese", CELL_SYSUTIL_LANG_JAPANESE }, + { "English (US)", CELL_SYSUTIL_LANG_ENGLISH_US }, + { "French", CELL_SYSUTIL_LANG_FRENCH }, + { "Spanish", CELL_SYSUTIL_LANG_SPANISH }, + { "German", CELL_SYSUTIL_LANG_GERMAN }, + { "Italian", CELL_SYSUTIL_LANG_ITALIAN }, + { "Dutch", CELL_SYSUTIL_LANG_DUTCH }, + { "Portuguese (PT)", CELL_SYSUTIL_LANG_PORTUGUESE_PT }, + { "Russian", CELL_SYSUTIL_LANG_RUSSIAN }, + { "Korean", CELL_SYSUTIL_LANG_KOREAN }, + { "Chinese (Trad.)", CELL_SYSUTIL_LANG_CHINESE_T }, + { "Chinese (Simp.)", CELL_SYSUTIL_LANG_CHINESE_S }, + { "Finnish", CELL_SYSUTIL_LANG_FINNISH }, + { "Swedish", CELL_SYSUTIL_LANG_SWEDISH }, + { "Danish", CELL_SYSUTIL_LANG_DANISH }, + { "Norwegian", CELL_SYSUTIL_LANG_NORWEGIAN }, + { "Polish", CELL_SYSUTIL_LANG_POLISH }, + { "English (UK)", CELL_SYSUTIL_LANG_ENGLISH_GB }, +}); + +static const char* get_systemparam_id_name(s32 id) +{ + thread_local static char tls_id_name[16]; // for test + switch (id) { case CELL_SYSUTIL_SYSTEMPARAM_ID_LANG: return "ID_LANG"; @@ -33,18 +74,22 @@ const char* get_systemparam_id_name(s32 id) case CELL_SYSUTIL_SYSTEMPARAM_ID_PAD_AUTOOFF: return "ID_PAD_AUTOOFF"; case CELL_SYSUTIL_SYSTEMPARAM_ID_NICKNAME: return "ID_NICKNAME"; case CELL_SYSUTIL_SYSTEMPARAM_ID_CURRENT_USERNAME: return "ID_CURRENT_USERNAME"; - default: return "???"; } + + std::snprintf(tls_id_name, sizeof(tls_id_name), "0x%04X", id); + return tls_id_name; } s32 cellSysutilGetSystemParamInt(s32 id, vm::ptr value) { - cellSysutil.warning("cellSysutilGetSystemParamInt(id=0x%x(%s), value=*0x%x)", id, get_systemparam_id_name(id), value); + cellSysutil.warning("cellSysutilGetSystemParamInt(id=%s, value=*0x%x)", get_systemparam_id_name(id), value); + + // TODO: load this information from config (preferably "sys/" group) switch(id) { case CELL_SYSUTIL_SYSTEMPARAM_ID_LANG: - *value = rpcs3::config.system.language.value(); + *value = g_cfg_sys_language.get(); break; case CELL_SYSUTIL_SYSTEMPARAM_ID_ENTER_BUTTON_ASSIGN: @@ -133,29 +178,6 @@ s32 cellSysutilGetSystemParamString(s32 id, vm::ptr buf, u32 bufsize) return CELL_OK; } -struct sys_callback -{ - vm::ptr func; - vm::ptr arg; -} -g_sys_callback[4]; - -void sysutilSendSystemCommand(u64 status, u64 param) -{ - // TODO: check it and find the source of the return value (void isn't equal to CELL_OK) - for (auto& cb : g_sys_callback) - { - if (cb.func) - { - Emu.GetCallbackManager().Register([=](PPUThread& ppu) -> s32 - { - cb.func(ppu, status, param, cb.arg); - return CELL_OK; - }); - } - } -} - s32 cellSysutilCheckCallback(PPUThread& CPU) { cellSysutil.trace("cellSysutilCheckCallback()"); @@ -177,27 +199,25 @@ s32 cellSysutilRegisterCallback(s32 slot, vm::ptr func, vm: { cellSysutil.warning("cellSysutilRegisterCallback(slot=%d, func=*0x%x, userdata=*0x%x)", slot, func, userdata); - if ((u32)slot > 3) + if (slot >= sys_callbacks_t{}.size()) { return CELL_SYSUTIL_ERROR_VALUE; } - g_sys_callback[slot].func = func; - g_sys_callback[slot].arg = userdata; + fxm::get_always()->at(slot) = std::make_pair(func, userdata); return CELL_OK; } -s32 cellSysutilUnregisterCallback(s32 slot) +s32 cellSysutilUnregisterCallback(u32 slot) { cellSysutil.warning("cellSysutilUnregisterCallback(slot=%d)", slot); - if ((u32)slot > 3) + if (slot >= sys_callbacks_t{}.size()) { return CELL_SYSUTIL_ERROR_VALUE; } - g_sys_callback[slot].func.set(0); - g_sys_callback[slot].arg.set(0); + fxm::get_always()->at(slot) = std::make_pair(vm::null, vm::null); return CELL_OK; } @@ -205,13 +225,12 @@ s32 cellSysCacheClear(void) { cellSysutil.todo("cellSysCacheClear()"); - if (!g_sysutil->cacheMounted) + if (!fxm::check()) { return CELL_SYSCACHE_ERROR_NOTMOUNTED; } - std::string localPath; - Emu.GetVFS().GetDevice("/dev_hdd1/cache/", localPath); + const std::string& local_path = vfs::get("/dev_hdd1/cache/"); // TODO: Write tests to figure out, what is deleted. @@ -222,13 +241,15 @@ s32 cellSysCacheMount(vm::ptr param) { cellSysutil.warning("cellSysCacheMount(param=*0x%x)", param); - // TODO: implement - char id[CELL_SYSCACHE_ID_SIZE] = { '\0' }; - strncpy(id, param->cacheId, CELL_SYSCACHE_ID_SIZE - 1); - strncpy(param->getCachePath, ("/dev_hdd1/cache/"s + id + "/").c_str(), CELL_SYSCACHE_PATH_MAX); - param->getCachePath[CELL_SYSCACHE_PATH_MAX - 1] = '\0'; - Emu.GetVFS().CreateDir(param->getCachePath); - g_sysutil->cacheMounted.exchange(true); + const std::string& cache_id = param->cacheId; + ASSERT(cache_id.size() < sizeof(param->cacheId)); + + const std::string& cache_path = "/dev_hdd1/cache/" + cache_id + '/'; + strcpy_trunc(param->getCachePath, cache_path); + + // TODO: implement (what?) + fs::create_dir(vfs::get(cache_path)); + fxm::make_always(*param); return CELL_SYSCACHE_RET_OK_RELAYED; } @@ -302,7 +323,8 @@ s32 cellSysutilGetBgmPlaybackStatus2(vm::ptr stat s32 cellSysutilSetBgmPlaybackExtraParam() { - throw EXCEPTION(""); + cellSysutil.todo("cellSysutilSetBgmPlaybackExtraParam()"); + return CELL_OK; } s32 cellSysutilRegisterCallbackDispatcher() @@ -351,16 +373,8 @@ extern void cellSysutil_WebBrowser_init(); extern void cellSysutil_AudioOut_init(); extern void cellSysutil_VideoOut_init(); -Module<> cellSysutil("cellSysutil", []() +DECLARE(ppu_module_manager::cellSysutil)("cellSysutil", []() { - g_sysutil = std::make_unique(); - - for (auto& v : g_sys_callback) - { - v.func.set(0); - v.arg.set(0); - } - cellSysutil_SaveData_init(); // cellSaveData functions cellSysutil_GameData_init(); // cellGameData, cellHddGame functions cellSysutil_MsgDialog_init(); // cellMsgDialog functions diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutil.h b/rpcs3/Emu/Cell/Modules/cellSysutil.h similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/cellSysutil.h rename to rpcs3/Emu/Cell/Modules/cellSysutil.h index 1018ba4d89..69d9c2917d 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutil.h +++ b/rpcs3/Emu/Cell/Modules/cellSysutil.h @@ -82,8 +82,6 @@ enum using CellSysutilCallback = void(u64 status, u64 param, vm::ptr userdata); -void sysutilSendSystemCommand(u64 status, u64 param); - enum { CELL_SYSUTIL_ENTER_BUTTON_ASSIGN_CIRCLE = 0, @@ -197,7 +195,4 @@ struct CellSysCacheParam vm::ptr reserved; }; -struct sysutil_t -{ - std::atomic cacheMounted{ false }; -}; +extern void sysutilSendSystemCommand(u64 status, u64 param); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutilAp.cpp b/rpcs3/Emu/Cell/Modules/cellSysutilAp.cpp similarity index 87% rename from rpcs3/Emu/SysCalls/Modules/cellSysutilAp.cpp rename to rpcs3/Emu/Cell/Modules/cellSysutilAp.cpp index b2d3947b8d..f8c6d1668f 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutilAp.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysutilAp.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellSysutilAp; +LOG_CHANNEL(cellSysutilAp); // Return Codes enum @@ -35,7 +34,7 @@ s32 cellSysutilApOff() return CELL_OK; } -Module<> cellSysutilAp("cellSysutilAp", []() +DECLARE(ppu_module_manager::cellSysutilAp)("cellSysutilAp", []() { REG_FUNC(cellSysutilAp, cellSysutilApGetRequiredMemSize); REG_FUNC(cellSysutilAp, cellSysutilApOn); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutilAvc.cpp b/rpcs3/Emu/Cell/Modules/cellSysutilAvc.cpp similarity index 96% rename from rpcs3/Emu/SysCalls/Modules/cellSysutilAvc.cpp rename to rpcs3/Emu/Cell/Modules/cellSysutilAvc.cpp index b6d132419b..24b78da7b4 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutilAvc.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysutilAvc.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellSysutilAvc; +LOG_CHANNEL(cellSysutilAvc); s32 cellSysutilAvcByeRequest() { @@ -218,8 +217,6 @@ s32 cellSysutilAvcExtGetWindowShowStatus() void cellSysutil_SysutilAvc_init() { - extern Module<> cellSysutil; - REG_FUNC(cellSysutil, cellSysutilAvcByeRequest); REG_FUNC(cellSysutil, cellSysutilAvcCancelByeRequest); REG_FUNC(cellSysutil, cellSysutilAvcCancelJoinRequest); @@ -242,7 +239,7 @@ void cellSysutil_SysutilAvc_init() REG_FUNC(cellSysutil, cellSysutilAvcUnloadAsync); } -Module<> cellSysutilAvc("cellSysutilAvc", []() +DECLARE(ppu_module_manager::cellSysutilAvc)("cellSysutilAvc", []() { REG_FUNC(cellSysutilAvc, cellSysutilAvcExtInitOptionParam); REG_FUNC(cellSysutilAvc, cellSysutilAvcExtSetHideNamePlate); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutilAvc2.cpp b/rpcs3/Emu/Cell/Modules/cellSysutilAvc2.cpp similarity index 94% rename from rpcs3/Emu/SysCalls/Modules/cellSysutilAvc2.cpp rename to rpcs3/Emu/Cell/Modules/cellSysutilAvc2.cpp index 97cfb7cb29..c88ffd32d5 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutilAvc2.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysutilAvc2.cpp @@ -1,13 +1,11 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/state.h" +#include "Emu/Cell/PPUModule.h" #include "sceNp.h" #include "sceNp2.h" #include "cellSysutilAvc2.h" -extern Module<> cellSysutilAvc2; +LOG_CHANNEL(cellSysutilAvc2); s32 cellSysutilAvc2GetPlayerInfo() { @@ -133,16 +131,7 @@ s32 cellSysutilAvc2IsCameraAttached(vm::ptr status) { cellSysutilAvc2.todo("cellSysutilAvc2IsCameraAttached()"); - if (rpcs3::config.io.camera.value() == io_camera_state::null) - { - *status = CELL_AVC2_CAMERA_STATUS_DETACHED; - } - else - { - // TODO: We need to check if the camera has been turned on, but this requires further implementation of cellGem/cellCamera. - *status = CELL_AVC2_CAMERA_STATUS_ATTACHED_OFF; - } - + *status = CELL_AVC2_CAMERA_STATUS_DETACHED; return CELL_OK; } @@ -334,7 +323,7 @@ s32 cellSysutilAvc2GetWindowPosition() } -Module<> cellSysutilAvc2("cellSysutilAvc2", []() +DECLARE(ppu_module_manager::cellSysutilAvc2)("cellSysutilAvc2", []() { REG_FUNC(cellSysutilAvc2, cellSysutilAvc2GetPlayerInfo); REG_FUNC(cellSysutilAvc2, cellSysutilAvc2JoinChat); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutilAvc2.h b/rpcs3/Emu/Cell/Modules/cellSysutilAvc2.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellSysutilAvc2.h rename to rpcs3/Emu/Cell/Modules/cellSysutilAvc2.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutilMisc.cpp b/rpcs3/Emu/Cell/Modules/cellSysutilMisc.cpp similarity index 86% rename from rpcs3/Emu/SysCalls/Modules/cellSysutilMisc.cpp rename to rpcs3/Emu/Cell/Modules/cellSysutilMisc.cpp index d93bba7751..e009f8e0bc 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutilMisc.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysutilMisc.cpp @@ -1,9 +1,8 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellSysutilMisc; +LOG_CHANNEL(cellSysutilMisc); // License areas enum @@ -33,7 +32,7 @@ s32 cellSysutilGetLicenseArea() } } -Module<> cellSysutilMisc("cellSysutilMisc", []() +DECLARE(ppu_module_manager::cellSysutilMisc)("cellSysutilMisc", []() { REG_FUNC(cellSysutilMisc, cellSysutilGetLicenseArea); }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellUsbd.cpp b/rpcs3/Emu/Cell/Modules/cellUsbd.cpp similarity index 96% rename from rpcs3/Emu/SysCalls/Modules/cellUsbd.cpp rename to rpcs3/Emu/Cell/Modules/cellUsbd.cpp index bcd3476fc4..607277c74e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellUsbd.cpp +++ b/rpcs3/Emu/Cell/Modules/cellUsbd.cpp @@ -1,10 +1,9 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellUsbd.h" -extern Module<> cellUsbd; +LOG_CHANNEL(cellUsbd); s32 cellUsbdInit() { @@ -152,7 +151,7 @@ s32 cellUsbdFreeMemory() return CELL_OK; } -Module<> cellUsbd("cellUsbd", []() +DECLARE(ppu_module_manager::cellUsbd)("cellUsbd", []() { REG_FUNC(cellUsbd, cellUsbdInit); REG_FUNC(cellUsbd, cellUsbdEnd); diff --git a/rpcs3/Emu/SysCalls/Modules/cellUsbd.h b/rpcs3/Emu/Cell/Modules/cellUsbd.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellUsbd.h rename to rpcs3/Emu/Cell/Modules/cellUsbd.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellUsbpspcm.cpp b/rpcs3/Emu/Cell/Modules/cellUsbpspcm.cpp similarity index 96% rename from rpcs3/Emu/SysCalls/Modules/cellUsbpspcm.cpp rename to rpcs3/Emu/Cell/Modules/cellUsbpspcm.cpp index 30a9fe71d1..ccd4cae8bb 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellUsbpspcm.cpp +++ b/rpcs3/Emu/Cell/Modules/cellUsbpspcm.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellUsbPspcm; +LOG_CHANNEL(cellUsbPspcm); // Return Codes enum @@ -183,7 +182,7 @@ s32 cellUsbPspcmCancelWaitData() return CELL_OK; } -Module<> cellUsbPspcm("cellUsbPspcm", []() +DECLARE(ppu_module_manager::cellUsbPspcm)("cellUsbPspcm", []() { REG_FUNC(cellUsbPspcm, cellUsbPspcmInit); REG_FUNC(cellUsbPspcm, cellUsbPspcmEnd); diff --git a/rpcs3/Emu/SysCalls/Modules/cellUserInfo.cpp b/rpcs3/Emu/Cell/Modules/cellUserInfo.cpp similarity index 69% rename from rpcs3/Emu/SysCalls/Modules/cellUserInfo.cpp rename to rpcs3/Emu/Cell/Modules/cellUserInfo.cpp index a868720f4e..facf4365aa 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellUserInfo.cpp +++ b/rpcs3/Emu/Cell/Modules/cellUserInfo.cpp @@ -1,13 +1,10 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFileBase.h" #include "cellUserInfo.h" -extern Module<> cellUserInfo; +LOG_CHANNEL(cellUserInfo); s32 cellUserInfoGetStat(u32 id, vm::ptr stat) { @@ -22,24 +19,16 @@ s32 cellUserInfoGetStat(u32 id, vm::ptr stat) id = 1; } - char path[256]; - sprintf(path, "/dev_hdd0/home/%08d", id); - if (!Emu.GetVFS().ExistsDir(path)) + const std::string& path = vfs::get(fmt::format("/dev_hdd0/home/%08d/", id)); + if (!fs::is_dir(path)) return CELL_USERINFO_ERROR_NOUSER; - sprintf(path, "/dev_hdd0/home/%08d/localusername", id); - vfsStream* stream = Emu.GetVFS().OpenFile(path, fom::read); - if (!stream || !(stream->IsOpened())) + const fs::file f(path + "localusername"); + if (!f) return CELL_USERINFO_ERROR_INTERNAL; - char name [CELL_USERINFO_USERNAME_SIZE]; - memset(name, 0, CELL_USERINFO_USERNAME_SIZE); - stream->Read(name, CELL_USERINFO_USERNAME_SIZE); - stream->Close(); - delete stream; - stat->id = id; - memcpy(stat->name, name, CELL_USERINFO_USERNAME_SIZE); + strcpy_trunc(stat->name, f.to_string()); return CELL_OK; } @@ -79,7 +68,7 @@ s32 cellUserInfoGetList(vm::ptr listNum, vm::ptr list return CELL_OK; } -Module<> cellUserInfo("cellUserInfo", []() +DECLARE(ppu_module_manager::cellUserInfo)("cellUserInfo", []() { REG_FUNC(cellUserInfo, cellUserInfoGetStat); REG_FUNC(cellUserInfo, cellUserInfoSelectUser_ListType); diff --git a/rpcs3/Emu/SysCalls/Modules/cellUserInfo.h b/rpcs3/Emu/Cell/Modules/cellUserInfo.h similarity index 73% rename from rpcs3/Emu/SysCalls/Modules/cellUserInfo.h rename to rpcs3/Emu/Cell/Modules/cellUserInfo.h index a06391519c..a9a77159c0 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellUserInfo.h +++ b/rpcs3/Emu/Cell/Modules/cellUserInfo.h @@ -21,7 +21,7 @@ enum CellUserInfoParamSize CELL_USERINFO_USERNAME_SIZE = 64, }; -enum CellUserInfoListType +enum CellUserInfoListType { CELL_USERINFO_LISTTYPE_ALL = 0, CELL_USERINFO_LISTTYPE_NOCURRENT = 1, @@ -37,7 +37,7 @@ enum struct CellUserInfoUserStat { be_t id; - u8 name[CELL_USERINFO_USERNAME_SIZE]; + char name[CELL_USERINFO_USERNAME_SIZE]; }; struct CellUserInfoUserList @@ -47,17 +47,17 @@ struct CellUserInfoUserList struct CellUserInfoListSet { - be_t title_addr; // (char*) - be_t focus; + vm::bptr title; + be_t focus; // id be_t fixedListNum; - vm::ptr fixedList; - be_t reserved_addr; // (void*) + vm::bptr fixedList; + vm::bptr reserved; }; struct CellUserInfoTypeSet { - be_t title_addr; // (char*) - be_t focus; - CellUserInfoListType type; - be_t reserved_addr; // (void*) + vm::bptr title; + be_t focus; // id + be_t type; // CellUserInfoListType + vm::bptr reserved; }; diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/Cell/Modules/cellVdec.cpp similarity index 96% rename from rpcs3/Emu/SysCalls/Modules/cellVdec.cpp rename to rpcs3/Emu/Cell/Modules/cellVdec.cpp index 34e06c726f..92f33a2d66 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp +++ b/rpcs3/Emu/Cell/Modules/cellVdec.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" std::mutex g_mutex_avcodec_open2; @@ -17,7 +16,9 @@ extern "C" #include "cellPamf.h" #include "cellVdec.h" -extern Module<> cellVdec; +LOG_CHANNEL(cellVdec); + +vm::gvar _cell_vdec_prx_ver; // ??? VideoDecoder::VideoDecoder(s32 type, u32 profile, u32 addr, u32 size, vm::ptr func, u32 arg) : type(type) @@ -538,8 +539,9 @@ void vdecOpen(u32 vdec_id) // TODO: call from the constructor vdec.is_finished = true; }; - vdec.vdecCb->run(); - vdec.vdecCb->exec(); + vdec.vdecCb->cpu_init(); + vdec.vdecCb->state -= cpu_state::stop; + vdec.vdecCb->safe_notify(); } s32 cellVdecQueryAttr(vm::cptr type, vm::ptr attr) @@ -595,7 +597,7 @@ s32 cellVdecClose(u32 handle) std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } - idm::remove(vdec->vdecCb->get_id()); + idm::remove(vdec->vdecCb->id); idm::remove(handle); return CELL_OK; } @@ -948,24 +950,24 @@ s32 cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frc) return CELL_OK; } -Module<> cellVdec("cellVdec", []() +DECLARE(ppu_module_manager::cellVdec)("libvdec", []() { - //REG_VARIABLE(cellVdec, _cell_vdec_prx_ver); // 0x085a7ecb + REG_VAR(libvdec, _cell_vdec_prx_ver); // 0x085a7ecb - REG_FUNC(cellVdec, cellVdecQueryAttr); - REG_FUNC(cellVdec, cellVdecQueryAttrEx); - REG_FUNC(cellVdec, cellVdecOpen); - REG_FUNC(cellVdec, cellVdecOpenEx); - //REG_FUNC(cellVdec, cellVdecOpenExt); // 0xef4d8ad7 - REG_FUNC(cellVdec, cellVdecClose); - REG_FUNC(cellVdec, cellVdecStartSeq); - //REG_FUNC(cellVdec, cellVdecStartSeqExt); // 0xebb8e70a - REG_FUNC(cellVdec, cellVdecEndSeq); - REG_FUNC(cellVdec, cellVdecDecodeAu); - REG_FUNC(cellVdec, cellVdecGetPicture); - REG_FUNC(cellVdec, cellVdecGetPictureExt); // 0xa21aa896 - REG_FUNC(cellVdec, cellVdecGetPicItem); - //REG_FUNC(cellVdec, cellVdecGetPicItemExt); // 0x2cbd9806 - REG_FUNC(cellVdec, cellVdecSetFrameRate); - //REG_FUNC(cellVdec, cellVdecSetFrameRateExt); // 0xcffc42a5 + REG_FUNC(libvdec, cellVdecQueryAttr); + REG_FUNC(libvdec, cellVdecQueryAttrEx); + REG_FUNC(libvdec, cellVdecOpen); + REG_FUNC(libvdec, cellVdecOpenEx); + //REG_FUNC(libvdec, cellVdecOpenExt); // 0xef4d8ad7 + REG_FUNC(libvdec, cellVdecClose); + REG_FUNC(libvdec, cellVdecStartSeq); + //REG_FUNC(libvdec, cellVdecStartSeqExt); // 0xebb8e70a + REG_FUNC(libvdec, cellVdecEndSeq); + REG_FUNC(libvdec, cellVdecDecodeAu); + REG_FUNC(libvdec, cellVdecGetPicture); + REG_FUNC(libvdec, cellVdecGetPictureExt); // 0xa21aa896 + REG_FUNC(libvdec, cellVdecGetPicItem); + //REG_FUNC(libvdec, cellVdecGetPicItemExt); // 0x2cbd9806 + REG_FUNC(libvdec, cellVdecSetFrameRate); + //REG_FUNC(libvdec, cellVdecSetFrameRateExt); // 0xcffc42a5 }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.h b/rpcs3/Emu/Cell/Modules/cellVdec.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellVdec.h rename to rpcs3/Emu/Cell/Modules/cellVdec.h diff --git a/rpcs3/Emu/Cell/Modules/cellVideoExport.cpp b/rpcs3/Emu/Cell/Modules/cellVideoExport.cpp new file mode 100644 index 0000000000..266d8abc45 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellVideoExport.cpp @@ -0,0 +1,45 @@ +#include "stdafx.h" +#include "Emu/Cell/PPUModule.h" + +LOG_CHANNEL(cellVideoExport); + +s32 cellVideoExportProgress() +{ + throw EXCEPTION(""); +} + +s32 cellVideoExportInitialize2() +{ + throw EXCEPTION(""); +} + +s32 cellVideoExportInitialize() +{ + throw EXCEPTION(""); +} + +s32 cellVideoExportFromFileWithCopy() +{ + throw EXCEPTION(""); +} + +s32 cellVideoExportFromFile() +{ + throw EXCEPTION(""); +} + +s32 cellVideoExportFinalize() +{ + throw EXCEPTION(""); +} + + +DECLARE(ppu_module_manager::cellVideoExport)("cellVideoExportUtility", []() +{ + REG_FUNC(cellVideoExportUtility, cellVideoExportProgress); + REG_FUNC(cellVideoExportUtility, cellVideoExportInitialize2); + REG_FUNC(cellVideoExportUtility, cellVideoExportInitialize); + REG_FUNC(cellVideoExportUtility, cellVideoExportFromFileWithCopy); + REG_FUNC(cellVideoExportUtility, cellVideoExportFromFile); + REG_FUNC(cellVideoExportUtility, cellVideoExportFinalize); +}); diff --git a/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp b/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp new file mode 100644 index 0000000000..c3fd404652 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp @@ -0,0 +1,239 @@ +#include "stdafx.h" +#include "Emu/System.h" +#include "Emu/Cell/PPUModule.h" + +#include "cellVideoOut.h" + +extern _log::channel cellSysutil; + +cfg::map_entry g_cfg_video_out_resolution(cfg::root.video, "Resolution", "1280x720", +{ + { "1920x1080", CELL_VIDEO_OUT_RESOLUTION_1080 }, + { "1280x720", CELL_VIDEO_OUT_RESOLUTION_720 }, + { "720x480", CELL_VIDEO_OUT_RESOLUTION_480 }, + { "720x576", CELL_VIDEO_OUT_RESOLUTION_576 }, + { "1600x1080", CELL_VIDEO_OUT_RESOLUTION_1600x1080 }, + { "1440x1080", CELL_VIDEO_OUT_RESOLUTION_1440x1080 }, + { "1280x1080", CELL_VIDEO_OUT_RESOLUTION_1280x1080 }, + { "960x1080", CELL_VIDEO_OUT_RESOLUTION_960x1080 }, +}); + +cfg::map_entry g_cfg_video_out_aspect_ratio(cfg::root.video, "Aspect ratio", "16x9", +{ + { "4x3", CELL_VIDEO_OUT_ASPECT_4_3 }, + { "16x9", CELL_VIDEO_OUT_ASPECT_16_9 }, +}); + +const extern std::unordered_map g_video_out_resolution_map +{ + { CELL_VIDEO_OUT_RESOLUTION_1080, { 1920, 1080 } }, + { CELL_VIDEO_OUT_RESOLUTION_720, { 1280, 720 } }, + { CELL_VIDEO_OUT_RESOLUTION_480, { 720, 480 } }, + { CELL_VIDEO_OUT_RESOLUTION_576, { 720, 576 } }, + { CELL_VIDEO_OUT_RESOLUTION_1600x1080, { 1600, 1080 } }, + { CELL_VIDEO_OUT_RESOLUTION_1440x1080, { 1440, 1080 } }, + { CELL_VIDEO_OUT_RESOLUTION_1280x1080, { 1280, 1080 } }, + { CELL_VIDEO_OUT_RESOLUTION_960x1080, { 960, 1080 } }, +}; + +ppu_error_code cellVideoOutGetState(u32 videoOut, u32 deviceIndex, vm::ptr state) +{ + cellSysutil.trace("cellVideoOutGetState(videoOut=%d, deviceIndex=%d, state=*0x%x)", videoOut, deviceIndex, state); + + if (deviceIndex) return CELL_VIDEO_OUT_ERROR_DEVICE_NOT_FOUND; + + switch (videoOut) + { + case CELL_VIDEO_OUT_PRIMARY: + state->state = CELL_VIDEO_OUT_OUTPUT_STATE_ENABLED; + state->colorSpace = CELL_VIDEO_OUT_COLOR_SPACE_RGB; + state->displayMode.resolutionId = g_cfg_video_out_resolution.get(); // TODO + state->displayMode.scanMode = CELL_VIDEO_OUT_SCAN_MODE_PROGRESSIVE; + state->displayMode.conversion = CELL_VIDEO_OUT_DISPLAY_CONVERSION_NONE; + state->displayMode.aspect = g_cfg_video_out_aspect_ratio.get(); // TODO + state->displayMode.refreshRates = CELL_VIDEO_OUT_REFRESH_RATE_59_94HZ; + return CELL_OK; + + case CELL_VIDEO_OUT_SECONDARY: + *state = { CELL_VIDEO_OUT_OUTPUT_STATE_DISABLED }; // ??? + return CELL_OK; + } + + return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; +} + +ppu_error_code cellVideoOutGetResolution(u32 resolutionId, vm::ptr resolution) +{ + cellSysutil.trace("cellVideoOutGetResolution(resolutionId=0x%x, resolution=*0x%x)", resolutionId, resolution); + + if (!resolution) + { + return CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER; + } + + switch (resolutionId) + { + case 0x01: *resolution = { 0x780, 0x438 }; break; + case 0x02: *resolution = { 0x500, 0x2d0 }; break; + case 0x04: *resolution = { 0x2d0, 0x1e0 }; break; + case 0x05: *resolution = { 0x2d0, 0x240 }; break; + case 0x0a: *resolution = { 0x640, 0x438 }; break; + case 0x0b: *resolution = { 0x5a0, 0x438 }; break; + case 0x0c: *resolution = { 0x500, 0x438 }; break; + case 0x0d: *resolution = { 0x3c0, 0x438 }; break; + case 0x64: *resolution = { 0x550, 0x300 }; break; + case 0x81: *resolution = { 0x500, 0x5be }; break; + case 0x82: *resolution = { 0x780, 0x438 }; break; + case 0x83: *resolution = { 0x780, 0x89d }; break; + case 0x8b: *resolution = { 0x280, 0x5be }; break; + case 0x8a: *resolution = { 0x320, 0x5be }; break; + case 0x89: *resolution = { 0x3c0, 0x5be }; break; + case 0x88: *resolution = { 0x400, 0x5be }; break; + case 0x91: *resolution = { 0x500, 0x5be }; break; + case 0x92: *resolution = { 0x780, 0x438 }; break; + case 0x9b: *resolution = { 0x280, 0x5be }; break; + case 0x9a: *resolution = { 0x320, 0x5be }; break; + case 0x99: *resolution = { 0x3c0, 0x5be }; break; + case 0x98: *resolution = { 0x400, 0x5be }; break; + case 0xa1: *resolution = { 0x780, 0x438 }; break; + + default: return CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER; + } + + return CELL_OK; +} + +ppu_error_code cellVideoOutConfigure(u32 videoOut, vm::ptr config, vm::ptr option, u32 waitForEvent) +{ + cellSysutil.warning("cellVideoOutConfigure(videoOut=%d, config=*0x%x, option=*0x%x, waitForEvent=%d)", videoOut, config, option, waitForEvent); + + switch (videoOut) + { + case CELL_VIDEO_OUT_PRIMARY: + // TODO + return CELL_OK; + + case CELL_VIDEO_OUT_SECONDARY: + return CELL_OK; + } + + return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; +} + +ppu_error_code cellVideoOutGetConfiguration(u32 videoOut, vm::ptr config, vm::ptr option) +{ + cellSysutil.warning("cellVideoOutGetConfiguration(videoOut=%d, config=*0x%x, option=*0x%x)", videoOut, config, option); + + if (option) *option = {}; + *config = {}; + + switch (videoOut) + { + case CELL_VIDEO_OUT_PRIMARY: + config->resolutionId = g_cfg_video_out_resolution.get(); + config->format = CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8; + config->aspect = g_cfg_video_out_aspect_ratio.get(); + config->pitch = 4 * g_video_out_resolution_map.at(g_cfg_video_out_resolution.get()).width; + + return CELL_OK; + + case CELL_VIDEO_OUT_SECONDARY: + + return CELL_OK; + } + + return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; +} + +ppu_error_code cellVideoOutGetDeviceInfo(u32 videoOut, u32 deviceIndex, vm::ptr info) +{ + cellSysutil.warning("cellVideoOutGetDeviceInfo(videoOut=%d, deviceIndex=%d, info=*0x%x)", videoOut, deviceIndex, info); + + if (deviceIndex) return CELL_VIDEO_OUT_ERROR_DEVICE_NOT_FOUND; + + // Use standard dummy values for now. + info->portType = CELL_VIDEO_OUT_PORT_HDMI; + info->colorSpace = CELL_VIDEO_OUT_COLOR_SPACE_RGB; + info->latency = 1000; + info->availableModeCount = 1; + info->state = CELL_VIDEO_OUT_DEVICE_STATE_AVAILABLE; + info->rgbOutputRange = 1; + info->colorInfo.blueX = 0xFFFF; + info->colorInfo.blueY = 0xFFFF; + info->colorInfo.greenX = 0xFFFF; + info->colorInfo.greenY = 0xFFFF; + info->colorInfo.redX = 0xFFFF; + info->colorInfo.redY = 0xFFFF; + info->colorInfo.whiteX = 0xFFFF; + info->colorInfo.whiteY = 0xFFFF; + info->colorInfo.gamma = 100; + info->availableModes[0].aspect = 0; + info->availableModes[0].conversion = 0; + info->availableModes[0].refreshRates = 0xF; + info->availableModes[0].resolutionId = 1; + info->availableModes[0].scanMode = 0; + + return CELL_OK; +} + +ppu_error_code cellVideoOutGetNumberOfDevice(u32 videoOut) +{ + cellSysutil.warning("cellVideoOutGetNumberOfDevice(videoOut=%d)", videoOut); + + switch (videoOut) + { + case CELL_VIDEO_OUT_PRIMARY: return NOT_AN_ERROR(1); + case CELL_VIDEO_OUT_SECONDARY: return NOT_AN_ERROR(0); + } + + return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; +} + +ppu_error_code cellVideoOutGetResolutionAvailability(u32 videoOut, u32 resolutionId, u32 aspect, u32 option) +{ + cellSysutil.warning("cellVideoOutGetResolutionAvailability(videoOut=%d, resolutionId=0x%x, aspect=%d, option=%d)", videoOut, resolutionId, aspect, option); + + switch (videoOut) + { + case CELL_VIDEO_OUT_PRIMARY: return NOT_AN_ERROR(1); + case CELL_VIDEO_OUT_SECONDARY: return NOT_AN_ERROR(0); + } + + return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; +} + +s32 cellVideoOutGetConvertCursorColorInfo(vm::ptr rgbOutputRange) +{ + throw EXCEPTION(""); +} + +s32 cellVideoOutDebugSetMonitorType(u32 videoOut, u32 monitorType) +{ + throw EXCEPTION(""); +} + +s32 cellVideoOutRegisterCallback(u32 slot, vm::ptr function, vm::ptr userData) +{ + throw EXCEPTION(""); +} + +s32 cellVideoOutUnregisterCallback(u32 slot) +{ + throw EXCEPTION(""); +} + + +void cellSysutil_VideoOut_init() +{ + REG_FUNC(cellSysutil, cellVideoOutGetState); + REG_FUNC(cellSysutil, cellVideoOutGetResolution, MFF_PERFECT); + REG_FUNC(cellSysutil, cellVideoOutConfigure); + REG_FUNC(cellSysutil, cellVideoOutGetConfiguration); + REG_FUNC(cellSysutil, cellVideoOutGetDeviceInfo); + REG_FUNC(cellSysutil, cellVideoOutGetNumberOfDevice); + REG_FUNC(cellSysutil, cellVideoOutGetResolutionAvailability); + REG_FUNC(cellSysutil, cellVideoOutGetConvertCursorColorInfo); + REG_FUNC(cellSysutil, cellVideoOutDebugSetMonitorType); + REG_FUNC(cellSysutil, cellVideoOutRegisterCallback); + REG_FUNC(cellSysutil, cellVideoOutUnregisterCallback); +} diff --git a/rpcs3/Emu/Cell/Modules/cellVideoOut.h b/rpcs3/Emu/Cell/Modules/cellVideoOut.h new file mode 100644 index 0000000000..988c36335c --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellVideoOut.h @@ -0,0 +1,262 @@ +#pragma once + +namespace vm { using namespace ps3; } + +#include "Emu/Cell/ErrorCodes.h" + +// Video Out Error Codes +enum CellVideoOutError : s32 +{ + CELL_VIDEO_OUT_ERROR_NOT_IMPLEMENTED = ERROR_CODE(0x8002b220), + CELL_VIDEO_OUT_ERROR_ILLEGAL_CONFIGURATION = ERROR_CODE(0x8002b221), + CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER = ERROR_CODE(0x8002b222), + CELL_VIDEO_OUT_ERROR_PARAMETER_OUT_OF_RANGE = ERROR_CODE(0x8002b223), + CELL_VIDEO_OUT_ERROR_DEVICE_NOT_FOUND = ERROR_CODE(0x8002b224), + CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT = ERROR_CODE(0x8002b225), + CELL_VIDEO_OUT_ERROR_UNSUPPORTED_DISPLAY_MODE = ERROR_CODE(0x8002b226), + CELL_VIDEO_OUT_ERROR_CONDITION_BUSY = ERROR_CODE(0x8002b227), + CELL_VIDEO_OUT_ERROR_VALUE_IS_NOT_SET = ERROR_CODE(0x8002b228), +}; + +template<> +inline const char* ppu_error_code::print(CellVideoOutError error) +{ + switch (error) + { + STR_CASE(CELL_VIDEO_OUT_ERROR_NOT_IMPLEMENTED); + STR_CASE(CELL_VIDEO_OUT_ERROR_ILLEGAL_CONFIGURATION); + STR_CASE(CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER); + STR_CASE(CELL_VIDEO_OUT_ERROR_PARAMETER_OUT_OF_RANGE); + STR_CASE(CELL_VIDEO_OUT_ERROR_DEVICE_NOT_FOUND); + STR_CASE(CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT); + STR_CASE(CELL_VIDEO_OUT_ERROR_UNSUPPORTED_DISPLAY_MODE); + STR_CASE(CELL_VIDEO_OUT_ERROR_CONDITION_BUSY); + STR_CASE(CELL_VIDEO_OUT_ERROR_VALUE_IS_NOT_SET); + } + + return nullptr; +} + +enum CellVideoOut : s32 +{ + CELL_VIDEO_OUT_PRIMARY = 0, + CELL_VIDEO_OUT_SECONDARY = 1, +}; + +enum CellVideoOutResolutionId : s32 +{ + CELL_VIDEO_OUT_RESOLUTION_UNDEFINED = 0, + CELL_VIDEO_OUT_RESOLUTION_1080 = 1, + CELL_VIDEO_OUT_RESOLUTION_720 = 2, + CELL_VIDEO_OUT_RESOLUTION_480 = 4, + CELL_VIDEO_OUT_RESOLUTION_576 = 5, + CELL_VIDEO_OUT_RESOLUTION_1600x1080 = 0xa, + CELL_VIDEO_OUT_RESOLUTION_1440x1080 = 0xb, + CELL_VIDEO_OUT_RESOLUTION_1280x1080 = 0xc, + CELL_VIDEO_OUT_RESOLUTION_960x1080 = 0xd, + CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING = 0x81, + CELL_VIDEO_OUT_RESOLUTION_1024x720_3D_FRAME_PACKING = 0x88, + CELL_VIDEO_OUT_RESOLUTION_960x720_3D_FRAME_PACKING = 0x89, + CELL_VIDEO_OUT_RESOLUTION_800x720_3D_FRAME_PACKING = 0x8a, + CELL_VIDEO_OUT_RESOLUTION_640x720_3D_FRAME_PACKING = 0x8b, + CELL_VIDEO_OUT_RESOLUTION_720_DUALVIEW_FRAME_PACKING = 0x91, + CELL_VIDEO_OUT_RESOLUTION_720_SIMULVIEW_FRAME_PACKING = 0x91, + CELL_VIDEO_OUT_RESOLUTION_1024x720_DUALVIEW_FRAME_PACKING = 0x98, + CELL_VIDEO_OUT_RESOLUTION_1024x720_SIMULVIEW_FRAME_PACKING = 0x98, + CELL_VIDEO_OUT_RESOLUTION_960x720_DUALVIEW_FRAME_PACKING = 0x99, + CELL_VIDEO_OUT_RESOLUTION_960x720_SIMULVIEW_FRAME_PACKING = 0x99, + CELL_VIDEO_OUT_RESOLUTION_800x720_DUALVIEW_FRAME_PACKING = 0x9a, + CELL_VIDEO_OUT_RESOLUTION_800x720_SIMULVIEW_FRAME_PACKING = 0x9a, + CELL_VIDEO_OUT_RESOLUTION_640x720_DUALVIEW_FRAME_PACKING = 0x9b, + CELL_VIDEO_OUT_RESOLUTION_640x720_SIMULVIEW_FRAME_PACKING = 0x9b, +}; + +enum CellVideoOutScanMode : s32 +{ + CELL_VIDEO_OUT_SCAN_MODE_INTERLACE, + CELL_VIDEO_OUT_SCAN_MODE_PROGRESSIVE, +}; + +enum CellVideoOutScanMode2 : s32 +{ + CELL_VIDEO_OUT_SCAN_MODE2_AUTO, + CELL_VIDEO_OUT_SCAN_MODE2_INTERLACE, + CELL_VIDEO_OUT_SCAN_MODE2_PROGRESSIVE, +}; + +enum CellVideoOutRefreshRate : s32 +{ + CELL_VIDEO_OUT_REFRESH_RATE_AUTO = 0x0000, + CELL_VIDEO_OUT_REFRESH_RATE_59_94HZ = 0x0001, + CELL_VIDEO_OUT_REFRESH_RATE_50HZ = 0x0002, + CELL_VIDEO_OUT_REFRESH_RATE_60HZ = 0x0004, + CELL_VIDEO_OUT_REFRESH_RATE_30HZ = 0x0008, +}; + +enum CellVideoOutPortType : s32 +{ + CELL_VIDEO_OUT_PORT_NONE = 0x00, + CELL_VIDEO_OUT_PORT_HDMI = 0x01, + CELL_VIDEO_OUT_PORT_NETWORK = 0x41, + CELL_VIDEO_OUT_PORT_COMPOSITE_S = 0x81, + CELL_VIDEO_OUT_PORT_D = 0x82, + CELL_VIDEO_OUT_PORT_COMPONENT = 0x83, + CELL_VIDEO_OUT_PORT_RGB = 0x84, + CELL_VIDEO_OUT_PORT_AVMULTI_SCART = 0x85, + CELL_VIDEO_OUT_PORT_DSUB = 0x86, +}; + +enum CellVideoOutDisplayAspect : s32 +{ + CELL_VIDEO_OUT_ASPECT_AUTO, + CELL_VIDEO_OUT_ASPECT_4_3, + CELL_VIDEO_OUT_ASPECT_16_9, +}; + +enum CellVideoOutBufferColorFormat : s32 +{ + CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8, + CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8B8G8R8, + CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT, +}; + +enum CellVideoOutOutputState : s32 +{ + CELL_VIDEO_OUT_OUTPUT_STATE_ENABLED, + CELL_VIDEO_OUT_OUTPUT_STATE_DISABLED, + CELL_VIDEO_OUT_OUTPUT_STATE_PREPARING, +}; + +enum CellVideoOutDeviceState : s32 +{ + CELL_VIDEO_OUT_DEVICE_STATE_UNAVAILABLE, + CELL_VIDEO_OUT_DEVICE_STATE_AVAILABLE, +}; + +enum CellVideoOutColorSpace : s32 +{ + CELL_VIDEO_OUT_COLOR_SPACE_RGB = 0x01, + CELL_VIDEO_OUT_COLOR_SPACE_YUV = 0x02, + CELL_VIDEO_OUT_COLOR_SPACE_XVYCC = 0x04, +}; + +enum CellVideoOutDebugMonitorType : s32 +{ + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_UNDEFINED = 0, + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_480I_59_94HZ = 1, + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_576I_50HZ = 2, + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_480P_59_94HZ = 3, + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_576P_50HZ = 4, + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_1080I_59_94HZ = 5, + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_720P_59_94HZ = 7, + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_1080P_59_94HZ = 9, + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_WXGA_60HZ = 11, + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_SXGA_60HZ = 12, + CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_WUXGA_60HZ = 13, +}; + +struct CellVideoOutColorInfo +{ + be_t redX; + be_t redY; + be_t greenX; + be_t greenY; + be_t blueX; + be_t blueY; + be_t whiteX; + be_t whiteY; + be_t gamma; +}; + +struct CellVideoOutKSVList +{ + u8 ksv[32*5]; + u8 reserved[4]; + be_t count; +}; + +enum CellVideoOutDisplayConversion : s32 +{ + CELL_VIDEO_OUT_DISPLAY_CONVERSION_NONE = 0x00, + CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_WXGA = 0x01, + CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_SXGA = 0x02, + CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_WUXGA = 0x03, + CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_1080 = 0x05, + CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_REMOTEPLAY = 0x10, + CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_720_3D_FRAME_PACKING = 0x80, +}; + +struct CellVideoOutDisplayMode +{ + u8 resolutionId; + u8 scanMode; + u8 conversion; + u8 aspect; + u8 reserved[2]; + be_t refreshRates; +}; + +struct CellVideoOutResolution +{ + be_t width; + be_t height; +}; + +struct CellVideoOutDeviceInfo +{ + u8 portType; + u8 colorSpace; + be_t latency; + u8 availableModeCount; + u8 state; + u8 rgbOutputRange; + u8 reserved[5]; + CellVideoOutColorInfo colorInfo; + CellVideoOutDisplayMode availableModes[32]; + CellVideoOutKSVList ksvList; +}; + +struct CellVideoOutState +{ + u8 state; + u8 colorSpace; + u8 reserved[6]; + CellVideoOutDisplayMode displayMode; +}; + +struct CellVideoOutConfiguration +{ + u8 resolutionId; + u8 format; + u8 aspect; + u8 reserved[9]; + be_t pitch; +}; + +struct CellVideoOutOption +{ + be_t reserved; +}; + +enum CellVideoOutEvent : s32 +{ + CELL_VIDEO_OUT_EVENT_DEVICE_CHANGED, + CELL_VIDEO_OUT_EVENT_OUTPUT_DISABLED, + CELL_VIDEO_OUT_EVENT_DEVICE_AUTHENTICATED, + CELL_VIDEO_OUT_EVENT_OUTPUT_ENABLED, +}; + +enum CellVideoOutCopyControl : s32 +{ + CELL_VIDEO_OUT_COPY_CONTROL_COPY_FREE, + CELL_VIDEO_OUT_COPY_CONTROL_COPY_ONCE, + CELL_VIDEO_OUT_COPY_CONTROL_COPY_NEVER, +}; + +enum CellVideoOutRGBOutputRange : s32 +{ + CELL_VIDEO_OUT_RGB_OUTPUT_RANGE_LIMITED, + CELL_VIDEO_OUT_RGB_OUTPUT_RANGE_FULL, +}; + +using CellVideoOutCallback = s32(u32 slot, u32 videoOut, u32 deviceIndex, u32 event, vm::ptr info, vm::ptr userData); diff --git a/rpcs3/Emu/Cell/Modules/cellVideoUpload.cpp b/rpcs3/Emu/Cell/Modules/cellVideoUpload.cpp new file mode 100644 index 0000000000..f41f52a573 --- /dev/null +++ b/rpcs3/Emu/Cell/Modules/cellVideoUpload.cpp @@ -0,0 +1,14 @@ +#include "stdafx.h" +#include "Emu/Cell/PPUModule.h" + +LOG_CHANNEL(cellVideoUpload); + +s32 cellVideoUploadInitialize() +{ + throw EXCEPTION(""); +} + +DECLARE(ppu_module_manager::cellVideoUpload)("cellVideoUpload", []() +{ + REG_FUNC(cellVideoUpload, cellVideoUploadInitialize); +}); diff --git a/rpcs3/Emu/SysCalls/Modules/cellVoice.cpp b/rpcs3/Emu/Cell/Modules/cellVoice.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/cellVoice.cpp rename to rpcs3/Emu/Cell/Modules/cellVoice.cpp index 5083aa6823..83c227faa9 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVoice.cpp +++ b/rpcs3/Emu/Cell/Modules/cellVoice.cpp @@ -1,9 +1,8 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" -extern Module<> cellVoice; +LOG_CHANNEL(cellVoice); // Error Codes enum @@ -237,7 +236,7 @@ s32 cellVoiceDebugTopology() return CELL_OK; } -Module<> cellVoice("cellVoice", []() +DECLARE(ppu_module_manager::cellVoice)("cellVoice", []() { REG_FUNC(cellVoice, cellVoiceConnectIPortToOPort); REG_FUNC(cellVoice, cellVoiceCreateNotifyEventQueue); diff --git a/rpcs3/Emu/SysCalls/Modules/cellVpost.cpp b/rpcs3/Emu/Cell/Modules/cellVpost.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/Modules/cellVpost.cpp rename to rpcs3/Emu/Cell/Modules/cellVpost.cpp index 1f466e12db..d42d4febbc 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVpost.cpp +++ b/rpcs3/Emu/Cell/Modules/cellVpost.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" extern "C" { @@ -11,7 +10,7 @@ extern "C" #include "cellVpost.h" -extern Module<> cellVpost; +LOG_CHANNEL(cellVpost); s32 cellVpostQueryAttr(vm::cptr cfgParam, vm::ptr attr) { @@ -137,7 +136,7 @@ s32 cellVpostExec(u32 handle, vm::cptr inPicBuff, vm::cptr cellVpost("cellVpost", []() +DECLARE(ppu_module_manager::cellVpost)("cellVpost", []() { REG_FUNC(cellVpost, cellVpostQueryAttr); REG_FUNC(cellVpost, cellVpostOpen); diff --git a/rpcs3/Emu/SysCalls/Modules/cellVpost.h b/rpcs3/Emu/Cell/Modules/cellVpost.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellVpost.h rename to rpcs3/Emu/Cell/Modules/cellVpost.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellWebBrowser.cpp b/rpcs3/Emu/Cell/Modules/cellWebBrowser.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/Modules/cellWebBrowser.cpp rename to rpcs3/Emu/Cell/Modules/cellWebBrowser.cpp index 1929045f4a..4f0877a095 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellWebBrowser.cpp +++ b/rpcs3/Emu/Cell/Modules/cellWebBrowser.cpp @@ -1,10 +1,9 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" +#include "Emu/Cell/PPUModule.h" #include "cellWebBrowser.h" -extern Module<> cellSysutil; +extern _log::channel cellSysutil; s32 cellWebBrowserActivate() { diff --git a/rpcs3/Emu/SysCalls/Modules/cellWebBrowser.h b/rpcs3/Emu/Cell/Modules/cellWebBrowser.h similarity index 100% rename from rpcs3/Emu/SysCalls/Modules/cellWebBrowser.h rename to rpcs3/Emu/Cell/Modules/cellWebBrowser.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp deleted file mode 100644 index bcd8928643..0000000000 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ /dev/null @@ -1,1027 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/state.h" -#include "Emu/IdManager.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/SysCalls/Callback.h" - -#include "Emu/SysCalls/lv2/sys_sync.h" -#include "Emu/SysCalls/lv2/sys_event.h" -#include "Emu/Event.h" -#include "Emu/Audio/AudioManager.h" -#include "Emu/Audio/AudioDumper.h" - -#include "cellAudio.h" - -extern Module<> cellAudio; - -extern u64 get_system_time(); - -AudioConfig g_audio; - -std::shared_ptr g_audio_thread; - -s32 cellAudioInit() -{ - cellAudio.warning("cellAudioInit()"); - - if (!g_audio.state.compare_and_swap_test(AUDIO_STATE_NOT_INITIALIZED, AUDIO_STATE_INITIALIZED)) - { - return CELL_AUDIO_ERROR_ALREADY_INIT; - } - - // clear ports - for (auto& port : g_audio.ports) - { - port.state = AUDIO_PORT_STATE_CLOSED; - } - - // reset variables - g_audio.counter = 0; - g_audio.keys.clear(); - g_audio.start_time = get_system_time(); - - // alloc memory (only once until the emulator is stopped) - g_audio.buffer = g_audio.buffer ? g_audio.buffer : vm::alloc(AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT, vm::main); - g_audio.indexes = g_audio.indexes ? g_audio.indexes : vm::alloc(SIZE_32(u64) * AUDIO_PORT_COUNT, vm::main); - - // clear memory - std::memset(vm::base(g_audio.buffer), 0, AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT); - std::memset(vm::base(g_audio.indexes), 0, SIZE_32(u64) * AUDIO_PORT_COUNT); - - // start audio thread - g_audio_thread = thread_ctrl::spawn(PURE_EXPR("Audio Thread"s), []() - { - const bool do_dump = rpcs3::config.audio.dump_to_file.value(); - - AudioDumper m_dump; - if (do_dump && !m_dump.Init(2)) // Init AudioDumper for 2 channels - { - throw EXCEPTION("AudioDumper::Init() failed"); - } - - float buf2ch[2 * BUFFER_SIZE]; // intermediate buffer for 2 channels - float buf8ch[8 * BUFFER_SIZE]; // intermediate buffer for 8 channels - - static const size_t out_buffer_size = 8 * BUFFER_SIZE; // output buffer for 8 channels - - std::unique_ptr out_buffer[BUFFER_NUM]; - - for (u32 i = 0; i < BUFFER_NUM; i++) - { - out_buffer[i].reset(new float[out_buffer_size] {}); - } - - squeue_t out_queue; - - scope_thread_t iat(PURE_EXPR("Internal Audio Thread"s), [&out_queue]() - { - const bool use_u16 = rpcs3::config.audio.convert_to_u16.value(); - - Emu.GetAudioManager().GetAudioOut().Init(); - - bool opened = false; - float* buffer; - - while (out_queue.pop(buffer, [](){ return g_audio.state != AUDIO_STATE_INITIALIZED; })) - { - if (use_u16) - { - // convert the data from float to u16 with clipping: - // 2x MULPS - // 2x MAXPS (optional) - // 2x MINPS (optional) - // 2x CVTPS2DQ (converts float to s32) - // PACKSSDW (converts s32 to s16 with signed saturation) - - u16 buf_u16[out_buffer_size]; - for (size_t i = 0; i < out_buffer_size; i += 8) - { - const auto scale = _mm_set1_ps(0x8000); - (__m128i&)(buf_u16[i]) = _mm_packs_epi32( - _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(buffer + i), scale)), - _mm_cvtps_epi32(_mm_mul_ps(_mm_load_ps(buffer + i + 4), scale))); - } - - if (!opened) - { - Emu.GetAudioManager().GetAudioOut().Open(buf_u16, out_buffer_size * sizeof(u16)); - opened = true; - } - else - { - Emu.GetAudioManager().GetAudioOut().AddData(buf_u16, out_buffer_size * sizeof(u16)); - } - } - else - { - if (!opened) - { - Emu.GetAudioManager().GetAudioOut().Open(buffer, out_buffer_size * sizeof(float)); - opened = true; - } - else - { - Emu.GetAudioManager().GetAudioOut().AddData(buffer, out_buffer_size * sizeof(float)); - } - } - } - - Emu.GetAudioManager().GetAudioOut().Quit(); - }); - - while (g_audio.state == AUDIO_STATE_INITIALIZED && !Emu.IsStopped()) - { - if (Emu.IsPaused()) - { - std::this_thread::sleep_for(1ms); // hack - continue; - } - - const u64 stamp0 = get_system_time(); - - const u64 time_pos = stamp0 - g_audio.start_time - Emu.GetPauseTime(); - - // TODO: send beforemix event (in ~2,6 ms before mixing) - - // precise time of sleeping: 5,(3) ms (or 256/48000 sec) - const u64 expected_time = g_audio.counter * AUDIO_SAMPLES * 1000000 / 48000; - if (expected_time >= time_pos) - { - std::this_thread::sleep_for(1ms); // hack - continue; - } - - //// crutch to hide giant lags caused by debugger - //const u64 missed_time = time_pos - expected_time; - //if (missed_time > AUDIO_SAMPLES * MHZ / 48000) - //{ - // cellAudio.notice("%f ms adjusted", (float)missed_time / 1000); - // g_audio.start_time += missed_time; - //} - - g_audio.counter++; - - const u32 out_pos = g_audio.counter % BUFFER_NUM; - - bool first_mix = true; - - // mixing: - for (auto& port : g_audio.ports) - { - if (port.state != AUDIO_PORT_STATE_STARTED) continue; - - const u32 block_size = port.channel * AUDIO_SAMPLES; - const u32 position = port.tag % port.block; // old value - const u32 buf_addr = port.addr + position * block_size * sizeof(float); - - auto buf = vm::_ptr(buf_addr); - - static const float k = 1.0f; // may be 1.0f - const float& m = port.level; - - auto step_volume = [](AudioPortConfig& port) // part of cellAudioSetPortLevel functionality - { - const auto param = port.level_set.load(); - - if (param.inc != 0.0f) - { - port.level += param.inc; - const bool dec = param.inc < 0.0f; - - if ((!dec && param.value - port.level <= 0.0f) || (dec && param.value - port.level >= 0.0f)) - { - port.level = param.value; - port.level_set.compare_and_swap(param, { param.value, 0.0f }); - } - } - }; - - if (port.channel == 2) - { - if (first_mix) - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - step_volume(port); - - // reverse byte order - const float left = buf[i + 0] * m; - const float right = buf[i + 1] * m; - - buf2ch[i + 0] = left; - buf2ch[i + 1] = right; - - buf8ch[i * 4 + 0] = left; - buf8ch[i * 4 + 1] = right; - buf8ch[i * 4 + 2] = 0.0f; - buf8ch[i * 4 + 3] = 0.0f; - buf8ch[i * 4 + 4] = 0.0f; - buf8ch[i * 4 + 5] = 0.0f; - buf8ch[i * 4 + 6] = 0.0f; - buf8ch[i * 4 + 7] = 0.0f; - } - first_mix = false; - } - else - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - step_volume(port); - - const float left = buf[i + 0] * m; - const float right = buf[i + 1] * m; - - buf2ch[i + 0] += left; - buf2ch[i + 1] += right; - - buf8ch[i * 4 + 0] += left; - buf8ch[i * 4 + 1] += right; - } - } - } - else if (port.channel == 8) - { - if (first_mix) - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - step_volume(port); - - const float left = buf[i * 4 + 0] * m; - const float right = buf[i * 4 + 1] * m; - const float center = buf[i * 4 + 2] * m; - const float low_freq = buf[i * 4 + 3] * m; - const float rear_left = buf[i * 4 + 4] * m; - const float rear_right = buf[i * 4 + 5] * m; - const float side_left = buf[i * 4 + 6] * m; - const float side_right = buf[i * 4 + 7] * m; - - const float mid = (center + low_freq) * 0.708f; - buf2ch[i + 0] = (left + rear_left + side_left + mid) * k; - buf2ch[i + 1] = (right + rear_right + side_right + mid) * k; - - buf8ch[i * 4 + 0] = left; - buf8ch[i * 4 + 1] = right; - buf8ch[i * 4 + 2] = center; - buf8ch[i * 4 + 3] = low_freq; - buf8ch[i * 4 + 4] = rear_left; - buf8ch[i * 4 + 5] = rear_right; - buf8ch[i * 4 + 6] = side_left; - buf8ch[i * 4 + 7] = side_right; - } - first_mix = false; - } - else - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - step_volume(port); - - const float left = buf[i * 4 + 0] * m; - const float right = buf[i * 4 + 1] * m; - const float center = buf[i * 4 + 2] * m; - const float low_freq = buf[i * 4 + 3] * m; - const float rear_left = buf[i * 4 + 4] * m; - const float rear_right = buf[i * 4 + 5] * m; - const float side_left = buf[i * 4 + 6] * m; - const float side_right = buf[i * 4 + 7] * m; - - const float mid = (center + low_freq) * 0.708f; - buf2ch[i + 0] += (left + rear_left + side_left + mid) * k; - buf2ch[i + 1] += (right + rear_right + side_right + mid) * k; - - buf8ch[i * 4 + 0] += left; - buf8ch[i * 4 + 1] += right; - buf8ch[i * 4 + 2] += center; - buf8ch[i * 4 + 3] += low_freq; - buf8ch[i * 4 + 4] += rear_left; - buf8ch[i * 4 + 5] += rear_right; - buf8ch[i * 4 + 6] += side_left; - buf8ch[i * 4 + 7] += side_right; - } - } - } - else - { - throw EXCEPTION("Unknown channel count (port=%lld, channel=%d)", &port - g_audio.ports, port.channel); - } - - memset(buf, 0, block_size * sizeof(float)); - } - - - if (!first_mix) - { - // copy output data (2 ch) - //for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i++) - //{ - // out_buffer[out_pos][i] = buf2ch[i]; - //} - - // copy output data (8 ch) - for (u32 i = 0; i < (sizeof(buf8ch) / sizeof(float)); i++) - { - out_buffer[out_pos][i] = buf8ch[i]; - } - } - - //const u64 stamp1 = get_system_time(); - - if (first_mix) - { - memset(out_buffer[out_pos].get(), 0, out_buffer_size * sizeof(float)); - } - - if (!out_queue.push(out_buffer[out_pos].get(), [](){ return g_audio.state != AUDIO_STATE_INITIALIZED; })) - { - break; - } - - //const u64 stamp2 = get_system_time(); - - { - // update indices: - - auto indexes = vm::ptr::make(g_audio.indexes); - - for (u32 i = 0; i < AUDIO_PORT_COUNT; i++) - { - AudioPortConfig& port = g_audio.ports[i]; - - if (port.state != AUDIO_PORT_STATE_STARTED) continue; - - u32 position = port.tag % port.block; // old value - port.counter = g_audio.counter; - port.tag++; // absolute index of block that will be read - indexes[i] = (position + 1) % port.block; // write new value - } - - // send aftermix event (normal audio event) - - LV2_LOCK; - - std::lock_guard lock(g_audio.mutex); - - for (auto key : g_audio.keys) - { - if (const auto queue = Emu.GetEventManager().GetEventQueue(key)) - { - queue->push(lv2_lock, 0, 0, 0, 0); // TODO: check arguments - } - } - } - - - //const u64 stamp3 = get_system_time(); - - if (do_dump && !first_mix) - { - if (m_dump.GetCh() == 8) - { - if (m_dump.WriteData(&buf8ch, sizeof(buf8ch)) != sizeof(buf8ch)) // write file data (8 ch) - { - throw EXCEPTION("AudioDumper::WriteData() failed (8 ch)"); - } - } - else if (m_dump.GetCh() == 2) - { - if (m_dump.WriteData(&buf2ch, sizeof(buf2ch)) != sizeof(buf2ch)) // write file data (2 ch) - { - throw EXCEPTION("AudioDumper::WriteData() failed (2 ch)"); - } - } - else - { - throw EXCEPTION("AudioDumper::GetCh() returned unknown value (%d)", m_dump.GetCh()); - } - } - - //LOG_NOTICE(HLE, "Audio perf: start=%d (access=%d, AddData=%d, events=%d, dump=%d)", - //time_pos, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3); - } - }); - - return CELL_OK; -} - -s32 cellAudioQuit() -{ - cellAudio.warning("cellAudioQuit()"); - - if (!g_audio.state.compare_and_swap_test(AUDIO_STATE_INITIALIZED, AUDIO_STATE_FINALIZED)) - { - return CELL_AUDIO_ERROR_NOT_INIT; - } - - g_audio_thread->join(); - g_audio_thread.reset(); - g_audio.state.exchange(AUDIO_STATE_NOT_INITIALIZED); - - return CELL_OK; -} - -s32 cellAudioPortOpen(vm::ptr audioParam, vm::ptr portNum) -{ - cellAudio.warning("cellAudioPortOpen(audioParam=*0x%x, portNum=*0x%x)", audioParam, portNum); - - if (g_audio.state != AUDIO_STATE_INITIALIZED) - { - return CELL_AUDIO_ERROR_NOT_INIT; - } - - if (!audioParam || !portNum) - { - return CELL_AUDIO_ERROR_PARAM; - } - - const u64 channel = audioParam->nChannel; - const u64 block = audioParam->nBlock; - const u64 attr = audioParam->attr; - - // check attributes - if (channel != CELL_AUDIO_PORT_2CH && - channel != CELL_AUDIO_PORT_8CH && - channel) - { - return CELL_AUDIO_ERROR_PARAM; - } - - if (block != CELL_AUDIO_BLOCK_8 && - block != CELL_AUDIO_BLOCK_16 && - block != 2 && - block != 4 && - block != 32) - { - return CELL_AUDIO_ERROR_PARAM; - } - - // list unsupported flags - if (attr & CELL_AUDIO_PORTATTR_BGM) - { - cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_BGM"); - } - if (attr & CELL_AUDIO_PORTATTR_OUT_SECONDARY) - { - cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_SECONDARY"); - } - if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_0) - { - cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_0"); - } - if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_1) - { - cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_1"); - } - if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_2) - { - cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_2"); - } - if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_3) - { - cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_3"); - } - if (attr & CELL_AUDIO_PORTATTR_OUT_NO_ROUTE) - { - cellAudio.todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_NO_ROUTE"); - } - if (attr & 0xFFFFFFFFF0EFEFEEULL) - { - cellAudio.todo("cellAudioPortOpen(): unknown attributes (0x%llx)", attr); - } - - // open audio port - const u32 port_index = g_audio.open_port(); - - if (!~port_index) - { - return CELL_AUDIO_ERROR_PORT_FULL; - } - - AudioPortConfig& port = g_audio.ports[port_index]; - - port.channel = (u32)channel; - port.block = (u32)block; - port.attr = attr; - port.addr = g_audio.buffer + AUDIO_PORT_OFFSET * port_index; - port.read_index_addr = g_audio.indexes + sizeof(u64) * port_index; - port.size = port.channel * port.block * AUDIO_SAMPLES * sizeof(float); - port.tag = 0; - - if (port.attr & CELL_AUDIO_PORTATTR_INITLEVEL) - { - port.level = audioParam->level; - } - else - { - port.level = 1.0f; - } - - port.level_set.store({ port.level, 0.0f }); - - *portNum = port_index; - cellAudio.warning("*** audio port opened(nChannel=%d, nBlock=%d, attr=0x%llx, level=%f): port = %d", channel, block, attr, port.level, port_index); - - return CELL_OK; -} - -s32 cellAudioGetPortConfig(u32 portNum, vm::ptr portConfig) -{ - cellAudio.warning("cellAudioGetPortConfig(portNum=%d, portConfig=*0x%x)", portNum, portConfig); - - if (g_audio.state != AUDIO_STATE_INITIALIZED) - { - return CELL_AUDIO_ERROR_NOT_INIT; - } - - if (!portConfig || portNum >= AUDIO_PORT_COUNT) - { - return CELL_AUDIO_ERROR_PARAM; - } - - AudioPortConfig& port = g_audio.ports[portNum]; - - portConfig->readIndexAddr = port.read_index_addr; - - switch (auto state = port.state.load()) - { - case AUDIO_PORT_STATE_CLOSED: portConfig->status = CELL_AUDIO_STATUS_CLOSE; break; - case AUDIO_PORT_STATE_OPENED: portConfig->status = CELL_AUDIO_STATUS_READY; break; - case AUDIO_PORT_STATE_STARTED: portConfig->status = CELL_AUDIO_STATUS_RUN; break; - default: throw EXCEPTION("Invalid port state (%d: %d)", portNum, state); - } - - portConfig->nChannel = port.channel; - portConfig->nBlock = port.block; - portConfig->portSize = port.size; - portConfig->portAddr = port.addr; - return CELL_OK; -} - -s32 cellAudioPortStart(u32 portNum) -{ - cellAudio.warning("cellAudioPortStart(portNum=%d)", portNum); - - if (g_audio.state != AUDIO_STATE_INITIALIZED) - { - return CELL_AUDIO_ERROR_NOT_INIT; - } - - if (portNum >= AUDIO_PORT_COUNT) - { - return CELL_AUDIO_ERROR_PARAM; - } - - switch (auto state = g_audio.ports[portNum].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_STARTED)) - { - case AUDIO_PORT_STATE_CLOSED: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; - case AUDIO_PORT_STATE_STARTED: return CELL_AUDIO_ERROR_PORT_ALREADY_RUN; - case AUDIO_PORT_STATE_OPENED: return CELL_OK; - default: throw EXCEPTION("Invalid port state (%d: %d)", portNum, state); - } -} - -s32 cellAudioPortClose(u32 portNum) -{ - cellAudio.warning("cellAudioPortClose(portNum=%d)", portNum); - - if (g_audio.state != AUDIO_STATE_INITIALIZED) - { - return CELL_AUDIO_ERROR_NOT_INIT; - } - - if (portNum >= AUDIO_PORT_COUNT) - { - return CELL_AUDIO_ERROR_PARAM; - } - - switch (auto state = g_audio.ports[portNum].state.exchange(AUDIO_PORT_STATE_CLOSED)) - { - case AUDIO_PORT_STATE_CLOSED: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; - case AUDIO_PORT_STATE_STARTED: return CELL_OK; - case AUDIO_PORT_STATE_OPENED: return CELL_OK; - default: throw EXCEPTION("Invalid port state (%d: %d)", portNum, state); - } -} - -s32 cellAudioPortStop(u32 portNum) -{ - cellAudio.warning("cellAudioPortStop(portNum=%d)", portNum); - - if (g_audio.state != AUDIO_STATE_INITIALIZED) - { - return CELL_AUDIO_ERROR_NOT_INIT; - } - - if (portNum >= AUDIO_PORT_COUNT) - { - return CELL_AUDIO_ERROR_PARAM; - } - - switch (auto state = g_audio.ports[portNum].state.compare_and_swap(AUDIO_PORT_STATE_STARTED, AUDIO_PORT_STATE_OPENED)) - { - case AUDIO_PORT_STATE_CLOSED: return CELL_AUDIO_ERROR_PORT_NOT_RUN; - case AUDIO_PORT_STATE_STARTED: return CELL_OK; - case AUDIO_PORT_STATE_OPENED: return CELL_AUDIO_ERROR_PORT_NOT_RUN; - default: throw EXCEPTION("Invalid port state (%d: %d)", portNum, state); - } -} - -s32 cellAudioGetPortTimestamp(u32 portNum, u64 tag, vm::ptr stamp) -{ - cellAudio.trace("cellAudioGetPortTimestamp(portNum=%d, tag=0x%llx, stamp=*0x%x)", portNum, tag, stamp); - - if (g_audio.state != AUDIO_STATE_INITIALIZED) - { - return CELL_AUDIO_ERROR_NOT_INIT; - } - - if (portNum >= AUDIO_PORT_COUNT) - { - return CELL_AUDIO_ERROR_PARAM; - } - - AudioPortConfig& port = g_audio.ports[portNum]; - - if (port.state == AUDIO_PORT_STATE_CLOSED) - { - return CELL_AUDIO_ERROR_PORT_NOT_OPEN; - } - - // TODO: check tag (CELL_AUDIO_ERROR_TAG_NOT_FOUND error) - - *stamp = g_audio.start_time + Emu.GetPauseTime() + (port.counter + (tag - port.tag)) * 256000000 / 48000; - - return CELL_OK; -} - -s32 cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, vm::ptr tag) -{ - cellAudio.trace("cellAudioGetPortBlockTag(portNum=%d, blockNo=0x%llx, tag=*0x%x)", portNum, blockNo, tag); - - if (g_audio.state != AUDIO_STATE_INITIALIZED) - { - return CELL_AUDIO_ERROR_NOT_INIT; - } - - if (portNum >= AUDIO_PORT_COUNT) - { - return CELL_AUDIO_ERROR_PARAM; - } - - AudioPortConfig& port = g_audio.ports[portNum]; - - if (port.state == AUDIO_PORT_STATE_CLOSED) - { - return CELL_AUDIO_ERROR_PORT_NOT_OPEN; - } - - if (blockNo >= port.block) - { - return CELL_AUDIO_ERROR_PARAM; - } - - u64 tag_base = port.tag; - if (tag_base % port.block > blockNo) - { - tag_base &= ~(port.block - 1); - tag_base += port.block; - } - else - { - tag_base &= ~(port.block - 1); - } - *tag = tag_base + blockNo; - - return CELL_OK; -} - -s32 cellAudioSetPortLevel(u32 portNum, float level) -{ - cellAudio.trace("cellAudioSetPortLevel(portNum=%d, level=%f)", portNum, level); - - if (g_audio.state != AUDIO_STATE_INITIALIZED) - { - return CELL_AUDIO_ERROR_NOT_INIT; - } - - if (portNum >= AUDIO_PORT_COUNT) - { - return CELL_AUDIO_ERROR_PARAM; - } - - AudioPortConfig& port = g_audio.ports[portNum]; - - if (port.state == AUDIO_PORT_STATE_CLOSED) - { - return CELL_AUDIO_ERROR_PORT_NOT_OPEN; - } - - if (level >= 0.0f) - { - port.level_set.exchange({ level, (port.level - level) / 624.0f }); - } - else - { - cellAudio.todo("cellAudioSetPortLevel(%d): negative level value (%f)", portNum, level); - } - - return CELL_OK; -} - -s32 cellAudioCreateNotifyEventQueue(vm::ptr id, vm::ptr key) -{ - cellAudio.warning("cellAudioCreateNotifyEventQueue(id=*0x%x, key=*0x%x)", id, key); - - for (u64 k = 0; k < 100; k++) - { - const u64 key_value = 0x80004d494f323221ull + k; - - // register key if not used yet - if (const auto queue = Emu.GetEventManager().MakeEventQueue(key_value, SYS_SYNC_FIFO, SYS_PPU_QUEUE, 0, key_value, 32)) - { - *id = queue->id; - *key = key_value; - - return CELL_OK; - } - } - - return CELL_AUDIO_ERROR_EVENT_QUEUE; -} - -s32 cellAudioCreateNotifyEventQueueEx(vm::ptr id, vm::ptr key, u32 iFlags) -{ - cellAudio.todo("cellAudioCreateNotifyEventQueueEx(id=*0x%x, key=*0x%x, iFlags=0x%x)", id, key, iFlags); - - if (iFlags & ~CELL_AUDIO_CREATEEVENTFLAG_SPU) - { - return CELL_AUDIO_ERROR_PARAM; - } - - // TODO - - return CELL_AUDIO_ERROR_EVENT_QUEUE; -} - -s32 cellAudioSetNotifyEventQueue(u64 key) -{ - cellAudio.warning("cellAudioSetNotifyEventQueue(key=0x%llx)", key); - - if (g_audio.state != AUDIO_STATE_INITIALIZED) - { - return CELL_AUDIO_ERROR_NOT_INIT; - } - - std::lock_guard lock(g_audio.mutex); - - for (auto k : g_audio.keys) // check for duplicates - { - if (k == key) - { - return CELL_AUDIO_ERROR_TRANS_EVENT; - } - } - - g_audio.keys.emplace_back(key); - - return CELL_OK; -} - -s32 cellAudioSetNotifyEventQueueEx(u64 key, u32 iFlags) -{ - cellAudio.todo("cellAudioSetNotifyEventQueueEx(key=0x%llx, iFlags=0x%x)", key, iFlags); - - // TODO - - return CELL_OK; -} - -s32 cellAudioRemoveNotifyEventQueue(u64 key) -{ - cellAudio.warning("cellAudioRemoveNotifyEventQueue(key=0x%llx)", key); - - if (g_audio.state != AUDIO_STATE_INITIALIZED) - { - return CELL_AUDIO_ERROR_NOT_INIT; - } - - std::lock_guard lock(g_audio.mutex); - - for (auto i = g_audio.keys.begin(); i != g_audio.keys.end(); i++) - { - if (*i == key) - { - g_audio.keys.erase(i); - - return CELL_OK; - } - } - - return CELL_AUDIO_ERROR_TRANS_EVENT; -} - -s32 cellAudioRemoveNotifyEventQueueEx(u64 key, u32 iFlags) -{ - cellAudio.todo("cellAudioRemoveNotifyEventQueueEx(key=0x%llx, iFlags=0x%x)", key, iFlags); - - // TODO - - return CELL_OK; -} - -s32 cellAudioAddData(u32 portNum, vm::ptr src, u32 samples, float volume) -{ - cellAudio.trace("cellAudioAddData(portNum=%d, src=*0x%x, samples=%d, volume=%f)", portNum, src, samples, volume); - - if (g_audio.state != AUDIO_STATE_INITIALIZED) - { - return CELL_AUDIO_ERROR_NOT_INIT; - } - - if (portNum >= AUDIO_PORT_COUNT || !src || !src.aligned()) - { - return CELL_AUDIO_ERROR_PARAM; - } - - if (samples != 256) - { - // despite the docs, seems that only fixed value is supported - cellAudio.error("cellAudioAddData(): invalid samples value (%d)", samples); - return CELL_AUDIO_ERROR_PARAM; - } - - const AudioPortConfig& port = g_audio.ports[portNum]; - - const auto dst = vm::ptr::make(port.addr + u32(port.tag % port.block) * port.channel * 256 * SIZE_32(float)); - - for (u32 i = 0; i < samples * port.channel; i++) - { - dst[i] += src[i] * volume; // mix all channels - } - - return CELL_OK; -} - -s32 cellAudioAdd2chData(u32 portNum, vm::ptr src, u32 samples, float volume) -{ - cellAudio.trace("cellAudioAdd2chData(portNum=%d, src=*0x%x, samples=%d, volume=%f)", portNum, src, samples, volume); - - if (g_audio.state != AUDIO_STATE_INITIALIZED) - { - return CELL_AUDIO_ERROR_NOT_INIT; - } - - if (portNum >= AUDIO_PORT_COUNT || !src || !src.aligned()) - { - return CELL_AUDIO_ERROR_PARAM; - } - - if (samples != 256) - { - // despite the docs, seems that only fixed value is supported - cellAudio.error("cellAudioAdd2chData(): invalid samples value (%d)", samples); - return CELL_AUDIO_ERROR_PARAM; - } - - const AudioPortConfig& port = g_audio.ports[portNum]; - - const auto dst = vm::ptr::make(port.addr + s32(port.tag % port.block) * port.channel * 256 * SIZE_32(float)); - - if (port.channel == 2) - { - cellAudio.error("cellAudioAdd2chData(portNum=%d): port.channel = 2", portNum); - } - else if (port.channel == 6) - { - for (u32 i = 0; i < samples; i++) - { - dst[i * 6 + 0] += src[i * 2 + 0] * volume; // mix L ch - dst[i * 6 + 1] += src[i * 2 + 1] * volume; // mix R ch - //dst[i * 6 + 2] += 0.0f; // center - //dst[i * 6 + 3] += 0.0f; // LFE - //dst[i * 6 + 4] += 0.0f; // rear L - //dst[i * 6 + 5] += 0.0f; // rear R - } - } - else if (port.channel == 8) - { - for (u32 i = 0; i < samples; i++) - { - dst[i * 8 + 0] += src[i * 2 + 0] * volume; // mix L ch - dst[i * 8 + 1] += src[i * 2 + 1] * volume; // mix R ch - //dst[i * 8 + 2] += 0.0f; // center - //dst[i * 8 + 3] += 0.0f; // LFE - //dst[i * 8 + 4] += 0.0f; // rear L - //dst[i * 8 + 5] += 0.0f; // rear R - //dst[i * 8 + 6] += 0.0f; // side L - //dst[i * 8 + 7] += 0.0f; // side R - } - } - else - { - cellAudio.error("cellAudioAdd2chData(portNum=%d): invalid port.channel value (%d)", portNum, port.channel); - } - - return CELL_OK; -} - -s32 cellAudioAdd6chData(u32 portNum, vm::ptr src, float volume) -{ - cellAudio.trace("cellAudioAdd6chData(portNum=%d, src=*0x%x, volume=%f)", portNum, src, volume); - - if (g_audio.state != AUDIO_STATE_INITIALIZED) - { - return CELL_AUDIO_ERROR_NOT_INIT; - } - - if (portNum >= AUDIO_PORT_COUNT || !src || !src.aligned()) - { - return CELL_AUDIO_ERROR_PARAM; - } - - const AudioPortConfig& port = g_audio.ports[portNum]; - - const auto dst = vm::ptr::make(port.addr + s32(port.tag % port.block) * port.channel * 256 * SIZE_32(float)); - - if (port.channel == 2 || port.channel == 6) - { - cellAudio.error("cellAudioAdd2chData(portNum=%d): port.channel = %d", portNum, port.channel); - } - else if (port.channel == 8) - { - for (u32 i = 0; i < 256; i++) - { - dst[i * 8 + 0] += src[i * 6 + 0] * volume; // mix L ch - dst[i * 8 + 1] += src[i * 6 + 1] * volume; // mix R ch - dst[i * 8 + 2] += src[i * 6 + 2] * volume; // mix center - dst[i * 8 + 3] += src[i * 6 + 3] * volume; // mix LFE - dst[i * 8 + 4] += src[i * 6 + 4] * volume; // mix rear L - dst[i * 8 + 5] += src[i * 6 + 5] * volume; // mix rear R - //dst[i * 8 + 6] += 0.0f; // side L - //dst[i * 8 + 7] += 0.0f; // side R - } - } - else - { - cellAudio.error("cellAudioAdd6chData(portNum=%d): invalid port.channel value (%d)", portNum, port.channel); - } - - return CELL_OK; -} - -s32 cellAudioMiscSetAccessoryVolume(u32 devNum, float volume) -{ - cellAudio.todo("cellAudioMiscSetAccessoryVolume(devNum=%d, volume=%f)", devNum, volume); - return CELL_OK; -} - -s32 cellAudioSendAck(u64 data3) -{ - cellAudio.todo("cellAudioSendAck(data3=0x%llx)", data3); - return CELL_OK; -} - -s32 cellAudioSetPersonalDevice(s32 iPersonalStream, s32 iDevice) -{ - cellAudio.todo("cellAudioSetPersonalDevice(iPersonalStream=%d, iDevice=%d)", iPersonalStream, iDevice); - return CELL_OK; -} - -s32 cellAudioUnsetPersonalDevice(s32 iPersonalStream) -{ - cellAudio.todo("cellAudioUnsetPersonalDevice(iPersonalStream=%d)", iPersonalStream); - return CELL_OK; -} - -Module<> cellAudio("cellAudio", []() -{ - g_audio.state = AUDIO_STATE_NOT_INITIALIZED; - g_audio.buffer = 0; - g_audio.indexes = 0; - - REG_FUNC(cellAudio, cellAudioInit); - REG_FUNC(cellAudio, cellAudioPortClose); - REG_FUNC(cellAudio, cellAudioPortStop); - REG_FUNC(cellAudio, cellAudioGetPortConfig); - REG_FUNC(cellAudio, cellAudioPortStart); - REG_FUNC(cellAudio, cellAudioQuit); - REG_FUNC(cellAudio, cellAudioPortOpen); - REG_FUNC(cellAudio, cellAudioSetPortLevel); - REG_FUNC(cellAudio, cellAudioCreateNotifyEventQueue); - REG_FUNC(cellAudio, cellAudioCreateNotifyEventQueueEx); - REG_FUNC(cellAudio, cellAudioMiscSetAccessoryVolume); - REG_FUNC(cellAudio, cellAudioSetNotifyEventQueue); - REG_FUNC(cellAudio, cellAudioSetNotifyEventQueueEx); - REG_FUNC(cellAudio, cellAudioGetPortTimestamp); - REG_FUNC(cellAudio, cellAudioAdd2chData); - REG_FUNC(cellAudio, cellAudioAdd6chData); - REG_FUNC(cellAudio, cellAudioAddData); - REG_FUNC(cellAudio, cellAudioGetPortBlockTag); - REG_FUNC(cellAudio, cellAudioRemoveNotifyEventQueue); - REG_FUNC(cellAudio, cellAudioRemoveNotifyEventQueueEx); - REG_FUNC(cellAudio, cellAudioSendAck); - REG_FUNC(cellAudio, cellAudioSetPersonalDevice); - REG_FUNC(cellAudio, cellAudioUnsetPersonalDevice); -}); diff --git a/rpcs3/Emu/SysCalls/Modules/cellNetCtl.cpp b/rpcs3/Emu/SysCalls/Modules/cellNetCtl.cpp deleted file mode 100644 index 170e405e9e..0000000000 --- a/rpcs3/Emu/SysCalls/Modules/cellNetCtl.cpp +++ /dev/null @@ -1,455 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/state.h" -#include "Emu/SysCalls/Modules.h" - -#include "cellSysutil.h" -#include "cellNetCtl.h" - -#ifdef _WIN32 -#include -#include -#include - -#pragma comment(lib, "iphlpapi.lib") -#else -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -extern Module<> cellNetCtl; - -s32 cellNetCtlInit() -{ - cellNetCtl.warning("cellNetCtlInit()"); - - return CELL_OK; -} - -s32 cellNetCtlTerm() -{ - cellNetCtl.warning("cellNetCtlTerm()"); - - return CELL_OK; -} - -s32 cellNetCtlGetState(vm::ptr state) -{ - cellNetCtl.trace("cellNetCtlGetState(state=*0x%x)", state); - - switch (rpcs3::config.misc.net.status.value()) - { - case misc_net_status::ip_obtained: *state = CELL_NET_CTL_STATE_IPObtained; break; - case misc_net_status::obtaining_ip: *state = CELL_NET_CTL_STATE_IPObtaining; break; - case misc_net_status::connecting: *state = CELL_NET_CTL_STATE_Connecting; break; - case misc_net_status::disconnected: *state = CELL_NET_CTL_STATE_Disconnected; break; - - default: *state = CELL_NET_CTL_STATE_Disconnected; break; - } - - return CELL_OK; -} - -s32 cellNetCtlAddHandler(vm::ptr handler, vm::ptr arg, vm::ptr hid) -{ - cellNetCtl.todo("cellNetCtlAddHandler(handler=*0x%x, arg=*0x%x, hid=*0x%x)", handler, arg, hid); - - return CELL_OK; -} - -s32 cellNetCtlDelHandler(s32 hid) -{ - cellNetCtl.todo("cellNetCtlDelHandler(hid=0x%x)", hid); - - return CELL_OK; -} - -s32 cellNetCtlGetInfo(s32 code, vm::ptr info) -{ - cellNetCtl.todo("cellNetCtlGetInfo(code=0x%x (%s), info=*0x%x)", code, InfoCodeToName(code), info); - - if (code == CELL_NET_CTL_INFO_MTU) - { -#ifdef _WIN32 - ULONG bufLen = sizeof(PIP_ADAPTER_ADDRESSES) + 1; - PIP_ADAPTER_ADDRESSES pAddresses = (PIP_ADAPTER_ADDRESSES)malloc(bufLen); - DWORD ret; - - ret = GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &bufLen); - - if (ret == ERROR_BUFFER_OVERFLOW) - { - cellNetCtl.error("cellNetCtlGetInfo(INFO_MTU): GetAdaptersAddresses buffer overflow."); - free(pAddresses); - pAddresses = (PIP_ADAPTER_ADDRESSES)malloc(bufLen); - - if (pAddresses == nullptr) - { - cellNetCtl.error("cellNetCtlGetInfo(INFO_MTU): Unable to allocate memory for pAddresses."); - return CELL_NET_CTL_ERROR_NET_CABLE_NOT_CONNECTED; - } - } - - ret = GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &bufLen); - - if (ret == NO_ERROR) - { - PIP_ADAPTER_ADDRESSES pCurrAddresses = pAddresses; - - for (int c = 0; c < rpcs3::config.misc.net._interface.value(); c++) - { - pCurrAddresses = pCurrAddresses->Next; - } - - info->mtu = pCurrAddresses->Mtu; - } - else - { - cellNetCtl.error("cellNetCtlGetInfo(INFO_MTU): Call to GetAdaptersAddresses failed. (%d)", ret); - info->mtu = 1500; // Seems to be the default value on Windows 10. - } - - free(pAddresses); -#else - struct ifaddrs *ifaddr, *ifa; - s32 family, n; - - if (getifaddrs(&ifaddr) == -1) - { - cellNetCtl.error("cellNetCtlGetInfo(INFO_MTU): Call to getifaddrs returned negative."); - } - - for (ifa = ifaddr, n = 0; ifa != nullptr; ifa = ifa->ifa_next, n++) - { - if (ifa->ifa_addr == nullptr) - { - continue; - } - - if (n < rpcs3::config.misc.net._interface.value()) - { - continue; - } - - family = ifa->ifa_addr->sa_family; - - if (family == AF_INET) - { - u32 fd = open("/proc/net/dev", O_RDONLY); - struct ifreq freq; - - if (ioctl(fd, SIOCGIFMTU, &freq) == -1) - { - cellNetCtl.error("cellNetCtlGetInfo(INFO_MTU): Call to ioctl failed."); - } - else - { - info->mtu = (u32)freq.ifr_mtu; - } - - close(fd); - } - } - - freeifaddrs(ifaddr); -#endif - } - else if (code == CELL_NET_CTL_INFO_LINK) - { - if (rpcs3::config.misc.net.status.value() == misc_net_status::ip_obtained) - { - info->link = CELL_NET_CTL_LINK_CONNECTED; - } - else - { - info->link = CELL_NET_CTL_LINK_DISCONNECTED; - } - } - else if (code == CELL_NET_CTL_INFO_IP_ADDRESS) - { - // 0.0.0.0 seems to be the default address when no ethernet cables are connected to the PS3 - strcpy_trunc(info->ip_address, "0.0.0.0"); - -#ifdef _WIN32 - ULONG bufLen = sizeof(IP_ADAPTER_INFO); - PIP_ADAPTER_INFO pAdapterInfo = (IP_ADAPTER_INFO*)malloc(bufLen); - DWORD ret; - - ret = GetAdaptersInfo(pAdapterInfo, &bufLen); - - if (ret == ERROR_BUFFER_OVERFLOW) - { - cellNetCtl.error("cellNetCtlGetInfo(IP_ADDRESS): GetAdaptersInfo buffer overflow."); - free(pAdapterInfo); - pAdapterInfo = (IP_ADAPTER_INFO*)malloc(bufLen); - - if (pAdapterInfo == nullptr) - { - cellNetCtl.error("cellNetCtlGetInfo(IP_ADDRESS): Unable to allocate memory for pAddresses."); - return CELL_NET_CTL_ERROR_NET_CABLE_NOT_CONNECTED; - } - } - - ret = GetAdaptersInfo(pAdapterInfo, &bufLen); - - if (ret == NO_ERROR) - { - PIP_ADAPTER_INFO pAdapter = pAdapterInfo; - - for (int c = 0; c < rpcs3::config.misc.net._interface.value(); c++) - { - pAdapter = pAdapter->Next; - } - - strcpy_trunc(info->ip_address, pAdapter->IpAddressList.IpAddress.String); - } - else - { - cellNetCtl.error("cellNetCtlGetInfo(IP_ADDRESS): Call to GetAdaptersInfo failed. (%d)", ret); - } - - free(pAdapterInfo); -#else - struct ifaddrs *ifaddr, *ifa; - s32 family, n; - - if (getifaddrs(&ifaddr) == -1) - { - cellNetCtl.error("cellNetCtlGetInfo(IP_ADDRESS): Call to getifaddrs returned negative."); - } - - for (ifa = ifaddr, n = 0; ifa != nullptr; ifa = ifa->ifa_next, n++) - { - if (ifa->ifa_addr == nullptr) - { - continue; - } - - if (n < rpcs3::config.misc.net._interface.value()) - { - continue; - } - - family = ifa->ifa_addr->sa_family; - - if (family == AF_INET) - { - strcpy_trunc(info->ip_address, ifa->ifa_addr->sa_data); - } - } - - freeifaddrs(ifaddr); -#endif - } - else if (code == CELL_NET_CTL_INFO_NETMASK) - { -#ifdef _WIN32 - ULONG bufLen = sizeof(IP_ADAPTER_INFO) + 1; - PIP_ADAPTER_INFO pAdapterInfo = (PIP_ADAPTER_INFO)malloc(bufLen); - DWORD ret; - - ret = GetAdaptersInfo(pAdapterInfo, &bufLen); - - if (ret == ERROR_BUFFER_OVERFLOW) - { - cellNetCtl.error("cellNetCtlGetInfo(INFO_NETMASK): GetAdaptersInfo buffer overflow."); - free(pAdapterInfo); - pAdapterInfo = (IP_ADAPTER_INFO*)malloc(bufLen); - - if (pAdapterInfo == nullptr) - { - cellNetCtl.error("cellNetCtlGetInfo(INFO_NETMASK): Unable to allocate memory for pAddresses."); - return CELL_NET_CTL_ERROR_NET_CABLE_NOT_CONNECTED; - } - } - - ret = GetAdaptersInfo(pAdapterInfo, &bufLen); - - if (ret == NO_ERROR) - { - PIP_ADAPTER_INFO pAdapter = pAdapterInfo; - - for (int c = 0; c < rpcs3::config.misc.net._interface.value(); c++) - { - pAdapter = pAdapter->Next; - } - - for (int c = 0; c < 4; c++) - { - info->netmask[c] = (s8)pAdapter->IpAddressList.IpMask.String; - } - } - else - { - cellNetCtl.error("cellNetCtlGetInfo(INFO_NETMASK): Call to GetAdaptersInfo failed. (%d)", ret); - // TODO: Is this the default netmask? - info->netmask[0] = 255; - info->netmask[1] = 255; - info->netmask[2] = 255; - info->netmask[3] = 0; - } - - free(pAdapterInfo); -#else - struct ifaddrs *ifaddr, *ifa; - s32 family, n; - - if (getifaddrs(&ifaddr) == -1) - { - cellNetCtl.error("cellNetCtlGetInfo(INFO_NETMASK): Call to getifaddrs returned negative."); - } - - for (ifa = ifaddr, n = 0; ifa != nullptr; ifa = ifa->ifa_next, n++) - { - if (ifa->ifa_addr == nullptr) - { - continue; - } - - if (n < rpcs3::config.misc.net._interface.value()) - { - continue; - } - - family = ifa->ifa_addr->sa_family; - - if (family == AF_INET) - { - strcpy_trunc(info->ip_address, ifa->ifa_netmask->sa_data); - } - } - - freeifaddrs(ifaddr); -#endif - } - - return CELL_OK; -} - -s32 cellNetCtlNetStartDialogLoadAsync(vm::ptr param) -{ - cellNetCtl.error("cellNetCtlNetStartDialogLoadAsync(param=*0x%x)", param); - - // TODO: Actually sign into PSN or an emulated network similar to PSN (ESN) - // TODO: Properly open the dialog prompt for sign in - sysutilSendSystemCommand(CELL_SYSUTIL_NET_CTL_NETSTART_LOADED, 0); - sysutilSendSystemCommand(CELL_SYSUTIL_NET_CTL_NETSTART_FINISHED, 0); - - return CELL_OK; -} - -s32 cellNetCtlNetStartDialogAbortAsync() -{ - cellNetCtl.error("cellNetCtlNetStartDialogAbortAsync()"); - - return CELL_OK; -} - -s32 cellNetCtlNetStartDialogUnloadAsync(vm::ptr result) -{ - cellNetCtl.warning("cellNetCtlNetStartDialogUnloadAsync(result=*0x%x)", result); - - result->result = CELL_NET_CTL_ERROR_DIALOG_CANCELED; - sysutilSendSystemCommand(CELL_SYSUTIL_NET_CTL_NETSTART_UNLOADED, 0); - - return CELL_OK; -} - -s32 cellNetCtlGetNatInfo(vm::ptr natInfo) -{ - cellNetCtl.todo("cellNetCtlGetNatInfo(natInfo=*0x%x)", natInfo); - - if (natInfo->size == 0) - { - cellNetCtl.error("cellNetCtlGetNatInfo : CELL_NET_CTL_ERROR_INVALID_SIZE"); - return CELL_NET_CTL_ERROR_INVALID_SIZE; - } - - return CELL_OK; -} - -s32 cellGameUpdateInit() -{ - throw EXCEPTION(""); -} - -s32 cellGameUpdateTerm() -{ - throw EXCEPTION(""); -} - - -s32 cellGameUpdateCheckStartAsync() -{ - throw EXCEPTION(""); -} - -s32 cellGameUpdateCheckFinishAsync() -{ - throw EXCEPTION(""); -} - -s32 cellGameUpdateCheckStartWithoutDialogAsync() -{ - throw EXCEPTION(""); -} - -s32 cellGameUpdateCheckAbort() -{ - throw EXCEPTION(""); -} - -s32 cellGameUpdateCheckStartAsyncEx() -{ - throw EXCEPTION(""); -} - -s32 cellGameUpdateCheckFinishAsyncEx() -{ - throw EXCEPTION(""); -} - -s32 cellGameUpdateCheckStartWithoutDialogAsyncEx() -{ - throw EXCEPTION(""); -} - - -Module<> cellNetCtl("cellNetCtl", []() -{ - REG_FUNC(cellNetCtl, cellNetCtlInit); - REG_FUNC(cellNetCtl, cellNetCtlTerm); - - REG_FUNC(cellNetCtl, cellNetCtlGetState); - REG_FUNC(cellNetCtl, cellNetCtlAddHandler); - REG_FUNC(cellNetCtl, cellNetCtlDelHandler); - - REG_FUNC(cellNetCtl, cellNetCtlGetInfo); - - REG_FUNC(cellNetCtl, cellNetCtlNetStartDialogLoadAsync); - REG_FUNC(cellNetCtl, cellNetCtlNetStartDialogAbortAsync); - REG_FUNC(cellNetCtl, cellNetCtlNetStartDialogUnloadAsync); - - REG_FUNC(cellNetCtl, cellNetCtlGetNatInfo); - - REG_FUNC(cellNetCtl, cellGameUpdateInit); - REG_FUNC(cellNetCtl, cellGameUpdateTerm); - - REG_FUNC(cellNetCtl, cellGameUpdateCheckStartAsync); - REG_FUNC(cellNetCtl, cellGameUpdateCheckFinishAsync); - REG_FUNC(cellNetCtl, cellGameUpdateCheckStartWithoutDialogAsync); - REG_FUNC(cellNetCtl, cellGameUpdateCheckAbort); - REG_FUNC(cellNetCtl, cellGameUpdateCheckStartAsyncEx); - REG_FUNC(cellNetCtl, cellGameUpdateCheckFinishAsyncEx); - REG_FUNC(cellNetCtl, cellGameUpdateCheckStartWithoutDialogAsyncEx); -}); diff --git a/rpcs3/Emu/SysCalls/Modules/cellResc.cpp b/rpcs3/Emu/SysCalls/Modules/cellResc.cpp deleted file mode 100644 index da4df9b68e..0000000000 --- a/rpcs3/Emu/SysCalls/Modules/cellResc.cpp +++ /dev/null @@ -1,1287 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" - -#include "cellSysutil.h" -#include "Emu/SysCalls/Modules/cellVideoOut.h" -#include "Emu/RSX/GSManager.h" -#include "Emu/RSX/GSRender.h" -#include "cellResc.h" - -extern Module<> cellResc; - -extern s32 cellVideoOutConfigure(u32 videoOut, vm::ptr config, vm::ptr option, u32 waitForEvent); -extern s32 cellGcmSetFlipMode(u32 mode); -extern void cellGcmSetFlipHandler(vm::ptr handler); -extern void cellGcmSetVBlankHandler(vm::ptr handler); -extern s32 cellGcmAddressToOffset(u32 address, vm::ptr offset); -extern s32 cellGcmSetDisplayBuffer(u32 id, u32 offset, u32 pitch, u32 width, u32 height); -extern s32 cellGcmSetPrepareFlip(PPUThread& ppu, vm::ptr ctx, u32 id); -extern s32 cellGcmSetSecondVFrequency(u32 freq); -extern u32 cellGcmGetLabelAddress(u8 index); -extern u32 cellGcmGetTiledPitchSize(u32 size); - -CCellRescInternal* s_rescInternalInstance = nullptr; - -// Local Functions -s32 cellRescGetNumColorBuffers(u32 dstMode, u32 palTemporalMode, u32 reserved); - -// Help Functions -inline bool IsPal() { return s_rescInternalInstance->m_dstMode == CELL_RESC_720x576; } -inline bool IsPal60Hsync() { return (IsPal() && s_rescInternalInstance->m_initConfig.palTemporalMode == CELL_RESC_PAL_60_FOR_HSYNC); } -inline bool IsPalDrop() { return (IsPal() && s_rescInternalInstance->m_initConfig.palTemporalMode == CELL_RESC_PAL_60_DROP); } -inline bool IsPalInterpolate() { - return (IsPal() && ((s_rescInternalInstance->m_initConfig.palTemporalMode == CELL_RESC_PAL_60_INTERPOLATE) - || (s_rescInternalInstance->m_initConfig.palTemporalMode == CELL_RESC_PAL_60_INTERPOLATE_30_DROP) - || (s_rescInternalInstance->m_initConfig.palTemporalMode == CELL_RESC_PAL_60_INTERPOLATE_DROP_FLEXIBLE))); -} -inline bool IsNotPalInterpolate() { return !IsPalInterpolate(); } -inline bool IsPalTemporal() { return (IsPal() && s_rescInternalInstance->m_initConfig.palTemporalMode != CELL_RESC_PAL_50); } -inline bool IsNotPalTemporal() { return !IsPalTemporal(); } -inline bool IsNotPal() { return !IsPal(); } -inline bool IsGcmFlip() { - return (IsNotPal() || (IsPal() && (s_rescInternalInstance->m_initConfig.palTemporalMode == CELL_RESC_PAL_50 - || s_rescInternalInstance->m_initConfig.palTemporalMode == CELL_RESC_PAL_60_FOR_HSYNC))); -} -inline s32 GetNumColorBuffers(){ return IsPalInterpolate() ? 6 : (IsPalDrop() ? 3 : 2); } -inline bool IsInterlace() { return s_rescInternalInstance->m_initConfig.interlaceMode == CELL_RESC_INTERLACE_FILTER; } -inline bool IsTextureNR() { return !IsInterlace(); } - -static const float -PICTURE_SIZE = (1.0f), -UV_DELTA_PS = (1.f / 8.f), -UV_DELTA_LB = (1.f / 6.f), -XY_DELTA_LB = (1.f / 8.f), -PI = 3.141592741f; - -void BuildupVertexBufferNR() -{ - const float PX_FS = PICTURE_SIZE; - const float PY_FS = PICTURE_SIZE; - - const float UV_HALF = 0.5f; - const float UV_CENTER = 0.5f; - float U_FS = UV_HALF / s_rescInternalInstance->m_ratioAdjX; - float V_FS = UV_HALF / s_rescInternalInstance->m_ratioAdjY; - float U_FS0 = UV_CENTER - U_FS; - float V_FS0 = UV_CENTER - V_FS; - float U_FS1 = UV_CENTER + U_FS; - float V_FS1 = UV_CENTER + V_FS; - float V_LB = (UV_HALF + UV_DELTA_LB) / s_rescInternalInstance->m_ratioAdjY; - float V_LB0 = UV_CENTER - V_LB; - float V_LB1 = UV_CENTER + V_LB; - float U_PS = (UV_HALF - UV_DELTA_PS) / s_rescInternalInstance->m_ratioAdjX; - float U_PS0 = UV_CENTER - U_PS; - float U_PS1 = UV_CENTER + U_PS; - - auto vv = vm::ptr::make(s_rescInternalInstance->m_vertexArrayEA); - - if (s_rescInternalInstance->m_dstMode == CELL_RESC_720x480 || s_rescInternalInstance->m_dstMode == CELL_RESC_720x576) - { - switch((u32)s_rescInternalInstance->m_initConfig.ratioMode) - { - case CELL_RESC_LETTERBOX: - goto NR_LETTERBOX; - case CELL_RESC_PANSCAN: - goto NR_PANSCAN; - default: - goto NR_FULLSCREEN; - } - } - else - { - goto NR_FULLSCREEN; - } - -NR_FULLSCREEN: - vv->Px = -PX_FS; vv->Py = PY_FS; vv->u = U_FS0; vv->v = V_FS0; vv->u2 = 0.0f; vv->v2 = 0.0f; ++vv; - vv->Px = PX_FS; vv->Py = PY_FS; vv->u = U_FS1; vv->v = V_FS0; vv->u2 = 1.0f; vv->v2 = 0.0f; ++vv; - vv->Px = PX_FS; vv->Py = -PY_FS; vv->u = U_FS1; vv->v = V_FS1; vv->u2 = 1.0f; vv->v2 = 1.0f; ++vv; - vv->Px = -PX_FS; vv->Py = -PY_FS; vv->u = U_FS0; vv->v = V_FS1; vv->u2 = 0.0f; vv->v2 = 1.0f; ++vv; - s_rescInternalInstance->m_nVertex = VERTEX_NUMBER_NORMAL; - return; - -NR_LETTERBOX: - vv->Px = -PX_FS; vv->Py = PY_FS; vv->u = U_FS0; vv->v = V_LB0; vv->u2 = 0.0f; vv->v2 = 0.0f; ++vv; - vv->Px = PX_FS; vv->Py = PY_FS; vv->u = U_FS1; vv->v = V_LB0; vv->u2 = 1.0f; vv->v2 = 0.0f; ++vv; - vv->Px = PX_FS; vv->Py = -PY_FS; vv->u = U_FS1; vv->v = V_LB1; vv->u2 = 1.0f; vv->v2 = 1.0f; ++vv; - vv->Px = -PX_FS; vv->Py = -PY_FS; vv->u = U_FS0; vv->v = V_LB1; vv->u2 = 0.0f; vv->v2 = 1.0f; ++vv; - s_rescInternalInstance->m_nVertex = VERTEX_NUMBER_NORMAL; - return; - -NR_PANSCAN: - vv->Px = -PX_FS; vv->Py = PY_FS; vv->u = U_PS0; vv->v = V_FS0; vv->u2 = 0.0f; vv->v2 = 0.0f; ++vv; - vv->Px = PX_FS; vv->Py = PY_FS; vv->u = U_PS1; vv->v = V_FS0; vv->u2 = 1.0f; vv->v2 = 0.0f; ++vv; - vv->Px = PX_FS; vv->Py = -PY_FS; vv->u = U_PS1; vv->v = V_FS1; vv->u2 = 1.0f; vv->v2 = 1.0f; ++vv; - vv->Px = -PX_FS; vv->Py = -PY_FS; vv->u = U_PS0; vv->v = V_FS1; vv->u2 = 0.0f; vv->v2 = 1.0f; ++vv; - s_rescInternalInstance->m_nVertex = VERTEX_NUMBER_NORMAL; - return; -} - -void BuildupVertexBufferUN(s32 srcIdx) -{ - if (s_rescInternalInstance->m_bNewlyAdjustRatio) - { - s_rescInternalInstance->m_srcWidthInterlace = s_rescInternalInstance->m_rescSrc[srcIdx].width; - s_rescInternalInstance->m_srcHeightInterlace = s_rescInternalInstance->m_rescSrc[srcIdx].height; - s_rescInternalInstance->m_bNewlyAdjustRatio = false; - } - else - { - if (s_rescInternalInstance->m_srcWidthInterlace == s_rescInternalInstance->m_rescSrc[srcIdx].width - && s_rescInternalInstance->m_srcHeightInterlace == s_rescInternalInstance->m_rescSrc[srcIdx].height) - { - return; - } - else - { - s_rescInternalInstance->m_srcWidthInterlace = s_rescInternalInstance->m_rescSrc[srcIdx].width; - s_rescInternalInstance->m_srcHeightInterlace = s_rescInternalInstance->m_rescSrc[srcIdx].height; - } - } - - const float PX_FS = PICTURE_SIZE; - const float PY_FS = PICTURE_SIZE; - - float U_HALF = s_rescInternalInstance->m_rescSrc[srcIdx].width * 0.5f; - float V_HALF = s_rescInternalInstance->m_rescSrc[srcIdx].height * 0.5f; - float U_CENTER = U_HALF; - float V_CENTER = V_HALF; - float U_FS = U_HALF / s_rescInternalInstance->m_ratioAdjX; - float V_FS = V_HALF / s_rescInternalInstance->m_ratioAdjY; - float U_FS0 = U_CENTER - U_FS; - float V_FS0 = V_CENTER - V_FS; - float U_FS1 = U_CENTER + U_FS; - float V_FS1 = V_CENTER + V_FS; - float V_LB = V_HALF * (1.f + 2.f*UV_DELTA_LB) / s_rescInternalInstance->m_ratioAdjY; - float V_LB0 = V_CENTER - V_LB; - float V_LB1 = V_CENTER + V_LB; - float U_PS = U_HALF * (1.f - 2.f*UV_DELTA_PS) / s_rescInternalInstance->m_ratioAdjX; - float U_PS0 = U_CENTER - U_PS; - float U_PS1 = U_CENTER + U_PS; - float U2_FS0 = 0.0f; - float V2_FS0 = 0.0f; - float U2_FS1 = (float)s_rescInternalInstance->m_dstWidth; - float V2_FS1 = (float)s_rescInternalInstance->m_dstHeight; - - auto vv = vm::ptr::make(s_rescInternalInstance->m_vertexArrayEA); - - if (s_rescInternalInstance->m_dstMode == CELL_RESC_720x480 || s_rescInternalInstance->m_dstMode == CELL_RESC_720x576) - { - switch((u32)s_rescInternalInstance->m_initConfig.ratioMode) - { - case CELL_RESC_LETTERBOX: - goto UN_LETTERBOX; - case CELL_RESC_PANSCAN: - goto UN_PANSCAN; - default: - goto UN_FULLSCREEN; - } - } - else - { - goto UN_FULLSCREEN; - } - -UN_FULLSCREEN: - vv->Px = -PX_FS; vv->Py = PY_FS; vv->u = U_FS0; vv->v = V_FS0; vv->u2 = U2_FS0; vv->v2 = V2_FS0; ++vv; - vv->Px = PX_FS; vv->Py = PY_FS; vv->u = U_FS1; vv->v = V_FS0; vv->u2 = U2_FS1; vv->v2 = V2_FS0; ++vv; - vv->Px = PX_FS; vv->Py = -PY_FS; vv->u = U_FS1; vv->v = V_FS1; vv->u2 = U2_FS1; vv->v2 = V2_FS1; ++vv; - vv->Px = -PX_FS; vv->Py = -PY_FS; vv->u = U_FS0; vv->v = V_FS1; vv->u2 = U2_FS0; vv->v2 = V2_FS1; ++vv; - s_rescInternalInstance->m_nVertex = VERTEX_NUMBER_NORMAL; - return; - -UN_LETTERBOX: - vv->Px = -PX_FS; vv->Py = PY_FS; vv->u = U_FS0; vv->v = V_LB0; vv->u2 = U2_FS0; vv->v2 = V2_FS0; ++vv; - vv->Px = PX_FS; vv->Py = PY_FS; vv->u = U_FS1; vv->v = V_LB0; vv->u2 = U2_FS1; vv->v2 = V2_FS0; ++vv; - vv->Px = PX_FS; vv->Py = -PY_FS; vv->u = U_FS1; vv->v = V_LB1; vv->u2 = U2_FS1; vv->v2 = V2_FS1; ++vv; - vv->Px = -PX_FS; vv->Py = -PY_FS; vv->u = U_FS0; vv->v = V_LB1; vv->u2 = U2_FS0; vv->v2 = V2_FS1; ++vv; - s_rescInternalInstance->m_nVertex = VERTEX_NUMBER_NORMAL; - return; - -UN_PANSCAN: - vv->Px = -PX_FS; vv->Py = PY_FS; vv->u = U_PS0; vv->v = V_FS0; vv->u2 = U2_FS0; vv->v2 = V2_FS0; ++vv; - vv->Px = PX_FS; vv->Py = PY_FS; vv->u = U_PS1; vv->v = V_FS0; vv->u2 = U2_FS1; vv->v2 = V2_FS0; ++vv; - vv->Px = PX_FS; vv->Py = -PY_FS; vv->u = U_PS1; vv->v = V_FS1; vv->u2 = U2_FS1; vv->v2 = V2_FS1; ++vv; - vv->Px = -PX_FS; vv->Py = -PY_FS; vv->u = U_PS0; vv->v = V_FS1; vv->u2 = U2_FS0; vv->v2 = V2_FS1; ++vv; - s_rescInternalInstance->m_nVertex = VERTEX_NUMBER_NORMAL; - return; -} - -inline s32 InternalVersion(vm::ptr conf) -{ - switch ((u32)conf->size) - { - case 20: - return 1; - case 24: - return 2; - case 28: - return 3; - default: return -1; - } -} - -inline s32 InternalVersion() { - switch ((u32)s_rescInternalInstance->m_initConfig.size) - { - case 20: - return 1; - case 24: - return 2; - case 28: - return 3; - default: - return -1; - } -} - -u8 RescBufferMode2SysutilResolutionId(u32 bufferMode) -{ - switch (bufferMode) - { - case CELL_RESC_720x576: - return CELL_VIDEO_OUT_RESOLUTION_576; - case CELL_RESC_1280x720: - return CELL_VIDEO_OUT_RESOLUTION_720; - case CELL_RESC_1920x1080: - return CELL_VIDEO_OUT_RESOLUTION_1080; - default: - return CELL_VIDEO_OUT_RESOLUTION_480; - } -} - -u8 RescDstFormat2SysutilFormat(u32 dstFormat) -{ - switch (dstFormat) - { - case CELL_RESC_SURFACE_F_W16Z16Y16X16: - return CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT; - default: - return CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8; - } -} - -u8 GcmSurfaceFormat2GcmTextureFormat(u8 surfaceFormat, u8 surfaceType) -{ - u8 result = 0; - - switch (rsx::to_surface_color_format(surfaceFormat)) - { - case rsx::surface_color_format::a8r8g8b8: - result = CELL_GCM_TEXTURE_A8R8G8B8; - break; - case rsx::surface_color_format::w16z16y16x16: - result = CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT; - break; - default: - return 0xFF; //Error - } - - switch (surfaceType) - { - case CELL_GCM_SURFACE_PITCH: - result |= CELL_GCM_TEXTURE_LN; - break; - case CELL_GCM_SURFACE_SWIZZLE: - result |= CELL_GCM_TEXTURE_SZ; - break; - default: - return 0xFF; //Error - } - - result |= CELL_GCM_TEXTURE_NR; - - return result; -} - -s32 GetRescDestsIndex(u32 dstMode) -{ - switch(dstMode) - { - case CELL_RESC_720x480: - return 0; - case CELL_RESC_720x576: - return 1; - case CELL_RESC_1280x720: - return 2; - case CELL_RESC_1920x1080: - return 3; - default: - return -1; - } -} - -void GetScreenSize(u32 mode, s32 *width, s32 *height) -{ - switch (mode) - { - case CELL_RESC_720x480: - *width = 720; *height = 480; - break; - case CELL_RESC_720x576: - *width = 720; *height = 576; - break; - case CELL_RESC_1280x720: - *width = 1280; *height = 720; - break; - case CELL_RESC_1920x1080: - *width = 1920; *height = 1080; - break; - default: - *width = *height = 0; - break; - } -} - -s32 CalculateSurfaceByteSize(u32 mode, CellRescDsts *dsts) -{ - s32 width, height; - GetScreenSize(mode, &width, &height); - return dsts->pitch * roundup(height, dsts->heightAlign); -} - -s32 CalculateMaxColorBuffersSize() -{ - s32 oneBufSize, bufNum, totalBufSize, maxBufSize; - maxBufSize = 0; - - for (u32 bufMode = CELL_RESC_720x480; bufMode <= CELL_RESC_1920x1080; bufMode <<= 1) - { - if (s_rescInternalInstance->m_initConfig.supportModes & bufMode) - { - oneBufSize = CalculateSurfaceByteSize(bufMode, &(s_rescInternalInstance->m_rescDsts[GetRescDestsIndex(bufMode)])); - bufNum = cellRescGetNumColorBuffers(bufMode, s_rescInternalInstance->m_initConfig.palTemporalMode, 0); - totalBufSize = oneBufSize * bufNum; - maxBufSize = (maxBufSize > totalBufSize) ? maxBufSize : totalBufSize; - } - } - - return maxBufSize; -} - -bool CheckInitConfig(vm::ptr initConfig) -{ - if ((initConfig->resourcePolicy & ~((u32)0x3)) || (initConfig->supportModes & 0xF) == 0 || (initConfig->ratioMode > 2) || (initConfig->palTemporalMode > 5)) - { - return false; - } - - if ( InternalVersion() >= 2 ) - { - if (InternalVersion() == 2 && initConfig->interlaceMode > 1) - { - return false; - } - } - - if ( InternalVersion() >= 3 ) - { - if ((initConfig->interlaceMode > 4) || (initConfig->flipMode > 1)) - { - return false; - } - } - - return true; -} - -void InitMembers() -{ - s_rescInternalInstance->m_dstMode = (CellRescBufferMode)0; - s_rescInternalInstance->m_interlaceElement = CELL_RESC_ELEMENT_FLOAT; - s_rescInternalInstance->m_colorBuffersEA = 0; - s_rescInternalInstance->m_vertexArrayEA = 0; - s_rescInternalInstance->m_fragmentUcodeEA = 0; - s_rescInternalInstance->m_interlaceTableEA = 0; - s_rescInternalInstance->m_bufIdFront = 0; - s_rescInternalInstance->m_dstWidth = 0; - s_rescInternalInstance->m_dstHeight = 0; - s_rescInternalInstance->m_dstPitch = 0; - s_rescInternalInstance->m_srcWidthInterlace = 0; - s_rescInternalInstance->m_srcHeightInterlace = 0; - s_rescInternalInstance->m_dstBufInterval = 0; - s_rescInternalInstance->m_nVertex = 0; - s_rescInternalInstance->m_ratioAdjX = 1.f; - s_rescInternalInstance->m_ratioAdjY = 1.f; - s_rescInternalInstance->m_interlaceTableLength = 32; - s_rescInternalInstance->m_bInitialized = false; - s_rescInternalInstance->m_bNewlyAdjustRatio = false; - - s_rescInternalInstance->s_applicationVBlankHandler.set(0); - s_rescInternalInstance->s_applicationFlipHandler.set(0); - - //E PAL related variables - //s_rescInternalInstance->m_intrThread50 = 0; - //s_rescInternalInstance->m_lastDummyFlip = 0; - //s_rescInternalInstance->m_lastVsync60 = 0; - //s_rescInternalInstance->m_lastVsync50 = 0; - s_rescInternalInstance->m_bufIdFrontPrevDrop = 2; - s_rescInternalInstance->m_bufIdPalMidPrev = 4; - s_rescInternalInstance->m_bufIdPalMidNow = 5; - //s_rescInternalInstance->m_cgpTvalue = 0; - s_rescInternalInstance->m_isDummyFlipped = true; - s_rescInternalInstance->m_flexRatio = 0.f; // interpolate - s_rescInternalInstance->m_commandIdxCaF = 1; - s_rescInternalInstance->m_rcvdCmdIdx = 0; - - //s_rescInternalInstance->m_lastV60.idx = 0; - //s_rescInternalInstance->m_lastV60.time = Util::GetSystemTime(); - //s_rescInternalInstance->m_lastV50.idx = 0; - //s_rescInternalInstance->m_lastV50.time = Util::GetSystemTime(); - - //s_rescInternalInstance->m_feedback.interval60 = 1; - - for (s32 i = 0; im_rescSrc[i].format = 0; - s_rescInternalInstance->m_rescSrc[i].pitch = 0; - s_rescInternalInstance->m_rescSrc[i].width = 0; - s_rescInternalInstance->m_rescSrc[i].height = 0; - s_rescInternalInstance->m_rescSrc[i].offset = 0; - } - - for (s32 i = 0; im_dstOffsets[i] = 0; - } - - for (s32 i = 0; im_cgParamIndex[i] = 0xFF; - } - { - s_rescInternalInstance->m_rescDsts[0].format = CELL_RESC_SURFACE_A8R8G8B8; - s_rescInternalInstance->m_rescDsts[0].pitch = cellGcmGetTiledPitchSize(720 * 4); - s_rescInternalInstance->m_rescDsts[0].heightAlign = 8; - s_rescInternalInstance->m_rescDsts[1].format = CELL_RESC_SURFACE_A8R8G8B8; - s_rescInternalInstance->m_rescDsts[1].pitch = cellGcmGetTiledPitchSize(720 * 4); - s_rescInternalInstance->m_rescDsts[1].heightAlign = 8; - s_rescInternalInstance->m_rescDsts[2].format = CELL_RESC_SURFACE_A8R8G8B8; - s_rescInternalInstance->m_rescDsts[2].pitch = cellGcmGetTiledPitchSize(1280 * 4); - s_rescInternalInstance->m_rescDsts[2].heightAlign = 8; - s_rescInternalInstance->m_rescDsts[3].format = CELL_RESC_SURFACE_A8R8G8B8; - s_rescInternalInstance->m_rescDsts[3].pitch = cellGcmGetTiledPitchSize(1920 * 4); - s_rescInternalInstance->m_rescDsts[3].heightAlign = 8; - } -} - -void SetupRsxRenderingStates(vm::ptr& cntxt) -{ - //TODO: use cntxt - GSRender& r = Emu.GetGSManager().GetRender(); - - // FIXME: only RSX Thread can write rsx::method_registers - // Others threads must fill the command buffer or use another - // mechanism. - -// rsx::method_registers[NV4097_SET_COLOR_MASK] = -1; -// rsx::method_registers[NV4097_SET_DEPTH_MASK] = 0; -// rsx::method_registers[NV4097_SET_ALPHA_TEST_ENABLE] = false; -// rsx::method_registers[NV4097_SET_BLEND_ENABLE] = false; -// rsx::method_registers[NV4097_SET_BLEND_ENABLE_MRT] = false; -// r.m_set_logic_op = false; -// rsx::method_registers[NV4097_SET_CULL_FACE_ENABLE] = false; -// r.m_set_depth_bounds_test = false; -// rsx::method_registers[NV4097_SET_DEPTH_TEST_ENABLE] = false; -// r.m_set_poly_offset_fill = false; -// r.m_set_stencil_test = false; -// r.m_set_two_sided_stencil_test_enable = false; -// r.m_set_two_side_light_enable = false; -// r.m_set_point_sprite_control = false; -// r.m_set_dither = true; -// r.m_set_shade_mode = true; r.m_shade_mode = CELL_GCM_SMOOTH; -// r.m_set_frequency_divider_operation = CELL_GCM_FREQUENCY_DIVIDE; - -// rsx::method_registers[NV4097_SET_SURFACE_CLIP_HORIZONTAL] = s_rescInternalInstance->m_dstWidth << 16; -// rsx::method_registers[NV4097_SET_SURFACE_CLIP_VERTICAL] = s_rescInternalInstance->m_dstHeight << 16; - -// r.m_set_scissor_horizontal = r.m_set_scissor_vertical = true; -// r.m_scissor_x = 0; -// r.m_scissor_y = 0; -// r.m_scissor_w = s_rescInternalInstance->m_dstWidth; -// r.m_scissor_h = s_rescInternalInstance->m_dstHeight; - -// r.m_width = s_rescInternalInstance->m_dstWidth; -// r.m_height = s_rescInternalInstance->m_dstHeight; - -// r.m_surface_depth_format = 2; -// rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET] = 1; - - if (IsPalInterpolate()) - { - //MRT - //GcmCmdTypePrefix::cellGcmSetColorMaskMrt(con, CELL_GCM_COLOR_MASK_MRT1_A | CELL_GCM_COLOR_MASK_MRT1_R | CELL_GCM_COLOR_MASK_MRT1_G | CELL_GCM_COLOR_MASK_MRT1_B); - } -} - -void SetupVertexArrays(vm::ptr& cntxt) -{ - GSRender& r = Emu.GetGSManager().GetRender(); - - //TODO -} - -void SetupSurfaces(vm::ptr& cntxt) -{ - bool isMrt; - u32 dstOffset0, dstOffset1; - - if (IsNotPalInterpolate()) - { - isMrt = false; - dstOffset0 = s_rescInternalInstance->m_dstOffsets[s_rescInternalInstance->m_bufIdFront]; - dstOffset1 = 0; - } - else - { - isMrt = true; - dstOffset0 = s_rescInternalInstance->m_dstOffsets[s_rescInternalInstance->m_bufIdFront]; - dstOffset1 = s_rescInternalInstance->m_dstOffsets[s_rescInternalInstance->m_bufIdPalMidNow]; - } - - GSRender& r = Emu.GetGSManager().GetRender(); - - // FIXME: only RSX Thread can write rsx::method_registers - // Others threads must fill the command buffer or use another - // mechanism. - -// r.m_surface_type = CELL_GCM_SURFACE_PITCH; -// r.m_surface_antialias = CELL_GCM_SURFACE_CENTER_1; -// r.m_surface_color_format = (u8)s_rescInternalInstance->m_pRescDsts->format; -/* rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET] = (!isMrt) ? CELL_GCM_SURFACE_TARGET_0 : CELL_GCM_SURFACE_TARGET_MRT1; - //surface.colorLocation[0] = CELL_GCM_LOCATION_LOCAL; - rsx::method_registers[NV4097_SET_SURFACE_COLOR_AOFFSET] = dstOffset0; - rsx::method_registers[NV4097_SET_SURFACE_PITCH_A] = s_rescInternalInstance->m_dstPitch; - //surface.colorLocation[1] = CELL_GCM_LOCATION_LOCAL; - rsx::method_registers[NV4097_SET_SURFACE_COLOR_BOFFSET] = (!isMrt) ? 0 : dstOffset1; - rsx::method_registers[NV4097_SET_SURFACE_PITCH_B] = (!isMrt) ? 64 : s_rescInternalInstance->m_dstPitch; - //surface.colorLocation[2] = CELL_GCM_LOCATION_LOCAL; - rsx::method_registers[NV4097_SET_SURFACE_COLOR_COFFSET] = 0; - rsx::method_registers[NV4097_SET_SURFACE_PITCH_C] = 64; - //surface.colorLocation[3] = CELL_GCM_LOCATION_LOCAL; - rsx::method_registers[NV4097_SET_SURFACE_COLOR_DOFFSET] = 0; - rsx::method_registers[NV4097_SET_SURFACE_PITCH_D] = 64; -// r.m_surface_depth_format = CELL_GCM_SURFACE_Z24S8; - //surface.depthLocation = CELL_GCM_LOCATION_LOCAL; - rsx::method_registers[NV4097_SET_SURFACE_ZETA_OFFSET]; - rsx::method_registers[NV4097_SET_SURFACE_PITCH_Z] = 64; -// r.m_surface_width = s_rescInternalInstance->m_dstWidth; -// r.m_surface_height = s_rescInternalInstance->m_dstHeight; -// r.m_surface_clip_x = 0;*/ -// r.m_surface_clip_y = 0; -} - -// Module<> Functions -s32 cellRescInit(vm::ptr initConfig) -{ - cellResc.warning("cellRescInit(initConfig=*0x%x)", initConfig); - - if (s_rescInternalInstance->m_bInitialized) - { - cellResc.error("cellRescInit : CELL_RESC_ERROR_REINITIALIZED"); - return CELL_RESC_ERROR_REINITIALIZED; - } - - if (InternalVersion(initConfig) == -1 || !CheckInitConfig(initConfig)) - { - cellResc.error("cellRescInit : CELL_RESC_ERROR_BAD_ARGUMENT"); - return CELL_RESC_ERROR_BAD_ARGUMENT; - } - - InitMembers(); - s_rescInternalInstance->m_initConfig = *initConfig; // TODO: This may be incompatible with older binaries - s_rescInternalInstance->m_bInitialized = true; - - return CELL_OK; -} - -void cellRescExit() -{ - cellResc.warning("cellRescExit()"); - - if (!s_rescInternalInstance->m_bInitialized) - { - cellResc.error("cellRescExit(): not initialized"); - return; - } - - if (IsPalTemporal()) - { - cellGcmSetSecondVFrequency(CELL_GCM_DISPLAY_FREQUENCY_DISABLE); - cellGcmSetVBlankHandler(vm::null); - //GcmSysTypePrefix::cellGcmSetSecondVHandler(NULL); - - if (IsPalInterpolate()) - { - // TODO: ExitSystemResource() - //s32 ret = ExitSystemResource(); - //if (ret != CELL_OK) - //{ - // cellResc.error("failed to clean up system resources.. continue. 0x%x\n", ret); - //} - } - } - - s_rescInternalInstance->m_bInitialized = false; -} - -s32 cellRescVideoOutResolutionId2RescBufferMode(u32 resolutionId, vm::ptr bufferMode) -{ - cellResc.trace("cellRescVideoOutResolutionId2RescBufferMode(resolutionId=%d, bufferMode=*0x%x)", resolutionId, bufferMode); - - switch (resolutionId) - { - case CELL_VIDEO_OUT_RESOLUTION_1080: - *bufferMode = CELL_RESC_1920x1080; - break; - case CELL_VIDEO_OUT_RESOLUTION_720: - *bufferMode = CELL_RESC_1280x720; - break; - case CELL_VIDEO_OUT_RESOLUTION_480: - *bufferMode = CELL_RESC_720x480; - break; - case CELL_VIDEO_OUT_RESOLUTION_576: - *bufferMode = CELL_RESC_720x576; - break; - default: - cellResc.error("cellRescVideoOutResolutionId2RescBufferMod : CELL_RESC_ERROR_BAD_ARGUMENT"); - return CELL_RESC_ERROR_BAD_ARGUMENT; - } - - return CELL_OK; -} - -s32 cellRescSetDsts(u32 dstsMode, vm::ptr dsts) -{ - cellResc.trace("cellRescSetDsts(dstsMode=%d, dsts=*0x%x)", dstsMode, dsts); - - if (!s_rescInternalInstance->m_bInitialized) - { - cellResc.error("cellRescSetDst : CELL_RESC_ERROR_NOT_INITIALIZED"); - return CELL_RESC_ERROR_NOT_INITIALIZED; - } - - if ((dstsMode != CELL_RESC_720x480) && (dstsMode != CELL_RESC_720x576) && (dstsMode != CELL_RESC_1280x720) && (dstsMode != CELL_RESC_1920x1080)) - { - cellResc.error("cellRescSetDsts : CELL_RESC_ERROR_BAD_ARGUMENT"); - return CELL_RESC_ERROR_BAD_ARGUMENT; - } - - s_rescInternalInstance->m_rescDsts[GetRescDestsIndex(dstsMode)] = *dsts; - - return CELL_OK; -} - -void SetVBlankHandler(vm::ptr handler) -{ - if (!s_rescInternalInstance->m_bInitialized || s_rescInternalInstance->m_dstMode == 0) - { - // If this function is called before SetDisplayMode, handler should be stored and set it properly later in SetDisplayMode. - s_rescInternalInstance->s_applicationVBlankHandler = handler; - return; - } - - if (IsNotPalTemporal()) - { - cellGcmSetVBlankHandler(handler); - s_rescInternalInstance->s_applicationVBlankHandler.set(0); - } - else if (IsPal60Hsync()) - { - //cellGcmSetSecondVHandler(handler); - s_rescInternalInstance->s_applicationVBlankHandler.set(0); - } - else - { - s_rescInternalInstance->s_applicationVBlankHandler = handler; - } -} - - -void SetFlipHandler(vm::ptr handler) -{ - if (!s_rescInternalInstance->m_bInitialized || s_rescInternalInstance->m_dstMode == 0) - { - // If this function is called before SetDisplayMode, handler should be stored and set it properly later in SetDisplayMode. - s_rescInternalInstance->s_applicationFlipHandler = handler; - return; - } - - if (IsGcmFlip()) - { - cellGcmSetFlipHandler(handler); - s_rescInternalInstance->s_applicationFlipHandler.set(0); - } - else - { - s_rescInternalInstance->s_applicationFlipHandler = handler; - } -} - -s32 cellRescSetDisplayMode(u32 displayMode) -{ - cellResc.warning("cellRescSetDisplayMode(displayMode=%d)", displayMode); - - if (!s_rescInternalInstance->m_bInitialized) - { - cellResc.error("cellRescSetDisplayMode : CELL_RESC_ERROR_NOT_INITIALIZED"); - return CELL_RESC_ERROR_NOT_INITIALIZED; - } - - if (!(s_rescInternalInstance->m_initConfig.supportModes & displayMode)) - { - cellResc.error("cellRescSetDisplayMode : CELL_RESC_ERROR_BAD_ARGUMENT"); - return CELL_RESC_ERROR_BAD_ARGUMENT; - } - - if ((displayMode != CELL_RESC_720x480) && (displayMode != CELL_RESC_720x576) && - (displayMode != CELL_RESC_1280x720) && (displayMode != CELL_RESC_1920x1080)) - { - cellResc.error("cellRescSetDisplayMode : CELL_RESC_ERROR_BAD_ARGUMENT"); - return CELL_RESC_ERROR_BAD_ARGUMENT; - } - - s_rescInternalInstance->m_dstMode = displayMode; - - if ((IsPalInterpolate() || IsPalDrop()) && s_rescInternalInstance->m_initConfig.flipMode == CELL_RESC_DISPLAY_HSYNC) - { - cellResc.error("cellRescSetDisplayMode : CELL_RESC_ERROR_BAD_COMBINATIONT"); - return CELL_RESC_ERROR_BAD_COMBINATION; - } - - if (IsPal60Hsync() && s_rescInternalInstance->m_initConfig.flipMode==CELL_RESC_DISPLAY_VSYNC) - { - cellResc.error("cellRescSetDisplayMode : CELL_RESC_ERROR_BAD_COMBINATIONT"); - return CELL_RESC_ERROR_BAD_COMBINATION; - } - - s_rescInternalInstance->m_pRescDsts = &s_rescInternalInstance->m_rescDsts[GetRescDestsIndex(displayMode)]; - GetScreenSize(s_rescInternalInstance->m_dstMode, &(s_rescInternalInstance->m_dstWidth), &(s_rescInternalInstance->m_dstHeight)); - - s_rescInternalInstance->m_dstPitch = s_rescInternalInstance->m_pRescDsts->pitch; - s_rescInternalInstance->m_dstBufInterval = s_rescInternalInstance->m_dstPitch * roundup(s_rescInternalInstance->m_dstHeight, s_rescInternalInstance->m_pRescDsts->heightAlign); - - /*if (IsPalInterpolate()) { - if(IsInterlace()) m_pCFragmentShader = m_pCFragmentShaderArray[RESC_SHADER_DEFAULT_INTERLACE_PAL]; - else m_pCFragmentShader = m_pCFragmentShaderArray[RESC_SHADER_DEFAULT_BILINEAR_PAL]; - } else { - if(IsInterlace()) m_pCFragmentShader = m_pCFragmentShaderArray[RESC_SHADER_DEFAULT_INTERLACE]; - else m_pCFragmentShader = m_pCFragmentShaderArray[RESC_SHADER_DEFAULT_BILINEAR]; - }*/ - - vm::var videocfg; - videocfg->resolutionId = RescBufferMode2SysutilResolutionId(s_rescInternalInstance->m_dstMode); - videocfg->format = RescDstFormat2SysutilFormat(s_rescInternalInstance->m_pRescDsts->format ); - videocfg->aspect = CELL_VIDEO_OUT_ASPECT_AUTO; - videocfg->pitch = s_rescInternalInstance->m_dstPitch; - - cellVideoOutConfigure(CELL_VIDEO_OUT_PRIMARY, videocfg, vm::null, 0); - - if (IsPalInterpolate()) - { - //s32 ret = InitSystemResource(); - //if (ret) return ret; - //InitLabels(); - cellGcmSetSecondVFrequency(CELL_GCM_DISPLAY_FREQUENCY_59_94HZ); - //cellGcmSetVBlankHandler(IntrHandler50); - //cellGcmSetSecondVHandler(IntrHandler60); - cellGcmSetFlipHandler(vm::null); - } - else if (IsPalDrop()) - { - //InitLabels(); - cellGcmSetSecondVFrequency(CELL_GCM_DISPLAY_FREQUENCY_59_94HZ); - cellGcmSetVBlankHandler(vm::null); - //cellGcmSetSecondVHandler(IntrHandler60Drop); - cellGcmSetFlipHandler(vm::null); - } - else if (IsPal60Hsync()) - { - cellGcmSetSecondVFrequency(CELL_GCM_DISPLAY_FREQUENCY_59_94HZ); - cellGcmSetVBlankHandler(vm::null); - } - - if (s_rescInternalInstance->s_applicationVBlankHandler) SetVBlankHandler(s_rescInternalInstance->s_applicationVBlankHandler); - if (s_rescInternalInstance->s_applicationFlipHandler) SetFlipHandler(s_rescInternalInstance->s_applicationFlipHandler); - cellGcmSetFlipMode((s_rescInternalInstance->m_initConfig.flipMode == CELL_RESC_DISPLAY_VSYNC) ? CELL_GCM_DISPLAY_VSYNC : CELL_GCM_DISPLAY_HSYNC); - - return CELL_OK; -} - -s32 cellRescAdjustAspectRatio(float horizontal, float vertical) -{ - cellResc.warning("cellRescAdjustAspectRatio(horizontal=%f, vertical=%f)", horizontal, vertical); - - if (!s_rescInternalInstance->m_bInitialized) - { - cellResc.error("cellRescAdjustAspectRatio : CELL_RESC_ERROR_NOT_INITIALIZED"); - return CELL_RESC_ERROR_NOT_INITIALIZED; - } - - if ((horizontal < 0.5f || 2.f < horizontal) || (vertical < 0.5f || 2.f < vertical)) - { - cellResc.error("cellRescAdjustAspectRatio : CELL_RESC_ERROR_BAD_ARGUMENT"); - return CELL_RESC_ERROR_BAD_ARGUMENT; - } - - s_rescInternalInstance->m_ratioAdjX = horizontal; - s_rescInternalInstance->m_ratioAdjY = vertical; - - if (s_rescInternalInstance->m_vertexArrayEA) - { - if (IsTextureNR()) - { - BuildupVertexBufferNR(); - } - else - { - s_rescInternalInstance->m_bNewlyAdjustRatio = true; - } - } - - return CELL_OK; -} - -s32 cellRescSetPalInterpolateDropFlexRatio(float ratio) -{ - cellResc.warning("cellRescSetPalInterpolateDropFlexRatio(ratio=%f)", ratio); - - if (!s_rescInternalInstance->m_bInitialized) - { - cellResc.error("cellRescSetPalInterpolateDropFlexRatio : CELL_RESC_ERROR_NOT_INITIALIZED"); - return CELL_RESC_ERROR_NOT_INITIALIZED; - } - - if (ratio < 0.f || 1.f < ratio) - { - cellResc.error("cellRescSetPalInterpolateDropFlexRatio : CELL_RESC_ERROR_BAD_ARGUMENT"); - return CELL_RESC_ERROR_BAD_ARGUMENT; - } - - s_rescInternalInstance->m_flexRatio = ratio; - - return CELL_OK; -} - -s32 cellRescGetBufferSize(vm::ptr colorBuffers, vm::ptr vertexArray, vm::ptr fragmentShader) -{ - cellResc.warning("cellRescGetBufferSize(colorBuffers=*0x%x, vertexArray=*0x%x, fragmentShader=*0x%x)", colorBuffers, vertexArray, fragmentShader); - - if (!s_rescInternalInstance->m_bInitialized) - { - cellResc.error("cellRescGetBufferSize : CELL_RESC_ERROR_NOT_INITIALIZED"); - return CELL_RESC_ERROR_NOT_INITIALIZED; - } - - s32 colorBuffersSize, vertexArraySize, fragmentUcodeSize; - if (s_rescInternalInstance->m_initConfig.resourcePolicy & CELL_RESC_MINIMUM_VRAM) - { - colorBuffersSize = s_rescInternalInstance->m_dstBufInterval * GetNumColorBuffers(); - vertexArraySize = 0x180; //sizeof(RescVertex_t) * VERTEX_NUMBER_RESERVED; - //fragmentUcodeSize = m_pCFragmentShader->GetUcodeSize(); - fragmentUcodeSize = 0x300; - } - else //CELL_RESC_CONSTANT_VRAM - { - colorBuffersSize = CalculateMaxColorBuffersSize(); - vertexArraySize = 0x180; //sizeof(RescVertex_t) * VERTEX_NUMBER_RESERVED; - fragmentUcodeSize = 0x300; - } - - if (colorBuffers) - { - *colorBuffers = colorBuffersSize; - } - - if (vertexArray) - { - *vertexArray = vertexArraySize; - } - - if (fragmentShader) - { - *fragmentShader = fragmentUcodeSize; - } - - return CELL_OK; -} - -s32 cellRescGetNumColorBuffers(u32 dstMode, u32 palTemporalMode, u32 reserved) -{ - cellResc.trace("cellRescGetNumColorBuffers(dstMode=%d, palTemporalMode=%d, reserved=%d)", dstMode, palTemporalMode, reserved); - - if (reserved != 0) - { - cellResc.error("cellRescGetNumColorBuffers : CELL_RESC_ERROR_BAD_ARGUMENT"); - return CELL_RESC_ERROR_BAD_ARGUMENT; - } - - return dstMode==CELL_RESC_720x576 - ? ((palTemporalMode==CELL_RESC_PAL_60_INTERPOLATE || - palTemporalMode==CELL_RESC_PAL_60_INTERPOLATE_30_DROP || - palTemporalMode==CELL_RESC_PAL_60_INTERPOLATE_DROP_FLEXIBLE) - ? 6 - : (palTemporalMode==CELL_RESC_PAL_60_DROP - ? 3 - : 2)) - : 2; -} - -s32 cellRescGcmSurface2RescSrc(vm::ptr gcmSurface, vm::ptr rescSrc) -{ - cellResc.trace("cellRescGcmSurface2RescSrc(gcmSurface=*0x%x, rescSrc=*0x%x)", gcmSurface, rescSrc); - - u8 textureFormat = GcmSurfaceFormat2GcmTextureFormat(gcmSurface->colorFormat, gcmSurface->type); - s32 xW = 1, xH = 1; - - switch(rsx::to_surface_antialiasing(gcmSurface->antialias)) - { - case rsx::surface_antialiasing::square_rotated_4_samples: - xW=xH=2; - break; - case rsx::surface_antialiasing::square_centered_4_samples: - xW=xH=2; - break; - case rsx::surface_antialiasing::diagonal_centered_2_samples: - xW=2; - break; - default: - break; - } - - rescSrc->format = textureFormat; - rescSrc->pitch = gcmSurface->colorPitch[0]; - rescSrc->width = gcmSurface->width * xW; - rescSrc->height = gcmSurface->height * xH; - rescSrc->offset = gcmSurface->colorOffset[0]; - - return CELL_OK; -} - -s32 cellRescSetSrc(s32 idx, vm::ptr src) -{ - cellResc.trace("cellRescSetSrc(idx=0x%x, src=*0x%x)", idx, src); - - if(!s_rescInternalInstance->m_bInitialized) - { - cellResc.error("cellRescSetSrc : CELL_RESC_ERROR_NOT_INITIALIZED"); - return CELL_RESC_ERROR_NOT_INITIALIZED; - } - - if (idx < 0 || idx >= SRC_BUFFER_NUM || src->width < 1 || src->width > 4096 || src->height < 1 || src->height > 4096) - { - cellResc.error("cellRescSetSrc : CELL_RESC_ERROR_BAD_ARGUMENT"); - return CELL_RESC_ERROR_BAD_ARGUMENT; - } - - cellResc.trace(" *** format=0x%x", src->format); - cellResc.trace(" *** pitch=%d", src->pitch); - cellResc.trace(" *** width=%d", src->width); - cellResc.trace(" *** height=%d", src->height); - cellResc.trace(" *** offset=0x%x", src->offset); - - s_rescInternalInstance->m_rescSrc[idx] = *src; - - cellGcmSetDisplayBuffer(idx, src->offset, src->pitch, src->width, src->height); - - return 0; -} - -s32 cellRescSetConvertAndFlip(PPUThread& ppu, vm::ptr cntxt, s32 idx) -{ - cellResc.trace("cellRescSetConvertAndFlip(cntxt=*0x%x, idx=0x%x)", cntxt, idx); - - if(!s_rescInternalInstance->m_bInitialized) - { - cellResc.error("cellRescSetConvertAndFlip : CELL_RESC_ERROR_NOT_INITIALIZED"); - return CELL_RESC_ERROR_NOT_INITIALIZED; - } - - if(idx < 0 || SRC_BUFFER_NUM <= idx) - { - cellResc.error("cellRescSetConvertAndFlip : CELL_RESC_ERROR_BAD_ARGUMENT"); - return CELL_RESC_ERROR_BAD_ARGUMENT; - } - - - if (!IsTextureNR()) - { - BuildupVertexBufferUN(idx); - } - - // Setup GPU internal status - SetupRsxRenderingStates(cntxt); - - // Setup vertex array pointers - SetupVertexArrays(cntxt); - - // Setup surface - SetupSurfaces(cntxt); - - //TODO: ? - - cellGcmSetPrepareFlip(ppu, cntxt, idx); - - return CELL_OK; -} - -s32 cellRescSetWaitFlip() -{ - cellResc.warning("cellRescSetWaitFlip()"); - - // TODO: emit RSX command for "wait flip" operation - - return CELL_OK; -} - -s32 cellRescSetBufferAddress(vm::ptr colorBuffers, vm::ptr vertexArray, vm::ptr fragmentShader) -{ - cellResc.warning("cellRescSetBufferAddress(colorBuffers=*0x%x, vertexArray=*0x%x, fragmentShader=*0x%x)", colorBuffers, vertexArray, fragmentShader); - - if(!s_rescInternalInstance->m_bInitialized) - { - cellResc.error("cellRescSetBufferAddress : CELL_RESC_ERROR_NOT_INITIALIZED"); - return CELL_RESC_ERROR_NOT_INITIALIZED; - } - - if(colorBuffers.addr() % COLOR_BUFFER_ALIGNMENT || vertexArray.addr() % VERTEX_BUFFER_ALIGNMENT || fragmentShader.addr() % FRAGMENT_SHADER_ALIGNMENT) - { - cellResc.error("cellRescSetBufferAddress : CELL_RESC_ERROR_BAD_ALIGNMENT"); - return CELL_RESC_ERROR_BAD_ALIGNMENT; - } - - s_rescInternalInstance->m_colorBuffersEA = colorBuffers.addr(); - s_rescInternalInstance->m_vertexArrayEA = vertexArray.addr(); - s_rescInternalInstance->m_fragmentUcodeEA = fragmentShader.addr(); - - vm::var dstOffset; - cellGcmAddressToOffset(s_rescInternalInstance->m_colorBuffersEA, dstOffset); - - for (s32 i=0; im_dstOffsets[i] = *dstOffset + i * s_rescInternalInstance->m_dstBufInterval; - } - - for (s32 i=0; im_dstOffsets[i], s_rescInternalInstance->m_dstPitch, s_rescInternalInstance->m_dstWidth, s_rescInternalInstance->m_dstHeight); - if (ret) return ret; - } - - if (IsTextureNR()) - { - BuildupVertexBufferNR(); - } - - //TODO: ? - - return CELL_OK; -} - -void cellRescSetFlipHandler(vm::ptr handler) -{ - cellResc.warning("cellRescSetFlipHandler(handler=*0x%x)", handler); - - Emu.GetGSManager().GetRender().flip_handler = handler; -} - -void cellRescResetFlipStatus() -{ - cellResc.trace("cellRescResetFlipStatus()"); - - Emu.GetGSManager().GetRender().flip_status = 1; -} - -s32 cellRescGetFlipStatus() -{ - cellResc.trace("cellRescGetFlipStatus()"); - - return Emu.GetGSManager().GetRender().flip_status; -} - -s32 cellRescGetRegisterCount() -{ - UNIMPLEMENTED_FUNC(cellResc); - return CELL_OK; -} - -u64 cellRescGetLastFlipTime() -{ - cellResc.trace("cellRescGetLastFlipTime()"); - - return Emu.GetGSManager().GetRender().last_flip_time; -} - -s32 cellRescSetRegisterCount() -{ - UNIMPLEMENTED_FUNC(cellResc); - return CELL_OK; -} - -void cellRescSetVBlankHandler(vm::ptr handler) -{ - cellResc.warning("cellRescSetVBlankHandler(handler=*0x%x)", handler); - - Emu.GetGSManager().GetRender().vblank_handler = handler; -} - -u16 FloatToHalf(float val) -{ - u8 *tmp = (u8*)&val; - u32 bits = ((u32)tmp[0] << 24) | ((u32)tmp[1] << 16) | ((u32)tmp[2] << 8) | (u32)tmp[3]; - - if (bits == 0) - { - return 0; - } - s32 e = ((bits & 0x7f800000) >> 23) - 127 + 15; - if (e < 0) - { - return 0; - } - else if (e > 31) - { - e = 31; - } - u32 s = bits & 0x80000000; - u32 m = bits & 0x007fffff; - - return ((s >> 16) & 0x8000) | ((e << 10) & 0x7c00) | ((m >> 13) & 0x03ff); -} - -static void blackman(float window[]) -{ - const float x0 = ((1.f * 2.f*PI) / 5.f) - PI; - const float x1 = ((2.f * 2.f*PI) / 5.f) - PI; - const float x2 = ((3.f * 2.f*PI) / 5.f) - PI; - const float x3 = ((4.f * 2.f*PI) / 5.f) - PI; - - const float a0 = 0.42f + (0.50f * cosf(x0)) + (0.08f * cosf(2.f*x0)); - const float a1 = 0.42f + (0.50f * cosf(x1)) + (0.08f * cosf(2.f*x1)); - const float a2 = 0.42f + (0.50f * cosf(x2)) + (0.08f * cosf(2.f*x2)); - const float a3 = 0.42f + (0.50f * cosf(x3)) + (0.08f * cosf(2.f*x3)); - - window[0] = ((100.f - SEVIRITY) / 100.f + SEVIRITY / 100.f*a0); - window[1] = ((100.f - SEVIRITY) / 100.f + SEVIRITY / 100.f*a1); - window[2] = ((100.f - SEVIRITY) / 100.f + SEVIRITY / 100.f*a2); - window[3] = ((100.f - SEVIRITY) / 100.f + SEVIRITY / 100.f*a3); -} - -s32 CreateInterlaceTable(u32 ea_addr, float srcH, float dstH, CellRescTableElement depth, s32 length) -{ - float phi[4], transient[4]; - float y_fraction; - float bandwidth = 0.5f / (srcH / dstH); - float phi_b = 2.f * PI * bandwidth; - float window[4]; - auto buf16 = vm::ptr::make(ea_addr); - auto buf32 = vm::ptr::make(ea_addr); - - blackman(window); - - for (s32 i = 0; i 1E-10) ? (sinf(phi[0]) / phi[0] * window[0]) : window[0]; - transient[1] = (fabsf(phi[1]) > 1E-10) ? (sinf(phi[1]) / phi[1] * window[1]) : window[1]; - transient[2] = (fabsf(phi[2]) > 1E-10) ? (sinf(phi[2]) / phi[2] * window[2]) : window[2]; - transient[3] = (fabsf(phi[3]) > 1E-10) ? (sinf(phi[3]) / phi[3] * window[3]) : window[3]; - - float total4 = transient[0] + transient[1] + transient[2] + transient[3]; - - if (depth == CELL_RESC_ELEMENT_HALF) - { - buf16[0] = FloatToHalf(transient[0] / total4); - buf16[1] = FloatToHalf(transient[1] / total4); - buf16[2] = FloatToHalf(transient[2] / total4); - buf16[3] = FloatToHalf(transient[3] / total4); - buf16 += 4; - } - else - { - buf32[0] = transient[0] / total4; - buf32[1] = transient[1] / total4; - buf32[2] = transient[2] / total4; - buf32[3] = transient[3] / total4; - buf32 += 4; - } - } - return CELL_OK; -} - -s32 cellRescCreateInterlaceTable(u32 ea_addr, float srcH, CellRescTableElement depth, s32 length) -{ - cellResc.warning("cellRescCreateInterlaceTable(ea_addr=0x%x, srcH=%f, depth=%d, length=%d)", ea_addr, srcH, depth, length); - - if (!s_rescInternalInstance->m_bInitialized) - { - cellResc.error("cellRescCreateInterlaceTable: CELL_RESC_ERROR_NOT_INITIALIZED"); - return CELL_RESC_ERROR_NOT_INITIALIZED; - } - - if ((ea_addr == 0) || (srcH <= 0.f) || (!(depth == CELL_RESC_ELEMENT_HALF || depth == CELL_RESC_ELEMENT_FLOAT)) || (length <= 0)) - { - cellResc.error("cellRescCreateInterlaceTable: CELL_RESC_ERROR_BAD_ARGUMENT"); - return CELL_RESC_ERROR_BAD_ARGUMENT; - } - - if (s_rescInternalInstance->m_dstHeight == 0) - { - cellResc.error("cellRescCreateInterlaceTable: CELL_RESC_ERROR_BAD_COMBINATION"); - return CELL_RESC_ERROR_BAD_COMBINATION; - } - - float ratioModeCoefficient = (s_rescInternalInstance->m_initConfig.ratioMode != CELL_RESC_LETTERBOX) ? 1.f : (1.f - 2.f * XY_DELTA_LB); - float dstH = s_rescInternalInstance->m_dstHeight * ratioModeCoefficient * s_rescInternalInstance->m_ratioAdjY; - - if (s32 retValue = CreateInterlaceTable(ea_addr, srcH, dstH, depth, length)) - { - return retValue; - } - else - { - s_rescInternalInstance->m_interlaceTableEA = ea_addr; - s_rescInternalInstance->m_interlaceElement = depth; - s_rescInternalInstance->m_interlaceTableLength = length; - return CELL_OK; - } -} - - -Module<> cellResc("cellResc", []() -{ - s_rescInternalInstance = new CCellRescInternal(); - - cellResc.on_stop = []() - { - delete s_rescInternalInstance; - }; - - REG_FUNC(cellResc, cellRescSetConvertAndFlip); - REG_FUNC(cellResc, cellRescSetWaitFlip); - REG_FUNC(cellResc, cellRescSetFlipHandler); - REG_FUNC(cellResc, cellRescGcmSurface2RescSrc); - REG_FUNC(cellResc, cellRescGetNumColorBuffers); - REG_FUNC(cellResc, cellRescSetDsts); - REG_FUNC(cellResc, cellRescResetFlipStatus); - REG_FUNC(cellResc, cellRescSetPalInterpolateDropFlexRatio); - REG_FUNC(cellResc, cellRescGetRegisterCount); - REG_FUNC(cellResc, cellRescAdjustAspectRatio); - REG_FUNC(cellResc, cellRescSetDisplayMode); - REG_FUNC(cellResc, cellRescExit); - REG_FUNC(cellResc, cellRescInit); - REG_FUNC(cellResc, cellRescGetBufferSize); - REG_FUNC(cellResc, cellRescGetLastFlipTime); - REG_FUNC(cellResc, cellRescSetSrc); - REG_FUNC(cellResc, cellRescSetRegisterCount); - REG_FUNC(cellResc, cellRescSetBufferAddress); - REG_FUNC(cellResc, cellRescGetFlipStatus); - REG_FUNC(cellResc, cellRescVideoOutResolutionId2RescBufferMode); - REG_FUNC(cellResc, cellRescSetVBlankHandler); - REG_FUNC(cellResc, cellRescCreateInterlaceTable); -}); diff --git a/rpcs3/Emu/SysCalls/Modules/cellRtc.cpp b/rpcs3/Emu/SysCalls/Modules/cellRtc.cpp deleted file mode 100644 index d36da41c37..0000000000 --- a/rpcs3/Emu/SysCalls/Modules/cellRtc.cpp +++ /dev/null @@ -1,488 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" - -#include "Utilities/rTime.h" -#include "cellRtc.h" - -extern Module<> cellRtc; - -s64 convertToUNIXTime(u16 seconds, u16 minutes, u16 hours, u16 days, s32 years) -{ - return (s64)seconds + (s64)minutes * 60 + (s64)hours * 3600 + (s64)days * 86400 + - (s64)(years - 70) * 31536000 + (s64)((years - 69) / 4) * 86400 - - (s64)((years - 1) / 100) * 86400 + (s64)((years + 299) / 400) * 86400; -} - -u64 convertToWin32FILETIME(u16 seconds, u16 minutes, u16 hours, u16 days, s32 years) -{ - s64 unixtime = convertToUNIXTime(seconds, minutes, hours, days, years); - u64 win32time = u64(unixtime) * u64(10000000) + u64(116444736000000000); - u64 win32filetime = win32time | win32time >> 32; - return win32filetime; -} - -s32 cellRtcGetCurrentTick(vm::ptr pTick) -{ - cellRtc.trace("cellRtcGetCurrentTick(pTick=*0x%x)", pTick); - - rDateTime unow = rDateTime::UNow(); - pTick->tick = unow.GetTicks(); - return CELL_OK; -} - -s32 cellRtcGetCurrentClock(vm::ptr pClock, s32 iTimeZone) -{ - cellRtc.trace("cellRtcGetCurrentClock(pClock=*0x%x, time_zone=%d)", pClock, iTimeZone); - - rDateTime unow = rDateTime::UNow(); - - // Add time_zone as offset in minutes. - rTimeSpan tz = rTimeSpan(0, (long) iTimeZone, 0, 0); - unow.Add(tz); - - pClock->year = unow.GetYear(rDateTime::TZ::UTC); - pClock->month = unow.GetMonth(rDateTime::TZ::UTC); - pClock->day = unow.GetDay(rDateTime::TZ::UTC); - pClock->hour = unow.GetHour(rDateTime::TZ::UTC); - pClock->minute = unow.GetMinute(rDateTime::TZ::UTC); - pClock->second = unow.GetSecond(rDateTime::TZ::UTC); - pClock->microsecond = unow.GetMillisecond(rDateTime::TZ::UTC) * 1000; - - return CELL_OK; -} - -s32 cellRtcGetCurrentClockLocalTime(vm::ptr pClock) -{ - cellRtc.trace("cellRtcGetCurrentClockLocalTime(pClock=*0x%x)", pClock); - - rDateTime unow = rDateTime::UNow(); - - pClock->year = unow.GetYear(rDateTime::TZ::Local); - pClock->month = unow.GetMonth(rDateTime::TZ::Local); - pClock->day = unow.GetDay(rDateTime::TZ::Local); - pClock->hour = unow.GetHour(rDateTime::TZ::Local); - pClock->minute = unow.GetMinute(rDateTime::TZ::Local); - pClock->second = unow.GetSecond(rDateTime::TZ::Local); - pClock->microsecond = unow.GetMillisecond(rDateTime::TZ::Local) * 1000; - - return CELL_OK; -} - -s32 cellRtcFormatRfc2822(vm::ptr pszDateTime, vm::ptr pUtc, s32 iTimeZone) -{ - cellRtc.trace("cellRtcFormatRfc2822(pszDateTime=*0x%x, pUtc=*0x%x, time_zone=%d)", pszDateTime, pUtc, iTimeZone); - - // Add time_zone as offset in minutes. - rTimeSpan tz = rTimeSpan(0, (long) iTimeZone, 0, 0); - - // Get date from ticks + tz. - rDateTime date = rDateTime((time_t)pUtc->tick); - date.Add(tz); - - // Format date string in RFC2822 format (e.g.: Mon, 01 Jan 1990 12:00:00 +0000). - const std::string str = date.Format("%a, %d %b %Y %T %z", rDateTime::TZ::UTC); - memcpy(pszDateTime.get_ptr(), str.c_str(), str.size() + 1); - - return CELL_OK; -} - -s32 cellRtcFormatRfc2822LocalTime(vm::ptr pszDateTime, vm::ptr pUtc) -{ - cellRtc.trace("cellRtcFormatRfc2822LocalTime(pszDateTime=*0x%x, pUtc=*0x%x)", pszDateTime, pUtc); - - // Get date from ticks. - rDateTime date = rDateTime((time_t)pUtc->tick); - - // Format date string in RFC2822 format (e.g.: Mon, 01 Jan 1990 12:00:00 +0000). - const std::string str = date.Format("%a, %d %b %Y %T %z", rDateTime::TZ::Local); - memcpy(pszDateTime.get_ptr(), str.c_str(), str.size() + 1); - - return CELL_OK; -} - -s32 cellRtcFormatRfc3339(vm::ptr pszDateTime, vm::ptr pUtc, s32 iTimeZone) -{ - cellRtc.trace("cellRtcFormatRfc3339(pszDateTime=*0x%x, pUtc=*0x%x, iTimeZone=%d)", pszDateTime, pUtc, iTimeZone); - - // Add time_zone as offset in minutes. - rTimeSpan tz = rTimeSpan(0, (long) iTimeZone, 0, 0); - - // Get date from ticks + tz. - rDateTime date = rDateTime((time_t)pUtc->tick); - date.Add(tz); - - // Format date string in RFC3339 format (e.g.: 1990-01-01T12:00:00.00Z). - const std::string str = date.Format("%FT%T.%zZ", rDateTime::TZ::UTC); - memcpy(pszDateTime.get_ptr(), str.c_str(), str.size() + 1); - - return CELL_OK; -} - -s32 cellRtcFormatRfc3339LocalTime(vm::ptr pszDateTime, vm::ptr pUtc) -{ - cellRtc.trace("cellRtcFormatRfc3339LocalTime(pszDateTime=*0x%x, pUtc=*0x%x)", pszDateTime, pUtc); - - // Get date from ticks. - rDateTime date = rDateTime((time_t) pUtc->tick); - - // Format date string in RFC3339 format (e.g.: 1990-01-01T12:00:00.00Z). - const std::string str = date.Format("%FT%T.%zZ", rDateTime::TZ::Local); - memcpy(pszDateTime.get_ptr(), str.c_str(), str.size() + 1); - - return CELL_OK; -} - -s32 cellRtcParseDateTime(vm::ptr pUtc, vm::cptr pszDateTime) -{ - cellRtc.trace("cellRtcParseDateTime(pUtc=*0x%x, pszDateTime=*0x%x)", pUtc, pszDateTime); - - // Get date from formatted string. - rDateTime date; - date.ParseDateTime(pszDateTime.get_ptr()); - - pUtc->tick = date.GetTicks(); - - return CELL_OK; -} - -s32 cellRtcParseRfc3339(vm::ptr pUtc, vm::cptr pszDateTime) -{ - cellRtc.trace("cellRtcParseRfc3339(pUtc=*0x%x, pszDateTime=*0x%x)", pUtc, pszDateTime); - - // Get date from RFC3339 formatted string. - rDateTime date; - date.ParseDateTime(pszDateTime.get_ptr()); - - pUtc->tick = date.GetTicks(); - - return CELL_OK; -} - -s32 cellRtcGetTick(vm::ptr pTime, vm::ptr pTick) -{ - cellRtc.trace("cellRtcGetTick(pTime=*0x%x, pTick=*0x%x)", pTime, pTick); - - rDateTime datetime = rDateTime(pTime->day, (rDateTime::Month)pTime->month.value(), pTime->year, pTime->hour, pTime->minute, pTime->second, (pTime->microsecond / 1000)); - pTick->tick = datetime.GetTicks(); - - return CELL_OK; -} - -s32 cellRtcSetTick(vm::ptr pTime, vm::ptr pTick) -{ - cellRtc.trace("cellRtcSetTick(pTime=*0x%x, pTick=*0x%x)", pTime, pTick); - - rDateTime date = rDateTime((time_t)pTick->tick); - - pTime->year = date.GetYear(rDateTime::TZ::UTC); - pTime->month = date.GetMonth(rDateTime::TZ::UTC); - pTime->day = date.GetDay(rDateTime::TZ::UTC); - pTime->hour = date.GetHour(rDateTime::TZ::UTC); - pTime->minute = date.GetMinute(rDateTime::TZ::UTC); - pTime->second = date.GetSecond(rDateTime::TZ::UTC); - pTime->microsecond = date.GetMillisecond(rDateTime::TZ::UTC) * 1000; - - return CELL_OK; -} - -s32 cellRtcTickAddTicks(vm::ptr pTick0, vm::ptr pTick1, s64 lAdd) -{ - cellRtc.trace("cellRtcTickAddTicks(pTick0=*0x%x, pTick1=*0x%x, lAdd=%lld)", pTick0, pTick1, lAdd); - - pTick0->tick = pTick1->tick + lAdd; - return CELL_OK; -} - -s32 cellRtcTickAddMicroseconds(vm::ptr pTick0, vm::ptr pTick1, s64 lAdd) -{ - cellRtc.trace("cellRtcTickAddMicroseconds(pTick0=*0x%x, pTick1=*0x%x, lAdd=%lld)", pTick0, pTick1, lAdd); - - rDateTime date = rDateTime((time_t)pTick1->tick); - rTimeSpan microseconds = rTimeSpan(0, 0, 0, lAdd / 1000); - date.Add(microseconds); - pTick0->tick = date.GetTicks(); - - return CELL_OK; -} - -s32 cellRtcTickAddSeconds(vm::ptr pTick0, vm::ptr pTick1, s64 lAdd) -{ - cellRtc.trace("cellRtcTickAddSeconds(pTick0=*0x%x, pTick1=*0x%x, lAdd=%lld)", pTick0, pTick1, lAdd); - - rDateTime date = rDateTime((time_t)pTick1->tick); - rTimeSpan seconds = rTimeSpan(0, 0, lAdd, 0); - date.Add(seconds); - pTick0->tick = date.GetTicks(); - - return CELL_OK; -} - -s32 cellRtcTickAddMinutes(vm::ptr pTick0, vm::ptr pTick1, s64 lAdd) -{ - cellRtc.trace("cellRtcTickAddMinutes(pTick0=*0x%x, pTick1=*0x%x, lAdd=%lld)", pTick0, pTick1, lAdd); - - rDateTime date = rDateTime((time_t)pTick1->tick); - rTimeSpan minutes = rTimeSpan(0, lAdd, 0, 0); // ??? - date.Add(minutes); - pTick0->tick = date.GetTicks(); - - return CELL_OK; -} - -s32 cellRtcTickAddHours(vm::ptr pTick0, vm::ptr pTick1, s32 iAdd) -{ - cellRtc.trace("cellRtcTickAddHours(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd); - - rDateTime date = rDateTime((time_t)pTick1->tick); - rTimeSpan hours = rTimeSpan(iAdd, 0, 0, 0); // ??? - date.Add(hours); - pTick0->tick = date.GetTicks(); - - return CELL_OK; -} - -s32 cellRtcTickAddDays(vm::ptr pTick0, vm::ptr pTick1, s32 iAdd) -{ - cellRtc.trace("cellRtcTickAddDays(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd); - - rDateTime date = rDateTime((time_t)pTick1->tick); - rDateSpan days = rDateSpan(0, 0, 0, iAdd); // ??? - date.Add(days); - pTick0->tick = date.GetTicks(); - - return CELL_OK; -} - -s32 cellRtcTickAddWeeks(vm::ptr pTick0, vm::ptr pTick1, s32 iAdd) -{ - cellRtc.trace("cellRtcTickAddWeeks(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd); - - rDateTime date = rDateTime((time_t)pTick1->tick); - rDateSpan weeks = rDateSpan(0, 0, iAdd, 0); - date.Add(weeks); - pTick0->tick = date.GetTicks(); - - return CELL_OK; -} - -s32 cellRtcTickAddMonths(vm::ptr pTick0, vm::ptr pTick1, s32 iAdd) -{ - cellRtc.trace("cellRtcTickAddMonths(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd); - - rDateTime date = rDateTime((time_t)pTick1->tick); - rDateSpan months = rDateSpan(0, iAdd, 0, 0); - date.Add(months); - pTick0->tick = date.GetTicks(); - - return CELL_OK; -} - -s32 cellRtcTickAddYears(vm::ptr pTick0, vm::ptr pTick1, s32 iAdd) -{ - cellRtc.trace("cellRtcTickAddYears(pTick0=*0x%x, pTick1=*0x%x, iAdd=%d)", pTick0, pTick1, iAdd); - - rDateTime date = rDateTime((time_t)pTick1->tick); - rDateSpan years = rDateSpan(iAdd, 0, 0, 0); - date.Add(years); - pTick0->tick = date.GetTicks(); - - return CELL_OK; -} - -s32 cellRtcConvertUtcToLocalTime(vm::ptr pUtc, vm::ptr pLocalTime) -{ - cellRtc.trace("cellRtcConvertUtcToLocalTime(pUtc=*0x%x, pLocalTime=*0x%x)", pUtc, pLocalTime); - - rDateTime time = rDateTime((time_t)pUtc->tick); - rDateTime local_time = time.FromUTC(false); - pLocalTime->tick = local_time.GetTicks(); - return CELL_OK; -} - -s32 cellRtcConvertLocalTimeToUtc(vm::ptr pLocalTime, vm::ptr pUtc) -{ - cellRtc.trace("cellRtcConvertLocalTimeToUtc(pLocalTime=*0x%x, pUtc=*0x%x)", pLocalTime, pUtc); - - rDateTime time = rDateTime((time_t)pLocalTime->tick); - rDateTime utc_time = time.ToUTC(false); - pUtc->tick = utc_time.GetTicks(); - return CELL_OK; -} - -s32 cellRtcGetDosTime(vm::ptr pDateTime, vm::ptr puiDosTime) -{ - cellRtc.trace("cellRtcGetDosTime(pDateTime=*0x%x, puiDosTime=*0x%x)", pDateTime, puiDosTime); - - // Convert to DOS time. - rDateTime date_time = rDateTime(pDateTime->day, (rDateTime::Month)pDateTime->month.value(), pDateTime->year, pDateTime->hour, pDateTime->minute, pDateTime->second, (pDateTime->microsecond / 1000)); - *puiDosTime = date_time.GetAsDOS(); - - return CELL_OK; -} - -s32 cellRtcGetTime_t(vm::ptr pDateTime, vm::ptr piTime) -{ - cellRtc.trace("cellRtcGetTime_t(pDateTime=*0x%x, piTime=*0x%x)", pDateTime, piTime); - - // Convert to POSIX time_t. - rDateTime date_time = rDateTime(pDateTime->day, (rDateTime::Month)pDateTime->month.value(), pDateTime->year, pDateTime->hour, pDateTime->minute, pDateTime->second, (pDateTime->microsecond / 1000)); - *piTime = convertToUNIXTime(date_time.GetSecond(rDateTime::TZ::UTC), date_time.GetMinute(rDateTime::TZ::UTC), - date_time.GetHour(rDateTime::TZ::UTC), date_time.GetDay(rDateTime::TZ::UTC), date_time.GetYear(rDateTime::TZ::UTC)); - - return CELL_OK; -} - -s32 cellRtcGetWin32FileTime(vm::ptr pDateTime, vm::ptr pulWin32FileTime) -{ - cellRtc.trace("cellRtcGetWin32FileTime(pDateTime=*0x%x, pulWin32FileTime=*0x%x)", pDateTime, pulWin32FileTime); - - // Convert to WIN32 FILETIME. - rDateTime date_time = rDateTime(pDateTime->day, (rDateTime::Month)pDateTime->month.value(), pDateTime->year, pDateTime->hour, pDateTime->minute, pDateTime->second, (pDateTime->microsecond / 1000)); - *pulWin32FileTime = convertToWin32FILETIME(date_time.GetSecond(rDateTime::TZ::UTC), date_time.GetMinute(rDateTime::TZ::UTC), - date_time.GetHour(rDateTime::TZ::UTC), date_time.GetDay(rDateTime::TZ::UTC), date_time.GetYear(rDateTime::TZ::UTC)); - - return CELL_OK; -} - -s32 cellRtcSetDosTime(vm::ptr pDateTime, u32 uiDosTime) -{ - cellRtc.trace("cellRtcSetDosTime(pDateTime=*0x%x, uiDosTime=0x%x)", pDateTime, uiDosTime); - - rDateTime date_time; - rDateTime dos_time = date_time.SetFromDOS(uiDosTime); - - pDateTime->year = dos_time.GetYear(rDateTime::TZ::UTC); - pDateTime->month = dos_time.GetMonth(rDateTime::TZ::UTC); - pDateTime->day = dos_time.GetDay(rDateTime::TZ::UTC); - pDateTime->hour = dos_time.GetHour(rDateTime::TZ::UTC); - pDateTime->minute = dos_time.GetMinute(rDateTime::TZ::UTC); - pDateTime->second = dos_time.GetSecond(rDateTime::TZ::UTC); - pDateTime->microsecond = dos_time.GetMillisecond(rDateTime::TZ::UTC) * 1000; - - return CELL_OK; -} - -s32 cellRtcSetTime_t(vm::ptr pDateTime, u64 iTime) -{ - cellRtc.trace("cellRtcSetTime_t(pDateTime=*0x%x, iTime=0x%llx)", pDateTime, iTime); - - rDateTime date_time = rDateTime((time_t)iTime); - - pDateTime->year = date_time.GetYear(rDateTime::TZ::UTC); - pDateTime->month = date_time.GetMonth(rDateTime::TZ::UTC); - pDateTime->day = date_time.GetDay(rDateTime::TZ::UTC); - pDateTime->hour = date_time.GetHour(rDateTime::TZ::UTC); - pDateTime->minute = date_time.GetMinute(rDateTime::TZ::UTC); - pDateTime->second = date_time.GetSecond(rDateTime::TZ::UTC); - pDateTime->microsecond = date_time.GetMillisecond(rDateTime::TZ::UTC) * 1000; - - return CELL_OK; -} - -s32 cellRtcSetWin32FileTime(vm::ptr pDateTime, u64 ulWin32FileTime) -{ - cellRtc.trace("cellRtcSetWin32FileTime(pDateTime=*0x%x, ulWin32FileTime=0x%llx)", pDateTime, ulWin32FileTime); - - rDateTime date_time = rDateTime((time_t)ulWin32FileTime); - - pDateTime->year = date_time.GetYear(rDateTime::TZ::UTC); - pDateTime->month = date_time.GetMonth(rDateTime::TZ::UTC); - pDateTime->day = date_time.GetDay(rDateTime::TZ::UTC); - pDateTime->hour = date_time.GetHour(rDateTime::TZ::UTC); - pDateTime->minute = date_time.GetMinute(rDateTime::TZ::UTC); - pDateTime->second = date_time.GetSecond(rDateTime::TZ::UTC); - pDateTime->microsecond = date_time.GetMillisecond(rDateTime::TZ::UTC) * 1000; - - return CELL_OK; -} - -s32 cellRtcIsLeapYear(s32 year) -{ - cellRtc.trace("cellRtcIsLeapYear(year=%d)", year); - - rDateTime datetime; - return datetime.IsLeapYear(year, rDateTime::Gregorian); -} - -s32 cellRtcGetDaysInMonth(s32 year, s32 month) -{ - cellRtc.trace("cellRtcGetDaysInMonth(year=%d, month=%d)", year, month); - - rDateTime datetime; - return datetime.GetNumberOfDays((rDateTime::Month) month, year, rDateTime::Gregorian); -} - -s32 cellRtcGetDayOfWeek(s32 year, s32 month, s32 day) -{ - cellRtc.trace("cellRtcGetDayOfWeek(year=%d, month=%d, day=%d)", year, month, day); - - rDateTime datetime; - datetime.SetToWeekDay((rDateTime::WeekDay) day, 1, (rDateTime::Month) month, year); - return datetime.GetWeekDay(); -} - -s32 cellRtcCheckValid(vm::ptr pTime) -{ - cellRtc.trace("cellRtcCheckValid(pTime=*0x%x)", pTime); - - if ((pTime->year < 1) || (pTime->year > 9999)) return CELL_RTC_ERROR_INVALID_YEAR; - else if ((pTime->month < 1) || (pTime->month > 12)) return CELL_RTC_ERROR_INVALID_MONTH; - else if ((pTime->day < 1) || (pTime->day > 31)) return CELL_RTC_ERROR_INVALID_DAY; - else if (pTime->hour > 23) return CELL_RTC_ERROR_INVALID_HOUR; - else if (pTime->minute > 59) return CELL_RTC_ERROR_INVALID_MINUTE; - else if (pTime->second > 59) return CELL_RTC_ERROR_INVALID_SECOND; - else if (pTime->microsecond > 999999) return CELL_RTC_ERROR_INVALID_MICROSECOND; - else return CELL_OK; -} - -s32 cellRtcCompareTick(vm::ptr pTick0, vm::ptr pTick1) -{ - cellRtc.trace("cellRtcCompareTick(pTick0=*0x%x, pTick1=*0x%x)", pTick0, pTick1); - - if (pTick0->tick < pTick1->tick) return -1; - else if (pTick0->tick > pTick1->tick) return 1; - else return CELL_OK; -} - -Module<> cellRtc("cellRtc", []() -{ - REG_FUNC(cellRtc, cellRtcGetCurrentTick); - REG_FUNC(cellRtc, cellRtcGetCurrentClock); - REG_FUNC(cellRtc, cellRtcGetCurrentClockLocalTime); - - REG_FUNC(cellRtc, cellRtcFormatRfc2822); - REG_FUNC(cellRtc, cellRtcFormatRfc2822LocalTime); - REG_FUNC(cellRtc, cellRtcFormatRfc3339); - REG_FUNC(cellRtc, cellRtcFormatRfc3339LocalTime); - REG_FUNC(cellRtc, cellRtcParseDateTime); - REG_FUNC(cellRtc, cellRtcParseRfc3339); - - REG_FUNC(cellRtc, cellRtcGetTick); - REG_FUNC(cellRtc, cellRtcSetTick); - REG_FUNC(cellRtc, cellRtcTickAddTicks); - REG_FUNC(cellRtc, cellRtcTickAddMicroseconds); - REG_FUNC(cellRtc, cellRtcTickAddSeconds); - REG_FUNC(cellRtc, cellRtcTickAddMinutes); - REG_FUNC(cellRtc, cellRtcTickAddHours); - REG_FUNC(cellRtc, cellRtcTickAddDays); - REG_FUNC(cellRtc, cellRtcTickAddWeeks); - REG_FUNC(cellRtc, cellRtcTickAddMonths); - REG_FUNC(cellRtc, cellRtcTickAddYears); - REG_FUNC(cellRtc, cellRtcConvertUtcToLocalTime); - REG_FUNC(cellRtc, cellRtcConvertLocalTimeToUtc); - - REG_FUNC(cellRtc, cellRtcGetDosTime); - REG_FUNC(cellRtc, cellRtcGetTime_t); - REG_FUNC(cellRtc, cellRtcGetWin32FileTime); - REG_FUNC(cellRtc, cellRtcSetDosTime); - REG_FUNC(cellRtc, cellRtcSetTime_t); - REG_FUNC(cellRtc, cellRtcSetWin32FileTime); - - REG_FUNC(cellRtc, cellRtcIsLeapYear); - REG_FUNC(cellRtc, cellRtcGetDaysInMonth); - REG_FUNC(cellRtc, cellRtcGetDayOfWeek); - REG_FUNC(cellRtc, cellRtcCheckValid); - - REG_FUNC(cellRtc, cellRtcCompareTick); -}); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp deleted file mode 100644 index 506eb4ba9a..0000000000 --- a/rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp +++ /dev/null @@ -1,1715 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/Cell/SPUThread.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/SysCalls/lv2/sys_sync.h" -#include "Emu/SysCalls/lv2/sys_lwmutex.h" -#include "Emu/SysCalls/lv2/sys_lwcond.h" -#include "Emu/SysCalls/lv2/sys_spu.h" -#include "Emu/SysCalls/Modules/cellSpurs.h" -#include "Loader/ELF32.h" -#include "Emu/FS/vfsStreamMemory.h" - -//---------------------------------------------------------------------------- -// Externs -//---------------------------------------------------------------------------- - -extern Module<> cellSpurs; - -//---------------------------------------------------------------------------- -// Function prototypes -//---------------------------------------------------------------------------- - -// -// SPURS utility functions -// -static void cellSpursModulePutTrace(CellSpursTracePacket * packet, u32 dmaTagId); -static u32 cellSpursModulePollStatus(SPUThread & spu, u32 * status); -static void cellSpursModuleExit(SPUThread & spu); - -static bool spursDma(SPUThread & spu, u32 cmd, u64 ea, u32 lsa, u32 size, u32 tag); -static u32 spursDmaGetCompletionStatus(SPUThread & spu, u32 tagMask); -static u32 spursDmaWaitForCompletion(SPUThread & spu, u32 tagMask, bool waitForAll = true); -static void spursHalt(SPUThread & spu); - -// -// SPURS kernel functions -// -static bool spursKernel1SelectWorkload(SPUThread & spu); -static bool spursKernel2SelectWorkload(SPUThread & spu); -static void spursKernelDispatchWorkload(SPUThread & spu, u64 widAndPollStatus); -static bool spursKernelWorkloadExit(SPUThread & spu); -bool spursKernelEntry(SPUThread & spu); - -// -// SPURS system workload functions -// -static bool spursSysServiceEntry(SPUThread & spu); -// TODO: Exit -static void spursSysServiceIdleHandler(SPUThread & spu, SpursKernelContext * ctxt); -static void spursSysServiceMain(SPUThread & spu, u32 pollStatus); -static void spursSysServiceProcessRequests(SPUThread & spu, SpursKernelContext * ctxt); -static void spursSysServiceActivateWorkload(SPUThread & spu, SpursKernelContext * ctxt); -// TODO: Deactivate workload -static void spursSysServiceUpdateShutdownCompletionEvents(SPUThread & spu, SpursKernelContext * ctxt, u32 wklShutdownBitSet); -static void spursSysServiceTraceSaveCount(SPUThread & spu, SpursKernelContext * ctxt); -static void spursSysServiceTraceUpdate(SPUThread & spu, SpursKernelContext * ctxt, u32 arg2, u32 arg3, u32 forceNotify); -// TODO: Deactivate trace -// TODO: System workload entry -static void spursSysServiceCleanupAfterSystemWorkload(SPUThread & spu, SpursKernelContext * ctxt); - -// -// SPURS taskset policy module functions -// -static bool spursTasksetEntry(SPUThread & spu); -static bool spursTasksetSyscallEntry(SPUThread & spu); -static void spursTasksetResumeTask(SPUThread & spu); -static void spursTasksetStartTask(SPUThread & spu, CellSpursTaskArgument & taskArgs); -static s32 spursTasksetProcessRequest(SPUThread & spu, s32 request, u32 * taskId, u32 * isWaiting); -static void spursTasksetProcessPollStatus(SPUThread & spu, u32 pollStatus); -static bool spursTasksetPollStatus(SPUThread & spu); -static void spursTasksetExit(SPUThread & spu); -static void spursTasksetOnTaskExit(SPUThread & spu, u64 addr, u32 taskId, s32 exitCode, u64 args); -static s32 spursTasketSaveTaskContext(SPUThread & spu); -static void spursTasksetDispatch(SPUThread & spu); -static s32 spursTasksetProcessSyscall(SPUThread & spu, u32 syscallNum, u32 args); -static void spursTasksetInit(SPUThread & spu, u32 pollStatus); -static s32 spursTasksetLoadElf(SPUThread & spu, u32 * entryPoint, u32 * lowestLoadAddr, u64 elfAddr, bool skipWriteableSegments); - -//---------------------------------------------------------------------------- -// SPURS utility functions -//---------------------------------------------------------------------------- - -/// Output trace information -void cellSpursModulePutTrace(CellSpursTracePacket * packet, u32 dmaTagId) { - // TODO: Implement this -} - -/// Check for execution right requests -u32 cellSpursModulePollStatus(SPUThread & spu, u32 * status) { - auto ctxt = vm::_ptr(spu.offset + 0x100); - - spu.gpr[3]._u32[3] = 1; - if (ctxt->spurs->flags1 & SF1_32_WORKLOADS) { - spursKernel2SelectWorkload(spu); - } else { - spursKernel1SelectWorkload(spu); - } - - auto result = spu.gpr[3]._u64[1]; - if (status) { - *status = (u32)result; - } - - u32 wklId = result >> 32; - return wklId == ctxt->wklCurrentId ? 0 : 1; -} - -/// Exit current workload -void cellSpursModuleExit(SPUThread & spu) { - auto ctxt = vm::_ptr(spu.offset + 0x100); - spu.pc = ctxt->exitToKernelAddr - 4; - throw SpursModuleExit(); -} - -/// Execute a DMA operation -bool spursDma(SPUThread & spu, u32 cmd, u64 ea, u32 lsa, u32 size, u32 tag) { - spu.set_ch_value(MFC_LSA, lsa); - spu.set_ch_value(MFC_EAH, (u32)(ea >> 32)); - spu.set_ch_value(MFC_EAL, (u32)(ea)); - spu.set_ch_value(MFC_Size, size); - spu.set_ch_value(MFC_TagID, tag); - spu.set_ch_value(MFC_Cmd, cmd); - - if (cmd == MFC_GETLLAR_CMD || cmd == MFC_PUTLLC_CMD || cmd == MFC_PUTLLUC_CMD) { - u32 rv; - - rv = spu.get_ch_value(MFC_RdAtomicStat); - auto success = rv ? true : false; - success = cmd == MFC_PUTLLC_CMD ? !success : success; - return success; - } - - return true; -} - -/// Get the status of DMA operations -u32 spursDmaGetCompletionStatus(SPUThread & spu, u32 tagMask) { - spu.set_ch_value(MFC_WrTagMask, tagMask); - spu.set_ch_value(MFC_WrTagUpdate, MFC_TAG_UPDATE_IMMEDIATE); - return spu.get_ch_value(MFC_RdTagStat); -} - -/// Wait for DMA operations to complete -u32 spursDmaWaitForCompletion(SPUThread & spu, u32 tagMask, bool waitForAll) { - spu.set_ch_value(MFC_WrTagMask, tagMask); - spu.set_ch_value(MFC_WrTagUpdate, waitForAll ? MFC_TAG_UPDATE_ALL : MFC_TAG_UPDATE_ANY); - return spu.get_ch_value(MFC_RdTagStat); -} - -/// Halt the SPU -void spursHalt(SPUThread & spu) { - spu.halt(); -} - -//---------------------------------------------------------------------------- -// SPURS kernel functions -//---------------------------------------------------------------------------- - -/// Select a workload to run -bool spursKernel1SelectWorkload(SPUThread & spu) { - auto ctxt = vm::_ptr(spu.offset + 0x100); - - // The first and only argument to this function is a boolean that is set to false if the function - // is called by the SPURS kernel and set to true if called by cellSpursModulePollStatus. - // If the first argument is true then the shared data is not updated with the result. - const auto isPoll = spu.gpr[3]._u32[3]; - - u32 wklSelectedId; - u32 pollStatus; - - vm::reservation_op(VM_CAST(ctxt->spurs.addr()), 128, [&]() { - // lock the first 0x80 bytes of spurs - auto spurs = ctxt->spurs.get_ptr_priv(); - - // Calculate the contention (number of SPUs used) for each workload - u8 contention[CELL_SPURS_MAX_WORKLOAD]; - u8 pendingContention[CELL_SPURS_MAX_WORKLOAD]; - for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) { - contention[i] = spurs->wklCurrentContention[i] - ctxt->wklLocContention[i]; - - // If this is a poll request then the number of SPUs pending to context switch is also added to the contention presumably - // to prevent unnecessary jumps to the kernel - if (isPoll) { - pendingContention[i] = spurs->wklPendingContention[i] - ctxt->wklLocPendingContention[i]; - if (i != ctxt->wklCurrentId) { - contention[i] += pendingContention[i]; - } - } - } - - wklSelectedId = CELL_SPURS_SYS_SERVICE_WORKLOAD_ID; - pollStatus = 0; - - // The system service has the highest priority. Select the system service if - // the system service message bit for this SPU is set. - if (spurs->sysSrvMessage & (1 << ctxt->spuNum)) { - ctxt->spuIdling = 0; - if (!isPoll || ctxt->wklCurrentId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) { - // Clear the message bit - spurs->sysSrvMessage.raw() &= ~(1 << ctxt->spuNum); - } - } else { - // Caclulate the scheduling weight for each workload - u16 maxWeight = 0; - for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) { - u16 runnable = ctxt->wklRunnable1 & (0x8000 >> i); - u16 wklSignal = spurs->wklSignal1.load() & (0x8000 >> i); - u8 wklFlag = spurs->wklFlag.flag.load() == 0 ? spurs->wklFlagReceiver == i ? 1 : 0 : 0; - u8 readyCount = spurs->wklReadyCount1[i] > CELL_SPURS_MAX_SPU ? CELL_SPURS_MAX_SPU : spurs->wklReadyCount1[i].load(); - u8 idleSpuCount = spurs->wklIdleSpuCountOrReadyCount2[i] > CELL_SPURS_MAX_SPU ? CELL_SPURS_MAX_SPU : spurs->wklIdleSpuCountOrReadyCount2[i].load(); - u8 requestCount = readyCount + idleSpuCount; - - // For a workload to be considered for scheduling: - // 1. Its priority must not be 0 - // 2. The number of SPUs used by it must be less than the max contention for that workload - // 3. The workload should be in runnable state - // 4. The number of SPUs allocated to it must be less than the number of SPUs requested (i.e. readyCount) - // OR the workload must be signalled - // OR the workload flag is 0 and the workload is configured as the wokload flag receiver - if (runnable && ctxt->priority[i] != 0 && spurs->wklMaxContention[i] > contention[i]) { - if (wklFlag || wklSignal || (readyCount != 0 && requestCount > contention[i])) { - // The scheduling weight of the workload is formed from the following parameters in decreasing order of priority: - // 1. Wokload signal set or workload flag or ready count > contention - // 2. Priority of the workload on the SPU - // 3. Is the workload the last selected workload - // 4. Minimum contention of the workload - // 5. Number of SPUs that are being used by the workload (lesser the number, more the weight) - // 6. Is the workload executable same as the currently loaded executable - // 7. The workload id (lesser the number, more the weight) - u16 weight = (wklFlag || wklSignal || (readyCount > contention[i])) ? 0x8000 : 0; - weight |= (u16)(ctxt->priority[i] & 0x7F) << 16; - weight |= i == ctxt->wklCurrentId ? 0x80 : 0x00; - weight |= (contention[i] > 0 && spurs->wklMinContention[i] > contention[i]) ? 0x40 : 0x00; - weight |= ((CELL_SPURS_MAX_SPU - contention[i]) & 0x0F) << 2; - weight |= ctxt->wklUniqueId[i] == ctxt->wklCurrentId ? 0x02 : 0x00; - weight |= 0x01; - - // In case of a tie the lower numbered workload is chosen - if (weight > maxWeight) { - wklSelectedId = i; - maxWeight = weight; - pollStatus = readyCount > contention[i] ? CELL_SPURS_MODULE_POLL_STATUS_READYCOUNT : 0; - pollStatus |= wklSignal ? CELL_SPURS_MODULE_POLL_STATUS_SIGNAL : 0; - pollStatus |= wklFlag ? CELL_SPURS_MODULE_POLL_STATUS_FLAG : 0; - } - } - } - } - - // Not sure what this does. Possibly mark the SPU as idle/in use. - ctxt->spuIdling = wklSelectedId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID ? 1 : 0; - - if (!isPoll || wklSelectedId == ctxt->wklCurrentId) { - // Clear workload signal for the selected workload - spurs->wklSignal1.raw() &= ~(0x8000 >> wklSelectedId); - spurs->wklSignal2.raw() &= ~(0x80000000u >> wklSelectedId); - - // If the selected workload is the wklFlag workload then pull the wklFlag to all 1s - if (wklSelectedId == spurs->wklFlagReceiver) { - spurs->wklFlag.flag = -1; - } - } - } - - if (!isPoll) { - // Called by kernel - // Increment the contention for the selected workload - if (wklSelectedId != CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) { - contention[wklSelectedId]++; - } - - for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) { - spurs->wklCurrentContention[i] = contention[i]; - spurs->wklPendingContention[i] = spurs->wklPendingContention[i] - ctxt->wklLocPendingContention[i]; - ctxt->wklLocContention[i] = 0; - ctxt->wklLocPendingContention[i] = 0; - } - - if (wklSelectedId != CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) { - ctxt->wklLocContention[wklSelectedId] = 1; - } - - ctxt->wklCurrentId = wklSelectedId; - } else if (wklSelectedId != ctxt->wklCurrentId) { - // Not called by kernel but a context switch is required - // Increment the pending contention for the selected workload - if (wklSelectedId != CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) { - pendingContention[wklSelectedId]++; - } - - for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) { - spurs->wklPendingContention[i] = pendingContention[i]; - ctxt->wklLocPendingContention[i] = 0; - } - - if (wklSelectedId != CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) { - ctxt->wklLocPendingContention[wklSelectedId] = 1; - } - } else { - // Not called by kernel and no context switch is required - for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) { - spurs->wklPendingContention[i] = spurs->wklPendingContention[i] - ctxt->wklLocPendingContention[i]; - ctxt->wklLocPendingContention[i] = 0; - } - } - - std::memcpy(vm::base(spu.offset + 0x100), spurs, 128); - }); - - u64 result = (u64)wklSelectedId << 32; - result |= pollStatus; - spu.gpr[3]._u64[1] = result; - return true; -} - -/// Select a workload to run -bool spursKernel2SelectWorkload(SPUThread & spu) { - auto ctxt = vm::_ptr(spu.offset + 0x100); - - // The first and only argument to this function is a boolean that is set to false if the function - // is called by the SPURS kernel and set to true if called by cellSpursModulePollStatus. - // If the first argument is true then the shared data is not updated with the result. - const auto isPoll = spu.gpr[3]._u32[3]; - - u32 wklSelectedId; - u32 pollStatus; - - vm::reservation_op(VM_CAST(ctxt->spurs.addr()), 128, [&]() { - // lock the first 0x80 bytes of spurs - auto spurs = ctxt->spurs.get_ptr_priv(); - - // Calculate the contention (number of SPUs used) for each workload - u8 contention[CELL_SPURS_MAX_WORKLOAD2]; - u8 pendingContention[CELL_SPURS_MAX_WORKLOAD2]; - for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD2; i++) { - contention[i] = spurs->wklCurrentContention[i & 0x0F] - ctxt->wklLocContention[i & 0x0F]; - contention[i] = i < CELL_SPURS_MAX_WORKLOAD ? contention[i] & 0x0F : contention[i] >> 4; - - // If this is a poll request then the number of SPUs pending to context switch is also added to the contention presumably - // to prevent unnecessary jumps to the kernel - if (isPoll) { - pendingContention[i] = spurs->wklPendingContention[i & 0x0F] - ctxt->wklLocPendingContention[i & 0x0F]; - pendingContention[i] = i < CELL_SPURS_MAX_WORKLOAD ? pendingContention[i] & 0x0F : pendingContention[i] >> 4; - if (i != ctxt->wklCurrentId) { - contention[i] += pendingContention[i]; - } - } - } - - wklSelectedId = CELL_SPURS_SYS_SERVICE_WORKLOAD_ID; - pollStatus = 0; - - // The system service has the highest priority. Select the system service if - // the system service message bit for this SPU is set. - if (spurs->sysSrvMessage & (1 << ctxt->spuNum)) { - // Not sure what this does. Possibly Mark the SPU as in use. - ctxt->spuIdling = 0; - if (!isPoll || ctxt->wklCurrentId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) { - // Clear the message bit - spurs->sysSrvMessage.raw() &= ~(1 << ctxt->spuNum); - } - } else { - // Caclulate the scheduling weight for each workload - u8 maxWeight = 0; - for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD2; i++) { - auto j = i & 0x0F; - u16 runnable = i < CELL_SPURS_MAX_WORKLOAD ? ctxt->wklRunnable1 & (0x8000 >> j) : ctxt->wklRunnable2 & (0x8000 >> j); - u8 priority = i < CELL_SPURS_MAX_WORKLOAD ? ctxt->priority[j] & 0x0F : ctxt->priority[j] >> 4; - u8 maxContention = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklMaxContention[j] & 0x0F : spurs->wklMaxContention[j] >> 4; - u16 wklSignal = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklSignal1.load() & (0x8000 >> j) : spurs->wklSignal2.load() & (0x8000 >> j); - u8 wklFlag = spurs->wklFlag.flag.load() == 0 ? spurs->wklFlagReceiver == i ? 1 : 0 : 0; - u8 readyCount = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklReadyCount1[j] : spurs->wklIdleSpuCountOrReadyCount2[j]; - - // For a workload to be considered for scheduling: - // 1. Its priority must be greater than 0 - // 2. The number of SPUs used by it must be less than the max contention for that workload - // 3. The workload should be in runnable state - // 4. The number of SPUs allocated to it must be less than the number of SPUs requested (i.e. readyCount) - // OR the workload must be signalled - // OR the workload flag is 0 and the workload is configured as the wokload receiver - if (runnable && priority > 0 && maxContention > contention[i]) { - if (wklFlag || wklSignal || readyCount > contention[i]) { - // The scheduling weight of the workload is equal to the priority of the workload for the SPU. - // The current workload is given a sligtly higher weight presumably to reduce the number of context switches. - // In case of a tie the lower numbered workload is chosen. - u8 weight = priority << 4; - if (ctxt->wklCurrentId == i) { - weight |= 0x04; - } - - if (weight > maxWeight) { - wklSelectedId = i; - maxWeight = weight; - pollStatus = readyCount > contention[i] ? CELL_SPURS_MODULE_POLL_STATUS_READYCOUNT : 0; - pollStatus |= wklSignal ? CELL_SPURS_MODULE_POLL_STATUS_SIGNAL : 0; - pollStatus |= wklFlag ? CELL_SPURS_MODULE_POLL_STATUS_FLAG : 0; - } - } - } - } - - // Not sure what this does. Possibly mark the SPU as idle/in use. - ctxt->spuIdling = wklSelectedId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID ? 1 : 0; - - if (!isPoll || wklSelectedId == ctxt->wklCurrentId) { - // Clear workload signal for the selected workload - spurs->wklSignal1.raw() &= ~(0x8000 >> wklSelectedId); - spurs->wklSignal2.raw() &= ~(0x80000000u >> wklSelectedId); - - // If the selected workload is the wklFlag workload then pull the wklFlag to all 1s - if (wklSelectedId == spurs->wklFlagReceiver) { - spurs->wklFlag.flag = -1; - } - } - } - - if (!isPoll) { - // Called by kernel - // Increment the contention for the selected workload - if (wklSelectedId != CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) { - contention[wklSelectedId]++; - } - - for (auto i = 0; i < (CELL_SPURS_MAX_WORKLOAD2 >> 1); i++) { - spurs->wklCurrentContention[i] = contention[i] | (contention[i + 0x10] << 4); - spurs->wklPendingContention[i] = spurs->wklPendingContention[i] - ctxt->wklLocPendingContention[i]; - ctxt->wklLocContention[i] = 0; - ctxt->wklLocPendingContention[i] = 0; - } - - ctxt->wklLocContention[wklSelectedId & 0x0F] = wklSelectedId < CELL_SPURS_MAX_WORKLOAD ? 0x01 : wklSelectedId < CELL_SPURS_MAX_WORKLOAD2 ? 0x10 : 0; - ctxt->wklCurrentId = wklSelectedId; - } else if (wklSelectedId != ctxt->wklCurrentId) { - // Not called by kernel but a context switch is required - // Increment the pending contention for the selected workload - if (wklSelectedId != CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) { - pendingContention[wklSelectedId]++; - } - - for (auto i = 0; i < (CELL_SPURS_MAX_WORKLOAD2 >> 1); i++) { - spurs->wklPendingContention[i] = pendingContention[i] | (pendingContention[i + 0x10] << 4); - ctxt->wklLocPendingContention[i] = 0; - } - - ctxt->wklLocPendingContention[wklSelectedId & 0x0F] = wklSelectedId < CELL_SPURS_MAX_WORKLOAD ? 0x01 : wklSelectedId < CELL_SPURS_MAX_WORKLOAD2 ? 0x10 : 0; - } else { - // Not called by kernel and no context switch is required - for (auto i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) { - spurs->wklPendingContention[i] = spurs->wklPendingContention[i] - ctxt->wklLocPendingContention[i]; - ctxt->wklLocPendingContention[i] = 0; - } - } - - std::memcpy(vm::base(spu.offset + 0x100), spurs, 128); - }); - - u64 result = (u64)wklSelectedId << 32; - result |= pollStatus; - spu.gpr[3]._u64[1] = result; - return true; -} - -/// SPURS kernel dispatch workload -void spursKernelDispatchWorkload(SPUThread & spu, u64 widAndPollStatus) { - auto ctxt = vm::_ptr(spu.offset + 0x100); - auto isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false; - - auto pollStatus = (u32)widAndPollStatus; - auto wid = (u32)(widAndPollStatus >> 32); - - // DMA in the workload info for the selected workload - auto wklInfoOffset = wid < CELL_SPURS_MAX_WORKLOAD ? &ctxt->spurs->wklInfo1[wid] : - wid < CELL_SPURS_MAX_WORKLOAD2 && isKernel2 ? &ctxt->spurs->wklInfo2[wid & 0xf] : - &ctxt->spurs->wklInfoSysSrv; - - std::memcpy(vm::base(spu.offset + 0x3FFE0), wklInfoOffset, 0x20); - - // Load the workload to LS - auto wklInfo = vm::_ptr(spu.offset + 0x3FFE0); - if (ctxt->wklCurrentAddr != wklInfo->addr) { - switch (wklInfo->addr.addr()) { - case SPURS_IMG_ADDR_SYS_SRV_WORKLOAD: - spu.RegisterHleFunction(0xA00, spursSysServiceEntry); - break; - case SPURS_IMG_ADDR_TASKSET_PM: - spu.RegisterHleFunction(0xA00, spursTasksetEntry); - break; - default: - std::memcpy(vm::base(spu.offset + 0xA00), wklInfo->addr.get_ptr(), wklInfo->size); - break; - } - - ctxt->wklCurrentAddr = wklInfo->addr; - ctxt->wklCurrentUniqueId = wklInfo->uniqueId; - } - - if (!isKernel2) { - ctxt->moduleId[0] = 0; - ctxt->moduleId[1] = 0; - } - - // Run workload - spu.gpr[0]._u32[3] = ctxt->exitToKernelAddr; - spu.gpr[1]._u32[3] = 0x3FFB0; - spu.gpr[3]._u32[3] = 0x100; - spu.gpr[4]._u64[1] = wklInfo->arg; - spu.gpr[5]._u32[3] = pollStatus; - spu.pc = 0xA00 - 4; -} - -/// SPURS kernel workload exit -bool spursKernelWorkloadExit(SPUThread & spu) { - auto ctxt = vm::_ptr(spu.offset + 0x100); - auto isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false; - - // Select next workload to run - spu.gpr[3].clear(); - if (isKernel2) { - spursKernel2SelectWorkload(spu); - } else { - spursKernel1SelectWorkload(spu); - } - - spursKernelDispatchWorkload(spu, spu.gpr[3]._u64[1]); - return false; -} - -/// SPURS kernel entry point -bool spursKernelEntry(SPUThread & spu) { - while (true) { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - CHECK_EMU_STATUS; - } - - auto ctxt = vm::_ptr(spu.offset + 0x100); - memset(ctxt, 0, sizeof(SpursKernelContext)); - - // Save arguments - ctxt->spuNum = spu.gpr[3]._u32[3]; - ctxt->spurs.set(spu.gpr[4]._u64[1]); - - auto isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false; - - // Initialise the SPURS context to its initial values - ctxt->dmaTagId = CELL_SPURS_KERNEL_DMA_TAG_ID; - ctxt->wklCurrentUniqueId = 0x20; - ctxt->wklCurrentId = CELL_SPURS_SYS_SERVICE_WORKLOAD_ID; - ctxt->exitToKernelAddr = isKernel2 ? CELL_SPURS_KERNEL2_EXIT_ADDR : CELL_SPURS_KERNEL1_EXIT_ADDR; - ctxt->selectWorkloadAddr = isKernel2 ? CELL_SPURS_KERNEL2_SELECT_WORKLOAD_ADDR : CELL_SPURS_KERNEL1_SELECT_WORKLOAD_ADDR; - if (!isKernel2) { - ctxt->x1F0 = 0xF0020000; - ctxt->x200 = 0x20000; - ctxt->guid[0] = 0x423A3A02; - ctxt->guid[1] = 0x43F43A82; - ctxt->guid[2] = 0x43F26502; - ctxt->guid[3] = 0x420EB382; - } else { - ctxt->guid[0] = 0x43A08402; - ctxt->guid[1] = 0x43FB0A82; - ctxt->guid[2] = 0x435E9302; - ctxt->guid[3] = 0x43A3C982; - } - - // Register SPURS kernel HLE functions - spu.UnregisterHleFunctions(0, 0x40000/*LS_BOTTOM*/); - spu.RegisterHleFunction(isKernel2 ? CELL_SPURS_KERNEL2_ENTRY_ADDR : CELL_SPURS_KERNEL1_ENTRY_ADDR, spursKernelEntry); - spu.RegisterHleFunction(ctxt->exitToKernelAddr, spursKernelWorkloadExit); - spu.RegisterHleFunction(ctxt->selectWorkloadAddr, isKernel2 ? spursKernel2SelectWorkload : spursKernel1SelectWorkload); - - // Start the system service - spursKernelDispatchWorkload(spu, ((u64)CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) << 32); - return false; -} - -//---------------------------------------------------------------------------- -// SPURS system workload functions -//---------------------------------------------------------------------------- - -/// Entry point of the system service -bool spursSysServiceEntry(SPUThread & spu) { - auto ctxt = vm::_ptr(spu.offset + spu.gpr[3]._u32[3]); - auto arg = spu.gpr[4]._u64[1]; - auto pollStatus = spu.gpr[5]._u32[3]; - - try { - if (ctxt->wklCurrentId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) { - spursSysServiceMain(spu, pollStatus); - } else { - // TODO: If we reach here it means the current workload was preempted to start the - // system workload. Need to implement this. - } - - cellSpursModuleExit(spu); - } - - catch (SpursModuleExit) { - } - - return false; -} - -/// Wait for an external event or exit the SPURS thread group if no workloads can be scheduled -void spursSysServiceIdleHandler(SPUThread & spu, SpursKernelContext * ctxt) { - bool shouldExit; - - std::unique_lock lock(spu.mutex, std::defer_lock); - - while (true) { - vm::reservation_acquire(vm::base(spu.offset + 0x100), VM_CAST(ctxt->spurs.addr()), 128); - auto spurs = vm::_ptr(spu.offset + 0x100); - - // Find the number of SPUs that are idling in this SPURS instance - u32 nIdlingSpus = 0; - for (u32 i = 0; i < 8; i++) { - if (spurs->spuIdling & (1 << i)) { - nIdlingSpus++; - } - } - - bool allSpusIdle = nIdlingSpus == spurs->nSpus ? true: false; - bool exitIfNoWork = spurs->flags1 & SF1_EXIT_IF_NO_WORK ? true : false; - shouldExit = allSpusIdle && exitIfNoWork; - - // Check if any workloads can be scheduled - bool foundReadyWorkload = false; - if (spurs->sysSrvMessage & (1 << ctxt->spuNum)) { - foundReadyWorkload = true; - } else { - if (spurs->flags1 & SF1_32_WORKLOADS) { - for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD2; i++) { - u32 j = i & 0x0F; - u16 runnable = i < CELL_SPURS_MAX_WORKLOAD ? ctxt->wklRunnable1 & (0x8000 >> j) : ctxt->wklRunnable2 & (0x8000 >> j); - u8 priority = i < CELL_SPURS_MAX_WORKLOAD ? ctxt->priority[j] & 0x0F : ctxt->priority[j] >> 4; - u8 maxContention = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklMaxContention[j] & 0x0F : spurs->wklMaxContention[j] >> 4; - u8 contention = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklCurrentContention[j] & 0x0F : spurs->wklCurrentContention[j] >> 4; - u16 wklSignal = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklSignal1.load() & (0x8000 >> j) : spurs->wklSignal2.load() & (0x8000 >> j); - u8 wklFlag = spurs->wklFlag.flag.load() == 0 ? spurs->wklFlagReceiver == i ? 1 : 0 : 0; - u8 readyCount = i < CELL_SPURS_MAX_WORKLOAD ? spurs->wklReadyCount1[j] : spurs->wklIdleSpuCountOrReadyCount2[j]; - - if (runnable && priority > 0 && maxContention > contention) { - if (wklFlag || wklSignal || readyCount > contention) { - foundReadyWorkload = true; - break; - } - } - } - } else { - for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) { - u16 runnable = ctxt->wklRunnable1 & (0x8000 >> i); - u16 wklSignal = spurs->wklSignal1.load() & (0x8000 >> i); - u8 wklFlag = spurs->wklFlag.flag.load() == 0 ? spurs->wklFlagReceiver == i ? 1 : 0 : 0; - u8 readyCount = spurs->wklReadyCount1[i] > CELL_SPURS_MAX_SPU ? CELL_SPURS_MAX_SPU : spurs->wklReadyCount1[i].load(); - u8 idleSpuCount = spurs->wklIdleSpuCountOrReadyCount2[i] > CELL_SPURS_MAX_SPU ? CELL_SPURS_MAX_SPU : spurs->wklIdleSpuCountOrReadyCount2[i].load(); - u8 requestCount = readyCount + idleSpuCount; - - if (runnable && ctxt->priority[i] != 0 && spurs->wklMaxContention[i] > spurs->wklCurrentContention[i]) { - if (wklFlag || wklSignal || (readyCount != 0 && requestCount > spurs->wklCurrentContention[i])) { - foundReadyWorkload = true; - break; - } - } - } - } - } - - bool spuIdling = spurs->spuIdling & (1 << ctxt->spuNum) ? true : false; - if (foundReadyWorkload && shouldExit == false) { - spurs->spuIdling &= ~(1 << ctxt->spuNum); - } else { - spurs->spuIdling |= 1 << ctxt->spuNum; - } - - // If all SPUs are idling and the exit_if_no_work flag is set then the SPU thread group must exit. Otherwise wait for external events. - if (spuIdling && shouldExit == false && foundReadyWorkload == false) { - // The system service blocks by making a reservation and waiting on the lock line reservation lost event. - CHECK_EMU_STATUS; - if (!lock) lock.lock(); - spu.cv.wait_for(lock, std::chrono::milliseconds(1)); - continue; - } - - if (vm::reservation_update(VM_CAST(ctxt->spurs.addr()), vm::base(spu.offset + 0x100), 128) && (shouldExit || foundReadyWorkload)) { - break; - } - } - - if (shouldExit) { - // TODO: exit spu thread group - } -} - -/// Main function for the system service -void spursSysServiceMain(SPUThread & spu, u32 pollStatus) { - auto ctxt = vm::_ptr(spu.offset + 0x100); - - if (!ctxt->spurs.aligned()) { - assert(!"spursSysServiceMain(): invalid spurs alignment"); - spursHalt(spu); - } - - // Initialise the system service if this is the first time its being started on this SPU - if (ctxt->sysSrvInitialised == 0) { - ctxt->sysSrvInitialised = 1; - - vm::reservation_acquire(vm::base(spu.offset + 0x100), VM_CAST(ctxt->spurs.addr()), 128); - - vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]() { - auto spurs = ctxt->spurs.get_ptr_priv(); - - // Halt if already initialised - if (spurs->sysSrvOnSpu & (1 << ctxt->spuNum)) { - assert(!"spursSysServiceMain(): already initialized"); - spursHalt(spu); - } - - spurs->sysSrvOnSpu |= 1 << ctxt->spuNum; - - std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); - }); - - ctxt->traceBuffer = 0; - ctxt->traceMsgCount = -1; - spursSysServiceTraceUpdate(spu, ctxt, 1, 1, 0); - spursSysServiceCleanupAfterSystemWorkload(spu, ctxt); - - // Trace - SERVICE: INIT - CellSpursTracePacket pkt; - memset(&pkt, 0, sizeof(pkt)); - pkt.header.tag = CELL_SPURS_TRACE_TAG_SERVICE; - pkt.data.service.incident = CELL_SPURS_TRACE_SERVICE_INIT; - cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); - } - - // Trace - START: Module='SYS ' - CellSpursTracePacket pkt; - memset(&pkt, 0, sizeof(pkt)); - pkt.header.tag = CELL_SPURS_TRACE_TAG_START; - memcpy(pkt.data.start.module, "SYS ", 4); - pkt.data.start.level = 1; // Policy module - pkt.data.start.ls = 0xA00 >> 2; - cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); - - while (true) { - CHECK_EMU_STATUS; - // Process requests for the system service - spursSysServiceProcessRequests(spu, ctxt); - -poll: - if (cellSpursModulePollStatus(spu, nullptr)) { - // Trace - SERVICE: EXIT - CellSpursTracePacket pkt; - memset(&pkt, 0, sizeof(pkt)); - pkt.header.tag = CELL_SPURS_TRACE_TAG_SERVICE; - pkt.data.service.incident = CELL_SPURS_TRACE_SERVICE_EXIT; - cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); - - // Trace - STOP: GUID - memset(&pkt, 0, sizeof(pkt)); - pkt.header.tag = CELL_SPURS_TRACE_TAG_STOP; - pkt.data.stop = SPURS_GUID_SYS_WKL; - cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); - - //spursDmaWaitForCompletion(spu, 1 << ctxt->dmaTagId); - break; - } - - // If we reach here it means that either there are more system service messages to be processed - // or there are no workloads that can be scheduled. - - // If the SPU is not idling then process the remaining system service messages - if (ctxt->spuIdling == 0) { - continue; - } - - // If we reach here it means that the SPU is idling - - // Trace - SERVICE: WAIT - CellSpursTracePacket pkt; - memset(&pkt, 0, sizeof(pkt)); - pkt.header.tag = CELL_SPURS_TRACE_TAG_SERVICE; - pkt.data.service.incident = CELL_SPURS_TRACE_SERVICE_WAIT; - cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); - - spursSysServiceIdleHandler(spu, ctxt); - CHECK_EMU_STATUS; - - goto poll; - } -} - -/// Process any requests -void spursSysServiceProcessRequests(SPUThread & spu, SpursKernelContext * ctxt) { - bool updateTrace = false; - bool updateWorkload = false; - bool terminate = false; - - vm::reservation_op(VM_CAST(ctxt->spurs.addr() + offsetof(CellSpurs, wklState1)), 128, [&]() { - auto spurs = ctxt->spurs.get_ptr_priv(); - - // Terminate request - if (spurs->sysSrvMsgTerminate & (1 << ctxt->spuNum)) { - spurs->sysSrvOnSpu &= ~(1 << ctxt->spuNum); - terminate = true; - } - - // Update workload message - if (spurs->sysSrvMsgUpdateWorkload & (1 << ctxt->spuNum)) { - spurs->sysSrvMsgUpdateWorkload &= ~(1 << ctxt->spuNum); - updateWorkload = true; - } - - // Update trace message - if (spurs->sysSrvTrace.load().sysSrvMsgUpdateTrace & (1 << ctxt->spuNum)) { - updateTrace = true; - } - - std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); - }); - - // Process update workload message - if (updateWorkload) { - spursSysServiceActivateWorkload(spu, ctxt); - } - - // Process update trace message - if (updateTrace) { - spursSysServiceTraceUpdate(spu, ctxt, 1, 0, 0); - } - - // Process terminate request - if (terminate) { - // TODO: Rest of the terminate processing - } -} - -/// Activate a workload -void spursSysServiceActivateWorkload(SPUThread & spu, SpursKernelContext * ctxt) { - auto spurs = vm::_ptr(spu.offset + 0x100); - std::memcpy(vm::base(spu.offset + 0x30000), ctxt->spurs->wklInfo1, 0x200); - if (spurs->flags1 & SF1_32_WORKLOADS) { - std::memcpy(vm::base(spu.offset + 0x30200), ctxt->spurs->wklInfo2, 0x200); - } - - u32 wklShutdownBitSet = 0; - ctxt->wklRunnable1 = 0; - ctxt->wklRunnable2 = 0; - for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) { - auto wklInfo1 = vm::_ptr(spu.offset + 0x30000); - - // Copy the priority of the workload for this SPU and its unique id to the LS - ctxt->priority[i] = wklInfo1[i].priority[ctxt->spuNum] == 0 ? 0 : 0x10 - wklInfo1[i].priority[ctxt->spuNum]; - ctxt->wklUniqueId[i] = wklInfo1[i].uniqueId; - - if (spurs->flags1 & SF1_32_WORKLOADS) { - auto wklInfo2 = vm::_ptr(spu.offset + 0x30200); - - // Copy the priority of the workload for this SPU to the LS - if (wklInfo2[i].priority[ctxt->spuNum]) { - ctxt->priority[i] |= (0x10 - wklInfo2[i].priority[ctxt->spuNum]) << 4; - } - } - } - - vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]() { - auto spurs = ctxt->spurs.get_ptr_priv(); - - for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) { - // Update workload status and runnable flag based on the workload state - auto wklStatus = spurs->wklStatus1[i]; - if (spurs->wklState1[i] == SPURS_WKL_STATE_RUNNABLE) { - spurs->wklStatus1[i] |= 1 << ctxt->spuNum; - ctxt->wklRunnable1 |= 0x8000 >> i; - } else { - spurs->wklStatus1[i] &= ~(1 << ctxt->spuNum); - } - - // If the workload is shutting down and if this is the last SPU from which it is being removed then - // add it to the shutdown bit set - if (spurs->wklState1[i] == SPURS_WKL_STATE_SHUTTING_DOWN) { - if (((wklStatus & (1 << ctxt->spuNum)) != 0) && (spurs->wklStatus1[i] == 0)) { - spurs->wklState1[i] = SPURS_WKL_STATE_REMOVABLE; - wklShutdownBitSet |= 0x80000000u >> i; - } - } - - if (spurs->flags1 & SF1_32_WORKLOADS) { - // Update workload status and runnable flag based on the workload state - wklStatus = spurs->wklStatus2[i]; - if (spurs->wklState2[i] == SPURS_WKL_STATE_RUNNABLE) { - spurs->wklStatus2[i] |= 1 << ctxt->spuNum; - ctxt->wklRunnable2 |= 0x8000 >> i; - } else { - spurs->wklStatus2[i] &= ~(1 << ctxt->spuNum); - } - - // If the workload is shutting down and if this is the last SPU from which it is being removed then - // add it to the shutdown bit set - if (spurs->wklState2[i] == SPURS_WKL_STATE_SHUTTING_DOWN) { - if (((wklStatus & (1 << ctxt->spuNum)) != 0) && (spurs->wklStatus2[i] == 0)) { - spurs->wklState2[i] = SPURS_WKL_STATE_REMOVABLE; - wklShutdownBitSet |= 0x8000 >> i; - } - } - } - } - - std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); - }); - - if (wklShutdownBitSet) { - spursSysServiceUpdateShutdownCompletionEvents(spu, ctxt, wklShutdownBitSet); - } -} - -/// Update shutdown completion events -void spursSysServiceUpdateShutdownCompletionEvents(SPUThread & spu, SpursKernelContext * ctxt, u32 wklShutdownBitSet) { - // Mark the workloads in wklShutdownBitSet as completed and also generate a bit set of the completed - // workloads that have a shutdown completion hook registered - u32 wklNotifyBitSet; - u8 spuPort; - vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]() { - auto spurs = ctxt->spurs.get_ptr_priv(); - - wklNotifyBitSet = 0; - spuPort = spurs->spuPort;; - for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) { - if (wklShutdownBitSet & (0x80000000u >> i)) { - spurs->wklEvent1[i] |= 0x01; - if (spurs->wklEvent1[i] & 0x02 || spurs->wklEvent1[i] & 0x10) { - wklNotifyBitSet |= 0x80000000u >> i; - } - } - - if (wklShutdownBitSet & (0x8000 >> i)) { - spurs->wklEvent2[i] |= 0x01; - if (spurs->wklEvent2[i] & 0x02 || spurs->wklEvent2[i] & 0x10) { - wklNotifyBitSet |= 0x8000 >> i; - } - } - } - - std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); - }); - - if (wklNotifyBitSet) { - // TODO: sys_spu_thread_send_event(spuPort, 0, wklNotifyMask); - } -} - -/// Update the trace count for this SPU -void spursSysServiceTraceSaveCount(SPUThread & spu, SpursKernelContext * ctxt) { - if (ctxt->traceBuffer) { - auto traceInfo = vm::ptr::make((u32)(ctxt->traceBuffer - (ctxt->spurs->traceStartIndex[ctxt->spuNum] << 4))); - traceInfo->count[ctxt->spuNum] = ctxt->traceMsgCount; - } -} - -/// Update trace control -void spursSysServiceTraceUpdate(SPUThread & spu, SpursKernelContext * ctxt, u32 arg2, u32 arg3, u32 forceNotify) { - bool notify; - - u8 sysSrvMsgUpdateTrace; - vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]() { - auto spurs = ctxt->spurs.get_ptr_priv(); - auto& trace = spurs->sysSrvTrace.raw(); - - sysSrvMsgUpdateTrace = trace.sysSrvMsgUpdateTrace; - trace.sysSrvMsgUpdateTrace &= ~(1 << ctxt->spuNum); - trace.sysSrvTraceInitialised &= ~(1 << ctxt->spuNum); - trace.sysSrvTraceInitialised |= arg2 << ctxt->spuNum; - - notify = false; - if (((sysSrvMsgUpdateTrace & (1 << ctxt->spuNum)) != 0) && (spurs->sysSrvTrace.load().sysSrvMsgUpdateTrace == 0) && (spurs->sysSrvTrace.load().sysSrvNotifyUpdateTraceComplete != 0)) { - trace.sysSrvNotifyUpdateTraceComplete = 0; - notify = true; - } - - if (forceNotify && spurs->sysSrvTrace.load().sysSrvNotifyUpdateTraceComplete != 0) { - trace.sysSrvNotifyUpdateTraceComplete = 0; - notify = true; - } - - std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); - }); - - // Get trace parameters from CellSpurs and store them in the LS - if (((sysSrvMsgUpdateTrace & (1 << ctxt->spuNum)) != 0) || (arg3 != 0)) { - vm::reservation_acquire(vm::base(spu.offset + 0x80), ctxt->spurs.ptr(&CellSpurs::traceBuffer).addr(), 128); - auto spurs = vm::_ptr(spu.offset + 0x80 - OFFSET_32(CellSpurs, traceBuffer)); - - if (ctxt->traceMsgCount != 0xFF || spurs->traceBuffer.addr() == 0) { - spursSysServiceTraceSaveCount(spu, ctxt); - } else { - std::memcpy(vm::base(spu.offset + 0x2C00), vm::base(spurs->traceBuffer.addr() & -0x4), 0x80); - auto traceBuffer = vm::_ptr(spu.offset + 0x2C00); - ctxt->traceMsgCount = traceBuffer->count[ctxt->spuNum]; - } - - ctxt->traceBuffer = spurs->traceBuffer.addr() + (spurs->traceStartIndex[ctxt->spuNum] << 4); - ctxt->traceMaxCount = spurs->traceStartIndex[1] - spurs->traceStartIndex[0]; - if (ctxt->traceBuffer == 0) { - ctxt->traceMsgCount = 0; - } - } - - if (notify) { - auto spurs = vm::_ptr(spu.offset + 0x2D80 - OFFSET_32(CellSpurs, wklState1)); - sys_spu_thread_send_event(spu, spurs->spuPort, 2, 0); - } -} - -/// Restore state after executing the system workload -void spursSysServiceCleanupAfterSystemWorkload(SPUThread & spu, SpursKernelContext * ctxt) { - u8 wklId; - - bool do_return = false; - - vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]() { - auto spurs = ctxt->spurs.get_ptr_priv(); - - if (spurs->sysSrvPreemptWklId[ctxt->spuNum] == 0xFF) { - do_return = true; - return; - } - - wklId = spurs->sysSrvPreemptWklId[ctxt->spuNum]; - spurs->sysSrvPreemptWklId[ctxt->spuNum] = 0xFF; - - std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); - }); - - if (do_return) return; - - spursSysServiceActivateWorkload(spu, ctxt); - - vm::reservation_op(VM_CAST(ctxt->spurs.addr()), 128, [&]() { - auto spurs = ctxt->spurs.get_ptr_priv(); - - if (wklId >= CELL_SPURS_MAX_WORKLOAD) { - spurs->wklCurrentContention[wklId & 0x0F] -= 0x10; - spurs->wklReadyCount1[wklId & 0x0F].raw() -= 1; - } else { - spurs->wklCurrentContention[wklId & 0x0F] -= 0x01; - spurs->wklIdleSpuCountOrReadyCount2[wklId & 0x0F].raw() -= 1; - } - - std::memcpy(vm::base(spu.offset + 0x100), spurs, 128); - }); - - // Set the current workload id to the id of the pre-empted workload since cellSpursModulePutTrace - // uses the current worload id to determine the workload to which the trace belongs - auto wklIdSaved = ctxt->wklCurrentId; - ctxt->wklCurrentId = wklId; - - // Trace - STOP: GUID - CellSpursTracePacket pkt; - memset(&pkt, 0, sizeof(pkt)); - pkt.header.tag = CELL_SPURS_TRACE_TAG_STOP; - pkt.data.stop = SPURS_GUID_SYS_WKL; - cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); - - ctxt->wklCurrentId = wklIdSaved; -} - -//---------------------------------------------------------------------------- -// SPURS taskset policy module functions -//---------------------------------------------------------------------------- - -enum SpursTasksetRequest { - SPURS_TASKSET_REQUEST_POLL_SIGNAL = -1, - SPURS_TASKSET_REQUEST_DESTROY_TASK = 0, - SPURS_TASKSET_REQUEST_YIELD_TASK = 1, - SPURS_TASKSET_REQUEST_WAIT_SIGNAL = 2, - SPURS_TASKSET_REQUEST_POLL = 3, - SPURS_TASKSET_REQUEST_WAIT_WKL_FLAG = 4, - SPURS_TASKSET_REQUEST_SELECT_TASK = 5, - SPURS_TASKSET_REQUEST_RECV_WKL_FLAG = 6, -}; - -/// Taskset PM entry point -bool spursTasksetEntry(SPUThread & spu) { - auto ctxt = vm::_ptr(spu.offset + 0x2700); - auto kernelCtxt = vm::_ptr(spu.offset + spu.gpr[3]._u32[3]); - - auto arg = spu.gpr[4]._u64[1]; - auto pollStatus = spu.gpr[5]._u32[3]; - - // Initialise memory and save args - memset(ctxt, 0, sizeof(*ctxt)); - ctxt->taskset.set(arg); - memcpy(ctxt->moduleId, "SPURSTASK MODULE", sizeof(ctxt->moduleId)); - ctxt->kernelMgmtAddr = spu.gpr[3]._u32[3]; - ctxt->syscallAddr = CELL_SPURS_TASKSET_PM_SYSCALL_ADDR; - ctxt->spuNum = kernelCtxt->spuNum; - ctxt->dmaTagId = kernelCtxt->dmaTagId; - ctxt->taskId = 0xFFFFFFFF; - - // Register SPURS takset policy module HLE functions - spu.UnregisterHleFunctions(CELL_SPURS_TASKSET_PM_ENTRY_ADDR, 0x40000/*LS_BOTTOM*/); - spu.RegisterHleFunction(CELL_SPURS_TASKSET_PM_ENTRY_ADDR, spursTasksetEntry); - spu.RegisterHleFunction(ctxt->syscallAddr, spursTasksetSyscallEntry); - - try { - // Initialise the taskset policy module - spursTasksetInit(spu, pollStatus); - - // Dispatch - spursTasksetDispatch(spu); - } - - catch (SpursModuleExit) { - } - - return false; -} - -/// Entry point into the Taskset PM for task syscalls -bool spursTasksetSyscallEntry(SPUThread & spu) { - auto ctxt = vm::_ptr(spu.offset + 0x2700); - - try { - // Save task context - ctxt->savedContextLr = spu.gpr[0]; - ctxt->savedContextSp = spu.gpr[1]; - for (auto i = 0; i < 48; i++) { - ctxt->savedContextR80ToR127[i] = spu.gpr[80 + i]; - } - - // Handle the syscall - spu.gpr[3]._u32[3] = spursTasksetProcessSyscall(spu, spu.gpr[3]._u32[3], spu.gpr[4]._u32[3]); - - // Resume the previously executing task if the syscall did not cause a context switch - throw EXCEPTION("Broken (TODO)"); - //if (spu.m_is_branch == false) { - // spursTasksetResumeTask(spu); - //} - } - - catch (SpursModuleExit) { - } - - return false; -} - -/// Resume a task -void spursTasksetResumeTask(SPUThread & spu) { - auto ctxt = vm::_ptr(spu.offset + 0x2700); - - // Restore task context - spu.gpr[0] = ctxt->savedContextLr; - spu.gpr[1] = ctxt->savedContextSp; - for (auto i = 0; i < 48; i++) { - spu.gpr[80 + i] = ctxt->savedContextR80ToR127[i]; - } - - spu.pc = spu.gpr[0]._u32[3] - 4; -} - -/// Start a task -void spursTasksetStartTask(SPUThread & spu, CellSpursTaskArgument & taskArgs) { - auto ctxt = vm::_ptr(spu.offset + 0x2700); - auto taskset = vm::_ptr(spu.offset + 0x2700); - - spu.gpr[2].clear(); - spu.gpr[3] = v128::from64r(taskArgs._u64[0], taskArgs._u64[1]); - spu.gpr[4]._u64[1] = taskset->args; - spu.gpr[4]._u64[0] = taskset->spurs.addr(); - for (auto i = 5; i < 128; i++) { - spu.gpr[i].clear(); - } - - spu.pc = ctxt->savedContextLr.value()._u32[3] - 4; -} - -/// Process a request and update the state of the taskset -s32 spursTasksetProcessRequest(SPUThread & spu, s32 request, u32 * taskId, u32 * isWaiting) { - auto kernelCtxt = vm::_ptr(spu.offset + 0x100); - auto ctxt = vm::_ptr(spu.offset + 0x2700); - - s32 rc = CELL_OK; - s32 numNewlyReadyTasks; - vm::reservation_op(VM_CAST(ctxt->taskset.addr()), 128, [&]() { - auto taskset = ctxt->taskset.get_ptr_priv(); - - // Verify taskset state is valid - be_t _0(v128::from32(0)); - if ((taskset->waiting & taskset->running) != _0 || (taskset->ready & taskset->pending_ready) != _0 || - ((taskset->running | taskset->ready | taskset->pending_ready | taskset->signalled | taskset->waiting) & ~taskset->enabled) != _0) { - assert(!"Invalid taskset state"); - spursHalt(spu); - } - - // Find the number of tasks that have become ready since the last iteration - auto newlyReadyTasks = (taskset->signalled | taskset->pending_ready) & ~taskset->ready.value(); - numNewlyReadyTasks = 0; - for (auto i = 0; i < 128; i++) { - if (newlyReadyTasks._bit[i]) { - numNewlyReadyTasks++; - } - } - - v128 readyButNotRunning; - u8 selectedTaskId; - v128 running = taskset->running.value(); - v128 waiting = taskset->waiting.value(); - v128 enabled = taskset->enabled.value(); - v128 signalled = (taskset->signalled & (taskset->ready | taskset->pending_ready)); - v128 ready = (taskset->signalled | taskset->ready | taskset->pending_ready); - - switch (request) { - case SPURS_TASKSET_REQUEST_POLL_SIGNAL: - rc = signalled._bit[ctxt->taskId] ? 1 : 0; - signalled._bit[ctxt->taskId] = false; - break; - case SPURS_TASKSET_REQUEST_DESTROY_TASK: - numNewlyReadyTasks--; - running._bit[ctxt->taskId] = false; - enabled._bit[ctxt->taskId] = false; - signalled._bit[ctxt->taskId] = false; - ready._bit[ctxt->taskId] = false; - break; - case SPURS_TASKSET_REQUEST_YIELD_TASK: - running._bit[ctxt->taskId] = false; - waiting._bit[ctxt->taskId] = true; - break; - case SPURS_TASKSET_REQUEST_WAIT_SIGNAL: - if (signalled._bit[ctxt->taskId] == false) { - numNewlyReadyTasks--; - running._bit[ctxt->taskId] = false; - waiting._bit[ctxt->taskId] = true; - signalled._bit[ctxt->taskId] = false; - ready._bit[ctxt->taskId] = false; - } - break; - case SPURS_TASKSET_REQUEST_POLL: - readyButNotRunning = ready & ~running; - if (taskset->wkl_flag_wait_task < CELL_SPURS_MAX_TASK) { - readyButNotRunning = readyButNotRunning & ~(v128::fromBit(taskset->wkl_flag_wait_task)); - } - - rc = readyButNotRunning != _0 ? 1 : 0; - break; - case SPURS_TASKSET_REQUEST_WAIT_WKL_FLAG: - if (taskset->wkl_flag_wait_task == 0x81) { - // A workload flag is already pending so consume it - taskset->wkl_flag_wait_task = 0x80; - rc = 0; - } else if (taskset->wkl_flag_wait_task == 0x80) { - // No tasks are waiting for the workload flag. Mark this task as waiting for the workload flag. - taskset->wkl_flag_wait_task = ctxt->taskId; - running._bit[ctxt->taskId] = false; - waiting._bit[ctxt->taskId] = true; - rc = 1; - numNewlyReadyTasks--; - } else { - // Another task is already waiting for the workload signal - rc = CELL_SPURS_TASK_ERROR_BUSY; - } - break; - case SPURS_TASKSET_REQUEST_SELECT_TASK: - readyButNotRunning = ready & ~running; - if (taskset->wkl_flag_wait_task < CELL_SPURS_MAX_TASK) { - readyButNotRunning = readyButNotRunning & ~(v128::fromBit(taskset->wkl_flag_wait_task)); - } - - // Select a task from the readyButNotRunning set to run. Start from the task after the last scheduled task to ensure fairness. - for (selectedTaskId = taskset->last_scheduled_task + 1; selectedTaskId < 128; selectedTaskId++) { - if (readyButNotRunning._bit[selectedTaskId]) { - break; - } - } - - if (selectedTaskId == 128) { - for (selectedTaskId = 0; selectedTaskId < taskset->last_scheduled_task + 1; selectedTaskId++) { - if (readyButNotRunning._bit[selectedTaskId]) { - break; - } - } - - if (selectedTaskId == taskset->last_scheduled_task + 1) { - selectedTaskId = CELL_SPURS_MAX_TASK; - } - } - - *taskId = selectedTaskId; - *isWaiting = waiting._bit[selectedTaskId < CELL_SPURS_MAX_TASK ? selectedTaskId : 0] ? 1 : 0; - if (selectedTaskId != CELL_SPURS_MAX_TASK) { - taskset->last_scheduled_task = selectedTaskId; - running._bit[selectedTaskId] = true; - waiting._bit[selectedTaskId] = false; - } - break; - case SPURS_TASKSET_REQUEST_RECV_WKL_FLAG: - if (taskset->wkl_flag_wait_task < CELL_SPURS_MAX_TASK) { - // There is a task waiting for the workload flag - taskset->wkl_flag_wait_task = 0x80; - rc = 1; - numNewlyReadyTasks++; - } else { - // No tasks are waiting for the workload flag - taskset->wkl_flag_wait_task = 0x81; - rc = 0; - } - break; - default: - assert(!"Unknown taskset request"); - spursHalt(spu); - } - - taskset->pending_ready = _0; - taskset->running = running; - taskset->waiting = waiting; - taskset->enabled = enabled; - taskset->signalled = signalled; - taskset->ready = ready; - - std::memcpy(vm::base(spu.offset + 0x2700), taskset, 128); - }); - - // Increment the ready count of the workload by the number of tasks that have become ready - vm::reservation_op(VM_CAST(kernelCtxt->spurs.addr()), 128, [&]() { - auto spurs = kernelCtxt->spurs.get_ptr_priv(); - - s32 readyCount = kernelCtxt->wklCurrentId < CELL_SPURS_MAX_WORKLOAD ? spurs->wklReadyCount1[kernelCtxt->wklCurrentId].load() : spurs->wklIdleSpuCountOrReadyCount2[kernelCtxt->wklCurrentId & 0x0F].load(); - readyCount += numNewlyReadyTasks; - readyCount = readyCount < 0 ? 0 : readyCount > 0xFF ? 0xFF : readyCount; - - if (kernelCtxt->wklCurrentId < CELL_SPURS_MAX_WORKLOAD) { - spurs->wklReadyCount1[kernelCtxt->wklCurrentId] = readyCount; - } else { - spurs->wklIdleSpuCountOrReadyCount2[kernelCtxt->wklCurrentId & 0x0F] = readyCount; - } - - std::memcpy(vm::base(spu.offset + 0x100), spurs, 128); - }); - - return rc; -} - -/// Process pollStatus received from the SPURS kernel -void spursTasksetProcessPollStatus(SPUThread & spu, u32 pollStatus) { - if (pollStatus & CELL_SPURS_MODULE_POLL_STATUS_FLAG) { - spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_RECV_WKL_FLAG, nullptr, nullptr); - } -} - -/// Check execution rights -bool spursTasksetPollStatus(SPUThread & spu) { - u32 pollStatus; - - if (cellSpursModulePollStatus(spu, &pollStatus)) { - return true; - } - - spursTasksetProcessPollStatus(spu, pollStatus); - return false; -} - -/// Exit the Taskset PM -void spursTasksetExit(SPUThread & spu) { - auto ctxt = vm::_ptr(spu.offset + 0x2700); - - // Trace - STOP - CellSpursTracePacket pkt; - memset(&pkt, 0, sizeof(pkt)); - pkt.header.tag = 0x54; // Its not clear what this tag means exactly but it seems similar to CELL_SPURS_TRACE_TAG_STOP - pkt.data.stop = SPURS_GUID_TASKSET_PM; - cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); - - // Not sure why this check exists. Perhaps to check for memory corruption. - if (memcmp(ctxt->moduleId, "SPURSTASK MODULE", 16) != 0) { - //spursHalt(spu); - assert(!"spursTasksetExit(): memory corruption"); - } - - cellSpursModuleExit(spu); -} - -/// Invoked when a task exits -void spursTasksetOnTaskExit(SPUThread & spu, u64 addr, u32 taskId, s32 exitCode, u64 args) { - auto ctxt = vm::_ptr(spu.offset + 0x2700); - - std::memcpy(vm::base(spu.offset + 0x10000), vm::base(addr & -0x80), (addr & 0x7F) << 11); - - spu.gpr[3]._u64[1] = ctxt->taskset.addr(); - spu.gpr[4]._u32[3] = taskId; - spu.gpr[5]._u32[3] = exitCode; - spu.gpr[6]._u64[1] = args; - spu.fast_call(0x10000); -} - -/// Save the context of a task -s32 spursTasketSaveTaskContext(SPUThread & spu) { - auto ctxt = vm::_ptr(spu.offset + 0x2700); - auto taskInfo = vm::_ptr(spu.offset + 0x2780); - - //spursDmaWaitForCompletion(spu, 0xFFFFFFFF); - - if (taskInfo->context_save_storage_and_alloc_ls_blocks == 0) { - return CELL_SPURS_TASK_ERROR_STAT; - } - - u32 allocLsBlocks = taskInfo->context_save_storage_and_alloc_ls_blocks & 0x7F; - u32 lsBlocks = 0; - v128 ls_pattern = v128::from64r(taskInfo->ls_pattern._u64[0], taskInfo->ls_pattern._u64[1]); - for (auto i = 0; i < 128; i++) { - if (ls_pattern._bit[i]) { - lsBlocks++; - } - } - - if (lsBlocks > allocLsBlocks) { - return CELL_SPURS_TASK_ERROR_STAT; - } - - // Make sure the stack is area is specified in the ls pattern - for (auto i = (ctxt->savedContextSp.value()._u32[3]) >> 11; i < 128; i++) { - if (ls_pattern._bit[i] == false) { - return CELL_SPURS_TASK_ERROR_STAT; - } - } - - // Get the processor context - v128 r; - spu.fpscr.Read(r); - ctxt->savedContextFpscr = r; - ctxt->savedSpuWriteEventMask = spu.get_ch_value(SPU_RdEventMask); - ctxt->savedWriteTagGroupQueryMask = spu.get_ch_value(MFC_RdTagMask); - - // Store the processor context - const u32 contextSaveStorage = VM_CAST(taskInfo->context_save_storage_and_alloc_ls_blocks & -0x80); - std::memcpy(vm::base(contextSaveStorage), vm::base(spu.offset + 0x2C80), 0x380); - - // Save LS context - for (auto i = 6; i < 128; i++) { - if (ls_pattern._bit[i]) { - // TODO: Combine DMA requests for consecutive blocks into a single request - std::memcpy(vm::base(contextSaveStorage + 0x400 + ((i - 6) << 11)), vm::base(spu.offset + CELL_SPURS_TASK_TOP + ((i - 6) << 11)), 0x800); - } - } - - //spursDmaWaitForCompletion(spu, 1 << ctxt->dmaTagId); - return CELL_OK; -} - -/// Taskset dispatcher -void spursTasksetDispatch(SPUThread & spu) { - auto ctxt = vm::_ptr(spu.offset + 0x2700); - auto taskset = vm::_ptr(spu.offset + 0x2700); - - u32 taskId; - u32 isWaiting; - spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_SELECT_TASK, &taskId, &isWaiting); - if (taskId >= CELL_SPURS_MAX_TASK) { - spursTasksetExit(spu); - return; - } - - ctxt->taskId = taskId; - - // DMA in the task info for the selected task - std::memcpy(vm::base(spu.offset + 0x2780), &ctxt->taskset->task_info[taskId], sizeof(CellSpursTaskset::TaskInfo)); - auto taskInfo = vm::_ptr(spu.offset + 0x2780); - auto elfAddr = taskInfo->elf.addr().value(); - taskInfo->elf.set(taskInfo->elf.addr() & 0xFFFFFFFFFFFFFFF8); - - // Trace - Task: Incident=dispatch - CellSpursTracePacket pkt; - memset(&pkt, 0, sizeof(pkt)); - pkt.header.tag = CELL_SPURS_TRACE_TAG_TASK; - pkt.data.task.incident = CELL_SPURS_TRACE_TASK_DISPATCH; - pkt.data.task.taskId = taskId; - cellSpursModulePutTrace(&pkt, CELL_SPURS_KERNEL_DMA_TAG_ID); - - if (isWaiting == 0) { - // If we reach here it means that the task is being started and not being resumed - std::memset(vm::base(spu.offset + CELL_SPURS_TASK_TOP), 0, CELL_SPURS_TASK_BOTTOM - CELL_SPURS_TASK_TOP); - ctxt->guidAddr = CELL_SPURS_TASK_TOP; - - u32 entryPoint; - u32 lowestLoadAddr; - if (spursTasksetLoadElf(spu, &entryPoint, &lowestLoadAddr, taskInfo->elf.addr(), false) != CELL_OK) { - assert(!"spursTaskLoadElf() failed"); - spursHalt(spu); - } - - //spursDmaWaitForCompletion(spu, 1 << ctxt->dmaTagId); - - ctxt->savedContextLr = v128::from32r(entryPoint); - ctxt->guidAddr = lowestLoadAddr; - ctxt->tasksetMgmtAddr = 0x2700; - ctxt->x2FC0 = 0; - ctxt->taskExitCode = isWaiting; - ctxt->x2FD4 = elfAddr & 5; // TODO: Figure this out - - if ((elfAddr & 5) == 1) { - std::memcpy(vm::base(spu.offset + 0x2FC0), &((CellSpursTaskset2*)(ctxt->taskset.get_ptr()))->task_exit_code[taskId], 0x10); - } - - // Trace - GUID - memset(&pkt, 0, sizeof(pkt)); - pkt.header.tag = CELL_SPURS_TRACE_TAG_GUID; - pkt.data.guid = 0; // TODO: Put GUID of taskId here - cellSpursModulePutTrace(&pkt, 0x1F); - - if (elfAddr & 2) { // TODO: Figure this out - spu.status |= SPU_STATUS_STOPPED_BY_STOP; - spu.stop(); - return; - } - - spursTasksetStartTask(spu, taskInfo->args); - } else { - if (taskset->enable_clear_ls) { - std::memset(vm::base(spu.offset + CELL_SPURS_TASK_TOP), 0, CELL_SPURS_TASK_BOTTOM - CELL_SPURS_TASK_TOP); - } - - // If the entire LS is saved then there is no need to load the ELF as it will be be saved in the context save area as well - v128 ls_pattern = v128::from64r(taskInfo->ls_pattern._u64[0], taskInfo->ls_pattern._u64[1]); - if (ls_pattern != v128::from64r(0x03FFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull)) { - // Load the ELF - u32 entryPoint; - if (spursTasksetLoadElf(spu, &entryPoint, nullptr, taskInfo->elf.addr(), true) != CELL_OK) { - assert(!"spursTasksetLoadElf() failed"); - spursHalt(spu); - } - } - - // Load saved context from main memory to LS - const u32 contextSaveStorage = VM_CAST(taskInfo->context_save_storage_and_alloc_ls_blocks & -0x80); - std::memcpy(vm::base(spu.offset + 0x2C80), vm::base(contextSaveStorage), 0x380); - for (auto i = 6; i < 128; i++) { - if (ls_pattern._bit[i]) { - // TODO: Combine DMA requests for consecutive blocks into a single request - std::memcpy(vm::base(spu.offset + CELL_SPURS_TASK_TOP + ((i - 6) << 11)), vm::base(contextSaveStorage + 0x400 + ((i - 6) << 11)), 0x800); - } - } - - //spursDmaWaitForCompletion(spu, 1 << ctxt->dmaTagId); - - // Restore saved registers - spu.fpscr.Write(ctxt->savedContextFpscr.value()); - spu.set_ch_value(MFC_WrTagMask, ctxt->savedWriteTagGroupQueryMask); - spu.set_ch_value(SPU_WrEventMask, ctxt->savedSpuWriteEventMask); - - // Trace - GUID - memset(&pkt, 0, sizeof(pkt)); - pkt.header.tag = CELL_SPURS_TRACE_TAG_GUID; - pkt.data.guid = 0; // TODO: Put GUID of taskId here - cellSpursModulePutTrace(&pkt, 0x1F); - - if (elfAddr & 2) { // TODO: Figure this out - spu.status |= SPU_STATUS_STOPPED_BY_STOP; - spu.stop(); - return; - } - - spu.gpr[3].clear(); - spursTasksetResumeTask(spu); - } -} - -/// Process a syscall request -s32 spursTasksetProcessSyscall(SPUThread & spu, u32 syscallNum, u32 args) { - auto ctxt = vm::_ptr(spu.offset + 0x2700); - auto taskset = vm::_ptr(spu.offset + 0x2700); - - // If the 0x10 bit is set in syscallNum then its the 2nd version of the - // syscall (e.g. cellSpursYield2 instead of cellSpursYield) and so don't wait - // for DMA completion - if ((syscallNum & 0x10) == 0) { - //spursDmaWaitForCompletion(spu, 0xFFFFFFFF); - } - - s32 rc = 0; - u32 incident = 0; - switch (syscallNum & 0x0F) { - case CELL_SPURS_TASK_SYSCALL_EXIT: - if (ctxt->x2FD4 == 4 || (ctxt->x2FC0 & 0xFFFFFFFF) != 0) { // TODO: Figure this out - if (ctxt->x2FD4 != 4) { - spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_DESTROY_TASK, nullptr, nullptr); - } - - const u64 addr = ctxt->x2FD4 == 4 ? taskset->x78 : ctxt->x2FC0; - const u64 args = ctxt->x2FD4 == 4 ? 0 : ctxt->x2FC8.value(); - spursTasksetOnTaskExit(spu, addr, ctxt->taskId, ctxt->taskExitCode, args); - } - - incident = CELL_SPURS_TRACE_TASK_EXIT; - break; - case CELL_SPURS_TASK_SYSCALL_YIELD: - if (spursTasksetPollStatus(spu) || spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_POLL, nullptr, nullptr)) { - // If we reach here then it means that either another task can be scheduled or another workload can be scheduled - // Save the context of the current task - rc = spursTasketSaveTaskContext(spu); - if (rc == CELL_OK) { - spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_YIELD_TASK, nullptr, nullptr); - incident = CELL_SPURS_TRACE_TASK_YIELD; - } - } - break; - case CELL_SPURS_TASK_SYSCALL_WAIT_SIGNAL: - if (spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_POLL_SIGNAL, nullptr, nullptr) == 0) { - rc = spursTasketSaveTaskContext(spu); - if (rc == CELL_OK) { - if (spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_WAIT_SIGNAL, nullptr, nullptr) == 0) { - incident = CELL_SPURS_TRACE_TASK_WAIT; - } - } - } - break; - case CELL_SPURS_TASK_SYSCALL_POLL: - rc = spursTasksetPollStatus(spu) ? CELL_SPURS_TASK_POLL_FOUND_WORKLOAD : 0; - rc |= spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_POLL, nullptr, nullptr) ? CELL_SPURS_TASK_POLL_FOUND_TASK : 0; - break; - case CELL_SPURS_TASK_SYSCALL_RECV_WKL_FLAG: - if (args == 0) { // TODO: Figure this out - assert(!"args == 0"); - //spursHalt(spu); - } - - if (spursTasksetPollStatus(spu) || spursTasksetProcessRequest(spu, SPURS_TASKSET_REQUEST_WAIT_WKL_FLAG, nullptr, nullptr) != 1) { - rc = spursTasketSaveTaskContext(spu); - if (rc == CELL_OK) { - incident = CELL_SPURS_TRACE_TASK_WAIT; - } - } - break; - default: - rc = CELL_SPURS_TASK_ERROR_NOSYS; - break; - } - - if (incident) { - // Trace - TASK - CellSpursTracePacket pkt; - memset(&pkt, 0, sizeof(pkt)); - pkt.header.tag = CELL_SPURS_TRACE_TAG_TASK; - pkt.data.task.incident = incident; - pkt.data.task.taskId = ctxt->taskId; - cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); - - // Clear the GUID of the task - std::memset(vm::base(spu.offset + ctxt->guidAddr), 0, 0x10); - - if (spursTasksetPollStatus(spu)) { - spursTasksetExit(spu); - } else { - spursTasksetDispatch(spu); - } - } - - return rc; -} - -/// Initialise the Taskset PM -void spursTasksetInit(SPUThread & spu, u32 pollStatus) { - auto ctxt = vm::_ptr(spu.offset + 0x2700); - auto kernelCtxt = vm::_ptr(spu.offset + 0x100); - - kernelCtxt->moduleId[0] = 'T'; - kernelCtxt->moduleId[1] = 'K'; - - // Trace - START: Module='TKST' - CellSpursTracePacket pkt; - memset(&pkt, 0, sizeof(pkt)); - pkt.header.tag = 0x52; // Its not clear what this tag means exactly but it seems similar to CELL_SPURS_TRACE_TAG_START - memcpy(pkt.data.start.module, "TKST", 4); - pkt.data.start.level = 2; - pkt.data.start.ls = 0xA00 >> 2; - cellSpursModulePutTrace(&pkt, ctxt->dmaTagId); - - spursTasksetProcessPollStatus(spu, pollStatus); -} - -/// Load an ELF -s32 spursTasksetLoadElf(SPUThread & spu, u32 * entryPoint, u32 * lowestLoadAddr, u64 elfAddr, bool skipWriteableSegments) { - if (elfAddr == 0 || (elfAddr & 0x0F) != 0) { - return CELL_SPURS_TASK_ERROR_INVAL; - } - - vfsStreamMemory stream(VM_CAST(elfAddr)); - loader::handlers::elf32 loader; - auto rc = loader.init(stream); - if (rc != loader::handler::ok) { - return CELL_SPURS_TASK_ERROR_NOEXEC; - } - - u32 _lowestLoadAddr = CELL_SPURS_TASK_BOTTOM; - for (auto & phdr : loader.m_phdrs) { - if (phdr.data_be.p_paddr >= CELL_SPURS_TASK_BOTTOM) { - break; - } - - if (phdr.data_be.p_type == 1/*PT_LOAD*/) { - if (skipWriteableSegments == false || (phdr.data_be.p_flags & 2/*PF_W*/) == 0) { - if (phdr.data_be.p_vaddr < CELL_SPURS_TASK_TOP || - phdr.data_be.p_vaddr + phdr.data_be.p_memsz > CELL_SPURS_TASK_BOTTOM) { - return CELL_SPURS_TASK_ERROR_FAULT; - } - - _lowestLoadAddr > phdr.data_be.p_vaddr ? _lowestLoadAddr = phdr.data_be.p_vaddr : _lowestLoadAddr; - } - } - } - - loader.load_data(spu.offset, skipWriteableSegments); - *entryPoint = loader.m_ehdr.data_be.e_entry; - if (*lowestLoadAddr) { - *lowestLoadAddr = _lowestLoadAddr; - } - - return CELL_OK; -} diff --git a/rpcs3/Emu/SysCalls/Modules/cellVideoExport.cpp b/rpcs3/Emu/SysCalls/Modules/cellVideoExport.cpp deleted file mode 100644 index c70757f56f..0000000000 --- a/rpcs3/Emu/SysCalls/Modules/cellVideoExport.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" - -extern Module<> cellVideoExport; - -s32 cellVideoExportProgress() -{ - throw EXCEPTION(""); -} - -s32 cellVideoExportInitialize2() -{ - throw EXCEPTION(""); -} - -s32 cellVideoExportInitialize() -{ - throw EXCEPTION(""); -} - -s32 cellVideoExportFromFileWithCopy() -{ - throw EXCEPTION(""); -} - -s32 cellVideoExportFromFile() -{ - throw EXCEPTION(""); -} - -s32 cellVideoExportFinalize() -{ - throw EXCEPTION(""); -} - - -Module<> cellVideoExport("cellVideoExport", []() -{ - REG_FUNC(cellVideoExport, cellVideoExportProgress); - REG_FUNC(cellVideoExport, cellVideoExportInitialize2); - REG_FUNC(cellVideoExport, cellVideoExportInitialize); - REG_FUNC(cellVideoExport, cellVideoExportFromFileWithCopy); - REG_FUNC(cellVideoExport, cellVideoExportFromFile); - REG_FUNC(cellVideoExport, cellVideoExportFinalize); -}); diff --git a/rpcs3/Emu/SysCalls/Modules/cellVideoOut.cpp b/rpcs3/Emu/SysCalls/Modules/cellVideoOut.cpp deleted file mode 100644 index 4649a164b7..0000000000 --- a/rpcs3/Emu/SysCalls/Modules/cellVideoOut.cpp +++ /dev/null @@ -1,206 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/state.h" -#include "Emu/SysCalls/Modules.h" - -#include "Emu/RSX/GSManager.h" -#include "cellVideoOut.h" - -extern Module<> cellSysutil; - -s32 cellVideoOutGetState(u32 videoOut, u32 deviceIndex, vm::ptr state) -{ - cellSysutil.trace("cellVideoOutGetState(videoOut=%d, deviceIndex=%d, state=*0x%x)", videoOut, deviceIndex, state); - - if (deviceIndex) return CELL_VIDEO_OUT_ERROR_DEVICE_NOT_FOUND; - - switch (videoOut) - { - case CELL_VIDEO_OUT_PRIMARY: - state->state = Emu.GetGSManager().GetState(); - state->colorSpace = Emu.GetGSManager().GetColorSpace(); - state->displayMode.resolutionId = Emu.GetGSManager().GetInfo().mode.resolutionId; - state->displayMode.scanMode = Emu.GetGSManager().GetInfo().mode.scanMode; - state->displayMode.conversion = Emu.GetGSManager().GetInfo().mode.conversion; - state->displayMode.aspect = Emu.GetGSManager().GetInfo().mode.aspect; - state->displayMode.refreshRates = Emu.GetGSManager().GetInfo().mode.refreshRates; - return CELL_OK; - - case CELL_VIDEO_OUT_SECONDARY: - *state = { CELL_VIDEO_OUT_OUTPUT_STATE_DISABLED }; // ??? - return CELL_OK; - } - - return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; -} - -s32 cellVideoOutGetResolution(u32 resolutionId, vm::ptr resolution) -{ - cellSysutil.trace("cellVideoOutGetResolution(resolutionId=%d, resolution=*0x%x)", resolutionId, resolution); - - u32 num = ResolutionIdToNum(resolutionId); - if (!num) - return CELL_EINVAL; - - resolution->width = ResolutionTable[num].width; - resolution->height = ResolutionTable[num].height; - - return CELL_OK; -} - -s32 cellVideoOutConfigure(u32 videoOut, vm::ptr config, vm::ptr option, u32 waitForEvent) -{ - cellSysutil.warning("cellVideoOutConfigure(videoOut=%d, config=*0x%x, option=*0x%x, waitForEvent=%d)", videoOut, config, option, waitForEvent); - - switch (videoOut) - { - case CELL_VIDEO_OUT_PRIMARY: - if (config->resolutionId) - { - Emu.GetGSManager().GetInfo().mode.resolutionId = config->resolutionId; - } - - Emu.GetGSManager().GetInfo().mode.format = config->format; - - if (config->aspect) - { - Emu.GetGSManager().GetInfo().mode.aspect = config->aspect; - } - - if (config->pitch) - { - Emu.GetGSManager().GetInfo().mode.pitch = config->pitch; - } - - return CELL_OK; - - case CELL_VIDEO_OUT_SECONDARY: - return CELL_OK; - } - - return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; -} - -s32 cellVideoOutGetConfiguration(u32 videoOut, vm::ptr config, vm::ptr option) -{ - cellSysutil.warning("cellVideoOutGetConfiguration(videoOut=%d, config=*0x%x, option=*0x%x)", videoOut, config, option); - - if (option) *option = {}; - *config = {}; - - switch (videoOut) - { - case CELL_VIDEO_OUT_PRIMARY: - config->resolutionId = Emu.GetGSManager().GetInfo().mode.resolutionId; - config->format = Emu.GetGSManager().GetInfo().mode.format; - config->aspect = Emu.GetGSManager().GetInfo().mode.aspect; - config->pitch = Emu.GetGSManager().GetInfo().mode.pitch; - - return CELL_OK; - - case CELL_VIDEO_OUT_SECONDARY: - - return CELL_OK; - } - - return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; -} - -s32 cellVideoOutGetDeviceInfo(u32 videoOut, u32 deviceIndex, vm::ptr info) -{ - cellSysutil.warning("cellVideoOutGetDeviceInfo(videoOut=%d, deviceIndex=%d, info=*0x%x)", videoOut, deviceIndex, info); - - if (deviceIndex) return CELL_VIDEO_OUT_ERROR_DEVICE_NOT_FOUND; - - // Use standard dummy values for now. - info->portType = CELL_VIDEO_OUT_PORT_HDMI; - info->colorSpace = Emu.GetGSManager().GetColorSpace(); - info->latency = 1000; - info->availableModeCount = 1; - info->state = CELL_VIDEO_OUT_DEVICE_STATE_AVAILABLE; - info->rgbOutputRange = 1; - info->colorInfo.blueX = 0xFFFF; - info->colorInfo.blueY = 0xFFFF; - info->colorInfo.greenX = 0xFFFF; - info->colorInfo.greenY = 0xFFFF; - info->colorInfo.redX = 0xFFFF; - info->colorInfo.redY = 0xFFFF; - info->colorInfo.whiteX = 0xFFFF; - info->colorInfo.whiteY = 0xFFFF; - info->colorInfo.gamma = 100; - info->availableModes[0].aspect = 0; - info->availableModes[0].conversion = 0; - info->availableModes[0].refreshRates = 0xF; - info->availableModes[0].resolutionId = 1; - info->availableModes[0].scanMode = 0; - - return CELL_OK; -} - -s32 cellVideoOutGetNumberOfDevice(u32 videoOut) -{ - cellSysutil.warning("cellVideoOutGetNumberOfDevice(videoOut=%d)", videoOut); - - switch (videoOut) - { - case CELL_VIDEO_OUT_PRIMARY: return 1; - case CELL_VIDEO_OUT_SECONDARY: return 0; - } - - return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; -} - -s32 cellVideoOutGetResolutionAvailability(u32 videoOut, u32 resolutionId, u32 aspect, u32 option) -{ - cellSysutil.warning("cellVideoOutGetResolutionAvailability(videoOut=%d, resolutionId=0x%x, aspect=%d, option=%d)", videoOut, resolutionId, aspect, option); - - if (!rpcs3::config.rsx._3dtv.value() && (resolutionId == CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING || resolutionId == CELL_VIDEO_OUT_RESOLUTION_1024x720_3D_FRAME_PACKING || - resolutionId == CELL_VIDEO_OUT_RESOLUTION_960x720_3D_FRAME_PACKING || resolutionId == CELL_VIDEO_OUT_RESOLUTION_800x720_3D_FRAME_PACKING || - resolutionId == CELL_VIDEO_OUT_RESOLUTION_640x720_3D_FRAME_PACKING)) - return 0; - - switch (videoOut) - { - case CELL_VIDEO_OUT_PRIMARY: return 1; - case CELL_VIDEO_OUT_SECONDARY: return 0; - } - - return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; -} - -s32 cellVideoOutGetConvertCursorColorInfo() -{ - throw EXCEPTION(""); -} - -s32 cellVideoOutDebugSetMonitorType() -{ - throw EXCEPTION(""); -} - -s32 cellVideoOutRegisterCallback() -{ - throw EXCEPTION(""); -} - -s32 cellVideoOutUnregisterCallback() -{ - throw EXCEPTION(""); -} - - -void cellSysutil_VideoOut_init() -{ - REG_FUNC(cellSysutil, cellVideoOutGetState); - REG_FUNC(cellSysutil, cellVideoOutGetResolution); - REG_FUNC(cellSysutil, cellVideoOutConfigure); - REG_FUNC(cellSysutil, cellVideoOutGetConfiguration); - REG_FUNC(cellSysutil, cellVideoOutGetDeviceInfo); - REG_FUNC(cellSysutil, cellVideoOutGetNumberOfDevice); - REG_FUNC(cellSysutil, cellVideoOutGetResolutionAvailability); - REG_FUNC(cellSysutil, cellVideoOutGetConvertCursorColorInfo); - REG_FUNC(cellSysutil, cellVideoOutDebugSetMonitorType); - REG_FUNC(cellSysutil, cellVideoOutRegisterCallback); - REG_FUNC(cellSysutil, cellVideoOutUnregisterCallback); -} diff --git a/rpcs3/Emu/SysCalls/Modules/cellVideoOut.h b/rpcs3/Emu/SysCalls/Modules/cellVideoOut.h deleted file mode 100644 index 84541bbee6..0000000000 --- a/rpcs3/Emu/SysCalls/Modules/cellVideoOut.h +++ /dev/null @@ -1,282 +0,0 @@ -#pragma once - -// Video Out Error Codes -enum -{ - CELL_VIDEO_OUT_ERROR_NOT_IMPLEMENTED = 0x8002b220, - CELL_VIDEO_OUT_ERROR_ILLEGAL_CONFIGURATION = 0x8002b221, - CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER = 0x8002b222, - CELL_VIDEO_OUT_ERROR_PARAMETER_OUT_OF_RANGE = 0x8002b223, - CELL_VIDEO_OUT_ERROR_DEVICE_NOT_FOUND = 0x8002b224, - CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT = 0x8002b225, - CELL_VIDEO_OUT_ERROR_UNSUPPORTED_DISPLAY_MODE = 0x8002b226, - CELL_VIDEO_OUT_ERROR_CONDITION_BUSY = 0x8002b227, - CELL_VIDEO_OUT_ERROR_VALUE_IS_NOT_SET = 0x8002b228, -}; - -enum CellVideoOut -{ - CELL_VIDEO_OUT_PRIMARY = 0, - CELL_VIDEO_OUT_SECONDARY = 1, -}; - -enum CellVideoOutResolutionId -{ - CELL_VIDEO_OUT_RESOLUTION_UNDEFINED = 0, - CELL_VIDEO_OUT_RESOLUTION_1080 = 1, - CELL_VIDEO_OUT_RESOLUTION_720 = 2, - CELL_VIDEO_OUT_RESOLUTION_480 = 4, - CELL_VIDEO_OUT_RESOLUTION_576 = 5, - CELL_VIDEO_OUT_RESOLUTION_1600x1080 = 10, - CELL_VIDEO_OUT_RESOLUTION_1440x1080 = 11, - CELL_VIDEO_OUT_RESOLUTION_1280x1080 = 12, - CELL_VIDEO_OUT_RESOLUTION_960x1080 = 13, - CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING = 0x81, - CELL_VIDEO_OUT_RESOLUTION_1024x720_3D_FRAME_PACKING = 0x88, - CELL_VIDEO_OUT_RESOLUTION_960x720_3D_FRAME_PACKING = 0x89, - CELL_VIDEO_OUT_RESOLUTION_800x720_3D_FRAME_PACKING = 0x8a, - CELL_VIDEO_OUT_RESOLUTION_640x720_3D_FRAME_PACKING = 0x8b, - CELL_VIDEO_OUT_RESOLUTION_720_SIMULVIEW_FRAME_PACKING = 0x91, -}; - -enum CellVideoOutScanMode -{ - CELL_VIDEO_OUT_SCAN_MODE_INTERLACE, - CELL_VIDEO_OUT_SCAN_MODE_PROGRESSIVE, -}; - -enum CellVideoOutScanMode2 -{ - CELL_VIDEO_OUT_SCAN_MODE2_AUTO, - CELL_VIDEO_OUT_SCAN_MODE2_INTERLACE, - CELL_VIDEO_OUT_SCAN_MODE2_PROGRESSIVE, -}; - -enum CellVideoOutRefreshRate -{ - CELL_VIDEO_OUT_REFRESH_RATE_AUTO = 0x0000, - CELL_VIDEO_OUT_REFRESH_RATE_59_94HZ = 0x0001, - CELL_VIDEO_OUT_REFRESH_RATE_50HZ = 0x0002, - CELL_VIDEO_OUT_REFRESH_RATE_60HZ = 0x0004, - CELL_VIDEO_OUT_REFRESH_RATE_30HZ = 0x0008 -}; - -enum CellVideoOutPortType -{ - CELL_VIDEO_OUT_PORT_NONE = 0x00, - CELL_VIDEO_OUT_PORT_HDMI = 0x01, - CELL_VIDEO_OUT_PORT_NETWORK = 0x41, - CELL_VIDEO_OUT_PORT_COMPOSITE_S = 0x81, - CELL_VIDEO_OUT_PORT_D = 0x82, - CELL_VIDEO_OUT_PORT_COMPONENT = 0x83, - CELL_VIDEO_OUT_PORT_RGB = 0x84, - CELL_VIDEO_OUT_PORT_AVMULTI_SCART = 0x85, - CELL_VIDEO_OUT_PORT_DSUB = 0x86 -}; - -enum CellVideoOutDisplayAspect -{ - CELL_VIDEO_OUT_ASPECT_AUTO, - CELL_VIDEO_OUT_ASPECT_4_3, - CELL_VIDEO_OUT_ASPECT_16_9, -}; - -enum CellVideoOutBufferColorFormat -{ - CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8, - CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8B8G8R8, - CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT, -}; - -enum CellVideoOutOutputState -{ - CELL_VIDEO_OUT_OUTPUT_STATE_ENABLED, - CELL_VIDEO_OUT_OUTPUT_STATE_DISABLED, - CELL_VIDEO_OUT_OUTPUT_STATE_PREPARING, -}; - -enum CellVideoOutDeviceState -{ - CELL_VIDEO_OUT_DEVICE_STATE_UNAVAILABLE, - CELL_VIDEO_OUT_DEVICE_STATE_AVAILABLE, -}; - -enum CellVideoOutColorSpace -{ - CELL_VIDEO_OUT_COLOR_SPACE_RGB = 0x01, - CELL_VIDEO_OUT_COLOR_SPACE_YUV = 0x02, - CELL_VIDEO_OUT_COLOR_SPACE_XVYCC = 0x04, -}; - -enum CellVideoOutDebugMonitorType -{ - CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_UNDEFINED = 0, - CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_480I_59_94HZ = 1, - CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_576I_50HZ = 2, - CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_480P_59_94HZ = 3, - CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_576P_50HZ = 4, - CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_1080I_59_94HZ = 5, - CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_720P_59_94HZ = 7, - CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_1080P_59_94HZ = 9, - CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_WXGA_60HZ = 11, - CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_SXGA_60HZ = 12, - CELL_VIDEO_OUT_DEBUG_MONITOR_TYPE_WUXGA_60HZ = 13 -}; - -struct CellVideoOutColorInfo -{ - u16 redX; - u16 redY; - u16 greenX; - u16 greenY; - u16 blueX; - u16 blueY; - u16 whiteX; - u16 whiteY; - u32 gamma; -}; - -struct CellVideoOutKSVList -{ - u8 ksv[32*5]; - u8 reserved[4]; - u32 count; -}; - -enum CellVideoOutDisplayConversion -{ - CELL_VIDEO_OUT_DISPLAY_CONVERSION_NONE = 0x00, - CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_WXGA = 0x01, - CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_SXGA = 0x02, - CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_WUXGA = 0x03, - CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_1080 = 0x05, - CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_REMOTEPLAY = 0x10, - CELL_VIDEO_OUT_DISPLAY_CONVERSION_TO_720_3D_FRAME_PACKING = 0x80, -}; - -struct CellVideoOutDisplayMode -{ - u8 resolutionId; - u8 scanMode; - u8 conversion; - u8 aspect; - u8 reserved[2]; - be_t refreshRates; -}; - -struct CellVideoOutResolution -{ - be_t width; - be_t height; -}; - -struct CellVideoOutDeviceInfo -{ - u8 portType; - u8 colorSpace; - u16 latency; - u8 availableModeCount; - u8 state; - u8 rgbOutputRange; - u8 reserved[5]; - CellVideoOutColorInfo colorInfo; - CellVideoOutDisplayMode availableModes[32]; - CellVideoOutKSVList ksvList; -}; - -struct CellVideoOutState -{ - u8 state; - u8 colorSpace; - u8 reserved[6]; - CellVideoOutDisplayMode displayMode; -}; - -struct CellVideoOutConfiguration -{ - u8 resolutionId; - u8 format; - u8 aspect; - u8 reserved[9]; - be_t pitch; -}; - -struct CellVideoOutOption -{ - be_t reserved; -}; - -enum CellVideoOutEvent -{ - CELL_VIDEO_OUT_EVENT_DEVICE_CHANGED, - CELL_VIDEO_OUT_EVENT_OUTPUT_DISABLED, - CELL_VIDEO_OUT_EVENT_DEVICE_AUTHENTICATED, - CELL_VIDEO_OUT_EVENT_OUTPUT_ENABLED, -}; - -enum CellVideoOutCopyControl -{ - CELL_VIDEO_OUT_COPY_CONTROL_COPY_FREE, - CELL_VIDEO_OUT_COPY_CONTROL_COPY_ONCE, - CELL_VIDEO_OUT_COPY_CONTROL_COPY_NEVER, -}; - -enum CellVideoOutRGBOutputRange -{ - CELL_VIDEO_OUT_RGB_OUTPUT_RANGE_LIMITED, - CELL_VIDEO_OUT_RGB_OUTPUT_RANGE_FULL, -}; - -static const CellVideoOutResolution ResolutionTable[] = -{ - { 0xffff, 0xffff }, //0 - 0 - { 1920, 1080 }, //1 - 1 - { 1280, 720 }, //2 - 2 - { 720, 480 }, //4 - 3 - { 720, 576 }, //5 - 4 - { 1600, 1080 }, //10 - 5 - { 1440, 1080 }, //11 - 6 - { 1280, 1080 }, //12 - 7 - { 960, 1080 }, //13 - 8 -}; - -inline static u32 ResolutionIdToNum(u32 id) -{ - static const u32 res[] = - { - 0, //0 - 1, //1 - 2, //2 - 0, //3 - 3, //4 - 4, //5 - 0, //6 - 0, //7 - 0, //8 - 0, //9 - 5, //10 - 6, //11 - 7, //12 - 8, //13 - }; - - return id <= 13 ? res[id] : 0; -} - -inline static u32 ResolutionNumToId(u32 num) -{ - static const u32 res[] = - { - 0, //0 - 1, //1 - 2, //2 - 4, //3 - 5, //4 - 10, //5 - 11, //6 - 12, //7 - 13, //8 - }; - - return num <= 8 ? res[num] : 0; -} diff --git a/rpcs3/Emu/SysCalls/Modules/cellVideoUpload.cpp b/rpcs3/Emu/SysCalls/Modules/cellVideoUpload.cpp deleted file mode 100644 index a6d7c3862c..0000000000 --- a/rpcs3/Emu/SysCalls/Modules/cellVideoUpload.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules.h" - -extern Module<> cellVideoUpload; - -s32 cellVideoUploadInitialize() -{ - throw EXCEPTION(""); -} - -Module<> cellVideoUpload("cellVideoUpload", []() -{ - REG_FUNC(cellVideoUpload, cellVideoUploadInitialize); -}); From 42e1d4d7525a002c2898fe1b9aa3c52ff323fa3c Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Thu, 14 Apr 2016 01:23:53 +0300 Subject: [PATCH 06/19] Partial commit: Syscalls --- .../SysCalls.cpp => Cell/lv2/lv2.cpp} | 99 ++++++------ rpcs3/Emu/{SysCalls => Cell}/lv2/sys_cond.cpp | 30 ++-- rpcs3/Emu/{SysCalls => Cell}/lv2/sys_cond.h | 8 +- rpcs3/Emu/{SysCalls => Cell}/lv2/sys_dbg.cpp | 5 +- rpcs3/Emu/{SysCalls => Cell}/lv2/sys_dbg.h | 0 .../Emu/{SysCalls => Cell}/lv2/sys_event.cpp | 121 +++++++------- rpcs3/Emu/{SysCalls => Cell}/lv2/sys_event.h | 55 +++++-- .../{SysCalls => Cell}/lv2/sys_event_flag.cpp | 28 ++-- .../{SysCalls => Cell}/lv2/sys_event_flag.h | 10 +- rpcs3/Emu/{SysCalls => Cell}/lv2/sys_fs.cpp | 151 ++++++++---------- rpcs3/Emu/{SysCalls => Cell}/lv2/sys_fs.h | 56 +++---- .../{SysCalls => Cell}/lv2/sys_interrupt.cpp | 33 ++-- .../{SysCalls => Cell}/lv2/sys_interrupt.h | 17 +- .../Emu/{SysCalls => Cell}/lv2/sys_lwcond.cpp | 25 ++- rpcs3/Emu/{SysCalls => Cell}/lv2/sys_lwcond.h | 4 +- .../{SysCalls => Cell}/lv2/sys_lwmutex.cpp | 21 ++- .../Emu/{SysCalls => Cell}/lv2/sys_lwmutex.h | 12 +- .../Emu/{SysCalls => Cell}/lv2/sys_memory.cpp | 11 +- rpcs3/Emu/{SysCalls => Cell}/lv2/sys_memory.h | 13 +- .../{SysCalls => Cell}/lv2/sys_mmapper.cpp | 14 +- .../Emu/{SysCalls => Cell}/lv2/sys_mmapper.h | 14 +- .../Emu/{SysCalls => Cell}/lv2/sys_mutex.cpp | 26 ++- rpcs3/Emu/{SysCalls => Cell}/lv2/sys_mutex.h | 14 +- .../{SysCalls => Cell}/lv2/sys_ppu_thread.cpp | 41 +++-- .../{SysCalls => Cell}/lv2/sys_ppu_thread.h | 0 .../{SysCalls => Cell}/lv2/sys_process.cpp | 8 +- .../Emu/{SysCalls => Cell}/lv2/sys_process.h | 0 rpcs3/Emu/{SysCalls => Cell}/lv2/sys_prx.cpp | 130 ++------------- rpcs3/Emu/{SysCalls => Cell}/lv2/sys_prx.h | 106 +----------- rpcs3/Emu/{SysCalls => Cell}/lv2/sys_rsx.cpp | 5 +- rpcs3/Emu/{SysCalls => Cell}/lv2/sys_rsx.h | 0 .../Emu/{SysCalls => Cell}/lv2/sys_rwlock.cpp | 38 ++--- rpcs3/Emu/{SysCalls => Cell}/lv2/sys_rwlock.h | 14 +- .../{SysCalls => Cell}/lv2/sys_semaphore.cpp | 17 +- .../{SysCalls => Cell}/lv2/sys_semaphore.h | 8 +- rpcs3/Emu/{SysCalls => Cell}/lv2/sys_spu.cpp | 137 ++++++++-------- rpcs3/Emu/{SysCalls => Cell}/lv2/sys_spu.h | 39 ++--- rpcs3/Emu/Cell/lv2/sys_sync.h | 113 +++++++++++++ rpcs3/Emu/{SysCalls => Cell}/lv2/sys_time.cpp | 5 +- rpcs3/Emu/{SysCalls => Cell}/lv2/sys_time.h | 0 .../Emu/{SysCalls => Cell}/lv2/sys_timer.cpp | 17 +- rpcs3/Emu/{SysCalls => Cell}/lv2/sys_timer.h | 33 ++-- .../Emu/{SysCalls => Cell}/lv2/sys_trace.cpp | 5 +- rpcs3/Emu/{SysCalls => Cell}/lv2/sys_trace.h | 0 rpcs3/Emu/{SysCalls => Cell}/lv2/sys_tty.cpp | 5 +- rpcs3/Emu/{SysCalls => Cell}/lv2/sys_tty.h | 0 rpcs3/Emu/{SysCalls => Cell}/lv2/sys_vm.cpp | 5 +- rpcs3/Emu/{SysCalls => Cell}/lv2/sys_vm.h | 2 +- rpcs3/Emu/SysCalls/SysCalls.h | 14 -- rpcs3/Emu/SysCalls/lv2/sys_sync.h | 42 ----- 50 files changed, 677 insertions(+), 874 deletions(-) rename rpcs3/Emu/{SysCalls/SysCalls.cpp => Cell/lv2/lv2.cpp} (97%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_cond.cpp (87%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_cond.h (81%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_dbg.cpp (59%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_dbg.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_event.cpp (72%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_event.h (65%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_event_flag.cpp (92%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_event_flag.h (93%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_fs.cpp (76%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_fs.h (87%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_interrupt.cpp (85%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_interrupt.h (65%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_lwcond.cpp (88%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_lwcond.h (84%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_lwmutex.cpp (88%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_lwmutex.h (86%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_memory.cpp (97%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_memory.h (92%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_mmapper.cpp (96%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_mmapper.h (86%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_mutex.cpp (88%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_mutex.h (72%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_ppu_thread.cpp (90%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_ppu_thread.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_process.cpp (97%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_process.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_prx.cpp (62%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_prx.h (69%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_rsx.cpp (98%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_rsx.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_rwlock.cpp (87%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_rwlock.h (70%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_semaphore.cpp (92%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_semaphore.h (87%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_spu.cpp (91%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_spu.h (86%) create mode 100644 rpcs3/Emu/Cell/lv2/sys_sync.h rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_time.cpp (97%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_time.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_timer.cpp (94%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_timer.h (63%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_trace.cpp (91%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_trace.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_tty.cpp (89%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_tty.h (100%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_vm.cpp (96%) rename rpcs3/Emu/{SysCalls => Cell}/lv2/sys_vm.h (97%) delete mode 100644 rpcs3/Emu/SysCalls/SysCalls.h delete mode 100644 rpcs3/Emu/SysCalls/lv2/sys_sync.h diff --git a/rpcs3/Emu/SysCalls/SysCalls.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/SysCalls.cpp rename to rpcs3/Emu/Cell/lv2/lv2.cpp index bb3ebdde99..771302c551 100644 --- a/rpcs3/Emu/SysCalls/SysCalls.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -1,42 +1,39 @@ #include "stdafx.h" #include "Utilities/AutoPause.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" -#include "Modules.h" -#include "lv2/sys_lwmutex.h" -#include "lv2/sys_lwcond.h" -#include "lv2/sys_mutex.h" -#include "lv2/sys_cond.h" -#include "lv2/sys_event.h" -#include "lv2/sys_event_flag.h" -#include "lv2/sys_interrupt.h" -#include "lv2/sys_memory.h" -#include "lv2/sys_mmapper.h" -#include "lv2/sys_ppu_thread.h" -#include "lv2/sys_process.h" -#include "lv2/sys_prx.h" -#include "lv2/sys_rsx.h" -#include "lv2/sys_rwlock.h" -#include "lv2/sys_semaphore.h" -#include "lv2/sys_spu.h" -#include "lv2/sys_time.h" -#include "lv2/sys_timer.h" -#include "lv2/sys_trace.h" -#include "lv2/sys_tty.h" -#include "lv2/sys_vm.h" -#include "lv2/sys_fs.h" -#include "lv2/sys_dbg.h" +#include "Emu/Cell/PPUFunction.h" +#include "Emu/Cell/ErrorCodes.h" +#include "sys_sync.h" +#include "sys_lwmutex.h" +#include "sys_lwcond.h" +#include "sys_mutex.h" +#include "sys_cond.h" +#include "sys_event.h" +#include "sys_event_flag.h" +#include "sys_interrupt.h" +#include "sys_memory.h" +#include "sys_mmapper.h" +#include "sys_ppu_thread.h" +#include "sys_process.h" +#include "sys_prx.h" +#include "sys_rsx.h" +#include "sys_rwlock.h" +#include "sys_semaphore.h" +#include "sys_spu.h" +#include "sys_time.h" +#include "sys_timer.h" +#include "sys_trace.h" +#include "sys_tty.h" +#include "sys_vm.h" +#include "sys_fs.h" +#include "sys_dbg.h" -#include "Emu/SysCalls/Modules/cellGcmSys.h" +extern std::string ppu_get_syscall_name(u64 code); -#include "SysCalls.h" - -void null_func(PPUThread& ppu) +static void null_func(PPUThread& ppu) { - const u64 code = ppu.GPR[11]; - LOG_TODO(HLE, "Unimplemented syscall %lld: %s -> CELL_OK", code, get_ps3_function_name(~code)); + LOG_TODO(HLE, "Unimplemented syscall %s -> CELL_OK", ppu_get_syscall_name(ppu.GPR[11])); ppu.GPR[3] = 0; } @@ -45,7 +42,7 @@ void null_func(PPUThread& ppu) // DBG = Debug // PM = Product Mode // AuthID = Authentication ID -const ppu_func_caller g_sc_table[1024] = +std::array g_ppu_syscall_table { null_func, BIND_FUNC(sys_process_getpid), //1 (0x001) @@ -887,24 +884,34 @@ const ppu_func_caller g_sc_table[1024] = null_func, null_func, null_func, null_func, null_func, //1009 UNS null_func, null_func, null_func, null_func, null_func, //1014 UNS null_func, null_func, null_func, null_func, null_func, //1019 UNS - null_func, null_func, null_func, BIND_FUNC(cellGcmCallback), //1023 UNS + null_func, null_func, null_func, null_func, //1023 UNS }; -void execute_syscall_by_index(PPUThread& ppu, u64 code) +extern void ppu_execute_syscall(PPUThread& ppu, u64 code) { - if (code >= 1024) + if (code >= g_ppu_syscall_table.size()) { - throw EXCEPTION("Invalid syscall number (0x%llx)", code); + throw fmt::exception("Invalid syscall number (%llu)", code); } + + // If autopause occures, check_status() will hold the thread till unpaused. + if (debug::autopause::pause_syscall(code) && ppu.check_status()) throw cpu_state::ret; + + const auto previous_function = ppu.last_function; // TODO: use gsl::finally or something - auto last_code = ppu.hle_code; - ppu.hle_code = ~code; + try + { + g_ppu_syscall_table[code](ppu); + } + catch (...) + { + LOG_WARNING(PPU, "Syscall '%s' (%llu) aborted", ppu_get_syscall_name(code), code); + ppu.last_function = previous_function; + throw; + } - LOG_TRACE(PPU, "Syscall %lld called: %s", code, get_ps3_function_name(~code)); - - g_sc_table[code](ppu); - - LOG_TRACE(PPU, "Syscall %lld finished: %s -> 0x%llx", code, get_ps3_function_name(~code), ppu.GPR[3]); - - ppu.hle_code = last_code; + LOG_TRACE(PPU, "Syscall '%s' (%llu) finished, r3=0x%llx", ppu_get_syscall_name(code), code, ppu.GPR[3]); + ppu.last_function = previous_function; } + +lv2_lock_t::type::mutex_type lv2_lock_t::mutex; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp b/rpcs3/Emu/Cell/lv2/sys_cond.cpp similarity index 87% rename from rpcs3/Emu/SysCalls/lv2/sys_cond.cpp rename to rpcs3/Emu/Cell/lv2/sys_cond.cpp index ceda3643e2..845a3ec097 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_cond.cpp @@ -1,22 +1,20 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" -#include "sys_sync.h" #include "sys_mutex.h" #include "sys_cond.h" -SysCallBase sys_cond("sys_cond"); +LOG_CHANNEL(sys_cond); extern u64 get_system_time(); -void lv2_cond_t::notify(lv2_lock_t& lv2_lock, sleep_queue_t::value_type& thread) +void lv2_cond_t::notify(lv2_lock_t, cpu_thread* thread) { - CHECK_LV2_LOCK(lv2_lock); - if (mutex->owner) { // add thread to the mutex sleep queue if cannot lock immediately @@ -24,12 +22,10 @@ void lv2_cond_t::notify(lv2_lock_t& lv2_lock, sleep_queue_t::value_type& thread) } else { - mutex->owner = thread; + mutex->owner = std::static_pointer_cast(thread->shared_from_this()); - if (!thread->signal()) - { - throw EXCEPTION("Thread already signaled"); - } + ASSERT(!thread->state.test_and_set(cpu_state::signal)); + thread->cv.notify_one(); } } @@ -150,9 +146,9 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id) return CELL_ESRCH; } - const auto found = std::find_if(cond->sq.begin(), cond->sq.end(), [=](sleep_queue_t::value_type& thread) + const auto found = std::find_if(cond->sq.begin(), cond->sq.end(), [=](cpu_thread* thread) { - return thread->get_id() == thread_id; + return thread->id == thread_id; }); // TODO: check if CELL_ESRCH is returned if thread_id is invalid @@ -196,12 +192,12 @@ s32 sys_cond_wait(PPUThread& ppu, u32 cond_id, u64 timeout) cond->mutex->unlock(lv2_lock); // add waiter; protocol is ignored in current implementation - sleep_queue_entry_t waiter(ppu, cond->sq); + sleep_entry waiter(cond->sq, ppu); // potential mutex waiter (not added immediately) - sleep_queue_entry_t mutex_waiter(ppu, cond->mutex->sq, defer_sleep); + sleep_entry mutex_waiter(cond->mutex->sq, ppu, defer_sleep); - while (!ppu.unsignal()) + while (!ppu.state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; @@ -215,7 +211,7 @@ s32 sys_cond_wait(PPUThread& ppu, u32 cond_id, u64 timeout) // try to reown mutex and exit if timed out if (!cond->mutex->owner) { - cond->mutex->owner = std::static_pointer_cast(ppu.shared_from_this()); + cond->mutex->owner = std::static_pointer_cast(ppu.shared_from_this()); break; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_cond.h b/rpcs3/Emu/Cell/lv2/sys_cond.h similarity index 81% rename from rpcs3/Emu/SysCalls/lv2/sys_cond.h rename to rpcs3/Emu/Cell/lv2/sys_cond.h index 2b0583cd1e..24b4012c7c 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_cond.h +++ b/rpcs3/Emu/Cell/lv2/sys_cond.h @@ -1,8 +1,6 @@ #pragma once -#include "Utilities/SleepQueue.h" - -namespace vm { using namespace ps3; } +#include "sys_sync.h" struct lv2_mutex_t; @@ -24,7 +22,7 @@ struct lv2_cond_t const u64 name; const std::shared_ptr mutex; // associated mutex - sleep_queue_t sq; + sleep_queue sq; lv2_cond_t(const std::shared_ptr& mutex, u64 name) : mutex(mutex) @@ -32,7 +30,7 @@ struct lv2_cond_t { } - void notify(lv2_lock_t& lv2_lock, sleep_queue_t::value_type& thread); + void notify(lv2_lock_t, cpu_thread* thread); }; class PPUThread; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_dbg.cpp b/rpcs3/Emu/Cell/lv2/sys_dbg.cpp similarity index 59% rename from rpcs3/Emu/SysCalls/lv2/sys_dbg.cpp rename to rpcs3/Emu/Cell/lv2/sys_dbg.cpp index bfa9445bb0..3890fc906f 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_dbg.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_dbg.cpp @@ -1,9 +1,10 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_dbg.h" -SysCallBase sys_dbg("sys_dbg"); +LOG_CHANNEL(sys_dbg); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_dbg.h b/rpcs3/Emu/Cell/lv2/sys_dbg.h similarity index 100% rename from rpcs3/Emu/SysCalls/lv2/sys_dbg.h rename to rpcs3/Emu/Cell/lv2/sys_dbg.h diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event.cpp b/rpcs3/Emu/Cell/lv2/sys_event.cpp similarity index 72% rename from rpcs3/Emu/SysCalls/lv2/sys_event.cpp rename to rpcs3/Emu/Cell/lv2/sys_event.cpp index a0cdd9b182..81a71bdc5d 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_event.cpp @@ -1,49 +1,65 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" #include "Emu/Cell/SPUThread.h" -#include "Emu/Event.h" -#include "sys_sync.h" #include "sys_process.h" #include "sys_event.h" -SysCallBase sys_event("sys_event"); +LOG_CHANNEL(sys_event); extern u64 get_system_time(); -lv2_event_queue_t::lv2_event_queue_t(u32 protocol, s32 type, u64 name, u64 key, s32 size) - : id(idm::get_last_id()) - , protocol(protocol) - , type(type) - , name(name) - , key(key) - , size(size) +static ipc_manager& get_ipc_manager() { + // Use magic static + static ipc_manager instance; + return instance; } -void lv2_event_queue_t::push(lv2_lock_t& lv2_lock, u64 source, u64 data1, u64 data2, u64 data3) +std::shared_ptr lv2_event_queue_t::make(u32 protocol, s32 type, u64 name, u64 ipc_key, s32 size) { - CHECK_LV2_LOCK(lv2_lock); + auto make_expr = WRAP_EXPR(idm::import(WRAP_EXPR(std::make_shared(protocol, type, name, ipc_key, size)))); - // save event if no waiters - if (sq.empty()) + if (ipc_key == SYS_EVENT_QUEUE_LOCAL) { - return events.emplace_back(source, data1, data2, data3); + // Not an IPC queue + return make_expr(); } - if (events.size()) + // IPC queue + return get_ipc_manager().add(ipc_key, make_expr); +} + +std::shared_ptr lv2_event_queue_t::find(u64 ipc_key) +{ + if (ipc_key == SYS_EVENT_QUEUE_LOCAL) { - throw EXCEPTION("Unexpected"); + // Invalid IPC key + return{}; + } + + return get_ipc_manager().get(ipc_key); +} + +void lv2_event_queue_t::push(lv2_lock_t, u64 source, u64 data1, u64 data2, u64 data3) +{ + Expects(m_sq.empty() || m_events.empty()); + + // save event if no waiters + if (m_sq.empty()) + { + return m_events.emplace_back(source, data1, data2, data3); } // notify waiter; protocol is ignored in current implementation - auto& thread = sq.front(); + auto& thread = m_sq.front(); - if (type == SYS_PPU_QUEUE && thread->get_type() == CPU_THREAD_PPU) + if (type == SYS_PPU_QUEUE && thread->type == cpu_type::ppu) { // store event data in registers auto& ppu = static_cast(*thread); @@ -53,7 +69,7 @@ void lv2_event_queue_t::push(lv2_lock_t& lv2_lock, u64 source, u64 data1, u64 da ppu.GPR[6] = data2; ppu.GPR[7] = data3; } - else if (type == SYS_SPU_QUEUE && thread->get_type() == CPU_THREAD_SPU) + else if (type == SYS_SPU_QUEUE && thread->type == cpu_type::spu) { // store event data in In_MBox auto& spu = static_cast(*thread); @@ -62,15 +78,21 @@ void lv2_event_queue_t::push(lv2_lock_t& lv2_lock, u64 source, u64 data1, u64 da } else { - throw EXCEPTION("Unexpected (queue_type=%d, thread_type=%d)", type, thread->get_type()); + throw fmt::exception("Unexpected (queue.type=%d, thread.type=%d)" HERE, type, thread->type); } - if (!sq.front()->signal()) - { - throw EXCEPTION("Thread already signaled"); - } + ASSERT(!thread->state.test_and_set(cpu_state::signal)); + thread->cv.notify_one(); - return sq.pop_front(); + return m_sq.pop_front(); +} + +lv2_event_queue_t::event_type lv2_event_queue_t::pop(lv2_lock_t) +{ + Expects(m_events.size()); + auto result = m_events.front(); + m_events.pop_front(); + return result; } s32 sys_event_queue_create(vm::ptr equeue_id, vm::ptr attr, u64 event_queue_key, s32 size) @@ -98,7 +120,7 @@ s32 sys_event_queue_create(vm::ptr equeue_id, vm::ptr(attr->name), event_queue_key, size); + const auto queue = lv2_event_queue_t::make(protocol, type, reinterpret_cast(attr->name), event_queue_key, size); if (!queue) { @@ -128,32 +150,32 @@ s32 sys_event_queue_destroy(u32 equeue_id, s32 mode) return CELL_EINVAL; } - if (!mode && queue->sq.size()) + if (!mode && queue->waiters()) { return CELL_EBUSY; } // cleanup - Emu.GetEventManager().UnregisterKey(queue->key); idm::remove(equeue_id); // signal all threads to return CELL_ECANCELED - for (auto& thread : queue->sq) + for (auto& thread : queue->thread_queue(lv2_lock)) { - if (queue->type == SYS_PPU_QUEUE && thread->get_type() == CPU_THREAD_PPU) + if (queue->type == SYS_PPU_QUEUE && thread->type == cpu_type::ppu) { static_cast(*thread).GPR[3] = 1; } - else if (queue->type == SYS_SPU_QUEUE && thread->get_type() == CPU_THREAD_SPU) + else if (queue->type == SYS_SPU_QUEUE && thread->type == cpu_type::spu) { static_cast(*thread).ch_in_mbox.set_values(1, CELL_ECANCELED); } else { - throw EXCEPTION("Unexpected (queue_type=%d, thread_type=%d)", queue->type, thread->get_type()); + throw fmt::exception("Unexpected (queue.type=%d, thread.type=%d)" HERE, queue->type, thread->type); } - thread->signal(); + thread->state += cpu_state::signal; + thread->cv.notify_one(); } return CELL_OK; @@ -174,7 +196,7 @@ s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr event_array, if (size < 0) { - throw EXCEPTION("Negative size"); + throw fmt::exception("Negative size (%d)" HERE, size); } if (queue->type != SYS_PPU_QUEUE) @@ -184,13 +206,11 @@ s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr event_array, s32 count = 0; - while (queue->sq.empty() && count < size && queue->events.size()) + while (queue->waiters() == 0 && count < size && queue->events()) { auto& dest = event_array[count++]; - std::tie(dest.source, dest.data1, dest.data2, dest.data3) = queue->events.front(); - - queue->events.pop_front(); + std::tie(dest.source, dest.data1, dest.data2, dest.data3) = queue->pop(lv2_lock); } *number = count; @@ -218,13 +238,10 @@ s32 sys_event_queue_receive(PPUThread& ppu, u32 equeue_id, vm::ptr return CELL_EINVAL; } - if (queue->events.size()) + if (queue->events()) { // event data is returned in registers (dummy_event is not used) - std::tie(ppu.GPR[4], ppu.GPR[5], ppu.GPR[6], ppu.GPR[7]) = queue->events.front(); - - queue->events.pop_front(); - + std::tie(ppu.GPR[4], ppu.GPR[5], ppu.GPR[6], ppu.GPR[7]) = queue->pop(lv2_lock); return CELL_OK; } @@ -232,9 +249,9 @@ s32 sys_event_queue_receive(PPUThread& ppu, u32 equeue_id, vm::ptr ppu.GPR[3] = 0; // add waiter; protocol is ignored in current implementation - sleep_queue_entry_t waiter(ppu, queue->sq); + sleep_entry waiter(queue->thread_queue(lv2_lock), ppu); - while (!ppu.unsignal()) + while (!ppu.state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; @@ -257,11 +274,7 @@ s32 sys_event_queue_receive(PPUThread& ppu, u32 equeue_id, vm::ptr if (ppu.GPR[3]) { - if (idm::check(equeue_id)) - { - throw EXCEPTION("Unexpected"); - } - + Ensures(!idm::check(equeue_id)); return CELL_ECANCELED; } @@ -282,7 +295,7 @@ s32 sys_event_queue_drain(u32 equeue_id) return CELL_ESRCH; } - queue->events.clear(); + queue->clear(lv2_lock); return CELL_OK; } @@ -401,7 +414,7 @@ s32 sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3) return CELL_ENOTCONN; } - if (queue->events.size() >= queue->size) + if (queue->events() >= queue->size) { return CELL_EBUSY; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event.h b/rpcs3/Emu/Cell/lv2/sys_event.h similarity index 65% rename from rpcs3/Emu/SysCalls/lv2/sys_event.h rename to rpcs3/Emu/Cell/lv2/sys_event.h index 5326e6cff8..e1c088870c 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event.h +++ b/rpcs3/Emu/Cell/lv2/sys_event.h @@ -1,8 +1,6 @@ #pragma once -#include "Utilities/SleepQueue.h" - -namespace vm { using namespace ps3; } +#include "sys_sync.h" // Event Queue Type enum : u32 @@ -65,23 +63,58 @@ struct sys_event_t be_t data3; }; -struct lv2_event_queue_t +class lv2_event_queue_t final { - const u32 id; + // Tuple elements: source, data1, data2, data3 + using event_type = std::tuple; + + std::deque m_events; + + sleep_queue m_sq; + +public: + // Try to make an event queue with specified global key + static std::shared_ptr make(u32 protocol, s32 type, u64 name, u64 ipc_key, s32 size); + + // Get event queue by its global key + static std::shared_ptr find(u64 ipc_key); + const u32 protocol; const s32 type; const u64 name; - const u64 key; + const u64 ipc_key; const s32 size; + const u32 id{}; - // tuple elements: source, data1, data2, data3 - std::deque> events; + lv2_event_queue_t(u32 protocol, s32 type, u64 name, u64 ipc_key, s32 size) + : protocol(protocol) + , type(type) + , name(name) + , ipc_key(ipc_key) + , size(size) + { + } - sleep_queue_t sq; + // Send an event + void push(lv2_lock_t, u64 source, u64 data1, u64 data2, u64 data3); - lv2_event_queue_t(u32 protocol, s32 type, u64 name, u64 key, s32 size); + // Receive an event (queue shouldn't be empty) + event_type pop(lv2_lock_t); - void push(lv2_lock_t& lv2_lock, u64 source, u64 data1, u64 data2, u64 data3); + // Remove all events + void clear(lv2_lock_t) + { + m_events.clear(); + } + + // Get event count + std::size_t events() const { return m_events.size(); } + + // Get waiter count + std::size_t waiters() const { return m_sq.size(); } + + // Get threads (TODO) + auto& thread_queue(lv2_lock_t) { return m_sq; } }; struct lv2_event_port_t diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp b/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp similarity index 92% rename from rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp rename to rpcs3/Emu/Cell/lv2/sys_event_flag.cpp index da3b58edc2..443cc55de3 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp @@ -1,22 +1,20 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" -#include "sys_sync.h" #include "sys_event_flag.h" -SysCallBase sys_event_flag("sys_event_flag"); +LOG_CHANNEL(sys_event_flag); extern u64 get_system_time(); -void lv2_event_flag_t::notify_all(lv2_lock_t& lv2_lock) +void lv2_event_flag_t::notify_all(lv2_lock_t) { - CHECK_LV2_LOCK(lv2_lock); - - auto pred = [this](sleep_queue_t::value_type& thread) -> bool + auto pred = [this](cpu_thread* thread) -> bool { auto& ppu = static_cast(*thread); @@ -30,10 +28,8 @@ void lv2_event_flag_t::notify_all(lv2_lock_t& lv2_lock) // save pattern ppu.GPR[4] = clear_pattern(bitptn, mode); - if (!ppu.signal()) - { - throw EXCEPTION("Thread already signaled"); - } + ASSERT(!thread->state.test_and_set(cpu_state::signal)); + thread->cv.notify_one(); return true; } @@ -147,9 +143,9 @@ s32 sys_event_flag_wait(PPUThread& ppu, u32 id, u64 bitptn, u32 mode, vm::ptrsq); + sleep_entry waiter(eflag->sq, ppu); - while (!ppu.unsignal()) + while (!ppu.state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; @@ -295,10 +291,8 @@ s32 sys_event_flag_cancel(u32 id, vm::ptr num) // clear "mode" as a sign of cancellation ppu.GPR[5] = 0; - if (!thread->signal()) - { - throw EXCEPTION("Thread already signaled"); - } + ASSERT(!thread->state.test_and_set(cpu_state::signal)); + thread->cv.notify_one(); } eflag->sq.clear(); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h b/rpcs3/Emu/Cell/lv2/sys_event_flag.h similarity index 93% rename from rpcs3/Emu/SysCalls/lv2/sys_event_flag.h rename to rpcs3/Emu/Cell/lv2/sys_event_flag.h index 35da424583..31b27947c5 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h +++ b/rpcs3/Emu/Cell/lv2/sys_event_flag.h @@ -1,8 +1,6 @@ #pragma once -#include "Utilities/SleepQueue.h" - -namespace vm { using namespace ps3; } +#include "sys_sync.h" enum { @@ -37,9 +35,9 @@ struct lv2_event_flag_t const s32 type; const u64 name; - std::atomic pattern; + atomic_t pattern; - sleep_queue_t sq; + sleep_queue sq; lv2_event_flag_t(u64 pattern, u32 protocol, s32 type, u64 name) : pattern(pattern) @@ -105,7 +103,7 @@ struct lv2_event_flag_t } } - void notify_all(lv2_lock_t& lv2_lock); + void notify_all(lv2_lock_t); }; // Aux diff --git a/rpcs3/Emu/SysCalls/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp similarity index 76% rename from rpcs3/Emu/SysCalls/lv2/sys_fs.cpp rename to rpcs3/Emu/Cell/lv2/sys_fs.cpp index 9b2fef1ae0..f9dc481f4b 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -1,17 +1,13 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" - -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFile.h" -#include "Emu/FS/vfsLocalFile.h" -#include "Emu/FS/vfsDir.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_fs.h" -SysCallBase sys_fs("sys_fs"); +LOG_CHANNEL(sys_fs); s32 sys_fs_test(u32 arg1, u32 arg2, vm::ptr arg3, u32 arg4, vm::ptr arg5, u32 arg6) { @@ -31,11 +27,8 @@ s32 sys_fs_open(vm::cptr path, s32 flags, vm::ptr fd, s32 mode, vm::c return CELL_FS_EINVAL; } - std::string local_path; - - const auto device = Emu.GetVFS().GetDevice(path.get_ptr(), local_path); - - if (!device) + const std::string& local_path = vfs::get(path.get_ptr()); + if (local_path.empty()) { sys_fs.error("sys_fs_open('%s') failed: device not mounted", path.get_ptr()); return CELL_FS_ENOTMOUNTED; @@ -49,50 +42,50 @@ s32 sys_fs_open(vm::cptr path, s32 flags, vm::ptr fd, s32 mode, vm::c return CELL_FS_EISDIR; } - u32 open_mode = 0; + mset open_mode{}; switch (flags & CELL_FS_O_ACCMODE) { - case CELL_FS_O_RDONLY: open_mode |= fom::read; break; - case CELL_FS_O_WRONLY: open_mode |= fom::write; break; - case CELL_FS_O_RDWR: open_mode |= fom::read | fom::write; break; + case CELL_FS_O_RDONLY: open_mode += fs::read; break; + case CELL_FS_O_WRONLY: open_mode += fs::write; break; + case CELL_FS_O_RDWR: open_mode += fs::read + fs::write; break; } if (flags & CELL_FS_O_CREAT) { - open_mode |= fom::create; + open_mode += fs::create; } if (flags & CELL_FS_O_TRUNC) { - open_mode |= fom::trunc; + open_mode += fs::trunc; } if (flags & CELL_FS_O_APPEND) { - open_mode |= fom::append; + open_mode += fs::append; } if (flags & CELL_FS_O_EXCL) { if (flags & CELL_FS_O_CREAT) { - open_mode |= fom::excl; + open_mode += fs::excl; } else { - open_mode = 0; // error + open_mode = {}; // error } } if (flags & ~(CELL_FS_O_ACCMODE | CELL_FS_O_CREAT | CELL_FS_O_TRUNC | CELL_FS_O_APPEND | CELL_FS_O_EXCL)) { - open_mode = 0; // error + open_mode = {}; // error } if ((flags & CELL_FS_O_ACCMODE) == CELL_FS_O_ACCMODE) { - open_mode = 0; // error + open_mode = {}; // error } if (!open_mode) @@ -100,13 +93,13 @@ s32 sys_fs_open(vm::cptr path, s32 flags, vm::ptr fd, s32 mode, vm::c throw EXCEPTION("Invalid or unimplemented flags (%#o): '%s'", flags, path.get_ptr()); } - std::shared_ptr file(Emu.GetVFS().OpenFile(path.get_ptr(), open_mode)); + fs::file file(local_path, open_mode); - if (!file || !file->IsOpened()) + if (!file) { sys_fs.error("sys_fs_open('%s'): failed to open file (flags=%#o, mode=%#o)", path.get_ptr(), flags, mode); - if (open_mode & fom::excl) + if (open_mode & fs::excl) { return CELL_FS_EEXIST; // approximation } @@ -122,7 +115,7 @@ s32 sys_fs_open(vm::cptr path, s32 flags, vm::ptr fd, s32 mode, vm::c return CELL_FS_EMFILE; } - *fd = idm::get_last_id(); + *fd = _file->id; return CELL_OK; } @@ -140,7 +133,7 @@ s32 sys_fs_read(u32 fd, vm::ptr buf, u64 nbytes, vm::ptr nread) std::lock_guard lock(file->mutex); - *nread = file->file->Read(buf.get_ptr(), nbytes); + *nread = file->file.read(buf.get_ptr(), nbytes); return CELL_OK; } @@ -160,7 +153,7 @@ s32 sys_fs_write(u32 fd, vm::cptr buf, u64 nbytes, vm::ptr nwrite) std::lock_guard lock(file->mutex); - *nwrite = file->file->Write(buf.get_ptr(), nbytes); + *nwrite = file->file.write(buf.get_ptr(), nbytes); return CELL_OK; } @@ -188,9 +181,9 @@ s32 sys_fs_opendir(vm::cptr path, vm::ptr fd) sys_fs.warning("sys_fs_opendir(path=*0x%x, fd=*0x%x)", path, fd); sys_fs.warning("*** path = '%s'", path.get_ptr()); - std::shared_ptr dir(Emu.GetVFS().OpenDir(path.get_ptr())); + fs::dir dir(vfs::get(path.get_ptr())); - if (!dir || !dir->IsOpened()) + if (!dir) { sys_fs.error("sys_fs_opendir('%s'): failed to open directory", path.get_ptr()); return CELL_FS_ENOENT; @@ -204,7 +197,7 @@ s32 sys_fs_opendir(vm::cptr path, vm::ptr fd) return CELL_FS_EMFILE; } - *fd = idm::get_last_id(); + *fd = _dir->id; return CELL_OK; } @@ -220,13 +213,13 @@ s32 sys_fs_readdir(u32 fd, vm::ptr dir, vm::ptr nread) return CELL_FS_EBADF; } - const DirEntryInfo* info = directory->dir->Read(); + fs::dir_entry info; - if (info) + if (directory->dir.read(info)) { - dir->d_type = (info->flags & DirEntry_TypeFile) ? CELL_FS_TYPE_REGULAR : CELL_FS_TYPE_DIRECTORY; - dir->d_namlen = u8(std::min(info->name.length(), CELL_FS_MAX_FS_FILE_NAME_LENGTH)); - strcpy_trunc(dir->d_name, info->name); + dir->d_type = info.is_directory ? CELL_FS_TYPE_DIRECTORY : CELL_FS_TYPE_REGULAR; + dir->d_namlen = u8(std::min(info.name.size(), CELL_FS_MAX_FS_FILE_NAME_LENGTH)); + strcpy_trunc(dir->d_name, info.name); *nread = sizeof(CellFsDirent); } else @@ -258,9 +251,9 @@ s32 sys_fs_stat(vm::cptr path, vm::ptr sb) sys_fs.warning("sys_fs_stat(path=*0x%x, sb=*0x%x)", path, sb); sys_fs.warning("*** path = '%s'", path.get_ptr()); - std::string local_path; + const std::string& local_path = vfs::get(path.get_ptr()); - if (!Emu.GetVFS().GetDevice(path.get_ptr(), local_path)) + if (local_path.empty()) { sys_fs.warning("sys_fs_stat('%s') failed: not mounted", path.get_ptr()); return CELL_FS_ENOTMOUNTED; @@ -299,20 +292,7 @@ s32 sys_fs_fstat(u32 fd, vm::ptr sb) std::lock_guard lock(file->mutex); - const auto local_file = dynamic_cast(file->file.get()); - - if (!local_file) - { - sys_fs.error("sys_fs_fstat(fd=0x%x): not a local file"); - return CELL_FS_ENOTSUP; - } - - fs::stat_t info; - - if (!local_file->GetFile().stat(info)) - { - return CELL_FS_EIO; // ??? - } + const fs::stat_t& info = file->file.stat(); sb->mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666; sb->uid = 1; // ??? @@ -331,14 +311,14 @@ s32 sys_fs_mkdir(vm::cptr path, s32 mode) sys_fs.warning("sys_fs_mkdir(path=*0x%x, mode=%#o)", path, mode); sys_fs.warning("*** path = '%s'", path.get_ptr()); - std::string ps3_path = path.get_ptr(); + const std::string& local_path = vfs::get(path.get_ptr()); - if (Emu.GetVFS().ExistsDir(ps3_path)) + if (fs::is_dir(local_path)) { return CELL_FS_EEXIST; } - if (!Emu.GetVFS().CreatePath(ps3_path)) + if (!fs::create_path(local_path)) { return CELL_FS_EIO; // ??? } @@ -353,7 +333,7 @@ s32 sys_fs_rename(vm::cptr from, vm::cptr to) sys_fs.warning("*** from = '%s'", from.get_ptr()); sys_fs.warning("*** to = '%s'", to.get_ptr()); - if (!Emu.GetVFS().Rename(from.get_ptr(), to.get_ptr())) + if (!fs::rename(vfs::get(from.get_ptr()), vfs::get(to.get_ptr()))) { return CELL_FS_ENOENT; // ??? } @@ -367,15 +347,14 @@ s32 sys_fs_rmdir(vm::cptr path) sys_fs.warning("sys_fs_rmdir(path=*0x%x)", path); sys_fs.warning("*** path = '%s'", path.get_ptr()); - std::string ps3_path = path.get_ptr(); - - if (!Emu.GetVFS().ExistsDir(ps3_path)) + if (!fs::remove_dir(vfs::get(path.get_ptr()))) { - return CELL_FS_ENOENT; - } + switch (auto error = errno) + { + case ENOENT: return CELL_FS_ENOENT; + default: sys_fs.error("sys_fs_rmdir(): unknown error %d", error); + } - if (!Emu.GetVFS().RemoveDir(ps3_path)) - { return CELL_FS_EIO; // ??? } @@ -388,15 +367,14 @@ s32 sys_fs_unlink(vm::cptr path) sys_fs.warning("sys_fs_unlink(path=*0x%x)", path); sys_fs.warning("*** path = '%s'", path.get_ptr()); - std::string ps3_path = path.get_ptr(); - - if (!Emu.GetVFS().ExistsFile(ps3_path)) + if (!fs::remove_file(vfs::get(path.get_ptr()))) { - return CELL_FS_ENOENT; - } + switch (auto error = errno) + { + case ENOENT: return CELL_FS_ENOENT; + default: sys_fs.error("sys_fs_unlink(): unknown error %d", error); + } - if (!Emu.GetVFS().RemoveFile(ps3_path)) - { return CELL_FS_EIO; // ??? } @@ -417,7 +395,7 @@ s32 sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ptr pos) if (whence >= 3) { - sys_fs.error("sys_fs_lseek(): unknown seek whence (%d)", whence); + sys_fs.error("sys_fs_lseek(): invalid seek whence (%d)", whence); return CELL_FS_EINVAL; } @@ -430,7 +408,7 @@ s32 sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ptr pos) std::lock_guard lock(file->mutex); - *pos = file->file->Seek(offset, (fs::seek_mode)whence); + *pos = file->file.seek(offset, static_cast(whence)); return CELL_OK; } @@ -468,15 +446,14 @@ s32 sys_fs_truncate(vm::cptr path, u64 size) sys_fs.warning("sys_fs_truncate(path=*0x%x, size=0x%llx)", path, size); sys_fs.warning("*** path = '%s'", path.get_ptr()); - std::string ps3_path = path.get_ptr(); - - if (!Emu.GetVFS().ExistsFile(ps3_path)) + if (!fs::truncate_file(vfs::get(path.get_ptr()), size)) { - return CELL_FS_ENOENT; - } + switch (auto error = errno) + { + case ENOENT: return CELL_FS_ENOENT; + default: sys_fs.error("sys_fs_truncate(): unknown error %d", error); + } - if (!Emu.GetVFS().TruncateFile(ps3_path, size)) - { return CELL_FS_EIO; // ??? } @@ -496,16 +473,14 @@ s32 sys_fs_ftruncate(u32 fd, u64 size) std::lock_guard lock(file->mutex); - const auto local_file = dynamic_cast(file->file.get()); - - if (!local_file) + if (!file->file.trunc(size)) { - sys_fs.error("sys_fs_ftruncate(fd=0x%x): not a local file"); - return CELL_FS_ENOTSUP; - } + switch (auto error = errno) + { + case 0: + default: sys_fs.error("sys_fs_ftruncate(): unknown error %d", error); + } - if (!local_file->GetFile().trunc(size)) - { return CELL_FS_EIO; // ??? } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_fs.h b/rpcs3/Emu/Cell/lv2/sys_fs.h similarity index 87% rename from rpcs3/Emu/SysCalls/lv2/sys_fs.h rename to rpcs3/Emu/Cell/lv2/sys_fs.h index 324958a54a..e943697325 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_fs.h +++ b/rpcs3/Emu/Cell/lv2/sys_fs.h @@ -148,8 +148,6 @@ struct CellFsUtimbuf #pragma pack(pop) -struct vfsStream; - // Stream Support Status (st_status) enum : u32 { @@ -161,16 +159,26 @@ enum : u32 using fs_st_cb_t = vm::ptr; -struct fs_st_cb_rec_t +struct alignas(16) fs_st_cb_rec_t { u64 size; fs_st_cb_t func; u32 pad; }; -struct lv2_file_t +struct lv2_fs_object_t { - const std::shared_ptr file; + using id_base = lv2_fs_object_t; + + static constexpr u32 id_min = 3; + static constexpr u32 id_max = 255; + + const u32 id{}; +}; + +struct lv2_file_t : lv2_fs_object_t +{ + const fs::file file; const s32 mode; const s32 flags; @@ -188,12 +196,12 @@ struct lv2_file_t u32 st_buffer; u64 st_read_size; - std::atomic st_total_read; - std::atomic st_copied; + atomic_t st_total_read; + atomic_t st_copied; atomic_t st_callback; - lv2_file_t(std::shared_ptr file, s32 mode, s32 flags) + lv2_file_t(fs::file file, s32 mode, s32 flags) : file(std::move(file)) , mode(mode) , flags(flags) @@ -203,42 +211,16 @@ struct lv2_file_t } }; -template<> struct id_traits +struct lv2_dir_t : lv2_fs_object_t { - static const u32 base = 0xfddd0000, max = 255; + const fs::dir dir; - static u32 next_id(u32 raw_id) - { - return - raw_id < 0x80000000 ? base + 3 : - raw_id - base < max ? raw_id + 1 : 0; - } - - static u32 in_id(u32 id) - { - return id + base; - } - - static u32 out_id(u32 raw_id) - { - return raw_id - base; - } -}; - -class vfsDirBase; - -struct lv2_dir_t -{ - const std::shared_ptr dir; - - lv2_dir_t(std::shared_ptr dir) + lv2_dir_t(fs::dir dir) : dir(std::move(dir)) { } }; -template<> struct id_traits : public id_traits {}; - // SysCalls s32 sys_fs_test(u32 arg1, u32 arg2, vm::ptr arg3, u32 arg4, vm::ptr arg5, u32 arg6); s32 sys_fs_open(vm::cptr path, s32 flags, vm::ptr fd, s32 mode, vm::cptr arg, u64 size); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_interrupt.cpp b/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp similarity index 85% rename from rpcs3/Emu/SysCalls/lv2/sys_interrupt.cpp rename to rpcs3/Emu/Cell/lv2/sys_interrupt.cpp index 6251f33d00..21c873cc3c 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_interrupt.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_interrupt.cpp @@ -1,36 +1,24 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" #include "sys_interrupt.h" -SysCallBase sys_interrupt("sys_interrupt"); +LOG_CHANNEL(sys_interrupt); -lv2_int_tag_t::lv2_int_tag_t() - : id(idm::get_last_id()) +void lv2_int_serv_t::join(PPUThread& ppu, lv2_lock_t lv2_lock) { -} - -lv2_int_serv_t::lv2_int_serv_t(const std::shared_ptr& thread) - : thread(thread) - , id(idm::get_last_id()) -{ -} - -void lv2_int_serv_t::join(PPUThread& ppu, lv2_lock_t& lv2_lock) -{ - CHECK_LV2_LOCK(lv2_lock); - // Use is_joining to stop interrupt thread and signal thread->is_joining = true; thread->cv.notify_one(); // Start joining - while (thread->is_alive()) + while (!(thread->state & cpu_state::exit)) { CHECK_EMU_STATUS; @@ -39,7 +27,7 @@ void lv2_int_serv_t::join(PPUThread& ppu, lv2_lock_t& lv2_lock) // Cleanup idm::remove(id); - idm::remove(thread->get_id()); + idm::remove(thread->id); } s32 sys_interrupt_tag_destroy(u32 intrtag) @@ -88,7 +76,7 @@ s32 _sys_interrupt_thread_establish(vm::ptr ih, u32 intrtag, u32 intrthread } // If interrupt thread is running, it's already established on another interrupt tag - if (!it->is_stopped()) + if (!(it->state & cpu_state::stop)) { return CELL_EAGAIN; } @@ -137,10 +125,11 @@ s32 _sys_interrupt_thread_establish(vm::ptr ih, u32 intrtag, u32 intrthread ppu.cv.wait(lv2_lock); } - ppu.exit(); + ppu.state += cpu_state::exit; }; - it->exec(); + it->state -= cpu_state::stop; + it->safe_notify(); *ih = handler->id; @@ -177,5 +166,5 @@ void sys_interrupt_thread_eoi(PPUThread& ppu) ppu.GPR[1] = align(ppu.stack_addr + ppu.stack_size, 0x200) - 0x200; // supercrutch to bypass stack check - ppu.fast_stop(); + ppu.state += cpu_state::ret; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_interrupt.h b/rpcs3/Emu/Cell/lv2/sys_interrupt.h similarity index 65% rename from rpcs3/Emu/SysCalls/lv2/sys_interrupt.h rename to rpcs3/Emu/Cell/lv2/sys_interrupt.h index fef802d89d..558aede372 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_interrupt.h +++ b/rpcs3/Emu/Cell/lv2/sys_interrupt.h @@ -1,28 +1,29 @@ #pragma once -namespace vm { using namespace ps3; } +#include "sys_sync.h" class PPUThread; struct lv2_int_tag_t { - const u32 id; + const u32 id{}; std::shared_ptr handler; - - lv2_int_tag_t(); }; struct lv2_int_serv_t { const std::shared_ptr thread; - const u32 id; + const u32 id{}; - std::atomic signal{ 0 }; // signal count + atomic_t signal{ 0 }; // signal count - lv2_int_serv_t(const std::shared_ptr& thread); + lv2_int_serv_t(const std::shared_ptr& thread) + : thread(thread) + { + } - void join(PPUThread& ppu, lv2_lock_t& lv2_lock); + void join(PPUThread& ppu, lv2_lock_t); }; // SysCalls diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp b/rpcs3/Emu/Cell/lv2/sys_lwcond.cpp similarity index 88% rename from rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp rename to rpcs3/Emu/Cell/lv2/sys_lwcond.cpp index ad843cae93..cb77b4b479 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_lwcond.cpp @@ -1,21 +1,20 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" #include "sys_lwmutex.h" #include "sys_lwcond.h" -SysCallBase sys_lwcond("sys_lwcond"); +LOG_CHANNEL(sys_lwcond); extern u64 get_system_time(); -void lv2_lwcond_t::notify(lv2_lock_t & lv2_lock, sleep_queue_t::value_type& thread, const std::shared_ptr& mutex, bool mode2) +void lv2_lwcond_t::notify(lv2_lock_t, cpu_thread* thread, const std::shared_ptr& mutex, bool mode2) { - CHECK_LV2_LOCK(lv2_lock); - auto& ppu = static_cast(*thread); ppu.GPR[3] = mode2; // set to return CELL_EBUSY @@ -30,10 +29,8 @@ void lv2_lwcond_t::notify(lv2_lock_t & lv2_lock, sleep_queue_t::value_type& thre mutex->signaled--; } - if (!ppu.signal()) - { - throw EXCEPTION("Thread already signaled"); - } + ASSERT(!thread->state.test_and_set(cpu_state::signal)); + thread->cv.notify_one(); } s32 _sys_lwcond_create(vm::ptr lwcond_id, u32 lwmutex_id, vm::ptr control, u64 name, u32 arg5) @@ -92,9 +89,9 @@ s32 _sys_lwcond_signal(u32 lwcond_id, u32 lwmutex_id, u32 ppu_thread_id, u32 mod // mode 3: lightweight mutex was forcefully owned by the calling thread // pick waiter; protocol is ignored in current implementation - const auto found = !~ppu_thread_id ? cond->sq.begin() : std::find_if(cond->sq.begin(), cond->sq.end(), [=](sleep_queue_t::value_type& thread) + const auto found = !~ppu_thread_id ? cond->sq.begin() : std::find_if(cond->sq.begin(), cond->sq.end(), [=](cpu_thread* thread) { - return thread->get_id() == ppu_thread_id; + return thread->id == ppu_thread_id; }); if (found == cond->sq.end()) @@ -177,12 +174,12 @@ s32 _sys_lwcond_queue_wait(PPUThread& ppu, u32 lwcond_id, u32 lwmutex_id, u64 ti mutex->unlock(lv2_lock); // add waiter; protocol is ignored in current implementation - sleep_queue_entry_t waiter(ppu, cond->sq); + sleep_entry waiter(cond->sq, ppu); // potential mutex waiter (not added immediately) - sleep_queue_entry_t mutex_waiter(ppu, cond->sq, defer_sleep); + sleep_entry mutex_waiter(cond->sq, ppu, defer_sleep); - while (!ppu.unsignal()) + while (!ppu.state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h b/rpcs3/Emu/Cell/lv2/sys_lwcond.h similarity index 84% rename from rpcs3/Emu/SysCalls/lv2/sys_lwcond.h rename to rpcs3/Emu/Cell/lv2/sys_lwcond.h index 552210ce34..8633318c03 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h +++ b/rpcs3/Emu/Cell/lv2/sys_lwcond.h @@ -21,14 +21,14 @@ struct lv2_lwcond_t { const u64 name; - sleep_queue_t sq; + sleep_queue sq; lv2_lwcond_t(u64 name) : name(name) { } - void notify(lv2_lock_t& lv2_lock, sleep_queue_t::value_type& thread, const std::shared_ptr& mutex, bool mode2); + void notify(lv2_lock_t, cpu_thread* thread, const std::shared_ptr& mutex, bool mode2); }; // Aux diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp b/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp similarity index 88% rename from rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp rename to rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp index 746f87464b..76833e1a93 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp @@ -1,21 +1,19 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" -#include "sys_sync.h" #include "sys_lwmutex.h" -SysCallBase sys_lwmutex("sys_lwmutex"); +LOG_CHANNEL(sys_lwmutex); extern u64 get_system_time(); -void lv2_lwmutex_t::unlock(lv2_lock_t& lv2_lock) +void lv2_lwmutex_t::unlock(lv2_lock_t) { - CHECK_LV2_LOCK(lv2_lock); - if (signaled) { throw EXCEPTION("Unexpected"); @@ -23,10 +21,9 @@ void lv2_lwmutex_t::unlock(lv2_lock_t& lv2_lock) if (sq.size()) { - if (!sq.front()->signal()) - { - throw EXCEPTION("Thread already signaled"); - } + auto& thread = sq.front(); + ASSERT(!thread->state.test_and_set(cpu_state::signal)); + thread->cv.notify_one(); sq.pop_front(); } @@ -102,9 +99,9 @@ s32 _sys_lwmutex_lock(PPUThread& ppu, u32 lwmutex_id, u64 timeout) } // add waiter; protocol is ignored in current implementation - sleep_queue_entry_t waiter(ppu, mutex->sq); + sleep_entry waiter(mutex->sq, ppu); - while (!ppu.unsignal()) + while (!ppu.state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h b/rpcs3/Emu/Cell/lv2/sys_lwmutex.h similarity index 86% rename from rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h rename to rpcs3/Emu/Cell/lv2/sys_lwmutex.h index 4386c83650..775bd11ff6 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h +++ b/rpcs3/Emu/Cell/lv2/sys_lwmutex.h @@ -1,8 +1,6 @@ #pragma once -#include "Utilities/SleepQueue.h" - -namespace vm { using namespace ps3; } +#include "sys_sync.h" struct sys_lwmutex_attribute_t { @@ -20,7 +18,7 @@ enum : u32 struct sys_lwmutex_t { - struct sync_var_t + struct alignas(8) sync_var_t { be_t owner; be_t waiter; @@ -52,9 +50,9 @@ struct lv2_lwmutex_t const u64 name; // this object is not truly a mutex and its syscall names may be wrong, it's probably a sleep queue or something - std::atomic signaled{ 0 }; + atomic_t signaled{ 0 }; - sleep_queue_t sq; + sleep_queue sq; lv2_lwmutex_t(u32 protocol, u64 name) : protocol(protocol) @@ -62,7 +60,7 @@ struct lv2_lwmutex_t { } - void unlock(lv2_lock_t& lv2_lock); + void unlock(lv2_lock_t); }; // Aux diff --git a/rpcs3/Emu/SysCalls/lv2/sys_memory.cpp b/rpcs3/Emu/Cell/lv2/sys_memory.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/lv2/sys_memory.cpp rename to rpcs3/Emu/Cell/lv2/sys_memory.cpp index 3141092f9f..47a7fc79cc 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_memory.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_memory.cpp @@ -1,18 +1,13 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_memory.h" -SysCallBase sys_memory("sys_memory"); - -lv2_memory_container_t::lv2_memory_container_t(u32 size) - : size(size) - , id(idm::get_last_id()) -{ -} +LOG_CHANNEL(sys_memory); s32 sys_memory_allocate(u32 size, u64 flags, vm::ptr alloc_addr) { diff --git a/rpcs3/Emu/SysCalls/lv2/sys_memory.h b/rpcs3/Emu/Cell/lv2/sys_memory.h similarity index 92% rename from rpcs3/Emu/SysCalls/lv2/sys_memory.h rename to rpcs3/Emu/Cell/lv2/sys_memory.h index da73297264..e99580083d 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_memory.h +++ b/rpcs3/Emu/Cell/lv2/sys_memory.h @@ -1,6 +1,6 @@ #pragma once -namespace vm { using namespace ps3; } +#include "sys_sync.h" enum : u32 { @@ -42,18 +42,23 @@ struct sys_page_attr_t be_t pad; }; +#include + struct lv2_memory_container_t { const u32 size; // amount of "physical" memory in this container - const u32 id; + const u32 id{}; // amount of memory allocated - std::atomic used{ 0 }; + atomic_t used{ 0 }; // allocations (addr -> size) std::map allocs; - lv2_memory_container_t(u32 size); + lv2_memory_container_t(u32 size) + : size(size) + { + } }; // SysCalls diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mmapper.cpp b/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp similarity index 96% rename from rpcs3/Emu/SysCalls/lv2/sys_mmapper.cpp rename to rpcs3/Emu/Cell/lv2/sys_mmapper.cpp index 5ec9fc02ac..c8e70246cd 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mmapper.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp @@ -1,21 +1,13 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_mmapper.h" -SysCallBase sys_mmapper("sys_mmapper"); - -lv2_memory_t::lv2_memory_t(u32 size, u32 align, u64 flags, const std::shared_ptr ct) - : size(size) - , align(align) - , id(idm::get_last_id()) - , flags(flags) - , ct(ct) -{ -} +LOG_CHANNEL(sys_mmapper); s32 sys_mmapper_allocate_address(u64 size, u64 flags, u64 alignment, vm::ptr alloc_addr) { diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mmapper.h b/rpcs3/Emu/Cell/lv2/sys_mmapper.h similarity index 86% rename from rpcs3/Emu/SysCalls/lv2/sys_mmapper.h rename to rpcs3/Emu/Cell/lv2/sys_mmapper.h index 684ac0fdc8..e8d9d9a265 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mmapper.h +++ b/rpcs3/Emu/Cell/lv2/sys_mmapper.h @@ -2,19 +2,23 @@ #include "sys_memory.h" -namespace vm { using namespace ps3; } - struct lv2_memory_t { const u32 size; // memory size const u32 align; // required alignment - const u32 id; const u64 flags; const std::shared_ptr ct; // memory container the physical memory is taken from + const u32 id{}; - std::atomic addr{ 0 }; // actual mapping address + atomic_t addr{ 0 }; // actual mapping address - lv2_memory_t(u32 size, u32 align, u64 flags, const std::shared_ptr ct); + lv2_memory_t(u32 size, u32 align, u64 flags, const std::shared_ptr ct) + : size(size) + , align(align) + , flags(flags) + , ct(ct) + { + } }; // SysCalls diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp b/rpcs3/Emu/Cell/lv2/sys_mutex.cpp similarity index 88% rename from rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp rename to rpcs3/Emu/Cell/lv2/sys_mutex.cpp index f2d50747ee..faf3f21b99 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_mutex.cpp @@ -1,32 +1,28 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" -#include "sys_sync.h" #include "sys_mutex.h" -SysCallBase sys_mutex("sys_mutex"); +LOG_CHANNEL(sys_mutex); extern u64 get_system_time(); -void lv2_mutex_t::unlock(lv2_lock_t& lv2_lock) +void lv2_mutex_t::unlock(lv2_lock_t) { - CHECK_LV2_LOCK(lv2_lock); - owner.reset(); if (sq.size()) { // pick new owner; protocol is ignored in current implementation - owner = sq.front(); + owner = std::static_pointer_cast(sq.front()->shared_from_this()); - if (!owner->signal()) - { - throw EXCEPTION("Mutex owner already signaled"); - } + ASSERT(!owner->state.test_and_set(cpu_state::signal)); + owner->cv.notify_one(); } } @@ -132,15 +128,15 @@ s32 sys_mutex_lock(PPUThread& ppu, u32 mutex_id, u64 timeout) // lock immediately if not locked if (!mutex->owner) { - mutex->owner = std::static_pointer_cast(ppu.shared_from_this()); + mutex->owner = std::static_pointer_cast(ppu.shared_from_this()); return CELL_OK; } // add waiter; protocol is ignored in current implementation - sleep_queue_entry_t waiter(ppu, mutex->sq); + sleep_entry waiter(mutex->sq, ppu); - while (!ppu.unsignal()) + while (!ppu.state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; @@ -207,7 +203,7 @@ s32 sys_mutex_trylock(PPUThread& ppu, u32 mutex_id) } // own the mutex if free - mutex->owner = std::static_pointer_cast(ppu.shared_from_this()); + mutex->owner = std::static_pointer_cast(ppu.shared_from_this()); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mutex.h b/rpcs3/Emu/Cell/lv2/sys_mutex.h similarity index 72% rename from rpcs3/Emu/SysCalls/lv2/sys_mutex.h rename to rpcs3/Emu/Cell/lv2/sys_mutex.h index 8e736b5ea9..97f9d7d858 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mutex.h +++ b/rpcs3/Emu/Cell/lv2/sys_mutex.h @@ -1,8 +1,6 @@ #pragma once -#include "Utilities/SleepQueue.h" - -namespace vm { using namespace ps3; } +#include "sys_sync.h" struct sys_mutex_attribute_t { @@ -27,11 +25,11 @@ struct lv2_mutex_t const u32 protocol; const u64 name; - std::atomic cond_count{ 0 }; // count of condition variables associated - std::atomic recursive_count{ 0 }; // count of recursive locks - std::shared_ptr owner; // current mutex owner + atomic_t cond_count{ 0 }; // count of condition variables associated + atomic_t recursive_count{ 0 }; // count of recursive locks + std::shared_ptr owner; // current mutex owner - sleep_queue_t sq; + sleep_queue sq; lv2_mutex_t(bool recursive, u32 protocol, u64 name) : recursive(recursive) @@ -40,7 +38,7 @@ struct lv2_mutex_t { } - void unlock(lv2_lock_t& lv2_lock); + void unlock(lv2_lock_t); }; class PPUThread; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp similarity index 90% rename from rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp rename to rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp index 51cff30866..f895072977 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp @@ -1,14 +1,15 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" #include "sys_mutex.h" #include "sys_ppu_thread.h" -SysCallBase sys_ppu_thread("sys_ppu_thread"); +LOG_CHANNEL(sys_ppu_thread); void _sys_ppu_thread_exit(PPUThread& ppu, u64 errorcode) { @@ -28,17 +29,17 @@ void _sys_ppu_thread_exit(PPUThread& ppu, u64 errorcode) if (!ppu.is_joinable) { - idm::remove(ppu.get_id()); + idm::remove(ppu.id); } else { - ppu.exit(); + ppu.state += cpu_state::exit; } - // Throw if this syscall was not called directly by the SC instruction - if (~ppu.hle_code != 41) + // Throw if this syscall was not called directly by the SC instruction (hack) + if (ppu.GPR[11] != 41 || ppu.custom_task) { - throw CPUThreadExit{}; + throw cpu_state::exit; } } @@ -76,7 +77,7 @@ s32 sys_ppu_thread_join(PPUThread& ppu, u32 thread_id, vm::ptr vptr) thread->is_joining = true; // join thread - while (thread->is_alive()) + while (!(thread->state & cpu_state::exit)) { CHECK_EMU_STATUS; @@ -84,10 +85,10 @@ s32 sys_ppu_thread_join(PPUThread& ppu, u32 thread_id, vm::ptr vptr) } // get exit status from the register - *vptr = thread->GPR[3]; + if (vptr) *vptr = thread->GPR[3]; // cleanup - idm::remove(thread->get_id()); + idm::remove(thread->id); return CELL_OK; } @@ -225,7 +226,7 @@ u32 ppu_thread_create(u32 entry, u64 arg, s32 prio, u32 stacksize, const std::st ppu->prio = prio; ppu->stack_size = stacksize; ppu->custom_task = std::move(task); - ppu->run(); + ppu->cpu_init(); if (entry) { @@ -234,9 +235,10 @@ u32 ppu_thread_create(u32 entry, u64 arg, s32 prio, u32 stacksize, const std::st } ppu->GPR[3] = arg; - ppu->exec(); + ppu->state -= cpu_state::stop; + ppu->safe_notify(); - return ppu->get_id(); + return ppu->id; } s32 _sys_ppu_thread_create(vm::ptr thread_id, vm::ptr param, u64 arg, u64 unk, s32 prio, u32 stacksize, u64 flags, vm::cptr threadname) @@ -263,21 +265,17 @@ s32 _sys_ppu_thread_create(vm::ptr thread_id, vm::ptr p ppu->prio = prio; ppu->stack_size = std::max(stacksize, 0x4000); - ppu->run(); + ppu->cpu_init(); ppu->PC = vm::read32(param->entry); ppu->GPR[2] = vm::read32(param->entry + 4); // rtoc ppu->GPR[3] = arg; ppu->GPR[4] = unk; // actually unknown + ppu->GPR[13] = param->tls; ppu->is_joinable = is_joinable; - if (u32 tls = param->tls) // hack - { - ppu->GPR[13] = tls; - } - - *thread_id = ppu->get_id(); + *thread_id = ppu->id; return CELL_OK; } @@ -295,7 +293,8 @@ s32 sys_ppu_thread_start(u32 thread_id) return CELL_ESRCH; } - thread->exec(); + thread->state -= cpu_state::stop; + thread->safe_notify(); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.h b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.h similarity index 100% rename from rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.h rename to rpcs3/Emu/Cell/lv2/sys_ppu_thread.h diff --git a/rpcs3/Emu/SysCalls/lv2/sys_process.cpp b/rpcs3/Emu/Cell/lv2/sys_process.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/lv2/sys_process.cpp rename to rpcs3/Emu/Cell/lv2/sys_process.cpp index 9de2ae7dbc..8291849120 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_process.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_process.cpp @@ -1,12 +1,10 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFile.h" -#include "Loader/PSF.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_lwmutex.h" #include "sys_lwcond.h" #include "sys_mutex.h" @@ -24,7 +22,7 @@ #include "sys_fs.h" #include "sys_process.h" -SysCallBase sys_process("sys_process"); +LOG_CHANNEL(sys_process); s32 process_getpid() { diff --git a/rpcs3/Emu/SysCalls/lv2/sys_process.h b/rpcs3/Emu/Cell/lv2/sys_process.h similarity index 100% rename from rpcs3/Emu/SysCalls/lv2/sys_process.h rename to rpcs3/Emu/Cell/lv2/sys_process.h diff --git a/rpcs3/Emu/SysCalls/lv2/sys_prx.cpp b/rpcs3/Emu/Cell/lv2/sys_prx.cpp similarity index 62% rename from rpcs3/Emu/SysCalls/lv2/sys_prx.cpp rename to rpcs3/Emu/Cell/lv2/sys_prx.cpp index 4f39c3059f..99ec5b9ac5 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_prx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_prx.cpp @@ -1,142 +1,32 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" -#include "Emu/SysCalls/CB_FUNC.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/SysCalls/ModuleManager.h" -#include "Emu/Cell/PPUInstrTable.h" - -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFile.h" #include "Crypto/unself.h" -#include "Loader/ELF64.h" +#include "Loader/ELF.h" + +#include "Emu/Cell/ErrorCodes.h" #include "sys_prx.h" -SysCallBase sys_prx("sys_prx"); - -lv2_prx_t::lv2_prx_t() - : id(idm::get_last_id()) -{ -} +LOG_CHANNEL(sys_prx); s32 prx_load_module(std::string path, u64 flags, vm::ptr pOpt) { sys_prx.warning("prx_load_module(path='%s', flags=0x%llx, pOpt=*0x%x)", path.c_str(), flags, pOpt); - loader::handlers::elf64 loader; + const ppu_prx_loader loader = fs::file(vfs::get(path)); - vfsFile f(path); - if (!f.IsOpened()) - { - return CELL_PRX_ERROR_UNKNOWN_MODULE; - } - - if (loader.init(f) != loader::handler::error_code::ok || !loader.is_sprx()) + if (loader != elf_error::ok) { return CELL_PRX_ERROR_ILLEGAL_LIBRARY; } - loader::handlers::elf64::sprx_info info; - loader.load_sprx(info); + const auto prx = loader.load(); - auto prx = idm::make_ptr(); - - auto meta = info.modules[""]; - prx->start.set(meta.exports[0xBC9A0086]); - prx->stop.set(meta.exports[0xAB779874]); - prx->exit.set(meta.exports[0x3AB9A95E]); - - for (auto &module_ : info.modules) + if (!prx) { - if (module_.first == "") - continue; - - Module<>* module = Emu.GetModuleManager().GetModuleByName(module_.first.c_str()); - - if (!module) - { - sys_prx.error("Unknown module '%s'", module_.first.c_str()); - } - - for (auto& f : module_.second.exports) - { - const u32 nid = f.first; - const u32 addr = f.second; - - u32 index; - - auto func = get_ppu_func_by_nid(nid, &index); - - if (!func) - { - index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr, nullptr, vm::ptr::make(addr))); - } - else - { - func->lle_func.set(addr); - - if (func->flags & MFF_FORCED_HLE) - { - u32 i_addr = 0; - - if (!vm::check_addr(addr, 8) || !vm::check_addr(i_addr = vm::read32(addr), 4)) - { - sys_prx.error("Failed to inject code for exported function '%s' (opd=0x%x, 0x%x)", get_ps3_function_name(nid), addr, i_addr); - } - else - { - vm::write32(i_addr, PPU_instr::HACK(index | EIF_PERFORM_BLR)); - } - } - } - } - - for (auto &import : module_.second.imports) - { - u32 nid = import.first; - u32 addr = import.second; - - u32 index; - - auto func = get_ppu_func_by_nid(nid, &index); - - if (!func) - { - sys_prx.error("Unknown function '%s' in '%s' module (0x%x)", get_ps3_function_name(nid), module_.first); - - index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr, nullptr)); - } - else - { - const bool is_lle = func->lle_func && !(func->flags & MFF_FORCED_HLE); - - sys_prx.error("Imported %sfunction '%s' in '%s' module (0x%x)", (is_lle ? "LLE " : ""), get_ps3_function_name(nid), module_.first, addr); - } - - if (!patch_ppu_import(addr, index)) - { - sys_prx.error("Failed to inject code at address 0x%x", addr); - } - } - } - - const auto decoder_cache = fxm::get(); - - for (auto& seg : info.segments) - { - const u32 addr = seg.begin.addr(); - const u32 size = align(seg.size, 4096); - - if (vm::check_addr(addr, size)) - { - decoder_cache->initialize(addr, size); - } - else - { - sys_prx.error("Failed to process executable area (addr=0x%x, size=0x%x)", addr, size); - } + return CELL_PRX_ERROR_ILLEGAL_LIBRARY; } return prx->id; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_prx.h b/rpcs3/Emu/Cell/lv2/sys_prx.h similarity index 69% rename from rpcs3/Emu/SysCalls/lv2/sys_prx.h rename to rpcs3/Emu/Cell/lv2/sys_prx.h index 89371e63ed..4d513b03b3 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_prx.h +++ b/rpcs3/Emu/Cell/lv2/sys_prx.h @@ -30,114 +30,21 @@ enum CELL_PRX_ERROR_ELF_IS_REGISTERED = 0x80011910, // Fixed ELF is already registered }; -struct sys_stub -{ - u8 s_size; // = 0x2c - u8 s_unk0; - be_t s_version; // = 0x1 - be_t s_unk1; // = 0x9 // flags? - be_t s_imports; - be_t s_unk2; // = 0x0 - be_t s_unk3; // = 0x0 - vm::bcptr s_modulename; - vm::bptr s_nid; - vm::bptr s_text; - be_t s_unk4; // = 0x0 - be_t s_unk5; // = 0x0 - be_t s_unk6; // = 0x0 - be_t s_unk7; // = 0x0 -}; - -struct sys_proc_prx_param -{ - be_t size; - be_t magic; - be_t version; - be_t pad0; - be_t libentstart; - be_t libentend; - vm::bptr libstubstart; - vm::bptr libstubend; - be_t ver; - be_t pad1; - be_t pad2; -}; - -// Information about imported or exported libraries in PRX modules -struct sys_prx_library_info_t -{ - u8 size; - u8 unk0; - be_t version; - be_t attributes; - be_t num_func; - be_t num_var; - be_t num_tlsvar; - u8 info_hash; - u8 info_tlshash; - u8 unk1[2]; - be_t name_addr; - be_t fnid_addr; - be_t fstub_addr; - be_t unk4; - be_t unk5; - be_t unk6; - be_t unk7; -}; - -// ELF file headers -struct sys_prx_param_t -{ - be_t size; - be_t magic; - be_t version; - be_t unk0; - be_t libentstart; - be_t libentend; - vm::bptr libstubstart; - vm::bptr libstubend; - be_t ver; - be_t unk1; - be_t unk2; -}; - struct sys_prx_get_module_id_by_name_option_t { be_t size; vm::ptr base; }; -// PRX file headers -struct sys_prx_module_info_t -{ - be_t attributes; - be_t version; - char name[28]; - be_t toc; - vm::bptr exports_start; - vm::bptr exports_end; - be_t imports_start; - be_t imports_end; -}; - -// Relocation information of the SCE_PPURELA segment -struct sys_prx_relocation_info_t -{ - be_t offset; - be_t unk0; - u8 index_value; - u8 index_addr; - be_t type; - vm::bptr ptr; -}; - -// Data types struct sys_prx_load_module_option_t { be_t size; vm::bptr base_addr; }; +struct sys_prx_segment_info_t;// TODO +struct sys_prx_module_info_t;// TODO + struct sys_prx_start_module_option_t { be_t size; @@ -165,18 +72,17 @@ struct sys_prx_get_module_list_t vm::bptr idlist; }; -// Auxiliary data types struct lv2_prx_t { - const u32 id; + const u32 id{}; bool is_started = false; + std::unordered_map specials; + vm::ptr argv)> start = vm::null; vm::ptr argv)> stop = vm::null; vm::ptr exit = vm::null; - - lv2_prx_t(); }; // SysCalls diff --git a/rpcs3/Emu/SysCalls/lv2/sys_rsx.cpp b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp similarity index 98% rename from rpcs3/Emu/SysCalls/lv2/sys_rsx.cpp rename to rpcs3/Emu/Cell/lv2/sys_rsx.cpp index eb25345942..5d4d8ee83d 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_rsx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rsx.cpp @@ -1,11 +1,12 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_rsx.h" -SysCallBase sys_rsx("sys_rsx"); +LOG_CHANNEL(sys_rsx); s32 sys_rsx_device_open() { diff --git a/rpcs3/Emu/SysCalls/lv2/sys_rsx.h b/rpcs3/Emu/Cell/lv2/sys_rsx.h similarity index 100% rename from rpcs3/Emu/SysCalls/lv2/sys_rsx.h rename to rpcs3/Emu/Cell/lv2/sys_rsx.h diff --git a/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp b/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp similarity index 87% rename from rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp rename to rpcs3/Emu/Cell/lv2/sys_rwlock.cpp index 1145e6cb31..0188cf7ac6 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp @@ -1,30 +1,26 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" -#include "sys_sync.h" #include "sys_rwlock.h" -SysCallBase sys_rwlock("sys_rwlock"); +LOG_CHANNEL(sys_rwlock); extern u64 get_system_time(); -void lv2_rwlock_t::notify_all(lv2_lock_t& lv2_lock) +void lv2_rwlock_t::notify_all(lv2_lock_t) { - CHECK_LV2_LOCK(lv2_lock); - // pick a new writer if possible; protocol is ignored in current implementation if (!readers && !writer && wsq.size()) { - writer = wsq.front(); + writer = std::static_pointer_cast(wsq.front()->shared_from_this()); - if (!writer->signal()) - { - throw EXCEPTION("Writer already signaled"); - } + ASSERT(!writer->state.test_and_set(cpu_state::signal)); + writer->cv.notify_one(); return wsq.pop_front(); } @@ -36,10 +32,8 @@ void lv2_rwlock_t::notify_all(lv2_lock_t& lv2_lock) for (auto& thread : rsq) { - if (!thread->signal()) - { - throw EXCEPTION("Reader already signaled"); - } + ASSERT(!thread->state.test_and_set(cpu_state::signal)); + thread->cv.notify_one(); } return rsq.clear(); @@ -123,9 +117,9 @@ s32 sys_rwlock_rlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout) } // add waiter; protocol is ignored in current implementation - sleep_queue_entry_t waiter(ppu, rwlock->rsq); + sleep_entry waiter(rwlock->rsq, ppu); - while (!ppu.unsignal()) + while (!ppu.state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; @@ -228,15 +222,15 @@ s32 sys_rwlock_wlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout) if (!rwlock->readers && !rwlock->writer) { - rwlock->writer = std::static_pointer_cast(ppu.shared_from_this()); + rwlock->writer = std::static_pointer_cast(ppu.shared_from_this()); return CELL_OK; } // add waiter; protocol is ignored in current implementation - sleep_queue_entry_t waiter(ppu, rwlock->wsq); + sleep_entry waiter(rwlock->wsq, ppu); - while (!ppu.unsignal()) + while (!ppu.state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; @@ -249,7 +243,7 @@ s32 sys_rwlock_wlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout) // if the last waiter quit the writer sleep queue, readers must acquire the lock if (!rwlock->writer && rwlock->wsq.size() == 1) { - if (rwlock->wsq.front().get() != &ppu) + if (rwlock->wsq.front() != &ppu) { throw EXCEPTION("Unexpected"); } @@ -300,7 +294,7 @@ s32 sys_rwlock_trywlock(PPUThread& ppu, u32 rw_lock_id) return CELL_EBUSY; } - rwlock->writer = std::static_pointer_cast(ppu.shared_from_this()); + rwlock->writer = std::static_pointer_cast(ppu.shared_from_this()); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_rwlock.h b/rpcs3/Emu/Cell/lv2/sys_rwlock.h similarity index 70% rename from rpcs3/Emu/SysCalls/lv2/sys_rwlock.h rename to rpcs3/Emu/Cell/lv2/sys_rwlock.h index ea9f19f138..596f1ad010 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_rwlock.h +++ b/rpcs3/Emu/Cell/lv2/sys_rwlock.h @@ -1,8 +1,6 @@ #pragma once -#include "Utilities/SleepQueue.h" - -namespace vm { using namespace ps3; } +#include "sys_sync.h" struct sys_rwlock_attribute_t { @@ -24,11 +22,11 @@ struct lv2_rwlock_t const u64 name; const u32 protocol; - std::atomic readers{ 0 }; // reader lock count - std::shared_ptr writer; // writer lock owner + atomic_t readers{ 0 }; // reader lock count + std::shared_ptr writer; // writer lock owner - sleep_queue_t rsq; // threads trying to acquire readed lock - sleep_queue_t wsq; // threads trying to acquire writer lock + sleep_queue rsq; // threads trying to acquire readed lock + sleep_queue wsq; // threads trying to acquire writer lock lv2_rwlock_t(u32 protocol, u64 name) : protocol(protocol) @@ -36,7 +34,7 @@ struct lv2_rwlock_t { } - void notify_all(lv2_lock_t& lv2_lock); + void notify_all(lv2_lock_t); }; // Aux diff --git a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp b/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp similarity index 92% rename from rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp rename to rpcs3/Emu/Cell/lv2/sys_semaphore.cpp index 089c38f814..04c4a59c9c 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp @@ -1,14 +1,14 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" -#include "sys_sync.h" #include "sys_semaphore.h" -SysCallBase sys_semaphore("sys_semaphore"); +LOG_CHANNEL(sys_semaphore); extern u64 get_system_time(); @@ -92,9 +92,9 @@ s32 sys_semaphore_wait(PPUThread& ppu, u32 sem_id, u64 timeout) } // add waiter; protocol is ignored in current implementation - sleep_queue_entry_t waiter(ppu, sem->sq); + sleep_entry waiter(sem->sq, ppu); - while (!ppu.unsignal()) + while (!ppu.state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; @@ -173,10 +173,9 @@ s32 sys_semaphore_post(u32 sem_id, s32 count) { count--; - if (!sem->sq.front()->signal()) - { - throw EXCEPTION("Thread already signaled"); - } + auto& thread = sem->sq.front(); + ASSERT(!thread->state.test_and_set(cpu_state::signal)); + thread->cv.notify_one(); sem->sq.pop_front(); } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.h b/rpcs3/Emu/Cell/lv2/sys_semaphore.h similarity index 87% rename from rpcs3/Emu/SysCalls/lv2/sys_semaphore.h rename to rpcs3/Emu/Cell/lv2/sys_semaphore.h index f179b072cd..9885b1a2eb 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.h +++ b/rpcs3/Emu/Cell/lv2/sys_semaphore.h @@ -1,8 +1,6 @@ #pragma once -#include "Utilities/SleepQueue.h" - -namespace vm { using namespace ps3; } +#include "sys_sync.h" struct sys_semaphore_attribute_t { @@ -25,9 +23,9 @@ struct lv2_sema_t const s32 max; const u64 name; - std::atomic value; + atomic_t value; - sleep_queue_t sq; + sleep_queue sq; lv2_sema_t(u32 protocol, s32 max, u64 name, s32 value) : protocol(protocol) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp similarity index 91% rename from rpcs3/Emu/SysCalls/lv2/sys_spu.cpp rename to rpcs3/Emu/Cell/lv2/sys_spu.cpp index 470c644dc1..fde8c1320b 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -1,30 +1,40 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" - -#include "Emu/CPU/CPUThreadManager.h" -#include "Emu/Cell/RawSPUThread.h" -#include "Emu/FS/vfsStreamMemory.h" -#include "Emu/FS/vfsFile.h" -#include "Loader/ELF32.h" #include "Crypto/unself.h" +#include "Loader/ELF.h" + +#include "Emu/Cell/ErrorCodes.h" +#include "Emu/Cell/RawSPUThread.h" #include "sys_interrupt.h" #include "sys_event.h" #include "sys_spu.h" -SysCallBase sys_spu("sys_spu"); +LOG_CHANNEL(sys_spu); -void LoadSpuImage(vfsStream& stream, u32& spu_ep, u32 addr) +void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr) { - loader::handlers::elf32 h; - h.init(stream); - h.load_data(addr); - spu_ep = h.m_ehdr.data_be.e_entry; + const spu_exec_loader loader = stream; + + if (loader != elf_error::ok) + { + throw fmt::exception("Failed to load SPU image: %s" HERE, bijective_find(loader, "???")); + } + + for (const auto& prog : loader.progs) + { + if (prog.p_type == 0x1 /* LOAD */) + { + std::memcpy(vm::base(addr + prog.p_vaddr), prog.bin.data(), prog.p_filesz); + } + } + + spu_ep = loader.header.e_entry; } -u32 LoadSpuImage(vfsStream& stream, u32& spu_ep) +u32 LoadSpuImage(const fs::file& stream, u32& spu_ep) { const u32 alloc_size = 256 * 1024; u32 spu_offset = (u32)vm::alloc(alloc_size, vm::main); @@ -33,20 +43,6 @@ u32 LoadSpuImage(vfsStream& stream, u32& spu_ep) return spu_offset; } -s32 spu_image_import(sys_spu_image& img, u32 src, u32 type) -{ - vfsStreamMemory f(src); - u32 entry; - u32 offset = LoadSpuImage(f, entry); - - img.type = SYS_SPU_IMAGE_TYPE_USER; - img.entry_point = entry; - img.addr = offset; // TODO: writing actual segment info - img.nsegs = 1; // wrong value - - return CELL_OK; -} - s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu) { sys_spu.warning("sys_spu_initialize(max_usable_spu=%d, max_raw_spu=%d)", max_usable_spu, max_raw_spu); @@ -59,14 +55,14 @@ s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu) return CELL_OK; } -s32 sys_spu_image_open(vm::ptr img, vm::cptr path) +s32 sys_spu_image_open(vm::ptr img, vm::cptr path) { sys_spu.warning("sys_spu_image_open(img=*0x%x, path=*0x%x)", img, path); - vfsFile f(path.get_ptr()); - if(!f.IsOpened()) + const fs::file f(vfs::get(path.get_ptr())); + if (!f) { - sys_spu.error("sys_spu_image_open error: '%s' not found!", path.get_ptr()); + sys_spu.error("sys_spu_image_open() error: '%s' not found!", path.get_ptr()); return CELL_ENOENT; } @@ -75,25 +71,23 @@ s32 sys_spu_image_open(vm::ptr img, vm::cptr path) if (hdr.CheckMagic()) { - sys_spu.error("sys_spu_image_open error: '%s' is encrypted! Decrypt SELF and try again.", path.get_ptr()); - Emu.Pause(); - return CELL_ENOENT; + throw fmt::exception("sys_spu_image_open() error: '%s' is encrypted! Try to decrypt it manually and try again.", path.get_ptr()); } - f.Seek(0); + f.seek(0); u32 entry; u32 offset = LoadSpuImage(f, entry); img->type = SYS_SPU_IMAGE_TYPE_USER; img->entry_point = entry; - img->addr = offset; // TODO: writing actual segment info + img->segs.set(offset); // TODO: writing actual segment info img->nsegs = 1; // wrong value return CELL_OK; } -u32 spu_thread_initialize(u32 group_id, u32 spu_num, vm::ptr img, const std::string& name, u32 option, u64 a1, u64 a2, u64 a3, u64 a4, std::function task = nullptr) +u32 spu_thread_initialize(u32 group_id, u32 spu_num, vm::ptr img, const std::string& name, u32 option, u64 a1, u64 a2, u64 a3, u64 a4, std::function task = nullptr) { if (option) { @@ -131,10 +125,10 @@ u32 spu_thread_initialize(u32 group_id, u32 spu_num, vm::ptr img, group->state = SPU_THREAD_GROUP_STATUS_INITIALIZED; } - return spu->get_id(); + return spu->id; } -s32 sys_spu_thread_initialize(vm::ptr thread, u32 group_id, u32 spu_num, vm::ptr img, vm::ptr attr, vm::ptr arg) +s32 sys_spu_thread_initialize(vm::ptr thread, u32 group_id, u32 spu_num, vm::ptr img, vm::ptr attr, vm::ptr arg) { sys_spu.warning("sys_spu_thread_initialize(thread=*0x%x, group=0x%x, spu_num=%d, img=*0x%x, attr=*0x%x, arg=*0x%x)", thread, group_id, spu_num, img, attr, arg); @@ -263,7 +257,7 @@ s32 sys_spu_thread_group_destroy(u32 id) { if (t) { - idm::remove(t->get_id()); + idm::remove(t->id); t.reset(); } @@ -312,10 +306,10 @@ s32 sys_spu_thread_group_start(u32 id) // Copy SPU image: // TODO: use segment info - std::memcpy(vm::base(t->offset), vm::base(image->addr), 256 * 1024); + std::memcpy(vm::base(t->offset), image->segs.get_ptr(), 256 * 1024); t->pc = image->entry_point; - t->run(); + t->cpu_init(); t->gpr[3] = v128::from64(0, args.arg1); t->gpr[4] = v128::from64(0, args.arg2); t->gpr[5] = v128::from64(0, args.arg3); @@ -329,9 +323,13 @@ s32 sys_spu_thread_group_start(u32 id) group->send_run_event(lv2_lock, id, 0, 0); // TODO: check data2 and data3 - for (auto& t : group->threads) + for (auto& thread : group->threads) { - if (t) t->exec(); + if (thread) + { + thread->state -= cpu_state::stop; + thread->safe_notify(); + } } return CELL_OK; @@ -379,9 +377,12 @@ s32 sys_spu_thread_group_suspend(u32 id) return CELL_ESTAT; } - for (auto& t : group->threads) + for (auto& thread : group->threads) { - if (t) t->sleep(); // trigger status check + if (thread) + { + thread->state += cpu_state::suspend; + } } return CELL_OK; @@ -420,9 +421,13 @@ s32 sys_spu_thread_group_resume(u32 id) return CELL_ESTAT; } - for (auto& t : group->threads) + for (auto& thread : group->threads) { - if (t) t->awake(); // untrigger status check + if (thread) + { + thread->state -= cpu_state::suspend; + thread->safe_notify(); + } } group->cv.notify_all(); @@ -499,9 +504,13 @@ s32 sys_spu_thread_group_terminate(u32 id, s32 value) return CELL_ESTAT; } - for (auto& t : group->threads) + for (auto& thread : group->threads) { - if (t) t->stop(); + if (thread) + { + thread->state += cpu_state::stop; + thread->safe_notify(); + } } group->state = SPU_THREAD_GROUP_STATUS_INITIALIZED; @@ -1143,14 +1152,14 @@ s32 sys_raw_spu_create(vm::ptr id, vm::ptr attr) // TODO: check number set by sys_spu_initialize() - const auto thread = Emu.GetCPU().NewRawSPUThread(); + const auto thread = idm::make_ptr(""); if (!thread) { return CELL_EAGAIN; } - thread->run(); + thread->cpu_init(); *id = thread->index; @@ -1163,7 +1172,7 @@ s32 sys_raw_spu_destroy(PPUThread& ppu, u32 id) LV2_LOCK; - const auto thread = Emu.GetCPU().GetRawSPUThread(id); + const auto thread = idm::get(id); if (!thread) { @@ -1173,7 +1182,7 @@ s32 sys_raw_spu_destroy(PPUThread& ppu, u32 id) // TODO: CELL_EBUSY is not returned // Stop thread - thread->stop(); + thread->state += cpu_state::stop; // Clear interrupt handlers for (auto& intr : thread->int_ctrl) @@ -1189,7 +1198,7 @@ s32 sys_raw_spu_destroy(PPUThread& ppu, u32 id) } } - idm::remove(thread->get_id()); + idm::remove(thread->id); return CELL_OK; } @@ -1200,7 +1209,7 @@ s32 sys_raw_spu_create_interrupt_tag(u32 id, u32 class_id, u32 hwthread, vm::ptr LV2_LOCK; - const auto thread = Emu.GetCPU().GetRawSPUThread(id); + const auto thread = idm::get(id); if (!thread) { @@ -1235,7 +1244,7 @@ s32 sys_raw_spu_set_int_mask(u32 id, u32 class_id, u64 mask) return CELL_EINVAL; } - const auto thread = Emu.GetCPU().GetRawSPUThread(id); + const auto thread = idm::get(id); if (!thread) { @@ -1256,7 +1265,7 @@ s32 sys_raw_spu_get_int_mask(u32 id, u32 class_id, vm::ptr mask) return CELL_EINVAL; } - const auto thread = Emu.GetCPU().GetRawSPUThread(id); + const auto thread = idm::get(id); if (!thread) { @@ -1277,7 +1286,7 @@ s32 sys_raw_spu_set_int_stat(u32 id, u32 class_id, u64 stat) return CELL_EINVAL; } - const auto thread = Emu.GetCPU().GetRawSPUThread(id); + const auto thread = idm::get(id); if (!thread) { @@ -1298,7 +1307,7 @@ s32 sys_raw_spu_get_int_stat(u32 id, u32 class_id, vm::ptr stat) return CELL_EINVAL; } - const auto thread = Emu.GetCPU().GetRawSPUThread(id); + const auto thread = idm::get(id); if (!thread) { @@ -1314,7 +1323,7 @@ s32 sys_raw_spu_read_puint_mb(u32 id, vm::ptr value) { sys_spu.trace("sys_raw_spu_read_puint_mb(id=%d, value=*0x%x)", id, value); - const auto thread = Emu.GetCPU().GetRawSPUThread(id); + const auto thread = idm::get(id); if (!thread) { @@ -1343,7 +1352,7 @@ s32 sys_raw_spu_set_spu_cfg(u32 id, u32 value) throw EXCEPTION("Unexpected value (0x%x)", value); } - const auto thread = Emu.GetCPU().GetRawSPUThread(id); + const auto thread = idm::get(id); if (!thread) { @@ -1359,7 +1368,7 @@ s32 sys_raw_spu_get_spu_cfg(u32 id, vm::ptr value) { sys_spu.trace("sys_raw_spu_get_spu_afg(id=%d, value=*0x%x)", id, value); - const auto thread = Emu.GetCPU().GetRawSPUThread(id); + const auto thread = idm::get(id); if (!thread) { diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spu.h b/rpcs3/Emu/Cell/lv2/sys_spu.h similarity index 86% rename from rpcs3/Emu/SysCalls/lv2/sys_spu.h rename to rpcs3/Emu/Cell/lv2/sys_spu.h index 1b720448de..cc6475447b 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spu.h +++ b/rpcs3/Emu/Cell/lv2/sys_spu.h @@ -1,7 +1,5 @@ #pragma once -namespace vm { using namespace ps3; } - #include "sys_event.h" enum : s32 @@ -107,15 +105,11 @@ enum : u32 SYS_SPU_IMAGE_TYPE_KERNEL = 1, }; -struct sys_spu_image +struct sys_spu_image_t { be_t type; // user, kernel be_t entry_point; - union - { - be_t addr; // temporarily used as offset of the whole LS image (should be removed) - vm::bptr segs; - }; + vm::bptr segs; be_t nsegs; }; @@ -151,14 +145,14 @@ struct lv2_spu_group_t const u32 ct; // Memory Container Id std::array, 256> threads; // SPU Threads - std::array, 256> images; // SPU Images + std::array, 256> images; // SPU Images std::array args; // SPU Thread Arguments s32 prio; // SPU Thread Group Priority volatile u32 state; // SPU Thread Group State s32 exit_status; // SPU Thread Group Exit Status - std::atomic join_state; // flags used to detect exit cause + atomic_t join_state; // flags used to detect exit cause std::condition_variable cv; // used to signal waiting PPU thread std::weak_ptr ep_run; // port for SYS_SPU_THREAD_GROUP_EVENT_RUN events @@ -177,30 +171,24 @@ struct lv2_spu_group_t { } - void send_run_event(lv2_lock_t& lv2_lock, u64 data1, u64 data2, u64 data3) + void send_run_event(lv2_lock_t lv2_lock, u64 data1, u64 data2, u64 data3) { - CHECK_LV2_LOCK(lv2_lock); - if (const auto queue = ep_run.lock()) { queue->push(lv2_lock, SYS_SPU_THREAD_GROUP_EVENT_RUN_KEY, data1, data2, data3); } } - void send_exception_event(lv2_lock_t& lv2_lock, u64 data1, u64 data2, u64 data3) + void send_exception_event(lv2_lock_t lv2_lock, u64 data1, u64 data2, u64 data3) { - CHECK_LV2_LOCK(lv2_lock); - if (const auto queue = ep_exception.lock()) { queue->push(lv2_lock, SYS_SPU_THREAD_GROUP_EVENT_EXCEPTION_KEY, data1, data2, data3); } } - void send_sysmodule_event(lv2_lock_t& lv2_lock, u64 data1, u64 data2, u64 data3) + void send_sysmodule_event(lv2_lock_t lv2_lock, u64 data1, u64 data2, u64 data3) { - CHECK_LV2_LOCK(lv2_lock); - if (const auto queue = ep_sysmodule.lock()) { queue->push(lv2_lock, SYS_SPU_THREAD_GROUP_EVENT_SYSTEM_MODULE_KEY, data1, data2, data3); @@ -208,20 +196,17 @@ struct lv2_spu_group_t } }; -struct vfsStream; class PPUThread; -void LoadSpuImage(vfsStream& stream, u32& spu_ep, u32 addr); -u32 LoadSpuImage(vfsStream& stream, u32& spu_ep); - // Aux -s32 spu_image_import(sys_spu_image& img, u32 src, u32 type); +void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr); +u32 LoadSpuImage(const fs::file& stream, u32& spu_ep); // SysCalls s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu); -s32 sys_spu_image_open(vm::ptr img, vm::cptr path); -s32 sys_spu_image_close(vm::ptr img); -s32 sys_spu_thread_initialize(vm::ptr thread, u32 group, u32 spu_num, vm::ptr img, vm::ptr attr, vm::ptr arg); +s32 sys_spu_image_open(vm::ptr img, vm::cptr path); +s32 sys_spu_image_close(vm::ptr img); +s32 sys_spu_thread_initialize(vm::ptr thread, u32 group, u32 spu_num, vm::ptr img, vm::ptr attr, vm::ptr arg); s32 sys_spu_thread_set_argument(u32 id, vm::ptr arg); s32 sys_spu_thread_group_create(vm::ptr id, u32 num, s32 prio, vm::ptr attr); s32 sys_spu_thread_group_destroy(u32 id); diff --git a/rpcs3/Emu/Cell/lv2/sys_sync.h b/rpcs3/Emu/Cell/lv2/sys_sync.h new file mode 100644 index 0000000000..37b147e472 --- /dev/null +++ b/rpcs3/Emu/Cell/lv2/sys_sync.h @@ -0,0 +1,113 @@ +#pragma once + +#include "Utilities/SharedMutex.h" +#include "Utilities/SleepQueue.h" + +namespace vm { using namespace ps3; } + +// attr_protocol (waiting scheduling policy) +enum +{ + // First In, First Out + SYS_SYNC_FIFO = 1, + // Priority Order + SYS_SYNC_PRIORITY = 2, + // Basic Priority Inheritance Protocol (probably not implemented) + SYS_SYNC_PRIORITY_INHERIT = 3, + // Not selected while unlocking + SYS_SYNC_RETRY = 4, + // + SYS_SYNC_ATTR_PROTOCOL_MASK = 0xF, +}; + +// attr_recursive (recursive locks policy) +enum +{ + // Recursive locks are allowed + SYS_SYNC_RECURSIVE = 0x10, + // Recursive locks are NOT allowed + SYS_SYNC_NOT_RECURSIVE = 0x20, + // + SYS_SYNC_ATTR_RECURSIVE_MASK = 0xF0, //??? +}; + +// attr_pshared +enum +{ + SYS_SYNC_NOT_PROCESS_SHARED = 0x200, +}; + +// attr_adaptive +enum +{ + SYS_SYNC_ADAPTIVE = 0x1000, + SYS_SYNC_NOT_ADAPTIVE = 0x2000, +}; + +// IPC manager collection for lv2 objects of type T +template +class ipc_manager final +{ + mutable shared_mutex m_mutex; + std::unordered_map> m_map; + +public: + // Add new object if specified ipc_key is not used + template + auto add(u64 ipc_key, F&& provider) -> decltype(static_cast>(provider())) + { + std::lock_guard lock(m_mutex); + + // Get object location + std::weak_ptr& wptr = m_map[ipc_key]; + + if (wptr.expired()) + { + // Call a function which must return the object + std::shared_ptr&& result = provider(); + wptr = result; + return result; + } + + return{}; + } + + // Get existing object with specified ipc_key + std::shared_ptr get(u64 ipc_key) const + { + reader_lock lock(m_mutex); + + const auto found = m_map.find(ipc_key); + + if (found != m_map.end()) + { + return found->second.lock(); + } + + return{}; + } +}; + +// Simple class for global mutex to pass unique_lock and check it +struct lv2_lock_t +{ + using type = std::unique_lock; + + type& ref; + + lv2_lock_t(type& lv2_lock) + : ref(lv2_lock) + { + Expects(ref.owns_lock()); + Expects(ref.mutex() == &mutex); + } + + operator type&() const + { + return ref; + } + + static type::mutex_type mutex; +}; + +#define LV2_LOCK lv2_lock_t::type lv2_lock(lv2_lock_t::mutex) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_time.cpp b/rpcs3/Emu/Cell/lv2/sys_time.cpp similarity index 97% rename from rpcs3/Emu/SysCalls/lv2/sys_time.cpp rename to rpcs3/Emu/Cell/lv2/sys_time.cpp index bdaed94974..39f4b1a156 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_time.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_time.cpp @@ -1,8 +1,9 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_time.h" #ifdef _WIN32 @@ -44,7 +45,7 @@ const g_time_aux_info = []() -> time_aux_info_t // initialize time-related value #endif -SysCallBase sys_time("sys_time"); +LOG_CHANNEL(sys_time); static const u64 g_timebase_freq = /*79800000*/ 80000000; // 80 Mhz diff --git a/rpcs3/Emu/SysCalls/lv2/sys_time.h b/rpcs3/Emu/Cell/lv2/sys_time.h similarity index 100% rename from rpcs3/Emu/SysCalls/lv2/sys_time.h rename to rpcs3/Emu/Cell/lv2/sys_time.h diff --git a/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp b/rpcs3/Emu/Cell/lv2/sys_timer.cpp similarity index 94% rename from rpcs3/Emu/SysCalls/lv2/sys_timer.cpp rename to rpcs3/Emu/Cell/lv2/sys_timer.cpp index 6fa2ba5001..3f8c8f78fc 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_timer.cpp @@ -1,15 +1,15 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" -#include "Utilities/Thread.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_event.h" #include "sys_process.h" #include "sys_timer.h" -SysCallBase sys_timer("sys_timer"); +LOG_CHANNEL(sys_timer); extern u64 get_system_time(); @@ -59,11 +59,6 @@ void lv2_timer_t::on_task() } } -lv2_timer_t::lv2_timer_t() - : id(idm::get_last_id()) -{ -} - s32 sys_timer_create(vm::ptr timer_id) { sys_timer.warning("sys_timer_create(timer_id=*0x%x)", timer_id); @@ -199,8 +194,8 @@ s32 sys_timer_connect_event_queue(u32 timer_id, u32 queue_id, u64 name, u64 data LV2_LOCK; - const auto timer(idm::get(timer_id)); - const auto queue(idm::get(queue_id)); + const auto timer = idm::get(timer_id); + const auto queue = idm::get(queue_id); if (!timer || !queue) { @@ -269,7 +264,7 @@ s32 sys_timer_sleep(u32 sleep_time) return CELL_OK; } -s32 sys_timer_usleep(u64 sleep_time) +s32 sys_timer_usleep(const u64 sleep_time) { sys_timer.trace("sys_timer_usleep(sleep_time=0x%llx)", sleep_time); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_timer.h b/rpcs3/Emu/Cell/lv2/sys_timer.h similarity index 63% rename from rpcs3/Emu/SysCalls/lv2/sys_timer.h rename to rpcs3/Emu/Cell/lv2/sys_timer.h index 5d1e32c68c..a0bcbba701 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_timer.h +++ b/rpcs3/Emu/Cell/lv2/sys_timer.h @@ -19,35 +19,36 @@ struct sys_timer_information_t be_t pad; }; -class lv2_timer_t final : public named_thread_t +class lv2_timer_t final : public named_thread { void on_task() override; - void on_id_aux_finalize() override +public: + std::string get_name() const override + { + return fmt::format("Timer Thread[0x%x]", id); + } + + void on_stop() override { // Signal thread using invalid state and join - { std::lock_guard{mutex}, state = -1; } + std::lock_guard{ mutex }, state = -1; cv.notify_one(); join(); } -public: - lv2_timer_t(); + const u32 id{}; // Timer id - std::string get_name() const override { return fmt::format("Timer Thread[0x%x]", id); } + atomic_t state{ SYS_TIMER_STATE_RUN }; // Timer state - const u32 id; - - std::weak_ptr port; // event queue - u64 source; // event source - u64 data1; // event arg 1 - u64 data2; // event arg 2 + std::weak_ptr port; // Event queue + u64 source; // Event source + u64 data1; // Event arg 1 + u64 data2; // Event arg 2 - u64 expire = 0; // next expiration time - u64 period = 0; // period (oneshot if 0) - - std::atomic state{ SYS_TIMER_STATE_RUN }; // timer state + u64 expire = 0; // Next expiration time + u64 period = 0; // Period (oneshot if 0) }; s32 sys_timer_create(vm::ptr timer_id); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_trace.cpp b/rpcs3/Emu/Cell/lv2/sys_trace.cpp similarity index 91% rename from rpcs3/Emu/SysCalls/lv2/sys_trace.cpp rename to rpcs3/Emu/Cell/lv2/sys_trace.cpp index f7b3d29c7e..78a10eb063 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_trace.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_trace.cpp @@ -1,11 +1,12 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_trace.h" -SysCallBase sys_trace("sys_trace"); +LOG_CHANNEL(sys_trace); s32 sys_trace_create() { diff --git a/rpcs3/Emu/SysCalls/lv2/sys_trace.h b/rpcs3/Emu/Cell/lv2/sys_trace.h similarity index 100% rename from rpcs3/Emu/SysCalls/lv2/sys_trace.h rename to rpcs3/Emu/Cell/lv2/sys_trace.h diff --git a/rpcs3/Emu/SysCalls/lv2/sys_tty.cpp b/rpcs3/Emu/Cell/lv2/sys_tty.cpp similarity index 89% rename from rpcs3/Emu/SysCalls/lv2/sys_tty.cpp rename to rpcs3/Emu/Cell/lv2/sys_tty.cpp index 8dadf61685..bdbe5fa49f 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_tty.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_tty.cpp @@ -1,11 +1,12 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_tty.h" -SysCallBase sys_tty("sys_tty"); +LOG_CHANNEL(sys_tty); s32 sys_tty_read(s32 ch, vm::ptr buf, u32 len, vm::ptr preadlen) { diff --git a/rpcs3/Emu/SysCalls/lv2/sys_tty.h b/rpcs3/Emu/Cell/lv2/sys_tty.h similarity index 100% rename from rpcs3/Emu/SysCalls/lv2/sys_tty.h rename to rpcs3/Emu/Cell/lv2/sys_tty.h diff --git a/rpcs3/Emu/SysCalls/lv2/sys_vm.cpp b/rpcs3/Emu/Cell/lv2/sys_vm.cpp similarity index 96% rename from rpcs3/Emu/SysCalls/lv2/sys_vm.cpp rename to rpcs3/Emu/Cell/lv2/sys_vm.cpp index 3e9361bedb..22492efb6e 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_vm.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_vm.cpp @@ -1,13 +1,14 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/SysCalls/SysCalls.h" +#include "Emu/Cell/ErrorCodes.h" #include "sys_memory.h" #include "sys_vm.h" -SysCallBase sys_vm("sys_vm"); +LOG_CHANNEL(sys_vm); s32 sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr) { diff --git a/rpcs3/Emu/SysCalls/lv2/sys_vm.h b/rpcs3/Emu/Cell/lv2/sys_vm.h similarity index 97% rename from rpcs3/Emu/SysCalls/lv2/sys_vm.h rename to rpcs3/Emu/Cell/lv2/sys_vm.h index cce3134611..5c03b588d1 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_vm.h +++ b/rpcs3/Emu/Cell/lv2/sys_vm.h @@ -1,6 +1,6 @@ #pragma once -namespace vm { using namespace ps3; } +#include "sys_sync.h" enum : u64 { diff --git a/rpcs3/Emu/SysCalls/SysCalls.h b/rpcs3/Emu/SysCalls/SysCalls.h deleted file mode 100644 index 2415401100..0000000000 --- a/rpcs3/Emu/SysCalls/SysCalls.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "ErrorCodes.h" - -struct SysCallBase : public _log::channel -{ - SysCallBase(const std::string& name) - : _log::channel(name, _log::level::notice) - { - } -}; - -void execute_syscall_by_index(class PPUThread& ppu, u64 code); -std::string get_ps3_function_name(u64 fid); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_sync.h b/rpcs3/Emu/SysCalls/lv2/sys_sync.h deleted file mode 100644 index 76fc562eae..0000000000 --- a/rpcs3/Emu/SysCalls/lv2/sys_sync.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -namespace vm { using namespace ps3; } - -// attr_protocol (waiting scheduling policy) -enum -{ - // First In, First Out - SYS_SYNC_FIFO = 1, - // Priority Order - SYS_SYNC_PRIORITY = 2, - // Basic Priority Inheritance Protocol (probably not implemented) - SYS_SYNC_PRIORITY_INHERIT = 3, - // Not selected while unlocking - SYS_SYNC_RETRY = 4, - // - SYS_SYNC_ATTR_PROTOCOL_MASK = 0xF, -}; - -// attr_recursive (recursive locks policy) -enum -{ - // Recursive locks are allowed - SYS_SYNC_RECURSIVE = 0x10, - // Recursive locks are NOT allowed - SYS_SYNC_NOT_RECURSIVE = 0x20, - // - SYS_SYNC_ATTR_RECURSIVE_MASK = 0xF0, //??? -}; - -// attr_pshared -enum -{ - SYS_SYNC_NOT_PROCESS_SHARED = 0x200, -}; - -// attr_adaptive -enum -{ - SYS_SYNC_ADAPTIVE = 0x1000, - SYS_SYNC_NOT_ADAPTIVE = 0x2000, -}; From c4e99dbdb20225b9c08db40cb5ad3653ce92b1fa Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Thu, 14 Apr 2016 02:09:41 +0300 Subject: [PATCH 07/19] Partial commit: Cell --- rpcs3/Emu/Cell/Common.h | 13 - rpcs3/Emu/{SysCalls => Cell}/ErrorCodes.h | 151 +- .../Callback.cpp => Cell/PPUCallback.cpp} | 20 +- .../CB_FUNC.h => Cell/PPUCallback.h} | 97 +- rpcs3/Emu/Cell/PPUDisAsm.cpp | 2160 +++++++ rpcs3/Emu/Cell/PPUDisAsm.h | 2232 ++----- rpcs3/Emu/Cell/PPUFunction.cpp | 2379 ++++++++ .../SC_FUNC.h => Cell/PPUFunction.h} | 117 +- rpcs3/Emu/Cell/PPUInterpreter.cpp | 3334 ++++++----- rpcs3/Emu/Cell/PPUInterpreter.h | 5110 ++--------------- rpcs3/Emu/Cell/PPUInterpreter2.h | 870 --- rpcs3/Emu/Cell/PPUModule.cpp | 1152 ++++ rpcs3/Emu/Cell/PPUModule.h | 255 + rpcs3/Emu/Cell/PPUOpcodes.h | 1499 ++--- rpcs3/Emu/Cell/PPUThread.cpp | 411 +- rpcs3/Emu/Cell/PPUThread.h | 1026 +--- rpcs3/Emu/Cell/RawSPUThread.cpp | 45 +- rpcs3/Emu/Cell/RawSPUThread.h | 43 +- rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp | 38 +- rpcs3/Emu/Cell/SPUASMJITRecompiler.h | 6 +- rpcs3/Emu/Cell/SPUAnalyser.cpp | 40 +- rpcs3/Emu/Cell/SPUAnalyser.h | 430 +- rpcs3/Emu/Cell/SPUContext.h | 5 - rpcs3/Emu/Cell/SPUDisAsm.cpp | 11 + rpcs3/Emu/Cell/SPUDisAsm.h | 14 +- rpcs3/Emu/Cell/SPUInterpreter.cpp | 127 +- rpcs3/Emu/Cell/SPUInterpreter.h | 486 +- rpcs3/Emu/Cell/SPUOpcodes.h | 489 +- rpcs3/Emu/Cell/SPURecompiler.cpp | 39 +- rpcs3/Emu/Cell/SPURecompiler.h | 29 +- rpcs3/Emu/Cell/SPUThread.cpp | 396 +- rpcs3/Emu/Cell/SPUThread.h | 188 +- 32 files changed, 10685 insertions(+), 12527 deletions(-) rename rpcs3/Emu/{SysCalls => Cell}/ErrorCodes.h (53%) rename rpcs3/Emu/{SysCalls/Callback.cpp => Cell/PPUCallback.cpp} (80%) rename rpcs3/Emu/{SysCalls/CB_FUNC.h => Cell/PPUCallback.h} (61%) create mode 100644 rpcs3/Emu/Cell/PPUDisAsm.cpp create mode 100644 rpcs3/Emu/Cell/PPUFunction.cpp rename rpcs3/Emu/{SysCalls/SC_FUNC.h => Cell/PPUFunction.h} (68%) delete mode 100644 rpcs3/Emu/Cell/PPUInterpreter2.h create mode 100644 rpcs3/Emu/Cell/PPUModule.cpp create mode 100644 rpcs3/Emu/Cell/PPUModule.h delete mode 100644 rpcs3/Emu/Cell/SPUContext.h create mode 100644 rpcs3/Emu/Cell/SPUDisAsm.cpp diff --git a/rpcs3/Emu/Cell/Common.h b/rpcs3/Emu/Cell/Common.h index b24396f854..214af66bce 100644 --- a/rpcs3/Emu/Cell/Common.h +++ b/rpcs3/Emu/Cell/Common.h @@ -8,16 +8,3 @@ enum FPSCR_RN FPSCR_RN_PINF = 2, FPSCR_RN_MINF = 3, }; - -using ppu_inter_func_t = void(*)(class PPUThread& CPU, union ppu_opcode_t opcode); - -struct ppu_decoder_cache_t -{ - ppu_inter_func_t* const pointer; - - ppu_decoder_cache_t(); - - ~ppu_decoder_cache_t(); - - void initialize(u32 addr, u32 size); -}; diff --git a/rpcs3/Emu/SysCalls/ErrorCodes.h b/rpcs3/Emu/Cell/ErrorCodes.h similarity index 53% rename from rpcs3/Emu/SysCalls/ErrorCodes.h rename to rpcs3/Emu/Cell/ErrorCodes.h index 373c806539..05445a6aa0 100644 --- a/rpcs3/Emu/SysCalls/ErrorCodes.h +++ b/rpcs3/Emu/Cell/ErrorCodes.h @@ -2,10 +2,13 @@ #define ERROR_CODE(code) static_cast(code) -enum : s32 +enum CellOk : s32 { - CELL_OK = 0, + CELL_OK = 0, +}; +enum CellError : s32 +{ CELL_EAGAIN = ERROR_CODE(0x80010001), // The resource is temporarily unavailable CELL_EINVAL = ERROR_CODE(0x80010002), // An invalid argument value is specified CELL_ENOSYS = ERROR_CODE(0x80010003), // The feature is not yet implemented @@ -64,6 +67,146 @@ enum : s32 CELL_EOVERFLOW = ERROR_CODE(0x80010039), CELL_ENOTMOUNTED = ERROR_CODE(0x8001003A), CELL_ENOTSDATA = ERROR_CODE(0x8001003B), - - CELL_UNKNOWN_ERROR = -1, }; + +// Special return type signaling on errors +struct ppu_error_code +{ + s32 value; + + // Print error message, error code is returned + static s32 report(s32 error, const char* text); + + // Must be specialized for specific tag type T + template + static const char* print(T code) + { + return nullptr; + } + + template + s32 error_check(T code) + { + if (const auto text = print(code)) + { + return report(code, text); + } + + return code; + } + + ppu_error_code() = default; + + // General error check + template::value>> + ppu_error_code(T value) + : value(error_check(value)) + { + } + + // Force error reporting with a message specified + ppu_error_code(s32 value, const char* text) + : value(report(value, text)) + { + } + + // Silence any error + constexpr ppu_error_code(s32 value, const std::nothrow_t&) + : value(value) + { + } + + // Conversion + constexpr operator s32() const + { + return value; + } +}; + +// Helper macro for silencing possible error checks on returning ppu_error_code values +#define NOT_AN_ERROR(value) { static_cast(value), std::nothrow } + +template +struct ppu_gpr_cast_impl; + +template<> +struct ppu_gpr_cast_impl +{ + static inline u64 to(const ppu_error_code& code) + { + return code; + } + + static inline ppu_error_code from(const u64 reg) + { + return NOT_AN_ERROR(reg); + } +}; + +template<> +inline const char* ppu_error_code::print(CellError error) +{ + switch (error) + { + STR_CASE(CELL_EAGAIN); + STR_CASE(CELL_EINVAL); + STR_CASE(CELL_ENOSYS); + STR_CASE(CELL_ENOMEM); + STR_CASE(CELL_ESRCH); + STR_CASE(CELL_ENOENT); + STR_CASE(CELL_ENOEXEC); + STR_CASE(CELL_EDEADLK); + STR_CASE(CELL_EPERM); + STR_CASE(CELL_EBUSY); + STR_CASE(CELL_ETIMEDOUT); + STR_CASE(CELL_EABORT); + STR_CASE(CELL_EFAULT); + STR_CASE(CELL_ESTAT); + STR_CASE(CELL_EALIGN); + STR_CASE(CELL_EKRESOURCE); + STR_CASE(CELL_EISDIR); + STR_CASE(CELL_ECANCELED); + STR_CASE(CELL_EEXIST); + STR_CASE(CELL_EISCONN); + STR_CASE(CELL_ENOTCONN); + STR_CASE(CELL_EAUTHFAIL); + STR_CASE(CELL_ENOTMSELF); + STR_CASE(CELL_ESYSVER); + STR_CASE(CELL_EAUTHFATAL); + STR_CASE(CELL_EDOM); + STR_CASE(CELL_ERANGE); + STR_CASE(CELL_EILSEQ); + STR_CASE(CELL_EFPOS); + STR_CASE(CELL_EINTR); + STR_CASE(CELL_EFBIG); + STR_CASE(CELL_EMLINK); + STR_CASE(CELL_ENFILE); + STR_CASE(CELL_ENOSPC); + STR_CASE(CELL_ENOTTY); + STR_CASE(CELL_EPIPE); + STR_CASE(CELL_EROFS); + STR_CASE(CELL_ESPIPE); + STR_CASE(CELL_E2BIG); + STR_CASE(CELL_EACCES); + STR_CASE(CELL_EBADF); + STR_CASE(CELL_EIO); + STR_CASE(CELL_EMFILE); + STR_CASE(CELL_ENODEV); + STR_CASE(CELL_ENOTDIR); + STR_CASE(CELL_ENXIO); + STR_CASE(CELL_EXDEV); + STR_CASE(CELL_EBADMSG); + STR_CASE(CELL_EINPROGRESS); + STR_CASE(CELL_EMSGSIZE); + STR_CASE(CELL_ENAMETOOLONG); + STR_CASE(CELL_ENOLCK); + STR_CASE(CELL_ENOTEMPTY); + STR_CASE(CELL_ENOTSUP); + STR_CASE(CELL_EFSSPECIFIC); + STR_CASE(CELL_EOVERFLOW); + STR_CASE(CELL_ENOTMOUNTED); + STR_CASE(CELL_ENOTSDATA); + } + + return nullptr; +} diff --git a/rpcs3/Emu/SysCalls/Callback.cpp b/rpcs3/Emu/Cell/PPUCallback.cpp similarity index 80% rename from rpcs3/Emu/SysCalls/Callback.cpp rename to rpcs3/Emu/Cell/PPUCallback.cpp index d2146c161f..8ca6a675e0 100644 --- a/rpcs3/Emu/SysCalls/Callback.cpp +++ b/rpcs3/Emu/Cell/PPUCallback.cpp @@ -3,9 +3,8 @@ #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/Cell/PPUThread.h" -#include "Emu/ARMv7/ARMv7Thread.h" -#include "Callback.h" +#include "PPUThread.h" +#include "PPUCallback.h" void CallbackManager::Register(check_cb_t func) { @@ -79,17 +78,14 @@ void CallbackManager::Init() } }; - if (vm::get(vm::main)->addr == 0x10000) - { - auto thread = idm::make_ptr("Callback Thread"); + auto thread = idm::make_ptr("Callback Thread"); - thread->prio = 1001; - thread->stack_size = 0x10000; - thread->custom_task = task; - thread->run(); + thread->prio = 1001; + thread->stack_size = 0x10000; + thread->custom_task = task; + thread->cpu_init(); - m_cb_thread = thread; - } + m_cb_thread = thread; } void CallbackManager::Clear() diff --git a/rpcs3/Emu/SysCalls/CB_FUNC.h b/rpcs3/Emu/Cell/PPUCallback.h similarity index 61% rename from rpcs3/Emu/SysCalls/CB_FUNC.h rename to rpcs3/Emu/Cell/PPUCallback.h index 2d621439f2..66b3ce2449 100644 --- a/rpcs3/Emu/SysCalls/CB_FUNC.h +++ b/rpcs3/Emu/Cell/PPUCallback.h @@ -2,7 +2,7 @@ #include "Emu/Cell/PPUThread.h" -namespace cb_detail +namespace ppu_cb_detail { enum _func_arg_type { @@ -10,7 +10,7 @@ namespace cb_detail ARG_FLOAT, ARG_VECTOR, ARG_STACK, - ARG_CONTEXT, // for compatibility with SC_FUNC and CALL_FUNC + ARG_CONTEXT, ARG_UNKNOWN, }; @@ -19,7 +19,7 @@ namespace cb_detail // It's possible to calculate suitable stack frame size in template, but too complicated. static const auto FIXED_STACK_FRAME_SIZE = 0x90; - template + template struct _func_arg { static_assert(type == ARG_GENERAL, "Unknown callback argument type"); @@ -27,50 +27,48 @@ namespace cb_detail static_assert(!std::is_reference::value, "Invalid callback argument type (reference)"); static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_GENERAL"); - force_inline static void set_value(PPUThread& CPU, const T& arg) + static inline void set_value(PPUThread& CPU, const T& arg) { - CPU.GPR[g_count + 2] = cast_to_ppu_gpr(arg); + CPU.GPR[g_count + 2] = ppu_gpr_cast(arg); } }; - template + template struct _func_arg { static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_FLOAT"); - force_inline static void set_value(PPUThread& CPU, const T& arg) + static inline void set_value(PPUThread& CPU, const T& arg) { CPU.FPR[f_count] = static_cast(arg); } }; - template + template struct _func_arg { - static_assert(std::is_same, v128>::value, "Invalid callback argument type for ARG_VECTOR"); + static_assert(std::is_same::value, "Invalid callback argument type for ARG_VECTOR"); - force_inline static void set_value(PPUThread& CPU, const T& arg) + static inline void set_value(PPUThread& CPU, const T& arg) { - CPU.VPR[v_count + 1] = arg; + CPU.VR[v_count + 1] = arg; } }; - template + template struct _func_arg { - static_assert(f_count <= 13, "TODO: Unsupported stack argument type (float)"); - static_assert(v_count <= 12, "TODO: Unsupported stack argument type (vector)"); - static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_STACK"); + static_assert(alignof(T) <= 16, "Unsupported callback argument type alignment for ARG_STACK"); - force_inline static void set_value(PPUThread& CPU, const T& arg) + static inline void set_value(PPUThread& CPU, const T& arg) { - const int stack_pos = (g_count - 9) * 8 - FIXED_STACK_FRAME_SIZE; - static_assert(stack_pos < 0, "TODO: Increase fixed stack frame size (arg count limit broken)"); - vm::ps3::write64(CPU.GPR[1] + stack_pos, cast_to_ppu_gpr(arg)); + const s64 stack_pos = (g_count - 1) * 0x8 + 0x30 - FIXED_STACK_FRAME_SIZE; + static_assert(stack_pos < 0, "TODO: Increase FIXED_STACK_FRAME_SIZE (arg count limit broken)"); + vm::ps3::write64(CPU.GPR[1] + stack_pos, ppu_gpr_cast(arg)); // TODO } }; - template + template struct _func_arg { static_assert(std::is_same::value, "Invalid callback argument type for ARG_CONTEXT"); @@ -80,18 +78,18 @@ namespace cb_detail } }; - template + template force_inline static bool _bind_func_args(PPUThread& CPU) { // terminator return false; } - template + template force_inline static bool _bind_func_args(PPUThread& CPU, T1 arg1, T... args) { const bool is_float = std::is_floating_point::value; - const bool is_vector = std::is_same, v128>::value; + const bool is_vector = std::is_same::value; const bool is_context = std::is_same::value; const bool is_general = !is_float && !is_vector && !is_context; @@ -102,9 +100,9 @@ namespace cb_detail is_context ? ARG_CONTEXT : ARG_UNKNOWN; - const int g = g_count + is_general; - const int f = f_count + is_float; - const int v = v_count + is_vector; + const u32 g = g_count + (is_general || is_float ? 1 : is_vector ? ::align(g_count, 2) + 2 : 0); + const u32 f = f_count + is_float; + const u32 v = v_count + is_vector; _func_arg::set_value(CPU, arg1); @@ -120,7 +118,7 @@ namespace cb_detail force_inline static T get_value(const PPUThread& CPU) { - return cast_from_ppu_gpr(CPU.GPR[3]); + return ppu_gpr_cast(CPU.GPR[3]); } }; @@ -138,11 +136,11 @@ namespace cb_detail template struct _func_res { - static_assert(std::is_same, v128>::value, "Invalid callback result type for ARG_VECTOR"); + static_assert(std::is_same::value, "Invalid callback result type for ARG_VECTOR"); force_inline static T get_value(const PPUThread& CPU) { - return CPU.VPR[2]; + return CPU.VR[2]; } }; @@ -169,11 +167,9 @@ namespace cb_detail force_inline static void call(PPUThread& CPU, u32 pc, u32 rtoc, T... args) { const bool stack = _bind_func_args<0, 0, 0, T...>(CPU, args...); - if (stack) CPU.GPR[1] -= FIXED_STACK_FRAME_SIZE; - CPU.GPR[1] -= 0x70; // create reserved area + CPU.GPR[1] -= stack ? FIXED_STACK_FRAME_SIZE : 0x30; // create reserved area CPU.fast_call(pc, rtoc); - CPU.GPR[1] += 0x70; - if (stack) CPU.GPR[1] += FIXED_STACK_FRAME_SIZE; + CPU.GPR[1] += stack ? FIXED_STACK_FRAME_SIZE : 0x30; } }; } @@ -183,15 +179,44 @@ namespace vm template force_inline RT _ptr_base::operator()(PPUThread& CPU, T... args) const { - const auto data = vm::ps3::_ptr(VM_CAST(m_addr)); + const auto data = vm::ps3::_ptr(vm::cast(m_addr, HERE)); const u32 pc = data[0]; const u32 rtoc = data[1]; - return cb_detail::_func_caller::call(CPU, pc, rtoc, args...); + return ppu_cb_detail::_func_caller::call(CPU, pc, rtoc, args...); } } template inline RT cb_call(PPUThread& CPU, u32 pc, u32 rtoc, T... args) { - return cb_detail::_func_caller::call(CPU, pc, rtoc, args...); + return ppu_cb_detail::_func_caller::call(CPU, pc, rtoc, args...); } + +#include + +class CallbackManager +{ + using check_cb_t = std::function; + using async_cb_t = std::function; + + std::mutex m_mutex; + + std::queue m_check_cb; + std::queue m_async_cb; + + std::shared_ptr m_cb_thread; + +public: + // Register checked callback + void Register(check_cb_t func); + + // Register async callback, called in callback thread + void Async(async_cb_t func); + + // Get one registered callback + check_cb_t Check(); + + void Init(); + + void Clear(); +}; diff --git a/rpcs3/Emu/Cell/PPUDisAsm.cpp b/rpcs3/Emu/Cell/PPUDisAsm.cpp new file mode 100644 index 0000000000..31a1cfa48d --- /dev/null +++ b/rpcs3/Emu/Cell/PPUDisAsm.cpp @@ -0,0 +1,2160 @@ +#include "stdafx.h" +#include "PPUDisAsm.h" + +const ppu_decoder s_ppu_disasm; + +u32 PPUDisAsm::disasm(u32 pc) +{ + const u32 op = *(be_t*)(offset + pc); + (this->*(s_ppu_disasm.decode(op)))({ op }); + return 4; +} + +void PPUDisAsm::TDI(ppu_opcode_t op) +{ + DisAsm_INT1_R1_IMM("tdi", op.bo, op.ra, op.simm16); +} + +void PPUDisAsm::TWI(ppu_opcode_t op) +{ + DisAsm_INT1_R1_IMM("twi", op.bo, op.ra, op.simm16); +} + +void PPUDisAsm::MFVSCR(ppu_opcode_t op) +{ + DisAsm_V1("mfvscr", op.vd); +} + +void PPUDisAsm::MTVSCR(ppu_opcode_t op) +{ + DisAsm_V1("mtvscr", op.vb); +} + +void PPUDisAsm::VADDCUW(ppu_opcode_t op) +{ + DisAsm_V3("vaddcuw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDFP(ppu_opcode_t op) +{ + DisAsm_V3("vaddfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDSBS(ppu_opcode_t op) +{ + DisAsm_V3("vaddsbs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDSHS(ppu_opcode_t op) +{ + DisAsm_V3("vaddshs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDSWS(ppu_opcode_t op) +{ + DisAsm_V3("vaddsws", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDUBM(ppu_opcode_t op) +{ + DisAsm_V3("vaddubm", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDUBS(ppu_opcode_t op) +{ + DisAsm_V3("vaddubs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDUHM(ppu_opcode_t op) +{ + DisAsm_V3("vadduhm", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDUHS(ppu_opcode_t op) +{ + DisAsm_V3("vadduhs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDUWM(ppu_opcode_t op) +{ + DisAsm_V3("vadduwm", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDUWS(ppu_opcode_t op) +{ + DisAsm_V3("vadduws", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAND(ppu_opcode_t op) +{ + DisAsm_V3("vand", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VANDC(ppu_opcode_t op) +{ + DisAsm_V3("vandc", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAVGSB(ppu_opcode_t op) +{ + DisAsm_V3("vavgsb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAVGSH(ppu_opcode_t op) +{ + DisAsm_V3("vavgsh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAVGSW(ppu_opcode_t op) +{ + DisAsm_V3("vavgsw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAVGUB(ppu_opcode_t op) +{ + DisAsm_V3("vavgub", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAVGUH(ppu_opcode_t op) +{ + DisAsm_V3("vavguh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAVGUW(ppu_opcode_t op) +{ + DisAsm_V3("vavguw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCFSX(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vcfsx", op.vd, op.vb, op.vuimm); +} + +void PPUDisAsm::VCFUX(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vcfux", op.vd, op.vb, op.vuimm); +} + +void PPUDisAsm::VCMPBFP(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpbfp." : "vcmpbfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPEQFP(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpeqfp." : "vcmpeqfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPEQUB(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpequb." : "vcmpequb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPEQUH(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpequh." : "vcmpequh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPEQUW(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpequw." : "vcmpequw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGEFP(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgefp." : "vcmpgefp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTFP(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtfp." : "vcmpgtfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTSB(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtsb." : "vcmpgtsb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTSH(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtsh." : "vcmpgtsh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTSW(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtsw." : "vcmpgtsw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTUB(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtub." : "vcmpgtub", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTUH(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtuh." : "vcmpgtuh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTUW(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtuw." : "vcmpgtuw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCTSXS(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vctsxs", op.vd, op.vb, op.vuimm); +} + +void PPUDisAsm::VCTUXS(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vctuxs", op.vd, op.vb, op.vuimm); +} + +void PPUDisAsm::VEXPTEFP(ppu_opcode_t op) +{ + DisAsm_V2("vexptefp", op.vd, op.vb); +} + +void PPUDisAsm::VLOGEFP(ppu_opcode_t op) +{ + DisAsm_V2("vlogefp", op.vd, op.vb); +} + +void PPUDisAsm::VMADDFP(ppu_opcode_t op) +{ + DisAsm_V4("vmaddfp", op.vd, op.va, op.vc, op.vb); +} + +void PPUDisAsm::VMAXFP(ppu_opcode_t op) +{ + DisAsm_V3("vmaxfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMAXSB(ppu_opcode_t op) +{ + DisAsm_V3("vmaxsb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMAXSH(ppu_opcode_t op) +{ + DisAsm_V3("vmaxsh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMAXSW(ppu_opcode_t op) +{ + DisAsm_V3("vmaxsw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMAXUB(ppu_opcode_t op) +{ + DisAsm_V3("vmaxub", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMAXUH(ppu_opcode_t op) +{ + DisAsm_V3("vmaxuh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMAXUW(ppu_opcode_t op) +{ + DisAsm_V3("vmaxuw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMHADDSHS(ppu_opcode_t op) +{ + DisAsm_V4("vmhaddshs", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMHRADDSHS(ppu_opcode_t op) +{ + DisAsm_V4("vmhraddshs", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMINFP(ppu_opcode_t op) +{ + DisAsm_V3("vminfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMINSB(ppu_opcode_t op) +{ + DisAsm_V3("vminsb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMINSH(ppu_opcode_t op) +{ + DisAsm_V3("vminsh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMINSW(ppu_opcode_t op) +{ + DisAsm_V3("vminsw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMINUB(ppu_opcode_t op) +{ + DisAsm_V3("vminub", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMINUH(ppu_opcode_t op) +{ + DisAsm_V3("vminuh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMINUW(ppu_opcode_t op) +{ + DisAsm_V3("vminuw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMLADDUHM(ppu_opcode_t op) +{ + DisAsm_V4("vmladduhm", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMRGHB(ppu_opcode_t op) +{ + DisAsm_V3("vmrghb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMRGHH(ppu_opcode_t op) +{ + DisAsm_V3("vmrghh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMRGHW(ppu_opcode_t op) +{ + DisAsm_V3("vmrghw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMRGLB(ppu_opcode_t op) +{ + DisAsm_V3("vmrglb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMRGLH(ppu_opcode_t op) +{ + DisAsm_V3("vmrglh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMRGLW(ppu_opcode_t op) +{ + DisAsm_V3("vmrglw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMSUMMBM(ppu_opcode_t op) +{ + DisAsm_V4("vmsummbm", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMSUMSHM(ppu_opcode_t op) +{ + DisAsm_V4("vmsumshm", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMSUMSHS(ppu_opcode_t op) +{ + DisAsm_V4("vmsumshs", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMSUMUBM(ppu_opcode_t op) +{ + DisAsm_V4("vmsumubm", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMSUMUHM(ppu_opcode_t op) +{ + DisAsm_V4("vmsumuhm", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMSUMUHS(ppu_opcode_t op) +{ + DisAsm_V4("vmsumuhs", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMULESB(ppu_opcode_t op) +{ + DisAsm_V3("vmulesb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULESH(ppu_opcode_t op) +{ + DisAsm_V3("vmulesh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULEUB(ppu_opcode_t op) +{ + DisAsm_V3("vmuleub", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULEUH(ppu_opcode_t op) +{ + DisAsm_V3("vmuleuh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULOSB(ppu_opcode_t op) +{ + DisAsm_V3("vmulosb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULOSH(ppu_opcode_t op) +{ + DisAsm_V3("vmulosh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULOUB(ppu_opcode_t op) +{ + DisAsm_V3("vmuloub", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULOUH(ppu_opcode_t op) +{ + DisAsm_V3("vmulouh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VNMSUBFP(ppu_opcode_t op) +{ + DisAsm_V4("vnmsubfp", op.vd, op.va, op.vc, op.vb); +} + +void PPUDisAsm::VNOR(ppu_opcode_t op) +{ + DisAsm_V3("vnor", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VOR(ppu_opcode_t op) +{ + DisAsm_V3("vor", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPERM(ppu_opcode_t op) +{ + DisAsm_V4("vperm", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VPKPX(ppu_opcode_t op) +{ + DisAsm_V3("vpkpx", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKSHSS(ppu_opcode_t op) +{ + DisAsm_V3("vpkshss", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKSHUS(ppu_opcode_t op) +{ + DisAsm_V3("vpkshus", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKSWSS(ppu_opcode_t op) +{ + DisAsm_V3("vpkswss", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKSWUS(ppu_opcode_t op) +{ + DisAsm_V3("vpkswus", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKUHUM(ppu_opcode_t op) +{ + DisAsm_V3("vpkuhum", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKUHUS(ppu_opcode_t op) +{ + DisAsm_V3("vpkuhus", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKUWUM(ppu_opcode_t op) +{ + DisAsm_V3("vpkuwum", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKUWUS(ppu_opcode_t op) +{ + DisAsm_V3("vpkuwus", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VREFP(ppu_opcode_t op) +{ + DisAsm_V2("vrefp", op.vd, op.vb); +} + +void PPUDisAsm::VRFIM(ppu_opcode_t op) +{ + DisAsm_V2("vrfim", op.vd, op.vb); +} + +void PPUDisAsm::VRFIN(ppu_opcode_t op) +{ + DisAsm_V2("vrfin", op.vd, op.vb); +} + +void PPUDisAsm::VRFIP(ppu_opcode_t op) +{ + DisAsm_V2("vrfip", op.vd, op.vb); +} + +void PPUDisAsm::VRFIZ(ppu_opcode_t op) +{ + DisAsm_V2("vrfiz", op.vd, op.vb); +} + +void PPUDisAsm::VRLB(ppu_opcode_t op) +{ + DisAsm_V3("vrlb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VRLH(ppu_opcode_t op) +{ + DisAsm_V3("vrlh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VRLW(ppu_opcode_t op) +{ + DisAsm_V3("vrlw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VRSQRTEFP(ppu_opcode_t op) +{ + DisAsm_V2("vrsqrtefp", op.vd, op.vb); +} + +void PPUDisAsm::VSEL(ppu_opcode_t op) +{ + DisAsm_V4("vsel", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VSL(ppu_opcode_t op) +{ + DisAsm_V3("vsl", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSLB(ppu_opcode_t op) +{ + DisAsm_V3("vslb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSLDOI(ppu_opcode_t op) +{ + DisAsm_V3_UIMM("vsldoi", op.vd, op.va, op.vb, op.vsh); +} + +void PPUDisAsm::VSLH(ppu_opcode_t op) +{ + DisAsm_V3("vslh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSLO(ppu_opcode_t op) +{ + DisAsm_V3("vslo", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSLW(ppu_opcode_t op) +{ + DisAsm_V3("vslw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSPLTB(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vspltb", op.vd, op.vb, op.vuimm & 0xf); +} + +void PPUDisAsm::VSPLTH(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vsplth", op.vd, op.vb, op.vuimm & 0x7); +} + +void PPUDisAsm::VSPLTISB(ppu_opcode_t op) +{ + DisAsm_V1_SIMM("vspltisb", op.vd, op.vsimm); +} + +void PPUDisAsm::VSPLTISH(ppu_opcode_t op) +{ + DisAsm_V1_SIMM("vspltish", op.vd, op.vsimm); +} + +void PPUDisAsm::VSPLTISW(ppu_opcode_t op) +{ + DisAsm_V1_SIMM("vspltisw", op.vd, op.vsimm); +} + +void PPUDisAsm::VSPLTW(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vspltw", op.vd, op.vb, op.vuimm & 0x3); +} + +void PPUDisAsm::VSR(ppu_opcode_t op) +{ + DisAsm_V3("vsr", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRAB(ppu_opcode_t op) +{ + DisAsm_V3("vsrab", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRAH(ppu_opcode_t op) +{ + DisAsm_V3("vsrah", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRAW(ppu_opcode_t op) +{ + DisAsm_V3("vsraw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRB(ppu_opcode_t op) +{ + DisAsm_V3("vsrb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRH(ppu_opcode_t op) +{ + DisAsm_V3("vsrh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRO(ppu_opcode_t op) +{ + DisAsm_V3("vsro", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRW(ppu_opcode_t op) +{ + DisAsm_V3("vsrw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBCUW(ppu_opcode_t op) +{ + DisAsm_V3("vsubcuw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBFP(ppu_opcode_t op) +{ + DisAsm_V3("vsubfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBSBS(ppu_opcode_t op) +{ + DisAsm_V3("vsubsbs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBSHS(ppu_opcode_t op) +{ + DisAsm_V3("vsubshs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBSWS(ppu_opcode_t op) +{ + DisAsm_V3("vsubsws", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBUBM(ppu_opcode_t op) +{ + DisAsm_V3("vsububm", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBUBS(ppu_opcode_t op) +{ + DisAsm_V3("vsububs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBUHM(ppu_opcode_t op) +{ + DisAsm_V3("vsubuhm", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBUHS(ppu_opcode_t op) +{ + DisAsm_V3("vsubuhs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBUWM(ppu_opcode_t op) +{ + DisAsm_V3("vsubuwm", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBUWS(ppu_opcode_t op) +{ + DisAsm_V3("vsubuws", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUMSWS(ppu_opcode_t op) +{ + DisAsm_V3("vsumsws", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUM2SWS(ppu_opcode_t op) +{ + DisAsm_V3("vsum2sws", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUM4SBS(ppu_opcode_t op) +{ + DisAsm_V3("vsum4sbs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUM4SHS(ppu_opcode_t op) +{ + DisAsm_V3("vsum4shs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUM4UBS(ppu_opcode_t op) +{ + DisAsm_V3("vsum4ubs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VUPKHPX(ppu_opcode_t op) +{ + DisAsm_V2("vupkhpx", op.vd, op.vb); +} + +void PPUDisAsm::VUPKHSB(ppu_opcode_t op) +{ + DisAsm_V2("vupkhsb", op.vd, op.vb); +} + +void PPUDisAsm::VUPKHSH(ppu_opcode_t op) +{ + DisAsm_V2("vupkhsh", op.vd, op.vb); +} + +void PPUDisAsm::VUPKLPX(ppu_opcode_t op) +{ + DisAsm_V2("vupklpx", op.vd, op.vb); +} + +void PPUDisAsm::VUPKLSB(ppu_opcode_t op) +{ + DisAsm_V2("vupklsb", op.vd, op.vb); +} + +void PPUDisAsm::VUPKLSH(ppu_opcode_t op) +{ + DisAsm_V2("vupklsh", op.vd, op.vb); +} + +void PPUDisAsm::VXOR(ppu_opcode_t op) +{ + DisAsm_V3("vxor", op.vd, op.va, op.vb); +} + +void PPUDisAsm::MULLI(ppu_opcode_t op) +{ + DisAsm_R2_IMM("mulli", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::SUBFIC(ppu_opcode_t op) +{ + DisAsm_R2_IMM("subfic", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::CMPLI(ppu_opcode_t op) +{ + DisAsm_CR1_R1_IMM(op.l10 ? "cmpdi" : "cmpwi", op.crfd, op.ra, op.uimm16); +} + +void PPUDisAsm::CMPI(ppu_opcode_t op) +{ + DisAsm_CR1_R1_IMM(op.l10 ? "cmpdi" : "cmpwi", op.crfd, op.ra, op.simm16); +} + +void PPUDisAsm::ADDIC(ppu_opcode_t op) +{ + DisAsm_R2_IMM(op.main & 1 ? "addic." : "addic", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::ADDI(ppu_opcode_t op) +{ + if (op.ra == 0) + { + DisAsm_R1_IMM("li", op.rd, op.simm16); + } + else + { + DisAsm_R2_IMM("addi", op.rd, op.ra, op.simm16); + } +} + +void PPUDisAsm::ADDIS(ppu_opcode_t op) +{ + if (op.ra == 0) + { + DisAsm_R1_IMM("lis", op.rd, op.simm16); + } + else + { + DisAsm_R2_IMM("addis", op.rd, op.ra, op.simm16); + } +} + +void PPUDisAsm::BC(ppu_opcode_t op) +{ + const u32 bo = op.bo; + const u32 bi = op.bi; + const s32 bd = op.ds * 4; + const u32 aa = op.aa; + const u32 lk = op.lk; + + if (m_mode == CPUDisAsm_CompilerElfMode) + { + Write(fmt::format("bc 0x%x, 0x%x, 0x%x, %d, %d", bo, bi, bd, aa, lk)); + return; + } + + //TODO: aa lk + const u8 bo0 = (bo & 0x10) ? 1 : 0; + const u8 bo1 = (bo & 0x08) ? 1 : 0; + const u8 bo2 = (bo & 0x04) ? 1 : 0; + const u8 bo3 = (bo & 0x02) ? 1 : 0; + const u8 bo4 = (bo & 0x01) ? 1 : 0; + + if (bo0 && !bo1 && !bo2 && bo3 && !bo4) + { + DisAsm_CR_BRANCH("bdz", bi / 4, bd); return; + } + else if (bo0 && bo1 && !bo2 && bo3 && !bo4) + { + DisAsm_CR_BRANCH("bdz-", bi / 4, bd); return; + } + else if (bo0 && bo1 && !bo2 && bo3 && bo4) + { + DisAsm_CR_BRANCH("bdz+", bi / 4, bd); return; + } + else if (bo0 && !bo1 && !bo2 && !bo3 && !bo4) + { + DisAsm_CR_BRANCH("bdnz", bi / 4, bd); return; + } + else if (bo0 && bo1 && !bo2 && !bo3 && !bo4) + { + DisAsm_CR_BRANCH("bdnz-", bi / 4, bd); return; + } + else if (bo0 && bo1 && !bo2 && !bo3 && bo4) + { + DisAsm_CR_BRANCH("bdnz+", bi / 4, bd); return; + } + else if (!bo0 && !bo1 && bo2 && !bo3 && !bo4) + { + switch (bi % 4) + { + case 0x0: DisAsm_CR_BRANCH("bge", bi / 4, bd); return; + case 0x1: DisAsm_CR_BRANCH("ble", bi / 4, bd); return; + case 0x2: DisAsm_CR_BRANCH("bne", bi / 4, bd); return; + } + } + else if (!bo0 && !bo1 && bo2 && bo3 && !bo4) + { + switch (bi % 4) + { + case 0x0: DisAsm_CR_BRANCH("bge-", bi / 4, bd); return; + case 0x1: DisAsm_CR_BRANCH("ble-", bi / 4, bd); return; + case 0x2: DisAsm_CR_BRANCH("bne-", bi / 4, bd); return; + } + } + else if (!bo0 && !bo1 && bo2 && bo3 && bo4) + { + switch (bi % 4) + { + case 0x0: DisAsm_CR_BRANCH("bge+", bi / 4, bd); return; + case 0x1: DisAsm_CR_BRANCH("ble+", bi / 4, bd); return; + case 0x2: DisAsm_CR_BRANCH("bne+", bi / 4, bd); return; + } + } + else if (!bo0 && bo1 && bo2 && !bo3 && !bo4) + { + switch (bi % 4) + { + case 0x0: DisAsm_CR_BRANCH("blt", bi / 4, bd); return; + case 0x1: DisAsm_CR_BRANCH("bgt", bi / 4, bd); return; + case 0x2: DisAsm_CR_BRANCH("beq", bi / 4, bd); return; + } + } + else if (!bo0 && bo1 && bo2 && bo3 && !bo4) + { + switch (bi % 4) + { + case 0x0: DisAsm_CR_BRANCH("blt-", bi / 4, bd); return; + case 0x1: DisAsm_CR_BRANCH("bgt-", bi / 4, bd); return; + case 0x2: DisAsm_CR_BRANCH("beq-", bi / 4, bd); return; + } + } + else if (!bo0 && bo1 && bo2 && bo3 && bo4) + { + switch (bi % 4) + { + case 0x0: DisAsm_CR_BRANCH("blt+", bi / 4, bd); return; + case 0x1: DisAsm_CR_BRANCH("bgt+", bi / 4, bd); return; + case 0x2: DisAsm_CR_BRANCH("beq+", bi / 4, bd); return; + } + } + + Write(fmt::format("bc [%x:%x:%x:%x:%x], cr%d[%x], 0x%x, %d, %d", bo0, bo1, bo2, bo3, bo4, bi / 4, bi % 4, bd, aa, lk)); +} + +void PPUDisAsm::HACK(ppu_opcode_t op) +{ + Write(fmt::format("hack %d", op.opcode & 0x3ffffff)); +} + +void PPUDisAsm::SC(ppu_opcode_t op) +{ + switch (op.lev) + { + case 0x0: Write("sc"); break; + case 0x1: Write("HyperCall LV1"); break; + case 0x3: Write("fast_stop()"); break; // hack + default: Write(fmt::format("Unknown sc: 0x%x", op.lev)); + } +} + +void PPUDisAsm::B(ppu_opcode_t op) +{ + const u32 ll = op.ll; + const u32 aa = op.aa; + const u32 lk = op.lk; + + if (m_mode == CPUDisAsm_CompilerElfMode) + { + Write(fmt::format("b 0x%x, %d, %d", ll, aa, lk)); + return; + } + + switch (lk) + { + case 0: + switch (aa) + { + case 0: DisAsm_BRANCH("b", ll); break; + case 1: DisAsm_BRANCH_A("ba", ll); break; + } + break; + + case 1: + switch (aa) + { + case 0: DisAsm_BRANCH("bl", ll); break; + case 1: DisAsm_BRANCH_A("bla", ll); break; + } + break; + } +} + +void PPUDisAsm::MCRF(ppu_opcode_t op) +{ + DisAsm_CR2("mcrf", op.crfd, op.crfs); +} + +void PPUDisAsm::BCLR(ppu_opcode_t op) +{ + const u32 bo = op.bo; + const u32 bi = op.bi; + + const u8 bo0 = (bo & 0x10) ? 1 : 0; + const u8 bo1 = (bo & 0x08) ? 1 : 0; + const u8 bo2 = (bo & 0x04) ? 1 : 0; + const u8 bo3 = (bo & 0x02) ? 1 : 0; + + if (bo0 && !bo1 && bo2 && !bo3) { Write("blr"); return; } + Write(fmt::format("bclr [%x:%x:%x:%x], cr%d[%x], %d, %d", bo0, bo1, bo2, bo3, bi / 4, bi % 4, op.bh, op.lk)); +} + +void PPUDisAsm::CRNOR(ppu_opcode_t op) +{ + DisAsm_INT3("crnor", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::CRANDC(ppu_opcode_t op) +{ + DisAsm_INT3("crandc", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::ISYNC(ppu_opcode_t op) +{ + Write("isync"); +} + +void PPUDisAsm::CRXOR(ppu_opcode_t op) +{ + DisAsm_INT3("crxor", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::CRNAND(ppu_opcode_t op) +{ + DisAsm_INT3("crnand", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::CRAND(ppu_opcode_t op) +{ + DisAsm_INT3("crand", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::CREQV(ppu_opcode_t op) +{ + DisAsm_INT3("creqv", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::CRORC(ppu_opcode_t op) +{ + DisAsm_INT3("crorc", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::CROR(ppu_opcode_t op) +{ + DisAsm_INT3("cror", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::BCCTR(ppu_opcode_t op) +{ + const u32 bo = op.bo; + const u32 bi = op.bi; + const u32 bh = op.bh; + + switch (op.lk) + { + case 0: DisAsm_INT3("bcctr", bo, bi, bh); break; + case 1: DisAsm_INT3("bcctrl", bo, bi, bh); break; + } +} + +void PPUDisAsm::RLWIMI(ppu_opcode_t op) +{ + DisAsm_R2_INT3_RC("rlwimi", op.ra, op.rs, op.sh32, op.mb32, op.me32, op.rc); +} + +void PPUDisAsm::RLWINM(ppu_opcode_t op) +{ + DisAsm_R2_INT3_RC("rlwinm", op.ra, op.rs, op.sh32, op.mb32, op.me32, op.rc); +} + +void PPUDisAsm::RLWNM(ppu_opcode_t op) +{ + DisAsm_R3_INT2_RC("rlwnm", op.ra, op.rs, op.rb, op.mb32, op.me32, op.rc); +} + +void PPUDisAsm::ORI(ppu_opcode_t op) +{ + if (op.rs == 0 && op.ra == 0 && op.uimm16 == 0) return Write("nop"); + DisAsm_R2_IMM("ori", op.rs, op.ra, op.uimm16); +} + +void PPUDisAsm::ORIS(ppu_opcode_t op) +{ + if (op.rs == 0 && op.ra == 0 && op.uimm16 == 0) return Write("nop"); + DisAsm_R2_IMM("oris", op.rs, op.ra, op.uimm16); +} + +void PPUDisAsm::XORI(ppu_opcode_t op) +{ + DisAsm_R2_IMM("xori", op.ra, op.rs, op.uimm16); +} + +void PPUDisAsm::XORIS(ppu_opcode_t op) +{ + DisAsm_R2_IMM("xoris", op.ra, op.rs, op.uimm16); +} + +void PPUDisAsm::ANDI(ppu_opcode_t op) +{ + DisAsm_R2_IMM("andi.", op.ra, op.rs, op.uimm16); +} + +void PPUDisAsm::ANDIS(ppu_opcode_t op) +{ + DisAsm_R2_IMM("andis.", op.ra, op.rs, op.uimm16); +} + +void PPUDisAsm::RLDICL(ppu_opcode_t op) +{ + const u32 sh = op.sh64; + const u32 mb = op.mbe64; + + if (sh == 0) + { + DisAsm_R2_INT1_RC("clrldi", op.ra, op.rs, mb, op.rc); + } + else if (mb == 0) + { + DisAsm_R2_INT1_RC("rotldi", op.ra, op.rs, sh, op.rc); + } + else if (mb == 64 - sh) + { + DisAsm_R2_INT1_RC("srdi", op.ra, op.rs, mb, op.rc); + } + else + { + DisAsm_R2_INT2_RC("rldicl", op.ra, op.rs, sh, mb, op.rc); + } +} + +void PPUDisAsm::RLDICR(ppu_opcode_t op) +{ + const u32 sh = op.sh64; + const u32 me = op.mbe64; + + DisAsm_R2_INT2_RC("rldicr", op.ra, op.rs, sh, me, op.rc); +} + +void PPUDisAsm::RLDIC(ppu_opcode_t op) +{ + const u32 sh = op.sh64; + const u32 mb = op.mbe64; + + DisAsm_R2_INT2_RC("rldic", op.ra, op.rs, sh, mb, op.rc); +} + +void PPUDisAsm::RLDIMI(ppu_opcode_t op) +{ + const u32 sh = op.sh64; + const u32 mb = op.mbe64; + + DisAsm_R2_INT2_RC("rldimi", op.ra, op.rs, sh, mb, op.rc); +} + +void PPUDisAsm::RLDCL(ppu_opcode_t op) +{ + const u32 mb = op.mbe64; + + DisAsm_R3_INT2_RC("rldcl", op.ra, op.rs, op.rb, mb, 0, op.rc); +} + +void PPUDisAsm::RLDCR(ppu_opcode_t op) +{ + const u32 me = op.mbe64; + + DisAsm_R3_INT2_RC("rldcr", op.ra, op.rs, op.rb, me, 0, op.rc); +} + +void PPUDisAsm::CMP(ppu_opcode_t op) +{ + DisAsm_CR1_R2(op.l10 ? "cmpd" : "cmpw", op.crfd, op.ra, op.rb); +} + +void PPUDisAsm::TW(ppu_opcode_t op) +{ + DisAsm_INT1_R2("tw", op.bo, op.ra, op.rb); +} + +void PPUDisAsm::LVSL(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvsl", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::LVEBX(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvebx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::SUBFC(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("subfc", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::ADDC(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("addc", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::MULHDU(ppu_opcode_t op) +{ + DisAsm_R3_RC("mulhdu", op.rd, op.ra, op.rb, op.rc); +} + +void PPUDisAsm::MULHWU(ppu_opcode_t op) +{ + DisAsm_R3_RC("mulhwu", op.rd, op.ra, op.rb, op.rc); +} + +void PPUDisAsm::MFOCRF(ppu_opcode_t op) +{ + if (op.l11) + { + DisAsm_R1_IMM("mfocrf", op.rd, op.crm); + } + else + { + DisAsm_R1("mfcr", op.rd); + } +} + +void PPUDisAsm::LWARX(ppu_opcode_t op) +{ + DisAsm_R3("lwarx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LDX(ppu_opcode_t op) +{ + DisAsm_R3("ldx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LWZX(ppu_opcode_t op) +{ + DisAsm_R3("lwzx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::SLW(ppu_opcode_t op) +{ + DisAsm_R3_RC("slw", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::CNTLZW(ppu_opcode_t op) +{ + DisAsm_R2_RC("cntlzw", op.ra, op.rs, op.rc); +} + +void PPUDisAsm::SLD(ppu_opcode_t op) +{ + DisAsm_R3_RC("sld", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::AND(ppu_opcode_t op) +{ + DisAsm_R3_RC("and", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::CMPL(ppu_opcode_t op) +{ + DisAsm_CR1_R2(op.l10 ? "cmpld" : "cmplw", op.crfd, op.ra, op.rb); +} + +void PPUDisAsm::LVSR(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvsr", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::LVEHX(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvehx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::SUBF(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("subf", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::LDUX(ppu_opcode_t op) +{ + DisAsm_R3("ldux", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::DCBST(ppu_opcode_t op) +{ + DisAsm_R2("dcbst", op.ra, op.rb); +} + +void PPUDisAsm::LWZUX(ppu_opcode_t op) +{ + DisAsm_R3("lwzux", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::CNTLZD(ppu_opcode_t op) +{ + DisAsm_R2_RC("cntlzd", op.ra, op.rs, op.rc); +} + +void PPUDisAsm::ANDC(ppu_opcode_t op) +{ + DisAsm_R3_RC("andc", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::TD(ppu_opcode_t op) +{ + DisAsm_INT1_R2("td", op.bo, op.ra, op.rb); +} + +void PPUDisAsm::LVEWX(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvewx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::MULHD(ppu_opcode_t op) +{ + DisAsm_R3_RC("mulhd", op.rd, op.ra, op.rb, op.rc); +} + +void PPUDisAsm::MULHW(ppu_opcode_t op) +{ + DisAsm_R3_RC("mulhw", op.rd, op.ra, op.rb, op.rc); +} + +void PPUDisAsm::LDARX(ppu_opcode_t op) +{ + DisAsm_R3("ldarx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::DCBF(ppu_opcode_t op) +{ + DisAsm_R2("dcbf", op.ra, op.rb); +} + +void PPUDisAsm::LBZX(ppu_opcode_t op) +{ + DisAsm_R3("lbzx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LVX(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::NEG(ppu_opcode_t op) +{ + DisAsm_R2_OE_RC("neg", op.rd, op.ra, op.oe, op.rc); +} + +void PPUDisAsm::LBZUX(ppu_opcode_t op) +{ + DisAsm_R3("lbzux", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::NOR(ppu_opcode_t op) +{ + if (op.rs == op.rb) + { + DisAsm_R2_RC("not", op.ra, op.rs, op.rc); + } + else + { + DisAsm_R3_RC("nor", op.ra, op.rs, op.rb, op.rc); + } +} + +void PPUDisAsm::STVEBX(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvebx", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::SUBFE(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("subfe", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::ADDE(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("adde", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::MTOCRF(ppu_opcode_t op) +{ + if (op.l11) + { + DisAsm_INT1_R1("mtocrf", op.crm, op.rs); + } + else + { + DisAsm_INT1_R1("mtcrf", op.crm, op.rs); + } +} + +void PPUDisAsm::STDX(ppu_opcode_t op) +{ + DisAsm_R3("stdx.", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STWCX(ppu_opcode_t op) +{ + DisAsm_R3("stwcx.", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STWX(ppu_opcode_t op) +{ + DisAsm_R3("stwx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STVEHX(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvehx", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::STDUX(ppu_opcode_t op) +{ + DisAsm_R3("stdux", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STWUX(ppu_opcode_t op) +{ + DisAsm_R3("stwux", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STVEWX(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvewx", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::SUBFZE(ppu_opcode_t op) +{ + DisAsm_R2_OE_RC("subfze", op.rd, op.ra, op.oe, op.rc); +} + +void PPUDisAsm::ADDZE(ppu_opcode_t op) +{ + DisAsm_R2_OE_RC("addze", op.rd, op.ra, op.oe, op.rc); +} + +void PPUDisAsm::STDCX(ppu_opcode_t op) +{ + DisAsm_R3("stdcx.", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STBX(ppu_opcode_t op) +{ + DisAsm_R3("stbx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STVX(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::SUBFME(ppu_opcode_t op) +{ + DisAsm_R2_OE_RC("subfme", op.rd, op.ra, op.oe, op.rc); +} + +void PPUDisAsm::MULLD(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("mulld", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::ADDME(ppu_opcode_t op) +{ + DisAsm_R2_OE_RC("addme", op.rd, op.ra, op.oe, op.rc); +} + +void PPUDisAsm::MULLW(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("mullw", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::DCBTST(ppu_opcode_t op) +{ + DisAsm_R3("dcbtst", op.ra, op.rb, op.bo); +} + +void PPUDisAsm::STBUX(ppu_opcode_t op) +{ + DisAsm_R3("stbux", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::ADD(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("add", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::DCBT(ppu_opcode_t op) +{ + DisAsm_R2("dcbt", op.ra, op.rb); +} + +void PPUDisAsm::LHZX(ppu_opcode_t op) +{ + DisAsm_R3("lhzx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::EQV(ppu_opcode_t op) +{ + DisAsm_R3_RC("eqv", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::ECIWX(ppu_opcode_t op) +{ + DisAsm_R3("eciwx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LHZUX(ppu_opcode_t op) +{ + DisAsm_R3("lhzux", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::XOR(ppu_opcode_t op) +{ + DisAsm_R3_RC("xor", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::MFSPR(ppu_opcode_t op) +{ + const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); + switch (n) + { + case 0x001: DisAsm_R1("mfxer", op.rd); break; + case 0x008: DisAsm_R1("mflr", op.rd); break; + case 0x009: DisAsm_R1("mfctr", op.rd); break; + default: DisAsm_R1_IMM("mfspr", op.rd, op.spr); break; + } +} + +void PPUDisAsm::LWAX(ppu_opcode_t op) +{ + DisAsm_R3("lwax", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::DST(ppu_opcode_t op) +{ + DisAsm_R2("dst(t)", op.ra, op.rb); +} + +void PPUDisAsm::LHAX(ppu_opcode_t op) +{ + DisAsm_R3("lhax", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LVXL(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvxl", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::MFTB(ppu_opcode_t op) +{ + const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); + switch (n) + { + case 268: DisAsm_R1("mftb", op.rd); break; + case 269: DisAsm_R1("mftbu", op.rd); break; + default: DisAsm_R1_IMM("mftb", op.rd, op.spr); break; + } +} + +void PPUDisAsm::LWAUX(ppu_opcode_t op) +{ + DisAsm_R3("lwaux", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::DSTST(ppu_opcode_t op) +{ + DisAsm_R2("dstst(t)", op.ra, op.rb); +} + +void PPUDisAsm::LHAUX(ppu_opcode_t op) +{ + DisAsm_R3("lhaux", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::STHX(ppu_opcode_t op) +{ + DisAsm_R3("sthx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::ORC(ppu_opcode_t op) +{ + DisAsm_R3_RC("orc", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::ECOWX(ppu_opcode_t op) +{ + DisAsm_R3("ecowx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STHUX(ppu_opcode_t op) +{ + DisAsm_R3("sthux", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::OR(ppu_opcode_t op) +{ + if (op.rs == op.rb) + { + DisAsm_R2_RC("mr", op.ra, op.rb, op.rc); + } + else + { + DisAsm_R3_RC("or", op.ra, op.rs, op.rb, op.rc); + } +} + +void PPUDisAsm::DIVDU(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("divdu", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::DIVWU(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("divwu", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::MTSPR(ppu_opcode_t op) +{ + const u32 n = (op.spr & 0x1f) + ((op.spr >> 5) & 0x1f); + + switch (n) + { + case 0x001: DisAsm_R1("mtxer", op.rs); break; + case 0x008: DisAsm_R1("mtlr", op.rs); break; + case 0x009: DisAsm_R1("mtctr", op.rs); break; + default: DisAsm_IMM_R1("mtspr", op.spr, op.rs); break; + } +} + +void PPUDisAsm::DCBI(ppu_opcode_t op) +{ + DisAsm_R2("dcbi", op.ra, op.rb); +} + +void PPUDisAsm::NAND(ppu_opcode_t op) +{ + DisAsm_R3_RC("nand", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::STVXL(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvxl", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::DIVD(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("divd", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::DIVW(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("divw", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::LVLX(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvlx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::LDBRX(ppu_opcode_t op) +{ + DisAsm_R3("ldbrx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LSWX(ppu_opcode_t op) +{ + DisAsm_R3("lswx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LWBRX(ppu_opcode_t op) +{ + DisAsm_R3("lwbrx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LFSX(ppu_opcode_t op) +{ + DisAsm_F1_R2("lfsx", op.frd, op.ra, op.rb); +} + +void PPUDisAsm::SRW(ppu_opcode_t op) +{ + DisAsm_R3_RC("srw", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::SRD(ppu_opcode_t op) +{ + DisAsm_R3_RC("srd", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::LVRX(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvrx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::LSWI(ppu_opcode_t op) +{ + DisAsm_R2_INT1("lswi", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LFSUX(ppu_opcode_t op) +{ + DisAsm_F1_R2("lfsux", op.frd, op.ra, op.rb); +} + +void PPUDisAsm::SYNC(ppu_opcode_t op) +{ + Write("sync"); +} + +void PPUDisAsm::LFDX(ppu_opcode_t op) +{ + DisAsm_F1_R2("lfdx", op.frd, op.ra, op.rb); +} + +void PPUDisAsm::LFDUX(ppu_opcode_t op) +{ + DisAsm_F1_R2("lfdux", op.frd, op.ra, op.rb); +} + +void PPUDisAsm::STVLX(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvlx", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::STDBRX(ppu_opcode_t op) +{ + DisAsm_R3("stdbrx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STSWX(ppu_opcode_t op) +{ + DisAsm_R3("swswx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STWBRX(ppu_opcode_t op) +{ + DisAsm_R3("stwbrx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STFSX(ppu_opcode_t op) +{ + DisAsm_F1_R2("stfsx", op.frs, op.ra, op.rb); +} + +void PPUDisAsm::STVRX(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvrx", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::STFSUX(ppu_opcode_t op) +{ + DisAsm_F1_R2("stfsux", op.frs, op.ra, op.rb); +} + +void PPUDisAsm::STSWI(ppu_opcode_t op) +{ + DisAsm_R2_INT1("stswi", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::STFDX(ppu_opcode_t op) +{ + DisAsm_F1_R2("stfdx", op.frs, op.ra, op.rb); +} + +void PPUDisAsm::STFDUX(ppu_opcode_t op) +{ + DisAsm_F1_R2("stfdux", op.frs, op.ra, op.rb); +} + +void PPUDisAsm::LVLXL(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvlxl", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::LHBRX(ppu_opcode_t op) +{ + DisAsm_R3("lhbrx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::SRAW(ppu_opcode_t op) +{ + DisAsm_R3_RC("sraw", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::SRAD(ppu_opcode_t op) +{ + DisAsm_R3_RC("srad", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::LVRXL(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvrxl", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::DSS(ppu_opcode_t op) +{ + Write("dss()"); +} + +void PPUDisAsm::SRAWI(ppu_opcode_t op) +{ + DisAsm_R2_INT1_RC("srawi", op.ra, op.rs, op.sh32, op.rc); +} + +void PPUDisAsm::SRADI(ppu_opcode_t op) +{ + DisAsm_R2_INT1_RC("sradi", op.ra, op.rs, op.sh64, op.rc); +} + +void PPUDisAsm::EIEIO(ppu_opcode_t op) +{ + Write("eieio"); +} + +void PPUDisAsm::STVLXL(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvlxl", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::STHBRX(ppu_opcode_t op) +{ + DisAsm_R3("sthbrx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::EXTSH(ppu_opcode_t op) +{ + DisAsm_R2_RC("extsh", op.ra, op.rs, op.rc); +} + +void PPUDisAsm::STVRXL(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvrxl", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::EXTSB(ppu_opcode_t op) +{ + DisAsm_R2_RC("extsb", op.ra, op.rs, op.rc); +} + +void PPUDisAsm::STFIWX(ppu_opcode_t op) +{ + DisAsm_F1_R2("stfiwx", op.frs, op.ra, op.rb); +} + +void PPUDisAsm::EXTSW(ppu_opcode_t op) +{ + DisAsm_R2_RC("extsw", op.ra, op.rs, op.rc); +} + +void PPUDisAsm::ICBI(ppu_opcode_t op) +{ + DisAsm_R2("icbi", op.ra, op.rb); +} + +void PPUDisAsm::DCBZ(ppu_opcode_t op) +{ + DisAsm_R2("dcbz", op.ra, op.rb); +} + +void PPUDisAsm::LWZ(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lwz", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::LWZU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lwzu", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::LBZ(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lbz", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::LBZU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lbzu", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::STW(ppu_opcode_t op) +{ + DisAsm_R2_IMM("stw", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::STWU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("stwu", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::STB(ppu_opcode_t op) +{ + DisAsm_R2_IMM("stb", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::STBU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("stbu", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::LHZ(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lhz", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::LHZU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lhzu", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::LHA(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lha", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::LHAU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lhau", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::STH(ppu_opcode_t op) +{ + DisAsm_R2_IMM("sth", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::STHU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("sthu", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::LMW(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lmw", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::STMW(ppu_opcode_t op) +{ + DisAsm_R2_IMM("stmw", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::LFS(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("lfs", op.frd, op.simm16, op.ra); +} + +void PPUDisAsm::LFSU(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("lfsu", op.frd, op.simm16, op.ra); +} + +void PPUDisAsm::LFD(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("lfd", op.frd, op.simm16, op.ra); +} + +void PPUDisAsm::LFDU(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("lfdu", op.frd, op.simm16, op.ra); +} + +void PPUDisAsm::STFS(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("stfs", op.frs, op.simm16, op.ra); +} + +void PPUDisAsm::STFSU(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("stfsu", op.frs, op.simm16, op.ra); +} + +void PPUDisAsm::STFD(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("stfd", op.frs, op.simm16, op.ra); +} + +void PPUDisAsm::STFDU(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("stfdu", op.frs, op.simm16, op.ra); +} + +void PPUDisAsm::LD(ppu_opcode_t op) +{ + DisAsm_R2_IMM("ld", op.rd, op.ra, op.ds * 4); +} + +void PPUDisAsm::LDU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("ldu", op.rd, op.ra, op.ds * 4); +} + +void PPUDisAsm::LWA(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lwa", op.rd, op.ra, op.ds * 4); +} + +void PPUDisAsm::FDIVS(ppu_opcode_t op) +{ + DisAsm_F3_RC("fdivs", op.frd, op.fra, op.frb, op.rc); +} + +void PPUDisAsm::FSUBS(ppu_opcode_t op) +{ + DisAsm_F3_RC("fsubs", op.frd, op.fra, op.frb, op.rc); +} + +void PPUDisAsm::FADDS(ppu_opcode_t op) +{ + DisAsm_F3_RC("fadds", op.frd, op.fra, op.frb, op.rc); +} + +void PPUDisAsm::FSQRTS(ppu_opcode_t op) +{ + DisAsm_F2_RC("fsqrts", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FRES(ppu_opcode_t op) +{ + DisAsm_F2_RC("fres", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FMULS(ppu_opcode_t op) +{ + DisAsm_F3_RC("fmuls", op.frd, op.fra, op.frc, op.rc); +} + +void PPUDisAsm::FMADDS(ppu_opcode_t op) +{ + DisAsm_F4_RC("fmadds", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FMSUBS(ppu_opcode_t op) +{ + DisAsm_F4_RC("fmsubs", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FNMSUBS(ppu_opcode_t op) +{ + DisAsm_F4_RC("fnmsubs", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FNMADDS(ppu_opcode_t op) +{ + DisAsm_F4_RC("fnmadds", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::STD(ppu_opcode_t op) +{ + DisAsm_R2_IMM("std", op.rs, op.ra, op.ds * 4); +} + +void PPUDisAsm::STDU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("stdu", op.rs, op.ra, op.ds * 4); +} + +void PPUDisAsm::MTFSB1(ppu_opcode_t op) +{ + Write(fmt::format("mtfsb1%s %d", op.rc ? "." : "", op.crbd)); +} + +void PPUDisAsm::MCRFS(ppu_opcode_t op) +{ + DisAsm_CR2("mcrfs", op.crfd, op.crfs); +} + +void PPUDisAsm::MTFSB0(ppu_opcode_t op) +{ + Write(fmt::format("mtfsb0%s %d", op.rc ? "." : "", op.crbd)); +} + +void PPUDisAsm::MTFSFI(ppu_opcode_t op) +{ + Write(fmt::format("mtfsfi%s cr%d,%d,%d", op.rc ? "." : "", op.crfd, op.i, op.l15)); +} + +void PPUDisAsm::MFFS(ppu_opcode_t op) +{ + DisAsm_F1_RC("mffs", op.frd, op.rc); +} + +void PPUDisAsm::MTFSF(ppu_opcode_t op) +{ + Write(fmt::format("mtfsf%s %d,f%d,%d,%d", op.rc ? "." : "", op.rc, op.flm, op.frb, op.l6, op.l15)); +} + +void PPUDisAsm::FCMPU(ppu_opcode_t op) +{ + DisAsm_CR1_F2("fcmpu", op.crfd, op.fra, op.frb); +} + +void PPUDisAsm::FRSP(ppu_opcode_t op) +{ + DisAsm_F2_RC("frsp", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FCTIW(ppu_opcode_t op) +{ + DisAsm_F2_RC("fctiw", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FCTIWZ(ppu_opcode_t op) +{ + DisAsm_F2_RC("fctiwz", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FDIV(ppu_opcode_t op) +{ + DisAsm_F3_RC("fdiv", op.frd, op.fra, op.frb, op.rc); +} + +void PPUDisAsm::FSUB(ppu_opcode_t op) +{ + DisAsm_F3_RC("fsub", op.frd, op.fra, op.frb, op.rc); +} + +void PPUDisAsm::FADD(ppu_opcode_t op) +{ + DisAsm_F3_RC("fadd", op.frd, op.fra, op.frb, op.rc); +} + +void PPUDisAsm::FSQRT(ppu_opcode_t op) +{ + DisAsm_F2_RC("fsqrt", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FSEL(ppu_opcode_t op) +{ + DisAsm_F4_RC("fsel", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FMUL(ppu_opcode_t op) +{ + DisAsm_F3_RC("fmul", op.frd, op.fra, op.frc, op.rc); +} + +void PPUDisAsm::FRSQRTE(ppu_opcode_t op) +{ + DisAsm_F2_RC("frsqrte", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FMSUB(ppu_opcode_t op) +{ + DisAsm_F4_RC("fmsub", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FMADD(ppu_opcode_t op) +{ + DisAsm_F4_RC("fmadd", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FNMSUB(ppu_opcode_t op) +{ + DisAsm_F4_RC("fnmsub", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FNMADD(ppu_opcode_t op) +{ + DisAsm_F4_RC("fnmadd", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FCMPO(ppu_opcode_t op) +{ + DisAsm_F3("fcmpo", op.crfd, op.fra, op.frb); +} + +void PPUDisAsm::FNEG(ppu_opcode_t op) +{ + DisAsm_F2_RC("fneg", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FMR(ppu_opcode_t op) +{ + DisAsm_F2_RC("fmr", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FNABS(ppu_opcode_t op) +{ + DisAsm_F2_RC("fnabs", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FABS(ppu_opcode_t op) +{ + DisAsm_F2_RC("fabs", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FCTID(ppu_opcode_t op) +{ + DisAsm_F2_RC("fctid", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FCTIDZ(ppu_opcode_t op) +{ + DisAsm_F2_RC("fctidz", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FCFID(ppu_opcode_t op) +{ + DisAsm_F2_RC("fcfid", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::UNK(ppu_opcode_t op) +{ + Write(fmt::format("Unknown/Illegal opcode! (0x%08x)", op.opcode)); +} diff --git a/rpcs3/Emu/Cell/PPUDisAsm.h b/rpcs3/Emu/Cell/PPUDisAsm.h index 53478560ac..7138bfe519 100644 --- a/rpcs3/Emu/Cell/PPUDisAsm.h +++ b/rpcs3/Emu/Cell/PPUDisAsm.h @@ -3,9 +3,7 @@ #include "Emu/Cell/PPCDisAsm.h" #include "Emu/Cell/PPUOpcodes.h" -class PPUDisAsm - : public PPUOpcodes - , public PPCDisAsm +class PPUDisAsm final : public PPCDisAsm { public: PPUDisAsm(CPUDisAsmMode mode) : PPCDisAsm(mode) @@ -15,7 +13,7 @@ public: private: u32 DisAsmBranchTarget(const s32 imm) { - return branchTarget(dump_pc, imm); + return ppu_branch_target(dump_pc, imm); } private: @@ -131,9 +129,9 @@ private: { DisAsm_R1_RC(op, r0, false); } - void DisAsm_R2_OE_RC(const std::string& op, u32 r0, u32 r1, u32 oe, u32 rc) + void DisAsm_R2_OE_RC(const std::string& op, u32 r0, u32 r1, u32 _oe, u32 rc) { - Write(fmt::format("%s%s%s r%d,r%d", FixOp(op).c_str(), (oe ? "o" : ""), (rc ? "." : ""), r0, r1)); + Write(fmt::format("%s%s%s r%d,r%d", FixOp(op).c_str(), (_oe ? "o" : ""), (rc ? "." : ""), r0, r1)); } void DisAsm_R2_RC(const std::string& op, u32 r0, u32 r1, u32 rc) { @@ -143,9 +141,9 @@ private: { DisAsm_R2_RC(op, r0, r1, false); } - void DisAsm_R3_OE_RC(const std::string& op, u32 r0, u32 r1, u32 r2, u32 oe, u32 rc) + void DisAsm_R3_OE_RC(const std::string& op, u32 r0, u32 r1, u32 r2, u32 _oe, u32 rc) { - Write(fmt::format("%s%s%s r%d,r%d,r%d", FixOp(op).c_str(), (oe ? "o" : ""), (rc ? "." : ""), r0, r1, r2)); + Write(fmt::format("%s%s%s r%d,r%d,r%d", FixOp(op).c_str(), (_oe ? "o" : ""), (rc ? "." : ""), r0, r1, r2)); } void DisAsm_R3_INT2_RC(const std::string& op, u32 r0, u32 r1, u32 r2, s32 i0, s32 i1, u32 rc) { @@ -242,1841 +240,389 @@ private: Write(fmt::format("%s cr%d,0x%x ", FixOp(op).c_str(), cr, DisAsmBranchTarget(pc))); } -private: - void NULL_OP() - { - Write( "null" ); - } +public: + u32 disasm(u32 pc) override; - void NOP() - { - Write( "nop" ); - } + void TDI(ppu_opcode_t op); + void TWI(ppu_opcode_t op); + void MFVSCR(ppu_opcode_t op); + void MTVSCR(ppu_opcode_t op); + void VADDCUW(ppu_opcode_t op); + void VADDFP(ppu_opcode_t op); + void VADDSBS(ppu_opcode_t op); + void VADDSHS(ppu_opcode_t op); + void VADDSWS(ppu_opcode_t op); + void VADDUBM(ppu_opcode_t op); + void VADDUBS(ppu_opcode_t op); + void VADDUHM(ppu_opcode_t op); + void VADDUHS(ppu_opcode_t op); + void VADDUWM(ppu_opcode_t op); + void VADDUWS(ppu_opcode_t op); + void VAND(ppu_opcode_t op); + void VANDC(ppu_opcode_t op); + void VAVGSB(ppu_opcode_t op); + void VAVGSH(ppu_opcode_t op); + void VAVGSW(ppu_opcode_t op); + void VAVGUB(ppu_opcode_t op); + void VAVGUH(ppu_opcode_t op); + void VAVGUW(ppu_opcode_t op); + void VCFSX(ppu_opcode_t op); + void VCFUX(ppu_opcode_t op); + void VCMPBFP(ppu_opcode_t op); + void VCMPEQFP(ppu_opcode_t op); + void VCMPEQUB(ppu_opcode_t op); + void VCMPEQUH(ppu_opcode_t op); + void VCMPEQUW(ppu_opcode_t op); + void VCMPGEFP(ppu_opcode_t op); + void VCMPGTFP(ppu_opcode_t op); + void VCMPGTSB(ppu_opcode_t op); + void VCMPGTSH(ppu_opcode_t op); + void VCMPGTSW(ppu_opcode_t op); + void VCMPGTUB(ppu_opcode_t op); + void VCMPGTUH(ppu_opcode_t op); + void VCMPGTUW(ppu_opcode_t op); + void VCTSXS(ppu_opcode_t op); + void VCTUXS(ppu_opcode_t op); + void VEXPTEFP(ppu_opcode_t op); + void VLOGEFP(ppu_opcode_t op); + void VMADDFP(ppu_opcode_t op); + void VMAXFP(ppu_opcode_t op); + void VMAXSB(ppu_opcode_t op); + void VMAXSH(ppu_opcode_t op); + void VMAXSW(ppu_opcode_t op); + void VMAXUB(ppu_opcode_t op); + void VMAXUH(ppu_opcode_t op); + void VMAXUW(ppu_opcode_t op); + void VMHADDSHS(ppu_opcode_t op); + void VMHRADDSHS(ppu_opcode_t op); + void VMINFP(ppu_opcode_t op); + void VMINSB(ppu_opcode_t op); + void VMINSH(ppu_opcode_t op); + void VMINSW(ppu_opcode_t op); + void VMINUB(ppu_opcode_t op); + void VMINUH(ppu_opcode_t op); + void VMINUW(ppu_opcode_t op); + void VMLADDUHM(ppu_opcode_t op); + void VMRGHB(ppu_opcode_t op); + void VMRGHH(ppu_opcode_t op); + void VMRGHW(ppu_opcode_t op); + void VMRGLB(ppu_opcode_t op); + void VMRGLH(ppu_opcode_t op); + void VMRGLW(ppu_opcode_t op); + void VMSUMMBM(ppu_opcode_t op); + void VMSUMSHM(ppu_opcode_t op); + void VMSUMSHS(ppu_opcode_t op); + void VMSUMUBM(ppu_opcode_t op); + void VMSUMUHM(ppu_opcode_t op); + void VMSUMUHS(ppu_opcode_t op); + void VMULESB(ppu_opcode_t op); + void VMULESH(ppu_opcode_t op); + void VMULEUB(ppu_opcode_t op); + void VMULEUH(ppu_opcode_t op); + void VMULOSB(ppu_opcode_t op); + void VMULOSH(ppu_opcode_t op); + void VMULOUB(ppu_opcode_t op); + void VMULOUH(ppu_opcode_t op); + void VNMSUBFP(ppu_opcode_t op); + void VNOR(ppu_opcode_t op); + void VOR(ppu_opcode_t op); + void VPERM(ppu_opcode_t op); + void VPKPX(ppu_opcode_t op); + void VPKSHSS(ppu_opcode_t op); + void VPKSHUS(ppu_opcode_t op); + void VPKSWSS(ppu_opcode_t op); + void VPKSWUS(ppu_opcode_t op); + void VPKUHUM(ppu_opcode_t op); + void VPKUHUS(ppu_opcode_t op); + void VPKUWUM(ppu_opcode_t op); + void VPKUWUS(ppu_opcode_t op); + void VREFP(ppu_opcode_t op); + void VRFIM(ppu_opcode_t op); + void VRFIN(ppu_opcode_t op); + void VRFIP(ppu_opcode_t op); + void VRFIZ(ppu_opcode_t op); + void VRLB(ppu_opcode_t op); + void VRLH(ppu_opcode_t op); + void VRLW(ppu_opcode_t op); + void VRSQRTEFP(ppu_opcode_t op); + void VSEL(ppu_opcode_t op); + void VSL(ppu_opcode_t op); + void VSLB(ppu_opcode_t op); + void VSLDOI(ppu_opcode_t op); + void VSLH(ppu_opcode_t op); + void VSLO(ppu_opcode_t op); + void VSLW(ppu_opcode_t op); + void VSPLTB(ppu_opcode_t op); + void VSPLTH(ppu_opcode_t op); + void VSPLTISB(ppu_opcode_t op); + void VSPLTISH(ppu_opcode_t op); + void VSPLTISW(ppu_opcode_t op); + void VSPLTW(ppu_opcode_t op); + void VSR(ppu_opcode_t op); + void VSRAB(ppu_opcode_t op); + void VSRAH(ppu_opcode_t op); + void VSRAW(ppu_opcode_t op); + void VSRB(ppu_opcode_t op); + void VSRH(ppu_opcode_t op); + void VSRO(ppu_opcode_t op); + void VSRW(ppu_opcode_t op); + void VSUBCUW(ppu_opcode_t op); + void VSUBFP(ppu_opcode_t op); + void VSUBSBS(ppu_opcode_t op); + void VSUBSHS(ppu_opcode_t op); + void VSUBSWS(ppu_opcode_t op); + void VSUBUBM(ppu_opcode_t op); + void VSUBUBS(ppu_opcode_t op); + void VSUBUHM(ppu_opcode_t op); + void VSUBUHS(ppu_opcode_t op); + void VSUBUWM(ppu_opcode_t op); + void VSUBUWS(ppu_opcode_t op); + void VSUMSWS(ppu_opcode_t op); + void VSUM2SWS(ppu_opcode_t op); + void VSUM4SBS(ppu_opcode_t op); + void VSUM4SHS(ppu_opcode_t op); + void VSUM4UBS(ppu_opcode_t op); + void VUPKHPX(ppu_opcode_t op); + void VUPKHSB(ppu_opcode_t op); + void VUPKHSH(ppu_opcode_t op); + void VUPKLPX(ppu_opcode_t op); + void VUPKLSB(ppu_opcode_t op); + void VUPKLSH(ppu_opcode_t op); + void VXOR(ppu_opcode_t op); + void MULLI(ppu_opcode_t op); + void SUBFIC(ppu_opcode_t op); + void CMPLI(ppu_opcode_t op); + void CMPI(ppu_opcode_t op); + void ADDIC(ppu_opcode_t op); + void ADDI(ppu_opcode_t op); + void ADDIS(ppu_opcode_t op); + void BC(ppu_opcode_t op); + void HACK(ppu_opcode_t op); + void SC(ppu_opcode_t op); + void B(ppu_opcode_t op); + void MCRF(ppu_opcode_t op); + void BCLR(ppu_opcode_t op); + void CRNOR(ppu_opcode_t op); + void CRANDC(ppu_opcode_t op); + void ISYNC(ppu_opcode_t op); + void CRXOR(ppu_opcode_t op); + void CRNAND(ppu_opcode_t op); + void CRAND(ppu_opcode_t op); + void CREQV(ppu_opcode_t op); + void CRORC(ppu_opcode_t op); + void CROR(ppu_opcode_t op); + void BCCTR(ppu_opcode_t op); + void RLWIMI(ppu_opcode_t op); + void RLWINM(ppu_opcode_t op); + void RLWNM(ppu_opcode_t op); + void ORI(ppu_opcode_t op); + void ORIS(ppu_opcode_t op); + void XORI(ppu_opcode_t op); + void XORIS(ppu_opcode_t op); + void ANDI(ppu_opcode_t op); + void ANDIS(ppu_opcode_t op); + void RLDICL(ppu_opcode_t op); + void RLDICR(ppu_opcode_t op); + void RLDIC(ppu_opcode_t op); + void RLDIMI(ppu_opcode_t op); + void RLDCL(ppu_opcode_t op); + void RLDCR(ppu_opcode_t op); + void CMP(ppu_opcode_t op); + void TW(ppu_opcode_t op); + void LVSL(ppu_opcode_t op); + void LVEBX(ppu_opcode_t op); + void SUBFC(ppu_opcode_t op); + void ADDC(ppu_opcode_t op); + void MULHDU(ppu_opcode_t op); + void MULHWU(ppu_opcode_t op); + void MFOCRF(ppu_opcode_t op); + void LWARX(ppu_opcode_t op); + void LDX(ppu_opcode_t op); + void LWZX(ppu_opcode_t op); + void SLW(ppu_opcode_t op); + void CNTLZW(ppu_opcode_t op); + void SLD(ppu_opcode_t op); + void AND(ppu_opcode_t op); + void CMPL(ppu_opcode_t op); + void LVSR(ppu_opcode_t op); + void LVEHX(ppu_opcode_t op); + void SUBF(ppu_opcode_t op); + void LDUX(ppu_opcode_t op); + void DCBST(ppu_opcode_t op); + void LWZUX(ppu_opcode_t op); + void CNTLZD(ppu_opcode_t op); + void ANDC(ppu_opcode_t op); + void TD(ppu_opcode_t op); + void LVEWX(ppu_opcode_t op); + void MULHD(ppu_opcode_t op); + void MULHW(ppu_opcode_t op); + void LDARX(ppu_opcode_t op); + void DCBF(ppu_opcode_t op); + void LBZX(ppu_opcode_t op); + void LVX(ppu_opcode_t op); + void NEG(ppu_opcode_t op); + void LBZUX(ppu_opcode_t op); + void NOR(ppu_opcode_t op); + void STVEBX(ppu_opcode_t op); + void SUBFE(ppu_opcode_t op); + void ADDE(ppu_opcode_t op); + void MTOCRF(ppu_opcode_t op); + void STDX(ppu_opcode_t op); + void STWCX(ppu_opcode_t op); + void STWX(ppu_opcode_t op); + void STVEHX(ppu_opcode_t op); + void STDUX(ppu_opcode_t op); + void STWUX(ppu_opcode_t op); + void STVEWX(ppu_opcode_t op); + void SUBFZE(ppu_opcode_t op); + void ADDZE(ppu_opcode_t op); + void STDCX(ppu_opcode_t op); + void STBX(ppu_opcode_t op); + void STVX(ppu_opcode_t op); + void SUBFME(ppu_opcode_t op); + void MULLD(ppu_opcode_t op); + void ADDME(ppu_opcode_t op); + void MULLW(ppu_opcode_t op); + void DCBTST(ppu_opcode_t op); + void STBUX(ppu_opcode_t op); + void ADD(ppu_opcode_t op); + void DCBT(ppu_opcode_t op); + void LHZX(ppu_opcode_t op); + void EQV(ppu_opcode_t op); + void ECIWX(ppu_opcode_t op); + void LHZUX(ppu_opcode_t op); + void XOR(ppu_opcode_t op); + void MFSPR(ppu_opcode_t op); + void LWAX(ppu_opcode_t op); + void DST(ppu_opcode_t op); + void LHAX(ppu_opcode_t op); + void LVXL(ppu_opcode_t op); + void MFTB(ppu_opcode_t op); + void LWAUX(ppu_opcode_t op); + void DSTST(ppu_opcode_t op); + void LHAUX(ppu_opcode_t op); + void STHX(ppu_opcode_t op); + void ORC(ppu_opcode_t op); + void ECOWX(ppu_opcode_t op); + void STHUX(ppu_opcode_t op); + void OR(ppu_opcode_t op); + void DIVDU(ppu_opcode_t op); + void DIVWU(ppu_opcode_t op); + void MTSPR(ppu_opcode_t op); + void DCBI(ppu_opcode_t op); + void NAND(ppu_opcode_t op); + void STVXL(ppu_opcode_t op); + void DIVD(ppu_opcode_t op); + void DIVW(ppu_opcode_t op); + void LVLX(ppu_opcode_t op); + void LDBRX(ppu_opcode_t op); + void LSWX(ppu_opcode_t op); + void LWBRX(ppu_opcode_t op); + void LFSX(ppu_opcode_t op); + void SRW(ppu_opcode_t op); + void SRD(ppu_opcode_t op); + void LVRX(ppu_opcode_t op); + void LSWI(ppu_opcode_t op); + void LFSUX(ppu_opcode_t op); + void SYNC(ppu_opcode_t op); + void LFDX(ppu_opcode_t op); + void LFDUX(ppu_opcode_t op); + void STVLX(ppu_opcode_t op); + void STDBRX(ppu_opcode_t op); + void STSWX(ppu_opcode_t op); + void STWBRX(ppu_opcode_t op); + void STFSX(ppu_opcode_t op); + void STVRX(ppu_opcode_t op); + void STFSUX(ppu_opcode_t op); + void STSWI(ppu_opcode_t op); + void STFDX(ppu_opcode_t op); + void STFDUX(ppu_opcode_t op); + void LVLXL(ppu_opcode_t op); + void LHBRX(ppu_opcode_t op); + void SRAW(ppu_opcode_t op); + void SRAD(ppu_opcode_t op); + void LVRXL(ppu_opcode_t op); + void DSS(ppu_opcode_t op); + void SRAWI(ppu_opcode_t op); + void SRADI(ppu_opcode_t op); + void EIEIO(ppu_opcode_t op); + void STVLXL(ppu_opcode_t op); + void STHBRX(ppu_opcode_t op); + void EXTSH(ppu_opcode_t op); + void STVRXL(ppu_opcode_t op); + void EXTSB(ppu_opcode_t op); + void STFIWX(ppu_opcode_t op); + void EXTSW(ppu_opcode_t op); + void ICBI(ppu_opcode_t op); + void DCBZ(ppu_opcode_t op); + void LWZ(ppu_opcode_t op); + void LWZU(ppu_opcode_t op); + void LBZ(ppu_opcode_t op); + void LBZU(ppu_opcode_t op); + void STW(ppu_opcode_t op); + void STWU(ppu_opcode_t op); + void STB(ppu_opcode_t op); + void STBU(ppu_opcode_t op); + void LHZ(ppu_opcode_t op); + void LHZU(ppu_opcode_t op); + void LHA(ppu_opcode_t op); + void LHAU(ppu_opcode_t op); + void STH(ppu_opcode_t op); + void STHU(ppu_opcode_t op); + void LMW(ppu_opcode_t op); + void STMW(ppu_opcode_t op); + void LFS(ppu_opcode_t op); + void LFSU(ppu_opcode_t op); + void LFD(ppu_opcode_t op); + void LFDU(ppu_opcode_t op); + void STFS(ppu_opcode_t op); + void STFSU(ppu_opcode_t op); + void STFD(ppu_opcode_t op); + void STFDU(ppu_opcode_t op); + void LD(ppu_opcode_t op); + void LDU(ppu_opcode_t op); + void LWA(ppu_opcode_t op); + void FDIVS(ppu_opcode_t op); + void FSUBS(ppu_opcode_t op); + void FADDS(ppu_opcode_t op); + void FSQRTS(ppu_opcode_t op); + void FRES(ppu_opcode_t op); + void FMULS(ppu_opcode_t op); + void FMADDS(ppu_opcode_t op); + void FMSUBS(ppu_opcode_t op); + void FNMSUBS(ppu_opcode_t op); + void FNMADDS(ppu_opcode_t op); + void STD(ppu_opcode_t op); + void STDU(ppu_opcode_t op); + void MTFSB1(ppu_opcode_t op); + void MCRFS(ppu_opcode_t op); + void MTFSB0(ppu_opcode_t op); + void MTFSFI(ppu_opcode_t op); + void MFFS(ppu_opcode_t op); + void MTFSF(ppu_opcode_t op); + void FCMPU(ppu_opcode_t op); + void FRSP(ppu_opcode_t op); + void FCTIW(ppu_opcode_t op); + void FCTIWZ(ppu_opcode_t op); + void FDIV(ppu_opcode_t op); + void FSUB(ppu_opcode_t op); + void FADD(ppu_opcode_t op); + void FSQRT(ppu_opcode_t op); + void FSEL(ppu_opcode_t op); + void FMUL(ppu_opcode_t op); + void FRSQRTE(ppu_opcode_t op); + void FMSUB(ppu_opcode_t op); + void FMADD(ppu_opcode_t op); + void FNMSUB(ppu_opcode_t op); + void FNMADD(ppu_opcode_t op); + void FCMPO(ppu_opcode_t op); + void FNEG(ppu_opcode_t op); + void FMR(ppu_opcode_t op); + void FNABS(ppu_opcode_t op); + void FABS(ppu_opcode_t op); + void FCTID(ppu_opcode_t op); + void FCTIDZ(ppu_opcode_t op); + void FCFID(ppu_opcode_t op); - void TDI(u32 to, u32 ra, s32 simm16) - { - DisAsm_INT1_R1_IMM("tdi", to, ra, simm16); - } - void TWI(u32 to, u32 ra, s32 simm16) - { - DisAsm_INT1_R1_IMM("twi", to, ra, simm16); - } - void MFVSCR(u32 vd) - { - DisAsm_V1("mfvscr", vd); - } - void MTVSCR(u32 vb) - { - DisAsm_V1("mtvscr", vb); - } - void VADDCUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddcuw", vd, va, vb); - } - void VADDFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddfp", vd, va, vb); - } - void VADDSBS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddsbs", vd, va, vb); - } - void VADDSHS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddshs", vd, va, vb); - } - void VADDSWS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddsws", vd, va, vb); - } - void VADDUBM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddubm", vd, va, vb); - } - void VADDUBS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddubs", vd, va, vb); - } - void VADDUHM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vadduhm", vd, va, vb); - } - void VADDUHS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vadduhs", vd, va, vb); - } - void VADDUWM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vadduwm", vd, va, vb); - } - void VADDUWS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vadduws", vd, va, vb); - } - void VAND(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vand", vd, va, vb); - } - void VANDC(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vandc", vd, va, vb); - } - void VAVGSB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vavgsb", vd, va, vb); - } - void VAVGSH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vavgsh", vd, va, vb); - } - void VAVGSW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vavgsw", vd, va, vb); - } - void VAVGUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vavgub", vd, va, vb); - } - void VAVGUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vavguh", vd, va, vb); - } - void VAVGUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vavguw", vd, va, vb); - } - void VCFSX(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vcfsx", vd, vb, uimm5); - } - void VCFUX(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vcfux", vd, vb, uimm5); - } - void VCMPBFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpbfp", vd, va, vb); - } - void VCMPBFP_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpbfp.", vd, va, vb); - } - void VCMPEQFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpeqfp", vd, va, vb); - } - void VCMPEQFP_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpeqfp.", vd, va, vb); - } - void VCMPEQUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpequb", vd, va, vb); - } - void VCMPEQUB_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpequb.", vd, va, vb); - } - void VCMPEQUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpequh", vd, va, vb); - } - void VCMPEQUH_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpequh.", vd, va, vb); - } - void VCMPEQUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpequw", vd, va, vb); - } - void VCMPEQUW_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpequw.", vd, va, vb); - } - void VCMPGEFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgefp", vd, va, vb); - } - void VCMPGEFP_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgefp.", vd, va, vb); - } - void VCMPGTFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtfp", vd, va, vb); - } - void VCMPGTFP_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtfp.", vd, va, vb); - } - void VCMPGTSB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtsb", vd, va, vb); - } - void VCMPGTSB_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtsb.", vd, va, vb); - } - void VCMPGTSH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtsh", vd, va, vb); - } - void VCMPGTSH_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtsh.", vd, va, vb); - } - void VCMPGTSW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtsw", vd, va, vb); - } - void VCMPGTSW_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtsw.", vd, va, vb); - } - void VCMPGTUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtub", vd, va, vb); - } - void VCMPGTUB_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtub.", vd, va, vb); - } - void VCMPGTUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtuh", vd, va, vb); - } - void VCMPGTUH_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtuh.", vd, va, vb); - } - void VCMPGTUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtuw", vd, va, vb); - } - void VCMPGTUW_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtuw.", vd, va, vb); - } - void VCTSXS(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vctsxs", vd, vb, uimm5); - } - void VCTUXS(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vctuxs", vd, vb, uimm5); - } - void VEXPTEFP(u32 vd, u32 vb) - { - DisAsm_V2("vexptefp", vd, vb); - } - void VLOGEFP(u32 vd, u32 vb) - { - DisAsm_V2("vlogefp", vd, vb); - } - void VMADDFP(u32 vd, u32 va, u32 vc, u32 vb) - { - DisAsm_V4("vmaddfp", vd, va, vc, vb); - } - void VMAXFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxfp", vd, va, vb); - } - void VMAXSB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxsb", vd, va, vb); - } - void VMAXSH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxsh", vd, va, vb); - } - void VMAXSW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxsw", vd, va, vb); - } - void VMAXUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxub", vd, va, vb); - } - void VMAXUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxuh", vd, va, vb); - } - void VMAXUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxuw", vd, va, vb); - } - void VMHADDSHS(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmhaddshs", vd, va, vb, vc); - } - void VMHRADDSHS(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmhraddshs", vd, va, vb, vc); - } - void VMINFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminfp", vd, va, vb); - } - void VMINSB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminsb", vd, va, vb); - } - void VMINSH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminsh", vd, va, vb); - } - void VMINSW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminsw", vd, va, vb); - } - void VMINUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminub", vd, va, vb); - } - void VMINUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminuh", vd, va, vb); - } - void VMINUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminuw", vd, va, vb); - } - void VMLADDUHM(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmladduhm", vd, va, vb, vc); - } - void VMRGHB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmrghb", vd, va, vb); - } - void VMRGHH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmrghh", vd, va, vb); - } - void VMRGHW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmrghw", vd, va, vb); - } - void VMRGLB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmrglb", vd, va, vb); - } - void VMRGLH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmrglh", vd, va, vb); - } - void VMRGLW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmrglw", vd, va, vb); - } - void VMSUMMBM(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmsummbm", vd, va, vb, vc); - } - void VMSUMSHM(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmsumshm", vd, va, vb, vc); - } - void VMSUMSHS(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmsumshs", vd, va, vb, vc); - } - void VMSUMUBM(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmsumubm", vd, va, vb, vc); - } - void VMSUMUHM(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmsumuhm", vd, va, vb, vc); - } - void VMSUMUHS(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmsumuhs", vd, va, vb, vc); - } - void VMULESB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmulesb", vd, va, vb); - } - void VMULESH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmulesh", vd, va, vb); - } - void VMULEUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmuleub", vd, va, vb); - } - void VMULEUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmuleuh", vd, va, vb); - } - void VMULOSB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmulosb", vd, va, vb); - } - void VMULOSH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmulosh", vd, va, vb); - } - void VMULOUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmuloub", vd, va, vb); - } - void VMULOUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmulouh", vd, va, vb); - } - void VNMSUBFP(u32 vd, u32 va, u32 vc, u32 vb) - { - DisAsm_V4("vnmsubfp", vd, va, vc, vb); - } - void VNOR(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vnor", vd, va, vb); - } - void VOR(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vor", vd, va, vb); - } - void VPERM(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vperm", vd, va, vb, vc); - } - void VPKPX(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkpx", vd, va, vb); - } - void VPKSHSS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkshss", vd, va, vb); - } - void VPKSHUS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkshus", vd, va, vb); - } - void VPKSWSS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkswss", vd, va, vb); - } - void VPKSWUS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkswus", vd, va, vb); - } - void VPKUHUM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkuhum", vd, va, vb); - } - void VPKUHUS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkuhus", vd, va, vb); - } - void VPKUWUM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkuwum", vd, va, vb); - } - void VPKUWUS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkuwus", vd, va, vb); - } - void VREFP(u32 vd, u32 vb) - { - DisAsm_V2("vrefp", vd, vb); - } - void VRFIM(u32 vd, u32 vb) - { - DisAsm_V2("vrfim", vd, vb); - } - void VRFIN(u32 vd, u32 vb) - { - DisAsm_V2("vrfin", vd, vb); - } - void VRFIP(u32 vd, u32 vb) - { - DisAsm_V2("vrfip", vd, vb); - } - void VRFIZ(u32 vd, u32 vb) - { - DisAsm_V2("vrfiz", vd, vb); - } - void VRLB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vrlb", vd, va, vb); - } - void VRLH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vrlh", vd, va, vb); - } - void VRLW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vrlw", vd, va, vb); - } - void VRSQRTEFP(u32 vd, u32 vb) - { - DisAsm_V2("vrsqrtefp", vd, vb); - } - void VSEL(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vsel", vd, va, vb, vc); - } - void VSL(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsl", vd, va, vb); - } - void VSLB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vslb", vd, va, vb); - } - void VSLDOI(u32 vd, u32 va, u32 vb, u32 sh) - { - DisAsm_V3_UIMM("vsldoi", vd, va, vb, sh); - } - void VSLH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vslh", vd, va, vb); - } - void VSLO(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vslo", vd, va, vb); - } - void VSLW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vslw", vd, va, vb); - } - void VSPLTB(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vspltb", vd, vb, uimm5); - } - void VSPLTH(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vsplth", vd, vb, uimm5); - } - void VSPLTISB(u32 vd, s32 simm5) - { - DisAsm_V1_SIMM("vspltisb", vd, simm5); - } - void VSPLTISH(u32 vd, s32 simm5) - { - DisAsm_V1_SIMM("vspltish", vd, simm5); - } - void VSPLTISW(u32 vd, s32 simm5) - { - DisAsm_V1_SIMM("vspltisw", vd, simm5); - } - void VSPLTW(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vspltw", vd, vb, uimm5); - } - void VSR(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsr", vd, va, vb); - } - void VSRAB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsrab", vd, va, vb); - } - void VSRAH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsrah", vd, va, vb); - } - void VSRAW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsraw", vd, va, vb); - } - void VSRB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsrb", vd, va, vb); - } - void VSRH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsrh", vd, va, vb); - } - void VSRO(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsro", vd, va, vb); - } - void VSRW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsrw", vd, va, vb); - } - void VSUBCUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubcuw", vd, va, vb); - } - void VSUBFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubfp", vd, va, vb); - } - void VSUBSBS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubsbs", vd, va, vb); - } - void VSUBSHS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubshs", vd, va, vb); - } - void VSUBSWS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubsws", vd, va, vb); - } - void VSUBUBM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsububm", vd, va, vb); - } - void VSUBUBS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsububs", vd, va, vb); - } - void VSUBUHM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubuhm", vd, va, vb); - } - void VSUBUHS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubuhs", vd, va, vb); - } - void VSUBUWM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubuwm", vd, va, vb); - } - void VSUBUWS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubuws", vd, va, vb); - } - void VSUMSWS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsumsws", vd, va, vb); - } - void VSUM2SWS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsum2sws", vd, va, vb); - } - void VSUM4SBS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsum4sbs", vd, va, vb); - } - void VSUM4SHS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsum4shs", vd, va, vb); - } - void VSUM4UBS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsum4ubs", vd, va, vb); - } - void VUPKHPX(u32 vd, u32 vb) - { - DisAsm_V2("vupkhpx", vd, vb); - } - void VUPKHSB(u32 vd, u32 vb) - { - DisAsm_V2("vupkhsb", vd, vb); - } - void VUPKHSH(u32 vd, u32 vb) - { - DisAsm_V2("vupkhsh", vd, vb); - } - void VUPKLPX(u32 vd, u32 vb) - { - DisAsm_V2("vupklpx", vd, vb); - } - void VUPKLSB(u32 vd, u32 vb) - { - DisAsm_V2("vupklsb", vd, vb); - } - void VUPKLSH(u32 vd, u32 vb) - { - DisAsm_V2("vupklsh", vd, vb); - } - void VXOR(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vxor", vd, va, vb); - } - void MULLI(u32 rd, u32 ra, s32 simm16) - { - DisAsm_R2_IMM("mulli", rd, ra, simm16); - } - void SUBFIC(u32 rd, u32 ra, s32 simm16) - { - DisAsm_R2_IMM("subfic", rd, ra, simm16); - } - void CMPLI(u32 crfd, u32 l, u32 ra, u32 uimm16) - { - DisAsm_CR1_R1_IMM(fmt::format("cmpl%si", (l ? "d" : "w")), crfd, ra, uimm16); - } - void CMPI(u32 crfd, u32 l, u32 ra, s32 simm16) - { - DisAsm_CR1_R1_IMM(fmt::format("cmp%si", (l ? "d" : "w")), crfd, ra, simm16); - } - void ADDIC(u32 rd, u32 ra, s32 simm16) - { - DisAsm_R2_IMM("addic", rd, ra, simm16); - } - void ADDIC_(u32 rd, u32 ra, s32 simm16) - { - DisAsm_R2_IMM("addic.", rd, ra, simm16); - } - void ADDI(u32 rd, u32 ra, s32 simm16) - { - if(ra == 0) - { - DisAsm_R1_IMM("li", rd, simm16); - } - else - { - DisAsm_R2_IMM("addi", rd, ra, simm16); - } - } - void ADDIS(u32 rd, u32 ra, s32 simm16) - { - if(ra == 0) - { - DisAsm_R1_IMM("lis", rd, simm16); - } - else - { - DisAsm_R2_IMM("addis", rd, ra, simm16); - } - } - void BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) - { - if(m_mode == CPUDisAsm_CompilerElfMode) - { - Write(fmt::format("bc 0x%x, 0x%x, 0x%x, %d, %d", bo, bi, bd, aa, lk)); - return; - } - - //TODO: aa lk - const u8 bo0 = (bo & 0x10) ? 1 : 0; - const u8 bo1 = (bo & 0x08) ? 1 : 0; - const u8 bo2 = (bo & 0x04) ? 1 : 0; - const u8 bo3 = (bo & 0x02) ? 1 : 0; - const u8 bo4 = (bo & 0x01) ? 1 : 0; - - if(bo0 && !bo1 && !bo2 && bo3 && !bo4) - { - DisAsm_CR_BRANCH("bdz", bi/4, bd); return; - } - else if(bo0 && bo1 && !bo2 && bo3 && !bo4) - { - DisAsm_CR_BRANCH("bdz-", bi/4, bd); return; - } - else if(bo0 && bo1 && !bo2 && bo3 && bo4) - { - DisAsm_CR_BRANCH("bdz+", bi/4, bd); return; - } - else if(bo0 && !bo1 && !bo2 && !bo3 && !bo4) - { - DisAsm_CR_BRANCH("bdnz", bi/4, bd); return; - } - else if(bo0 && bo1 && !bo2 && !bo3 && !bo4) - { - DisAsm_CR_BRANCH("bdnz-", bi/4, bd); return; - } - else if(bo0 && bo1 && !bo2 && !bo3 && bo4) - { - DisAsm_CR_BRANCH("bdnz+", bi/4, bd); return; - } - else if(!bo0 && !bo1 && bo2 && !bo3 && !bo4) - { - switch(bi % 4) - { - case 0x0: DisAsm_CR_BRANCH("bge", bi/4, bd); return; - case 0x1: DisAsm_CR_BRANCH("ble", bi/4, bd); return; - case 0x2: DisAsm_CR_BRANCH("bne", bi/4, bd); return; - } - } - else if(!bo0 && !bo1 && bo2 && bo3 && !bo4) - { - switch(bi % 4) - { - case 0x0: DisAsm_CR_BRANCH("bge-", bi/4, bd); return; - case 0x1: DisAsm_CR_BRANCH("ble-", bi/4, bd); return; - case 0x2: DisAsm_CR_BRANCH("bne-", bi/4, bd); return; - } - } - else if(!bo0 && !bo1 && bo2 && bo3 && bo4) - { - switch(bi % 4) - { - case 0x0: DisAsm_CR_BRANCH("bge+", bi/4, bd); return; - case 0x1: DisAsm_CR_BRANCH("ble+", bi/4, bd); return; - case 0x2: DisAsm_CR_BRANCH("bne+", bi/4, bd); return; - } - } - else if(!bo0 && bo1 && bo2 && !bo3 && !bo4) - { - switch(bi % 4) - { - case 0x0: DisAsm_CR_BRANCH("blt", bi/4, bd); return; - case 0x1: DisAsm_CR_BRANCH("bgt", bi/4, bd); return; - case 0x2: DisAsm_CR_BRANCH("beq", bi/4, bd); return; - } - } - else if(!bo0 && bo1 && bo2 && bo3 && !bo4) - { - switch(bi % 4) - { - case 0x0: DisAsm_CR_BRANCH("blt-", bi/4, bd); return; - case 0x1: DisAsm_CR_BRANCH("bgt-", bi/4, bd); return; - case 0x2: DisAsm_CR_BRANCH("beq-", bi/4, bd); return; - } - } - else if(!bo0 && bo1 && bo2 && bo3 && bo4) - { - switch(bi % 4) - { - case 0x0: DisAsm_CR_BRANCH("blt+", bi/4, bd); return; - case 0x1: DisAsm_CR_BRANCH("bgt+", bi/4, bd); return; - case 0x2: DisAsm_CR_BRANCH("beq+", bi/4, bd); return; - } - } - - Write(fmt::format("bc [%x:%x:%x:%x:%x], cr%d[%x], 0x%x, %d, %d", bo0, bo1, bo2, bo3, bo4, bi/4, bi%4, bd, aa, lk)); - } - void HACK(u32 index) - { - Write(fmt::format("hack %d", index)); - } - void SC(u32 lev) - { - switch (lev) - { - case 0x0: Write("sc"); break; - case 0x1: Write("HyperCall LV1"); break; - default: Write(fmt::format("Unknown sc: 0x%x", lev)); - } - } - void B(s32 ll, u32 aa, u32 lk) - { - if(m_mode == CPUDisAsm_CompilerElfMode) - { - Write(fmt::format("b 0x%x, %d, %d", ll, aa, lk)); - return; - } - - switch(lk) - { - case 0: - switch(aa) - { - case 0: DisAsm_BRANCH("b", ll); break; - case 1: DisAsm_BRANCH_A("ba", ll); break; - } - break; - - case 1: - switch(aa) - { - case 0: DisAsm_BRANCH("bl", ll); break; - case 1: DisAsm_BRANCH_A("bla", ll); break; - } - break; - } - } - void MCRF(u32 crfd, u32 crfs) - { - DisAsm_CR2("mcrf", crfd, crfs); - } - void BCLR(u32 bo, u32 bi, u32 bh, u32 lk) - { - const u8 bo0 = (bo & 0x10) ? 1 : 0; - const u8 bo1 = (bo & 0x08) ? 1 : 0; - const u8 bo2 = (bo & 0x04) ? 1 : 0; - const u8 bo3 = (bo & 0x02) ? 1 : 0; - - if(bo0 && !bo1 && bo2 && !bo3) {Write("blr"); return;} - Write(fmt::format("bclr [%x:%x:%x:%x], cr%d[%x], %d, %d", bo0, bo1, bo2, bo3, bi/4, bi%4, bh, lk)); - } - void CRNOR(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("crnor", bt, ba, bb); - } - void CRANDC(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("crandc", bt, ba, bb); - } - void ISYNC() - { - Write("isync"); - } - void CRXOR(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("crxor", bt, ba, bb); - } - void CRNAND(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("crnand", bt, ba, bb); - } - void CRAND(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("crand", bt, ba, bb); - } - void CREQV(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("creqv", bt, ba, bb); - } - void CRORC(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("crorc", bt, ba, bb); - } - void CROR(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("cror", bt, ba, bb); - } - void BCCTR(u32 bo, u32 bi, u32 bh, u32 lk) - { - switch(lk) - { - case 0: DisAsm_INT3("bcctr", bo, bi, bh); break; - case 1: DisAsm_INT3("bcctrl", bo, bi, bh); break; - } - } - void RLWIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) - { - DisAsm_R2_INT3_RC("rlwimi", ra, rs, sh, mb, me, rc); - } - void RLWINM(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) - { - DisAsm_R2_INT3_RC("rlwinm", ra, rs, sh, mb, me, rc); - } - void RLWNM(u32 ra, u32 rs, u32 rb, u32 MB, u32 ME, u32 rc) - { - DisAsm_R3_INT2_RC("rlwnm", ra, rs, rb, MB, ME, rc); - } - void ORI(u32 rs, u32 ra, u32 uimm16) - { - if(rs == 0 && ra == 0 && uimm16 == 0) - { - NOP(); - return; - } - DisAsm_R2_IMM("ori", rs, ra, uimm16); - } - void ORIS(u32 rs, u32 ra, u32 uimm16) - { - if(rs == 0 && ra == 0 && uimm16 == 0) - { - NOP(); - return; - } - DisAsm_R2_IMM("oris", rs, ra, uimm16); - } - void XORI(u32 ra, u32 rs, u32 uimm16) - { - DisAsm_R2_IMM("xori", ra, rs, uimm16); - } - void XORIS(u32 ra, u32 rs, u32 uimm16) - { - DisAsm_R2_IMM("xoris", ra, rs, uimm16); - } - void ANDI_(u32 ra, u32 rs, u32 uimm16) - { - DisAsm_R2_IMM("andi.", ra, rs, uimm16); - } - void ANDIS_(u32 ra, u32 rs, u32 uimm16) - { - DisAsm_R2_IMM("andis.", ra, rs, uimm16); - } - void RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) - { - if(sh == 0) - { - DisAsm_R2_INT1_RC("clrldi", ra, rs, mb, rc); - } - else if(mb == 0) - { - DisAsm_R2_INT1_RC("rotldi", ra, rs, sh, rc); - } - else if(mb == 64 - sh) - { - DisAsm_R2_INT1_RC("srdi", ra, rs, mb, rc); - } - else - { - DisAsm_R2_INT2_RC("rldicl", ra, rs, sh, mb, rc); - } - } - void RLDICR(u32 ra, u32 rs, u32 sh, u32 me, u32 rc) - { - DisAsm_R2_INT2_RC("rldicr", ra, rs, sh, me, rc); - } - void RLDIC(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) - { - DisAsm_R2_INT2_RC("rldic", ra, rs, sh, mb, rc); - } - void RLDIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) - { - DisAsm_R2_INT2_RC("rldimi", ra, rs, sh, mb, rc); - } - void RLDC_LR(u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc) - { - if (is_r) - DisAsm_R3_INT2_RC("rldcr", ra, rs, rb, m_eb, 0, rc); - else - DisAsm_R3_INT2_RC("rldcl", ra, rs, rb, m_eb, 0, rc); - } - void CMP(u32 crfd, u32 l, u32 ra, u32 rb) - { - DisAsm_CR1_R2(fmt::format("cmp%s", (l ? "d" : "w")), crfd, ra, rb); - } - void TW(u32 to, u32 ra, u32 rb) - { - DisAsm_INT1_R2("tw", to, ra, rb); - } - void LVSL(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvsl", vd, ra, rb); - } - void LVEBX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvebx", vd, ra, rb); - } - void SUBFC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("subfc", rd, ra, rb, oe, rc); - } - void ADDC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("addc", rd, ra, rb, oe, rc); - } - void MULHDU(u32 rd, u32 ra, u32 rb, u32 rc) - { - DisAsm_R3_RC("mulhdu", rd, ra, rb, rc); - } - void MULHWU(u32 rd, u32 ra, u32 rb, u32 rc) - { - DisAsm_R3_RC("mulhwu", rd, ra, rb, rc); - } - void MFOCRF(u32 a, u32 rd, u32 crm) - { - if(a) - { - DisAsm_R1_IMM("mfocrf", rd, crm); - } - else - { - DisAsm_R1("mfcr", rd); - } - } - void LWARX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lwarx", rd, ra, rb); - } - void LDX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("ldx", rd, ra, rb); - } - void LWZX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lwzx", rd, ra, rb); - } - void SLW(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("slw", ra, rs, rb, rc); - } - void CNTLZW(u32 ra, u32 rs, u32 rc) - { - DisAsm_R2_RC("cntlzw", ra, rs, rc); - } - void SLD(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("sld", ra, rs, rb, rc); - } - void AND(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("and", ra, rs, rb, rc); - } - void CMPL(u32 crfd, u32 l, u32 ra, u32 rb) - { - DisAsm_CR1_R2(fmt::format("cmpl%s", (l ? "d" : "w")), crfd, ra, rb); - } - void LVSR(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvsr", vd, ra, rb); - } - void LVEHX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvehx", vd, ra, rb); - } - void SUBF(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("subf", rd, ra, rb, oe, rc); - } - void LDUX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("ldux", rd, ra, rb); - } - void DCBST(u32 ra, u32 rb) - { - DisAsm_R2("dcbst", ra, rb); - } - void LWZUX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lwzux", rd, ra, rb); - } - void CNTLZD(u32 ra, u32 rs, u32 rc) - { - DisAsm_R2_RC("cntlzd", ra, rs, rc); - } - void ANDC(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("andc", ra, rs, rb, rc); - } - void TD(u32 to, u32 ra, u32 rb) - { - DisAsm_INT1_R2("td", to, ra, rb); - } - void LVEWX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvewx", vd, ra, rb); - } - void MULHD(u32 rd, u32 ra, u32 rb, u32 rc) - { - DisAsm_R3_RC("mulhd", rd, ra, rb, rc); - } - void MULHW(u32 rd, u32 ra, u32 rb, u32 rc) - { - DisAsm_R3_RC("mulhw", rd, ra, rb, rc); - } - void LDARX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("ldarx", rd, ra, rb); - } - void DCBF(u32 ra, u32 rb) - { - DisAsm_R2("dcbf", ra, rb); - } - void LBZX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lbzx", rd, ra, rb); - } - void LVX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvx", vd, ra, rb); - } - void NEG(u32 rd, u32 ra, u32 oe, u32 rc) - { - DisAsm_R2_OE_RC("neg", rd, ra, oe, rc); - } - void LBZUX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lbzux", rd, ra, rb); - } - void NOR(u32 ra, u32 rs, u32 rb, u32 rc) - { - if(rs == rb) - { - DisAsm_R2_RC("not", ra, rs, rc); - } - else - { - DisAsm_R3_RC("nor", ra, rs, rb, rc); - } - } - void STVEBX(u32 vs, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvebx", vs, ra, rb); - } - void SUBFE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("subfe", rd, ra, rb, oe, rc); - } - void ADDE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("adde", rd, ra, rb, oe, rc); - } - void MTOCRF(u32 l, u32 crm, u32 rs) - { - if(l) - { - DisAsm_INT1_R1("mtocrf", crm, rs); - } - else - { - DisAsm_INT1_R1("mtcrf", crm, rs); - } - } - void STDX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stdx.", rs, ra, rb); - } - void STWCX_(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stwcx.", rs, ra, rb); - } - void STWX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stwx", rs, ra, rb); - } - void STVEHX(u32 vs, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvehx", vs, ra, rb); - } - void STDUX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stdux", rs, ra, rb); - } - void STWUX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stwux", rs, ra, rb); - } - void STVEWX(u32 vs, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvewx", vs, ra, rb); - } - void SUBFZE(u32 rd, u32 ra, u32 oe, u32 rc) - { - DisAsm_R2_OE_RC("subfze", rd, ra, oe, rc); - } - void ADDZE(u32 rd, u32 ra, u32 oe, u32 rc) - { - DisAsm_R2_OE_RC("addze", rd, ra, oe, rc); - } - void STDCX_(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stdcx.", rs, ra, rb); - } - void STBX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stbx", rs, ra, rb); - } - void STVX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvx", vd, ra, rb); - } - void SUBFME(u32 rd, u32 ra, u32 oe, u32 rc) - { - DisAsm_R2_OE_RC("subfme", rd, ra, oe, rc); - } - void MULLD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("mulld", rd, ra, rb, oe, rc); - } - void ADDME(u32 rd, u32 ra, u32 oe, u32 rc) - { - DisAsm_R2_OE_RC("addme", rd, ra, oe, rc); - } - void MULLW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("mullw", rd, ra, rb, oe, rc); - } - void DCBTST(u32 ra, u32 rb, u32 th) - { - DisAsm_R3("dcbtst", ra, rb, th); - } - void STBUX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stbux", rs, ra, rb); - } - void ADD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("add", rd, ra, rb, oe, rc); - } - void DCBT(u32 ra, u32 rb, u32 th) - { - DisAsm_R2("dcbt", ra, rb); - } - void LHZX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lhzx", rd, ra, rb); - } - void EQV(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("eqv", ra, rs, rb, rc); - } - void ECIWX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("eciwx", rd, ra, rb); - } - void LHZUX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lhzux", rd, ra, rb); - } - void XOR(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("xor", ra, rs, rb, rc); - } - void MFSPR(u32 rd, u32 spr) - { - const u32 n = (spr >> 5) | ((spr & 0x1f) << 5); - switch(n) - { - case 0x001: DisAsm_R1("mfxer", rd); break; - case 0x008: DisAsm_R1("mflr", rd); break; - case 0x009: DisAsm_R1("mfctr", rd); break; - default: DisAsm_R1_IMM("mfspr", rd, spr); break; - } - } - void LWAX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lwax", rd, ra, rb); - } - void DST(u32 ra, u32 rb, u32 strm, u32 t) - { - if(t) - { - DisAsm_R2_INT1("dstt", ra, rb, strm); - } - else - { - DisAsm_R2_INT1("dst", ra, rb, strm); - } - } - void LHAX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lhax", rd, ra, rb); - } - void LVXL(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvxl", vd, ra, rb); - } - void MFTB(u32 rd, u32 spr) - { - const u32 n = (spr >> 5) | ((spr & 0x1f) << 5); - switch(n) - { - case 268: DisAsm_R1("mftb", rd); break; - case 269: DisAsm_R1("mftbu", rd); break; - default: DisAsm_R1_IMM("mftb", rd, spr); break; - } - } - void LWAUX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lwaux", rd, ra, rb); - } - void DSTST(u32 ra, u32 rb, u32 strm, u32 t) - { - if(t) - { - DisAsm_R2_INT1("dststt", ra, rb, strm); - } - else - { - DisAsm_R2_INT1("dstst", ra, rb, strm); - } - } - void LHAUX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lhaux", rd, ra, rb); - } - void STHX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("sthx", rs, ra, rb); - } - void ORC(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("orc", ra, rs, rb, rc); - } - void ECOWX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("ecowx", rs, ra, rb); - } - void STHUX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("sthux", rs, ra, rb); - } - void OR(u32 ra, u32 rs, u32 rb, u32 rc) - { - if(rs==rb) - { - DisAsm_R2_RC("mr", ra, rb, rc); - } - else - { - DisAsm_R3_RC("or", ra, rs, rb, rc); - } - } - void DIVDU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("divdu", rd, ra, rb, oe, rc); - } - void DIVWU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("divwu", rd, ra, rb, oe, rc); - } - void MTSPR(u32 spr, u32 rs) - { - const u32 n = (spr & 0x1f) + ((spr >> 5) & 0x1f); - - switch(n) - { - case 0x001: DisAsm_R1("mtxer", rs); break; - case 0x008: DisAsm_R1("mtlr", rs); break; - case 0x009: DisAsm_R1("mtctr", rs); break; - default: DisAsm_IMM_R1("mtspr", spr, rs); break; - } - } - void DCBI(u32 ra, u32 rb) - { - DisAsm_R2("dcbi", ra, rb); - } - void NAND(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("nand", ra, rs, rb, rc); - } - void STVXL(u32 vs, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvxl", vs, ra, rb); - } - void DIVD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("divd", rd, ra, rb, oe, rc); - } - void DIVW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("divw", rd, ra, rb, oe, rc); - } - void LVLX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvlx", vd, ra, rb); - } - void LDBRX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("ldbrx", rd, ra, rb); - } - void LSWX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lswx", rd, ra, rb); - } - void LWBRX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lwbrx", rd, ra, rb); - } - void LFSX(u32 frd, u32 ra, u32 rb) - { - DisAsm_F1_R2("lfsx", frd, ra, rb); - } - void SRW(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("srw", ra, rs, rb, rc); - } - void SRD(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("srd", ra, rs, rb, rc); - } - void LVRX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvrx", vd, ra, rb); - } - void LSWI(u32 rd, u32 ra, u32 nb) - { - DisAsm_R2_INT1("lswi", rd, ra, nb); - } - void LFSUX(u32 frd, u32 ra, u32 rb) - { - DisAsm_F1_R2("lfsux", frd, ra, rb); - } - void SYNC(u32 l) - { - DisAsm_INT1("sync", l); - } - void LFDX(u32 frd, u32 ra, u32 rb) - { - DisAsm_F1_R2("lfdx", frd, ra, rb); - } - void LFDUX(u32 frd, u32 ra, u32 rb) - { - DisAsm_F1_R2("lfdux", frd, ra, rb); - } - void STVLX(u32 vs, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvlx", vs, ra, rb); - } - void STDBRX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stdbrx", rs, ra, rb); - } - void STSWX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("swswx", rs, ra, rb); - } - void STWBRX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stwbrx", rs, ra, rb); - } - void STFSX(u32 frs, u32 ra, u32 rb) - { - DisAsm_F1_R2("stfsx", frs, ra, rb); - } - void STVRX(u32 sd, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvrx", sd, ra, rb); - } - void STFSUX(u32 frs, u32 ra, u32 rb) - { - DisAsm_F1_R2("stfsux", frs, ra, rb); - } - void STSWI(u32 rd, u32 ra, u32 nb) - { - DisAsm_R2_INT1("stswi", rd, ra, nb); - } - void STFDX(u32 frs, u32 ra, u32 rb) - { - DisAsm_F1_R2("stfdx", frs, ra, rb); - } - void STFDUX(u32 frs, u32 ra, u32 rb) - { - DisAsm_F1_R2("stfdux", frs, ra, rb); - } - void LVLXL(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvlxl", vd, ra, rb); - } - void LHBRX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lhbrx", rd, ra, rb); - } - void SRAW(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("sraw", ra, rs, rb, rc); - } - void SRAD(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("srad", ra, rs, rb, rc); - } - void LVRXL(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvrxl", vd, ra, rb); - } - void DSS(u32 strm, u32 a) - { - if(a) - { - Write("dssall"); - } - else - { - DisAsm_INT1("dss", strm); - } - } - void SRAWI(u32 ra, u32 rs, u32 sh, u32 rc) - { - DisAsm_R2_INT1_RC("srawi", ra, rs, sh, rc); - } - void SRADI1(u32 ra, u32 rs, u32 sh, u32 rc) - { - DisAsm_R2_INT1_RC("sradi", ra, rs, sh, rc); - } - void SRADI2(u32 ra, u32 rs, u32 sh, u32 rc) - { - DisAsm_R2_INT1_RC("sradi", ra, rs, sh, rc); - } - void EIEIO() - { - Write("eieio"); - } - void STVLXL(u32 vs, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvlxl", vs, ra, rb); - } - void STHBRX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("sthbrx", rs, ra, rb); - } - void EXTSH(u32 ra, u32 rs, u32 rc) - { - DisAsm_R2_RC("extsh", ra, rs, rc); - } - void STVRXL(u32 sd, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvrxl", sd, ra, rb); - } - void EXTSB(u32 ra, u32 rs, u32 rc) - { - DisAsm_R2_RC("extsb", ra, rs, rc); - } - void STFIWX(u32 frs, u32 ra, u32 rb) - { - DisAsm_F1_R2("stfiwx", frs, ra, rb); - } - void EXTSW(u32 ra, u32 rs, u32 rc) - { - DisAsm_R2_RC("extsw", ra, rs, rc); - } - void ICBI(u32 ra, u32 rb) - { - DisAsm_R2("icbi", ra, rb); - } - void DCBZ(u32 ra, u32 rb) - { - DisAsm_R2("dcbz", ra, rb); - } - void LWZ(u32 rd, u32 ra, s32 d) - { - DisAsm_R2_IMM("lwz", rd, ra, d); - } - void LWZU(u32 rd, u32 ra, s32 d) - { - DisAsm_R2_IMM("lwzu", rd, ra, d); - } - void LBZ(u32 rd, u32 ra, s32 d) - { - DisAsm_R2_IMM("lbz", rd, ra, d); - } - void LBZU(u32 rd, u32 ra, s32 d) - { - DisAsm_R2_IMM("lbzu", rd, ra, d); - } - void STW(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("stw", rs, ra, d); - } - void STWU(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("stwu", rs, ra, d); - } - void STB(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("stb", rs, ra, d); - } - void STBU(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("stbu", rs, ra, d); - } - void LHZ(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("lhz", rs, ra, d); - } - void LHZU(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("lhzu", rs, ra, d); - } - void LHA(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("lha", rs, ra, d); - } - void LHAU(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("lhau", rs, ra, d); - } - void STH(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("sth", rs, ra, d); - } - void STHU(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("sthu", rs, ra, d); - } - void LMW(u32 rd, u32 ra, s32 d) - { - DisAsm_R2_IMM("lmw", rd, ra, d); - } - void STMW(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("stmw", rs, ra, d); - } - void LFS(u32 frd, u32 ra, s32 d) - { - DisAsm_F1_IMM_R1("lfs", frd, d, ra); - } - void LFSU(u32 frd, u32 ra, s32 ds) - { - DisAsm_F1_IMM_R1("lfsu", frd, ds, ra); - } - void LFD(u32 frd, u32 ra, s32 d) - { - DisAsm_F1_IMM_R1("lfd", frd, d, ra); - } - void LFDU(u32 frd, u32 ra, s32 ds) - { - DisAsm_F1_IMM_R1("lfdu", frd, ds, ra); - } - void STFS(u32 frs, u32 ra, s32 d) - { - DisAsm_F1_IMM_R1("stfs", frs, d, ra); - } - void STFSU(u32 frs, u32 ra, s32 d) - { - DisAsm_F1_IMM_R1("stfsu", frs, d, ra); - } - void STFD(u32 frs, u32 ra, s32 d) - { - DisAsm_F1_IMM_R1("stfd", frs, d, ra); - } - void STFDU(u32 frs, u32 ra, s32 d) - { - DisAsm_F1_IMM_R1("stfdu", frs, d, ra); - } - void LD(u32 rd, u32 ra, s32 ds) - { - DisAsm_R2_IMM("ld", rd, ra, ds); - } - void LDU(u32 rd, u32 ra, s32 ds) - { - DisAsm_R2_IMM("ldu", rd, ra, ds); - } - void LWA(u32 rd, u32 ra, s32 ds) - { - DisAsm_R2_IMM("lwa", rd, ra, ds); - } - void FDIVS(u32 frd, u32 fra, u32 frb, u32 rc) - { - DisAsm_F3_RC("fdivs", frd, fra, frb, rc); - } - void FSUBS(u32 frd, u32 fra, u32 frb, u32 rc) - { - DisAsm_F3_RC("fsubs", frd, fra, frb, rc); - } - void FADDS(u32 frd, u32 fra, u32 frb, u32 rc) - { - DisAsm_F3_RC("fadds", frd, fra, frb, rc); - } - void FSQRTS(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fsqrts", frd, frb, rc); - } - void FRES(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fres", frd, frb, rc); - } - void FMULS(u32 frd, u32 fra, u32 frc, u32 rc) - { - DisAsm_F3_RC("fmuls", frd, fra, frc, rc); - } - void FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fmadds", frd, fra, frc, frb, rc); - } - void FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fmsubs", frd, fra, frc, frb, rc); - } - void FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fnmsubs", frd, fra, frc, frb, rc); - } - void FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fnmadds", frd, fra, frc, frb, rc); - } - void STD(u32 rs, u32 ra, s32 ds) - { - DisAsm_R2_IMM("std", rs, ra, ds); - } - void STDU(u32 rs, u32 ra, s32 ds) - { - DisAsm_R2_IMM("stdu", rs, ra, ds); - } - void MTFSB1(u32 bt, u32 rc) - { - DisAsm_F1_RC("mtfsb1", bt, rc); - } - void MCRFS(u32 bf, u32 bfa) - { - DisAsm_F2("mcrfs", bf, bfa); - } - void MTFSB0(u32 bt, u32 rc) - { - DisAsm_F1_RC("mtfsb0", bt, rc); - } - void MTFSFI(u32 crfd, u32 i, u32 rc) - { - DisAsm_F2_RC("mtfsfi", crfd, i, rc); - } - void MFFS(u32 frd, u32 rc) - { - DisAsm_F1_RC("mffs", frd, rc); - } - void MTFSF(u32 flm, u32 frb, u32 rc) - { - DisAsm_F2_RC("mtfsf", flm, frb, rc); - } - void FCMPU(u32 crfd, u32 fra, u32 frb) - { - DisAsm_CR1_F2("fcmpu", crfd, fra, frb); - } - void FRSP(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("frsp", frd, frb, rc); - } - void FCTIW(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fctiw", frd, frb, rc); - } - void FCTIWZ(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fctiwz", frd, frb, rc); - } - void FDIV(u32 frd, u32 fra, u32 frb, u32 rc) - { - DisAsm_F3_RC("fdiv", frd, fra, frb, rc); - } - void FSUB(u32 frd, u32 fra, u32 frb, u32 rc) - { - DisAsm_F3_RC("fsub", frd, fra, frb, rc); - } - void FADD(u32 frd, u32 fra, u32 frb, u32 rc) - { - DisAsm_F3_RC("fadd", frd, fra, frb, rc); - } - void FSQRT(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fsqrt", frd, frb, rc); - } - void FSEL(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fsel", frd, fra, frc, frb, rc); - } - void FMUL(u32 frd, u32 fra, u32 frc, u32 rc) - { - DisAsm_F3_RC("fmul", frd, fra, frc, rc); - } - void FRSQRTE(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("frsqrte", frd, frb, rc); - } - void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fmsub", frd, fra, frc, frb, rc); - } - void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fmadd", frd, fra, frc, frb, rc); - } - void FNMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fnmsub", frd, fra, frc, frb, rc); - } - void FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fnmadd", frd, fra, frc, frb, rc); - } - void FCMPO(u32 crfd, u32 fra, u32 frb) - { - DisAsm_F3("fcmpo", crfd, fra, frb); - } - void FNEG(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fneg", frd, frb, rc); - } - void FMR(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fmr", frd, frb, rc); - } - void FNABS(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fnabs", frd, frb, rc); - } - void FABS(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fabs", frd, frb, rc); - } - void FCTID(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fctid", frd, frb, rc); - } - void FCTIDZ(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fctidz", frd, frb, rc); - } - void FCFID(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fcfid", frd, frb, rc); - } - - void UNK(const u32 code, const u32 opcode, const u32 gcode) - { - Write(fmt::format("Unknown/Illegal opcode! (0x%08x : 0x%x : 0x%x)", code, opcode, gcode)); - } + void UNK(ppu_opcode_t op); }; - -#undef START_OPCODES_GROUP -#undef END_OPCODES_GROUP diff --git a/rpcs3/Emu/Cell/PPUFunction.cpp b/rpcs3/Emu/Cell/PPUFunction.cpp new file mode 100644 index 0000000000..8ad14ff3db --- /dev/null +++ b/rpcs3/Emu/Cell/PPUFunction.cpp @@ -0,0 +1,2379 @@ +#include "stdafx.h" +#include "PPUModule.h" + +extern std::string ppu_get_syscall_name(u64 code) +{ + switch (code) + { + case 1: return "sys_process_getpid"; + case 2: return "sys_process_wait_for_child"; + case 3: return "sys_process_exit"; + case 4: return "sys_process_get_status"; + case 5: return "sys_process_detach_child"; + case 12: return "sys_process_get_number_of_object"; + case 13: return "sys_process_get_id"; + case 14: return "sys_process_is_spu_lock_line_reservation_address"; + case 18: return "sys_process_getppid"; + case 19: return "sys_process_kill"; + case 21: return "_sys_process_spawn"; + case 22: return "sys_process_exit"; + case 23: return "sys_process_wait_for_child2"; + case 25: return "sys_process_get_sdk_version"; + case 26: return "_sys_process_exit"; + case 28: return "_sys_process_get_number_of_object"; + case 29: return "sys_process_get_id"; + case 30: return "_sys_process_get_paramsfo"; + case 31: return "sys_process_get_ppu_guid"; + case 41: return "_sys_ppu_thread_exit"; + case 43: return "sys_ppu_thread_yield"; + case 44: return "sys_ppu_thread_join"; + case 45: return "sys_ppu_thread_detach"; + case 46: return "sys_ppu_thread_get_join_state"; + case 47: return "sys_ppu_thread_set_priority"; + case 48: return "sys_ppu_thread_get_priority"; + case 49: return "sys_ppu_thread_get_stack_information"; + case 50: return "sys_ppu_thread_stop"; + case 51: return "sys_ppu_thread_restart"; + case 52: return "_sys_ppu_thread_create"; + case 53: return "sys_ppu_thread_start"; + case 56: return "sys_ppu_thread_rename"; + case 57: return "sys_ppu_thread_recover_page_fault"; + case 58: return "sys_ppu_thread_get_page_fault_context"; + case 60: return "sys_trace_create"; + case 61: return "sys_trace_start"; + case 62: return "sys_trace_stop"; + case 63: return "sys_trace_update_top_index"; + case 64: return "sys_trace_destroy"; + case 65: return "sys_trace_drain"; + case 66: return "sys_trace_attach_process"; + case 67: return "sys_trace_allocate_buffer"; + case 68: return "sys_trace_free_buffer"; + case 69: return "sys_trace_create2"; + case 70: return "sys_timer_create"; + case 71: return "sys_timer_destroy"; + case 72: return "sys_timer_get_information"; + case 73: return "_sys_timer_start"; + case 74: return "sys_timer_stop"; + case 75: return "sys_timer_connect_event_queue"; + case 76: return "sys_timer_disconnect_event_queue"; + case 77: return "sys_trace_create2_in_cbepm"; + case 80: return "sys_interrupt_tag_create"; + case 81: return "sys_interrupt_tag_destroy"; + case 82: return "sys_event_flag_create"; + case 83: return "sys_event_flag_destroy"; + case 84: return "_sys_interrupt_thread_establish"; + case 85: return "sys_event_flag_wait"; + case 86: return "sys_event_flag_trywait"; + case 87: return "sys_event_flag_set"; + case 88: return "sys_interrupt_thread_eoi"; + case 89: return "_sys_interrupt_thread_disestablish"; + case 90: return "sys_semaphore_create"; + case 91: return "sys_semaphore_destroy"; + case 92: return "sys_semaphore_wait"; + case 93: return "sys_semaphore_trywait"; + case 94: return "sys_semaphore_post"; + case 95: return "_sys_lwmutex_create"; + case 96: return "_sys_lwmutex_destroy"; + case 97: return "_sys_lwmutex_lock"; + case 98: return "_sys_lwmutex_unlock"; + case 99: return "_sys_lwmutex_trylock"; + case 100: return "sys_mutex_create"; + case 101: return "sys_mutex_destroy"; + case 102: return "sys_mutex_lock"; + case 103: return "sys_mutex_trylock"; + case 104: return "sys_mutex_unlock"; + case 105: return "sys_cond_create"; + case 106: return "sys_cond_destroy"; + case 107: return "sys_cond_wait"; + case 108: return "sys_cond_signal"; + case 109: return "sys_cond_signal_all"; + case 110: return "sys_cond_signal_to"; + case 111: return "_sys_lwcond_create"; + case 112: return "_sys_lwcond_destroy"; + case 113: return "_sys_lwcond_queue_wait"; + case 114: return "sys_semaphore_get_value"; + case 115: return "_sys_lwcond_signal"; + case 116: return "_sys_lwcond_signal_all"; + case 118: return "sys_event_flag_clear"; + case 120: return "sys_rwlock_create"; + case 121: return "sys_rwlock_destroy"; + case 122: return "sys_rwlock_rlock"; + case 123: return "sys_rwlock_tryrlock"; + case 124: return "sys_rwlock_runlock"; + case 125: return "sys_rwlock_wlock"; + case 126: return "sys_rwlock_trywlock"; + case 127: return "sys_rwlock_wunlock"; + case 128: return "sys_event_queue_create"; + case 129: return "sys_event_queue_destroy"; + case 130: return "sys_event_queue_receive"; + case 131: return "sys_event_queue_tryreceive"; + case 132: return "sys_event_flag_cancel"; + case 133: return "sys_event_queue_drain"; + case 134: return "sys_event_port_create"; + case 135: return "sys_event_port_destroy"; + case 136: return "sys_event_port_connect_local"; + case 137: return "sys_event_port_disconnect"; + case 138: return "sys_event_port_send"; + case 139: return "sys_event_flag_get"; + case 140: return "sys_event_port_connect_ipc"; + case 141: return "sys_timer_usleep"; + case 142: return "sys_timer_sleep"; + case 143: return "sys_time_set_timezone"; + case 144: return "sys_time_get_timezone"; + case 145: return "sys_time_get_current_time"; + case 146: return "sys_time_get_system_time"; + case 147: return "sys_time_get_timebase_frequency"; + case 148: return "_sys_rwlock_trywlock"; + case 150: return "sys_raw_spu_create_interrupt_tag"; + case 151: return "sys_raw_spu_set_int_mask"; + case 152: return "sys_raw_spu_get_int_mask"; + case 153: return "sys_raw_spu_set_int_stat"; + case 154: return "sys_raw_spu_get_int_stat"; + case 155: return "sys_spu_image_get_information?"; + case 156: return "sys_spu_image_open"; + case 157: return "sys_spu_image_import"; + case 158: return "sys_spu_image_close"; + case 159: return "sys_raw_spu_load"; + case 160: return "sys_raw_spu_create"; + case 161: return "sys_raw_spu_destroy"; + case 163: return "sys_raw_spu_read_puint_mb"; + case 165: return "sys_spu_thread_get_exit_status"; + case 166: return "sys_spu_thread_set_argument"; + case 167: return "sys_spu_thread_group_start_on_exit"; + case 169: return "sys_spu_initialize"; + case 170: return "sys_spu_thread_group_create"; + case 171: return "sys_spu_thread_group_destroy"; + case 172: return "sys_spu_thread_initialize"; + case 173: return "sys_spu_thread_group_start"; + case 174: return "sys_spu_thread_group_suspend"; + case 175: return "sys_spu_thread_group_resume"; + case 176: return "sys_spu_thread_group_yield"; + case 177: return "sys_spu_thread_group_terminate"; + case 178: return "sys_spu_thread_group_join"; + case 179: return "sys_spu_thread_group_set_priority"; + case 180: return "sys_spu_thread_group_get_priority"; + case 181: return "sys_spu_thread_write_ls"; + case 182: return "sys_spu_thread_read_ls"; + case 184: return "sys_spu_thread_write_snr"; + case 185: return "sys_spu_thread_group_connect_event"; + case 186: return "sys_spu_thread_group_disconnect_event"; + case 187: return "sys_spu_thread_set_spu_cfg"; + case 188: return "sys_spu_thread_get_spu_cfg"; + case 190: return "sys_spu_thread_write_spu_mb"; + case 191: return "sys_spu_thread_connect_event"; + case 192: return "sys_spu_thread_disconnect_event"; + case 193: return "sys_spu_thread_bind_queue"; + case 194: return "sys_spu_thread_unbind_queue"; + case 196: return "sys_raw_spu_set_spu_cfg"; + case 197: return "sys_raw_spu_get_spu_cfg"; + case 198: return "sys_spu_thread_recover_page_fault"; + case 199: return "sys_raw_spu_recover_page_fault"; + case 215: return "sys_dbg_mat_set_condition"; + case 216: return "sys_dbg_mat_get_condition"; + case 230: return "sys_isolated_spu_create"; + case 231: return "sys_isolated_spu_destroy"; + case 232: return "sys_isolated_spu_start"; + case 233: return "sys_isolated_spu_create_interrupt_tag"; + case 234: return "sys_isolated_spu_set_int_mask"; + case 235: return "sys_isolated_spu_get_int_mask"; + case 236: return "sys_isolated_spu_set_int_stat"; + case 237: return "sys_isolated_spu_get_int_stat"; + case 238: return "sys_isolated_spu_set_spu_cfg"; + case 239: return "sys_isolated_spu_get_spu_cfg"; + case 240: return "sys_isolated_spu_read_puint_mb"; + case 244: return "sys_spu_thread_group_system_set_next_group"; + case 245: return "sys_spu_thread_group_system_unset_next_group"; + case 246: return "sys_spu_thread_group_system_set_switch_group"; + case 247: return "sys_spu_thread_group_system_unset_switch_group"; + case 250: return "sys_spu_thread_group_set_cooperative_victims"; + case 251: return "sys_spu_thread_group_connect_event_all_threads"; + case 252: return "sys_spu_thread_group_disconnect_event_all_threads"; + case 254: return "sys_spu_thread_group_log"; + case 260: return "sys_spu_image_open_by_fd"; + case 300: return "sys_vm_memory_map"; + case 301: return "sys_vm_unmap"; + case 302: return "sys_vm_append_memory"; + case 303: return "sys_vm_return_memory"; + case 304: return "sys_vm_lock"; + case 305: return "sys_vm_unlock"; + case 306: return "sys_vm_touch"; + case 307: return "sys_vm_flush"; + case 308: return "sys_vm_invalidate"; + case 309: return "sys_vm_store"; + case 310: return "sys_vm_sync"; + case 311: return "sys_vm_test"; + case 312: return "sys_vm_get_statistics"; + case 324: return "sys_memory_container_create"; + case 325: return "sys_memory_container_destroy"; + case 326: return "sys_mmapper_allocate_fixed_address"; + case 327: return "sys_mmapper_enable_page_fault_notification"; + case 329: return "sys_mmapper_free_shared_memory"; + case 330: return "sys_mmapper_allocate_address"; + case 331: return "sys_mmapper_free_address"; + case 332: return "sys_mmapper_allocate_shared_memory"; + case 333: return "sys_mmapper_set_shared_memory_flag"; + case 334: return "sys_mmapper_map_shared_memory"; + case 335: return "sys_mmapper_unmap_shared_memory"; + case 336: return "sys_mmapper_change_address_access_right"; + case 337: return "sys_mmapper_search_and_map"; + case 338: return "sys_mmapper_get_shared_memory_attribute"; + case 341: return "sys_memory_container_create"; + case 342: return "sys_memory_container_destroy"; + case 343: return "sys_memory_container_get_size"; + case 344: return "sys_memory_budget_set"; + case 348: return "sys_memory_allocate"; + case 349: return "sys_memory_free"; + case 350: return "sys_memory_allocate_from_container"; + case 351: return "sys_memory_get_page_attribute"; + case 352: return "sys_memory_get_user_memory_size"; + case 353: return "sys_memory_get_user_memory_stat"; + case 356: return "sys_memory_allocate_colored"; + case 361: return "sys_memory_allocate_from_container_colored"; + case 362: return "sys_mmapper_allocate_memory_from_container"; + case 367: return "sys_uart_initialize"; + case 368: return "sys_uart_receive"; + case 369: return "sys_uart_send"; + case 370: return "sys_uart_get_params"; + case 372: return "sys_game_watchdog_start"; + case 373: return "sys_game_watchdog_stop"; + case 374: return "sys_game_watchdog_clear"; + case 375: return "sys_game_set_system_sw_version"; + case 376: return "sys_game_get_system_sw_version"; + case 377: return "sys_sm_set_shop_mode"; + case 378: return "sys_sm_get_ext_event2"; + case 379: return "sys_sm_shutdown"; + case 380: return "sys_sm_get_params"; + case 381: return "sys_sm_get_inter_lpar_parameter"; + case 383: return "sys_game_get_temperature"; + case 384: return "sys_sm_get_tzpb"; + case 385: return "sys_sm_request_led"; + case 386: return "sys_sm_control_led"; + case 387: return "sys_sm_get_platform_info"; + case 388: return "sys_sm_ring_buzzer"; + case 389: return "sys_sm_set_fan_policy"; + case 390: return "sys_sm_request_error_log"; + case 391: return "sys_sm_request_be_count"; + case 392: return "sys_sm_ring_buzzer"; + case 393: return "sys_sm_get_hw_config"; + case 394: return "sys_sm_request_scversion"; + case 395: return "sys_sm_request_system_event_log"; + case 396: return "sys_sm_set_rtc_alarm"; + case 397: return "sys_sm_get_rtc_alarm"; + case 398: return "sys_console_write"; + case 402: return "sys_tty_read"; + case 403: return "sys_tty_write"; + case 408: return "sys_sm_get_tzpb"; + case 409: return "sys_sm_get_fan_policy"; + case 410: return "sys_game_board_storage_read"; + case 411: return "sys_game_board_storage_write"; + case 412: return "sys_game_get_rtc_status"; + case 450: return "sys_overlay_load_module"; + case 451: return "sys_overlay_unload_module"; + case 452: return "sys_overlay_get_module_list"; + case 453: return "sys_overlay_get_module_info"; + case 454: return "sys_overlay_load_module_by_fd"; + case 455: return "sys_overlay_get_module_info2"; + case 456: return "sys_overlay_get_sdk_version"; + case 457: return "sys_overlay_get_module_dbg_info"; + case 458: return "sys_overlay_get_module_dbg_info"; + case 460: return "sys_prx_dbg_get_module_id_list"; + case 461: return "sys_prx_get_module_id_by_address"; + case 463: return "sys_prx_load_module_by_fd"; + case 464: return "sys_prx_load_module_on_memcontainer_by_fd"; + case 465: return "sys_prx_load_module_list"; + case 466: return "sys_prx_load_module_list_on_memcontainer"; + case 467: return "sys_prx_get_ppu_guid"; + case 480: return "sys_prx_load_module"; + case 481: return "sys_prx_start_module"; + case 482: return "sys_prx_stop_module"; + case 483: return "sys_prx_unload_module"; + case 484: return "sys_prx_register_module"; + case 485: return "sys_prx_query_module"; + case 486: return "sys_prx_register_library"; + case 487: return "sys_prx_unregister_library"; + case 488: return "sys_prx_link_library"; + case 489: return "sys_prx_unlink_library"; + case 490: return "sys_prx_query_library"; + case 493: return "sys_prx_dbg_get_module_info"; + case 494: return "sys_prx_get_module_list"; + case 495: return "sys_prx_get_module_info"; + case 496: return "sys_prx_get_module_id_by_name"; + case 497: return "sys_prx_load_module_on_memcontainer"; + case 498: return "sys_prx_start"; + case 499: return "sys_prx_stop"; + case 500: return "sys_hid_manager_open"; + case 501: return "sys_hid_manager_close"; + case 502: return "sys_hid_manager_read"; + case 503: return "sys_hid_manager_ioctl"; + case 504: return "sys_hid_manager_map_logical_id_to_port_id"; + case 505: return "sys_hid_manager_unmap_logical_id_to_port_id"; + case 506: return "sys_hid_manager_add_hot_key_observer"; + case 507: return "sys_hid_manager_remove_hot_key_observer"; + case 508: return "sys_hid_manager_grab_focus"; + case 509: return "sys_hid_manager_release_focus"; + case 516: return "sys_config_open"; + case 517: return "sys_config_close"; + case 518: return "sys_config_get_service_event"; + case 519: return "sys_config_add_service_listener"; + case 520: return "sys_config_remove_service_listener"; + case 521: return "sys_config_register_service"; + case 522: return "sys_config_unregister_service"; + case 523: return "sys_config_io_event"; + case 530: return "sys_usbd_initialize"; + case 531: return "sys_usbd_finalize"; + case 532: return "sys_usbd_get_device_list"; + case 533: return "sys_usbd_get_descriptor_size"; + case 534: return "sys_usbd_get_descriptor"; + case 535: return "sys_usbd_register_ldd"; + case 536: return "sys_usbd_unregister_ldd"; + case 537: return "sys_usbd_open_pipe"; + case 538: return "sys_usbd_open_default_pipe"; + case 539: return "sys_usbd_close_pipe"; + case 540: return "sys_usbd_receive_event"; + case 541: return "sys_usbd_detect_event"; + case 542: return "sys_usbd_attach"; + case 543: return "sys_usbd_transfer_data"; + case 544: return "sys_usbd_isochronous_transfer_data"; + case 545: return "sys_usbd_get_transfer_status"; + case 546: return "sys_usbd_get_isochronous_transfer_status"; + case 547: return "sys_usbd_get_device_location"; + case 548: return "sys_usbd_send_event"; + case 550: return "sys_usbd_allocate_memory"; + case 551: return "sys_usbd_free_memory"; + case 556: return "sys_usbd_get_device_speed"; + case 559: return "sys_usbd_register_extra_ldd"; + case 571: return "sys_pad_ldd_unregister_controller"; + case 572: return "sys_pad_ldd_data_insert"; + case 573: return "sys_pad_dbg_ldd_set_data_insert_mode"; + case 574: return "sys_pad_ldd_register_controller"; + case 575: return "sys_pad_ldd_get_port_no"; + case 577: return "sys_pad_manager_..."; + case 600: return "sys_storage_open"; + case 601: return "sys_storage_close"; + case 602: return "sys_storage_read"; + case 603: return "sys_storage_write"; + case 604: return "sys_storage_send_device_command"; + case 605: return "sys_storage_async_configure"; + case 606: return "sys_storage_async_read"; + case 607: return "sys_storage_async_write"; + case 608: return "sys_storage_async_cancel"; + case 609: return "sys_storage_get_device_info"; + case 610: return "sys_storage_get_device_config"; + case 611: return "sys_storage_report_devices"; + case 612: return "sys_storage_configure_medium_event"; + case 613: return "sys_storage_set_medium_polling_interval"; + case 614: return "sys_storage_create_region"; + case 615: return "sys_storage_delete_region"; + case 616: return "sys_storage_execute_device_command"; + case 617: return "sys_storage_check_region_acl"; + case 618: return "sys_storage_set_region_acl"; + case 619: return "sys_storage_async_send_device_command"; + case 621: return "sys_gamepad_ycon_if"; + case 622: return "sys_storage_get_region_offset"; + case 623: return "sys_storage_set_emulated_speed"; + case 624: return "sys_io_buffer_create"; + case 625: return "sys_io_buffer_destroy"; + case 626: return "sys_io_buffer_allocate"; + case 627: return "sys_io_buffer_free"; + case 630: return "sys_gpio_set"; + case 631: return "sys_gpio_get"; + case 633: return "sys_fsw_connect_event"; + case 634: return "sys_fsw_disconnect_event"; + case 635: return "sys_btsetting_if"; + case 650: return "sys_rsxaudio_initialize"; + case 651: return "sys_rsxaudio_finalize"; + case 652: return "sys_rsxaudio_import_shared_memory"; + case 653: return "sys_rsxaudio_unimport_shared_memory"; + case 654: return "sys_rsxaudio_create_connection"; + case 655: return "sys_rsxaudio_close_connection"; + case 656: return "sys_rsxaudio_prepare_process"; + case 657: return "sys_rsxaudio_start_process"; + case 666: return "sys_rsx_device_open"; + case 667: return "sys_rsx_device_close"; + case 668: return "sys_rsx_memory_allocate"; + case 669: return "sys_rsx_memory_free"; + case 670: return "sys_rsx_context_allocate"; + case 671: return "sys_rsx_context_free"; + case 672: return "sys_rsx_context_iomap"; + case 673: return "sys_rsx_context_iounmap"; + case 674: return "sys_rsx_context_attribute"; + case 675: return "sys_rsx_device_map"; + case 676: return "sys_rsx_device_unmap"; + case 677: return "sys_rsx_attribute"; + case 699: return "sys_bdemu_send_command"; + case 700: return "sys_net_bnet_accept"; + case 701: return "sys_net_bnet_bind"; + case 702: return "sys_net_bnet_connect"; + case 703: return "sys_net_bnet_getpeername"; + case 704: return "sys_net_bnet_getsockname"; + case 705: return "sys_net_bnet_getsockopt"; + case 706: return "sys_net_bnet_listen"; + case 707: return "sys_net_bnet_recvfrom"; + case 708: return "sys_net_bnet_recvmsg"; + case 709: return "sys_net_bnet_sendmsg"; + case 710: return "sys_net_bnet_sendto"; + case 711: return "sys_net_bnet_setsockop"; + case 712: return "sys_net_bnet_shutdown"; + case 713: return "sys_net_bnet_socket"; + case 714: return "sys_net_bnet_close"; + case 715: return "sys_net_bnet_poll"; + case 716: return "sys_net_bnet_select"; + case 717: return "sys_net_open_dump"; + case 718: return "sys_net_read_dump"; + case 719: return "sys_net_close_dump"; + case 720: return "sys_net_write_dump"; + case 721: return "sys_net_abort"; + case 722: return "sys_net_infoctl"; + case 723: return "sys_net_control"; + case 724: return "sys_net_bnet_ioctl"; + case 725: return "sys_net_bnet_sysctl"; + case 726: return "sys_net_eurus_post_command"; + case 800: return "sys_fs_test"; + case 801: return "sys_fs_open"; + case 802: return "sys_fs_read"; + case 803: return "sys_fs_write"; + case 804: return "sys_fs_close"; + case 805: return "sys_fs_opendir"; + case 806: return "sys_fs_readdir"; + case 807: return "sys_fs_closedir"; + case 808: return "sys_fs_stat"; + case 809: return "sys_fs_fstat"; + case 810: return "sys_fs_link"; + case 811: return "sys_fs_mkdir"; + case 812: return "sys_fs_rename"; + case 813: return "sys_fs_rmdir"; + case 814: return "sys_fs_unlink"; + case 815: return "sys_fs_utime"; + case 816: return "sys_fs_access"; + case 817: return "sys_fs_fcntl"; + case 818: return "sys_fs_lseek"; + case 819: return "sys_fs_fdatasync"; + case 820: return "sys_fs_fsync"; + case 821: return "sys_fs_fget_block_size"; + case 822: return "sys_fs_get_block_size"; + case 823: return "sys_fs_acl_read"; + case 824: return "sys_fs_acl_write"; + case 825: return "sys_fs_lsn_get_cda_size"; + case 826: return "sys_fs_lsn_get_cda"; + case 827: return "sys_fs_lsn_lock"; + case 828: return "sys_fs_lsn_unlock"; + case 829: return "sys_fs_lsn_read"; + case 830: return "sys_fs_lsn_write"; + case 831: return "sys_fs_truncate"; + case 832: return "sys_fs_ftruncate"; + case 833: return "sys_fs_symbolic_link"; + case 834: return "sys_fs_chmod"; + case 835: return "sys_fs_chown"; + case 836: return "sys_fs_newfs"; + case 837: return "sys_fs_mount"; + case 838: return "sys_fs_unmount"; + case 839: return "sys_fs_sync"; + case 840: return "sys_fs_disk_free"; + case 841: return "sys_fs_get_mount_info_size"; + case 842: return "sys_fs_get_mount_info"; + case 843: return "sys_fs_get_fs_info_size"; + case 844: return "sys_fs_get_fs_info"; + case 845: return "sys_fs_mapped_allocate"; + case 846: return "sys_fs_mapped_free"; + case 847: return "sys_fs_truncate2"; + case 860: return "sys_ss_get_cache_of_analog_sunset_flag"; + case 865: return "sys_ss_random_number_generator"; + case 870: return "sys_ss_get_console_id"; + case 871: return "sys_ss_access_control_engine"; + case 872: return "sys_ss_get_open_psid"; + case 873: return "sys_ss_get_cache_of_product_mode"; + case 874: return "sys_ss_get_cache_of_flash_ext_flag"; + case 875: return "sys_ss_get_boot_device"; + case 876: return "sys_ss_disc_access_control"; + case 877: return "sys_ss_~utoken_if"; + case 878: return "sys_ss_ad_sign"; + case 879: return "sys_ss_media_id"; + case 880: return "sys_deci3_open"; + case 881: return "sys_deci3_create_event_path"; + case 882: return "sys_deci3_close"; + case 883: return "sys_deci3_send"; + case 884: return "sys_deci3_receive"; + case 885: return "sys_deci3_open2"; + case 890: return "sys_deci3_initialize"; + case 891: return "sys_deci3_terminate"; + case 892: return "sys_deci3_debug_mode"; + case 893: return "sys_deci3_show_status"; + case 894: return "sys_deci3_echo_test"; + case 895: return "sys_deci3_send_dcmp_packet"; + case 896: return "sys_deci3_dump_cp_register"; + case 897: return "sys_deci3_dump_cp_buffer"; + case 899: return "sys_deci3_test"; + case 900: return "sys_dbg_stop_processes"; + case 901: return "sys_dbg_continue_processes"; + case 902: return "sys_dbg_stop_threads"; + case 903: return "sys_dbg_continue_threads"; + case 904: return "sys_dbg_read_process_memory"; + case 905: return "sys_dbg_write_process_memory"; + case 906: return "sys_dbg_read_thread_register"; + case 907: return "sys_dbg_write_thread_register"; + case 908: return "sys_dbg_get_process_list"; + case 909: return "sys_dbg_get_thread_list"; + case 910: return "sys_dbg_get_thread_info"; + case 911: return "sys_dbg_spu_thread_read_from_ls"; + case 912: return "sys_dbg_spu_thread_write_to_ls"; + case 913: return "sys_dbg_kill_process"; + case 914: return "sys_dbg_get_process_info"; + case 915: return "sys_dbg_set_run_control_bit_to_spu"; + case 916: return "sys_dbg_spu_thread_get_exception_cause"; + case 917: return "sys_dbg_create_kernel_event_queue"; + case 918: return "sys_dbg_read_kernel_event_queue"; + case 919: return "sys_dbg_destroy_kernel_event_queue"; + case 920: return "sys_dbg_get_process_event_ctrl_flag"; + case 921: return "sys_dbg_set_process_event_cntl_flag"; + case 922: return "sys_dbg_get_spu_thread_group_event_cntl_flag"; + case 923: return "sys_dbg_set_spu_thread_group_event_cntl_flag"; + case 925: return "sys_dbg_get_raw_spu_list"; + case 932: return "sys_dbg_get_mutex_list"; + case 933: return "sys_dbg_get_mutex_information"; + case 934: return "sys_dbg_get_cond_list"; + case 935: return "sys_dbg_get_cond_information"; + case 936: return "sys_dbg_get_rwlock_list"; + case 937: return "sys_dbg_get_rwlock_information"; + case 938: return "sys_dbg_get_lwmutex_list"; + case 939: return "sys_dbg_get_address_from_dabr"; + case 940: return "sys_dbg_set_address_to_dabr"; + case 941: return "sys_dbg_get_lwmutex_information"; + case 942: return "sys_dbg_get_event_queue_list"; + case 943: return "sys_dbg_get_event_queue_information"; + case 944: return "sys_dbg_initialize_ppu_exception_handler"; + case 945: return "sys_dbg_finalize_ppu_exception_handler"; + case 946: return "sys_dbg_get_semaphore_list"; + case 947: return "sys_dbg_get_semaphore_information"; + case 948: return "sys_dbg_get_kernel_thread_list"; + case 949: return "sys_dbg_get_kernel_thread_info"; + case 950: return "sys_dbg_get_lwcond_list"; + case 951: return "sys_dbg_get_lwcond_information"; + case 952: return "sys_dbg_create_scratch_data_area_ext"; + case 953: return "sys_dbg_vm_get_page_information"; + case 954: return "sys_dbg_vm_get_info"; + case 955: return "sys_dbg_enable_floating_point_enabled_exception"; + case 956: return "sys_dbg_disable_floating_point_enabled_exception"; + case 960: return "sys_dbg_perfomance_monitor"; + case 970: return "sys_dbg_get_event_flag_list"; + case 971: return "sys_dbg_get_event_flag_information"; + case 975: return "sys_dbg_read_spu_thread_context2"; + case 985: return "sys_dbg_get_console_type"; + } + + return fmt::format("syscall_%llu", code); +} + +// Get function name by FNID +extern std::string ppu_get_function_name(const std::string& module, u32 fnid) +{ + // Check known FNIDs + if (module == "sys_libc" || module == "sys_libm") switch (fnid) + { + case 0x00acf0e5: return "spu_printf_finalize"; + case 0x00fb4a6b: return "spu_thread_sprintf"; + case 0x0125b2ca: return "_rand_int32_TT800"; + case 0x01508f24: return "raw_spu_write_float"; + case 0x0264f468: return "_Wctomb"; + case 0x02f4d325: return "spu_thread_read_double"; + case 0x02f52a3c: return "_filep_close_it"; + case 0x03becf3c: return "_Defloc"; + case 0x04a183fc: return "strcpy"; + case 0x04a1f19d: return "raw_spu_write_short"; + case 0x05d821c4: return "_Stoullx"; + case 0x077cdb23: return "btowc"; + case 0x07c7971d: return "_Stoldx"; + case 0x0871ffb0: return "mspace_malloc_usable_size"; + case 0x0891a3fa: return "_Tlsfree"; + case 0x09cbee1e: return "strxfrm"; + case 0x0a1d4b00: return "spu_thread_read_uint"; + case 0x0a4e2541: return "spu_thread_read_ldouble"; + case 0x0ae275a4: return "_Stolx"; + case 0x0b0d272f: return "_malloc_finalize"; + case 0x0b9d04d0: return "_Getnloc"; + case 0x0b9ecb98: return "toupper_ascii"; + case 0x0cae547f: return "raw_spu_write_double"; + case 0x0d2a593b: return "srand"; + case 0x0d8a2de0: return "_CStrxfrm"; + case 0x0df8809f: return "__call_functions_registered_with_atexit"; + case 0x0f60eb63: return "vfwscanf"; + case 0x0ff4722c: return "raw_spu_read_ushort"; + case 0x1096f8f1: return "ispunct_ascii"; + case 0x1098a99d: return "localeconv"; + case 0x112ea8ea: return "strspn"; + case 0x115e2f70: return "spu_thread_snprintf"; + case 0x116cda13: return "wcstol"; + case 0x118712ea: return "islower"; + case 0x11d270d2: return "exitspawn"; + case 0x126656b7: return "_Btowc"; + case 0x128b334f: return "raw_spu_read_mem"; + case 0x12a55fb7: return "mbrtowc"; + case 0x130d20a5: return "towlower"; + case 0x1365b52a: return "fcntl"; + case 0x13808972: return "wcstok"; + case 0x14052ae0: return "absi4"; + case 0x14348b57: return "divi4"; + case 0x145853cd: return "mspace_destroy"; + case 0x15362bc9: return "spu_thread_read_long"; + case 0x153b364a: return "mkdir"; + case 0x15bdcc00: return "rand"; + case 0x15c2e29d: return "isgraph_ascii"; + case 0x17752bab: return "wcsftime"; + case 0x17bc0136: return "_Lrv2d"; + case 0x17c031d7: return "spu_thread_read_ulong"; + case 0x1855b9b1: return "setlocale"; + case 0x1895908d: return "mspace_realloc"; + case 0x18e48b5d: return "wscanf"; + case 0x18f7b77d: return "_Dnorm"; + case 0x1970cd7e: return "getpid"; + case 0x19ccbb81: return "mktime"; + case 0x1ab01ea8: return "truncate"; + case 0x1abd0985: return "div"; + case 0x1ae06860: return "wcstoumax"; + case 0x1b4c3ff0: return "atexit"; + case 0x1c0e8ab6: return "vswscanf"; + case 0x1c2ef212: return "getwc"; + case 0x1cf4d80a: return "iswalpha"; + case 0x1dcd8609: return "_Strxfrmx"; + case 0x1dd0d4c5: return "spu_printf_attach_group"; + case 0x1df4732e: return "_Getptolower"; + case 0x1e9d2b4f: return "spu_thread_read_int"; + case 0x1ecae195: return "_Vacopy"; + case 0x1f913e8d: return "chmod"; + case 0x1f925c41: return "_allocate_mapped_pages"; + case 0x206612c4: return "spu_thread_read_ptr"; + case 0x216984ed: return "spu_thread_write_long"; + case 0x216fcd2a: return "_Atrealloc"; + case 0x21807b8e: return "towctrans"; + case 0x225702e1: return "_fs_initialize"; + case 0x22b0e566: return "_Stollx"; + case 0x23d3bca7: return "_Eadd"; + case 0x242c603e: return "_Frprep"; + case 0x243b52d8: return "_Mbtowcx"; + case 0x24802244: return "iswcntrl"; + case 0x24c9e021: return "abs"; + case 0x24e230d2: return "_Wctob"; + case 0x24f6cbdd: return "clock"; + case 0x253b7210: return "_rand_real2_TT800"; + case 0x25beee5a: return "__raw_spu_printf"; + case 0x25da8fbb: return "iscntrl"; + case 0x266311a0: return "localtime"; + case 0x2677568c: return "putchar"; + case 0x26f023d5: return "ftell"; + case 0x273b9711: return "sprintf"; + case 0x28b92ebf: return "raw_spu_read_uchar"; + case 0x296bc72f: return "_FDunscale"; + case 0x2b45cb34: return "wcsrtombs"; + case 0x2b7ba4ca: return "_Tlsset"; + case 0x2b81fb7f: return "readdir"; + case 0x2bc9dee6: return "raw_spu_read_short"; + case 0x2caea755: return "_Once"; + case 0x2d067448: return "ftruncate64"; + case 0x2d17ca7f: return "_Puttxt"; + case 0x2eea9f25: return "_Esub"; + case 0x2f45d39c: return "strlen"; + case 0x2fecec13: return "getwchar"; + case 0x30fb2899: return "_Getmem"; + case 0x312be3b3: return "_malloc_init_lv2"; + case 0x313f04ab: return "raw_spu_read_char"; + case 0x329a4540: return "_WPrintf"; + case 0x32e4a30a: return "_Mtxdst"; + case 0x336b4191: return "_Getint"; + case 0x33d6ae54: return "ferror"; + case 0x344eca7e: return "_WGetstr"; + case 0x34dd6650: return "_Getcloc"; + case 0x34e7c97e: return "_Unlocksyslock"; + case 0x3512ad38: return "tmpnam"; + case 0x355fd1fd: return "mbtowc"; + case 0x3574d37d: return "_Wcsxfrmx"; + case 0x36c067c1: return "_Stoll"; + case 0x36f2b4ed: return "strtoull"; + case 0x36feb965: return "raw_spu_write_llong"; + case 0x3704840e: return "_fs_finalize"; + case 0x38426d25: return "_Wctombx"; + case 0x3902363a: return "malloc_footprint"; + case 0x39bf419c: return "valloc"; + case 0x3a210c93: return "swscanf"; + case 0x3a840ae3: return "snprintf"; + case 0x3b22e88a: return "isxdigit"; + case 0x3b8097ac: return "_WScanf"; + case 0x3bce073b: return "putc"; + case 0x3bd9ce0a: return "fsync"; + case 0x3ca81c76: return "_Iswctype"; + case 0x3d1460e9: return "_Strerror"; + case 0x3d541975: return "atoi"; + case 0x3d5fdea7: return "vfwprintf"; + case 0x3d85d6f8: return "strcmp"; + case 0x3dbc3bee: return "opendir"; + case 0x3e57dfac: return "_Genld"; + case 0x3ec99a66: return "_Getptimes"; + case 0x3ee29d0b: return "_Stof"; + case 0x3f125e2e: return "spu_thread_write_short"; + case 0x3f4ccdc7: return "isdigit"; + case 0x3f650700: return "mspace_is_heap_empty"; + case 0x40a2599a: return "atol"; + case 0x40d04e4e: return "fwide"; + case 0x40e0ff25: return "_WGenld"; + case 0x41283333: return "isdigit_ascii"; + case 0x418bdfe1: return "_get_fd"; + case 0x4217b4cf: return "difftime"; + case 0x433fe2a9: return "fwscanf"; + case 0x44115dd0: return "_Geterrno"; + case 0x44796e5c: return "strerror"; + case 0x449317ed: return "_Fopen"; + case 0x44d7cae8: return "raw_spu_read_float"; + case 0x4544c2de: return "spu_thread_write_mem"; + case 0x4569518c: return "malloc_stats"; + case 0x459072c3: return "_init_TT800"; + case 0x4595c42b: return "wcsxfrm"; + case 0x468b45dc: return "mspace_calloc"; + case 0x4911ff9c: return "rand_int31_TT800"; + case 0x498a5036: return "raw_spu_write_mem"; + case 0x4a0049c6: return "_Getpctype"; + case 0x4ab5fbe2: return "_Printf"; + case 0x4b36c0e0: return "vfscanf"; + case 0x4b6a4010: return "vswprintf"; + case 0x4bb8e2b2: return "raw_spu_write_ushort"; + case 0x4c3f5f29: return "_Getgloballocale"; + case 0x4c7dc863: return "iswupper"; + case 0x4d348427: return "fputs"; + case 0x4e4be299: return "longjmp"; + case 0x4e72f810: return "wmemchr"; + case 0x4ffba189: return "feof"; + case 0x508196b4: return "raw_spu_printf"; + case 0x508e00c6: return "_Getloc"; + case 0x51b28904: return "_Stodx"; + case 0x526a496a: return "write"; + case 0x532b03be: return "raw_spu_read_uint"; + case 0x53eb43a1: return "_Getpmbstate"; + case 0x54b383bc: return "_Locvar"; + case 0x54c2844e: return "spu_raw_snprintf"; + case 0x54f57626: return "rewind"; + case 0x5516bbbf: return "iswctype"; + case 0x55d4866e: return "fgetws"; + case 0x5751acf9: return "_LDscale"; + case 0x575fb268: return "wctrans"; + case 0x57ff7dd7: return "_WStod"; + case 0x58320830: return "_WLitob"; + case 0x589b5314: return "strncat"; + case 0x5909e3c4: return "memset"; + case 0x59640bc6: return "raw_spu_read_ullong"; + case 0x59c1bb1f: return "_Getpwcstate"; + case 0x59e8dd58: return "strtoll"; + case 0x5a74f774: return "spu_thread_read_float"; + case 0x5b162b7f: return "memmove"; + case 0x5b4b6d6d: return "wcspbrk"; + case 0x5cc71eee: return "raw_spu_write_ldouble"; + case 0x5d43c1a3: return "_Mbtowc"; + case 0x5dbceee3: return "rand_int32_TT800"; + case 0x5e06c3fe: return "__getpid"; + case 0x5e7888f0: return "bsearch"; + case 0x5eb95641: return "_Stold"; + case 0x5f922a30: return "_Dscale"; + case 0x5f9a65c7: return "_WStold"; + case 0x5fa1e497: return "_Unlockfilelock"; + case 0x60627fb3: return "_LDunscale"; + case 0x6075a3c6: return "_Ld2rv"; + case 0x609080ec: return "isspace_ascii"; + case 0x6137d196: return "memalign"; + case 0x6287ac6a: return "iswdigit"; + case 0x62bf1d6c: return "swprintf"; + case 0x64aaf016: return "raw_spu_read_ldouble"; + case 0x6514dbe5: return "wcstold"; + case 0x6539ff6d: return "_Gentime"; + case 0x6545b7de: return "fgetpos"; + case 0x65e8d4d0: return "wcslen"; + case 0x6660fc8d: return "TlsGetValue"; + case 0x6687fba4: return "_Fgpos"; + case 0x66b71b17: return "wcsspn"; + case 0x67582370: return "spu_thread_write_double"; + case 0x676e3e7a: return "raw_spu_write_ptr"; + case 0x67d6334b: return "strtof"; + case 0x6823c180: return "iswprint"; + case 0x69106fd2: return "_init_by_array_TT800"; + case 0x692b497f: return "perror"; + case 0x6995f5e8: return "_Ldtob"; + case 0x69c27c12: return "fopen"; + case 0x69ff1b9b: return "fseek"; + case 0x6ba10474: return "_Tlsalloc"; + case 0x6cf78f3e: return "_Mtxunlock"; + case 0x6d5115b0: return "wcsncmp"; + case 0x6e988e5f: return "_rand_int31_TT800"; + case 0x7028dea9: return "_Locksyslock"; + case 0x703ec767: return "setvbuf"; + case 0x70b0e833: return "mblen"; + case 0x714c9618: return "__raw_spu_putfld"; + case 0x717b2502: return "stat"; + case 0x72236cbc: return "raw_spu_write_ullong"; + case 0x72b84004: return "spu_printf_attach_thread"; + case 0x73096858: return "wctob"; + case 0x7345b4be: return "_WStoll"; + case 0x73eae03d: return "strrchr"; + case 0x744d2505: return "ispunct"; + case 0x74fe4a7b: return "iswgraph"; + case 0x759e0635: return "malloc"; + case 0x75d4485c: return "rename"; + case 0x75f98579: return "wcscoll"; + case 0x76da0c84: return "ftruncate"; + case 0x76ed4243: return "_Wcsftime"; + case 0x770bfaee: return "wctype"; + case 0x77a602dd: return "free"; + case 0x77c15441: return "_WGetfloat"; + case 0x77e241bc: return "_Skip"; + case 0x7817edf0: return "raw_spu_write_uint"; + case 0x783636d1: return "spu_thread_read_char"; + case 0x78429d81: return "putwchar"; + case 0x79819dbf: return "fputc"; + case 0x7994c28d: return "_FDtentox"; + case 0x79eadf05: return "malloc_usable_size"; + case 0x7aaab95c: return "iswblank"; + case 0x7ae82e0f: return "vsprintf"; + case 0x7aee5acd: return "_Lockfilelock"; + case 0x7b5aac20: return "spu_thread_write_ptr"; + case 0x7b7a687a: return "_WPutfld"; + case 0x7b9c592e: return "spu_thread_read_ullong"; + case 0x7c1bcf37: return "isalnum_ascii"; + case 0x7c370679: return "_Foprep"; + case 0x7cec7b39: return "_Putfld"; + case 0x7d894764: return "_Readloc"; + case 0x7e7017b1: return "rmdir"; + case 0x7ea8d860: return "spu_printf_detach_group"; + case 0x7efd420a: return "_Daysto"; + case 0x7fd325c4: return "mspace_malloc_stats"; + case 0x7fdcf73e: return "wcscat"; + case 0x806fd281: return "isblank_ascii"; + case 0x809a143f: return "kill"; + case 0x813a9666: return "ungetwc"; + case 0x814d8cb0: return "fflush"; + case 0x81a0a858: return "_memset_int"; + case 0x82a3cc30: return "wcschr"; + case 0x82a4561a: return "_put_fd"; + case 0x831d70a5: return "memcpy"; + case 0x8342b757: return "utime"; + case 0x84378ddc: return "wcsncpy"; + case 0x86532174: return "imaxdiv"; + case 0x867275d7: return "_Stoul"; + case 0x86b4c669: return "tolower_ascii"; + case 0x8713c859: return "link"; + case 0x8725a1a7: return "_memset_vmx"; + case 0x87e8f748: return "memset_vmx"; + case 0x8809cdfd: return "_Getpwctytab"; + case 0x882689f2: return "_Makeloc"; + case 0x882e7760: return "raw_spu_write_uchar"; + case 0x889d5804: return "_Dunscale"; + case 0x88e009f5: return "vwprintf"; + case 0x896e1bfd: return "spu_thread_write_uchar"; + case 0x89b62f56: return "_Etentox"; + case 0x89f6f026: return "time"; + case 0x8a6830e7: return "abort"; + case 0x8a71132c: return "remove"; + case 0x8a847b51: return "tmpfile"; + case 0x8ab0abc6: return "strncpy"; + case 0x8b439438: return "clearerr"; + case 0x8b9d8dd2: return "iswpunct"; + case 0x8cb6bfdc: return "_Locsum"; + case 0x8d7ffaf1: return "_WStopfx"; + case 0x8e2484f1: return "_Emul"; + case 0x8ed71e8b: return "_WGetfld"; + case 0x8ef85e47: return "_WPuttxt"; + case 0x8f5dd179: return "_Nnl"; + case 0x90010029: return "gets"; + case 0x9027fd99: return "_WStoldx"; + case 0x90457fe3: return "raw_spu_read_long"; + case 0x90b27880: return "strtoumax"; + case 0x9234f738: return "raw_spu_read_int"; + case 0x93427cb9: return "setbuf"; + case 0x938bfcf7: return "spu_thread_write_char"; + case 0x93a3e3ac: return "tolower"; + case 0x9439e4cd: return "wcsncat"; + case 0x96b6baa6: return "spu_thread_read_mem"; + case 0x96e6303b: return "_WStoxflt"; + case 0x96ea4de6: return "wctomb"; + case 0x97896359: return "isspace"; + case 0x9800573c: return "_WLdtob"; + case 0x980d3ea7: return "_Getfld"; + case 0x9886810c: return "_FDnorm"; + case 0x98f0eeab: return "raw_spu_write_ulong"; + case 0x99782342: return "strncasecmp_ascii"; + case 0x99a72146: return "vsnprintf"; + case 0x99b38ce7: return "wmemmove"; + case 0x9a87bb3a: return "_Getmbcurmax"; + case 0x9abe8c74: return "wprintf"; + case 0x9c7028a5: return "spu_thread_write_uint"; + case 0x9c9d7b0d: return "strtold"; + case 0x9cab08d1: return "spu_thread_write_int"; + case 0x9d140351: return "_Destroytls"; + case 0x9eb25e00: return "strcoll"; + case 0x9eee5387: return "truncate64"; + case 0x9ff08d57: return "_Clearlocks"; + case 0xa0ab76d5: return "_absi4"; + case 0xa0bc0efb: return "mallinfo"; + case 0xa0ddba8e: return "_Stoulx"; + case 0xa1dbb466: return "_Gettime"; + case 0xa2945229: return "_WGetint"; + case 0xa30d4797: return "wcstoll"; + case 0xa3440924: return "closedir"; + case 0xa3da58f6: return "rand_real1_TT800"; + case 0xa45a0313: return "mspace_create"; + case 0xa483d50d: return "_rv2d"; + case 0xa53800c2: return "_malloc_finalize_lv2"; + case 0xa568db82: return "spu_thread_read_ushort"; + case 0xa57cc615: return "iswspace"; + case 0xa5bc0e19: return "getchar"; + case 0xa6463518: return "__rename"; + case 0xa650df19: return "toupper"; + case 0xa65886b8: return "_Findloc"; + case 0xa72a7595: return "calloc"; + case 0xa797790f: return "wcsstr"; + case 0xa82d70da: return "_Tlsget"; + case 0xa835be11: return "__cxa_atexit"; + case 0xa874036a: return "wcstof"; + case 0xa8a6f615: return "TlsSetValue"; + case 0xa8b07f1b: return "wmemcpy"; + case 0xa9f68eff: return "qsort"; + case 0xaa1e687d: return "isgraph"; + case 0xaa266d35: return "_malloc_init"; + case 0xaa9635d7: return "strcat"; + case 0xab4c7ca1: return "_CWcsxfrm"; + case 0xab77019f: return "fstat"; + case 0xabc27420: return "wcstoul"; + case 0xac758d20: return "wmemcmp"; + case 0xac893127: return "fgetc"; + case 0xace90be4: return "_Dtentox"; + case 0xad62a342: return "ldiv"; + case 0xad8e9ad0: return "_Initlocks"; + case 0xaec7c970: return "lseek"; + case 0xaf002043: return "independent_comalloc"; + case 0xaf44a615: return "fgets"; + case 0xaf6bdcb0: return "_Nonfatal_Assert"; + case 0xaf89fdbd: return "_Assert"; + case 0xafa39179: return "_WPutstr"; + case 0xb120f6ca: return "close"; + case 0xb17b79d0: return "isalpha"; + case 0xb18cc115: return "freopen"; + case 0xb1cc43e3: return "_CStrftime"; + case 0xb1f4779d: return "spu_thread_printf"; + case 0xb24cb8d6: return "_Locterm"; + case 0xb2702e15: return "wcrtomb"; + case 0xb2748a9f: return "_Freeloc"; + case 0xb30042ce: return "lldiv"; + case 0xb37982ea: return "_Getstr"; + case 0xb3c495bd: return "imaxabs"; + case 0xb3d98d59: return "_rand_real1_TT800"; + case 0xb400f226: return "isupper_ascii"; + case 0xb4225825: return "mbsinit"; + case 0xb43c25c7: return "wcstoull"; + case 0xb49eea74: return "_init_malloc_lock0"; + case 0xb4a54446: return "_Stofx"; + case 0xb4fc7078: return "_close_all_FILE"; + case 0xb529d259: return "isalnum"; + case 0xb569849d: return "reallocalign"; + case 0xb57bdf7b: return "iswxdigit"; + case 0xb5d353e8: return "_LDtentox"; + case 0xb6002508: return "_Putstr"; + case 0xb6257e3d: return "strncasecmp"; + case 0xb680e240: return "wcstombs"; + case 0xb6af290e: return "_WFrprep"; + case 0xb6d92ac3: return "strcasecmp"; + case 0xb738027a: return "strtok_r"; + case 0xb794631e: return "_WStofx"; + case 0xb7ab5127: return "wcsrchr"; + case 0xb7b793ed: return "get_state_TT800"; + case 0xb7ba4aeb: return "_WStoul"; + case 0xb7d3427f: return "iscntrl_ascii"; + case 0xb81cd66a: return "mbrlen"; + case 0xb9ed25d4: return "raw_spu_read_ulong"; + case 0xba62681f: return "mspace_memalign"; + case 0xbb605c96: return "pvalloc"; + case 0xbbd4582f: return "_Setloc"; + case 0xbc1d69c5: return "atoll"; + case 0xbc374779: return "_Getlname"; + case 0xbc5af0b5: return "fgetwc"; + case 0xbc7b4b8e: return "ctime"; + case 0xbe11beaa: return "_wremove"; + case 0xbe251a29: return "islower_ascii"; + case 0xbe6e5c58: return "spu_thread_read_uchar"; + case 0xbec43f86: return "raw_spu_read_ptr"; + case 0xbf5bf5ea: return "lseek64"; + case 0xbfcd1b3b: return "_Getdst"; + case 0xc01d9f97: return "printf"; + case 0xc08cc41d: return "wcstod"; + case 0xc0e27b2c: return "_Makestab"; + case 0xc155a73f: return "_WStoull"; + case 0xc15e657e: return "spu_raw_sprintf"; + case 0xc1a71972: return "_d2rv"; + case 0xc1b4bbb9: return "raw_spu_write_char"; + case 0xc1c8737c: return "_Getptoupper"; + case 0xc291e698: return "exit"; + case 0xc3c598e2: return "spu_printf_initialize"; + case 0xc3e14cbe: return "memcmp"; + case 0xc4178000: return "_rand_real3_TT800"; + case 0xc41c6e5d: return "_Scanf"; + case 0xc57337f8: return "_Fofind"; + case 0xc5c09834: return "strstr"; + case 0xc63c354f: return "_Exit"; + case 0xc69b2427: return "labs"; + case 0xc78df618: return "rand_real3_TT800"; + case 0xc7b62ab8: return "spu_thread_write_ullong"; + case 0xc9471fac: return "_Mtxinit"; + case 0xc94b27e3: return "_WStof"; + case 0xc95b20d3: return "fputwc"; + case 0xc9607d35: return "_Stopfx"; + case 0xc97a17d7: return "vsscanf"; + case 0xcab654bf: return "_Once_ctor"; + case 0xcb85ac70: return "mspace_malloc"; + case 0xcb9c535b: return "strftime"; + case 0xcbac7ad7: return "memchr"; + case 0xcbdc3a6d: return "raw_spu_write_int"; + case 0xcc5e0c72: return "_divi4"; + case 0xcca68e9c: return "putwc"; + case 0xce7a9e76: return "isprint_ascii"; + case 0xcecbcdc4: return "_Frv2d"; + case 0xcf863219: return "_Fwprep"; + case 0xcfbfb7a7: return "spu_printf_detach_thread"; + case 0xd14ece90: return "strtol"; + case 0xd1d69cb8: return "_Stod"; + case 0xd20f6601: return "independent_calloc"; + case 0xd2a99b1e: return "isprint"; + case 0xd2ac48d7: return "iswalnum"; + case 0xd360dcb4: return "fileno"; + case 0xd3964a09: return "__spu_thread_putfld"; + case 0xd40723d6: return "fread"; + case 0xd417eeb5: return "_Stoull"; + case 0xd4912ee3: return "_FDscale"; + case 0xd5c8cb55: return "spu_thread_write_ushort"; + case 0xd69c513d: return "_Wcscollx"; + case 0xd784459d: return "isupper"; + case 0xd7dc3a8f: return "strtod"; + case 0xd8b4eb20: return "__spu_thread_puttxt"; + case 0xd9674905: return "mspace_reallocalign"; + case 0xd9a4f812: return "atoff"; + case 0xda5a7eb8: return "strtoul"; + case 0xdaeada07: return "mallopt"; + case 0xddbac025: return "strcasecmp_ascii"; + case 0xddc71a75: return "_SCE_Assert"; + case 0xde1bb092: return "init_by_array_TT800"; + case 0xde32a334: return "_Exitspawn"; + case 0xde7aff7a: return "memcpy16"; + case 0xdebee2af: return "strchr"; + case 0xdef86a83: return "isxdigit_ascii"; + case 0xdfb52083: return "_Stoxflt"; + case 0xe03c7ab1: return "_Fspos"; + case 0xe1858899: return "_Getpwctrtab"; + case 0xe1bd3587: return "fclose"; + case 0xe1e83c65: return "strncmp"; + case 0xe2c5274a: return "_WStoflt"; + case 0xe3812672: return "fdopen"; + case 0xe3cc73f3: return "puts"; + case 0xe3d91db3: return "raw_spu_read_double"; + case 0xe40ba755: return "strtok"; + case 0xe44bf0bf: return "atof"; + case 0xe469fb20: return "_Atexit"; + case 0xe48348e9: return "vprintf"; + case 0xe4c51d4c: return "wcstoimax"; + case 0xe5ea9e2b: return "_Isdst"; + case 0xe5f09c80: return "llabs"; + case 0xe60ee9e5: return "fputws"; + case 0xe6a7de0a: return "ungetc"; + case 0xe7def231: return "_Getfloat"; + case 0xe89071ad: return "isalpha_ascii"; + case 0xe9137453: return "fwprintf"; + case 0xe9a2cc40: return "raw_spu_write_long"; + case 0xe9b560a5: return "sscanf"; + case 0xeb26298c: return "gmtime"; + case 0xeb40c9ec: return "rand_real2_TT800"; + case 0xeb8abe73: return "vwscanf"; + case 0xec9e7cb9: return "spu_thread_read_llong"; + case 0xecddba69: return "_WStodx"; + case 0xed6ec979: return "fsetpos"; + case 0xeda48c80: return "malloc_trim"; + case 0xeddcee2c: return "init_TT800"; + case 0xedec777d: return "_Ttotm"; + case 0xeeeb4f3e: return "_get_state_TT800"; + case 0xeeffc9a6: return "_wrename"; + case 0xef110b6b: return "unlink"; + case 0xf06eed36: return "wmemset"; + case 0xf0776a44: return "wcscmp"; + case 0xf0e022c6: return "getc"; + case 0xf2bbbee9: return "_Litob"; + case 0xf2fca4b2: return "spu_thread_write_llong"; + case 0xf356418c: return "open"; + case 0xf3ef3678: return "wcscspn"; + case 0xf41355f9: return "wcscpy"; + case 0xf418ee84: return "_WFwprep"; + case 0xf4207734: return "spu_thread_write_ulong"; + case 0xf5a32994: return "_Getpcostate"; + case 0xf5ef229c: return "_Getpwcostate"; + case 0xf5f7dda8: return "towupper"; + case 0xf68e2ac9: return "_init_malloc_lock"; + case 0xf7583d67: return "vscanf"; + case 0xf7908e27: return "strcspn"; + case 0xf7a14a22: return "realloc"; + case 0xf7d51596: return "scanf"; + case 0xf7ddb471: return "_Setgloballocale"; + case 0xf88f26c4: return "fwrite"; + case 0xf8935fe3: return "spu_thread_write_float"; + case 0xf89dc648: return "strpbrk"; + case 0xf9dae72c: return "setjmp"; + case 0xf9dba140: return "_Mtxlock"; + case 0xf9e26b72: return "_Once_dtor"; + case 0xfa00d211: return "read"; + case 0xfae4b063: return "_Strcollx"; + case 0xfaec8c60: return "fprintf"; + case 0xfb0f0018: return "_Makewct"; + case 0xfb2081fd: return "vfprintf"; + case 0xfb81426d: return "iswlower"; + case 0xfb8ea4d2: return "_Fd2rv"; + case 0xfc0428a6: return "strdup"; + case 0xfc60575c: return "__spu_thread_printf"; + case 0xfc606237: return "mbsrtowcs"; + case 0xfcac2e8e: return "mbstowcs"; + case 0xfd0cb96d: return "spu_thread_read_short"; + case 0xfd461e85: return "spu_thread_write_ldouble"; + case 0xfd6a1ddb: return "raw_spu_read_llong"; + case 0xfd81f6ca: return "_Stoflt"; + case 0xfe0261aa: return "mspace_free"; + case 0xfe630fd9: return "isblank"; + case 0xfe88e97e: return "fscanf"; + case 0xff689124: return "strtoimax"; + case 0xffbae95e: return "asctime"; + case 0xffbd876b: return "__raw_spu_puttxt"; + case 0x003395d9: return "_Feraise"; + case 0x00367be0: return "fminl"; + case 0x007854f4: return "_FDclass"; + case 0x00fde072: return "f_powf"; + case 0x010818fc: return "asinf4"; + case 0x012d0a91: return "_fminf4"; + case 0x016556df: return "_sinf4"; + case 0x01b84b27: return "llround"; + case 0x01ecef7d: return "_FCbuild"; + case 0x02e68d44: return "_f_fmodf"; + case 0x032cc709: return "csin"; + case 0x03593d2c: return "_f_expf"; + case 0x03aea906: return "divf4"; + case 0x0522d1af: return "_recipf4"; + case 0x054aae63: return "_fdimf4"; + case 0x05cb1718: return "f_fdimf"; + case 0x05e27a13: return "log10f4fast"; + case 0x05efc660: return "asin"; + case 0x05f1dc9e: return "_FExp"; + case 0x07274304: return "csinh"; + case 0x07daed62: return "log2f4"; + case 0x07f400e3: return "_LCbuild"; + case 0x080414bd: return "conjl"; + case 0x08139bd2: return "_fmaxf4"; + case 0x0829a21d: return "asinhl"; + case 0x0a242ed5: return "sinf4"; + case 0x0b3f4e90: return "catanhf"; + case 0x0bb036a6: return "_cosf4"; + case 0x0c14cfcc: return "fesetenv"; + case 0x0c9b8305: return "hypotf4"; + case 0x0cbdae68: return "sinf"; + case 0x0cf9b8bd: return "_Erfc"; + case 0x0d86295d: return "_LCaddcr"; + case 0x0e53319f: return "_asinf4"; + case 0x0e8573dc: return "expm1l"; + case 0x0f02f882: return "llrintl"; + case 0x0f428f0f: return "rint"; + case 0x0f721a9d: return "_LCsubcc"; + case 0x10627248: return "f_fmodf"; + case 0x11c51388: return "tgamma"; + case 0x1225dd31: return "casinf"; + case 0x12de4e46: return "_powf4"; + case 0x12e04cd7: return "cimagl"; + case 0x1313a420: return "acos"; + case 0x137f7e77: return "expf4"; + case 0x14208b00: return "_asinf4fast"; + case 0x1498a072: return "_Cmulcr"; + case 0x16bf208a: return "log10f"; + case 0x17316bee: return "log2"; + case 0x178d98dd: return "atanf4fast"; + case 0x17cd5d87: return "_recipf4fast"; + case 0x182cd542: return "tgammal"; + case 0x18668ce3: return "exp"; + case 0x18b26998: return "remainderl"; + case 0x18ec6099: return "rintl"; + case 0x1988732d: return "clog10"; + case 0x1a1adede: return "rsqrtf4fast"; + case 0x1acb2b16: return "acosf4"; + case 0x1bbdcd9f: return "expm1f4"; + case 0x1bcdeb47: return "_LSinh"; + case 0x1be996cc: return "_LCdivcc"; + case 0x1c11885d: return "_floorf4"; + case 0x1d35bfe4: return "_LLog"; + case 0x1d5bf5d0: return "_modff4"; + case 0x1e623f95: return "truncf4"; + case 0x1e85ef02: return "f_atanf"; + case 0x1e9fd6ba: return "_sinf4fast"; + case 0x2033eeb7: return "csqrt"; + case 0x2118fe46: return "cexpl"; + case 0x21a37b3e: return "log1pf"; + case 0x21e6d304: return "ceil"; + case 0x22c3e308: return "_exp2f4"; + case 0x238af59b: return "fegetenv"; + case 0x23b985f7: return "floorf"; + case 0x241f9337: return "_FCmulcr"; + case 0x24497c52: return "cosf"; + case 0x246ea8d0: return "f_sqrtf"; + case 0x2627d6b2: return "erfc"; + case 0x266d2473: return "_Caddcr"; + case 0x26deed0b: return "cosl"; + case 0x26ef50ed: return "asinh"; + case 0x28faaa5a: return "ilogbf4"; + case 0x29685118: return "_negatef4"; + case 0x2a138d2b: return "truncf"; + case 0x2a4dcbad: return "cacosl"; + case 0x2a89ce33: return "llrintf"; + case 0x2af4b73b: return "fmax"; + case 0x2b282ebb: return "sqrtl"; + case 0x2bb0f2c9: return "logb"; + case 0x2c45fe6a: return "fmaxl"; + case 0x2c601f3b: return "csinl"; + case 0x2cbb6f53: return "f_hypotf"; + case 0x2dcab6a4: return "nanl"; + case 0x2df339bc: return "_f_floorf"; + case 0x2e69bb2a: return "_FCosh"; + case 0x2ec867b4: return "exp2f4fast"; + case 0x30bc7a53: return "logf4"; + case 0x315673f6: return "_Csubcc"; + case 0x31be25c3: return "scalblnf"; + case 0x31db8c89: return "atan2"; + case 0x321c55de: return "nexttowardl"; + case 0x3261de11: return "fesetexceptflag"; + case 0x329ec019: return "rsqrtf4"; + case 0x32f994a1: return "cosf4fast"; + case 0x33e5929b: return "_LDsign"; + case 0x33f27f25: return "_FCdivcr"; + case 0x3436f008: return "csinhf"; + case 0x3459748b: return "log10f4"; + case 0x347c1ee1: return "atanf4"; + case 0x34c0371e: return "powl"; + case 0x358d7f93: return "_f_lrintf"; + case 0x3593a445: return "clog"; + case 0x35b6e70a: return "lrintl"; + case 0x35d3f688: return "creal"; + case 0x36778d1b: return "coshf"; + case 0x373054d1: return "cpow"; + case 0x37345541: return "log1pl"; + case 0x376fb27f: return "sinhl"; + case 0x3792b12d: return "lroundl"; + case 0x38ba5590: return "ccosl"; + case 0x38e69f09: return "pow"; + case 0x398483aa: return "_expm1f4fast"; + case 0x39ef81c9: return "f_fmaxf"; + case 0x3ad203fa: return "lrint"; + case 0x3adc01d7: return "f_frexpf"; + case 0x3b802524: return "ldexpf4"; + case 0x3c057fbd: return "atanf"; + case 0x3c616743: return "_LDtest"; + case 0x3cb818fa: return "_f_fdimf"; + case 0x3d4efafb: return "atan2l"; + case 0x3d549f2a: return "ctanhl"; + case 0x3d901a10: return "_ceilf4"; + case 0x3da55602: return "fabsf"; + case 0x3dfa060f: return "scalbnl"; + case 0x3e7eb58f: return "frexpf4"; + case 0x3e919cba: return "scalbnf"; + case 0x3ec9de23: return "_cbrtf4"; + case 0x3eeedb0e: return "_Dclass"; + case 0x3f6262b3: return "f_fminf"; + case 0x3f701e78: return "_Poly"; + case 0x4020f5ef: return "cbrt"; + case 0x405f9727: return "_log1pf4fast"; + case 0x40a2e212: return "_fabsf4"; + case 0x4111b546: return "_LExp"; + case 0x411434bb: return "asinf"; + case 0x414c5ecc: return "_f_hypotf"; + case 0x4152669c: return "scalbln"; + case 0x417851ce: return "feholdexcept"; + case 0x418036e3: return "_FTgamma"; + case 0x4189a367: return "remquo"; + case 0x41d1b236: return "_f_rintf"; + case 0x430309a1: return "ldexpf"; + case 0x434881a0: return "cacosf"; + case 0x43d522f4: return "cabsl"; + case 0x44cd6308: return "remainder"; + case 0x44cf744b: return "tanhl"; + case 0x45034943: return "nan"; + case 0x452ac4bb: return "floorf4"; + case 0x453f9e91: return "cbrtf"; + case 0x46b66f76: return "csqrtl"; + case 0x46cf72d9: return "fdimf"; + case 0x47433144: return "expm1f4fast"; + case 0x475d855b: return "trunc"; + case 0x476b5591: return "fmaf"; + case 0x48157605: return "_f_llrintf"; + case 0x4826db61: return "fma"; + case 0x4875601d: return "_exp2f4fast"; + case 0x487bbd1c: return "tanf4"; + case 0x488df791: return "cexp"; + case 0x48d462a9: return "_FDint"; + case 0x4930ac11: return "logbl"; + case 0x4a5ae27d: return "f_exp2f"; + case 0x4a6ca9a6: return "powf4"; + case 0x4ab22a63: return "_Caddcc"; + case 0x4add664c: return "feclearexcept"; + case 0x4ae52dd3: return "exp2"; + case 0x4b03d5b2: return "f_rintf"; + case 0x4b584841: return "f_asinf"; + case 0x4cb5fa99: return "nexttoward"; + case 0x4d878773: return "remainderf4"; + case 0x4ddb926b: return "powf"; + case 0x4e010403: return "copysign"; + case 0x4eb5eb51: return "sin"; + case 0x4fa4f5ec: return "nexttowardf"; + case 0x501c412f: return "cargf"; + case 0x519ebb77: return "floor"; + case 0x547fb4a7: return "sinf4fast"; + case 0x54d2fb8c: return "rintf"; + case 0x5516d621: return "acosl"; + case 0x55c8a549: return "truncl"; + case 0x56c573a8: return "log1p"; + case 0x575e9b6e: return "asinl"; + case 0x58eb9e57: return "fabs"; + case 0x596ab55c: return "atanh"; + case 0x5b18eded: return "clogl"; + case 0x5b474c22: return "casinhl"; + case 0x5bfd37be: return "_FCaddcc"; + case 0x5e48dede: return "exp2f4"; + case 0x5ee10a95: return "catanh"; + case 0x5ee37927: return "_LErfc"; + case 0x60e9ff3c: return "_expm1f4"; + case 0x61250988: return "catanl"; + case 0x6261c0b5: return "_log10f4"; + case 0x63bbdfa6: return "_FCmulcc"; + case 0x642e3d18: return "_frexpf4"; + case 0x642f7d6b: return "f_copysignf"; + case 0x645557bd: return "copysignl"; + case 0x64abdb4d: return "csinhl"; + case 0x657d0e83: return "divf4fast"; + case 0x65935877: return "ilogbf"; + case 0x659e011e: return "sqrt"; + case 0x6636c4a5: return "frexpf"; + case 0x664e04b9: return "negatef4"; + case 0x6764c707: return "f_log2f"; + case 0x683cacb3: return "sinh"; + case 0x68a8957f: return "casinhf"; + case 0x68f72416: return "nextafterl"; + case 0x69040b9b: return "logbf4"; + case 0x69725dce: return "lgamma"; + case 0x6ad1c42b: return "_sincosf4"; + case 0x6b660894: return "_acosf4fast"; + case 0x6b6ab2a9: return "_LDclass"; + case 0x6c009c56: return "f_log10f"; + case 0x6c6285c6: return "acoshf"; + case 0x6cc4bd13: return "casinh"; + case 0x6ddd31b2: return "hypot"; + case 0x6df35518: return "floorl"; + case 0x6e9eb0dc: return "sincosf4fast"; + case 0x6ef6b083: return "_FCsubcr"; + case 0x6f5dd7d2: return "cexpf"; + case 0x6f639afb: return "f_llroundf"; + case 0x6fcc1e27: return "_FPoly"; + case 0x70357b12: return "_atanf4fast"; + case 0x7048396e: return "carg"; + case 0x705d9e24: return "f_acosf"; + case 0x70f71871: return "_FCdivcc"; + case 0x71293b71: return "_FLog"; + case 0x714adce1: return "log"; + case 0x71f2bc56: return "_divf4fast"; + case 0x728149e5: return "f_ldexpf"; + case 0x729b7269: return "cproj"; + case 0x72a3ed28: return "fesettrapenable"; + case 0x72f1f64b: return "_logbf4"; + case 0x734ca589: return "_f_cosf"; + case 0x742f12b4: return "_Sin"; + case 0x74902d4b: return "expf4fast"; + case 0x749440f9: return "lgammal"; + case 0x752fa85e: return "fmaxf4"; + case 0x758f33dc: return "nearbyint"; + case 0x75e3e2e9: return "nearbyintl"; + case 0x76afaf04: return "_sqrtf4"; + case 0x76e639ec: return "_atanf4"; + case 0x772f1e4d: return "lround"; + case 0x7793a86b: return "ctanf"; + case 0x7831a2e0: return "hypotl"; + case 0x78e4590a: return "acosh"; + case 0x790c53bd: return "_Fpcomp"; + case 0x7919f414: return "_f_nearbyintf"; + case 0x79ba9b5c: return "expl"; + case 0x7a893af1: return "_rsqrtf4"; + case 0x7ab679da: return "f_cosf"; + case 0x7c2eaeb5: return "fminf"; + case 0x7d02a5ca: return "sqrtf4fast"; + case 0x7d6191d0: return "_Cosh"; + case 0x7f381837: return "frexp"; + case 0x7f579e03: return "atan"; + case 0x7f91cd41: return "tanf4fast"; + case 0x812ed488: return "cabsf"; + case 0x81daf880: return "_LCsubcr"; + case 0x8217e783: return "cosh"; + case 0x833e6b0e: return "cimag"; + case 0x834f5917: return "ccosh"; + case 0x842cb14d: return "_log1pf4"; + case 0x8451edf0: return "sqrtf"; + case 0x889cccb0: return "llroundl"; + case 0x88fb4a66: return "recipf4fast"; + case 0x892f2590: return "fegetround"; + case 0x895cdb49: return "fmaxf"; + case 0x89b507b3: return "catanhl"; + case 0x89d1d168: return "_LAtan"; + case 0x8b168769: return "fdiml"; + case 0x8bd1deb2: return "_LTgamma"; + case 0x8bd67efc: return "erf"; + case 0x8c85369b: return "_f_fminf"; + case 0x8d5858db: return "_f_exp2f"; + case 0x8e01379e: return "cacoshf"; + case 0x8e258fa0: return "cacos"; + case 0x8ecae294: return "nextafter"; + case 0x8f2bcdb5: return "_logf4"; + case 0x8f96319e: return "log10l"; + case 0x8fb7bac7: return "_sqrtf4fast"; + case 0x904e646b: return "cargl"; + case 0x90f0242f: return "_f_sinf"; + case 0x9110708a: return "modfl"; + case 0x91cdfdb0: return "asinf4fast"; + case 0x9232baea: return "_FDtest"; + case 0x9245e01b: return "_divf4"; + case 0x9379e36e: return "tanf"; + case 0x938fb946: return "_tanf4fast"; + case 0x947ae18e: return "_LHypot"; + case 0x9558ed08: return "lrintf"; + case 0x95dfecb1: return "_FCsubcc"; + case 0x961688d1: return "f_nearbyintf"; + case 0x9616e336: return "_FHypot"; + case 0x964ac044: return "creall"; + case 0x96d1b95e: return "log2f4fast"; + case 0x9700d9cd: return "clogf"; + case 0x970a3432: return "cacosh"; + case 0x99a6c261: return "catanf"; + case 0x99c228fc: return "roundl"; + case 0x9a81e583: return "fmodf"; + case 0x9af30eaf: return "casin"; + case 0x9e289062: return "_f_ceilf"; + case 0x9e3ada21: return "logl"; + case 0x9e8130b6: return "ccos"; + case 0x9f03dd3e: return "lgammaf"; + case 0x9f0efc6e: return "exp2l"; + case 0x9f46f5a4: return "tgammaf"; + case 0x9f65bd34: return "fdimf4"; + case 0x9f78f052: return "cos"; + case 0x9fded78a: return "_acosf4"; + case 0xa0160c30: return "_copysignf4"; + case 0xa20827a8: return "ctanl"; + case 0xa2c81938: return "_LSin"; + case 0xa4578433: return "fmin"; + case 0xa46a70a1: return "atanhl"; + case 0xa4ca5cf2: return "llroundf"; + case 0xa56557b6: return "catan"; + case 0xa5d0b260: return "acoshl"; + case 0xa713f8cf: return "modf"; + case 0xa7658186: return "log1pf4"; + case 0xa823836b: return "ilogb"; + case 0xa8c16038: return "_FDsign"; + case 0xa8d180e8: return "_Cbuild"; + case 0xa92bcc85: return "cabs"; + case 0xa9e039c4: return "erfcf"; + case 0xaaa270dc: return "_LCdivcr"; + case 0xab377381: return "log2f"; + case 0xabdccc7a: return "f_atan2f"; + case 0xacca2f83: return "copysignf"; + case 0xad17e787: return "_Dint"; + case 0xad3a093d: return "_LCosh"; + case 0xad5d3e57: return "_FLgamma"; + case 0xaddce673: return "erfcl"; + case 0xafa13040: return "f_llrintf"; + case 0xafcfdad7: return "_Lgamma"; + case 0xafd9a625: return "cimagf"; + case 0xb0fa1592: return "clog10l"; + case 0xb24bd2f8: return "logbf"; + case 0xb348c5c2: return "_LLgamma"; + case 0xb412a8dc: return "_LDint"; + case 0xb4ef29d5: return "f_floorf"; + case 0xb4f4513e: return "_Tgamma"; + case 0xb54cc9a1: return "f_sinf"; + case 0xb5961d4e: return "_sincosf4fast"; + case 0xb598a495: return "fmodl"; + case 0xb5e28191: return "_FSin"; + case 0xb7696143: return "nextafterf"; + case 0xb79012ba: return "modff"; + case 0xb89863bc: return "_rsqrtf4fast"; + case 0xb8aa984e: return "_expf4"; + case 0xb94b9d13: return "_Dtest"; + case 0xb9d2ad22: return "remquol"; + case 0xba136594: return "csinf"; + case 0xba84eab5: return "coshl"; + case 0xbaf11866: return "ceilf"; + case 0xbb165807: return "expm1f"; + case 0xbb208b20: return "cbrtf4fast"; + case 0xbb761c89: return "remquof"; + case 0xbbaa300b: return "f_log1pf"; + case 0xbbf7354e: return "fegetexceptflag"; + case 0xbd7410d9: return "recipf4"; + case 0xbd8bb75c: return "asinhf"; + case 0xbf23f2e7: return "cprojl"; + case 0xbfda6837: return "_f_log10f"; + case 0xc0609820: return "nearbyintf"; + case 0xc0bcf25e: return "_logf4fast"; + case 0xc357b33a: return "frexpl"; + case 0xc406dd09: return "cbrtf4"; + case 0xc41f01db: return "fminf4"; + case 0xc477c0f6: return "f_lroundf"; + case 0xc4cccd1f: return "modff4"; + case 0xc7369fce: return "_Atan"; + case 0xc78ac9d0: return "scalbn"; + case 0xc7b45a19: return "_LFpcomp"; + case 0xc7f1d407: return "fmal"; + case 0xc7fb73d6: return "f_lrintf"; + case 0xc8910002: return "ilogbl"; + case 0xc8dd9279: return "expm1"; + case 0xc90f4bbc: return "_atan2f4"; + case 0xc9481758: return "_tanf4"; + case 0xc94fcc63: return "cbrtl"; + case 0xc977e1ea: return "fetestexcept"; + case 0xc984bf53: return "roundf"; + case 0xc9c536ce: return "_ldexpf4"; + case 0xca239640: return "fmodf4"; + case 0xca463458: return "_Log"; + case 0xcaaf7ae7: return "cprojf"; + case 0xcac167a5: return "_Cmulcc"; + case 0xcb6599c0: return "exp2f"; + case 0xcb6a147e: return "_cosf4fast"; + case 0xcbdf9afb: return "_log10f4fast"; + case 0xccc66f11: return "_FSinh"; + case 0xce91ff18: return "nanf"; + case 0xcfee82d8: return "_remainderf4"; + case 0xd0fd3ca8: return "_hypotf4"; + case 0xd125b89e: return "conjf"; + case 0xd1a3574c: return "clog10f"; + case 0xd231e30a: return "ldexpl"; + case 0xd28ef6dd: return "_Hypot"; + case 0xd2a666c9: return "ctanh"; + case 0xd3a346a8: return "tanl"; + case 0xd40f3f2c: return "erff"; + case 0xd42904b7: return "fabsl"; + case 0xd477852d: return "logf"; + case 0xd48eaae1: return "scalblnl"; + case 0xd4f37b9d: return "tanhf"; + case 0xd50277ad: return "tan"; + case 0xd54039cb: return "fegettrapenable"; + case 0xd5adc4b2: return "cpowl"; + case 0xd5d38552: return "_LCaddcc"; + case 0xd612fa16: return "_Sinh"; + case 0xd70df92a: return "_FCaddcr"; + case 0xd7653782: return "sinhf"; + case 0xd76a16da: return "_fmaf4"; + case 0xd8270894: return "fdim"; + case 0xd8c4096d: return "atan2f4"; + case 0xd8d157f5: return "f_expf"; + case 0xd8f79f4c: return "log10"; + case 0xd97852b7: return "sinl"; + case 0xd97ce5d4: return "fesetround"; + case 0xda217d1f: return "atanl"; + case 0xda31fc5d: return "_FFpcomp"; + case 0xdc14974c: return "fmaf4"; + case 0xdc151707: return "_f_log2f"; + case 0xdd8660d2: return "atan2f4fast"; + case 0xdd92118e: return "ceill"; + case 0xdddabb32: return "remainderf"; + case 0xde7833f2: return "_log2f4fast"; + case 0xdece76a6: return "acosf"; + case 0xdfd41734: return "_Exp"; + case 0xdffb4e3c: return "casinl"; + case 0xe1288c47: return "atanhf"; + case 0xe1c71b05: return "ccoshl"; + case 0xe2b596ec: return "ccosf"; + case 0xe2de89e6: return "csqrtf"; + case 0xe2f1d4b2: return "tanh"; + case 0xe31cc0d3: return "_ilogbf4"; + case 0xe3e379b8: return "_expf4fast"; + case 0xe584836c: return "_LPoly"; + case 0xe58fc9b5: return "erfl"; + case 0xe5a0be9f: return "_powf4fast"; + case 0xe5d2293f: return "_Force_raise"; + case 0xe5ea65e8: return "feraiseexcept"; + case 0xe6c1ff41: return "llrint"; + case 0xe769e5cf: return "fmod"; + case 0xe8fcf1f8: return "acosf4fast"; + case 0xe913a166: return "logf4fast"; + case 0xe92f3fb8: return "_f_fmaf"; + case 0xe93abfca: return "ctan"; + case 0xe9ac8223: return "_LCmulcr"; + case 0xe9f501df: return "crealf"; + case 0xea1e83e3: return "f_logf"; + case 0xeac62795: return "_Cdivcc"; + case 0xeac7ca2c: return "ceilf4"; + case 0xebb4e08a: return "hypotf"; + case 0xec43b983: return "_f_sqrtf"; + case 0xec7da0c8: return "_atan2f4fast"; + case 0xed05c265: return "sqrtf4"; + case 0xed9d1ac5: return "f_tanf"; + case 0xeda86c48: return "copysignf4"; + case 0xee0db701: return "_Csubcr"; + case 0xee204ac6: return "f_ceilf"; + case 0xee303936: return "_Dsign"; + case 0xeed82401: return "_f_logf"; + case 0xf0947035: return "ctanhf"; + case 0xf0ab77c1: return "ccoshf"; + case 0xf16568af: return "_FAtan"; + case 0xf19c5e94: return "sincosf4"; + case 0xf1aaa2f8: return "conj"; + case 0xf3bd7d08: return "_cbrtf4fast"; + case 0xf3ec0258: return "round"; + case 0xf4ad6ea8: return "ldexp"; + case 0xf537d837: return "_truncf4"; + case 0xf5cd1e19: return "cosf4"; + case 0xf7844153: return "_f_fmaxf"; + case 0xf83a372f: return "f_fmaf"; + case 0xf95b7769: return "powf4fast"; + case 0xf99da2fc: return "fabsf4"; + case 0xfa28434b: return "log2l"; + case 0xfa765d42: return "_Cdivcr"; + case 0xfa97afbf: return "feupdateenv"; + case 0xfae9e727: return "_f_copysignf"; + case 0xfb6e6213: return "log1pf4fast"; + case 0xfb932a56: return "atan2f"; + case 0xfbb4047a: return "lroundf"; + case 0xfbe88922: return "_FErfc"; + case 0xfcedabc3: return "_fmodf4"; + case 0xfcf08193: return "expf"; + case 0xfdec16e1: return "cacoshl"; + case 0xfe23dbe9: return "_log2f4"; + case 0xff036800: return "cpowf"; + case 0xfffe79bf: return "_LCmulcc"; + } + + if (module == "sys_libstdcxx") switch (fnid) + { + case 0x002c338b: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE16do_get_monthnameES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x002e18d8: return "_ZNSt6locale7_LocimpD0Ev"; + case 0x0091a3fd: return "_ZNKSt6locale9_GetfacetEj"; + case 0x00c3975e: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE5_LockEv"; + case 0x00cf44f7: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecl"; + case 0x01409785: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE7_GetintERS3_S5_iiRi"; + case 0x01aa0cef: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERx"; + case 0x01c4ef01: return "_ZNSt6localeC2ERKS_S1_i"; + case 0x01d9b3f5: return "_ZNSt6localeC1EPKci"; + case 0x01f81190: return "_ZNSt12codecvt_baseD1Ev"; + case 0x020b22f3: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewPKv"; + case 0x02e40598: return "_ZNSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE5_InitERKSt8_Locinfo"; + case 0x03217f6f: return "_ZNSt19istreambuf_iteratorIcSt11char_traitsIcEE5_PeekEv"; + case 0x0339259c: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecPKv"; + case 0x033c18f4: return "_ZNSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEED1Ev"; + case 0x03cca12f: return "_ZNSt6localeC1ERKS_PKci"; + case 0x040c18ff: return "_ZNKSt7_MpunctIwE16do_decimal_pointEv"; + case 0x045e124a: return "_ZdaPv"; + case 0x0490855d: return "_ZNSt8numpunctIwE7_GetcatEPPKNSt6locale5facetE"; + case 0x055c1462: return "_ZNSt15basic_streambufIcSt11char_traitsIcEED1Ev"; + case 0x05903101: return "_ZNKSt7collateIcE7do_hashEPKcS2_"; + case 0x05a9cef6: return "_ZNSt7_MpunctIcE5_InitERKSt8_Locinfo"; + case 0x05ec37c8: return "_ZSt10_MaklocstrIwEPT_PKcS1_RKSt7_Cvtvec"; + case 0x06bc5b51: return "_ZNKSt7_MpunctIwE16do_positive_signEv"; + case 0x07a3bd16: return "_ZNSt6locale7_LocimpD1Ev"; + case 0x07b6c924: return "_ZTv0_n12_NSt13basic_ostreamIwSt11char_traitsIwEED1Ev"; + case 0x085bff4f: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE5_LockEv"; + case 0x08e1865c: return "_ZNKSt8numpunctIwE16do_thousands_sepEv"; + case 0x09e73a2a: return "_ZNKSt7codecvtIwcSt9_MbstatetE11do_encodingEv"; + case 0x0ba5483c: return "_ZNKSt12codecvt_base11do_encodingEv"; + case 0x0bc08c57: return "_ZNKSt7collateIwE7do_hashEPKwS2_"; + case 0x0bcc1910: return "_ZNSt10ostrstreamD2Ev"; + case 0x0d4290d2: return "_ZNSt12length_errorD0Ev"; + case 0x0d644dca: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE11do_get_dateES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x0e147a9d: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE9pbackfailEi"; + case 0x0e744ef5: return "_ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEED1Ev"; + case 0x0e9698af: return "_ZNSt7codecvtIwcSt9_MbstatetED1Ev"; + case 0x0e9a5554: return "_ZNSt13basic_istreamIwSt11char_traitsIwEED0Ev"; + case 0x0f930fdd: return "_ZNSt13messages_baseD2Ev"; + case 0x0ff264b9: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE4syncEv"; + case 0x10231873: return "_ZNSt13runtime_errorD1Ev"; + case 0x10dc3f6c: return "_ZNSbIwSt11char_traitsIwESaIwEE6appendEjw"; + case 0x113a515f: return "_ZNKSt8messagesIcE7do_openERKSsRKSt6locale"; + case 0x114e9178: return "_ZNSt11logic_errorD0Ev"; + case 0x128cd621: return "_ZNKSt5ctypeIwE10do_scan_isEsPKwS2_"; + case 0x12de5772: return "_ZNKSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_bRSt8ios_baseRNSt5_IosbIiE8_IostateERSs"; + case 0x1374b8c8: return "_ZNSt10moneypunctIcLb0EED1Ev"; + case 0x143048bf: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE7seekoffElNSt5_IosbIiE8_SeekdirENS4_9_OpenmodeE"; + case 0x1474ac53: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERt"; + case 0x14e3faa5: return "_ZNKSt5ctypeIwE9do_narrowEwc"; + case 0x1527fe95: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE4syncEv"; + case 0x1692ae0c: return "_ZNSt6localeD1Ev"; + case 0x16df5ecb: return "_ZNKSt12codecvt_base16do_always_noconvEv"; + case 0x17dd0a4e: return "_ZNKSt7_MpunctIwE16do_negative_signEv"; + case 0x18628537: return "_ZNKSt8numpunctIcE16do_decimal_pointEv"; + case 0x186bcc94: return "_ZNSt8ios_base4InitD1Ev"; + case 0x18a38254: return "_ZNSt10ctype_baseD1Ev"; + case 0x197fc348: return "_ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEED1Ev"; + case 0x1989f59c: return "_ZNSt8ios_base17register_callbackEPFvNS_5eventERS_iEi"; + case 0x19c901ce: return "_ZTv0_n12_NSt9strstreamD0Ev"; + case 0x1a00f889: return "_ZNSt9exceptionD2Ev"; + case 0x1a4f2fa6: return "_ZNSt8ios_base7failureD0Ev"; + case 0x1a7f963c: return "_ZNKSt8numpunctIcE11do_truenameEv"; + case 0x1b266c3d: return "_ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE7_GetcatEPPKNSt6locale5facetE"; + case 0x1b6a7482: return "_ZNKSt7_MpunctIwE13do_neg_formatEv"; + case 0x1b6ad260: return "_ZSt13resetiosflagsNSt5_IosbIiE9_FmtflagsE"; + case 0x1b9b3b5c: return "_ZNSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEED0Ev"; + case 0x1bccd2ca: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE7_GetintERS3_S5_iiRi"; + case 0x1c3f1c4f: return "_ZNSt6_MutexD1Ev"; + case 0x1c8083c5: return "_ZNSt12strstreambufD0Ev"; + case 0x1c8405dc: return "_ZNSt7_MpunctIcEC2Ejb"; + case 0x1cf6785d: return "_ZSt9use_facetISt5ctypeIwEERKT_RKSt6locale"; + case 0x1d43fb44: return "_ZSt9use_facetISt8numpunctIwEERKT_RKSt6locale"; + case 0x1ee13e83: return "_ZNSt6locale5facetD0Ev"; + case 0x1f2e9f4e: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE9underflowEv"; + case 0x1f3a9ada: return "_ZNSt12strstreambuf7seekposESt4fposISt9_MbstatetENSt5_IosbIiE9_OpenmodeE"; + case 0x2070a73d: return "_ZNSt6locale7_LocimpC1ERKS0_"; + case 0x207b56fa: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE8_GetffldEPcRS3_S6_RKSt6locale"; + case 0x20a02b6d: return "_ZNSt6locale2idcvjEv"; + case 0x20f7e066: return "_ZNSt10moneypunctIwLb0EED0Ev"; + case 0x21659e45: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE5_FputES3_RSt8ios_basecPKcjjjj"; + case 0x22777290: return "_ZNSs7replaceEjjPKcj"; + case 0x229a0963: return "_ZNKSt5ctypeIwE5do_isEsw"; + case 0x2354ec0a: return "_ZNKSt7codecvtIwcSt9_MbstatetE10do_unshiftERS0_PcS3_RS3_"; + case 0x2356ef16: return "_ZnajRKSt9nothrow_t"; + case 0x23a87483: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE11do_get_timeES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x23ef7642: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE8_GetifldEPcRS3_S6_NSt5_IosbIiE9_FmtflagsERKSt6locale"; + case 0x258359df: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basece"; + case 0x2670b433: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE8_GetffldEPcRS3_S6_RKSt6locale"; + case 0x268c3ea5: return "_ZNKSt7_MpunctIwE13do_pos_formatEv"; + case 0x26e8e1cf: return "_ZNKSt5ctypeIwE5do_isEPKwS2_Ps"; + case 0x273be056: return "_ZNKSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE8_PutmfldES3_bRSt8ios_basecbSs"; + case 0x281f9107: return "_ZTv0_n12_NSiD1Ev"; + case 0x294779fb: return "_ZNSt8ios_base4InitD2Ev"; + case 0x2954d64d: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE9underflowEv"; + case 0x29c11f46: return "_ZNKSt7codecvtIccSt9_MbstatetE9do_lengthERKS0_PKcS5_j"; + case 0x29c90b94: return "_ZNKSt8numpunctIcE16do_thousands_sepEv"; + case 0x2a16469d: return "_ZNSt8ios_base5imbueERKSt6locale"; + case 0x2ac890f4: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERb"; + case 0x2adccb1a: return "_ZNKSt7_MpunctIcE14do_frac_digitsEv"; + case 0x2af79bd6: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE5_IputES3_RSt8ios_basecPcj"; + case 0x2b05b95a: return "_ZNKSt7_MpunctIcE11do_groupingEv"; + case 0x2b88f26e: return "_ZNSt15basic_streambufIwSt11char_traitsIwEED0Ev"; + case 0x2c241d13: return "_ZnajjRKSt9nothrow_t"; + case 0x2c6ce396: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERd"; + case 0x2cf8ea50: return "_ZNKSt7codecvtIwcSt9_MbstatetE16do_always_noconvEv"; + case 0x2d489b47: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE9underflowEv"; + case 0x2d50650f: return "_ZSt9use_facetISt10moneypunctIcLb1EEERKT_RKSt6locale"; + case 0x2d8be7e8: return "_ZNKSt9exception6_RaiseEv"; + case 0x2daa5a42: return "_ZTv0_n12_NSt9strstreamD1Ev"; + case 0x2e2b80c8: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERPv"; + case 0x2e84ebb3: return "_ZNSt8_LocinfoC1EiPKc"; + case 0x2eb5c13a: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE4syncEv"; + case 0x2f29da90: return "_ZNSt12strstreambuf5_TidyEv"; + case 0x2ff8d101: return "_ZNSt6localeC1ERKS_S1_i"; + case 0x30195cf5: return "_ZNKSt8numpunctIcE11do_groupingEv"; + case 0x30ce43d4: return "_ZNSt8numpunctIcED0Ev"; + case 0x30e297ea: return "_ZNSt7_MpunctIcEC2ERKSt8_Locinfojb"; + case 0x316b7a34: return "_ZNSt9exceptionD1Ev"; + case 0x31a81476: return "_ZdlPvj"; + case 0x31b3e5cc: return "_ZNSs5_TidyEbj"; + case 0x3286b855: return "_ZNSt8time_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE7_GetcatEPPKNSt6locale5facetE"; + case 0x332f8409: return "_ZNSt8time_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE7_GetcatEPPKNSt6locale5facetE"; + case 0x336e904e: return "_ZNSdD0Ev"; + case 0x33e04d8e: return "_ZNKSt7collateIwE12do_transformEPKwS2_"; + case 0x34b63588: return "_ZNKSt5ctypeIwE9_DonarrowEwc"; + case 0x34edd72b: return "_ZNSt10moneypunctIwLb0EED1Ev"; + case 0x360f8a4f: return "_ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEED1Ev"; + case 0x3697bbd3: return "_ZNSt8ios_base5_InitEv"; + case 0x36e7826a: return "_ZNSt7collateIcED1Ev"; + case 0x3783acfa: return "_ZTv0_n12_NSt13basic_istreamIwSt11char_traitsIwEED1Ev"; + case 0x38783beb: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE11do_get_yearES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x3933645f: return "_ZNKSt7_MpunctIwE14do_frac_digitsEv"; + case 0x3937f2f8: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecm"; + case 0x39775ce9: return "_ZNSt11logic_errorD2Ev"; + case 0x3ad12959: return "_ZNSt9basic_iosIcSt11char_traitsIcEE4initEPSt15basic_streambufIcS1_Eb"; + case 0x3bac19dc: return "_ZThn8_NSdD0Ev"; + case 0x3bda45a7: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecy"; + case 0x3d32a7f4: return "_ZNSt6localeC2EPKci"; + case 0x3da21a90: return "_ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEED1Ev"; + case 0x3e18602a: return "_ZNKSt12codecvt_base13do_max_lengthEv"; + case 0x3eeb7167: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE7_UnlockEv"; + case 0x3f6a6e68: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE9_EndwriteEv"; + case 0x3f9cb259: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERl"; + case 0x3fc2324d: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecd"; + case 0x409409af: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE6setbufEPci"; + case 0x411b923e: return "_ZSt9use_facetISt8numpunctIcEERKT_RKSt6locale"; + case 0x4148e091: return "_ZNKSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE8_GetmfldERS3_S5_bRSt8ios_base"; + case 0x417f47af: return "_ZSt9use_facetISt10moneypunctIcLb0EEERKT_RKSt6locale"; + case 0x42c40b2f: return "_ZNSt12out_of_rangeD0Ev"; + case 0x45010630: return "_ZNSt10moneypunctIcLb1EED0Ev"; + case 0x4520d6a2: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE5_LockEv"; + case 0x46034d2e: return "_ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEED0Ev"; + case 0x460e5cb7: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE7seekposESt4fposISt9_MbstatetENSt5_IosbIiE9_OpenmodeE"; + case 0x4761783a: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE5imbueERKSt6locale"; + case 0x47aab531: return "_ZNSt7_MpunctIcED0Ev"; + case 0x47e5c318: return "_ZNSt8_LocinfoD2Ev"; + case 0x4827e6be: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERe"; + case 0x48d101ef: return "_ZNKSt8ios_base7failure8_DoraiseEv"; + case 0x493212da: return "_ZNSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEED0Ev"; + case 0x4952490e: return "_ZNSt8ios_base5clearENSt5_IosbIiE8_IostateEb"; + case 0x496c6f50: return "_Getctyptab"; + case 0x49d9ddaf: return "_ZNKSt8numpunctIwE12do_falsenameEv"; + case 0x49da8c5f: return "_ZNKSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_bRSt8ios_baseRNSt5_IosbIiE8_IostateERe"; + case 0x49f7d434: return "_ZNSt8numpunctIwED0Ev"; + case 0x4a40969d: return "_Fac_tidy"; + case 0x4a799510: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERl"; + case 0x4aec14d5: return "_ZNSt12length_errorD1Ev"; + case 0x4aff73cc: return "_ZSt14_Debug_messagePKcS0_"; + case 0x4b1ad744: return "_ZdaPvjRKSt9nothrow_t"; + case 0x4b5a8abc: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE6setbufEPwi"; + case 0x4bc193c7: return "_ZNSt10ostrstreamC2EPciNSt5_IosbIiE9_OpenmodeE"; + case 0x4bda379a: return "_ZNSt8ios_base4InitC1Ev"; + case 0x4bee7ba9: return "_ZNSt8ios_base7failureD1Ev"; + case 0x4cb35e7d: return "_ZNSt9time_baseD1Ev"; + case 0x4cdab0ba: return "_ZNSt7_MpunctIwED0Ev"; + case 0x4daf3fcf: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE6xsgetnEPci"; + case 0x4e34cf83: return "_ZNSbIwSt11char_traitsIwESaIwEE5_GrowEjb"; + case 0x4e5cd916: return "_ZNKSt8numpunctIwE11do_groupingEv"; + case 0x4ec89bf8: return "_ZNSt7collateIcE7_GetcatEPPKNSt6locale5facetE"; + case 0x4ef0eb8e: return "_ZNSt12strstreambuf7seekoffElNSt5_IosbIiE8_SeekdirENS1_9_OpenmodeE"; + case 0x4fde96de: return "_ZNSt15basic_streambufIwSt11char_traitsIwEED1Ev"; + case 0x5015b8d3: return "_ZSt7_FiopenPKwNSt5_IosbIiE9_OpenmodeEi"; + case 0x50b34c09: return "_ZNKSt9exception4whatEv"; + case 0x5102ac61: return "_ZNKSt7_MpunctIwE14do_curr_symbolEv"; + case 0x5119680b: return "_ZNSt8_LocinfoD1Ev"; + case 0x5127dcd1: return "_ZNSsC1Ev"; + case 0x522b0457: return "_ZNSt10istrstreamD0Ev"; + case 0x52330fbd: return "_ZNSt13runtime_errorD0Ev"; + case 0x5298ef8e: return "_ZdaPvRKSt9nothrow_t"; + case 0x5333bdc9: return "_ZNKSt13runtime_error4whatEv"; + case 0x53693d40: return "_ZSt11setiosflagsNSt5_IosbIiE9_FmtflagsE"; + case 0x5438d7d8: return "_ZdaPvS_"; + case 0x550255f7: return "_ZNKSt7codecvtIccSt9_MbstatetE10do_unshiftERS0_PcS3_RS3_"; + case 0x55481e6f: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE9showmanycEv"; + case 0x5560c79e: return "_ZNSdD1Ev"; + case 0x55b3ebf2: return "_ZNSt9strstreamC2EPciNSt5_IosbIiE9_OpenmodeE"; + case 0x563fd2be: return "_ZNSt6localeC2ERKS_PKci"; + case 0x5656ccff: return "_ZNKSt7collateIcE10do_compareEPKcS2_S2_S2_"; + case 0x56d3d4f0: return "_ZNSt9bad_allocD1Ev"; + case 0x56fac416: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERe"; + case 0x577c2695: return "_ZNSt6_Mutex5_LockEv"; + case 0x57ef52f0: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE7_UnlockEv"; + case 0x581fc95b: return "_ZNSt5ctypeIcED0Ev"; + case 0x58fad1c1: return "_ZNSt5ctypeIwE7_GetcatEPPKNSt6locale5facetE"; + case 0x5949408e: return "_ZNSt8ios_base5_TidyEv"; + case 0x59c77266: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERd"; + case 0x5a3ad4bd: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERf"; + case 0x5a5a9107: return "_ZNSt6localeC2Ev"; + case 0x5a6e4e50: return "_ZNSt6locale7_Locimp9_MakewlocERKSt8_LocinfoiPS0_PKS_"; + case 0x5a898327: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE7seekoffElNSt5_IosbIiE8_SeekdirENS4_9_OpenmodeE"; + case 0x5adf9060: return "_ZNKSt5ctypeIcE8do_widenEPKcS2_Pc"; + case 0x5b71b85d: return "_ZNSt19istreambuf_iteratorIwSt11char_traitsIwEE4_IncEv"; + case 0x5c15972f: return "_ZNSt13basic_ostreamIwSt11char_traitsIwEED1Ev"; + case 0x5ca98e4a: return "_ZNSt13basic_filebufIcSt11char_traitsIcEED0Ev"; + case 0x5e1f2d37: return "_ZNKSt9exception8_DoraiseEv"; + case 0x5e55ab8c: return "_ZSt10_GetloctxtIwSt19istreambuf_iteratorIwSt11char_traitsIwEEEiRT0_S5_jPKT_"; + case 0x5ed4fb7a: return "_ZTv0_n12_NSt13basic_istreamIwSt11char_traitsIwEED0Ev"; + case 0x604fec95: return "_ZNSt12out_of_rangeD1Ev"; + case 0x605131d5: return "_ZNSt8_LocinfoC1EPKc"; + case 0x6051c802: return "_ZNSt7codecvtIccSt9_MbstatetED0Ev"; + case 0x608abbb5: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE5uflowEv"; + case 0x61119152: return "_ZNSt6locale5_InitEv"; + case 0x61248c80: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE13do_date_orderEv"; + case 0x61a23009: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE5_FputES3_RSt8ios_basewPKcjjjj"; + case 0x61f55c30: return "_ZNKSt5ctypeIcE8do_widenEc"; + case 0x629b8531: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE5_IputES3_RSt8ios_basewPcj"; + case 0x62d6bf82: return "_ZNSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEED1Ev"; + case 0x62f52bb0: return "_ZNSt7_MpunctIwEC2ERKSt8_Locinfojb"; + case 0x635166c3: return "_ZNKSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_bRSt8ios_basewe"; + case 0x63a2b2cc: return "_ZNKSt8messagesIcE8do_closeEi"; + case 0x643235cf: return "_ZNSt9strstreamD1Ev"; + case 0x6437a975: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERt"; + case 0x643e67f4: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERPv"; + case 0x6463d9ea: return "_ZNKSt8messagesIwE6do_getEiiiRKSbIwSt11char_traitsIwESaIwEE"; + case 0x64ce0374: return "_ZNSbIwSt11char_traitsIwESaIwEE7replaceEjjPKwj"; + case 0x64ed868e: return "_ZSt9terminatev"; + case 0x6500d2d5: return "_ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE7_GetcatEPPKNSt6locale5facetE"; + case 0x65f19631: return "_ZTv0_n12_NSiD0Ev"; + case 0x660882e8: return "_ZNSt6localeC1Ev"; + case 0x667d741b: return "_ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEED0Ev"; + case 0x668b31c6: return "_ZNSs5_GrowEjb"; + case 0x66f39adb: return "_ZNSt8numpunctIwED1Ev"; + case 0x66fcc6f4: return "_ZNSt8messagesIwE7_GetcatEPPKNSt6locale5facetE"; + case 0x67948307: return "_ZNKSt7codecvtIwcSt9_MbstatetE9do_lengthERKS0_PKcS5_j"; + case 0x67c09257: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERx"; + case 0x67edde2f: return "_ZdlPvjRKSt9nothrow_t"; + case 0x67fbabf0: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE14do_get_weekdayES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x683ca70a: return "_ZNKSt12_String_base5_XlenEv"; + case 0x6863452e: return "_ZNSt6locale5facetD1Ev"; + case 0x6929318d: return "_ZNSs6assignERKSsjj"; + case 0x696b47f2: return "_ZNKSt7_MpunctIcE13do_neg_formatEv"; + case 0x6a6b90c9: return "_ZSt15set_new_handlerPFvvE"; + case 0x6adc320a: return "_ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEED0Ev"; + case 0x6b493669: return "_ZSt7setbasei"; + case 0x6b913d53: return "_ZNSs6insertEjjc"; + case 0x6c19db26: return "_ZNKSt7_MpunctIcE16do_thousands_sepEv"; + case 0x6c386f54: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE7seekposESt4fposISt9_MbstatetENSt5_IosbIiE9_OpenmodeE"; + case 0x6c8dc459: return "_ZNKSt8bad_cast4whatEv"; + case 0x6cb1a335: return "_ZNSt6locale5facet7_DecrefEv"; + case 0x6d483b7a: return "_ZNSt12strstreambuf9pbackfailEi"; + case 0x6daed882: return "_ZNSt8ios_baseD0Ev"; + case 0x6dbbb9de: return "_ZNKSt5ctypeIcE10do_toupperEc"; + case 0x6e0bf85d: return "_ZTv0_n12_NSt10istrstreamD1Ev"; + case 0x6e4a84c1: return "_ZNSt5ctypeIcED1Ev"; + case 0x6e61426d: return "_ZNSt13basic_filebufIwSt11char_traitsIwEED1Ev"; + case 0x6f1945fc: return "_ZNSoD1Ev"; + case 0x6fe060a0: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE7seekposESt4fposISt9_MbstatetENSt5_IosbIiE9_OpenmodeE"; + case 0x7008e209: return "_ZNKSt5ctypeIwE10do_toupperEw"; + case 0x708cf940: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE11do_get_dateES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x709ab035: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE6setbufEPci"; + case 0x7142ad20: return "_ZNKSt7_MpunctIcE16do_decimal_pointEv"; + case 0x718977c5: return "_ZNSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE7_GetcatEPPKNSt6locale5facetE"; + case 0x736c5f22: return "_ZNSoD0Ev"; + case 0x74a39b4f: return "_ZThn8_NSt9strstreamD1Ev"; + case 0x753c71db: return "_ZNKSt7_MpunctIcE13do_pos_formatEv"; + case 0x75824de0: return "_ZNSt6_MutexC1Ev"; + case 0x75975eb4: return "_ZNSsC1EPKc"; + case 0x75a0617c: return "_ZNKSt7_MpunctIwE11do_groupingEv"; + case 0x764ceaa4: return "_ZNSt10ostrstreamD0Ev"; + case 0x767a4e70: return "_ZNSt6_WinitC2Ev"; + case 0x76db6974: return "_ZNSt7codecvtIwcSt9_MbstatetED0Ev"; + case 0x76de9b0f: return "_ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEED1Ev"; + case 0x76e846b2: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE6xsputnEPKwi"; + case 0x77c1d3a9: return "_ZNKSt13runtime_error8_DoraiseEv"; + case 0x7882e64e: return "_ZNSt7collateIwED0Ev"; + case 0x78a142d0: return "_ZSt7_FiopenPKcNSt5_IosbIiE9_OpenmodeEi"; + case 0x79a415f8: return "_ZNSbIwSt11char_traitsIwESaIwEE6insertEjjw"; + case 0x79ad3575: return "_ZTv0_n12_NSoD1Ev"; + case 0x7a180518: return "_ZNSt10money_baseD0Ev"; + case 0x7b1db41e: return "_ZNSt6locale7_AddfacEPNS_5facetEjj"; + case 0x7b5fce95: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE6setbufEPwi"; + case 0x7c391411: return "_ZNSt10moneypunctIcLb0EED0Ev"; + case 0x7cdbda48: return "_ZNSt7collateIcED0Ev"; + case 0x7d23aa12: return "_ZNSt10moneypunctIwLb0EE7_GetcatEPPKNSt6locale5facetE"; + case 0x7da7fdb1: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewy"; + case 0x7e7ac30e: return "_ZNSt6locale5emptyEv"; + case 0x7ebad3f0: return "_ZNKSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE8_PutmfldES3_bRSt8ios_basewbSbIwS2_SaIwEE"; + case 0x7fe08910: return "_ZNSt10moneypunctIcLb0EE7_GetcatEPPKNSt6locale5facetE"; + case 0x7ff35597: return "_ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE7_GetcatEPPKNSt6locale5facetE"; + case 0x8006c4ec: return "_ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEED0Ev"; + case 0x8044f596: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE5_LockEv"; + case 0x81027e75: return "_ZNSt7_MpunctIwE5_InitERKSt8_Locinfo"; + case 0x816aebc3: return "_ZNSt9bad_allocD0Ev"; + case 0x823759d3: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewl"; + case 0x8341b529: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE8overflowEi"; + case 0x83b2cc6f: return "_Znwj"; + case 0x83bca135: return "_ZNKSt11logic_error4whatEv"; + case 0x83cba890: return "_ZNSt6locale5facetD2Ev"; + case 0x84023c03: return "_ZSt12setprecisioni"; + case 0x854bc7c7: return "_ZNSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEED0Ev"; + case 0x85b3c6da: return "_ZNKSt8_Locinfo7_GetcvtEv"; + case 0x85ba062f: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE7_UnlockEv"; + case 0x867956a4: return "_ZNSt9basic_iosIcSt11char_traitsIcEED1Ev"; + case 0x868531a3: return "_ZdaPvj"; + case 0x86c66cfc: return "_ZNSsD1Ev"; + case 0x871506ea: return "_ZNSbIwSt11char_traitsIwESaIwEE6assignERKS2_jj"; + case 0x8729f617: return "_ZNSt10ostrstreamC1EPciNSt5_IosbIiE9_OpenmodeE"; + case 0x87b1f5eb: return "_ZNSt9exceptionD0Ev"; + case 0x88052736: return "_ZTv0_n12_NSt10ostrstreamD0Ev"; + case 0x883e1f16: return "_ZNKSt11logic_error8_DoraiseEv"; + case 0x884b021b: return "_ZNKSt5ctypeIwE8_DowidenEc"; + case 0x8a665143: return "_ZNSt8_Locinfo8_AddcatsEiPKc"; + case 0x8a85d688: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewx"; + case 0x8bfd4395: return "_ZNSt9basic_iosIwSt11char_traitsIwEE4initEPSt15basic_streambufIwS1_Eb"; + case 0x8c2e6d06: return "_ZNKSt8messagesIwE7do_openERKSsRKSt6locale"; + case 0x8c3afd4c: return "_ZSt10unexpectedv"; + case 0x8c6b8d39: return "_ZNSt13basic_filebufIcSt11char_traitsIcEED1Ev"; + case 0x8cda1f3b: return "_ZSt10_GetloctxtIcSt19istreambuf_iteratorIcSt11char_traitsIcEEEiRT0_S5_jPKT_"; + case 0x8d4e266b: return "_ZNKSt8_Locinfo9_GetctypeEv"; + case 0x8fa764f3: return "_ZNSt6_WinitC1Ev"; + case 0x900d1fa4: return "_ZNSt8time_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEED0Ev"; + case 0x903afa37: return "_ZTv0_n12_NSt13basic_ostreamIwSt11char_traitsIwEED0Ev"; + case 0x904dbd32: return "_ZNSt6locale7_LocimpC1Eb"; + case 0x9111ec36: return "_ZNSt13messages_baseD0Ev"; + case 0x91959ed6: return "_ZNKSt5ctypeIcE9do_narrowEcc"; + case 0x91b0e37e: return "_ZSt14set_unexpectedPFvvE"; + case 0x9268d6e7: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERj"; + case 0x928fbe36: return "_ZTv0_n12_NSdD1Ev"; + case 0x93c638e9: return "_ZNSt19istreambuf_iteratorIwSt11char_traitsIwEE5_PeekEv"; + case 0x94c49383: return "_ZdlPvS_"; + case 0x94fa1f5b: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE5uflowEv"; + case 0x95082493: return "_ZNKSt8messagesIcE6do_getEiiiRKSs"; + case 0x95b43c9d: return "_ZNSt6locale7_LocimpD2Ev"; + case 0x96634e42: return "_ZNKSt9bad_alloc4whatEv"; + case 0x96bc2578: return "_Znajj"; + case 0x97911f5f: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE5uflowEv"; + case 0x984ce3d7: return "_ZNSt8numpunctIcED1Ev"; + case 0x9891bf45: return "_ZNKSt7_MpunctIwE16do_thousands_sepEv"; + case 0x9a194306: return "_ZNSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE5_InitERKSt8_Locinfo"; + case 0x9a449047: return "_ZNSt7_MpunctIwEC2Ejb"; + case 0x9aa7a8b3: return "_ZNSt10istrstreamD2Ev"; + case 0x9afa5d71: return "_ZNSt10money_baseD2Ev"; + case 0x9b5358f9: return "_ZNKSt7_MpunctIcE16do_positive_signEv"; + case 0x9c40d1f9: return "_ZNKSt8numpunctIwE16do_decimal_pointEv"; + case 0x9c486668: return "_ZNSt6locale7_Locimp9_MakexlocERKSt8_LocinfoiPS0_PKS_"; + case 0x9cb73ee0: return "_ZSt6_ThrowRKSt9exception"; + case 0x9cfc0eaf: return "_ZNSiD1Ev"; + case 0x9d6a8167: return "_ZNSbIwSt11char_traitsIwESaIwEE5eraseEjj"; + case 0x9dbbe07d: return "_ZNKSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE8_GetmfldERS3_S5_bRSt8ios_base"; + case 0x9dc040e4: return "_Deletegloballocale"; + case 0x9dcb4bcb: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE14do_get_weekdayES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x9e741d47: return "_ZNSsC1ERKSs"; + case 0x9ec88ae6: return "_ZNKSt5ctypeIwE10do_tolowerEPwPKw"; + case 0x9ef60bf3: return "_ZNKSt5ctypeIwE10do_tolowerEw"; + case 0x9f528cd3: return "_ZNKSt7codecvtIccSt9_MbstatetE6do_outERS0_PKcS4_RS4_PcS6_RS6_"; + case 0x9f959451: return "_ZNSt13basic_istreamIwSt11char_traitsIwEED1Ev"; + case 0x9facb533: return "_ZNSt13messages_baseD1Ev"; + case 0x9fd2eea9: return "_ZNSt8_LocinfoC2EiPKc"; + case 0xa1c6fc55: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE7_UnlockEv"; + case 0xa1de25c2: return "_ZTv0_n12_NSt10ostrstreamD1Ev"; + case 0xa22d5dda: return "_ZNSt8messagesIcED0Ev"; + case 0xa2fd0ec5: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE9pbackfailEi"; + case 0xa35033e8: return "_ZNKSt5ctypeIwE8do_widenEPKcS2_Pw"; + case 0xa37c3e51: return "_ZNKSt5ctypeIwE8do_widenEc"; + case 0xa3f5c3b2: return "_ZNSt9strstreamD2Ev"; + case 0xa433147a: return "_ZNSt8messagesIcE7_GetcatEPPKNSt6locale5facetE"; + case 0xa464c70a: return "_ZNKSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_bRSt8ios_basewRKSbIwS2_SaIwEE"; + case 0xa4f6a919: return "_ZThn8_NSdD1Ev"; + case 0xa5306edb: return "_ZNSt10moneypunctIwLb1EED1Ev"; + case 0xa562099c: return "_ZNSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEED1Ev"; + case 0xa700bc7d: return "_ZNKSt7codecvtIwcSt9_MbstatetE6do_outERS0_PKwS4_RS4_PcS6_RS6_"; + case 0xa74e5a27: return "_ZNKSt6localeeqERKS_"; + case 0xa79c4516: return "_ZNSt15basic_streambufIcSt11char_traitsIcEED0Ev"; + case 0xa8ece2e0: return "_ZSt9use_facetISt10moneypunctIwLb0EEERKT_RKSt6locale"; + case 0xa8f64fdb: return "_ZNKSt5ctypeIcE10do_tolowerEPcPKc"; + case 0xa90c4ff2: return "_ZNSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE7_GetcatEPPKNSt6locale5facetE"; + case 0xa9116516: return "_ZNSs6appendEjc"; + case 0xa94be0fa: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE9_EndwriteEv"; + case 0xa957adcc: return "_ZNKSt5ctypeIcE9do_narrowEPKcS2_cPc"; + case 0xa9e5bb16: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERm"; + case 0xaa520d9f: return "_ZNSt6locale7_Locimp7_AddfacEPNS_5facetEj"; + case 0xaae64804: return "_ZNSt8ios_base8_FindarrEi"; + case 0xab211d97: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecb"; + case 0xab5832fd: return "_ZNSt10money_baseD1Ev"; + case 0xabd92bcc: return "_ZNSt7collateIwE7_GetcatEPPKNSt6locale5facetE"; + case 0xabdc2b49: return "_ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE7_GetcatEPPKNSt6locale5facetE"; + case 0xac6c23c0: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERy"; + case 0xad3777a2: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE8overflowEi"; + case 0xad382a99: return "_ZdlPvRKSt9nothrow_t"; + case 0xad6d839f: return "_ZNSt12codecvt_baseD0Ev"; + case 0xad6dbac2: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERm"; + case 0xadc2263b: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE6xsputnEPKci"; + case 0xae7d042f: return "_ZNSt7codecvtIwcSt9_MbstatetE7_GetcatEPPKNSt6locale5facetE"; + case 0xaea59ceb: return "_ZNSt10ctype_baseD0Ev"; + case 0xb0c185b7: return "_ZNSt10moneypunctIcLb1EE7_GetcatEPPKNSt6locale5facetE"; + case 0xb0e7c2f3: return "_ZNSiD0Ev"; + case 0xb1550b3c: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecx"; + case 0xb1ac1fa3: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE6xsgetnEPwi"; + case 0xb1d696f7: return "_ZNKSt8numpunctIcE12do_falsenameEv"; + case 0xb326f699: return "_ZNKSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_bRSt8ios_basece"; + case 0xb33ef042: return "_ZNSt8bad_castD0Ev"; + case 0xb3f05af3: return "_ZNKSt7collateIcE12do_transformEPKcS2_"; + case 0xb4352488: return "_ZNKSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_bRSt8ios_basecRKSs"; + case 0xb4a8791f: return "_ZNSt8time_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEED1Ev"; + case 0xb509ab64: return "_ZNSt10moneypunctIcLb1EED1Ev"; + case 0xb53fa02e: return "_ZnwjjRKSt9nothrow_t"; + case 0xb6a4d760: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE7seekposESt4fposISt9_MbstatetENSt5_IosbIiE9_OpenmodeE"; + case 0xb6a7ba7a: return "_ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEED0Ev"; + case 0xb74f7b8f: return "_ZNSt6locale7_LocimpC2ERKS0_"; + case 0xb7dcbfdd: return "__Setgloballocale"; + case 0xb80ca215: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE5imbueERKSt6locale"; + case 0xb87c4b43: return "_ZNSt12strstreambuf6freezeEb"; + case 0xb8836b50: return "_ZNSt9exception18_Set_raise_handlerEPFvRKS_E"; + case 0xb8ec13a5: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewb"; + case 0xb9a2282d: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE8overflowEi"; + case 0xba0b6300: return "_ZNSt9basic_iosIwSt11char_traitsIwEED1Ev"; + case 0xba85ce08: return "_ZNSt12strstreambufD2Ev"; + case 0xbaa15803: return "_ZSt4setwi"; + case 0xbb4599c5: return "_ZNSt11logic_errorD1Ev"; + case 0xbb712718: return "_ZnwjRKSt9nothrow_t"; + case 0xbc5ad91c: return "_ZNKSt7collateIwE10do_compareEPKwS2_S2_S2_"; + case 0xbd140e12: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE11do_get_timeES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0xbd316983: return "_ZNSt8numpunctIcE5_InitERKSt8_Locinfo"; + case 0xbd35830b: return "_ZdaPvjS_"; + case 0xbd58ea5a: return "_ZNSt19ostreambuf_iteratorIwSt11char_traitsIwEEaSEw"; + case 0xbda26024: return "_ZNSt9strstreamD0Ev"; + case 0xbf9c3609: return "_ZNKSt5ctypeIwE10do_toupperEPwPKw"; + case 0xc013acd8: return "_ZNSt8ios_base8_CallfnsENS_5eventE"; + case 0xc06a4cd8: return "_ZNSt7_MpunctIwED1Ev"; + case 0xc22cebd8: return "_ZNSt8messagesIwED1Ev"; + case 0xc3d24eb3: return "_ZNSt9basic_iosIwSt11char_traitsIwEED0Ev"; + case 0xc41d676d: return "_ZNSt9time_baseD2Ev"; + case 0xc4c7993b: return "_ZNSbIwSt11char_traitsIwESaIwEE5_TidyEbj"; + case 0xc53ab1c0: return "_ZNSt8numpunctIwE5_InitERKSt8_Locinfo"; + case 0xc5977986: return "_ZNSt8ios_base7_AddstdEv"; + case 0xc612a38e: return "_ZNSt6_WinitD1Ev"; + case 0xc6e09225: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE5_InitEPSt6_FiletNS2_7_InitflE"; + case 0xc6ea0fd0: return "_ZNSt6locale7classicEv"; + case 0xc6f18e84: return "_ZNKSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_bRSt8ios_baseRNSt5_IosbIiE8_IostateERSbIwS2_SaIwEE"; + case 0xc79278ec: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE5imbueERKSt6locale"; + case 0xc7931798: return "_ZNKSt12_String_base5_XranEv"; + case 0xc7d0ee0c: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE16do_get_monthnameES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0xc862f7c8: return "_ZNSt12strstreambuf8overflowEi"; + case 0xcac83a05: return "_ZNSt6locale7_LocimpC2Eb"; + case 0xcb7d00a4: return "_ZNSt6_WinitD2Ev"; + case 0xcb82e0dc: return "_ZSt13set_terminatePFvvE"; + case 0xcbe74ad3: return "_ZNKSt8messagesIwE8do_closeEi"; + case 0xcc79f55d: return "_ZNKSt7_MpunctIcE16do_negative_signEv"; + case 0xccf14bd5: return "_ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE7_GetcatEPPKNSt6locale5facetE"; + case 0xcd33ed4f: return "_ZNSbIwSt11char_traitsIwESaIwEEC1Ev"; + case 0xcdafdf19: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE9showmanycEv"; + case 0xce653b6c: return "_ZNSt6_MutexC2Ev"; + case 0xce6705c3: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE8_GetifldEPcRS3_S6_NSt5_IosbIiE9_FmtflagsERKSt6locale"; + case 0xce8c6abc: return "_ZNSt8ios_base4InitC2Ev"; + case 0xcf9b4d80: return "_ZNSt10moneypunctIwLb1EED0Ev"; + case 0xd05ea37c: return "_ZNKSt19istreambuf_iteratorIwSt11char_traitsIwEEdeEv"; + case 0xd1b043b7: return "_ZSt10_MaklocchrIwET_cPS0_RKSt7_Cvtvec"; + case 0xd1ee6195: return "_ZNKSt8time_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecPKSt2tmcc"; + case 0xd2f9d93d: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewe"; + case 0xd356aefd: return "_ZNSt6_Mutex7_UnlockEv"; + case 0xd38f4018: return "_ZSt11_MaklocbyteIwEcT_RKSt7_Cvtvec"; + case 0xd4838fbd: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewm"; + case 0xd4ba5b31: return "_ZNSt8_LocinfoC2EPKc"; + case 0xd5244a29: return "_ZNSt10moneypunctIwLb1EE7_GetcatEPPKNSt6locale5facetE"; + case 0xd5c5ee3d: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERj"; + case 0xd6ee1090: return "_ZNKSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_bRSt8ios_baseRNSt5_IosbIiE8_IostateERe"; + case 0xd73321ed: return "_ZNSt10ostrstreamD1Ev"; + case 0xd76b2e07: return "_ZNKSt7codecvtIwcSt9_MbstatetE13do_max_lengthEv"; + case 0xd78efcc3: return "_ZNSt12strstreambuf9underflowEv"; + case 0xd7bc220d: return "_ZNSt8time_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEED1Ev"; + case 0xd7d92e51: return "_ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEED0Ev"; + case 0xd830252c: return "_ZNSt12strstreambuf5_InitEiPcS0_i"; + case 0xd84b3689: return "_ZdlPv"; + case 0xd8aeb94a: return "_ZNSt8messagesIcED1Ev"; + case 0xd8b23008: return "_ZNSt8ios_baseD2Ev"; + case 0xd93d52b1: return "_ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEED1Ev"; + case 0xd9a12c5e: return "_ZNKSt5ctypeIcE10do_toupperEPcPKc"; + case 0xd9d8af82: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE8overflowEi"; + case 0xda1088ce: return "_ZNSt6locale5facet7_IncrefEv"; + case 0xda1b159a: return "_ZNSt6_MutexD2Ev"; + case 0xda5469b3: return "_ZNSt9time_baseD0Ev"; + case 0xdab0a910: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE9pbackfailEi"; + case 0xdaf3996f: return "_ZNSt6locale6globalERKS_"; + case 0xdb5eae26: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE5_InitEPSt6_FiletNS2_7_InitflE"; + case 0xdc0c889c: return "_ZNSt8ios_base7copyfmtERKS_"; + case 0xdc4d7540: return "_ZNSt5ctypeIwED1Ev"; + case 0xdc65ab00: return "_ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEED1Ev"; + case 0xdc981b5f: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE9underflowEv"; + case 0xdd8b1d47: return "_ZNSs5eraseEjj"; + case 0xdefe3230: return "_ZNSt8ios_baseD1Ev"; + case 0xdf1e09e1: return "_ZNKSt5ctypeIwE9do_narrowEPKwS2_cPc"; + case 0xdf7edb4d: return "_ZSt9use_facetISt10moneypunctIwLb1EEERKT_RKSt6locale"; + case 0xe177fd02: return "_ZNSt7_MpunctIcED2Ev"; + case 0xe196beab: return "_ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEED0Ev"; + case 0xe206c08f: return "_ZNSt13basic_filebufIwSt11char_traitsIwEED0Ev"; + case 0xe2b2ac5a: return "_ZNSt6locale5facet9_RegisterEv"; + case 0xe3edd790: return "_ZNSt8bad_castD1Ev"; + case 0xe528a368: return "_ZNKSt7_MpunctIcE14do_curr_symbolEv"; + case 0xe54f1fe0: return "_ZNKSt9bad_alloc8_DoraiseEv"; + case 0xe5e1dcbc: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE5imbueERKSt6locale"; + case 0xe6547e35: return "_ZNSt8messagesIwED0Ev"; + case 0xe667985a: return "_ZNSt8time_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEED0Ev"; + case 0xe75f6e21: return "_ZNKSt12length_error8_DoraiseEv"; + case 0xe7d8449e: return "_ZdlPvjS_"; + case 0xe82a422d: return "_ZNKSt8numpunctIwE11do_truenameEv"; + case 0xe8691be5: return "_ZNSt5ctypeIwED0Ev"; + case 0xe8c15f8a: return "_ZNSt7_MpunctIwED2Ev"; + case 0xe9d7a4ae: return "_ZNKSt8time_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewPKSt2tmcc"; + case 0xeb76301c: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE9pbackfailEi"; + case 0xebd4b51d: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE11do_get_yearES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0xece969c0: return "_ZTv0_n12_NSt10istrstreamD0Ev"; + case 0xed3da02b: return "_Znwjj"; + case 0xee853baf: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE4syncEv"; + case 0xef62751c: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE13do_date_orderEv"; + case 0xef6f90d8: return "_ZNKSt5ctypeIwE11do_scan_notEsPKwS2_"; + case 0xef959a6d: return "_ZThn8_NSt9strstreamD0Ev"; + case 0xf001a741: return "_ZNSt12strstreambufD1Ev"; + case 0xf00401d2: return "_ZNSt9basic_iosIcSt11char_traitsIcEED0Ev"; + case 0xf01deff8: return "_ZNKSt7codecvtIwcSt9_MbstatetE5do_inERS0_PKcS4_RS4_PwS6_RS6_"; + case 0xf05df017: return "_ZNSt5ctypeIcE7_GetcatEPPKNSt6locale5facetE"; + case 0xf127e816: return "_ZNSt10istrstreamD1Ev"; + case 0xf1543f02: return "_ZNKSt8_Locinfo8_GetcollEv"; + case 0xf1c86c92: return "_ZNKSt12out_of_range8_DoraiseEv"; + case 0xf1cff87d: return "_ZNSt10ctype_baseD2Ev"; + case 0xf2b9ab86: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERf"; + case 0xf30d3407: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewd"; + case 0xf51dc289: return "_ZNSt7codecvtIccSt9_MbstatetED1Ev"; + case 0xf53021e0: return "_ZNSt8bad_castC1Ev"; + case 0xf5825c7d: return "_ZNSt7collateIwED1Ev"; + case 0xf584de56: return "_ZNSt6locale7_Locimp8_MakelocERKSt8_LocinfoiPS0_PKS_"; + case 0xf58e83a5: return "_Znaj"; + case 0xf67a7e17: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE5uflowEv"; + case 0xf73f6afc: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE7seekoffElNSt5_IosbIiE8_SeekdirENS4_9_OpenmodeE"; + case 0xf7845d1c: return "_ZNSt7_MpunctIcED1Ev"; + case 0xf7ba51fd: return "_ZNSt13basic_ostreamIwSt11char_traitsIwEED0Ev"; + case 0xf83e8d95: return "_ZNKSt5ctypeIcE10do_tolowerEc"; + case 0xf9ff46a1: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE7seekoffElNSt5_IosbIiE8_SeekdirENS4_9_OpenmodeE"; + case 0xfb36c588: return "_ZNSt9strstreamC1EPciNSt5_IosbIiE9_OpenmodeE"; + case 0xfc563813: return "_ZNKSt7codecvtIccSt9_MbstatetE5do_inERS0_PKcS4_RS4_PcS6_RS6_"; + case 0xfc825dda: return "_ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE7_GetcatEPPKNSt6locale5facetE"; + case 0xfe468b7a: return "_ZTv0_n12_NSdD0Ev"; + case 0xfeb4107c: return "_ZNSt12codecvt_baseD2Ev"; + case 0xfefd7d3a: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERy"; + case 0xffaf3218: return "_ZTv0_n12_NSoD0Ev"; + case 0xfff6ef55: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERb"; + } + + if (module == "sysPrxForUser") switch (fnid) + { + case 0x0341bb97: return "sys_prx_get_module_id_by_address"; + case 0x04e83d2c: return "_sys_strncmp"; + case 0x052d29a6: return "_sys_strcat"; + case 0x05c65656: return "sys_mempool_try_allocate_block"; + case 0x0618936b: return "_sys_vsnprintf"; + case 0x06574237: return "_sys_snprintf"; + case 0x1573dc3f: return "sys_lwmutex_lock"; + case 0x191f0c4a: return "_sys_strrchr"; + case 0x1ae10b92: return "_sys_spu_printf_attach_thread"; + case 0x1bc200f4: return "sys_lwmutex_unlock"; + case 0x1c9a942c: return "sys_lwcond_destroy"; + case 0x1ca525a2: return "_sys_strncasecmp"; + case 0x1ed454ce: return "sys_spu_elf_get_information"; + case 0x24a1ea07: return "sys_ppu_thread_create"; + case 0x25596f51: return "sys_mempool_get_count"; + case 0x26090058: return "sys_prx_load_module"; + case 0x27427742: return "_sys_memmove"; + case 0x2a6d9d51: return "sys_lwcond_wait"; + case 0x2c847572: return "_sys_process_atexitspawn"; + case 0x2d36462b: return "_sys_strlen"; + case 0x2f85c0ef: return "sys_lwmutex_create"; + case 0x3172759d: return "sys_game_get_temperature"; + case 0x318f17e1: return "_sys_memalign"; + case 0x350d454e: return "sys_ppu_thread_get_id"; + case 0x35168520: return "_sys_heap_malloc"; + case 0x3bd53c7b: return "_sys_memchr"; + case 0x3dd4a957: return "sys_ppu_thread_register_atexit"; + case 0x409ad939: return "sys_mmapper_free_memory"; + case 0x42b23552: return "sys_prx_register_library"; + case 0x44265c08: return "_sys_heap_memalign"; + case 0x459b4393: return "_sys_strcmp"; + case 0x45fe2fce: return "_sys_spu_printf_initialize"; + case 0x4643ba6e: return "sys_mmapper_unmap_memory"; + case 0x4a071d98: return "sys_interrupt_thread_disestablish"; + case 0x4b2f301a: return "_sys_tolower"; + case 0x5267cb35: return "sys_spinlock_unlock"; + case 0x52aadadf: return "sys_lwcond_signal_to"; + case 0x5fdfb2fe: return "_sys_spu_printf_detach_group"; + case 0x608212fc: return "sys_mempool_free_block"; + case 0x620e35a7: return "sys_game_get_system_sw_version"; + case 0x67f9fedb: return "sys_game_process_exitspawn2"; + case 0x68b9b011: return "_sys_memset"; + case 0x6bf66ea7: return "_sys_memcpy"; + case 0x6e05231d: return "sys_game_watchdog_stop"; + case 0x70258515: return "sys_mmapper_allocate_memory_from_container"; + case 0x71a8472a: return "sys_get_random_number"; + case 0x722a0254: return "sys_spinlock_trylock"; + case 0x74311398: return "sys_prx_get_my_module_id"; + case 0x744680a2: return "sys_initialize_tls"; + case 0x7498887b: return "_sys_strchr"; + case 0x791b9219: return "_sys_vsprintf"; + case 0x80fb0c19: return "sys_prx_stop_module"; + case 0x8461e528: return "sys_time_get_system_time"; + case 0x84bb6774: return "sys_prx_get_module_info"; + case 0x893305fa: return "sys_raw_spu_load"; + case 0x8985b5b6: return "_sys_heap_stats"; + case 0x8a2f159b: return "console_getc"; + case 0x8a561d92: return "_sys_heap_free"; + case 0x8bb03ab8: return "sys_game_board_storage_write"; + case 0x8c2bb498: return "sys_spinlock_initialize"; + case 0x96328741: return "_sys_process_at_Exitspawn"; + case 0x4f7172c9: return "sys_process_is_stack"; + case 0x996f7cf8: return "_sys_strncat"; + case 0x99c88692: return "_sys_strcpy"; + case 0x9d3c0f81: return "sys_mempool_destroy"; + case 0x9e0623b5: return "sys_game_watchdog_start"; + case 0x9f04f7af: return "_sys_printf"; + case 0x9f18429d: return "sys_prx_start_module"; + case 0x9f950780: return "sys_game_get_rtc_status"; + case 0xa146a143: return "sys_mempool_allocate_block"; + case 0xa1f9eafe: return "_sys_sprintf"; + case 0xa285139d: return "sys_spinlock_lock"; + case 0xa2c7ba64: return "sys_prx_exitspawn_with_level"; + case 0xa330ad84: return "sys_prx_load_module_on_memcontainer_by_fd"; + case 0xa3e3be68: return "sys_ppu_thread_once"; + case 0xa5d06bf0: return "sys_prx_get_module_list"; + case 0xaa6d9bff: return "sys_prx_load_module_on_memcontainer"; + case 0xac6fc404: return "sys_ppu_thread_unregister_atexit"; + case 0xacad8fb6: return "sys_game_watchdog_clear"; + case 0xaeb78725: return "sys_lwmutex_trylock"; + case 0xaede4b03: return "_sys_heap_delete_heap"; + case 0xaff080a4: return "sys_ppu_thread_exit"; + case 0xb257540b: return "sys_mmapper_allocate_memory"; + case 0xb27c8ae7: return "sys_prx_load_module_list"; + case 0xb2fcf2c8: return "_sys_heap_create_heap"; + case 0xb3bbcf2a: return "_sys_spu_printf_detach_thread"; + case 0xb6369393: return "_sys_heap_get_total_free_size"; + case 0xb995662e: return "sys_raw_spu_image_load"; + case 0xb9bf1078: return "_sys_heap_alloc_heap_memory"; + case 0xbdb18f83: return "_sys_malloc"; + case 0xc3476d0c: return "sys_lwmutex_destroy"; + case 0xc4fd6121: return "_sys_qsort"; + case 0xca9a60bf: return "sys_mempool_create"; + case 0xd0ea47a7: return "sys_prx_unregister_library"; + case 0xd1ad4570: return "_sys_heap_get_mallinfo"; + case 0xd3039d4d: return "_sys_strncpy"; + case 0xda0eb71a: return "sys_lwcond_create"; + case 0xdb6b3250: return "sys_spu_elf_get_segments"; + case 0xdc578057: return "sys_mmapper_map_memory"; + case 0xdd0c1e09: return "_sys_spu_printf_attach_group"; + case 0xdd3b27ac: return "_sys_spu_printf_finalize"; + case 0xe0998dbf: return "sys_prx_get_module_id_by_name"; + case 0xe0da8efd: return "sys_spu_image_close"; + case 0xe66bac36: return "console_putc"; + case 0xe6f2c1e7: return "sys_process_exit"; + case 0xe76964f5: return "sys_game_board_storage_read"; + case 0xe7ef3a80: return "sys_prx_load_module_list_on_memcontainer"; + case 0xe9a1bd84: return "sys_lwcond_signal_all"; + case 0xebe5f72f: return "sys_spu_image_import"; + case 0xeef75113: return "_sys_toupper"; + case 0xef68c17c: return "sys_prx_load_module_by_fd"; + case 0xef87a695: return "sys_lwcond_signal"; + case 0xf0aece0d: return "sys_prx_unload_module"; + case 0xf57e1d6f: return "console_write"; + case 0xf7f7fb20: return "_sys_free"; + case 0xfa7f693d: return "_sys_vprintf"; + case 0xfb5db080: return "_sys_memcmp"; + case 0xfc52a7a9: return "sys_game_process_exitspawn"; + } + + // Check registered functions + if (const auto sm = ppu_module_manager::get_module(module)) + { + const auto found = sm->functions.find(fnid); + + if (found != sm->functions.end()) + { + return found->second.name; + } + } + + return fmt::format("0x%08X", fnid); +} + +// Get variable name by VNID +extern std::string ppu_get_variable_name(const std::string& module, u32 vnid) +{ + // Check registered variables + if (const auto sm = ppu_module_manager::get_module(module)) + { + const auto found = sm->variables.find(vnid); + + if (found != sm->variables.end()) + { + return found->second.name; + } + } + + return fmt::format("0x%08X", vnid); +} + +s32 ppu_error_code::report(s32 error, const char* text) +{ + if (auto thread = get_current_cpu_thread()) + { + if (thread->type == cpu_type::ppu) + { + if (auto func = static_cast(thread)->last_function) + { + LOG_ERROR(PPU, "Function '%s' failed with 0x%08x : %s", func, error, text); + } + else + { + LOG_ERROR(PPU, "Unknown function failed with 0x%08x : %s", error, text); + } + + return error; + } + } + + LOG_ERROR(PPU, "Illegal call to ppu_report_error(0x%x, '%s')!"); + return error; +} diff --git a/rpcs3/Emu/SysCalls/SC_FUNC.h b/rpcs3/Emu/Cell/PPUFunction.h similarity index 68% rename from rpcs3/Emu/SysCalls/SC_FUNC.h rename to rpcs3/Emu/Cell/PPUFunction.h index 510c7fd0ff..184e8bba7b 100644 --- a/rpcs3/Emu/SysCalls/SC_FUNC.h +++ b/rpcs3/Emu/Cell/PPUFunction.h @@ -1,14 +1,14 @@ #pragma once -#include "Emu/Cell/PPUThread.h" +#include "PPUThread.h" -using ppu_func_caller = void(*)(PPUThread&); +using ppu_function_t = void(*)(PPUThread&); + +#define BIND_FUNC(func) [](PPUThread& ppu){ ppu.last_function = #func; ppu_func_detail::do_call(ppu, func); } struct ppu_va_args_t { - u32 g_count; - u32 f_count; - u32 v_count; + u32 count; // Number of 64-bit args passed }; namespace ppu_func_detail @@ -16,12 +16,12 @@ namespace ppu_func_detail // argument type classification enum arg_class : u32 { - ARG_GENERAL, // argument is stored in GPR registers (from r3 to r10) - ARG_FLOAT, // argument is stored in FPR registers (from f1 to f13) - ARG_VECTOR, // argument is stored in VPR registers (from v2 to v13) - ARG_STACK, // argument is stored on the stack + ARG_GENERAL, // argument stored in GPR (from r3 to r10) + ARG_FLOAT, // argument stored in FPR (from f1 to f13) + ARG_VECTOR, // argument stored in VR (from v2 to v13) + ARG_STACK, // argument stored on the stack ARG_CONTEXT, // PPUThread& passed, doesn't affect g/f/v_count - ARG_VARIADIC, // information about arg counts already passed, doesn't affect g/f/v_count + ARG_VARIADIC, // argument count at specific position, doesn't affect g/f/v_count ARG_UNKNOWN, }; @@ -33,9 +33,9 @@ namespace ppu_func_detail static_assert(!std::is_reference::value, "Invalid function argument type (reference)"); static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_GENERAL"); - static force_inline T get_arg(PPUThread& ppu) + static inline T get_arg(PPUThread& ppu) { - return cast_from_ppu_gpr(ppu.GPR[g_count + 2]); + return ppu_gpr_cast(ppu.GPR[g_count + 2]); } }; @@ -44,7 +44,7 @@ namespace ppu_func_detail { static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_FLOAT"); - static force_inline T get_arg(PPUThread& ppu) + static inline T get_arg(PPUThread& ppu) { return static_cast(ppu.FPR[f_count]); } @@ -53,26 +53,22 @@ namespace ppu_func_detail template struct bind_arg { - static_assert(std::is_same, v128>::value, "Invalid function argument type for ARG_VECTOR"); + static_assert(std::is_same::value, "Invalid function argument type for ARG_VECTOR"); static force_inline T get_arg(PPUThread& ppu) { - return ppu.VPR[v_count + 1]; + return ppu.VR[v_count + 1]; } }; template struct bind_arg { - static_assert(f_count <= 13, "TODO: Unsupported stack argument type (float)"); - static_assert(v_count <= 12, "TODO: Unsupported stack argument type (vector)"); - static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_STACK"); + static_assert(alignof(T) <= 16, "Unsupported type alignment for ARG_STACK"); static force_inline T get_arg(PPUThread& ppu) { - // TODO: check stack argument displacement - const u64 res = ppu.get_stack_arg(8 + std::max(g_count - 8, 0) + std::max(f_count - 13, 0) + std::max(v_count - 12, 0)); - return cast_from_ppu_gpr(res); + return ppu_gpr_cast(*ppu.get_stack_arg(g_count, alignof(T))); // TODO } }; @@ -94,7 +90,7 @@ namespace ppu_func_detail static force_inline ppu_va_args_t get_arg(PPUThread& ppu) { - return{ g_count, f_count, v_count }; + return{ g_count }; } }; @@ -106,7 +102,7 @@ namespace ppu_func_detail static force_inline void put_result(PPUThread& ppu, const T& result) { - ppu.GPR[3] = cast_to_ppu_gpr(result); + ppu.GPR[3] = ppu_gpr_cast(result); } }; @@ -124,11 +120,11 @@ namespace ppu_func_detail template struct bind_result { - static_assert(std::is_same, v128>::value, "Invalid function result type for ARG_VECTOR"); + static_assert(std::is_same::value, "Invalid function result type for ARG_VECTOR"); static force_inline void put_result(PPUThread& ppu, const T& result) { - ppu.VPR[2] = result; + ppu.VR[2] = result; } }; @@ -176,9 +172,9 @@ namespace ppu_func_detail // TODO: check calculations const bool is_float = std::is_floating_point::value; - const bool is_vector = std::is_same, v128>::value; + const bool is_vector = std::is_same::value; const bool is_context = std::is_same::value; - const bool is_variadic = std::is_same, ppu_va_args_t>::value; + const bool is_variadic = std::is_same::value; const bool is_general = !is_float && !is_vector && !is_context && !is_variadic; const arg_class t = @@ -189,19 +185,20 @@ namespace ppu_func_detail is_variadic ? ARG_VARIADIC : ARG_UNKNOWN; - const u32 g = g_count + is_general; + const u32 g = g_count + (is_general || is_float ? 1 : is_vector ? ::align(g_count, 2) + 2 : 0); const u32 f = f_count + is_float; const u32 v = v_count + is_vector; return call(ppu, func, arg_info_pack_t{}); } - template struct result_type + template + struct result_type { static_assert(!std::is_pointer::value, "Invalid function result type (pointer)"); static_assert(!std::is_reference::value, "Invalid function result type (reference)"); static const bool is_float = std::is_floating_point::value; - static const bool is_vector = std::is_same, v128>::value; + static const bool is_vector = std::is_same::value; static const arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); }; @@ -229,10 +226,66 @@ namespace ppu_func_detail } }; - template force_inline void do_call(PPUThread& ppu, RT(*func)(T...)) + template + force_inline void do_call(PPUThread& ppu, RT(*func)(T...)) { func_binder::do_call(ppu, func); } } -#define BIND_FUNC(func) [](PPUThread& ppu){ ppu_func_detail::do_call(ppu, func); } +class ppu_function_manager +{ + // Global variable for each registered function + template + struct registered + { + static u32 index; + }; + + // Access global function list + static never_inline auto& access() + { + static std::vector list + { + nullptr, + [](PPUThread& ppu) { ppu.state += cpu_state::ret; }, + }; + + return list; + } + + static never_inline u32 add_function(ppu_function_t function) + { + auto& list = access(); + + list.push_back(function); + + return ::size32(list) - 1; + } + +public: + // Register function (shall only be called during global initialization) + template + static inline u32 register_function(ppu_function_t func) + { + return registered::index = add_function(func); + } + + // Get function index + template + static inline u32 get_index() + { + return registered::index; + } + + // Read all registered functions + static inline const auto& get() + { + return access(); + } +}; + +template +u32 ppu_function_manager::registered::index = 0; + +#define FIND_FUNC(func) ppu_function_manager::get_index() diff --git a/rpcs3/Emu/Cell/PPUInterpreter.cpp b/rpcs3/Emu/Cell/PPUInterpreter.cpp index ec051c8ab1..1a33bad5a6 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.cpp +++ b/rpcs3/Emu/Cell/PPUInterpreter.cpp @@ -1,13 +1,40 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/Cell/PPUThread.h" -#include "Emu/SysCalls/SysCalls.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/Cell/PPUDecoder.h" -#include "PPUInstrTable.h" +#include "PPUThread.h" #include "PPUInterpreter.h" -#include "PPUInterpreter2.h" + +inline u8 rol8(const u8 x, const u8 n) { return x << n | x >> (8 - n); } +inline u16 rol16(const u16 x, const u16 n) { return x << n | x >> (16 - n); } +inline u32 rol32(const u32 x, const u32 n) { return x << n | x >> (32 - n); } +inline u64 rol64(const u64 x, const u64 n) { return x << n | x >> (64 - n); } +inline u64 dup32(const u32 x) { return x | static_cast(x) << 32; } + +#if defined(__GNUG__) +inline std::uint64_t UMULH64(std::uint64_t a, std::uint64_t b) +{ + std::uint64_t result; + __asm__("mulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b)); + return result; +} + +inline std::int64_t MULH64(std::int64_t a, std::int64_t b) +{ + std::int64_t result; + __asm__("imulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b)); + return result; +} +#endif + +#if defined(_MSC_VER) +#define UMULH64 __umulh +#define MULH64 __mulh +#endif + +extern u64 get_timebased_time(); +extern void ppu_execute_syscall(PPUThread& ppu, u64 code); +extern void ppu_execute_function(PPUThread& ppu, u32 index); + +namespace vm { using namespace ps3; } class ppu_scale_table_t { @@ -30,20 +57,10 @@ public: const g_ppu_scale_table; -void ppu_interpreter::NULL_OP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::TDI(PPUThread& ppu, ppu_opcode_t op) { - PPUInterpreter inter(CPU); (*PPU_instr::main_list)(&inter, op.opcode); -} - -void ppu_interpreter::NOP(PPUThread& CPU, ppu_opcode_t op) -{ -} - - -void ppu_interpreter::TDI(PPUThread& CPU, ppu_opcode_t op) -{ - const s64 a = CPU.GPR[op.ra], b = op.simm16; - const u64 a_ = a, b_ = b; // unsigned + const s64 a = ppu.GPR[op.ra], b = op.simm16; + const u64 a_ = a, b_ = b; if (((op.bo & 0x10) && a < b) || ((op.bo & 0x8) && a > b) || @@ -51,14 +68,14 @@ void ppu_interpreter::TDI(PPUThread& CPU, ppu_opcode_t op) ((op.bo & 0x2) && a_ < b_) || ((op.bo & 0x1) && a_ > b_)) { - throw EXCEPTION(""); + throw std::runtime_error("Trap!" HERE); } } -void ppu_interpreter::TWI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::TWI(PPUThread& ppu, ppu_opcode_t op) { - const s32 a = (s32)CPU.GPR[op.ra], b = op.simm16; - const u32 a_ = a, b_ = b; // unsigned + const s32 a = u32(ppu.GPR[op.ra]), b = op.simm16; + const u32 a_ = a, b_ = b; if (((op.bo & 0x10) && a < b) || ((op.bo & 0x8) && a > b) || @@ -66,511 +83,439 @@ void ppu_interpreter::TWI(PPUThread& CPU, ppu_opcode_t op) ((op.bo & 0x2) && a_ < b_) || ((op.bo & 0x1) && a_ > b_)) { - throw EXCEPTION(""); + throw std::runtime_error("Trap!" HERE); } } -void ppu_interpreter::MFVSCR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MFVSCR(PPUThread& ppu, ppu_opcode_t op) { - throw EXCEPTION(""); + throw std::runtime_error("MFVSCR" HERE); } -void ppu_interpreter::MTVSCR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MTVSCR(PPUThread& ppu, ppu_opcode_t op) { - // ignored (MFVSCR disabled) + LOG_WARNING(PPU, "MTVSCR"); } -void ppu_interpreter::VADDCUW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDCUW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; - CPU.VPR[op.vd].vi = _mm_srli_epi32(_mm_cmpgt_epi32(_mm_xor_si128(b, _mm_set1_epi32(0x80000000)), _mm_xor_si128(a, _mm_set1_epi32(0x7fffffff))), 31); + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; + ppu.VR[op.vd].vi = _mm_srli_epi32(_mm_cmpgt_epi32(_mm_xor_si128(b, _mm_set1_epi32(0x80000000)), _mm_xor_si128(a, _mm_set1_epi32(0x7fffffff))), 31); } -void ppu_interpreter::VADDFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::addfs(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::addfs(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VADDSBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDSBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_adds_epi8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_adds_epi8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VADDSHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDSHS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_adds_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_adds_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VADDSWS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDSWS(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va]; - const auto b = CPU.VPR[op.vb]; + const auto a = ppu.VR[op.va]; + const auto b = ppu.VR[op.vb]; const auto s = v128::add32(a, b); // a + b const auto m = (a ^ s) & (b ^ s); // overflow bit const auto x = _mm_srai_epi32(m.vi, 31); // saturation mask const auto y = _mm_srai_epi32(_mm_and_si128(s.vi, m.vi), 31); // positive saturation mask - CPU.VPR[op.vd].vi = _mm_xor_si128(_mm_xor_si128(_mm_srli_epi32(x, 1), y), _mm_or_si128(s.vi, x)); + ppu.VR[op.vd].vi = _mm_xor_si128(_mm_xor_si128(_mm_srli_epi32(x, 1), y), _mm_or_si128(s.vi, x)); } -void ppu_interpreter::VADDUBM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDUBM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::add8(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::add8(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VADDUBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDUBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_adds_epu8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_adds_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VADDUHM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDUHM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::add16(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::add16(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VADDUHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDUHS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_adds_epu16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_adds_epu16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VADDUWM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDUWM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::add32(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::add32(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VADDUWS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDUWS(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_add_epi32(a, b), _mm_cmpgt_epi32(_mm_xor_si128(b, _mm_set1_epi32(0x80000000)), _mm_xor_si128(a, _mm_set1_epi32(0x7fffffff)))); + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; + ppu.VR[op.vd].vi = _mm_or_si128(_mm_add_epi32(a, b), _mm_cmpgt_epi32(_mm_xor_si128(b, _mm_set1_epi32(0x80000000)), _mm_xor_si128(a, _mm_set1_epi32(0x7fffffff)))); } -void ppu_interpreter::VAND(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAND(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = CPU.VPR[op.va] & CPU.VPR[op.vb]; + ppu.VR[op.vd] = ppu.VR[op.va] & ppu.VR[op.vb]; } -void ppu_interpreter::VANDC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VANDC(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = CPU.VPR[op.va] & ~CPU.VPR[op.vb]; + ppu.VR[op.vd] = v128::andnot(ppu.VR[op.vb], ppu.VR[op.va]); } -void ppu_interpreter::VAVGSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAVGSB(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va]; - const auto b = v128::add8(CPU.VPR[op.vb], v128::from8p(1)); // add 1 + const auto a = ppu.VR[op.va]; + const auto b = v128::add8(ppu.VR[op.vb], v128::from8p(1)); // add 1 const auto summ = v128::add8(a, b) & v128::from8p(0xfe); const auto sign = v128::from8p(0x80); const auto overflow = (((a ^ summ) & (b ^ summ)) ^ summ ^ v128::eq8(b, sign)) & sign; // calculate msb - CPU.VPR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi64(summ.vi, 1)); + ppu.VR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi64(summ.vi, 1)); } -void ppu_interpreter::VAVGSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAVGSH(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va]; - const auto b = v128::add16(CPU.VPR[op.vb], v128::from16p(1)); // add 1 + const auto a = ppu.VR[op.va]; + const auto b = v128::add16(ppu.VR[op.vb], v128::from16p(1)); // add 1 const auto summ = v128::add16(a, b); const auto sign = v128::from16p(0x8000); const auto overflow = (((a ^ summ) & (b ^ summ)) ^ summ ^ v128::eq16(b, sign)) & sign; // calculate msb - CPU.VPR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi16(summ.vi, 1)); + ppu.VR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi16(summ.vi, 1)); } -void ppu_interpreter::VAVGSW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAVGSW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va]; - const auto b = v128::add32(CPU.VPR[op.vb], v128::from32p(1)); // add 1 + const auto a = ppu.VR[op.va]; + const auto b = v128::add32(ppu.VR[op.vb], v128::from32p(1)); // add 1 const auto summ = v128::add32(a, b); const auto sign = v128::from32p(0x80000000); const auto overflow = (((a ^ summ) & (b ^ summ)) ^ summ ^ v128::eq32(b, sign)) & sign; // calculate msb - CPU.VPR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi32(summ.vi, 1)); + ppu.VR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi32(summ.vi, 1)); } -void ppu_interpreter::VAVGUB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAVGUB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_avg_epu8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_avg_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VAVGUH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAVGUH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_avg_epu16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_avg_epu16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VAVGUW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAVGUW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va]; - const auto b = CPU.VPR[op.vb]; + const auto a = ppu.VR[op.va]; + const auto b = ppu.VR[op.vb]; const auto summ = v128::add32(v128::add32(a, b), v128::from32p(1)); const auto carry = _mm_xor_si128(_mm_slli_epi32(sse_cmpgt_epu32(summ.vi, a.vi), 31), _mm_set1_epi32(0x80000000)); - CPU.VPR[op.vd].vi = _mm_or_si128(carry, _mm_srli_epi32(summ.vi, 1)); + ppu.VR[op.vd].vi = _mm_or_si128(carry, _mm_srli_epi32(summ.vi, 1)); } -void ppu_interpreter::VCFSX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCFSX(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_mul_ps(_mm_cvtepi32_ps(CPU.VPR[op.vb].vi), g_ppu_scale_table[0 - op.vuimm]); + ppu.VR[op.vd].vf = _mm_mul_ps(_mm_cvtepi32_ps(ppu.VR[op.vb].vi), g_ppu_scale_table[0 - op.vuimm]); } -void ppu_interpreter::VCFUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCFUX(PPUThread& ppu, ppu_opcode_t op) { - const auto b = CPU.VPR[op.vb].vi; + const auto b = ppu.VR[op.vb].vi; const auto fix = _mm_and_ps(_mm_castsi128_ps(_mm_srai_epi32(b, 31)), _mm_set1_ps(0x80000000)); - CPU.VPR[op.vd].vf = _mm_mul_ps(_mm_add_ps(_mm_cvtepi32_ps(_mm_and_si128(b, _mm_set1_epi32(0x7fffffff))), fix), g_ppu_scale_table[0 - op.vuimm]); + ppu.VR[op.vd].vf = _mm_mul_ps(_mm_add_ps(_mm_cvtepi32_ps(_mm_and_si128(b, _mm_set1_epi32(0x7fffffff))), fix), g_ppu_scale_table[0 - op.vuimm]); } -void ppu_interpreter::VCMPBFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPBFP(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vf; - const auto b = CPU.VPR[op.vb].vf; + const auto a = ppu.VR[op.va].vf; + const auto b = ppu.VR[op.vb].vf; const auto sign = _mm_castsi128_ps(_mm_set1_epi32(0x80000000)); - const auto bneg = _mm_xor_ps(b, sign); - CPU.VPR[op.vd].vf = _mm_or_ps(_mm_and_ps(_mm_cmpnle_ps(a, b), sign), _mm_and_ps(_mm_cmpnge_ps(a, bneg), _mm_castsi128_ps(_mm_set1_epi32(0x40000000)))); + const auto cmp1 = _mm_cmpnle_ps(a, b); + const auto cmp2 = _mm_cmpnge_ps(a, _mm_xor_ps(b, sign)); + ppu.VR[op.vd].vf = _mm_or_ps(_mm_and_ps(cmp1, sign), _mm_and_ps(cmp2, _mm_castsi128_ps(_mm_set1_epi32(0x40000000)))); + if (op.oe) ppu.SetCR(6, false, false, _mm_movemask_ps(_mm_or_ps(cmp1, cmp2)) == 0, false); } -void ppu_interpreter::VCMPBFP_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPEQFP(PPUThread& ppu, ppu_opcode_t op) { - VCMPBFP(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? 0 : 2; // set 2 if all in bounds + const auto rmask = _mm_movemask_ps(ppu.VR[op.vd].vf = _mm_cmpeq_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf)); + if (op.oe) ppu.SetCR(6, rmask == 0xf, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPEQUB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_cmpeq_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vb].vf); + const auto rmask = _mm_movemask_epi8((ppu.VR[op.vd] = v128::eq8(ppu.VR[op.va], ppu.VR[op.vb])).vi); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQFP_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPEQUH(PPUThread& ppu, ppu_opcode_t op) { - VCMPEQFP(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; // set 2 if none equal, 8 if all equal + const auto rmask = _mm_movemask_epi8((ppu.VR[op.vd] = v128::eq16(ppu.VR[op.va], ppu.VR[op.vb])).vi); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQUB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPEQUW(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::eq8(CPU.VPR[op.va], CPU.VPR[op.vb]); + const auto rmask = _mm_movemask_epi8((ppu.VR[op.vd] = v128::eq32(ppu.VR[op.va], ppu.VR[op.vb])).vi); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQUB_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGEFP(PPUThread& ppu, ppu_opcode_t op) { - VCMPEQUB(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; // set 2 if none equal, 8 if all equal + const auto rmask = _mm_movemask_ps(ppu.VR[op.vd].vf = _mm_cmpge_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf)); + if (op.oe) ppu.SetCR(6, rmask == 0xf, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQUH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::eq16(CPU.VPR[op.va], CPU.VPR[op.vb]); + const auto rmask = _mm_movemask_ps(ppu.VR[op.vd].vf = _mm_cmpgt_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf)); + if (op.oe) ppu.SetCR(6, rmask == 0xf, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQUH_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTSB(PPUThread& ppu, ppu_opcode_t op) { - VCMPEQUH(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; // set 2 if none equal, 8 if all equal + const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = _mm_cmpgt_epi8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi)); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQUW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTSH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::eq32(CPU.VPR[op.va], CPU.VPR[op.vb]); + const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = _mm_cmpgt_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi)); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQUW_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTSW(PPUThread& ppu, ppu_opcode_t op) { - VCMPEQUW(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; // set 2 if none equal, 8 if all equal + const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = _mm_cmpgt_epi32(ppu.VR[op.va].vi, ppu.VR[op.vb].vi)); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPGEFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTUB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_cmpge_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vb].vf); + const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = sse_cmpgt_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi)); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPGEFP_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTUH(PPUThread& ppu, ppu_opcode_t op) { - VCMPGEFP(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; + const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = sse_cmpgt_epu16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi)); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPGTFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTUW(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_cmpgt_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vb].vf); + const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = sse_cmpgt_epu32(ppu.VR[op.va].vi, ppu.VR[op.vb].vi)); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPGTFP_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCTSXS(PPUThread& ppu, ppu_opcode_t op) { - VCMPGTFP(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; + const auto scaled = _mm_mul_ps(ppu.VR[op.vb].vf, g_ppu_scale_table[op.vuimm]); + ppu.VR[op.vd].vi = _mm_xor_si128(_mm_cvttps_epi32(scaled), _mm_castps_si128(_mm_cmpge_ps(scaled, _mm_set1_ps(0x80000000)))); } -void ppu_interpreter::VCMPGTSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCTUXS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_cmpgt_epi8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); -} - -void ppu_interpreter::VCMPGTSB_(PPUThread& CPU, ppu_opcode_t op) -{ - VCMPGTSB(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; -} - -void ppu_interpreter::VCMPGTSH(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.VPR[op.vd].vi = _mm_cmpgt_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); -} - -void ppu_interpreter::VCMPGTSH_(PPUThread& CPU, ppu_opcode_t op) -{ - VCMPGTSH(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; -} - -void ppu_interpreter::VCMPGTSW(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.VPR[op.vd].vi = _mm_cmpgt_epi32(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); -} - -void ppu_interpreter::VCMPGTSW_(PPUThread& CPU, ppu_opcode_t op) -{ - VCMPGTSW(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; -} - -void ppu_interpreter::VCMPGTUB(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.VPR[op.vd].vi = sse_cmpgt_epu8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); -} - -void ppu_interpreter::VCMPGTUB_(PPUThread& CPU, ppu_opcode_t op) -{ - VCMPGTUB(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; -} - -void ppu_interpreter::VCMPGTUH(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.VPR[op.vd].vi = sse_cmpgt_epu16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); -} - -void ppu_interpreter::VCMPGTUH_(PPUThread& CPU, ppu_opcode_t op) -{ - VCMPGTUH(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; -} - -void ppu_interpreter::VCMPGTUW(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.VPR[op.vd].vi = sse_cmpgt_epu32(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); -} - -void ppu_interpreter::VCMPGTUW_(PPUThread& CPU, ppu_opcode_t op) -{ - VCMPGTUW(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; -} - -void ppu_interpreter::VCTSXS(PPUThread& CPU, ppu_opcode_t op) -{ - const auto scaled = _mm_mul_ps(CPU.VPR[op.vb].vf, g_ppu_scale_table[op.vuimm]); - CPU.VPR[op.vd].vi = _mm_xor_si128(_mm_cvttps_epi32(scaled), _mm_castps_si128(_mm_cmpge_ps(scaled, _mm_set1_ps(0x80000000)))); -} - -void ppu_interpreter::VCTUXS(PPUThread& CPU, ppu_opcode_t op) -{ - const auto scaled1 = _mm_max_ps(_mm_mul_ps(CPU.VPR[op.vb].vf, g_ppu_scale_table[op.vuimm]), _mm_set1_ps(0.0f)); + const auto scaled1 = _mm_max_ps(_mm_mul_ps(ppu.VR[op.vb].vf, g_ppu_scale_table[op.vuimm]), _mm_set1_ps(0.0f)); const auto scaled2 = _mm_and_ps(_mm_sub_ps(scaled1, _mm_set1_ps(0x80000000)), _mm_cmpge_ps(scaled1, _mm_set1_ps(0x80000000))); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_or_si128(_mm_cvttps_epi32(scaled1), _mm_cvttps_epi32(scaled2)), _mm_castps_si128(_mm_cmpge_ps(scaled1, _mm_set1_ps(0x100000000)))); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_or_si128(_mm_cvttps_epi32(scaled1), _mm_cvttps_epi32(scaled2)), _mm_castps_si128(_mm_cmpge_ps(scaled1, _mm_set1_ps(0x100000000)))); } -void ppu_interpreter::VEXPTEFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VEXPTEFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = sse_exp2_ps(CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = sse_exp2_ps(ppu.VR[op.vb].vf); } -void ppu_interpreter::VLOGEFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VLOGEFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = sse_log2_ps(CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = sse_log2_ps(ppu.VR[op.vb].vf); } -void ppu_interpreter::VMADDFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMADDFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_add_ps(_mm_mul_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vc].vf), CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = _mm_add_ps(_mm_mul_ps(ppu.VR[op.va].vf, ppu.VR[op.vc].vf), ppu.VR[op.vb].vf); } -void ppu_interpreter::VMAXFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_max_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = _mm_max_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf); } -void ppu_interpreter::VMAXSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXSB(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto m = _mm_cmpgt_epi8(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b)); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b)); } -void ppu_interpreter::VMAXSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXSH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_max_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_max_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VMAXSW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXSW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto m = _mm_cmpgt_epi32(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b)); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b)); } -void ppu_interpreter::VMAXUB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXUB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_max_epu8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_max_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VMAXUH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXUH(PPUThread& ppu, ppu_opcode_t op) { const auto mask = _mm_set1_epi32(0x80008000); - CPU.VPR[op.vd].vi = _mm_xor_si128(_mm_max_epi16(_mm_xor_si128(CPU.VPR[op.va].vi, mask), _mm_xor_si128(CPU.VPR[op.vb].vi, mask)), mask); + ppu.VR[op.vd].vi = _mm_xor_si128(_mm_max_epi16(_mm_xor_si128(ppu.VR[op.va].vi, mask), _mm_xor_si128(ppu.VR[op.vb].vi, mask)), mask); } -void ppu_interpreter::VMAXUW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXUW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto m = sse_cmpgt_epu32(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b)); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b)); } -void ppu_interpreter::VMHADDSHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMHADDSHS(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; - const auto c = CPU.VPR[op.vc].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; + const auto c = ppu.VR[op.vc].vi; const auto m = _mm_or_si128(_mm_srli_epi16(_mm_mullo_epi16(a, b), 15), _mm_slli_epi16(_mm_mulhi_epi16(a, b), 1)); const auto s = _mm_cmpeq_epi16(m, _mm_set1_epi16(-0x8000)); // detect special case (positive 0x8000) - CPU.VPR[op.vd].vi = _mm_adds_epi16(_mm_adds_epi16(_mm_xor_si128(m, s), c), _mm_srli_epi16(s, 15)); + ppu.VR[op.vd].vi = _mm_adds_epi16(_mm_adds_epi16(_mm_xor_si128(m, s), c), _mm_srli_epi16(s, 15)); } -void ppu_interpreter::VMHRADDSHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMHRADDSHS(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; - const auto c = CPU.VPR[op.vc].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; + const auto c = ppu.VR[op.vc].vi; const auto m = _mm_mulhrs_epi16(a, b); const auto s = _mm_cmpeq_epi16(m, _mm_set1_epi16(-0x8000)); // detect special case (positive 0x8000) - CPU.VPR[op.vd].vi = _mm_adds_epi16(_mm_adds_epi16(_mm_xor_si128(m, s), c), _mm_srli_epi16(s, 15)); + ppu.VR[op.vd].vi = _mm_adds_epi16(_mm_adds_epi16(_mm_xor_si128(m, s), c), _mm_srli_epi16(s, 15)); } -void ppu_interpreter::VMINFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_min_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = _mm_min_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf); } -void ppu_interpreter::VMINSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINSB(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto m = _mm_cmpgt_epi8(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b)); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b)); } -void ppu_interpreter::VMINSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINSH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_min_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_min_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VMINSW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINSW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto m = _mm_cmpgt_epi32(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b)); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b)); } -void ppu_interpreter::VMINUB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINUB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_min_epu8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_min_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VMINUH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINUH(PPUThread& ppu, ppu_opcode_t op) { const auto mask = _mm_set1_epi32(0x80008000); - CPU.VPR[op.vd].vi = _mm_xor_si128(_mm_min_epi16(_mm_xor_si128(CPU.VPR[op.va].vi, mask), _mm_xor_si128(CPU.VPR[op.vb].vi, mask)), mask); + ppu.VR[op.vd].vi = _mm_xor_si128(_mm_min_epi16(_mm_xor_si128(ppu.VR[op.va].vi, mask), _mm_xor_si128(ppu.VR[op.vb].vi, mask)), mask); } -void ppu_interpreter::VMINUW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINUW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto m = sse_cmpgt_epu32(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b)); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b)); } -void ppu_interpreter::VMLADDUHM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMLADDUHM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_add_epi16(_mm_mullo_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi), CPU.VPR[op.vc].vi); + ppu.VR[op.vd].vi = _mm_add_epi16(_mm_mullo_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi), ppu.VR[op.vc].vi); } -void ppu_interpreter::VMRGHB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMRGHB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_unpackhi_epi8(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_unpackhi_epi8(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VMRGHH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMRGHH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_unpackhi_epi16(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_unpackhi_epi16(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VMRGHW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMRGHW(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_unpackhi_epi32(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_unpackhi_epi32(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VMRGLB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMRGLB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_unpacklo_epi8(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_unpacklo_epi8(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VMRGLH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMRGLH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_unpacklo_epi16(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_unpacklo_epi16(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VMRGLW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMRGLW(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_unpacklo_epi32(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_unpacklo_epi32(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VMSUMMBM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMSUMMBM(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; // signed bytes - const auto b = CPU.VPR[op.vb].vi; // unsigned bytes - const auto c = CPU.VPR[op.vc].vi; + const auto a = ppu.VR[op.va].vi; // signed bytes + const auto b = ppu.VR[op.vb].vi; // unsigned bytes + const auto c = ppu.VR[op.vc].vi; const auto ah = _mm_srai_epi16(a, 8); const auto bh = _mm_srli_epi16(b, 8); const auto al = _mm_srai_epi16(_mm_slli_epi16(a, 8), 8); const auto bl = _mm_and_si128(b, _mm_set1_epi16(0x00ff)); const auto sh = _mm_madd_epi16(ah, bh); const auto sl = _mm_madd_epi16(al, bl); - CPU.VPR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, sh), sl); + ppu.VR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, sh), sl); } -void ppu_interpreter::VMSUMSHM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMSUMSHM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_add_epi32(_mm_madd_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi), CPU.VPR[op.vc].vi); + ppu.VR[op.vd].vi = _mm_add_epi32(_mm_madd_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi), ppu.VR[op.vc].vi); } -void ppu_interpreter::VMSUMSHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMSUMSHS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + const auto& c = ppu.VR[op.vc]; + for (uint w = 0; w < 4; w++) { s64 result = 0; @@ -578,10 +523,10 @@ void ppu_interpreter::VMSUMSHS(PPUThread& CPU, ppu_opcode_t op) for (uint h = 0; h < 2; h++) { - result += CPU.VPR[op.va]._s16[w * 2 + h] * CPU.VPR[op.vb]._s16[w * 2 + h]; + result += a._s16[w * 2 + h] * b._s16[w * 2 + h]; } - result += CPU.VPR[op.vc]._s32[w]; + result += c._s32[w]; if (result > 0x7fffffff) { @@ -594,15 +539,15 @@ void ppu_interpreter::VMSUMSHS(PPUThread& CPU, ppu_opcode_t op) else saturated = (s32)result; - CPU.VPR[op.vd]._s32[w] = saturated; + d._s32[w] = saturated; } } -void ppu_interpreter::VMSUMUBM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMSUMUBM(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; - const auto c = CPU.VPR[op.vc].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; + const auto c = ppu.VR[op.vc].vi; const auto mask = _mm_set1_epi16(0x00ff); const auto ah = _mm_srli_epi16(a, 8); const auto al = _mm_and_si128(a, mask); @@ -610,23 +555,28 @@ void ppu_interpreter::VMSUMUBM(PPUThread& CPU, ppu_opcode_t op) const auto bl = _mm_and_si128(b, mask); const auto sh = _mm_madd_epi16(ah, bh); const auto sl = _mm_madd_epi16(al, bl); - CPU.VPR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, sh), sl); + ppu.VR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, sh), sl); } -void ppu_interpreter::VMSUMUHM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMSUMUHM(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; - const auto c = CPU.VPR[op.vc].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; + const auto c = ppu.VR[op.vc].vi; const auto ml = _mm_mullo_epi16(a, b); // low results const auto mh = _mm_mulhi_epu16(a, b); // high results const auto ls = _mm_add_epi32(_mm_srli_epi32(ml, 16), _mm_and_si128(ml, _mm_set1_epi32(0x0000ffff))); const auto hs = _mm_add_epi32(_mm_slli_epi32(mh, 16), _mm_and_si128(mh, _mm_set1_epi32(0xffff0000))); - CPU.VPR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, ls), hs); + ppu.VR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, ls), hs); } -void ppu_interpreter::VMSUMUHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMSUMUHS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + const auto& c = ppu.VR[op.vc]; + for (uint w = 0; w < 4; w++) { u64 result = 0; @@ -634,10 +584,10 @@ void ppu_interpreter::VMSUMUHS(PPUThread& CPU, ppu_opcode_t op) for (uint h = 0; h < 2; h++) { - result += (u64)CPU.VPR[op.va]._u16[w * 2 + h] * (u64)CPU.VPR[op.vb]._u16[w * 2 + h]; + result += (u64)a._u16[w * 2 + h] * (u64)b._u16[w * 2 + h]; } - result += CPU.VPR[op.vc]._u32[w]; + result += c._u32[w]; if (result > 0xffffffffu) { @@ -646,88 +596,89 @@ void ppu_interpreter::VMSUMUHS(PPUThread& CPU, ppu_opcode_t op) else saturated = (u32)result; - CPU.VPR[op.vd]._u32[w] = saturated; + d._u32[w] = saturated; } } -void ppu_interpreter::VMULESB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULESB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_mullo_epi16(_mm_srai_epi16(CPU.VPR[op.va].vi, 8), _mm_srai_epi16(CPU.VPR[op.vb].vi, 8)); + ppu.VR[op.vd].vi = _mm_mullo_epi16(_mm_srai_epi16(ppu.VR[op.va].vi, 8), _mm_srai_epi16(ppu.VR[op.vb].vi, 8)); } -void ppu_interpreter::VMULESH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULESH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_madd_epi16(_mm_srli_epi32(CPU.VPR[op.va].vi, 16), _mm_srli_epi32(CPU.VPR[op.vb].vi, 16)); + ppu.VR[op.vd].vi = _mm_madd_epi16(_mm_srli_epi32(ppu.VR[op.va].vi, 16), _mm_srli_epi32(ppu.VR[op.vb].vi, 16)); } -void ppu_interpreter::VMULEUB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULEUB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_mullo_epi16(_mm_srli_epi16(CPU.VPR[op.va].vi, 8), _mm_srli_epi16(CPU.VPR[op.vb].vi, 8)); + ppu.VR[op.vd].vi = _mm_mullo_epi16(_mm_srli_epi16(ppu.VR[op.va].vi, 8), _mm_srli_epi16(ppu.VR[op.vb].vi, 8)); } -void ppu_interpreter::VMULEUH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULEUH(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto ml = _mm_mullo_epi16(a, b); const auto mh = _mm_mulhi_epu16(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_srli_epi32(ml, 16), _mm_and_si128(mh, _mm_set1_epi32(0xffff0000))); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_srli_epi32(ml, 16), _mm_and_si128(mh, _mm_set1_epi32(0xffff0000))); } -void ppu_interpreter::VMULOSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULOSB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_mullo_epi16(_mm_srai_epi16(_mm_slli_epi16(CPU.VPR[op.va].vi, 8), 8), _mm_srai_epi16(_mm_slli_epi16(CPU.VPR[op.vb].vi, 8), 8)); + ppu.VR[op.vd].vi = _mm_mullo_epi16(_mm_srai_epi16(_mm_slli_epi16(ppu.VR[op.va].vi, 8), 8), _mm_srai_epi16(_mm_slli_epi16(ppu.VR[op.vb].vi, 8), 8)); } -void ppu_interpreter::VMULOSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULOSH(PPUThread& ppu, ppu_opcode_t op) { const auto mask = _mm_set1_epi32(0x0000ffff); - CPU.VPR[op.vd].vi = _mm_madd_epi16(_mm_and_si128(CPU.VPR[op.va].vi, mask), _mm_and_si128(CPU.VPR[op.vb].vi, mask)); + ppu.VR[op.vd].vi = _mm_madd_epi16(_mm_and_si128(ppu.VR[op.va].vi, mask), _mm_and_si128(ppu.VR[op.vb].vi, mask)); } -void ppu_interpreter::VMULOUB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULOUB(PPUThread& ppu, ppu_opcode_t op) { const auto mask = _mm_set1_epi16(0x00ff); - CPU.VPR[op.vd].vi = _mm_mullo_epi16(_mm_and_si128(CPU.VPR[op.va].vi, mask), _mm_and_si128(CPU.VPR[op.vb].vi, mask)); + ppu.VR[op.vd].vi = _mm_mullo_epi16(_mm_and_si128(ppu.VR[op.va].vi, mask), _mm_and_si128(ppu.VR[op.vb].vi, mask)); } -void ppu_interpreter::VMULOUH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULOUH(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto ml = _mm_mullo_epi16(a, b); const auto mh = _mm_mulhi_epu16(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_slli_epi32(mh, 16), _mm_and_si128(ml, _mm_set1_epi32(0x0000ffff))); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_slli_epi32(mh, 16), _mm_and_si128(ml, _mm_set1_epi32(0x0000ffff))); } -void ppu_interpreter::VNMSUBFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VNMSUBFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_sub_ps(CPU.VPR[op.vb].vf, _mm_mul_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vc].vf)); + ppu.VR[op.vd].vf = _mm_sub_ps(ppu.VR[op.vb].vf, _mm_mul_ps(ppu.VR[op.va].vf, ppu.VR[op.vc].vf)); } -void ppu_interpreter::VNOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VNOR(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = ~(CPU.VPR[op.va] | CPU.VPR[op.vb]); + ppu.VR[op.vd] = ~(ppu.VR[op.va] | ppu.VR[op.vb]); } -void ppu_interpreter::VOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VOR(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = CPU.VPR[op.va] | CPU.VPR[op.vb]; + ppu.VR[op.vd] = ppu.VR[op.va] | ppu.VR[op.vb]; } -void ppu_interpreter::VPERM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPERM(PPUThread& ppu, ppu_opcode_t op) { - const auto index = _mm_andnot_si128(CPU.VPR[op.vc].vi, _mm_set1_epi8(0x1f)); + const auto index = _mm_andnot_si128(ppu.VR[op.vc].vi, _mm_set1_epi8(0x1f)); const auto mask = _mm_cmpgt_epi8(index, _mm_set1_epi8(0xf)); - const auto sa = _mm_shuffle_epi8(CPU.VPR[op.va].vi, index); - const auto sb = _mm_shuffle_epi8(CPU.VPR[op.vb].vi, index); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_and_si128(mask, sa), _mm_andnot_si128(mask, sb)); + const auto sa = _mm_shuffle_epi8(ppu.VR[op.va].vi, index); + const auto sb = _mm_shuffle_epi8(ppu.VR[op.vb].vi, index); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_and_si128(mask, sa), _mm_andnot_si128(mask, sb)); } -void ppu_interpreter::VPKPX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKPX(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + v128 VB = ppu.VR[op.vb]; for (uint h = 0; h < 4; h++) { u16 bb7 = VB._u8[15 - (h * 4 + 0)] & 0x1; @@ -739,32 +690,32 @@ void ppu_interpreter::VPKPX(PPUThread& CPU, ppu_opcode_t op) u16 ab16 = VA._u8[15 - (h * 4 + 2)] >> 3; u16 ab24 = VA._u8[15 - (h * 4 + 3)] >> 3; - CPU.VPR[op.vd]._u16[3 - h] = (bb7 << 15) | (bb8 << 10) | (bb16 << 5) | bb24; - CPU.VPR[op.vd]._u16[4 + (3 - h)] = (ab7 << 15) | (ab8 << 10) | (ab16 << 5) | ab24; + d._u16[3 - h] = (bb7 << 15) | (bb8 << 10) | (bb16 << 5) | bb24; + d._u16[4 + (3 - h)] = (ab7 << 15) | (ab8 << 10) | (ab16 << 5) | ab24; } } -void ppu_interpreter::VPKSHSS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKSHSS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_packs_epi16(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_packs_epi16(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VPKSHUS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKSHUS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_packus_epi16(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_packus_epi16(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VPKSWSS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKSWSS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_packs_epi32(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_packs_epi32(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VPKSWUS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKSWUS(PPUThread& ppu, ppu_opcode_t op) { - //CPU.VPR[op.vd].vi = _mm_packus_epi32(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); - - v128 VA = CPU.VPR[op.va]; - v128 VB = CPU.VPR[op.vb]; + //ppu.VR[op.vd].vi = _mm_packus_epi32(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + v128 VB = ppu.VR[op.vb]; for (uint h = 0; h < 4; h++) { s32 result = VA._s32[h]; @@ -778,7 +729,7 @@ void ppu_interpreter::VPKSWUS(PPUThread& CPU, ppu_opcode_t op) result = 0; } - CPU.VPR[op.vd]._u16[h + 4] = result; + d._u16[h + 4] = result; result = VB._s32[h]; @@ -791,25 +742,27 @@ void ppu_interpreter::VPKSWUS(PPUThread& CPU, ppu_opcode_t op) result = 0; } - CPU.VPR[op.vd]._u16[h] = result; + d._u16[h] = result; } } -void ppu_interpreter::VPKUHUM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKUHUM(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + v128 VB = ppu.VR[op.vb]; for (uint b = 0; b < 8; b++) { - CPU.VPR[op.vd]._u8[b + 8] = VA._u8[b * 2]; - CPU.VPR[op.vd]._u8[b] = VB._u8[b * 2]; + d._u8[b + 8] = VA._u8[b * 2]; + d._u8[b] = VB._u8[b * 2]; } } -void ppu_interpreter::VPKUHUS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKUHUS(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + v128 VB = ppu.VR[op.vb]; for (uint b = 0; b < 8; b++) { u16 result = VA._u16[b]; @@ -819,7 +772,7 @@ void ppu_interpreter::VPKUHUS(PPUThread& CPU, ppu_opcode_t op) result = UINT8_MAX; } - CPU.VPR[op.vd]._u8[b + 8] = (u8)result; + d._u8[b + 8] = (u8)result; result = VB._u16[b]; @@ -828,25 +781,27 @@ void ppu_interpreter::VPKUHUS(PPUThread& CPU, ppu_opcode_t op) result = UINT8_MAX; } - CPU.VPR[op.vd]._u8[b] = (u8)result; + d._u8[b] = (u8)result; } } -void ppu_interpreter::VPKUWUM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKUWUM(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + v128 VB = ppu.VR[op.vb]; for (uint h = 0; h < 4; h++) { - CPU.VPR[op.vd]._u16[h + 4] = VA._u16[h * 2]; - CPU.VPR[op.vd]._u16[h] = VB._u16[h * 2]; + d._u16[h + 4] = VA._u16[h * 2]; + d._u16[h] = VB._u16[h * 2]; } } -void ppu_interpreter::VPKUWUS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKUWUS(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + v128 VB = ppu.VR[op.vb]; for (uint h = 0; h < 4; h++) { u32 result = VA._u32[h]; @@ -856,7 +811,7 @@ void ppu_interpreter::VPKUWUS(PPUThread& CPU, ppu_opcode_t op) result = UINT16_MAX; } - CPU.VPR[op.vd]._u16[h + 4] = result; + d._u16[h + 4] = result; result = VB._u32[h]; @@ -865,830 +820,935 @@ void ppu_interpreter::VPKUWUS(PPUThread& CPU, ppu_opcode_t op) result = UINT16_MAX; } - CPU.VPR[op.vd]._u16[h] = result; + d._u16[h] = result; } } -void ppu_interpreter::VREFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VREFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_rcp_ps(CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = _mm_rcp_ps(ppu.VR[op.vb].vf); } -void ppu_interpreter::VRFIM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRFIM(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - const float b = CPU.VPR[op.vb]._f[w]; - CPU.VPR[op.vd]._f[w] = floorf(CPU.VPR[op.vb]._f[w]); + d._f[w] = floorf(b._f[w]); } } -void ppu_interpreter::VRFIN(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRFIN(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - const float b = CPU.VPR[op.vb]._f[w]; - CPU.VPR[op.vd]._f[w] = nearbyintf(CPU.VPR[op.vb]._f[w]); + d._f[w] = nearbyintf(b._f[w]); } } -void ppu_interpreter::VRFIP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRFIP(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - const float b = CPU.VPR[op.vb]._f[w]; - CPU.VPR[op.vd]._f[w] = ceilf(CPU.VPR[op.vb]._f[w]); + d._f[w] = ceilf(b._f[w]); } } -void ppu_interpreter::VRFIZ(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRFIZ(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - const float b = CPU.VPR[op.vb]._f[w]; - CPU.VPR[op.vd]._f[w] = truncf(CPU.VPR[op.vb]._f[w]); + d._f[w] = truncf(b._f[w]); } } -void ppu_interpreter::VRLB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRLB(PPUThread& ppu, ppu_opcode_t op) { - for (uint b = 0; b < 16; b++) + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + + for (uint i = 0; i < 16; i++) { - int nRot = CPU.VPR[op.vb]._u8[b] & 0x7; - - CPU.VPR[op.vd]._u8[b] = (CPU.VPR[op.va]._u8[b] << nRot) | (CPU.VPR[op.va]._u8[b] >> (8 - nRot)); + d._u8[i] = rol8(a._u8[i], b._u8[i] & 0x7); } } -void ppu_interpreter::VRLH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRLH(PPUThread& ppu, ppu_opcode_t op) { - for (uint h = 0; h < 8; h++) + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + + for (uint i = 0; i < 8; i++) { - CPU.VPR[op.vd]._u16[h] = rotl16(CPU.VPR[op.va]._u16[h], CPU.VPR[op.vb]._u8[h * 2] & 0xf); + d._u16[i] = rol16(a._u16[i], b._u8[i * 2] & 0xf); } } -void ppu_interpreter::VRLW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRLW(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._u32[w] = (u32)rotl32(CPU.VPR[op.va]._u32[w], CPU.VPR[op.vb]._u8[w * 4] & 0x1f); + d._u32[w] = rol32(a._u32[w], b._u8[w * 4] & 0x1f); } } -void ppu_interpreter::VRSQRTEFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRSQRTEFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_rsqrt_ps(CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = _mm_rsqrt_ps(ppu.VR[op.vb].vf); } -void ppu_interpreter::VSEL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSEL(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = (CPU.VPR[op.vb] & CPU.VPR[op.vc]) | (CPU.VPR[op.va] & ~CPU.VPR[op.vc]); + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + const auto& c = ppu.VR[op.vc]; + + d = (b & c) | v128::andnot(c, a); } -void ppu_interpreter::VSL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSL(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - u8 sh = CPU.VPR[op.vb]._u8[0] & 0x7; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + u8 sh = ppu.VR[op.vb]._u8[0] & 0x7; - CPU.VPR[op.vd]._u8[0] = VA._u8[0] << sh; + d._u8[0] = VA._u8[0] << sh; for (uint b = 1; b < 16; b++) { - CPU.VPR[op.vd]._u8[b] = (VA._u8[b] << sh) | (VA._u8[b - 1] >> (8 - sh)); + d._u8[b] = (VA._u8[b] << sh) | (VA._u8[b - 1] >> (8 - sh)); } } -void ppu_interpreter::VSLB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSLB(PPUThread& ppu, ppu_opcode_t op) { - for (uint b = 0; b < 16; b++) + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + + for (uint i = 0; i < 16; i++) { - CPU.VPR[op.vd]._u8[b] = CPU.VPR[op.va]._u8[b] << (CPU.VPR[op.vb]._u8[b] & 0x7); + d._u8[i] = a._u8[i] << (b._u8[i] & 0x7); } } -void ppu_interpreter::VSLDOI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSLDOI(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; u8 tmpSRC[32]; - std::memcpy(tmpSRC, CPU.VPR + op.vb, 16); - std::memcpy(tmpSRC + 16, CPU.VPR + op.va, 16); + std::memcpy(tmpSRC, &ppu.VR[op.vb], 16); + std::memcpy(tmpSRC + 16, &ppu.VR[op.va], 16); for (uint b = 0; b<16; b++) { - CPU.VPR[op.vd]._u8[15 - b] = tmpSRC[31 - (b + op.vsh)]; + d._u8[15 - b] = tmpSRC[31 - (b + op.vsh)]; } } -void ppu_interpreter::VSLH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSLH(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._u16[h] = CPU.VPR[op.va]._u16[h] << (CPU.VPR[op.vb]._u16[h] & 0xf); + d._u16[h] = a._u16[h] << (b._u16[h] & 0xf); } } -void ppu_interpreter::VSLO(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSLO(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - u8 nShift = (CPU.VPR[op.vb]._u8[0] >> 3) & 0xf; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + u8 nShift = (ppu.VR[op.vb]._u8[0] >> 3) & 0xf; - CPU.VPR[op.vd].clear(); + d.clear(); for (u8 b = 0; b < 16 - nShift; b++) { - CPU.VPR[op.vd]._u8[15 - b] = VA._u8[15 - (b + nShift)]; + d._u8[15 - b] = VA._u8[15 - (b + nShift)]; } } -void ppu_interpreter::VSLW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSLW(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._u32[w] = CPU.VPR[op.va]._u32[w] << (CPU.VPR[op.vb]._u32[w] & 0x1f); + d._u32[w] = a._u32[w] << (b._u32[w] & 0x1f); } } -void ppu_interpreter::VSPLTB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSPLTB(PPUThread& ppu, ppu_opcode_t op) { - u8 byte = CPU.VPR[op.vb]._u8[15 - op.vuimm]; + auto& d = ppu.VR[op.vd]; + u8 byte = ppu.VR[op.vb]._u8[15 - op.vuimm]; for (uint b = 0; b < 16; b++) { - CPU.VPR[op.vd]._u8[b] = byte; + d._u8[b] = byte; } } -void ppu_interpreter::VSPLTH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSPLTH(PPUThread& ppu, ppu_opcode_t op) { - assert(op.vuimm < 8); + auto& d = ppu.VR[op.vd]; + Expects(op.vuimm < 8); - u16 hword = CPU.VPR[op.vb]._u16[7 - op.vuimm]; + u16 hword = ppu.VR[op.vb]._u16[7 - op.vuimm]; for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._u16[h] = hword; + d._u16[h] = hword; } } -void ppu_interpreter::VSPLTISB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSPLTISB(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const s8 imm = op.vsimm; + for (uint b = 0; b < 16; b++) { - CPU.VPR[op.vd]._u8[b] = op.vsimm; + d._u8[b] = imm; } } -void ppu_interpreter::VSPLTISH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSPLTISH(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const s16 imm = op.vsimm; + for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._u16[h] = (s16)op.vsimm; + d._u16[h] = imm; } } -void ppu_interpreter::VSPLTISW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSPLTISW(PPUThread& ppu, ppu_opcode_t op) { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[op.vd]._u32[w] = (s32)op.vsimm; - } -} - -void ppu_interpreter::VSPLTW(PPUThread& CPU, ppu_opcode_t op) -{ - assert(op.vuimm < 4); - - u32 word = CPU.VPR[op.vb]._u32[3 - op.vuimm]; + auto& d = ppu.VR[op.vd]; + const s32 imm = op.vsimm; for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._u32[w] = word; + d._u32[w] = imm; } } -void ppu_interpreter::VSR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSPLTW(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - u8 sh = CPU.VPR[op.vb]._u8[0] & 0x7; + auto& d = ppu.VR[op.vd]; + Expects(op.vuimm < 4); - CPU.VPR[op.vd]._u8[15] = VA._u8[15] >> sh; + u32 word = ppu.VR[op.vb]._u32[3 - op.vuimm]; + + for (uint w = 0; w < 4; w++) + { + d._u32[w] = word; + } +} + +void ppu_interpreter::VSR(PPUThread& ppu, ppu_opcode_t op) +{ + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + u8 sh = ppu.VR[op.vb]._u8[0] & 0x7; + + d._u8[15] = VA._u8[15] >> sh; for (uint b = 14; ~b; b--) { - CPU.VPR[op.vd]._u8[b] = (VA._u8[b] >> sh) | (VA._u8[b + 1] << (8 - sh)); + d._u8[b] = (VA._u8[b] >> sh) | (VA._u8[b + 1] << (8 - sh)); } } -void ppu_interpreter::VSRAB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRAB(PPUThread& ppu, ppu_opcode_t op) { - for (uint b = 0; b < 16; b++) + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + + for (uint i = 0; i < 16; i++) { - CPU.VPR[op.vd]._s8[b] = CPU.VPR[op.va]._s8[b] >> (CPU.VPR[op.vb]._u8[b] & 0x7); + d._s8[i] = a._s8[i] >> (b._u8[i] & 0x7); } } -void ppu_interpreter::VSRAH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRAH(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._s16[h] = CPU.VPR[op.va]._s16[h] >> (CPU.VPR[op.vb]._u16[h] & 0xf); + d._s16[h] = a._s16[h] >> (b._u16[h] & 0xf); } } -void ppu_interpreter::VSRAW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRAW(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._s32[w] = CPU.VPR[op.va]._s32[w] >> (CPU.VPR[op.vb]._u32[w] & 0x1f); + d._s32[w] = a._s32[w] >> (b._u32[w] & 0x1f); } } -void ppu_interpreter::VSRB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRB(PPUThread& ppu, ppu_opcode_t op) { - for (uint b = 0; b < 16; b++) + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + + for (uint i = 0; i < 16; i++) { - CPU.VPR[op.vd]._u8[b] = CPU.VPR[op.va]._u8[b] >> (CPU.VPR[op.vb]._u8[b] & 0x7); + d._u8[i] = a._u8[i] >> (b._u8[i] & 0x7); } } -void ppu_interpreter::VSRH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRH(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._u16[h] = CPU.VPR[op.va]._u16[h] >> (CPU.VPR[op.vb]._u16[h] & 0xf); + d._u16[h] = a._u16[h] >> (b._u16[h] & 0xf); } } -void ppu_interpreter::VSRO(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRO(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - u8 nShift = (CPU.VPR[op.vb]._u8[0] >> 3) & 0xf; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + u8 nShift = (ppu.VR[op.vb]._u8[0] >> 3) & 0xf; - CPU.VPR[op.vd].clear(); + d.clear(); for (u8 b = 0; b < 16 - nShift; b++) { - CPU.VPR[op.vd]._u8[b] = VA._u8[b + nShift]; + d._u8[b] = VA._u8[b + nShift]; } } -void ppu_interpreter::VSRW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRW(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._u32[w] = CPU.VPR[op.va]._u32[w] >> (CPU.VPR[op.vb]._u32[w] & 0x1f); + d._u32[w] = a._u32[w] >> (b._u32[w] & 0x1f); } } -void ppu_interpreter::VSUBCUW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBCUW(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._u32[w] = CPU.VPR[op.va]._u32[w] < CPU.VPR[op.vb]._u32[w] ? 0 : 1; + d._u32[w] = a._u32[w] < b._u32[w] ? 0 : 1; } } -void ppu_interpreter::VSUBFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::subfs(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::subfs(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VSUBSBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBSBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_subs_epi8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_subs_epi8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VSUBSHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBSHS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_subs_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_subs_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VSUBSWS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBSWS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - s64 result = (s64)CPU.VPR[op.va]._s32[w] - (s64)CPU.VPR[op.vb]._s32[w]; + s64 result = (s64)a._s32[w] - (s64)b._s32[w]; if (result < INT32_MIN) { - CPU.VPR[op.vd]._s32[w] = (s32)INT32_MIN; + d._s32[w] = (s32)INT32_MIN; } else if (result > INT32_MAX) { - CPU.VPR[op.vd]._s32[w] = (s32)INT32_MAX; + d._s32[w] = (s32)INT32_MAX; } else - CPU.VPR[op.vd]._s32[w] = (s32)result; + d._s32[w] = (s32)result; } } -void ppu_interpreter::VSUBUBM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBUBM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::sub8(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::sub8(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VSUBUBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBUBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_subs_epu8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_subs_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VSUBUHM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBUHM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::sub16(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::sub16(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VSUBUHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBUHS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_subs_epu16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_subs_epu16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VSUBUWM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBUWM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::sub32(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::sub32(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VSUBUWS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBUWS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - s64 result = (s64)CPU.VPR[op.va]._u32[w] - (s64)CPU.VPR[op.vb]._u32[w]; + s64 result = (s64)a._u32[w] - (s64)b._u32[w]; if (result < 0) { - CPU.VPR[op.vd]._u32[w] = 0; + d._u32[w] = 0; } else - CPU.VPR[op.vd]._u32[w] = (u32)result; + d._u32[w] = (u32)result; } } -void ppu_interpreter::VSUMSWS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUMSWS(PPUThread& ppu, ppu_opcode_t op) { - s64 sum = CPU.VPR[op.vb]._s32[0]; + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + + s64 sum = b._s32[0]; for (uint w = 0; w < 4; w++) { - sum += CPU.VPR[op.va]._s32[w]; + sum += a._s32[w]; } - CPU.VPR[op.vd].clear(); + d.clear(); if (sum > INT32_MAX) { - CPU.VPR[op.vd]._s32[0] = (s32)INT32_MAX; + d._s32[0] = (s32)INT32_MAX; } else if (sum < INT32_MIN) { - CPU.VPR[op.vd]._s32[0] = (s32)INT32_MIN; + d._s32[0] = (s32)INT32_MIN; } else - CPU.VPR[op.vd]._s32[0] = (s32)sum; + d._s32[0] = (s32)sum; } -void ppu_interpreter::VSUM2SWS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUM2SWS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint n = 0; n < 2; n++) { - s64 sum = (s64)CPU.VPR[op.va]._s32[n * 2] + CPU.VPR[op.va]._s32[n * 2 + 1] + CPU.VPR[op.vb]._s32[n * 2]; + s64 sum = (s64)a._s32[n * 2] + a._s32[n * 2 + 1] + b._s32[n * 2]; if (sum > INT32_MAX) { - CPU.VPR[op.vd]._s32[n * 2] = (s32)INT32_MAX; + d._s32[n * 2] = (s32)INT32_MAX; } else if (sum < INT32_MIN) { - CPU.VPR[op.vd]._s32[n * 2] = (s32)INT32_MIN; + d._s32[n * 2] = (s32)INT32_MIN; } else - CPU.VPR[op.vd]._s32[n * 2] = (s32)sum; + d._s32[n * 2] = (s32)sum; } - CPU.VPR[op.vd]._s32[1] = 0; - CPU.VPR[op.vd]._s32[3] = 0; + d._s32[1] = 0; + d._s32[3] = 0; } -void ppu_interpreter::VSUM4SBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUM4SBS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - s64 sum = CPU.VPR[op.vb]._s32[w]; + s64 sum = b._s32[w]; for (uint b = 0; b < 4; b++) { - sum += CPU.VPR[op.va]._s8[w * 4 + b]; + sum += a._s8[w * 4 + b]; } if (sum > INT32_MAX) { - CPU.VPR[op.vd]._s32[w] = (s32)INT32_MAX; + d._s32[w] = (s32)INT32_MAX; } else if (sum < INT32_MIN) { - CPU.VPR[op.vd]._s32[w] = (s32)INT32_MIN; + d._s32[w] = (s32)INT32_MIN; } else - CPU.VPR[op.vd]._s32[w] = (s32)sum; + d._s32[w] = (s32)sum; } } -void ppu_interpreter::VSUM4SHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUM4SHS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - s64 sum = CPU.VPR[op.vb]._s32[w]; + s64 sum = b._s32[w]; for (uint h = 0; h < 2; h++) { - sum += CPU.VPR[op.va]._s16[w * 2 + h]; + sum += a._s16[w * 2 + h]; } if (sum > INT32_MAX) { - CPU.VPR[op.vd]._s32[w] = (s32)INT32_MAX; + d._s32[w] = (s32)INT32_MAX; } else if (sum < INT32_MIN) { - CPU.VPR[op.vd]._s32[w] = (s32)INT32_MIN; + d._s32[w] = (s32)INT32_MIN; } else - CPU.VPR[op.vd]._s32[w] = (s32)sum; + d._s32[w] = (s32)sum; } } -void ppu_interpreter::VSUM4UBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUM4UBS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - u64 sum = CPU.VPR[op.vb]._u32[w]; + u64 sum = b._u32[w]; for (uint b = 0; b < 4; b++) { - sum += CPU.VPR[op.va]._u8[w * 4 + b]; + sum += a._u8[w * 4 + b]; } if (sum > UINT32_MAX) { - CPU.VPR[op.vd]._u32[w] = (u32)UINT32_MAX; + d._u32[w] = (u32)UINT32_MAX; } else - CPU.VPR[op.vd]._u32[w] = (u32)sum; + d._u32[w] = (u32)sum; } } -void ppu_interpreter::VUPKHPX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VUPKHPX(PPUThread& ppu, ppu_opcode_t op) { - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VB = ppu.VR[op.vb]; for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._s8[w * 4 + 3] = VB._s8[8 + w * 2 + 1] >> 7; // signed shift sign extends - CPU.VPR[op.vd]._u8[w * 4 + 2] = (VB._u8[8 + w * 2 + 1] >> 2) & 0x1f; - CPU.VPR[op.vd]._u8[w * 4 + 1] = ((VB._u8[8 + w * 2 + 1] & 0x3) << 3) | ((VB._u8[8 + w * 2 + 0] >> 5) & 0x7); - CPU.VPR[op.vd]._u8[w * 4 + 0] = VB._u8[8 + w * 2 + 0] & 0x1f; + d._s8[w * 4 + 3] = VB._s8[8 + w * 2 + 1] >> 7; // signed shift sign extends + d._u8[w * 4 + 2] = (VB._u8[8 + w * 2 + 1] >> 2) & 0x1f; + d._u8[w * 4 + 1] = ((VB._u8[8 + w * 2 + 1] & 0x3) << 3) | ((VB._u8[8 + w * 2 + 0] >> 5) & 0x7); + d._u8[w * 4 + 0] = VB._u8[8 + w * 2 + 0] & 0x1f; } } -void ppu_interpreter::VUPKHSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VUPKHSB(PPUThread& ppu, ppu_opcode_t op) { - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VB = ppu.VR[op.vb]; for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._s16[h] = VB._s8[8 + h]; + d._s16[h] = VB._s8[8 + h]; } } -void ppu_interpreter::VUPKHSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VUPKHSH(PPUThread& ppu, ppu_opcode_t op) { - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VB = ppu.VR[op.vb]; for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._s32[w] = VB._s16[4 + w]; + d._s32[w] = VB._s16[4 + w]; } } -void ppu_interpreter::VUPKLPX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VUPKLPX(PPUThread& ppu, ppu_opcode_t op) { - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VB = ppu.VR[op.vb]; for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._s8[w * 4 + 3] = VB._s8[w * 2 + 1] >> 7; // signed shift sign extends - CPU.VPR[op.vd]._u8[w * 4 + 2] = (VB._u8[w * 2 + 1] >> 2) & 0x1f; - CPU.VPR[op.vd]._u8[w * 4 + 1] = ((VB._u8[w * 2 + 1] & 0x3) << 3) | ((VB._u8[w * 2 + 0] >> 5) & 0x7); - CPU.VPR[op.vd]._u8[w * 4 + 0] = VB._u8[w * 2 + 0] & 0x1f; + d._s8[w * 4 + 3] = VB._s8[w * 2 + 1] >> 7; // signed shift sign extends + d._u8[w * 4 + 2] = (VB._u8[w * 2 + 1] >> 2) & 0x1f; + d._u8[w * 4 + 1] = ((VB._u8[w * 2 + 1] & 0x3) << 3) | ((VB._u8[w * 2 + 0] >> 5) & 0x7); + d._u8[w * 4 + 0] = VB._u8[w * 2 + 0] & 0x1f; } } -void ppu_interpreter::VUPKLSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VUPKLSB(PPUThread& ppu, ppu_opcode_t op) { - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VB = ppu.VR[op.vb]; for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._s16[h] = VB._s8[h]; + d._s16[h] = VB._s8[h]; } } -void ppu_interpreter::VUPKLSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VUPKLSH(PPUThread& ppu, ppu_opcode_t op) { - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VB = ppu.VR[op.vb]; for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._s32[w] = VB._s16[w]; + d._s32[w] = VB._s16[w]; } } -void ppu_interpreter::VXOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VXOR(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = CPU.VPR[op.va] ^ CPU.VPR[op.vb]; + ppu.VR[op.vd] = ppu.VR[op.va] ^ ppu.VR[op.vb]; } -void ppu_interpreter::MULLI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULLI(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = (s64)CPU.GPR[op.ra] * op.simm16; + ppu.GPR[op.rd] = (s64)ppu.GPR[op.ra] * op.simm16; } -void ppu_interpreter::SUBFIC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SUBFIC(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 IMM = (s64)op.simm16; - CPU.GPR[op.rd] = ~RA + IMM + 1; - - CPU.XER.CA = CPU.IsCarry(~RA, IMM, 1); + const u64 a = ppu.GPR[op.ra]; + const s64 i = op.simm16; + const auto r = add64_flags(~a, i, 1); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; } -void ppu_interpreter::CMPLI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CMPLI(PPUThread& ppu, ppu_opcode_t op) { - CPU.UpdateCRnU(op.l10, op.crfd, CPU.GPR[op.ra], op.uimm16); + if (op.l10) + { + ppu.SetCR(op.crfd, ppu.GPR[op.ra], op.uimm16); + } + else + { + ppu.SetCR(op.crfd, u32(ppu.GPR[op.ra]), op.uimm16); + } } -void ppu_interpreter::CMPI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CMPI(PPUThread& ppu, ppu_opcode_t op) { - CPU.UpdateCRnS(op.l10, op.crfd, CPU.GPR[op.ra], op.simm16); + if (op.l10) + { + ppu.SetCR(op.crfd, ppu.GPR[op.ra], op.simm16); + } + else + { + ppu.SetCR(op.crfd, u32(ppu.GPR[op.ra]), op.simm16); + } } -void ppu_interpreter::ADDIC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDIC(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = RA + op.simm16; - CPU.XER.CA = CPU.IsCarry(RA, op.simm16); + const s64 a = ppu.GPR[op.ra]; + const s64 i = op.simm16; + const auto r = add64_flags(a, i); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.main & 1) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::ADDIC_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDI(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = RA + op.simm16; - CPU.XER.CA = CPU.IsCarry(RA, op.simm16); - CPU.UpdateCR0(CPU.GPR[op.rd]); + ppu.GPR[op.rd] = op.ra ? ((s64)ppu.GPR[op.ra] + op.simm16) : op.simm16; } -void ppu_interpreter::ADDI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDIS(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = op.ra ? ((s64)CPU.GPR[op.ra] + op.simm16) : op.simm16; + ppu.GPR[op.rd] = op.ra ? ((s64)ppu.GPR[op.ra] + (op.simm16 << 16)) : (op.simm16 << 16); } -void ppu_interpreter::ADDIS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::BC(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = op.ra ? ((s64)CPU.GPR[op.ra] + (op.simm16 << 16)) : (op.simm16 << 16); -} + const bool bo0 = (op.bo & 0x10) != 0; + const bool bo1 = (op.bo & 0x08) != 0; + const bool bo2 = (op.bo & 0x04) != 0; + const bool bo3 = (op.bo & 0x02) != 0; -void ppu_interpreter::BC(PPUThread& CPU, ppu_opcode_t op) -{ - const u8 bo0 = (op.bo & 0x10) ? 1 : 0; - const u8 bo1 = (op.bo & 0x08) ? 1 : 0; - const u8 bo2 = (op.bo & 0x04) ? 1 : 0; - const u8 bo3 = (op.bo & 0x02) ? 1 : 0; + ppu.CTR -= (bo2 ^ true); - if (!bo2) --CPU.CTR; - - const u8 ctr_ok = bo2 | ((CPU.CTR != 0) ^ bo3); - const u8 cond_ok = bo0 | (CPU.IsCR(op.bi) ^ (~bo1 & 0x1)); + const bool ctr_ok = bo2 | ((ppu.CTR != 0) ^ bo3); + const bool cond_ok = bo0 | (ppu.CR[op.bi] ^ (bo1 ^ true)); if (ctr_ok && cond_ok) { - const u32 nextLR = CPU.PC + 4; - CPU.PC = PPUOpcodes::branchTarget((op.aa ? 0 : CPU.PC), op.simm16) - 4; - if (op.lk) CPU.LR = nextLR; + const u32 nextLR = ppu.PC + 4; + ppu.PC = ppu_branch_target((op.aa ? 0 : ppu.PC), op.simm16) - 4; + if (op.lk) ppu.LR = nextLR; } } -void ppu_interpreter::HACK(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::HACK(PPUThread& ppu, ppu_opcode_t op) { - execute_ppu_func_by_index(CPU, op.opcode & 0x3ffffff); + ppu_execute_function(ppu, op.opcode & 0x3ffffff); } -void ppu_interpreter::SC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SC(PPUThread& ppu, ppu_opcode_t op) { - switch (op.lev) + switch (u32 lv = op.lev) { - case 0x0: execute_syscall_by_index(CPU, CPU.GPR[11]); break; - case 0x3: CPU.fast_stop(); break; - default: throw EXCEPTION(""); + case 0x0: ppu_execute_syscall(ppu, ppu.GPR[11]); break; + default: throw fmt::exception("SC lv%u", lv); } } -void ppu_interpreter::B(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::B(PPUThread& ppu, ppu_opcode_t op) { - const u32 nextLR = CPU.PC + 4; - CPU.PC = PPUOpcodes::branchTarget(op.aa ? 0 : CPU.PC, op.ll) - 4; - if (op.lk) CPU.LR = nextLR; + const u32 nextLR = ppu.PC + 4; + ppu.PC = ppu_branch_target(op.aa ? 0 : ppu.PC, op.ll) - 4; + if (op.lk) ppu.LR = nextLR; } -void ppu_interpreter::MCRF(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MCRF(PPUThread& ppu, ppu_opcode_t op) { - CPU.SetCR(op.crfd, CPU.GetCR(op.crfs)); + CHECK_SIZE(PPUThread::CR, 32); + reinterpret_cast(ppu.CR)[op.crfd] = reinterpret_cast(ppu.CR)[op.crfs]; } -void ppu_interpreter::BCLR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::BCLR(PPUThread& ppu, ppu_opcode_t op) { - const u8 bo0 = (op.bo & 0x10) ? 1 : 0; - const u8 bo1 = (op.bo & 0x08) ? 1 : 0; - const u8 bo2 = (op.bo & 0x04) ? 1 : 0; - const u8 bo3 = (op.bo & 0x02) ? 1 : 0; + const bool bo0 = (op.bo & 0x10) != 0; + const bool bo1 = (op.bo & 0x08) != 0; + const bool bo2 = (op.bo & 0x04) != 0; + const bool bo3 = (op.bo & 0x02) != 0; - if (!bo2) --CPU.CTR; + ppu.CTR -= (bo2 ^ true); - const u8 ctr_ok = bo2 | ((CPU.CTR != 0) ^ bo3); - const u8 cond_ok = bo0 | (CPU.IsCR(op.bi) ^ (~bo1 & 0x1)); + const bool ctr_ok = bo2 | ((ppu.CTR != 0) ^ bo3); + const bool cond_ok = bo0 | (ppu.CR[op.bi] ^ (bo1 ^ true)); if (ctr_ok && cond_ok) { - const u32 nextLR = CPU.PC + 4; - CPU.PC = PPUOpcodes::branchTarget(0, (u32)CPU.LR) - 4; - if (op.lk) CPU.LR = nextLR; + const u32 nextLR = ppu.PC + 4; + ppu.PC = ppu_branch_target(0, (u32)ppu.LR) - 4; + if (op.lk) ppu.LR = nextLR; } } -void ppu_interpreter::CRNOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CRNOR(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = 1 ^ (CPU.IsCR(op.crba) | CPU.IsCR(op.crbb)); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = (ppu.CR[op.crba] | ppu.CR[op.crbb]) ^ true; } -void ppu_interpreter::CRANDC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CRANDC(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = CPU.IsCR(op.crba) & (1 ^ CPU.IsCR(op.crbb)); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = ppu.CR[op.crba] & (ppu.CR[op.crbb] ^ true); } -void ppu_interpreter::ISYNC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ISYNC(PPUThread& ppu, ppu_opcode_t op) { _mm_mfence(); } -void ppu_interpreter::CRXOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CRXOR(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = CPU.IsCR(op.crba) ^ CPU.IsCR(op.crbb); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = ppu.CR[op.crba] ^ ppu.CR[op.crbb]; } -void ppu_interpreter::CRNAND(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CRNAND(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = 1 ^ (CPU.IsCR(op.crba) & CPU.IsCR(op.crbb)); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = (ppu.CR[op.crba] & ppu.CR[op.crbb]) ^ true; } -void ppu_interpreter::CRAND(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CRAND(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = CPU.IsCR(op.crba) & CPU.IsCR(op.crbb); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = ppu.CR[op.crba] & ppu.CR[op.crbb]; } -void ppu_interpreter::CREQV(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CREQV(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = 1 ^ (CPU.IsCR(op.crba) ^ CPU.IsCR(op.crbb)); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = (ppu.CR[op.crba] ^ ppu.CR[op.crbb]) ^ true; } -void ppu_interpreter::CRORC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CRORC(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = CPU.IsCR(op.crba) | (1 ^ CPU.IsCR(op.crbb)); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = ppu.CR[op.crba] | (ppu.CR[op.crbb] ^ true); } -void ppu_interpreter::CROR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CROR(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = CPU.IsCR(op.crba) | CPU.IsCR(op.crbb); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = ppu.CR[op.crba] | ppu.CR[op.crbb]; } -void ppu_interpreter::BCCTR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::BCCTR(PPUThread& ppu, ppu_opcode_t op) { - if (op.bo & 0x10 || CPU.IsCR(op.bi) == ((op.bo & 0x8) != 0)) + if (op.bo & 0x10 || ppu.CR[op.bi] == ((op.bo & 0x8) != 0)) { - const u32 nextLR = CPU.PC + 4; - CPU.PC = PPUOpcodes::branchTarget(0, (u32)CPU.CTR) - 4; - if (op.lk) CPU.LR = nextLR; + const u32 nextLR = ppu.PC + 4; + ppu.PC = ppu_branch_target(0, (u32)ppu.CTR) - 4; + if (op.lk) ppu.LR = nextLR; } } -void ppu_interpreter::RLWIMI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLWIMI(PPUThread& ppu, ppu_opcode_t op) { - const u64 mask = rotate_mask[32 + op.mb][32 + op.me]; - CPU.GPR[op.ra] = (CPU.GPR[op.ra] & ~mask) | (rotl32(CPU.GPR[op.rs], op.sh) & mask); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + const u64 mask = ppu_rotate_mask(32 + op.mb32, 32 + op.me32); + ppu.GPR[op.ra] = (ppu.GPR[op.ra] & ~mask) | (dup32(rol32(u32(ppu.GPR[op.rs]), op.sh32)) & mask); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLWINM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLWINM(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = rotl32(CPU.GPR[op.rs], op.sh) & rotate_mask[32 + op.mb][32 + op.me]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = dup32(rol32(u32(ppu.GPR[op.rs]), op.sh32)) & ppu_rotate_mask(32 + op.mb32, 32 + op.me32); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLWNM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLWNM(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = rotl32(CPU.GPR[op.rs], CPU.GPR[op.rb] & 0x1f) & rotate_mask[32 + op.mb][32 + op.me]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = dup32(rol32(u32(ppu.GPR[op.rs]), ppu.GPR[op.rb] & 0x1f)) & ppu_rotate_mask(32 + op.mb32, 32 + op.me32); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::ORI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ORI(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] | op.uimm16; + ppu.GPR[op.ra] = ppu.GPR[op.rs] | op.uimm16; } -void ppu_interpreter::ORIS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ORIS(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] | ((u64)op.uimm16 << 16); + ppu.GPR[op.ra] = ppu.GPR[op.rs] | ((u64)op.uimm16 << 16); } -void ppu_interpreter::XORI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::XORI(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] ^ op.uimm16; + ppu.GPR[op.ra] = ppu.GPR[op.rs] ^ op.uimm16; } -void ppu_interpreter::XORIS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::XORIS(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] ^ ((u64)op.uimm16 << 16); + ppu.GPR[op.ra] = ppu.GPR[op.rs] ^ ((u64)op.uimm16 << 16); } -void ppu_interpreter::ANDI_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ANDI(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] & op.uimm16; - CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = ppu.GPR[op.rs] & op.uimm16; + ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::ANDIS_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ANDIS(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] & ((u64)op.uimm16 << 16); - CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = ppu.GPR[op.rs] & ((u64)op.uimm16 << 16); + ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLDICL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLDICL(PPUThread& ppu, ppu_opcode_t op) { - auto sh = (op.shh << 5) | op.shl; - auto mb = (op.mbmeh << 5) | op.mbmel; - - CPU.GPR[op.ra] = rotl64(CPU.GPR[op.rs], sh) & rotate_mask[mb][63]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], op.sh64) & ppu_rotate_mask(op.mbe64, 63); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLDICR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLDICR(PPUThread& ppu, ppu_opcode_t op) { - auto sh = (op.shh << 5) | op.shl; - auto me = (op.mbmeh << 5) | op.mbmel; - - CPU.GPR[op.ra] = rotl64(CPU.GPR[op.rs], sh) & rotate_mask[0][me]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], op.sh64) & ppu_rotate_mask(0, op.mbe64); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLDIC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLDIC(PPUThread& ppu, ppu_opcode_t op) { - auto sh = (op.shh << 5) | op.shl; - auto mb = (op.mbmeh << 5) | op.mbmel; - - CPU.GPR[op.ra] = rotl64(CPU.GPR[op.rs], sh) & rotate_mask[mb][63 - sh]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], op.sh64) & ppu_rotate_mask(op.mbe64, op.sh64 ^ 63); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLDIMI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLDIMI(PPUThread& ppu, ppu_opcode_t op) { - auto sh = (op.shh << 5) | op.shl; - auto mb = (op.mbmeh << 5) | op.mbmel; - - const u64 mask = rotate_mask[mb][63 - sh]; - CPU.GPR[op.ra] = (CPU.GPR[op.ra] & ~mask) | (rotl64(CPU.GPR[op.rs], sh) & mask); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + const u64 mask = ppu_rotate_mask(op.mbe64, op.sh64 ^ 63); + ppu.GPR[op.ra] = (ppu.GPR[op.ra] & ~mask) | (rol64(ppu.GPR[op.rs], op.sh64) & mask); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLDC_LR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLDCL(PPUThread& ppu, ppu_opcode_t op) { - auto sh = (u32)(CPU.GPR[op.rb] & 0x3F); - auto mbme = (op.mbmeh << 5) | op.mbmel; + ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], ppu.GPR[op.rb] & 0x3f) & ppu_rotate_mask(op.mbe64, 63); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} - if (op.aa) // rldcr +void ppu_interpreter::RLDCR(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], ppu.GPR[op.rb] & 0x3f) & ppu_rotate_mask(0, op.mbe64); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::CMP(PPUThread& ppu, ppu_opcode_t op) +{ + if (op.l10) { - CPU.GPR[op.ra] = rotl64(CPU.GPR[op.rs], sh) & rotate_mask[0][mbme]; + ppu.SetCR(op.crfd, ppu.GPR[op.ra], ppu.GPR[op.rb]); } - else // rldcl + else { - CPU.GPR[op.ra] = rotl64(CPU.GPR[op.rs], sh) & rotate_mask[mbme][63]; + ppu.SetCR(op.crfd, u32(ppu.GPR[op.ra]), u32(ppu.GPR[op.rb])); } - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); } -void ppu_interpreter::CMP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::TW(PPUThread& ppu, ppu_opcode_t op) { - CPU.UpdateCRnS(op.l10, op.crfd, CPU.GPR[op.ra], CPU.GPR[op.rb]); -} - -void ppu_interpreter::TW(PPUThread& CPU, ppu_opcode_t op) -{ - s32 a = (s32)CPU.GPR[op.ra]; - s32 b = (s32)CPU.GPR[op.rb]; + s32 a = (s32)ppu.GPR[op.ra]; + s32 b = (s32)ppu.GPR[op.rb]; if ((a < b && (op.bo & 0x10)) || (a > b && (op.bo & 0x8)) || @@ -1696,13 +1756,13 @@ void ppu_interpreter::TW(PPUThread& CPU, ppu_opcode_t op) ((u32)a < (u32)b && (op.bo & 0x2)) || ((u32)a >(u32)b && (op.bo & 0x1))) { - throw EXCEPTION(""); + throw std::runtime_error("Trap!" HERE); } } -void ppu_interpreter::LVSL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVSL(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; static const u64 lvsl_values[0x10][2] = { @@ -1724,125 +1784,140 @@ void ppu_interpreter::LVSL(PPUThread& CPU, ppu_opcode_t op) { 0x1718191A1B1C1D1E, 0x0F10111213141516 }, }; - CPU.VPR[op.vd]._u64[0] = lvsl_values[addr & 0xf][0]; - CPU.VPR[op.vd]._u64[1] = lvsl_values[addr & 0xf][1]; + ppu.VR[op.vd]._u64[0] = lvsl_values[addr & 0xf][0]; + ppu.VR[op.vd]._u64[1] = lvsl_values[addr & 0xf][1]; } -void ppu_interpreter::LVEBX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVEBX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.VPR[op.vd]._u8[15 - (addr & 0xf)] = vm::read8(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.VR[op.vd]._u8[15 - (addr & 0xf)] = vm::read8(vm::cast(addr, HERE)); } -void ppu_interpreter::SUBFC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SUBFC(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - CPU.GPR[op.rd] = ~RA + RB + 1; - CPU.XER.CA = CPU.IsCarry(~RA, RB, 1); - if (op.oe) CPU.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + const auto r = add64_flags(~RA, RB, 1); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::MULHDU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULHDU(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = UMULH64(CPU.GPR[op.ra], CPU.GPR[op.rb]); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + ppu.GPR[op.rd] = UMULH64(ppu.GPR[op.ra], ppu.GPR[op.rb]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); } -void ppu_interpreter::ADDC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDC(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - CPU.GPR[op.rd] = RA + RB; - CPU.XER.CA = CPU.IsCarry(RA, RB); - if (op.oe) CPU.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + const auto r = add64_flags(RA, RB); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::MULHWU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULHWU(PPUThread& ppu, ppu_opcode_t op) { - u32 a = (u32)CPU.GPR[op.ra]; - u32 b = (u32)CPU.GPR[op.rb]; - CPU.GPR[op.rd] = ((u64)a * (u64)b) >> 32; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + u32 a = (u32)ppu.GPR[op.ra]; + u32 b = (u32)ppu.GPR[op.rb]; + ppu.GPR[op.rd] = ((u64)a * (u64)b) >> 32; + if (op.rc) ppu.SetCR(0, false, false, false, ppu.SO); } -void ppu_interpreter::MFOCRF(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MFOCRF(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = CPU.CR.CR; + if (op.l11) + { + // MFOCRF + const u32 n = cntlz32(op.crm) & 7; + const u32 p = n * 4; + const u32 v = ppu.CR[p + 0] << 3 | ppu.CR[p + 1] << 2 | ppu.CR[p + 2] << 1 | ppu.CR[p + 3] << 0; + + ppu.GPR[op.rd] = v << (p ^ 0x1c); + } + else + { + // MFCR + auto* lanes = reinterpret_cast*>(ppu.CR); + const u32 mh = _mm_movemask_epi8(_mm_slli_epi64(lanes[0].value().vi, 7)); + const u32 ml = _mm_movemask_epi8(_mm_slli_epi64(lanes[1].value().vi, 7)); + + ppu.GPR[op.rd] = (mh << 16) | ml; + } } -void ppu_interpreter::LWARX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWARX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; be_t value; - vm::reservation_acquire(&value, VM_CAST(addr), SIZE_32(value)); + vm::reservation_acquire(&value, vm::cast(addr, HERE), SIZE_32(value)); - CPU.GPR[op.rd] = value; + ppu.GPR[op.rd] = value; } -void ppu_interpreter::LDX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LDX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::read64(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read64(vm::cast(addr, HERE)); } -void ppu_interpreter::LWZX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWZX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::read32(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read32(vm::cast(addr, HERE)); } -void ppu_interpreter::SLW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SLW(PPUThread& ppu, ppu_opcode_t op) { - u32 n = CPU.GPR[op.rb] & 0x1f; - u32 r = (u32)rotl32((u32)CPU.GPR[op.rs], n); - u32 m = ((u32)CPU.GPR[op.rb] & 0x20) ? 0 : (u32)rotate_mask[32][63 - n]; - - CPU.GPR[op.ra] = r & m; - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = u32(ppu.GPR[op.rs] << (ppu.GPR[op.rb] & 0x3f)); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::CNTLZW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CNTLZW(PPUThread& ppu, ppu_opcode_t op) { - u32 i; - for (i = 0; i < 32; i++) + ppu.GPR[op.ra] = cntlz32(u32(ppu.GPR[op.rs])); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::SLD(PPUThread& ppu, ppu_opcode_t op) +{ + u32 n = ppu.GPR[op.rb] & 0x3f; + u64 r = rol64(ppu.GPR[op.rs], n); + u64 m = (ppu.GPR[op.rb] & 0x40) ? 0 : ppu_rotate_mask(0, 63 - n); + + ppu.GPR[op.ra] = r & m; + + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::AND(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.GPR[op.ra] = ppu.GPR[op.rs] & ppu.GPR[op.rb]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::CMPL(PPUThread& ppu, ppu_opcode_t op) +{ + if (op.l10) { - if (CPU.GPR[op.rs] & (1ULL << (31 - i))) break; + ppu.SetCR(op.crfd, ppu.GPR[op.ra], ppu.GPR[op.rb]); + } + else + { + ppu.SetCR(op.crfd, u32(ppu.GPR[op.ra]), u32(ppu.GPR[op.rb])); } - - CPU.GPR[op.ra] = i; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); } -void ppu_interpreter::SLD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVSR(PPUThread& ppu, ppu_opcode_t op) { - u32 n = CPU.GPR[op.rb] & 0x3f; - u64 r = rotl64(CPU.GPR[op.rs], n); - u64 m = (CPU.GPR[op.rb] & 0x40) ? 0 : rotate_mask[0][63 - n]; - - CPU.GPR[op.ra] = r & m; - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); -} - -void ppu_interpreter::AND(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.GPR[op.ra] = CPU.GPR[op.rs] & CPU.GPR[op.rb]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); -} - -void ppu_interpreter::CMPL(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.UpdateCRnU(op.l10, op.crfd, CPU.GPR[op.ra], CPU.GPR[op.rb]); -} - -void ppu_interpreter::LVSR(PPUThread& CPU, ppu_opcode_t op) -{ - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; static const u64 lvsr_values[0x10][2] = { @@ -1864,696 +1939,636 @@ void ppu_interpreter::LVSR(PPUThread& CPU, ppu_opcode_t op) { 0x090A0B0C0D0E0F10, 0x0102030405060708 }, }; - CPU.VPR[op.vd]._u64[0] = lvsr_values[addr & 0xf][0]; - CPU.VPR[op.vd]._u64[1] = lvsr_values[addr & 0xf][1]; + ppu.VR[op.vd]._u64[0] = lvsr_values[addr & 0xf][0]; + ppu.VR[op.vd]._u64[1] = lvsr_values[addr & 0xf][1]; } -void ppu_interpreter::LVEHX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVEHX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~1ULL; - CPU.VPR[op.vd]._u16[7 - ((addr >> 1) & 0x7)] = vm::read16(VM_CAST(addr)); + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~1ULL; + ppu.VR[op.vd]._u16[7 - ((addr >> 1) & 0x7)] = vm::read16(vm::cast(addr, HERE)); } -void ppu_interpreter::SUBF(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SUBF(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - CPU.GPR[op.rd] = RB - RA; - if (op.oe) CPU.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + ppu.GPR[op.rd] = RB - RA; + if (op.oe) ppu.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); } -void ppu_interpreter::LDUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LDUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::read64(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read64(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::DCBST(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DCBST(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::LWZUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWZUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::read32(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read32(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::CNTLZD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CNTLZD(PPUThread& ppu, ppu_opcode_t op) { - u32 i; - for (i = 0; i < 64; i++) + ppu.GPR[op.ra] = cntlz64(ppu.GPR[op.rs]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::ANDC(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.GPR[op.ra] = ppu.GPR[op.rs] & ~ppu.GPR[op.rb]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::TD(PPUThread& ppu, ppu_opcode_t op) +{ + const s64 a = ppu.GPR[op.ra], b = ppu.GPR[op.rb]; + const u64 a_ = a, b_ = b; + + if (((op.bo & 0x10) && a < b) || + ((op.bo & 0x8) && a > b) || + ((op.bo & 0x4) && a == b) || + ((op.bo & 0x2) && a_ < b_) || + ((op.bo & 0x1) && a_ > b_)) { - if (CPU.GPR[op.rs] & (1ULL << (63 - i))) break; + throw std::runtime_error("Trap!" HERE); } - - CPU.GPR[op.ra] = i; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); } -void ppu_interpreter::ANDC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVEWX(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] & ~CPU.GPR[op.rb]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~3ULL; + ppu.VR[op.vd]._u32[3 - ((addr >> 2) & 0x3)] = vm::read32(vm::cast(addr, HERE)); } -void ppu_interpreter::TD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULHD(PPUThread& ppu, ppu_opcode_t op) { - throw EXCEPTION(""); + ppu.GPR[op.rd] = MULH64(ppu.GPR[op.ra], ppu.GPR[op.rb]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); } -void ppu_interpreter::LVEWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULHW(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~3ULL; - CPU.VPR[op.vd]._u32[3 - ((addr >> 2) & 0x3)] = vm::read32(VM_CAST(addr)); + s32 a = (s32)ppu.GPR[op.ra]; + s32 b = (s32)ppu.GPR[op.rb]; + ppu.GPR[op.rd] = ((s64)a * (s64)b) >> 32; + if (op.rc) ppu.SetCR(0, false, false, false, ppu.SO); } -void ppu_interpreter::MULHD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LDARX(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = MULH64(CPU.GPR[op.ra], CPU.GPR[op.rb]); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); -} - -void ppu_interpreter::MULHW(PPUThread& CPU, ppu_opcode_t op) -{ - s32 a = (s32)CPU.GPR[op.ra]; - s32 b = (s32)CPU.GPR[op.rb]; - CPU.GPR[op.rd] = ((s64)a * (s64)b) >> 32; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); -} - -void ppu_interpreter::LDARX(PPUThread& CPU, ppu_opcode_t op) -{ - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; be_t value; - vm::reservation_acquire(&value, VM_CAST(addr), SIZE_32(value)); + vm::reservation_acquire(&value, vm::cast(addr, HERE), SIZE_32(value)); - CPU.GPR[op.rd] = value; + ppu.GPR[op.rd] = value; } -void ppu_interpreter::DCBF(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DCBF(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::LBZX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LBZX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::read8(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read8(vm::cast(addr, HERE)); } -void ppu_interpreter::LVX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~0xfull; - CPU.VPR[op.vd] = vm::_ref(VM_CAST(addr)); + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~0xfull; + ppu.VR[op.vd] = vm::_ref(vm::cast(addr, HERE)); } -void ppu_interpreter::NEG(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::NEG(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = 0 - RA; - if (op.oe) CPU.SetOV((~RA >> 63 == 0) && (~RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + ppu.GPR[op.rd] = 0 - RA; + if (op.oe) ppu.SetOV((~RA >> 63 == 0) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); } -void ppu_interpreter::LBZUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LBZUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::read8(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read8(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::NOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::NOR(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = ~(CPU.GPR[op.rs] | CPU.GPR[op.rb]); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = ~(ppu.GPR[op.rs] | ppu.GPR[op.rb]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::STVEBX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVEBX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u8 eb = addr & 0xf; - vm::write8(VM_CAST(addr), CPU.VPR[op.vs]._u8[15 - eb]); + vm::write8(vm::cast(addr, HERE), ppu.VR[op.vs]._u8[15 - eb]); } -void ppu_interpreter::SUBFE(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SUBFE(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - CPU.GPR[op.rd] = ~RA + RB + CPU.XER.CA; - CPU.XER.CA = CPU.IsCarry(~RA, RB, CPU.XER.CA); - if (op.oe) CPU.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + const auto r = add64_flags(~RA, RB, ppu.CA); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::ADDE(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDE(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - if (CPU.XER.CA) - { - if (RA == ~0ULL) //-1 - { - CPU.GPR[op.rd] = RB; - CPU.XER.CA = 1; - } - else - { - CPU.GPR[op.rd] = RA + 1 + RB; - CPU.XER.CA = CPU.IsCarry(RA + 1, RB); - } - } - else - { - CPU.GPR[op.rd] = RA + RB; - CPU.XER.CA = CPU.IsCarry(RA, RB); - } - if (op.oe) CPU.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + const auto r = add64_flags(RA, RB, ppu.CA); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::MTOCRF(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MTOCRF(PPUThread& ppu, ppu_opcode_t op) { + const u64 s = ppu.GPR[op.rs]; + if (op.l11) { - u32 n = 0, count = 0; - for (u32 i = 0; i<8; ++i) - { - if (op.crm & (1 << i)) - { - n = i; - count++; - } - } + // MTOCRF - if (count == 1) - { - //CR[4*n : 4*n+3] = RS[32+4*n : 32+4*n+3]; - CPU.SetCR(7 - n, (CPU.GPR[op.rs] >> (4 * n)) & 0xf); - } - else - CPU.CR.CR = 0; + const u32 n = cntlz32(op.crm) & 7; + const u32 p = n * 4; + const u64 v = s >> (p ^ 0x1c); + ppu.CR[p + 0] = (v & 8) != 0; + ppu.CR[p + 1] = (v & 4) != 0; + ppu.CR[p + 2] = (v & 2) != 0; + ppu.CR[p + 3] = (v & 1) != 0; } else { - for (u32 i = 0; i<8; ++i) + // MTCRF + + for (u32 i = 0; i < 8; i++) { - if (op.crm & (1 << i)) + const u32 p = i * 4; + const u64 v = s >> (p ^ 0x1c); + + if (op.crm & (128 >> i)) { - CPU.SetCR(7 - i, (CPU.GPR[op.rs] >> (i * 4)) & 0xf); + ppu.CR[p + 0] = (v & 8) != 0; + ppu.CR[p + 1] = (v & 4) != 0; + ppu.CR[p + 2] = (v & 2) != 0; + ppu.CR[p + 3] = (v & 1) != 0; } } } } -void ppu_interpreter::STDX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STDX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::write64(VM_CAST(addr), CPU.GPR[op.rs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::write64(vm::cast(addr, HERE), ppu.GPR[op.rs]); } -void ppu_interpreter::STWCX_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STWCX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; - const be_t value = (u32)CPU.GPR[op.rs]; - CPU.SetCR_EQ(0, vm::reservation_update(VM_CAST(addr), &value, SIZE_32(value))); + const be_t value = (u32)ppu.GPR[op.rs]; + ppu.SetCR(0, false, false, vm::reservation_update(vm::cast(addr, HERE), &value, SIZE_32(value)), ppu.SO); } -void ppu_interpreter::STWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STWX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::write32(VM_CAST(addr), (u32)CPU.GPR[op.rs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[op.rs]); } -void ppu_interpreter::STVEHX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVEHX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~1ULL; + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~1ULL; const u8 eb = (addr & 0xf) >> 1; - vm::write16(VM_CAST(addr), CPU.VPR[op.vs]._u16[7 - eb]); + vm::write16(vm::cast(addr, HERE), ppu.VR[op.vs]._u16[7 - eb]); } -void ppu_interpreter::STDUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STDUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - vm::write64(VM_CAST(addr), CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + vm::write64(vm::cast(addr, HERE), ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STWUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STWUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - vm::write32(VM_CAST(addr), (u32)CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STVEWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVEWX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~3ULL; + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~3ULL; const u8 eb = (addr & 0xf) >> 2; - vm::write32(VM_CAST(addr), CPU.VPR[op.vs]._u32[3 - eb]); + vm::write32(vm::cast(addr, HERE), ppu.VR[op.vs]._u32[3 - eb]); } -void ppu_interpreter::SUBFZE(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SUBFZE(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = ~RA + CPU.XER.CA; - CPU.XER.CA = CPU.IsCarry(~RA, CPU.XER.CA); - if (op.oe) CPU.SetOV((~RA >> 63 == 0) && (~RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const auto r = add64_flags(~RA, 0, ppu.CA); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((~RA >> 63 == 0) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::ADDZE(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDZE(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = RA + CPU.XER.CA; - CPU.XER.CA = CPU.IsCarry(RA, CPU.XER.CA); - if (op.oe) CPU.SetOV((RA >> 63 == 0) && (RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const auto r = add64_flags(RA, 0, ppu.CA); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((RA >> 63 == 0) && (RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::STDCX_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STDCX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; - const be_t value = CPU.GPR[op.rs]; - CPU.SetCR_EQ(0, vm::reservation_update(VM_CAST(addr), &value, SIZE_32(value))); + const be_t value = ppu.GPR[op.rs]; + ppu.SetCR(0, false, false, vm::reservation_update(vm::cast(addr, HERE), &value, SIZE_32(value)), ppu.SO); } -void ppu_interpreter::STBX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STBX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[op.rs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::write8(vm::cast(addr, HERE), (u8)ppu.GPR[op.rs]); } -void ppu_interpreter::STVX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~0xfull; - vm::_ref(VM_CAST(addr)) = CPU.VPR[op.vs]; + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~0xfull; + vm::_ref(vm::cast(addr, HERE)) = ppu.VR[op.vs]; } -void ppu_interpreter::MULLD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULLD(PPUThread& ppu, ppu_opcode_t op) { - const s64 RA = CPU.GPR[op.ra]; - const s64 RB = CPU.GPR[op.rb]; - CPU.GPR[op.rd] = (s64)(RA * RB); + const s64 RA = ppu.GPR[op.ra]; + const s64 RB = ppu.GPR[op.rb]; + ppu.GPR[op.rd] = (s64)(RA * RB); if (op.oe) { const s64 high = MULH64(RA, RB); - CPU.SetOV(high != s64(CPU.GPR[op.rd]) >> 63); + ppu.SetOV(high != s64(ppu.GPR[op.rd]) >> 63); } - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); } -void ppu_interpreter::SUBFME(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SUBFME(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = ~RA + CPU.XER.CA + ~0ULL; - CPU.XER.CA = CPU.IsCarry(~RA, CPU.XER.CA, ~0ULL); - if (op.oe) CPU.SetOV((~RA >> 63 == 1) && (~RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const auto r = add64_flags(~RA, ~0ull, ppu.CA); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((~RA >> 63 == 1) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::ADDME(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDME(PPUThread& ppu, ppu_opcode_t op) { - const s64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = RA + CPU.XER.CA - 1; - CPU.XER.CA |= RA != 0; - - if (op.oe) CPU.SetOV((u64(RA) >> 63 == 1) && (u64(RA) >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const s64 RA = ppu.GPR[op.ra]; + const auto r = add64_flags(RA, ~0ull, ppu.CA); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((u64(RA) >> 63 == 1) && (u64(RA) >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::MULLW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULLW(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = (s64)((s64)(s32)CPU.GPR[op.ra] * (s64)(s32)CPU.GPR[op.rb]); - if (op.oe) CPU.SetOV(s64(CPU.GPR[op.rd]) < s64(-1) << 31 || s64(CPU.GPR[op.rd]) >= s64(1) << 31); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + ppu.GPR[op.rd] = (s64)((s64)(s32)ppu.GPR[op.ra] * (s64)(s32)ppu.GPR[op.rb]); + if (op.oe) ppu.SetOV(s64(ppu.GPR[op.rd]) < s64(-1) << 31 || s64(ppu.GPR[op.rd]) >= s64(1) << 31); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::DCBTST(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DCBTST(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::STBUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STBUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + vm::write8(vm::cast(addr, HERE), (u8)ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::ADD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADD(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - CPU.GPR[op.rd] = RA + RB; - if (op.oe) CPU.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + ppu.GPR[op.rd] = RA + RB; + if (op.oe) ppu.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); } -void ppu_interpreter::DCBT(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DCBT(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::LHZX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHZX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::read16(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read16(vm::cast(addr, HERE)); } -void ppu_interpreter::EQV(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::EQV(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = ~(CPU.GPR[op.rs] ^ CPU.GPR[op.rb]); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = ~(ppu.GPR[op.rs] ^ ppu.GPR[op.rb]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::ECIWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ECIWX(PPUThread& ppu, ppu_opcode_t op) { - throw EXCEPTION(""); + throw std::runtime_error("ECIWX" HERE); } -void ppu_interpreter::LHZUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHZUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::read16(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read16(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::XOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::XOR(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] ^ CPU.GPR[op.rb]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = ppu.GPR[op.rs] ^ ppu.GPR[op.rb]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::MFSPR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MFSPR(PPUThread& ppu, ppu_opcode_t op) { const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); switch (n) { - case 0x001: CPU.GPR[op.rd] = CPU.XER.XER; return; - case 0x008: CPU.GPR[op.rd] = CPU.LR; return; - case 0x009: CPU.GPR[op.rd] = CPU.CTR; return; - case 0x100: CPU.GPR[op.rd] = CPU.VRSAVE; return; - case 0x103: CPU.GPR[op.rd] = CPU.SPRG[3]; return; + case 0x001: ppu.GPR[op.rd] = u32{ ppu.SO } << 31 | ppu.OV << 30 | ppu.CA << 29 | ppu.XCNT; return; + case 0x008: ppu.GPR[op.rd] = ppu.LR; return; + case 0x009: ppu.GPR[op.rd] = ppu.CTR; return; + case 0x100: ppu.GPR[op.rd] = ppu.VRSAVE; return; - case 0x10C: CPU.TB = get_timebased_time(); CPU.GPR[op.rd] = CPU.TB; return; - case 0x10D: CPU.TB = get_timebased_time(); CPU.GPR[op.rd] = CPU.TB >> 32; return; - - case 0x110: - case 0x111: - case 0x112: - case 0x113: - case 0x114: - case 0x115: - case 0x116: - case 0x117: CPU.GPR[op.rd] = CPU.SPRG[n - 0x110]; return; + case 0x10C: ppu.GPR[op.rd] = get_timebased_time() & 0xffffffff; return; + case 0x10D: ppu.GPR[op.rd] = get_timebased_time() >> 32; return; } - throw EXCEPTION(""); + throw fmt::exception("MFSPR 0x%x" HERE, n); } -void ppu_interpreter::LWAX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWAX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = (s64)(s32)vm::read32(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = (s64)(s32)vm::read32(vm::cast(addr, HERE)); } -void ppu_interpreter::DST(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DST(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::LHAX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHAX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = (s64)(s16)vm::read16(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = (s64)(s16)vm::read16(vm::cast(addr, HERE)); } -void ppu_interpreter::LVXL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVXL(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~0xfull; - CPU.VPR[op.vd] = vm::_ref(VM_CAST(addr)); + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~0xfull; + ppu.VR[op.vd] = vm::_ref(vm::cast(addr, HERE)); } -void ppu_interpreter::MFTB(PPUThread& CPU, ppu_opcode_t op) -{ - const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); - - CPU.TB = get_timebased_time(); - switch (n) - { - case 0x10C: CPU.GPR[op.rd] = CPU.TB; break; - case 0x10D: CPU.GPR[op.rd] = CPU.TB >> 32; break; - default: throw EXCEPTION(""); - } -} - -void ppu_interpreter::LWAUX(PPUThread& CPU, ppu_opcode_t op) -{ - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = (s64)(s32)vm::read32(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; -} - -void ppu_interpreter::DSTST(PPUThread& CPU, ppu_opcode_t op) -{ -} - -void ppu_interpreter::LHAUX(PPUThread& CPU, ppu_opcode_t op) -{ - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = (s64)(s16)vm::read16(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; -} - -void ppu_interpreter::STHX(PPUThread& CPU, ppu_opcode_t op) -{ - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::write16(VM_CAST(addr), (u16)CPU.GPR[op.rs]); -} - -void ppu_interpreter::ORC(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.GPR[op.ra] = CPU.GPR[op.rs] | ~CPU.GPR[op.rb]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); -} - -void ppu_interpreter::ECOWX(PPUThread& CPU, ppu_opcode_t op) -{ - throw EXCEPTION(""); -} - -void ppu_interpreter::STHUX(PPUThread& CPU, ppu_opcode_t op) -{ - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - vm::write16(VM_CAST(addr), (u16)CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; -} - -void ppu_interpreter::OR(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.GPR[op.ra] = CPU.GPR[op.rs] | CPU.GPR[op.rb]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); -} - -void ppu_interpreter::DIVDU(PPUThread& CPU, ppu_opcode_t op) -{ - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - - if (RB == 0) - { - if (op.oe) CPU.SetOV(true); - CPU.GPR[op.rd] = 0; - } - else - { - if (op.oe) CPU.SetOV(false); - CPU.GPR[op.rd] = RA / RB; - } - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); -} - -void ppu_interpreter::DIVWU(PPUThread& CPU, ppu_opcode_t op) -{ - const u32 RA = (u32)CPU.GPR[op.ra]; - const u32 RB = (u32)CPU.GPR[op.rb]; - - if (RB == 0) - { - if (op.oe) CPU.SetOV(true); - CPU.GPR[op.rd] = 0; - } - else - { - if (op.oe) CPU.SetOV(false); - CPU.GPR[op.rd] = RA / RB; - } - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); -} - -void ppu_interpreter::MTSPR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MFTB(PPUThread& ppu, ppu_opcode_t op) { const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); switch (n) { - case 0x001: CPU.XER.XER = CPU.GPR[op.rs]; return; - case 0x008: CPU.LR = CPU.GPR[op.rs]; return; - case 0x009: CPU.CTR = CPU.GPR[op.rs]; return; - case 0x100: CPU.VRSAVE = (u32)CPU.GPR[op.rs]; return; - - case 0x110: - case 0x111: - case 0x112: - case 0x113: - case 0x114: - case 0x115: - case 0x116: - case 0x117: CPU.SPRG[n - 0x110] = CPU.GPR[op.rs]; return; + case 0x10C: ppu.GPR[op.rd] = get_timebased_time() & 0xffffffff; break; + case 0x10D: ppu.GPR[op.rd] = get_timebased_time() >> 32; break; + default: throw fmt::exception("MFSPR 0x%x" HERE, n); } - - throw EXCEPTION(""); } -void ppu_interpreter::DCBI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWAUX(PPUThread& ppu, ppu_opcode_t op) +{ + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = (s64)(s32)vm::read32(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; +} + +void ppu_interpreter::DSTST(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::NAND(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHAUX(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = ~(CPU.GPR[op.rs] & CPU.GPR[op.rb]); - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = (s64)(s16)vm::read16(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STVXL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STHX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~0xfull; - vm::_ref(VM_CAST(addr)) = CPU.VPR[op.vs]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::write16(vm::cast(addr, HERE), (u16)ppu.GPR[op.rs]); } -void ppu_interpreter::DIVD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ORC(PPUThread& ppu, ppu_opcode_t op) { - const s64 RA = CPU.GPR[op.ra]; - const s64 RB = CPU.GPR[op.rb]; + ppu.GPR[op.ra] = ppu.GPR[op.rs] | ~ppu.GPR[op.rb]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} - if (RB == 0 || ((u64)RA == (1ULL << 63) && RB == -1)) +void ppu_interpreter::ECOWX(PPUThread& ppu, ppu_opcode_t op) +{ + throw std::runtime_error("ECOWX" HERE); +} + +void ppu_interpreter::STHUX(PPUThread& ppu, ppu_opcode_t op) +{ + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + vm::write16(vm::cast(addr, HERE), (u16)ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; +} + +void ppu_interpreter::OR(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.GPR[op.ra] = ppu.GPR[op.rs] | ppu.GPR[op.rb]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::DIVDU(PPUThread& ppu, ppu_opcode_t op) +{ + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + ppu.GPR[op.rd] = RB == 0 ? 0 : RA / RB; + if (op.oe) ppu.SetOV(RB == 0); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); +} + +void ppu_interpreter::DIVWU(PPUThread& ppu, ppu_opcode_t op) +{ + const u32 RA = (u32)ppu.GPR[op.ra]; + const u32 RB = (u32)ppu.GPR[op.rb]; + ppu.GPR[op.rd] = RB == 0 ? 0 : RA / RB; + if (op.oe) ppu.SetOV(RB == 0); + if (op.rc) ppu.SetCR(0, false, false, false, ppu.SO); +} + +void ppu_interpreter::MTSPR(PPUThread& ppu, ppu_opcode_t op) +{ + const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); + + switch (n) { - if (op.oe) CPU.SetOV(true); - CPU.GPR[op.rd] = /*(((u64)RA & (1ULL << 63)) && RB == 0) ? -1 :*/ 0; - } - else + case 0x001: { - if (op.oe) CPU.SetOV(false); - CPU.GPR[op.rd] = RA / RB; + const u64 value = ppu.GPR[op.rs]; + ppu.SO = (value & 0x80000000) != 0; + ppu.OV = (value & 0x40000000) != 0; + ppu.CA = (value & 0x20000000) != 0; + ppu.XCNT = value & 0x7f; + return; + } + case 0x008: ppu.LR = ppu.GPR[op.rs]; return; + case 0x009: ppu.CTR = ppu.GPR[op.rs]; return; + case 0x100: ppu.VRSAVE = (u32)ppu.GPR[op.rs]; return; } - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + throw fmt::exception("MTSPR 0x%x" HERE, n); } -void ppu_interpreter::DIVW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DCBI(PPUThread& ppu, ppu_opcode_t op) { - const s32 RA = (s32)CPU.GPR[op.ra]; - const s32 RB = (s32)CPU.GPR[op.rb]; - - if (RB == 0 || ((u32)RA == (1 << 31) && RB == -1)) - { - if (op.oe) CPU.SetOV(true); - CPU.GPR[op.rd] = /*(((u32)RA & (1 << 31)) && RB == 0) ? -1 :*/ 0; - } - else - { - if (op.oe) CPU.SetOV(false); - CPU.GPR[op.rd] = (u32)(RA / RB); - } - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); } -void ppu_interpreter::LVLX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::NAND(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + ppu.GPR[op.ra] = ~(ppu.GPR[op.rs] & ppu.GPR[op.rb]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::STVXL(PPUThread& ppu, ppu_opcode_t op) +{ + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~0xfull; + vm::_ref(vm::cast(addr, HERE)) = ppu.VR[op.vs]; +} + +void ppu_interpreter::DIVD(PPUThread& ppu, ppu_opcode_t op) +{ + const s64 RA = ppu.GPR[op.ra]; + const s64 RB = ppu.GPR[op.rb]; + const bool o = RB == 0 || ((u64)RA == (1ULL << 63) && RB == -1); + ppu.GPR[op.rd] = o ? 0 : RA / RB; + if (op.oe) ppu.SetOV(o); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); +} + +void ppu_interpreter::DIVW(PPUThread& ppu, ppu_opcode_t op) +{ + const s32 RA = (s32)ppu.GPR[op.ra]; + const s32 RB = (s32)ppu.GPR[op.rb]; + const bool o = RB == 0 || ((u32)RA == (1 << 31) && RB == -1); + ppu.GPR[op.rd] = o ? 0 : u32(RA / RB); + if (op.oe) ppu.SetOV(o); + if (op.rc) ppu.SetCR(0, false, false, false, ppu.SO); +} + +void ppu_interpreter::LVLX(PPUThread& ppu, ppu_opcode_t op) +{ + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u32 eb = addr & 0xf; - CPU.VPR[op.vd].clear(); - for (u32 i = 0; i < 16u - eb; ++i) CPU.VPR[op.vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i)); + ppu.VR[op.vd].clear(); + for (u32 i = 0; i < 16u - eb; ++i) ppu.VR[op.vd]._u8[15 - i] = vm::read8(vm::cast(addr + i, HERE)); } -void ppu_interpreter::LDBRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LDBRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::_ref>(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::_ref>(vm::cast(addr, HERE)); } -void ppu_interpreter::LSWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LSWX(PPUThread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - u32 count = CPU.XER.XER & 0x7F; + u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + u32 count = ppu.XCNT & 0x7f; for (; count >= 4; count -= 4, addr += 4, op.rd = (op.rd + 1) & 31) { - CPU.GPR[op.rd] = vm::_ref(VM_CAST(addr)); + ppu.GPR[op.rd] = vm::_ref(vm::cast(addr, HERE)); } if (count) { u32 value = 0; for (u32 byte = 0; byte < count; byte++) { - u32 byte_value = vm::_ref(VM_CAST(addr + byte)); + u32 byte_value = vm::_ref(vm::cast(addr + byte, HERE)); value |= byte_value << ((3 ^ byte) * 8); } - CPU.GPR[op.rd] = value; + ppu.GPR[op.rd] = value; } } -void ppu_interpreter::LWBRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWBRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::_ref>(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::_ref>(vm::cast(addr, HERE)); } -void ppu_interpreter::LFSX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFSX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); } -void ppu_interpreter::SRW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SRW(PPUThread& ppu, ppu_opcode_t op) { - u32 n = CPU.GPR[op.rb] & 0x1f; - u32 r = (u32)rotl32((u32)CPU.GPR[op.rs], 64 - n); - u32 m = ((u32)CPU.GPR[op.rb] & 0x20) ? 0 : (u32)rotate_mask[32 + n][63]; - CPU.GPR[op.ra] = r & m; - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = (ppu.GPR[op.rs] & 0xffffffff) >> (ppu.GPR[op.rb] & 0x3f); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::SRD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SRD(PPUThread& ppu, ppu_opcode_t op) { - u32 n = CPU.GPR[op.rb] & 0x3f; - u64 r = rotl64(CPU.GPR[op.rs], 64 - n); - u64 m = (CPU.GPR[op.rb] & 0x40) ? 0 : rotate_mask[n][63]; - CPU.GPR[op.ra] = r & m; + u32 n = ppu.GPR[op.rb] & 0x3f; + u64 r = rol64(ppu.GPR[op.rs], 64 - n); + u64 m = (ppu.GPR[op.rb] & 0x40) ? 0 : ppu_rotate_mask(n, 63); + ppu.GPR[op.ra] = r & m; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::LVRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u8 eb = addr & 0xf; - CPU.VPR[op.vd].clear(); - for (u32 i = 16 - eb; i < 16; ++i) CPU.VPR[op.vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i - 16)); + ppu.VR[op.vd].clear(); + for (u32 i = 16 - eb; i < 16; ++i) ppu.VR[op.vd]._u8[15 - i] = vm::read8(vm::cast(addr + i - 16, HERE)); } -void ppu_interpreter::LSWI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LSWI(PPUThread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? CPU.GPR[op.ra] : 0; + u64 addr = op.ra ? ppu.GPR[op.ra] : 0; u64 N = op.rb ? op.rb : 32; u8 reg = op.rd; @@ -2561,7 +2576,7 @@ void ppu_interpreter::LSWI(PPUThread& CPU, ppu_opcode_t op) { if (N > 3) { - CPU.GPR[reg] = vm::read32(VM_CAST(addr)); + ppu.GPR[reg] = vm::read32(vm::cast(addr, HERE)); addr += 4; N -= 4; } @@ -2572,104 +2587,104 @@ void ppu_interpreter::LSWI(PPUThread& CPU, ppu_opcode_t op) while (N > 0) { N = N - 1; - buf |= vm::read8(VM_CAST(addr)) << (i * 8); + buf |= vm::read8(vm::cast(addr, HERE)) << (i * 8); addr++; i--; } - CPU.GPR[reg] = buf; + ppu.GPR[reg] = buf; } reg = (reg + 1) % 32; } } -void ppu_interpreter::LFSUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFSUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::SYNC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SYNC(PPUThread& ppu, ppu_opcode_t op) { _mm_mfence(); } -void ppu_interpreter::LFDX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFDX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); } -void ppu_interpreter::LFDUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFDUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STVLX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVLX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u32 eb = addr & 0xf; - for (u32 i = 0; i < 16u - eb; ++i) vm::write8(VM_CAST(addr + i), CPU.VPR[op.vs]._u8[15 - i]); + for (u32 i = 0; i < 16u - eb; ++i) vm::write8(vm::cast(addr + i, HERE), ppu.VR[op.vs]._u8[15 - i]); } -void ppu_interpreter::STDBRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STDBRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::_ref>(VM_CAST(addr)) = CPU.GPR[op.rs]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::_ref>(vm::cast(addr, HERE)) = ppu.GPR[op.rs]; } -void ppu_interpreter::STSWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STSWX(PPUThread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - u32 count = CPU.XER.XER & 0x7F; + u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + u32 count = ppu.XCNT & 0x7F; for (; count >= 4; count -= 4, addr += 4, op.rs = (op.rs + 1) & 31) { - vm::write32(VM_CAST(addr), (u32)CPU.GPR[op.rs]); + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[op.rs]); } if (count) { - u32 value = (u32)CPU.GPR[op.rs]; + u32 value = (u32)ppu.GPR[op.rs]; for (u32 byte = 0; byte < count; byte++) { u32 byte_value = (u8)(value >> ((3 ^ byte) * 8)); - vm::write8(VM_CAST(addr + byte), byte_value); + vm::write8(vm::cast(addr + byte, HERE), byte_value); } } } -void ppu_interpreter::STWBRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STWBRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::_ref>(VM_CAST(addr)) = (u32)CPU.GPR[op.rs]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::_ref>(vm::cast(addr, HERE)) = (u32)ppu.GPR[op.rs]; } -void ppu_interpreter::STFSX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFSX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::_ref(VM_CAST(addr)) = static_cast(CPU.FPR[op.frs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::_ref(vm::cast(addr, HERE)) = static_cast(ppu.FPR[op.frs]); } -void ppu_interpreter::STVRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u8 eb = addr & 0xf; - for (u32 i = 16 - eb; i < 16; ++i) vm::write8(VM_CAST(addr + i - 16), CPU.VPR[op.vs]._u8[15 - i]); + for (u32 i = 16 - eb; i < 16; ++i) vm::write8(vm::cast(addr + i - 16, HERE), ppu.VR[op.vs]._u8[15 - i]); } -void ppu_interpreter::STFSUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFSUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - vm::_ref(VM_CAST(addr)) = static_cast(CPU.FPR[op.frs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + vm::_ref(vm::cast(addr, HERE)) = static_cast(ppu.FPR[op.frs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STSWI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STSWI(PPUThread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? CPU.GPR[op.ra] : 0; + u64 addr = op.ra ? ppu.GPR[op.ra] : 0; u64 N = op.rb ? op.rb : 32; u8 reg = op.rd; @@ -2677,17 +2692,17 @@ void ppu_interpreter::STSWI(PPUThread& CPU, ppu_opcode_t op) { if (N > 3) { - vm::write32(VM_CAST(addr), (u32)CPU.GPR[reg]); + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[reg]); addr += 4; N -= 4; } else { - u32 buf = (u32)CPU.GPR[reg]; + u32 buf = (u32)ppu.GPR[reg]; while (N > 0) { N = N - 1; - vm::write8(VM_CAST(addr), (0xFF000000 & buf) >> 24); + vm::write8(vm::cast(addr, HERE), (0xFF000000 & buf) >> 24); buf <<= 8; addr++; } @@ -2696,631 +2711,598 @@ void ppu_interpreter::STSWI(PPUThread& CPU, ppu_opcode_t op) } } -void ppu_interpreter::STFDX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFDX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::_ref(VM_CAST(addr)) = CPU.FPR[op.frs]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::_ref(vm::cast(addr, HERE)) = ppu.FPR[op.frs]; } -void ppu_interpreter::STFDUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFDUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - vm::_ref(VM_CAST(addr)) = CPU.FPR[op.frs]; - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + vm::_ref(vm::cast(addr, HERE)) = ppu.FPR[op.frs]; + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LVLXL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVLXL(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u32 eb = addr & 0xf; - CPU.VPR[op.vd].clear(); - for (u32 i = 0; i < 16u - eb; ++i) CPU.VPR[op.vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i)); + ppu.VR[op.vd].clear(); + for (u32 i = 0; i < 16u - eb; ++i) ppu.VR[op.vd]._u8[15 - i] = vm::read8(vm::cast(addr + i, HERE)); } -void ppu_interpreter::LHBRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHBRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::_ref>(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::_ref>(vm::cast(addr, HERE)); } -void ppu_interpreter::SRAW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SRAW(PPUThread& ppu, ppu_opcode_t op) { - s32 RS = (s32)CPU.GPR[op.rs]; - u8 shift = CPU.GPR[op.rb] & 63; + s32 RS = (s32)ppu.GPR[op.rs]; + u8 shift = ppu.GPR[op.rb] & 63; if (shift > 31) { - CPU.GPR[op.ra] = 0 - (RS < 0); - CPU.XER.CA = (RS < 0); + ppu.GPR[op.ra] = 0 - (RS < 0); + ppu.CA = (RS < 0); } else { - CPU.GPR[op.ra] = RS >> shift; - CPU.XER.CA = (RS < 0) & ((CPU.GPR[op.ra] << shift) != RS); + ppu.GPR[op.ra] = RS >> shift; + ppu.CA = (RS < 0) && ((ppu.GPR[op.ra] << shift) != RS); } - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::SRAD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SRAD(PPUThread& ppu, ppu_opcode_t op) { - s64 RS = CPU.GPR[op.rs]; - u8 shift = CPU.GPR[op.rb] & 127; + s64 RS = ppu.GPR[op.rs]; + u8 shift = ppu.GPR[op.rb] & 127; if (shift > 63) { - CPU.GPR[op.ra] = 0 - (RS < 0); - CPU.XER.CA = (RS < 0); + ppu.GPR[op.ra] = 0 - (RS < 0); + ppu.CA = (RS < 0); } else { - CPU.GPR[op.ra] = RS >> shift; - CPU.XER.CA = (RS < 0) & ((CPU.GPR[op.ra] << shift) != RS); + ppu.GPR[op.ra] = RS >> shift; + ppu.CA = (RS < 0) && ((ppu.GPR[op.ra] << shift) != RS); } - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::LVRXL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVRXL(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u8 eb = addr & 0xf; - CPU.VPR[op.vd].clear(); - for (u32 i = 16 - eb; i < 16; ++i) CPU.VPR[op.vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i - 16)); + ppu.VR[op.vd].clear(); + for (u32 i = 16 - eb; i < 16; ++i) ppu.VR[op.vd]._u8[15 - i] = vm::read8(vm::cast(addr + i - 16, HERE)); } -void ppu_interpreter::DSS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DSS(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::SRAWI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SRAWI(PPUThread& ppu, ppu_opcode_t op) { - s32 RS = (u32)CPU.GPR[op.rs]; - CPU.GPR[op.ra] = RS >> op.sh; - CPU.XER.CA = (RS < 0) & ((u32)(CPU.GPR[op.ra] << op.sh) != RS); + s32 RS = (u32)ppu.GPR[op.rs]; + ppu.GPR[op.ra] = RS >> op.sh32; + ppu.CA = (RS < 0) && ((u32)(ppu.GPR[op.ra] << op.sh32) != RS); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::SRADI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SRADI(PPUThread& ppu, ppu_opcode_t op) { - auto sh = (op.shh << 5) | op.shl; - s64 RS = CPU.GPR[op.rs]; - CPU.GPR[op.ra] = RS >> sh; - CPU.XER.CA = (RS < 0) & ((CPU.GPR[op.ra] << sh) != RS); + auto sh = op.sh64; + s64 RS = ppu.GPR[op.rs]; + ppu.GPR[op.ra] = RS >> sh; + ppu.CA = (RS < 0) && ((ppu.GPR[op.ra] << sh) != RS); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::EIEIO(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::EIEIO(PPUThread& ppu, ppu_opcode_t op) { _mm_mfence(); } -void ppu_interpreter::STVLXL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVLXL(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u32 eb = addr & 0xf; - for (u32 i = 0; i < 16u - eb; ++i) vm::write8(VM_CAST(addr + i), CPU.VPR[op.vs]._u8[15 - i]); + for (u32 i = 0; i < 16u - eb; ++i) vm::write8(vm::cast(addr + i, HERE), ppu.VR[op.vs]._u8[15 - i]); } -void ppu_interpreter::STHBRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STHBRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::_ref>(VM_CAST(addr)) = (u16)CPU.GPR[op.rs]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::_ref>(vm::cast(addr, HERE)) = (u16)ppu.GPR[op.rs]; } -void ppu_interpreter::EXTSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::EXTSH(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = (s64)(s16)CPU.GPR[op.rs]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = (s64)(s16)ppu.GPR[op.rs]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::STVRXL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVRXL(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u8 eb = addr & 0xf; - for (u32 i = 16 - eb; i < 16; ++i) vm::write8(VM_CAST(addr + i - 16), CPU.VPR[op.vs]._u8[15 - i]); + for (u32 i = 16 - eb; i < 16; ++i) vm::write8(vm::cast(addr + i - 16, HERE), ppu.VR[op.vs]._u8[15 - i]); } -void ppu_interpreter::EXTSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::EXTSB(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = (s64)(s8)CPU.GPR[op.rs]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = (s64)(s8)ppu.GPR[op.rs]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::STFIWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFIWX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::write32(VM_CAST(addr), (u32&)CPU.FPR[op.frs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::write32(vm::cast(addr, HERE), (u32&)ppu.FPR[op.frs]); } -void ppu_interpreter::EXTSW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::EXTSW(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = (s64)(s32)CPU.GPR[op.rs]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = (s64)(s32)ppu.GPR[op.rs]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::ICBI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ICBI(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::DCBZ(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DCBZ(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; - std::memset(vm::base(VM_CAST(addr) & ~127), 0, 128); + std::memset(vm::base(vm::cast(addr, HERE) & ~127), 0, 128); } -void ppu_interpreter::LWZ(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWZ(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - CPU.GPR[op.rd] = vm::read32(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + ppu.GPR[op.rd] = vm::read32(vm::cast(addr, HERE)); } -void ppu_interpreter::LWZU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWZU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - CPU.GPR[op.rd] = vm::read32(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + ppu.GPR[op.rd] = vm::read32(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LBZ(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LBZ(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - CPU.GPR[op.rd] = vm::read8(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + ppu.GPR[op.rd] = vm::read8(vm::cast(addr, HERE)); } -void ppu_interpreter::LBZU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LBZU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - CPU.GPR[op.rd] = vm::read8(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + ppu.GPR[op.rd] = vm::read8(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STW(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - vm::write32(VM_CAST(addr), (u32)CPU.GPR[op.rs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[op.rs]); } -void ppu_interpreter::STWU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STWU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - vm::write32(VM_CAST(addr), (u32)CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STB(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[op.rs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + vm::write8(vm::cast(addr, HERE), (u8)ppu.GPR[op.rs]); } -void ppu_interpreter::STBU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STBU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + vm::write8(vm::cast(addr, HERE), (u8)ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LHZ(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHZ(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - CPU.GPR[op.rd] = vm::read16(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + ppu.GPR[op.rd] = vm::read16(vm::cast(addr, HERE)); } -void ppu_interpreter::LHZU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHZU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - CPU.GPR[op.rd] = vm::read16(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + ppu.GPR[op.rd] = vm::read16(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LHA(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHA(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - CPU.GPR[op.rd] = (s64)(s16)vm::read16(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + ppu.GPR[op.rd] = (s64)(s16)vm::read16(vm::cast(addr, HERE)); } -void ppu_interpreter::LHAU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHAU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - CPU.GPR[op.rd] = (s64)(s16)vm::read16(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + ppu.GPR[op.rd] = (s64)(s16)vm::read16(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STH(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - vm::write16(VM_CAST(addr), (u16)CPU.GPR[op.rs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + vm::write16(vm::cast(addr, HERE), (u16)ppu.GPR[op.rs]); } -void ppu_interpreter::STHU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STHU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - vm::write16(VM_CAST(addr), (u16)CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + vm::write16(vm::cast(addr, HERE), (u16)ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LMW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LMW(PPUThread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; + u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; for (u32 i = op.rd; i<32; ++i, addr += 4) { - CPU.GPR[i] = vm::read32(VM_CAST(addr)); + ppu.GPR[i] = vm::read32(vm::cast(addr, HERE)); } } -void ppu_interpreter::STMW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STMW(PPUThread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; + u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; for (u32 i = op.rs; i<32; ++i, addr += 4) { - vm::write32(VM_CAST(addr), (u32)CPU.GPR[i]); + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[i]); } } -void ppu_interpreter::LFS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFS(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); } -void ppu_interpreter::LFSU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFSU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LFD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFD(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); } -void ppu_interpreter::LFDU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFDU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STFS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFS(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - vm::_ref(VM_CAST(addr)) = static_cast(CPU.FPR[op.frs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + vm::_ref(vm::cast(addr, HERE)) = static_cast(ppu.FPR[op.frs]); } -void ppu_interpreter::STFSU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFSU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - vm::_ref(VM_CAST(addr)) = static_cast(CPU.FPR[op.frs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + vm::_ref(vm::cast(addr, HERE)) = static_cast(ppu.FPR[op.frs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STFD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFD(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - vm::_ref(VM_CAST(addr)) = CPU.FPR[op.frs]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + vm::_ref(vm::cast(addr, HERE)) = ppu.FPR[op.frs]; } -void ppu_interpreter::STFDU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFDU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - vm::_ref(VM_CAST(addr)) = CPU.FPR[op.frs]; - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + vm::_ref(vm::cast(addr, HERE)) = ppu.FPR[op.frs]; + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LD(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.simm16 & ~3) + (op.ra ? CPU.GPR[op.ra] : 0); - CPU.GPR[op.rd] = vm::read64(VM_CAST(addr)); + const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.GPR[op.ra] : 0); + ppu.GPR[op.rd] = vm::read64(vm::cast(addr, HERE)); } -void ppu_interpreter::LDU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LDU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + (op.simm16 & ~3); - CPU.GPR[op.rd] = vm::read64(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + (op.simm16 & ~3); + ppu.GPR[op.rd] = vm::read64(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LWA(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWA(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.simm16 & ~3) + (op.ra ? CPU.GPR[op.ra] : 0); - CPU.GPR[op.rd] = (s64)(s32)vm::read32(VM_CAST(addr)); + const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.GPR[op.ra] : 0); + ppu.GPR[op.rd] = (s64)(s32)vm::read32(vm::cast(addr, HERE)); } -void ppu_interpreter::FDIVS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FDIVS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] / CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] / ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FSUBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FSUBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] - CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] - ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FADDS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FADDS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] + CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] + ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FSQRTS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FSQRTS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = sqrt(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(sqrt(ppu.FPR[op.frb])); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FRES(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FRES(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = 1.0 / CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(1.0 / ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FMULS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FMULS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] * CPU.FPR[op.frc]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] * ppu.FPR[op.frc]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FMADDS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FMADDS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] * CPU.FPR[op.frc] + CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] * ppu.FPR[op.frc] + ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FMSUBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FMSUBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] * CPU.FPR[op.frc] - CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] * ppu.FPR[op.frc] - ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FNMSUBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FNMSUBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = -(CPU.FPR[op.fra] * CPU.FPR[op.frc]) + CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(-(ppu.FPR[op.fra] * ppu.FPR[op.frc]) + ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FNMADDS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FNMADDS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = -(CPU.FPR[op.fra] * CPU.FPR[op.frc]) - CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(-(ppu.FPR[op.fra] * ppu.FPR[op.frc]) - ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::STD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STD(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.simm16 & ~3) + (op.ra ? CPU.GPR[op.ra] : 0); - vm::write64(VM_CAST(addr), CPU.GPR[op.rs]); + const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.GPR[op.ra] : 0); + vm::write64(vm::cast(addr, HERE), ppu.GPR[op.rs]); } -void ppu_interpreter::STDU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STDU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + (op.simm16 & ~3); - vm::write64(VM_CAST(addr), CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + (op.simm16 & ~3); + vm::write64(vm::cast(addr, HERE), ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::MTFSB1(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MTFSB1(PPUThread& ppu, ppu_opcode_t op) { - u32 mask = 1 << (31 - op.crbd); - if ((op.crbd >= 3 && op.crbd <= 6) && !(CPU.FPSCR.FPSCR & mask)) mask |= 1ULL << 31; //FPSCR.FX - if ((op.crbd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode enabled"); - CPU.SetFPSCR(CPU.FPSCR.FPSCR | mask); - - if (op.rc) CPU.UpdateCR1(); + LOG_WARNING(PPU, "MTFSB1"); + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::MCRFS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MCRFS(PPUThread& ppu, ppu_opcode_t op) { - CPU.SetCR(op.crfd, (CPU.FPSCR.FPSCR >> ((7 - op.crfs) * 4)) & 0xf); - const u32 exceptions_mask = 0x9FF80700; - CPU.SetFPSCR(CPU.FPSCR.FPSCR & ~(exceptions_mask & 0xf << ((7 - op.crfs) * 4))); + LOG_WARNING(PPU, "MCRFS"); + ppu.SetCR(op.crfd, false, false, false, false); } -void ppu_interpreter::MTFSB0(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MTFSB0(PPUThread& ppu, ppu_opcode_t op) { - u32 mask = 1 << (31 - op.crbd); - if ((op.crbd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode disabled"); - CPU.SetFPSCR(CPU.FPSCR.FPSCR & ~mask); - - if (op.rc) CPU.UpdateCR1(); + LOG_WARNING(PPU, "MTFSB0"); + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::MTFSFI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MTFSFI(PPUThread& ppu, ppu_opcode_t op) { - u32 mask = 0xF0000000 >> (op.crfd * 4); - u32 val = (op.i & 0xF) << ((7 - op.crfd) * 4); - - const u32 oldNI = CPU.FPSCR.NI; - CPU.SetFPSCR((CPU.FPSCR.FPSCR & ~mask) | val); - if (CPU.FPSCR.NI != oldNI) - { - if (oldNI) - LOG_WARNING(PPU, "Non-IEEE mode disabled"); - else - LOG_WARNING(PPU, "Non-IEEE mode enabled"); - } - - if (op.rc) CPU.UpdateCR1(); + LOG_WARNING(PPU, "MTFSFI"); + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::MFFS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MFFS(PPUThread& ppu, ppu_opcode_t op) { - (u64&)CPU.FPR[op.frd]._double = CPU.FPSCR.FPSCR; - if (op.rc) CPU.UpdateCR1(); + LOG_WARNING(PPU, "MFFS"); + ppu.FPR[op.frd] = 0.0; + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::MTFSF(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MTFSF(PPUThread& ppu, ppu_opcode_t op) { - u32 mask = 0; - for (u32 i = 0; i<8; ++i) - { - if (op.flm & (1 << i)) mask |= 0xf << (i * 4); - } - mask &= ~0x60000000; + LOG_WARNING(PPU, "MTFSF"); + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} - const u32 oldNI = CPU.FPSCR.NI; - CPU.SetFPSCR((CPU.FPSCR.FPSCR & ~mask) | ((u32&)CPU.FPR[op.frb] & mask)); - if (CPU.FPSCR.NI != oldNI) - { - if (oldNI) - LOG_WARNING(PPU, "Non-IEEE mode disabled"); - else - LOG_WARNING(PPU, "Non-IEEE mode enabled"); - } - if (op.rc) CPU.UpdateCR1(); +void ppu_interpreter::FCMPU(PPUThread& ppu, ppu_opcode_t op) +{ + const f64 a = ppu.FPR[op.fra]; + const f64 b = ppu.FPR[op.frb]; + ppu.FG = a > b; + ppu.FL = a < b; + ppu.FE = a == b; + //ppu.FU = a != a || b != b; + ppu.SetCR(op.crfd, ppu.FL, ppu.FG, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FRSP(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = f32(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FCTIW(PPUThread& ppu, ppu_opcode_t op) +{ + (s32&)ppu.FPR[op.frd] = lrint(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FCTIWZ(PPUThread& ppu, ppu_opcode_t op) +{ + (s32&)ppu.FPR[op.frd] = static_cast(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FDIV(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] / ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FSUB(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] - ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FADD(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] + ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FSQRT(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = sqrt(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FSEL(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] >= 0.0 ? ppu.FPR[op.frc] : ppu.FPR[op.frb]; + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FMUL(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] * ppu.FPR[op.frc]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FRSQRTE(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = 1.0 / sqrt(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FMSUB(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] * ppu.FPR[op.frc] - ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FMADD(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] * ppu.FPR[op.frc] + ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FNMSUB(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = -(ppu.FPR[op.fra] * ppu.FPR[op.frc]) + ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FNMADD(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = -(ppu.FPR[op.fra] * ppu.FPR[op.frc]) - ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FCMPO(PPUThread& ppu, ppu_opcode_t op) +{ + return FCMPU(ppu, op); +} + +void ppu_interpreter::FNEG(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = -ppu.FPR[op.frb]; + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FMR(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.frb]; + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FNABS(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = -fabs(ppu.FPR[op.frb]); + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FABS(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = fabs(ppu.FPR[op.frb]); + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FCTID(PPUThread& ppu, ppu_opcode_t op) +{ + (s64&)ppu.FPR[op.frd] = llrint(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FCTIDZ(PPUThread& ppu, ppu_opcode_t op) +{ + (s64&)ppu.FPR[op.frd] = static_cast(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FCFID(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = static_cast((s64&)ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FCMPU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::UNK(PPUThread& ppu, ppu_opcode_t op) { - s32 cmp_res = FPRdouble::Cmp(CPU.FPR[op.fra], CPU.FPR[op.frb]); - //CPU.FPSCR.FPRF = cmp_res; - CPU.SetCR(op.crfd, cmp_res); -} - -void ppu_interpreter::FRSP(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = static_cast(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FCTIW(PPUThread& CPU, ppu_opcode_t op) -{ - (s32&)CPU.FPR[op.frd]._double = lrint(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FCTIWZ(PPUThread& CPU, ppu_opcode_t op) -{ - (s32&)CPU.FPR[op.frd]._double = static_cast(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FDIV(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] / CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FSUB(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] - CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FADD(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] + CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FSQRT(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = sqrt(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FSEL(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] >= 0.0 ? CPU.FPR[op.frc] : CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FMUL(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] * CPU.FPR[op.frc]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FRSQRTE(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = 1.0 / sqrt(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FMSUB(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] * CPU.FPR[op.frc] - CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FMADD(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] * CPU.FPR[op.frc] + CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FNMSUB(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = -(CPU.FPR[op.fra] * CPU.FPR[op.frc]) + CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FNMADD(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = -(CPU.FPR[op.fra] * CPU.FPR[op.frc]) - CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FCMPO(PPUThread& CPU, ppu_opcode_t op) -{ - s32 cmp_res = FPRdouble::Cmp(CPU.FPR[op.fra], CPU.FPR[op.frb]); - //CPU.FPSCR.FPRF = cmp_res; - CPU.SetCR(op.crfd, cmp_res); -} - -void ppu_interpreter::FNEG(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = -CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FMR(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FNABS(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = -fabs(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FABS(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = fabs(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FCTID(PPUThread& CPU, ppu_opcode_t op) -{ - (s64&)CPU.FPR[op.frd]._double = llrint(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FCTIDZ(PPUThread& CPU, ppu_opcode_t op) -{ - (s64&)CPU.FPR[op.frd]._double = static_cast(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FCFID(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = static_cast((s64&)CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - - -void ppu_interpreter::UNK(PPUThread& CPU, ppu_opcode_t op) -{ - throw EXCEPTION(""); + throw fmt::exception("Unknown/Illegal opcode: 0x%08x" HERE, op.opcode); } diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h index 984723c34e..ddca283103 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.h +++ b/rpcs3/Emu/Cell/PPUInterpreter.h @@ -1,4719 +1,403 @@ #pragma once -#include "Emu/Cell/PPUOpcodes.h" -#include "Emu/Memory/Memory.h" +#include "PPUOpcodes.h" -#if defined(_MSC_VER) -#include -#else -#include -#define _rotl64(x,r) (((u64)(x) << (r)) | ((u64)(x) >> (64 - (r)))) -#endif +class PPUThread; -#if defined(__GNUG__) -inline std::uint64_t UMULH64(std::uint64_t a, std::uint64_t b) +using ppu_inter_func_t = void(*)(PPUThread& ppu, ppu_opcode_t op); + +struct ppu_interpreter { - std::uint64_t result; - __asm__("mulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b)); - return result; -} - -inline std::int64_t MULH64(std::int64_t a, std::int64_t b) -{ - std::int64_t result; - __asm__("imulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b)); - return result; -} -#else -#define UMULH64 __umulh -#define MULH64 __mulh -#endif - -#include - -extern u64 rotate_mask[64][64]; // defined in PPUThread.cpp -extern u64 get_timebased_time(); - -inline void InitRotateMask() -{ - static bool inited = false; - if(inited) return; - - for(u32 mb=0; mb<64; mb++) for(u32 me=0; me<64; me++) - { - const u64 mask = ((u64)-1 >> mb) ^ ((me >= 63) ? 0 : (u64)-1 >> (me + 1)); - rotate_mask[mb][me] = mb > me ? ~mask : mask; - } - - inited = true; -} - -inline u8 rotl8(const u8 x, const u8 n) { return (x << n) | (x >> (8 - n)); } -inline u8 rotr8(const u8 x, const u8 n) { return (x >> n) | (x << (8 - n)); } - -inline u16 rotl16(const u16 x, const u8 n) { return (x << n) | (x >> (16 - n)); } -inline u16 rotr16(const u16 x, const u8 n) { return (x >> n) | (x << (16 - n)); } -/* -u32 rotl32(const u32 x, const u8 n) { return (x << n) | (x >> (32 - n)); } -u32 rotr32(const u32 x, const u8 n) { return (x >> n) | (x << (32 - n)); } -u64 rotl64(const u64 x, const u8 n) { return (x << n) | (x >> (64 - n)); } -u64 rotr64(const u64 x, const u8 n) { return (x >> n) | (x << (64 - n)); } -*/ - -#define rotl32(x, n) _rotl64((u64)(u32)x | ((u64)(u32)x << 32), n) -#define rotr32(x, n) _rotr64((u64)(u32)x | ((u64)(u32)x << 32), n) -#define rotl64 _rotl64 -#define rotr64 _rotr64 - -static double SilenceNaN(double x) -{ - u64 bits = (u64&)x; - bits |= 0x0008000000000000ULL; - return (double&)bits; -} - -static float SilenceNaN(float x) -{ - return static_cast(SilenceNaN(static_cast(x))); -} - -static void SetHostRoundingMode(u32 rn) -{ - switch (rn) - { - case FPSCR_RN_NEAR: - fesetround(FE_TONEAREST); - break; - case FPSCR_RN_ZERO: - fesetround(FE_TOWARDZERO); - break; - case FPSCR_RN_PINF: - fesetround(FE_UPWARD); - break; - case FPSCR_RN_MINF: - fesetround(FE_DOWNWARD); - break; - } -} - - -namespace ppu_recompiler_llvm { - class Compiler; - class RecompilationEngine; -} - -class ppu_llvm_test_class; - -class PPUInterpreter : public PPUOpcodes -{ -#ifdef PPU_LLVM_RECOMPILER - friend class ppu_recompiler_llvm::Compiler; - friend class ppu_llvm_test_class; - friend class ppu_recompiler_llvm::RecompilationEngine; -#endif -private: - PPUThread& CPU; - -public: - PPUInterpreter(PPUThread& cpu) : CPU(cpu) - { - } - -private: - void CheckHostFPExceptions() - { - CPU.SetFPSCR_FI(fetestexcept(FE_INEXACT) != 0); - if (fetestexcept(FE_UNDERFLOW)) CPU.SetFPSCRException(FPSCR_UX); - if (fetestexcept(FE_OVERFLOW)) CPU.SetFPSCRException(FPSCR_OX); - } - - void NULL_OP() override - { - throw EXCEPTION("Null operation"); - } - - void NOP() override - { - //__asm nop - } - - float CheckVSCR_NJ(const float v) const - { - if(!CPU.VSCR.NJ) return v; - - const int fpc = _fpclass(v); -#ifdef __GNUG__ - if(fpc == FP_SUBNORMAL) - return std::signbit(v) ? -0.0f : 0.0f; -#else - if(fpc & _FPCLASS_ND) return -0.0f; - if(fpc & _FPCLASS_PD) return 0.0f; -#endif - - return v; - } - - bool CheckCondition(u32 bo, u32 bi) - { - const u8 bo0 = (bo & 0x10) ? 1 : 0; - const u8 bo1 = (bo & 0x08) ? 1 : 0; - const u8 bo2 = (bo & 0x04) ? 1 : 0; - const u8 bo3 = (bo & 0x02) ? 1 : 0; - - if(!bo2) --CPU.CTR; - - const u8 ctr_ok = bo2 | ((CPU.CTR != 0) ^ bo3); - const u8 cond_ok = bo0 | (CPU.IsCR(bi) ^ (~bo1 & 0x1)); - - return ctr_ok && cond_ok; - } - - u64 ReadSPR(u32 spr) - { - const u32 n = (spr >> 5) | ((spr & 0x1f) << 5); - - switch (n) - { - case 0x001: return CPU.XER.XER; - case 0x008: return CPU.LR; - case 0x009: return CPU.CTR; - case 0x100: return CPU.VRSAVE; - case 0x103: return CPU.SPRG[3]; - - case 0x10C: CPU.TB = get_timebased_time(); return CPU.TB; - case 0x10D: CPU.TB = get_timebased_time(); return CPU.TB >> 32; - - case 0x110: - case 0x111: - case 0x112: - case 0x113: - case 0x114: - case 0x115: - case 0x116: - case 0x117: return CPU.SPRG[n - 0x110]; - } - - throw EXCEPTION("Unknown SPR (spr=0x%x, n=0x%x)", spr, n); - } - - void WriteSPR(u32 spr, u64 value) - { - const u32 n = (spr >> 5) | ((spr & 0x1f) << 5); - - switch (n) - { - case 0x001: CPU.XER.XER = value; return; - case 0x008: CPU.LR = value; return; - case 0x009: CPU.CTR = value; return; - case 0x100: CPU.VRSAVE = (u32)value; return; - case 0x103: throw EXCEPTION("WriteSPR(0x103, 0x%llx): Write to read-only SPR", value); - - case 0x10C: throw EXCEPTION("WriteSPR(0x10C, 0x%llx): Write to time-based SPR", value); - case 0x10D: throw EXCEPTION("WriteSPR(0x10D, 0x%llx): Write to time-based SPR", value); - - case 0x110: - case 0x111: - case 0x112: - case 0x113: - case 0x114: - case 0x115: - case 0x116: - case 0x117: CPU.SPRG[n - 0x110] = value; return; - } - - throw EXCEPTION("Unknown SPR (spr=0x%x, n=0x%x, value=0x%llx)", spr, n, value); - } - - void TDI(u32 to, u32 ra, s32 simm16) override - { - s64 a = CPU.GPR[ra]; - - if( (a < (s64)simm16 && (to & 0x10)) || - (a > (s64)simm16 && (to & 0x8)) || - (a == (s64)simm16 && (to & 0x4)) || - ((u64)a < (u64)simm16 && (to & 0x2)) || - ((u64)a > (u64)simm16 && (to & 0x1)) ) - { - throw EXCEPTION("Trap! (tdi 0x%x, r%d, 0x%x)", to, ra, simm16); - } - } - - static void TWI_impl(PPUThread *CPU, u32 to, u32 ra, s32 simm16) - { - s32 a = (s32)CPU->GPR[ra]; - - if ((a < simm16 && (to & 0x10)) || - (a > simm16 && (to & 0x8)) || - (a == simm16 && (to & 0x4)) || - ((u32)a < (u32)simm16 && (to & 0x2)) || - ((u32)a > (u32)simm16 && (to & 0x1)) ) - { - throw EXCEPTION("Trap! (twi 0x%x, r%d, 0x%x)", to, ra, simm16); - } - } - - void TWI(u32 to, u32 ra, s32 simm16) override - { - TWI_impl(&CPU, to, ra, simm16); - } - - void MFVSCR(u32 vd) override //nf - { - CPU.VPR[vd].clear(); - CPU.VPR[vd]._u32[0] = CPU.VSCR.VSCR; - } - void MTVSCR(u32 vb) override - { - CPU.VSCR.VSCR = CPU.VPR[vb]._u32[0]; - CPU.VSCR.X = CPU.VSCR.Y = 0; - } - void VADDCUW(u32 vd, u32 va, u32 vb) override //nf - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = ~CPU.VPR[va]._u32[w] < CPU.VPR[vb]._u32[w]; - } - } - void VADDFP(u32 vd, u32 va, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(a)) - CPU.VPR[vd]._f[w] = SilenceNaN(a); - else if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (std::isinf(a) && std::isinf(b) && a != b) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - CPU.VPR[vd]._f[w] = CheckVSCR_NJ(a + b); - } - } - void VADDSBS(u32 vd, u32 va, u32 vb) override //nf - { - for(u32 b=0; b<16; ++b) - { - s16 result = (s16)CPU.VPR[va]._s8[b] + (s16)CPU.VPR[vb]._s8[b]; - - if (result > 0x7f) - { - CPU.VPR[vd]._s8[b] = 0x7f; - CPU.VSCR.SAT = 1; - } - else if (result < -0x80) - { - CPU.VPR[vd]._s8[b] = -0x80; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s8[b] = (s8)result; - } - } - void VADDSHS(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - s32 result = (s32)CPU.VPR[va]._s16[h] + (s32)CPU.VPR[vb]._s16[h]; - - if (result > 0x7fff) - { - CPU.VPR[vd]._s16[h] = 0x7fff; - CPU.VSCR.SAT = 1; - } - else if (result < -0x8000) - { - CPU.VPR[vd]._s16[h] = -0x8000; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s16[h] = result; - } - } - void VADDSWS(u32 vd, u32 va, u32 vb) override //nf - { - for (uint w = 0; w < 4; w++) - { - s64 result = (s64)CPU.VPR[va]._s32[w] + (s64)CPU.VPR[vb]._s32[w]; - - if (result > 0x7fffffff) - { - CPU.VPR[vd]._s32[w] = 0x7fffffff; - CPU.VSCR.SAT = 1; - } - else if (result < (s32)0x80000000) - { - CPU.VPR[vd]._s32[w] = 0x80000000; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[w] = (s32)result; - } - } - void VADDUBM(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = CPU.VPR[va]._u8[b] + CPU.VPR[vb]._u8[b]; - } - } - void VADDUBS(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - { - u16 result = (u16)CPU.VPR[va]._u8[b] + (u16)CPU.VPR[vb]._u8[b]; - - if (result > 0xff) - { - CPU.VPR[vd]._u8[b] = 0xff; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u8[b] = (u8)result; - } - } - void VADDUHM(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] + CPU.VPR[vb]._u16[h]; - } - } - void VADDUHS(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - u32 result = (u32)CPU.VPR[va]._u16[h] + (u32)CPU.VPR[vb]._u16[h]; - - if (result > 0xffff) - { - CPU.VPR[vd]._u16[h] = 0xffff; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u16[h] = result; - } - } - void VADDUWM(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] + CPU.VPR[vb]._u32[w]; - } - } - void VADDUWS(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - u64 result = (u64)CPU.VPR[va]._u32[w] + (u64)CPU.VPR[vb]._u32[w]; - - if (result > 0xffffffff) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u32[w] = (u32)result; - } - } - void VAND(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] & CPU.VPR[vb]._u32[w]; - } - } - void VANDC(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] & (~CPU.VPR[vb]._u32[w]); - } - } - void VAVGSB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._s8[b] = (CPU.VPR[va]._s8[b] + CPU.VPR[vb]._s8[b] + 1) >> 1; - } - } - void VAVGSH(u32 vd, u32 va, u32 vb) override //nf - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = (CPU.VPR[va]._s16[h] + CPU.VPR[vb]._s16[h] + 1) >> 1; - } - } - void VAVGSW(u32 vd, u32 va, u32 vb) override //nf - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = ((s64)CPU.VPR[va]._s32[w] + (s64)CPU.VPR[vb]._s32[w] + 1) >> 1; - } - } - void VAVGUB(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - CPU.VPR[vd]._u8[b] = (CPU.VPR[va]._u8[b] + CPU.VPR[vb]._u8[b] + 1) >> 1; - } - void VAVGUH(u32 vd, u32 va, u32 vb) override //nf - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = (CPU.VPR[va]._u16[h] + CPU.VPR[vb]._u16[h] + 1) >> 1; - } - } - void VAVGUW(u32 vd, u32 va, u32 vb) override //nf - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = ((u64)CPU.VPR[va]._u32[w] + (u64)CPU.VPR[vb]._u32[w] + 1) >> 1; - } - } - void VCFSX(u32 vd, u32 uimm5, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - u32 scale = 1 << uimm5; - - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._f[w] = ((float)CPU.VPR[vb]._s32[w]) / scale; - } - } - void VCFUX(u32 vd, u32 uimm5, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - u32 scale = 1 << uimm5; - - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._f[w] = ((float)CPU.VPR[vb]._u32[w]) / scale; - } - } - void VCMPBFP(u32 vd, u32 va, u32 vb, u32 rc) - { - bool allInBounds = true; - - for (uint w = 0; w < 4; w++) - { - u32 mask = 1<<31 | 1<<30; - - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - - if (a <= b) mask &= ~(1 << 31); - if (a >= -b) mask &= ~(1 << 30); - - CPU.VPR[vd]._u32[w] = mask; - - if (mask) - allInBounds = false; - } - - if (rc) - { - // Bit n°2 of CR6 - CPU.SetCR(6, 0); - CPU.SetCRBit(6, 0x2, allInBounds); - } - } - void VCMPBFP(u32 vd, u32 va, u32 vb) override {VCMPBFP(vd, va, vb, false);} - void VCMPBFP_(u32 vd, u32 va, u32 vb) override {VCMPBFP(vd, va, vb, true);} - void VCMPEQFP(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_equal = 0x8; - int none_equal = 0x2; - - for (uint w = 0; w < 4; w++) - { - if (CPU.VPR[va]._f[w] == CPU.VPR[vb]._f[w]) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - none_equal = 0; - } - else - { - CPU.VPR[vd]._u32[w] = 0; - all_equal = 0; - } - } - - if (rc) CPU.CR.cr6 = all_equal | none_equal; - } - void VCMPEQFP(u32 vd, u32 va, u32 vb) override {VCMPEQFP(vd, va, vb, false);} - void VCMPEQFP_(u32 vd, u32 va, u32 vb) override {VCMPEQFP(vd, va, vb, true);} - void VCMPEQUB(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_equal = 0x8; - int none_equal = 0x2; - - for (uint b = 0; b < 16; b++) - { - if (CPU.VPR[va]._u8[b] == CPU.VPR[vb]._u8[b]) - { - CPU.VPR[vd]._u8[b] = 0xff; - none_equal = 0; - } - else - { - CPU.VPR[vd]._u8[b] = 0; - all_equal = 0; - } - } - - if (rc) CPU.CR.cr6 = all_equal | none_equal; - } - void VCMPEQUB(u32 vd, u32 va, u32 vb) override {VCMPEQUB(vd, va, vb, false);} - void VCMPEQUB_(u32 vd, u32 va, u32 vb) override {VCMPEQUB(vd, va, vb, true);} - void VCMPEQUH(u32 vd, u32 va, u32 vb, u32 rc) //nf - { - int all_equal = 0x8; - int none_equal = 0x2; - - for (uint h = 0; h < 8; h++) - { - if (CPU.VPR[va]._u16[h] == CPU.VPR[vb]._u16[h]) - { - CPU.VPR[vd]._u16[h] = 0xffff; - none_equal = 0; - } - else - { - CPU.VPR[vd]._u16[h] = 0; - all_equal = 0; - } - } - - if (rc) CPU.CR.cr6 = all_equal | none_equal; - } - void VCMPEQUH(u32 vd, u32 va, u32 vb) override {VCMPEQUH(vd, va, vb, false);} - void VCMPEQUH_(u32 vd, u32 va, u32 vb) override {VCMPEQUH(vd, va, vb, true);} - void VCMPEQUW(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_equal = 0x8; - int none_equal = 0x2; - - for (uint w = 0; w < 4; w++) - { - if (CPU.VPR[va]._u32[w] == CPU.VPR[vb]._u32[w]) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - none_equal = 0; - } - else - { - CPU.VPR[vd]._u32[w] = 0; - all_equal = 0; - } - } - - if (rc) CPU.CR.cr6 = all_equal | none_equal; - } - void VCMPEQUW(u32 vd, u32 va, u32 vb) override {VCMPEQUW(vd, va, vb, false);} - void VCMPEQUW_(u32 vd, u32 va, u32 vb) override {VCMPEQUW(vd, va, vb, true);} - void VCMPGEFP(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_ge = 0x8; - int none_ge = 0x2; - - for (uint w = 0; w < 4; w++) - { - if (CPU.VPR[va]._f[w] >= CPU.VPR[vb]._f[w]) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - none_ge = 0; - } - else - { - CPU.VPR[vd]._u32[w] = 0; - all_ge = 0; - } - } - - if (rc) CPU.CR.cr6 = all_ge | none_ge; - } - void VCMPGEFP(u32 vd, u32 va, u32 vb) override {VCMPGEFP(vd, va, vb, false);} - void VCMPGEFP_(u32 vd, u32 va, u32 vb) override {VCMPGEFP(vd, va, vb, true);} - void VCMPGTFP(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_ge = 0x8; - int none_ge = 0x2; - - for (uint w = 0; w < 4; w++) - { - if (CPU.VPR[va]._f[w] > CPU.VPR[vb]._f[w]) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - none_ge = 0; - } - else - { - CPU.VPR[vd]._u32[w] = 0; - all_ge = 0; - } - } - - if (rc) CPU.CR.cr6 = all_ge | none_ge; - } - void VCMPGTFP(u32 vd, u32 va, u32 vb) override {VCMPGTFP(vd, va, vb, false);} - void VCMPGTFP_(u32 vd, u32 va, u32 vb) override {VCMPGTFP(vd, va, vb, true);} - void VCMPGTSB(u32 vd, u32 va, u32 vb, u32 rc) //nf - { - int all_gt = 0x8; - int none_gt = 0x2; - - for (uint b = 0; b < 16; b++) - { - if (CPU.VPR[va]._s8[b] > CPU.VPR[vb]._s8[b]) - { - CPU.VPR[vd]._u8[b] = 0xff; - none_gt = 0; - } - else - { - CPU.VPR[vd]._u8[b] = 0; - all_gt = 0; - } - } - - if (rc) CPU.CR.cr6 = all_gt | none_gt; - } - void VCMPGTSB(u32 vd, u32 va, u32 vb) override {VCMPGTSB(vd, va, vb, false);} - void VCMPGTSB_(u32 vd, u32 va, u32 vb) override {VCMPGTSB(vd, va, vb, true);} - void VCMPGTSH(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_gt = 0x8; - int none_gt = 0x2; - - for (uint h = 0; h < 8; h++) - { - if (CPU.VPR[va]._s16[h] > CPU.VPR[vb]._s16[h]) - { - CPU.VPR[vd]._u16[h] = 0xffff; - none_gt = 0; - } - else - { - CPU.VPR[vd]._u16[h] = 0; - all_gt = 0; - } - } - - if (rc) CPU.CR.cr6 = all_gt | none_gt; - } - void VCMPGTSH(u32 vd, u32 va, u32 vb) override {VCMPGTSH(vd, va, vb, false);} - void VCMPGTSH_(u32 vd, u32 va, u32 vb) override {VCMPGTSH(vd, va, vb, true);} - void VCMPGTSW(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_gt = 0x8; - int none_gt = 0x2; - - for (uint w = 0; w < 4; w++) - { - if (CPU.VPR[va]._s32[w] > CPU.VPR[vb]._s32[w]) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - none_gt = 0; - } - else - { - CPU.VPR[vd]._u32[w] = 0; - all_gt = 0; - } - } - - if (rc) CPU.CR.cr6 = all_gt | none_gt; - } - void VCMPGTSW(u32 vd, u32 va, u32 vb) override {VCMPGTSW(vd, va, vb, false);} - void VCMPGTSW_(u32 vd, u32 va, u32 vb) override {VCMPGTSW(vd, va, vb, true);} - void VCMPGTUB(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_gt = 0x8; - int none_gt = 0x2; - - for (uint b = 0; b < 16; b++) - { - if (CPU.VPR[va]._u8[b] > CPU.VPR[vb]._u8[b]) - { - CPU.VPR[vd]._u8[b] = 0xff; - none_gt = 0; - } - else - { - CPU.VPR[vd]._u8[b] = 0; - all_gt = 0; - } - } - - if (rc) CPU.CR.cr6 = all_gt | none_gt; - } - void VCMPGTUB(u32 vd, u32 va, u32 vb) override {VCMPGTUB(vd, va, vb, false);} - void VCMPGTUB_(u32 vd, u32 va, u32 vb) override {VCMPGTUB(vd, va, vb, true);} - void VCMPGTUH(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_gt = 0x8; - int none_gt = 0x2; - - for (uint h = 0; h < 8; h++) - { - if (CPU.VPR[va]._u16[h] > CPU.VPR[vb]._u16[h]) - { - CPU.VPR[vd]._u16[h] = 0xffff; - none_gt = 0; - } - else - { - CPU.VPR[vd]._u16[h] = 0; - all_gt = 0; - } - } - - if (rc) CPU.CR.cr6 = all_gt | none_gt; - } - void VCMPGTUH(u32 vd, u32 va, u32 vb) override {VCMPGTUH(vd, va, vb, false);} - void VCMPGTUH_(u32 vd, u32 va, u32 vb) override {VCMPGTUH(vd, va, vb, true);} - void VCMPGTUW(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_gt = 0x8; - int none_gt = 0x2; - - for (uint w = 0; w < 4; w++) - { - if (CPU.VPR[va]._u32[w] > CPU.VPR[vb]._u32[w]) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - none_gt = 0; - } - else - { - CPU.VPR[vd]._u32[w] = 0; - all_gt = 0; - } - } - - if (rc) CPU.CR.cr6 = all_gt | none_gt; - } - void VCMPGTUW(u32 vd, u32 va, u32 vb) override {VCMPGTUW(vd, va, vb, false);} - void VCMPGTUW_(u32 vd, u32 va, u32 vb) override {VCMPGTUW(vd, va, vb, true);} - void VCTSXS(u32 vd, u32 uimm5, u32 vb) override - { - u32 nScale = 1 << uimm5; - - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - { - CPU.VPR[vd]._s32[w] = 0; - } - else - { - double result = (double)b * nScale; - if (result > 0x7fffffff) - { - CPU.VPR[vd]._s32[w] = (int)0x7fffffff; - CPU.VSCR.SAT = 1; - } - else if (result < -pow(2, 31)) - { - CPU.VPR[vd]._s32[w] = (int)0x80000000; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[w] = (int)trunc(result); - } - } - } - void VCTUXS(u32 vd, u32 uimm5, u32 vb) override - { - u32 nScale = 1 << uimm5; - - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - { - CPU.VPR[vd]._s32[w] = 0; - } - else - { - double result = (double)b * nScale; - if (result > 0xffffffffu) - { - CPU.VPR[vd]._u32[w] = 0xffffffffu; - CPU.VSCR.SAT = 1; - } - else if (result < 0) - { - CPU.VPR[vd]._u32[w] = 0; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u32[w] = (u32)trunc(result); - } - } - } - void VEXPTEFP(u32 vd, u32 vb) override - { - // vd = 2^x - // ISA : Note that the value placed into the element of vD may vary between implementations - // and between different executions on the same implementation. - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - CPU.VPR[vd]._f[w] = CheckVSCR_NJ(powf(2.0f, b)); - } - } - void VLOGEFP(u32 vd, u32 vb) override - { - // ISA : Note that the value placed into the element of vD may vary between implementations - // and between different executions on the same implementation. - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - CPU.VPR[vd]._f[w] = log2f(b); // Can never be denormal. - } - } - void VMADDFP(u32 vd, u32 va, u32 vc, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - const float c = CheckVSCR_NJ(CPU.VPR[vc]._f[w]); - if (std::isnan(a)) - CPU.VPR[vd]._f[w] = SilenceNaN(a); - else if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (std::isnan(c)) - CPU.VPR[vd]._f[w] = SilenceNaN(c); - else if ((std::isinf(a) && c == 0) || (a == 0 && std::isinf(c))) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - { - const float result = fmaf(a, c, b); - if (std::isnan(result)) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - CPU.VPR[vd]._f[w] = CheckVSCR_NJ(result); - } - } - } - void VMAXFP(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(a)) - CPU.VPR[vd]._f[w] = SilenceNaN(a); - else if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (a > b) - CPU.VPR[vd]._f[w] = a; - else if (b > a) - CPU.VPR[vd]._f[w] = b; - else if (CPU.VPR[vb]._u32[w] == 0x80000000) - CPU.VPR[vd]._f[w] = a; // max(+0,-0) = +0 - else - CPU.VPR[vd]._f[w] = b; - } - } - void VMAXSB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint b = 0; b < 16; b++) - CPU.VPR[vd]._s8[b] = std::max(CPU.VPR[va]._s8[b], CPU.VPR[vb]._s8[b]); - } - void VMAXSH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = std::max(CPU.VPR[va]._s16[h], CPU.VPR[vb]._s16[h]); - } - } - void VMAXSW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = std::max(CPU.VPR[va]._s32[w], CPU.VPR[vb]._s32[w]); - } - } - void VMAXUB(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - CPU.VPR[vd]._u8[b] = std::max(CPU.VPR[va]._u8[b], CPU.VPR[vb]._u8[b]); - } - void VMAXUH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = std::max(CPU.VPR[va]._u16[h], CPU.VPR[vb]._u16[h]); - } - } - void VMAXUW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = std::max(CPU.VPR[va]._u32[w], CPU.VPR[vb]._u32[w]); - } - } - void VMHADDSHS(u32 vd, u32 va, u32 vb, u32 vc) override - { - for (uint h = 0; h < 8; h++) - { - s32 result = (s32)CPU.VPR[va]._s16[h] * (s32)CPU.VPR[vb]._s16[h]; - result = (result >> 15) + (s32)CPU.VPR[vc]._s16[h]; - - if (result > INT16_MAX) - { - CPU.VPR[vd]._s16[h] = (s16)INT16_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < INT16_MIN) - { - CPU.VPR[vd]._s16[h] = (s16)INT16_MIN; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s16[h] = (s16)result; - } - } - void VMHRADDSHS(u32 vd, u32 va, u32 vb, u32 vc) override - { - for (uint h = 0; h < 8; h++) - { - s32 result = ((s32)CPU.VPR[va]._s16[h] * (s32)CPU.VPR[vb]._s16[h]) + 0x4000; - result = (result >> 15) + (s32)CPU.VPR[vc]._s16[h]; - - if (result > INT16_MAX) - { - CPU.VPR[vd]._s16[h] = (s16)INT16_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < INT16_MIN) - { - CPU.VPR[vd]._s16[h] = (s16)INT16_MIN; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s16[h] = (s16)result; - } - } - void VMINFP(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(a)) - CPU.VPR[vd]._f[w] = SilenceNaN(a); - else if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (a < b) - CPU.VPR[vd]._f[w] = a; - else if (b < a) - CPU.VPR[vd]._f[w] = b; - else if (CPU.VPR[vb]._u32[w] == 0x00000000) - CPU.VPR[vd]._f[w] = a; // min(-0,+0) = -0 - else - CPU.VPR[vd]._f[w] = b; - } - } - void VMINSB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._s8[b] = std::min(CPU.VPR[va]._s8[b], CPU.VPR[vb]._s8[b]); - } - } - void VMINSH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = std::min(CPU.VPR[va]._s16[h], CPU.VPR[vb]._s16[h]); - } - } - void VMINSW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = std::min(CPU.VPR[va]._s32[w], CPU.VPR[vb]._s32[w]); - } - } - void VMINUB(u32 vd, u32 va, u32 vb)override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = std::min(CPU.VPR[va]._u8[b], CPU.VPR[vb]._u8[b]); - } - } - void VMINUH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = std::min(CPU.VPR[va]._u16[h], CPU.VPR[vb]._u16[h]); - } - } - void VMINUW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = std::min(CPU.VPR[va]._u32[w], CPU.VPR[vb]._u32[w]); - } - } - void VMLADDUHM(u32 vd, u32 va, u32 vb, u32 vc) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] * CPU.VPR[vb]._u16[h] + CPU.VPR[vc]._u16[h]; - } - } - void VMRGHB(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u8[15 - h*2] = VA._u8[15 - h]; - CPU.VPR[vd]._u8[15 - h*2 - 1] = VB._u8[15 - h]; - } - } - void VMRGHH(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u16[7 - w*2] = VA._u16[7 - w]; - CPU.VPR[vd]._u16[7 - w*2 - 1] = VB._u16[7 - w]; - } - } - void VMRGHW(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint d = 0; d < 2; d++) - { - CPU.VPR[vd]._u32[3 - d*2] = VA._u32[3 - d]; - CPU.VPR[vd]._u32[3 - d*2 - 1] = VB._u32[3 - d]; - } - } - void VMRGLB(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u8[15 - h*2] = VA._u8[7 - h]; - CPU.VPR[vd]._u8[15 - h*2 - 1] = VB._u8[7 - h]; - } - } - void VMRGLH(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u16[7 - w*2] = VA._u16[3 - w]; - CPU.VPR[vd]._u16[7 - w*2 - 1] = VB._u16[3 - w]; - } - } - void VMRGLW(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint d = 0; d < 2; d++) - { - CPU.VPR[vd]._u32[3 - d*2] = VA._u32[1 - d]; - CPU.VPR[vd]._u32[3 - d*2 - 1] = VB._u32[1 - d]; - } - } - void VMSUMMBM(u32 vd, u32 va, u32 vb, u32 vc) override //nf - { - for (uint w = 0; w < 4; w++) - { - s32 result = 0; - - for (uint b = 0; b < 4; b++) - { - result += CPU.VPR[va]._s8[w*4 + b] * CPU.VPR[vb]._u8[w*4 + b]; - } - - result += CPU.VPR[vc]._s32[w]; - CPU.VPR[vd]._s32[w] = result; - } - } - void VMSUMSHM(u32 vd, u32 va, u32 vb, u32 vc) override //nf - { - for (uint w = 0; w < 4; w++) - { - s32 result = 0; - - for (uint h = 0; h < 2; h++) - { - result += CPU.VPR[va]._s16[w*2 + h] * CPU.VPR[vb]._s16[w*2 + h]; - } - - result += CPU.VPR[vc]._s32[w]; - CPU.VPR[vd]._s32[w] = result; - } - } - void VMSUMSHS(u32 vd, u32 va, u32 vb, u32 vc) override //nf - { - for (uint w = 0; w < 4; w++) - { - s64 result = 0; - s32 saturated = 0; - - for (uint h = 0; h < 2; h++) - { - result += CPU.VPR[va]._s16[w*2 + h] * CPU.VPR[vb]._s16[w*2 + h]; - } - - result += CPU.VPR[vc]._s32[w]; - - if (result > 0x7fffffff) - { - saturated = 0x7fffffff; - CPU.VSCR.SAT = 1; - } - else if (result < (s64)(s32)0x80000000) - { - saturated = 0x80000000; - CPU.VSCR.SAT = 1; - } - else - saturated = (s32)result; - - CPU.VPR[vd]._s32[w] = saturated; - } - } - void VMSUMUBM(u32 vd, u32 va, u32 vb, u32 vc) override - { - for (uint w = 0; w < 4; w++) - { - u32 result = 0; - - for (uint b = 0; b < 4; b++) - { - result += (u32)CPU.VPR[va]._u8[w*4 + b] * (u32)CPU.VPR[vb]._u8[w*4 + b]; - } - - result += CPU.VPR[vc]._u32[w]; - CPU.VPR[vd]._u32[w] = result; - } - } - void VMSUMUHM(u32 vd, u32 va, u32 vb, u32 vc) override //nf - { - for (uint w = 0; w < 4; w++) - { - u32 result = 0; - - for (uint h = 0; h < 2; h++) - { - result += (u32)CPU.VPR[va]._u16[w*2 + h] * (u32)CPU.VPR[vb]._u16[w*2 + h]; - } - - result += CPU.VPR[vc]._u32[w]; - CPU.VPR[vd]._u32[w] = result; - } - } - void VMSUMUHS(u32 vd, u32 va, u32 vb, u32 vc) override //nf - { - for (uint w = 0; w < 4; w++) - { - u64 result = 0; - u32 saturated = 0; - - for (uint h = 0; h < 2; h++) - { - result += (u64)CPU.VPR[va]._u16[w*2 + h] * (u64)CPU.VPR[vb]._u16[w*2 + h]; - } - - result += CPU.VPR[vc]._u32[w]; - - if (result > 0xffffffffu) - { - saturated = 0xffffffff; - CPU.VSCR.SAT = 1; - } - else - saturated = (u32)result; - - CPU.VPR[vd]._u32[w] = saturated; - } - } - void VMULESB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = (s16)CPU.VPR[va]._s8[h*2+1] * (s16)CPU.VPR[vb]._s8[h*2+1]; - } - } - void VMULESH(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = (s32)CPU.VPR[va]._s16[w*2+1] * (s32)CPU.VPR[vb]._s16[w*2+1]; - } - } - void VMULEUB(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = (u16)CPU.VPR[va]._u8[h*2+1] * (u16)CPU.VPR[vb]._u8[h*2+1]; - } - } - void VMULEUH(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = (u32)CPU.VPR[va]._u16[w*2+1] * (u32)CPU.VPR[vb]._u16[w*2+1]; - } - } - void VMULOSB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = (s16)CPU.VPR[va]._s8[h*2] * (s16)CPU.VPR[vb]._s8[h*2]; - } - } - void VMULOSH(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = (s32)CPU.VPR[va]._s16[w*2] * (s32)CPU.VPR[vb]._s16[w*2]; - } - } - void VMULOUB(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = (u16)CPU.VPR[va]._u8[h*2] * (u16)CPU.VPR[vb]._u8[h*2]; - } - } - void VMULOUH(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = (u32)CPU.VPR[va]._u16[w*2] * (u32)CPU.VPR[vb]._u16[w*2]; - } - } - void VNMSUBFP(u32 vd, u32 va, u32 vc, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - const float c = CheckVSCR_NJ(CPU.VPR[vc]._f[w]); - if (std::isnan(a)) - CPU.VPR[vd]._f[w] = SilenceNaN(a); - else if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (std::isnan(c)) - CPU.VPR[vd]._f[w] = SilenceNaN(c); - else if ((std::isinf(a) && c == 0) || (a == 0 && std::isinf(c))) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - { - const float result = -fmaf(a, c, -b); - if (std::isnan(result)) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - CPU.VPR[vd]._f[w] = CheckVSCR_NJ(result); - } - } - } - void VNOR(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = ~(CPU.VPR[va]._u32[w] | CPU.VPR[vb]._u32[w]); - } - } - void VOR(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] | CPU.VPR[vb]._u32[w]; - } - } - void VPERM(u32 vd, u32 va, u32 vb, u32 vc) override - { - u8 tmpSRC[32]; - std::memcpy(tmpSRC, CPU.VPR + vb, 16); - std::memcpy(tmpSRC + 16, CPU.VPR + va, 16); - - for (uint b = 0; b < 16; b++) - { - u8 index = CPU.VPR[vc]._u8[b] & 0x1f; - - CPU.VPR[vd]._u8[b] = tmpSRC[0x1f - index]; - } - } - void VPKPX(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 4; h++) - { - u16 bb7 = VB._u8[15 - (h*4 + 0)] & 0x1; - u16 bb8 = VB._u8[15 - (h*4 + 1)] >> 3; - u16 bb16 = VB._u8[15 - (h*4 + 2)] >> 3; - u16 bb24 = VB._u8[15 - (h*4 + 3)] >> 3; - u16 ab7 = VA._u8[15 - (h*4 + 0)] & 0x1; - u16 ab8 = VA._u8[15 - (h*4 + 1)] >> 3; - u16 ab16 = VA._u8[15 - (h*4 + 2)] >> 3; - u16 ab24 = VA._u8[15 - (h*4 + 3)] >> 3; - - CPU.VPR[vd]._u16[3 - h] = (bb7 << 15) | (bb8 << 10) | (bb16 << 5) | bb24; - CPU.VPR[vd]._u16[4 + (3 - h)] = (ab7 << 15) | (ab8 << 10) | (ab16 << 5) | ab24; - } - } - void VPKSHSS(u32 vd, u32 va, u32 vb) override //nf - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint b = 0; b < 8; b++) - { - s16 result = VA._s16[b]; - - if (result > INT8_MAX) - { - result = INT8_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < INT8_MIN) - { - result = INT8_MIN; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._s8[b+8] = (s8)result; - - result = VB._s16[b]; - - if (result > INT8_MAX) - { - result = INT8_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < INT8_MIN) - { - result = INT8_MIN; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._s8[b] = (s8)result; - } - } - void VPKSHUS(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint b = 0; b < 8; b++) - { - s16 result = VA._s16[b]; - - if (result > UINT8_MAX) - { - result = UINT8_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < 0) - { - result = 0; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u8[b+8] = (u8)result; - - result = VB._s16[b]; - - if (result > UINT8_MAX) - { - result = UINT8_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < 0) - { - result = 0; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u8[b] = (u8)result; - } - } - void VPKSWSS(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 4; h++) - { - s32 result = VA._s32[h]; - - if (result > INT16_MAX) - { - result = INT16_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < INT16_MIN) - { - result = INT16_MIN; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._s16[h+4] = result; - - result = VB._s32[h]; - - if (result > INT16_MAX) - { - result = INT16_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < INT16_MIN) - { - result = INT16_MIN; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._s16[h] = result; - } - } - void VPKSWUS(u32 vd, u32 va, u32 vb) override //nf - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 4; h++) - { - s32 result = VA._s32[h]; - - if (result > UINT16_MAX) - { - result = UINT16_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < 0) - { - result = 0; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u16[h+4] = result; - - result = VB._s32[h]; - - if (result > UINT16_MAX) - { - result = UINT16_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < 0) - { - result = 0; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u16[h] = result; - } - } - void VPKUHUM(u32 vd, u32 va, u32 vb) override //nf - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint b = 0; b < 8; b++) - { - CPU.VPR[vd]._u8[b+8] = VA._u8[b*2]; - CPU.VPR[vd]._u8[b ] = VB._u8[b*2]; - } - } - void VPKUHUS(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint b = 0; b < 8; b++) - { - u16 result = VA._u16[b]; - - if (result > UINT8_MAX) - { - result = UINT8_MAX; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u8[b+8] = (u8)result; - - result = VB._u16[b]; - - if (result > UINT8_MAX) - { - result = UINT8_MAX; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u8[b] = (u8)result; - } - } - void VPKUWUM(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 4; h++) - { - CPU.VPR[vd]._u16[h+4] = VA._u16[h*2]; - CPU.VPR[vd]._u16[h ] = VB._u16[h*2]; - } - } - void VPKUWUS(u32 vd, u32 va, u32 vb) override //nf - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 4; h++) - { - u32 result = VA._u32[h]; - - if (result > UINT16_MAX) - { - result = UINT16_MAX; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u16[h+4] = result; - - result = VB._u32[h]; - - if (result > UINT16_MAX) - { - result = UINT16_MAX; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u16[h] = result; - } - } - void VREFP(u32 vd, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - CPU.VPR[vd]._f[w] = CheckVSCR_NJ(1.0f / b); - } - } - void VRFIM(u32 vd, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - CPU.VPR[vd]._f[w] = floorf(CPU.VPR[vb]._f[w]); - } - } - void VRFIN(u32 vd, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - { - SetHostRoundingMode(FPSCR_RN_NEAR); - CPU.VPR[vd]._f[w] = nearbyintf(CPU.VPR[vb]._f[w]); - } - } - } - void VRFIP(u32 vd, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - CPU.VPR[vd]._f[w] = ceilf(CPU.VPR[vb]._f[w]); - } - } - void VRFIZ(u32 vd, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - CPU.VPR[vd]._f[w] = truncf(CPU.VPR[vb]._f[w]); - } - } - void VRLB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint b = 0; b < 16; b++) - { - int nRot = CPU.VPR[vb]._u8[b] & 0x7; - - CPU.VPR[vd]._u8[b] = (CPU.VPR[va]._u8[b] << nRot) | (CPU.VPR[va]._u8[b] >> (8 - nRot)); - } - } - void VRLH(u32 vd, u32 va, u32 vb) override //nf - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = rotl16(CPU.VPR[va]._u16[h], CPU.VPR[vb]._u8[h*2] & 0xf); - } - } - void VRLW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = (u32)rotl32(CPU.VPR[va]._u32[w], CPU.VPR[vb]._u8[w*4] & 0x1f); - } - } - void VRSQRTEFP(u32 vd, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - //TODO: accurate div - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (b < 0) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - CPU.VPR[vd]._f[w] = 1.0f / sqrtf(b); // Can never be denormal. - } - } - void VSEL(u32 vd, u32 va, u32 vb, u32 vc) override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = (CPU.VPR[vb]._u8[b] & CPU.VPR[vc]._u8[b]) | (CPU.VPR[va]._u8[b] & (~CPU.VPR[vc]._u8[b])); - } - } - void VSL(u32 vd, u32 va, u32 vb) override //nf - { - v128 VA = CPU.VPR[va]; - u8 sh = CPU.VPR[vb]._u8[0] & 0x7; - - CPU.VPR[vd]._u8[0] = VA._u8[0] << sh; - for (uint b = 1; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = (VA._u8[b] << sh) | (VA._u8[b-1] >> (8 - sh)); - } - } - void VSLB(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = CPU.VPR[va]._u8[b] << (CPU.VPR[vb]._u8[b] & 0x7); - } - } - void VSLDOI(u32 vd, u32 va, u32 vb, u32 sh) override - { - u8 tmpSRC[32]; - std::memcpy(tmpSRC, CPU.VPR + vb, 16); - std::memcpy(tmpSRC + 16, CPU.VPR + va, 16); - - for(uint b=0; b<16; b++) - { - CPU.VPR[vd]._u8[15 - b] = tmpSRC[31 - (b + sh)]; - } - } - void VSLH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] << (CPU.VPR[vb]._u16[h] & 0xf); - } - } - void VSLO(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - u8 nShift = (CPU.VPR[vb]._u8[0] >> 3) & 0xf; - - CPU.VPR[vd].clear(); - - for (u8 b = 0; b < 16 - nShift; b++) - { - CPU.VPR[vd]._u8[15 - b] = VA._u8[15 - (b + nShift)]; - } - } - void VSLW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] << (CPU.VPR[vb]._u32[w] & 0x1f); - } - } - void VSPLTB(u32 vd, u32 uimm5, u32 vb) override - { - u8 byte = CPU.VPR[vb]._u8[15 - uimm5]; - - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = byte; - } - } - void VSPLTH(u32 vd, u32 uimm5, u32 vb) override - { - assert(uimm5 < 8); - - u16 hword = CPU.VPR[vb]._u16[7 - uimm5]; - - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = hword; - } - } - void VSPLTISB(u32 vd, s32 simm5) override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = simm5; - } - } - void VSPLTISH(u32 vd, s32 simm5) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = (s16)simm5; - } - } - void VSPLTISW(u32 vd, s32 simm5) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = (s32)simm5; - } - } - void VSPLTW(u32 vd, u32 uimm5, u32 vb) override - { - assert(uimm5 < 4); - - u32 word = CPU.VPR[vb]._u32[3 - uimm5]; - - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = word; - } - } - void VSR(u32 vd, u32 va, u32 vb) override //nf - { - v128 VA = CPU.VPR[va]; - u8 sh = CPU.VPR[vb]._u8[0] & 0x7; - - CPU.VPR[vd]._u8[15] = VA._u8[15] >> sh; - for (uint b = 14; ~b; b--) - { - CPU.VPR[vd]._u8[b] = (VA._u8[b] >> sh) | (VA._u8[b+1] << (8 - sh)); - } - } - void VSRAB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._s8[b] = CPU.VPR[va]._s8[b] >> (CPU.VPR[vb]._u8[b] & 0x7); - } - } - void VSRAH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = CPU.VPR[va]._s16[h] >> (CPU.VPR[vb]._u16[h] & 0xf); - } - } - void VSRAW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = CPU.VPR[va]._s32[w] >> (CPU.VPR[vb]._u32[w] & 0x1f); - } - } - void VSRB(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = CPU.VPR[va]._u8[b] >> (CPU.VPR[vb]._u8[b] & 0x7); - } - } - void VSRH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] >> (CPU.VPR[vb]._u16[h] & 0xf); - } - } - void VSRO(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - u8 nShift = (CPU.VPR[vb]._u8[0] >> 3) & 0xf; - - CPU.VPR[vd].clear(); - - for (u8 b = 0; b < 16 - nShift; b++) - { - CPU.VPR[vd]._u8[b] = VA._u8[b + nShift]; - } - } - void VSRW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] >> (CPU.VPR[vb]._u32[w] & 0x1f); - } - } - void VSUBCUW(u32 vd, u32 va, u32 vb) override //nf - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] < CPU.VPR[vb]._u32[w] ? 0 : 1; - } - } - void VSUBFP(u32 vd, u32 va, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(a)) - CPU.VPR[vd]._f[w] = SilenceNaN(a); - else if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (std::isinf(a) && std::isinf(b) && a == b) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - CPU.VPR[vd]._f[w] = CheckVSCR_NJ(a - b); - } - } - void VSUBSBS(u32 vd, u32 va, u32 vb) override //nf - { - for (uint b = 0; b < 16; b++) - { - s16 result = (s16)CPU.VPR[va]._s8[b] - (s16)CPU.VPR[vb]._s8[b]; - - if (result < INT8_MIN) - { - CPU.VPR[vd]._s8[b] = INT8_MIN; - CPU.VSCR.SAT = 1; - } - else if (result > INT8_MAX) - { - CPU.VPR[vd]._s8[b] = INT8_MAX; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s8[b] = (s8)result; - } - } - void VSUBSHS(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - s32 result = (s32)CPU.VPR[va]._s16[h] - (s32)CPU.VPR[vb]._s16[h]; - - if (result < INT16_MIN) - { - CPU.VPR[vd]._s16[h] = (s16)INT16_MIN; - CPU.VSCR.SAT = 1; - } - else if (result > INT16_MAX) - { - CPU.VPR[vd]._s16[h] = (s16)INT16_MAX; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s16[h] = (s16)result; - } - } - void VSUBSWS(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - s64 result = (s64)CPU.VPR[va]._s32[w] - (s64)CPU.VPR[vb]._s32[w]; - - if (result < INT32_MIN) - { - CPU.VPR[vd]._s32[w] = (s32)INT32_MIN; - CPU.VSCR.SAT = 1; - } - else if (result > INT32_MAX) - { - CPU.VPR[vd]._s32[w] = (s32)INT32_MAX; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[w] = (s32)result; - } - } - void VSUBUBM(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = (u8)((CPU.VPR[va]._u8[b] - CPU.VPR[vb]._u8[b]) & 0xff); - } - } - void VSUBUBS(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - { - s16 result = (s16)CPU.VPR[va]._u8[b] - (s16)CPU.VPR[vb]._u8[b]; - - if (result < 0) - { - CPU.VPR[vd]._u8[b] = 0; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u8[b] = (u8)result; - } - } - void VSUBUHM(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] - CPU.VPR[vb]._u16[h]; - } - } - void VSUBUHS(u32 vd, u32 va, u32 vb) override //nf - { - for (uint h = 0; h < 8; h++) - { - s32 result = (s32)CPU.VPR[va]._u16[h] - (s32)CPU.VPR[vb]._u16[h]; - - if (result < 0) - { - CPU.VPR[vd]._u16[h] = 0; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u16[h] = (u16)result; - } - } - void VSUBUWM(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] - CPU.VPR[vb]._u32[w]; - } - } - void VSUBUWS(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - s64 result = (s64)CPU.VPR[va]._u32[w] - (s64)CPU.VPR[vb]._u32[w]; - - if (result < 0) - { - CPU.VPR[vd]._u32[w] = 0; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u32[w] = (u32)result; - } - } - void VSUMSWS(u32 vd, u32 va, u32 vb) override - { - s64 sum = CPU.VPR[vb]._s32[0]; - - for (uint w = 0; w < 4; w++) - { - sum += CPU.VPR[va]._s32[w]; - } - - CPU.VPR[vd].clear(); - if (sum > INT32_MAX) - { - CPU.VPR[vd]._s32[0] = (s32)INT32_MAX; - CPU.VSCR.SAT = 1; - } - else if (sum < INT32_MIN) - { - CPU.VPR[vd]._s32[0] = (s32)INT32_MIN; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[0] = (s32)sum; - } - void VSUM2SWS(u32 vd, u32 va, u32 vb) override - { - for (uint n = 0; n < 2; n++) - { - s64 sum = (s64)CPU.VPR[va]._s32[n*2] + CPU.VPR[va]._s32[n*2 + 1] + CPU.VPR[vb]._s32[n*2]; - - if (sum > INT32_MAX) - { - CPU.VPR[vd]._s32[n*2] = (s32)INT32_MAX; - CPU.VSCR.SAT = 1; - } - else if (sum < INT32_MIN) - { - CPU.VPR[vd]._s32[n*2] = (s32)INT32_MIN; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[n*2] = (s32)sum; - } - CPU.VPR[vd]._s32[1] = 0; - CPU.VPR[vd]._s32[3] = 0; - } - void VSUM4SBS(u32 vd, u32 va, u32 vb) override //nf - { - for (uint w = 0; w < 4; w++) - { - s64 sum = CPU.VPR[vb]._s32[w]; - - for (uint b = 0; b < 4; b++) - { - sum += CPU.VPR[va]._s8[w*4 + b]; - } - - if (sum > INT32_MAX) - { - CPU.VPR[vd]._s32[w] = (s32)INT32_MAX; - CPU.VSCR.SAT = 1; - } - else if (sum < INT32_MIN) - { - CPU.VPR[vd]._s32[w] = (s32)INT32_MIN; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[w] = (s32)sum; - } - } - void VSUM4SHS(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - s64 sum = CPU.VPR[vb]._s32[w]; - - for (uint h = 0; h < 2; h++) - { - sum += CPU.VPR[va]._s16[w*2 + h]; - } - - if (sum > INT32_MAX) - { - CPU.VPR[vd]._s32[w] = (s32)INT32_MAX; - CPU.VSCR.SAT = 1; - } - else if (sum < INT32_MIN) - { - CPU.VPR[vd]._s32[w] = (s32)INT32_MIN; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[w] = (s32)sum; - } - } - void VSUM4UBS(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - u64 sum = CPU.VPR[vb]._u32[w]; - - for (uint b = 0; b < 4; b++) - { - sum += CPU.VPR[va]._u8[w*4 + b]; - } - - if (sum > UINT32_MAX) - { - CPU.VPR[vd]._u32[w] = (u32)UINT32_MAX; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u32[w] = (u32)sum; - } - } - void VUPKHPX(u32 vd, u32 vb) override - { - v128 VB = CPU.VPR[vb]; - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s8[w*4 + 3] = VB._s8[8 + w*2 + 1] >> 7; // signed shift sign extends - CPU.VPR[vd]._u8[w*4 + 2] = (VB._u8[8 + w*2 + 1] >> 2) & 0x1f; - CPU.VPR[vd]._u8[w*4 + 1] = ((VB._u8[8 + w*2 + 1] & 0x3) << 3) | ((VB._u8[8 + w*2 + 0] >> 5) & 0x7); - CPU.VPR[vd]._u8[w*4 + 0] = VB._u8[8 + w*2 + 0] & 0x1f; - } - } - void VUPKHSB(u32 vd, u32 vb) override - { - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = VB._s8[8 + h]; - } - } - void VUPKHSH(u32 vd, u32 vb) override - { - v128 VB = CPU.VPR[vb]; - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = VB._s16[4 + w]; - } - } - void VUPKLPX(u32 vd, u32 vb) override - { - v128 VB = CPU.VPR[vb]; - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s8[w*4 + 3] = VB._s8[w*2 + 1] >> 7; // signed shift sign extends - CPU.VPR[vd]._u8[w*4 + 2] = (VB._u8[w*2 + 1] >> 2) & 0x1f; - CPU.VPR[vd]._u8[w*4 + 1] = ((VB._u8[w*2 + 1] & 0x3) << 3) | ((VB._u8[w*2 + 0] >> 5) & 0x7); - CPU.VPR[vd]._u8[w*4 + 0] = VB._u8[w*2 + 0] & 0x1f; - } - } - void VUPKLSB(u32 vd, u32 vb) override //nf - { - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = VB._s8[h]; - } - } - void VUPKLSH(u32 vd, u32 vb) override - { - v128 VB = CPU.VPR[vb]; - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = VB._s16[w]; - } - } - void VXOR(u32 vd, u32 va, u32 vb) override - { - CPU.VPR[vd]._u32[0] = CPU.VPR[va]._u32[0] ^ CPU.VPR[vb]._u32[0]; - CPU.VPR[vd]._u32[1] = CPU.VPR[va]._u32[1] ^ CPU.VPR[vb]._u32[1]; - CPU.VPR[vd]._u32[2] = CPU.VPR[va]._u32[2] ^ CPU.VPR[vb]._u32[2]; - CPU.VPR[vd]._u32[3] = CPU.VPR[va]._u32[3] ^ CPU.VPR[vb]._u32[3]; - } - static void MULLI_impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16) - { - CPU->GPR[rd] = (s64)CPU->GPR[ra] * simm16; - } - void MULLI(u32 rd, u32 ra, s32 simm16) override - { - MULLI_impl(&CPU, rd, ra, simm16); - } - static void SUBFIC_impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16) - { - const u64 RA = CPU->GPR[ra]; - const u64 IMM = (s64)simm16; - CPU->GPR[rd] = ~RA + IMM + 1; - - CPU->XER.CA = CPU->IsCarry(~RA, IMM, 1); - } - void SUBFIC(u32 rd, u32 ra, s32 simm16) override - { - SUBFIC_impl(&CPU, rd, ra, simm16); - } - - static void CMPLI_impl(PPUThread *CPU, u32 crfd, u32 l, u32 ra, u32 uimm16) - { - CPU->UpdateCRnU(l, crfd, CPU->GPR[ra], uimm16); - } - void CMPLI(u32 crfd, u32 l, u32 ra, u32 uimm16) override - { - CMPLI_impl(&CPU, crfd, l, ra, uimm16); - } - - static void CMPI_impl(PPUThread *CPU, u32 crfd, u32 l, u32 ra, s32 simm16) - { - CPU->UpdateCRnS(l, crfd, CPU->GPR[ra], simm16); - } - void CMPI(u32 crfd, u32 l, u32 ra, s32 simm16) override - { - CMPI_impl(&CPU, crfd, l, ra, simm16); - } - - static void ADDIC_impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16) - { - const u64 RA = CPU->GPR[ra]; - CPU->GPR[rd] = RA + simm16; - CPU->XER.CA = CPU->IsCarry(RA, simm16); - } - void ADDIC(u32 rd, u32 ra, s32 simm16) override - { - ADDIC_impl(&CPU, rd, ra, simm16); - } - static void ADDIC__impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16) - { - const u64 RA = CPU->GPR[ra]; - CPU->GPR[rd] = RA + simm16; - CPU->XER.CA = CPU->IsCarry(RA, simm16); - CPU->UpdateCR0(CPU->GPR[rd]); - } - void ADDIC_(u32 rd, u32 ra, s32 simm16) override - { - ADDIC__impl(&CPU, rd, ra, simm16); - } - - static void ADDI_impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16) - { - CPU->GPR[rd] = ra ? ((s64)CPU->GPR[ra] + simm16) : simm16; - } - void ADDI(u32 rd, u32 ra, s32 simm16) override - { - ADDI_impl(&CPU, rd, ra, simm16); - } - - static void ADDIS_impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16) - { - CPU->GPR[rd] = ra ? ((s64)CPU->GPR[ra] + (static_cast(simm16) << 16)) : (static_cast(simm16) << 16); - } - void ADDIS(u32 rd, u32 ra, s32 simm16) override - { - ADDIS_impl(&CPU, rd, ra, simm16); - } - - void BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) override - { - if (CheckCondition(bo, bi)) - { - const u32 nextLR = CPU.PC + 4; - CPU.PC = branchTarget((aa ? 0 : CPU.PC), bd) - 4; - if(lk) CPU.LR = nextLR; - } - } - void HACK(u32 index) override - { - extern void execute_ppu_func_by_index(PPUThread& ppu, u32 index); - - execute_ppu_func_by_index(CPU, index); - } - void SC(u32 lev) override - { - extern void execute_syscall_by_index(PPUThread& ppu, u64 code); - - switch (lev) - { - case 0x0: execute_syscall_by_index(CPU, CPU.GPR[11]); break; - case 0x1: throw EXCEPTION("HyperCall LV1"); - case 0x3: CPU.fast_stop(); break; - default: throw EXCEPTION("Unknown level (0x%x)", lev); - } - } - void B(s32 ll, u32 aa, u32 lk) override - { - const u32 nextLR = CPU.PC + 4; - CPU.PC = branchTarget(aa ? 0 : CPU.PC, ll) - 4; - if(lk) CPU.LR = nextLR; - } - static void MCRF_impl(PPUThread *CPU, u32 crfd, u32 crfs) - { - CPU->SetCR(crfd, CPU->GetCR(crfs)); - } - void MCRF(u32 crfd, u32 crfs) override - { - MCRF_impl(&CPU, crfd, crfs); - } - void BCLR(u32 bo, u32 bi, u32 bh, u32 lk) override - { - if (CheckCondition(bo, bi)) - { - const u32 nextLR = CPU.PC + 4; - CPU.PC = branchTarget(0, (u32)CPU.LR) - 4; - if(lk) CPU.LR = nextLR; - } - } - static void CRNOR_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = 1 ^ (CPU->IsCR(crba) | CPU->IsCR(crbb)); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CRNOR(u32 crbd, u32 crba, u32 crbb) override - { - CRNOR_impl(&CPU, crbd, crba, crbb); - } - static void CRANDC_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = CPU->IsCR(crba) & (1 ^ CPU->IsCR(crbb)); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CRANDC(u32 crbd, u32 crba, u32 crbb) override - { - CRANDC_impl(&CPU, crbd, crba, crbb); - } - void ISYNC() override - { - _mm_mfence(); - } - static void CRXOR_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = CPU->IsCR(crba) ^ CPU->IsCR(crbb); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CRXOR(u32 crbd, u32 crba, u32 crbb) override - { - CRXOR_impl(&CPU, crbd, crba, crbb); - } - static void CRNAND_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = 1 ^ (CPU->IsCR(crba) & CPU->IsCR(crbb)); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CRNAND(u32 crbd, u32 crba, u32 crbb)override - { - CRNAND_impl(&CPU, crbd, crba, crbb); - } - static void CRAND_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = CPU->IsCR(crba) & CPU->IsCR(crbb); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CRAND(u32 crbd, u32 crba, u32 crbb) override - { - CRAND_impl(&CPU, crbd, crba, crbb); - } - static void CREQV_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = 1 ^ (CPU->IsCR(crba) ^ CPU->IsCR(crbb)); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CREQV(u32 crbd, u32 crba, u32 crbb) override - { - CREQV_impl(&CPU, crbd, crba, crbb); - } - static void CRORC_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = CPU->IsCR(crba) | (1 ^ CPU->IsCR(crbb)); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CRORC(u32 crbd, u32 crba, u32 crbb) override - { - CRORC_impl(&CPU, crbd, crba, crbb); - } - static void CROR_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = CPU->IsCR(crba) | CPU->IsCR(crbb); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CROR(u32 crbd, u32 crba, u32 crbb) override - { - CROR_impl(&CPU, crbd, crba, crbb); - } - void BCCTR(u32 bo, u32 bi, u32 bh, u32 lk) override - { - if(bo & 0x10 || CPU.IsCR(bi) == ((bo & 0x8) != 0)) - { - const u32 nextLR = CPU.PC + 4; - CPU.PC = branchTarget(0, (u32)CPU.CTR) - 4; - if(lk) CPU.LR = nextLR; - } - } - static void RLWIMI_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) - { - const u64 mask = rotate_mask[32 + mb][32 + me]; - CPU->GPR[ra] = (CPU->GPR[ra] & ~mask) | (rotl32(CPU->GPR[rs], sh) & mask); - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void RLWIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) override - { - RLWIMI_impl(&CPU, ra, rs, sh, mb, me, rc); - } - - static void RLWINM_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) - { - CPU->GPR[ra] = rotl32(CPU->GPR[rs], sh) & rotate_mask[32 + mb][32 + me]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void RLWINM(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) override - { - RLWINM_impl(&CPU, ra, rs, sh, mb, me, rc); - } - static void RLWNM_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rb, u32 mb, u32 me, u32 rc) - { - CPU->GPR[ra] = rotl32(CPU->GPR[rs], CPU->GPR[rb] & 0x1f) & rotate_mask[32 + mb][32 + me]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void RLWNM(u32 ra, u32 rs, u32 rb, u32 mb, u32 me, u32 rc) override - { - RLWNM_impl(&CPU, ra, rs, rb, mb, me, rc); - } - - static void ORI_impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16) - { - CPU->GPR[ra] = CPU->GPR[rs] | uimm16; - } - void ORI(u32 ra, u32 rs, u32 uimm16) override - { - ORI_impl(&CPU, ra, rs, uimm16); - } - static void ORIS_impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16) - { - CPU->GPR[ra] = CPU->GPR[rs] | ((u64)uimm16 << 16); - } - void ORIS(u32 ra, u32 rs, u32 uimm16) override - { - ORIS_impl(&CPU, ra, rs, uimm16); - } - static void XORI_impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16) - { - CPU->GPR[ra] = CPU->GPR[rs] ^ uimm16; - } - void XORI(u32 ra, u32 rs, u32 uimm16) override - { - XORI_impl(&CPU, ra, rs, uimm16); - } - static void XORIS_impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16) - { - CPU->GPR[ra] = CPU->GPR[rs] ^ ((u64)uimm16 << 16); - } - void XORIS(u32 ra, u32 rs, u32 uimm16) override - { - XORIS_impl(&CPU, ra, rs, uimm16); - } - static void ANDI__impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16) - { - CPU->GPR[ra] = CPU->GPR[rs] & uimm16; - CPU->UpdateCR0(CPU->GPR[ra]); - } - void ANDI_(u32 ra, u32 rs, u32 uimm16) override - { - ANDI__impl(&CPU, ra, rs, uimm16); - } - static void ANDIS__impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16) - { - CPU->GPR[ra] = CPU->GPR[rs] & ((u64)uimm16 << 16); - CPU->UpdateCR0(CPU->GPR[ra]); - } - void ANDIS_(u32 ra, u32 rs, u32 uimm16) override - { - ANDIS__impl(&CPU, ra, rs, uimm16); - } - - static - void RLDICL_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) - { - CPU->GPR[ra] = rotl64(CPU->GPR[rs], sh) & rotate_mask[mb][63]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) override - { - RLDICL_impl(&CPU, ra, rs, sh, mb, rc); - } - - static - void RLDICR_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 me, u32 rc) - { - CPU->GPR[ra] = rotl64(CPU->GPR[rs], sh) & rotate_mask[0][me]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - - void RLDICR(u32 ra, u32 rs, u32 sh, u32 me, u32 rc) override - { - RLDICR_impl(&CPU, ra, rs, sh, me, rc); - } - static void RLDIC_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) - { - CPU->GPR[ra] = rotl64(CPU->GPR[rs], sh) & rotate_mask[mb][63 - sh]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void RLDIC(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) override - { - RLDIC_impl(&CPU, ra, rs, sh, mb, rc); - } - static void RLDIMI_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) - { - const u64 mask = rotate_mask[mb][63 - sh]; - CPU->GPR[ra] = (CPU->GPR[ra] & ~mask) | (rotl64(CPU->GPR[rs], sh) & mask); - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void RLDIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) override - { - RLDIMI_impl(&CPU, ra, rs, sh, mb, rc); - } - static void RLDC_LR_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc) - { - if (is_r) // rldcr - { - RLDICR_impl(CPU, ra, rs, (u32)(CPU->GPR[rb] & 0x3F), m_eb, rc); - } - else // rldcl - { - RLDICL_impl(CPU, ra, rs, (u32)(CPU->GPR[rb] & 0x3F), m_eb, rc); - } - } - void RLDC_LR(u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc) override - { - RLDC_LR_impl(&CPU, ra, rs, rb, m_eb, is_r, rc); - } - - static void CMP_impl(PPUThread *CPU, u32 crfd, u32 l, u32 ra, u32 rb) - { - CPU->UpdateCRnS(l, crfd, CPU->GPR[ra], CPU->GPR[rb]); - } - void CMP(u32 crfd, u32 l, u32 ra, u32 rb) override - { - CMP_impl(&CPU, crfd, l, ra, rb); - } - - void TW(u32 to, u32 ra, u32 rb) override - { - s32 a = (s32)CPU.GPR[ra]; - s32 b = (s32)CPU.GPR[rb]; - - if( (a < b && (to & 0x10)) || - (a > b && (to & 0x8)) || - (a == b && (to & 0x4)) || - ((u32)a < (u32)b && (to & 0x2)) || - ((u32)a > (u32)b && (to & 0x1)) ) - { - throw EXCEPTION("Trap! (tw 0x%x, r%d, r%d)", to, ra, rb); - } - } - void LVSL(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - - static const u64 lvsl_values[0x10][2] = - { - {0x08090A0B0C0D0E0F, 0x0001020304050607}, - {0x090A0B0C0D0E0F10, 0x0102030405060708}, - {0x0A0B0C0D0E0F1011, 0x0203040506070809}, - {0x0B0C0D0E0F101112, 0x030405060708090A}, - {0x0C0D0E0F10111213, 0x0405060708090A0B}, - {0x0D0E0F1011121314, 0x05060708090A0B0C}, - {0x0E0F101112131415, 0x060708090A0B0C0D}, - {0x0F10111213141516, 0x0708090A0B0C0D0E}, - {0x1011121314151617, 0x08090A0B0C0D0E0F}, - {0x1112131415161718, 0x090A0B0C0D0E0F10}, - {0x1213141516171819, 0x0A0B0C0D0E0F1011}, - {0x131415161718191A, 0x0B0C0D0E0F101112}, - {0x1415161718191A1B, 0x0C0D0E0F10111213}, - {0x15161718191A1B1C, 0x0D0E0F1011121314}, - {0x161718191A1B1C1D, 0x0E0F101112131415}, - {0x1718191A1B1C1D1E, 0x0F10111213141516}, - }; - - CPU.VPR[vd]._u64[0] = lvsl_values[addr & 0xf][0]; - CPU.VPR[vd]._u64[1] = lvsl_values[addr & 0xf][1]; - } - void LVEBX(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.VPR[vd]._u8[15 - (addr & 0xf)] = vm::read8(VM_CAST(addr)); - // It's bad idea to read 128 bit there - } - void SUBFC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - const u64 RB = CPU.GPR[rb]; - CPU.GPR[rd] = ~RA + RB + 1; - CPU.XER.CA = CPU.IsCarry(~RA, RB, 1); - if(oe) CPU.SetOV((~RA>>63 == RB>>63) && (~RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void MULHDU(u32 rd, u32 ra, u32 rb, u32 rc) override - { - CPU.GPR[rd] = UMULH64(CPU.GPR[ra], CPU.GPR[rb]); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void ADDC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - const u64 RB = CPU.GPR[rb]; - CPU.GPR[rd] = RA + RB; - CPU.XER.CA = CPU.IsCarry(RA, RB); - if(oe) CPU.SetOV((RA>>63 == RB>>63) && (RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void MULHWU(u32 rd, u32 ra, u32 rb, u32 rc) override - { - u32 a = (u32)CPU.GPR[ra]; - u32 b = (u32)CPU.GPR[rb]; - CPU.GPR[rd] = ((u64)a * (u64)b) >> 32; - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - - static void MFOCRF_impl(PPUThread *CPU, u32 a, u32 rd, u32 crm) - { - CPU->GPR[rd] = CPU->CR.CR; - } - void MFOCRF(u32 a, u32 rd, u32 crm) override - { - MFOCRF_impl(&CPU, a, rd, crm); - } - static void LWARX_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb) - { - const u64 addr = ra ? CPU->GPR[ra] + CPU->GPR[rb] : CPU->GPR[rb]; - - be_t value; - vm::reservation_acquire(&value, VM_CAST(addr), sizeof(value)); - - CPU->GPR[rd] = value; - } - void LWARX(u32 rd, u32 ra, u32 rb) override - { - LWARX_impl(&CPU, rd, ra, rb); - } - void LDX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::read64(VM_CAST(addr)); - } - void LWZX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::read32(VM_CAST(addr)); - } - void SLW(u32 ra, u32 rs, u32 rb, u32 rc) override - { - u32 n = CPU.GPR[rb] & 0x1f; - u32 r = (u32)rotl32((u32)CPU.GPR[rs], n); - u32 m = ((u32)CPU.GPR[rb] & 0x20) ? 0 : (u32)rotate_mask[32][63 - n]; - - CPU.GPR[ra] = r & m; - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void CNTLZW(u32 ra, u32 rs, u32 rc) override - { - u32 i; - for(i=0; i < 32; i++) - { - if(CPU.GPR[rs] & (1ULL << (31 - i))) break; - } - - CPU.GPR[ra] = i; - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void SLD(u32 ra, u32 rs, u32 rb, u32 rc) override - { - u32 n = CPU.GPR[rb] & 0x3f; - u64 r = rotl64(CPU.GPR[rs], n); - u64 m = (CPU.GPR[rb] & 0x40) ? 0 : rotate_mask[0][63 - n]; - - CPU.GPR[ra] = r & m; - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - - static void AND_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rb, u32 rc) - { - CPU->GPR[ra] = CPU->GPR[rs] & CPU->GPR[rb]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void AND(u32 ra, u32 rs, u32 rb, u32 rc) override - { - AND_impl(&CPU, ra, rs, rb, rc); - } - - static void CMPL_impl(PPUThread *CPU, u32 crfd, u32 l, u32 ra, u32 rb) - { - CPU->UpdateCRnU(l, crfd, CPU->GPR[ra], CPU->GPR[rb]); - } - void CMPL(u32 crfd, u32 l, u32 ra, u32 rb) override - { - CMPL_impl(&CPU, crfd, l, ra, rb); - } - - void LVSR(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - - static const u64 lvsr_values[0x10][2] = - { - {0x18191A1B1C1D1E1F, 0x1011121314151617}, - {0x1718191A1B1C1D1E, 0x0F10111213141516}, - {0x161718191A1B1C1D, 0x0E0F101112131415}, - {0x15161718191A1B1C, 0x0D0E0F1011121314}, - {0x1415161718191A1B, 0x0C0D0E0F10111213}, - {0x131415161718191A, 0x0B0C0D0E0F101112}, - {0x1213141516171819, 0x0A0B0C0D0E0F1011}, - {0x1112131415161718, 0x090A0B0C0D0E0F10}, - {0x1011121314151617, 0x08090A0B0C0D0E0F}, - {0x0F10111213141516, 0x0708090A0B0C0D0E}, - {0x0E0F101112131415, 0x060708090A0B0C0D}, - {0x0D0E0F1011121314, 0x05060708090A0B0C}, - {0x0C0D0E0F10111213, 0x0405060708090A0B}, - {0x0B0C0D0E0F101112, 0x030405060708090A}, - {0x0A0B0C0D0E0F1011, 0x0203040506070809}, - {0x090A0B0C0D0E0F10, 0x0102030405060708}, - }; - - CPU.VPR[vd]._u64[0] = lvsr_values[addr & 0xf][0]; - CPU.VPR[vd]._u64[1] = lvsr_values[addr & 0xf][1]; - } - void LVEHX(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~1ULL; - CPU.VPR[vd]._u16[7 - ((addr >> 1) & 0x7)] = vm::ps3::read16(VM_CAST(addr)); - // It's bad idea to read 128 bit there - } - - static void SUBF_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - const u64 RA = CPU->GPR[ra]; - const u64 RB = CPU->GPR[rb]; - CPU->GPR[rd] = RB - RA; - if(oe) CPU->SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != CPU->GPR[rd] >> 63)); - if(rc) CPU->UpdateCR0(CPU->GPR[rd]); - } - void SUBF(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - SUBF_impl(&CPU, rd, ra, rb, oe, rc); - } - - void LDUX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::read64(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void DCBST(u32 ra, u32 rb) override - { - } - void LWZUX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::read32(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void CNTLZD(u32 ra, u32 rs, u32 rc) override - { - u32 i; - for(i=0; i < 64; i++) - { - if(CPU.GPR[rs] & (1ULL << (63 - i))) break; - } - - CPU.GPR[ra] = i; - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void ANDC(u32 ra, u32 rs, u32 rb, u32 rc) override - { - CPU.GPR[ra] = CPU.GPR[rs] & ~CPU.GPR[rb]; - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void TD(u32 to, u32 ra, u32 rb) override - { - throw EXCEPTION(""); - } - void LVEWX(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~3ULL; - CPU.VPR[vd]._u32[3 - ((addr >> 2) & 0x3)] = vm::ps3::read32(VM_CAST(addr)); - // It's bad idea to read 128 bit there - } - void MULHD(u32 rd, u32 ra, u32 rb, u32 rc) override - { - CPU.GPR[rd] = MULH64(CPU.GPR[ra], CPU.GPR[rb]); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void MULHW(u32 rd, u32 ra, u32 rb, u32 rc) override - { - s32 a = (s32)CPU.GPR[ra]; - s32 b = (s32)CPU.GPR[rb]; - CPU.GPR[rd] = ((s64)a * (s64)b) >> 32; - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void LDARX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - - be_t value; - vm::reservation_acquire(&value, VM_CAST(addr), sizeof(value)); - - CPU.GPR[rd] = value; - } - void DCBF(u32 ra, u32 rb) override - { - } - void LBZX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::read8(VM_CAST(addr)); - } - void LVX(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfull; - CPU.VPR[vd] = vm::ps3::_ref(VM_CAST(addr)); - } - - static void NEG_impl(PPUThread *CPU, u32 rd, u32 ra, u32 oe, u32 rc) - { - const u64 RA = CPU->GPR[ra]; - CPU->GPR[rd] = 0 - RA; - if(oe) CPU->SetOV((~RA >> 63 == 0) && (~RA >> 63 != CPU->GPR[rd] >> 63)); - if(rc) CPU->UpdateCR0(CPU->GPR[rd]); - } - void NEG(u32 rd, u32 ra, u32 oe, u32 rc) override - { - NEG_impl(&CPU, rd, ra, oe, rc); - } - - void LBZUX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - CPU.GPR[rd] = vm::read8(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void NOR(u32 ra, u32 rs, u32 rb, u32 rc) override - { - CPU.GPR[ra] = ~(CPU.GPR[rs] | CPU.GPR[rb]); - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void STVEBX(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u8 eb = addr & 0xf; - vm::write8(VM_CAST(addr), CPU.VPR[vs]._u8[15 - eb]); - } - void SUBFE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - const u64 RB = CPU.GPR[rb]; - CPU.GPR[rd] = ~RA + RB + CPU.XER.CA; - CPU.XER.CA = CPU.IsCarry(~RA, RB, CPU.XER.CA); - if(oe) CPU.SetOV((~RA>>63 == RB>>63) && (~RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void ADDE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - const u64 RB = CPU.GPR[rb]; - if (CPU.XER.CA) - { - if (RA == ~0ULL) //-1 - { - CPU.GPR[rd] = RB; - CPU.XER.CA = 1; - } - else - { - CPU.GPR[rd] = RA + 1 + RB; - CPU.XER.CA = CPU.IsCarry(RA + 1, RB); - } - } - else - { - CPU.GPR[rd] = RA + RB; - CPU.XER.CA = CPU.IsCarry(RA, RB); - } - if(oe) CPU.SetOV((RA>>63 == RB>>63) && (RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - - static void MTOCRF_impl(PPUThread *CPU, u32 l, u32 crm, u32 rs) - { - if(l) - { - u32 n = 0, count = 0; - for(u32 i=0; i<8; ++i) - { - if (crm & (1 << i)) - { - n = i; - count++; - } - } - - if(count == 1) - { - //CR[4*n : 4*n+3] = RS[32+4*n : 32+4*n+3]; - CPU->SetCR(7 - n, (CPU->GPR[rs] >> (4 * n)) & 0xf); - } - else - CPU->CR.CR = 0; - } - else - { - for(u32 i=0; i<8; ++i) - { - if(crm & (1 << i)) - { - CPU->SetCR(7 - i, (CPU->GPR[rs] >> (i * 4)) & 0xf); - } - } - } - } - void MTOCRF(u32 l, u32 crm, u32 rs) override - { - MTOCRF_impl(&CPU, l, crm, rs); - } - - void STDX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::write64(VM_CAST(addr), CPU.GPR[rs]); - } - static void STWCX__impl(PPUThread* CPU, u32 rs, u32 ra, u32 rb) - { - const u64 addr = ra ? CPU->GPR[ra] + CPU->GPR[rb] : CPU->GPR[rb]; - - const be_t value = (u32)CPU->GPR[rs]; - CPU->SetCR_EQ(0, vm::reservation_update(VM_CAST(addr), &value, sizeof(value))); - } - void STWCX_(u32 rs, u32 ra, u32 rb) override - { - STWCX__impl(&CPU, rs, ra, rb); - } - void STWX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); - } - void STVEHX(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~1ULL; - const u8 eb = (addr & 0xf) >> 1; - vm::ps3::write16(VM_CAST(addr), CPU.VPR[vs]._u16[7 - eb]); - } - void STDUX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - vm::ps3::write64(VM_CAST(addr), CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - void STWUX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - void STVEWX(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~3ULL; - const u8 eb = (addr & 0xf) >> 2; - vm::ps3::write32(VM_CAST(addr), CPU.VPR[vs]._u32[3 - eb]); - } - void SUBFZE(u32 rd, u32 ra, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - CPU.GPR[rd] = ~RA + CPU.XER.CA; - CPU.XER.CA = CPU.IsCarry(~RA, CPU.XER.CA); - if(oe) CPU.SetOV((~RA>>63 == 0) && (~RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void ADDZE(u32 rd, u32 ra, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - CPU.GPR[rd] = RA + CPU.XER.CA; - CPU.XER.CA = CPU.IsCarry(RA, CPU.XER.CA); - if(oe) CPU.SetOV((RA>>63 == 0) && (RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void STDCX_(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - - const be_t value = CPU.GPR[rs]; - CPU.SetCR_EQ(0, vm::reservation_update(VM_CAST(addr), &value, sizeof(value))); - } - void STBX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[rs]); - } - void STVX(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfull; - vm::ps3::_ref(VM_CAST(addr)) = CPU.VPR[vs]; - } - void MULLD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const s64 RA = CPU.GPR[ra]; - const s64 RB = CPU.GPR[rb]; - CPU.GPR[rd] = (s64)(RA * RB); - if(oe) - { - const s64 high = MULH64(RA, RB); - CPU.SetOV(high != s64(CPU.GPR[rd]) >> 63); - } - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void SUBFME(u32 rd, u32 ra, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - CPU.GPR[rd] = ~RA + CPU.XER.CA + ~0ULL; - CPU.XER.CA = CPU.IsCarry(~RA, CPU.XER.CA, ~0ULL); - if(oe) CPU.SetOV((~RA>>63 == 1) && (~RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void ADDME(u32 rd, u32 ra, u32 oe, u32 rc) override - { - const s64 RA = CPU.GPR[ra]; - CPU.GPR[rd] = RA + CPU.XER.CA - 1; - CPU.XER.CA |= RA != 0; - - if(oe) CPU.SetOV((u64(RA)>>63 == 1) && (u64(RA)>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - - static void MULLW_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - CPU->GPR[rd] = (s64)((s64)(s32)CPU->GPR[ra] * (s64)(s32)CPU->GPR[rb]); - if(oe) CPU->SetOV(s64(CPU->GPR[rd]) < s64(-1) << 31 || s64(CPU->GPR[rd]) >= s64(1) << 31); - if(rc) CPU->UpdateCR0(CPU->GPR[rd]); - } - void MULLW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - MULLW_impl(&CPU, rd, ra, rb, oe, rc); - } - - void DCBTST(u32 ra, u32 rb, u32 th) override - { - } - void STBUX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - - static void ADD_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - const u64 RA = CPU->GPR[ra]; - const u64 RB = CPU->GPR[rb]; - CPU->GPR[rd] = RA + RB; - if(oe) CPU->SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != CPU->GPR[rd] >> 63)); - if(rc) CPU->UpdateCR0(CPU->GPR[rd]); - } - void ADD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - ADD_impl(&CPU, rd, ra, rb, oe, rc); - } - - void DCBT(u32 ra, u32 rb, u32 th) override - { - } - void LHZX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::read16(VM_CAST(addr)); - } - void EQV(u32 ra, u32 rs, u32 rb, u32 rc) override - { - CPU.GPR[ra] = ~(CPU.GPR[rs] ^ CPU.GPR[rb]); - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void ECIWX(u32 rd, u32 ra, u32 rb) override - { - throw EXCEPTION("Privileged instruction"); - } - void LHZUX(u32 rd, u32 ra, u32 rb)override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::read16(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void XOR(u32 ra, u32 rs, u32 rb, u32 rc) override - { - CPU.GPR[ra] = CPU.GPR[rs] ^ CPU.GPR[rb]; - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void MFSPR(u32 rd, u32 spr) override - { - CPU.GPR[rd] = ReadSPR(spr); - } - void LWAX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = (s64)(s32)vm::ps3::read32(VM_CAST(addr)); - } - void DST(u32 ra, u32 rb, u32 strm, u32 t) override - { - } - void LHAX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = (s64)(s16)vm::ps3::read16(VM_CAST(addr)); - } - void LVXL(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfull; - CPU.VPR[vd] = vm::ps3::_ref(VM_CAST(addr)); - } - void MFTB(u32 rd, u32 spr) override - { - const u32 n = (spr >> 5) | ((spr & 0x1f) << 5); - - CPU.TB = get_timebased_time(); - switch(n) - { - case 0x10C: CPU.GPR[rd] = CPU.TB; break; - case 0x10D: CPU.GPR[rd] = CPU.TB >> 32; break; - default: throw EXCEPTION("mftb r%d, %d", rd, spr); - } - } - void LWAUX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = (s64)(s32)vm::ps3::read32(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void DSTST(u32 ra, u32 rb, u32 strm, u32 t) override - { - } - void LHAUX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = (s64)(s16)vm::ps3::read16(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void STHX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::write16(VM_CAST(addr), (u16)CPU.GPR[rs]); - } - void ORC(u32 ra, u32 rs, u32 rb, u32 rc) override - { - CPU.GPR[ra] = CPU.GPR[rs] | ~CPU.GPR[rb]; - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void ECOWX(u32 rs, u32 ra, u32 rb) override - { - throw EXCEPTION("Privileged instruction"); - } - void STHUX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - vm::ps3::write16(VM_CAST(addr), (u16)CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - - static void OR_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rb, u32 rc) - { - CPU->GPR[ra] = CPU->GPR[rs] | CPU->GPR[rb]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void OR(u32 ra, u32 rs, u32 rb, u32 rc) override - { - OR_impl(&CPU, ra, rs, rb, rc); - } - - void DIVDU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - const u64 RB = CPU.GPR[rb]; - - if(RB == 0) - { - if(oe) CPU.SetOV(true); - CPU.GPR[rd] = 0; - } - else - { - if(oe) CPU.SetOV(false); - CPU.GPR[rd] = RA / RB; - } - - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - - static void DIVWU_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - const u32 RA = (u32)CPU->GPR[ra]; - const u32 RB = (u32)CPU->GPR[rb]; - - if(RB == 0) - { - if(oe) CPU->SetOV(true); - CPU->GPR[rd] = 0; - } - else - { - if(oe) CPU->SetOV(false); - CPU->GPR[rd] = RA / RB; - } - - if(rc) CPU->UpdateCR0(CPU->GPR[rd]); - } - void DIVWU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - DIVWU_impl(&CPU, rd, ra, rb, oe, rc); - } - - void MTSPR(u32 spr, u32 rs) override - { - WriteSPR(spr, CPU.GPR[rs]); - } - void DCBI(u32 ra, u32 rb) override - { - } - void NAND(u32 ra, u32 rs, u32 rb, u32 rc) override - { - CPU.GPR[ra] = ~(CPU.GPR[rs] & CPU.GPR[rb]); - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void STVXL(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfull; - vm::ps3::_ref(VM_CAST(addr)) = CPU.VPR[vs]; - } - void DIVD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const s64 RA = CPU.GPR[ra]; - const s64 RB = CPU.GPR[rb]; - - if (RB == 0 || ((u64)RA == (1ULL << 63) && RB == -1)) - { - if(oe) CPU.SetOV(true); - CPU.GPR[rd] = /*(((u64)RA & (1ULL << 63)) && RB == 0) ? -1 :*/ 0; - } - else - { - if(oe) CPU.SetOV(false); - CPU.GPR[rd] = RA / RB; - } - - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - - static void DIVW_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - const s32 RA = (s32)CPU->GPR[ra]; - const s32 RB = (s32)CPU->GPR[rb]; - - if (RB == 0 || ((u32)RA == (1 << 31) && RB == -1)) - { - if(oe) CPU->SetOV(true); - CPU->GPR[rd] = /*(((u32)RA & (1 << 31)) && RB == 0) ? -1 :*/ 0; - } - else - { - if(oe) CPU->SetOV(false); - CPU->GPR[rd] = (u32)(RA / RB); - } - - if(rc) CPU->UpdateCR0(CPU->GPR[rd]); - } - void DIVW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - DIVW_impl(&CPU, rd, ra, rb, oe, rc); - } - - void LVLX(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u32 eb = addr & 0xf; - - CPU.VPR[vd].clear(); - for (u32 i = 0; i < 16u - eb; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i)); - } - void LDBRX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::_ref>(VM_CAST(addr)); - } - void LSWX(u32 rd, u32 ra, u32 rb) override - { - u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - u32 count = CPU.XER.XER & 0x7F; - for (; count >= 4; count -= 4, addr += 4, rd = (rd+1) & 31) - { - CPU.GPR[rd] = vm::ps3::_ref(VM_CAST(addr)); - } - if (count) - { - u32 value = 0; - for (u32 byte = 0; byte < count; byte++) - { - u32 byte_value = vm::ps3::_ref(VM_CAST(addr+byte)); - value |= byte_value << ((3^byte)*8); - } - CPU.GPR[rd] = value; - } - } - void LWBRX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::_ref>(VM_CAST(addr)); - } - void LFSX(u32 frd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const f32 val = vm::ps3::_ref(VM_CAST(addr)); - if (!FPRdouble::IsNaN(val)) - { - CPU.FPR[frd] = val; - } - else - { - u64 bits = (u32&)val; - (u64&)CPU.FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29; - } - } - void SRW(u32 ra, u32 rs, u32 rb, u32 rc) override - { - u32 n = CPU.GPR[rb] & 0x1f; - u32 r = (u32)rotl32((u32)CPU.GPR[rs], 64 - n); - u32 m = ((u32)CPU.GPR[rb] & 0x20) ? 0 : (u32)rotate_mask[32 + n][63]; - CPU.GPR[ra] = r & m; - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void SRD(u32 ra, u32 rs, u32 rb, u32 rc) override - { - u32 n = CPU.GPR[rb] & 0x3f; - u64 r = rotl64(CPU.GPR[rs], 64 - n); - u64 m = (CPU.GPR[rb] & 0x40) ? 0 : rotate_mask[n][63]; - CPU.GPR[ra] = r & m; - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void LVRX(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u8 eb = addr & 0xf; - - CPU.VPR[vd].clear(); - for (u32 i = 16 - eb; i < 16; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i - 16)); - } - void LSWI(u32 rd, u32 ra, u32 nb) override - { - u64 addr = ra ? CPU.GPR[ra] : 0; - u64 N = nb ? nb : 32; - u8 reg = rd; - - while (N > 0) - { - if (N > 3) - { - CPU.GPR[reg] = vm::ps3::read32(VM_CAST(addr)); - addr += 4; - N -= 4; - } - else - { - u32 buf = 0; - u32 i = 3; - while (N > 0) - { - N = N - 1; - buf |= vm::read8(VM_CAST(addr)) << (i * 8); - addr++; - i--; - } - CPU.GPR[reg] = buf; - } - reg = (reg + 1) % 32; - } - } - void LFSUX(u32 frd, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - const f32 val = vm::ps3::_ref(VM_CAST(addr)); - if (!FPRdouble::IsNaN(val)) - { - CPU.FPR[frd] = val; - } - else - { - u64 bits = (u32&)val; - (u64&)CPU.FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29; - } - CPU.GPR[ra] = addr; - } - void SYNC(u32 l) override - { - _mm_mfence(); - } - void LFDX(u32 frd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.FPR[frd]._double = vm::ps3::_ref(VM_CAST(addr)); - } - void LFDUX(u32 frd, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - CPU.FPR[frd]._double = vm::ps3::_ref(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void STVLX(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u32 eb = addr & 0xf; - - for (u32 i = 0; i < 16u - eb; ++i) vm::write8(VM_CAST(addr + i), CPU.VPR[vs]._u8[15 - i]); - } - void STDBRX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::_ref>(VM_CAST(addr)) = CPU.GPR[rs]; - } - void STSWX(u32 rs, u32 ra, u32 rb) override - { - u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - u32 count = CPU.XER.XER & 0x7F; - for (; count >= 4; count -= 4, addr += 4, rs = (rs+1) & 31) - { - vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); - } - if (count) - { - u32 value = (u32)CPU.GPR[rs]; - for (u32 byte = 0; byte < count; byte++) - { - u32 byte_value = (u8)(value >> ((3^byte)*8)); - vm::write8(VM_CAST(addr+byte), byte_value); - } - } - } - void STWBRX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::_ref>(VM_CAST(addr)) = (u32)CPU.GPR[rs]; - } - void STFSX(u32 frs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - double val = CPU.FPR[frs]; - if (!FPRdouble::IsNaN(val)) - { - vm::ps3::_ref(VM_CAST(addr)) = (float)val; - } - else - { - u64 bits = (u64&)val; - u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff); - vm::ps3::_ref(VM_CAST(addr)) = bits32; - } - } - void STVRX(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u8 eb = addr & 0xf; - - for (u32 i = 16 - eb; i < 16; ++i) vm::write8(VM_CAST(addr + i - 16), CPU.VPR[vs]._u8[15 - i]); - } - void STFSUX(u32 frs, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - double val = CPU.FPR[frs]; - if (!FPRdouble::IsNaN(val)) - { - vm::ps3::_ref(VM_CAST(addr)) = (float)val; - } - else - { - u64 bits = (u64&)val; - u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff); - vm::ps3::_ref(VM_CAST(addr)) = bits32; - } - CPU.GPR[ra] = addr; - } - void STSWI(u32 rd, u32 ra, u32 nb) override - { - u64 addr = ra ? CPU.GPR[ra] : 0; - u64 N = nb ? nb : 32; - u8 reg = rd; - - while (N > 0) - { - if (N > 3) - { - vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[reg]); - addr += 4; - N -= 4; - } - else - { - u32 buf = (u32)CPU.GPR[reg]; - while (N > 0) - { - N = N - 1; - vm::write8(VM_CAST(addr), (0xFF000000 & buf) >> 24); - buf <<= 8; - addr++; - } - } - reg = (reg + 1) % 32; - } - } - void STFDX(u32 frs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::_ref(VM_CAST(addr)) = CPU.FPR[frs]; - } - void STFDUX(u32 frs, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - vm::ps3::_ref(VM_CAST(addr)) = CPU.FPR[frs]; - CPU.GPR[ra] = addr; - } - void LVLXL(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u32 eb = addr & 0xf; - - CPU.VPR[vd].clear(); - for (u32 i = 0; i < 16u - eb; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i)); - } - void LHBRX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::_ref>(VM_CAST(addr)); - } - void SRAW(u32 ra, u32 rs, u32 rb, u32 rc) override - { - s32 RS = (s32)CPU.GPR[rs]; - u8 shift = CPU.GPR[rb] & 63; - if (shift > 31) - { - CPU.GPR[ra] = 0 - (RS < 0); - CPU.XER.CA = (RS < 0); - } - else - { - CPU.GPR[ra] = RS >> shift; - CPU.XER.CA = (RS < 0) & ((CPU.GPR[ra] << shift) != RS); - } - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void SRAD(u32 ra, u32 rs, u32 rb, u32 rc) override - { - s64 RS = CPU.GPR[rs]; - u8 shift = CPU.GPR[rb] & 127; - if (shift > 63) - { - CPU.GPR[ra] = 0 - (RS < 0); - CPU.XER.CA = (RS < 0); - } - else - { - CPU.GPR[ra] = RS >> shift; - CPU.XER.CA = (RS < 0) & ((CPU.GPR[ra] << shift) != RS); - } - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void LVRXL(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u8 eb = addr & 0xf; - - CPU.VPR[vd].clear(); - for (u32 i = 16 - eb; i < 16; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i - 16)); - } - void DSS(u32 strm, u32 a) override - { - } - - static void SRAWI_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 rc) - { - s32 RS = (u32)CPU->GPR[rs]; - CPU->GPR[ra] = RS >> sh; - CPU->XER.CA = (RS < 0) & ((u32)(CPU->GPR[ra] << sh) != RS); - - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void SRAWI(u32 ra, u32 rs, u32 sh, u32 rc) override - { - SRAWI_impl(&CPU, ra, rs, sh, rc); - } - - void SRADI1(u32 ra, u32 rs, u32 sh, u32 rc) override - { - s64 RS = CPU.GPR[rs]; - CPU.GPR[ra] = RS >> sh; - CPU.XER.CA = (RS < 0) & ((CPU.GPR[ra] << sh) != RS); - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void SRADI2(u32 ra, u32 rs, u32 sh, u32 rc) override - { - SRADI1(ra, rs, sh, rc); - } - void EIEIO() override - { - _mm_mfence(); - } - void STVLXL(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u32 eb = addr & 0xf; - - for (u32 i = 0; i < 16u - eb; ++i) vm::write8(VM_CAST(addr + i), CPU.VPR[vs]._u8[15 - i]); - } - void STHBRX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::_ref>(VM_CAST(addr)) = (u16)CPU.GPR[rs]; - } - void EXTSH(u32 ra, u32 rs, u32 rc) override - { - CPU.GPR[ra] = (s64)(s16)CPU.GPR[rs]; - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void STVRXL(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u8 eb = addr & 0xf; - - for (u32 i = 16 - eb; i < 16; ++i) vm::write8(VM_CAST(addr + i - 16), CPU.VPR[vs]._u8[15 - i]); - } - - static void EXTSB_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rc) - { - CPU->GPR[ra] = (s64)(s8)CPU->GPR[rs]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void EXTSB(u32 ra, u32 rs, u32 rc) override - { - EXTSB_impl(&CPU, ra, rs, rc); - } - - void STFIWX(u32 frs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::write32(VM_CAST(addr), (u32&)CPU.FPR[frs]); - } - - static void EXTSW_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rc) - { - CPU->GPR[ra] = (s64)(s32)CPU->GPR[rs]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void EXTSW(u32 ra, u32 rs, u32 rc) override - { - EXTSW_impl(&CPU, ra, rs, rc); - } - - void ICBI(u32 ra, u32 rs) override - { - // Clear jit for the specified block? Nothing to do in the interpreter. - } - void DCBZ(u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - - std::memset(vm::base(VM_CAST(addr) & ~127), 0, 128); - } - - static void LWZ_impl(PPUThread *CPU, u32 rd, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - CPU->GPR[rd] = vm::ps3::read32(VM_CAST(addr)); - } - void LWZ(u32 rd, u32 ra, s32 d) override - { - LWZ_impl(&CPU, rd, ra, d); - } - - void LWZU(u32 rd, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - CPU.GPR[rd] = vm::ps3::read32(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - - static void LBZ_impl(PPUThread *CPU, u32 rd, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - CPU->GPR[rd] = vm::read8(VM_CAST(addr)); - } - void LBZ(u32 rd, u32 ra, s32 d) override - { - LBZ_impl(&CPU, rd, ra, d); - } - - void LBZU(u32 rd, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - CPU.GPR[rd] = vm::read8(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - - static void STW_impl(PPUThread *CPU, u32 rs, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - vm::ps3::write32(VM_CAST(addr), (u32)CPU->GPR[rs]); - } - void STW(u32 rs, u32 ra, s32 d) override - { - STW_impl(&CPU, rs, ra, d); - } - - void STWU(u32 rs, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - void STB(u32 rs, u32 ra, s32 d) override - { - const u64 addr = ra ? CPU.GPR[ra] + d : d; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[rs]); - } - void STBU(u32 rs, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - static void LHZ_impl(PPUThread *CPU, u32 rd, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - CPU->GPR[rd] = vm::ps3::read16(VM_CAST(addr)); - } - void LHZ(u32 rd, u32 ra, s32 d) override - { - LHZ_impl(&CPU, rd, ra, d); - } - void LHZU(u32 rd, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - CPU.GPR[rd] = vm::ps3::read16(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void LHA(u32 rd, u32 ra, s32 d) override - { - const u64 addr = ra ? CPU.GPR[ra] + d : d; - CPU.GPR[rd] = (s64)(s16)vm::ps3::read16(VM_CAST(addr)); - } - void LHAU(u32 rd, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - CPU.GPR[rd] = (s64)(s16)vm::ps3::read16(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void STH(u32 rs, u32 ra, s32 d) override - { - const u64 addr = ra ? CPU.GPR[ra] + d : d; - vm::ps3::write16(VM_CAST(addr), (u16)CPU.GPR[rs]); - } - void STHU(u32 rs, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - vm::ps3::write16(VM_CAST(addr), (u16)CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - void LMW(u32 rd, u32 ra, s32 d) override - { - u64 addr = ra ? CPU.GPR[ra] + d : d; - for(u32 i=rd; i<32; ++i, addr += 4) - { - CPU.GPR[i] = vm::ps3::read32(VM_CAST(addr)); - } - } - void STMW(u32 rs, u32 ra, s32 d) override - { - u64 addr = ra ? CPU.GPR[ra] + d : d; - for(u32 i=rs; i<32; ++i, addr += 4) - { - vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[i]); - } - } - - static void LFS_impl(PPUThread *CPU, u32 frd, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - const f32 val = vm::ps3::_ref(VM_CAST(addr)); - if (!FPRdouble::IsNaN(val)) - { - CPU->FPR[frd] = val; - } - else - { - u64 bits = (u32&)val; - (u64&)CPU->FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29; - } - } - void LFS(u32 frd, u32 ra, s32 d) override - { - LFS_impl(&CPU, frd, ra, d); - } - - void LFSU(u32 frd, u32 ra, s32 ds) override - { - const u64 addr = CPU.GPR[ra] + ds; - const f32 val = vm::ps3::_ref(VM_CAST(addr)); - if (!FPRdouble::IsNaN(val)) - { - CPU.FPR[frd] = val; - } - else - { - u64 bits = (u32&)val; - (u64&)CPU.FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29; - } - CPU.GPR[ra] = addr; - } - void LFD(u32 frd, u32 ra, s32 d) override - { - const u64 addr = ra ? CPU.GPR[ra] + d : d; - CPU.FPR[frd]._double = vm::ps3::_ref(VM_CAST(addr)); - } - void LFDU(u32 frd, u32 ra, s32 ds) override - { - const u64 addr = CPU.GPR[ra] + ds; - CPU.FPR[frd]._double = vm::ps3::_ref(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - - static void STFS_impl(PPUThread *CPU, u32 frs, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - double val = CPU->FPR[frs]; - if (!FPRdouble::IsNaN(val)) - { - vm::ps3::_ref(VM_CAST(addr)) = (float)val; - } - else - { - u64 bits = (u64&)val; - u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff); - vm::ps3::_ref(VM_CAST(addr)) = bits32; - } - } - void STFS(u32 frs, u32 ra, s32 d) override - { - STFS_impl(&CPU, frs, ra, d); - } - - void STFSU(u32 frs, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - double val = CPU.FPR[frs]; - if (!FPRdouble::IsNaN(val)) - { - vm::ps3::_ref(VM_CAST(addr)) = (float)val; - } - else - { - u64 bits = (u64&)val; - u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff); - vm::ps3::_ref(VM_CAST(addr)) = bits32; - } - CPU.GPR[ra] = addr; - } - void STFD(u32 frs, u32 ra, s32 d) override - { - const u64 addr = ra ? CPU.GPR[ra] + d : d; - vm::ps3::_ref(VM_CAST(addr)) = CPU.FPR[frs]; - } - void STFDU(u32 frs, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - vm::ps3::_ref(VM_CAST(addr)) = CPU.FPR[frs]; - CPU.GPR[ra] = addr; - } - - static void LD_impl(PPUThread *CPU, u32 rd, u32 ra, s32 ds) - { - const u64 addr = ra ? CPU->GPR[ra] + ds : ds; - CPU->GPR[rd] = vm::ps3::read64(VM_CAST(addr)); - } - void LD(u32 rd, u32 ra, s32 ds) override - { - LD_impl(&CPU, rd, ra, ds); - } - - void LDU(u32 rd, u32 ra, s32 ds) override - { - const u64 addr = CPU.GPR[ra] + ds; - CPU.GPR[rd] = vm::ps3::read64(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void LWA(u32 rd, u32 ra, s32 ds) override - { - const u64 addr = ra ? CPU.GPR[ra] + ds : ds; - CPU.GPR[rd] = (s64)(s32)vm::ps3::read32(VM_CAST(addr)); - } - void FDIVS(u32 frd, u32 fra, u32 frb, u32 rc) override {FDIV(frd, fra, frb, rc, true);} - void FSUBS(u32 frd, u32 fra, u32 frb, u32 rc) override {FSUB(frd, fra, frb, rc, true);} - void FADDS(u32 frd, u32 fra, u32 frb, u32 rc) override {FADD(frd, fra, frb, rc, true);} - void FSQRTS(u32 frd, u32 frb, u32 rc) override {FSQRT(frd, frb, rc, true);} - void FRES(u32 frd, u32 frb, u32 rc) override - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double b = CPU.FPR[frb]; - if(FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(b == 0.0) - { - CPU.SetFPSCRException(FPSCR_ZX); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if (CPU.FPSCR.ZE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = 1.0 / b; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - CPU.FPR[frd] = static_cast(1.0 / b); - CheckHostFPExceptions(); - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FMULS(u32 frd, u32 fra, u32 frc, u32 rc) override {FMUL(frd, fra, frc, rc, true);} - void FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, false, false, true);} - void FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, false, true, true);} - void FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, true, true, true);} - void FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, true, false, true);} - - static void STD_impl(PPUThread *CPU, u32 rs, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - vm::ps3::write64(VM_CAST(addr), CPU->GPR[rs]); - } - - void STD(u32 rs, u32 ra, s32 d) override - { - STD_impl(&CPU, rs, ra, d); - } - - static void STDU_impl(PPUThread *CPU, u32 rs, u32 ra, s32 ds) - { - const u64 addr = CPU->GPR[ra] + ds; - vm::ps3::write64(VM_CAST(addr), CPU->GPR[rs]); - CPU->GPR[ra] = addr; - } - - void STDU(u32 rs, u32 ra, s32 ds) override - { - STDU_impl(&CPU, rs, ra, ds); - } - - void MTFSB1(u32 crbd, u32 rc) override - { - u32 mask = 1 << (31 - crbd); - if ((crbd >= 3 && crbd <= 6) && !(CPU.FPSCR.FPSCR & mask)) mask |= 1 << 31; //FPSCR.FX - if ((crbd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode enabled"); - CPU.SetFPSCR(CPU.FPSCR.FPSCR | mask); - - if(rc) CPU.UpdateCR1(); - } - void MCRFS(u32 crbd, u32 crbs) override - { - CPU.SetCR(crbd, (CPU.FPSCR.FPSCR >> ((7 - crbs) * 4)) & 0xf); - const u32 exceptions_mask = 0x9FF80700; - CPU.SetFPSCR(CPU.FPSCR.FPSCR & ~(exceptions_mask & 0xf << ((7 - crbs) * 4))); - } - void MTFSB0(u32 crbd, u32 rc) override - { - u32 mask = 1 << (31 - crbd); - if ((crbd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode disabled"); - CPU.SetFPSCR(CPU.FPSCR.FPSCR & ~mask); - - if(rc) CPU.UpdateCR1(); - } - void MTFSFI(u32 crfd, u32 i, u32 rc) override - { - u32 mask = 0xF0000000 >> (crfd * 4); - u32 val = (i & 0xF) << ((7 - crfd) * 4); - - const u32 oldNI = CPU.FPSCR.NI; - CPU.SetFPSCR((CPU.FPSCR.FPSCR & ~mask) | val); - if (CPU.FPSCR.NI != oldNI) - { - if (oldNI) - LOG_WARNING(PPU, "Non-IEEE mode disabled"); - else - LOG_WARNING(PPU, "Non-IEEE mode enabled"); - } - - if(rc) CPU.UpdateCR1(); - } - void MFFS(u32 frd, u32 rc) override - { - (u64&)CPU.FPR[frd] = CPU.FPSCR.FPSCR; - if(rc) CPU.UpdateCR1(); - } - void MTFSF(u32 flm, u32 frb, u32 rc) override - { - u32 mask = 0; - for(u32 i=0; i<8; ++i) - { - if(flm & (1 << i)) mask |= 0xf << (i * 4); - } - mask &= ~0x60000000; - - const u32 oldNI = CPU.FPSCR.NI; - CPU.SetFPSCR((CPU.FPSCR.FPSCR & ~mask) | ((u32&)CPU.FPR[frb] & mask)); - if (CPU.FPSCR.NI != oldNI) - { - if (oldNI) - LOG_WARNING(PPU, "Non-IEEE mode disabled"); - else - LOG_WARNING(PPU, "Non-IEEE mode enabled"); - } - if(rc) CPU.UpdateCR1(); - } - void FCMPU(u32 crfd, u32 fra, u32 frb) override - { - int cmp_res = FPRdouble::Cmp(CPU.FPR[fra], CPU.FPR[frb]); - - if(cmp_res == CR_SO) - { - if(FPRdouble::IsSNaN(CPU.FPR[fra]) || FPRdouble::IsSNaN(CPU.FPR[frb])) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - } - } - - CPU.FPSCR.FPRF = cmp_res; - CPU.SetCR(crfd, cmp_res); - } - void FRSP(u32 frd, u32 frb, u32 rc) override - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double b = CPU.FPR[frb]; - if (FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if (CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - double b0 = b; - if(CPU.FPSCR.NI) - { - if (((u64&)b0 & DOUBLE_EXP) < 0x3800000000000000ULL) (u64&)b0 &= DOUBLE_SIGN; - } - feclearexcept(FE_ALL_EXCEPT); - const double r = static_cast(b0); - if (FPRdouble::IsNaN(r)) - { - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - } - else - { - CPU.FPSCR.FR = fabs(r) > fabs(b); - CheckHostFPExceptions(); - } - u32 type = PPCdouble(r).GetType(); - if (type == FPR_PN && r < ldexp(1.0, -126)) type = FPR_PD; - else if (type == FPR_NN && r > ldexp(-1.0, -126)) type = FPR_ND; - CPU.FPSCR.FPRF = type; - CPU.FPR[frd] = r; - if(rc) CPU.UpdateCR1(); - } - void FCTIW(u32 frd, u32 frb, u32 rc) override {FCTIW(frd, frb, rc, false);} - void FCTIW(u32 frd, u32 frb, u32 rc, bool truncate) - { - const double b = CPU.FPR[frb]; - u32 r; - if (FPRdouble::IsNaN(b) || b < -(double)0x80000000) - { - CPU.SetFPSCRException(FPSCR_VXCVI); - if(FPRdouble::IsSNaN(b)) CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FI = 0; - CPU.FPSCR.FR = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - r = 0x80000000; - } - else if(b > (double)0x7fffffff) - { - CPU.SetFPSCRException(FPSCR_VXCVI); - CPU.FPSCR.FI = 0; - CPU.FPSCR.FR = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - r = 0x7fffffff; - } - else - { - s32 i = 0; - const u32 rn = truncate ? FPSCR_RN_ZERO : CPU.FPSCR.RN; - switch(rn) - { - case FPSCR_RN_NEAR: - SetHostRoundingMode(FPSCR_RN_NEAR); - i = (s32)nearbyint(b); - break; - case FPSCR_RN_ZERO: - i = (s32)b; - break; - case FPSCR_RN_PINF: - i = (s32)ceil(b); - break; - case FPSCR_RN_MINF: - i = (s32)floor(b); - break; - } - r = (u32)i; - double di = i; - if (di == b) - { - CPU.SetFPSCR_FI(0); - CPU.FPSCR.FR = 0; - } - else - { - CPU.SetFPSCR_FI(1); - CPU.FPSCR.FR = fabs(di) > fabs(b); - } - } - - (u64&)CPU.FPR[frd] = r; - if(rc) CPU.UpdateCR1(); - } - void FCTIWZ(u32 frd, u32 frb, u32 rc) override {FCTIW(frd, frb, rc, true);} - void FDIV(u32 frd, u32 fra, u32 frb, u32 rc) override {FDIV(frd, fra, frb, rc, false);} - void FDIV(u32 frd, u32 fra, u32 frb, u32 rc, bool single) - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double a = CPU.FPR[fra]; - const double b = CPU.FPR[frb]; - if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(a)) - { - CPU.FPR[frd] = SilenceNaN(a); - } - else if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(a == 0.0 && b == 0.0) - { - CPU.SetFPSCRException(FPSCR_VXZDZ); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else if(FPRdouble::IsINF(a) && FPRdouble::IsINF(b)) - { - CPU.SetFPSCRException(FPSCR_VXIDI); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - if(b == 0.0) - { - CPU.SetFPSCRException(FPSCR_ZX); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if (CPU.FPSCR.ZE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - feclearexcept(FE_ALL_EXCEPT); - const double res = a / b; - if(single) CPU.FPR[frd] = (float)res; - else CPU.FPR[frd] = res; - CheckHostFPExceptions(); - } - - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FSUB(u32 frd, u32 fra, u32 frb, u32 rc) override {FSUB(frd, fra, frb, rc, false);} - void FSUB(u32 frd, u32 fra, u32 frb, u32 rc, bool single) - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double a = CPU.FPR[fra]; - const double b = CPU.FPR[frb]; - if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(a)) - { - CPU.FPR[frd] = SilenceNaN(a); - } - else if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(FPRdouble::IsINF(a) && FPRdouble::IsINF(b) && a == b) - { - CPU.SetFPSCRException(FPSCR_VXISI); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - const double res = a - b; - if(single) CPU.FPR[frd] = (float)res; - else CPU.FPR[frd] = res; - CheckHostFPExceptions(); - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FADD(u32 frd, u32 fra, u32 frb, u32 rc) override {FADD(frd, fra, frb, rc, false);} - void FADD(u32 frd, u32 fra, u32 frb, u32 rc, bool single) - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double a = CPU.FPR[fra]; - const double b = CPU.FPR[frb]; - if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(a)) - { - CPU.FPR[frd] = SilenceNaN(a); - } - else if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(FPRdouble::IsINF(a) && FPRdouble::IsINF(b) && a != b) - { - CPU.SetFPSCRException(FPSCR_VXISI); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - const double res = a + b; - if(single) CPU.FPR[frd] = (float)res; - else CPU.FPR[frd] = res; - CheckHostFPExceptions(); - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FSQRT(u32 frd, u32 frb, u32 rc) override {FSQRT(frd, frb, rc, false);} - void FSQRT(u32 frd, u32 frb, u32 rc, bool single) - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double b = CPU.FPR[frb]; - if(FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(b < 0.0) - { - CPU.SetFPSCRException(FPSCR_VXSQRT); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - const double res = sqrt(b); - if(single) CPU.FPR[frd] = (float)res; - else CPU.FPR[frd] = res; - CheckHostFPExceptions(); - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FSEL(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override - { - CPU.FPR[frd] = CPU.FPR[fra] >= 0.0 ? CPU.FPR[frc] : CPU.FPR[frb]; - if(rc) CPU.UpdateCR1(); - } - void FMUL(u32 frd, u32 fra, u32 frc, u32 rc) override {FMUL(frd, fra, frc, rc, false);} - void FMUL(u32 frd, u32 fra, u32 frc, u32 rc, bool single) - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double a = CPU.FPR[fra]; - const double c = CPU.FPR[frc]; - if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(c)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(a)) - { - CPU.FPR[frd] = SilenceNaN(a); - } - else if(FPRdouble::IsNaN(c)) - { - CPU.FPR[frd] = SilenceNaN(c); - } - else if((FPRdouble::IsINF(a) && c == 0.0) || (a == 0.0 && FPRdouble::IsINF(c))) - { - CPU.SetFPSCRException(FPSCR_VXIMZ); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - const double res = a * c; - if(single) CPU.FPR[frd] = (float)res; - else CPU.FPR[frd] = res; - CheckHostFPExceptions(); - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FRSQRTE(u32 frd, u32 frb, u32 rc) override - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double b = CPU.FPR[frb]; - if(FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(b < 0.0) - { - CPU.SetFPSCRException(FPSCR_VXSQRT); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else if(b == 0.0) - { - CPU.SetFPSCRException(FPSCR_ZX); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if (CPU.FPSCR.ZE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = 1.0 / b; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - CPU.FPR[frd] = 1.0 / sqrt(b); - CheckHostFPExceptions(); - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, false, true, false);} - void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, false, false, false);} - void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc, bool neg, bool sub, bool single) - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double a = CPU.FPR[fra]; - const double b = CPU.FPR[frb]; - const double c = CPU.FPR[frc]; - if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(b) || FPRdouble::IsSNaN(c)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(a)) - { - CPU.FPR[frd] = SilenceNaN(a); - } - else if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(FPRdouble::IsNaN(c)) - { - CPU.FPR[frd] = SilenceNaN(c); - } - else if((FPRdouble::IsINF(a) && c == 0.0) || (a == 0.0 && FPRdouble::IsINF(c))) - { - CPU.SetFPSCRException(FPSCR_VXIMZ); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - const double res = fma(a, c, sub ? -b : b); - if(FPRdouble::IsNaN(res)) - { - CPU.SetFPSCRException(FPSCR_VXISI); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - if(single) CPU.FPR[frd] = (float)(neg ? -res : res); - else CPU.FPR[frd] = (neg ? -res : res); - CheckHostFPExceptions(); - } - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FNMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, true, true, false);} - void FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, true, false, false);} - void FCMPO(u32 crfd, u32 fra, u32 frb) override - { - int cmp_res = FPRdouble::Cmp(CPU.FPR[fra], CPU.FPR[frb]); - - if(cmp_res == CR_SO) - { - if(FPRdouble::IsSNaN(CPU.FPR[fra]) || FPRdouble::IsSNaN(CPU.FPR[frb])) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - if(!CPU.FPSCR.VE) CPU.SetFPSCRException(FPSCR_VXVC); - } - else - { - CPU.SetFPSCRException(FPSCR_VXVC); - } - - CPU.FPSCR.FX = 1; - } - - CPU.FPSCR.FPRF = cmp_res; - CPU.SetCR(crfd, cmp_res); - } - void FNEG(u32 frd, u32 frb, u32 rc) override - { - CPU.FPR[frd] = -CPU.FPR[frb]; - if(rc) CPU.UpdateCR1(); - } - void FMR(u32 frd, u32 frb, u32 rc) override - { - CPU.FPR[frd] = CPU.FPR[frb]; - if(rc) CPU.UpdateCR1(); - } - void FNABS(u32 frd, u32 frb, u32 rc) override - { - CPU.FPR[frd] = -fabs(CPU.FPR[frb]); - if(rc) CPU.UpdateCR1(); - } - void FABS(u32 frd, u32 frb, u32 rc) override - { - CPU.FPR[frd] = fabs(CPU.FPR[frb]); - if(rc) CPU.UpdateCR1(); - } - void FCTID(u32 frd, u32 frb, u32 rc) override {FCTID(frd, frb, rc, false);} - void FCTID(u32 frd, u32 frb, u32 rc, bool truncate) - { - const double b = CPU.FPR[frb]; - u64 r; - if (FPRdouble::IsNaN(b) || b < -(double)0x8000000000000000) - { - CPU.SetFPSCRException(FPSCR_VXCVI); - if(FPRdouble::IsSNaN(b)) CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FI = 0; - CPU.FPSCR.FR = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - r = 0x8000000000000000; - } - else if(b >= (double)0x8000000000000000) - { - CPU.SetFPSCRException(FPSCR_VXCVI); - CPU.FPSCR.FI = 0; - CPU.FPSCR.FR = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - r = 0x7fffffffffffffff; - } - else - { - s64 i = 0; - const u32 rn = truncate ? FPSCR_RN_ZERO : CPU.FPSCR.RN; - switch(rn) - { - case FPSCR_RN_NEAR: - SetHostRoundingMode(FPSCR_RN_NEAR); - i = (s64)nearbyint(b); - break; - case FPSCR_RN_ZERO: - i = (s64)b; - break; - case FPSCR_RN_PINF: - i = (s64)ceil(b); - break; - case FPSCR_RN_MINF: - i = (s64)floor(b); - break; - } - r = (u64)i; - double di = (double)i; - if (di == b) - { - CPU.SetFPSCR_FI(0); - CPU.FPSCR.FR = 0; - } - else - { - CPU.SetFPSCR_FI(1); - CPU.FPSCR.FR = fabs(di) > fabs(b); - } - } - - (u64&)CPU.FPR[frd] = r; - if(rc) CPU.UpdateCR1(); - } - void FCTIDZ(u32 frd, u32 frb, u32 rc) override {FCTID(frd, frb, rc, true);} - void FCFID(u32 frd, u32 frb, u32 rc) override - { - s64 bi = (s64&)CPU.FPR[frb]; - double bf = (double)bi; - s64 bfi = (s64)bf; - - if(bi == bfi) - { - CPU.SetFPSCR_FI(0); - CPU.FPSCR.FR = 0; - } - else - { - CPU.SetFPSCR_FI(1); - CPU.FPSCR.FR = std::abs(bfi) > std::abs(bi); - } - - CPU.FPR[frd] = bf; - - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - - void UNK(const u32 code, const u32 opcode, const u32 gcode) override - { - throw EXCEPTION("Unknown/Illegal opcode! (0x%08x : 0x%x : 0x%x)", code, opcode, gcode); - } + static void TDI(PPUThread&, ppu_opcode_t); + static void TWI(PPUThread&, ppu_opcode_t); + static void MFVSCR(PPUThread&, ppu_opcode_t); + static void MTVSCR(PPUThread&, ppu_opcode_t); + static void VADDCUW(PPUThread&, ppu_opcode_t); + static void VADDFP(PPUThread&, ppu_opcode_t); + static void VADDSBS(PPUThread&, ppu_opcode_t); + static void VADDSHS(PPUThread&, ppu_opcode_t); + static void VADDSWS(PPUThread&, ppu_opcode_t); + static void VADDUBM(PPUThread&, ppu_opcode_t); + static void VADDUBS(PPUThread&, ppu_opcode_t); + static void VADDUHM(PPUThread&, ppu_opcode_t); + static void VADDUHS(PPUThread&, ppu_opcode_t); + static void VADDUWM(PPUThread&, ppu_opcode_t); + static void VADDUWS(PPUThread&, ppu_opcode_t); + static void VAND(PPUThread&, ppu_opcode_t); + static void VANDC(PPUThread&, ppu_opcode_t); + static void VAVGSB(PPUThread&, ppu_opcode_t); + static void VAVGSH(PPUThread&, ppu_opcode_t); + static void VAVGSW(PPUThread&, ppu_opcode_t); + static void VAVGUB(PPUThread&, ppu_opcode_t); + static void VAVGUH(PPUThread&, ppu_opcode_t); + static void VAVGUW(PPUThread&, ppu_opcode_t); + static void VCFSX(PPUThread&, ppu_opcode_t); + static void VCFUX(PPUThread&, ppu_opcode_t); + static void VCMPBFP(PPUThread&, ppu_opcode_t); + static void VCMPEQFP(PPUThread&, ppu_opcode_t); + static void VCMPEQUB(PPUThread&, ppu_opcode_t); + static void VCMPEQUH(PPUThread&, ppu_opcode_t); + static void VCMPEQUW(PPUThread&, ppu_opcode_t); + static void VCMPGEFP(PPUThread&, ppu_opcode_t); + static void VCMPGTFP(PPUThread&, ppu_opcode_t); + static void VCMPGTSB(PPUThread&, ppu_opcode_t); + static void VCMPGTSH(PPUThread&, ppu_opcode_t); + static void VCMPGTSW(PPUThread&, ppu_opcode_t); + static void VCMPGTUB(PPUThread&, ppu_opcode_t); + static void VCMPGTUH(PPUThread&, ppu_opcode_t); + static void VCMPGTUW(PPUThread&, ppu_opcode_t); + static void VCTSXS(PPUThread&, ppu_opcode_t); + static void VCTUXS(PPUThread&, ppu_opcode_t); + static void VEXPTEFP(PPUThread&, ppu_opcode_t); + static void VLOGEFP(PPUThread&, ppu_opcode_t); + static void VMADDFP(PPUThread&, ppu_opcode_t); + static void VMAXFP(PPUThread&, ppu_opcode_t); + static void VMAXSB(PPUThread&, ppu_opcode_t); + static void VMAXSH(PPUThread&, ppu_opcode_t); + static void VMAXSW(PPUThread&, ppu_opcode_t); + static void VMAXUB(PPUThread&, ppu_opcode_t); + static void VMAXUH(PPUThread&, ppu_opcode_t); + static void VMAXUW(PPUThread&, ppu_opcode_t); + static void VMHADDSHS(PPUThread&, ppu_opcode_t); + static void VMHRADDSHS(PPUThread&, ppu_opcode_t); + static void VMINFP(PPUThread&, ppu_opcode_t); + static void VMINSB(PPUThread&, ppu_opcode_t); + static void VMINSH(PPUThread&, ppu_opcode_t); + static void VMINSW(PPUThread&, ppu_opcode_t); + static void VMINUB(PPUThread&, ppu_opcode_t); + static void VMINUH(PPUThread&, ppu_opcode_t); + static void VMINUW(PPUThread&, ppu_opcode_t); + static void VMLADDUHM(PPUThread&, ppu_opcode_t); + static void VMRGHB(PPUThread&, ppu_opcode_t); + static void VMRGHH(PPUThread&, ppu_opcode_t); + static void VMRGHW(PPUThread&, ppu_opcode_t); + static void VMRGLB(PPUThread&, ppu_opcode_t); + static void VMRGLH(PPUThread&, ppu_opcode_t); + static void VMRGLW(PPUThread&, ppu_opcode_t); + static void VMSUMMBM(PPUThread&, ppu_opcode_t); + static void VMSUMSHM(PPUThread&, ppu_opcode_t); + static void VMSUMSHS(PPUThread&, ppu_opcode_t); + static void VMSUMUBM(PPUThread&, ppu_opcode_t); + static void VMSUMUHM(PPUThread&, ppu_opcode_t); + static void VMSUMUHS(PPUThread&, ppu_opcode_t); + static void VMULESB(PPUThread&, ppu_opcode_t); + static void VMULESH(PPUThread&, ppu_opcode_t); + static void VMULEUB(PPUThread&, ppu_opcode_t); + static void VMULEUH(PPUThread&, ppu_opcode_t); + static void VMULOSB(PPUThread&, ppu_opcode_t); + static void VMULOSH(PPUThread&, ppu_opcode_t); + static void VMULOUB(PPUThread&, ppu_opcode_t); + static void VMULOUH(PPUThread&, ppu_opcode_t); + static void VNMSUBFP(PPUThread&, ppu_opcode_t); + static void VNOR(PPUThread&, ppu_opcode_t); + static void VOR(PPUThread&, ppu_opcode_t); + static void VPERM(PPUThread&, ppu_opcode_t); + static void VPKPX(PPUThread&, ppu_opcode_t); + static void VPKSHSS(PPUThread&, ppu_opcode_t); + static void VPKSHUS(PPUThread&, ppu_opcode_t); + static void VPKSWSS(PPUThread&, ppu_opcode_t); + static void VPKSWUS(PPUThread&, ppu_opcode_t); + static void VPKUHUM(PPUThread&, ppu_opcode_t); + static void VPKUHUS(PPUThread&, ppu_opcode_t); + static void VPKUWUM(PPUThread&, ppu_opcode_t); + static void VPKUWUS(PPUThread&, ppu_opcode_t); + static void VREFP(PPUThread&, ppu_opcode_t); + static void VRFIM(PPUThread&, ppu_opcode_t); + static void VRFIN(PPUThread&, ppu_opcode_t); + static void VRFIP(PPUThread&, ppu_opcode_t); + static void VRFIZ(PPUThread&, ppu_opcode_t); + static void VRLB(PPUThread&, ppu_opcode_t); + static void VRLH(PPUThread&, ppu_opcode_t); + static void VRLW(PPUThread&, ppu_opcode_t); + static void VRSQRTEFP(PPUThread&, ppu_opcode_t); + static void VSEL(PPUThread&, ppu_opcode_t); + static void VSL(PPUThread&, ppu_opcode_t); + static void VSLB(PPUThread&, ppu_opcode_t); + static void VSLDOI(PPUThread&, ppu_opcode_t); + static void VSLH(PPUThread&, ppu_opcode_t); + static void VSLO(PPUThread&, ppu_opcode_t); + static void VSLW(PPUThread&, ppu_opcode_t); + static void VSPLTB(PPUThread&, ppu_opcode_t); + static void VSPLTH(PPUThread&, ppu_opcode_t); + static void VSPLTISB(PPUThread&, ppu_opcode_t); + static void VSPLTISH(PPUThread&, ppu_opcode_t); + static void VSPLTISW(PPUThread&, ppu_opcode_t); + static void VSPLTW(PPUThread&, ppu_opcode_t); + static void VSR(PPUThread&, ppu_opcode_t); + static void VSRAB(PPUThread&, ppu_opcode_t); + static void VSRAH(PPUThread&, ppu_opcode_t); + static void VSRAW(PPUThread&, ppu_opcode_t); + static void VSRB(PPUThread&, ppu_opcode_t); + static void VSRH(PPUThread&, ppu_opcode_t); + static void VSRO(PPUThread&, ppu_opcode_t); + static void VSRW(PPUThread&, ppu_opcode_t); + static void VSUBCUW(PPUThread&, ppu_opcode_t); + static void VSUBFP(PPUThread&, ppu_opcode_t); + static void VSUBSBS(PPUThread&, ppu_opcode_t); + static void VSUBSHS(PPUThread&, ppu_opcode_t); + static void VSUBSWS(PPUThread&, ppu_opcode_t); + static void VSUBUBM(PPUThread&, ppu_opcode_t); + static void VSUBUBS(PPUThread&, ppu_opcode_t); + static void VSUBUHM(PPUThread&, ppu_opcode_t); + static void VSUBUHS(PPUThread&, ppu_opcode_t); + static void VSUBUWM(PPUThread&, ppu_opcode_t); + static void VSUBUWS(PPUThread&, ppu_opcode_t); + static void VSUMSWS(PPUThread&, ppu_opcode_t); + static void VSUM2SWS(PPUThread&, ppu_opcode_t); + static void VSUM4SBS(PPUThread&, ppu_opcode_t); + static void VSUM4SHS(PPUThread&, ppu_opcode_t); + static void VSUM4UBS(PPUThread&, ppu_opcode_t); + static void VUPKHPX(PPUThread&, ppu_opcode_t); + static void VUPKHSB(PPUThread&, ppu_opcode_t); + static void VUPKHSH(PPUThread&, ppu_opcode_t); + static void VUPKLPX(PPUThread&, ppu_opcode_t); + static void VUPKLSB(PPUThread&, ppu_opcode_t); + static void VUPKLSH(PPUThread&, ppu_opcode_t); + static void VXOR(PPUThread&, ppu_opcode_t); + static void MULLI(PPUThread&, ppu_opcode_t); + static void SUBFIC(PPUThread&, ppu_opcode_t); + static void CMPLI(PPUThread&, ppu_opcode_t); + static void CMPI(PPUThread&, ppu_opcode_t); + static void ADDIC(PPUThread&, ppu_opcode_t); + static void ADDI(PPUThread&, ppu_opcode_t); + static void ADDIS(PPUThread&, ppu_opcode_t); + static void BC(PPUThread&, ppu_opcode_t); + static void HACK(PPUThread&, ppu_opcode_t); + static void SC(PPUThread&, ppu_opcode_t); + static void B(PPUThread&, ppu_opcode_t); + static void MCRF(PPUThread&, ppu_opcode_t); + static void BCLR(PPUThread&, ppu_opcode_t); + static void CRNOR(PPUThread&, ppu_opcode_t); + static void CRANDC(PPUThread&, ppu_opcode_t); + static void ISYNC(PPUThread&, ppu_opcode_t); + static void CRXOR(PPUThread&, ppu_opcode_t); + static void CRNAND(PPUThread&, ppu_opcode_t); + static void CRAND(PPUThread&, ppu_opcode_t); + static void CREQV(PPUThread&, ppu_opcode_t); + static void CRORC(PPUThread&, ppu_opcode_t); + static void CROR(PPUThread&, ppu_opcode_t); + static void BCCTR(PPUThread&, ppu_opcode_t); + static void RLWIMI(PPUThread&, ppu_opcode_t); + static void RLWINM(PPUThread&, ppu_opcode_t); + static void RLWNM(PPUThread&, ppu_opcode_t); + static void ORI(PPUThread&, ppu_opcode_t); + static void ORIS(PPUThread&, ppu_opcode_t); + static void XORI(PPUThread&, ppu_opcode_t); + static void XORIS(PPUThread&, ppu_opcode_t); + static void ANDI(PPUThread&, ppu_opcode_t); + static void ANDIS(PPUThread&, ppu_opcode_t); + static void RLDICL(PPUThread&, ppu_opcode_t); + static void RLDICR(PPUThread&, ppu_opcode_t); + static void RLDIC(PPUThread&, ppu_opcode_t); + static void RLDIMI(PPUThread&, ppu_opcode_t); + static void RLDCL(PPUThread&, ppu_opcode_t); + static void RLDCR(PPUThread&, ppu_opcode_t); + static void CMP(PPUThread&, ppu_opcode_t); + static void TW(PPUThread&, ppu_opcode_t); + static void LVSL(PPUThread&, ppu_opcode_t); + static void LVEBX(PPUThread&, ppu_opcode_t); + static void SUBFC(PPUThread&, ppu_opcode_t); + static void MULHDU(PPUThread&, ppu_opcode_t); + static void ADDC(PPUThread&, ppu_opcode_t); + static void MULHWU(PPUThread&, ppu_opcode_t); + static void MFOCRF(PPUThread&, ppu_opcode_t); + static void LWARX(PPUThread&, ppu_opcode_t); + static void LDX(PPUThread&, ppu_opcode_t); + static void LWZX(PPUThread&, ppu_opcode_t); + static void SLW(PPUThread&, ppu_opcode_t); + static void CNTLZW(PPUThread&, ppu_opcode_t); + static void SLD(PPUThread&, ppu_opcode_t); + static void AND(PPUThread&, ppu_opcode_t); + static void CMPL(PPUThread&, ppu_opcode_t); + static void LVSR(PPUThread&, ppu_opcode_t); + static void LVEHX(PPUThread&, ppu_opcode_t); + static void SUBF(PPUThread&, ppu_opcode_t); + static void LDUX(PPUThread&, ppu_opcode_t); + static void DCBST(PPUThread&, ppu_opcode_t); + static void LWZUX(PPUThread&, ppu_opcode_t); + static void CNTLZD(PPUThread&, ppu_opcode_t); + static void ANDC(PPUThread&, ppu_opcode_t); + static void TD(PPUThread&, ppu_opcode_t); + static void LVEWX(PPUThread&, ppu_opcode_t); + static void MULHD(PPUThread&, ppu_opcode_t); + static void MULHW(PPUThread&, ppu_opcode_t); + static void LDARX(PPUThread&, ppu_opcode_t); + static void DCBF(PPUThread&, ppu_opcode_t); + static void LBZX(PPUThread&, ppu_opcode_t); + static void LVX(PPUThread&, ppu_opcode_t); + static void NEG(PPUThread&, ppu_opcode_t); + static void LBZUX(PPUThread&, ppu_opcode_t); + static void NOR(PPUThread&, ppu_opcode_t); + static void STVEBX(PPUThread&, ppu_opcode_t); + static void SUBFE(PPUThread&, ppu_opcode_t); + static void ADDE(PPUThread&, ppu_opcode_t); + static void MTOCRF(PPUThread&, ppu_opcode_t); + static void STDX(PPUThread&, ppu_opcode_t); + static void STWCX(PPUThread&, ppu_opcode_t); + static void STWX(PPUThread&, ppu_opcode_t); + static void STVEHX(PPUThread&, ppu_opcode_t); + static void STDUX(PPUThread&, ppu_opcode_t); + static void STWUX(PPUThread&, ppu_opcode_t); + static void STVEWX(PPUThread&, ppu_opcode_t); + static void SUBFZE(PPUThread&, ppu_opcode_t); + static void ADDZE(PPUThread&, ppu_opcode_t); + static void STDCX(PPUThread&, ppu_opcode_t); + static void STBX(PPUThread&, ppu_opcode_t); + static void STVX(PPUThread&, ppu_opcode_t); + static void MULLD(PPUThread&, ppu_opcode_t); + static void SUBFME(PPUThread&, ppu_opcode_t); + static void ADDME(PPUThread&, ppu_opcode_t); + static void MULLW(PPUThread&, ppu_opcode_t); + static void DCBTST(PPUThread&, ppu_opcode_t); + static void STBUX(PPUThread&, ppu_opcode_t); + static void ADD(PPUThread&, ppu_opcode_t); + static void DCBT(PPUThread&, ppu_opcode_t); + static void LHZX(PPUThread&, ppu_opcode_t); + static void EQV(PPUThread&, ppu_opcode_t); + static void ECIWX(PPUThread&, ppu_opcode_t); + static void LHZUX(PPUThread&, ppu_opcode_t); + static void XOR(PPUThread&, ppu_opcode_t); + static void MFSPR(PPUThread&, ppu_opcode_t); + static void LWAX(PPUThread&, ppu_opcode_t); + static void DST(PPUThread&, ppu_opcode_t); + static void LHAX(PPUThread&, ppu_opcode_t); + static void LVXL(PPUThread&, ppu_opcode_t); + static void MFTB(PPUThread&, ppu_opcode_t); + static void LWAUX(PPUThread&, ppu_opcode_t); + static void DSTST(PPUThread&, ppu_opcode_t); + static void LHAUX(PPUThread&, ppu_opcode_t); + static void STHX(PPUThread&, ppu_opcode_t); + static void ORC(PPUThread&, ppu_opcode_t); + static void ECOWX(PPUThread&, ppu_opcode_t); + static void STHUX(PPUThread&, ppu_opcode_t); + static void OR(PPUThread&, ppu_opcode_t); + static void DIVDU(PPUThread&, ppu_opcode_t); + static void DIVWU(PPUThread&, ppu_opcode_t); + static void MTSPR(PPUThread&, ppu_opcode_t); + static void DCBI(PPUThread&, ppu_opcode_t); + static void NAND(PPUThread&, ppu_opcode_t); + static void STVXL(PPUThread&, ppu_opcode_t); + static void DIVD(PPUThread&, ppu_opcode_t); + static void DIVW(PPUThread&, ppu_opcode_t); + static void LVLX(PPUThread&, ppu_opcode_t); + static void LDBRX(PPUThread&, ppu_opcode_t); + static void LSWX(PPUThread&, ppu_opcode_t); + static void LWBRX(PPUThread&, ppu_opcode_t); + static void LFSX(PPUThread&, ppu_opcode_t); + static void SRW(PPUThread&, ppu_opcode_t); + static void SRD(PPUThread&, ppu_opcode_t); + static void LVRX(PPUThread&, ppu_opcode_t); + static void LSWI(PPUThread&, ppu_opcode_t); + static void LFSUX(PPUThread&, ppu_opcode_t); + static void SYNC(PPUThread&, ppu_opcode_t); + static void LFDX(PPUThread&, ppu_opcode_t); + static void LFDUX(PPUThread&, ppu_opcode_t); + static void STVLX(PPUThread&, ppu_opcode_t); + static void STDBRX(PPUThread&, ppu_opcode_t); + static void STSWX(PPUThread&, ppu_opcode_t); + static void STWBRX(PPUThread&, ppu_opcode_t); + static void STFSX(PPUThread&, ppu_opcode_t); + static void STVRX(PPUThread&, ppu_opcode_t); + static void STFSUX(PPUThread&, ppu_opcode_t); + static void STSWI(PPUThread&, ppu_opcode_t); + static void STFDX(PPUThread&, ppu_opcode_t); + static void STFDUX(PPUThread&, ppu_opcode_t); + static void LVLXL(PPUThread&, ppu_opcode_t); + static void LHBRX(PPUThread&, ppu_opcode_t); + static void SRAW(PPUThread&, ppu_opcode_t); + static void SRAD(PPUThread&, ppu_opcode_t); + static void LVRXL(PPUThread&, ppu_opcode_t); + static void DSS(PPUThread&, ppu_opcode_t); + static void SRAWI(PPUThread&, ppu_opcode_t); + static void SRADI(PPUThread&, ppu_opcode_t); + static void EIEIO(PPUThread&, ppu_opcode_t); + static void STVLXL(PPUThread&, ppu_opcode_t); + static void STHBRX(PPUThread&, ppu_opcode_t); + static void EXTSH(PPUThread&, ppu_opcode_t); + static void STVRXL(PPUThread&, ppu_opcode_t); + static void EXTSB(PPUThread&, ppu_opcode_t); + static void STFIWX(PPUThread&, ppu_opcode_t); + static void EXTSW(PPUThread&, ppu_opcode_t); + static void ICBI(PPUThread&, ppu_opcode_t); + static void DCBZ(PPUThread&, ppu_opcode_t); + static void LWZ(PPUThread&, ppu_opcode_t); + static void LWZU(PPUThread&, ppu_opcode_t); + static void LBZ(PPUThread&, ppu_opcode_t); + static void LBZU(PPUThread&, ppu_opcode_t); + static void STW(PPUThread&, ppu_opcode_t); + static void STWU(PPUThread&, ppu_opcode_t); + static void STB(PPUThread&, ppu_opcode_t); + static void STBU(PPUThread&, ppu_opcode_t); + static void LHZ(PPUThread&, ppu_opcode_t); + static void LHZU(PPUThread&, ppu_opcode_t); + static void LHA(PPUThread&, ppu_opcode_t); + static void LHAU(PPUThread&, ppu_opcode_t); + static void STH(PPUThread&, ppu_opcode_t); + static void STHU(PPUThread&, ppu_opcode_t); + static void LMW(PPUThread&, ppu_opcode_t); + static void STMW(PPUThread&, ppu_opcode_t); + static void LFS(PPUThread&, ppu_opcode_t); + static void LFSU(PPUThread&, ppu_opcode_t); + static void LFD(PPUThread&, ppu_opcode_t); + static void LFDU(PPUThread&, ppu_opcode_t); + static void STFS(PPUThread&, ppu_opcode_t); + static void STFSU(PPUThread&, ppu_opcode_t); + static void STFD(PPUThread&, ppu_opcode_t); + static void STFDU(PPUThread&, ppu_opcode_t); + static void LD(PPUThread&, ppu_opcode_t); + static void LDU(PPUThread&, ppu_opcode_t); + static void LWA(PPUThread&, ppu_opcode_t); + static void FDIVS(PPUThread&, ppu_opcode_t); + static void FSUBS(PPUThread&, ppu_opcode_t); + static void FADDS(PPUThread&, ppu_opcode_t); + static void FSQRTS(PPUThread&, ppu_opcode_t); + static void FRES(PPUThread&, ppu_opcode_t); + static void FMULS(PPUThread&, ppu_opcode_t); + static void FMADDS(PPUThread&, ppu_opcode_t); + static void FMSUBS(PPUThread&, ppu_opcode_t); + static void FNMSUBS(PPUThread&, ppu_opcode_t); + static void FNMADDS(PPUThread&, ppu_opcode_t); + static void STD(PPUThread&, ppu_opcode_t); + static void STDU(PPUThread&, ppu_opcode_t); + static void MTFSB1(PPUThread&, ppu_opcode_t); + static void MCRFS(PPUThread&, ppu_opcode_t); + static void MTFSB0(PPUThread&, ppu_opcode_t); + static void MTFSFI(PPUThread&, ppu_opcode_t); + static void MFFS(PPUThread&, ppu_opcode_t); + static void MTFSF(PPUThread&, ppu_opcode_t); + static void FCMPU(PPUThread&, ppu_opcode_t); + static void FRSP(PPUThread&, ppu_opcode_t); + static void FCTIW(PPUThread&, ppu_opcode_t); + static void FCTIWZ(PPUThread&, ppu_opcode_t); + static void FDIV(PPUThread&, ppu_opcode_t); + static void FSUB(PPUThread&, ppu_opcode_t); + static void FADD(PPUThread&, ppu_opcode_t); + static void FSQRT(PPUThread&, ppu_opcode_t); + static void FSEL(PPUThread&, ppu_opcode_t); + static void FMUL(PPUThread&, ppu_opcode_t); + static void FRSQRTE(PPUThread&, ppu_opcode_t); + static void FMSUB(PPUThread&, ppu_opcode_t); + static void FMADD(PPUThread&, ppu_opcode_t); + static void FNMSUB(PPUThread&, ppu_opcode_t); + static void FNMADD(PPUThread&, ppu_opcode_t); + static void FCMPO(PPUThread&, ppu_opcode_t); + static void FNEG(PPUThread&, ppu_opcode_t); + static void FMR(PPUThread&, ppu_opcode_t); + static void FNABS(PPUThread&, ppu_opcode_t); + static void FABS(PPUThread&, ppu_opcode_t); + static void FCTID(PPUThread&, ppu_opcode_t); + static void FCTIDZ(PPUThread&, ppu_opcode_t); + static void FCFID(PPUThread&, ppu_opcode_t); + + static void UNK(PPUThread&, ppu_opcode_t); +}; + +struct ppu_interpreter_precise final : ppu_interpreter +{ + // TODO +}; + +struct ppu_interpreter_fast final : ppu_interpreter +{ + // TODO }; diff --git a/rpcs3/Emu/Cell/PPUInterpreter2.h b/rpcs3/Emu/Cell/PPUInterpreter2.h deleted file mode 100644 index 051c70b3dd..0000000000 --- a/rpcs3/Emu/Cell/PPUInterpreter2.h +++ /dev/null @@ -1,870 +0,0 @@ -#pragma once - -#include "PPUOpcodes.h" - -class PPUThread; - -union ppu_opcode_t -{ - u32 opcode; - - bf_t shh; // 30 - bf_t mbmeh; // 26 - bf_t mbmel; // 21..25 - bf_t shl; // 16..20 - bf_t vuimm; // 11..15 - bf_t vs; // 6..10 - bf_t vsh; // 22..25 - bf_t oe; // 21 - bf_t spr; // 11..20 - bf_t vc; // 21..25 - bf_t vb; // 16..20 - bf_t va; // 11..15 - bf_t vd; // 6..10 - bf_t lk; // 31 - bf_t aa; // 30 - bf_t rb; // 16..20 - bf_t ra; // 11..15 - bf_t rd; // 6..10 - bf_t uimm16; // 16..31 - bf_t l11; // 11 - bf_t rs; // 6..10 - bf_t simm16; // 16..31, signed - bf_t vsimm; // 11..15, signed - bf_t ll; // 6..31, signed - bf_t lev; // 20..26 - bf_t i; // 16..19 - bf_t crfs; // 11..13 - bf_t l10; // 10 - bf_t crfd; // 6..8 - bf_t crbb; // 16..20 - bf_t crba; // 11..15 - bf_t crbd; // 6..10 - bf_t rc; // 31 - bf_t me; // 26..30 - bf_t mb; // 21..25 - bf_t sh; // 16..20 - bf_t bi; // 11..15 - bf_t bo; // 6..10 - bf_t frc; // 21..25 - bf_t frb; // 16..20 - bf_t fra; // 11..15 - bf_t frd; // 6..10 - bf_t crm; // 12..19 - bf_t frs; // 6..10 - bf_t flm; // 7..14 -}; - -namespace ppu_interpreter -{ - void NULL_OP(PPUThread& CPU, ppu_opcode_t op); - void NOP(PPUThread& CPU, ppu_opcode_t op); - - void TDI(PPUThread& CPU, ppu_opcode_t op); - void TWI(PPUThread& CPU, ppu_opcode_t op); - - void MFVSCR(PPUThread& CPU, ppu_opcode_t op); - void MTVSCR(PPUThread& CPU, ppu_opcode_t op); - void VADDCUW(PPUThread& CPU, ppu_opcode_t op); - void VADDFP(PPUThread& CPU, ppu_opcode_t op); - void VADDSBS(PPUThread& CPU, ppu_opcode_t op); - void VADDSHS(PPUThread& CPU, ppu_opcode_t op); - void VADDSWS(PPUThread& CPU, ppu_opcode_t op); - void VADDUBM(PPUThread& CPU, ppu_opcode_t op); - void VADDUBS(PPUThread& CPU, ppu_opcode_t op); - void VADDUHM(PPUThread& CPU, ppu_opcode_t op); - void VADDUHS(PPUThread& CPU, ppu_opcode_t op); - void VADDUWM(PPUThread& CPU, ppu_opcode_t op); - void VADDUWS(PPUThread& CPU, ppu_opcode_t op); - void VAND(PPUThread& CPU, ppu_opcode_t op); - void VANDC(PPUThread& CPU, ppu_opcode_t op); - void VAVGSB(PPUThread& CPU, ppu_opcode_t op); - void VAVGSH(PPUThread& CPU, ppu_opcode_t op); - void VAVGSW(PPUThread& CPU, ppu_opcode_t op); - void VAVGUB(PPUThread& CPU, ppu_opcode_t op); - void VAVGUH(PPUThread& CPU, ppu_opcode_t op); - void VAVGUW(PPUThread& CPU, ppu_opcode_t op); - void VCFSX(PPUThread& CPU, ppu_opcode_t op); - void VCFUX(PPUThread& CPU, ppu_opcode_t op); - void VCMPBFP(PPUThread& CPU, ppu_opcode_t op); - void VCMPBFP_(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQFP(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQFP_(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQUB(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQUB_(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQUH(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQUH_(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQUW(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQUW_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGEFP(PPUThread& CPU, ppu_opcode_t op); - void VCMPGEFP_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTFP(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTFP_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTSB(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTSB_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTSH(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTSH_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTSW(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTSW_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTUB(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTUB_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTUH(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTUH_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTUW(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTUW_(PPUThread& CPU, ppu_opcode_t op); - void VCTSXS(PPUThread& CPU, ppu_opcode_t op); - void VCTUXS(PPUThread& CPU, ppu_opcode_t op); - void VEXPTEFP(PPUThread& CPU, ppu_opcode_t op); - void VLOGEFP(PPUThread& CPU, ppu_opcode_t op); - void VMADDFP(PPUThread& CPU, ppu_opcode_t op); - void VMAXFP(PPUThread& CPU, ppu_opcode_t op); - void VMAXSB(PPUThread& CPU, ppu_opcode_t op); - void VMAXSH(PPUThread& CPU, ppu_opcode_t op); - void VMAXSW(PPUThread& CPU, ppu_opcode_t op); - void VMAXUB(PPUThread& CPU, ppu_opcode_t op); - void VMAXUH(PPUThread& CPU, ppu_opcode_t op); - void VMAXUW(PPUThread& CPU, ppu_opcode_t op); - void VMHADDSHS(PPUThread& CPU, ppu_opcode_t op); - void VMHRADDSHS(PPUThread& CPU, ppu_opcode_t op); - void VMINFP(PPUThread& CPU, ppu_opcode_t op); - void VMINSB(PPUThread& CPU, ppu_opcode_t op); - void VMINSH(PPUThread& CPU, ppu_opcode_t op); - void VMINSW(PPUThread& CPU, ppu_opcode_t op); - void VMINUB(PPUThread& CPU, ppu_opcode_t op); - void VMINUH(PPUThread& CPU, ppu_opcode_t op); - void VMINUW(PPUThread& CPU, ppu_opcode_t op); - void VMLADDUHM(PPUThread& CPU, ppu_opcode_t op); - void VMRGHB(PPUThread& CPU, ppu_opcode_t op); - void VMRGHH(PPUThread& CPU, ppu_opcode_t op); - void VMRGHW(PPUThread& CPU, ppu_opcode_t op); - void VMRGLB(PPUThread& CPU, ppu_opcode_t op); - void VMRGLH(PPUThread& CPU, ppu_opcode_t op); - void VMRGLW(PPUThread& CPU, ppu_opcode_t op); - void VMSUMMBM(PPUThread& CPU, ppu_opcode_t op); - void VMSUMSHM(PPUThread& CPU, ppu_opcode_t op); - void VMSUMSHS(PPUThread& CPU, ppu_opcode_t op); - void VMSUMUBM(PPUThread& CPU, ppu_opcode_t op); - void VMSUMUHM(PPUThread& CPU, ppu_opcode_t op); - void VMSUMUHS(PPUThread& CPU, ppu_opcode_t op); - void VMULESB(PPUThread& CPU, ppu_opcode_t op); - void VMULESH(PPUThread& CPU, ppu_opcode_t op); - void VMULEUB(PPUThread& CPU, ppu_opcode_t op); - void VMULEUH(PPUThread& CPU, ppu_opcode_t op); - void VMULOSB(PPUThread& CPU, ppu_opcode_t op); - void VMULOSH(PPUThread& CPU, ppu_opcode_t op); - void VMULOUB(PPUThread& CPU, ppu_opcode_t op); - void VMULOUH(PPUThread& CPU, ppu_opcode_t op); - void VNMSUBFP(PPUThread& CPU, ppu_opcode_t op); - void VNOR(PPUThread& CPU, ppu_opcode_t op); - void VOR(PPUThread& CPU, ppu_opcode_t op); - void VPERM(PPUThread& CPU, ppu_opcode_t op); - void VPKPX(PPUThread& CPU, ppu_opcode_t op); - void VPKSHSS(PPUThread& CPU, ppu_opcode_t op); - void VPKSHUS(PPUThread& CPU, ppu_opcode_t op); - void VPKSWSS(PPUThread& CPU, ppu_opcode_t op); - void VPKSWUS(PPUThread& CPU, ppu_opcode_t op); - void VPKUHUM(PPUThread& CPU, ppu_opcode_t op); - void VPKUHUS(PPUThread& CPU, ppu_opcode_t op); - void VPKUWUM(PPUThread& CPU, ppu_opcode_t op); - void VPKUWUS(PPUThread& CPU, ppu_opcode_t op); - void VREFP(PPUThread& CPU, ppu_opcode_t op); - void VRFIM(PPUThread& CPU, ppu_opcode_t op); - void VRFIN(PPUThread& CPU, ppu_opcode_t op); - void VRFIP(PPUThread& CPU, ppu_opcode_t op); - void VRFIZ(PPUThread& CPU, ppu_opcode_t op); - void VRLB(PPUThread& CPU, ppu_opcode_t op); - void VRLH(PPUThread& CPU, ppu_opcode_t op); - void VRLW(PPUThread& CPU, ppu_opcode_t op); - void VRSQRTEFP(PPUThread& CPU, ppu_opcode_t op); - void VSEL(PPUThread& CPU, ppu_opcode_t op); - void VSL(PPUThread& CPU, ppu_opcode_t op); - void VSLB(PPUThread& CPU, ppu_opcode_t op); - void VSLDOI(PPUThread& CPU, ppu_opcode_t op); - void VSLH(PPUThread& CPU, ppu_opcode_t op); - void VSLO(PPUThread& CPU, ppu_opcode_t op); - void VSLW(PPUThread& CPU, ppu_opcode_t op); - void VSPLTB(PPUThread& CPU, ppu_opcode_t op); - void VSPLTH(PPUThread& CPU, ppu_opcode_t op); - void VSPLTISB(PPUThread& CPU, ppu_opcode_t op); - void VSPLTISH(PPUThread& CPU, ppu_opcode_t op); - void VSPLTISW(PPUThread& CPU, ppu_opcode_t op); - void VSPLTW(PPUThread& CPU, ppu_opcode_t op); - void VSR(PPUThread& CPU, ppu_opcode_t op); - void VSRAB(PPUThread& CPU, ppu_opcode_t op); - void VSRAH(PPUThread& CPU, ppu_opcode_t op); - void VSRAW(PPUThread& CPU, ppu_opcode_t op); - void VSRB(PPUThread& CPU, ppu_opcode_t op); - void VSRH(PPUThread& CPU, ppu_opcode_t op); - void VSRO(PPUThread& CPU, ppu_opcode_t op); - void VSRW(PPUThread& CPU, ppu_opcode_t op); - void VSUBCUW(PPUThread& CPU, ppu_opcode_t op); - void VSUBFP(PPUThread& CPU, ppu_opcode_t op); - void VSUBSBS(PPUThread& CPU, ppu_opcode_t op); - void VSUBSHS(PPUThread& CPU, ppu_opcode_t op); - void VSUBSWS(PPUThread& CPU, ppu_opcode_t op); - void VSUBUBM(PPUThread& CPU, ppu_opcode_t op); - void VSUBUBS(PPUThread& CPU, ppu_opcode_t op); - void VSUBUHM(PPUThread& CPU, ppu_opcode_t op); - void VSUBUHS(PPUThread& CPU, ppu_opcode_t op); - void VSUBUWM(PPUThread& CPU, ppu_opcode_t op); - void VSUBUWS(PPUThread& CPU, ppu_opcode_t op); - void VSUMSWS(PPUThread& CPU, ppu_opcode_t op); - void VSUM2SWS(PPUThread& CPU, ppu_opcode_t op); - void VSUM4SBS(PPUThread& CPU, ppu_opcode_t op); - void VSUM4SHS(PPUThread& CPU, ppu_opcode_t op); - void VSUM4UBS(PPUThread& CPU, ppu_opcode_t op); - void VUPKHPX(PPUThread& CPU, ppu_opcode_t op); - void VUPKHSB(PPUThread& CPU, ppu_opcode_t op); - void VUPKHSH(PPUThread& CPU, ppu_opcode_t op); - void VUPKLPX(PPUThread& CPU, ppu_opcode_t op); - void VUPKLSB(PPUThread& CPU, ppu_opcode_t op); - void VUPKLSH(PPUThread& CPU, ppu_opcode_t op); - void VXOR(PPUThread& CPU, ppu_opcode_t op); - void MULLI(PPUThread& CPU, ppu_opcode_t op); - void SUBFIC(PPUThread& CPU, ppu_opcode_t op); - void CMPLI(PPUThread& CPU, ppu_opcode_t op); - void CMPI(PPUThread& CPU, ppu_opcode_t op); - void ADDIC(PPUThread& CPU, ppu_opcode_t op); - void ADDIC_(PPUThread& CPU, ppu_opcode_t op); - void ADDI(PPUThread& CPU, ppu_opcode_t op); - void ADDIS(PPUThread& CPU, ppu_opcode_t op); - void BC(PPUThread& CPU, ppu_opcode_t op); - void HACK(PPUThread& CPU, ppu_opcode_t op); - void SC(PPUThread& CPU, ppu_opcode_t op); - void B(PPUThread& CPU, ppu_opcode_t op); - void MCRF(PPUThread& CPU, ppu_opcode_t op); - void BCLR(PPUThread& CPU, ppu_opcode_t op); - void CRNOR(PPUThread& CPU, ppu_opcode_t op); - void CRANDC(PPUThread& CPU, ppu_opcode_t op); - void ISYNC(PPUThread& CPU, ppu_opcode_t op); - void CRXOR(PPUThread& CPU, ppu_opcode_t op); - void CRNAND(PPUThread& CPU, ppu_opcode_t op); - void CRAND(PPUThread& CPU, ppu_opcode_t op); - void CREQV(PPUThread& CPU, ppu_opcode_t op); - void CRORC(PPUThread& CPU, ppu_opcode_t op); - void CROR(PPUThread& CPU, ppu_opcode_t op); - void BCCTR(PPUThread& CPU, ppu_opcode_t op); - void RLWIMI(PPUThread& CPU, ppu_opcode_t op); - void RLWINM(PPUThread& CPU, ppu_opcode_t op); - void RLWNM(PPUThread& CPU, ppu_opcode_t op); - void ORI(PPUThread& CPU, ppu_opcode_t op); - void ORIS(PPUThread& CPU, ppu_opcode_t op); - void XORI(PPUThread& CPU, ppu_opcode_t op); - void XORIS(PPUThread& CPU, ppu_opcode_t op); - void ANDI_(PPUThread& CPU, ppu_opcode_t op); - void ANDIS_(PPUThread& CPU, ppu_opcode_t op); - void RLDICL(PPUThread& CPU, ppu_opcode_t op); - void RLDICR(PPUThread& CPU, ppu_opcode_t op); - void RLDIC(PPUThread& CPU, ppu_opcode_t op); - void RLDIMI(PPUThread& CPU, ppu_opcode_t op); - void RLDC_LR(PPUThread& CPU, ppu_opcode_t op); - void CMP(PPUThread& CPU, ppu_opcode_t op); - void TW(PPUThread& CPU, ppu_opcode_t op); - void LVSL(PPUThread& CPU, ppu_opcode_t op); - void LVEBX(PPUThread& CPU, ppu_opcode_t op); - void SUBFC(PPUThread& CPU, ppu_opcode_t op); - void MULHDU(PPUThread& CPU, ppu_opcode_t op); - void ADDC(PPUThread& CPU, ppu_opcode_t op); - void MULHWU(PPUThread& CPU, ppu_opcode_t op); - void MFOCRF(PPUThread& CPU, ppu_opcode_t op); - void LWARX(PPUThread& CPU, ppu_opcode_t op); - void LDX(PPUThread& CPU, ppu_opcode_t op); - void LWZX(PPUThread& CPU, ppu_opcode_t op); - void SLW(PPUThread& CPU, ppu_opcode_t op); - void CNTLZW(PPUThread& CPU, ppu_opcode_t op); - void SLD(PPUThread& CPU, ppu_opcode_t op); - void AND(PPUThread& CPU, ppu_opcode_t op); - void CMPL(PPUThread& CPU, ppu_opcode_t op); - void LVSR(PPUThread& CPU, ppu_opcode_t op); - void LVEHX(PPUThread& CPU, ppu_opcode_t op); - void SUBF(PPUThread& CPU, ppu_opcode_t op); - void LDUX(PPUThread& CPU, ppu_opcode_t op); - void DCBST(PPUThread& CPU, ppu_opcode_t op); - void LWZUX(PPUThread& CPU, ppu_opcode_t op); - void CNTLZD(PPUThread& CPU, ppu_opcode_t op); - void ANDC(PPUThread& CPU, ppu_opcode_t op); - void TD(PPUThread& CPU, ppu_opcode_t op); - void LVEWX(PPUThread& CPU, ppu_opcode_t op); - void MULHD(PPUThread& CPU, ppu_opcode_t op); - void MULHW(PPUThread& CPU, ppu_opcode_t op); - void LDARX(PPUThread& CPU, ppu_opcode_t op); - void DCBF(PPUThread& CPU, ppu_opcode_t op); - void LBZX(PPUThread& CPU, ppu_opcode_t op); - void LVX(PPUThread& CPU, ppu_opcode_t op); - void NEG(PPUThread& CPU, ppu_opcode_t op); - void LBZUX(PPUThread& CPU, ppu_opcode_t op); - void NOR(PPUThread& CPU, ppu_opcode_t op); - void STVEBX(PPUThread& CPU, ppu_opcode_t op); - void SUBFE(PPUThread& CPU, ppu_opcode_t op); - void ADDE(PPUThread& CPU, ppu_opcode_t op); - void MTOCRF(PPUThread& CPU, ppu_opcode_t op); - void STDX(PPUThread& CPU, ppu_opcode_t op); - void STWCX_(PPUThread& CPU, ppu_opcode_t op); - void STWX(PPUThread& CPU, ppu_opcode_t op); - void STVEHX(PPUThread& CPU, ppu_opcode_t op); - void STDUX(PPUThread& CPU, ppu_opcode_t op); - void STWUX(PPUThread& CPU, ppu_opcode_t op); - void STVEWX(PPUThread& CPU, ppu_opcode_t op); - void SUBFZE(PPUThread& CPU, ppu_opcode_t op); - void ADDZE(PPUThread& CPU, ppu_opcode_t op); - void STDCX_(PPUThread& CPU, ppu_opcode_t op); - void STBX(PPUThread& CPU, ppu_opcode_t op); - void STVX(PPUThread& CPU, ppu_opcode_t op); - void MULLD(PPUThread& CPU, ppu_opcode_t op); - void SUBFME(PPUThread& CPU, ppu_opcode_t op); - void ADDME(PPUThread& CPU, ppu_opcode_t op); - void MULLW(PPUThread& CPU, ppu_opcode_t op); - void DCBTST(PPUThread& CPU, ppu_opcode_t op); - void STBUX(PPUThread& CPU, ppu_opcode_t op); - void ADD(PPUThread& CPU, ppu_opcode_t op); - void DCBT(PPUThread& CPU, ppu_opcode_t op); - void LHZX(PPUThread& CPU, ppu_opcode_t op); - void EQV(PPUThread& CPU, ppu_opcode_t op); - void ECIWX(PPUThread& CPU, ppu_opcode_t op); - void LHZUX(PPUThread& CPU, ppu_opcode_t op); - void XOR(PPUThread& CPU, ppu_opcode_t op); - void MFSPR(PPUThread& CPU, ppu_opcode_t op); - void LWAX(PPUThread& CPU, ppu_opcode_t op); - void DST(PPUThread& CPU, ppu_opcode_t op); - void LHAX(PPUThread& CPU, ppu_opcode_t op); - void LVXL(PPUThread& CPU, ppu_opcode_t op); - void MFTB(PPUThread& CPU, ppu_opcode_t op); - void LWAUX(PPUThread& CPU, ppu_opcode_t op); - void DSTST(PPUThread& CPU, ppu_opcode_t op); - void LHAUX(PPUThread& CPU, ppu_opcode_t op); - void STHX(PPUThread& CPU, ppu_opcode_t op); - void ORC(PPUThread& CPU, ppu_opcode_t op); - void ECOWX(PPUThread& CPU, ppu_opcode_t op); - void STHUX(PPUThread& CPU, ppu_opcode_t op); - void OR(PPUThread& CPU, ppu_opcode_t op); - void DIVDU(PPUThread& CPU, ppu_opcode_t op); - void DIVWU(PPUThread& CPU, ppu_opcode_t op); - void MTSPR(PPUThread& CPU, ppu_opcode_t op); - void DCBI(PPUThread& CPU, ppu_opcode_t op); - void NAND(PPUThread& CPU, ppu_opcode_t op); - void STVXL(PPUThread& CPU, ppu_opcode_t op); - void DIVD(PPUThread& CPU, ppu_opcode_t op); - void DIVW(PPUThread& CPU, ppu_opcode_t op); - void LVLX(PPUThread& CPU, ppu_opcode_t op); - void LDBRX(PPUThread& CPU, ppu_opcode_t op); - void LSWX(PPUThread& CPU, ppu_opcode_t op); - void LWBRX(PPUThread& CPU, ppu_opcode_t op); - void LFSX(PPUThread& CPU, ppu_opcode_t op); - void SRW(PPUThread& CPU, ppu_opcode_t op); - void SRD(PPUThread& CPU, ppu_opcode_t op); - void LVRX(PPUThread& CPU, ppu_opcode_t op); - void LSWI(PPUThread& CPU, ppu_opcode_t op); - void LFSUX(PPUThread& CPU, ppu_opcode_t op); - void SYNC(PPUThread& CPU, ppu_opcode_t op); - void LFDX(PPUThread& CPU, ppu_opcode_t op); - void LFDUX(PPUThread& CPU, ppu_opcode_t op); - void STVLX(PPUThread& CPU, ppu_opcode_t op); - void STDBRX(PPUThread& CPU, ppu_opcode_t op); - void STSWX(PPUThread& CPU, ppu_opcode_t op); - void STWBRX(PPUThread& CPU, ppu_opcode_t op); - void STFSX(PPUThread& CPU, ppu_opcode_t op); - void STVRX(PPUThread& CPU, ppu_opcode_t op); - void STFSUX(PPUThread& CPU, ppu_opcode_t op); - void STSWI(PPUThread& CPU, ppu_opcode_t op); - void STFDX(PPUThread& CPU, ppu_opcode_t op); - void STFDUX(PPUThread& CPU, ppu_opcode_t op); - void LVLXL(PPUThread& CPU, ppu_opcode_t op); - void LHBRX(PPUThread& CPU, ppu_opcode_t op); - void SRAW(PPUThread& CPU, ppu_opcode_t op); - void SRAD(PPUThread& CPU, ppu_opcode_t op); - void LVRXL(PPUThread& CPU, ppu_opcode_t op); - void DSS(PPUThread& CPU, ppu_opcode_t op); - void SRAWI(PPUThread& CPU, ppu_opcode_t op); - void SRADI(PPUThread& CPU, ppu_opcode_t op); - void EIEIO(PPUThread& CPU, ppu_opcode_t op); - void STVLXL(PPUThread& CPU, ppu_opcode_t op); - void STHBRX(PPUThread& CPU, ppu_opcode_t op); - void EXTSH(PPUThread& CPU, ppu_opcode_t op); - void STVRXL(PPUThread& CPU, ppu_opcode_t op); - void EXTSB(PPUThread& CPU, ppu_opcode_t op); - void STFIWX(PPUThread& CPU, ppu_opcode_t op); - void EXTSW(PPUThread& CPU, ppu_opcode_t op); - void ICBI(PPUThread& CPU, ppu_opcode_t op); - void DCBZ(PPUThread& CPU, ppu_opcode_t op); - void LWZ(PPUThread& CPU, ppu_opcode_t op); - void LWZU(PPUThread& CPU, ppu_opcode_t op); - void LBZ(PPUThread& CPU, ppu_opcode_t op); - void LBZU(PPUThread& CPU, ppu_opcode_t op); - void STW(PPUThread& CPU, ppu_opcode_t op); - void STWU(PPUThread& CPU, ppu_opcode_t op); - void STB(PPUThread& CPU, ppu_opcode_t op); - void STBU(PPUThread& CPU, ppu_opcode_t op); - void LHZ(PPUThread& CPU, ppu_opcode_t op); - void LHZU(PPUThread& CPU, ppu_opcode_t op); - void LHA(PPUThread& CPU, ppu_opcode_t op); - void LHAU(PPUThread& CPU, ppu_opcode_t op); - void STH(PPUThread& CPU, ppu_opcode_t op); - void STHU(PPUThread& CPU, ppu_opcode_t op); - void LMW(PPUThread& CPU, ppu_opcode_t op); - void STMW(PPUThread& CPU, ppu_opcode_t op); - void LFS(PPUThread& CPU, ppu_opcode_t op); - void LFSU(PPUThread& CPU, ppu_opcode_t op); - void LFD(PPUThread& CPU, ppu_opcode_t op); - void LFDU(PPUThread& CPU, ppu_opcode_t op); - void STFS(PPUThread& CPU, ppu_opcode_t op); - void STFSU(PPUThread& CPU, ppu_opcode_t op); - void STFD(PPUThread& CPU, ppu_opcode_t op); - void STFDU(PPUThread& CPU, ppu_opcode_t op); - void LD(PPUThread& CPU, ppu_opcode_t op); - void LDU(PPUThread& CPU, ppu_opcode_t op); - void LWA(PPUThread& CPU, ppu_opcode_t op); - void FDIVS(PPUThread& CPU, ppu_opcode_t op); - void FSUBS(PPUThread& CPU, ppu_opcode_t op); - void FADDS(PPUThread& CPU, ppu_opcode_t op); - void FSQRTS(PPUThread& CPU, ppu_opcode_t op); - void FRES(PPUThread& CPU, ppu_opcode_t op); - void FMULS(PPUThread& CPU, ppu_opcode_t op); - void FMADDS(PPUThread& CPU, ppu_opcode_t op); - void FMSUBS(PPUThread& CPU, ppu_opcode_t op); - void FNMSUBS(PPUThread& CPU, ppu_opcode_t op); - void FNMADDS(PPUThread& CPU, ppu_opcode_t op); - void STD(PPUThread& CPU, ppu_opcode_t op); - void STDU(PPUThread& CPU, ppu_opcode_t op); - void MTFSB1(PPUThread& CPU, ppu_opcode_t op); - void MCRFS(PPUThread& CPU, ppu_opcode_t op); - void MTFSB0(PPUThread& CPU, ppu_opcode_t op); - void MTFSFI(PPUThread& CPU, ppu_opcode_t op); - void MFFS(PPUThread& CPU, ppu_opcode_t op); - void MTFSF(PPUThread& CPU, ppu_opcode_t op); - - void FCMPU(PPUThread& CPU, ppu_opcode_t op); - void FRSP(PPUThread& CPU, ppu_opcode_t op); - void FCTIW(PPUThread& CPU, ppu_opcode_t op); - void FCTIWZ(PPUThread& CPU, ppu_opcode_t op); - void FDIV(PPUThread& CPU, ppu_opcode_t op); - void FSUB(PPUThread& CPU, ppu_opcode_t op); - void FADD(PPUThread& CPU, ppu_opcode_t op); - void FSQRT(PPUThread& CPU, ppu_opcode_t op); - void FSEL(PPUThread& CPU, ppu_opcode_t op); - void FMUL(PPUThread& CPU, ppu_opcode_t op); - void FRSQRTE(PPUThread& CPU, ppu_opcode_t op); - void FMSUB(PPUThread& CPU, ppu_opcode_t op); - void FMADD(PPUThread& CPU, ppu_opcode_t op); - void FNMSUB(PPUThread& CPU, ppu_opcode_t op); - void FNMADD(PPUThread& CPU, ppu_opcode_t op); - void FCMPO(PPUThread& CPU, ppu_opcode_t op); - void FNEG(PPUThread& CPU, ppu_opcode_t op); - void FMR(PPUThread& CPU, ppu_opcode_t op); - void FNABS(PPUThread& CPU, ppu_opcode_t op); - void FABS(PPUThread& CPU, ppu_opcode_t op); - void FCTID(PPUThread& CPU, ppu_opcode_t op); - void FCTIDZ(PPUThread& CPU, ppu_opcode_t op); - void FCFID(PPUThread& CPU, ppu_opcode_t op); - - void UNK(PPUThread& CPU, ppu_opcode_t op); -} - -class PPUInterpreter2 : public PPUOpcodes -{ -public: - virtual ~PPUInterpreter2() {} - - ppu_inter_func_t func; - - virtual void NULL_OP() { func = ppu_interpreter::NULL_OP; } - virtual void NOP() { func = ppu_interpreter::NOP; } - - virtual void TDI(u32 to, u32 ra, s32 simm16) { func = ppu_interpreter::TDI; } - virtual void TWI(u32 to, u32 ra, s32 simm16) { func = ppu_interpreter::TWI; } - - virtual void MFVSCR(u32 vd) { func = ppu_interpreter::MFVSCR; } - virtual void MTVSCR(u32 vb) { func = ppu_interpreter::MTVSCR; } - virtual void VADDCUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDCUW; } - virtual void VADDFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDFP; } - virtual void VADDSBS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDSBS; } - virtual void VADDSHS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDSHS; } - virtual void VADDSWS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDSWS; } - virtual void VADDUBM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDUBM; } - virtual void VADDUBS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDUBS; } - virtual void VADDUHM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDUHM; } - virtual void VADDUHS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDUHS; } - virtual void VADDUWM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDUWM; } - virtual void VADDUWS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDUWS; } - virtual void VAND(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAND; } - virtual void VANDC(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VANDC; } - virtual void VAVGSB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAVGSB; } - virtual void VAVGSH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAVGSH; } - virtual void VAVGSW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAVGSW; } - virtual void VAVGUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAVGUB; } - virtual void VAVGUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAVGUH; } - virtual void VAVGUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAVGUW; } - virtual void VCFSX(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VCFSX; } - virtual void VCFUX(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VCFUX; } - virtual void VCMPBFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPBFP; } - virtual void VCMPBFP_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPBFP_; } - virtual void VCMPEQFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQFP; } - virtual void VCMPEQFP_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQFP_; } - virtual void VCMPEQUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQUB; } - virtual void VCMPEQUB_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQUB_; } - virtual void VCMPEQUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQUH; } - virtual void VCMPEQUH_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQUH_; } - virtual void VCMPEQUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQUW; } - virtual void VCMPEQUW_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQUW_; } - virtual void VCMPGEFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGEFP; } - virtual void VCMPGEFP_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGEFP_; } - virtual void VCMPGTFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTFP; } - virtual void VCMPGTFP_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTFP_; } - virtual void VCMPGTSB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTSB; } - virtual void VCMPGTSB_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTSB_; } - virtual void VCMPGTSH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTSH; } - virtual void VCMPGTSH_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTSH_; } - virtual void VCMPGTSW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTSW; } - virtual void VCMPGTSW_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTSW_; } - virtual void VCMPGTUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTUB; } - virtual void VCMPGTUB_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTUB_; } - virtual void VCMPGTUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTUH; } - virtual void VCMPGTUH_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTUH_; } - virtual void VCMPGTUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTUW; } - virtual void VCMPGTUW_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTUW_; } - virtual void VCTSXS(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VCTSXS; } - virtual void VCTUXS(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VCTUXS; } - virtual void VEXPTEFP(u32 vd, u32 vb) { func = ppu_interpreter::VEXPTEFP; } - virtual void VLOGEFP(u32 vd, u32 vb) { func = ppu_interpreter::VLOGEFP; } - virtual void VMADDFP(u32 vd, u32 va, u32 vc, u32 vb) { func = ppu_interpreter::VMADDFP; } - virtual void VMAXFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXFP; } - virtual void VMAXSB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXSB; } - virtual void VMAXSH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXSH; } - virtual void VMAXSW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXSW; } - virtual void VMAXUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXUB; } - virtual void VMAXUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXUH; } - virtual void VMAXUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXUW; } - virtual void VMHADDSHS(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMHADDSHS; } - virtual void VMHRADDSHS(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMHRADDSHS; } - virtual void VMINFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINFP; } - virtual void VMINSB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINSB; } - virtual void VMINSH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINSH; } - virtual void VMINSW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINSW; } - virtual void VMINUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINUB; } - virtual void VMINUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINUH; } - virtual void VMINUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINUW; } - virtual void VMLADDUHM(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMLADDUHM; } - virtual void VMRGHB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMRGHB; } - virtual void VMRGHH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMRGHH; } - virtual void VMRGHW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMRGHW; } - virtual void VMRGLB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMRGLB; } - virtual void VMRGLH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMRGLH; } - virtual void VMRGLW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMRGLW; } - virtual void VMSUMMBM(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMSUMMBM; } - virtual void VMSUMSHM(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMSUMSHM; } - virtual void VMSUMSHS(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMSUMSHS; } - virtual void VMSUMUBM(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMSUMUBM; } - virtual void VMSUMUHM(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMSUMUHM; } - virtual void VMSUMUHS(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMSUMUHS; } - virtual void VMULESB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULESB; } - virtual void VMULESH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULESH; } - virtual void VMULEUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULEUB; } - virtual void VMULEUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULEUH; } - virtual void VMULOSB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULOSB; } - virtual void VMULOSH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULOSH; } - virtual void VMULOUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULOUB; } - virtual void VMULOUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULOUH; } - virtual void VNMSUBFP(u32 vd, u32 va, u32 vc, u32 vb) { func = ppu_interpreter::VNMSUBFP; } - virtual void VNOR(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VNOR; } - virtual void VOR(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VOR; } - virtual void VPERM(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VPERM; } - virtual void VPKPX(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKPX; } - virtual void VPKSHSS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKSHSS; } - virtual void VPKSHUS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKSHUS; } - virtual void VPKSWSS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKSWSS; } - virtual void VPKSWUS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKSWUS; } - virtual void VPKUHUM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKUHUM; } - virtual void VPKUHUS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKUHUS; } - virtual void VPKUWUM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKUWUM; } - virtual void VPKUWUS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKUWUS; } - virtual void VREFP(u32 vd, u32 vb) { func = ppu_interpreter::VREFP; } - virtual void VRFIM(u32 vd, u32 vb) { func = ppu_interpreter::VRFIM; } - virtual void VRFIN(u32 vd, u32 vb) { func = ppu_interpreter::VRFIN; } - virtual void VRFIP(u32 vd, u32 vb) { func = ppu_interpreter::VRFIP; } - virtual void VRFIZ(u32 vd, u32 vb) { func = ppu_interpreter::VRFIZ; } - virtual void VRLB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VRLB; } - virtual void VRLH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VRLH; } - virtual void VRLW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VRLW; } - virtual void VRSQRTEFP(u32 vd, u32 vb) { func = ppu_interpreter::VRSQRTEFP; } - virtual void VSEL(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VSEL; } - virtual void VSL(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSL; } - virtual void VSLB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSLB; } - virtual void VSLDOI(u32 vd, u32 va, u32 vb, u32 sh) { func = ppu_interpreter::VSLDOI; } - virtual void VSLH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSLH; } - virtual void VSLO(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSLO; } - virtual void VSLW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSLW; } - virtual void VSPLTB(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VSPLTB; } - virtual void VSPLTH(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VSPLTH; } - virtual void VSPLTISB(u32 vd, s32 simm5) { func = ppu_interpreter::VSPLTISB; } - virtual void VSPLTISH(u32 vd, s32 simm5) { func = ppu_interpreter::VSPLTISH; } - virtual void VSPLTISW(u32 vd, s32 simm5) { func = ppu_interpreter::VSPLTISW; } - virtual void VSPLTW(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VSPLTW; } - virtual void VSR(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSR; } - virtual void VSRAB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRAB; } - virtual void VSRAH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRAH; } - virtual void VSRAW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRAW; } - virtual void VSRB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRB; } - virtual void VSRH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRH; } - virtual void VSRO(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRO; } - virtual void VSRW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRW; } - virtual void VSUBCUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBCUW; } - virtual void VSUBFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBFP; } - virtual void VSUBSBS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBSBS; } - virtual void VSUBSHS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBSHS; } - virtual void VSUBSWS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBSWS; } - virtual void VSUBUBM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBUBM; } - virtual void VSUBUBS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBUBS; } - virtual void VSUBUHM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBUHM; } - virtual void VSUBUHS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBUHS; } - virtual void VSUBUWM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBUWM; } - virtual void VSUBUWS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBUWS; } - virtual void VSUMSWS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUMSWS; } - virtual void VSUM2SWS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUM2SWS; } - virtual void VSUM4SBS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUM4SBS; } - virtual void VSUM4SHS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUM4SHS; } - virtual void VSUM4UBS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUM4UBS; } - virtual void VUPKHPX(u32 vd, u32 vb) { func = ppu_interpreter::VUPKHPX; } - virtual void VUPKHSB(u32 vd, u32 vb) { func = ppu_interpreter::VUPKHSB; } - virtual void VUPKHSH(u32 vd, u32 vb) { func = ppu_interpreter::VUPKHSH; } - virtual void VUPKLPX(u32 vd, u32 vb) { func = ppu_interpreter::VUPKLPX; } - virtual void VUPKLSB(u32 vd, u32 vb) { func = ppu_interpreter::VUPKLSB; } - virtual void VUPKLSH(u32 vd, u32 vb) { func = ppu_interpreter::VUPKLSH; } - virtual void VXOR(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VXOR; } - virtual void MULLI(u32 rd, u32 ra, s32 simm16) { func = ppu_interpreter::MULLI; } - virtual void SUBFIC(u32 rd, u32 ra, s32 simm16) { func = ppu_interpreter::SUBFIC; } - virtual void CMPLI(u32 bf, u32 l, u32 ra, u32 uimm16) { func = ppu_interpreter::CMPLI; } - virtual void CMPI(u32 bf, u32 l, u32 ra, s32 simm16) { func = ppu_interpreter::CMPI; } - virtual void ADDIC(u32 rd, u32 ra, s32 simm16) { func = ppu_interpreter::ADDIC; } - virtual void ADDIC_(u32 rd, u32 ra, s32 simm16) { func = ppu_interpreter::ADDIC_; } - virtual void ADDI(u32 rd, u32 ra, s32 simm16) { func = ppu_interpreter::ADDI; } - virtual void ADDIS(u32 rd, u32 ra, s32 simm16) { func = ppu_interpreter::ADDIS; } - virtual void BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) { func = ppu_interpreter::BC; } - virtual void HACK(u32 index) { func = ppu_interpreter::HACK; } - virtual void SC(u32 lev) { func = ppu_interpreter::SC; } - virtual void B(s32 ll, u32 aa, u32 lk) { func = ppu_interpreter::B; } - virtual void MCRF(u32 crfd, u32 crfs) { func = ppu_interpreter::MCRF; } - virtual void BCLR(u32 bo, u32 bi, u32 bh, u32 lk) { func = ppu_interpreter::BCLR; } - virtual void CRNOR(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CRNOR; } - virtual void CRANDC(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CRANDC; } - virtual void ISYNC() { func = ppu_interpreter::ISYNC; } - virtual void CRXOR(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CRXOR; } - virtual void CRNAND(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CRNAND; } - virtual void CRAND(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CRAND; } - virtual void CREQV(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CREQV; } - virtual void CRORC(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CRORC; } - virtual void CROR(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CROR; } - virtual void BCCTR(u32 bo, u32 bi, u32 bh, u32 lk) { func = ppu_interpreter::BCCTR; } - virtual void RLWIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) { func = ppu_interpreter::RLWIMI; } - virtual void RLWINM(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) { func = ppu_interpreter::RLWINM; } - virtual void RLWNM(u32 ra, u32 rs, u32 rb, u32 MB, u32 ME, u32 rc) { func = ppu_interpreter::RLWNM; } - virtual void ORI(u32 rs, u32 ra, u32 uimm16) { func = ppu_interpreter::ORI; } - virtual void ORIS(u32 rs, u32 ra, u32 uimm16) { func = ppu_interpreter::ORIS; } - virtual void XORI(u32 ra, u32 rs, u32 uimm16) { func = ppu_interpreter::XORI; } - virtual void XORIS(u32 ra, u32 rs, u32 uimm16) { func = ppu_interpreter::XORIS; } - virtual void ANDI_(u32 ra, u32 rs, u32 uimm16) { func = ppu_interpreter::ANDI_; } - virtual void ANDIS_(u32 ra, u32 rs, u32 uimm16) { func = ppu_interpreter::ANDIS_; } - virtual void RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) { func = ppu_interpreter::RLDICL; } - virtual void RLDICR(u32 ra, u32 rs, u32 sh, u32 me, u32 rc) { func = ppu_interpreter::RLDICR; } - virtual void RLDIC(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) { func = ppu_interpreter::RLDIC; } - virtual void RLDIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) { func = ppu_interpreter::RLDIMI; } - virtual void RLDC_LR(u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc) { func = ppu_interpreter::RLDC_LR; } - virtual void CMP(u32 crfd, u32 l, u32 ra, u32 rb) { func = ppu_interpreter::CMP; } - virtual void TW(u32 to, u32 ra, u32 rb) { func = ppu_interpreter::TW; } - virtual void LVSL(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVSL; } - virtual void LVEBX(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVEBX; } - virtual void SUBFC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::SUBFC; } - virtual void MULHDU(u32 rd, u32 ra, u32 rb, u32 rc) { func = ppu_interpreter::MULHDU; } - virtual void ADDC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::ADDC; } - virtual void MULHWU(u32 rd, u32 ra, u32 rb, u32 rc) { func = ppu_interpreter::MULHWU; } - virtual void MFOCRF(u32 a, u32 rd, u32 crm) { func = ppu_interpreter::MFOCRF; } - virtual void LWARX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LWARX; } - virtual void LDX(u32 ra, u32 rs, u32 rb) { func = ppu_interpreter::LDX; } - virtual void LWZX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LWZX; } - virtual void SLW(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::SLW; } - virtual void CNTLZW(u32 ra, u32 rs, u32 rc) { func = ppu_interpreter::CNTLZW; } - virtual void SLD(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::SLD; } - virtual void AND(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::AND; } - virtual void CMPL(u32 bf, u32 l, u32 ra, u32 rb) { func = ppu_interpreter::CMPL; } - virtual void LVSR(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVSR; } - virtual void LVEHX(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVEHX; } - virtual void SUBF(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::SUBF; } - virtual void LDUX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LDUX; } - virtual void DCBST(u32 ra, u32 rb) { func = ppu_interpreter::DCBST; } - virtual void LWZUX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LWZUX; } - virtual void CNTLZD(u32 ra, u32 rs, u32 rc) { func = ppu_interpreter::CNTLZD; } - virtual void ANDC(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::ANDC; } - virtual void TD(u32 to, u32 ra, u32 rb) { func = ppu_interpreter::TD; } - virtual void LVEWX(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVEWX; } - virtual void MULHD(u32 rd, u32 ra, u32 rb, u32 rc) { func = ppu_interpreter::MULHD; } - virtual void MULHW(u32 rd, u32 ra, u32 rb, u32 rc) { func = ppu_interpreter::MULHW; } - virtual void LDARX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LDARX; } - virtual void DCBF(u32 ra, u32 rb) { func = ppu_interpreter::DCBF; } - virtual void LBZX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LBZX; } - virtual void LVX(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVX; } - virtual void NEG(u32 rd, u32 ra, u32 oe, u32 rc) { func = ppu_interpreter::NEG; } - virtual void LBZUX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LBZUX; } - virtual void NOR(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::NOR; } - virtual void STVEBX(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVEBX; } - virtual void SUBFE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::SUBFE; } - virtual void ADDE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::ADDE; } - virtual void MTOCRF(u32 l, u32 crm, u32 rs) { func = ppu_interpreter::MTOCRF; } - virtual void STDX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STDX; } - virtual void STWCX_(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STWCX_; } - virtual void STWX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STWX; } - virtual void STVEHX(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVEHX; } - virtual void STDUX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STDUX; } - virtual void STWUX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STWUX; } - virtual void STVEWX(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVEWX; } - virtual void SUBFZE(u32 rd, u32 ra, u32 oe, u32 rc) { func = ppu_interpreter::SUBFZE; } - virtual void ADDZE(u32 rd, u32 ra, u32 oe, u32 rc) { func = ppu_interpreter::ADDZE; } - virtual void STDCX_(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STDCX_; } - virtual void STBX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STBX; } - virtual void STVX(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVX; } - virtual void MULLD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::MULLD; } - virtual void SUBFME(u32 rd, u32 ra, u32 oe, u32 rc) { func = ppu_interpreter::SUBFME; } - virtual void ADDME(u32 rd, u32 ra, u32 oe, u32 rc) { func = ppu_interpreter::ADDME; } - virtual void MULLW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::MULLW; } - virtual void DCBTST(u32 ra, u32 rb, u32 th) { func = ppu_interpreter::DCBTST; } - virtual void STBUX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STBUX; } - virtual void ADD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::ADD; } - virtual void DCBT(u32 ra, u32 rb, u32 th) { func = ppu_interpreter::DCBT; } - virtual void LHZX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LHZX; } - virtual void EQV(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::EQV; } - virtual void ECIWX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::ECIWX; } - virtual void LHZUX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LHZUX; } - virtual void XOR(u32 rs, u32 ra, u32 rb, u32 rc) { func = ppu_interpreter::XOR; } - virtual void MFSPR(u32 rd, u32 spr) { func = ppu_interpreter::MFSPR; } - virtual void LWAX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LWAX; } - virtual void DST(u32 ra, u32 rb, u32 strm, u32 t) { func = ppu_interpreter::DST; } - virtual void LHAX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LHAX; } - virtual void LVXL(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVXL; } - virtual void MFTB(u32 rd, u32 spr) { func = ppu_interpreter::MFTB; } - virtual void LWAUX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LWAUX; } - virtual void DSTST(u32 ra, u32 rb, u32 strm, u32 t) { func = ppu_interpreter::DSTST; } - virtual void LHAUX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LHAUX; } - virtual void STHX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STHX; } - virtual void ORC(u32 rs, u32 ra, u32 rb, u32 rc) { func = ppu_interpreter::ORC; } - virtual void ECOWX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::ECOWX; } - virtual void STHUX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STHUX; } - virtual void OR(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::OR; } - virtual void DIVDU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::DIVDU; } - virtual void DIVWU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::DIVWU; } - virtual void MTSPR(u32 spr, u32 rs) { func = ppu_interpreter::MTSPR; } - virtual void DCBI(u32 ra, u32 rb) { func = ppu_interpreter::DCBI; } - virtual void NAND(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::NAND; } - virtual void STVXL(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVXL; } - virtual void DIVD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::DIVD; } - virtual void DIVW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::DIVW; } - virtual void LVLX(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVLX; } - virtual void LDBRX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LDBRX; } - virtual void LSWX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LSWX; } - virtual void LWBRX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LWBRX; } - virtual void LFSX(u32 frd, u32 ra, u32 rb) { func = ppu_interpreter::LFSX; } - virtual void SRW(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::SRW; } - virtual void SRD(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::SRD; } - virtual void LVRX(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVRX; } - virtual void LSWI(u32 rd, u32 ra, u32 nb) { func = ppu_interpreter::LSWI; } - virtual void LFSUX(u32 frd, u32 ra, u32 rb) { func = ppu_interpreter::LFSUX; } - virtual void SYNC(u32 l) { func = ppu_interpreter::SYNC; } - virtual void LFDX(u32 frd, u32 ra, u32 rb) { func = ppu_interpreter::LFDX; } - virtual void LFDUX(u32 frd, u32 ra, u32 rb) { func = ppu_interpreter::LFDUX; } - virtual void STVLX(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVLX; } - virtual void STDBRX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STDBRX; } - virtual void STSWX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STSWX; } - virtual void STWBRX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STWBRX; } - virtual void STFSX(u32 frs, u32 ra, u32 rb) { func = ppu_interpreter::STFSX; } - virtual void STVRX(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVRX; } - virtual void STFSUX(u32 frs, u32 ra, u32 rb) { func = ppu_interpreter::STFSUX; } - virtual void STSWI(u32 rd, u32 ra, u32 nb) { func = ppu_interpreter::STSWI; } - virtual void STFDX(u32 frs, u32 ra, u32 rb) { func = ppu_interpreter::STFDX; } - virtual void STFDUX(u32 frs, u32 ra, u32 rb) { func = ppu_interpreter::STFDUX; } - virtual void LVLXL(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVLXL; } - virtual void LHBRX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LHBRX; } - virtual void SRAW(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::SRAW; } - virtual void SRAD(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::SRAD; } - virtual void LVRXL(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVRXL; } - virtual void DSS(u32 strm, u32 a) { func = ppu_interpreter::DSS; } - virtual void SRAWI(u32 ra, u32 rs, u32 sh, u32 rc) { func = ppu_interpreter::SRAWI; } - virtual void SRADI1(u32 ra, u32 rs, u32 sh, u32 rc) { func = ppu_interpreter::SRADI; } - virtual void SRADI2(u32 ra, u32 rs, u32 sh, u32 rc) { func = ppu_interpreter::SRADI; } - virtual void EIEIO() { func = ppu_interpreter::EIEIO; } - virtual void STVLXL(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVLXL; } - virtual void STHBRX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STHBRX; } - virtual void EXTSH(u32 ra, u32 rs, u32 rc) { func = ppu_interpreter::EXTSH; } - virtual void STVRXL(u32 sd, u32 ra, u32 rb) { func = ppu_interpreter::STVRXL; } - virtual void EXTSB(u32 ra, u32 rs, u32 rc) { func = ppu_interpreter::EXTSB; } - virtual void STFIWX(u32 frs, u32 ra, u32 rb) { func = ppu_interpreter::STFIWX; } - virtual void EXTSW(u32 ra, u32 rs, u32 rc) { func = ppu_interpreter::EXTSW; } - virtual void ICBI(u32 ra, u32 rb) { func = ppu_interpreter::ICBI; } - virtual void DCBZ(u32 ra, u32 rb) { func = ppu_interpreter::DCBZ; } - virtual void LWZ(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LWZ; } - virtual void LWZU(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LWZU; } - virtual void LBZ(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LBZ; } - virtual void LBZU(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LBZU; } - virtual void STW(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STW; } - virtual void STWU(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STWU; } - virtual void STB(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STB; } - virtual void STBU(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STBU; } - virtual void LHZ(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LHZ; } - virtual void LHZU(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LHZU; } - virtual void LHA(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::LHA; } - virtual void LHAU(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::LHAU; } - virtual void STH(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STH; } - virtual void STHU(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STHU; } - virtual void LMW(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LMW; } - virtual void STMW(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STMW; } - virtual void LFS(u32 frd, u32 ra, s32 d) { func = ppu_interpreter::LFS; } - virtual void LFSU(u32 frd, u32 ra, s32 d) { func = ppu_interpreter::LFSU; } - virtual void LFD(u32 frd, u32 ra, s32 d) { func = ppu_interpreter::LFD; } - virtual void LFDU(u32 frd, u32 ra, s32 d) { func = ppu_interpreter::LFDU; } - virtual void STFS(u32 frs, u32 ra, s32 d) { func = ppu_interpreter::STFS; } - virtual void STFSU(u32 frs, u32 ra, s32 d) { func = ppu_interpreter::STFSU; } - virtual void STFD(u32 frs, u32 ra, s32 d) { func = ppu_interpreter::STFD; } - virtual void STFDU(u32 frs, u32 ra, s32 d) { func = ppu_interpreter::STFDU; } - virtual void LD(u32 rd, u32 ra, s32 ds) { func = ppu_interpreter::LD; } - virtual void LDU(u32 rd, u32 ra, s32 ds) { func = ppu_interpreter::LDU; } - virtual void LWA(u32 rd, u32 ra, s32 ds) { func = ppu_interpreter::LWA; } - virtual void FDIVS(u32 frd, u32 fra, u32 frb, u32 rc) { func = ppu_interpreter::FDIVS; } - virtual void FSUBS(u32 frd, u32 fra, u32 frb, u32 rc) { func = ppu_interpreter::FSUBS; } - virtual void FADDS(u32 frd, u32 fra, u32 frb, u32 rc) { func = ppu_interpreter::FADDS; } - virtual void FSQRTS(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FSQRTS; } - virtual void FRES(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FRES; } - virtual void FMULS(u32 frd, u32 fra, u32 frc, u32 rc) { func = ppu_interpreter::FMULS; } - virtual void FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FMADDS; } - virtual void FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FMSUBS; } - virtual void FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FNMSUBS; } - virtual void FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FNMADDS; } - virtual void STD(u32 rs, u32 ra, s32 ds) { func = ppu_interpreter::STD; } - virtual void STDU(u32 rs, u32 ra, s32 ds) { func = ppu_interpreter::STDU; } - virtual void MTFSB1(u32 bt, u32 rc) { func = ppu_interpreter::MTFSB1; } - virtual void MCRFS(u32 bf, u32 bfa) { func = ppu_interpreter::MCRFS; } - virtual void MTFSB0(u32 bt, u32 rc) { func = ppu_interpreter::MTFSB0; } - virtual void MTFSFI(u32 crfd, u32 i, u32 rc) { func = ppu_interpreter::MTFSFI; } - virtual void MFFS(u32 frd, u32 rc) { func = ppu_interpreter::MFFS; } - virtual void MTFSF(u32 flm, u32 frb, u32 rc) { func = ppu_interpreter::MTFSF; } - - virtual void FCMPU(u32 bf, u32 fra, u32 frb) { func = ppu_interpreter::FCMPU; } - virtual void FRSP(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FRSP; } - virtual void FCTIW(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FCTIW; } - virtual void FCTIWZ(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FCTIWZ; } - virtual void FDIV(u32 frd, u32 fra, u32 frb, u32 rc) { func = ppu_interpreter::FDIV; } - virtual void FSUB(u32 frd, u32 fra, u32 frb, u32 rc) { func = ppu_interpreter::FSUB; } - virtual void FADD(u32 frd, u32 fra, u32 frb, u32 rc) { func = ppu_interpreter::FADD; } - virtual void FSQRT(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FSQRT; } - virtual void FSEL(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FSEL; } - virtual void FMUL(u32 frd, u32 fra, u32 frc, u32 rc) { func = ppu_interpreter::FMUL; } - virtual void FRSQRTE(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FRSQRTE; } - virtual void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FMSUB; } - virtual void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FMADD; } - virtual void FNMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FNMSUB; } - virtual void FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FNMADD; } - virtual void FCMPO(u32 crfd, u32 fra, u32 frb) { func = ppu_interpreter::FCMPO; } - virtual void FNEG(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FNEG; } - virtual void FMR(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FMR; } - virtual void FNABS(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FNABS; } - virtual void FABS(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FABS; } - virtual void FCTID(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FCTID; } - virtual void FCTIDZ(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FCTIDZ; } - virtual void FCFID(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FCFID; } - - virtual void UNK(const u32 code, const u32 opcode, const u32 gcode) { func = ppu_interpreter::UNK; } -}; \ No newline at end of file diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp new file mode 100644 index 0000000000..faec008071 --- /dev/null +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -0,0 +1,1152 @@ +#include "stdafx.h" +#include "Utilities/AutoPause.h" +#include "Crypto/sha1.h" +#include "Loader/ELF.h" +#include "Emu/System.h" +#include "Emu/IdManager.h" + +#include "Emu/Cell/PPUOpcodes.h" +#include "Emu/Cell/PPUModule.h" + +#include "Emu/Cell/lv2/sys_prx.h" + +cfg::bool_entry g_cfg_hook_ppu_funcs(cfg::root.core, "Hook static functions"); +cfg::bool_entry g_cfg_load_liblv2(cfg::root.core, "Load liblv2.sprx only"); + +cfg::set_entry g_cfg_load_libs(cfg::root.core, "Load libraries"); + +extern std::string ppu_get_function_name(const std::string& module, u32 fnid); +extern std::string ppu_get_variable_name(const std::string& module, u32 vnid); + +extern void sys_initialize_tls(PPUThread&, u64, u32, u32, u32); + +// Function lookup table. Not supposed to grow after emulation start. +std::vector g_ppu_function_cache; + +// Function NID cache for autopause. Autopause tool should probably be rewritten. +std::vector g_ppu_fnid_cache; + +extern void ppu_execute_function(PPUThread& ppu, u32 index) +{ + if (index < g_ppu_function_cache.size()) + { + // If autopause occures, check_status() will hold the thread until unpaused. + if (debug::autopause::pause_function(g_ppu_fnid_cache[index]) && ppu.check_status()) throw cpu_state::ret; + + if (const auto func = g_ppu_function_cache[index]) + { + const auto previous_function = ppu.last_function; // TODO: use gsl::finally or something, but only if it's equally fast + + try + { + func(ppu); + } + catch (...) + { + LOG_WARNING(PPU, "Function '%s' aborted", ppu.last_function); + ppu.last_function = previous_function; + throw; + } + + LOG_TRACE(PPU, "Function '%s' finished, r3=0x%llx", ppu.last_function, ppu.GPR[3]); + ppu.last_function = previous_function; + return; + } + } + + throw fmt::exception("Function not registered (index %u)" HERE, index); +} + +extern u32 ppu_generate_id(const char* name) +{ + // Symbol name suffix + const auto suffix = "\x67\x59\x65\x99\x04\x25\x04\x90\x56\x64\x27\x49\x94\x89\x74\x1A"; + + sha1_context ctx; + u8 output[20]; + + // Compute SHA-1 hash + sha1_starts(&ctx); + sha1_update(&ctx, reinterpret_cast(name), std::strlen(name)); + sha1_update(&ctx, reinterpret_cast(suffix), std::strlen(suffix)); + sha1_finish(&ctx, output); + + return reinterpret_cast&>(output[0]); +} + +ppu_static_module::ppu_static_module(const char* name) + : name(name) +{ + ppu_module_manager::register_module(this); +} + +// Initialize static modules. +static void ppu_initialize_modules() +{ + const std::initializer_list registered + { + &ppu_module_manager::cellAdec, + &ppu_module_manager::cellAtrac, + &ppu_module_manager::cellAtracMulti, + &ppu_module_manager::cellAudio, + &ppu_module_manager::cellAvconfExt, + &ppu_module_manager::cellBGDL, + &ppu_module_manager::cellCamera, + &ppu_module_manager::cellCelp8Enc, + &ppu_module_manager::cellCelpEnc, + &ppu_module_manager::cellDaisy, + &ppu_module_manager::cellDmux, + &ppu_module_manager::cellFiber, + &ppu_module_manager::cellFont, + &ppu_module_manager::cellFontFT, + &ppu_module_manager::cellFs, + &ppu_module_manager::cellGame, + &ppu_module_manager::cellGameExec, + &ppu_module_manager::cellGcmSys, + &ppu_module_manager::cellGem, + &ppu_module_manager::cellGifDec, + &ppu_module_manager::cellHttp, + &ppu_module_manager::cellHttps, + &ppu_module_manager::cellHttpUtil, + &ppu_module_manager::cellImeJp, + &ppu_module_manager::cellJpgDec, + &ppu_module_manager::cellJpgEnc, + &ppu_module_manager::cellKey2char, + &ppu_module_manager::cellL10n, + &ppu_module_manager::cellMic, + &ppu_module_manager::cellMusic, + &ppu_module_manager::cellMusicDecode, + &ppu_module_manager::cellMusicExport, + &ppu_module_manager::cellNetCtl, + &ppu_module_manager::cellOskDialog, + &ppu_module_manager::cellOvis, + &ppu_module_manager::cellPamf, + &ppu_module_manager::cellPhotoDecode, + &ppu_module_manager::cellPhotoExport, + &ppu_module_manager::cellPhotoImportUtil, + &ppu_module_manager::cellPngDec, + &ppu_module_manager::cellPngEnc, + &ppu_module_manager::cellPrint, + &ppu_module_manager::cellRec, + &ppu_module_manager::cellRemotePlay, + &ppu_module_manager::cellResc, + &ppu_module_manager::cellRtc, + &ppu_module_manager::cellRudp, + &ppu_module_manager::cellSail, + &ppu_module_manager::cellSailRec, + &ppu_module_manager::cellSaveData, + &ppu_module_manager::cellMinisSaveData, + &ppu_module_manager::cellScreenShot, + &ppu_module_manager::cellSearch, + &ppu_module_manager::cellSheap, + &ppu_module_manager::cellSpudll, + &ppu_module_manager::cellSpurs, + &ppu_module_manager::cellSpursJq, + &ppu_module_manager::cellSsl, + &ppu_module_manager::cellSubdisplay, + &ppu_module_manager::cellSync, + &ppu_module_manager::cellSync2, + &ppu_module_manager::cellSysconf, + &ppu_module_manager::cellSysmodule, + &ppu_module_manager::cellSysutil, + &ppu_module_manager::cellSysutilAp, + &ppu_module_manager::cellSysutilAvc, + &ppu_module_manager::cellSysutilAvc2, + &ppu_module_manager::cellSysutilMisc, + &ppu_module_manager::cellUsbd, + &ppu_module_manager::cellUsbPspcm, + &ppu_module_manager::cellUserInfo, + &ppu_module_manager::cellVdec, + &ppu_module_manager::cellVideoExport, + &ppu_module_manager::cellVideoUpload, + &ppu_module_manager::cellVoice, + &ppu_module_manager::cellVpost, + &ppu_module_manager::libmixer, + &ppu_module_manager::libsnd3, + &ppu_module_manager::libsynth2, + &ppu_module_manager::sceNp, + &ppu_module_manager::sceNp2, + &ppu_module_manager::sceNpClans, + &ppu_module_manager::sceNpCommerce2, + &ppu_module_manager::sceNpSns, + &ppu_module_manager::sceNpTrophy, + &ppu_module_manager::sceNpTus, + &ppu_module_manager::sceNpUtil, + &ppu_module_manager::sys_io, + &ppu_module_manager::libnet, + &ppu_module_manager::sysPrxForUser, + &ppu_module_manager::sys_libc, + &ppu_module_manager::sys_lv2dbg, + }; + + // Reinitialize function cache + g_ppu_function_cache = ppu_function_manager::get(); + g_ppu_fnid_cache = std::vector(g_ppu_function_cache.size()); + + // "Use" all the modules for correct linkage + for (auto& module : registered) + { + LOG_TRACE(LOADER, "Registered static module: %s", module->name); + + for (auto& function : module->functions) + { + LOG_TRACE(LOADER, "** 0x%08X: %s", function.first, function.second.name); + g_ppu_fnid_cache.at(function.second.index) = function.first; + } + + for (auto& variable : module->variables) + { + LOG_TRACE(LOADER, "** &0x%08X: %s (size=0x%x, align=0x%x)", variable.first, variable.second.name, variable.second.size, variable.second.align); + variable.second.var->set(0); + } + } +} + +// Detect import stub at specified address and inject HACK instruction with index immediate. +static bool ppu_patch_import_stub(u32 addr, u32 index) +{ + const auto data = vm::cptr::make(addr); + + using namespace ppu_instructions; + + // Check various patterns: + + if (vm::check_addr(addr, 32) && + (data[0] & 0xffff0000) == LI(r12, 0) && + (data[1] & 0xffff0000) == ORIS(r12, r12, 0) && + (data[2] & 0xffff0000) == LWZ(r12, r12, 0) && + data[3] == STD(r2, r1, 0x28) && + data[4] == LWZ(r0, r12, 0) && + data[5] == LWZ(r2, r12, 4) && + data[6] == MTCTR(r0) && + data[7] == BCTR()) + { + std::memset(vm::base(addr), 0, 32); + vm::write32(addr + 0, STD(r2, r1, 0x28)); // Save RTOC + vm::write32(addr + 4, HACK(index)); + vm::write32(addr + 8, BLR()); + return true; + } + + if (vm::check_addr(addr, 12) && + (data[0] & 0xffff0000) == LI(r0, 0) && + (data[1] & 0xffff0000) == ORIS(r0, r0, 0) && + (data[2] & 0xfc000003) == B(0, 0, 0)) + { + const auto sub = vm::cptr::make(addr + 8 + ((s32)data[2] << 6 >> 8 << 2)); + + if (vm::check_addr(sub.addr(), 60) && + sub[0x0] == STDU(r1, r1, -0x80) && + sub[0x1] == STD(r2, r1, 0x70) && + sub[0x2] == MR(r2, r0) && + sub[0x3] == MFLR(r0) && + sub[0x4] == STD(r0, r1, 0x90) && + sub[0x5] == LWZ(r2, r2, 0) && + sub[0x6] == LWZ(r0, r2, 0) && + sub[0x7] == LWZ(r2, r2, 4) && + sub[0x8] == MTCTR(r0) && + sub[0x9] == BCTRL() && + sub[0xa] == LD(r2, r1, 0x70) && + sub[0xb] == ADDI(r1, r1, 0x80) && + sub[0xc] == LD(r0, r1, 0x10) && + sub[0xd] == MTLR(r0) && + sub[0xe] == BLR()) + { + vm::write32(addr + 0, HACK(index)); + vm::write32(addr + 4, BLR()); + vm::write32(addr + 8, 0); + return true; + } + } + + if (vm::check_addr(addr, 64) && + data[0x0] == MFLR(r0) && + data[0x1] == STD(r0, r1, 0x10) && + data[0x2] == STDU(r1, r1, -0x80) && + data[0x3] == STD(r2, r1, 0x70) && + (data[0x4] & 0xffff0000) == LI(r2, 0) && + (data[0x5] & 0xffff0000) == ORIS(r2, r2, 0) && + data[0x6] == LWZ(r2, r2, 0) && + data[0x7] == LWZ(r0, r2, 0) && + data[0x8] == LWZ(r2, r2, 4) && + data[0x9] == MTCTR(r0) && + data[0xa] == BCTRL() && + data[0xb] == LD(r2, r1, 0x70) && + data[0xc] == ADDI(r1, r1, 0x80) && + data[0xd] == LD(r0, r1, 0x10) && + data[0xe] == MTLR(r0) && + data[0xf] == BLR()) + { + std::memset(vm::base(addr), 0, 64); + vm::write32(addr + 0, HACK(index)); + vm::write32(addr + 4, BLR()); + return true; + } + + if (vm::check_addr(addr, 64) && + data[0x0] == MFLR(r0) && + data[0x1] == STD(r0, r1, 0x10) && + data[0x2] == STDU(r1, r1, -0x80) && + data[0x3] == STD(r2, r1, 0x70) && + (data[0x4] & 0xffff0000) == LIS(r12, 0) && + (data[0x5] & 0xffff0000) == LWZ(r12, r12, 0) && + data[0x6] == LWZ(r0, r12, 0) && + data[0x7] == LWZ(r2, r12, 4) && + data[0x8] == MTCTR(r0) && + data[0x9] == BCTRL() && + data[0xa] == LD(r2, r1, 0x70) && + data[0xb] == ADDI(r1, r1, 0x80) && + data[0xc] == LD(r0, r1, 0x10) && + data[0xd] == MTLR(r0) && + data[0xe] == BLR()) + { + std::memset(vm::base(addr), 0, 64); + vm::write32(addr + 0, HACK(index)); + vm::write32(addr + 4, BLR()); + return true; + } + + if (vm::check_addr(addr, 56) && + (data[0x0] & 0xffff0000) == LI(r12, 0) && + (data[0x1] & 0xffff0000) == ORIS(r12, r12, 0) && + (data[0x2] & 0xffff0000) == LWZ(r12, r12, 0) && + data[0x3] == STD(r2, r1, 0x28) && + data[0x4] == MFLR(r0) && + data[0x5] == STD(r0, r1, 0x20) && + data[0x6] == LWZ(r0, r12, 0) && + data[0x7] == LWZ(r2, r12, 4) && + data[0x8] == MTCTR(r0) && + data[0x9] == BCTRL() && + data[0xa] == LD(r0, r1, 0x20) && + data[0xb] == MTLR(r0) && + data[0xc] == LD(r2, r1, 0x28) && + data[0xd] == BLR()) + { + std::memset(vm::base(addr), 0, 56); + vm::write32(addr + 0, HACK(index)); + vm::write32(addr + 4, BLR()); + return true; + } + + return false; +} + +// Global linkage information +struct ppu_linkage_info +{ + struct module + { + using info_t = std::unordered_map>>; + + info_t functions; + info_t variables; + }; + + // Module -> (NID -> (export; [imports...])) + std::unordered_map modules; +}; + +// Link variable +static void ppu_patch_variable_stub(u32 vref, u32 vaddr) +{ + struct vref_t + { + be_t type; + be_t addr; + be_t unk0; + }; + + for (auto ref = vm::ptr::make(vref); ref->type; ref++) + { + if (ref->unk0) LOG_ERROR(LOADER, "**** VREF(%u): Unknown values (0x%x, 0x%x)", ref->type, ref->addr, ref->unk0); + + // OPs are probably similar to relocations + switch (u32 type = ref->type) + { + case 0x1: + { + const u32 value = vm::_ref(ref->addr) = vaddr; + LOG_WARNING(LOADER, "**** VREF(1): 0x%x <- 0x%x", ref->addr, value); + break; + } + + case 0x4: + case 0x6: + default: LOG_ERROR(LOADER, "**** VREF(%u): Unknown/Illegal type (0x%x, 0x%x)", ref->type, ref->addr, ref->unk0); + } + } +} + +// Export or import module struct +struct ppu_prx_module_info +{ + u8 size; + u8 unk0; + be_t version; + be_t attributes; + be_t num_func; + be_t num_var; + be_t num_tlsvar; + u8 info_hash; + u8 info_tlshash; + u8 unk1[2]; + vm::bcptr name; + vm::bcptr nids; // Imported FNIDs, Exported NIDs + vm::bptr addrs; + vm::bcptr vnids; // Imported VNIDs + vm::bcptr vstubs; + be_t unk4; + be_t unk5; +}; + +// Load and register exports; return special exports found (nameless module) +static auto ppu_load_exports(const std::shared_ptr& link, u32 exports_start, u32 exports_end) +{ + std::unordered_map result; + + for (u32 addr = exports_start; addr < exports_end;) + { + const auto& lib = vm::_ref(addr); + + if (!lib.name) + { + // Set special exports + for (u32 i = 0, end = lib.num_func + lib.num_var; i < end; i++) + { + const u32 nid = lib.nids[i]; + const u32 addr = lib.addrs[i]; + + if (i < lib.num_func) + { + LOG_NOTICE(LOADER, "** Special: [%s] at 0x%x", ppu_get_function_name({}, nid), addr); + } + else + { + LOG_NOTICE(LOADER, "** Special: &[%s] at 0x%x", ppu_get_variable_name({}, nid), addr); + } + + result.emplace(nid, addr); + } + + addr += lib.size ? lib.size : sizeof(ppu_prx_module_info); + continue; + } + + const std::string module_name(lib.name.get_ptr()); + + LOG_NOTICE(LOADER, "** Exported module '%s' (0x%x, 0x%x, 0x%x, 0x%x)", module_name, lib.vnids, lib.vstubs, lib.unk4, lib.unk5); + + if (lib.num_tlsvar) + { + LOG_FATAL(LOADER, "Unexpected num_tlsvar (%u)!", lib.num_tlsvar); + } + + // Static module + const auto _sm = ppu_module_manager::get_module(module_name); + + const auto fnids = +lib.nids; + const auto faddrs = +lib.addrs; + + // Get functions + for (u32 i = 0, end = lib.num_func; i < end; i++) + { + const u32 fnid = fnids[i]; + const u32 faddr = faddrs[i]; + LOG_NOTICE(LOADER, "**** %s export: [%s] at 0x%x", module_name, ppu_get_function_name(module_name, fnid), faddr); + + // Function linkage info + auto& flink = link->modules[module_name].functions[fnid]; + + if (flink.first) + { + LOG_FATAL(LOADER, "Already linked function '%s' in module '%s'", ppu_get_function_name(module_name, fnid), module_name); + } + else + { + // Static function + const auto _sf = _sm && _sm->functions.count(fnid) ? &_sm->functions.at(fnid) : nullptr; + + if (_sf && (_sf->flags & MFF_FORCED_HLE)) + { + // Inject HACK instruction (TODO: guess function size and analyse B instruction, or reimplement BLR flag for HACK instruction) + const auto code = vm::ptr::make(vm::read32(faddr)); + code[0] = ppu_instructions::HACK(_sf->index); + code[1] = ppu_instructions::BLR(); + } + else + { + // Set exported function + flink.first = faddr; + + // Fix imports + for (const auto addr : flink.second) + { + vm::write32(addr, faddr); + //LOG_WARNING(LOADER, "Exported function '%s' in module '%s'", ppu_get_function_name(module_name, fnid), module_name); + } + } + } + } + + const auto vnids = lib.nids + lib.num_func; + const auto vaddrs = lib.addrs + lib.num_func; + + // Get variables + for (u32 i = 0, end = lib.num_var; i < end; i++) + { + const u32 vnid = vnids[i]; + const u32 vaddr = vaddrs[i]; + LOG_NOTICE(LOADER, "**** %s export: &[%s] at 0x%x", module_name, ppu_get_variable_name(module_name, vnid), vaddr); + + // Variable linkage info + auto& vlink = link->modules[module_name].variables[vnid]; + + if (vlink.first) + { + LOG_FATAL(LOADER, "Already linked variable '%s' in module '%s'", ppu_get_variable_name(module_name, vnid), module_name); + } + else + { + // Set exported variable + vlink.first = vaddr; + + // Fix imports + for (const auto vref : vlink.second) + { + ppu_patch_variable_stub(vref, vaddr); + //LOG_WARNING(LOADER, "Exported variable '%s' in module '%s'", ppu_get_variable_name(module_name, vnid), module_name); + } + } + } + + addr += lib.size ? lib.size : sizeof(ppu_prx_module_info); + } + + return result; +} + +static void ppu_load_imports(const std::shared_ptr& link, u32 imports_start, u32 imports_end) +{ + for (u32 addr = imports_start; addr < imports_end;) + { + const auto& lib = vm::_ref(addr); + + const std::string module_name(lib.name.get_ptr()); + + LOG_NOTICE(LOADER, "** Imported module '%s' (0x%x, 0x%x)", module_name, lib.unk4, lib.unk5); + + if (lib.num_tlsvar) + { + LOG_FATAL(LOADER, "Unexpected num_tlsvar (%u)!", lib.num_tlsvar); + } + + // Static module + const auto _sm = ppu_module_manager::get_module(module_name); + + const auto fnids = +lib.nids; + const auto faddrs = +lib.addrs; + + for (u32 i = 0, end = lib.num_func; i < end; i++) + { + const u32 fnid = fnids[i]; + const u32 fstub = faddrs[i]; + const u32 faddr = (faddrs + i).addr(); + LOG_NOTICE(LOADER, "**** %s import: [%s] -> 0x%x", module_name, ppu_get_function_name(module_name, fnid), fstub); + + // Function linkage info + auto& flink = link->modules[module_name].functions[fnid]; + + // Add new import + flink.second.emplace(faddr); + + // Link if available + if (flink.first) vm::write32(faddr, flink.first); + + //LOG_WARNING(LOADER, "Imported function '%s' in module '%s' (0x%x)", ppu_get_function_name(module_name, fnid), module_name, faddr); + } + + const auto vnids = +lib.vnids; + const auto vstubs = +lib.vstubs; + + for (u32 i = 0, end = lib.num_var; i < end; i++) + { + const u32 vnid = vnids[i]; + const u32 vref = vstubs[i]; + LOG_NOTICE(LOADER, "**** %s import: &[%s] (ref=*0x%x)", module_name, ppu_get_variable_name(module_name, vnid), vref); + + // Variable linkage info + auto& vlink = link->modules[module_name].variables[vnid]; + + // Add new import + vlink.second.emplace(vref); + + // Link if available + if (vlink.first) ppu_patch_variable_stub(vref, vlink.first); + + //LOG_WARNING(LOADER, "Imported variable '%s' in module '%s' (0x%x)", ppu_get_variable_name(module_name, vnid), module_name, vlink.first); + } + + addr += lib.size ? lib.size : sizeof(ppu_prx_module_info); + } +} + +template<> +std::shared_ptr ppu_prx_loader::load() const +{ + std::vector segments; + + for (const auto& prog : progs) + { + LOG_NOTICE(LOADER, "** Segment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, flags=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_flags); + + switch (const u32 p_type = prog.p_type) + { + case 0x1: // LOAD + { + if (prog.p_memsz) + { + const u32 mem_size = fmt::narrow("Invalid p_memsz (0x%llx)" HERE, prog.p_memsz); + const u32 file_size = fmt::narrow("Invalid p_filesz (0x%llx)" HERE, prog.p_filesz); + const u32 init_addr = fmt::narrow("Invalid p_vaddr (0x%llx)" HERE, prog.p_vaddr); + + // Alloc segment memory + const u32 addr = vm::alloc(mem_size, vm::main); + + if (!addr) + { + throw fmt::exception("vm::alloc() failed (size=0x%x)", mem_size); + } + + // Copy data + std::memcpy(vm::base(addr), prog.bin.data(), file_size); + LOG_WARNING(LOADER, "**** Loaded to 0x%x (size=0x%x)", addr, mem_size); + + segments.push_back(addr); + } + + break; + } + + case 0x700000a4: break; // Relocations + + default: LOG_ERROR(LOADER, "Unknown segment type! 0x%08x", p_type); + } + } + + // Do relocations + for (auto& prog : progs) + { + switch (const u32 p_type = prog.p_type) + { + case 0x700000a4: + { + // Relocation information of the SCE_PPURELA segment + struct ppu_prx_relocation_info + { + be_t offset; + be_t unk0; + u8 index_value; + u8 index_addr; + be_t type; + vm::bptr ptr; + }; + + for (uint i = 0; i < prog.p_filesz; i += sizeof(ppu_prx_relocation_info)) + { + const auto& rel = reinterpret_cast(prog.bin[i]); + + const u32 raddr = vm::cast(segments.at(rel.index_addr) + rel.offset, HERE); + const u64 rdata = segments.at(rel.index_value) + rel.ptr.addr(); + + switch (const u32 type = rel.type) + { + case 1: + { + const u32 value = vm::_ref(raddr) = static_cast(rdata); + LOG_TRACE(LOADER, "**** RELOCATION(1): 0x%x <- 0x%08x (0x%llx)", raddr, value, rdata); + break; + } + + case 4: + { + const u16 value = vm::_ref(raddr) = static_cast(rdata); + LOG_TRACE(LOADER, "**** RELOCATION(4): 0x%x <- 0x%04x (0x%llx)", raddr, value, rdata); + break; + } + + case 5: + { + const u16 value = vm::_ref(raddr) = static_cast(rdata >> 16); + LOG_TRACE(LOADER, "**** RELOCATION(5): 0x%x <- 0x%04x (0x%llx)", raddr, value, rdata); + break; + } + + case 6: + { + const u16 value = vm::_ref(raddr) = static_cast(rdata >> 16) + (rdata & 0x8000 ? 1 : 0); + LOG_TRACE(LOADER, "**** RELOCATION(6): 0x%x <- 0x%04x (0x%llx)", raddr, value, rdata); + break; + } + + case 10: + case 44: + case 57: + default: LOG_ERROR(LOADER, "**** RELOCATION(%u): Illegal/Unknown type! (addr=0x%x)", type, raddr); + } + } + + break; + } + } + } + + // Access linkage information object + const auto link = fxm::get_always(); + + // Create new PRX object + auto prx = idm::make_ptr(); + + if (!progs.empty() && progs[0].p_paddr) + { + struct ppu_prx_library_info + { + be_t attributes; + be_t version; + char name[28]; + be_t toc; + be_t exports_start; + be_t exports_end; + be_t imports_start; + be_t imports_end; + }; + + // Access library information (TODO) + const auto& lib_info = vm::_ref(vm::cast(segments[0] + progs[0].p_paddr - progs[0].p_offset, HERE)); + const auto& lib_name = std::string(lib_info.name); + + LOG_WARNING(LOADER, "Library %s (toc=0x%x, rtoc=0x%x):", lib_name, lib_info.toc, lib_info.toc + segments[0]); + + prx->specials = ppu_load_exports(link, lib_info.exports_start, lib_info.exports_end); + + ppu_load_imports(link, lib_info.imports_start, lib_info.imports_end); + } + else + { + LOG_FATAL(LOADER, "Library %s: PRX library info not found"); + } + + prx->start.set(prx->specials[0xbc9a0086]); + prx->stop.set(prx->specials[0xab779874]); + prx->exit.set(prx->specials[0x3ab9a95e]); + + return prx; +} + +template<> +void ppu_exec_loader::load() const +{ + ppu_initialize_modules(); + + if (g_cfg_hook_ppu_funcs) + { + LOG_TODO(LOADER, "'Hook static functions' option deactivated"); + } + + // Access linkage information object + const auto link = fxm::get_always(); + + // Allocate memory at fixed positions + for (const auto& prog : progs) + { + const u32 addr = vm::cast(prog.p_vaddr, HERE); + const u32 size = fmt::narrow("Invalid p_memsz: 0x%llx" HERE, prog.p_memsz); + + if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz) + { + if (prog.bin.size() > size || prog.bin.size() != prog.p_filesz) + throw fmt::exception("Invalid binary size (0x%llx, memsz=0x%x)", prog.bin.size(), size); + + if (!vm::falloc(addr, size, vm::main)) + throw fmt::exception("vm::falloc() failed (addr=0x%x, memsz=0x%x)", addr, size); + + std::memcpy(vm::base(addr), prog.bin.data(), prog.bin.size()); + } + } + + // Load other programs + for (auto& prog : progs) + { + switch (const u32 p_type = prog.p_type) + { + case 0x00000001: break; //LOAD + + case 0x00000007: //TLS + { + const u32 addr = vm::cast(prog.p_vaddr, HERE); + const u32 filesz = fmt::narrow("Invalid p_filesz (0x%llx)" HERE, prog.p_filesz); + const u32 memsz = fmt::narrow("Invalid p_memsz (0x%llx)" HERE, prog.p_memsz); + Emu.SetTLSData(addr, filesz, memsz); + LOG_NOTICE(LOADER, "*** TLS segment addr: 0x%08x", Emu.GetTLSAddr()); + LOG_NOTICE(LOADER, "*** TLS segment size: 0x%08x", Emu.GetTLSFilesz()); + LOG_NOTICE(LOADER, "*** TLS memory size: 0x%08x", Emu.GetTLSMemsz()); + break; + } + + case 0x60000001: //LOOS+1 + { + if (prog.p_filesz) + { + struct process_param_t + { + be_t size; + be_t magic; + be_t version; + be_t sdk_version; + be_t primary_prio; + be_t primary_stacksize; + be_t malloc_pagesize; + be_t ppc_seg; + //be_t crash_dump_param_addr; + }; + + const auto& info = vm::ps3::_ref(vm::cast(prog.p_vaddr, HERE)); + + if (info.size < sizeof(process_param_t)) + { + LOG_WARNING(LOADER, "Bad process_param size! [0x%x : 0x%x]", info.size, SIZE_32(process_param_t)); + } + if (info.magic != 0x13bcc5f6) + { + LOG_ERROR(LOADER, "Bad process_param magic! [0x%x]", info.magic); + } + else + { + LOG_NOTICE(LOADER, "*** sdk version: 0x%x", info.sdk_version); + LOG_NOTICE(LOADER, "*** primary prio: %d", info.primary_prio); + LOG_NOTICE(LOADER, "*** primary stacksize: 0x%x", info.primary_stacksize); + LOG_NOTICE(LOADER, "*** malloc pagesize: 0x%x", info.malloc_pagesize); + LOG_NOTICE(LOADER, "*** ppc seg: 0x%x", info.ppc_seg); + //LOG_NOTICE(LOADER, "*** crash dump param addr: 0x%x", info.crash_dump_param_addr); + + Emu.SetParams(info.sdk_version, info.malloc_pagesize, std::max(info.primary_stacksize, 0x4000), info.primary_prio); + } + } + break; + } + + case 0x60000002: //LOOS+2 + { + if (prog.p_filesz) + { + struct ppu_proc_prx_param_t + { + be_t size; + be_t magic; + be_t version; + be_t unk0; + be_t libent_start; + be_t libent_end; + be_t libstub_start; + be_t libstub_end; + be_t ver; + be_t unk1; + be_t unk2; + }; + + const auto& proc_prx_param = vm::_ref(vm::cast(prog.p_vaddr, HERE)); + + if (proc_prx_param.magic != 0x1b434cec) + { + throw fmt::exception("Bad magic! (0x%x)", proc_prx_param.magic); + } + + ppu_load_exports(link, proc_prx_param.libent_start, proc_prx_param.libent_end); + ppu_load_imports(link, proc_prx_param.libstub_start, proc_prx_param.libstub_end); + } + break; + } + default: + { + LOG_ERROR(LOADER, "Unknown phdr type (0x%08x)", p_type); + } + } + } + + // Initialize process + std::vector start_funcs; + + // Load modules + const std::string& lle_dir = vfs::get("/dev_flash/sys/external"); + + if (g_cfg_load_liblv2) + { + const ppu_prx_loader loader = fs::file(lle_dir + "/liblv2.sprx"); + + if (loader == elf_error::ok) + { + start_funcs.push_back(loader.load()->start.addr()); + } + else + { + throw fmt::exception("Failed to load liblv2.sprx: %s", bijective_find(loader, "???")); + } + } + else + { + for (const auto& name : g_cfg_load_libs.get_set()) + { + const ppu_prx_loader loader = fs::file(lle_dir + '/' + name); + + if (loader == elf_error::ok) + { + LOG_WARNING(LOADER, "Loading library: %s", name); + + const auto prx = loader.load(); + + if (prx->start) + { + start_funcs.push_back(prx->start.addr()); + } + } + else + { + LOG_FATAL(LOADER, "Failed to load %s: %s", name, bijective_find(loader, "???")); + } + } + } + + // Check unlinked functions and variables + for (auto& module : link->modules) + { + const auto _sm = ppu_module_manager::get_module(module.first); + + if (!_sm) + { + LOG_ERROR(LOADER, "Unknown module '%s'", module.first); + } + else + { + // Allocate HLE variables (TODO) + for (auto& var : _sm->variables) + { + var.second.var->set(vm::alloc(var.second.size, vm::main, std::max(var.second.align, 4096))); + LOG_WARNING(LOADER, "Allocated variable '%s' in module '%s' at *0x%x", var.second.name, module.first, var.second.var->addr()); + } + + // Initialize HLE variables (TODO) + for (auto& var : _sm->variables) + { + var.second.init(); + } + } + + for (auto& entry : module.second.functions) + { + const u32 fnid = entry.first; + const u32 faddr = entry.second.first; + + if (faddr == 0) + { + if (const auto _sf = _sm && _sm->functions.count(fnid) ? &_sm->functions.at(fnid) : nullptr) + { + // Static function + for (auto& import : entry.second.second) + { + const u32 stub = vm::read32(import); + + if (!ppu_patch_import_stub(stub, _sf->index)) + { + LOG_ERROR(LOADER, "Failed to inject code for function '%s' in module '%s' (0x%x)", _sf->name, module.first, stub); + } + else + { + LOG_NOTICE(LOADER, "Injected hack for function '%s' in module '%s' (*0x%x)", _sf->name, module.first, stub); + } + } + } + else + { + // TODO + const u32 index = ::size32(g_ppu_function_cache); + g_ppu_function_cache.emplace_back(); + g_ppu_fnid_cache.emplace_back(fnid); + + LOG_ERROR(LOADER, "Unknown function '%s' in module '%s' (index %u)", ppu_get_function_name(module.first, fnid), module.first, index); + + for (auto& import : entry.second.second) + { + if (_sm) + { + const u32 stub = vm::read32(import); + + if (!ppu_patch_import_stub(stub, index)) + { + LOG_ERROR(LOADER, "Failed to inject code for function '%s' in module '%s' (0x%x)", ppu_get_function_name(module.first, fnid), module.first, stub); + } + else + { + LOG_NOTICE(LOADER, "Injected hack for function '%s' in module '%s' (*0x%x)", ppu_get_function_name(module.first, fnid), module.first, stub); + } + } + + LOG_WARNING(LOADER, "** Not linked at *0x%x", import); + } + } + } + } + + for (auto& entry : module.second.variables) + { + const u32 vnid = entry.first; + const u32 vaddr = entry.second.first; + + if (vaddr == 0) + { + // Static variable + if (const auto _sv = _sm && _sm->variables.count(vnid) ? &_sm->variables.at(vnid) : nullptr) + { + LOG_NOTICE(LOADER, "Linking HLE variable '%s' in module '%s' (*0x%x):", ppu_get_variable_name(module.first, vnid), module.first, _sv->var->addr()); + + for (auto& ref : entry.second.second) + { + ppu_patch_variable_stub(ref, _sv->var->addr()); + LOG_NOTICE(LOADER, "** Linked at ref=*0x%x", ref); + } + } + else + { + LOG_ERROR(LOADER, "Unknown variable '%s' in module '%s'", ppu_get_variable_name(module.first, vnid), module.first); + + for (auto& ref : entry.second.second) + { + LOG_WARNING(LOADER, "** Not linked at ref=*0x%x", ref); + } + } + } + else + { + // Retro-link LLE variable (TODO: HLE must not be allocated/initialized in this case) + if (const auto _sv = _sm && _sm->variables.count(vnid) ? &_sm->variables.at(vnid) : nullptr) + { + _sv->var->set(vaddr); + LOG_NOTICE(LOADER, "Linked LLE variable '%s' in module '%s' -> 0x%x", ppu_get_variable_name(module.first, vnid), module.first, vaddr); + } + } + } + } + + // TODO: adjust for liblv2 loading option + using namespace ppu_instructions; + + auto ppu_thr_stop_data = vm::ptr::make(vm::alloc(2 * 4, vm::main)); + Emu.SetCPUThreadStop(ppu_thr_stop_data.addr()); + ppu_thr_stop_data[0] = HACK(1); + ppu_thr_stop_data[1] = BLR(); + + static const int branch_size = 10 * 4; + + auto make_branch = [](vm::ptr& ptr, u32 addr) + { + const u32 stub = vm::read32(addr); + const u32 rtoc = vm::read32(addr + 4); + + *ptr++ = LI(r0, 0); + *ptr++ = ORI(r0, r0, stub & 0xffff); + *ptr++ = ORIS(r0, r0, stub >> 16); + *ptr++ = LI(r2, 0); + *ptr++ = ORI(r2, r2, rtoc & 0xffff); + *ptr++ = ORIS(r2, r2, rtoc >> 16); + *ptr++ = MTCTR(r0); + *ptr++ = BCTRL(); + }; + + auto entry = vm::ptr::make(vm::alloc(48 + branch_size * (::size32(start_funcs) + 1), vm::main)); + + // Save initialization args + *entry++ = MR(r14, r3); + *entry++ = MR(r15, r4); + *entry++ = MR(r16, r5); + *entry++ = MR(r17, r6); + *entry++ = MR(r18, r11); + *entry++ = MR(r19, r12); + + if (!g_cfg_load_liblv2) + { + // Call sys_initialize_tls explicitly + *entry++ = MR(r3, r7); + *entry++ = MR(r4, r8); + *entry++ = MR(r5, r9); + *entry++ = MR(r6, r10); + *entry++ = HACK(FIND_FUNC(sys_initialize_tls)); + } + + for (auto& f : start_funcs) + { + // Reset arguments (TODO) + *entry++ = LI(r3, 0); + *entry++ = LI(r4, 0); + make_branch(entry, f); + } + + // Restore initialization args + *entry++ = MR(r3, r14); + *entry++ = MR(r4, r15); + *entry++ = MR(r5, r16); + *entry++ = MR(r6, r17); + *entry++ = MR(r11, r18); + *entry++ = MR(r12, r19); + + // Branch to initialization + make_branch(entry, vm::cast(header.e_entry, HERE)); + + auto ppu = idm::make_ptr("main_thread"); + + ppu->PC = entry.addr() & -0x1000; + ppu->stack_size = Emu.GetPrimaryStackSize(); + ppu->prio = Emu.GetPrimaryPrio(); + ppu->cpu_init(); + + ppu->GPR[2] = 0xdeadbeef; // rtoc + ppu->GPR[11] = 0xabadcafe; // OPD ??? + ppu->GPR[12] = Emu.GetMallocPageSize(); + + std::initializer_list args = { Emu.GetPath()/*, "-emu"s*/ }; + + auto argv = vm::ptr::make(vm::alloc(SIZE_32(u64) * ::size32(args), vm::main)); + auto envp = vm::ptr::make(vm::alloc(::align(SIZE_32(u64), 0x10), vm::main)); + *envp = 0; + + ppu->GPR[3] = args.size(); // argc + ppu->GPR[4] = argv.addr(); + ppu->GPR[5] = envp.addr(); + ppu->GPR[6] = 0; // ??? + + for (const auto& arg : args) + { + const u32 arg_size = ::align(::size32(arg) + 1, 0x10); + const u32 arg_addr = vm::alloc(arg_size, vm::main); + + std::memcpy(vm::base(arg_addr), arg.data(), arg_size); + + *argv++ = arg_addr; + } + + // Arguments for sys_initialize_tls() + ppu->GPR[7] = ppu->id; + ppu->GPR[8] = Emu.GetTLSAddr(); + ppu->GPR[9] = Emu.GetTLSFilesz(); + ppu->GPR[10] = Emu.GetTLSMemsz(); + + // Set memory protections + //for (const auto& prog : progs) + //{ + // const u32 addr = static_cast(prog.p_vaddr); + // const u32 size = static_cast(prog.p_memsz); + + // if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz && (prog.p_flags & 0x2) == 0 /* W */) + // { + // // Set memory protection to read-only where necessary + // ASSERT(vm::page_protect(addr, ::align(size, 0x1000), 0, 0, vm::page_writable)); + // } + //} +} diff --git a/rpcs3/Emu/Cell/PPUModule.h b/rpcs3/Emu/Cell/PPUModule.h new file mode 100644 index 0000000000..81d4dadfcf --- /dev/null +++ b/rpcs3/Emu/Cell/PPUModule.h @@ -0,0 +1,255 @@ +#pragma once + +#include "Utilities/Config.h" +#include "PPUFunction.h" +#include "PPUCallback.h" +#include "ErrorCodes.h" + +namespace vm { using namespace ps3; } + +// Generate FNID or VNID for given name +extern u32 ppu_generate_id(const char* name); + +// Flags set with REG_FUNC +enum ppu_static_function_flags : u32 +{ + MFF_FORCED_HLE = (1 << 0), // Always call HLE function (TODO: deactivated) + + MFF_PERFECT = MFF_FORCED_HLE, // Indicates that function is completely implemented and can replace LLE implementation +}; + +// HLE function information +struct ppu_static_function +{ + const char* name; + u32 index; // Index for ppu_function_manager + u32 flags; +}; + +// HLE variable information +struct ppu_static_variable +{ + const char* name; + vm::gvar* var; // Pointer to variable address storage + void(*init)(); // Variable initialization function + u32 size; + u32 align; +}; + +// HLE module information +class ppu_static_module final +{ +public: + const std::string name; + + task_stack on_load; + task_stack on_unload; + + std::unordered_map functions; + std::unordered_map variables; + +public: + ppu_static_module(const char* name); + + ppu_static_module(const char* name, void(*init)()) + : ppu_static_module(name) + { + init(); + } + + ppu_static_module(const char* name, void(*init)(ppu_static_module* _this)) + : ppu_static_module(name) + { + init(this); + } +}; + +class ppu_module_manager final +{ + friend class ppu_static_module; + + static never_inline auto& access() + { + static std::unordered_map map; + + return map; + } + + static never_inline void register_module(ppu_static_module* module) + { + access().emplace(module->name, module); + } + + static never_inline auto& access_static_function(const char* module, u32 fnid) + { + return access().at(module)->functions[fnid]; + } + + static never_inline auto& access_static_variable(const char* module, u32 vnid) + { + return access().at(module)->variables[vnid]; + } + +public: + static never_inline const ppu_static_module* get_module(const std::string& name) + { + const auto& map = access(); + const auto found = map.find(name); + return found != map.end() ? found->second : nullptr; + } + + template + static void register_static_function(const char* module, const char* name, ppu_function_t func, u32 fnid, u32 flags) + { + auto& info = access_static_function(module, fnid); + + info.name = name; + info.index = ppu_function_manager::register_function(func); + info.flags = flags; + } + + template + static void register_static_variable(const char* module, const char* name, u32 vnid, void(*init)()) + { + static_assert(std::is_same::value, "Static variable registration: vm::gvar expected"); + + auto& info = access_static_variable(module, vnid); + + info.name = name; + info.var = reinterpret_cast*>(Var); + info.init = init ? init : [] {}; + info.size = SIZE_32(typename T::type); + info.align = ALIGN_32(typename T::type); + } + + static const ppu_static_module cellAdec; + static const ppu_static_module cellAtrac; + static const ppu_static_module cellAtracMulti; + static const ppu_static_module cellAudio; + static const ppu_static_module cellAvconfExt; + static const ppu_static_module cellBGDL; + static const ppu_static_module cellCamera; + static const ppu_static_module cellCelp8Enc; + static const ppu_static_module cellCelpEnc; + static const ppu_static_module cellDaisy; + static const ppu_static_module cellDmux; + static const ppu_static_module cellFiber; + static const ppu_static_module cellFont; + static const ppu_static_module cellFontFT; + static const ppu_static_module cellFs; + static const ppu_static_module cellGame; + static const ppu_static_module cellGameExec; + static const ppu_static_module cellGcmSys; + static const ppu_static_module cellGem; + static const ppu_static_module cellGifDec; + static const ppu_static_module cellHttp; + static const ppu_static_module cellHttps; + static const ppu_static_module cellHttpUtil; + static const ppu_static_module cellImeJp; + static const ppu_static_module cellJpgDec; + static const ppu_static_module cellJpgEnc; + static const ppu_static_module cellKey2char; + static const ppu_static_module cellL10n; + static const ppu_static_module cellMic; + static const ppu_static_module cellMusic; + static const ppu_static_module cellMusicDecode; + static const ppu_static_module cellMusicExport; + static const ppu_static_module cellNetCtl; + static const ppu_static_module cellOskDialog; + static const ppu_static_module cellOvis; + static const ppu_static_module cellPamf; + static const ppu_static_module cellPhotoDecode; + static const ppu_static_module cellPhotoExport; + static const ppu_static_module cellPhotoImportUtil; + static const ppu_static_module cellPngDec; + static const ppu_static_module cellPngEnc; + static const ppu_static_module cellPrint; + static const ppu_static_module cellRec; + static const ppu_static_module cellRemotePlay; + static const ppu_static_module cellResc; + static const ppu_static_module cellRtc; + static const ppu_static_module cellRudp; + static const ppu_static_module cellSail; + static const ppu_static_module cellSailRec; + static const ppu_static_module cellSaveData; + static const ppu_static_module cellMinisSaveData; + static const ppu_static_module cellScreenShot; + static const ppu_static_module cellSearch; + static const ppu_static_module cellSheap; + static const ppu_static_module cellSpudll; + static const ppu_static_module cellSpurs; + static const ppu_static_module cellSpursJq; + static const ppu_static_module cellSsl; + static const ppu_static_module cellSubdisplay; + static const ppu_static_module cellSync; + static const ppu_static_module cellSync2; + static const ppu_static_module cellSysconf; + static const ppu_static_module cellSysmodule; + static const ppu_static_module cellSysutil; + static const ppu_static_module cellSysutilAp; + static const ppu_static_module cellSysutilAvc; + static const ppu_static_module cellSysutilAvc2; + static const ppu_static_module cellSysutilMisc; + static const ppu_static_module cellUsbd; + static const ppu_static_module cellUsbPspcm; + static const ppu_static_module cellUserInfo; + static const ppu_static_module cellVdec; + static const ppu_static_module cellVideoExport; + static const ppu_static_module cellVideoUpload; + static const ppu_static_module cellVoice; + static const ppu_static_module cellVpost; + static const ppu_static_module libmixer; + static const ppu_static_module libsnd3; + static const ppu_static_module libsynth2; + static const ppu_static_module sceNp; + static const ppu_static_module sceNp2; + static const ppu_static_module sceNpClans; + static const ppu_static_module sceNpCommerce2; + static const ppu_static_module sceNpSns; + static const ppu_static_module sceNpTrophy; + static const ppu_static_module sceNpTus; + static const ppu_static_module sceNpUtil; + static const ppu_static_module sys_io; + static const ppu_static_module libnet; + static const ppu_static_module sysPrxForUser; + static const ppu_static_module sys_libc; + static const ppu_static_module sys_lv2dbg; +}; + +// Call specified function directly if LLE is not available, call LLE equivalent in callback style otherwise +template> +inline RT ppu_execute_function_or_callback(const char* name, PPUThread& ppu, Args&&... args) +{ + const auto previous_function = ppu.last_function; // TODO + + try + { + return Func(std::forward(args)...); + } + catch (const std::exception&) + { + LOG_ERROR(PPU, "Function '%s' aborted", ppu.last_function); + ppu.last_function = previous_function; + throw; + } + catch (...) + { + LOG_WARNING(PPU, "Function '%s' aborted", ppu.last_function); + ppu.last_function = previous_function; + throw; + } + + ppu.last_function = previous_function; +} + +#define CALL_FUNC(ppu, func, ...) ppu_execute_function_or_callback(#func, ppu, __VA_ARGS__) + +#define REG_FNID(module, nid, func, ...) ppu_module_manager::register_static_function(#module, #func, BIND_FUNC(func), nid, {__VA_ARGS__}) + +#define REG_FUNC(module, func, ...) REG_FNID(module, ppu_generate_id(#func), func, __VA_ARGS__) + +#define REG_VNID(module, nid, var, ...) ppu_module_manager::register_static_variable(#module, #var, nid, {__VA_ARGS__}) + +#define REG_VAR(module, var, ...) REG_VNID(module, ppu_generate_id(#var), var, __VA_ARGS__) + +#define UNIMPLEMENTED_FUNC(module) module.todo("%s", __func__) diff --git a/rpcs3/Emu/Cell/PPUOpcodes.h b/rpcs3/Emu/Cell/PPUOpcodes.h index 185f22905b..36691c9c8e 100644 --- a/rpcs3/Emu/Cell/PPUOpcodes.h +++ b/rpcs3/Emu/Cell/PPUOpcodes.h @@ -1,881 +1,652 @@ #pragma once -namespace PPU_opcodes +#include "../../../Utilities/BitField.h" + +template using ppu_bf_t = bf_t; + +union ppu_opcode_t { - enum PPU_MainOpcodes - { - HACK = 0x01, //HLE Call - TDI = 0x02, //Trap Doubleword Immediate - TWI = 0x03, //Trap Word Immediate - G_04 = 0x04, - MULLI = 0x07, //Multiply Low Immediate - SUBFIC = 0x08, //Subtract from Immediate Carrying - //DOZI = 0x09, - CMPLI = 0x0a, //Compare Logical Immediate - CMPI = 0x0b, //Compare Immediate - ADDIC = 0x0c, //Add Immediate Carrying - ADDIC_ = 0x0d, //Add Immediate Carrying and Record - ADDI = 0x0e, //Add Immediate - ADDIS = 0x0f, //Add Immediate Shifted - BC = 0x10, //Branch Conditional - SC = 0x11, //System Call - B = 0x12, //Branch - G_13 = 0x13, - RLWIMI = 0x14, //Rotate Left Word Immediate then Mask Insert - RLWINM = 0x15, //Rotate Left Word Immediate then AND with Mask - RLWNM = 0x17, //Rotate Left Word then AND with Mask - ORI = 0x18, //OR Immediate - ORIS = 0x19, //OR Immediate Shifted - XORI = 0x1a, //XOR Immediate - XORIS = 0x1b, //XOR Immediate Shifted - ANDI_ = 0x1c, //AND Immediate - ANDIS_ = 0x1d, //AND Immediate Shifted - G_1e = 0x1e, - G_1f = 0x1f, - LWZ = 0x20, //Load Word and Zero Indexed - LWZU = 0x21, //Load Word and Zero with Update Indexed - LBZ = 0x22, //Load Byte and Zero - LBZU = 0x23, //Load Byte and Zero with Update - STW = 0x24, //Store Word - STWU = 0x25, //Store Word with Update - STB = 0x26, //Store Byte - STBU = 0x27, //Store Byte with Update - LHZ = 0x28, //Load Halfword and Zero - LHZU = 0x29, //Load Halfword and Zero with Update - LHA = 0x2a, //Load Halfword Algebraic with Update - LHAU = 0x2b, //Load Halfword Algebraic - STH = 0x2c, //Store Halfword - STHU = 0x2d, //Store Halfword with Update - LMW = 0x2e, //Load Multiple Word - STMW = 0x2f, //Store Multiple Word - LFS = 0x30, //Load Floating-Point Single - LFSU = 0x31, //Load Floating-Point Single with Update - LFD = 0x32, //Load Floating-Point Double - LFDU = 0x33, //Load Floating-Point Double with Update - STFS = 0x34, //Store Floating-Point Single - STFSU = 0x35, //Store Floating-Point Single with Update - STFD = 0x36, //Store Floating-Point Double - STFDU = 0x37, //Store Floating-Point Double with Update - LFQ = 0x38, // - LFQU = 0x39, // - G_3a = 0x3a, - G_3b = 0x3b, - G_3e = 0x3e, - G_3f = 0x3f, - }; + u32 opcode; - enum G_04Opcodes - { - VADDUBM = 0x0, - VMAXUB = 0x2, - VRLB = 0x4, - VCMPEQUB = 0x6, - VMULOUB = 0x8, - VADDFP = 0xa, - VMRGHB = 0xc, - VPKUHUM = 0xe, - VADDUHM = 0x40, - VMAXUH = 0x42, - VRLH = 0x44, - VCMPEQUH = 0x46, - VMULOUH = 0x48, - VSUBFP = 0x4a, - VMRGHH = 0x4c, - VPKUWUM = 0x4e, - VADDUWM = 0x80, - VMAXUW = 0x82, - VRLW = 0x84, - VCMPEQUW = 0x86, - VMRGHW = 0x8c, - VPKUHUS = 0x8e, - VCMPEQFP = 0xc6, - VPKUWUS = 0xce, - VMAXSB = 0x102, - VSLB = 0x104, - VMULOSB = 0x108, - VREFP = 0x10a, - VMRGLB = 0x10c, - VPKSHUS = 0x10e, - VMAXSH = 0x142, - VSLH = 0x144, - VMULOSH = 0x148, - VRSQRTEFP = 0x14a, - VMRGLH = 0x14c, - VPKSWUS = 0x14e, - VADDCUW = 0x180, - VMAXSW = 0x182, - VSLW = 0x184, - VEXPTEFP = 0x18a, - VMRGLW = 0x18c, - VPKSHSS = 0x18e, - VSL = 0x1c4, - VCMPGEFP = 0x1c6, - VLOGEFP = 0x1ca, - VPKSWSS = 0x1ce, - VADDUBS = 0x200, - VMINUB = 0x202, - VSRB = 0x204, - VCMPGTUB = 0x206, - VMULEUB = 0x208, - VRFIN = 0x20a, - VSPLTB = 0x20c, - VUPKHSB = 0x20e, - VADDUHS = 0x240, - VMINUH = 0x242, - VSRH = 0x244, - VCMPGTUH = 0x246, - VMULEUH = 0x248, - VRFIZ = 0x24a, - VSPLTH = 0x24c, - VUPKHSH = 0x24e, - VADDUWS = 0x280, - VMINUW = 0x282, - VSRW = 0x284, - VCMPGTUW = 0x286, - VRFIP = 0x28a, - VSPLTW = 0x28c, - VUPKLSB = 0x28e, - VSR = 0x2c4, - VCMPGTFP = 0x2c6, - VRFIM = 0x2ca, - VUPKLSH = 0x2ce, - VADDSBS = 0x300, - VMINSB = 0x302, - VSRAB = 0x304, - VCMPGTSB = 0x306, - VMULESB = 0x308, - VCFUX = 0x30a, - VSPLTISB = 0x30c, - VPKPX = 0x30e, - VADDSHS = 0x340, - VMINSH = 0x342, - VSRAH = 0x344, - VCMPGTSH = 0x346, - VMULESH = 0x348, - VCFSX = 0x34a, - VSPLTISH = 0x34c, - VUPKHPX = 0x34e, - VADDSWS = 0x380, - VMINSW = 0x382, - VSRAW = 0x384, - VCMPGTSW = 0x386, - VCTUXS = 0x38a, - VSPLTISW = 0x38c, - VCMPBFP = 0x3c6, - VCTSXS = 0x3ca, - VUPKLPX = 0x3ce, - VSUBUBM = 0x400, - VAVGUB = 0x402, - VAND = 0x404, - VCMPEQUB_ = 0x406, - VMAXFP = 0x40a, - VSLO = 0x40c, - VSUBUHM = 0x440, - VAVGUH = 0x442, - VANDC = 0x444, - VCMPEQUH_ = 0x446, - VMINFP = 0x44a, - VSRO = 0x44c, - VSUBUWM = 0x480, - VAVGUW = 0x482, - VOR = 0x484, - VCMPEQUW_ = 0x486, - VXOR = 0x4c4, - VCMPEQFP_ = 0x4c6, - VAVGSB = 0x502, - VNOR = 0x504, - VAVGSH = 0x542, - VSUBCUW = 0x580, - VAVGSW = 0x582, - VCMPGEFP_ = 0x5c6, - VSUBUBS = 0x600, - MFVSCR = 0x604, - VCMPGTUB_ = 0x606, - VSUM4UBS = 0x608, - VSUBUHS = 0x640, - MTVSCR = 0x644, - VCMPGTUH_ = 0x646, - VSUM4SHS = 0x648, - VSUBUWS = 0x680, - VCMPGTUW_ = 0x686, - VSUM2SWS = 0x688, - VCMPGTFP_ = 0x6c6, - VSUBSBS = 0x700, - VCMPGTSB_ = 0x706, - VSUM4SBS = 0x708, - VSUBSHS = 0x740, - VCMPGTSH_ = 0x746, - VSUBSWS = 0x780, - VCMPGTSW_ = 0x786, - VSUMSWS = 0x788, - VCMPBFP_ = 0x7c6, - }; + ppu_bf_t main; // 0..5 + cf_t, ppu_bf_t> sh64; // 30 + 16..20 + cf_t, ppu_bf_t> mbe64; // 26 + 21..25 + ppu_bf_t vuimm; // 11..15 + ppu_bf_t vs; // 6..10 + ppu_bf_t vsh; // 22..25 + ppu_bf_t oe; // 21 + ppu_bf_t spr; // 11..20 + ppu_bf_t vc; // 21..25 + ppu_bf_t vb; // 16..20 + ppu_bf_t va; // 11..15 + ppu_bf_t vd; // 6..10 + ppu_bf_t lk; // 31 + ppu_bf_t aa; // 30 + ppu_bf_t rb; // 16..20 + ppu_bf_t ra; // 11..15 + ppu_bf_t rd; // 6..10 + ppu_bf_t uimm16; // 16..31 + ppu_bf_t l11; // 11 + ppu_bf_t rs; // 6..10 + ppu_bf_t simm16; // 16..31, signed + ppu_bf_t ds; // 16..29, signed + ppu_bf_t vsimm; // 11..15, signed + ppu_bf_t ll; // 6..31, signed + ppu_bf_t lev; // 20..26 + ppu_bf_t i; // 16..19 + ppu_bf_t crfs; // 11..13 + ppu_bf_t l10; // 10 + ppu_bf_t crfd; // 6..8 + ppu_bf_t crbb; // 16..20 + ppu_bf_t crba; // 11..15 + ppu_bf_t crbd; // 6..10 + ppu_bf_t rc; // 31 + ppu_bf_t me32; // 26..30 + ppu_bf_t mb32; // 21..25 + ppu_bf_t sh32; // 16..20 + ppu_bf_t bi; // 11..15 + ppu_bf_t bo; // 6..10 + ppu_bf_t bh; // 19..20 + ppu_bf_t frc; // 21..25 + ppu_bf_t frb; // 16..20 + ppu_bf_t fra; // 11..15 + ppu_bf_t frd; // 6..10 + ppu_bf_t crm; // 12..19 + ppu_bf_t frs; // 6..10 + ppu_bf_t flm; // 7..14 + ppu_bf_t l6; // 6 + ppu_bf_t l15; // 15 +}; - enum G_04_VA_Opcodes - { - VMHADDSHS = 0x20, - VMHRADDSHS = 0x21, - VMLADDUHM = 0x22, - VMSUMUBM = 0x24, - VMSUMMBM = 0x25, - VMSUMUHM = 0x26, - VMSUMUHS = 0x27, - VMSUMSHM = 0x28, - VMSUMSHS = 0x29, - VSEL = 0x2a, - VPERM = 0x2b, - VSLDOI = 0x2c, - VMADDFP = 0x2e, - VNMSUBFP = 0x2f, - }; - - enum G_13Opcodes //Field 21 - 30 - { - MCRF = 0x000, - BCLR = 0x010, - CRNOR = 0x021, - CRANDC = 0x081, - ISYNC = 0x096, - CRXOR = 0x0c1, - CRNAND = 0x0e1, - CRAND = 0x101, - CREQV = 0x121, - CRORC = 0x1a1, - CROR = 0x1c1, - BCCTR = 0x210, - }; - - enum G_1eOpcodes //Field 27 - 29 - { - RLDICL = 0x0, - RLDICR = 0x1, - RLDIC = 0x2, - RLDIMI = 0x3, - RLDC_LR = 0x4, - }; - - enum G_1fOpcodes //Field 21 - 30 - { - CMP = 0x000, - TW = 0x004, - LVSL = 0x006, //Load Vector for Shift Left - LVEBX = 0x007, //Load Vector Element Byte Indexed - SUBFC = 0x008, //Subtract from Carrying - MULHDU = 0x009, - ADDC = 0x00a, - MULHWU = 0x00b, - MFOCRF = 0x013, - LWARX = 0x014, - LDX = 0x015, - LWZX = 0x017, - SLW = 0x018, - CNTLZW = 0x01a, - SLD = 0x01b, - AND = 0x01c, - CMPL = 0x020, - LVSR = 0x026, //Load Vector for Shift Right - LVEHX = 0x027, //Load Vector Element Halfword Indexed - SUBF = 0x028, - LDUX = 0x035, //Load Doubleword with Update Indexed - DCBST = 0x036, //Data Cache Block Store - LWZUX = 0x037, - CNTLZD = 0x03a, - ANDC = 0x03c, - TD = 0x044, - LVEWX = 0x047, //Load Vector Element Word Indexed - MULHD = 0x049, - MULHW = 0x04b, - LDARX = 0x054, - DCBF = 0x056, //Data Cache Block Flush - LBZX = 0x057, - LVX = 0x067, //Load Vector Indexed - NEG = 0x068, - LBZUX = 0x077, - NOR = 0x07c, - STVEBX = 0x087, //Store Vector Element Byte Indexed - SUBFE = 0x088, //Subtract from Extended - ADDE = 0x08a, - MTOCRF = 0x090, - STDX = 0x095, - STWCX_ = 0x096, - STWX = 0x097, - STVEHX = 0x0a7, //Store Vector Element Halfword Indexed - STDUX = 0x0b5, - STWUX = 0x0b7, - STVEWX = 0x0c7, //Store Vector Element Word Indexed - SUBFZE = 0x0c8, - ADDZE = 0x0ca, - STDCX_ = 0x0d6, - STBX = 0x0d7, - STVX = 0x0e7, - SUBFME = 0x0e8, - MULLD = 0x0e9, - ADDME = 0x0ea, - MULLW = 0x0eb, - DCBTST = 0x0f6, //Data Cache Block Touch for Store - STBUX = 0x0f7, - DOZ = 0x108, - ADD = 0x10a, - DCBT = 0x116, //Data Cache Block Touch - LHZX = 0x117, - EQV = 0x11c, - ECIWX = 0x136, - LHZUX = 0x137, - XOR = 0x13c, - MFSPR = 0x153, - LWAX = 0x155, - DST = 0x156, //Data Stream Touch - LHAX = 0x157, - LVXL = 0x167, //Load Vector Indexed Last - MFTB = 0x173, - LWAUX = 0x175, - DSTST = 0x176, //Data Stream Touch for Store - LHAUX = 0x177, - STHX = 0x197, //Store Halfword Indexed - ORC = 0x19c, //OR with Complement - ECOWX = 0x1b6, - STHUX = 0x1b7, - OR = 0x1bc, - DIVDU = 0x1c9, - DIVWU = 0x1cb, - MTSPR = 0x1d3, - DCBI = 0x1d6, //Data Cache Block Invalidate - NAND = 0x1dc, - STVXL = 0x1e7, //Store Vector Indexed Last - DIVD = 0x1e9, - DIVW = 0x1eb, - LVLX = 0x207, //Load Vector Left Indexed - SUBFCO = 0x208, - ADDCO = 0x20a, - LDBRX = 0x214, - LSWX = 0x215, - LWBRX = 0x216, - LFSX = 0x217, - SRW = 0x218, - SRD = 0x21b, - LVRX = 0x227, //Load Vector Right Indexed - SUBFO = 0x228, - LFSUX = 0x237, - LSWI = 0x255, - SYNC = 0x256, - LFDX = 0x257, - NEGO = 0x268, - LFDUX = 0x277, - STVLX = 0x287, //Store Vector Left Indexed - SUBFEO = 0x288, - ADDEO = 0x28a, - STDBRX = 0x294, - STSWX = 0x295, - STWBRX = 0x296, - STFSX = 0x297, - STVRX = 0x2a7, //Store Vector Right Indexed - STFSUX = 0x2b7, - SUBFZEO= 0x2c8, - ADDZEO = 0x2ca, - STSWI = 0x2d5, - STFDX = 0x2d7, //Store Floating-Point Double Indexed - SUBFMEO= 0x2e8, - MULLDO = 0x2e9, - ADDMEO = 0x2ea, - MULLWO = 0x2eb, - STFDUX = 0x2f7, - LVLXL = 0x307, //Load Vector Left Indexed Last - ADDO = 0x30a, - LHBRX = 0x316, - SRAW = 0x318, - SRAD = 0x31a, - LVRXL = 0x327, //Load Vector Right Indexed Last - DSS = 0x336, //Data Stream Stop - SRAWI = 0x338, - SRADI1 = 0x33a, //sh_5 == 0 - SRADI2 = 0x33b, //sh_5 != 0 - EIEIO = 0x356, - STVLXL = 0x387, //Store Vector Left Indexed Last - STHBRX = 0x396, - EXTSH = 0x39a, - STVRXL = 0x3a7, //Store Vector Right Indexed Last - EXTSB = 0x3ba, - DIVDUO = 0x3c9, - DIVWUO = 0x3cb, - STFIWX = 0x3d7, - EXTSW = 0x3da, - ICBI = 0x3d6, //Instruction Cache Block Invalidate - DIVDO = 0x3e9, - DIVWO = 0x3eb, - DCBZ = 0x3f6, //Data Cache Block Set to Zero - }; - - enum G_3aOpcodes //Field 30 - 31 - { - LD = 0x0, - LDU = 0x1, - LWA = 0x2, - }; - - enum G_3bOpcodes //Field 26 - 30 - { - FDIVS = 0x12, - FSUBS = 0x14, - FADDS = 0x15, - FSQRTS = 0x16, - FRES = 0x18, - FMULS = 0x19, - FMSUBS = 0x1c, - FMADDS = 0x1d, - FNMSUBS = 0x1e, - FNMADDS = 0x1f, - }; - - enum G_3eOpcodes //Field 30 - 31 - { - STD = 0x0, - STDU = 0x1, - }; - - enum G_3fOpcodes //Field 21 - 30 - { - MTFSB1 = 0x026, - MCRFS = 0x040, - MTFSB0 = 0x046, - MTFSFI = 0x086, - MFFS = 0x247, - MTFSF = 0x2c7, - - FCMPU = 0x000, - FRSP = 0x00c, - FCTIW = 0x00e, - FCTIWZ = 0x00f, - FDIV = 0x012, - FSUB = 0x014, - FADD = 0x015, - FSQRT = 0x016, - FSEL = 0x017, - FMUL = 0x019, - FRSQRTE = 0x01a, - FMSUB = 0x01c, - FMADD = 0x01d, - FNMSUB = 0x01e, - FNMADD = 0x01f, - FCMPO = 0x020, - FNEG = 0x028, - FMR = 0x048, - FNABS = 0x088, - FABS = 0x108, - FCTID = 0x32e, - FCTIDZ = 0x32f, - FCFID = 0x34e, - }; +inline u32 ppu_branch_target(u32 pc, u32 imm) +{ + return pc + (imm & ~0x3u); } -class PPUOpcodes +inline u64 ppu_branch_target(u64 pc, u64 imm) { -public: - virtual ~PPUOpcodes() {} + return pc + (imm & ~0x3ull); +} - static u32 branchTarget(const u32 pc, const u32 imm) +inline u64 ppu_rotate_mask(u32 mb, u32 me) +{ + const u64 mask = ~0ull << (63 ^ (me - mb)); + return mask >> mb | mask << (64 - mb); // Rotate +} + +inline u32 ppu_decode(u32 inst) +{ + return (inst >> 26 | inst << (32 - 26)) & 0x1ffff; // Rotate + mask +} + +// PPU decoder object. D provides functions. T is function pointer type returned. +template +class ppu_decoder +{ + // Fast lookup table + std::array m_table; + + struct instruction_info { - return pc + (imm & ~0x3ULL); + u32 value; + T pointer; + u32 magn; // Non-zero for "columns" (effectively, number of most significant bits "eaten") + }; + + // Fill lookup table + void fill_table(u32 main_op, u32 count, u32 sh, std::initializer_list entries) + { + if (sh < 11) + { + for (const auto& v : entries) + { + for (u32 i = 0; i < 1u << (v.magn + (11 - sh - count)); i++) + { + for (u32 j = 0; j < 1u << sh; j++) + { + m_table.at((((((i << (count - v.magn)) | v.value) << sh) | j) << 6) | main_op) = v.pointer; + } + } + } + } + else + { + // Main table (special case) + for (const auto& v : entries) + { + for (u32 i = 0; i < 1u << 11; i++) + { + m_table.at(i << 6 | v.value) = v.pointer; + } + } + } } - virtual void NULL_OP() = 0; - virtual void NOP() = 0; +public: + ppu_decoder() + { + m_table.fill(&D::UNK); - virtual void TDI(u32 to, u32 ra, s32 simm16) = 0; - virtual void TWI(u32 to, u32 ra, s32 simm16) = 0; + // Main opcodes (field 0..5) + fill_table(0x00, 6, -1, + { + { 0x01, &D::HACK }, + { 0x02, &D::TDI }, + { 0x03, &D::TWI }, + { 0x07, &D::MULLI }, + { 0x08, &D::SUBFIC }, + { 0x0a, &D::CMPLI }, + { 0x0b, &D::CMPI }, + { 0x0c, &D::ADDIC }, + { 0x0d, &D::ADDIC }, + { 0x0e, &D::ADDI }, + { 0x0f, &D::ADDIS }, + { 0x10, &D::BC }, + { 0x11, &D::SC }, + { 0x12, &D::B }, + { 0x14, &D::RLWIMI }, + { 0x15, &D::RLWINM }, + { 0x17, &D::RLWNM }, + { 0x18, &D::ORI }, + { 0x19, &D::ORIS }, + { 0x1a, &D::XORI }, + { 0x1b, &D::XORIS }, + { 0x1c, &D::ANDI }, + { 0x1d, &D::ANDIS }, + { 0x20, &D::LWZ }, + { 0x21, &D::LWZU }, + { 0x22, &D::LBZ }, + { 0x23, &D::LBZU }, + { 0x24, &D::STW }, + { 0x25, &D::STWU }, + { 0x26, &D::STB }, + { 0x27, &D::STBU }, + { 0x28, &D::LHZ }, + { 0x29, &D::LHZU }, + { 0x2a, &D::LHA }, + { 0x2b, &D::LHAU }, + { 0x2c, &D::STH }, + { 0x2d, &D::STHU }, + { 0x2e, &D::LMW }, + { 0x2f, &D::STMW }, + { 0x30, &D::LFS }, + { 0x31, &D::LFSU }, + { 0x32, &D::LFD }, + { 0x33, &D::LFDU }, + { 0x34, &D::STFS }, + { 0x35, &D::STFSU }, + { 0x36, &D::STFD }, + { 0x37, &D::STFDU }, + }); - virtual void MFVSCR(u32 vd) = 0; - virtual void MTVSCR(u32 vb) = 0; - virtual void VADDCUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDSBS(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDSHS(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDSWS(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDUBM(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDUBS(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDUHM(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDUHS(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDUWM(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDUWS(u32 vd, u32 va, u32 vb) = 0; - virtual void VAND(u32 vd, u32 va, u32 vb) = 0; - virtual void VANDC(u32 vd, u32 va, u32 vb) = 0; - virtual void VAVGSB(u32 vd, u32 va, u32 vb) = 0; - virtual void VAVGSH(u32 vd, u32 va, u32 vb) = 0; - virtual void VAVGSW(u32 vd, u32 va, u32 vb) = 0; - virtual void VAVGUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VAVGUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VAVGUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VCFSX(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VCFUX(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VCMPBFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPBFP_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQFP_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQUB_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQUH_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQUW_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGEFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGEFP_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTFP_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTSB(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTSB_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTSH(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTSH_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTSW(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTSW_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTUB_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTUH_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTUW_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCTSXS(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VCTUXS(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VEXPTEFP(u32 vd, u32 vb) = 0; - virtual void VLOGEFP(u32 vd, u32 vb) = 0; - virtual void VMADDFP(u32 vd, u32 va, u32 vc, u32 vb) = 0; - virtual void VMAXFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VMAXSB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMAXSH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMAXSW(u32 vd, u32 va, u32 vb) = 0; - virtual void VMAXUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMAXUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMAXUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VMHADDSHS(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMHRADDSHS(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMINFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VMINSB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMINSH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMINSW(u32 vd, u32 va, u32 vb) = 0; - virtual void VMINUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMINUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMINUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VMLADDUHM(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMRGHB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMRGHH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMRGHW(u32 vd, u32 va, u32 vb) = 0; - virtual void VMRGLB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMRGLH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMRGLW(u32 vd, u32 va, u32 vb) = 0; - virtual void VMSUMMBM(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMSUMSHM(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMSUMSHS(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMSUMUBM(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMSUMUHM(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMSUMUHS(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMULESB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULESH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULEUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULEUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULOSB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULOSH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULOUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULOUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VNMSUBFP(u32 vd, u32 va, u32 vc, u32 vb) = 0; - virtual void VNOR(u32 vd, u32 va, u32 vb) = 0; - virtual void VOR(u32 vd, u32 va, u32 vb) = 0; - virtual void VPERM(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VPKPX(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKSHSS(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKSHUS(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKSWSS(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKSWUS(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKUHUM(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKUHUS(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKUWUM(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKUWUS(u32 vd, u32 va, u32 vb) = 0; - virtual void VREFP(u32 vd, u32 vb) = 0; - virtual void VRFIM(u32 vd, u32 vb) = 0; - virtual void VRFIN(u32 vd, u32 vb) = 0; - virtual void VRFIP(u32 vd, u32 vb) = 0; - virtual void VRFIZ(u32 vd, u32 vb) = 0; - virtual void VRLB(u32 vd, u32 va, u32 vb) = 0; - virtual void VRLH(u32 vd, u32 va, u32 vb) = 0; - virtual void VRLW(u32 vd, u32 va, u32 vb) = 0; - virtual void VRSQRTEFP(u32 vd, u32 vb) = 0; - virtual void VSEL(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VSL(u32 vd, u32 va, u32 vb) = 0; - virtual void VSLB(u32 vd, u32 va, u32 vb) = 0; - virtual void VSLDOI(u32 vd, u32 va, u32 vb, u32 sh) = 0; - virtual void VSLH(u32 vd, u32 va, u32 vb) = 0; - virtual void VSLO(u32 vd, u32 va, u32 vb) = 0; - virtual void VSLW(u32 vd, u32 va, u32 vb) = 0; - virtual void VSPLTB(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VSPLTH(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VSPLTISB(u32 vd, s32 simm5) = 0; - virtual void VSPLTISH(u32 vd, s32 simm5) = 0; - virtual void VSPLTISW(u32 vd, s32 simm5) = 0; - virtual void VSPLTW(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VSR(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRAB(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRAH(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRAW(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRB(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRH(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRO(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRW(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBCUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBSBS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBSHS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBSWS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBUBM(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBUBS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBUHM(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBUHS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBUWM(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBUWS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUMSWS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUM2SWS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUM4SBS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUM4SHS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUM4UBS(u32 vd, u32 va, u32 vb) = 0; - virtual void VUPKHPX(u32 vd, u32 vb) = 0; - virtual void VUPKHSB(u32 vd, u32 vb) = 0; - virtual void VUPKHSH(u32 vd, u32 vb) = 0; - virtual void VUPKLPX(u32 vd, u32 vb) = 0; - virtual void VUPKLSB(u32 vd, u32 vb) = 0; - virtual void VUPKLSH(u32 vd, u32 vb) = 0; - virtual void VXOR(u32 vd, u32 va, u32 vb) = 0; - virtual void MULLI(u32 rd, u32 ra, s32 simm16) = 0; - virtual void SUBFIC(u32 rd, u32 ra, s32 simm16) = 0; - virtual void CMPLI(u32 bf, u32 l, u32 ra, u32 uimm16) = 0; - virtual void CMPI(u32 bf, u32 l, u32 ra, s32 simm16) = 0; - virtual void ADDIC(u32 rd, u32 ra, s32 simm16) = 0; - virtual void ADDIC_(u32 rd, u32 ra, s32 simm16) = 0; - virtual void ADDI(u32 rd, u32 ra, s32 simm16) = 0; - virtual void ADDIS(u32 rd, u32 ra, s32 simm16) = 0; - virtual void BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) = 0; - virtual void HACK(u32 index) = 0; - virtual void SC(u32 lev) = 0; - virtual void B(s32 ll, u32 aa, u32 lk) = 0; - virtual void MCRF(u32 crfd, u32 crfs) = 0; - virtual void BCLR(u32 bo, u32 bi, u32 bh, u32 lk) = 0; - virtual void CRNOR(u32 bt, u32 ba, u32 bb) = 0; - virtual void CRANDC(u32 bt, u32 ba, u32 bb) = 0; - virtual void ISYNC() = 0; - virtual void CRXOR(u32 bt, u32 ba, u32 bb) = 0; - virtual void CRNAND(u32 bt, u32 ba, u32 bb) = 0; - virtual void CRAND(u32 bt, u32 ba, u32 bb) = 0; - virtual void CREQV(u32 bt, u32 ba, u32 bb) = 0; - virtual void CRORC(u32 bt, u32 ba, u32 bb) = 0; - virtual void CROR(u32 bt, u32 ba, u32 bb) = 0; - virtual void BCCTR(u32 bo, u32 bi, u32 bh, u32 lk) = 0; - virtual void RLWIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) = 0; - virtual void RLWINM(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) = 0; - virtual void RLWNM(u32 ra, u32 rs, u32 rb, u32 MB, u32 ME, u32 rc) = 0; - virtual void ORI(u32 rs, u32 ra, u32 uimm16) = 0; - virtual void ORIS(u32 rs, u32 ra, u32 uimm16) = 0; - virtual void XORI(u32 ra, u32 rs, u32 uimm16) = 0; - virtual void XORIS(u32 ra, u32 rs, u32 uimm16) = 0; - virtual void ANDI_(u32 ra, u32 rs, u32 uimm16) = 0; - virtual void ANDIS_(u32 ra, u32 rs, u32 uimm16) = 0; - virtual void RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) = 0; - virtual void RLDICR(u32 ra, u32 rs, u32 sh, u32 me, u32 rc) = 0; - virtual void RLDIC(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) = 0; - virtual void RLDIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) = 0; - virtual void RLDC_LR(u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc) = 0; - virtual void CMP(u32 crfd, u32 l, u32 ra, u32 rb) = 0; - virtual void TW(u32 to, u32 ra, u32 rb) = 0; - virtual void LVSL(u32 vd, u32 ra, u32 rb) = 0; - virtual void LVEBX(u32 vd, u32 ra, u32 rb) = 0; - virtual void SUBFC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void MULHDU(u32 rd, u32 ra, u32 rb, u32 rc) = 0; - virtual void ADDC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void MULHWU(u32 rd, u32 ra, u32 rb, u32 rc) = 0; - virtual void MFOCRF(u32 a, u32 rd, u32 crm) = 0; - virtual void LWARX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LDX(u32 ra, u32 rs, u32 rb) = 0; - virtual void LWZX(u32 rd, u32 ra, u32 rb) = 0; - virtual void SLW(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void CNTLZW(u32 ra, u32 rs, u32 rc) = 0; - virtual void SLD(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void AND(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void CMPL(u32 bf, u32 l, u32 ra, u32 rb) = 0; - virtual void LVSR(u32 vd, u32 ra, u32 rb) = 0; - virtual void LVEHX(u32 vd, u32 ra, u32 rb) = 0; - virtual void SUBF(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void LDUX(u32 rd, u32 ra, u32 rb) = 0; - virtual void DCBST(u32 ra, u32 rb) = 0; - virtual void LWZUX(u32 rd, u32 ra, u32 rb) = 0; - virtual void CNTLZD(u32 ra, u32 rs, u32 rc) = 0; - virtual void ANDC(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void TD(u32 to, u32 ra, u32 rb) = 0; - virtual void LVEWX(u32 vd, u32 ra, u32 rb) = 0; - virtual void MULHD(u32 rd, u32 ra, u32 rb, u32 rc) = 0; - virtual void MULHW(u32 rd, u32 ra, u32 rb, u32 rc) = 0; - virtual void LDARX(u32 rd, u32 ra, u32 rb) = 0; - virtual void DCBF(u32 ra, u32 rb) = 0; - virtual void LBZX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LVX(u32 vd, u32 ra, u32 rb) = 0; - virtual void NEG(u32 rd, u32 ra, u32 oe, u32 rc) = 0; - virtual void LBZUX(u32 rd, u32 ra, u32 rb) = 0; - virtual void NOR(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void STVEBX(u32 vs, u32 ra, u32 rb) = 0; - virtual void SUBFE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void ADDE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void MTOCRF(u32 l, u32 crm, u32 rs) = 0; - virtual void STDX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STWCX_(u32 rs, u32 ra, u32 rb) = 0; - virtual void STWX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STVEHX(u32 vs, u32 ra, u32 rb) = 0; - virtual void STDUX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STWUX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STVEWX(u32 vs, u32 ra, u32 rb) = 0; - virtual void SUBFZE(u32 rd, u32 ra, u32 oe, u32 rc) = 0; - virtual void ADDZE(u32 rd, u32 ra, u32 oe, u32 rc) = 0; - virtual void STDCX_(u32 rs, u32 ra, u32 rb) = 0; - virtual void STBX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STVX(u32 vs, u32 ra, u32 rb) = 0; - virtual void MULLD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void SUBFME(u32 rd, u32 ra, u32 oe, u32 rc) = 0; - virtual void ADDME(u32 rd, u32 ra, u32 oe, u32 rc) = 0; - virtual void MULLW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void DCBTST(u32 ra, u32 rb, u32 th) = 0; - virtual void STBUX(u32 rs, u32 ra, u32 rb) = 0; - virtual void ADD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void DCBT(u32 ra, u32 rb, u32 th) = 0; - virtual void LHZX(u32 rd, u32 ra, u32 rb) = 0; - virtual void EQV(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void ECIWX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LHZUX(u32 rd, u32 ra, u32 rb) = 0; - virtual void XOR(u32 rs, u32 ra, u32 rb, u32 rc) = 0; - virtual void MFSPR(u32 rd, u32 spr) = 0; - virtual void LWAX(u32 rd, u32 ra, u32 rb) = 0; - virtual void DST(u32 ra, u32 rb, u32 strm, u32 t) = 0; - virtual void LHAX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LVXL(u32 vd, u32 ra, u32 rb) = 0; - virtual void MFTB(u32 rd, u32 spr) = 0; - virtual void LWAUX(u32 rd, u32 ra, u32 rb) = 0; - virtual void DSTST(u32 ra, u32 rb, u32 strm, u32 t) = 0; - virtual void LHAUX(u32 rd, u32 ra, u32 rb) = 0; - virtual void STHX(u32 rs, u32 ra, u32 rb) = 0; - virtual void ORC(u32 rs, u32 ra, u32 rb, u32 rc) = 0; - virtual void ECOWX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STHUX(u32 rs, u32 ra, u32 rb) = 0; - virtual void OR(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void DIVDU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void DIVWU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void MTSPR(u32 spr, u32 rs) = 0; - virtual void DCBI(u32 ra, u32 rb) = 0; - virtual void NAND(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void STVXL(u32 vs, u32 ra, u32 rb) = 0; - virtual void DIVD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void DIVW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void LVLX(u32 vd, u32 ra, u32 rb) = 0; - virtual void LDBRX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LSWX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LWBRX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LFSX(u32 frd, u32 ra, u32 rb) = 0; - virtual void SRW(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void SRD(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void LVRX(u32 vd, u32 ra, u32 rb) = 0; - virtual void LSWI(u32 rd, u32 ra, u32 nb) = 0; - virtual void LFSUX(u32 frd, u32 ra, u32 rb) = 0; - virtual void SYNC(u32 l) = 0; - virtual void LFDX(u32 frd, u32 ra, u32 rb) = 0; - virtual void LFDUX(u32 frd, u32 ra, u32 rb) = 0; - virtual void STVLX(u32 vs, u32 ra, u32 rb) = 0; - virtual void STDBRX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STSWX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STWBRX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STFSX(u32 frs, u32 ra, u32 rb) = 0; - virtual void STVRX(u32 vs, u32 ra, u32 rb) = 0; - virtual void STFSUX(u32 frs, u32 ra, u32 rb) = 0; - virtual void STSWI(u32 rd, u32 ra, u32 nb) = 0; - virtual void STFDX(u32 frs, u32 ra, u32 rb) = 0; - virtual void STFDUX(u32 frs, u32 ra, u32 rb) = 0; - virtual void LVLXL(u32 vd, u32 ra, u32 rb) = 0; - virtual void LHBRX(u32 rd, u32 ra, u32 rb) = 0; - virtual void SRAW(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void SRAD(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void LVRXL(u32 vd, u32 ra, u32 rb) = 0; - virtual void DSS(u32 strm, u32 a) = 0; - virtual void SRAWI(u32 ra, u32 rs, u32 sh, u32 rc) = 0; - virtual void SRADI1(u32 ra, u32 rs, u32 sh, u32 rc) = 0; - virtual void SRADI2(u32 ra, u32 rs, u32 sh, u32 rc) = 0; - virtual void EIEIO() = 0; - virtual void STVLXL(u32 vs, u32 ra, u32 rb) = 0; - virtual void STHBRX(u32 rs, u32 ra, u32 rb) = 0; - virtual void EXTSH(u32 ra, u32 rs, u32 rc) = 0; - virtual void STVRXL(u32 sd, u32 ra, u32 rb) = 0; - virtual void EXTSB(u32 ra, u32 rs, u32 rc) = 0; - virtual void STFIWX(u32 frs, u32 ra, u32 rb) = 0; - virtual void EXTSW(u32 ra, u32 rs, u32 rc) = 0; - virtual void ICBI(u32 ra, u32 rb) = 0; - virtual void DCBZ(u32 ra, u32 rb) = 0; - virtual void LWZ(u32 rd, u32 ra, s32 d) = 0; - virtual void LWZU(u32 rd, u32 ra, s32 d) = 0; - virtual void LBZ(u32 rd, u32 ra, s32 d) = 0; - virtual void LBZU(u32 rd, u32 ra, s32 d) = 0; - virtual void STW(u32 rs, u32 ra, s32 d) = 0; - virtual void STWU(u32 rs, u32 ra, s32 d) = 0; - virtual void STB(u32 rs, u32 ra, s32 d) = 0; - virtual void STBU(u32 rs, u32 ra, s32 d) = 0; - virtual void LHZ(u32 rd, u32 ra, s32 d) = 0; - virtual void LHZU(u32 rd, u32 ra, s32 d) = 0; - virtual void LHA(u32 rs, u32 ra, s32 d) = 0; - virtual void LHAU(u32 rs, u32 ra, s32 d) = 0; - virtual void STH(u32 rs, u32 ra, s32 d) = 0; - virtual void STHU(u32 rs, u32 ra, s32 d) = 0; - virtual void LMW(u32 rd, u32 ra, s32 d) = 0; - virtual void STMW(u32 rs, u32 ra, s32 d) = 0; - virtual void LFS(u32 frd, u32 ra, s32 d) = 0; - virtual void LFSU(u32 frd, u32 ra, s32 d) = 0; - virtual void LFD(u32 frd, u32 ra, s32 d) = 0; - virtual void LFDU(u32 frd, u32 ra, s32 d) = 0; - virtual void STFS(u32 frs, u32 ra, s32 d) = 0; - virtual void STFSU(u32 frs, u32 ra, s32 d) = 0; - virtual void STFD(u32 frs, u32 ra, s32 d) = 0; - virtual void STFDU(u32 frs, u32 ra, s32 d) = 0; - virtual void LD(u32 rd, u32 ra, s32 ds) = 0; - virtual void LDU(u32 rd, u32 ra, s32 ds) = 0; - virtual void LWA(u32 rd, u32 ra, s32 ds) = 0; - virtual void FDIVS(u32 frd, u32 fra, u32 frb, u32 rc) = 0; - virtual void FSUBS(u32 frd, u32 fra, u32 frb, u32 rc) = 0; - virtual void FADDS(u32 frd, u32 fra, u32 frb, u32 rc) = 0; - virtual void FSQRTS(u32 frd, u32 frb, u32 rc) = 0; - virtual void FRES(u32 frd, u32 frb, u32 rc) = 0; - virtual void FMULS(u32 frd, u32 fra, u32 frc, u32 rc) = 0; - virtual void FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void STD(u32 rs, u32 ra, s32 ds) = 0; - virtual void STDU(u32 rs, u32 ra, s32 ds) = 0; - virtual void MTFSB1(u32 bt, u32 rc) = 0; - virtual void MCRFS(u32 bf, u32 bfa) = 0; - virtual void MTFSB0(u32 bt, u32 rc) = 0; - virtual void MTFSFI(u32 crfd, u32 i, u32 rc) = 0; - virtual void MFFS(u32 frd, u32 rc) = 0; - virtual void MTFSF(u32 flm, u32 frb, u32 rc) = 0; + // Group 0x04 opcodes (field 21..31) + fill_table(0x04, 11, 0, + { + { 0x0, &D::VADDUBM }, + { 0x2, &D::VMAXUB }, + { 0x4, &D::VRLB }, + { 0x6, &D::VCMPEQUB, 1 }, + { 0x8, &D::VMULOUB }, + { 0xa, &D::VADDFP }, + { 0xc, &D::VMRGHB }, + { 0xe, &D::VPKUHUM }, - virtual void FCMPU(u32 bf, u32 fra, u32 frb) = 0; - virtual void FRSP(u32 frd, u32 frb, u32 rc) = 0; - virtual void FCTIW(u32 frd, u32 frb, u32 rc) = 0; - virtual void FCTIWZ(u32 frd, u32 frb, u32 rc) = 0; - virtual void FDIV(u32 frd, u32 fra, u32 frb, u32 rc) = 0; - virtual void FSUB(u32 frd, u32 fra, u32 frb, u32 rc) = 0; - virtual void FADD(u32 frd, u32 fra, u32 frb, u32 rc) = 0; - virtual void FSQRT(u32 frd, u32 frb, u32 rc) = 0; - virtual void FSEL(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FMUL(u32 frd, u32 fra, u32 frc, u32 rc) = 0; - virtual void FRSQRTE(u32 frd, u32 frb, u32 rc) = 0; - virtual void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FNMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FCMPO(u32 crfd, u32 fra, u32 frb) = 0; - virtual void FNEG(u32 frd, u32 frb, u32 rc) = 0; - virtual void FMR(u32 frd, u32 frb, u32 rc) = 0; - virtual void FNABS(u32 frd, u32 frb, u32 rc) = 0; - virtual void FABS(u32 frd, u32 frb, u32 rc) = 0; - virtual void FCTID(u32 frd, u32 frb, u32 rc) = 0; - virtual void FCTIDZ(u32 frd, u32 frb, u32 rc) = 0; - virtual void FCFID(u32 frd, u32 frb, u32 rc) = 0; + { 0x20, &D::VMHADDSHS, 5 }, + { 0x21, &D::VMHRADDSHS, 5 }, + { 0x22, &D::VMLADDUHM, 5 }, + { 0x24, &D::VMSUMUBM, 5 }, + { 0x25, &D::VMSUMMBM, 5 }, + { 0x26, &D::VMSUMUHM, 5 }, + { 0x27, &D::VMSUMUHS, 5 }, + { 0x28, &D::VMSUMSHM, 5 }, + { 0x29, &D::VMSUMSHS, 5 }, + { 0x2a, &D::VSEL, 5 }, + { 0x2b, &D::VPERM, 5 }, + { 0x2c, &D::VSLDOI, 5 }, + { 0x2e, &D::VMADDFP, 5 }, + { 0x2f, &D::VNMSUBFP, 5 }, - virtual void UNK(const u32 code, const u32 opcode, const u32 gcode) = 0; + { 0x40, &D::VADDUHM }, + { 0x42, &D::VMAXUH }, + { 0x44, &D::VRLH }, + { 0x46, &D::VCMPEQUH, 1 }, + { 0x48, &D::VMULOUH }, + { 0x4a, &D::VSUBFP }, + { 0x4c, &D::VMRGHH }, + { 0x4e, &D::VPKUWUM }, + { 0x80, &D::VADDUWM }, + { 0x82, &D::VMAXUW }, + { 0x84, &D::VRLW }, + { 0x86, &D::VCMPEQUW, 1 }, + { 0x8c, &D::VMRGHW }, + { 0x8e, &D::VPKUHUS }, + { 0xc6, &D::VCMPEQFP, 1 }, + { 0xce, &D::VPKUWUS }, + + { 0x102, &D::VMAXSB }, + { 0x104, &D::VSLB }, + { 0x108, &D::VMULOSB }, + { 0x10a, &D::VREFP }, + { 0x10c, &D::VMRGLB }, + { 0x10e, &D::VPKSHUS }, + { 0x142, &D::VMAXSH }, + { 0x144, &D::VSLH }, + { 0x148, &D::VMULOSH }, + { 0x14a, &D::VRSQRTEFP }, + { 0x14c, &D::VMRGLH }, + { 0x14e, &D::VPKSWUS }, + { 0x180, &D::VADDCUW }, + { 0x182, &D::VMAXSW }, + { 0x184, &D::VSLW }, + { 0x18a, &D::VEXPTEFP }, + { 0x18c, &D::VMRGLW }, + { 0x18e, &D::VPKSHSS }, + { 0x1c4, &D::VSL }, + { 0x1c6, &D::VCMPGEFP, 1 }, + { 0x1ca, &D::VLOGEFP }, + { 0x1ce, &D::VPKSWSS }, + { 0x200, &D::VADDUBS }, + { 0x202, &D::VMINUB }, + { 0x204, &D::VSRB }, + { 0x206, &D::VCMPGTUB, 1 }, + { 0x208, &D::VMULEUB }, + { 0x20a, &D::VRFIN }, + { 0x20c, &D::VSPLTB }, + { 0x20e, &D::VUPKHSB }, + { 0x240, &D::VADDUHS }, + { 0x242, &D::VMINUH }, + { 0x244, &D::VSRH }, + { 0x246, &D::VCMPGTUH, 1 }, + { 0x248, &D::VMULEUH }, + { 0x24a, &D::VRFIZ }, + { 0x24c, &D::VSPLTH }, + { 0x24e, &D::VUPKHSH }, + { 0x280, &D::VADDUWS }, + { 0x282, &D::VMINUW }, + { 0x284, &D::VSRW }, + { 0x286, &D::VCMPGTUW, 1 }, + { 0x28a, &D::VRFIP }, + { 0x28c, &D::VSPLTW }, + { 0x28e, &D::VUPKLSB }, + { 0x2c4, &D::VSR }, + { 0x2c6, &D::VCMPGTFP, 1 }, + { 0x2ca, &D::VRFIM }, + { 0x2ce, &D::VUPKLSH }, + { 0x300, &D::VADDSBS }, + { 0x302, &D::VMINSB }, + { 0x304, &D::VSRAB }, + { 0x306, &D::VCMPGTSB, 1 }, + { 0x308, &D::VMULESB }, + { 0x30a, &D::VCFUX }, + { 0x30c, &D::VSPLTISB }, + { 0x30e, &D::VPKPX }, + { 0x340, &D::VADDSHS }, + { 0x342, &D::VMINSH }, + { 0x344, &D::VSRAH }, + { 0x346, &D::VCMPGTSH, 1 }, + { 0x348, &D::VMULESH }, + { 0x34a, &D::VCFSX }, + { 0x34c, &D::VSPLTISH }, + { 0x34e, &D::VUPKHPX }, + { 0x380, &D::VADDSWS }, + { 0x382, &D::VMINSW }, + { 0x384, &D::VSRAW }, + { 0x386, &D::VCMPGTSW, 1 }, + { 0x38a, &D::VCTUXS }, + { 0x38c, &D::VSPLTISW }, + { 0x3c6, &D::VCMPBFP, 1 }, + { 0x3ca, &D::VCTSXS }, + { 0x3ce, &D::VUPKLPX }, + { 0x400, &D::VSUBUBM }, + { 0x402, &D::VAVGUB }, + { 0x404, &D::VAND }, + { 0x40a, &D::VMAXFP }, + { 0x40c, &D::VSLO }, + { 0x440, &D::VSUBUHM }, + { 0x442, &D::VAVGUH }, + { 0x444, &D::VANDC }, + { 0x44a, &D::VMINFP }, + { 0x44c, &D::VSRO }, + { 0x480, &D::VSUBUWM }, + { 0x482, &D::VAVGUW }, + { 0x484, &D::VOR }, + { 0x4c4, &D::VXOR }, + { 0x502, &D::VAVGSB }, + { 0x504, &D::VNOR }, + { 0x542, &D::VAVGSH }, + { 0x580, &D::VSUBCUW }, + { 0x582, &D::VAVGSW }, + { 0x600, &D::VSUBUBS }, + { 0x604, &D::MFVSCR }, + { 0x608, &D::VSUM4UBS }, + { 0x640, &D::VSUBUHS }, + { 0x644, &D::MTVSCR }, + { 0x648, &D::VSUM4SHS }, + { 0x680, &D::VSUBUWS }, + { 0x688, &D::VSUM2SWS }, + { 0x700, &D::VSUBSBS }, + { 0x708, &D::VSUM4SBS }, + { 0x740, &D::VSUBSHS }, + { 0x780, &D::VSUBSWS }, + { 0x788, &D::VSUMSWS }, + }); + + // Group 0x13 opcodes (field 21..30) + fill_table(0x13, 10, 1, + { + { 0x000, &D::MCRF }, + { 0x010, &D::BCLR }, + { 0x021, &D::CRNOR }, + { 0x081, &D::CRANDC }, + { 0x096, &D::ISYNC }, + { 0x0c1, &D::CRXOR }, + { 0x0e1, &D::CRNAND }, + { 0x101, &D::CRAND }, + { 0x121, &D::CREQV }, + { 0x1a1, &D::CRORC }, + { 0x1c1, &D::CROR }, + { 0x210, &D::BCCTR }, + }); + + // Group 0x1e opcodes (field 27..30) + fill_table(0x1e, 4, 1, + { + { 0x0, &D::RLDICL }, + { 0x1, &D::RLDICL }, + { 0x2, &D::RLDICR }, + { 0x3, &D::RLDICR }, + { 0x4, &D::RLDIC }, + { 0x5, &D::RLDIC }, + { 0x6, &D::RLDIMI }, + { 0x7, &D::RLDIMI }, + { 0x8, &D::RLDCL }, + { 0x9, &D::RLDCR }, + }); + + // Group 0x1f opcodes (field 21..30) + fill_table(0x1f, 10, 1, + { + { 0x000, &D::CMP }, + { 0x004, &D::TW }, + { 0x006, &D::LVSL }, + { 0x007, &D::LVEBX }, + { 0x008, &D::SUBFC, 1 }, + { 0x009, &D::MULHDU }, + { 0x00a, &D::ADDC, 1 }, + { 0x00b, &D::MULHWU }, + { 0x013, &D::MFOCRF }, + { 0x014, &D::LWARX }, + { 0x015, &D::LDX }, + { 0x017, &D::LWZX }, + { 0x018, &D::SLW }, + { 0x01a, &D::CNTLZW }, + { 0x01b, &D::SLD }, + { 0x01c, &D::AND }, + { 0x020, &D::CMPL }, + { 0x026, &D::LVSR }, + { 0x027, &D::LVEHX }, + { 0x028, &D::SUBF, 1 }, + { 0x035, &D::LDUX }, + { 0x036, &D::DCBST }, + { 0x037, &D::LWZUX }, + { 0x03a, &D::CNTLZD }, + { 0x03c, &D::ANDC }, + { 0x044, &D::TD }, + { 0x047, &D::LVEWX }, + { 0x049, &D::MULHD }, + { 0x04b, &D::MULHW }, + { 0x054, &D::LDARX }, + { 0x056, &D::DCBF }, + { 0x057, &D::LBZX }, + { 0x067, &D::LVX }, + { 0x068, &D::NEG, 1 }, + { 0x077, &D::LBZUX }, + { 0x07c, &D::NOR }, + { 0x087, &D::STVEBX }, + { 0x088, &D::SUBFE, 1 }, + { 0x08a, &D::ADDE, 1 }, + { 0x090, &D::MTOCRF }, + { 0x095, &D::STDX }, + { 0x096, &D::STWCX }, + { 0x097, &D::STWX }, + { 0x0a7, &D::STVEHX }, + { 0x0b5, &D::STDUX }, + { 0x0b7, &D::STWUX }, + { 0x0c7, &D::STVEWX }, + { 0x0c8, &D::SUBFZE, 1 }, + { 0x0ca, &D::ADDZE, 1 }, + { 0x0d6, &D::STDCX }, + { 0x0d7, &D::STBX }, + { 0x0e7, &D::STVX }, + { 0x0e8, &D::SUBFME, 1 }, + { 0x0e9, &D::MULLD, 1 }, + { 0x0ea, &D::ADDME, 1 }, + { 0x0eb, &D::MULLW, 1 }, + { 0x0f6, &D::DCBTST }, + { 0x0f7, &D::STBUX }, + { 0x10a, &D::ADD, 1 }, + { 0x116, &D::DCBT }, + { 0x117, &D::LHZX }, + { 0x11c, &D::EQV }, + { 0x136, &D::ECIWX }, + { 0x137, &D::LHZUX }, + { 0x13c, &D::XOR }, + { 0x153, &D::MFSPR }, + { 0x155, &D::LWAX }, + { 0x156, &D::DST }, + { 0x157, &D::LHAX }, + { 0x167, &D::LVXL }, + { 0x173, &D::MFTB }, + { 0x175, &D::LWAUX }, + { 0x176, &D::DSTST }, + { 0x177, &D::LHAUX }, + { 0x197, &D::STHX }, + { 0x19c, &D::ORC }, + { 0x1b6, &D::ECOWX }, + { 0x1b7, &D::STHUX }, + { 0x1bc, &D::OR }, + { 0x1c9, &D::DIVDU, 1 }, + { 0x1cb, &D::DIVWU, 1 }, + { 0x1d3, &D::MTSPR }, + { 0x1d6, &D::DCBI }, + { 0x1dc, &D::NAND }, + { 0x1e7, &D::STVXL }, + { 0x1e9, &D::DIVD, 1 }, + { 0x1eb, &D::DIVW, 1 }, + { 0x207, &D::LVLX }, + { 0x214, &D::LDBRX }, + { 0x215, &D::LSWX }, + { 0x216, &D::LWBRX }, + { 0x217, &D::LFSX }, + { 0x218, &D::SRW }, + { 0x21b, &D::SRD }, + { 0x227, &D::LVRX }, + { 0x237, &D::LFSUX }, + { 0x255, &D::LSWI }, + { 0x256, &D::SYNC }, + { 0x257, &D::LFDX }, + { 0x277, &D::LFDUX }, + { 0x287, &D::STVLX }, + { 0x294, &D::STDBRX }, + { 0x295, &D::STSWX }, + { 0x296, &D::STWBRX }, + { 0x297, &D::STFSX }, + { 0x2a7, &D::STVRX }, + { 0x2b7, &D::STFSUX }, + { 0x2d5, &D::STSWI }, + { 0x2d7, &D::STFDX }, + { 0x2f7, &D::STFDUX }, + { 0x307, &D::LVLXL }, + { 0x316, &D::LHBRX }, + { 0x318, &D::SRAW }, + { 0x31a, &D::SRAD }, + { 0x327, &D::LVRXL }, + { 0x336, &D::DSS }, + { 0x338, &D::SRAWI }, + { 0x33a, &D::SRADI }, + { 0x33b, &D::SRADI }, + { 0x356, &D::EIEIO }, + { 0x387, &D::STVLXL }, + { 0x396, &D::STHBRX }, + { 0x39a, &D::EXTSH }, + { 0x3a7, &D::STVRXL }, + { 0x3ba, &D::EXTSB }, + { 0x3d7, &D::STFIWX }, + { 0x3da, &D::EXTSW }, + { 0x3d6, &D::ICBI }, + { 0x3f6, &D::DCBZ }, + }); + + // Group 0x3a opcodes (field 30..31) + fill_table(0x3a, 2, 0, + { + { 0x0, &D::LD }, + { 0x1, &D::LDU }, + { 0x2, &D::LWA }, + }); + + // Group 0x3b opcodes (field 21..30) + fill_table(0x3b, 10, 1, + { + { 0x12, &D::FDIVS, 5 }, + { 0x14, &D::FSUBS, 5 }, + { 0x15, &D::FADDS, 5 }, + { 0x16, &D::FSQRTS, 5 }, + { 0x18, &D::FRES, 5 }, + { 0x19, &D::FMULS, 5 }, + { 0x1c, &D::FMSUBS, 5 }, + { 0x1d, &D::FMADDS, 5 }, + { 0x1e, &D::FNMSUBS, 5 }, + { 0x1f, &D::FNMADDS, 5 }, + }); + + // Group 0x3e opcodes (field 30..31) + fill_table(0x3e, 2, 0, + { + { 0x0, &D::STD }, + { 0x1, &D::STDU }, + }); + + // Group 0x3f opcodes (field 21..30) + fill_table(0x3f, 10, 1, + { + { 0x026, &D::MTFSB1 }, + { 0x040, &D::MCRFS }, + { 0x046, &D::MTFSB0 }, + { 0x086, &D::MTFSFI }, + { 0x247, &D::MFFS }, + { 0x2c7, &D::MTFSF }, + + { 0x000, &D::FCMPU }, + { 0x00c, &D::FRSP }, + { 0x00e, &D::FCTIW }, + { 0x00f, &D::FCTIWZ }, + + { 0x012, &D::FDIV, 5 }, + { 0x014, &D::FSUB, 5 }, + { 0x015, &D::FADD, 5 }, + { 0x016, &D::FSQRT, 5 }, + { 0x017, &D::FSEL, 5 }, + { 0x019, &D::FMUL, 5 }, + { 0x01a, &D::FRSQRTE, 5 }, + { 0x01c, &D::FMSUB, 5 }, + { 0x01d, &D::FMADD, 5 }, + { 0x01e, &D::FNMSUB, 5 }, + { 0x01f, &D::FNMADD, 5 }, + + { 0x020, &D::FCMPO }, + { 0x028, &D::FNEG }, + { 0x048, &D::FMR }, + { 0x088, &D::FNABS }, + { 0x108, &D::FABS }, + { 0x32e, &D::FCTID }, + { 0x32f, &D::FCTIDZ }, + { 0x34e, &D::FCFID }, + }); + } + + const std::array& get_table() const + { + return m_table; + } + + T decode(u32 inst) const + { + return m_table[ppu_decode(inst)]; + } }; + +namespace ppu_instructions +{ + namespace fields + { + enum + { + r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, + r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, + r22, r23, r24, r25, r26, r27, r28, r29, r30, r31, + }; + } + + using namespace fields; + + inline u32 ADDI(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x0eu << 26 }; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; } + inline u32 ADDIS(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x0fu << 26 }; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; } + inline u32 ORI(u32 rt, u32 ra, u32 ui) { ppu_opcode_t op{ 0x18u << 26 }; op.rd = rt; op.ra = ra; op.uimm16 = ui; return op.opcode; } + inline u32 ORIS(u32 rt, u32 ra, u32 ui) { ppu_opcode_t op{ 0x19u << 26 }; op.rd = rt; op.ra = ra; op.uimm16 = ui; return op.opcode; } + inline u32 OR(u32 ra, u32 rs, u32 rb, bool rc = false) { ppu_opcode_t op{ 0x1fu << 26 | 0x1bcu << 1 }; op.rs = rs; op.ra = ra; op.rb = rb; op.rc = rc; return op.opcode; } + inline u32 SC(u32 lev) { ppu_opcode_t op{ 0x11u << 26 }; op.lev = lev; return op.opcode; } + inline u32 B(s32 li, bool aa = false, bool lk = false) { ppu_opcode_t op{ 0x12u << 26 }; op.ll = li; op.aa = aa; op.lk = lk; return op.opcode; } + inline u32 BC(u32 bo, u32 bi, s32 bd, bool aa = false, bool lk = false) { ppu_opcode_t op{ 0x10u << 26 }; op.bo = bo; op.bi = bi; op.ds = bd / 4; op.aa = aa; op.lk = lk; return op.opcode; } + inline u32 BCLR(u32 bo, u32 bi, u32 bh, bool lk = false) { ppu_opcode_t op{ 0x13u << 26 | 0x10u << 1 }; op.bo = bo; op.bi = bi; op.bh = bh; op.lk = lk; return op.opcode; } + inline u32 BCCTR(u32 bo, u32 bi, u32 bh, bool lk = false) { ppu_opcode_t op{ 0x13u << 26 | 0x210u << 1 }; op.bo = bo; op.bi = bi; op.bh = bh; op.lk = lk; return op.opcode; } + inline u32 MFSPR(u32 rt, u32 spr) { ppu_opcode_t op{ 0x1fu << 26 | 0x153u << 1 }; op.rd = rt; op.spr = spr; return op.opcode; } + inline u32 MTSPR(u32 spr, u32 rs) { ppu_opcode_t op{ 0x1fu << 26 | 0x1d3u << 1 }; op.rs = rs; op.spr = spr; return op.opcode; } + inline u32 LWZ(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x20u << 26 }; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; } + inline u32 STD(u32 rs, u32 ra, s32 si) { ppu_opcode_t op{ 0x3eu << 26 }; op.rs = rs; op.ra = ra; op.ds = si / 4; return op.opcode; } + inline u32 STDU(u32 rs, u32 ra, s32 si) { ppu_opcode_t op{ 0x3eu << 26 | 1 }; op.rs = rs; op.ra = ra; op.ds = si / 4; return op.opcode; } + inline u32 LD(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x3au << 26 }; op.rd = rt; op.ra = ra; op.ds = si / 4; return op.opcode; } + inline u32 LDU(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x3au << 26 | 1 }; op.rd = rt; op.ra = ra; op.ds = si / 4; return op.opcode; } + //inline u32 CMPI(u32 bf, u32 l, u32 ra, u32 ui) { ppu_opcode_t op{ 0xbu << 26 }; op.crfd = bf; op.l10 = l; op.ra = ra; op.uimm16 = ui; return op.opcode; } + //inline u32 CMPLI(u32 bf, u32 l, u32 ra, u32 ui) { ppu_opcode_t op{ 0xau << 26 }; op.crfd = bf; op.l10 = l; op.ra = ra; op.uimm16 = ui; return op.opcode; } + inline u32 RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, bool rc = false) { ppu_opcode_t op{ 30 << 26 }; op.ra = ra; op.rs = rs; op.sh64 = sh; op.mbe64 = mb; op.rc = rc; return op.opcode; } + + namespace implicts + { + inline u32 HACK(u32 index) { return 0x01 << 26 | index; } + inline u32 NOP() { return ORI(r0, r0, 0); } + inline u32 MR(u32 rt, u32 ra) { return OR(rt, ra, ra, false); } + inline u32 LI(u32 rt, u32 imm) { return ADDI(rt, r0, imm); } + inline u32 LIS(u32 rt, u32 imm) { return ADDIS(rt, r0, imm); } + + inline u32 BLR() { return BCLR(0x10 | 0x04, 0, 0); } + inline u32 BCTR() { return BCCTR(0x10 | 0x04, 0, 0); } + inline u32 BCTRL() { return BCCTR(0x10 | 0x04, 0, 0, true); } + inline u32 MFCTR(u32 reg) { return MFSPR(reg, 9 << 5); } + inline u32 MTCTR(u32 reg) { return MTSPR(9 << 5, reg); } + inline u32 MFLR(u32 reg) { return MFSPR(reg, 8 << 5); } + inline u32 MTLR(u32 reg) { return MTSPR(8 << 5, reg); } + + //inline u32 BNE(u32 cr, s32 imm) { return BC(4, 2 | cr << 2, imm); } + //inline u32 BEQ(u32 cr, s32 imm) { return BC(12, 2 | cr << 2, imm); } + //inline u32 BGT(u32 cr, s32 imm) { return BC(12, 1 | cr << 2, imm); } + //inline u32 BNE(s32 imm) { return BNE(cr0, imm); } + //inline u32 BEQ(s32 imm) { return BEQ(cr0, imm); } + //inline u32 BGT(s32 imm) { return BGT(cr0, imm); } + + //inline u32 CMPDI(u32 cr, u32 reg, u32 imm) { return CMPI(cr, 1, reg, imm); } + //inline u32 CMPDI(u32 reg, u32 imm) { return CMPDI(cr0, reg, imm); } + //inline u32 CMPWI(u32 cr, u32 reg, u32 imm) { return CMPI(cr, 0, reg, imm); } + //inline u32 CMPWI(u32 reg, u32 imm) { return CMPWI(cr0, reg, imm); } + //inline u32 CMPLDI(u32 cr, u32 reg, u32 imm) { return CMPLI(cr, 1, reg, imm); } + //inline u32 CMPLDI(u32 reg, u32 imm) { return CMPLDI(cr0, reg, imm); } + //inline u32 CMPLWI(u32 cr, u32 reg, u32 imm) { return CMPLI(cr, 0, reg, imm); } + //inline u32 CMPLWI(u32 reg, u32 imm) { return CMPLWI(cr0, reg, imm); } + + inline u32 EXTRDI(u32 x, u32 y, u32 n, u32 b) { return RLDICL(x, y, b + n, 64 - b, false); } + inline u32 SRDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 64 - n, n, false); } + inline u32 CLRLDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 0, n, false); } + } + + using namespace implicts; +} diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 58be498031..ccce38e9e6 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -1,108 +1,62 @@ #include "stdafx.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" #include "Emu/IdManager.h" -#include "Emu/Cell/PPUThread.h" -#include "Emu/Cell/PPUDecoder.h" -#include "Emu/Cell/PPUInterpreter.h" -#include "Emu/Cell/PPUInterpreter2.h" -#include "Emu/Cell/PPULLVMRecompiler.h" -//#include "Emu/Cell/PPURecompiler.h" -#include "Utilities/VirtualMemory.h" +#include "PPUThread.h" +#include "PPUInterpreter.h" +#include "PPUModule.h" -#ifdef _WIN32 -#include -#else -#include -#include -#endif - -u64 rotate_mask[64][64]; - -extern u32 ppu_get_tls(u32 thread); -extern void ppu_free_tls(u32 thread); - -//thread_local const std::weak_ptr g_tls_ppu_decoder_cache = fxm::get(); -thread_local const ppu_decoder_cache_t* g_tls_ppu_decoder_cache = nullptr; // temporarily, because thread_local is not fully available - -ppu_decoder_cache_t::ppu_decoder_cache_t() - : pointer(static_cast(memory_helper::reserve_memory(0x200000000))) +enum class ppu_decoder_type { -} + precise, + fast, + llvm, +}; -ppu_decoder_cache_t::~ppu_decoder_cache_t() +cfg::map_entry g_cfg_ppu_decoder(cfg::root.core, "PPU Decoder", 1, { - memory_helper::free_reserved_memory(pointer, 0x200000000); -} + { "Interpreter (precise)", ppu_decoder_type::precise }, + { "Interpreter (fast)", ppu_decoder_type::fast }, + { "Recompiler (LLVM)", ppu_decoder_type::llvm }, +}); -void ppu_decoder_cache_t::initialize(u32 addr, u32 size) -{ - memory_helper::commit_page_memory(pointer + addr / 4, size * 2); - - PPUInterpreter2* inter; - PPUDecoder dec(inter = new PPUInterpreter2); - - for (u32 pos = addr; pos < addr + size; pos += 4) - { - inter->func = ppu_interpreter::NULL_OP; - - // decode PPU opcode - dec.Decode(vm::ps3::read32(pos)); - - // store function address - pointer[pos / 4] = inter->func; - } -} - -PPUThread::PPUThread(const std::string& name) - : CPUThread(CPU_THREAD_PPU, name) -{ - InitRotateMask(); -} - -PPUThread::~PPUThread() -{ - close_stack(); - ppu_free_tls(m_id); -} +const ppu_decoder s_ppu_interpreter_precise; +const ppu_decoder s_ppu_interpreter_fast; std::string PPUThread::get_name() const { - return fmt::format("PPU Thread[0x%x] (%s)[0x%08x]", m_id, CPUThread::get_name(), PC); + return fmt::format("PPU[0x%x] Thread (%s)", id, name); } -void PPUThread::dump_info() const +std::string PPUThread::dump() const { - extern std::string get_ps3_function_name(u64 fid); + std::string ret = "Registers:\n=========\n"; - if (~hle_code < 1024) - { - LOG_SUCCESS(HLE, "Last syscall: %lld (%s)", ~hle_code, get_ps3_function_name(hle_code)); - } - else if (hle_code) - { - LOG_SUCCESS(HLE, "Last function: %s (0x%llx)", get_ps3_function_name(hle_code), hle_code); - } + for (uint i = 0; i<32; ++i) ret += fmt::format("GPR[%d] = 0x%llx\n", i, GPR[i]); + for (uint i = 0; i<32; ++i) ret += fmt::format("FPR[%d] = %.6G\n", i, FPR[i]); + for (uint i = 0; i<32; ++i) ret += fmt::format("VR[%d] = 0x%s [%s]\n", i, VR[i].to_hex().c_str(), VR[i].to_xyzw().c_str()); + ret += fmt::format("CR = 0x%08x\n", GetCR()); + ret += fmt::format("LR = 0x%llx\n", LR); + ret += fmt::format("CTR = 0x%llx\n", CTR); + ret += fmt::format("XER = [CA=%u | OV=%u | SO=%u | CNT=%u]\n", u32{ CA }, u32{ OV }, u32{ SO }, u32{ XCNT }); + //ret += fmt::format("FPSCR = 0x%x " + // "[RN=%d | NI=%d | XE=%d | ZE=%d | UE=%d | OE=%d | VE=%d | " + // "VXCVI=%d | VXSQRT=%d | VXSOFT=%d | FPRF=%d | " + // "FI=%d | FR=%d | VXVC=%d | VXIMZ=%d | " + // "VXZDZ=%d | VXIDI=%d | VXISI=%d | VXSNAN=%d | " + // "XX=%d | ZX=%d | UX=%d | OX=%d | VX=%d | FEX=%d | FX=%d]\n", + // FPSCR.FPSCR, + // u32{ FPSCR.RN }, + // u32{ FPSCR.NI }, u32{ FPSCR.XE }, u32{ FPSCR.ZE }, u32{ FPSCR.UE }, u32{ FPSCR.OE }, u32{ FPSCR.VE }, + // u32{ FPSCR.VXCVI }, u32{ FPSCR.VXSQRT }, u32{ FPSCR.VXSOFT }, u32{ FPSCR.FPRF }, + // u32{ FPSCR.FI }, u32{ FPSCR.FR }, u32{ FPSCR.VXVC }, u32{ FPSCR.VXIMZ }, + // u32{ FPSCR.VXZDZ }, u32{ FPSCR.VXIDI }, u32{ FPSCR.VXISI }, u32{ FPSCR.VXSNAN }, + // u32{ FPSCR.XX }, u32{ FPSCR.ZX }, u32{ FPSCR.UX }, u32{ FPSCR.OX }, u32{ FPSCR.VX }, u32{ FPSCR.FEX }, u32{ FPSCR.FX }); - CPUThread::dump_info(); + return ret; } -void PPUThread::init_regs() -{ - GPR[1] = align(stack_addr + stack_size, 0x200) - 0x200; - GPR[13] = ppu_get_tls(m_id) + 0x7000; // 0x7000 is subtracted from r13 to access first TLS element - - LR = 0; - CTR = PC; - CR.CR = 0x22000082; - VSCR.NJ = 1; - TB = 0; - - //m_state |= CPU_STATE_INTR; -} - -void PPUThread::init_stack() +void PPUThread::cpu_init() { if (!stack_addr) { @@ -118,14 +72,70 @@ void PPUThread::init_stack() throw EXCEPTION("Out of stack memory"); } } + + GPR[1] = align(stack_addr + stack_size, 0x200) - 0x200; } -void PPUThread::close_stack() +void PPUThread::cpu_task() { - if (stack_addr) + //SetHostRoundingMode(FPSCR_RN_NEAR); + + if (custom_task) { - vm::dealloc_verbose_nothrow(stack_addr, vm::stack); - stack_addr = 0; + if (check_status()) return; + + return custom_task(*this); + } + + _log::g_tls_make_prefix = [](const auto&, auto, const auto&) + { + const auto cpu = static_cast(get_current_cpu_thread()); + + return fmt::format("%s [0x%08x]", cpu->get_name(), cpu->PC); + }; + + const auto base = vm::_ptr(0); + + // Select opcode table + const auto& table = *( + g_cfg_ppu_decoder.get() == ppu_decoder_type::precise ? &s_ppu_interpreter_precise.get_table() : + g_cfg_ppu_decoder.get() == ppu_decoder_type::fast ? &s_ppu_interpreter_fast.get_table() : + throw std::logic_error("Invalid PPU decoder")); + + u32 _pc{}; + u32 op0, op1, op2; + ppu_inter_func_t func0, func1, func2; + + while (true) + { + if (_pc == PC && !state.load()) + { + func0(*this, { op0 }); + + if ((_pc += 4) == (PC += 4) && !state.load()) + { + func1(*this, { op1 }); + + if ((_pc += 4) == (PC += 4)) + { + op0 = op2; + func0 = func2; + const auto ops = reinterpret_cast*>(base + _pc); + func1 = table[ppu_decode(op1 = ops[1])]; + func2 = table[ppu_decode(op2 = ops[2])]; + continue; + } + } + } + + // Reinitialize + _pc = PC; + const auto ops = reinterpret_cast*>(base + _pc); + func0 = table[ppu_decode(op0 = ops[0])]; + func1 = table[ppu_decode(op1 = ops[1])]; + func2 = table[ppu_decode(op2 = ops[2])]; + + if (check_status()) return; } } @@ -134,99 +144,28 @@ bool PPUThread::handle_interrupt() return false; } -void PPUThread::do_run() +PPUThread::~PPUThread() { - m_dec.reset(); - - switch (auto mode = rpcs3::state.config.core.ppu_decoder.value()) + if (stack_addr) { - case ppu_decoder_type::interpreter: // original interpreter - { - m_dec.reset(new PPUDecoder(new PPUInterpreter(*this))); - break; - } - - case ppu_decoder_type::interpreter2: // alternative interpreter - { - break; - } - - case ppu_decoder_type::recompiler_llvm: - { -#ifdef PPU_LLVM_RECOMPILER - m_dec.reset(new ppu_recompiler_llvm::CPUHybridDecoderRecompiler(*this)); -#else - LOG_ERROR(PPU, "This image does not include PPU JIT (LLVM)"); - Emu.Pause(); -#endif - break; - } - - //case 3: m_dec.reset(new PPURecompiler(*this)); break; - - default: - { - LOG_ERROR(PPU, "Invalid CPU decoder mode: %d", mode); - Emu.Pause(); - } + vm::dealloc_verbose_nothrow(stack_addr, vm::stack); } } -bool FPRdouble::IsINF(PPCdouble d) +be_t* PPUThread::get_stack_arg(s32 i, u64 align) { - return ((u64&)d & 0x7FFFFFFFFFFFFFFFULL) == 0x7FF0000000000000ULL; -} - -bool FPRdouble::IsNaN(PPCdouble d) -{ - return std::isnan((double)d) ? 1 : 0; -} - -bool FPRdouble::IsQNaN(PPCdouble d) -{ - return - ((u64&)d & 0x7FF0000000000000ULL) == 0x7FF0000000000000ULL && - ((u64&)d & 0x0007FFFFFFFFFFFULL) == 0ULL && - ((u64&)d & 0x000800000000000ULL) != 0ULL; -} - -bool FPRdouble::IsSNaN(PPCdouble d) -{ - return - ((u64&)d & 0x7FF0000000000000ULL) == 0x7FF0000000000000ULL && - ((u64&)d & 0x000FFFFFFFFFFFFFULL) != 0ULL && - ((u64&)d & 0x0008000000000000ULL) == 0ULL; -} - -int FPRdouble::Cmp(PPCdouble a, PPCdouble b) -{ - if(a < b) return CR_LT; - if(a > b) return CR_GT; - if(a == b) return CR_EQ; - - return CR_SO; -} - -u64 PPUThread::get_stack_arg(s32 i) -{ - return vm::ps3::read64(VM_CAST(GPR[1] + 0x70 + 0x8 * (i - 9))); + if (align != 1 && align != 2 && align != 4 && align != 8 && align != 16) throw fmt::exception("Unsupported alignment: 0x%llx" HERE, align); + return vm::_ptr(vm::cast((GPR[1] + 0x30 + 0x8 * (i - 1)) & (0 - align), HERE)); } void PPUThread::fast_call(u32 addr, u32 rtoc) { - if (!is_current()) - { - throw EXCEPTION("Called from the wrong thread"); - } - auto old_PC = PC; auto old_stack = GPR[1]; auto old_rtoc = GPR[2]; auto old_LR = LR; auto old_task = std::move(custom_task); - assert(!old_task || !custom_task); - PC = addr; GPR[2] = rtoc; LR = Emu.GetCPUThreadStop(); @@ -236,11 +175,13 @@ void PPUThread::fast_call(u32 addr, u32 rtoc) { cpu_task(); } - catch (CPUThreadReturn) + catch (cpu_state _s) { + state += _s; + if (_s != cpu_state::ret) throw; } - m_state &= ~CPU_STATE_RETURN; + state -= cpu_state::ret; PC = old_PC; @@ -253,135 +194,3 @@ void PPUThread::fast_call(u32 addr, u32 rtoc) LR = old_LR; custom_task = std::move(old_task); } - -void PPUThread::fast_stop() -{ - m_state |= CPU_STATE_RETURN; -} - -void PPUThread::cpu_task() -{ - SetHostRoundingMode(FPSCR_RN_NEAR); - - if (custom_task) - { - if (check_status()) return; - - return custom_task(*this); - } - - if (!g_tls_ppu_decoder_cache) - { - const auto decoder_cache = fxm::get(); - - if (!decoder_cache) - { - throw EXCEPTION("PPU Decoder Cache not initialized"); - } - - g_tls_ppu_decoder_cache = decoder_cache.get(); // unsafe (TODO) - } - - const auto exec_map = g_tls_ppu_decoder_cache->pointer; - - if (m_dec) - { - while (true) - { - if (m_state && check_status()) break; - - // decode instruction using specified decoder - m_dec->DecodeMemory(PC); - - // next instruction - PC += 4; - } - } - else - { - while (true) - { - // get cached interpreter function address - const auto func = exec_map[PC / 4]; - - // check status - if (!m_state) - { - // call interpreter function - func(*this, { vm::ps3::read32(PC) }); - - // next instruction - PC += 4; - - continue; - } - - if (check_status()) - { - break; - } - } - } -} - -ppu_thread::ppu_thread(u32 entry, const std::string& name, u32 stack_size, s32 prio) -{ - auto ppu = idm::make_ptr(name); - - if (entry) - { - ppu->PC = vm::ps3::read32(entry); - ppu->GPR[2] = vm::ps3::read32(entry + 4); // rtoc - } - - ppu->stack_size = stack_size ? stack_size : Emu.GetPrimaryStackSize(); - ppu->prio = prio ? prio : Emu.GetPrimaryPrio(); - - thread = std::move(ppu); - - argc = 0; -} - -cpu_thread& ppu_thread::args(std::initializer_list values) -{ - if (!values.size()) - return *this; - - assert(argc == 0); - - envp.set(vm::alloc(align(SIZE_32(*envp), stack_align), vm::main)); - *envp = 0; - argv.set(vm::alloc(SIZE_32(*argv) * (u32)values.size(), vm::main)); - - for (auto &arg : values) - { - const u32 arg_size = align(u32(arg.size() + 1), stack_align); - const u32 arg_addr = vm::alloc(arg_size, vm::main); - - std::memcpy(vm::base(arg_addr), arg.c_str(), arg.size() + 1); - - argv[argc++] = arg_addr; - } - - return *this; -} - -cpu_thread& ppu_thread::run() -{ - thread->run(); - - gpr(3, argc); - gpr(4, argv.addr()); - gpr(5, envp.addr()); - - return *this; -} - -ppu_thread& ppu_thread::gpr(uint index, u64 value) -{ - assert(index < 32); - - static_cast(*thread).GPR[index] = value; - - return *this; -} diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 897864d611..4c007110e8 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -4,246 +4,32 @@ #include "Emu/CPU/CPUThread.h" #include "Emu/Memory/vm.h" -enum +class PPUThread final : public cpu_thread { - XER_SO = 0x80000000, - XER_OV = 0x40000000, - XER_CA = 0x20000000, -}; +public: + virtual std::string get_name() const override; + virtual std::string dump() const override; + virtual void cpu_init() override; + virtual void cpu_task() override; + virtual bool handle_interrupt() override; -enum -{ - CR_LT = 0x8, - CR_GT = 0x4, - CR_EQ = 0x2, - CR_SO = 0x1, -}; - -enum FPSCR_EXP -{ - FPSCR_FX = 0x80000000, - FPSCR_FEX = 0x40000000, - FPSCR_VX = 0x20000000, - FPSCR_OX = 0x10000000, - - FPSCR_UX = 0x08000000, - FPSCR_ZX = 0x04000000, - FPSCR_XX = 0x02000000, - FPSCR_VXSNAN = 0x01000000, - - FPSCR_VXISI = 0x00800000, - FPSCR_VXIDI = 0x00400000, - FPSCR_VXZDZ = 0x00200000, - FPSCR_VXIMZ = 0x00100000, - - FPSCR_VXVC = 0x00080000, - FPSCR_FR = 0x00040000, - FPSCR_FI = 0x00020000, - - FPSCR_VXSOFT = 0x00000400, - FPSCR_VXSQRT = 0x00000200, - FPSCR_VXCVI = 0x00000100, - - FPSCR_VX_ALL = FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI | FPSCR_VXZDZ | FPSCR_VXIMZ | FPSCR_VXVC | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI, -}; - -static const u64 DOUBLE_SIGN = 0x8000000000000000ULL; -static const u64 DOUBLE_EXP = 0x7FF0000000000000ULL; -static const u64 DOUBLE_FRAC = 0x000FFFFFFFFFFFFFULL; -static const u64 DOUBLE_ZERO = 0x0000000000000000ULL; - -union FPSCRhdr -{ - struct + PPUThread(const std::string& name) + : cpu_thread(cpu_type::ppu, name) { - u32 RN :2; //Floating-point rounding control - u32 NI :1; //Floating-point non-IEEE mode - u32 XE :1; //Floating-point inexact exception enable - u32 ZE :1; //IEEE floating-point zero divide exception enable - u32 UE :1; //IEEE floating-point underflow exception enable - u32 OE :1; //IEEE floating-point overflow exception enable - u32 VE :1; //Floating-point invalid operation exception enable - u32 VXCVI :1; //Floating-point invalid operation exception for invalid integer convert - u32 VXSQRT :1; //Floating-point invalid operation exception for invalid square root - u32 VXSOFT :1; //Floating-point invalid operation exception for software request - u32 :1; //Reserved - u32 FPRF :5; //Floating-point result flags - u32 FI :1; //Floating-point fraction inexact - u32 FR :1; //Floating-point fraction rounded - u32 VXVC :1; //Floating-point invalid operation exception for invalid compare - u32 VXIMZ :1; //Floating-point invalid operation exception for * * 0 - u32 VXZDZ :1; //Floating-point invalid operation exception for 0 / 0 - u32 VXIDI :1; //Floating-point invalid operation exception for * + * - u32 VXISI :1; //Floating-point invalid operation exception for * - * - u32 VXSNAN :1; //Floating-point invalid operation exception for SNaN - u32 XX :1; //Floating-point inexact exception - u32 ZX :1; //Floating-point zero divide exception - u32 UX :1; //Floating-point underflow exception - u32 OX :1; //Floating-point overflow exception - u32 VX :1; //Floating-point invalid operation exception summary - u32 FEX :1; //Floating-point enabled exception summary - u32 FX :1; //Floating-point exception summary - }; + } - u32 FPSCR; -}; + virtual ~PPUThread() override; -union MSRhdr -{ - struct - { - //Little-endian mode enable - //0 The processor runs in big-endian mode. - //1 The processor runs in little-endian mode. - u64 LE : 1; + u64 GPR[32]{}; // General-Purpose Registers + f64 FPR[32]{}; // Floating Point Registers + v128 VR[32]{}; // Vector Registers + alignas(16) bool CR[32]{}; // Condition Registers + bool SO{}; // XER: Summary overflow + bool OV{}; // XER: Overflow + bool CA{}; // XER: Carry + u8 XCNT{}; // XER: 0..6 - //Recoverable exception (for system reset and machine check exceptions). - //0 Exception is not recoverable. - //1 Exception is recoverable. - u64 RI : 1; - - //Reserved - u64 : 2; - - //Data address translation - //0 Data address translation is disabled. - //1 Data address translation is enabled. - u64 DR : 1; - - //Instruction address translation - //0 Instruction address translation is disabled. - //1 Instruction address translation is enabled. - u64 IR : 1; - - //Exception prefix. The setting of this bit specifies whether an exception vector offset - //is prepended with Fs or 0s. In the following description, nnnnn is the offset of the - //exception. - //0 Exceptions are vectored to the physical address 0x0000_0000_000n_nnnn in 64-bit implementations. - //1 Exceptions are vectored to the physical address 0xFFFF_FFFF_FFFn_nnnn in 64-bit implementations. - u64 IP : 1; - - //Reserved - u64 : 1; - - //Floating-point exception mode 1 - u64 FE1 : 1; - - //Branch trace enable (Optional) - //0 The processor executes branch instructions normally. - //1 The processor generates a branch trace exception after completing the - //execution of a branch instruction, regardless of whether or not the branch was - //taken. - //Note: If the function is not implemented, this bit is treated as reserved. - u64 BE : 1; - - //Single-step trace enable (Optional) - //0 The processor executes instructions normally. - //1 The processor generates a single-step trace exception upon the successful - //execution of the next instruction. - //Note: If the function is not implemented, this bit is treated as reserved. - u64 SE : 1; - - //Floating-point exception mode 0 - u64 FE0 : 1; - - //Machine check enable - //0 Machine check exceptions are disabled. - //1 Machine check exceptions are enabled. - u64 ME : 1; - - //Floating-point available - //0 The processor prevents dispatch of floating-point instructions, including - //floating-point loads, stores, and moves. - //1 The processor can execute floating-point instructions. - u64 FP : 1; - - //Privilege level - //0 The processor can execute both user- and supervisor-level instructions. - //1 The processor can only execute user-level instructions. - u64 PR : 1; - - //External interrupt enable - //0 While the bit is cleared the processor delays recognition of external interrupts - //and decrementer exception conditions. - //1 The processor is enabled to take an external interrupt or the decrementer - //exception. - u64 EE : 1; - - //Exception little-endian mode. When an exception occurs, this bit is copied into - //MSR[LE] to select the endian mode for the context established by the exception - u64 ILE : 1; - - //Reserved - u64 : 1; - - //Power management enable - //0 Power management disabled (normal operation mode). - //1 Power management enabled (reduced power mode). - //Note: Power management functions are implementation-dependent. If the function - //is not implemented, this bit is treated as reserved. - u64 POW : 1; - - //Reserved - u64 : 44; - - //Sixty-four bit mode - //0 The 64-bit processor runs in 32-bit mode. - //1 The 64-bit processor runs in 64-bit mode. Note that this is the default setting. - u64 SF : 1; - }; - - u64 MSR; -}; - -union PVRhdr -{ - struct - { - u16 revision; - u16 version; - }; - - u32 PVR; -}; - -union CRhdr -{ - u32 CR; - - struct - { - u8 cr7 : 4; - u8 cr6 : 4; - u8 cr5 : 4; - u8 cr4 : 4; - u8 cr3 : 4; - u8 cr2 : 4; - u8 cr1 : 4; - u8 cr0 : 4; - }; -}; - -union XERhdr -{ - u64 XER; - - struct - { - u32 L : 29; - u32 CA : 1; - u32 OV : 1; - u32 SO : 1; - u32 : 32; - }; -}; - -union VSCRhdr -{ - u32 VSCR; - - struct - { - /* + /* Saturation. A sticky status bit indicating that some field in a saturating instruction saturated since the last time SAT was cleared. In other words when SAT = '1' it remains set to '1' until it is cleared to '0' by an mtvscr instruction. @@ -261,11 +47,10 @@ union VSCRhdr Vector Pack with Saturation (vpkuhus, vpkuwus, vpkshus, vpkswus, vpkshss, vpkswss) Vector Convert to Fixed-Point with Saturation (vctuxs, vctsxs) 0 Indicates no saturation occurred; mtvscr can explicitly clear this bit. - */ - u32 SAT : 1; - u32 X : 15; + */ + bool SAT{}; - /* + /* Non-Java. A mode control bit that determines whether vector floating-point operations will be performed in a Java-IEEE-C9X-compliant mode or a possibly faster non-Java/non-IEEE mode. 0 The Java-IEEE-C9X-compliant mode is selected. Denormalized values are handled as specified @@ -274,759 +59,162 @@ union VSCRhdr contains a denormalized value, the value '0' is used instead. If an instruction causes an underflow exception, the corresponding element in the target VR is cleared to '0'. In both cases, the '0' has the same sign as the denormalized or underflowing value. - */ - u32 NJ : 1; - u32 Y : 15; - }; -}; + */ + bool NJ{ true }; -enum FPRType -{ - //FPR_NORM, - //FPR_ZERO, - //FPR_SNAN, - //FPR_QNAN, - //FPR_INF, - FPR_PZ = 0x2, - FPR_PN = 0x4, - FPR_PINF = 0x5, - FPR_NN = 0x8, - FPR_NINF = 0x9, - FPR_QNAN = 0x11, - FPR_NZ = 0x12, - FPR_PD = 0x14, - FPR_ND = 0x18, -}; + bool FL{}; // FPSCR.FPCC.FL + bool FG{}; // FPSCR.FPCC.FG + bool FE{}; // FPSCR.FPCC.FE + bool FU{}; // FPSCR.FPCC.FU -static const u64 FPR_NAN_I = 0x7FF8000000000000ULL; -static const double& FPR_NAN = (double&)FPR_NAN_I; + u64 LR{}; // Link Register + u64 CTR{}; // Counter Register + u32 VRSAVE{}; + u32 PC{}; -struct PPCdouble -{ - union - { - double _double; - u64 _u64; - - struct - { - u64 frac : 52; - u64 exp : 11; - u64 sign : 1; - }; - - struct - { - u64 : 51; - u64 nan : 1; - u64 : 12; - }; - }; - - FPRType type; - - operator double&() { return _double; } - operator const double&() const { return _double; } - - PPCdouble& operator = (const PPCdouble& r) - { - _u64 = r._u64; - type = UpdateType(); - return *this; - } - - FPRType UpdateType() const - { - const int fpc = _fpclass(_double); - -#ifndef __GNUG__ - switch(fpc) - { - case _FPCLASS_SNAN:// return FPR_SNAN; - case _FPCLASS_QNAN: return FPR_QNAN; - case _FPCLASS_NINF: return FPR_NINF; - case _FPCLASS_NN: return FPR_NN; - case _FPCLASS_ND: return FPR_ND; - case _FPCLASS_NZ: return FPR_NZ; - case _FPCLASS_PZ: return FPR_PZ; - case _FPCLASS_PD: return FPR_PD; - case _FPCLASS_PN: return FPR_PN; - case _FPCLASS_PINF: return FPR_PINF; - default: throw EXCEPTION("Unknown fpclass (0x%04x)", fpc); - } -#else - switch (fpc) - { - case FP_NAN: return FPR_QNAN; - case FP_INFINITE: return std::signbit(_double) ? FPR_NINF : FPR_PINF; - case FP_SUBNORMAL: return std::signbit(_double) ? FPR_ND : FPR_PD; - case FP_ZERO: return std::signbit(_double) ? FPR_NZ : FPR_PZ; - default: return std::signbit(_double) ? FPR_NN : FPR_PN; - } -#endif - } - - FPRType GetType() const - { - return type; - } - - u32 To32() const - { - float res = (float)_double; - - return (u32&)res; - } - - u64 To64() const - { - return (u64&)_double; - } - - u32 GetZerosCount() const - { - u32 ret; - u32 dd = frac >> 32; - if(dd) - { - ret = 31; - } - else - { - dd = frac; - ret = 63; - } - - if(dd > 0xffff) - { - ret -= 16; - dd >>= 16; - } - if(dd > 0xff) - { - ret -= 8; - dd >>= 8; - } - if(dd & 0xf0) - { - ret -= 4; - dd >>= 4; - } - if(dd & 0xc) - { - ret -= 2; - dd >>= 2; - } - if(dd & 0x2) ret--; - - return ret; - } - - PPCdouble() : _u64(0) - { - type = UpdateType(); - } - - PPCdouble(double val) : _double(val) - { - type = UpdateType(); - } - - PPCdouble(u64 val) : _u64(val) - { - type = UpdateType(); - } - - PPCdouble(u32 val) : _u64(val) - { - type = UpdateType(); - } -}; - -struct FPRdouble -{ - static const u64 double_sign = 0x8000000000000000ULL; - static const u64 double_frac = 0x000FFFFFFFFFFFFFULL; - - static bool IsINF(PPCdouble d); - static bool IsNaN(PPCdouble d); - static bool IsQNaN(PPCdouble d); - static bool IsSNaN(PPCdouble d); - - static int Cmp(PPCdouble a, PPCdouble b); -}; - -class PPUThread final : public CPUThread -{ -public: - PPCdouble FPR[32]{}; //Floating Point Register - FPSCRhdr FPSCR{}; //Floating Point Status and Control Register - u64 GPR[32]{}; //General-Purpose Register - v128 VPR[32]{}; - u32 vpcr = 0; - - CRhdr CR{}; //Condition Register - //CR0 - // 0 : LT - Negative (is negative) - // : 0 - Result is not negative - // : 1 - Result is negative - // 1 : GT - Positive (is positive) - // : 0 - Result is not positive - // : 1 - Result is positive - // 2 : EQ - Zero (is zero) - // : 0 - Result is not equal to zero - // : 1 - Result is equal to zero - // 3 : SO - Summary overflow (copy of the final state XER[S0]) - // : 0 - No overflow occurred - // : 1 - Overflow occurred - - //CRn - // 0 : LT - Less than (rA > X) - // : 0 - rA is not less than - // : 1 - rA is less than - // 1 : GT - Greater than (rA < X) - // : 0 - rA is not greater than - // : 1 - rA is greater than - // 2 : EQ - Equal to (rA == X) - // : 0 - Result is not equal to zero - // : 1 - Result is equal to zero - // 3 : SO - Summary overflow (copy of the final state XER[S0]) - // : 0 - No overflow occurred - // : 1 - Overflow occurred - - //SPR : Special-Purpose Registers - - XERhdr XER{}; //SPR 0x001 : Fixed-Point Expection Register - // 0 : SO - Summary overflow - // : 0 - No overflow occurred - // : 1 - Overflow occurred - // 1 : OV - Overflow - // : 0 - No overflow occurred - // : 1 - Overflow occurred - // 2 : CA - Carry - // : 0 - Carry did not occur - // : 1 - Carry occured - // 3 - 24 : Reserved - // 25 - 31 : TBC - // Transfer-byte count - - MSRhdr MSR{}; //Machine State Register - PVRhdr PVR{}; //Processor Version Register - - VSCRhdr VSCR{}; // Vector Status and Control Register - - u64 LR = 0; //SPR 0x008 : Link Register - u64 CTR = 0; //SPR 0x009 : Count Register - - u32 VRSAVE = 0; //SPR 0x100: VR Save/Restore Register (32 bits) - - u64 SPRG[8]{}; //SPR 0x110 - 0x117 : SPR General-Purpose Registers - - //TBR : Time-Base Registers - u64 TB = 0; //TBR 0x10C - 0x10D - - u32 PC = 0; - s32 prio = 0; // thread priority - u32 stack_addr = 0; // stack address - u32 stack_size = 0; // stack size + s32 prio = 0; // Thread priority + u32 stack_addr = 0; // Stack address + u32 stack_size = 0; // Stack size bool is_joinable = true; bool is_joining = false; - u64 hle_code = 0; // current syscall (~0..~1023) or function id (1..UINT32_MAX) + std::function custom_task; - std::function custom_task; + // Function name can be stored here. Used to print the last called function. + const char* last_function = nullptr; // When a thread has met an exception, this variable is used to retro propagate it through stack call. std::exception_ptr pending_exception; -public: - PPUThread(const std::string& name); - virtual ~PPUThread() override; - - virtual std::string get_name() const override; - virtual void dump_info() const override; - virtual u32 get_pc() const override { return PC; } - virtual u32 get_offset() const override { return 0; } - virtual void do_run() override; - virtual void cpu_task() override; - - virtual void init_regs() override; - virtual void init_stack() override; - virtual void close_stack() override; - - virtual bool handle_interrupt() override; - - u8 GetCR(const u8 n) const + // Pack CR bits + u32 GetCR() const { - switch(n) + u32 result{}; + + for (u32 bit : CR) { - case 0: return CR.cr0; - case 1: return CR.cr1; - case 2: return CR.cr2; - case 3: return CR.cr3; - case 4: return CR.cr4; - case 5: return CR.cr5; - case 6: return CR.cr6; - case 7: return CR.cr7; + result = (result << 1) | bit; } - return 0; + return result; } - void SetCR(const u8 n, const u32 value) + // Unpack CR bits + void SetCR(u32 value) { - switch(n) + for (bool& b : CR) { - case 0: CR.cr0 = value; break; - case 1: CR.cr1 = value; break; - case 2: CR.cr2 = value; break; - case 3: CR.cr3 = value; break; - case 4: CR.cr4 = value; break; - case 5: CR.cr5 = value; break; - case 6: CR.cr6 = value; break; - case 7: CR.cr7 = value; break; + b = (value & 0x1) != 0; + value >>= 1; } } - void SetCRBit(const u8 n, const u32 bit, const bool value) + // Set CR field + void SetCR(u32 field, bool le, bool gt, bool eq, bool so) { - switch(n) - { - case 0: CR.cr0 = (value ? CR.cr0 | bit : CR.cr0 & ~bit); break; - case 1: CR.cr1 = (value ? CR.cr1 | bit : CR.cr1 & ~bit); break; - case 2: CR.cr2 = (value ? CR.cr2 | bit : CR.cr2 & ~bit); break; - case 3: CR.cr3 = (value ? CR.cr3 | bit : CR.cr3 & ~bit); break; - case 4: CR.cr4 = (value ? CR.cr4 | bit : CR.cr4 & ~bit); break; - case 5: CR.cr5 = (value ? CR.cr5 | bit : CR.cr5 & ~bit); break; - case 6: CR.cr6 = (value ? CR.cr6 | bit : CR.cr6 & ~bit); break; - case 7: CR.cr7 = (value ? CR.cr7 | bit : CR.cr7 & ~bit); break; - } + CR[field * 4 + 0] = le; + CR[field * 4 + 1] = gt; + CR[field * 4 + 2] = eq; + CR[field * 4 + 3] = so; } - void SetCR_EQ(const u8 n, const bool value) { SetCRBit(n, CR_EQ, value); } - void SetCR_GT(const u8 n, const bool value) { SetCRBit(n, CR_GT, value); } - void SetCR_LT(const u8 n, const bool value) { SetCRBit(n, CR_LT, value); } - void SetCR_SO(const u8 n, const bool value) { SetCRBit(n, CR_SO, value); } - - bool IsCR_EQ(const u8 n) const { return (GetCR(n) & CR_EQ) ? 1 : 0; } - bool IsCR_GT(const u8 n) const { return (GetCR(n) & CR_GT) ? 1 : 0; } - bool IsCR_LT(const u8 n) const { return (GetCR(n) & CR_LT) ? 1 : 0; } - - template void UpdateCRn(const u8 n, const T a, const T b) + // Set CR field for comparison + template + void SetCR(u32 field, const T& a, const T& b) { - if (a < b) SetCR(n, CR_LT); - else if (a > b) SetCR(n, CR_GT); - else if (a == b) SetCR(n, CR_EQ); - - SetCR_SO(n, XER.SO); + SetCR(field, a < b, a > b, a == b, SO); } - void UpdateCRnU(const u8 l, const u8 n, const u64 a, const u64 b) - { - if(l) - { - UpdateCRn(n, a, b); - } - else - { - UpdateCRn(n, (u32)a, (u32)b); - } - } - - void UpdateCRnS(const u8 l, const u8 n, const u64 a, const u64 b) - { - if(l) - { - UpdateCRn(n, (s64)a, (s64)b); - } - else - { - UpdateCRn(n, (s32)a, (s32)b); - } - } - - template void UpdateCR0(const T val) - { - UpdateCRn(0, val, 0); - } - - void UpdateCR1() - { - SetCR_LT(1, FPSCR.FX); - SetCR_GT(1, FPSCR.FEX); - SetCR_EQ(1, FPSCR.VX); - SetCR_SO(1, FPSCR.OX); - } - - const u8 GetCRBit(const u32 bit) const { return 1 << (3 - (bit % 4)); } - - void SetCRBit (const u32 bit, bool set) { SetCRBit(bit >> 2, GetCRBit(bit), set); } - void SetCRBit2(const u32 bit, bool set) { SetCRBit(bit >> 2, 0x8 >> (bit & 3), set); } - - const u8 IsCR(const u32 bit) const { return (GetCR(bit >> 2) & GetCRBit(bit)) ? 1 : 0; } - - bool IsCarry(const u64 a, const u64 b) { return (a + b) < a; } - bool IsCarry(const u64 a, const u64 b, const u64 c) { return IsCarry(a, b) || IsCarry(a + b, c); } - + // Set overflow bit void SetOV(const bool set) { - XER.OV = set; - XER.SO |= set; + OV = set; + SO |= set; } - void UpdateFPSCR_FEX() + u64 get_next_arg(u32& g_count) { - const u32 exceptions = (FPSCR.FPSCR >> 25) & 0x1F; - const u32 enabled = (FPSCR.FPSCR >> 3) & 0x1F; - if (exceptions & enabled) FPSCR.FEX = 1; - } - - void UpdateFPSCR_VX() - { - if (FPSCR.FPSCR & FPSCR_VX_ALL) FPSCR.VX = 1; - } - - void SetFPSCR(const u32 val) - { - FPSCR.FPSCR = val & ~(FPSCR_FEX | FPSCR_VX); - UpdateFPSCR_VX(); - UpdateFPSCR_FEX(); - } - - void SetFPSCRException(const FPSCR_EXP mask) - { - if ((FPSCR.FPSCR & mask) != mask) FPSCR.FX = 1; - FPSCR.FPSCR |= mask; - UpdateFPSCR_VX(); - UpdateFPSCR_FEX(); - } - - void SetFPSCR_FI(const u32 val) - { - if(val) SetFPSCRException(FPSCR_XX); - FPSCR.FI = val; - } - - virtual std::string RegsToString() const override - { - std::string ret = "Registers:\n=========\n"; - - for(uint i=0; i<32; ++i) ret += fmt::format("GPR[%d] = 0x%llx\n", i, GPR[i]); - for(uint i=0; i<32; ++i) ret += fmt::format("FPR[%d] = %.6G\n", i, (double)FPR[i]); - for(uint i=0; i<32; ++i) ret += fmt::format("VPR[%d] = 0x%s [%s]\n", i, VPR[i].to_hex().c_str(), VPR[i].to_xyzw().c_str()); - ret += fmt::format("CR = 0x%08x\n", CR.CR); - ret += fmt::format("LR = 0x%llx\n", LR); - ret += fmt::format("CTR = 0x%llx\n", CTR); - ret += fmt::format("XER = 0x%llx [CA=%lld | OV=%lld | SO=%lld]\n", XER.XER, u32{ XER.CA }, u32{ XER.OV }, u32{ XER.SO }); - ret += fmt::format("FPSCR = 0x%x " - "[RN=%d | NI=%d | XE=%d | ZE=%d | UE=%d | OE=%d | VE=%d | " - "VXCVI=%d | VXSQRT=%d | VXSOFT=%d | FPRF=%d | " - "FI=%d | FR=%d | VXVC=%d | VXIMZ=%d | " - "VXZDZ=%d | VXIDI=%d | VXISI=%d | VXSNAN=%d | " - "XX=%d | ZX=%d | UX=%d | OX=%d | VX=%d | FEX=%d | FX=%d]\n", - FPSCR.FPSCR, - u32{ FPSCR.RN }, - u32{ FPSCR.NI }, u32{ FPSCR.XE }, u32{ FPSCR.ZE }, u32{ FPSCR.UE }, u32{ FPSCR.OE }, u32{ FPSCR.VE }, - u32{ FPSCR.VXCVI }, u32{ FPSCR.VXSQRT }, u32{ FPSCR.VXSOFT }, u32{ FPSCR.FPRF }, - u32{ FPSCR.FI }, u32{ FPSCR.FR }, u32{ FPSCR.VXVC }, u32{ FPSCR.VXIMZ }, - u32{ FPSCR.VXZDZ }, u32{ FPSCR.VXIDI }, u32{ FPSCR.VXISI }, u32{ FPSCR.VXSNAN }, - u32{ FPSCR.XX }, u32{ FPSCR.ZX }, u32{ FPSCR.UX }, u32{ FPSCR.OX }, u32{ FPSCR.VX }, u32{ FPSCR.FEX }, u32{ FPSCR.FX }); - - return ret; - } - - virtual std::string ReadRegString(const std::string& reg) const override - { - std::string::size_type first_brk = reg.find('['); - if (first_brk != std::string::npos) - { - long reg_index = atol(reg.substr(first_brk+1,reg.length()-first_brk-2).c_str()); - if (reg.find("GPR")==0) return fmt::format("%016llx", GPR[reg_index]); - if (reg.find("FPR")==0) return fmt::format("%016llx", (double)FPR[reg_index]); - if (reg.find("VPR")==0) return fmt::format("%016llx%016llx", VPR[reg_index]._u64[1], VPR[reg_index]._u64[0]); - } - if (reg == "CR") return fmt::format("%08x", CR.CR); - if (reg == "LR") return fmt::format("%016llx", LR); - if (reg == "CTR") return fmt::format("%016llx", CTR); - if (reg == "XER") return fmt::format("%016llx", XER.XER); - if (reg == "FPSCR") return fmt::format("%08x", FPSCR.FPSCR); - - return ""; - } - - bool WriteRegString(const std::string& reg, std::string value) override - { - while (value.length() < 32) value = "0"+value; - std::string::size_type first_brk = reg.find('['); - try - { - if (first_brk != std::string::npos) - { - long reg_index = atol(reg.substr(first_brk + 1, reg.length() - first_brk - 2).c_str()); - if (reg.find("GPR")==0 || reg.find("FPR")==0 ) - { - unsigned long long reg_value; - reg_value = std::stoull(value.substr(16, 31),0,16); - if (reg.find("GPR")==0) GPR[reg_index] = (u64)reg_value; - if (reg.find("FPR")==0) FPR[reg_index] = (u64)reg_value; - return true; - } - if (reg.find("VPR")==0) - { - unsigned long long reg_value0; - unsigned long long reg_value1; - reg_value0 = std::stoull(value.substr(16, 31), 0, 16); - reg_value1 = std::stoull(value.substr(0, 15), 0, 16); - VPR[reg_index]._u64[0] = (u64)reg_value0; - VPR[reg_index]._u64[1] = (u64)reg_value1; - return true; - } - } - if (reg == "LR" || reg == "CTR" || reg == "XER") - { - unsigned long long reg_value; - reg_value = std::stoull(value.substr(16, 31), 0, 16); - if (reg == "LR") LR = (u64)reg_value; - if (reg == "CTR") CTR = (u64)reg_value; - if (reg == "XER") XER.XER = (u64)reg_value; - return true; - } - if (reg == "CR" || reg == "FPSCR") - { - unsigned long long reg_value; - reg_value = std::stoull(value.substr(24, 31), 0, 16); - if (reg == "CR") CR.CR = (u32)reg_value; - if (reg == "FPSCR") FPSCR.FPSCR = (u32)reg_value; - return true; - } - } - catch (std::invalid_argument&)//if any of the stoull conversion fail - { - return false; - } - return false; - } - - u64 get_next_gpr_arg(u32& g_count, u32& f_count, u32& v_count) - { - assert(!f_count && !v_count); // not supported - if (g_count < 8) { return GPR[g_count++ + 3]; } else { - return get_stack_arg(++g_count); + return *get_stack_arg(++g_count); } } -public: - u64 get_stack_arg(s32 i); + be_t* get_stack_arg(s32 i, u64 align = alignof(u64)); void fast_call(u32 addr, u32 rtoc); - void fast_stop(); }; -class ppu_thread : cpu_thread +template +struct ppu_gpr_cast_impl { - static const u32 stack_align = 0x10; - vm::_ptr_base> argv; - u32 argc; - vm::_ptr_base> envp; - -public: - ppu_thread(u32 entry, const std::string& name = "", u32 stack_size = 0, s32 prio = 0); - - cpu_thread& args(std::initializer_list values) override; - cpu_thread& run() override; - ppu_thread& gpr(uint index, u64 value); + static_assert(!sizeof(T), "Invalid type for ppu_gpr_cast<>"); }; -template::value> -struct cast_ppu_gpr +template +struct ppu_gpr_cast_impl::value || std::is_enum::value>> { - static_assert(is_enum, "Invalid type for cast_ppu_gpr"); + static_assert(sizeof(T) <= 8, "Too big integral type for ppu_gpr_cast<>()"); + static_assert(std::is_same::value == false, "bool type is deprecated in ppu_gpr_cast<>(), use b8 instead"); - force_inline static u64 to_gpr(const T& value) + static inline u64 to(const T& value) { - return cast_ppu_gpr>::to_gpr(static_cast>(value)); + return static_cast(value); } - force_inline static T from_gpr(const u64 reg) + static inline T from(const u64 reg) { - return static_cast(cast_ppu_gpr>::from_gpr(reg)); + return static_cast(reg); } }; template<> -struct cast_ppu_gpr +struct ppu_gpr_cast_impl { - force_inline static u64 to_gpr(const u8& value) + static inline u64 to(const b8& value) { return value; } - force_inline static u8 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const u16& value) - { - return value; - } - - force_inline static u16 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const u32& value) - { - return value; - } - - force_inline static u32 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -#ifdef __APPLE__ -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const unsigned long& value) - { - return value; - } - - force_inline static unsigned long from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; -#endif - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const u64& value) - { - return value; - } - - force_inline static u64 from_gpr(const u64 reg) - { - return reg; - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const s8& value) - { - return value; - } - - force_inline static s8 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const s16& value) - { - return value; - } - - force_inline static s16 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const s32& value) - { - return value; - } - - force_inline static s32 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const s64& value) - { - return value; - } - - force_inline static s64 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const b8& value) - { - return value; - } - - force_inline static b8 from_gpr(const u64& reg) + static inline b8 from(const u64 reg) { return static_cast(reg) != 0; } }; -template -force_inline u64 cast_to_ppu_gpr(const T& value) +template +struct ppu_gpr_cast_impl, void> { - return cast_ppu_gpr::to_gpr(value); -} + static inline u64 to(const vm::_ptr_base& value) + { + return ppu_gpr_cast_impl::to(value.addr()); + } -template -force_inline T cast_from_ppu_gpr(const u64 reg) -{ - return cast_ppu_gpr::from_gpr(reg); -} - -// flags set in ModuleFunc -enum : u32 -{ - MFF_FORCED_HLE = (1 << 0), // always call HLE function - MFF_NO_RETURN = (1 << 1), // uses EIF_USE_BRANCH flag with LLE, ignored with MFF_FORCED_HLE - - MFF_PERFECT = /* 0 */ MFF_FORCED_HLE, // can be set for fully implemented functions with LLE compatibility + static inline vm::_ptr_base from(const u64 reg) + { + return{ ppu_gpr_cast_impl::from(reg), vm::addr }; + } }; -// flags passed with index -enum : u32 +template +struct ppu_gpr_cast_impl, void> { - EIF_SAVE_RTOC = (1 << 25), // save RTOC in [SP+0x28] before calling HLE/LLE function - EIF_PERFORM_BLR = (1 << 24), // do BLR after calling HLE/LLE function - EIF_USE_BRANCH = (1 << 23), // do only branch, LLE must be set, last_syscall must be zero + static inline u64 to(const vm::_ref_base& value) + { + return ppu_gpr_cast_impl::to(value.addr()); + } - EIF_FLAGS = 0x3800000, // all flags + static inline vm::_ref_base from(const u64 reg) + { + return{ ppu_gpr_cast_impl::from(reg), vm::addr }; + } }; + +template +inline To ppu_gpr_cast(const From& value) +{ + return ppu_gpr_cast_impl::from(ppu_gpr_cast_impl::to(value)); +} diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index f0c9c06f6a..facaa0fa3e 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -1,17 +1,27 @@ #include "stdafx.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Callback.h" +#include "Emu/IdManager.h" +#include "Loader/ELF.h" #include "Emu/Cell/RawSPUThread.h" // Originally, SPU MFC registers are accessed externally in a concurrent manner (don't mix with channels, SPU MFC channels are isolated) thread_local spu_mfc_arg_t raw_spu_mfc[8] = {}; -RawSPUThread::RawSPUThread(const std::string& name, u32 index) - : SPUThread(CPU_THREAD_RAW_SPU, name, index, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index) +void RawSPUThread::cpu_task() { - CHECK_ASSERTION(vm::falloc(offset, 0x40000) == offset); + // get next PC and SPU Interrupt status + pc = npc.exchange(0); + + set_interrupt_status((pc & 1) != 0); + + pc &= 0x3fffc; + + SPUThread::cpu_task(); + + // save next PC and current SPU Interrupt status + npc = pc | ((ch_event_stat & SPU_EVENT_INTR_ENABLED) != 0); } bool RawSPUThread::read_reg(const u32 addr, u32& value) @@ -81,7 +91,8 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value) } })) { - exec(); + state -= cpu_state::stop; + safe_notify(); } }; @@ -182,7 +193,7 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value) else if (value == SPU_RUNCNTL_STOP_REQUEST) { status &= ~SPU_STATUS_RUNNING; - stop(); + state += cpu_state::stop; } else { @@ -221,17 +232,19 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value) return false; } -void RawSPUThread::cpu_task() +template<> +void spu_exec_loader::load() const { - // get next PC and SPU Interrupt status - pc = npc.exchange(0); + auto spu = idm::make_ptr("TEST_SPU"); - set_interrupt_status((pc & 1) != 0); + for (const auto& prog : progs) + { + if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz) + { + std::memcpy(vm::base(spu->offset + prog.p_vaddr), prog.bin.data(), prog.p_filesz); + } + } - pc &= 0x3fffc; - - SPUThread::cpu_task(); - - // save next PC and current SPU Interrupt status - npc = pc | ((ch_event_stat & SPU_EVENT_INTR_ENABLED) != 0); + spu->cpu_init(); + spu->npc = header.e_entry; } diff --git a/rpcs3/Emu/Cell/RawSPUThread.h b/rpcs3/Emu/Cell/RawSPUThread.h index 32cf470052..c3a27aa46f 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.h +++ b/rpcs3/Emu/Cell/RawSPUThread.h @@ -2,27 +2,36 @@ #include "SPUThread.h" -enum : u32 -{ - RAW_SPU_OFFSET = 0x00100000, - RAW_SPU_BASE_ADDR = 0xE0000000, - RAW_SPU_LS_OFFSET = 0x00000000, - RAW_SPU_PROB_OFFSET = 0x00040000, -}; - -force_inline static u32 GetRawSPURegAddrByNum(int num, int offset) -{ - return RAW_SPU_OFFSET * num + RAW_SPU_BASE_ADDR + RAW_SPU_PROB_OFFSET + offset; -} - class RawSPUThread final : public SPUThread { + void cpu_task() override; + public: - RawSPUThread(const std::string& name, u32 index); + /* IdManager setups */ + + using id_base = RawSPUThread; + + static constexpr u32 id_min = 0; + static constexpr u32 id_max = 4; + + void on_init() override + { + if (!offset) + { + // Install correct SPU index and LS address + const_cast(index) = id; + const_cast(offset) = vm::falloc(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, 0x40000); + ASSERT(offset); + + SPUThread::on_init(); + } + } + + RawSPUThread(const std::string& name) + : SPUThread(name) + { + } bool read_reg(const u32 addr, u32& value); bool write_reg(const u32 addr, const u32 value); - -private: - virtual void cpu_task() override; }; diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp index 1f5f43f9c4..a20f92c4b0 100644 --- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "SPUDisAsm.h" @@ -9,10 +10,6 @@ #define ASMJIT_STATIC #define ASMJIT_DEBUG -#ifdef _MSC_VER -#pragma comment(lib, "asmjit.lib") -#endif - #include "asmjit.h" #define SPU_OFF_128(x) asmjit::host::oword_ptr(*cpu, OFFSET_32(SPUThread, x)) @@ -21,6 +18,9 @@ #define SPU_OFF_16(x) asmjit::host::word_ptr(*cpu, OFFSET_32(SPUThread, x)) #define SPU_OFF_8(x) asmjit::host::byte_ptr(*cpu, OFFSET_32(SPUThread, x)) +const spu_decoder s_spu_interpreter; // TODO: remove +const spu_decoder s_spu_decoder; + spu_recompiler::spu_recompiler() : m_jit(std::make_shared()) { @@ -29,7 +29,7 @@ spu_recompiler::spu_recompiler() LOG_SUCCESS(SPU, "SPU Recompiler (ASMJIT) created..."); - fs::file(fs::get_config_dir() + "SPUJIT.log", fom::rewrite).write(fmt::format("SPU JIT initialization...\n\nTitle: %s\nTitle ID: %s\n\n", Emu.GetTitle().c_str(), Emu.GetTitleID().c_str())); + fs::file(fs::get_config_dir() + "SPUJIT.log", fs::rewrite).write(fmt::format("SPU JIT initialization...\n\nTitle: %s\nTitle ID: %s\n\n", Emu.GetTitle().c_str(), Emu.GetTitleID().c_str())); } void spu_recompiler::compile(spu_function_t& f) @@ -145,13 +145,13 @@ void spu_recompiler::compile(spu_function_t& f) // Disasm dis_asm.dump_pc = m_pos; - dis_asm.do_disasm(op); + dis_asm.disasm(m_pos); compiler.addComment(dis_asm.last_opcode.c_str()); log += dis_asm.last_opcode.c_str(); log += '\n'; // Recompiler function - (this->*spu_recompiler::opcodes[op])({ op }); + (this->*s_spu_decoder.decode(op))({ op }); // Collect allocated xmm vars for (u32 i = 0; i < vec_vars.size(); i++) @@ -214,7 +214,7 @@ void spu_recompiler::compile(spu_function_t& f) log += "\n\n\n"; // Append log file - fs::file(fs::get_config_dir() + "SPUJIT.log", fom::write | fom::append).write(log); + fs::file(fs::get_config_dir() + "SPUJIT.log", fs::write + fs::append).write(log); } spu_recompiler::XmmLink spu_recompiler::XmmAlloc() // get empty xmm register @@ -267,7 +267,7 @@ void spu_recompiler::InterpreterCall(spu_opcode_t op) const u32 old_pc = _spu->pc; - if (_spu->m_state && _spu->check_status()) + if (_spu->state.load() && _spu->check_status()) { return 0x2000000 | _spu->pc; } @@ -294,7 +294,7 @@ void spu_recompiler::InterpreterCall(spu_opcode_t op) asmjit::X86CallNode* call = c->call(asmjit::imm_ptr(asmjit_cast(gate)), asmjit::kFuncConvHost, asmjit::FuncBuilder3()); call->setArg(0, *cpu); call->setArg(1, asmjit::imm_u(op.opcode)); - call->setArg(2, asmjit::imm_ptr(asmjit_cast(spu_interpreter::fast::g_spu_opcode_table[op.opcode]))); + call->setArg(2, asmjit::imm_ptr(asmjit_cast(s_spu_interpreter.decode(op.opcode)))); call->setRet(0, *addr); // return immediately if an error occured @@ -338,21 +338,20 @@ void spu_recompiler::FunctionCall() LOG_ERROR(SPU, "Branch-to-self"); } - while (!_spu->m_state || !_spu->check_status()) + while (!_spu->state.load() || !_spu->check_status()) { - // Call override function directly since the type is known - static_cast(*_spu->m_dec).DecodeMemory(_spu->offset + _spu->pc); + // Proceed recursively + spu_recompiler_base::enter(*_spu); - if (_spu->m_state & CPU_STATE_RETURN) + if (_spu->state & cpu_state::ret) { break; } if (_spu->pc == link) { - // returned successfully _spu->recursion_level--; - return 0; + return 0; // Successfully returned } } @@ -2185,7 +2184,7 @@ void spu_recompiler::BR(spu_opcode_t op) c->mov(*addr, target | 0x2000000); //c->cmp(asmjit::host::dword_ptr(*ls, m_pos), 0x32); // compare instruction opcode with BR-to-self //c->je(labels[target / 4]); - c->lock().or_(SPU_OFF_64(m_state), CPU_STATE_RETURN | CPU_STATE_STOPPED); + c->lock().or_(SPU_OFF_32(state), (to_mset(cpu_state::stop) + cpu_state::ret)._value()); c->jmp(*end); c->unuse(*addr); return; @@ -2614,7 +2613,6 @@ void spu_recompiler::FMS(spu_opcode_t op) void spu_recompiler::UNK(spu_opcode_t op) { - throw EXCEPTION("Unknown/Illegal opcode (0x%08x)", op.opcode); + LOG_ERROR(SPU, "0x%05x: Unknown/Illegal opcode (0x%08x)", m_pos, op.opcode); + c->int3(); } - -const spu_opcode_table_t spu_recompiler::opcodes{ DEFINE_SPU_OPCODES(&spu_recompiler::), &spu_recompiler::UNK }; diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.h b/rpcs3/Emu/Cell/SPUASMJITRecompiler.h index 9655b19ce9..2055a778ca 100644 --- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.h +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.h @@ -13,7 +13,7 @@ namespace asmjit } // SPU ASMJIT Recompiler -class spu_recompiler : public SPURecompilerBase +class spu_recompiler : public spu_recompiler_base { const std::shared_ptr m_jit; @@ -75,7 +75,7 @@ private: asmjit::X86Mem XmmConst(__m128 data); asmjit::X86Mem XmmConst(__m128i data); -private: +public: void InterpreterCall(spu_opcode_t op); void FunctionCall(); @@ -280,6 +280,4 @@ private: void FMS(spu_opcode_t op); void UNK(spu_opcode_t op); - - static const spu_opcode_table_t opcodes; }; diff --git a/rpcs3/Emu/Cell/SPUAnalyser.cpp b/rpcs3/Emu/Cell/SPUAnalyser.cpp index d8e063c7b2..57cc2d4b14 100644 --- a/rpcs3/Emu/Cell/SPUAnalyser.cpp +++ b/rpcs3/Emu/Cell/SPUAnalyser.cpp @@ -4,7 +4,7 @@ #include "SPURecompiler.h" #include "SPUAnalyser.h" -const spu_opcode_table_t g_spu_itype{ DEFINE_SPU_OPCODES(spu_itype::), spu_itype::UNK }; +const spu_decoder s_spu_itype; std::shared_ptr SPUDatabase::find(const be_t* data, u64 key, u32 max_size) { @@ -83,7 +83,7 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en { const spu_opcode_t op{ ls[pos / 4] }; - const spu_itype_t type = g_spu_itype[op.opcode]; + const auto type = s_spu_itype.decode(op.opcode); using namespace spu_itype; @@ -172,15 +172,15 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en break; } - if (type == BI || type == IRET) // Branch Indirect + if (type == &type::BI || type == &type::IRET) // Branch Indirect { - if (type == IRET) LOG_ERROR(SPU, "[0x%05x] Interrupt Return", pos); + if (type == &type::IRET) LOG_ERROR(SPU, "[0x%05x] Interrupt Return", pos); blocks.emplace(start); start = pos + 4; } - else if (type == BR || type == BRA) // Branch Relative/Absolute + else if (type == &type::BR || type == &type::BRA) // Branch Relative/Absolute { - const u32 target = spu_branch_target(type == BR ? pos : 0, op.i16); + const u32 target = spu_branch_target(type == &type::BR ? pos : 0, op.i16); // Add adjacent function because it always could be adjacent.emplace(target); @@ -192,9 +192,9 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en blocks.emplace(start); start = pos + 4; } - else if (type == BRSL || type == BRASL) // Branch Relative/Absolute and Set Link + else if (type == &type::BRSL || type == &type::BRASL) // Branch Relative/Absolute and Set Link { - const u32 target = spu_branch_target(type == BRSL ? pos : 0, op.i16); + const u32 target = spu_branch_target(type == &type::BRSL ? pos : 0, op.i16); if (target == pos + 4) { @@ -215,11 +215,11 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en if (op.rt != 0) LOG_ERROR(SPU, "[0x%05x] Function call without $LR", pos); } } - else if (type == BISL || type == BISLED) // Branch Indirect and Set Link + else if (type == &type::BISL || type == &type::BISLED) // Branch Indirect and Set Link { if (op.rt != 0) LOG_ERROR(SPU, "[0x%05x] Indirect function call without $LR", pos); } - else if (type == BRNZ || type == BRZ || type == BRHNZ || type == BRHZ) // Branch Relative if (Not) Zero (Half)word + else if (type == &type::BRNZ || type == &type::BRZ || type == &type::BRHNZ || type == &type::BRHZ) // Branch Relative if (Not) Zero (Half)word { const u32 target = spu_branch_target(pos, op.i16); @@ -231,24 +231,24 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en blocks.emplace(target); } } - else if (type == BINZ || type == BIZ || type == BIHNZ || type == BIHZ) // Branch Indirect if (Not) Zero (Half)word + else if (type == &type::BINZ || type == &type::BIZ || type == &type::BIHNZ || type == &type::BIHZ) // Branch Indirect if (Not) Zero (Half)word { } - else if (type == HBR || type == HBRA || type == HBRR) // Hint for Branch + else if (type == &type::HBR || type == &type::HBRA || type == &type::HBRR) // Hint for Branch { } - else if (type == STQA || type == STQD || type == STQR || type == STQX || type == FSCRWR || type == MTSPR || type == WRCH) // Store + else if (type == &type::STQA || type == &type::STQD || type == &type::STQR || type == &type::STQX || type == &type::FSCRWR || type == &type::MTSPR || type == &type::WRCH) // Store { } - else if (type == HEQ || type == HEQI || type == HGT || type == HGTI || type == HLGT || type == HLGTI) // Halt + else if (type == &type::HEQ || type == &type::HEQI || type == &type::HGT || type == &type::HGTI || type == &type::HLGT || type == &type::HLGTI) // Halt { } - else if (type == STOP || type == STOPD || type == NOP || type == LNOP || type == SYNC || type == DSYNC) // Miscellaneous + else if (type == &type::STOP || type == &type::STOPD || type == &type::NOP || type == &type::LNOP || type == &type::SYNC || type == &type::DSYNC) // Miscellaneous { } else // Other instructions (writing rt reg) { - const u32 rt = type == SELB || type == SHUFB || type == MPYA || type == FNMS || type == FMA || type == FMS ? +op.rc : +op.rt; + const u32 rt = type == &type::SELB || type == &type::SHUFB || type == &type::MPYA || type == &type::FNMS || type == &type::FMA || type == &type::FMS ? +op.rc : +op.rt; // Analyse link register access if (rt == 0) @@ -258,7 +258,7 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en // Analyse stack pointer access if (rt == 1) { - if (type == ILA && pos < ila_sp_pos) + if (type == &type::ILA && pos < ila_sp_pos) { // set minimal ila $SP,* instruction position ila_sp_pos = pos; @@ -272,7 +272,7 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en { const spu_opcode_t op{ ls[pos / 4] }; - const spu_itype_t type = g_spu_itype[op.opcode]; + const auto type = s_spu_itype.decode(op.opcode); using namespace spu_itype; @@ -280,9 +280,9 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en { break; } - else if (type == BRSL || type == BRASL) // Branch Relative/Absolute and Set Link + else if (type == &type::BRSL || type == &type::BRASL) // Branch Relative/Absolute and Set Link { - const u32 target = spu_branch_target(type == BRSL ? pos : 0, op.i16); + const u32 target = spu_branch_target(type == &type::BRSL ? pos : 0, op.i16); if (target != pos + 4 && target > entry && limit > target) { diff --git a/rpcs3/Emu/Cell/SPUAnalyser.h b/rpcs3/Emu/Cell/SPUAnalyser.h index c03429f134..1588d31c8a 100644 --- a/rpcs3/Emu/Cell/SPUAnalyser.h +++ b/rpcs3/Emu/Cell/SPUAnalyser.h @@ -3,250 +3,246 @@ #include "Emu/Cell/SPUOpcodes.h" #include "Utilities/SharedMutex.h" +#include + class SPUThread; // Type of the runtime functions generated by SPU recompiler using spu_jit_func_t = u32(*)(SPUThread* _spu, be_t* _ls); -// SPU instruction classification namespace +// SPU Instruction Classifier namespace spu_itype { - enum spu_itype_t : u32 + struct type { - UNK = 0, - - STOP, - LNOP, - SYNC, - DSYNC, - MFSPR, - RDCH, - RCHCNT, - SF, - OR, - BG, - SFH, - NOR, - ABSDB, - ROT, - ROTM, - ROTMA, - SHL, - ROTH, - ROTHM, - ROTMAH, - SHLH, - ROTI, - ROTMI, - ROTMAI, - SHLI, - ROTHI, - ROTHMI, - ROTMAHI, - SHLHI, - A, - AND, - CG, - AH, - NAND, - AVGB, - MTSPR, - WRCH, - BIZ, - BINZ, - BIHZ, - BIHNZ, - STOPD, - STQX, - BI, - BISL, - IRET, - BISLED, - HBR, - GB, - GBH, - GBB, - FSM, - FSMH, - FSMB, - FREST, - FRSQEST, - LQX, - ROTQBYBI, - ROTQMBYBI, - SHLQBYBI, - CBX, - CHX, - CWX, - CDX, - ROTQBI, - ROTQMBI, - SHLQBI, - ROTQBY, - ROTQMBY, - SHLQBY, - ORX, - CBD, - CHD, - CWD, - CDD, - ROTQBII, - ROTQMBII, - SHLQBII, - ROTQBYI, - ROTQMBYI, - SHLQBYI, - NOP, - CGT, - XOR, - CGTH, - EQV, - CGTB, - SUMB, - HGT, - CLZ, - XSWD, - XSHW, - CNTB, - XSBH, - CLGT, - ANDC, - FCGT, - DFCGT, - FA, - FS, - FM, - CLGTH, - ORC, - FCMGT, - DFCMGT, - DFA, - DFS, - DFM, - CLGTB, - HLGT, - DFMA, - DFMS, - DFNMS, - DFNMA, - CEQ, - MPYHHU, - ADDX, - SFX, - CGX, - BGX, - MPYHHA, - MPYHHAU, - FSCRRD, - FESD, - FRDS, - FSCRWR, - DFTSV, - FCEQ, - DFCEQ, - MPY, - MPYH, - MPYHH, - MPYS, - CEQH, - FCMEQ, - DFCMEQ, - MPYU, - CEQB, - FI, - HEQ, - CFLTS, - CFLTU, - CSFLT, - CUFLT, - BRZ, - STQA, - BRNZ, - BRHZ, - BRHNZ, - STQR, - BRA, - LQA, - BRASL, - BR, - FSMBI, - BRSL, - LQR, - IL, - ILHU, - ILH, - IOHL, - ORI, - ORHI, - ORBI, - SFI, - SFHI, - ANDI, - ANDHI, - ANDBI, - AI, - AHI, - STQD, - LQD, - XORI, - XORHI, - XORBI, - CGTI, - CGTHI, - CGTBI, - HGTI, - CLGTI, - CLGTHI, - CLGTBI, - HLGTI, - MPYI, - MPYUI, - CEQI, - CEQHI, - CEQBI, - HEQI, - HBRA, - HBRR, - ILA, - SELB, - SHUFB, - MPYA, - FNMS, - FMA, - FMS, + u32 UNK; + u32 STOP; + u32 LNOP; + u32 SYNC; + u32 DSYNC; + u32 MFSPR; + u32 RDCH; + u32 RCHCNT; + u32 SF; + u32 OR; + u32 BG; + u32 SFH; + u32 NOR; + u32 ABSDB; + u32 ROT; + u32 ROTM; + u32 ROTMA; + u32 SHL; + u32 ROTH; + u32 ROTHM; + u32 ROTMAH; + u32 SHLH; + u32 ROTI; + u32 ROTMI; + u32 ROTMAI; + u32 SHLI; + u32 ROTHI; + u32 ROTHMI; + u32 ROTMAHI; + u32 SHLHI; + u32 A; + u32 AND; + u32 CG; + u32 AH; + u32 NAND; + u32 AVGB; + u32 MTSPR; + u32 WRCH; + u32 BIZ; + u32 BINZ; + u32 BIHZ; + u32 BIHNZ; + u32 STOPD; + u32 STQX; + u32 BI; + u32 BISL; + u32 IRET; + u32 BISLED; + u32 HBR; + u32 GB; + u32 GBH; + u32 GBB; + u32 FSM; + u32 FSMH; + u32 FSMB; + u32 FREST; + u32 FRSQEST; + u32 LQX; + u32 ROTQBYBI; + u32 ROTQMBYBI; + u32 SHLQBYBI; + u32 CBX; + u32 CHX; + u32 CWX; + u32 CDX; + u32 ROTQBI; + u32 ROTQMBI; + u32 SHLQBI; + u32 ROTQBY; + u32 ROTQMBY; + u32 SHLQBY; + u32 ORX; + u32 CBD; + u32 CHD; + u32 CWD; + u32 CDD; + u32 ROTQBII; + u32 ROTQMBII; + u32 SHLQBII; + u32 ROTQBYI; + u32 ROTQMBYI; + u32 SHLQBYI; + u32 NOP; + u32 CGT; + u32 XOR; + u32 CGTH; + u32 EQV; + u32 CGTB; + u32 SUMB; + u32 HGT; + u32 CLZ; + u32 XSWD; + u32 XSHW; + u32 CNTB; + u32 XSBH; + u32 CLGT; + u32 ANDC; + u32 FCGT; + u32 DFCGT; + u32 FA; + u32 FS; + u32 FM; + u32 CLGTH; + u32 ORC; + u32 FCMGT; + u32 DFCMGT; + u32 DFA; + u32 DFS; + u32 DFM; + u32 CLGTB; + u32 HLGT; + u32 DFMA; + u32 DFMS; + u32 DFNMS; + u32 DFNMA; + u32 CEQ; + u32 MPYHHU; + u32 ADDX; + u32 SFX; + u32 CGX; + u32 BGX; + u32 MPYHHA; + u32 MPYHHAU; + u32 FSCRRD; + u32 FESD; + u32 FRDS; + u32 FSCRWR; + u32 DFTSV; + u32 FCEQ; + u32 DFCEQ; + u32 MPY; + u32 MPYH; + u32 MPYHH; + u32 MPYS; + u32 CEQH; + u32 FCMEQ; + u32 DFCMEQ; + u32 MPYU; + u32 CEQB; + u32 FI; + u32 HEQ; + u32 CFLTS; + u32 CFLTU; + u32 CSFLT; + u32 CUFLT; + u32 BRZ; + u32 STQA; + u32 BRNZ; + u32 BRHZ; + u32 BRHNZ; + u32 STQR; + u32 BRA; + u32 LQA; + u32 BRASL; + u32 BR; + u32 FSMBI; + u32 BRSL; + u32 LQR; + u32 IL; + u32 ILHU; + u32 ILH; + u32 IOHL; + u32 ORI; + u32 ORHI; + u32 ORBI; + u32 SFI; + u32 SFHI; + u32 ANDI; + u32 ANDHI; + u32 ANDBI; + u32 AI; + u32 AHI; + u32 STQD; + u32 LQD; + u32 XORI; + u32 XORHI; + u32 XORBI; + u32 CGTI; + u32 CGTHI; + u32 CGTBI; + u32 HGTI; + u32 CLGTI; + u32 CLGTHI; + u32 CLGTBI; + u32 HLGTI; + u32 MPYI; + u32 MPYUI; + u32 CEQI; + u32 CEQHI; + u32 CEQBI; + u32 HEQI; + u32 HBRA; + u32 HBRR; + u32 ILA; + u32 SELB; + u32 SHUFB; + u32 MPYA; + u32 FNMS; + u32 FMA; + u32 FMS; }; -} - -using spu_itype::spu_itype_t; - -// SPU Instruction Classification table -extern const spu_opcode_table_t g_spu_itype; +}; // SPU basic function information structure struct spu_function_t { - // entry point (LS address) + // Entry point (LS address) const u32 addr; - // function size (in bytes) + // Function size (in bytes) const u32 size; - // function contents (binary copy) + // Function contents (binary copy) std::vector> data; - // basic blocks (start addresses) + // Basic blocks (start addresses) std::set blocks; - // functions possibly called by this function (may not be available) + // Functions possibly called by this function (may not be available) std::set adjacent; - // jump table values (start addresses) + // Jump table values (start addresses) std::set jtable; - // whether ila $SP,* instruction found + // Whether ila $SP,* instruction found bool does_reset_stack; - // pointer to the compiled function + // Pointer to the compiled function spu_jit_func_t compiled = nullptr; spu_function_t(u32 addr, u32 size) diff --git a/rpcs3/Emu/Cell/SPUContext.h b/rpcs3/Emu/Cell/SPUContext.h deleted file mode 100644 index 9c408ffdd2..0000000000 --- a/rpcs3/Emu/Cell/SPUContext.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -struct spu_context_t -{ -}; diff --git a/rpcs3/Emu/Cell/SPUDisAsm.cpp b/rpcs3/Emu/Cell/SPUDisAsm.cpp new file mode 100644 index 0000000000..85b5eeb14e --- /dev/null +++ b/rpcs3/Emu/Cell/SPUDisAsm.cpp @@ -0,0 +1,11 @@ +#include "stdafx.h" +#include "SPUDisAsm.h" + +const spu_decoder s_spu_disasm; + +u32 SPUDisAsm::disasm(u32 pc) +{ + const u32 op = *(be_t*)(offset + pc); + (this->*(s_spu_disasm.decode(op)))({ op }); + return 4; +} diff --git a/rpcs3/Emu/Cell/SPUDisAsm.h b/rpcs3/Emu/Cell/SPUDisAsm.h index 0583d9fa04..69d10c4c8a 100644 --- a/rpcs3/Emu/Cell/SPUDisAsm.h +++ b/rpcs3/Emu/Cell/SPUDisAsm.h @@ -66,7 +66,7 @@ static const char* spu_ch_name[128] = "$ch121", "$ch122", "$ch123", "$ch124", "$ch125", "$ch126", "$ch127", }; -class SPUDisAsm : public PPCDisAsm +class SPUDisAsm final : public PPCDisAsm { public: SPUDisAsm(CPUDisAsmMode mode) : PPCDisAsm(mode) @@ -133,6 +133,10 @@ private: { Write(fmt::format("%s %s,%s,%s,%s", FixOp(op).c_str(), a1, a2, a3, a4)); } + +public: + u32 disasm(u32 pc) override; + //0 - 10 void STOP(spu_opcode_t op) { @@ -945,12 +949,4 @@ private: { Write(fmt::format("Unknown/Illegal opcode! (0x%08x)", op.opcode)); } - - static const spu_opcode_table_t opcodes; - -public: - void do_disasm(u32 opcode) - { - (this->*opcodes[opcode])({ opcode }); - } }; diff --git a/rpcs3/Emu/Cell/SPUInterpreter.cpp b/rpcs3/Emu/Cell/SPUInterpreter.cpp index 0c669c37ac..8af145cbe6 100644 --- a/rpcs3/Emu/Cell/SPUInterpreter.cpp +++ b/rpcs3/Emu/Cell/SPUInterpreter.cpp @@ -7,20 +7,7 @@ #include -namespace spu_interpreter -{ - namespace fast - { - const spu_opcode_table_t g_spu_opcode_table{ DEFINE_SPU_OPCODES(+), default_function }; - } - - namespace precise - { - const spu_opcode_table_t g_spu_opcode_table{ DEFINE_SPU_OPCODES(+), default_function }; - } -} - -void spu_interpreter::default_function(SPUThread& spu, spu_opcode_t op) +void spu_interpreter::UNK(SPUThread& spu, spu_opcode_t op) { throw EXCEPTION("Unknown/Illegal instruction (0x%08x)", op.opcode); } @@ -396,12 +383,12 @@ void spu_interpreter::FSMB(SPUThread& spu, spu_opcode_t op) spu.gpr[op.rt] = g_spu_imm.fsmb[spu.gpr[op.ra]._u32[3] & 0xffff]; } -void spu_interpreter::fast::FREST(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FREST(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vf = _mm_rcp_ps(spu.gpr[op.ra].vf); } -void spu_interpreter::fast::FRSQEST(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FRSQEST(SPUThread& spu, spu_opcode_t op) { const auto mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)); spu.gpr[op.rt].vf = _mm_rsqrt_ps(_mm_and_ps(spu.gpr[op.ra].vf, mask)); @@ -687,7 +674,7 @@ void spu_interpreter::ANDC(SPUThread& spu, spu_opcode_t op) spu.gpr[op.rt] = v128::andnot(spu.gpr[op.rb], spu.gpr[op.ra]); } -void spu_interpreter::fast::FCGT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FCGT(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vf = _mm_cmplt_ps(spu.gpr[op.rb].vf, spu.gpr[op.ra].vf); } @@ -697,17 +684,17 @@ void spu_interpreter::DFCGT(SPUThread& spu, spu_opcode_t op) throw EXCEPTION("Unexpected instruction"); } -void spu_interpreter::fast::FA(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FA(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt] = v128::addfs(spu.gpr[op.ra], spu.gpr[op.rb]); } -void spu_interpreter::fast::FS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FS(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt] = v128::subfs(spu.gpr[op.ra], spu.gpr[op.rb]); } -void spu_interpreter::fast::FM(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FM(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vf = _mm_mul_ps(spu.gpr[op.ra].vf, spu.gpr[op.rb].vf); } @@ -722,7 +709,7 @@ void spu_interpreter::ORC(SPUThread& spu, spu_opcode_t op) spu.gpr[op.rt] = spu.gpr[op.ra] | ~spu.gpr[op.rb]; } -void spu_interpreter::fast::FCMGT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FCMGT(SPUThread& spu, spu_opcode_t op) { const auto mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)); spu.gpr[op.rt].vf = _mm_cmplt_ps(_mm_and_ps(spu.gpr[op.rb].vf, mask), _mm_and_ps(spu.gpr[op.ra].vf, mask)); @@ -733,17 +720,17 @@ void spu_interpreter::DFCMGT(SPUThread& spu, spu_opcode_t op) throw EXCEPTION("Unexpected instruction"); } -void spu_interpreter::fast::DFA(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFA(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt] = v128::addfd(spu.gpr[op.ra], spu.gpr[op.rb]); } -void spu_interpreter::fast::DFS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFS(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt] = v128::subfd(spu.gpr[op.ra], spu.gpr[op.rb]); } -void spu_interpreter::fast::DFM(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFM(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vd = _mm_mul_pd(spu.gpr[op.ra].vd, spu.gpr[op.rb].vd); } @@ -761,22 +748,22 @@ void spu_interpreter::HLGT(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::fast::DFMA(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFMA(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vd = _mm_add_pd(_mm_mul_pd(spu.gpr[op.ra].vd, spu.gpr[op.rb].vd), spu.gpr[op.rt].vd); } -void spu_interpreter::fast::DFMS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFMS(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vd = _mm_sub_pd(_mm_mul_pd(spu.gpr[op.ra].vd, spu.gpr[op.rb].vd), spu.gpr[op.rt].vd); } -void spu_interpreter::fast::DFNMS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFNMS(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vd = _mm_sub_pd(spu.gpr[op.rt].vd, _mm_mul_pd(spu.gpr[op.ra].vd, spu.gpr[op.rb].vd)); } -void spu_interpreter::fast::DFNMA(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFNMA(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vd = _mm_sub_pd(_mm_set1_pd(0.0), _mm_add_pd(_mm_mul_pd(spu.gpr[op.ra].vd, spu.gpr[op.rb].vd), spu.gpr[op.rt].vd)); } @@ -833,24 +820,24 @@ void spu_interpreter::MPYHHAU(SPUThread& spu, spu_opcode_t op) spu.gpr[op.rt].vi = _mm_add_epi32(spu.gpr[op.rt].vi, _mm_or_si128(_mm_srli_epi32(_mm_mullo_epi16(a, b), 16), _mm_and_si128(_mm_mulhi_epu16(a, b), _mm_set1_epi32(0xffff0000)))); } -void spu_interpreter::fast::FSCRRD(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FSCRRD(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].clear(); } -void spu_interpreter::fast::FESD(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FESD(SPUThread& spu, spu_opcode_t op) { const auto a = spu.gpr[op.ra].vf; spu.gpr[op.rt].vd = _mm_cvtps_pd(_mm_shuffle_ps(a, a, 0x8d)); } -void spu_interpreter::fast::FRDS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FRDS(SPUThread& spu, spu_opcode_t op) { const auto t = _mm_cvtpd_ps(spu.gpr[op.ra].vd); spu.gpr[op.rt].vf = _mm_shuffle_ps(t, t, 0x72); } -void spu_interpreter::fast::FSCRWR(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FSCRWR(SPUThread& spu, spu_opcode_t op) { } @@ -859,7 +846,7 @@ void spu_interpreter::DFTSV(SPUThread& spu, spu_opcode_t op) throw EXCEPTION("Unexpected instruction"); } -void spu_interpreter::fast::FCEQ(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FCEQ(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vf = _mm_cmpeq_ps(spu.gpr[op.rb].vf, spu.gpr[op.ra].vf); } @@ -895,7 +882,7 @@ void spu_interpreter::CEQH(SPUThread& spu, spu_opcode_t op) spu.gpr[op.rt].vi = _mm_cmpeq_epi16(spu.gpr[op.ra].vi, spu.gpr[op.rb].vi); } -void spu_interpreter::fast::FCMEQ(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FCMEQ(SPUThread& spu, spu_opcode_t op) { const auto mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)); spu.gpr[op.rt].vf = _mm_cmpeq_ps(_mm_and_ps(spu.gpr[op.rb].vf, mask), _mm_and_ps(spu.gpr[op.ra].vf, mask)); @@ -918,7 +905,7 @@ void spu_interpreter::CEQB(SPUThread& spu, spu_opcode_t op) spu.gpr[op.rt].vi = _mm_cmpeq_epi8(spu.gpr[op.ra].vi, spu.gpr[op.rb].vi); } -void spu_interpreter::fast::FI(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FI(SPUThread& spu, spu_opcode_t op) { // TODO const auto mask_se = _mm_castsi128_ps(_mm_set1_epi32(0xff800000)); // sign and exponent mask @@ -940,25 +927,25 @@ void spu_interpreter::HEQ(SPUThread& spu, spu_opcode_t op) } -void spu_interpreter::fast::CFLTS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::CFLTS(SPUThread& spu, spu_opcode_t op) { const auto scaled = _mm_mul_ps(spu.gpr[op.ra].vf, g_spu_imm.scale[173 - op.i8]); spu.gpr[op.rt].vi = _mm_xor_si128(_mm_cvttps_epi32(scaled), _mm_castps_si128(_mm_cmpge_ps(scaled, _mm_set1_ps(0x80000000)))); } -void spu_interpreter::fast::CFLTU(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::CFLTU(SPUThread& spu, spu_opcode_t op) { const auto scaled1 = _mm_max_ps(_mm_mul_ps(spu.gpr[op.ra].vf, g_spu_imm.scale[173 - op.i8]), _mm_set1_ps(0.0f)); const auto scaled2 = _mm_and_ps(_mm_sub_ps(scaled1, _mm_set1_ps(0x80000000)), _mm_cmpge_ps(scaled1, _mm_set1_ps(0x80000000))); spu.gpr[op.rt].vi = _mm_or_si128(_mm_or_si128(_mm_cvttps_epi32(scaled1), _mm_cvttps_epi32(scaled2)), _mm_castps_si128(_mm_cmpge_ps(scaled1, _mm_set1_ps(0x100000000)))); } -void spu_interpreter::fast::CSFLT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::CSFLT(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vf = _mm_mul_ps(_mm_cvtepi32_ps(spu.gpr[op.ra].vi), g_spu_imm.scale[op.i8 - 155]); } -void spu_interpreter::fast::CUFLT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::CUFLT(SPUThread& spu, spu_opcode_t op) { const auto a = spu.gpr[op.ra].vi; const auto fix = _mm_and_ps(_mm_castsi128_ps(_mm_srai_epi32(a, 31)), _mm_set1_ps(0x80000000)); @@ -1265,17 +1252,17 @@ void spu_interpreter::MPYA(SPUThread& spu, spu_opcode_t op) spu.gpr[op.rt4].vi = _mm_add_epi32(spu.gpr[op.rc].vi, _mm_madd_epi16(_mm_and_si128(spu.gpr[op.ra].vi, mask), _mm_and_si128(spu.gpr[op.rb].vi, mask))); } -void spu_interpreter::fast::FNMS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FNMS(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt4].vf = _mm_sub_ps(spu.gpr[op.rc].vf, _mm_mul_ps(spu.gpr[op.ra].vf, spu.gpr[op.rb].vf)); } -void spu_interpreter::fast::FMA(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FMA(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt4].vf = _mm_add_ps(_mm_mul_ps(spu.gpr[op.ra].vf, spu.gpr[op.rb].vf), spu.gpr[op.rc].vf); } -void spu_interpreter::fast::FMS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FMS(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt4].vf = _mm_sub_ps(_mm_mul_ps(spu.gpr[op.ra].vf, spu.gpr[op.rb].vf), spu.gpr[op.rc].vf); } @@ -1360,7 +1347,7 @@ inline bool isdenormal(double x) #endif } -void spu_interpreter::precise::FREST(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FREST(SPUThread& spu, spu_opcode_t op) { SetHostRoundingMode(FPSCR_RN_ZERO); for (int i = 0; i < 4; i++) @@ -1380,7 +1367,7 @@ void spu_interpreter::precise::FREST(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FRSQEST(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FRSQEST(SPUThread& spu, spu_opcode_t op) { SetHostRoundingMode(FPSCR_RN_ZERO); for (int i = 0; i < 4; i++) @@ -1400,7 +1387,7 @@ void spu_interpreter::precise::FRSQEST(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FCGT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FCGT(SPUThread& spu, spu_opcode_t op) { for (int i = 0; i < 4; i++) { @@ -1508,11 +1495,11 @@ static void FA_FS(SPUThread& spu, spu_opcode_t op, bool sub) } } -void spu_interpreter::precise::FA(SPUThread& spu, spu_opcode_t op) { FA_FS(spu, op, false); } +void spu_interpreter_precise::FA(SPUThread& spu, spu_opcode_t op) { FA_FS(spu, op, false); } -void spu_interpreter::precise::FS(SPUThread& spu, spu_opcode_t op) { FA_FS(spu, op, true); } +void spu_interpreter_precise::FS(SPUThread& spu, spu_opcode_t op) { FA_FS(spu, op, true); } -void spu_interpreter::precise::FM(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FM(SPUThread& spu, spu_opcode_t op) { SetHostRoundingMode(FPSCR_RN_ZERO); for (int w = 0; w < 4; w++) @@ -1585,7 +1572,7 @@ void spu_interpreter::precise::FM(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FCMGT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FCMGT(SPUThread& spu, spu_opcode_t op) { for (int i = 0; i < 4; i++) { @@ -1666,11 +1653,11 @@ static void DFASM(SPUThread& spu, spu_opcode_t op, DoubleOp operation) } } -void spu_interpreter::precise::DFA(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_A); } +void spu_interpreter_precise::DFA(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_A); } -void spu_interpreter::precise::DFS(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_S); } +void spu_interpreter_precise::DFS(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_S); } -void spu_interpreter::precise::DFM(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_M); } +void spu_interpreter_precise::DFM(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_M); } static void DFMA(SPUThread& spu, spu_opcode_t op, bool neg, bool sub) { @@ -1727,20 +1714,20 @@ static void DFMA(SPUThread& spu, spu_opcode_t op, bool neg, bool sub) } } -void spu_interpreter::precise::DFMA(SPUThread& spu, spu_opcode_t op) { DFMA(spu, op, false, false); } +void spu_interpreter_precise::DFMA(SPUThread& spu, spu_opcode_t op) { ::DFMA(spu, op, false, false); } -void spu_interpreter::precise::DFMS(SPUThread& spu, spu_opcode_t op) { DFMA(spu, op, false, true); } +void spu_interpreter_precise::DFMS(SPUThread& spu, spu_opcode_t op) { ::DFMA(spu, op, false, true); } -void spu_interpreter::precise::DFNMS(SPUThread& spu, spu_opcode_t op) { DFMA(spu, op, true, true); } +void spu_interpreter_precise::DFNMS(SPUThread& spu, spu_opcode_t op) { ::DFMA(spu, op, true, true); } -void spu_interpreter::precise::DFNMA(SPUThread& spu, spu_opcode_t op) { DFMA(spu, op, true, false); } +void spu_interpreter_precise::DFNMA(SPUThread& spu, spu_opcode_t op) { ::DFMA(spu, op, true, false); } -void spu_interpreter::precise::FSCRRD(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FSCRRD(SPUThread& spu, spu_opcode_t op) { spu.fpscr.Read(spu.gpr[op.rt]); } -void spu_interpreter::precise::FESD(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FESD(SPUThread& spu, spu_opcode_t op) { for (int i = 0; i < 2; i++) { @@ -1764,7 +1751,7 @@ void spu_interpreter::precise::FESD(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FRDS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FRDS(SPUThread& spu, spu_opcode_t op) { for (int i = 0; i < 2; i++) { @@ -1792,12 +1779,12 @@ void spu_interpreter::precise::FRDS(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FSCRWR(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FSCRWR(SPUThread& spu, spu_opcode_t op) { spu.fpscr.Write(spu.gpr[op.ra]); } -void spu_interpreter::precise::FCEQ(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FCEQ(SPUThread& spu, spu_opcode_t op) { for (int i = 0; i < 4; i++) { @@ -1812,7 +1799,7 @@ void spu_interpreter::precise::FCEQ(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FCMEQ(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FCMEQ(SPUThread& spu, spu_opcode_t op) { for (int i = 0; i < 4; i++) { @@ -1827,13 +1814,13 @@ void spu_interpreter::precise::FCMEQ(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FI(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FI(SPUThread& spu, spu_opcode_t op) { // TODO spu.gpr[op.rt] = spu.gpr[op.rb]; } -void spu_interpreter::precise::CFLTS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::CFLTS(SPUThread& spu, spu_opcode_t op) { const int scale = 173 - (op.i8 & 0xff); //unsigned immediate for (int i = 0; i < 4; i++) @@ -1855,7 +1842,7 @@ void spu_interpreter::precise::CFLTS(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::CFLTU(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::CFLTU(SPUThread& spu, spu_opcode_t op) { const int scale = 173 - (op.i8 & 0xff); //unsigned immediate for (int i = 0; i < 4; i++) @@ -1877,7 +1864,7 @@ void spu_interpreter::precise::CFLTU(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::CSFLT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::CSFLT(SPUThread& spu, spu_opcode_t op) { SetHostRoundingMode(FPSCR_RN_ZERO); const int scale = 155 - (op.i8 & 0xff); //unsigned immediate @@ -1900,7 +1887,7 @@ void spu_interpreter::precise::CSFLT(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::CUFLT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::CUFLT(SPUThread& spu, spu_opcode_t op) { SetHostRoundingMode(FPSCR_RN_ZERO); const int scale = 155 - (op.i8 & 0xff); //unsigned immediate @@ -2068,8 +2055,8 @@ static void FMA(SPUThread& spu, spu_opcode_t op, bool neg, bool sub) } } -void spu_interpreter::precise::FNMS(SPUThread& spu, spu_opcode_t op) { FMA(spu, op, true, true); } +void spu_interpreter_precise::FNMS(SPUThread& spu, spu_opcode_t op) { ::FMA(spu, op, true, true); } -void spu_interpreter::precise::FMA(SPUThread& spu, spu_opcode_t op) { FMA(spu, op, false, false); } +void spu_interpreter_precise::FMA(SPUThread& spu, spu_opcode_t op) { ::FMA(spu, op, false, false); } -void spu_interpreter::precise::FMS(SPUThread& spu, spu_opcode_t op) { FMA(spu, op, false, true); } +void spu_interpreter_precise::FMS(SPUThread& spu, spu_opcode_t op) { ::FMA(spu, op, false, true); } diff --git a/rpcs3/Emu/Cell/SPUInterpreter.h b/rpcs3/Emu/Cell/SPUInterpreter.h index 5b57cd671e..68c0d4f9f9 100644 --- a/rpcs3/Emu/Cell/SPUInterpreter.h +++ b/rpcs3/Emu/Cell/SPUInterpreter.h @@ -4,256 +4,246 @@ class SPUThread; -using spu_inter_func_t = void(*)(SPUThread& spu, spu_opcode_t opcode); +using spu_inter_func_t = void(*)(SPUThread& spu, spu_opcode_t op); -namespace spu_interpreter +struct spu_interpreter { - namespace fast - { - extern const spu_opcode_table_t g_spu_opcode_table; - } + static void UNK(SPUThread&, spu_opcode_t); + static void set_interrupt_status(SPUThread&, spu_opcode_t); - namespace precise - { - extern const spu_opcode_table_t g_spu_opcode_table; - } + static void STOP(SPUThread&, spu_opcode_t); + static void LNOP(SPUThread&, spu_opcode_t); + static void SYNC(SPUThread&, spu_opcode_t); + static void DSYNC(SPUThread&, spu_opcode_t); + static void MFSPR(SPUThread&, spu_opcode_t); + static void RDCH(SPUThread&, spu_opcode_t); + static void RCHCNT(SPUThread&, spu_opcode_t); + static void SF(SPUThread&, spu_opcode_t); + static void OR(SPUThread&, spu_opcode_t); + static void BG(SPUThread&, spu_opcode_t); + static void SFH(SPUThread&, spu_opcode_t); + static void NOR(SPUThread&, spu_opcode_t); + static void ABSDB(SPUThread&, spu_opcode_t); + static void ROT(SPUThread&, spu_opcode_t); + static void ROTM(SPUThread&, spu_opcode_t); + static void ROTMA(SPUThread&, spu_opcode_t); + static void SHL(SPUThread&, spu_opcode_t); + static void ROTH(SPUThread&, spu_opcode_t); + static void ROTHM(SPUThread&, spu_opcode_t); + static void ROTMAH(SPUThread&, spu_opcode_t); + static void SHLH(SPUThread&, spu_opcode_t); + static void ROTI(SPUThread&, spu_opcode_t); + static void ROTMI(SPUThread&, spu_opcode_t); + static void ROTMAI(SPUThread&, spu_opcode_t); + static void SHLI(SPUThread&, spu_opcode_t); + static void ROTHI(SPUThread&, spu_opcode_t); + static void ROTHMI(SPUThread&, spu_opcode_t); + static void ROTMAHI(SPUThread&, spu_opcode_t); + static void SHLHI(SPUThread&, spu_opcode_t); + static void A(SPUThread&, spu_opcode_t); + static void AND(SPUThread&, spu_opcode_t); + static void CG(SPUThread&, spu_opcode_t); + static void AH(SPUThread&, spu_opcode_t); + static void NAND(SPUThread&, spu_opcode_t); + static void AVGB(SPUThread&, spu_opcode_t); + static void MTSPR(SPUThread&, spu_opcode_t); + static void WRCH(SPUThread&, spu_opcode_t); + static void BIZ(SPUThread&, spu_opcode_t); + static void BINZ(SPUThread&, spu_opcode_t); + static void BIHZ(SPUThread&, spu_opcode_t); + static void BIHNZ(SPUThread&, spu_opcode_t); + static void STOPD(SPUThread&, spu_opcode_t); + static void STQX(SPUThread&, spu_opcode_t); + static void BI(SPUThread&, spu_opcode_t); + static void BISL(SPUThread&, spu_opcode_t); + static void IRET(SPUThread&, spu_opcode_t); + static void BISLED(SPUThread&, spu_opcode_t); + static void HBR(SPUThread&, spu_opcode_t); + static void GB(SPUThread&, spu_opcode_t); + static void GBH(SPUThread&, spu_opcode_t); + static void GBB(SPUThread&, spu_opcode_t); + static void FSM(SPUThread&, spu_opcode_t); + static void FSMH(SPUThread&, spu_opcode_t); + static void FSMB(SPUThread&, spu_opcode_t); + static void LQX(SPUThread&, spu_opcode_t); + static void ROTQBYBI(SPUThread&, spu_opcode_t); + static void ROTQMBYBI(SPUThread&, spu_opcode_t); + static void SHLQBYBI(SPUThread&, spu_opcode_t); + static void CBX(SPUThread&, spu_opcode_t); + static void CHX(SPUThread&, spu_opcode_t); + static void CWX(SPUThread&, spu_opcode_t); + static void CDX(SPUThread&, spu_opcode_t); + static void ROTQBI(SPUThread&, spu_opcode_t); + static void ROTQMBI(SPUThread&, spu_opcode_t); + static void SHLQBI(SPUThread&, spu_opcode_t); + static void ROTQBY(SPUThread&, spu_opcode_t); + static void ROTQMBY(SPUThread&, spu_opcode_t); + static void SHLQBY(SPUThread&, spu_opcode_t); + static void ORX(SPUThread&, spu_opcode_t); + static void CBD(SPUThread&, spu_opcode_t); + static void CHD(SPUThread&, spu_opcode_t); + static void CWD(SPUThread&, spu_opcode_t); + static void CDD(SPUThread&, spu_opcode_t); + static void ROTQBII(SPUThread&, spu_opcode_t); + static void ROTQMBII(SPUThread&, spu_opcode_t); + static void SHLQBII(SPUThread&, spu_opcode_t); + static void ROTQBYI(SPUThread&, spu_opcode_t); + static void ROTQMBYI(SPUThread&, spu_opcode_t); + static void SHLQBYI(SPUThread&, spu_opcode_t); + static void NOP(SPUThread&, spu_opcode_t); + static void CGT(SPUThread&, spu_opcode_t); + static void XOR(SPUThread&, spu_opcode_t); + static void CGTH(SPUThread&, spu_opcode_t); + static void EQV(SPUThread&, spu_opcode_t); + static void CGTB(SPUThread&, spu_opcode_t); + static void SUMB(SPUThread&, spu_opcode_t); + static void HGT(SPUThread&, spu_opcode_t); + static void CLZ(SPUThread&, spu_opcode_t); + static void XSWD(SPUThread&, spu_opcode_t); + static void XSHW(SPUThread&, spu_opcode_t); + static void CNTB(SPUThread&, spu_opcode_t); + static void XSBH(SPUThread&, spu_opcode_t); + static void CLGT(SPUThread&, spu_opcode_t); + static void ANDC(SPUThread&, spu_opcode_t); + static void CLGTH(SPUThread&, spu_opcode_t); + static void ORC(SPUThread&, spu_opcode_t); + static void CLGTB(SPUThread&, spu_opcode_t); + static void HLGT(SPUThread&, spu_opcode_t); + static void CEQ(SPUThread&, spu_opcode_t); + static void MPYHHU(SPUThread&, spu_opcode_t); + static void ADDX(SPUThread&, spu_opcode_t); + static void SFX(SPUThread&, spu_opcode_t); + static void CGX(SPUThread&, spu_opcode_t); + static void BGX(SPUThread&, spu_opcode_t); + static void MPYHHA(SPUThread&, spu_opcode_t); + static void MPYHHAU(SPUThread&, spu_opcode_t); + static void MPY(SPUThread&, spu_opcode_t); + static void MPYH(SPUThread&, spu_opcode_t); + static void MPYHH(SPUThread&, spu_opcode_t); + static void MPYS(SPUThread&, spu_opcode_t); + static void CEQH(SPUThread&, spu_opcode_t); + static void MPYU(SPUThread&, spu_opcode_t); + static void CEQB(SPUThread&, spu_opcode_t); + static void HEQ(SPUThread&, spu_opcode_t); + static void BRZ(SPUThread&, spu_opcode_t); + static void STQA(SPUThread&, spu_opcode_t); + static void BRNZ(SPUThread&, spu_opcode_t); + static void BRHZ(SPUThread&, spu_opcode_t); + static void BRHNZ(SPUThread&, spu_opcode_t); + static void STQR(SPUThread&, spu_opcode_t); + static void BRA(SPUThread&, spu_opcode_t); + static void LQA(SPUThread&, spu_opcode_t); + static void BRASL(SPUThread&, spu_opcode_t); + static void BR(SPUThread&, spu_opcode_t); + static void FSMBI(SPUThread&, spu_opcode_t); + static void BRSL(SPUThread&, spu_opcode_t); + static void LQR(SPUThread&, spu_opcode_t); + static void IL(SPUThread&, spu_opcode_t); + static void ILHU(SPUThread&, spu_opcode_t); + static void ILH(SPUThread&, spu_opcode_t); + static void IOHL(SPUThread&, spu_opcode_t); + static void ORI(SPUThread&, spu_opcode_t); + static void ORHI(SPUThread&, spu_opcode_t); + static void ORBI(SPUThread&, spu_opcode_t); + static void SFI(SPUThread&, spu_opcode_t); + static void SFHI(SPUThread&, spu_opcode_t); + static void ANDI(SPUThread&, spu_opcode_t); + static void ANDHI(SPUThread&, spu_opcode_t); + static void ANDBI(SPUThread&, spu_opcode_t); + static void AI(SPUThread&, spu_opcode_t); + static void AHI(SPUThread&, spu_opcode_t); + static void STQD(SPUThread&, spu_opcode_t); + static void LQD(SPUThread&, spu_opcode_t); + static void XORI(SPUThread&, spu_opcode_t); + static void XORHI(SPUThread&, spu_opcode_t); + static void XORBI(SPUThread&, spu_opcode_t); + static void CGTI(SPUThread&, spu_opcode_t); + static void CGTHI(SPUThread&, spu_opcode_t); + static void CGTBI(SPUThread&, spu_opcode_t); + static void HGTI(SPUThread&, spu_opcode_t); + static void CLGTI(SPUThread&, spu_opcode_t); + static void CLGTHI(SPUThread&, spu_opcode_t); + static void CLGTBI(SPUThread&, spu_opcode_t); + static void HLGTI(SPUThread&, spu_opcode_t); + static void MPYI(SPUThread&, spu_opcode_t); + static void MPYUI(SPUThread&, spu_opcode_t); + static void CEQI(SPUThread&, spu_opcode_t); + static void CEQHI(SPUThread&, spu_opcode_t); + static void CEQBI(SPUThread&, spu_opcode_t); + static void HEQI(SPUThread&, spu_opcode_t); + static void HBRA(SPUThread&, spu_opcode_t); + static void HBRR(SPUThread&, spu_opcode_t); + static void ILA(SPUThread&, spu_opcode_t); + static void SELB(SPUThread&, spu_opcode_t); + static void SHUFB(SPUThread&, spu_opcode_t); + static void MPYA(SPUThread&, spu_opcode_t); + static void DFCGT(SPUThread&, spu_opcode_t); + static void DFCMGT(SPUThread&, spu_opcode_t); + static void DFTSV(SPUThread&, spu_opcode_t); + static void DFCEQ(SPUThread&, spu_opcode_t); + static void DFCMEQ(SPUThread&, spu_opcode_t); +}; - void default_function(SPUThread& spu, spu_opcode_t op); - void set_interrupt_status(SPUThread& spu, spu_opcode_t op); +struct spu_interpreter_fast final : spu_interpreter +{ + static void FREST(SPUThread&, spu_opcode_t); + static void FRSQEST(SPUThread&, spu_opcode_t); + static void FCGT(SPUThread&, spu_opcode_t); + static void FA(SPUThread&, spu_opcode_t); + static void FS(SPUThread&, spu_opcode_t); + static void FM(SPUThread&, spu_opcode_t); + static void FCMGT(SPUThread&, spu_opcode_t); + static void DFA(SPUThread&, spu_opcode_t); + static void DFS(SPUThread&, spu_opcode_t); + static void DFM(SPUThread&, spu_opcode_t); + static void DFMA(SPUThread&, spu_opcode_t); + static void DFMS(SPUThread&, spu_opcode_t); + static void DFNMS(SPUThread&, spu_opcode_t); + static void DFNMA(SPUThread&, spu_opcode_t); + static void FSCRRD(SPUThread&, spu_opcode_t); + static void FESD(SPUThread&, spu_opcode_t); + static void FRDS(SPUThread&, spu_opcode_t); + static void FSCRWR(SPUThread&, spu_opcode_t); + static void FCEQ(SPUThread&, spu_opcode_t); + static void FCMEQ(SPUThread&, spu_opcode_t); + static void FI(SPUThread&, spu_opcode_t); + static void CFLTS(SPUThread&, spu_opcode_t); + static void CFLTU(SPUThread&, spu_opcode_t); + static void CSFLT(SPUThread&, spu_opcode_t); + static void CUFLT(SPUThread&, spu_opcode_t); + static void FNMS(SPUThread&, spu_opcode_t); + static void FMA(SPUThread&, spu_opcode_t); + static void FMS(SPUThread&, spu_opcode_t); +}; - void STOP(SPUThread& spu, spu_opcode_t op); - void LNOP(SPUThread& spu, spu_opcode_t op); - void SYNC(SPUThread& spu, spu_opcode_t op); - void DSYNC(SPUThread& spu, spu_opcode_t op); - void MFSPR(SPUThread& spu, spu_opcode_t op); - void RDCH(SPUThread& spu, spu_opcode_t op); - void RCHCNT(SPUThread& spu, spu_opcode_t op); - void SF(SPUThread& spu, spu_opcode_t op); - void OR(SPUThread& spu, spu_opcode_t op); - void BG(SPUThread& spu, spu_opcode_t op); - void SFH(SPUThread& spu, spu_opcode_t op); - void NOR(SPUThread& spu, spu_opcode_t op); - void ABSDB(SPUThread& spu, spu_opcode_t op); - void ROT(SPUThread& spu, spu_opcode_t op); - void ROTM(SPUThread& spu, spu_opcode_t op); - void ROTMA(SPUThread& spu, spu_opcode_t op); - void SHL(SPUThread& spu, spu_opcode_t op); - void ROTH(SPUThread& spu, spu_opcode_t op); - void ROTHM(SPUThread& spu, spu_opcode_t op); - void ROTMAH(SPUThread& spu, spu_opcode_t op); - void SHLH(SPUThread& spu, spu_opcode_t op); - void ROTI(SPUThread& spu, spu_opcode_t op); - void ROTMI(SPUThread& spu, spu_opcode_t op); - void ROTMAI(SPUThread& spu, spu_opcode_t op); - void SHLI(SPUThread& spu, spu_opcode_t op); - void ROTHI(SPUThread& spu, spu_opcode_t op); - void ROTHMI(SPUThread& spu, spu_opcode_t op); - void ROTMAHI(SPUThread& spu, spu_opcode_t op); - void SHLHI(SPUThread& spu, spu_opcode_t op); - void A(SPUThread& spu, spu_opcode_t op); - void AND(SPUThread& spu, spu_opcode_t op); - void CG(SPUThread& spu, spu_opcode_t op); - void AH(SPUThread& spu, spu_opcode_t op); - void NAND(SPUThread& spu, spu_opcode_t op); - void AVGB(SPUThread& spu, spu_opcode_t op); - void MTSPR(SPUThread& spu, spu_opcode_t op); - void WRCH(SPUThread& spu, spu_opcode_t op); - void BIZ(SPUThread& spu, spu_opcode_t op); - void BINZ(SPUThread& spu, spu_opcode_t op); - void BIHZ(SPUThread& spu, spu_opcode_t op); - void BIHNZ(SPUThread& spu, spu_opcode_t op); - void STOPD(SPUThread& spu, spu_opcode_t op); - void STQX(SPUThread& spu, spu_opcode_t op); - void BI(SPUThread& spu, spu_opcode_t op); - void BISL(SPUThread& spu, spu_opcode_t op); - void IRET(SPUThread& spu, spu_opcode_t op); - void BISLED(SPUThread& spu, spu_opcode_t op); - void HBR(SPUThread& spu, spu_opcode_t op); - void GB(SPUThread& spu, spu_opcode_t op); - void GBH(SPUThread& spu, spu_opcode_t op); - void GBB(SPUThread& spu, spu_opcode_t op); - void FSM(SPUThread& spu, spu_opcode_t op); - void FSMH(SPUThread& spu, spu_opcode_t op); - void FSMB(SPUThread& spu, spu_opcode_t op); - void LQX(SPUThread& spu, spu_opcode_t op); - void ROTQBYBI(SPUThread& spu, spu_opcode_t op); - void ROTQMBYBI(SPUThread& spu, spu_opcode_t op); - void SHLQBYBI(SPUThread& spu, spu_opcode_t op); - void CBX(SPUThread& spu, spu_opcode_t op); - void CHX(SPUThread& spu, spu_opcode_t op); - void CWX(SPUThread& spu, spu_opcode_t op); - void CDX(SPUThread& spu, spu_opcode_t op); - void ROTQBI(SPUThread& spu, spu_opcode_t op); - void ROTQMBI(SPUThread& spu, spu_opcode_t op); - void SHLQBI(SPUThread& spu, spu_opcode_t op); - void ROTQBY(SPUThread& spu, spu_opcode_t op); - void ROTQMBY(SPUThread& spu, spu_opcode_t op); - void SHLQBY(SPUThread& spu, spu_opcode_t op); - void ORX(SPUThread& spu, spu_opcode_t op); - void CBD(SPUThread& spu, spu_opcode_t op); - void CHD(SPUThread& spu, spu_opcode_t op); - void CWD(SPUThread& spu, spu_opcode_t op); - void CDD(SPUThread& spu, spu_opcode_t op); - void ROTQBII(SPUThread& spu, spu_opcode_t op); - void ROTQMBII(SPUThread& spu, spu_opcode_t op); - void SHLQBII(SPUThread& spu, spu_opcode_t op); - void ROTQBYI(SPUThread& spu, spu_opcode_t op); - void ROTQMBYI(SPUThread& spu, spu_opcode_t op); - void SHLQBYI(SPUThread& spu, spu_opcode_t op); - void NOP(SPUThread& spu, spu_opcode_t op); - void CGT(SPUThread& spu, spu_opcode_t op); - void XOR(SPUThread& spu, spu_opcode_t op); - void CGTH(SPUThread& spu, spu_opcode_t op); - void EQV(SPUThread& spu, spu_opcode_t op); - void CGTB(SPUThread& spu, spu_opcode_t op); - void SUMB(SPUThread& spu, spu_opcode_t op); - void HGT(SPUThread& spu, spu_opcode_t op); - void CLZ(SPUThread& spu, spu_opcode_t op); - void XSWD(SPUThread& spu, spu_opcode_t op); - void XSHW(SPUThread& spu, spu_opcode_t op); - void CNTB(SPUThread& spu, spu_opcode_t op); - void XSBH(SPUThread& spu, spu_opcode_t op); - void CLGT(SPUThread& spu, spu_opcode_t op); - void ANDC(SPUThread& spu, spu_opcode_t op); - void CLGTH(SPUThread& spu, spu_opcode_t op); - void ORC(SPUThread& spu, spu_opcode_t op); - void CLGTB(SPUThread& spu, spu_opcode_t op); - void HLGT(SPUThread& spu, spu_opcode_t op); - void CEQ(SPUThread& spu, spu_opcode_t op); - void MPYHHU(SPUThread& spu, spu_opcode_t op); - void ADDX(SPUThread& spu, spu_opcode_t op); - void SFX(SPUThread& spu, spu_opcode_t op); - void CGX(SPUThread& spu, spu_opcode_t op); - void BGX(SPUThread& spu, spu_opcode_t op); - void MPYHHA(SPUThread& spu, spu_opcode_t op); - void MPYHHAU(SPUThread& spu, spu_opcode_t op); - void MPY(SPUThread& spu, spu_opcode_t op); - void MPYH(SPUThread& spu, spu_opcode_t op); - void MPYHH(SPUThread& spu, spu_opcode_t op); - void MPYS(SPUThread& spu, spu_opcode_t op); - void CEQH(SPUThread& spu, spu_opcode_t op); - void MPYU(SPUThread& spu, spu_opcode_t op); - void CEQB(SPUThread& spu, spu_opcode_t op); - void HEQ(SPUThread& spu, spu_opcode_t op); - void BRZ(SPUThread& spu, spu_opcode_t op); - void STQA(SPUThread& spu, spu_opcode_t op); - void BRNZ(SPUThread& spu, spu_opcode_t op); - void BRHZ(SPUThread& spu, spu_opcode_t op); - void BRHNZ(SPUThread& spu, spu_opcode_t op); - void STQR(SPUThread& spu, spu_opcode_t op); - void BRA(SPUThread& spu, spu_opcode_t op); - void LQA(SPUThread& spu, spu_opcode_t op); - void BRASL(SPUThread& spu, spu_opcode_t op); - void BR(SPUThread& spu, spu_opcode_t op); - void FSMBI(SPUThread& spu, spu_opcode_t op); - void BRSL(SPUThread& spu, spu_opcode_t op); - void LQR(SPUThread& spu, spu_opcode_t op); - void IL(SPUThread& spu, spu_opcode_t op); - void ILHU(SPUThread& spu, spu_opcode_t op); - void ILH(SPUThread& spu, spu_opcode_t op); - void IOHL(SPUThread& spu, spu_opcode_t op); - void ORI(SPUThread& spu, spu_opcode_t op); - void ORHI(SPUThread& spu, spu_opcode_t op); - void ORBI(SPUThread& spu, spu_opcode_t op); - void SFI(SPUThread& spu, spu_opcode_t op); - void SFHI(SPUThread& spu, spu_opcode_t op); - void ANDI(SPUThread& spu, spu_opcode_t op); - void ANDHI(SPUThread& spu, spu_opcode_t op); - void ANDBI(SPUThread& spu, spu_opcode_t op); - void AI(SPUThread& spu, spu_opcode_t op); - void AHI(SPUThread& spu, spu_opcode_t op); - void STQD(SPUThread& spu, spu_opcode_t op); - void LQD(SPUThread& spu, spu_opcode_t op); - void XORI(SPUThread& spu, spu_opcode_t op); - void XORHI(SPUThread& spu, spu_opcode_t op); - void XORBI(SPUThread& spu, spu_opcode_t op); - void CGTI(SPUThread& spu, spu_opcode_t op); - void CGTHI(SPUThread& spu, spu_opcode_t op); - void CGTBI(SPUThread& spu, spu_opcode_t op); - void HGTI(SPUThread& spu, spu_opcode_t op); - void CLGTI(SPUThread& spu, spu_opcode_t op); - void CLGTHI(SPUThread& spu, spu_opcode_t op); - void CLGTBI(SPUThread& spu, spu_opcode_t op); - void HLGTI(SPUThread& spu, spu_opcode_t op); - void MPYI(SPUThread& spu, spu_opcode_t op); - void MPYUI(SPUThread& spu, spu_opcode_t op); - void CEQI(SPUThread& spu, spu_opcode_t op); - void CEQHI(SPUThread& spu, spu_opcode_t op); - void CEQBI(SPUThread& spu, spu_opcode_t op); - void HEQI(SPUThread& spu, spu_opcode_t op); - void HBRA(SPUThread& spu, spu_opcode_t op); - void HBRR(SPUThread& spu, spu_opcode_t op); - void ILA(SPUThread& spu, spu_opcode_t op); - void SELB(SPUThread& spu, spu_opcode_t op); - void SHUFB(SPUThread& spu, spu_opcode_t op); - void MPYA(SPUThread& spu, spu_opcode_t op); - void DFCGT(SPUThread& spu, spu_opcode_t op); - void DFCMGT(SPUThread& spu, spu_opcode_t op); - void DFTSV(SPUThread& spu, spu_opcode_t op); - void DFCEQ(SPUThread& spu, spu_opcode_t op); - void DFCMEQ(SPUThread& spu, spu_opcode_t op); - - namespace fast - { - void FREST(SPUThread& spu, spu_opcode_t op); - void FRSQEST(SPUThread& spu, spu_opcode_t op); - void FCGT(SPUThread& spu, spu_opcode_t op); - void FA(SPUThread& spu, spu_opcode_t op); - void FS(SPUThread& spu, spu_opcode_t op); - void FM(SPUThread& spu, spu_opcode_t op); - void FCMGT(SPUThread& spu, spu_opcode_t op); - void DFA(SPUThread& spu, spu_opcode_t op); - void DFS(SPUThread& spu, spu_opcode_t op); - void DFM(SPUThread& spu, spu_opcode_t op); - void DFMA(SPUThread& spu, spu_opcode_t op); - void DFMS(SPUThread& spu, spu_opcode_t op); - void DFNMS(SPUThread& spu, spu_opcode_t op); - void DFNMA(SPUThread& spu, spu_opcode_t op); - void FSCRRD(SPUThread& spu, spu_opcode_t op); - void FESD(SPUThread& spu, spu_opcode_t op); - void FRDS(SPUThread& spu, spu_opcode_t op); - void FSCRWR(SPUThread& spu, spu_opcode_t op); - void FCEQ(SPUThread& spu, spu_opcode_t op); - void FCMEQ(SPUThread& spu, spu_opcode_t op); - void FI(SPUThread& spu, spu_opcode_t op); - void CFLTS(SPUThread& spu, spu_opcode_t op); - void CFLTU(SPUThread& spu, spu_opcode_t op); - void CSFLT(SPUThread& spu, spu_opcode_t op); - void CUFLT(SPUThread& spu, spu_opcode_t op); - void FNMS(SPUThread& spu, spu_opcode_t op); - void FMA(SPUThread& spu, spu_opcode_t op); - void FMS(SPUThread& spu, spu_opcode_t op); - } - - namespace precise - { - void FREST(SPUThread& spu, spu_opcode_t op); - void FRSQEST(SPUThread& spu, spu_opcode_t op); - void FCGT(SPUThread& spu, spu_opcode_t op); - void FA(SPUThread& spu, spu_opcode_t op); - void FS(SPUThread& spu, spu_opcode_t op); - void FM(SPUThread& spu, spu_opcode_t op); - void FCMGT(SPUThread& spu, spu_opcode_t op); - void DFA(SPUThread& spu, spu_opcode_t op); - void DFS(SPUThread& spu, spu_opcode_t op); - void DFM(SPUThread& spu, spu_opcode_t op); - void DFMA(SPUThread& spu, spu_opcode_t op); - void DFMS(SPUThread& spu, spu_opcode_t op); - void DFNMS(SPUThread& spu, spu_opcode_t op); - void DFNMA(SPUThread& spu, spu_opcode_t op); - void FSCRRD(SPUThread& spu, spu_opcode_t op); - void FESD(SPUThread& spu, spu_opcode_t op); - void FRDS(SPUThread& spu, spu_opcode_t op); - void FSCRWR(SPUThread& spu, spu_opcode_t op); - void FCEQ(SPUThread& spu, spu_opcode_t op); - void FCMEQ(SPUThread& spu, spu_opcode_t op); - void FI(SPUThread& spu, spu_opcode_t op); - void CFLTS(SPUThread& spu, spu_opcode_t op); - void CFLTU(SPUThread& spu, spu_opcode_t op); - void CSFLT(SPUThread& spu, spu_opcode_t op); - void CUFLT(SPUThread& spu, spu_opcode_t op); - void FNMS(SPUThread& spu, spu_opcode_t op); - void FMA(SPUThread& spu, spu_opcode_t op); - void FMS(SPUThread& spu, spu_opcode_t op); - } -} +struct spu_interpreter_precise final : spu_interpreter +{ + static void FREST(SPUThread&, spu_opcode_t); + static void FRSQEST(SPUThread&, spu_opcode_t); + static void FCGT(SPUThread&, spu_opcode_t); + static void FA(SPUThread&, spu_opcode_t); + static void FS(SPUThread&, spu_opcode_t); + static void FM(SPUThread&, spu_opcode_t); + static void FCMGT(SPUThread&, spu_opcode_t); + static void DFA(SPUThread&, spu_opcode_t); + static void DFS(SPUThread&, spu_opcode_t); + static void DFM(SPUThread&, spu_opcode_t); + static void DFMA(SPUThread&, spu_opcode_t); + static void DFMS(SPUThread&, spu_opcode_t); + static void DFNMS(SPUThread&, spu_opcode_t); + static void DFNMA(SPUThread&, spu_opcode_t); + static void FSCRRD(SPUThread&, spu_opcode_t); + static void FESD(SPUThread&, spu_opcode_t); + static void FRDS(SPUThread&, spu_opcode_t); + static void FSCRWR(SPUThread&, spu_opcode_t); + static void FCEQ(SPUThread&, spu_opcode_t); + static void FCMEQ(SPUThread&, spu_opcode_t); + static void FI(SPUThread&, spu_opcode_t); + static void CFLTS(SPUThread&, spu_opcode_t); + static void CFLTU(SPUThread&, spu_opcode_t); + static void CSFLT(SPUThread&, spu_opcode_t); + static void CUFLT(SPUThread&, spu_opcode_t); + static void FNMS(SPUThread&, spu_opcode_t); + static void FMA(SPUThread&, spu_opcode_t); + static void FMS(SPUThread&, spu_opcode_t); +}; diff --git a/rpcs3/Emu/Cell/SPUOpcodes.h b/rpcs3/Emu/Cell/SPUOpcodes.h index 25c02fb604..e3f3618f71 100644 --- a/rpcs3/Emu/Cell/SPUOpcodes.h +++ b/rpcs3/Emu/Cell/SPUOpcodes.h @@ -1,5 +1,7 @@ #pragma once +#include "../../../Utilities/BitField.h" + union spu_opcode_t { u32 opcode; @@ -23,246 +25,6 @@ union spu_opcode_t bf_t i18; // 7..24 }; -#define DEFINE_SPU_OPCODES(ns) { \ - { 10, 0x0, ns STOP }, \ - { 10, 0x1, ns LNOP }, \ - { 10, 0x2, ns SYNC }, \ - { 10, 0x3, ns DSYNC }, \ - { 10, 0xc, ns MFSPR }, \ - { 10, 0xd, ns RDCH }, \ - { 10, 0xf, ns RCHCNT }, \ - { 10, 0x40, ns SF }, \ - { 10, 0x41, ns OR }, \ - { 10, 0x42, ns BG }, \ - { 10, 0x48, ns SFH }, \ - { 10, 0x49, ns NOR }, \ - { 10, 0x53, ns ABSDB }, \ - { 10, 0x58, ns ROT }, \ - { 10, 0x59, ns ROTM }, \ - { 10, 0x5a, ns ROTMA }, \ - { 10, 0x5b, ns SHL }, \ - { 10, 0x5c, ns ROTH }, \ - { 10, 0x5d, ns ROTHM }, \ - { 10, 0x5e, ns ROTMAH }, \ - { 10, 0x5f, ns SHLH }, \ - { 10, 0x78, ns ROTI }, \ - { 10, 0x79, ns ROTMI }, \ - { 10, 0x7a, ns ROTMAI }, \ - { 10, 0x7b, ns SHLI }, \ - { 10, 0x7c, ns ROTHI }, \ - { 10, 0x7d, ns ROTHMI }, \ - { 10, 0x7e, ns ROTMAHI }, \ - { 10, 0x7f, ns SHLHI }, \ - { 10, 0xc0, ns A }, \ - { 10, 0xc1, ns AND }, \ - { 10, 0xc2, ns CG }, \ - { 10, 0xc8, ns AH }, \ - { 10, 0xc9, ns NAND }, \ - { 10, 0xd3, ns AVGB }, \ - { 10, 0x10c, ns MTSPR }, \ - { 10, 0x10d, ns WRCH }, \ - { 10, 0x128, ns BIZ }, \ - { 10, 0x129, ns BINZ }, \ - { 10, 0x12a, ns BIHZ }, \ - { 10, 0x12b, ns BIHNZ }, \ - { 10, 0x140, ns STOPD }, \ - { 10, 0x144, ns STQX }, \ - { 10, 0x1a8, ns BI }, \ - { 10, 0x1a9, ns BISL }, \ - { 10, 0x1aa, ns IRET }, \ - { 10, 0x1ab, ns BISLED }, \ - { 10, 0x1ac, ns HBR }, \ - { 10, 0x1b0, ns GB }, \ - { 10, 0x1b1, ns GBH }, \ - { 10, 0x1b2, ns GBB }, \ - { 10, 0x1b4, ns FSM }, \ - { 10, 0x1b5, ns FSMH }, \ - { 10, 0x1b6, ns FSMB }, \ - { 10, 0x1b8, ns FREST }, \ - { 10, 0x1b9, ns FRSQEST }, \ - { 10, 0x1c4, ns LQX }, \ - { 10, 0x1cc, ns ROTQBYBI }, \ - { 10, 0x1cd, ns ROTQMBYBI }, \ - { 10, 0x1cf, ns SHLQBYBI }, \ - { 10, 0x1d4, ns CBX }, \ - { 10, 0x1d5, ns CHX }, \ - { 10, 0x1d6, ns CWX }, \ - { 10, 0x1d7, ns CDX }, \ - { 10, 0x1d8, ns ROTQBI }, \ - { 10, 0x1d9, ns ROTQMBI }, \ - { 10, 0x1db, ns SHLQBI }, \ - { 10, 0x1dc, ns ROTQBY }, \ - { 10, 0x1dd, ns ROTQMBY }, \ - { 10, 0x1df, ns SHLQBY }, \ - { 10, 0x1f0, ns ORX }, \ - { 10, 0x1f4, ns CBD }, \ - { 10, 0x1f5, ns CHD }, \ - { 10, 0x1f6, ns CWD }, \ - { 10, 0x1f7, ns CDD }, \ - { 10, 0x1f8, ns ROTQBII }, \ - { 10, 0x1f9, ns ROTQMBII }, \ - { 10, 0x1fb, ns SHLQBII }, \ - { 10, 0x1fc, ns ROTQBYI }, \ - { 10, 0x1fd, ns ROTQMBYI }, \ - { 10, 0x1ff, ns SHLQBYI }, \ - { 10, 0x201, ns NOP }, \ - { 10, 0x240, ns CGT }, \ - { 10, 0x241, ns XOR }, \ - { 10, 0x248, ns CGTH }, \ - { 10, 0x249, ns EQV }, \ - { 10, 0x250, ns CGTB }, \ - { 10, 0x253, ns SUMB }, \ - { 10, 0x258, ns HGT }, \ - { 10, 0x2a5, ns CLZ }, \ - { 10, 0x2a6, ns XSWD }, \ - { 10, 0x2ae, ns XSHW }, \ - { 10, 0x2b4, ns CNTB }, \ - { 10, 0x2b6, ns XSBH }, \ - { 10, 0x2c0, ns CLGT }, \ - { 10, 0x2c1, ns ANDC }, \ - { 10, 0x2c2, ns FCGT }, \ - { 10, 0x2c3, ns DFCGT }, \ - { 10, 0x2c4, ns FA }, \ - { 10, 0x2c5, ns FS }, \ - { 10, 0x2c6, ns FM }, \ - { 10, 0x2c8, ns CLGTH }, \ - { 10, 0x2c9, ns ORC }, \ - { 10, 0x2ca, ns FCMGT }, \ - { 10, 0x2cb, ns DFCMGT }, \ - { 10, 0x2cc, ns DFA }, \ - { 10, 0x2cd, ns DFS }, \ - { 10, 0x2ce, ns DFM }, \ - { 10, 0x2d0, ns CLGTB }, \ - { 10, 0x2d8, ns HLGT }, \ - { 10, 0x35c, ns DFMA }, \ - { 10, 0x35d, ns DFMS }, \ - { 10, 0x35e, ns DFNMS }, \ - { 10, 0x35f, ns DFNMA }, \ - { 10, 0x3c0, ns CEQ }, \ - { 10, 0x3ce, ns MPYHHU }, \ - { 10, 0x340, ns ADDX }, \ - { 10, 0x341, ns SFX }, \ - { 10, 0x342, ns CGX }, \ - { 10, 0x343, ns BGX }, \ - { 10, 0x346, ns MPYHHA }, \ - { 10, 0x34e, ns MPYHHAU }, \ - { 10, 0x398, ns FSCRRD }, \ - { 10, 0x3b8, ns FESD }, \ - { 10, 0x3b9, ns FRDS }, \ - { 10, 0x3ba, ns FSCRWR }, \ - { 10, 0x3bf, ns DFTSV }, \ - { 10, 0x3c2, ns FCEQ }, \ - { 10, 0x3c3, ns DFCEQ }, \ - { 10, 0x3c4, ns MPY }, \ - { 10, 0x3c5, ns MPYH }, \ - { 10, 0x3c6, ns MPYHH }, \ - { 10, 0x3c7, ns MPYS }, \ - { 10, 0x3c8, ns CEQH }, \ - { 10, 0x3ca, ns FCMEQ }, \ - { 10, 0x3cb, ns DFCMEQ }, \ - { 10, 0x3cc, ns MPYU }, \ - { 10, 0x3d0, ns CEQB }, \ - { 10, 0x3d4, ns FI }, \ - { 10, 0x3d8, ns HEQ }, \ - { 9, 0x1d8, ns CFLTS }, \ - { 9, 0x1d9, ns CFLTU }, \ - { 9, 0x1da, ns CSFLT }, \ - { 9, 0x1db, ns CUFLT }, \ - { 8, 0x40, ns BRZ }, \ - { 8, 0x41, ns STQA }, \ - { 8, 0x42, ns BRNZ }, \ - { 8, 0x44, ns BRHZ }, \ - { 8, 0x46, ns BRHNZ }, \ - { 8, 0x47, ns STQR }, \ - { 8, 0x60, ns BRA }, \ - { 8, 0x61, ns LQA }, \ - { 8, 0x62, ns BRASL }, \ - { 8, 0x64, ns BR }, \ - { 8, 0x65, ns FSMBI }, \ - { 8, 0x66, ns BRSL }, \ - { 8, 0x67, ns LQR }, \ - { 8, 0x81, ns IL }, \ - { 8, 0x82, ns ILHU }, \ - { 8, 0x83, ns ILH }, \ - { 8, 0xc1, ns IOHL }, \ - { 7, 0x4, ns ORI }, \ - { 7, 0x5, ns ORHI }, \ - { 7, 0x6, ns ORBI }, \ - { 7, 0xc, ns SFI }, \ - { 7, 0xd, ns SFHI }, \ - { 7, 0x14, ns ANDI }, \ - { 7, 0x15, ns ANDHI }, \ - { 7, 0x16, ns ANDBI }, \ - { 7, 0x1c, ns AI }, \ - { 7, 0x1d, ns AHI }, \ - { 7, 0x24, ns STQD }, \ - { 7, 0x34, ns LQD }, \ - { 7, 0x44, ns XORI }, \ - { 7, 0x45, ns XORHI }, \ - { 7, 0x46, ns XORBI }, \ - { 7, 0x4c, ns CGTI }, \ - { 7, 0x4d, ns CGTHI }, \ - { 7, 0x4e, ns CGTBI }, \ - { 7, 0x4f, ns HGTI }, \ - { 7, 0x5c, ns CLGTI }, \ - { 7, 0x5d, ns CLGTHI }, \ - { 7, 0x5e, ns CLGTBI }, \ - { 7, 0x5f, ns HLGTI }, \ - { 7, 0x74, ns MPYI }, \ - { 7, 0x75, ns MPYUI }, \ - { 7, 0x7c, ns CEQI }, \ - { 7, 0x7d, ns CEQHI }, \ - { 7, 0x7e, ns CEQBI }, \ - { 7, 0x7f, ns HEQI }, \ - { 6, 0x8, ns HBRA }, \ - { 6, 0x9, ns HBRR }, \ - { 6, 0x21, ns ILA }, \ - { 3, 0x8, ns SELB }, \ - { 3, 0xb, ns SHUFB }, \ - { 3, 0xc, ns MPYA }, \ - { 3, 0xd, ns FNMS }, \ - { 3, 0xe, ns FMA }, \ - { 3, 0xf, ns FMS }, \ -} - -template class spu_opcode_table_t -{ - std::array m_data; - - struct opcode_entry_t - { - u32 group; - u32 value; - T pointer; - }; - -public: - // opcode table initialization (TODO: optimize it a bit) - spu_opcode_table_t(std::initializer_list opcodes, T default_value = {}) - { - for (u32 i = 0; i < 2048; i++) - { - m_data[i] = default_value; - - for (auto& op : opcodes) - { - if (((i << 21) & (INT_MIN >> op.group)) == (op.value << (31 - op.group))) - { - m_data[i] = op.pointer; - break; - } - } - } - } - - // access opcode table - T operator [](u32 opcode_data) const - { - // the whole decoding process is shifting opcode data - return m_data[opcode_data >> 21]; - } -}; - inline u32 spu_branch_target(u32 pc, u32 imm = 0) { return (pc + (imm << 2)) & 0x3fffc; @@ -272,3 +34,250 @@ inline u32 spu_ls_target(u32 pc, u32 imm = 0) { return (pc + (imm << 2)) & 0x3fff0; } + +static u32 spu_decode(u32 inst) +{ + return inst >> 21; +} + +// SPU decoder object. D provides functions. T is function pointer type returned. +template +class spu_decoder +{ + // Fast lookup table + std::array m_table; + + struct instruction_info + { + u32 magn; // Count = 2 ^ magn + u32 value; + T pointer; + }; + +public: + spu_decoder() + { + const std::initializer_list instructions + { + { 0, 0x0, &D::STOP }, + { 0, 0x1, &D::LNOP }, + { 0, 0x2, &D::SYNC }, + { 0, 0x3, &D::DSYNC }, + { 0, 0xc, &D::MFSPR }, + { 0, 0xd, &D::RDCH }, + { 0, 0xf, &D::RCHCNT }, + { 0, 0x40, &D::SF }, + { 0, 0x41, &D::OR }, + { 0, 0x42, &D::BG }, + { 0, 0x48, &D::SFH }, + { 0, 0x49, &D::NOR }, + { 0, 0x53, &D::ABSDB }, + { 0, 0x58, &D::ROT }, + { 0, 0x59, &D::ROTM }, + { 0, 0x5a, &D::ROTMA }, + { 0, 0x5b, &D::SHL }, + { 0, 0x5c, &D::ROTH }, + { 0, 0x5d, &D::ROTHM }, + { 0, 0x5e, &D::ROTMAH }, + { 0, 0x5f, &D::SHLH }, + { 0, 0x78, &D::ROTI }, + { 0, 0x79, &D::ROTMI }, + { 0, 0x7a, &D::ROTMAI }, + { 0, 0x7b, &D::SHLI }, + { 0, 0x7c, &D::ROTHI }, + { 0, 0x7d, &D::ROTHMI }, + { 0, 0x7e, &D::ROTMAHI }, + { 0, 0x7f, &D::SHLHI }, + { 0, 0xc0, &D::A }, + { 0, 0xc1, &D::AND }, + { 0, 0xc2, &D::CG }, + { 0, 0xc8, &D::AH }, + { 0, 0xc9, &D::NAND }, + { 0, 0xd3, &D::AVGB }, + { 0, 0x10c, &D::MTSPR }, + { 0, 0x10d, &D::WRCH }, + { 0, 0x128, &D::BIZ }, + { 0, 0x129, &D::BINZ }, + { 0, 0x12a, &D::BIHZ }, + { 0, 0x12b, &D::BIHNZ }, + { 0, 0x140, &D::STOPD }, + { 0, 0x144, &D::STQX }, + { 0, 0x1a8, &D::BI }, + { 0, 0x1a9, &D::BISL }, + { 0, 0x1aa, &D::IRET }, + { 0, 0x1ab, &D::BISLED }, + { 0, 0x1ac, &D::HBR }, + { 0, 0x1b0, &D::GB }, + { 0, 0x1b1, &D::GBH }, + { 0, 0x1b2, &D::GBB }, + { 0, 0x1b4, &D::FSM }, + { 0, 0x1b5, &D::FSMH }, + { 0, 0x1b6, &D::FSMB }, + { 0, 0x1b8, &D::FREST }, + { 0, 0x1b9, &D::FRSQEST }, + { 0, 0x1c4, &D::LQX }, + { 0, 0x1cc, &D::ROTQBYBI }, + { 0, 0x1cd, &D::ROTQMBYBI }, + { 0, 0x1cf, &D::SHLQBYBI }, + { 0, 0x1d4, &D::CBX }, + { 0, 0x1d5, &D::CHX }, + { 0, 0x1d6, &D::CWX }, + { 0, 0x1d7, &D::CDX }, + { 0, 0x1d8, &D::ROTQBI }, + { 0, 0x1d9, &D::ROTQMBI }, + { 0, 0x1db, &D::SHLQBI }, + { 0, 0x1dc, &D::ROTQBY }, + { 0, 0x1dd, &D::ROTQMBY }, + { 0, 0x1df, &D::SHLQBY }, + { 0, 0x1f0, &D::ORX }, + { 0, 0x1f4, &D::CBD }, + { 0, 0x1f5, &D::CHD }, + { 0, 0x1f6, &D::CWD }, + { 0, 0x1f7, &D::CDD }, + { 0, 0x1f8, &D::ROTQBII }, + { 0, 0x1f9, &D::ROTQMBII }, + { 0, 0x1fb, &D::SHLQBII }, + { 0, 0x1fc, &D::ROTQBYI }, + { 0, 0x1fd, &D::ROTQMBYI }, + { 0, 0x1ff, &D::SHLQBYI }, + { 0, 0x201, &D::NOP }, + { 0, 0x240, &D::CGT }, + { 0, 0x241, &D::XOR }, + { 0, 0x248, &D::CGTH }, + { 0, 0x249, &D::EQV }, + { 0, 0x250, &D::CGTB }, + { 0, 0x253, &D::SUMB }, + { 0, 0x258, &D::HGT }, + { 0, 0x2a5, &D::CLZ }, + { 0, 0x2a6, &D::XSWD }, + { 0, 0x2ae, &D::XSHW }, + { 0, 0x2b4, &D::CNTB }, + { 0, 0x2b6, &D::XSBH }, + { 0, 0x2c0, &D::CLGT }, + { 0, 0x2c1, &D::ANDC }, + { 0, 0x2c2, &D::FCGT }, + { 0, 0x2c3, &D::DFCGT }, + { 0, 0x2c4, &D::FA }, + { 0, 0x2c5, &D::FS }, + { 0, 0x2c6, &D::FM }, + { 0, 0x2c8, &D::CLGTH }, + { 0, 0x2c9, &D::ORC }, + { 0, 0x2ca, &D::FCMGT }, + { 0, 0x2cb, &D::DFCMGT }, + { 0, 0x2cc, &D::DFA }, + { 0, 0x2cd, &D::DFS }, + { 0, 0x2ce, &D::DFM }, + { 0, 0x2d0, &D::CLGTB }, + { 0, 0x2d8, &D::HLGT }, + { 0, 0x35c, &D::DFMA }, + { 0, 0x35d, &D::DFMS }, + { 0, 0x35e, &D::DFNMS }, + { 0, 0x35f, &D::DFNMA }, + { 0, 0x3c0, &D::CEQ }, + { 0, 0x3ce, &D::MPYHHU }, + { 0, 0x340, &D::ADDX }, + { 0, 0x341, &D::SFX }, + { 0, 0x342, &D::CGX }, + { 0, 0x343, &D::BGX }, + { 0, 0x346, &D::MPYHHA }, + { 0, 0x34e, &D::MPYHHAU }, + { 0, 0x398, &D::FSCRRD }, + { 0, 0x3b8, &D::FESD }, + { 0, 0x3b9, &D::FRDS }, + { 0, 0x3ba, &D::FSCRWR }, + { 0, 0x3bf, &D::DFTSV }, + { 0, 0x3c2, &D::FCEQ }, + { 0, 0x3c3, &D::DFCEQ }, + { 0, 0x3c4, &D::MPY }, + { 0, 0x3c5, &D::MPYH }, + { 0, 0x3c6, &D::MPYHH }, + { 0, 0x3c7, &D::MPYS }, + { 0, 0x3c8, &D::CEQH }, + { 0, 0x3ca, &D::FCMEQ }, + { 0, 0x3cb, &D::DFCMEQ }, + { 0, 0x3cc, &D::MPYU }, + { 0, 0x3d0, &D::CEQB }, + { 0, 0x3d4, &D::FI }, + { 0, 0x3d8, &D::HEQ }, + { 1, 0x1d8, &D::CFLTS }, + { 1, 0x1d9, &D::CFLTU }, + { 1, 0x1da, &D::CSFLT }, + { 1, 0x1db, &D::CUFLT }, + { 2, 0x40, &D::BRZ }, + { 2, 0x41, &D::STQA }, + { 2, 0x42, &D::BRNZ }, + { 2, 0x44, &D::BRHZ }, + { 2, 0x46, &D::BRHNZ }, + { 2, 0x47, &D::STQR }, + { 2, 0x60, &D::BRA }, + { 2, 0x61, &D::LQA }, + { 2, 0x62, &D::BRASL }, + { 2, 0x64, &D::BR }, + { 2, 0x65, &D::FSMBI }, + { 2, 0x66, &D::BRSL }, + { 2, 0x67, &D::LQR }, + { 2, 0x81, &D::IL }, + { 2, 0x82, &D::ILHU }, + { 2, 0x83, &D::ILH }, + { 2, 0xc1, &D::IOHL }, + { 3, 0x4, &D::ORI }, + { 3, 0x5, &D::ORHI }, + { 3, 0x6, &D::ORBI }, + { 3, 0xc, &D::SFI }, + { 3, 0xd, &D::SFHI }, + { 3, 0x14, &D::ANDI }, + { 3, 0x15, &D::ANDHI }, + { 3, 0x16, &D::ANDBI }, + { 3, 0x1c, &D::AI }, + { 3, 0x1d, &D::AHI }, + { 3, 0x24, &D::STQD }, + { 3, 0x34, &D::LQD }, + { 3, 0x44, &D::XORI }, + { 3, 0x45, &D::XORHI }, + { 3, 0x46, &D::XORBI }, + { 3, 0x4c, &D::CGTI }, + { 3, 0x4d, &D::CGTHI }, + { 3, 0x4e, &D::CGTBI }, + { 3, 0x4f, &D::HGTI }, + { 3, 0x5c, &D::CLGTI }, + { 3, 0x5d, &D::CLGTHI }, + { 3, 0x5e, &D::CLGTBI }, + { 3, 0x5f, &D::HLGTI }, + { 3, 0x74, &D::MPYI }, + { 3, 0x75, &D::MPYUI }, + { 3, 0x7c, &D::CEQI }, + { 3, 0x7d, &D::CEQHI }, + { 3, 0x7e, &D::CEQBI }, + { 3, 0x7f, &D::HEQI }, + { 4, 0x8, &D::HBRA }, + { 4, 0x9, &D::HBRR }, + { 4, 0x21, &D::ILA }, + { 7, 0x8, &D::SELB }, + { 7, 0xb, &D::SHUFB }, + { 7, 0xc, &D::MPYA }, + { 7, 0xd, &D::FNMS }, + { 7, 0xe, &D::FMA }, + { 7, 0xf, &D::FMS }, + }; + + m_table.fill(&D::UNK); + + for (auto& entry : instructions) + { + for (u32 i = 0; i < 1u << entry.magn; i++) + { + m_table[entry.value << entry.magn | i] = entry.pointer; + } + } + } + + const std::array& get_table() const + { + return m_table; + } + + T decode(u32 inst) const + { + return m_table[spu_decode(inst)]; + } +}; diff --git a/rpcs3/Emu/Cell/SPURecompiler.cpp b/rpcs3/Emu/Cell/SPURecompiler.cpp index c490b187ea..b6e635bfb2 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.cpp +++ b/rpcs3/Emu/Cell/SPURecompiler.cpp @@ -8,39 +8,36 @@ extern u64 get_system_time(); -SPURecompilerDecoder::SPURecompilerDecoder(SPUThread& spu) - : db(fxm::get_always()) - , rec(fxm::get_always()) - , spu(spu) +void spu_recompiler_base::enter(SPUThread& spu) { -} - -u32 SPURecompilerDecoder::DecodeMemory(const u32 address) -{ - if (spu.offset != address - spu.pc || spu.pc >= 0x40000 || spu.pc % 4) + if (spu.pc >= 0x40000 || spu.pc % 4) { - throw EXCEPTION("Invalid address or PC (address=0x%x, PC=0x%05x)", address, spu.pc); + throw fmt::exception("Invalid PC: 0x%05x", spu.pc); } - // get SPU LS pointer + // Get SPU LS pointer const auto _ls = vm::ps3::_ptr(spu.offset); - // always validate (TODO) - const auto func = db->analyse(_ls, spu.pc); + // Always validate (TODO) + const auto func = spu.spu_db->analyse(_ls, spu.pc); - // reset callstack if necessary + // Reset callstack if necessary if (func->does_reset_stack && spu.recursion_level) { - spu.m_state |= CPU_STATE_RETURN; - - return 0; + spu.state += cpu_state::ret; + return; } if (!func->compiled) { - rec->compile(*func); + if (!spu.spu_rec) + { + spu.spu_rec = fxm::get_always(); + } - if (!func->compiled) throw EXCEPTION("Compilation failed"); + spu.spu_rec->compile(*func); + + if (!func->compiled) throw std::runtime_error("Compilation failed" HERE); } const u32 res = func->compiled(&spu, _ls); @@ -64,7 +61,7 @@ u32 SPURecompilerDecoder::DecodeMemory(const u32 address) { if (res & 0x8000000) { - throw EXCEPTION("Undefined behaviour"); + throw std::logic_error("Invalid interrupt status set" HERE); } spu.set_interrupt_status(true); @@ -75,6 +72,4 @@ u32 SPURecompilerDecoder::DecodeMemory(const u32 address) } spu.pc = res & 0x3fffc; - - return 0; } diff --git a/rpcs3/Emu/Cell/SPURecompiler.h b/rpcs3/Emu/Cell/SPURecompiler.h index 5ef15efc55..ed9b9aae64 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.h +++ b/rpcs3/Emu/Cell/SPURecompiler.h @@ -1,12 +1,9 @@ #pragma once -#include "Emu/CPU/CPUDecoder.h" #include "SPUAnalyser.h" -class SPUThread; - // SPU Recompiler instance base (must be global or PS3 process-local) -class SPURecompilerBase +class spu_recompiler_base { protected: std::mutex m_mutex; // must be locked in compile() @@ -16,21 +13,11 @@ protected: u32 m_pos; // current position public: - virtual void compile(spu_function_t& f) = 0; // compile specified function - virtual ~SPURecompilerBase() {}; -}; - -// SPU Decoder instance (created per SPU thread) -class SPURecompilerDecoder final : public CPUDecoder -{ -public: - const std::shared_ptr db; // associated SPU Analyser instance - - const std::shared_ptr rec; // assiciated SPU Recompiler instance - - SPUThread& spu; // associated SPU Thread - - SPURecompilerDecoder(SPUThread& spu); - - u32 DecodeMemory(const u32 address) override; // non-virtual override (to avoid virtual call whenever possible) + virtual ~spu_recompiler_base() = default; + + // Compile specified function + virtual void compile(spu_function_t& f) = 0; + + // Run + static void enter(class SPUThread&); }; diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 5c92fae5f5..9bb9fdc4b6 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1,15 +1,15 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" #include "Emu/IdManager.h" #include "Emu/Cell/PPUThread.h" -#include "Emu/SysCalls/ErrorCodes.h" -#include "Emu/SysCalls/lv2/sys_spu.h" -#include "Emu/SysCalls/lv2/sys_event_flag.h" -#include "Emu/SysCalls/lv2/sys_event.h" -#include "Emu/SysCalls/lv2/sys_interrupt.h" +#include "Emu/Cell/ErrorCodes.h" +#include "Emu/Cell/lv2/sys_spu.h" +#include "Emu/Cell/lv2/sys_event_flag.h" +#include "Emu/Cell/lv2/sys_event.h" +#include "Emu/Cell/lv2/sys_interrupt.h" #include "Emu/Cell/SPUDisAsm.h" #include "Emu/Cell/SPUThread.h" @@ -20,8 +20,24 @@ extern u64 get_timebased_time(); -// defined here since SPUDisAsm.cpp doesn't exist -const spu_opcode_table_t SPUDisAsm::opcodes{ DEFINE_SPU_OPCODES(&SPUDisAsm::), &SPUDisAsm::UNK }; +enum class spu_decoder_type +{ + precise, + fast, + asmjit, + llvm, +}; + +cfg::map_entry g_cfg_spu_decoder(cfg::root.core, "SPU Decoder", 2, +{ + { "Interpreter (precise)", spu_decoder_type::precise }, + { "Interpreter (fast)", spu_decoder_type::fast }, + { "Recompiler (ASMJIT)", spu_decoder_type::asmjit }, + { "Recompiler (LLVM)", spu_decoder_type::llvm }, +}); + +const spu_decoder s_spu_interpreter_precise; +const spu_decoder s_spu_interpreter_fast; thread_local bool spu_channel_t::notification_required; @@ -31,7 +47,7 @@ void spu_int_ctrl_t::set(u64 ints) ints &= mask; // notify if at least 1 bit was set - if (ints && ~stat._or(ints) & ints && tag) + if (ints && ~stat.fetch_or(ints) & ints && tag) { LV2_LOCK; @@ -44,112 +60,23 @@ void spu_int_ctrl_t::set(u64 ints) } } -void spu_int_ctrl_t::clear(u64 ints) -{ - stat &= ~ints; -} - const spu_imm_table_t g_spu_imm; -SPUThread::SPUThread(CPUThreadType type, const std::string& name, u32 index, u32 offset) - : CPUThread(type, name) - , index(index) - , offset(offset) -{ -} - -SPUThread::SPUThread(const std::string& name, u32 index) - : CPUThread(CPU_THREAD_SPU, name) - , index(index) - , offset(vm::alloc(0x40000, vm::main)) -{ - CHECK_ASSERTION(offset); -} - -SPUThread::~SPUThread() -{ - // Deallocate Local Storage - vm::dealloc_verbose_nothrow(offset); -} - -bool SPUThread::is_paused() const -{ - if (CPUThread::is_paused()) - { - return true; - } - - if (const auto group = tg.lock()) - { - if (group->state >= SPU_THREAD_GROUP_STATUS_WAITING && group->state <= SPU_THREAD_GROUP_STATUS_SUSPENDED) - { - return true; - } - } - - return false; -} - std::string SPUThread::get_name() const { - return fmt::format("%s[0x%x] Thread (%s)[0x%05x]", CPUThread::GetTypeString(), m_id, CPUThread::get_name(), pc); + return fmt::format("%sSPU[0x%x] Thread (%s)", offset > RAW_SPU_BASE_ADDR ? "Raw" : "", id, name); } -void SPUThread::dump_info() const +std::string SPUThread::dump() const { - CPUThread::dump_info(); + std::string ret = "Registers:\n=========\n"; + + for (uint i = 0; i<128; ++i) ret += fmt::format("GPR[%d] = 0x%s\n", i, gpr[i].to_hex().c_str()); + + return ret; } -void SPUThread::cpu_task() -{ - std::fesetround(FE_TOWARDZERO); - - if (!custom_task && !m_dec) - { - // Select opcode table (TODO) - const auto& table = rpcs3::state.config.core.spu_decoder.value() == spu_decoder_type::interpreter_precise ? spu_interpreter::precise::g_spu_opcode_table : spu_interpreter::fast::g_spu_opcode_table; - - // LS base address - const auto base = vm::_ptr(offset); - - while (true) - { - if (!m_state) - { - // read opcode - const u32 opcode = base[pc / 4]; - - // call interpreter function - table[opcode](*this, { opcode }); - - // next instruction - pc += 4; - - continue; - } - - if (check_status()) - { - return; - } - } - } - - if (custom_task) - { - if (check_status()) return; - - return custom_task(*this); - } - - while (!m_state || !check_status()) - { - // decode instruction using specified decoder - pc += m_dec->DecodeMemory(pc + offset); - } -} - -void SPUThread::init_regs() +void SPUThread::cpu_init() { gpr = {}; fpscr.Reset(); @@ -190,75 +117,96 @@ void SPUThread::init_regs() gpr[1]._u32[3] = 0x3FFF0; // initial stack frame pointer } -void SPUThread::init_stack() +void SPUThread::cpu_task() { - // nothing to do -} + std::fesetround(FE_TOWARDZERO); -void SPUThread::close_stack() -{ - // nothing to do here -} - -void SPUThread::do_run() -{ - m_dec.reset(); - - switch (auto mode = rpcs3::state.config.core.spu_decoder.value()) + if (custom_task) { - case spu_decoder_type::interpreter_precise: // Interpreter 1 (Precise) - case spu_decoder_type::interpreter_fast: // Interpreter 2 (Fast) - { - break; + if (check_status()) return; + + return custom_task(*this); } - case spu_decoder_type::recompiler_asmjit: + _log::g_tls_make_prefix = [](const auto&, auto, const auto&) { - m_dec.reset(new SPURecompilerDecoder(*this)); - break; + const auto cpu = static_cast(get_current_cpu_thread()); + + return fmt::format("%s [0x%05x]", cpu->get_name(), cpu->pc); + }; + + if (g_cfg_spu_decoder.get() == spu_decoder_type::asmjit) + { + if (!spu_db) spu_db = fxm::get_always(); + return spu_recompiler_base::enter(*this); } - default: + // Select opcode table + const auto& table = *( + g_cfg_spu_decoder.get() == spu_decoder_type::precise ? &s_spu_interpreter_precise.get_table() : + g_cfg_spu_decoder.get() == spu_decoder_type::fast ? &s_spu_interpreter_fast.get_table() : + throw std::logic_error("Invalid SPU decoder")); + + // LS base address + const auto base = vm::_ptr(offset); + + while (true) { - LOG_ERROR(SPU, "Invalid SPU decoder mode: %d", (u8)mode); - Emu.Pause(); - } + if (!state.load()) + { + // Read opcode + const u32 op = base[pc / 4]; + + // Call interpreter function + table[spu_decode(op)](*this, { op }); + + // Next instruction + pc += 4; + continue; + } + + if (check_status()) return; } } -void SPUThread::fast_call(u32 ls_addr) +SPUThread::SPUThread(const std::string & name, u32 index) + : cpu_thread(cpu_type::spu, name) + , index(index) + , offset(vm::alloc(0x40000, vm::main)) { - if (!is_current()) + Ensures(offset); +} + +SPUThread::~SPUThread() +{ + // Deallocate Local Storage + vm::dealloc_verbose_nothrow(offset); +} + +void SPUThread::push_snr(u32 number, u32 value) +{ + // get channel + const auto channel = + number == 0 ? &ch_snr1 : + number == 1 ? &ch_snr2 : throw EXCEPTION("Unexpected"); + + // check corresponding SNR register settings + if ((snr_config >> number) & 1) { - throw EXCEPTION("Called from the wrong thread"); + channel->push_or(value); + } + else + { + channel->push(value); } - // LS:0x0: this is originally the entry point of the interrupt handler, but interrupts are not implemented - _ref(0) = 0x00000002; // STOP 2 - - auto old_pc = pc; - auto old_lr = gpr[0]._u32[3]; - auto old_stack = gpr[1]._u32[3]; // only saved and restored (may be wrong) - auto old_task = std::move(custom_task); - - pc = ls_addr; - gpr[0]._u32[3] = 0x0; - custom_task = nullptr; - - try + if (channel->notification_required) { - cpu_task(); - } - catch (CPUThreadReturn) - { - } + // lock for reliable notification + std::lock_guard lock(mutex); - m_state &= ~CPU_STATE_RETURN; - - pc = old_pc; - gpr[0]._u32[3] = old_lr; - gpr[1]._u32[3] = old_stack; - custom_task = std::move(old_task); + cv.notify_one(); + } } void SPUThread::do_dma_transfer(u32 cmd, spu_mfc_arg_t args) @@ -268,9 +216,9 @@ void SPUThread::do_dma_transfer(u32 cmd, spu_mfc_arg_t args) _mm_mfence(); } - u32 eal = VM_CAST(args.ea); + u32 eal = vm::cast(args.ea, HERE); - if (eal >= SYS_SPU_THREAD_BASE_LOW && m_type == CPU_THREAD_SPU) // SPU Thread Group MMIO (LS and SNR) + if (eal >= SYS_SPU_THREAD_BASE_LOW && offset >= RAW_SPU_BASE_ADDR) // SPU Thread Group MMIO (LS and SNR) { const u32 index = (eal - SYS_SPU_THREAD_BASE_LOW) / SYS_SPU_THREAD_OFFSET; // thread number in group const u32 offset = (eal - SYS_SPU_THREAD_BASE_LOW) % SYS_SPU_THREAD_OFFSET; // LS offset or MMIO register @@ -413,7 +361,7 @@ void SPUThread::process_mfc_cmd(u32 cmd) break; } - const u32 raddr = VM_CAST(ch_mfc_args.ea); + const u32 raddr = vm::cast(ch_mfc_args.ea, HERE); vm::reservation_acquire(vm::base(offset + ch_mfc_args.lsa), raddr, 128); @@ -434,7 +382,7 @@ void SPUThread::process_mfc_cmd(u32 cmd) break; } - if (vm::reservation_update(VM_CAST(ch_mfc_args.ea), vm::base(offset + ch_mfc_args.lsa), 128)) + if (vm::reservation_update(vm::cast(ch_mfc_args.ea, HERE), vm::base(offset + ch_mfc_args.lsa), 128)) { if (last_raddr == 0) { @@ -466,9 +414,9 @@ void SPUThread::process_mfc_cmd(u32 cmd) break; } - vm::reservation_op(VM_CAST(ch_mfc_args.ea), 128, [this]() + vm::reservation_op(vm::cast(ch_mfc_args.ea, HERE), 128, [this]() { - std::memcpy(vm::base_priv(VM_CAST(ch_mfc_args.ea)), vm::base(offset + ch_mfc_args.lsa), 128); + std::memcpy(vm::base_priv(vm::cast(ch_mfc_args.ea, HERE)), vm::base(offset + ch_mfc_args.lsa), 128); }); if (last_raddr != 0 && vm::g_tls_did_break_reservation) @@ -539,7 +487,7 @@ void SPUThread::set_events(u32 mask) } // set new events, get old event mask - const u32 old_stat = ch_event_stat._or(mask); + const u32 old_stat = ch_event_stat.fetch_or(mask); // notify if some events were set if (~old_stat & mask && old_stat & SPU_EVENT_WAITING) @@ -617,7 +565,10 @@ u32 SPUThread::get_ch_value(u32 ch) CHECK_EMU_STATUS; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } if (!lock) { @@ -658,7 +609,10 @@ u32 SPUThread::get_ch_value(u32 ch) CHECK_EMU_STATUS; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } if (!lock) { @@ -723,14 +677,14 @@ u32 SPUThread::get_ch_value(u32 ch) if (ch_event_mask & SPU_EVENT_LR) { // register waiter if polling reservation status is required - vm::wait_op(*this, last_raddr, 128, WRAP_EXPR(get_events(true) || is_stopped())); + vm::wait_op(*this, last_raddr, 128, WRAP_EXPR(get_events(true) || state & cpu_state::stop)); } else { lock.lock(); // simple waiting loop otherwise - while (!get_events(true) && !is_stopped()) + while (!get_events(true) && !(state & cpu_state::stop)) { CHECK_EMU_STATUS; @@ -740,7 +694,10 @@ u32 SPUThread::get_ch_value(u32 ch) ch_event_stat &= ~SPU_EVENT_WAITING; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } return get_events(); } @@ -767,7 +724,7 @@ void SPUThread::set_ch_value(u32 ch, u32 value) // break; case SPU_WrOutIntrMbox: { - if (m_type == CPU_THREAD_RAW_SPU) + if (offset >= RAW_SPU_BASE_ADDR) { std::unique_lock lock(mutex, std::defer_lock); @@ -775,7 +732,10 @@ void SPUThread::set_ch_value(u32 ch, u32 value) { CHECK_EMU_STATUS; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } if (!lock) { @@ -824,12 +784,12 @@ void SPUThread::set_ch_value(u32 ch, u32 value) return ch_in_mbox.set_values(1, CELL_ENOTCONN); // TODO: check error passing } - if (queue->events.size() >= queue->size) + if (queue->events() >= queue->size) { return ch_in_mbox.set_values(1, CELL_EBUSY); } - queue->push(lv2_lock, SYS_SPU_THREAD_EVENT_USER_KEY, m_id, ((u64)spup << 32) | (value & 0x00ffffff), data); + queue->push(lv2_lock, SYS_SPU_THREAD_EVENT_USER_KEY, id, ((u64)spup << 32) | (value & 0x00ffffff), data); return ch_in_mbox.set_values(1, CELL_OK); } @@ -861,13 +821,13 @@ void SPUThread::set_ch_value(u32 ch, u32 value) } // TODO: check passing spup value - if (queue->events.size() >= queue->size) + if (queue->events() >= queue->size) { LOG_WARNING(SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x) failed (queue is full)", spup, (value & 0x00ffffff), data); return; } - queue->push(lv2_lock, SYS_SPU_THREAD_EVENT_USER_KEY, m_id, ((u64)spup << 32) | (value & 0x00ffffff), data); + queue->push(lv2_lock, SYS_SPU_THREAD_EVENT_USER_KEY, id, ((u64)spup << 32) | (value & 0x00ffffff), data); return; } else if (code == 128) @@ -979,7 +939,10 @@ void SPUThread::set_ch_value(u32 ch, u32 value) { CHECK_EMU_STATUS; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } if (!lock) { @@ -1136,7 +1099,7 @@ void SPUThread::stop_and_signal(u32 code) { LOG_TRACE(SPU, "stop_and_signal(code=0x%x)", code); - if (m_type == CPU_THREAD_RAW_SPU) + if (offset >= RAW_SPU_BASE_ADDR) { status.atomic_op([code](u32& status) { @@ -1146,8 +1109,7 @@ void SPUThread::stop_and_signal(u32 code) }); int_ctrl[2].set(SPU_INT2_STAT_SPU_STOP_AND_SIGNAL_INT); - - return stop(); + throw cpu_state::stop; } switch (code) @@ -1160,7 +1122,7 @@ void SPUThread::stop_and_signal(u32 code) case 0x002: { - m_state |= CPU_STATE_RETURN; + state += cpu_state::ret; return; } @@ -1241,7 +1203,10 @@ void SPUThread::stop_and_signal(u32 code) { CHECK_EMU_STATUS; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } group->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); } @@ -1253,7 +1218,10 @@ void SPUThread::stop_and_signal(u32 code) for (auto& thread : group->threads) { - if (thread) thread->sleep(); // trigger status check + if (thread) + { + thread->state += cpu_state::suspend; + } } } else @@ -1261,24 +1229,25 @@ void SPUThread::stop_and_signal(u32 code) throw EXCEPTION("Unexpected SPU Thread Group state (%d)", group->state); } - if (queue->events.size()) + if (queue->events()) { - auto& event = queue->events.front(); + const auto event = queue->pop(lv2_lock); ch_in_mbox.set_values(4, CELL_OK, static_cast(std::get<1>(event)), static_cast(std::get<2>(event)), static_cast(std::get<3>(event))); - - queue->events.pop_front(); } else { // add waiter; protocol is ignored in current implementation - sleep_queue_entry_t waiter(*this, queue->sq); + sleep_entry waiter(queue->thread_queue(lv2_lock), *this); // wait on the event queue - while (!unsignal()) + while (!state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } cv.wait(lv2_lock); } @@ -1302,9 +1271,14 @@ void SPUThread::stop_and_signal(u32 code) for (auto& thread : group->threads) { - if (thread) thread->awake(); // untrigger status check + if (thread && thread.get() != this) + { + thread->state -= cpu_state::suspend; + thread->safe_notify(); + } } + state -= cpu_state::suspend; group->cv.notify_all(); return; @@ -1338,7 +1312,8 @@ void SPUThread::stop_and_signal(u32 code) { if (thread && thread.get() != this) { - thread->stop(); + thread->state += cpu_state::stop; + thread->safe_notify(); } } @@ -1347,7 +1322,7 @@ void SPUThread::stop_and_signal(u32 code) group->join_state |= SPU_TGJSF_GROUP_EXIT; group->cv.notify_one(); - return stop(); + throw cpu_state::stop; } case 0x102: @@ -1373,7 +1348,7 @@ void SPUThread::stop_and_signal(u32 code) status |= SPU_STATUS_STOPPED_BY_STOP; group->cv.notify_one(); - return stop(); + throw cpu_state::stop; } } @@ -1391,7 +1366,7 @@ void SPUThread::halt() { LOG_TRACE(SPU, "halt()"); - if (m_type == CPU_THREAD_RAW_SPU) + if (offset >= RAW_SPU_BASE_ADDR) { status.atomic_op([](u32& status) { @@ -1401,18 +1376,41 @@ void SPUThread::halt() int_ctrl[2].set(SPU_INT2_STAT_SPU_HALT_OR_STEP_INT); - return stop(); + throw cpu_state::stop; } status |= SPU_STATUS_STOPPED_BY_HALT; throw EXCEPTION("Halt"); } -spu_thread::spu_thread(u32 entry, const std::string& name, u32 stack_size, u32 prio) +void SPUThread::fast_call(u32 ls_addr) { - auto spu = idm::make_ptr(name, 0x13370666); + // LS:0x0: this is originally the entry point of the interrupt handler, but interrupts are not implemented + _ref(0) = 0x00000002; // STOP 2 - spu->pc = entry; + auto old_pc = pc; + auto old_lr = gpr[0]._u32[3]; + auto old_stack = gpr[1]._u32[3]; // only saved and restored (may be wrong) + auto old_task = std::move(custom_task); - thread = std::move(spu); + pc = ls_addr; + gpr[0]._u32[3] = 0x0; + custom_task = nullptr; + + try + { + cpu_task(); + } + catch (cpu_state _s) + { + state += _s; + if (_s != cpu_state::ret) throw; + } + + state -= cpu_state::ret; + + pc = old_pc; + gpr[0]._u32[3] = old_lr; + gpr[1]._u32[3] = old_stack; + custom_task = std::move(old_task); } diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index c16547f3d6..7da16bfc7a 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -2,10 +2,10 @@ #include "Emu/Cell/Common.h" #include "Emu/CPU/CPUThread.h" -#include "Emu/Cell/SPUContext.h" +#include "Emu/Cell/SPUInterpreter.h" #include "MFC.h" -struct lv2_event_queue_t; +class lv2_event_queue_t; struct lv2_spu_group_t; struct lv2_int_tag_t; @@ -135,12 +135,20 @@ enum SPU_RdSigNotify2_offs = 0x1C00C, }; +enum : u32 +{ + RAW_SPU_BASE_ADDR = 0xE0000000, + RAW_SPU_OFFSET = 0x00100000, + RAW_SPU_LS_OFFSET = 0x00000000, + RAW_SPU_PROB_OFFSET = 0x00040000, +}; + struct spu_channel_t { // set to true if SPU thread must be notified after SPU channel operation thread_local static bool notification_required; - struct sync_var_t + struct alignas(8) sync_var_t { bool count; // value available bool wait; // notification required @@ -153,7 +161,7 @@ public: // returns true on success bool try_push(u32 value) { - const auto old = data.atomic_op([=](sync_var_t& data) + const auto old = data.fetch_op([=](sync_var_t& data) { if ((data.wait = data.count) == false) { @@ -168,7 +176,7 @@ public: // push performing bitwise OR with previous value, may require notification void push_or(u32 value) { - const auto old = data.atomic_op([=](sync_var_t& data) + const auto old = data.fetch_op([=](sync_var_t& data) { data.count = true; data.wait = false; @@ -181,7 +189,7 @@ public: // push unconditionally (overwriting previous value), may require notification void push(u32 value) { - const auto old = data.atomic_op([=](sync_var_t& data) + const auto old = data.fetch_op([=](sync_var_t& data) { data.count = true; data.wait = false; @@ -194,7 +202,7 @@ public: // returns true on success and loaded value std::tuple try_pop() { - const auto old = data.atomic_op([](sync_var_t& data) + const auto old = data.fetch_op([](sync_var_t& data) { data.wait = !data.count; data.count = false; @@ -207,7 +215,7 @@ public: // pop unconditionally (loading last value), may require notification u32 pop() { - const auto old = data.atomic_op([](sync_var_t& data) + const auto old = data.fetch_op([](sync_var_t& data) { data.wait = false; data.count = false; @@ -237,7 +245,7 @@ public: struct spu_channel_4_t { - struct sync_var_t + struct alignas(16) sync_var_t { struct { @@ -256,7 +264,7 @@ struct spu_channel_4_t public: void clear() { - values = sync_var_t{}; + values.store({}); value3 = 0; } @@ -333,7 +341,10 @@ struct spu_int_ctrl_t void set(u64 ints); - void clear(u64 ints); + void clear(u64 ints) + { + stat &= ~ints; + } void clear() { @@ -526,12 +537,27 @@ public: } }; -class SPUThread : public CPUThread +class SPUThread : public cpu_thread { - friend class SPURecompilerDecoder; - friend class spu_recompiler; +public: + virtual std::string get_name() const override; + virtual std::string dump() const override; + virtual void cpu_init() override; + virtual void cpu_task() override; + +protected: + SPUThread(const std::string& name) + : cpu_thread(cpu_type::spu, name) + , index(0) + , offset(0) + { + } public: + SPUThread(const std::string& name, u32 index); + + virtual ~SPUThread() override; + std::array gpr; // General-Purpose Registers SPU_FPSCR fpscr; @@ -578,32 +604,14 @@ public: const u32 index; // SPU index const u32 offset; // SPU LS offset - void push_snr(u32 number, u32 value) - { - // get channel - const auto channel = - number == 0 ? &ch_snr1 : - number == 1 ? &ch_snr2 : throw EXCEPTION("Unexpected"); + std::function custom_task; + std::exception_ptr pending_exception; - // check corresponding SNR register settings - if ((snr_config >> number) & 1) - { - channel->push_or(value); - } - else - { - channel->push(value); - } - - if (channel->notification_required) - { - // lock for reliable notification - std::lock_guard lock(mutex); - - cv.notify_one(); - } - } + std::shared_ptr spu_db; + std::shared_ptr spu_rec; + u32 recursion_level = 0; + void push_snr(u32 number, u32 value); void do_dma_transfer(u32 cmd, spu_mfc_arg_t args); void do_dma_list_cmd(u32 cmd, spu_mfc_arg_t args); void process_mfc_cmd(u32 cmd); @@ -618,14 +626,18 @@ public: void stop_and_signal(u32 code); void halt(); + void fast_call(u32 ls_addr); + // Convert specified SPU LS address to a pointer of specified (possibly converted to BE) type - template inline to_be_t* _ptr(u32 lsa) + template + inline to_be_t* _ptr(u32 lsa) { return static_cast*>(vm::base(offset + lsa)); } // Convert specified SPU LS address to a reference of specified (possibly converted to BE) type - template inline to_be_t& _ref(u32 lsa) + template + inline to_be_t& _ref(u32 lsa) { return *_ptr(lsa); } @@ -655,100 +667,4 @@ public: } } } - - std::function custom_task; - std::exception_ptr pending_exception; - u32 recursion_level = 0; - -protected: - SPUThread(CPUThreadType type, const std::string& name, u32 index, u32 offset); - -public: - SPUThread(const std::string& name, u32 index); - virtual ~SPUThread() override; - - virtual bool is_paused() const override; - - virtual std::string get_name() const override; - virtual void dump_info() const override; - virtual u32 get_pc() const override { return pc; } - virtual u32 get_offset() const override { return offset; } - virtual void do_run() override; - virtual void cpu_task() override; - - virtual void init_regs() override; - virtual void init_stack() override; - virtual void close_stack() override; - - void fast_call(u32 ls_addr); - - virtual std::string RegsToString() const override - { - std::string ret = "Registers:\n=========\n"; - - for(uint i=0; i<128; ++i) ret += fmt::format("GPR[%d] = 0x%s\n", i, gpr[i].to_hex().c_str()); - - return ret; - } - - virtual std::string ReadRegString(const std::string& reg) const override - { - std::string::size_type first_brk = reg.find('['); - if (first_brk != std::string::npos) - { - long reg_index; - reg_index = atol(reg.substr(first_brk + 1, reg.length()-2).c_str()); - if (reg.find("GPR")==0) return fmt::format("%016llx%016llx", gpr[reg_index]._u64[1], gpr[reg_index]._u64[0]); - } - return ""; - } - - bool WriteRegString(const std::string& reg, std::string value) override - { - while (value.length() < 32) value = "0"+value; - std::string::size_type first_brk = reg.find('['); - if (first_brk != std::string::npos) - { - long reg_index; - reg_index = atol(reg.substr(first_brk + 1, reg.length() - 2).c_str()); - if (reg.find("GPR")==0) - { - unsigned long long reg_value0; - unsigned long long reg_value1; - try - { - reg_value0 = std::stoull(value.substr(16, 31), 0, 16); - reg_value1 = std::stoull(value.substr(0, 15), 0, 16); - } - catch (std::invalid_argument& /*e*/) - { - return false; - } - gpr[reg_index]._u64[0] = (u64)reg_value0; - gpr[reg_index]._u64[1] = (u64)reg_value1; - return true; - } - } - return false; - } -}; - -class spu_thread : cpu_thread -{ -public: - spu_thread(u32 entry, const std::string& name = "", u32 stack_size = 0, u32 prio = 0); - - cpu_thread& args(std::initializer_list values) override - { - return *this; - } - - cpu_thread& run() override - { - auto& spu = static_cast(*thread); - - spu.run(); - - return *this; - } }; From 4cf41305e09ddec0e13bd0999f3a0f047d9a0632 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Thu, 14 Apr 2016 02:09:58 +0300 Subject: [PATCH 08/19] Partial commit: Cell (deletions) --- rpcs3/Emu/Cell/PPCDecoder.cpp | 11 - rpcs3/Emu/Cell/PPCDecoder.h | 32 - rpcs3/Emu/Cell/PPCInstrTable.h | 172 - rpcs3/Emu/Cell/PPCThreadManager.cpp | 110 - rpcs3/Emu/Cell/PPCThreadManager.h | 37 - rpcs3/Emu/Cell/PPUDecoder.h | 25 - rpcs3/Emu/Cell/PPUInstrTable.h | 704 --- rpcs3/Emu/Cell/PPULLVMRecompiler.cpp | 680 --- rpcs3/Emu/Cell/PPULLVMRecompiler.h | 946 ---- rpcs3/Emu/Cell/PPULLVMRecompilerCore.cpp | 5527 ---------------------- rpcs3/Emu/Cell/PPUProgramCompiler.cpp | 1735 ------- rpcs3/Emu/Cell/PPUProgramCompiler.h | 192 - rpcs3/Emu/SysCalls/Callback.h | 30 - rpcs3/Emu/SysCalls/FuncList.cpp | 4418 ----------------- 14 files changed, 14619 deletions(-) delete mode 100644 rpcs3/Emu/Cell/PPCDecoder.cpp delete mode 100644 rpcs3/Emu/Cell/PPCDecoder.h delete mode 100644 rpcs3/Emu/Cell/PPCInstrTable.h delete mode 100644 rpcs3/Emu/Cell/PPCThreadManager.cpp delete mode 100644 rpcs3/Emu/Cell/PPCThreadManager.h delete mode 100644 rpcs3/Emu/Cell/PPUDecoder.h delete mode 100644 rpcs3/Emu/Cell/PPUInstrTable.h delete mode 100644 rpcs3/Emu/Cell/PPULLVMRecompiler.cpp delete mode 100644 rpcs3/Emu/Cell/PPULLVMRecompiler.h delete mode 100644 rpcs3/Emu/Cell/PPULLVMRecompilerCore.cpp delete mode 100644 rpcs3/Emu/Cell/PPUProgramCompiler.cpp delete mode 100644 rpcs3/Emu/Cell/PPUProgramCompiler.h delete mode 100644 rpcs3/Emu/SysCalls/Callback.h delete mode 100644 rpcs3/Emu/SysCalls/FuncList.cpp diff --git a/rpcs3/Emu/Cell/PPCDecoder.cpp b/rpcs3/Emu/Cell/PPCDecoder.cpp deleted file mode 100644 index 7cbb50565f..0000000000 --- a/rpcs3/Emu/Cell/PPCDecoder.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "PPCDecoder.h" - -u32 PPCDecoder::DecodeMemory(const u32 address) -{ - u32 instr = vm::ps3::read32(address); - Decode(instr); - - return sizeof(u32); -} diff --git a/rpcs3/Emu/Cell/PPCDecoder.h b/rpcs3/Emu/Cell/PPCDecoder.h deleted file mode 100644 index 0a602f562a..0000000000 --- a/rpcs3/Emu/Cell/PPCDecoder.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once -#include "Emu/CPU/CPUDecoder.h" -#include "PPCInstrTable.h" - -class PPCDecoder : public CPUDecoder -{ -public: - virtual void Decode(const u32 code) = 0; - - virtual u32 DecodeMemory(const u32 address); - - virtual ~PPCDecoder() = default; -}; - - -template -static InstrList<(1 << (CodeField::size)), TO>* new_list(const CodeField& func, InstrCaller* error_func = nullptr) -{ - return new InstrList<(1 << (CodeField::size)), TO>(func, error_func); -} - -template -static InstrList<(1 << (CodeField::size)), TO>* new_list(InstrList* parent, int opcode, const CodeField& func, InstrCaller* error_func = nullptr) -{ - return connect_list(parent, new InstrList<(1 << (CodeField::size)), TO>(func, error_func), opcode); -} - -template -static InstrList<(1 << (CodeField::size)), TO>* new_list(InstrList* parent, const CodeField& func, InstrCaller* error_func = nullptr) -{ - return connect_list(parent, new InstrList<(1 << (CodeField::size)), TO>(func, error_func)); -} diff --git a/rpcs3/Emu/Cell/PPCInstrTable.h b/rpcs3/Emu/Cell/PPCInstrTable.h deleted file mode 100644 index 2eac8f73a7..0000000000 --- a/rpcs3/Emu/Cell/PPCInstrTable.h +++ /dev/null @@ -1,172 +0,0 @@ -#pragma once -#include "Emu/CPU/CPUInstrTable.h" - -enum CodeFieldType -{ - FIELD_IMM, - FIELD_R_GPR, - FIELD_R_FPR, - FIELD_R_VPR, - FIELD_R_CR, - FIELD_BRANCH, -}; - -template -class CodeField : public CodeFieldBase -{ - static_assert(from <= to, "too big 'from' value"); - static_assert(to <= 31, "too big 'to' value"); - -public: - CodeField(CodeFieldType type = FIELD_IMM) : CodeFieldBase(type) - { - } - - static const u32 size = to - from + 1; - static const u32 shift = 31 - to; - static const u32 mask = ((1ULL << ((to - from) + 1)) - 1) << shift; - - static force_inline void encode(u32& data, u32 value) - { - data &= ~mask; - data |= (value << shift) & mask; - } - - static force_inline u32 decode(u32 data) - { - return (data & mask) >> shift; - } - - virtual u32 operator ()(u32 data) const - { - return decode(data); - } - - virtual void operator()(u32& data, u32 value) const - { - encode(data, value); - } -}; - -static CodeField<0, 31> GetCode; - -template -class DoubleCodeField : public CodeField -{ - static_assert(from2 <= to2, "too big from2 value"); - static_assert(to2 <= 31, "too big to2 value"); - -public: - DoubleCodeField(CodeFieldType type = FIELD_IMM) : CodeField(type) - { - } - - static const u32 shift2 = 31 - to2; - static const u32 mask2 = ((1 << ((to2 - from2) + 1)) - 1) << shift2; - - static force_inline void encode(u32& data, u32 value) - { - data &= ~(CodeField::mask | mask2); - data |= ((value << CodeField::shift) & CodeField::mask) | (((value >> offset) << shift2) & mask2); - } - - static force_inline u32 decode(u32 data) - { - return ((data & CodeField::mask) >> CodeField::shift) | (((data & mask2) >> shift2) << offset); - } - - virtual u32 operator ()(u32 data) const - { - return decode(data); - } - - virtual void operator()(u32& data, u32 value) const - { - encode(data, value); - } -}; - -template -class CodeFieldSigned : public CodeField -{ -public: - CodeFieldSigned(CodeFieldType type = FIELD_IMM) : CodeField(type) - { - } - - static const int size = _size; - - static force_inline u32 decode(u32 data) - { - return sign((data & CodeField::mask) >> CodeField::shift); - } - - virtual u32 operator ()(u32 data) const - { - return decode(data); - } -}; - -template -class CodeFieldOffset : public CodeField -{ - static const int offset = _offset; - -public: - CodeFieldOffset(CodeFieldType type = FIELD_IMM) : CodeField(type) - { - } - - static force_inline u32 decode(u32 data) - { - return ((data & CodeField::mask) >> CodeField::shift) << offset; - } - - static force_inline void encode(u32& data, u32 value) - { - data &= ~CodeField::mask; - data |= ((value >> offset) << CodeField::shift) & CodeField::mask; - } - - virtual u32 operator ()(u32 data) const - { - return decode(data); - } - - virtual void operator ()(u32& data, u32 value) const - { - return encode(data, value); - } -}; - -template -class CodeFieldSignedOffset : public CodeFieldSigned -{ - static const int offset = _offset; - -public: - CodeFieldSignedOffset(CodeFieldType type = FIELD_IMM) : CodeFieldSigned(type) - { - } - - static force_inline u32 decode(u32 data) - { - return sign((data & CodeField::mask) >> CodeField::shift) << offset; - } - - static force_inline void encode(u32& data, u32 value) - { - data &= ~CodeField::mask; - data |= ((value >> offset) << CodeField::shift) & CodeField::mask; - } - - virtual u32 operator ()(u32 data) const - { - return decode(data); - } - - virtual void operator ()(u32& data, u32 value) const - { - return encode(data, value); - } -}; diff --git a/rpcs3/Emu/Cell/PPCThreadManager.cpp b/rpcs3/Emu/Cell/PPCThreadManager.cpp deleted file mode 100644 index b829ef72e5..0000000000 --- a/rpcs3/Emu/Cell/PPCThreadManager.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#if 0 -#include "stdafx.h" -#include "PPCThreadManager.h" -#include "PPUThread.h" -#include "SPUThread.h" -#include "RawSPUThread.h" - -PPCThreadManager::PPCThreadManager() : -m_raw_spu_num(0) -{ -} - -PPCThreadManager::~PPCThreadManager() -{ - Close(); -} - -void PPCThreadManager::Close() -{ - while(m_threads.size()) RemoveThread(m_threads[0]->GetId()); -} - -PPCThread& PPCThreadManager::AddThread(PPCThreadType type) -{ - std::lock_guard lock(m_mtx_thread); - - PPCThread* new_thread; - char* name; - switch(type) - { - case PPC_THREAD_PPU: new_thread = new PPUThread(); name = "PPU"; break; - case PPC_THREAD_SPU: new_thread = new SPUThread(); name = "SPU"; break; - case PPC_THREAD_RAW_SPU: new_thread = new RawSPUThread(m_raw_spu_num++); name = "RawSPU"; break; - default: assert(0); - } - - new_thread->SetId(Emu.GetIdManager().GetNewID(fmt::Format("%s Thread", name), new_thread)); - - m_threads.push_back(new_thread); - wxGetApp().SendDbgCommand(DID_CREATE_THREAD, new_thread); - - return *new_thread; -} - -void PPCThreadManager::RemoveThread(const u32 id) -{ - std::lock_guard lock(m_mtx_thread); - - for(u32 i=0; im_wait_thread_id == id) - { - m_threads[i]->Wait(false); - m_threads[i]->m_wait_thread_id = -1; - } - - if(m_threads[i]->GetId() != id) continue; - - PPCThread* thr = m_threads[i]; - wxGetApp().SendDbgCommand(DID_REMOVE_THREAD, thr); - if(thr->IsAlive()) - { - thr->Close(); - } - else - { - thr->Close(); - delete thr; - } - - - m_threads.erase(m_threads.begin() + i); - i--; - } - - Emu.GetIdManager().RemoveID(id, false); - Emu.CheckStatus(); -} - -s32 PPCThreadManager::GetThreadNumById(PPCThreadType type, u32 id) -{ - s32 num = 0; - - for(u32 i=0; iGetId() == id) return num; - if(m_threads[i]->GetType() == type) num++; - } - - return -1; -} - -PPCThread* PPCThreadManager::GetThread(u32 id) -{ - for(u32 i=0; iGetId() == id) return m_threads[i]; - } - - return nullptr; -} - -void PPCThreadManager::Exec() -{ - for(u32 i=0; iExec(); - } -} -#endif diff --git a/rpcs3/Emu/Cell/PPCThreadManager.h b/rpcs3/Emu/Cell/PPCThreadManager.h deleted file mode 100644 index 9bb650304c..0000000000 --- a/rpcs3/Emu/Cell/PPCThreadManager.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once -#include "PPCThread.h" - -enum PPCThreadType -{ - PPC_THREAD_PPU, - PPC_THREAD_SPU, - PPC_THREAD_RAW_SPU -}; - -class PPCThreadManager -{ - //IdManager m_threads_id; - //ArrayF m_ppu_threads; - //ArrayF m_spu_threads; - std::vector m_threads; - std::mutex m_mtx_thread; - wxSemaphore m_sem_task; - u32 m_raw_spu_num; - -public: - PPCThreadManager(); - ~PPCThreadManager(); - - void Close(); - - PPCThread& AddThread(PPCThreadType type); - void RemoveThread(const u32 id); - - std::vector& GetThreads() { return m_threads; } - s32 GetThreadNumById(PPCThreadType type, u32 id); - PPCThread* GetThread(u32 id); - //IdManager& GetIDs() {return m_threads_id;} - - void Exec(); - void Task(); -}; diff --git a/rpcs3/Emu/Cell/PPUDecoder.h b/rpcs3/Emu/Cell/PPUDecoder.h deleted file mode 100644 index 97132b07e9..0000000000 --- a/rpcs3/Emu/Cell/PPUDecoder.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "Emu/Cell/PPUOpcodes.h" -#include "Emu/Cell/PPCDecoder.h" -#include "PPUInstrTable.h" - -class PPUDecoder : public PPCDecoder -{ - PPUOpcodes* m_op; - -public: - PPUDecoder(PPUOpcodes* op) : m_op(op) - { - } - - virtual ~PPUDecoder() - { - delete m_op; - } - - virtual void Decode(const u32 code) - { - (*PPU_instr::main_list)(m_op, code); - } -}; \ No newline at end of file diff --git a/rpcs3/Emu/Cell/PPUInstrTable.h b/rpcs3/Emu/Cell/PPUInstrTable.h deleted file mode 100644 index fbad298fbb..0000000000 --- a/rpcs3/Emu/Cell/PPUInstrTable.h +++ /dev/null @@ -1,704 +0,0 @@ -#pragma once -#include "PPCInstrTable.h" -#include "PPCDecoder.h" -#include "PPUOpcodes.h" - -namespace PPU_instr -{ - namespace fields - { - //This field is used in rotate instructions to specify the first 1 bit of a 64-bit mask - static DoubleCodeField<21, 25, 26, 26, 5> mb; - - //This field is used in rotate instructions to specify the last 1 bit of a 64-bit mask - static DoubleCodeField<21, 25, 26, 26, 5> me; - - //This field is used to specify a shift amount - static DoubleCodeField<16, 20, 30, 30, 5> sh; - - //This field is used to specify a special-purpose register for the mtspr and mfspr instructions - static CodeField<11, 20> SPR; - - // - static CodeField<6, 10> VS(FIELD_R_VPR); - - // - static CodeField<6, 10> VD(FIELD_R_VPR); - - // - static CodeField<11, 15> VA(FIELD_R_VPR); - - // - static CodeField<16, 20> VB(FIELD_R_VPR); - - // - static CodeField<21, 25> VC(FIELD_R_VPR); - - // - static CodeField<11, 15> VUIMM; - - // - static CodeFieldSigned<11, 15> VSIMM; - - // - static CodeField<22, 25> VSH; - - //This field is used to specify a GPR to be used as a destination - static CodeField<6, 10> RD(FIELD_R_GPR); - - //This field is used to specify a GPR to be used as a source - static CodeField<6, 10> RS(FIELD_R_GPR); - - //This field is used to specify a GPR to be used as a source or destination - static CodeField<11, 15> RA(FIELD_R_GPR); - - //This field is used to specify a GPR to be used as a source - static CodeField<16, 20> RB(FIELD_R_GPR); - - //This field is used to specify the number of bytes to move in an immediate string load or store - static CodeField<16, 20> NB; - - //This field is used to specify one of the CR fields, or one of the FPSCR fields, as a destination - static CodeField<6, 8> CRFD(FIELD_R_CR); - - //This field is used to specify one of the CR fields, or one of the FPSCR fields, as a source - static CodeField<11, 13> CRFS(FIELD_R_CR); - - //This field is used to specify a bit in the CR to be used as a source - static CodeField<11, 15> CRBA(FIELD_R_CR); - - //This field is used to specify a bit in the CR to be used as a source - static CodeField<16, 20> CRBB(FIELD_R_CR); - - //This field is used to specify a bit in the CR, or in the FPSCR, as the destination of the result of an instruction - static CodeField<6, 10> CRBD(FIELD_R_CR); - - //This field is used to specify options for the branch conditional instructions - static CodeField<6, 10> BO; - - //This field is used to specify a bit in the CR to be used as the condition of a branch conditional instruction - static CodeField<11, 15> BI; - - //Immediate field specifying a 14-bit signed two's complement branch displacement that is concatenated on the - //right with '00' and sign-extended to 64 bits. - static CodeFieldSigned<16, 31> BD(FIELD_BRANCH); - - // - static CodeField<19, 20> BH; - - // - static CodeField<11, 13> BFA; - - //Field used by the optional data stream variant of the dcbt instruction. - static CodeField<9, 10> TH; - - //This field is used to specify the conditions on which to trap - static CodeField<6, 10> TO; - - // - static CodeField<21, 25> MB; - - // - static CodeField<26, 30> ME; - - //This field is used to specify a shift amount - static CodeField<16, 20> SH; - - /* - Absolute address bit. - 0 The immediate field represents an address relative to the current instruction address (CIA). (For more - information on the CIA, see Table 8-3.) The effective (logical) address of the branch is either the sum - of the LI field sign-extended to 64 bits and the address of the branch instruction or the sum of the BD - field sign-extended to 64 bits and the address of the branch instruction. - 1 The immediate field represents an absolute address. The effective address (EA) of the branch is the - LI field sign-extended to 64 bits or the BD field sign-extended to 64 bits. - */ - static CodeField<30> AA; - - // - static CodeFieldSignedOffset<6, 29, 2> LL(FIELD_BRANCH); - /* - Link bit. - 0 Does not update the link register (LR). - 1 Updates the LR. If the instruction is a branch instruction, the address of the instruction following the - branch instruction is placed into the LR. - */ - static CodeField<31> LK; - - //This field is used for extended arithmetic to enable setting OV and SO in the XER - static CodeField<21> OE; - - //Field used to specify whether an integer compare instruction is to compare 64-bit numbers or 32-bit numbers - static CodeField<10> L_10; - static CodeField<6> L_6; - static CodeField<9, 10> L_9_10; - static CodeField<11> L_11; - // - static CodeField<16, 19> I; - - // - static CodeField<16, 27> DQ; - - //This field is used to specify an FPR as the destination - static CodeField<6, 10> FRD; - - //This field is used to specify an FPR as a source - static CodeField<6, 10> FRS; - - // - static CodeField<7, 14> FM; - - //This field is used to specify an FPR as a source - static CodeField<11, 15> FRA(FIELD_R_FPR); - - //This field is used to specify an FPR as a source - static CodeField<16, 20> FRB(FIELD_R_FPR); - - //This field is used to specify an FPR as a source - static CodeField<21, 25> FRC(FIELD_R_FPR); - - //This field mask is used to identify the CR fields that are to be updated by the mtcrf instruction. - static CodeField<12, 19> CRM; - - // This field is used to identify the system call level - static CodeField<20, 26> LEV; - - //Immediate field specifying a 16-bit signed two's complement integer that is sign-extended to 64 bits - static CodeFieldSigned<16, 31> D; - - // - static CodeFieldSignedOffset<16, 29, 2> DS; - - //This immediate field is used to specify a 16-bit signed integer - static CodeFieldSigned<16, 31> simm16; - - //This immediate field is used to specify a 16-bit unsigned integer - static CodeField<16, 31> uimm16; - - static CodeField<6, 31> uimm26; - - /* - Record bit. - 0 Does not update the condition register (CR). - 1 Updates the CR to reflect the result of the operation. - For integer instructions, CR bits [0-2] are set to reflect the result as a signed quantity and CR bit [3] - receives a copy of the summary overflow bit, XER[SO]. The result as an unsigned quantity or a bit - string can be deduced from the EQ bit. For floating-point instructions, CR bits [4-7] are set to reflect - floating-point exception, floating-point enabled exception, floating-point invalid operation exception, - and floating-point overflow exception. - */ - static CodeField<31> RC; - - //Primary opcode field - static CodeField<0, 5> OPCD; - - static CodeField<26, 31> GD_04; //0x3f - static CodeField<21, 31> GD_04_0;//0x7ff - static CodeField<21, 30> GD_13; //0x3ff - static CodeField<27, 29> GD_1e; //0x7 - static CodeField<21, 30> GD_1f; //0x3ff - static CodeField<30, 31> GD_3a; //0x3 - static CodeField<26, 30> GD_3b; //0x1f - static CodeField<30, 31> GD_3e; //0x3 - static CodeField<26, 30> GD_3f;//0x1f - static CodeField<21, 30> GD_3f_0; //0x3ff - - static CodeField<9, 10> STRM; - } - - namespace lists - { - using namespace fields; - - //static auto main_list = new_list(OPCD, instr_bind(&PPUOpcodes::UNK, GetCode, OPCD, OPCD)); - static InstrList<1 << CodeField<0, 5>::size, ::PPUOpcodes> main_list_obj(OPCD, instr_bind(&PPUOpcodes::UNK, GetCode, OPCD, OPCD)); - static auto main_list = &main_list_obj; - static auto g04_list = new_list(main_list, PPU_opcodes::G_04, GD_04); - static auto g04_0_list = new_list(g04_list, GD_04_0, instr_bind(&PPUOpcodes::UNK, GetCode, OPCD, GD_04_0)); - static auto g13_list = new_list(main_list, PPU_opcodes::G_13, GD_13, instr_bind(&PPUOpcodes::UNK, GetCode, OPCD, GD_13)); - static auto g1e_list = new_list(main_list, PPU_opcodes::G_1e, GD_1e, instr_bind(&PPUOpcodes::UNK, GetCode, OPCD, GD_1e)); - static auto g1f_list = new_list(main_list, PPU_opcodes::G_1f, GD_1f, instr_bind(&PPUOpcodes::UNK, GetCode, OPCD, GD_1f)); - static auto g3a_list = new_list(main_list, PPU_opcodes::G_3a, GD_3a, instr_bind(&PPUOpcodes::UNK, GetCode, OPCD, GD_3a)); - static auto g3b_list = new_list(main_list, PPU_opcodes::G_3b, GD_3b, instr_bind(&PPUOpcodes::UNK, GetCode, OPCD, GD_3b)); - static auto g3e_list = new_list(main_list, PPU_opcodes::G_3e, GD_3e, instr_bind(&PPUOpcodes::UNK, GetCode, OPCD, GD_3e)); - static auto g3f_list = new_list(main_list, PPU_opcodes::G_3f, GD_3f); - static auto g3f_0_list = new_list(g3f_list, GD_3f_0, instr_bind(&PPUOpcodes::UNK, GetCode, OPCD, GD_3f_0)); - -#define bind_instr(list, name, ...) \ - static const auto& name = make_instr(list, #name, &PPUOpcodes::name, ##__VA_ARGS__) -#define bind_instr_oe(list, name, ...) \ - bind_instr(list, name, ##__VA_ARGS__); \ - static const auto& name##O = make_instr(list, #name "O", &PPUOpcodes::name, ##__VA_ARGS__) - - bind_instr(main_list, TDI, TO, RA, simm16); - bind_instr(main_list, TWI, TO, RA, simm16); - bind_instr(main_list, MULLI, RD, RA, simm16); - bind_instr(main_list, SUBFIC, RD, RA, simm16); - bind_instr(main_list, CMPLI, CRFD, L_10, RA, uimm16); - bind_instr(main_list, CMPI, CRFD, L_10, RA, simm16); - bind_instr(main_list, ADDIC, RD, RA, simm16); - bind_instr(main_list, ADDIC_, RD, RA, simm16); - bind_instr(main_list, ADDI, RD, RA, simm16); - bind_instr(main_list, ADDIS, RD, RA, simm16); - bind_instr(main_list, BC, BO, BI, BD, AA, LK); - bind_instr(main_list, HACK, uimm26); - bind_instr(main_list, SC, LEV); - bind_instr(main_list, B, LL, AA, LK); - bind_instr(main_list, RLWIMI, RA, RS, SH, MB, ME, RC); - bind_instr(main_list, RLWINM, RA, RS, SH, MB, ME, RC); - bind_instr(main_list, RLWNM, RA, RS, RB, MB, ME, RC); - bind_instr(main_list, ORI, RA, RS, uimm16); - bind_instr(main_list, ORIS, RA, RS, uimm16); - bind_instr(main_list, XORI, RA, RS, uimm16); - bind_instr(main_list, XORIS, RA, RS, uimm16); - bind_instr(main_list, ANDI_, RA, RS, uimm16); - bind_instr(main_list, ANDIS_, RA, RS, uimm16); - bind_instr(main_list, LWZ, RD, RA, D); - bind_instr(main_list, LWZU, RD, RA, D); - bind_instr(main_list, LBZ, RD, RA, D); - bind_instr(main_list, LBZU, RD, RA, D); - bind_instr(main_list, STW, RS, RA, D); - bind_instr(main_list, STWU, RS, RA, D); - bind_instr(main_list, STB, RS, RA, D); - bind_instr(main_list, STBU, RS, RA, D); - bind_instr(main_list, LHZ, RD, RA, D); - bind_instr(main_list, LHZU, RD, RA, D); - bind_instr(main_list, LHA, RD, RA, D); - bind_instr(main_list, LHAU, RD, RA, D); - bind_instr(main_list, STH, RS, RA, D); - bind_instr(main_list, STHU, RS, RA, D); - bind_instr(main_list, LMW, RD, RA, D); - bind_instr(main_list, STMW, RS, RA, D); - bind_instr(main_list, LFS, FRD, RA, D); - bind_instr(main_list, LFSU, FRD, RA, D); - bind_instr(main_list, LFD, FRD, RA, D); - bind_instr(main_list, LFDU, FRD, RA, D); - bind_instr(main_list, STFS, FRS, RA, D); - bind_instr(main_list, STFSU, FRS, RA, D); - bind_instr(main_list, STFD, FRS, RA, D); - bind_instr(main_list, STFDU, FRS, RA, D); - - bind_instr(g04_list, VMADDFP, VD, VA, VC, VB); - bind_instr(g04_list, VMHADDSHS, VD, VA, VB, VC); - bind_instr(g04_list, VMHRADDSHS, VD, VA, VB, VC); - bind_instr(g04_list, VMLADDUHM, VD, VA, VB, VC); - bind_instr(g04_list, VMSUMMBM, VD, VA, VB, VC); - bind_instr(g04_list, VMSUMSHM, VD, VA, VB, VC); - bind_instr(g04_list, VMSUMSHS, VD, VA, VB, VC); - bind_instr(g04_list, VMSUMUBM, VD, VA, VB, VC); - bind_instr(g04_list, VMSUMUHM, VD, VA, VB, VC); - bind_instr(g04_list, VMSUMUHS, VD, VA, VB, VC); - bind_instr(g04_list, VNMSUBFP, VD, VA, VC, VB); - bind_instr(g04_list, VPERM, VD, VA, VB, VC); - bind_instr(g04_list, VSEL, VD, VA, VB, VC); - bind_instr(g04_list, VSLDOI, VD, VA, VB, VSH); - - bind_instr(g04_0_list, MFVSCR, VD); - bind_instr(g04_0_list, MTVSCR, VB); - bind_instr(g04_0_list, VADDCUW, VD, VA, VB); - bind_instr(g04_0_list, VADDFP, VD, VA, VB); - bind_instr(g04_0_list, VADDSBS, VD, VA, VB); - bind_instr(g04_0_list, VADDSHS, VD, VA, VB); - bind_instr(g04_0_list, VADDSWS, VD, VA, VB); - bind_instr(g04_0_list, VADDUBM, VD, VA, VB); - bind_instr(g04_0_list, VADDUBS, VD, VA, VB); - bind_instr(g04_0_list, VADDUHM, VD, VA, VB); - bind_instr(g04_0_list, VADDUHS, VD, VA, VB); - bind_instr(g04_0_list, VADDUWM, VD, VA, VB); - bind_instr(g04_0_list, VADDUWS, VD, VA, VB); - bind_instr(g04_0_list, VAND, VD, VA, VB); - bind_instr(g04_0_list, VANDC, VD, VA, VB); - bind_instr(g04_0_list, VAVGSB, VD, VA, VB); - bind_instr(g04_0_list, VAVGSH, VD, VA, VB); - bind_instr(g04_0_list, VAVGSW, VD, VA, VB); - bind_instr(g04_0_list, VAVGUB, VD, VA, VB); - bind_instr(g04_0_list, VAVGUH, VD, VA, VB); - bind_instr(g04_0_list, VAVGUW, VD, VA, VB); - bind_instr(g04_0_list, VCFSX, VD, VUIMM, VB); - bind_instr(g04_0_list, VCFUX, VD, VUIMM, VB); - bind_instr(g04_0_list, VCMPBFP, VD, VA, VB); - bind_instr(g04_0_list, VCMPBFP_, VD, VA, VB); - bind_instr(g04_0_list, VCMPEQFP, VD, VA, VB); - bind_instr(g04_0_list, VCMPEQFP_, VD, VA, VB); - bind_instr(g04_0_list, VCMPEQUB, VD, VA, VB); - bind_instr(g04_0_list, VCMPEQUB_, VD, VA, VB); - bind_instr(g04_0_list, VCMPEQUH, VD, VA, VB); - bind_instr(g04_0_list, VCMPEQUH_, VD, VA, VB); - bind_instr(g04_0_list, VCMPEQUW, VD, VA, VB); - bind_instr(g04_0_list, VCMPEQUW_, VD, VA, VB); - bind_instr(g04_0_list, VCMPGEFP, VD, VA, VB); - bind_instr(g04_0_list, VCMPGEFP_, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTFP, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTFP_, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTSB, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTSB_, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTSH, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTSH_, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTSW, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTSW_, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTUB, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTUB_, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTUH, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTUH_, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTUW, VD, VA, VB); - bind_instr(g04_0_list, VCMPGTUW_, VD, VA, VB); - bind_instr(g04_0_list, VCTSXS, VD, VUIMM, VB); - bind_instr(g04_0_list, VCTUXS, VD, VUIMM, VB); - bind_instr(g04_0_list, VEXPTEFP, VD, VB); - bind_instr(g04_0_list, VLOGEFP, VD, VB); - bind_instr(g04_0_list, VMAXFP, VD, VA, VB); - bind_instr(g04_0_list, VMAXSB, VD, VA, VB); - bind_instr(g04_0_list, VMAXSH, VD, VA, VB); - bind_instr(g04_0_list, VMAXSW, VD, VA, VB); - bind_instr(g04_0_list, VMAXUB, VD, VA, VB); - bind_instr(g04_0_list, VMAXUH, VD, VA, VB); - bind_instr(g04_0_list, VMAXUW, VD, VA, VB); - bind_instr(g04_0_list, VMINFP, VD, VA, VB); - bind_instr(g04_0_list, VMINSB, VD, VA, VB); - bind_instr(g04_0_list, VMINSH, VD, VA, VB); - bind_instr(g04_0_list, VMINSW, VD, VA, VB); - bind_instr(g04_0_list, VMINUB, VD, VA, VB); - bind_instr(g04_0_list, VMINUH, VD, VA, VB); - bind_instr(g04_0_list, VMINUW, VD, VA, VB); - bind_instr(g04_0_list, VMRGHB, VD, VA, VB); - bind_instr(g04_0_list, VMRGHH, VD, VA, VB); - bind_instr(g04_0_list, VMRGHW, VD, VA, VB); - bind_instr(g04_0_list, VMRGLB, VD, VA, VB); - bind_instr(g04_0_list, VMRGLH, VD, VA, VB); - bind_instr(g04_0_list, VMRGLW, VD, VA, VB); - bind_instr(g04_0_list, VMULESB, VD, VA, VB); - bind_instr(g04_0_list, VMULESH, VD, VA, VB); - bind_instr(g04_0_list, VMULEUB, VD, VA, VB); - bind_instr(g04_0_list, VMULEUH, VD, VA, VB); - bind_instr(g04_0_list, VMULOSB, VD, VA, VB); - bind_instr(g04_0_list, VMULOSH, VD, VA, VB); - bind_instr(g04_0_list, VMULOUB, VD, VA, VB); - bind_instr(g04_0_list, VMULOUH, VD, VA, VB); - bind_instr(g04_0_list, VNOR, VD, VA, VB); - bind_instr(g04_0_list, VOR, VD, VA, VB); - bind_instr(g04_0_list, VPKPX, VD, VA, VB); - bind_instr(g04_0_list, VPKSHSS, VD, VA, VB); - bind_instr(g04_0_list, VPKSHUS, VD, VA, VB); - bind_instr(g04_0_list, VPKSWSS, VD, VA, VB); - bind_instr(g04_0_list, VPKSWUS, VD, VA, VB); - bind_instr(g04_0_list, VPKUHUM, VD, VA, VB); - bind_instr(g04_0_list, VPKUHUS, VD, VA, VB); - bind_instr(g04_0_list, VPKUWUM, VD, VA, VB); - bind_instr(g04_0_list, VPKUWUS, VD, VA, VB); - bind_instr(g04_0_list, VREFP, VD, VB); - bind_instr(g04_0_list, VRFIM, VD, VB); - bind_instr(g04_0_list, VRFIN, VD, VB); - bind_instr(g04_0_list, VRFIP, VD, VB); - bind_instr(g04_0_list, VRFIZ, VD, VB); - bind_instr(g04_0_list, VRLB, VD, VA, VB); - bind_instr(g04_0_list, VRLH, VD, VA, VB); - bind_instr(g04_0_list, VRLW, VD, VA, VB); - bind_instr(g04_0_list, VRSQRTEFP, VD, VB); - bind_instr(g04_0_list, VSL, VD, VA, VB); - bind_instr(g04_0_list, VSLB, VD, VA, VB); - bind_instr(g04_0_list, VSLH, VD, VA, VB); - bind_instr(g04_0_list, VSLO, VD, VA, VB); - bind_instr(g04_0_list, VSLW, VD, VA, VB); - bind_instr(g04_0_list, VSPLTB, VD, VUIMM, VB); - bind_instr(g04_0_list, VSPLTH, VD, VUIMM, VB); - bind_instr(g04_0_list, VSPLTISB, VD, VSIMM); - bind_instr(g04_0_list, VSPLTISH, VD, VSIMM); - bind_instr(g04_0_list, VSPLTISW, VD, VSIMM); - bind_instr(g04_0_list, VSPLTW, VD, VUIMM, VB); - bind_instr(g04_0_list, VSR, VD, VA, VB); - bind_instr(g04_0_list, VSRAB, VD, VA, VB); - bind_instr(g04_0_list, VSRAH, VD, VA, VB); - bind_instr(g04_0_list, VSRAW, VD, VA, VB); - bind_instr(g04_0_list, VSRB, VD, VA, VB); - bind_instr(g04_0_list, VSRH, VD, VA, VB); - bind_instr(g04_0_list, VSRO, VD, VA, VB); - bind_instr(g04_0_list, VSRW, VD, VA, VB); - bind_instr(g04_0_list, VSUBCUW, VD, VA, VB); - bind_instr(g04_0_list, VSUBFP, VD, VA, VB); - bind_instr(g04_0_list, VSUBSBS, VD, VA, VB); - bind_instr(g04_0_list, VSUBSHS, VD, VA, VB); - bind_instr(g04_0_list, VSUBSWS, VD, VA, VB); - bind_instr(g04_0_list, VSUBUBM, VD, VA, VB); - bind_instr(g04_0_list, VSUBUBS, VD, VA, VB); - bind_instr(g04_0_list, VSUBUHM, VD, VA, VB); - bind_instr(g04_0_list, VSUBUHS, VD, VA, VB); - bind_instr(g04_0_list, VSUBUWM, VD, VA, VB); - bind_instr(g04_0_list, VSUBUWS, VD, VA, VB); - bind_instr(g04_0_list, VSUMSWS, VD, VA, VB); - bind_instr(g04_0_list, VSUM2SWS, VD, VA, VB); - bind_instr(g04_0_list, VSUM4SBS, VD, VA, VB); - bind_instr(g04_0_list, VSUM4SHS, VD, VA, VB); - bind_instr(g04_0_list, VSUM4UBS, VD, VA, VB); - bind_instr(g04_0_list, VUPKHPX, VD, VB); - bind_instr(g04_0_list, VUPKHSB, VD, VB); - bind_instr(g04_0_list, VUPKHSH, VD, VB); - bind_instr(g04_0_list, VUPKLPX, VD, VB); - bind_instr(g04_0_list, VUPKLSB, VD, VB); - bind_instr(g04_0_list, VUPKLSH, VD, VB); - bind_instr(g04_0_list, VXOR, VD, VA, VB); - - bind_instr(g13_list, MCRF, CRFD, CRFS); - bind_instr(g13_list, BCLR, BO, BI, BH, LK); - bind_instr(g13_list, CRNOR, CRBD, CRBA, CRBB); - bind_instr(g13_list, CRANDC, CRBD, CRBA, CRBB); - bind_instr(g13_list, ISYNC); - bind_instr(g13_list, CRXOR, CRBD, CRBA, CRBB); - bind_instr(g13_list, CRNAND, CRBD, CRBA, CRBB); - bind_instr(g13_list, CRAND, CRBD, CRBA, CRBB); - bind_instr(g13_list, CREQV, CRBD, CRBA, CRBB); - bind_instr(g13_list, CRORC, CRBD, CRBA, CRBB); - bind_instr(g13_list, CROR, CRBD, CRBA, CRBB); - bind_instr(g13_list, BCCTR, BO, BI, BH, LK); - - bind_instr(g1e_list, RLDICL, RA, RS, sh, mb, RC); - bind_instr(g1e_list, RLDICR, RA, RS, sh, me, RC); - bind_instr(g1e_list, RLDIC, RA, RS, sh, mb, RC); - bind_instr(g1e_list, RLDIMI, RA, RS, sh, mb, RC); - bind_instr(g1e_list, RLDC_LR, RA, RS, RB, mb, AA, RC); - - /*0x000*/bind_instr(g1f_list, CMP, CRFD, L_10, RA, RB); - /*0x004*/bind_instr(g1f_list, TW, TO, RA, RB); - /*0x006*/bind_instr(g1f_list, LVSL, VD, RA, RB); - /*0x007*/bind_instr(g1f_list, LVEBX, VD, RA, RB); - /*0x008*/bind_instr_oe(g1f_list, SUBFC, RD, RA, RB, OE, RC); - /*0x009*/bind_instr(g1f_list, MULHDU, RD, RA, RB, RC); - /*0x00a*/bind_instr_oe(g1f_list, ADDC, RD, RA, RB, OE, RC); - /*0x00b*/bind_instr(g1f_list, MULHWU, RD, RA, RB, RC); - /*0x013*/bind_instr(g1f_list, MFOCRF, L_11, RD, CRM); - /*0x014*/bind_instr(g1f_list, LWARX, RD, RA, RB); - /*0x015*/bind_instr(g1f_list, LDX, RD, RA, RB); - /*0x017*/bind_instr(g1f_list, LWZX, RD, RA, RB); - /*0x018*/bind_instr(g1f_list, SLW, RA, RS, RB, RC); - /*0x01a*/bind_instr(g1f_list, CNTLZW, RA, RS, RC); - /*0x01b*/bind_instr(g1f_list, SLD, RA, RS, RB, RC); - /*0x01c*/bind_instr(g1f_list, AND, RA, RS, RB, RC); - /*0x020*/bind_instr(g1f_list, CMPL, CRFD, L_10, RA, RB); - /*0x026*/bind_instr(g1f_list, LVSR, VD, RA, RB); - /*0x027*/bind_instr(g1f_list, LVEHX, VD, RA, RB); - /*0x028*/bind_instr_oe(g1f_list, SUBF, RD, RA, RB, OE, RC); - /*0x035*/bind_instr(g1f_list, LDUX, RD, RA, RB); - /*0x036*/bind_instr(g1f_list, DCBST, RA, RB); - /*0x037*/bind_instr(g1f_list, LWZUX, RD, RA, RB); - /*0x03a*/bind_instr(g1f_list, CNTLZD, RA, RS, RC); - /*0x03c*/bind_instr(g1f_list, ANDC, RA, RS, RB, RC); - /*0x03c*/bind_instr(g1f_list, TD, TO, RA, RB); - /*0x047*/bind_instr(g1f_list, LVEWX, VD, RA, RB); - /*0x049*/bind_instr(g1f_list, MULHD, RD, RA, RB, RC); - /*0x04b*/bind_instr(g1f_list, MULHW, RD, RA, RB, RC); - /*0x054*/bind_instr(g1f_list, LDARX, RD, RA, RB); - /*0x056*/bind_instr(g1f_list, DCBF, RA, RB); - /*0x057*/bind_instr(g1f_list, LBZX, RD, RA, RB); - /*0x067*/bind_instr(g1f_list, LVX, VD, RA, RB); - /*0x068*/bind_instr_oe(g1f_list, NEG, RD, RA, OE, RC); - /*0x077*/bind_instr(g1f_list, LBZUX, RD, RA, RB); - /*0x07c*/bind_instr(g1f_list, NOR, RA, RS, RB, RC); - /*0x087*/bind_instr(g1f_list, STVEBX, VS, RA, RB); - /*0x088*/bind_instr_oe(g1f_list, SUBFE, RD, RA, RB, OE, RC); - /*0x08a*/bind_instr_oe(g1f_list, ADDE, RD, RA, RB, OE, RC); - /*0x090*/bind_instr(g1f_list, MTOCRF, L_11, CRM, RS); - /*0x095*/bind_instr(g1f_list, STDX, RS, RA, RB); - /*0x096*/bind_instr(g1f_list, STWCX_, RS, RA, RB); - /*0x097*/bind_instr(g1f_list, STWX, RS, RA, RB); - /*0x0a7*/bind_instr(g1f_list, STVEHX, VS, RA, RB); - /*0x0b5*/bind_instr(g1f_list, STDUX, RS, RA, RB); - /*0x0b7*/bind_instr(g1f_list, STWUX, RS, RA, RB); - /*0x0c7*/bind_instr(g1f_list, STVEWX, VS, RA, RB); - /*0x0c8*/bind_instr_oe(g1f_list, SUBFZE, RD, RA, OE, RC); - /*0x0ca*/bind_instr_oe(g1f_list, ADDZE, RD, RA, OE, RC); - /*0x0d6*/bind_instr(g1f_list, STDCX_, RS, RA, RB); - /*0x0d7*/bind_instr(g1f_list, STBX, RS, RA, RB); - /*0x0e7*/bind_instr(g1f_list, STVX, VS, RA, RB); - /*0x0e8*/bind_instr_oe(g1f_list, SUBFME, RD, RA, OE, RC); - /*0x0e9*/bind_instr_oe(g1f_list, MULLD, RD, RA, RB, OE, RC); - /*0x0ea*/bind_instr_oe(g1f_list, ADDME, RD, RA, OE, RC); - /*0x0eb*/bind_instr_oe(g1f_list, MULLW, RD, RA, RB, OE, RC); - /*0x0f6*/bind_instr(g1f_list, DCBTST, RA, RB, TH); - /*0x0f7*/bind_instr(g1f_list, STBUX, RS, RA, RB); - /*0x10a*/bind_instr_oe(g1f_list, ADD, RD, RA, RB, OE, RC); - /*0x116*/bind_instr(g1f_list, DCBT, RA, RB, TH); - /*0x117*/bind_instr(g1f_list, LHZX, RD, RA, RB); - /*0x11c*/bind_instr(g1f_list, EQV, RA, RS, RB, RC); - /*0x136*/bind_instr(g1f_list, ECIWX, RD, RA, RB); - /*0x137*/bind_instr(g1f_list, LHZUX, RD, RA, RB); - /*0x13c*/bind_instr(g1f_list, XOR, RA, RS, RB, RC); - /*0x153*/bind_instr(g1f_list, MFSPR, RD, SPR); - /*0x155*/bind_instr(g1f_list, LWAX, RD, RA, RB); - /*0x156*/bind_instr(g1f_list, DST, RA, RB, STRM, L_6); - /*0x157*/bind_instr(g1f_list, LHAX, RD, RA, RB); - /*0x167*/bind_instr(g1f_list, LVXL, VD, RA, RB); - /*0x173*/bind_instr(g1f_list, MFTB, RD, SPR); - /*0x175*/bind_instr(g1f_list, LWAUX, RD, RA, RB); - /*0x176*/bind_instr(g1f_list, DSTST, RA, RB, STRM, L_6); - /*0x177*/bind_instr(g1f_list, LHAUX, RD, RA, RB); - /*0x197*/bind_instr(g1f_list, STHX, RS, RA, RB); - /*0x19c*/bind_instr(g1f_list, ORC, RA, RS, RB, RC); - /*0x1b6*/bind_instr(g1f_list, ECOWX, RS, RA, RB); - /*0x1b7*/bind_instr(g1f_list, STHUX, RS, RA, RB); - /*0x1bc*/bind_instr(g1f_list, OR, RA, RS, RB, RC); - /*0x1c9*/bind_instr_oe(g1f_list, DIVDU, RD, RA, RB, OE, RC); - /*0x1cb*/bind_instr_oe(g1f_list, DIVWU, RD, RA, RB, OE, RC); - /*0x1d3*/bind_instr(g1f_list, MTSPR, SPR, RS); - /*0x1d6*///DCBI - /*0x1dc*/bind_instr(g1f_list, NAND, RA, RS, RB, RC); - /*0x1e7*/bind_instr(g1f_list, STVXL, VS, RA, RB); - /*0x1e9*/bind_instr_oe(g1f_list, DIVD, RD, RA, RB, OE, RC); - /*0x1eb*/bind_instr_oe(g1f_list, DIVW, RD, RA, RB, OE, RC); - /*0x207*/bind_instr(g1f_list, LVLX, VD, RA, RB); - // MULH{D|DU|W|WU} don't use OE, but a real Cell accepts - // opcodes with OE=1 and Rc=0, behaving as if OE was not set. - // OE=1 and Rc=1 causes an invalid instruction exception, but - // we don't worry about that. - static const auto& MULHDUO = make_instr<0x209>(g1f_list, "MULHDUO", &PPUOpcodes::MULHDU, RD, RA, RB, RC); - static const auto& MULHWUO = make_instr<0x20b>(g1f_list, "MULHWUO", &PPUOpcodes::MULHWU, RD, RA, RB, RC); - /*0x214*/bind_instr(g1f_list, LDBRX, RD, RA, RB); - /*0x215*/bind_instr(g1f_list, LSWX, RD, RA, RB); - /*0x216*/bind_instr(g1f_list, LWBRX, RD, RA, RB); - /*0x217*/bind_instr(g1f_list, LFSX, FRD, RA, RB); - /*0x218*/bind_instr(g1f_list, SRW, RA, RS, RB, RC); - /*0x21b*/bind_instr(g1f_list, SRD, RA, RS, RB, RC); - /*0x227*/bind_instr(g1f_list, LVRX, VD, RA, RB); - /*0x237*/bind_instr(g1f_list, LFSUX, FRD, RA, RB); - static const auto& MULHDO = make_instr<0x249>(g1f_list, "MULHDO", &PPUOpcodes::MULHD, RD, RA, RB, RC); - static const auto& MULHWO = make_instr<0x24b>(g1f_list, "MULHWO", &PPUOpcodes::MULHW, RD, RA, RB, RC); - /*0x255*/bind_instr(g1f_list, LSWI, RD, RA, NB); - /*0x256*/bind_instr(g1f_list, SYNC, L_9_10); - /*0x257*/bind_instr(g1f_list, LFDX, FRD, RA, RB); - /*0x277*/bind_instr(g1f_list, LFDUX, FRD, RA, RB); - /*0x287*/bind_instr(g1f_list, STVLX, VS, RA, RB); - /*0x294*/bind_instr(g1f_list, STDBRX, RD, RA, RB); - /*0x296*/bind_instr(g1f_list, STSWX, RS, RA, RB); - /*0x296*/bind_instr(g1f_list, STWBRX, RS, RA, RB); - /*0x297*/bind_instr(g1f_list, STFSX, FRS, RA, RB); - /*0x2a7*/bind_instr(g1f_list, STVRX, VS, RA, RB); - /*0x2b7*/bind_instr(g1f_list, STFSUX, FRS, RA, RB); - /*0x2d5*/bind_instr(g1f_list, STSWI, RS, RA, NB); - /*0x2d7*/bind_instr(g1f_list, STFDX, FRS, RA, RB); - /*0x2d7*/bind_instr(g1f_list, STFDUX, FRS, RA, RB); - /*0x307*/bind_instr(g1f_list, LVLXL, VD, RA, RB); - /*0x316*/bind_instr(g1f_list, LHBRX, RD, RA, RB); - /*0x318*/bind_instr(g1f_list, SRAW, RA, RS, RB, RC); - /*0x31a*/bind_instr(g1f_list, SRAD, RA, RS, RB, RC); - /*0x327*/bind_instr(g1f_list, LVRXL, VD, RA, RB); - /*0x336*/bind_instr(g1f_list, DSS, STRM, L_6); - /*0x338*/bind_instr(g1f_list, SRAWI, RA, RS, SH, RC); - /*0x33a*/bind_instr(g1f_list, SRADI1, RA, RS, sh, RC); - /*0x33b*/bind_instr(g1f_list, SRADI2, RA, RS, sh, RC); - /*0x356*/bind_instr(g1f_list, EIEIO); - /*0x387*/bind_instr(g1f_list, STVLXL, VS, RA, RB); - /*0x396*/bind_instr(g1f_list, STHBRX, RS, RA, RB); - /*0x39a*/bind_instr(g1f_list, EXTSH, RA, RS, RC); - /*0x387*/bind_instr(g1f_list, STVRXL, VS, RA, RB); - /*0x3ba*/bind_instr(g1f_list, EXTSB, RA, RS, RC); - /*0x3d7*/bind_instr(g1f_list, STFIWX, FRS, RA, RB); - /*0x3da*/bind_instr(g1f_list, EXTSW, RA, RS, RC); - /*0x3d6*/bind_instr(g1f_list, ICBI, RA, RB); - /*0x3f6*/bind_instr(g1f_list, DCBZ, RA, RB); - - bind_instr(g3a_list, LD, RD, RA, DS); - bind_instr(g3a_list, LDU, RD, RA, DS); - bind_instr(g3a_list, LWA, RD, RA, DS); - - bind_instr(g3b_list, FDIVS, FRD, FRA, FRB, RC); - bind_instr(g3b_list, FSUBS, FRD, FRA, FRB, RC); - bind_instr(g3b_list, FADDS, FRD, FRA, FRB, RC); - bind_instr(g3b_list, FSQRTS, FRD, FRB, RC); - bind_instr(g3b_list, FRES, FRD, FRB, RC); - bind_instr(g3b_list, FMULS, FRD, FRA, FRC, RC); - bind_instr(g3b_list, FMADDS, FRD, FRA, FRC, FRB, RC); - bind_instr(g3b_list, FMSUBS, FRD, FRA, FRC, FRB, RC); - bind_instr(g3b_list, FNMSUBS, FRD, FRA, FRC, FRB, RC); - bind_instr(g3b_list, FNMADDS, FRD, FRA, FRC, FRB, RC); - - bind_instr(g3e_list, STD, RS, RA, DS); - bind_instr(g3e_list, STDU, RS, RA, DS); - - bind_instr(g3f_list, FSEL, FRD, FRA, FRC, FRB, RC); - bind_instr(g3f_list, FMUL, FRD, FRA, FRC, RC); - bind_instr(g3f_list, FMSUB, FRD, FRA, FRC, FRB, RC); - bind_instr(g3f_list, FMADD, FRD, FRA, FRC, FRB, RC); - bind_instr(g3f_list, FNMSUB, FRD, FRA, FRC, FRB, RC); - bind_instr(g3f_list, FNMADD, FRD, FRA, FRC, FRB, RC); - - bind_instr(g3f_0_list, FDIV, FRD, FRA, FRB, RC); - bind_instr(g3f_0_list, FSUB, FRD, FRA, FRB, RC); - bind_instr(g3f_0_list, FADD, FRD, FRA, FRB, RC); - bind_instr(g3f_0_list, FSQRT, FRD, FRB, RC); - bind_instr(g3f_0_list, FRSQRTE, FRD, FRB, RC); - bind_instr(g3f_0_list, FCMPU, CRFD, FRA, FRB); - bind_instr(g3f_0_list, FRSP, FRD, FRB, RC); - bind_instr(g3f_0_list, FCTIW, FRD, FRB, RC); - bind_instr(g3f_0_list, FCTIWZ, FRD, FRB, RC); - bind_instr(g3f_0_list, FCMPO, CRFD, FRA, FRB); - bind_instr(g3f_0_list, FNEG, FRD, FRB, RC); - bind_instr(g3f_0_list, FMR, FRD, FRB, RC); - bind_instr(g3f_0_list, FNABS, FRD, FRB, RC); - bind_instr(g3f_0_list, FABS, FRD, FRB, RC); - bind_instr(g3f_0_list, FCFID, FRD, FRB, RC); - bind_instr(g3f_0_list, FCTID, FRD, FRB, RC); - bind_instr(g3f_0_list, FCTIDZ, FRD, FRB, RC); - - bind_instr(g3f_0_list, MTFSB1, CRBD, RC); - bind_instr(g3f_0_list, MCRFS, CRFD, CRFS); - bind_instr(g3f_0_list, MTFSB0, CRBD, RC); - bind_instr(g3f_0_list, MTFSFI, CRFD, I, RC); - bind_instr(g3f_0_list, MFFS, FRD, RC); - bind_instr(g3f_0_list, MTFSF, FM, FRB, RC); - - enum - { - r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, - r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, - r22, r23, r24, r25, r26, r27, r28, r29, r30, r31 - }; - - enum - { - cr0, cr1, cr2, cr3, cr4, cr5, cr6, cr7 - }; - } - - namespace implicts - { - using namespace lists; - - inline u32 LIS(u32 reg, u32 imm) { return ADDIS(reg, r0, imm); } - inline u32 LI_(u32 reg, u32 imm) { return ADDI(reg, r0, imm); } - inline u32 NOP() { return ORI(r0, r0, 0); } - inline u32 MR(u32 x, u32 y) { return OR(x, y, y, false); } - inline u32 BLR() { return BCLR(0x10 | 0x04, 0, 0, 0); } - inline u32 BCTR() { return BCCTR(0x10 | 0x04, 0, 0, 0); } - inline u32 BCTRL() { return BCCTR(0x10 | 0x04, 0, 0, 1); } - inline u32 MFCTR(u32 reg) { return MFSPR(reg, 9 << 5); } - inline u32 MTCTR(u32 reg) { return MTSPR(9 << 5, reg); } - inline u32 MFLR(u32 reg) { return MFSPR(reg, 8 << 5); } - inline u32 MTLR(u32 reg) { return MTSPR(8 << 5, reg); } - - inline u32 BNE(u32 cr, s32 imm) { return BC(4, 2 | cr << 2, imm, 0, 0); } - inline u32 BEQ(u32 cr, s32 imm) { return BC(12, 2 | cr << 2, imm, 0, 0); } - inline u32 BGT(u32 cr, s32 imm) { return BC(12, 1 | cr << 2, imm, 0, 0); } - - inline u32 BNE(s32 imm) { return BNE(cr0, imm); } - inline u32 BEQ(s32 imm) { return BEQ(cr0, imm); } - inline u32 BGT(s32 imm) { return BGT(cr0, imm); } - - inline u32 CMPDI(u32 cr, u32 reg, u32 imm) { return CMPI(cr, 1, reg, imm); } - inline u32 CMPDI(u32 reg, u32 imm) { return CMPDI(cr0, reg, imm); } - - inline u32 CMPWI(u32 cr, u32 reg, u32 imm) { return CMPI(cr, 0, reg, imm); } - inline u32 CMPWI(u32 reg, u32 imm) { return CMPWI(cr0, reg, imm); } - - inline u32 CMPLDI(u32 cr, u32 reg, u32 imm) { return CMPLI(cr, 1, reg, imm); } - inline u32 CMPLDI(u32 reg, u32 imm) { return CMPLDI(cr0, reg, imm); } - - inline u32 CMPLWI(u32 cr, u32 reg, u32 imm) { return CMPLI(cr, 0, reg, imm); } - inline u32 CMPLWI(u32 reg, u32 imm) { return CMPLWI(cr0, reg, imm); } - - inline u32 EXTRDI(u32 x, u32 y, u32 n, u32 b) { return RLDICL(x, y, b + n, 64 - b, false); } - inline u32 SRDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 64 - n, n, false); } - inline u32 CLRLDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 0, n, false); } - } - - using namespace lists; - using namespace implicts; - #undef bind_instr -}; diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp deleted file mode 100644 index d1e621c44d..0000000000 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp +++ /dev/null @@ -1,680 +0,0 @@ -#include "stdafx.h" -#ifdef LLVM_AVAILABLE -#include "Emu/System.h" -#include "Emu/state.h" -#include "Emu/Cell/PPUDisAsm.h" -#include "Emu/Cell/PPULLVMRecompiler.h" -#include "Emu/Memory/Memory.h" -#include "Utilities/VirtualMemory.h" -#ifdef _MSC_VER -#pragma warning(push, 0) -#endif -#include "llvm/Support/TargetSelect.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/ExecutionEngine/GenericValue.h" -#include "llvm/ExecutionEngine/MCJIT.h" -#include "llvm/IR/Intrinsics.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Analysis/Passes.h" -#include "llvm/Analysis/TargetTransformInfo.h" -#include "llvm/Analysis/MemoryDependenceAnalysis.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/Analysis/ScalarEvolution.h" -#include "llvm/IR/Dominators.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/Vectorize.h" -#include "llvm/MC/MCDisassembler.h" -#include "llvm/IR/Verifier.h" -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -using namespace llvm; -using namespace ppu_recompiler_llvm; - -#ifdef ID_MANAGER_INCLUDED -#error "ID Manager cannot be used in this module" -#endif - -// PS3 can address 32 bits aligned on 4 bytes boundaries : 2^30 pointers -#define VIRTUAL_INSTRUCTION_COUNT 0x40000000 -#define PAGE_SIZE 4096 - -u64 Compiler::s_rotate_mask[64][64]; -bool Compiler::s_rotate_mask_inited = false; - -std::unique_ptr Compiler::create_module(LLVMContext &llvm_context) -{ - const std::vector arg_types = { Type::getInt8PtrTy(llvm_context), Type::getInt64Ty(llvm_context) }; - FunctionType *compiled_function_type = FunctionType::get(Type::getInt32Ty(llvm_context), arg_types, false); - - std::unique_ptr result(new llvm::Module("Module", llvm_context)); - Function *execute_unknown_function = (Function *)result->getOrInsertFunction("execute_unknown_function", compiled_function_type); - execute_unknown_function->setCallingConv(CallingConv::X86_64_Win64); - - Function *execute_unknown_block = (Function *)result->getOrInsertFunction("execute_unknown_block", compiled_function_type); - execute_unknown_block->setCallingConv(CallingConv::X86_64_Win64); - - std::string targetTriple = "x86_64-pc-windows-elf"; - result->setTargetTriple(targetTriple); - - return result; -} - -void Compiler::optimise_module(llvm::Module *module) -{ - llvm::FunctionPassManager fpm(module); - fpm.add(createNoAAPass()); - fpm.add(createBasicAliasAnalysisPass()); - fpm.add(createNoTargetTransformInfoPass()); - fpm.add(createEarlyCSEPass()); - fpm.add(createTailCallEliminationPass()); - fpm.add(createReassociatePass()); - fpm.add(createInstructionCombiningPass()); - fpm.add(new DominatorTreeWrapperPass()); - fpm.add(new MemoryDependenceAnalysis()); - fpm.add(createGVNPass()); - fpm.add(createInstructionCombiningPass()); - fpm.add(new MemoryDependenceAnalysis()); - fpm.add(createDeadStoreEliminationPass()); - fpm.add(new LoopInfo()); - fpm.add(new ScalarEvolution()); - fpm.add(createSLPVectorizerPass()); - fpm.add(createInstructionCombiningPass()); - fpm.add(createCFGSimplificationPass()); - fpm.doInitialization(); - - for (auto I = module->begin(), E = module->end(); I != E; ++I) - fpm.run(*I); -} - - -Compiler::Compiler(LLVMContext *context, llvm::IRBuilder<> *builder, std::unordered_map &function_ptrs) - : m_llvm_context(context), - m_ir_builder(builder), - m_executable_map(function_ptrs) { - - std::vector arg_types; - arg_types.push_back(m_ir_builder->getInt8PtrTy()); - arg_types.push_back(m_ir_builder->getInt64Ty()); - m_compiled_function_type = FunctionType::get(m_ir_builder->getInt32Ty(), arg_types, false); - - if (!s_rotate_mask_inited) { - InitRotateMask(); - s_rotate_mask_inited = true; - } -} - -Compiler::~Compiler() { -} - -void Compiler::initiate_function(const std::string &name) -{ - m_state.function = (Function *)m_module->getOrInsertFunction(name, m_compiled_function_type); - m_state.function->setCallingConv(CallingConv::X86_64_Win64); - auto arg_i = m_state.function->arg_begin(); - arg_i->setName("ppu_state"); - m_state.args[CompileTaskState::Args::State] = arg_i; - (++arg_i)->setName("context"); - m_state.args[CompileTaskState::Args::Context] = arg_i; -} - -void ppu_recompiler_llvm::Compiler::translate_to_llvm_ir(llvm::Module *module, const std::string & name, u32 start_address, u32 instruction_count) -{ - m_module = module; - - m_execute_unknown_function = module->getFunction("execute_unknown_function"); - m_execute_unknown_block = module->getFunction("execute_unknown_block"); - - initiate_function(name); - - // Create the entry block and add code to branch to the first instruction - m_ir_builder->SetInsertPoint(GetBasicBlockFromAddress(0)); - m_ir_builder->CreateBr(GetBasicBlockFromAddress(start_address)); - - // Convert each instruction in the CFG to LLVM IR - std::vector exit_instr_list; - for (u32 instructionAddress = start_address; instructionAddress < start_address + instruction_count * 4; instructionAddress += 4) { - m_state.hit_branch_instruction = false; - m_state.current_instruction_address = instructionAddress; - BasicBlock *instr_bb = GetBasicBlockFromAddress(instructionAddress); - m_ir_builder->SetInsertPoint(instr_bb); - - u32 instr = vm::ps3::read32(instructionAddress); - - Decode(instr); - if (!m_state.hit_branch_instruction) - m_ir_builder->CreateBr(GetBasicBlockFromAddress(instructionAddress + 4)); - } - - // Generate exit logic for all empty blocks - const std::string &default_exit_block_name = GetBasicBlockNameFromAddress(0xFFFFFFFF); - for (BasicBlock &block_i : *m_state.function) { - if (!block_i.getInstList().empty() || block_i.getName() == default_exit_block_name) - continue; - - // Found an empty block - m_state.current_instruction_address = GetAddressFromBasicBlockName(block_i.getName()); - - m_ir_builder->SetInsertPoint(&block_i); - PHINode *exit_instr_i32 = m_ir_builder->CreatePHI(m_ir_builder->getInt32Ty(), 0); - exit_instr_list.push_back(exit_instr_i32); - - SetPc(m_ir_builder->getInt32(m_state.current_instruction_address)); - - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusBlockEnded)); - } - - // If the function has a default exit block then generate code for it - BasicBlock *default_exit_bb = GetBasicBlockFromAddress(0xFFFFFFFF, "", false); - if (default_exit_bb) { - m_ir_builder->SetInsertPoint(default_exit_bb); - PHINode *exit_instr_i32 = m_ir_builder->CreatePHI(m_ir_builder->getInt32Ty(), 0); - exit_instr_list.push_back(exit_instr_i32); - - m_ir_builder->CreateRet(m_ir_builder->getInt32(0)); - } - - // Add incoming values for all exit instr PHI nodes - for (PHINode *exit_instr_i : exit_instr_list) { - BasicBlock *block = exit_instr_i->getParent(); - for (pred_iterator pred_i = pred_begin(block); pred_i != pred_end(block); pred_i++) { - u32 pred_address = GetAddressFromBasicBlockName((*pred_i)->getName()); - exit_instr_i->addIncoming(m_ir_builder->getInt32(pred_address), *pred_i); - } - } - - std::string verify; - raw_string_ostream verify_ostream(verify); - if (verifyFunction(*m_state.function, &verify_ostream)) { -// m_recompilation_engine.trace() << "Verification failed: " << verify_ostream.str() << "\n"; - } - - m_module = nullptr; - m_state.function = nullptr; -} - -void Compiler::Decode(const u32 code) { - (*PPU_instr::main_list)(this, code); -} - -std::mutex RecompilationEngine::s_mutex; -std::shared_ptr RecompilationEngine::s_the_instance = nullptr; - -RecompilationEngine::RecompilationEngine() - : m_log(nullptr) - , m_currentId(0) - , m_last_cache_clear_time(std::chrono::high_resolution_clock::now()) - , m_llvm_context(getGlobalContext()) - , m_ir_builder(getGlobalContext()) { - InitializeNativeTarget(); - InitializeNativeTargetAsmPrinter(); - InitializeNativeTargetDisassembler(); - - FunctionCache = (ExecutableStorageType *)memory_helper::reserve_memory(VIRTUAL_INSTRUCTION_COUNT * sizeof(ExecutableStorageType)); - // Each char can store 8 page status - FunctionCachePagesCommited = (char *)malloc(VIRTUAL_INSTRUCTION_COUNT / (8 * PAGE_SIZE)); - if (FunctionCachePagesCommited == nullptr) - throw EXCEPTION("Memory error"); - memset(FunctionCachePagesCommited, 0, VIRTUAL_INSTRUCTION_COUNT / (8 * PAGE_SIZE)); -} - -RecompilationEngine::~RecompilationEngine() { - m_executable_storage.clear(); - memory_helper::free_reserved_memory(FunctionCache, VIRTUAL_INSTRUCTION_COUNT * sizeof(ExecutableStorageType)); - free(FunctionCachePagesCommited); -} - -bool RecompilationEngine::isAddressCommited(u32 address) const -{ - size_t offset = address * sizeof(ExecutableStorageType); - size_t page = offset / 4096; - // Since bool is stored in char, the char index is page / 8 (or page >> 3) - // and we shr the value with the remaining bits (page & 7) - return (FunctionCachePagesCommited[page >> 3] >> (page & 7)) & 1; -} - -void RecompilationEngine::commitAddress(u32 address) -{ - size_t offset = address * sizeof(ExecutableStorageType); - size_t page = offset / 4096; - memory_helper::commit_page_memory((u8*)FunctionCache + page * 4096, 4096); - // Reverse of isAddressCommited : we set the (page & 7)th bit of (page / 8) th char - // in the array - FunctionCachePagesCommited[page >> 3] |= (1 << (page & 7)); -} - -const Executable RecompilationEngine::GetCompiledExecutableIfAvailable(u32 address) const -{ - if (!isAddressCommited(address / 4)) - return nullptr; - u32 id = FunctionCache[address / 4].second; - if (rpcs3::state.config.core.llvm.exclusion_range.value() && - (id >= rpcs3::state.config.core.llvm.min_id.value() && id <= rpcs3::state.config.core.llvm.max_id.value())) - return nullptr; - return FunctionCache[address / 4].first; -} - -void RecompilationEngine::NotifyBlockStart(u32 address) { - { - std::lock_guard lock(m_pending_address_start_lock); - if (m_pending_address_start.size() > 10000) - m_pending_address_start.clear(); - m_pending_address_start.push_back(address); - } - - if (!is_started()) { - start(); - } - - cv.notify_one(); - // TODO: Increase the priority of the recompilation engine thread -} - -raw_fd_ostream & RecompilationEngine::Log() { - if (!m_log) { - std::error_code error; - m_log = new raw_fd_ostream("PPULLVMRecompiler.log", error, sys::fs::F_Text); - m_log->SetUnbuffered(); - } - - return *m_log; -} - -void RecompilationEngine::on_task() { - std::chrono::nanoseconds idling_time(0); - std::chrono::nanoseconds recompiling_time(0); - - auto start = std::chrono::high_resolution_clock::now(); - while (!Emu.IsStopped()) { - bool work_done_this_iteration = false; - std::list m_current_execution_traces; - - { - std::lock_guard lock(m_pending_address_start_lock); - m_current_execution_traces.swap(m_pending_address_start); - } - - if (!m_current_execution_traces.empty()) { - for (u32 address : m_current_execution_traces) - work_done_this_iteration |= IncreaseHitCounterAndBuild(address); - } - - if (!work_done_this_iteration) { - // Wait a few ms for something to happen - auto idling_start = std::chrono::high_resolution_clock::now(); - std::unique_lock lock(mutex); - cv.wait_for(lock, std::chrono::milliseconds(10)); - auto idling_end = std::chrono::high_resolution_clock::now(); - idling_time += std::chrono::duration_cast(idling_end - idling_start); - } - } - - s_the_instance = nullptr; // Can cause deadlock if this is the last instance. Need to fix this. -} - -bool RecompilationEngine::IncreaseHitCounterAndBuild(u32 address) { - auto It = m_block_table.find(address); - if (It == m_block_table.end()) - It = m_block_table.emplace(address, BlockEntry(address)).first; - BlockEntry &block = It->second; - if (!block.is_compiled) { - block.num_hits++; - if (block.num_hits >= rpcs3::state.config.core.llvm.threshold.value()) { - CompileBlock(block); - return true; - } - } - return false; -} - -extern void execute_ppu_func_by_index(PPUThread& ppu, u32 id); -extern void execute_syscall_by_index(PPUThread& ppu, u64 code); - -static u32 -wrappedExecutePPUFuncByIndex(PPUThread &CPU, u32 index) noexcept { - try - { - execute_ppu_func_by_index(CPU, index); - return ExecutionStatus::ExecutionStatusBlockEnded; - } - catch (...) - { - CPU.pending_exception = std::current_exception(); - return ExecutionStatus::ExecutionStatusPropagateException; - } -} - -static u32 wrappedDoSyscall(PPUThread &CPU, u64 code) noexcept { - try - { - execute_syscall_by_index(CPU, code); - return ExecutionStatus::ExecutionStatusBlockEnded; - } - catch (...) - { - CPU.pending_exception = std::current_exception(); - return ExecutionStatus::ExecutionStatusPropagateException; - } -} - -static void wrapped_fast_stop(PPUThread &CPU) -{ - CPU.fast_stop(); -} - -static void wrapped_trap(PPUThread &CPU, u32) noexcept { - try - { - throw EXCEPTION("trap"); - } - catch (...) - { - CPU.pending_exception = std::current_exception(); - } -} - -std::pair RecompilationEngine::compile(const std::string & name, u32 start_address, u32 instruction_count) { - std::unique_ptr module = Compiler::create_module(m_llvm_context); - - std::unordered_map function_ptrs; - function_ptrs["execute_unknown_function"] = reinterpret_cast(CPUHybridDecoderRecompiler::ExecuteFunction); - function_ptrs["execute_unknown_block"] = reinterpret_cast(CPUHybridDecoderRecompiler::ExecuteTillReturn); - function_ptrs["PollStatus"] = reinterpret_cast(CPUHybridDecoderRecompiler::PollStatus); - function_ptrs["PPUThread.fast_stop"] = reinterpret_cast(wrapped_fast_stop); - function_ptrs["vm.reservation_acquire"] = reinterpret_cast(vm::reservation_acquire); - function_ptrs["vm.reservation_update"] = reinterpret_cast(vm::reservation_update); - function_ptrs["get_timebased_time"] = reinterpret_cast(get_timebased_time); - function_ptrs["wrappedExecutePPUFuncByIndex"] = reinterpret_cast(wrappedExecutePPUFuncByIndex); - function_ptrs["wrappedDoSyscall"] = reinterpret_cast(wrappedDoSyscall); - function_ptrs["trap"] = reinterpret_cast(wrapped_trap); - -#define REGISTER_FUNCTION_PTR(name) \ - function_ptrs[#name] = reinterpret_cast(PPUInterpreter::name##_impl); - - MACRO_PPU_INST_MAIN_EXPANDERS(REGISTER_FUNCTION_PTR) - MACRO_PPU_INST_G_13_EXPANDERS(REGISTER_FUNCTION_PTR) - MACRO_PPU_INST_G_1E_EXPANDERS(REGISTER_FUNCTION_PTR) - MACRO_PPU_INST_G_1F_EXPANDERS(REGISTER_FUNCTION_PTR) - MACRO_PPU_INST_G_3A_EXPANDERS(REGISTER_FUNCTION_PTR) - MACRO_PPU_INST_G_3E_EXPANDERS(REGISTER_FUNCTION_PTR) - - Compiler(&m_llvm_context, &m_ir_builder, function_ptrs) - .translate_to_llvm_ir(module.get(), name, start_address, instruction_count); - - llvm::Module *module_ptr = module.get(); - - Log() << *module_ptr; - Compiler::optimise_module(module_ptr); - - llvm::ExecutionEngine *execution_engine = - EngineBuilder(std::move(module)) - .setEngineKind(EngineKind::JIT) - .setMCJITMemoryManager(std::unique_ptr(new CustomSectionMemoryManager(function_ptrs))) - .setOptLevel(llvm::CodeGenOpt::Aggressive) - .setMCPU("nehalem") - .create(); - module_ptr->setDataLayout(execution_engine->getDataLayout()); - - // Translate to machine code - execution_engine->finalizeObject(); - - Function *llvm_function = module_ptr->getFunction(name); - void *function = execution_engine->getPointerToFunction(llvm_function); - - /* m_recompilation_engine.trace() << "\nDisassembly:\n"; - auto disassembler = LLVMCreateDisasm(sys::getProcessTriple().c_str(), nullptr, 0, nullptr, nullptr); - for (size_t pc = 0; pc < mci.size();) { - char str[1024]; - - auto size = LLVMDisasmInstruction(disassembler, ((u8 *)mci.address()) + pc, mci.size() - pc, (uint64_t)(((u8 *)mci.address()) + pc), str, sizeof(str)); - m_recompilation_engine.trace() << fmt::format("0x%08X: ", (u64)(((u8 *)mci.address()) + pc)) << str << '\n'; - pc += size; - } - - LLVMDisasmDispose(disassembler);*/ - - assert(function != nullptr); - return std::make_pair((Executable)function, execution_engine); -} - -/** -* This code is inspired from Dolphin PPC Analyst -*/ -inline s32 SignExt16(s16 x) { return (s32)(s16)x; } -inline s32 SignExt26(u32 x) { return x & 0x2000000 ? (s32)(x | 0xFC000000) : (s32)(x); } - -bool RecompilationEngine::AnalyseBlock(BlockEntry &functionData, size_t maxSize) -{ - u32 startAddress = functionData.address; - u32 farthestBranchTarget = startAddress; - functionData.instructionCount = 0; - functionData.calledFunctions.clear(); - functionData.is_analysed = true; - functionData.is_compilable_function = true; - Log() << "Analysing " << (void*)(uint64_t)startAddress << "hit " << functionData.num_hits << "\n"; - // Used to decode instructions - PPUDisAsm dis_asm(CPUDisAsm_DumpMode); - dis_asm.offset = vm::ps3::_ptr(startAddress); - for (u32 instructionAddress = startAddress; instructionAddress < startAddress + maxSize; instructionAddress += 4) - { - u32 instr = vm::ps3::read32((u32)instructionAddress); - - dis_asm.dump_pc = instructionAddress - startAddress; - (*PPU_instr::main_list)(&dis_asm, instr); - Log() << dis_asm.last_opcode; - functionData.instructionCount++; - if (instr == PPU_instr::implicts::BLR() && instructionAddress >= farthestBranchTarget && functionData.is_compilable_function) - { - Log() << "Analysis: Block is compilable into a function \n"; - return true; - } - else if (PPU_instr::fields::GD_13(instr) == PPU_opcodes::G_13Opcodes::BCCTR) - { - if (!PPU_instr::fields::LK(instr)) - { - Log() << "Analysis: indirect branching found \n"; - functionData.is_compilable_function = false; - return true; - } - } - else if (PPU_instr::fields::OPCD(instr) == PPU_opcodes::PPU_MainOpcodes::BC) - { - u32 target = SignExt16(PPU_instr::fields::BD(instr)); - if (!PPU_instr::fields::AA(instr)) // Absolute address - target += (u32)instructionAddress; - if (target > farthestBranchTarget && !PPU_instr::fields::LK(instr)) - farthestBranchTarget = target; - } - else if (PPU_instr::fields::OPCD(instr) == PPU_opcodes::PPU_MainOpcodes::B) - { - u32 target = SignExt26(PPU_instr::fields::LL(instr)); - if (!PPU_instr::fields::AA(instr)) // Absolute address - target += (u32)instructionAddress; - - if (!PPU_instr::fields::LK(instr)) - { - if (target < startAddress) - { - Log() << "Analysis: branch to previous block\n"; - functionData.is_compilable_function = false; - return true; - } - else if (target > farthestBranchTarget) - farthestBranchTarget = target; - } - else - functionData.calledFunctions.insert(target); - } - } - Log() << "Analysis: maxSize reached \n"; - functionData.is_compilable_function = false; - return true; -} - -void RecompilationEngine::CompileBlock(BlockEntry & block_entry) { - if (block_entry.is_analysed) - return; - - if (!AnalyseBlock(block_entry)) - return; - Log() << "Compile: " << block_entry.ToString() << "\n"; - - { - // We create a lock here so that data are properly stored at the end of the function. - /// Lock for accessing compiler - std::mutex local_mutex; - std::unique_lock lock(local_mutex); - - const std::pair &compileResult = - compile(fmt::format("fn_0x%08X", block_entry.address), block_entry.address, block_entry.instructionCount); - - if (!isAddressCommited(block_entry.address / 4)) - commitAddress(block_entry.address / 4); - - m_executable_storage.push_back(std::unique_ptr(compileResult.second)); - Log() << "Associating " << (void*)(uint64_t)block_entry.address << " with ID " << m_currentId << "\n"; - FunctionCache[block_entry.address / 4] = std::make_pair(compileResult.first, m_currentId); - m_currentId++; - block_entry.is_compiled = true; - } -} - -std::shared_ptr RecompilationEngine::GetInstance() { - std::lock_guard lock(s_mutex); - - if (s_the_instance == nullptr) { - s_the_instance = std::shared_ptr(new RecompilationEngine()); - } - - return s_the_instance; -} - -ppu_recompiler_llvm::CPUHybridDecoderRecompiler::CPUHybridDecoderRecompiler(PPUThread & ppu) - : m_ppu(ppu) - , m_interpreter(new PPUInterpreter(ppu)) - , m_decoder(m_interpreter) - , m_recompilation_engine(RecompilationEngine::GetInstance()) { -} - -ppu_recompiler_llvm::CPUHybridDecoderRecompiler::~CPUHybridDecoderRecompiler() { -} - -u32 ppu_recompiler_llvm::CPUHybridDecoderRecompiler::DecodeMemory(const u32 address) { - ExecuteFunction(&m_ppu, 0); - if (m_ppu.pending_exception != nullptr) { - std::exception_ptr exn = m_ppu.pending_exception; - m_ppu.pending_exception = nullptr; - std::rethrow_exception(exn); - } - return 0; -} - -u32 ppu_recompiler_llvm::CPUHybridDecoderRecompiler::ExecuteFunction(PPUThread * ppu_state, u64 context) { - auto execution_engine = (CPUHybridDecoderRecompiler *)ppu_state->GetDecoder(); - if (ExecuteTillReturn(ppu_state, 0) == ExecutionStatus::ExecutionStatusPropagateException) - return ExecutionStatus::ExecutionStatusPropagateException; - return ExecutionStatus::ExecutionStatusReturn; -} - -/// Get the branch type from a branch instruction -static BranchType GetBranchTypeFromInstruction(u32 instruction) -{ - u32 instructionOpcode = PPU_instr::fields::OPCD(instruction); - u32 lk = instruction & 1; - - if (instructionOpcode == PPU_opcodes::PPU_MainOpcodes::B || - instructionOpcode == PPU_opcodes::PPU_MainOpcodes::BC) - return lk ? BranchType::FunctionCall : BranchType::LocalBranch; - if (instructionOpcode == PPU_opcodes::PPU_MainOpcodes::G_13) { - u32 G13Opcode = PPU_instr::fields::GD_13(instruction); - if (G13Opcode == PPU_opcodes::G_13Opcodes::BCLR) - return lk ? BranchType::FunctionCall : BranchType::Return; - if (G13Opcode == PPU_opcodes::G_13Opcodes::BCCTR) - return lk ? BranchType::FunctionCall : BranchType::LocalBranch; - return BranchType::NonBranch; - } - if (instructionOpcode == PPU_opcodes::PPU_MainOpcodes::HACK && (instruction & EIF_PERFORM_BLR)) // classify HACK instruction - return instruction & EIF_USE_BRANCH ? BranchType::FunctionCall : BranchType::Return; - if (instructionOpcode == PPU_opcodes::PPU_MainOpcodes::HACK && (instruction & EIF_USE_BRANCH)) - return BranchType::LocalBranch; - return BranchType::NonBranch; -} - -u32 ppu_recompiler_llvm::CPUHybridDecoderRecompiler::ExecuteTillReturn(PPUThread * ppu_state, u64 context) { - CPUHybridDecoderRecompiler *execution_engine = (CPUHybridDecoderRecompiler *)ppu_state->GetDecoder(); - - // A block is a sequence of contiguous address. - bool previousInstContigousAndInterp = false; - - while (PollStatus(ppu_state) == false) { - const Executable executable = execution_engine->m_recompilation_engine->GetCompiledExecutableIfAvailable(ppu_state->PC); - if (executable) - { - auto entry = ppu_state->PC; - u32 exit = (u32)executable(ppu_state, 0); - if (exit == ExecutionStatus::ExecutionStatusReturn) - { - if (Emu.GetCPUThreadStop() == ppu_state->PC) ppu_state->fast_stop(); - return ExecutionStatus::ExecutionStatusReturn; - } - if (exit == ExecutionStatus::ExecutionStatusPropagateException) - return ExecutionStatus::ExecutionStatusPropagateException; - previousInstContigousAndInterp = false; - continue; - } - // if previousInstContigousAndInterp is true, ie previous step was either a compiled block or a branch inst - // that caused a "gap" in instruction flow, we notify a new block. - if (!previousInstContigousAndInterp) - execution_engine->m_recompilation_engine->NotifyBlockStart(ppu_state->PC); - u32 instruction = vm::ps3::read32(ppu_state->PC); - u32 oldPC = ppu_state->PC; - try - { - execution_engine->m_decoder.Decode(instruction); - } - catch (...) - { - ppu_state->pending_exception = std::current_exception(); - return ExecutionStatus::ExecutionStatusPropagateException; - } - previousInstContigousAndInterp = (oldPC == ppu_state->PC); - auto branch_type = ppu_state->PC != oldPC ? GetBranchTypeFromInstruction(instruction) : BranchType::NonBranch; - ppu_state->PC += 4; - - switch (branch_type) { - case BranchType::Return: - if (Emu.GetCPUThreadStop() == ppu_state->PC) ppu_state->fast_stop(); - return 0; - case BranchType::FunctionCall: { - u32 status = ExecuteFunction(ppu_state, 0); - if (status == ExecutionStatus::ExecutionStatusPropagateException) - return ExecutionStatus::ExecutionStatusPropagateException; - break; - } - case BranchType::LocalBranch: - break; - case BranchType::NonBranch: - break; - default: - assert(0); - break; - } - } - - return 0; -} - -bool ppu_recompiler_llvm::CPUHybridDecoderRecompiler::PollStatus(PPUThread * ppu_state) { - try - { - return ppu_state->check_status(); - } - catch (...) - { - ppu_state->pending_exception = std::current_exception(); - return true; - } -} -#endif // LLVM_AVAILABLE diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.h b/rpcs3/Emu/Cell/PPULLVMRecompiler.h deleted file mode 100644 index 1b882f68d5..0000000000 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.h +++ /dev/null @@ -1,946 +0,0 @@ -#ifndef PPU_LLVM_RECOMPILER_H -#define PPU_LLVM_RECOMPILER_H - -#ifdef LLVM_AVAILABLE -#define PPU_LLVM_RECOMPILER 1 - -#include -#include "Emu/Cell/PPUDecoder.h" -#include "Emu/Cell/PPUThread.h" -#include "Emu/Cell/PPUInterpreter.h" -#ifdef _MSC_VER -#pragma warning(push, 0) -#endif -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/SectionMemoryManager.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/GlobalVariable.h" -#include "llvm/PassManager.h" -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -namespace ppu_recompiler_llvm { - enum ExecutionStatus - { - ExecutionStatusReturn = 0, ///< Block has hit a return, caller can continue execution - ExecutionStatusBlockEnded, ///< Block has been executed but no return was hit, at least another block must be executed before caller can continue - ExecutionStatusPropagateException, ///< an exception was thrown - }; - - class Compiler; - class RecompilationEngine; - class ExecutionEngine; - struct PPUState; - - enum class BranchType { - NonBranch, - LocalBranch, - FunctionCall, - Return, - }; - - /// Pointer to an executable - typedef u32(*Executable)(PPUThread * ppu_state, u64 context); - - /// Parses PPU opcodes and translate them into llvm ir. - class Compiler : protected PPUOpcodes, protected PPCDecoder { - public: - Compiler(llvm::LLVMContext *context, llvm::IRBuilder<> *builder, std::unordered_map &function_ptrs); - - Compiler(const Compiler&) = delete; // Delete copy/move constructors and copy/move operators - - virtual ~Compiler(); - - /// Create a module setting target triples and some callbacks - static std::unique_ptr create_module(llvm::LLVMContext &llvm_context); - - /// Create a function called name in module and populates it by translating block at start_address with instruction_count length. - void translate_to_llvm_ir(llvm::Module *module, const std::string & name, u32 start_address, u32 instruction_count); - - static void optimise_module(llvm::Module *module); - - protected: - void Decode(const u32 code) override; - - void NULL_OP() override; - void NOP() override; - - void TDI(u32 to, u32 ra, s32 simm16) override; - void TWI(u32 to, u32 ra, s32 simm16) override; - - void MFVSCR(u32 vd) override; - void MTVSCR(u32 vb) override; - void VADDCUW(u32 vd, u32 va, u32 vb) override; - void VADDFP(u32 vd, u32 va, u32 vb) override; - void VADDSBS(u32 vd, u32 va, u32 vb) override; - void VADDSHS(u32 vd, u32 va, u32 vb) override; - void VADDSWS(u32 vd, u32 va, u32 vb) override; - void VADDUBM(u32 vd, u32 va, u32 vb) override; - void VADDUBS(u32 vd, u32 va, u32 vb) override; - void VADDUHM(u32 vd, u32 va, u32 vb) override; - void VADDUHS(u32 vd, u32 va, u32 vb) override; - void VADDUWM(u32 vd, u32 va, u32 vb) override; - void VADDUWS(u32 vd, u32 va, u32 vb) override; - void VAND(u32 vd, u32 va, u32 vb) override; - void VANDC(u32 vd, u32 va, u32 vb) override; - void VAVGSB(u32 vd, u32 va, u32 vb) override; - void VAVGSH(u32 vd, u32 va, u32 vb) override; - void VAVGSW(u32 vd, u32 va, u32 vb) override; - void VAVGUB(u32 vd, u32 va, u32 vb) override; - void VAVGUH(u32 vd, u32 va, u32 vb) override; - void VAVGUW(u32 vd, u32 va, u32 vb) override; - void VCFSX(u32 vd, u32 uimm5, u32 vb) override; - void VCFUX(u32 vd, u32 uimm5, u32 vb) override; - void VCMPBFP(u32 vd, u32 va, u32 vb) override; - void VCMPBFP_(u32 vd, u32 va, u32 vb) override; - void VCMPEQFP(u32 vd, u32 va, u32 vb) override; - void VCMPEQFP_(u32 vd, u32 va, u32 vb) override; - void VCMPEQUB(u32 vd, u32 va, u32 vb) override; - void VCMPEQUB_(u32 vd, u32 va, u32 vb) override; - void VCMPEQUH(u32 vd, u32 va, u32 vb) override; - void VCMPEQUH_(u32 vd, u32 va, u32 vb) override; - void VCMPEQUW(u32 vd, u32 va, u32 vb) override; - void VCMPEQUW_(u32 vd, u32 va, u32 vb) override; - void VCMPGEFP(u32 vd, u32 va, u32 vb) override; - void VCMPGEFP_(u32 vd, u32 va, u32 vb) override; - void VCMPGTFP(u32 vd, u32 va, u32 vb) override; - void VCMPGTFP_(u32 vd, u32 va, u32 vb) override; - void VCMPGTSB(u32 vd, u32 va, u32 vb) override; - void VCMPGTSB_(u32 vd, u32 va, u32 vb) override; - void VCMPGTSH(u32 vd, u32 va, u32 vb) override; - void VCMPGTSH_(u32 vd, u32 va, u32 vb) override; - void VCMPGTSW(u32 vd, u32 va, u32 vb) override; - void VCMPGTSW_(u32 vd, u32 va, u32 vb) override; - void VCMPGTUB(u32 vd, u32 va, u32 vb) override; - void VCMPGTUB_(u32 vd, u32 va, u32 vb) override; - void VCMPGTUH(u32 vd, u32 va, u32 vb) override; - void VCMPGTUH_(u32 vd, u32 va, u32 vb) override; - void VCMPGTUW(u32 vd, u32 va, u32 vb) override; - void VCMPGTUW_(u32 vd, u32 va, u32 vb) override; - void VCTSXS(u32 vd, u32 uimm5, u32 vb) override; - void VCTUXS(u32 vd, u32 uimm5, u32 vb) override; - void VEXPTEFP(u32 vd, u32 vb) override; - void VLOGEFP(u32 vd, u32 vb) override; - void VMADDFP(u32 vd, u32 va, u32 vc, u32 vb) override; - void VMAXFP(u32 vd, u32 va, u32 vb) override; - void VMAXSB(u32 vd, u32 va, u32 vb) override; - void VMAXSH(u32 vd, u32 va, u32 vb) override; - void VMAXSW(u32 vd, u32 va, u32 vb) override; - void VMAXUB(u32 vd, u32 va, u32 vb) override; - void VMAXUH(u32 vd, u32 va, u32 vb) override; - void VMAXUW(u32 vd, u32 va, u32 vb) override; - void VMHADDSHS(u32 vd, u32 va, u32 vb, u32 vc) override; - void VMHRADDSHS(u32 vd, u32 va, u32 vb, u32 vc) override; - void VMINFP(u32 vd, u32 va, u32 vb) override; - void VMINSB(u32 vd, u32 va, u32 vb) override; - void VMINSH(u32 vd, u32 va, u32 vb) override; - void VMINSW(u32 vd, u32 va, u32 vb) override; - void VMINUB(u32 vd, u32 va, u32 vb) override; - void VMINUH(u32 vd, u32 va, u32 vb) override; - void VMINUW(u32 vd, u32 va, u32 vb) override; - void VMLADDUHM(u32 vd, u32 va, u32 vb, u32 vc) override; - void VMRGHB(u32 vd, u32 va, u32 vb) override; - void VMRGHH(u32 vd, u32 va, u32 vb) override; - void VMRGHW(u32 vd, u32 va, u32 vb) override; - void VMRGLB(u32 vd, u32 va, u32 vb) override; - void VMRGLH(u32 vd, u32 va, u32 vb) override; - void VMRGLW(u32 vd, u32 va, u32 vb) override; - void VMSUMMBM(u32 vd, u32 va, u32 vb, u32 vc) override; - void VMSUMSHM(u32 vd, u32 va, u32 vb, u32 vc) override; - void VMSUMSHS(u32 vd, u32 va, u32 vb, u32 vc) override; - void VMSUMUBM(u32 vd, u32 va, u32 vb, u32 vc) override; - void VMSUMUHM(u32 vd, u32 va, u32 vb, u32 vc) override; - void VMSUMUHS(u32 vd, u32 va, u32 vb, u32 vc) override; - void VMULESB(u32 vd, u32 va, u32 vb) override; - void VMULESH(u32 vd, u32 va, u32 vb) override; - void VMULEUB(u32 vd, u32 va, u32 vb) override; - void VMULEUH(u32 vd, u32 va, u32 vb) override; - void VMULOSB(u32 vd, u32 va, u32 vb) override; - void VMULOSH(u32 vd, u32 va, u32 vb) override; - void VMULOUB(u32 vd, u32 va, u32 vb) override; - void VMULOUH(u32 vd, u32 va, u32 vb) override; - void VNMSUBFP(u32 vd, u32 va, u32 vc, u32 vb) override; - void VNOR(u32 vd, u32 va, u32 vb) override; - void VOR(u32 vd, u32 va, u32 vb) override; - void VPERM(u32 vd, u32 va, u32 vb, u32 vc) override; - void VPKPX(u32 vd, u32 va, u32 vb) override; - void VPKSHSS(u32 vd, u32 va, u32 vb) override; - void VPKSHUS(u32 vd, u32 va, u32 vb) override; - void VPKSWSS(u32 vd, u32 va, u32 vb) override; - void VPKSWUS(u32 vd, u32 va, u32 vb) override; - void VPKUHUM(u32 vd, u32 va, u32 vb) override; - void VPKUHUS(u32 vd, u32 va, u32 vb) override; - void VPKUWUM(u32 vd, u32 va, u32 vb) override; - void VPKUWUS(u32 vd, u32 va, u32 vb) override; - void VREFP(u32 vd, u32 vb) override; - void VRFIM(u32 vd, u32 vb) override; - void VRFIN(u32 vd, u32 vb) override; - void VRFIP(u32 vd, u32 vb) override; - void VRFIZ(u32 vd, u32 vb) override; - void VRLB(u32 vd, u32 va, u32 vb) override; - void VRLH(u32 vd, u32 va, u32 vb) override; - void VRLW(u32 vd, u32 va, u32 vb) override; - void VRSQRTEFP(u32 vd, u32 vb) override; - void VSEL(u32 vd, u32 va, u32 vb, u32 vc) override; - void VSL(u32 vd, u32 va, u32 vb) override; - void VSLB(u32 vd, u32 va, u32 vb) override; - void VSLDOI(u32 vd, u32 va, u32 vb, u32 sh) override; - void VSLH(u32 vd, u32 va, u32 vb) override; - void VSLO(u32 vd, u32 va, u32 vb) override; - void VSLW(u32 vd, u32 va, u32 vb) override; - void VSPLTB(u32 vd, u32 uimm5, u32 vb) override; - void VSPLTH(u32 vd, u32 uimm5, u32 vb) override; - void VSPLTISB(u32 vd, s32 simm5) override; - void VSPLTISH(u32 vd, s32 simm5) override; - void VSPLTISW(u32 vd, s32 simm5) override; - void VSPLTW(u32 vd, u32 uimm5, u32 vb) override; - void VSR(u32 vd, u32 va, u32 vb) override; - void VSRAB(u32 vd, u32 va, u32 vb) override; - void VSRAH(u32 vd, u32 va, u32 vb) override; - void VSRAW(u32 vd, u32 va, u32 vb) override; - void VSRB(u32 vd, u32 va, u32 vb) override; - void VSRH(u32 vd, u32 va, u32 vb) override; - void VSRO(u32 vd, u32 va, u32 vb) override; - void VSRW(u32 vd, u32 va, u32 vb) override; - void VSUBCUW(u32 vd, u32 va, u32 vb) override; - void VSUBFP(u32 vd, u32 va, u32 vb) override; - void VSUBSBS(u32 vd, u32 va, u32 vb) override; - void VSUBSHS(u32 vd, u32 va, u32 vb) override; - void VSUBSWS(u32 vd, u32 va, u32 vb) override; - void VSUBUBM(u32 vd, u32 va, u32 vb) override; - void VSUBUBS(u32 vd, u32 va, u32 vb) override; - void VSUBUHM(u32 vd, u32 va, u32 vb) override; - void VSUBUHS(u32 vd, u32 va, u32 vb) override; - void VSUBUWM(u32 vd, u32 va, u32 vb) override; - void VSUBUWS(u32 vd, u32 va, u32 vb) override; - void VSUMSWS(u32 vd, u32 va, u32 vb) override; - void VSUM2SWS(u32 vd, u32 va, u32 vb) override; - void VSUM4SBS(u32 vd, u32 va, u32 vb) override; - void VSUM4SHS(u32 vd, u32 va, u32 vb) override; - void VSUM4UBS(u32 vd, u32 va, u32 vb) override; - void VUPKHPX(u32 vd, u32 vb) override; - void VUPKHSB(u32 vd, u32 vb) override; - void VUPKHSH(u32 vd, u32 vb) override; - void VUPKLPX(u32 vd, u32 vb) override; - void VUPKLSB(u32 vd, u32 vb) override; - void VUPKLSH(u32 vd, u32 vb) override; - void VXOR(u32 vd, u32 va, u32 vb) override; - void MULLI(u32 rd, u32 ra, s32 simm16) override; - void SUBFIC(u32 rd, u32 ra, s32 simm16) override; - void CMPLI(u32 bf, u32 l, u32 ra, u32 uimm16) override; - void CMPI(u32 bf, u32 l, u32 ra, s32 simm16) override; - void ADDIC(u32 rd, u32 ra, s32 simm16) override; - void ADDIC_(u32 rd, u32 ra, s32 simm16) override; - void ADDI(u32 rd, u32 ra, s32 simm16) override; - void ADDIS(u32 rd, u32 ra, s32 simm16) override; - void BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) override; - void HACK(u32 id) override; - void SC(u32 sc_code) override; - void B(s32 ll, u32 aa, u32 lk) override; - void MCRF(u32 crfd, u32 crfs) override; - void BCLR(u32 bo, u32 bi, u32 bh, u32 lk) override; - void CRNOR(u32 bt, u32 ba, u32 bb) override; - void CRANDC(u32 bt, u32 ba, u32 bb) override; - void ISYNC() override; - void CRXOR(u32 bt, u32 ba, u32 bb) override; - void CRNAND(u32 bt, u32 ba, u32 bb) override; - void CRAND(u32 bt, u32 ba, u32 bb) override; - void CREQV(u32 bt, u32 ba, u32 bb) override; - void CRORC(u32 bt, u32 ba, u32 bb) override; - void CROR(u32 bt, u32 ba, u32 bb) override; - void BCCTR(u32 bo, u32 bi, u32 bh, u32 lk) override; - void RLWIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) override; - void RLWINM(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) override; - void RLWNM(u32 ra, u32 rs, u32 rb, u32 MB, u32 ME, u32 rc) override; - void ORI(u32 rs, u32 ra, u32 uimm16) override; - void ORIS(u32 rs, u32 ra, u32 uimm16) override; - void XORI(u32 ra, u32 rs, u32 uimm16) override; - void XORIS(u32 ra, u32 rs, u32 uimm16) override; - void ANDI_(u32 ra, u32 rs, u32 uimm16) override; - void ANDIS_(u32 ra, u32 rs, u32 uimm16) override; - void RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) override; - void RLDICR(u32 ra, u32 rs, u32 sh, u32 me, u32 rc) override; - void RLDIC(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) override; - void RLDIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) override; - void RLDC_LR(u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc) override; - void CMP(u32 crfd, u32 l, u32 ra, u32 rb) override; - void TW(u32 to, u32 ra, u32 rb) override; - void LVSL(u32 vd, u32 ra, u32 rb) override; - void LVEBX(u32 vd, u32 ra, u32 rb) override; - void SUBFC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void MULHDU(u32 rd, u32 ra, u32 rb, u32 rc) override; - void ADDC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void MULHWU(u32 rd, u32 ra, u32 rb, u32 rc) override; - void MFOCRF(u32 a, u32 rd, u32 crm) override; - void LWARX(u32 rd, u32 ra, u32 rb) override; - void LDX(u32 ra, u32 rs, u32 rb) override; - void LWZX(u32 rd, u32 ra, u32 rb) override; - void SLW(u32 ra, u32 rs, u32 rb, u32 rc) override; - void CNTLZW(u32 ra, u32 rs, u32 rc) override; - void SLD(u32 ra, u32 rs, u32 rb, u32 rc) override; - void AND(u32 ra, u32 rs, u32 rb, u32 rc) override; - void CMPL(u32 bf, u32 l, u32 ra, u32 rb) override; - void LVSR(u32 vd, u32 ra, u32 rb) override; - void LVEHX(u32 vd, u32 ra, u32 rb) override; - void SUBF(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void LDUX(u32 rd, u32 ra, u32 rb) override; - void DCBST(u32 ra, u32 rb) override; - void LWZUX(u32 rd, u32 ra, u32 rb) override; - void CNTLZD(u32 ra, u32 rs, u32 rc) override; - void ANDC(u32 ra, u32 rs, u32 rb, u32 rc) override; - void TD(u32 to, u32 ra, u32 rb) override; - void LVEWX(u32 vd, u32 ra, u32 rb) override; - void MULHD(u32 rd, u32 ra, u32 rb, u32 rc) override; - void MULHW(u32 rd, u32 ra, u32 rb, u32 rc) override; - void LDARX(u32 rd, u32 ra, u32 rb) override; - void DCBF(u32 ra, u32 rb) override; - void LBZX(u32 rd, u32 ra, u32 rb) override; - void LVX(u32 vd, u32 ra, u32 rb) override; - void NEG(u32 rd, u32 ra, u32 oe, u32 rc) override; - void LBZUX(u32 rd, u32 ra, u32 rb) override; - void NOR(u32 ra, u32 rs, u32 rb, u32 rc) override; - void STVEBX(u32 vs, u32 ra, u32 rb) override; - void SUBFE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void ADDE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void MTOCRF(u32 l, u32 crm, u32 rs) override; - void STDX(u32 rs, u32 ra, u32 rb) override; - void STWCX_(u32 rs, u32 ra, u32 rb) override; - void STWX(u32 rs, u32 ra, u32 rb) override; - void STVEHX(u32 vs, u32 ra, u32 rb) override; - void STDUX(u32 rs, u32 ra, u32 rb) override; - void STWUX(u32 rs, u32 ra, u32 rb) override; - void STVEWX(u32 vs, u32 ra, u32 rb) override; - void SUBFZE(u32 rd, u32 ra, u32 oe, u32 rc) override; - void ADDZE(u32 rd, u32 ra, u32 oe, u32 rc) override; - void STDCX_(u32 rs, u32 ra, u32 rb) override; - void STBX(u32 rs, u32 ra, u32 rb) override; - void STVX(u32 vs, u32 ra, u32 rb) override; - void MULLD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void SUBFME(u32 rd, u32 ra, u32 oe, u32 rc) override; - void ADDME(u32 rd, u32 ra, u32 oe, u32 rc) override; - void MULLW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void DCBTST(u32 ra, u32 rb, u32 th) override; - void STBUX(u32 rs, u32 ra, u32 rb) override; - void ADD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void DCBT(u32 ra, u32 rb, u32 th) override; - void LHZX(u32 rd, u32 ra, u32 rb) override; - void EQV(u32 ra, u32 rs, u32 rb, u32 rc) override; - void ECIWX(u32 rd, u32 ra, u32 rb) override; - void LHZUX(u32 rd, u32 ra, u32 rb) override; - void XOR(u32 rs, u32 ra, u32 rb, u32 rc) override; - void MFSPR(u32 rd, u32 spr) override; - void LWAX(u32 rd, u32 ra, u32 rb) override; - void DST(u32 ra, u32 rb, u32 strm, u32 t) override; - void LHAX(u32 rd, u32 ra, u32 rb) override; - void LVXL(u32 vd, u32 ra, u32 rb) override; - void MFTB(u32 rd, u32 spr) override; - void LWAUX(u32 rd, u32 ra, u32 rb) override; - void DSTST(u32 ra, u32 rb, u32 strm, u32 t) override; - void LHAUX(u32 rd, u32 ra, u32 rb) override; - void STHX(u32 rs, u32 ra, u32 rb) override; - void ORC(u32 rs, u32 ra, u32 rb, u32 rc) override; - void ECOWX(u32 rs, u32 ra, u32 rb) override; - void STHUX(u32 rs, u32 ra, u32 rb) override; - void OR(u32 ra, u32 rs, u32 rb, u32 rc) override; - void DIVDU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void DIVWU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void MTSPR(u32 spr, u32 rs) override; - void DCBI(u32 ra, u32 rb) override; - void NAND(u32 ra, u32 rs, u32 rb, u32 rc) override; - void STVXL(u32 vs, u32 ra, u32 rb) override; - void DIVD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void DIVW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override; - void LVLX(u32 vd, u32 ra, u32 rb) override; - void LDBRX(u32 rd, u32 ra, u32 rb) override; - void LSWX(u32 rd, u32 ra, u32 rb) override; - void LWBRX(u32 rd, u32 ra, u32 rb) override; - void LFSX(u32 frd, u32 ra, u32 rb) override; - void SRW(u32 ra, u32 rs, u32 rb, u32 rc) override; - void SRD(u32 ra, u32 rs, u32 rb, u32 rc) override; - void LVRX(u32 vd, u32 ra, u32 rb) override; - void LSWI(u32 rd, u32 ra, u32 nb) override; - void LFSUX(u32 frd, u32 ra, u32 rb) override; - void SYNC(u32 l) override; - void LFDX(u32 frd, u32 ra, u32 rb) override; - void LFDUX(u32 frd, u32 ra, u32 rb) override; - void STVLX(u32 vs, u32 ra, u32 rb) override; - void STDBRX(u32 rd, u32 ra, u32 rb) override; - void STSWX(u32 rs, u32 ra, u32 rb) override; - void STWBRX(u32 rs, u32 ra, u32 rb) override; - void STFSX(u32 frs, u32 ra, u32 rb) override; - void STVRX(u32 vs, u32 ra, u32 rb) override; - void STFSUX(u32 frs, u32 ra, u32 rb) override; - void STSWI(u32 rd, u32 ra, u32 nb) override; - void STFDX(u32 frs, u32 ra, u32 rb) override; - void STFDUX(u32 frs, u32 ra, u32 rb) override; - void LVLXL(u32 vd, u32 ra, u32 rb) override; - void LHBRX(u32 rd, u32 ra, u32 rb) override; - void SRAW(u32 ra, u32 rs, u32 rb, u32 rc) override; - void SRAD(u32 ra, u32 rs, u32 rb, u32 rc) override; - void LVRXL(u32 vd, u32 ra, u32 rb) override; - void DSS(u32 strm, u32 a) override; - void SRAWI(u32 ra, u32 rs, u32 sh, u32 rc) override; - void SRADI1(u32 ra, u32 rs, u32 sh, u32 rc) override; - void SRADI2(u32 ra, u32 rs, u32 sh, u32 rc) override; - void EIEIO() override; - void STVLXL(u32 vs, u32 ra, u32 rb) override; - void STHBRX(u32 rs, u32 ra, u32 rb) override; - void EXTSH(u32 ra, u32 rs, u32 rc) override; - void STVRXL(u32 sd, u32 ra, u32 rb) override; - void EXTSB(u32 ra, u32 rs, u32 rc) override; - void STFIWX(u32 frs, u32 ra, u32 rb) override; - void EXTSW(u32 ra, u32 rs, u32 rc) override; - void ICBI(u32 ra, u32 rb) override; - void DCBZ(u32 ra, u32 rb) override; - void LWZ(u32 rd, u32 ra, s32 d) override; - void LWZU(u32 rd, u32 ra, s32 d) override; - void LBZ(u32 rd, u32 ra, s32 d) override; - void LBZU(u32 rd, u32 ra, s32 d) override; - void STW(u32 rs, u32 ra, s32 d) override; - void STWU(u32 rs, u32 ra, s32 d) override; - void STB(u32 rs, u32 ra, s32 d) override; - void STBU(u32 rs, u32 ra, s32 d) override; - void LHZ(u32 rd, u32 ra, s32 d) override; - void LHZU(u32 rd, u32 ra, s32 d) override; - void LHA(u32 rs, u32 ra, s32 d) override; - void LHAU(u32 rs, u32 ra, s32 d) override; - void STH(u32 rs, u32 ra, s32 d) override; - void STHU(u32 rs, u32 ra, s32 d) override; - void LMW(u32 rd, u32 ra, s32 d) override; - void STMW(u32 rs, u32 ra, s32 d) override; - void LFS(u32 frd, u32 ra, s32 d) override; - void LFSU(u32 frd, u32 ra, s32 d) override; - void LFD(u32 frd, u32 ra, s32 d) override; - void LFDU(u32 frd, u32 ra, s32 d) override; - void STFS(u32 frs, u32 ra, s32 d) override; - void STFSU(u32 frs, u32 ra, s32 d) override; - void STFD(u32 frs, u32 ra, s32 d) override; - void STFDU(u32 frs, u32 ra, s32 d) override; - void LD(u32 rd, u32 ra, s32 ds) override; - void LDU(u32 rd, u32 ra, s32 ds) override; - void LWA(u32 rd, u32 ra, s32 ds) override; - void FDIVS(u32 frd, u32 fra, u32 frb, u32 rc) override; - void FSUBS(u32 frd, u32 fra, u32 frb, u32 rc) override; - void FADDS(u32 frd, u32 fra, u32 frb, u32 rc) override; - void FSQRTS(u32 frd, u32 frb, u32 rc) override; - void FRES(u32 frd, u32 frb, u32 rc) override; - void FMULS(u32 frd, u32 fra, u32 frc, u32 rc) override; - void FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override; - void FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override; - void FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override; - void FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override; - void STD(u32 rs, u32 ra, s32 ds) override; - void STDU(u32 rs, u32 ra, s32 ds) override; - void MTFSB1(u32 bt, u32 rc) override; - void MCRFS(u32 bf, u32 bfa) override; - void MTFSB0(u32 bt, u32 rc) override; - void MTFSFI(u32 crfd, u32 i, u32 rc) override; - void MFFS(u32 frd, u32 rc) override; - void MTFSF(u32 flm, u32 frb, u32 rc) override; - - void FCMPU(u32 bf, u32 fra, u32 frb) override; - void FRSP(u32 frd, u32 frb, u32 rc) override; - void FCTIW(u32 frd, u32 frb, u32 rc) override; - void FCTIWZ(u32 frd, u32 frb, u32 rc) override; - void FDIV(u32 frd, u32 fra, u32 frb, u32 rc) override; - void FSUB(u32 frd, u32 fra, u32 frb, u32 rc) override; - void FADD(u32 frd, u32 fra, u32 frb, u32 rc) override; - void FSQRT(u32 frd, u32 frb, u32 rc) override; - void FSEL(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override; - void FMUL(u32 frd, u32 fra, u32 frc, u32 rc) override; - void FRSQRTE(u32 frd, u32 frb, u32 rc) override; - void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override; - void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override; - void FNMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override; - void FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override; - void FCMPO(u32 crfd, u32 fra, u32 frb) override; - void FNEG(u32 frd, u32 frb, u32 rc) override; - void FMR(u32 frd, u32 frb, u32 rc) override; - void FNABS(u32 frd, u32 frb, u32 rc) override; - void FABS(u32 frd, u32 frb, u32 rc) override; - void FCTID(u32 frd, u32 frb, u32 rc) override; - void FCTIDZ(u32 frd, u32 frb, u32 rc) override; - void FCFID(u32 frd, u32 frb, u32 rc) override; - - void UNK(const u32 code, const u32 opcode, const u32 gcode) override; - - /// Utility function creating a function called name with Executable signature - void initiate_function(const std::string &name); - - protected: - /// State of a compilation task - struct CompileTaskState { - enum Args { - State, - Context, - MaxArgs, - }; - - /// The LLVM function for the compilation task - llvm::Function * function; - - /// Args of the LLVM function - llvm::Value * args[MaxArgs]; - - /// Address of the current instruction being compiled - u32 current_instruction_address; - - /// A flag used to detect branch instructions. - /// This is set to false at the start of compilation of an instruction. - /// If a branch instruction is encountered, this is set to true by the decode function. - bool hit_branch_instruction; - }; - - /// The function that will be called to execute unknown functions - llvm::Function * m_execute_unknown_function; - - /// The executable that will be called to execute unknown blocks - llvm::Function * m_execute_unknown_block; - - /// Maps function name to executable memory pointer - std::unordered_map &m_executable_map; - - /// LLVM context - llvm::LLVMContext * m_llvm_context; - - /// LLVM IR builder - llvm::IRBuilder<> * m_ir_builder; - - /// Module to which all generated code is output to - llvm::Module * m_module; - - /// LLVM type of the functions genreated by the compiler - llvm::FunctionType * m_compiled_function_type; - - /// State of the current compilation task - CompileTaskState m_state; - - /// Get the name of the basic block for the specified address - std::string GetBasicBlockNameFromAddress(u32 address, const std::string & suffix = "") const; - - /// Get the address of a basic block from its name - u32 GetAddressFromBasicBlockName(const std::string & name) const; - - /// Get the basic block in for the specified address. - llvm::BasicBlock * GetBasicBlockFromAddress(u32 address, const std::string & suffix = "", bool create_if_not_exist = true); - - /// Get a bit - llvm::Value * GetBit(llvm::Value * val, u32 n); - - /// Clear a bit - llvm::Value * ClrBit(llvm::Value * val, u32 n); - - /// Set a bit - llvm::Value * SetBit(llvm::Value * val, u32 n, llvm::Value * bit, bool doClear = true); - - /// Get a nibble - llvm::Value * GetNibble(llvm::Value * val, u32 n); - - /// Clear a nibble - llvm::Value * ClrNibble(llvm::Value * val, u32 n); - - /// Set a nibble - llvm::Value * SetNibble(llvm::Value * val, u32 n, llvm::Value * nibble, bool doClear = true); - - /// Set a nibble - llvm::Value * SetNibble(llvm::Value * val, u32 n, llvm::Value * b0, llvm::Value * b1, llvm::Value * b2, llvm::Value * b3, bool doClear = true); - - /// Load PC - llvm::Value * GetPc(); - - /// Set PC - void SetPc(llvm::Value * val_ix); - - /// Load GPR - llvm::Value * GetGpr(u32 r, u32 num_bits = 64); - - /// Set GPR - void SetGpr(u32 r, llvm::Value * val_x64); - - /// Load CR - llvm::Value * GetCr(); - - /// Load CR and get field CRn - llvm::Value * GetCrField(u32 n); - - /// Set CR - void SetCr(llvm::Value * val_x32); - - /// Set CR field - void SetCrField(u32 n, llvm::Value * field); - - /// Set CR field - void SetCrField(u32 n, llvm::Value * b0, llvm::Value * b1, llvm::Value * b2, llvm::Value * b3); - - /// Set CR field based on signed comparison - void SetCrFieldSignedCmp(u32 n, llvm::Value * a, llvm::Value * b); - - /// Set CR field based on unsigned comparison - void SetCrFieldUnsignedCmp(u32 n, llvm::Value * a, llvm::Value * b); - - /// Set CR6 based on the result of the vector compare instruction - void SetCr6AfterVectorCompare(u32 vr); - - /// Get LR - llvm::Value * GetLr(); - - /// Set LR - void SetLr(llvm::Value * val_x64); - - /// Get CTR - llvm::Value * GetCtr(); - - /// Set CTR - void SetCtr(llvm::Value * val_x64); - - /// Load XER and convert it to an i64 - llvm::Value * GetXer(); - - /// Load XER and return the CA bit - llvm::Value * GetXerCa(); - - /// Load XER and return the SO bit - llvm::Value * GetXerSo(); - - /// Set XER - void SetXer(llvm::Value * val_x64); - - /// Set the CA bit of XER - void SetXerCa(llvm::Value * ca); - - /// Set the SO bit of XER - void SetXerSo(llvm::Value * so); - - /// Get VRSAVE - llvm::Value * GetVrsave(); - - /// Set VRSAVE - void SetVrsave(llvm::Value * val_x64); - - /// Load FPSCR - llvm::Value * GetFpscr(); - - /// Set FPSCR - void SetFpscr(llvm::Value * val_x32); - - /// Get FPR - llvm::Value * GetFpr(u32 r, u32 bits = 64, bool as_int = false); - - /// Set FPR - void SetFpr(u32 r, llvm::Value * val); - - /// Load VSCR - llvm::Value * GetVscr(); - - /// Set VSCR - void SetVscr(llvm::Value * val_x32); - - /// Load VR - llvm::Value * GetVr(u32 vr); - - /// Load VR and convert it to an integer vector - llvm::Value * GetVrAsIntVec(u32 vr, u32 vec_elt_num_bits); - - /// Load VR and convert it to a float vector with 4 elements - llvm::Value * GetVrAsFloatVec(u32 vr); - - /// Load VR and convert it to a double vector with 2 elements - llvm::Value * GetVrAsDoubleVec(u32 vr); - - /// Set VR to the specified value - void SetVr(u32 vr, llvm::Value * val_x128); - - /// Check condition for branch instructions - llvm::Value * CheckBranchCondition(u32 bo, u32 bi); - - /// Create IR for a branch instruction - void CreateBranch(llvm::Value * cmp_i1, llvm::Value * target_i32, bool lk, bool target_is_lr = false); - - /// Read from memory - llvm::Value * ReadMemory(llvm::Value * addr_i64, u32 bits, u32 alignment = 0, bool bswap = true, bool could_be_mmio = true); - - /// Write to memory - void WriteMemory(llvm::Value * addr_i64, llvm::Value * val_ix, u32 alignment = 0, bool bswap = true, bool could_be_mmio = true); - - /// Convert a C++ type to an LLVM type - template - llvm::Type * CppToLlvmType() { - if (std::is_void::value) { - return m_ir_builder->getVoidTy(); - } - else if (std::is_same::value || std::is_same::value) { - return m_ir_builder->getInt64Ty(); - } - else if (std::is_same::value || std::is_same::value) { - return m_ir_builder->getInt32Ty(); - } - else if (std::is_same::value || std::is_same::value) { - return m_ir_builder->getInt16Ty(); - } - else if (std::is_same::value || std::is_same::value) { - return m_ir_builder->getInt8Ty(); - } - else if (std::is_same::value) { - return m_ir_builder->getFloatTy(); - } - else if (std::is_same::value) { - return m_ir_builder->getDoubleTy(); - } - else if (std::is_same::value) { - return m_ir_builder->getInt1Ty(); - } - else if (std::is_pointer::value) { - return m_ir_builder->getInt8PtrTy(); - } - else { - assert(0); - } - - return nullptr; - } - - /// Call a function - template - llvm::Value * Call(const char * name, Args... args) { - auto fn = m_module->getFunction(name); - if (!fn) { - std::vector fn_args_type = { args->getType()... }; - auto fn_type = llvm::FunctionType::get(CppToLlvmType(), fn_args_type, false); - fn = llvm::cast(m_module->getOrInsertFunction(name, fn_type)); - fn->setCallingConv(llvm::CallingConv::X86_64_Win64); - // Create an entry in m_executable_map that will be populated outside of compiler - (void)m_executable_map[name]; - } - - std::vector fn_args = { args... }; - return m_ir_builder->CreateCall(fn, fn_args); - } - - /// Handle compilation errors - void CompilationError(const std::string & error); - - /// A mask used in rotate instructions - static u64 s_rotate_mask[64][64]; - - /// A flag indicating whether s_rotate_mask has been initialised or not - static bool s_rotate_mask_inited; - - /// Initialse s_rotate_mask - static void InitRotateMask(); - }; - - /** - * Manages block compilation. - * PPUInterpreter1 execution is traced (using Tracer class) - * Periodically RecompilationEngine process traces result to find blocks - * whose compilation can improve performances. - * It then builds them asynchroneously and update the executable mapping - * using atomic based locks to avoid undefined behavior. - **/ - class RecompilationEngine final : public named_thread_t { - friend class CPUHybridDecoderRecompiler; - public: - virtual ~RecompilationEngine() override; - - /** - * Get the executable for the specified address if a compiled version is - * available, otherwise returns nullptr. - **/ - const Executable GetCompiledExecutableIfAvailable(u32 address) const; - - /// Notify the recompilation engine about a newly detected block start. - void NotifyBlockStart(u32 address); - - /// Log - llvm::raw_fd_ostream & Log(); - - std::string get_name() const override { return "PPU Recompilation Engine"; } - - void on_task() override; - - /// Get a pointer to the instance of this class - static std::shared_ptr GetInstance(); - - private: - /// An entry in the block table - struct BlockEntry { - /// Start address - u32 address; - - /// Number of times this block was hit - u32 num_hits; - - /// Indicates whether this function has been analysed or not - bool is_analysed; - - /// Indicates whether the block has been compiled or not - bool is_compiled; - - /// Indicate wheter the block is a function that can be completly compiled - /// that is, that has a clear "return" semantic and no indirect branch - bool is_compilable_function; - - /// If the analysis was successfull, how long the block is. - u32 instructionCount; - - /// If the analysis was successfull, which function does it call. - std::set calledFunctions; - - BlockEntry(u32 start_address) - : num_hits(0) - , address(start_address) - , is_compiled(false) - , is_analysed(false) - , is_compilable_function(false) - , instructionCount(0) { - } - - std::string ToString() const { - return fmt::format("0x%08X: NumHits=%u, IsCompiled=%c", - address, num_hits, is_compiled ? 'Y' : 'N'); - } - - bool operator == (const BlockEntry & other) const { - return address == other.address; - } - }; - - /// Log - llvm::raw_fd_ostream * m_log; - - /// Lock for accessing m_pending_address_start. TODO: Eliminate this and use a lock-free queue. - std::mutex m_pending_address_start_lock; - - /// Queue of block start address to process - std::list m_pending_address_start; - - /// Block table - std::unordered_map m_block_table; - - int m_currentId; - - /// (function, id). - typedef std::pair ExecutableStorageType; - - /// Virtual memory allocated array. - /// Store pointer to every compiled function/block and a unique Id. - /// We need to map every instruction in PS3 Ram so it's a big table - /// But a lot of it won't be accessed. Fortunatly virtual memory help here... - ExecutableStorageType* FunctionCache; - - // Bitfield recording page status in FunctionCache reserved memory. - char *FunctionCachePagesCommited; - - bool isAddressCommited(u32) const; - void commitAddress(u32); - - /// vector storing all exec engine - std::vector > m_executable_storage; - - - /// LLVM context - llvm::LLVMContext &m_llvm_context; - - /// LLVM IR builder - llvm::IRBuilder<> m_ir_builder; - - /** - * Compile a code fragment described by a cfg and return an executable and the ExecutionEngine storing it - * Pointer to function can be retrieved with getPointerToFunction - */ - std::pair compile(const std::string & name, u32 start_address, u32 instruction_count); - - /// The time at which the m_address_to_ordinal cache was last cleared - std::chrono::high_resolution_clock::time_point m_last_cache_clear_time; - - RecompilationEngine(); - - RecompilationEngine(const RecompilationEngine&) = delete; // Delete copy/move constructors and copy/move operators - - /// Increase usage counter for block starting at addr and compile it if threshold was reached. - /// Returns true if block was compiled - bool IncreaseHitCounterAndBuild(u32 addr); - - /** - * Analyse block to get useful info (function called, has indirect branch...) - * This code is inspired from Dolphin PPC Analyst - * Return true if analysis is successful. - */ - bool AnalyseBlock(BlockEntry &functionData, size_t maxSize = 10000); - - /// Compile a block - void CompileBlock(BlockEntry & block_entry); - - /// Mutex used to prevent multiple creation - static std::mutex s_mutex; - - /// The instance - static std::shared_ptr s_the_instance; - }; - - /** - * PPU execution engine - * Relies on PPUInterpreter1 to execute uncompiled code. - * Traces execution to determine which block to compile. - * Use LLVM to compile block into native code. - */ - class CPUHybridDecoderRecompiler : public CPUDecoder { - friend class RecompilationEngine; - friend class Compiler; - public: - CPUHybridDecoderRecompiler(PPUThread & ppu); - - CPUHybridDecoderRecompiler(const CPUHybridDecoderRecompiler&) = delete; // Delete copy/move constructors and copy/move operators - - virtual ~CPUHybridDecoderRecompiler(); - - u32 DecodeMemory(const u32 address) override; - - private: - /// PPU processor context - PPUThread & m_ppu; - - /// PPU Interpreter - PPUInterpreter * m_interpreter; - - /// PPU instruction Decoder - PPUDecoder m_decoder; - - /// Recompilation engine - std::shared_ptr m_recompilation_engine; - - /// Execute a function - static u32 ExecuteFunction(PPUThread * ppu_state, u64 context); - - /// Execute till the current function returns - static u32 ExecuteTillReturn(PPUThread * ppu_state, u64 context); - - /// Check thread status. Returns true if the thread must exit. - static bool PollStatus(PPUThread * ppu_state); - }; - - class CustomSectionMemoryManager : public llvm::SectionMemoryManager { - private: - std::unordered_map &executableMap; - public: - CustomSectionMemoryManager(std::unordered_map &map) : - executableMap(map) - {} - ~CustomSectionMemoryManager() override {} - - virtual uint64_t getSymbolAddress(const std::string &Name) override - { - std::unordered_map::const_iterator It = executableMap.find(Name); - if (It != executableMap.end()) - return (uint64_t)It->second; - return getSymbolAddressInProcess(Name); - } - }; -} - -#endif // LLVM_AVAILABLE -#endif // PPU_LLVM_RECOMPILER_H diff --git a/rpcs3/Emu/Cell/PPULLVMRecompilerCore.cpp b/rpcs3/Emu/Cell/PPULLVMRecompilerCore.cpp deleted file mode 100644 index b9a0c065d2..0000000000 --- a/rpcs3/Emu/Cell/PPULLVMRecompilerCore.cpp +++ /dev/null @@ -1,5527 +0,0 @@ -#include "stdafx.h" -#ifdef LLVM_AVAILABLE -#include "Emu/state.h" -#include "Emu/System.h" -#include "Emu/Cell/PPULLVMRecompiler.h" -#include "Emu/Memory/Memory.h" -#ifdef _MSC_VER -#pragma warning(push, 0) -#endif -#include "llvm/Support/TargetSelect.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/ExecutionEngine/GenericValue.h" -#include "llvm/ExecutionEngine/MCJIT.h" -#include "llvm/ExecutionEngine/SectionMemoryManager.h" -#include "llvm/IR/Intrinsics.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Analysis/Passes.h" -#include "llvm/Analysis/TargetTransformInfo.h" -#include "llvm/Analysis/MemoryDependenceAnalysis.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/Analysis/ScalarEvolution.h" -#include "llvm/IR/Dominators.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/Vectorize.h" -#include "llvm/MC/MCDisassembler.h" -#include "llvm/IR/Verifier.h" -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -#define USE_INTERP_IF_REQUESTED(inst, ...) \ - if (!rpcs3::state.config.core.llvm.enable_##inst.value()) \ - { \ - Call(#inst, m_state.args[CompileTaskState::Args::State], __VA_ARGS__); \ - return; \ - } - -using namespace llvm; -using namespace ppu_recompiler_llvm; - -void Compiler::NULL_OP() { - CompilationError("NULL_OP"); -} - -void Compiler::NOP() { - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::donothing)); -} - -void Compiler::TDI(u32 to, u32 ra, s32 simm16) { - llvm::Value *gpr_a = GetGpr(ra); - llvm::Value *cst_simm16 = m_ir_builder->getInt64(simm16); - llvm::Value *trap_condition = m_ir_builder->getFalse(); - - if (to & 0x10) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpSLT(gpr_a, cst_simm16)); - if (to & 0x8) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpSGT(gpr_a, cst_simm16)); - if (to & 0x4) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpEQ(gpr_a, cst_simm16)); - if (to & 0x2) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpULT(gpr_a, cst_simm16)); - if (to & 0x1) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpUGT(gpr_a, cst_simm16)); - - llvm::BasicBlock *trap_block = GetBasicBlockFromAddress(m_state.current_instruction_address, "trap_block"); - llvm::BasicBlock *normal_execution = GetBasicBlockFromAddress(m_state.current_instruction_address, "normal_execution"); - m_ir_builder->CreateCondBr(trap_condition, trap_block, normal_execution); - - m_ir_builder->SetInsertPoint(trap_block); - Call("trap"); - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - - m_ir_builder->SetInsertPoint(normal_execution); -} - -void Compiler::TWI(u32 to, u32 ra, s32 simm16) { - llvm::Value *gpr_a = GetGpr(ra, 32); - llvm::Value *cst_simm16 = m_ir_builder->getInt32(simm16); - llvm::Value *trap_condition = m_ir_builder->getFalse(); - - if (to & 0x10) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpSLT(gpr_a, cst_simm16)); - if (to & 0x8) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpSGT(gpr_a, cst_simm16)); - if (to & 0x4) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpEQ(gpr_a, cst_simm16)); - if (to & 0x2) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpULT(gpr_a, cst_simm16)); - if (to & 0x1) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpUGT(gpr_a, cst_simm16)); - - llvm::BasicBlock *trap_block = GetBasicBlockFromAddress(m_state.current_instruction_address, "trap_block"); - llvm::BasicBlock *normal_execution = GetBasicBlockFromAddress(m_state.current_instruction_address, "normal_execution"); - m_ir_builder->CreateCondBr(trap_condition, trap_block, normal_execution); - - m_ir_builder->SetInsertPoint(trap_block); - Call("trap"); - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - - m_ir_builder->SetInsertPoint(normal_execution); -} - -void Compiler::MFVSCR(u32 vd) { - auto vscr_i32 = GetVscr(); - auto vscr_i128 = m_ir_builder->CreateZExt(vscr_i32, m_ir_builder->getIntNTy(128)); - SetVr(vd, vscr_i128); -} - -void Compiler::MTVSCR(u32 vb) { - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto vscr_i32 = m_ir_builder->CreateExtractElement(vb_v4i32, m_ir_builder->getInt32(0)); - vscr_i32 = m_ir_builder->CreateAnd(vscr_i32, 0x00010001); - SetVscr(vscr_i32); -} - -void Compiler::VADDCUW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - - va_v4i32 = m_ir_builder->CreateNot(va_v4i32); - auto cmpv4i1 = m_ir_builder->CreateICmpULT(va_v4i32, vb_v4i32); - auto cmpv4i32 = m_ir_builder->CreateZExt(cmpv4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, cmpv4i32); -} - -void Compiler::VADDFP(u32 vd, u32 va, u32 vb) { - auto va_v4f32 = GetVrAsFloatVec(va); - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto sum_v4f32 = m_ir_builder->CreateFAdd(va_v4f32, vb_v4f32); - SetVr(vd, sum_v4f32); -} - -void Compiler::VADDSBS(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto sum_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_padds_b), va_v16i8, vb_v16i8); - SetVr(vd, sum_v16i8); - - // TODO: Set VSCR.SAT -} - -void Compiler::VADDSHS(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto sum_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_padds_w), va_v8i16, vb_v8i16); - SetVr(vd, sum_v8i16); - - // TODO: Set VSCR.SAT -} - -void Compiler::VADDSWS(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - - // It looks like x86 does not have an instruction to add 32 bit intergers with signed/unsigned saturation. - // To implement add with saturation, we first determine what the result would be if the operation were to cause - // an overflow. If two -ve numbers are being added and cause an overflow, the result would be 0x80000000. - // If two +ve numbers are being added and cause an overflow, the result would be 0x7FFFFFFF. Addition of a -ve - // number and a +ve number cannot cause overflow. So the result in case of an overflow is 0x7FFFFFFF + sign bit - // of any one of the operands. - auto tmp1_v4i32 = m_ir_builder->CreateLShr(va_v4i32, 31); - tmp1_v4i32 = m_ir_builder->CreateAdd(tmp1_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x7FFFFFFF))); - auto tmp1_v16i8 = m_ir_builder->CreateBitCast(tmp1_v4i32, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - - // Next, we find if the addition can actually result in an overflow. Since an overflow can only happen if the operands - // have the same sign, we bitwise XOR both the operands. If the sign bit of the result is 0 then the operands have the - // same sign and so may cause an overflow. We invert the result so that the sign bit is 1 when the operands have the - // same sign. - auto tmp2_v4i32 = m_ir_builder->CreateXor(va_v4i32, vb_v4i32); - tmp2_v4i32 = m_ir_builder->CreateNot(tmp2_v4i32); - - // Perform the sum. - auto sum_v4i32 = m_ir_builder->CreateAdd(va_v4i32, vb_v4i32); - auto sum_v16i8 = m_ir_builder->CreateBitCast(sum_v4i32, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - - // If an overflow occurs, then the sign of the sum will be different from the sign of the operands. So, we xor the - // result with one of the operands. The sign bit of the result will be 1 if the sign bit of the sum and the sign bit of the - // result is different. This result is again ANDed with tmp3 (the sign bit of tmp3 is 1 only if the operands have the same - // sign and so can cause an overflow). - auto tmp3_v4i32 = m_ir_builder->CreateXor(va_v4i32, sum_v4i32); - tmp3_v4i32 = m_ir_builder->CreateAnd(tmp2_v4i32, tmp3_v4i32); - tmp3_v4i32 = m_ir_builder->CreateAShr(tmp3_v4i32, 31); - auto tmp3_v16i8 = m_ir_builder->CreateBitCast(tmp3_v4i32, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - - // tmp4 is equal to 0xFFFFFFFF if an overflow occured and 0x00000000 otherwise. - auto res_v16i8 = m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pblendvb), sum_v16i8, tmp1_v16i8, tmp3_v16i8); - SetVr(vd, res_v16i8); - - // TODO: Set SAT -} - -void Compiler::VADDUBM(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto sum_v16i8 = m_ir_builder->CreateAdd(va_v16i8, vb_v16i8); - SetVr(vd, sum_v16i8); -} - -void Compiler::VADDUBS(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto sum_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_paddus_b), va_v16i8, vb_v16i8); - SetVr(vd, sum_v16i8); - - // TODO: Set SAT -} - -void Compiler::VADDUHM(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto sum_v8i16 = m_ir_builder->CreateAdd(va_v8i16, vb_v8i16); - SetVr(vd, sum_v8i16); -} - -void Compiler::VADDUHS(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto sum_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_paddus_w), va_v8i16, vb_v8i16); - SetVr(vd, sum_v8i16); - - // TODO: Set SAT -} - -void Compiler::VADDUWM(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto sum_v4i32 = m_ir_builder->CreateAdd(va_v4i32, vb_v4i32); - SetVr(vd, sum_v4i32); -} - -void Compiler::VADDUWS(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto sum_v4i32 = m_ir_builder->CreateAdd(va_v4i32, vb_v4i32); - auto cmp_v4i1 = m_ir_builder->CreateICmpULT(sum_v4i32, va_v4i32); - auto cmp_v4i32 = m_ir_builder->CreateSExt(cmp_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - auto res_v4i32 = m_ir_builder->CreateOr(sum_v4i32, cmp_v4i32); - SetVr(vd, res_v4i32); - - // TODO: Set SAT -} - -void Compiler::VAND(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto res_v4i32 = m_ir_builder->CreateAnd(va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VANDC(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - vb_v4i32 = m_ir_builder->CreateNot(vb_v4i32); - auto res_v4i32 = m_ir_builder->CreateAnd(va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VAVGSB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto va_v16i16 = m_ir_builder->CreateSExt(va_v16i8, VectorType::get(m_ir_builder->getInt16Ty(), 16)); - auto vb_v16i16 = m_ir_builder->CreateSExt(vb_v16i8, VectorType::get(m_ir_builder->getInt16Ty(), 16)); - auto sum_v16i16 = m_ir_builder->CreateAdd(va_v16i16, vb_v16i16); - sum_v16i16 = m_ir_builder->CreateAdd(sum_v16i16, m_ir_builder->CreateVectorSplat(16, m_ir_builder->getInt16(1))); - auto avg_v16i16 = m_ir_builder->CreateAShr(sum_v16i16, 1); - auto avg_v16i8 = m_ir_builder->CreateTrunc(avg_v16i16, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - SetVr(vd, avg_v16i8); -} - -void Compiler::VAVGSH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto va_v8i32 = m_ir_builder->CreateSExt(va_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto vb_v8i32 = m_ir_builder->CreateSExt(vb_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto sum_v8i32 = m_ir_builder->CreateAdd(va_v8i32, vb_v8i32); - sum_v8i32 = m_ir_builder->CreateAdd(sum_v8i32, m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt32(1))); - auto avg_v8i32 = m_ir_builder->CreateAShr(sum_v8i32, 1); - auto avg_v8i16 = m_ir_builder->CreateTrunc(avg_v8i32, VectorType::get(m_ir_builder->getInt16Ty(), 8)); - SetVr(vd, avg_v8i16); -} - -void Compiler::VAVGSW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto va_v4i64 = m_ir_builder->CreateSExt(va_v4i32, VectorType::get(m_ir_builder->getInt64Ty(), 4)); - auto vb_v4i64 = m_ir_builder->CreateSExt(vb_v4i32, VectorType::get(m_ir_builder->getInt64Ty(), 4)); - auto sum_v4i64 = m_ir_builder->CreateAdd(va_v4i64, vb_v4i64); - sum_v4i64 = m_ir_builder->CreateAdd(sum_v4i64, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(1))); - auto avg_v4i64 = m_ir_builder->CreateAShr(sum_v4i64, 1); - auto avg_v4i32 = m_ir_builder->CreateTrunc(avg_v4i64, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, avg_v4i32); -} - -void Compiler::VAVGUB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto avg_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_pavg_b), va_v16i8, vb_v16i8); - SetVr(vd, avg_v16i8); -} - -void Compiler::VAVGUH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto avg_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_pavg_w), va_v8i16, vb_v8i16); - SetVr(vd, avg_v8i16); -} - -void Compiler::VAVGUW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto va_v4i64 = m_ir_builder->CreateZExt(va_v4i32, VectorType::get(m_ir_builder->getInt64Ty(), 4)); - auto vb_v4i64 = m_ir_builder->CreateZExt(vb_v4i32, VectorType::get(m_ir_builder->getInt64Ty(), 4)); - auto sum_v4i64 = m_ir_builder->CreateAdd(va_v4i64, vb_v4i64); - sum_v4i64 = m_ir_builder->CreateAdd(sum_v4i64, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(1))); - auto avg_v4i64 = m_ir_builder->CreateLShr(sum_v4i64, 1); - auto avg_v4i32 = m_ir_builder->CreateTrunc(avg_v4i64, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, avg_v4i32); -} - -void Compiler::VCFSX(u32 vd, u32 uimm5, u32 vb) { - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto res_v4f32 = m_ir_builder->CreateSIToFP(vb_v4i32, VectorType::get(m_ir_builder->getFloatTy(), 4)); - - if (uimm5) { - float scale = (float)((u64)1 << uimm5); - res_v4f32 = m_ir_builder->CreateFDiv(res_v4f32, m_ir_builder->CreateVectorSplat(4, ConstantFP::get(m_ir_builder->getFloatTy(), scale))); - } - - SetVr(vd, res_v4f32); -} - -void Compiler::VCFUX(u32 vd, u32 uimm5, u32 vb) { - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto res_v4f32 = m_ir_builder->CreateUIToFP(vb_v4i32, VectorType::get(m_ir_builder->getFloatTy(), 4)); - - if (uimm5) { - float scale = (float)((u64)1 << uimm5); - res_v4f32 = m_ir_builder->CreateFDiv(res_v4f32, m_ir_builder->CreateVectorSplat(4, ConstantFP::get(m_ir_builder->getFloatTy(), scale))); - } - - SetVr(vd, res_v4f32); -} - -void Compiler::VCMPBFP(u32 vd, u32 va, u32 vb) { - auto va_v4f32 = GetVrAsFloatVec(va); - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto cmp_gt_v4i1 = m_ir_builder->CreateFCmpOGT(va_v4f32, vb_v4f32); - vb_v4f32 = m_ir_builder->CreateFNeg(vb_v4f32); - auto cmp_lt_v4i1 = m_ir_builder->CreateFCmpOLT(va_v4f32, vb_v4f32); - auto cmp_gt_v4i32 = m_ir_builder->CreateZExt(cmp_gt_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - auto cmp_lt_v4i32 = m_ir_builder->CreateZExt(cmp_lt_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - cmp_gt_v4i32 = m_ir_builder->CreateShl(cmp_gt_v4i32, 31); - cmp_lt_v4i32 = m_ir_builder->CreateShl(cmp_lt_v4i32, 30); - auto res_v4i32 = m_ir_builder->CreateOr(cmp_gt_v4i32, cmp_lt_v4i32); - SetVr(vd, res_v4i32); - - // TODO: Implement NJ mode -} - -void Compiler::VCMPBFP_(u32 vd, u32 va, u32 vb) { - VCMPBFP(vd, va, vb); - - auto vd_v16i8 = GetVrAsIntVec(vd, 8); - u32 mask_v16i32[16] = { 3, 7, 11, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - vd_v16i8 = m_ir_builder->CreateShuffleVector(vd_v16i8, UndefValue::get(VectorType::get(m_ir_builder->getInt8Ty(), 16)), ConstantDataVector::get(m_ir_builder->getContext(), mask_v16i32)); - auto vd_v4i32 = m_ir_builder->CreateBitCast(vd_v16i8, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - auto vd_mask_i32 = m_ir_builder->CreateExtractElement(vd_v4i32, m_ir_builder->getInt32(0)); - auto cmp_i1 = m_ir_builder->CreateICmpEQ(vd_mask_i32, m_ir_builder->getInt32(0)); - SetCrField(6, nullptr, nullptr, cmp_i1, nullptr); -} - -void Compiler::VCMPEQFP(u32 vd, u32 va, u32 vb) { - auto va_v4f32 = GetVrAsFloatVec(va); - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto cmp_v4i1 = m_ir_builder->CreateFCmpOEQ(va_v4f32, vb_v4f32); - auto cmp_v4i32 = m_ir_builder->CreateSExt(cmp_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, cmp_v4i32); -} - -void Compiler::VCMPEQFP_(u32 vd, u32 va, u32 vb) { - VCMPEQFP(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPEQUB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto cmp_v16i1 = m_ir_builder->CreateICmpEQ(va_v16i8, vb_v16i8); - auto cmp_v16i8 = m_ir_builder->CreateSExt(cmp_v16i1, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - SetVr(vd, cmp_v16i8); -} - -void Compiler::VCMPEQUB_(u32 vd, u32 va, u32 vb) { - VCMPEQUB(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPEQUH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto cmp_v8i1 = m_ir_builder->CreateICmpEQ(va_v8i16, vb_v8i16); - auto cmp_v8i16 = m_ir_builder->CreateSExt(cmp_v8i1, VectorType::get(m_ir_builder->getInt16Ty(), 8)); - SetVr(vd, cmp_v8i16); -} - -void Compiler::VCMPEQUH_(u32 vd, u32 va, u32 vb) { - VCMPEQUH(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPEQUW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto cmp_v4i1 = m_ir_builder->CreateICmpEQ(va_v4i32, vb_v4i32); - auto cmp_v4i32 = m_ir_builder->CreateSExt(cmp_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, cmp_v4i32); -} - -void Compiler::VCMPEQUW_(u32 vd, u32 va, u32 vb) { - VCMPEQUW(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPGEFP(u32 vd, u32 va, u32 vb) { - auto va_v4f32 = GetVrAsFloatVec(va); - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto cmp_v4i1 = m_ir_builder->CreateFCmpOGE(va_v4f32, vb_v4f32); - auto cmp_v4i32 = m_ir_builder->CreateSExt(cmp_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, cmp_v4i32); -} - -void Compiler::VCMPGEFP_(u32 vd, u32 va, u32 vb) { - VCMPGEFP(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPGTFP(u32 vd, u32 va, u32 vb) { - auto va_v4f32 = GetVrAsFloatVec(va); - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto cmp_v4i1 = m_ir_builder->CreateFCmpOGT(va_v4f32, vb_v4f32); - auto cmp_v4i32 = m_ir_builder->CreateSExt(cmp_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, cmp_v4i32); -} - -void Compiler::VCMPGTFP_(u32 vd, u32 va, u32 vb) { - VCMPGTFP(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPGTSB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto cmp_v16i1 = m_ir_builder->CreateICmpSGT(va_v16i8, vb_v16i8); - auto cmp_v16i8 = m_ir_builder->CreateSExt(cmp_v16i1, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - SetVr(vd, cmp_v16i8); -} - -void Compiler::VCMPGTSB_(u32 vd, u32 va, u32 vb) { - VCMPGTSB(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPGTSH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto cmp_v8i1 = m_ir_builder->CreateICmpSGT(va_v8i16, vb_v8i16); - auto cmp_v8i16 = m_ir_builder->CreateSExt(cmp_v8i1, VectorType::get(m_ir_builder->getInt16Ty(), 8)); - SetVr(vd, cmp_v8i16); -} - -void Compiler::VCMPGTSH_(u32 vd, u32 va, u32 vb) { - VCMPGTSH(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPGTSW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto cmp_v4i1 = m_ir_builder->CreateICmpSGT(va_v4i32, vb_v4i32); - auto cmp_v4i32 = m_ir_builder->CreateSExt(cmp_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, cmp_v4i32); -} - -void Compiler::VCMPGTSW_(u32 vd, u32 va, u32 vb) { - VCMPGTSW(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPGTUB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto cmp_v16i1 = m_ir_builder->CreateICmpUGT(va_v16i8, vb_v16i8); - auto cmp_v16i8 = m_ir_builder->CreateSExt(cmp_v16i1, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - SetVr(vd, cmp_v16i8); -} - -void Compiler::VCMPGTUB_(u32 vd, u32 va, u32 vb) { - VCMPGTUB(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPGTUH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto cmp_v8i1 = m_ir_builder->CreateICmpUGT(va_v8i16, vb_v8i16); - auto cmp_v8i16 = m_ir_builder->CreateSExt(cmp_v8i1, VectorType::get(m_ir_builder->getInt16Ty(), 8)); - SetVr(vd, cmp_v8i16); -} - -void Compiler::VCMPGTUH_(u32 vd, u32 va, u32 vb) { - VCMPGTUH(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCMPGTUW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto cmp_v4i1 = m_ir_builder->CreateICmpUGT(va_v4i32, vb_v4i32); - auto cmp_v4i32 = m_ir_builder->CreateSExt(cmp_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, cmp_v4i32); -} - -void Compiler::VCMPGTUW_(u32 vd, u32 va, u32 vb) { - VCMPGTUW(vd, va, vb); - SetCr6AfterVectorCompare(vd); -} - -void Compiler::VCTSXS(u32 vd, u32 uimm5, u32 vb) { - auto vb_v4f32 = GetVrAsFloatVec(vb); - if (uimm5) { - u64 power_of_two = UINT64_C(1) << uimm5; - vb_v4f32 = m_ir_builder->CreateFMul(vb_v4f32, m_ir_builder->CreateVectorSplat(4, ConstantFP::get(m_ir_builder->getFloatTy(), static_cast(power_of_two)))); - } - - auto res_v4i32 = (Value *)m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_cvtps2dq), vb_v4f32); - auto cmp_v4i1 = m_ir_builder->CreateFCmpOGE(vb_v4f32, m_ir_builder->CreateVectorSplat(4, ConstantFP::get(m_ir_builder->getFloatTy(), 0x7FFFFFFF))); - auto cmp_v4i32 = m_ir_builder->CreateSExt(cmp_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - res_v4i32 = m_ir_builder->CreateXor(cmp_v4i32, res_v4i32); - SetVr(vd, res_v4i32); - - // TODO: Set VSCR.SAT -} - -void Compiler::VCTUXS(u32 vd, u32 uimm5, u32 vb) { - auto vb_v4f32 = GetVrAsFloatVec(vb); - if (uimm5) { - u64 power_of_two = UINT64_C(1) << uimm5; - vb_v4f32 = m_ir_builder->CreateFMul(vb_v4f32, m_ir_builder->CreateVectorSplat(4, ConstantFP::get(m_ir_builder->getFloatTy(), static_cast(power_of_two)))); - } - - auto res_v4f32 = (Value *)m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse_max_ps), vb_v4f32, m_ir_builder->CreateVectorSplat(4, ConstantFP::get(m_ir_builder->getFloatTy(), 0))); - auto cmp_v4i1 = m_ir_builder->CreateFCmpOGE(res_v4f32, m_ir_builder->CreateVectorSplat(4, ConstantFP::get(m_ir_builder->getFloatTy(), 0xFFFFFFFFu))); - auto cmp_v4i32 = m_ir_builder->CreateSExt(cmp_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - auto res_v4i32 = m_ir_builder->CreateFPToUI(res_v4f32, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - res_v4i32 = m_ir_builder->CreateOr(res_v4i32, cmp_v4i32); - SetVr(vd, res_v4i32); - - // TODO: Set VSCR.SAT -} - -void Compiler::VEXPTEFP(u32 vd, u32 vb) { - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto res_v4f32 = (Value *)m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::pow, VectorType::get(m_ir_builder->getFloatTy(), 4)), - m_ir_builder->CreateVectorSplat(4, ConstantFP::get(m_ir_builder->getFloatTy(), 2.0f)), vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VLOGEFP(u32 vd, u32 vb) { - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto res_v4f32 = (Value *)m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::log2, VectorType::get(m_ir_builder->getFloatTy(), 4)), vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VMADDFP(u32 vd, u32 va, u32 vc, u32 vb) { - auto va_v4f32 = GetVrAsFloatVec(va); - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto vc_v4f32 = GetVrAsFloatVec(vc); - auto res_v4f32 = m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, VectorType::get(m_ir_builder->getFloatTy(), 4)), va_v4f32, vc_v4f32, vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VMAXFP(u32 vd, u32 va, u32 vb) { - auto va_v4f32 = GetVrAsFloatVec(va); - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto res_v4f32 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse_max_ps), va_v4f32, vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VMAXSB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto res_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pmaxsb), va_v16i8, vb_v16i8); - SetVr(vd, res_v16i8); -} - -void Compiler::VMAXSH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto res_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_pmaxs_w), va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VMAXSW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto res_v4i32 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pmaxsd), va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VMAXUB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto res_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_pmaxu_b), va_v16i8, vb_v16i8); - SetVr(vd, res_v16i8); -} - -void Compiler::VMAXUH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto res_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pmaxuw), va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VMAXUW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto res_v4i32 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pmaxud), va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VMHADDSHS(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto vc_v8i16 = GetVrAsIntVec(vc, 16); - auto va_v8i32 = m_ir_builder->CreateSExt(va_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto vb_v8i32 = m_ir_builder->CreateSExt(vb_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto vc_v8i32 = m_ir_builder->CreateSExt(vc_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto res_v8i32 = m_ir_builder->CreateMul(va_v8i32, vb_v8i32); - res_v8i32 = m_ir_builder->CreateAShr(res_v8i32, 15); - res_v8i32 = m_ir_builder->CreateAdd(res_v8i32, vc_v8i32); - - u32 mask1_v4i32[4] = { 0, 1, 2, 3 }; - auto res1_v4i32 = m_ir_builder->CreateShuffleVector(res_v8i32, UndefValue::get(VectorType::get(m_ir_builder->getInt32Ty(), 8)), ConstantDataVector::get(m_ir_builder->getContext(), mask1_v4i32)); - u32 mask2_v4i32[4] = { 4, 5, 6, 7 }; - auto res2_v4i32 = m_ir_builder->CreateShuffleVector(res_v8i32, UndefValue::get(VectorType::get(m_ir_builder->getInt32Ty(), 8)), ConstantDataVector::get(m_ir_builder->getContext(), mask2_v4i32)); - auto res_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_packssdw_128), res1_v4i32, res2_v4i32); - SetVr(vd, res_v8i16); - - // TODO: Set VSCR.SAT -} - -void Compiler::VMHRADDSHS(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto vc_v8i16 = GetVrAsIntVec(vc, 16); - auto va_v8i32 = m_ir_builder->CreateSExt(va_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto vb_v8i32 = m_ir_builder->CreateSExt(vb_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto vc_v8i32 = m_ir_builder->CreateSExt(vc_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto res_v8i32 = m_ir_builder->CreateMul(va_v8i32, vb_v8i32); - res_v8i32 = m_ir_builder->CreateAdd(res_v8i32, m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt32(0x4000))); - res_v8i32 = m_ir_builder->CreateAShr(res_v8i32, 15); - res_v8i32 = m_ir_builder->CreateAdd(res_v8i32, vc_v8i32); - - u32 mask1_v4i32[4] = { 0, 1, 2, 3 }; - auto res1_v4i32 = m_ir_builder->CreateShuffleVector(res_v8i32, UndefValue::get(VectorType::get(m_ir_builder->getInt32Ty(), 8)), ConstantDataVector::get(m_ir_builder->getContext(), mask1_v4i32)); - u32 mask2_v4i32[4] = { 4, 5, 6, 7 }; - auto res2_v4i32 = m_ir_builder->CreateShuffleVector(res_v8i32, UndefValue::get(VectorType::get(m_ir_builder->getInt32Ty(), 8)), ConstantDataVector::get(m_ir_builder->getContext(), mask2_v4i32)); - auto res_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_packssdw_128), res1_v4i32, res2_v4i32); - SetVr(vd, res_v8i16); - - // TODO: Set VSCR.SAT -} - -void Compiler::VMINFP(u32 vd, u32 va, u32 vb) { - auto va_v4f32 = GetVrAsFloatVec(va); - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto res_v4f32 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse_min_ps), va_v4f32, vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VMINSB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto res_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pminsb), va_v16i8, vb_v16i8); - SetVr(vd, res_v16i8); -} - -void Compiler::VMINSH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto res_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_pmins_w), va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VMINSW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto res_v4i32 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pminsd), va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VMINUB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto res_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_pminu_b), va_v16i8, vb_v16i8); - SetVr(vd, res_v16i8); -} - -void Compiler::VMINUH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto res_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pminuw), va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VMINUW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto res_v4i32 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pminud), va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VMLADDUHM(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto vc_v8i16 = GetVrAsIntVec(vc, 16); - auto res_v8i16 = m_ir_builder->CreateMul(va_v8i16, vb_v8i16); - res_v8i16 = m_ir_builder->CreateAdd(res_v8i16, vc_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VMRGHB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - u32 mask_v16i32[16] = { 24, 8, 25, 9, 26, 10, 27, 11, 28, 12, 29, 13, 30, 14, 31, 15 }; - auto vd_v16i8 = m_ir_builder->CreateShuffleVector(va_v16i8, vb_v16i8, ConstantDataVector::get(m_ir_builder->getContext(), mask_v16i32)); - SetVr(vd, vd_v16i8); -} - -void Compiler::VMRGHH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - u32 mask_v8i32[8] = { 12, 4, 13, 5, 14, 6, 15, 7 }; - auto vd_v8i16 = m_ir_builder->CreateShuffleVector(va_v8i16, vb_v8i16, ConstantDataVector::get(m_ir_builder->getContext(), mask_v8i32)); - SetVr(vd, vd_v8i16); -} - -void Compiler::VMRGHW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - u32 mask_v4i32[4] = { 6, 2, 7, 3 }; - auto vd_v4i32 = m_ir_builder->CreateShuffleVector(va_v4i32, vb_v4i32, ConstantDataVector::get(m_ir_builder->getContext(), mask_v4i32)); - SetVr(vd, vd_v4i32); -} - -void Compiler::VMRGLB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - u32 mask_v16i32[16] = { 16, 0, 17, 1, 18, 2, 19, 3, 20, 4, 21, 5, 22, 6, 23, 7 }; - auto vd_v16i8 = m_ir_builder->CreateShuffleVector(va_v16i8, vb_v16i8, ConstantDataVector::get(m_ir_builder->getContext(), mask_v16i32)); - SetVr(vd, vd_v16i8); -} - -void Compiler::VMRGLH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - u32 mask_v8i32[8] = { 8, 0, 9, 1, 10, 2, 11, 3 }; - auto vd_v8i16 = m_ir_builder->CreateShuffleVector(va_v8i16, vb_v8i16, ConstantDataVector::get(m_ir_builder->getContext(), mask_v8i32)); - SetVr(vd, vd_v8i16); -} - -void Compiler::VMRGLW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - u32 mask_v4i32[4] = { 4, 0, 5, 1 }; - auto vd_v4i32 = m_ir_builder->CreateShuffleVector(va_v4i32, vb_v4i32, ConstantDataVector::get(m_ir_builder->getContext(), mask_v4i32)); - SetVr(vd, vd_v4i32); -} - -void Compiler::VMSUMMBM(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto va_v16i16 = m_ir_builder->CreateSExt(va_v16i8, VectorType::get(m_ir_builder->getInt16Ty(), 16)); - auto vb_v16i16 = m_ir_builder->CreateZExt(vb_v16i8, VectorType::get(m_ir_builder->getInt16Ty(), 16)); - auto tmp_v16i16 = m_ir_builder->CreateMul(va_v16i16, vb_v16i16); - - auto undef_v16i16 = UndefValue::get(VectorType::get(m_ir_builder->getInt16Ty(), 16)); - u32 mask1_v4i32[4] = { 0, 4, 8, 12 }; - auto tmp1_v4i16 = m_ir_builder->CreateShuffleVector(tmp_v16i16, undef_v16i16, ConstantDataVector::get(m_ir_builder->getContext(), mask1_v4i32)); - auto tmp1_v4i32 = m_ir_builder->CreateSExt(tmp1_v4i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - u32 mask2_v4i32[4] = { 1, 5, 9, 13 }; - auto tmp2_v4i16 = m_ir_builder->CreateShuffleVector(tmp_v16i16, undef_v16i16, ConstantDataVector::get(m_ir_builder->getContext(), mask2_v4i32)); - auto tmp2_v4i32 = m_ir_builder->CreateSExt(tmp2_v4i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - u32 mask3_v4i32[4] = { 2, 6, 10, 14 }; - auto tmp3_v4i16 = m_ir_builder->CreateShuffleVector(tmp_v16i16, undef_v16i16, ConstantDataVector::get(m_ir_builder->getContext(), mask3_v4i32)); - auto tmp3_v4i32 = m_ir_builder->CreateSExt(tmp3_v4i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - u32 mask4_v4i32[4] = { 3, 7, 11, 15 }; - auto tmp4_v4i16 = m_ir_builder->CreateShuffleVector(tmp_v16i16, undef_v16i16, ConstantDataVector::get(m_ir_builder->getContext(), mask4_v4i32)); - auto tmp4_v4i32 = m_ir_builder->CreateSExt(tmp4_v4i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - - auto vc_v4i32 = GetVrAsIntVec(vc, 32); - auto res_v4i32 = m_ir_builder->CreateAdd(tmp1_v4i32, tmp2_v4i32); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, tmp3_v4i32); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, tmp4_v4i32); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, vc_v4i32); - - SetVr(vd, res_v4i32); - - // TODO: Try to optimize with horizontal add -} - -void Compiler::VMSUMSHM(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto vc_v4i32 = GetVrAsIntVec(vc, 32); - auto res_v4i32 = (Value *)m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_pmadd_wd), va_v8i16, vb_v8i16); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, vc_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VMSUMSHS(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto vc_v4i32 = GetVrAsIntVec(vc, 32); - auto res_v4i32 = (Value *)m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_pmadd_wd), va_v8i16, vb_v8i16); - - auto tmp1_v4i32 = m_ir_builder->CreateLShr(vc_v4i32, 31); - tmp1_v4i32 = m_ir_builder->CreateAdd(tmp1_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x7FFFFFFF))); - auto tmp1_v16i8 = m_ir_builder->CreateBitCast(tmp1_v4i32, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - auto tmp2_v4i32 = m_ir_builder->CreateXor(vc_v4i32, res_v4i32); - tmp2_v4i32 = m_ir_builder->CreateNot(tmp2_v4i32); - auto sum_v4i32 = m_ir_builder->CreateAdd(vc_v4i32, res_v4i32); - auto sum_v16i8 = m_ir_builder->CreateBitCast(sum_v4i32, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - auto tmp3_v4i32 = m_ir_builder->CreateXor(vc_v4i32, sum_v4i32); - tmp3_v4i32 = m_ir_builder->CreateAnd(tmp2_v4i32, tmp3_v4i32); - tmp3_v4i32 = m_ir_builder->CreateAShr(tmp3_v4i32, 31); - auto tmp3_v16i8 = m_ir_builder->CreateBitCast(tmp3_v4i32, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - auto res_v16i8 = m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pblendvb), sum_v16i8, tmp1_v16i8, tmp3_v16i8); - SetVr(vd, res_v16i8); - - // TODO: Set VSCR.SAT -} - -void Compiler::VMSUMUBM(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto va_v16i16 = m_ir_builder->CreateZExt(va_v16i8, VectorType::get(m_ir_builder->getInt16Ty(), 16)); - auto vb_v16i16 = m_ir_builder->CreateZExt(vb_v16i8, VectorType::get(m_ir_builder->getInt16Ty(), 16)); - auto tmp_v16i16 = m_ir_builder->CreateMul(va_v16i16, vb_v16i16); - - auto undef_v16i16 = UndefValue::get(VectorType::get(m_ir_builder->getInt16Ty(), 16)); - u32 mask1_v4i32[4] = { 0, 4, 8, 12 }; - auto tmp1_v4i16 = m_ir_builder->CreateShuffleVector(tmp_v16i16, undef_v16i16, ConstantDataVector::get(m_ir_builder->getContext(), mask1_v4i32)); - auto tmp1_v4i32 = m_ir_builder->CreateZExt(tmp1_v4i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - u32 mask2_v4i32[4] = { 1, 5, 9, 13 }; - auto tmp2_v4i16 = m_ir_builder->CreateShuffleVector(tmp_v16i16, undef_v16i16, ConstantDataVector::get(m_ir_builder->getContext(), mask2_v4i32)); - auto tmp2_v4i32 = m_ir_builder->CreateZExt(tmp2_v4i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - u32 mask3_v4i32[4] = { 2, 6, 10, 14 }; - auto tmp3_v4i16 = m_ir_builder->CreateShuffleVector(tmp_v16i16, undef_v16i16, ConstantDataVector::get(m_ir_builder->getContext(), mask3_v4i32)); - auto tmp3_v4i32 = m_ir_builder->CreateZExt(tmp3_v4i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - u32 mask4_v4i32[4] = { 3, 7, 11, 15 }; - auto tmp4_v4i16 = m_ir_builder->CreateShuffleVector(tmp_v16i16, undef_v16i16, ConstantDataVector::get(m_ir_builder->getContext(), mask4_v4i32)); - auto tmp4_v4i32 = m_ir_builder->CreateZExt(tmp4_v4i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - - auto vc_v4i32 = GetVrAsIntVec(vc, 32); - auto res_v4i32 = m_ir_builder->CreateAdd(tmp1_v4i32, tmp2_v4i32); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, tmp3_v4i32); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, tmp4_v4i32); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, vc_v4i32); - - SetVr(vd, res_v4i32); - - // TODO: Try to optimize with horizontal add -} - -void Compiler::VMSUMUHM(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto va_v8i32 = m_ir_builder->CreateZExt(va_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto vb_v8i32 = m_ir_builder->CreateZExt(vb_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto tmp_v8i32 = m_ir_builder->CreateMul(va_v8i32, vb_v8i32); - - auto undef_v8i32 = UndefValue::get(VectorType::get(m_ir_builder->getInt32Ty(), 8)); - u32 mask1_v4i32[4] = { 0, 2, 4, 6 }; - auto tmp1_v4i32 = m_ir_builder->CreateShuffleVector(tmp_v8i32, undef_v8i32, ConstantDataVector::get(m_ir_builder->getContext(), mask1_v4i32)); - u32 mask2_v4i32[4] = { 1, 3, 5, 7 }; - auto tmp2_v4i32 = m_ir_builder->CreateShuffleVector(tmp_v8i32, undef_v8i32, ConstantDataVector::get(m_ir_builder->getContext(), mask2_v4i32)); - - auto vc_v4i32 = GetVrAsIntVec(vc, 32); - auto res_v4i32 = m_ir_builder->CreateAdd(tmp1_v4i32, tmp2_v4i32); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, vc_v4i32); - - SetVr(vd, res_v4i32); - - // TODO: Try to optimize with horizontal add -} - -void Compiler::VMSUMUHS(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto va_v8i32 = m_ir_builder->CreateZExt(va_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto vb_v8i32 = m_ir_builder->CreateZExt(vb_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 8)); - auto tmp_v8i32 = m_ir_builder->CreateMul(va_v8i32, vb_v8i32); - auto tmp_v8i64 = m_ir_builder->CreateZExt(tmp_v8i32, VectorType::get(m_ir_builder->getInt64Ty(), 8)); - - u32 mask1_v4i32[4] = { 0, 2, 4, 6 }; - u32 mask2_v4i32[4] = { 1, 3, 5, 7 }; - auto tmp1_v4i64 = m_ir_builder->CreateShuffleVector(tmp_v8i64, UndefValue::get(tmp_v8i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask1_v4i32)); - auto tmp2_v4i64 = m_ir_builder->CreateShuffleVector(tmp_v8i64, UndefValue::get(tmp_v8i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask2_v4i32)); - - auto vc_v4i32 = GetVrAsIntVec(vc, 32); - auto vc_v4i64 = m_ir_builder->CreateZExt(vc_v4i32, VectorType::get(m_ir_builder->getInt64Ty(), 4)); - auto res_v4i64 = m_ir_builder->CreateAdd(tmp1_v4i64, tmp2_v4i64); - res_v4i64 = m_ir_builder->CreateAdd(res_v4i64, vc_v4i64); - auto gt_v4i1 = m_ir_builder->CreateICmpUGT(res_v4i64, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(0xFFFFFFFF))); - auto gt_v4i64 = m_ir_builder->CreateSExt(gt_v4i1, VectorType::get(m_ir_builder->getInt64Ty(), 4)); - res_v4i64 = m_ir_builder->CreateOr(res_v4i64, gt_v4i64); - auto res_v4i32 = m_ir_builder->CreateTrunc(res_v4i64, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, res_v4i32); - - // TODO: Set VSCR.SAT -} - -void Compiler::VMULESB(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - va_v8i16 = m_ir_builder->CreateAShr(va_v8i16, 8); - vb_v8i16 = m_ir_builder->CreateAShr(vb_v8i16, 8); - auto res_v8i16 = m_ir_builder->CreateMul(va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VMULESH(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - va_v4i32 = m_ir_builder->CreateAShr(va_v4i32, 16); - vb_v4i32 = m_ir_builder->CreateAShr(vb_v4i32, 16); - auto res_v4i32 = m_ir_builder->CreateMul(va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VMULEUB(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - va_v8i16 = m_ir_builder->CreateLShr(va_v8i16, 8); - vb_v8i16 = m_ir_builder->CreateLShr(vb_v8i16, 8); - auto res_v8i16 = m_ir_builder->CreateMul(va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VMULEUH(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - va_v4i32 = m_ir_builder->CreateLShr(va_v4i32, 16); - vb_v4i32 = m_ir_builder->CreateLShr(vb_v4i32, 16); - auto res_v4i32 = m_ir_builder->CreateMul(va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VMULOSB(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - va_v8i16 = m_ir_builder->CreateShl(va_v8i16, 8); - va_v8i16 = m_ir_builder->CreateAShr(va_v8i16, 8); - vb_v8i16 = m_ir_builder->CreateShl(vb_v8i16, 8); - vb_v8i16 = m_ir_builder->CreateAShr(vb_v8i16, 8); - auto res_v8i16 = m_ir_builder->CreateMul(va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VMULOSH(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - va_v4i32 = m_ir_builder->CreateShl(va_v4i32, 16); - va_v4i32 = m_ir_builder->CreateAShr(va_v4i32, 16); - vb_v4i32 = m_ir_builder->CreateShl(vb_v4i32, 16); - vb_v4i32 = m_ir_builder->CreateAShr(vb_v4i32, 16); - auto res_v4i32 = m_ir_builder->CreateMul(va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VMULOUB(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - va_v8i16 = m_ir_builder->CreateShl(va_v8i16, 8); - va_v8i16 = m_ir_builder->CreateLShr(va_v8i16, 8); - vb_v8i16 = m_ir_builder->CreateShl(vb_v8i16, 8); - vb_v8i16 = m_ir_builder->CreateLShr(vb_v8i16, 8); - auto res_v8i16 = m_ir_builder->CreateMul(va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VMULOUH(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - va_v4i32 = m_ir_builder->CreateShl(va_v4i32, 16); - va_v4i32 = m_ir_builder->CreateLShr(va_v4i32, 16); - vb_v4i32 = m_ir_builder->CreateShl(vb_v4i32, 16); - vb_v4i32 = m_ir_builder->CreateLShr(vb_v4i32, 16); - auto res_v4i32 = m_ir_builder->CreateMul(va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VNMSUBFP(u32 vd, u32 va, u32 vc, u32 vb) { - auto va_v4f32 = GetVrAsFloatVec(va); - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto vc_v4f32 = GetVrAsFloatVec(vc); - vc_v4f32 = m_ir_builder->CreateFNeg(vc_v4f32); - auto res_v4f32 = (Value *)m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, VectorType::get(m_ir_builder->getFloatTy(), 4)), va_v4f32, vc_v4f32, vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VNOR(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto res_v8i16 = m_ir_builder->CreateOr(va_v8i16, vb_v8i16); - res_v8i16 = m_ir_builder->CreateNot(res_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VOR(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto res_v8i16 = m_ir_builder->CreateOr(va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VPERM(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto vc_v16i8 = GetVrAsIntVec(vc, 8); - - auto thrity_one_v16i8 = m_ir_builder->CreateVectorSplat(16, m_ir_builder->getInt8(31)); - vc_v16i8 = m_ir_builder->CreateAnd(vc_v16i8, thrity_one_v16i8); - - auto fifteen_v16i8 = m_ir_builder->CreateVectorSplat(16, m_ir_builder->getInt8(15)); - auto vc_le15_v16i8 = m_ir_builder->CreateSub(fifteen_v16i8, vc_v16i8); - auto res_va_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_ssse3_pshuf_b_128), va_v16i8, vc_le15_v16i8); - - auto vc_gt15_v16i8 = m_ir_builder->CreateSub(thrity_one_v16i8, vc_v16i8); - auto cmp_i1 = m_ir_builder->CreateICmpUGT(vc_gt15_v16i8, fifteen_v16i8); - auto cmp_i8 = m_ir_builder->CreateSExt(cmp_i1, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - vc_gt15_v16i8 = m_ir_builder->CreateOr(cmp_i8, vc_gt15_v16i8); - auto res_vb_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_ssse3_pshuf_b_128), vb_v16i8, vc_gt15_v16i8); - - auto res_v16i8 = m_ir_builder->CreateOr(res_vb_v16i8, res_va_v16i8); - SetVr(vd, res_v16i8); -} - -void Compiler::VPKPX(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - - auto tmpa_v4i32 = m_ir_builder->CreateShl(va_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(7))); - tmpa_v4i32 = m_ir_builder->CreateAnd(tmpa_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0xFC000000))); - va_v4i32 = m_ir_builder->CreateShl(va_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(10))); - va_v4i32 = m_ir_builder->CreateAnd(va_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(~0xFC000000))); - tmpa_v4i32 = m_ir_builder->CreateOr(tmpa_v4i32, va_v4i32); - tmpa_v4i32 = m_ir_builder->CreateAnd(tmpa_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0xFFE00000))); - va_v4i32 = m_ir_builder->CreateShl(va_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(3))); - va_v4i32 = m_ir_builder->CreateAnd(va_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(~0xFFE00000))); - tmpa_v4i32 = m_ir_builder->CreateOr(tmpa_v4i32, va_v4i32); - auto tmpa_v8i16 = m_ir_builder->CreateBitCast(tmpa_v4i32, VectorType::get(m_ir_builder->getInt16Ty(), 8)); - - auto tmpb_v4i32 = m_ir_builder->CreateShl(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(7))); - tmpb_v4i32 = m_ir_builder->CreateAnd(tmpb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0xFC000000))); - vb_v4i32 = m_ir_builder->CreateShl(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(10))); - vb_v4i32 = m_ir_builder->CreateAnd(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(~0xFC000000))); - tmpb_v4i32 = m_ir_builder->CreateOr(tmpb_v4i32, vb_v4i32); - tmpb_v4i32 = m_ir_builder->CreateAnd(tmpb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0xFFE00000))); - vb_v4i32 = m_ir_builder->CreateShl(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(3))); - vb_v4i32 = m_ir_builder->CreateAnd(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(~0xFFE00000))); - tmpb_v4i32 = m_ir_builder->CreateOr(tmpb_v4i32, vb_v4i32); - auto tmpb_v8i16 = m_ir_builder->CreateBitCast(tmpb_v4i32, VectorType::get(m_ir_builder->getInt16Ty(), 8)); - - u32 mask_v8i32[8] = { 1, 3, 5, 7, 9, 11, 13, 15 }; - auto res_v8i16 = m_ir_builder->CreateShuffleVector(tmpb_v8i16, tmpa_v8i16, ConstantDataVector::get(m_ir_builder->getContext(), mask_v8i32)); - - SetVr(vd, res_v8i16); - - // TODO: Implement with pext on CPUs with BMI -} - -void Compiler::VPKSHSS(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto res_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_packsswb_128), vb_v8i16, va_v8i16); - SetVr(vd, res_v16i8); - - // TODO: VSCR.SAT -} - -void Compiler::VPKSHUS(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto res_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_packuswb_128), vb_v8i16, va_v8i16); - SetVr(vd, res_v16i8); - - // TODO: VSCR.SAT -} - -void Compiler::VPKSWSS(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto res_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_packssdw_128), vb_v4i32, va_v4i32); - SetVr(vd, res_v8i16); - - // TODO: VSCR.SAT -} - -void Compiler::VPKSWUS(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto res_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_packusdw), vb_v4i32, va_v4i32); - SetVr(vd, res_v8i16); - - // TODO: VSCR.SAT -} - -void Compiler::VPKUHUM(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - - u32 mask_v16i32[16] = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30 }; - auto res_v16i8 = m_ir_builder->CreateShuffleVector(vb_v16i8, va_v16i8, ConstantDataVector::get(m_ir_builder->getContext(), mask_v16i32)); - SetVr(vd, res_v16i8); -} - -void Compiler::VPKUHUS(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - va_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pminuw), va_v8i16, m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt16(0xFF))); - vb_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pminuw), vb_v8i16, m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt16(0xFF))); - auto va_v16i8 = m_ir_builder->CreateBitCast(va_v8i16, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - auto vb_v16i8 = m_ir_builder->CreateBitCast(vb_v8i16, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - - u32 mask_v16i32[16] = { 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30 }; - auto res_v16i8 = m_ir_builder->CreateShuffleVector(vb_v16i8, va_v16i8, ConstantDataVector::get(m_ir_builder->getContext(), mask_v16i32)); - SetVr(vd, res_v16i8); - - // TODO: Set VSCR.SAT -} - -void Compiler::VPKUWUM(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - - u32 mask_v8i32[8] = { 0, 2, 4, 6, 8, 10, 12, 14 }; - auto res_v8i16 = m_ir_builder->CreateShuffleVector(vb_v8i16, va_v8i16, ConstantDataVector::get(m_ir_builder->getContext(), mask_v8i32)); - SetVr(vd, res_v8i16); -} - -void Compiler::VPKUWUS(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - va_v4i32 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pminud), va_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0xFFFF))); - vb_v4i32 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pminud), vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0xFFFF))); - auto va_v8i16 = m_ir_builder->CreateBitCast(va_v4i32, VectorType::get(m_ir_builder->getInt16Ty(), 8)); - auto vb_v8i16 = m_ir_builder->CreateBitCast(vb_v4i32, VectorType::get(m_ir_builder->getInt16Ty(), 8)); - - u32 mask_v8i32[8] = { 0, 2, 4, 6, 8, 10, 12, 14 }; - auto res_v8i16 = m_ir_builder->CreateShuffleVector(vb_v8i16, va_v8i16, ConstantDataVector::get(m_ir_builder->getContext(), mask_v8i32)); - SetVr(vd, res_v8i16); - - // TODO: Set VSCR.SAT -} - -void Compiler::VREFP(u32 vd, u32 vb) { - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto res_v4f32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse_rcp_ps), vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VRFIM(u32 vd, u32 vb) { - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto res_v4f32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::floor, VectorType::get(m_ir_builder->getFloatTy(), 4)), vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VRFIN(u32 vd, u32 vb) { - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto res_v4f32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::nearbyint, VectorType::get(m_ir_builder->getFloatTy(), 4)), vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VRFIP(u32 vd, u32 vb) { - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto res_v4f32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::ceil, VectorType::get(m_ir_builder->getFloatTy(), 4)), vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VRFIZ(u32 vd, u32 vb) { - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto res_v4f32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::trunc, VectorType::get(m_ir_builder->getFloatTy(), 4)), vb_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VRLB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - vb_v16i8 = m_ir_builder->CreateAnd(vb_v16i8, m_ir_builder->CreateVectorSplat(16, m_ir_builder->getInt8(7))); - auto tmp1_v16i8 = m_ir_builder->CreateShl(va_v16i8, vb_v16i8); - vb_v16i8 = m_ir_builder->CreateSub(m_ir_builder->CreateVectorSplat(16, m_ir_builder->getInt8(8)), vb_v16i8); - auto tmp2_v16i8 = m_ir_builder->CreateLShr(va_v16i8, vb_v16i8); - auto res_v16i8 = m_ir_builder->CreateOr(tmp1_v16i8, tmp2_v16i8); - SetVr(vd, res_v16i8); -} - -void Compiler::VRLH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - vb_v8i16 = m_ir_builder->CreateAnd(vb_v8i16, m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt16(0xF))); - auto tmp1_v8i16 = m_ir_builder->CreateShl(va_v8i16, vb_v8i16); - vb_v8i16 = m_ir_builder->CreateSub(m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt16(0x10)), vb_v8i16); - auto tmp2_v8i16 = m_ir_builder->CreateLShr(va_v8i16, vb_v8i16); - auto res_v8i16 = m_ir_builder->CreateOr(tmp1_v8i16, tmp2_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VRLW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - vb_v4i32 = m_ir_builder->CreateAnd(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x1F))); - auto tmp1_v4i32 = m_ir_builder->CreateShl(va_v4i32, vb_v4i32); - vb_v4i32 = m_ir_builder->CreateSub(m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x20)), vb_v4i32); - auto tmp2_v4i32 = m_ir_builder->CreateLShr(va_v4i32, vb_v4i32); - auto res_v4i32 = m_ir_builder->CreateOr(tmp1_v4i32, tmp2_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VRSQRTEFP(u32 vd, u32 vb) { - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto res_v4f32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::sqrt, VectorType::get(m_ir_builder->getFloatTy(), 4)), vb_v4f32); - res_v4f32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse_rcp_ps), res_v4f32); - SetVr(vd, res_v4f32); -} - -void Compiler::VSEL(u32 vd, u32 va, u32 vb, u32 vc) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto vc_v4i32 = GetVrAsIntVec(vc, 32); - vb_v4i32 = m_ir_builder->CreateAnd(vb_v4i32, vc_v4i32); - vc_v4i32 = m_ir_builder->CreateNot(vc_v4i32); - va_v4i32 = m_ir_builder->CreateAnd(va_v4i32, vc_v4i32); - auto vd_v4i32 = m_ir_builder->CreateOr(va_v4i32, vb_v4i32); - SetVr(vd, vd_v4i32); -} - -void Compiler::VSL(u32 vd, u32 va, u32 vb) { - auto va_i128 = GetVr(va); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto sh_i8 = m_ir_builder->CreateExtractElement(vb_v16i8, m_ir_builder->getInt8(0)); - sh_i8 = m_ir_builder->CreateAnd(sh_i8, 0x7); - auto sh_i128 = m_ir_builder->CreateZExt(sh_i8, m_ir_builder->getIntNTy(128)); - va_i128 = m_ir_builder->CreateShl(va_i128, sh_i128); - SetVr(vd, va_i128); -} - -void Compiler::VSLB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - vb_v16i8 = m_ir_builder->CreateAnd(vb_v16i8, m_ir_builder->CreateVectorSplat(16, m_ir_builder->getInt8(0x7))); - auto res_v16i8 = m_ir_builder->CreateShl(va_v16i8, vb_v16i8); - SetVr(vd, res_v16i8); -} - -void Compiler::VSLDOI(u32 vd, u32 va, u32 vb, u32 sh) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - sh = 16 - sh; - u32 mask_v16i32[16] = { sh, sh + 1, sh + 2, sh + 3, sh + 4, sh + 5, sh + 6, sh + 7, sh + 8, sh + 9, sh + 10, sh + 11, sh + 12, sh + 13, sh + 14, sh + 15 }; - auto vd_v16i8 = m_ir_builder->CreateShuffleVector(vb_v16i8, va_v16i8, ConstantDataVector::get(m_ir_builder->getContext(), mask_v16i32)); - SetVr(vd, vd_v16i8); -} - -void Compiler::VSLH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - vb_v8i16 = m_ir_builder->CreateAnd(vb_v8i16, m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt16(0xF))); - auto res_v8i16 = m_ir_builder->CreateShl(va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VSLO(u32 vd, u32 va, u32 vb) { - auto va_i128 = GetVr(va); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto sh_i8 = m_ir_builder->CreateExtractElement(vb_v16i8, m_ir_builder->getInt8(0)); - sh_i8 = m_ir_builder->CreateAnd(sh_i8, 0x78); - auto sh_i128 = m_ir_builder->CreateZExt(sh_i8, m_ir_builder->getIntNTy(128)); - va_i128 = m_ir_builder->CreateShl(va_i128, sh_i128); - SetVr(vd, va_i128); -} - -void Compiler::VSLW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - vb_v4i32 = m_ir_builder->CreateAnd(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x1F))); - auto res_v4i32 = m_ir_builder->CreateShl(va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VSPLTB(u32 vd, u32 uimm5, u32 vb) { - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto undef_v16i8 = UndefValue::get(VectorType::get(m_ir_builder->getInt8Ty(), 16)); - auto mask_v16i32 = m_ir_builder->CreateVectorSplat(16, m_ir_builder->getInt32(15 - uimm5)); - auto res_v16i8 = m_ir_builder->CreateShuffleVector(vb_v16i8, undef_v16i8, mask_v16i32); - SetVr(vd, res_v16i8); -} - -void Compiler::VSPLTH(u32 vd, u32 uimm5, u32 vb) { - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto undef_v8i16 = UndefValue::get(VectorType::get(m_ir_builder->getInt16Ty(), 8)); - auto mask_v8i32 = m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt32(7 - uimm5)); - auto res_v8i16 = m_ir_builder->CreateShuffleVector(vb_v8i16, undef_v8i16, mask_v8i32); - SetVr(vd, res_v8i16); -} - -void Compiler::VSPLTISB(u32 vd, s32 simm5) { - auto vd_v16i8 = m_ir_builder->CreateVectorSplat(16, m_ir_builder->getInt8((s8)simm5)); - SetVr(vd, vd_v16i8); -} - -void Compiler::VSPLTISH(u32 vd, s32 simm5) { - auto vd_v8i16 = m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt16((s16)simm5)); - SetVr(vd, vd_v8i16); -} - -void Compiler::VSPLTISW(u32 vd, s32 simm5) { - auto vd_v4i32 = m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32((s32)simm5)); - SetVr(vd, vd_v4i32); -} - -void Compiler::VSPLTW(u32 vd, u32 uimm5, u32 vb) { - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto undef_v4i32 = UndefValue::get(VectorType::get(m_ir_builder->getInt32Ty(), 4)); - auto mask_v4i32 = m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(3 - uimm5)); - auto res_v4i32 = m_ir_builder->CreateShuffleVector(vb_v4i32, undef_v4i32, mask_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VSR(u32 vd, u32 va, u32 vb) { - auto va_i128 = GetVr(va); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto sh_i8 = m_ir_builder->CreateExtractElement(vb_v16i8, m_ir_builder->getInt8(0)); - sh_i8 = m_ir_builder->CreateAnd(sh_i8, 0x7); - auto sh_i128 = m_ir_builder->CreateZExt(sh_i8, m_ir_builder->getIntNTy(128)); - va_i128 = m_ir_builder->CreateLShr(va_i128, sh_i128); - SetVr(vd, va_i128); -} - -void Compiler::VSRAB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - vb_v16i8 = m_ir_builder->CreateAnd(vb_v16i8, m_ir_builder->CreateVectorSplat(16, m_ir_builder->getInt8(0x7))); - auto res_v16i8 = m_ir_builder->CreateAShr(va_v16i8, vb_v16i8); - SetVr(vd, res_v16i8); -} - -void Compiler::VSRAH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - vb_v8i16 = m_ir_builder->CreateAnd(vb_v8i16, m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt16(0xF))); - auto res_v8i16 = m_ir_builder->CreateAShr(va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VSRAW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - vb_v4i32 = m_ir_builder->CreateAnd(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x1F))); - auto res_v4i32 = m_ir_builder->CreateAShr(va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VSRB(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - vb_v16i8 = m_ir_builder->CreateAnd(vb_v16i8, m_ir_builder->CreateVectorSplat(16, m_ir_builder->getInt8(0x7))); - auto res_v16i8 = m_ir_builder->CreateLShr(va_v16i8, vb_v16i8); - SetVr(vd, res_v16i8); -} - -void Compiler::VSRH(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - vb_v8i16 = m_ir_builder->CreateAnd(vb_v8i16, m_ir_builder->CreateVectorSplat(8, m_ir_builder->getInt16(0xF))); - auto res_v8i16 = m_ir_builder->CreateLShr(va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::VSRO(u32 vd, u32 va, u32 vb) { - auto va_i128 = GetVr(va); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto sh_i8 = m_ir_builder->CreateExtractElement(vb_v16i8, m_ir_builder->getInt8(0)); - sh_i8 = m_ir_builder->CreateAnd(sh_i8, 0x78); - auto sh_i128 = m_ir_builder->CreateZExt(sh_i8, m_ir_builder->getIntNTy(128)); - va_i128 = m_ir_builder->CreateLShr(va_i128, sh_i128); - SetVr(vd, va_i128); -} - -void Compiler::VSRW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - vb_v4i32 = m_ir_builder->CreateAnd(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x1F))); - auto res_v4i32 = m_ir_builder->CreateLShr(va_v4i32, vb_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VSUBCUW(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - - auto cmpv4i1 = m_ir_builder->CreateICmpUGE(va_v4i32, vb_v4i32); - auto cmpv4i32 = m_ir_builder->CreateZExt(cmpv4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, cmpv4i32); -} - -void Compiler::VSUBFP(u32 vd, u32 va, u32 vb) { - auto va_v4f32 = GetVrAsFloatVec(va); - auto vb_v4f32 = GetVrAsFloatVec(vb); - auto diff_v4f32 = m_ir_builder->CreateFSub(va_v4f32, vb_v4f32); - SetVr(vd, diff_v4f32); -} - -void Compiler::VSUBSBS(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto diff_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_psubs_b), va_v16i8, vb_v16i8); - SetVr(vd, diff_v16i8); - - // TODO: Set VSCR.SAT -} - -void Compiler::VSUBSHS(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto diff_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_psubs_w), va_v8i16, vb_v8i16); - SetVr(vd, diff_v8i16); - - // TODO: Set VSCR.SAT -} - -void Compiler::VSUBSWS(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - - // See the comments for VADDSWS for a detailed description of how this works - - // Find the result in case of an overflow - auto tmp1_v4i32 = m_ir_builder->CreateLShr(va_v4i32, 31); - tmp1_v4i32 = m_ir_builder->CreateAdd(tmp1_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x7FFFFFFF))); - auto tmp1_v16i8 = m_ir_builder->CreateBitCast(tmp1_v4i32, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - - // Find the elements that can overflow (elements with opposite sign bits) - auto tmp2_v4i32 = m_ir_builder->CreateXor(va_v4i32, vb_v4i32); - - // Perform the sub - auto diff_v4i32 = m_ir_builder->CreateSub(va_v4i32, vb_v4i32); - auto diff_v16i8 = m_ir_builder->CreateBitCast(diff_v4i32, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - - // Find the elements that overflowed - auto tmp3_v4i32 = m_ir_builder->CreateXor(va_v4i32, diff_v4i32); - tmp3_v4i32 = m_ir_builder->CreateAnd(tmp2_v4i32, tmp3_v4i32); - tmp3_v4i32 = m_ir_builder->CreateAShr(tmp3_v4i32, 31); - auto tmp3_v16i8 = m_ir_builder->CreateBitCast(tmp3_v4i32, VectorType::get(m_ir_builder->getInt8Ty(), 16)); - - // tmp4 is equal to 0xFFFFFFFF if an overflow occured and 0x00000000 otherwise. - auto res_v16i8 = m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse41_pblendvb), diff_v16i8, tmp1_v16i8, tmp3_v16i8); - SetVr(vd, res_v16i8); - - // TODO: Set SAT -} - -void Compiler::VSUBUBM(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto diff_v16i8 = m_ir_builder->CreateSub(va_v16i8, vb_v16i8); - SetVr(vd, diff_v16i8); -} - -void Compiler::VSUBUBS(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - auto diff_v16i8 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_psubus_b), va_v16i8, vb_v16i8); - SetVr(vd, diff_v16i8); - - // TODO: Set SAT -} - -void Compiler::VSUBUHM(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto diff_v8i16 = m_ir_builder->CreateSub(va_v8i16, vb_v8i16); - SetVr(vd, diff_v8i16); -} - -void Compiler::VSUBUHS(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto diff_v8i16 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_psubus_w), va_v8i16, vb_v8i16); - SetVr(vd, diff_v8i16); - - // TODO: Set SAT -} - -void Compiler::VSUBUWM(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto diff_v4i32 = m_ir_builder->CreateSub(va_v4i32, vb_v4i32); - SetVr(vd, diff_v4i32); -} - -void Compiler::VSUBUWS(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - auto diff_v4i32 = m_ir_builder->CreateSub(va_v4i32, vb_v4i32); - auto cmp_v4i1 = m_ir_builder->CreateICmpULE(diff_v4i32, va_v4i32); - auto cmp_v4i32 = m_ir_builder->CreateSExt(cmp_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - auto res_v4i32 = m_ir_builder->CreateAnd(diff_v4i32, cmp_v4i32); - SetVr(vd, res_v4i32); - - // TODO: Set SAT -} - -void Compiler::VSUMSWS(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - - auto res_i32 = m_ir_builder->CreateExtractElement(vb_v4i32, m_ir_builder->getInt32(3)); - auto res_i64 = m_ir_builder->CreateSExt(res_i32, m_ir_builder->getInt64Ty()); - for (auto i = 0; i < 4; i++) { - auto va_i32 = m_ir_builder->CreateExtractElement(va_v4i32, m_ir_builder->getInt32(i)); - auto va_i64 = m_ir_builder->CreateSExt(va_i32, m_ir_builder->getInt64Ty()); - res_i64 = m_ir_builder->CreateAdd(res_i64, va_i64); - } - - auto gt_i1 = m_ir_builder->CreateICmpSGT(res_i64, m_ir_builder->getInt64(0x7FFFFFFFull)); - auto lt_i1 = m_ir_builder->CreateICmpSLT(res_i64, m_ir_builder->getInt64(0xFFFFFFFF80000000ull)); - res_i64 = m_ir_builder->CreateSelect(gt_i1, m_ir_builder->getInt64(0x7FFFFFFFull), res_i64); - res_i64 = m_ir_builder->CreateSelect(lt_i1, m_ir_builder->getInt64(0xFFFFFFFF80000000ull), res_i64); - auto res_i128 = m_ir_builder->CreateZExt(res_i64, m_ir_builder->getIntNTy(128)); - - SetVr(vd, res_i128); - - // TODO: Set VSCR.SAT -} - -void Compiler::VSUM2SWS(u32 vd, u32 va, u32 vb) { - auto va_v4i32 = GetVrAsIntVec(va, 32); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - - u32 mask1_v2i32[2] = { 0, 2 }; - u32 mask2_v2i32[2] = { 1, 3 }; - auto va_v4i64 = m_ir_builder->CreateSExt(va_v4i32, VectorType::get(m_ir_builder->getInt64Ty(), 4)); - auto va1_v2i64 = m_ir_builder->CreateShuffleVector(va_v4i64, UndefValue::get(va_v4i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask1_v2i32)); - auto va2_v2i64 = m_ir_builder->CreateShuffleVector(va_v4i64, UndefValue::get(va_v4i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask2_v2i32)); - auto vb_v4i64 = m_ir_builder->CreateSExt(vb_v4i32, VectorType::get(m_ir_builder->getInt64Ty(), 4)); - auto vb_v2i64 = m_ir_builder->CreateShuffleVector(vb_v4i64, UndefValue::get(vb_v4i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask1_v2i32)); - - auto res_v2i64 = m_ir_builder->CreateAdd(va1_v2i64, va2_v2i64); - res_v2i64 = m_ir_builder->CreateAdd(res_v2i64, vb_v2i64); - auto gt_v2i1 = m_ir_builder->CreateICmpSGT(res_v2i64, m_ir_builder->CreateVectorSplat(2, m_ir_builder->getInt64(0x7FFFFFFFull))); - auto lt_v2i1 = m_ir_builder->CreateICmpSLT(res_v2i64, m_ir_builder->CreateVectorSplat(2, m_ir_builder->getInt64(0xFFFFFFFF80000000ull))); - res_v2i64 = m_ir_builder->CreateSelect(gt_v2i1, m_ir_builder->CreateVectorSplat(2, m_ir_builder->getInt64(0x7FFFFFFFull)), res_v2i64); - res_v2i64 = m_ir_builder->CreateSelect(lt_v2i1, m_ir_builder->CreateVectorSplat(2, m_ir_builder->getInt64(0x80000000ull)), res_v2i64); - SetVr(vd, res_v2i64); - - // TODO: Set VSCR.SAT -} - -void Compiler::VSUM4SBS(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - - u32 mask1_v4i32[4] = { 0, 4, 8, 12 }; - u32 mask2_v4i32[4] = { 1, 5, 9, 13 }; - u32 mask3_v4i32[4] = { 2, 6, 10, 14 }; - u32 mask4_v4i32[4] = { 3, 7, 11, 15 }; - auto va_v16i64 = m_ir_builder->CreateSExt(va_v16i8, VectorType::get(m_ir_builder->getInt64Ty(), 16)); - auto va1_v4i64 = m_ir_builder->CreateShuffleVector(va_v16i64, UndefValue::get(va_v16i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask1_v4i32)); - auto va2_v4i64 = m_ir_builder->CreateShuffleVector(va_v16i64, UndefValue::get(va_v16i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask2_v4i32)); - auto va3_v4i64 = m_ir_builder->CreateShuffleVector(va_v16i64, UndefValue::get(va_v16i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask3_v4i32)); - auto va4_v4i64 = m_ir_builder->CreateShuffleVector(va_v16i64, UndefValue::get(va_v16i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask4_v4i32)); - auto vb_v4i64 = m_ir_builder->CreateSExt(vb_v4i32, VectorType::get(m_ir_builder->getInt64Ty(), 4)); - - auto res_v4i64 = m_ir_builder->CreateAdd(va1_v4i64, va2_v4i64); - res_v4i64 = m_ir_builder->CreateAdd(res_v4i64, va3_v4i64); - res_v4i64 = m_ir_builder->CreateAdd(res_v4i64, va4_v4i64); - res_v4i64 = m_ir_builder->CreateAdd(res_v4i64, vb_v4i64); - auto gt_v4i1 = m_ir_builder->CreateICmpSGT(res_v4i64, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(0x7FFFFFFFull))); - auto lt_v4i1 = m_ir_builder->CreateICmpSLT(res_v4i64, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(0xFFFFFFFF80000000ull))); - res_v4i64 = m_ir_builder->CreateSelect(gt_v4i1, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(0x7FFFFFFFull)), res_v4i64); - res_v4i64 = m_ir_builder->CreateSelect(lt_v4i1, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(0x80000000ull)), res_v4i64); - auto res_v4i32 = m_ir_builder->CreateTrunc(res_v4i64, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, res_v4i32); - - // TODO: Set VSCR.SAT -} - -void Compiler::VSUM4SHS(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - - u32 mask1_v4i32[4] = { 0, 2, 4, 6 }; - u32 mask2_v4i32[4] = { 1, 3, 5, 7 }; - auto va_v8i64 = m_ir_builder->CreateSExt(va_v8i16, VectorType::get(m_ir_builder->getInt64Ty(), 8)); - auto va1_v4i64 = m_ir_builder->CreateShuffleVector(va_v8i64, UndefValue::get(va_v8i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask1_v4i32)); - auto va2_v4i64 = m_ir_builder->CreateShuffleVector(va_v8i64, UndefValue::get(va_v8i64->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask2_v4i32)); - auto vb_v4i64 = m_ir_builder->CreateSExt(vb_v4i32, VectorType::get(m_ir_builder->getInt64Ty(), 4)); - - auto res_v4i64 = m_ir_builder->CreateAdd(va1_v4i64, va2_v4i64); - res_v4i64 = m_ir_builder->CreateAdd(res_v4i64, vb_v4i64); - auto gt_v4i1 = m_ir_builder->CreateICmpSGT(res_v4i64, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(0x7FFFFFFFull))); - auto lt_v4i1 = m_ir_builder->CreateICmpSLT(res_v4i64, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(0xFFFFFFFF80000000ull))); - res_v4i64 = m_ir_builder->CreateSelect(gt_v4i1, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(0x7FFFFFFFull)), res_v4i64); - res_v4i64 = m_ir_builder->CreateSelect(lt_v4i1, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt64(0x80000000ull)), res_v4i64); - auto res_v4i32 = m_ir_builder->CreateTrunc(res_v4i64, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, res_v4i32); - - // TODO: Set VSCR.SAT -} - -void Compiler::VSUM4UBS(u32 vd, u32 va, u32 vb) { - auto va_v16i8 = GetVrAsIntVec(va, 8); - auto vb_v4i32 = GetVrAsIntVec(vb, 32); - - u32 mask1_v4i32[4] = { 0, 4, 8, 12 }; - u32 mask2_v4i32[4] = { 1, 5, 9, 13 }; - u32 mask3_v4i32[4] = { 2, 6, 10, 14 }; - u32 mask4_v4i32[4] = { 3, 7, 11, 15 }; - auto va1_v4i8 = m_ir_builder->CreateShuffleVector(va_v16i8, UndefValue::get(va_v16i8->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask1_v4i32)); - auto va1_v4i32 = m_ir_builder->CreateZExt(va1_v4i8, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - auto va2_v4i8 = m_ir_builder->CreateShuffleVector(va_v16i8, UndefValue::get(va_v16i8->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask2_v4i32)); - auto va2_v4i32 = m_ir_builder->CreateZExt(va2_v4i8, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - auto va3_v4i8 = m_ir_builder->CreateShuffleVector(va_v16i8, UndefValue::get(va_v16i8->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask3_v4i32)); - auto va3_v4i32 = m_ir_builder->CreateZExt(va3_v4i8, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - auto va4_v4i8 = m_ir_builder->CreateShuffleVector(va_v16i8, UndefValue::get(va_v16i8->getType()), ConstantDataVector::get(m_ir_builder->getContext(), mask4_v4i32)); - auto va4_v4i32 = m_ir_builder->CreateZExt(va4_v4i8, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - - auto res_v4i32 = m_ir_builder->CreateAdd(va1_v4i32, va2_v4i32); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, va3_v4i32); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, va4_v4i32); - res_v4i32 = m_ir_builder->CreateAdd(res_v4i32, vb_v4i32); - auto lt_v4i1 = m_ir_builder->CreateICmpULT(res_v4i32, vb_v4i32); - auto lt_v4i32 = m_ir_builder->CreateSExt(lt_v4i1, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - res_v4i32 = m_ir_builder->CreateOr(lt_v4i32, res_v4i32); - SetVr(vd, res_v4i32); - - // TODO: Set VSCR.SAT -} - -void Compiler::VUPKHPX(u32 vd, u32 vb) { - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - u32 mask_v8i32[8] = { 4, 4, 5, 5, 6, 6, 7, 7 }; - vb_v8i16 = m_ir_builder->CreateShuffleVector(vb_v8i16, UndefValue::get(VectorType::get(m_ir_builder->getInt16Ty(), 8)), ConstantDataVector::get(m_ir_builder->getContext(), mask_v8i32)); - - auto vb_v4i32 = m_ir_builder->CreateBitCast(vb_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - vb_v4i32 = m_ir_builder->CreateAShr(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(10))); - auto tmp1_v4i32 = m_ir_builder->CreateLShr(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(3))); - tmp1_v4i32 = m_ir_builder->CreateAnd(tmp1_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x00001F00))); - auto tmp2_v4i32 = m_ir_builder->CreateLShr(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(6))); - tmp2_v4i32 = m_ir_builder->CreateAnd(tmp2_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x0000001F))); - auto res_v4i32 = m_ir_builder->CreateAnd(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0xFF1F0000))); - res_v4i32 = m_ir_builder->CreateOr(res_v4i32, tmp1_v4i32); - res_v4i32 = m_ir_builder->CreateOr(res_v4i32, tmp2_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VUPKHSB(u32 vd, u32 vb) { - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - u32 mask_v8i32[8] = { 8, 9, 10, 11, 12, 13, 14, 15 }; - auto vb_v8i8 = m_ir_builder->CreateShuffleVector(vb_v16i8, UndefValue::get(VectorType::get(m_ir_builder->getInt8Ty(), 16)), ConstantDataVector::get(m_ir_builder->getContext(), mask_v8i32)); - auto res_v8i16 = m_ir_builder->CreateSExt(vb_v8i8, VectorType::get(m_ir_builder->getInt16Ty(), 8)); - SetVr(vd, res_v8i16); -} - -void Compiler::VUPKHSH(u32 vd, u32 vb) { - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - u32 mask_v4i32[4] = { 4, 5, 6, 7 }; - auto vb_v4i16 = m_ir_builder->CreateShuffleVector(vb_v8i16, UndefValue::get(VectorType::get(m_ir_builder->getInt16Ty(), 8)), ConstantDataVector::get(m_ir_builder->getContext(), mask_v4i32)); - auto res_v4i32 = m_ir_builder->CreateSExt(vb_v4i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, res_v4i32); -} - -void Compiler::VUPKLPX(u32 vd, u32 vb) { - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - u32 mask_v8i32[8] = { 0, 0, 1, 1, 2, 2, 3, 3 }; - vb_v8i16 = m_ir_builder->CreateShuffleVector(vb_v8i16, UndefValue::get(VectorType::get(m_ir_builder->getInt16Ty(), 8)), ConstantDataVector::get(m_ir_builder->getContext(), mask_v8i32)); - - auto vb_v4i32 = m_ir_builder->CreateBitCast(vb_v8i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - vb_v4i32 = m_ir_builder->CreateAShr(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(10))); - auto tmp1_v4i32 = m_ir_builder->CreateLShr(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(3))); - tmp1_v4i32 = m_ir_builder->CreateAnd(tmp1_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x00001F00))); - auto tmp2_v4i32 = m_ir_builder->CreateLShr(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(6))); - tmp2_v4i32 = m_ir_builder->CreateAnd(tmp2_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0x0000001F))); - auto res_v4i32 = m_ir_builder->CreateAnd(vb_v4i32, m_ir_builder->CreateVectorSplat(4, m_ir_builder->getInt32(0xFF1F0000))); - res_v4i32 = m_ir_builder->CreateOr(res_v4i32, tmp1_v4i32); - res_v4i32 = m_ir_builder->CreateOr(res_v4i32, tmp2_v4i32); - SetVr(vd, res_v4i32); -} - -void Compiler::VUPKLSB(u32 vd, u32 vb) { - auto vb_v16i8 = GetVrAsIntVec(vb, 8); - u32 mask_v8i32[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; - auto vb_v8i8 = m_ir_builder->CreateShuffleVector(vb_v16i8, UndefValue::get(VectorType::get(m_ir_builder->getInt8Ty(), 16)), ConstantDataVector::get(m_ir_builder->getContext(), mask_v8i32)); - auto res_v8i16 = m_ir_builder->CreateSExt(vb_v8i8, VectorType::get(m_ir_builder->getInt16Ty(), 8)); - SetVr(vd, res_v8i16); -} - -void Compiler::VUPKLSH(u32 vd, u32 vb) { - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - u32 mask_v4i32[4] = { 0, 1, 2, 3 }; - auto vb_v4i16 = m_ir_builder->CreateShuffleVector(vb_v8i16, UndefValue::get(VectorType::get(m_ir_builder->getInt16Ty(), 8)), ConstantDataVector::get(m_ir_builder->getContext(), mask_v4i32)); - auto res_v4i32 = m_ir_builder->CreateSExt(vb_v4i16, VectorType::get(m_ir_builder->getInt32Ty(), 4)); - SetVr(vd, res_v4i32); -} - -void Compiler::VXOR(u32 vd, u32 va, u32 vb) { - auto va_v8i16 = GetVrAsIntVec(va, 16); - auto vb_v8i16 = GetVrAsIntVec(vb, 16); - auto res_v8i16 = m_ir_builder->CreateXor(va_v8i16, vb_v8i16); - SetVr(vd, res_v8i16); -} - -void Compiler::MULLI(u32 rd, u32 ra, s32 simm16) { - USE_INTERP_IF_REQUESTED(MULLI, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(simm16)); - - auto ra_i64 = GetGpr(ra); - auto res_i64 = m_ir_builder->CreateMul(ra_i64, m_ir_builder->getInt64((s64)simm16)); - SetGpr(rd, res_i64); -} - -void Compiler::SUBFIC(u32 rd, u32 ra, s32 simm16) { - USE_INTERP_IF_REQUESTED(SUBFIC, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(simm16)) - - auto ra_i64 = GetGpr(ra); - ra_i64 = m_ir_builder->CreateNeg(ra_i64); // simpler way of doing ~ra + 1 - auto res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), ra_i64, m_ir_builder->getInt64((s64)simm16)); - auto diff_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - auto is_zero = m_ir_builder->CreateICmpEQ(ra_i64, m_ir_builder->getInt64(0)); // if ra is zero when ~ra + 1 = 0 sets overflow bit - carry_i1 = m_ir_builder->CreateOr(is_zero, carry_i1); - SetGpr(rd, diff_i64); - SetXerCa(carry_i1); -} - -void Compiler::CMPLI(u32 crfd, u32 l, u32 ra, u32 uimm16) { - USE_INTERP_IF_REQUESTED(CMPLI, m_ir_builder->getInt32(crfd), m_ir_builder->getInt32(l), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(uimm16)); - - Value * ra_i64; - if (l == 0) { - ra_i64 = m_ir_builder->CreateZExt(GetGpr(ra, 32), m_ir_builder->getInt64Ty()); - } - else { - ra_i64 = GetGpr(ra); - } - - SetCrFieldUnsignedCmp(crfd, ra_i64, m_ir_builder->getInt64(uimm16)); -} - -void Compiler::CMPI(u32 crfd, u32 l, u32 ra, s32 simm16) { - USE_INTERP_IF_REQUESTED(CMPI, m_ir_builder->getInt32(crfd), m_ir_builder->getInt32(l), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(simm16)); - - Value * ra_i64; - if (l == 0) { - ra_i64 = m_ir_builder->CreateSExt(GetGpr(ra, 32), m_ir_builder->getInt64Ty()); - } - else { - ra_i64 = GetGpr(ra); - } - - SetCrFieldSignedCmp(crfd, ra_i64, m_ir_builder->getInt64((s64)simm16)); -} - -void Compiler::ADDIC(u32 rd, u32 ra, s32 simm16) { - USE_INTERP_IF_REQUESTED(ADDIC, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(simm16)); - - auto ra_i64 = GetGpr(ra); - auto res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), m_ir_builder->getInt64((s64)simm16), ra_i64); - auto sum_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - SetGpr(rd, sum_i64); - SetXerCa(carry_i1); -} - -void Compiler::ADDIC_(u32 rd, u32 ra, s32 simm16) { - USE_INTERP_IF_REQUESTED(ADDIC_, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(simm16)); - - ADDIC(rd, ra, simm16); - SetCrFieldSignedCmp(0, GetGpr(rd), m_ir_builder->getInt64(0)); -} - -void Compiler::ADDI(u32 rd, u32 ra, s32 simm16) { - USE_INTERP_IF_REQUESTED(ADDI, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(simm16)); - - if (ra == 0) { - SetGpr(rd, m_ir_builder->getInt64((s64)simm16)); - } - else { - auto ra_i64 = GetGpr(ra); - auto sum_i64 = m_ir_builder->CreateAdd(ra_i64, m_ir_builder->getInt64((s64)simm16)); - SetGpr(rd, sum_i64); - } -} - -void Compiler::ADDIS(u32 rd, u32 ra, s32 simm16) { - USE_INTERP_IF_REQUESTED(ADDIS, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(simm16)); - - if (ra == 0) { - SetGpr(rd, m_ir_builder->getInt64((s64)simm16 << 16)); - } - else { - auto ra_i64 = GetGpr(ra); - auto sum_i64 = m_ir_builder->CreateAdd(ra_i64, m_ir_builder->getInt64((s64)simm16 << 16)); - SetGpr(rd, sum_i64); - } -} - -void Compiler::BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) { - auto target_i64 = m_ir_builder->getInt64(branchTarget(aa ? 0 : m_state.current_instruction_address, bd)); - auto target_i32 = m_ir_builder->CreateTrunc(target_i64, m_ir_builder->getInt32Ty()); - CreateBranch(CheckBranchCondition(bo, bi), target_i32, lk ? true : false); -} - -void Compiler::HACK(u32 index) { - llvm::Value *status = Call("wrappedExecutePPUFuncByIndex", m_state.args[CompileTaskState::Args::State], m_ir_builder->getInt32(index & EIF_USE_BRANCH ? index : index & ~EIF_PERFORM_BLR)); - llvm::BasicBlock *cputhreadexitblock = GetBasicBlockFromAddress(m_state.current_instruction_address, "early_exit"); - llvm::Value *isCPUThreadExit = m_ir_builder->CreateICmpEQ(status, m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - llvm::BasicBlock *normal_execution = GetBasicBlockFromAddress(m_state.current_instruction_address, "normal_execution"); - m_ir_builder->CreateCondBr(isCPUThreadExit, cputhreadexitblock, normal_execution); - m_ir_builder->SetInsertPoint(cputhreadexitblock); - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - - m_ir_builder->SetInsertPoint(normal_execution); - if (index & EIF_PERFORM_BLR || index & EIF_USE_BRANCH) { - auto lr_i32 = index & EIF_USE_BRANCH ? GetPc() : m_ir_builder->CreateTrunc(m_ir_builder->CreateAnd(GetLr(), ~0x3ULL), m_ir_builder->getInt32Ty()); - CreateBranch(nullptr, lr_i32, false, (index & EIF_USE_BRANCH) == 0); - } -} - -void Compiler::SC(u32 lev) { - switch (lev) { - case 0: - { - llvm::Value *status = Call("wrappedDoSyscall", m_state.args[CompileTaskState::Args::State], GetGpr(11)); - llvm::BasicBlock *cputhreadexitblock = GetBasicBlockFromAddress(m_state.current_instruction_address, "early_exit"); - llvm::Value *isCPUThreadExit = m_ir_builder->CreateICmpEQ(status, m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - llvm::BasicBlock *normal_execution = GetBasicBlockFromAddress(m_state.current_instruction_address, "normal_execution"); - m_ir_builder->CreateCondBr(isCPUThreadExit, cputhreadexitblock, normal_execution); - m_ir_builder->SetInsertPoint(cputhreadexitblock); - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - m_ir_builder->SetInsertPoint(normal_execution); - } - break; - case 3: - Call("PPUThread.fast_stop", m_state.args[CompileTaskState::Args::State]); - break; - default: - CompilationError(fmt::format("SC %u", lev)); - break; - } - - auto ret_i1 = Call("PollStatus", m_state.args[CompileTaskState::Args::State]); - auto cmp_i1 = m_ir_builder->CreateICmpEQ(ret_i1, m_ir_builder->getInt1(true)); - auto then_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "then_true"); - auto merge_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "merge_true"); - m_ir_builder->CreateCondBr(cmp_i1, then_bb, merge_bb); - m_ir_builder->SetInsertPoint(then_bb); - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusBlockEnded)); - m_ir_builder->SetInsertPoint(merge_bb); -} - -void Compiler::B(s32 ll, u32 aa, u32 lk) { - auto target_i64 = m_ir_builder->getInt64(branchTarget(aa ? 0 : m_state.current_instruction_address, ll)); - auto target_i32 = m_ir_builder->CreateTrunc(target_i64, m_ir_builder->getInt32Ty()); - CreateBranch(nullptr, target_i32, lk ? true : false); -} - -void Compiler::MCRF(u32 crfd, u32 crfs) { - USE_INTERP_IF_REQUESTED(MCRF, m_ir_builder->getInt32(crfd), m_ir_builder->getInt32(crfs)); - - if (crfd != crfs) { - auto cr_i32 = GetCr(); - auto crf_i32 = GetNibble(cr_i32, crfs); - cr_i32 = SetNibble(cr_i32, crfd, crf_i32); - SetCr(cr_i32); - } -} - -void Compiler::BCLR(u32 bo, u32 bi, u32 bh, u32 lk) { - auto lr_i64 = GetLr(); - lr_i64 = m_ir_builder->CreateAnd(lr_i64, ~0x3ULL); - auto lr_i32 = m_ir_builder->CreateTrunc(lr_i64, m_ir_builder->getInt32Ty()); - CreateBranch(CheckBranchCondition(bo, bi), lr_i32, lk ? true : false, true); -} - -void Compiler::CRNOR(u32 crbd, u32 crba, u32 crbb) { - USE_INTERP_IF_REQUESTED(CRNOR, m_ir_builder->getInt32(crbd), m_ir_builder->getInt32(crba), m_ir_builder->getInt32(crbb)); - - auto cr_i32 = GetCr(); - auto ba_i32 = GetBit(cr_i32, crba); - auto bb_i32 = GetBit(cr_i32, crbb); - auto res_i32 = m_ir_builder->CreateOr(ba_i32, bb_i32); - res_i32 = m_ir_builder->CreateXor(res_i32, 1); - cr_i32 = SetBit(cr_i32, crbd, res_i32); - SetCr(cr_i32); -} - -void Compiler::CRANDC(u32 crbd, u32 crba, u32 crbb) { - USE_INTERP_IF_REQUESTED(CRANDC, m_ir_builder->getInt32(crbd), m_ir_builder->getInt32(crba), m_ir_builder->getInt32(crbb)); - - auto cr_i32 = GetCr(); - auto ba_i32 = GetBit(cr_i32, crba); - auto bb_i32 = GetBit(cr_i32, crbb); - auto res_i32 = m_ir_builder->CreateXor(bb_i32, 1); - res_i32 = m_ir_builder->CreateAnd(ba_i32, res_i32); - cr_i32 = SetBit(cr_i32, crbd, res_i32); - SetCr(cr_i32); -} - -void Compiler::ISYNC() { - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_mfence)); -} - -void Compiler::CRXOR(u32 crbd, u32 crba, u32 crbb) { - USE_INTERP_IF_REQUESTED(CRXOR, m_ir_builder->getInt32(crbd), m_ir_builder->getInt32(crba), m_ir_builder->getInt32(crbb)); - - auto cr_i32 = GetCr(); - auto ba_i32 = GetBit(cr_i32, crba); - auto bb_i32 = GetBit(cr_i32, crbb); - auto res_i32 = m_ir_builder->CreateXor(ba_i32, bb_i32); - cr_i32 = SetBit(cr_i32, crbd, res_i32); - SetCr(cr_i32); -} - -void Compiler::DCBI(u32 ra, u32 rb) { - // TODO: See if this can be translated to cache flush - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::donothing)); -} - -void Compiler::CRNAND(u32 crbd, u32 crba, u32 crbb) { - USE_INTERP_IF_REQUESTED(CRNAND, m_ir_builder->getInt32(crbd), m_ir_builder->getInt32(crba), m_ir_builder->getInt32(crbb)); - - auto cr_i32 = GetCr(); - auto ba_i32 = GetBit(cr_i32, crba); - auto bb_i32 = GetBit(cr_i32, crbb); - auto res_i32 = m_ir_builder->CreateAnd(ba_i32, bb_i32); - res_i32 = m_ir_builder->CreateXor(res_i32, 1); - cr_i32 = SetBit(cr_i32, crbd, res_i32); - SetCr(cr_i32); -} - -void Compiler::CRAND(u32 crbd, u32 crba, u32 crbb) { - USE_INTERP_IF_REQUESTED(CRAND, m_ir_builder->getInt32(crbd), m_ir_builder->getInt32(crba), m_ir_builder->getInt32(crbb)); - - auto cr_i32 = GetCr(); - auto ba_i32 = GetBit(cr_i32, crba); - auto bb_i32 = GetBit(cr_i32, crbb); - auto res_i32 = m_ir_builder->CreateAnd(ba_i32, bb_i32); - cr_i32 = SetBit(cr_i32, crbd, res_i32); - SetCr(cr_i32); -} - -void Compiler::CREQV(u32 crbd, u32 crba, u32 crbb) { - USE_INTERP_IF_REQUESTED(CREQV, m_ir_builder->getInt32(crbd), m_ir_builder->getInt32(crba), m_ir_builder->getInt32(crbb)); - - auto cr_i32 = GetCr(); - auto ba_i32 = GetBit(cr_i32, crba); - auto bb_i32 = GetBit(cr_i32, crbb); - auto res_i32 = m_ir_builder->CreateXor(ba_i32, bb_i32); - res_i32 = m_ir_builder->CreateXor(res_i32, 1); - cr_i32 = SetBit(cr_i32, crbd, res_i32); - SetCr(cr_i32); -} - -void Compiler::CRORC(u32 crbd, u32 crba, u32 crbb) { - USE_INTERP_IF_REQUESTED(CRORC, m_ir_builder->getInt32(crbd), m_ir_builder->getInt32(crba), m_ir_builder->getInt32(crbb)); - - auto cr_i32 = GetCr(); - auto ba_i32 = GetBit(cr_i32, crba); - auto bb_i32 = GetBit(cr_i32, crbb); - auto res_i32 = m_ir_builder->CreateXor(bb_i32, 1); - res_i32 = m_ir_builder->CreateOr(ba_i32, res_i32); - cr_i32 = SetBit(cr_i32, crbd, res_i32); - SetCr(cr_i32); -} - -void Compiler::CROR(u32 crbd, u32 crba, u32 crbb) { - USE_INTERP_IF_REQUESTED(CROR, m_ir_builder->getInt32(crbd), m_ir_builder->getInt32(crba), m_ir_builder->getInt32(crbb)); - - auto cr_i32 = GetCr(); - auto ba_i32 = GetBit(cr_i32, crba); - auto bb_i32 = GetBit(cr_i32, crbb); - auto res_i32 = m_ir_builder->CreateOr(ba_i32, bb_i32); - cr_i32 = SetBit(cr_i32, crbd, res_i32); - SetCr(cr_i32); -} - -void Compiler::BCCTR(u32 bo, u32 bi, u32 bh, u32 lk) { - auto ctr_i64 = GetCtr(); - ctr_i64 = m_ir_builder->CreateAnd(ctr_i64, ~0x3ULL); - auto ctr_i32 = m_ir_builder->CreateTrunc(ctr_i64, m_ir_builder->getInt32Ty()); - CreateBranch(CheckBranchCondition(bo, bi), ctr_i32, lk ? true : false); -} - -void Compiler::RLWIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) { - USE_INTERP_IF_REQUESTED(RLWIMI, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(sh), m_ir_builder->getInt32(mb), m_ir_builder->getInt32(me), m_ir_builder->getInt32(rc)); - - auto rs_i32 = GetGpr(rs, 32); - auto rs_i64 = m_ir_builder->CreateZExt(rs_i32, m_ir_builder->getInt64Ty()); - auto rsh_i64 = m_ir_builder->CreateShl(rs_i64, 32); - rs_i64 = m_ir_builder->CreateOr(rs_i64, rsh_i64); - auto ra_i64 = GetGpr(ra); - auto res_i64 = rs_i64; - if (sh) { - auto resl_i64 = m_ir_builder->CreateLShr(rs_i64, 64 - sh); - auto resh_i64 = m_ir_builder->CreateShl(rs_i64, sh); - res_i64 = m_ir_builder->CreateOr(resh_i64, resl_i64); - } - - u64 mask = s_rotate_mask[32 + mb][32 + me]; - res_i64 = m_ir_builder->CreateAnd(res_i64, mask); - ra_i64 = m_ir_builder->CreateAnd(ra_i64, ~mask); - res_i64 = m_ir_builder->CreateOr(res_i64, ra_i64); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::RLWINM(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) { - USE_INTERP_IF_REQUESTED(RLWINM, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(sh), m_ir_builder->getInt32(mb), m_ir_builder->getInt32(me), m_ir_builder->getInt32(rc)); - - auto rs_i32 = GetGpr(rs, 32); - auto rs_i64 = m_ir_builder->CreateZExt(rs_i32, m_ir_builder->getInt64Ty()); - auto rsh_i64 = m_ir_builder->CreateShl(rs_i64, 32); - rs_i64 = m_ir_builder->CreateOr(rs_i64, rsh_i64); - auto res_i64 = rs_i64; - if (sh) { - auto resl_i64 = m_ir_builder->CreateLShr(rs_i64, 64 - sh); - auto resh_i64 = m_ir_builder->CreateShl(rs_i64, sh); - res_i64 = m_ir_builder->CreateOr(resh_i64, resl_i64); - } - - res_i64 = m_ir_builder->CreateAnd(res_i64, s_rotate_mask[32 + mb][32 + me]); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::RLWNM(u32 ra, u32 rs, u32 rb, u32 mb, u32 me, u32 rc) { - USE_INTERP_IF_REQUESTED(RLWNM, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(rb), m_ir_builder->getInt32(mb), m_ir_builder->getInt32(me), m_ir_builder->getInt32(rc)); - - auto rs_i32 = GetGpr(rs, 32); - auto rs_i64 = m_ir_builder->CreateZExt(rs_i32, m_ir_builder->getInt64Ty()); - auto rsh_i64 = m_ir_builder->CreateShl(rs_i64, 32); - rs_i64 = m_ir_builder->CreateOr(rs_i64, rsh_i64); - auto rb_i64 = GetGpr(rb); - auto shl_i64 = m_ir_builder->CreateAnd(rb_i64, 0x1F); - auto shr_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(32), shl_i64); - auto resl_i64 = m_ir_builder->CreateLShr(rs_i64, shr_i64); - auto resh_i64 = m_ir_builder->CreateShl(rs_i64, shl_i64); - auto res_i64 = m_ir_builder->CreateOr(resh_i64, resl_i64); - res_i64 = m_ir_builder->CreateAnd(res_i64, s_rotate_mask[32 + mb][32 + me]); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::ORI(u32 ra, u32 rs, u32 uimm16) { - USE_INTERP_IF_REQUESTED(ORI, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(uimm16)); - - auto rs_i64 = GetGpr(rs); - auto res_i64 = m_ir_builder->CreateOr(rs_i64, uimm16); - SetGpr(ra, res_i64); -} - -void Compiler::ORIS(u32 ra, u32 rs, u32 uimm16) { - USE_INTERP_IF_REQUESTED(ORIS, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(uimm16)); - - auto rs_i64 = GetGpr(rs); - auto res_i64 = m_ir_builder->CreateOr(rs_i64, (u64)uimm16 << 16); - SetGpr(ra, res_i64); -} - -void Compiler::XORI(u32 ra, u32 rs, u32 uimm16) { - USE_INTERP_IF_REQUESTED(XORI, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(uimm16)); - - auto rs_i64 = GetGpr(rs); - auto res_i64 = m_ir_builder->CreateXor(rs_i64, uimm16); - SetGpr(ra, res_i64); -} - -void Compiler::XORIS(u32 ra, u32 rs, u32 uimm16) { - USE_INTERP_IF_REQUESTED(XORIS, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(uimm16)); - - auto rs_i64 = GetGpr(rs); - auto res_i64 = m_ir_builder->CreateXor(rs_i64, (u64)uimm16 << 16); - SetGpr(ra, res_i64); -} - -void Compiler::ANDI_(u32 ra, u32 rs, u32 uimm16) { - USE_INTERP_IF_REQUESTED(ANDI_, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(uimm16)); - - auto rs_i64 = GetGpr(rs); - auto res_i64 = m_ir_builder->CreateAnd(rs_i64, uimm16); - SetGpr(ra, res_i64); - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); -} - -void Compiler::ANDIS_(u32 ra, u32 rs, u32 uimm16) { - USE_INTERP_IF_REQUESTED(ANDIS_, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(uimm16)); - - auto rs_i64 = GetGpr(rs); - auto res_i64 = m_ir_builder->CreateAnd(rs_i64, (u64)uimm16 << 16); - SetGpr(ra, res_i64); - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); -} - -void Compiler::RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) { - USE_INTERP_IF_REQUESTED(RLDICL, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(sh), m_ir_builder->getInt32(mb), m_ir_builder->getInt32(rc)); - - auto rs_i64 = GetGpr(rs); - auto res_i64 = rs_i64; - if (sh) { - auto resl_i64 = m_ir_builder->CreateLShr(rs_i64, 64 - sh); - auto resh_i64 = m_ir_builder->CreateShl(rs_i64, sh); - res_i64 = m_ir_builder->CreateOr(resh_i64, resl_i64); - } - - res_i64 = m_ir_builder->CreateAnd(res_i64, s_rotate_mask[mb][63]); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::RLDICR(u32 ra, u32 rs, u32 sh, u32 me, u32 rc) { - USE_INTERP_IF_REQUESTED(RLDICR, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(sh), m_ir_builder->getInt32(me), m_ir_builder->getInt32(rc)); - - auto rs_i64 = GetGpr(rs); - auto res_i64 = rs_i64; - if (sh) { - auto resl_i64 = m_ir_builder->CreateLShr(rs_i64, 64 - sh); - auto resh_i64 = m_ir_builder->CreateShl(rs_i64, sh); - res_i64 = m_ir_builder->CreateOr(resh_i64, resl_i64); - } - - res_i64 = m_ir_builder->CreateAnd(res_i64, s_rotate_mask[0][me]); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::RLDIC(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) { - USE_INTERP_IF_REQUESTED(RLDIC, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(sh), m_ir_builder->getInt32(mb), m_ir_builder->getInt32(rc)); - - auto rs_i64 = GetGpr(rs); - auto res_i64 = rs_i64; - if (sh) { - auto resl_i64 = m_ir_builder->CreateLShr(rs_i64, 64 - sh); - auto resh_i64 = m_ir_builder->CreateShl(rs_i64, sh); - res_i64 = m_ir_builder->CreateOr(resh_i64, resl_i64); - } - - res_i64 = m_ir_builder->CreateAnd(res_i64, s_rotate_mask[mb][63 - sh]); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::RLDIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) { - USE_INTERP_IF_REQUESTED(RLDIMI, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(sh), m_ir_builder->getInt32(mb), m_ir_builder->getInt32(rc)); - - auto rs_i64 = GetGpr(rs); - auto ra_i64 = GetGpr(ra); - auto res_i64 = rs_i64; - if (sh) { - auto resl_i64 = m_ir_builder->CreateLShr(rs_i64, 64 - sh); - auto resh_i64 = m_ir_builder->CreateShl(rs_i64, sh); - res_i64 = m_ir_builder->CreateOr(resh_i64, resl_i64); - } - - u64 mask = s_rotate_mask[mb][63 - sh]; - res_i64 = m_ir_builder->CreateAnd(res_i64, mask); - ra_i64 = m_ir_builder->CreateAnd(ra_i64, ~mask); - res_i64 = m_ir_builder->CreateOr(res_i64, ra_i64); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::RLDC_LR(u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc) { - USE_INTERP_IF_REQUESTED(RLDC_LR, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(rb), m_ir_builder->getInt32(m_eb), m_ir_builder->getInt32(is_r), m_ir_builder->getInt32(rc)); - - auto rs_i64 = GetGpr(rs); - auto rb_i64 = GetGpr(rb); - auto shl_i64 = m_ir_builder->CreateAnd(rb_i64, 0x3F); - auto shr_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(64), shl_i64); - auto resl_i64 = m_ir_builder->CreateLShr(rs_i64, shr_i64); - auto resh_i64 = m_ir_builder->CreateShl(rs_i64, shl_i64); - auto res_i64 = m_ir_builder->CreateOr(resh_i64, resl_i64); - - if (is_r) { - res_i64 = m_ir_builder->CreateAnd(res_i64, s_rotate_mask[0][m_eb]); - } - else { - res_i64 = m_ir_builder->CreateAnd(res_i64, s_rotate_mask[m_eb][63]); - } - - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::CMP(u32 crfd, u32 l, u32 ra, u32 rb) { - USE_INTERP_IF_REQUESTED(CMP, m_ir_builder->getInt32(crfd), m_ir_builder->getInt32(l), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rb)); - - Value * ra_i64; - Value * rb_i64; - if (l == 0) { - ra_i64 = m_ir_builder->CreateSExt(GetGpr(ra, 32), m_ir_builder->getInt64Ty()); - rb_i64 = m_ir_builder->CreateSExt(GetGpr(rb, 32), m_ir_builder->getInt64Ty()); - } - else { - ra_i64 = GetGpr(ra); - rb_i64 = GetGpr(rb); - } - - SetCrFieldSignedCmp(crfd, ra_i64, rb_i64); -} - -void Compiler::TW(u32 to, u32 ra, u32 rb) { - llvm::Value *gpr_a = GetGpr(ra, 32); - llvm::Value *gpr_b = GetGpr(rb, 32); - llvm::Value *trap_condition = m_ir_builder->getFalse(); - - if (to & 0x10) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpSLT(gpr_a, gpr_b)); - if (to & 0x8) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpSGT(gpr_a, gpr_b)); - if (to & 0x4) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpEQ(gpr_a, gpr_b)); - if (to & 0x2) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpULT(gpr_a, gpr_b)); - if (to & 0x1) - trap_condition = m_ir_builder->CreateOr(trap_condition, - m_ir_builder->CreateICmpUGT(gpr_a, gpr_b)); - - llvm::BasicBlock *trap_block = GetBasicBlockFromAddress(m_state.current_instruction_address, "trap_block"); - llvm::BasicBlock *normal_execution = GetBasicBlockFromAddress(m_state.current_instruction_address, "normal_execution"); - m_ir_builder->CreateCondBr(trap_condition, trap_block, normal_execution); - - m_ir_builder->SetInsertPoint(trap_block); - Call("trap"); - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - - m_ir_builder->SetInsertPoint(normal_execution); -} - -void Compiler::LVSL(u32 vd, u32 ra, u32 rb) { - static const u64 s_lvsl_values[0x10][2] = { - { 0x08090A0B0C0D0E0F, 0x0001020304050607 }, - { 0x090A0B0C0D0E0F10, 0x0102030405060708 }, - { 0x0A0B0C0D0E0F1011, 0x0203040506070809 }, - { 0x0B0C0D0E0F101112, 0x030405060708090A }, - { 0x0C0D0E0F10111213, 0x0405060708090A0B }, - { 0x0D0E0F1011121314, 0x05060708090A0B0C }, - { 0x0E0F101112131415, 0x060708090A0B0C0D }, - { 0x0F10111213141516, 0x0708090A0B0C0D0E }, - { 0x1011121314151617, 0x08090A0B0C0D0E0F }, - { 0x1112131415161718, 0x090A0B0C0D0E0F10 }, - { 0x1213141516171819, 0x0A0B0C0D0E0F1011 }, - { 0x131415161718191A, 0x0B0C0D0E0F101112 }, - { 0x1415161718191A1B, 0x0C0D0E0F10111213 }, - { 0x15161718191A1B1C, 0x0D0E0F1011121314 }, - { 0x161718191A1B1C1D, 0x0E0F101112131415 }, - { 0x1718191A1B1C1D1E, 0x0F10111213141516 }, - }; - - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto index_i64 = m_ir_builder->CreateAnd(addr_i64, 0xF); - auto lvsl_values_v16i8_ptr = m_ir_builder->CreateIntToPtr(m_ir_builder->getInt64((u64)s_lvsl_values), VectorType::get(m_ir_builder->getInt8Ty(), 16)->getPointerTo()); - lvsl_values_v16i8_ptr = m_ir_builder->CreateGEP(lvsl_values_v16i8_ptr, index_i64); - auto val_v16i8 = m_ir_builder->CreateAlignedLoad(lvsl_values_v16i8_ptr, 16); - SetVr(vd, val_v16i8); -} - -void Compiler::LVEBX(u32 vd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto val_i8 = ReadMemory(addr_i64, 8); - auto index_i64 = m_ir_builder->CreateAnd(addr_i64, 0xf); - index_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(15), index_i64); - auto vd_v16i8 = GetVrAsIntVec(vd, 8); - vd_v16i8 = m_ir_builder->CreateInsertElement(vd_v16i8, val_i8, index_i64); - SetVr(vd, vd_v16i8); -} - -void Compiler::SUBFC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - auto ra_i64 = GetGpr(ra); - ra_i64 = m_ir_builder->CreateNeg(ra_i64); - auto rb_i64 = GetGpr(rb); - auto res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), ra_i64, rb_i64); - auto diff_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - SetGpr(rd, diff_i64); - SetXerCa(carry_i1); - - if (rc) { - SetCrFieldSignedCmp(0, diff_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - CompilationError("SUBFCO"); - } -} - -void Compiler::ADDC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - auto ra_i64 = GetGpr(ra); - auto rb_i64 = GetGpr(rb); - auto res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), ra_i64, rb_i64); - auto sum_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - SetGpr(rd, sum_i64); - SetXerCa(carry_i1); - - if (rc) { - SetCrFieldSignedCmp(0, sum_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - } -} - -void Compiler::MULHDU(u32 rd, u32 ra, u32 rb, u32 rc) { - auto ra_i64 = GetGpr(ra); - auto rb_i64 = GetGpr(rb); - auto ra_i128 = m_ir_builder->CreateZExt(ra_i64, m_ir_builder->getIntNTy(128)); - auto rb_i128 = m_ir_builder->CreateZExt(rb_i64, m_ir_builder->getIntNTy(128)); - auto prod_i128 = m_ir_builder->CreateMul(ra_i128, rb_i128); - prod_i128 = m_ir_builder->CreateLShr(prod_i128, 64); - auto prod_i64 = m_ir_builder->CreateTrunc(prod_i128, m_ir_builder->getInt64Ty()); - SetGpr(rd, prod_i64); - - if (rc) { - SetCrFieldSignedCmp(0, prod_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::MULHWU(u32 rd, u32 ra, u32 rb, u32 rc) { - auto ra_i32 = GetGpr(ra, 32); - auto rb_i32 = GetGpr(rb, 32); - auto ra_i64 = m_ir_builder->CreateZExt(ra_i32, m_ir_builder->getInt64Ty()); - auto rb_i64 = m_ir_builder->CreateZExt(rb_i32, m_ir_builder->getInt64Ty()); - auto prod_i64 = m_ir_builder->CreateMul(ra_i64, rb_i64); - prod_i64 = m_ir_builder->CreateLShr(prod_i64, 32); - SetGpr(rd, prod_i64); - - if (rc) { - SetCrFieldSignedCmp(0, prod_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::MFOCRF(u32 a, u32 rd, u32 crm) { - USE_INTERP_IF_REQUESTED(MFOCRF, m_ir_builder->getInt32(a), m_ir_builder->getInt32(rd), m_ir_builder->getInt32(crm)); - - auto cr_i32 = GetCr(); - auto cr_i64 = m_ir_builder->CreateZExt(cr_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, cr_i64); -} - -void Compiler::LWARX(u32 rd, u32 ra, u32 rb) { - USE_INTERP_IF_REQUESTED(LWARX, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rb)); - - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto addr_i32 = m_ir_builder->CreateTrunc(addr_i64, m_ir_builder->getInt32Ty()); - auto val_i32_ptr = m_ir_builder->CreateAlloca(m_ir_builder->getInt32Ty()); - val_i32_ptr->setAlignment(4); - Call("vm.reservation_acquire", m_ir_builder->CreateBitCast(val_i32_ptr, m_ir_builder->getInt8PtrTy()), addr_i32, m_ir_builder->getInt32(4)); - auto val_i32 = (Value *)m_ir_builder->CreateLoad(val_i32_ptr); - val_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, m_ir_builder->getInt32Ty()), val_i32); - auto val_i64 = m_ir_builder->CreateZExt(val_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, val_i64); -} - -void Compiler::LDX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i64 = ReadMemory(addr_i64, 64); - SetGpr(rd, mem_i64); -} - -void Compiler::LWZX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i32 = ReadMemory(addr_i64, 32); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::SLW(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i32 = GetGpr(rs, 32); - auto rs_i64 = m_ir_builder->CreateZExt(rs_i32, m_ir_builder->getInt64Ty()); - auto rb_i8 = GetGpr(rb, 8); - rb_i8 = m_ir_builder->CreateAnd(rb_i8, 0x3F); - auto rb_i64 = m_ir_builder->CreateZExt(rb_i8, m_ir_builder->getInt64Ty()); - auto res_i64 = m_ir_builder->CreateShl(rs_i64, rb_i64); - auto res_i32 = m_ir_builder->CreateTrunc(res_i64, m_ir_builder->getInt32Ty()); - res_i64 = m_ir_builder->CreateZExt(res_i32, m_ir_builder->getInt64Ty()); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::CNTLZW(u32 ra, u32 rs, u32 rc) { - auto rs_i32 = GetGpr(rs, 32); - auto res_i32 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::ctlz, m_ir_builder->getInt32Ty()), rs_i32, m_ir_builder->getInt1(false)); - auto res_i64 = m_ir_builder->CreateZExt(res_i32, m_ir_builder->getInt64Ty()); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::SLD(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto rs_i128 = m_ir_builder->CreateZExt(rs_i64, m_ir_builder->getIntNTy(128)); - auto rb_i8 = GetGpr(rb, 8); - rb_i8 = m_ir_builder->CreateAnd(rb_i8, 0x7F); - auto rb_i128 = m_ir_builder->CreateZExt(rb_i8, m_ir_builder->getIntNTy(128)); - auto res_i128 = m_ir_builder->CreateShl(rs_i128, rb_i128); - auto res_i64 = m_ir_builder->CreateTrunc(res_i128, m_ir_builder->getInt64Ty()); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::AND(u32 ra, u32 rs, u32 rb, u32 rc) { - USE_INTERP_IF_REQUESTED(AND, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(rb), m_ir_builder->getInt32(rc)); - - auto rs_i64 = GetGpr(rs); - auto rb_i64 = GetGpr(rb); - auto res_i64 = m_ir_builder->CreateAnd(rs_i64, rb_i64); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::CMPL(u32 crfd, u32 l, u32 ra, u32 rb) { - USE_INTERP_IF_REQUESTED(CMPL, m_ir_builder->getInt32(crfd), m_ir_builder->getInt32(l), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rb)); - - Value * ra_i64; - Value * rb_i64; - if (l == 0) { - ra_i64 = m_ir_builder->CreateZExt(GetGpr(ra, 32), m_ir_builder->getInt64Ty()); - rb_i64 = m_ir_builder->CreateZExt(GetGpr(rb, 32), m_ir_builder->getInt64Ty()); - } - else { - ra_i64 = GetGpr(ra); - rb_i64 = GetGpr(rb); - } - - SetCrFieldUnsignedCmp(crfd, ra_i64, rb_i64); -} - -void Compiler::LVSR(u32 vd, u32 ra, u32 rb) { - static const u64 s_lvsr_values[0x10][2] = { - { 0x18191A1B1C1D1E1F, 0x1011121314151617 }, - { 0x1718191A1B1C1D1E, 0x0F10111213141516 }, - { 0x161718191A1B1C1D, 0x0E0F101112131415 }, - { 0x15161718191A1B1C, 0x0D0E0F1011121314 }, - { 0x1415161718191A1B, 0x0C0D0E0F10111213 }, - { 0x131415161718191A, 0x0B0C0D0E0F101112 }, - { 0x1213141516171819, 0x0A0B0C0D0E0F1011 }, - { 0x1112131415161718, 0x090A0B0C0D0E0F10 }, - { 0x1011121314151617, 0x08090A0B0C0D0E0F }, - { 0x0F10111213141516, 0x0708090A0B0C0D0E }, - { 0x0E0F101112131415, 0x060708090A0B0C0D }, - { 0x0D0E0F1011121314, 0x05060708090A0B0C }, - { 0x0C0D0E0F10111213, 0x0405060708090A0B }, - { 0x0B0C0D0E0F101112, 0x030405060708090A }, - { 0x0A0B0C0D0E0F1011, 0x0203040506070809 }, - { 0x090A0B0C0D0E0F10, 0x0102030405060708 }, - }; - - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto index_i64 = m_ir_builder->CreateAnd(addr_i64, 0xF); - auto lvsr_values_v16i8_ptr = m_ir_builder->CreateIntToPtr(m_ir_builder->getInt64((u64)s_lvsr_values), VectorType::get(m_ir_builder->getInt8Ty(), 16)->getPointerTo()); - lvsr_values_v16i8_ptr = m_ir_builder->CreateGEP(lvsr_values_v16i8_ptr, index_i64); - auto val_v16i8 = m_ir_builder->CreateAlignedLoad(lvsr_values_v16i8_ptr, 16); - SetVr(vd, val_v16i8); -} - -void Compiler::LVEHX(u32 vd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFFFFFFFFFEULL); - auto val_i16 = ReadMemory(addr_i64, 16, 2); - auto index_i64 = m_ir_builder->CreateAnd(addr_i64, 0xf); - index_i64 = m_ir_builder->CreateLShr(index_i64, 1); - index_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(7), index_i64); - auto vd_v8i16 = GetVrAsIntVec(vd, 16); - vd_v8i16 = m_ir_builder->CreateInsertElement(vd_v8i16, val_i16, index_i64); - SetVr(vd, vd_v8i16); -} - -void Compiler::SUBF(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - USE_INTERP_IF_REQUESTED(SUBF, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rb), m_ir_builder->getInt32(oe), m_ir_builder->getInt32(rc)); - - auto ra_i64 = GetGpr(ra); - auto rb_i64 = GetGpr(rb); - auto diff_i64 = m_ir_builder->CreateSub(rb_i64, ra_i64); - SetGpr(rd, diff_i64); - - if (rc) { - SetCrFieldSignedCmp(0, diff_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - CompilationError("SUBFO"); - } -} - -void Compiler::LDUX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i64 = ReadMemory(addr_i64, 64); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::DCBST(u32 ra, u32 rb) { - // TODO: Implement this - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::donothing)); -} - -void Compiler::LWZUX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i32 = ReadMemory(addr_i64, 32); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::CNTLZD(u32 ra, u32 rs, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto res_i64 = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::ctlz, m_ir_builder->getInt64Ty()), rs_i64, m_ir_builder->getInt1(false)); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::ANDC(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto rb_i64 = GetGpr(rb); - rb_i64 = m_ir_builder->CreateNot(rb_i64); - auto res_i64 = m_ir_builder->CreateAnd(rs_i64, rb_i64); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::TD(u32 to, u32 ra, u32 rb) { - Call("trap"); - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); -} - -void Compiler::LVEWX(u32 vd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFFFFFFFFFCULL); - auto val_i32 = ReadMemory(addr_i64, 32, 4); - auto index_i64 = m_ir_builder->CreateAnd(addr_i64, 0xf); - index_i64 = m_ir_builder->CreateLShr(index_i64, 2); - index_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(3), index_i64); - auto vd_v4i32 = GetVrAsIntVec(vd, 32); - vd_v4i32 = m_ir_builder->CreateInsertElement(vd_v4i32, val_i32, index_i64); - SetVr(vd, vd_v4i32); -} - -void Compiler::MULHD(u32 rd, u32 ra, u32 rb, u32 rc) { - auto ra_i64 = GetGpr(ra); - auto rb_i64 = GetGpr(rb); - auto ra_i128 = m_ir_builder->CreateSExt(ra_i64, m_ir_builder->getIntNTy(128)); - auto rb_i128 = m_ir_builder->CreateSExt(rb_i64, m_ir_builder->getIntNTy(128)); - auto prod_i128 = m_ir_builder->CreateMul(ra_i128, rb_i128); - prod_i128 = m_ir_builder->CreateLShr(prod_i128, 64); - auto prod_i64 = m_ir_builder->CreateTrunc(prod_i128, m_ir_builder->getInt64Ty()); - SetGpr(rd, prod_i64); - - if (rc) { - SetCrFieldSignedCmp(0, prod_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::MULHW(u32 rd, u32 ra, u32 rb, u32 rc) { - auto ra_i32 = GetGpr(ra, 32); - auto rb_i32 = GetGpr(rb, 32); - auto ra_i64 = m_ir_builder->CreateSExt(ra_i32, m_ir_builder->getInt64Ty()); - auto rb_i64 = m_ir_builder->CreateSExt(rb_i32, m_ir_builder->getInt64Ty()); - auto prod_i64 = m_ir_builder->CreateMul(ra_i64, rb_i64); - prod_i64 = m_ir_builder->CreateAShr(prod_i64, 32); - SetGpr(rd, prod_i64); - - if (rc) { - SetCrFieldSignedCmp(0, prod_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::LDARX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto addr_i32 = m_ir_builder->CreateTrunc(addr_i64, m_ir_builder->getInt32Ty()); - auto val_i64_ptr = m_ir_builder->CreateAlloca(m_ir_builder->getInt64Ty()); - val_i64_ptr->setAlignment(8); - Call("vm.reservation_acquire", m_ir_builder->CreateBitCast(val_i64_ptr, m_ir_builder->getInt8PtrTy()), addr_i32, m_ir_builder->getInt32(8)); - auto val_i64 = (Value *)m_ir_builder->CreateLoad(val_i64_ptr); - val_i64 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, m_ir_builder->getInt64Ty()), val_i64); - SetGpr(rd, val_i64); -} - -void Compiler::DCBF(u32 ra, u32 rb) { - // TODO: Implement this - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::donothing)); -} - -void Compiler::LBZX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i8 = ReadMemory(addr_i64, 8); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i8, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::LVX(u32 vd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFFFFFFFFF0ULL); - auto mem_i128 = ReadMemory(addr_i64, 128, 16); - SetVr(vd, mem_i128); -} - -void Compiler::NEG(u32 rd, u32 ra, u32 oe, u32 rc) { - USE_INTERP_IF_REQUESTED(NEG, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(oe), m_ir_builder->getInt32(rc)); - - auto ra_i64 = GetGpr(ra); - auto diff_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(0), ra_i64); - SetGpr(rd, diff_i64); - - if (rc) { - SetCrFieldSignedCmp(0, diff_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - CompilationError("NEGO"); - } -} - -void Compiler::LBZUX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i8 = ReadMemory(addr_i64, 8); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i8, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::NOR(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto rb_i64 = GetGpr(rb); - auto res_i64 = m_ir_builder->CreateOr(rs_i64, rb_i64); - res_i64 = m_ir_builder->CreateXor(res_i64, (s64)-1); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::STVEBX(u32 vs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto index_i64 = m_ir_builder->CreateAnd(addr_i64, 0xf); - index_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(15), index_i64); - auto vs_v16i8 = GetVrAsIntVec(vs, 8); - auto val_i8 = m_ir_builder->CreateExtractElement(vs_v16i8, index_i64); - WriteMemory(addr_i64, val_i8); -} - -void Compiler::SUBFE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - auto ca_i64 = GetXerCa(); - auto ra_i64 = GetGpr(ra); - auto rb_i64 = GetGpr(rb); - ra_i64 = m_ir_builder->CreateNot(ra_i64); - auto res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), ra_i64, ca_i64); - auto res_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry1_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), res_i64, rb_i64); - res_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry2_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - auto carry_i1 = m_ir_builder->CreateOr(carry1_i1, carry2_i1); - SetGpr(rd, res_i64); - SetXerCa(carry_i1); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - CompilationError("SUBFEO"); - } -} - -void Compiler::ADDE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - auto ca_i64 = GetXerCa(); - auto ra_i64 = GetGpr(ra); - auto rb_i64 = GetGpr(rb); - auto res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), ra_i64, ca_i64); - auto res_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry1_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), res_i64, rb_i64); - res_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry2_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - auto carry_i1 = m_ir_builder->CreateOr(carry1_i1, carry2_i1); - SetGpr(rd, res_i64); - SetXerCa(carry_i1); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - CompilationError("ADDEO"); - } -} - -void Compiler::MTOCRF(u32 l, u32 crm, u32 rs) { - USE_INTERP_IF_REQUESTED(MTOCRF, m_ir_builder->getInt32(l), m_ir_builder->getInt32(crm), m_ir_builder->getInt32(rs)); - - auto rs_i32 = GetGpr(rs, 32); - auto cr_i32 = GetCr(); - u64 mask = 0; - - for (u32 i = 0; i < 8; i++) { - if (crm & (1 << i)) { - mask |= UINT64_C(0xF) << (i * 4); // move 0xF to the left i positions (in hex form) - if (l) { - break; - } - } - } - - cr_i32 = m_ir_builder->CreateAnd(cr_i32, ~mask); // null ith nibble - rs_i32 = m_ir_builder->CreateAnd(rs_i32, mask); // null everything except ith nibble - cr_i32 = m_ir_builder->CreateOr(cr_i32, rs_i32); // now ith cr nibble == ith rs nibble - SetCr(cr_i32); -} - -void Compiler::STDX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs, 64)); -} - -void Compiler::STWCX_(u32 rs, u32 ra, u32 rb) { - USE_INTERP_IF_REQUESTED(STWCX_, m_ir_builder->getInt32(rs), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rb)); - - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto addr_i32 = m_ir_builder->CreateTrunc(addr_i64, m_ir_builder->getInt32Ty()); - auto rs_i32 = GetGpr(rs, 32); - rs_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, m_ir_builder->getInt32Ty()), rs_i32); - auto rs_i32_ptr = m_ir_builder->CreateAlloca(m_ir_builder->getInt32Ty()); - rs_i32_ptr->setAlignment(4); - m_ir_builder->CreateStore(rs_i32, rs_i32_ptr); - auto success_i1 = Call("vm.reservation_update", addr_i32, m_ir_builder->CreateBitCast(rs_i32_ptr, m_ir_builder->getInt8PtrTy()), m_ir_builder->getInt32(4)); - - auto cr_i32 = GetCr(); - cr_i32 = SetBit(cr_i32, 2, success_i1); - SetCr(cr_i32); -} - -void Compiler::STWX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs, 32)); -} - -void Compiler::STVEHX(u32 vs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFFFFFFFFFEULL); - auto index_i64 = m_ir_builder->CreateAnd(addr_i64, 0xf); - index_i64 = m_ir_builder->CreateLShr(index_i64, 1); - index_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(7), index_i64); - auto vs_v8i16 = GetVrAsIntVec(vs, 16); - auto val_i16 = m_ir_builder->CreateExtractElement(vs_v8i16, index_i64); - WriteMemory(addr_i64, val_i16, 2); -} - -void Compiler::STDUX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - WriteMemory(addr_i64, GetGpr(rs, 64)); - SetGpr(ra, addr_i64); -} - -void Compiler::STWUX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - WriteMemory(addr_i64, GetGpr(rs, 32)); - SetGpr(ra, addr_i64); -} - -void Compiler::STVEWX(u32 vs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFFFFFFFFFCULL); - auto index_i64 = m_ir_builder->CreateAnd(addr_i64, 0xf); - index_i64 = m_ir_builder->CreateLShr(index_i64, 2); - index_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(3), index_i64); - auto vs_v4i32 = GetVrAsIntVec(vs, 32); - auto val_i32 = m_ir_builder->CreateExtractElement(vs_v4i32, index_i64); - WriteMemory(addr_i64, val_i32, 4); -} - -void Compiler::ADDZE(u32 rd, u32 ra, u32 oe, u32 rc) { - auto ra_i64 = GetGpr(ra); - auto ca_i64 = GetXerCa(); - auto res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), ra_i64, ca_i64); - auto sum_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - SetGpr(rd, sum_i64); - SetXerCa(carry_i1); - - if (rc) { - SetCrFieldSignedCmp(0, sum_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - CompilationError("ADDZEO"); - } -} - -void Compiler::SUBFZE(u32 rd, u32 ra, u32 oe, u32 rc) { - auto ra_i64 = GetGpr(ra); - ra_i64 = m_ir_builder->CreateNot(ra_i64); - auto ca_i64 = GetXerCa(); - auto res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), ra_i64, ca_i64); - auto res_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - SetGpr(rd, res_i64); - SetXerCa(carry_i1); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - CompilationError("SUBFZEO"); - } -} - -void Compiler::STDCX_(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto addr_i32 = m_ir_builder->CreateTrunc(addr_i64, m_ir_builder->getInt32Ty()); - auto rs_i64 = GetGpr(rs); - rs_i64 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, m_ir_builder->getInt64Ty()), rs_i64); - auto rs_i64_ptr = m_ir_builder->CreateAlloca(m_ir_builder->getInt64Ty()); - rs_i64_ptr->setAlignment(8); - m_ir_builder->CreateStore(rs_i64, rs_i64_ptr); - auto success_i1 = Call("vm.reservation_update", addr_i32, m_ir_builder->CreateBitCast(rs_i64_ptr, m_ir_builder->getInt8PtrTy()), m_ir_builder->getInt32(8)); - - auto cr_i32 = GetCr(); - cr_i32 = SetBit(cr_i32, 2, success_i1); - SetCr(cr_i32); -} - -void Compiler::STBX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs, 8)); -} - -void Compiler::STVX(u32 vs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFFFFFFFFF0ULL); - WriteMemory(addr_i64, GetVr(vs), 16); -} - -void Compiler::SUBFME(u32 rd, u32 ra, u32 oe, u32 rc) { - auto ca_i64 = GetXerCa(); - auto ra_i64 = GetGpr(ra); - ra_i64 = m_ir_builder->CreateNot(ra_i64); - auto res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), ra_i64, ca_i64); - auto res_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry1_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), res_i64, m_ir_builder->getInt64((s64)-1)); - res_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry2_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - auto carry_i1 = m_ir_builder->CreateOr(carry1_i1, carry2_i1); - SetGpr(rd, res_i64); - SetXerCa(carry_i1); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - CompilationError("SUBFMEO"); - } -} - -void Compiler::MULLD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - auto ra_i64 = GetGpr(ra); - auto rb_i64 = GetGpr(rb); - auto prod_i64 = m_ir_builder->CreateMul(ra_i64, rb_i64); - SetGpr(rd, prod_i64); - - if (rc) { - SetCrFieldSignedCmp(0, prod_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO implement oe - CompilationError("MULLDO"); - } -} - -void Compiler::ADDME(u32 rd, u32 ra, u32 oe, u32 rc) { - auto ca_i64 = GetXerCa(); - auto ra_i64 = GetGpr(ra); - auto res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), ra_i64, ca_i64); - auto res_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry1_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - res_s = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::uadd_with_overflow, m_ir_builder->getInt64Ty()), res_i64, m_ir_builder->getInt64((s64)-1)); - res_i64 = m_ir_builder->CreateExtractValue(res_s, { 0 }); - auto carry2_i1 = m_ir_builder->CreateExtractValue(res_s, { 1 }); - auto carry_i1 = m_ir_builder->CreateOr(carry1_i1, carry2_i1); - SetGpr(rd, res_i64); - SetXerCa(carry_i1); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - CompilationError("ADDMEO"); - } -} - -void Compiler::MULLW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - USE_INTERP_IF_REQUESTED(MULLW, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rb), m_ir_builder->getInt32(oe), m_ir_builder->getInt32(rc)); - - auto ra_i32 = GetGpr(ra, 32); - auto rb_i32 = GetGpr(rb, 32); - auto ra_i64 = m_ir_builder->CreateSExt(ra_i32, m_ir_builder->getInt64Ty()); - auto rb_i64 = m_ir_builder->CreateSExt(rb_i32, m_ir_builder->getInt64Ty()); - auto prod_i64 = m_ir_builder->CreateMul(ra_i64, rb_i64); - SetGpr(rd, prod_i64); - - if (rc) { - SetCrFieldSignedCmp(0, prod_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO implement oe - CompilationError("MULLWO"); - } -} - -void Compiler::DCBTST(u32 ra, u32 rb, u32 th) { - // TODO: Implement this - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::donothing)); -} - -void Compiler::STBUX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - WriteMemory(addr_i64, GetGpr(rs, 8)); - SetGpr(ra, addr_i64); -} - -void Compiler::ADD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - USE_INTERP_IF_REQUESTED(ADD, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rb), m_ir_builder->getInt32(oe), m_ir_builder->getInt32(rc)); - - auto ra_i64 = GetGpr(ra); - auto rb_i64 = GetGpr(rb); - auto sum_i64 = m_ir_builder->CreateAdd(ra_i64, rb_i64); - SetGpr(rd, sum_i64); - - if (rc) { - SetCrFieldSignedCmp(0, sum_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO: Implement this - CompilationError("ADDO"); - } -} - -void Compiler::DCBT(u32 ra, u32 rb, u32 th) { - // TODO: Implement this using prefetch - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::donothing)); -} - -void Compiler::LHZX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i16 = ReadMemory(addr_i64, 16); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i16, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::EQV(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto rb_i64 = GetGpr(rb); - auto res_i64 = m_ir_builder->CreateXor(rs_i64, rb_i64); - res_i64 = m_ir_builder->CreateNot(res_i64); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::ECIWX(u32 rd, u32 ra, u32 rb) { - CompilationError("ECIWX"); - //auto addr_i64 = GetGpr(rb); - //if (ra) { - // auto ra_i64 = GetGpr(ra); - // addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - //} - - //auto mem_i32 = ReadMemory(addr_i64, 32); - //auto mem_i64 = m_ir_builder->CreateZExt(mem_i32, m_ir_builder->getInt64Ty()); - //SetGpr(rd, mem_i64); -} - -void Compiler::LHZUX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i16 = ReadMemory(addr_i64, 16); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i16, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::XOR(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto rb_i64 = GetGpr(rb); - auto res_i64 = m_ir_builder->CreateXor(rs_i64, rb_i64); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::MFSPR(u32 rd, u32 spr) { - Value * rd_i64; - auto n = (spr >> 5) | ((spr & 0x1f) << 5); - - switch (n) { - case 0x001: - rd_i64 = GetXer(); - break; - case 0x008: - rd_i64 = GetLr(); - break; - case 0x009: - rd_i64 = GetCtr(); - break; - case 0x100: - rd_i64 = GetVrsave(); - break; - case 0x10C: - rd_i64 = Call("get_timebased_time"); - break; - case 0x10D: - rd_i64 = Call("get_timebased_time"); - rd_i64 = m_ir_builder->CreateLShr(rd_i64, 32); - break; - default: - assert(0); - break; - } - - SetGpr(rd, rd_i64); -} - -void Compiler::LWAX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i32 = ReadMemory(addr_i64, 32); - auto mem_i64 = m_ir_builder->CreateSExt(mem_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::DST(u32 ra, u32 rb, u32 strm, u32 t) { - // TODO: Revisit - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::donothing)); -} - -void Compiler::LHAX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i16 = ReadMemory(addr_i64, 16); - auto mem_i64 = m_ir_builder->CreateSExt(mem_i16, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::LVXL(u32 vd, u32 ra, u32 rb) { - LVX(vd, ra, rb); -} - -void Compiler::MFTB(u32 rd, u32 spr) { - auto tb_i64 = Call("get_timebased_time"); - - u32 n = (spr >> 5) | ((spr & 0x1f) << 5); - if (n == 0x10D) { - tb_i64 = m_ir_builder->CreateLShr(tb_i64, 32); - } - - SetGpr(rd, tb_i64); -} - -void Compiler::LWAUX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i32 = ReadMemory(addr_i64, 32); - auto mem_i64 = m_ir_builder->CreateSExt(mem_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::DSTST(u32 ra, u32 rb, u32 strm, u32 t) { - // TODO: Revisit - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::donothing)); -} - -void Compiler::LHAUX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i16 = ReadMemory(addr_i64, 16); - auto mem_i64 = m_ir_builder->CreateSExt(mem_i16, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::STHX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs, 16)); -} - -void Compiler::ORC(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto rb_i64 = GetGpr(rb); - rb_i64 = m_ir_builder->CreateNot(rb_i64); - auto res_i64 = m_ir_builder->CreateOr(rs_i64, rb_i64); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::ECOWX(u32 rs, u32 ra, u32 rb) { - CompilationError("ECOWX"); - //auto addr_i64 = GetGpr(rb); - //if (ra) { - // auto ra_i64 = GetGpr(ra); - // addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - //} - - //WriteMemory(addr_i64, GetGpr(rs, 32)); -} - -void Compiler::STHUX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - WriteMemory(addr_i64, GetGpr(rs, 16)); - SetGpr(ra, addr_i64); -} - -void Compiler::OR(u32 ra, u32 rs, u32 rb, u32 rc) { - USE_INTERP_IF_REQUESTED(OR, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(rb), m_ir_builder->getInt32(rc)); - - auto rs_i64 = GetGpr(rs); - auto rb_i64 = GetGpr(rb); - auto res_i64 = m_ir_builder->CreateOr(rs_i64, rb_i64); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::DIVDU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - auto ra_i64 = GetGpr(ra); - auto rb_i64 = GetGpr(rb); - auto res_i64 = m_ir_builder->CreateUDiv(ra_i64, rb_i64); - SetGpr(rd, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO implement oe - CompilationError("DIVDUO"); - } - - // TODO make sure an exception does not occur on divide by 0 and overflow -} - -void Compiler::DIVWU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - USE_INTERP_IF_REQUESTED(DIVWU, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rb), m_ir_builder->getInt32(oe), m_ir_builder->getInt32(rc)); - - auto ra_i32 = GetGpr(ra, 32); - auto rb_i32 = GetGpr(rb, 32); - auto res_i32 = m_ir_builder->CreateUDiv(ra_i32, rb_i32); - auto res_i64 = m_ir_builder->CreateZExt(res_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO implement oe - CompilationError("DIVWUO"); - } - - // TODO make sure an exception does not occur on divide by 0 and overflow -} - -void Compiler::MTSPR(u32 spr, u32 rs) { - auto rs_i64 = GetGpr(rs); - auto n = (spr >> 5) | ((spr & 0x1f) << 5); - - switch (n) { - case 0x001: - SetXer(rs_i64); - break; - case 0x008: - SetLr(rs_i64); - break; - case 0x009: - SetCtr(rs_i64); - break; - case 0x100: - SetVrsave(rs_i64); - break; - default: - assert(0); - break; - } -} - -void Compiler::NAND(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto rb_i64 = GetGpr(rb); - auto res_i64 = m_ir_builder->CreateAnd(rs_i64, rb_i64); - res_i64 = m_ir_builder->CreateNot(res_i64); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::STVXL(u32 vs, u32 ra, u32 rb) { - STVX(vs, ra, rb); -} - -void Compiler::DIVD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - auto ra_i64 = GetGpr(ra); - auto rb_i64 = GetGpr(rb); - auto res_i64 = m_ir_builder->CreateSDiv(ra_i64, rb_i64); - SetGpr(rd, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO implement oe - CompilationError("DIVDO"); - } - - // TODO make sure an exception does not occur on divide by 0 and overflow -} - -void Compiler::DIVW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { - USE_INTERP_IF_REQUESTED(DIVW, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rb), m_ir_builder->getInt32(oe), m_ir_builder->getInt32(rc)); - - auto ra_i32 = GetGpr(ra, 32); - auto rb_i32 = GetGpr(rb, 32); - auto res_i32 = m_ir_builder->CreateSDiv(ra_i32, rb_i32); - auto res_i64 = m_ir_builder->CreateZExt(res_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } - - if (oe) { - // TODO implement oe - CompilationError("DIVWO"); - } - - // TODO make sure an exception does not occur on divide by 0 and overflow -} - -void Compiler::LVLX(u32 vd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto eb_i64 = m_ir_builder->CreateAnd(addr_i64, 0xF); - eb_i64 = m_ir_builder->CreateShl(eb_i64, 3); - auto eb_i128 = m_ir_builder->CreateZExt(eb_i64, m_ir_builder->getIntNTy(128)); - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFFFFFFFFF0ULL); - auto mem_i128 = ReadMemory(addr_i64, 128, 16); - mem_i128 = m_ir_builder->CreateShl(mem_i128, eb_i128); - SetVr(vd, mem_i128); -} - -void Compiler::LDBRX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i64 = ReadMemory(addr_i64, 64, 0, false); - SetGpr(rd, mem_i64); -} - -void Compiler::LSWX(u32 rd, u32 ra, u32 rb) { - CompilationError("LSWX"); -} - -void Compiler::LWBRX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i32 = ReadMemory(addr_i64, 32, 0, false); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::LFSX(u32 frd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i32 = ReadMemory(addr_i64, 32); - SetFpr(frd, mem_i32); -} - -void Compiler::SRW(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i32 = GetGpr(rs, 32); - auto rs_i64 = m_ir_builder->CreateZExt(rs_i32, m_ir_builder->getInt64Ty()); - auto rb_i8 = GetGpr(rb, 8); - rb_i8 = m_ir_builder->CreateAnd(rb_i8, 0x3F); - auto rb_i64 = m_ir_builder->CreateZExt(rb_i8, m_ir_builder->getInt64Ty()); - auto res_i64 = m_ir_builder->CreateLShr(rs_i64, rb_i64); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::SRD(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto rs_i128 = m_ir_builder->CreateZExt(rs_i64, m_ir_builder->getIntNTy(128)); - auto rb_i8 = GetGpr(rb, 8); - rb_i8 = m_ir_builder->CreateAnd(rb_i8, 0x7F); - auto rb_i128 = m_ir_builder->CreateZExt(rb_i8, m_ir_builder->getIntNTy(128)); - auto res_i128 = m_ir_builder->CreateLShr(rs_i128, rb_i128); - auto res_i64 = m_ir_builder->CreateTrunc(res_i128, m_ir_builder->getInt64Ty()); - SetGpr(ra, res_i64); - - if (rc) { - SetCrFieldSignedCmp(0, res_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::LVRX(u32 vd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto eb_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(16), addr_i64); - eb_i64 = m_ir_builder->CreateAnd(eb_i64, 0xF); - eb_i64 = m_ir_builder->CreateShl(eb_i64, 3); - auto eb_i128 = m_ir_builder->CreateZExt(eb_i64, m_ir_builder->getIntNTy(128)); - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFFFFFFFFF0ULL); - auto mem_i128 = ReadMemory(addr_i64, 128, 16); - mem_i128 = m_ir_builder->CreateLShr(mem_i128, eb_i128); - auto cmp_i1 = m_ir_builder->CreateICmpNE(eb_i64, m_ir_builder->getInt64(0)); - auto cmp_i128 = m_ir_builder->CreateSExt(cmp_i1, m_ir_builder->getIntNTy(128)); - mem_i128 = m_ir_builder->CreateAnd(mem_i128, cmp_i128); - SetVr(vd, mem_i128); -} - -void Compiler::LSWI(u32 rd, u32 ra, u32 nb) { - auto addr_i64 = ra ? GetGpr(ra) : m_ir_builder->getInt64(0); - - nb = nb ? nb : 32; - for (u32 i = 0; i < nb; i += 4) { - auto val_i32 = ReadMemory(addr_i64, 32, 0, true, false); - - if (i + 4 <= nb) { - addr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64(4)); - } - else { - u32 mask = 0xFFFFFFFF << ((4 - (nb - i)) * 8); - val_i32 = m_ir_builder->CreateAnd(val_i32, mask); - } - - auto val_i64 = m_ir_builder->CreateZExt(val_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, val_i64); - rd = (rd + 1) % 32; - } -} - -void Compiler::LFSUX(u32 frd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - auto mem_i32 = ReadMemory(addr_i64, 32); - SetFpr(frd, mem_i32); - SetGpr(ra, addr_i64); -} - -void Compiler::SYNC(u32 l) { - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_mfence)); -} - -void Compiler::LFDX(u32 frd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i64 = ReadMemory(addr_i64, 64); - SetFpr(frd, mem_i64); -} - -void Compiler::LFDUX(u32 frd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - auto mem_i64 = ReadMemory(addr_i64, 64); - SetFpr(frd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::STVLX(u32 vs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto index_i64 = m_ir_builder->CreateAnd(addr_i64, 0xf); - auto size_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(16), index_i64); - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFF); - addr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64((u64)vm::base(0))); - auto addr_i8_ptr = m_ir_builder->CreateIntToPtr(addr_i64, m_ir_builder->getInt8PtrTy()); - - auto vs_i128 = GetVr(vs); - vs_i128 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, vs_i128->getType()), vs_i128); - auto vs_i128_ptr = m_ir_builder->CreateAlloca(vs_i128->getType()); - vs_i128_ptr->setAlignment(16); - m_ir_builder->CreateAlignedStore(vs_i128, vs_i128_ptr, 16); - auto vs_i8_ptr = m_ir_builder->CreateBitCast(vs_i128_ptr, m_ir_builder->getInt8PtrTy()); - - Type * types[3] = { m_ir_builder->getInt8PtrTy(), m_ir_builder->getInt8PtrTy(), m_ir_builder->getInt64Ty() }; - m_ir_builder->CreateCall5(Intrinsic::getDeclaration(m_module, Intrinsic::memcpy, types), - addr_i8_ptr, vs_i8_ptr, size_i64, m_ir_builder->getInt32(1), m_ir_builder->getInt1(false)); -} - -void Compiler::STDBRX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs), 0, false); -} - -void Compiler::STSWX(u32 rs, u32 ra, u32 rb) { - CompilationError("STSWX"); -} - -void Compiler::STWBRX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs, 32), 0, false); -} - -void Compiler::STFSX(u32 frs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto frs_i32 = m_ir_builder->CreateBitCast(GetFpr(frs, 32), m_ir_builder->getInt32Ty()); - WriteMemory(addr_i64, frs_i32); -} - -void Compiler::STVRX(u32 vs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto size_i64 = m_ir_builder->CreateAnd(addr_i64, 0xf); - auto index_i64 = m_ir_builder->CreateSub(m_ir_builder->getInt64(16), size_i64); - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFF0); - addr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64((u64)vm::base(0))); - auto addr_i8_ptr = m_ir_builder->CreateIntToPtr(addr_i64, m_ir_builder->getInt8PtrTy()); - - auto vs_i128 = GetVr(vs); - vs_i128 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, vs_i128->getType()), vs_i128); - auto vs_i128_ptr = m_ir_builder->CreateAlloca(vs_i128->getType()); - vs_i128_ptr->setAlignment(16); - m_ir_builder->CreateAlignedStore(vs_i128, vs_i128_ptr, 16); - auto vs_i8_ptr = m_ir_builder->CreateBitCast(vs_i128_ptr, m_ir_builder->getInt8PtrTy()); - vs_i8_ptr = m_ir_builder->CreateGEP(vs_i8_ptr, index_i64); - - Type * types[3] = { m_ir_builder->getInt8PtrTy(), m_ir_builder->getInt8PtrTy(), m_ir_builder->getInt64Ty() }; - m_ir_builder->CreateCall5(Intrinsic::getDeclaration(m_module, Intrinsic::memcpy, types), - addr_i8_ptr, vs_i8_ptr, size_i64, m_ir_builder->getInt32(1), m_ir_builder->getInt1(false)); -} - -void Compiler::STFSUX(u32 frs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto frs_i32 = m_ir_builder->CreateBitCast(GetFpr(frs, 32), m_ir_builder->getInt32Ty()); - WriteMemory(addr_i64, frs_i32); - SetGpr(ra, addr_i64); -} - -void Compiler::STSWI(u32 rd, u32 ra, u32 nb) { - auto addr_i64 = ra ? GetGpr(ra) : m_ir_builder->getInt64(0); - - nb = nb ? nb : 32; - for (u32 i = 0; i < nb; i += 4) { - auto val_i32 = GetGpr(rd, 32); - - if (i + 4 <= nb) { - WriteMemory(addr_i64, val_i32, 0, true, false); - addr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64(4)); - rd = (rd + 1) % 32; - } - else { - u32 n = nb - i; - if (n >= 2) { - auto val_i16 = m_ir_builder->CreateLShr(val_i32, 16); - val_i16 = m_ir_builder->CreateTrunc(val_i16, m_ir_builder->getInt16Ty()); - WriteMemory(addr_i64, val_i16); - - if (n == 3) { - auto val_i8 = m_ir_builder->CreateLShr(val_i32, 8); - val_i8 = m_ir_builder->CreateTrunc(val_i8, m_ir_builder->getInt8Ty()); - addr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64(2)); - WriteMemory(addr_i64, val_i8); - } - } - else { - auto val_i8 = m_ir_builder->CreateLShr(val_i32, 24); - val_i8 = m_ir_builder->CreateTrunc(val_i8, m_ir_builder->getInt8Ty()); - WriteMemory(addr_i64, val_i8); - } - } - } -} - -void Compiler::STFDX(u32 frs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto frs_i64 = m_ir_builder->CreateBitCast(GetFpr(frs), m_ir_builder->getInt64Ty()); - WriteMemory(addr_i64, frs_i64); -} - -void Compiler::STFDUX(u32 frs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto frs_i64 = m_ir_builder->CreateBitCast(GetFpr(frs), m_ir_builder->getInt64Ty()); - WriteMemory(addr_i64, frs_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::LVLXL(u32 vd, u32 ra, u32 rb) { - LVLX(vd, ra, rb); -} - -void Compiler::LHBRX(u32 rd, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i16 = ReadMemory(addr_i64, 16, 0, false); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i16, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::SRAW(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i32 = GetGpr(rs, 32); - auto rs_i64 = m_ir_builder->CreateZExt(rs_i32, m_ir_builder->getInt64Ty()); - rs_i64 = m_ir_builder->CreateShl(rs_i64, 32); - auto rb_i8 = GetGpr(rb, 8); - rb_i8 = m_ir_builder->CreateAnd(rb_i8, 0x3F); - auto rb_i64 = m_ir_builder->CreateZExt(rb_i8, m_ir_builder->getInt64Ty()); - auto res_i64 = m_ir_builder->CreateAShr(rs_i64, rb_i64); - auto ra_i64 = m_ir_builder->CreateAShr(res_i64, 32); - SetGpr(ra, ra_i64); - - auto res_i32 = m_ir_builder->CreateTrunc(res_i64, m_ir_builder->getInt32Ty()); - auto ca1_i1 = m_ir_builder->CreateICmpSLT(ra_i64, m_ir_builder->getInt64(0)); - auto ca2_i1 = m_ir_builder->CreateICmpNE(res_i32, m_ir_builder->getInt32(0)); - auto ca_i1 = m_ir_builder->CreateAnd(ca1_i1, ca2_i1); - SetXerCa(ca_i1); - - if (rc) { - SetCrFieldSignedCmp(0, ra_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::SRAD(u32 ra, u32 rs, u32 rb, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto rs_i128 = m_ir_builder->CreateZExt(rs_i64, m_ir_builder->getIntNTy(128)); - rs_i128 = m_ir_builder->CreateShl(rs_i128, 64); - auto rb_i8 = GetGpr(rb, 8); - rb_i8 = m_ir_builder->CreateAnd(rb_i8, 0x7F); - auto rb_i128 = m_ir_builder->CreateZExt(rb_i8, m_ir_builder->getIntNTy(128)); - auto res_i128 = m_ir_builder->CreateAShr(rs_i128, rb_i128); - auto ra_i128 = m_ir_builder->CreateAShr(res_i128, 64); - auto ra_i64 = m_ir_builder->CreateTrunc(ra_i128, m_ir_builder->getInt64Ty()); - SetGpr(ra, ra_i64); - - auto res_i64 = m_ir_builder->CreateTrunc(res_i128, m_ir_builder->getInt64Ty()); - auto ca1_i1 = m_ir_builder->CreateICmpSLT(ra_i64, m_ir_builder->getInt64(0)); - auto ca2_i1 = m_ir_builder->CreateICmpNE(res_i64, m_ir_builder->getInt64(0)); - auto ca_i1 = m_ir_builder->CreateAnd(ca1_i1, ca2_i1); - SetXerCa(ca_i1); - - if (rc) { - SetCrFieldSignedCmp(0, ra_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::LVRXL(u32 vd, u32 ra, u32 rb) { - LVRX(vd, ra, rb); -} - -void Compiler::DSS(u32 strm, u32 a) { - // TODO: Revisit - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::donothing)); -} - -void Compiler::SRAWI(u32 ra, u32 rs, u32 sh, u32 rc) { - USE_INTERP_IF_REQUESTED(SRAWI, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(sh), m_ir_builder->getInt32(rc)); - - auto rs_i32 = GetGpr(rs, 32); - auto rs_i64 = m_ir_builder->CreateZExt(rs_i32, m_ir_builder->getInt64Ty()); - rs_i64 = m_ir_builder->CreateShl(rs_i64, 32); - auto res_i64 = m_ir_builder->CreateAShr(rs_i64, sh); - auto ra_i64 = m_ir_builder->CreateAShr(res_i64, 32); - SetGpr(ra, ra_i64); - - auto res_i32 = m_ir_builder->CreateTrunc(res_i64, m_ir_builder->getInt32Ty()); - auto ca1_i1 = m_ir_builder->CreateICmpSLT(ra_i64, m_ir_builder->getInt64(0)); - auto ca2_i1 = m_ir_builder->CreateICmpNE(res_i32, m_ir_builder->getInt32(0)); - auto ca_i1 = m_ir_builder->CreateAnd(ca1_i1, ca2_i1); - SetXerCa(ca_i1); - - if (rc) { - SetCrFieldSignedCmp(0, ra_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::SRADI1(u32 ra, u32 rs, u32 sh, u32 rc) { - auto rs_i64 = GetGpr(rs); - auto rs_i128 = m_ir_builder->CreateZExt(rs_i64, m_ir_builder->getIntNTy(128)); - rs_i128 = m_ir_builder->CreateShl(rs_i128, 64); - auto res_i128 = m_ir_builder->CreateAShr(rs_i128, sh); - auto ra_i128 = m_ir_builder->CreateAShr(res_i128, 64); - auto ra_i64 = m_ir_builder->CreateTrunc(ra_i128, m_ir_builder->getInt64Ty()); - SetGpr(ra, ra_i64); - - auto res_i64 = m_ir_builder->CreateTrunc(res_i128, m_ir_builder->getInt64Ty()); - auto ca1_i1 = m_ir_builder->CreateICmpSLT(ra_i64, m_ir_builder->getInt64(0)); - auto ca2_i1 = m_ir_builder->CreateICmpNE(res_i64, m_ir_builder->getInt64(0)); - auto ca_i1 = m_ir_builder->CreateAnd(ca1_i1, ca2_i1); - SetXerCa(ca_i1); - - if (rc) { - SetCrFieldSignedCmp(0, ra_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::SRADI2(u32 ra, u32 rs, u32 sh, u32 rc) { - SRADI1(ra, rs, sh, rc); -} - -void Compiler::EIEIO() { - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_mfence)); -} - -void Compiler::STVLXL(u32 vs, u32 ra, u32 rb) { - STVLX(vs, ra, rb); -} - -void Compiler::STHBRX(u32 rs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs, 16), 0, false); -} - -void Compiler::EXTSH(u32 ra, u32 rs, u32 rc) { - auto rs_i16 = GetGpr(rs, 16); - auto rs_i64 = m_ir_builder->CreateSExt(rs_i16, m_ir_builder->getInt64Ty()); - SetGpr(ra, rs_i64); - - if (rc) { - SetCrFieldSignedCmp(0, rs_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::STVRXL(u32 vs, u32 ra, u32 rb) { - STVRX(vs, ra, rb); -} - -void Compiler::EXTSB(u32 ra, u32 rs, u32 rc) { - USE_INTERP_IF_REQUESTED(EXTSB, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(rc)); - - auto rs_i8 = GetGpr(rs, 8); - auto rs_i64 = m_ir_builder->CreateSExt(rs_i8, m_ir_builder->getInt64Ty()); - SetGpr(ra, rs_i64); - - if (rc) { - SetCrFieldSignedCmp(0, rs_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::STFIWX(u32 frs, u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto frs_i64 = m_ir_builder->CreateBitCast(GetFpr(frs), m_ir_builder->getInt64Ty()); - auto frs_i32 = m_ir_builder->CreateTrunc(frs_i64, m_ir_builder->getInt32Ty()); - WriteMemory(addr_i64, frs_i32); -} - -void Compiler::EXTSW(u32 ra, u32 rs, u32 rc) { - USE_INTERP_IF_REQUESTED(EXTSW, m_ir_builder->getInt32(ra), m_ir_builder->getInt32(rs), m_ir_builder->getInt32(rc)); - - auto rs_i32 = GetGpr(rs, 32); - auto rs_i64 = m_ir_builder->CreateSExt(rs_i32, m_ir_builder->getInt64Ty()); - SetGpr(ra, rs_i64); - - if (rc) { - SetCrFieldSignedCmp(0, rs_i64, m_ir_builder->getInt64(0)); - } -} - -void Compiler::ICBI(u32 ra, u32 rs) { - // TODO: Revisit - m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::donothing)); -} - -void Compiler::DCBZ(u32 ra, u32 rb) { - auto addr_i64 = GetGpr(rb); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - addr_i64 = m_ir_builder->CreateAnd(addr_i64, ~(127ULL)); - addr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64((u64)vm::base(0))); - auto addr_i8_ptr = m_ir_builder->CreateIntToPtr(addr_i64, m_ir_builder->getInt8PtrTy()); - - std::vector types = { (Type *)m_ir_builder->getInt8PtrTy(), (Type *)m_ir_builder->getInt32Ty() }; - m_ir_builder->CreateCall5(Intrinsic::getDeclaration(m_module, Intrinsic::memset, types), - addr_i8_ptr, m_ir_builder->getInt8(0), m_ir_builder->getInt32(128), m_ir_builder->getInt32(128), m_ir_builder->getInt1(true)); -} - -void Compiler::LWZ(u32 rd, u32 ra, s32 d) { - USE_INTERP_IF_REQUESTED(LWZ, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(d)); - - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i32 = ReadMemory(addr_i64, 32); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::LWZU(u32 rd, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i32 = ReadMemory(addr_i64, 32); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::LBZ(u32 rd, u32 ra, s32 d) { - USE_INTERP_IF_REQUESTED(LBZ, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(d)); - - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i8 = ReadMemory(addr_i64, 8); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i8, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::LBZU(u32 rd, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i8 = ReadMemory(addr_i64, 8); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i8, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::STW(u32 rs, u32 ra, s32 d) { - USE_INTERP_IF_REQUESTED(STW, m_ir_builder->getInt32(rs), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(d)); - - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs, 32)); -} - -void Compiler::STWU(u32 rs, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - WriteMemory(addr_i64, GetGpr(rs, 32)); - SetGpr(ra, addr_i64); -} - -void Compiler::STB(u32 rs, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs, 8)); -} - -void Compiler::STBU(u32 rs, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - WriteMemory(addr_i64, GetGpr(rs, 8)); - SetGpr(ra, addr_i64); -} - -void Compiler::LHZ(u32 rd, u32 ra, s32 d) { - USE_INTERP_IF_REQUESTED(LHZ, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(d)); - - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i16 = ReadMemory(addr_i64, 16); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i16, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::LHZU(u32 rd, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i16 = ReadMemory(addr_i64, 16); - auto mem_i64 = m_ir_builder->CreateZExt(mem_i16, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::LHA(u32 rd, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i16 = ReadMemory(addr_i64, 16); - auto mem_i64 = m_ir_builder->CreateSExt(mem_i16, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::LHAU(u32 rd, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i16 = ReadMemory(addr_i64, 16); - auto mem_i64 = m_ir_builder->CreateSExt(mem_i16, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::STH(u32 rs, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs, 16)); -} - -void Compiler::STHU(u32 rs, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - WriteMemory(addr_i64, GetGpr(rs, 16)); - SetGpr(ra, addr_i64); -} - -void Compiler::LMW(u32 rd, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - addr_i64 = m_ir_builder->CreateAdd(addr_i64, GetGpr(ra)); - } - - for (u32 i = rd; i < 32; i++) { - auto val_i32 = ReadMemory(addr_i64, 32); - auto val_i64 = m_ir_builder->CreateZExt(val_i32, m_ir_builder->getInt64Ty()); - SetGpr(i, val_i64); - addr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64(4)); - } -} - -void Compiler::STMW(u32 rs, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - addr_i64 = m_ir_builder->CreateAdd(addr_i64, GetGpr(ra)); - } - - for (u32 i = rs; i < 32; i++) { - auto val_i32 = GetGpr(i, 32); - WriteMemory(addr_i64, val_i32); - addr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64(4)); - } -} - -void Compiler::LFS(u32 frd, u32 ra, s32 d) { - USE_INTERP_IF_REQUESTED(LFS, m_ir_builder->getInt32(frd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(d)); - - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i32 = ReadMemory(addr_i64, 32); - SetFpr(frd, mem_i32); -} - -void Compiler::LFSU(u32 frd, u32 ra, s32 ds) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)ds); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - auto mem_i32 = ReadMemory(addr_i64, 32); - SetFpr(frd, mem_i32); - SetGpr(ra, addr_i64); -} - -void Compiler::LFD(u32 frd, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i64 = ReadMemory(addr_i64, 64); - SetFpr(frd, mem_i64); -} - -void Compiler::LFDU(u32 frd, u32 ra, s32 ds) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)ds); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i64 = ReadMemory(addr_i64, 64); - SetFpr(frd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::STFS(u32 frs, u32 ra, s32 d) { - USE_INTERP_IF_REQUESTED(STFS, m_ir_builder->getInt32(frs), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(d)); - - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto frs_i32 = m_ir_builder->CreateBitCast(GetFpr(frs, 32), m_ir_builder->getInt32Ty()); - WriteMemory(addr_i64, frs_i32); -} - -void Compiler::STFSU(u32 frs, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto frs_i32 = m_ir_builder->CreateBitCast(GetFpr(frs, 32), m_ir_builder->getInt32Ty()); - WriteMemory(addr_i64, frs_i32); - SetGpr(ra, addr_i64); -} - -void Compiler::STFD(u32 frs, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto frs_i64 = m_ir_builder->CreateBitCast(GetFpr(frs), m_ir_builder->getInt64Ty()); - WriteMemory(addr_i64, frs_i64); -} - -void Compiler::STFDU(u32 frs, u32 ra, s32 d) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto frs_i64 = m_ir_builder->CreateBitCast(GetFpr(frs), m_ir_builder->getInt64Ty()); - WriteMemory(addr_i64, frs_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::LD(u32 rd, u32 ra, s32 ds) { - USE_INTERP_IF_REQUESTED(LD, m_ir_builder->getInt32(rd), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(ds)); - - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)ds); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i64 = ReadMemory(addr_i64, 64); - SetGpr(rd, mem_i64); -} - -void Compiler::LDU(u32 rd, u32 ra, s32 ds) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)ds); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - auto mem_i64 = ReadMemory(addr_i64, 64); - SetGpr(rd, mem_i64); - SetGpr(ra, addr_i64); -} - -void Compiler::LWA(u32 rd, u32 ra, s32 ds) { - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)ds); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - auto mem_i32 = ReadMemory(addr_i64, 32); - auto mem_i64 = m_ir_builder->CreateSExt(mem_i32, m_ir_builder->getInt64Ty()); - SetGpr(rd, mem_i64); -} - -void Compiler::FDIVS(u32 frd, u32 fra, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto res_f64 = m_ir_builder->CreateFDiv(ra_f64, rb_f64); - auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy()); - SetFpr(frd, res_f32); - - if (rc) { - // TODO: Implement this - CompilationError("FDIVS."); - } - - // TODO: Set flags -} - -void Compiler::FSUBS(u32 frd, u32 fra, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto res_f64 = m_ir_builder->CreateFSub(ra_f64, rb_f64); - auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy()); - SetFpr(frd, res_f32); - - if (rc) { - // TODO: Implement this - CompilationError("FSUBS."); - } - - // TODO: Set flags -} - -void Compiler::FADDS(u32 frd, u32 fra, u32 frb, u32 rc) { - - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto res_f64 = m_ir_builder->CreateFAdd(ra_f64, rb_f64); - auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy()); - SetFpr(frd, res_f32); - - if (rc) { - // TODO: Implement this - CompilationError("FADDS."); - } - - // TODO: Set flags -} - -void Compiler::FSQRTS(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto res_f64 = (Value *)m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::sqrt, m_ir_builder->getDoubleTy()), rb_f64); - auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy()); - SetFpr(frd, res_f32); - - if (rc) { - // TODO: Implement this - CompilationError("FSQRTS."); - } - - // TODO: Set flags -} - -void Compiler::FRES(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto res_f64 = m_ir_builder->CreateFDiv(ConstantFP::get(m_ir_builder->getDoubleTy(), 1.0), rb_f64); - auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy()); - SetFpr(frd, res_f32); - - if (rc) { - // TODO: Implement this - CompilationError("FRES."); - } - - // TODO: Set flags -} - -void Compiler::FMULS(u32 frd, u32 fra, u32 frc, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rc_f64 = GetFpr(frc); - auto res_f64 = m_ir_builder->CreateFMul(ra_f64, rc_f64); - auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy()); - SetFpr(frd, res_f32); - - if (rc) { - // TODO: Implement this - CompilationError("FMULS."); - } - - // TODO: Set flags -} - -void Compiler::FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto rc_f64 = GetFpr(frc); - auto res_f64 = (Value *)m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, m_ir_builder->getDoubleTy()), ra_f64, rc_f64, rb_f64); - auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy()); - SetFpr(frd, res_f32); - - if (rc) { - // TODO: Implement this - CompilationError("FMADDS."); - } - - // TODO: Set flags -} - -void Compiler::FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto rc_f64 = GetFpr(frc); - rb_f64 = m_ir_builder->CreateFNeg(rb_f64); - auto res_f64 = (Value *)m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, m_ir_builder->getDoubleTy()), ra_f64, rc_f64, rb_f64); - auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy()); - SetFpr(frd, res_f32); - - if (rc) { - // TODO: Implement this - CompilationError("FMSUBS."); - } - - // TODO: Set flags -} - -void Compiler::FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto rc_f64 = GetFpr(frc); - rb_f64 = m_ir_builder->CreateFNeg(rb_f64); - auto res_f64 = (Value *)m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, m_ir_builder->getDoubleTy()), ra_f64, rc_f64, rb_f64); - res_f64 = m_ir_builder->CreateFNeg(res_f64); - auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy()); - SetFpr(frd, res_f32); - - if (rc) { - // TODO: Implement this - CompilationError("FNMSUBS."); - } - - // TODO: Set flags -} - -void Compiler::FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto rc_f64 = GetFpr(frc); - auto res_f64 = (Value *)m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, m_ir_builder->getDoubleTy()), ra_f64, rc_f64, rb_f64); - res_f64 = m_ir_builder->CreateFNeg(res_f64); - auto res_f32 = m_ir_builder->CreateFPTrunc(res_f64, m_ir_builder->getFloatTy()); - SetFpr(frd, res_f32); - - if (rc) { - // TODO: Implement this - CompilationError("FNMADDS."); - } - - // TODO: Set flags -} - -void Compiler::STD(u32 rs, u32 ra, s32 d) { - USE_INTERP_IF_REQUESTED(STD, m_ir_builder->getInt32(rs), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(d)); - - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)d); - if (ra) { - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - } - - WriteMemory(addr_i64, GetGpr(rs, 64)); -} - -void Compiler::STDU(u32 rs, u32 ra, s32 ds) { - USE_INTERP_IF_REQUESTED(STDU, m_ir_builder->getInt32(rs), m_ir_builder->getInt32(ra), m_ir_builder->getInt32(ds)); - - auto addr_i64 = (Value *)m_ir_builder->getInt64((s64)ds); - auto ra_i64 = GetGpr(ra); - addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); - - WriteMemory(addr_i64, GetGpr(rs, 64)); - SetGpr(ra, addr_i64); -} - -void Compiler::MTFSB1(u32 crbd, u32 rc) { - auto fpscr_i32 = GetFpscr(); - fpscr_i32 = SetBit(fpscr_i32, crbd, m_ir_builder->getInt32(1), false); - SetFpscr(fpscr_i32); - - if (rc) { - // TODO: Implement this - CompilationError("MTFSB1."); - } -} - -void Compiler::MCRFS(u32 crbd, u32 crbs) { - auto fpscr_i32 = GetFpscr(); - auto val_i32 = GetNibble(fpscr_i32, crbs); - SetCrField(crbd, val_i32); - - switch (crbs) { - case 0: - fpscr_i32 = ClrBit(fpscr_i32, 0); - fpscr_i32 = ClrBit(fpscr_i32, 3); - break; - case 1: - fpscr_i32 = ClrNibble(fpscr_i32, 1); - break; - case 2: - fpscr_i32 = ClrNibble(fpscr_i32, 2); - break; - case 3: - fpscr_i32 = ClrBit(fpscr_i32, 12); - break; - case 5: - fpscr_i32 = ClrBit(fpscr_i32, 21); - fpscr_i32 = ClrBit(fpscr_i32, 22); - fpscr_i32 = ClrBit(fpscr_i32, 23); - break; - default: - break; - } - - SetFpscr(fpscr_i32); -} - -void Compiler::MTFSB0(u32 crbd, u32 rc) { - auto fpscr_i32 = GetFpscr(); - fpscr_i32 = ClrBit(fpscr_i32, crbd); - SetFpscr(fpscr_i32); - - if (rc) { - // TODO: Implement this - CompilationError("MTFSB0."); - } -} - -void Compiler::MTFSFI(u32 crfd, u32 i, u32 rc) { - auto fpscr_i32 = GetFpscr(); - fpscr_i32 = SetNibble(fpscr_i32, crfd, m_ir_builder->getInt32(i & 0xF)); - SetFpscr(fpscr_i32); - - if (rc) { - // TODO: Implement this - CompilationError("MTFSFI."); - } -} - -void Compiler::MFFS(u32 frd, u32 rc) { - auto fpscr_i32 = GetFpscr(); - auto fpscr_i64 = m_ir_builder->CreateZExt(fpscr_i32, m_ir_builder->getInt64Ty()); - SetFpr(frd, fpscr_i64); - - if (rc) { - // TODO: Implement this - CompilationError("MFFS."); - } -} - -void Compiler::MTFSF(u32 flm, u32 frb, u32 rc) { - u64 mask = 0; - for (u32 i = 0; i < 8; i++) { - if (flm & (1 << i)) { - mask |= UINT64_C(0xF) << (i * 4); - } - } - - auto rb_i32 = GetFpr(frb, 32, true); - auto fpscr_i32 = GetFpscr(); - fpscr_i32 = m_ir_builder->CreateAnd(fpscr_i32, ~mask); - rb_i32 = m_ir_builder->CreateAnd(rb_i32, mask); - fpscr_i32 = m_ir_builder->CreateOr(fpscr_i32, rb_i32); - SetFpscr(fpscr_i32); - - if (rc) { - // TODO: Implement this - CompilationError("MTFSF."); - } -} - -void Compiler::FCMPU(u32 crfd, u32 fra, u32 frb) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto lt_i1 = m_ir_builder->CreateFCmpOLT(ra_f64, rb_f64); - auto gt_i1 = m_ir_builder->CreateFCmpOGT(ra_f64, rb_f64); - auto eq_i1 = m_ir_builder->CreateFCmpOEQ(ra_f64, rb_f64); - auto cr_i32 = GetCr(); - cr_i32 = SetNibble(cr_i32, crfd, lt_i1, gt_i1, eq_i1, m_ir_builder->getInt1(false)); - SetCr(cr_i32); - - // TODO: Set flags / Handle NaN -} - -void Compiler::FRSP(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto res_f32 = m_ir_builder->CreateFPTrunc(rb_f64, m_ir_builder->getFloatTy()); - auto res_f64 = m_ir_builder->CreateFPExt(res_f32, m_ir_builder->getDoubleTy()); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FRSP."); - } - - // TODO: Revisit this - // TODO: Set flags -} - -void Compiler::FCTIW(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto max_i1 = m_ir_builder->CreateFCmpOGT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), 2147483647.0)); - auto min_i1 = m_ir_builder->CreateFCmpULT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), -2147483648.0)); - auto res_i32 = m_ir_builder->CreateFPToSI(rb_f64, m_ir_builder->getInt32Ty()); - auto res_i64 = m_ir_builder->CreateZExt(res_i32, m_ir_builder->getInt64Ty()); - res_i64 = m_ir_builder->CreateSelect(max_i1, m_ir_builder->getInt64(0x7FFFFFFF), res_i64); - res_i64 = m_ir_builder->CreateSelect(min_i1, m_ir_builder->getInt64(0x80000000), res_i64); - SetFpr(frd, res_i64); - - if (rc) { - // TODO: Implement this - CompilationError("FCTIW."); - } - - // TODO: Set flags / Implement rounding modes -} - -void Compiler::FCTIWZ(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto max_i1 = m_ir_builder->CreateFCmpOGT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), 2147483647.0)); - auto min_i1 = m_ir_builder->CreateFCmpULT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), -2147483648.0)); - auto res_i32 = m_ir_builder->CreateFPToSI(rb_f64, m_ir_builder->getInt32Ty()); - auto res_i64 = m_ir_builder->CreateZExt(res_i32, m_ir_builder->getInt64Ty()); - res_i64 = m_ir_builder->CreateSelect(max_i1, m_ir_builder->getInt64(0x7FFFFFFF), res_i64); - res_i64 = m_ir_builder->CreateSelect(min_i1, m_ir_builder->getInt64(0x80000000), res_i64); - SetFpr(frd, res_i64); - - if (rc) { - // TODO: Implement this - CompilationError("FCTIWZ."); - } - - // TODO: Set flags -} - -void Compiler::FDIV(u32 frd, u32 fra, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto res_f64 = m_ir_builder->CreateFDiv(ra_f64, rb_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FDIV."); - } - - // TODO: Set flags -} - -void Compiler::FSUB(u32 frd, u32 fra, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto res_f64 = m_ir_builder->CreateFSub(ra_f64, rb_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FSUB."); - } - - // TODO: Set flags -} - -void Compiler::FADD(u32 frd, u32 fra, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto res_f64 = m_ir_builder->CreateFAdd(ra_f64, rb_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FADD."); - } - - // TODO: Set flags -} - -void Compiler::FSQRT(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto res_f64 = (Value *)m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::sqrt, m_ir_builder->getDoubleTy()), rb_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FSQRT."); - } - - // TODO: Set flags -} - -void Compiler::FSEL(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto rc_f64 = GetFpr(frc); - auto cmp_i1 = m_ir_builder->CreateFCmpOGE(ra_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), 0.0)); - auto res_f64 = m_ir_builder->CreateSelect(cmp_i1, rc_f64, rb_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FSEL."); - } - - // TODO: Set flags -} - -void Compiler::FMUL(u32 frd, u32 fra, u32 frc, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rc_f64 = GetFpr(frc); - auto res_f64 = m_ir_builder->CreateFMul(ra_f64, rc_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FMUL."); - } - - // TODO: Set flags -} - -void Compiler::FRSQRTE(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto res_f64 = (Value *)m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::sqrt, m_ir_builder->getDoubleTy()), rb_f64); - res_f64 = m_ir_builder->CreateFDiv(ConstantFP::get(m_ir_builder->getDoubleTy(), 1.0), res_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FRSQRTE."); - } -} - -void Compiler::FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto rc_f64 = GetFpr(frc); - rb_f64 = m_ir_builder->CreateFNeg(rb_f64); - auto res_f64 = m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, m_ir_builder->getDoubleTy()), ra_f64, rc_f64, rb_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FMSUB."); - } - - // TODO: Set flags -} - -void Compiler::FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto rc_f64 = GetFpr(frc); - auto res_f64 = m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, m_ir_builder->getDoubleTy()), ra_f64, rc_f64, rb_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FMADD."); - } - - // TODO: Set flags -} - -void Compiler::FNMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto rc_f64 = GetFpr(frc); - rc_f64 = m_ir_builder->CreateFNeg(rc_f64); - auto res_f64 = (Value *)m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, m_ir_builder->getDoubleTy()), ra_f64, rc_f64, rb_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FNMSUB."); - } - - // TODO: Set flags -} - -void Compiler::FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto rc_f64 = GetFpr(frc); - rb_f64 = m_ir_builder->CreateFNeg(rb_f64); - rc_f64 = m_ir_builder->CreateFNeg(rc_f64); - auto res_f64 = (Value *)m_ir_builder->CreateCall3(Intrinsic::getDeclaration(m_module, Intrinsic::fmuladd, m_ir_builder->getDoubleTy()), ra_f64, rc_f64, rb_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FNMADD."); - } - - // TODO: Set flags -} - -void Compiler::FCMPO(u32 crfd, u32 fra, u32 frb) { - auto ra_f64 = GetFpr(fra); - auto rb_f64 = GetFpr(frb); - auto lt_i1 = m_ir_builder->CreateFCmpOLT(ra_f64, rb_f64); - auto gt_i1 = m_ir_builder->CreateFCmpOGT(ra_f64, rb_f64); - auto eq_i1 = m_ir_builder->CreateFCmpOEQ(ra_f64, rb_f64); - auto cr_i32 = GetCr(); - cr_i32 = SetNibble(cr_i32, crfd, lt_i1, gt_i1, eq_i1, m_ir_builder->getInt1(false)); - SetCr(cr_i32); - - // TODO: Set flags / Handle NaN -} - -void Compiler::FNEG(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - rb_f64 = m_ir_builder->CreateFNeg(rb_f64); - SetFpr(frd, rb_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FNEG."); - } - - // TODO: Set flags -} - -void Compiler::FMR(u32 frd, u32 frb, u32 rc) { - SetFpr(frd, GetFpr(frb)); - - if (rc) { - // TODO: Implement this - CompilationError("FMR."); - } - - // TODO: Set flags -} - -void Compiler::FNABS(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto res_f64 = (Value *)m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::fabs, m_ir_builder->getDoubleTy()), rb_f64); - res_f64 = m_ir_builder->CreateFNeg(res_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FNABS."); - } - - // TODO: Set flags -} - -void Compiler::FABS(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto res_f64 = (Value *)m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::fabs, m_ir_builder->getDoubleTy()), rb_f64); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FABS."); - } - - // TODO: Set flags -} - -void Compiler::FCTID(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto max_i1 = m_ir_builder->CreateFCmpOGT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), 9223372036854775807.0)); - auto min_i1 = m_ir_builder->CreateFCmpULT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), -9223372036854775808.0)); - auto res_i64 = m_ir_builder->CreateFPToSI(rb_f64, m_ir_builder->getInt64Ty()); - res_i64 = m_ir_builder->CreateSelect(max_i1, m_ir_builder->getInt64(0x7FFFFFFFFFFFFFFF), res_i64); - res_i64 = m_ir_builder->CreateSelect(min_i1, m_ir_builder->getInt64(0x8000000000000000), res_i64); - SetFpr(frd, res_i64); - - if (rc) { - // TODO: Implement this - CompilationError("FCTID."); - } - - // TODO: Set flags / Implement rounding modes -} - -void Compiler::FCTIDZ(u32 frd, u32 frb, u32 rc) { - auto rb_f64 = GetFpr(frb); - auto max_i1 = m_ir_builder->CreateFCmpOGT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), 9223372036854775807.0)); - auto min_i1 = m_ir_builder->CreateFCmpULT(rb_f64, ConstantFP::get(m_ir_builder->getDoubleTy(), -9223372036854775808.0)); - auto res_i64 = m_ir_builder->CreateFPToSI(rb_f64, m_ir_builder->getInt64Ty()); - res_i64 = m_ir_builder->CreateSelect(max_i1, m_ir_builder->getInt64(0x7FFFFFFFFFFFFFFF), res_i64); - res_i64 = m_ir_builder->CreateSelect(min_i1, m_ir_builder->getInt64(0x8000000000000000), res_i64); - SetFpr(frd, res_i64); - - if (rc) { - // TODO: Implement this - CompilationError("FCTIDZ."); - } - - // TODO: Set flags -} - -void Compiler::FCFID(u32 frd, u32 frb, u32 rc) { - auto rb_i64 = GetFpr(frb, 64, true); - auto res_f64 = m_ir_builder->CreateSIToFP(rb_i64, m_ir_builder->getDoubleTy()); - SetFpr(frd, res_f64); - - if (rc) { - // TODO: Implement this - CompilationError("FCFID."); - } - - // TODO: Set flags -} - -void Compiler::UNK(const u32 code, const u32 opcode, const u32 gcode) { - CompilationError(fmt::format("Unknown/Illegal opcode! (0x%08x : 0x%x : 0x%x)", code, opcode, gcode)); -} - -std::string Compiler::GetBasicBlockNameFromAddress(u32 address, const std::string & suffix) const { - std::string name; - - if (address == 0) { - name = "entry"; - } - else if (address == 0xFFFFFFFF) { - name = "default_exit"; - } - else { - name = fmt::format("instr_0x%08X", address); - } - - if (suffix != "") { - name += "_" + suffix; - } - - return name; -} - -u32 Compiler::GetAddressFromBasicBlockName(const std::string & name) const { - if (name.compare(0, 6, "instr_") == 0) { - return strtoul(name.c_str() + 6, nullptr, 0); - } - else if (name == GetBasicBlockNameFromAddress(0)) { - return 0; - } - else if (name == GetBasicBlockNameFromAddress(0xFFFFFFFF)) { - return 0xFFFFFFFF; - } - - return 0; -} - -BasicBlock * Compiler::GetBasicBlockFromAddress(u32 address, const std::string & suffix, bool create_if_not_exist) { - auto block_name = GetBasicBlockNameFromAddress(address, suffix); - BasicBlock * block = nullptr; - BasicBlock * next_block = nullptr; - for (auto i = m_state.function->begin(); i != m_state.function->end(); i++) { - if (i->getName() == block_name) { - block = &(*i); - break; - } - - auto block_address = GetAddressFromBasicBlockName(i->getName()); - if (block_address > address) { - next_block = &(*i); - break; - } - } - - if (!block && create_if_not_exist) { - block = BasicBlock::Create(m_ir_builder->getContext(), block_name, m_state.function, next_block); - } - - return block; -} - -Value * Compiler::GetBit(Value * val, u32 n) { - Value * bit = val; - -#ifdef PPU_LLVM_RECOMPILER_USE_BMI - if (val->getType()->isIntegerTy(32)) { - bit = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_bmi_pext_32), val, m_ir_builder->getInt32(1 << (31 - n))); - } - else if (val->getType()->isIntegerTy(64)) { - bit = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_bmi_pext_64), val, m_ir_builder->getInt64((u64)1 << (63 - n))); - } - else { -#endif - if (val->getType()->getIntegerBitWidth() != (n + 1)) { - bit = m_ir_builder->CreateLShr(val, val->getType()->getIntegerBitWidth() - n - 1); - } - - bit = m_ir_builder->CreateAnd(bit, 1); -#ifdef PPU_LLVM_RECOMPILER_USE_BMI - } -#endif - - return bit; -} - -Value * Compiler::ClrBit(Value * val, u32 n) { - return m_ir_builder->CreateAnd(val, ~((u64)1 << (val->getType()->getIntegerBitWidth() - n - 1))); -} - -Value * Compiler::SetBit(Value * val, u32 n, Value * bit, bool doClear) { - if (doClear) { - val = ClrBit(val, n); - } - - if (bit->getType()->getIntegerBitWidth() < val->getType()->getIntegerBitWidth()) { - bit = m_ir_builder->CreateZExt(bit, val->getType()); - } - else if (bit->getType()->getIntegerBitWidth() > val->getType()->getIntegerBitWidth()) { - bit = m_ir_builder->CreateTrunc(bit, val->getType()); - } - - if (val->getType()->getIntegerBitWidth() != (n + 1)) { - bit = m_ir_builder->CreateShl(bit, bit->getType()->getIntegerBitWidth() - n - 1); - } - - return m_ir_builder->CreateOr(val, bit); -} - -Value * Compiler::GetNibble(Value * val, u32 n) { - Value * nibble; - -#ifdef PPU_LLVM_RECOMPILER_USE_BMI - if (val->getType()->isIntegerTy(32)) { - nibble = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_bmi_pext_32), val, m_ir_builder->getInt32((u64)0xF << ((7 - n) * 4))); - } - else if (val->getType()->isIntegerTy(64)) { - nibble = m_ir_builder->CreateCall2(Intrinsic::getDeclaration(m_module, Intrinsic::x86_bmi_pext_64), val, m_ir_builder->getInt64((u64)0xF << ((15 - n) * 4))); - } - else { -#endif - if ((val->getType()->getIntegerBitWidth() >> 2) != (n + 1)) { - val = m_ir_builder->CreateLShr(val, (((val->getType()->getIntegerBitWidth() >> 2) - 1) - n) * 4); - } - - nibble = m_ir_builder->CreateAnd(val, 0xF); -#ifdef PPU_LLVM_RECOMPILER_USE_BMI - } -#endif - - return nibble; -} - -Value * Compiler::ClrNibble(Value * val, u32 n) { - return m_ir_builder->CreateAnd(val, ~((u64)0xF << ((((val->getType()->getIntegerBitWidth() >> 2) - 1) - n) * 4))); -} - -Value * Compiler::SetNibble(Value * val, u32 n, Value * nibble, bool doClear) { - if (doClear) { - val = ClrNibble(val, n); - } - - if (nibble->getType()->getIntegerBitWidth() < val->getType()->getIntegerBitWidth()) { - nibble = m_ir_builder->CreateZExt(nibble, val->getType()); - } - else if (nibble->getType()->getIntegerBitWidth() > val->getType()->getIntegerBitWidth()) { - nibble = m_ir_builder->CreateTrunc(nibble, val->getType()); - } - - if ((val->getType()->getIntegerBitWidth() >> 2) != (n + 1)) { - nibble = m_ir_builder->CreateShl(nibble, (((val->getType()->getIntegerBitWidth() >> 2) - 1) - n) * 4); - } - - return m_ir_builder->CreateOr(val, nibble); -} - -Value * Compiler::SetNibble(Value * val, u32 n, Value * b0, Value * b1, Value * b2, Value * b3, bool doClear) { - if (doClear) { - val = ClrNibble(val, n); - } - - if (b0) { - val = SetBit(val, n * 4, b0, false); - } - - if (b1) { - val = SetBit(val, (n * 4) + 1, b1, false); - } - - if (b2) { - val = SetBit(val, (n * 4) + 2, b2, false); - } - - if (b3) { - val = SetBit(val, (n * 4) + 3, b3, false); - } - - return val; -} - -Value * Compiler::GetPc() { - auto pc_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, PC)); - auto pc_i32_ptr = m_ir_builder->CreateBitCast(pc_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(pc_i32_ptr, 4); -} - -void Compiler::SetPc(Value * val_ix) { - auto pc_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, PC)); - auto pc_i32_ptr = m_ir_builder->CreateBitCast(pc_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - auto val_i32 = m_ir_builder->CreateZExtOrTrunc(val_ix, m_ir_builder->getInt32Ty()); - m_ir_builder->CreateAlignedStore(val_i32, pc_i32_ptr, 4); -} - -Value * Compiler::GetGpr(u32 r, u32 num_bits) { - auto r_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, GPR[r])); - auto r_ix_ptr = m_ir_builder->CreateBitCast(r_i8_ptr, m_ir_builder->getIntNTy(num_bits)->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(r_ix_ptr, 8); -} - -void Compiler::SetGpr(u32 r, Value * val_x64) { - auto r_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, GPR[r])); - auto r_i64_ptr = m_ir_builder->CreateBitCast(r_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - auto val_i64 = m_ir_builder->CreateBitCast(val_x64, m_ir_builder->getInt64Ty()); - m_ir_builder->CreateAlignedStore(val_i64, r_i64_ptr, 8); -} - -Value * Compiler::GetCr() { - auto cr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, CR)); - auto cr_i32_ptr = m_ir_builder->CreateBitCast(cr_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(cr_i32_ptr, 4); -} - -Value * Compiler::GetCrField(u32 n) { - return GetNibble(GetCr(), n); -} - -void Compiler::SetCr(Value * val_x32) { - auto val_i32 = m_ir_builder->CreateBitCast(val_x32, m_ir_builder->getInt32Ty()); - auto cr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, CR)); - auto cr_i32_ptr = m_ir_builder->CreateBitCast(cr_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - m_ir_builder->CreateAlignedStore(val_i32, cr_i32_ptr, 4); -} - -void Compiler::SetCrField(u32 n, Value * field) { - SetCr(SetNibble(GetCr(), n, field)); -} - -void Compiler::SetCrField(u32 n, Value * b0, Value * b1, Value * b2, Value * b3) { - SetCr(SetNibble(GetCr(), n, b0, b1, b2, b3)); -} - -void Compiler::SetCrFieldSignedCmp(u32 n, Value * a, Value * b) { - auto lt_i1 = m_ir_builder->CreateICmpSLT(a, b); - auto gt_i1 = m_ir_builder->CreateICmpSGT(a, b); - auto eq_i1 = m_ir_builder->CreateICmpEQ(a, b); - auto cr_i32 = GetCr(); - cr_i32 = SetNibble(cr_i32, n, lt_i1, gt_i1, eq_i1, GetXerSo()); - SetCr(cr_i32); -} - -void Compiler::SetCrFieldUnsignedCmp(u32 n, Value * a, Value * b) { - auto lt_i1 = m_ir_builder->CreateICmpULT(a, b); - auto gt_i1 = m_ir_builder->CreateICmpUGT(a, b); - auto eq_i1 = m_ir_builder->CreateICmpEQ(a, b); - auto cr_i32 = GetCr(); - cr_i32 = SetNibble(cr_i32, n, lt_i1, gt_i1, eq_i1, GetXerSo()); - SetCr(cr_i32); -} - -void Compiler::SetCr6AfterVectorCompare(u32 vr) { - auto vr_v16i8 = GetVrAsIntVec(vr, 8); - auto vr_mask_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::x86_sse2_pmovmskb_128), vr_v16i8); - auto cmp0_i1 = m_ir_builder->CreateICmpEQ(vr_mask_i32, m_ir_builder->getInt32(0)); - auto cmp1_i1 = m_ir_builder->CreateICmpEQ(vr_mask_i32, m_ir_builder->getInt32(0xFFFF)); - auto cr_i32 = GetCr(); - cr_i32 = SetNibble(cr_i32, 6, cmp1_i1, nullptr, cmp0_i1, nullptr); - SetCr(cr_i32); -} - -Value * Compiler::GetLr() { - auto lr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, LR)); - auto lr_i64_ptr = m_ir_builder->CreateBitCast(lr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(lr_i64_ptr, 8); -} - -void Compiler::SetLr(Value * val_x64) { - auto val_i64 = m_ir_builder->CreateBitCast(val_x64, m_ir_builder->getInt64Ty()); - auto lr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, LR)); - auto lr_i64_ptr = m_ir_builder->CreateBitCast(lr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - m_ir_builder->CreateAlignedStore(val_i64, lr_i64_ptr, 8); -} - -Value * Compiler::GetCtr() { - auto ctr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, CTR)); - auto ctr_i64_ptr = m_ir_builder->CreateBitCast(ctr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(ctr_i64_ptr, 8); -} - -void Compiler::SetCtr(Value * val_x64) { - auto val_i64 = m_ir_builder->CreateBitCast(val_x64, m_ir_builder->getInt64Ty()); - auto ctr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, CTR)); - auto ctr_i64_ptr = m_ir_builder->CreateBitCast(ctr_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - m_ir_builder->CreateAlignedStore(val_i64, ctr_i64_ptr, 8); -} - -Value * Compiler::GetXer() { - auto xer_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, XER)); - auto xer_i64_ptr = m_ir_builder->CreateBitCast(xer_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(xer_i64_ptr, 8); -} - -Value * Compiler::GetXerCa() { - return GetBit(GetXer(), 34); -} - -Value * Compiler::GetXerSo() { - return GetBit(GetXer(), 32); -} - -void Compiler::SetXer(Value * val_x64) { - auto val_i64 = m_ir_builder->CreateBitCast(val_x64, m_ir_builder->getInt64Ty()); - auto xer_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, XER)); - auto xer_i64_ptr = m_ir_builder->CreateBitCast(xer_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - m_ir_builder->CreateAlignedStore(val_i64, xer_i64_ptr, 8); -} - -void Compiler::SetXerCa(Value * ca) { - auto xer_i64 = GetXer(); - xer_i64 = SetBit(xer_i64, 34, ca); - SetXer(xer_i64); -} - -void Compiler::SetXerSo(Value * so) { - auto xer_i64 = GetXer(); - xer_i64 = SetBit(xer_i64, 32, so); - SetXer(xer_i64); -} - -Value * Compiler::GetVrsave() { - auto vrsave_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VRSAVE)); - auto vrsave_i32_ptr = m_ir_builder->CreateBitCast(vrsave_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - auto val_i32 = m_ir_builder->CreateAlignedLoad(vrsave_i32_ptr, 4); - return m_ir_builder->CreateZExtOrTrunc(val_i32, m_ir_builder->getInt64Ty()); -} - -void Compiler::SetVrsave(Value * val_x64) { - auto val_i64 = m_ir_builder->CreateBitCast(val_x64, m_ir_builder->getInt64Ty()); - auto val_i32 = m_ir_builder->CreateZExtOrTrunc(val_i64, m_ir_builder->getInt32Ty()); - auto vrsave_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VRSAVE)); - auto vrsave_i32_ptr = m_ir_builder->CreateBitCast(vrsave_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - m_ir_builder->CreateAlignedStore(val_i32, vrsave_i32_ptr, 8); -} - -Value * Compiler::GetFpscr() { - auto fpscr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, FPSCR)); - auto fpscr_i32_ptr = m_ir_builder->CreateBitCast(fpscr_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(fpscr_i32_ptr, 4); -} - -void Compiler::SetFpscr(Value * val_x32) { - auto val_i32 = m_ir_builder->CreateBitCast(val_x32, m_ir_builder->getInt32Ty()); - auto fpscr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, FPSCR)); - auto fpscr_i32_ptr = m_ir_builder->CreateBitCast(fpscr_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - m_ir_builder->CreateAlignedStore(val_i32, fpscr_i32_ptr, 4); -} - -Value * Compiler::GetFpr(u32 r, u32 bits, bool as_int) { - auto r_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, FPR[r])); - if (!as_int) { - auto r_f64_ptr = m_ir_builder->CreateBitCast(r_i8_ptr, m_ir_builder->getDoubleTy()->getPointerTo()); - auto r_f64 = m_ir_builder->CreateAlignedLoad(r_f64_ptr, 8); - if (bits == 32) { - return m_ir_builder->CreateFPTrunc(r_f64, m_ir_builder->getFloatTy()); - } - else { - return r_f64; - } - } - else { - auto r_i64_ptr = m_ir_builder->CreateBitCast(r_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - auto r_i64 = m_ir_builder->CreateAlignedLoad(r_i64_ptr, 8); - if (bits == 32) { - return m_ir_builder->CreateTrunc(r_i64, m_ir_builder->getInt32Ty()); - } - else { - return r_i64; - } - } -} - -void Compiler::SetFpr(u32 r, Value * val) { - auto r_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, FPR[r])); - auto r_f64_ptr = m_ir_builder->CreateBitCast(r_i8_ptr, m_ir_builder->getDoubleTy()->getPointerTo()); - - Value* val_f64; - if (val->getType()->isDoubleTy() || val->getType()->isIntegerTy(64)) { - val_f64 = m_ir_builder->CreateBitCast(val, m_ir_builder->getDoubleTy()); - } - else if (val->getType()->isFloatTy() || val->getType()->isIntegerTy(32)) { - auto val_f32 = m_ir_builder->CreateBitCast(val, m_ir_builder->getFloatTy()); - val_f64 = m_ir_builder->CreateFPExt(val_f32, m_ir_builder->getDoubleTy()); - } - else { - assert(0); - } - - m_ir_builder->CreateAlignedStore(val_f64, r_f64_ptr, 8); -} - -Value * Compiler::GetVscr() { - auto vscr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VSCR)); - auto vscr_i32_ptr = m_ir_builder->CreateBitCast(vscr_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(vscr_i32_ptr, 4); -} - -void Compiler::SetVscr(Value * val_x32) { - auto val_i32 = m_ir_builder->CreateBitCast(val_x32, m_ir_builder->getInt32Ty()); - auto vscr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VSCR)); - auto vscr_i32_ptr = m_ir_builder->CreateBitCast(vscr_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); - m_ir_builder->CreateAlignedStore(val_i32, vscr_i32_ptr, 4); -} - -Value * Compiler::GetVr(u32 vr) { - auto vr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VPR[vr])); - auto vr_i128_ptr = m_ir_builder->CreateBitCast(vr_i8_ptr, m_ir_builder->getIntNTy(128)->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(vr_i128_ptr, 16); -} - -Value * Compiler::GetVrAsIntVec(u32 vr, u32 vec_elt_num_bits) { - auto vr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VPR[vr])); - auto vr_i128_ptr = m_ir_builder->CreateBitCast(vr_i8_ptr, m_ir_builder->getIntNTy(128)->getPointerTo()); - auto vr_vec_ptr = m_ir_builder->CreateBitCast(vr_i128_ptr, VectorType::get(m_ir_builder->getIntNTy(vec_elt_num_bits), 128 / vec_elt_num_bits)->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(vr_vec_ptr, 16); -} - -Value * Compiler::GetVrAsFloatVec(u32 vr) { - auto vr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VPR[vr])); - auto vr_i128_ptr = m_ir_builder->CreateBitCast(vr_i8_ptr, m_ir_builder->getIntNTy(128)->getPointerTo()); - auto vr_v4f32_ptr = m_ir_builder->CreateBitCast(vr_i128_ptr, VectorType::get(m_ir_builder->getFloatTy(), 4)->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(vr_v4f32_ptr, 16); -} - -Value * Compiler::GetVrAsDoubleVec(u32 vr) { - auto vr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VPR[vr])); - auto vr_i128_ptr = m_ir_builder->CreateBitCast(vr_i8_ptr, m_ir_builder->getIntNTy(128)->getPointerTo()); - auto vr_v2f64_ptr = m_ir_builder->CreateBitCast(vr_i128_ptr, VectorType::get(m_ir_builder->getDoubleTy(), 2)->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(vr_v2f64_ptr, 16); -} - -void Compiler::SetVr(u32 vr, Value * val_x128) { - auto vr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], OFFSET_32(PPUThread, VPR[vr])); - auto vr_i128_ptr = m_ir_builder->CreateBitCast(vr_i8_ptr, m_ir_builder->getIntNTy(128)->getPointerTo()); - auto val_i128 = m_ir_builder->CreateBitCast(val_x128, m_ir_builder->getIntNTy(128)); - m_ir_builder->CreateAlignedStore(val_i128, vr_i128_ptr, 16); -} - -Value * Compiler::CheckBranchCondition(u32 bo, u32 bi) { - bool bo0 = bo & 0x10 ? true : false; - bool bo1 = bo & 0x08 ? true : false; - bool bo2 = bo & 0x04 ? true : false; - bool bo3 = bo & 0x02 ? true : false; - - auto ctr_i64 = GetCtr(); - if (!bo2) { - ctr_i64 = m_ir_builder->CreateSub(ctr_i64, m_ir_builder->getInt64(1)); - SetCtr(ctr_i64); - } - - Value * ctr_ok_i1 = nullptr; - if (!bo2) { - // TODO: Check if we should compare all bits or just the lower 32 bits. This depends on MSR[SF]. Not sure what it is for PS3. - ctr_ok_i1 = m_ir_builder->CreateICmpNE(ctr_i64, m_ir_builder->getInt64(0)); - if (bo3) { - ctr_ok_i1 = m_ir_builder->CreateXor(ctr_ok_i1, m_ir_builder->getInt1(bo3)); - } - } - - Value * cond_ok_i1 = nullptr; - if (!bo0) { - auto cr_bi_i32 = GetBit(GetCr(), bi); - cond_ok_i1 = m_ir_builder->CreateTrunc(cr_bi_i32, m_ir_builder->getInt1Ty()); - if (!bo1) { - cond_ok_i1 = m_ir_builder->CreateXor(cond_ok_i1, m_ir_builder->getInt1(!bo1)); - } - } - - Value * cmp_i1 = nullptr; - if (ctr_ok_i1 && cond_ok_i1) { - cmp_i1 = m_ir_builder->CreateAnd(ctr_ok_i1, cond_ok_i1); - } - else if (ctr_ok_i1) { - cmp_i1 = ctr_ok_i1; - } - else if (cond_ok_i1) { - cmp_i1 = cond_ok_i1; - } - - return cmp_i1; -} - -void Compiler::CreateBranch(llvm::Value * cmp_i1, llvm::Value * target_i32, bool lk, bool target_is_lr) { - if (lk) - SetLr(m_ir_builder->getInt64(m_state.current_instruction_address + 4)); - - BasicBlock *current_block = m_ir_builder->GetInsertBlock(); - - BasicBlock * target_block = nullptr; - if (dyn_cast(target_i32)) { - // Target address is an immediate value. - u32 target_address = (u32)(dyn_cast(target_i32)->getLimitedValue()); - if (lk) { - // Function call - if (cmp_i1) { // There is no need to create a new block for an unconditional jump - target_block = GetBasicBlockFromAddress(m_state.current_instruction_address, "target"); - m_ir_builder->SetInsertPoint(target_block); - } - - SetPc(target_i32); -// Function *fn = m_module->getFunction(fmt::format("function_0x%08X", target_address)); - llvm::Value *execStatus; -// if (fn) -// execStatus = m_ir_builder->CreateCall2(fn, m_state.args[CompileTaskState::Args::State], m_ir_builder->getInt64(0)); -// else - execStatus = Call("execute_unknown_function", m_state.args[CompileTaskState::Args::State], m_ir_builder->getInt64(0)); - - llvm::BasicBlock *cputhreadexitblock = GetBasicBlockFromAddress(m_state.current_instruction_address, "early_exit"); - llvm::Value *isCPUThreadExit = m_ir_builder->CreateICmpEQ(execStatus, m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - llvm::BasicBlock *normal_execution = GetBasicBlockFromAddress(m_state.current_instruction_address, "normal_execution"); - m_ir_builder->CreateCondBr(isCPUThreadExit, cputhreadexitblock, normal_execution); - m_ir_builder->SetInsertPoint(cputhreadexitblock); - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - m_ir_builder->SetInsertPoint(normal_execution); - - m_ir_builder->CreateBr(GetBasicBlockFromAddress(m_state.current_instruction_address + 4)); - } - else { - // Local branch - target_block = GetBasicBlockFromAddress(target_address); - } - } - else { - // Target address is in a register - if (cmp_i1) { // There is no need to create a new block for an unconditional jump - target_block = GetBasicBlockFromAddress(m_state.current_instruction_address, "target"); - m_ir_builder->SetInsertPoint(target_block); - } - - SetPc(target_i32); - if (target_is_lr && !lk) { - // Return from this function - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusReturn)); - } - else if (lk) { - BasicBlock *next_block = GetBasicBlockFromAddress(m_state.current_instruction_address + 4); - - llvm::Value *execStatus = m_ir_builder->CreateCall2(m_execute_unknown_function, m_state.args[CompileTaskState::Args::State], m_ir_builder->getInt64(0)); - - llvm::BasicBlock *cputhreadexitblock = GetBasicBlockFromAddress(m_state.current_instruction_address, "early_exit"); - llvm::Value *isCPUThreadExit = m_ir_builder->CreateICmpEQ(execStatus, m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - llvm::BasicBlock *normal_execution = GetBasicBlockFromAddress(m_state.current_instruction_address, "normal_execution"); - m_ir_builder->CreateCondBr(isCPUThreadExit, cputhreadexitblock, normal_execution); - m_ir_builder->SetInsertPoint(cputhreadexitblock); - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusPropagateException)); - m_ir_builder->SetInsertPoint(normal_execution); - - m_ir_builder->CreateBr(next_block); - } - else { - m_ir_builder->CreateRet(m_ir_builder->getInt32(ExecutionStatus::ExecutionStatusBlockEnded)); - } - } - - if (cmp_i1) { - // Conditional branch - auto next_block = GetBasicBlockFromAddress(m_state.current_instruction_address + 4); - m_ir_builder->SetInsertPoint(current_block); - m_ir_builder->CreateCondBr(cmp_i1, target_block, next_block); - } - else { - // Unconditional branch - if (target_block) { - m_ir_builder->SetInsertPoint(current_block); - m_ir_builder->CreateBr(target_block); - } - } - - m_state.hit_branch_instruction = true; -} - -// FIXME: Find out why alignement is needed -Value * Compiler::ReadMemory(Value * addr_i64, u32 bits, u32 alignment, bool bswap, bool could_be_mmio) { - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFF); - auto eaddr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64((u64)vm::base(0))); - auto eaddr_ix_ptr = m_ir_builder->CreateIntToPtr(eaddr_i64, m_ir_builder->getIntNTy(bits)->getPointerTo()); - auto val_ix = (Value *)m_ir_builder->CreateLoad(eaddr_ix_ptr); - if (bits > 8 && bswap) { - val_ix = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, m_ir_builder->getIntNTy(bits)), val_ix); - } - - return val_ix; -} - -void Compiler::WriteMemory(Value * addr_i64, Value * val_ix, u32 alignment, bool bswap, bool could_be_mmio) { - if (val_ix->getType()->getIntegerBitWidth() > 8 && bswap) { - val_ix = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, val_ix->getType()), val_ix); - } - - addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFF); - auto eaddr_i64 = m_ir_builder->CreateAdd(addr_i64, m_ir_builder->getInt64((u64)vm::base(0))); - auto eaddr_ix_ptr = m_ir_builder->CreateIntToPtr(eaddr_i64, val_ix->getType()->getPointerTo()); - m_ir_builder->CreateAlignedStore(val_ix, eaddr_ix_ptr, alignment); -} - -void Compiler::CompilationError(const std::string & error) { - LOG_ERROR(PPU, "[0x%08X] %s", m_state.current_instruction_address, error.c_str()); - Emu.Pause(); -} - -void Compiler::InitRotateMask() { - for (u32 mb = 0; mb < 64; mb++) { - for (u32 me = 0; me < 64; me++) { - u64 mask = ((u64)-1 >> mb) ^ ((me >= 63) ? 0 : (u64)-1 >> (me + 1)); - s_rotate_mask[mb][me] = mb > me ? ~mask : mask; - } - } -} -#endif diff --git a/rpcs3/Emu/Cell/PPUProgramCompiler.cpp b/rpcs3/Emu/Cell/PPUProgramCompiler.cpp deleted file mode 100644 index 26480c2cdb..0000000000 --- a/rpcs3/Emu/Cell/PPUProgramCompiler.cpp +++ /dev/null @@ -1,1735 +0,0 @@ -#include "stdafx.h" -#include "stdafx_gui.h" -#include "PPUProgramCompiler.h" -/* -using namespace PPU_instr; - -template -InstrBase* GetInstruction(T* list, const std::string& str) -{ - for(int i=0; icount; ++i) - { - auto instr = list->get_instr_info(i); - - if(instr) - { - if(instr->GetName() == str) - { - return instr; - } - } - } - - return nullptr; -} - -template -InstrBase* GetInstruction(const std::string& str) -{ - if(auto res = GetInstruction(main_list, str)) return res; - if(auto res = GetInstruction(g04_list, str)) return res; - if(auto res = GetInstruction(g04_0_list, str)) return res; - if(auto res = GetInstruction(g13_list, str)) return res; - if(auto res = GetInstruction(g1e_list, str)) return res; - if(auto res = GetInstruction(g1f_list, str)) return res; - if(auto res = GetInstruction(g3a_list, str)) return res; - if(auto res = GetInstruction(g3b_list, str)) return res; - if(auto res = GetInstruction(g3e_list, str)) return res; - if(auto res = GetInstruction(g3f_list, str)) return res; - if(auto res = GetInstruction(g3f_0_list, str)) return res; - - return nullptr; -} - -s64 FindOp(const std::string& text, const std::string& op, s64 from) -{ - if (text.length() < op.length()) return -1; - - for (s64 i = from; i < (s64)text.length(); ++i) - { - if(i - 1 < 0 || text[(size_t)i - 1] == '\n' || CompilePPUProgram::IsSkip(text[(size_t)i - 1])) - { - if (text.length() - i < op.length()) return -1; - - if (text.substr(i, op.length()).compare(op) != 0) continue; - if (i + op.length() >= text.length() || text[(size_t) i + op.length()] == '\n' || - CompilePPUProgram::IsSkip(text[(size_t) i + op.length()])) return i; - } - } - - return -1; -} - -std::vector sections_list; -u32 section_name_offs = 0; -u32 section_offs = 0; - -SectionInfo::SectionInfo(const std::string& _name) -{ - name = _name; - memset(&shdr, 0, sizeof(Elf64_Shdr)); - - sections_list.push_back(this); - section_num = sections_list.size() - 1; - - shdr.sh_offset = section_offs; - shdr.sh_name = section_name_offs; - - section_name_offs += name.length() + 1; -} - -void SectionInfo::SetDataSize(u32 size, u32 addralign) -{ - if (addralign) shdr.sh_addralign = addralign; - if (shdr.sh_addralign) size = align(size, shdr.sh_addralign); - - if(!code.empty()) - { - for(u32 i=section_num + 1; ishdr.sh_offset -= code.size(); - } - - section_offs -= code.size(); - } - - code.resize(size); - - section_offs += size; - - for(u32 i=section_num + 1; ishdr.sh_offset += size; - } -} - -SectionInfo::~SectionInfo() -{ - sections_list.erase(sections_list.begin() + section_num); - - for(u32 i=section_num + 1; ishdr.sh_offset -= code.size(); - sections_list[i]->shdr.sh_name -= name.length(); - } - - section_offs -= code.size(); - section_name_offs -= name.length(); -} - -CompilePPUProgram::CompilePPUProgram( - const std::string& asm_, - const std::string& file_path, - wxTextCtrl* asm_list, - wxTextCtrl* hex_list, - wxTextCtrl* err_list, - bool analyze) - : m_asm(asm_) - , m_file_path(file_path) - , m_asm_list(asm_list) - , m_hex_list(hex_list) - , m_err_list(err_list) - , m_analyze(analyze) - , p(0) - , m_error(false) - , m_line(1) - , m_end_args(false) - , m_branch_pos(0) - , m_text_addr(0) -{ -} - -void CompilePPUProgram::WriteHex(const std::string& text) -{ - if(m_hex_list) - { - m_hex_list->WriteText(fmt::FromUTF8(text)); - } -} - -void CompilePPUProgram::WriteError(const std::string& error) -{ - if(m_err_list) - { - m_err_list->WriteText(fmt::FromUTF8(fmt::format("line %lld: %s\n", m_line, error.c_str()))); - } -} - -bool CompilePPUProgram::IsSkip(const char c) { return c == ' ' || c == '\t'; } -bool CompilePPUProgram::IsCommit(const char c) { return c == '#'; } -bool CompilePPUProgram::IsEnd() const { return p >= (s64)m_asm.length(); } -bool CompilePPUProgram::IsEndLn(const char c) const { return c == '\n' || p - 1 >= (s64)m_asm.length(); } - -char CompilePPUProgram::NextChar() { return *m_asm.substr(p++, 1).c_str(); } -void CompilePPUProgram::NextLn() { while( !IsEndLn(NextChar()) ) continue; if(!IsEnd()) m_line++; } -void CompilePPUProgram::EndLn() -{ - NextLn(); - p--; - m_line--; -} - -void CompilePPUProgram::FirstChar() -{ - p = 0; - m_line = 1; - m_branch_pos = 0; -} - -void CompilePPUProgram::PrevArg() -{ - while( --p >= 0 && (IsSkip(m_asm[(size_t)p]) || m_asm[(size_t)p] == ',')); - while( --p >= 0 && !IsSkip(m_asm[(size_t)p]) && !IsEndLn(m_asm[(size_t)p]) ); - if(IsEndLn(m_asm[(size_t)p])) p++; -} - -bool CompilePPUProgram::GetOp(std::string& result) -{ - s64 from = -1; - - for(;;) - { - const char cur_char = NextChar(); - - const bool skip = IsSkip(cur_char); - const bool commit = IsCommit(cur_char); - const bool endln = IsEndLn(cur_char); - - if(endln) p--; - - if(from == -1) - { - if(endln || commit) return false; - if(!skip) from = p - 1; - continue; - } - - if(skip || endln || commit) - { - const s64 to = (endln ? p : p - 1) - from; - result = m_asm.substr(from, to); - - return true; - } - } - - return false; -} - -int CompilePPUProgram::GetArg(std::string& result, bool func) -{ - s64 from = -1; - - for(char cur_char = NextChar(); !m_error; cur_char = NextChar()) - { - const bool skip = IsSkip(cur_char); - const bool commit = IsCommit(cur_char); - const bool endln = IsEndLn(cur_char); - const bool end = cur_char == ',' || (func && cur_char == ']'); - - if(endln) p--; - - if(from == -1) - { - if(endln || commit || end) return 0; - if(!skip) from = p - 1; - continue; - } - - const bool text = m_asm[(size_t)from] == '"'; - const bool end_text = cur_char == '"'; - - if((text ? end_text : (skip || commit || end)) || endln) - { - if(text && p > 2 && m_asm[(size_t)p - 2] == '\\' && (p <= 3 || m_asm[(size_t)p - 3] != '\\')) - { - continue; - } - - if(text && !end_text) - { - WriteError("'\"' not found."); - m_error = true; - } - - const s64 to = ((endln || text) ? p : p - 1) - from; - int ret = 1; - - if(skip || text) - { - for(char cur_char = NextChar(); !m_error; cur_char = NextChar()) - { - const bool skip = IsSkip(cur_char); - const bool commit = IsCommit(cur_char); - const bool endln = IsEndLn(cur_char); - const bool end = cur_char == ',' || (func && cur_char == ']'); - - if(skip) continue; - if(end) break; - - if(commit) - { - EndLn(); - ret = -1; - break; - } - - if(endln) - { - p--; - break; - } - - WriteError(fmt::format("Bad symbol '%c'", cur_char)); - m_error = true; - break; - } - } - - result = m_asm.substr(from, to); - - if(text) - { - for(u32 pos = 0; (s32)(pos = result.find('\\', pos)) != std::string::npos;) - { - if(pos + 1 < result.length() && result[pos + 1] == '\\') - { - pos += 2; - continue; - } - - const char v = result[pos + 1]; - switch(v) - { - case 'n': result = result.substr(0, pos) + '\n' + result.substr(pos + 2, result.length() - (pos + 2)); break; - case 'r': result = result.substr(0, pos) + '\r' + result.substr(pos + 2, result.length() - (pos + 2)); break; - case 't': result = result.substr(0, pos) + '\t' + result.substr(pos + 2, result.length() - (pos + 2)); break; - } - - pos++; - } - } - - return ret; - } - } - - return 0; -} - -bool CompilePPUProgram::CheckEnd(bool show_err) -{ - if(m_error) - { - NextLn(); - return false; - } - - while(true) - { - const char cur_char = NextChar(); - const bool skip = IsSkip(cur_char); - const bool commit = IsCommit(cur_char); - const bool endln = IsEndLn(cur_char); - - if(skip) continue; - - if(commit) - { - NextLn(); - return true; - } - - if(endln) - { - p--; - NextLn(); - return true; - } - - WriteError(fmt::format("Bad symbol '%c'", cur_char)); - NextLn(); - return false; - } - - return false; -} - -void CompilePPUProgram::DetectArgInfo(Arg& arg) -{ - const std::string str = arg.string; - - if(str.empty()) - { - arg.type = ARG_ERR; - return; - } - - if(GetInstruction(str)) - { - arg.type = ARG_INSTR; - return; - } - - if(str.length() > 1) - { - for(const Branch& branch : m_branches) - { - if(str != branch.m_name) - continue; - - arg.type = ARG_BRANCH; - arg.value = GetBranchValue(str); - return; - } - } - - switch((char)str[0]) - { - case 'r': case 'f': case 'v': - { - if(str.length() < 2) - { - arg.type = ARG_ERR; - return; - } - - if(str == "rtoc") - { - arg.type = ARG_REG_R; - arg.value = 2; - return; - } - - for(u32 i=1; i '9') - { - arg.type = ARG_ERR; - return; - } - } - - u32 reg = std::stoul(str.substr(1, str.length() - 1)); - - if(reg >= 32) - { - arg.type = ARG_ERR; - return; - } - - switch(str[0]) - { - case 'r': arg.type = ARG_REG_R; break; - case 'f': arg.type = ARG_REG_F; break; - case 'v': arg.type = ARG_REG_V; break; - default: arg.type = ARG_ERR; break; - } - - arg.value = reg; - } - return; - - case 'c': - if(str.length() > 2 && str[1] == 'r') - { - for(u32 i=2; i '9') - { - arg.type = ARG_ERR; - return; - } - } - - u32 reg; - sscanf(str.c_str(), "cr%d", ®); - - if(reg < 8) - { - arg.type = ARG_REG_CR; - arg.value = reg; - } - else - { - arg.type = ARG_ERR; - } - - return; - } - break; - - case '"': - if(str.length() < 2) - { - arg.type = ARG_ERR; - return; - } - - if(str[str.length() - 1] != '"') - { - arg.type = ARG_ERR; - return; - } - - arg.string = str.substr(1, str.length() - 2); - arg.type = ARG_TXT; - return; - } - - // Hex numbers - if(str.length() > 2 && str.substr(0, 2) == "0x") - { - for(u32 i=2; i= '0' && str[i] <= '9') || - (str[i] >= 'a' && str[i] <= 'f') || - (str[i] >= 'A' && str[i] <= 'F') - ) continue; - - arg.type = ARG_ERR; - return; - } - - arg.type = ARG_NUM16; - arg.value = std::stoul(str, nullptr, 16); - return; - } - - for(u32 i= str[0] == '-' ? 1 : 0; i '9') - { - arg.type = ARG_ERR; - return; - } - } - - arg.type = ARG_NUM; - arg.value = std::stoul(str); -} - -void CompilePPUProgram::LoadArgs() -{ - m_args.clear(); - m_cur_arg = 0; - - std::string str; - while(int r = GetArg(str)) - { - m_args.emplace_back(str); - DetectArgInfo(m_args[m_args.size() -1]); - - if(r == -1) - break; - } - - m_end_args = m_args.size() > 0; -} - -u32 CompilePPUProgram::GetBranchValue(const std::string& branch_name) const -{ - for(const Branch& branch : m_branches) - { - if(branch_name != branch.m_name) - continue; - - if(branch.m_pos >= 0) - return m_text_addr + branch.m_pos * 4; - - return branch.m_addr; - } - - return 0; -} - -bool CompilePPUProgram::SetNextArgType(u32 types, bool show_err) -{ - if(m_error) return false; - - if(m_cur_arg >= m_args.size()) - { - if(show_err) - { - WriteError(fmt::format("%d arg not found", m_cur_arg + 1)); - m_error = true; - } - - return false; - } - - const Arg& arg = m_args[m_cur_arg]; - - if(arg.type & types) - { - m_cur_arg++; - return true; - } - - if(show_err) - { - WriteError(fmt::format("Bad arg '%s'", arg.string.c_str())); - m_error = true; - } - - return false; -} - -bool CompilePPUProgram::SetNextArgBranch(u8 aa, bool show_err) -{ - const u32 pos = m_cur_arg; - const bool ret = SetNextArgType(ARG_BRANCH | ARG_IMM, show_err); - - if(!aa && pos < m_args.size()) - { - switch(m_args[pos].type) - { - case ARG_NUM: - m_args[pos].value += m_text_addr + m_branch_pos * 4; - break; - - case ARG_BRANCH: - m_args[pos].value -= m_text_addr + m_branch_pos * 4; - break; - } - } - - return ret; -} - -bool CompilePPUProgram::IsBranchOp(const std::string& op) -{ - return op.length() > 1 && op[op.length() - 1] == ':'; -} - -bool CompilePPUProgram::IsFuncOp(const std::string& op) -{ - return op.length() >= 1 && op[0] == '['; -} - -CompilePPUProgram::SP_TYPE CompilePPUProgram::GetSpType(const std::string& op) -{ - if (op.compare(".int") == 0) return SP_INT; - if (op.compare(".string") == 0) return SP_STRING; - if (op.compare(".strlen") == 0) return SP_STRLEN; - if (op.compare(".buf") == 0) return SP_BUF; - if (op.compare(".srl") == 0) return SP_SRL; - if (op.compare(".srr") == 0) return SP_SRR; - if (op.compare(".mul") == 0) return SP_MUL; - if (op.compare(".div") == 0) return SP_DIV; - if (op.compare(".add") == 0) return SP_ADD; - if (op.compare(".sub") == 0) return SP_SUB; - if (op.compare(".and") == 0) return SP_AND; - if (op.compare(".or") == 0) return SP_OR; - if (op.compare(".xor") == 0) return SP_XOR; - if (op.compare(".not") == 0) return SP_NOT; - if (op.compare(".nor") == 0) return SP_NOR; - - return SP_ERR; -} - -std::string CompilePPUProgram::GetSpStyle(const SP_TYPE sp) -{ - switch(sp) - { - case SP_INT: - case SP_STRING: - case SP_STRLEN: - case SP_NOT: - return "[dst, src]"; - - case SP_BUF: - return "[dst, size]"; - - case SP_SRL: - case SP_SRR: - case SP_MUL: - case SP_DIV: - case SP_ADD: - case SP_SUB: - case SP_AND: - case SP_OR: - case SP_XOR: - case SP_NOR: - return "[dst, src1, src2]"; - } - - return "error"; -} - -bool CompilePPUProgram::IsSpOp(const std::string& op) -{ - return GetSpType(op) != SP_ERR; -} - -CompilePPUProgram::Branch& CompilePPUProgram::GetBranch(const std::string& name) -{ - for(Branch& branch : m_branches) - { - if(name != branch.m_name) - continue; - - return branch; - } - - return m_branches[0]; -} - -void CompilePPUProgram::SetSp(const std::string& name, u32 addr, bool create) -{ - if(create) - { - m_branches.emplace_back(name, -1, addr); - return; - } - - GetBranch(name); - - for(Branch& branch : m_branches) - { - if(name != branch.m_name) - continue; - - branch.m_addr = addr; - } -} - -void CompilePPUProgram::LoadSp(const std::string& op, Elf64_Shdr& s_opd) -{ - SP_TYPE sp = GetSpType(op); - - std::string test; - if(!GetArg(test) || test[0] != '[') - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("data not found. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - NextLn(); - return; - } - - while(p > 0 && m_asm[(size_t)p] != '[') p--; - p++; - - std::string dst; - if(!GetArg(dst)) - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("dst not found. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - NextLn(); - return; - } - - Arg a_dst(dst); - DetectArgInfo(a_dst); - - Branch* dst_branch = NULL; - - switch(a_dst.type) - { - case ARG_BRANCH: - { - Branch& b = GetBranch(dst); - if(b.m_addr >= 0 && b.m_id < 0 && b.m_pos < 0) dst_branch = &b; - } - break; - - case ARG_ERR: - { - m_branches.emplace_back("", -1, 0); - dst_branch = &m_branches[m_branches.size() - 1]; - } - break; - } - - if(!dst_branch) - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("bad dst type. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - NextLn(); - return; - } - - switch(sp) - { - case SP_INT: - case SP_STRING: - case SP_STRLEN: - case SP_BUF: - case SP_NOT: - { - std::string src1; - if(!GetArg(src1, true)) - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("src not found. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - NextLn(); - return; - } - - Arg a_src1(src1); - DetectArgInfo(a_src1); - - if(sp == SP_STRLEN - ? ~(ARG_TXT | ARG_BRANCH) & a_src1.type - : sp == SP_STRING - ? ~ARG_TXT & a_src1.type - : ~(ARG_IMM | ARG_BRANCH) & a_src1.type) - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("bad src type. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - NextLn(); - return; - } - - if(m_asm[(size_t)p - 1] != ']') - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("']' not found. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - NextLn(); - return; - } - - if(!CheckEnd()) - { - if(m_analyze) WriteHex("error\n"); - return; - } - - if(sp == SP_STRING) - { - src1 = src1.substr(1, src1.length()-2); - bool founded = false; - - for(const SpData& sp_str : m_sp_string) - { - if(src1 != sp_str.m_data) - continue; - - *dst_branch = Branch(dst, -1, sp_str.m_addr); - founded = true; - } - - if(!founded) - { - const u32 addr = s_opd.sh_addr + s_opd.sh_size; - m_sp_string.emplace_back(src1, addr); - s_opd.sh_size += src1.length() + 1; - *dst_branch = Branch(dst, -1, addr); - } - } - else if(sp == SP_STRLEN) - { - switch(a_src1.type) - { - case ARG_TXT: *dst_branch = Branch(dst, -1, src1.length() - 2); break; - case ARG_BRANCH: - { - for(const SpData& sp_str : m_sp_string) - { - if(sp_str.m_addr == a_src1.value) - { - *dst_branch = Branch(dst, -1, sp_str.m_data.length()); - break; - } - } - } - break; - } - } - else - { - switch(sp) - { - case SP_INT: *dst_branch = Branch(dst, -1, a_src1.value); break; - case SP_BUF: - *dst_branch = Branch(dst, -1, s_opd.sh_addr + s_opd.sh_size); - s_opd.sh_size += a_src1.value; - break; - case SP_NOT: *dst_branch = Branch(dst, -1, ~a_src1.value); break; - } - } - } - break; - - case SP_SRL: - case SP_SRR: - case SP_MUL: - case SP_DIV: - case SP_ADD: - case SP_SUB: - case SP_AND: - case SP_OR: - case SP_XOR: - case SP_NOR: - { - std::string src1; - if(!GetArg(src1)) - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("src1 not found. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - NextLn(); - return; - } - - Arg a_src1(src1); - DetectArgInfo(a_src1); - - if(~(ARG_IMM | ARG_BRANCH) & a_src1.type) - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("bad src1 type. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - NextLn(); - return; - } - - std::string src2; - if(!GetArg(src2, true)) - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("src2 not found. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - return; - } - - Arg a_src2(src2); - DetectArgInfo(a_src2); - - if(~(ARG_IMM | ARG_BRANCH) & a_src2.type) - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("bad src2 type. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - NextLn(); - return; - } - - if(m_asm[(size_t)p - 1] != ']') - { - if(m_analyze) WriteHex("error\n"); - WriteError(fmt::format("']' not found. style: %s", GetSpStyle(sp).c_str())); - m_error = true; - NextLn(); - return; - } - - if(!CheckEnd()) - { - if(m_analyze) WriteHex("error\n"); - return; - } - - switch(sp) - { - case SP_SRL: *dst_branch = Branch(dst, -1, a_src1.value << a_src2.value); break; - case SP_SRR: *dst_branch = Branch(dst, -1, a_src1.value >> a_src2.value); break; - case SP_MUL: *dst_branch = Branch(dst, -1, a_src1.value * a_src2.value); break; - case SP_DIV: *dst_branch = Branch(dst, -1, a_src1.value / a_src2.value); break; - case SP_ADD: *dst_branch = Branch(dst, -1, a_src1.value + a_src2.value); break; - case SP_SUB: *dst_branch = Branch(dst, -1, a_src1.value - a_src2.value); break; - case SP_AND: *dst_branch = Branch(dst, -1, a_src1.value & a_src2.value); break; - case SP_OR: *dst_branch = Branch(dst, -1, a_src1.value | a_src2.value); break; - case SP_XOR: *dst_branch = Branch(dst, -1, a_src1.value ^ a_src2.value); break; - case SP_NOR: *dst_branch = Branch(dst, -1, ~(a_src1.value | a_src2.value)); break; - } - } - break; - } - - if(m_analyze) WriteHex("\n"); -} - -void CompilePPUProgram::Compile() -{ - if(m_err_list) - { - m_err_list->Freeze(); - m_err_list->Clear(); - } - - if(m_analyze && m_hex_list) - { - m_hex_list->Freeze(); - m_hex_list->Clear(); - } - - m_code.clear(); - m_branches.clear(); - - u32 text_size = 0; - while(!IsEnd()) - { - std::string op; - if(GetOp(op) && !IsFuncOp(op) && !IsBranchOp(op) && !IsSpOp(op)) - { - text_size += 4; - } - - NextLn(); - } - - Elf64_Ehdr elf_info; - memset(&elf_info, 0, sizeof(Elf64_Ehdr)); - elf_info.e_phentsize = sizeof(Elf64_Phdr); - elf_info.e_shentsize = sizeof(Elf64_Shdr); - elf_info.e_ehsize = sizeof(Elf64_Ehdr); - elf_info.e_phnum = 5; - elf_info.e_shnum = 15; - elf_info.e_shstrndx = elf_info.e_shnum - 1; - elf_info.e_phoff = elf_info.e_ehsize; - u32 section_offset = align(elf_info.e_phoff + elf_info.e_phnum * elf_info.e_phentsize, 0x100); - - static const u32 sceStub_text_block = 8 * 4; - - Elf64_Shdr s_null; - memset(&s_null, 0, sizeof(Elf64_Shdr)); - - std::vector sections_names; - u32 section_name_offset = 1; - - Elf64_Shdr s_text; - memset(&s_text, 0, sizeof(Elf64_Shdr)); - s_text.sh_type = 1; - s_text.sh_offset = section_offset; - s_text.sh_addr = section_offset + 0x10000; - s_text.sh_size = text_size; - s_text.sh_addralign = 4; - s_text.sh_flags = 6; - s_text.sh_name = section_name_offset; - sections_names.push_back(".text"); - section_name_offset += std::string(".text").length() + 1; - section_offset += s_text.sh_size; - - m_text_addr = s_text.sh_addr; - - struct Module - { - std::string m_name; - std::vector m_imports; - - Module(const std::string& name, u32 import) : m_name(name) - { - Add(import); - } - - void Add(u32 import) - { - m_imports.push_back(import); - } - - void Clear() - { - m_name.clear(); - m_imports.clear(); - } - }; - - std::vector modules; - - FirstChar(); - while(!IsEnd()) - { - std::string op; - if(!GetOp(op) || !IsFuncOp(op)) - { - NextLn(); - continue; - } - - while(p > 0 && m_asm[(size_t)p] != '[') p--; - p++; - - std::string module_name, name, id; - - if(!GetArg(module_name)) - { - WriteError("module not found. style: [module, name, id]"); - m_error = true; - NextLn(); - continue; - } - - Arg a_module(module_name); - DetectArgInfo(a_module); - - if(~ARG_ERR & a_module.type) - { - WriteError("bad module type. style: [module, name, id]"); - m_error = true; - NextLn(); - continue; - } - - if(!GetArg(name)) - { - WriteError("name not found. style: [module, name, id]"); - m_error = true; - NextLn(); - continue; - } - - Arg a_name(name); - DetectArgInfo(a_name); - - if(~ARG_ERR & a_name.type) - { - WriteError("bad name type. style: [module, name, id]"); - m_error = true; - NextLn(); - continue; - } - - if(!GetArg(id, true)) - { - WriteError("id not found. style: [module, name, id]"); - m_error = true; - NextLn(); - continue; - } - - Arg a_id(id); - DetectArgInfo(a_id); - - if(~ARG_IMM & a_id.type) - { - WriteError("bad id type. style: [module, name, id]"); - m_error = true; - NextLn(); - continue; - } - - if(m_asm[(size_t)p - 1] != ']') - { - WriteError("']' not found. style: [module, name, id]"); - m_error = true; - NextLn(); - continue; - } - - if(!CheckEnd()) continue; - - m_branches.emplace_back(name, a_id.value, 0); - const u32 import = m_branches.size() - 1; - - bool founded = false; - for(Module& module : modules) - { - if(module.m_name != module_name) - continue; - - founded = true; - module.Add(import); - break; - } - - if(!founded) modules.emplace_back(module_name, import); - } - - u32 imports_count = 0; - - for(const Module& module : modules) - { - imports_count += module.m_imports.size(); - } - - Elf64_Shdr s_sceStub_text; - memset(&s_sceStub_text, 0, sizeof(Elf64_Shdr)); - s_sceStub_text.sh_addralign = 4; - section_offset = align(section_offset, s_sceStub_text.sh_addralign); - s_sceStub_text.sh_type = 1; - s_sceStub_text.sh_offset = section_offset; - s_sceStub_text.sh_addr = section_offset + 0x10000; - s_sceStub_text.sh_name = section_name_offset; - s_sceStub_text.sh_flags = 6; - s_sceStub_text.sh_size = imports_count * sceStub_text_block; - sections_names.push_back(".sceStub.text"); - section_name_offset += std::string(".sceStub.text").length() + 1; - section_offset += s_sceStub_text.sh_size; - - for(const Module& module : modules) - { - u32 pos = 0; - for(const u32& import : module.m_imports) - { - m_branches[import].m_addr = s_sceStub_text.sh_addr + sceStub_text_block * pos; - ++pos; - } - } - - Elf64_Shdr s_lib_stub_top; - memset(&s_lib_stub_top, 0, sizeof(Elf64_Shdr)); - s_lib_stub_top.sh_addralign = 4; - section_offset = align(section_offset, s_lib_stub_top.sh_addralign); - s_lib_stub_top.sh_type = 1; - s_lib_stub_top.sh_name = section_name_offset; - s_lib_stub_top.sh_offset = section_offset; - s_lib_stub_top.sh_addr = section_offset + 0x10000; - s_lib_stub_top.sh_flags = 2; - s_lib_stub_top.sh_size = 4; - sections_names.push_back(".lib.stub.top"); - section_name_offset += std::string(".lib.stub.top").length() + 1; - section_offset += s_lib_stub_top.sh_size; - - Elf64_Shdr s_lib_stub; - memset(&s_lib_stub, 0, sizeof(Elf64_Shdr)); - s_lib_stub.sh_addralign = 4; - s_lib_stub.sh_type = 1; - s_lib_stub.sh_name = section_name_offset; - s_lib_stub.sh_offset = section_offset; - s_lib_stub.sh_addr = section_offset + 0x10000; - s_lib_stub.sh_flags = 2; - s_lib_stub.sh_size = sizeof(sys_stub) * modules.size(); - sections_names.push_back(".lib.stub"); - section_name_offset += std::string(".lib.stub").length() + 1; - section_offset += s_lib_stub.sh_size; - - Elf64_Shdr s_lib_stub_btm; - memset(&s_lib_stub_btm, 0, sizeof(Elf64_Shdr)); - s_lib_stub_btm.sh_addralign = 4; - s_lib_stub_btm.sh_type = 1; - s_lib_stub_btm.sh_name = section_name_offset; - s_lib_stub_btm.sh_offset = section_offset; - s_lib_stub_btm.sh_addr = section_offset + 0x10000; - s_lib_stub_btm.sh_flags = 2; - s_lib_stub_btm.sh_size = 4; - sections_names.push_back(".lib.stub.btm"); - section_name_offset += std::string(".lib.stub.btm").length() + 1; - section_offset += s_lib_stub_btm.sh_size; - - Elf64_Shdr s_rodata_sceFNID; - memset(&s_rodata_sceFNID, 0, sizeof(Elf64_Shdr)); - s_rodata_sceFNID.sh_addralign = 4; - section_offset = align(section_offset, s_rodata_sceFNID.sh_addralign); - s_rodata_sceFNID.sh_type = 1; - s_rodata_sceFNID.sh_name = section_name_offset; - s_rodata_sceFNID.sh_offset = section_offset; - s_rodata_sceFNID.sh_addr = section_offset + 0x10000; - s_rodata_sceFNID.sh_flags = 2; - s_rodata_sceFNID.sh_size = imports_count * 4; - sections_names.push_back(".rodata.sceFNID"); - section_name_offset += std::string(".rodata.sceFNID").length() + 1; - section_offset += s_rodata_sceFNID.sh_size; - - Elf64_Shdr s_rodata_sceResident; - memset(&s_rodata_sceResident, 0, sizeof(Elf64_Shdr)); - s_rodata_sceResident.sh_addralign = 4; - section_offset = align(section_offset, s_rodata_sceResident.sh_addralign); - s_rodata_sceResident.sh_type = 1; - s_rodata_sceResident.sh_name = section_name_offset; - s_rodata_sceResident.sh_offset = section_offset; - s_rodata_sceResident.sh_addr = section_offset + 0x10000; - s_rodata_sceResident.sh_flags = 2; - s_rodata_sceResident.sh_size = 4; - for(const Module& module : modules) - { - s_rodata_sceResident.sh_size += module.m_name.length() + 1; - } - s_rodata_sceResident.sh_size = align(s_rodata_sceResident.sh_size, s_rodata_sceResident.sh_addralign); - sections_names.push_back(".rodata.sceResident"); - section_name_offset += std::string(".rodata.sceResident").length() + 1; - section_offset += s_rodata_sceResident.sh_size; - - Elf64_Shdr s_lib_ent_top; - memset(&s_lib_ent_top, 0, sizeof(Elf64_Shdr)); - s_lib_ent_top.sh_addralign = 4; - section_offset = align(section_offset, s_lib_ent_top.sh_addralign); - s_lib_ent_top.sh_size = 4; - s_lib_ent_top.sh_flags = 2; - s_lib_ent_top.sh_type = 1; - s_lib_ent_top.sh_name = section_name_offset; - s_lib_ent_top.sh_offset = section_offset; - s_lib_ent_top.sh_addr = section_offset + 0x10000; - sections_names.push_back(".lib.ent.top"); - section_name_offset += std::string(".lib.ent.top").length() + 1; - section_offset += s_lib_ent_top.sh_size; - - Elf64_Shdr s_lib_ent_btm; - memset(&s_lib_ent_btm, 0, sizeof(Elf64_Shdr)); - s_lib_ent_btm.sh_addralign = 4; - s_lib_ent_btm.sh_size = 4; - s_lib_ent_btm.sh_flags = 2; - s_lib_ent_btm.sh_type = 1; - s_lib_ent_btm.sh_name = section_name_offset; - s_lib_ent_btm.sh_offset = section_offset; - s_lib_ent_btm.sh_addr = section_offset + 0x10000; - sections_names.push_back(".lib.ent.btm"); - section_name_offset += std::string(".lib.ent.btm").length() + 1; - section_offset += s_lib_ent_btm.sh_size; - - Elf64_Shdr s_sys_proc_prx_param; - memset(&s_sys_proc_prx_param, 0, sizeof(Elf64_Shdr)); - s_sys_proc_prx_param.sh_addralign = 4; - section_offset = align(section_offset, s_sys_proc_prx_param.sh_addralign); - s_sys_proc_prx_param.sh_type = 1; - s_sys_proc_prx_param.sh_size = sizeof(sys_proc_prx_param); - s_sys_proc_prx_param.sh_name = section_name_offset; - s_sys_proc_prx_param.sh_offset = section_offset; - s_sys_proc_prx_param.sh_addr = section_offset + 0x10000; - s_sys_proc_prx_param.sh_flags = 2; - sections_names.push_back(".sys_proc_prx_param"); - section_name_offset += std::string(".sys_proc_prx_param").length() + 1; - section_offset += s_sys_proc_prx_param.sh_size; - - const u32 prog_load_0_end = section_offset; - - section_offset = align(section_offset + 0x10000, 0x10000); - const u32 prog_load_1_start = section_offset; - - Elf64_Shdr s_data_sceFStub; - memset(&s_data_sceFStub, 0, sizeof(Elf64_Shdr)); - s_data_sceFStub.sh_name = section_name_offset; - s_data_sceFStub.sh_addralign = 4; - section_offset = align(section_offset, s_data_sceFStub.sh_addralign); - s_data_sceFStub.sh_flags = 3; - s_data_sceFStub.sh_type = 1; - s_data_sceFStub.sh_offset = section_offset; - s_data_sceFStub.sh_addr = section_offset + 0x10000; - s_data_sceFStub.sh_size = imports_count * 4; - sections_names.push_back(".data.sceFStub"); - section_name_offset += std::string(".data.sceFStub").length() + 1; - section_offset += s_data_sceFStub.sh_size; - - Elf64_Shdr s_tbss; - memset(&s_tbss, 0, sizeof(Elf64_Shdr)); - s_tbss.sh_addralign = 4; - section_offset = align(section_offset, s_tbss.sh_addralign); - s_tbss.sh_size = 4; - s_tbss.sh_flags = 0x403; - s_tbss.sh_type = 8; - s_tbss.sh_name = section_name_offset; - s_tbss.sh_offset = section_offset; - s_tbss.sh_addr = section_offset + 0x10000; - sections_names.push_back(".tbss"); - section_name_offset += std::string(".tbss").length() + 1; - section_offset += s_tbss.sh_size; - - Elf64_Shdr s_opd; - memset(&s_opd, 0, sizeof(Elf64_Shdr)); - s_opd.sh_addralign = 8; - section_offset = align(section_offset, s_opd.sh_addralign); - s_opd.sh_size = 2*4; - s_opd.sh_type = 1; - s_opd.sh_offset = section_offset; - s_opd.sh_addr = section_offset + 0x10000; - s_opd.sh_name = section_name_offset; - s_opd.sh_flags = 3; - sections_names.push_back(".opd"); - section_name_offset += std::string(".opd").length() + 1; - - FirstChar(); - - while(!IsEnd()) - { - std::string op; - if(!GetOp(op) || IsFuncOp(op) || IsSpOp(op)) - { - NextLn(); - continue; - } - - if(IsBranchOp(op)) - { - const std::string& name = op.substr(0, op.length() - 1); - - for(const Branch& branch : m_branches) - { - if(name != branch.m_name) - continue; - - WriteError(fmt::format("'%s' already declared", name.c_str())); - m_error = true; - break; - } - - Arg a_name(name); - DetectArgInfo(a_name); - - if(a_name.type != ARG_ERR) - { - WriteError(fmt::format("bad name '%s'", name.c_str())); - m_error = true; - } - - if(m_error) break; - - m_branches.emplace_back(name, m_branch_pos); - - CheckEnd(); - continue; - } - - m_branch_pos++; - NextLn(); - } - - bool has_entry = false; - for(const Branch& branch : m_branches) - { - if(branch.m_name != "entry") - continue; - - has_entry = true; - break; - } - - if(!has_entry) m_branches.emplace_back("entry", 0); - - if(m_analyze) m_error = false; - FirstChar(); - - while(!IsEnd()) - { - m_args.clear(); - m_end_args = false; - - std::string op; - if(!GetOp(op) || IsBranchOp(op) || IsFuncOp(op)) - { - if(m_analyze) WriteHex("\n"); - NextLn(); - continue; - } - - if(IsSpOp(op)) - { - LoadSp(op, s_opd); - continue; - } - - LoadArgs(); - - auto instr = GetInstruction(op); - if(instr) - { - uint type[] = - { - ARG_IMM, - ARG_REG_R, - ARG_REG_F, - ARG_REG_V, - ARG_REG_CR, - }; - - for(uint i=0; iGetArgCount(); ++i) - { - switch(instr->GetArg(i).m_type) - { - case FIELD_BRANCH: - SetNextArgBranch(0); //TODO - break; - - default: - SetNextArgType(type[instr->GetArg(i).m_type]); - break; - } - } - } - else - { - WriteError(fmt::format("unknown instruction '%s'", op.c_str())); - EndLn(); - m_error = true; - } - - CheckEnd(); - - if(m_error) - { - if(m_analyze) - { - WriteHex("error\n"); - m_error = false; - continue; - } - - break; - } - - u32 code; - - { - std::vector args; - args.resize(m_args.size()); - for(uint i=0; i::make(s_lib_stub_top.sh_addr + s_lib_stub_top.sh_size); - prx_param.libstubend = vm::bptr::make(s_lib_stub_btm.sh_addr); - prx_param.ver = 0x101; - - elf_info.e_entry = s_opd.sh_addr; - - f.Seek(0); - WriteEhdr(f, elf_info); - - f.Seek(elf_info.e_shoff); - WriteShdr(f, s_null); - WriteShdr(f, s_text); - WriteShdr(f, s_opd); - WriteShdr(f, s_sceStub_text); - WriteShdr(f, s_lib_stub_top); - WriteShdr(f, s_lib_stub); - WriteShdr(f, s_lib_stub_btm); - WriteShdr(f, s_data_sceFStub); - WriteShdr(f, s_rodata_sceFNID); - WriteShdr(f, s_rodata_sceResident); - WriteShdr(f, s_sys_proc_prx_param); - WriteShdr(f, s_lib_ent_top); - WriteShdr(f, s_lib_ent_btm); - WriteShdr(f, s_tbss); - WriteShdr(f, s_shstrtab); - - f.Seek(s_text.sh_offset); - for(const u32& code : m_code) - { - Write32(f, code); - } - - f.Seek(s_opd.sh_offset); - f.Write(opd_data, 8); - for(u32 i=0; i> 16)); - Write32(f, LWZ(12, 12, addr)); - Write32(f, STD(2, 1, 40)); - Write32(f, LWZ(0, 12, 0)); - Write32(f, LWZ(2, 12, 4)); - Write32(f, MTSPR(0x009, 0)); - Write32(f, BCCTR(20, 0, 0, 0)); - } - - f.Seek(s_lib_stub_top.sh_offset); - f.Seek(s_lib_stub_top.sh_size, rFromCurrent); - - f.Seek(s_lib_stub.sh_offset); - for(u32 i=0, nameoffs=4, dataoffs=0; i::make(s_rodata_sceResident.sh_addr + nameoffs); - stub.s_nid = vm::bptr::make(s_rodata_sceFNID.sh_addr + dataoffs); - stub.s_text = vm::bptr::make(s_data_sceFStub.sh_addr + dataoffs); - stub.s_imports = modules[i].m_imports.size(); - - dataoffs += modules[i].m_imports.size() * 4; - - f.Write(&stub, sizeof(sys_stub)); - nameoffs += modules[i].m_name.length() + 1; - } - - f.Seek(s_lib_stub_btm.sh_offset); - f.Seek(s_lib_stub_btm.sh_size, rFromCurrent); - - f.Seek(s_data_sceFStub.sh_offset); - for(const Module& module : modules) - { - for(const u32& import : module.m_imports) - { - Write32(f, m_branches[import].m_addr); - } - } - - f.Seek(s_rodata_sceFNID.sh_offset); - for(const Module& module : modules) - { - for(const u32& import : module.m_imports) - { - Write32(f, m_branches[import].m_id); - } - } - - f.Seek(s_rodata_sceResident.sh_offset + 4); - for(u32 i=0; iThaw(); - - if(m_analyze) - { - if(m_hex_list) - { - m_hex_list->Thaw(); - } - } - else - { - //TODO: doesn't look portable - system("make_fself.cmd"); - } -} -*/ \ No newline at end of file diff --git a/rpcs3/Emu/Cell/PPUProgramCompiler.h b/rpcs3/Emu/Cell/PPUProgramCompiler.h deleted file mode 100644 index f7d5a00559..0000000000 --- a/rpcs3/Emu/Cell/PPUProgramCompiler.h +++ /dev/null @@ -1,192 +0,0 @@ -#pragma once -/*#include "PPUInstrTable.h" -#include "Loader/ELF64.h" - -enum ArgType -{ - ARG_ERR = 0, - ARG_NUM = 1 << 0, - ARG_NUM16 = 1 << 1, - ARG_TXT = 1 << 2, - ARG_REG_R = 1 << 3, - ARG_REG_F = 1 << 4, - ARG_REG_V = 1 << 5, - ARG_REG_CR = 1 << 6, - ARG_BRANCH = 1 << 7, - ARG_INSTR = 1 << 8, - ARG_IMM = ARG_NUM | ARG_NUM16 | ARG_BRANCH, -}; - -struct Arg -{ - std::string string; - u32 value; - ArgType type; - - Arg(const std::string& _string, const u32 _value = 0, const ArgType _type = ARG_ERR) - : string(_string) - , value(_value) - , type(_type) - { - } -}; - -struct SectionInfo -{ - Elf64_Shdr shdr; - std::string name; - std::vector code; - u32 section_num; - - SectionInfo(const std::string& name); - ~SectionInfo(); - - void SetDataSize(u32 size, u32 align = 0); -}; - -struct ProgramInfo -{ - std::vector code; - Elf64_Phdr phdr; - bool is_preload; - - ProgramInfo() - { - is_preload = false; - memset(&phdr, 0, sizeof(Elf64_Phdr)); - } -}; - -class CompilePPUProgram -{ - struct Branch - { - std::string m_name; - s32 m_pos; - s32 m_id; - s32 m_addr; - - Branch(const std::string& name, s32 pos) - : m_name(name) - , m_pos(pos) - , m_id(-1) - , m_addr(-1) - { - } - - Branch(const std::string& name, u32 id, u32 addr) - : m_name(name) - , m_pos(-1) - , m_id(id) - , m_addr(addr) - { - } - }; - - bool m_analyze; - s64 p; - u64 m_line; - const std::string& m_asm; - wxTextCtrl* m_asm_list; - wxTextCtrl* m_hex_list; - wxTextCtrl* m_err_list; - bool m_error; - std::vector m_code; - bool m_end_args; - std::vector m_branches; - s32 m_branch_pos; - u32 m_text_addr; - std::string m_file_path; - - struct SpData - { - std::string m_data; - u32 m_addr; - - SpData(const std::string& data, u32 addr) - : m_data(data) - , m_addr(addr) - { - } - }; - - std::vector m_sp_string; - std::vector m_args; - u32 m_cur_arg; - -public: - CompilePPUProgram( - const std::string& asm_, - const std::string& file_path = "", - wxTextCtrl* asm_list = nullptr, - wxTextCtrl* hex_list = nullptr, - wxTextCtrl* err_list = nullptr, - bool analyze = false); - - static bool IsSkip(const char c); - static bool IsCommit(const char c); - -protected: - bool IsEnd() const; - bool IsEndLn(const char c) const; - - void WriteHex(const std::string& text); - void WriteError(const std::string& error); - - char NextChar(); - void NextLn(); - void EndLn(); - - void FirstChar(); - void PrevArg(); - - bool GetOp(std::string& result); - int GetArg(std::string& result, bool func = false); - - bool CheckEnd(bool show_err = true); - - void DetectArgInfo(Arg& arg); - void LoadArgs(); - u32 GetBranchValue(const std::string& branch) const; - - bool SetNextArgType(u32 types, bool show_err = true); - bool SetNextArgBranch(u8 aa, bool show_err = true); - -public: - static bool IsBranchOp(const std::string& op); - static bool IsFuncOp(const std::string& op); - - enum SP_TYPE - { - SP_ERR, - SP_INT, - SP_STRING, - SP_STRLEN, - SP_BUF, - SP_SRL, - SP_SRR, - SP_MUL, - SP_DIV, - SP_ADD, - SP_SUB, - SP_AND, - SP_OR, - SP_XOR, - SP_NOT, - SP_NOR, - }; - - static SP_TYPE GetSpType(const std::string& op); - static std::string GetSpStyle(const SP_TYPE sp); - - static bool IsSpOp(const std::string& op); - -protected: - Branch& GetBranch(const std::string& name); - void SetSp(const std::string& name, u32 addr, bool create); - void LoadSp(const std::string& op, Elf64_Shdr& s_opd); - -public: - void Compile(); -}; -*/ \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Callback.h b/rpcs3/Emu/SysCalls/Callback.h deleted file mode 100644 index cd32f7b21b..0000000000 --- a/rpcs3/Emu/SysCalls/Callback.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -class PPUThread; - -class CallbackManager -{ - using check_cb_t = std::function; - using async_cb_t = std::function; - - std::mutex m_mutex; - - std::queue m_check_cb; - std::queue m_async_cb; - - std::shared_ptr m_cb_thread; - -public: - // Register checked callback - void Register(check_cb_t func); - - // Register async callback, called in callback thread - void Async(async_cb_t func); - - // Get one registered callback - check_cb_t Check(); - - void Init(); - - void Clear(); -}; diff --git a/rpcs3/Emu/SysCalls/FuncList.cpp b/rpcs3/Emu/SysCalls/FuncList.cpp deleted file mode 100644 index 95705cb01e..0000000000 --- a/rpcs3/Emu/SysCalls/FuncList.cpp +++ /dev/null @@ -1,4418 +0,0 @@ -#include "stdafx.h" -#include "Modules.h" -#include "SysCalls.h" - -std::string get_ps3_function_name(u64 fid) -{ - // check syscalls - switch (~fid) - { - case 1: return "sys_process_getpid"; - case 2: return "sys_process_wait_for_child"; - case 3: return "sys_process_exit"; - case 4: return "sys_process_get_status"; - case 5: return "sys_process_detach_child"; - case 12: return "sys_process_get_number_of_object"; - case 13: return "sys_process_get_id"; - case 14: return "sys_process_is_spu_lock_line_reservation_address"; - case 18: return "sys_process_getppid"; - case 19: return "sys_process_kill"; - case 21: return "_sys_process_spawn"; - case 22: return "sys_process_exit"; - case 23: return "sys_process_wait_for_child2"; - case 25: return "sys_process_get_sdk_version"; - case 26: return "_sys_process_exit"; - case 28: return "_sys_process_get_number_of_object"; - case 29: return "sys_process_get_id"; - case 30: return "_sys_process_get_paramsfo"; - case 31: return "sys_process_get_ppu_guid"; - case 41: return "_sys_ppu_thread_exit"; - case 43: return "sys_ppu_thread_yield"; - case 44: return "sys_ppu_thread_join"; - case 45: return "sys_ppu_thread_detach"; - case 46: return "sys_ppu_thread_get_join_state"; - case 47: return "sys_ppu_thread_set_priority"; - case 48: return "sys_ppu_thread_get_priority"; - case 49: return "sys_ppu_thread_get_stack_information"; - case 50: return "sys_ppu_thread_stop"; - case 51: return "sys_ppu_thread_restart"; - case 52: return "_sys_ppu_thread_create"; - case 53: return "sys_ppu_thread_start"; - case 56: return "sys_ppu_thread_rename"; - case 57: return "sys_ppu_thread_recover_page_fault"; - case 58: return "sys_ppu_thread_get_page_fault_context"; - case 60: return "sys_trace_create"; - case 61: return "sys_trace_start"; - case 62: return "sys_trace_stop"; - case 63: return "sys_trace_update_top_index"; - case 64: return "sys_trace_destroy"; - case 65: return "sys_trace_drain"; - case 66: return "sys_trace_attach_process"; - case 67: return "sys_trace_allocate_buffer"; - case 68: return "sys_trace_free_buffer"; - case 69: return "sys_trace_create2"; - case 70: return "sys_timer_create"; - case 71: return "sys_timer_destroy"; - case 72: return "sys_timer_get_information"; - case 73: return "_sys_timer_start"; - case 74: return "sys_timer_stop"; - case 75: return "sys_timer_connect_event_queue"; - case 76: return "sys_timer_disconnect_event_queue"; - case 77: return "sys_trace_create2_in_cbepm"; - case 80: return "sys_interrupt_tag_create"; - case 81: return "sys_interrupt_tag_destroy"; - case 82: return "sys_event_flag_create"; - case 83: return "sys_event_flag_destroy"; - case 84: return "_sys_interrupt_thread_establish"; - case 85: return "sys_event_flag_wait"; - case 86: return "sys_event_flag_trywait"; - case 87: return "sys_event_flag_set"; - case 88: return "sys_interrupt_thread_eoi"; - case 89: return "_sys_interrupt_thread_disestablish"; - case 90: return "sys_semaphore_create"; - case 91: return "sys_semaphore_destroy"; - case 92: return "sys_semaphore_wait"; - case 93: return "sys_semaphore_trywait"; - case 94: return "sys_semaphore_post"; - case 95: return "_sys_lwmutex_create"; - case 96: return "_sys_lwmutex_destroy"; - case 97: return "_sys_lwmutex_lock"; - case 98: return "_sys_lwmutex_unlock"; - case 99: return "_sys_lwmutex_trylock"; - case 100: return "sys_mutex_create"; - case 101: return "sys_mutex_destroy"; - case 102: return "sys_mutex_lock"; - case 103: return "sys_mutex_trylock"; - case 104: return "sys_mutex_unlock"; - case 105: return "sys_cond_create"; - case 106: return "sys_cond_destroy"; - case 107: return "sys_cond_wait"; - case 108: return "sys_cond_signal"; - case 109: return "sys_cond_signal_all"; - case 110: return "sys_cond_signal_to"; - case 111: return "_sys_lwcond_create"; - case 112: return "_sys_lwcond_destroy"; - case 113: return "_sys_lwcond_queue_wait"; - case 114: return "sys_semaphore_get_value"; - case 115: return "_sys_lwcond_signal"; - case 116: return "_sys_lwcond_signal_all"; - case 118: return "sys_event_flag_clear"; - case 120: return "sys_rwlock_create"; - case 121: return "sys_rwlock_destroy"; - case 122: return "sys_rwlock_rlock"; - case 123: return "sys_rwlock_tryrlock"; - case 124: return "sys_rwlock_runlock"; - case 125: return "sys_rwlock_wlock"; - case 126: return "sys_rwlock_trywlock"; - case 127: return "sys_rwlock_wunlock"; - case 128: return "sys_event_queue_create"; - case 129: return "sys_event_queue_destroy"; - case 130: return "sys_event_queue_receive"; - case 131: return "sys_event_queue_tryreceive"; - case 132: return "sys_event_flag_cancel"; - case 133: return "sys_event_queue_drain"; - case 134: return "sys_event_port_create"; - case 135: return "sys_event_port_destroy"; - case 136: return "sys_event_port_connect_local"; - case 137: return "sys_event_port_disconnect"; - case 138: return "sys_event_port_send"; - case 139: return "sys_event_flag_get"; - case 140: return "sys_event_port_connect_ipc"; - case 141: return "sys_timer_usleep"; - case 142: return "sys_timer_sleep"; - case 143: return "sys_time_set_timezone"; - case 144: return "sys_time_get_timezone"; - case 145: return "sys_time_get_current_time"; - case 146: return "sys_time_get_system_time"; - case 147: return "sys_time_get_timebase_frequency"; - case 148: return "_sys_rwlock_trywlock"; - case 150: return "sys_raw_spu_create_interrupt_tag"; - case 151: return "sys_raw_spu_set_int_mask"; - case 152: return "sys_raw_spu_get_int_mask"; - case 153: return "sys_raw_spu_set_int_stat"; - case 154: return "sys_raw_spu_get_int_stat"; - case 155: return "sys_spu_image_get_information?"; - case 156: return "sys_spu_image_open"; - case 157: return "sys_spu_image_import"; - case 158: return "sys_spu_image_close"; - case 159: return "sys_raw_spu_load"; - case 160: return "sys_raw_spu_create"; - case 161: return "sys_raw_spu_destroy"; - case 163: return "sys_raw_spu_read_puint_mb"; - case 165: return "sys_spu_thread_get_exit_status"; - case 166: return "sys_spu_thread_set_argument"; - case 167: return "sys_spu_thread_group_start_on_exit"; - case 169: return "sys_spu_initialize"; - case 170: return "sys_spu_thread_group_create"; - case 171: return "sys_spu_thread_group_destroy"; - case 172: return "sys_spu_thread_initialize"; - case 173: return "sys_spu_thread_group_start"; - case 174: return "sys_spu_thread_group_suspend"; - case 175: return "sys_spu_thread_group_resume"; - case 176: return "sys_spu_thread_group_yield"; - case 177: return "sys_spu_thread_group_terminate"; - case 178: return "sys_spu_thread_group_join"; - case 179: return "sys_spu_thread_group_set_priority"; - case 180: return "sys_spu_thread_group_get_priority"; - case 181: return "sys_spu_thread_write_ls"; - case 182: return "sys_spu_thread_read_ls"; - case 184: return "sys_spu_thread_write_snr"; - case 185: return "sys_spu_thread_group_connect_event"; - case 186: return "sys_spu_thread_group_disconnect_event"; - case 187: return "sys_spu_thread_set_spu_cfg"; - case 188: return "sys_spu_thread_get_spu_cfg"; - case 190: return "sys_spu_thread_write_spu_mb"; - case 191: return "sys_spu_thread_connect_event"; - case 192: return "sys_spu_thread_disconnect_event"; - case 193: return "sys_spu_thread_bind_queue"; - case 194: return "sys_spu_thread_unbind_queue"; - case 196: return "sys_raw_spu_set_spu_cfg"; - case 197: return "sys_raw_spu_get_spu_cfg"; - case 198: return "sys_spu_thread_recover_page_fault"; - case 199: return "sys_raw_spu_recover_page_fault"; - case 215: return "sys_dbg_mat_set_condition"; - case 216: return "sys_dbg_mat_get_condition"; - case 230: return "sys_isolated_spu_create"; - case 231: return "sys_isolated_spu_destroy"; - case 232: return "sys_isolated_spu_start"; - case 233: return "sys_isolated_spu_create_interrupt_tag"; - case 234: return "sys_isolated_spu_set_int_mask"; - case 235: return "sys_isolated_spu_get_int_mask"; - case 236: return "sys_isolated_spu_set_int_stat"; - case 237: return "sys_isolated_spu_get_int_stat"; - case 238: return "sys_isolated_spu_set_spu_cfg"; - case 239: return "sys_isolated_spu_get_spu_cfg"; - case 240: return "sys_isolated_spu_read_puint_mb"; - case 244: return "sys_spu_thread_group_system_set_next_group"; - case 245: return "sys_spu_thread_group_system_unset_next_group"; - case 246: return "sys_spu_thread_group_system_set_switch_group"; - case 247: return "sys_spu_thread_group_system_unset_switch_group"; - case 250: return "sys_spu_thread_group_set_cooperative_victims"; - case 251: return "sys_spu_thread_group_connect_event_all_threads"; - case 252: return "sys_spu_thread_group_disconnect_event_all_threads"; - case 254: return "sys_spu_thread_group_log"; - case 260: return "sys_spu_image_open_by_fd"; - case 300: return "sys_vm_memory_map"; - case 301: return "sys_vm_unmap"; - case 302: return "sys_vm_append_memory"; - case 303: return "sys_vm_return_memory"; - case 304: return "sys_vm_lock"; - case 305: return "sys_vm_unlock"; - case 306: return "sys_vm_touch"; - case 307: return "sys_vm_flush"; - case 308: return "sys_vm_invalidate"; - case 309: return "sys_vm_store"; - case 310: return "sys_vm_sync"; - case 311: return "sys_vm_test"; - case 312: return "sys_vm_get_statistics"; - case 324: return "sys_memory_container_create"; - case 325: return "sys_memory_container_destroy"; - case 326: return "sys_mmapper_allocate_fixed_address"; - case 327: return "sys_mmapper_enable_page_fault_notification"; - case 329: return "sys_mmapper_free_shared_memory"; - case 330: return "sys_mmapper_allocate_address"; - case 331: return "sys_mmapper_free_address"; - case 332: return "sys_mmapper_allocate_shared_memory"; - case 333: return "sys_mmapper_set_shared_memory_flag"; - case 334: return "sys_mmapper_map_shared_memory"; - case 335: return "sys_mmapper_unmap_shared_memory"; - case 336: return "sys_mmapper_change_address_access_right"; - case 337: return "sys_mmapper_search_and_map"; - case 338: return "sys_mmapper_get_shared_memory_attribute"; - case 341: return "sys_memory_container_create"; - case 342: return "sys_memory_container_destroy"; - case 343: return "sys_memory_container_get_size"; - case 344: return "sys_memory_budget_set"; - case 348: return "sys_memory_allocate"; - case 349: return "sys_memory_free"; - case 350: return "sys_memory_allocate_from_container"; - case 351: return "sys_memory_get_page_attribute"; - case 352: return "sys_memory_get_user_memory_size"; - case 353: return "sys_memory_get_user_memory_stat"; - case 356: return "sys_memory_allocate_colored"; - case 361: return "sys_memory_allocate_from_container_colored"; - case 362: return "sys_mmapper_allocate_memory_from_container"; - case 367: return "sys_uart_initialize"; - case 368: return "sys_uart_receive"; - case 369: return "sys_uart_send"; - case 370: return "sys_uart_get_params"; - case 372: return "sys_game_watchdog_start"; - case 373: return "sys_game_watchdog_stop"; - case 374: return "sys_game_watchdog_clear"; - case 375: return "sys_game_set_system_sw_version"; - case 376: return "sys_game_get_system_sw_version"; - case 377: return "sys_sm_set_shop_mode"; - case 378: return "sys_sm_get_ext_event2"; - case 379: return "sys_sm_shutdown"; - case 380: return "sys_sm_get_params"; - case 381: return "sys_sm_get_inter_lpar_parameter"; - case 383: return "sys_game_get_temperature"; - case 384: return "sys_sm_get_tzpb"; - case 385: return "sys_sm_request_led"; - case 386: return "sys_sm_control_led"; - case 387: return "sys_sm_get_platform_info"; - case 388: return "sys_sm_ring_buzzer"; - case 389: return "sys_sm_set_fan_policy"; - case 390: return "sys_sm_request_error_log"; - case 391: return "sys_sm_request_be_count"; - case 392: return "sys_sm_ring_buzzer"; - case 393: return "sys_sm_get_hw_config"; - case 394: return "sys_sm_request_scversion"; - case 395: return "sys_sm_request_system_event_log"; - case 396: return "sys_sm_set_rtc_alarm"; - case 397: return "sys_sm_get_rtc_alarm"; - case 398: return "sys_console_write"; - case 402: return "sys_tty_read"; - case 403: return "sys_tty_write"; - case 408: return "sys_sm_get_tzpb"; - case 409: return "sys_sm_get_fan_policy"; - case 410: return "sys_game_board_storage_read"; - case 411: return "sys_game_board_storage_write"; - case 412: return "sys_game_get_rtc_status"; - case 450: return "sys_overlay_load_module"; - case 451: return "sys_overlay_unload_module"; - case 452: return "sys_overlay_get_module_list"; - case 453: return "sys_overlay_get_module_info"; - case 454: return "sys_overlay_load_module_by_fd"; - case 455: return "sys_overlay_get_module_info2"; - case 456: return "sys_overlay_get_sdk_version"; - case 457: return "sys_overlay_get_module_dbg_info"; - case 458: return "sys_overlay_get_module_dbg_info"; - case 460: return "sys_prx_dbg_get_module_id_list"; - case 461: return "sys_prx_get_module_id_by_address"; - case 463: return "sys_prx_load_module_by_fd"; - case 464: return "sys_prx_load_module_on_memcontainer_by_fd"; - case 465: return "sys_prx_load_module_list"; - case 466: return "sys_prx_load_module_list_on_memcontainer"; - case 467: return "sys_prx_get_ppu_guid"; - case 480: return "sys_prx_load_module"; - case 481: return "sys_prx_start_module"; - case 482: return "sys_prx_stop_module"; - case 483: return "sys_prx_unload_module"; - case 484: return "sys_prx_register_module"; - case 485: return "sys_prx_query_module"; - case 486: return "sys_prx_register_library"; - case 487: return "sys_prx_unregister_library"; - case 488: return "sys_prx_link_library"; - case 489: return "sys_prx_unlink_library"; - case 490: return "sys_prx_query_library"; - case 493: return "sys_prx_dbg_get_module_info"; - case 494: return "sys_prx_get_module_list"; - case 495: return "sys_prx_get_module_info"; - case 496: return "sys_prx_get_module_id_by_name"; - case 497: return "sys_prx_load_module_on_memcontainer"; - case 498: return "sys_prx_start"; - case 499: return "sys_prx_stop"; - case 500: return "sys_hid_manager_open"; - case 501: return "sys_hid_manager_close"; - case 502: return "sys_hid_manager_read"; - case 503: return "sys_hid_manager_ioctl"; - case 504: return "sys_hid_manager_map_logical_id_to_port_id"; - case 505: return "sys_hid_manager_unmap_logical_id_to_port_id"; - case 506: return "sys_hid_manager_add_hot_key_observer"; - case 507: return "sys_hid_manager_remove_hot_key_observer"; - case 508: return "sys_hid_manager_grab_focus"; - case 509: return "sys_hid_manager_release_focus"; - case 516: return "sys_config_open"; - case 517: return "sys_config_close"; - case 518: return "sys_config_get_service_event"; - case 519: return "sys_config_add_service_listener"; - case 520: return "sys_config_remove_service_listener"; - case 521: return "sys_config_register_service"; - case 522: return "sys_config_unregister_service"; - case 523: return "sys_config_io_event"; - case 530: return "sys_usbd_initialize"; - case 531: return "sys_usbd_finalize"; - case 532: return "sys_usbd_get_device_list"; - case 533: return "sys_usbd_get_descriptor_size"; - case 534: return "sys_usbd_get_descriptor"; - case 535: return "sys_usbd_register_ldd"; - case 536: return "sys_usbd_unregister_ldd"; - case 537: return "sys_usbd_open_pipe"; - case 538: return "sys_usbd_open_default_pipe"; - case 539: return "sys_usbd_close_pipe"; - case 540: return "sys_usbd_receive_event"; - case 541: return "sys_usbd_detect_event"; - case 542: return "sys_usbd_attach"; - case 543: return "sys_usbd_transfer_data"; - case 544: return "sys_usbd_isochronous_transfer_data"; - case 545: return "sys_usbd_get_transfer_status"; - case 546: return "sys_usbd_get_isochronous_transfer_status"; - case 547: return "sys_usbd_get_device_location"; - case 548: return "sys_usbd_send_event"; - case 550: return "sys_usbd_allocate_memory"; - case 551: return "sys_usbd_free_memory"; - case 556: return "sys_usbd_get_device_speed"; - case 559: return "sys_usbd_register_extra_ldd"; - case 571: return "sys_pad_ldd_unregister_controller"; - case 572: return "sys_pad_ldd_data_insert"; - case 573: return "sys_pad_dbg_ldd_set_data_insert_mode"; - case 574: return "sys_pad_ldd_register_controller"; - case 575: return "sys_pad_ldd_get_port_no"; - case 577: return "sys_pad_manager_..."; - case 600: return "sys_storage_open"; - case 601: return "sys_storage_close"; - case 602: return "sys_storage_read"; - case 603: return "sys_storage_write"; - case 604: return "sys_storage_send_device_command"; - case 605: return "sys_storage_async_configure"; - case 606: return "sys_storage_async_read"; - case 607: return "sys_storage_async_write"; - case 608: return "sys_storage_async_cancel"; - case 609: return "sys_storage_get_device_info"; - case 610: return "sys_storage_get_device_config"; - case 611: return "sys_storage_report_devices"; - case 612: return "sys_storage_configure_medium_event"; - case 613: return "sys_storage_set_medium_polling_interval"; - case 614: return "sys_storage_create_region"; - case 615: return "sys_storage_delete_region"; - case 616: return "sys_storage_execute_device_command"; - case 617: return "sys_storage_check_region_acl"; - case 618: return "sys_storage_set_region_acl"; - case 619: return "sys_storage_async_send_device_command"; - case 621: return "sys_gamepad_ycon_if"; - case 622: return "sys_storage_get_region_offset"; - case 623: return "sys_storage_set_emulated_speed"; - case 624: return "sys_io_buffer_create"; - case 625: return "sys_io_buffer_destroy"; - case 626: return "sys_io_buffer_allocate"; - case 627: return "sys_io_buffer_free"; - case 630: return "sys_gpio_set"; - case 631: return "sys_gpio_get"; - case 633: return "sys_fsw_connect_event"; - case 634: return "sys_fsw_disconnect_event"; - case 635: return "sys_btsetting_if"; - case 650: return "sys_rsxaudio_initialize"; - case 651: return "sys_rsxaudio_finalize"; - case 652: return "sys_rsxaudio_import_shared_memory"; - case 653: return "sys_rsxaudio_unimport_shared_memory"; - case 654: return "sys_rsxaudio_create_connection"; - case 655: return "sys_rsxaudio_close_connection"; - case 656: return "sys_rsxaudio_prepare_process"; - case 657: return "sys_rsxaudio_start_process"; - case 666: return "sys_rsx_device_open"; - case 667: return "sys_rsx_device_close"; - case 668: return "sys_rsx_memory_allocate"; - case 669: return "sys_rsx_memory_free"; - case 670: return "sys_rsx_context_allocate"; - case 671: return "sys_rsx_context_free"; - case 672: return "sys_rsx_context_iomap"; - case 673: return "sys_rsx_context_iounmap"; - case 674: return "sys_rsx_context_attribute"; - case 675: return "sys_rsx_device_map"; - case 676: return "sys_rsx_device_unmap"; - case 677: return "sys_rsx_attribute"; - case 699: return "sys_bdemu_send_command"; - case 700: return "sys_net_bnet_accept"; - case 701: return "sys_net_bnet_bind"; - case 702: return "sys_net_bnet_connect"; - case 703: return "sys_net_bnet_getpeername"; - case 704: return "sys_net_bnet_getsockname"; - case 705: return "sys_net_bnet_getsockopt"; - case 706: return "sys_net_bnet_listen"; - case 707: return "sys_net_bnet_recvfrom"; - case 708: return "sys_net_bnet_recvmsg"; - case 709: return "sys_net_bnet_sendmsg"; - case 710: return "sys_net_bnet_sendto"; - case 711: return "sys_net_bnet_setsockop"; - case 712: return "sys_net_bnet_shutdown"; - case 713: return "sys_net_bnet_socket"; - case 714: return "sys_net_bnet_close"; - case 715: return "sys_net_bnet_poll"; - case 716: return "sys_net_bnet_select"; - case 717: return "sys_net_open_dump"; - case 718: return "sys_net_read_dump"; - case 719: return "sys_net_close_dump"; - case 720: return "sys_net_write_dump"; - case 721: return "sys_net_abort"; - case 722: return "sys_net_infoctl"; - case 723: return "sys_net_control"; - case 724: return "sys_net_bnet_ioctl"; - case 725: return "sys_net_bnet_sysctl"; - case 726: return "sys_net_eurus_post_command"; - case 800: return "sys_fs_test"; - case 801: return "sys_fs_open"; - case 802: return "sys_fs_read"; - case 803: return "sys_fs_write"; - case 804: return "sys_fs_close"; - case 805: return "sys_fs_opendir"; - case 806: return "sys_fs_readdir"; - case 807: return "sys_fs_closedir"; - case 808: return "sys_fs_stat"; - case 809: return "sys_fs_fstat"; - case 810: return "sys_fs_link"; - case 811: return "sys_fs_mkdir"; - case 812: return "sys_fs_rename"; - case 813: return "sys_fs_rmdir"; - case 814: return "sys_fs_unlink"; - case 815: return "sys_fs_utime"; - case 816: return "sys_fs_access"; - case 817: return "sys_fs_fcntl"; - case 818: return "sys_fs_lseek"; - case 819: return "sys_fs_fdatasync"; - case 820: return "sys_fs_fsync"; - case 821: return "sys_fs_fget_block_size"; - case 822: return "sys_fs_get_block_size"; - case 823: return "sys_fs_acl_read"; - case 824: return "sys_fs_acl_write"; - case 825: return "sys_fs_lsn_get_cda_size"; - case 826: return "sys_fs_lsn_get_cda"; - case 827: return "sys_fs_lsn_lock"; - case 828: return "sys_fs_lsn_unlock"; - case 829: return "sys_fs_lsn_read"; - case 830: return "sys_fs_lsn_write"; - case 831: return "sys_fs_truncate"; - case 832: return "sys_fs_ftruncate"; - case 833: return "sys_fs_symbolic_link"; - case 834: return "sys_fs_chmod"; - case 835: return "sys_fs_chown"; - case 836: return "sys_fs_newfs"; - case 837: return "sys_fs_mount"; - case 838: return "sys_fs_unmount"; - case 839: return "sys_fs_sync"; - case 840: return "sys_fs_disk_free"; - case 841: return "sys_fs_get_mount_info_size"; - case 842: return "sys_fs_get_mount_info"; - case 843: return "sys_fs_get_fs_info_size"; - case 844: return "sys_fs_get_fs_info"; - case 845: return "sys_fs_mapped_allocate"; - case 846: return "sys_fs_mapped_free"; - case 847: return "sys_fs_truncate2"; - case 860: return "sys_ss_get_cache_of_analog_sunset_flag"; - case 865: return "sys_ss_random_number_generator"; - case 870: return "sys_ss_get_console_id"; - case 871: return "sys_ss_access_control_engine"; - case 872: return "sys_ss_get_open_psid"; - case 873: return "sys_ss_get_cache_of_product_mode"; - case 874: return "sys_ss_get_cache_of_flash_ext_flag"; - case 875: return "sys_ss_get_boot_device"; - case 876: return "sys_ss_disc_access_control"; - case 877: return "sys_ss_~utoken_if"; - case 878: return "sys_ss_ad_sign"; - case 879: return "sys_ss_media_id"; - case 880: return "sys_deci3_open"; - case 881: return "sys_deci3_create_event_path"; - case 882: return "sys_deci3_close"; - case 883: return "sys_deci3_send"; - case 884: return "sys_deci3_receive"; - case 885: return "sys_deci3_open2"; - case 890: return "sys_deci3_initialize"; - case 891: return "sys_deci3_terminate"; - case 892: return "sys_deci3_debug_mode"; - case 893: return "sys_deci3_show_status"; - case 894: return "sys_deci3_echo_test"; - case 895: return "sys_deci3_send_dcmp_packet"; - case 896: return "sys_deci3_dump_cp_register"; - case 897: return "sys_deci3_dump_cp_buffer"; - case 899: return "sys_deci3_test"; - case 900: return "sys_dbg_stop_processes"; - case 901: return "sys_dbg_continue_processes"; - case 902: return "sys_dbg_stop_threads"; - case 903: return "sys_dbg_continue_threads"; - case 904: return "sys_dbg_read_process_memory"; - case 905: return "sys_dbg_write_process_memory"; - case 906: return "sys_dbg_read_thread_register"; - case 907: return "sys_dbg_write_thread_register"; - case 908: return "sys_dbg_get_process_list"; - case 909: return "sys_dbg_get_thread_list"; - case 910: return "sys_dbg_get_thread_info"; - case 911: return "sys_dbg_spu_thread_read_from_ls"; - case 912: return "sys_dbg_spu_thread_write_to_ls"; - case 913: return "sys_dbg_kill_process"; - case 914: return "sys_dbg_get_process_info"; - case 915: return "sys_dbg_set_run_control_bit_to_spu"; - case 916: return "sys_dbg_spu_thread_get_exception_cause"; - case 917: return "sys_dbg_create_kernel_event_queue"; - case 918: return "sys_dbg_read_kernel_event_queue"; - case 919: return "sys_dbg_destroy_kernel_event_queue"; - case 920: return "sys_dbg_get_process_event_ctrl_flag"; - case 921: return "sys_dbg_set_process_event_cntl_flag"; - case 922: return "sys_dbg_get_spu_thread_group_event_cntl_flag"; - case 923: return "sys_dbg_set_spu_thread_group_event_cntl_flag"; - case 925: return "sys_dbg_get_raw_spu_list"; - case 932: return "sys_dbg_get_mutex_list"; - case 933: return "sys_dbg_get_mutex_information"; - case 934: return "sys_dbg_get_cond_list"; - case 935: return "sys_dbg_get_cond_information"; - case 936: return "sys_dbg_get_rwlock_list"; - case 937: return "sys_dbg_get_rwlock_information"; - case 938: return "sys_dbg_get_lwmutex_list"; - case 939: return "sys_dbg_get_address_from_dabr"; - case 940: return "sys_dbg_set_address_to_dabr"; - case 941: return "sys_dbg_get_lwmutex_information"; - case 942: return "sys_dbg_get_event_queue_list"; - case 943: return "sys_dbg_get_event_queue_information"; - case 944: return "sys_dbg_initialize_ppu_exception_handler"; - case 945: return "sys_dbg_finalize_ppu_exception_handler"; - case 946: return "sys_dbg_get_semaphore_list"; - case 947: return "sys_dbg_get_semaphore_information"; - case 948: return "sys_dbg_get_kernel_thread_list"; - case 949: return "sys_dbg_get_kernel_thread_info"; - case 950: return "sys_dbg_get_lwcond_list"; - case 951: return "sys_dbg_get_lwcond_information"; - case 952: return "sys_dbg_create_scratch_data_area_ext"; - case 953: return "sys_dbg_vm_get_page_information"; - case 954: return "sys_dbg_vm_get_info"; - case 955: return "sys_dbg_enable_floating_point_enabled_exception"; - case 956: return "sys_dbg_disable_floating_point_enabled_exception"; - case 960: return "sys_dbg_perfomance_monitor"; - case 970: return "sys_dbg_get_event_flag_list"; - case 971: return "sys_dbg_get_event_flag_information"; - case 975: return "sys_dbg_read_spu_thread_context2"; - case 985: return "sys_dbg_get_console_type"; - } - - // check HLE functions - switch (fid) - { - case 0x1529e506: return "cellAdecDecodeAu"; - case 0x487b613e: return "cellAdecStartSeq"; - case 0x7e4a4a49: return "cellAdecQueryAttr"; - case 0x847d2380: return "cellAdecClose"; - case 0x8b5551a4: return "cellAdecOpenEx"; - case 0x97ff2af1: return "cellAdecGetPcm"; - case 0xbd75f78b: return "cellAdecGetPcmItem"; - case 0xd00a6988: return "cellAdecOpen"; - case 0xe2ea549b: return "cellAdecEndSeq"; - case 0x006016da: return "cellAtracGetBitrate"; - case 0x06ddb53e: return "cellAtracSetSecondBuffer"; - case 0x0f9667b6: return "cellAtracGetChannel"; - case 0x2642d4cc: return "cellAtracCreateDecoderExt"; - case 0x2bfff084: return "cellAtracGetStreamDataInfo"; - case 0x46cfc013: return "cellAtracAddStreamData"; - case 0x4797d1ff: return "cellAtracGetNextSample"; - case 0x5f62d546: return "cellAtracGetMaxSample"; - case 0x66afc68e: return "cellAtracSetDataAndGetMemSize"; - case 0x761cb9be: return "cellAtracDeleteDecoder"; - case 0x7772eb2b: return "cellAtracResetPlayPosition"; - case 0x78ba5c41: return "cellAtracSetLoopNum"; - case 0x7b22e672: return "cellAtracGetNextDecodePosition"; - case 0x8eb0e65f: return "cellAtracDecode"; - case 0x99efe171: return "cellAtracIsSecondBufferNeeded"; - case 0x99fb73d1: return "cellAtracGetBufferInfoForResetting"; - case 0xab6b6dbf: return "cellAtracGetLoopInfo"; - case 0xb5c11938: return "cellAtracGetInternalErrorInfo"; - case 0xbe07f05e: return "cellAtracGetSecondBufferInfo"; - case 0xc9a95fcb: return "cellAtracGetVacantSize"; - case 0xcf01d5d4: return "cellAtracGetSoundInfo"; - case 0xdfab73aa: return "cellAtracGetRemainFrame"; - case 0xfa293e88: return "cellAtracCreateDecoder"; - case 0x04af134e: return "cellAudioCreateNotifyEventQueue"; - case 0x0b168f92: return "cellAudioInit"; - case 0x17d1213b: return "cellAudioSendAck"; - case 0x28bc1409: return "cellAudioUnsetPersonalDevice"; - case 0x2b9bd9ad: return "cellAudioRemoveNotifyEventQueueEx"; - case 0x31211f6b: return "cellAudioMiscSetAccessoryVolume"; - case 0x377e0cd9: return "cellAudioSetNotifyEventQueue"; - case 0x4109d08c: return "cellAudioGetPortTimestamp"; - case 0x4129fe2d: return "cellAudioPortClose"; - case 0x5676f81c: return "cellAudioSetPersonalDevice"; - case 0x56dfe179: return "cellAudioSetPortLevel"; - case 0x5b1e2c73: return "cellAudioPortStop"; - case 0x74a66af0: return "cellAudioGetPortConfig"; - case 0x832df17e: return "cellAudioAdd6chData"; - case 0x89be28f2: return "cellAudioPortStart"; - case 0x9e4b1db8: return "cellAudioAdd2chData"; - case 0xa4c9ba65: return "cellAudioCreateNotifyEventQueueEx"; - case 0xb56ef5a1: return "cellAudioSetNotifyEventQueueEx"; - case 0xca5ac370: return "cellAudioQuit"; - case 0xcd7bc431: return "cellAudioPortOpen"; - case 0xdab029aa: return "cellAudioAddData"; - case 0xe4046afe: return "cellAudioGetPortBlockTag"; - case 0xff3626fd: return "cellAudioRemoveNotifyEventQueue"; - case 0x2ab0d183: return "cellBGDLGetInfo2"; - case 0x4e9bb95b: return "cellBGDLGetInfo"; - case 0x74e57bdf: return "cellBGDLGetMode"; - case 0x7e134a90: return "cellBGDLSetMode"; - case 0x02f5ced0: return "cellCameraStop"; - case 0x0e63c444: return "cellCameraGetBufferInfoEx"; - case 0x10697d7f: return "cellCameraGetBufferInfo"; - case 0x21fc151f: return "cellCameraReadEx"; - case 0x2dea3e9b: return "cellCameraSetExtensionUnit"; - case 0x379c5dd6: return "cellCameraClose"; - case 0x3845d39b: return "cellCameraRead"; - case 0x44673f07: return "cellCameraRemoveNotifyEventQueue2"; - case 0x456dc4aa: return "cellCameraStart"; - case 0x532b8aaa: return "cellCameraGetAttribute"; - case 0x58bc5870: return "cellCameraGetType"; - case 0x5ad46570: return "cellCameraEnd"; - case 0x5d25f866: return "cellCameraOpenEx"; - case 0x5eebf24e: return "cellCameraIsStarted"; - case 0x602e2052: return "cellCameraGetDeviceGUID"; - case 0x61dfbe83: return "cellCameraPrepExtensionUnit"; - case 0x7dac520c: return "cellCameraGetBufferSize"; - case 0x7e063bbc: return "cellCameraIsAttached"; - case 0x81f83db9: return "cellCameraReset"; - case 0x85e1b8da: return "cellCameraOpen"; - case 0x8ca53dde: return "cellCameraIsAvailable"; - case 0x8cd56eee: return "cellCameraSetAttribute"; - case 0x9b98d258: return "cellCameraRemoveNotifyEventQueue"; - case 0xa7fd2f5b: return "cellCameraSetNotifyEventQueue2"; - case 0xb0647e5a: return "cellCameraSetNotifyEventQueue"; - case 0xb602e328: return "cellCameraGetExtensionUnit"; - case 0xbf47c5dd: return "cellCameraInit"; - case 0xe28b206b: return "cellCameraReadComplete"; - case 0xeb6f95fb: return "cellCameraCtrlExtensionUnit"; - case 0xfa160f24: return "cellCameraIsOpen"; - case 0x0f6ab57b: return "cellCelp8EncStart"; - case 0x2099f86e: return "cellCelp8EncEncodeFrame"; - case 0x29da1ea6: return "cellCelp8EncWaitForOutput"; - case 0x2d677e0c: return "cellCelp8EncQueryAttr"; - case 0x2eb6efee: return "cellCelp8EncOpen"; - case 0x48c5020d: return "cellCelp8EncGetAu"; - case 0xbbbc2c1c: return "cellCelp8EncEnd"; - case 0xcd48ad62: return "cellCelp8EncOpenEx"; - case 0xfd2566b4: return "cellCelp8EncClose"; - case 0x15ec0cca: return "cellCelpEncClose"; - case 0x3773692f: return "cellCelpEncGetAu"; - case 0x55dc23de: return "cellCelpEncStart"; - case 0x6b148570: return "cellCelpEncQueryAttr"; - case 0x77b3b29a: return "cellCelpEncOpen"; - case 0x81fe030c: return "cellCelpEncEncodeFrame"; - case 0x9b244272: return "cellCelpEncWaitForOutput"; - case 0x9eb084db: return "cellCelpEncOpenEx"; - case 0xf2b85dff: return "cellCelpEncEnd"; - case 0x002e8da2: return "cellDmuxPeekAuEx"; - case 0x02170d1a: return "cellDmuxQueryEsAttr"; - case 0x04e7499f: return "cellDmuxSetStream"; - case 0x05371c8d: return "cellDmuxDisableEs"; - case 0x11bc3a6c: return "cellDmuxOpen2"; - case 0x21d424f0: return "cellDmuxResetEs"; - case 0x24ea6474: return "cellDmuxReleaseAu"; - case 0x2750c5e0: return "cellDmuxPeekAu"; - case 0x2c9a5857: return "cellDmuxGetAuEx"; - case 0x3f76e3cd: return "cellDmuxQueryAttr2"; - case 0x42c716b5: return "cellDmuxGetAu"; - case 0x52911bcf: return "cellDmuxQueryEsAttr2"; - case 0x5d345de9: return "cellDmuxResetStream"; - case 0x68492de9: return "cellDmuxOpen"; - case 0x7b56dc3f: return "cellDmuxEnableEs"; - case 0x8c692521: return "cellDmuxClose"; - case 0xa2d4189b: return "cellDmuxQueryAttr"; - case 0xccff1284: return "cellDmuxResetStreamAndWaitDone"; - case 0xebb3b2bd: return "cellDmuxFlushEs"; - case 0xf6c23560: return "cellDmuxOpenEx"; - case 0x01036193: return "cellFiberPpuContextReturnToThread"; - case 0x081c98be: return "cellFiberPpuContextRunScheduler"; - case 0x0a25b6c8: return "cellFiberPpuContextEnterScheduler"; - case 0x0c44f441: return "cellFiberPpuYield"; - case 0x12b1acf0: return "cellFiberPpuRunFibers"; - case 0x1e7a247a: return "cellFiberPpuUtilWorkerControlRunFibers"; - case 0x31252ec3: return "_cellFiberPpuContextAttributeInitialize"; - case 0x3204b146: return "cellFiberPpuUtilWorkerControlInitialize"; - case 0x34a81091: return "cellFiberPpuContextSelf"; - case 0x3860a12a: return "cellFiberPpuSchedulerTraceFinalize"; - case 0x392c5aa5: return "cellFiberPpuUtilWorkerControlSetPollingMode"; - case 0x3b417f82: return "cellFiberPpuUtilWorkerControlJoinFiber"; - case 0x4fc86b2c: return "cellFiberPpuUtilWorkerControlDisconnectEventQueue"; - case 0x55870804: return "_cellFiberPpuInitialize"; - case 0x5d3992dd: return "cellFiberPpuUtilWorkerControlSendSignal"; - case 0x5d9a7034: return "cellFiberPpuSelf"; - case 0x62a20f0d: return "cellFiberPpuUtilWorkerControlConnectEventQueueToSpurs"; - case 0x68ba4568: return "_cellFiberPpuUtilWorkerControlAttributeInitialize"; - case 0x6c164b3b: return "cellFiberPpuWaitSignal"; - case 0x72086315: return "cellFiberPpuContextInitialize"; - case 0x7c2f4034: return "cellFiberPpuCreateFiber"; - case 0x8afb8356: return "cellFiberPpuSendSignal"; - case 0x8b6baa01: return "cellFiberPpuFinalizeScheduler"; - case 0x9e25c72d: return "_cellFiberPpuSchedulerAttributeInitialize"; - case 0xa27c95ca: return "cellFiberPpuUtilWorkerControlFinalize"; - case 0xa4599cf3: return "cellFiberPpuWaitFlag"; - case 0xa6004249: return "cellFiberPpuJoinFiber"; - case 0xaba1c563: return "cellFiberPpuContextRun"; - case 0xadedbebf: return "cellFiberPpuSchedulerTraceStart"; - case 0xb0594b2d: return "cellFiberPpuGetScheduler"; - case 0xb3a48079: return "cellFiberPpuContextFinalize"; - case 0xb90c871b: return "cellFiberPpuContextCheckStackLimit"; - case 0xbabf714b: return "cellFiberPpuUtilWorkerControlWakeup"; - case 0xbf9cd933: return "cellFiberPpuSchedulerTraceInitialize"; - case 0xbfca88d3: return "cellFiberPpuUtilWorkerControlCreateFiber"; - case 0xc04e2438: return "cellFiberPpuUtilWorkerControlShutdown"; - case 0xc11f8056: return "_cellFiberPpuAttributeInitialize"; - case 0xd0066b17: return "cellFiberPpuContextSwitch"; - case 0xe492a675: return "cellFiberPpuHasRunnableFiber"; - case 0xe665f9a9: return "cellFiberPpuSchedulerTraceStop"; - case 0xea6dc1ad: return "cellFiberPpuUtilWorkerControlCheckFlags"; - case 0xee3b604d: return "cellFiberPpuInitializeScheduler"; - case 0xf2ccad4f: return "cellFiberPpuUtilWorkerControlInitializeWithAttribute"; - case 0xf3e81219: return "cellFiberPpuCheckStackLimit"; - case 0xf6c6900c: return "cellFiberPpuCheckFlags"; - case 0xfa8d5f95: return "cellFiberPpuExit"; - case 0xfbf5fe40: return "cellFiberPpuSetPriority"; - case 0x0109f3d3: return "cellFontGetRenderEffectWeight"; - case 0x03a142b9: return "cellFontGraphicsGetDrawType"; - case 0x042e74e3: return "cellFontCreateRenderer"; - case 0x061049ad: return "cellFontGraphicsSetFontRGBA"; - case 0x06be743d: return "cellFontGetKerning"; - case 0x073fa321: return "cellFontOpenFontsetOnMemory"; - case 0x0a7306a4: return "cellFontOpenFontFile"; - case 0x0baf90fe: return "cellFontGetRenderScaledKerning"; - case 0x0d106a11: return "cellFontGetRenderScalePixel"; - case 0x1387c45c: return "cellFontGetHorizontalLayout"; - case 0x16322df1: return "cellFontGraphicsSetScalePixel"; - case 0x1a218fe4: return "cellFontRenderCharGlyphImageHorizontal"; - case 0x21ebb248: return "cellFontDestroyRenderer"; - case 0x227e1e3c: return "cellFontSetupRenderScalePixel"; - case 0x22e24707: return "cellFontGlyphGetScalePixel"; - case 0x231d5941: return "cellFontGlyphGetHorizontalShift"; - case 0x2388186c: return "cellFontGraphicsGetScalePixel"; - case 0x25253fe4: return "cellFontSetEffectWeight"; - case 0x25dbeff9: return "cellFontGetEffectWeight"; - case 0x285d30d6: return "cellFontGetScalePixel"; - case 0x29329541: return "cellFontOpenFontInstance"; - case 0x297f0e93: return "cellFontSetScalePixel"; - case 0x2da9fd9d: return "cellFontGetRenderCharGlyphMetrics"; - case 0x3da90559: return "cellFontClearFileCache"; - case 0x40d40544: return "cellFontEndLibrary"; - case 0x47ca71ef: return "cellFontAdjustFontScaling"; - case 0x4d19c631: return "cellFontSetupRenderScalePoint"; - case 0x534e785f: return "cellFontGlyphGetVerticalShift"; - case 0x53f529fe: return "cellFontGlyphSetupVertexesGlyph"; - case 0x59ef0073: return "cellFontGetGlyphExpandBufferInfo"; - case 0x5abd8b1e: return "cellFontGetLibrary"; - case 0x66a23100: return "cellFontBindRenderer"; - case 0x698897f8: return "cellFontGetVerticalLayout"; - case 0x6bad7a69: return "cellFontVertexesGlyphRelocate"; - case 0x6bf6f832: return "cellFontSetFontsetOpenMode"; - case 0x6cfada83: return "cellFontSetFontOpenMode"; - case 0x700e6223: return "cellFontGetRenderCharGlyphMetricsVertical"; - case 0x70f3e728: return "cellFontSetScalePoint"; - case 0x78d05e08: return "cellFontSetupRenderEffectSlant"; - case 0x7ab47f7e: return "cellFontEnd"; - case 0x7c5df0d8: return "cellFontGetInitializedRevisionFlags"; - case 0x7c83bc15: return "cellFontGraphicsSetLineRGBA"; - case 0x8657c8f5: return "cellFontSetEffectSlant"; - case 0x87bd650f: return "cellFontGraphicsSetDrawType"; - case 0x88be4799: return "cellFontRenderCharGlyphImage"; - case 0x8a35c887: return "cellFontEndGraphics"; - case 0x8a632038: return "cellFontGetResolutionDpi"; - case 0x8e3f2c40: return "cellFontGlyphRenderImageVertical"; - case 0x90b9465e: return "cellFontRenderSurfaceInit"; - case 0x970d4c22: return "cellFontGraphicsSetupDrawContext"; - case 0x97b95244: return "cellFontGlyphRenderImageHorizontal"; - case 0x98ac5524: return "cellFontGetFontIdCode"; - case 0x9c8d3ff7: return "cellFontGlyphGetOutlineVertexes"; - case 0x9e19072b: return "cellFontOpenFontMemory"; - case 0x9e3b1e16: return "cellFontAdjustGlyphExpandBuffer"; - case 0xa165daae: return "cellFontGetRenderScalePoint"; - case 0xa41342dc: return "cellFontGraphicsGetFontRGBA"; - case 0xa6dc25d1: return "cellFontSetupRenderEffectWeight"; - case 0xa7b2103a: return "cellFontDelete"; - case 0xa885cc9b: return "cellFontOpenFontset"; - case 0xa8fae920: return "cellFontGlyphGetOutlineControlDistance"; - case 0xb015a84e: return "cellFontGetRevisionFlags"; - case 0xb276f1f6: return "cellFontCloseFont"; - case 0xb3d304b2: return "cellFontPatchWorks"; - case 0xb422b005: return "cellFontRenderSurfaceSetScissor"; - case 0xb4d112af: return "cellFontGlyphGetVertexesGlyphSize"; - case 0xc17259de: return "cellFontGenerateCharGlyph"; - case 0xc91c8ece: return "cellFontGetBindingRenderer"; - case 0xcaed32c1: return "cellFontGenerateCharGlyphVertical"; - case 0xced4dda9: return "cellFontGetRenderEffectSlant"; - case 0xd62f5d76: return "cellFontDeleteGlyph"; - case 0xd8eaee9f: return "cellFontGetCharGlyphMetrics"; - case 0xdee0836c: return "cellFontExtend"; - case 0xe01b199e: return "cellFontGlyphRenderImage"; - case 0xe16e679a: return "cellFontGetEffectSlant"; - case 0xe857a0ca: return "cellFontRenderCharGlyphImageVertical"; - case 0xf03dcc29: return "cellFontInitializeWithRevision"; - case 0xf16379fa: return "cellFontUnbindRenderer"; - case 0xf7a19060: return "cellFontGetScalePoint"; - case 0xf7aaa8e2: return "cellFontGraphicsGetLineRGBA"; - case 0xfb3341ba: return "cellFontSetResolutionDpi"; - case 0xfe9a6dd7: return "cellFontGetCharGlyphMetricsVertical"; - case 0x7a0a83c4: return "cellFontInitLibraryFreeTypeWithRevision"; - case 0xec89a187: return "cellFontFTGetRevisionFlags"; - case 0xfa0c2de0: return "cellFontFTGetInitializedRevisionFlags"; - case 0x2a8e6b92: return "cellGameGetDiscContentInfoUpdatePath"; - case 0x3a5d726a: return "cellGameGetParamString"; - case 0x42a2e133: return "cellGameCreateGameData"; - case 0x70acec67: return "cellGameContentPermit"; - case 0x87406734: return "cellGameThemeInstallFromBuffer"; - case 0xa80bf223: return "cellGameGetLocalWebContentPath"; - case 0xb0a1f8c6: return "cellGameContentErrorDialog"; - case 0xb367c6e3: return "cellGameDeleteGameData"; - case 0xb7a45caf: return "cellGameGetParamInt"; - case 0xce4374f6: return "cellGamePatchCheck"; - case 0xd24e3928: return "cellGameThemeInstall"; - case 0xdaa5cd20: return "cellGameSetParamString"; - case 0xdb9819f3: return "cellGameDataCheck"; - case 0xef9d42d5: return "cellGameGetSizeKB"; - case 0xf52639ea: return "cellGameBootCheck"; - case 0x38579ec9: return "cellGameSetExitParam"; - case 0x59b1ede1: return "cellGameGetHomeDataExportPath"; - case 0x59bbebd4: return "cellGameGetHomePath"; - case 0x72cc6cf7: return "cellGameGetHomeDataImportPath"; - case 0x94e9f81d: return "cellGameGetHomeLaunchOptionPath"; - case 0xf6acd0bc: return "cellGameGetBootGameInfo"; - case 0x055bd74d: return "cellGcmGetTiledPitchSize"; - case 0x06edea9e: return "cellGcmSetUserHandler"; - case 0x0a862772: return "cellGcmSetQueueHandler"; - case 0x0b4b62d5: return "cellGcmSetPrepareFlip"; - case 0x0e6b0dae: return "cellGcmGetDisplayInfo"; - case 0x107bf3a1: return "cellGcmInitCursor"; - case 0x15bae46b: return "_cellGcmInitBody"; - case 0x172c3197: return "cellGcmSetDefaultCommandBufferAndSegmentWordSize"; - case 0x1a0de550: return "cellGcmSetCursorPosition"; - case 0x1bd633f8: return "_cellGcmFunc3"; - case 0x1f61b3ff: return "cellGcmDumpGraphicsError"; - case 0x21397818: return "_cellGcmSetFlipCommand"; - case 0x21ac3697: return "cellGcmAddressToOffset"; - case 0x21cee035: return "cellGcmGetNotifyDataAddress"; - case 0x23ae55a3: return "cellGcmGetLastSecondVTime"; - case 0x25b40ab4: return "cellGcmSortRemapEaIoAddress"; - case 0x2922aed0: return "cellGcmGetOffsetTable"; - case 0x2a6fba9c: return "cellGcmIoOffsetToAddress"; - case 0x2ad4951b: return "cellGcmGetTimeStampLocation"; - case 0x371674cf: return "cellGcmGetDisplayBufferByFlipIndex"; - case 0x3a33c1fd: return "_cellGcmFunc15"; - case 0x3b9bd5bd: return "cellGcmUnreserveIoMapSize"; - case 0x4524cccd: return "cellGcmBindTile"; - case 0x4ae8d215: return "cellGcmSetFlipMode"; - case 0x4d7ce993: return "cellGcmSetSecondVFrequency"; - case 0x51c9d62b: return "cellGcmSetDebugOutputLevel"; - case 0x527c6439: return "cellGcmTerminate"; - case 0x5a41c10f: return "cellGcmGetTimeStamp"; - case 0x5e2ee0f0: return "cellGcmGetDefaultCommandWordSize"; - case 0x5f909b17: return "_cellGcmFunc1"; - case 0x626e8518: return "cellGcmMapEaIoAddressWithFlags"; - case 0x63387071: return "cellGcmGetLastFlipTime"; - case 0x63441cb4: return "cellGcmMapEaIoAddress"; - case 0x657571f7: return "cellGcmGetTileInfo"; - case 0x661fe266: return "_cellGcmFunc12"; - case 0x688b8ac9: return "_cellGcmFunc38"; - case 0x69c6cc82: return "cellGcmSetCursorDisable"; - case 0x723bbc7e: return "cellGcmGetVBlankCount"; - case 0x72a577ce: return "cellGcmGetFlipStatus"; - case 0x7fc034bc: return "_cellGcmFunc4"; - case 0x8572bce2: return "cellGcmGetReportDataAddressLocation"; - case 0x8bde5ebf: return "cellGcmSetUserCommand"; - case 0x8cdf8c70: return "cellGcmGetDefaultSegmentWordSize"; - case 0x8effb7fd: return "_cellGcmFunc2"; - case 0x93806525: return "cellGcmGetCurrentDisplayBufferId"; - case 0x983fb9aa: return "cellGcmSetWaitFlip"; - case 0x99d397ac: return "cellGcmGetReport"; - case 0x9a0159af: return "cellGcmGetReportDataAddress"; - case 0x9ba451e4: return "cellGcmSetDefaultFifoSize"; - case 0x9dc04436: return "cellGcmBindZcull"; - case 0xa114ec67: return "cellGcmMapMainMemory"; - case 0xa41ef7e8: return "cellGcmSetFlipHandler"; - case 0xa47c09ff: return "cellGcmSetFlipStatus"; - case 0xa53d12ae: return "cellGcmSetDisplayBuffer"; - case 0xa547adde: return "cellGcmGetControlRegister"; - case 0xa6b180ac: return "cellGcmGetReportDataLocation"; - case 0xa75640e8: return "cellGcmUnbindZcull"; - case 0xa7ede268: return "cellGcmReserveIoMapSize"; - case 0xa91b0402: return "cellGcmSetVBlankHandler"; - case 0xacee8542: return "cellGcmSetFlipImmediate"; - case 0xb2e761d4: return "cellGcmResetFlipStatus"; - case 0xbb42a9dd: return "_cellGcmFunc13"; - case 0xbc982946: return "cellGcmSetDefaultCommandBuffer"; - case 0xbd100dbc: return "cellGcmSetTileInfo"; - case 0xbd2fa0a7: return "cellGcmUpdateCursor"; - case 0xbd6d60d9: return "cellGcmSetInvalidateTile"; - case 0xc47d0812: return "cellGcmSetCursorEnable"; - case 0xc8f3bd09: return "cellGcmGetCurrentField"; - case 0xcaabd992: return "cellGcmInitDefaultFifoMode"; - case 0xd01b570d: return "cellGcmSetGraphicsHandler"; - case 0xd0b1d189: return "cellGcmSetTile"; - case 0xd34a420d: return "cellGcmSetZcull"; - case 0xd8f88e1a: return "_cellGcmSetFlipCommandWithWaitLabel"; - case 0xd9a0a879: return "cellGcmGetZcullInfo"; - case 0xd9b7653e: return "cellGcmUnbindTile"; - case 0xdb23e867: return "cellGcmUnmapIoAddress"; - case 0xdb769b32: return "cellGcmMapLocalMemory"; - case 0xdc09357e: return "cellGcmSetFlip"; - case 0xdc494430: return "cellGcmSetSecondVHandler"; - case 0xdf6476bd: return "cellGcmSetWaitFlipUnsafe"; - case 0xe315a0b2: return "cellGcmGetConfiguration"; - case 0xe44874f3: return "cellGcmSysGetLastVBlankTime"; - case 0xefd00f54: return "cellGcmUnmapEaIoAddress"; - case 0xf80196c1: return "cellGcmGetLabelAddress"; - case 0xf9bfdc72: return "cellGcmSetCursorImageOffset"; - case 0xfb81c03e: return "cellGcmGetMaxIoMapSize"; - case 0xfce9e764: return "cellGcmInitSystemMode"; - case 0xffe0160e: return "cellGcmSetVBlankFrequency"; - case 0x02e7e03e: return "cellGifDecExtDecodeData"; - case 0x116a7da9: return "cellGifDecClose"; - case 0x17fb83c1: return "cellGifDecExtOpen"; - case 0x41a90dc4: return "cellGifDecSetParameter"; - case 0x44b1bc61: return "cellGifDecDecodeData"; - case 0x4711cb7f: return "cellGifDecExtCreate"; - case 0x75745079: return "cellGifDecOpen"; - case 0x95cae771: return "cellGifDecExtSetParameter"; - case 0xb60d42a5: return "cellGifDecCreate"; - case 0xe53f91f2: return "cellGifDecExtReadHeader"; - case 0xe74b2cb1: return "cellGifDecDestroy"; - case 0xf0da95de: return "cellGifDecReadHeader"; - case 0x052a80d9: return "cellHttpCreateTransaction"; - case 0x070f1020: return "cellHttpClientGetTotalPoolSize"; - case 0x0b9fea5f: return "cellHttpRequestGetHeader"; - case 0x0d846d63: return "cellHttpCookieImportWithClientId"; - case 0x0d896b97: return "cellHttpSetProxy"; - case 0x0d9c65be: return "cellHttpClientGetAllHeaders"; - case 0x0ef17399: return "cellHttpTransactionGetUri"; - case 0x10d0d7fc: return "cellHttpResponseGetStatusCode"; - case 0x130150ea: return "cellHttpClientGetRecvBufferSize"; - case 0x1395d8d1: return "cellHttpClientSetSslCallback"; - case 0x13fe767b: return "cellHttpClientSetCookieRecvCallback"; - case 0x14bfc765: return "cellHttpClientGetConnTimeout"; - case 0x16214411: return "cellHttpRequestDeleteHeader"; - case 0x1b5bdcc6: return "cellHttpAddCookieWithClientId"; - case 0x2033b878: return "cellHttpClientCloseAllConnections"; - case 0x211d8ba3: return "cellHttpClientSetAutoRedirect"; - case 0x224e1610: return "cellHttpClientSetRecvTimeout"; - case 0x250c386c: return "cellHttpInit"; - case 0x271a0b06: return "cellHttpClientGetSendTimeout"; - case 0x27f86d70: return "cellHttpClientCloseConnections"; - case 0x2960e309: return "cellHttpClientGetAutoRedirect"; - case 0x296a46cf: return "cellHttpClientSetPipeline"; - case 0x2a1f28f6: return "cellHttpClientGetPipeline"; - case 0x2a78ff04: return "cellHttpTransactionGetSslId"; - case 0x2a87603a: return "cellHttpGetProxy"; - case 0x2d52848b: return "cellHttpTransactionAbortConnection"; - case 0x32f5cae2: return "cellHttpDestroyTransaction"; - case 0x34061e49: return "cellHttpTransactionGetSslCipherId"; - case 0x38954133: return "cellHttpTransactionGetSslCipherBits"; - case 0x40547d8b: return "cellHttpClientSetVersion"; - case 0x4137a1f6: return "cellHttpRequestGetChunkedTransferStatus"; - case 0x42205fe0: return "cellHttpRequestGetAllHeaders"; - case 0x434419c8: return "cellHttpClientSetCookieStatus"; - case 0x464ff889: return "cellHttpResponseGetContentLength"; - case 0x46bcc9ff: return "cellHttpClientGetPerHostKeepAliveMax"; - case 0x473cd9f1: return "cellHttpClientSetRedirectCallback"; - case 0x4b33942a: return "cellHttpClientAddHeader"; - case 0x4d40cf98: return "cellHttpClientGetProxy"; - case 0x4d915204: return "cellHttpClientSetCookieSendCallback"; - case 0x4e4ee53a: return "cellHttpCreateClient"; - case 0x4f5d8d20: return "cellHttpResponseGetHeader"; - case 0x522180bc: return "cellHttpsInit"; - case 0x54f2a4de: return "cellHttpRequestSetHeader"; - case 0x591c21a8: return "cellHttpClientGetKeepAlive"; - case 0x595adee9: return "cellHttpClientSetPerHostKeepAliveMax"; - case 0x5980a293: return "cellHttpClientGetAutoAuthentication"; - case 0x5d473170: return "cellHttpClientSetKeepAlive"; - case 0x617eec02: return "cellHttpClientDeleteHeader"; - case 0x61b2bade: return "cellHttpEndCookie"; - case 0x61c90691: return "cellHttpRecvResponse"; - case 0x65691795: return "cellHttpClientSetSslVersion"; - case 0x660d42a9: return "cellHttpClientSetAuthenticationCallback"; - case 0x6884cdb7: return "cellHttpClientGetResponseBufferMax"; - case 0x6a81b5e4: return "cellHttpResponseGetStatusLine"; - case 0x6eed4999: return "cellHttpClientSetAuthenticationCacheStatus"; - case 0x71714cdc: return "cellHttpClientSetSendTimeout"; - case 0x7313c78d: return "cellHttpClientSetSslIdDestroyCallback"; - case 0x895c604c: return "cellHttpTransactionGetSslCipherName"; - case 0x8aa5fcd3: return "cellHttpClientSetTotalPoolSize"; - case 0x8e3f7ee1: return "cellHttpRequestSetChunkedTransferStatus"; - case 0x8eaf47a3: return "cellHttpClientSetAutoAuthentication"; - case 0x93e938e5: return "cellHttpTransactionGetSslCipherVersion"; - case 0x958323cf: return "cellHttpRequestGetContentLength"; - case 0x9638f766: return "cellHttpInitCookie"; - case 0x980855ac: return "cellHttpDestroyClient"; - case 0xa0d9223c: return "cellHttpTransactionCloseConnection"; - case 0xa34c4b6f: return "cellHttpClientSetHeader"; - case 0xa755b005: return "cellHttpSendRequest"; - case 0xab1c55ab: return "cellHttpClientSetPerHostPoolSize"; - case 0xad1c6f02: return "cellHttpTransactionGetSslVersion"; - case 0xad6a2e5b: return "cellHttpSessionCookieFlush"; - case 0xadc0a4b2: return "cellHttpClientPollConnections"; - case 0xadd66b5c: return "cellHttpClientSetResponseBufferMax"; - case 0xaf73a64e: return "cellHttpRequestSetContentLength"; - case 0xb6feb84b: return "cellHttpClientSetTransactionStateCallback"; - case 0xba78e51f: return "cellHttpClientGetRecvTimeout"; - case 0xbea17389: return "cellHttpResponseGetAllHeaders"; - case 0xbf6e3659: return "cellHttpClientSetRecvBufferSize"; - case 0xcac9fc34: return "cellHttpClientSetUserAgent"; - case 0xccf57336: return "cellHttpClientGetSslVersion"; - case 0xd06c90a4: return "cellHttpClientGetPerPipelineMax"; - case 0xd1ec0b25: return "cellHttpClientGetHeader"; - case 0xd276ff1f: return "cellHttpEnd"; - case 0xd47cc666: return "cellHttpTransactionReleaseConnection"; - case 0xd7471088: return "cellHttpClientSetConnTimeout"; - case 0xd7d3cd5d: return "cellHttpClientSetProxy"; - case 0xd8352a40: return "cellHttpClientSetSslClientCertificate"; - case 0xdc405507: return "cellHttpClientGetVersion"; - case 0xdc7ed599: return "cellHttpClientSetPerPipelineMax"; - case 0xe3c424b3: return "cellHttpTransactionGetSslCipherString"; - case 0xe6d4202f: return "cellHttpsEnd"; - case 0xeb9c1e5e: return "cellHttpClientGetCookieStatus"; - case 0xed993147: return "cellHttpRequestAddHeader"; - case 0xee05b0c1: return "cellHttpClientGetUserAgent"; - case 0xf972c733: return "cellHttpCookieExportWithClientId"; - case 0xfce39343: return "cellHttpClientGetAuthenticationCacheStatus"; - case 0xffc74003: return "cellHttpClientGetPerHostPoolSize"; - case 0x04accebf: return "cellHttpUtilBuildHeader"; - case 0x1c6e4dbb: return "cellHttpUtilBuildRequestLine"; - case 0x2763fd66: return "cellHttpUtilUnescapeUri"; - case 0x2bcbced4: return "cellHttpUtilParseStatusLine"; - case 0x32faaf58: return "cellHttpUtilParseUri"; - case 0x37bb53a2: return "cellHttpUtilAppendHeaderValue"; - case 0x44d756d6: return "cellHttpUtilFormUrlEncode"; - case 0x50ea75bc: return "cellHttpUtilCopyStatusLine"; - case 0x6f0f7667: return "cellHttpUtilBuildUri"; - case 0x83faa354: return "cellHttpUtilBase64Encoder"; - case 0x8bb608e4: return "cellHttpUtilParseUriPath"; - case 0x8e52ee08: return "cellHttpUtilBase64Decoder"; - case 0x8e6c5bb9: return "cellHttpUtilFormUrlDecode"; - case 0x8ea23deb: return "cellHttpUtilMergeUriPath"; - case 0x9003b1f2: return "cellHttpUtilEscapeUri"; - case 0x97f9fbe5: return "cellHttpUtilCopyHeader"; - case 0xa3457869: return "cellHttpUtilParseProxy"; - case 0xaabeb869: return "cellHttpUtilSweepPath"; - case 0xe1fb0ebd: return "cellHttpUtilParseHeader"; - case 0xf05df789: return "cellHttpUtilCopyUri"; - case 0x0e363ae7: return "cellImeJpGetFocusTop"; - case 0x177bd218: return "cellImeJpGetCandidateSelect"; - case 0x1986f2cd: return "cellImeJpGetPredictList"; - case 0x1b119958: return "cellImeJpOpen3"; - case 0x1e29103b: return "cellImeJpConvertForward"; - case 0x1e411261: return "cellImeJpMoveFocusClause"; - case 0x24e9d8fc: return "cellImeJpSetKanaInputMode"; - case 0x36d38701: return "cellImeJpReset"; - case 0x37961cc1: return "cellImeJpExtendConvertArea"; - case 0x441a1c2b: return "cellImeJpEnterString"; - case 0x44608862: return "cellImeJpOpen"; - case 0x46d1234a: return "cellImeJpClose"; - case 0x47b43dd4: return "cellImeJpOpen2"; - case 0x5b6ada55: return "cellImeJpEnterCharExt"; - case 0x5f5b3227: return "cellImeJpGetFocusLength"; - case 0x6298b55a: return "cellImeJpEnterStringExt"; - case 0x6319eda3: return "cellImeJpAllDeleteConvertString"; - case 0x66c6cc78: return "cellImeJpGetStatus"; - case 0x6ccbe3d6: return "cellImeJpEnterChar"; - case 0x7189430b: return "cellImeJpAllConfirm"; - case 0x72257652: return "cellImeJpDeleteWord"; - case 0x7a18c2b9: return "cellImeJpCurrentPartConfirm"; - case 0x89f8a567: return "cellImeJpGetConfirmYomiString"; - case 0x8bb41f47: return "cellImeJpPostConvert"; - case 0xaa1d1f57: return "cellImeJpBackspaceWord"; - case 0xaa2a3287: return "cellImeJpShortenConvertArea"; - case 0xac6693d8: return "cellImeJpModeCaretRight"; - case 0xbd679cc1: return "cellImeJpTemporalConfirm"; - case 0xc1786c81: return "cellImeJpSetFixInputMode"; - case 0xc2bb48bc: return "cellImeJpConvertBackward"; - case 0xc4796a45: return "cellImeJpGetCandidateListSize"; - case 0xcbbc20b7: return "cellImeJpAllConvertCancel"; - case 0xd3fc3606: return "cellImeJpGetConfirmString"; - case 0xe4cc15ba: return "cellImeJpGetCandidateList"; - case 0xe76c9700: return "cellImeJpModeCaretLeft"; - case 0xea2d4881: return "cellImeJpGetConvertYomiString"; - case 0xeae879dc: return "cellImeJpConvertCancel"; - case 0xeede898c: return "cellImeJpConfirmPrediction"; - case 0xf5992ec8: return "cellImeJpSetInputCharType"; - case 0xf91abda3: return "cellImeJpGetConvertString"; - case 0x65cbbb16: return "cellJpgDecExtSetParameter"; - case 0x6d9ebccf: return "cellJpgDecReadHeader"; - case 0x716f8792: return "cellJpgDecExtDecodeData"; - case 0x8b300f66: return "cellJpgDecExtCreate"; - case 0x9338a07a: return "cellJpgDecClose"; - case 0x976ca5c2: return "cellJpgDecOpen"; - case 0xa7978f59: return "cellJpgDecCreate"; - case 0xa9f703e3: return "cellJpgDecExtOpen"; - case 0xaf8bb012: return "cellJpgDecDecodeData"; - case 0xb91eb3d2: return "cellJpgDecExtReadHeader"; - case 0xd8ea91f8: return "cellJpgDecDestroy"; - case 0xe08f3910: return "cellJpgDecSetParameter"; - case 0x0cf2b78b: return "cellJpgEncReset"; - case 0x12d9b6c5: return "cellJpgEncQueryAttr"; - case 0x2ae79be8: return "cellJpgEncWaitForInput"; - case 0x4262e880: return "cellJpgEncGetStreamInfo"; - case 0x636dc89e: return "cellJpgEncEncodePicture2"; - case 0x6f2d371c: return "cellJpgEncOpenEx"; - case 0x969fc5f7: return "cellJpgEncClose"; - case 0x9b4e3a74: return "cellJpgEncWaitForOutput"; - case 0xa4bfae51: return "cellJpgEncOpen"; - case 0xa9e81214: return "cellJpgEncEncodePicture"; - case 0x0dfbadfa: return "cellKey2CharSetArrangement"; - case 0x14bf2dc1: return "cellKey2CharClose"; - case 0x56776c0d: return "cellKey2CharGetChar"; - case 0xabf629c1: return "cellKey2CharOpen"; - case 0xbfc03768: return "cellKey2CharSetMode"; - case 0x005200e6: return "UCS2toEUCJP"; - case 0x01b0cbf4: return "l10n_convert"; - case 0x0356038c: return "UCS2toUTF32"; - case 0x05028763: return "jis2kuten"; - case 0x058addc8: return "UTF8toGB18030"; - case 0x060ee3b2: return "JISstoUTF8s"; - case 0x07168a83: return "SjisZen2Han"; - case 0x0bc386c8: return "ToSjisLower"; - case 0x0bedf77d: return "UCS2toGB18030"; - case 0x0bf867e2: return "HZstoUCS2s"; - case 0x0ce278fd: return "UCS2stoHZs"; - case 0x0d90a48d: return "UCS2stoSJISs"; - case 0x0f624540: return "kuten2eucjp"; - case 0x14ee3649: return "sjis2jis"; - case 0x14f504b8: return "EUCKRstoUCS2s"; - case 0x16eaf5f1: return "UHCstoEUCKRs"; - case 0x1758053c: return "jis2sjis"; - case 0x1906ce6b: return "jstrnchk"; - case 0x1ac0d23d: return "L10nConvert"; - case 0x1ae2acee: return "EUCCNstoUTF8s"; - case 0x1cb1138f: return "GBKstoUCS2s"; - case 0x1da42d70: return "eucjphan2zen"; - case 0x1ec712e0: return "ToSjisHira"; - case 0x1fb50183: return "GBKtoUCS2"; - case 0x21948c03: return "eucjp2jis"; - case 0x21aa3045: return "UTF32stoUTF8s"; - case 0x24fd32a9: return "sjishan2zen"; - case 0x256b6861: return "UCS2toSBCS"; - case 0x262a5ae2: return "UTF8stoGBKs"; - case 0x28724522: return "UTF8toUCS2"; - case 0x2ad091c6: return "UCS2stoUTF8s"; - case 0x2b84030c: return "EUCKRstoUTF8s"; - case 0x2efa7294: return "UTF16stoUTF32s"; - case 0x2f9eb543: return "UTF8toEUCKR"; - case 0x317ab7c2: return "UTF16toUTF8"; - case 0x32689828: return "ARIBstoUTF8s"; - case 0x33435818: return "SJISstoUTF8s"; - case 0x33f8b35c: return "sjiszen2han"; - case 0x3968f176: return "ToEucJpLower"; - case 0x398a3dee: return "MSJIStoUTF8"; - case 0x3a20bc34: return "UCS2stoMSJISs"; - case 0x3dabd5a7: return "EUCJPtoUTF8"; - case 0x3df65b64: return "eucjp2sjis"; - case 0x408a622b: return "ToEucJpHira"; - case 0x41b4a5ae: return "UHCstoUCS2s"; - case 0x41ccf033: return "ToEucJpKata"; - case 0x42838145: return "HZstoUTF8s"; - case 0x4931b44e: return "UTF8toMSJIS"; - case 0x4b3bbacb: return "BIG5toUTF8"; - case 0x511d386b: return "EUCJPstoSJISs"; - case 0x52b7883f: return "UTF8stoBIG5s"; - case 0x53558b6b: return "UTF16stoUCS2s"; - case 0x53764725: return "UCS2stoGB18030s"; - case 0x53c71ac2: return "EUCJPtoSJIS"; - case 0x54f59807: return "EUCJPtoUCS2"; - case 0x55f6921c: return "UCS2stoGBKs"; - case 0x58246762: return "EUCKRtoUHC"; - case 0x596df41c: return "UCS2toSJIS"; - case 0x5a4ab223: return "MSJISstoUTF8s"; - case 0x5ac783dc: return "EUCJPstoUTF8s"; - case 0x5b684dfb: return "UCS2toBIG5"; - case 0x5cd29270: return "UTF8stoEUCKRs"; - case 0x5e1d9330: return "UHCstoUTF8s"; - case 0x60ffa0ec: return "GB18030stoUCS2s"; - case 0x6122e000: return "SJIStoUTF8"; - case 0x6169f205: return "JISstoSJISs"; - case 0x61fb9442: return "UTF8toUTF16"; - case 0x62b36bcf: return "UTF8stoMSJISs"; - case 0x63219199: return "EUCKRtoUTF8"; - case 0x638c2fc1: return "SjisHan2Zen"; - case 0x64a10ec8: return "UCS2toUTF16"; - case 0x65444204: return "UCS2toMSJIS"; - case 0x6621a82c: return "sjis2kuten"; - case 0x6a6f25d1: return "UCS2toUHC"; - case 0x6c62d879: return "UTF32toUCS2"; - case 0x6de4b508: return "ToSjisUpper"; - case 0x6e0705c4: return "UTF8toEUCJP"; - case 0x6e5906fd: return "UCS2stoEUCJPs"; - case 0x6fc530b3: return "UTF16toUCS2"; - case 0x714a9b4a: return "UCS2stoUTF16s"; - case 0x71804d64: return "UCS2stoEUCCNs"; - case 0x72632e53: return "SBCSstoUTF8s"; - case 0x73f2cd21: return "SJISstoJISs"; - case 0x74496718: return "SBCStoUTF8"; - case 0x74871fe0: return "UTF8toUTF32"; - case 0x750c363d: return "jstrchk"; - case 0x7c5bde1c: return "UHCtoEUCKR"; - case 0x7c912bda: return "kuten2jis"; - case 0x7d07a1c2: return "UTF8toEUCCN"; - case 0x8171c1cc: return "EUCCNtoUTF8"; - case 0x82d5ecdf: return "EucJpZen2Han"; - case 0x8555fe15: return "UTF32stoUTF16s"; - case 0x860fc741: return "GBKtoUTF8"; - case 0x867f7b8b: return "ToEucJpUpper"; - case 0x88f8340b: return "UCS2stoJISs"; - case 0x89236c86: return "UTF8stoGB18030s"; - case 0x8a56f148: return "EUCKRstoUHCs"; - case 0x8ccdba38: return "UTF8stoUTF32s"; - case 0x8f472054: return "UTF8stoEUCCNs"; - case 0x90e9b5d2: return "EUCJPstoUCS2s"; - case 0x91a99765: return "UHCtoUCS2"; - case 0x931ff25a: return "L10nConvertStr"; - case 0x949bb14c: return "GBKstoUTF8s"; - case 0x9557ac9b: return "UTF8toUHC"; - case 0x9768b6d3: return "UTF32toUTF8"; - case 0x9874020d: return "sjis2eucjp"; - case 0x9a0e7d23: return "UCS2toEUCCN"; - case 0x9a13d6b8: return "UTF8stoUHCs"; - case 0x9a72059d: return "EUCKRtoUCS2"; - case 0x9b1210c6: return "UTF32toUTF16"; - case 0x9cd8135b: return "EUCCNstoUCS2s"; - case 0x9ce52809: return "SBCSstoUCS2s"; - case 0x9cf1ab77: return "UTF8stoJISs"; - case 0x9d14dc46: return "ToSjisKata"; - case 0x9dcde367: return "jis2eucjp"; - case 0x9ec52258: return "BIG5toUCS2"; - case 0xa0d463c0: return "UCS2toGBK"; - case 0xa19fb9de: return "UTF16toUTF32"; - case 0xa298cad2: return "l10n_convert_str"; - case 0xa34fa0eb: return "EUCJPstoJISs"; - case 0xa5146299: return "UTF8stoARIBs"; - case 0xa609f3e9: return "JISstoEUCJPs"; - case 0xa60ff5c9: return "EucJpHan2Zen"; - case 0xa963619c: return "isEucJpKigou"; - case 0xa9a76fb8: return "UCS2toUTF8"; - case 0xaf18d499: return "GB18030toUCS2"; - case 0xb3361be6: return "UHCtoUTF8"; - case 0xb6e45343: return "MSJIStoUCS2"; - case 0xb7cef4a6: return "UTF8toGBK"; - case 0xb7e08f7a: return "kuten2sjis"; - case 0xb9cf473d: return "UTF8toSBCS"; - case 0xbdd44ee3: return "SJIStoUCS2"; - case 0xbe42e661: return "eucjpzen2han"; - case 0xbe8d5485: return "UCS2stoARIBs"; - case 0xbefe3869: return "isSjisKigou"; - case 0xc62b758d: return "UTF8stoEUCJPs"; - case 0xc7bdcb4c: return "UCS2toEUCKR"; - case 0xc944fa56: return "SBCStoUCS2"; - case 0xc9b78f58: return "MSJISstoUCS2s"; - case 0xcc1633cc: return "l10n_get_converter"; - case 0xd02ef83d: return "GB18030stoUTF8s"; - case 0xd8721e2c: return "SJISstoEUCJPs"; - case 0xd8cb24cb: return "UTF32stoUCS2s"; - case 0xd990858b: return "BIG5stoUTF8s"; - case 0xd9fb1224: return "EUCCNtoUCS2"; - case 0xda67b37f: return "UTF8stoSBCSs"; - case 0xdc54886c: return "UCS2stoEUCKRs"; - case 0xdd5ebdeb: return "UTF8stoSJISs"; - case 0xdefa1c17: return "UTF8stoHZs"; - case 0xe2eabb32: return "eucjp2kuten"; - case 0xe6d9e234: return "UTF8toBIG5"; - case 0xe6f5711b: return "UTF16stoUTF8s"; - case 0xe956dc64: return "JISstoUCS2s"; - case 0xeabc3d00: return "GB18030toUTF8"; - case 0xeb3dc670: return "UTF8toSJIS"; - case 0xeb41cc68: return "ARIBstoUCS2s"; - case 0xeb685b83: return "UCS2stoUTF32s"; - case 0xebae29c0: return "UCS2stoSBCSs"; - case 0xee6c6a39: return "UCS2stoBIG5s"; - case 0xf1dcfa71: return "UCS2stoUHCs"; - case 0xf439728e: return "SJIStoEUCJP"; - case 0xf7681b9a: return "UTF8stoUTF16s"; - case 0xf9b1896d: return "SJISstoUCS2s"; - case 0xfa4a675a: return "BIG5stoUCS2s"; - case 0xfdbf6ac5: return "UTF8stoUCS2s"; - case 0x0252efcc: return "cellUserTraceInit"; - case 0x05893e7c: return "cellUserTraceRegister"; - case 0x6d045c2e: return "cellUserTraceUnregister"; - case 0x898c77bf: return "cellUserTraceTerminate"; - case 0x017024a8: return "cellMicGetDeviceGUID"; - case 0x05709bbf: return "cellMicOpenEx"; - case 0x07e1b12c: return "cellMicRead"; - case 0x186cb1fb: return "cellMicIsOpen"; - case 0x1b42101b: return "cellMicIsAttached"; - case 0x25c5723f: return "cellMicGetStatus"; - case 0x323deb41: return "cellMicSetSignalAttr"; - case 0x3acc118e: return "cellMicReadAux"; - case 0x3ace58f3: return "cellMicSysShareClose"; - case 0x48108a23: return "cellMicGetFormat"; - case 0x4e0b69ee: return "cellMicGetFormatRaw"; - case 0x65336418: return "cellMicRemoveNotifyEventQueue"; - case 0x6a024aa0: return "cellMicGetDeviceAttr"; - case 0x6bc46aab: return "cellMicReset"; - case 0x6cc7ae00: return "cellMicSetNotifyEventQueue2"; - case 0x72165a7f: return "cellMicReadRaw"; - case 0x7903400e: return "cellMicSetNotifyEventQueue"; - case 0x8325e02d: return "cellMicInit"; - case 0x87a08d29: return "cellMicGetFormatDsp"; - case 0x891c6291: return "cellMicSetMultiMicNotifyEventQueue"; - case 0x8d229f8e: return "cellMicClose"; - case 0xa42ac07a: return "cellMicOpenRaw"; - case 0xa52d2ae4: return "cellMicGetType"; - case 0xac5ba03a: return "cellMicGetSignalAttr"; - case 0xad049ecf: return "cellMicGetFormatEx"; - case 0xb2c16321: return "cellMicSetDeviceAttr"; - case 0xb30780eb: return "cellMicGetSignalState"; - case 0xbdfd51e2: return "cellMicSysShareStop"; - case 0xc3610dbd: return "cellMicSysShareOpen"; - case 0xc414faa5: return "cellMicReadDsp"; - case 0xc461563c: return "cellMicCommand"; - case 0xc6328caa: return "cellMicEnd"; - case 0xcac7e7d7: return "cellMicSysShareStart"; - case 0xd127cd3e: return "cellMicSysShareInit"; - case 0xdd1b59f0: return "cellMicOpen"; - case 0xdd724314: return "cellMicStart"; - case 0xddd19a89: return "cellMicStartEx"; - case 0xe839380f: return "cellMicStopEx"; - case 0xf82bbf7c: return "cellMicSysShareEnd"; - case 0xfcfaf246: return "cellMicStop"; - case 0xfda12276: return "cellMicGetFormatAux"; - case 0xfdbbe469: return "cellMicGetDeviceIdentifier"; - case 0x066bb1cf: return "cellMusicDecodeSetDecodeCommand"; - case 0x1576e4f2: return "cellMusicDecodeGetDecodeStatus2"; - case 0x25ea7ac0: return "cellMusicDecodeGetContentsId2"; - case 0x2ef701ec: return "cellMusicDecodeSetDecodeCommand2"; - case 0x491d6ba5: return "cellMusicDecodeSetSelectionContext2"; - case 0x4aef2877: return "cellMusicDecodeFinalize2"; - case 0x58ab1999: return "cellMusicDecodeGetContentsId"; - case 0x5af74c50: return "cellMusicDecodeGetDecodeStatus"; - case 0x84f154b2: return "cellMusicDecodeInitializeSystemWorkload"; - case 0xa8615dc8: return "cellMusicDecodeFinalize"; - case 0xa881b744: return "cellMusicDecodeRead"; - case 0xb2d054df: return "cellMusicDecodeRead2"; - case 0xb641168e: return "cellMusicDecodeInitialize2SystemWorkload"; - case 0xb84f5c81: return "cellMusicDecodeSetSelectionContext"; - case 0xc22563c4: return "cellMusicDecodeSelectContents2"; - case 0xd55dbc11: return "cellMusicDecodeInitialize"; - case 0xdbf70550: return "cellMusicDecodeGetSelectionContext"; - case 0xf24cb963: return "cellMusicDecodeSelectContents"; - case 0xf80e31e5: return "cellMusicDecodeInitialize2"; - case 0xf91639f9: return "cellMusicDecodeGetSelectionContext2"; - case 0x92b50ebc: return "cellMusicExportProgress"; - case 0xb202f0e8: return "cellMusicExportFromFile"; - case 0xb4c9b4f9: return "cellMusicExportInitialize"; - case 0xe0443a44: return "cellMusicExportInitialize2"; - case 0xe90effea: return "cellMusicExportFinalize"; - case 0x0b461648: return "cellMusicGetSelectionContext"; - case 0x2bdc5d6b: return "cellMusicSetSelectionContext2"; - case 0x4014c246: return "cellMusicSetVolume2"; - case 0x4c188caa: return "cellMusicGetContentsId"; - case 0x5bff31bf: return "cellMusicSetSelectionContext"; - case 0x61865281: return "cellMusicInitialize2SystemWorkload"; - case 0x648b7611: return "cellMusicGetPlaybackStatus2"; - case 0x6674de2d: return "cellMusicGetContentsId2"; - case 0x6f2104f3: return "cellMusicFinalize"; - case 0x72876546: return "cellMusicInitializeSystemWorkload"; - case 0x72ec14b5: return "cellMusicInitialize"; - case 0x7be4dc31: return "cellMusicFinalize2"; - case 0x8793ef97: return "cellMusicGetSelectionContext2"; - case 0x8aa188e3: return "cellMusicGetVolume"; - case 0x95f7d9d9: return "cellMusicGetPlaybackStatus"; - case 0x98947a6e: return "cellMusicSetPlaybackCommand2"; - case 0xa0661626: return "cellMusicSetPlaybackCommand"; - case 0xad04cddd: return "cellMusicSelectContents2"; - case 0xb2336ba7: return "cellMusicSelectContents"; - case 0xbe50b11e: return "cellMusicInitialize2"; - case 0xe74ce7bd: return "cellMusicSetVolume"; - case 0xf9073a24: return "cellMusicGetVolume2"; - case 0x04459230: return "cellNetCtlNetStartDialogLoadAsync"; - case 0x0791015f: return "cellGameUpdateCheckStartAsyncEx"; - case 0x0ce13c6b: return "cellNetCtlAddHandler"; - case 0x0f1f13d3: return "cellNetCtlNetStartDialogUnloadAsync"; - case 0x105ee2cb: return "cellNetCtlTerm"; - case 0x10dae56d: return "cellGameUpdateTerm"; - case 0x1e585b5d: return "cellNetCtlGetInfo"; - case 0x3a12865f: return "cellNetCtlGetNatInfo"; - case 0x3e359ab6: return "cellGameUpdateCheckAbort"; - case 0x558700f6: return "cellGameUpdateCheckStartWithoutDialogAsyncEx"; - case 0x71d53210: return "cellNetCtlNetStartDialogAbortAsync"; - case 0x8b3eba69: return "cellNetCtlGetState"; - case 0x901815c3: return "cellNetCtlDelHandler"; - case 0x99ab1a26: return "cellGameUpdateInit"; - case 0xa5e1fa60: return "cellGameUpdateCheckStartWithoutDialogAsync"; - case 0xbd5a59fc: return "cellNetCtlInit"; - case 0xd0a5d727: return "cellGameUpdateCheckStartAsync"; - case 0xf463981c: return "cellGameUpdateCheckFinishAsyncEx"; - case 0xffa3d791: return "cellGameUpdateCheckFinishAsync"; - case 0x09565b21: return "cellOskDialogExtInputDeviceUnlock"; - case 0x1e1b4c97: return "cellOskDialogExtRegisterKeyboardEventHookCallback"; - case 0x23a2ede6: return "cellOskDialogExtAddJapaneseOptionDictionary"; - case 0x42439db5: return "cellOskDialogExtSendFinishMessage"; - case 0x4fe14d09: return "cellOskDialogExtAddOptionDictionary"; - case 0x75370397: return "cellOskDialogExtSetInitialScale"; - case 0x7c95feb8: return "cellOskDialogExtInputDeviceLock"; - case 0x7eb292cd: return "cellOskDialogExtSetBaseColor"; - case 0x8692fcd2: return "cellOskDialogExtRegisterConfirmWordFilterCallback"; - case 0x8b60c469: return "cellOskDialogExtUpdateInputText"; - case 0xe6c43c58: return "cellOskDialogExtEnableHalfByteKana"; - case 0xe800f586: return "cellOskDialogExtRegisterForceFinishCallback"; - case 0x629ba0c0: return "cellOvisInvalidateOverlappedSegments"; - case 0x82f294b2: return "cellOvisGetOverlayTableSize"; - case 0xa876c911: return "cellOvisInitializeOverlayTable"; - case 0xce6cb776: return "cellOvisFixSpuSegments"; - case 0x01067e22: return "cellPamfStreamTypeToEsFilterId"; - case 0x03fd2caa: return "cellPamfReaderSetStreamWithTypeAndChannel"; - case 0x041cc708: return "cellPamfReaderGetStreamIndex"; - case 0x1abeb9d6: return "cellPamfEpIteratorGetEp"; - case 0x28b4e2c1: return "cellPamfReaderSetStreamWithTypeAndIndex"; - case 0x37f723f7: return "cellPamfReaderGetNumberOfStreams"; - case 0x439fba17: return "cellPamfReaderGetEpIteratorWithTimeStamp"; - case 0x44f5c9e3: return "cellPamfGetStreamOffsetAndSize"; - case 0x461534b4: return "cellPamfReaderSetStreamWithIndex"; - case 0x4de501b1: return "cellPamfReaderGetPresentationStartTime"; - case 0x50b83205: return "cellPamfEpIteratorMove"; - case 0x67fd273b: return "cellPamfReaderGetStreamInfo"; - case 0x71df326a: return "cellPamfReaderGetEsFilterId"; - case 0x90fc9a59: return "cellPamfGetHeaderSize2"; - case 0x9ab20793: return "cellPamfReaderGetStreamTypeAndChannel"; - case 0xb8436ee5: return "cellPamfReaderInitialize"; - case 0xca8181c1: return "cellPamfGetHeaderSize"; - case 0xd0230671: return "cellPamfReaderGetNumberOfSpecificStreams"; - case 0xd1a40ef4: return "cellPamfVerify"; - case 0xd9ea3457: return "cellPamfReaderGetNumberOfEp"; - case 0xdb70296c: return "cellPamfReaderGetMuxRateBound"; - case 0xe8586ec6: return "cellPamfReaderGetEpIteratorWithIndex"; - case 0xf61609d6: return "cellPamfReaderGetPresentationEndTime"; - case 0x0f424ecb: return "cellPhotoDecodeInitialize2"; - case 0x28b22e44: return "cellPhotoDecodeFromFile"; - case 0x596f0a56: return "cellPhotoDecodeInitialize"; - case 0xad7d8f38: return "cellPhotoDecodeFinalize"; - case 0x0783bce0: return "cellPhotoImport"; - case 0x1ab8df55: return "cellPhotoImport2"; - case 0x08cbd8e1: return "cellPhotoExportInitialize2"; - case 0x09ce84ac: return "cellPhotoExportFromFile"; - case 0x3f7fc0af: return "cellPhotoFinalize"; - case 0x42a32983: return "cellPhotoRegistFromFile"; - case 0x4357c77f: return "cellPhotoExportInitialize"; - case 0x55c70783: return "cellPhotoInitialize"; - case 0xde509ead: return "cellPhotoExportProgress"; - case 0xed4a0148: return "cellPhotoExportFinalize"; - case 0x0c515302: return "cellPngDecExtOpen"; - case 0x157d30c5: return "cellPngDecCreate"; - case 0x2310f155: return "cellPngDecDecodeData"; - case 0x27c921b5: return "cellPngDecGetoFFs"; - case 0x30cb334a: return "cellPngDecGetsBIT"; - case 0x35a6846c: return "cellPngDecGettIME"; - case 0x3d50016a: return "cellPngDecGetpHYs"; - case 0x48436b2d: return "cellPngDecExtCreate"; - case 0x5b3d1ff1: return "cellPngDecClose"; - case 0x609ec7d5: return "cellPngDecGetUnknownChunks"; - case 0x726fc1d0: return "cellPngDecExtDecodeData"; - case 0x7585a275: return "cellPngDecGetbKGD"; - case 0x7a062d26: return "cellPngDecGetcHRM"; - case 0x820dae1a: return "cellPngDecDestroy"; - case 0x8b33f863: return "cellPngDecExtReadHeader"; - case 0x9ccdcc95: return "cellPngDecReadHeader"; - case 0x9e9d7d42: return "cellPngDecExtSetParameter"; - case 0xa5cdf57e: return "cellPngDecGetsPLT"; - case 0xb153629c: return "cellPngDecGetgAMA"; - case 0xb40ca175: return "cellPngDecGetTextChunk"; - case 0xb4fe75e1: return "cellPngDecGetpCAL"; - case 0xb905ebb7: return "cellPngDecGethIST"; - case 0xb96fb26e: return "cellPngDecGettRNS"; - case 0xc41e1198: return "cellPngDecGetsCAL"; - case 0xd2bc5bfd: return "cellPngDecOpen"; - case 0xe163977f: return "cellPngDecGetPLTE"; - case 0xe4416e82: return "cellPngDecGetsRGB"; - case 0xe97c9bd4: return "cellPngDecSetParameter"; - case 0xf44b6c30: return "cellPngDecGetiCCP"; - case 0x117cd726: return "cellPngEncClose"; - case 0x19256dc5: return "cellPngEncOpen"; - case 0x496cfcd0: return "cellPngEncQueryAttr"; - case 0x585269bc: return "cellPngEncGetStreamInfo"; - case 0x5b546ca4: return "cellPngEncEncodePicture"; - case 0x662bd637: return "cellPngEncWaitForInput"; - case 0x6ac91de3: return "cellPngEncReset"; - case 0x90ef2963: return "cellPngEncWaitForOutput"; - case 0xc82558ce: return "cellPngEncOpenEx"; - case 0x0a373522: return "cellPrintSendBand"; - case 0x0d44f661: return "cellPrintEndPage"; - case 0x293d9e9c: return "cellPrintCancelJob"; - case 0x6802dfb5: return "cellPrintGetStatus"; - case 0x6d996018: return "cellSysutilPrintShutdown"; - case 0x6e952645: return "cellPrintGetPrintableArea"; - case 0x795b12b3: return "cellPrintStartJob"; - case 0x865acf74: return "cellPrintStartPage"; - case 0xc04a7d42: return "cellPrintEndJob"; - case 0xc9c3ef14: return "cellPrintLoadAsync"; - case 0xcf1aaefa: return "cellSysutilPrintInit"; - case 0xeb51aa38: return "cellPrintUnloadAsync"; - case 0xf0865182: return "cellPrintLoadAsync2"; - case 0xf9a53f35: return "cellPrintOpenConfig"; - case 0x39651e01: return "cellRecOpen"; - case 0x4ac76585: return "cellRecClose"; - case 0x5a8a8b0f: return "cellRecGetInfo"; - case 0x5b45439d: return "cellRecStop"; - case 0x964cd1b8: return "cellRecStart"; - case 0xdbf22bd1: return "cellRecQueryMemSize"; - case 0xf0958f73: return "cellRecSetInfo"; - case 0x533f41df: return "cellRemotePlayGetStatus"; - case 0x743918bd: return "cellRemotePlaySetComparativeVolume"; - case 0xa445cd55: return "cellRemotePlayGetPeerInfo"; - case 0xc267987b: return "cellRemotePlayGetSharedMemory"; - case 0xd29fe5e3: return "cellRemotePlayEncryptAllData"; - case 0xd6f3fc82: return "cellRemotePlayStopPeerVideoOut"; - case 0xe12c8c19: return "cellRemotePlayGetComparativeVolume"; - case 0xfb793f27: return "cellRemotePlayBreak"; - case 0x01220224: return "cellRescGcmSurface2RescSrc"; - case 0x0a2069c7: return "cellRescGetNumColorBuffers"; - case 0x0d3c22ce: return "cellRescSetWaitFlip"; - case 0x10db5b1a: return "cellRescSetDsts"; - case 0x129922a0: return "cellRescResetFlipStatus"; - case 0x19a2a967: return "cellRescSetPalInterpolateDropFlexRatio"; - case 0x1dd3c4cd: return "cellRescGetRegisterCount"; - case 0x22ae06d8: return "cellRescAdjustAspectRatio"; - case 0x23134710: return "cellRescSetDisplayMode"; - case 0x25c107e6: return "cellRescSetConvertAndFlip"; - case 0x2ea3061e: return "cellRescExit"; - case 0x2ea94661: return "cellRescSetFlipHandler"; - case 0x516ee89e: return "cellRescInit"; - case 0x5a338cdb: return "cellRescGetBufferSize"; - case 0x66f5e388: return "cellRescGetLastFlipTime"; - case 0x6cd0f95f: return "cellRescSetSrc"; - case 0x7af8a37f: return "cellRescSetRegisterCount"; - case 0x8107277c: return "cellRescSetBufferAddress"; - case 0xc47c5c22: return "cellRescGetFlipStatus"; - case 0xd1ca0503: return "cellRescVideoOutResolutionId2RescBufferMode"; - case 0xd3758645: return "cellRescSetVBlankHandler"; - case 0xe0cef79e: return "cellRescCreateInterlaceTable"; - case 0x1324948a: return "cellRtcFormatRfc3339LocalTime"; - case 0x269a1882: return "cellRtcTickAddTicks"; - case 0x2cce9cf5: return "cellRtcGetCurrentClockLocalTime"; - case 0x2f010bfa: return "cellRtcTickAddMinutes"; - case 0x32c941cf: return "cellRtcGetCurrentClock"; - case 0x332a74dd: return "cellRtcTickAddYears"; - case 0x46ca7fe0: return "cellRtcConvertLocalTimeToUtc"; - case 0x5316b4a8: return "cellRtcIsLeapYear"; - case 0x5491b9d5: return "cellRtcFormatRfc2822"; - case 0x5b6a0a1d: return "cellRtcGetDaysInMonth"; - case 0x5f68c268: return "cellRtcSetWin32FileTime"; - case 0x64c63fd5: return "cellRtcTickAddWeeks"; - case 0x75744e2a: return "cellRtcTickAddDays"; - case 0x7f1086e6: return "cellRtcCheckValid"; - case 0x9598d4b3: return "cellRtcSetDosTime"; - case 0x99b13034: return "cellRtcSetTick"; - case 0x9dafc0d9: return "cellRtcGetCurrentTick"; - case 0xa07c3d2f: return "cellRtcFormatRfc2822LocalTime"; - case 0xbb543189: return "cellRtcSetTime_t"; - case 0xc2d8cf95: return "cellRtcGetDayOfWeek"; - case 0xc48d5002: return "cellRtcConvertUtcToLocalTime"; - case 0xc5bc0fac: return "cellRtcParseDateTime"; - case 0xc7bdb7eb: return "cellRtcGetTick"; - case 0xcb90c761: return "cellRtcGetTime_t"; - case 0xccce71bd: return "cellRtcTickAddSeconds"; - case 0xcf11c3d6: return "cellRtcParseRfc3339"; - case 0xd41d3bd2: return "cellRtcTickAddHours"; - case 0xd9c0b463: return "cellRtcFormatRfc3339"; - case 0xdfff32cf: return "cellRtcGetDosTime"; - case 0xe0ecbb45: return "cellRtcTickAddMonths"; - case 0xe7086f05: return "cellRtcGetWin32FileTime"; - case 0xf8509925: return "cellRtcTickAddMicroseconds"; - case 0xfb51fc61: return "cellRtcCompareTick"; - case 0x2cde989f: return "cellRudpGetSizeReadable"; - case 0x384ba777: return "cellRudpSetOption"; - case 0x48c001b0: return "cellRudpWrite"; - case 0x48d3eeac: return "cellRudpTerminate"; - case 0x54f81789: return "cellRudpSetMaxSegmentSize"; - case 0x576831ae: return "cellRudpGetRemoteInfo"; - case 0x63f63545: return "cellRudpInit"; - case 0x6bc587e9: return "cellRudpPollCreate"; - case 0x6c0cff03: return "cellRudpEnableInternalIOThread"; - case 0x6ee04954: return "cellRudpNetReceived"; - case 0x74bfad12: return "cellRudpGetContextStatus"; - case 0x7dadc739: return "cellRudpCreateContext"; - case 0x7ed95e60: return "cellRudpSetEventHandler"; - case 0x8ac398f1: return "cellRudpPollDestroy"; - case 0x92e4d899: return "cellRudpRead"; - case 0xa3db855c: return "cellRudpPollControl"; - case 0xa70737da: return "cellRudpFlush"; - case 0xa86b28e3: return "cellRudpGetSizeWritable"; - case 0xb6bcb4a1: return "cellRudpEnd"; - case 0xc1ad7ced: return "cellRudpActivate"; - case 0xc407844f: return "cellRudpInitiate"; - case 0xcd1a3f23: return "cellRudpGetStatus"; - case 0xd666931f: return "cellRudpGetLocalInfo"; - case 0xd8310700: return "cellRudpPollWait"; - case 0xee41e16a: return "cellRudpBind"; - case 0xfade48b2: return "cellRudpProcessEvents"; - case 0xfbf7e9e4: return "cellRudpGetMaxSegmentSize"; - case 0xff9d259c: return "cellRudpGetOption"; - case 0x018281a8: return "cellSailGraphicsAdapterGetFrame2"; - case 0x0247c69e: return "cellSailGraphicsAdapterGetFrame"; - case 0x025b4974: return "cellSailPlayerUnregisterSource"; - case 0x06dd4174: return "cellSailRendererAudioFinalize"; - case 0x07924359: return "cellSailPlayerCloseEsVideo"; - case 0x09de25fd: return "cellSailPlayerIsEsAudioMuted"; - case 0x0abb318b: return "cellSailDescriptorCreateDatabase"; - case 0x0c4cb439: return "cellSailFutureReset"; - case 0x0d0c2f0c: return "cellSailDescriptorSetEs"; - case 0x10298371: return "cellSailAviMovieGetHeader"; - case 0x1139a206: return "cellSailPlayerSetSoundAdapter"; - case 0x145f9b11: return "cellSailPlayerOpenEsAudio"; - case 0x15fd6a2a: return "cellSailDescriptorClose"; - case 0x17932b26: return "cellSailPlayerInitialize"; - case 0x186b98d3: return "cellSailPlayerGetRegisteredProtocols"; - case 0x1872331b: return "cellSailGraphicsAdapterPtsToTimePosition"; - case 0x18b4629d: return "cellSailPlayerFinalize"; - case 0x18bcd21b: return "cellSailPlayerSetGraphicsAdapter"; - case 0x1c983864: return "cellSailGraphicsAdapterInitialize"; - case 0x1c9d5e5a: return "cellSailSoundAdapterSetPreferredFormat"; - case 0x23654375: return "cellSailPlayerInitialize2"; - case 0x26563ddc: return "cellSailPlayerNext"; - case 0x277adf21: return "cellSailDescriptorIsAutoSelection"; - case 0x28336e89: return "cellSailDescriptorDestroyDatabase"; - case 0x2e3ccb5e: return "cellSailGraphicsAdapterSetPreferredFormat"; - case 0x325039b9: return "cellSailRendererAudioNotifyOutputEos"; - case 0x346ebba3: return "cellSailMemAllocatorInitialize"; - case 0x34ecc1b9: return "cellSailPlayerOpenStream"; - case 0x38144ecf: return "cellSailPlayerGetRepeatMode"; - case 0x3a1132ed: return "cellSailAuReceiverGet"; - case 0x3a2d806c: return "cellSailFutureGet"; - case 0x3d0d3b72: return "cellSailSoundAdapterInitialize"; - case 0x3dd9639a: return "cellSailAuReceiverInitialize"; - case 0x3df98d41: return "cellSailSourceNotifyOpenCompleted"; - case 0x3e908c56: return "cellSailAviMovieGetStreamByIndex"; - case 0x44a20e79: return "cellSailGraphicsAdapterUpdateAvSync"; - case 0x47055fea: return "cellSailRendererVideoFinalize"; - case 0x47632810: return "cellSailPlayerReplaceEventHandler"; - case 0x477501f6: return "cellSailPlayerOpenEsVideo"; - case 0x4ae979df: return "cellSailSoundAdapterPtsToTimePosition"; - case 0x4c191088: return "cellSailDescriptorGetUri"; - case 0x4cc54f8e: return "cellSailFutureInitialize"; - case 0x4fa5ad09: return "cellSailPlayerReopenEsAudio"; - case 0x51ecf361: return "cellSailFutureIsDone"; - case 0x54c53688: return "cellSailSourceNotifyInputEos"; - case 0x5783a454: return "cellSailMp4MovieGetMovieInfo"; - case 0x5f44f64f: return "cellSailMp4TrackGetTrackReference"; - case 0x5f77e8df: return "cellSailRendererVideoNotifyFrameDone"; - case 0x5f7c7a6f: return "cellSailPlayerSetParameter"; - case 0x5faf802b: return "cellSailMp4MovieGetTrackByIndex"; - case 0x640c7278: return "cellSailSourceNotifyStartCompleted"; - case 0x67b4d01f: return "cellSailRendererAudioInitialize"; - case 0x69793952: return "cellSailPlayerUnsubscribeEvent"; - case 0x6e83f5c0: return "cellSailAviMovieGetMovieInfo"; - case 0x6f0b1002: return "cellSailPlayerSubscribeEvent"; - case 0x72236ec1: return "cellSailMp4TrackGetTrackReferenceCount"; - case 0x7473970a: return "cellSailSourceNotifyStopCompleted"; - case 0x752f8585: return "cellSailPlayerGetDescriptorCount"; - case 0x75fca288: return "cellSailPlayerGetCurrentDescriptor"; - case 0x76488bb1: return "cellSailGraphicsAdapterFinalize"; - case 0x764ec2d2: return "cellSailSourceNotifyCallCompleted"; - case 0x76b1a425: return "cellSailDescriptorSetAutoSelection"; - case 0x7b6fa92e: return "cellSailPlayerReopenEsUser"; - case 0x7c8dff3b: return "cellSailPlayerAddDescriptor"; - case 0x7eb8d6b5: return "cellSailSoundAdapterGetFrame"; - case 0x85b07126: return "cellSailMp4MovieGetTrackById"; - case 0x85beffcc: return "cellSailPlayerCloseStream"; - case 0x8d1ff475: return "cellSailRendererVideoInitialize"; - case 0x91d287f6: return "cellSailPlayerSetEsAudioMuted"; - case 0x92590d52: return "cellSailDescriptorInquireCapability"; - case 0x92eaf6ca: return "cellSailPlayerSetRendererAudio"; - case 0x946ecca0: return "cellSailSourceNotifyReadCompleted"; - case 0x950d53c1: return "cellSailPlayerCancel"; - case 0x952269c9: return "cellSailPlayerGetParameter"; - case 0x954f48f8: return "cellSailRendererVideoNotifyCallCompleted"; - case 0x9553af65: return "cellSailFutureFinalize"; - case 0x95ee1695: return "cellSailSourceNotifyStreamOut"; - case 0x9897fbd1: return "cellSailPlayerRemoveDescriptor"; - case 0x9d30bdce: return "cellSailSourceInitialize"; - case 0xa37fed15: return "cellSailFutureSet"; - case 0xa48be428: return "cellSailMp4TrackGetTrackInfo"; - case 0xa849d0a7: return "cellSailPlayerOpenEsUser"; - case 0xaafa17b8: return "cellSailPlayerIsPaused"; - case 0xac9c3b1f: return "cellSailDescriptorGetCapabilities"; - case 0xaed9d6cd: return "cellSailPlayerCloseEsUser"; - case 0xb7b4ecee: return "cellSailRendererAudioNotifyCallCompleted"; - case 0xb980b76e: return "cellSailMp4MovieGetBrand"; - case 0xbd1635f4: return "cellSailDescriptorGetMediaInfo"; - case 0xbdb2251a: return "cellSailSourceSetDiagHandler"; - case 0xbdf21b0f: return "cellSailPlayerBoot"; - case 0xbedccc74: return "cellSailPlayerRegisterSource"; - case 0xbf9b8d72: return "cellSailPlayerCloseEsAudio"; - case 0xc044fab1: return "cellSailDescriptorOpen"; - case 0xc09e2f23: return "cellSailAviStreamGetMediaType"; - case 0xc2d90ec9: return "cellSailMp4MovieGetTrackByTypeAndIndex"; - case 0xc457b203: return "cellSailSourceNotifyCloseCompleted"; - case 0xcc3cca60: return "cellSailAviStreamGetHeader"; - case 0xcc987ba6: return "cellSailPlayerDumpImage"; - case 0xd1462438: return "cellSailSoundAdapterFinalize"; - case 0xd1d55a90: return "cellSailPlayerSetPaused"; - case 0xd4049de0: return "cellSailMp4MovieIsCompatibleBrand"; - case 0xd5f9a15b: return "cellSailDescriptorGetStreamType"; - case 0xd7938b8d: return "cellSailPlayerCreateDescriptor"; - case 0xdbe32ed4: return "cellSailPlayerIsEsVideoMuted"; - case 0xddebd2a5: return "cellSailAviMovieGetStreamByTypeAndIndex"; - case 0xdf5553ef: return "cellSailDescriptorClearEs"; - case 0xdff1cda2: return "cellSailRendererVideoNotifyOutputEos"; - case 0xe535b0d3: return "cellSailPlayerStart"; - case 0xeba8d4ec: return "cellSailPlayerStop"; - case 0xecf56150: return "cellSailPlayerSetRendererVideo"; - case 0xed58e3ec: return "cellSailAuReceiverFinalize"; - case 0xee724c99: return "cellSailSourceFinalize"; - case 0xee94b99b: return "cellSailDescriptorSetParameter"; - case 0xeec22809: return "cellSailSoundAdapterUpdateAvSync"; - case 0xf1446a40: return "cellSailPlayerSetEsVideoMuted"; - case 0xf25f197d: return "cellSailSoundAdapterGetFormat"; - case 0xf289f0cd: return "cellSailSourceNotifySessionError"; - case 0xf4009a94: return "cellSailSourceNotifyMediaStateChanged"; - case 0xf5747e1f: return "cellSailPlayerSetAuReceiver"; - case 0xf60a8a69: return "cellSailPlayerReopenEsVideo"; - case 0xf841a537: return "cellSailRendererAudioNotifyFrameDone"; - case 0xfc5baf8a: return "cellSailPlayerSetRepeatMode"; - case 0xfc839bd4: return "cellSailPlayerDestroyDescriptor"; - case 0xffd58aa4: return "cellSailGraphicsAdapterGetFormat"; - case 0x0a3ea2a9: return "cellSailRecorderSetParameter"; - case 0x10c81457: return "cellSailRecorderOpenStream"; - case 0x1422a425: return "cellSailProfileSetEsVideoParameter"; - case 0x18ecc741: return "cellSailRecorderStop"; - case 0x376c3926: return "cellSailRecorderDestroyProfile"; - case 0x37aad85f: return "cellSailRecorderDumpImage"; - case 0x3c775cea: return "cellSailFeederAudioNotifyFrameOut"; - case 0x3deae857: return "cellSailRecorderSetFeederAudio"; - case 0x455c4709: return "cellSailRecorderDestroyVideoConverter"; - case 0x4830faf8: return "cellSailRecorderStart"; - case 0x49476a3d: return "cellSailRecorderCreateVideoConverter"; - case 0x4fec43a9: return "cellSailRecorderSetFeederVideo"; - case 0x50affdc1: return "cellSailRecorderCreateProfile"; - case 0x57415dd3: return "cellSailFeederVideoInitialize"; - case 0x7a52bf69: return "cellSailRecorderInitialize"; - case 0x81bfeae8: return "cellSailFeederVideoFinalize"; - case 0x855da8c6: return "cellSailVideoConverterProcess"; - case 0x86cae679: return "cellSailFeederVideoNotifySessionError"; - case 0x899d1587: return "cellSailFeederAudioFinalize"; - case 0x999c0dc5: return "cellSailFeederAudioNotifySessionEnd"; - case 0xaf310ae6: return "cellSailFeederAudioNotifySessionError"; - case 0xb3d30b0d: return "cellSailVideoConverterCanProcess"; - case 0xbd591197: return "cellSailFeederAudioInitialize"; - case 0xbff6e8d3: return "cellSailFeederVideoNotifySessionEnd"; - case 0xc2e2f30d: return "cellSailFeederAudioNotifyCallCompleted"; - case 0xc4617ddc: return "cellSailRecorderBoot"; - case 0xd37fb694: return "cellSailRecorderCancel"; - case 0xd84daeb9: return "cellSailFeederVideoNotifyCallCompleted"; - case 0xe14cae97: return "cellSailProfileSetEsAudioParameter"; - case 0xe15679fe: return "cellSailVideoConverterGetResult"; - case 0xe16de678: return "cellSailVideoConverterCanGetResult"; - case 0xe3f56f62: return "cellSailRecorderCloseStream"; - case 0xe5e0572a: return "cellSailFeederVideoNotifyFrameOut"; - case 0xe8d86c43: return "cellSailProfileSetStreamParameter"; - case 0xf57d74e3: return "cellSailRecorderFinalize"; - case 0xff20157b: return "cellSailRecorderGetParameter"; - case 0x04c06fc2: return "cellSaveDataGetListItem"; - case 0x273d116a: return "cellSaveDataUserListExport"; - case 0x27cb8bc2: return "cellSaveDataListDelete"; - case 0x39d6ee43: return "cellSaveDataUserListImport"; - case 0x46a2d878: return "cellSaveDataFixedExport"; - case 0x491cc554: return "cellSaveDataListExport"; - case 0x52541151: return "cellSaveDataFixedImport"; - case 0x529231b0: return "cellSaveDataUserFixedImport"; - case 0x6b4e0de6: return "cellSaveDataListImport"; - case 0x7048a9ba: return "cellSaveDataUserListDelete"; - case 0x95ae2cde: return "cellSaveDataUserFixedExport"; - case 0xf6482036: return "cellSaveDataUserGetListItem"; - case 0x7a9c2243: return "cellScreenShotSetOverlayImage"; - case 0x9e33ab8f: return "cellScreenShotEnable"; - case 0xd3ad63e4: return "cellScreenShotSetParameter"; - case 0xfc6f4e74: return "cellScreenShotDisable"; - case 0x025ce169: return "cellSearchGetMusicSelectionContext"; - case 0x0591826f: return "cellSearchStartContentSearch"; - case 0x0a4c8295: return "cellSearchStartListSearch"; - case 0x13524faa: return "cellSearchStartSceneSearch"; - case 0x35cda406: return "cellSearchGetContentInfoDeveloperData"; - case 0x37b5ba0c: return "cellSearchGetContentInfoPathMovieThumb"; - case 0x3b210319: return "cellSearchGetContentInfoByOffset"; - case 0x540d9068: return "cellSearchGetOffsetByContentId"; - case 0x64fb0b76: return "cellSearchStartContentSearchInList"; - case 0x774033d6: return "cellSearchEnd"; - case 0x8fe376a6: return "cellSearchCancel"; - case 0x94e21701: return "cellSearchGetContentIdByOffset"; - case 0x9663a44b: return "cellSearchGetContentInfoByContentId"; - case 0xbfab7616: return "cellSearchFinalize"; - case 0xc0ed0522: return "cellSearchStartSceneSearchInVideo"; - case 0xc81ccf8a: return "cellSearchInitialize"; - case 0xd7a7a433: return "cellSearchGetContentInfoGameComment"; - case 0xe73cb0d2: return "cellSearchPrepareFile"; - case 0xed20e079: return "cellSearchGetMusicSelectionContextOfSingleTrack"; - case 0xffb28491: return "cellSearchGetContentInfoPath"; - case 0x2452679f: return "cellKeySheapMutexDelete"; - case 0x3478e1e6: return "cellKeySheapMutexNew"; - case 0x37968718: return "cellSheapQueryMax"; - case 0x4a5b9659: return "cellKeySheapBufferNew"; - case 0x4b1383fb: return "cellSheapAllocate"; - case 0x5c5994bd: return "cellSheapFree"; - case 0x69a5861d: return "cellKeySheapSemaphoreNew"; - case 0x73a45cf8: return "cellKeySheapSemaphoreDelete"; - case 0x79a6abd0: return "cellKeySheapQueueDelete"; - case 0x7fa23275: return "cellSheapQueryFree"; - case 0x987e260e: return "cellKeySheapQueueNew"; - case 0xa1b25841: return "cellKeySheapInitialize"; - case 0xbbb47cd8: return "cellSheapInitialize"; - case 0xe6b37362: return "cellKeySheapBufferDelete"; - case 0xe897c835: return "cellKeySheapBarrierNew"; - case 0xed136702: return "cellKeySheapRwmDelete"; - case 0xf01ac471: return "cellKeySheapRwmNew"; - case 0xf6f5fbca: return "cellKeySheapBarrierDelete"; - case 0x3fbcf1d6: return "cellSpudllHandleConfigSetDefaultValues"; - case 0xcccd3257: return "cellSpudllGetImageSize"; - case 0x00af2519: return "cellSpursJobGuardReset"; - case 0x011ee38b: return "_cellSpursLFQueueInitialize"; - case 0x039d70b7: return "cellSpursQueueDetachLv2EventQueue"; - case 0x07529113: return "cellSpursAttributeSetNamePrefix"; - case 0x082bfb09: return "_cellSpursQueueInitialize"; - case 0x0eb4bc38: return "cellSpursWorkloadAttributeSetShutdownCompletionEventHook"; - case 0x1051d134: return "cellSpursAttributeEnableSpuPrintfIfAvailable"; - case 0x13ae18f3: return "cellSpursTaskExitCodeGet"; - case 0x161da6a7: return "cellSpursJobChainGetError"; - case 0x16394a4e: return "_cellSpursTasksetAttributeInitialize"; - case 0x1656d49f: return "cellSpursLFQueueAttachLv2EventQueue"; - case 0x17001000: return "cellSpursAddUrgentCommand"; - case 0x182d9890: return "cellSpursRequestIdleSpu"; - case 0x1d2bca4b: return "cellSpursSendWorkloadSignal"; - case 0x1d344406: return "cellSpursTaskGetLoadableSegmentPattern"; - case 0x1d46fedf: return "cellSpursCreateTaskWithAttribute"; - case 0x1ebcf459: return "cellSpursDestroyTaskset2"; - case 0x1f402f8f: return "cellSpursGetInfo"; - case 0x2093252b: return "cellSpursQueueGetTasksetAddress"; - case 0x22aab31d: return "cellSpursEventFlagDetachLv2EventQueue"; - case 0x247414d0: return "cellSpursQueueClear"; - case 0x2cfccb99: return "cellSpursJobChainAttributeSetJobTypeMemoryCheck"; - case 0x2ddbcc0a: return "_cellSpursWorkloadFlagReceiver2"; - case 0x2edcff92: return "cellSpursTasksetSetExceptionEventHandler"; - case 0x303c19cd: return "cellSpursCreateJobChainWithAttribute"; - case 0x30aa96c4: return "cellSpursInitializeWithAttribute2"; - case 0x32b94add: return "cellSpursEnableExceptionEventHandler"; - case 0x34552fa6: return "cellSpursTaskExitCodeInitialize"; - case 0x3548f483: return "_cellSpursJobChainAttributeInitialize"; - case 0x35dae22b: return "_cellSpursLFQueuePopBody"; - case 0x35f02287: return "cellSpursQueueDepth"; - case 0x369fe03d: return "cellSpursQueueGetEntrySize"; - case 0x373523d4: return "cellSpursEventFlagWait"; - case 0x39c173fb: return "cellSpursGetSpuThreadGroupId"; - case 0x494613c7: return "cellSpursJobChainGetSpursAddress"; - case 0x49a3426d: return "cellSpursReadyCountSwap"; - case 0x4a5eab63: return "cellSpursWorkloadAttributeSetName"; - case 0x4a6465e3: return "cellSpursCreateTaskset2"; - case 0x4ac7bae4: return "cellSpursEventFlagClear"; - case 0x4c75deb8: return "cellSpursUnsetExceptionEventHandler"; - case 0x4cce88a9: return "cellSpursLookUpTasksetAddress"; - case 0x4ceb9694: return "cellSpursGetJobChainInfo"; - case 0x4d1e9373: return "cellSpursEventFlagGetClearMode"; - case 0x4de203e2: return "cellSpursSetPreemptionVictimHints"; - case 0x4e153e3e: return "cellSpursGetWorkloadInfo"; - case 0x4e66d483: return "cellSpursDetachLv2EventQueue"; - case 0x5202e53b: return "cellSpursJobChainSetExceptionEventHandler"; - case 0x52cc6c82: return "cellSpursCreateTaskset"; - case 0x54876603: return "cellSpursQueueSize"; - case 0x568b2352: return "cellSpursSemaphoreGetTasksetAddress"; - case 0x569674e3: return "cellSpursTraceInitialize"; - case 0x57e4dec3: return "cellSpursRemoveWorkload"; - case 0x58d58fcf: return "cellSpursTasksetGetSpursAddress"; - case 0x5ef96465: return "_cellSpursEventFlagInitialize"; - case 0x5fd43fe4: return "cellSpursWaitForWorkloadShutdown"; - case 0x60eb2dec: return "cellSpursCreateJobChain"; - case 0x652b70e2: return "cellSpursTasksetAttributeSetName"; - case 0x68aaeba9: return "cellSpursJobGuardInitialize"; - case 0x69726aa2: return "cellSpursAddWorkload"; - case 0x6aa76999: return "cellSpursJobChainUnsetExceptionEventHandler"; - case 0x6c960f6d: return "cellSpursGetSpuThreadId"; - case 0x6d2d9339: return "cellSpursEventFlagTryWait"; - case 0x6fcdf6e3: return "cellSpursGetSpuGuid"; - case 0x738e40e6: return "cellSpursShutdownJobChain"; - case 0x73e06f91: return "cellSpursLFQueueDetachLv2EventQueue"; - case 0x7517724a: return "cellSpursSetGlobalExceptionEventHandler"; - case 0x75211196: return "cellSpursReadyCountAdd"; - case 0x77cdac0c: return "_cellSpursSemaphoreInitialize"; - case 0x7b9cbb74: return "cellSpursTraceFinalize"; - case 0x7cb33c2e: return "cellSpursTaskGetReadOnlyAreaPattern"; - case 0x7e4ea023: return "cellSpursWakeUp"; - case 0x7fdf4fef: return "cellSpursBarrierInitialize"; - case 0x80a29e27: return "cellSpursSetPriorities"; - case 0x82275c1c: return "cellSpursAttributeSetMemoryContainerForSpuThread"; - case 0x838fa4f0: return "cellSpursTryJoinTask2"; - case 0x84d2f6d5: return "cellSpursSetMaxContention"; - case 0x861237f8: return "cellSpursUnsetGlobalExceptionEventHandler"; - case 0x86c864a2: return "cellSpursGetJobChainId"; - case 0x87630976: return "cellSpursEventFlagAttachLv2EventQueue"; - case 0x890f9e5a: return "cellSpursEventFlagGetDirection"; - case 0x8a85674d: return "_cellSpursLFQueuePushBody"; - case 0x8adadf65: return "_cellSpursTaskAttribute2Initialize"; - case 0x8f122ef8: return "cellSpursTasksetAttributeSetTasksetSize"; - case 0x8fdf50b2: return "cellSpursAddUrgentCall"; - case 0x9034e538: return "cellSpursTaskGetContextSaveAreaSize"; - case 0x91066667: return "cellSpursQueuePopBody"; - case 0x9197915f: return "cellSpursTaskGenerateLsPattern"; - case 0x92cff6ed: return "cellSpursQueuePushBody"; - case 0x94034c95: return "cellSpursTasksetUnsetExceptionEventHandler"; - case 0x947efb0b: return "cellSpursEventFlagGetTasksetAddress"; - case 0x95180230: return "_cellSpursAttributeInitialize"; - case 0x97a2f6c8: return "cellSpursJobHeaderSetJobbin2Param"; - case 0x98d5b343: return "cellSpursShutdownWorkload"; - case 0x9aeb5432: return "cellSpursBarrierGetTasksetAddress"; - case 0x9dcbcb5d: return "cellSpursAttributeEnableSystemWorkload"; - case 0x9f72add3: return "cellSpursJoinTaskset"; - case 0x9fcb567b: return "cellSpursGetTasksetInfo"; - case 0x9fef70c2: return "cellSpursJobChainAttributeSetName"; - case 0xa121a224: return "cellSpursTaskAttributeSetExitCodeContainer"; - case 0xa73bf47e: return "_cellSpursWorkloadFlagReceiver"; - case 0xa789e631: return "cellSpursShutdownTaskset"; - case 0xa7a94892: return "cellSpursJoinTask2"; - case 0xa7c066de: return "cellSpursJoinJobChain"; - case 0xa7f9e716: return "cellSpursGetWorkloadData"; - case 0xa839a4d9: return "cellSpursAttributeSetSpuThreadGroupType"; - case 0xaa6269a8: return "cellSpursInitializeWithAttribute"; - case 0xacfc8dbc: return "cellSpursInitialize"; - case 0xb792ca1a: return "cellSpursLFQueueGetTasksetAddress"; - case 0xb8474eff: return "_cellSpursTaskAttributeInitialize"; - case 0xb9bc6207: return "cellSpursAttachLv2EventQueue"; - case 0xbb68d76e: return "cellSpursJobChainAttributeSetHaltOnError"; - case 0xbeb600ac: return "cellSpursCreateTask"; - case 0xbfea60fa: return "cellSpursKickJobChain"; - case 0xc0158d8b: return "cellSpursAddWorkloadWithAttribute"; - case 0xc10931cb: return "cellSpursCreateTasksetWithAttribute"; - case 0xc2acdf43: return "_cellSpursTasksetAttribute2Initialize"; - case 0xc56defb5: return "cellSpursGetNumSpuThread"; - case 0xc765b995: return "cellSpursGetWorkloadFlag"; - case 0xca4c4600: return "cellSpursFinalize"; - case 0xce853fbf: return "cellSpursTraceStart"; - case 0xd2e23fa9: return "cellSpursSetExceptionEventHandler"; - case 0xd5d0b256: return "cellSpursJobGuardNotify"; - case 0xd86380d8: return "cellSpursGetJobPipelineInfo"; - case 0xdca13593: return "cellSpursTasksetAttributeEnableClearLS"; - case 0xddc81b5a: return "cellSpursTraceStop"; - case 0xe0a6dbe4: return "_cellSpursSendSignal"; - case 0xe14ca62d: return "cellSpursCreateTask2"; - case 0xe4944a1c: return "cellSpursCreateTask2WithBinInfo"; - case 0xe5443be7: return "cellSpursQueueAttachLv2EventQueue"; - case 0xe717ac73: return "cellSpursTaskExitCodeTryGet"; - case 0xe7b0e69a: return "cellSpursJobSetMaxGrab"; - case 0xe7dd87e1: return "cellSpursGetTasksetId"; - case 0xec68442c: return "cellSpursQueueGetDirection"; - case 0xefeb2679: return "_cellSpursWorkloadAttributeInitialize"; - case 0xf1d3552d: return "cellSpursReadyCountCompareAndSwap"; - case 0xf31731bb: return "cellSpursRunJobChain"; - case 0xf5507729: return "cellSpursEventFlagSet"; - case 0xf843818d: return "cellSpursReadyCountStore"; - case 0x01bbf2e0: return "cellSpursJobQueueGetSpurs"; - case 0x0582338a: return "cellSpursJobQueueAttributeSetDoBusyWaiting"; - case 0x0d69929e: return "_cellSpursJobQueueAllocateJobDescriptorBody"; - case 0x0f03f712: return "cellSpursJobQueueAttributeSetSubmitWithEntryLock"; - case 0x13671514: return "cellSpursJobQueueSetWaitingMode"; - case 0x15934401: return "cellSpursJobQueueGetSuspendedJobSize"; - case 0x1686957e: return "cellSpursJobQueueAttributeSetMaxSizeJobDescriptor"; - case 0x1917359d: return "_cellSpursJobQueuePortCopyPushJobBody"; - case 0x1b6eea7e: return "_cellSpursJobQueuePortPushJobListBody"; - case 0x1da890c7: return "_cellSpursJobQueuePushAndReleaseJobBody"; - case 0x26fa81b4: return "cellSpursJobQueuePortFinalize"; - case 0x29c2acc5: return "cellSpursJobQueueClose"; - case 0x2e775550: return "cellSpursJobQueueGetError"; - case 0x36d0a53c: return "_cellSpursJobQueuePushJob2Body"; - case 0x3d1294fc: return "cellSpursJobQueuePortInitialize"; - case 0x435bff07: return "cellSpursJobQueuePort2GetJobQueue"; - case 0x43ddab4f: return "cellSpursJobQueueAttributeInitialize"; - case 0x46c3fb5a: return "_cellSpursJobQueuePortCopyPushBody"; - case 0x4e1a17a6: return "_cellSpursJobQueuePortPushBody"; - case 0x5659da82: return "cellSpursJobQueueGetMaxSizeJobDescriptor"; - case 0x5fb9b05d: return "cellSpursJobQueueAttributeSetMaxGrab"; - case 0x634b1502: return "cellSpursJobQueuePortSync"; - case 0x677027af: return "cellSpursJobQueueSemaphoreInitialize"; - case 0x6c93ea18: return "cellSpursJobQueueSemaphoreAcquire"; - case 0x701fd8a9: return "_cellSpursJobQueuePushSync"; - case 0x742cec0d: return "cellSpursJobQueueAttributeSetIsJobTypeMemoryCheck"; - case 0x80a0264c: return "cellSpursJobQueuePortTrySync"; - case 0x840c5239: return "cellSpursJobQueueGetHandleCount"; - case 0x85cd04cd: return "_cellSpursJobQueuePortPushJobBody"; - case 0x8c97a96c: return "cellSpursShutdownJobQueue"; - case 0x8ce4cffa: return "cellSpursJoinJobQueue"; - case 0x90c88f84: return "cellSpursJobQueuePortGetJobQueue"; - case 0x90e392cf: return "_cellSpursJobQueuePortPushJobBody2"; - case 0x915455b3: return "cellSpursJobQueueSendSignal"; - case 0x93248b92: return "cellSpursJobQueueUnsetExceptionEventHandler"; - case 0x934abb00: return "cellSpursJobQueuePort2AllocateJobDescriptor"; - case 0x9396be1d: return "_cellSpursJobQueuePortPushSync"; - case 0x97409f67: return "cellSpursJobQueueSemaphoreTryAcquire"; - case 0x98203e3c: return "_cellSpursJobQueuePushJobBody2"; - case 0x983be7fc: return "_cellSpursCreateJobQueueWithJobDescriptorPool"; - case 0x99316997: return "_cellSpursJobQueuePushBody"; - case 0x9c300489: return "cellSpursJobQueueSetExceptionEventHandler"; - case 0xaf1c7a1d: return "_cellSpursJobQueuePushJobListBody"; - case 0xb53436e7: return "_cellSpursJobQueuePort2PushJobListBody"; - case 0xbd1c5d6b: return "_cellSpursJobQueuePortPushFlush"; - case 0xbfea28ab: return "cellSpursJobQueuePort2PushFlush"; - case 0xc343ee10: return "cellSpursGetJobQueueId"; - case 0xc39173a4: return "_cellSpursJobQueuePort2CopyPushJobBody"; - case 0xc4843b74: return "_cellSpursJobQueuePushJobBody"; - case 0xc485d207: return "cellSpursJobQueuePort2Destroy"; - case 0xcf89f218: return "_cellSpursJobQueuePort2PushJobBody"; - case 0xdf0120c2: return "_cellSpursJobQueuePushFlush"; - case 0xe1731df3: return "_cellSpursJobQueuePort2PushAndReleaseJobBody"; - case 0xe70f874e: return "cellSpursJobQueueAttributeSetGrabParameters"; - case 0xef66c4b7: return "_cellSpursJobQueuePortCopyPushJobBody2"; - case 0xf11fe0f1: return "cellSpursJobQueuePort2Create"; - case 0xf244e799: return "_cellSpursCreateJobQueue"; - case 0xf5de6363: return "cellSpursJobQueuePortInitializeWithDescriptorBuffer"; - case 0xfacb3ced: return "cellSpursJobQueuePort2Sync"; - case 0xfc526b72: return "cellSpursJobQueuePort2PushSync"; - case 0xff03cc79: return "cellSpursJobQueueAttributeSetIsHaltOnError"; - case 0xff7a7bd2: return "cellSpursJobQueueOpen"; - case 0x006c4900: return "cellSslCertGetNameEntryInfo"; - case 0x033c4905: return "cellSslCertGetRsaPublicKeyExponent"; - case 0x1650aea4: return "cellSslEnd"; - case 0x218b64da: return "cellSslCertGetNotAfter"; - case 0x31d9ba8d: return "cellSslCertGetNotBefore"; - case 0x32c61bdf: return "cellSslCertGetSubjectName"; - case 0x571afaca: return "cellSslCertificateLoader"; - case 0x5e9253ca: return "cellSslCertGetMd5Fingerprint"; - case 0x766d3ca1: return "cellSslCertGetNameEntryCount"; - case 0x7b689ebc: return "cellSslCertGetSerialNumber"; - case 0x8e505175: return "cellSslCertGetRsaPublicKeyModulus"; - case 0xae6eb491: return "cellSslCertGetIssuerName"; - case 0xf8206492: return "cellSslCertGetPublicKey"; - case 0xfb02c9d2: return "cellSslInit"; - case 0x5468d6b0: return "cellSubDisplayAudioOutNonBlocking"; - case 0x551d80a5: return "cellSubDisplayEnd"; - case 0x6595ce22: return "cellSubDisplayGetRequiredMemory"; - case 0x6d85ddb3: return "cellSubDisplayStop"; - case 0x8a264d71: return "cellSubDisplayGetPeerNum"; - case 0x938ac642: return "cellSubDisplayGetVideoBuffer"; - case 0xa5bccb47: return "cellSubDisplayStart"; - case 0xaee1e0c2: return "cellSubDisplayAudioOutBlocking"; - case 0xe2485f79: return "cellSubDisplayGetPeerList"; - case 0xf9a7e8a5: return "cellSubDisplayInit"; - case 0x07254fda: return "cellSyncBarrierInitialize"; - case 0x0c7cb9f7: return "cellSyncLFQueueGetEntrySize"; - case 0x167ea63e: return "cellSyncLFQueueSize"; - case 0x1bb675c2: return "cellSyncMutexLock"; - case 0x268edd6d: return "cellSyncBarrierTryNotify"; - case 0x2af0c515: return "cellSyncLFQueueClear"; - case 0x35bbdad2: return "_cellSyncLFQueueCompletePushPointer2"; - case 0x35f21355: return "cellSyncBarrierWait"; - case 0x3929948d: return "cellSyncQueueInitialize"; - case 0x46356fe0: return "_cellSyncLFQueueGetPopPointer2"; - case 0x48154c9b: return "cellSyncQueuePeek"; - case 0x4da349b2: return "cellSyncQueueSize"; - case 0x4da6d7e0: return "cellSyncQueuePop"; - case 0x4e88c68d: return "_cellSyncLFQueueCompletePushPointer"; - case 0x54fc2032: return "_cellSyncLFQueueAttachLv2EventQueue"; - case 0x5ae841e5: return "cellSyncQueuePush"; - case 0x68af923c: return "cellSyncQueueTryPeek"; - case 0x6bb4ef9d: return "_cellSyncLFQueueGetPushPointer2"; - case 0x6c272124: return "cellSyncBarrierTryWait"; - case 0x705985cd: return "cellSyncQueueTryPush"; - case 0x74c37666: return "_cellSyncLFQueueGetPopPointer"; - case 0x7a51deee: return "_cellSyncLFQueueCompletePopPointer2"; - case 0x811d148e: return "_cellSyncLFQueueDetachLv2EventQueue"; - case 0x91f2b7b0: return "cellSyncMutexUnlock"; - case 0xa5362e73: return "cellSyncQueueClear"; - case 0xa58df87f: return "cellSyncQueueTryPop"; - case 0xa6669751: return "cellSyncRwmTryRead"; - case 0xa9072dee: return "cellSyncMutexInitialize"; - case 0xaa355278: return "cellSyncLFQueueInitialize"; - case 0xaff7627a: return "_cellSyncLFQueueGetSignalAddress"; - case 0xba5961ca: return "_cellSyncLFQueuePushBody"; - case 0xba5bee48: return "cellSyncRwmTryWrite"; - case 0xcece771f: return "cellSyncRwmRead"; - case 0xd06918c4: return "cellSyncMutexTryLock"; - case 0xd59aa307: return "cellSyncLFQueueGetDirection"; - case 0xe18c273c: return "cellSyncLFQueueDepth"; - case 0xe1bc7add: return "_cellSyncLFQueuePopBody"; - case 0xe9bf2110: return "_cellSyncLFQueueGetPushPointer"; - case 0xed773f5f: return "cellSyncRwmWrite"; - case 0xf06a6415: return "cellSyncBarrierNotify"; - case 0xfc48b03f: return "cellSyncRwmInitialize"; - case 0xfe74e8e7: return "_cellSyncLFQueueCompletePopPointer"; - case 0x0080fe88: return "cellSync2MutexUnlock"; - case 0x0c2983ac: return "cellSync2SemaphoreRelease"; - case 0x0c9a0ea9: return "cellSync2QueueTryPop"; - case 0x12f0a27d: return "cellSync2QueueGetSize"; - case 0x164843a7: return "cellSync2SemaphoreFinalize"; - case 0x27f2d61c: return "cellSync2MutexFinalize"; - case 0x2d77fe17: return "_cellSync2SemaphoreAttributeInitialize"; - case 0x4e2ee031: return "cellSync2SemaphoreGetCount"; - case 0x55836e73: return "_cellSync2MutexAttributeInitialize"; - case 0x58be9a0f: return "cellSync2CondInitialize"; - case 0x5b1e4d7a: return "cellSync2CondEstimateBufferSize"; - case 0x5e00d433: return "_cellSync2QueueAttributeInitialize"; - case 0x5e4b0f87: return "cellSync2SemaphoreTryAcquire"; - case 0x63062249: return "cellSync2CondFinalize"; - case 0x6af85cdf: return "cellSync2QueueFinalize"; - case 0x74c2780f: return "cellSync2SemaphoreEstimateBufferSize"; - case 0x7d967d91: return "cellSync2QueuePush"; - case 0x7fd479fe: return "cellSync2QueueTryPush"; - case 0x871af804: return "cellSync2CondSignal"; - case 0x8aae07c2: return "cellSync2CondSignalAll"; - case 0xa400d82e: return "cellSync2MutexLock"; - case 0xa69c749c: return "cellSync2MutexTryLock"; - case 0xbc96d751: return "cellSync2CondWait"; - case 0xc08cc0f9: return "cellSync2QueueEstimateBufferSize"; - case 0xc5dee254: return "cellSync2SemaphoreInitialize"; - case 0xd1b0d146: return "cellSync2SemaphoreAcquire"; - case 0xd51bfae7: return "cellSync2MutexEstimateBufferSize"; - case 0xd83ab0c9: return "cellSync2QueuePop"; - case 0xdf3c532a: return "_cellSync2CondAttributeInitialize"; - case 0xeb81a467: return "cellSync2MutexInitialize"; - case 0xf0e1471c: return "cellSync2QueueGetDepth"; - case 0xf125e044: return "cellSync2QueueInitialize"; - case 0x08db2adf: return "cellSysconfBtGetDeviceList"; - case 0x112a5ee9: return "cellSysmoduleUnloadModule"; - case 0x1ef115ef: return "cellSysmoduleGetImagesize"; - case 0x32267a31: return "cellSysmoduleLoadModule"; - case 0x3c92be09: return "cellSysmoduleFetchImage"; - case 0x5a59e258: return "cellSysmoduleIsLoaded"; - case 0x63ff6ff9: return "cellSysmoduleInitialize"; - case 0x96c07adf: return "cellSysmoduleFinalize"; - case 0xa193143c: return "cellSysmoduleSetMemcontainer"; - case 0x018a1381: return "cellSysutilAvcSetLayoutMode"; - case 0x01f04d94: return "cellSysutilGamePowerOff_I"; - case 0x02ff3c1b: return "cellSysutilUnregisterCallback"; - case 0x073b89d5: return "cellSysutilAvcGetSpeakerVolumeLevel"; - case 0x08269f37: return "cellSysutilAvcGetShowStatus"; - case 0x0bae8772: return "cellVideoOutConfigure"; - case 0x0c316b87: return "cellWebBrowserConfigGetHeapSize2"; - case 0x0e091c36: return "cellSaveDataUserListAutoSave"; - case 0x0f03cfb0: return "cellSaveDataUserListSave"; - case 0x0f8a3b6b: return "cellWebBrowserConfigSetMimeSet"; - case 0x10cabeff: return "cellWebBrowserGetUsrdataOnGameExit"; - case 0x15b0b0cd: return "cellVideoOutGetConfiguration"; - case 0x15df71ed: return "cellSysutilAvcLoadAsync"; - case 0x17dbe8b3: return "cellSysutilAvcJoinRequest"; - case 0x189a74da: return "cellSysutilCheckCallback"; - case 0x1a91874b: return "cellWebBrowserConfigSetFullScreen2"; - case 0x1d99c3ee: return "cellOskDialogGetInputText"; - case 0x1dfbfdd6: return "cellSaveDataListLoad2"; - case 0x1dfcce99: return "cellSysutilGameDataExit"; - case 0x1e7bff94: return "cellSysCacheMount"; - case 0x1e930eef: return "cellVideoOutGetDeviceInfo"; - case 0x1f6629e4: return "cellWebBrowserConfigSetErrorHook2"; - case 0x20543730: return "cellMsgDialogClose"; - case 0x21425307: return "cellSaveDataListAutoLoad"; - case 0x21fc0c71: return "cellGameUnregisterDiscChangeCallback"; - case 0x220894e3: return "cellSysutilEnableBgmPlayback"; - case 0x24644561: return "cellWebBrowserWakeupWithGameExit"; - case 0x248bd1d8: return "cellSaveDataUserListAutoLoad"; - case 0x27ac51e4: return "cellStorageDataImportMove"; - case 0x2a8eada2: return "cellSaveDataFixedLoad2"; - case 0x2a95d8bc: return "cellSysutilGameExit_I"; - case 0x2aae9ef5: return "cellSaveDataFixedSave2"; - case 0x2beac488: return "cellAudioOutGetSoundAvailability2"; - case 0x2dbc92c7: return "cellSysutilAvcShowPanel"; - case 0x2de0d663: return "cellSaveDataListSave2"; - case 0x30d3d12b: return "cellSysutilGameReboot_I"; - case 0x3261a9c8: return "cellWebBrowserConfigSetDisableTabs"; - case 0x35beade0: return "cellOskDialogGetSize"; - case 0x39dd8425: return "cellSaveDataUserListLoad"; - case 0x3d1e1931: return "cellOskDialogUnloadAsync"; - case 0x3dbd2314: return "cellSaveDataListSave"; - case 0x3e22cb4b: return "cellMsgDialogOpenErrorCode"; - case 0x4056c932: return "cellSysutilAvcSetVoiceMuting"; - case 0x40b34847: return "cellSaveDataUserFixedSave"; - case 0x40e895d3: return "cellSysutilGetSystemParamInt"; - case 0x41bc2ca1: return "cellSaveDataFixedSave"; - case 0x41f20828: return "cellOskDialogDisableDimmer"; - case 0x4692ab35: return "cellAudioOutConfigure"; - case 0x46a0285d: return "cellWebBrowserDeactivate"; - case 0x4b6e8560: return "cellWebBrowserCreateRenderWithRect2"; - case 0x4bdec82a: return "cellHddGameCheck2"; - case 0x4dd03a4e: return "cellSaveDataListAutoSave"; - case 0x50183b44: return "cellSaveDataFixedLoad"; - case 0x523a96c4: return "cellGameDataSetSystemVer"; - case 0x52aac4fa: return "cellSaveDataUserAutoSave"; - case 0x52d9457a: return "cellWebBrowserConfigSetFullVersion2"; - case 0x53e39df3: return "cellOskDialogSetSeparateWindowOption"; - case 0x55e425c3: return "cellVideoOutGetConvertCursorColorInfo"; - case 0x58c89c4a: return "cellWebBrowserEstimate"; - case 0x5e91bc26: return "cellSysutilAvcEnumPlayers"; - case 0x5ee3bc26: return "cellSysutilAvcGetVoiceMuting"; - case 0x60a4daab: return "cellWebBrowserConfigSetVersion"; - case 0x6144f033: return "cellWebComponentCreateAsync"; - case 0x619b1427: return "cellWebBrowserConfigSetTabCount2"; - case 0x62b0f803: return "cellMsgDialogAbort"; - case 0x68bc4ff3: return "cellAudioOutRegisterCallback"; - case 0x6c1082aa: return "cellWebBrowserConfigWithVer"; - case 0x6c673f78: return "cellSysutilAvcUnloadAsync"; - case 0x6cfd856f: return "cellSysutilGetBgmPlaybackStatus2"; - case 0x6d087930: return "cellWebBrowserEstimate2"; - case 0x6d7444e6: return "cellWebBrowserActivate"; - case 0x6dfff31d: return "cellWebBrowserSetSystemCallbackUsrdata"; - case 0x6e7264ed: return "cellSaveDataUserFixedLoad"; - case 0x71acb8d3: return "cellSysutilAvcSetVideoMuting"; - case 0x744c1544: return "cellSysCacheClear"; - case 0x749c9b5f: return "cellWebBrowserInitialize"; - case 0x75bbb672: return "cellVideoOutGetNumberOfDevice"; - case 0x7603d3db: return "cellMsgDialogOpen2"; - case 0x7663e368: return "cellAudioOutGetDeviceInfo"; - case 0x76948bfc: return "cellSysconfAbort"; - case 0x76fc8fb1: return "cellWebBrowserConfigSetHeapSize"; - case 0x7871bed4: return "cellVideoOutUnregisterCallback"; - case 0x7bc2c8a8: return "cellMsgDialogProgressBarReset"; - case 0x7d94ca36: return "cellSysutilAvcGetVideoMuting"; - case 0x7f21c918: return "cellOskDialogAddSupportLanguage"; - case 0x7f881be1: return "cellWebBrowserCreate"; - case 0x7f896a1f: return "cellWebBrowserConfigSetCustomExit"; - case 0x7fb3c6a5: return "cellWebBrowserConfig2"; - case 0x7fcfc915: return "cellOskDialogLoadAsync"; - case 0x83668b8e: return "cellWebBrowserConfig"; - case 0x887572d5: return "cellVideoOutGetState"; - case 0x8a4cb646: return "cellWebBrowserCreateWithConfig"; - case 0x8a5dbb58: return "cellWebComponentCreate"; - case 0x8b7ed64b: return "cellSaveDataAutoSave2"; - case 0x8b8a2f48: return "cellSaveDataUserFixedDelete"; - case 0x8e8bc444: return "cellVideoOutRegisterCallback"; - case 0x9117df20: return "cellHddGameCheck"; - case 0x918288fb: return "cellStorageDataImport"; - case 0x938013a0: return "cellSysutilGetSystemParamString"; - case 0x93c523c6: return "cellWebBrowserConfigSetNotifyHook2"; - case 0x93ced48d: return "cellWebBrowserShutdown"; - case 0x94862702: return "cellMsgDialogProgressBarInc"; - case 0x9949bf82: return "cellGameDataExitBroken"; - case 0x9997e6b6: return "cellSysutilGameDataAssignVmc"; - case 0x9c9fe6a4: return "cellWebBrowserConfigSetFunction"; - case 0x9ca9ffa7: return "cellHddGameSetSystemVer"; - case 0x9d6af72a: return "cellMsgDialogProgressBarSetMsg"; - case 0x9d98afa0: return "cellSysutilRegisterCallback"; - case 0x9dfdad46: return "cellAudioOutUnregisterCallback"; - case 0x9fb97b10: return "cellWebBrowserNavigate2"; - case 0xa11552f6: return "cellSysutilGetBgmPlaybackStatus"; - case 0xa322db75: return "cellVideoOutGetResolutionAvailability"; - case 0xa36335a5: return "cellSysutilDisableBgmPlaybackEx"; - case 0xa4dd11cc: return "cellWebBrowserConfigGetHeapSize"; - case 0xa4ed7dfe: return "cellSaveDataDelete"; - case 0xa58943f8: return "cellWebBrowserCreateWithRect2"; - case 0xa5f12145: return "cellWebBrowserCreate2"; - case 0xa9a439e0: return "cellWebBrowserConfigSetUnknownMIMETypeHook2"; - case 0xa9b0c1d9: return "cellGameDataGetSizeKB"; - case 0xa9b62ac8: return "cellWebBrowserConfigSetViewRect2"; - case 0xabc3cd2c: return "cellStorageDataExport"; - case 0xac16777e: return "cellWebBrowserConfigSetStatusHook2"; - case 0xac58ad2b: return "cellSysutilEnableBgmPlaybackEx"; - case 0xafd605b3: return "cellHddGameExitBroken"; - case 0xaffdadc0: return "cellSysutilAvcSetSpeakerVolumeLevel"; - case 0xb2b6cdd0: return "cellSysconfOpen"; - case 0xb53b3d42: return "cellWebBrowserCreateWithConfigFull"; - case 0xb53c54fa: return "cellOskDialogSetKeyLayoutOption"; - case 0xb6d84526: return "cellOskDialogAbort"; - case 0xb72bc4e6: return "cellDiscGameGetBootDiscInfo"; - case 0xbccd70dd: return "cellSysutilAvcCancelJoinRequest"; - case 0xbed85cb8: return "cellWebBrowserDestroy"; - case 0xc01b4e7c: return "cellAudioOutGetSoundAvailability"; - case 0xc22c79b5: return "cellSaveDataAutoLoad"; - case 0xc427890c: return "cellOskDialogSetInitialKeyLayout"; - case 0xc8971db5: return "cellWebBrowserSetLocalContentsAdditionalTitleID"; - case 0xc9645c41: return "cellGameDataCheckCreate2"; - case 0xc96e89e9: return "cellAudioOutSetCopyControl"; - case 0xcdc6aefd: return "cellSaveDataUserAutoLoad"; - case 0xced17573: return "cellSaveDataFixedDelete"; - case 0xcfdd8e87: return "cellSysutilDisableBgmPlayback"; - case 0xcfdf24bb: return "cellVideoOutDebugSetMonitorType"; - case 0xd3790a86: return "cellOskDialogSetDeviceMask"; - case 0xd7a617f5: return "cellWebBrowserConfigSetViewCondition2"; - case 0xd9ea5709: return "cellSysutilAvcHidePanel"; - case 0xdce51399: return "cellWebComponentDestroy"; - case 0xdfdd302e: return "cellDiscGameRegisterDiscChangeCallback"; - case 0xe22ed55d: return "cellWebBrowserConfigSetFunction2"; - case 0xe558748d: return "cellVideoOutGetResolution"; - case 0xe5e2b09d: return "cellAudioOutGetNumberOfDevice"; - case 0xe7951dee: return "cellGameDataCheckCreate"; - case 0xe7fa820b: return "cellSaveDataEnableOverlay"; - case 0xe8dee79c: return "cellWebBrowserDestroy2"; - case 0xeb9d78d8: return "cellSysutilAvcGetLayoutMode"; - case 0xeca938ca: return "cellSysutilAvcSetAttribute"; - case 0xed5d96af: return "cellAudioOutGetConfiguration"; - case 0xedadd797: return "cellSaveDataDelete2"; - case 0xedc34e1a: return "cellDiscGameUnregisterDiscChangeCallback"; - case 0xee7528f3: return "cellWebBrowserConfigSetRequestHook2"; - case 0xef5a353d: return "cellSaveDataListLoad"; - case 0xf0ec3ccc: return "cellOskDialogSetLayoutMode"; - case 0xf1a443e7: return "cellWebBrowserCreateRender2"; - case 0xf2c4a425: return "cellSysutilAvcByeRequest"; - case 0xf3b4b43e: return "cellOskDialogSetInitialInputDevice"; - case 0xf3dbf5a7: return "cellSysutilSetBgmPlaybackExtraParam"; - case 0xf481967f: return "cellSysutilAvcGetAttribute"; - case 0xf4aa8b27: return "cellSysutilAvcCancelByeRequest"; - case 0xf4e3caa0: return "cellAudioOutGetState"; - case 0xf8115d69: return "cellGameRegisterDiscChangeCallback"; - case 0xf81eca25: return "cellMsgDialogOpen"; - case 0xf82e2ef7: return "cellHddGameGetSizeKB"; - case 0xf8a175ec: return "cellSaveDataAutoSave"; - case 0xfbd5c856: return "cellSaveDataAutoLoad2"; - case 0xfe669845: return "cellWebBrowserConfigSetHeapSize2"; - case 0x3343824c: return "cellSysutilApOn"; - case 0x90c2bb19: return "cellSysutilApOff"; - case 0x9e67e0dd: return "cellSysutilApGetRequiredMemSize"; - case 0x02c5417a: return "cellSysutilAvc2GetPlayerInfo"; - case 0x02dc41ee: return "cellSysutilAvc2JoinChat"; - case 0x04e1e1e4: return "cellSysutilAvc2StopStreaming"; - case 0x07236c83: return "cellSysutilAvc2ChangeVideoResolution"; - case 0x0b45cd84: return "cellSysutilAvc2ShowScreen"; - case 0x0f5a2afb: return "cellSysutilAvc2GetVideoMuting"; - case 0x103d6b46: return "cellSysutilAvc2GetWindowAttribute"; - case 0x11f071cb: return "cellSysutilAvc2StopStreaming2"; - case 0x14937714: return "cellSysutilAvc2SetVoiceMuting"; - case 0x16ff9ba0: return "cellSysutilAvc2StartVoiceDetection"; - case 0x17481336: return "cellSysutilAvc2UnloadAsync"; - case 0x178982d9: return "cellSysutilAvc2StopVoiceDetection"; - case 0x1be2b4e0: return "cellSysutilAvc2GetAttribute"; - case 0x1d73ab8c: return "cellSysutilAvc2LoadAsync"; - case 0x207621a8: return "cellSysutilAvc2SetSpeakerVolumeLevel"; - case 0x225142bd: return "cellSysutilAvc2SetWindowString"; - case 0x2f280883: return "cellSysutilAvc2EstimateMemoryContainerSize"; - case 0x2fc0ab58: return "cellSysutilAvc2SetVideoMuting"; - case 0x31fc8b92: return "cellSysutilAvc2SetPlayerVoiceMuting"; - case 0x3447668a: return "cellSysutilAvc2SetStreamingTarget"; - case 0x38f33624: return "cellSysutilAvc2Unload"; - case 0x3a37e7f1: return "cellSysutilAvc2DestroyWindow"; - case 0x3c8c827c: return "cellSysutilAvc2SetWindowPosition"; - case 0x3ef4f668: return "cellSysutilAvc2GetSpeakerVolumeLevel"; - case 0x4c4b9665: return "cellSysutilAvc2IsCameraAttached"; - case 0x55d7bbfd: return "cellSysutilAvc2MicRead"; - case 0x5f3811f8: return "cellSysutilAvc2GetPlayerVoiceMuting"; - case 0x712d51d6: return "cellSysutilAvc2JoinChatRequest"; - case 0x74d22119: return "cellSysutilAvc2StartStreaming"; - case 0x7a69ecc1: return "cellSysutilAvc2SetWindowAttribute"; - case 0x82ced772: return "cellSysutilAvc2GetWindowShowStatus"; - case 0x89456724: return "cellSysutilAvc2InitParam"; - case 0x8a40a618: return "cellSysutilAvc2GetWindowSize"; - case 0x8c2f5be3: return "cellSysutilAvc2SetStreamPriority"; - case 0x97b2da6a: return "cellSysutilAvc2LeaveChatRequest"; - case 0xa26aa437: return "cellSysutilAvc2IsMicAttached"; - case 0xa8dc0efa: return "cellSysutilAvc2CreateWindow"; - case 0xa9f5b75c: return "cellSysutilAvc2GetSpeakerMuting"; - case 0xac170042: return "cellSysutilAvc2ShowWindow"; - case 0xaee75751: return "cellSysutilAvc2SetWindowSize"; - case 0xb81b9777: return "cellSysutilAvc2EnumPlayers"; - case 0xb856b63f: return "cellSysutilAvc2GetWindowString"; - case 0xbf022284: return "cellSysutilAvc2LeaveChat"; - case 0xc35ed665: return "cellSysutilAvc2SetSpeakerMuting"; - case 0xc6c93d62: return "cellSysutilAvc2Load"; - case 0xccf0aeff: return "cellSysutilAvc2SetAttribute"; - case 0xce6780c9: return "cellSysutilAvc2UnloadAsync2"; - case 0xd42657dd: return "cellSysutilAvc2StartStreaming2"; - case 0xd7d6272f: return "cellSysutilAvc2HideScreen"; - case 0xde6afc37: return "cellSysutilAvc2HideWindow"; - case 0xdf2ed367: return "cellSysutilAvc2GetVoiceMuting"; - case 0xe40e3dfc: return "cellSysutilAvc2GetScreenShowStatus"; - case 0xf3b5ff77: return "cellSysutilAvc2Unload2"; - case 0xfc2873a9: return "cellSysutilAvc2GetWindowPosition"; - case 0x1b6e8cd2: return "cellSysutilAvcExtSetWindowRotation"; - case 0x22a36b23: return "cellSysutilAvcExtGetWindowPosition"; - case 0x22ca0929: return "cellSysutilAvcExtSetHideNamePlate"; - case 0x245ff230: return "cellSysutilAvcExtSetWindowPosition"; - case 0x28f0dc04: return "cellSysutilAvcExtGetWindowSize"; - case 0x2d9a1997: return "cellSysutilAvcExtGetWindowShowStatus"; - case 0x326fab55: return "cellSysutilAvcExtGetNamePlateShowStatus"; - case 0x332ee22c: return "cellSysutilAvcExtSetWindowAlpha"; - case 0x40bc33c8: return "cellSysutilAvcExtSetWindowSize"; - case 0x4466c0e2: return "cellSysutilAvcExtShowPanelEx"; - case 0x51ccbe09: return "cellSysutilAvcExtLoadAsyncEx"; - case 0x5a763d0e: return "cellSysutilAvcExtSetShowNamePlate"; - case 0x5ba98e47: return "cellSysutilAvcExtStopVoiceDetection"; - case 0x61b1cb18: return "cellSysutilAvcExtShowWindow"; - case 0x683fe299: return "cellSysutilAvcExtHidePanelEx"; - case 0x739c2f63: return "cellSysutilAvcExtHideWindow"; - case 0x8ed310e5: return "cellSysutilAvcExtGetWindowRotation"; - case 0xaed82c21: return "cellSysutilAvcExtGetWindowAlpha"; - case 0xc851a4c0: return "cellSysutilAvcExtStartVoiceDetection"; - case 0xcbe0c10a: return "cellSysutilAvcExtGetSurfacePointer"; - case 0xd8685383: return "cellSysutilAvcExtInitOptionParam"; - case 0xe8b1c18d: return "cellSysutilAvcExtSetWindowZorder"; - case 0x0bddef7d: return "cellAudioOutUnregisterDevice"; - case 0x18d0ada6: return "cellAudioOutGetDeviceInfo2"; - case 0x1cfa1a11: return "cellVideoOutSetXVColor"; - case 0x269ffedd: return "cellVideoOutSetupDisplay"; - case 0x3d5730ce: return "cellAudioInGetDeviceInfo"; - case 0x4ec8c141: return "cellVideoOutConvertCursorColor"; - case 0x655a0364: return "cellVideoOutGetGamma"; - case 0x65bf9ea3: return "cellAudioInGetAvailableDeviceInfo"; - case 0xc3273d9b: return "cellAudioOutGetAvailableDeviceInfo"; - case 0xc7020f62: return "cellVideoOutSetGamma"; - case 0xc7087631: return "cellAudioOutRegisterDevice"; - case 0xe4645af8: return "cellAudioOutSetDeviceMode"; - case 0xeb6c50fb: return "cellAudioInSetDeviceMode"; - case 0xeb6fcff1: return "cellAudioInRegisterDevice"; - case 0xfa6bcc17: return "cellAudioInUnregisterDevice"; - case 0xfaa275a4: return "cellVideoOutGetScreenSize"; - case 0x571dc686: return "cellSysutilGetLicenseArea"; - case 0x074dbb39: return "cellUsbdAllocateMemory"; - case 0x0f411262: return "cellUsbdInterruptTransfer"; - case 0x254289ac: return "cellUsbdOpenPipe"; - case 0x2fb08e1e: return "cellUsbdScanStaticDescriptor"; - case 0x359befba: return "cellUsbdRegisterLdd"; - case 0x35f22ac3: return "cellUsbdEnd"; - case 0x4e456e81: return "cellUsbdFreeMemory"; - case 0x5c832bd7: return "cellUsbdSetThreadPriority2"; - case 0x5de3af36: return "cellUsbdGetPrivateData"; - case 0x63bfdb97: return "cellUsbdSetPrivateData"; - case 0x64951ac7: return "cellUsbdUnregisterLdd"; - case 0x7a1b6eab: return "cellUsbdHSIsochronousTransfer"; - case 0x7fe92c54: return "cellUsbdRegisterExtraLdd"; - case 0x90460081: return "cellUsbdUnregisterExtraLdd"; - case 0x9763e962: return "cellUsbdClosePipe"; - case 0x97cf128e: return "cellUsbdControlTransfer"; - case 0xac77eb78: return "cellUsbdBulkTransfer"; - case 0xbd554bcb: return "cellUsbdRegisterExtraLdd2"; - case 0xbdbd2428: return "cellUsbdGetDeviceSpeed"; - case 0xc24af1d7: return "cellUsbdSetThreadPriority"; - case 0xd0e766fe: return "cellUsbdInit"; - case 0xd5263dea: return "cellUsbdGetThreadPriority"; - case 0xdb819e03: return "cellUsbdGetDeviceLocation"; - case 0xde58c4c2: return "cellUsbdIsochronousTransfer"; - case 0x01a4cde0: return "cellUsbPspcmPollBindAsync"; - case 0x02955295: return "cellUsbPspcmRecvAsync"; - case 0x0f7b3b6d: return "cellUsbPspcmEnd"; - case 0x17f42197: return "cellUsbPspcmBindAsync"; - case 0x3caddf6c: return "cellUsbPspcmWaitSendAsync"; - case 0x3f22403e: return "cellUsbPspcmPollResetAsync"; - case 0x461dc8cc: return "cellUsbPspcmWaitRecvAsync"; - case 0x4abe830e: return "cellUsbPspcmWaitBindAsync"; - case 0x4af23efa: return "cellUsbPspcmSendAsync"; - case 0x4ef182dd: return "cellUsbPspcmResetAsync"; - case 0x657fcd36: return "cellUsbPspcmInit"; - case 0x7277d7c3: return "cellUsbPspcmSend"; - case 0x7b249315: return "cellUsbPspcmPollRecvAsync"; - case 0x7f0a3eaf: return "cellUsbPspcmPollSendAsync"; - case 0x7ff72b42: return "cellUsbPspcmUnregister"; - case 0x816799dd: return "cellUsbPspcmPollData"; - case 0x97670a90: return "cellUsbPspcmGetAddr"; - case 0xa4a5ddb4: return "cellUsbPspcmCancelBind"; - case 0xabe090e3: return "cellUsbPspcmBind"; - case 0xdb864d11: return "cellUsbPspcmWaitData"; - case 0xe3fbf64d: return "cellUsbPspcmRegister"; - case 0xe68a65ac: return "cellUsbPspcmReset"; - case 0xe76e79ab: return "cellUsbPspcmCancelWaitData"; - case 0xe840f449: return "cellUsbPspcmWaitResetAsync"; - case 0xf20df7fc: return "cellUsbPspcmCalcPoolSize"; - case 0xf9883d3b: return "cellUsbPspcmRecv"; - case 0xfa07d320: return "cellUsbPspcmClose"; - case 0x2b761140: return "cellUserInfoGetStat"; - case 0x3097cc1c: return "cellUserInfoSelectUser_ListType"; - case 0x55123a25: return "cellUserInfoSelectUser_SetList"; - case 0xb3516536: return "cellUserInfoEnableOverlay"; - case 0xc55e338b: return "cellUserInfoGetList"; - case 0x1bb79ff4: return "cellVideoExportProgress"; - case 0x2f457571: return "cellVideoExportInitialize2"; - case 0x6a24cc70: return "cellVideoExportInitialize"; - case 0x81296524: return "cellVideoExportFromFile"; - case 0xc15be817: return "cellVideoExportFinalize"; - case 0x122e0d0f: return "cellVideoUploadInitialize"; - case 0x0a563878: return "cellVoiceStart"; - case 0x18d3df30: return "cellVoiceDisconnectIPortFromOPort"; - case 0x20bafe31: return "cellVoiceDebugTopology"; - case 0x2a01013e: return "cellVoiceCreateNotifyEventQueue"; - case 0x2de54871: return "cellVoiceCreatePort"; - case 0x2f24fea3: return "cellVoiceUpdatePort"; - case 0x30f0b5ab: return "cellVoiceWriteToIPortEx"; - case 0x35d84910: return "cellVoiceSetNotifyEventQueue"; - case 0x36472c57: return "cellVoiceReadFromOPort"; - case 0x3dad26e7: return "cellVoiceWriteToIPort"; - case 0x474609e2: return "cellVoiceGetMuteFlag"; - case 0x54ac3519: return "cellVoiceGetPortInfo"; - case 0x762dc193: return "cellVoiceGetVolume"; - case 0x7bf17b15: return "cellVoiceResumePort"; - case 0x7e60adc6: return "cellVoiceSetBitRate"; - case 0x7f3963f7: return "cellVoiceResumePortAll"; - case 0x87c71b06: return "cellVoicePausePort"; - case 0x94d51f92: return "cellVoiceStartEx"; - case 0x9d0f4af1: return "cellVoiceSetPortAttr"; - case 0x9f70c475: return "cellVoiceDeletePort"; - case 0xae6a21d5: return "cellVoiceConnectIPortToOPort"; - case 0xb1a2c38f: return "cellVoiceInitEx"; - case 0xbef53a2b: return "cellVoiceGetBitRate"; - case 0xc7cf1182: return "cellVoiceInit"; - case 0xd14e784d: return "cellVoicePausePortAll"; - case 0xd3a84be1: return "cellVoiceStop"; - case 0xd4d80ea5: return "cellVoiceSetMuteFlagAll"; - case 0xd5ae37d8: return "cellVoiceSetVolume"; - case 0xd6811aa7: return "cellVoiceGetSignalState"; - case 0xdd000886: return "cellVoiceRemoveNotifyEventQueue"; - case 0xdde35a0c: return "cellVoiceSetMuteFlag"; - case 0xe0e1ae12: return "cellVoiceEnd"; - case 0xf629ed67: return "cellVoiceGetPortAttr"; - case 0xff0fa43a: return "cellVoiceResetPort"; - case 0x10ef39f6: return "cellVpostClose"; - case 0x40524325: return "cellVpostOpenEx"; - case 0x95e788c3: return "cellVpostQueryAttr"; - case 0xabb8cc3d: return "cellVpostExec"; - case 0xcd33f3e2: return "cellVpostOpen"; - case 0x02eb41bb: return "cellGemGetEnvironmentLightingColor"; - case 0x0ecd2261: return "cellGemUpdateStart"; - case 0x13ea7c64: return "cellGemInit"; - case 0x18ea899a: return "cellGemGetTrackerHue"; - case 0x1a13d010: return "cellGemConvertVideoFinish"; - case 0x1a2518a2: return "cellGemEnableMagnetometer"; - case 0x1b30cc22: return "cellGemGetRGB"; - case 0x1f6328d8: return "cellGemWriteExternalPort"; - case 0x2d2c2764: return "cellGemGetAllTrackableHues"; - case 0x2e0a170d: return "cellGemGetMemorySize"; - case 0x41ae9c31: return "cellGemUpdateFinish"; - case 0x4219de31: return "cellGemEnableCameraPitchAngleCorrection"; - case 0x49609306: return "cellGemSetRumble"; - case 0x6441d38d: return "cellGemGetState"; - case 0x6a5b7048: return "cellGemGetAccelerometerPositionInDevice"; - case 0x6db6b007: return "cellGemGetRumble"; - case 0x6dce048c: return "cellGemConvertVideoStart"; - case 0x6fc4c791: return "cellGemFilterState"; - case 0x77e08704: return "cellGemSetYaw"; - case 0x8befac67: return "cellGemGetCameraState"; - case 0x928ac5f8: return "cellGemTrackHues"; - case 0x92cc4b34: return "cellGemGetImageState"; - case 0x9b9714a4: return "cellGemClearStatusFlags"; - case 0x9e1dff96: return "cellGemGetInfo"; - case 0xa03ef587: return "cellGemPrepareCamera"; - case 0xafa99ead: return "cellGemCalibrate"; - case 0xb8ef56a6: return "cellGemGetHuePixels"; - case 0xc07896f9: return "cellGemPrepareVideoConvert"; - case 0xc7622586: return "cellGemHSVtoRGB"; - case 0xce6d7791: return "cellGemForceRGB"; - case 0xd37b127a: return "cellGemGetInertialState"; - case 0xde54e2fc: return "cellGemReset"; - case 0xe1f85a80: return "cellGemEnd"; - case 0xe3e4f0d6: return "cellGemInvalidateCalibration"; - case 0xfb5887f9: return "cellGemIsTrackableHue"; - case 0xfee33481: return "cellGemGetStatusFlags"; - case 0x40ad67eb: return "cellMediatorCreateContext"; - case 0x4aecea24: return "cellMediatorGetSignatureLength"; - case 0x4d249136: return "cellMediatorGetUserInfo"; - case 0x5d4431f0: return "cellMediatorFlushCache"; - case 0x6b8f5cb9: return "cellMediatorSign"; - case 0x85dc6981: return "cellMediatorPostReports"; - case 0x9d11991d: return "cellMediatorGetProviderUrl"; - case 0xa14c6000: return "cellMediatorReliablePostReports"; - case 0xc324f60c: return "cellMediatorCloseContext"; - case 0xf7e4a50a: return "cellMediatorGetStatus"; - case 0x0053e2d8: return "cellVdecOpenEx"; - case 0x16698e83: return "cellVdecClose"; - case 0x17c702b9: return "cellVdecGetPicItem"; - case 0x2bf4ddd2: return "cellVdecDecodeAu"; - case 0x807c861a: return "cellVdecGetPicture"; - case 0x824433f0: return "cellVdecEndSeq"; - case 0xb6bbcd5d: return "cellVdecOpen"; - case 0xc757c2aa: return "cellVdecStartSeq"; - case 0xc982a84a: return "cellVdecQueryAttrEx"; - case 0xe13ef6fc: return "cellVdecSetFrameRate"; - case 0xff6f6ebe: return "cellVdecQueryAttr"; - case 0x000e53cc: return "sceNpManagerSubSignout"; - case 0x01cd9cfd: return "sceNpCommerceGetChildProductSkuInfo"; - case 0x01fbbc9b: return "sceNpBasicSendMessageGui"; - case 0x03c741a7: return "sceNpMatchingGetResult"; - case 0x04372385: return "sceNpBasicGetFriendListEntry"; - case 0x04ca5e6a: return "sceNpScoreRecordGameData"; - case 0x0561448b: return "sceNpCommerceGetDataFlagAbort"; - case 0x05af1cb8: return "sceNpBasicGetMatchingInvitationEntry"; - case 0x05d65dff: return "sceNpScoreGetRankingByNpId"; - case 0x0968aa36: return "sceNpManagerGetTicket"; - case 0x14497465: return "sceNpMatchingQuickMatchGUI"; - case 0x155de760: return "sceNpSignalingGetConnectionInfo"; - case 0x166dcc11: return "sceNpLookupNpId"; - case 0x1672170e: return "sceNpScoreRecordScore"; - case 0x168a3117: return "sceNpBasicAddPlayersHistory"; - case 0x168fcece: return "sceNpManagerGetAccountAge"; - case 0x16f88a6f: return "sceNpManagerGetPsHandle"; - case 0x1a2704f7: return "sceNpScoreWaitAsync"; - case 0x1a3fcb69: return "sceNpCommerceGetSkuUserData"; - case 0x1ae8a549: return "sceNpBasicAddBlockListEntry"; - case 0x1fdb3ec2: return "sceNpLookupUserProfileWithAvatarSizeAsync"; - case 0x21206642: return "sceNpScoreGetRankingByRangeAsync"; - case 0x227f8763: return "sceNpScoreGetClansRankingByClanIdAsync"; - case 0x259113b8: return "sceNpScoreDestroyTitleCtx"; - case 0x260caedd: return "sceNpBasicGetFriendPresenceByNpId2"; - case 0x2687a127: return "sceNpSignalingGetCtxOpt"; - case 0x26b3bc94: return "sceNpMatchingGetResultGUI"; - case 0x26f33146: return "sceNpCommerceGetProductCategoryStart"; - case 0x2706eaa1: return "sceNpScoreSetPlayerCharacterId"; - case 0x276c72b2: return "sceNpSignalingSetCtxOpt"; - case 0x27c69eba: return "sceNpBasicAddFriend"; - case 0x29dd45dc: return "sceNpScoreSetTimeout"; - case 0x2a76895a: return "sceNpScoreGetClansRankingByClanId"; - case 0x2ad7837d: return "sceNpMatchingAcceptInvitationGUI"; - case 0x2be41ece: return "sceNpCommerceGetNumOfChildCategory"; - case 0x2cd2a1af: return "sceNpScoreSanitizeCommentAsync"; - case 0x2e1c5068: return "sceNpMatchingDestroyCtx"; - case 0x2ecd48ed: return "sceNpDrmVerifyUpgradeLicense"; - case 0x2f2c6b3e: return "sceNpProfileAbortGui"; - case 0x2fccbfe0: return "sceNpLookupUserProfileWithAvatarSize"; - case 0x30d1cbde: return "sceNpBasicGetMessageEntry"; - case 0x32200389: return "sceNpManagerGetMyLanguages"; - case 0x32c78a6a: return "sceNpBasicGetFriendPresenceByIndex"; - case 0x32cf311f: return "sceNpScoreInit"; - case 0x32febb4c: return "sceNpMatchingSearchJoinRoomGUI"; - case 0x34cc0ca4: return "sceNpMatchingKickRoomMember"; - case 0x34ce82a0: return "sceNpSignalingGetConnectionFromPeerAddress"; - case 0x359642a6: return "sceNpCommerceGetCategoryDescription"; - case 0x36d0c2c5: return "sceNpManagerGetAvatarUrl"; - case 0x39a69619: return "sceNpCommerceGetSkuId"; - case 0x3b02418d: return "sceNpScoreGetGameData"; - case 0x3cc8588a: return "sceNpMatchingCreateRoomGUI"; - case 0x3d1760dc: return "sceNpLookupAbortTransaction"; - case 0x3db7914d: return "sceNpScoreGetRankingByNpIdAsync"; - case 0x3f0808aa: return "sceNpBasicSetPresence"; - case 0x3f195b3a: return "sceNpCommerceGetProductCategoryResult"; - case 0x4026eac5: return "sceNpBasicRegisterContextSensitiveHandler"; - case 0x41ffd4f2: return "sceNpScoreGetClansMembersRankingByNpIdPcId"; - case 0x433fcb30: return "sceNpScoreGetClansMembersRankingByNpIdPcIdAsync"; - case 0x43b989f5: return "sceNpBasicSendMessageAttachment"; - case 0x442381f7: return "sceNpManagerSubSignin"; - case 0x45f8f3aa: return "sceNpCustomMenuRegisterActions"; - case 0x474b7b13: return "sceNpMatchingJoinRoomGUI"; - case 0x481ce0e8: return "sceNpBasicAbortGui"; - case 0x4885aa18: return "sceNpTerm"; - case 0x4a18a89e: return "sceNpMatchingSetRoomInfoNoLimit"; - case 0x4b9efb7a: return "sceNpManagerGetCachedInfo"; - case 0x4d5e0670: return "sceNpScoreGetClansMembersRankingByRangeAsync"; - case 0x4d9c615d: return "sceNpBasicGetClanMessageEntry"; - case 0x50b86d94: return "sceNpSignalingAddExtendedHandler"; - case 0x52a6b523: return "sceNpManagerUnregisterCallback"; - case 0x58fa4fcd: return "sceNpManagerGetTicketParam"; - case 0x5d543bbe: return "sceNpBasicGetMessageAttachmentEntry"; - case 0x5de61626: return "sceNpLookupDestroyTitleCtx"; - case 0x5e117ed5: return "sceNpLookupTitleStorageAsync"; - case 0x5e849303: return "sceNpBasicSetPresenceDetails2"; - case 0x5f2d9257: return "sceNpLookupInit"; - case 0x60440c73: return "sceNpManagerSubSigninAbortGui"; - case 0x60897c38: return "sceNpSignalingActivateConnection"; - case 0x6356082e: return "sceNpSignalingCreateCtx"; - case 0x6453b27b: return "sceNpBasicGetFriendPresenceByIndex2"; - case 0x64a704cc: return "sceNpBasicRecvMessageAttachmentLoad"; - case 0x64dbb89d: return "sceNpSignalingCancelPeerNetInfo"; - case 0x674bb9ff: return "sceNpCommerceGetProductCategoryAbort"; - case 0x691f429d: return "sceNpMatchingGetRoomInfo"; - case 0x6cb81eb2: return "sceNpCommerceDestroyProductCategory"; - case 0x6d4adc3b: return "sceNpScoreGetClansMembersRankingByRange"; - case 0x6e2ab18b: return "sceNpCommerceGetCategoryName"; - case 0x6ee62ed2: return "sceNpManagerGetContentRatingFlag"; - case 0x6f5e8143: return "sceNpScoreCreateTransactionCtx"; - case 0x6f8fd267: return "sceNpMatchingSetRoomInfo"; - case 0x71e5af7e: return "sceNpLookupSetTimeout"; - case 0x7208dc08: return "sceNpCommerceGetNumOfChildProductSku"; - case 0x73931bd0: return "sceNpBasicGetBlockListEntryCount"; - case 0x73a2e36b: return "sceNpMatchingGetRoomMemberListLocal"; - case 0x741fbf24: return "sceNpScoreGetClanMemberGameData"; - case 0x7508112e: return "sceNpLookupPollAsync"; - case 0x75eb50cb: return "sceNpSignalingGetPeerNetInfo"; - case 0x78d7f9ad: return "sceNpCommerceGetSkuPrice"; - case 0x79225aa3: return "sceNpCommerceGetCurrencyCode"; - case 0x7b7e9137: return "sceNpScoreGetClansRankingByRangeAsync"; - case 0x7be47e61: return "sceNpScoreCensorCommentAsync"; - case 0x7deb244c: return "sceNpScoreCensorComment"; - case 0x7e2fef28: return "sceNpManagerRequestTicket"; - case 0x806960ab: return "sceNpBasicRecvMessageCustom"; - case 0x816c6a5f: return "_sceNpSysutilClientFree"; - case 0x8297f1ec: return "sceNpManagerRequestTicket2"; - case 0x8440537c: return "sceNpLookupTerm"; - case 0x860b1756: return "sceNpLookupTitleSmallStorageAsync"; - case 0x8b7bbd73: return "sceNpMatchingSendInvitationGUI"; - case 0x8d1d096c: return "sceNpCommerceInitProductCategory"; - case 0x8d4518a0: return "sceNpCommerceSetDataFlagFinish"; - case 0x9153bdf4: return "sceNpBasicGetMessageAttachmentEntryCount"; - case 0x9281e87a: return "sceNpCommerceGetDataFlagFinish"; - case 0x936df4aa: return "sceNpCommerceGetProductId"; - case 0x9452f4f8: return "sceNpCommerceGetCategoryImageURL"; - case 0x9458f464: return "sceNpCustomMenuRegisterExceptionList"; - case 0x95c7bba3: return "sceNpSignalingTerminateConnection"; - case 0x9851f805: return "sceNpScoreTerm"; - case 0x99ac9952: return "sceNpCommerceSetDataFlagStart"; - case 0x9ad7fbd1: return "sceNpSignalingGetLocalNetInfo"; - case 0x9ee9f97e: return "sceNpLookupTitleStorage"; - case 0xa15f35fe: return "sceNpBasicGetPlayersHistoryEntryCount"; - case 0xa1709abd: return "sceNpManagerGetEntitlementById"; - case 0xa284bd1d: return "sceNpMatchingSetRoomSearchFlag"; - case 0xa7a090e5: return "sceNpScorePollAsync"; - case 0xa7bff757: return "sceNpManagerGetStatus"; - case 0xa85a4951: return "sceNpCommerceGetSkuDescription"; - case 0xa8afa7d4: return "sceNpBasicGetCustomInvitationEntryCount"; - case 0xa8cf8451: return "sceNpSignalingDestroyCtx"; - case 0xaa16695f: return "sceNpDrmProcessExitSpawn"; - case 0xac66568c: return "sceNpMatchingCreateCtx"; - case 0xacb9ee8e: return "sceNpBasicUnregisterHandler"; - case 0xad218faf: return "sceNpDrmIsAvailable"; - case 0xaee8cf71: return "sceNpCommerceGetCategoryId"; - case 0xaf3eba5a: return "sceNpCommerceDoCheckoutFinishAsync"; - case 0xaf505def: return "sceNpBasicGetMatchingInvitationEntryCount"; - case 0xaf57d9c9: return "sceNpCommerceGetCurrencyDecimals"; - case 0xafef640d: return "sceNpBasicGetFriendListEntryCount"; - case 0xb020684e: return "sceNpMatchingGetRoomInfoNoLimit"; - case 0xb082003b: return "sceNpScoreGetClansRankingByRange"; - case 0xb1c02d66: return "sceNpCommerceGetCurrencyInfo"; - case 0xb1e0718b: return "sceNpManagerGetAccountRegion"; - case 0xb5cb2d56: return "sceNpBasicRecvMessageAttachment"; - case 0xb6017827: return "sceNpLookupAvatarImage"; - case 0xb66d1c46: return "sceNpManagerGetEntitlementIdList"; - case 0xb9f93bbb: return "sceNpScoreCreateTitleCtx"; - case 0xba65de6d: return "sceNpCommerceGetChildCategoryInfo"; - case 0xbab91fc9: return "sceNpBasicGetPlayersHistoryEntry"; - case 0xbcc09fe7: return "sceNpBasicRegisterHandler"; - case 0xbcdbb2ab: return "sceNpBasicAddPlayersHistoryAsync"; - case 0xbd28fdbf: return "sceNpInit"; - case 0xbdc07fd5: return "sceNpManagerGetNetworkTime"; - case 0xbe07c708: return "sceNpManagerGetOnlineId"; - case 0xbe0e3ee2: return "sceNpDrmVerifyUpgradeLicense2"; - case 0xbe81c71c: return "sceNpBasicSetPresenceDetails"; - case 0xbef887e5: return "sceNpScoreGetClanMemberGameDataAsync"; - case 0xbf607ec6: return "sceNpBasicGetClanMessageEntryCount"; - case 0xbf9eea93: return "sceNpLookupAvatarImageAsync"; - case 0xc3a991ee: return "sceNpScoreGetRankingByNpIdPcId"; - case 0xc4b6cd8f: return "sceNpScoreGetRankingByNpIdPcIdAsync"; - case 0xc5f4cf82: return "sceNpScoreDestroyTransactionCtx"; - case 0xca0a2d04: return "sceNpSignalingGetConnectionStatus"; - case 0xca39c4b2: return "sceNpLookupTitleSmallStorage"; - case 0xccbe2e69: return "sceNpCommerceGetSkuImageURL"; - case 0xce81c7f0: return "sceNpLookupCreateTitleCtx"; - case 0xceeebc7a: return "sceNpProfileCallGui"; - case 0xcf51864b: return "sceNpDrmGetTimelimit"; - case 0xcfd469e4: return "sceNpCommerceGetProductCategoryFinish"; - case 0xd03cea35: return "sceNpCommerceGetDataFlagState"; - case 0xd053f113: return "sceNpBasicGetCustomInvitationEntry"; - case 0xd0958814: return "sceNpSignalingGetPeerNetInfoResult"; - case 0xd12e40ae: return "sceNpLookupNpIdAsync"; - case 0xd208f91d: return "sceNpUtilCmpNpId"; - case 0xd20d7798: return "sceNpMatchingKickRoomMemberWithOpt"; - case 0xd737fd2d: return "sceNpLookupWaitAsync"; - case 0xd7fb1fa6: return "sceNpFriendlistCustom"; - case 0xdae2d351: return "sceNpMatchingGrantOwnership"; - case 0xdb2e4dc2: return "sceNpScoreGetGameDataAsync"; - case 0xdbdb909f: return "sceNpCommerceGetDataFlagStart"; - case 0xddce7d15: return "sceNpScoreGetBoardInfoAsync"; - case 0xded17c26: return "sceNpScoreGetClansMembersRankingByNpId"; - case 0xdfd63b62: return "sceNpLookupUserProfile"; - case 0xe035f7d6: return "sceNpBasicGetEvent"; - case 0xe1c9f675: return "sceNpBasicMarkMessageAsUsed"; - case 0xe24eea19: return "sceNpMatchingGetRoomListLimitGUI"; - case 0xe2877bea: return "sceNpCommerceDestroyCtx"; - case 0xe36c660e: return "sceNpCommerceDoCheckoutStartAsync"; - case 0xe6c8f3f9: return "sceNpDrmProcessExitSpawn2"; - case 0xe7dcd3b4: return "sceNpManagerRegisterCallback"; - case 0xe853d388: return "sceNpSignalingGetConnectionFromNpId"; - case 0xe8a67160: return "sceNpScoreGetClansMembersRankingByNpIdAsync"; - case 0xea2e9ffc: return "sceNpLookupCreateTransactionCtx"; - case 0xeb5f2544: return "sceNpCommerceGetProductName"; - case 0xeb7a3d84: return "sceNpManagerGetChatRestrictionFlag"; - case 0xeb9df054: return "sceNpCommerceGetCategoryInfo"; - case 0xec0a1fbf: return "sceNpBasicSendMessage"; - case 0xecd503de: return "sceNpBasicGetMessageEntryCount"; - case 0xee0cc40c: return "_sceNpSysutilClientMalloc"; - case 0xee530059: return "sceNpCommerceGetSkuName"; - case 0xee5b20d9: return "sceNpScoreAbortTransaction"; - case 0xee64cf8e: return "sceNpMatchingGetRoomSearchFlag"; - case 0xf042b14f: return "sceNpDrmIsAvailable2"; - case 0xf0a9182b: return "sceNpFriendlist"; - case 0xf0b1e399: return "sceNpScoreRecordScoreAsync"; - case 0xf1b77918: return "sceNpScoreSanitizeComment"; - case 0xf283c143: return "sceNpDrmExecuteGamePurchase"; - case 0xf2b3338a: return "sceNpBasicGetBlockListEntry"; - case 0xf42c0df8: return "sceNpManagerGetOnlineName"; - case 0xf4e0f607: return "sceNpScoreGetBoardInfo"; - case 0xf59e1da8: return "sceNpFriendlistAbortGui"; - case 0xf5ff5f31: return "sceNpUtilCmpNpIdInOrder"; - case 0xf76847c2: return "sceNpScoreRecordGameDataAsync"; - case 0xf806c54c: return "sceNpMatchingLeaveRoom"; - case 0xf9732ac8: return "sceNpCustomMenuActionSetActivation"; - case 0xfb87cf5e: return "sceNpLookupDestroyTransactionCtx"; - case 0xfbc82301: return "sceNpScoreGetRankingByRange"; - case 0xfcac355a: return "sceNpCommerceCreateCtx"; - case 0xfd0eb5ae: return "sceNpSignalingDeactivateConnection"; - case 0xfd39ae13: return "sceNpBasicGetFriendPresenceByNpId"; - case 0xfe37a7f4: return "sceNpManagerGetNpId"; - case 0xff0a2378: return "sceNpLookupUserProfileAsync"; - case 0x01379fd7: return "sceNpMatching2DestroyContext"; - case 0x02065e3d: return "sceNpMatching2LeaveLobby"; - case 0x03a2f42a: return "sceNpMatching2RegisterLobbyMessageCallback"; - case 0x05bf2fbd: return "sceNpMatching2GetWorldInfoList"; - case 0x0884fc95: return "sceNpMatching2RegisterLobbyEventCallback"; - case 0x0b2218a3: return "sceNpMatching2GetLobbyMemberDataInternalList"; - case 0x0d22867f: return "sceNpMatching2SearchRoom"; - case 0x0ebe4c6b: return "sceNpMatching2SignalingGetConnectionStatus"; - case 0x1022e6d6: return "sceNpMatching2SetUserInfo"; - case 0x12034412: return "sceNpMatching2GetClanLobbyId"; - case 0x129663d0: return "sceNpMatching2GetLobbyMemberDataInternal"; - case 0x12d0b0f9: return "sceNpMatching2ContextStart"; - case 0x16b3e5a4: return "sceNpMatching2CreateServerContext"; - case 0x196a06f9: return "sceNpMatching2GetMemoryInfo"; - case 0x1f372697: return "sceNpMatching2LeaveRoom"; - case 0x215b0d75: return "sceNpMatching2SetRoomDataExternal"; - case 0x23009d07: return "sceNpMatching2Term2"; - case 0x26ae9ff8: return "sceNpMatching2SignalingGetConnectionInfo"; - case 0x28cad8b3: return "sceNpMatching2SendRoomMessage"; - case 0x29e78389: return "sceNpMatching2JoinLobby"; - case 0x2c5b7fc9: return "sceNpMatching2GetRoomMemberDataExternalList"; - case 0x2ed909dc: return "sceNpMatching2AbortRequest"; - case 0x2fe0da7d: return "sceNpMatching2Term"; - case 0x3457c0db: return "sceNpMatching2GetServerInfo"; - case 0x3c00c9d4: return "sceNpMatching2GetEventData"; - case 0x3cc27344: return "sceNpMatching2GetRoomSlotInfoLocal"; - case 0x3f3bd413: return "sceNpMatching2SendLobbyChatMessage"; - case 0x3f62c759: return "sceNpMatching2Init"; - case 0x41251f74: return "sceNp2Init"; - case 0x430ce063: return "sceNpMatching2AbortContextStart"; - case 0x490124fd: return "sceNpMatching2GetRoomMemberIdListLocal"; - case 0x5721e711: return "sceNpMatching2JoinRoom"; - case 0x58a04247: return "sceNpMatching2GetRoomMemberDataInternalLocal"; - case 0x62d446ac: return "sceNpMatching2GetCbQueueInfo"; - case 0x66f19527: return "sceNpMatching2KickoutRoomMember"; - case 0x6ba4c668: return "sceNpMatching2ContextStartAsync"; - case 0x6fcd84c1: return "sceNpMatching2SetSignalingOptParam"; - case 0x748029a2: return "sceNpMatching2RegisterContextCallback"; - case 0x7bf6e152: return "sceNpMatching2SendRoomChatMessage"; - case 0x817d1090: return "sceNpMatching2SetRoomDataInternal"; - case 0x8b209ca2: return "sceNpMatching2GetRoomDataInternal"; - case 0x8d3f8d49: return "sceNpMatching2SignalingGetPingInfo"; - case 0x8e5cfe9f: return "sceNpMatching2GetServerIdListLocal"; - case 0x8e930999: return "sceNpUtilBuildCdnUrl"; - case 0x9344d41f: return "sceNpMatching2GrantRoomOwner"; - case 0x9cbce3f2: return "sceNpMatching2CreateContext"; - case 0xa2b01449: return "sceNpMatching2GetSignalingOptParamLocal"; - case 0xa9e6103e: return "sceNpMatching2RegisterSignalingCallback"; - case 0xaa6c2c43: return "sceNpMatching2ClearEventData"; - case 0xaadb7c12: return "sceNp2Term"; - case 0xac98b03a: return "sceNpMatching2GetUserInfoList"; - case 0xb0c51412: return "sceNpMatching2GetRoomMemberDataInternal"; - case 0xb851aacf: return "sceNpMatching2SetRoomMemberDataInternal"; - case 0xba578d19: return "sceNpMatching2JoinProhibitiveRoom"; - case 0xbf014813: return "sceNpMatching2SignalingSetCtxOpt"; - case 0xc6b63b7e: return "sceNpMatching2DeleteServerContext"; - case 0xdb87b088: return "sceNpMatching2SetDefaultRequestOptParam"; - case 0xdcb6b27d: return "sceNpMatching2RegisterRoomEventCallback"; - case 0xde6d308b: return "sceNpMatching2GetRoomPasswordLocal"; - case 0xe4ac32ca: return "sceNpMatching2GetRoomDataExternalList"; - case 0xe7a3bc7a: return "sceNpMatching2CreateJoinRoom"; - case 0xe9946648: return "sceNpMatching2SignalingGetCtxOpt"; - case 0xefbd9357: return "sceNpMatching2GetLobbyInfoList"; - case 0xeffe5a16: return "sceNpMatching2GetLobbyMemberIdListLocal"; - case 0xefff8779: return "sceNpMatching2SendLobbyInvitation"; - case 0xf43c647a: return "sceNpMatching2ContextStop"; - case 0xf4babd3f: return "sceNpMatching2Init2"; - case 0xfa0583c6: return "sceNpMatching2SetLobbyMemberDataInternal"; - case 0xfee11e72: return "sceNpMatching2RegisterRoomMessageCallback"; - case 0x095e12c6: return "sceNpClansSendInvitationResponse"; - case 0x09f9e1a9: return "sceNpClansUpdateClanInfo"; - case 0x0df25834: return "sceNpClansRetrieveChallenges"; - case 0x1221a1bf: return "sceNpClansSearchByProfile"; - case 0x20472da0: return "sceNpClansGetMemberInfo"; - case 0x299ccc9b: return "sceNpClansCancelMembershipRequest"; - case 0x38dadf1f: return "sceNpClansGetAutoAcceptStatus"; - case 0x42332cb7: return "sceNpClansTerm"; - case 0x4826f6d5: return "sceNpClansDisbandClan"; - case 0x487de998: return "sceNpClansGetClanInfo"; - case 0x4d06aef7: return "sceNpClansAddBlacklistEntry"; - case 0x560f717b: return "sceNpClansLeaveClan"; - case 0x56bc5a7c: return "sceNpClansGetBlacklist"; - case 0x59743b2b: return "sceNpClansSendMembershipRequest"; - case 0x5bff9da1: return "sceNpClansRemoveBlacklistEntry"; - case 0x5da94854: return "sceNpClansUpdateAutoAcceptStatus"; - case 0x672399a8: return "sceNpClansGetClanListByNpId"; - case 0x726dffd5: return "sceNpClansCancelInvitation"; - case 0x727aa7f8: return "sceNpClansRetrieveAnnouncements"; - case 0x83d65529: return "sceNpClansPostChallenge"; - case 0x856ff5c0: return "sceNpClansGetMemberList"; - case 0x8e785b97: return "sceNpClansRetrievePostedChallenges"; - case 0x942dbdc4: return "sceNpClansSendMembershipResponse"; - case 0x9a72232d: return "sceNpClansCreateRequest"; - case 0x9b820047: return "sceNpClansInit"; - case 0x9cac2085: return "sceNpClansChangeMemberRole"; - case 0xa6a31a38: return "sceNpClansCreateClan"; - case 0xaa7912b5: return "sceNpClansKickMember"; - case 0xace0cfba: return "sceNpClansSearchByName"; - case 0xada45b84: return "sceNpClansPostAnnouncement"; - case 0xbc05ef31: return "sceNpClansSendInvitation"; - case 0xca4181b4: return "sceNpClansGetClanList"; - case 0xce6dc0f0: return "sceNpClansRemoveChallenge"; - case 0xd3346dc4: return "sceNpClansRemovePostedChallenge"; - case 0xd6551cd1: return "sceNpClansDestroyRequest"; - case 0xdbf300ca: return "sceNpClansJoinClan"; - case 0xe2590f60: return "sceNpClansRemoveAnnouncement"; - case 0xe82969e2: return "sceNpClansAbortRequest"; - case 0xf4a2d52b: return "sceNpClansUpdateMemberInfo"; - case 0x104551a6: return "sceNpCommerce2DoCheckoutStartAsync"; - case 0x146618df: return "sceNpCommerce2GetProductInfoListGetResult"; - case 0x150fdca3: return "sceNpCommerce2GetContentRatingDescriptor"; - case 0x1fa1b312: return "sceNpCommerce2GetStoreBrowseUserdata"; - case 0x2a910f05: return "sceNpCommerce2DestroyReq"; - case 0x3539d233: return "sceNpCommerce2Init"; - case 0x371a2edd: return "sceNpCommerce2GetCategoryContentsStart"; - case 0x3d627d81: return "sceNpCommerce2GetBGDLAvailability"; - case 0x410d42be: return "sceNpCommerce2DoDlListFinishAsync"; - case 0x4d4a094c: return "sceNpCommerce2Term"; - case 0x62023e98: return "sceNpCommerce2CreateSessionAbort"; - case 0x6ca9efd4: return "sceNpCommerce2DoDlListStartAsync"; - case 0x6f67ea80: return "sceNpCommerce2DestroyCtx"; - case 0x7370d8d0: return "sceNpCommerce2GetCategoryContentsCreateReq"; - case 0x8df0057f: return "sceNpCommerce2AbortReq"; - case 0x8f46325b: return "sceNpCommerce2GetProductInfoStart"; - case 0x91f8843d: return "sceNpCommerce2CreateSessionFinish"; - case 0x972ab46c: return "sceNpCommerce2GetContentInfo"; - case 0x9825a0fc: return "sceNpCommerce2DoProductBrowseStartAsync"; - case 0x9cde07cc: return "sceNpCommerce2GetProductInfoListStart"; - case 0x9d9cb96b: return "sceNpCommerce2DestroyGetCategoryContentsResult"; - case 0xa5a863fe: return "sceNpCommerce2SetBGDLAvailability"; - case 0xa975ebb4: return "sceNpCommerce2GetProductInfoCreateReq"; - case 0xa9f945b3: return "sceNpCommerce2DoProductCodeFinishAsync"; - case 0xac78c1f3: return "sceNpCommerce2GetContentRatingInfoFromCategoryInfo"; - case 0xb23e3bd1: return "sceNpCommerce2DoProductBrowseFinishAsync"; - case 0xbd49eab2: return "sceNpCommerce2GetCategoryInfo"; - case 0xbf5f58ea: return "sceNpCommerce2GetProductInfoGetResult"; - case 0xca0ea996: return "sceNpCommerce2GetCategoryContentsGetResult"; - case 0xcc18cd2c: return "sceNpCommerce2CreateSessionStart"; - case 0xd43a130e: return "sceNpCommerce2DoCheckoutFinishAsync"; - case 0xd8a473a3: return "sceNpCommerce2InitGetCategoryContentsResult"; - case 0xd9956ce7: return "sceNpCommerce2GetGameProductInfoFromGetProductInfoListResult"; - case 0xd9fdcec2: return "sceNpCommerce2CreateCtx"; - case 0xda8e322d: return "sceNpCommerce2GetPrice"; - case 0xdb19194c: return "sceNpCommerce2GetGameSkuInfoFromGameProductInfo"; - case 0xde7ab33d: return "sceNpCommerce2DoProductCodeStartAsync"; - case 0xe0f90e44: return "sceNpCommerce2InitGetProductInfoListResult"; - case 0xe1e7b5ac: return "sceNpCommerce2GetProductInfoListCreateReq"; - case 0xe51a4944: return "sceNpCommerce2GetGameProductInfoFromContentInfo"; - case 0xec324c8f: return "sceNpCommerce2GetContentRatingInfoFromGameProductInfo"; - case 0xeef51be0: return "sceNpCommerce2ExecuteStoreBrowse"; - case 0xef645654: return "sceNpCommerce2GetGameProductInfo"; - case 0xef8eafcd: return "sceNpCommerce2DestroyGetProductInfoResult"; - case 0xf6139b58: return "sceNpCommerce2DestroyGetProductInfoListResult"; - case 0xf798f5e3: return "sceNpCommerce2InitGetProductInfoResult"; - case 0xfc216890: return "sceNpCommerce2GetCategoryInfoFromContentInfo"; - case 0x079f0e87: return "sceNpTrophyGetGameProgress"; - case 0x1197b52c: return "sceNpTrophyRegisterContext"; - case 0x1c25470d: return "sceNpTrophyCreateHandle"; - case 0x27deda93: return "sceNpTrophySetSoundLevel"; - case 0x370136fe: return "sceNpTrophyGetRequiredDiskSpace"; - case 0x3741ecc7: return "sceNpTrophyDestroyContext"; - case 0x39567781: return "sceNpTrophyInit"; - case 0x48bd97c7: return "sceNpTrophyAbortHandle"; - case 0x49d18217: return "sceNpTrophyGetGameInfo"; - case 0x623cd2dc: return "sceNpTrophyDestroyHandle"; - case 0x8ceedd21: return "sceNpTrophyUnlockTrophy"; - case 0xa7fabf4d: return "sceNpTrophyTerm"; - case 0xb3ac3478: return "sceNpTrophyGetTrophyUnlockState"; - case 0xbaedf689: return "sceNpTrophyGetTrophyIcon"; - case 0xe3bf9a28: return "sceNpTrophyCreateContext"; - case 0xfce6d30a: return "sceNpTrophyGetTrophyInfo"; - case 0xff299e03: return "sceNpTrophyGetGameIcon"; - case 0x01711e81: return "sceNpTusDeleteMultiSlotDataVUser"; - case 0x0423e622: return "sceNpTusGetMultiSlotVariable"; - case 0x065b610d: return "sceNpTusSetMultiSlotVariableAsync"; - case 0x0835deb2: return "sceNpTusSetDataVUser"; - case 0x0d15043b: return "sceNpTusGetMultiUserVariable"; - case 0x17db7aa7: return "sceNpTusTryAndSetVariableVUserAsync"; - case 0x1904435e: return "sceNpTusCreateTransactionCtx"; - case 0x19bce18c: return "sceNpTusPollAsync"; - case 0x1fa5c87d: return "sceNpTusAddAndGetVariableAsync"; - case 0x225aed26: return "sceNpTusTerm"; - case 0x2357ba9e: return "sceNpTusGetMultiSlotVariableVUser"; - case 0x2ab21ea9: return "sceNpTusGetMultiSlotDataStatusVUserAsync"; - case 0x2d1b9f1a: return "sceNpTusGetMultiUserDataStatusVUser"; - case 0x2e162a62: return "sceNpTusDestroyTitleCtx"; - case 0x3175af23: return "sceNpTusDeleteMultiSlotDataAsync"; - case 0x325c6284: return "sceNpTusAbortTransaction"; - case 0x348dbcb4: return "sceNpTusGetMultiUserDataStatus"; - case 0x3602bc80: return "sceNpTusTryAndSetVariableVUser"; - case 0x368fec59: return "sceNpTusGetMultiUserDataStatusVUserAsync"; - case 0x38f364b0: return "sceNpTusGetDataVUserAsync"; - case 0x44eca8b4: return "sceNpTusDestroyTransactionCtx"; - case 0x47e9424a: return "sceNpTusTryAndSetVariable"; - case 0x5175abb9: return "sceNpTusGetDataAsync"; - case 0x59432970: return "sceNpTusSetTimeout"; - case 0x651fd79f: return "sceNpTusGetMultiSlotDataStatusAsync"; - case 0x6c511024: return "sceNpTusGetMultiUserVariableVUser"; - case 0x7caf58ee: return "sceNpTusCreateTitleCtx"; - case 0x7d5f0f0e: return "sceNpTusSetData"; - case 0x8ddd0d85: return "sceNpTusGetData"; - case 0x8f87a06b: return "sceNpTusInit"; - case 0x94989003: return "sceNpTusAddAndGetVariable"; - case 0x9549d22c: return "sceNpTusGetMultiUserVariableVUserAsync"; - case 0x96a06212: return "sceNpTusSetMultiSlotVariableVUserAsync"; - case 0x9cc0cf44: return "sceNpTusSetDataVUserAsync"; - case 0xa3abfadb: return "sceNpTusGetMultiSlotDataStatusVUser"; - case 0xa7993bf3: return "sceNpTusAddAndGetVariableVUserAsync"; - case 0xae4e590e: return "sceNpTusGetDataVUser"; - case 0xaf985783: return "sceNpTusDeleteMultiSlotVariable"; - case 0xb8e8ff22: return "sceNpTusWaitAsync"; - case 0xbb2877f2: return "sceNpTusGetMultiSlotVariableAsync"; - case 0xbbb244b7: return "sceNpTusTryAndSetVariableAsync"; - case 0xc2e18da8: return "sceNpTusDeleteMultiSlotVariableVUserAsync"; - case 0xc4e51fbf: return "sceNpTusDeleteMultiSlotVariableVUser"; - case 0xc66ba67e: return "sceNpTusGetMultiUserDataStatusAsync"; - case 0xc815b219: return "sceNpTusDeleteMultiSlotDataVUserAsync"; - case 0xc848d425: return "sceNpTusGetMultiSlotDataStatus"; - case 0xcc7a31cd: return "sceNpTusGetMultiUserVariableAsync"; - case 0xcc86a8f6: return "sceNpTusSetMultiSlotVariable"; - case 0xe0719847: return "sceNpTusDeleteMultiSlotData"; - case 0xe847341f: return "sceNpTusSetDataAsync"; - case 0xf5363608: return "sceNpTusDeleteMultiSlotVariableAsync"; - case 0xf60be06f: return "sceNpTusAddAndGetVariableVUser"; - case 0xf819be91: return "sceNpTusSetMultiSlotVariableVUser"; - case 0xfc7d346e: return "sceNpTusGetMultiSlotVariableVUserAsync"; - case 0x432b3cbf: return "sceNpUtilBandwidthTestShutdown"; - case 0xc2ced2b7: return "sceNpUtilBandwidthTestInitStart"; - case 0xc880f37d: return "sceNpUtilBandwidthTestGetStatus"; - case 0xc99ee313: return "sceNpUtilBandwidthTestAbort"; - case 0x02671310: return "cellFsSetDefaultContainer"; - case 0x0d5b4a14: return "cellFsReadWithOffset"; - case 0x0e2939e5: return "cellFsFtruncate"; - case 0x103b8632: return "cellFsAllocateFileAreaWithInitialData"; - case 0x190912f6: return "cellFsStReadGetCurrentAddr"; - case 0x1a108ab7: return "cellFsGetBlockSize"; - case 0x1ea02e2f: return "cellFsArcadeHddSerialNumber"; - case 0x2664c8ae: return "cellFsStReadInit"; - case 0x27800c6b: return "cellFsStRead"; - case 0x2796fdf3: return "cellFsRmdir"; - case 0x2cb51f0d: return "cellFsClose"; - case 0x2cf1296b: return "cellFsAllocateFileAreaByFdWithoutZeroFill"; - case 0x3140f6e1: return "cellFsSetIoBuffer"; - case 0x3394f037: return "cellFsAllocateFileAreaByFdWithInitialData"; - case 0x3a1c8393: return "cellFsTruncate2"; - case 0x3f61245c: return "cellFsOpendir"; - case 0x4cef342e: return "cellFsAioWrite"; - case 0x4d5ff8e2: return "cellFsRead"; - case 0x5c74903d: return "cellFsReaddir"; - case 0x606f9f42: return "cellFsChangeFileSizeWithoutAllocation"; - case 0x6d3bb15b: return "cellFsSdataOpenByFd"; - case 0x718bf5f8: return "cellFsOpen"; - case 0x75f16dc5: return "cellFsSetIoBufferFromDefaultContainer"; - case 0x7a0329a1: return "cellFsAllocateFileAreaWithoutZeroFill"; - case 0x7de6dced: return "cellFsStat"; - case 0x7f13fc8c: return "cellFsAioCancel"; - case 0x7f4677a8: return "cellFsUnlink"; - case 0x81f33783: return "cellFsStReadPutCurrentAddr"; - case 0x866f6aec: return "cellFsStReadWaitCallback"; - case 0x8cb722d5: return "cellFsWriteWithOffset"; - case 0x8df28ff9: return "cellFsStReadStart"; - case 0x8f71c5b2: return "cellFsStReadWait"; - case 0x91a1beaa: return "cellFsSetDiscReadRetrySetting"; - case 0x967a162b: return "cellFsFsync"; - case 0x99406d0b: return "cellFsChmod"; - case 0x9b882495: return "cellFsGetDirectoryEntries"; - case 0x9f951810: return "cellFsAioFinish"; - case 0xa01ee33a: return "cellFsRegisterConversionCallback"; - case 0xa397d042: return "cellFsLseek"; - case 0xaa3b4bcd: return "cellFsGetFreeSize"; - case 0xb1840b53: return "cellFsSdataOpen"; - case 0xb3afee8b: return "cellFsStReadGetRingBuf"; - case 0xba901fe6: return "cellFsMkdir"; - case 0xbd273a88: return "cellFsStReadGetRegid"; - case 0xbef554a4: return "cellFsUtime"; - case 0xc1c507e7: return "cellFsAioRead"; - case 0xc9dc3ac5: return "cellFsTruncate"; - case 0xcb588dba: return "cellFsFGetBlockSize"; - case 0xcf34969c: return "cellFsStReadGetStatus"; - case 0xd73938df: return "cellFsStReadFinish"; - case 0xdb869f20: return "cellFsAioInit"; - case 0xe15939c3: return "cellFsChangeFileSizeByFdWithoutAllocation"; - case 0xecdcf2ab: return "cellFsWrite"; - case 0xef3efa34: return "cellFsFstat"; - case 0xf12eecc8: return "cellFsRename"; - case 0xf8e5d9a0: return "cellFsStReadStop"; - case 0xf94baa80: return "cellFsUnregisterL10nCallbacks"; - case 0xff42dcc3: return "cellFsClosedir"; - case 0x068fcbc6: return "sys_config_start"; - case 0x0d5f2c14: return "cellPadClearBuf"; - case 0x0e2dfaad: return "cellPadInfoPressMode"; - case 0x1cf98800: return "cellPadInit"; - case 0x1f71ecbe: return "cellKbGetConfiguration"; - case 0x2073b7f6: return "cellKbClearBuf"; - case 0x20a97ba2: return "cellPadLddRegisterController"; - case 0x21a62e9b: return "cellMouseGetTabletDataList"; - case 0x2d16da4f: return "cellMouseSetTabletMode"; - case 0x2f1774d5: return "cellKbGetInfo"; - case 0x3138e632: return "cellMouseGetData"; - case 0x3aaad464: return "cellPadGetInfo"; - case 0x3ef66b95: return "cellMouseClearBuf"; - case 0x3f72c56e: return "cellKbSetLEDStatus"; - case 0x3f797dff: return "cellPadGetRawData"; - case 0x433f6ec0: return "cellKbInit"; - case 0x4ab1fa77: return "cellKbCnvRawCode"; - case 0x4cc9b68d: return "cellPadPeriphGetInfo"; - case 0x4d0b3b1f: return "cellMouseInfoTabletMode"; - case 0x4d9b75d5: return "cellPadEnd"; - case 0x578e3c98: return "cellPadSetPortSetting"; - case 0x5baf30fb: return "cellMouseGetInfo"; - case 0x5f81900c: return "sys_config_unregister_service"; - case 0x6ae10596: return "sys_config_add_service_listener"; - case 0x6bc09c61: return "cellPadGetDataExtra"; - case 0x6bd131f0: return "cellMouseGetDataList"; - case 0x6d367953: return "sys_config_stop"; - case 0x78200559: return "cellPadInfoSensorMode"; - case 0x78f058a2: return "sys_config_register_service"; - case 0x7c5d5fc1: return "cellPadDbgPeriphRegisterDevice"; - case 0x8a00f264: return "cellPadPeriphGetData"; - case 0x8b72cda1: return "cellPadGetData"; - case 0x8b8231e5: return "cellPadLddGetPortNo"; - case 0x94b98e39: return "cellPadDbgLddSetDataInsertMode"; - case 0xa328cc35: return "cellMouseGetRawData"; - case 0xa5f85e4d: return "cellKbSetCodeType"; - case 0xa703a51d: return "cellPadGetInfo2"; - case 0xa74396e5: return "cellPadDbgLddRegisterController"; - case 0xbafd6409: return "cellPadLddDataInsert"; - case 0xbe5be3ba: return "cellPadSetSensorMode"; - case 0xbfce3285: return "cellKbEnd"; - case 0xc9030138: return "cellMouseInit"; - case 0xcf3051f7: return "cellPadDbgGetData"; - case 0xdeefdfa7: return "cellKbSetReadMode"; - case 0xe10183ce: return "cellMouseEnd"; - case 0xe442faa8: return "cellPadLddUnregisterController"; - case 0xf5d9d571: return "sys_config_remove_service_listener"; - case 0xf65544ee: return "cellPadSetActDirect"; - case 0xf83f8182: return "cellPadSetPressMode"; - case 0xff0a21b7: return "cellKbRead"; - case 0x00acf0e5: return "spu_printf_finalize"; - case 0x00fb4a6b: return "spu_thread_sprintf"; - case 0x0125b2ca: return "_rand_int32_TT800"; - case 0x01508f24: return "raw_spu_write_float"; - case 0x0264f468: return "_Wctomb"; - case 0x02f4d325: return "spu_thread_read_double"; - case 0x02f52a3c: return "_filep_close_it"; - case 0x03becf3c: return "_Defloc"; - case 0x04a183fc: return "strcpy"; - case 0x04a1f19d: return "raw_spu_write_short"; - case 0x05d821c4: return "_Stoullx"; - case 0x077cdb23: return "btowc"; - case 0x07c7971d: return "_Stoldx"; - case 0x0871ffb0: return "mspace_malloc_usable_size"; - case 0x0891a3fa: return "_Tlsfree"; - case 0x09cbee1e: return "strxfrm"; - case 0x0a1d4b00: return "spu_thread_read_uint"; - case 0x0a4e2541: return "spu_thread_read_ldouble"; - case 0x0ae275a4: return "_Stolx"; - case 0x0b0d272f: return "_malloc_finalize"; - case 0x0b9d04d0: return "_Getnloc"; - case 0x0b9ecb98: return "toupper_ascii"; - case 0x0cae547f: return "raw_spu_write_double"; - case 0x0d2a593b: return "srand"; - case 0x0d8a2de0: return "_CStrxfrm"; - case 0x0df8809f: return "__call_functions_registered_with_atexit"; - case 0x0f60eb63: return "vfwscanf"; - case 0x0ff4722c: return "raw_spu_read_ushort"; - case 0x1096f8f1: return "ispunct_ascii"; - case 0x1098a99d: return "localeconv"; - case 0x112ea8ea: return "strspn"; - case 0x115e2f70: return "spu_thread_snprintf"; - case 0x116cda13: return "wcstol"; - case 0x118712ea: return "islower"; - case 0x11d270d2: return "exitspawn"; - case 0x126656b7: return "_Btowc"; - case 0x128b334f: return "raw_spu_read_mem"; - case 0x12a55fb7: return "mbrtowc"; - case 0x130d20a5: return "towlower"; - case 0x1365b52a: return "fcntl"; - case 0x13808972: return "wcstok"; - case 0x14052ae0: return "absi4"; - case 0x14348b57: return "divi4"; - case 0x145853cd: return "mspace_destroy"; - case 0x15362bc9: return "spu_thread_read_long"; - case 0x153b364a: return "mkdir"; - case 0x15bdcc00: return "rand"; - case 0x15c2e29d: return "isgraph_ascii"; - case 0x17752bab: return "wcsftime"; - case 0x17bc0136: return "_Lrv2d"; - case 0x17c031d7: return "spu_thread_read_ulong"; - case 0x1855b9b1: return "setlocale"; - case 0x1895908d: return "mspace_realloc"; - case 0x18e48b5d: return "wscanf"; - case 0x18f7b77d: return "_Dnorm"; - case 0x1970cd7e: return "getpid"; - case 0x19ccbb81: return "mktime"; - case 0x1ab01ea8: return "truncate"; - case 0x1abd0985: return "div"; - case 0x1ae06860: return "wcstoumax"; - case 0x1b4c3ff0: return "atexit"; - case 0x1c0e8ab6: return "vswscanf"; - case 0x1c2ef212: return "getwc"; - case 0x1cf4d80a: return "iswalpha"; - case 0x1dcd8609: return "_Strxfrmx"; - case 0x1dd0d4c5: return "spu_printf_attach_group"; - case 0x1df4732e: return "_Getptolower"; - case 0x1e9d2b4f: return "spu_thread_read_int"; - case 0x1ecae195: return "_Vacopy"; - case 0x1f913e8d: return "chmod"; - case 0x1f925c41: return "_allocate_mapped_pages"; - case 0x206612c4: return "spu_thread_read_ptr"; - case 0x216984ed: return "spu_thread_write_long"; - case 0x216fcd2a: return "_Atrealloc"; - case 0x21807b8e: return "towctrans"; - case 0x225702e1: return "_fs_initialize"; - case 0x22b0e566: return "_Stollx"; - case 0x23d3bca7: return "_Eadd"; - case 0x242c603e: return "_Frprep"; - case 0x243b52d8: return "_Mbtowcx"; - case 0x24802244: return "iswcntrl"; - case 0x24c9e021: return "abs"; - case 0x24e230d2: return "_Wctob"; - case 0x24f6cbdd: return "clock"; - case 0x253b7210: return "_rand_real2_TT800"; - case 0x25beee5a: return "__raw_spu_printf"; - case 0x25da8fbb: return "iscntrl"; - case 0x266311a0: return "localtime"; - case 0x2677568c: return "putchar"; - case 0x26f023d5: return "ftell"; - case 0x273b9711: return "sprintf"; - case 0x28b92ebf: return "raw_spu_read_uchar"; - case 0x296bc72f: return "_FDunscale"; - case 0x2b45cb34: return "wcsrtombs"; - case 0x2b7ba4ca: return "_Tlsset"; - case 0x2b81fb7f: return "readdir"; - case 0x2bc9dee6: return "raw_spu_read_short"; - case 0x2caea755: return "_Once"; - case 0x2d067448: return "ftruncate64"; - case 0x2d17ca7f: return "_Puttxt"; - case 0x2eea9f25: return "_Esub"; - case 0x2f45d39c: return "strlen"; - case 0x2fecec13: return "getwchar"; - case 0x30fb2899: return "_Getmem"; - case 0x312be3b3: return "_malloc_init_lv2"; - case 0x313f04ab: return "raw_spu_read_char"; - case 0x329a4540: return "_WPrintf"; - case 0x32e4a30a: return "_Mtxdst"; - case 0x336b4191: return "_Getint"; - case 0x33d6ae54: return "ferror"; - case 0x344eca7e: return "_WGetstr"; - case 0x34dd6650: return "_Getcloc"; - case 0x34e7c97e: return "_Unlocksyslock"; - case 0x3512ad38: return "tmpnam"; - case 0x355fd1fd: return "mbtowc"; - case 0x3574d37d: return "_Wcsxfrmx"; - case 0x36c067c1: return "_Stoll"; - case 0x36f2b4ed: return "strtoull"; - case 0x36feb965: return "raw_spu_write_llong"; - case 0x3704840e: return "_fs_finalize"; - case 0x38426d25: return "_Wctombx"; - case 0x3902363a: return "malloc_footprint"; - case 0x39bf419c: return "valloc"; - case 0x3a210c93: return "swscanf"; - case 0x3a840ae3: return "snprintf"; - case 0x3b22e88a: return "isxdigit"; - case 0x3b8097ac: return "_WScanf"; - case 0x3bce073b: return "putc"; - case 0x3bd9ce0a: return "fsync"; - case 0x3ca81c76: return "_Iswctype"; - case 0x3d1460e9: return "_Strerror"; - case 0x3d541975: return "atoi"; - case 0x3d5fdea7: return "vfwprintf"; - case 0x3d85d6f8: return "strcmp"; - case 0x3dbc3bee: return "opendir"; - case 0x3e57dfac: return "_Genld"; - case 0x3ec99a66: return "_Getptimes"; - case 0x3ee29d0b: return "_Stof"; - case 0x3f125e2e: return "spu_thread_write_short"; - case 0x3f4ccdc7: return "isdigit"; - case 0x3f650700: return "mspace_is_heap_empty"; - case 0x40a2599a: return "atol"; - case 0x40d04e4e: return "fwide"; - case 0x40e0ff25: return "_WGenld"; - case 0x41283333: return "isdigit_ascii"; - case 0x418bdfe1: return "_get_fd"; - case 0x4217b4cf: return "difftime"; - case 0x433fe2a9: return "fwscanf"; - case 0x44115dd0: return "_Geterrno"; - case 0x44796e5c: return "strerror"; - case 0x449317ed: return "_Fopen"; - case 0x44d7cae8: return "raw_spu_read_float"; - case 0x4544c2de: return "spu_thread_write_mem"; - case 0x4569518c: return "malloc_stats"; - case 0x459072c3: return "_init_TT800"; - case 0x4595c42b: return "wcsxfrm"; - case 0x468b45dc: return "mspace_calloc"; - case 0x4911ff9c: return "rand_int31_TT800"; - case 0x498a5036: return "raw_spu_write_mem"; - case 0x4a0049c6: return "_Getpctype"; - case 0x4ab5fbe2: return "_Printf"; - case 0x4b36c0e0: return "vfscanf"; - case 0x4b6a4010: return "vswprintf"; - case 0x4bb8e2b2: return "raw_spu_write_ushort"; - case 0x4c3f5f29: return "_Getgloballocale"; - case 0x4c7dc863: return "iswupper"; - case 0x4d348427: return "fputs"; - case 0x4e4be299: return "longjmp"; - case 0x4e72f810: return "wmemchr"; - case 0x4ffba189: return "feof"; - case 0x508196b4: return "raw_spu_printf"; - case 0x508e00c6: return "_Getloc"; - case 0x51b28904: return "_Stodx"; - case 0x526a496a: return "write"; - case 0x532b03be: return "raw_spu_read_uint"; - case 0x53eb43a1: return "_Getpmbstate"; - case 0x54b383bc: return "_Locvar"; - case 0x54c2844e: return "spu_raw_snprintf"; - case 0x54f57626: return "rewind"; - case 0x5516bbbf: return "iswctype"; - case 0x55d4866e: return "fgetws"; - case 0x5751acf9: return "_LDscale"; - case 0x575fb268: return "wctrans"; - case 0x57ff7dd7: return "_WStod"; - case 0x58320830: return "_WLitob"; - case 0x589b5314: return "strncat"; - case 0x5909e3c4: return "memset"; - case 0x59640bc6: return "raw_spu_read_ullong"; - case 0x59c1bb1f: return "_Getpwcstate"; - case 0x59e8dd58: return "strtoll"; - case 0x5a74f774: return "spu_thread_read_float"; - case 0x5b162b7f: return "memmove"; - case 0x5b4b6d6d: return "wcspbrk"; - case 0x5cc71eee: return "raw_spu_write_ldouble"; - case 0x5d43c1a3: return "_Mbtowc"; - case 0x5dbceee3: return "rand_int32_TT800"; - case 0x5e06c3fe: return "__getpid"; - case 0x5e7888f0: return "bsearch"; - case 0x5eb95641: return "_Stold"; - case 0x5f922a30: return "_Dscale"; - case 0x5f9a65c7: return "_WStold"; - case 0x5fa1e497: return "_Unlockfilelock"; - case 0x60627fb3: return "_LDunscale"; - case 0x6075a3c6: return "_Ld2rv"; - case 0x609080ec: return "isspace_ascii"; - case 0x6137d196: return "memalign"; - case 0x6287ac6a: return "iswdigit"; - case 0x62bf1d6c: return "swprintf"; - case 0x64aaf016: return "raw_spu_read_ldouble"; - case 0x6514dbe5: return "wcstold"; - case 0x6539ff6d: return "_Gentime"; - case 0x6545b7de: return "fgetpos"; - case 0x65e8d4d0: return "wcslen"; - case 0x6660fc8d: return "TlsGetValue"; - case 0x6687fba4: return "_Fgpos"; - case 0x66b71b17: return "wcsspn"; - case 0x67582370: return "spu_thread_write_double"; - case 0x676e3e7a: return "raw_spu_write_ptr"; - case 0x67d6334b: return "strtof"; - case 0x6823c180: return "iswprint"; - case 0x69106fd2: return "_init_by_array_TT800"; - case 0x692b497f: return "perror"; - case 0x6995f5e8: return "_Ldtob"; - case 0x69c27c12: return "fopen"; - case 0x69ff1b9b: return "fseek"; - case 0x6ba10474: return "_Tlsalloc"; - case 0x6cf78f3e: return "_Mtxunlock"; - case 0x6d5115b0: return "wcsncmp"; - case 0x6e988e5f: return "_rand_int31_TT800"; - case 0x7028dea9: return "_Locksyslock"; - case 0x703ec767: return "setvbuf"; - case 0x70b0e833: return "mblen"; - case 0x714c9618: return "__raw_spu_putfld"; - case 0x717b2502: return "stat"; - case 0x72236cbc: return "raw_spu_write_ullong"; - case 0x72b84004: return "spu_printf_attach_thread"; - case 0x73096858: return "wctob"; - case 0x7345b4be: return "_WStoll"; - case 0x73eae03d: return "strrchr"; - case 0x744d2505: return "ispunct"; - case 0x74fe4a7b: return "iswgraph"; - case 0x759e0635: return "malloc"; - case 0x75d4485c: return "rename"; - case 0x75f98579: return "wcscoll"; - case 0x76da0c84: return "ftruncate"; - case 0x76ed4243: return "_Wcsftime"; - case 0x770bfaee: return "wctype"; - case 0x77a602dd: return "free"; - case 0x77c15441: return "_WGetfloat"; - case 0x77e241bc: return "_Skip"; - case 0x7817edf0: return "raw_spu_write_uint"; - case 0x783636d1: return "spu_thread_read_char"; - case 0x78429d81: return "putwchar"; - case 0x79819dbf: return "fputc"; - case 0x7994c28d: return "_FDtentox"; - case 0x79eadf05: return "malloc_usable_size"; - case 0x7aaab95c: return "iswblank"; - case 0x7ae82e0f: return "vsprintf"; - case 0x7aee5acd: return "_Lockfilelock"; - case 0x7b5aac20: return "spu_thread_write_ptr"; - case 0x7b7a687a: return "_WPutfld"; - case 0x7b9c592e: return "spu_thread_read_ullong"; - case 0x7c1bcf37: return "isalnum_ascii"; - case 0x7c370679: return "_Foprep"; - case 0x7cec7b39: return "_Putfld"; - case 0x7d894764: return "_Readloc"; - case 0x7e7017b1: return "rmdir"; - case 0x7ea8d860: return "spu_printf_detach_group"; - case 0x7efd420a: return "_Daysto"; - case 0x7fd325c4: return "mspace_malloc_stats"; - case 0x7fdcf73e: return "wcscat"; - case 0x806fd281: return "isblank_ascii"; - case 0x809a143f: return "kill"; - case 0x813a9666: return "ungetwc"; - case 0x814d8cb0: return "fflush"; - case 0x81a0a858: return "_memset_int"; - case 0x82a3cc30: return "wcschr"; - case 0x82a4561a: return "_put_fd"; - case 0x831d70a5: return "memcpy"; - case 0x8342b757: return "utime"; - case 0x84378ddc: return "wcsncpy"; - case 0x86532174: return "imaxdiv"; - case 0x867275d7: return "_Stoul"; - case 0x86b4c669: return "tolower_ascii"; - case 0x8713c859: return "link"; - case 0x8725a1a7: return "_memset_vmx"; - case 0x87e8f748: return "memset_vmx"; - case 0x8809cdfd: return "_Getpwctytab"; - case 0x882689f2: return "_Makeloc"; - case 0x882e7760: return "raw_spu_write_uchar"; - case 0x889d5804: return "_Dunscale"; - case 0x88e009f5: return "vwprintf"; - case 0x896e1bfd: return "spu_thread_write_uchar"; - case 0x89b62f56: return "_Etentox"; - case 0x89f6f026: return "time"; - case 0x8a6830e7: return "abort"; - case 0x8a71132c: return "remove"; - case 0x8a847b51: return "tmpfile"; - case 0x8ab0abc6: return "strncpy"; - case 0x8b439438: return "clearerr"; - case 0x8b9d8dd2: return "iswpunct"; - case 0x8cb6bfdc: return "_Locsum"; - case 0x8d7ffaf1: return "_WStopfx"; - case 0x8e2484f1: return "_Emul"; - case 0x8ed71e8b: return "_WGetfld"; - case 0x8ef85e47: return "_WPuttxt"; - case 0x8f5dd179: return "_Nnl"; - case 0x90010029: return "gets"; - case 0x9027fd99: return "_WStoldx"; - case 0x90457fe3: return "raw_spu_read_long"; - case 0x90b27880: return "strtoumax"; - case 0x9234f738: return "raw_spu_read_int"; - case 0x93427cb9: return "setbuf"; - case 0x938bfcf7: return "spu_thread_write_char"; - case 0x93a3e3ac: return "tolower"; - case 0x9439e4cd: return "wcsncat"; - case 0x96b6baa6: return "spu_thread_read_mem"; - case 0x96e6303b: return "_WStoxflt"; - case 0x96ea4de6: return "wctomb"; - case 0x97896359: return "isspace"; - case 0x9800573c: return "_WLdtob"; - case 0x980d3ea7: return "_Getfld"; - case 0x9886810c: return "_FDnorm"; - case 0x98f0eeab: return "raw_spu_write_ulong"; - case 0x99782342: return "strncasecmp_ascii"; - case 0x99a72146: return "vsnprintf"; - case 0x99b38ce7: return "wmemmove"; - case 0x9a87bb3a: return "_Getmbcurmax"; - case 0x9abe8c74: return "wprintf"; - case 0x9c7028a5: return "spu_thread_write_uint"; - case 0x9c9d7b0d: return "strtold"; - case 0x9cab08d1: return "spu_thread_write_int"; - case 0x9d140351: return "_Destroytls"; - case 0x9eb25e00: return "strcoll"; - case 0x9eee5387: return "truncate64"; - case 0x9ff08d57: return "_Clearlocks"; - case 0xa0ab76d5: return "_absi4"; - case 0xa0bc0efb: return "mallinfo"; - case 0xa0ddba8e: return "_Stoulx"; - case 0xa1dbb466: return "_Gettime"; - case 0xa2945229: return "_WGetint"; - case 0xa30d4797: return "wcstoll"; - case 0xa3440924: return "closedir"; - case 0xa3da58f6: return "rand_real1_TT800"; - case 0xa45a0313: return "mspace_create"; - case 0xa483d50d: return "_rv2d"; - case 0xa53800c2: return "_malloc_finalize_lv2"; - case 0xa568db82: return "spu_thread_read_ushort"; - case 0xa57cc615: return "iswspace"; - case 0xa5bc0e19: return "getchar"; - case 0xa6463518: return "__rename"; - case 0xa650df19: return "toupper"; - case 0xa65886b8: return "_Findloc"; - case 0xa72a7595: return "calloc"; - case 0xa797790f: return "wcsstr"; - case 0xa82d70da: return "_Tlsget"; - case 0xa835be11: return "__cxa_atexit"; - case 0xa874036a: return "wcstof"; - case 0xa8a6f615: return "TlsSetValue"; - case 0xa8b07f1b: return "wmemcpy"; - case 0xa9f68eff: return "qsort"; - case 0xaa1e687d: return "isgraph"; - case 0xaa266d35: return "_malloc_init"; - case 0xaa9635d7: return "strcat"; - case 0xab4c7ca1: return "_CWcsxfrm"; - case 0xab77019f: return "fstat"; - case 0xabc27420: return "wcstoul"; - case 0xac758d20: return "wmemcmp"; - case 0xac893127: return "fgetc"; - case 0xace90be4: return "_Dtentox"; - case 0xad62a342: return "ldiv"; - case 0xad8e9ad0: return "_Initlocks"; - case 0xaec7c970: return "lseek"; - case 0xaf002043: return "independent_comalloc"; - case 0xaf44a615: return "fgets"; - case 0xaf6bdcb0: return "_Nonfatal_Assert"; - case 0xaf89fdbd: return "_Assert"; - case 0xafa39179: return "_WPutstr"; - case 0xb120f6ca: return "close"; - case 0xb17b79d0: return "isalpha"; - case 0xb18cc115: return "freopen"; - case 0xb1cc43e3: return "_CStrftime"; - case 0xb1f4779d: return "spu_thread_printf"; - case 0xb24cb8d6: return "_Locterm"; - case 0xb2702e15: return "wcrtomb"; - case 0xb2748a9f: return "_Freeloc"; - case 0xb30042ce: return "lldiv"; - case 0xb37982ea: return "_Getstr"; - case 0xb3c495bd: return "imaxabs"; - case 0xb3d98d59: return "_rand_real1_TT800"; - case 0xb400f226: return "isupper_ascii"; - case 0xb4225825: return "mbsinit"; - case 0xb43c25c7: return "wcstoull"; - case 0xb49eea74: return "_init_malloc_lock0"; - case 0xb4a54446: return "_Stofx"; - case 0xb4fc7078: return "_close_all_FILE"; - case 0xb529d259: return "isalnum"; - case 0xb569849d: return "reallocalign"; - case 0xb57bdf7b: return "iswxdigit"; - case 0xb5d353e8: return "_LDtentox"; - case 0xb6002508: return "_Putstr"; - case 0xb6257e3d: return "strncasecmp"; - case 0xb680e240: return "wcstombs"; - case 0xb6af290e: return "_WFrprep"; - case 0xb6d92ac3: return "strcasecmp"; - case 0xb738027a: return "strtok_r"; - case 0xb794631e: return "_WStofx"; - case 0xb7ab5127: return "wcsrchr"; - case 0xb7b793ed: return "get_state_TT800"; - case 0xb7ba4aeb: return "_WStoul"; - case 0xb7d3427f: return "iscntrl_ascii"; - case 0xb81cd66a: return "mbrlen"; - case 0xb9ed25d4: return "raw_spu_read_ulong"; - case 0xba62681f: return "mspace_memalign"; - case 0xbb605c96: return "pvalloc"; - case 0xbbd4582f: return "_Setloc"; - case 0xbc1d69c5: return "atoll"; - case 0xbc374779: return "_Getlname"; - case 0xbc5af0b5: return "fgetwc"; - case 0xbc7b4b8e: return "ctime"; - case 0xbe11beaa: return "_wremove"; - case 0xbe251a29: return "islower_ascii"; - case 0xbe6e5c58: return "spu_thread_read_uchar"; - case 0xbec43f86: return "raw_spu_read_ptr"; - case 0xbf5bf5ea: return "lseek64"; - case 0xbfcd1b3b: return "_Getdst"; - case 0xc01d9f97: return "printf"; - case 0xc08cc41d: return "wcstod"; - case 0xc0e27b2c: return "_Makestab"; - case 0xc155a73f: return "_WStoull"; - case 0xc15e657e: return "spu_raw_sprintf"; - case 0xc1a71972: return "_d2rv"; - case 0xc1b4bbb9: return "raw_spu_write_char"; - case 0xc1c8737c: return "_Getptoupper"; - case 0xc291e698: return "exit"; - case 0xc3c598e2: return "spu_printf_initialize"; - case 0xc3e14cbe: return "memcmp"; - case 0xc4178000: return "_rand_real3_TT800"; - case 0xc41c6e5d: return "_Scanf"; - case 0xc57337f8: return "_Fofind"; - case 0xc5c09834: return "strstr"; - case 0xc63c354f: return "_Exit"; - case 0xc69b2427: return "labs"; - case 0xc78df618: return "rand_real3_TT800"; - case 0xc7b62ab8: return "spu_thread_write_ullong"; - case 0xc9471fac: return "_Mtxinit"; - case 0xc94b27e3: return "_WStof"; - case 0xc95b20d3: return "fputwc"; - case 0xc9607d35: return "_Stopfx"; - case 0xc97a17d7: return "vsscanf"; - case 0xcab654bf: return "_Once_ctor"; - case 0xcb85ac70: return "mspace_malloc"; - case 0xcb9c535b: return "strftime"; - case 0xcbac7ad7: return "memchr"; - case 0xcbdc3a6d: return "raw_spu_write_int"; - case 0xcc5e0c72: return "_divi4"; - case 0xcca68e9c: return "putwc"; - case 0xce7a9e76: return "isprint_ascii"; - case 0xcecbcdc4: return "_Frv2d"; - case 0xcf863219: return "_Fwprep"; - case 0xcfbfb7a7: return "spu_printf_detach_thread"; - case 0xd14ece90: return "strtol"; - case 0xd1d69cb8: return "_Stod"; - case 0xd20f6601: return "independent_calloc"; - case 0xd2a99b1e: return "isprint"; - case 0xd2ac48d7: return "iswalnum"; - case 0xd360dcb4: return "fileno"; - case 0xd3964a09: return "__spu_thread_putfld"; - case 0xd40723d6: return "fread"; - case 0xd417eeb5: return "_Stoull"; - case 0xd4912ee3: return "_FDscale"; - case 0xd5c8cb55: return "spu_thread_write_ushort"; - case 0xd69c513d: return "_Wcscollx"; - case 0xd784459d: return "isupper"; - case 0xd7dc3a8f: return "strtod"; - case 0xd8b4eb20: return "__spu_thread_puttxt"; - case 0xd9674905: return "mspace_reallocalign"; - case 0xd9a4f812: return "atoff"; - case 0xda5a7eb8: return "strtoul"; - case 0xdaeada07: return "mallopt"; - case 0xdbf4c59c: return "cellPadGetCapabilityInfo"; - case 0xddbac025: return "strcasecmp_ascii"; - case 0xddc71a75: return "_SCE_Assert"; - case 0xde1bb092: return "init_by_array_TT800"; - case 0xde32a334: return "_Exitspawn"; - case 0xde7aff7a: return "memcpy16"; - case 0xdebee2af: return "strchr"; - case 0xdef86a83: return "isxdigit_ascii"; - case 0xdfb52083: return "_Stoxflt"; - case 0xe03c7ab1: return "_Fspos"; - case 0xe1858899: return "_Getpwctrtab"; - case 0xe1bd3587: return "fclose"; - case 0xe1e83c65: return "strncmp"; - case 0xe2c5274a: return "_WStoflt"; - case 0xe3812672: return "fdopen"; - case 0xe3cc73f3: return "puts"; - case 0xe3d91db3: return "raw_spu_read_double"; - case 0xe40ba755: return "strtok"; - case 0xe44bf0bf: return "atof"; - case 0xe469fb20: return "_Atexit"; - case 0xe48348e9: return "vprintf"; - case 0xe4c51d4c: return "wcstoimax"; - case 0xe5ea9e2b: return "_Isdst"; - case 0xe5f09c80: return "llabs"; - case 0xe60ee9e5: return "fputws"; - case 0xe6a7de0a: return "ungetc"; - case 0xe7def231: return "_Getfloat"; - case 0xe89071ad: return "isalpha_ascii"; - case 0xe9137453: return "fwprintf"; - case 0xe9a2cc40: return "raw_spu_write_long"; - case 0xe9b560a5: return "sscanf"; - case 0xeb26298c: return "gmtime"; - case 0xeb40c9ec: return "rand_real2_TT800"; - case 0xeb8abe73: return "vwscanf"; - case 0xec9e7cb9: return "spu_thread_read_llong"; - case 0xecddba69: return "_WStodx"; - case 0xed6ec979: return "fsetpos"; - case 0xeda48c80: return "malloc_trim"; - case 0xeddcee2c: return "init_TT800"; - case 0xedec777d: return "_Ttotm"; - case 0xeeeb4f3e: return "_get_state_TT800"; - case 0xeeffc9a6: return "_wrename"; - case 0xef110b6b: return "unlink"; - case 0xf06eed36: return "wmemset"; - case 0xf0776a44: return "wcscmp"; - case 0xf0e022c6: return "getc"; - case 0xf2bbbee9: return "_Litob"; - case 0xf2fca4b2: return "spu_thread_write_llong"; - case 0xf356418c: return "open"; - case 0xf3ef3678: return "wcscspn"; - case 0xf41355f9: return "wcscpy"; - case 0xf418ee84: return "_WFwprep"; - case 0xf4207734: return "spu_thread_write_ulong"; - case 0xf5a32994: return "_Getpcostate"; - case 0xf5ef229c: return "_Getpwcostate"; - case 0xf5f7dda8: return "towupper"; - case 0xf68e2ac9: return "_init_malloc_lock"; - case 0xf7583d67: return "vscanf"; - case 0xf7908e27: return "strcspn"; - case 0xf7a14a22: return "realloc"; - case 0xf7d51596: return "scanf"; - case 0xf7ddb471: return "_Setgloballocale"; - case 0xf88f26c4: return "fwrite"; - case 0xf8935fe3: return "spu_thread_write_float"; - case 0xf89dc648: return "strpbrk"; - case 0xf9dae72c: return "setjmp"; - case 0xf9dba140: return "_Mtxlock"; - case 0xf9e26b72: return "_Once_dtor"; - case 0xfa00d211: return "read"; - case 0xfae4b063: return "_Strcollx"; - case 0xfaec8c60: return "fprintf"; - case 0xfb0f0018: return "_Makewct"; - case 0xfb2081fd: return "vfprintf"; - case 0xfb81426d: return "iswlower"; - case 0xfb8ea4d2: return "_Fd2rv"; - case 0xfc0428a6: return "strdup"; - case 0xfc60575c: return "__spu_thread_printf"; - case 0xfc606237: return "mbsrtowcs"; - case 0xfcac2e8e: return "mbstowcs"; - case 0xfd0cb96d: return "spu_thread_read_short"; - case 0xfd461e85: return "spu_thread_write_ldouble"; - case 0xfd6a1ddb: return "raw_spu_read_llong"; - case 0xfd81f6ca: return "_Stoflt"; - case 0xfe0261aa: return "mspace_free"; - case 0xfe630fd9: return "isblank"; - case 0xfe88e97e: return "fscanf"; - case 0xff689124: return "strtoimax"; - case 0xffbae95e: return "asctime"; - case 0xffbd876b: return "__raw_spu_puttxt"; - case 0x003395d9: return "_Feraise"; - case 0x00367be0: return "fminl"; - case 0x007854f4: return "_FDclass"; - case 0x00fde072: return "f_powf"; - case 0x010818fc: return "asinf4"; - case 0x012d0a91: return "_fminf4"; - case 0x016556df: return "_sinf4"; - case 0x01b84b27: return "llround"; - case 0x01ecef7d: return "_FCbuild"; - case 0x02e68d44: return "_f_fmodf"; - case 0x032cc709: return "csin"; - case 0x03593d2c: return "_f_expf"; - case 0x03aea906: return "divf4"; - case 0x0522d1af: return "_recipf4"; - case 0x054aae63: return "_fdimf4"; - case 0x05cb1718: return "f_fdimf"; - case 0x05e27a13: return "log10f4fast"; - case 0x05efc660: return "asin"; - case 0x05f1dc9e: return "_FExp"; - case 0x07274304: return "csinh"; - case 0x07daed62: return "log2f4"; - case 0x07f400e3: return "_LCbuild"; - case 0x080414bd: return "conjl"; - case 0x08139bd2: return "_fmaxf4"; - case 0x0829a21d: return "asinhl"; - case 0x0a242ed5: return "sinf4"; - case 0x0b3f4e90: return "catanhf"; - case 0x0bb036a6: return "_cosf4"; - case 0x0c14cfcc: return "fesetenv"; - case 0x0c9b8305: return "hypotf4"; - case 0x0cbdae68: return "sinf"; - case 0x0cf9b8bd: return "_Erfc"; - case 0x0d86295d: return "_LCaddcr"; - case 0x0e53319f: return "_asinf4"; - case 0x0e8573dc: return "expm1l"; - case 0x0f02f882: return "llrintl"; - case 0x0f428f0f: return "rint"; - case 0x0f721a9d: return "_LCsubcc"; - case 0x10627248: return "f_fmodf"; - case 0x11c51388: return "tgamma"; - case 0x1225dd31: return "casinf"; - case 0x12de4e46: return "_powf4"; - case 0x12e04cd7: return "cimagl"; - case 0x1313a420: return "acos"; - case 0x137f7e77: return "expf4"; - case 0x14208b00: return "_asinf4fast"; - case 0x1498a072: return "_Cmulcr"; - case 0x16bf208a: return "log10f"; - case 0x17316bee: return "log2"; - case 0x178d98dd: return "atanf4fast"; - case 0x17cd5d87: return "_recipf4fast"; - case 0x182cd542: return "tgammal"; - case 0x18668ce3: return "exp"; - case 0x18b26998: return "remainderl"; - case 0x18ec6099: return "rintl"; - case 0x1988732d: return "clog10"; - case 0x1a1adede: return "rsqrtf4fast"; - case 0x1acb2b16: return "acosf4"; - case 0x1bbdcd9f: return "expm1f4"; - case 0x1bcdeb47: return "_LSinh"; - case 0x1be996cc: return "_LCdivcc"; - case 0x1c11885d: return "_floorf4"; - case 0x1d35bfe4: return "_LLog"; - case 0x1d5bf5d0: return "_modff4"; - case 0x1e623f95: return "truncf4"; - case 0x1e85ef02: return "f_atanf"; - case 0x1e9fd6ba: return "_sinf4fast"; - case 0x2033eeb7: return "csqrt"; - case 0x2118fe46: return "cexpl"; - case 0x21a37b3e: return "log1pf"; - case 0x21e6d304: return "ceil"; - case 0x22c3e308: return "_exp2f4"; - case 0x238af59b: return "fegetenv"; - case 0x23b985f7: return "floorf"; - case 0x241f9337: return "_FCmulcr"; - case 0x24497c52: return "cosf"; - case 0x246ea8d0: return "f_sqrtf"; - case 0x2627d6b2: return "erfc"; - case 0x266d2473: return "_Caddcr"; - case 0x26deed0b: return "cosl"; - case 0x26ef50ed: return "asinh"; - case 0x28faaa5a: return "ilogbf4"; - case 0x29685118: return "_negatef4"; - case 0x2a138d2b: return "truncf"; - case 0x2a4dcbad: return "cacosl"; - case 0x2a89ce33: return "llrintf"; - case 0x2af4b73b: return "fmax"; - case 0x2b282ebb: return "sqrtl"; - case 0x2bb0f2c9: return "logb"; - case 0x2c45fe6a: return "fmaxl"; - case 0x2c601f3b: return "csinl"; - case 0x2cbb6f53: return "f_hypotf"; - case 0x2dcab6a4: return "nanl"; - case 0x2df339bc: return "_f_floorf"; - case 0x2e69bb2a: return "_FCosh"; - case 0x2ec867b4: return "exp2f4fast"; - case 0x30bc7a53: return "logf4"; - case 0x315673f6: return "_Csubcc"; - case 0x31be25c3: return "scalblnf"; - case 0x31db8c89: return "atan2"; - case 0x321c55de: return "nexttowardl"; - case 0x3261de11: return "fesetexceptflag"; - case 0x329ec019: return "rsqrtf4"; - case 0x32f994a1: return "cosf4fast"; - case 0x33e5929b: return "_LDsign"; - case 0x33f27f25: return "_FCdivcr"; - case 0x3436f008: return "csinhf"; - case 0x3459748b: return "log10f4"; - case 0x347c1ee1: return "atanf4"; - case 0x34c0371e: return "powl"; - case 0x358d7f93: return "_f_lrintf"; - case 0x3593a445: return "clog"; - case 0x35b6e70a: return "lrintl"; - case 0x35d3f688: return "creal"; - case 0x36778d1b: return "coshf"; - case 0x373054d1: return "cpow"; - case 0x37345541: return "log1pl"; - case 0x376fb27f: return "sinhl"; - case 0x3792b12d: return "lroundl"; - case 0x38ba5590: return "ccosl"; - case 0x38e69f09: return "pow"; - case 0x398483aa: return "_expm1f4fast"; - case 0x39ef81c9: return "f_fmaxf"; - case 0x3ad203fa: return "lrint"; - case 0x3adc01d7: return "f_frexpf"; - case 0x3b802524: return "ldexpf4"; - case 0x3c057fbd: return "atanf"; - case 0x3c616743: return "_LDtest"; - case 0x3cb818fa: return "_f_fdimf"; - case 0x3d4efafb: return "atan2l"; - case 0x3d549f2a: return "ctanhl"; - case 0x3d901a10: return "_ceilf4"; - case 0x3da55602: return "fabsf"; - case 0x3dfa060f: return "scalbnl"; - case 0x3e7eb58f: return "frexpf4"; - case 0x3e919cba: return "scalbnf"; - case 0x3ec9de23: return "_cbrtf4"; - case 0x3eeedb0e: return "_Dclass"; - case 0x3f6262b3: return "f_fminf"; - case 0x3f701e78: return "_Poly"; - case 0x4020f5ef: return "cbrt"; - case 0x405f9727: return "_log1pf4fast"; - case 0x40a2e212: return "_fabsf4"; - case 0x4111b546: return "_LExp"; - case 0x411434bb: return "asinf"; - case 0x414c5ecc: return "_f_hypotf"; - case 0x4152669c: return "scalbln"; - case 0x417851ce: return "feholdexcept"; - case 0x418036e3: return "_FTgamma"; - case 0x4189a367: return "remquo"; - case 0x41d1b236: return "_f_rintf"; - case 0x430309a1: return "ldexpf"; - case 0x434881a0: return "cacosf"; - case 0x43d522f4: return "cabsl"; - case 0x44cd6308: return "remainder"; - case 0x44cf744b: return "tanhl"; - case 0x45034943: return "nan"; - case 0x452ac4bb: return "floorf4"; - case 0x453f9e91: return "cbrtf"; - case 0x46b66f76: return "csqrtl"; - case 0x46cf72d9: return "fdimf"; - case 0x47433144: return "expm1f4fast"; - case 0x475d855b: return "trunc"; - case 0x476b5591: return "fmaf"; - case 0x48157605: return "_f_llrintf"; - case 0x4826db61: return "fma"; - case 0x4875601d: return "_exp2f4fast"; - case 0x487bbd1c: return "tanf4"; - case 0x488df791: return "cexp"; - case 0x48d462a9: return "_FDint"; - case 0x4930ac11: return "logbl"; - case 0x4a5ae27d: return "f_exp2f"; - case 0x4a6ca9a6: return "powf4"; - case 0x4ab22a63: return "_Caddcc"; - case 0x4add664c: return "feclearexcept"; - case 0x4ae52dd3: return "exp2"; - case 0x4b03d5b2: return "f_rintf"; - case 0x4b584841: return "f_asinf"; - case 0x4cb5fa99: return "nexttoward"; - case 0x4d878773: return "remainderf4"; - case 0x4ddb926b: return "powf"; - case 0x4e010403: return "copysign"; - case 0x4eb5eb51: return "sin"; - case 0x4fa4f5ec: return "nexttowardf"; - case 0x501c412f: return "cargf"; - case 0x519ebb77: return "floor"; - case 0x547fb4a7: return "sinf4fast"; - case 0x54d2fb8c: return "rintf"; - case 0x5516d621: return "acosl"; - case 0x55c8a549: return "truncl"; - case 0x56c573a8: return "log1p"; - case 0x575e9b6e: return "asinl"; - case 0x58eb9e57: return "fabs"; - case 0x596ab55c: return "atanh"; - case 0x5b18eded: return "clogl"; - case 0x5b474c22: return "casinhl"; - case 0x5bfd37be: return "_FCaddcc"; - case 0x5e48dede: return "exp2f4"; - case 0x5ee10a95: return "catanh"; - case 0x5ee37927: return "_LErfc"; - case 0x60e9ff3c: return "_expm1f4"; - case 0x61250988: return "catanl"; - case 0x6261c0b5: return "_log10f4"; - case 0x63bbdfa6: return "_FCmulcc"; - case 0x642e3d18: return "_frexpf4"; - case 0x642f7d6b: return "f_copysignf"; - case 0x645557bd: return "copysignl"; - case 0x64abdb4d: return "csinhl"; - case 0x657d0e83: return "divf4fast"; - case 0x65935877: return "ilogbf"; - case 0x659e011e: return "sqrt"; - case 0x6636c4a5: return "frexpf"; - case 0x664e04b9: return "negatef4"; - case 0x6764c707: return "f_log2f"; - case 0x683cacb3: return "sinh"; - case 0x68a8957f: return "casinhf"; - case 0x68f72416: return "nextafterl"; - case 0x69040b9b: return "logbf4"; - case 0x69725dce: return "lgamma"; - case 0x6ad1c42b: return "_sincosf4"; - case 0x6b660894: return "_acosf4fast"; - case 0x6b6ab2a9: return "_LDclass"; - case 0x6c009c56: return "f_log10f"; - case 0x6c6285c6: return "acoshf"; - case 0x6cc4bd13: return "casinh"; - case 0x6ddd31b2: return "hypot"; - case 0x6df35518: return "floorl"; - case 0x6e9eb0dc: return "sincosf4fast"; - case 0x6ef6b083: return "_FCsubcr"; - case 0x6f5dd7d2: return "cexpf"; - case 0x6f639afb: return "f_llroundf"; - case 0x6fcc1e27: return "_FPoly"; - case 0x70357b12: return "_atanf4fast"; - case 0x7048396e: return "carg"; - case 0x705d9e24: return "f_acosf"; - case 0x70f71871: return "_FCdivcc"; - case 0x71293b71: return "_FLog"; - case 0x714adce1: return "log"; - case 0x71f2bc56: return "_divf4fast"; - case 0x728149e5: return "f_ldexpf"; - case 0x729b7269: return "cproj"; - case 0x72a3ed28: return "fesettrapenable"; - case 0x72f1f64b: return "_logbf4"; - case 0x734ca589: return "_f_cosf"; - case 0x742f12b4: return "_Sin"; - case 0x74902d4b: return "expf4fast"; - case 0x749440f9: return "lgammal"; - case 0x752fa85e: return "fmaxf4"; - case 0x758f33dc: return "nearbyint"; - case 0x75e3e2e9: return "nearbyintl"; - case 0x76afaf04: return "_sqrtf4"; - case 0x76e639ec: return "_atanf4"; - case 0x772f1e4d: return "lround"; - case 0x7793a86b: return "ctanf"; - case 0x7831a2e0: return "hypotl"; - case 0x78e4590a: return "acosh"; - case 0x790c53bd: return "_Fpcomp"; - case 0x7919f414: return "_f_nearbyintf"; - case 0x79ba9b5c: return "expl"; - case 0x7a893af1: return "_rsqrtf4"; - case 0x7ab679da: return "f_cosf"; - case 0x7c2eaeb5: return "fminf"; - case 0x7d02a5ca: return "sqrtf4fast"; - case 0x7d6191d0: return "_Cosh"; - case 0x7f381837: return "frexp"; - case 0x7f579e03: return "atan"; - case 0x7f91cd41: return "tanf4fast"; - case 0x812ed488: return "cabsf"; - case 0x81daf880: return "_LCsubcr"; - case 0x8217e783: return "cosh"; - case 0x833e6b0e: return "cimag"; - case 0x834f5917: return "ccosh"; - case 0x842cb14d: return "_log1pf4"; - case 0x8451edf0: return "sqrtf"; - case 0x889cccb0: return "llroundl"; - case 0x88fb4a66: return "recipf4fast"; - case 0x892f2590: return "fegetround"; - case 0x895cdb49: return "fmaxf"; - case 0x89b507b3: return "catanhl"; - case 0x89d1d168: return "_LAtan"; - case 0x8b168769: return "fdiml"; - case 0x8bd1deb2: return "_LTgamma"; - case 0x8bd67efc: return "erf"; - case 0x8c85369b: return "_f_fminf"; - case 0x8d5858db: return "_f_exp2f"; - case 0x8e01379e: return "cacoshf"; - case 0x8e258fa0: return "cacos"; - case 0x8ecae294: return "nextafter"; - case 0x8f2bcdb5: return "_logf4"; - case 0x8f96319e: return "log10l"; - case 0x8fb7bac7: return "_sqrtf4fast"; - case 0x904e646b: return "cargl"; - case 0x90f0242f: return "_f_sinf"; - case 0x9110708a: return "modfl"; - case 0x91cdfdb0: return "asinf4fast"; - case 0x9232baea: return "_FDtest"; - case 0x9245e01b: return "_divf4"; - case 0x9379e36e: return "tanf"; - case 0x938fb946: return "_tanf4fast"; - case 0x947ae18e: return "_LHypot"; - case 0x9558ed08: return "lrintf"; - case 0x95dfecb1: return "_FCsubcc"; - case 0x961688d1: return "f_nearbyintf"; - case 0x9616e336: return "_FHypot"; - case 0x964ac044: return "creall"; - case 0x96d1b95e: return "log2f4fast"; - case 0x9700d9cd: return "clogf"; - case 0x970a3432: return "cacosh"; - case 0x99a6c261: return "catanf"; - case 0x99c228fc: return "roundl"; - case 0x9a81e583: return "fmodf"; - case 0x9af30eaf: return "casin"; - case 0x9e289062: return "_f_ceilf"; - case 0x9e3ada21: return "logl"; - case 0x9e8130b6: return "ccos"; - case 0x9f03dd3e: return "lgammaf"; - case 0x9f0efc6e: return "exp2l"; - case 0x9f46f5a4: return "tgammaf"; - case 0x9f65bd34: return "fdimf4"; - case 0x9f78f052: return "cos"; - case 0x9fded78a: return "_acosf4"; - case 0xa0160c30: return "_copysignf4"; - case 0xa20827a8: return "ctanl"; - case 0xa2c81938: return "_LSin"; - case 0xa4578433: return "fmin"; - case 0xa46a70a1: return "atanhl"; - case 0xa4ca5cf2: return "llroundf"; - case 0xa56557b6: return "catan"; - case 0xa5d0b260: return "acoshl"; - case 0xa713f8cf: return "modf"; - case 0xa7658186: return "log1pf4"; - case 0xa823836b: return "ilogb"; - case 0xa8c16038: return "_FDsign"; - case 0xa8d180e8: return "_Cbuild"; - case 0xa92bcc85: return "cabs"; - case 0xa9e039c4: return "erfcf"; - case 0xaaa270dc: return "_LCdivcr"; - case 0xab377381: return "log2f"; - case 0xabdccc7a: return "f_atan2f"; - case 0xacca2f83: return "copysignf"; - case 0xad17e787: return "_Dint"; - case 0xad3a093d: return "_LCosh"; - case 0xad5d3e57: return "_FLgamma"; - case 0xaddce673: return "erfcl"; - case 0xafa13040: return "f_llrintf"; - case 0xafcfdad7: return "_Lgamma"; - case 0xafd9a625: return "cimagf"; - case 0xb0fa1592: return "clog10l"; - case 0xb24bd2f8: return "logbf"; - case 0xb348c5c2: return "_LLgamma"; - case 0xb412a8dc: return "_LDint"; - case 0xb4ef29d5: return "f_floorf"; - case 0xb4f4513e: return "_Tgamma"; - case 0xb54cc9a1: return "f_sinf"; - case 0xb5961d4e: return "_sincosf4fast"; - case 0xb598a495: return "fmodl"; - case 0xb5e28191: return "_FSin"; - case 0xb7696143: return "nextafterf"; - case 0xb79012ba: return "modff"; - case 0xb89863bc: return "_rsqrtf4fast"; - case 0xb8aa984e: return "_expf4"; - case 0xb94b9d13: return "_Dtest"; - case 0xb9d2ad22: return "remquol"; - case 0xba136594: return "csinf"; - case 0xba84eab5: return "coshl"; - case 0xbaf11866: return "ceilf"; - case 0xbb165807: return "expm1f"; - case 0xbb208b20: return "cbrtf4fast"; - case 0xbb761c89: return "remquof"; - case 0xbbaa300b: return "f_log1pf"; - case 0xbbf7354e: return "fegetexceptflag"; - case 0xbd7410d9: return "recipf4"; - case 0xbd8bb75c: return "asinhf"; - case 0xbf23f2e7: return "cprojl"; - case 0xbfda6837: return "_f_log10f"; - case 0xc0609820: return "nearbyintf"; - case 0xc0bcf25e: return "_logf4fast"; - case 0xc357b33a: return "frexpl"; - case 0xc406dd09: return "cbrtf4"; - case 0xc41f01db: return "fminf4"; - case 0xc477c0f6: return "f_lroundf"; - case 0xc4cccd1f: return "modff4"; - case 0xc7369fce: return "_Atan"; - case 0xc78ac9d0: return "scalbn"; - case 0xc7b45a19: return "_LFpcomp"; - case 0xc7f1d407: return "fmal"; - case 0xc7fb73d6: return "f_lrintf"; - case 0xc8910002: return "ilogbl"; - case 0xc8dd9279: return "expm1"; - case 0xc90f4bbc: return "_atan2f4"; - case 0xc9481758: return "_tanf4"; - case 0xc94fcc63: return "cbrtl"; - case 0xc977e1ea: return "fetestexcept"; - case 0xc984bf53: return "roundf"; - case 0xc9c536ce: return "_ldexpf4"; - case 0xca239640: return "fmodf4"; - case 0xca463458: return "_Log"; - case 0xcaaf7ae7: return "cprojf"; - case 0xcac167a5: return "_Cmulcc"; - case 0xcb6599c0: return "exp2f"; - case 0xcb6a147e: return "_cosf4fast"; - case 0xcbdf9afb: return "_log10f4fast"; - case 0xccc66f11: return "_FSinh"; - case 0xce91ff18: return "nanf"; - case 0xcfee82d8: return "_remainderf4"; - case 0xd0fd3ca8: return "_hypotf4"; - case 0xd125b89e: return "conjf"; - case 0xd1a3574c: return "clog10f"; - case 0xd231e30a: return "ldexpl"; - case 0xd28ef6dd: return "_Hypot"; - case 0xd2a666c9: return "ctanh"; - case 0xd3a346a8: return "tanl"; - case 0xd40f3f2c: return "erff"; - case 0xd42904b7: return "fabsl"; - case 0xd477852d: return "logf"; - case 0xd48eaae1: return "scalblnl"; - case 0xd4f37b9d: return "tanhf"; - case 0xd50277ad: return "tan"; - case 0xd54039cb: return "fegettrapenable"; - case 0xd5adc4b2: return "cpowl"; - case 0xd5d38552: return "_LCaddcc"; - case 0xd612fa16: return "_Sinh"; - case 0xd70df92a: return "_FCaddcr"; - case 0xd7653782: return "sinhf"; - case 0xd76a16da: return "_fmaf4"; - case 0xd8270894: return "fdim"; - case 0xd8c4096d: return "atan2f4"; - case 0xd8d157f5: return "f_expf"; - case 0xd8f79f4c: return "log10"; - case 0xd97852b7: return "sinl"; - case 0xd97ce5d4: return "fesetround"; - case 0xda217d1f: return "atanl"; - case 0xda31fc5d: return "_FFpcomp"; - case 0xdc14974c: return "fmaf4"; - case 0xdc151707: return "_f_log2f"; - case 0xdd8660d2: return "atan2f4fast"; - case 0xdd92118e: return "ceill"; - case 0xdddabb32: return "remainderf"; - case 0xde7833f2: return "_log2f4fast"; - case 0xdece76a6: return "acosf"; - case 0xdfd41734: return "_Exp"; - case 0xdffb4e3c: return "casinl"; - case 0xe1288c47: return "atanhf"; - case 0xe1c71b05: return "ccoshl"; - case 0xe2b596ec: return "ccosf"; - case 0xe2de89e6: return "csqrtf"; - case 0xe2f1d4b2: return "tanh"; - case 0xe31cc0d3: return "_ilogbf4"; - case 0xe3e379b8: return "_expf4fast"; - case 0xe584836c: return "_LPoly"; - case 0xe58fc9b5: return "erfl"; - case 0xe5a0be9f: return "_powf4fast"; - case 0xe5d2293f: return "_Force_raise"; - case 0xe5ea65e8: return "feraiseexcept"; - case 0xe6c1ff41: return "llrint"; - case 0xe769e5cf: return "fmod"; - case 0xe8fcf1f8: return "acosf4fast"; - case 0xe913a166: return "logf4fast"; - case 0xe92f3fb8: return "_f_fmaf"; - case 0xe93abfca: return "ctan"; - case 0xe9ac8223: return "_LCmulcr"; - case 0xe9f501df: return "crealf"; - case 0xea1e83e3: return "f_logf"; - case 0xeac62795: return "_Cdivcc"; - case 0xeac7ca2c: return "ceilf4"; - case 0xebb4e08a: return "hypotf"; - case 0xec43b983: return "_f_sqrtf"; - case 0xec7da0c8: return "_atan2f4fast"; - case 0xed05c265: return "sqrtf4"; - case 0xed9d1ac5: return "f_tanf"; - case 0xeda86c48: return "copysignf4"; - case 0xee0db701: return "_Csubcr"; - case 0xee204ac6: return "f_ceilf"; - case 0xee303936: return "_Dsign"; - case 0xeed82401: return "_f_logf"; - case 0xf0947035: return "ctanhf"; - case 0xf0ab77c1: return "ccoshf"; - case 0xf16568af: return "_FAtan"; - case 0xf19c5e94: return "sincosf4"; - case 0xf1aaa2f8: return "conj"; - case 0xf3bd7d08: return "_cbrtf4fast"; - case 0xf3ec0258: return "round"; - case 0xf4ad6ea8: return "ldexp"; - case 0xf537d837: return "_truncf4"; - case 0xf5cd1e19: return "cosf4"; - case 0xf7844153: return "_f_fmaxf"; - case 0xf83a372f: return "f_fmaf"; - case 0xf95b7769: return "powf4fast"; - case 0xf99da2fc: return "fabsf4"; - case 0xfa28434b: return "log2l"; - case 0xfa765d42: return "_Cdivcr"; - case 0xfa97afbf: return "feupdateenv"; - case 0xfae9e727: return "_f_copysignf"; - case 0xfb6e6213: return "log1pf4fast"; - case 0xfb932a56: return "atan2f"; - case 0xfbb4047a: return "lroundf"; - case 0xfbe88922: return "_FErfc"; - case 0xfcedabc3: return "_fmodf4"; - case 0xfcf08193: return "expf"; - case 0xfdec16e1: return "cacoshl"; - case 0xfe23dbe9: return "_log2f4"; - case 0xff036800: return "cpowf"; - case 0xfffe79bf: return "_LCmulcc"; - case 0x06a840f5: return "sys_dbg_set_stacksize_ppu_exception_handler"; - case 0x08ef08a9: return "sys_dbg_get_spu_thread_group_ids"; - case 0x113b0bea: return "sys_dbg_get_ppu_thread_ids"; - case 0x1860f909: return "sys_dbg_get_spu_thread_ids"; - case 0x22916f45: return "sys_dbg_register_ppu_exception_handler"; - case 0x24a3d413: return "sys_dbg_mat_set_condition"; - case 0x266c2bd3: return "sys_dbg_read_spu_thread_context2"; - case 0x3147c6ca: return "sys_dbg_enable_floating_point_enabled_exception"; - case 0x381ae33e: return "sys_dbg_get_event_queue_information"; - case 0x3e5eed36: return "sys_dbg_get_spu_thread_name"; - case 0x4b55f456: return "sys_dbg_get_ppu_thread_name"; - case 0x4ded9f6c: return "sys_dbg_signal_to_ppu_exception_handler"; - case 0x50453aa8: return "sys_dbg_get_mutex_information"; - case 0x580f8203: return "sys_dbg_vm_get_page_information"; - case 0x590a276e: return "sys_dbg_mat_get_condition"; - case 0x63bd413e: return "sys_dbg_get_cond_information"; - case 0x6b413178: return "sys_dbg_get_ppu_thread_status"; - case 0x7bdadb01: return "sys_dbg_get_lwcond_information"; - case 0x9794bb53: return "sys_dbg_get_rwlock_information"; - case 0x9ddb9dc3: return "sys_dbg_get_spu_thread_group_status"; - case 0xa2d6cbd2: return "sys_dbg_get_semaphore_information"; - case 0xab475d53: return "sys_dbg_set_mask_to_ppu_exception_handler"; - case 0xb9da87d3: return "sys_dbg_get_coredump_params"; - case 0xbb0ae221: return "sys_dbg_get_address_from_dabr"; - case 0xbd69e584: return "sys_dbg_get_spu_thread_group_name"; - case 0xc0eb9266: return "sys_dbg_finalize_ppu_exception_handler"; - case 0xc21ee635: return "sys_dbg_read_spu_thread_context"; - case 0xc353353a: return "sys_dbg_initialize_ppu_exception_handler"; - case 0xc5eef17f: return "sys_dbg_read_ppu_thread_context"; - case 0xc6d7ec13: return "sys_dbg_unregister_ppu_exception_handler"; - case 0xcb377e36: return "sys_dbg_get_lwmutex_information"; - case 0xd830062a: return "sys_dbg_signal_to_coredump_handler"; - case 0xdb14b37b: return "sys_dbg_set_address_to_dabr"; - case 0xdf856979: return "sys_dbg_get_event_flag_information"; - case 0xf254768c: return "sys_dbg_disable_floating_point_enabled_exception"; - case 0x051ee3ee: return "socketpoll"; - case 0x05bd4438: return "sys_net_get_udpp2p_test_param"; - case 0x10b81ed6: return "sys_net_set_udpp2p_test_param"; - case 0x139a9e9b: return "sys_net_initialize_network_ex"; - case 0x13efe7f5: return "getsockname"; - case 0x1d14d6e4: return "sys_net_get_lib_name_server"; - case 0x1f953b9f: return "recvfrom"; - case 0x27fb339d: return "sys_net_if_ctl"; - case 0x28e208bb: return "listen"; - case 0x368823c0: return "sys_net_get_netemu_test_param"; - case 0x3b27c780: return "sys_net_get_sockinfo"; - case 0x3f09e20a: return "socketselect"; - case 0x44328aa2: return "sys_net_close_dump"; - case 0x4ab0b9b9: return "sys_net_set_test_param"; - case 0x506ad863: return "inet_network"; - case 0x5420e419: return "sys_net_show_nameserver"; - case 0x566893ce: return "inet_lnaof"; - case 0x5a045bd1: return "getsockopt"; - case 0x6005cde1: return "_sys_net_errno_loc"; - case 0x64f66d35: return "connect"; - case 0x6db6e8cd: return "socketclose"; - case 0x71f4c717: return "gethostbyname"; - case 0x7687d48c: return "sys_net_set_resolver_configurations"; - case 0x79b61646: return "sys_net_show_route"; - case 0x858a930b: return "inet_ntoa"; - case 0x88f03575: return "setsockopt"; - case 0x89c9917c: return "sys_net_read_dump"; - case 0x8af3825e: return "inet_pton"; - case 0x8ccf05ed: return "sys_net_abort_resolver"; - case 0x8d1b77fb: return "sys_net_abort_socket"; - case 0x9647570b: return "sendto"; - case 0x9a318259: return "sys_net_set_lib_name_server"; - case 0x9c056962: return "socket"; - case 0xa50777c6: return "shutdown"; - case 0xa5a86557: return "sys_net_get_test_param"; - case 0xa765d029: return "sys_net_get_sockinfo_ex"; - case 0xa9a079e0: return "inet_aton"; - case 0xab447704: return "sys_net_open_dump"; - case 0xad09481b: return "sendmsg"; - case 0xb0a59804: return "bind"; - case 0xb4152c74: return "inet_makeaddr"; - case 0xb48636c4: return "sys_net_show_ifconfig"; - case 0xb68d5625: return "sys_net_finalize_network"; - case 0xc9157d30: return "_sys_net_h_errno_loc"; - case 0xc94f6939: return "accept"; - case 0xc98a3146: return "inet_ntop"; - case 0xc9d09c34: return "recvmsg"; - case 0xdabbc2c0: return "inet_addr"; - case 0xdc751b40: return "send"; - case 0xe2434507: return "sys_net_set_netemu_test_param"; - case 0xe39a62a7: return "inet_netof"; - case 0xf7ac8941: return "gethostbyaddr"; - case 0xf9ec2db6: return "getpeername"; - case 0xfba04f37: return "recv"; - case 0xfdb8f926: return "sys_net_free_thread_context"; - case 0x0341bb97: return "sys_prx_get_module_id_by_address"; - case 0x04e83d2c: return "_sys_strncmp"; - case 0x052d29a6: return "_sys_strcat"; - case 0x05c65656: return "sys_mempool_try_allocate_block"; - case 0x0618936b: return "_sys_vsnprintf"; - case 0x06574237: return "_sys_snprintf"; - case 0x1573dc3f: return "sys_lwmutex_lock"; - case 0x191f0c4a: return "_sys_strrchr"; - case 0x1ae10b92: return "_sys_spu_printf_attach_thread"; - case 0x1bc200f4: return "sys_lwmutex_unlock"; - case 0x1c9a942c: return "sys_lwcond_destroy"; - case 0x1ca525a2: return "_sys_strncasecmp"; - case 0x1ed454ce: return "sys_spu_elf_get_information"; - case 0x24a1ea07: return "sys_ppu_thread_create"; - case 0x25596f51: return "sys_mempool_get_count"; - case 0x26090058: return "sys_prx_load_module"; - case 0x27427742: return "_sys_memmove"; - case 0x2a6d9d51: return "sys_lwcond_wait"; - case 0x2c847572: return "_sys_process_atexitspawn"; - case 0x2d36462b: return "_sys_strlen"; - case 0x2f85c0ef: return "sys_lwmutex_create"; - case 0x3172759d: return "sys_game_get_temperature"; - case 0x318f17e1: return "_sys_memalign"; - case 0x350d454e: return "sys_ppu_thread_get_id"; - case 0x35168520: return "_sys_heap_malloc"; - case 0x3bd53c7b: return "_sys_memchr"; - case 0x3dd4a957: return "sys_ppu_thread_register_atexit"; - case 0x409ad939: return "sys_mmapper_free_memory"; - case 0x42b23552: return "sys_prx_register_library"; - case 0x44265c08: return "_sys_heap_memalign"; - case 0x459b4393: return "_sys_strcmp"; - case 0x45fe2fce: return "_sys_spu_printf_initialize"; - case 0x4643ba6e: return "sys_mmapper_unmap_memory"; - case 0x4a071d98: return "sys_interrupt_thread_disestablish"; - case 0x4b2f301a: return "_sys_tolower"; - case 0x5267cb35: return "sys_spinlock_unlock"; - case 0x52aadadf: return "sys_lwcond_signal_to"; - case 0x5fdfb2fe: return "_sys_spu_printf_detach_group"; - case 0x608212fc: return "sys_mempool_free_block"; - case 0x620e35a7: return "sys_game_get_system_sw_version"; - case 0x67f9fedb: return "sys_game_process_exitspawn2"; - case 0x68b9b011: return "_sys_memset"; - case 0x6bf66ea7: return "_sys_memcpy"; - case 0x6e05231d: return "sys_game_watchdog_stop"; - case 0x70258515: return "sys_mmapper_allocate_memory_from_container"; - case 0x71a8472a: return "sys_get_random_number"; - case 0x722a0254: return "sys_spinlock_trylock"; - case 0x74311398: return "sys_prx_get_my_module_id"; - case 0x744680a2: return "sys_initialize_tls"; - case 0x7498887b: return "_sys_strchr"; - case 0x791b9219: return "_sys_vsprintf"; - case 0x80fb0c19: return "sys_prx_stop_module"; - case 0x8461e528: return "sys_time_get_system_time"; - case 0x84bb6774: return "sys_prx_get_module_info"; - case 0x893305fa: return "sys_raw_spu_load"; - case 0x8985b5b6: return "_sys_heap_stats"; - case 0x8a2f159b: return "console_getc"; - case 0x8a561d92: return "_sys_heap_free"; - case 0x8bb03ab8: return "sys_game_board_storage_write"; - case 0x8c2bb498: return "sys_spinlock_initialize"; - case 0x96328741: return "_sys_process_at_Exitspawn"; - case 0x4f7172c9: return "sys_process_is_stack"; - case 0x996f7cf8: return "_sys_strncat"; - case 0x99c88692: return "_sys_strcpy"; - case 0x9d3c0f81: return "sys_mempool_destroy"; - case 0x9e0623b5: return "sys_game_watchdog_start"; - case 0x9f04f7af: return "_sys_printf"; - case 0x9f18429d: return "sys_prx_start_module"; - case 0x9f950780: return "sys_game_get_rtc_status"; - case 0xa146a143: return "sys_mempool_allocate_block"; - case 0xa1f9eafe: return "_sys_sprintf"; - case 0xa285139d: return "sys_spinlock_lock"; - case 0xa2c7ba64: return "sys_prx_exitspawn_with_level"; - case 0xa330ad84: return "sys_prx_load_module_on_memcontainer_by_fd"; - case 0xa3e3be68: return "sys_ppu_thread_once"; - case 0xa5d06bf0: return "sys_prx_get_module_list"; - case 0xaa6d9bff: return "sys_prx_load_module_on_memcontainer"; - case 0xac6fc404: return "sys_ppu_thread_unregister_atexit"; - case 0xacad8fb6: return "sys_game_watchdog_clear"; - case 0xaeb78725: return "sys_lwmutex_trylock"; - case 0xaede4b03: return "_sys_heap_delete_heap"; - case 0xaff080a4: return "sys_ppu_thread_exit"; - case 0xb257540b: return "sys_mmapper_allocate_memory"; - case 0xb27c8ae7: return "sys_prx_load_module_list"; - case 0xb2fcf2c8: return "_sys_heap_create_heap"; - case 0xb3bbcf2a: return "_sys_spu_printf_detach_thread"; - case 0xb6369393: return "_sys_heap_get_total_free_size"; - case 0xb995662e: return "sys_raw_spu_image_load"; - case 0xb9bf1078: return "_sys_heap_alloc_heap_memory"; - case 0xbdb18f83: return "_sys_malloc"; - case 0xc3476d0c: return "sys_lwmutex_destroy"; - case 0xc4fd6121: return "_sys_qsort"; - case 0xca9a60bf: return "sys_mempool_create"; - case 0xd0ea47a7: return "sys_prx_unregister_library"; - case 0xd1ad4570: return "_sys_heap_get_mallinfo"; - case 0xd3039d4d: return "_sys_strncpy"; - case 0xda0eb71a: return "sys_lwcond_create"; - case 0xdb6b3250: return "sys_spu_elf_get_segments"; - case 0xdc578057: return "sys_mmapper_map_memory"; - case 0xdd0c1e09: return "_sys_spu_printf_attach_group"; - case 0xdd3b27ac: return "_sys_spu_printf_finalize"; - case 0xe0998dbf: return "sys_prx_get_module_id_by_name"; - case 0xe0da8efd: return "sys_spu_image_close"; - case 0xe66bac36: return "console_putc"; - case 0xe6f2c1e7: return "sys_process_exit"; - case 0xe76964f5: return "sys_game_board_storage_read"; - case 0xe7ef3a80: return "sys_prx_load_module_list_on_memcontainer"; - case 0xe9a1bd84: return "sys_lwcond_signal_all"; - case 0xebe5f72f: return "sys_spu_image_import"; - case 0xeef75113: return "_sys_toupper"; - case 0xef68c17c: return "sys_prx_load_module_by_fd"; - case 0xef87a695: return "sys_lwcond_signal"; - case 0xf0aece0d: return "sys_prx_unload_module"; - case 0xf57e1d6f: return "console_write"; - case 0xf7f7fb20: return "_sys_free"; - case 0xfa7f693d: return "_sys_vprintf"; - case 0xfb5db080: return "_sys_memcmp"; - case 0xfc52a7a9: return "sys_game_process_exitspawn"; - } - - // check registered functions - if (fid < 0x100000000ull) - { - if (const auto func = get_ppu_func_by_nid(static_cast(fid))) - { - if (func->name) - { - return func->name; - } - } - } - - return ~fid < 1024 ? fmt::format("syscall_%lld", ~fid) : fmt::format("0x%08llX", fid); -} From b85a68e8a12e9bea9af04820dc04ab7d1aa15dee Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 2 Feb 2016 00:50:02 +0300 Subject: [PATCH 09/19] Partial commit: RSX --- rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp | 6 +- rpcs3/Emu/RSX/CgBinaryProgram.h | 2 +- rpcs3/Emu/RSX/CgBinaryVertexProgram.cpp | 4 +- rpcs3/Emu/RSX/Common/BufferUtils.cpp | 6 +- .../RSX/Common/FragmentProgramDecompiler.cpp | 2 +- rpcs3/Emu/RSX/Common/ProgramStateCache.h | 4 +- rpcs3/Emu/RSX/Common/ShaderParam.h | 5 +- .../RSX/Common/VertexProgramDecompiler.cpp | 1 - .../Emu/RSX/Common/VertexProgramDecompiler.h | 1 + rpcs3/Emu/RSX/Common/surface_store.h | 1 + rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp | 2 +- .../D3D12/D3D12FragmentProgramDecompiler.cpp | 1 + rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp | 62 ++++++++++++++----- rpcs3/Emu/RSX/D3D12/D3D12GSRender.h | 1 - rpcs3/Emu/RSX/D3D12/D3D12MemoryHelpers.h | 1 + rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp | 6 +- rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h | 8 +-- rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp | 17 ++--- rpcs3/Emu/RSX/GCM.cpp | 6 +- rpcs3/Emu/RSX/GL/GLCommonDecompiler.h | 4 +- rpcs3/Emu/RSX/GL/GLGSRender.cpp | 9 +-- rpcs3/Emu/RSX/GL/GLProgramBuffer.h | 4 +- rpcs3/Emu/RSX/GL/gl_helpers.cpp | 2 +- rpcs3/Emu/RSX/GL/gl_helpers.h | 27 -------- rpcs3/Emu/RSX/GL/gl_render_targets.cpp | 15 +++-- rpcs3/Emu/RSX/GSManager.cpp | 44 ------------- rpcs3/Emu/RSX/GSManager.h | 41 ------------ rpcs3/Emu/RSX/GSRender.cpp | 15 +++-- rpcs3/Emu/RSX/GSRender.h | 24 +++++-- rpcs3/Emu/RSX/RSXThread.cpp | 38 +++++++----- rpcs3/Emu/RSX/RSXThread.h | 52 +++++----------- rpcs3/Emu/RSX/VK/VKCommonDecompiler.h | 2 +- rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp | 2 +- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 2 - rpcs3/Emu/RSX/VK/VKHelpers.cpp | 2 +- rpcs3/Emu/RSX/VK/VKHelpers.h | 11 ++-- rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp | 5 +- rpcs3/Emu/RSX/VK/VKVertexProgram.cpp | 2 +- rpcs3/Emu/RSX/VK/VulkanAPI.cpp | 2 +- rpcs3/Emu/RSX/rsx_methods.cpp | 35 +++++------ 40 files changed, 200 insertions(+), 274 deletions(-) delete mode 100644 rpcs3/Emu/RSX/GSManager.cpp delete mode 100644 rpcs3/Emu/RSX/GSManager.h diff --git a/rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp b/rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp index 9c9aee7dcd..743be6817a 100644 --- a/rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp @@ -6,7 +6,7 @@ void CgBinaryDisasm::AddCodeAsm(const std::string& code) { - assert(m_opcode < 70); + Expects(m_opcode < 70); std::string op_name = ""; if (dst.dest_reg == 63) @@ -223,7 +223,7 @@ void CgBinaryDisasm::TaskFP() { m_size = 0; u32* data = (u32*)&m_buffer[m_offset]; - assert((m_buffer_size - m_offset) % sizeof(u32) == 0); + Expects((m_buffer_size - m_offset) % sizeof(u32) == 0); for (u32 i = 0; i < (m_buffer_size - m_offset) / sizeof(u32); i++) { data[i] = se_storage::swap(data[i]); // WTF, cannot use be_t<> there? @@ -471,7 +471,7 @@ void CgBinaryDisasm::TaskFP() break; } - assert(m_step % sizeof(u32) == 0); + Ensures(m_step % sizeof(u32) == 0); data += m_step / sizeof(u32); } } \ No newline at end of file diff --git a/rpcs3/Emu/RSX/CgBinaryProgram.h b/rpcs3/Emu/RSX/CgBinaryProgram.h index f29905d225..566468ecea 100644 --- a/rpcs3/Emu/RSX/CgBinaryProgram.h +++ b/rpcs3/Emu/RSX/CgBinaryProgram.h @@ -373,7 +373,7 @@ public: m_offset = prog.ucode; u32* vdata = (u32*)&m_buffer[m_offset]; - assert((m_buffer_size - m_offset) % sizeof(u32) == 0); + Ensures((m_buffer_size - m_offset) % sizeof(u32) == 0); for (u32 i = 0; i < (m_buffer_size - m_offset) / sizeof(u32); i++) { vdata[i] = se_storage::swap(vdata[i]); // WTF, cannot use be_t<> there? diff --git a/rpcs3/Emu/RSX/CgBinaryVertexProgram.cpp b/rpcs3/Emu/RSX/CgBinaryVertexProgram.cpp index 4ebe12a0b0..a318201274 100644 --- a/rpcs3/Emu/RSX/CgBinaryVertexProgram.cpp +++ b/rpcs3/Emu/RSX/CgBinaryVertexProgram.cpp @@ -6,13 +6,13 @@ void CgBinaryDisasm::AddScaCodeDisasm(const std::string& code) { - assert(m_sca_opcode < 21); + Expects(m_sca_opcode < 21); m_arb_shader += rsx_vp_sca_op_names[m_sca_opcode] + code + " "; } void CgBinaryDisasm::AddVecCodeDisasm(const std::string& code) { - assert(m_vec_opcode < 26); + Expects(m_vec_opcode < 26); m_arb_shader += rsx_vp_vec_op_names[m_vec_opcode] + code + " "; } diff --git a/rpcs3/Emu/RSX/Common/BufferUtils.cpp b/rpcs3/Emu/RSX/Common/BufferUtils.cpp index 34526bedb8..05c4a8acdc 100644 --- a/rpcs3/Emu/RSX/Common/BufferUtils.cpp +++ b/rpcs3/Emu/RSX/Common/BufferUtils.cpp @@ -254,7 +254,7 @@ bool is_primitive_native(rsx::primitive_type draw_mode) case rsx::primitive_type::quad_strip: return false; } - throw new EXCEPTION("Wrong primitive type"); + throw EXCEPTION("Wrong primitive type"); } /** We assume that polygon is convex in polygon mode (constraints in OpenGL) @@ -289,7 +289,7 @@ size_t get_index_type_size(rsx::index_array_type type) case rsx::index_array_type::u16: return sizeof(u16); case rsx::index_array_type::u32: return sizeof(u32); } - throw new EXCEPTION("Wrong index type"); + throw EXCEPTION("Wrong index type"); } void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst, rsx::primitive_type draw_mode, unsigned first, unsigned count) @@ -386,7 +386,7 @@ std::tuple write_index_array_data_to_buffer_impl(gsl::span({ ptr, count }, dst, is_primitive_restart_enabled, primitive_restart_index); } - throw new EXCEPTION("Unknow draw mode"); + throw EXCEPTION("Unknow draw mode"); } std::tuple write_index_array_data_to_buffer(gsl::span dst, rsx::index_array_type type, rsx::primitive_type draw_mode, const std::vector > &first_count_arguments) diff --git a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp index 13cf23d71d..938f0d9c5e 100644 --- a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp @@ -644,7 +644,7 @@ std::string FragmentProgramDecompiler::Decompile() if (dst.end) break; - assert(m_offset % sizeof(u32) == 0); + Ensures(m_offset % sizeof(u32) == 0); data += m_offset / sizeof(u32); } diff --git a/rpcs3/Emu/RSX/Common/ProgramStateCache.h b/rpcs3/Emu/RSX/Common/ProgramStateCache.h index 1f6e82050a..3aae330991 100644 --- a/rpcs3/Emu/RSX/Common/ProgramStateCache.h +++ b/rpcs3/Emu/RSX/Common/ProgramStateCache.h @@ -162,7 +162,7 @@ public: auto I = m_vertex_shader_cache.find(rsx_vp); if (I != m_vertex_shader_cache.end()) return I->second; - throw new EXCEPTION("Trying to get unknow transform program"); + throw EXCEPTION("Trying to get unknown transform program"); } const fragment_program_type& get_shader_program(const RSXFragmentProgram& rsx_fp) const @@ -170,7 +170,7 @@ public: auto I = m_fragment_shader_cache.find(rsx_fp); if (I != m_fragment_shader_cache.end()) return I->second; - throw new EXCEPTION("Trying to get unknow shader program"); + throw EXCEPTION("Trying to get unknown shader program"); } template diff --git a/rpcs3/Emu/RSX/Common/ShaderParam.h b/rpcs3/Emu/RSX/Common/ShaderParam.h index 02458cb1cb..c542ac8141 100644 --- a/rpcs3/Emu/RSX/Common/ShaderParam.h +++ b/rpcs3/Emu/RSX/Common/ShaderParam.h @@ -149,10 +149,7 @@ public: { auto var_blocks = fmt::split(var, { "." }); - if (var_blocks.size() == 0) - { - assert(0); - } + Expects(var_blocks.size() != 0); name = var_blocks[0]; diff --git a/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp b/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp index 3b0e156868..39f72c2674 100644 --- a/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp @@ -395,7 +395,6 @@ std::string VertexProgramDecompiler::BuildCode() { lvl -= m_instructions[i].close_scopes; if (lvl < 1) lvl = 1; - //assert(lvl >= 1); for (int j = 0; j < m_instructions[i].put_close_scopes; ++j) { --lvl; diff --git a/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.h b/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.h index e01dc5f2ba..9ac403340d 100644 --- a/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.h +++ b/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.h @@ -1,6 +1,7 @@ #pragma once #include "Emu/RSX/RSXVertexProgram.h" #include +#include #include #include "ShaderParam.h" diff --git a/rpcs3/Emu/RSX/Common/surface_store.h b/rpcs3/Emu/RSX/Common/surface_store.h index 7d5448099a..41b440af38 100644 --- a/rpcs3/Emu/RSX/Common/surface_store.h +++ b/rpcs3/Emu/RSX/Common/surface_store.h @@ -2,6 +2,7 @@ #include #include "../GCM.h" +#include namespace rsx { diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp index a6a94fffe6..c987400078 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp @@ -350,7 +350,7 @@ std::tuple> D3D12GSRe return std::make_tuple(true, index_count, upload_vertex_attributes(first_count_commands, command_list)); } - assert(draw_command == rsx::draw_command::indexed); + Expects(draw_command == rsx::draw_command::indexed); // Index count size_t index_count = get_index_count(draw_mode, gsl::narrow(get_vertex_count(first_count_commands))); diff --git a/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp index 0876e961fe..1eba50945c 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp @@ -5,6 +5,7 @@ #include "D3D12CommonDecompiler.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" +#include D3D12FragmentDecompiler::D3D12FragmentDecompiler(const RSXFragmentProgram &prog, u32& size) : FragmentProgramDecompiler(prog, size) diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp index e304861c78..c4f2e66e17 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp @@ -1,17 +1,27 @@ #include "stdafx.h" #include "stdafx_d3d12.h" #ifdef _MSC_VER +#include "Utilities/Config.h" #include "D3D12GSRender.h" #include #include #include #include +#include +#include #include "d3dx12.h" #include -#include "Emu/state.h" #include "D3D12Formats.h" #include "../rsx_methods.h" +extern cfg::bool_entry g_cfg_rsx_vsync; +extern cfg::bool_entry g_cfg_rsx_debug_output; +extern cfg::bool_entry g_cfg_rsx_overlay; + +static cfg::node s_cfg_d3d12(cfg::root.video, "D3D12"); + +cfg::string_entry g_cfg_d3d12_adapter(s_cfg_d3d12, "Adapter"); + PFN_D3D12_CREATE_DEVICE wrapD3D12CreateDevice; PFN_D3D12_GET_DEBUG_INTERFACE wrapD3D12GetDebugInterface; PFN_D3D12_SERIALIZE_ROOT_SIGNATURE wrapD3D12SerializeRootSignature; @@ -33,13 +43,13 @@ HMODULE D3DCompiler; void loadD3D12FunctionPointers() { - CHECK_ASSERTION(D3D12Module = LoadLibrary(L"d3d12.dll")); + ASSERT(D3D12Module = LoadLibrary(L"d3d12.dll")); wrapD3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)GetProcAddress(D3D12Module, "D3D12CreateDevice"); wrapD3D12GetDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress(D3D12Module, "D3D12GetDebugInterface"); wrapD3D12SerializeRootSignature = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)GetProcAddress(D3D12Module, "D3D12SerializeRootSignature"); - CHECK_ASSERTION(D3D11Module = LoadLibrary(L"d3d11.dll")); + ASSERT(D3D11Module = LoadLibrary(L"d3d11.dll")); wrapD3D11On12CreateDevice = (PFN_D3D11ON12_CREATE_DEVICE)GetProcAddress(D3D11Module, "D3D11On12CreateDevice"); - CHECK_ASSERTION(D3DCompiler = LoadLibrary(L"d3dcompiler_47.dll")); + ASSERT(D3DCompiler = LoadLibrary(L"d3dcompiler_47.dll")); wrapD3DCompile = (pD3DCompile)GetProcAddress(D3DCompiler, "D3DCompile"); } @@ -130,9 +140,11 @@ namespace } D3D12GSRender::D3D12GSRender() - : GSRender(frame_type::DX12), m_d3d12_lib(), m_current_pso({}) + : GSRender(frame_type::DX12) + , m_d3d12_lib() + , m_current_pso({}) { - if (rpcs3::config.rsx.d3d12.debug_output.value()) + if (g_cfg_rsx_debug_output) { Microsoft::WRL::ComPtr debugInterface; wrapD3D12GetDebugInterface(IID_PPV_ARGS(&debugInterface)); @@ -141,10 +153,30 @@ D3D12GSRender::D3D12GSRender() Microsoft::WRL::ComPtr dxgi_factory; CHECK_HRESULT(CreateDXGIFactory(IID_PPV_ARGS(&dxgi_factory))); + // Create adapter - ComPtr adaptater = nullptr; - CHECK_HRESULT(dxgi_factory->EnumAdapters(rpcs3::state.config.rsx.d3d12.adaptater.value(), adaptater.GetAddressOf())); - CHECK_HRESULT(wrapD3D12CreateDevice(adaptater.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device))); + ComPtr adapter; + const std::wstring& adapter_name = std::wstring_convert>().from_bytes(g_cfg_d3d12_adapter); + + for (UINT id = 0; dxgi_factory->EnumAdapters(id, adapter.ReleaseAndGetAddressOf()) != DXGI_ERROR_NOT_FOUND; id++) + { + DXGI_ADAPTER_DESC desc; + adapter->GetDesc(&desc); + + // Adapter with specified name + if (adapter_name == desc.Description) + { + break; + } + + // Default adapter + if (id == 1 && adapter_name.empty()) + { + break; + } + } + + CHECK_HRESULT(wrapD3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device))); // Queues D3D12_COMMAND_QUEUE_DESC graphic_queue_desc = { D3D12_COMMAND_LIST_TYPE_DIRECT }; @@ -224,7 +256,7 @@ D3D12GSRender::D3D12GSRender() ) ); - if (rpcs3::config.rsx.d3d12.overlay.value()) + if (g_cfg_rsx_overlay) init_d2d_structures(); } @@ -418,7 +450,7 @@ void D3D12GSRender::end() m_timers.draw_calls_duration += std::chrono::duration_cast(end_duration - start_duration).count(); m_timers.draw_calls_count++; - if (rpcs3::config.rsx.d3d12.debug_output.value()) + if (g_cfg_rsx_debug_output) { CHECK_HRESULT(get_current_resource_storage().command_list->Close()); m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf()); @@ -454,7 +486,7 @@ void D3D12GSRender::flip(int buffer) if (!is_flip_surface_in_global_memory(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))) { resource_storage &storage = get_current_resource_storage(); - assert(storage.ram_framebuffer == nullptr); + ASSERT(storage.ram_framebuffer == nullptr); size_t w = 0, h = 0, row_pitch = 0; @@ -583,21 +615,21 @@ void D3D12GSRender::flip(int buffer) if (resource_to_flip) get_current_resource_storage().command_list->DrawInstanced(4, 1, 0, 0); - if (!rpcs3::config.rsx.d3d12.overlay.value()) + if (!g_cfg_rsx_overlay) get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_backbuffer[m_swap_chain->GetCurrentBackBufferIndex()].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT)); if (is_flip_surface_in_global_memory(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])) && resource_to_flip != nullptr) get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(resource_to_flip, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_RENDER_TARGET)); CHECK_HRESULT(get_current_resource_storage().command_list->Close()); m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf()); - if(rpcs3::config.rsx.d3d12.overlay.value()) + if (g_cfg_rsx_overlay) render_overlay(); reset_timer(); std::chrono::time_point flip_start = std::chrono::system_clock::now(); - CHECK_HRESULT(m_swap_chain->Present(rpcs3::state.config.rsx.vsync.value() ? 1 : 0, 0)); + CHECK_HRESULT(m_swap_chain->Present(g_cfg_rsx_vsync ? 1 : 0, 0)); // Add an event signaling queue completion resource_storage &storage = get_non_current_resource_storage(); diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h index 51dd134cfe..ff995241a2 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h @@ -1,7 +1,6 @@ #pragma once #include "D3D12Utils.h" -#include "Utilities/rPlatform.h" // only for rImage #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/RSX/GSRender.h" diff --git a/rpcs3/Emu/RSX/D3D12/D3D12MemoryHelpers.h b/rpcs3/Emu/RSX/D3D12/D3D12MemoryHelpers.h index 24290d5b91..2de6ee913b 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12MemoryHelpers.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12MemoryHelpers.h @@ -2,6 +2,7 @@ #include "D3D12Utils.h" #include "d3dx12.h" #include "../Common/ring_buffer_helper.h" +#include struct d3d12_data_heap : public data_heap { diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp index fdb6e003ae..2ba3d0e5ec 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp @@ -1,14 +1,16 @@ #include "stdafx.h" #include "stdafx_d3d12.h" #ifdef _MSC_VER +#include "Utilities/Config.h" #include "D3D12PipelineState.h" #include "D3D12GSRender.h" -#include "Emu/state.h" #include "D3D12Formats.h" #include "../rsx_methods.h" #define TO_STRING(x) #x +extern cfg::bool_entry g_cfg_rsx_debug_output; + extern pD3DCompile wrapD3DCompile; void Shader::Compile(const std::string &code, SHADER_TYPE st) @@ -17,7 +19,7 @@ void Shader::Compile(const std::string &code, SHADER_TYPE st) HRESULT hr; ComPtr errorBlob; UINT compileFlags; - if (rpcs3::config.rsx.d3d12.debug_output.value()) + if (g_cfg_rsx_debug_output) compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; else compileFlags = 0; diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h index a84e8ca92a..2fc7de5364 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h @@ -130,7 +130,7 @@ struct D3D12Traits } } - fs::file(fs::get_config_dir() + "FragmentProgram" + std::to_string(ID) + ".hlsl", fom::rewrite).write(shader); + fs::file(fs::get_config_dir() + "FragmentProgram" + std::to_string(ID) + ".hlsl", fs::rewrite).write(shader); fragmentProgramData.id = (u32)ID; } @@ -141,7 +141,7 @@ struct D3D12Traits std::string shaderCode = VS.Decompile(); vertexProgramData.Compile(shaderCode, Shader::SHADER_TYPE::SHADER_TYPE_VERTEX); vertexProgramData.vertex_shader_input_count = RSXVP.rsx_vertex_inputs.size(); - fs::file(fs::get_config_dir() + "VertexProgram" + std::to_string(ID) + ".hlsl", fom::rewrite).write(shaderCode); + fs::file(fs::get_config_dir() + "VertexProgram" + std::to_string(ID) + ".hlsl", fs::rewrite).write(shaderCode); vertexProgramData.id = (u32)ID; } @@ -154,12 +154,12 @@ struct D3D12Traits D3D12_GRAPHICS_PIPELINE_STATE_DESC graphicPipelineStateDesc = {}; if (vertexProgramData.bytecode == nullptr) - throw new EXCEPTION("Vertex program compilation failure"); + throw EXCEPTION("Vertex program compilation failure"); graphicPipelineStateDesc.VS.BytecodeLength = vertexProgramData.bytecode->GetBufferSize(); graphicPipelineStateDesc.VS.pShaderBytecode = vertexProgramData.bytecode->GetBufferPointer(); if (fragmentProgramData.bytecode == nullptr) - throw new EXCEPTION("fragment program compilation failure"); + throw EXCEPTION("fragment program compilation failure"); graphicPipelineStateDesc.PS.BytecodeLength = fragmentProgramData.bytecode->GetBufferSize(); graphicPipelineStateDesc.PS.pShaderBytecode = fragmentProgramData.bytecode->GetBufferPointer(); diff --git a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp index f10cbb9bbe..1370d91f30 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp @@ -1,11 +1,10 @@ #include "stdafx.h" #include "stdafx_d3d12.h" #ifdef _MSC_VER +#include "Utilities/Config.h" #include "D3D12RenderTargetSets.h" -#include "Utilities/rPlatform.h" // only for rImage #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" #include "Emu/RSX/GSRender.h" #include "../rsx_methods.h" @@ -13,6 +12,10 @@ #include "D3D12GSRender.h" #include "D3D12Formats.h" +extern cfg::bool_entry g_cfg_rsx_debug_output; +extern cfg::bool_entry g_cfg_rsx_write_color_buffers; +extern cfg::bool_entry g_cfg_rsx_write_depth_buffer; + namespace { u32 get_max_depth_value(rsx::surface_depth_format format) @@ -159,7 +162,7 @@ void D3D12GSRender::clear_surface(u32 arg) m_timers.draw_calls_duration += std::chrono::duration_cast(end_duration - start_duration).count(); m_timers.draw_calls_count++; - if (rpcs3::config.rsx.d3d12.debug_output.value()) + if (g_cfg_rsx_debug_output) { CHECK_HRESULT(get_current_resource_storage().command_list->Close()); m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf()); @@ -330,7 +333,7 @@ void D3D12GSRender::copy_render_target_to_dma_location() bool need_transfer = false; - if (m_context_dma_z && rpcs3::state.config.rsx.opengl.write_depth_buffer) + if (m_context_dma_z && g_cfg_rsx_write_depth_buffer) { get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_depth_stencil), D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_COPY_SOURCE)); get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(m_readback_resources.get_heap(), { depth_buffer_offset_in_heap,{ DXGI_FORMAT_R32_TYPELESS, (UINT)clip_w, (UINT)clip_h, 1, (UINT)depth_row_pitch } }), 0, 0, 0, @@ -342,7 +345,7 @@ void D3D12GSRender::copy_render_target_to_dma_location() } size_t color_buffer_offset_in_heap[4]; - if (rpcs3::state.config.rsx.opengl.write_color_buffers) + if (g_cfg_rsx_write_color_buffers) { for (u8 i : get_rtt_indexes(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))) { @@ -363,7 +366,7 @@ void D3D12GSRender::copy_render_target_to_dma_location() //Wait for result wait_for_command_queue(m_device.Get(), m_command_queue.Get()); - if (address_z && rpcs3::state.config.rsx.opengl.write_depth_buffer) + if (address_z && g_cfg_rsx_write_depth_buffer) { auto ptr = vm::base(address_z); char *depth_buffer = (char*)ptr; @@ -383,7 +386,7 @@ void D3D12GSRender::copy_render_target_to_dma_location() m_readback_resources.unmap(); } - if (rpcs3::state.config.rsx.opengl.write_color_buffers) + if (g_cfg_rsx_write_color_buffers) { size_t srcPitch = get_aligned_pitch(m_surface.color_format, clip_w); size_t dstPitch = get_packed_pitch(m_surface.color_format, clip_w); diff --git a/rpcs3/Emu/RSX/GCM.cpp b/rpcs3/Emu/RSX/GCM.cpp index 645ecd9106..2910594db2 100644 --- a/rpcs3/Emu/RSX/GCM.cpp +++ b/rpcs3/Emu/RSX/GCM.cpp @@ -731,7 +731,7 @@ rsx::vertex_base_type rsx::to_vertex_base_type(u8 in) case 6: return rsx::vertex_base_type::cmp; case 7: return rsx::vertex_base_type::ub256; } - throw new EXCEPTION("Unknow vertex base type %d", in); + throw EXCEPTION("Unknow vertex base type %d", in); } rsx::index_array_type rsx::to_index_array_type(u8 in) @@ -741,7 +741,7 @@ rsx::index_array_type rsx::to_index_array_type(u8 in) case 0: return rsx::index_array_type::u32; case 1: return rsx::index_array_type::u16; } - throw new EXCEPTION("Unknown index array type %d", in); + throw EXCEPTION("Unknown index array type %d", in); } rsx::primitive_type rsx::to_primitive_type(u8 in) @@ -759,7 +759,7 @@ rsx::primitive_type rsx::to_primitive_type(u8 in) case 9: return rsx::primitive_type::quad_strip; case 10: return rsx::primitive_type::polygon; } - throw new EXCEPTION("Unknow primitive type %d", in); + throw EXCEPTION("Unknow primitive type %d", in); } enum diff --git a/rpcs3/Emu/RSX/GL/GLCommonDecompiler.h b/rpcs3/Emu/RSX/GL/GLCommonDecompiler.h index 6d4c11473a..e2a11f6cb6 100644 --- a/rpcs3/Emu/RSX/GL/GLCommonDecompiler.h +++ b/rpcs3/Emu/RSX/GL/GLCommonDecompiler.h @@ -1,7 +1,9 @@ #pragma once + #include "../Common/ShaderParam.h" +#include std::string getFloatTypeNameImpl(size_t elementCount); std::string getFunctionImpl(FUNCTION f); std::string compareFunctionImpl(COMPARE f, const std::string &Op0, const std::string &Op1); -void insert_glsl_legacy_function(std::ostream& OS); \ No newline at end of file +void insert_glsl_legacy_function(std::ostream& OS); diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index d728628d79..1bd3f7c505 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -1,12 +1,13 @@ #include "stdafx.h" -#include "Utilities/rPlatform.h" // only for rImage +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" #include "GLGSRender.h" #include "../rsx_methods.h" #include "../Common/BufferUtils.h" +extern cfg::bool_entry g_cfg_rsx_debug_output; + #define DUMP_VERTEX_DATA 0 namespace @@ -366,7 +367,7 @@ void GLGSRender::on_init_thread() GSRender::on_init_thread(); gl::init(); - if (rpcs3::config.rsx.d3d12.debug_output.value()) + if (g_cfg_rsx_debug_output) gl::enable_debugging(); LOG_NOTICE(RSX, "%s", (const char*)glGetString(GL_VERSION)); LOG_NOTICE(RSX, "%s", (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION)); @@ -737,4 +738,4 @@ bool GLGSRender::on_access_violation(u32 address, bool is_writing) { if (is_writing) return m_gl_texture_cache.mark_as_dirty(address); return false; -} \ No newline at end of file +} diff --git a/rpcs3/Emu/RSX/GL/GLProgramBuffer.h b/rpcs3/Emu/RSX/GL/GLProgramBuffer.h index ccecef2037..284bc70218 100644 --- a/rpcs3/Emu/RSX/GL/GLProgramBuffer.h +++ b/rpcs3/Emu/RSX/GL/GLProgramBuffer.h @@ -17,7 +17,7 @@ struct GLTraits fragmentProgramData.Compile(); //checkForGlError("m_fragment_prog.Compile"); - fs::file(fs::get_config_dir() + "FragmentProgram.txt", fom::rewrite).write(fragmentProgramData.shader); + fs::file(fs::get_config_dir() + "FragmentProgram.txt", fs::rewrite).write(fragmentProgramData.shader); } static @@ -27,7 +27,7 @@ struct GLTraits vertexProgramData.Compile(); //checkForGlError("m_vertex_prog.Compile"); - fs::file(fs::get_config_dir() + "VertexProgram.txt", fom::rewrite).write(vertexProgramData.shader); + fs::file(fs::get_config_dir() + "VertexProgram.txt", fs::rewrite).write(vertexProgramData.shader); } static diff --git a/rpcs3/Emu/RSX/GL/gl_helpers.cpp b/rpcs3/Emu/RSX/GL/gl_helpers.cpp index 862773713e..926ae5a0ae 100644 --- a/rpcs3/Emu/RSX/GL/gl_helpers.cpp +++ b/rpcs3/Emu/RSX/GL/gl_helpers.cpp @@ -20,7 +20,7 @@ namespace gl case rsx::primitive_type::quad_strip: return GL_TRIANGLES; case rsx::primitive_type::polygon: return GL_TRIANGLES; } - throw new EXCEPTION("unknow primitive type"); + throw EXCEPTION("unknow primitive type"); } #ifdef WIN32 diff --git a/rpcs3/Emu/RSX/GL/gl_helpers.h b/rpcs3/Emu/RSX/GL/gl_helpers.h index d4ef6f883c..7ec6d54f49 100644 --- a/rpcs3/Emu/RSX/GL/gl_helpers.h +++ b/rpcs3/Emu/RSX/GL/gl_helpers.h @@ -7,9 +7,6 @@ #include #include -#include -#include - #include "OpenGL.h" #include "../GCM.h" @@ -1778,23 +1775,6 @@ namespace gl void operator = (const color4i& rhs) const { m_program.use(); glUniform4i(location(), rhs.r, rhs.g, rhs.b, rhs.a); } void operator = (const color4f& rhs) const { m_program.use(); glUniform4f(location(), rhs.r, rhs.g, rhs.b, rhs.a); } //void operator = (const color4d& rhs) const { m_program.use(); glUniform4d(location(), rhs.r, rhs.g, rhs.b, rhs.a); } - - void operator = (const glm::ivec2& rhs) const { m_program.use(); glUniform2i(location(), rhs.r, rhs.g); } - void operator = (const glm::vec2& rhs) const { m_program.use(); glUniform2f(location(), rhs.r, rhs.g); } - //void operator = (const glm::dvec2& rhs) const { m_program.use(); glUniform2d(location(), rhs.r, rhs.g); } - void operator = (const glm::ivec3& rhs) const { m_program.use(); glUniform3i(location(), rhs.r, rhs.g, rhs.b); } - void operator = (const glm::vec3& rhs) const { m_program.use(); glUniform3f(location(), rhs.r, rhs.g, rhs.b); } - //void operator = (const glm::dvec3& rhs) const { m_program.use(); glUniform3d(location(), rhs.r, rhs.g, rhs.b); } - void operator = (const glm::ivec4& rhs) const { m_program.use(); glUniform4i(location(), rhs.r, rhs.g, rhs.b, rhs.a); } - void operator = (const glm::vec4& rhs) const { m_program.use(); glUniform4f(location(), rhs.r, rhs.g, rhs.b, rhs.a); } - //void operator = (const glm::dvec4& rhs) const { m_program.use(); glUniform4d(location(), rhs.r, rhs.g, rhs.b, rhs.a); } - - void operator = (const glm::mat2& rhs) const { m_program.use(); glUniformMatrix2fv(location(), 1, GL_FALSE, glm::value_ptr(rhs)); } - //void operator = (const glm::dmat2& rhs) const { m_program.use(); glUniformMatrix2dv(location(), 1, GL_FALSE, glm::value_ptr(rhs)); } - void operator = (const glm::mat3& rhs) const { m_program.use(); glUniformMatrix3fv(location(), 1, GL_FALSE, glm::value_ptr(rhs)); } - //void operator = (const glm::dmat3& rhs) const { m_program.use(); glUniformMatrix3dv(location(), 1, GL_FALSE, glm::value_ptr(rhs)); } - void operator = (const glm::mat4& rhs) const { m_program.use(); glUniformMatrix4fv(location(), 1, GL_FALSE, glm::value_ptr(rhs)); } - //void operator = (const glm::dmat4& rhs) const { m_program.use(); glUniformMatrix4dv(location(), 1, GL_FALSE, glm::value_ptr(rhs)); } }; class attrib_t @@ -1826,13 +1806,6 @@ namespace gl void operator = (const color4f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib4f(location(), rhs.r, rhs.g, rhs.b, rhs.a); } void operator = (const color4d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib4d(location(), rhs.r, rhs.g, rhs.b, rhs.a); } - void operator = (const glm::vec2& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib2f(location(), rhs.r, rhs.g); } - void operator = (const glm::dvec2& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib2d(location(), rhs.r, rhs.g); } - void operator = (const glm::vec3& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib3f(location(), rhs.r, rhs.g, rhs.b); } - void operator = (const glm::dvec3& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib3d(location(), rhs.r, rhs.g, rhs.b); } - void operator = (const glm::vec4& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib4f(location(), rhs.r, rhs.g, rhs.b, rhs.a); } - void operator = (const glm::dvec4& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib4d(location(), rhs.r, rhs.g, rhs.b, rhs.a); } - void operator =(buffer_pointer& pointer) const { pointer.get_vao().enable_for_attribute(location()); diff --git a/rpcs3/Emu/RSX/GL/gl_render_targets.cpp b/rpcs3/Emu/RSX/GL/gl_render_targets.cpp index 0aef73fc28..8a61bed026 100644 --- a/rpcs3/Emu/RSX/GL/gl_render_targets.cpp +++ b/rpcs3/Emu/RSX/GL/gl_render_targets.cpp @@ -1,7 +1,12 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "../rsx_methods.h" #include "GLGSRender.h" -#include "Emu/state.h" + +extern cfg::bool_entry g_cfg_rsx_write_color_buffers; +extern cfg::bool_entry g_cfg_rsx_write_depth_buffer; +extern cfg::bool_entry g_cfg_rsx_read_color_buffers; +extern cfg::bool_entry g_cfg_rsx_read_depth_buffer; color_format rsx::internals::surface_color_format_to_gl(rsx::surface_color_format color_format) { @@ -151,7 +156,7 @@ void GLGSRender::read_buffers() glDisable(GL_STENCIL_TEST); - if (rpcs3::state.config.rsx.opengl.read_color_buffers) + if (g_cfg_rsx_read_color_buffers) { auto color_format = rsx::internals::surface_color_format_to_gl(m_surface.color_format); @@ -222,7 +227,7 @@ void GLGSRender::read_buffers() } } - if (rpcs3::state.config.rsx.opengl.read_depth_buffer) + if (g_cfg_rsx_read_depth_buffer) { //TODO: use pitch u32 pitch = rsx::method_registers[NV4097_SET_SURFACE_PITCH_Z]; @@ -279,7 +284,7 @@ void GLGSRender::write_buffers() //TODO: Detect when the data is actually being used by cell and issue download command on-demand (mark as not present?) //Should also mark cached resources as dirty so that read buffers works out-of-the-box without modification - if (rpcs3::state.config.rsx.opengl.write_color_buffers) + if (g_cfg_rsx_write_color_buffers) { auto color_format = rsx::internals::surface_color_format_to_gl(m_surface.color_format); @@ -337,7 +342,7 @@ void GLGSRender::write_buffers() } } - if (rpcs3::state.config.rsx.opengl.write_depth_buffer) + if (g_cfg_rsx_write_depth_buffer) { //TODO: use pitch u32 pitch = rsx::method_registers[NV4097_SET_SURFACE_PITCH_Z]; diff --git a/rpcs3/Emu/RSX/GSManager.cpp b/rpcs3/Emu/RSX/GSManager.cpp deleted file mode 100644 index 6bb058a596..0000000000 --- a/rpcs3/Emu/RSX/GSManager.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "stdafx.h" -#include "Emu/System.h" -#include "Emu/Memory/Memory.h" -#include "Emu/SysCalls/Modules/cellVideoOut.h" -#include "Emu/state.h" - -#include "GSManager.h" - -void GSInfo::Init() -{ - mode.resolutionId = (u8)rpcs3::state.config.rsx.resolution.value(); - mode.scanMode = CELL_VIDEO_OUT_SCAN_MODE_INTERLACE; - mode.conversion = CELL_VIDEO_OUT_DISPLAY_CONVERSION_NONE; - mode.aspect = (u8)rpcs3::state.config.rsx.aspect_ratio.value(); - mode.refreshRates = CELL_VIDEO_OUT_REFRESH_RATE_50HZ; - mode.format = CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8; - mode.pitch = 4; -} - -void GSManager::Init() -{ - if (m_render) return; - - m_info.Init(); - - m_render = Emu.GetCallbacks().get_gs_render(); - - //m_render->Init(GetInfo().outresolution.width, GetInfo().outresolution.height); -} - -void GSManager::Close() -{ - m_render.reset(); -} - -u8 GSManager::GetState() -{ - return CELL_VIDEO_OUT_OUTPUT_STATE_ENABLED; -} - -u8 GSManager::GetColorSpace() -{ - return CELL_VIDEO_OUT_COLOR_SPACE_RGB; -} diff --git a/rpcs3/Emu/RSX/GSManager.h b/rpcs3/Emu/RSX/GSManager.h deleted file mode 100644 index 91f9ae888b..0000000000 --- a/rpcs3/Emu/RSX/GSManager.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -class GSRender; - -struct GSInfo -{ - struct - { - u8 resolutionId; - u8 scanMode; - u8 conversion; - u8 aspect; - u8 format; - u16 refreshRates; - u32 pitch; - } mode; - - GSInfo() - { - } - - void Init(); -}; - -class GSManager -{ - GSInfo m_info; - std::shared_ptr m_render; - -public: - void Init(); - void Close(); - - bool IsInited() const { return m_render != nullptr; } - - GSInfo& GetInfo() { return m_info; } - GSRender& GetRender() { return *m_render; } - - u8 GetState(); - u8 GetColorSpace(); -}; diff --git a/rpcs3/Emu/RSX/GSRender.cpp b/rpcs3/Emu/RSX/GSRender.cpp index d7358fc642..f02f51d680 100644 --- a/rpcs3/Emu/RSX/GSRender.cpp +++ b/rpcs3/Emu/RSX/GSRender.cpp @@ -1,10 +1,13 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "GSManager.h" #include "GSRender.h" +// temporarily (u8 value is really CellVideoOutResolutionId, but HLE declarations shouldn't be available for the rest of emu, even indirectly) +extern cfg::map_entry g_cfg_video_out_resolution; +extern const std::unordered_map g_video_out_resolution_map; draw_context_t GSFrameBase::new_context() { @@ -16,12 +19,8 @@ draw_context_t GSFrameBase::new_context() return nullptr; } -void GSFrameBase::title_message(const std::wstring& msg) -{ - m_title_message = msg; -} - -GSRender::GSRender(frame_type type) : m_frame(Emu.GetCallbacks().get_gs_frame(type).release()) +GSRender::GSRender(frame_type type) + : m_frame(Emu.GetCallbacks().get_gs_frame(type, g_video_out_resolution_map.at(g_cfg_video_out_resolution.get())).release()) { } @@ -36,7 +35,7 @@ GSRender::~GSRender() } } -void GSRender::on_init() +void GSRender::on_init_rsx() { if (m_frame) { diff --git a/rpcs3/Emu/RSX/GSRender.h b/rpcs3/Emu/RSX/GSRender.h index 2ebffee14a..6743d6391a 100644 --- a/rpcs3/Emu/RSX/GSRender.h +++ b/rpcs3/Emu/RSX/GSRender.h @@ -1,14 +1,29 @@ #pragma once + #include "Emu/RSX/RSXThread.h" #include +struct RSXDebuggerProgram +{ + u32 id; + u32 vp_id; + u32 fp_id; + std::string vp_shader; + std::string fp_shader; + bool modified; + + RSXDebuggerProgram() + : modified(false) + { + } +}; + +using RSXDebuggerPrograms = std::vector; + using draw_context_t = std::shared_ptr; class GSFrameBase { -protected: - std::wstring m_title_message; - public: GSFrameBase() = default; GSFrameBase(const GSFrameBase&) = delete; @@ -25,7 +40,6 @@ public: virtual size2i client_size() = 0; virtual void* handle() const = 0; - void title_message(const std::wstring&); protected: virtual void delete_context(void* ctx) = 0; @@ -50,7 +64,7 @@ public: GSRender(frame_type type); virtual ~GSRender(); - void on_init() override; + void on_init_rsx() override; void on_init_thread() override; void flip(int buffer) override; diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index f3e28cf1a2..6878d06b60 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -1,22 +1,31 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" -#include "Emu/RSX/GSManager.h" #include "RSXThread.h" -#include "Emu/SysCalls/Callback.h" -#include "Emu/SysCalls/CB_FUNC.h" -#include "Emu/SysCalls/lv2/sys_time.h" +#include "Emu/Cell/PPUCallback.h" #include "Common/BufferUtils.h" #include "rsx_methods.h" #define CMD_DEBUG 0 +cfg::bool_entry g_cfg_rsx_write_color_buffers(cfg::root.video, "Write Color Buffers"); +cfg::bool_entry g_cfg_rsx_write_depth_buffer(cfg::root.video, "Write Depth Buffer"); +cfg::bool_entry g_cfg_rsx_read_color_buffers(cfg::root.video, "Read Color Buffers"); +cfg::bool_entry g_cfg_rsx_read_depth_buffer(cfg::root.video, "Read Depth Buffer"); +cfg::bool_entry g_cfg_rsx_log_programs(cfg::root.video, "Log shader programs"); +cfg::bool_entry g_cfg_rsx_vsync(cfg::root.video, "VSync"); +cfg::bool_entry g_cfg_rsx_3dtv(cfg::root.video, "3D Monitor"); +cfg::bool_entry g_cfg_rsx_debug_output(cfg::root.video, "Debug output"); +cfg::bool_entry g_cfg_rsx_overlay(cfg::root.video, "Debug overlay"); + bool user_asked_for_frame_capture = false; frame_capture_data frame_debug; +namespace vm { using namespace ps3; } + namespace rsx { std::function g_access_violation_handler; @@ -28,14 +37,14 @@ namespace rsx void shaders_cache::load(const std::string &path, shader_language lang) { - std::string lang_name = convert::to(lang); + const std::string lang_name = bijective_find(lang, ""); auto extract_hash = [](const std::string &string) { return std::stoull(string.substr(0, string.find('.')).c_str(), 0, 16); }; - for (const fs::dir::entry &entry : fs::dir{ path }) + for (const auto& entry : fs::dir(path)) { if (entry.name == "." || entry.name == "..") continue; @@ -106,7 +115,7 @@ namespace rsx throw EXCEPTION("GetAddress(offset=0x%x, location=0x%x): RSXIO memory not mapped", offset, location); } - //if (Emu.GetGSManager().GetRender().strict_ordering[offset >> 20]) + //if (fxm::get()->strict_ordering[offset >> 20]) //{ // _mm_mfence(); // probably doesn't have any effect on current implementation //} @@ -353,7 +362,7 @@ namespace rsx last_flip_time = get_system_time() - 1000000; - scope_thread_t vblank(PURE_EXPR("VBlank Thread"s), [this]() + scope_thread vblank("VBlank Thread", [this]() { const u64 start_time = get_system_time(); @@ -386,8 +395,8 @@ namespace rsx { CHECK_EMU_STATUS; - be_t get = ctrl->get; - be_t put = ctrl->put; + const u32 get = ctrl->get; + const u32 put = ctrl->put; if (put == get || !Emu.IsRunning()) { @@ -442,10 +451,7 @@ namespace rsx u32 reg = cmd & CELL_GCM_METHOD_FLAG_NON_INCREMENT ? first_cmd : first_cmd + i; u32 value = args[i]; - if (rpcs3::config.misc.log.rsx_logging.value()) - { - LOG_NOTICE(RSX, "%s(0x%x) = 0x%x", get_method_name(reg).c_str(), reg, value); - } + LOG_TRACE(RSX, "%s(0x%x) = 0x%x", get_method_name(reg).c_str(), reg, value); method_registers[reg] = value; if (capture_current_frame) @@ -831,7 +837,7 @@ namespace rsx m_used_gcm_commands.clear(); - on_init(); + on_init_rsx(); start(); } diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 1277cc8341..d449f4c4a5 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -1,15 +1,17 @@ #pragma once +#include +#include +#include +#include #include "GCM.h" #include "RSXTexture.h" #include "RSXVertexProgram.h" #include "RSXFragmentProgram.h" -#include #include "Utilities/Semaphore.h" #include "Utilities/Thread.h" #include "Utilities/Timer.h" -#include "Utilities/convert.h" extern u64 get_system_time(); @@ -46,44 +48,20 @@ namespace rsx enum class shader_language { glsl, - hlsl + hlsl, }; } -namespace convert +template<> +struct bijective { - template<> - struct to_impl_t + static constexpr std::pair map[] { - static rsx::shader_language func(const std::string &from) - { - if (from == "glsl") - return rsx::shader_language::glsl; - - if (from == "hlsl") - return rsx::shader_language::hlsl; - - throw; - } + { rsx::shader_language::glsl, "glsl" }, + { rsx::shader_language::hlsl, "hlsl" }, }; +}; - template<> - struct to_impl_t - { - static std::string func(rsx::shader_language from) - { - switch (from) - { - case rsx::shader_language::glsl: - return "glsl"; - case rsx::shader_language::hlsl: - return "hlsl"; - } - - throw; - } - }; -} namespace rsx { namespace limits @@ -212,7 +190,7 @@ namespace rsx indexed, }; - class thread : public named_thread_t + class thread : public named_thread { protected: std::stack m_call_stack; @@ -280,7 +258,6 @@ namespace rsx u32 gcm_buffers_count; u32 gcm_current_buffer; u32 ctxt_addr; - u32 report_main_addr; u32 label_addr; rsx::draw_command draw_command; primitive_type draw_mode; @@ -324,10 +301,13 @@ namespace rsx public: virtual std::string get_name() const override; + virtual void on_init() override {} // disable start() (TODO) + virtual void on_stop() override {} // disable join() + virtual void begin(); virtual void end(); - virtual void on_init() = 0; + virtual void on_init_rsx() = 0; virtual void on_init_thread() = 0; virtual bool do_method(u32 cmd, u32 value) { return false; } virtual void flip(int buffer) = 0; diff --git a/rpcs3/Emu/RSX/VK/VKCommonDecompiler.h b/rpcs3/Emu/RSX/VK/VKCommonDecompiler.h index b5b72f70b6..0ca2d3158c 100644 --- a/rpcs3/Emu/RSX/VK/VKCommonDecompiler.h +++ b/rpcs3/Emu/RSX/VK/VKCommonDecompiler.h @@ -17,4 +17,4 @@ namespace vk const varying_register_t& get_varying_register(const std::string& name); bool compile_glsl_to_spv(std::string& shader, glsl::program_domain domain, std::vector &spv); -} \ No newline at end of file +} diff --git a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp index c2951f181e..7beb37484a 100644 --- a/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKFragmentProgram.cpp @@ -276,7 +276,7 @@ void VKFragmentProgram::Decompile(const RSXFragmentProgram& prog) void VKFragmentProgram::Compile() { - fs::file(fs::get_config_dir() + "FragmentProgram.frag", fom::rewrite).write(shader); + fs::file(fs::get_config_dir() + "FragmentProgram.frag", fs::rewrite).write(shader); std::vector spir_v; if (!vk::compile_glsl_to_spv(shader, vk::glsl::glsl_fragment_program, spir_v)) diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index b3be3b0497..dfdf299ec5 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -1,8 +1,6 @@ #include "stdafx.h" -#include "Utilities/rPlatform.h" // only for rImage #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" #include "VKGSRender.h" #include "../rsx_methods.h" #include "../Common/BufferUtils.h" diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.cpp b/rpcs3/Emu/RSX/VK/VKHelpers.cpp index 0b14fd1518..17e5b4a185 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.cpp +++ b/rpcs3/Emu/RSX/VK/VKHelpers.cpp @@ -251,4 +251,4 @@ namespace vk return false; } -} \ No newline at end of file +} diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.h b/rpcs3/Emu/RSX/VK/VKHelpers.h index 53106de926..3a64404897 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.h +++ b/rpcs3/Emu/RSX/VK/VKHelpers.h @@ -8,15 +8,14 @@ #include #include -#include -#include - -#include "Emu/state.h" +#include "Utilities/Config.h" #include "VulkanAPI.h" #include "../GCM.h" #include "../Common/TextureUtils.h" #include "../Common/ring_buffer_helper.h" +extern cfg::bool_entry g_cfg_rsx_debug_output; + namespace rsx { class texture; @@ -174,7 +173,7 @@ namespace vk std::vector layers; - if (rpcs3::config.rsx.d3d12.debug_output.value()) + if (g_cfg_rsx_debug_output) layers.push_back("VK_LAYER_LUNARG_standard_validation"); VkDeviceCreateInfo device; @@ -1039,7 +1038,7 @@ namespace vk std::vector layers; - if (rpcs3::config.rsx.d3d12.debug_output.value()) + if (g_cfg_rsx_debug_output) layers.push_back("VK_LAYER_LUNARG_standard_validation"); VkInstanceCreateInfo instance_info = {}; diff --git a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp index 6adff8ac03..0713ea9cc8 100644 --- a/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp +++ b/rpcs3/Emu/RSX/VK/VKVertexBuffers.cpp @@ -1,8 +1,6 @@ #include "stdafx.h" -#include "Utilities/rPlatform.h" // only for rImage #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" #include "VKGSRender.h" #include "../rsx_methods.h" #include "../Common/BufferUtils.h" @@ -590,4 +588,5 @@ VKGSRender::upload_vertex_data() } return std::make_tuple(prims, is_indexed_draw, index_count, offset_in_index_buffer, index_format); -} \ No newline at end of file +} + diff --git a/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp b/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp index 4841597d93..b463e6d098 100644 --- a/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp +++ b/rpcs3/Emu/RSX/VK/VKVertexProgram.cpp @@ -253,7 +253,7 @@ void VKVertexProgram::Decompile(const RSXVertexProgram& prog) void VKVertexProgram::Compile() { - fs::file(fs::get_config_dir() + "VertexProgram.vert", fom::rewrite).write(shader); + fs::file(fs::get_config_dir() + "VertexProgram.vert", fs::rewrite).write(shader); std::vector spir_v; if (!vk::compile_glsl_to_spv(shader, vk::glsl::glsl_vertex_program, spir_v)) diff --git a/rpcs3/Emu/RSX/VK/VulkanAPI.cpp b/rpcs3/Emu/RSX/VK/VulkanAPI.cpp index 1577c4e3bc..fd4f341c7b 100644 --- a/rpcs3/Emu/RSX/VK/VulkanAPI.cpp +++ b/rpcs3/Emu/RSX/VK/VulkanAPI.cpp @@ -1 +1 @@ -#include "stdafx.h" \ No newline at end of file +#include "stdafx.h" diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index b86f15c71b..8193f66324 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -1,12 +1,21 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "rsx_methods.h" #include "RSXThread.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" #include "rsx_utils.h" -#include "Emu/SysCalls/Callback.h" -#include "Emu/SysCalls/CB_FUNC.h" +#include "Emu/Cell/PPUCallback.h" + +cfg::map_entry g_cfg_rsx_frame_limit(cfg::root.video, "Frame limit", +{ + { "Off", 0. }, + { "59.94", 59.94 }, + { "50", 50. }, + { "60", 60. }, + { "30", 30. }, + { "Auto", -1. }, +}); namespace rsx { @@ -667,24 +676,14 @@ namespace rsx rsx->sem_flip.post_and_wait(); - //sync - double limit; - switch (rpcs3::state.config.rsx.frame_limit.value()) + if (double limit = g_cfg_rsx_frame_limit.get()) { - case rsx_frame_limit::_50: limit = 50.; break; - case rsx_frame_limit::_59_94: limit = 59.94; break; - case rsx_frame_limit::_30: limit = 30.; break; - case rsx_frame_limit::_60: limit = 60.; break; - case rsx_frame_limit::Auto: limit = rsx->fps_limit; break; //TODO + if (limit < 0) limit = rsx->fps_limit; // TODO - case rsx_frame_limit::Off: - default: - return; + std::this_thread::sleep_for(std::chrono::milliseconds((s64)(1000.0 / limit - rsx->timer_sync.GetElapsedTimeInMilliSec()))); + rsx->timer_sync.Start(); + rsx->local_transform_constants.clear(); } - - std::this_thread::sleep_for(std::chrono::milliseconds((s64)(1000.0 / limit - rsx->timer_sync.GetElapsedTimeInMilliSec()))); - rsx->timer_sync.Start(); - rsx->local_transform_constants.clear(); } void user_command(thread* rsx, u32 arg) From 984aa44220b12c60cd27a35eecc819e88b8242c2 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 2 Feb 2016 00:50:22 +0300 Subject: [PATCH 10/19] Partial commit: FS --- rpcs3/Emu/FS/VFS.cpp | 568 ---------------------------- rpcs3/Emu/FS/VFS.h | 98 ----- rpcs3/Emu/FS/vfsDevice.cpp | 249 ------------ rpcs3/Emu/FS/vfsDevice.h | 55 --- rpcs3/Emu/FS/vfsDeviceLocalFile.cpp | 14 - rpcs3/Emu/FS/vfsDeviceLocalFile.h | 9 - rpcs3/Emu/FS/vfsDir.cpp | 79 ---- rpcs3/Emu/FS/vfsDir.h | 17 - rpcs3/Emu/FS/vfsDirBase.cpp | 59 --- rpcs3/Emu/FS/vfsDirBase.h | 106 ------ rpcs3/Emu/FS/vfsFile.cpp | 62 --- rpcs3/Emu/FS/vfsFile.h | 26 -- rpcs3/Emu/FS/vfsFileBase.cpp | 37 -- rpcs3/Emu/FS/vfsFileBase.h | 24 -- rpcs3/Emu/FS/vfsLocalDir.cpp | 44 --- rpcs3/Emu/FS/vfsLocalDir.h | 16 - rpcs3/Emu/FS/vfsLocalFile.cpp | 49 --- rpcs3/Emu/FS/vfsLocalFile.h | 27 -- rpcs3/Emu/FS/vfsStream.cpp | 2 - rpcs3/Emu/FS/vfsStream.h | 69 ---- rpcs3/Emu/FS/vfsStreamMemory.cpp | 29 -- rpcs3/Emu/FS/vfsStreamMemory.h | 55 --- 22 files changed, 1694 deletions(-) delete mode 100644 rpcs3/Emu/FS/VFS.cpp delete mode 100644 rpcs3/Emu/FS/VFS.h delete mode 100644 rpcs3/Emu/FS/vfsDevice.cpp delete mode 100644 rpcs3/Emu/FS/vfsDevice.h delete mode 100644 rpcs3/Emu/FS/vfsDeviceLocalFile.cpp delete mode 100644 rpcs3/Emu/FS/vfsDeviceLocalFile.h delete mode 100644 rpcs3/Emu/FS/vfsDir.cpp delete mode 100644 rpcs3/Emu/FS/vfsDir.h delete mode 100644 rpcs3/Emu/FS/vfsDirBase.cpp delete mode 100644 rpcs3/Emu/FS/vfsDirBase.h delete mode 100644 rpcs3/Emu/FS/vfsFile.cpp delete mode 100644 rpcs3/Emu/FS/vfsFile.h delete mode 100644 rpcs3/Emu/FS/vfsFileBase.cpp delete mode 100644 rpcs3/Emu/FS/vfsFileBase.h delete mode 100644 rpcs3/Emu/FS/vfsLocalDir.cpp delete mode 100644 rpcs3/Emu/FS/vfsLocalDir.h delete mode 100644 rpcs3/Emu/FS/vfsLocalFile.cpp delete mode 100644 rpcs3/Emu/FS/vfsLocalFile.h delete mode 100644 rpcs3/Emu/FS/vfsStream.cpp delete mode 100644 rpcs3/Emu/FS/vfsStream.h delete mode 100644 rpcs3/Emu/FS/vfsStreamMemory.cpp delete mode 100644 rpcs3/Emu/FS/vfsStreamMemory.h diff --git a/rpcs3/Emu/FS/VFS.cpp b/rpcs3/Emu/FS/VFS.cpp deleted file mode 100644 index fdcfa4a37d..0000000000 --- a/rpcs3/Emu/FS/VFS.cpp +++ /dev/null @@ -1,568 +0,0 @@ -#include "stdafx.h" -#include "VFS.h" -#include "vfsDir.h" -#include "vfsFile.h" -#include "vfsDirBase.h" -#include "Emu/HDD/HDD.h" -#include "vfsDeviceLocalFile.h" -#include "Emu/System.h" -#include "Emu/state.h" - -std::vector simplify_path_blocks(const std::string& path) -{ - // fmt::tolower() removed - std::vector path_blocks = std::move(fmt::split(path, { "/", "\\" })); - - for (s32 i = 0; i < path_blocks.size(); ++i) - { - if (path_blocks[i] == "." || (i > 0 && path_blocks[i].empty())) - { - path_blocks.erase(path_blocks.begin() + i); - i--; - } - else if (i > 0 && path_blocks[i] == "..") - { - path_blocks.erase(path_blocks.begin() + (i - 1), path_blocks.begin() + (i + 1)); - i--; - } - } - - return path_blocks; -} - -std::string simplify_path(const std::string& path, bool is_dir, bool is_ps3) -{ - std::vector path_blocks = simplify_path_blocks(path); - - if (path_blocks.empty()) - return ""; - - std::string result = fmt::merge(path_blocks, "/"); - -#ifdef _WIN32 - if (is_ps3) -#endif - { - result = "/" + result; - } - - if (is_dir) result = result + "/"; - - return result; -} - -VFS::~VFS() -{ - UnMountAll(); -} - -void VFS::Mount(const std::string& ps3_path, const std::string& local_path, vfsDevice* device) -{ - std::string simpl_ps3_path = simplify_path(ps3_path, true, true); - - UnMount(simpl_ps3_path); - - device->SetPath(simpl_ps3_path, simplify_path(local_path, true, false)); - m_devices.push_back(device); - - if (m_devices.size() > 1) - { - std::sort(m_devices.begin(), m_devices.end(), [](vfsDevice *a, vfsDevice *b) { return b->GetPs3Path().length() < a->GetPs3Path().length(); }); - } -} - -void VFS::Link(const std::string& mount_point, const std::string& ps3_path) -{ - links[simplify_path_blocks(mount_point)] = simplify_path_blocks(ps3_path); -} - -std::string VFS::GetLinked(const std::string& ps3_path) const -{ - // fmt::tolower removed - auto path_blocks = fmt::split(ps3_path, { "/", "\\" }); - - for (auto link : links) - { - if (path_blocks.size() < link.first.size()) - continue; - - bool is_ok = true; - - for (size_t i = 0; i < link.first.size(); ++i) - { - if (link.first[i] != path_blocks[i]) - { - is_ok = false; - break; - } - } - - if (is_ok) - return fmt::merge({ link.second, std::vector(path_blocks.begin() + link.first.size(), path_blocks.end()) }, "/"); - } - - return ps3_path; -} - -void VFS::UnMount(const std::string& ps3_path) -{ - std::string simpl_ps3_path = simplify_path(ps3_path, true, true); - - for (u32 i = 0; i < m_devices.size(); ++i) - { - if (!strcmp(m_devices[i]->GetPs3Path().c_str(), simpl_ps3_path.c_str())) - { - delete m_devices[i]; - - m_devices.erase(m_devices.begin() +i); - - return; - } - } -} - -void VFS::UnMountAll() -{ - for(u32 i=0; iGetNewFileStream()) - { - res->Open(path, mode); - return res; - } - } - - return nullptr; -} - -vfsDirBase* VFS::OpenDir(const std::string& ps3_path) const -{ - std::string path; - - if (vfsDevice* dev = GetDevice(ps3_path, path)) - { - if (vfsDirBase* res = dev->GetNewDirStream()) - { - res->Open(path); - return res; - } - } - - return nullptr; -} - -bool VFS::CreateDir(const std::string& ps3_path) const -{ - std::string path; - - if (vfsDevice* dev = GetDevice(ps3_path, path)) - { - // return dev->create_dir(path); - return fs::create_dir(path); - } - - return false; -} - -bool VFS::CreatePath(const std::string& ps3_path) const -{ - std::string path; - - if (vfsDevice* dev = GetDevice(ps3_path, path)) - { - // return dev->create_path(path); - return fs::create_path(path); - } - - return false; -} - -bool VFS::RemoveFile(const std::string& ps3_path) const -{ - std::string path; - - if (vfsDevice* dev = GetDevice(ps3_path, path)) - { - // return dev->remove_file(path); - return fs::remove_file(path); - } - - return false; -} - -bool VFS::RemoveDir(const std::string& ps3_path) const -{ - std::string path; - - if (vfsDevice* dev = GetDevice(ps3_path, path)) - { - // return dev->remove_dir(path); - return fs::remove_dir(path); - } - - return false; -} - -void VFS::DeleteAll(const std::string& ps3_path) const -{ - // Delete directory and all its contents recursively - for (const auto entry : vfsDir(ps3_path)) - { - if (entry->name == "." || entry->name == "..") - { - continue; - } - - if (entry->flags & DirEntry_TypeFile) - { - RemoveFile(ps3_path + "/" + entry->name); - } - - if (entry->flags & DirEntry_TypeDir) - { - DeleteAll(ps3_path + "/" + entry->name); - } - } - - RemoveDir(ps3_path); -} - -u64 VFS::GetDirSize(const std::string& ps3_path) const -{ - u64 result = 0; - - for (const auto entry : vfsDir(ps3_path)) - { - if (entry->name == "." || entry->name == "..") - { - continue; - } - - if (entry->flags & DirEntry_TypeFile) - { - result += entry->size; - } - - if (entry->flags & DirEntry_TypeDir) - { - result += GetDirSize(ps3_path + "/" + entry->name); - } - } - - return result; -} - -bool VFS::ExistsFile(const std::string& ps3_path) const -{ - std::string path; - - if (vfsDevice* dev = GetDevice(ps3_path, path)) - { - // return dev->is_file(path); - return fs::is_file(path); - } - - return false; -} - -bool VFS::ExistsDir(const std::string& ps3_path) const -{ - std::string path; - - if (vfsDevice* dev = GetDevice(ps3_path, path)) - { - // return dev->is_dir(path); - return fs::is_dir(path); - } - - return false; -} - -bool VFS::Exists(const std::string& ps3_path) const -{ - std::string path; - - if (vfsDevice* dev = GetDevice(ps3_path, path)) - { - // return dev->exists(path); - return fs::exists(path); - } - - return false; -} - -bool VFS::Rename(const std::string& ps3_path_from, const std::string& ps3_path_to) const -{ - std::string path_from, path_to; - - if (vfsDevice* dev = GetDevice(ps3_path_from, path_from)) - { - if (vfsDevice* dev_ = GetDevice(ps3_path_to, path_to)) - { - // return dev->rename(dev_, path_from, path_to); - return fs::rename(path_from, path_to); - } - } - - return false; -} - -bool VFS::CopyFile(const std::string& ps3_path_from, const std::string& ps3_path_to, bool overwrite) const -{ - std::string path_from, path_to; - - if (vfsDevice* dev = GetDevice(ps3_path_from, path_from)) - { - if (vfsDevice* dev_ = GetDevice(ps3_path_to, path_to)) - { - // return dev->copy_file(dev_, path_from, path_to, overwrite); - return fs::copy_file(path_from, path_to, overwrite); - } - } - - return false; -} - -bool VFS::TruncateFile(const std::string& ps3_path, u64 length) const -{ - std::string path; - - if (vfsDevice* dev = GetDevice(ps3_path, path)) - { - // return dev->truncate_file(path, length); - return fs::truncate_file(path, length); - } - - return false; -} - -vfsDevice* VFS::GetDevice(const std::string& ps3_path, std::string& path) const -{ - auto try_get_device = [this, &path](const std::string& ps3_path) -> vfsDevice* - { - std::vector ps3_path_blocks = simplify_path_blocks(ps3_path); - size_t max_eq = 0; - int max_i = -1; - - for (u32 i = 0; i < m_devices.size(); ++i) - { - std::vector dev_ps3_path_blocks = simplify_path_blocks(m_devices[i]->GetPs3Path()); - - if (ps3_path_blocks.size() < dev_ps3_path_blocks.size()) - continue; - - size_t eq = 0; - for (; eq < dev_ps3_path_blocks.size(); ++eq) - { - if (strcmp(ps3_path_blocks[eq].c_str(), dev_ps3_path_blocks[eq].c_str())) - { - break; - } - } - - if (eq > max_eq) - { - max_eq = eq; - max_i = i; - } - } - - if (max_i < 0) - return nullptr; - - path = m_devices[max_i]->GetLocalPath(); - - for (size_t i = max_eq; i < ps3_path_blocks.size(); i++) - { - path += "/" + ps3_path_blocks[i]; - } - - path = simplify_path(path, false, false); - - return m_devices[max_i]; - }; - - if (!ps3_path.size() || ps3_path[0] != '/') - { - return nullptr; - } - - return try_get_device(GetLinked(ps3_path)); - - // What is it? cwd is real path, ps3_path is ps3 path, but GetLinked accepts ps3 path - //if (auto res = try_get_device(GetLinked(cwd + ps3_path))) - // return res; -} - -vfsDevice* VFS::GetDeviceLocal(const std::string& local_path, std::string& path) const -{ - int max_eq = -1; - int max_i = -1; - - std::vector local_path_blocks = simplify_path_blocks(local_path); - - for (u32 i = 0; i < m_devices.size(); ++i) - { - std::vector dev_local_path_blocks = simplify_path_blocks(m_devices[i]->GetLocalPath()); - - if (local_path_blocks.size() < dev_local_path_blocks.size()) - continue; - - int dev_blocks = dev_local_path_blocks.size(); - - bool prefix_equal = std::equal( - std::begin(dev_local_path_blocks), - std::end(dev_local_path_blocks), - std::begin(local_path_blocks), - [](const std::string& a, const std::string& b){ return strcmp(a.c_str(), b.c_str()) == 0; } - ); - - if (prefix_equal && dev_blocks > max_eq) - { - max_eq = dev_blocks; - max_i = i; - } - } - - if (max_i < 0) - return nullptr; - - path = m_devices[max_i]->GetPs3Path(); - - for (size_t i = max_eq; i < local_path_blocks.size(); i++) - { - path += "/" + local_path_blocks[i]; - } - - path = simplify_path(path, false, true); - - return m_devices[max_i]; -} - -void VFS::Init(const std::string& path) -{ - cwd = simplify_path(path, true, false); - - UnMountAll(); - - std::vector entries; - SaveLoadDevices(entries, true); - - for(const VFSManagerEntry& entry : entries) - { - vfsDevice* dev; - - switch(entry.device) - { - case vfsDevice_LocalFile: - dev = new vfsDeviceLocalFile(); - break; - - case vfsDevice_HDD: - dev = new vfsDeviceHDD(entry.device_path); - break; - - default: - continue; - } - - std::string mpath = entry.path; - // If no value assigned to SysEmulationDirPath in INI, use the path that with executable. - if (rpcs3::config.system.emulation_dir_path_enable.value()) - { - fmt::Replace(mpath, "$(EmulatorDir)", rpcs3::config.system.emulation_dir_path.value()); - } - else - { - fmt::Replace(mpath, "$(EmulatorDir)", fs::get_executable_dir()); - } - fmt::Replace(mpath, "$(GameDir)", cwd); - Mount(entry.mount, mpath, dev); - } - - Link("/app_home/", "/host_root/" + cwd); -} - -void VFS::SaveLoadDevices(std::vector& res, bool is_load) -{ - int count = 0; - if (is_load) - { - count = rpcs3::config.vfs.count.value(); - - if (!count) - { - res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_hdd0/", "/dev_hdd0/"); - res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_hdd1/", "/dev_hdd1/"); - res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_flash/", "/dev_flash/"); - res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_usb000/", "/dev_usb000/"); - res.emplace_back(vfsDevice_LocalFile, "$(EmulatorDir)/dev_usb000/", "/dev_usb/"); - res.emplace_back(vfsDevice_LocalFile, "", "/host_root/"); - - return; - } - - res.resize(count); - } - else - { - count = (int)res.size(); - rpcs3::config.vfs.count = count; - } - - // Custom EmulationDir - if (rpcs3::config.system.emulation_dir_path_enable.value()) - { - std::string dir = rpcs3::config.system.emulation_dir_path.value(); - - if (dir.empty()) - { - rpcs3::config.system.emulation_dir_path = fs::get_executable_dir(); - } - - if (!fs::is_dir(dir)) - { - LOG_ERROR(GENERAL, "Custom EmulationDir: directory '%s' not found", dir); - } - else - { - LOG_NOTICE(GENERAL, "Custom EmulationDir: $(EmulatorDir) bound to '%s'", dir); - } - } - - for(int i=0; i(fmt::format("path[%d]", i), std::string{}); - res[i].device_path = rpcs3::config.vfs.get_entry_value(fmt::format("device_path[%d]", i), std::string{}); - res[i].mount = rpcs3::config.vfs.get_entry_value(fmt::format("mount[%d]", i), std::string{}); - res[i].device = (vfsDeviceType)rpcs3::config.vfs.get_entry_value(fmt::format("device[%d]", i), 0); - } - else - { - rpcs3::config.vfs.set_entry_value(fmt::format("path[%d]", i), res[i].path); - rpcs3::config.vfs.set_entry_value(fmt::format("device_path[%d]", i), res[i].device_path); - rpcs3::config.vfs.set_entry_value(fmt::format("mount[%d]", i), res[i].mount); - rpcs3::config.vfs.set_entry_value(fmt::format("device[%d]", i), (int)res[i].device); - } - } -} diff --git a/rpcs3/Emu/FS/VFS.h b/rpcs3/Emu/FS/VFS.h deleted file mode 100644 index 4418ea33f1..0000000000 --- a/rpcs3/Emu/FS/VFS.h +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once -#include - -class vfsDevice; -struct vfsFileBase; -class vfsDirBase; - -enum vfsDeviceType -{ - vfsDevice_LocalFile, - vfsDevice_HDD, -}; - -static const char* vfsDeviceTypeNames[] = -{ - "Local", - "HDD", -}; - -struct VFSManagerEntry -{ - vfsDeviceType device; - std::string device_path; - std::string path; - std::string mount; - - VFSManagerEntry() - : device(vfsDevice_LocalFile) - , device_path("") - , path("") - , mount("") - { - } - - VFSManagerEntry(const vfsDeviceType& device, const std::string& path, const std::string& mount) - : device(device) - , device_path("") - , path(path) - , mount(mount) - - { - } -}; - -std::vector simplify_path_blocks(const std::string& path); -std::string simplify_path(const std::string& path, bool is_dir, bool is_ps3); - -struct VFS -{ - ~VFS(); - - std::string cwd; - - //TODO: find out where these are supposed to be deleted or just make it shared_ptr - //and also make GetDevice and GetDeviceLocal return shared_ptr then. - // A vfsDevice will be deleted when they're unmounted or the VFS struct is destroyed. - // This will cause problems if other code stores the pointer returned by GetDevice/GetDeviceLocal - // and tries to use it after the device is unmounted. - std::vector m_devices; - - struct links_sorter - { - bool operator()(const std::vector& a, const std::vector& b) const - { - return b.size() < a.size(); - } - }; - - std::map, std::vector, links_sorter> links; - - void Mount(const std::string& ps3_path, const std::string& local_path, vfsDevice* device); - void Link(const std::string& mount_point, const std::string& ps3_path); - void UnMount(const std::string& ps3_path); - void UnMountAll(); - - std::string GetLinked(const std::string& ps3_path) const; - - vfsFileBase* OpenFile(const std::string& ps3_path, u32 mode) const; - vfsDirBase* OpenDir(const std::string& ps3_path) const; - bool CreateDir(const std::string& ps3_path) const; - bool CreatePath(const std::string& ps3_path) const; - bool RemoveFile(const std::string& ps3_path) const; - bool RemoveDir(const std::string& ps3_path) const; - void DeleteAll(const std::string& ps3_path) const; - u64 GetDirSize(const std::string& ps3_path) const; - bool ExistsFile(const std::string& ps3_path) const; - bool ExistsDir(const std::string& ps3_path) const; - bool Exists(const std::string& ps3_path) const; - bool Rename(const std::string& ps3_path_from, const std::string& ps3_path_to) const; - bool CopyFile(const std::string& ps3_path_from, const std::string& ps3_path_to, bool overwrite = true) const; - bool TruncateFile(const std::string& ps3_path, u64 length) const; - - vfsDevice* GetDevice(const std::string& ps3_path, std::string& path) const; - vfsDevice* GetDeviceLocal(const std::string& local_path, std::string& path) const; - - void Init(const std::string& path); - void SaveLoadDevices(std::vector& res, bool is_load); -}; diff --git a/rpcs3/Emu/FS/vfsDevice.cpp b/rpcs3/Emu/FS/vfsDevice.cpp deleted file mode 100644 index 652c6f4f55..0000000000 --- a/rpcs3/Emu/FS/vfsDevice.cpp +++ /dev/null @@ -1,249 +0,0 @@ -#include "stdafx.h" -#include "vfsDevice.h" - -vfsDevice::vfsDevice(const std::string& ps3_path, const std::string& local_path) - : m_ps3_path(ps3_path) - , m_local_path(GetWinPath(local_path)) -{ -} - -std::string vfsDevice::GetLocalPath() const -{ - return m_local_path; -} - -std::string vfsDevice::GetPs3Path() const -{ - return m_ps3_path; -} - -void vfsDevice::SetPath(const std::string& ps3_path, const std::string& local_path) -{ - m_ps3_path = ps3_path; - m_local_path = local_path; -} - -u32 vfsDevice::CmpPs3Path(const std::string& ps3_path) -{ - const u32 lim = (u32)std::min(m_ps3_path.length(), ps3_path.length()); - u32 ret = 0; - - for(u32 i=0; i arr0 = fmt::rSplit(m_local_path, DL); - std::vector arr1 = fmt::rSplit(local_path, DL); - - const u32 lim = (u32)std::min(arr0.size(), arr1.size()); - u32 ret = 0; - - for(u32 i=0; i= 0; --i) - { - if(path[i] == '\\' || path[i] == '/' || i == 0) - { - if(dir++ == end_dir_count) - { - to = i; - break; - } - } - } - - return path.substr(from, to - from); -} - -std::string vfsDevice::GetRoot(const std::string& path) -{ - //return fmt::ToUTF8(wxFileName(fmt::FromUTF8(path), wxPATH_UNIX).GetPath()); - if(path.empty()) return ""; - - u32 first_dir = (u32)path.length() - 1; - - for(int i = (int)path.length() - 1, dir = 0, li = (int)path.length() - 1; i >= 0 && dir < 2; --i) - { - if(path[i] == '\\' || path[i] == '/' || i == 0) - { - switch(dir++) - { - case 0: - first_dir = i; - break; - - case 1: - if(!path.substr(i + 1, li - i).compare("USRDIR")) return path.substr(0, i + 1); - continue; - } - - li = i - 1; - } - } - - return path.substr(0, first_dir + 1); -} - -std::string vfsDevice::GetRootPs3(const std::string& path) -{ - if(path.empty()) return ""; - - static const std::string home = "/dev_hdd0/game/"; - u32 last_dir = 0; - u32 first_dir = (u32)path.length() - 1; - - for(int i = (int)path.length() - 1, dir = 0; i >= 0; --i) - { - if(path[i] == '\\' || path[i] == '/' || i == 0) - { - switch(dir++) - { - case 1: - if(path.substr(i + 1, last_dir - i - 1) == "USRDIR") return ""; - break; - - case 2: - return GetPs3Path(home + path.substr(i + 1, last_dir - i - 1)); - } - - last_dir = i; - } - } - - return GetPs3Path(home + path.substr(0, last_dir - 1)); -} - -std::string vfsDevice::GetWinPath(const std::string& p, bool is_dir) -{ - if(p.empty()) return ""; - - std::string ret; - bool is_ls = false; - - for(u32 i=0; iIsOpened() ? m_stream->GetPath() : path), true, true); - - auto blocks = simplify_path_blocks(GetPath()); - - for (auto dev : Emu.GetVFS().m_devices) - { - auto dev_blocks = simplify_path_blocks(dev->GetPs3Path()); - - if (dev_blocks.size() < (blocks.size() + 1)) - { - continue; - } - - bool is_ok = true; - - for (size_t i = 0; i < blocks.size(); ++i) - { - if (strcmp(dev_blocks[i].c_str(), blocks[i].c_str())) - { - is_ok = false; - break; - } - } - - if (is_ok) - { - info.name = dev_blocks[blocks.size()]; - m_entries.push_back(info); - } - } - - if (m_stream && m_stream->IsOpened()) - { - m_entries.insert(m_entries.begin(), m_stream->GetEntries().begin(), m_stream->GetEntries().end()); - } - - return !m_entries.empty(); -} - -void vfsDir::Close() -{ - m_stream.reset(); -} - -bool vfsDir::IsOpened() const -{ - return !m_entries.empty(); -} diff --git a/rpcs3/Emu/FS/vfsDir.h b/rpcs3/Emu/FS/vfsDir.h deleted file mode 100644 index 61a2004875..0000000000 --- a/rpcs3/Emu/FS/vfsDir.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "vfsDirBase.h" - -class vfsDir : public vfsDirBase -{ -private: - std::shared_ptr m_stream; - -public: - vfsDir(); - vfsDir(const std::string& path); - - virtual bool Open(const std::string& path) override; - virtual bool IsOpened() const override; - virtual void Close() override; - //virtual std::string GetPath() const override; -}; diff --git a/rpcs3/Emu/FS/vfsDirBase.cpp b/rpcs3/Emu/FS/vfsDirBase.cpp deleted file mode 100644 index 8e4cccc327..0000000000 --- a/rpcs3/Emu/FS/vfsDirBase.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "stdafx.h" -#include "vfsDirBase.h" - -vfsDirBase::vfsDirBase(vfsDevice* device) - : m_pos(0) - , m_device(device) -{ -} - -vfsDirBase::~vfsDirBase() -{ -} - -bool vfsDirBase::Open(const std::string& path) -{ - if (IsOpened()) - { - Close(); - } - - m_pos = 0; - m_cwd += '/' + path; - return true; -} - -bool vfsDirBase::IsOpened() const -{ - return !m_cwd.empty(); -} - -const std::vector& vfsDirBase::GetEntries() const -{ - return m_entries; -} - -void vfsDirBase::Close() -{ - m_cwd = ""; - m_entries.clear(); -} - -std::string vfsDirBase::GetPath() const -{ - return m_cwd; -} - -const DirEntryInfo* vfsDirBase::Read() -{ - if (m_pos >= m_entries.size()) - return nullptr; - - return &m_entries[m_pos++]; -} - -const DirEntryInfo* vfsDirBase::First() -{ - m_pos = 0; - return Read(); -} diff --git a/rpcs3/Emu/FS/vfsDirBase.h b/rpcs3/Emu/FS/vfsDirBase.h deleted file mode 100644 index ee43cb602d..0000000000 --- a/rpcs3/Emu/FS/vfsDirBase.h +++ /dev/null @@ -1,106 +0,0 @@ -#pragma once - -class vfsDevice; - -enum DirEntryFlags -{ - DirEntry_TypeDir = 0x1, - DirEntry_TypeFile = 0x2, - DirEntry_TypeMask = 0x3, - DirEntry_PermWritable = 0x20, - DirEntry_PermReadable = 0x40, - DirEntry_PermExecutable = 0x80, -}; - -struct DirEntryInfo -{ - std::string name; - u32 flags; - u64 size; - time_t create_time; - time_t access_time; - time_t modify_time; - - DirEntryInfo() - : flags(0) - , size(0) - , create_time(0) - , access_time(0) - , modify_time(0) - { - } -}; - -class vfsDirBase -{ -protected: - std::string m_cwd; - std::vector m_entries; - uint m_pos; - vfsDevice* m_device; - -public: - vfsDirBase(vfsDevice* device); - virtual ~vfsDirBase(); - - virtual bool Open(const std::string& path); - virtual bool IsOpened() const; - virtual const std::vector& GetEntries() const; - virtual void Close(); - virtual std::string GetPath() const; - - virtual const DirEntryInfo* Read(); - virtual const DirEntryInfo* First(); - - class iterator - { - vfsDirBase *parent; - const DirEntryInfo* data; - - public: - iterator(vfsDirBase* parent) - : parent(parent) - , data(parent->First()) - { - } - - iterator(vfsDirBase* parent, const DirEntryInfo* data) - : parent(parent) - , data(data) - { - } - - iterator& operator++() - { - data = parent->Read(); - return *this; - } - - iterator operator++(int) - { - const DirEntryInfo* olddata = data; - data = parent->Read(); - return iterator(parent, olddata); - } - - const DirEntryInfo* operator *() - { - return data; - } - - bool operator !=(iterator other) const - { - return data != other.data; - } - }; - - iterator begin() - { - return iterator(this); - } - - iterator end() - { - return iterator(this, nullptr); - } -}; diff --git a/rpcs3/Emu/FS/vfsFile.cpp b/rpcs3/Emu/FS/vfsFile.cpp deleted file mode 100644 index cded25282c..0000000000 --- a/rpcs3/Emu/FS/vfsFile.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "stdafx.h" -#include "Emu/System.h" - -#include "VFS.h" -#include "vfsFile.h" - -vfsFile::vfsFile() - : vfsFileBase(nullptr) - , m_stream(nullptr) -{ -} - -vfsFile::vfsFile(const std::string& path, u32 mode) - : vfsFileBase(nullptr) - , m_stream(nullptr) -{ - Open(path, mode); -} - -bool vfsFile::Open(const std::string& path, u32 mode) -{ - Close(); - - m_stream.reset(Emu.GetVFS().OpenFile(path, mode)); - - return m_stream && m_stream->IsOpened(); -} - -void vfsFile::Close() -{ - m_stream.reset(); -} - -u64 vfsFile::GetSize() const -{ - return m_stream->GetSize(); -} - -u64 vfsFile::Write(const void* src, u64 size) -{ - return m_stream->Write(src, size); -} - -u64 vfsFile::Read(void* dst, u64 size) -{ - return m_stream->Read(dst, size); -} - -u64 vfsFile::Seek(s64 offset, fs::seek_mode whence) -{ - return m_stream->Seek(offset, whence); -} - -u64 vfsFile::Tell() const -{ - return m_stream->Tell(); -} - -bool vfsFile::IsOpened() const -{ - return m_stream && m_stream->IsOpened(); -} diff --git a/rpcs3/Emu/FS/vfsFile.h b/rpcs3/Emu/FS/vfsFile.h deleted file mode 100644 index 74f538abc5..0000000000 --- a/rpcs3/Emu/FS/vfsFile.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "vfsFileBase.h" - -class vfsFile : public vfsFileBase -{ -private: - std::shared_ptr m_stream; - -public: - vfsFile(); - vfsFile(const std::string& path, u32 mode = fom::read); - - virtual bool Open(const std::string& path, u32 mode = fom::read) override; - virtual void Close() override; - - virtual u64 GetSize() const override; - - virtual u64 Write(const void* src, u64 size) override; - virtual u64 Read(void* dst, u64 size) override; - - virtual u64 Seek(s64 offset, fs::seek_mode whence = fs::seek_set) override; - virtual u64 Tell() const override; - - virtual bool IsOpened() const override; -}; diff --git a/rpcs3/Emu/FS/vfsFileBase.cpp b/rpcs3/Emu/FS/vfsFileBase.cpp deleted file mode 100644 index b3cc967246..0000000000 --- a/rpcs3/Emu/FS/vfsFileBase.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "stdafx.h" -#include "vfsFileBase.h" - -vfsFileBase::vfsFileBase(vfsDevice* device) - : vfsStream() - , m_device(device) -{ -} - -vfsFileBase::~vfsFileBase() -{ - Close(); -} - -bool vfsFileBase::Open(const std::string& path, u32 mode) -{ - m_path = path; - m_mode = mode; - - return true; -} - -void vfsFileBase::Close() -{ - m_path = ""; - vfsStream::Close(); -} - -std::string vfsFileBase::GetPath() const -{ - return m_path; -} - -u32 vfsFileBase::GetOpenMode() const -{ - return m_mode; -} diff --git a/rpcs3/Emu/FS/vfsFileBase.h b/rpcs3/Emu/FS/vfsFileBase.h deleted file mode 100644 index 0b4f00b4b2..0000000000 --- a/rpcs3/Emu/FS/vfsFileBase.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "vfsStream.h" - -class vfsDevice; - -struct vfsFileBase : public vfsStream -{ -protected: - std::string m_path; - u32 m_mode; - vfsDevice* m_device; - -public: - vfsFileBase(vfsDevice* device); - virtual ~vfsFileBase() override; - - virtual bool Open(const std::string& path, u32 mode); - virtual void Close() override; - virtual bool IsOpened() const override { return !m_path.empty(); } - - std::string GetPath() const; - u32 GetOpenMode() const; -}; diff --git a/rpcs3/Emu/FS/vfsLocalDir.cpp b/rpcs3/Emu/FS/vfsLocalDir.cpp deleted file mode 100644 index 95062193cb..0000000000 --- a/rpcs3/Emu/FS/vfsLocalDir.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "stdafx.h" -#include "vfsDevice.h" -#include "vfsLocalDir.h" - -vfsLocalDir::vfsLocalDir(vfsDevice* device) : vfsDirBase(device) -{ -} - -vfsLocalDir::~vfsLocalDir() -{ -} - -bool vfsLocalDir::Open(const std::string& path) -{ - if (!vfsDirBase::Open(path) || !m_dir.open(path)) - { - return false; - } - - std::string name; - fs::stat_t file_info; - - while (m_dir.read(name, file_info) && name.size()) - { - m_entries.emplace_back(); - - DirEntryInfo& info = m_entries.back(); - - info.name = name; - info.flags |= file_info.is_directory ? DirEntry_TypeDir | DirEntry_PermExecutable : DirEntry_TypeFile; - info.flags |= file_info.is_writable ? DirEntry_PermWritable | DirEntry_PermReadable : DirEntry_PermReadable; - info.size = file_info.size; - info.access_time = file_info.atime; - info.modify_time = file_info.mtime; - info.create_time = file_info.ctime; - } - - return true; -} - -bool vfsLocalDir::IsOpened() const -{ - return m_dir && vfsDirBase::IsOpened(); -} diff --git a/rpcs3/Emu/FS/vfsLocalDir.h b/rpcs3/Emu/FS/vfsLocalDir.h deleted file mode 100644 index f64ae9a768..0000000000 --- a/rpcs3/Emu/FS/vfsLocalDir.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "vfsDirBase.h" - -class vfsLocalDir : public vfsDirBase -{ -private: - u32 m_pos; - fs::dir m_dir; - -public: - vfsLocalDir(vfsDevice* device); - virtual ~vfsLocalDir(); - - virtual bool Open(const std::string& path) override; - virtual bool IsOpened() const override; -}; diff --git a/rpcs3/Emu/FS/vfsLocalFile.cpp b/rpcs3/Emu/FS/vfsLocalFile.cpp deleted file mode 100644 index 573fc9db47..0000000000 --- a/rpcs3/Emu/FS/vfsLocalFile.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "stdafx.h" -#include "vfsLocalFile.h" - -vfsLocalFile::vfsLocalFile(vfsDevice* device) : vfsFileBase(device) -{ -} - -bool vfsLocalFile::Open(const std::string& path, u32 mode) -{ - Close(); - - return m_file.open(path, mode) && vfsFileBase::Open(path, mode); -} - -void vfsLocalFile::Close() -{ - m_file.close(); - vfsFileBase::Close(); -} - -u64 vfsLocalFile::GetSize() const -{ - return m_file.size(); -} - -u64 vfsLocalFile::Write(const void* src, u64 size) -{ - return m_file.write(src, size); -} - -u64 vfsLocalFile::Read(void* dst, u64 size) -{ - return m_file.read(dst, size); -} - -u64 vfsLocalFile::Seek(s64 offset, fs::seek_mode whence) -{ - return m_file.seek(offset, whence); -} - -u64 vfsLocalFile::Tell() const -{ - return m_file.seek(0, fs::seek_cur); -} - -bool vfsLocalFile::IsOpened() const -{ - return m_file && vfsFileBase::IsOpened(); -} diff --git a/rpcs3/Emu/FS/vfsLocalFile.h b/rpcs3/Emu/FS/vfsLocalFile.h deleted file mode 100644 index dc56074b71..0000000000 --- a/rpcs3/Emu/FS/vfsLocalFile.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "vfsFileBase.h" - -class vfsLocalFile : public vfsFileBase -{ -private: - fs::file m_file; - -public: - vfsLocalFile(vfsDevice* device); - - virtual bool Open(const std::string& path, u32 mode = fom::read) override; - virtual void Close() override; - - virtual u64 GetSize() const override; - - virtual u64 Write(const void* src, u64 size) override; - virtual u64 Read(void* dst, u64 size) override; - - virtual u64 Seek(s64 offset, fs::seek_mode whence = fs::seek_set) override; - virtual u64 Tell() const override; - - virtual bool IsOpened() const override; - - virtual const fs::file& GetFile() const { return m_file; } -}; diff --git a/rpcs3/Emu/FS/vfsStream.cpp b/rpcs3/Emu/FS/vfsStream.cpp deleted file mode 100644 index a1fe0ffc0e..0000000000 --- a/rpcs3/Emu/FS/vfsStream.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "stdafx.h" -#include "vfsStream.h" diff --git a/rpcs3/Emu/FS/vfsStream.h b/rpcs3/Emu/FS/vfsStream.h deleted file mode 100644 index 74839c7fab..0000000000 --- a/rpcs3/Emu/FS/vfsStream.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -struct vfsStream -{ - vfsStream() = default; - - virtual ~vfsStream() - { - Close(); - } - - virtual void Close() - { - } - - virtual u64 GetSize() const = 0; - - virtual u64 Write(const void* src, u64 count) = 0; - - template - force_inline bool SWrite(const T& data, u64 count = sizeof(T)) - { - return Write(&data, count) == count; - } - - virtual u64 Read(void* dst, u64 count) = 0; - - template - force_inline bool SRead(T& data, u64 count = sizeof(T)) - { - return Read(&data, count) == count; - } - - template - bool VWrite(const std::vector& vec) - { - return IsOpened() && Write(vec.data(), vec.size() * sizeof(T)) == vec.size() * sizeof(T); - } - - template - std::vector VRead() - { - std::vector result; - if (IsOpened() == false) - { - return result; - } - - result.resize(GetSize() / sizeof(T)); - - if (Seek(0) == -1 || Read(result.data(), result.size() * sizeof(T)) != result.size() * sizeof(T)) - { - result.clear(); - } - - return result; - } - - virtual u64 Seek(s64 offset, fs::seek_mode whence = fs::seek_set) = 0; - - virtual u64 Tell() const = 0; - - virtual bool Eof() const - { - return Tell() >= GetSize(); - } - - virtual bool IsOpened() const = 0; -}; diff --git a/rpcs3/Emu/FS/vfsStreamMemory.cpp b/rpcs3/Emu/FS/vfsStreamMemory.cpp deleted file mode 100644 index 35dd1830af..0000000000 --- a/rpcs3/Emu/FS/vfsStreamMemory.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "vfsStreamMemory.h" - -u64 vfsStreamMemory::Write(const void* src, u64 count) -{ - assert(m_pos < m_size); - if (m_pos + count > m_size) - { - count = m_size - m_pos; - } - - std::memcpy(vm::base(VM_CAST(m_addr + m_pos)), src, count); - m_pos += count; - return count; -} - -u64 vfsStreamMemory::Read(void* dst, u64 count) -{ - assert(m_pos < m_size); - if (m_pos + count > m_size) - { - count = m_size - m_pos; - } - - std::memcpy(dst, vm::base(VM_CAST(m_addr + m_pos)), count); - m_pos += count; - return count; -} diff --git a/rpcs3/Emu/FS/vfsStreamMemory.h b/rpcs3/Emu/FS/vfsStreamMemory.h deleted file mode 100644 index d5dd22c0db..0000000000 --- a/rpcs3/Emu/FS/vfsStreamMemory.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once -#include "vfsStream.h" - -class vfsStreamMemory : public vfsStream -{ - u64 m_pos = 0; - u32 m_addr = 0; - u64 m_size = 0; - -public: - vfsStreamMemory() = default; - - vfsStreamMemory(u32 addr, u32 size = 0) - { - Open(addr, size); - } - - void Open(u32 addr, u32 size = 0) - { - m_pos = 0; - m_addr = addr; - m_size = size ? size : 0x100000000ull - addr; // determine max possible size - } - - virtual u64 GetSize() const override - { - return m_size; - } - - virtual u64 Write(const void* src, u64 count) override; - - virtual u64 Read(void* dst, u64 count) override; - - virtual u64 Seek(s64 offset, fs::seek_mode whence) override - { - switch (whence) - { - case fs::seek_set: return m_pos = offset; - case fs::seek_cur: return m_pos += offset; - case fs::seek_end: return m_pos = m_size + offset; - } - - throw EXCEPTION("Unknown seek_mode (0x%x)", whence); - } - - virtual u64 Tell() const override - { - return m_pos; - } - - virtual bool IsOpened() const override - { - return true; - } -}; From 766f1b2b0110ddbc946df8ec93c77d1e27cc36ee Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 2 Feb 2016 00:51:09 +0300 Subject: [PATCH 11/19] Partial commit: IO --- rpcs3/BasicKeyboardHandler.cpp | 170 +++++++++++++++++ rpcs3/BasicKeyboardHandler.h | 15 ++ rpcs3/BasicMouseHandler.cpp | 57 ++++++ rpcs3/BasicMouseHandler.h | 16 ++ rpcs3/Emu/Io/Keyboard.cpp | 15 -- rpcs3/Emu/Io/Keyboard.h | 20 -- rpcs3/Emu/Io/KeyboardHandler.h | 5 +- rpcs3/Emu/Io/Mouse.cpp | 15 -- rpcs3/Emu/Io/Mouse.h | 19 -- rpcs3/Emu/Io/MouseHandler.h | 5 +- rpcs3/Emu/Io/Null/NullKeyboardHandler.h | 14 +- rpcs3/Emu/Io/Null/NullMouseHandler.h | 14 +- rpcs3/Emu/Io/Null/NullPadHandler.h | 14 +- rpcs3/Emu/Io/Pad.cpp | 15 -- rpcs3/Emu/Io/Pad.h | 18 -- rpcs3/Emu/Io/PadHandler.h | 5 +- rpcs3/Emu/Io/Windows/WindowsKeyboardHandler.h | 171 ------------------ rpcs3/Emu/Io/Windows/WindowsMouseHandler.h | 56 ------ rpcs3/Emu/Io/Windows/WindowsPadHandler.h | 65 ------- rpcs3/KeyboardPadHandler.cpp | 68 +++++++ rpcs3/KeyboardPadHandler.h | 61 +++++++ .../{Emu/Io/XInput => }/XInputPadHandler.cpp | 2 +- rpcs3/{Emu/Io/XInput => }/XInputPadHandler.h | 4 +- 23 files changed, 405 insertions(+), 439 deletions(-) create mode 100644 rpcs3/BasicKeyboardHandler.cpp create mode 100644 rpcs3/BasicKeyboardHandler.h create mode 100644 rpcs3/BasicMouseHandler.cpp create mode 100644 rpcs3/BasicMouseHandler.h delete mode 100644 rpcs3/Emu/Io/Keyboard.cpp delete mode 100644 rpcs3/Emu/Io/Keyboard.h delete mode 100644 rpcs3/Emu/Io/Mouse.cpp delete mode 100644 rpcs3/Emu/Io/Mouse.h delete mode 100644 rpcs3/Emu/Io/Pad.cpp delete mode 100644 rpcs3/Emu/Io/Pad.h delete mode 100644 rpcs3/Emu/Io/Windows/WindowsKeyboardHandler.h delete mode 100644 rpcs3/Emu/Io/Windows/WindowsMouseHandler.h delete mode 100644 rpcs3/Emu/Io/Windows/WindowsPadHandler.h create mode 100644 rpcs3/KeyboardPadHandler.cpp create mode 100644 rpcs3/KeyboardPadHandler.h rename rpcs3/{Emu/Io/XInput => }/XInputPadHandler.cpp (99%) rename rpcs3/{Emu/Io/XInput => }/XInputPadHandler.h (88%) diff --git a/rpcs3/BasicKeyboardHandler.cpp b/rpcs3/BasicKeyboardHandler.cpp new file mode 100644 index 0000000000..b0947155f4 --- /dev/null +++ b/rpcs3/BasicKeyboardHandler.cpp @@ -0,0 +1,170 @@ +#include "stdafx.h" +#include "stdafx_gui.h" +#include "rpcs3.h" +#include "BasicKeyboardHandler.h" + +void BasicKeyboardHandler::Init(const u32 max_connect) +{ + for (u32 i = 0; i(m_keyboards.size(), max_connect); + m_info.info = 0; // Ownership of keyboard data: 0=Application, 1=System + m_info.status[0] = CELL_KB_STATUS_CONNECTED; // (TODO: Support for more keyboards) +} + +BasicKeyboardHandler::BasicKeyboardHandler() +{ + wxGetApp().Bind(wxEVT_KEY_DOWN, &BasicKeyboardHandler::KeyDown, this); + wxGetApp().Bind(wxEVT_KEY_UP, &BasicKeyboardHandler::KeyUp, this); +} + +void BasicKeyboardHandler::KeyDown(wxKeyEvent& event) +{ + Key(event.GetKeyCode(), 1); + event.Skip(); +} + +void BasicKeyboardHandler::KeyUp(wxKeyEvent& event) +{ + Key(event.GetKeyCode(), 0); + event.Skip(); +} + +void BasicKeyboardHandler::LoadSettings() +{ + // Meta Keys + m_keyboards[0].m_buttons.emplace_back(WXK_CONTROL, CELL_KB_MKEY_L_CTRL); + m_keyboards[0].m_buttons.emplace_back(WXK_SHIFT, CELL_KB_MKEY_L_SHIFT); + m_keyboards[0].m_buttons.emplace_back(WXK_ALT, CELL_KB_MKEY_L_ALT); + m_keyboards[0].m_buttons.emplace_back(WXK_WINDOWS_LEFT, CELL_KB_MKEY_L_WIN); + m_keyboards[0].m_buttons.emplace_back(WXK_COMMAND, CELL_KB_MKEY_L_WIN); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KB_MKEY_R_CTRL); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KB_MKEY_R_SHIFT); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KB_MKEY_R_ALT); + m_keyboards[0].m_buttons.emplace_back(WXK_WINDOWS_RIGHT, CELL_KB_MKEY_R_WIN); + + // CELL_KB_RAWDAT + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_NO_EVENT); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_E_ROLLOVER); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_E_POSTFAIL); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_E_UNDEF); + m_keyboards[0].m_buttons.emplace_back(WXK_ESCAPE, CELL_KEYC_ESCAPE); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_106_KANJI); + m_keyboards[0].m_buttons.emplace_back(WXK_CAPITAL, CELL_KEYC_CAPS_LOCK); + m_keyboards[0].m_buttons.emplace_back(WXK_F1, CELL_KEYC_F1); + m_keyboards[0].m_buttons.emplace_back(WXK_F2, CELL_KEYC_F2); + m_keyboards[0].m_buttons.emplace_back(WXK_F3, CELL_KEYC_F3); + m_keyboards[0].m_buttons.emplace_back(WXK_F4, CELL_KEYC_F4); + m_keyboards[0].m_buttons.emplace_back(WXK_F5, CELL_KEYC_F5); + m_keyboards[0].m_buttons.emplace_back(WXK_F6, CELL_KEYC_F6); + m_keyboards[0].m_buttons.emplace_back(WXK_F7, CELL_KEYC_F7); + m_keyboards[0].m_buttons.emplace_back(WXK_F8, CELL_KEYC_F8); + m_keyboards[0].m_buttons.emplace_back(WXK_F9, CELL_KEYC_F9); + m_keyboards[0].m_buttons.emplace_back(WXK_F10, CELL_KEYC_F10); + m_keyboards[0].m_buttons.emplace_back(WXK_F11, CELL_KEYC_F11); + m_keyboards[0].m_buttons.emplace_back(WXK_F12, CELL_KEYC_F12); + m_keyboards[0].m_buttons.emplace_back(WXK_PRINT, CELL_KEYC_PRINTSCREEN); + m_keyboards[0].m_buttons.emplace_back(WXK_SCROLL, CELL_KEYC_SCROLL_LOCK); + m_keyboards[0].m_buttons.emplace_back(WXK_PAUSE, CELL_KEYC_PAUSE); + m_keyboards[0].m_buttons.emplace_back(WXK_INSERT, CELL_KEYC_INSERT); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_HOME); + m_keyboards[0].m_buttons.emplace_back(WXK_PAGEUP, CELL_KEYC_PAGE_UP); + m_keyboards[0].m_buttons.emplace_back(WXK_DELETE, CELL_KEYC_DELETE); + m_keyboards[0].m_buttons.emplace_back(WXK_END, CELL_KEYC_END); + m_keyboards[0].m_buttons.emplace_back(WXK_PAGEDOWN, CELL_KEYC_PAGE_DOWN); + m_keyboards[0].m_buttons.emplace_back(WXK_RIGHT, CELL_KEYC_RIGHT_ARROW); + m_keyboards[0].m_buttons.emplace_back(WXK_LEFT, CELL_KEYC_LEFT_ARROW); + m_keyboards[0].m_buttons.emplace_back(WXK_DOWN, CELL_KEYC_DOWN_ARROW); + m_keyboards[0].m_buttons.emplace_back(WXK_UP, CELL_KEYC_UP_ARROW); + //m_keyboards[0].m_buttons.emplace_back(WXK_NUMLOCK, CELL_KEYC_NUM_LOCK); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_APPLICATION); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_KANA); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_HENKAN); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_MUHENKAN); + + // CELL_KB_KEYPAD + m_keyboards[0].m_buttons.emplace_back(WXK_NUMLOCK, CELL_KEYC_KPAD_NUMLOCK); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD_DIVIDE, CELL_KEYC_KPAD_SLASH); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD_MULTIPLY, CELL_KEYC_KPAD_ASTERISK); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD_SUBTRACT, CELL_KEYC_KPAD_MINUS); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD_ADD, CELL_KEYC_KPAD_PLUS); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD_ENTER, CELL_KEYC_KPAD_ENTER); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD1, CELL_KEYC_KPAD_1); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD2, CELL_KEYC_KPAD_2); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD3, CELL_KEYC_KPAD_3); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD4, CELL_KEYC_KPAD_4); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD5, CELL_KEYC_KPAD_5); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD6, CELL_KEYC_KPAD_6); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD7, CELL_KEYC_KPAD_7); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD8, CELL_KEYC_KPAD_8); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD9, CELL_KEYC_KPAD_9); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD0, CELL_KEYC_KPAD_0); + m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD_DELETE, CELL_KEYC_KPAD_PERIOD); + + // ASCII Printable characters + m_keyboards[0].m_buttons.emplace_back('A', CELL_KEYC_A); + m_keyboards[0].m_buttons.emplace_back('B', CELL_KEYC_B); + m_keyboards[0].m_buttons.emplace_back('C', CELL_KEYC_C); + m_keyboards[0].m_buttons.emplace_back('D', CELL_KEYC_D); + m_keyboards[0].m_buttons.emplace_back('E', CELL_KEYC_E); + m_keyboards[0].m_buttons.emplace_back('F', CELL_KEYC_F); + m_keyboards[0].m_buttons.emplace_back('G', CELL_KEYC_G); + m_keyboards[0].m_buttons.emplace_back('H', CELL_KEYC_H); + m_keyboards[0].m_buttons.emplace_back('I', CELL_KEYC_I); + m_keyboards[0].m_buttons.emplace_back('J', CELL_KEYC_J); + m_keyboards[0].m_buttons.emplace_back('K', CELL_KEYC_K); + m_keyboards[0].m_buttons.emplace_back('L', CELL_KEYC_L); + m_keyboards[0].m_buttons.emplace_back('M', CELL_KEYC_M); + m_keyboards[0].m_buttons.emplace_back('N', CELL_KEYC_N); + m_keyboards[0].m_buttons.emplace_back('O', CELL_KEYC_O); + m_keyboards[0].m_buttons.emplace_back('P', CELL_KEYC_P); + m_keyboards[0].m_buttons.emplace_back('Q', CELL_KEYC_Q); + m_keyboards[0].m_buttons.emplace_back('R', CELL_KEYC_R); + m_keyboards[0].m_buttons.emplace_back('S', CELL_KEYC_S); + m_keyboards[0].m_buttons.emplace_back('T', CELL_KEYC_T); + m_keyboards[0].m_buttons.emplace_back('U', CELL_KEYC_U); + m_keyboards[0].m_buttons.emplace_back('V', CELL_KEYC_V); + m_keyboards[0].m_buttons.emplace_back('W', CELL_KEYC_W); + m_keyboards[0].m_buttons.emplace_back('X', CELL_KEYC_X); + m_keyboards[0].m_buttons.emplace_back('Y', CELL_KEYC_Y); + m_keyboards[0].m_buttons.emplace_back('Z', CELL_KEYC_Z); + + m_keyboards[0].m_buttons.emplace_back('1', CELL_KEYC_1); + m_keyboards[0].m_buttons.emplace_back('2', CELL_KEYC_2); + m_keyboards[0].m_buttons.emplace_back('3', CELL_KEYC_3); + m_keyboards[0].m_buttons.emplace_back('4', CELL_KEYC_4); + m_keyboards[0].m_buttons.emplace_back('5', CELL_KEYC_5); + m_keyboards[0].m_buttons.emplace_back('6', CELL_KEYC_6); + m_keyboards[0].m_buttons.emplace_back('7', CELL_KEYC_7); + m_keyboards[0].m_buttons.emplace_back('8', CELL_KEYC_8); + m_keyboards[0].m_buttons.emplace_back('9', CELL_KEYC_9); + m_keyboards[0].m_buttons.emplace_back('0', CELL_KEYC_0); + + m_keyboards[0].m_buttons.emplace_back(WXK_RETURN, CELL_KEYC_ENTER); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_ESC); + m_keyboards[0].m_buttons.emplace_back(WXK_TAB, CELL_KEYC_TAB); + m_keyboards[0].m_buttons.emplace_back(WXK_SPACE, CELL_KEYC_SPACE); + m_keyboards[0].m_buttons.emplace_back(WXK_SUBTRACT, CELL_KEYC_MINUS); + m_keyboards[0].m_buttons.emplace_back('=', CELL_KEYC_EQUAL_101); + m_keyboards[0].m_buttons.emplace_back('^', CELL_KEYC_ACCENT_CIRCONFLEX_106); + //m_keyboards[0].m_buttons.emplace_back('(', CELL_KEYC_LEFT_BRACKET_101); + m_keyboards[0].m_buttons.emplace_back('@', CELL_KEYC_ATMARK_106); + //m_keyboards[0].m_buttons.emplace_back(')', CELL_KEYC_RIGHT_BRACKET_101); + m_keyboards[0].m_buttons.emplace_back('(', CELL_KEYC_LEFT_BRACKET_106); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_BACKSLASH_101); + m_keyboards[0].m_buttons.emplace_back('(', CELL_KEYC_RIGHT_BRACKET_106); + m_keyboards[0].m_buttons.emplace_back(';', CELL_KEYC_SEMICOLON); + m_keyboards[0].m_buttons.emplace_back('"', CELL_KEYC_QUOTATION_101); + m_keyboards[0].m_buttons.emplace_back(':', CELL_KEYC_COLON_106); + m_keyboards[0].m_buttons.emplace_back(',', CELL_KEYC_COMMA); + m_keyboards[0].m_buttons.emplace_back('.', CELL_KEYC_PERIOD); + m_keyboards[0].m_buttons.emplace_back('/', CELL_KEYC_SLASH); + m_keyboards[0].m_buttons.emplace_back('\\', CELL_KEYC_BACKSLASH_106); + //m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_YEN_106); +} diff --git a/rpcs3/BasicKeyboardHandler.h b/rpcs3/BasicKeyboardHandler.h new file mode 100644 index 0000000000..2c83265d23 --- /dev/null +++ b/rpcs3/BasicKeyboardHandler.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Emu/Io/KeyboardHandler.h" + +class BasicKeyboardHandler final : public KeyboardHandlerBase, public wxWindow +{ +public: + virtual void Init(const u32 max_connect) override; + + BasicKeyboardHandler(); + + void KeyDown(wxKeyEvent& event); + void KeyUp(wxKeyEvent& event); + void LoadSettings(); +}; diff --git a/rpcs3/BasicMouseHandler.cpp b/rpcs3/BasicMouseHandler.cpp new file mode 100644 index 0000000000..3a6b55ca1f --- /dev/null +++ b/rpcs3/BasicMouseHandler.cpp @@ -0,0 +1,57 @@ +#include "stdafx.h" +#include "stdafx_gui.h" +#include "rpcs3.h" +#include "BasicMouseHandler.h" + +void BasicMouseHandler::Init(const u32 max_connect) +{ + m_mice.emplace_back(Mouse()); + memset(&m_info, 0, sizeof(MouseInfo)); + m_info.max_connect = max_connect; + m_info.now_connect = std::min(m_mice.size(), (size_t)max_connect); + m_info.info = 0; // Ownership of mouse data: 0=Application, 1=System + m_info.status[0] = CELL_MOUSE_STATUS_CONNECTED; // (TODO: Support for more mice) + for (u32 i = 1; iInit(max_connect); -} - -void KeyboardManager::Close() -{ - m_keyboard_handler.reset(); -} diff --git a/rpcs3/Emu/Io/Keyboard.h b/rpcs3/Emu/Io/Keyboard.h deleted file mode 100644 index c61916dc3b..0000000000 --- a/rpcs3/Emu/Io/Keyboard.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include "KeyboardHandler.h" - -class KeyboardManager -{ - std::unique_ptr m_keyboard_handler; - -public: - void Init(u32 max_connect); - void Close(); - - std::vector& GetKeyboards() { return m_keyboard_handler->GetKeyboards(); } - KbInfo& GetInfo() { return m_keyboard_handler->GetInfo(); } - std::vector& GetButtons(const u32 keyboard) { return m_keyboard_handler->GetButtons(keyboard); } - KbData& GetData(const u32 keyboard) { return m_keyboard_handler->GetData(keyboard); } - KbConfig& GetConfig(const u32 keyboard) { return m_keyboard_handler->GetConfig(keyboard); } - - bool IsInited() const { return m_keyboard_handler.operator bool(); } -}; diff --git a/rpcs3/Emu/Io/KeyboardHandler.h b/rpcs3/Emu/Io/KeyboardHandler.h index 04d143dd01..06065a5bed 100644 --- a/rpcs3/Emu/Io/KeyboardHandler.h +++ b/rpcs3/Emu/Io/KeyboardHandler.h @@ -1,5 +1,7 @@ #pragma once +// TODO: HLE info (constants, structs, etc.) should not be available here + extern u16 cellKbCnvRawCode(u32 arrange, u32 mkey, u32 led, u16 rawcode); // (TODO: Can it be problematic to place SysCalls in middle of nowhere?) enum KbPortStatus @@ -263,8 +265,7 @@ protected: std::vector m_keyboards; public: - virtual void Init(const u32 max_connect)=0; - virtual void Close()=0; + virtual void Init(const u32 max_connect) = 0; virtual ~KeyboardHandlerBase() = default; void Key(const u32 code, bool pressed) diff --git a/rpcs3/Emu/Io/Mouse.cpp b/rpcs3/Emu/Io/Mouse.cpp deleted file mode 100644 index e07534e3c8..0000000000 --- a/rpcs3/Emu/Io/Mouse.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "stdafx.h" -#include "Emu/System.h" - -#include "Mouse.h" - -void MouseManager::Init(u32 max_connect) -{ - m_mouse_handler = Emu.GetCallbacks().get_mouse_handler(); - m_mouse_handler->Init(max_connect); -} - -void MouseManager::Close() -{ - m_mouse_handler.reset(); -} diff --git a/rpcs3/Emu/Io/Mouse.h b/rpcs3/Emu/Io/Mouse.h deleted file mode 100644 index 98d86185c4..0000000000 --- a/rpcs3/Emu/Io/Mouse.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "MouseHandler.h" - -class MouseManager -{ - std::unique_ptr m_mouse_handler; - -public: - void Init(u32 max_connect); - void Close(); - - std::vector& GetMice() { return m_mouse_handler->GetMice(); } - MouseInfo& GetInfo() { return m_mouse_handler->GetInfo(); } - MouseData& GetData(const u32 mouse) { return m_mouse_handler->GetData(mouse); } - MouseRawData& GetRawData(const u32 mouse) { return m_mouse_handler->GetRawData(mouse); } - - bool IsInited() const { return m_mouse_handler.operator bool(); } -}; diff --git a/rpcs3/Emu/Io/MouseHandler.h b/rpcs3/Emu/Io/MouseHandler.h index 7c472c9d5e..8d82d33aa8 100644 --- a/rpcs3/Emu/Io/MouseHandler.h +++ b/rpcs3/Emu/Io/MouseHandler.h @@ -1,5 +1,7 @@ #pragma once +// TODO: HLE info (constants, structs, etc.) should not be available here + enum MousePortStatus { CELL_MOUSE_STATUS_DISCONNECTED = 0x00000000, @@ -104,8 +106,7 @@ protected: std::vector m_mice; public: - virtual void Init(const u32 max_connect)=0; - virtual void Close()=0; + virtual void Init(const u32 max_connect) = 0; virtual ~MouseHandlerBase() = default; void Button(u8 button, bool pressed) diff --git a/rpcs3/Emu/Io/Null/NullKeyboardHandler.h b/rpcs3/Emu/Io/Null/NullKeyboardHandler.h index 78d25be2b3..e26688e042 100644 --- a/rpcs3/Emu/Io/Null/NullKeyboardHandler.h +++ b/rpcs3/Emu/Io/Null/NullKeyboardHandler.h @@ -5,11 +5,7 @@ class NullKeyboardHandler final : public KeyboardHandlerBase { public: - NullKeyboardHandler() - { - } - - virtual void Init(const u32 max_connect) + void Init(const u32 max_connect) override { memset(&m_info, 0, sizeof(KbInfo)); m_info.max_connect = max_connect; @@ -19,10 +15,4 @@ public: m_keyboards.emplace_back(Keyboard()); } } - - virtual void Close() - { - memset(&m_info, 0, sizeof(KbInfo)); - m_keyboards.clear(); - } -}; \ No newline at end of file +}; diff --git a/rpcs3/Emu/Io/Null/NullMouseHandler.h b/rpcs3/Emu/Io/Null/NullMouseHandler.h index 883bca01ef..4be6fb8445 100644 --- a/rpcs3/Emu/Io/Null/NullMouseHandler.h +++ b/rpcs3/Emu/Io/Null/NullMouseHandler.h @@ -5,20 +5,10 @@ class NullMouseHandler final : public MouseHandlerBase { public: - NullMouseHandler() - { - } - - virtual void Init(const u32 max_connect) + void Init(const u32 max_connect) override { memset(&m_info, 0, sizeof(MouseInfo)); m_info.max_connect = max_connect; m_mice.clear(); } - - virtual void Close() - { - memset(&m_info, 0, sizeof(MouseInfo)); - m_mice.clear(); - } -}; \ No newline at end of file +}; diff --git a/rpcs3/Emu/Io/Null/NullPadHandler.h b/rpcs3/Emu/Io/Null/NullPadHandler.h index d770bf4a00..2f72cf7607 100644 --- a/rpcs3/Emu/Io/Null/NullPadHandler.h +++ b/rpcs3/Emu/Io/Null/NullPadHandler.h @@ -5,20 +5,10 @@ class NullPadHandler final : public PadHandlerBase { public: - NullPadHandler() - { - } - - virtual void Init(const u32 max_connect) + void Init(const u32 max_connect) override { memset(&m_info, 0, sizeof(PadInfo)); m_info.max_connect = max_connect; m_pads.clear(); } - - virtual void Close() - { - memset(&m_info, 0, sizeof(PadInfo)); - m_pads.clear(); - } -}; \ No newline at end of file +}; diff --git a/rpcs3/Emu/Io/Pad.cpp b/rpcs3/Emu/Io/Pad.cpp deleted file mode 100644 index 5c3328337d..0000000000 --- a/rpcs3/Emu/Io/Pad.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "stdafx.h" -#include "Emu/System.h" - -#include "Pad.h" - -void PadManager::Init(u32 max_connect) -{ - m_pad_handler = Emu.GetCallbacks().get_pad_handler(); - m_pad_handler->Init(max_connect); -} - -void PadManager::Close() -{ - m_pad_handler.reset(); -} diff --git a/rpcs3/Emu/Io/Pad.h b/rpcs3/Emu/Io/Pad.h deleted file mode 100644 index 8bbb3a01f3..0000000000 --- a/rpcs3/Emu/Io/Pad.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "PadHandler.h" - -class PadManager -{ - std::unique_ptr m_pad_handler; - -public: - void Init(u32 max_connect); - void Close(); - - std::vector& GetPads() { return m_pad_handler->GetPads(); } - PadInfo& GetInfo() { return m_pad_handler->GetInfo(); } - std::vector