mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-29 22:20:48 +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
|
//0 - 10
|
||||||
void STOP(u32 code)
|
void STOP(u32 code)
|
||||||
{
|
{
|
||||||
if (CPU.SPU.Out_MBox.GetCount()) // the real exit status is probably stored there
|
CPU.SetExitStatus(code); // exit code (not status)
|
||||||
ConLog.Warning("STOP: 0x%x (message=0x%x)", code, CPU.SPU.Out_MBox.GetValue());
|
|
||||||
else
|
switch (code)
|
||||||
ConLog.Warning("STOP: 0x%x (no message)", code);
|
{
|
||||||
CPU.SetExitStatus(code);
|
case 0x110: /* ===== sys_spu_thread_receive_event ===== */
|
||||||
CPU.Stop();
|
{
|
||||||
|
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()
|
void LNOP()
|
||||||
{
|
{
|
||||||
|
@ -95,3 +95,22 @@ void SPUThread::DoStop()
|
|||||||
delete m_dec;
|
delete m_dec;
|
||||||
m_dec = nullptr;
|
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;
|
FPSCR FPSCR;
|
||||||
SPU_SNRConfig_hdr cfg; //Signal Notification Registers Configuration (OR-mode enabled: 0x1 for SNR1, 0x2 for SNR2)
|
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>
|
template<size_t _max_count>
|
||||||
class Channel
|
class Channel
|
||||||
{
|
{
|
||||||
@ -317,8 +320,13 @@ public:
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
res = m_value[--m_index];
|
res = m_value[0];
|
||||||
m_value[m_index] = 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;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -479,7 +487,6 @@ public:
|
|||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
Channel<1> Out_MBox;
|
Channel<1> Out_MBox;
|
||||||
Channel<1> OutIntr_Mbox;
|
|
||||||
Channel<4> In_MBox;
|
Channel<4> In_MBox;
|
||||||
Channel<1> MBox_Status;
|
Channel<1> MBox_Status;
|
||||||
Channel<1> RunCntl;
|
Channel<1> RunCntl;
|
||||||
@ -616,11 +623,14 @@ public:
|
|||||||
|
|
||||||
case SPU_WrOutIntrMbox:
|
case SPU_WrOutIntrMbox:
|
||||||
ConLog.Warning("GetChannelCount(%s) = 0", wxString(spu_ch_name[ch]).wx_str());
|
ConLog.Warning("GetChannelCount(%s) = 0", wxString(spu_ch_name[ch]).wx_str());
|
||||||
return 0;//return SPU.OutIntr_Mbox.GetFreeCount();
|
return 0;
|
||||||
|
|
||||||
case MFC_RdTagStat:
|
case MFC_RdTagStat:
|
||||||
return Prxy.TagStatus.GetCount();
|
return Prxy.TagStatus.GetCount();
|
||||||
|
|
||||||
|
case MFC_WrTagUpdate:
|
||||||
|
return Prxy.TagStatus.GetCount(); // hack
|
||||||
|
|
||||||
case SPU_RdSigNotify1:
|
case SPU_RdSigNotify1:
|
||||||
return SPU.SNR[0].GetCount();
|
return SPU.SNR[0].GetCount();
|
||||||
|
|
||||||
@ -646,12 +656,63 @@ public:
|
|||||||
switch(ch)
|
switch(ch)
|
||||||
{
|
{
|
||||||
case SPU_WrOutIntrMbox:
|
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;
|
break;
|
||||||
|
|
||||||
case SPU_WrOutMbox:
|
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);
|
while (!SPU.Out_MBox.Push(v) && !Emu.IsStopped()) Sleep(1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -707,7 +768,7 @@ public:
|
|||||||
{
|
{
|
||||||
case SPU_RdInMbox:
|
case SPU_RdInMbox:
|
||||||
while (!SPU.In_MBox.Pop(v) && !Emu.IsStopped()) Sleep(1);
|
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;
|
break;
|
||||||
|
|
||||||
case MFC_RdTagStat:
|
case MFC_RdTagStat:
|
||||||
@ -738,7 +799,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool IsGoodLSA(const u32 lsa) const { return Memory.IsGoodAddr(lsa + m_offset) && lsa < 0x40000; }
|
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 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 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); }
|
virtual u64 ReadLS64 (const u32 lsa) const { return Memory.Read64 (lsa + m_offset); }
|
||||||
@ -805,6 +866,7 @@ protected:
|
|||||||
virtual void DoPause();
|
virtual void DoPause();
|
||||||
virtual void DoResume();
|
virtual void DoResume();
|
||||||
virtual void DoStop();
|
virtual void DoStop();
|
||||||
|
virtual void DoClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
SPUThread& GetCurrentSPUThread();
|
SPUThread& GetCurrentSPUThread();
|
||||||
|
@ -26,6 +26,11 @@ bool EventManager::RegisterKey(EventQueue* data, u64 key)
|
|||||||
|
|
||||||
if (key_map.find(key) != key_map.end()) return false;
|
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;
|
key_map[key] = data;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -137,7 +137,12 @@ struct AudioPortConfig
|
|||||||
{
|
{
|
||||||
bool m_is_audio_port_opened;
|
bool m_is_audio_port_opened;
|
||||||
bool m_is_audio_port_started;
|
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
|
struct AudioConfig //custom structure
|
||||||
@ -153,12 +158,15 @@ struct AudioConfig //custom structure
|
|||||||
bool m_is_audio_finalized;
|
bool m_is_audio_finalized;
|
||||||
u32 m_port_in_use;
|
u32 m_port_in_use;
|
||||||
u64 event_key;
|
u64 event_key;
|
||||||
|
u64 counter;
|
||||||
|
u64 start_time;
|
||||||
|
|
||||||
AudioConfig()
|
AudioConfig()
|
||||||
: m_is_audio_initialized(false)
|
: m_is_audio_initialized(false)
|
||||||
, m_is_audio_finalized(false)
|
, m_is_audio_finalized(false)
|
||||||
, m_port_in_use(0)
|
, m_port_in_use(0)
|
||||||
, event_key(0)
|
, event_key(0)
|
||||||
|
, counter(0)
|
||||||
{
|
{
|
||||||
memset(&m_ports, 0, sizeof(AudioPortConfig) * AUDIO_PORT_COUNT);
|
memset(&m_ports, 0, sizeof(AudioPortConfig) * AUDIO_PORT_COUNT);
|
||||||
}
|
}
|
||||||
@ -282,6 +290,7 @@ int cellAudioInit()
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_config.m_is_audio_initialized = true;
|
m_config.m_is_audio_initialized = true;
|
||||||
|
m_config.counter = 0;
|
||||||
|
|
||||||
// alloc memory
|
// alloc memory
|
||||||
m_config.m_buffer = Memory.Alloc(128 * 1024 * m_config.AUDIO_PORT_COUNT, 1024);
|
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);
|
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);
|
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)
|
WAVHeader header(2); // WAV file header (stereo)
|
||||||
|
|
||||||
@ -304,13 +313,14 @@ int cellAudioInit()
|
|||||||
|
|
||||||
ConLog.Write("Audio started");
|
ConLog.Write("Audio started");
|
||||||
|
|
||||||
u64 start_time = get_system_time();
|
m_config.start_time = get_system_time();
|
||||||
u64 counter = 0;
|
|
||||||
|
|
||||||
output.Write(&header, sizeof(header)); // write file header
|
output.Write(&header, sizeof(header)); // write file header
|
||||||
|
|
||||||
float buffer[2*256]; // buffer for 2 channels
|
float buffer[2*256]; // buffer for 2 channels
|
||||||
float buffer2[8*256]; // buffer for 8 channels (max count)
|
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)
|
while (m_config.m_is_audio_initialized)
|
||||||
{
|
{
|
||||||
@ -323,13 +333,13 @@ int cellAudioInit()
|
|||||||
// TODO: send beforemix event (in ~2,6 ms before mixing)
|
// TODO: send beforemix event (in ~2,6 ms before mixing)
|
||||||
|
|
||||||
// Sleep(5); // precise time of sleeping: 5,(3) ms (or 256/48000 sec)
|
// 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);
|
Sleep(1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
counter++;
|
m_config.counter++;
|
||||||
|
|
||||||
if (Emu.IsPaused())
|
if (Emu.IsPaused())
|
||||||
{
|
{
|
||||||
@ -346,16 +356,21 @@ int cellAudioInit()
|
|||||||
AudioPortConfig& port = m_config.m_ports[i];
|
AudioPortConfig& port = m_config.m_ports[i];
|
||||||
mem64_t index(m_config.m_indexes + i * sizeof(u64));
|
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));
|
u32 buf_addr = m_config.m_buffer + (i * 128 * 1024) + (position * block_size * sizeof(float));
|
||||||
|
|
||||||
memcpy(buffer2, Memory + buf_addr, block_size * sizeof(float));
|
memcpy(buffer2, Memory + buf_addr, block_size * sizeof(float));
|
||||||
memset(Memory + buf_addr, 0, 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)
|
if (first_mix)
|
||||||
{
|
{
|
||||||
@ -419,7 +434,7 @@ int cellAudioQuit()
|
|||||||
if (Emu.IsStopped())
|
if (Emu.IsStopped())
|
||||||
{
|
{
|
||||||
ConLog.Warning("cellAudioQuit() aborted");
|
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)
|
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;
|
port.channel = audioParam->nChannel;
|
||||||
param.nBlock = audioParam->nBlock;
|
port.block = audioParam->nBlock;
|
||||||
param.attr = audioParam->attr;
|
port.attr = audioParam->attr;
|
||||||
param.level = audioParam->level;
|
port.level = audioParam->level;
|
||||||
|
|
||||||
portNum = i;
|
portNum = i;
|
||||||
cellAudio.Warning("*** audio port opened(nChannel=%lld, nBlock=0x%llx, attr=0x%llx, level=%f): port = %d",
|
cellAudio.Warning("*** audio port opened(nChannel=%d, nBlock=%d, attr=0x%llx, level=%f): port = %d",
|
||||||
(u64)param.nChannel, (u64)param.nBlock, (u64)param.attr, (float)param.level, i);
|
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_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;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -494,15 +511,15 @@ int cellAudioGetPortConfig(u32 portNum, mem_ptr_t<CellAudioPortConfig> portConfi
|
|||||||
portConfig->status = CELL_AUDIO_STATUS_READY;
|
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->nChannel = port.channel;
|
||||||
portConfig->nBlock = ref.nBlock;
|
portConfig->nBlock = port.block;
|
||||||
portConfig->portSize = ref.nChannel * ref.nBlock * 256 * sizeof(float);
|
portConfig->portSize = port.channel * port.block * 256 * sizeof(float);
|
||||||
portConfig->portAddr = m_config.m_buffer + (128 * 1024 * portNum); // 0x20020000
|
portConfig->portAddr = m_config.m_buffer + (128 * 1024 * portNum); // 0x20020000
|
||||||
portConfig->readIndexAddr = m_config.m_indexes + (sizeof(u64) * portNum); // 0x20010010 on ps3
|
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);
|
(u32)portConfig->nChannel, (u32)portConfig->nBlock, (u32)portConfig->portSize, (u32)portConfig->portAddr, (u32)portConfig->readIndexAddr);
|
||||||
// portAddr - readIndexAddr == 0xFFF0 on ps3
|
// portAddr - readIndexAddr == 0xFFF0 on ps3
|
||||||
|
|
||||||
@ -577,13 +594,71 @@ int cellAudioPortStop(u32 portNum)
|
|||||||
|
|
||||||
int cellAudioGetPortTimestamp(u32 portNum, u64 tag, mem64_t stamp)
|
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;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, mem64_t tag)
|
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;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ extern void sys_game_process_exitspawn2(u32 path_addr, u32 argv_addr, u32 envp_a
|
|||||||
//sys_event
|
//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_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_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_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_queue_drain(u32 event_queue_id);
|
||||||
extern int sys_event_port_create(mem32_t eport_id, int port_type, u64 name);
|
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();
|
u32 tid = GetCurrentPPUThread().GetId();
|
||||||
|
|
||||||
eq->m_mutex.lock(tid);
|
eq->sq.m_mutex.lock(tid);
|
||||||
eq->owner.lock(tid);
|
eq->owner.lock(tid);
|
||||||
// check if some threads are waiting for an event
|
// 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->owner.unlock(tid);
|
||||||
eq->m_mutex.unlock(tid);
|
eq->sq.m_mutex.unlock(tid);
|
||||||
return CELL_EBUSY;
|
return CELL_EBUSY;
|
||||||
}
|
}
|
||||||
eq->owner.unlock(tid, ~0);
|
eq->owner.unlock(tid, ~0);
|
||||||
eq->m_mutex.unlock(tid);
|
eq->sq.m_mutex.unlock(tid);
|
||||||
while (eq->list.GetCount())
|
while (eq->sq.list.GetCount())
|
||||||
{
|
{
|
||||||
Sleep(1);
|
Sleep(1);
|
||||||
if (Emu.IsStopped())
|
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();
|
u32 tid = GetCurrentPPUThread().GetId();
|
||||||
|
|
||||||
eq->m_mutex.lock(tid);
|
eq->sq.m_mutex.lock(tid);
|
||||||
eq->owner.lock(tid);
|
eq->owner.lock(tid);
|
||||||
if (eq->list.GetCount())
|
if (eq->sq.list.GetCount())
|
||||||
{
|
{
|
||||||
number = 0;
|
number = 0;
|
||||||
eq->owner.unlock(tid);
|
eq->owner.unlock(tid);
|
||||||
eq->m_mutex.unlock(tid);
|
eq->sq.m_mutex.unlock(tid);
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
number = eq->events.pop_all((sys_event_data*)(Memory + event_array.GetAddr()), size);
|
number = eq->events.pop_all((sys_event_data*)(Memory + event_array.GetAddr()), size);
|
||||||
eq->owner.unlock(tid);
|
eq->owner.unlock(tid);
|
||||||
eq->m_mutex.unlock(tid);
|
eq->sq.m_mutex.unlock(tid);
|
||||||
return CELL_OK;
|
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();
|
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;
|
timeout = timeout ? (timeout / 1000) : ~0;
|
||||||
u64 counter = 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
|
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)
|
if (next != tid)
|
||||||
{
|
{
|
||||||
eq->owner.unlock(tid, next);
|
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->events.pop(*event);
|
||||||
eq->owner.unlock(tid);
|
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;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
case SMR_FAILED: break;
|
case SMR_FAILED: break;
|
||||||
default: eq->invalidate(tid); return CELL_ECANCELED;
|
default: eq->sq.invalidate(tid); return CELL_ECANCELED;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sleep(1);
|
Sleep(1);
|
||||||
if (counter++ > timeout || Emu.IsStopped())
|
if (counter++ > timeout || Emu.IsStopped())
|
||||||
{
|
{
|
||||||
if (Emu.IsStopped()) ConLog.Warning("sys_event_queue_receive(equeue=%d) aborted", equeue_id);
|
if (Emu.IsStopped()) ConLog.Warning("sys_event_queue_receive(equeue=%d) aborted", equeue_id);
|
||||||
eq->invalidate(tid);
|
eq->sq.invalidate(tid);
|
||||||
return CELL_ETIMEDOUT;
|
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)
|
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;
|
EventQueue* eq;
|
||||||
if (!Emu.GetIdManager().GetIDData(equeue_id, 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->ports.remove(eport);
|
||||||
eport->eq = 0;
|
eport->eq = nullptr;
|
||||||
eport->mutex.unlock(tid);
|
eport->mutex.unlock(tid);
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3)
|
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);
|
eport_id, data1, data2, data3);
|
||||||
|
|
||||||
EventPort* eport;
|
EventPort* eport;
|
||||||
@ -419,12 +374,13 @@ int sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3)
|
|||||||
|
|
||||||
SMutexLocker lock(eport->mutex);
|
SMutexLocker lock(eport->mutex);
|
||||||
|
|
||||||
if (!eport->eq)
|
EventQueue* eq = eport->eq;
|
||||||
|
if (!eq)
|
||||||
{
|
{
|
||||||
return CELL_ENOTCONN;
|
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;
|
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->attribute = attr->attr_protocol | attr->attr_recursive;
|
||||||
|
lwmutex->all_info = 0;
|
||||||
lwmutex->owner.initialize();
|
lwmutex->owner.initialize();
|
||||||
lwmutex->waiter = lwmutex->owner.GetOwner();
|
//lwmutex->waiter = lwmutex->owner.GetOwner();
|
||||||
lwmutex->pad = 0;
|
lwmutex->pad = 0;
|
||||||
lwmutex->recursive_count = 0;
|
lwmutex->recursive_count = 0;
|
||||||
|
|
||||||
@ -130,7 +131,7 @@ u32 SleepQueue::pop_prio() // SYS_SYNC_PRIORITY
|
|||||||
{
|
{
|
||||||
if (list.GetCount())
|
if (list.GetCount())
|
||||||
{
|
{
|
||||||
u64 max_prio = 0;
|
u32 highest_prio = ~0;
|
||||||
u32 sel = 0;
|
u32 sel = 0;
|
||||||
for (u32 i = 0; i < list.GetCount(); i++)
|
for (u32 i = 0; i < list.GetCount(); i++)
|
||||||
{
|
{
|
||||||
@ -142,9 +143,9 @@ u32 SleepQueue::pop_prio() // SYS_SYNC_PRIORITY
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
u64 prio = t->GetPrio();
|
u64 prio = t->GetPrio();
|
||||||
if (prio > max_prio)
|
if (prio < highest_prio)
|
||||||
{
|
{
|
||||||
max_prio = prio;
|
highest_prio = prio;
|
||||||
sel = i;
|
sel = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,6 +222,8 @@ int sys_spu_thread_group_destroy(u32 id)
|
|||||||
|
|
||||||
for (u32 i = 0; i < group_info->list.GetCount(); i++)
|
for (u32 i = 0; i < group_info->list.GetCount(); i++)
|
||||||
{
|
{
|
||||||
|
// TODO: disconnect all event ports
|
||||||
|
|
||||||
Emu.GetCPU().RemoveThread(group_info->list[i]);
|
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;
|
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)
|
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)",
|
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);
|
sc_spu.Error("sys_spu_thread_group_disconnect_event_all_threads(id=%d, spup=%d)", id, spup);
|
||||||
|
|
||||||
return CELL_OK;
|
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
|
#pragma once
|
||||||
#include "Emu/SysCalls/lv2/SC_Lwmutex.h"
|
#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
|
enum EventQueueType
|
||||||
{
|
{
|
||||||
SYS_PPU_QUEUE = 1,
|
SYS_PPU_QUEUE = 1,
|
||||||
@ -158,6 +161,7 @@ public:
|
|||||||
SMutexLocker lock(m_lock);
|
SMutexLocker lock(m_lock);
|
||||||
for (u32 i = 0; i < data.GetCount(); i++)
|
for (u32 i = 0; i < data.GetCount(); i++)
|
||||||
{
|
{
|
||||||
|
SMutexLocker lock2(data[i]->mutex);
|
||||||
data[i]->eq = nullptr; // force all ports to disconnect
|
data[i]->eq = nullptr; // force all ports to disconnect
|
||||||
}
|
}
|
||||||
data.Clear();
|
data.Clear();
|
||||||
@ -183,8 +187,9 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EventQueue : SleepQueue
|
struct EventQueue
|
||||||
{
|
{
|
||||||
|
SleepQueue sq;
|
||||||
EventPortList ports;
|
EventPortList ports;
|
||||||
EventRingBuffer events;
|
EventRingBuffer events;
|
||||||
SMutex owner;
|
SMutex owner;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user