SPU Thread Group-specific MMIO

LS access, SNR writing
This commit is contained in:
Nekotekina 2014-03-16 00:46:53 +04:00
parent 0a35c4f2c4
commit c9a421f12f
5 changed files with 119 additions and 36 deletions

View File

@ -55,7 +55,7 @@ enum
MFC_SPU_MAX_QUEUE_SPACE = 0x10,
};
struct DMAC_Queue
/*struct DMAC_Queue
{
bool is_valid;
u64 ea;
@ -149,13 +149,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 +195,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 +219,10 @@ struct DMAC
ClearCmd();
}
}
}
}*/
};
struct MFC
/*struct MFC
{
SPUReg<1> MFC_LSA;
SPUReg<1> MFC_EAH;
@ -299,4 +288,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

@ -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,82 @@ 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_BARRIER_MASK | MFC_FENCE_MASK | MFC_LIST_MASK)) == 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))
{
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 +647,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;
@ -606,7 +704,7 @@ public:
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,7 +713,7 @@ public:
}
else
{
MFCArgs.CMDStatus.SetValue(dmac.Cmd(cmd, tag, lsa, ea, size));
MFCArgs.CMDStatus.SetValue(dmacCmd(cmd, tag, lsa, ea, size));
}
}
break;
@ -650,7 +748,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 +758,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 +775,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);

View File

@ -120,6 +120,7 @@ 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());
@ -500,14 +501,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;
}