From c9a421f12fc1d3fba39b73f15933297a8e0eec00 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sun, 16 Mar 2014 00:46:53 +0400 Subject: [PATCH] SPU Thread Group-specific MMIO LS access, SNR writing --- rpcs3/Emu/Cell/MFC.h | 27 ++---- rpcs3/Emu/Cell/RawSPUThread.cpp | 2 +- rpcs3/Emu/Cell/SPUThread.cpp | 6 +- rpcs3/Emu/Cell/SPUThread.h | 110 +++++++++++++++++++++-- rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp | 10 +-- 5 files changed, 119 insertions(+), 36 deletions(-) diff --git a/rpcs3/Emu/Cell/MFC.h b/rpcs3/Emu/Cell/MFC.h index bef241c7b8..1628e16d87 100644 --- a/rpcs3/Emu/Cell/MFC.h +++ b/rpcs3/Emu/Cell/MFC.h @@ -55,7 +55,7 @@ enum MFC_SPU_MAX_QUEUE_SPACE = 0x10, }; -struct DMAC_Queue +/*struct DMAC_Queue { bool is_valid; u64 ea; @@ -149,13 +149,14 @@ public: { return Memory.Read32(m_addr); } -}; +};*/ struct DMAC { - //DMAC_Queue queue[MFC_SPU_MAX_QUEUE_SPACE]; //not used yet - DMAC_Proxy proxy[MFC_PPU_MAX_QUEUE_SPACE+MFC_SPU_MAX_QUEUE_SPACE]; //temporarily 24 u64 ls_offset; + + /*//DMAC_Queue queue[MFC_SPU_MAX_QUEUE_SPACE]; //not used yet + DMAC_Proxy proxy[MFC_PPU_MAX_QUEUE_SPACE+MFC_SPU_MAX_QUEUE_SPACE]; //temporarily 24 u32 queue_pos; u32 proxy_pos; long queue_lock; @@ -194,18 +195,6 @@ struct DMAC return MFC_PPU_DMA_QUEUE_FULL; } - /* while (std::atomic_exchange(&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; */ ProcessCmd(cmd, tag, lsa, ea, size); return MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL; @@ -230,10 +219,10 @@ struct DMAC ClearCmd(); } } - } + }*/ }; -struct MFC +/*struct MFC { SPUReg<1> MFC_LSA; SPUReg<1> MFC_EAH; @@ -299,4 +288,4 @@ struct MFC MFC_QStatus.SetValue(mask); } } -}; +};*/ diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index 49f2abfff2..4cb3d27354 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -283,7 +283,7 @@ void RawSPUThread::Task() continue; } - dmac.DoCmd(); + //dmac.DoCmd(); if(SPU.RunCntl.GetValue() != SPU_RUNCNTL_RUNNABLE) { diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 2e32989e08..0d651af5f5 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -20,6 +20,8 @@ SPUThread::SPUThread(CPUThreadType type) : PPCThread(type) { assert(type == CPU_THREAD_SPU || type == CPU_THREAD_RAW_SPU); + group = nullptr; + Reset(); } @@ -46,10 +48,10 @@ void SPUThread::InitRegs() cfg.Reset(); dmac.ls_offset = m_offset; - dmac.proxy_pos = 0; + /*dmac.proxy_pos = 0; dmac.queue_pos = 0; dmac.proxy_lock = 0; - dmac.queue_lock = 0; + dmac.queue_lock = 0;*/ SPU.RunCntl.SetValue(SPU_RUNCNTL_STOP); SPU.Status.SetValue(SPU_STATUS_RUNNING); diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index cfed36752e..01fb622f6d 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -119,6 +119,15 @@ enum SPU_STATUS_SINGLE_STEP = 0x10, }; +enum : u32 +{ + SYS_SPU_THREAD_BASE_LOW = 0xf0000000, + SYS_SPU_THREAD_BASE_MASK = 0xfffffff, + SYS_SPU_THREAD_OFFSET = 0x00100000, + SYS_SPU_THREAD_SNR1 = 0x05400c, + SYS_SPU_THREAD_SNR2 = 0x05C00c, +}; + //Floating point status and control register. Unsure if this is one of the GPRs or SPRs //Is 128 bits, but bits 0-19, 24-28, 32-49, 56-60, 64-81, 88-92, 96-115, 120-124 are unused class FPSCR @@ -278,6 +287,7 @@ public: EventPort SPUPs[64]; // SPU Thread Event Ports EventManager SPUQs; // SPU Queue Mapping + SpuGroupInfo* group; // associated SPU Thread Group (null for raw spu) template class Channel @@ -512,6 +522,18 @@ public: Channel<1> SNR[2]; } SPU; + void WriteSNR(bool number, u32 value) + { + if (cfg.value & ((u64)1 << (u64)number)) + { + SPU.SNR[number].PushUncond_OR(value); // logical OR + } + else + { + SPU.SNR[number].PushUncond(value); // overwrite + } + } + u32 LSA; union @@ -522,6 +544,82 @@ public: DMAC dmac; + bool ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size) + { + if (cmd & (MFC_BARRIER_MASK | MFC_FENCE_MASK)) _mm_mfence(); + + if ((ea & 0xf0000000) == SYS_SPU_THREAD_BASE_LOW) + { + if (group) + { + // SPU Thread Group MMIO (LS and SNR) + u32 num = (ea & SYS_SPU_THREAD_BASE_MASK) / SYS_SPU_THREAD_OFFSET; // thread number in group + if (num >= group->list.GetCount() || !group->list[num]) + { + ConLog.Error("DMAC::ProcessCmd(): SPU Thread Group MMIO Access (ea=0x%llx): invalid thread", ea); + return false; + } + + SPUThread* spu = (SPUThread*)Emu.GetCPU().GetThread(group->list[num]); + + u32 addr = (ea & SYS_SPU_THREAD_BASE_MASK) % SYS_SPU_THREAD_OFFSET; + if ((addr <= 0x3ffff) && (addr + size <= 0x40000)) + { + // LS access + ea = spu->dmac.ls_offset + addr; + } + else if ((cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_LIST_MASK)) == MFC_PUT_CMD && + size == 4 && (addr == SYS_SPU_THREAD_SNR1 || addr == SYS_SPU_THREAD_SNR2)) + { + spu->WriteSNR(SYS_SPU_THREAD_SNR2 == addr, Memory.Read32(dmac.ls_offset + lsa)); + return true; + } + else + { + ConLog.Error("DMAC::ProcessCmd(): SPU Thread Group MMIO Access (ea=0x%llx, size=%d, cmd=0x%x): invalid command", ea, size, cmd); + return false; + } + } + else + { + ConLog.Error("DMAC::ProcessCmd(): SPU Thread Group MMIO Access (ea=0x%llx): group not set", ea); + return false; + } + } + + switch(cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_LIST_MASK)) + { + case MFC_PUT_CMD: + { + return Memory.Copy(ea, dmac.ls_offset + lsa, size); + } + + case MFC_GET_CMD: + { + return Memory.Copy(dmac.ls_offset + lsa, ea, size); + } + + default: + { + ConLog.Error("DMAC::ProcessCmd(): Unknown DMA cmd."); + return false; + } + } + } + + u32 dmacCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size) + { + /*if(proxy_pos >= MFC_PPU_MAX_QUEUE_SPACE) + { + return MFC_PPU_DMA_QUEUE_FULL; + }*/ + + if (ProcessCmd(cmd, tag, lsa, ea, size)) + return MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL; + else + return MFC_PPU_DMA_CMD_SEQUENCE_ERROR; + } + void ListCmd(u32 lsa, u64 ea, u16 tag, u16 size, u32 cmd, MFCReg& MFCArgs) { u32 list_addr = ea & 0x3ffff; @@ -549,7 +647,7 @@ public: } u32 addr = rec->ea; - result = dmac.Cmd(cmd, tag, lsa | (addr & 0xf), addr, size); + result = dmacCmd(cmd, tag, lsa | (addr & 0xf), addr, size); if (result == MFC_PPU_DMA_CMD_SEQUENCE_ERROR) { break; @@ -606,7 +704,7 @@ public: if (op & MFC_PUT_CMD) { SMutexLocker lock(reservation.mutex); // should be removed - MFCArgs.CMDStatus.SetValue(dmac.Cmd(cmd, tag, lsa, ea, size)); + 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)) { @@ -615,7 +713,7 @@ public: } else { - MFCArgs.CMDStatus.SetValue(dmac.Cmd(cmd, tag, lsa, ea, size)); + MFCArgs.CMDStatus.SetValue(dmacCmd(cmd, tag, lsa, ea, size)); } } break; @@ -650,7 +748,7 @@ public: reservation.owner = lock.tid; reservation.addr = ea; reservation.size = 128; - dmac.ProcessCmd(MFC_GET_CMD, tag, lsa, ea, 128); + ProcessCmd(MFC_GET_CMD, tag, lsa, ea, 128); Prxy.AtomicStat.PushUncond(MFC_GETLLAR_SUCCESS); } else if (op == MFC_PUTLLC_CMD) // store conditional @@ -660,7 +758,7 @@ public: { if (reservation.addr == ea && reservation.size == 128) { - dmac.ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128); + ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128); Prxy.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS); } else @@ -677,7 +775,7 @@ public: else // store unconditional { SMutexLocker lock(reservation.mutex); - dmac.ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128); + ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128); if (op == MFC_PUTLLUC_CMD) { Prxy.AtomicStat.PushUncond(MFC_PUTLLUC_SUCCESS); diff --git a/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp b/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp index 170343883c..22f5d43018 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp @@ -120,6 +120,7 @@ int sys_spu_thread_initialize(mem32_t thread, u32 group, u32 spu_num, mem_ptr_t< new_thread.Run(); thread = group_info->list[spu_num] = new_thread.GetId(); + (*(SPUThread*)&new_thread).group = group_info; sc_spu.Warning("*** New SPU Thread [%s] (img_offset=0x%x, ls_offset=0x%x, ep=0x%x, a1=0x%llx, a2=0x%llx, a3=0x%llx, a4=0x%llx): id=%d", wxString(name).wx_str(), (u32)img->segs_addr, ((SPUThread&)new_thread).dmac.ls_offset, spu_ep, a1, a2, a3, a4, thread.GetValue()); @@ -500,14 +501,7 @@ int sys_spu_thread_write_snr(u32 id, u32 number, u32 value) return CELL_EINVAL; } - if ((*(SPUThread*)thr).cfg.value & ((u64)1<