#include #include #include #include #include #include #include #include #include #define TEST_FILE "default.xex" int main() { const auto file = LoadFile(TEST_FILE).value(); auto image = Image::ParseImage(file.data(), file.size()).value(); std::println("Analysing functions..."); uint32_t cxxFrameHandler = std::byteswap(0x831B1C90); uint32_t cSpecificFrameHandler = std::byteswap(0x8324B3BC); image.symbols.emplace("__CxxFrameHandler", 0x831B1C90, 0x38, Symbol_Function); image.symbols.emplace("__C_specific_handler", 0x82BD7780, 0x38, Symbol_Function); image.symbols.emplace("__memcpy", 0x831B0ED0, 0x488, Symbol_Function); image.symbols.emplace("__memset", 0x831B0BA0, 0xA0, Symbol_Function); image.symbols.emplace("__blkmov", 0x831B1358, 0xA8, Symbol_Function); image.symbols.emplace(std::format("sub_{:X}", 0x82EF5D78), 0x82EF5D78, 0x3F8, Symbol_Function); std::vector functions; auto& pdata = *image.Find(".pdata"); size_t count = pdata.size / sizeof(IMAGE_CE_RUNTIME_FUNCTION); auto* pf = (IMAGE_CE_RUNTIME_FUNCTION*)pdata.data; for (size_t i = 0; i < count; i++) { auto fn = pf[i]; fn.BeginAddress = std::byteswap(fn.BeginAddress); fn.Data = std::byteswap(fn.Data); auto& f = functions.emplace_back(); f.base = fn.BeginAddress; f.size = fn.FunctionLength * 4; image.symbols.emplace(std::format("sub_{:X}", f.base), f.base, f.size, Symbol_Function); } for (const auto& section : image.sections) { if (!(section.flags & SectionFlags_Code)) { continue; } size_t base = section.base; uint8_t* data = section.data; uint8_t* dataEnd = section.data + section.size; const Symbol* prevSymbol = nullptr; while (data < dataEnd) { if (*(uint32_t*)data == 0) { data += 4; base += 4; continue; } if (*(uint32_t*)data == cxxFrameHandler || *(uint32_t*)data == cSpecificFrameHandler) { data += 8; base += 8; continue; } auto fnSymbol = image.symbols.find(base); if (fnSymbol != image.symbols.end() && fnSymbol->type == Symbol_Function) { assert(fnSymbol->address == base); prevSymbol = &*fnSymbol; base += fnSymbol->size; data += fnSymbol->size; } else { auto& missingFn = functions.emplace_back(Function::Analyze(data, dataEnd - data, base)); image.symbols.emplace(std::format("sub_{:X}", missingFn.base), missingFn.base, missingFn.size, Symbol_Function); base += missingFn.size; data += missingFn.size; } } } std::string out; out.reserve(512 * 1024 * 1024); auto print = [&](std::format_string fmt, Args&&... args) { std::vformat_to(std::back_inserter(out), fmt.get(), std::make_format_args(args...)); }; auto println = [&](std::format_string fmt, Args&&... args) { std::vformat_to(std::back_inserter(out), fmt.get(), std::make_format_args(args...)); out += '\n'; }; println("#include \n"); for (auto& symbol : image.symbols) println("PPC_FUNC void {}(PPCContext& __restrict ctx, uint8_t* base);", symbol.name); println(""); for (size_t funcIdx = 0; funcIdx < functions.size(); funcIdx++) { if ((funcIdx % 1000) == 0) std::println("Recompiling functions... {}%", static_cast(funcIdx) / functions.size() * 100.0f); auto& fn = functions[funcIdx]; auto base = fn.base; auto end = base + fn.size; auto* data = (uint32_t*)image.Find(base); auto symbol = image.symbols.find(fn.base); if (symbol != image.symbols.end()) { println("PPC_FUNC void {}(PPCContext& __restrict ctx, uint8_t* base) {{", symbol->name); } else { println("PPC_FUNC void sub_{:X}(PPCContext& __restrict ctx, uint8_t* base) {{", fn.base); } println("\tPPCRegister temp;"); println("\tuint32_t ea;\n"); ppc_insn insn; while (base < end) { println("loc_{:X}:", base); ppc::Disassemble(data, 4, base, insn); base += 4; ++data; if (insn.opcode == nullptr) { println("\t// {:x} {}", base - 4, insn.op_str); } else { println("\t// {:x} {} {}", base - 4, insn.opcode->name, insn.op_str); auto printFunctionCall = [&](uint32_t ea) { auto targetSymbol = image.symbols.find(ea); if (targetSymbol != image.symbols.end() && targetSymbol->type == Symbol_Function) { println("\t{}(ctx, base);", targetSymbol->name); } else { println("\tctx.fn[0x{:X}](ctx, base);", ea / 4); } }; auto printConditionalBranch = [&](bool not_, const std::string_view& cond) { if (insn.operands[1] < fn.base || insn.operands[1] >= fn.base + fn.size) { println("\tif ({}ctx.cr{}.{}) {{", not_ ? "!" : "", insn.operands[0], cond); print("\t"); printFunctionCall(insn.operands[1]); println("\t\treturn;"); println("\t}}"); } else { println("\tif ({}ctx.cr{}.{}) goto loc_{:X};", not_ ? "!" : "", insn.operands[0], cond, insn.operands[1]); } }; switch (insn.opcode->id) { case PPC_INST_ADD: println("\tctx.r{}.u64 = ctx.r{}.u64 + ctx.r{}.u64;", insn.operands[0], insn.operands[1], insn.operands[2]); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_ADDI: print("\tctx.r{}.s64 = ", insn.operands[0]); if (insn.operands[1] != 0) print("ctx.r{}.s64 + ", insn.operands[1]); println("{};", static_cast(insn.operands[2])); break; case PPC_INST_ADDIC: println("\tctx.xer.ca = _addcarry_u64(0, ctx.r{}.u64, uint64_t(int64_t({})), &ctx.r{}.u64);", insn.operands[1], static_cast(insn.operands[2]), insn.operands[0]); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_ADDIS: print("\tctx.r{}.s64 = ", insn.operands[0]); if (insn.operands[1] != 0) print("ctx.r{}.s64 + ", insn.operands[1]); println("{};", static_cast(insn.operands[2] << 16)); break; case PPC_INST_ADDZE: println("\tctx.xer.ca = _addcarry_u64(ctx.xer.ca, ctx.r{}.u64, 0, &ctx.r{}.u64);", insn.operands[1], insn.operands[0]); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_AND: println("\tctx.r{}.u64 = ctx.r{}.u64 & ctx.r{}.u64;", insn.operands[0], insn.operands[1], insn.operands[2]); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_ANDC: println("\tctx.r{}.u64 = ctx.r{}.u64 & ~ctx.r{}.u64;", insn.operands[0], insn.operands[1], insn.operands[2]); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_ANDI: println("\tctx.r{}.u64 = ctx.r{}.u64 & {};", insn.operands[0], insn.operands[1], insn.operands[2]); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_ANDIS: println("\tctx.r{}.u64 = ctx.r{}.u64 & {};", insn.operands[0], insn.operands[1], insn.operands[2] << 16); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_ATTN: // undefined instruction break; case PPC_INST_B: if (insn.operands[0] < fn.base || insn.operands[0] >= fn.base + fn.size) { printFunctionCall(insn.operands[0]); println("\treturn;"); } else { println("\tgoto loc_{:X};", insn.operands[0]); } break; case PPC_INST_BCTR: println("\tctx.fn[ctx.ctr / 4](ctx, base);"); println("\treturn;"); break; case PPC_INST_BCTRL: println("\tctx.lr = 0x{:X};", base); println("\tctx.fn[ctx.ctr / 4](ctx, base);"); break; case PPC_INST_BDNZ: println("\tif (--ctx.ctr != 0) goto loc_{:X};", insn.operands[0]); break; case PPC_INST_BDNZF: // NOTE: assuming eq here as a shortcut because all the instructions in the game do that println("\tif (--ctx.ctr != 0 && !ctx.cr{}.eq) goto loc_{:X};", insn.operands[0], insn.operands[2]); break; case PPC_INST_BEQ: printConditionalBranch(false, "eq"); break; case PPC_INST_BEQLR: println("\tif (ctx.cr{}.eq) return;", insn.operands[0]); break; case PPC_INST_BGE: printConditionalBranch(true, "lt"); break; case PPC_INST_BGELR: println("\tif (!ctx.cr{}.lt) return;", insn.operands[0]); break; case PPC_INST_BGT: printConditionalBranch(false, "gt"); break; case PPC_INST_BGTLR: println("\tif (ctx.cr{}.gt) return;", insn.operands[0]); break; case PPC_INST_BL: println("\tctx.lr = 0x{:X};", base); printFunctionCall(insn.operands[0]); break; case PPC_INST_BLE: printConditionalBranch(true, "gt"); break; case PPC_INST_BLELR: println("\tif (!ctx.cr{}.gt) return;", insn.operands[0]); break; case PPC_INST_BLR: println("\treturn;"); break; case PPC_INST_BLRL: println("\tctx.fn[ctx.lr / 4](ctx, base);"); break; case PPC_INST_BLT: printConditionalBranch(false, "lt"); break; case PPC_INST_BLTLR: println("\tif (ctx.cr{}.lt) return;", insn.operands[0]); break; case PPC_INST_BNE: printConditionalBranch(true, "eq"); break; case PPC_INST_BNECTR: println("\tif (!ctx.cr{}.eq) {{", insn.operands[0]); println("\t\tctx.fn[ctx.ctr / 4](ctx, base);"); println("\t\treturn;"); println("\t}}"); break; case PPC_INST_BNELR: println("\tif (!ctx.cr{}.eq) return;", insn.operands[0]); break; case PPC_INST_CCTPL: // no op break; case PPC_INST_CCTPM: // no op break; case PPC_INST_CLRLDI: println("\tctx.r{}.u64 = ctx.r{}.u64 & 0x{:X};", insn.operands[0], insn.operands[1], (1ull << (64 - insn.operands[2])) - 1); break; case PPC_INST_CLRLWI: println("\tctx.r{}.u64 = ctx.r{}.u32 & 0x{:X};", insn.operands[0], insn.operands[1], (1ull << (32 - insn.operands[2])) - 1); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_CMPD: println("\tctx.cr{}.compare(ctx.r{}.s64, ctx.r{}.s64, ctx.xer);", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_CMPDI: println("\tctx.cr{}.compare(ctx.r{}.s64, {}, ctx.xer);", insn.operands[0], insn.operands[1], int32_t(insn.operands[2])); break; case PPC_INST_CMPLD: println("\tctx.cr{}.compare(ctx.r{}.u64, ctx.r{}.u64, ctx.xer);", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_CMPLDI: println("\tctx.cr{}.compare(ctx.r{}.u64, {}, ctx.xer);", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_CMPLW: println("\tctx.cr{}.compare(ctx.r{}.u32, ctx.r{}.u32, ctx.xer);", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_CMPLWI: println("\tctx.cr{}.compare(ctx.r{}.u32, {}, ctx.xer);", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_CMPW: println("\tctx.cr{}.compare(ctx.r{}.s32, ctx.r{}.s32, ctx.xer);", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_CMPWI: println("\tctx.cr{}.compare(ctx.r{}.s32, {}, ctx.xer);", insn.operands[0], insn.operands[1], int32_t(insn.operands[2])); break; case PPC_INST_CNTLZD: println("\tctx.r{}.u64 = __lzcnt64(ctx.r{}.u64);", insn.operands[0], insn.operands[1]); break; case PPC_INST_CNTLZW: println("\tctx.r{}.u64 = __lzcnt(ctx.r{}.u32);", insn.operands[0], insn.operands[1]); break; case PPC_INST_DB16CYC: // no op break; case PPC_INST_DCBF: // no op break; case PPC_INST_DCBT: // no op break; case PPC_INST_DCBTST: // no op break; case PPC_INST_DCBZ: print("\tmemset(base + (("); if (insn.operands[0] != 0) print("ctx.r{}.u32 + ", insn.operands[0]); println("ctx.r{}.u32) & ~31), 0, 32);", insn.operands[1]); break; case PPC_INST_DCBZL: print("\tmemset(base + (("); if (insn.operands[0] != 0) print("ctx.r{}.u32 + ", insn.operands[0]); println("ctx.r{}.u32) & ~127), 0, 128);", insn.operands[1]); break; case PPC_INST_DIVD: println("\tctx.r{}.s64 = ctx.r{}.s64 / ctx.r{}.s64;", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_DIVDU: println("\tctx.r{}.u64 = ctx.r{}.u64 / ctx.r{}.u64;", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_DIVW: println("\tctx.r{}.s32 = ctx.r{}.s32 / ctx.r{}.s32;", insn.operands[0], insn.operands[1], insn.operands[2]); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_DIVWU: println("\tctx.r{}.u32 = ctx.r{}.u32 / ctx.r{}.u32;", insn.operands[0], insn.operands[1], insn.operands[2]); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_EIEIO: // no op break; case PPC_INST_EXTSB: println("\tctx.r{}.s64 = ctx.r{}.s8;", insn.operands[0], insn.operands[1]); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_EXTSH: println("\tctx.r{}.s64 = ctx.r{}.s16;", insn.operands[0], insn.operands[1]); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_EXTSW: println("\tctx.r{}.s64 = ctx.r{}.s32;", insn.operands[0], insn.operands[1]); break; // TODO: fpu operations require denormal flushing checks case PPC_INST_FABS: println("\tctx.f{}.f64 = fabs(ctx.f{}.f64);", insn.operands[0], insn.operands[1]); break; case PPC_INST_FADD: println("\tctx.f{}.f64 = ctx.f{}.f64 + ctx.f{}.f64;", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_FADDS: println("\tctx.f{}.f64 = float(ctx.f{}.f64 + ctx.f{}.f64);", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_FCFID: // TODO: rounding mode? println("\tctx.f{}.f64 = ctx.f{}.s64;", insn.operands[0], insn.operands[1]); break; case PPC_INST_FCMPU: println("\tctx.cr{}.compare(ctx.f{}.f64, ctx.f{}.f64);", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_FCTID: // TODO: rounding mode? println("\tctx.f{}.s64 = ctx.f{}.f64;", insn.operands[0], insn.operands[1]); break; case PPC_INST_FCTIDZ: println("\tctx.f{}.s64 = ctx.f{}.f64;", insn.operands[0], insn.operands[1]); break; case PPC_INST_FCTIWZ: println("\tctx.f{}.s32 = ctx.f{}.f64;", insn.operands[0], insn.operands[1]); break; case PPC_INST_FDIV: println("\tctx.f{}.f64 = ctx.f{}.f64 / ctx.f{}.f64;", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_FDIVS: println("\tctx.f{}.f64 = float(ctx.f{}.f64 / ctx.f{}.f64);", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_FMADD: println("\tctx.f{}.f64 = ctx.f{}.f64 * ctx.f{}.f64 + ctx.f{}.f64;", insn.operands[0], insn.operands[1], insn.operands[2], insn.operands[3]); break; case PPC_INST_FMADDS: println("\tctx.f{}.f64 = float(ctx.f{}.f64 * ctx.f{}.f64 + ctx.f{}.f64);", insn.operands[0], insn.operands[1], insn.operands[2], insn.operands[3]); break; case PPC_INST_FMR: println("\tctx.f{}.f64 = ctx.f{}.f64;", insn.operands[0], insn.operands[1]); break; case PPC_INST_FMSUB: println("\tctx.f{}.f64 = ctx.f{}.f64 * ctx.f{}.f64 - ctx.f{}.f64;", insn.operands[0], insn.operands[1], insn.operands[2], insn.operands[3]); break; case PPC_INST_FMSUBS: println("\tctx.f{}.f64 = float(ctx.f{}.f64 * ctx.f{}.f64 - ctx.f{}.f64);", insn.operands[0], insn.operands[1], insn.operands[2], insn.operands[3]); break; case PPC_INST_FMUL: println("\tctx.f{}.f64 = ctx.f{}.f64 * ctx.f{}.f64;", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_FMULS: println("\tctx.f{}.f64 = float(ctx.f{}.f64 * ctx.f{}.f64);", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_FNABS: println("\tctx.f{}.f64 = -fabs(ctx.f{}.f64);", insn.operands[0], insn.operands[1]); break; case PPC_INST_FNEG: println("\tctx.f{}.f64 = -ctx.f{}.f64;", insn.operands[0], insn.operands[1]); break; case PPC_INST_FNMADDS: println("\tctx.f{}.f64 = -float(ctx.f{}.f64 * ctx.f{}.f64 + ctx.f{}.f64);", insn.operands[0], insn.operands[1], insn.operands[2], insn.operands[3]); break; case PPC_INST_FNMSUB: println("\tctx.f{}.f64 = -(ctx.f{}.f64 * ctx.f{}.f64 - ctx.f{}.f64);", insn.operands[0], insn.operands[1], insn.operands[2], insn.operands[3]); break; case PPC_INST_FNMSUBS: println("\tctx.f{}.f64 = -float(ctx.f{}.f64 * ctx.f{}.f64 - ctx.f{}.f64);", insn.operands[0], insn.operands[1], insn.operands[2], insn.operands[3]); break; case PPC_INST_FRES: println("\tctx.f{}.f64 = 1.0 / ctx.f{}.f64;", insn.operands[0], insn.operands[1]); break; case PPC_INST_FRSP: println("\tctx.f{}.f64 = float(ctx.f{}.f64);", insn.operands[0], insn.operands[1]); break; case PPC_INST_FSEL: println("\tctx.f{}.f64 = ctx.f{}.f64 >= 0.0 ? ctx.f{}.f64 : ctx.f{}.f64;", insn.operands[0], insn.operands[1], insn.operands[2], insn.operands[3]); break; case PPC_INST_FSQRT: println("\tctx.f{}.f64 = sqrt(ctx.f{}.f64);", insn.operands[0], insn.operands[1]); break; case PPC_INST_FSQRTS: println("\tctx.f{}.f64 = float(sqrt(ctx.f{}.f64));", insn.operands[0], insn.operands[1]); break; case PPC_INST_FSUB: println("\tctx.f{}.f64 = ctx.f{}.f64 - ctx.f{}.f64;", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_FSUBS: println("\tctx.f{}.f64 = float(ctx.f{}.f64 - ctx.f{}.f64);", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_LBZ: print("\tctx.r{}.u64 = PPC_LOAD_U8(", insn.operands[0]); if (insn.operands[2] != 0) print("ctx.r{}.u32 + ", insn.operands[2]); println("{});", int32_t(insn.operands[1])); break; case PPC_INST_LBZU: println("\tea = {} + ctx.r{}.u32;", int32_t(insn.operands[1]), insn.operands[2]); println("\tctx.r{}.u64 = PPC_LOAD_U8(ea);", insn.operands[0]); println("\tctx.r{}.u64 = ea;", insn.operands[2]); break; case PPC_INST_LBZX: print("\tctx.r{}.u64 = PPC_LOAD_U8(", insn.operands[0]); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32);", insn.operands[2]); break; case PPC_INST_LD: print("\tctx.r{}.u64 = PPC_LOAD_U64(", insn.operands[0]); if (insn.operands[2] != 0) print("ctx.r{}.u32 + ", insn.operands[2]); println("{});", int32_t(insn.operands[1])); break; case PPC_INST_LDARX: print("\tctx.reserved.u64 = PPC_LOAD_U64("); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32);", insn.operands[2]); println("\tctx.r{}.u64 = ctx.reserved.u64;", insn.operands[0]); break; case PPC_INST_LDU: println("\tea = {} + ctx.r{}.u32;", int32_t(insn.operands[1]), insn.operands[2]); println("\tctx.r{}.u64 = PPC_LOAD_U64(ea);", insn.operands[0]); println("\tctx.r{}.u64 = ea;", insn.operands[2]); break; case PPC_INST_LDX: print("\tctx.r{}.u64 = PPC_LOAD_U64(", insn.operands[0]); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32);", insn.operands[2]); break; case PPC_INST_LFD: print("\tctx.f{}.u64 = PPC_LOAD_U64(", insn.operands[0]); if (insn.operands[2] != 0) print("ctx.r{}.u32 + ", insn.operands[2]); println("{});", int32_t(insn.operands[1])); break; case PPC_INST_LFDX: print("\tctx.f{}.u64 = PPC_LOAD_U64(", insn.operands[0]); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32);", insn.operands[2]); break; case PPC_INST_LFS: print("\ttemp.u32 = PPC_LOAD_U32("); if (insn.operands[2] != 0) print("ctx.r{}.u32 + ", insn.operands[2]); println("{});", int32_t(insn.operands[1])); println("\tctx.f{}.f64 = temp.f32;", insn.operands[0]); break; case PPC_INST_LFSX: print("\ttemp.u32 = PPC_LOAD_U32("); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32);", insn.operands[2]); println("\tctx.f{}.f64 = temp.f32;", insn.operands[0]); break; case PPC_INST_LHA: print("\tctx.r{}.s64 = int16_t(PPC_LOAD_U16(", insn.operands[0]); if (insn.operands[2] != 0) print("ctx.r{}.u32 + ", insn.operands[2]); println("{}));", int32_t(insn.operands[1])); break; case PPC_INST_LHAX: print("\tctx.r{}.s64 = int16_t(PPC_LOAD_U16(", insn.operands[0]); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32));", insn.operands[2]); break; case PPC_INST_LHZ: print("\tctx.r{}.u64 = PPC_LOAD_U16(", insn.operands[0]); if (insn.operands[2] != 0) print("ctx.r{}.u32 + ", insn.operands[2]); println("{});", int32_t(insn.operands[1])); break; case PPC_INST_LHZX: print("\tctx.r{}.u64 = PPC_LOAD_U16(", insn.operands[0]); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32);", insn.operands[2]); break; case PPC_INST_LI: println("\tctx.r{}.s64 = {};", insn.operands[0], int32_t(insn.operands[1])); break; case PPC_INST_LIS: println("\tctx.r{}.s64 = {};", insn.operands[0], int32_t(insn.operands[1] << 16)); break; case PPC_INST_LVEWX: case PPC_INST_LVEWX128: case PPC_INST_LVX: case PPC_INST_LVX128: // TODO: endian swap print("\t_mm_store_ps(ctx.v{}.f32, _mm_load_ps(reinterpret_cast(base + ", insn.operands[0]); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32)));", insn.operands[2]); break; case PPC_INST_LVLX: case PPC_INST_LVLX128: case PPC_INST_LVRX: case PPC_INST_LVRX128: case PPC_INST_LVSL: case PPC_INST_LVSR: break; case PPC_INST_LWA: print("\tctx.r{}.s64 = int32_t(PPC_LOAD_U32(", insn.operands[0]); if (insn.operands[2] != 0) print("ctx.r{}.u32 + ", insn.operands[2]); println("{}));", int32_t(insn.operands[1])); break; case PPC_INST_LWARX: print("\tctx.reserved.u32 = PPC_LOAD_U32("); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32);", insn.operands[2]); println("\tctx.r{}.u64 = ctx.reserved.u32;", insn.operands[0]); break; case PPC_INST_LWAX: print("\tctx.r{}.s64 = int32_t(PPC_LOAD_U32(", insn.operands[0]); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32));", insn.operands[2]); break; case PPC_INST_LWBRX: print("\tctx.r{}.u64 = _byteswap_ulong(PPC_LOAD_U32(", insn.operands[0]); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32));", insn.operands[2]); break; case PPC_INST_LWSYNC: // no op break; case PPC_INST_LWZ: print("\tctx.r{}.u64 = PPC_LOAD_U32(", insn.operands[0]); if (insn.operands[2] != 0) print("ctx.r{}.u32 + ", insn.operands[2]); println("{});", int32_t(insn.operands[1])); break; case PPC_INST_LWZU: println("\tea = {} + ctx.r{}.u32;", int32_t(insn.operands[1]), insn.operands[2]); println("\tctx.r{}.u64 = PPC_LOAD_U32(ea);", insn.operands[0]); println("\tctx.r{}.u64 = ea;", insn.operands[2]); break; case PPC_INST_LWZX: print("\tctx.r{}.u64 = PPC_LOAD_U32(", insn.operands[0]); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32);", insn.operands[2]); break; case PPC_INST_MFCR: case PPC_INST_MFFS: break; case PPC_INST_MFLR: println("\tctx.r{}.u64 = ctx.lr;", insn.operands[0]); break; case PPC_INST_MFMSR: case PPC_INST_MFOCRF: case PPC_INST_MFTB: break; case PPC_INST_MR: println("\tctx.r{}.u64 = ctx.r{}.u64;", insn.operands[0], insn.operands[1]); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_MTCR: break; case PPC_INST_MTCTR: println("\tctx.ctr = ctx.r{}.u64;", insn.operands[0]); break; case PPC_INST_MTFSF: break; case PPC_INST_MTLR: println("\tctx.lr = ctx.r{}.u64;", insn.operands[0]); break; case PPC_INST_MTMSRD: case PPC_INST_MTXER: case PPC_INST_MULCHWU: case PPC_INST_MULHHW: break; case PPC_INST_MULHW: println("\tctx.r{}.s64 = int64_t(ctx.r{}.s32 * ctx.r{}.s32) << 32;", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_MULHWU: println("\tctx.r{}.u64 = uint64_t(ctx.r{}.u32 * ctx.r{}.u32) << 32;", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_MULLD: println("\tctx.r{}.s64 = ctx.r{}.s64 * ctx.r{}.s64;", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_MULLI: println("\tctx.r{}.s64 = ctx.r{}.s64 * {};", insn.operands[0], insn.operands[1], static_cast(insn.operands[2])); break; case PPC_INST_MULLW: println("\tctx.r{}.s64 = ctx.r{}.s32 * ctx.r{}.s32;", insn.operands[0], insn.operands[1], insn.operands[2]); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_NAND: println("\tctx.r{}.u64 = ~(ctx.r{}.u64 & ctx.r{}.u64);", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_NEG: println("\tctx.r{}.s64 = -ctx.r{}.s64;", insn.operands[0], insn.operands[1]); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_NOP: // no op break; case PPC_INST_NOR: println("\tctx.r{}.u64 = ~(ctx.r{}.u64 | ctx.r{}.u64);", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_NOT: println("\tctx.r{}.u64 = ~ctx.r{}.u64;", insn.operands[0], insn.operands[1]); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_OR: println("\tctx.r{}.u64 = ctx.r{}.u64 | ctx.r{}.u64;", insn.operands[0], insn.operands[1], insn.operands[2]); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_ORC: println("\tctx.r{}.u64 = ctx.r{}.u64 | ~ctx.r{}.u64;", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_ORI: println("\tctx.r{}.u64 = ctx.r{}.u64 | {};", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_ORIS: println("\tctx.r{}.u64 = ctx.r{}.u64 | {};", insn.operands[0], insn.operands[1], insn.operands[2] << 16); break; case PPC_INST_RLDICL: case PPC_INST_RLDICR: case PPC_INST_RLDIMI: case PPC_INST_RLWIMI: case PPC_INST_RLWINM: case PPC_INST_ROTLDI: case PPC_INST_ROTLW: case PPC_INST_ROTLWI: break; case PPC_INST_SLD: println("\tctx.r{}.u64 = ctx.r{}.u8 & 0x40 ? 0 : ctx.r{}.u64 << (ctx.r{}.u8 & 0x7F);", insn.operands[0], insn.operands[2], insn.operands[1], insn.operands[2]); break; case PPC_INST_SLW: println("\tctx.r{}.u64 = ctx.r{}.u8 & 0x20 ? 0 : ctx.r{}.u32 << (ctx.r{}.u8 & 0x3F);", insn.operands[0], insn.operands[2], insn.operands[1], insn.operands[2]); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_SRAD: case PPC_INST_SRADI: case PPC_INST_SRAW: case PPC_INST_SRAWI: break; case PPC_INST_SRD: println("\tctx.r{}.u64 = ctx.r{}.u8 & 0x40 ? 0 : ctx.r{}.u64 >> (ctx.r{}.u8 & 0x7F);", insn.operands[0], insn.operands[2], insn.operands[1], insn.operands[2]); break; case PPC_INST_SRW: println("\tctx.r{}.u64 = ctx.r{}.u8 & 0x20 ? 0 : ctx.r{}.u32 >> (ctx.r{}.u8 & 0x3F);", insn.operands[0], insn.operands[2], insn.operands[1], insn.operands[2]); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_STB: print("\tPPC_STORE_U8("); if (insn.operands[2] != 0) print("ctx.r{}.u32 + ", insn.operands[2]); println("{}, ctx.r{}.u8);", int32_t(insn.operands[1]), insn.operands[0]); break; case PPC_INST_STBU: println("\tea = {} + ctx.r{}.u32;", int32_t(insn.operands[1]), insn.operands[2]); println("\tPPC_STORE_U8(ea, ctx.r{}.u8);", insn.operands[0]); println("\tctx.r{}.u64 = ea;", insn.operands[0]); break; case PPC_INST_STBX: print("\tPPC_STORE_U8("); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32, ctx.r{}.u8);", insn.operands[2], insn.operands[0]); break; case PPC_INST_STD: print("\tPPC_STORE_U64("); if (insn.operands[2] != 0) print("ctx.r{}.u32 + ", insn.operands[2]); println("{}, ctx.r{}.u64);", int32_t(insn.operands[1]), insn.operands[0]); break; case PPC_INST_STDCX: println("\tctx.cr0.lt = 0;"); println("\tctx.cr0.gt = 0;"); print("\tctx.cr0.eq = _InterlockedCompareExchange64(reinterpret_cast<__int64*>(base + "); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32), _byteswap_uint64(ctx.r{}.s64), _byteswap_uint64(ctx.reserved.s64)) == _byteswap_uint64(ctx.reserved.s64);", insn.operands[2], insn.operands[0]); println("\tctx.cr0.so = ctx.xer.so;"); break; case PPC_INST_STDU: println("\tea = {} + ctx.r{}.u32;", int32_t(insn.operands[1]), insn.operands[2]); println("\tPPC_STORE_U64(ea, ctx.r{}.u64);", insn.operands[0]); println("\tctx.r{}.u64 = ea;", insn.operands[0]); break; case PPC_INST_STDX: print("\tPPC_STORE_U64("); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32, ctx.r{}.u64);", insn.operands[2], insn.operands[0]); break; case PPC_INST_STFD: print("\tPPC_STORE_U64("); if (insn.operands[2] != 0) print("ctx.r{}.u32 + ", insn.operands[2]); println("{}, ctx.f{}.u64);", int32_t(insn.operands[1]), insn.operands[0]); break; case PPC_INST_STFDX: print("\tPPC_STORE_U64("); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32, ctx.f{}.u64);", insn.operands[2], insn.operands[0]); break; case PPC_INST_STFIWX: print("\tPPC_STORE_U32("); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32, ctx.f{}.u32);", insn.operands[2], insn.operands[0]); break; case PPC_INST_STFS: println("\ttemp.f32 = ctx.f{}.f64;", insn.operands[0]); print("\tPPC_STORE_U32("); if (insn.operands[2] != 0) print("ctx.r{}.u32 +", insn.operands[2]); println("{}, temp.u32);", int32_t(insn.operands[1])); break; case PPC_INST_STFSX: println("\ttemp.f32 = ctx.f{}.f64;", insn.operands[0]); print("\tPPC_STORE_U32("); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32, temp.u32);", insn.operands[2]); break; case PPC_INST_STH: print("\tPPC_STORE_U16("); if (insn.operands[2] != 0) print("ctx.r{}.u32 + ", insn.operands[2]); println("{}, ctx.r{}.u16);", int32_t(insn.operands[1]), insn.operands[0]); break; case PPC_INST_STHBRX: print("\tPPC_STORE_U16("); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32, _byteswap_ushort(ctx.r{}.u16));", insn.operands[2], insn.operands[0]); break; case PPC_INST_STHX: print("\tPPC_STORE_U16("); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32, ctx.r{}.u16);", insn.operands[2], insn.operands[0]); break; case PPC_INST_STVEHX: case PPC_INST_STVEWX: case PPC_INST_STVEWX128: case PPC_INST_STVLX: case PPC_INST_STVLX128: case PPC_INST_STVRX: case PPC_INST_STVRX128: case PPC_INST_STVX: case PPC_INST_STVX128: break; case PPC_INST_STW: print("\tPPC_STORE_U32("); if (insn.operands[2] != 0) print("ctx.r{}.u32 + ", insn.operands[2]); println("{}, ctx.r{}.u32);", int32_t(insn.operands[1]), insn.operands[0]); break; case PPC_INST_STWBRX: print("\tPPC_STORE_U32("); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32, _byteswap_ulong(ctx.r{}.u32));", insn.operands[2], insn.operands[0]); break; case PPC_INST_STWCX: println("\tctx.cr0.lt = 0;"); println("\tctx.cr0.gt = 0;"); print("\tctx.cr0.eq = _InterlockedCompareExchange(reinterpret_cast(base + "); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32), _byteswap_ulong(ctx.r{}.s32), _byteswap_ulong(ctx.reserved.s32)) == _byteswap_ulong(ctx.reserved.s32);", insn.operands[2], insn.operands[0]); println("\tctx.cr0.so = ctx.xer.so;"); break; case PPC_INST_STWU: println("\tea = {} + ctx.r{}.u32;", int32_t(insn.operands[1]), insn.operands[2]); println("\tPPC_STORE_U32(ea, ctx.r{}.u32);", insn.operands[0]); println("\tctx.r{}.u64 = ea;", insn.operands[0]); break; case PPC_INST_STWUX: println("\tea = ctx.r{}.u32 + ctx.r{}.u32;", insn.operands[1], insn.operands[2]); println("\tPPC_STORE_U32(ea, ctx.r{}.u32);", insn.operands[0]); println("\tctx.r{}.u32 = ea;", insn.operands[0]); break; case PPC_INST_STWX: print("\tPPC_STORE_U32("); if (insn.operands[1] != 0) print("ctx.r{}.u32 + ", insn.operands[1]); println("ctx.r{}.u32, ctx.r{}.u32);", insn.operands[2], insn.operands[0]); break; case PPC_INST_SUBF: println("\tctx.r{}.s64 = ctx.r{}.s64 - ctx.r{}.s64;", insn.operands[0], insn.operands[1], insn.operands[2]); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_SUBFC: println("\tctx.xer.ca = _subborrow_u64(0, ctx.r{}.u64, ctx.r{}.u64, &ctx.r{}.u64);", insn.operands[2], insn.operands[1], insn.operands[0]); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_SUBFE: println("\tctx.xer.ca = _addcarry_u64(ctx.xer.ca, ~ctx.r{}.u64, ctx.r{}.u64, &ctx.r{}.u64);", insn.operands[1], insn.operands[2], insn.operands[0]); break; case PPC_INST_SUBFIC: println("\tctx.xer.ca = _subborrow_u64(0, uint64_t(int64_t({})), ctx.r{}.u64, &ctx.r{}.u64);", static_cast(insn.operands[2]), insn.operands[1], insn.operands[0]); break; case PPC_INST_SYNC: // no op? break; case PPC_INST_TDLGEI: // no op break; case PPC_INST_TDLLEI: // no op break; case PPC_INST_TWI: // no op break; case PPC_INST_TWLGEI: // no op break; case PPC_INST_TWLLEI: // no op break; case PPC_INST_VADDFP: case PPC_INST_VADDFP128: println("\t_mm_store_ps(ctx.v{}.f32, _mm_add_ps(_mm_load_ps(ctx.v{}.f32), _mm_load_ps(ctx.v{}.f32)));", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_VADDSHS: case PPC_INST_VADDUBM: case PPC_INST_VADDUBS: case PPC_INST_VADDUHM: case PPC_INST_VADDUWM: case PPC_INST_VADDUWS: break; case PPC_INST_VAND: case PPC_INST_VAND128: println("\t_mm_store_ps(ctx.v{}.f32, _mm_and_ps(_mm_load_ps(ctx.v{}.f32), _mm_load_ps(ctx.v{}.f32)));", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_VANDC128: println("\t_mm_store_ps(ctx.v{}.f32, _mm_andnot_ps(_mm_load_ps(ctx.v{}.f32), _mm_load_ps(ctx.v{}.f32)));", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_VAVGSB: case PPC_INST_VAVGSH: case PPC_INST_VAVGUB: case PPC_INST_VCFPSXWS128: case PPC_INST_VCFSX: case PPC_INST_VCFUX: case PPC_INST_VCMPBFP128: case PPC_INST_VCMPEQFP: case PPC_INST_VCMPEQFP128: case PPC_INST_VCMPEQUB: case PPC_INST_VCMPEQUW: case PPC_INST_VCMPEQUW128: case PPC_INST_VCMPGEFP: case PPC_INST_VCMPGEFP128: case PPC_INST_VCMPGTFP: case PPC_INST_VCMPGTFP128: case PPC_INST_VCMPGTUB: case PPC_INST_VCMPGTUH: case PPC_INST_VCSXWFP128: case PPC_INST_VCTSXS: case PPC_INST_VCUXWFP128: break; case PPC_INST_VEXPTEFP128: // TODO: this doesn't exist despite being documented? //println("\t_mm_store_ps(ctx.v{}.f32, _mm_exp2_ps(_mm_load_ps(ctx.v{}.f32)));", insn.operands[0], insn.operands[1]); break; case PPC_INST_VLOGEFP128: // TODO: this doesn't exist despite being documented? //println("\t_mm_store_ps(ctx.v{}.f32, _mm_log2_ps(_mm_load_ps(ctx.v{}.f32)));", insn.operands[0], insn.operands[1]); break; case PPC_INST_VMADDCFP128: // TODO: wrong argument order println("\t_mm_store_ps(ctx.v{}.f32, _mm_fmadd_ps(_mm_load_ps(ctx.v{}.f32), _mm_load_ps(ctx.v{}.f32), _mm_load_ps(ctx.v{}.f32)));", insn.operands[0], insn.operands[1], insn.operands[2], insn.operands[3]); break; case PPC_INST_VMADDFP: case PPC_INST_VMADDFP128: // TODO: wrong argument order println("\t_mm_store_ps(ctx.v{}.f32, _mm_fmadd_ps(_mm_load_ps(ctx.v{}.f32), _mm_load_ps(ctx.v{}.f32), _mm_load_ps(ctx.v{}.f32)));", insn.operands[0], insn.operands[1], insn.operands[2], insn.operands[3]); break; case PPC_INST_VMAXFP: case PPC_INST_VMAXFP128: println("\t_mm_store_ps(ctx.v{}.f32, _mm_max_ps(_mm_load_ps(ctx.v{}.f32), _mm_load_ps(ctx.v{}.f32)));", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_VMAXSW: break; case PPC_INST_VMINFP: case PPC_INST_VMINFP128: println("\t_mm_store_ps(ctx.v{}.f32, _mm_min_ps(_mm_load_ps(ctx.v{}.f32), _mm_load_ps(ctx.v{}.f32)));", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_VMRGHB: case PPC_INST_VMRGHH: case PPC_INST_VMRGHW: case PPC_INST_VMRGHW128: case PPC_INST_VMRGLB: case PPC_INST_VMRGLH: case PPC_INST_VMRGLW: case PPC_INST_VMRGLW128: break; case PPC_INST_VMSUM3FP128: println("\t_mm_store_ps(ctx.v{}.f32, _mm_dp_ps(_mm_load_ps(ctx.v{}.f32), _mm_load_ps(ctx.v{}.f32), 0xEF));", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_VMSUM4FP128: println("\t_mm_store_ps(ctx.v{}.f32, _mm_dp_ps(_mm_load_ps(ctx.v{}.f32), _mm_load_ps(ctx.v{}.f32), 0xFF));", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_VMULFP128: println("\t_mm_store_ps(ctx.v{}.f32, _mm_mul_ps(_mm_load_ps(ctx.v{}.f32), _mm_load_ps(ctx.v{}.f32)));", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_VNMSUBFP: case PPC_INST_VNMSUBFP128: // TODO: wrong argument order println("\t_mm_store_ps(ctx.v{}.f32, _mm_fnmadd_ps(_mm_load_ps(ctx.v{}.f32), _mm_load_ps(ctx.v{}.f32), _mm_load_ps(ctx.v{}.f32)));", insn.operands[0], insn.operands[1], insn.operands[2], insn.operands[3]); break; case PPC_INST_VOR: case PPC_INST_VOR128: println("\t_mm_store_ps(ctx.v{}.f32, _mm_or_ps(_mm_load_ps(ctx.v{}.f32), _mm_load_ps(ctx.v{}.f32)));", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_VPERM: case PPC_INST_VPERM128: case PPC_INST_VPERMWI128: case PPC_INST_VPKD3D128: case PPC_INST_VPKSHUS: break; case PPC_INST_VREFP: case PPC_INST_VREFP128: println("\t_mm_store_ps(ctx.v{}.f32, _mm_rcp_ps(_mm_load_ps(ctx.v{}.f32)));", insn.operands[0], insn.operands[1]); break; case PPC_INST_VRFIM128: case PPC_INST_VRFIN: case PPC_INST_VRFIN128: case PPC_INST_VRFIZ128: case PPC_INST_VRLIMI128: break; case PPC_INST_VRSQRTEFP: case PPC_INST_VRSQRTEFP128: println("\t_mm_store_ps(ctx.v{}.f32, _mm_rsqrt_ps(_mm_load_ps(ctx.v{}.f32)));", insn.operands[0], insn.operands[1]); break; case PPC_INST_VSEL: case PPC_INST_VSLB: case PPC_INST_VSLDOI: case PPC_INST_VSLDOI128: case PPC_INST_VSLW128: case PPC_INST_VSPLTH: case PPC_INST_VSPLTISB: case PPC_INST_VSPLTISW: case PPC_INST_VSPLTISW128: case PPC_INST_VSPLTW: case PPC_INST_VSPLTW128: case PPC_INST_VSR: case PPC_INST_VSRAW128: case PPC_INST_VSRW: case PPC_INST_VSRW128: break; case PPC_INST_VSUBFP: case PPC_INST_VSUBFP128: println("\t_mm_store_ps(ctx.v{}.f32, _mm_sub_ps(_mm_load_ps(ctx.v{}.f32), _mm_load_ps(ctx.v{}.f32)));", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_VSUBSWS: case PPC_INST_VSUBUBS: case PPC_INST_VSUBUHM: case PPC_INST_VUPKD3D128: case PPC_INST_VUPKHSB128: case PPC_INST_VUPKHSH: case PPC_INST_VUPKLSB128: case PPC_INST_VUPKLSH: break; case PPC_INST_VXOR: case PPC_INST_VXOR128: println("\t_mm_store_ps(ctx.v{}.f32, _mm_xor_ps(_mm_load_ps(ctx.v{}.f32), _mm_load_ps(ctx.v{}.f32)));", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_XOR: println("\tctx.r{}.u64 = ctx.r{}.u64 ^ ctx.r{}.u64;", insn.operands[0], insn.operands[1], insn.operands[2]); if (insn.opcode->opcode & 0x1) println("\tctx.cr0.compare(ctx.r{}.s32, 0, ctx.xer);", insn.operands[0]); break; case PPC_INST_XORI: println("\tctx.r{}.u64 = ctx.r{}.u64 ^ {};", insn.operands[0], insn.operands[1], insn.operands[2]); break; case PPC_INST_XORIS: println("\tctx.r{}.u64 = ctx.r{}.u64 ^ {};", insn.operands[0], insn.operands[1], insn.operands[2] << 16); break; } } } println("}}\n"); } std::filesystem::create_directory("out"); FILE* f = fopen("out/" TEST_FILE ".cpp", "w"); fwrite(out.data(), 1, out.size(), f); fclose(f); return 0; }