diff --git a/rpcs3/Emu/Cell/SPUInterpreter.h b/rpcs3/Emu/Cell/SPUInterpreter.h index 2f087d0fac..d90e8e0bed 100644 --- a/rpcs3/Emu/Cell/SPUInterpreter.h +++ b/rpcs3/Emu/Cell/SPUInterpreter.h @@ -32,12 +32,99 @@ private: //0 - 10 void STOP(u32 code) { - if (CPU.SPU.Out_MBox.GetCount()) // the real exit status is probably stored there - ConLog.Warning("STOP: 0x%x (message=0x%x)", code, CPU.SPU.Out_MBox.GetValue()); - else - ConLog.Warning("STOP: 0x%x (no message)", code); - CPU.SetExitStatus(code); - CPU.Stop(); + CPU.SetExitStatus(code); // exit code (not status) + + switch (code) + { + case 0x110: /* ===== sys_spu_thread_receive_event ===== */ + { + u32 spuq = 0; + if (!CPU.SPU.Out_MBox.Pop(spuq)) + { + ConLog.Error("sys_spu_thread_receive_event: cannot read Out_MBox"); + CPU.SPU.In_MBox.PushUncond(CELL_EINVAL); // ??? + return; + } + + if (CPU.SPU.In_MBox.GetCount()) + { + ConLog.Error("sys_spu_thread_receive_event(spuq=0x%x): In_MBox is not empty", spuq); + CPU.SPU.In_MBox.PushUncond(CELL_EBUSY); // ??? + return; + } + + if (Ini.HLELogging.GetValue()) + { + ConLog.Write("sys_spu_thread_receive_event(spuq=0x%x)", spuq); + } + + EventQueue* eq; + if (!CPU.SPUQs.GetEventQueue(FIX_SPUQ(spuq), eq)) + { + CPU.SPU.In_MBox.PushUncond(CELL_EINVAL); // TODO: check error value + return; + } + + u32 tid = GetCurrentSPUThread().GetId(); + + eq->sq.push(tid); // add thread to sleep queue + + while (true) + { + switch (eq->owner.trylock(tid)) + { + case SMR_OK: + if (!eq->events.count()) + { + eq->owner.unlock(tid); + break; + } + else + { + u32 next = (eq->protocol == SYS_SYNC_FIFO) ? eq->sq.pop() : eq->sq.pop_prio(); + if (next != tid) + { + eq->owner.unlock(tid, next); + break; + } + } + case SMR_SIGNAL: + { + sys_event_data event; + eq->events.pop(event); + eq->owner.unlock(tid); + CPU.SPU.In_MBox.PushUncond(CELL_OK); + CPU.SPU.In_MBox.PushUncond(event.data1); + CPU.SPU.In_MBox.PushUncond(event.data2); + CPU.SPU.In_MBox.PushUncond(event.data3); + return; + } + case SMR_FAILED: break; + default: eq->sq.invalidate(tid); CPU.SPU.In_MBox.PushUncond(CELL_ECANCELED); return; + } + + Sleep(1); + if (Emu.IsStopped()) + { + ConLog.Warning("sys_spu_thread_receive_event(spuq=0x%x) aborted", spuq); + eq->sq.invalidate(tid); + return; + } + } + } + break; + case 0x102: default: + if (!CPU.SPU.Out_MBox.GetCount()) // the real exit status + { + ConLog.Warning("STOP: 0x%x (no message)", code); + } + else if (Ini.HLELogging.GetValue() || code != 0x102) + { + ConLog.Warning("STOP: 0x%x (message=0x%x)", code, CPU.SPU.Out_MBox.GetValue()); + } + CPU.Stop(); + break; + } } void LNOP() { diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 6a0d8f5892..2e32989e08 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -95,3 +95,22 @@ void SPUThread::DoStop() delete m_dec; m_dec = nullptr; } + +void SPUThread::DoClose() +{ + // disconnect all event ports + if (Emu.IsStopped()) + { + return; + } + for (u32 i = 0; i < 64; i++) + { + EventPort& port = SPUPs[i]; + SMutexLocker lock(port.mutex); + if (port.eq) + { + port.eq->ports.remove(&port); + port.eq = nullptr; + } + } +} \ No newline at end of file diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 89f39c32ce..fcaccd72c9 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -275,6 +275,9 @@ public: FPSCR FPSCR; SPU_SNRConfig_hdr cfg; //Signal Notification Registers Configuration (OR-mode enabled: 0x1 for SNR1, 0x2 for SNR2) + EventPort SPUPs[64]; // SPU Thread Event Ports + EventManager SPUQs; // SPU Queue Mapping + template class Channel { @@ -317,8 +320,13 @@ public: { return false; } - res = m_value[--m_index]; - m_value[m_index] = 0; + res = m_value[0]; + for (u32 i = 1; i < max_count; i++) // FIFO + { + m_value[i-1] = m_value[i]; + } + m_value[max_count-1] = 0; + m_index--; return true; } else @@ -479,7 +487,6 @@ public: struct { Channel<1> Out_MBox; - Channel<1> OutIntr_Mbox; Channel<4> In_MBox; Channel<1> MBox_Status; Channel<1> RunCntl; @@ -616,11 +623,14 @@ public: case SPU_WrOutIntrMbox: ConLog.Warning("GetChannelCount(%s) = 0", wxString(spu_ch_name[ch]).wx_str()); - return 0;//return SPU.OutIntr_Mbox.GetFreeCount(); + return 0; case MFC_RdTagStat: return Prxy.TagStatus.GetCount(); + case MFC_WrTagUpdate: + return Prxy.TagStatus.GetCount(); // hack + case SPU_RdSigNotify1: return SPU.SNR[0].GetCount(); @@ -646,12 +656,63 @@ public: switch(ch) { case SPU_WrOutIntrMbox: - ConLog.Warning("%s: %s = 0x%x", wxString(__FUNCTION__).wx_str(), wxString(spu_ch_name[ch]).wx_str(), v); - while (!SPU.OutIntr_Mbox.Push(v) && !Emu.IsStopped()) Sleep(1); + { + u8 code = v >> 24; + if (code < 64) + { + /* ===== sys_spu_thread_send_event ===== */ + + u8 spup = code & 63; + + u32 data; + if (!SPU.Out_MBox.Pop(data)) + { + ConLog.Error("sys_spu_thread_send_event(v=0x%x, spup=%d): Out_MBox is empty", v, spup); + return; + } + + if (SPU.In_MBox.GetCount()) + { + ConLog.Error("sys_spu_thread_send_event(v=0x%x, spup=%d): In_MBox is not empty", v, spup); + SPU.In_MBox.PushUncond(CELL_EBUSY); // ??? + return; + } + + if (Ini.HLELogging.GetValue()) + { + ConLog.Write("sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x)", spup, v & 0x00ffffff, data); + } + + EventPort& port = SPUPs[spup]; + + SMutexLocker lock(port.mutex); + + if (!port.eq) + { + SPU.In_MBox.PushUncond(CELL_ENOTCONN); // check error passing + return; + } + + if (!port.eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, lock.tid, ((u64)code << 32) | (v & 0x00ffffff), data)) + { + SPU.In_MBox.PushUncond(CELL_EBUSY); + return; + } + + SPU.In_MBox.PushUncond(CELL_OK); + return; + } + else + { + ConLog.Error("SPU_WrOutIntrMbox: unknown data (v=0x%x)", v); + SPU.In_MBox.PushUncond(CELL_EINVAL); // ??? + return; + } + } break; case SPU_WrOutMbox: - ConLog.Warning("%s: %s = 0x%x", wxString(__FUNCTION__).wx_str(), wxString(spu_ch_name[ch]).wx_str(), v); + //ConLog.Warning("%s: %s = 0x%x", wxString(__FUNCTION__).wx_str(), wxString(spu_ch_name[ch]).wx_str(), v); while (!SPU.Out_MBox.Push(v) && !Emu.IsStopped()) Sleep(1); break; @@ -707,7 +768,7 @@ public: { case SPU_RdInMbox: while (!SPU.In_MBox.Pop(v) && !Emu.IsStopped()) Sleep(1); - ConLog.Warning("%s: 0x%x = %s", wxString(__FUNCTION__).wx_str(), v, wxString(spu_ch_name[ch]).wx_str()); + //ConLog.Warning("%s: 0x%x = %s", wxString(__FUNCTION__).wx_str(), v, wxString(spu_ch_name[ch]).wx_str()); break; case MFC_RdTagStat: @@ -738,7 +799,7 @@ public: } bool IsGoodLSA(const u32 lsa) const { return Memory.IsGoodAddr(lsa + m_offset) && lsa < 0x40000; } - virtual u8 ReadLS8 (const u32 lsa) const { return Memory.Read8 (lsa + (m_offset & 0x3fffc)); } + virtual u8 ReadLS8 (const u32 lsa) const { return Memory.Read8 (lsa + m_offset); } // m_offset & 0x3fffc ????? virtual u16 ReadLS16 (const u32 lsa) const { return Memory.Read16 (lsa + m_offset); } virtual u32 ReadLS32 (const u32 lsa) const { return Memory.Read32 (lsa + m_offset); } virtual u64 ReadLS64 (const u32 lsa) const { return Memory.Read64 (lsa + m_offset); } @@ -805,6 +866,7 @@ protected: virtual void DoPause(); virtual void DoResume(); virtual void DoStop(); + virtual void DoClose(); }; SPUThread& GetCurrentSPUThread(); diff --git a/rpcs3/Emu/Event.cpp b/rpcs3/Emu/Event.cpp index 40290a9a94..e31e2601fa 100644 --- a/rpcs3/Emu/Event.cpp +++ b/rpcs3/Emu/Event.cpp @@ -26,6 +26,11 @@ bool EventManager::RegisterKey(EventQueue* data, u64 key) if (key_map.find(key) != key_map.end()) return false; + for (auto& v = key_map.begin(); v != key_map.end(); ++v) + { + if (v->second == data) return false; + } + key_map[key] = data; return true; diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp index 3f3058e7aa..2503d9c7fd 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp @@ -137,7 +137,12 @@ struct AudioPortConfig { bool m_is_audio_port_opened; bool m_is_audio_port_started; - CellAudioPortParam m_param; + u8 channel; + u8 block; + float level; + u64 attr; + u64 tag; + u64 counter; // copy of global counter }; struct AudioConfig //custom structure @@ -153,12 +158,15 @@ struct AudioConfig //custom structure bool m_is_audio_finalized; u32 m_port_in_use; u64 event_key; + u64 counter; + u64 start_time; AudioConfig() : m_is_audio_initialized(false) , m_is_audio_finalized(false) , m_port_in_use(0) , event_key(0) + , counter(0) { memset(&m_ports, 0, sizeof(AudioPortConfig) * AUDIO_PORT_COUNT); } @@ -282,6 +290,7 @@ int cellAudioInit() } m_config.m_is_audio_initialized = true; + m_config.counter = 0; // alloc memory m_config.m_buffer = Memory.Alloc(128 * 1024 * m_config.AUDIO_PORT_COUNT, 1024); @@ -289,7 +298,7 @@ int cellAudioInit() m_config.m_indexes = Memory.Alloc(sizeof(u64) * m_config.AUDIO_PORT_COUNT, 16); memset(Memory + m_config.m_indexes, 0, sizeof(u64) * m_config.AUDIO_PORT_COUNT); - thread t("Audio", []() + thread t("AudioThread", []() { WAVHeader header(2); // WAV file header (stereo) @@ -304,13 +313,14 @@ int cellAudioInit() ConLog.Write("Audio started"); - u64 start_time = get_system_time(); - u64 counter = 0; + m_config.start_time = get_system_time(); output.Write(&header, sizeof(header)); // write file header float buffer[2*256]; // buffer for 2 channels float buffer2[8*256]; // buffer for 8 channels (max count) + memset(&buffer, 0, sizeof(buffer)); + memset(&buffer2, 0, sizeof(buffer2)); while (m_config.m_is_audio_initialized) { @@ -323,13 +333,13 @@ int cellAudioInit() // TODO: send beforemix event (in ~2,6 ms before mixing) // Sleep(5); // precise time of sleeping: 5,(3) ms (or 256/48000 sec) - if (counter * 256000000 / 48000 >= get_system_time() - start_time) + if (m_config.counter * 256000000 / 48000 >= get_system_time() - m_config.start_time) { Sleep(1); continue; } - counter++; + m_config.counter++; if (Emu.IsPaused()) { @@ -346,16 +356,21 @@ int cellAudioInit() AudioPortConfig& port = m_config.m_ports[i]; mem64_t index(m_config.m_indexes + i * sizeof(u64)); - const u32 block_size = port.m_param.nChannel * 256; + const u32 block_size = port.channel * 256; - u32 position = index.GetValue(); // get old value + u32 position = port.tag % port.block; // old value u32 buf_addr = m_config.m_buffer + (i * 128 * 1024) + (position * block_size * sizeof(float)); memcpy(buffer2, Memory + buf_addr, block_size * sizeof(float)); memset(Memory + buf_addr, 0, block_size * sizeof(float)); - index = (position + 1) % port.m_param.nBlock; // write new value + // TODO: atomic + port.counter = m_config.counter; + port.tag++; // absolute index of block that will be read + index = (position + 1) % port.block; // write new value + + if (first_mix) { @@ -419,7 +434,7 @@ int cellAudioQuit() if (Emu.IsStopped()) { ConLog.Warning("cellAudioQuit() aborted"); - break; + return CELL_OK; } } @@ -451,20 +466,22 @@ int cellAudioPortOpen(mem_ptr_t audioParam, mem32_t portNum) { if (!m_config.m_ports[i].m_is_audio_port_opened) { - CellAudioPortParam& param = m_config.m_ports[i].m_param; + AudioPortConfig& port = m_config.m_ports[i]; - param.nChannel = audioParam->nChannel; - param.nBlock = audioParam->nBlock; - param.attr = audioParam->attr; - param.level = audioParam->level; + port.channel = audioParam->nChannel; + port.block = audioParam->nBlock; + port.attr = audioParam->attr; + port.level = audioParam->level; portNum = i; - cellAudio.Warning("*** audio port opened(nChannel=%lld, nBlock=0x%llx, attr=0x%llx, level=%f): port = %d", - (u64)param.nChannel, (u64)param.nBlock, (u64)param.attr, (float)param.level, i); + cellAudio.Warning("*** audio port opened(nChannel=%d, nBlock=%d, attr=0x%llx, level=%f): port = %d", + port.channel, port.block, port.attr, port.level, i); + port.m_is_audio_port_opened = true; + port.m_is_audio_port_started = false; + port.tag = 0; + m_config.m_port_in_use++; - m_config.m_ports[i].m_is_audio_port_opened = true; - m_config.m_ports[i].m_is_audio_port_started = false; return CELL_OK; } } @@ -494,15 +511,15 @@ int cellAudioGetPortConfig(u32 portNum, mem_ptr_t portConfi portConfig->status = CELL_AUDIO_STATUS_READY; } - CellAudioPortParam& ref = m_config.m_ports[portNum].m_param; + AudioPortConfig& port = m_config.m_ports[portNum]; - portConfig->nChannel = ref.nChannel; - portConfig->nBlock = ref.nBlock; - portConfig->portSize = ref.nChannel * ref.nBlock * 256 * sizeof(float); + portConfig->nChannel = port.channel; + portConfig->nBlock = port.block; + portConfig->portSize = port.channel * port.block * 256 * sizeof(float); portConfig->portAddr = m_config.m_buffer + (128 * 1024 * portNum); // 0x20020000 portConfig->readIndexAddr = m_config.m_indexes + (sizeof(u64) * portNum); // 0x20010010 on ps3 - ConLog.Write("*** nChannel=%d, nBlock=%d, portSize=0x%x, portAddr=0x%x, readIndexAddr=0x%x", + cellAudio.Log("*** port config: nChannel=%d, nBlock=%d, portSize=0x%x, portAddr=0x%x, readIndexAddr=0x%x", (u32)portConfig->nChannel, (u32)portConfig->nBlock, (u32)portConfig->portSize, (u32)portConfig->portAddr, (u32)portConfig->readIndexAddr); // portAddr - readIndexAddr == 0xFFF0 on ps3 @@ -577,13 +594,71 @@ int cellAudioPortStop(u32 portNum) int cellAudioGetPortTimestamp(u32 portNum, u64 tag, mem64_t stamp) { - cellAudio.Error("cellAudioGetPortTimestamp(portNum=0x%x, tag=0x%llx, stamp_addr=0x%x)", portNum, tag, stamp.GetAddr()); + cellAudio.Warning("cellAudioGetPortTimestamp(portNum=0x%x, tag=0x%llx, stamp_addr=0x%x)", portNum, tag, stamp.GetAddr()); + + if (portNum >= m_config.AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + if (!m_config.m_ports[portNum].m_is_audio_port_opened) + { + return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + } + + if (!m_config.m_ports[portNum].m_is_audio_port_started) + { + return CELL_AUDIO_ERROR_PORT_NOT_RUN; + } + + AudioPortConfig& port = m_config.m_ports[portNum]; + + // TODO: atomic + stamp = m_config.start_time + (port.counter + (tag - port.tag)) * 256000000 / 48000; + return CELL_OK; } int cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, mem64_t tag) { - cellAudio.Error("cellAudioGetPortBlockTag(portNum=0x%x, blockNo=0x%llx, tag_addr=0x%x)", portNum, blockNo, tag.GetAddr()); + cellAudio.Warning("cellAudioGetPortBlockTag(portNum=0x%x, blockNo=0x%llx, tag_addr=0x%x)", portNum, blockNo, tag.GetAddr()); + + if (portNum >= m_config.AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + if (!m_config.m_ports[portNum].m_is_audio_port_opened) + { + return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + } + + if (!m_config.m_ports[portNum].m_is_audio_port_started) + { + return CELL_AUDIO_ERROR_PORT_NOT_RUN; + } + + AudioPortConfig& port = m_config.m_ports[portNum]; + + if (blockNo >= port.block) + { + cellAudio.Error("cellAudioGetPortBlockTag: wrong blockNo(%lld)", blockNo); + return CELL_AUDIO_ERROR_PARAM; + } + + // TODO: atomic + u64 tag_base = port.tag; + if (tag_base % port.block > blockNo) + { + tag_base &= ~(port.block-1); + tag_base += port.block; + } + else + { + tag_base &= ~(port.block-1); + } + tag = tag_base + blockNo; + return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/SysCalls.h b/rpcs3/Emu/SysCalls/SysCalls.h index 531cb88f88..01e491f7b9 100644 --- a/rpcs3/Emu/SysCalls/SysCalls.h +++ b/rpcs3/Emu/SysCalls/SysCalls.h @@ -130,7 +130,7 @@ extern void sys_game_process_exitspawn2(u32 path_addr, u32 argv_addr, u32 envp_a //sys_event extern int sys_event_queue_create(mem32_t equeue_id, mem_ptr_t attr, u64 event_queue_key, int size); extern int sys_event_queue_destroy(u32 equeue_id, int mode); -extern int sys_event_queue_receive(u32 equeue_id, mem_ptr_t _event, u64 timeout); +extern int sys_event_queue_receive(u32 equeue_id, mem_ptr_t event, u64 timeout); extern int sys_event_queue_tryreceive(u32 equeue_id, mem_ptr_t event_array, int size, mem32_t number); extern int sys_event_queue_drain(u32 event_queue_id); extern int sys_event_port_create(mem32_t eport_id, int port_type, u64 name); diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Event.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Event.cpp index 3ca31155b1..8d9d9c2350 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Event.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Event.cpp @@ -74,18 +74,18 @@ int sys_event_queue_destroy(u32 equeue_id, int mode) u32 tid = GetCurrentPPUThread().GetId(); - eq->m_mutex.lock(tid); + eq->sq.m_mutex.lock(tid); eq->owner.lock(tid); // check if some threads are waiting for an event - if (!mode && eq->list.GetCount()) + if (!mode && eq->sq.list.GetCount()) { eq->owner.unlock(tid); - eq->m_mutex.unlock(tid); + eq->sq.m_mutex.unlock(tid); return CELL_EBUSY; } eq->owner.unlock(tid, ~0); - eq->m_mutex.unlock(tid); - while (eq->list.GetCount()) + eq->sq.m_mutex.unlock(tid); + while (eq->sq.list.GetCount()) { Sleep(1); if (Emu.IsStopped()) @@ -136,18 +136,18 @@ int sys_event_queue_tryreceive(u32 equeue_id, mem_ptr_t event_ar u32 tid = GetCurrentPPUThread().GetId(); - eq->m_mutex.lock(tid); + eq->sq.m_mutex.lock(tid); eq->owner.lock(tid); - if (eq->list.GetCount()) + if (eq->sq.list.GetCount()) { number = 0; eq->owner.unlock(tid); - eq->m_mutex.unlock(tid); + eq->sq.m_mutex.unlock(tid); return CELL_OK; } number = eq->events.pop_all((sys_event_data*)(Memory + event_array.GetAddr()), size); eq->owner.unlock(tid); - eq->m_mutex.unlock(tid); + eq->sq.m_mutex.unlock(tid); return CELL_OK; } @@ -174,7 +174,7 @@ int sys_event_queue_receive(u32 equeue_id, mem_ptr_t event, u64 u32 tid = GetCurrentPPUThread().GetId(); - eq->push(tid); // add thread to sleep queue + eq->sq.push(tid); // add thread to sleep queue timeout = timeout ? (timeout / 1000) : ~0; u64 counter = 0; @@ -190,7 +190,7 @@ int sys_event_queue_receive(u32 equeue_id, mem_ptr_t event, u64 } else { - u32 next = (eq->protocol == SYS_SYNC_FIFO) ? eq->pop() : eq->pop_prio(); + u32 next = (eq->protocol == SYS_SYNC_FIFO) ? eq->sq.pop() : eq->sq.pop_prio(); if (next != tid) { eq->owner.unlock(tid, next); @@ -201,78 +201,33 @@ int sys_event_queue_receive(u32 equeue_id, mem_ptr_t event, u64 { eq->events.pop(*event); eq->owner.unlock(tid); + sys_event.Log(" *** event received: source=0x%llx, d1=0x%llx, d2=0x%llx, d3=0x%llx", + (u64)event->source, (u64)event->data1, (u64)event->data2, (u64)event->data3); + /* HACK: passing event data in registers */ + PPUThread& t = GetCurrentPPUThread(); + t.GPR[4] = event->source; + t.GPR[5] = event->data1; + t.GPR[6] = event->data2; + t.GPR[7] = event->data3; return CELL_OK; } case SMR_FAILED: break; - default: eq->invalidate(tid); return CELL_ECANCELED; + default: eq->sq.invalidate(tid); return CELL_ECANCELED; } Sleep(1); if (counter++ > timeout || Emu.IsStopped()) { if (Emu.IsStopped()) ConLog.Warning("sys_event_queue_receive(equeue=%d) aborted", equeue_id); - eq->invalidate(tid); + eq->sq.invalidate(tid); return CELL_ETIMEDOUT; } } - /* auto queue_receive = [&](int status) -> bool - { - if(status == CPUThread_Stopped) - { - result = CELL_ECANCELED; - return false; - } - - EventQueue* equeue; - if (!Emu.GetIdManager().GetIDData(equeue_id, equeue)) - { - result = CELL_ESRCH; - return false; - } - - for(int i=0; ipos; ++i) - { - if(!equeue->ports[i]->has_data && equeue->ports[i]->thread) - { - SPUThread* thr = (SPUThread*)equeue->ports[i]->thread; - if(thr->SPU.OutIntr_Mbox.GetCount()) - { - u32 val; - thr->SPU.OutIntr_Mbox.Pop(val); - if(!thr->SPU.Out_MBox.Pop(val)) val = 0; - equeue->ports[i]->data1 = val; - equeue->ports[i]->data2 = 0; - equeue->ports[i]->data3 = 0; - equeue->ports[i]->has_data = true; - } - } - } - - for(int i=0; ipos; i++) - { - if(equeue->ports[i]->has_data) - { - event->source = equeue->ports[i]->name; - event->data1 = equeue->ports[i]->data1; - event->data2 = equeue->ports[i]->data2; - event->data3 = equeue->ports[i]->data3; - - equeue->ports[i]->has_data = false; - - result = CELL_OK; - return false; - } - } - - return true; - }; - - GetCurrentPPUThread().WaitFor(queue_receive);*/ } int sys_event_queue_drain(u32 equeue_id) { - sys_event.Warning("sys_event_queue_drain(equeue_id=%d)", equeue_id); + sys_event.Log("sys_event_queue_drain(equeue_id=%d)", equeue_id); EventQueue* eq; if (!Emu.GetIdManager().GetIDData(equeue_id, eq)) @@ -401,14 +356,14 @@ int sys_event_port_disconnect(u32 eport_id) } eport->eq->ports.remove(eport); - eport->eq = 0; + eport->eq = nullptr; eport->mutex.unlock(tid); return CELL_OK; } int sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3) { - sys_event.Warning("sys_event_port_send(eport_id=%d, data1=0x%llx, data2=0x%llx, data3=0x%llx)", + sys_event.Log("sys_event_port_send(eport_id=%d, data1=0x%llx, data2=0x%llx, data3=0x%llx)", eport_id, data1, data2, data3); EventPort* eport; @@ -419,12 +374,13 @@ int sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3) SMutexLocker lock(eport->mutex); - if (!eport->eq) + EventQueue* eq = eport->eq; + if (!eq) { return CELL_ENOTCONN; } - if (!eport->eq->events.push(eport->name, data1, data2, data3)) + if (!eq->events.push(eport->name, data1, data2, data3)) { return CELL_EBUSY; } diff --git a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp index 87d3968d10..b6783d63cd 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_Lwmutex.cpp @@ -28,8 +28,9 @@ int sys_lwmutex_create(mem_ptr_t lwmutex, mem_ptr_tattribute = attr->attr_protocol | attr->attr_recursive; + lwmutex->all_info = 0; lwmutex->owner.initialize(); - lwmutex->waiter = lwmutex->owner.GetOwner(); + //lwmutex->waiter = lwmutex->owner.GetOwner(); lwmutex->pad = 0; lwmutex->recursive_count = 0; @@ -130,7 +131,7 @@ u32 SleepQueue::pop_prio() // SYS_SYNC_PRIORITY { if (list.GetCount()) { - u64 max_prio = 0; + u32 highest_prio = ~0; u32 sel = 0; for (u32 i = 0; i < list.GetCount(); i++) { @@ -142,9 +143,9 @@ u32 SleepQueue::pop_prio() // SYS_SYNC_PRIORITY break; } u64 prio = t->GetPrio(); - if (prio > max_prio) + if (prio < highest_prio) { - max_prio = prio; + highest_prio = prio; sel = i; } } diff --git a/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp b/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp index a3adbb1270..1cf481be3d 100644 --- a/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp +++ b/rpcs3/Emu/SysCalls/lv2/SC_SPU_Thread.cpp @@ -222,6 +222,8 @@ int sys_spu_thread_group_destroy(u32 id) for (u32 i = 0; i < group_info->list.GetCount(); i++) { + // TODO: disconnect all event ports + Emu.GetCPU().RemoveThread(group_info->list[i]); } @@ -550,6 +552,152 @@ int sys_spu_thread_group_disconnect_event(u32 id, u32 et) return CELL_OK; } +/* +SPU-Side functions: +int sys_spu_thread_receive_event(u32 spuq_num, mem32_t d1, mem32_t d2, mem32_t d3); +int sys_spu_thread_send_event(u8 spup, u24 data0, u32 data1); +int sys_spu_thread_throw_event(u8 spup, u24 data0, u32 data1); +int sys_spu_thread_tryreceive_event(u32 spuq_num, mem32_t d1, mem32_t d2, mem32_t d3); +*/ + +int sys_spu_thread_connect_event(u32 id, u32 eq_id, u32 et, u8 spup) +{ + sc_spu.Warning("sys_spu_thread_connect_event(id=%d, eq_id=%d, event_type=0x%x, spup=%d)", id, eq_id, et, spup); + + CPUThread* thr = Emu.GetCPU().GetThread(id); + + if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) + { + return CELL_ESRCH; + } + + EventQueue* eq; + if (!Emu.GetIdManager().GetIDData(eq_id, eq)) + { + return CELL_ESRCH; + } + + if (spup > 63) + { + sc_spu.Error("sys_spu_thread_connect_event: invalid spup (%d)", spup); + return CELL_EINVAL; + } + + if (et != SYS_SPU_THREAD_EVENT_USER) + { + sc_spu.Error("sys_spu_thread_connect_event: unsupported event type (0x%x)", et); + return CELL_EINVAL; + } + + // TODO: check if can receive this events + + SPUThread& spu = *(SPUThread*)thr; + + EventPort& port = spu.SPUPs[spup]; + + SMutexLocker lock(port.mutex); + + if (port.eq) + { + return CELL_EISCONN; + } + + eq->ports.add(&port); + port.eq = eq; + + return CELL_OK; +} + +// +int sys_spu_thread_disconnect_event(u32 id, u32 et, u8 spup) +{ + sc_spu.Warning("sys_spu_thread_disconnect_event(id=%d, event_type=0x%x, spup=%d)", id, et, spup); + + CPUThread* thr = Emu.GetCPU().GetThread(id); + + if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) + { + return CELL_ESRCH; + } + + if (spup > 63) + { + sc_spu.Error("sys_spu_thread_connect_event: invalid spup (%d)", spup); + return CELL_EINVAL; + } + + if (et != SYS_SPU_THREAD_EVENT_USER) + { + sc_spu.Error("sys_spu_thread_connect_event: unsupported event type (0x%x)", et); + return CELL_EINVAL; + } + + SPUThread& spu = *(SPUThread*)thr; + + EventPort& port = spu.SPUPs[spup]; + + SMutexLocker lock(port.mutex); + + if (!port.eq) + { + return CELL_ENOTCONN; + } + + port.eq->ports.remove(&port); + port.eq = nullptr; + + return CELL_OK; +} + +int sys_spu_thread_bind_queue(u32 id, u32 eq_id, u32 spuq_num) +{ + sc_spu.Warning("sys_spu_thread_bind_queue(id=%d, equeue_id=%d, spuq_num=0x%x)", id, eq_id, spuq_num); + + EventQueue* eq; + if (!Emu.GetIdManager().GetIDData(eq_id, eq)) + { + return CELL_ESRCH; + } + + if (eq->type != SYS_SPU_QUEUE) + { + return CELL_EINVAL; + } + + CPUThread* thr = Emu.GetCPU().GetThread(id); + + if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) + { + return CELL_ESRCH; + } + + if (!(*(SPUThread*)thr).SPUQs.RegisterKey(eq, FIX_SPUQ(spuq_num))) + { + return CELL_EBUSY; + } + + return CELL_OK; +} + +int sys_spu_thread_unbind_queue(u32 id, u32 spuq_num) +{ + sc_spu.Warning("sys_spu_thread_unbind_queue(id=0x%x, spuq_num=0x%x)", id, spuq_num); + + CPUThread* thr = Emu.GetCPU().GetThread(id); + + if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) + { + return CELL_ESRCH; + } + + if (!(*(SPUThread*)thr).SPUQs.UnregisterKey(FIX_SPUQ(spuq_num))) + { + return CELL_ESRCH; // may be CELL_EINVAL + } + + return CELL_OK; +} + int sys_spu_thread_group_connect_event_all_threads(u32 id, u32 eq, u64 req, u32 spup_addr) { sc_spu.Error("sys_spu_thread_group_connect_event_all_threads(id=%d, eq=%d, req=0x%llx, spup_addr=0x%x)", @@ -602,82 +750,4 @@ int sys_spu_thread_group_disconnect_event_all_threads(u32 id, u8 spup) sc_spu.Error("sys_spu_thread_group_disconnect_event_all_threads(id=%d, spup=%d)", id, spup); return CELL_OK; -} - -int sys_spu_thread_connect_event(u32 id, u32 eq, u32 et, u8 spup) -{ - sc_spu.Error("sys_spu_thread_connect_event(id=%d, eq=%d, et=0x%x, spup=%d)", id, eq, et, spup); - - EventQueue* equeue; - if(!sys_event.CheckId(eq, equeue)) - { - return CELL_ESRCH; - } - - if(spup > 63) - { - return CELL_EINVAL; - } - - CPUThread* thr = Emu.GetCPU().GetThread(id); - - if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) - { - return CELL_ESRCH; - } - /* - for(int j=0; jpos; ++j) - { - if(!equeue->ports[j]->thread) - { - equeue->ports[j]->thread = thr; - return CELL_OK; - } - } - */ - - return CELL_EISCONN; -} - -// -int sys_spu_thread_disconnect_event(u32 id, u32 event_type, u8 spup) -{ - sc_spu.Error("sys_spu_thread_disconnect_event(id=%d, event_type=0x%x, spup=%d", id, event_type, spup); - - return CELL_OK; -} - -/* -SPU-Side functions: -int sys_spu_thread_receive_event(u32 spuq_num, mem32_t d1, mem32_t d2, mem32_t d3); -int sys_spu_thread_send_event(u8 spup, u24 data0, u32 data1); -int sys_spu_thread_throw_event(u8 spup, u24 data0, u32 data1); -int sys_spu_thread_tryreceive_event(u32 spuq_num, mem32_t d1, mem32_t d2, mem32_t d3); -*/ - -int sys_spu_thread_bind_queue(u32 id, u32 eq, u32 spuq_num) -{ - sc_spu.Error("sys_spu_thread_bind_queue(id=%d, equeue_id=%d, spuq_num=%d)", id, eq, spuq_num); - - EventQueue* equeue; - if(!sys_event.CheckId(eq, equeue)) - { - return CELL_ESRCH; - } - - CPUThread* thr = Emu.GetCPU().GetThread(id); - - if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU)) - { - return CELL_ESRCH; - } - - return CELL_OK; -} - -int sys_spu_thread_unbind_queue(u32 id, u32 spuq_num) -{ - sc_spu.Error("sys_spu_thread_unbind_queue(id=0x%x, spuq_num=%d)", id, spuq_num); - - return CELL_OK; -} +} \ No newline at end of file diff --git a/rpcs3/Emu/event.h b/rpcs3/Emu/event.h index 16ec0ab0b1..76d3802672 100644 --- a/rpcs3/Emu/event.h +++ b/rpcs3/Emu/event.h @@ -1,6 +1,9 @@ #pragma once #include "Emu/SysCalls/lv2/SC_Lwmutex.h" +#define FIX_SPUQ(x) ((u64)x | 0x5350555100000000ULL) +// arbitrary code to prevent "special" zero value in key argument + enum EventQueueType { SYS_PPU_QUEUE = 1, @@ -158,6 +161,7 @@ public: SMutexLocker lock(m_lock); for (u32 i = 0; i < data.GetCount(); i++) { + SMutexLocker lock2(data[i]->mutex); data[i]->eq = nullptr; // force all ports to disconnect } data.Clear(); @@ -183,8 +187,9 @@ public: } }; -struct EventQueue : SleepQueue +struct EventQueue { + SleepQueue sq; EventPortList ports; EventRingBuffer events; SMutex owner;