diff --git a/CMakeLists.txt b/CMakeLists.txt index b00647a..2da5e35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,14 @@ endif() set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") +include(FetchContent) +FetchContent_Declare( + tomlplusplus + GIT_REPOSITORY https://github.com/marzer/tomlplusplus.git + GIT_TAG v3.4.0 +) +FetchContent_MakeAvailable(tomlplusplus) + add_subdirectory(${THIRDPARTY_ROOT}/disasm) project ("PowerRecomp-ALL") diff --git a/PowerRecomp/CMakeLists.txt b/PowerRecomp/CMakeLists.txt index f80739b..638e0d1 100644 --- a/PowerRecomp/CMakeLists.txt +++ b/PowerRecomp/CMakeLists.txt @@ -3,4 +3,4 @@ cmake_minimum_required (VERSION 3.8) project("PowerRecomp") add_executable(PowerRecomp "main.cpp") -target_link_libraries(PowerRecomp PRIVATE LibPowerAnalyse) +target_link_libraries(PowerRecomp PRIVATE LibPowerAnalyse tomlplusplus::tomlplusplus) diff --git a/PowerRecomp/main.cpp b/PowerRecomp/main.cpp index 72d28d1..e1154cb 100644 --- a/PowerRecomp/main.cpp +++ b/PowerRecomp/main.cpp @@ -7,8 +7,10 @@ #include #include #include +#include +#include -#define TEST_FILE "default.xex" +#define TEST_FILE "private/default.xex" static uint64_t computeMask(uint32_t mstart, uint32_t mstop) { @@ -23,6 +25,29 @@ int main() const auto file = LoadFile(TEST_FILE).value(); auto image = Image::ParseImage(file.data(), file.size()).value(); + std::println("Loading switch tables..."); + + struct SwitchTable + { + size_t r; + std::vector labels; + }; + + std::unordered_map switchTables; + + toml::table toml = toml::parse_file("out/switches.toml"); + for (auto& entry : *toml["switch"].as_array()) + { + auto& table = *entry.as_table(); + + SwitchTable switchTable; + switchTable.r = *table["r"].value(); + for (auto& array : *table["labels"].as_array()) + switchTable.labels.push_back(*array.value()); + + switchTables.emplace(*table["base"].value(), std::move(switchTable)); + } + std::println("Analysing functions..."); uint32_t cxxFrameHandler = std::byteswap(0x831B1C90); @@ -142,11 +167,16 @@ int main() println("\tPPCRegister temp;"); println("\tuint32_t ea;\n"); + auto switchTable = switchTables.end(); + ppc_insn insn; while (base < end) { println("loc_{:X}:", base); + if (switchTable == switchTables.end()) + switchTable = switchTables.find(base); + ppc::Disassemble(data, 4, base, insn); base += 4; @@ -264,8 +294,23 @@ int main() break; case PPC_INST_BCTR: - println("\tctx.fn[ctx.ctr / 4](ctx, base);"); - println("\treturn;"); + if (switchTable != switchTables.end()) + { + println("\tswitch (ctx.r{}.u64) {{", switchTable->second.r); + + for (size_t i = 0; i < switchTable->second.labels.size(); i++) + println("\t\tcase {}: goto loc_{:X};", i, switchTable->second.labels[i]); + + println("\t\tdefault: __unreachable();"); + println("\t}}"); + + switchTable = switchTables.end(); + } + else + { + println("\tctx.fn[ctx.ctr / 4](ctx, base);"); + println("\treturn;"); + } break; case PPC_INST_BCTRL: diff --git a/PowerUtils/ppc_context.h b/PowerUtils/ppc_context.h index aebfdbb..966eccb 100644 --- a/PowerUtils/ppc_context.h +++ b/PowerUtils/ppc_context.h @@ -12,10 +12,12 @@ #define _byteswap_uint64 __builtin_bswap64 #define isnan __builtin_isnan #define __assume __builtin_assume +#define __unreachable() __builtin_unreachable() #define PPC_FUNC __attribute__((weak,noinline)) #else #include #define PPC_FUNC __declspec(noinline) +#define __unreachable() __assume(0) #endif #define PPC_LOAD_U8(x) *(uint8_t*)(base + (x))