diff --git a/src/xenia/cpu/ppc/disasm_memory.cc b/src/xenia/cpu/ppc/disasm_memory.cc index 676154b78..c0bbe5acf 100644 --- a/src/xenia/cpu/ppc/disasm_memory.cc +++ b/src/xenia/cpu/ppc/disasm_memory.cc @@ -413,33 +413,75 @@ XEDISASMR(stwx, 0x7C00012E, X )(InstrData& i, InstrDisasm& d) { // Integer load and store with byte reverse (A-1 XEDISASMR(lhbrx, 0x7C00062C, X )(InstrData& i, InstrDisasm& d) { - XEINSTRNOTIMPLEMENTED(); - return 1; + d.Init("lhbrx", "Load Halfword Byte-Reverse Indexed", 0); + d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite); + if (i.X.RA) { + d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead); + } else { + d.AddUImmOperand(0, 1); + } + d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead); + return d.Finish(); } XEDISASMR(lwbrx, 0x7C00042C, X )(InstrData& i, InstrDisasm& d) { - XEINSTRNOTIMPLEMENTED(); - return 1; + d.Init("lwbrx", "Load Word Byte-Reverse Indexed", 0); + d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite); + if (i.X.RA) { + d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead); + } else { + d.AddUImmOperand(0, 1); + } + d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead); + return d.Finish(); } XEDISASMR(ldbrx, 0x7C000428, X )(InstrData& i, InstrDisasm& d) { - XEINSTRNOTIMPLEMENTED(); - return 1; + d.Init("ldbrx", "Load Doubleword Byte-Reverse Indexed", 0); + d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kWrite); + if (i.X.RA) { + d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead); + } else { + d.AddUImmOperand(0, 1); + } + d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead); + return d.Finish(); } XEDISASMR(sthbrx, 0x7C00072C, X )(InstrData& i, InstrDisasm& d) { - XEINSTRNOTIMPLEMENTED(); - return 1; + d.Init("sthbrx", "Store Halfword Byte-Reverse Indexed", 0); + d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead); + if (i.X.RA) { + d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead); + } else { + d.AddUImmOperand(0, 1); + } + d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead); + return d.Finish(); } XEDISASMR(stwbrx, 0x7C00052C, X )(InstrData& i, InstrDisasm& d) { - XEINSTRNOTIMPLEMENTED(); - return 1; + d.Init("stwbrx", "Store Word Byte-Reverse Indexed", 0); + d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead); + if (i.X.RA) { + d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead); + } else { + d.AddUImmOperand(0, 1); + } + d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead); + return d.Finish(); } XEDISASMR(stdbrx, 0x7C000528, X )(InstrData& i, InstrDisasm& d) { - XEINSTRNOTIMPLEMENTED(); - return 1; + d.Init("stdbrx", "Store Doubleword Byte-Reverse Indexed", 0); + d.AddRegOperand(InstrRegister::kGPR, i.X.RT, InstrRegister::kRead); + if (i.X.RA) { + d.AddRegOperand(InstrRegister::kGPR, i.X.RA, InstrRegister::kRead); + } else { + d.AddUImmOperand(0, 1); + } + d.AddRegOperand(InstrRegister::kGPR, i.X.RB, InstrRegister::kRead); + return d.Finish(); } diff --git a/src/xenia/cpu/x64/x64_emit_memory.cc b/src/xenia/cpu/x64/x64_emit_memory.cc index 7df9b043f..985757c9f 100644 --- a/src/xenia/cpu/x64/x64_emit_memory.cc +++ b/src/xenia/cpu/x64/x64_emit_memory.cc @@ -911,33 +911,125 @@ XEEMITTER(stwx, 0x7C00012E, X )(X64Emitter& e, X86Compiler& c, InstrDat // Integer load and store with byte reverse (A-1 XEEMITTER(lhbrx, 0x7C00062C, X )(X64Emitter& e, X86Compiler& c, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- i48.0 || bswap(MEM(EA, 2)) + + GpVar ea(c.newGpVar()); + c.mov(ea, e.gpr_value(i.X.RB)); + if (i.X.RA) { + c.add(ea, e.gpr_value(i.X.RA)); + } + GpVar v = e.ReadMemory(i.address, ea, 2, false, false); + // Zero extend done by ReadMemory. + e.update_gpr_value(i.X.RT, v); + + e.clear_constant_gpr_value(i.X.RT); + + return 0; } XEEMITTER(lwbrx, 0x7C00042C, X )(X64Emitter& e, X86Compiler& c, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- i32.0 || bswap(MEM(EA, 4)) + + GpVar ea(c.newGpVar()); + c.mov(ea, e.gpr_value(i.X.RB)); + if (i.X.RA) { + c.add(ea, e.gpr_value(i.X.RA)); + } + GpVar v = e.ReadMemory(i.address, ea, 4, false, false); + // Zero extend done by ReadMemory. + e.update_gpr_value(i.X.RT, v); + + e.clear_constant_gpr_value(i.X.RT); + + return 0; } XEEMITTER(ldbrx, 0x7C000428, X )(X64Emitter& e, X86Compiler& c, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- bswap(MEM(EA, 8)) + + GpVar ea(c.newGpVar()); + c.mov(ea, e.gpr_value(i.X.RB)); + if (i.X.RA) { + c.add(ea, e.gpr_value(i.X.RA)); + } + GpVar v = e.ReadMemory(i.address, ea, 8, false, false); + e.update_gpr_value(i.X.RT, v); + + e.clear_constant_gpr_value(i.X.RT); + + return 0; } XEEMITTER(sthbrx, 0x7C00072C, X )(X64Emitter& e, X86Compiler& c, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 2) <- bswap((RS)[48:63]) + + GpVar ea(c.newGpVar()); + c.mov(ea, e.gpr_value(i.X.RB)); + if (i.D.RA) { + c.add(ea, e.gpr_value(i.X.RA)); + } + GpVar v = e.gpr_value(i.X.RT); + e.WriteMemory(i.address, ea, 2, v, false, false); + + return 0; } XEEMITTER(stwbrx, 0x7C00052C, X )(X64Emitter& e, X86Compiler& c, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 4) <- bswap((RS)[32:63]) + + GpVar ea(c.newGpVar()); + c.mov(ea, e.gpr_value(i.X.RB)); + if (i.X.RA) { + c.add(ea, e.gpr_value(i.X.RA)); + } + GpVar v = e.gpr_value(i.X.RT); + e.WriteMemory(i.address, ea, 4, v, false, false); + + return 0; } XEEMITTER(stdbrx, 0x7C000528, X )(X64Emitter& e, X86Compiler& c, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 8) <- bswap(RS) + + GpVar ea(c.newGpVar()); + c.mov(ea, e.gpr_value(i.X.RB)); + if (i.X.RA) { + c.add(ea, e.gpr_value(i.X.RA)); + } + GpVar v = e.gpr_value(i.X.RT); + e.WriteMemory(i.address, ea, 8, v, false, false); + + return 0; } diff --git a/src/xenia/cpu/x64/x64_emitter.cc b/src/xenia/cpu/x64/x64_emitter.cc index 276d49d38..44103f66b 100644 --- a/src/xenia/cpu/x64/x64_emitter.cc +++ b/src/xenia/cpu/x64/x64_emitter.cc @@ -1874,7 +1874,7 @@ GpVar X64Emitter::TouchMemoryAddress(uint32_t cia, GpVar& addr) { uint64_t X64Emitter::reserved_addr_ = 0; GpVar X64Emitter::ReadMemory( - uint32_t cia, GpVar& addr, uint32_t size, bool acquire) { + uint32_t cia, GpVar& addr, uint32_t size, bool acquire, bool bswap) { X86Compiler& c = compiler_; // Rebase off of memory base pointer. @@ -1900,16 +1900,22 @@ GpVar X64Emitter::ReadMemory( case 2: c.mov(value.r16(), word_ptr(real_address)); c.and_(value, imm(0xFFFF)); - c.xchg(value.r8Lo(), value.r8Hi()); + if (bswap) { + c.xchg(value.r8Lo(), value.r8Hi()); + } break; case 4: c.mov(value.r32(), dword_ptr(real_address)); // No need to and -- the mov to e*x will extend for us. - c.bswap(value.r32()); + if (bswap) { + c.bswap(value.r32()); + } break; case 8: c.mov(value, qword_ptr(real_address)); - c.bswap(value.r64()); + if (bswap) { + c.bswap(value.r64()); + } break; default: XEASSERTALWAYS(); @@ -1922,7 +1928,7 @@ GpVar X64Emitter::ReadMemory( void X64Emitter::WriteMemory( uint32_t cia, GpVar& addr, uint32_t size, GpVar& value, - bool release) { + bool release, bool bswap) { X86Compiler& c = compiler_; // Rebase off of memory base pointer. @@ -1961,19 +1967,25 @@ void X64Emitter::WriteMemory( case 2: tmp = c.newGpVar(); c.mov(tmp, value); - c.xchg(tmp.r8Lo(), tmp.r8Hi()); + if (bswap) { + c.xchg(tmp.r8Lo(), tmp.r8Hi()); + } c.mov(word_ptr(real_address), tmp.r16()); break; case 4: tmp = c.newGpVar(); c.mov(tmp, value); - c.bswap(tmp.r32()); + if (bswap) { + c.bswap(tmp.r32()); + } c.mov(dword_ptr(real_address), tmp.r32()); break; case 8: tmp = c.newGpVar(); c.mov(tmp, value); - c.bswap(tmp.r64()); + if (bswap) { + c.bswap(tmp.r64()); + } c.mov(qword_ptr(real_address), tmp.r64()); break; default: diff --git a/src/xenia/cpu/x64/x64_emitter.h b/src/xenia/cpu/x64/x64_emitter.h index d854504b9..a2f7cf662 100644 --- a/src/xenia/cpu/x64/x64_emitter.h +++ b/src/xenia/cpu/x64/x64_emitter.h @@ -104,10 +104,11 @@ public: AsmJit::GpVar TouchMemoryAddress(uint32_t cia, AsmJit::GpVar& addr); AsmJit::GpVar ReadMemory( - uint32_t cia, AsmJit::GpVar& addr, uint32_t size, bool acquire = false); + uint32_t cia, AsmJit::GpVar& addr, uint32_t size, bool acquire = false, + bool bswap = true); void WriteMemory( uint32_t cia, AsmJit::GpVar& addr, uint32_t size, AsmJit::GpVar& value, - bool release = false); + bool release = false, bool bswap = true); void ByteSwapXmm(AsmJit::XmmVar& value); AsmJit::XmmVar ReadMemoryXmm( uint32_t cia, AsmJit::GpVar& addr, uint32_t alignment);