Merge pull request #113 from Nekotekina/master

Playable video
This commit is contained in:
B1ackDaemon 2014-03-22 23:09:00 +02:00
commit d1ffea0847
45 changed files with 1379 additions and 430 deletions

View File

@ -79,12 +79,12 @@ public:
}
}
volatile u32 GetCount()
volatile u32 GetCount() // may be not safe
{
return m_count;
}
volatile bool IsEmpty()
volatile bool IsEmpty() // may be not safe
{
return !m_count;
}
@ -97,7 +97,28 @@ public:
T& Peek(u32 pos = 0)
{
SMutexLocker lock(m_mutex);
while (true)
{
if (m_mutex.GetOwner() == m_mutex.GetDeadValue())
{
break;
}
if (!m_count)
{
if (Emu.IsStopped())
{
break;
}
Sleep(1);
continue;
}
{
SMutexLocker lock(m_mutex);
if (m_count) break;
}
}
return m_data[(m_pos + pos) % SQSize];
}
};

View File

@ -23,16 +23,22 @@ void AudioDumper::WriteHeader()
size_t AudioDumper::WriteData(const void* buffer, size_t size)
{
for (u32 i = 0; i < size / 8; i++)
{
if (((u64*)buffer)[i]) goto process;
}
for (u32 i = 0; i < size % 8; i++)
{
if (((u8*)buffer)[i + (size & ~7)]) goto process;
}
return size; // ignore empty data
process:
size_t ret = m_output.Write(buffer, size);
m_header.Size += ret;
m_header.RIFF.Size += ret;
return ret;
}
void AudioDumper::UpdateHeader(size_t size)
{
m_header.Size += size;
m_header.RIFF.Size += size;
}
void AudioDumper::Finalize()
{
m_output.Seek(0);

View File

@ -64,6 +64,5 @@ public:
bool Init();
void WriteHeader();
size_t WriteData(const void* buffer, size_t size);
void UpdateHeader(size_t size);
void Finalize();
};

View File

@ -58,7 +58,7 @@ void CPUThread::CloseStack()
{
if(m_stack_addr)
{
Memory.Free(m_stack_addr);
Memory.StackMem.Free(m_stack_addr);
m_stack_addr = 0;
}

View File

@ -4,13 +4,16 @@
enum
{
MFC_PUT_CMD = 0x20, MFC_PUTB_CMD = 0x21, MFC_PUTF_CMD = 0x22,
MFC_PUTR_CMD = 0x30, MFC_PUTRB_CMD = 0x31, MFC_PUTRF_CMD = 0x32,
MFC_GET_CMD = 0x40, MFC_GETB_CMD = 0x41, MFC_GETF_CMD = 0x42,
MFC_PUTL_CMD = 0x24, MFC_PUTLB_CMD = 0x25, MFC_PUTLF_CMD = 0x26,
MFC_PUTRL_CMD = 0x34, MFC_PUTRLB_CMD = 0x35, MFC_PUTRLF_CMD = 0x36,
MFC_GETL_CMD = 0x44, MFC_GETLB_CMD = 0x45, MFC_GETLF_CMD = 0x46,
MFC_GETLLAR_CMD = 0xD0,
MFC_PUTLLC_CMD = 0xB4,
MFC_PUTLLUC_CMD = 0xB0,
MFC_PUTQLLUC_CMD = 0xB8,
MFC_SNDSIG_CMD = 0xA0, MFC_SNDSIGB_CMD = 0xA1, MFC_SNDSIGF_CMD = 0xA2,
MFC_BARRIER_CMD = 0xC0,
MFC_EIEIO_CMD = 0xC8,
@ -19,6 +22,8 @@ enum
MFC_BARRIER_MASK = 0x01,
MFC_FENCE_MASK = 0x02,
MFC_LIST_MASK = 0x04,
MFC_START_MASK = 0x08, // ???
MFC_RESULT_MASK = 0x10, // ???
MFC_MASK_CMD = 0xffff,
};
@ -55,7 +60,7 @@ enum
MFC_SPU_MAX_QUEUE_SPACE = 0x10,
};
struct DMAC_Queue
/*struct DMAC_Queue
{
bool is_valid;
u64 ea;
@ -149,13 +154,14 @@ public:
{
return Memory.Read32(m_addr);
}
};
};*/
struct DMAC
{
//DMAC_Queue queue[MFC_SPU_MAX_QUEUE_SPACE]; //not used yet
DMAC_Proxy proxy[MFC_PPU_MAX_QUEUE_SPACE+MFC_SPU_MAX_QUEUE_SPACE]; //temporarily 24
u64 ls_offset;
/*//DMAC_Queue queue[MFC_SPU_MAX_QUEUE_SPACE]; //not used yet
DMAC_Proxy proxy[MFC_PPU_MAX_QUEUE_SPACE+MFC_SPU_MAX_QUEUE_SPACE]; //temporarily 24
u32 queue_pos;
u32 proxy_pos;
long queue_lock;
@ -194,18 +200,6 @@ struct DMAC
return MFC_PPU_DMA_QUEUE_FULL;
}
/* while (std::atomic_exchange(&proxy_lock, 1));
_mm_lfence();
DMAC_Proxy& p = proxy[proxy_pos];
p.cmd = cmd;
p.tag = tag;
p.lsa = lsa;
p.ea = ea;
p.size = size;
_mm_sfence(); //for DoCmd()
proxy_pos++;
_mm_sfence();
proxy_lock = 0; */
ProcessCmd(cmd, tag, lsa, ea, size);
return MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL;
@ -230,10 +224,10 @@ struct DMAC
ClearCmd();
}
}
}
}*/
};
struct MFC
/*struct MFC
{
SPUReg<1> MFC_LSA;
SPUReg<1> MFC_EAH;
@ -299,4 +293,4 @@ struct MFC
MFC_QStatus.SetValue(mask);
}
}
};
};*/

View File

@ -283,7 +283,7 @@ void RawSPUThread::Task()
continue;
}
dmac.DoCmd();
//dmac.DoCmd();
if(SPU.RunCntl.GetValue() != SPU_RUNCNTL_RUNNABLE)
{

View File

@ -113,14 +113,26 @@ private:
}
}
break;
case 0x102: default:
if (!CPU.SPU.Out_MBox.GetCount()) // the real exit status
case 0x102:
if (!CPU.SPU.Out_MBox.GetCount())
{
ConLog.Warning("STOP: 0x%x (no message)", code);
ConLog.Error("sys_spu_thread_exit (no status, code 0x102)");
}
else if (Ini.HLELogging.GetValue() || code != 0x102)
else if (Ini.HLELogging.GetValue())
{
ConLog.Warning("STOP: 0x%x (message=0x%x)", code, CPU.SPU.Out_MBox.GetValue());
// the real exit status
ConLog.Write("sys_spu_thread_exit (status=0x%x)", CPU.SPU.Out_MBox.GetValue());
}
CPU.Stop();
break;
default:
if (!CPU.SPU.Out_MBox.GetCount())
{
ConLog.Error("Unknown STOP code: 0x%x (no message)", code);
}
else
{
ConLog.Error("Unknown STOP code: 0x%x (message=0x%x)", code, CPU.SPU.Out_MBox.GetValue());
}
CPU.Stop();
break;

View File

@ -20,6 +20,8 @@ SPUThread::SPUThread(CPUThreadType type) : PPCThread(type)
{
assert(type == CPU_THREAD_SPU || type == CPU_THREAD_RAW_SPU);
group = nullptr;
Reset();
}
@ -46,10 +48,10 @@ void SPUThread::InitRegs()
cfg.Reset();
dmac.ls_offset = m_offset;
dmac.proxy_pos = 0;
/*dmac.proxy_pos = 0;
dmac.queue_pos = 0;
dmac.proxy_lock = 0;
dmac.queue_lock = 0;
dmac.queue_lock = 0;*/
SPU.RunCntl.SetValue(SPU_RUNCNTL_STOP);
SPU.Status.SetValue(SPU_STATUS_RUNNING);

View File

@ -119,6 +119,15 @@ enum
SPU_STATUS_SINGLE_STEP = 0x10,
};
enum : u32
{
SYS_SPU_THREAD_BASE_LOW = 0xf0000000,
SYS_SPU_THREAD_BASE_MASK = 0xfffffff,
SYS_SPU_THREAD_OFFSET = 0x00100000,
SYS_SPU_THREAD_SNR1 = 0x05400c,
SYS_SPU_THREAD_SNR2 = 0x05C00c,
};
//Floating point status and control register. Unsure if this is one of the GPRs or SPRs
//Is 128 bits, but bits 0-19, 24-28, 32-49, 56-60, 64-81, 88-92, 96-115, 120-124 are unused
class FPSCR
@ -278,6 +287,7 @@ public:
EventPort SPUPs[64]; // SPU Thread Event Ports
EventManager SPUQs; // SPU Queue Mapping
SpuGroupInfo* group; // associated SPU Thread Group (null for raw spu)
template<size_t _max_count>
class Channel
@ -512,6 +522,18 @@ public:
Channel<1> SNR[2];
} SPU;
void WriteSNR(bool number, u32 value)
{
if (cfg.value & ((u64)1 << (u64)number))
{
SPU.SNR[number].PushUncond_OR(value); // logical OR
}
else
{
SPU.SNR[number].PushUncond(value); // overwrite
}
}
u32 LSA;
union
@ -522,6 +544,81 @@ public:
DMAC dmac;
bool ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size)
{
if (cmd & (MFC_BARRIER_MASK | MFC_FENCE_MASK)) _mm_mfence();
if ((ea & 0xf0000000) == SYS_SPU_THREAD_BASE_LOW)
{
if (group)
{
// SPU Thread Group MMIO (LS and SNR)
u32 num = (ea & SYS_SPU_THREAD_BASE_MASK) / SYS_SPU_THREAD_OFFSET; // thread number in group
if (num >= group->list.GetCount() || !group->list[num])
{
ConLog.Error("DMAC::ProcessCmd(): SPU Thread Group MMIO Access (ea=0x%llx): invalid thread", ea);
return false;
}
SPUThread* spu = (SPUThread*)Emu.GetCPU().GetThread(group->list[num]);
u32 addr = (ea & SYS_SPU_THREAD_BASE_MASK) % SYS_SPU_THREAD_OFFSET;
if ((addr <= 0x3ffff) && (addr + size <= 0x40000))
{
// LS access
ea = spu->dmac.ls_offset + addr;
}
else if ((cmd & MFC_PUT_CMD) && size == 4 && (addr == SYS_SPU_THREAD_SNR1 || addr == SYS_SPU_THREAD_SNR2))
{
spu->WriteSNR(SYS_SPU_THREAD_SNR2 == addr, Memory.Read32(dmac.ls_offset + lsa));
return true;
}
else
{
ConLog.Error("DMAC::ProcessCmd(): SPU Thread Group MMIO Access (ea=0x%llx, size=%d, cmd=0x%x): invalid command", ea, size, cmd);
return false;
}
}
else
{
ConLog.Error("DMAC::ProcessCmd(): SPU Thread Group MMIO Access (ea=0x%llx): group not set", ea);
return false;
}
}
switch(cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_LIST_MASK | MFC_RESULT_MASK))
{
case MFC_PUT_CMD:
{
return Memory.Copy(ea, dmac.ls_offset + lsa, size);
}
case MFC_GET_CMD:
{
return Memory.Copy(dmac.ls_offset + lsa, ea, size);
}
default:
{
ConLog.Error("DMAC::ProcessCmd(): Unknown DMA cmd.");
return false;
}
}
}
u32 dmacCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size)
{
/*if(proxy_pos >= MFC_PPU_MAX_QUEUE_SPACE)
{
return MFC_PPU_DMA_QUEUE_FULL;
}*/
if (ProcessCmd(cmd, tag, lsa, ea, size))
return MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL;
else
return MFC_PPU_DMA_CMD_SEQUENCE_ERROR;
}
void ListCmd(u32 lsa, u64 ea, u16 tag, u16 size, u32 cmd, MFCReg& MFCArgs)
{
u32 list_addr = ea & 0x3ffff;
@ -549,7 +646,7 @@ public:
}
u32 addr = rec->ea;
result = dmac.Cmd(cmd, tag, lsa | (addr & 0xf), addr, size);
result = dmacCmd(cmd, tag, lsa | (addr & 0xf), addr, size);
if (result == MFC_PPU_DMA_CMD_SEQUENCE_ERROR)
{
break;
@ -596,17 +693,19 @@ public:
switch(op & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK))
{
case MFC_PUT_CMD:
case MFC_PUTR_CMD: // ???
case MFC_GET_CMD:
{
if (Ini.HLELogging.GetValue()) ConLog.Write("DMA %s%s%s: lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x",
wxString(op & MFC_PUT_CMD ? "PUT" : "GET").wx_str(),
if (Ini.HLELogging.GetValue()) ConLog.Write("DMA %s%s%s%s: lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x",
wxString(op & MFC_PUT_CMD ? "PUT" : "GET").wx_str(),
wxString(op & MFC_RESULT_MASK ? "R" : "").wx_str(),
wxString(op & MFC_BARRIER_MASK ? "B" : "").wx_str(),
wxString(op & MFC_FENCE_MASK ? "F" : "").wx_str(),
lsa, ea, tag, size, cmd);
if (op & MFC_PUT_CMD)
{
SMutexLocker lock(reservation.mutex); // should be removed
MFCArgs.CMDStatus.SetValue(dmac.Cmd(cmd, tag, lsa, ea, size));
MFCArgs.CMDStatus.SetValue(dmacCmd(cmd, tag, lsa, ea, size));
if ((reservation.addr + reservation.size > ea && reservation.addr <= ea + size) ||
(ea + size > reservation.addr && ea <= reservation.addr + reservation.size))
{
@ -615,16 +714,18 @@ public:
}
else
{
MFCArgs.CMDStatus.SetValue(dmac.Cmd(cmd, tag, lsa, ea, size));
MFCArgs.CMDStatus.SetValue(dmacCmd(cmd, tag, lsa, ea, size));
}
}
break;
case MFC_PUTL_CMD:
case MFC_PUTRL_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(),
if (Ini.HLELogging.GetValue()) ConLog.Write("DMA %s%s%s%s: lsa = 0x%x, list = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x",
wxString(op & MFC_PUT_CMD ? "PUT" : "GET").wx_str(),
wxString(op & MFC_RESULT_MASK ? "RL" : "L").wx_str(),
wxString(op & MFC_BARRIER_MASK ? "B" : "").wx_str(),
wxString(op & MFC_FENCE_MASK ? "F" : "").wx_str(),
lsa, ea, tag, size, cmd);
@ -650,7 +751,7 @@ public:
reservation.owner = lock.tid;
reservation.addr = ea;
reservation.size = 128;
dmac.ProcessCmd(MFC_GET_CMD, tag, lsa, ea, 128);
ProcessCmd(MFC_GET_CMD, tag, lsa, ea, 128);
Prxy.AtomicStat.PushUncond(MFC_GETLLAR_SUCCESS);
}
else if (op == MFC_PUTLLC_CMD) // store conditional
@ -660,7 +761,7 @@ public:
{
if (reservation.addr == ea && reservation.size == 128)
{
dmac.ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128);
ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128);
Prxy.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
}
else
@ -677,7 +778,7 @@ public:
else // store unconditional
{
SMutexLocker lock(reservation.mutex);
dmac.ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128);
ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128);
if (op == MFC_PUTLLUC_CMD)
{
Prxy.AtomicStat.PushUncond(MFC_PUTLLUC_SUCCESS);
@ -795,9 +896,66 @@ public:
SPU.In_MBox.PushUncond(CELL_OK);
return;
}
else if (code = 128)
{
/* ===== sys_event_flag_set_bit ===== */
u32 flag = v & 0xffffff;
u32 data;
if (!SPU.Out_MBox.Pop(data))
{
ConLog.Error("sys_event_flag_set_bit(v=0x%x (flag=%d)): Out_MBox is empty", v, flag);
return;
}
if (flag > 63)
{
ConLog.Error("sys_event_flag_set_bit(id=%d, v=0x%x): flag > 63", data, v, flag);
return;
}
//if (Ini.HLELogging.GetValue())
{
ConLog.Warning("sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d))", data, v, flag);
}
EventFlag* ef;
if (!Emu.GetIdManager().GetIDData(data, ef))
{
ConLog.Error("sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag);
SPU.In_MBox.PushUncond(CELL_ESRCH);
return;
}
u32 tid = GetCurrentCPUThread()->GetId();
ef->m_mutex.lock(tid);
ef->flags |= (u64)1 << flag;
if (u32 target = ef->check())
{
// if signal, leave both mutexes locked...
ef->signal.lock(target);
ef->m_mutex.unlock(tid, target);
}
else
{
ef->m_mutex.unlock(tid);
}
SPU.In_MBox.PushUncond(CELL_OK);
return;
}
else
{
ConLog.Error("SPU_WrOutIntrMbox: unknown data (v=0x%x)", v);
u32 data;
if (SPU.Out_MBox.Pop(data))
{
ConLog.Error("SPU_WrOutIntrMbox: unknown data (v=0x%x); Out_MBox = 0x%x", v, data);
}
else
{
ConLog.Error("SPU_WrOutIntrMbox: unknown data (v=0x%x)", v);
}
SPU.In_MBox.PushUncond(CELL_EINVAL); // ???
return;
}

View File

@ -48,8 +48,14 @@ u32 vfsDevice::CmpLocalPath(const wxString& local_path)
wxFileName path0(m_local_path);
path0.Normalize();
wxArrayString arr0 = wxSplit(path0.GetFullPath(), '/');
wxArrayString arr1 = wxSplit(local_path, '/');
#ifdef _WIN32
#define DL '\\'
#else
#define DL '/'
#endif
wxArrayString arr0 = wxSplit(path0.GetFullPath(), DL);
wxArrayString arr1 = wxSplit(local_path, DL);
const u32 lim = min(arr0.GetCount(), arr1.GetCount());
u32 ret = 0;
@ -179,7 +185,7 @@ wxString vfsDevice::GetWinPath(const wxString& p, bool is_dir)
ret += p[i];
}
if(is_dir && ret[ret.Len() - 1] != '/') ret += '/';
if(is_dir && ret[ret.Len() - 1] != '/' && ret[ret.Len() - 1] != '\\') ret += '/'; // ???
wxFileName res(ret);
res.Normalize();

View File

@ -56,7 +56,7 @@ bool vfsLocalFile::Create(const wxString& path)
for(uint p=1; p < path.Len() && path[p] != '\0' ; p++)
{
for(; p < path.Len() && path[p] != '\0'; p++)
if(path[p] == '/') break;
if(path[p] == '/' || path[p] == '\\') break; // ???
if(p == path.Len() || path[p] == '\0')
break;
@ -70,7 +70,8 @@ bool vfsLocalFile::Create(const wxString& path)
}
//create file
if(path(path.Len() - 1, 1) != '/' && !wxFileExists(path))
wxString m = path(path.Len() - 1, 1);
if(m != '/' && m != '\\' && !wxFileExists(path)) // ???
{
wxFile f;
return f.Create(path);

View File

@ -1144,6 +1144,14 @@ void GLGSRender::Flip()
if(src_buffer)
{
glDisable(GL_STENCIL_TEST);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CLIP_PLANE0);
glDisable(GL_CLIP_PLANE1);
glDisable(GL_CLIP_PLANE2);
glDisable(GL_CLIP_PLANE3);
glDisable(GL_CLIP_PLANE4);
glDisable(GL_CLIP_PLANE5);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, g_flip_tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format, GL_UNSIGNED_INT_8_8_8_8, src_buffer);
@ -1163,6 +1171,7 @@ void GLGSRender::Flip()
m_program.Use();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_ACCUM_BUFFER_BIT);
glColor3f(1, 1, 1);
glBegin(GL_QUADS);
glTexCoord2i(0, 1);
glVertex2i(0, 0);

View File

@ -695,7 +695,7 @@ public:
do
{
if(s[pos] == '/' || s[pos] == '\0')
if(s[pos] == '\\' || s[pos] == '/' || s[pos] == '\0') // ???
{
if(file_pos != -1)
{

View File

@ -210,6 +210,11 @@ bool DynamicMemoryBlockBase<PT>::Free(u64 addr)
}
}
ConLog.Error("DynamicMemoryBlock::Free(addr=0x%llx): failed", addr);
for (u32 i = 0; i < m_allocated.GetCount(); i++)
{
ConLog.Write("*** Memory Block: addr = 0x%llx, size = 0x%x", m_allocated[i].addr, m_allocated[i].size);
}
return false;
}

View File

@ -9,6 +9,7 @@ extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"
}
#include "cellAdec.h"
@ -16,7 +17,7 @@ extern "C"
void cellAdec_init();
Module cellAdec(0x0006, cellAdec_init);
int adecRead(void* opaque, u8* buf, int buf_size)
int adecRawRead(void* opaque, u8* buf, int buf_size)
{
AudioDecoder& adec = *(AudioDecoder*)opaque;
@ -61,13 +62,14 @@ next:
adec.reader.addr = adec.task.au.addr;
adec.reader.size = adec.task.au.size;
//ConLog.Write("Audio AU: size = 0x%x, pts = 0x%llx", adec.task.au.size, adec.task.au.pts);
adec.last_pts = adec.task.au.pts;
//if (adec.last_pts > adec.task.au.pts) adec.last_pts = adec.task.au.pts;
}
break;
default:
ConLog.Error("adecRead(): sequence error (task %d)", adec.job.Peek().type);
return 0;
return -1;
}
goto next;
@ -95,6 +97,89 @@ next:
}
}
int adecRead(void* opaque, u8* buf, int buf_size)
{
AudioDecoder& adec = *(AudioDecoder*)opaque;
int res = 0;
if (adec.reader.rem_size && adec.reader.rem)
{
if (buf_size < (int)adec.reader.rem_size)
{
ConLog.Error("adecRead: too small buf_size (rem_size = %d, buf_size = %d)", adec.reader.rem_size, buf_size);
Emu.Pause();
return 0;
}
memcpy(buf, adec.reader.rem, adec.reader.rem_size);
free(adec.reader.rem);
adec.reader.rem = nullptr;
buf += adec.reader.rem_size;
buf_size -= adec.reader.rem_size;
res += adec.reader.rem_size;
adec.reader.rem_size = 0;
}
while (buf_size)
{
u8 header[8];
if (adecRawRead(opaque, header, 8) < 8) break;
if (header[0] != 0x0f || header[1] != 0xd0)
{
ConLog.Error("adecRead: 0x0FD0 header not found");
Emu.Pause();
return -1;
}
if (!adec.reader.init)
{
OMAHeader oma(1 /* atrac3p id */, header[2], header[3]);
if (buf_size < sizeof(oma) + 8)
{
ConLog.Error("adecRead: OMAHeader writing failed");
Emu.Pause();
return 0;
}
memcpy(buf, &oma, sizeof(oma));
buf += sizeof(oma);
buf_size -= sizeof(oma);
res += sizeof(oma);
adec.reader.init = true;
}
else
{
}
u32 size = (((header[2] & 0x3) << 8) | header[3]) * 8 + 8; // data to be read before next header
//ConLog.Write("*** audio block read: size = 0x%x", size);
if (buf_size < (int)size)
{
if (adecRawRead(opaque, buf, buf_size) < buf_size) break; // ???
res += buf_size;
size -= buf_size;
buf_size = 0;
adec.reader.rem = (u8*)malloc(size);
adec.reader.rem_size = size;
if (adecRawRead(opaque, adec.reader.rem, size) < (int)size) break; // ???
}
else
{
if (adecRawRead(opaque, buf, size) < (int)size) break; // ???
buf += size;
buf_size -= size;
res += size;
}
}
return res;
}
u32 adecOpen(AudioDecoder* data)
{
AudioDecoder& adec = *data;
@ -146,6 +231,10 @@ u32 adecOpen(AudioDecoder* data)
adec.reader.addr = 0;
adec.reader.size = 0;
adec.reader.init = false;
if (adec.reader.rem) free(adec.reader.rem);
adec.reader.rem = nullptr;
adec.reader.rem_size = 0;
adec.is_running = true;
adec.just_started = true;
}
@ -175,8 +264,10 @@ u32 adecOpen(AudioDecoder* data)
adec.reader.addr = task.au.addr;
adec.reader.size = task.au.size;
//ConLog.Write("Audio AU: size = 0x%x, pts = 0x%llx", task.au.size, task.au.pts);
adec.last_pts = task.au.pts;
//if (adec.last_pts > task.au.pts || adec.just_started) adec.last_pts = task.au.pts;
if (adec.just_started) adec.last_pts = task.au.pts;
struct AVPacketHolder : AVPacket
{
@ -212,11 +303,11 @@ u32 adecOpen(AudioDecoder* data)
if (Memory.CopyToReal(buf, task.au.addr, task.au.size)) dump.Write(buf, task.au.size);
free(buf);
dump.Close();
}
}*/
if (adec.just_started) // deferred initialization
{
err = avformat_open_input(&adec.fmt, NULL, NULL, NULL);
err = avformat_open_input(&adec.fmt, NULL, av_find_input_format("oma"), NULL);
if (err)
{
ConLog.Error("adecDecodeAu: avformat_open_input() failed");
@ -230,7 +321,7 @@ u32 adecOpen(AudioDecoder* data)
Emu.Pause();
break;
}
err = avformat_find_stream_info(adec.fmt, NULL);
/*err = avformat_find_stream_info(adec.fmt, NULL);
if (err)
{
ConLog.Error("adecDecodeAu: avformat_find_stream_info() failed");
@ -242,6 +333,12 @@ u32 adecOpen(AudioDecoder* data)
ConLog.Error("adecDecodeAu: no stream found");
Emu.Pause();
break;
}*/
if (!avformat_new_stream(adec.fmt, codec))
{
ConLog.Error("adecDecodeAu: avformat_new_stream() failed");
Emu.Pause();
break;
}
adec.ctx = adec.fmt->streams[0]->codec; // TODO: check data
@ -259,7 +356,7 @@ u32 adecOpen(AudioDecoder* data)
break;
}
adec.just_started = false;
}*/
}
bool last_frame = false;
@ -271,7 +368,7 @@ u32 adecOpen(AudioDecoder* data)
return;
}
if (!adec.ctx) // fake
/*if (!adec.ctx) // fake
{
AdecFrame frame;
frame.pts = task.au.pts;
@ -285,7 +382,7 @@ u32 adecOpen(AudioDecoder* data)
adec.adecCb->ExecAsCallback(adec.cbFunc, false, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg);
break;
}
}*/
last_frame = av_read_frame(adec.fmt, &au) < 0;
if (last_frame)
@ -336,13 +433,30 @@ u32 adecOpen(AudioDecoder* data)
if (got_frame)
{
ConLog.Write("got_frame (%d, pts=0x%llx, dts=0x%llx)", got_frame, au.pts, au.dts);
frame.pts = task.au.pts; // ???
frame.pts = adec.last_pts;
adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / 48000; // ???
frame.auAddr = task.au.addr;
frame.auSize = task.au.size;
frame.userdata = task.au.userdata;
frame.size = 32768; // ????
frame.size = frame.data->nb_samples * frame.data->channels * sizeof(float);
if (frame.data->format != AV_SAMPLE_FMT_FLTP)
{
ConLog.Error("adecDecodeaAu: unsupported frame format(%d)", frame.data->format);
Emu.Pause();
break;
}
if (frame.data->channels != 2)
{
ConLog.Error("adecDecodeAu: unsupported channel count (%d)", frame.data->channels);
Emu.Pause();
break;
}
//ConLog.Write("got audio frame (pts=0x%llx, nb_samples=%d, ch=%d, sample_rate=%d, nbps=%d)",
//frame.pts, frame.data->nb_samples, frame.data->channels, frame.data->sample_rate,
//av_get_bytes_per_sample((AVSampleFormat)frame.data->format));
adec.frames.Push(frame);
frame.data = nullptr; // to prevent destruction
@ -569,26 +683,62 @@ int cellAdecGetPcm(u32 handle, u32 outBuffer_addr)
AdecFrame af;
adec->frames.Pop(af);
//AVFrame& frame = *af.data;
AVFrame* frame = af.data;
int result = CELL_OK;
if (!Memory.IsGoodAddr(outBuffer_addr, af.size))
{
result = CELL_ADEC_ERROR_FATAL;
goto end;
}
else
if (!af.data) // fake: empty data
{
// copy data
if (!af.data) // fake: empty data
{
u8* buf = (u8*)malloc(4096);
memset(buf, 0, 4096);
Memory.CopyFromReal(outBuffer_addr, buf, 4096);
free(buf);
return CELL_OK;
}
/*u8* buf = (u8*)malloc(4096);
memset(buf, 0, 4096);
Memory.CopyFromReal(outBuffer_addr, buf, 4096);
free(buf);*/
goto end;
}
// copy data
SwrContext* swr = nullptr;
u8* out = nullptr;
out = (u8*)malloc(af.size);
/*swr = swr_alloc_set_opts(NULL, AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_FLT, 48000,
frame->channel_layout, (AVSampleFormat)frame->format, frame->sample_rate, 0, NULL);
if (!swr)
{
ConLog.Error("cellAdecGetPcm(%d): swr_alloc_set_opts() failed", handle);
Emu.Pause();
goto end;
}
// something is wrong
swr_convert(swr, &out, frame->nb_samples, (const u8**)frame->extended_data, frame->nb_samples); */
// reverse byte order, extract data:
float* in_f[2];
in_f[0] = (float*)frame->extended_data[0];
in_f[1] = (float*)frame->extended_data[1];
be_t<float>* out_f = (be_t<float>*)out;
for (u32 i = 0; i < af.size / 8; i++)
{
out_f[i*2] = in_f[0][i];
out_f[i*2+1] = in_f[1][i];
}
if (!Memory.CopyFromReal(outBuffer_addr, out, af.size))
{
ConLog.Error("cellAdecGetPcm(%d): data copying failed (addr=0x%x)", handle, outBuffer_addr);
Emu.Pause();
}
end:
if (out) free(out);
if (swr) swr_free(&swr);
if (af.data)
{
@ -620,7 +770,7 @@ int cellAdecGetPcmItem(u32 handle, mem32_t pcmItem_ptr)
return CELL_ADEC_ERROR_EMPTY;
}
//AVFrame& frame = *af.data;
AVFrame* frame = af.data;
mem_ptr_t<CellAdecPcmItem> pcm(adec->memAddr + adec->memBias);
@ -635,15 +785,15 @@ int cellAdecGetPcmItem(u32 handle, mem32_t pcmItem_ptr)
pcm->startAddr = 0x00000312; // invalid address (no output)
pcm->size = af.size;
pcm->status = CELL_OK;
pcm->auInfo.pts.lower = af.pts; // ???
pcm->auInfo.pts.lower = af.pts;
pcm->auInfo.pts.upper = af.pts >> 32;
pcm->auInfo.size = af.auSize;
pcm->auInfo.startAddr = af.auAddr;
pcm->auInfo.userData = af.userdata;
mem_ptr_t<CellAdecAtracXInfo> atx(pcm.GetAddr() + sizeof(CellAdecPcmItem));
atx->samplingFreq = 48000; // ???
atx->nbytes = 2048; // ???
atx->samplingFreq = frame->sample_rate; // ???
atx->nbytes = frame->nb_samples * frame->channels * sizeof(float); // ???
atx->channelConfigIndex = CELL_ADEC_CH_STEREO; // ???
pcmItem_ptr = pcm.GetAddr();

View File

@ -1036,6 +1036,40 @@ struct AdecFrame
int adecRead(void* opaque, u8* buf, int buf_size);
struct OMAHeader // OMA Header
{
u32 magic; // 0x01334145
u16 size; // 96 << 8
u16 unk0; // 0xffff
u64 unk1; // 0x00500f0100000000ULL
u64 unk2; // 0xcef5000000000400ULL
u64 unk3; // 0x1c458024329192d2ULL
u8 codecId; // 1 for ATRAC3P
u8 reserved0; // 0
u8 code1;
u8 code2;
u32 reserved1; // 0
u64 reserved[7]; // 0
OMAHeader(u8 id, u8 code1, u8 code2)
: magic(0x01334145)
, size(96 << 8)
, unk0(0xffff)
, unk1(0x00500f0100000000ULL)
, unk2(0xcef5000000000400ULL)
, unk3(0x1c458024329192d2ULL)
, codecId(id)
, reserved0(0)
, code1(code1)
, code2(code2)
, reserved1(0)
{
memset(reserved, 0, sizeof(reserved));
}
};
static_assert(sizeof(OMAHeader) == 96, "Wrong OMAHeader size");
class AudioDecoder
{
public:
@ -1053,6 +1087,21 @@ public:
{
u32 addr;
u32 size;
bool init;
u8* rem;
u32 rem_size;
AudioReader()
: rem(nullptr)
, rem_size(0)
{
}
~AudioReader()
{
if (rem) free(rem);
rem = nullptr;
}
} reader;
SQueue<AdecFrame> frames;

View File

@ -5,32 +5,7 @@
void cellAtrac_init();
Module cellAtrac(0x0013, cellAtrac_init);
// Return Codes
enum
{
CELL_ATRAC_OK = 0x00000000,
CELL_ATRAC_ERROR_API_FAIL = 0x80610301,
CELL_ATRAC_ERROR_READSIZE_OVER_BUFFER = 0x80610311,
CELL_ATRAC_ERROR_UNKNOWN_FORMAT = 0x80610312,
CELL_ATRAC_ERROR_READSIZE_IS_TOO_SMALL = 0x80610313,
CELL_ATRAC_ERROR_ILLEGAL_SAMPLING_RATE = 0x80610314,
CELL_ATRAC_ERROR_ILLEGAL_DATA = 0x80610315,
CELL_ATRAC_ERROR_NO_DECODER = 0x80610321,
CELL_ATRAC_ERROR_UNSET_DATA = 0x80610322,
CELL_ATRAC_ERROR_DECODER_WAS_CREATED = 0x80610323,
CELL_ATRAC_ERROR_ALLDATA_WAS_DECODED = 0x80610331,
CELL_ATRAC_ERROR_NODATA_IN_BUFFER = 0x80610332,
CELL_ATRAC_ERROR_NOT_ALIGNED_OUT_BUFFER = 0x80610333,
CELL_ATRAC_ERROR_NEED_SECOND_BUFFER = 0x80610334,
CELL_ATRAC_ERROR_ALLDATA_IS_ONMEMORY = 0x80610341,
CELL_ATRAC_ERROR_ADD_DATA_IS_TOO_BIG = 0x80610342,
CELL_ATRAC_ERROR_NONEED_SECOND_BUFFER = 0x80610351,
CELL_ATRAC_ERROR_UNSET_LOOP_NUM = 0x80610361,
CELL_ATRAC_ERROR_ILLEGAL_SAMPLE = 0x80610371,
CELL_ATRAC_ERROR_ILLEGAL_RESET_BYTE = 0x80610372,
CELL_ATRAC_ERROR_ILLEGAL_PPU_THREAD_PRIORITY = 0x80610381,
CELL_ATRAC_ERROR_ILLEGAL_SPU_THREAD_PRIORITY = 0x80610382,
};
#include "cellAtrac.h"
int cellAtracSetDataAndGetMemSize()
{
@ -58,13 +33,13 @@ int cellAtracDeleteDecoder()
int cellAtracDecode()
{
UNIMPLEMENTED_FUNC(cellAtrac);
//UNIMPLEMENTED_FUNC(cellAtrac);
return CELL_OK;
}
int cellAtracGetStreamDataInfo()
{
UNIMPLEMENTED_FUNC(cellAtrac);
//UNIMPLEMENTED_FUNC(cellAtrac);
return CELL_OK;
}

View File

@ -0,0 +1,28 @@
#pragma once
// Return Codes
enum
{
CELL_ATRAC_OK = 0x00000000,
CELL_ATRAC_ERROR_API_FAIL = 0x80610301,
CELL_ATRAC_ERROR_READSIZE_OVER_BUFFER = 0x80610311,
CELL_ATRAC_ERROR_UNKNOWN_FORMAT = 0x80610312,
CELL_ATRAC_ERROR_READSIZE_IS_TOO_SMALL = 0x80610313,
CELL_ATRAC_ERROR_ILLEGAL_SAMPLING_RATE = 0x80610314,
CELL_ATRAC_ERROR_ILLEGAL_DATA = 0x80610315,
CELL_ATRAC_ERROR_NO_DECODER = 0x80610321,
CELL_ATRAC_ERROR_UNSET_DATA = 0x80610322,
CELL_ATRAC_ERROR_DECODER_WAS_CREATED = 0x80610323,
CELL_ATRAC_ERROR_ALLDATA_WAS_DECODED = 0x80610331,
CELL_ATRAC_ERROR_NODATA_IN_BUFFER = 0x80610332,
CELL_ATRAC_ERROR_NOT_ALIGNED_OUT_BUFFER = 0x80610333,
CELL_ATRAC_ERROR_NEED_SECOND_BUFFER = 0x80610334,
CELL_ATRAC_ERROR_ALLDATA_IS_ONMEMORY = 0x80610341,
CELL_ATRAC_ERROR_ADD_DATA_IS_TOO_BIG = 0x80610342,
CELL_ATRAC_ERROR_NONEED_SECOND_BUFFER = 0x80610351,
CELL_ATRAC_ERROR_UNSET_LOOP_NUM = 0x80610361,
CELL_ATRAC_ERROR_ILLEGAL_SAMPLE = 0x80610371,
CELL_ATRAC_ERROR_ILLEGAL_RESET_BYTE = 0x80610372,
CELL_ATRAC_ERROR_ILLEGAL_PPU_THREAD_PRIORITY = 0x80610381,
CELL_ATRAC_ERROR_ILLEGAL_SPU_THREAD_PRIORITY = 0x80610382,
};

View File

@ -118,29 +118,37 @@ int cellAudioInit()
index = (position + 1) % port.block; // write new value
}
u32 k = port.channel / 2;
if (first_mix)
{
for (u32 i = 0; i < (sizeof(buffer) / sizeof(float)); i++)
for (u32 i = 0; i < (sizeof(buffer) / sizeof(float)); i += 2)
{
// reverse byte order (TODO: use port.m_param.level)
buffer[i] = buffer2[i];
buffer[i] = buffer2[i*k];
buffer[i+1] = buffer2[i*k+1];
// convert the data from float to u16
assert(buffer[i] >= -4.0f && buffer[i] <= 4.0f);
assert(buffer[i+1] >= -4.0f && buffer[i+1] <= 4.0f);
oal_buffer[oal_buffer_offset + i] = (u16)(buffer[i] * ((1 << 13) - 1));
oal_buffer[oal_buffer_offset + i + 1] = (u16)(buffer[i+1] * ((1 << 13) - 1));
}
first_mix = false;
}
else
{
for (u32 i = 0; i < (sizeof(buffer) / sizeof(float)); i++)
for (u32 i = 0; i < (sizeof(buffer) / sizeof(float)); i += 2)
{
buffer[i] = (buffer[i] + buffer2[i]) * 0.5; // TODO: valid mixing
buffer[i] = (buffer[i] + buffer2[i*k]) * 0.5; // TODO: valid mixing
buffer[i+1] = (buffer[i+1] + buffer2[i*k+1]) * 0.5;
// convert the data from float to u16
assert(buffer[i] >= -4.0f && buffer[i] <= 4.0f);
assert(buffer[i+1] >= -4.0f && buffer[i+1] <= 4.0f);
oal_buffer[oal_buffer_offset + i] = (u16)(buffer[i] * ((1 << 13) - 1));
oal_buffer[oal_buffer_offset + i + 1] = (u16)(buffer[i+1] * ((1 << 13) - 1));
}
}
}
@ -176,8 +184,6 @@ int cellAudioInit()
ConLog.Error("Port aborted: cannot write file!");
goto abort;
}
m_dump.UpdateHeader(sizeof(buffer));
}
}
ConLog.Write("Audio finished");

View File

@ -18,9 +18,9 @@ void dmuxQueryEsAttr(u32 info_addr /* may be 0 */, const mem_ptr_t<CellCodecEsFi
const u32 esSpecificInfo_addr, mem_ptr_t<CellDmuxEsAttr> attr)
{
if (esFilterId->filterIdMajor >= 0xe0)
attr->memSize = 0x3000000; // 0x45fa49 from ps3
attr->memSize = 0x500000; // 0x45fa49 from ps3
else
attr->memSize = 0x200000; // 0x73d9 from ps3
attr->memSize = 0x8000; // 0x73d9 from ps3
cellDmux.Warning("*** filter(0x%x, 0x%x, 0x%x, 0x%x)", (u32)esFilterId->filterIdMajor, (u32)esFilterId->filterIdMinor,
(u32)esFilterId->supplementalInfo1, (u32)esFilterId->supplementalInfo2);
@ -131,7 +131,7 @@ u32 dmuxOpen(Demuxer* data)
}
// read additional header:
stream.peek(ch);
stream.peek(ch); // ???
//stream.skip(4);
//pes.size += 4;
@ -148,26 +148,18 @@ u32 dmuxOpen(Demuxer* data)
Sleep(1);
}
/*if (es.hasunseen()) // hack, probably useless
if (es.hasunseen()) // hack, probably useless
{
stream = backup;
continue;
}*/
//ConLog.Write("*** AT3+ AU sent (pts=0x%llx, dts=0x%llx)", pes.pts, pes.dts);
}
stream.skip(4);
len -= 4;
u32 abc;
stream.peek(abc);
if (abc == 0x5548D00F)
{
stream.skip(8);
len -= 8;
}
es.push(stream, len - pes.size - 3, pes);
es.finish(stream);
//ConLog.Write("*** AT3+ AU sent (len=0x%x, pts=0x%llx)", len - pes.size - 3, pes.pts);
mem_ptr_t<CellDmuxEsMsg> esMsg(a128(dmux.memAddr) + (cb_add ^= 16));
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND;
@ -211,13 +203,18 @@ u32 dmuxOpen(Demuxer* data)
stream.get(len);
PesHeader pes(stream);
if (es.freespace() < (u32)(len + 6))
{
pes.new_au = true;
}
if (pes.new_au && es.hasdata()) // new AU detected
{
/*if (es.hasunseen()) // hack, probably useless
if (es.hasunseen()) // hack, probably useless
{
stream = backup;
continue;
}*/
}
es.finish(stream);
// callback
mem_ptr_t<CellDmuxEsMsg> esMsg(a128(dmux.memAddr) + (cb_add ^= 16));
@ -298,8 +295,9 @@ u32 dmuxOpen(Demuxer* data)
{
case dmuxSetStream:
{
if (stream.discontinuity)
if (task.stream.discontinuity)
{
ConLog.Warning("dmuxSetStream (beginning)");
for (u32 i = 0; i < 192; i++)
{
if (esALL[i])
@ -319,8 +317,8 @@ u32 dmuxOpen(Demuxer* data)
updates_count++;
stream = task.stream;
ConLog.Write("*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)",
stream.addr, stream.size, stream.discontinuity, stream.userdata);
//ConLog.Write("*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)",
//stream.addr, stream.size, stream.discontinuity, stream.userdata);
dmux.is_running = true;
dmux.fbSetStream.Push(task.stream.addr); // feedback
@ -652,7 +650,7 @@ int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize
int cellDmuxResetStream(u32 demuxerHandle)
{
cellDmux.Log("cellDmuxResetStream(demuxerHandle=%d)", demuxerHandle);
cellDmux.Warning("cellDmuxResetStream(demuxerHandle=%d)", demuxerHandle);
Demuxer* dmux;
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
@ -667,7 +665,7 @@ int cellDmuxResetStream(u32 demuxerHandle)
int cellDmuxResetStreamAndWaitDone(u32 demuxerHandle)
{
cellDmux.Log("cellDmuxResetStreamAndWaitDone(demuxerHandle=%d)", demuxerHandle);
cellDmux.Warning("cellDmuxResetStreamAndWaitDone(demuxerHandle=%d)", demuxerHandle);
Demuxer* dmux;
if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux))
@ -947,9 +945,7 @@ int cellDmuxPeekAuEx(u32 esHandle, mem32_t auInfoEx_ptr, mem32_t auSpecificInfo_
int cellDmuxReleaseAu(u32 esHandle)
{
cellDmux.Log("(disabled) cellDmuxReleaseAu(esHandle=0x%x)", esHandle);
return CELL_OK;
cellDmux.Log("cellDmuxReleaseAu(esHandle=0x%x)", esHandle);
ElementaryStream* es;
if (!Emu.GetIdManager().GetIDData(esHandle, es))

View File

@ -483,23 +483,29 @@ class ElementaryStream
{
SMutex mutex;
u32 first_addr; // AU that will be released
u32 last_addr; // AU that is being written now
u32 last_size; // number of bytes written (after 128b header)
u32 peek_addr; // AU that will be obtained by GetAu(Ex)/PeekAu(Ex)
SQueue<u32> entries; // AU starting addresses
u32 put_count; // number of AU written
u32 released; // number of AU released
u32 peek_count; // number of AU obtained by GetAu(Ex)
u32 put; // AU that is being written now
u32 size; // number of bytes written (after 128b header)
//u32 first; // AU that will be released
//u32 peek; // AU that will be obtained by GetAu(Ex)/PeekAu(Ex)
bool is_full()
{
if (first_addr)
if (released < put_count)
{
if (first_addr >= last_addr)
u32 first = entries.Peek();
if (first >= put)
{
return (first_addr - last_addr) <= GetMaxAU();
return (first - put) < GetMaxAU();
}
else
{
// probably, always false
return (last_addr + GetMaxAU()) > (memAddr + memSize);
return (put + GetMaxAU()) > (memAddr + memSize);
}
}
else
@ -532,26 +538,42 @@ public:
, cbFunc(cbFunc)
, cbArg(cbArg)
, spec(spec)
, first_addr(0)
, peek_addr(0)
, last_addr(memAddr)
, last_size(0)
//, first(0)
//, peek(0)
, put(memAddr)
, size(0)
, put_count(0)
, released(0)
, peek_count(0)
{
}
const u32 GetMaxAU() const
{
return 640 * 1024 + 128;
return (fidMajor == 0xbd) ? 4096 : 640 * 1024 + 128; // TODO
}
volatile bool hasunseen()
u32 freespace()
{
return peek_addr;
if (size > GetMaxAU())
{
ConLog.Error("es::freespace(): last_size too big (size=0x%x, max_au=0x%x)", size, GetMaxAU());
Emu.Pause();
return 0;
}
return GetMaxAU() - size;
}
volatile bool hasdata()
bool hasunseen()
{
return last_size;
SMutexLocker lock(mutex);
return peek_count < put_count;
}
bool hasdata()
{
SMutexLocker lock(mutex);
return size;
}
bool isfull()
@ -562,54 +584,70 @@ public:
void finish(DemuxerStream& stream) // not multithread-safe
{
SMutexLocker lock(mutex);
//ConLog.Write("es::finish(): peek=0x%x, first=0x%x, last=0x%x, size=0x%x", peek_addr, first_addr, last_addr, last_size);
if (!first_addr)
u32 addr;
{
first_addr = last_addr;
}
if (!peek_addr)
{
peek_addr = last_addr;
}
SMutexLocker lock(mutex);
//if (fidMajor != 0xbd) ConLog.Write(">>> es::finish(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size);
u32 new_addr = a128(last_addr + 128 + last_size);
if ((new_addr + GetMaxAU()) > (memAddr + memSize))
{
last_addr = memAddr;
addr = put;
/*if (!first)
{
first = put;
}
if (!peek)
{
peek = put;
}*/
mem_ptr_t<CellDmuxAuInfo> info(put);
//if (fidMajor != 0xbd) ConLog.Warning("es::finish(): (%s) size = 0x%x, info_addr=0x%x, pts = 0x%x",
//wxString(fidMajor == 0xbd ? "ATRAC3P Audio" : "Video AVC").wx_str(),
//(u32)info->auSize, put, (u32)info->ptsLower);
u32 new_addr = a128(put + 128 + size);
if ((new_addr + GetMaxAU()) > (memAddr + memSize))
{
put = memAddr;
}
else
{
put = new_addr;
}
size = 0;
put_count++;
//if (fidMajor != 0xbd) ConLog.Write("<<< es::finish(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size);
}
else
if (!entries.Push(addr))
{
last_addr = new_addr;
ConLog.Error("es::finish() aborted (no space)");
}
last_size = 0;
}
void push(DemuxerStream& stream, u32 size, PesHeader& pes)
void push(DemuxerStream& stream, u32 sz, PesHeader& pes)
{
SMutexLocker lock(mutex);
//ConLog.Write("es::push(): peek=0x%x, first=0x%x, last=0x%x, size=0x%x", peek_addr, first_addr, last_addr, last_size);
if (is_full())
{
ConLog.Error("ElementaryStream::push(): buffer is full");
ConLog.Error("es::push(): buffer is full");
Emu.Pause();
return;
}
u32 data_addr = last_addr + 128 + last_size;
last_size += size;
if (!Memory.Copy(data_addr, stream.addr, size))
u32 data_addr = put + 128 + size;
size += sz;
if (!Memory.Copy(data_addr, stream.addr, sz))
{
ConLog.Error("ElementaryStream::push(): data copying failed");
ConLog.Error("es::push(): data copying failed");
Emu.Pause();
return;
}
stream.skip(size);
stream.skip(sz);
mem_ptr_t<CellDmuxAuInfoEx> info(last_addr);
info->auAddr = last_addr + 128;
info->auSize = last_size;
mem_ptr_t<CellDmuxAuInfoEx> info(put);
info->auAddr = put + 128;
info->auSize = size;
if (pes.new_au)
{
info->dts.lower = (u32)pes.dts;
@ -621,12 +659,12 @@ public:
info->userData = stream.userdata;
}
mem_ptr_t<CellDmuxPamfAuSpecificInfoAvc> tail(last_addr + sizeof(CellDmuxAuInfoEx));
mem_ptr_t<CellDmuxPamfAuSpecificInfoAvc> tail(put + sizeof(CellDmuxAuInfoEx));
tail->reserved1 = 0;
mem_ptr_t<CellDmuxAuInfo> inf(last_addr + 64);
inf->auAddr = last_addr + 128;
inf->auSize = last_size;
mem_ptr_t<CellDmuxAuInfo> inf(put + 64);
inf->auAddr = put + 128;
inf->auSize = size;
if (pes.new_au)
{
inf->dtsLower = (u32)pes.dts;
@ -641,76 +679,107 @@ public:
bool release()
{
SMutexLocker lock(mutex);
//ConLog.Write("es::release(): peek=0x%x, first=0x%x, last=0x%x, size=0x%x", peek_addr, first_addr, last_addr, last_size);
if (!first_addr)
//if (fidMajor != 0xbd) ConLog.Write(">>> es::release(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size);
if (released >= put_count)
{
ConLog.Error("ElementaryStream::release(): buffer is empty");
ConLog.Error("es::release(): buffer is empty");
return false;
}
u32 size = a128(Memory.Read32(first_addr + 4) + 128);
u32 new_addr = first_addr + size;
u32 addr = entries.Peek();
if (peek_addr == first_addr)
mem_ptr_t<CellDmuxAuInfo> info(addr);
//if (fidMajor != 0xbd) ConLog.Warning("es::release(): (%s) size = 0x%x, info = 0x%x, pts = 0x%x",
//wxString(fidMajor == 0xbd ? "ATRAC3P Audio" : "Video AVC").wx_str(), (u32)info->auSize, first, (u32)info->ptsLower);
if (released >= peek_count)
{
ConLog.Error("ElementaryStream::release(): buffer has not been seen yet");
ConLog.Error("es::release(): buffer has not been seen yet");
return false;
}
//if (peek_addr <= first_addr) peek_addr = new_addr;
if (new_addr == last_addr)
/*u32 new_addr = a128(info.GetAddr() + 128 + info->auSize);
if (new_addr == put)
{
first_addr = 0;
first = 0;
}
else if ((new_addr + GetMaxAU()) > (memAddr + memSize))
{
first_addr = memAddr;
first = memAddr;
}
else
{
first_addr = new_addr;
}
first = new_addr;
}*/
released++;
if (!entries.Pop(addr))
{
ConLog.Error("es::release(): entries.Pop() aborted (no entries found)");
return false;
}
//if (fidMajor != 0xbd) ConLog.Write("<<< es::release(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size);
return true;
}
bool peek(u32& out_data, bool no_ex, u32& out_spec, bool update_index)
{
SMutexLocker lock(mutex);
/*ConLog.Write("es::peek(%sAu%s): peek=0x%x, first=0x%x, last=0x%x, size=0x%x", wxString(update_index ? "Get" : "Peek").wx_str(),
wxString(no_ex ? "" : "Ex").wx_str(), peek_addr, first_addr, last_addr, last_size);*/
if (!peek_addr) return false;
//if (fidMajor != 0xbd) ConLog.Write(">>> es::peek(%sAu%s): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", wxString(update_index ? "Get" : "Peek").wx_str(),
//wxString(no_ex ? "" : "Ex").wx_str(), peek, first, put, size);
if (peek_count >= put_count) return false;
out_data = peek_addr;
if (peek_count < released)
{
ConLog.Error("es::peek(): sequence error: peek_count < released (peek_count=%d, released=%d)", peek_count, released);
Emu.Pause();
return false;
}
u32 addr = entries.Peek(peek_count - released);
mem_ptr_t<CellDmuxAuInfo> info(addr);
//if (fidMajor != 0xbd) ConLog.Warning("es::peek(%sAu(Ex)): (%s) size = 0x%x, info = 0x%x, pts = 0x%x",
//wxString(update_index ? "Get" : "Peek").wx_str(),
//wxString(fidMajor == 0xbd ? "ATRAC3P Audio" : "Video AVC").wx_str(), (u32)info->auSize, peek, (u32)info->ptsLower);
out_data = addr;
out_spec = out_data + sizeof(CellDmuxAuInfoEx);
if (no_ex) out_data += 64;
if (update_index)
{
u32 size = a128(Memory.Read32(peek_addr + 4) + 128);
u32 new_addr = peek_addr + size;
if (new_addr = last_addr)
/*u32 new_addr = a128(peek + 128 + info->auSize);
if (new_addr = put)
{
peek_addr = 0;
peek = 0;
}
else if ((new_addr + GetMaxAU()) > (memAddr + memSize))
{
peek_addr = memAddr;
peek = memAddr;
}
else
{
peek_addr = new_addr;
}
peek = new_addr;
}*/
peek_count++;
}
//if (fidMajor != 0xbd) ConLog.Write("<<< es::peek(%sAu%s): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", wxString(update_index ? "Get" : "Peek").wx_str(),
//wxString(no_ex ? "" : "Ex").wx_str(), peek, first, put, size);
return true;
}
void reset()
{
SMutexLocker lock(mutex);
first_addr = 0;
peek_addr = 0;
last_addr = memAddr;
last_size = 0;
//first = 0;
//peek = 0;
put = memAddr;
size = 0;
entries.Clear();
put_count = 0;
released = 0;
peek_count = 0;
}
};

View File

@ -37,6 +37,7 @@ uint32_t cellGcmGetMaxIoMapSize();
void cellGcmGetOffsetTable(mem_ptr_t<gcm_offset> table);
int32_t cellGcmIoOffsetToAddress(u32 ioOffset, u64 address);
int32_t cellGcmMapEaIoAddress(const u32 ea, const u32 io, const u32 size);
int32_t cellGcmMapEaIoAddressWithFlags(const u32 ea, const u32 io, const u32 size, const u32 flags);
int32_t cellGcmMapMainMemory(u64 ea, u32 size, mem32_t offset);
int32_t cellGcmReserveIoMapSize(const u32 size);
int32_t cellGcmUnmapEaIoAddress(u64 ea);
@ -68,6 +69,14 @@ int cellGcmInit(u32 context_addr, u32 cmdSize, u32 ioSize, u32 ioAddress)
cellGcmSys.Warning("*** local memory(addr=0x%x, size=0x%x)", local_addr, local_size);
InitOffsetTable();
Memory.MemoryBlocks.push_back(Memory.RSXIOMem.SetRange(0x50000000, 0x10000000/*256MB*/));//TODO: implement allocateAdressSpace in memoryBase
if(cellGcmMapEaIoAddress(ioAddress, 0, ioSize) != CELL_OK)
{
Memory.MemoryBlocks.pop_back();
return CELL_GCM_ERROR_FAILURE;
}
map_offset_addr = 0;
map_offset_pos = 0;
current_config.ioSize = ioSize;
@ -77,10 +86,7 @@ int cellGcmInit(u32 context_addr, u32 cmdSize, u32 ioSize, u32 ioAddress)
current_config.memoryFrequency = 650000000;
current_config.coreFrequency = 500000000;
InitOffsetTable();
Memory.RSXCMDMem.AllocAlign(cmdSize);
Memory.MemoryBlocks.push_back(Memory.RSXIOMem.SetRange(0x50000000, 0x10000000/*256MB*/));//TODO: implement allocateAdressSpace in memoryBase
cellGcmMapEaIoAddress(ioAddress, 0, ioSize);
u32 ctx_begin = ioAddress/* + 0x1000*/;
u32 ctx_size = 0x6ffc;
@ -677,6 +683,12 @@ int32_t cellGcmMapEaIoAddress(const u32 ea, const u32 io, const u32 size)
return CELL_OK;
}
int32_t cellGcmMapEaIoAddressWithFlags(const u32 ea, const u32 io, const u32 size, const u32 flags)
{
cellGcmSys.Warning("cellGcmMapEaIoAddressWithFlags(ea=0x%x, io=0x%x, size=0x%x, flags=0x%x)", ea, io, size, flags);
return cellGcmMapEaIoAddress(ea, io, size); // TODO: strict ordering
}
int32_t cellGcmMapLocalMemory(u64 address, u64 size)
{
if(!local_size && !local_addr)
@ -855,6 +867,7 @@ void cellGcmSys_init()
cellGcmSys.AddFunc(0x2922aed0, cellGcmGetOffsetTable);
cellGcmSys.AddFunc(0x2a6fba9c, cellGcmIoOffsetToAddress);
cellGcmSys.AddFunc(0x63441cb4, cellGcmMapEaIoAddress);
cellGcmSys.AddFunc(0x626e8518, cellGcmMapEaIoAddressWithFlags);
cellGcmSys.AddFunc(0xdb769b32, cellGcmMapLocalMemory);
cellGcmSys.AddFunc(0xa114ec67, cellGcmMapMainMemory);
cellGcmSys.AddFunc(0xa7ede268, cellGcmReserveIoMapSize);

View File

@ -19,6 +19,19 @@ enum
ConverterUnknown,
};
// detection result
enum
{
L10N_STR_UNKNOWN = (1 << 0),
L10N_STR_ASCII = (1 << 1),
L10N_STR_JIS = (1 << 2),
L10N_STR_EUCJP = (1 << 3),
L10N_STR_SJIS = (1 << 4),
L10N_STR_UTF8 = (1 << 5),
L10N_STR_ILLEGAL = (1 << 16),
L10N_STR_ERROR = (1 << 17),
};
int UTF16stoUTF8s(mem16_ptr_t utf16, mem64_t utf16_len, mem8_ptr_t utf8, mem64_t utf8_len)
{
cellL10n.Warning("UTF16stoUTF8s(utf16_addr=0x%x, utf16_len_addr=0x%x, utf8_addr=0x%x, utf8_len_addr=0x%x)",
@ -43,6 +56,13 @@ int UTF16stoUTF8s(mem16_ptr_t utf16, mem64_t utf16_len, mem8_ptr_t utf8, mem64_t
return ConversionOK;
}
int jstrchk(mem8_ptr_t jstr)
{
cellL10n.Log("jstrchk(jstr_addr=0x%x [%s])", jstr.GetAddr(), "omitted" /*Memory.ReadString(jstr.GetAddr()).wx_str()*/);
return L10N_STR_UTF8;
}
void cellL10n_init()
{
// NOTE: I think this module should be LLE'd instead of implementing all its functions
@ -132,7 +152,7 @@ void cellL10n_init()
// cellL10n.AddFunc(0x73f2cd21, SJISstoJISs);
// cellL10n.AddFunc(0x74496718, SBCStoUTF8);
// cellL10n.AddFunc(0x74871fe0, UTF8toUTF32);
// cellL10n.AddFunc(0x750c363d, jstrchk);
cellL10n.AddFunc(0x750c363d, jstrchk);
// cellL10n.AddFunc(0x7c5bde1c, UHCtoEUCKR);
// cellL10n.AddFunc(0x7c912bda, kuten2jis);
// cellL10n.AddFunc(0x7d07a1c2, UTF8toEUCCN);

View File

@ -66,9 +66,10 @@ next:
vdec.reader.addr = vdec.task.addr;
vdec.reader.size = vdec.task.size;
//ConLog.Write("Video AU: size = 0x%x, pts = 0x%llx, dts = 0x%llx", vdec.task.size, vdec.task.pts, vdec.task.dts);
vdec.last_pts = vdec.task.pts;
vdec.last_dts = vdec.task.dts;
//if (vdec.last_pts > vdec.task.pts) vdec.last_pts = vdec.task.pts;
//if (vdec.last_dts > vdec.task.dts) vdec.last_dts = vdec.task.dts;
}
break;
default:
@ -205,9 +206,15 @@ u32 vdecOpen(VideoDecoder* data)
vdec.reader.addr = task.addr;
vdec.reader.size = task.size;
//ConLog.Write("Video AU: size = 0x%x, pts = 0x%llx, dts = 0x%llx", task.size, task.pts, task.dts);
vdec.last_pts = task.pts;
vdec.last_dts = task.dts;
//if (vdec.last_pts > task.pts || vdec.just_started) vdec.last_pts = task.pts;
//if (vdec.last_dts > task.dts || vdec.just_started) vdec.last_dts = task.dts;
if (vdec.just_started)
{
vdec.last_pts = task.pts;
vdec.last_dts = task.dts;
}
struct AVPacketHolder : AVPacket
{
@ -350,11 +357,12 @@ u32 vdecOpen(VideoDecoder* data)
if (got_picture)
{
//ConLog.Write("got_picture (%d, vdec: pts=0x%llx, dts=0x%llx)", got_picture, au.pts, au.dts);
frame.dts = vdec.last_dts; vdec.last_dts += 3003; // + duration???
frame.pts = vdec.last_pts; vdec.last_pts += 3003;
frame.userdata = task.userData;
//ConLog.Write("got picture (pts=0x%llx, dts=0x%llx)", frame.pts, frame.dts);
vdec.frames.Push(frame); // !!!!!!!!
frame.data = nullptr; // to prevent destruction

View File

@ -1,6 +1,12 @@
#include "stdafx.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/SysCalls/SC_FUNC.h"
extern "C"
{
#include "libswscale/swscale.h"
}
#include "cellVpost.h"
void cellVpost_init();
@ -93,13 +99,15 @@ int cellVpostExec(u32 handle, const u32 inPicBuff_addr, const mem_ptr_t<CellVpos
u32 w = ctrlParam->inWidth;
u32 h = ctrlParam->inHeight;
u32 ow = ctrlParam->outWidth;
u32 oh = ctrlParam->outHeight;
if (!Memory.IsGoodAddr(inPicBuff_addr, w*h*3/2))
{
return CELL_VPOST_ERROR_E_ARG_INPICBUF_INVALID;
}
if (!Memory.IsGoodAddr(outPicBuff_addr, w*h*4))
if (!Memory.IsGoodAddr(outPicBuff_addr, ow*oh*4))
{
return CELL_VPOST_ERROR_E_ARG_OUTPICBUF_INVALID;
}
@ -110,13 +118,21 @@ int cellVpostExec(u32 handle, const u32 inPicBuff_addr, const mem_ptr_t<CellVpos
}
ctrlParam->inWindow; // ignored
if (ctrlParam->inWindow.x) ConLog.Warning("*** inWindow.x = %d", (u32)ctrlParam->inWindow.x);
if (ctrlParam->inWindow.y) ConLog.Warning("*** inWindow.y = %d", (u32)ctrlParam->inWindow.y);
if (ctrlParam->inWindow.width != w) ConLog.Warning("*** inWindow.width = %d", (u32)ctrlParam->inWindow.width);
if (ctrlParam->inWindow.height != h) ConLog.Warning("*** inWindow.height = %d", (u32)ctrlParam->inWindow.height);
ctrlParam->outWindow; // ignored
if (ctrlParam->outWindow.x) ConLog.Warning("*** outWindow.x = %d", (u32)ctrlParam->outWindow.x);
if (ctrlParam->outWindow.y) ConLog.Warning("*** outWindow.y = %d", (u32)ctrlParam->outWindow.y);
if (ctrlParam->outWindow.width != ow) ConLog.Warning("*** outWindow.width = %d", (u32)ctrlParam->outWindow.width);
if (ctrlParam->outWindow.height != oh) ConLog.Warning("*** outWindow.height = %d", (u32)ctrlParam->outWindow.height);
ctrlParam->execType; // ignored
ctrlParam->scalerType; // ignored
ctrlParam->ipcType; // ignored
picInfo->inWidth = ctrlParam->inWidth; // copy
picInfo->inHeight = ctrlParam->inHeight; // copy
picInfo->inWidth = w; // copy
picInfo->inHeight = h; // copy
picInfo->inDepth = CELL_VPOST_PIC_DEPTH_8; // fixed
picInfo->inScanType = CELL_VPOST_SCAN_TYPE_P; // TODO
picInfo->inPicFmt = CELL_VPOST_PIC_FMT_IN_YUV420_PLANAR; // fixed
@ -125,24 +141,25 @@ int cellVpostExec(u32 handle, const u32 inPicBuff_addr, const mem_ptr_t<CellVpos
picInfo->inQuantRange = ctrlParam->inQuantRange; // copy
picInfo->inColorMatrix = ctrlParam->inColorMatrix; // copy
picInfo->outWidth = picInfo->inWidth; // TODO (resampling)
picInfo->outHeight = picInfo->inHeight; // TODO
picInfo->outWidth = ow; // copy
picInfo->outHeight = oh; // copy
picInfo->outDepth = CELL_VPOST_PIC_DEPTH_8; // fixed
picInfo->outScanType = CELL_VPOST_SCAN_TYPE_P; // TODO
picInfo->outPicFmt = CELL_VPOST_PIC_FMT_OUT_RGBA_ILV; // TODO
picInfo->outChromaPosType = ctrlParam->inChromaPosType; // ???
picInfo->outPicStruct = picInfo->inPicStruct; // ???
picInfo->outQuantRange = ctrlParam->inQuantRange; // ???
picInfo->outColorMatrix = ctrlParam->inColorMatrix; // ???
picInfo->outChromaPosType = ctrlParam->inChromaPosType; // ignored
picInfo->outPicStruct = picInfo->inPicStruct; // ignored
picInfo->outQuantRange = ctrlParam->inQuantRange; // ignored
picInfo->outColorMatrix = ctrlParam->inColorMatrix; // ignored
picInfo->userData = ctrlParam->userData; // copy
picInfo->reserved1 = 0;
picInfo->reserved2 = 0;
u8* pY = (u8*)malloc(w*h); // color planes
u8* pU = (u8*)malloc(w*h/4);
u8* pV = (u8*)malloc(w*h/4);
u32* res = (u32*)malloc(w*h*4); // RGBA interleaved output
u8* pA = (u8*)malloc(w*h);
u32* res = (u32*)malloc(ow*oh*4); // RGBA interleaved output
const u8 alpha = ctrlParam->outAlpha;
if (!Memory.CopyToReal(pY, inPicBuff_addr, w*h))
@ -163,6 +180,20 @@ int cellVpostExec(u32 handle, const u32 inPicBuff_addr, const mem_ptr_t<CellVpos
Emu.Pause();
}
memset(pA, alpha, w*h);
SwsContext* sws = sws_getContext(w, h, AV_PIX_FMT_YUVA420P, ow, oh, AV_PIX_FMT_RGBA, SWS_BILINEAR, NULL, NULL, NULL);
u8* in_data[4] = { pY, pU, pV, pA };
int in_line[4] = { w, w/2, w/2, w };
u8* out_data[4] = { (u8*)res, NULL, NULL, NULL };
int out_line[4] = { ow*4, 0, 0, 0 };
sws_scale(sws, in_data, in_line, 0, h, out_data, out_line);
sws_freeContext(sws);
/*
for (u32 i = 0; i < h; i++) for (u32 j = 0; j < w; j++)
{
float Cr = pV[(i/2)*(w/2)+j/2] - 128;
@ -179,9 +210,9 @@ int cellVpostExec(u32 handle, const u32 inPicBuff_addr, const mem_ptr_t<CellVpos
if (B < 0) B = 0;
if (B > 255) B = 255;
res[i*w+j] = ((u32)alpha << 24) | (B << 16) | (G << 8) | (R);
}
}*/
if (!Memory.CopyFromReal(outPicBuff_addr, res, w*h*4))
if (!Memory.CopyFromReal(outPicBuff_addr, res, ow*oh*4))
{
cellVpost.Error("cellVpostExec: data copying failed(result)");
Emu.Pause();
@ -190,6 +221,7 @@ int cellVpostExec(u32 handle, const u32 inPicBuff_addr, const mem_ptr_t<CellVpos
free(pY);
free(pU);
free(pV);
free(pA);
free(res);
return CELL_OK;
}

View File

@ -106,7 +106,7 @@ static func_caller* sc_table[1024] =
bind_func(sys_spu_thread_get_exit_status), bind_func(sys_spu_thread_set_argument), null_func, null_func, bind_func(sys_spu_initialize), //169
bind_func(sys_spu_thread_group_create), bind_func(sys_spu_thread_group_destroy), bind_func(sys_spu_thread_initialize), //172
bind_func(sys_spu_thread_group_start), bind_func(sys_spu_thread_group_suspend), //174
null_func, null_func, null_func, bind_func(sys_spu_thread_group_join), null_func, //179
bind_func(sys_spu_thread_group_resume), null_func, null_func, bind_func(sys_spu_thread_group_join), null_func, //179
null_func, bind_func(sys_spu_thread_write_ls), bind_func(sys_spu_thread_read_ls), null_func, bind_func(sys_spu_thread_write_snr), //184
bind_func(sys_spu_thread_group_connect_event), bind_func(sys_spu_thread_group_disconnect_event), //186
bind_func(sys_spu_thread_set_spu_cfg), bind_func(sys_spu_thread_get_spu_cfg), null_func, //189

View File

@ -356,6 +356,7 @@ extern int sys_spu_thread_set_argument(u32 id, mem_ptr_t<sys_spu_thread_argument
extern int sys_spu_thread_group_destroy(u32 id);
extern int sys_spu_thread_group_start(u32 id);
extern int sys_spu_thread_group_suspend(u32 id);
extern int sys_spu_thread_group_resume(u32 id);
extern int sys_spu_thread_group_create(mem32_t id, u32 num, int prio, mem_ptr_t<sys_spu_thread_group_attribute> attr);
extern int sys_spu_thread_create(mem32_t thread_id, mem32_t entry, u64 arg, int prio, u32 stacksize, u64 flags, u32 threadname_addr);
extern int sys_spu_thread_group_join(u32 id, mem32_t cause, mem32_t status);

View File

@ -74,7 +74,7 @@ int sys_cond_signal(u32 cond_id)
if (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? cond->m_queue.pop_prio() : cond->m_queue.pop()))
{
cond->cond.lock(target);
cond->signal.lock(target);
if (Emu.IsStopped())
{
@ -99,7 +99,7 @@ int sys_cond_signal_all(u32 cond_id)
while (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? cond->m_queue.pop_prio() : cond->m_queue.pop()))
{
cond->cond.lock(target);
cond->signal.lock(target);
if (Emu.IsStopped())
{
@ -134,7 +134,7 @@ int sys_cond_signal_to(u32 cond_id, u32 thread_id)
u32 target = thread_id;
{
cond->cond.lock(target);
cond->signal.lock(target);
}
if (Emu.IsStopped())
@ -160,24 +160,46 @@ int sys_cond_wait(u32 cond_id, u64 timeout)
if (mutex->m_mutex.GetOwner() != tid)
{
sys_cond.Warning("sys_cond_wait(cond_id=%d) failed (EPERM)", cond_id);
return CELL_EPERM;
}
cond->m_queue.push(tid);
if (mutex->recursive != 1)
{
sys_cond.Warning("sys_cond_wait(cond_id=%d): associated mutex had wrong recursive value (%d)", cond_id, mutex->recursive);
}
mutex->recursive = 0;
mutex->m_mutex.unlock(tid);
mutex->m_mutex.unlock(tid, mutex->protocol == SYS_SYNC_PRIORITY ? mutex->m_queue.pop_prio() : mutex->m_queue.pop());
u32 counter = 0;
const u32 max_counter = timeout ? (timeout / 1000) : ~0;
while (true)
{
if (cond->cond.GetOwner() == tid)
if (cond->signal.unlock(tid, tid) == SMR_OK)
{
mutex->m_mutex.lock(tid);
if (SMutexResult res = mutex->m_mutex.trylock(tid))
{
if (res != SMR_FAILED)
{
goto abort;
}
mutex->m_queue.push(tid);
switch (mutex->m_mutex.lock(tid))
{
case SMR_OK:
mutex->m_queue.invalidate(tid);
case SMR_SIGNAL:
break;
default:
goto abort;
}
}
mutex->recursive = 1;
cond->cond.unlock(tid);
cond->signal.unlock(tid);
return CELL_OK;
}
@ -186,13 +208,16 @@ int sys_cond_wait(u32 cond_id, u64 timeout)
if (counter++ > max_counter)
{
cond->m_queue.invalidate(tid);
GetCurrentPPUThread().owned_mutexes--;
GetCurrentPPUThread().owned_mutexes--; // ???
return CELL_ETIMEDOUT;
}
if (Emu.IsStopped())
{
ConLog.Warning("sys_cond_wait(id=%d) aborted", cond_id);
return CELL_OK;
goto abort;
}
}
abort:
ConLog.Warning("sys_cond_wait(id=%d) aborted", cond_id);
return CELL_OK;
}

View File

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

View File

@ -16,10 +16,10 @@ int sys_event_flag_create(mem32_t eflag_id, mem_ptr_t<sys_event_flag_attr> attr,
switch (attr->protocol.ToBE())
{
case se32(SYS_SYNC_PRIORITY): sys_event_flag.Warning("TODO: SYS_SYNC_PRIORITY attr"); break;
case se32(SYS_SYNC_PRIORITY): break;
case se32(SYS_SYNC_RETRY): sys_event_flag.Warning("TODO: SYS_SYNC_RETRY attr"); break;
case se32(SYS_SYNC_PRIORITY_INHERIT): sys_event_flag.Warning("TODO: SYS_SYNC_PRIORITY_INHERIT attr"); break;
case se32(SYS_SYNC_FIFO): sys_event_flag.Warning("TODO: SYS_SYNC_FIFO attr"); break;
case se32(SYS_SYNC_FIFO): break;
default: return CELL_EINVAL;
}
@ -30,12 +30,12 @@ int sys_event_flag_create(mem32_t eflag_id, mem_ptr_t<sys_event_flag_attr> attr,
switch (attr->type.ToBE())
{
case se32(SYS_SYNC_WAITER_SINGLE): sys_event_flag.Warning("TODO: SYS_SYNC_WAITER_SINGLE type"); break;
case se32(SYS_SYNC_WAITER_MULTIPLE): sys_event_flag.Warning("TODO: SYS_SYNC_WAITER_MULTIPLE type"); break;
case se32(SYS_SYNC_WAITER_SINGLE): break;
case se32(SYS_SYNC_WAITER_MULTIPLE): break;
default: return CELL_EINVAL;
}
eflag_id = sys_event_flag.GetNewId(new event_flag(init, (u32)attr->protocol, (int)attr->type));
eflag_id = sys_event_flag.GetNewId(new EventFlag(init, (u32)attr->protocol, (int)attr->type));
sys_event_flag.Warning("*** event_flag created [%s] (protocol=0x%x, type=0x%x): id = %d",
wxString(attr->name, 8).wx_str(), (u32)attr->protocol, (int)attr->type, eflag_id.GetValue());
@ -47,9 +47,14 @@ int sys_event_flag_destroy(u32 eflag_id)
{
sys_event_flag.Warning("sys_event_flag_destroy(eflag_id=%d)", eflag_id);
event_flag* ef;
EventFlag* ef;
if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
if (ef->waiters.GetCount()) // ???
{
return CELL_EBUSY;
}
Emu.GetIdManager().RemoveID(eflag_id);
return CELL_OK;
@ -57,26 +62,220 @@ int sys_event_flag_destroy(u32 eflag_id)
int sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result, u64 timeout)
{
sys_event_flag.Error("sys_event_flag_wait(eflag_id=%d, bitptn=0x%llx, mode=0x%x, result_addr=0x%x, timeout=%lld)",
sys_event_flag.Warning("sys_event_flag_wait(eflag_id=%d, bitptn=0x%llx, mode=0x%x, result_addr=0x%x, timeout=%lld)",
eflag_id, bitptn, mode, result.GetAddr(), timeout);
return CELL_OK;
if (result.IsGood()) result = 0;
switch (mode & 0xf)
{
case SYS_EVENT_FLAG_WAIT_AND: break;
case SYS_EVENT_FLAG_WAIT_OR: break;
default: return CELL_EINVAL;
}
switch (mode & ~0xf)
{
case 0: break; // ???
case SYS_EVENT_FLAG_WAIT_CLEAR: break;
case SYS_EVENT_FLAG_WAIT_CLEAR_ALL: break;
default: return CELL_EINVAL;
}
EventFlag* ef;
if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
u32 tid = GetCurrentPPUThread().GetId();
{
SMutexLocker lock(ef->m_mutex);
if (ef->m_type == SYS_SYNC_WAITER_SINGLE && ef->waiters.GetCount() > 0)
{
return CELL_EPERM;
}
EventFlagWaiter rec;
rec.bitptn = bitptn;
rec.mode = mode;
rec.tid = tid;
ef->waiters.AddCpy(rec);
if (ef->check() == tid)
{
u64 flags = ef->flags;
ef->waiters.RemoveAt(ef->waiters.GetCount() - 1);
if (mode & SYS_EVENT_FLAG_WAIT_CLEAR)
{
ef->flags &= ~bitptn;
}
else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL)
{
ef->flags = 0;
}
if (result.IsGood())
{
result = flags;
return CELL_OK;
}
if (!result.GetAddr())
{
return CELL_OK;
}
return CELL_EFAULT;
}
}
u32 counter = 0;
const u32 max_counter = timeout ? (timeout / 1000) : ~0;
while (true)
{
if (ef->signal.GetOwner() == tid)
{
SMutexLocker lock(ef->m_mutex);
ef->signal.unlock(tid);
u64 flags = ef->flags;
for (u32 i = 0; i < ef->waiters.GetCount(); i++)
{
if (ef->waiters[i].tid == tid)
{
ef->waiters.RemoveAt(i);
if (mode & SYS_EVENT_FLAG_WAIT_CLEAR)
{
ef->flags &= ~bitptn;
}
else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL)
{
ef->flags = 0;
}
if (result.IsGood())
{
result = flags;
return CELL_OK;
}
if (!result.GetAddr())
{
return CELL_OK;
}
return CELL_EFAULT;
}
}
return CELL_ECANCELED;
}
Sleep(1);
if (counter++ > max_counter)
{
SMutexLocker lock(ef->m_mutex);
for (u32 i = 0; i < ef->waiters.GetCount(); i++)
{
if (ef->waiters[i].tid == tid)
{
ef->waiters.RemoveAt(i);
break;
}
}
return CELL_ETIMEDOUT;
}
if (Emu.IsStopped())
{
ConLog.Warning("sys_event_flag_wait(id=%d) aborted", eflag_id);
return CELL_OK;
}
}
}
int sys_event_flag_trywait(u32 eflag_id, u64 bitptn, u32 mode, mem64_t result)
{
sys_event_flag.Error("sys_event_flag_trywait(eflag_id=%d, bitptn=0x%llx, mode=0x%x, result_addr=0x%x)",
sys_event_flag.Warning("sys_event_flag_trywait(eflag_id=%d, bitptn=0x%llx, mode=0x%x, result_addr=0x%x)",
eflag_id, bitptn, mode, result.GetAddr());
return CELL_OK;
if (result.IsGood()) result = 0;
switch (mode & 0xf)
{
case SYS_EVENT_FLAG_WAIT_AND: break;
case SYS_EVENT_FLAG_WAIT_OR: break;
default: return CELL_EINVAL;
}
switch (mode & ~0xf)
{
case 0: break; // ???
case SYS_EVENT_FLAG_WAIT_CLEAR: break;
case SYS_EVENT_FLAG_WAIT_CLEAR_ALL: break;
default: return CELL_EINVAL;
}
EventFlag* ef;
if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
SMutexLocker lock(ef->m_mutex);
u64 flags = ef->flags;
if (((mode & SYS_EVENT_FLAG_WAIT_AND) && (flags & bitptn) == bitptn) ||
((mode & SYS_EVENT_FLAG_WAIT_OR) && (flags & bitptn)))
{
if (mode & SYS_EVENT_FLAG_WAIT_CLEAR)
{
ef->flags &= ~bitptn;
}
else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL)
{
ef->flags = 0;
}
if (result.IsGood())
{
result = flags;
return CELL_OK;
}
if (!result.GetAddr())
{
return CELL_OK;
}
return CELL_EFAULT;
}
return CELL_EBUSY;
}
int sys_event_flag_set(u32 eflag_id, u64 bitptn)
{
sys_event_flag.Warning("sys_event_flag_set(eflag_id=%d, bitptn=0x%llx)", eflag_id, bitptn);
event_flag* ef;
EventFlag* ef;
if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
u32 tid = GetCurrentPPUThread().GetId();
ef->m_mutex.lock(tid);
ef->flags |= bitptn;
if (u32 target = ef->check())
{
// if signal, leave both mutexes locked...
ef->signal.lock(target);
ef->m_mutex.unlock(tid, target);
}
else
{
ef->m_mutex.unlock(tid);
}
return CELL_OK;
}
@ -85,9 +284,10 @@ int sys_event_flag_clear(u32 eflag_id, u64 bitptn)
{
sys_event_flag.Warning("sys_event_flag_clear(eflag_id=%d, bitptn=0x%llx)", eflag_id, bitptn);
event_flag* ef;
EventFlag* ef;
if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
SMutexLocker lock(ef->m_mutex);
ef->flags &= bitptn;
return CELL_OK;
@ -95,23 +295,61 @@ int sys_event_flag_clear(u32 eflag_id, u64 bitptn)
int sys_event_flag_cancel(u32 eflag_id, mem32_t num)
{
sys_event_flag.Error("sys_event_flag_cancel(eflag_id=%d, num_addr=0x%x)", eflag_id, num.GetAddr());
return CELL_OK;
sys_event_flag.Warning("sys_event_flag_cancel(eflag_id=%d, num_addr=0x%x)", eflag_id, num.GetAddr());
EventFlag* ef;
if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
Array<u32> tids;
{
SMutexLocker lock(ef->m_mutex);
tids.SetCount(ef->waiters.GetCount());
for (u32 i = 0; i < ef->waiters.GetCount(); i++)
{
tids[i] = ef->waiters[i].tid;
}
ef->waiters.Clear();
}
for (u32 i = 0; i < tids.GetCount(); i++)
{
if (Emu.IsStopped()) break;
ef->signal.lock(tids[i]);
}
if (Emu.IsStopped())
{
ConLog.Warning("sys_event_flag_cancel(id=%d) aborted", eflag_id);
return CELL_OK;
}
if (num.IsGood())
{
num = tids.GetCount();
return CELL_OK;
}
if (!num.GetAddr())
{
return CELL_OK;
}
return CELL_EFAULT;
}
int sys_event_flag_get(u32 eflag_id, mem64_t flags)
{
sys_event_flag.Warning("sys_event_flag_get(eflag_id=%d, flags_addr=0x%x)", eflag_id, flags.GetAddr());
EventFlag* ef;
if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
if (!flags.IsGood())
{
return CELL_EFAULT;
}
event_flag* ef;
if(!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
flags = ef->flags;
flags = ef->flags; // ???
return CELL_OK;
}

View File

@ -4,6 +4,12 @@ enum
{
SYS_SYNC_WAITER_SINGLE = 0x10000,
SYS_SYNC_WAITER_MULTIPLE = 0x20000,
SYS_EVENT_FLAG_WAIT_AND = 0x01,
SYS_EVENT_FLAG_WAIT_OR = 0x02,
SYS_EVENT_FLAG_WAIT_CLEAR = 0x10,
SYS_EVENT_FLAG_WAIT_CLEAR_ALL = 0x20,
};
struct sys_event_flag_attr
@ -16,16 +22,54 @@ struct sys_event_flag_attr
char name[8];
};
struct event_flag
struct EventFlagWaiter
{
std::atomic<u64> flags;
u32 tid;
u32 mode;
u64 bitptn;
};
struct EventFlag
{
SMutex m_mutex;
u64 flags;
Array<EventFlagWaiter> waiters;
SMutex signal;
const u32 m_protocol;
const int m_type;
event_flag(u64 pattern, u32 protocol, int type)
EventFlag(u64 pattern, u32 protocol, int type)
: flags(pattern)
, m_protocol(protocol)
, m_type(type)
{
}
u32 check()
{
SleepQueue sq; // TODO: implement without SleepQueue
u32 target = 0;
for (u32 i = 0; i < waiters.GetCount(); i++)
{
if (((waiters[i].mode & SYS_EVENT_FLAG_WAIT_AND) && (flags & waiters[i].bitptn) == waiters[i].bitptn) ||
((waiters[i].mode & SYS_EVENT_FLAG_WAIT_OR) && (flags & waiters[i].bitptn)))
{
if (m_protocol == SYS_SYNC_FIFO)
{
target = waiters[i].tid;
break;
}
sq.list.AddCpy(waiters[i].tid);
}
}
if (m_protocol == SYS_SYNC_PRIORITY)
{
target = sq.pop_prio();
}
return target;
}
};

View File

@ -16,7 +16,7 @@ int sys_lwcond_create(mem_ptr_t<sys_lwcond_t> lwcond, mem_ptr_t<sys_lwmutex_t> l
}
lwcond->lwmutex = lwmutex.GetAddr();
lwcond->lwcond_queue = sys_lwcond.GetNewId(new SleepQueue(attr->name_u64));
lwcond->lwcond_queue = sys_lwcond.GetNewId(new Lwcond(attr->name_u64));
if (lwmutex.IsGood())
{
@ -49,20 +49,20 @@ int sys_lwcond_destroy(mem_ptr_t<sys_lwcond_t> lwcond)
return CELL_EFAULT;
}
u32 lwc = lwcond->lwcond_queue;
u32 id = lwcond->lwcond_queue;
SleepQueue* sq;
if (!Emu.GetIdManager().GetIDData(lwc, sq))
Lwcond* lw;
if (!Emu.GetIdManager().GetIDData(id, lw))
{
return CELL_ESRCH;
}
if (!sq->finalize())
if (!lw->m_queue.finalize())
{
return CELL_EBUSY;
}
Emu.GetIdManager().RemoveID(lwc);
Emu.GetIdManager().RemoveID(id);
return CELL_OK;
}
@ -75,37 +75,23 @@ int sys_lwcond_signal(mem_ptr_t<sys_lwcond_t> lwcond)
return CELL_EFAULT;
}
SleepQueue* sq;
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, sq))
Lwcond* lw;
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw))
{
return CELL_ESRCH;
}
mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex);
be_t<u32> tid = GetCurrentPPUThread().GetId();
bool was_locked = (mutex->mutex.GetOwner() == tid);
if (be_t<u32> target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? sq->pop_prio() : sq->pop()))
if (u32 target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? lw->m_queue.pop_prio() : lw->m_queue.pop()))
{
if (!was_locked)
{
mutex->mutex.lock(tid);
mutex->recursive_count = 1;
mutex->mutex.unlock(tid, target);
}
else
{
mutex->recursive_count = 1;
mutex->mutex.unlock(tid, target);
mutex->mutex.lock(tid);
mutex->recursive_count = 1;
}
}
lw->signal.lock(target);
if (Emu.IsStopped())
{
ConLog.Warning("sys_lwcond_signal(sq=%d) aborted", (u32)lwcond->lwcond_queue);
if (Emu.IsStopped())
{
ConLog.Warning("sys_lwcond_signal(id=%d) aborted", (u32)lwcond->lwcond_queue);
return CELL_OK;
}
}
return CELL_OK;
@ -120,37 +106,23 @@ int sys_lwcond_signal_all(mem_ptr_t<sys_lwcond_t> lwcond)
return CELL_EFAULT;
}
SleepQueue* sq;
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, sq))
Lwcond* lw;
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw))
{
return CELL_ESRCH;
}
mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex);
be_t<u32> tid = GetCurrentPPUThread().GetId();
bool was_locked = (mutex->mutex.GetOwner() == tid);
while (be_t<u32> target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? sq->pop_prio() : sq->pop()))
while (u32 target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? lw->m_queue.pop_prio() : lw->m_queue.pop()))
{
if (!was_locked)
{
mutex->mutex.lock(tid);
mutex->recursive_count = 1;
mutex->mutex.unlock(tid, target);
}
else
{
mutex->recursive_count = 1;
mutex->mutex.unlock(tid, target);
mutex->mutex.lock(tid);
mutex->recursive_count = 1;
}
}
lw->signal.lock(target);
if (Emu.IsStopped())
{
ConLog.Warning("sys_lwcond_signal_all(sq=%d) aborted", (u32)lwcond->lwcond_queue);
if (Emu.IsStopped())
{
ConLog.Warning("sys_lwcond_signal_all(id=%d) aborted", (u32)lwcond->lwcond_queue);
return CELL_OK;
}
}
return CELL_OK;
@ -165,8 +137,8 @@ int sys_lwcond_signal_to(mem_ptr_t<sys_lwcond_t> lwcond, u32 ppu_thread_id)
return CELL_EFAULT;
}
SleepQueue* sq;
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, sq))
Lwcond* lw;
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw))
{
return CELL_ESRCH;
}
@ -176,36 +148,20 @@ int sys_lwcond_signal_to(mem_ptr_t<sys_lwcond_t> lwcond, u32 ppu_thread_id)
return CELL_ESRCH;
}
if (!sq->invalidate(ppu_thread_id))
if (!lw->m_queue.invalidate(ppu_thread_id))
{
return CELL_EPERM;
}
mem_ptr_t<sys_lwmutex_t> mutex(lwcond->lwmutex);
be_t<u32> tid = GetCurrentPPUThread().GetId();
bool was_locked = (mutex->mutex.GetOwner() == tid);
be_t<u32> target = ppu_thread_id;
u32 target = ppu_thread_id;
{
if (!was_locked)
{
mutex->mutex.lock(tid);
mutex->recursive_count = 1;
mutex->mutex.unlock(tid, target);
}
else
{
mutex->recursive_count = 1;
mutex->mutex.unlock(tid, target);
mutex->mutex.lock(tid);
mutex->recursive_count = 1;
}
}
lw->signal.lock(target);
if (Emu.IsStopped())
{
ConLog.Warning("sys_lwcond_signal_to(sq=%d, to=%d) aborted", (u32)lwcond->lwcond_queue, ppu_thread_id);
if (Emu.IsStopped())
{
ConLog.Warning("sys_lwcond_signal_to(id=%d, to=%d) aborted", (u32)lwcond->lwcond_queue, ppu_thread_id);
return CELL_OK;
}
}
return CELL_OK;
@ -220,8 +176,8 @@ int sys_lwcond_wait(mem_ptr_t<sys_lwcond_t> lwcond, u64 timeout)
return CELL_EFAULT;
}
SleepQueue* sq;
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, sq))
Lwcond* lw;
if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw))
{
return CELL_ESRCH;
}
@ -230,29 +186,57 @@ int sys_lwcond_wait(mem_ptr_t<sys_lwcond_t> lwcond, u64 timeout)
u32 tid_le = GetCurrentPPUThread().GetId();
be_t<u32> tid = tid_le;
SleepQueue* sq = nullptr;
Emu.GetIdManager().GetIDData((u32)mutex->sleep_queue, sq);
if (mutex->mutex.GetOwner() != tid)
{
sys_lwcond.Warning("sys_lwcond_wait(id=%d) failed (EPERM)", (u32)lwcond->lwcond_queue);
return CELL_EPERM; // caller must own this lwmutex
}
sq->push(tid_le);
lw->m_queue.push(tid_le);
if (mutex->recursive_count.ToBE() != se32(1))
{
sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex had wrong recursive value (%d)",
(u32)lwcond->lwcond_queue, (u32)mutex->recursive_count);
}
mutex->recursive_count = 0;
mutex->mutex.unlock(tid);
if (sq)
{
mutex->mutex.unlock(tid, mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? sq->pop_prio() : sq->pop());
}
else if (mutex->attribute.ToBE() == se32(SYS_SYNC_RETRY))
{
mutex->mutex.unlock(tid); // SYS_SYNC_RETRY
}
else
{
sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex had invalid sleep queue (%d)",
(u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue);
}
u32 counter = 0;
const u32 max_counter = timeout ? (timeout / 1000) : ~0;
while (true)
{
/* switch (mutex->trylock(tid))
if (lw->signal.unlock(tid, tid) == SMR_OK)
{
case SMR_OK: mutex->unlock(tid); break;
case SMR_SIGNAL: return CELL_OK;
} */
if (mutex->mutex.GetOwner() == tid)
{
_mm_mfence();
switch (mutex->lock(tid, 0))
{
case CELL_OK: break;
case CELL_EDEADLK: sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex was locked",
(u32)lwcond->lwcond_queue); return CELL_OK;
case CELL_ESRCH: sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex not found (%d)",
(u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue); return CELL_ESRCH;
case CELL_EINVAL: goto abort;
}
mutex->recursive_count = 1;
lw->signal.unlock(tid);
return CELL_OK;
}
@ -260,13 +244,16 @@ int sys_lwcond_wait(mem_ptr_t<sys_lwcond_t> lwcond, u64 timeout)
if (counter++ > max_counter)
{
sq->invalidate(tid_le);
lw->m_queue.invalidate(tid_le);
return CELL_ETIMEDOUT;
}
if (Emu.IsStopped())
{
ConLog.Warning("sys_lwcond_wait(sq=%d) aborted", (u32)lwcond->lwcond_queue);
return CELL_OK;
goto abort;
}
}
abort:
ConLog.Warning("sys_lwcond_wait(id=%d) aborted", (u32)lwcond->lwcond_queue);
return CELL_OK;
}

View File

@ -13,4 +13,15 @@ struct sys_lwcond_t
{
be_t<u32> lwmutex;
be_t<u32> lwcond_queue;
};
struct Lwcond
{
SMutex signal;
SleepQueue m_queue;
Lwcond(u64 name)
: m_queue(name)
{
}
};

View File

@ -177,7 +177,7 @@ bool SleepQueue::invalidate(u32 tid)
{
if (list[i] = tid)
{
list[i] = 0;
list.RemoveAt(i);
return true;
}
}
@ -206,10 +206,11 @@ int sys_lwmutex_t::trylock(be_t<u32> tid)
{
if (attribute.ToBE() == se32(0xDEADBEEF)) return CELL_EINVAL;
be_t<u32> owner_tid = mutex.GetOwner();
be_t<u32> owner_tid = mutex.GetFreeValue();
if (owner_tid != mutex.GetFreeValue())
if (mutex.unlock(owner_tid, owner_tid) != SMR_OK) // check free value
{
owner_tid = mutex.GetOwner();
if (CPUThread* tt = Emu.GetCPU().GetThread(owner_tid))
{
if (!tt->IsAlive())
@ -263,7 +264,7 @@ int sys_lwmutex_t::trylock(be_t<u32> tid)
int sys_lwmutex_t::unlock(be_t<u32> tid)
{
if (tid != mutex.GetOwner())
if (mutex.unlock(tid, tid) != SMR_OK)
{
return CELL_EPERM;
}

View File

@ -63,7 +63,7 @@ int sys_mutex_destroy(u32 mutex_id)
return CELL_ESRCH;
}
if ((u32&)mutex->cond_count) // check if associated condition variable exists
if (mutex->cond_count) // check if associated condition variable exists
{
return CELL_EPERM;
}
@ -99,9 +99,7 @@ int sys_mutex_lock(u32 mutex_id, u64 timeout)
PPUThread& t = GetCurrentPPUThread();
u32 tid = t.GetId();
_mm_mfence();
u32 owner = mutex->m_mutex.GetOwner();
if (owner == tid)
if (mutex->m_mutex.unlock(tid, tid) == SMR_OK)
{
if (mutex->is_recursive)
{
@ -116,7 +114,7 @@ int sys_mutex_lock(u32 mutex_id, u64 timeout)
return CELL_EDEADLK;
}
}
else if (owner)
else if (u32 owner = mutex->m_mutex.GetOwner())
{
if (CPUThread* tt = Emu.GetCPU().GetThread(owner))
{
@ -170,9 +168,7 @@ int sys_mutex_trylock(u32 mutex_id)
PPUThread& t = GetCurrentPPUThread();
u32 tid = t.GetId();
_mm_mfence();
u32 owner = mutex->m_mutex.GetOwner();
if (owner == tid)
if (mutex->m_mutex.unlock(tid, tid) == SMR_OK)
{
if (mutex->is_recursive)
{
@ -187,7 +183,7 @@ int sys_mutex_trylock(u32 mutex_id)
return CELL_EDEADLK;
}
}
else if (owner)
else if (u32 owner = mutex->m_mutex.GetOwner())
{
if (CPUThread* tt = Emu.GetCPU().GetThread(owner))
{
@ -219,8 +215,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->m_mutex.unlock(tid, tid) == SMR_OK)
{
if (!mutex->recursive || (mutex->recursive != 1 && !mutex->is_recursive))
{

View File

@ -158,6 +158,9 @@ int sys_ppu_thread_create(u32 thread_id_addr, u32 entry, u64 arg, int prio, u32
new_thread.SetStackSize(stacksize);
//new_thread.flags = flags;
new_thread.SetName(Memory.ReadString(threadname_addr).ToStdString());
ConLog.Write("*** New PPU Thread [%s] (): id = %d", wxString(new_thread.GetName()).wx_str(), new_thread.GetId());
new_thread.Run();
new_thread.Exec();
@ -177,7 +180,7 @@ void sys_ppu_thread_once(u32 once_ctrl_addr, u32 entry)
new_thread.Run();
new_thread.Exec();
GetCurrentPPUThread().Wait(new_thread);
//GetCurrentPPUThread().Wait(new_thread);
}
}

View File

@ -83,9 +83,12 @@ int sys_spu_thread_initialize(mem32_t thread, u32 group, u32 spu_num, mem_ptr_t<
return CELL_EFAULT;
}
if(!Memory.IsGoodAddr(attr->name_addr, attr->name_len))
if (attr->name_addr)
{
return CELL_EFAULT;
if(!Memory.IsGoodAddr(attr->name_addr, attr->name_len))
{
return CELL_EFAULT;
}
}
if(spu_num >= group_info->list.GetCount())
@ -99,7 +102,13 @@ int sys_spu_thread_initialize(mem32_t thread, u32 group, u32 spu_num, mem_ptr_t<
}
u32 spu_ep = (u32)img->entry_point;
std::string name = Memory.ReadString(attr->name_addr, attr->name_len).ToStdString();
std::string name = "SPUThread";
if (attr->name_addr)
{
name = Memory.ReadString(attr->name_addr, attr->name_len).ToStdString();
}
u64 a1 = arg->arg1;
u64 a2 = arg->arg2;
u64 a3 = arg->arg3;
@ -120,9 +129,10 @@ int sys_spu_thread_initialize(mem32_t thread, u32 group, u32 spu_num, mem_ptr_t<
new_thread.Run();
thread = group_info->list[spu_num] = new_thread.GetId();
(*(SPUThread*)&new_thread).group = group_info;
sc_spu.Warning("*** New SPU Thread [%s] (img_offset=0x%x, ls_offset=0x%x, ep=0x%x, a1=0x%llx, a2=0x%llx, a3=0x%llx, a4=0x%llx): id=%d",
wxString(name).wx_str(), (u32)img->segs_addr, ((SPUThread&)new_thread).dmac.ls_offset, spu_ep, a1, a2, a3, a4, thread.GetValue());
wxString(attr->name_addr ? name : "").wx_str(), (u32)img->segs_addr, ((SPUThread&)new_thread).dmac.ls_offset, spu_ep, a1, a2, a3, a4, thread.GetValue());
return CELL_OK;
}
@ -216,6 +226,8 @@ int sys_spu_thread_group_start(u32 id)
return CELL_ESRCH;
}
// TODO: check group state
for (u32 i = 0; i < group_info->list.GetCount(); i++)
{
CPUThread* t;
@ -239,7 +251,8 @@ int sys_spu_thread_group_suspend(u32 id)
return CELL_ESRCH;
}
//Emu.Pause();
// TODO: check group state
for (u32 i = 0; i < group_info->list.GetCount(); i++)
{
if (CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i]))
@ -251,6 +264,30 @@ int sys_spu_thread_group_suspend(u32 id)
return CELL_OK;
}
//175
int sys_spu_thread_group_resume(u32 id)
{
sc_spu.Log("sys_spu_thread_group_resume(id=%d)", id);
SpuGroupInfo* group_info;
if(!Emu.GetIdManager().GetIDData(id, group_info))
{
return CELL_ESRCH;
}
// TODO: check group state
for (u32 i = 0; i < group_info->list.GetCount(); i++)
{
if (CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i]))
{
t->Resume();
}
}
return CELL_OK;
}
//170
int sys_spu_thread_group_create(mem32_t id, u32 num, int prio, mem_ptr_t<sys_spu_thread_group_attribute> attr)
{
@ -500,14 +537,7 @@ int sys_spu_thread_write_snr(u32 id, u32 number, u32 value)
return CELL_EINVAL;
}
if ((*(SPUThread*)thr).cfg.value & ((u64)1<<number))
{ //logical OR
(*(SPUThread*)thr).SPU.SNR[number].PushUncond_OR(value);
}
else
{ //overwrite
(*(SPUThread*)thr).SPU.SNR[number].PushUncond(value);
}
(*(SPUThread*)thr).WriteSNR(number, value);
return CELL_OK;
}

View File

@ -44,8 +44,10 @@ void sys_spinlock_unlock(mem_ptr_t<spinlock> lock)
{
sys_spinlock.Log("sys_spinlock_unlock(lock_addr=0x%x)", lock.GetAddr());
again:
switch (lock->mutex.unlock(lock->mutex.GetOwner()))
{
case SMR_PERMITTED: goto again;
default: break;
}
}

View File

@ -141,7 +141,7 @@ void Emulator::Load()
m_path = elf_path;
}
ConLog.Write("Loading '%s'...", m_path.ToStdString().c_str());
ConLog.Write("Loading '%s'...", m_path.wx_str());
GetInfo().Reset();
m_vfs.Init(m_path);
@ -149,7 +149,7 @@ void Emulator::Load()
ConLog.Write("Mount info:");
for(uint i=0; i<m_vfs.m_devices.GetCount(); ++i)
{
ConLog.Write("%s -> %s", m_vfs.m_devices[i].GetPs3Path().ToStdString().c_str(), m_vfs.m_devices[i].GetLocalPath().ToStdString().c_str());
ConLog.Write("%s -> %s", m_vfs.m_devices[i].GetPs3Path().wx_str(), m_vfs.m_devices[i].GetLocalPath().wx_str());
}
ConLog.SkipLn();
@ -162,7 +162,7 @@ void Emulator::Load()
if(!f.IsOpened())
{
ConLog.Error("Elf not found! (%s - %s)", m_path.ToStdString().c_str(), m_elf_path.ToStdString().c_str());
ConLog.Error("Elf not found! (%s - %s)", m_path.wx_str(), m_elf_path.wx_str());
return;
}
@ -441,7 +441,7 @@ void Emulator::LoadPoints(const std::string& path)
if(version != bpdb_version ||
(sizeof(u16) + break_count * sizeof(u64) + sizeof(u32) + marked_count * sizeof(u64) + sizeof(u32)) != length)
{
ConLog.Error("'%s' is broken", path.c_str());
ConLog.Error("'%s' is broken", wxString(path).wx_str());
return;
}

View File

@ -14,18 +14,18 @@ std::mutex g_cs_conlog;
static const uint max_item_count = 500;
static const uint buffer_size = 1024 * 64;
static const std::string g_log_colors[] =
static const wxString g_log_colors[] =
{
"Black", "Green", "White", "Yellow", "Red",
};
struct LogPacket
{
std::string m_prefix;
std::string m_text;
std::string m_colour;
wxString m_prefix;
wxString m_text;
wxString m_colour;
LogPacket(const std::string& prefix, const std::string& text, const std::string& colour)
LogPacket(const wxString& prefix, const wxString& text, const wxString& colour)
: m_prefix(prefix)
, m_text(text)
, m_colour(colour)
@ -46,9 +46,9 @@ struct _LogBuffer : public MTPacketBuffer<LogPacket>
void _push(const LogPacket& data)
{
const u32 sprefix = data.m_prefix.length();
const u32 stext = data.m_text.length();
const u32 scolour = data.m_colour.length();
const u32 sprefix = data.m_prefix.length() * sizeof(wxChar);
const u32 stext = data.m_text.length() * sizeof(wxChar);
const u32 scolour = data.m_colour.length() * sizeof(wxChar);
m_buffer.Reserve(
sizeof(u32) + sprefix +
@ -59,17 +59,17 @@ struct _LogBuffer : public MTPacketBuffer<LogPacket>
memcpy(&m_buffer[c_put], &sprefix, sizeof(u32));
c_put += sizeof(u32);
memcpy(&m_buffer[c_put], data.m_prefix.c_str(), sprefix);
memcpy(&m_buffer[c_put], data.m_prefix.wx_str(), sprefix);
c_put += sprefix;
memcpy(&m_buffer[c_put], &stext, sizeof(u32));
c_put += sizeof(u32);
memcpy(&m_buffer[c_put], data.m_text.c_str(), stext);
memcpy(&m_buffer[c_put], data.m_text.wx_str(), stext);
c_put += stext;
memcpy(&m_buffer[c_put], &scolour, sizeof(u32));
c_put += sizeof(u32);
memcpy(&m_buffer[c_put], data.m_colour.c_str(), scolour);
memcpy(&m_buffer[c_put], data.m_colour.wx_str(), scolour);
c_put += scolour;
m_put = c_put;
@ -84,20 +84,17 @@ struct _LogBuffer : public MTPacketBuffer<LogPacket>
const u32& sprefix = *(u32*)&m_buffer[c_get];
c_get += sizeof(u32);
ret.m_prefix.resize(sprefix);
if(sprefix) memcpy((void*)ret.m_prefix.c_str(), &m_buffer[c_get], sprefix);
ret.m_prefix = wxString((wxChar*)&m_buffer[c_get], sprefix / sizeof(wxChar));
c_get += sprefix;
const u32& stext = *(u32*)&m_buffer[c_get];
c_get += sizeof(u32);
ret.m_text.resize(stext);
if(stext) memcpy((void*)ret.m_text.c_str(), &m_buffer[c_get], stext);
ret.m_text = wxString((wxChar*)&m_buffer[c_get], stext / sizeof(wxChar));
c_get += stext;
const u32& scolour = *(u32*)&m_buffer[c_get];
c_get += sizeof(u32);
ret.m_colour.resize(scolour);
if(scolour) memcpy((void*)ret.m_colour.c_str(), &m_buffer[c_get], scolour);
ret.m_colour = wxString((wxChar*)&m_buffer[c_get], scolour / sizeof(wxChar));
c_get += scolour;
m_get = c_get;
@ -117,7 +114,7 @@ LogWriter::LogWriter()
}
}
void LogWriter::WriteToLog(std::string prefix, std::string value, u8 lvl/*, wxColour bgcolour*/)
void LogWriter::WriteToLog(wxString prefix, wxString value, u8 lvl/*, wxColour bgcolour*/)
{
if(!prefix.empty())
{
@ -127,8 +124,8 @@ void LogWriter::WriteToLog(std::string prefix, std::string value, u8 lvl/*, wxCo
}
}
if(m_logfile.IsOpened())
m_logfile.Write(wxString(prefix.empty() ? "" : std::string("[" + prefix + "]: ") + value + "\n").wx_str());
if(m_logfile.IsOpened() && !prefix.empty())
m_logfile.Write(wxString("[") + prefix + "]: " + value + "\n");
if(!ConLogFrame || Ini.HLELogLvl.GetValue() == 4 || (lvl != 0 && lvl <= Ini.HLELogLvl.GetValue()))
return;
@ -175,7 +172,7 @@ void LogWriter::Write(const wxString fmt, ...)
va_end(list);
WriteToLog("!", (const char *)frmt.ToAscii(), 2);
WriteToLog("!", frmt, 2);
}
void LogWriter::Error(const wxString fmt, ...)
@ -188,7 +185,7 @@ void LogWriter::Error(const wxString fmt, ...)
va_end(list);
WriteToLog("E", static_cast<const char *>(frmt), 4);
WriteToLog("E", frmt, 4);
}
void LogWriter::Warning(const wxString fmt, ...)
@ -201,7 +198,7 @@ void LogWriter::Warning(const wxString fmt, ...)
va_end(list);
WriteToLog("W", static_cast<const char *>(frmt), 3);
WriteToLog("W", frmt, 3);
}
void LogWriter::Success(const wxString fmt, ...)
@ -214,7 +211,7 @@ void LogWriter::Success(const wxString fmt, ...)
va_end(list);
WriteToLog("S", static_cast<const char *>(frmt), 1);
WriteToLog("S", frmt, 1);
}
void LogWriter::SkipLn()
@ -279,9 +276,9 @@ void LogFrame::Task()
const int cur_item = m_log.GetItemCount();
m_log.InsertItem(cur_item, wxString(item.m_prefix).wx_str());
m_log.SetItem(cur_item, 1, wxString(item.m_text).wx_str());
m_log.SetItemTextColour(cur_item, wxString(item.m_colour).wx_str());
m_log.InsertItem(cur_item, item.m_prefix);
m_log.SetItem(cur_item, 1, item.m_text);
m_log.SetItemTextColour(cur_item, item.m_colour);
m_log.SetColumnWidth(0, -1); // crashes on exit
m_log.SetColumnWidth(1, -1);

View File

@ -8,10 +8,10 @@ class LogWriter
wxFile m_logfile;
wxColour m_txtcolour;
std::string m_prefix;
std::string m_value;
//wxString m_prefix;
//wxString m_value;
virtual void WriteToLog(std::string prefix, std::string value, u8 lvl);
virtual void WriteToLog(wxString prefix, wxString value, u8 lvl);
public:
LogWriter();

View File

@ -202,7 +202,7 @@ void MainFrame::BootGame(wxCommandEvent& WXUNUSED(event))
}
else
{
ConLog.Error("Ps3 executable not found in selected folder (%s)", ctrl.GetPath().ToStdString().c_str());
ConLog.Error("Ps3 executable not found in selected folder (%s)", ctrl.GetPath().wx_str());
}
}

View File

@ -286,6 +286,7 @@
<ClCompile Include="Emu\SysCalls\lv2\SC_VM.cpp" />
<ClCompile Include="Emu\SysCalls\Modules.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\cellAdec.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\cellAtrac.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\cellAudio.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\cellDmux.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\cellFont.cpp" />

View File

@ -475,6 +475,9 @@
<ClCompile Include="Emu\SysCalls\Modules\cellSaveData.cpp">
<Filter>Emu\SysCalls\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\SysCalls\Modules\cellAtrac.cpp">
<Filter>Emu\SysCalls\Modules</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="rpcs3.rc" />

View File

@ -34,6 +34,11 @@
#include <wx/wxprec.h>
#endif
#ifndef _WIN32
//hack, disabled
//#define wx_str() ToStdString().c_str()
#endif
#include <cstdint>
typedef unsigned int uint;
@ -68,6 +73,12 @@ union u128
operator bool() const { return _u64[0] != 0 || _u64[1] != 0; }
static u128 From128( u64 hi, u64 lo )
{
u128 ret = {hi, lo};
return ret;
}
static u128 From64( u64 src )
{
u128 ret = {0, src};
@ -84,6 +95,27 @@ union u128
return ret;
}
static u128 FromBit ( u32 bit )
{
u128 ret;
if (bit < 64)
{
ret.hi = 0;
ret.lo = (u64)1 << bit;
}
else if (bit < 128)
{
ret.hi = (u64)1 << (bit - 64);
ret.lo = 0;
}
else
{
ret.hi = 0;
ret.lo = 0;
}
return ret;
}
bool operator == ( const u128& right ) const
{
return (lo == right.lo) && (hi == right.hi);
@ -93,6 +125,26 @@ union u128
{
return (lo != right.lo) || (hi != right.hi);
}
u128 operator | ( const u128& right ) const
{
return From128(hi | right.hi, lo | right.lo);
}
u128 operator & ( const u128& right ) const
{
return From128(hi & right.hi, lo & right.lo);
}
u128 operator ^ ( const u128& right ) const
{
return From128(hi ^ right.hi, lo ^ right.lo);
}
u128 operator ~ () const
{
return From128(~hi, ~lo);
}
};
union s128