From e9b3f2c3d81b32825221843ef3e7fd5ea096a4ab Mon Sep 17 00:00:00 2001 From: bitsh1ft3r <156549629+bitsh1ft3r@users.noreply.github.com> Date: Mon, 10 Feb 2025 10:01:15 -0600 Subject: [PATCH] [PPU] Implement new instruction decoder. (#35) * Interpreter: Implement experimental code Implement a few instrs, change to full jump-table, skipping decoding. * Fix debug message * [Formatting]: Fix build & formatting errors * [Config]: Fix option var for ODD * [Interpreter] Add mtmsr instruction. --------- Co-authored-by: Vali <78507032+Vali0004@users.noreply.github.com> --- CMakeLists.txt | 2 + Xenon/Base/Assert.cpp | 4 +- Xenon/Base/Assert.h | 1 + Xenon/Base/Config.cpp | 2 +- Xenon/Base/Types.h | 106 +- .../PCIBridge/AUDIOCTRLLR/AudioController.cpp | 37 +- .../HostBridge/PCIBridge/EHCI0/EHCI0.cpp | 37 +- .../HostBridge/PCIBridge/EHCI1/EHCI1.cpp | 37 +- .../PCIBridge/ETHERNET/Ethernet.cpp | 37 +- .../RootBus/HostBridge/PCIBridge/HDD/HDD.cpp | 36 +- .../RootBus/HostBridge/PCIBridge/ODD/ODD.cpp | 36 +- .../HostBridge/PCIBridge/OHCI0/OHCI0.cpp | 37 +- .../HostBridge/PCIBridge/OHCI1/OHCI1.cpp | 37 +- .../HostBridge/PCIBridge/SFCX/SFCX.cpp | 30 +- .../RootBus/HostBridge/PCIBridge/SMC/SMC.cpp | 30 +- .../RootBus/HostBridge/PCIBridge/XMA/XMA.cpp | 36 +- Xenon/Core/XCPU/Bitfield.h | 195 ++ Xenon/Core/XCPU/Interpreter/PPCInternal.h | 11 +- .../Core/XCPU/Interpreter/PPCInterpreter.cpp | 627 ++-- Xenon/Core/XCPU/Interpreter/PPCInterpreter.h | 208 +- Xenon/Core/XCPU/Interpreter/PPCOpcodes.h | 216 ++ Xenon/Core/XCPU/Interpreter/PPC_ALU.cpp | 114 +- Xenon/Core/XCPU/Interpreter/PPC_FPU.cpp | 3 +- .../Core/XCPU/Interpreter/PPC_Instruction.cpp | 2544 +++++++++-------- Xenon/Core/XCPU/Interpreter/PPC_Instruction.h | 321 +-- Xenon/Core/XCPU/Interpreter/PPC_LS.cpp | 21 +- Xenon/Core/XCPU/Interpreter/PPC_System.cpp | 4 +- Xenon/Core/XCPU/PPU/PPU.cpp | 2 +- Xenon/Core/XCPU/PPU/PowerPC.h | 69 +- Xenon/Xe_Main.cpp | 2 +- 30 files changed, 2506 insertions(+), 2336 deletions(-) create mode 100644 Xenon/Core/XCPU/Bitfield.h create mode 100644 Xenon/Core/XCPU/Interpreter/PPCOpcodes.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a0f1e80..ecccf6a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,6 +122,7 @@ set(RootBus ) set(XCPU + Xenon/Core/XCPU/Bitfield.h Xenon/Core/XCPU/Xenon.cpp Xenon/Core/XCPU/Xenon.h Xenon/Core/XCPU/XenonReservations.cpp @@ -141,6 +142,7 @@ set(XCPU Xenon/Core/XCPU/Interpreter/PPCInterpreter.cpp Xenon/Core/XCPU/Interpreter/PPCInterpreter.h Xenon/Core/XCPU/Interpreter/PPCInternal.h + Xenon/Core/XCPU/Interpreter/PPCOpcodes.h Xenon/Core/XCPU/PostBus/PostBus.cpp Xenon/Core/XCPU/PostBus/PostBus.h Xenon/Core/XCPU/PPU/PPU.cpp diff --git a/Xenon/Base/Assert.cpp b/Xenon/Base/Assert.cpp index 1c97631..15cd986 100644 --- a/Xenon/Base/Assert.cpp +++ b/Xenon/Base/Assert.cpp @@ -29,7 +29,7 @@ void assert_fail_impl() { throw std::runtime_error("Unreachable code"); } -void assert_fail_debug_msg(const char* msg) { - LOG_CRITICAL(Debug, "Assertion Failed!\n{}", msg); +void assert_fail_debug_msg(const std::string& msg) { + LOG_CRITICAL(Debug, "Assertion Failed!\n{}", msg.data()); assert_fail_impl(); } diff --git a/Xenon/Base/Assert.h b/Xenon/Base/Assert.h index 9093dc2..242f5e8 100644 --- a/Xenon/Base/Assert.h +++ b/Xenon/Base/Assert.h @@ -10,6 +10,7 @@ void assert_fail_impl(); [[noreturn]] void unreachable_impl(); +void assert_fail_debug_msg(const std::string& msg); #ifdef _MSC_VER #define XENON_NO_INLINE __declspec(noinline) diff --git a/Xenon/Base/Config.cpp b/Xenon/Base/Config.cpp index fd2d897..842d357 100644 --- a/Xenon/Base/Config.cpp +++ b/Xenon/Base/Config.cpp @@ -203,7 +203,7 @@ void saveConfig(const std::filesystem::path &path) { data["Paths"]["Fuses"] = fusesTxtPath; data["Paths"]["OneBL"] = oneBlBinPath; data["Paths"]["Nand"] = nandBinPath; - data["Paths"]["ISO"] = oddDiscImagePath; + data["Paths"]["ODDImage"] = oddDiscImagePath; // HighlyExperimental. data["HighlyExperimental"].comments().push_back("# Do not touch these options unless you know what you're doing!"); diff --git a/Xenon/Base/Types.h b/Xenon/Base/Types.h index 8dceb58..440b16c 100644 --- a/Xenon/Base/Types.h +++ b/Xenon/Base/Types.h @@ -3,29 +3,113 @@ #pragma once #include +#include +#include // Signed -using s8 = std::int8_t; -using s16 = std::int16_t; -using s32 = std::int32_t; -using s64 = std::int64_t; +using s8 = signed char; +using s16 = short; +using s32 = int; +using sl32 = long; +using s64 = long long; // Unsigned -using u8 = std::uint8_t; -using u16 = std::uint16_t; -using u32 = std::uint32_t; -using u64 = std::uint64_t; +using u8 = unsigned char; +using u16 = unsigned short; +using u32 = unsigned int; +using ul32 = unsigned long; +using u64 = unsigned long long; +// Floating point using f32 = float; using f64 = double; // UDLs for memory size values -constexpr u64 operator""_KB(const u64 x) { +[[nodiscard]] inline constexpr u64 operator""_KB(const u64 x) { return 1024ULL * x; } -constexpr u64 operator""_MB(const u64 x) { +[[nodiscard]] inline constexpr u64 operator""_MB(const u64 x) { return 1024_KB * x; } -constexpr u64 operator""_GB(const u64 x) { +[[nodiscard]] inline constexpr u64 operator""_GB(const u64 x) { return 1024_MB * x; } + +// Min/max value of a typetemplate +template +static consteval T min_t() { + if constexpr (std::is_unsigned_v) { + return 0; + } else if constexpr (std::is_same_v) { + return (-0x7FFFFFFFFFFFFFFF - 1); + } else if constexpr (std::is_same_v || std::is_same_v) { + return (-0x7FFFFFFF - 1); + } else if constexpr (std::is_same_v) { + return (-0x7FFF - 1); + } else if constexpr (std::is_same_v) { + return (-0x7F - 1); + } +} +template +class min { +public: + static constexpr T value = min_t(); +}; +template +constexpr T min_v = min::value; +template +static consteval T max_t() { + if constexpr (std::is_same_v) { + return 0xFFFFFFFFFFFFFFFFu; + } else if constexpr (std::is_same_v) { + return 0x7FFFFFFFFFFFFFFF; + } else if constexpr (std::is_same_v || std::is_same_v) { + return 0xFFFFFFFF; + } else if constexpr (std::is_same_v || std::is_same_v) { + return 0x7FFFFFFF; + } else if constexpr (std::is_same_v) { + return 0xFFFF; + } else if constexpr (std::is_same_v) { + return 0x7FFF; + } else if constexpr (std::is_same_v) { + return 0xFF; + } else if constexpr (std::is_same_v) { + return 0x7F; + } +} +template +class max { +public: + static constexpr T value = max_t(); +}; +template +constexpr T max_v = max::value; + +extern void assert_fail_debug_msg(const std::string& msg); + +// Array accessors +template + requires requires (cT&& x) { std::size(x); std::data(x); } || requires (cT && x) { std::size(x); x.front(); } +[[nodiscard]] constexpr auto& c_at(cT&& c, T&& idx) { + // Associative container + size_t cSize = c.size(); + if (cSize <= idx) [[unlikely]] { + assert_fail_debug_msg(std::format("Range check failed! (index: {}{})", idx, cSize != max_v ? std::format(", size: {}", cSize) : "")); + } + auto it = std::begin(std::forward(c)); + std::advance(it, idx); + return *it; +} +template + requires requires(cT&& x, T&& y) { x.count(y); x.find(y); } +[[nodiscard]] static constexpr auto& c_at(cT&& c, T&& idx) { + // Associative container + const auto found = c.find(std::forward(idx)); + size_t cSize = max_v; + if constexpr ((requires() { c.size(); })) + cSize = c.size(); + if (found == c.end()) [[unlikely]] { + assert_fail_debug_msg(std::format("Range check failed! (index: {}{})", idx, cSize != max_v ? std::format(", size: {}", cSize) : "")); + } + return found->second; +} \ No newline at end of file diff --git a/Xenon/Core/RootBus/HostBridge/PCIBridge/AUDIOCTRLLR/AudioController.cpp b/Xenon/Core/RootBus/HostBridge/PCIBridge/AUDIOCTRLLR/AudioController.cpp index 74f6726..23e0fe3 100644 --- a/Xenon/Core/RootBus/HostBridge/PCIBridge/AUDIOCTRLLR/AudioController.cpp +++ b/Xenon/Core/RootBus/HostBridge/PCIBridge/AUDIOCTRLLR/AudioController.cpp @@ -24,25 +24,26 @@ void Xe::PCIDev::AUDIOCTRLR::AUDIOCTRLR::Write(u64 writeAddress, u64 data, void Xe::PCIDev::AUDIOCTRLR::AUDIOCTRLR::ConfigWrite(u64 writeAddress, u64 data, u8 byteCount) { - // Check if we're being scanned. - if (static_cast(writeAddress) >= 0x10 && static_cast(writeAddress) < 0x34) { - const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; - if (pciDevSizes[regOffset] != 0) { - if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. - u32 x = 2; - for (int idx = 2; idx < 31; idx++) { - data &= ~x; - x <<= 1; - if (x >= pciDevSizes[regOffset]) { - break; - } - } - data &= ~0x3; - } - } - if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. - data = 0; // Register not implemented. + // Check if we're being scanned. + if (static_cast(writeAddress) >= 0x10 && static_cast(writeAddress) < 0x34) { + const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; + if (pciDevSizes[regOffset] != 0) { + if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. + u64 x = 2; + for (int idx = 2; idx < 31; idx++) { + data &= ~x; + x <<= 1; + if (x >= pciDevSizes[regOffset]) { + break; + } } + data &= ~0x3; + } + } + if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. + data = 0; // Register not implemented. } + } + memcpy(&pciConfigSpace.data[static_cast(writeAddress)], &data, byteCount); } diff --git a/Xenon/Core/RootBus/HostBridge/PCIBridge/EHCI0/EHCI0.cpp b/Xenon/Core/RootBus/HostBridge/PCIBridge/EHCI0/EHCI0.cpp index d27ed99..32398e1 100644 --- a/Xenon/Core/RootBus/HostBridge/PCIBridge/EHCI0/EHCI0.cpp +++ b/Xenon/Core/RootBus/HostBridge/PCIBridge/EHCI0/EHCI0.cpp @@ -23,25 +23,26 @@ void Xe::PCIDev::EHCI0::EHCI0::Write(u64 writeAddress, u64 data, u8 byteCount) { void Xe::PCIDev::EHCI0::EHCI0::ConfigWrite(u64 writeAddress, u64 data, u8 byteCount) { - // Check if we're being scanned. - if (static_cast(writeAddress) >= 0x10 && static_cast(writeAddress) < 0x34) { - const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; - if (pciDevSizes[regOffset] != 0) { - if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. - u32 x = 2; - for (int idx = 2; idx < 31; idx++) { - data &= ~x; - x <<= 1; - if (x >= pciDevSizes[regOffset]) { - break; - } - } - data &= ~0x3; - } - } - if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. - data = 0; // Register not implemented. + // Check if we're being scanned. + if (static_cast(writeAddress) >= 0x10 && static_cast(writeAddress) < 0x34) { + const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; + if (pciDevSizes[regOffset] != 0) { + if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. + u64 x = 2; + for (int idx = 2; idx < 31; idx++) { + data &= ~x; + x <<= 1; + if (x >= pciDevSizes[regOffset]) { + break; + } } + data &= ~0x3; + } + } + if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. + data = 0; // Register not implemented. } + } + memcpy(&pciConfigSpace.data[static_cast(writeAddress)], &data, byteCount); } diff --git a/Xenon/Core/RootBus/HostBridge/PCIBridge/EHCI1/EHCI1.cpp b/Xenon/Core/RootBus/HostBridge/PCIBridge/EHCI1/EHCI1.cpp index 2f6da84..fbe0314 100644 --- a/Xenon/Core/RootBus/HostBridge/PCIBridge/EHCI1/EHCI1.cpp +++ b/Xenon/Core/RootBus/HostBridge/PCIBridge/EHCI1/EHCI1.cpp @@ -23,25 +23,26 @@ void Xe::PCIDev::EHCI1::EHCI1::Write(u64 writeAddress, u64 data, u8 byteCount) { void Xe::PCIDev::EHCI1::EHCI1::ConfigWrite(u64 writeAddress, u64 data, u8 byteCount) { - // Check if we're being scanned. - if (static_cast(writeAddress) >= 0x10 && static_cast(writeAddress) < 0x34) { - const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; - if (pciDevSizes[regOffset] != 0) { - if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. - u32 x = 2; - for (int idx = 2; idx < 31; idx++) { - data &= ~x; - x <<= 1; - if (x >= pciDevSizes[regOffset]) { - break; - } - } - data &= ~0x3; - } - } - if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. - data = 0; // Register not implemented. + // Check if we're being scanned. + if (static_cast(writeAddress) >= 0x10 && static_cast(writeAddress) < 0x34) { + const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; + if (pciDevSizes[regOffset] != 0) { + if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. + u64 x = 2; + for (int idx = 2; idx < 31; idx++) { + data &= ~x; + x <<= 1; + if (x >= pciDevSizes[regOffset]) { + break; + } } + data &= ~0x3; + } + } + if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. + data = 0; // Register not implemented. } + } + memcpy(&pciConfigSpace.data[static_cast(writeAddress)], &data, byteCount); } diff --git a/Xenon/Core/RootBus/HostBridge/PCIBridge/ETHERNET/Ethernet.cpp b/Xenon/Core/RootBus/HostBridge/PCIBridge/ETHERNET/Ethernet.cpp index 399bd33..878f53b 100644 --- a/Xenon/Core/RootBus/HostBridge/PCIBridge/ETHERNET/Ethernet.cpp +++ b/Xenon/Core/RootBus/HostBridge/PCIBridge/ETHERNET/Ethernet.cpp @@ -154,25 +154,26 @@ void Xe::PCIDev::ETHERNET::ETHERNET::Write(u64 writeAddress, u64 data, void Xe::PCIDev::ETHERNET::ETHERNET::ConfigWrite(u64 writeAddress, u64 data, u8 byteCount) { - // Check if we're being scanned. - if (static_cast(writeAddress) >= 0x10 && static_cast(writeAddress) < 0x34) { - const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; - if (pciDevSizes[regOffset] != 0) { - if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. - u32 x = 2; - for (int idx = 2; idx < 31; idx++) { - data &= ~x; - x <<= 1; - if (x >= pciDevSizes[regOffset]) { - break; - } - } - data &= ~0x3; - } - } - if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. - data = 0; // Register not implemented. + // Check if we're being scanned. + if (static_cast(writeAddress) >= 0x10 && static_cast(writeAddress) < 0x34) { + const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; + if (pciDevSizes[regOffset] != 0) { + if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. + u64 x = 2; + for (int idx = 2; idx < 31; idx++) { + data &= ~x; + x <<= 1; + if (x >= pciDevSizes[regOffset]) { + break; + } } + data &= ~0x3; + } + } + if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. + data = 0; // Register not implemented. } + } + memcpy(&pciConfigSpace.data[static_cast(writeAddress)], &data, byteCount); } diff --git a/Xenon/Core/RootBus/HostBridge/PCIBridge/HDD/HDD.cpp b/Xenon/Core/RootBus/HostBridge/PCIBridge/HDD/HDD.cpp index 14c4765..f3b92f6 100644 --- a/Xenon/Core/RootBus/HostBridge/PCIBridge/HDD/HDD.cpp +++ b/Xenon/Core/RootBus/HostBridge/PCIBridge/HDD/HDD.cpp @@ -136,26 +136,26 @@ void HDD::ConfigRead(u64 readAddress, u64 *data, u8 byteCount) { } void HDD::ConfigWrite(u64 writeAddress, u64 data, u8 byteCount) { - // Check if we're being scanned. - if (static_cast(writeAddress) >= 0x10 && static_cast(writeAddress) < 0x34) { - const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; - if (pciDevSizes[regOffset] != 0) { - if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. - u32 x = 2; - for (int idx = 2; idx < 31; idx++) { - data &= ~x; - x <<= 1; - if (x >= pciDevSizes[regOffset]) { - break; - } - } - data &= ~0x3; - } - } - if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. - data = 0; // Register not implemented. + // Check if we're being scanned. + if (static_cast(writeAddress) >= 0x10 && static_cast(writeAddress) < 0x34) { + const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; + if (pciDevSizes[regOffset] != 0) { + if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. + u64 x = 2; + for (int idx = 2; idx < 31; idx++) { + data &= ~x; + x <<= 1; + if (x >= pciDevSizes[regOffset]) { + break; + } } + data &= ~0x3; + } } + if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. + data = 0; // Register not implemented. + } + } memcpy(&pciConfigSpace.data[static_cast(writeAddress)], &data, byteCount); } diff --git a/Xenon/Core/RootBus/HostBridge/PCIBridge/ODD/ODD.cpp b/Xenon/Core/RootBus/HostBridge/PCIBridge/ODD/ODD.cpp index a4be171..6aed07d 100644 --- a/Xenon/Core/RootBus/HostBridge/PCIBridge/ODD/ODD.cpp +++ b/Xenon/Core/RootBus/HostBridge/PCIBridge/ODD/ODD.cpp @@ -706,25 +706,25 @@ void ODD::ConfigRead(u64 readAddress, u64 *data, u8 byteCount) { } void ODD::ConfigWrite(u64 writeAddress, u64 data, u8 byteCount) { - // Check if we're being scanned. - if (static_cast(writeAddress) >= 0x10 && static_cast(writeAddress) < 0x34) { - const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; - if (pciDevSizes[regOffset] != 0) { - if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. - u32 x = 2; - for (int idx = 2; idx < 31; idx++) { - data &= ~x; - x <<= 1; - if (x >= pciDevSizes[regOffset]) { - break; - } - } - data &= ~0x3; - } - } - if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. - data = 0; // Register not implemented. + // Check if we're being scanned. + if (static_cast(writeAddress) >= 0x10 && static_cast(writeAddress) < 0x34) { + const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; + if (pciDevSizes[regOffset] != 0) { + if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. + u64 x = 2; + for (int idx = 2; idx < 31; idx++) { + data &= ~x; + x <<= 1; + if (x >= pciDevSizes[regOffset]) { + break; + } } + data &= ~0x3; + } } + if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. + data = 0; // Register not implemented. + } + } memcpy(&pciConfigSpace.data[static_cast(writeAddress)], &data, byteCount); } diff --git a/Xenon/Core/RootBus/HostBridge/PCIBridge/OHCI0/OHCI0.cpp b/Xenon/Core/RootBus/HostBridge/PCIBridge/OHCI0/OHCI0.cpp index ac5d9d9..e8abbfa 100644 --- a/Xenon/Core/RootBus/HostBridge/PCIBridge/OHCI0/OHCI0.cpp +++ b/Xenon/Core/RootBus/HostBridge/PCIBridge/OHCI0/OHCI0.cpp @@ -25,25 +25,26 @@ void Xe::PCIDev::OHCI0::OHCI0::Write(u64 writeAddress, u64 data, u8 byteCount) { void Xe::PCIDev::OHCI0::OHCI0::ConfigWrite(u64 writeAddress, u64 data, u8 byteCount) { - // Check if we're being scanned. - if (static_cast(writeAddress) >= 0x10 && static_cast(writeAddress) < 0x34) { - const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; - if (pciDevSizes[regOffset] != 0) { - if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. - u32 x = 2; - for (int idx = 2; idx < 31; idx++) { - data &= ~x; - x <<= 1; - if (x >= pciDevSizes[regOffset]) { - break; - } - } - data &= ~0x3; - } - } - if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. - data = 0; // Register not implemented. + // Check if we're being scanned. + if (static_cast(writeAddress) >= 0x10 && static_cast(writeAddress) < 0x34) { + const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; + if (pciDevSizes[regOffset] != 0) { + if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. + u64 x = 2; + for (int idx = 2; idx < 31; idx++) { + data &= ~x; + x <<= 1; + if (x >= pciDevSizes[regOffset]) { + break; + } } + data &= ~0x3; + } + } + if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. + data = 0; // Register not implemented. } + } + memcpy(&pciConfigSpace.data[static_cast(writeAddress)], &data, byteCount); } diff --git a/Xenon/Core/RootBus/HostBridge/PCIBridge/OHCI1/OHCI1.cpp b/Xenon/Core/RootBus/HostBridge/PCIBridge/OHCI1/OHCI1.cpp index 08b69f1..2fefbe2 100644 --- a/Xenon/Core/RootBus/HostBridge/PCIBridge/OHCI1/OHCI1.cpp +++ b/Xenon/Core/RootBus/HostBridge/PCIBridge/OHCI1/OHCI1.cpp @@ -25,25 +25,26 @@ void Xe::PCIDev::OHCI1::OHCI1::Write(u64 writeAddress, u64 data, u8 byteCount) { void Xe::PCIDev::OHCI1::OHCI1::ConfigWrite(u64 writeAddress, u64 data, u8 byteCount) { - // Check if we're being scanned. - if (static_cast(writeAddress) >= 0x10 && static_cast(writeAddress) < 0x34) { - const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; - if (pciDevSizes[regOffset] != 0) { - if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. - u32 x = 2; - for (int idx = 2; idx < 31; idx++) { - data &= ~x; - x <<= 1; - if (x >= pciDevSizes[regOffset]) { - break; - } - } - data &= ~0x3; - } - } - if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. - data = 0; // Register not implemented. + // Check if we're being scanned. + if (static_cast(writeAddress) >= 0x10 && static_cast(writeAddress) < 0x34) { + const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; + if (pciDevSizes[regOffset] != 0) { + if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. + u64 x = 2; + for (int idx = 2; idx < 31; idx++) { + data &= ~x; + x <<= 1; + if (x >= pciDevSizes[regOffset]) { + break; + } } + data &= ~0x3; + } + } + if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. + data = 0; // Register not implemented. } + } + memcpy(&pciConfigSpace.data[static_cast(writeAddress)], &data, byteCount); } diff --git a/Xenon/Core/RootBus/HostBridge/PCIBridge/SFCX/SFCX.cpp b/Xenon/Core/RootBus/HostBridge/PCIBridge/SFCX/SFCX.cpp index fcbaa37..c97477b 100644 --- a/Xenon/Core/RootBus/HostBridge/PCIBridge/SFCX/SFCX.cpp +++ b/Xenon/Core/RootBus/HostBridge/PCIBridge/SFCX/SFCX.cpp @@ -214,23 +214,23 @@ void SFCX::ConfigWrite(u64 writeAddress, u64 data, u8 byteCount) { // Check if we're being scanned. if (static_cast(writeAddress) >= 0x10 && static_cast(writeAddress) < 0x34) { - u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; - if (pciDevSizes[regOffset] != 0) { - if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. - u32 x = 2; - for (int idx = 2; idx < 31; idx++) { - data &= ~x; - x <<= 1; - if (x >= pciDevSizes[regOffset]) { - break; - } - } - data &= ~0x3; + const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; + if (pciDevSizes[regOffset] != 0) { + if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. + u64 x = 2; + for (int idx = 2; idx < 31; idx++) { + data &= ~x; + x <<= 1; + if (x >= pciDevSizes[regOffset]) { + break; } + } + data &= ~0x3; } - if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. - data = 0; // Register not implemented. - } + } + if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. + data = 0; // Register not implemented. + } } memcpy(&pciConfigSpace.data[offset], &data, byteCount); diff --git a/Xenon/Core/RootBus/HostBridge/PCIBridge/SMC/SMC.cpp b/Xenon/Core/RootBus/HostBridge/PCIBridge/SMC/SMC.cpp index 953038c..73e366f 100644 --- a/Xenon/Core/RootBus/HostBridge/PCIBridge/SMC/SMC.cpp +++ b/Xenon/Core/RootBus/HostBridge/PCIBridge/SMC/SMC.cpp @@ -243,23 +243,23 @@ void Xe::PCIDev::SMC::SMCCore::ConfigWrite(u64 writeAddress, u64 data, // Check if we're being scanned. if (static_cast(writeAddress) >= 0x10 && static_cast(writeAddress) < 0x34) { - const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; - if (pciDevSizes[regOffset] != 0) { - if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. - u32 x = 2; - for (int idx = 2; idx < 31; idx++) { - data &= ~x; - x <<= 1; - if (x >= pciDevSizes[regOffset]) { - break; - } - } - data &= ~0x3; + const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; + if (pciDevSizes[regOffset] != 0) { + if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. + u64 x = 2; + for (int idx = 2; idx < 31; idx++) { + data &= ~x; + x <<= 1; + if (x >= pciDevSizes[regOffset]) { + break; } + } + data &= ~0x3; } - if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. - data = 0; // Register not implemented. - } + } + if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. + data = 0; // Register not implemented. + } } memcpy(&pciConfigSpace.data[static_cast(writeAddress)], &data, byteCount); diff --git a/Xenon/Core/RootBus/HostBridge/PCIBridge/XMA/XMA.cpp b/Xenon/Core/RootBus/HostBridge/PCIBridge/XMA/XMA.cpp index e634b5f..7227291 100644 --- a/Xenon/Core/RootBus/HostBridge/PCIBridge/XMA/XMA.cpp +++ b/Xenon/Core/RootBus/HostBridge/PCIBridge/XMA/XMA.cpp @@ -20,26 +20,26 @@ void XMA::ConfigRead(u64 readAddress, u64 *data, u8 byteCount) { } void XMA::ConfigWrite(u64 writeAddress, u64 data, u8 byteCount) { - // Check if we're being scanned. - if (static_cast(writeAddress) >= 0x10 && static_cast(writeAddress) < 0x34) { - const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; - if (pciDevSizes[regOffset] != 0) { - if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. - u32 x = 2; - for (int idx = 2; idx < 31; idx++) { - data &= ~x; - x <<= 1; - if (x >= pciDevSizes[regOffset]) { - break; - } - } - data &= ~0x3; - } - } - if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. - data = 0; // Register not implemented. + // Check if we're being scanned. + if (static_cast(writeAddress) >= 0x10 && static_cast(writeAddress) < 0x34) { + const u32 regOffset = (static_cast(writeAddress) - 0x10) >> 2; + if (pciDevSizes[regOffset] != 0) { + if (data == 0xFFFFFFFF) { // PCI BAR Size discovery. + u64 x = 2; + for (int idx = 2; idx < 31; idx++) { + data &= ~x; + x <<= 1; + if (x >= pciDevSizes[regOffset]) { + break; + } } + data &= ~0x3; + } + } + if (static_cast(writeAddress) == 0x30) { // Expansion ROM Base Address. + data = 0; // Register not implemented. } + } memcpy(&pciConfigSpace.data[static_cast(writeAddress)], &data, byteCount); } diff --git a/Xenon/Core/XCPU/Bitfield.h b/Xenon/Core/XCPU/Bitfield.h new file mode 100644 index 0000000..3e746e7 --- /dev/null +++ b/Xenon/Core/XCPU/Bitfield.h @@ -0,0 +1,195 @@ +#pragma once +/* +* Copyright 2025 Xenon Emulator Project + +* All original authors of the rpcs3 PPU_Decoder and PPU_Opcodes maintain their original copyright. +* Modifed for usage in the Xenon Emulator +* All rights reserved +* License: GPL2 +*/ + +#include + +#include "Base/Types.h" + +template +class _bitfield { +public: + // Types + using bT = T; + using vT = std::common_type_t; + using uT = std::make_unsigned_t; + static constexpr bool canBePacked = N < (sizeof(s64) * 8 + (std::is_unsigned_v ? 1 : 0)) && sizeof(vT) > sizeof(s64); + using cT = std::conditional_t, u64, s64>, vT>; + // Bitsize + static constexpr u64 bitmax = sizeof(T) * 8; + static_assert(N - 1 < bitmax, "_bitfield<> error: N out of bounds"); + // Bitfield size + static constexpr u64 bitsize = N; + // All ones mask + static constexpr uT mask1 = static_cast(~static_cast(0)); + // Value mask + static constexpr uT vmask = mask1 >> (bitmax - bitsize); +protected: + T data; +}; +// Bitfield accessor (N bits from I position, 0 is LSB) +template +class bitfield : public _bitfield { +public: + // Types + using bT = typename bitfield::bT; + using vT = typename bitfield::vT; + using uT = typename bitfield::uT; + using cT = typename bitfield::cT; + // Field offset + static constexpr u64 bitpos = I; + static_assert((bitpos + N) <= bitfield::bitmax, "bitfield<> error: I out of bounds"); + // Get bitmask of size N, at I pos + static constexpr uT data_mask() { + return static_cast(static_cast(bitfield::mask1 >> (bitfield::bitmax - bitfield::bitsize)) << bitpos); + } + // Bitfield extraction + static constexpr cT extract(const T& data) noexcept { + if constexpr (std::is_signed_v) { + // Load signed value (sign-extended) + return static_cast(static_cast(static_cast(data) << (bitfield::bitmax - bitpos - N)) >> (bitfield::bitmax - N)); + } + else { + // Load unsigned value + return static_cast((static_cast(data) >> bitpos) & bitfield::vmask); + } + } + // Bitfield insertion + static constexpr vT insert(cT value) { + return static_cast((value & bitfield::vmask) << bitpos); + } + // Load bitfield value + constexpr operator cT() const noexcept { + return extract(this->data); + } + // Load raw data with mask applied + constexpr T unshifted() const { + return static_cast(this->data & data_mask()); + } + // Optimized bool conversion (must be removed if inappropriate) + explicit constexpr operator bool() const noexcept { + return unshifted() != 0u; + } + // Store bitfield value + bitfield& operator =(cT value) noexcept { + this->data = static_cast((this->data & ~data_mask()) | insert(value)); + return *this; + } + cT operator ++(s32) { + cT result = *this; + *this = static_cast(result + 1u); + return result; + } + bitfield& operator ++() { + return *this = static_cast(*this + 1u); + } + cT operator --(s32) { + cT result = *this; + *this = static_cast(result - 1u); + return result; + } + bitfield& operator --() { + return *this = static_cast(*this - 1u); + } + bitfield& operator +=(cT right) { + return *this = static_cast(*this + right); + } + bitfield& operator -=(cT right) { + return *this = static_cast(*this - right); + } + bitfield& operator *=(cT right) { + return *this = static_cast(*this * right); + } + bitfield& operator &=(cT right) { + this->data &= static_cast(((static_cast(right + 0u) & bitfield::vmask) << bitpos) | ~(bitfield::vmask << bitpos)); + return *this; + } + bitfield& operator |=(cT right) { + this->data |= static_cast((static_cast(right + 0u) & bitfield::vmask) << bitpos); + return *this; + } + bitfield& operator ^=(cT right) { + this->data ^= static_cast((static_cast(right + 0u) & bitfield::vmask) << bitpos); + return *this; + } +}; +template +class std::common_type, bitfield> : public std::common_type +{}; +template +class std::common_type, T2> : public std::common_type> +{}; +template +class std::common_type> : public std::common_type, T2> +{}; + +// Field pack (concatenated from left to right) +template +class ControlField : public _bitfield::bitsize> { +public: + // Types + using bT = typename ControlField::bT; + using vT = typename ControlField::vT; + using uT = typename ControlField::uT; + using cT = typename ControlField::cT; + // Get disjunction of all "data" masks of concatenated values + static constexpr vT data_mask() { + return static_cast(F::data_mask() | ControlField::data_mask()); + } + // Extract all bitfields and concatenate + static constexpr cT extract(const bT& data) { + return static_cast(static_cast(F::extract(data)) << ControlField::bitsize | ControlField::extract(data)); + } + // Split bitfields and insert them + static constexpr vT insert(cT value) { + return static_cast(F::insert(value >> ControlField::bitsize) | ControlField::insert(value)); + } + constexpr operator cT() const noexcept { + return extract(this->data); + } + ControlField& operator =(cT value) noexcept { + this->data = (this->data & ~data_mask()) | insert(value); + return *this; + } +}; + +// Empty field pack (recursion terminator) +template <> +class ControlField { +public: + static constexpr u64 bitsize = 0; + static constexpr u64 data_mask() { + return 0; + } + template + static constexpr auto extract(const T&) -> decltype(+T()) { + return 0; + } + template + static constexpr T insert(T /*value*/) { + return 0; + } +}; + +// Fixed field (provides constant values in field pack) +template +class FixedField : public _bitfield { +public: + using bT = typename FixedField::bT; + using vT = typename FixedField::vT; + // Return constant value + static constexpr vT extract(const T&) { + static_assert((V & FixedField::vmask) == V, "FixedField<> error: V out of bounds"); + return V; + } + // Get value + constexpr operator vT() const noexcept { + return V; + } +}; diff --git a/Xenon/Core/XCPU/Interpreter/PPCInternal.h b/Xenon/Core/XCPU/Interpreter/PPCInternal.h index d4e2a2a..f6f03ae 100644 --- a/Xenon/Core/XCPU/Interpreter/PPCInternal.h +++ b/Xenon/Core/XCPU/Interpreter/PPCInternal.h @@ -5,7 +5,6 @@ #include "Base/Types.h" #define PPC_OPC_RC 1 -#define PPC_OPC_OE (1 << 10) #define PPC_OPC_LK 1 #define PPC_OPC_AA (1 << 1) @@ -123,9 +122,9 @@ static inline u64 ExtractBits64(u32 input, u32 begin, u32 end) { (dw) |= ((dwSet) << (31 - (e))) & DMASK(b, e); #define IFIELD(v, b, e) \ - u32 v = DGET(hCore->ppuThread[hCore->currentThread].CI, b, e); + u32 v = DGET(hCore->ppuThread[hCore->currentThread].CI.opcode, b, e); #define IFIELDQ(v, b, e) \ - u64 v = DGET(hCore->ppuThread[hCore->currentThread].CI, b, e); + u64 v = DGET(hCore->ppuThread[hCore->currentThread].CI.opcode, b, e); #define I_FORM_LI_AA_LK \ IFIELD(LI, 6, 29); \ @@ -307,21 +306,19 @@ static inline u64 ExtractBits64(u32 input, u32 begin, u32 end) { IFIELD(RC, 31, 31); \ u32 sh = (sh_2 << 5) | sh_1; -#define XO_FORM_rD_rA_rB_OE_RC \ +#define XO_FORM_rD_rA_rB_RC \ IFIELD(rD, 6, 10); \ IFIELD(rA, 11, 15); \ IFIELD(rB, 16, 20); \ - IFIELD(OE, 21, 21); \ IFIELD(RC, 31, 31); #define XO_FORM_rD_rA_rB_RC \ IFIELD(rD, 6, 10); \ IFIELD(rA, 11, 15); \ IFIELD(rB, 16, 20); \ IFIELD(RC, 31, 31); -#define XO_FORM_rD_rA_OE_RC \ +#define XO_FORM_rD_rA_RC \ IFIELD(rD, 6, 10); \ IFIELD(rA, 11, 15); \ - IFIELD(OE, 21, 21); \ IFIELD(RC, 31, 31); #define A_FORM_FrD_FrA_FrB_FRC_XO_RC \ diff --git a/Xenon/Core/XCPU/Interpreter/PPCInterpreter.cpp b/Xenon/Core/XCPU/Interpreter/PPCInterpreter.cpp index 7946267..d38e775 100644 --- a/Xenon/Core/XCPU/Interpreter/PPCInterpreter.cpp +++ b/Xenon/Core/XCPU/Interpreter/PPCInterpreter.cpp @@ -11,232 +11,65 @@ using namespace PPCInterpreter; XENON_CONTEXT* PPCInterpreter::intXCPUContext = nullptr; RootBus* PPCInterpreter::sysBus = nullptr; -// Define a type alias for function pointers -using instructionHandler = void(*)(PPU_STATE*); - -// Define a lookup table for instruction handlers. -std::unordered_map instructionHandlers = { - {PPCInstruction::addex, PPCInterpreter_addex}, - {PPCInstruction::addi, PPCInterpreter_addi}, - {PPCInstruction::addic, PPCInterpreter_addic}, - {PPCInstruction::addicx, PPCInterpreter_addic_rc}, - {PPCInstruction::addis, PPCInterpreter_addis}, - {PPCInstruction::addx, PPCInterpreter_addx}, - {PPCInstruction::addzex, PPCInterpreter_addzex}, - {PPCInstruction::andcx, PPCInterpreter_andc}, - {PPCInstruction::andix, PPCInterpreter_andi}, - {PPCInstruction::andisx, PPCInterpreter_andis}, - {PPCInstruction::andx, PPCInterpreter_and}, - {PPCInstruction::bcctrx, PPCInterpreter_bcctr}, - {PPCInstruction::bclrx, PPCInterpreter_bclr}, - {PPCInstruction::bcx, PPCInterpreter_bc}, - {PPCInstruction::bx, PPCInterpreter_b}, - {PPCInstruction::cmp, PPCInterpreter_cmp}, - {PPCInstruction::cmpi, PPCInterpreter_cmpi}, - {PPCInstruction::cmpl, PPCInterpreter_cmpl}, - {PPCInstruction::cmpli, PPCInterpreter_cmpli}, - {PPCInstruction::cntlzdx, PPCInterpreter_cntlzd}, - {PPCInstruction::cntlzwx, PPCInterpreter_cntlzw}, - {PPCInstruction::crand, PPCInterpreter_crand}, - {PPCInstruction::crandc, PPCInterpreter_crandc}, - {PPCInstruction::creqv, PPCInterpreter_creqv}, - {PPCInstruction::crnand, PPCInterpreter_crnand}, - {PPCInstruction::crnor, PPCInterpreter_crnor}, - {PPCInstruction::cror, PPCInterpreter_cror}, - {PPCInstruction::crorc, PPCInterpreter_crorc}, - {PPCInstruction::crxor, PPCInterpreter_crxor}, - {PPCInstruction::dcbf, PPCInterpreter_dcbf}, - {PPCInstruction::dcbi, PPCInterpreter_dcbi}, - {PPCInstruction::dcbst, PPCInterpreter_dcbst}, - {PPCInstruction::dcbt, PPCInterpreter_dcbt}, - {PPCInstruction::dcbtst, PPCInterpreter_dcbtst}, - {PPCInstruction::dcbz, PPCInterpreter_dcbz}, - {PPCInstruction::divdux, PPCInterpreter_divdu}, - {PPCInstruction::divdx, PPCInterpreter_divd}, - {PPCInstruction::divwux, PPCInterpreter_divwux}, - {PPCInstruction::divwx, PPCInterpreter_divwx}, - {PPCInstruction::eieio, PPCInterpreter_eieio}, - {PPCInstruction::extsbx, PPCInterpreter_extsbx}, - {PPCInstruction::extshx, PPCInterpreter_extshx}, - {PPCInstruction::extswx, PPCInterpreter_extswx}, - {PPCInstruction::icbi, PPCInterpreter_icbi}, - {PPCInstruction::isync, PPCInterpreter_isync}, - {PPCInstruction::lbz, PPCInterpreter_lbz}, - {PPCInstruction::lbzu, PPCInterpreter_lbzu}, - {PPCInstruction::lbzux, PPCInterpreter_lbzux}, - {PPCInstruction::lbzx, PPCInterpreter_lbzx}, - {PPCInstruction::ld, PPCInterpreter_ld}, - {PPCInstruction::ldarx, PPCInterpreter_ldarx}, - {PPCInstruction::ldu, PPCInterpreter_ldu}, - {PPCInstruction::ldux, PPCInterpreter_ldux}, - {PPCInstruction::ldx, PPCInterpreter_ldx}, - {PPCInstruction::lfd, PPCInterpreter_lfd}, - {PPCInstruction::lfs, PPCInterpreter_lfs}, - {PPCInstruction::lha, PPCInterpreter_lha}, - {PPCInstruction::lhau, PPCInterpreter_lhau}, - {PPCInstruction::lhax, PPCInterpreter_lhax}, - {PPCInstruction::lhbrx, PPCInterpreter_lhbrx}, - {PPCInstruction::lhz, PPCInterpreter_lhz}, - {PPCInstruction::lhzu, PPCInterpreter_lhzu}, - {PPCInstruction::lhzux, PPCInterpreter_lhzux}, - {PPCInstruction::lhzx, PPCInterpreter_lhzx}, - {PPCInstruction::lmw, PPCInterpreter_lmw}, - {PPCInstruction::lswi, PPCInterpreter_lswi}, - {PPCInstruction::lwa, PPCInterpreter_lwa}, - {PPCInstruction::lwarx, PPCInterpreter_lwarx}, - {PPCInstruction::lwax, PPCInterpreter_lwax}, - {PPCInstruction::lwbrx, PPCInterpreter_lwbrx}, - {PPCInstruction::lwz, PPCInterpreter_lwz}, - {PPCInstruction::lwzu, PPCInterpreter_lwzu}, - {PPCInstruction::lwzux, PPCInterpreter_lwzux}, - {PPCInstruction::lwzx, PPCInterpreter_lwzx}, - {PPCInstruction::mcrf, PPCInterpreter_mcrf}, - {PPCInstruction::mfcr, PPCInterpreter_mfcr}, - {PPCInstruction::mffsx, PPCInterpreter_mffsx}, - {PPCInstruction::mfmsr, PPCInterpreter_mfmsr}, - {PPCInstruction::mfspr, PPCInterpreter_mfspr}, - {PPCInstruction::mftb, PPCInterpreter_mftb}, - {PPCInstruction::mtcrf, PPCInterpreter_mtcrf}, - {PPCInstruction::mtfsfx, PPCInterpreter_mtfsfx}, - {PPCInstruction::mtmsr, PPCInterpreter_mtmsr}, - {PPCInstruction::mtmsrd, PPCInterpreter_mtmsrd}, - {PPCInstruction::mtspr, PPCInterpreter_mtspr}, - {PPCInstruction::mulhdux, PPCInterpreter_mulhdux}, - {PPCInstruction::mulhwux, PPCInterpreter_mulhwux}, - {PPCInstruction::mulldx, PPCInterpreter_mulldx}, - {PPCInstruction::mulli, PPCInterpreter_mulli}, - {PPCInstruction::mullwx, PPCInterpreter_mullw}, - {PPCInstruction::nandx, PPCInterpreter_nandx}, - {PPCInstruction::negx, PPCInterpreter_negx}, - {PPCInstruction::norx, PPCInterpreter_norx}, - {PPCInstruction::orcx, PPCInterpreter_orcx}, - {PPCInstruction::ori, PPCInterpreter_ori}, - {PPCInstruction::oris, PPCInterpreter_oris}, - {PPCInstruction::orx, PPCInterpreter_orx}, - {PPCInstruction::rfid, PPCInterpreter_rfid}, - {PPCInstruction::rldcrx, PPCInterpreter_rldcrx}, - {PPCInstruction::rldiclx, PPCInterpreter_rldiclx}, - {PPCInstruction::rldicrx, PPCInterpreter_rldicrx}, - {PPCInstruction::rldicx, PPCInterpreter_rldicx}, - {PPCInstruction::rldimix, PPCInterpreter_rldimix}, - {PPCInstruction::rlwimix, PPCInterpreter_rlwimix}, - {PPCInstruction::rlwinmx, PPCInterpreter_rlwinmx}, - {PPCInstruction::rlwnmx, PPCInterpreter_rlwnmx}, - {PPCInstruction::sc, PPCInterpreter_sc}, - {PPCInstruction::slbia, PPCInterpreter_slbia}, - {PPCInstruction::slbie, PPCInterpreter_slbie}, - {PPCInstruction::slbmte, PPCInterpreter_slbmte}, - {PPCInstruction::sldx, PPCInterpreter_sldx}, - {PPCInstruction::slwx, PPCInterpreter_slwx}, - {PPCInstruction::sradix, PPCInterpreter_sradix}, - {PPCInstruction::sradx, PPCInterpreter_sradx}, - {PPCInstruction::srawix, PPCInterpreter_srawix}, - {PPCInstruction::srawx, PPCInterpreter_srawx}, - {PPCInstruction::srdx, PPCInterpreter_srdx}, - {PPCInstruction::srwx, PPCInterpreter_srwx}, - {PPCInstruction::stb, PPCInterpreter_stb}, - {PPCInstruction::stbu, PPCInterpreter_stbu}, - {PPCInstruction::stbux, PPCInterpreter_stbux}, - {PPCInstruction::stbx, PPCInterpreter_stbx}, - {PPCInstruction::std, PPCInterpreter_std}, - {PPCInstruction::stdcx, PPCInterpreter_stdcx}, - {PPCInstruction::stdu, PPCInterpreter_stdu}, - {PPCInstruction::stdux, PPCInterpreter_stdux}, - {PPCInstruction::stdx, PPCInterpreter_stdx}, - {PPCInstruction::stfd, PPCInterpreter_stfd}, - {PPCInstruction::sth, PPCInterpreter_sth}, - {PPCInstruction::sthbrx, PPCInterpreter_sthbrx}, - {PPCInstruction::sthu, PPCInterpreter_sthu}, - {PPCInstruction::sthux, PPCInterpreter_sthux}, - {PPCInstruction::sthx, PPCInterpreter_sthx}, - {PPCInstruction::stmw, PPCInterpreter_stmw}, - {PPCInstruction::stswi, PPCInterpreter_stswi}, - {PPCInstruction::stw, PPCInterpreter_stw}, - {PPCInstruction::stwbrx, PPCInterpreter_stwbrx}, - {PPCInstruction::stwcx, PPCInterpreter_stwcx}, - {PPCInstruction::stwu, PPCInterpreter_stwu}, - {PPCInstruction::stwux, PPCInterpreter_stwux}, - {PPCInstruction::stwx, PPCInterpreter_stwx}, - {PPCInstruction::subfcx, PPCInterpreter_subfcx}, - {PPCInstruction::subfex, PPCInterpreter_subfex}, - {PPCInstruction::subfic, PPCInterpreter_subfic}, - {PPCInstruction::subfx, PPCInterpreter_subfx}, - {PPCInstruction::sync, PPCInterpreter_sync}, - {PPCInstruction::tdi, PPCInterpreter_tdi}, - {PPCInstruction::tlbie, PPCInterpreter_tlbie}, - {PPCInstruction::tlbiel, PPCInterpreter_tlbiel}, - {PPCInstruction::tlbsync, PPCInterpreter_tlbsync}, - {PPCInstruction::tw, PPCInterpreter_tw}, - {PPCInstruction::twi, PPCInterpreter_twi}, - {PPCInstruction::xori, PPCInterpreter_xori}, - {PPCInstruction::xoris, PPCInterpreter_xoris}, - {PPCInstruction::xorx, PPCInterpreter_xorx} -}; +PPCInterpreter::PPCDecoder ppcDecoder{}; + // Interpreter Single Instruction Processing. void PPCInterpreter::ppcExecuteSingleInstruction(PPU_STATE* hCore) { + PPU_THREAD_REGISTERS& thread = + hCore->ppuThread[hCore->currentThread]; - PPCInstruction currentInstr = - getOpcode(hCore->ppuThread[hCore->currentThread].CI); + // RGH 2 for CB_A 9188 in a JRunner XDKBuild. + if (thread.CIA == 0x000000000200c870) { + //thread.GPR[0x5] = 0; + } - // RGH 2 for CB_A 9188 in a JRunner XDKBuild. - if (hCore->ppuThread[hCore->currentThread].CIA == 0x000000000200c870) { - //hCore->ppuThread[hCore->currentThread].GPR[0x5] = 0; - } + // RGH 2 for CB_A 9188 in a JRunner Normal Build. + if (thread.CIA == 0x000000000200c820) { + thread.GPR[0x3] = 0; + } - // RGH 2 for CB_A 9188 in a JRunner Normal Build. - if (hCore->ppuThread[hCore->currentThread].CIA == 0x000000000200c820) { - hCore->ppuThread[hCore->currentThread].GPR[0x3] = 0; - } + // RGH 2 17489 in a JRunner Corona XDKBuild. + if (thread.CIA == 0x200c7f0) { + thread.GPR[0x3] = 0; + } - // RGH 2 17489 in a JRunner Corona XDKBuild. - if (hCore->ppuThread[hCore->currentThread].CIA == 0x200c7f0) { - hCore->ppuThread[hCore->currentThread].GPR[0x3] = 0; - } + // 3BL Check Bypass Devkit 2.0.1838.1 + if (thread.CIA == 0x0000000003004994) { + // thread.GPR[0x3] = 1; + } - // 3BL Check Bypass Devkit 2.0.1838.1 - if (hCore->ppuThread[hCore->currentThread].CIA == 0x0000000003004994) { - // hCore->ppuThread[hCore->currentThread].GPR[0x3] = 1; - } + // 4BL Check Bypass Devkit 2.0.1838.1 + if (thread.CIA == 0x0000000003004bf0) { + // thread.GPR[0x3] = 1; + } - // 4BL Check Bypass Devkit 2.0.1838.1 - if (hCore->ppuThread[hCore->currentThread].CIA == 0x0000000003004bf0) { - // hCore->ppuThread[hCore->currentThread].GPR[0x3] = 1; - } + // 3BL Signature Check Bypass Devkit 2.0.2853.0 + if (thread.CIA == 0x0000000003006488) { + // thread.GPR[0x3] = 0; + } - // 3BL Signature Check Bypass Devkit 2.0.2853.0 - if (hCore->ppuThread[hCore->currentThread].CIA == 0x0000000003006488) { - // hCore->ppuThread[hCore->currentThread].GPR[0x3] = 0; - } + // XDK 17.489.0 AudioChipCorder Device Detect bypass. This is not needed for + // older console revisions. + if ((u32)thread.CIA == 0x801AF580) { + return; + } - // XDK 17.489.0 AudioChipCorder Device Detect bypass. This is not needed for - // older console revisions. - if ((u32)hCore->ppuThread[hCore->currentThread].CIA == 0x801AF580) { - return; - } + // This is just to set a PC breakpoint in any PPU/Thread. + if ((u32)thread.CIA == 0x8009ce40) { + u8 a = 0; + } - // This is just to set a PC breakpoint in any PPU/Thread. - if ((u32)hCore->ppuThread[hCore->currentThread].CIA == 0x8009ce40) { - u8 a = 0; - } + // This is to set a PPU0[Thread0] breakpoint. + if (thread.SPR.PIR == 0) { + thread.lastRegValue = + thread.GPR[11]; + } - // This is to set a PPU0[Thread0] breakpoint. - if (hCore->ppuThread[hCore->currentThread].SPR.PIR == 0) { - hCore->ppuThread[hCore->currentThread].lastRegValue = - hCore->ppuThread[hCore->currentThread].GPR[11]; - } + instructionHandler function = + ppcDecoder.decode(thread.CI.opcode); - // Execute the instruction using the lookup table. - auto it = instructionHandlers.find(currentInstr); - if (it != instructionHandlers.end()) { - it->second(hCore); - } - else { - LOG_CRITICAL(Xenon, "PPC Interpreter: Unknown or unimplemented instruction found: data: {:#x}, address: {:#x}, OpCode: {}.", - hCore->ppuThread[hCore->currentThread].CI, - hCore->ppuThread[hCore->currentThread].CIA, - getOpcodeName(hCore->ppuThread[hCore->currentThread].CI)); - } + function(hCore); } // @@ -247,206 +80,236 @@ void PPCInterpreter::ppcExecuteSingleInstruction(PPU_STATE* hCore) { // System reset Exception (0x100) void PPCInterpreter::ppcResetException(PPU_STATE* hCore) { - LOG_INFO(Xenon, "[{}](Thrd{:#d}): Reset exception.", hCore->ppuName, (s8)hCore->currentThread); - hCore->ppuThread[hCore->currentThread].SPR.SRR0 = - hCore->ppuThread[hCore->currentThread].NIA; - hCore->ppuThread[hCore->currentThread].SPR.SRR1 = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex & - (QMASK(0, 32) | QMASK(37, 41) | QMASK(48, 63)); - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex & - ~(QMASK(48, 50) | QMASK(52, 55) | QMASK(58, 59) | QMASK(61, 63)); - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex | - (QMASK(0, 0) | QMASK(3, 3)); - hCore->ppuThread[hCore->currentThread].NIA = hCore->SPR.HRMOR + 0x100; - hCore->ppuThread[hCore->currentThread].SPR.MSR.DR = 0; - hCore->ppuThread[hCore->currentThread].SPR.MSR.IR = 0; + PPU_THREAD_REGISTERS& thread = + hCore->ppuThread[hCore->currentThread]; + + LOG_INFO(Xenon, "[{}](Thrd{:#d}): Reset exception.", hCore->ppuName, (s8)hCore->currentThread); + thread.SPR.SRR0 = + thread.NIA; + thread.SPR.SRR1 = + thread.SPR.MSR.MSR_Hex & + (QMASK(0, 32) | QMASK(37, 41) | QMASK(48, 63)); + thread.SPR.MSR.MSR_Hex = + thread.SPR.MSR.MSR_Hex & + ~(QMASK(48, 50) | QMASK(52, 55) | QMASK(58, 59) | QMASK(61, 63)); + thread.SPR.MSR.MSR_Hex = + thread.SPR.MSR.MSR_Hex | + (QMASK(0, 0) | QMASK(3, 3)); + thread.NIA = hCore->SPR.HRMOR + 0x100; + thread.SPR.MSR.DR = 0; + thread.SPR.MSR.IR = 0; } // Data Storage Exception (0x300) void PPCInterpreter::ppcDataStorageException(PPU_STATE* hCore) { - LOG_TRACE(Xenon, "[{}](Thrd{:#d}): Data Storage exception.", hCore->ppuName, (s8)hCore->currentThread); - hCore->ppuThread[hCore->currentThread].SPR.SRR0 = - hCore->ppuThread[hCore->currentThread].CIA; - hCore->ppuThread[hCore->currentThread].SPR.SRR1 = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex & - (QMASK(0, 32) | QMASK(37, 41) | QMASK(48, 63)); - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex & - ~(QMASK(48, 50) | QMASK(52, 55) | QMASK(58, 59) | QMASK(61, 63)); - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex | - (QMASK(0, 0) | QMASK(3, 3)); - hCore->ppuThread[hCore->currentThread].NIA = hCore->SPR.HRMOR + 0x300; - hCore->ppuThread[hCore->currentThread].SPR.MSR.DR = 0; - hCore->ppuThread[hCore->currentThread].SPR.MSR.IR = 0; + PPU_THREAD_REGISTERS& thread = + hCore->ppuThread[hCore->currentThread]; + + LOG_TRACE(Xenon, "[{}](Thrd{:#d}): Data Storage exception.", hCore->ppuName, (s8)hCore->currentThread); + thread.SPR.SRR0 = + thread.CIA; + thread.SPR.SRR1 = + thread.SPR.MSR.MSR_Hex & + (QMASK(0, 32) | QMASK(37, 41) | QMASK(48, 63)); + thread.SPR.MSR.MSR_Hex = + thread.SPR.MSR.MSR_Hex & + ~(QMASK(48, 50) | QMASK(52, 55) | QMASK(58, 59) | QMASK(61, 63)); + thread.SPR.MSR.MSR_Hex = + thread.SPR.MSR.MSR_Hex | + (QMASK(0, 0) | QMASK(3, 3)); + thread.NIA = hCore->SPR.HRMOR + 0x300; + thread.SPR.MSR.DR = 0; + thread.SPR.MSR.IR = 0; } // Data Segment Exception (0x380) void PPCInterpreter::ppcDataSegmentException(PPU_STATE* hCore) { - LOG_TRACE(Xenon, "[{}](Thrd{:#d}): Data Segment exception.", hCore->ppuName, (s8)hCore->currentThread); - hCore->ppuThread[hCore->currentThread].SPR.SRR0 = - hCore->ppuThread[hCore->currentThread].CIA; - hCore->ppuThread[hCore->currentThread].SPR.SRR1 = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex & - (QMASK(0, 32) | QMASK(37, 41) | QMASK(48, 63)); - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex & - ~(QMASK(48, 50) | QMASK(52, 55) | QMASK(58, 59) | QMASK(61, 63)); - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex | - (QMASK(0, 0) | QMASK(3, 3)); - hCore->ppuThread[hCore->currentThread].NIA = hCore->SPR.HRMOR + 0x380; - hCore->ppuThread[hCore->currentThread].SPR.MSR.DR = 0; - hCore->ppuThread[hCore->currentThread].SPR.MSR.IR = 0; + PPU_THREAD_REGISTERS& thread = + hCore->ppuThread[hCore->currentThread]; + + LOG_TRACE(Xenon, "[{}](Thrd{:#d}): Data Segment exception.", hCore->ppuName, (s8)hCore->currentThread); + thread.SPR.SRR0 = + thread.CIA; + thread.SPR.SRR1 = + thread.SPR.MSR.MSR_Hex & + (QMASK(0, 32) | QMASK(37, 41) | QMASK(48, 63)); + thread.SPR.MSR.MSR_Hex = + thread.SPR.MSR.MSR_Hex & + ~(QMASK(48, 50) | QMASK(52, 55) | QMASK(58, 59) | QMASK(61, 63)); + thread.SPR.MSR.MSR_Hex = + thread.SPR.MSR.MSR_Hex | + (QMASK(0, 0) | QMASK(3, 3)); + thread.NIA = hCore->SPR.HRMOR + 0x380; + thread.SPR.MSR.DR = 0; + thread.SPR.MSR.IR = 0; } // Instruction Storage Exception (0x400) void PPCInterpreter::ppcInstStorageException(PPU_STATE* hCore) { - LOG_TRACE(Xenon, "[{}](Thrd{:#d}): Instruction Storage exception.", hCore->ppuName, (s8)hCore->currentThread); - hCore->ppuThread[hCore->currentThread].SPR.SRR0 = - hCore->ppuThread[hCore->currentThread].CIA; - hCore->ppuThread[hCore->currentThread].SPR.SRR1 = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex & - (QMASK(0, 32) | QMASK(37, 41) | QMASK(48, 63)); - hCore->ppuThread[hCore->currentThread].SPR.SRR1 |= QMASK(33, 33); - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex & - ~(QMASK(48, 50) | QMASK(52, 55) | QMASK(58, 59) | QMASK(61, 63)); - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex | - (QMASK(0, 0) | QMASK(3, 3)); - hCore->ppuThread[hCore->currentThread].NIA = hCore->SPR.HRMOR + 0x400; - hCore->ppuThread[hCore->currentThread].SPR.MSR.DR = 0; - hCore->ppuThread[hCore->currentThread].SPR.MSR.IR = 0; + PPU_THREAD_REGISTERS& thread = + hCore->ppuThread[hCore->currentThread]; + + LOG_TRACE(Xenon, "[{}](Thrd{:#d}): Instruction Storage exception.", hCore->ppuName, (s8)hCore->currentThread); + thread.SPR.SRR0 = + thread.CIA; + thread.SPR.SRR1 = + thread.SPR.MSR.MSR_Hex & + (QMASK(0, 32) | QMASK(37, 41) | QMASK(48, 63)); + thread.SPR.SRR1 |= QMASK(33, 33); + thread.SPR.MSR.MSR_Hex = + thread.SPR.MSR.MSR_Hex & + ~(QMASK(48, 50) | QMASK(52, 55) | QMASK(58, 59) | QMASK(61, 63)); + thread.SPR.MSR.MSR_Hex = + thread.SPR.MSR.MSR_Hex | + (QMASK(0, 0) | QMASK(3, 3)); + thread.NIA = hCore->SPR.HRMOR + 0x400; + thread.SPR.MSR.DR = 0; + thread.SPR.MSR.IR = 0; } // Instruction Segment Exception (0x480) void PPCInterpreter::ppcInstSegmentException(PPU_STATE* hCore) { - LOG_TRACE(Xenon, "[{}](Thrd{:#d}): Instruction Segment exception.", hCore->ppuName, (s8)hCore->currentThread); - hCore->ppuThread[hCore->currentThread].SPR.SRR0 = - hCore->ppuThread[hCore->currentThread].CIA; - hCore->ppuThread[hCore->currentThread].SPR.SRR1 = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex & - (QMASK(0, 32) | QMASK(37, 41) | QMASK(48, 63)); - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex & - ~(QMASK(48, 50) | QMASK(52, 55) | QMASK(58, 59) | QMASK(61, 63)); - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex | - (QMASK(0, 0) | QMASK(3, 3)); - hCore->ppuThread[hCore->currentThread].NIA = hCore->SPR.HRMOR + 0x480; - hCore->ppuThread[hCore->currentThread].SPR.MSR.DR = 0; - hCore->ppuThread[hCore->currentThread].SPR.MSR.IR = 0; + PPU_THREAD_REGISTERS& thread = + hCore->ppuThread[hCore->currentThread]; + + LOG_TRACE(Xenon, "[{}](Thrd{:#d}): Instruction Segment exception.", hCore->ppuName, (s8)hCore->currentThread); + thread.SPR.SRR0 = + thread.CIA; + thread.SPR.SRR1 = + thread.SPR.MSR.MSR_Hex & + (QMASK(0, 32) | QMASK(37, 41) | QMASK(48, 63)); + thread.SPR.MSR.MSR_Hex = + thread.SPR.MSR.MSR_Hex & + ~(QMASK(48, 50) | QMASK(52, 55) | QMASK(58, 59) | QMASK(61, 63)); + thread.SPR.MSR.MSR_Hex = + thread.SPR.MSR.MSR_Hex | + (QMASK(0, 0) | QMASK(3, 3)); + thread.NIA = hCore->SPR.HRMOR + 0x480; + thread.SPR.MSR.DR = 0; + thread.SPR.MSR.IR = 0; } // External Exception (0x500) void PPCInterpreter::ppcExternalException(PPU_STATE* hCore) { - LOG_TRACE(Xenon, "[{}](Thrd{:#d}): External exception.", hCore->ppuName, (s8)hCore->currentThread); - hCore->ppuThread[hCore->currentThread].SPR.SRR0 = - hCore->ppuThread[hCore->currentThread].NIA; - hCore->ppuThread[hCore->currentThread].SPR.SRR1 = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex & - (QMASK(0, 32) | QMASK(37, 41) | QMASK(48, 63)); - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex & - ~(QMASK(48, 50) | QMASK(52, 55) | QMASK(58, 59) | QMASK(61, 63)); - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex | - (QMASK(0, 0) | QMASK(3, 3)); - hCore->ppuThread[hCore->currentThread].NIA = hCore->SPR.HRMOR + 0x500; - hCore->ppuThread[hCore->currentThread].SPR.MSR.DR = 0; - hCore->ppuThread[hCore->currentThread].SPR.MSR.IR = 0; + PPU_THREAD_REGISTERS& thread = + hCore->ppuThread[hCore->currentThread]; + + LOG_TRACE(Xenon, "[{}](Thrd{:#d}): External exception.", hCore->ppuName, (s8)hCore->currentThread); + thread.SPR.SRR0 = + thread.NIA; + thread.SPR.SRR1 = + thread.SPR.MSR.MSR_Hex & + (QMASK(0, 32) | QMASK(37, 41) | QMASK(48, 63)); + thread.SPR.MSR.MSR_Hex = + thread.SPR.MSR.MSR_Hex & + ~(QMASK(48, 50) | QMASK(52, 55) | QMASK(58, 59) | QMASK(61, 63)); + thread.SPR.MSR.MSR_Hex = + thread.SPR.MSR.MSR_Hex | + (QMASK(0, 0) | QMASK(3, 3)); + thread.NIA = hCore->SPR.HRMOR + 0x500; + thread.SPR.MSR.DR = 0; + thread.SPR.MSR.IR = 0; } // Program Exception (0x700) void PPCInterpreter::ppcProgramException(PPU_STATE* hCore) { - LOG_TRACE(Xenon, "[{}](Thrd{:#d}): Program exception.", hCore->ppuName, (s8)hCore->currentThread); - hCore->ppuThread[hCore->currentThread].SPR.SRR0 = - hCore->ppuThread[hCore->currentThread].CIA; - hCore->ppuThread[hCore->currentThread].SPR.SRR1 = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex & - (QMASK(0, 32) | QMASK(37, 41) | QMASK(48, 63)); - BSET(hCore->ppuThread[hCore->currentThread].SPR.SRR1, 64, - hCore->ppuThread[hCore->currentThread].exceptTrapType); - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex & - ~(QMASK(48, 50) | QMASK(52, 55) | QMASK(58, 59) | QMASK(61, 63)); - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex | - (QMASK(0, 0) | QMASK(3, 3)); - hCore->ppuThread[hCore->currentThread].NIA = hCore->SPR.HRMOR + 0x700; - hCore->ppuThread[hCore->currentThread].SPR.MSR.DR = 0; - hCore->ppuThread[hCore->currentThread].SPR.MSR.IR = 0; + PPU_THREAD_REGISTERS& thread = + hCore->ppuThread[hCore->currentThread]; + + LOG_TRACE(Xenon, "[{}](Thrd{:#d}): Program exception.", hCore->ppuName, (s8)hCore->currentThread); + thread.SPR.SRR0 = + thread.CIA; + thread.SPR.SRR1 = + thread.SPR.MSR.MSR_Hex & + (QMASK(0, 32) | QMASK(37, 41) | QMASK(48, 63)); + BSET(thread.SPR.SRR1, 64, + thread.exceptTrapType); + thread.SPR.MSR.MSR_Hex = + thread.SPR.MSR.MSR_Hex & + ~(QMASK(48, 50) | QMASK(52, 55) | QMASK(58, 59) | QMASK(61, 63)); + thread.SPR.MSR.MSR_Hex = + thread.SPR.MSR.MSR_Hex | + (QMASK(0, 0) | QMASK(3, 3)); + thread.NIA = hCore->SPR.HRMOR + 0x700; + thread.SPR.MSR.DR = 0; + thread.SPR.MSR.IR = 0; } void PPCInterpreter::ppcDecrementerException(PPU_STATE* hCore) { - LOG_TRACE(Xenon, "[{}](Thrd{:#d}): Decrementer exception.", hCore->ppuName, (s8)hCore->currentThread); - hCore->ppuThread[hCore->currentThread].SPR.SRR0 = - hCore->ppuThread[hCore->currentThread].NIA; - hCore->ppuThread[hCore->currentThread].SPR.SRR1 = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex & - (QMASK(0, 32) | QMASK(37, 41) | QMASK(48, 63)); - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex & - ~(QMASK(48, 50) | QMASK(52, 55) | QMASK(58, 59) | QMASK(61, 63)); - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex | QMASK(0, 0) | - (QMASK(3, 3)); - hCore->ppuThread[hCore->currentThread].NIA = hCore->SPR.HRMOR + 0x900; - hCore->ppuThread[hCore->currentThread].SPR.MSR.DR = 0; - hCore->ppuThread[hCore->currentThread].SPR.MSR.IR = 0; + PPU_THREAD_REGISTERS& thread = + hCore->ppuThread[hCore->currentThread]; + + LOG_TRACE(Xenon, "[{}](Thrd{:#d}): Decrementer exception.", hCore->ppuName, (s8)hCore->currentThread); + thread.SPR.SRR0 = + thread.NIA; + thread.SPR.SRR1 = + thread.SPR.MSR.MSR_Hex & + (QMASK(0, 32) | QMASK(37, 41) | QMASK(48, 63)); + thread.SPR.MSR.MSR_Hex = + thread.SPR.MSR.MSR_Hex & + ~(QMASK(48, 50) | QMASK(52, 55) | QMASK(58, 59) | QMASK(61, 63)); + thread.SPR.MSR.MSR_Hex = + thread.SPR.MSR.MSR_Hex | QMASK(0, 0) | + (QMASK(3, 3)); + thread.NIA = hCore->SPR.HRMOR + 0x900; + thread.SPR.MSR.DR = 0; + thread.SPR.MSR.IR = 0; } // System Call Exception (0xC00) void PPCInterpreter::ppcSystemCallException(PPU_STATE* hCore) { - LOG_TRACE(Xenon, "[{}](Thrd{:#d}): System Call exception.", hCore->ppuName, (s8)hCore->currentThread); - hCore->ppuThread[hCore->currentThread].SPR.SRR0 = - hCore->ppuThread[hCore->currentThread].NIA; - hCore->ppuThread[hCore->currentThread].SPR.SRR1 = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex & - (QMASK(0, 32) | QMASK(37, 41) | QMASK(48, 63)); - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex & - ~(QMASK(48, 50) | QMASK(52, 55) | QMASK(58, 59) | QMASK(61, 63)); - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex = - hCore->ppuThread[hCore->currentThread].SPR.MSR.MSR_Hex | QMASK(0, 0) | - (hCore->ppuThread[hCore->currentThread].exceptHVSysCall ? 0 - : QMASK(3, 3)); - hCore->ppuThread[hCore->currentThread].NIA = hCore->SPR.HRMOR + 0xc00; - hCore->ppuThread[hCore->currentThread].SPR.MSR.DR = 0; - hCore->ppuThread[hCore->currentThread].SPR.MSR.IR = 0; + PPU_THREAD_REGISTERS& thread = + hCore->ppuThread[hCore->currentThread]; + + LOG_TRACE(Xenon, "[{}](Thrd{:#d}): System Call exception.", hCore->ppuName, (s8)hCore->currentThread); + thread.SPR.SRR0 = + thread.NIA; + thread.SPR.SRR1 = + thread.SPR.MSR.MSR_Hex & + (QMASK(0, 32) | QMASK(37, 41) | QMASK(48, 63)); + thread.SPR.MSR.MSR_Hex = + thread.SPR.MSR.MSR_Hex & + ~(QMASK(48, 50) | QMASK(52, 55) | QMASK(58, 59) | QMASK(61, 63)); + thread.SPR.MSR.MSR_Hex = + thread.SPR.MSR.MSR_Hex | QMASK(0, 0) | + (thread.exceptHVSysCall ? 0 + : QMASK(3, 3)); + thread.NIA = hCore->SPR.HRMOR + 0xc00; + thread.SPR.MSR.DR = 0; + thread.SPR.MSR.IR = 0; } void PPCInterpreter::ppcInterpreterTrap(PPU_STATE* hCore, u32 trapNumber) { - if (trapNumber == - 0x14) // DbgPrint, r3 = PCSTR stringAddress, r4 = int String Size. - { - std::string dbgString; - dbgString.resize(hCore->ppuThread[hCore->currentThread].GPR[0x4]); - size_t strSize = (size_t)hCore->ppuThread[hCore->currentThread].GPR[0x4]; - for (int idx = 0; idx < strSize; idx++) { - dbgString[idx] = MMURead8( - hCore, hCore->ppuThread[hCore->currentThread].GPR[0x3] + idx); - } - LOG_XBOX(DebugPrint, "> {}", dbgString); + PPU_THREAD_REGISTERS& thread = + hCore->ppuThread[hCore->currentThread]; + + if (trapNumber == + 0x14) // DbgPrint, r3 = PCSTR stringAddress, r4 = int String Size. + { + std::string dbgString; + dbgString.resize(thread.GPR[0x4]); + size_t strSize = (size_t)thread.GPR[0x4]; + for (int idx = 0; idx < strSize; idx++) { + dbgString[idx] = MMURead8( + hCore, thread.GPR[0x3] + idx); } + LOG_XBOX(DebugPrint, "> {}", dbgString); + } - if (trapNumber == 0x17) { - // DebugLoadImageSymbols, type signature: - // PUBLIC VOID DebugLoadImageSymbols(IN PSTRING ModuleName == $r3, - // IN PKD_SYMBOLS_INFO Info == $r4) + if (trapNumber == 0x17) { + // DebugLoadImageSymbols, type signature: + // PUBLIC VOID DebugLoadImageSymbols(IN PSTRING ModuleName == $r3, + // IN PKD_SYMBOLS_INFO Info == $r4) - ppcDebugLoadImageSymbols(hCore, - hCore->ppuThread[hCore->currentThread].GPR[0x3], - hCore->ppuThread[hCore->currentThread].GPR[4]); - } - if (trapNumber == 24) { - // DebugUnloadImageSymbols, type signature: - // PUBLIC VOID DebugUnloadImageSymbols(IN PSTRING ModuleName == $r3, - // IN PKD_SYMBOLS_INFO Info == $r4) - - ppcDebugUnloadImageSymbols(hCore, - hCore->ppuThread[hCore->currentThread].GPR[0x3], - hCore->ppuThread[hCore->currentThread].GPR[4]); - } + ppcDebugLoadImageSymbols(hCore, + thread.GPR[0x3], + thread.GPR[4]); + } + if (trapNumber == 24) { + // DebugUnloadImageSymbols, type signature: + // PUBLIC VOID DebugUnloadImageSymbols(IN PSTRING ModuleName == $r3, + // IN PKD_SYMBOLS_INFO Info == $r4) + + ppcDebugUnloadImageSymbols(hCore, + thread.GPR[0x3], + thread.GPR[4]); + } - hCore->ppuThread[hCore->currentThread].exceptReg |= PPU_EX_PROG; - hCore->ppuThread[hCore->currentThread].exceptTrapType = - TRAP_TYPE_SRR1_TRAP_TRAP; + thread.exceptReg |= PPU_EX_PROG; + thread.exceptTrapType = + TRAP_TYPE_SRR1_TRAP_TRAP; } diff --git a/Xenon/Core/XCPU/Interpreter/PPCInterpreter.h b/Xenon/Core/XCPU/Interpreter/PPCInterpreter.h index 4c9719b..fa9d0d8 100644 --- a/Xenon/Core/XCPU/Interpreter/PPCInterpreter.h +++ b/Xenon/Core/XCPU/Interpreter/PPCInterpreter.h @@ -4,6 +4,7 @@ #include "PPCInternal.h" #include "PPC_Instruction.h" +#include "PPCOpcodes.h" #include "Core/RootBus/RootBus.h" #include "Core/XCPU/PPU/PowerPC.h" @@ -102,211 +103,4 @@ void MMUWrite8(PPU_STATE *ppuState, u64 EA, u8 data); void MMUWrite16(PPU_STATE *ppuState, u64 EA, u16 data); void MMUWrite32(PPU_STATE *ppuState, u64 EA, u32 data); void MMUWrite64(PPU_STATE *ppuState, u64 EA, u64 data); - -// -// Instruction definitions, only implemented instructions as of now. -// - -// ALU -void PPCInterpreter_addx(PPU_STATE *hCore); -void PPCInterpreter_addex(PPU_STATE *hCore); -void PPCInterpreter_addi(PPU_STATE *hCore); -void PPCInterpreter_addic(PPU_STATE *hCore); -void PPCInterpreter_addic_rc(PPU_STATE *hCore); -void PPCInterpreter_addis(PPU_STATE *hCore); -void PPCInterpreter_addzex(PPU_STATE *hCore); -void PPCInterpreter_and(PPU_STATE *hCore); -void PPCInterpreter_andc(PPU_STATE *hCore); -void PPCInterpreter_andi(PPU_STATE *hCore); -void PPCInterpreter_andis(PPU_STATE *hCore); -void PPCInterpreter_cmp(PPU_STATE *hCore); -void PPCInterpreter_cmpi(PPU_STATE *hCore); -void PPCInterpreter_cmpl(PPU_STATE *hCore); -void PPCInterpreter_cmpli(PPU_STATE *hCore); -void PPCInterpreter_cntlzd(PPU_STATE *hCore); -void PPCInterpreter_cntlzw(PPU_STATE *hCore); -void PPCInterpreter_crand(PPU_STATE *hCore); -void PPCInterpreter_crandc(PPU_STATE *hCore); -void PPCInterpreter_creqv(PPU_STATE *hCore); -void PPCInterpreter_crnand(PPU_STATE *hCore); -void PPCInterpreter_crnor(PPU_STATE *hCore); -void PPCInterpreter_cror(PPU_STATE *hCore); -void PPCInterpreter_crorc(PPU_STATE *hCore); -void PPCInterpreter_crxor(PPU_STATE *hCore); -void PPCInterpreter_divd(PPU_STATE *hCore); -void PPCInterpreter_divdu(PPU_STATE *hCore); -void PPCInterpreter_divwx(PPU_STATE *hCore); -void PPCInterpreter_divwux(PPU_STATE *hCore); -void PPCInterpreter_isync(PPU_STATE *hCore); -void PPCInterpreter_extsbx(PPU_STATE *hCore); -void PPCInterpreter_extshx(PPU_STATE *hCore); -void PPCInterpreter_extswx(PPU_STATE *hCore); -void PPCInterpreter_mcrf(PPU_STATE *hCore); -void PPCInterpreter_mfcr(PPU_STATE *hCore); -void PPCInterpreter_mftb(PPU_STATE *hCore); -void PPCInterpreter_mtcrf(PPU_STATE *hCore); -void PPCInterpreter_mulli(PPU_STATE *hCore); -void PPCInterpreter_mulldx(PPU_STATE *hCore); -void PPCInterpreter_mullw(PPU_STATE *hCore); -void PPCInterpreter_mulhwux(PPU_STATE *hCore); -void PPCInterpreter_mulhdux(PPU_STATE *hCore); -void PPCInterpreter_nandx(PPU_STATE *hCore); -void PPCInterpreter_negx(PPU_STATE *hCore); -void PPCInterpreter_norx(PPU_STATE *hCore); -void PPCInterpreter_orcx(PPU_STATE *hCore); -void PPCInterpreter_ori(PPU_STATE *hCore); -void PPCInterpreter_oris(PPU_STATE *hCore); -void PPCInterpreter_orx(PPU_STATE *hCore); -void PPCInterpreter_rldicx(PPU_STATE *hCore); -void PPCInterpreter_rldcrx(PPU_STATE *hCore); -void PPCInterpreter_rldiclx(PPU_STATE *hCore); -void PPCInterpreter_rldicrx(PPU_STATE *hCore); -void PPCInterpreter_rldimix(PPU_STATE *hCore); -void PPCInterpreter_rlwimix(PPU_STATE *hCore); -void PPCInterpreter_rlwnmx(PPU_STATE *hCore); -void PPCInterpreter_rlwinmx(PPU_STATE *hCore); -void PPCInterpreter_sldx(PPU_STATE *hCore); -void PPCInterpreter_slwx(PPU_STATE *hCore); -void PPCInterpreter_sradx(PPU_STATE *hCore); -void PPCInterpreter_sradix(PPU_STATE *hCore); -void PPCInterpreter_srawx(PPU_STATE *hCore); -void PPCInterpreter_srawix(PPU_STATE *hCore); -void PPCInterpreter_srdx(PPU_STATE *hCore); -void PPCInterpreter_srwx(PPU_STATE *hCore); -void PPCInterpreter_subfcx(PPU_STATE *hCore); -void PPCInterpreter_subfx(PPU_STATE *hCore); -void PPCInterpreter_subfex(PPU_STATE *hCore); -void PPCInterpreter_subfic(PPU_STATE *hCore); -void PPCInterpreter_xori(PPU_STATE *hCore); -void PPCInterpreter_xoris(PPU_STATE *hCore); -void PPCInterpreter_xorx(PPU_STATE *hCore); - -// Program control -void PPCInterpreter_b(PPU_STATE *hCore); -void PPCInterpreter_bc(PPU_STATE *hCore); -void PPCInterpreter_bcctr(PPU_STATE *hCore); -void PPCInterpreter_bclr(PPU_STATE *hCore); - -// System instructions -void PPCInterpreter_eieio(PPU_STATE *hCore); -void PPCInterpreter_sc(PPU_STATE *hCore); -void PPCInterpreter_slbia(PPU_STATE *hCore); -void PPCInterpreter_slbie(PPU_STATE *hCore); -void PPCInterpreter_slbmte(PPU_STATE *hCore); -void PPCInterpreter_rfid(PPU_STATE *hCore); -void PPCInterpreter_tw(PPU_STATE *hCore); -void PPCInterpreter_twi(PPU_STATE *hCore); -void PPCInterpreter_tdi(PPU_STATE *hCore); -void PPCInterpreter_tlbie(PPU_STATE *hCore); -void PPCInterpreter_tlbiel(PPU_STATE *hCore); -void PPCInterpreter_tlbsync(PPU_STATE *hCore); -void PPCInterpreter_mfspr(PPU_STATE *hCore); -void PPCInterpreter_mtspr(PPU_STATE *hCore); -void PPCInterpreter_mfmsr(PPU_STATE *hCore); -void PPCInterpreter_mtmsr(PPU_STATE *hCore); -void PPCInterpreter_mtmsrd(PPU_STATE *hCore); -void PPCInterpreter_sync(PPU_STATE *hCore); - -// Cache Management -void PPCInterpreter_dcbf(PPU_STATE *hCore); -void PPCInterpreter_dcbi(PPU_STATE* hCore); -void PPCInterpreter_dcbt(PPU_STATE* hCore); -void PPCInterpreter_dcbtst(PPU_STATE* hCore); -void PPCInterpreter_dcbst(PPU_STATE *hCore); -void PPCInterpreter_dcbz(PPU_STATE *hCore); -void PPCInterpreter_icbi(PPU_STATE *hCore); - -// -// FPU -// -void PPCInterpreter_mffsx(PPU_STATE* hCore); -void PPCInterpreter_mtfsfx(PPU_STATE* hCore); - -// -// Load/Store -// - -// Store Byte -void PPCInterpreter_stb(PPU_STATE *hCore); -void PPCInterpreter_stbu(PPU_STATE *hCore); -void PPCInterpreter_stbux(PPU_STATE *hCore); -void PPCInterpreter_stbx(PPU_STATE *hCore); - -// Store Halfword -void PPCInterpreter_sth(PPU_STATE *hCore); -void PPCInterpreter_sthbrx(PPU_STATE *hCore); -void PPCInterpreter_sthu(PPU_STATE *hCore); -void PPCInterpreter_sthux(PPU_STATE *hCore); -void PPCInterpreter_sthx(PPU_STATE *hCore); - -// Store String Word -void PPCInterpreter_stswi(PPU_STATE *hCore); - -// Store Multiple Word -void PPCInterpreter_stmw(PPU_STATE* hCore); - -// Store Word -void PPCInterpreter_stw(PPU_STATE *hCore); -void PPCInterpreter_stwbrx(PPU_STATE *hCore); -void PPCInterpreter_stwcx(PPU_STATE *hCore); -void PPCInterpreter_stwu(PPU_STATE *hCore); -void PPCInterpreter_stwux(PPU_STATE *hCore); -void PPCInterpreter_stwx(PPU_STATE *hCore); - -// Store Doubleword -void PPCInterpreter_std(PPU_STATE *hCore); -void PPCInterpreter_stdcx(PPU_STATE *hCore); -void PPCInterpreter_stdu(PPU_STATE *hCore); -void PPCInterpreter_stdux(PPU_STATE *hCore); -void PPCInterpreter_stdx(PPU_STATE *hCore); - -// Store Floating -void PPCInterpreter_stfd(PPU_STATE *hCore); - -// Load Byte -void PPCInterpreter_lbz(PPU_STATE *hCore); -void PPCInterpreter_lbzu(PPU_STATE *hCore); -void PPCInterpreter_lbzux(PPU_STATE *hCore); -void PPCInterpreter_lbzx(PPU_STATE *hCore); - -// Load Halfword -void PPCInterpreter_lha(PPU_STATE *hCore); -void PPCInterpreter_lhau(PPU_STATE *hCore); -void PPCInterpreter_lhax(PPU_STATE *hCore); -void PPCInterpreter_lhbrx(PPU_STATE *hCore); -void PPCInterpreter_lhz(PPU_STATE *hCore); -void PPCInterpreter_lhzu(PPU_STATE *hCore); -void PPCInterpreter_lhzux(PPU_STATE *hCore); -void PPCInterpreter_lhzx(PPU_STATE *hCore); - -// Load String Word -void PPCInterpreter_lswi(PPU_STATE *hCore); - -// Load Multiple Word -void PPCInterpreter_lmw(PPU_STATE* hCore); - -// Load Word -void PPCInterpreter_lwa(PPU_STATE *hCore); -void PPCInterpreter_lwax(PPU_STATE *hCore); -void PPCInterpreter_lwarx(PPU_STATE *hCore); -void PPCInterpreter_lwbrx(PPU_STATE *hCore); -void PPCInterpreter_lwz(PPU_STATE *hCore); -void PPCInterpreter_lwzu(PPU_STATE *hCore); -void PPCInterpreter_lwzux(PPU_STATE *hCore); -void PPCInterpreter_lwzx(PPU_STATE *hCore); - -// Load Doubleword -void PPCInterpreter_ld(PPU_STATE *hCore); -void PPCInterpreter_ldarx(PPU_STATE *hCore); -void PPCInterpreter_ldbrx(PPU_STATE *hCore); -void PPCInterpreter_ldu(PPU_STATE *hCore); -void PPCInterpreter_ldux(PPU_STATE *hCore); -void PPCInterpreter_ldx(PPU_STATE *hCore); - -// -// Load Floating -// - -void PPCInterpreter_lfd(PPU_STATE *hCore); -void PPCInterpreter_lfs(PPU_STATE *hCore); } // namespace PPCInterpreter diff --git a/Xenon/Core/XCPU/Interpreter/PPCOpcodes.h b/Xenon/Core/XCPU/Interpreter/PPCOpcodes.h new file mode 100644 index 0000000..9004b84 --- /dev/null +++ b/Xenon/Core/XCPU/Interpreter/PPCOpcodes.h @@ -0,0 +1,216 @@ +#pragma once +#include "PPCInternal.h" +#include "Core/XCPU/PPU/PowerPC.h" + +namespace PPCInterpreter { +// +// Instruction definitions +// + +// Stubs +extern void PPCInterpreter_invalid(PPU_STATE* hCore); +extern void PPCInterpreter_known_unimplemented(const char* name, PPU_STATE* hCore); + +// ALU +extern void PPCInterpreter_addx(PPU_STATE *hCore); +extern void PPCInterpreter_addex(PPU_STATE *hCore); +extern void PPCInterpreter_addi(PPU_STATE *hCore); +extern void PPCInterpreter_addic(PPU_STATE *hCore); +extern void PPCInterpreter_addis(PPU_STATE *hCore); +extern void PPCInterpreter_addzex(PPU_STATE *hCore); +extern void PPCInterpreter_andx(PPU_STATE *hCore); +extern void PPCInterpreter_andcx(PPU_STATE *hCore); +extern void PPCInterpreter_andi(PPU_STATE *hCore); +extern void PPCInterpreter_andis(PPU_STATE* hCore); +extern void PPCInterpreter_cmp(PPU_STATE *hCore); +extern void PPCInterpreter_cmpi(PPU_STATE *hCore); +extern void PPCInterpreter_cmpl(PPU_STATE *hCore); +extern void PPCInterpreter_cmpli(PPU_STATE *hCore); +extern void PPCInterpreter_cntlzdx(PPU_STATE *hCore); +extern void PPCInterpreter_cntlzwx(PPU_STATE *hCore); +extern void PPCInterpreter_crand(PPU_STATE *hCore); +extern void PPCInterpreter_crandc(PPU_STATE *hCore); +extern void PPCInterpreter_creqv(PPU_STATE *hCore); +extern void PPCInterpreter_crnand(PPU_STATE *hCore); +extern void PPCInterpreter_crnor(PPU_STATE *hCore); +extern void PPCInterpreter_cror(PPU_STATE *hCore); +extern void PPCInterpreter_crorc(PPU_STATE *hCore); +extern void PPCInterpreter_crxor(PPU_STATE *hCore); +extern void PPCInterpreter_divdx(PPU_STATE *hCore); +extern void PPCInterpreter_divdux(PPU_STATE *hCore); +extern void PPCInterpreter_divwx(PPU_STATE *hCore); +extern void PPCInterpreter_divwux(PPU_STATE *hCore); +extern void PPCInterpreter_isync(PPU_STATE *hCore); +extern void PPCInterpreter_extsbx(PPU_STATE *hCore); +extern void PPCInterpreter_extshx(PPU_STATE *hCore); +extern void PPCInterpreter_extswx(PPU_STATE *hCore); +extern void PPCInterpreter_mcrf(PPU_STATE *hCore); +extern void PPCInterpreter_mfocrf(PPU_STATE *hCore); +extern void PPCInterpreter_mftb(PPU_STATE *hCore); +extern void PPCInterpreter_mtocrf(PPU_STATE *hCore); +extern void PPCInterpreter_mulli(PPU_STATE *hCore); +extern void PPCInterpreter_mulldx(PPU_STATE *hCore); +extern void PPCInterpreter_mullwx(PPU_STATE *hCore); +extern void PPCInterpreter_mulhwux(PPU_STATE *hCore); +extern void PPCInterpreter_mulhdux(PPU_STATE *hCore); +extern void PPCInterpreter_nandx(PPU_STATE *hCore); +extern void PPCInterpreter_negx(PPU_STATE *hCore); +extern void PPCInterpreter_norx(PPU_STATE *hCore); +extern void PPCInterpreter_orcx(PPU_STATE *hCore); +extern void PPCInterpreter_ori(PPU_STATE *hCore); +extern void PPCInterpreter_oris(PPU_STATE *hCore); +extern void PPCInterpreter_orx(PPU_STATE *hCore); +extern void PPCInterpreter_rldicx(PPU_STATE *hCore); +extern void PPCInterpreter_rldcrx(PPU_STATE *hCore); +extern void PPCInterpreter_rldiclx(PPU_STATE *hCore); +extern void PPCInterpreter_rldicrx(PPU_STATE *hCore); +extern void PPCInterpreter_rldimix(PPU_STATE *hCore); +extern void PPCInterpreter_rlwimix(PPU_STATE *hCore); +extern void PPCInterpreter_rlwnmx(PPU_STATE *hCore); +extern void PPCInterpreter_rlwinmx(PPU_STATE *hCore); +extern void PPCInterpreter_sldx(PPU_STATE *hCore); +extern void PPCInterpreter_slwx(PPU_STATE *hCore); +extern void PPCInterpreter_sradx(PPU_STATE *hCore); +extern void PPCInterpreter_sradix(PPU_STATE *hCore); +extern void PPCInterpreter_srawx(PPU_STATE *hCore); +extern void PPCInterpreter_srawix(PPU_STATE *hCore); +extern void PPCInterpreter_srdx(PPU_STATE *hCore); +extern void PPCInterpreter_srwx(PPU_STATE *hCore); +extern void PPCInterpreter_subfcx(PPU_STATE *hCore); +extern void PPCInterpreter_subfx(PPU_STATE *hCore); +extern void PPCInterpreter_subfex(PPU_STATE *hCore); +extern void PPCInterpreter_subfic(PPU_STATE *hCore); +extern void PPCInterpreter_xori(PPU_STATE *hCore); +extern void PPCInterpreter_xoris(PPU_STATE *hCore); +extern void PPCInterpreter_xorx(PPU_STATE *hCore); + +// Program control +extern void PPCInterpreter_b(PPU_STATE *hCore); +extern void PPCInterpreter_bc(PPU_STATE *hCore); +extern void PPCInterpreter_bcctr(PPU_STATE *hCore); +extern void PPCInterpreter_bclr(PPU_STATE *hCore); + +// System instructions +extern void PPCInterpreter_eieio(PPU_STATE *hCore); +extern void PPCInterpreter_sc(PPU_STATE *hCore); +extern void PPCInterpreter_slbia(PPU_STATE *hCore); +extern void PPCInterpreter_slbie(PPU_STATE *hCore); +extern void PPCInterpreter_slbmte(PPU_STATE *hCore); +extern void PPCInterpreter_rfid(PPU_STATE *hCore); +extern void PPCInterpreter_tw(PPU_STATE *hCore); +extern void PPCInterpreter_twi(PPU_STATE *hCore); +extern void PPCInterpreter_tdi(PPU_STATE *hCore); +extern void PPCInterpreter_tlbie(PPU_STATE *hCore); +extern void PPCInterpreter_tlbiel(PPU_STATE *hCore); +extern void PPCInterpreter_tlbsync(PPU_STATE *hCore); +extern void PPCInterpreter_mfspr(PPU_STATE *hCore); +extern void PPCInterpreter_mtspr(PPU_STATE *hCore); +extern void PPCInterpreter_mfmsr(PPU_STATE *hCore); +extern void PPCInterpreter_mtmsr(PPU_STATE *hCore); +extern void PPCInterpreter_mtmsrd(PPU_STATE *hCore); +extern void PPCInterpreter_sync(PPU_STATE *hCore); + +// Cache Management +extern void PPCInterpreter_dcbf(PPU_STATE *hCore); +extern void PPCInterpreter_dcbi(PPU_STATE* hCore); +extern void PPCInterpreter_dcbt(PPU_STATE* hCore); +extern void PPCInterpreter_dcbtst(PPU_STATE* hCore); +extern void PPCInterpreter_dcbst(PPU_STATE *hCore); +extern void PPCInterpreter_dcbz(PPU_STATE *hCore); +extern void PPCInterpreter_icbi(PPU_STATE *hCore); + +// +// FPU +// +extern void PPCInterpreter_mffsx(PPU_STATE* hCore); +extern void PPCInterpreter_mtfsfx(PPU_STATE* hCore); + +// +// Load/Store +// + +// Store Byte +extern void PPCInterpreter_stb(PPU_STATE *hCore); +extern void PPCInterpreter_stbu(PPU_STATE *hCore); +extern void PPCInterpreter_stbux(PPU_STATE *hCore); +extern void PPCInterpreter_stbx(PPU_STATE *hCore); + +// Store Halfword +extern void PPCInterpreter_sth(PPU_STATE *hCore); +extern void PPCInterpreter_sthbrx(PPU_STATE *hCore); +extern void PPCInterpreter_sthu(PPU_STATE *hCore); +extern void PPCInterpreter_sthux(PPU_STATE *hCore); +extern void PPCInterpreter_sthx(PPU_STATE *hCore); + +// Store String Word +extern void PPCInterpreter_stswi(PPU_STATE *hCore); + +// Store Multiple Word +extern void PPCInterpreter_stmw(PPU_STATE* hCore); + +// Store Word +extern void PPCInterpreter_stw(PPU_STATE *hCore); +extern void PPCInterpreter_stwbrx(PPU_STATE *hCore); +extern void PPCInterpreter_stwcx(PPU_STATE *hCore); +extern void PPCInterpreter_stwu(PPU_STATE *hCore); +extern void PPCInterpreter_stwux(PPU_STATE *hCore); +extern void PPCInterpreter_stwx(PPU_STATE *hCore); + +// Store Doubleword +extern void PPCInterpreter_std(PPU_STATE *hCore); +extern void PPCInterpreter_stdcx(PPU_STATE *hCore); +extern void PPCInterpreter_stdu(PPU_STATE *hCore); +extern void PPCInterpreter_stdux(PPU_STATE *hCore); +extern void PPCInterpreter_stdx(PPU_STATE *hCore); + +// Store Floating +extern void PPCInterpreter_stfd(PPU_STATE *hCore); + +// Load Byte +extern void PPCInterpreter_lbz(PPU_STATE *hCore); +extern void PPCInterpreter_lbzu(PPU_STATE *hCore); +extern void PPCInterpreter_lbzux(PPU_STATE *hCore); +extern void PPCInterpreter_lbzx(PPU_STATE *hCore); + +// Load Halfword +extern void PPCInterpreter_lha(PPU_STATE *hCore); +extern void PPCInterpreter_lhau(PPU_STATE *hCore); +extern void PPCInterpreter_lhax(PPU_STATE *hCore); +extern void PPCInterpreter_lhbrx(PPU_STATE *hCore); +extern void PPCInterpreter_lhz(PPU_STATE *hCore); +extern void PPCInterpreter_lhzu(PPU_STATE *hCore); +extern void PPCInterpreter_lhzux(PPU_STATE *hCore); +extern void PPCInterpreter_lhzx(PPU_STATE *hCore); + +// Load String Word +extern void PPCInterpreter_lswi(PPU_STATE *hCore); + +// Load Multiple Word +extern void PPCInterpreter_lmw(PPU_STATE* hCore); + +// Load Word +extern void PPCInterpreter_lwa(PPU_STATE *hCore); +extern void PPCInterpreter_lwax(PPU_STATE *hCore); +extern void PPCInterpreter_lwarx(PPU_STATE *hCore); +extern void PPCInterpreter_lwbrx(PPU_STATE *hCore); +extern void PPCInterpreter_lwz(PPU_STATE *hCore); +extern void PPCInterpreter_lwzu(PPU_STATE *hCore); +extern void PPCInterpreter_lwzux(PPU_STATE *hCore); +extern void PPCInterpreter_lwzx(PPU_STATE *hCore); + +// Load Doubleword +extern void PPCInterpreter_ld(PPU_STATE *hCore); +extern void PPCInterpreter_ldarx(PPU_STATE *hCore); +extern void PPCInterpreter_ldbrx(PPU_STATE *hCore); +extern void PPCInterpreter_ldu(PPU_STATE *hCore); +extern void PPCInterpreter_ldux(PPU_STATE *hCore); +extern void PPCInterpreter_ldx(PPU_STATE *hCore); + +// +// Load Floating +// + +extern void PPCInterpreter_lfd(PPU_STATE *hCore); +extern void PPCInterpreter_lfs(PPU_STATE *hCore); + +} \ No newline at end of file diff --git a/Xenon/Core/XCPU/Interpreter/PPC_ALU.cpp b/Xenon/Core/XCPU/Interpreter/PPC_ALU.cpp index 2107464..d515d3e 100644 --- a/Xenon/Core/XCPU/Interpreter/PPC_ALU.cpp +++ b/Xenon/Core/XCPU/Interpreter/PPC_ALU.cpp @@ -7,14 +7,10 @@ #define XER_SET_CA(v) hCore->ppuThread[hCore->currentThread].SPR.XER.CA = v void PPCInterpreter::PPCInterpreter_addx(PPU_STATE *hCore) { - XO_FORM_rD_rA_rB_OE_RC; + XO_FORM_rD_rA_rB_RC; GPR(rD) = GPR(rA) + GPR(rB); - if (OE) { - LOG_CRITICAL(Xenon, "ADDX -> Fatal error, OE not implemented!"); - } - if (RC) { u32 CR = CRCompS(hCore, GPR(rD), 0); ppcUpdateCR(hCore, 0, CR); @@ -22,15 +18,11 @@ void PPCInterpreter::PPCInterpreter_addx(PPU_STATE *hCore) { } void PPCInterpreter::PPCInterpreter_addex(PPU_STATE *hCore) { - XO_FORM_rD_rA_rB_OE_RC; + XO_FORM_rD_rA_rB_RC; GPR(rD) = ppcAddCarrying(hCore, GPR(rA), GPR(rB), hCore->ppuThread[hCore->currentThread].SPR.XER.CA); - if (OE) { - LOG_CRITICAL(Xenon, "ADDEXX -> Fatal error, OE not implemented!"); - } - if (RC) { u32 CR = CRCompS(hCore, GPR(rD), 0); ppcUpdateCR(hCore, 0, CR); @@ -49,15 +41,11 @@ void PPCInterpreter::PPCInterpreter_addic(PPU_STATE *hCore) { D_FORM_rD_rA_SI; SI = EXTS(SI, 16); GPR(rD) = ppcAddCarrying(hCore, GPR(rA), SI, 0); -} - -void PPCInterpreter::PPCInterpreter_addic_rc(PPU_STATE *hCore) { - D_FORM_rD_rA_SI; - SI = EXTS(SI, 16); - - GPR(rD) = ppcAddCarrying(hCore, GPR(rA), SI, 0); - u32 CR = CRCompS(hCore, GPR(rD), 0); - ppcUpdateCR(hCore, 0, CR); + // _rc + if (hCore->ppuThread[hCore->currentThread].CI.main & 1) { + u32 CR = CRCompS(hCore, GPR(rD), 0); + ppcUpdateCR(hCore, 0, CR); + } } void PPCInterpreter::PPCInterpreter_addis(PPU_STATE *hCore) { @@ -68,22 +56,18 @@ void PPCInterpreter::PPCInterpreter_addis(PPU_STATE *hCore) { } void PPCInterpreter::PPCInterpreter_addzex(PPU_STATE *hCore) { - XO_FORM_rD_rA_OE_RC; + XO_FORM_rD_rA_RC; GPR(rD) = ppcAddCarrying(hCore, GPR(rA), 0, hCore->ppuThread[hCore->currentThread].SPR.XER.CA); - if (OE) { - LOG_CRITICAL(Xenon, "ADDZEX -> Fatal error, OE not implemented!"); - } - if (RC) { u32 CR = CRCompS(hCore, GPR(rD), 0); ppcUpdateCR(hCore, 0, CR); } } -void PPCInterpreter::PPCInterpreter_and(PPU_STATE *hCore) { +void PPCInterpreter::PPCInterpreter_andx(PPU_STATE *hCore) { X_FORM_rS_rA_rB_RC; GPR(rA) = GPR(rS) & GPR(rB); @@ -94,7 +78,7 @@ void PPCInterpreter::PPCInterpreter_and(PPU_STATE *hCore) { } } -void PPCInterpreter::PPCInterpreter_andc(PPU_STATE *hCore) { +void PPCInterpreter::PPCInterpreter_andcx(PPU_STATE *hCore) { X_FORM_rS_rA_rB_RC; GPR(rA) = GPR(rS) & ~GPR(rB); @@ -178,7 +162,7 @@ void PPCInterpreter::PPCInterpreter_cmpli(PPU_STATE *hCore) { ppcUpdateCR(hCore, BF, CR); } -void PPCInterpreter::PPCInterpreter_cntlzd(PPU_STATE *hCore) { +void PPCInterpreter::PPCInterpreter_cntlzdx(PPU_STATE *hCore) { X_FORM_rS_rA_RC; u64 RegS = GPR(rS); @@ -197,7 +181,7 @@ void PPCInterpreter::PPCInterpreter_cntlzd(PPU_STATE *hCore) { } } -void PPCInterpreter::PPCInterpreter_cntlzw(PPU_STATE *hCore) { +void PPCInterpreter::PPCInterpreter_cntlzwx(PPU_STATE *hCore) { X_FORM_rS_rA_RC; u32 RegS = (u32)GPR(rS); @@ -327,8 +311,8 @@ void PPCInterpreter::PPCInterpreter_crxor(PPU_STATE *hCore) { BCLR(hCore->ppuThread[hCore->currentThread].CR.CR_Hex, 32, BT); } -void PPCInterpreter::PPCInterpreter_divd(PPU_STATE *hCore) { - XO_FORM_rD_rA_rB_OE_RC; +void PPCInterpreter::PPCInterpreter_divdx(PPU_STATE *hCore) { + XO_FORM_rD_rA_rB_RC; if (GPR(rB) != 0 && (GPR(rA) != 0x8000000000000000 || GPR(rB) != 0xFFFFFFFFFFFFFFFF)) { @@ -336,27 +320,19 @@ void PPCInterpreter::PPCInterpreter_divd(PPU_STATE *hCore) { GPR(rD) = (u64)r; } - if (OE) { - LOG_CRITICAL(Xenon, "DIVDX -> Fatal error, OE not implemented!"); - } - if (RC) { u32 CR = CRCompS(hCore, GPR(rD), 0); ppcUpdateCR(hCore, 0, CR); } } -void PPCInterpreter::PPCInterpreter_divdu(PPU_STATE *hCore) { - XO_FORM_rD_rA_rB_OE_RC; +void PPCInterpreter::PPCInterpreter_divdux(PPU_STATE *hCore) { + XO_FORM_rD_rA_rB_RC; if (GPR(rB) != 0) { GPR(rD) = (u64)((u64)GPR(rA) / (u64)GPR(rB)); } - if (OE) { - LOG_CRITICAL(Xenon, "DIVDU -> Fatal error, OE not implemented!"); - } - if (RC) { u32 CR = CRCompS(hCore, GPR(rD), 0); ppcUpdateCR(hCore, 0, CR); @@ -364,16 +340,12 @@ void PPCInterpreter::PPCInterpreter_divdu(PPU_STATE *hCore) { } void PPCInterpreter::PPCInterpreter_divwx(PPU_STATE *hCore) { - XO_FORM_rD_rA_rB_OE_RC; + XO_FORM_rD_rA_rB_RC; if (GPR(rB) != 0 && (GPR(rA) != 0x80000000 || GPR(rB) != 0xFFFFFFFF)) { GPR(rD) = (u32)((s64)(long)GPR(rA) / (s64)(long)GPR(rB)); } - if (OE) { - LOG_CRITICAL(Xenon, "DIVWX -> Fatal error, OE not implemented!"); - } - if (RC) { u32 CR = CRCompS(hCore, GPR(rD), 0); ppcUpdateCR(hCore, 0, CR); @@ -381,16 +353,12 @@ void PPCInterpreter::PPCInterpreter_divwx(PPU_STATE *hCore) { } void PPCInterpreter::PPCInterpreter_divwux(PPU_STATE *hCore) { - XO_FORM_rD_rA_rB_OE_RC; + XO_FORM_rD_rA_rB_RC; if ((u32)GPR(rB) != 0) { GPR(rD) = (u32)((u64)(u32)GPR(rA) / (u64)(u32)GPR(rB)); } - if (OE) { - LOG_CRITICAL(Xenon, "DIVWUX -> Fatal error, OE not implemented!"); - } - if (RC) { u32 CR = CRCompS(hCore, GPR(rD), 0); ppcUpdateCR(hCore, 0, CR); @@ -445,7 +413,7 @@ void PPCInterpreter::PPCInterpreter_mcrf(PPU_STATE *hCore) { ppcUpdateCR(hCore, BF, CR); } -void PPCInterpreter::PPCInterpreter_mfcr(PPU_STATE *hCore) { +void PPCInterpreter::PPCInterpreter_mfocrf(PPU_STATE *hCore) { XFX_FORM_rD; GPR(rD) = hCore->ppuThread[hCore->currentThread].CR.CR_Hex; @@ -468,9 +436,8 @@ void PPCInterpreter::PPCInterpreter_mftb(PPU_STATE *hCore) { } } -void PPCInterpreter::PPCInterpreter_mtcrf(PPU_STATE *hCore) { +void PPCInterpreter::PPCInterpreter_mtocrf(PPU_STATE *hCore) { XFX_FORM_rS_FXM; - u32 Mask = 0; u32 b = 0x80; @@ -480,8 +447,7 @@ void PPCInterpreter::PPCInterpreter_mtcrf(PPU_STATE *hCore) { if (FXM & b) { Mask |= 0xF; } - } - + } hCore->ppuThread[hCore->currentThread].CR.CR_Hex = ((u32)GPR(rS) & Mask) | (hCore->ppuThread[hCore->currentThread].CR.CR_Hex & ~Mask); @@ -499,14 +465,10 @@ void PPCInterpreter::PPCInterpreter_mulli(PPU_STATE *hCore) { } void PPCInterpreter::PPCInterpreter_mulldx(PPU_STATE *hCore) { - XO_FORM_rD_rA_rB_OE_RC; + XO_FORM_rD_rA_rB_RC; u64 qwH, qwL; - if (OE) { - LOG_CRITICAL(Xenon, "MULLDX -> Fatal error, OE not implemented!"); - } - ppcMul64Signed(GPR(rA), GPR(rB), &qwH, &qwL); GPR(rD) = qwL; @@ -517,8 +479,8 @@ void PPCInterpreter::PPCInterpreter_mulldx(PPU_STATE *hCore) { } } -void PPCInterpreter::PPCInterpreter_mullw(PPU_STATE *hCore) { - XO_FORM_rD_rA_rB_OE_RC; +void PPCInterpreter::PPCInterpreter_mullwx(PPU_STATE *hCore) { + XO_FORM_rD_rA_rB_RC; const s64 regA = static_cast(GPR(rA)); const s64 regB = static_cast(GPR(rB)); @@ -526,10 +488,6 @@ void PPCInterpreter::PPCInterpreter_mullw(PPU_STATE *hCore) { GPR(rD) = static_cast(res); - if (OE) { - LOG_CRITICAL(Xenon, "MULLW -> Fatal error, OE not implemented!"); - } - if (RC) { u32 CR = CRCompS(hCore, GPR(rD), 0); ppcUpdateCR(hCore, 0, CR); @@ -577,14 +535,10 @@ void PPCInterpreter::PPCInterpreter_nandx(PPU_STATE *hCore) { } /* Negate */ void PPCInterpreter::PPCInterpreter_negx(PPU_STATE *hCore) { - XO_FORM_rD_rA_OE_RC; + XO_FORM_rD_rA_RC; GPR(rD) = (~GPR(rA)) + 1; - if (OE) { - LOG_CRITICAL(Xenon, "NEG -> Fatal error, OE not implemented!"); - } - if (RC) { u32 CR = CRCompS(hCore, GPR(rD), 0); ppcUpdateCR(hCore, 0, CR); @@ -903,15 +857,11 @@ void PPCInterpreter::PPCInterpreter_srwx(PPU_STATE *hCore) { } void PPCInterpreter::PPCInterpreter_subfcx(PPU_STATE *hCore) { - XO_FORM_rD_rA_rB_OE_RC; + XO_FORM_rD_rA_rB_RC; GPR(rD) = ~GPR(rA) + GPR(rB) + 1; XER_SET_CA((GPR(rD) < ~GPR(rA))); - if (OE) { - LOG_CRITICAL(Xenon, "SUBFCX -> Fatal error, OE not implemented!"); - } - if (RC) { u32 CR = CRCompS(hCore, GPR(rD), 0); ppcUpdateCR(hCore, 0, CR); @@ -919,14 +869,10 @@ void PPCInterpreter::PPCInterpreter_subfcx(PPU_STATE *hCore) { } void PPCInterpreter::PPCInterpreter_subfx(PPU_STATE *hCore) { - XO_FORM_rD_rA_rB_OE_RC; + XO_FORM_rD_rA_rB_RC; GPR(rD) = ~GPR(rA) + GPR(rB) + 1; - if (OE) { - LOG_CRITICAL(Xenon, "SUBFX -> Fatal error, OE not implemented!"); - } - if (RC) { u32 CR = CRCompS(hCore, GPR(rD), 0); ppcUpdateCR(hCore, 0, CR); @@ -934,15 +880,11 @@ void PPCInterpreter::PPCInterpreter_subfx(PPU_STATE *hCore) { } void PPCInterpreter::PPCInterpreter_subfex(PPU_STATE *hCore) { - XO_FORM_rD_rA_rB_OE_RC; + XO_FORM_rD_rA_rB_RC; GPR(rD) = ppcAddCarrying(hCore, ~GPR(rA), GPR(rB), hCore->ppuThread[hCore->currentThread].SPR.XER.CA); - if (OE) { - LOG_CRITICAL(Xenon, "SUBFEX -> Fatal error, OE not implemented!"); - } - if (RC) { u32 CR = CRCompS(hCore, GPR(rD), 0); ppcUpdateCR(hCore, 0, CR); diff --git a/Xenon/Core/XCPU/Interpreter/PPC_FPU.cpp b/Xenon/Core/XCPU/Interpreter/PPC_FPU.cpp index 5995e26..782555d 100644 --- a/Xenon/Core/XCPU/Interpreter/PPC_FPU.cpp +++ b/Xenon/Core/XCPU/Interpreter/PPC_FPU.cpp @@ -8,8 +8,7 @@ #define SET_FPSCR(x) hCore->ppuThread[hCore->currentThread].FPSCR.FPSCR_Hex = x static inline void checkFpuAvailable(PPU_STATE* hCore) { - if (hCore->ppuThread[hCore->currentThread].SPR.MSR.FP != 1) - { + if (hCore->ppuThread[hCore->currentThread].SPR.MSR.FP != 1) { hCore->ppuThread[hCore->currentThread].exceptReg |= PPU_EX_FPU; return; } diff --git a/Xenon/Core/XCPU/Interpreter/PPC_Instruction.cpp b/Xenon/Core/XCPU/Interpreter/PPC_Instruction.cpp index 97f170a..3125fbc 100644 --- a/Xenon/Core/XCPU/Interpreter/PPC_Instruction.cpp +++ b/Xenon/Core/XCPU/Interpreter/PPC_Instruction.cpp @@ -1,1210 +1,1362 @@ -// Copyright 2025 Xenon Emulator Project +/* +* Copyright 2025 Xenon Emulator Project + +* All original authors of the rpcs3 PPU_Decoder and PPU_Opcodes maintain their original copyright. +* Modifed for usage in the Xenon Emulator +* All rights reserved +* License: GPL2 +*/ #include "Base/Logging/Log.h" #include "PPCInterpreter.h" #include "PPC_Instruction.h" +#define D_STUB(name) void PPCInterpreter_##name(PPU_STATE *hCore) { return PPCInterpreter_known_unimplemented(#name, hCore); } +#define D_STUBRC(name) void PPCInterpreter_##name##x(PPU_STATE *hCore) { return PPCInterpreter_known_unimplemented(#name "x", hCore); } -PPCInstruction PPCInterpreter::getOpcode(u32 instrData) { - u32 OPCD = ExtractBits(instrData, 0, 5); +namespace PPCInterpreter { + void PPCInterpreter_nop(PPU_STATE *hCore) { + // Do nothing + } + void PPCInterpreter_invalid(PPU_STATE *hCore) { + PPU_THREAD_REGISTERS& thread = + hCore->ppuThread[hCore->currentThread]; - u32 XO_20to30 = ExtractBits(instrData, 20, 30); - u32 XO_27to29 = ExtractBits(instrData, 27, 29); - u32 XO_27to30 = ExtractBits(instrData, 27, 30); - u32 XO_21to30 = ExtractBits(instrData, 21, 30); - u32 XO_22to30 = ExtractBits(instrData, 22, 30); - u32 XO_21to29 = ExtractBits(instrData, 21, 29); - u32 XO_30to31 = ExtractBits(instrData, 30, 31); + std::string name = + legacy_GetOpcodeName(thread.CI.opcode); - switch (OPCD) { - case 2: // tdi - return PPCInstruction::tdi; - break; - case 3: // twi - return PPCInstruction::twi; - break; - case 7: // mulli - return PPCInstruction::mulli; - break; - case 8: // subfic - return PPCInstruction::subfic; - break; - case 10: // cmpli - return PPCInstruction::cmpli; - break; - case 11: // cmpi - return PPCInstruction::cmpi; - break; - case 12: // addic - return PPCInstruction::addic; - break; - case 13: // addic. - return PPCInstruction::addicx; - break; - case 14: // addi - return PPCInstruction::addi; - break; - case 15: // addis - return PPCInstruction::addis; - break; - case 16: // bcx - return PPCInstruction::bcx; - break; - case 17: // sc - return PPCInstruction::sc; - break; - case 18: // bx - return PPCInstruction::bx; - break; - case 19: /* Subgroup 19 */ - switch (XO_21to30) { - case 0: // mcrf - return PPCInstruction::mcrf; - break; - case 16: // bclrx - return PPCInstruction::bclrx; - break; - case 18: // rfid - return PPCInstruction::rfid; - break; - case 33: // crnor - return PPCInstruction::crnor; - break; - case 129: // crandc - return PPCInstruction::crandc; - break; - case 150: // isync - return PPCInstruction::isync; - break; - case 193: // crxor - return PPCInstruction::crxor; - break; - case 225: // crnand - return PPCInstruction::crnand; - break; - case 257: // crand - return PPCInstruction::crand; - break; - case 289: // creqv - return PPCInstruction::creqv; - break; - case 417: // crorc - return PPCInstruction::crorc; - break; - case 449: // cror - return PPCInstruction::cror; - break; - case 528: // bcctrx - return PPCInstruction::bcctrx; - break; - } - LOG_ERROR(Xenon, "PPC Decoder: Unimplemented instruction found, SUBGROUP 19!"); - return PPCInstruction::invalidInstruction; - break; - case 20: // rlwimix - return PPCInstruction::rlwimix; - break; - case 21: // rlwinmx - return PPCInstruction::rlwinmx; - break; - case 23: // rlwnmx - return PPCInstruction::rlwnmx; - break; - case 24: // ori - return PPCInstruction::ori; - break; - case 25: // oris - return PPCInstruction::oris; - break; - case 26: // xori - return PPCInstruction::xori; - break; - case 27: // xoris - return PPCInstruction::xoris; - break; - case 28: // andi. - return PPCInstruction::andix; - break; - case 29: // andis. - return PPCInstruction::andisx; - break; - case 30: /* Subgroup 30 */ - switch (XO_27to29) { - case 0: // rldiclx - return PPCInstruction::rldiclx; - break; - case 1: // rldicrx - return PPCInstruction::rldicrx; - break; - case 2: // rldicx - return PPCInstruction::rldicx; - break; - case 3: // rldimix - return PPCInstruction::rldimix; - break; - } - switch (XO_27to30) { - case 8: // rldclx - return PPCInstruction::rldclx; - break; - case 9: // rldcrx - return PPCInstruction::rldcrx; - break; - } - LOG_ERROR(Xenon, "PPC Decoder: Unimplemented instruction found, SUBGROUP 30!"); - return PPCInstruction::invalidInstruction; - break; - case 31: /* Subgroup 31 */ - switch (XO_21to30) { - case 0: // cmp - return PPCInstruction::cmp; - break; - case 4: // tw - return PPCInstruction::tw; - break; - case 19: // mfcr - return PPCInstruction::mfcr; - break; - case 20: // lwarx - return PPCInstruction::lwarx; - break; - case 21: // ldx - return PPCInstruction::ldx; - break; - case 23: // lwzx - return PPCInstruction::lwzx; - break; - case 24: // slwx - return PPCInstruction::slwx; - break; - case 26: // cntlzwx - return PPCInstruction::cntlzwx; - break; - case 27: // sldx - return PPCInstruction::sldx; - break; - case 28: // andx - return PPCInstruction::andx; - break; - case 32: // cmpl - return PPCInstruction::cmpl; - break; - case 53: // ldux - return PPCInstruction::ldux; - break; - case 54: // dcbst - return PPCInstruction::dcbst; - break; - case 55: // lwzux - return PPCInstruction::lwzux; - break; - case 58: // cntlzdx - return PPCInstruction::cntlzdx; - break; - case 60: // andcx - return PPCInstruction::andcx; - break; - case 68: // td - return PPCInstruction::td; - break; - case 83: // mfmsr - return PPCInstruction::mfmsr; - break; - case 84: // ldarx - return PPCInstruction::ldarx; - break; - case 86: // dcbf - return PPCInstruction::dcbf; - break; - case 87: // lbzx - return PPCInstruction::lbzx; - break; - case 119: // lbzux - return PPCInstruction::lbzux; - break; - case 124: // norx - return PPCInstruction::norx; - break; - case 144: // mtcrf - return PPCInstruction::mtcrf; - break; - case 146: // mtmsr - return PPCInstruction::mtmsr; - break; - case 149: // stdx - return PPCInstruction::stdx; - break; - case 150: // stwcx. - return PPCInstruction::stwcx; - break; - case 151: // stwx - return PPCInstruction::stwx; - break; - case 178: // mtmsrd - return PPCInstruction::mtmsrd; - break; - case 181: // stdux - return PPCInstruction::stdux; - break; - case 183: // stwux - return PPCInstruction::stwux; - break; - case 210: // mtsr - return PPCInstruction::mtsr; - break; - case 214: // stdcx. - return PPCInstruction::stdcx; - break; - case 215: // stbx - return PPCInstruction::stbx; - break; - case 242: // mtsrin - return PPCInstruction::mtsrin; - break; - case 247: // stbux - return PPCInstruction::stbux; - break; - case 246: // dcbt - return PPCInstruction::dcbt; - break; - case 278: // dcbt - return PPCInstruction::dcbt; - break; - case 279: // lhzx - return PPCInstruction::lhzx; - break; - case 284: // eqvx - return PPCInstruction::eqvx; - break; - case 274: // tlbiel - return PPCInstruction::tlbiel; - break; - case 306: // tlbie - return PPCInstruction::tlbie; - break; - case 310: // eciwx - return PPCInstruction::eciwx; - break; - case 311: // lhzux - return PPCInstruction::lhzux; - break; - case 316: // xorx - return PPCInstruction::xorx; - break; - case 339: // mfspr - return PPCInstruction::mfspr; - break; - case 341: // lwax - return PPCInstruction::lwax; - break; - case 343: // lhax - return PPCInstruction::lhax; - break; - case 370: // tlbia - return PPCInstruction::tlbia; - break; - case 371: // mftb - return PPCInstruction::mftb; - break; - case 373: // lwaux - return PPCInstruction::lwaux; - break; - case 375: // lhaux - return PPCInstruction::lhaux; - break; - case 407: // sthx - return PPCInstruction::sthx; - break; - case 412: // orcx - return PPCInstruction::orcx; - break; - case 434: // slbie - return PPCInstruction::slbie; - break; - case 438: // ecowx - return PPCInstruction::ecowx; - break; - case 439: // sthux - return PPCInstruction::sthux; - break; - case 444: // orx - return PPCInstruction::orx; - break; - case 467: // mtspr - return PPCInstruction::mtspr; - break; - case 476: // nandx - return PPCInstruction::nandx; - break; - case 498: // slbia - return PPCInstruction::slbia; - break; - case 533: // lswx - return PPCInstruction::lswx; - break; - case 534: // lwbrx - return PPCInstruction::lwbrx; - break; - case 535: // lfsx - return PPCInstruction::lfsx; - break; - case 536: // srwx - return PPCInstruction::srwx; - break; - case 539: // srdx - return PPCInstruction::srdx; - break; - case 566: // tlbsync - return PPCInstruction::tlbsync; - break; - case 567: // lfsux - return PPCInstruction::lfsux; - break; - case 595: // mfsr - return PPCInstruction::mfsr; - break; - case 597: // lswi - return PPCInstruction::lswi; - break; - case 598: // sync - return PPCInstruction::sync; - break; - case 599: // lfdx - return PPCInstruction::lfdx; - break; - case 631: // lfdux - return PPCInstruction::lfdux; - break; - case 569: // mfsrin - return PPCInstruction::mfsrin; - break; - case 915: // slbmfee - return PPCInstruction::slbmfee; - break; - case 851: // slbmfev - return PPCInstruction::slbmfev; - break; - case 402: // slbmte - return PPCInstruction::slbmte; - break; - case 661: // stswx - return PPCInstruction::stswx; - break; - case 662: // stwbrx - return PPCInstruction::stwbrx; - break; - case 663: // stfsx - return PPCInstruction::stfsx; - break; - case 695: // stfsux - return PPCInstruction::stfsux; - break; - case 725: // stswi - return PPCInstruction::stswi; - break; - case 727: // stfdx - return PPCInstruction::stfdx; - break; - case 759: // stfdux - return PPCInstruction::stfdux; - break; - case 790: // lhbrx - return PPCInstruction::lhbrx; - break; - case 792: // srawx - return PPCInstruction::srawx; - break; - case 794: // sradx - return PPCInstruction::sradx; - break; - case 824: // srawix - return PPCInstruction::srawix; - break; - case 854: // eieio - return PPCInstruction::eieio; - break; - case 918: // sthbrx - return PPCInstruction::sthbrx; - break; - case 922: // extshx - return PPCInstruction::extshx; - break; - case 954: // extsbx - return PPCInstruction::extsbx; - break; - case 982: // icbi - return PPCInstruction::icbi; - break; - case 983: // stfiwx - return PPCInstruction::stfiwx; - break; - case 986: // extswx - return PPCInstruction::extswx; - break; - case 1014: // dcbz - return PPCInstruction::dcbz; - break; - } - switch (XO_22to30) { - case 8: // subfcx - return PPCInstruction::subfcx; - break; - case 9: // mulhdux - return PPCInstruction::mulhdux; - break; - case 10: // addcx - return PPCInstruction::addcx; - break; - case 11: // mulhwux - return PPCInstruction::mulhwux; - break; - case 40: // subfx - return PPCInstruction::subfx; - break; - case 73: // mulhdx - return PPCInstruction::mulhdx; - break; - case 75: // mulhwx - return PPCInstruction::mulhwx; - break; - case 104: // negx - return PPCInstruction::negx; - break; - case 136: // subfex - return PPCInstruction::subfex; - break; - case 138: // addex - return PPCInstruction::addex; - break; - case 200: // subfzex - return PPCInstruction::subfzex; - break; - case 202: // addzex - return PPCInstruction::addzex; - break; - case 232: // subfmex - return PPCInstruction::subfmex; - break; - case 233: // mulldx - return PPCInstruction::mulldx; - break; - case 234: // addmex - return PPCInstruction::addmex; - break; - case 235: // mullwx - return PPCInstruction::mullwx; - break; - case 266: // addx - return PPCInstruction::addx; - break; - case 457: // divdux - return PPCInstruction::divdux; - break; - case 459: // divwux - return PPCInstruction::divwux; - break; - case 489: // divdx - return PPCInstruction::divdx; - break; - case 491: // divwx - return PPCInstruction::divwx; - break; - } - switch (XO_21to29) { - case 413: // sradix - return PPCInstruction::sradix; - break; - } - LOG_ERROR(Xenon, "PPC Decoder: Unimplemented instruction found, SUBGROUP 31!"); - return PPCInstruction::invalidInstruction; - break; - case 32: // lwz - return PPCInstruction::lwz; - break; - case 33: // lwzu - return PPCInstruction::lwzu; - break; - case 34: // lbz - return PPCInstruction::lbz; - break; - case 35: // lbzu - return PPCInstruction::lbzu; - break; - case 36: // stw - return PPCInstruction::stw; - break; - case 37: // stwu - return PPCInstruction::stwu; - break; - case 38: // stb - return PPCInstruction::stb; - break; - case 39: // stbu - return PPCInstruction::stbu; - break; - case 40: // lhz - return PPCInstruction::lhz; - break; - case 41: // lhzu - return PPCInstruction::lhzu; - break; - case 42: // lha - return PPCInstruction::lha; - break; - case 43: // lhau - return PPCInstruction::lhau; - break; - case 44: // sth - return PPCInstruction::sth; - break; - case 45: // sthu - return PPCInstruction::sthu; - break; - case 46: // lmw - return PPCInstruction::lmw; - break; - case 47: // stmw - return PPCInstruction::stmw; - break; - case 48: // lfs - return PPCInstruction::lfs; - break; - case 50: // lfd - return PPCInstruction::lfd; - break; - case 52: // stfs - return PPCInstruction::stfs; - break; - case 53: // stfsu - return PPCInstruction::stfs; - break; - case 54: // stfd - return PPCInstruction::stfd; - break; - case 55: // stfdu - return PPCInstruction::stfdu; - break; - case 58: - switch (XO_30to31) { - case 0: // ld - return PPCInstruction::ld; - break; - case 1: // ldu - return PPCInstruction::ldu; - break; - case 2: // lwa - return PPCInstruction::lwa; - break; - default: - LOG_ERROR(Xenon, "PPC Decoder: Unimplemented instruction found, SUBGROUP 58!"); - return PPCInstruction::invalidInstruction; - break; - } - case 62: - switch (XO_30to31) { - case 0: // std - return PPCInstruction::std; - break; - case 1: // stdu - return PPCInstruction::stdu; - break; - default: - LOG_ERROR(Xenon, "PPC Decoder: Unimplemented instruction found, SUBGROUP 62!"); - return PPCInstruction::invalidInstruction; - break; - } - case 63: - switch (XO_21to30) { - case 583: // mffsx - return PPCInstruction::mffsx; - break; - case 711: // mtfsfx - return PPCInstruction::mtfsfx; - break; - default: - LOG_ERROR(Xenon, "PPC Decoder: Unimplemented instruction found, SUBGROUP 63!"); - return PPCInstruction::invalidInstruction; - break; - } - break; - default: - LOG_ERROR(Xenon, "PPC Decoder: Unimplemented instruction found, data {:#x}", instrData); - return PPCInstruction::invalidInstruction; - break; + LOG_CRITICAL(Xenon, "PPC Interpreter: {} found: data: {:#x}, address: {:#x}", + name.data(), + thread.CI.opcode, + thread.CIA); } -} -std::string PPCInterpreter::getOpcodeName(u32 instrData) { - u32 OPCD = ExtractBits(instrData, 0, 5); + void PPCInterpreter_known_unimplemented(const char *name, PPU_STATE *hCore) { + PPU_THREAD_REGISTERS& thread = + hCore->ppuThread[hCore->currentThread]; - u32 XO_20to30 = ExtractBits(instrData, 20, 30); - u32 XO_27to29 = ExtractBits(instrData, 27, 29); - u32 XO_27to30 = ExtractBits(instrData, 27, 30); - u32 XO_21to30 = ExtractBits(instrData, 21, 30); - u32 XO_22to30 = ExtractBits(instrData, 22, 30); - u32 XO_21to29 = ExtractBits(instrData, 21, 29); - u32 XO_30to31 = ExtractBits(instrData, 30, 31); + LOG_CRITICAL(Xenon, "PPC Interpreter: {} is not implemented! data: {:#x}, address: {:#x}", + name, + thread.CI.opcode, + thread.CIA); + } - switch (OPCD) { - case 2: // tdi - return "tdi"; - break; - case 3: // twi - return "twi"; - break; - case 7: // mulli - return "mulli"; - break; - case 8: // subfic - return "subfic"; - break; - case 10: // cmpli - return "cmpli"; - break; - case 11: // cmpi - return "cmpi"; - break; - case 12: // addic - return "addic"; - break; - case 13: // addic. - return "addicx"; - break; - case 14: // addi - return "addi"; - break; - case 15: // addis - return "addis"; - break; - case 16: // bcx - return "bcx"; - break; - case 17: // sc - return "sc"; - break; - case 18: // bx - return "bx"; - break; - case 19: /* Subgroup 19 */ - switch (XO_20to30) { - case 0: // mcrf - return "mcrf"; - break; - case 16: // bclrx - return "bclrx"; - break; - case 18: // rfid - return "rfid"; - break; - case 33: // crnor - return "crnor"; - break; - case 129: // crandc - return "crandc"; - break; - case 150: // isync - return "isync"; - break; - case 193: // crxor - return "crxor"; - break; - case 225: // crnand - return "crnand"; - break; - case 257: // crand - return "crand"; - break; - case 289: // creqv - return "creqv"; - break; - case 417: // crorc - return "crorc"; - break; - case 449: // cror - return "cror"; - break; - case 528: // bcctrx - return "bcctrx"; - break; - } - return "INVALID"; - break; - case 20: // rlwimix - return "rlwimix"; - break; - case 21: // rlwinmx - return "rlwinmx"; - break; - case 23: // rlwnmx - return "rlwnmx"; - break; - case 24: // ori - return "ori"; - break; - case 25: // oris - return "oris"; - break; - case 26: // xori - return "xori"; - break; - case 27: // xoris - return "xoris"; - break; - case 28: // andi. - return "andix"; - break; - case 29: // andis. - return "andisx"; - break; - case 30: /* Subgroup 30 */ - switch (XO_27to29) { - case 0: // rldiclx - return "rldiclx"; - break; - case 1: // rldicrx - return "rldicrx"; - break; - case 2: // rldicx - return "rldicx"; - break; - case 3: // rldimix - return "rldimix"; - break; - } - switch (XO_27to30) { - case 8: // rldclx - return "rldclx"; - break; - case 9: // rldcrx - return "rldcrx"; - break; - } - return "INVALID"; - break; - case 31: /* Subgroup 31 */ - switch (XO_21to30) { - case 0: // cmp - return "cmp"; - break; - case 4: // tw - return "tw"; - break; - case 19: // mfcr - return "mfcr"; - break; - case 20: // lwarx - return "lwarx"; - break; - case 21: // ldx - return "ldx"; - break; - case 23: // lwzx - return "lwzx"; - break; - case 24: // slwx - return "slwx"; - break; - case 26: // cntlzwx - return "cntlzwx"; - break; - case 27: // sldx - return "sldx"; - break; - case 28: // andx - return "andx"; - break; - case 32: // cmpl - return "cmpl"; - break; - case 53: // ldux - return "ldux"; - break; - case 54: // dcbst - return "dcbst"; - break; - case 55: // lwzux - return "lwzux"; - break; - case 58: // cntlzdx - return "cntlzdx"; - break; - case 60: // andcx - return "andcx"; - break; - case 68: // td - return "td"; - break; - case 83: // mfmsr - return "mfmsr"; - break; - case 84: // ldarx - return "ldarx"; - break; - case 86: // dcbf - return "dcbf"; - break; - case 87: // lbzx - return "lbzx"; - break; - case 119: // lbzux - return "lbzux"; - break; - case 124: // norx - return "norx"; - break; - case 144: // mtcrf - return "mtcrf"; - break; - case 146: // mtmsr - return "mtmsr"; - break; - case 149: // stdx - return "stdx"; - break; - case 150: // stwcx. - return "stwcx"; - break; - case 151: // stwx - return "stwx"; - break; - case 178: // mtmsrd - return "mtmsrd"; - break; - case 181: // stdux - return "stdux"; - break; - case 183: // stwux - return "stwux"; - break; - case 210: // mtsr - return "mtsr"; - break; - case 214: // stdcx. - return "stdcx"; - break; - case 215: // stbx - return "stbx"; - break; - case 242: // mtsrin - return "mtsrin"; - break; - case 247: // stbux - return "stbux"; - break; - case 246: // dcbt - return "dcbt"; - break; - case 278: // dcbt - return "dcbt"; - break; - case 279: // lhzx - return "lhzx"; - break; - case 284: // eqvx - return "eqvx"; - break; - case 274: // tlbiel - return "tlbiel"; - break; - case 306: // tlbie - return "tlbie"; - break; - case 310: // eciwx - return "eciwx"; - break; - case 311: // lhzux - return "lhzux"; - break; - case 316: // xorx - return "xorx"; - break; - case 339: // mfspr - return "mfspr"; - break; - case 341: // lwax - return "lwax"; - break; - case 343: // lhax - return "lhax"; - break; - case 370: // tlbia - return "tlbia"; - break; - case 371: // mftb - return "mftb"; - break; - case 373: // lwaux - return "lwaux"; - break; - case 375: // lhaux - return "lhaux"; - break; - case 407: // sthx - return "sthx"; - break; - case 412: // orcx - return "orcx"; - break; - case 434: // slbie - return "slbie"; - break; - case 438: // ecowx - return "ecowx"; - break; - case 439: // sthux - return "sthux"; - break; - case 444: // orx - return "orx"; - break; - case 467: // mtspr - return "mtspr"; - break; - case 476: // nandx - return "nandx"; - break; - case 498: // slbia - return "slbia"; - break; - case 533: // lswx - return "lswx"; - break; - case 534: // lwbrx - return "lwbrx"; - break; - case 535: // lfsx - return "lfsx"; - break; - case 536: // srwx - return "srwx"; - break; - case 539: // srdx - return "srdx"; - break; - case 566: // tlbsync - return "tlbsync"; - break; - case 567: // lfsux - return "lfsux"; - break; - case 595: // mfsr - return "mfsr"; - break; - case 597: // lswi - return "lswi"; - break; - case 598: // sync - return "sync"; - break; - case 599: // lfdx - return "lfdx"; - break; - case 631: // lfdux - return "lfdux"; - break; - case 569: // mfsrin - return "mfsrin"; - break; - case 915: // slbmfee - return "slbmfee"; - break; - case 851: // slbmfev - return "slbmfev"; - break; - case 402: // slbmte - return "slbmte"; - break; - case 661: // stswx - return "stswx"; - break; - case 662: // stwbrx - return "stwbrx"; - break; - case 663: // stfsx - return "stfsx"; - break; - case 695: // stfsux - return "stfsux"; - break; - case 725: // stswi - return "stswi"; - break; - case 727: // stfdx - return "stfdx"; - break; - case 759: // stfdux - return "stfdux"; - break; - case 790: // lhbrx - return "lhbrx"; - break; - case 762: // srawx - return "srawx"; - break; - case 794: // sradx - return "sradx"; - break; - case 824: // srawix - return "srawix"; - break; - case 854: // eieio - return "eieio"; - break; - case 918: // sthbrx - return "sthbrx"; - break; - case 922: // extshx - return "extshx"; - break; - case 954: // extsbx - return "extsbx"; - break; - case 982: // icbi - return "icbi"; - break; - case 983: // stfiwx - return "stfiwx"; - break; - case 986: // extswx - return "extswx"; - break; - case 1014: // dcbz - return "dcbz"; - break; - } - switch (XO_22to30) { - case 8: // subfcx - return "subfcx"; - break; - case 9: // mulhdux - return "mulhdux"; - break; - case 10: // addcx - return "addcx"; - break; - case 11: // mulhwux - return "mulhwux"; - break; - case 40: // subfx - return "subfx"; - break; - case 73: // mulhdx - return "mulhdx"; - break; - case 75: // mulhwx - return "mulhwx"; - break; - case 104: // negx - return "negx"; - break; - case 136: // subfex - return "subfex"; - break; - case 138: // addex - return "addex"; - break; - case 200: // subfzex - return "subfzex"; - break; - case 202: // addzex - return "addzex"; - break; - case 232: // subfmex - return "subfmex"; - break; - case 233: // mulldx - return "mulldx"; - break; - case 234: // addmex - return "addmex"; - break; - case 235: // mullwx - return "mullwx"; - break; - case 266: // addx - return "addx"; - break; - case 457: // divdux - return "divdux"; - break; - case 459: // divwux - return "divwux"; - break; - case 489: // divdx - return "divdx"; - break; - case 491: // divwx - return "divwx"; - break; - } - switch (XO_21to29) { - case 413: // sradix - return "sradix"; - break; - } - return "INVALID"; - break; - case 32: // lwz - return "lwz"; - break; - case 33: // lwzu - return "lwzu"; - break; - case 34: // lbz - return "lbz"; - break; - case 35: // lbzu - return "lbzu"; - break; - case 36: // stw - return "stw"; - break; - case 37: // stwu - return "stwu"; - break; - case 38: // stb - return "stb"; - break; - case 39: // stbu - return "stbu"; - break; - case 40: // lhz - return "lhz"; - break; - case 41: // lhzu - return "lhzu"; - break; - case 44: // sth - return "sth"; - break; - case 48: // lfs - return "lfs"; - break; - case 58: - switch (XO_30to31) { - case 0: // ld - return "ld"; - break; - case 1: // ldu - return "ldu"; - break; - default: - return "INVALID"; - break; - } - case 62: - switch (XO_30to31) { - case 0: // std - return "std"; - break; - case 1: // stdu - return "stdu"; - break; + D_STUBRC(addc); + D_STUBRC(addco); + D_STUBRC(addo); + D_STUBRC(addeo); + D_STUBRC(addzeo); + D_STUBRC(addme); + D_STUBRC(addmeo); + D_STUBRC(subfco); + D_STUBRC(subfeo); + D_STUBRC(subfo); + D_STUBRC(subfze); + D_STUBRC(subfzeo); + D_STUBRC(subfme); + D_STUBRC(subfmeo); + D_STUBRC(divduo); + D_STUBRC(divdo); + D_STUBRC(divwo); + D_STUBRC(divwuo); + D_STUBRC(mulhd); + D_STUBRC(mulldo); + D_STUBRC(mulhw); + D_STUBRC(mullwo); + D_STUBRC(nego); + D_STUBRC(rldcl); + D_STUBRC(mcrfs); + D_STUBRC(mtfsb1); + D_STUBRC(mtfsb0); + D_STUBRC(mtfsfi); + D_STUBRC(fadd); + D_STUBRC(fsub); + D_STUBRC(fctid); + D_STUBRC(fctidz); + D_STUBRC(fcfid); + D_STUBRC(fctiw); + D_STUBRC(fctiwz); + D_STUBRC(fadds); + D_STUBRC(fsubs); + D_STUBRC(fdiv); + D_STUBRC(fdivs); + D_STUBRC(fmr); + D_STUBRC(fmadds); + D_STUBRC(fmsubs); + D_STUBRC(fmul); + D_STUBRC(fmuls); + D_STUBRC(fnmsub); + D_STUBRC(fnmsubs); + D_STUBRC(fnmadd); + D_STUBRC(fmadd); + D_STUBRC(fnmadds); + D_STUBRC(fmsub); + D_STUBRC(fneg); + D_STUBRC(fsel); + D_STUBRC(fres); + D_STUBRC(frsp); + D_STUBRC(fabs); + D_STUBRC(fnabs); + D_STUBRC(fsqrt); + D_STUBRC(fsqrts); + D_STUBRC(frsqrte); + D_STUBRC(eqv); + D_STUB(td); + D_STUB(dst); + D_STUB(dss); + D_STUB(dstst); + D_STUB(lfdx); + D_STUB(lfdu); + D_STUB(lfdux); + D_STUB(lfsx); + D_STUB(lfsu); + D_STUB(lfsux); + D_STUB(mfsrin); + D_STUB(mfsr); + D_STUB(lvsr); + D_STUB(lvsl); + D_STUB(lvx); + D_STUB(lvrx); + D_STUB(lvxl); + D_STUB(lvrxl); + D_STUB(lvlx); + D_STUB(lvlxl); + D_STUB(lwaux); + D_STUB(lswx); + D_STUB(lhaux); + D_STUB(lvewx); + D_STUB(lveb); + D_STUB(lvebx); + D_STUB(lvehx); + D_STUB(stdbrx); + D_STUB(stswx); + D_STUB(stfdu); + D_STUB(stfs); + D_STUB(stfdx); + D_STUB(stfsx); + D_STUB(stfsu); + D_STUB(stfsux); + D_STUB(stfdux); + D_STUB(stfiwx); + D_STUB(stvebx); + D_STUB(fcmpo); + D_STUB(fcmpu); + D_STUB(stvx); + D_STUB(stvxl); + D_STUB(stvrx); + D_STUB(stvlx); + D_STUB(stvrxl); + D_STUB(stvlxl); + D_STUB(stvehx); + D_STUB(stvewx); + D_STUB(eciwx); + D_STUB(ecowx); + D_STUB(orc); + D_STUB(slbmfev); + D_STUB(slbmfee); + + // Vector-instructions + D_STUB(vaddubm); + D_STUB(vmaxub); + D_STUB(vrlb); + D_STUB(vcmpequb); + D_STUB(vcmpequb_); + D_STUB(vmuloub); + D_STUB(vaddfp); + D_STUB(vmrghb); + D_STUB(vpkuhum); + + D_STUB(vmhaddshs); + D_STUB(vmhraddshs); + D_STUB(vmladduhm); + D_STUB(vmsumubm); + D_STUB(vmsummbm); + D_STUB(vmsumuhm); + D_STUB(vmsumuhs); + D_STUB(vmsumshm); + D_STUB(vmsumshs); + D_STUB(vsel); + D_STUB(vperm); + D_STUB(vsldoi); + D_STUB(vmaddfp); + D_STUB(vnmsubfp); + + D_STUB(vadduhm); + D_STUB(vmaxuh); + D_STUB(vrlh); + D_STUB(vcmpequh); + D_STUB(vcmpequh_); + D_STUB(vmulouh); + D_STUB(vsubfp); + D_STUB(vmrghh); + D_STUB(vpkuwum); + D_STUB(vadduwm); + D_STUB(vmaxuw); + D_STUB(vrlw); + D_STUB(vcmpequw); + D_STUB(vcmpequw_); + D_STUB(vmrghw); + D_STUB(vpkuhus); + D_STUB(vcmpeqfp); + D_STUB(vcmpeqfp_); + D_STUB(vpkuwus); + + D_STUB(vmaxsb); + D_STUB(vslb); + D_STUB(vmulosb); + D_STUB(vrefp); + D_STUB(vmrglb); + D_STUB(vpkshus); + D_STUB(vmaxsh); + D_STUB(vslh); + D_STUB(vmulosh); + D_STUB(vrsqrtefp); + D_STUB(vmrglh); + D_STUB(vpkswus); + D_STUB(vaddcuw); + D_STUB(vmaxsw); + D_STUB(vslw); + D_STUB(vexptefp); + D_STUB(vmrglw); + D_STUB(vpkshss); + D_STUB(vsl); + D_STUB(vcmpgefp); + D_STUB(vcmpgefp_); + D_STUB(vlogefp); + D_STUB(vpkswss); + D_STUB(vaddubs); + D_STUB(vminub); + D_STUB(vsrb); + D_STUB(vcmpgtub); + D_STUB(vcmpgtub_); + D_STUB(vmuleub); + D_STUB(vrfin); + D_STUB(vspltb); + D_STUB(vupkhsb); + D_STUB(vadduhs); + D_STUB(vminuh); + D_STUB(vsrh); + D_STUB(vcmpgtuh); + D_STUB(vcmpgtuh_); + D_STUB(vmuleuh); + D_STUB(vrfiz); + D_STUB(vsplth); + D_STUB(vupkhsh); + D_STUB(vadduws); + D_STUB(vminuw); + D_STUB(vsrw); + D_STUB(vcmpgtuw); + D_STUB(vcmpgtuw_); + D_STUB(vrfip); + D_STUB(vspltw); + D_STUB(vupklsb); + D_STUB(vsr); + D_STUB(vcmpgtfp); + D_STUB(vcmpgtfp_); + D_STUB(vrfim); + D_STUB(vupklsh); + D_STUB(vaddsbs); + D_STUB(vminsb); + D_STUB(vsrab); + D_STUB(vcmpgtsb); + D_STUB(vcmpgtsb_); + D_STUB(vmulesb); + D_STUB(vcfux); + D_STUB(vspltisb); + D_STUB(vpkpx); + D_STUB(vaddshs); + D_STUB(vminsh); + D_STUB(vsrah); + D_STUB(vcmpgtsh); + D_STUB(vcmpgtsh_); + D_STUB(vmulesh); + D_STUB(vcfsx); + D_STUB(vspltish); + D_STUB(vupkhpx); + D_STUB(vaddsws); + D_STUB(vminsw); + D_STUB(vsraw); + D_STUB(vcmpgtsw); + D_STUB(vcmpgtsw_); + D_STUB(vctuxs); + D_STUB(vspltisw); + D_STUB(vcmpbfp); + D_STUB(vcmpbfp_); + D_STUB(vctsxs); + D_STUB(vupklpx); + D_STUB(vsububm); + D_STUB(vavgub); + D_STUB(vand); + D_STUB(vmaxfp); + D_STUB(vslo); + D_STUB(vsubuhm); + D_STUB(vavguh); + D_STUB(vandc); + D_STUB(vminfp); + D_STUB(vsro); + D_STUB(vsubuwm); + D_STUB(vavguw); + D_STUB(vor); + D_STUB(vxor); + D_STUB(vavgsb); + D_STUB(vnor); + D_STUB(vavgsh); + D_STUB(vsubcuw); + D_STUB(vavgsw); + D_STUB(vsububs); + D_STUB(mfvscr); + D_STUB(vsum4ubs); + D_STUB(vsubuhs); + D_STUB(mtvscr); + D_STUB(vsum4shs); + D_STUB(vsubuws); + D_STUB(vsum2sws); + D_STUB(vsubsbs); + D_STUB(vsum4sbs); + D_STUB(vsubshs); + D_STUB(vsubsws); + D_STUB(vsumsws); + + PPCDecoder::PPCDecoder() { + #define GET_(name) &PPCInterpreter_##name + #define GET(name) GET_(name), GET_(name) + #define GETRC(name) GET_(name##x), GET_(name##x) + for (auto& x : table) { + x = GET(invalid); + } + // Main opcodes (field 0..5) + fillTable(0x00, 6, -1, { + { 0x02, GET(tdi) }, + { 0x03, GET(twi) }, + { 0x07, GET(mulli) }, + { 0x08, GET(subfic) }, + { 0x0A, GET(cmpli) }, + { 0x0B, GET(cmpi) }, + { 0x0C, GET(addic) }, + { 0x0D, GET(addic) }, + { 0x0E, GET(addi) }, + { 0x0F, GET(addis) }, + { 0x10, GET(bc) }, + { 0x11, GET(sc) }, + { 0x12, GET(b) }, + { 0x14, GETRC(rlwimi) }, + { 0x15, GETRC(rlwinm) }, + { 0x17, GETRC(rlwnm) }, + { 0x18, GET(ori) }, + { 0x19, GET(oris) }, + { 0x1A, GET(xori) }, + { 0x1B, GET(xoris) }, + { 0x1C, GET(andi) }, + { 0x1D, GET(andis) }, + { 0x20, GET(lwz) }, + { 0x21, GET(lwzu) }, + { 0x22, GET(lbz) }, + { 0x23, GET(lbzu) }, + { 0x24, GET(stw) }, + { 0x25, GET(stwu) }, + { 0x26, GET(stb) }, + { 0x27, GET(stbu) }, + { 0x28, GET(lhz) }, + { 0x29, GET(lhzu) }, + { 0x2A, GET(lha) }, + { 0x2B, GET(lhau) }, + { 0x2C, GET(sth) }, + { 0x2D, GET(sthu) }, + { 0x2E, GET(lmw) }, + { 0x2F, GET(stmw) }, + { 0x30, GET(lfs) }, + { 0x31, GET(lfsu) }, + { 0x32, GET(lfd) }, + { 0x33, GET(lfdu) }, + { 0x34, GET(stfs) }, + { 0x35, GET(stfsu) }, + { 0x36, GET(stfd) }, + { 0x37, GET(stfdu) }, + }); + // Group 0x04 opcodes (field 21..31) + fillTable(0x04, 11, 0, { + { 0x0, GET(vaddubm) }, + { 0x2, GET(vmaxub) }, + { 0x4, GET(vrlb) }, + { 0x006, GET(vcmpequb) }, + { 0x406, GET(vcmpequb_) }, + { 0x8, GET(vmuloub) }, + { 0xA, GET(vaddfp) }, + { 0xC, GET(vmrghb) }, + { 0xE, GET(vpkuhum) }, + + { 0x20, GET(vmhaddshs), 5 }, + { 0x21, GET(vmhraddshs), 5 }, + { 0x22, GET(vmladduhm), 5 }, + { 0x24, GET(vmsumubm), 5 }, + { 0x25, GET(vmsummbm), 5 }, + { 0x26, GET(vmsumuhm), 5 }, + { 0x27, GET(vmsumuhs), 5 }, + { 0x28, GET(vmsumshm), 5 }, + { 0x29, GET(vmsumshs), 5 }, + { 0x2A, GET(vsel), 5 }, + { 0x2B, GET(vperm), 5 }, + { 0x2C, GET(vsldoi), 5 }, + { 0x2E, GET(vmaddfp), 5 }, + { 0x2F, GET(vnmsubfp), 5 }, + + { 0x40, GET(vadduhm) }, + { 0x42, GET(vmaxuh) }, + { 0x44, GET(vrlh) }, + { 0x046, GET(vcmpequh) }, + { 0x446, GET(vcmpequh_) }, + { 0x48, GET(vmulouh) }, + { 0x4A, GET(vsubfp) }, + { 0x4C, GET(vmrghh) }, + { 0x4E, GET(vpkuwum) }, + { 0x80, GET(vadduwm) }, + { 0x82, GET(vmaxuw) }, + { 0x84, GET(vrlw) }, + { 0x086, GET(vcmpequw) }, + { 0x486, GET(vcmpequw_) }, + { 0x8C, GET(vmrghw) }, + { 0x8E, GET(vpkuhus) }, + { 0x0C6, GET(vcmpeqfp) }, + { 0x4C6, GET(vcmpeqfp_) }, + { 0xCE, GET(vpkuwus) }, + + { 0x102, GET(vmaxsb) }, + { 0x104, GET(vslb) }, + { 0x108, GET(vmulosb) }, + { 0x10A, GET(vrefp) }, + { 0x10C, GET(vmrglb) }, + { 0x10E, GET(vpkshus) }, + { 0x142, GET(vmaxsh) }, + { 0x144, GET(vslh) }, + { 0x148, GET(vmulosh) }, + { 0x14A, GET(vrsqrtefp) }, + { 0x14C, GET(vmrglh) }, + { 0x14E, GET(vpkswus) }, + { 0x180, GET(vaddcuw) }, + { 0x182, GET(vmaxsw) }, + { 0x184, GET(vslw) }, + { 0x18A, GET(vexptefp) }, + { 0x18C, GET(vmrglw) }, + { 0x18E, GET(vpkshss) }, + { 0x1C4, GET(vsl) }, + { 0x1C6, GET(vcmpgefp) }, + { 0x5C6, GET(vcmpgefp_) }, + { 0x1CA, GET(vlogefp) }, + { 0x1CE, GET(vpkswss) }, + { 0x200, GET(vaddubs) }, + { 0x202, GET(vminub) }, + { 0x204, GET(vsrb) }, + { 0x206, GET(vcmpgtub) }, + { 0x606, GET(vcmpgtub_) }, + { 0x208, GET(vmuleub) }, + { 0x20A, GET(vrfin) }, + { 0x20C, GET(vspltb) }, + { 0x20E, GET(vupkhsb) }, + { 0x240, GET(vadduhs) }, + { 0x242, GET(vminuh) }, + { 0x244, GET(vsrh) }, + { 0x246, GET(vcmpgtuh) }, + { 0x646, GET(vcmpgtuh_) }, + { 0x248, GET(vmuleuh) }, + { 0x24A, GET(vrfiz) }, + { 0x24C, GET(vsplth) }, + { 0x24E, GET(vupkhsh) }, + { 0x280, GET(vadduws) }, + { 0x282, GET(vminuw) }, + { 0x284, GET(vsrw) }, + { 0x286, GET(vcmpgtuw) }, + { 0x686, GET(vcmpgtuw_) }, + { 0x28A, GET(vrfip) }, + { 0x28C, GET(vspltw) }, + { 0x28E, GET(vupklsb) }, + { 0x2C4, GET(vsr) }, + { 0x2C6, GET(vcmpgtfp) }, + { 0x6C6, GET(vcmpgtfp_) }, + { 0x2CA, GET(vrfim) }, + { 0x2CE, GET(vupklsh) }, + { 0x300, GET(vaddsbs) }, + { 0x302, GET(vminsb) }, + { 0x304, GET(vsrab) }, + { 0x306, GET(vcmpgtsb) }, + { 0x706, GET(vcmpgtsb_) }, + { 0x308, GET(vmulesb) }, + { 0x30A, GET(vcfux) }, + { 0x30C, GET(vspltisb) }, + { 0x30E, GET(vpkpx) }, + { 0x340, GET(vaddshs) }, + { 0x342, GET(vminsh) }, + { 0x344, GET(vsrah) }, + { 0x346, GET(vcmpgtsh) }, + { 0x746, GET(vcmpgtsh_) }, + { 0x348, GET(vmulesh) }, + { 0x34A, GET(vcfsx) }, + { 0x34C, GET(vspltish) }, + { 0x34E, GET(vupkhpx) }, + { 0x380, GET(vaddsws) }, + { 0x382, GET(vminsw) }, + { 0x384, GET(vsraw) }, + { 0x386, GET(vcmpgtsw) }, + { 0x786, GET(vcmpgtsw_) }, + { 0x38A, GET(vctuxs) }, + { 0x38C, GET(vspltisw) }, + { 0x3C6, GET(vcmpbfp) }, + { 0x7C6, GET(vcmpbfp_) }, + { 0x3CA, GET(vctsxs) }, + { 0x3CE, GET(vupklpx) }, + { 0x400, GET(vsububm) }, + { 0x402, GET(vavgub) }, + { 0x404, GET(vand) }, + { 0x40A, GET(vmaxfp) }, + { 0x40C, GET(vslo) }, + { 0x440, GET(vsubuhm) }, + { 0x442, GET(vavguh) }, + { 0x444, GET(vandc) }, + { 0x44A, GET(vminfp) }, + { 0x44C, GET(vsro) }, + { 0x480, GET(vsubuwm) }, + { 0x482, GET(vavguw) }, + { 0x484, GET(vor) }, + { 0x4C4, GET(vxor) }, + { 0x502, GET(vavgsb) }, + { 0x504, GET(vnor) }, + { 0x542, GET(vavgsh) }, + { 0x580, GET(vsubcuw) }, + { 0x582, GET(vavgsw) }, + { 0x600, GET(vsububs) }, + { 0x604, GET(mfvscr) }, + { 0x608, GET(vsum4ubs) }, + { 0x640, GET(vsubuhs) }, + { 0x644, GET(mtvscr) }, + { 0x648, GET(vsum4shs) }, + { 0x680, GET(vsubuws) }, + { 0x688, GET(vsum2sws) }, + { 0x700, GET(vsubsbs) }, + { 0x708, GET(vsum4sbs) }, + { 0x740, GET(vsubshs) }, + { 0x780, GET(vsubsws) }, + { 0x788, GET(vsumsws) }, + }); + // Group 0x13 opcodes (field 21..30) + fillTable(0x13, 10, 1, { + { 0x000, GET(mcrf) }, + { 0x010, GET(bclr) }, + { 0x012, GET(rfid) }, + { 0x021, GET(crnor) }, + { 0x081, GET(crandc) }, + { 0x096, GET(isync) }, + { 0x0C1, GET(crxor) }, + { 0x0E1, GET(crnand) }, + { 0x101, GET(crand) }, + { 0x121, GET(creqv) }, + { 0x1A1, GET(crorc) }, + { 0x1C1, GET(cror) }, + { 0x210, GET(bcctr) }, + }); + // Group 0x1E opcodes (field 27..30) + fillTable(0x1E, 4, 1, { + { 0x0, GETRC(rldicl) }, + { 0x1, GETRC(rldicl) }, + { 0x2, GETRC(rldicr) }, + { 0x3, GETRC(rldicr) }, + { 0x4, GETRC(rldic) }, + { 0x5, GETRC(rldic) }, + { 0x6, GETRC(rldimi) }, + { 0x7, GETRC(rldimi) }, + { 0x8, GETRC(rldcl) }, + { 0x9, GETRC(rldcr) }, + }); + // Group 0x1F opcodes (field 21..30) + fillTable(0x1F, 10, 1, { + { 0x000, GET(cmp) }, + { 0x004, GET(tw) }, + { 0x006, GET(lvsl) }, + { 0x007, GET(lvebx) }, + { 0x008, GETRC(subfc) }, + { 0x208, GETRC(subfco) }, + { 0x009, GETRC(mulhdu) }, + { 0x00A, GETRC(addc) }, + { 0x20A, GETRC(addco) }, + { 0x00B, GETRC(mulhwu) }, + { 0x013, GET(mfocrf) }, + { 0x014, GET(lwarx) }, + { 0x015, GET(ldx) }, + { 0x017, GET(lwzx) }, + { 0x018, GETRC(slw) }, + { 0x01A, GETRC(cntlzw) }, + { 0x01B, GETRC(sld) }, + { 0x01C, GETRC(and) }, + { 0x020, GET(cmpl) }, + { 0x026, GET(lvsr) }, + { 0x027, GET(lvehx) }, + { 0x028, GETRC(subf) }, + { 0x228, GETRC(subfo) }, + { 0x035, GET(ldux) }, + { 0x036, GET(dcbst) }, + { 0x037, GET(lwzux) }, + { 0x03A, GETRC(cntlzd) }, + { 0x03C, GETRC(andc) }, + { 0x044, GET(td) }, + { 0x047, GET(lvewx) }, + { 0x049, GETRC(mulhd) }, + { 0x04B, GETRC(mulhw) }, + { 0x053, GET(mfmsr) }, + { 0x054, GET(ldarx) }, + { 0x056, GET(dcbf) }, + { 0x057, GET(lbzx) }, + { 0x067, GET(lvx) }, + { 0x068, GETRC(neg) }, + { 0x268, GETRC(nego) }, + { 0x077, GET(lbzux) }, + { 0x07C, GETRC(nor) }, + { 0x087, GET(stvebx) }, + { 0x088, GETRC(subfe) }, + { 0x288, GETRC(subfeo) }, + { 0x08A, GETRC(adde) }, + { 0x28A, GETRC(addeo) }, + { 0x090, GET(mtocrf) }, + { 0x092, GET(mtmsr) }, + { 0x095, GET(stdx) }, + { 0x096, GET(stwcx) }, + { 0x097, GET(stwx) }, + { 0x0A7, GET(stvehx) }, + { 0x0B2, GET(mtmsrd) }, + { 0x0B5, GET(stdux) }, + { 0x0B7, GET(stwux) }, + { 0x0C7, GET(stvewx) }, + { 0x0C8, GETRC(subfze) }, + { 0x2C8, GETRC(subfzeo) }, + { 0x0CA, GETRC(addze) }, + { 0x2CA, GETRC(addzeo) }, + { 0x0D6, GET(stdcx) }, + { 0x0D7, GET(stbx) }, + { 0x0E7, GET(stvx) }, + { 0x0E8, GETRC(subfme) }, + { 0x2E8, GETRC(subfmeo) }, + { 0x0E9, GETRC(mulld) }, + { 0x2E9, GETRC(mulldo) }, + { 0x0EA, GETRC(addme) }, + { 0x2EA, GETRC(addmeo) }, + { 0x0EB, GETRC(mullw) }, + { 0x2EB, GETRC(mullwo) }, + { 0x0F6, GET(dcbtst) }, + { 0x0F7, GET(stbux) }, + { 0x10A, GETRC(add) }, + { 0x30A, GETRC(addo) }, + { 0x116, GET(dcbt) }, + { 0x117, GET(lhzx) }, + { 0x11C, GETRC(eqv) }, + { 0x112, GET(tlbiel) }, + { 0x132, GET(tlbie) }, + { 0x136, GET(eciwx) }, + { 0x137, GET(lhzux) }, + { 0x13C, GETRC(xor) }, + { 0x153, GET(mfspr) }, + { 0x155, GET(lwax) }, + { 0x156, GET(dst) }, + { 0x157, GET(lhax) }, + { 0x167, GET(lvxl) }, + { 0x173, GET(mftb) }, + { 0x175, GET(lwaux) }, + { 0x176, GET(dstst) }, + { 0x177, GET(lhaux) }, + { 0x192, GET(slbmte) }, + { 0x197, GET(sthx) }, + { 0x19C, GET(orc) }, + { 0x1B6, GET(ecowx) }, + { 0x1B7, GET(sthux) }, + { 0x1BC, GETRC(or) }, + { 0x1C9, GETRC(divdu) }, + { 0x3C9, GETRC(divduo) }, + { 0x1CB, GETRC(divwu) }, + { 0x3CB, GETRC(divwuo) }, + { 0x1D3, GET(mtspr) }, + { 0x1D6, GET(dcbi) }, + { 0x1DC, GETRC(nand) }, + { 0x1F2, GET(slbia) }, + { 0x1E7, GET(stvxl) }, + { 0x1E9, GETRC(divd) }, + { 0x3E9, GETRC(divdo) }, + { 0x1EB, GETRC(divw) }, + { 0x3EB, GETRC(divwo) }, + { 0x207, GET(lvlx) }, + { 0x214, GET(ldbrx) }, + { 0x215, GET(lswx) }, + { 0x216, GET(lwbrx) }, + { 0x217, GET(lfsx) }, + { 0x218, GETRC(srw) }, + { 0x21B, GETRC(srd) }, + { 0x227, GET(lvrx) }, + { 0x236, GET(tlbsync) }, + { 0x237, GET(lfsux) }, + { 0x239, GET(mfsrin) }, + { 0x253, GET(mfsr) }, + { 0x255, GET(lswi) }, + { 0x256, GET(sync) }, + { 0x257, GET(lfdx) }, + { 0x277, GET(lfdux) }, + { 0x287, GET(stvlx) }, + { 0x294, GET(stdbrx) }, + { 0x295, GET(stswx) }, + { 0x296, GET(stwbrx) }, + { 0x297, GET(stfsx) }, + { 0x2A7, GET(stvrx) }, + { 0x2B7, GET(stfsux) }, + { 0x2D5, GET(stswi) }, + { 0x2D7, GET(stfdx) }, + { 0x2F7, GET(stfdux) }, + { 0x307, GET(lvlxl) }, + { 0x316, GET(lhbrx) }, + { 0x318, GETRC(sraw) }, + { 0x31A, GETRC(srad) }, + { 0x327, GET(lvrxl) }, + { 0x336, GET(dss) }, + { 0x338, GETRC(srawi) }, + { 0x33A, GETRC(sradi) }, + { 0x33B, GETRC(sradi) }, + { 0x353, GET(slbmfev) }, + { 0x356, GET(eieio) }, + { 0x387, GET(stvlxl) }, + { 0x393, GET(slbmfee) }, + { 0x396, GET(sthbrx) }, + { 0x39A, GETRC(extsh) }, + { 0x3A7, GET(stvrxl) }, + { 0x3BA, GETRC(extsb) }, + { 0x3D7, GET(stfiwx) }, + { 0x3DA, GETRC(extsw) }, + { 0x3D6, GET(icbi) }, + { 0x3F6, GET(dcbz) }, + }); + // Group 0x3A opcodes (field 30..31) + fillTable(0x3A,2, 0, { + { 0x0, GET(ld) }, + { 0x1, GET(ldu) }, + { 0x2, GET(lwa) }, + }); + // Group 0x3B opcodes (field 21..30) + fillTable(0x3B, 10, 1, { + { 0x12, GETRC(fdivs), 5 }, + { 0x14, GETRC(fsubs), 5 }, + { 0x15, GETRC(fadds), 5 }, + { 0x16, GETRC(fsqrts), 5 }, + { 0x18, GETRC(fres), 5 }, + { 0x19, GETRC(fmuls), 5 }, + { 0x1C, GETRC(fmsubs), 5 }, + { 0x1D, GETRC(fmadds), 5 }, + { 0x1E, GETRC(fnmsubs), 5 }, + { 0x1F, GETRC(fnmadds), 5 }, + }); + // Group 0x3E opcodes (field 30..31) + fillTable(0x3E, 2, 0, { + { 0x0, GET(std) }, + { 0x1, GET(stdu) }, + }); + // Group 0x3F opcodes (field 21..30) + fillTable(0x3F, 10, 1, { + { 0x026, GETRC(mtfsb1) }, + { 0x040, GETRC(mcrfs) }, + { 0x046, GETRC(mtfsb0) }, + { 0x086, GETRC(mtfsfi) }, + { 0x247, GETRC(mffs) }, + { 0x2C7, GETRC(mtfsf) }, + + { 0x000, GET(fcmpu) }, + { 0x00C, GETRC(frsp) }, + { 0x00E, GETRC(fctiw) }, + { 0x00F, GETRC(fctiwz) }, + + { 0x012, GETRC(fdiv), 5 }, + { 0x014, GETRC(fsub), 5 }, + { 0x015, GETRC(fadd), 5 }, + { 0x016, GETRC(fsqrt), 5 }, + { 0x017, GETRC(fsel), 5 }, + { 0x019, GETRC(fmul), 5 }, + { 0x01A, GETRC(frsqrte), 5 }, + { 0x01C, GETRC(fmsub), 5 }, + { 0x01D, GETRC(fmadd), 5 }, + { 0x01E, GETRC(fnmsub), 5 }, + { 0x01F, GETRC(fnmadd), 5 }, + + { 0x020, GET(fcmpo) }, + { 0x028, GETRC(fneg) }, + { 0x048, GETRC(fmr) }, + { 0x088, GETRC(fnabs) }, + { 0x108, GETRC(fabs) }, + { 0x32E, GETRC(fctid) }, + { 0x32F, GETRC(fctidz) }, + { 0x34E, GETRC(fcfid) }, + }); + } + std::string legacy_GetOpcodeName(u32 instrData) { + u32 OPCD = ExtractBits(instrData, 0, 5); + + u32 XO_20to30 = ExtractBits(instrData, 20, 30); + u32 XO_27to29 = ExtractBits(instrData, 27, 29); + u32 XO_27to30 = ExtractBits(instrData, 27, 30); + u32 XO_21to30 = ExtractBits(instrData, 21, 30); + u32 XO_22to30 = ExtractBits(instrData, 22, 30); + u32 XO_21to29 = ExtractBits(instrData, 21, 29); + u32 XO_30to31 = ExtractBits(instrData, 30, 31); + + switch (OPCD) { + case 2: // tdi + return "tdi"; + break; + case 3: // twi + return "twi"; + break; + case 7: // mulli + return "mulli"; + break; + case 8: // subfic + return "subfic"; + break; + case 10: // cmpli + return "cmpli"; + break; + case 11: // cmpi + return "cmpi"; + break; + case 12: // addic + return "addic"; + break; + case 13: // addic. + return "addicx"; + break; + case 14: // addi + return "addi"; + break; + case 15: // addis + return "addis"; + break; + case 16: // bcx + return "bcx"; + break; + case 17: // sc + return "sc"; + break; + case 18: // bx + return "bx"; + break; + case 19: /* Subgroup 19 */ + switch (XO_20to30) { + case 0: // mcrf + return "mcrf"; + break; + case 16: // bclrx + return "bclrx"; + break; + case 18: // rfid + return "rfid"; + break; + case 33: // crnor + return "crnor"; + break; + case 129: // crandc + return "crandc"; + break; + case 150: // isync + return "isync"; + break; + case 193: // crxor + return "crxor"; + break; + case 225: // crnand + return "crnand"; + break; + case 257: // crand + return "crand"; + break; + case 289: // creqv + return "creqv"; + break; + case 417: // crorc + return "crorc"; + break; + case 449: // cror + return "cror"; + break; + case 528: // bcctrx + return "bcctrx"; + break; + } + return "Unknown instruction"; + break; + case 20: // rlwimix + return "rlwimix"; + break; + case 21: // rlwinmx + return "rlwinmx"; + break; + case 23: // rlwnmx + return "rlwnmx"; + break; + case 24: // ori + return "ori"; + break; + case 25: // oris + return "oris"; + break; + case 26: // xori + return "xori"; + break; + case 27: // xoris + return "xoris"; + break; + case 28: // andi. + return "andix"; + break; + case 29: // andis. + return "andisx"; + break; + case 30: /* Subgroup 30 */ + switch (XO_27to29) { + case 0: // rldiclx + return "rldiclx"; + break; + case 1: // rldicrx + return "rldicrx"; + break; + case 2: // rldicx + return "rldicx"; + break; + case 3: // rldimix + return "rldimix"; + break; + } + switch (XO_27to30) { + case 8: // rldclx + return "rldclx"; + break; + case 9: // rldcrx + return "rldcrx"; + break; + } + return "Unknown instruction"; + break; + case 31: /* Subgroup 31 */ + switch (XO_21to30) { + case 0: // cmp + return "cmp"; + break; + case 4: // tw + return "tw"; + break; + case 19: // mfcr + return "mfcr"; + break; + case 20: // lwarx + return "lwarx"; + break; + case 21: // ldx + return "ldx"; + break; + case 23: // lwzx + return "lwzx"; + break; + case 24: // slwx + return "slwx"; + break; + case 26: // cntlzwx + return "cntlzwx"; + break; + case 27: // sldx + return "sldx"; + break; + case 28: // andx + return "andx"; + break; + case 32: // cmpl + return "cmpl"; + break; + case 53: // ldux + return "ldux"; + break; + case 54: // dcbst + return "dcbst"; + break; + case 55: // lwzux + return "lwzux"; + break; + case 58: // cntlzdx + return "cntlzdx"; + break; + case 60: // andcx + return "andcx"; + break; + case 68: // td + return "td"; + break; + case 83: // mfmsr + return "mfmsr"; + break; + case 84: // ldarx + return "ldarx"; + break; + case 86: // dcbf + return "dcbf"; + break; + case 87: // lbzx + return "lbzx"; + break; + case 119: // lbzux + return "lbzux"; + break; + case 124: // norx + return "norx"; + break; + case 144: // mtcrf + return "mtcrf"; + break; + case 146: // mtmsr + return "mtmsr"; + break; + case 149: // stdx + return "stdx"; + break; + case 150: // stwcx. + return "stwcx"; + break; + case 151: // stwx + return "stwx"; + break; + case 178: // mtmsrd + return "mtmsrd"; + break; + case 181: // stdux + return "stdux"; + break; + case 183: // stwux + return "stwux"; + break; + case 210: // mtsr + return "mtsr"; + break; + case 214: // stdcx. + return "stdcx"; + break; + case 215: // stbx + return "stbx"; + break; + case 242: // mtsrin + return "mtsrin"; + break; + case 247: // stbux + return "stbux"; + break; + case 246: // dcbt + return "dcbt"; + break; + case 278: // dcbt + return "dcbt"; + break; + case 279: // lhzx + return "lhzx"; + break; + case 284: // eqvx + return "eqvx"; + break; + case 274: // tlbiel + return "tlbiel"; + break; + case 306: // tlbie + return "tlbie"; + break; + case 310: // eciwx + return "eciwx"; + break; + case 311: // lhzux + return "lhzux"; + break; + case 316: // xorx + return "xorx"; + break; + case 339: // mfspr + return "mfspr"; + break; + case 341: // lwax + return "lwax"; + break; + case 343: // lhax + return "lhax"; + break; + case 370: // tlbia + return "tlbia"; + break; + case 371: // mftb + return "mftb"; + break; + case 373: // lwaux + return "lwaux"; + break; + case 375: // lhaux + return "lhaux"; + break; + case 407: // sthx + return "sthx"; + break; + case 412: // orcx + return "orcx"; + break; + case 434: // slbie + return "slbie"; + break; + case 438: // ecowx + return "ecowx"; + break; + case 439: // sthux + return "sthux"; + break; + case 444: // orx + return "orx"; + break; + case 467: // mtspr + return "mtspr"; + break; + case 476: // nandx + return "nandx"; + break; + case 498: // slbia + return "slbia"; + break; + case 533: // lswx + return "lswx"; + break; + case 534: // lwbrx + return "lwbrx"; + break; + case 535: // lfsx + return "lfsx"; + break; + case 536: // srwx + return "srwx"; + break; + case 539: // srdx + return "srdx"; + break; + case 566: // tlbsync + return "tlbsync"; + break; + case 567: // lfsux + return "lfsux"; + break; + case 595: // mfsr + return "mfsr"; + break; + case 597: // lswi + return "lswi"; + break; + case 598: // sync + return "sync"; + break; + case 599: // lfdx + return "lfdx"; + break; + case 631: // lfdux + return "lfdux"; + break; + case 569: // mfsrin + return "mfsrin"; + break; + case 915: // slbmfee + return "slbmfee"; + break; + case 851: // slbmfev + return "slbmfev"; + break; + case 402: // slbmte + return "slbmte"; + break; + case 661: // stswx + return "stswx"; + break; + case 662: // stwbrx + return "stwbrx"; + break; + case 663: // stfsx + return "stfsx"; + break; + case 695: // stfsux + return "stfsux"; + break; + case 725: // stswi + return "stswi"; + break; + case 727: // stfdx + return "stfdx"; + break; + case 759: // stfdux + return "stfdux"; + break; + case 790: // lhbrx + return "lhbrx"; + break; + case 762: // srawx + return "srawx"; + break; + case 794: // sradx + return "sradx"; + break; + case 824: // srawix + return "srawix"; + break; + case 854: // eieio + return "eieio"; + break; + case 918: // sthbrx + return "sthbrx"; + break; + case 922: // extshx + return "extshx"; + break; + case 954: // extsbx + return "extsbx"; + break; + case 982: // icbi + return "icbi"; + break; + case 983: // stfiwx + return "stfiwx"; + break; + case 986: // extswx + return "extswx"; + break; + case 1014: // dcbz + return "dcbz"; + break; + } + switch (XO_22to30) { + case 8: // subfcx + return "subfcx"; + break; + case 9: // mulhdux + return "mulhdux"; + break; + case 10: // addcx + return "addcx"; + break; + case 11: // mulhwux + return "mulhwux"; + break; + case 40: // subfx + return "subfx"; + break; + case 73: // mulhdx + return "mulhdx"; + break; + case 75: // mulhwx + return "mulhwx"; + break; + case 104: // negx + return "negx"; + break; + case 136: // subfex + return "subfex"; + break; + case 138: // addex + return "addex"; + break; + case 200: // subfzex + return "subfzex"; + break; + case 202: // addzex + return "addzex"; + break; + case 232: // subfmex + return "subfmex"; + break; + case 233: // mulldx + return "mulldx"; + break; + case 234: // addmex + return "addmex"; + break; + case 235: // mullwx + return "mullwx"; + break; + case 266: // addx + return "addx"; + break; + case 457: // divdux + return "divdux"; + break; + case 459: // divwux + return "divwux"; + break; + case 489: // divdx + return "divdx"; + break; + case 491: // divwx + return "divwx"; + break; + } + switch (XO_21to29) { + case 413: // sradix + return "sradix"; + break; + } + return "Unknown instruction"; + break; + case 32: // lwz + return "lwz"; + break; + case 33: // lwzu + return "lwzu"; + break; + case 34: // lbz + return "lbz"; + break; + case 35: // lbzu + return "lbzu"; + break; + case 36: // stw + return "stw"; + break; + case 37: // stwu + return "stwu"; + break; + case 38: // stb + return "stb"; + break; + case 39: // stbu + return "stbu"; + break; + case 40: // lhz + return "lhz"; + break; + case 41: // lhzu + return "lhzu"; + break; + case 44: // sth + return "sth"; + break; + case 48: // lfs + return "lfs"; + break; + case 58: + switch (XO_30to31) { + case 0: // ld + return "ld"; + break; + case 1: // ldu + return "ldu"; + break; + default: + return "Unknown instruction"; + break; + } + case 62: + switch (XO_30to31) { + case 0: // std + return "std"; + break; + case 1: // stdu + return "stdu"; + break; + default: + return "Unknown instruction"; + break; + } default: - return "INVALID"; + return "Unknown instruction"; break; } - default: - return "INVALID"; - break; - } -} + }} \ No newline at end of file diff --git a/Xenon/Core/XCPU/Interpreter/PPC_Instruction.h b/Xenon/Core/XCPU/Interpreter/PPC_Instruction.h index bca687b..cdda578 100644 --- a/Xenon/Core/XCPU/Interpreter/PPC_Instruction.h +++ b/Xenon/Core/XCPU/Interpreter/PPC_Instruction.h @@ -1,253 +1,88 @@ -// Copyright 2025 Xenon Emulator Project - #pragma once +/* +* Copyright 2025 Xenon Emulator Project + +* All original authors of the rpcs3 PPU_Decoder and PPU_Opcodes maintain their original copyright. +* Modifed for usage in the Xenon Emulator +* All rights reserved +* License: GPL2 +*/ +#include #include #include "Base/Types.h" +#include "Base/Logging/Log.h" +#include "Core/XCPU/Bitfield.h" +#include "Core/XCPU/PPU/PowerPC.h" -// -// PowerPC Instruction definitions -// +constexpr u64 PPCRotateMask(u32 mb, u32 me) { + const u64 mask = ~0ull << (~(me - mb) & 63); + return (mask >> (mb & 63)) | (mask << ((64 - mb) & 63)); +} -enum class PPCInstruction { - invalidInstruction, - addcx, - addex, - addi, - addic, - addicx, - addis, - addmex, - addx, - addzex, - andcx, - andix, - andisx, - andx, - bcctrx, - bclrx, - bcx, - bx, - cmp, - cmpi, - cmpl, - cmpli, - cntlzdx, - cntlzwx, - crand, - crandc, - creqv, - crnand, - crnor, - cror, - crorc, - crxor, - dcbf, - dcbi, - dcbst, - dcbt, - dcbtst, - dcbz, - divdux, - divdx, - divwux, - divwx, - eciwx, - ecowx, - eieio, - eqvx, - extsbx, - extshx, - extswx, - fabsx, - faddsx, - faddx, - fcfidx, - fcmpo, - fcmpu, - fctidx, - fctidzx, - fctiwx, - fctiwzx, - fdivsx, - fdivx, - fmaddsx, - fmaddx, - fmrx, - fmsubsx, - fmsubx, - fmulsx, - fmulx, - fnabsx, - fnegx, - fnmaddsx, - fnmaddx, - fnmsubsx, - fnmsubx, - fresx, - frspx, - frsqrtex, - fselx, - fsqrtsx, - fsqrtx, - fsubsx, - fsubx, - icbi, - isync, - lbz, - lbzu, - lbzux, - lbzx, - ld, - ldarx, - ldbrx, - ldu, - ldux, - ldx, - lfd, - lfdu, - lfdux, - lfdx, - lfs, - lfsu, - lfsux, - lfsx, - lha, - lhau, - lhaux, - lhax, - lhbrx, - lhz, - lhzu, - lhzux, - lhzx, - lmw, - lswi, - lswx, - lwa, - lwarx, - lwaux, - lwax, - lwbrx, - lwz, - lwzu, - lwzux, - lwzx, - mcrf, - mcrfs, - mcrxr, - mfcr, - mffsx, - mfmsr, - mfocrf, - mfspr, - mfsr, - mfsrin, - mftb, - mtcrf, - mtfsb0x, - mtfsb1x, - mtfsfix, - mtfsfx, - mtmsr, - mtmsrd, - mtocrf, - mtspr, - mtsr, - mtsrin, - mulhdux, - mulhdx, - mulhwux, - mulhwx, - mulldx, - mulli, - mullwx, - nandx, - negx, - norx, - orcx, - ori, - oris, - orx, - rfid, - rldclx, - rldcrx, - rldiclx, - rldicrx, - rldicx, - rldimix, - rlwimix, - rlwinmx, - rlwnmx, - sc, - slbia, - slbie, - slbmfee, - slbmfev, - slbmte, - sldx, - slwx, - sradix, - sradx, - srawix, - srawx, - srdx, - srwx, - stb, - stbu, - stbux, - stbx, - std, - stdcx, - stdu, - stdux, - stdx, - stfd, - stdbrx, - stfdu, - stfdux, - stfdx, - stfiwx, - stfs, - stfsu, - stfsux, - stfsx, - sth, - sthbrx, - sthu, - sthux, - sthx, - stmw, - stswi, - stswx, - stw, - stwbrx, - stwcx, - stwu, - stwux, - stwx, - subfcx, - subfex, - subfic, - subfmex, - subfx, - subfzex, - sync, - td, - tdi, - tlbia, - tlbie, - tlbiel, - tlbsync, - tw, - twi, - xori, - xoris, - xorx -}; +constexpr u32 PPCDecode(u32 inst) { + return ((inst >> 26) | (inst << 6)) & 0x1FFFF; // Rotate + mask +} namespace PPCInterpreter { -PPCInstruction getOpcode(u32 instrData); -std::string getOpcodeName(u32 instrData); + // Define a type alias for function pointers + using instructionHandler = void(*)(PPU_STATE*); + extern void PPCInterpreter_nop(PPU_STATE *hCore); + extern void PPCInterpreter_invalid(PPU_STATE *hCore); + extern void PPCInterpreter_known_unimplemented(const char *name, PPU_STATE *hCore); + class PPCDecoder { + class InstrInfo { + public: + constexpr InstrInfo(u32 v, instructionHandler p, instructionHandler pRc, u32 m = 0) : + value(v), ptr0(p), ptrRc(pRc), magn(m) + {} + + constexpr InstrInfo(u32 v, const instructionHandler* p, const instructionHandler* pRc, u32 m = 0) : + value(v), ptr0(*p), ptrRc(*pRc), magn(m) + {} + + u32 value; + instructionHandler ptr0; + instructionHandler ptrRc; + u32 magn; // Non-zero for "columns" (effectively, number of most significant bits "eaten") + }; + public: + PPCDecoder(); + ~PPCDecoder() = default; + const std::array& getTable() const noexcept { + return table; + } + instructionHandler decode(u32 inst) const noexcept { + if (inst == 0x60000000) { + return &PPCInterpreter_nop; + } + return table[PPCDecode(inst)]; + } + private: + // Fast lookup table + std::array table; + + void fillTable(u32 mainOp, u32 count, u32 sh, std::initializer_list entries) noexcept { + 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++) { + const u32 k = (((i << (count - v.magn)) | v.value) << sh) | j; + c_at(table, (k << 6) | mainOp) = k & 1 ? v.ptrRc : v.ptr0; + } + } + } + } + else { + // Main table (special case) + for (const auto& v : entries) { + for (u32 i = 0; i < 1u << 11; i++) { + c_at(table, i << 6 | v.value) = i & 1 ? v.ptrRc : v.ptr0; + } + } + } + } + }; + std::string legacy_GetOpcodeName(u32 instrData); } // namespace PPCInterpreter diff --git a/Xenon/Core/XCPU/Interpreter/PPC_LS.cpp b/Xenon/Core/XCPU/Interpreter/PPC_LS.cpp index 8046b4e..b3c0303 100644 --- a/Xenon/Core/XCPU/Interpreter/PPC_LS.cpp +++ b/Xenon/Core/XCPU/Interpreter/PPC_LS.cpp @@ -8,6 +8,7 @@ // Store Byte // +#include #define DBG_LOAD(x) // std::cout << x void PPCInterpreter::PPCInterpreter_dcbst(PPU_STATE *hCore) { @@ -740,6 +741,24 @@ void PPCInterpreter::PPCInterpreter_ld(PPU_STATE *hCore) { hCore->ppuThread[hCore->currentThread].GPR[rD] = data; } +void PPCInterpreter::PPCInterpreter_ldbrx(PPU_STATE *hCore) { + X_FORM_rD_rA_rB; + + u64 EA = (rA ? hCore->ppuThread[hCore->currentThread].GPR[rA] : 0) + + hCore->ppuThread[hCore->currentThread].GPR[rB]; + + u64 RA = EA & ~7; + + u64 data = MMURead64(hCore, EA); + + if (hCore->ppuThread[hCore->currentThread].exceptReg & PPU_EX_DATASEGM || + hCore->ppuThread[hCore->currentThread].exceptReg & PPU_EX_DATASTOR) + return; + + DBG_LOAD("ldbrx: Addr 0x" << std::hex << EA << " data = 0x" << std::hex << (int)data << std::endl;) + hCore->ppuThread[hCore->currentThread].GPR[rD] = data; +} + void PPCInterpreter::PPCInterpreter_ldarx(PPU_STATE *hCore) { X_FORM_rD_rA_rB; @@ -762,7 +781,7 @@ void PPCInterpreter::PPCInterpreter_ldarx(PPU_STATE *hCore) { if (hCore->ppuThread[hCore->currentThread].exceptReg & PPU_EX_DATASEGM || hCore->ppuThread[hCore->currentThread].exceptReg & PPU_EX_DATASTOR) return; - DBG_LOAD("ldarx: Addr 0x" << EA << " data = 0x" << data << std::endl;) + DBG_LOAD("ldarx:Addr 0x" << std::hex << EA << " data = 0x" << std::hex << (int)data << std::endl;) hCore->ppuThread[hCore->currentThread].GPR[rD] = data; } diff --git a/Xenon/Core/XCPU/Interpreter/PPC_System.cpp b/Xenon/Core/XCPU/Interpreter/PPC_System.cpp index 9521f09..b90ff62 100644 --- a/Xenon/Core/XCPU/Interpreter/PPC_System.cpp +++ b/Xenon/Core/XCPU/Interpreter/PPC_System.cpp @@ -194,8 +194,8 @@ void PPCInterpreter::PPCInterpreter_tdi(PPU_STATE *hCore) { void PPCInterpreter::PPCInterpreter_mfspr(PPU_STATE *hCore) { u64 rS, crm = 0; - PPC_OPC_TEMPL_XFX(hCore->ppuThread[hCore->currentThread].CI, rS, crm); - u32 sprNum = ExtractBits(hCore->ppuThread[hCore->currentThread].CI, 11, 20); + PPC_OPC_TEMPL_XFX(hCore->ppuThread[hCore->currentThread].CI.opcode, rS, crm); + u32 sprNum = hCore->ppuThread[hCore->currentThread].CI.spr; sprNum = ((sprNum & 0x1f) << 5) | ((sprNum >> 5) & 0x1F); u64 value = 0; diff --git a/Xenon/Core/XCPU/PPU/PPU.cpp b/Xenon/Core/XCPU/PPU/PPU.cpp index 7e7d4a4..42b9b69 100644 --- a/Xenon/Core/XCPU/PPU/PPU.cpp +++ b/Xenon/Core/XCPU/PPU/PPU.cpp @@ -278,7 +278,7 @@ bool PPU::ppuReadNextInstruction() { ppuState->ppuThread[ppuState->currentThread].NIA += 4; ppuState->ppuThread[ppuState->currentThread].iFetch = true; // Fetch the instruction from memory. - ppuState->ppuThread[ppuState->currentThread].CI = PPCInterpreter::MMURead32( + ppuState->ppuThread[ppuState->currentThread].CI.opcode = PPCInterpreter::MMURead32( ppuState, ppuState->ppuThread[ppuState->currentThread].CIA); if (ppuState->ppuThread[ppuState->currentThread].exceptReg & PPU_EX_INSSTOR || ppuState->ppuThread[ppuState->currentThread].exceptReg & diff --git a/Xenon/Core/XCPU/PPU/PowerPC.h b/Xenon/Core/XCPU/PPU/PowerPC.h index 5efc9de..791cc4f 100644 --- a/Xenon/Core/XCPU/PPU/PowerPC.h +++ b/Xenon/Core/XCPU/PPU/PowerPC.h @@ -2,10 +2,75 @@ #pragma once -#include "Core/XCPU/IIC/IIC.h" +#include "Core/XCPU/IIC/IIC.h" +#include "Core/XCPU/Bitfield.h" #include "Core/XCPU/XenonReservations.h" #include "Core/XCPU/eFuse.h" +// PowerPC Opcode definitions +/* +* All original authors of the rpcs3 PPU_Decoder and PPU_Opcodes maintain their original copyright. +* Modifed for usage in the Xenon Emulator +* All rights reserved +* License: GPL2 +*/ +template +using PPCBitfield = bitfield; +union PPCOpcode { + u32 opcode; + PPCBitfield main; // 0..5 + ControlField, PPCBitfield> sh64; // 30 + 16..20 + ControlField, PPCBitfield> mbe64; // 26 + 21..25 + PPCBitfield vuimm; // 11..15 + PPCBitfield vs; // 6..10 + PPCBitfield vsh; // 22..25 + PPCBitfield oe; // 21 + PPCBitfield spr; // 11..20 + PPCBitfield vc; // 21..25 + PPCBitfield vb; // 16..20 + PPCBitfield va; // 11..15 + PPCBitfield vd; // 6..10 + PPCBitfield lk; // 31 + PPCBitfield aa; // 30 + PPCBitfield rb; // 16..20 + PPCBitfield ra; // 11..15 + PPCBitfield rd; // 6..10 + PPCBitfield uimm16; // 16..31 + PPCBitfield l11; // 11 + PPCBitfield rs; // 6..10 + PPCBitfield simm16; // 16..31, signed + PPCBitfield ds; // 16..29, signed + PPCBitfield vsimm; // 11..15, signed + PPCBitfield ll; // 6..31, signed + PPCBitfield li; // 6..29, signed + PPCBitfield lev; // 20..26 + PPCBitfield i; // 16..19 + PPCBitfield crfs; // 11..13 + PPCBitfield l10; // 10 + PPCBitfield crfd; // 6..8 + PPCBitfield crbb; // 16..20 + PPCBitfield crba; // 11..15 + PPCBitfield crbd; // 6..10 + PPCBitfield rc; // 31 + PPCBitfield me32; // 26..30 + PPCBitfield mb32; // 21..25 + PPCBitfield sh32; // 16..20 + PPCBitfield bi; // 11..15 + PPCBitfield bo; // 6..10 + PPCBitfield bh; // 19..20 + PPCBitfield frc; // 21..25 + PPCBitfield frb; // 16..20 + PPCBitfield fra; // 11..15 + PPCBitfield frd; // 6..10 + PPCBitfield crm; // 12..19 + PPCBitfield frs; // 6..10 + PPCBitfield flm; // 7..14 + PPCBitfield l6; // 6 + PPCBitfield l15; // 15 + ControlField, FixedField> bt14; + ControlField, FixedField> bt24; +}; + // // PowerPC Register definitions // @@ -401,7 +466,7 @@ struct PPU_THREAD_REGISTERS { // Next Instruction Address u64 NIA; // Current instruction data - u32 CI; + PPCOpcode CI; // Instruction fetch flag bool iFetch = false; // General-Purpose Registers (32) diff --git a/Xenon/Xe_Main.cpp b/Xenon/Xe_Main.cpp index 2ad701d..431bc4f 100644 --- a/Xenon/Xe_Main.cpp +++ b/Xenon/Xe_Main.cpp @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) { #endif // Display Version on Boot. - LOG_INFO(System, "Starting Xenon emulator {}", std::string(Base::VERSION)); + LOG_INFO(System, "Starting Xenon {}", std::string(Base::VERSION)); // Load configuration. const auto user_dir = Base::FS::GetUserPath(Base::FS::PathType::UserDir);