diff --git a/rpcs3/Emu/Cell/SPUInterpreter.h b/rpcs3/Emu/Cell/SPUInterpreter.h index 9cae507585..1955137b5c 100644 --- a/rpcs3/Emu/Cell/SPUInterpreter.h +++ b/rpcs3/Emu/Cell/SPUInterpreter.h @@ -936,7 +936,8 @@ private: void FSCRRD(u32 rt) { - UNIMPLEMENTED(); // TODO (rarely used) + // TODO (rarely used) + CPU.GPR[rt].Reset(); } void FESD(u32 rt, u32 ra) { @@ -952,7 +953,12 @@ private: } void FSCRWR(u32 rt, u32 ra) { - UNIMPLEMENTED(); // TODO (rarely used) + // TODO (rarely used) + if (CPU.GPR[ra]._u128) + { + LOG_ERROR(SPU, "FSCRWR(%d,%d): value = %s", rt, ra, CPU.GPR[ra].ToString().c_str()); + UNIMPLEMENTED(); + } } void DFTSV(u32 rt, u32 ra, s32 i7) { diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 559861ddd3..b7a0c6787b 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -81,6 +81,9 @@ void SPUThread::InitRegs() MFC1.TagStatus.SetValue(0); MFC2.TagStatus.SetValue(0); //PC = SPU.NPC.GetValue(); + + m_event_mask = 0; + m_events = 0; } u64 SPUThread::GetFreeStackSize() const diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 3e2df02763..b883feb9e6 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -106,6 +106,24 @@ enum MFCchannels MFC_RdAtomicStat = 27, //Read completion status of last completed immediate MFC atomic update command }; +enum SPUEvents +{ + SPU_EVENT_MS = 0x1000, // multisource synchronization event + SPU_EVENT_A = 0x800, // privileged attention event + SPU_EVENT_LR = 0x400, // lock line reservation lost event + SPU_EVENT_S1 = 0x200, // signal notification register 1 available + SPU_EVENT_S2 = 0x100, // signal notification register 2 available + SPU_EVENT_LE = 0x80, // SPU outbound mailbox available + SPU_EVENT_ME = 0x40, // SPU outbound interrupt mailbox available + SPU_EVENT_TM = 0x20, // SPU decrementer became negative (?) + SPU_EVENT_MB = 0x10, // SPU inbound mailbox available + SPU_EVENT_QV = 0x4, // MFC SPU command queue available + SPU_EVENT_SN = 0x2, // MFC list command stall-and-notify event + SPU_EVENT_TG = 0x1, // MFC tag-group status update event + + SPU_EVENT_IMPLEMENTED = SPU_EVENT_LR, +}; + enum { SPU_RUNCNTL_STOP = 0, @@ -302,6 +320,9 @@ public: u64 m_dec_start; // timestamp of writing decrementer value u32 m_dec_value; // written decrementer value + u32 m_event_mask; + u32 m_events; + struct IntrTag { u32 enabled; // 1 == true @@ -855,6 +876,32 @@ public: } } + bool CheckEvents() // checks events + { + // SPU_EVENT_LR: + { + SMutexLockerR lock(reservation.mutex); + + if (reservation.owner == lock.tid) + { + for (u32 i = 0; i < 16; i++) + { + if (*(u64*)&Memory[reservation.addr + i * 8] != reservation.data[i]) + { + m_events |= SPU_EVENT_LR; + reservation.clear(); + } + } + } + else + { + m_events |= SPU_EVENT_LR; // ??? + } + } + + return (m_events & m_event_mask) != 0; + } + u32 GetChannelCount(u32 ch) { switch(ch) @@ -868,6 +915,7 @@ public: case SPU_RdSigNotify1: return SPU.SNR[0].GetCount(); case SPU_RdSigNotify2: return SPU.SNR[1].GetCount(); case MFC_RdAtomicStat: return MFC1.AtomicStat.GetCount(); + case SPU_RdEventStat: return CheckEvents() ? 1 : 0; default: { @@ -1112,6 +1160,19 @@ public: break; } + case SPU_WrEventMask: + { + m_event_mask = v; + if (v & ~(SPU_EVENT_IMPLEMENTED)) LOG_ERROR(Log::SPU, "SPU_WrEventMask: unsupported event masked (0x%x)"); + break; + } + + case SPU_WrEventAck: + { + m_events &= ~v; + break; + } + default: { LOG_ERROR(Log::SPU, "%s error (v=0x%x): unknown/illegal channel (%d [%s]).", __FUNCTION__, v, ch, spu_ch_name[ch]); @@ -1141,6 +1202,12 @@ public: break; } + case MFC_RdTagMask: + { + v = MFC1.QueryMask.GetValue(); + break; + } + case SPU_RdSigNotify1: { while (!SPU.SNR[0].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); @@ -1171,6 +1238,19 @@ public: break; } + case SPU_RdEventMask: + { + v = m_event_mask; + break; + } + + case SPU_RdEventStat: + { + while (!CheckEvents() && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + v = m_events & m_event_mask; + break; + } + default: { LOG_ERROR(Log::SPU, "%s error: unknown/illegal channel (%d [%s]).", __FUNCTION__, ch, spu_ch_name[ch]); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp index db11e00f77..0f44d19821 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp @@ -2261,10 +2261,54 @@ void cellSync_init() FIX_IMPORT(sysPrxForUser, _sys_vprintf , libsre + 0x1D97C); FIX_IMPORT(sysPrxForUser, _sys_memcmp , libsre + 0x1D99C); - // fix xrefs - for (u32 i = libsre + 0x30EAC; i < libsre + 0x31EE0; i += 4) + const u32 seg2 = 0x2DF00; + // start of table: + // addr = (u64) addr - seg2, (u32) 1, (u32) 1, (u64) ptr + // addr = (u64) addr - seg2, (u32) 0x101, (u32) 1, (u64) ptr - seg2 (???) + // addr = (u64) addr, (u32) 0x100, (u32) 1, (u64) ptr - seg2 (???) + // addr = (u64) addr, (u32) 0, (u32) 1, (u64) ptr (???) + + for (u32 i = libsre + 0x31EE0; i < libsre + 0x3A4F0; i += 24) { - Memory.Write32(i, Memory.Read32(i) + libsre); + u64 addr = Memory.Read64(i); + const u64 flag = Memory.Read64(i + 8); + + if (flag == 0x10100000001ull) + { + addr = addr + seg2 + libsre; + u32 value = Memory.Read32(addr); + assert(value == Memory.Read64(i + 16) + seg2); + Memory.Write32(addr, value + libsre); + } + else if (flag == 0x100000001ull) + { + addr = addr + seg2 + libsre; + u32 value = Memory.Read32(addr); + assert(value == Memory.Read64(i + 16)); + Memory.Write32(addr, value + libsre); + } + else if (flag == 0x10000000001ull) + { + addr = addr + libsre; + u32 value = Memory.Read32(addr); + assert(value == Memory.Read64(i + 16) + seg2); + Memory.Write32(addr, value + libsre); + } + else if (flag == 1) + { + addr = addr + libsre; + u32 value = Memory.Read32(addr); + assert(value == Memory.Read64(i + 16)); + Memory.Write32(addr, value + libsre); + } + else if (flag == 0x10000000004ull || flag == 0x10000000006ull) + { + // seems to be instruction modifiers for imports (done in other way in FIX_IMPORT) + } + else + { + LOG_NOTICE(HLE, "libsre: 0x%x : 0x%llx", i - libsre, flag); + } } }); #endif