Merge pull request #574 from Nekotekina/SРU

SPU Fixes
This commit is contained in:
Hykem 2014-07-17 13:41:15 +01:00
commit a7971b55ee
13 changed files with 267 additions and 318 deletions

2
.gitignore vendored
View File

@ -61,7 +61,7 @@ rpcs3/git-version.h
!/bin/dev_hdd0/game/TEST12345/
# Ignore other system generated files
bin/dev_hdd0/log.txt
bin/dev_hdd0/*.txt
x64/Debug/emucore.lib
x64/Release/emucore.lib

View File

@ -11,7 +11,6 @@
#include "Emu/ARMv7/ARMv7Thread.h"
CPUThreadManager::CPUThreadManager()
: m_raw_spu_num(0)
{
}
@ -22,7 +21,6 @@ CPUThreadManager::~CPUThreadManager()
void CPUThreadManager::Close()
{
m_raw_spu_num = 0;
while(m_threads.size()) RemoveThread(m_threads[0]->GetId());
}
@ -34,10 +32,26 @@ CPUThread& CPUThreadManager::AddThread(CPUThreadType type)
switch(type)
{
case CPU_THREAD_PPU: new_thread = new PPUThread(); break;
case CPU_THREAD_SPU: new_thread = new SPUThread(); break;
case CPU_THREAD_RAW_SPU: new_thread = new RawSPUThread(m_raw_spu_num++); break;
case CPU_THREAD_ARMv7: new_thread = new ARMv7Thread(); break;
case CPU_THREAD_PPU:
{
new_thread = new PPUThread();
break;
}
case CPU_THREAD_SPU:
{
new_thread = new SPUThread();
break;
}
case CPU_THREAD_RAW_SPU:
{
new_thread = new RawSPUThread();
break;
}
case CPU_THREAD_ARMv7:
{
new_thread = new ARMv7Thread();
break;
}
default: assert(0);
}

View File

@ -7,7 +7,6 @@ class CPUThreadManager
{
std::vector<CPUThread*> m_threads;
std::mutex m_mtx_thread;
u32 m_raw_spu_num;
public:
CPUThreadManager();

View File

@ -7,12 +7,11 @@
#include "Emu/Cell/RawSPUThread.h"
RawSPUThread::RawSPUThread(u32 index, CPUThreadType type)
RawSPUThread::RawSPUThread(CPUThreadType type)
: SPUThread(type)
, MemoryBlock()
, m_index(index)
{
Memory.InitRawSPU(SetRange(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, RAW_SPU_PROB_OFFSET), m_index);
m_index = Memory.InitRawSPU(this);
Reset();
}
@ -23,75 +22,20 @@ RawSPUThread::~RawSPUThread()
bool RawSPUThread::Read32(const u64 addr, u32* value)
{
if(addr < GetStartAddr() + RAW_SPU_PROB_OFFSET)
{
return MemoryBlock::Read32(addr, value);
}
const u64 offset = addr - GetStartAddr() - RAW_SPU_PROB_OFFSET;
const u32 offset = addr - GetStartAddr() - RAW_SPU_PROB_OFFSET;
switch(offset)
switch (offset)
{
case MFC_LSA_offs:
{
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Read32(MFC_LSA)", m_index);
*value = MFC2.LSA.GetValue();
break;
}
case MFC_EAH_offs:
{
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Read32(MFC_EAH)", m_index);
*value = MFC2.EAH.GetValue();
break;
}
case MFC_EAL_offs:
{
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Read32(MFC_EAL)", m_index);
*value = MFC2.EAL.GetValue();
break;
}
case MFC_Size_Tag_offs:
{
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Read32(MFC_Size_Tag)", m_index);
*value = MFC2.Size_Tag.GetValue();
break;
}
case MFC_CMDStatus_offs:
{
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Read32(MFC_CMDStatus)", m_index);
*value = MFC2.CMDStatus.GetValue();
break;
}
case MFC_QStatus_offs:
{
LOG_WARNING(Log::SPU, "RawSPUThread[%d]: Read32(MFC_QStatus)", m_index);
*value = MFC2.QStatus.GetValue();
break;
}
case Prxy_QueryType_offs:
{
LOG_WARNING(Log::SPU, "RawSPUThread[%d]: Read32(Prxy_QueryType)", m_index);
*value = Prxy.QueryType.GetValue();
break;
}
case Prxy_QueryMask_offs:
{
LOG_WARNING(Log::SPU, "RawSPUThread[%d]: Read32(Prxy_QueryMask)", m_index);
*value = Prxy.QueryMask.GetValue();
break;
}
case Prxy_TagStatus_offs:
{
LOG_WARNING(Log::SPU, "RawSPUThread[%d]: Read32(Prxy_TagStatus)", m_index);
*value = Prxy.TagStatus.GetValue();
// TagStatus is not used: mask is written directly
*value = MFC2.QueryMask.GetValue();
break;
}
@ -101,62 +45,23 @@ bool RawSPUThread::Read32(const u64 addr, u32* value)
SPU.Out_MBox.PopUncond(*value);
break;
}
case SPU_In_MBox_offs:
{
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Read32(SPU_In_MBox)", m_index);
while (!SPU.In_MBox.Pop(*value) && !Emu.IsStopped())
std::this_thread::sleep_for(std::chrono::milliseconds(1));
break;
}
case SPU_MBox_Status_offs:
{
//LOG_WARNING(Log::SPU, "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() & 0xff) | (SPU.In_MBox.GetFreeCount() << 8));
*value = SPU.MBox_Status.GetValue();
*value = (SPU.Out_MBox.GetCount() & 0xff) | (SPU.In_MBox.GetFreeCount() << 8);
break;
}
case SPU_RunCntl_offs:
{
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Read32(SPU_RunCntl)", m_index);
*value = (u32)IsRunning();
break;
}
case SPU_Status_offs:
{
*value = SPU.Status.GetValue();
break;
}
case SPU_NPC_offs:
{
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Read32(SPU_NPC)", m_index);
*value = SPU.NPC.GetValue();
break;
}
case SPU_RdSigNotify1_offs:
{
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Read32(SPU_RdSigNotify1)", m_index);
*value = SPU.SNR[0].GetValue();
break;
}
case SPU_RdSigNotify2_offs:
{
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Read32(SPU_RdSigNotify2)", m_index);
*value = SPU.SNR[1].GetValue();
break;
}
default:
{
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Read32(0x%x)", m_index, offset);
Emu.Pause();
// TODO: read value from LS if necessary (not important)
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Read32(0x%llx)", m_index, offset);
return false;
}
}
@ -166,14 +71,9 @@ bool RawSPUThread::Read32(const u64 addr, u32* value)
bool RawSPUThread::Write32(const u64 addr, const u32 value)
{
if(addr < GetStartAddr() + RAW_SPU_PROB_OFFSET)
{
return MemoryBlock::Write32(addr, value);
}
const u64 offset = addr - GetStartAddr() - RAW_SPU_PROB_OFFSET;
const u32 offset = addr - GetStartAddr() - RAW_SPU_PROB_OFFSET;
switch(offset)
switch (offset)
{
case MFC_LSA_offs:
{
@ -206,53 +106,26 @@ bool RawSPUThread::Write32(const u64 addr, const u32 value)
break;
}
case MFC_QStatus_offs:
{
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Write32(MFC_QStatus, 0x%x)", m_index, value);
//MFC2.QStatus.SetValue(value);
break;
}
case Prxy_QueryType_offs:
{
LOG_WARNING(Log::SPU, "RawSPUThread[%d]: Write32(Prxy_QueryType, 0x%x)", m_index, value);
Prxy.QueryType.SetValue(value);
switch(value)
{
case 2:
LOG_WARNING(Log::SPU, "RawSPUThread[%d]: Prxy Query Immediate.", m_index);
break;
case 2: break;
default:
{
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Unknown Prxy Query Type. (prxy_query=0x%x)", m_index, value);
break;
return false;
}
}
Prxy.QueryType.SetValue(0);
MFC2.QStatus.SetValue(Prxy.QueryMask.GetValue());
MFC2.QueryType.SetValue(value); // not used
break;
}
case Prxy_QueryMask_offs:
{
LOG_WARNING(Log::SPU, "RawSPUThread[%d]: Write32(Prxy_QueryMask, 0x%x)", m_index, value);
Prxy.QueryMask.SetValue(value);
break;
}
case Prxy_TagStatus_offs:
{
LOG_WARNING(Log::SPU, "RawSPUThread[%d]: Write32(Prxy_TagStatus, 0x%x)", m_index, value);
Prxy.TagStatus.SetValue(value);
break;
}
case SPU_Out_MBox_offs:
{
LOG_WARNING(Log::SPU, "RawSPUThread[%d]: Write32(SPU_Out_MBox, 0x%x)", m_index, value);
while (!SPU.Out_MBox.Push(value) && !Emu.IsStopped())
std::this_thread::sleep_for(std::chrono::milliseconds(1));
MFC2.QueryMask.SetValue(value); // TagStatus is not used
break;
}
@ -262,13 +135,6 @@ bool RawSPUThread::Write32(const u64 addr, const u32 value)
SPU.In_MBox.PushUncond(value);
break;
}
case SPU_MBox_Status_offs:
{
LOG_WARNING(Log::SPU, "RawSPUThread[%d]: Write32(SPU_MBox_Status, 0x%x)", m_index, value);
SPU.MBox_Status.SetValue(value);
break;
}
case SPU_RunCntl_offs:
{
@ -290,39 +156,29 @@ bool RawSPUThread::Write32(const u64 addr, const u32 value)
break;
}
case SPU_Status_offs:
{
LOG_WARNING(Log::SPU, "RawSPUThread[%d]: Write32(SPU_Status, 0x%x)", m_index, value);
SPU.Status.SetValue(value);
break;
}
case SPU_NPC_offs:
{
LOG_WARNING(Log::SPU, "RawSPUThread[%d]: Write32(SPU_NPC, 0x%x)", m_index, value);
SPU.NPC.SetValue(value);
break;
}
case SPU_RdSigNotify1_offs:
{
LOG_WARNING(Log::SPU, "RawSPUThread[%d]: Write32(SPU_RdSigNotify1, 0x%x)", m_index, value);
SPU.SNR[0].SetValue(value);
WriteSNR(0, value);
break;
}
case SPU_RdSigNotify2_offs:
{
LOG_WARNING(Log::SPU, "RawSPUThread[%d]: Write32(SPU_RdSigNotify2, 0x%x)", m_index, value);
SPU.SNR[1].SetValue(value);
WriteSNR(1, value);
break;
}
default:
{
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Write32(0x%x, 0x%x)", m_index, offset, value);
Emu.Pause();
break;
// TODO: write value to LS if necessary (not important)
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Write32(0x%llx, 0x%x)", m_index, offset, value);
return false;
}
}
@ -344,7 +200,7 @@ void RawSPUThread::Task()
{
PC = SPU.NPC.GetValue();
CPUThread::Task();
SPUThread::Task();
SPU.NPC.SetValue(PC);
}

View File

@ -19,7 +19,7 @@ class RawSPUThread
u32 m_index;
public:
RawSPUThread(u32 index, CPUThreadType type = CPU_THREAD_RAW_SPU);
RawSPUThread(CPUThreadType type = CPU_THREAD_RAW_SPU);
virtual ~RawSPUThread();
virtual bool Read32(const u64 addr, u32* value) override;

View File

@ -503,29 +503,50 @@ private:
void ROTQBI(u32 rt, u32 ra, u32 rb)
{
const int t = CPU.GPR[rb]._u32[3] & 0x7;
const SPU_GPR_hdr temp = CPU.GPR[ra];
CPU.GPR[rt]._u32[0] = (temp._u32[0] << t) | (temp._u32[3] >> (32 - t));
CPU.GPR[rt]._u32[1] = (temp._u32[1] << t) | (temp._u32[0] >> (32 - t));
CPU.GPR[rt]._u32[2] = (temp._u32[2] << t) | (temp._u32[1] >> (32 - t));
CPU.GPR[rt]._u32[3] = (temp._u32[3] << t) | (temp._u32[2] >> (32 - t));
if (t) // not an optimization, it fixes shifts
{
const SPU_GPR_hdr temp = CPU.GPR[ra];
CPU.GPR[rt]._u32[0] = (temp._u32[0] << t) | (temp._u32[3] >> (32 - t));
CPU.GPR[rt]._u32[1] = (temp._u32[1] << t) | (temp._u32[0] >> (32 - t));
CPU.GPR[rt]._u32[2] = (temp._u32[2] << t) | (temp._u32[1] >> (32 - t));
CPU.GPR[rt]._u32[3] = (temp._u32[3] << t) | (temp._u32[2] >> (32 - t));
}
else
{
CPU.GPR[rt] = CPU.GPR[ra];
}
}
void ROTQMBI(u32 rt, u32 ra, u32 rb)
{
const int t = (0 - CPU.GPR[rb]._u32[3]) & 0x7;
const SPU_GPR_hdr temp = CPU.GPR[ra];
CPU.GPR[rt]._u32[0] = (temp._u32[0] >> t) | (temp._u32[1] << (32 - t));
CPU.GPR[rt]._u32[1] = (temp._u32[1] >> t) | (temp._u32[2] << (32 - t));
CPU.GPR[rt]._u32[2] = (temp._u32[2] >> t) | (temp._u32[3] << (32 - t));
CPU.GPR[rt]._u32[3] = (temp._u32[3] >> t);
if (t) // not an optimization, it fixes shifts
{
const SPU_GPR_hdr temp = CPU.GPR[ra];
CPU.GPR[rt]._u32[0] = (temp._u32[0] >> t) | (temp._u32[1] << (32 - t));
CPU.GPR[rt]._u32[1] = (temp._u32[1] >> t) | (temp._u32[2] << (32 - t));
CPU.GPR[rt]._u32[2] = (temp._u32[2] >> t) | (temp._u32[3] << (32 - t));
CPU.GPR[rt]._u32[3] = (temp._u32[3] >> t);
}
else
{
CPU.GPR[rt] = CPU.GPR[ra];
}
}
void SHLQBI(u32 rt, u32 ra, u32 rb)
{
const int t = CPU.GPR[rb]._u32[3] & 0x7;
const SPU_GPR_hdr temp = CPU.GPR[ra];
CPU.GPR[rt]._u32[0] = (temp._u32[0] << t);
CPU.GPR[rt]._u32[1] = (temp._u32[1] << t) | (temp._u32[0] >> (32 - t));
CPU.GPR[rt]._u32[2] = (temp._u32[2] << t) | (temp._u32[1] >> (32 - t));
CPU.GPR[rt]._u32[3] = (temp._u32[3] << t) | (temp._u32[2] >> (32 - t));
if (t) // not an optimization, it fixes shifts
{
const SPU_GPR_hdr temp = CPU.GPR[ra];
CPU.GPR[rt]._u32[0] = (temp._u32[0] << t);
CPU.GPR[rt]._u32[1] = (temp._u32[1] << t) | (temp._u32[0] >> (32 - t));
CPU.GPR[rt]._u32[2] = (temp._u32[2] << t) | (temp._u32[1] >> (32 - t));
CPU.GPR[rt]._u32[3] = (temp._u32[3] << t) | (temp._u32[2] >> (32 - t));
}
else
{
CPU.GPR[rt] = CPU.GPR[ra];
}
}
void ROTQBY(u32 rt, u32 ra, u32 rb)
{
@ -591,29 +612,50 @@ private:
void ROTQBII(u32 rt, u32 ra, s32 i7)
{
const int s = i7 & 0x7;
const SPU_GPR_hdr temp = CPU.GPR[ra];
CPU.GPR[rt]._u32[0] = (temp._u32[0] << s) | (temp._u32[3] >> (32 - s));
CPU.GPR[rt]._u32[1] = (temp._u32[1] << s) | (temp._u32[0] >> (32 - s));
CPU.GPR[rt]._u32[2] = (temp._u32[2] << s) | (temp._u32[1] >> (32 - s));
CPU.GPR[rt]._u32[3] = (temp._u32[3] << s) | (temp._u32[2] >> (32 - s));
if (s) // not an optimization, it fixes shifts
{
const SPU_GPR_hdr temp = CPU.GPR[ra];
CPU.GPR[rt]._u32[0] = (temp._u32[0] << s) | (temp._u32[3] >> (32 - s));
CPU.GPR[rt]._u32[1] = (temp._u32[1] << s) | (temp._u32[0] >> (32 - s));
CPU.GPR[rt]._u32[2] = (temp._u32[2] << s) | (temp._u32[1] >> (32 - s));
CPU.GPR[rt]._u32[3] = (temp._u32[3] << s) | (temp._u32[2] >> (32 - s));
}
else
{
CPU.GPR[rt] = CPU.GPR[ra];
}
}
void ROTQMBII(u32 rt, u32 ra, s32 i7)
{
const int s = (0 - i7) & 0x7;
const SPU_GPR_hdr temp = CPU.GPR[ra];
CPU.GPR[rt]._u32[0] = (temp._u32[0] >> s) | (temp._u32[1] << (32 - s));
CPU.GPR[rt]._u32[1] = (temp._u32[1] >> s) | (temp._u32[2] << (32 - s));
CPU.GPR[rt]._u32[2] = (temp._u32[2] >> s) | (temp._u32[3] << (32 - s));
CPU.GPR[rt]._u32[3] = (temp._u32[3] >> s);
if (s) // not an optimization, it fixes shifts
{
const SPU_GPR_hdr temp = CPU.GPR[ra];
CPU.GPR[rt]._u32[0] = (temp._u32[0] >> s) | (temp._u32[1] << (32 - s));
CPU.GPR[rt]._u32[1] = (temp._u32[1] >> s) | (temp._u32[2] << (32 - s));
CPU.GPR[rt]._u32[2] = (temp._u32[2] >> s) | (temp._u32[3] << (32 - s));
CPU.GPR[rt]._u32[3] = (temp._u32[3] >> s);
}
else
{
CPU.GPR[rt] = CPU.GPR[ra];
}
}
void SHLQBII(u32 rt, u32 ra, s32 i7)
{
const int s = i7 & 0x7;
const SPU_GPR_hdr temp = CPU.GPR[ra];
CPU.GPR[rt]._u32[0] = (temp._u32[0] << s);
CPU.GPR[rt]._u32[1] = (temp._u32[1] << s) | (temp._u32[0] >> (32 - s));
CPU.GPR[rt]._u32[2] = (temp._u32[2] << s) | (temp._u32[1] >> (32 - s));
CPU.GPR[rt]._u32[3] = (temp._u32[3] << s) | (temp._u32[2] >> (32 - s));
if (s) // not an optimization, it fixes shifts
{
const SPU_GPR_hdr temp = CPU.GPR[ra];
CPU.GPR[rt]._u32[0] = (temp._u32[0] << s);
CPU.GPR[rt]._u32[1] = (temp._u32[1] << s) | (temp._u32[0] >> (32 - s));
CPU.GPR[rt]._u32[2] = (temp._u32[2] << s) | (temp._u32[1] >> (32 - s));
CPU.GPR[rt]._u32[3] = (temp._u32[3] << s) | (temp._u32[2] >> (32 - s));
}
else
{
CPU.GPR[rt] = CPU.GPR[ra];
}
}
void ROTQBYI(u32 rt, u32 ra, s32 i7)
{
@ -747,24 +789,27 @@ private:
}
void FA(u32 rt, u32 ra, u32 rb)
{
CPU.GPR[rt]._f[0] = CPU.GPR[ra]._f[0] + CPU.GPR[rb]._f[0];
CPU.GPR[rt]._f[1] = CPU.GPR[ra]._f[1] + CPU.GPR[rb]._f[1];
CPU.GPR[rt]._f[2] = CPU.GPR[ra]._f[2] + CPU.GPR[rb]._f[2];
CPU.GPR[rt]._f[3] = CPU.GPR[ra]._f[3] + CPU.GPR[rb]._f[3];
for (int w = 0; w < 4; w++)
{
CPU.GPR[rt]._f[w] = CPU.GPR[ra]._f[w] + CPU.GPR[rb]._f[w];
//if (CPU.GPR[rt]._f[w] == -0.0f) CPU.GPR[rt]._f[w] = 0.0f;
}
}
void FS(u32 rt, u32 ra, u32 rb)
{
CPU.GPR[rt]._f[0] = CPU.GPR[ra]._f[0] - CPU.GPR[rb]._f[0];
CPU.GPR[rt]._f[1] = CPU.GPR[ra]._f[1] - CPU.GPR[rb]._f[1];
CPU.GPR[rt]._f[2] = CPU.GPR[ra]._f[2] - CPU.GPR[rb]._f[2];
CPU.GPR[rt]._f[3] = CPU.GPR[ra]._f[3] - CPU.GPR[rb]._f[3];
for (int w = 0; w < 4; w++)
{
CPU.GPR[rt]._f[w] = CPU.GPR[ra]._f[w] - CPU.GPR[rb]._f[w];
//if (CPU.GPR[rt]._f[w] == -0.0f) CPU.GPR[rt]._f[w] = 0.0f;
}
}
void FM(u32 rt, u32 ra, u32 rb)
{
CPU.GPR[rt]._f[0] = CPU.GPR[ra]._f[0] * CPU.GPR[rb]._f[0];
CPU.GPR[rt]._f[1] = CPU.GPR[ra]._f[1] * CPU.GPR[rb]._f[1];
CPU.GPR[rt]._f[2] = CPU.GPR[ra]._f[2] * CPU.GPR[rb]._f[2];
CPU.GPR[rt]._f[3] = CPU.GPR[ra]._f[3] * CPU.GPR[rb]._f[3];
for (int w = 0; w < 4; w++)
{
CPU.GPR[rt]._f[w] = CPU.GPR[ra]._f[w] * CPU.GPR[rb]._f[w];
//if (CPU.GPR[rt]._f[w] == -0.0f) CPU.GPR[rt]._f[w] = 0.0f;
}
}
void CLGTH(u32 rt, u32 ra, u32 rb)
{
@ -1513,24 +1558,27 @@ private:
}
void FNMS(u32 rt, u32 ra, u32 rb, u32 rc)
{
CPU.GPR[rt]._f[0] = CPU.GPR[rc]._f[0] - CPU.GPR[ra]._f[0] * CPU.GPR[rb]._f[0];
CPU.GPR[rt]._f[1] = CPU.GPR[rc]._f[1] - CPU.GPR[ra]._f[1] * CPU.GPR[rb]._f[1];
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];
for (int w = 0; w < 4; w++)
{
CPU.GPR[rt]._f[w] = CPU.GPR[rc]._f[w] - CPU.GPR[ra]._f[w] * CPU.GPR[rb]._f[w];
//if (CPU.GPR[rt]._f[w] == -0.0f) CPU.GPR[rt]._f[w] = 0.0f;
}
}
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[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[3] = CPU.GPR[ra]._f[3] * CPU.GPR[rb]._f[3] + CPU.GPR[rc]._f[3];
for (int w = 0; w < 4; w++)
{
CPU.GPR[rt]._f[w] = CPU.GPR[rc]._f[w] + CPU.GPR[ra]._f[w] * CPU.GPR[rb]._f[w];
//if (CPU.GPR[rt]._f[w] == -0.0f) CPU.GPR[rt]._f[w] = 0.0f;
}
}
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[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[3] = CPU.GPR[ra]._f[3] * CPU.GPR[rb]._f[3] - CPU.GPR[rc]._f[3];
for (int w = 0; w < 4; w++)
{
CPU.GPR[rt]._f[w] = CPU.GPR[ra]._f[w] * CPU.GPR[rb]._f[w] - CPU.GPR[rc]._f[w];
//if (CPU.GPR[rt]._f[w] == -0.0f) CPU.GPR[rt]._f[w] = 0.0f;
}
}
void UNK(u32 code, u32 opcode, u32 gcode)

View File

@ -1485,8 +1485,8 @@ private:
c.movdqa(vr.get(), XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
XmmFinalize(vr, rt);
XmmInvalidate(rt);
c.mov(dword_ptr(*cpu_var, *addr, 0, offsetof(SPUThread, GPR[rt]._u32[0])), 0x00010203);
c.mov(dword_ptr(*cpu_var, *addr, 0, offsetof(SPUThread, GPR[rt]._u32[1])), 0x04050607);
c.mov(dword_ptr(*cpu_var, *addr, 0, offsetof(SPUThread, GPR[rt]._u32[0])), 0x04050607);
c.mov(dword_ptr(*cpu_var, *addr, 0, offsetof(SPUThread, GPR[rt]._u32[1])), 0x00010203);
LOG_OPCODE();
}
void ROTQBI(u32 rt, u32 ra, u32 rb)
@ -1628,8 +1628,8 @@ private:
c.movdqa(vr.get(), XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
XmmFinalize(vr, rt);
XmmInvalidate(rt);
c.mov(dword_ptr(*cpu_var, *addr, 0, offsetof(SPUThread, GPR[rt]._u32[0])), 0x00010203);
c.mov(dword_ptr(*cpu_var, *addr, 0, offsetof(SPUThread, GPR[rt]._u32[1])), 0x04050607);
c.mov(dword_ptr(*cpu_var, *addr, 0, offsetof(SPUThread, GPR[rt]._u32[0])), 0x04050607);
c.mov(dword_ptr(*cpu_var, *addr, 0, offsetof(SPUThread, GPR[rt]._u32[1])), 0x00010203);
LOG_OPCODE();
}
void ROTQBII(u32 rt, u32 ra, s32 i7)

View File

@ -10,6 +10,8 @@
#include "Emu/Cell/SPUDisAsm.h"
#include "Emu/Cell/SPURecompiler.h"
#include <cfenv>
SPUThread& GetCurrentSPUThread()
{
PPCThread* thread = GetCurrentPPCThread();
@ -35,6 +37,19 @@ SPUThread::~SPUThread()
{
}
void SPUThread::Task()
{
const int round = std::fegetround();
std::fesetround(FE_TOWARDZERO);
CPUThread::Task();
if (std::fegetround() != FE_TOWARDZERO)
{
LOG_ERROR(Log::SPU, "Rounding mode has changed(%d)", std::fegetround());
}
std::fesetround(round);
}
void SPUThread::DoReset()
{
PPCThread::DoReset();
@ -60,9 +75,13 @@ void SPUThread::InitRegs()
dmac.queue_lock = 0;*/
SPU.Status.SetValue(SPU_STATUS_STOPPED);
Prxy.QueryType.SetValue(0);
// TODO: check initialization if necessary
MFC2.QueryType.SetValue(0); // prxy
MFC1.CMDStatus.SetValue(0);
MFC2.CMDStatus.SetValue(0);
MFC1.TagStatus.SetValue(0);
MFC2.TagStatus.SetValue(0);
//PC = SPU.NPC.GetValue();
}

View File

@ -523,16 +523,11 @@ public:
Channel<1> EAL;
Channel<1> Size_Tag;
Channel<1> CMDStatus;
Channel<1> QStatus;
} MFC1, MFC2;
struct
{
Channel<1> QueryType;
Channel<1> QueryType; // only for prxy
Channel<1> QueryMask;
Channel<1> TagStatus;
Channel<1> AtomicStat;
} Prxy;
} MFC1, MFC2;
struct StalledList
{
@ -555,7 +550,6 @@ public:
Channel<1> Out_MBox;
Channel<1> Out_IntrMBox;
Channel<4> In_MBox;
Channel<1> MBox_Status;
Channel<1> Status;
Channel<1> NPC;
Channel<1> SNR[2];
@ -831,7 +825,7 @@ public:
reservation.data[i] = *(u128*)&Memory[(u32)ea + i * 16];
*(u128*)&Memory[dmac.ls_offset + lsa + i * 16] = reservation.data[i];
}
Prxy.AtomicStat.PushUncond(MFC_GETLLAR_SUCCESS);
MFCArgs.AtomicStat.PushUncond(MFC_GETLLAR_SUCCESS);
}
else if (op == MFC_PUTLLC_CMD) // store conditional
{
@ -854,7 +848,7 @@ public:
}
if (changed == 0) // nothing changed?
{
Prxy.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
}
else if (changed == 1)
{
@ -862,7 +856,7 @@ public:
{
LOG_ERROR(Log::SPU, "MFC_PUTLLC_CMD: TODO: 128bit compare and swap");
Emu.Pause();
Prxy.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
}
else
{
@ -871,11 +865,11 @@ public:
if (InterlockedCompareExchange64((volatile long long*)(Memory + (u32)ea + last * 16 + last_q * 8),
buf[last]._u64[last_q], reservation.data[last]._u64[last_q]) == reservation.data[last]._u64[last_q])
{
Prxy.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
}
else
{
Prxy.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])
@ -890,7 +884,7 @@ public:
{
LOG_ERROR(Log::SPU, "MFC_PUTLLC_CMD: TODO: 64bit compare and swap");
Emu.Pause();
Prxy.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
}*/
}
}
@ -900,18 +894,18 @@ public:
LOG_ERROR(Log::SPU, "MFC_PUTLLC_CMD: Reservation Error: impossibru (~ 16x%d (mask=0x%x)) (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)",
changed, mask, op, cmd, lsa, ea, tag, size);
Emu.Pause();
Prxy.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
}
}
else
{
Prxy.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
}
reservation.clear();
}
else // failed
{
Prxy.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
}
}
else // store unconditional
@ -920,7 +914,7 @@ public:
ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128);
if (op == MFC_PUTLLUC_CMD)
{
Prxy.AtomicStat.PushUncond(MFC_PUTLLUC_SUCCESS);
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLUC_SUCCESS);
}
if ((reservation.addr + reservation.size > ea && reservation.addr <= ea + size) ||
(ea + size > reservation.addr && ea <= reservation.addr + reservation.size))
@ -944,12 +938,12 @@ public:
{
case SPU_WrOutMbox: return SPU.Out_MBox.GetFreeCount();
case SPU_RdInMbox: return SPU.In_MBox.GetCount();
case MFC_RdTagStat: return Prxy.TagStatus.GetCount();
case MFC_RdTagStat: return MFC1.TagStatus.GetCount();
case MFC_RdListStallStat: return StallStat.GetCount();
case MFC_WrTagUpdate: return Prxy.TagStatus.GetCount(); // hack
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 Prxy.AtomicStat.GetCount();
case MFC_RdAtomicStat: return MFC1.AtomicStat.GetCount();
default:
{
@ -1115,14 +1109,14 @@ public:
case MFC_WrTagMask:
{
//ConLog.Warning("%s: %s = 0x%x", __FUNCTION__, spu_ch_name[ch], v);
Prxy.QueryMask.SetValue(v);
MFC1.QueryMask.SetValue(v);
break;
}
case MFC_WrTagUpdate:
{
//ConLog.Warning("%s: %s = 0x%x", __FUNCTION__, spu_ch_name[ch], v);
Prxy.TagStatus.PushUncond(Prxy.QueryMask.GetValue());
MFC1.TagStatus.PushUncond(MFC1.QueryMask.GetValue());
break;
}
@ -1184,7 +1178,7 @@ public:
case SPU_WrDec:
{
m_dec_start = get_system_time();
m_dec_start = get_time();
m_dec_value = v;
break;
}
@ -1215,7 +1209,7 @@ public:
case MFC_RdTagStat:
{
while (!Prxy.TagStatus.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
while (!MFC1.TagStatus.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
//ConLog.Warning("%s: 0x%x = %s", __FUNCTION__, v, spu_ch_name[ch]);
break;
}
@ -1236,7 +1230,7 @@ public:
case MFC_RdAtomicStat:
{
while (!Prxy.AtomicStat.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
while (!MFC1.AtomicStat.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
break;
}
@ -1248,8 +1242,7 @@ public:
case SPU_RdDec:
{
// decrementer freq is probably 80 MHz
v = m_dec_value - (u32)(get_system_time() - m_dec_start) * 80;
v = m_dec_value - (u32)(get_time() - m_dec_start);
break;
}
@ -1444,6 +1437,7 @@ public:
public:
virtual void InitRegs();
virtual u64 GetFreeStackSize() const;
virtual void Task();
protected:
virtual void DoReset();

View File

@ -214,12 +214,22 @@ public:
}
}
void InitRawSPU(MemoryBlock* raw_spu, const u32 num)
u32 InitRawSPU(MemoryBlock* raw_spu)
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);
MemoryBlocks.push_back(raw_spu);
if (num < sizeof(RawSPUMem) / sizeof(RawSPUMem[0])) RawSPUMem[num] = raw_spu;
u32 index;
for (index = 0; index < sizeof(RawSPUMem) / sizeof(RawSPUMem[0]); index++)
{
if (!RawSPUMem[index])
{
RawSPUMem[index] = raw_spu;
break;
}
}
MemoryBlocks.push_back(raw_spu->SetRange(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, RAW_SPU_PROB_OFFSET));
return index;
}
void CloseRawSPU(MemoryBlock* raw_spu, const u32 num)
@ -391,7 +401,10 @@ public:
}
else
{
RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET]->Write32(addr, data);
if (!RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET]->Write32(addr, data))
{
*(u32*)((u8*)GetBaseAddr() + addr) = re32(data);
}
}
}
else
@ -464,7 +477,10 @@ public:
else
{
u32 res;
RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET]->Read32(addr, &res);
if (!RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET]->Read32(addr, &res))
{
res = re32(*(u32*)((u8*)GetBaseAddr() + addr));
}
return res;
}
}

View File

@ -18,46 +18,12 @@ u32 LoadSpuImage(vfsStream& stream, u32& spu_ep)
{
ELFLoader l(stream);
l.LoadInfo();
const u32 alloc_size = 256 * 1024 /*0x1000000 - stream.GetSize()*/;
const u32 alloc_size = 256 * 1024;
u32 spu_offset = Memory.MainMem.AllocAlign(alloc_size);
l.LoadData(spu_offset);
spu_ep = l.GetEntry();
return spu_offset;
}
/*u64 g_last_spu_offset = 0;
static const u64 g_spu_alloc_size = 0x1000000;
u32 LoadSpuImage(vfsStream& stream, u64 address)
{
ELFLoader l(stream);
l.LoadInfo();
l.LoadData(address);
return address + l.GetEntry();
}
u32 LoadSpuImage(vfsStream& stream)
{
g_last_spu_offset = Memory.MainMem.Alloc(g_spu_alloc_size);
return LoadSpuImage(stream, g_last_spu_offset);
}*/
/*u32 _max_usable_spu = 0;
u32 _max_raw_spu = 0;
s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu)
{
sc_spu.Log("sys_spu_initialize(max_usable_spu=%d, max_raw_spu=%d)", max_usable_spu, max_raw_spu);
_max_usable_spu = max_usable_spu;
_max_raw_spu = max_raw_spu;
return CELL_OK;
}
s32 sys_raw_spu_create(u32 id_addr, u32 attr_addr)
{
Memory.Write32(id_addr, Emu.GetIdManager().GetNewID("raw_spu"));
return CELL_OK;
}*/
//156
s32 sys_spu_image_open(mem_ptr_t<sys_spu_image> img, u32 path_addr)
@ -349,13 +315,23 @@ s32 sys_spu_thread_group_join(u32 id, mem32_t cause, mem32_t status)
return CELL_ESRCH;
}
if (cause.GetAddr() && !cause.IsGood())
{
return CELL_EFAULT;
}
if (status.GetAddr() && !status.IsGood())
{
return CELL_EFAULT;
}
if (group_info->lock.exchange(1)) // acquire lock
{
return CELL_EBUSY;
}
cause = SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT;
status = 0; //unspecified because of ALL_THREADS_EXIT
if (cause.GetAddr()) cause = SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT;
if (status.GetAddr()) status = 0; //unspecified because of ALL_THREADS_EXIT
for (u32 i = 0; i < group_info->list.size(); i++)
{
@ -796,24 +772,38 @@ s32 sys_raw_spu_create(mem32_t id, u32 attr_addr)
{
sc_spu.Warning("sys_raw_spu_create(id_addr=0x%x, attr_addr=0x%x)", id.GetAddr(), attr_addr);
//Emu.GetIdManager().GetNewID("sys_raw_spu", new u32(attr_addr));
CPUThread& new_thread = Emu.GetCPU().AddThread(CPU_THREAD_RAW_SPU);
if (((RawSPUThread&)new_thread).GetIndex() >= 5)
{
Emu.GetCPU().RemoveThread(new_thread.GetId());
return CELL_EAGAIN;
}
id = ((RawSPUThread&)new_thread).GetIndex();
new_thread.Run();
return CELL_OK;
}
s32 sys_raw_spu_destroy(u32 id)
{
sc_spu.Error("sys_raw_spu_destroy(id=%d)", id);
sc_spu.Warning("sys_raw_spu_destroy(id=%d)", id);
RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id);
if (!t)
{
return CELL_ESRCH;
}
// TODO: check if busy
Emu.GetCPU().RemoveThread(t->GetId());
return CELL_OK;
}
s32 sys_raw_spu_create_interrupt_tag(u32 id, u32 class_id, u32 hwthread, mem32_t intrtag)
{
sc_spu.Error("sys_raw_spu_create_interrupt_tag(id=%d, class_id=%d, hwthread=0x%x, intrtag_addr=0x%x)", id, class_id, hwthread, intrtag.GetAddr());
sc_spu.Warning("sys_raw_spu_create_interrupt_tag(id=%d, class_id=%d, hwthread=0x%x, intrtag_addr=0x%x)", id, class_id, hwthread, intrtag.GetAddr());
RawSPUThread* t = Emu.GetCPU().GetRawSPUThread(id);

View File

@ -14,22 +14,33 @@
SysCallBase sys_time("sys_time");
//static const u64 timebase_frequency = 79800000;
static const u64 timebase_frequency = /*79800000*/ 80000000; // 80 Mhz
extern int cellSysutilGetSystemParamInt(int id, mem32_t value);
// Auxiliary functions
u64 get_time()
{
#ifdef _WIN32
static struct PerformanceFreqHolder
{
u64 value;
PerformanceFreqHolder()
{
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
value = freq.QuadPart;
}
} freq;
LARGE_INTEGER cycle;
LARGE_INTEGER freq;
QueryPerformanceCounter(&cycle);
QueryPerformanceFrequency(&freq);
return cycle.QuadPart * 10000000 / freq.QuadPart;
u64 sec = cycle.QuadPart / freq.value;
return sec * timebase_frequency + (cycle.QuadPart % freq.value) * timebase_frequency / freq.value;
#else
struct timespec ts;
if (!clock_gettime(CLOCK_MONOTONIC, &ts))
return ts.tv_sec * (s64)10000000 + (s64)ts.tv_nsec / (s64)100;
return ts.tv_sec * (s64)timebase_frequency + (s64)ts.tv_nsec * (s64)timebase_frequency / 1000000000;
// Should never occur.
assert(0);
@ -40,7 +51,7 @@ u64 get_time()
// Returns some relative time in microseconds, don't change this fact
u64 get_system_time()
{
return get_time() / 10;
return get_time() / (timebase_frequency / MHZ);
}
@ -61,8 +72,8 @@ s32 sys_time_get_current_time(u32 sec_addr, u32 nsec_addr)
u64 time = get_time();
Memory.Write64(sec_addr, time / 10000000);
Memory.Write64(nsec_addr, (time % 10000000) * 100);
Memory.Write64(sec_addr, time / timebase_frequency);
Memory.Write64(nsec_addr, (time % timebase_frequency) * 1000000000 / (s64)(timebase_frequency));
return CELL_OK;
}
@ -76,5 +87,5 @@ s64 sys_time_get_system_time()
u64 sys_time_get_timebase_frequency()
{
sys_time.Log("sys_time_get_timebase_frequency()");
return 10000000;
return timebase_frequency;
}

View File

@ -1,5 +1,7 @@
#pragma once
#define MHZ (10000000)
// Auxiliary functions
u64 get_time();
u64 get_system_time();