diff --git a/src/xenia/cpu/ppc/ppc_context.h b/src/xenia/cpu/ppc/ppc_context.h index b37f4cda4..9c96daa6b 100644 --- a/src/xenia/cpu/ppc/ppc_context.h +++ b/src/xenia/cpu/ppc/ppc_context.h @@ -423,8 +423,8 @@ typedef struct PPCContext_s { uint8_t* physical_membase; - // Keep the struct padded out to 64b total. - uint8_t _padding[8]; + // Value of last reserved load + uint64_t reserved_val; static std::string GetRegisterName(PPCRegister reg); std::string GetStringFromValue(PPCRegister reg) const; diff --git a/src/xenia/cpu/ppc/ppc_emit_memory.cc b/src/xenia/cpu/ppc/ppc_emit_memory.cc index 8749deb9a..517081c68 100644 --- a/src/xenia/cpu/ppc/ppc_emit_memory.cc +++ b/src/xenia/cpu/ppc/ppc_emit_memory.cc @@ -658,6 +658,7 @@ int InstrEmit_ldarx(PPCHIRBuilder& f, const InstrData& i) { Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); Value* rt = f.ByteSwap(f.Load(ea, INT64_TYPE)); + f.StoreReserved(rt); f.StoreGPR(i.X.RT, rt); return 0; } @@ -682,6 +683,7 @@ int InstrEmit_lwarx(PPCHIRBuilder& f, const InstrData& i) { Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); Value* rt = f.ZeroExtend(f.ByteSwap(f.Load(ea, INT32_TYPE)), INT64_TYPE); + f.StoreReserved(rt); f.StoreGPR(i.X.RT, rt); return 0; } @@ -703,8 +705,9 @@ int InstrEmit_stdcx(PPCHIRBuilder& f, const InstrData& i) { Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); Value* rt = f.ByteSwap(f.LoadGPR(i.X.RT)); - f.Store(ea, rt); - f.StoreContext(offsetof(PPCContext, cr0.cr0_eq), f.LoadConstantInt8(1)); + Value* res = f.ByteSwap(f.LoadReserved()); + Value* v = f.AtomicCompareExchange(ea, res, rt); + f.StoreContext(offsetof(PPCContext, cr0.cr0_eq), v); f.StoreContext(offsetof(PPCContext, cr0.cr0_lt), f.LoadZeroInt8()); f.StoreContext(offsetof(PPCContext, cr0.cr0_gt), f.LoadZeroInt8()); @@ -732,8 +735,9 @@ int InstrEmit_stwcx(PPCHIRBuilder& f, const InstrData& i) { Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); Value* rt = f.ByteSwap(f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE)); - f.Store(ea, rt); - f.StoreContext(offsetof(PPCContext, cr0.cr0_eq), f.LoadConstantInt8(1)); + Value* res = f.ByteSwap(f.Truncate(f.LoadReserved(), INT32_TYPE)); + Value* v = f.AtomicCompareExchange(ea, res, rt); + f.StoreContext(offsetof(PPCContext, cr0.cr0_eq), v); f.StoreContext(offsetof(PPCContext, cr0.cr0_lt), f.LoadZeroInt8()); f.StoreContext(offsetof(PPCContext, cr0.cr0_gt), f.LoadZeroInt8()); diff --git a/src/xenia/cpu/ppc/ppc_hir_builder.cc b/src/xenia/cpu/ppc/ppc_hir_builder.cc index bce5d9d16..e18118d7b 100644 --- a/src/xenia/cpu/ppc/ppc_hir_builder.cc +++ b/src/xenia/cpu/ppc/ppc_hir_builder.cc @@ -511,6 +511,15 @@ void PPCHIRBuilder::StoreVR(uint32_t reg, Value* value) { trace_reg.value = value; } +void PPCHIRBuilder::StoreReserved(Value* val) { + assert_true(val->type == INT64_TYPE); + StoreContext(offsetof(PPCContext, reserved_val), val); +} + +Value* PPCHIRBuilder::LoadReserved() { + return LoadContext(offsetof(PPCContext, reserved_val), INT64_TYPE); +} + } // namespace ppc } // namespace cpu } // namespace xe diff --git a/src/xenia/cpu/ppc/ppc_hir_builder.h b/src/xenia/cpu/ppc/ppc_hir_builder.h index ca9830799..8b88ae35d 100644 --- a/src/xenia/cpu/ppc/ppc_hir_builder.h +++ b/src/xenia/cpu/ppc/ppc_hir_builder.h @@ -78,6 +78,9 @@ class PPCHIRBuilder : public hir::HIRBuilder { Value* LoadVR(uint32_t reg); void StoreVR(uint32_t reg, Value* value); + void StoreReserved(Value* val); + Value* LoadReserved(); + private: void AnnotateLabel(uint32_t address, Label* label);