diff --git a/PowerRecomp/recompiler.cpp b/PowerRecomp/recompiler.cpp index 0c3af75..ebf0375 100644 --- a/PowerRecomp/recompiler.cpp +++ b/PowerRecomp/recompiler.cpp @@ -158,6 +158,7 @@ bool Recompiler::Recompile( const Function& fn, uint32_t base, const ppc_insn& insn, + const uint32_t* data, std::unordered_map::iterator& switchTable, RecompilerLocalVariables& localVariables, CSRState& csrState) @@ -262,6 +263,12 @@ bool Recompiler::Recompile( return "ea"; }; + // TODO (Sajid): Check for out of bounds access + auto mmioStore = [&]() -> bool + { + return *(data + 1) == c_eieio; + }; + auto printFunctionCall = [&](uint32_t address) { if (address == config.longJmpAddress) @@ -1362,7 +1369,7 @@ bool Recompiler::Recompile( break; case PPC_INST_STB: - print("\tPPC_STORE_U8("); + print("{}", mmioStore() ? "\tPPC_MM_STORE_U8(" : "\tPPC_STORE_U8("); if (insn.operands[2] != 0) print("{}.u32 + ", r(insn.operands[2])); println("{}, {}.u8);", int32_t(insn.operands[1]), r(insn.operands[0])); @@ -1375,14 +1382,14 @@ bool Recompiler::Recompile( break; case PPC_INST_STBX: - print("\tPPC_STORE_U8("); + print("{}", mmioStore() ? "\tPPC_MM_STORE_U8(" : "\tPPC_STORE_U8("); if (insn.operands[1] != 0) print("{}.u32 + ", r(insn.operands[1])); println("{}.u32, {}.u8);", r(insn.operands[2]), r(insn.operands[0])); break; case PPC_INST_STD: - print("\tPPC_STORE_U64("); + print("{}", mmioStore() ? "\tPPC_MM_STORE_U64(" : "\tPPC_STORE_U64("); if (insn.operands[2] != 0) print("{}.u32 + ", r(insn.operands[2])); println("{}, {}.u64);", int32_t(insn.operands[1]), r(insn.operands[0])); @@ -1405,7 +1412,7 @@ bool Recompiler::Recompile( break; case PPC_INST_STDX: - print("\tPPC_STORE_U64("); + print("{}", mmioStore() ? "\tPPC_MM_STORE_U64(" : "\tPPC_STORE_U64("); if (insn.operands[1] != 0) print("{}.u32 + ", r(insn.operands[1])); println("{}.u32, {}.u64);", r(insn.operands[2]), r(insn.operands[0])); @@ -1413,7 +1420,7 @@ bool Recompiler::Recompile( case PPC_INST_STFD: printSetFlushMode(false); - print("\tPPC_STORE_U64("); + print("{}", mmioStore() ? "\tPPC_MM_STORE_U64(" : "\tPPC_STORE_U64("); if (insn.operands[2] != 0) print("{}.u32 + ", r(insn.operands[2])); println("{}, {}.u64);", int32_t(insn.operands[1]), f(insn.operands[0])); @@ -1421,7 +1428,7 @@ bool Recompiler::Recompile( case PPC_INST_STFDX: printSetFlushMode(false); - print("\tPPC_STORE_U64("); + print("{}", mmioStore() ? "\tPPC_MM_STORE_U64(" : "\tPPC_STORE_U64("); if (insn.operands[1] != 0) print("{}.u32 + ", r(insn.operands[1])); println("{}.u32, {}.u64);", r(insn.operands[2]), f(insn.operands[0])); @@ -1429,7 +1436,7 @@ bool Recompiler::Recompile( case PPC_INST_STFIWX: printSetFlushMode(false); - print("\tPPC_STORE_U32("); + print("{}", mmioStore() ? "\tPPC_MM_STORE_U32(" : "\tPPC_STORE_U32("); if (insn.operands[1] != 0) print("{}.u32 + ", r(insn.operands[1])); println("{}.u32, {}.u32);", r(insn.operands[2]), f(insn.operands[0])); @@ -1438,7 +1445,7 @@ bool Recompiler::Recompile( case PPC_INST_STFS: printSetFlushMode(false); println("\t{}.f32 = float({}.f64);", temp(), f(insn.operands[0])); - print("\tPPC_STORE_U32("); + print("{}", mmioStore() ? "\tPPC_MM_STORE_U32(" : "\tPPC_STORE_U32("); if (insn.operands[2] != 0) print("{}.u32 + ", r(insn.operands[2])); println("{}, {}.u32);", int32_t(insn.operands[1]), temp()); @@ -1447,28 +1454,28 @@ bool Recompiler::Recompile( case PPC_INST_STFSX: printSetFlushMode(false); println("\t{}.f32 = float({}.f64);", temp(), f(insn.operands[0])); - print("\tPPC_STORE_U32("); + print("{}", mmioStore() ? "\tPPC_MM_STORE_U32(" : "\tPPC_STORE_U32("); if (insn.operands[1] != 0) print("{}.u32 + ", r(insn.operands[1])); println("{}.u32, {}.u32);", r(insn.operands[2]), temp()); break; case PPC_INST_STH: - print("\tPPC_STORE_U16("); + print("{}", mmioStore() ? "\tPPC_MM_STORE_U16(" : "\tPPC_STORE_U16("); if (insn.operands[2] != 0) print("{}.u32 + ", r(insn.operands[2])); println("{}, {}.u16);", int32_t(insn.operands[1]), r(insn.operands[0])); break; case PPC_INST_STHBRX: - print("\tPPC_STORE_U16("); + print("{}", mmioStore() ? "\tPPC_MM_STORE_U16(" : "\tPPC_STORE_U16("); if (insn.operands[1] != 0) print("{}.u32 + ", r(insn.operands[1])); println("{}.u32, __builtin_bswap16({}.u16));", r(insn.operands[2]), r(insn.operands[0])); break; case PPC_INST_STHX: - print("\tPPC_STORE_U16("); + print("{}", mmioStore() ? "\tPPC_MM_STORE_U16(" : "\tPPC_STORE_U16("); if (insn.operands[1] != 0) print("{}.u32 + ", r(insn.operands[1])); println("{}.u32, {}.u16);", r(insn.operands[2]), r(insn.operands[0])); @@ -1530,14 +1537,14 @@ bool Recompiler::Recompile( break; case PPC_INST_STW: - print("\tPPC_STORE_U32("); + print("{}", mmioStore() ? "\tPPC_MM_STORE_U32(" : "\tPPC_STORE_U32("); if (insn.operands[2] != 0) print("{}.u32 + ", r(insn.operands[2])); println("{}, {}.u32);", int32_t(insn.operands[1]), r(insn.operands[0])); break; case PPC_INST_STWBRX: - print("\tPPC_STORE_U32("); + print("{}", mmioStore() ? "\tPPC_MM_STORE_U32(" : "\tPPC_STORE_U32("); if (insn.operands[1] != 0) print("{}.u32 + ", r(insn.operands[1])); println("{}.u32, __builtin_bswap32({}.u32));", r(insn.operands[2]), r(insn.operands[0])); @@ -1566,7 +1573,7 @@ bool Recompiler::Recompile( break; case PPC_INST_STWX: - print("\tPPC_STORE_U32("); + print("{}", mmioStore() ? "\tPPC_MM_STORE_U32(" : "\tPPC_STORE_U32("); if (insn.operands[1] != 0) print("{}.u32 + ", r(insn.operands[1])); println("{}.u32, {}.u32);", r(insn.operands[2]), r(insn.operands[0])); @@ -2287,7 +2294,7 @@ bool Recompiler::Recompile(const Function& fn) if (insn.opcode->id == PPC_INST_BCTR && (*(data - 1) == 0x07008038 || *(data - 1) == 0x00000060) && switchTable == config.switchTables.end()) std::println("Found a switch jump table at {:X} with no switch table entry present", base); - if (!Recompile(fn, base, insn, switchTable, localVariables, csrState)) + if (!Recompile(fn, base, insn, data, switchTable, localVariables, csrState)) { std::println("Unrecognized instruction at 0x{:X}: {}", base, insn.opcode->name); allRecompiled = false; diff --git a/PowerRecomp/recompiler.h b/PowerRecomp/recompiler.h index 5fbfaf3..c7103cd 100644 --- a/PowerRecomp/recompiler.h +++ b/PowerRecomp/recompiler.h @@ -27,6 +27,8 @@ enum class CSRState struct Recompiler { + // Enforce In-order Execution of I/O constant for quick comparison + static constexpr uint32_t c_eieio = 0xAC06007C; Image image; std::vector functions; std::string out; @@ -54,7 +56,8 @@ struct Recompiler bool Recompile( const Function& fn, uint32_t base, - const ppc_insn& insn, + const ppc_insn& insn, + const uint32_t* data, std::unordered_map::iterator& switchTable, RecompilerLocalVariables& localVariables, CSRState& csrState); diff --git a/PowerUtils/ppc_context.h b/PowerUtils/ppc_context.h index 17fcdef..212ca6a 100644 --- a/PowerUtils/ppc_context.h +++ b/PowerUtils/ppc_context.h @@ -29,11 +29,27 @@ #define PPC_LOAD_U32(x) __builtin_bswap32(*(volatile uint32_t*)(base + (x))) #define PPC_LOAD_U64(x) __builtin_bswap64(*(volatile uint64_t*)(base + (x))) +// TODO: Implement. +// These are currently unused. However, MMIO loads could possibly be handled statically with some profiling and a fallback. +// The fallback would be a runtime exception handler which will intercept reads from MMIO regions +// and log the PC for compiling to static code later. +#define PPC_MM_LOAD_U8(x) PPC_LOAD_U8 (x) +#define PPC_MM_LOAD_U16(x) PPC_LOAD_U16(x) +#define PPC_MM_LOAD_U32(x) PPC_LOAD_U32(x) +#define PPC_MM_LOAD_U64(x) PPC_LOAD_U64(x) + #define PPC_STORE_U8(x, y) *(volatile uint8_t*)(base + (x)) = (y) #define PPC_STORE_U16(x, y) *(volatile uint16_t*)(base + (x)) = __builtin_bswap16(y) #define PPC_STORE_U32(x, y) *(volatile uint32_t*)(base + (x)) = __builtin_bswap32(y) #define PPC_STORE_U64(x, y) *(volatile uint64_t*)(base + (x)) = __builtin_bswap64(y) +// MMIO Store handling is completely reliant on being preeceded by eieio. +// TODO: Verify if that's always the case. +#define PPC_MM_STORE_U8(x, y) PPC_STORE_U8 (x, y) +#define PPC_MM_STORE_U16(x, y) PPC_STORE_U16(x, y) +#define PPC_MM_STORE_U32(x, y) PPC_STORE_U32(x, y) +#define PPC_MM_STORE_U64(x, y) PPC_STORE_U64(x, y) + #define PPC_CALL_FUNC(x) x(ctx, base) #define PPC_CALL_INDIRECT_FUNC(x) (*(PPCFunc**)(ctx.fn + uint64_t(x) * 2))(ctx, base)