mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-14 10:21:21 +00:00
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:
parent
81147506f0
commit
b56df0c7f6
@ -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()
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user