Small SPU cleanup

This commit is contained in:
Nekotekina 2014-07-21 22:35:44 +04:00
parent e3fbfc4bda
commit fa5311718e
3 changed files with 30 additions and 296 deletions

View File

@ -12,7 +12,7 @@ struct reservation_struct
// std::mutex doesn't work because it probably wakes up waiting threads in the most unwanted order // std::mutex doesn't work because it probably wakes up waiting threads in the most unwanted order
// and doesn't give a chance to finish some work before losing the reservation // and doesn't give a chance to finish some work before losing the reservation
u32 owner; // id of thread that got reservation u32 owner; // id of thread that got reservation
u32 addr; u64 addr;
u32 size; u32 size;
u32 data32; u32 data32;
u64 data64; u64 data64;

View File

@ -60,237 +60,7 @@ enum
MFC_SPU_MAX_QUEUE_SPACE = 0x10, MFC_SPU_MAX_QUEUE_SPACE = 0x10,
}; };
/*struct DMAC_Queue
{
bool is_valid;
u64 ea;
u32 lsa;
u16 size;
u32 op;
u8 tag;
u8 rt;
u16 list_addr;
u16 list_size;
u32 dep_state;
u32 cmd;
u32 dep_type;
};
struct DMAC_Proxy
{
u64 ea;
u32 lsa;
u16 size;
u32 op;
u8 tag;
u8 rt;
u16 list_addr;
u16 list_size;
u32 dep_state;
u32 cmd;
u32 dep_type;
};
template<size_t _max_count>
class SPUReg
{
u64 m_addr;
u32 m_pos;
public:
static const size_t max_count = _max_count;
static const size_t size = max_count * 4;
SPUReg()
{
Init();
}
void Init()
{
m_pos = 0;
}
void SetAddr(u64 addr)
{
m_addr = addr;
}
u64 GetAddr() const
{
return m_addr;
}
__forceinline bool Pop(u32& res)
{
if(!m_pos) return false;
res = Memory.Read32(m_addr + m_pos--);
return true;
}
__forceinline bool Push(u32 value)
{
if(m_pos >= max_count) return false;
Memory.Write32(m_addr + m_pos++, value);
return true;
}
u32 GetCount() const
{
return m_pos;
}
u32 GetFreeCount() const
{
return max_count - m_pos;
}
void SetValue(u32 value)
{
Memory.Write32(m_addr, value);
}
u32 GetValue() const
{
return Memory.Read32(m_addr);
}
};*/
struct DMAC struct DMAC
{ {
u64 ls_offset; 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;
volatile std::atomic<int> proxy_lock;
bool ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size)
{
//returns true if the command should be deleted from the queue
if (cmd & (MFC_BARRIER_MASK | MFC_FENCE_MASK)) _mm_mfence();
switch(cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_LIST_MASK))
{
case MFC_PUT_CMD:
Memory.Copy(ea, ls_offset + lsa, size);
return true;
case MFC_GET_CMD:
Memory.Copy(ls_offset + lsa, ea, size);
return true;
default:
LOG_ERROR(HLE, "DMAC::ProcessCmd(): Unknown DMA cmd.");
return true;
}
}
u32 Cmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size)
{
if(!Memory.IsGoodAddr(ls_offset + lsa, size) || !Memory.IsGoodAddr(ea, size))
{
return MFC_PPU_DMA_CMD_SEQUENCE_ERROR;
}
if(proxy_pos >= MFC_PPU_MAX_QUEUE_SPACE)
{
return MFC_PPU_DMA_QUEUE_FULL;
}
ProcessCmd(cmd, tag, lsa, ea, size);
return MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL;
}
void ClearCmd()
{
while (std::atomic_exchange(&proxy_lock, 1));
_mm_lfence();
memcpy(proxy, proxy + 1, --proxy_pos * sizeof(DMAC_Proxy));
_mm_sfence();
proxy_lock = 0; //release lock
}
void DoCmd()
{
if(proxy_pos)
{
const DMAC_Proxy& p = proxy[0];
if (ProcessCmd(p.cmd, p.tag, p.lsa, p.ea, p.size))
{
ClearCmd();
}
}
}*/
}; };
/*struct MFC
{
SPUReg<1> MFC_LSA;
SPUReg<1> MFC_EAH;
SPUReg<1> MFC_EAL;
SPUReg<1> MFC_Size_Tag;
SPUReg<1> MFC_CMDStatus;
SPUReg<1> MFC_QStatus;
SPUReg<1> Prxy_QueryType;
SPUReg<1> Prxy_QueryMask;
SPUReg<1> Prxy_TagStatus;
SPUReg<1> SPU_Out_MBox;
SPUReg<4> SPU_In_MBox;
SPUReg<1> SPU_MBox_Status;
SPUReg<1> SPU_RunCntl;
SPUReg<1> SPU_Status;
SPUReg<1> SPU_NPC;
SPUReg<1> SPU_RdSigNotify1;
SPUReg<1> SPU_RdSigNotify2;
DMAC dmac;
void Handle()
{
u32 cmd = MFC_CMDStatus.GetValue();
if(cmd)
{
u16 op = cmd & MFC_MASK_CMD;
switch(op)
{
case MFC_PUT_CMD:
case MFC_GET_CMD:
{
u32 lsa = MFC_LSA.GetValue();
u64 ea = (u64)MFC_EAL.GetValue() | ((u64)MFC_EAH.GetValue() << 32);
u32 size_tag = MFC_Size_Tag.GetValue();
u16 tag = (u16)size_tag;
u16 size = size_tag >> 16;
LOG_WARNING(HLE, "RawSPU DMA %s:", op == MFC_PUT_CMD ? "PUT" : "GET");
LOG_WARNING(HLE, "*** lsa = 0x%x", lsa);
LOG_WARNING(HLE, "*** ea = 0x%llx", ea);
LOG_WARNING(HLE, "*** tag = 0x%x", tag);
LOG_WARNING(HLE, "*** size = 0x%x", size);
LOG_WARNING(HLE, " ");
MFC_CMDStatus.SetValue(dmac.Cmd(cmd, tag, lsa, ea, size));
}
break;
default:
LOG_ERROR(HLE, "Unknown MFC cmd. (opcode=0x%x, cmd=0x%x)", op, cmd);
break;
}
}
if(Prxy_QueryType.GetValue() == 2)
{
Prxy_QueryType.SetValue(0);
u32 mask = Prxy_QueryMask.GetValue();
//
MFC_QStatus.SetValue(mask);
}
}
};*/

View File

@ -579,7 +579,7 @@ public:
#define LOG_DMAC(type, text) type(Log::SPU, "DMAC::ProcessCmd(cmd=0x%x, tag=0x%x, lsa=0x%x, ea=0x%llx, size=0x%x): " text, cmd, tag, lsa, ea, size) #define LOG_DMAC(type, text) type(Log::SPU, "DMAC::ProcessCmd(cmd=0x%x, tag=0x%x, lsa=0x%x, ea=0x%llx, size=0x%x): " text, cmd, tag, lsa, ea, size)
bool ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size) void ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size)
{ {
if (cmd & (MFC_BARRIER_MASK | MFC_FENCE_MASK)) _mm_mfence(); if (cmd & (MFC_BARRIER_MASK | MFC_FENCE_MASK)) _mm_mfence();
@ -588,7 +588,8 @@ public:
if (ea >= 0x100000000) if (ea >= 0x100000000)
{ {
LOG_DMAC(LOG_ERROR, "Invalid external address"); LOG_DMAC(LOG_ERROR, "Invalid external address");
return false; Emu.Pause();
return;
} }
else if (group) else if (group)
{ {
@ -597,7 +598,8 @@ public:
if (num >= group->list.size() || !group->list[num]) if (num >= group->list.size() || !group->list[num])
{ {
LOG_DMAC(LOG_ERROR, "Invalid thread (SPU Thread Group MMIO)"); LOG_DMAC(LOG_ERROR, "Invalid thread (SPU Thread Group MMIO)");
return false; Emu.Pause();
return;
} }
SPUThread* spu = (SPUThread*)Emu.GetCPU().GetThread(group->list[num]); SPUThread* spu = (SPUThread*)Emu.GetCPU().GetThread(group->list[num]);
@ -611,18 +613,20 @@ public:
else if ((cmd & MFC_PUT_CMD) && size == 4 && (addr == SYS_SPU_THREAD_SNR1 || addr == SYS_SPU_THREAD_SNR2)) 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)); spu->WriteSNR(SYS_SPU_THREAD_SNR2 == addr, Memory.Read32(dmac.ls_offset + lsa));
return true; return;
} }
else else
{ {
LOG_DMAC(LOG_ERROR, "Invalid register (SPU Thread Group MMIO)"); LOG_DMAC(LOG_ERROR, "Invalid register (SPU Thread Group MMIO)");
return false; Emu.Pause();
return;
} }
} }
else else
{ {
LOG_DMAC(LOG_ERROR, "Thread group not set (SPU Thread Group MMIO)"); LOG_DMAC(LOG_ERROR, "Thread group not set (SPU Thread Group MMIO)");
return false; Emu.Pause();
return;
} }
} }
else if (ea >= RAW_SPU_BASE_ADDR && size == 4) else if (ea >= RAW_SPU_BASE_ADDR && size == 4)
@ -632,19 +636,20 @@ public:
case MFC_PUT_CMD: case MFC_PUT_CMD:
{ {
Memory.Write32(ea, ReadLS32(lsa)); Memory.Write32(ea, ReadLS32(lsa));
return true; return;
} }
case MFC_GET_CMD: case MFC_GET_CMD:
{ {
WriteLS32(lsa, Memory.Read32(ea)); WriteLS32(lsa, Memory.Read32(ea));
return true; return;
} }
default: default:
{ {
LOG_DMAC(LOG_ERROR, "Unknown DMA command"); LOG_DMAC(LOG_ERROR, "Unknown DMA command");
return false; Emu.Pause();
return;
} }
} }
} }
@ -653,53 +658,27 @@ public:
{ {
case MFC_PUT_CMD: case MFC_PUT_CMD:
{ {
if (Memory.Copy(ea, dmac.ls_offset + lsa, size)) memcpy(Memory + ea, Memory + dmac.ls_offset + lsa, size);
{ return;
return true;
}
else
{
LOG_DMAC(LOG_ERROR, "PUT* cmd failed");
return false; // TODO: page fault (?)
}
} }
case MFC_GET_CMD: case MFC_GET_CMD:
{ {
if (Memory.Copy(dmac.ls_offset + lsa, ea, size)) memcpy(Memory + dmac.ls_offset + lsa, Memory + ea, size);
{ return;
return true;
}
else
{
LOG_DMAC(LOG_ERROR, "GET* cmd failed");
return false; // TODO: page fault (?)
}
} }
default: default:
{ {
LOG_DMAC(LOG_ERROR, "Unknown DMA command"); LOG_DMAC(LOG_ERROR, "Unknown DMA command");
return false; // ??? Emu.Pause();
return;
} }
} }
} }
#undef LOG_CMD #undef LOG_CMD
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) void ListCmd(u32 lsa, u64 ea, u16 tag, u16 size, u32 cmd, MFCReg& MFCArgs)
{ {
u32 list_addr = ea & 0x3ffff; u32 list_addr = ea & 0x3ffff;
@ -713,7 +692,7 @@ public:
be_t<u32> ea; // External Address Low be_t<u32> ea; // External Address Low
}; };
u32 result = MFC_PPU_DMA_CMD_SEQUENCE_ERROR; u32 result = MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL;
for (u32 i = 0; i < list_size; i++) for (u32 i = 0; i < list_size; i++)
{ {
@ -723,15 +702,12 @@ public:
if (size < 16 && size != 1 && size != 2 && size != 4 && size != 8) if (size < 16 && size != 1 && size != 2 && size != 4 && size != 8)
{ {
LOG_ERROR(Log::SPU, "DMA List: invalid transfer size(%d)", size); LOG_ERROR(Log::SPU, "DMA List: invalid transfer size(%d)", size);
return; result = MFC_PPU_DMA_CMD_SEQUENCE_ERROR;
break;
} }
u32 addr = rec->ea; u32 addr = rec->ea;
result = dmacCmd(cmd, tag, lsa | (addr & 0xf), addr, size); ProcessCmd(cmd, tag, lsa | (addr & 0xf), addr, size);
if (result == MFC_PPU_DMA_CMD_SEQUENCE_ERROR)
{
break;
}
if (Ini.HLELogging.GetValue() || rec->s) if (Ini.HLELogging.GetValue() || rec->s)
LOG_NOTICE(Log::SPU, "*** list element(%d/%d): s = 0x%x, ts = 0x%x, low ea = 0x%x (lsa = 0x%x)", LOG_NOTICE(Log::SPU, "*** list element(%d/%d): s = 0x%x, ts = 0x%x, low ea = 0x%x (lsa = 0x%x)",
@ -746,6 +722,8 @@ public:
if (StallList[tag].MFCArgs) if (StallList[tag].MFCArgs)
{ {
LOG_ERROR(Log::SPU, "DMA List: existing stalled list found (tag=%d)", tag); LOG_ERROR(Log::SPU, "DMA List: existing stalled list found (tag=%d)", tag);
result = MFC_PPU_DMA_CMD_SEQUENCE_ERROR;
break;
} }
StallList[tag].MFCArgs = &MFCArgs; StallList[tag].MFCArgs = &MFCArgs;
StallList[tag].cmd = cmd; StallList[tag].cmd = cmd;
@ -753,7 +731,7 @@ public:
StallList[tag].lsa = lsa; StallList[tag].lsa = lsa;
StallList[tag].size = (list_size - i - 1) * 8; StallList[tag].size = (list_size - i - 1) * 8;
return; break;
} }
} }
@ -784,7 +762,8 @@ public:
(op & MFC_FENCE_MASK ? "F" : ""), (op & MFC_FENCE_MASK ? "F" : ""),
lsa, ea, tag, size, cmd); lsa, ea, tag, size, cmd);
MFCArgs.CMDStatus.SetValue(dmacCmd(cmd, tag, lsa, ea, size)); ProcessCmd(cmd, tag, lsa, ea, size);
MFCArgs.CMDStatus.SetValue(MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL);
} }
break; break;
@ -871,21 +850,6 @@ public:
{ {
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE); MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
} }
/*u32 last_d = last_q * 2;
if (buf[last]._u32[last_d] == reservation.data[last]._u32[last_d] && buf[last]._u32[last_d+1] != reservation.data[last]._u32[last_d+1])
{
last_d++;
}
else if (buf[last]._u32[last_d+1] == reservation.data[last]._u32[last_d+1])
{
last_d;
}
else // full 64 bit
{
LOG_ERROR(Log::SPU, "MFC_PUTLLC_CMD: TODO: 64bit compare and swap");
Emu.Pause();
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
}*/
} }
} }
else else