DMA List commands

cellAudio: multiple queue support
sys_cond simplified
cellFsMkdir (?)
This commit is contained in:
Nekotekina 2014-03-15 19:43:14 +04:00
parent 024aa0660c
commit 60d922da11
11 changed files with 215 additions and 175 deletions

View File

@ -121,6 +121,7 @@ struct AudioPortConfig
struct AudioConfig //custom structure
{
std::mutex m_mutex;
enum
{
AUDIO_PORT_COUNT = 8,
@ -131,15 +132,14 @@ struct AudioConfig //custom structure
bool m_is_audio_initialized;
bool m_is_audio_finalized;
u32 m_port_in_use;
u64 event_key;
u64 counter;
u64 start_time;
Array<u64> m_keys;
AudioConfig()
: m_is_audio_initialized(false)
, m_is_audio_finalized(false)
, m_port_in_use(0)
, event_key(0x80004d494f323221)
, counter(0)
{
memset(&m_ports, 0, sizeof(AudioPortConfig) * AUDIO_PORT_COUNT);

View File

@ -18,6 +18,7 @@ enum
MFC_BARRIER_MASK = 0x01,
MFC_FENCE_MASK = 0x02,
MFC_LIST_MASK = 0x04,
MFC_MASK_CMD = 0xffff,
};
@ -165,7 +166,7 @@ struct DMAC
//returns true if the command should be deleted from the queue
if (cmd & (MFC_BARRIER_MASK | MFC_FENCE_MASK)) _mm_mfence();
switch(cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK))
switch(cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_LIST_MASK))
{
case MFC_PUT_CMD:
Memory.Copy(ea, ls_offset + lsa, size);
@ -176,7 +177,7 @@ struct DMAC
return true;
default:
ConLog.Error("Unknown DMA cmd.");
ConLog.Error("DMAC::ProcessCmd(): Unknown DMA cmd.");
return true;
}
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "PPCThread.h"
#include "Emu/event.h"
#include "Emu/SysCalls/lv2/SC_SPU_Thread.h"
#include "MFC.h"
#include <mutex>
@ -484,6 +485,22 @@ public:
Channel<1> AtomicStat;
} Prxy;
struct StalledList
{
u32 lsa;
u64 ea;
u16 tag;
u16 size;
u32 cmd;
MFCReg* MFCArgs;
StalledList()
: MFCArgs(nullptr)
{
}
} StallList[32];
Channel<1> StallStat;
struct
{
Channel<1> Out_MBox;
@ -505,6 +522,66 @@ public:
DMAC dmac;
void ListCmd(u32 lsa, u64 ea, u16 tag, u16 size, u32 cmd, MFCReg& MFCArgs)
{
u32 list_addr = ea & 0x3ffff;
u32 list_size = size / 8;
lsa &= 0x3fff0;
struct list_element
{
be_t<u16> s; // Stall-and-Notify bit (0x8000)
be_t<u16> ts; // List Transfer Size
be_t<u32> ea; // External Address Low
};
u32 result = MFC_PPU_DMA_CMD_SEQUENCE_ERROR;
for (u32 i = 0; i < list_size; i++)
{
mem_ptr_t<list_element> rec(dmac.ls_offset + list_addr + i * 8);
u32 size = rec->ts;
if (size < 16 && size != 1 && size != 2 && size != 4 && size != 8)
{
ConLog.Error("DMA List: invalid transfer size(%d)", size);
return;
}
u32 addr = rec->ea;
result = dmac.Cmd(cmd, tag, lsa | (addr & 0xf), addr, size);
if (result == MFC_PPU_DMA_CMD_SEQUENCE_ERROR)
{
break;
}
if (Ini.HLELogging.GetValue() || rec->s)
ConLog.Write("*** list element(%d/%d): s = 0x%x, ts = 0x%x, low ea = 0x%x (lsa = 0x%x)",
i, list_size, (u16)rec->s, (u16)rec->ts, (u32)rec->ea, lsa | (addr & 0xf));
lsa += max(size, (u32)16);
if (rec->s & se16(0x8000))
{
StallStat.PushUncond_OR(1 << tag);
if (StallList[tag].MFCArgs)
{
ConLog.Error("DMA List: existing stalled list found (tag=%d)", tag);
}
StallList[tag].MFCArgs = &MFCArgs;
StallList[tag].cmd = cmd;
StallList[tag].ea = (ea & ~0xffffffff) | (list_addr + (i + 1) * 8);
StallList[tag].lsa = lsa;
StallList[tag].size = (list_size - i - 1) * 8;
return;
}
}
MFCArgs.CMDStatus.SetValue(result);
}
void EnqMfcCmd(MFCReg& MFCArgs)
{
u32 cmd = MFCArgs.CMDStatus.GetValue();
@ -528,7 +605,7 @@ public:
lsa, ea, tag, size, cmd);
if (op & MFC_PUT_CMD)
{
SMutexLocker lock(reservation.mutex);
SMutexLocker lock(reservation.mutex); // should be removed
MFCArgs.CMDStatus.SetValue(dmac.Cmd(cmd, tag, lsa, ea, size));
if ((reservation.addr + reservation.size > ea && reservation.addr <= ea + size) ||
(ea + size > reservation.addr && ea <= reservation.addr + reservation.size))
@ -543,6 +620,19 @@ public:
}
break;
case MFC_PUTL_CMD:
case MFC_GETL_CMD:
{
if (Ini.HLELogging.GetValue()) ConLog.Write("DMA %s%s%s: lsa = 0x%x, list = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x",
wxString(op & MFC_PUT_CMD ? "PUTL" : "GETL").wx_str(),
wxString(op & MFC_BARRIER_MASK ? "B" : "").wx_str(),
wxString(op & MFC_FENCE_MASK ? "F" : "").wx_str(),
lsa, ea, tag, size, cmd);
ListCmd(lsa, ea, tag, size, cmd, MFCArgs);
}
break;
case MFC_GETLLAR_CMD:
case MFC_PUTLLC_CMD:
case MFC_PUTLLUC_CMD:
@ -628,6 +718,9 @@ public:
case MFC_RdTagStat:
return Prxy.TagStatus.GetCount();
case MFC_RdListStallStat:
return StallStat.GetCount();
case MFC_WrTagUpdate:
return Prxy.TagStatus.GetCount(); // hack
@ -751,6 +844,24 @@ public:
EnqMfcCmd(MFC1);
break;
case MFC_WrListStallAck:
{
if (v >= 32)
{
ConLog.Error("MFC_WrListStallAck error: invalid tag(%d)", v);
return;
}
StalledList temp = StallList[v];
if (!temp.MFCArgs)
{
ConLog.Error("MFC_WrListStallAck error: empty tag(%d)", v);
return;
}
StallList[v].MFCArgs = nullptr;
ListCmd(temp.lsa, temp.ea, temp.tag, temp.size, temp.cmd, *temp.MFCArgs);
}
break;
default:
ConLog.Error("%s error: unknown/illegal channel (%d [%s]).", wxString(__FUNCTION__).wx_str(), ch, wxString(spu_ch_name[ch]).wx_str());
break;
@ -790,6 +901,10 @@ public:
while (!Prxy.AtomicStat.Pop(v) && !Emu.IsStopped()) Sleep(1);
break;
case MFC_RdListStallStat:
while (!StallStat.Pop(v) && !Emu.IsStopped()) Sleep(1);
break;
default:
ConLog.Error("%s error: unknown/illegal channel (%d [%s]).", wxString(__FUNCTION__).wx_str(), ch, wxString(spu_ch_name[ch]).wx_str());
break;

View File

@ -60,6 +60,8 @@ int cellAudioInit()
memset(buffer2, 0, sizeof(buffer2));
memset(oal_buffer.get(), 0, oal_buffer_size * sizeof(u16));
Array<u64> keys;
if(m_audio_out)
{
m_audio_out->Init();
@ -144,8 +146,16 @@ int cellAudioInit()
}
// send aftermix event (normal audio event)
{
std::lock_guard<std::mutex> lock(m_config.m_mutex);
keys.SetCount(m_config.m_keys.GetCount());
memcpy(keys.GetPtr(), m_config.m_keys.GetPtr(), sizeof(u64) * keys.GetCount());
}
for (u32 i = 0; i < keys.GetCount(); i++)
{
// TODO: check event source
Emu.GetEventManager().SendEvent(m_config.event_key, 0x10103000e010e07, 0, 0, 0);
Emu.GetEventManager().SendEvent(keys[i], 0x10103000e010e07, 0, 0, 0);
}
oal_buffer_offset += sizeof(buffer) / sizeof(float);
@ -441,22 +451,27 @@ int cellAudioCreateNotifyEventQueue(mem32_t id, mem64_t key)
{
cellAudio.Warning("cellAudioCreateNotifyEventQueue(id_addr=0x%x, key_addr=0x%x)", id.GetAddr(), key.GetAddr());
while (Emu.GetEventManager().CheckKey(m_config.event_key))
std::lock_guard<std::mutex> lock(m_config.m_mutex);
u64 event_key = 0;
while (Emu.GetEventManager().CheckKey((event_key << 48) | 0x80004d494f323221))
{
m_config.event_key++; // experimental
event_key++; // experimental
//return CELL_AUDIO_ERROR_EVENT_QUEUE;
}
event_key = (event_key << 48) | 0x80004d494f323221; // left part: 0x8000, 0x8001, 0x8002 ...
EventQueue* eq = new EventQueue(SYS_SYNC_FIFO, SYS_PPU_QUEUE, m_config.event_key, m_config.event_key, 32);
EventQueue* eq = new EventQueue(SYS_SYNC_FIFO, SYS_PPU_QUEUE, event_key, event_key, 32);
if (!Emu.GetEventManager().RegisterKey(eq, m_config.event_key))
if (!Emu.GetEventManager().RegisterKey(eq, event_key))
{
delete eq;
return CELL_AUDIO_ERROR_EVENT_QUEUE;
}
m_config.m_keys.AddCpy(event_key);
id = cellAudio.GetNewId(eq);
key = m_config.event_key;
key = event_key;
return CELL_OK;
}
@ -471,7 +486,9 @@ int cellAudioSetNotifyEventQueue(u64 key)
{
cellAudio.Warning("cellAudioSetNotifyEventQueue(key=0x%llx)", key);
//m_config.event_key = key;
std::lock_guard<std::mutex> lock(m_config.m_mutex);
m_config.m_keys.AddCpy(key);
/*EventQueue* eq;
if (!Emu.GetEventManager().GetEventQueue(key, eq))
@ -494,13 +511,30 @@ int cellAudioRemoveNotifyEventQueue(u64 key)
{
cellAudio.Warning("cellAudioRemoveNotifyEventQueue(key=0x%llx)", key);
EventQueue* eq;
if (!Emu.GetEventManager().GetEventQueue(key, eq))
std::lock_guard<std::mutex> lock(m_config.m_mutex);
bool found = false;
for (u32 i = 0; i < m_config.m_keys.GetCount(); i++)
{
if (m_config.m_keys[i] == key)
{
m_config.m_keys.RemoveAt(i);
found = true;
break;
}
}
if (!found)
{
// ???
return CELL_AUDIO_ERROR_PARAM;
}
m_config.event_key = 0x80004d494f323221;
/*EventQueue* eq;
if (!Emu.GetEventManager().GetEventQueue(key, eq))
{
return CELL_AUDIO_ERROR_PARAM;
}*/
// TODO: disconnect port

View File

@ -71,49 +71,16 @@ int sys_cond_signal(u32 cond_id)
}
Mutex* mutex = cond->mutex;
u32 tid = GetCurrentPPUThread().GetId();
bool was_locked = (mutex->m_mutex.GetOwner() == tid);
if (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? cond->m_queue.pop_prio() : cond->m_queue.pop()))
{
CPUThread* tt = Emu.GetCPU().GetThread(target);
bool valid = tt && tt->IsAlive();
if (!valid)
{
sys_cond.Error("sys_cond_signal(%d): signal to invalid thread(%d)", cond_id, target);
return CELL_OK;
}
if (!was_locked) // mutex hasn't been locked (don't care about mutex state)
{
if (u32 owner = mutex->m_mutex.GetOwner())
{
tt = Emu.GetCPU().GetThread(owner);
valid = tt && tt->IsAlive();
if (!valid)
{
sys_cond.Error("sys_cond_signal(%d): deadlock on invalid thread(%d)", cond_id, owner);
return CELL_OK;
}
}
mutex->m_mutex.lock(tid);
mutex->recursive = 1;
mutex->m_mutex.unlock(tid, target);
}
else // mutex has been locked (should preserve original mutex state)
{
mutex->recursive = 1;
mutex->m_mutex.unlock(tid, target);
mutex->m_mutex.lock(tid);
mutex->recursive = 1;
}
}
cond->cond.lock(target);
if (Emu.IsStopped())
{
ConLog.Warning("sys_cond_signal(id=%d) aborted", cond_id);
}
}
return CELL_OK;
}
@ -129,43 +96,10 @@ int sys_cond_signal_all(u32 cond_id)
}
Mutex* mutex = cond->mutex;
u32 tid = GetCurrentPPUThread().GetId();
bool was_locked = (mutex->m_mutex.GetOwner() == tid);
while (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? cond->m_queue.pop_prio() : cond->m_queue.pop()))
{
CPUThread* tt = Emu.GetCPU().GetThread(target);
bool valid = tt && tt->IsAlive();
if (!valid)
{
sys_cond.Error("sys_cond_signal_all(%d): signal to invalid thread(%d)", cond_id, target);
return CELL_OK;
}
if (!was_locked)
{
if (u32 owner = mutex->m_mutex.GetOwner())
{
tt = Emu.GetCPU().GetThread(owner);
valid = tt && tt->IsAlive();
if (!valid)
{
sys_cond.Error("sys_cond_signal_all(%d): deadlock on invalid thread(%d)", cond_id, owner);
return CELL_OK;
}
}
mutex->m_mutex.lock(tid);
mutex->recursive = 1;
mutex->m_mutex.unlock(tid, target);
}
else
{
mutex->recursive = 1;
mutex->m_mutex.unlock(tid, target);
mutex->m_mutex.lock(tid);
mutex->recursive = 1;
}
cond->cond.lock(target);
if (Emu.IsStopped())
{
@ -197,35 +131,10 @@ int sys_cond_signal_to(u32 cond_id, u32 thread_id)
}
Mutex* mutex = cond->mutex;
u32 tid = GetCurrentPPUThread().GetId();
bool was_locked = (mutex->m_mutex.GetOwner() == tid);
u32 target = thread_id;
{
if (!was_locked)
{
if (u32 owner = mutex->m_mutex.GetOwner())
{
CPUThread* tt = Emu.GetCPU().GetThread(owner);
bool valid = tt && tt->IsAlive();
if (!valid)
{
sys_cond.Error("sys_cond_signal_to(%d): deadlock on invalid thread(%d)", cond_id, owner);
return CELL_OK;
}
}
mutex->m_mutex.lock(tid);
mutex->recursive = 1;
mutex->m_mutex.unlock(tid, target);
}
else
{
mutex->recursive = 1;
mutex->m_mutex.unlock(tid, target);
mutex->m_mutex.lock(tid);
mutex->recursive = 1;
}
cond->cond.lock(target);
}
if (Emu.IsStopped())
@ -264,15 +173,11 @@ int sys_cond_wait(u32 cond_id, u64 timeout)
while (true)
{
/* switch (mutex->m_mutex.trylock(tid))
if (cond->cond.GetOwner() == tid)
{
case SMR_OK: mutex->m_mutex.unlock(tid); break;
case SMR_SIGNAL: mutex->recursive = 1; return CELL_OK;
} */
if (mutex->m_mutex.GetOwner() == tid)
{
_mm_mfence();
mutex->m_mutex.lock(tid);
mutex->recursive = 1;
cond->cond.unlock(tid);
return CELL_OK;
}
@ -281,6 +186,7 @@ int sys_cond_wait(u32 cond_id, u64 timeout)
if (counter++ > max_counter)
{
cond->m_queue.invalidate(tid);
GetCurrentPPUThread().owned_mutexes--;
return CELL_ETIMEDOUT;
}
if (Emu.IsStopped())

View File

@ -16,6 +16,7 @@ struct sys_cond_attribute
struct Cond
{
Mutex* mutex; // associated with mutex
SMutex cond;
SleepQueue m_queue;
Cond(Mutex* mutex, u64 name)

View File

@ -203,7 +203,7 @@ int sys_event_queue_receive(u32 equeue_id, mem_ptr_t<sys_event_data> event, u64
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 */
/* passing event data in registers */
PPUThread& t = GetCurrentPPUThread();
t.GPR[4] = event->source;
t.GPR[5] = event->data1;

View File

@ -324,10 +324,15 @@ int cellFsMkdir(u32 path_addr, u32 mode)
const wxString& ps3_path = Memory.ReadString(path_addr);
sys_fs.Log("cellFsMkdir(path=\"%s\", mode=0x%x)", ps3_path.wx_str(), mode);
vfsDir dir;
/*vfsDir dir;
if(dir.IsExists(ps3_path))
return CELL_EEXIST;
if(!dir.Create(ps3_path))
return CELL_EBUSY;*/
if(Emu.GetVFS().ExistsDir(ps3_path))
return CELL_EEXIST;
if(!Emu.GetVFS().CreateDir(ps3_path))
return CELL_EBUSY;
return CELL_OK;

View File

@ -98,8 +98,9 @@ int sys_mutex_lock(u32 mutex_id, u64 timeout)
PPUThread& t = GetCurrentPPUThread();
u32 tid = t.GetId();
u32 owner = mutex->m_mutex.GetOwner();
_mm_mfence();
u32 owner = mutex->m_mutex.GetOwner();
if (owner == tid)
{
if (mutex->is_recursive)
@ -119,22 +120,10 @@ int sys_mutex_lock(u32 mutex_id, u64 timeout)
{
if (CPUThread* tt = Emu.GetCPU().GetThread(owner))
{
if (!tt->IsAlive())
{
if (owner == mutex->m_mutex.GetOwner()) sys_mtx.Error("sys_mutex_lock(%d): deadlock on invalid thread(%d)", mutex_id, owner);
/*mutex->m_mutex.unlock(owner, tid);
mutex->recursive = 1;
t.owned_mutexes++;
return CELL_OK;*/
}
}
else
{
sys_mtx.Error("sys_mutex_lock(%d): deadlock on invalid thread(%d)", mutex_id, owner);
/*mutex->m_mutex.unlock(owner, tid);
mutex->recursive = 1;
t.owned_mutexes++;
return CELL_OK;*/
}
}
@ -180,8 +169,9 @@ int sys_mutex_trylock(u32 mutex_id)
PPUThread& t = GetCurrentPPUThread();
u32 tid = t.GetId();
u32 owner = mutex->m_mutex.GetOwner();
_mm_mfence();
u32 owner = mutex->m_mutex.GetOwner();
if (owner == tid)
{
if (mutex->is_recursive)
@ -201,22 +191,10 @@ int sys_mutex_trylock(u32 mutex_id)
{
if (CPUThread* tt = Emu.GetCPU().GetThread(owner))
{
if (!tt->IsAlive())
{
if (owner == mutex->m_mutex.GetOwner()) sys_mtx.Error("sys_mutex_trylock(%d): deadlock on invalid thread(%d)", mutex_id, owner);
/*mutex->m_mutex.unlock(owner, tid);
mutex->recursive = 1;
t.owned_mutexes++;
return CELL_OK;*/
}
}
else
{
sys_mtx.Error("sys_mutex_trylock(%d): deadlock on invalid thread(%d)", mutex_id, owner);
/*mutex->m_mutex.unlock(owner, tid);
mutex->recursive = 1;
t.owned_mutexes++;
return CELL_OK;*/
}
}
@ -241,6 +219,7 @@ int sys_mutex_unlock(u32 mutex_id)
PPUThread& t = GetCurrentPPUThread();
u32 tid = t.GetId();
_mm_mfence();
if (mutex->m_mutex.GetOwner() == tid)
{
if (!mutex->recursive || (mutex->recursive != 1 && !mutex->is_recursive))

View File

@ -9,32 +9,6 @@
static SysCallBase sc_spu("sys_spu");
extern SysCallBase sys_event;
static const u32 g_spu_group_thr_max = 255;
struct SpuGroupInfo
{
Array<u32> list;
std::atomic<u32> lock;
wxString m_name;
int m_prio;
int m_type;
int m_ct;
SpuGroupInfo(wxString name, u32 num, int prio, int type, u32 ct)
: m_name(name)
, m_prio(prio)
, m_type(type)
, m_ct(ct)
, lock(0)
{
list.SetCount(num);
for (u32 i = 0; i < num; i++)
{
list[i] = 0;
}
}
};
u32 LoadSpuImage(vfsStream& stream, u32& spu_ep)
{
ELFLoader l(stream);
@ -114,7 +88,7 @@ int sys_spu_thread_initialize(mem32_t thread, u32 group, u32 spu_num, mem_ptr_t<
return CELL_EFAULT;
}
if(spu_num >= g_spu_group_thr_max)
if(spu_num >= group_info->list.GetCount())
{
return CELL_EINVAL;
}
@ -287,7 +261,7 @@ int sys_spu_thread_group_create(mem32_t id, u32 num, int prio, mem_ptr_t<sys_spu
if (!Memory.IsGoodAddr(attr->name_addr, attr->name_len)) return CELL_EFAULT;
if (num > g_spu_group_thr_max) return CELL_EINVAL;
if (num > 256) return CELL_EINVAL;
if (prio < 16 || prio > 255) return CELL_EINVAL;

View File

@ -55,3 +55,28 @@ struct sys_spu_segment
be_t<int> size;
be_t<u64> src;
};
struct SpuGroupInfo
{
Array<u32> list;
std::atomic<u32> lock;
wxString m_name;
int m_prio;
int m_type;
int m_ct;
SpuGroupInfo(wxString name, u32 num, int prio, int type, u32 ct)
: m_name(name)
, m_prio(prio)
, m_type(type)
, m_ct(ct)
, lock(0)
{
num = 256;
list.SetCount(num);
for (u32 i = 0; i < num; i++)
{
list[i] = 0;
}
}
};