diff --git a/src/xenia/cpu/x64/x64_emit_memory.cc b/src/xenia/cpu/x64/x64_emit_memory.cc index 1db4a5a23..1bee4b07e 100644 --- a/src/xenia/cpu/x64/x64_emit_memory.cc +++ b/src/xenia/cpu/x64/x64_emit_memory.cc @@ -1000,8 +1000,6 @@ XEEMITTER(ldarx, 0x7C0000A8, X )(X64Emitter& e, X86Compiler& c, InstrDat // RESERVE_ADDR <- real_addr(EA) // RT <- MEM(EA, 8) - // TODO(benvanik): make this right - GpVar ea(c.newGpVar()); c.mov(ea, e.gpr_value(i.X.RB)); if (i.X.RA) { @@ -1026,8 +1024,6 @@ XEEMITTER(lwarx, 0x7C000028, X )(X64Emitter& e, X86Compiler& c, InstrDat // RESERVE_ADDR <- real_addr(EA) // RT <- i32.0 || MEM(EA, 4) - // TODO(benvanik): make this right - GpVar ea(c.newGpVar()); c.mov(ea, e.gpr_value(i.X.RB)); if (i.X.RA) { @@ -1052,8 +1048,6 @@ XEEMITTER(stdcx, 0x7C0001AD, X )(X64Emitter& e, X86Compiler& c, InstrDat // n <- 1 if store performed // CR0[LT GT EQ SO] = 0b00 || n || XER[SO] - // TODO(benvanik): make this right - GpVar ea(c.newGpVar()); c.mov(ea, e.gpr_value(i.X.RB)); if (i.X.RA) { @@ -1062,9 +1056,6 @@ XEEMITTER(stdcx, 0x7C0001AD, X )(X64Emitter& e, X86Compiler& c, InstrDat GpVar v = e.gpr_value(i.X.RT); e.WriteMemory(i.address, ea, 8, v, /* release */ true); - // We always succeed. - e.update_cr_value(0, e.get_uint64(1 << 2)); - return 0; } @@ -1079,8 +1070,6 @@ XEEMITTER(stwcx, 0x7C00012D, X )(X64Emitter& e, X86Compiler& c, InstrDat // n <- 1 if store performed // CR0[LT GT EQ SO] = 0b00 || n || XER[SO] - // TODO(benvanik): make this right - GpVar ea(c.newGpVar()); c.mov(ea, e.gpr_value(i.X.RB)); if (i.X.RA) { @@ -1089,9 +1078,6 @@ XEEMITTER(stwcx, 0x7C00012D, X )(X64Emitter& e, X86Compiler& c, InstrDat GpVar v = e.gpr_value(i.X.RT); e.WriteMemory(i.address, ea, 4, v, /* release */ true); - // We always succeed. - e.update_cr_value(0, e.get_uint64(1 << 2)); - return 0; } diff --git a/src/xenia/cpu/x64/x64_emitter.cc b/src/xenia/cpu/x64/x64_emitter.cc index b7d17dfdc..f29c46b66 100644 --- a/src/xenia/cpu/x64/x64_emitter.cc +++ b/src/xenia/cpu/x64/x64_emitter.cc @@ -1852,6 +1852,8 @@ GpVar X64Emitter::TouchMemoryAddress(uint32_t cia, GpVar& addr) { return real_address; } +uint64_t X64Emitter::reserved_addr_ = 0; + GpVar X64Emitter::ReadMemory( uint32_t cia, GpVar& addr, uint32_t size, bool acquire) { X86Compiler& c = compiler_; @@ -1859,12 +1861,15 @@ GpVar X64Emitter::ReadMemory( // Rebase off of memory base pointer. GpVar real_address = TouchMemoryAddress(cia, addr); + // Acquire semantics -- make reservation for address. + // Note that we overwrite any other reservation. if (acquire) { - // TODO(benvanik): acquire semantics. - // load_value->setAlignment(size); - // load_value->setVolatile(true); - // load_value->setAtomic(Acquire); - XELOGE("Ignoring acquire semantics on read -- TODO"); + GpVar reservation(c.newGpVar()); + c.mov(reservation, real_address); + GpVar reserved_addr(c.newGpVar()); + c.mov(reserved_addr, imm((sysint_t)&X64Emitter::reserved_addr_)); + c.lock(); + c.xchg(reservation, qword_ptr(reserved_addr)); } GpVar value(c.newGpVar()); @@ -1904,6 +1909,31 @@ void X64Emitter::WriteMemory( // Rebase off of memory base pointer. GpVar real_address = TouchMemoryAddress(cia, addr); + // Release semantics - clear reservation. + Label reservation_mismatch(c.newLabel()); + if (release) { + // Atomically swap 0 with the reserved_addr_ -- this clears the reservation + // and lets us compare -- if we match, we can write. + GpVar reservation(c.newGpVar()); + c.alloc(reservation, rax); + c.xor_(reservation, reservation); + GpVar reserved_addr(c.newGpVar()); + c.mov(reserved_addr, imm((sysint_t)&X64Emitter::reserved_addr_)); + c.lock(); + c.xchg(reservation, qword_ptr(reserved_addr)); + // If reservation was not for address, skip write. + GpVar cr(c.newGpVar()); + c.xor_(cr, cr); + GpVar cr_set(c.newGpVar()); + c.mov(cr_set, imm(1 << 2)); + c.cmp(reservation, real_address); + c.unuse(reservation); + c.cmove(cr, cr_set); + update_cr_value(0, cr); + c.test(cr, cr); + c.jz(reservation_mismatch, kCondHintUnlikely); + } + GpVar tmp; switch (size) { case 1: @@ -1932,12 +1962,8 @@ void X64Emitter::WriteMemory( return; } - // TODO(benvanik): release semantics if (release) { - // store_value->setAlignment(size); - // store_value->setVolatile(true); - // store_value->setAtomic(Release); - XELOGE("Ignoring release semantics on write -- TODO"); + c.bind(reservation_mismatch); } } diff --git a/src/xenia/cpu/x64/x64_emitter.h b/src/xenia/cpu/x64/x64_emitter.h index a922ee154..d854504b9 100644 --- a/src/xenia/cpu/x64/x64_emitter.h +++ b/src/xenia/cpu/x64/x64_emitter.h @@ -142,6 +142,8 @@ private: void* gpu_read_; void* gpu_write_; + static uint64_t reserved_addr_; + AsmJit::Logger* logger_; AsmJit::X86Assembler assembler_; AsmJit::X86Compiler compiler_;