Small update

This commit is contained in:
Nekotekina 2014-10-02 14:29:20 +04:00
parent 4a6779469c
commit 752449bbc0
10 changed files with 173 additions and 76 deletions

View File

@ -104,6 +104,16 @@ union u128
return ret;
}
static u128 from32r(u32 _3, u32 _2 = 0, u32 _1 = 0, u32 _0 = 0)
{
u128 ret;
ret._u32[0] = _0;
ret._u32[1] = _1;
ret._u32[2] = _2;
ret._u32[3] = _3;
return ret;
}
static u128 fromBit(u32 bit)
{
u128 ret = {};

View File

@ -61,5 +61,4 @@ enum
struct DMAC
{
u32 ls_offset;
};

View File

@ -190,7 +190,7 @@ bool RawSPUThread::Write32(const u64 addr, const u32 value)
void RawSPUThread::InitRegs()
{
dmac.ls_offset = m_offset = (u32)GetStartAddr() + RAW_SPU_LS_OFFSET;
ls_offset = m_offset = (u32)GetStartAddr() + RAW_SPU_LS_OFFSET;
SPUThread::InitRegs();
}

View File

@ -3,7 +3,7 @@
#define UNIMPLEMENTED() UNK(__FUNCTION__)
#define MEM_AND_REG_HASH() \
unsigned char mem_h[20]; sha1(vm::get_ptr<u8>(CPU.dmac.ls_offset), 256*1024, mem_h); \
unsigned char mem_h[20]; sha1(vm::get_ptr<u8>(CPU.ls_offset), 256*1024, mem_h); \
unsigned char reg_h[20]; sha1((const unsigned char*)CPU.GPR, sizeof(CPU.GPR), reg_h); \
LOG_NOTICE(Log::SPU, "Mem hash: 0x%llx, reg hash: 0x%llx", *(u64*)mem_h, *(u64*)reg_h);

View File

@ -49,7 +49,7 @@ void SPURecompilerCore::Compile(u16 pos)
u64 time0 = 0;
SPUDisAsm dis_asm(CPUDisAsm_InterpreterMode);
dis_asm.offset = vm::get_ptr<u8>(CPU.dmac.ls_offset);
dis_asm.offset = vm::get_ptr<u8>(CPU.ls_offset);
StringLogger stringLogger;
stringLogger.setOption(kLoggerOptionBinaryForm, true);
@ -103,7 +103,7 @@ void SPURecompilerCore::Compile(u16 pos)
while (true)
{
const u32 opcode = vm::read32(CPU.dmac.ls_offset + pos * 4);
const u32 opcode = vm::read32(CPU.ls_offset + pos * 4);
m_enc->do_finalize = false;
if (opcode)
{
@ -182,8 +182,8 @@ void SPURecompilerCore::Compile(u16 pos)
u8 SPURecompilerCore::DecodeMemory(const u32 address)
{
assert(CPU.dmac.ls_offset == address - CPU.PC);
const u32 m_offset = CPU.dmac.ls_offset;
assert(CPU.ls_offset == address - CPU.PC);
const u32 m_offset = CPU.ls_offset;
const u16 pos = (u16)(CPU.PC >> 2);
//ConLog.Write("DecodeMemory: pos=%d", pos);

View File

@ -80,7 +80,7 @@ void SPUThread::InitRegs()
cfg.Reset();
dmac.ls_offset = m_offset;
ls_offset = m_offset;
SPU.Status.SetValue(SPU_STATUS_STOPPED);
@ -148,19 +148,27 @@ void SPUThread::DoClose()
void SPUThread::FastCall(u32 ls_addr)
{
// doesn't touch thread status (instead of PPUThread::FastCall2);
// can't be called from another thread (because it doesn't make sense);
// FastStop-like routine is not defined (TODO);
// can't be called from another thread (because it doesn't make sense)
WriteLS32(0x0, 2);
auto old_PC = PC;
auto old_stack = GPR[1]; // only saved and restored (may be wrong)
auto old_LR = GPR[0]._u32[3];
auto old_stack = GPR[1]._u32[3]; // only saved and restored (may be wrong)
m_status = Running;
PC = ls_addr;
GPR[0]._u32[3] = 0x0;
CPUThread::Task();
PC = old_PC;
GPR[1] = old_stack;
GPR[0]._u32[3] = old_LR;
GPR[1]._u32[3] = old_stack;
}
void SPUThread::FastStop()
{
m_status = Stopped;
}
void SPUThread::WriteSNR(bool number, u32 value)
@ -206,11 +214,11 @@ void SPUThread::ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size)
if ((addr <= 0x3ffff) && (addr + size <= 0x40000))
{
// LS access
ea = spu->dmac.ls_offset + addr;
ea = spu->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, vm::read32(dmac.ls_offset + lsa));
spu->WriteSNR(SYS_SPU_THREAD_SNR2 == addr, vm::read32(ls_offset + lsa));
return;
}
else
@ -256,13 +264,13 @@ void SPUThread::ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size)
{
case MFC_PUT_CMD:
{
memcpy(vm::get_ptr<void>(ea), vm::get_ptr<void>(dmac.ls_offset + lsa), size);
memcpy(vm::get_ptr<void>(ea), vm::get_ptr<void>(ls_offset + lsa), size);
return;
}
case MFC_GET_CMD:
{
memcpy(vm::get_ptr<void>(dmac.ls_offset + lsa), vm::get_ptr<void>(ea), size);
memcpy(vm::get_ptr<void>(ls_offset + lsa), vm::get_ptr<void>(ea), size);
return;
}
@ -294,7 +302,7 @@ void SPUThread::ListCmd(u32 lsa, u64 ea, u16 tag, u16 size, u32 cmd, MFCReg& MFC
for (u32 i = 0; i < list_size; i++)
{
auto rec = vm::ptr<list_element>::make(dmac.ls_offset + list_addr + i * 8);
auto rec = vm::ptr<list_element>::make(ls_offset + list_addr + i * 8);
u32 size = rec->ts;
if (!(rec->s.ToBE() & se16(0x8000)) && size < 16 && size != 1 && size != 2 && size != 4 && size != 8)
@ -405,7 +413,7 @@ void SPUThread::EnqMfcCmd(MFCReg& MFCArgs)
for (u32 i = 0; i < 16; i++)
{
R_DATA[i] = vm::get_ptr<u64>(R_ADDR)[i];
vm::get_ptr<u64>(dmac.ls_offset + lsa)[i] = R_DATA[i];
vm::get_ptr<u64>(ls_offset + lsa)[i] = R_DATA[i];
}
MFCArgs.AtomicStat.PushUncond(MFC_GETLLAR_SUCCESS);
}
@ -419,7 +427,7 @@ void SPUThread::EnqMfcCmd(MFCReg& MFCArgs)
u64 buf[16];
for (u32 i = 0; i < 16; i++)
{
buf[i] = vm::get_ptr<u64>(dmac.ls_offset + lsa)[i];
buf[i] = vm::get_ptr<u64>(ls_offset + lsa)[i];
if (buf[i] != R_DATA[i])
{
changed++;
@ -464,8 +472,8 @@ void SPUThread::EnqMfcCmd(MFCReg& MFCArgs)
for (s32 i = (s32)PC; i < (s32)PC + 4 * 7; i += 4)
{
dis_asm.dump_pc = i;
dis_asm.offset = vm::get_ptr<u8>(dmac.ls_offset);
const u32 opcode = vm::read32(i + dmac.ls_offset);
dis_asm.offset = vm::get_ptr<u8>(ls_offset);
const u32 opcode = vm::read32(i + ls_offset);
(*SPU_instr::rrr_list)(&dis_asm, opcode);
if (i >= 0 && i < 0x40000)
{
@ -526,18 +534,20 @@ bool SPUThread::CheckEvents()
u32 SPUThread::GetChannelCount(u32 ch)
{
u32 res = 0xdeafbeef;
switch (ch)
{
case SPU_WrOutMbox: return SPU.Out_MBox.GetFreeCount();
case SPU_WrOutIntrMbox: return SPU.Out_IntrMBox.GetFreeCount();
case SPU_RdInMbox: return SPU.In_MBox.GetCount();
case MFC_RdTagStat: return MFC1.TagStatus.GetCount();
case MFC_RdListStallStat: return StallStat.GetCount();
case MFC_WrTagUpdate: return MFC1.TagStatus.GetCount(); // hack
case SPU_RdSigNotify1: return SPU.SNR[0].GetCount();
case SPU_RdSigNotify2: return SPU.SNR[1].GetCount();
case MFC_RdAtomicStat: return MFC1.AtomicStat.GetCount();
case SPU_RdEventStat: return CheckEvents() ? 1 : 0;
case SPU_WrOutMbox: res = SPU.Out_MBox.GetFreeCount(); break;
case SPU_WrOutIntrMbox: res = SPU.Out_IntrMBox.GetFreeCount(); break;
case SPU_RdInMbox: res = SPU.In_MBox.GetCount(); break;
case MFC_RdTagStat: res = MFC1.TagStatus.GetCount(); break;
case MFC_RdListStallStat: res = StallStat.GetCount(); break;
case MFC_WrTagUpdate: res = MFC1.TagStatus.GetCount(); break;// hack
case SPU_RdSigNotify1: res = SPU.SNR[0].GetCount(); break;
case SPU_RdSigNotify2: res = SPU.SNR[1].GetCount(); break;
case MFC_RdAtomicStat: res = MFC1.AtomicStat.GetCount(); break;
case SPU_RdEventStat: res = CheckEvents() ? 1 : 0; break;
default:
{
@ -546,12 +556,17 @@ u32 SPUThread::GetChannelCount(u32 ch)
return 0;
}
}
//LOG_NOTICE(Log::SPU, "%s(%s) -> 0x%x", __FUNCTION__, spu_ch_name[ch], res);
return res;
}
void SPUThread::WriteChannel(u32 ch, const u128& r)
{
const u32 v = r._u32[3];
//LOG_NOTICE(Log::SPU, "%s(%s): v=0x%x", __FUNCTION__, spu_ch_name[ch], v);
switch (ch)
{
case SPU_WrOutIntrMbox:
@ -908,13 +923,27 @@ void SPUThread::ReadChannel(u128& r, u32 ch)
case SPU_RdSigNotify1:
{
while (!SPU.SNR[0].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
if (cfg.value & 1)
{
while (!SPU.SNR[0].Pop_XCHG(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
else
{
while (!SPU.SNR[0].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
break;
}
case SPU_RdSigNotify2:
{
while (!SPU.SNR[1].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
if (cfg.value & 2)
{
while (!SPU.SNR[1].Pop_XCHG(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
else
{
while (!SPU.SNR[1].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
break;
}
@ -964,6 +993,8 @@ void SPUThread::ReadChannel(u128& r, u32 ch)
}
if (Emu.IsStopped()) LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]);
//LOG_NOTICE(Log::SPU, "%s(%s) -> 0x%x", __FUNCTION__, spu_ch_name[ch], v);
}
void SPUThread::StopAndSignal(u32 code)
@ -973,6 +1004,18 @@ void SPUThread::StopAndSignal(u32 code)
switch (code)
{
case 0x001:
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
break;
}
case 0x002:
{
FastStop();
break;
}
case 0x110:
{
/* ===== sys_spu_thread_receive_event ===== */

View File

@ -420,7 +420,7 @@ public:
struct { u32 EAH, EAL; };
};
DMAC dmac;
u32 ls_offset;
void ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size);
@ -510,6 +510,7 @@ public:
virtual void InitRegs();
virtual void Task();
void FastCall(u32 ls_addr);
void FastStop();
protected:
virtual void DoReset();

View File

@ -102,14 +102,16 @@ s64 spursInit(
{
spurs->m.xC0[i] = -1;
}
// default or system workload:
#ifdef PRX_DEBUG
spurs->m.unk7 = vm::read32(libsre_rtoc - 0x7EA4); // write 64-bit pointer to unknown data
spurs->m.wklSysG.pm.set(be_t<u64>::make(vm::read32(libsre_rtoc - 0x7EA4)));
#else
spurs->m.unk7 = 0x7ull << 48 | 0x7; // wrong 64-bit address
spurs->m.wklSysG.pm.set(be_t<u64>::make(0x100)); // wrong 64-bit address
#endif
spurs->m.unk8 = 0ull;
spurs->m.unk9 = 0x2200;
spurs->m.unk10 = -1;
spurs->m.wklSysG.data = 0;
spurs->m.wklSysG.size = 0x2200;
spurs->m.wklSysG.copy.write_relaxed(0xff);
u32 sem;
for (u32 i = 0; i < 0x10; i++)
{
@ -161,13 +163,58 @@ s64 spursInit(
name += "CellSpursKernel0";
for (s32 num = 0; num < nSpus; num++, name[name.size() - 1]++)
{
spurs->m.spus[num] = spu_thread_initialize(tg, num, spurs->m.spuImg, name, SYS_SPU_THREAD_OPTION_DEC_SYNC_TB_ENABLE, 0, 0, 0, 0, [spurs, num, isSecond](SPUThread& CPU)
spurs->m.spus[num] = spu_thread_initialize(tg, num, spurs->m.spuImg, name, SYS_SPU_THREAD_OPTION_DEC_SYNC_TB_ENABLE, 0, 0, 0, 0, [spurs, num, isSecond](SPUThread& SPU)
{
#ifdef PRX_DEBUG
CPU.GPR[3]._u32[3] = num;
CPU.GPR[4]._u64[1] = spurs.addr();
return CPU.FastCall(CPU.PC);
#ifdef PRX_DEBUG_XXX
SPU.GPR[3]._u32[3] = num;
SPU.GPR[4]._u64[1] = spurs.addr();
return SPU.FastCall(SPU.PC);
#endif
SPU.WriteLS128(0x1c0, u128::from32r(0, spurs.addr(), num, 0x1f));
u32 wid = 0x20;
while (true)
{
if (Emu.IsStopped())
{
cellSpurs->Warning("Spurs Kernel aborted");
return;
}
// get current workload info:
auto& wkl = wid <= 15 ? spurs->m.wklG1[wid] : (wid <= 31 && isSecond ? spurs->m.wklG2[wid & 0xf] : spurs->m.wklSysG);
if (SPU.ReadLS64(0x1d0) != wkl.pm.addr())
{
// load executable code:
memcpy(vm::get_ptr<void>(SPU.ls_offset + 0xa00), wkl.pm.get_ptr(), wkl.size);
SPU.WriteLS64(0x1d0, wkl.pm.addr());
SPU.WriteLS32(0x1d8, wkl.priority.ToLE() >> 24 & 0xff); // ???
}
if (!isSecond) SPU.WriteLS16(0x1e8, 0);
// run workload:
SPU.GPR[1]._u32[3] = 0x3FFB0;
SPU.GPR[3]._u32[3] = 0x100;
SPU.GPR[4]._u64[1] = wkl.data;
SPU.GPR[5]._u32[3] = 0;
SPU.FastCall(0xa00);
// check status:
auto status = SPU.SPU.Status.GetValue();
if (status == SPU_STATUS_STOPPED_BY_STOP)
{
return;
}
else
{
assert(status == SPU_STATUS_RUNNING);
}
// get workload id:
}
})->GetId();
}
@ -240,7 +287,7 @@ s64 spursInit(
for (u32 i = 0; i < 16; i++)
{
if (spurs->m.wklStat1[i].read_relaxed() == 2 &&
spurs->m.wklG1[i].wklPriority.ToBE() != 0 &&
spurs->m.wklG1[i].priority.ToBE() != 0 &&
spurs->m.wklMaxCnt[i].read_relaxed() & 0xf
)
{
@ -258,7 +305,7 @@ s64 spursInit(
if (spurs->m.flags1 & SF1_IS_SECOND) for (u32 i = 0; i < 16; i++)
{
if (spurs->m.wklStat2[i].read_relaxed() == 2 &&
spurs->m.wklG2[i].wklPriority.ToBE() != 0 &&
spurs->m.wklG2[i].priority.ToBE() != 0 &&
spurs->m.wklMaxCnt[i].read_relaxed() & 0xf0
)
{
@ -951,10 +998,10 @@ s32 spursAddWorkload(
spurs->m.wklStat1[wnum].write_relaxed(1);
spurs->m.wklD1[wnum] = 0;
spurs->m.wklE1[wnum] = 0;
spurs->m.wklG1[wnum].wklPm = pm;
spurs->m.wklG1[wnum].wklArg = data;
spurs->m.wklG1[wnum].wklSize = size;
spurs->m.wklG1[wnum].wklPriority = *(be_t<u64>*)priorityTable;
spurs->m.wklG1[wnum].pm = pm;
spurs->m.wklG1[wnum].data = data;
spurs->m.wklG1[wnum].size = size;
spurs->m.wklG1[wnum].priority = *(be_t<u64>*)priorityTable;
spurs->m.wklH1[wnum].nameClass = nameClass;
spurs->m.wklH1[wnum].nameInstance = nameInstance;
memset(spurs->m.wklF1[wnum].unk0, 0, 0x20); // clear struct preserving semaphore id
@ -978,10 +1025,10 @@ s32 spursAddWorkload(
spurs->m.wklStat2[index].write_relaxed(1);
spurs->m.wklD2[index] = 0;
spurs->m.wklE2[index] = 0;
spurs->m.wklG2[index].wklPm = pm;
spurs->m.wklG2[index].wklArg = data;
spurs->m.wklG2[index].wklSize = size;
spurs->m.wklG2[index].wklPriority = *(be_t<u64>*)priorityTable;
spurs->m.wklG2[index].pm = pm;
spurs->m.wklG2[index].data = data;
spurs->m.wklG2[index].size = size;
spurs->m.wklG2[index].priority = *(be_t<u64>*)priorityTable;
spurs->m.wklH2[index].nameClass = nameClass;
spurs->m.wklH2[index].nameInstance = nameInstance;
memset(spurs->m.wklF2[index].unk0, 0, 0x20); // clear struct preserving semaphore id
@ -1034,21 +1081,21 @@ s32 spursAddWorkload(
if (mask & m)
{
CellSpurs::_sub_str3& current = i <= 15 ? spurs->m.wklG1[i] : spurs->m.wklG2[i & 0xf];
if (current.wklPm.addr() == wkl.wklPm.addr())
if (current.pm.addr() == wkl.pm.addr())
{
// if a workload with identical policy module found
res_wkl = current.wklCopy.read_relaxed();
res_wkl = current.copy.read_relaxed();
break;
}
else
{
k |= 0x80000000 >> current.wklCopy.read_relaxed();
k |= 0x80000000 >> current.copy.read_relaxed();
res_wkl = cntlz32(~k);
}
}
}
wkl.wklCopy.exchange((u8)res_wkl);
wkl.copy.exchange((u8)res_wkl);
v = mask | (0x80000000u >> wnum);
});
assert(res_wkl <= 31);

View File

@ -221,8 +221,6 @@ struct CellSpurs
struct _sub_str1
{
static const uint size = 0x80;
u8 unk0[0x20];
be_t<u64> sem; // 0x20
u8 unk1[0x8];
@ -231,10 +229,10 @@ struct CellSpurs
u8 unk2[0x40];
};
static_assert(sizeof(_sub_str1) == 0x80, "Wrong _sub_str1 size");
struct _sub_str2
{
static const uint size = 0x80;
be_t<u32> unk0;
be_t<u32> unk1;
be_t<u32> unk2;
@ -243,17 +241,19 @@ struct CellSpurs
u8 unk_[0x68];
};
static_assert(sizeof(_sub_str2) == 0x80, "Wrong _sub_str2 size");
struct _sub_str3
{
static const uint size = 0x20;
vm::bptr<const void, 1, u64> wklPm; // policy module
be_t<u64> wklArg; // spu argument
be_t<u32> wklSize;
atomic_t<u8> wklCopy;
be_t<u64> wklPriority;
vm::bptr<const void, 1, u64> pm; // policy module
be_t<u64> data; // spu argument
be_t<u32> size;
atomic_t<u8> copy;
be_t<u64> priority;
};
static_assert(sizeof(_sub_str3) == 0x20, "Wrong _sub_str3 size");
struct _sub_str4
{
static const uint size = 0x10;
@ -315,11 +315,7 @@ struct CellSpurs
be_t<u64> unk13; // 0x990
u8 unknown4[0xB00 - 0x998];
_sub_str3 wklG1[0x10]; // 0xB00
be_t<u64> unk7; // 0xD00
be_t<u64> unk8; // 0xD08
be_t<u32> unk9; // 0xD10
u8 unk10; // 0xD14
u8 unknown5[0xD20 - 0xD15];
_sub_str3 wklSysG; // 0xD00
be_t<u64> ppu0; // 0xD20
be_t<u64> ppu1; // 0xD28
be_t<u32> spuTG; // 0xD30

View File

@ -236,6 +236,7 @@ s32 sys_spu_thread_group_start(u32 id)
CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i]);
if (t)
{
((SPUThread*)t)->SPU.Status.SetValue(SPU_STATUS_RUNNING);
t->Exec();
}
}
@ -471,7 +472,7 @@ s32 sys_spu_thread_group_join(u32 id, vm::ptr<be_t<u32>> cause, vm::ptr<be_t<u32
{
while (CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i]))
{
if (!t->IsRunning())
if (!t->IsAlive())
{
if (((SPUThread*)t)->SPU.Status.GetValue() != SPU_STATUS_STOPPED_BY_STOP)
{