From c9abf559be4fecf68a07bc3c29f5d45e8325bd16 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sun, 22 Dec 2013 21:40:50 +0400 Subject: [PATCH] SPU Improvements Implemented SNR channels and syscalls, fixed sys_spu_thread_initialize (args' passing, SPU image copying for each thread) --- rpcs3/Emu/Cell/RawSPUThread.cpp | 8 +- rpcs3/Emu/Cell/SPUInterpreter.h | 8 +- rpcs3/Emu/Cell/SPUThread.cpp | 2 + rpcs3/Emu/Cell/SPUThread.h | 107 +++++++++++++++------- rpcs3/Emu/SysCalls/SysCalls.cpp | 4 +- rpcs3/Emu/SysCalls/SysCalls.h | 3 + rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp | 112 +++++++++++++++++++---- rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.h | 1 + 8 files changed, 184 insertions(+), 61 deletions(-) diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index 248321e99b..006c7b28d7 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -82,8 +82,8 @@ bool RawSPUThread::Read32(const u64 addr, u32* value) case SPU_RunCntl_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_RunCntl)", m_index); *value = SPU.RunCntl.GetValue(); break; case SPU_Status_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_Status)", m_index); *value = SPU.Status.GetValue(); break; case SPU_NPC_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_NPC)", m_index); *value = SPU.NPC.GetValue(); break; - case SPU_RdSigNotify1_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_RdSigNotify1)", m_index); *value = SPU.RdSigNotify1.GetValue(); break; - case SPU_RdSigNotify2_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_RdSigNotify2)", m_index); *value = SPU.RdSigNotify2.GetValue(); break; + case SPU_RdSigNotify1_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_RdSigNotify1)", m_index); *value = SPU.SNR[0].GetValue(); break; + case SPU_RdSigNotify2_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_RdSigNotify2)", m_index); *value = SPU.SNR[1].GetValue(); break; default: ConLog.Error("RawSPUThread[%d]: Read32(0x%x)", m_index, offset); @@ -197,8 +197,8 @@ bool RawSPUThread::Write32(const u64 addr, const u32 value) 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; case SPU_NPC_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_NPC, 0x%x)", m_index, value); SPU.NPC.SetValue(value); break; - case SPU_RdSigNotify1_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_RdSigNotify1, 0x%x)", m_index, value); SPU.RdSigNotify1.SetValue(value); break; - case SPU_RdSigNotify2_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_RdSigNotify2, 0x%x)", m_index, value); SPU.RdSigNotify2.SetValue(value); break; + case SPU_RdSigNotify1_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_RdSigNotify1, 0x%x)", m_index, value); SPU.SNR[0].SetValue(value); break; + case SPU_RdSigNotify2_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_RdSigNotify2, 0x%x)", m_index, value); SPU.SNR[1].SetValue(value); break; default: ConLog.Error("RawSPUThread[%d]: Write32(0x%x, 0x%x)", m_index, offset, value); diff --git a/rpcs3/Emu/Cell/SPUInterpreter.h b/rpcs3/Emu/Cell/SPUInterpreter.h index e71eb5a7f0..f4e88eccdc 100644 --- a/rpcs3/Emu/Cell/SPUInterpreter.h +++ b/rpcs3/Emu/Cell/SPUInterpreter.h @@ -35,24 +35,24 @@ private: if(code & 0x2000) { CPU.SetExitStatus(code & 0xfff); - CPU.Stop(); } else { ConLog.Warning("STOP: 0x%x", code); - Emu.Pause(); + //Emu.Pause(); } + CPU.Stop(); } void LNOP() { } void SYNC(u32 Cbit) { - //UNIMPLEMENTED(); + _mm_mfence(); } void DSYNC() { - //UNIMPLEMENTED(); + _mm_mfence(); } void MFSPR(u32 rt, u32 sa) { diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 34e24b5471..76732b7f58 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -43,6 +43,8 @@ void SPUThread::InitRegs() GPR[5]._u64[1] = m_args[2]; GPR[6]._u64[1] = m_args[3]; + cfg.Reset(); + dmac.ls_offset = m_offset; dmac.proxy_pos = 0; dmac.queue_pos = 0; diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 7dc71b74f1..de0b0f17a8 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -249,12 +249,30 @@ union SPU_SPR_hdr } }; +union SPU_SNRConfig_hdr +{ + u64 value; + + SPU_SNRConfig_hdr() {} + + wxString ToString() const + { + return wxString::Format("%01x", value); + } + + void Reset() + { + memset(this, 0, sizeof(*this)); + } +}; + class SPUThread : public PPCThread { public: SPU_GPR_hdr GPR[128]; //General-Purpose Register SPU_SPR_hdr SPR[128]; //Special-Purpose Registers FPSCR FPSCR; + SPU_SNRConfig_hdr cfg; //Signal Notification Registers Configuration (OR-mode enabled: 0x1 for SNR1, 0x2 for SNR2) template class Channel @@ -322,6 +340,18 @@ public: m_lock = 0; } + __forceinline void PushUncond_OR(u32 value) + { + while (_InterlockedExchange(&m_lock, 1)); + _mm_lfence(); + if(m_index >= max_count) + m_value[max_count-1] |= value; //last message is logically ORed + else + m_value[m_index++] = value; + _mm_sfence(); + m_lock = 0; + } + __forceinline void PopUncond(u32& res) { while (_InterlockedExchange(&m_lock, 1)); @@ -385,8 +415,7 @@ public: Channel<1> RunCntl; Channel<1> Status; Channel<1> NPC; - Channel<1> RdSigNotify1; - Channel<1> RdSigNotify2; + Channel<1> SNR[2]; } SPU; u32 LSA; @@ -404,31 +433,29 @@ public: u32 cmd = MFCArgs.CMDStatus.GetValue(); u16 op = cmd & MFC_MASK_CMD; + u32 lsa = MFCArgs.LSA.GetValue(); + u64 ea = (u64)MFCArgs.EAL.GetValue() | ((u64)MFCArgs.EAH.GetValue() << 32); + u32 size_tag = MFCArgs.Size_Tag.GetValue(); + u16 tag = (u16)size_tag; + u16 size = size_tag >> 16; + switch(op & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK)) { case MFC_PUT_CMD: case MFC_GET_CMD: { - u32 lsa = MFCArgs.LSA.GetValue(); - u64 ea = (u64)MFCArgs.EAL.GetValue() | ((u64)MFCArgs.EAH.GetValue() << 32); - u32 size_tag = MFCArgs.Size_Tag.GetValue(); - 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(); - + ConLog.Warning("DMA %s%s%s: lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x", + op & MFC_PUT_CMD ? "PUT" : "GET", + op & MFC_BARRIER_MASK ? "B" : "", + op & MFC_FENCE_MASK ? "F" : "", + lsa, ea, tag, size, cmd); MFCArgs.CMDStatus.SetValue(dmac.Cmd(cmd, tag, lsa, ea, size)); } break; default: - ConLog.Error("Unknown MFC cmd. (opcode=0x%x, cmd=0x%x)", op, cmd); + ConLog.Error("Unknown MFC cmd. (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)", + op, cmd, lsa, ea, tag, size); break; } } @@ -446,6 +473,15 @@ public: case SPU_WrOutIntrMbox: return 0;//return SPU.OutIntr_Mbox.GetFreeCount(); + case MFC_RdTagStat: + return Prxy.TagStatus.GetCount(); + + case SPU_RdSigNotify1: + return SPU.SNR[0].GetCount(); + + case SPU_RdSigNotify2: + return SPU.SNR[1].GetCount(); + default: ConLog.Error("%s error: unknown/illegal channel (%d [%s]).", __FUNCTION__, ch, spu_ch_name[ch]); break; @@ -458,30 +494,26 @@ public: { const u32 v = r._u32[3]; - ConLog.Warning("%s: %s = 0x%x", __FUNCTION__, spu_ch_name[ch], v); - switch(ch) { case SPU_WrOutIntrMbox: - while(!SPU.OutIntr_Mbox.Push(v) && !Emu.IsStopped()) - { - Sleep(1); - } + ConLog.Warning("%s: %s = 0x%x", __FUNCTION__, spu_ch_name[ch], v); + while (!SPU.OutIntr_Mbox.Push(v) && !Emu.IsStopped()) _mm_pause(); break; case SPU_WrOutMbox: - while(!SPU.Out_MBox.Push(v) && !Emu.IsStopped()) - { - Sleep(1); - } + ConLog.Warning("%s: %s = 0x%x", __FUNCTION__, spu_ch_name[ch], v); + while (!SPU.Out_MBox.Push(v) && !Emu.IsStopped()) _mm_pause(); break; case MFC_WrTagMask: + //ConLog.Warning("%s: %s = 0x%x", __FUNCTION__, spu_ch_name[ch], v); Prxy.QueryMask.SetValue(v); break; case MFC_WrTagUpdate: - Prxy.TagStatus.SetValue(Prxy.QueryMask.GetValue()); + //ConLog.Warning("%s: %s = 0x%x", __FUNCTION__, spu_ch_name[ch], v); + Prxy.TagStatus.PushUncond(Prxy.QueryMask.GetValue()); break; case MFC_LSA: @@ -523,19 +555,30 @@ public: switch(ch) { case SPU_RdInMbox: - if(!SPU.In_MBox.Pop(v)) v = 0; + while (!SPU.In_MBox.Pop(v) && !Emu.IsStopped()) _mm_pause(); + ConLog.Warning("%s: 0x%x = %s", __FUNCTION__, v, spu_ch_name[ch]); break; case MFC_RdTagStat: - v = Prxy.TagStatus.GetValue(); + while (dmac.proxy_pos) dmac.DoCmd(); //probably incompatible with MFC lists + while (!Prxy.TagStatus.Pop(v) && !Emu.IsStopped()) _mm_pause(); + //ConLog.Warning("%s: 0x%x = %s", __FUNCTION__, v, spu_ch_name[ch]); + break; + + case SPU_RdSigNotify1: + while (!SPU.SNR[0].Pop(v) && !Emu.IsStopped()) _mm_pause(); + ConLog.Warning("%s: 0x%x = %s", __FUNCTION__, v, spu_ch_name[ch]); + break; + + case SPU_RdSigNotify2: + while (!SPU.SNR[1].Pop(v) && !Emu.IsStopped()) _mm_pause(); + //ConLog.Warning("%s: 0x%x = %s", __FUNCTION__, v, spu_ch_name[ch]); break; default: ConLog.Error("%s error: unknown/illegal channel (%d [%s]).", __FUNCTION__, ch, spu_ch_name[ch]); break; } - - ConLog.Warning("%s: 0x%x = %s", __FUNCTION__, v, spu_ch_name[ch]); } bool IsGoodLSA(const u32 lsa) const { return Memory.IsGoodAddr(lsa + m_offset) && lsa < 0x40000; } diff --git a/rpcs3/Emu/SysCalls/SysCalls.cpp b/rpcs3/Emu/SysCalls/SysCalls.cpp index 686e5e78b7..959fd93dd1 100644 --- a/rpcs3/Emu/SysCalls/SysCalls.cpp +++ b/rpcs3/Emu/SysCalls/SysCalls.cpp @@ -97,8 +97,8 @@ static func_caller* sc_table[1024] = null_func, null_func, null_func, null_func, bind_func(sys_spu_initialize), //169 bind_func(sys_spu_thread_group_create), bind_func(sys_spu_thread_set_argument), bind_func(sys_spu_thread_initialize), bind_func(sys_spu_thread_group_start), null_func, //174 null_func, null_func, null_func, null_func, null_func, //179 - null_func, bind_func(sys_spu_thread_write_ls), bind_func(sys_spu_thread_read_ls), null_func, null_func, //184 - null_func, null_func, null_func, null_func, null_func, //189 + null_func, bind_func(sys_spu_thread_write_ls), bind_func(sys_spu_thread_read_ls), null_func, bind_func(sys_spu_thread_write_snr), //184 + null_func, null_func, bind_func(sys_spu_thread_set_spu_cfg), bind_func(sys_spu_thread_get_spu_cfg), null_func, //189 bind_func(sys_spu_thread_write_spu_mb), bind_func(sys_spu_thread_connect_event), null_func, null_func, null_func, //194 null_func, null_func, null_func, null_func, null_func, //199 null_func, null_func, null_func, null_func, null_func, //204 diff --git a/rpcs3/Emu/SysCalls/SysCalls.h b/rpcs3/Emu/SysCalls/SysCalls.h index 7dfb90e6cf..02e481cf6c 100644 --- a/rpcs3/Emu/SysCalls/SysCalls.h +++ b/rpcs3/Emu/SysCalls/SysCalls.h @@ -292,6 +292,9 @@ extern int sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu); extern int sys_spu_thread_write_ls(u32 id, u32 address, u64 value, u32 type); extern int sys_spu_thread_read_ls(u32 id, u32 address, mem64_t value, u32 type); extern int sys_spu_thread_write_spu_mb(u32 id, u32 value); +extern int sys_spu_thread_set_spu_cfg(u32 id, u64 value); +extern int sys_spu_thread_get_spu_cfg(u32 id, mem64_t value); +extern int sys_spu_thread_write_snr(u32 id, u32 number, u32 value); //sys_time extern int sys_time_get_timezone(mem32_t timezone, mem32_t summertime); diff --git a/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp b/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp index b888915c28..23e84922bb 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp @@ -21,12 +21,14 @@ struct SpuGroupInfo }; u64 g_spu_offset = 0; +u64 g_spu_alloc_size = 0; u32 LoadSpuImage(vfsStream& stream) { ELFLoader l(stream); l.LoadInfo(); - g_spu_offset = Memory.MainMem.Alloc(0xFFFFED - stream.GetSize()); + g_spu_alloc_size = 0xFFFFED - stream.GetSize(); + g_spu_offset = Memory.MainMem.Alloc(g_spu_alloc_size); l.LoadData(g_spu_offset); return g_spu_offset + l.GetEntry(); @@ -56,6 +58,7 @@ int sys_spu_image_open(mem_ptr_t img, u32 path_addr) img->entry_point = entry; img->segs_addr = 0x0; img->nsegs = 0; + img->_img_offs = g_spu_offset; return CELL_OK; } @@ -93,37 +96,42 @@ int sys_spu_thread_initialize(mem32_t thread, u32 group, u32 spu_num, mem_ptr_t< return CELL_EBUSY; } - u32 entry = img->entry_point; + u32 ls_entry = img->entry_point - img->_img_offs; std::string name = Memory.ReadString(attr->name_addr, attr->name_len).mb_str(); u64 a1 = arg->arg1; u64 a2 = arg->arg2; u64 a3 = arg->arg3; u64 a4 = arg->arg4; + CPUThread& new_thread = Emu.GetCPU().AddThread(CPU_THREAD_SPU); + //copy SPU image: + g_spu_alloc_size = 256 * 1024; + g_spu_offset = Memory.MainMem.Alloc(g_spu_alloc_size); + memcpy(Memory + g_spu_offset, Memory + img->_img_offs, g_spu_alloc_size); + //initialize from new place: + new_thread.SetOffset(g_spu_offset); + new_thread.SetEntry(ls_entry); + new_thread.SetName(name); + new_thread.SetArg(0, a1); + new_thread.SetArg(1, a2); + new_thread.SetArg(2, a3); + new_thread.SetArg(3, a4); + new_thread.Run(); + + thread = new_thread.GetId(); + + group_info.threads[spu_num] = &new_thread; + ConLog.Write("New SPU Thread:"); - ConLog.Write("entry = 0x%x", entry); + ConLog.Write("ls_entry = 0x%x", ls_entry); ConLog.Write("name = %s", name); ConLog.Write("a1 = 0x%x", a1); ConLog.Write("a2 = 0x%x", a2); ConLog.Write("a3 = 0x%x", a3); ConLog.Write("a4 = 0x%x", a4); + ConLog.Write("ls_offset = 0x%x", ((SPUThread&)new_thread).dmac.ls_offset); ConLog.SkipLn(); - CPUThread& new_thread = Emu.GetCPU().AddThread(CPU_THREAD_SPU); - new_thread.SetOffset(g_spu_offset); - new_thread.SetEntry(entry - g_spu_offset); - new_thread.SetName(name); - new_thread.Run(); - new_thread.Pause(); - new_thread.SetArg(0, a1); - new_thread.SetArg(1, a2); - new_thread.SetArg(2, a3); - new_thread.SetArg(3, a4); - - thread = new_thread.GetId(); - - group_info.threads[spu_num] = &new_thread; - return CELL_OK; } @@ -164,7 +172,7 @@ int sys_spu_thread_group_start(u32 id) ID& id_data = Emu.GetIdManager().GetIDData(id); SpuGroupInfo& group_info = *(SpuGroupInfo*)id_data.m_data; - Emu.Pause(); + //Emu.Pause(); for(int i=0; iGetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) + { + return CELL_ESRCH; + } + + if (value > 3) + { + return CELL_EINVAL; + } + + (*(SPUThread*)thr).cfg.value = value; + + return CELL_OK; +} + +//188 +int sys_spu_thread_get_spu_cfg(u32 id, mem64_t value) +{ + sc_spu.Warning("sys_spu_thread_get_spu_cfg(id=0x%x, value_addr=0x%x)", id, value.GetAddr()); + + CPUThread* thr = Emu.GetCPU().GetThread(id); + + if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) + { + return CELL_ESRCH; + } + + value = (*(SPUThread*)thr).cfg.value; + + return CELL_OK; +} + +//184 +int sys_spu_thread_write_snr(u32 id, u32 number, u32 value) +{ + CPUThread* thr = Emu.GetCPU().GetThread(id); + + if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) + { + return CELL_ESRCH; + } + + if (number > 1) + { + return CELL_EINVAL; + } + + if ((*(SPUThread*)thr).cfg.value & (1< entry_point; be_t segs_addr; be_t nsegs; + u64 _img_offs; };