New functions

sys_spu_thread_bind_queue, sys_spu_thread_connect_event and SPU-side
sys_spu_thread_receive_event, sys_spu_thread_send_event
Fixed event system
Fixed SleepQueue priority alg
Audio: cellAudioGetPortTimestamp and cellAudioGetPortBlockTag
This commit is contained in:
Nekotekina 2014-02-22 04:26:50 +04:00
parent 81147506f0
commit b56df0c7f6
10 changed files with 477 additions and 197 deletions

View File

@ -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()
{

View File

@ -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;
}
}
}

View File

@ -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<size_t _max_count>
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();

View File

@ -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;

View File

@ -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<CellAudioPortParam> 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<CellAudioPortConfig> 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;
}

View File

@ -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<sys_event_queue_attr> 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<sys_event_data> _event, u64 timeout);
extern int sys_event_queue_receive(u32 equeue_id, mem_ptr_t<sys_event_data> event, u64 timeout);
extern int sys_event_queue_tryreceive(u32 equeue_id, mem_ptr_t<sys_event_data> 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);

View File

@ -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<sys_event_data> 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<sys_event_data> 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<sys_event_data> 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<sys_event_data> 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; i<equeue->pos; ++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; i<equeue->pos; 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;
}

View File

@ -28,8 +28,9 @@ int sys_lwmutex_create(mem_ptr_t<sys_lwmutex_t> lwmutex, mem_ptr_t<sys_lwmutex_a
}
lwmutex->attribute = 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;
}
}

View File

@ -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; j<equeue->pos; ++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;
}
}

View File

@ -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;