From 8a54f542d0e8f006dc3c49c8da3f237eb2f45e44 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 25 Mar 2014 17:05:07 +0400 Subject: [PATCH] Reservation improved --- .gitignore | 1 + rpcs3/Emu/CPU/CPUThread.h | 12 ++--- rpcs3/Emu/Cell/SPUThread.h | 90 ++++++++++++++++++++++++++++++-------- rpcs3/Emu/GS/RSXThread.cpp | 2 +- 4 files changed, 79 insertions(+), 26 deletions(-) diff --git a/.gitignore b/.gitignore index cea62cad43..07c7bb0da1 100644 --- a/.gitignore +++ b/.gitignore @@ -58,3 +58,4 @@ rpcs3/git-version.h # Ignore other system generated files bin/dev_hdd0/home/00000001/trophy +bin/dev_hdd0/log.txt diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index 3c2bbafd3e..10348c5c20 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -6,12 +6,12 @@ struct reservation_struct { SMutex mutex; // mutex for updating reservation_owner and data - volatile u32 owner; // id of thread that got reservation - volatile u32 addr; - volatile u32 size; - volatile u32 data32; - volatile u64 data64; - // atm, PPU can't break SPU MFC reservation correctly + u32 owner; // id of thread that got reservation + u32 addr; + u32 size; + u32 data32; + u64 data64; + u128 data[8]; __forceinline void clear() { diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index c898783979..d4e0028784 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -586,7 +586,7 @@ public: } } - Sleep(1); + Sleep(1); // hack switch(cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_LIST_MASK | MFC_RESULT_MASK)) { @@ -704,20 +704,8 @@ public: wxString(op & MFC_BARRIER_MASK ? "B" : "").wx_str(), wxString(op & MFC_FENCE_MASK ? "F" : "").wx_str(), lsa, ea, tag, size, cmd); - if (op & MFC_PUT_CMD) - { - SMutexLocker lock(reservation.mutex); // should be removed - MFCArgs.CMDStatus.SetValue(dmacCmd(cmd, tag, lsa, ea, size)); - if ((reservation.addr + reservation.size > ea && reservation.addr <= ea + size) || - (ea + size > reservation.addr && ea <= reservation.addr + reservation.size)) - { - reservation.clear(); - } - } - else - { - MFCArgs.CMDStatus.SetValue(dmacCmd(cmd, tag, lsa, ea, size)); - } + + MFCArgs.CMDStatus.SetValue(dmacCmd(cmd, tag, lsa, ea, size)); } break; @@ -741,7 +729,7 @@ public: case MFC_PUTLLUC_CMD: case MFC_PUTQLLUC_CMD: { - if (Ini.HLELogging.GetValue()) ConLog.Write("DMA %s: lsa=0x%x, ea = 0x%llx, (tag) = 0x%x, (size) = 0x%x, cmd = 0x%x", + if (Ini.HLELogging.GetValue() || size != 128) ConLog.Write("DMA %s: lsa=0x%x, ea = 0x%llx, (tag) = 0x%x, (size) = 0x%x, cmd = 0x%x", wxString(op == MFC_GETLLAR_CMD ? "GETLLAR" : op == MFC_PUTLLC_CMD ? "PUTLLC" : op == MFC_PUTLLUC_CMD ? "PUTLLUC" : "PUTQLLUC").wx_str(), @@ -753,7 +741,11 @@ public: reservation.owner = lock.tid; reservation.addr = ea; reservation.size = 128; - ProcessCmd(MFC_GET_CMD, tag, lsa, ea, 128); + for (u32 i = 0; i < 8; i++) + { + reservation.data[i] = *(u128*)&Memory[(u32)ea + i * 16]; + *(u128*)&Memory[dmac.ls_offset + lsa + i * 16] = reservation.data[i]; + } Prxy.AtomicStat.PushUncond(MFC_GETLLAR_SUCCESS); } else if (op == MFC_PUTLLC_CMD) // store conditional @@ -763,8 +755,68 @@ public: { if (reservation.addr == ea && reservation.size == 128) { - ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128); - Prxy.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS); + u128 buf[8]; // data being written newly + u32 changed = 0, mask = 0, last = 0; + for (u32 i = 0; i < 8; i++) + { + buf[i] = *(u128*)&Memory[dmac.ls_offset + lsa + i * 16]; + if (buf[i] != reservation.data[i]) + { + changed++; + last = i; + mask |= (0xf << (i * 4)); + } + } + if (changed == 0) // nothing changed? + { + Prxy.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS); + } + else if (changed == 1) + { + if (buf[last].hi != reservation.data[last].hi && buf[last].lo != reservation.data[last].lo) + { + ConLog.Error("MFC_PUTLLC_CMD: TODO: 128bit compare and swap"); + Emu.Pause(); + Prxy.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS); + } + else + { + const u32 last_q = (buf[last].hi == reservation.data[last].hi); + + if (InterlockedCompareExchange64((volatile long long*)(Memory + (u32)ea + last * 16 + last_q * 8), + buf[last]._u64[last_q], reservation.data[last]._u64[last_q]) == reservation.data[last]._u64[last_q]) + { + Prxy.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS); + } + else + { + Prxy.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE); + } + /*u32 last_d = last_q * 2; + if (buf[last]._u32[last_d] == reservation.data[last]._u32[last_d] && buf[last]._u32[last_d+1] != reservation.data[last]._u32[last_d+1]) + { + last_d++; + } + else if (buf[last]._u32[last_d+1] == reservation.data[last]._u32[last_d+1]) + { + last_d; + } + else // full 64 bit + { + ConLog.Error("MFC_PUTLLC_CMD: TODO: 64bit compare and swap"); + Emu.Pause(); + Prxy.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS); + }*/ + } + } + else + { + ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128); + ConLog.Error("MFC_PUTLLC_CMD: Reservation Error: impossibru (~ 16x%d (mask=0x%x)) (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)", + changed, mask, op, cmd, lsa, ea, tag, size); + Emu.Pause(); + Prxy.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS); + } } else { diff --git a/rpcs3/Emu/GS/RSXThread.cpp b/rpcs3/Emu/GS/RSXThread.cpp index 063a6116a2..b161d8f0a7 100644 --- a/rpcs3/Emu/GS/RSXThread.cpp +++ b/rpcs3/Emu/GS/RSXThread.cpp @@ -652,7 +652,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, mem32_ptr_t& args, const u3 case NV4097_SET_SHADER_PROGRAM: { m_cur_shader_prog = &m_shader_progs[m_cur_shader_prog_num]; - //m_cur_shader_prog_num = (m_cur_shader_prog_num + 1) % 16; + m_cur_shader_prog_num = (m_cur_shader_prog_num + 1) % 16; u32 a0 = ARGS(0); m_cur_shader_prog->offset = a0 & ~0x3; m_cur_shader_prog->addr = GetAddress(m_cur_shader_prog->offset, (a0 & 0x3) - 1);