mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-17 17:11:23 +00:00
commit
f477b62813
@ -3,9 +3,22 @@
|
|||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
MFC_PUT_CMD = 0x20,
|
MFC_PUT_CMD = 0x20, MFC_PUTB_CMD = 0x21, MFC_PUTF_CMD = 0x22,
|
||||||
MFC_GET_CMD = 0x40,
|
MFC_GET_CMD = 0x40, MFC_GETB_CMD = 0x41, MFC_GETF_CMD = 0x42,
|
||||||
MFC_MASK_CMD = 0xffff,
|
MFC_PUTL_CMD = 0x24, MFC_PUTLB_CMD = 0x25, MFC_PUTLF_CMD = 0x26,
|
||||||
|
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,
|
||||||
|
MFC_SYNC_CMD = 0xCC,
|
||||||
|
|
||||||
|
MFC_BARRIER_MASK = 0x01,
|
||||||
|
MFC_FENCE_MASK = 0x02,
|
||||||
|
MFC_MASK_CMD = 0xffff,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@ -130,11 +143,34 @@ public:
|
|||||||
|
|
||||||
struct DMAC
|
struct DMAC
|
||||||
{
|
{
|
||||||
DMAC_Queue queue[MFC_SPU_MAX_QUEUE_SPACE];
|
//DMAC_Queue queue[MFC_SPU_MAX_QUEUE_SPACE]; //not used yet
|
||||||
DMAC_Proxy proxy[MFC_PPU_MAX_QUEUE_SPACE];
|
DMAC_Proxy proxy[MFC_PPU_MAX_QUEUE_SPACE+MFC_SPU_MAX_QUEUE_SPACE]; //temporarily 24
|
||||||
u64 ls_offset;
|
u64 ls_offset;
|
||||||
std::atomic<u32> queue_pos;
|
u32 queue_pos;
|
||||||
std::atomic<u32> proxy_pos;
|
u32 proxy_pos;
|
||||||
|
long queue_lock;
|
||||||
|
long 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))
|
||||||
|
{
|
||||||
|
case MFC_PUT_CMD:
|
||||||
|
memcpy(Memory + ea, Memory + ls_offset + lsa, size);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MFC_GET_CMD:
|
||||||
|
memcpy(Memory + ls_offset + lsa, Memory + ea, size);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ConLog.Error("Unknown DMA cmd.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
u32 Cmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size)
|
u32 Cmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size)
|
||||||
{
|
{
|
||||||
@ -148,36 +184,40 @@ struct DMAC
|
|||||||
return MFC_PPU_DMA_QUEUE_FULL;
|
return MFC_PPU_DMA_QUEUE_FULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
DMAC_Proxy& p = proxy[proxy_pos++];
|
/* while (_InterlockedExchange(&proxy_lock, 1));
|
||||||
|
_mm_lfence();
|
||||||
|
DMAC_Proxy& p = proxy[proxy_pos];
|
||||||
p.cmd = cmd;
|
p.cmd = cmd;
|
||||||
p.tag = tag;
|
p.tag = tag;
|
||||||
p.lsa = lsa;
|
p.lsa = lsa;
|
||||||
p.ea = ea;
|
p.ea = ea;
|
||||||
p.size = size;
|
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;
|
return MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClearCmd()
|
||||||
|
{
|
||||||
|
while (_InterlockedExchange(&proxy_lock, 1));
|
||||||
|
_mm_lfence();
|
||||||
|
memcpy(proxy, proxy + 1, --proxy_pos * sizeof(DMAC_Proxy));
|
||||||
|
_mm_sfence();
|
||||||
|
proxy_lock = 0; //release lock
|
||||||
|
}
|
||||||
|
|
||||||
void DoCmd()
|
void DoCmd()
|
||||||
{
|
{
|
||||||
if(proxy_pos)
|
if(proxy_pos)
|
||||||
{
|
{
|
||||||
DMAC_Proxy p = proxy[0];
|
const DMAC_Proxy& p = proxy[0];
|
||||||
memcpy(proxy, proxy + 1, --proxy_pos * sizeof(DMAC_Proxy));
|
if (ProcessCmd(p.cmd, p.tag, p.lsa, p.ea, p.size))
|
||||||
|
|
||||||
switch(p.cmd)
|
|
||||||
{
|
{
|
||||||
case MFC_PUT_CMD:
|
ClearCmd();
|
||||||
memcpy(Memory + p.ea, Memory + ls_offset + p.lsa, p.size);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MFC_GET_CMD:
|
|
||||||
memcpy(Memory + ls_offset + p.lsa, Memory + p.ea, p.size);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ConLog.Error("Unknown DMA cmd.");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ namespace PPU_instr
|
|||||||
static CodeField<11, 15> BI;
|
static CodeField<11, 15> BI;
|
||||||
|
|
||||||
//Immediate field specifying a 14-bit signed two's complement branch displacement that is concatenated on the
|
//Immediate field specifying a 14-bit signed two's complement branch displacement that is concatenated on the
|
||||||
//right with ‘00’ and sign-extended to 64 bits.
|
//right with '00' and sign-extended to 64 bits.
|
||||||
static CodeFieldSigned<16, 31> BD(FIELD_BRANCH);
|
static CodeFieldSigned<16, 31> BD(FIELD_BRANCH);
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -179,9 +179,9 @@ namespace PPU_instr
|
|||||||
Record bit.
|
Record bit.
|
||||||
0 Does not update the condition register (CR).
|
0 Does not update the condition register (CR).
|
||||||
1 Updates the CR to reflect the result of the operation.
|
1 Updates the CR to reflect the result of the operation.
|
||||||
For integer instructions, CR bits [0–2] are set to reflect the result as a signed quantity and CR bit [3]
|
For integer instructions, CR bits [0-2] are set to reflect the result as a signed quantity and CR bit [3]
|
||||||
receives a copy of the summary overflow bit, XER[SO]. The result as an unsigned quantity or a bit
|
receives a copy of the summary overflow bit, XER[SO]. The result as an unsigned quantity or a bit
|
||||||
string can be deduced from the EQ bit. For floating-point instructions, CR bits [4–7] are set to reflect
|
string can be deduced from the EQ bit. For floating-point instructions, CR bits [4-7] are set to reflect
|
||||||
floating-point exception, floating-point enabled exception, floating-point invalid operation exception,
|
floating-point exception, floating-point enabled exception, floating-point invalid operation exception,
|
||||||
and floating-point overflow exception.
|
and floating-point overflow exception.
|
||||||
*/
|
*/
|
||||||
|
@ -3427,6 +3427,7 @@ private:
|
|||||||
void MTFSB1(u32 crbd, bool rc)
|
void MTFSB1(u32 crbd, bool rc)
|
||||||
{
|
{
|
||||||
u64 mask = (1ULL << crbd);
|
u64 mask = (1ULL << crbd);
|
||||||
|
if ((crbd == 29) && !CPU.FPSCR.NI) ConLog.Warning("Non-IEEE mode enabled");
|
||||||
CPU.FPSCR.FPSCR |= mask;
|
CPU.FPSCR.FPSCR |= mask;
|
||||||
|
|
||||||
if(rc) UNIMPLEMENTED();
|
if(rc) UNIMPLEMENTED();
|
||||||
@ -3440,6 +3441,7 @@ private:
|
|||||||
void MTFSB0(u32 crbd, bool rc)
|
void MTFSB0(u32 crbd, bool rc)
|
||||||
{
|
{
|
||||||
u64 mask = (1ULL << crbd);
|
u64 mask = (1ULL << crbd);
|
||||||
|
if ((crbd == 29) && !CPU.FPSCR.NI) ConLog.Warning("Non-IEEE mode disabled");
|
||||||
CPU.FPSCR.FPSCR &= ~mask;
|
CPU.FPSCR.FPSCR &= ~mask;
|
||||||
|
|
||||||
if(rc) UNIMPLEMENTED();
|
if(rc) UNIMPLEMENTED();
|
||||||
@ -3450,10 +3452,12 @@ private:
|
|||||||
|
|
||||||
if(i)
|
if(i)
|
||||||
{
|
{
|
||||||
|
if ((crfd == 29) && !CPU.FPSCR.NI) ConLog.Warning("Non-IEEE mode enabled");
|
||||||
CPU.FPSCR.FPSCR |= mask;
|
CPU.FPSCR.FPSCR |= mask;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if ((crfd == 29) && CPU.FPSCR.NI) ConLog.Warning("Non-IEEE mode disabled");
|
||||||
CPU.FPSCR.FPSCR &= ~mask;
|
CPU.FPSCR.FPSCR &= ~mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3472,7 +3476,15 @@ private:
|
|||||||
if(flm & (1 << i)) mask |= 0xf << (i * 4);
|
if(flm & (1 << i)) mask |= 0xf << (i * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const u32 oldNI = CPU.FPSCR.NI;
|
||||||
CPU.FPSCR.FPSCR = (CPU.FPSCR.FPSCR & ~mask) | ((u32&)CPU.FPR[frb] & mask);
|
CPU.FPSCR.FPSCR = (CPU.FPSCR.FPSCR & ~mask) | ((u32&)CPU.FPR[frb] & mask);
|
||||||
|
if (CPU.FPSCR.NI != oldNI)
|
||||||
|
{
|
||||||
|
if (oldNI)
|
||||||
|
ConLog.Warning("Non-IEEE mode disabled");
|
||||||
|
else
|
||||||
|
ConLog.Warning("Non-IEEE mode enabled");
|
||||||
|
}
|
||||||
if(rc) UNK("mtfsf.");
|
if(rc) UNK("mtfsf.");
|
||||||
}
|
}
|
||||||
void FCMPU(u32 crfd, u32 fra, u32 frb)
|
void FCMPU(u32 crfd, u32 fra, u32 frb)
|
||||||
|
@ -57,16 +57,22 @@ bool RawSPUThread::Read32(const u64 addr, u32* value)
|
|||||||
u32 offset = addr - GetStartAddr() - RAW_SPU_PROB_OFFSET;
|
u32 offset = addr - GetStartAddr() - RAW_SPU_PROB_OFFSET;
|
||||||
switch(offset)
|
switch(offset)
|
||||||
{
|
{
|
||||||
case MFC_LSA_offs: ConLog.Warning("RawSPUThread[%d]: Read32(MFC_LSA)", m_index); *value = MFC.LSA.GetValue(); break;
|
case MFC_LSA_offs: ConLog.Warning("RawSPUThread[%d]: Read32(MFC_LSA)", m_index); *value = MFC2.LSA.GetValue(); break;
|
||||||
case MFC_EAH_offs: ConLog.Warning("RawSPUThread[%d]: Read32(MFC_EAH)", m_index); *value = MFC.EAH.GetValue(); break;
|
case MFC_EAH_offs: ConLog.Warning("RawSPUThread[%d]: Read32(MFC_EAH)", m_index); *value = MFC2.EAH.GetValue(); break;
|
||||||
case MFC_EAL_offs: ConLog.Warning("RawSPUThread[%d]: Read32(MFC_EAL)", m_index); *value = MFC.EAL.GetValue(); break;
|
case MFC_EAL_offs: ConLog.Warning("RawSPUThread[%d]: Read32(MFC_EAL)", m_index); *value = MFC2.EAL.GetValue(); break;
|
||||||
case MFC_Size_Tag_offs: ConLog.Warning("RawSPUThread[%d]: Read32(MFC_Size_Tag)", m_index); *value = MFC.Size_Tag.GetValue(); break;
|
case MFC_Size_Tag_offs: ConLog.Warning("RawSPUThread[%d]: Read32(MFC_Size_Tag)", m_index); *value = MFC2.Size_Tag.GetValue(); break;
|
||||||
case MFC_CMDStatus_offs: ConLog.Warning("RawSPUThread[%d]: Read32(MFC_CMDStatus)", m_index); *value = MFC.CMDStatus.GetValue(); break;
|
case MFC_CMDStatus_offs: ConLog.Warning("RawSPUThread[%d]: Read32(MFC_CMDStatus)", m_index); *value = MFC2.CMDStatus.GetValue(); break;
|
||||||
case MFC_QStatus_offs: ConLog.Warning("RawSPUThread[%d]: Read32(MFC_QStatus)", m_index); *value = MFC.QStatus.GetValue(); break;
|
case MFC_QStatus_offs:
|
||||||
|
ConLog.Warning("RawSPUThread[%d]: Read32(MFC_QStatus)", m_index);
|
||||||
|
*value = MFC2.QStatus.GetValue();
|
||||||
|
break;
|
||||||
case Prxy_QueryType_offs: ConLog.Warning("RawSPUThread[%d]: Read32(Prxy_QueryType)", m_index); *value = Prxy.QueryType.GetValue(); break;
|
case Prxy_QueryType_offs: ConLog.Warning("RawSPUThread[%d]: Read32(Prxy_QueryType)", m_index); *value = Prxy.QueryType.GetValue(); break;
|
||||||
case Prxy_QueryMask_offs: ConLog.Warning("RawSPUThread[%d]: Read32(Prxy_QueryMask)", m_index); *value = Prxy.QueryMask.GetValue(); break;
|
case Prxy_QueryMask_offs: ConLog.Warning("RawSPUThread[%d]: Read32(Prxy_QueryMask)", m_index); *value = Prxy.QueryMask.GetValue(); break;
|
||||||
case Prxy_TagStatus_offs: ConLog.Warning("RawSPUThread[%d]: Read32(Prxy_TagStatus)", m_index); *value = Prxy.TagStatus.GetValue(); break;
|
case Prxy_TagStatus_offs: ConLog.Warning("RawSPUThread[%d]: Read32(Prxy_TagStatus)", m_index); *value = Prxy.TagStatus.GetValue(); break;
|
||||||
case SPU_Out_MBox_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_Out_MBox)", m_index); while(!SPU.Out_MBox.Pop(*value) && !Emu.IsStopped()) Sleep(1); break;
|
case SPU_Out_MBox_offs:
|
||||||
|
ConLog.Warning("RawSPUThread[%d]: Read32(SPU_Out_MBox)", m_index);
|
||||||
|
SPU.Out_MBox.PopUncond(*value); //if Out_MBox is empty yet, the result will be undefined
|
||||||
|
break;
|
||||||
case SPU_In_MBox_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_In_MBox)", m_index); while(!SPU.In_MBox.Pop(*value) && !Emu.IsStopped()) Sleep(1); break;
|
case SPU_In_MBox_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_In_MBox)", m_index); while(!SPU.In_MBox.Pop(*value) && !Emu.IsStopped()) Sleep(1); break;
|
||||||
case SPU_MBox_Status_offs: //ConLog.Warning("RawSPUThread[%d]: Read32(SPU_MBox_Status)", m_index);
|
case SPU_MBox_Status_offs: //ConLog.Warning("RawSPUThread[%d]: Read32(SPU_MBox_Status)", m_index);
|
||||||
//SPU.MBox_Status.SetValue(SPU.Out_MBox.GetCount() ? SPU.MBox_Status.GetValue() | 1 : SPU.MBox_Status.GetValue() & ~1);
|
//SPU.MBox_Status.SetValue(SPU.Out_MBox.GetCount() ? SPU.MBox_Status.GetValue() | 1 : SPU.MBox_Status.GetValue() & ~1);
|
||||||
@ -76,8 +82,8 @@ bool RawSPUThread::Read32(const u64 addr, u32* value)
|
|||||||
case SPU_RunCntl_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_RunCntl)", m_index); *value = SPU.RunCntl.GetValue(); break;
|
case SPU_RunCntl_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_RunCntl)", m_index); *value = SPU.RunCntl.GetValue(); break;
|
||||||
case SPU_Status_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_Status)", m_index); *value = SPU.Status.GetValue(); break;
|
case SPU_Status_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_Status)", m_index); *value = SPU.Status.GetValue(); break;
|
||||||
case SPU_NPC_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_NPC)", m_index); *value = SPU.NPC.GetValue(); break;
|
case SPU_NPC_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_NPC)", m_index); *value = SPU.NPC.GetValue(); break;
|
||||||
case SPU_RdSigNotify1_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_RdSigNotify1)", m_index); *value = SPU.RdSigNotify1.GetValue(); break;
|
case SPU_RdSigNotify1_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_RdSigNotify1)", m_index); *value = SPU.SNR[0].GetValue(); break;
|
||||||
case SPU_RdSigNotify2_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_RdSigNotify2)", m_index); *value = SPU.RdSigNotify2.GetValue(); break;
|
case SPU_RdSigNotify2_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_RdSigNotify2)", m_index); *value = SPU.SNR[1].GetValue(); break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ConLog.Error("RawSPUThread[%d]: Read32(0x%x)", m_index, offset);
|
ConLog.Error("RawSPUThread[%d]: Read32(0x%x)", m_index, offset);
|
||||||
@ -151,16 +157,15 @@ bool RawSPUThread::Write32(const u64 addr, const u32 value)
|
|||||||
|
|
||||||
switch(offset)
|
switch(offset)
|
||||||
{
|
{
|
||||||
case MFC_LSA_offs: ConLog.Warning("RawSPUThread[%d]: Write32(MFC_LSA, 0x%x)", m_index, value); MFC.LSA.SetValue(value); break;
|
case MFC_LSA_offs: MFC2.LSA.SetValue(value); break;
|
||||||
case MFC_EAH_offs: ConLog.Warning("RawSPUThread[%d]: Write32(MFC_EAH, 0x%x)", m_index, value); MFC.EAH.SetValue(value); break;
|
case MFC_EAH_offs: MFC2.EAH.SetValue(value); break;
|
||||||
case MFC_EAL_offs: ConLog.Warning("RawSPUThread[%d]: Write32(MFC_EAL, 0x%x)", m_index, value); MFC.EAL.SetValue(value); break;
|
case MFC_EAL_offs: MFC2.EAL.SetValue(value); break;
|
||||||
case MFC_Size_Tag_offs: ConLog.Warning("RawSPUThread[%d]: Write32(MFC_Size_Tag, 0x%x)", m_index, value); MFC.Size_Tag.SetValue(value); break;
|
case MFC_Size_Tag_offs: MFC2.Size_Tag.SetValue(value); break;
|
||||||
case MFC_CMDStatus_offs:
|
case MFC_CMDStatus_offs:
|
||||||
ConLog.Warning("RawSPUThread[%d]: Write32(MFC_CMDStatus, 0x%x)", m_index, value);
|
MFC2.CMDStatus.SetValue(value);
|
||||||
MFC.CMDStatus.SetValue(value);
|
EnqMfcCmd(MFC2);
|
||||||
DoMfcCmd();
|
|
||||||
break;
|
break;
|
||||||
case MFC_QStatus_offs: ConLog.Warning("RawSPUThread[%d]: Write32(MFC_QStatus, 0x%x)", m_index, value); MFC.QStatus.SetValue(value); break;
|
case MFC_QStatus_offs: ConLog.Warning("RawSPUThread[%d]: Write32(MFC_QStatus, 0x%x)", m_index, value); MFC2.QStatus.SetValue(value); break;
|
||||||
case Prxy_QueryType_offs:
|
case Prxy_QueryType_offs:
|
||||||
{
|
{
|
||||||
ConLog.Warning("RawSPUThread[%d]: Write32(Prxy_QueryType, 0x%x)", m_index, value);
|
ConLog.Warning("RawSPUThread[%d]: Write32(Prxy_QueryType, 0x%x)", m_index, value);
|
||||||
@ -178,19 +183,22 @@ bool RawSPUThread::Write32(const u64 addr, const u32 value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Prxy.QueryType.SetValue(0);
|
Prxy.QueryType.SetValue(0);
|
||||||
MFC.QStatus.SetValue(Prxy.QueryMask.GetValue());
|
MFC2.QStatus.SetValue(Prxy.QueryMask.GetValue());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Prxy_QueryMask_offs: ConLog.Warning("RawSPUThread[%d]: Write32(Prxy_QueryMask, 0x%x)", m_index, value); Prxy.QueryMask.SetValue(value); break;
|
case Prxy_QueryMask_offs: ConLog.Warning("RawSPUThread[%d]: Write32(Prxy_QueryMask, 0x%x)", m_index, value); Prxy.QueryMask.SetValue(value); break;
|
||||||
case Prxy_TagStatus_offs: ConLog.Warning("RawSPUThread[%d]: Write32(Prxy_TagStatus, 0x%x)", m_index, value); Prxy.TagStatus.SetValue(value); break;
|
case Prxy_TagStatus_offs: ConLog.Warning("RawSPUThread[%d]: Write32(Prxy_TagStatus, 0x%x)", m_index, value); Prxy.TagStatus.SetValue(value); break;
|
||||||
case SPU_Out_MBox_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_Out_MBox, 0x%x)", m_index, value); while(!SPU.Out_MBox.Push(value) && !Emu.IsStopped()) Sleep(1); break;
|
case SPU_Out_MBox_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_Out_MBox, 0x%x)", m_index, value); while(!SPU.Out_MBox.Push(value) && !Emu.IsStopped()) Sleep(1); break;
|
||||||
case SPU_In_MBox_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_In_MBox, 0x%x)", m_index, value); while(!SPU.In_MBox.Push(value) && !Emu.IsStopped()) Sleep(1); break;
|
case SPU_In_MBox_offs:
|
||||||
|
ConLog.Warning("RawSPUThread[%d]: Write32(SPU_In_MBox, 0x%x)", m_index, value);
|
||||||
|
SPU.In_MBox.PushUncond(value); //if In_MBox is already full, the last message will be overwritten
|
||||||
|
break;
|
||||||
case SPU_MBox_Status_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_MBox_Status, 0x%x)", m_index, value); SPU.MBox_Status.SetValue(value); break;
|
case SPU_MBox_Status_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_MBox_Status, 0x%x)", m_index, value); SPU.MBox_Status.SetValue(value); break;
|
||||||
case SPU_RunCntl_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_RunCntl, 0x%x)", m_index, value); SPU.RunCntl.SetValue(value); break;
|
case SPU_RunCntl_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_RunCntl, 0x%x)", m_index, value); SPU.RunCntl.SetValue(value); break;
|
||||||
case SPU_Status_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_Status, 0x%x)", m_index, value); SPU.Status.SetValue(value); break;
|
case SPU_Status_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_Status, 0x%x)", m_index, value); SPU.Status.SetValue(value); break;
|
||||||
case SPU_NPC_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_NPC, 0x%x)", m_index, value); SPU.NPC.SetValue(value); break;
|
case SPU_NPC_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_NPC, 0x%x)", m_index, value); SPU.NPC.SetValue(value); break;
|
||||||
case SPU_RdSigNotify1_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_RdSigNotify1, 0x%x)", m_index, value); SPU.RdSigNotify1.SetValue(value); break;
|
case SPU_RdSigNotify1_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_RdSigNotify1, 0x%x)", m_index, value); SPU.SNR[0].SetValue(value); break;
|
||||||
case SPU_RdSigNotify2_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_RdSigNotify2, 0x%x)", m_index, value); SPU.RdSigNotify2.SetValue(value); break;
|
case SPU_RdSigNotify2_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_RdSigNotify2, 0x%x)", m_index, value); SPU.SNR[1].SetValue(value); break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ConLog.Error("RawSPUThread[%d]: Write32(0x%x, 0x%x)", m_index, offset, value);
|
ConLog.Error("RawSPUThread[%d]: Write32(0x%x, 0x%x)", m_index, offset, value);
|
||||||
|
@ -7,12 +7,12 @@
|
|||||||
|
|
||||||
#define UNIMPLEMENTED() UNK(__FUNCTION__)
|
#define UNIMPLEMENTED() UNK(__FUNCTION__)
|
||||||
|
|
||||||
typedef union _CRT_ALIGN(16) __u32x4 {
|
/* typedef union _CRT_ALIGN(16) __u32x4 {
|
||||||
unsigned __int32 _u32[4];
|
u32 _u32[4];
|
||||||
__m128i m128i;
|
__m128i m128i;
|
||||||
__m128 m128;
|
__m128 m128;
|
||||||
__m128d m128d;
|
__m128d m128d;
|
||||||
} __u32x4;
|
} __u32x4; */
|
||||||
|
|
||||||
class SPUInterpreter : public SPUOpcodes
|
class SPUInterpreter : public SPUOpcodes
|
||||||
{
|
{
|
||||||
@ -35,24 +35,24 @@ private:
|
|||||||
if(code & 0x2000)
|
if(code & 0x2000)
|
||||||
{
|
{
|
||||||
CPU.SetExitStatus(code & 0xfff);
|
CPU.SetExitStatus(code & 0xfff);
|
||||||
CPU.Stop();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ConLog.Warning("STOP: 0x%x", code);
|
ConLog.Warning("STOP: 0x%x", code);
|
||||||
Emu.Pause();
|
//Emu.Pause();
|
||||||
}
|
}
|
||||||
|
CPU.Stop();
|
||||||
}
|
}
|
||||||
void LNOP()
|
void LNOP()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
void SYNC(u32 Cbit)
|
void SYNC(u32 Cbit)
|
||||||
{
|
{
|
||||||
//UNIMPLEMENTED();
|
_mm_mfence();
|
||||||
}
|
}
|
||||||
void DSYNC()
|
void DSYNC()
|
||||||
{
|
{
|
||||||
//UNIMPLEMENTED();
|
_mm_mfence();
|
||||||
}
|
}
|
||||||
void MFSPR(u32 rt, u32 sa)
|
void MFSPR(u32 rt, u32 sa)
|
||||||
{
|
{
|
||||||
@ -191,18 +191,8 @@ private:
|
|||||||
{
|
{
|
||||||
const u32 s = i7 & 0x3f;
|
const u32 s = i7 & 0x3f;
|
||||||
|
|
||||||
for(u32 j = 0; j < 4; ++j)
|
for (u32 j = 0; j < 4; ++j)
|
||||||
{
|
CPU.GPR[rt]._u32[j] = CPU.GPR[ra]._u32[j] << s;
|
||||||
const u32 t = CPU.GPR[ra]._u32[j];
|
|
||||||
u32 r = 0;
|
|
||||||
|
|
||||||
for(u32 b = 0; b + s < 32; ++b)
|
|
||||||
{
|
|
||||||
r |= t & (1 << (b + s));
|
|
||||||
}
|
|
||||||
|
|
||||||
CPU.GPR[rt]._u32[j] = r;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
void ROTHI(u32 rt, u32 ra, s32 i7)
|
void ROTHI(u32 rt, u32 ra, s32 i7)
|
||||||
{
|
{
|
||||||
@ -388,28 +378,21 @@ private:
|
|||||||
}
|
}
|
||||||
void FREST(u32 rt, u32 ra)
|
void FREST(u32 rt, u32 ra)
|
||||||
{
|
{
|
||||||
//(SSE) RCPPS - Compute Reciprocals of Packed Single-Precision Floating-Point Values
|
//CPU.GPR[rt]._m128 = _mm_rcp_ps(CPU.GPR[ra]._m128);
|
||||||
//rt = approximate(1/ra)
|
for (int i = 0; i < 4; i++)
|
||||||
CPU.GPR[rt]._m128 = _mm_rcp_ps(CPU.GPR[ra]._m128);
|
CPU.GPR[rt]._f[i] = 1 / CPU.GPR[ra]._f[i];
|
||||||
}
|
}
|
||||||
void FRSQEST(u32 rt, u32 ra)
|
void FRSQEST(u32 rt, u32 ra)
|
||||||
{
|
{
|
||||||
//(SSE) RSQRTPS - Compute Reciprocals of Square Roots of Packed Single-Precision Floating-Point Values
|
//const __u32x4 FloatAbsMask = {0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff};
|
||||||
//rt = approximate(1/sqrt(abs(ra)))
|
//CPU.GPR[rt]._m128 = _mm_rsqrt_ps(_mm_and_ps(CPU.GPR[ra]._m128, FloatAbsMask.m128));
|
||||||
//abs(ra) === ra & FloatAbsMask
|
for (int i = 0; i < 4; i++)
|
||||||
const __u32x4 FloatAbsMask = {0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff};
|
CPU.GPR[rt]._f[i] = 1 / sqrt(abs(CPU.GPR[ra]._f[i]));
|
||||||
CPU.GPR[rt]._m128 = _mm_rsqrt_ps(_mm_and_ps(CPU.GPR[ra]._m128, FloatAbsMask.m128));
|
|
||||||
}
|
}
|
||||||
void LQX(u32 rt, u32 ra, u32 rb)
|
void LQX(u32 rt, u32 ra, u32 rb)
|
||||||
{
|
{
|
||||||
u32 a = CPU.GPR[ra]._u32[3], b = CPU.GPR[rb]._u32[3];
|
u32 a = CPU.GPR[ra]._u32[3], b = CPU.GPR[rb]._u32[3];
|
||||||
|
|
||||||
if(b & 0xf)
|
|
||||||
{
|
|
||||||
ConLog.Warning("LQX HACK (a[0x%x] + b[0x%x(0x%x)])", a, b << 3, b);
|
|
||||||
b <<= 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 lsa = (a + b) & 0x3fff0;
|
u32 lsa = (a + b) & 0x3fff0;
|
||||||
|
|
||||||
if(!CPU.IsGoodLSA(lsa))
|
if(!CPU.IsGoodLSA(lsa))
|
||||||
@ -1009,9 +992,10 @@ private:
|
|||||||
exp = 255;
|
exp = 255;
|
||||||
|
|
||||||
CPU.GPR[rt]._u32[i] = (CPU.GPR[ra]._u32[i] & 0x807fffff) | (exp << 23);
|
CPU.GPR[rt]._u32[i] = (CPU.GPR[ra]._u32[i] & 0x807fffff) | (exp << 23);
|
||||||
|
|
||||||
|
CPU.GPR[rt]._u32[i] = (u32)CPU.GPR[rt]._f[i]; //trunc
|
||||||
}
|
}
|
||||||
//(SSE2) CVTTPS2DQ - Convert with Truncation Packed Single FP to Packed Dword Int
|
//CPU.GPR[rt]._m128i = _mm_cvttps_epi32(CPU.GPR[rt]._m128);
|
||||||
CPU.GPR[rt]._m128i = _mm_cvttps_epi32(CPU.GPR[rt]._m128);
|
|
||||||
}
|
}
|
||||||
void CFLTU(u32 rt, u32 ra, s32 i8)
|
void CFLTU(u32 rt, u32 ra, s32 i8)
|
||||||
{
|
{
|
||||||
@ -1038,11 +1022,12 @@ private:
|
|||||||
}
|
}
|
||||||
void CSFLT(u32 rt, u32 ra, s32 i8)
|
void CSFLT(u32 rt, u32 ra, s32 i8)
|
||||||
{
|
{
|
||||||
//(SSE2) CVTDQ2PS - Convert Packed Dword Integers to Packed Single-Precision FP Values
|
//CPU.GPR[rt]._m128 = _mm_cvtepi32_ps(CPU.GPR[ra]._m128i);
|
||||||
CPU.GPR[rt]._m128 = _mm_cvtepi32_ps(CPU.GPR[ra]._m128i);
|
|
||||||
const u32 scale = 155 - (i8 & 0xff); //unsigned immediate
|
const u32 scale = 155 - (i8 & 0xff); //unsigned immediate
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
|
CPU.GPR[rt]._f[i] = (s32)CPU.GPR[ra]._i32[i];
|
||||||
|
|
||||||
u32 exp = ((CPU.GPR[rt]._u32[i] >> 23) & 0xff) - scale;
|
u32 exp = ((CPU.GPR[rt]._u32[i] >> 23) & 0xff) - scale;
|
||||||
|
|
||||||
if (exp > 255) //< 0
|
if (exp > 255) //< 0
|
||||||
@ -1412,7 +1397,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void MPYA(u32 rc, u32 ra, u32 rb, u32 rt)
|
void MPYA(u32 rt, u32 ra, u32 rb, u32 rc)
|
||||||
{
|
{
|
||||||
for (int w = 0; w < 4; w++)
|
for (int w = 0; w < 4; w++)
|
||||||
CPU.GPR[rt]._i32[w] = CPU.GPR[ra]._i16[w*2] * CPU.GPR[rb]._i16[w*2] + CPU.GPR[rc]._i32[w];
|
CPU.GPR[rt]._i32[w] = CPU.GPR[ra]._i16[w*2] * CPU.GPR[rb]._i16[w*2] + CPU.GPR[rc]._i32[w];
|
||||||
@ -1424,14 +1409,14 @@ private:
|
|||||||
CPU.GPR[rt]._f[2] = CPU.GPR[rc]._f[2] - CPU.GPR[ra]._f[2] * CPU.GPR[rb]._f[2];
|
CPU.GPR[rt]._f[2] = CPU.GPR[rc]._f[2] - CPU.GPR[ra]._f[2] * CPU.GPR[rb]._f[2];
|
||||||
CPU.GPR[rt]._f[3] = CPU.GPR[rc]._f[3] - CPU.GPR[ra]._f[3] * CPU.GPR[rb]._f[3];
|
CPU.GPR[rt]._f[3] = CPU.GPR[rc]._f[3] - CPU.GPR[ra]._f[3] * CPU.GPR[rb]._f[3];
|
||||||
}
|
}
|
||||||
void FMA(u32 rc, u32 ra, u32 rb, u32 rt)
|
void FMA(u32 rt, u32 ra, u32 rb, u32 rc)
|
||||||
{
|
{
|
||||||
CPU.GPR[rt]._f[0] = CPU.GPR[ra]._f[0] * CPU.GPR[rb]._f[0] + CPU.GPR[rc]._f[0];
|
CPU.GPR[rt]._f[0] = CPU.GPR[ra]._f[0] * CPU.GPR[rb]._f[0] + CPU.GPR[rc]._f[0];
|
||||||
CPU.GPR[rt]._f[1] = CPU.GPR[ra]._f[1] * CPU.GPR[rb]._f[1] + CPU.GPR[rc]._f[1];
|
CPU.GPR[rt]._f[1] = CPU.GPR[ra]._f[1] * CPU.GPR[rb]._f[1] + CPU.GPR[rc]._f[1];
|
||||||
CPU.GPR[rt]._f[2] = CPU.GPR[ra]._f[2] * CPU.GPR[rb]._f[2] + CPU.GPR[rc]._f[2];
|
CPU.GPR[rt]._f[2] = CPU.GPR[ra]._f[2] * CPU.GPR[rb]._f[2] + CPU.GPR[rc]._f[2];
|
||||||
CPU.GPR[rt]._f[3] = CPU.GPR[ra]._f[3] * CPU.GPR[rb]._f[3] + CPU.GPR[rc]._f[3];
|
CPU.GPR[rt]._f[3] = CPU.GPR[ra]._f[3] * CPU.GPR[rb]._f[3] + CPU.GPR[rc]._f[3];
|
||||||
}
|
}
|
||||||
void FMS(u32 rc, u32 ra, u32 rb, u32 rt)
|
void FMS(u32 rt, u32 ra, u32 rb, u32 rc)
|
||||||
{
|
{
|
||||||
CPU.GPR[rt]._f[0] = CPU.GPR[ra]._f[0] * CPU.GPR[rb]._f[0] - CPU.GPR[rc]._f[0];
|
CPU.GPR[rt]._f[0] = CPU.GPR[ra]._f[0] * CPU.GPR[rb]._f[0] - CPU.GPR[rc]._f[0];
|
||||||
CPU.GPR[rt]._f[1] = CPU.GPR[ra]._f[1] * CPU.GPR[rb]._f[1] - CPU.GPR[rc]._f[1];
|
CPU.GPR[rt]._f[1] = CPU.GPR[ra]._f[1] * CPU.GPR[rb]._f[1] - CPU.GPR[rc]._f[1];
|
||||||
|
@ -43,14 +43,19 @@ void SPUThread::InitRegs()
|
|||||||
GPR[5]._u64[1] = m_args[2];
|
GPR[5]._u64[1] = m_args[2];
|
||||||
GPR[6]._u64[1] = m_args[3];
|
GPR[6]._u64[1] = m_args[3];
|
||||||
|
|
||||||
|
cfg.Reset();
|
||||||
|
|
||||||
dmac.ls_offset = m_offset;
|
dmac.ls_offset = m_offset;
|
||||||
dmac.proxy_pos = 0;
|
dmac.proxy_pos = 0;
|
||||||
dmac.queue_pos = 0;
|
dmac.queue_pos = 0;
|
||||||
|
dmac.proxy_lock = 0;
|
||||||
|
dmac.queue_lock = 0;
|
||||||
|
|
||||||
SPU.RunCntl.SetValue(SPU_RUNCNTL_STOP);
|
SPU.RunCntl.SetValue(SPU_RUNCNTL_STOP);
|
||||||
SPU.Status.SetValue(SPU_STATUS_RUNNING);
|
SPU.Status.SetValue(SPU_STATUS_RUNNING);
|
||||||
Prxy.QueryType.SetValue(0);
|
Prxy.QueryType.SetValue(0);
|
||||||
MFC.CMDStatus.SetValue(0);
|
MFC1.CMDStatus.SetValue(0);
|
||||||
|
MFC2.CMDStatus.SetValue(0);
|
||||||
//PC = SPU.NPC.GetValue();
|
//PC = SPU.NPC.GetValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,22 +249,51 @@ union SPU_SPR_hdr
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
union SPU_SNRConfig_hdr
|
||||||
|
{
|
||||||
|
u64 value;
|
||||||
|
|
||||||
|
SPU_SNRConfig_hdr() {}
|
||||||
|
|
||||||
|
wxString ToString() const
|
||||||
|
{
|
||||||
|
return wxString::Format("%01x", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
memset(this, 0, sizeof(*this));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class SPUThread : public PPCThread
|
class SPUThread : public PPCThread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SPU_GPR_hdr GPR[128]; //General-Purpose Register
|
SPU_GPR_hdr GPR[128]; //General-Purpose Register
|
||||||
SPU_SPR_hdr SPR[128]; //Special-Purpose Registers
|
SPU_SPR_hdr SPR[128]; //Special-Purpose Registers
|
||||||
FPSCR FPSCR;
|
FPSCR FPSCR;
|
||||||
|
SPU_SNRConfig_hdr cfg; //Signal Notification Registers Configuration (OR-mode enabled: 0x1 for SNR1, 0x2 for SNR2)
|
||||||
|
|
||||||
template<size_t _max_count>
|
template<size_t _max_count>
|
||||||
class Channel
|
class Channel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static const size_t max_count = _max_count;
|
static const size_t max_count = _max_count;
|
||||||
|
#ifdef _M_X64
|
||||||
|
static const bool x86 = false;
|
||||||
|
#else
|
||||||
|
static const bool x86 = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
u32 m_value[max_count];
|
union _CRT_ALIGN(8) {
|
||||||
u32 m_index;
|
struct {
|
||||||
|
volatile u32 m_index;
|
||||||
|
u32 m_value[max_count];
|
||||||
|
};
|
||||||
|
volatile u64 m_indval;
|
||||||
|
};
|
||||||
|
volatile long m_lock;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -276,29 +305,154 @@ public:
|
|||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
m_index = 0;
|
m_index = 0;
|
||||||
|
m_lock = 0; //simple lock
|
||||||
}
|
}
|
||||||
|
|
||||||
__forceinline bool Pop(u32& res)
|
__forceinline bool Pop(u32& res)
|
||||||
{
|
{
|
||||||
if(!m_index) return false;
|
if (max_count > 1 || x86)
|
||||||
res = m_value[--m_index];
|
{
|
||||||
return true;
|
while (_InterlockedExchange(&m_lock, 1));
|
||||||
|
_mm_lfence();
|
||||||
|
if(!m_index)
|
||||||
|
{
|
||||||
|
m_lock = 0; //release lock
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
res = m_value[--m_index];
|
||||||
|
m_value[m_index] = 0;
|
||||||
|
_mm_sfence();
|
||||||
|
m_lock = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ //lock-free
|
||||||
|
if(!m_index)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = (m_indval >> 32);
|
||||||
|
m_indval = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__forceinline bool Push(u32 value)
|
__forceinline bool Push(u32 value)
|
||||||
{
|
{
|
||||||
if(m_index >= max_count) return false;
|
if (max_count > 1 || x86)
|
||||||
m_value[m_index++] = value;
|
{
|
||||||
return true;
|
while (_InterlockedExchange(&m_lock, 1));
|
||||||
|
_mm_lfence();
|
||||||
|
if(m_index >= max_count)
|
||||||
|
{
|
||||||
|
m_lock = 0; //release lock
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_value[m_index++] = value;
|
||||||
|
_mm_sfence();
|
||||||
|
m_lock = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ //lock-free
|
||||||
|
if(m_index)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_indval = ((u64)value << 32) | 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline void PushUncond(u32 value)
|
||||||
|
{
|
||||||
|
if (max_count > 1 || x86)
|
||||||
|
{
|
||||||
|
while (_InterlockedExchange(&m_lock, 1));
|
||||||
|
_mm_lfence();
|
||||||
|
if(m_index >= max_count)
|
||||||
|
m_value[max_count-1] = value; //last message is overwritten
|
||||||
|
else
|
||||||
|
m_value[m_index++] = value;
|
||||||
|
_mm_sfence();
|
||||||
|
m_lock = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ //lock-free
|
||||||
|
m_indval = ((u64)value << 32) | 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline void PushUncond_OR(u32 value)
|
||||||
|
{
|
||||||
|
if (max_count > 1 || x86)
|
||||||
|
{
|
||||||
|
while (_InterlockedExchange(&m_lock, 1));
|
||||||
|
_mm_lfence();
|
||||||
|
if(m_index >= max_count)
|
||||||
|
m_value[max_count-1] |= value; //last message is logically ORed
|
||||||
|
else
|
||||||
|
m_value[m_index++] = value;
|
||||||
|
_mm_sfence();
|
||||||
|
m_lock = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef _M_X64
|
||||||
|
_InterlockedOr64((volatile __int64*)m_indval, ((u64)value << 32) | 1);
|
||||||
|
#else
|
||||||
|
ConLog.Error("PushUncond_OR(): no code compiled");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__forceinline void PopUncond(u32& res)
|
||||||
|
{
|
||||||
|
if (max_count > 1 || x86)
|
||||||
|
{
|
||||||
|
while (_InterlockedExchange(&m_lock, 1));
|
||||||
|
_mm_lfence();
|
||||||
|
if(!m_index)
|
||||||
|
res = 0; //result is undefined
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = m_value[--m_index];
|
||||||
|
m_value[m_index] = 0;
|
||||||
|
}
|
||||||
|
_mm_sfence();
|
||||||
|
m_lock = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ //lock-free
|
||||||
|
if(!m_index)
|
||||||
|
res = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = (m_indval >> 32);
|
||||||
|
m_indval = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GetCount() const
|
u32 GetCount() const
|
||||||
{
|
{
|
||||||
|
if (max_count > 1 || x86)
|
||||||
|
{
|
||||||
|
while (m_lock);
|
||||||
|
_mm_lfence();
|
||||||
|
}
|
||||||
return m_index;
|
return m_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GetFreeCount() const
|
u32 GetFreeCount() const
|
||||||
{
|
{
|
||||||
|
if (max_count > 1 || x86)
|
||||||
|
{
|
||||||
|
while (m_lock);
|
||||||
|
_mm_lfence();
|
||||||
|
}
|
||||||
return max_count - m_index;
|
return max_count - m_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,7 +467,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct
|
struct MFCReg
|
||||||
{
|
{
|
||||||
Channel<1> LSA;
|
Channel<1> LSA;
|
||||||
Channel<1> EAH;
|
Channel<1> EAH;
|
||||||
@ -321,7 +475,7 @@ public:
|
|||||||
Channel<1> Size_Tag;
|
Channel<1> Size_Tag;
|
||||||
Channel<1> CMDStatus;
|
Channel<1> CMDStatus;
|
||||||
Channel<1> QStatus;
|
Channel<1> QStatus;
|
||||||
} MFC;
|
} MFC1, MFC2;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
@ -339,8 +493,7 @@ public:
|
|||||||
Channel<1> RunCntl;
|
Channel<1> RunCntl;
|
||||||
Channel<1> Status;
|
Channel<1> Status;
|
||||||
Channel<1> NPC;
|
Channel<1> NPC;
|
||||||
Channel<1> RdSigNotify1;
|
Channel<1> SNR[2];
|
||||||
Channel<1> RdSigNotify2;
|
|
||||||
} SPU;
|
} SPU;
|
||||||
|
|
||||||
u32 LSA;
|
u32 LSA;
|
||||||
@ -353,36 +506,34 @@ public:
|
|||||||
|
|
||||||
DMAC dmac;
|
DMAC dmac;
|
||||||
|
|
||||||
void DoMfcCmd()
|
void EnqMfcCmd(MFCReg& MFCArgs)
|
||||||
{
|
{
|
||||||
u32 cmd = MFC.CMDStatus.GetValue();
|
u32 cmd = MFCArgs.CMDStatus.GetValue();
|
||||||
u16 op = cmd & MFC_MASK_CMD;
|
u16 op = cmd & MFC_MASK_CMD;
|
||||||
|
|
||||||
switch(op & (MFC_PUT_CMD | MFC_GET_CMD))
|
u32 lsa = MFCArgs.LSA.GetValue();
|
||||||
|
u64 ea = (u64)MFCArgs.EAL.GetValue() | ((u64)MFCArgs.EAH.GetValue() << 32);
|
||||||
|
u32 size_tag = MFCArgs.Size_Tag.GetValue();
|
||||||
|
u16 tag = (u16)size_tag;
|
||||||
|
u16 size = size_tag >> 16;
|
||||||
|
|
||||||
|
switch(op & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK))
|
||||||
{
|
{
|
||||||
case MFC_PUT_CMD:
|
case MFC_PUT_CMD:
|
||||||
case MFC_GET_CMD:
|
case MFC_GET_CMD:
|
||||||
{
|
{
|
||||||
u32 lsa = MFC.LSA.GetValue();
|
/* ConLog.Warning("DMA %s%s%s: lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x",
|
||||||
u64 ea = (u64)MFC.EAL.GetValue() | ((u64)MFC.EAH.GetValue() << 32);
|
op & MFC_PUT_CMD ? "PUT" : "GET",
|
||||||
u32 size_tag = MFC.Size_Tag.GetValue();
|
op & MFC_BARRIER_MASK ? "B" : "",
|
||||||
u16 tag = (u16)size_tag;
|
op & MFC_FENCE_MASK ? "F" : "",
|
||||||
u16 size = size_tag >> 16;
|
lsa, ea, tag, size, cmd); */
|
||||||
|
MFCArgs.CMDStatus.SetValue(dmac.Cmd(cmd, tag, lsa, ea, size));
|
||||||
ConLog.Warning("DMA %s:", op & MFC_PUT_CMD ? "PUT" : "GET");
|
|
||||||
ConLog.Warning("*** lsa = 0x%x", lsa);
|
|
||||||
ConLog.Warning("*** ea = 0x%llx", ea);
|
|
||||||
ConLog.Warning("*** tag = 0x%x", tag);
|
|
||||||
ConLog.Warning("*** size = 0x%x", size);
|
|
||||||
ConLog.Warning("*** cmd = 0x%x", cmd);
|
|
||||||
ConLog.SkipLn();
|
|
||||||
|
|
||||||
MFC.CMDStatus.SetValue(dmac.Cmd(cmd, tag, lsa, ea, size));
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ConLog.Error("Unknown MFC cmd. (opcode=0x%x, cmd=0x%x)", op, cmd);
|
ConLog.Error("Unknown MFC cmd. (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)",
|
||||||
|
op, cmd, lsa, ea, tag, size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -391,34 +542,6 @@ public:
|
|||||||
{
|
{
|
||||||
switch(ch)
|
switch(ch)
|
||||||
{
|
{
|
||||||
case SPU_RdEventStat: //Read event status with mask applied
|
|
||||||
case SPU_WrEventMask: //Write event mask
|
|
||||||
case SPU_WrEventAck: //Write end of event processing
|
|
||||||
case SPU_RdSigNotify1: //Signal notification 1
|
|
||||||
case SPU_RdSigNotify2: //Signal notification 2
|
|
||||||
case SPU_WrDec: //Write decrementer count
|
|
||||||
case SPU_RdDec: //Read decrementer count
|
|
||||||
case SPU_RdEventMask: //Read event mask
|
|
||||||
case SPU_RdMachStat: //Read SPU run status
|
|
||||||
case SPU_WrSRR0: //Write SPU machine state save/restore register 0 (SRR0)
|
|
||||||
case SPU_RdSRR0: //Read SPU machine state save/restore register 0 (SRR0)
|
|
||||||
case MFC_WrMSSyncReq: //Write multisource synchronization request
|
|
||||||
case MFC_RdTagMask: //Read tag mask
|
|
||||||
case MFC_LSA: //Write local memory address command parameter
|
|
||||||
case MFC_EAH: //Write high order DMA effective address command parameter
|
|
||||||
case MFC_EAL: //Write low order DMA effective address command parameter
|
|
||||||
case MFC_Size: //Write DMA transfer size command parameter
|
|
||||||
case MFC_TagID: //Write tag identifier command parameter
|
|
||||||
case MFC_Cmd: //Write and enqueue DMA command with associated class ID
|
|
||||||
case MFC_WrTagMask: //Write tag mask
|
|
||||||
case MFC_WrTagUpdate: //Write request for conditional or unconditional tag status update
|
|
||||||
case MFC_RdTagStat: //Read tag status with mask applied
|
|
||||||
case MFC_RdListStallStat: //Read DMA list stall-and-notify status
|
|
||||||
case MFC_WrListStallAck: //Write DMA list stall-and-notify acknowledge
|
|
||||||
case MFC_RdAtomicStat: //Read completion status of last completed immediate MFC atomic update command
|
|
||||||
ConLog.Error("%s error: unimplemented channel (%s).", __FUNCTION__, spu_ch_name[ch]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SPU_WrOutMbox:
|
case SPU_WrOutMbox:
|
||||||
return SPU.Out_MBox.GetFreeCount();
|
return SPU.Out_MBox.GetFreeCount();
|
||||||
|
|
||||||
@ -426,8 +549,18 @@ public:
|
|||||||
return SPU.In_MBox.GetCount();
|
return SPU.In_MBox.GetCount();
|
||||||
|
|
||||||
case SPU_WrOutIntrMbox:
|
case SPU_WrOutIntrMbox:
|
||||||
|
ConLog.Warning("GetChannelCount(%s) = 0", spu_ch_name[ch]);
|
||||||
return 0;//return SPU.OutIntr_Mbox.GetFreeCount();
|
return 0;//return SPU.OutIntr_Mbox.GetFreeCount();
|
||||||
|
|
||||||
|
case MFC_RdTagStat:
|
||||||
|
return Prxy.TagStatus.GetCount();
|
||||||
|
|
||||||
|
case SPU_RdSigNotify1:
|
||||||
|
return SPU.SNR[0].GetCount();
|
||||||
|
|
||||||
|
case SPU_RdSigNotify2:
|
||||||
|
return SPU.SNR[1].GetCount();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ConLog.Error("%s error: unknown/illegal channel (%d [%s]).", __FUNCTION__, ch, spu_ch_name[ch]);
|
ConLog.Error("%s error: unknown/illegal channel (%d [%s]).", __FUNCTION__, ch, spu_ch_name[ch]);
|
||||||
break;
|
break;
|
||||||
@ -440,55 +573,51 @@ public:
|
|||||||
{
|
{
|
||||||
const u32 v = r._u32[3];
|
const u32 v = r._u32[3];
|
||||||
|
|
||||||
ConLog.Warning("%s: %s = 0x%x", __FUNCTION__, spu_ch_name[ch], v);
|
|
||||||
|
|
||||||
switch(ch)
|
switch(ch)
|
||||||
{
|
{
|
||||||
case SPU_WrOutIntrMbox:
|
case SPU_WrOutIntrMbox:
|
||||||
while(!SPU.OutIntr_Mbox.Push(v) && !Emu.IsStopped())
|
ConLog.Warning("%s: %s = 0x%x", __FUNCTION__, spu_ch_name[ch], v);
|
||||||
{
|
while (!SPU.OutIntr_Mbox.Push(v) && !Emu.IsStopped()) Sleep(1);
|
||||||
Sleep(1);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPU_WrOutMbox:
|
case SPU_WrOutMbox:
|
||||||
while(!SPU.Out_MBox.Push(v) && !Emu.IsStopped())
|
ConLog.Warning("%s: %s = 0x%x", __FUNCTION__, spu_ch_name[ch], v);
|
||||||
{
|
while (!SPU.Out_MBox.Push(v) && !Emu.IsStopped()) Sleep(1);
|
||||||
Sleep(1);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MFC_WrTagMask:
|
case MFC_WrTagMask:
|
||||||
|
//ConLog.Warning("%s: %s = 0x%x", __FUNCTION__, spu_ch_name[ch], v);
|
||||||
Prxy.QueryMask.SetValue(v);
|
Prxy.QueryMask.SetValue(v);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MFC_WrTagUpdate:
|
case MFC_WrTagUpdate:
|
||||||
Prxy.TagStatus.SetValue(Prxy.QueryMask.GetValue());
|
//ConLog.Warning("%s: %s = 0x%x", __FUNCTION__, spu_ch_name[ch], v);
|
||||||
|
Prxy.TagStatus.PushUncond(Prxy.QueryMask.GetValue());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MFC_LSA:
|
case MFC_LSA:
|
||||||
MFC.LSA.SetValue(v);
|
MFC1.LSA.SetValue(v);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MFC_EAH:
|
case MFC_EAH:
|
||||||
MFC.EAH.SetValue(v);
|
MFC1.EAH.SetValue(v);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MFC_EAL:
|
case MFC_EAL:
|
||||||
MFC.EAL.SetValue(v);
|
MFC1.EAL.SetValue(v);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MFC_Size:
|
case MFC_Size:
|
||||||
MFC.Size_Tag.SetValue((MFC.Size_Tag.GetValue() & 0xffff) | (v << 16));
|
MFC1.Size_Tag.SetValue((MFC1.Size_Tag.GetValue() & 0xffff) | (v << 16));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MFC_TagID:
|
case MFC_TagID:
|
||||||
MFC.Size_Tag.SetValue((MFC.Size_Tag.GetValue() & ~0xffff) | (v & 0xffff));
|
MFC1.Size_Tag.SetValue((MFC1.Size_Tag.GetValue() & ~0xffff) | (v & 0xffff));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MFC_Cmd:
|
case MFC_Cmd:
|
||||||
MFC.CMDStatus.SetValue(v);
|
MFC1.CMDStatus.SetValue(v);
|
||||||
DoMfcCmd();
|
EnqMfcCmd(MFC1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -505,19 +634,29 @@ public:
|
|||||||
switch(ch)
|
switch(ch)
|
||||||
{
|
{
|
||||||
case SPU_RdInMbox:
|
case SPU_RdInMbox:
|
||||||
if(!SPU.In_MBox.Pop(v)) v = 0;
|
while (!SPU.In_MBox.Pop(v) && !Emu.IsStopped()) Sleep(1);
|
||||||
|
ConLog.Warning("%s: 0x%x = %s", __FUNCTION__, v, spu_ch_name[ch]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MFC_RdTagStat:
|
case MFC_RdTagStat:
|
||||||
v = Prxy.TagStatus.GetValue();
|
while (!Prxy.TagStatus.Pop(v) && !Emu.IsStopped()) Sleep(1);
|
||||||
|
//ConLog.Warning("%s: 0x%x = %s", __FUNCTION__, v, spu_ch_name[ch]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SPU_RdSigNotify1:
|
||||||
|
while (!SPU.SNR[0].Pop(v) && !Emu.IsStopped()) Sleep(1);
|
||||||
|
//ConLog.Warning("%s: 0x%x = %s", __FUNCTION__, v, spu_ch_name[ch]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SPU_RdSigNotify2:
|
||||||
|
while (!SPU.SNR[1].Pop(v) && !Emu.IsStopped()) Sleep(1);
|
||||||
|
//ConLog.Warning("%s: 0x%x = %s", __FUNCTION__, v, spu_ch_name[ch]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ConLog.Error("%s error: unknown/illegal channel (%d [%s]).", __FUNCTION__, ch, spu_ch_name[ch]);
|
ConLog.Error("%s error: unknown/illegal channel (%d [%s]).", __FUNCTION__, ch, spu_ch_name[ch]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConLog.Warning("%s: 0x%x = %s", __FUNCTION__, v, spu_ch_name[ch]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsGoodLSA(const u32 lsa) const { return Memory.IsGoodAddr(lsa + m_offset) && lsa < 0x40000; }
|
bool IsGoodLSA(const u32 lsa) const { return Memory.IsGoodAddr(lsa + m_offset) && lsa < 0x40000; }
|
||||||
|
@ -30,7 +30,11 @@ u32 vfsDevice::CmpPs3Path(const wxString& ps3_path)
|
|||||||
|
|
||||||
for(u32 i=0; i<lim; ++i, ++ret)
|
for(u32 i=0; i<lim; ++i, ++ret)
|
||||||
{
|
{
|
||||||
if(m_ps3_path[i] != ps3_path[i]) break;
|
if(m_ps3_path[i] != ps3_path[i])
|
||||||
|
{
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "Emu/SysCalls/SysCalls.h"
|
#include "Emu/SysCalls/SysCalls.h"
|
||||||
#include "Emu/SysCalls/SC_FUNC.h"
|
#include "Emu/SysCalls/SC_FUNC.h"
|
||||||
|
#include "Emu/SysCalls/lv2/SC_SPU_Thread.h"
|
||||||
|
#include "Loader/ELF.h"
|
||||||
|
#include "Emu/Cell/RawSPUThread.h"
|
||||||
|
|
||||||
void sysPrxForUser_init();
|
void sysPrxForUser_init();
|
||||||
Module sysPrxForUser("sysPrxForUser", sysPrxForUser_init);
|
Module sysPrxForUser("sysPrxForUser", sysPrxForUser_init);
|
||||||
@ -13,13 +16,13 @@ void sys_initialize_tls()
|
|||||||
s64 sys_process_atexitspawn()
|
s64 sys_process_atexitspawn()
|
||||||
{
|
{
|
||||||
sysPrxForUser.Log("sys_process_atexitspawn()");
|
sysPrxForUser.Log("sys_process_atexitspawn()");
|
||||||
return 0;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 sys_process_at_Exitspawn()
|
s64 sys_process_at_Exitspawn()
|
||||||
{
|
{
|
||||||
sysPrxForUser.Log("sys_process_at_Exitspawn");
|
sysPrxForUser.Log("sys_process_at_Exitspawn");
|
||||||
return 0;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sys_process_is_stack(u32 p)
|
int sys_process_is_stack(u32 p)
|
||||||
@ -34,19 +37,19 @@ int sys_process_is_stack(u32 p)
|
|||||||
int sys_spu_printf_initialize(int a1, int a2, int a3, int a4, int a5)
|
int sys_spu_printf_initialize(int a1, int a2, int a3, int a4, int a5)
|
||||||
{
|
{
|
||||||
sysPrxForUser.Warning("sys_spu_printf_initialize(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)", a1, a2, a3, a4, a5);
|
sysPrxForUser.Warning("sys_spu_printf_initialize(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)", a1, a2, a3, a4, a5);
|
||||||
return 0;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 sys_prx_register_library(u32 lib_addr)
|
s64 sys_prx_register_library(u32 lib_addr)
|
||||||
{
|
{
|
||||||
sysPrxForUser.Error("sys_prx_register_library(lib_addr=0x%x)", lib_addr);
|
sysPrxForUser.Error("sys_prx_register_library(lib_addr=0x%x)", lib_addr);
|
||||||
return 0;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 sys_prx_exitspawn_with_level()
|
s64 sys_prx_exitspawn_with_level()
|
||||||
{
|
{
|
||||||
sysPrxForUser.Log("sys_prx_exitspawn_with_level()");
|
sysPrxForUser.Log("sys_prx_exitspawn_with_level()");
|
||||||
return 0;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 sys_strlen(u32 addr)
|
s64 sys_strlen(u32 addr)
|
||||||
@ -56,6 +59,73 @@ s64 sys_strlen(u32 addr)
|
|||||||
return str.Len();
|
return str.Len();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sys_spu_elf_get_information(u32 elf_img, mem32_t entry, mem32_t nseg)
|
||||||
|
{
|
||||||
|
sysPrxForUser.Warning("sys_spu_elf_get_information(elf_img=0x%x, entry_addr=0x%x, nseg_addr=0x%x", elf_img, entry.GetAddr(), nseg.GetAddr());
|
||||||
|
return CELL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sys_spu_elf_get_segments(u32 elf_img, mem_ptr_t<sys_spu_segment> segments, int nseg)
|
||||||
|
{
|
||||||
|
sysPrxForUser.Warning("sys_spu_elf_get_segments(elf_img=0x%x, segments_addr=0x%x, nseg=0x%x)", elf_img, segments.GetAddr(), nseg);
|
||||||
|
return CELL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sys_spu_image_import(mem_ptr_t<sys_spu_image> img, u32 src, u32 type)
|
||||||
|
{
|
||||||
|
sysPrxForUser.Warning("sys_spu_image_import(img=0x%x, src=0x%x, type=0x%x)", img.GetAddr(), src, type);
|
||||||
|
|
||||||
|
if(!img.IsGood() || !Memory.IsGoodAddr(src))
|
||||||
|
{
|
||||||
|
return CELL_EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
vfsStreamMemory f(src);
|
||||||
|
u32 entry = LoadSpuImage(f);
|
||||||
|
|
||||||
|
img->type = 1;
|
||||||
|
img->entry_point = entry;
|
||||||
|
img->segs_addr = 0x0;
|
||||||
|
img->nsegs = 0;
|
||||||
|
|
||||||
|
return CELL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sys_raw_spu_load(int id, u32 path_addr, mem32_t entry)
|
||||||
|
{
|
||||||
|
const wxString path = Memory.ReadString(path_addr).mb_str();
|
||||||
|
sysPrxForUser.Warning("sys_raw_spu_load(id=0x%x, path=0x%x [%s], entry_addr=0x%x)",
|
||||||
|
id, path_addr, path, entry.GetAddr());
|
||||||
|
|
||||||
|
vfsFile f(path.c_str());
|
||||||
|
if(!f.IsOpened())
|
||||||
|
{
|
||||||
|
sysPrxForUser.Error("sys_raw_spu_load error: '%s' not found!", path);
|
||||||
|
return CELL_ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ELFLoader l(f);
|
||||||
|
l.LoadInfo();
|
||||||
|
l.LoadData(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id);
|
||||||
|
|
||||||
|
entry = l.GetEntry();
|
||||||
|
|
||||||
|
return CELL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern u64 g_last_spu_offset;
|
||||||
|
|
||||||
|
int sys_raw_spu_image_load(int id, mem_ptr_t<sys_spu_image> img)
|
||||||
|
{
|
||||||
|
sysPrxForUser.Warning("sys_raw_spu_image_load(id=0x%x, img_addr=0x%x)", id, img.GetAddr());
|
||||||
|
|
||||||
|
memcpy(Memory + RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id, Memory + g_last_spu_offset, 256 * 1024);
|
||||||
|
Memory.Write32(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id + RAW_SPU_PROB_OFFSET + SPU_NPC_offs,
|
||||||
|
img->entry_point - g_last_spu_offset);
|
||||||
|
|
||||||
|
return CELL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
void sysPrxForUser_init()
|
void sysPrxForUser_init()
|
||||||
{
|
{
|
||||||
sysPrxForUser.AddFunc(0x744680a2, sys_initialize_tls);
|
sysPrxForUser.AddFunc(0x744680a2, sys_initialize_tls);
|
||||||
@ -92,4 +162,11 @@ void sysPrxForUser_init()
|
|||||||
|
|
||||||
sysPrxForUser.AddFunc(0xb257540b, sys_mmapper_allocate_memory);
|
sysPrxForUser.AddFunc(0xb257540b, sys_mmapper_allocate_memory);
|
||||||
sysPrxForUser.AddFunc(0xdc578057, sys_mmapper_map_memory);
|
sysPrxForUser.AddFunc(0xdc578057, sys_mmapper_map_memory);
|
||||||
|
|
||||||
|
sysPrxForUser.AddFunc(0x1ed454ce, sys_spu_elf_get_information);
|
||||||
|
sysPrxForUser.AddFunc(0xdb6b3250, sys_spu_elf_get_segments);
|
||||||
|
sysPrxForUser.AddFunc(0xebe5f72f, sys_spu_image_import);
|
||||||
|
|
||||||
|
sysPrxForUser.AddFunc(0x893305fa, sys_raw_spu_load);
|
||||||
|
sysPrxForUser.AddFunc(0xb995662e, sys_raw_spu_image_load);
|
||||||
}
|
}
|
||||||
|
@ -97,8 +97,8 @@ static func_caller* sc_table[1024] =
|
|||||||
null_func, null_func, null_func, null_func, bind_func(sys_spu_initialize), //169
|
null_func, null_func, null_func, null_func, bind_func(sys_spu_initialize), //169
|
||||||
bind_func(sys_spu_thread_group_create), bind_func(sys_spu_thread_set_argument), bind_func(sys_spu_thread_initialize), bind_func(sys_spu_thread_group_start), null_func, //174
|
bind_func(sys_spu_thread_group_create), bind_func(sys_spu_thread_set_argument), bind_func(sys_spu_thread_initialize), bind_func(sys_spu_thread_group_start), null_func, //174
|
||||||
null_func, null_func, null_func, null_func, null_func, //179
|
null_func, null_func, null_func, null_func, null_func, //179
|
||||||
null_func, bind_func(sys_spu_thread_write_ls), bind_func(sys_spu_thread_read_ls), null_func, null_func, //184
|
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
|
||||||
null_func, null_func, null_func, null_func, null_func, //189
|
null_func, null_func, bind_func(sys_spu_thread_set_spu_cfg), bind_func(sys_spu_thread_get_spu_cfg), null_func, //189
|
||||||
bind_func(sys_spu_thread_write_spu_mb), bind_func(sys_spu_thread_connect_event), null_func, null_func, null_func, //194
|
bind_func(sys_spu_thread_write_spu_mb), bind_func(sys_spu_thread_connect_event), null_func, null_func, null_func, //194
|
||||||
null_func, null_func, null_func, null_func, null_func, //199
|
null_func, null_func, null_func, null_func, null_func, //199
|
||||||
null_func, null_func, null_func, null_func, null_func, //204
|
null_func, null_func, null_func, null_func, null_func, //204
|
||||||
|
@ -291,6 +291,9 @@ extern int sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu);
|
|||||||
extern int sys_spu_thread_write_ls(u32 id, u32 address, u64 value, u32 type);
|
extern int sys_spu_thread_write_ls(u32 id, u32 address, u64 value, u32 type);
|
||||||
extern int sys_spu_thread_read_ls(u32 id, u32 address, mem64_t value, u32 type);
|
extern int sys_spu_thread_read_ls(u32 id, u32 address, mem64_t value, u32 type);
|
||||||
extern int sys_spu_thread_write_spu_mb(u32 id, u32 value);
|
extern int sys_spu_thread_write_spu_mb(u32 id, u32 value);
|
||||||
|
extern int sys_spu_thread_set_spu_cfg(u32 id, u64 value);
|
||||||
|
extern int sys_spu_thread_get_spu_cfg(u32 id, mem64_t value);
|
||||||
|
extern int sys_spu_thread_write_snr(u32 id, u32 number, u32 value);
|
||||||
|
|
||||||
//sys_time
|
//sys_time
|
||||||
extern int sys_time_get_timezone(mem32_t timezone, mem32_t summertime);
|
extern int sys_time_get_timezone(mem32_t timezone, mem32_t summertime);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "SC_SPU_Thread.h"
|
#include "SC_SPU_Thread.h"
|
||||||
#include "Emu/SysCalls/SysCalls.h"
|
#include "Emu/SysCalls/SysCalls.h"
|
||||||
|
#include "Emu/SysCalls/SC_FUNC.h"
|
||||||
#include "Loader/ELF.h"
|
#include "Loader/ELF.h"
|
||||||
#include "Emu/Cell/RawSPUThread.h"
|
#include "Emu/Cell/RawSPUThread.h"
|
||||||
|
|
||||||
@ -20,22 +21,23 @@ struct SpuGroupInfo
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
u64 g_spu_offset = 0;
|
u64 g_last_spu_offset = 0;
|
||||||
|
|
||||||
u32 LoadSpuImage(vfsStream& stream)
|
u32 LoadSpuImage(vfsStream& stream)
|
||||||
{
|
{
|
||||||
ELFLoader l(stream);
|
ELFLoader l(stream);
|
||||||
l.LoadInfo();
|
l.LoadInfo();
|
||||||
g_spu_offset = Memory.MainMem.Alloc(0xFFFFED - stream.GetSize());
|
u32 alloc_size = 0xFFFFED - stream.GetSize();
|
||||||
l.LoadData(g_spu_offset);
|
g_last_spu_offset = Memory.MainMem.Alloc(alloc_size);
|
||||||
|
l.LoadData(g_last_spu_offset);
|
||||||
|
|
||||||
return g_spu_offset + l.GetEntry();
|
return g_last_spu_offset + l.GetEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
//156
|
//156
|
||||||
int sys_spu_image_open(mem_ptr_t<sys_spu_image> img, u32 path_addr)
|
int sys_spu_image_open(mem_ptr_t<sys_spu_image> img, u32 path_addr)
|
||||||
{
|
{
|
||||||
const std::string& path = Memory.ReadString(path_addr).mb_str();
|
const wxString path = Memory.ReadString(path_addr).mb_str();
|
||||||
sc_spu.Warning("sys_spu_image_open(img_addr=0x%x, path_addr=0x%x [%s])", img.GetAddr(), path_addr, path);
|
sc_spu.Warning("sys_spu_image_open(img_addr=0x%x, path_addr=0x%x [%s])", img.GetAddr(), path_addr, path);
|
||||||
|
|
||||||
if(!img.IsGood() || !Memory.IsGoodAddr(path_addr))
|
if(!img.IsGood() || !Memory.IsGoodAddr(path_addr))
|
||||||
@ -93,37 +95,41 @@ int sys_spu_thread_initialize(mem32_t thread, u32 group, u32 spu_num, mem_ptr_t<
|
|||||||
return CELL_EBUSY;
|
return CELL_EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 entry = img->entry_point;
|
u32 ls_entry = img->entry_point - g_last_spu_offset;
|
||||||
std::string name = Memory.ReadString(attr->name_addr, attr->name_len).mb_str();
|
std::string name = Memory.ReadString(attr->name_addr, attr->name_len).mb_str();
|
||||||
u64 a1 = arg->arg1;
|
u64 a1 = arg->arg1;
|
||||||
u64 a2 = arg->arg2;
|
u64 a2 = arg->arg2;
|
||||||
u64 a3 = arg->arg3;
|
u64 a3 = arg->arg3;
|
||||||
u64 a4 = arg->arg4;
|
u64 a4 = arg->arg4;
|
||||||
|
|
||||||
ConLog.Write("New SPU Thread:");
|
|
||||||
ConLog.Write("entry = 0x%x", entry);
|
|
||||||
ConLog.Write("name = %s", name);
|
|
||||||
ConLog.Write("a1 = 0x%x", a1);
|
|
||||||
ConLog.Write("a2 = 0x%x", a2);
|
|
||||||
ConLog.Write("a3 = 0x%x", a3);
|
|
||||||
ConLog.Write("a4 = 0x%x", a4);
|
|
||||||
ConLog.SkipLn();
|
|
||||||
|
|
||||||
CPUThread& new_thread = Emu.GetCPU().AddThread(CPU_THREAD_SPU);
|
CPUThread& new_thread = Emu.GetCPU().AddThread(CPU_THREAD_SPU);
|
||||||
new_thread.SetOffset(g_spu_offset);
|
//copy SPU image:
|
||||||
new_thread.SetEntry(entry - g_spu_offset);
|
u32 spu_offset = Memory.MainMem.Alloc(256 * 1024);
|
||||||
|
memcpy(Memory + spu_offset, Memory + g_last_spu_offset, 256 * 1024);
|
||||||
|
//initialize from new place:
|
||||||
|
new_thread.SetOffset(spu_offset);
|
||||||
|
new_thread.SetEntry(ls_entry);
|
||||||
new_thread.SetName(name);
|
new_thread.SetName(name);
|
||||||
new_thread.Run();
|
|
||||||
new_thread.Pause();
|
|
||||||
new_thread.SetArg(0, a1);
|
new_thread.SetArg(0, a1);
|
||||||
new_thread.SetArg(1, a2);
|
new_thread.SetArg(1, a2);
|
||||||
new_thread.SetArg(2, a3);
|
new_thread.SetArg(2, a3);
|
||||||
new_thread.SetArg(3, a4);
|
new_thread.SetArg(3, a4);
|
||||||
|
new_thread.Run();
|
||||||
|
|
||||||
thread = new_thread.GetId();
|
thread = new_thread.GetId();
|
||||||
|
|
||||||
group_info.threads[spu_num] = &new_thread;
|
group_info.threads[spu_num] = &new_thread;
|
||||||
|
|
||||||
|
ConLog.Write("New SPU Thread:");
|
||||||
|
ConLog.Write("ls_entry = 0x%x", ls_entry);
|
||||||
|
ConLog.Write("name = %s", wxString(name));
|
||||||
|
ConLog.Write("a1 = 0x%x", a1);
|
||||||
|
ConLog.Write("a2 = 0x%x", a2);
|
||||||
|
ConLog.Write("a3 = 0x%x", a3);
|
||||||
|
ConLog.Write("a4 = 0x%x", a4);
|
||||||
|
ConLog.Write("ls_offset = 0x%x", ((SPUThread&)new_thread).dmac.ls_offset);
|
||||||
|
ConLog.SkipLn();
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,7 +170,7 @@ int sys_spu_thread_group_start(u32 id)
|
|||||||
ID& id_data = Emu.GetIdManager().GetIDData(id);
|
ID& id_data = Emu.GetIdManager().GetIDData(id);
|
||||||
SpuGroupInfo& group_info = *(SpuGroupInfo*)id_data.m_data;
|
SpuGroupInfo& group_info = *(SpuGroupInfo*)id_data.m_data;
|
||||||
|
|
||||||
Emu.Pause();
|
//Emu.Pause();
|
||||||
for(int i=0; i<g_spu_group_thr_count; i++)
|
for(int i=0; i<g_spu_group_thr_count; i++)
|
||||||
{
|
{
|
||||||
if(group_info.threads[i])
|
if(group_info.threads[i])
|
||||||
@ -190,7 +196,7 @@ int sys_spu_thread_group_create(mem32_t id, u32 num, int prio, mem_ptr_t<sys_spu
|
|||||||
ConLog.Write("*** attr.type=%d", attr->type.ToLE());
|
ConLog.Write("*** attr.type=%d", attr->type.ToLE());
|
||||||
ConLog.Write("*** attr.option.ct=%d", attr->option.ct.ToLE());
|
ConLog.Write("*** attr.option.ct=%d", attr->option.ct.ToLE());
|
||||||
|
|
||||||
const std::string& name = Memory.ReadString(attr->name_addr, attr->name_len).mb_str();
|
const wxString name = Memory.ReadString(attr->name_addr, attr->name_len).mb_str();
|
||||||
ConLog.Write("*** name='%s'", name);
|
ConLog.Write("*** name='%s'", name);
|
||||||
|
|
||||||
id = Emu.GetIdManager().GetNewID(wxString::Format("sys_spu_thread_group '%s'", name), new SpuGroupInfo(*attr));
|
id = Emu.GetIdManager().GetNewID(wxString::Format("sys_spu_thread_group '%s'", name), new SpuGroupInfo(*attr));
|
||||||
@ -335,6 +341,72 @@ int sys_spu_thread_write_spu_mb(u32 id, u32 value)
|
|||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//187
|
||||||
|
int sys_spu_thread_set_spu_cfg(u32 id, u64 value)
|
||||||
|
{
|
||||||
|
sc_spu.Warning("sys_spu_thread_set_spu_cfg(id=0x%x, value=0x%x)", id, value);
|
||||||
|
|
||||||
|
CPUThread* thr = Emu.GetCPU().GetThread(id);
|
||||||
|
|
||||||
|
if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU))
|
||||||
|
{
|
||||||
|
return CELL_ESRCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value > 3)
|
||||||
|
{
|
||||||
|
return CELL_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*(SPUThread*)thr).cfg.value = value;
|
||||||
|
|
||||||
|
return CELL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
//188
|
||||||
|
int sys_spu_thread_get_spu_cfg(u32 id, mem64_t value)
|
||||||
|
{
|
||||||
|
sc_spu.Warning("sys_spu_thread_get_spu_cfg(id=0x%x, value_addr=0x%x)", id, value.GetAddr());
|
||||||
|
|
||||||
|
CPUThread* thr = Emu.GetCPU().GetThread(id);
|
||||||
|
|
||||||
|
if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU))
|
||||||
|
{
|
||||||
|
return CELL_ESRCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = (*(SPUThread*)thr).cfg.value;
|
||||||
|
|
||||||
|
return CELL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
//184
|
||||||
|
int sys_spu_thread_write_snr(u32 id, u32 number, u32 value)
|
||||||
|
{
|
||||||
|
CPUThread* thr = Emu.GetCPU().GetThread(id);
|
||||||
|
|
||||||
|
if(!thr || (thr->GetType() != CPU_THREAD_SPU && thr->GetType() != CPU_THREAD_RAW_SPU))
|
||||||
|
{
|
||||||
|
return CELL_ESRCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (number > 1)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CELL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
int sys_spu_thread_group_connect_event_all_threads(u32 id, u32 eq, u64 req, u32 spup_addr)
|
int sys_spu_thread_group_connect_event_all_threads(u32 id, u32 eq, u64 req, u32 spup_addr)
|
||||||
{
|
{
|
||||||
sc_spu.Warning("sys_spu_thread_group_connect_event_all_threads(id=0x%x, eq=0x%x, req=0x%llx, spup_addr=0x%x)",
|
sc_spu.Warning("sys_spu_thread_group_connect_event_all_threads(id=0x%x, eq=0x%x, req=0x%llx, spup_addr=0x%x)",
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
u32 LoadSpuImage(vfsStream& stream);
|
||||||
|
|
||||||
struct sys_spu_thread_group_attribute
|
struct sys_spu_thread_group_attribute
|
||||||
{
|
{
|
||||||
be_t<u32> name_len;
|
be_t<u32> name_len;
|
||||||
@ -30,3 +32,11 @@ struct sys_spu_image
|
|||||||
be_t<u32> segs_addr;
|
be_t<u32> segs_addr;
|
||||||
be_t<int> nsegs;
|
be_t<int> nsegs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct sys_spu_segment
|
||||||
|
{
|
||||||
|
be_t<int> type;
|
||||||
|
be_t<u32> ls_start;
|
||||||
|
be_t<int> size;
|
||||||
|
be_t<u64> src;
|
||||||
|
};
|
||||||
|
@ -354,7 +354,6 @@ void Emulator::Load()
|
|||||||
|
|
||||||
thread.Run();
|
thread.Run();
|
||||||
|
|
||||||
wxCriticalSectionLocker lock(m_cs_status);
|
|
||||||
m_status = Ready;
|
m_status = Ready;
|
||||||
#ifndef QT_UI
|
#ifndef QT_UI
|
||||||
wxGetApp().SendDbgCommand(DID_READY_EMU);
|
wxGetApp().SendDbgCommand(DID_READY_EMU);
|
||||||
@ -379,7 +378,6 @@ void Emulator::Run()
|
|||||||
wxGetApp().SendDbgCommand(DID_START_EMU);
|
wxGetApp().SendDbgCommand(DID_START_EMU);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
wxCriticalSectionLocker lock(m_cs_status);
|
|
||||||
//ConLog.Write("run...");
|
//ConLog.Write("run...");
|
||||||
m_status = Running;
|
m_status = Running;
|
||||||
|
|
||||||
@ -403,7 +401,6 @@ void Emulator::Pause()
|
|||||||
wxGetApp().SendDbgCommand(DID_PAUSE_EMU);
|
wxGetApp().SendDbgCommand(DID_PAUSE_EMU);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
wxCriticalSectionLocker lock(m_cs_status);
|
|
||||||
m_status = Paused;
|
m_status = Paused;
|
||||||
#ifndef QT_UI
|
#ifndef QT_UI
|
||||||
wxGetApp().SendDbgCommand(DID_PAUSED_EMU);
|
wxGetApp().SendDbgCommand(DID_PAUSED_EMU);
|
||||||
@ -418,7 +415,6 @@ void Emulator::Resume()
|
|||||||
wxGetApp().SendDbgCommand(DID_RESUME_EMU);
|
wxGetApp().SendDbgCommand(DID_RESUME_EMU);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
wxCriticalSectionLocker lock(m_cs_status);
|
|
||||||
m_status = Running;
|
m_status = Running;
|
||||||
|
|
||||||
CheckStatus();
|
CheckStatus();
|
||||||
@ -436,10 +432,7 @@ void Emulator::Stop()
|
|||||||
#ifndef QT_UI
|
#ifndef QT_UI
|
||||||
wxGetApp().SendDbgCommand(DID_STOP_EMU);
|
wxGetApp().SendDbgCommand(DID_STOP_EMU);
|
||||||
#endif
|
#endif
|
||||||
{
|
m_status = Stopped;
|
||||||
wxCriticalSectionLocker lock(m_cs_status);
|
|
||||||
m_status = Stopped;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_rsx_callback = 0;
|
m_rsx_callback = 0;
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include "Gui/MemoryViewer.h"
|
#include "Gui/MemoryViewer.h"
|
||||||
#include "Emu/CPU/CPUThreadManager.h"
|
#include "Emu/CPU/CPUThreadManager.h"
|
||||||
#include "Emu/Io/Pad.h"
|
#include "Emu/Io/Pad.h"
|
||||||
@ -64,9 +65,8 @@ class Emulator
|
|||||||
InterpreterDisAsm,
|
InterpreterDisAsm,
|
||||||
Interpreter,
|
Interpreter,
|
||||||
};
|
};
|
||||||
|
|
||||||
mutable wxCriticalSection m_cs_status;
|
volatile uint m_status;
|
||||||
Status m_status;
|
|
||||||
uint m_mode;
|
uint m_mode;
|
||||||
|
|
||||||
u32 m_rsx_callback;
|
u32 m_rsx_callback;
|
||||||
@ -159,10 +159,10 @@ public:
|
|||||||
void SavePoints(const std::string& path);
|
void SavePoints(const std::string& path);
|
||||||
void LoadPoints(const std::string& path);
|
void LoadPoints(const std::string& path);
|
||||||
|
|
||||||
__forceinline bool IsRunning() const { wxCriticalSectionLocker lock(m_cs_status); return m_status == Running; }
|
__forceinline bool IsRunning() const { return m_status == Running; }
|
||||||
__forceinline bool IsPaused() const { wxCriticalSectionLocker lock(m_cs_status); return m_status == Paused; }
|
__forceinline bool IsPaused() const { return m_status == Paused; }
|
||||||
__forceinline bool IsStopped() const { wxCriticalSectionLocker lock(m_cs_status); return m_status == Stopped; }
|
__forceinline bool IsStopped() const { return m_status == Stopped; }
|
||||||
__forceinline bool IsReady() const { wxCriticalSectionLocker lock(m_cs_status); return m_status == Ready; }
|
__forceinline bool IsReady() const { return m_status == Ready; }
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Emulator Emu;
|
extern Emulator Emu;
|
@ -1,6 +1,6 @@
|
|||||||
// This is a generated file.
|
// This is a generated file.
|
||||||
|
|
||||||
#define RPCS3_GIT_VERSION "d83a9b1"
|
#define RPCS3_GIT_VERSION "unknown"
|
||||||
|
|
||||||
// If you don't want this file to update/recompile, change to 1.
|
// If you don't want this file to update/recompile, change to 1.
|
||||||
#define RPCS3_GIT_VERSION_NO_UPDATE 0
|
#define RPCS3_GIT_VERSION_NO_UPDATE 1
|
||||||
|
Loading…
Reference in New Issue
Block a user