From ee137323aa4f635e93318860768451bae3486aab Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Fri, 13 Dec 2013 05:35:28 +0400 Subject: [PATCH] MBox, some improvements Some changes reverted (warnings), multi-thread safety fixed, MBox MMIO modified --- rpcs3/Emu/Cell/MFC.h | 9 +++-- rpcs3/Emu/Cell/RawSPUThread.cpp | 15 +++++++-- rpcs3/Emu/Cell/SPUThread.h | 60 +++++++++++++++++++++++---------- 3 files changed, 61 insertions(+), 23 deletions(-) diff --git a/rpcs3/Emu/Cell/MFC.h b/rpcs3/Emu/Cell/MFC.h index 54700c3285..9f63247e1a 100644 --- a/rpcs3/Emu/Cell/MFC.h +++ b/rpcs3/Emu/Cell/MFC.h @@ -163,14 +163,17 @@ struct DMAC return MFC_PPU_DMA_QUEUE_FULL; } - while (_InterlockedCompareExchange(&proxy_lock, 1, 0)); + while (_InterlockedExchange(&proxy_lock, 1)); + _mm_lfence(); DMAC_Proxy& p = proxy[proxy_pos]; p.cmd = cmd; p.tag = tag; p.lsa = lsa; p.ea = ea; p.size = size; + _mm_sfence(); //for DoCmd() proxy_pos++; + _mm_sfence(); proxy_lock = 0; return MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL; @@ -178,8 +181,10 @@ struct DMAC void ClearCmd() { - while (_InterlockedCompareExchange(&proxy_lock, 1, 0)); + while (_InterlockedExchange(&proxy_lock, 1)); + _mm_lfence(); memcpy(proxy, proxy + 1, --proxy_pos * sizeof(DMAC_Proxy)); + _mm_sfence(); proxy_lock = 0; //release lock } diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index 17d0512701..248321e99b 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -62,11 +62,17 @@ bool RawSPUThread::Read32(const u64 addr, u32* value) case MFC_EAL_offs: ConLog.Warning("RawSPUThread[%d]: Read32(MFC_EAL)", m_index); *value = MFC2.EAL.GetValue(); break; case MFC_Size_Tag_offs: ConLog.Warning("RawSPUThread[%d]: Read32(MFC_Size_Tag)", m_index); *value = MFC2.Size_Tag.GetValue(); break; case MFC_CMDStatus_offs: ConLog.Warning("RawSPUThread[%d]: Read32(MFC_CMDStatus)", m_index); *value = MFC2.CMDStatus.GetValue(); break; - case MFC_QStatus_offs: *value = MFC2.QStatus.GetValue(); break; + case MFC_QStatus_offs: + ConLog.Warning("RawSPUThread[%d]: Read32(MFC_QStatus)", m_index); + *value = MFC2.QStatus.GetValue(); + break; case Prxy_QueryType_offs: ConLog.Warning("RawSPUThread[%d]: Read32(Prxy_QueryType)", m_index); *value = Prxy.QueryType.GetValue(); break; case Prxy_QueryMask_offs: ConLog.Warning("RawSPUThread[%d]: Read32(Prxy_QueryMask)", m_index); *value = Prxy.QueryMask.GetValue(); break; case Prxy_TagStatus_offs: ConLog.Warning("RawSPUThread[%d]: Read32(Prxy_TagStatus)", m_index); *value = Prxy.TagStatus.GetValue(); break; - case SPU_Out_MBox_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_Out_MBox)", m_index); while(!SPU.Out_MBox.Pop(*value) && !Emu.IsStopped()) Sleep(1); break; + case SPU_Out_MBox_offs: + ConLog.Warning("RawSPUThread[%d]: Read32(SPU_Out_MBox)", m_index); + SPU.Out_MBox.PopUncond(*value); //if Out_MBox is empty yet, the result will be undefined + break; case SPU_In_MBox_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_In_MBox)", m_index); while(!SPU.In_MBox.Pop(*value) && !Emu.IsStopped()) Sleep(1); break; case SPU_MBox_Status_offs: //ConLog.Warning("RawSPUThread[%d]: Read32(SPU_MBox_Status)", m_index); //SPU.MBox_Status.SetValue(SPU.Out_MBox.GetCount() ? SPU.MBox_Status.GetValue() | 1 : SPU.MBox_Status.GetValue() & ~1); @@ -183,7 +189,10 @@ bool RawSPUThread::Write32(const u64 addr, const u32 value) case Prxy_QueryMask_offs: ConLog.Warning("RawSPUThread[%d]: Write32(Prxy_QueryMask, 0x%x)", m_index, value); Prxy.QueryMask.SetValue(value); break; case Prxy_TagStatus_offs: ConLog.Warning("RawSPUThread[%d]: Write32(Prxy_TagStatus, 0x%x)", m_index, value); Prxy.TagStatus.SetValue(value); break; case SPU_Out_MBox_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_Out_MBox, 0x%x)", m_index, value); while(!SPU.Out_MBox.Push(value) && !Emu.IsStopped()) Sleep(1); break; - case SPU_In_MBox_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_In_MBox, 0x%x)", m_index, value); while(!SPU.In_MBox.Push(value) && !Emu.IsStopped()) Sleep(1); break; + case SPU_In_MBox_offs: + ConLog.Warning("RawSPUThread[%d]: Write32(SPU_In_MBox, 0x%x)", m_index, value); + SPU.In_MBox.PushUncond(value); //if In_MBox is already full, the last message will be overwritten + break; case SPU_MBox_Status_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_MBox_Status, 0x%x)", m_index, value); SPU.MBox_Status.SetValue(value); break; case SPU_RunCntl_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_RunCntl, 0x%x)", m_index, value); SPU.RunCntl.SetValue(value); break; case SPU_Status_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_Status, 0x%x)", m_index, value); SPU.Status.SetValue(value); break; diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 106306c181..7e123062e8 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -282,37 +282,69 @@ public: __forceinline bool Pop(u32& res) { - while (_InterlockedCompareExchange(&m_lock, 1, 0)); + while (_InterlockedExchange(&m_lock, 1)); + _mm_lfence(); if(!m_index) { m_lock = 0; //release lock return false; } res = m_value[--m_index]; + _mm_sfence(); m_lock = 0; return true; } __forceinline bool Push(u32 value) { - while (_InterlockedCompareExchange(&m_lock, 1, 0)); + while (_InterlockedExchange(&m_lock, 1)); + _mm_lfence(); if(m_index >= max_count) { m_lock = 0; //release lock return false; } m_value[m_index++] = value; + _mm_sfence(); m_lock = 0; return true; } + __forceinline void PushUncond(u32 value) + { + while (_InterlockedExchange(&m_lock, 1)); + _mm_lfence(); + if(m_index >= max_count) + m_value[max_count-1] = value; //last message is overwritten + else + m_value[m_index++] = value; + _mm_sfence(); + m_lock = 0; + } + + __forceinline void PopUncond(u32& res) + { + while (_InterlockedExchange(&m_lock, 1)); + _mm_lfence(); + if(!m_index) + res = 0; //result is undefined + else + res = m_value[--m_index]; + _mm_sfence(); + m_lock = 0; + } + u32 GetCount() const { + while (m_lock); + _mm_lfence(); return m_index; } u32 GetFreeCount() const { + while (m_lock); + _mm_lfence(); return max_count - m_index; } @@ -383,6 +415,14 @@ public: u16 tag = (u16)size_tag; u16 size = size_tag >> 16; + ConLog.Warning("DMA %s:", op & MFC_PUT_CMD ? "PUT" : "GET"); + ConLog.Warning("*** lsa = 0x%x", lsa); + ConLog.Warning("*** ea = 0x%llx", ea); + ConLog.Warning("*** tag = 0x%x", tag); + ConLog.Warning("*** size = 0x%x", size); + ConLog.Warning("*** cmd = 0x%x", cmd); + ConLog.SkipLn(); + MFCArgs.CMDStatus.SetValue(dmac.Cmd(cmd, tag, lsa, ea, size)); } break; @@ -406,22 +446,6 @@ public: case SPU_WrOutIntrMbox: return 0;//return SPU.OutIntr_Mbox.GetFreeCount(); - case MFC_LSA: - return MFC1.LSA.max_count; - - case MFC_EAH: - return MFC1.EAH.max_count; - - case MFC_EAL: - return MFC1.EAL.max_count; - - case MFC_Size: - case MFC_TagID: - return MFC1.Size_Tag.max_count; - - case MFC_Cmd: - return MFC1.CMDStatus.max_count; - default: ConLog.Error("%s error: unknown/illegal channel (%d [%s]).", __FUNCTION__, ch, spu_ch_name[ch]); break;