mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-21 18:22:33 +01:00
SPU Cleanup
SPURecompiler improved Old SPU decoder removed SPU Interpreters merged
This commit is contained in:
parent
58181c5c17
commit
817fec9684
2
asmjit
2
asmjit
@ -1 +1 @@
|
||||
Subproject commit bd0d261e8b72d1915e64da8a6b5bebae5637fa20
|
||||
Subproject commit b0dad1af25fb141bf2b20cf29392194886448832
|
@ -6,10 +6,11 @@
|
||||
|
||||
#include "Emu/Cell/RawSPUThread.h"
|
||||
|
||||
// Originally, SPU MFC registers are accessed externally in a concurrent manner (don't mix with channels, SPU MFC channels are isolated)
|
||||
thread_local spu_mfc_arg_t raw_spu_mfc[8] = {};
|
||||
|
||||
RawSPUThread::RawSPUThread(const std::string& name, u32 index)
|
||||
: SPUThread(CPU_THREAD_RAW_SPU, name, COPY_EXPR(fmt::format("RawSPU%d[0x%x] Thread (%s)[0x%08x]", index, m_id, m_name.c_str(), PC)), index, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index)
|
||||
: SPUThread(CPU_THREAD_RAW_SPU, name, COPY_EXPR(fmt::format("RawSPU[%d] Thread (0x%x)[0x%05x]", index, m_id, pc)), index, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index)
|
||||
{
|
||||
if (!vm::falloc(offset, 0x40000))
|
||||
{
|
||||
@ -45,13 +46,11 @@ bool RawSPUThread::read_reg(const u32 addr, u32& value)
|
||||
|
||||
case SPU_Out_MBox_offs:
|
||||
{
|
||||
bool notify;
|
||||
value = ch_out_mbox.pop();
|
||||
|
||||
std::tie(value, notify) = ch_out_mbox.pop();
|
||||
|
||||
if (notify)
|
||||
if (ch_out_mbox.notification_required)
|
||||
{
|
||||
// notify if necessary
|
||||
// lock for reliable notification
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
|
||||
cv.notify_one();
|
||||
@ -170,7 +169,6 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value)
|
||||
|
||||
case Prxy_QueryMask_offs:
|
||||
{
|
||||
//proxy_tag_mask = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -178,7 +176,7 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value)
|
||||
{
|
||||
if (ch_in_mbox.push(value))
|
||||
{
|
||||
// notify if necessary
|
||||
// lock for reliable notification
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
|
||||
cv.notify_one();
|
||||
@ -238,14 +236,14 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value)
|
||||
void RawSPUThread::task()
|
||||
{
|
||||
// get next PC and SPU Interrupt status
|
||||
PC = npc.exchange(0);
|
||||
pc = npc.exchange(0);
|
||||
|
||||
set_interrupt_status((PC & 1) != 0);
|
||||
set_interrupt_status((pc & 1) != 0);
|
||||
|
||||
PC &= 0x3FFFC;
|
||||
pc &= 0x3fffc;
|
||||
|
||||
SPUThread::task();
|
||||
|
||||
// save next PC and current SPU Interrupt status
|
||||
npc.store(PC | ((ch_event_stat.load() & SPU_EVENT_INTR_ENABLED) != 0));
|
||||
npc.store(pc | u32{ (ch_event_stat.load() & SPU_EVENT_INTR_ENABLED) != 0 });
|
||||
}
|
||||
|
2576
rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp
Normal file
2576
rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
309
rpcs3/Emu/Cell/SPUASMJITRecompiler.h
Normal file
309
rpcs3/Emu/Cell/SPUASMJITRecompiler.h
Normal file
@ -0,0 +1,309 @@
|
||||
#pragma once
|
||||
|
||||
#include "SPURecompiler.h"
|
||||
|
||||
namespace asmjit
|
||||
{
|
||||
struct JitRuntime;
|
||||
struct X86Compiler;
|
||||
struct X86GpVar;
|
||||
struct X86XmmVar;
|
||||
struct X86Mem;
|
||||
struct Label;
|
||||
}
|
||||
|
||||
// SPU ASMJIT Recompiler
|
||||
class spu_recompiler : public SPURecompilerBase
|
||||
{
|
||||
const std::shared_ptr<asmjit::JitRuntime> m_jit;
|
||||
|
||||
public:
|
||||
spu_recompiler();
|
||||
|
||||
virtual void compile(spu_function_t& f) override;
|
||||
|
||||
private:
|
||||
// emitter:
|
||||
asmjit::X86Compiler* c;
|
||||
|
||||
// input:
|
||||
asmjit::X86GpVar* cpu;
|
||||
asmjit::X86GpVar* ls;
|
||||
|
||||
// output:
|
||||
asmjit::X86GpVar* pos;
|
||||
|
||||
// temporary:
|
||||
asmjit::X86GpVar* addr;
|
||||
asmjit::X86GpVar* qw0;
|
||||
asmjit::X86GpVar* qw1;
|
||||
asmjit::X86GpVar* qw2;
|
||||
std::array<asmjit::X86XmmVar*, 10> vec;
|
||||
|
||||
// labels:
|
||||
asmjit::Label* labels; // array[0x10000]
|
||||
asmjit::Label* jt; // jump table resolver
|
||||
|
||||
class XmmLink
|
||||
{
|
||||
friend class spu_recompiler;
|
||||
|
||||
asmjit::X86XmmVar*& m_alloc;
|
||||
asmjit::X86XmmVar* xmm_var;
|
||||
|
||||
XmmLink(asmjit::X86XmmVar*& xmm_var)
|
||||
: m_alloc(xmm_var)
|
||||
, xmm_var(xmm_var)
|
||||
{
|
||||
m_alloc = nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
XmmLink() = delete;
|
||||
|
||||
XmmLink(const XmmLink&) = delete;
|
||||
|
||||
XmmLink(XmmLink&& right)
|
||||
: m_alloc(right.m_alloc)
|
||||
, xmm_var(right.xmm_var)
|
||||
{
|
||||
right.xmm_var = nullptr;
|
||||
}
|
||||
|
||||
XmmLink& operator =(const XmmLink&) = delete;
|
||||
|
||||
XmmLink& operator =(XmmLink&& right) = delete;
|
||||
|
||||
~XmmLink()
|
||||
{
|
||||
if (xmm_var) m_alloc = xmm_var;
|
||||
}
|
||||
|
||||
inline operator const asmjit::X86XmmVar&() const
|
||||
{
|
||||
return *xmm_var;
|
||||
}
|
||||
};
|
||||
|
||||
enum class XmmType
|
||||
{
|
||||
Int,
|
||||
Float,
|
||||
Double,
|
||||
};
|
||||
|
||||
XmmLink XmmAlloc();
|
||||
XmmLink XmmGet(s8 reg, XmmType type);
|
||||
|
||||
asmjit::X86Mem XmmConst(v128 data);
|
||||
asmjit::X86Mem XmmConst(__m128 data);
|
||||
asmjit::X86Mem XmmConst(__m128i data);
|
||||
|
||||
private:
|
||||
void InterpreterCall(spu_opcode_t op);
|
||||
void FunctionCall();
|
||||
|
||||
void STOP(spu_opcode_t op);
|
||||
void LNOP(spu_opcode_t op);
|
||||
void SYNC(spu_opcode_t op);
|
||||
void DSYNC(spu_opcode_t op);
|
||||
void MFSPR(spu_opcode_t op);
|
||||
void RDCH(spu_opcode_t op);
|
||||
void RCHCNT(spu_opcode_t op);
|
||||
void SF(spu_opcode_t op);
|
||||
void OR(spu_opcode_t op);
|
||||
void BG(spu_opcode_t op);
|
||||
void SFH(spu_opcode_t op);
|
||||
void NOR(spu_opcode_t op);
|
||||
void ABSDB(spu_opcode_t op);
|
||||
void ROT(spu_opcode_t op);
|
||||
void ROTM(spu_opcode_t op);
|
||||
void ROTMA(spu_opcode_t op);
|
||||
void SHL(spu_opcode_t op);
|
||||
void ROTH(spu_opcode_t op);
|
||||
void ROTHM(spu_opcode_t op);
|
||||
void ROTMAH(spu_opcode_t op);
|
||||
void SHLH(spu_opcode_t op);
|
||||
void ROTI(spu_opcode_t op);
|
||||
void ROTMI(spu_opcode_t op);
|
||||
void ROTMAI(spu_opcode_t op);
|
||||
void SHLI(spu_opcode_t op);
|
||||
void ROTHI(spu_opcode_t op);
|
||||
void ROTHMI(spu_opcode_t op);
|
||||
void ROTMAHI(spu_opcode_t op);
|
||||
void SHLHI(spu_opcode_t op);
|
||||
void A(spu_opcode_t op);
|
||||
void AND(spu_opcode_t op);
|
||||
void CG(spu_opcode_t op);
|
||||
void AH(spu_opcode_t op);
|
||||
void NAND(spu_opcode_t op);
|
||||
void AVGB(spu_opcode_t op);
|
||||
void MTSPR(spu_opcode_t op);
|
||||
void WRCH(spu_opcode_t op);
|
||||
void BIZ(spu_opcode_t op);
|
||||
void BINZ(spu_opcode_t op);
|
||||
void BIHZ(spu_opcode_t op);
|
||||
void BIHNZ(spu_opcode_t op);
|
||||
void STOPD(spu_opcode_t op);
|
||||
void STQX(spu_opcode_t op);
|
||||
void BI(spu_opcode_t op);
|
||||
void BISL(spu_opcode_t op);
|
||||
void IRET(spu_opcode_t op);
|
||||
void BISLED(spu_opcode_t op);
|
||||
void HBR(spu_opcode_t op);
|
||||
void GB(spu_opcode_t op);
|
||||
void GBH(spu_opcode_t op);
|
||||
void GBB(spu_opcode_t op);
|
||||
void FSM(spu_opcode_t op);
|
||||
void FSMH(spu_opcode_t op);
|
||||
void FSMB(spu_opcode_t op);
|
||||
void FREST(spu_opcode_t op);
|
||||
void FRSQEST(spu_opcode_t op);
|
||||
void LQX(spu_opcode_t op);
|
||||
void ROTQBYBI(spu_opcode_t op);
|
||||
void ROTQMBYBI(spu_opcode_t op);
|
||||
void SHLQBYBI(spu_opcode_t op);
|
||||
void CBX(spu_opcode_t op);
|
||||
void CHX(spu_opcode_t op);
|
||||
void CWX(spu_opcode_t op);
|
||||
void CDX(spu_opcode_t op);
|
||||
void ROTQBI(spu_opcode_t op);
|
||||
void ROTQMBI(spu_opcode_t op);
|
||||
void SHLQBI(spu_opcode_t op);
|
||||
void ROTQBY(spu_opcode_t op);
|
||||
void ROTQMBY(spu_opcode_t op);
|
||||
void SHLQBY(spu_opcode_t op);
|
||||
void ORX(spu_opcode_t op);
|
||||
void CBD(spu_opcode_t op);
|
||||
void CHD(spu_opcode_t op);
|
||||
void CWD(spu_opcode_t op);
|
||||
void CDD(spu_opcode_t op);
|
||||
void ROTQBII(spu_opcode_t op);
|
||||
void ROTQMBII(spu_opcode_t op);
|
||||
void SHLQBII(spu_opcode_t op);
|
||||
void ROTQBYI(spu_opcode_t op);
|
||||
void ROTQMBYI(spu_opcode_t op);
|
||||
void SHLQBYI(spu_opcode_t op);
|
||||
void NOP(spu_opcode_t op);
|
||||
void CGT(spu_opcode_t op);
|
||||
void XOR(spu_opcode_t op);
|
||||
void CGTH(spu_opcode_t op);
|
||||
void EQV(spu_opcode_t op);
|
||||
void CGTB(spu_opcode_t op);
|
||||
void SUMB(spu_opcode_t op);
|
||||
void HGT(spu_opcode_t op);
|
||||
void CLZ(spu_opcode_t op);
|
||||
void XSWD(spu_opcode_t op);
|
||||
void XSHW(spu_opcode_t op);
|
||||
void CNTB(spu_opcode_t op);
|
||||
void XSBH(spu_opcode_t op);
|
||||
void CLGT(spu_opcode_t op);
|
||||
void ANDC(spu_opcode_t op);
|
||||
void FCGT(spu_opcode_t op);
|
||||
void DFCGT(spu_opcode_t op);
|
||||
void FA(spu_opcode_t op);
|
||||
void FS(spu_opcode_t op);
|
||||
void FM(spu_opcode_t op);
|
||||
void CLGTH(spu_opcode_t op);
|
||||
void ORC(spu_opcode_t op);
|
||||
void FCMGT(spu_opcode_t op);
|
||||
void DFCMGT(spu_opcode_t op);
|
||||
void DFA(spu_opcode_t op);
|
||||
void DFS(spu_opcode_t op);
|
||||
void DFM(spu_opcode_t op);
|
||||
void CLGTB(spu_opcode_t op);
|
||||
void HLGT(spu_opcode_t op);
|
||||
void DFMA(spu_opcode_t op);
|
||||
void DFMS(spu_opcode_t op);
|
||||
void DFNMS(spu_opcode_t op);
|
||||
void DFNMA(spu_opcode_t op);
|
||||
void CEQ(spu_opcode_t op);
|
||||
void MPYHHU(spu_opcode_t op);
|
||||
void ADDX(spu_opcode_t op);
|
||||
void SFX(spu_opcode_t op);
|
||||
void CGX(spu_opcode_t op);
|
||||
void BGX(spu_opcode_t op);
|
||||
void MPYHHA(spu_opcode_t op);
|
||||
void MPYHHAU(spu_opcode_t op);
|
||||
void FSCRRD(spu_opcode_t op);
|
||||
void FESD(spu_opcode_t op);
|
||||
void FRDS(spu_opcode_t op);
|
||||
void FSCRWR(spu_opcode_t op);
|
||||
void DFTSV(spu_opcode_t op);
|
||||
void FCEQ(spu_opcode_t op);
|
||||
void DFCEQ(spu_opcode_t op);
|
||||
void MPY(spu_opcode_t op);
|
||||
void MPYH(spu_opcode_t op);
|
||||
void MPYHH(spu_opcode_t op);
|
||||
void MPYS(spu_opcode_t op);
|
||||
void CEQH(spu_opcode_t op);
|
||||
void FCMEQ(spu_opcode_t op);
|
||||
void DFCMEQ(spu_opcode_t op);
|
||||
void MPYU(spu_opcode_t op);
|
||||
void CEQB(spu_opcode_t op);
|
||||
void FI(spu_opcode_t op);
|
||||
void HEQ(spu_opcode_t op);
|
||||
void CFLTS(spu_opcode_t op);
|
||||
void CFLTU(spu_opcode_t op);
|
||||
void CSFLT(spu_opcode_t op);
|
||||
void CUFLT(spu_opcode_t op);
|
||||
void BRZ(spu_opcode_t op);
|
||||
void STQA(spu_opcode_t op);
|
||||
void BRNZ(spu_opcode_t op);
|
||||
void BRHZ(spu_opcode_t op);
|
||||
void BRHNZ(spu_opcode_t op);
|
||||
void STQR(spu_opcode_t op);
|
||||
void BRA(spu_opcode_t op);
|
||||
void LQA(spu_opcode_t op);
|
||||
void BRASL(spu_opcode_t op);
|
||||
void BR(spu_opcode_t op);
|
||||
void FSMBI(spu_opcode_t op);
|
||||
void BRSL(spu_opcode_t op);
|
||||
void LQR(spu_opcode_t op);
|
||||
void IL(spu_opcode_t op);
|
||||
void ILHU(spu_opcode_t op);
|
||||
void ILH(spu_opcode_t op);
|
||||
void IOHL(spu_opcode_t op);
|
||||
void ORI(spu_opcode_t op);
|
||||
void ORHI(spu_opcode_t op);
|
||||
void ORBI(spu_opcode_t op);
|
||||
void SFI(spu_opcode_t op);
|
||||
void SFHI(spu_opcode_t op);
|
||||
void ANDI(spu_opcode_t op);
|
||||
void ANDHI(spu_opcode_t op);
|
||||
void ANDBI(spu_opcode_t op);
|
||||
void AI(spu_opcode_t op);
|
||||
void AHI(spu_opcode_t op);
|
||||
void STQD(spu_opcode_t op);
|
||||
void LQD(spu_opcode_t op);
|
||||
void XORI(spu_opcode_t op);
|
||||
void XORHI(spu_opcode_t op);
|
||||
void XORBI(spu_opcode_t op);
|
||||
void CGTI(spu_opcode_t op);
|
||||
void CGTHI(spu_opcode_t op);
|
||||
void CGTBI(spu_opcode_t op);
|
||||
void HGTI(spu_opcode_t op);
|
||||
void CLGTI(spu_opcode_t op);
|
||||
void CLGTHI(spu_opcode_t op);
|
||||
void CLGTBI(spu_opcode_t op);
|
||||
void HLGTI(spu_opcode_t op);
|
||||
void MPYI(spu_opcode_t op);
|
||||
void MPYUI(spu_opcode_t op);
|
||||
void CEQI(spu_opcode_t op);
|
||||
void CEQHI(spu_opcode_t op);
|
||||
void CEQBI(spu_opcode_t op);
|
||||
void HEQI(spu_opcode_t op);
|
||||
void HBRA(spu_opcode_t op);
|
||||
void HBRR(spu_opcode_t op);
|
||||
void ILA(spu_opcode_t op);
|
||||
void SELB(spu_opcode_t op);
|
||||
void SHUFB(spu_opcode_t op);
|
||||
void MPYA(spu_opcode_t op);
|
||||
void FNMS(spu_opcode_t op);
|
||||
void FMA(spu_opcode_t op);
|
||||
void FMS(spu_opcode_t op);
|
||||
|
||||
void UNK(spu_opcode_t op);
|
||||
|
||||
static const spu_opcode_table_t<void(spu_recompiler::*)(spu_opcode_t)> opcodes;
|
||||
};
|
267
rpcs3/Emu/Cell/SPUAnalyser.cpp
Normal file
267
rpcs3/Emu/Cell/SPUAnalyser.cpp
Normal file
@ -0,0 +1,267 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
|
||||
#include "Crypto/sha1.h"
|
||||
#include "SPURecompiler.h"
|
||||
#include "SPUAnalyser.h"
|
||||
|
||||
const spu_opcode_table_t<spu_itype_t> g_spu_itype{ DEFINE_SPU_OPCODES(spu_itype::), spu_itype::UNK };
|
||||
|
||||
SPUDatabase::SPUDatabase()
|
||||
{
|
||||
// TODO: load existing database associated with currently running executable
|
||||
|
||||
LOG_SUCCESS(SPU, "SPU Database initialized...");
|
||||
}
|
||||
|
||||
SPUDatabase::~SPUDatabase()
|
||||
{
|
||||
// TODO: serialize database
|
||||
}
|
||||
|
||||
std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 entry, u32 max_limit)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
// Check arguments (bounds and alignment)
|
||||
if (max_limit > 0x40000 || entry >= max_limit || entry % 4 || max_limit % 4)
|
||||
{
|
||||
throw EXCEPTION("Invalid arguments (entry=0x%05x, limit=0x%05x)", entry, max_limit);
|
||||
}
|
||||
|
||||
// Key for multimap
|
||||
const u64 key = entry | u64{ ls[entry / 4] } << 32;
|
||||
|
||||
// Try to find existing function in the database
|
||||
for (auto found = m_db.find(key); found != m_db.end(); found++)
|
||||
{
|
||||
// Compare binary data explicitly (TODO: optimize)
|
||||
if (std::equal(found->second->data.begin(), found->second->data.end(), ls + entry / 4))
|
||||
{
|
||||
return found->second;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize block entries with the function entry point
|
||||
std::set<u32> blocks{ entry };
|
||||
|
||||
// Entries of adjacent functions; jump table entries
|
||||
std::set<u32> adjacent, jt;
|
||||
|
||||
// Set initial limit which will be narrowed later
|
||||
u32 limit = max_limit;
|
||||
|
||||
// Find preliminary set of possible block entries (first pass), `start` is the current block address
|
||||
for (u32 start = entry, pos = entry; pos < limit; pos += 4)
|
||||
{
|
||||
const spu_opcode_t op{ ls[pos / 4] };
|
||||
|
||||
const spu_itype_t type = g_spu_itype[op.opcode];
|
||||
|
||||
using namespace spu_itype;
|
||||
|
||||
if (start == pos) // Additional analysis at the beginning of the block (questionable)
|
||||
{
|
||||
// Possible jump table
|
||||
std::vector<u32> jt_abs, jt_rel;
|
||||
|
||||
for (; pos < limit; pos += 4)
|
||||
{
|
||||
const u32 target = ls[pos / 4];
|
||||
|
||||
if (target % 4)
|
||||
{
|
||||
// Misaligned address: abort analysis
|
||||
break;
|
||||
}
|
||||
|
||||
if (target >= entry && target < limit)
|
||||
{
|
||||
// Possible jump table entry (absolute)
|
||||
jt_abs.emplace_back(target);
|
||||
}
|
||||
|
||||
if (target + start >= entry && target + start < limit)
|
||||
{
|
||||
// Possible jump table entry (relative)
|
||||
jt_rel.emplace_back(target + start);
|
||||
}
|
||||
|
||||
if (std::max(jt_abs.size(), jt_rel.size()) * 4 + start <= pos)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos - start >= 8)
|
||||
{
|
||||
// Register jump table block (at least 2 entries) as an ordinary block
|
||||
blocks.emplace(start);
|
||||
|
||||
// Register jump table entries (absolute)
|
||||
if (jt_abs.size() * 4 == pos - start)
|
||||
{
|
||||
blocks.insert(jt_abs.begin(), jt_abs.end());
|
||||
|
||||
jt.insert(jt_abs.begin(), jt_abs.end());
|
||||
}
|
||||
|
||||
// Register jump table entries (relative)
|
||||
if (jt_rel.size() * 4 == pos - start)
|
||||
{
|
||||
blocks.insert(jt_rel.begin(), jt_rel.end());
|
||||
|
||||
jt.insert(jt_rel.begin(), jt_rel.end());
|
||||
}
|
||||
|
||||
// Fix pos value
|
||||
start = pos; pos = pos - 4;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Restore pos value
|
||||
pos = start;
|
||||
}
|
||||
|
||||
if (!type || (start == pos && start > *blocks.rbegin())) // Invalid instruction or "unrelated" block started
|
||||
{
|
||||
// Discard current block and abort the operation
|
||||
limit = start;
|
||||
|
||||
break;
|
||||
}
|
||||
else if (op.opcode == 0) // Hack: special case (STOP 0)
|
||||
{
|
||||
limit = pos + 4;
|
||||
|
||||
break;
|
||||
}
|
||||
else if (type == BI) // Branch Indirect
|
||||
{
|
||||
blocks.emplace(start); start = pos + 4;
|
||||
}
|
||||
else if (type == BR || type == BRA) // Branch Relative/Absolute
|
||||
{
|
||||
const u32 target = spu_branch_target(type == BR ? pos : 0, op.i16);
|
||||
|
||||
// Add adjacent function because it always could be
|
||||
adjacent.emplace(target);
|
||||
|
||||
if (target > entry)
|
||||
{
|
||||
blocks.emplace(target);
|
||||
}
|
||||
|
||||
blocks.emplace(start); start = pos + 4;
|
||||
}
|
||||
else if (type == BRSL || type == BRASL) // Branch Relative/Absolute and Set Link
|
||||
{
|
||||
const u32 target = spu_branch_target(type == BRSL ? pos : 0, op.i16);
|
||||
|
||||
if (target == pos + 4)
|
||||
{
|
||||
// Branch to the next instruction and set link ("get next instruction address" idiom)
|
||||
|
||||
if (op.rt == 0) LOG_ERROR(SPU, "Suspicious instruction at [0x%05x]", pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add adjacent function
|
||||
adjacent.emplace(target);
|
||||
|
||||
if (target > entry)
|
||||
{
|
||||
limit = std::min<u32>(limit, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type == BISL) // Branch Indirect and Set Link
|
||||
{
|
||||
// Nothing
|
||||
}
|
||||
else if (type == BRNZ || type == BRZ || type == BRHNZ || type == BRHZ) // Branch Relative if (Not) Zero Word/Halfword
|
||||
{
|
||||
const u32 target = spu_branch_target(pos, op.i16);
|
||||
|
||||
// Add adjacent function because it always could be
|
||||
adjacent.emplace(target);
|
||||
|
||||
if (target > entry)
|
||||
{
|
||||
blocks.emplace(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find more function calls (second pass, questionable)
|
||||
for (u32 pos = 0; pos < 0x40000; pos += 4)
|
||||
{
|
||||
const spu_opcode_t op{ ls[pos / 4] };
|
||||
|
||||
const spu_itype_t type = g_spu_itype[op.opcode];
|
||||
|
||||
using namespace spu_itype;
|
||||
|
||||
if (!type) // Invalid instruction
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (type == BRSL || type == BRASL) // Branch Relative/Absolute and Set Link
|
||||
{
|
||||
const u32 target = spu_branch_target(type == BRSL ? pos : 0, op.i16);
|
||||
|
||||
if (target != pos + 4 && target > entry && limit > target)
|
||||
{
|
||||
// Narrow the limit
|
||||
limit = target;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (limit <= entry)
|
||||
{
|
||||
LOG_ERROR(SPU, "Function not found [0x%05x]", entry);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Prepare new function (set addr and size)
|
||||
auto func = std::make_shared<spu_function_t>(entry, limit - entry);
|
||||
|
||||
// Fill function block info
|
||||
for (auto i = blocks.crbegin(); i != blocks.crend(); i++)
|
||||
{
|
||||
if (limit > *i)
|
||||
{
|
||||
func->blocks.emplace_hint(func->blocks.begin(), *i);
|
||||
}
|
||||
}
|
||||
|
||||
// Fill adjacent function info
|
||||
for (auto i = adjacent.crbegin(); i != adjacent.crend(); i++)
|
||||
{
|
||||
if (limit <= *i || entry >= *i)
|
||||
{
|
||||
func->adjacent.emplace_hint(func->adjacent.begin(), *i);
|
||||
}
|
||||
}
|
||||
|
||||
// Fill jump table entries
|
||||
for (auto i = jt.crbegin(); i != jt.crend(); i++)
|
||||
{
|
||||
if (limit > *i)
|
||||
{
|
||||
func->jtable.emplace_hint(func->jtable.begin(), *i);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy function contents
|
||||
func->data = { ls + entry / 4, ls + limit / 4 };
|
||||
|
||||
// Add function to the database
|
||||
m_db.emplace(key, func);
|
||||
|
||||
LOG_SUCCESS(SPU, "Function detected [0x%05x-0x%05x] (size=0x%x)", func->addr, func->addr + func->size, func->size);
|
||||
|
||||
return func;
|
||||
}
|
269
rpcs3/Emu/Cell/SPUAnalyser.h
Normal file
269
rpcs3/Emu/Cell/SPUAnalyser.h
Normal file
@ -0,0 +1,269 @@
|
||||
#pragma once
|
||||
|
||||
#include "Emu/Cell/SPUOpcodes.h"
|
||||
|
||||
class SPUThread;
|
||||
|
||||
// Type of the runtime functions generated by SPU recompiler
|
||||
using spu_jit_func_t = u32(*)(SPUThread* _spu, be_t<u32>* _ls);
|
||||
|
||||
// SPU instruction classification namespace
|
||||
namespace spu_itype
|
||||
{
|
||||
enum spu_itype_t : u32
|
||||
{
|
||||
UNK = 0,
|
||||
|
||||
STOP,
|
||||
LNOP,
|
||||
SYNC,
|
||||
DSYNC,
|
||||
MFSPR,
|
||||
RDCH,
|
||||
RCHCNT,
|
||||
SF,
|
||||
OR,
|
||||
BG,
|
||||
SFH,
|
||||
NOR,
|
||||
ABSDB,
|
||||
ROT,
|
||||
ROTM,
|
||||
ROTMA,
|
||||
SHL,
|
||||
ROTH,
|
||||
ROTHM,
|
||||
ROTMAH,
|
||||
SHLH,
|
||||
ROTI,
|
||||
ROTMI,
|
||||
ROTMAI,
|
||||
SHLI,
|
||||
ROTHI,
|
||||
ROTHMI,
|
||||
ROTMAHI,
|
||||
SHLHI,
|
||||
A,
|
||||
AND,
|
||||
CG,
|
||||
AH,
|
||||
NAND,
|
||||
AVGB,
|
||||
MTSPR,
|
||||
WRCH,
|
||||
BIZ,
|
||||
BINZ,
|
||||
BIHZ,
|
||||
BIHNZ,
|
||||
STOPD,
|
||||
STQX,
|
||||
BI,
|
||||
BISL,
|
||||
IRET,
|
||||
BISLED,
|
||||
HBR,
|
||||
GB,
|
||||
GBH,
|
||||
GBB,
|
||||
FSM,
|
||||
FSMH,
|
||||
FSMB,
|
||||
FREST,
|
||||
FRSQEST,
|
||||
LQX,
|
||||
ROTQBYBI,
|
||||
ROTQMBYBI,
|
||||
SHLQBYBI,
|
||||
CBX,
|
||||
CHX,
|
||||
CWX,
|
||||
CDX,
|
||||
ROTQBI,
|
||||
ROTQMBI,
|
||||
SHLQBI,
|
||||
ROTQBY,
|
||||
ROTQMBY,
|
||||
SHLQBY,
|
||||
ORX,
|
||||
CBD,
|
||||
CHD,
|
||||
CWD,
|
||||
CDD,
|
||||
ROTQBII,
|
||||
ROTQMBII,
|
||||
SHLQBII,
|
||||
ROTQBYI,
|
||||
ROTQMBYI,
|
||||
SHLQBYI,
|
||||
NOP,
|
||||
CGT,
|
||||
XOR,
|
||||
CGTH,
|
||||
EQV,
|
||||
CGTB,
|
||||
SUMB,
|
||||
HGT,
|
||||
CLZ,
|
||||
XSWD,
|
||||
XSHW,
|
||||
CNTB,
|
||||
XSBH,
|
||||
CLGT,
|
||||
ANDC,
|
||||
FCGT,
|
||||
DFCGT,
|
||||
FA,
|
||||
FS,
|
||||
FM,
|
||||
CLGTH,
|
||||
ORC,
|
||||
FCMGT,
|
||||
DFCMGT,
|
||||
DFA,
|
||||
DFS,
|
||||
DFM,
|
||||
CLGTB,
|
||||
HLGT,
|
||||
DFMA,
|
||||
DFMS,
|
||||
DFNMS,
|
||||
DFNMA,
|
||||
CEQ,
|
||||
MPYHHU,
|
||||
ADDX,
|
||||
SFX,
|
||||
CGX,
|
||||
BGX,
|
||||
MPYHHA,
|
||||
MPYHHAU,
|
||||
FSCRRD,
|
||||
FESD,
|
||||
FRDS,
|
||||
FSCRWR,
|
||||
DFTSV,
|
||||
FCEQ,
|
||||
DFCEQ,
|
||||
MPY,
|
||||
MPYH,
|
||||
MPYHH,
|
||||
MPYS,
|
||||
CEQH,
|
||||
FCMEQ,
|
||||
DFCMEQ,
|
||||
MPYU,
|
||||
CEQB,
|
||||
FI,
|
||||
HEQ,
|
||||
CFLTS,
|
||||
CFLTU,
|
||||
CSFLT,
|
||||
CUFLT,
|
||||
BRZ,
|
||||
STQA,
|
||||
BRNZ,
|
||||
BRHZ,
|
||||
BRHNZ,
|
||||
STQR,
|
||||
BRA,
|
||||
LQA,
|
||||
BRASL,
|
||||
BR,
|
||||
FSMBI,
|
||||
BRSL,
|
||||
LQR,
|
||||
IL,
|
||||
ILHU,
|
||||
ILH,
|
||||
IOHL,
|
||||
ORI,
|
||||
ORHI,
|
||||
ORBI,
|
||||
SFI,
|
||||
SFHI,
|
||||
ANDI,
|
||||
ANDHI,
|
||||
ANDBI,
|
||||
AI,
|
||||
AHI,
|
||||
STQD,
|
||||
LQD,
|
||||
XORI,
|
||||
XORHI,
|
||||
XORBI,
|
||||
CGTI,
|
||||
CGTHI,
|
||||
CGTBI,
|
||||
HGTI,
|
||||
CLGTI,
|
||||
CLGTHI,
|
||||
CLGTBI,
|
||||
HLGTI,
|
||||
MPYI,
|
||||
MPYUI,
|
||||
CEQI,
|
||||
CEQHI,
|
||||
CEQBI,
|
||||
HEQI,
|
||||
HBRA,
|
||||
HBRR,
|
||||
ILA,
|
||||
SELB,
|
||||
SHUFB,
|
||||
MPYA,
|
||||
FNMS,
|
||||
FMA,
|
||||
FMS,
|
||||
};
|
||||
}
|
||||
|
||||
using spu_itype::spu_itype_t;
|
||||
|
||||
// SPU Instruction Classification table
|
||||
extern const spu_opcode_table_t<spu_itype_t> g_spu_itype;
|
||||
|
||||
// SPU basic function information structure
|
||||
struct spu_function_t
|
||||
{
|
||||
// entry point (LS address)
|
||||
const u32 addr;
|
||||
|
||||
// function size (in bytes)
|
||||
const u32 size;
|
||||
|
||||
// function contents (binary copy)
|
||||
std::vector<be_t<u32>> data;
|
||||
|
||||
// basic blocks (start addresses)
|
||||
std::set<u32> blocks;
|
||||
|
||||
// functions possibly called by this function (may not be available)
|
||||
std::set<u32> adjacent;
|
||||
|
||||
// jump table values (start addresses)
|
||||
std::set<u32> jtable;
|
||||
|
||||
// pointer to the compiled function
|
||||
spu_jit_func_t compiled = nullptr;
|
||||
|
||||
spu_function_t(u32 addr, u32 size)
|
||||
: addr(addr)
|
||||
, size(size)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// SPU Function Database (must be global or PS3 process-local)
|
||||
class SPUDatabase final
|
||||
{
|
||||
std::mutex m_mutex;
|
||||
|
||||
// All registered functions (uses addr and first instruction as a key)
|
||||
std::unordered_multimap<u64, std::shared_ptr<spu_function_t>> m_db;
|
||||
|
||||
public:
|
||||
SPUDatabase();
|
||||
~SPUDatabase();
|
||||
|
||||
// Try to retrieve SPU function information
|
||||
std::shared_ptr<spu_function_t> analyse(const be_t<u32>* ls, u32 entry, u32 limit = 0x40000);
|
||||
};
|
@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
struct SPUContext
|
||||
struct spu_context_t
|
||||
{
|
||||
v128 gpr[128];
|
||||
};
|
||||
|
@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Emu/Cell/SPUOpcodes.h"
|
||||
#include "Emu/Cell/PPCDecoder.h"
|
||||
#include "Emu/Cell/SPUInstrTable.h"
|
||||
|
||||
class SPUDecoder : public PPCDecoder
|
||||
{
|
||||
SPUOpcodes* m_op;
|
||||
|
||||
public:
|
||||
SPUDecoder(SPUOpcodes& op) : m_op(&op)
|
||||
{
|
||||
}
|
||||
|
||||
~SPUDecoder()
|
||||
{
|
||||
delete m_op;
|
||||
}
|
||||
|
||||
virtual void Decode(const u32 code)
|
||||
{
|
||||
(*SPU_instr::rrr_list)(m_op, code);
|
||||
}
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -1,259 +0,0 @@
|
||||
#pragma once
|
||||
#include "PPCDecoder.h"
|
||||
#include "SPUOpcodes.h"
|
||||
|
||||
namespace SPU_instr
|
||||
{
|
||||
static CodeField<4, 10> RC(FIELD_R_GPR);
|
||||
static CodeField<25, 31> RT(FIELD_R_GPR);
|
||||
static CodeField<18, 24> RA(FIELD_R_GPR);
|
||||
static CodeField<11, 17> RB(FIELD_R_GPR);
|
||||
|
||||
static CodeField<11, 17> i7;
|
||||
static CodeField<10, 17> i8;
|
||||
static CodeField<8, 17> i10;
|
||||
static CodeField<9, 24> i16;
|
||||
static CodeField<7, 24> i18;
|
||||
|
||||
static CodeFieldSigned<11, 17> si7;
|
||||
static CodeFieldSigned<10, 17> si8;
|
||||
static CodeFieldSigned<8, 17> si10;
|
||||
static CodeFieldSignedOffset<8, 17, 4> si10s4;
|
||||
static CodeFieldSigned<9, 24> si16;
|
||||
static CodeFieldOffset<9, 24, 2> i16s2;
|
||||
static CodeFieldSigned<7, 24> si18;
|
||||
|
||||
static CodeField<16, 17> ROH;
|
||||
static CodeField<25, 31> ROL;
|
||||
static DoubleCodeField<16, 17, 25, 31, 8> RO;
|
||||
|
||||
static CodeField<0, 3> RRR;
|
||||
static CodeField<0, 6> RI18;
|
||||
static CodeField<0, 7> RI10;
|
||||
static CodeField<0, 8> RI16;
|
||||
static CodeField<0, 9> RI8;
|
||||
static CodeField<0, 10> RI7;
|
||||
static CodeField<0, 10> RR;
|
||||
|
||||
static CodeField<18, 31> L_18_31;
|
||||
static CodeField<11> L_11;
|
||||
|
||||
// static auto rrr_list = new_list<SPUOpcodes>(RRR);
|
||||
static InstrList<1 << CodeField<0, 3>::size, SPUOpcodes> rrr_list_obj(RRR, nullptr);
|
||||
static auto rrr_list = &rrr_list_obj;
|
||||
static auto ri18_list = new_list(rrr_list, RI18);
|
||||
static auto ri10_list = new_list(ri18_list, RI10);
|
||||
static auto ri16_list = new_list(ri10_list, RI16);
|
||||
static auto ri8_list = new_list(ri16_list, RI8);
|
||||
static auto ri7_list = new_list(ri8_list, RI7, instr_bind(&SPUOpcodes::UNK, GetCode, RRR, RI7));
|
||||
|
||||
#define bind_instr(list, name, ...) \
|
||||
static const auto& name = make_instr<SPU_opcodes::name>(list, #name, &SPUOpcodes::name, ##__VA_ARGS__)
|
||||
|
||||
bind_instr(ri7_list, STOP, L_18_31);
|
||||
bind_instr(ri7_list, LNOP);
|
||||
bind_instr(ri7_list, SYNC, L_11);
|
||||
bind_instr(ri7_list, DSYNC);
|
||||
bind_instr(ri7_list, MFSPR, RT, RA);
|
||||
bind_instr(ri7_list, RDCH, RT, RA);
|
||||
bind_instr(ri7_list, RCHCNT, RT, RA);
|
||||
bind_instr(ri7_list, SF, RT, RA, RB);
|
||||
bind_instr(ri7_list, OR, RT, RA, RB);
|
||||
bind_instr(ri7_list, BG, RT, RA, RB);
|
||||
bind_instr(ri7_list, SFH, RT, RA, RB);
|
||||
bind_instr(ri7_list, NOR, RT, RA, RB);
|
||||
bind_instr(ri7_list, ABSDB, RT, RA, RB);
|
||||
bind_instr(ri7_list, ROT, RT, RA, RB);
|
||||
bind_instr(ri7_list, ROTM, RT, RA, RB);
|
||||
bind_instr(ri7_list, ROTMA, RT, RA, RB);
|
||||
bind_instr(ri7_list, SHL, RT, RA, RB);
|
||||
bind_instr(ri7_list, ROTH, RT, RA, RB);
|
||||
bind_instr(ri7_list, ROTHM, RT, RA, RB);
|
||||
bind_instr(ri7_list, ROTMAH, RT, RA, RB);
|
||||
bind_instr(ri7_list, SHLH, RT, RA, RB);
|
||||
bind_instr(ri7_list, ROTI, RT, RA, RB);
|
||||
bind_instr(ri7_list, ROTMI, RT, RA, RB);
|
||||
bind_instr(ri7_list, ROTMAI, RT, RA, RB);
|
||||
bind_instr(ri7_list, SHLI, RT, RA, i7);
|
||||
bind_instr(ri7_list, ROTHI, RT, RA, i7);
|
||||
bind_instr(ri7_list, ROTHMI, RT, RA, i7);
|
||||
bind_instr(ri7_list, ROTMAHI, RT, RA, i7);
|
||||
bind_instr(ri7_list, SHLHI, RT, RA, i7);
|
||||
bind_instr(ri7_list, A, RT, RA, RB);
|
||||
bind_instr(ri7_list, AND, RT, RA, RB);
|
||||
bind_instr(ri7_list, CG, RT, RA, RB);
|
||||
bind_instr(ri7_list, AH, RT, RA, RB);
|
||||
bind_instr(ri7_list, NAND, RT, RA, RB);
|
||||
bind_instr(ri7_list, AVGB, RT, RA, RB);
|
||||
bind_instr(ri7_list, MTSPR, RT, RA);
|
||||
bind_instr(ri7_list, WRCH, RA, RT);
|
||||
bind_instr(ri7_list, BIZ, RB, RT, RA);
|
||||
bind_instr(ri7_list, BINZ, RB, RT, RA);
|
||||
bind_instr(ri7_list, BIHZ, RB, RT, RA);
|
||||
bind_instr(ri7_list, BIHNZ, RB, RT, RA);
|
||||
bind_instr(ri7_list, STOPD, RT, RA, RB);
|
||||
bind_instr(ri7_list, STQX, RT, RA, RB);
|
||||
bind_instr(ri7_list, BI, RB, RA);
|
||||
bind_instr(ri7_list, BISL, RB, RT, RA);
|
||||
bind_instr(ri7_list, IRET, RA);
|
||||
bind_instr(ri7_list, BISLED, RB, RT, RA);
|
||||
bind_instr(ri7_list, HBR, L_11, RO, RA);
|
||||
bind_instr(ri7_list, GB, RT, RA);
|
||||
bind_instr(ri7_list, GBH, RT, RA);
|
||||
bind_instr(ri7_list, GBB, RT, RA);
|
||||
bind_instr(ri7_list, FSM, RT, RA);
|
||||
bind_instr(ri7_list, FSMH, RT, RA);
|
||||
bind_instr(ri7_list, FSMB, RT, RA);
|
||||
bind_instr(ri7_list, FREST, RT, RA);
|
||||
bind_instr(ri7_list, FRSQEST, RT, RA);
|
||||
bind_instr(ri7_list, LQX, RT, RA, RB);
|
||||
bind_instr(ri7_list, ROTQBYBI, RT, RA, RB);
|
||||
bind_instr(ri7_list, ROTQMBYBI, RT, RA, RB);
|
||||
bind_instr(ri7_list, SHLQBYBI, RT, RA, RB);
|
||||
bind_instr(ri7_list, CBX, RT, RA, RB);
|
||||
bind_instr(ri7_list, CHX, RT, RA, RB);
|
||||
bind_instr(ri7_list, CWX, RT, RA, RB);
|
||||
bind_instr(ri7_list, CDX, RT, RA, RB);
|
||||
bind_instr(ri7_list, ROTQBI, RT, RA, RB);
|
||||
bind_instr(ri7_list, ROTQMBI, RT, RA, RB);
|
||||
bind_instr(ri7_list, SHLQBI, RT, RA, RB);
|
||||
bind_instr(ri7_list, ROTQBY, RT, RA, RB);
|
||||
bind_instr(ri7_list, ROTQMBY, RT, RA, RB);
|
||||
bind_instr(ri7_list, SHLQBY, RT, RA, RB);
|
||||
bind_instr(ri7_list, ORX, RT, RA);
|
||||
bind_instr(ri7_list, CBD, RT, RA, si7);
|
||||
bind_instr(ri7_list, CHD, RT, RA, si7);
|
||||
bind_instr(ri7_list, CWD, RT, RA, si7);
|
||||
bind_instr(ri7_list, CDD, RT, RA, si7);
|
||||
bind_instr(ri7_list, ROTQBII, RT, RA, i7);
|
||||
bind_instr(ri7_list, ROTQMBII, RT, RA, i7);
|
||||
bind_instr(ri7_list, SHLQBII, RT, RA, i7);
|
||||
bind_instr(ri7_list, ROTQBYI, RT, RA, i7);
|
||||
bind_instr(ri7_list, ROTQMBYI, RT, RA, i7);
|
||||
bind_instr(ri7_list, SHLQBYI, RT, RA, i7);
|
||||
bind_instr(ri7_list, NOP, RT);
|
||||
bind_instr(ri7_list, CGT, RT, RA, RB);
|
||||
bind_instr(ri7_list, XOR, RT, RA, RB);
|
||||
bind_instr(ri7_list, CGTH, RT, RA, RB);
|
||||
bind_instr(ri7_list, EQV, RT, RA, RB);
|
||||
bind_instr(ri7_list, CGTB, RT, RA, RB);
|
||||
bind_instr(ri7_list, SUMB, RT, RA, RB);
|
||||
bind_instr(ri7_list, HGT, RT, RA, RB);
|
||||
bind_instr(ri7_list, CLZ, RT, RA);
|
||||
bind_instr(ri7_list, XSWD, RT, RA);
|
||||
bind_instr(ri7_list, XSHW, RT, RA);
|
||||
bind_instr(ri7_list, CNTB, RT, RA);
|
||||
bind_instr(ri7_list, XSBH, RT, RA);
|
||||
bind_instr(ri7_list, CLGT, RT, RA, RB);
|
||||
bind_instr(ri7_list, ANDC, RT, RA, RB);
|
||||
bind_instr(ri7_list, FCGT, RT, RA, RB);
|
||||
bind_instr(ri7_list, DFCGT, RT, RA, RB);
|
||||
bind_instr(ri7_list, FA, RT, RA, RB);
|
||||
bind_instr(ri7_list, FS, RT, RA, RB);
|
||||
bind_instr(ri7_list, FM, RT, RA, RB);
|
||||
bind_instr(ri7_list, CLGTH, RT, RA, RB);
|
||||
bind_instr(ri7_list, ORC, RT, RA, RB);
|
||||
bind_instr(ri7_list, FCMGT, RT, RA, RB);
|
||||
bind_instr(ri7_list, DFCMGT, RT, RA, RB);
|
||||
bind_instr(ri7_list, DFA, RT, RA, RB);
|
||||
bind_instr(ri7_list, DFS, RT, RA, RB);
|
||||
bind_instr(ri7_list, DFM, RT, RA, RB);
|
||||
bind_instr(ri7_list, CLGTB, RT, RA, RB);
|
||||
bind_instr(ri7_list, HLGT, RT, RA, RB);
|
||||
bind_instr(ri7_list, DFMA, RT, RA, RB);
|
||||
bind_instr(ri7_list, DFMS, RT, RA, RB);
|
||||
bind_instr(ri7_list, DFNMS, RT, RA, RB);
|
||||
bind_instr(ri7_list, DFNMA, RT, RA, RB);
|
||||
bind_instr(ri7_list, CEQ, RT, RA, RB);
|
||||
bind_instr(ri7_list, MPYHHU, RT, RA, RB);
|
||||
bind_instr(ri7_list, ADDX, RT, RA, RB);
|
||||
bind_instr(ri7_list, SFX, RT, RA, RB);
|
||||
bind_instr(ri7_list, CGX, RT, RA, RB);
|
||||
bind_instr(ri7_list, BGX, RT, RA, RB);
|
||||
bind_instr(ri7_list, MPYHHA, RT, RA, RB);
|
||||
bind_instr(ri7_list, MPYHHAU, RT, RA, RB);
|
||||
bind_instr(ri7_list, FSCRRD, RT);
|
||||
bind_instr(ri7_list, FESD, RT, RA);
|
||||
bind_instr(ri7_list, FRDS, RT, RA);
|
||||
bind_instr(ri7_list, FSCRWR, RT, RA);
|
||||
bind_instr(ri7_list, DFTSV, RT, RA, i7);
|
||||
bind_instr(ri7_list, FCEQ, RT, RA, RB);
|
||||
bind_instr(ri7_list, DFCEQ, RT, RA, RB);
|
||||
bind_instr(ri7_list, MPY, RT, RA, RB);
|
||||
bind_instr(ri7_list, MPYH, RT, RA, RB);
|
||||
bind_instr(ri7_list, MPYHH, RT, RA, RB);
|
||||
bind_instr(ri7_list, MPYS, RT, RA, RB);
|
||||
bind_instr(ri7_list, CEQH, RT, RA, RB);
|
||||
bind_instr(ri7_list, FCMEQ, RT, RA, RB);
|
||||
bind_instr(ri7_list, DFCMEQ, RT, RA, RB);
|
||||
bind_instr(ri7_list, MPYU, RT, RA, RB);
|
||||
bind_instr(ri7_list, CEQB, RT, RA, RB);
|
||||
bind_instr(ri7_list, FI, RT, RA, RB);
|
||||
bind_instr(ri7_list, HEQ, RT, RA, RB);
|
||||
|
||||
bind_instr(ri8_list, CFLTS, RT, RA, i8);
|
||||
bind_instr(ri8_list, CFLTU, RT, RA, i8);
|
||||
bind_instr(ri8_list, CSFLT, RT, RA, i8);
|
||||
bind_instr(ri8_list, CUFLT, RT, RA, i8);
|
||||
|
||||
bind_instr(ri16_list, BRZ, RT, si16);
|
||||
bind_instr(ri16_list, STQA, RT, si16);
|
||||
bind_instr(ri16_list, BRNZ, RT, si16);
|
||||
bind_instr(ri16_list, BRHZ, RT, si16);
|
||||
bind_instr(ri16_list, BRHNZ, RT, si16);
|
||||
bind_instr(ri16_list, STQR, RT, i16);
|
||||
bind_instr(ri16_list, BRA, si16);
|
||||
bind_instr(ri16_list, LQA, RT, si16);
|
||||
bind_instr(ri16_list, BRASL, RT, si16);
|
||||
bind_instr(ri16_list, BR, si16);
|
||||
bind_instr(ri16_list, FSMBI, RT, i16);
|
||||
bind_instr(ri16_list, BRSL, RT, si16);
|
||||
bind_instr(ri16_list, LQR, RT, si16);
|
||||
bind_instr(ri16_list, IL, RT, si16);
|
||||
bind_instr(ri16_list, ILHU, RT, i16);
|
||||
bind_instr(ri16_list, ILH, RT, i16);
|
||||
bind_instr(ri16_list, IOHL, RT, i16);
|
||||
|
||||
bind_instr(ri10_list, ORI, RT, RA, si10);
|
||||
bind_instr(ri10_list, ORHI, RT, RA, si10);
|
||||
bind_instr(ri10_list, ORBI, RT, RA, i10);
|
||||
bind_instr(ri10_list, SFI, RT, RA, si10);
|
||||
bind_instr(ri10_list, SFHI, RT, RA, si10);
|
||||
bind_instr(ri10_list, ANDI, RT, RA, si10);
|
||||
bind_instr(ri10_list, ANDHI, RT, RA, si10);
|
||||
bind_instr(ri10_list, ANDBI, RT, RA, i10);
|
||||
bind_instr(ri10_list, AI, RT, RA, si10);
|
||||
bind_instr(ri10_list, AHI, RT, RA, si10);
|
||||
bind_instr(ri10_list, STQD, RT, si10s4, RA);
|
||||
bind_instr(ri10_list, LQD, RT, si10s4, RA);
|
||||
bind_instr(ri10_list, XORI, RT, RA, si10);
|
||||
bind_instr(ri10_list, XORHI, RT, RA, si10);
|
||||
bind_instr(ri10_list, XORBI, RT, RA, i10);
|
||||
bind_instr(ri10_list, CGTI, RT, RA, si10);
|
||||
bind_instr(ri10_list, CGTHI, RT, RA, si10);
|
||||
bind_instr(ri10_list, CGTBI, RT, RA, i10);
|
||||
bind_instr(ri10_list, HGTI, RT, RA, si10);
|
||||
bind_instr(ri10_list, CLGTI, RT, RA, si10);
|
||||
bind_instr(ri10_list, CLGTHI, RT, RA, si10);
|
||||
bind_instr(ri10_list, CLGTBI, RT, RA, i10);
|
||||
bind_instr(ri10_list, HLGTI, RT, RA, si10);
|
||||
bind_instr(ri10_list, MPYI, RT, RA, si10);
|
||||
bind_instr(ri10_list, MPYUI, RT, RA, si10);
|
||||
bind_instr(ri10_list, CEQI, RT, RA, si10);
|
||||
bind_instr(ri10_list, CEQHI, RT, RA, si10);
|
||||
bind_instr(ri10_list, CEQBI, RT, RA, i10);
|
||||
bind_instr(ri10_list, HEQI, RT, RA, si10);
|
||||
|
||||
bind_instr(ri18_list, HBRA, RO, i16s2);
|
||||
bind_instr(ri18_list, HBRR, RO, si16);
|
||||
bind_instr(ri18_list, ILA, RT, i18);
|
||||
|
||||
bind_instr(rrr_list, SELB, RC, RA, RB, RT);
|
||||
bind_instr(rrr_list, SHUFB, RC, RA, RB, RT);
|
||||
bind_instr(rrr_list, MPYA, RC, RA, RB, RT);
|
||||
bind_instr(rrr_list, FNMS, RC, RA, RB, RT);
|
||||
bind_instr(rrr_list, FMA, RC, RA, RB, RT);
|
||||
bind_instr(rrr_list, FMS, RC, RA, RB, RT);
|
||||
|
||||
#undef bind_instr
|
||||
};
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,514 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
class SPUThread;
|
||||
|
||||
union spu_opcode_t
|
||||
{
|
||||
u32 opcode;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 rt : 7; // 25..31, it's actually RC in 4-op instructions
|
||||
u32 ra : 7; // 18..24
|
||||
u32 rb : 7; // 11..17
|
||||
u32 rc : 7; // 4..10, it's actually RT in 4-op instructions
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 : 14; // 18..31
|
||||
u32 i7 : 7; // 11..17
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 : 14; // 18..31
|
||||
u32 i8 : 8; // 10..17
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 : 14; // 18..31
|
||||
u32 i10 : 10; // 8..17
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 : 7; // 25..31
|
||||
u32 i16 : 16; // 9..24
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 : 7; // 25..31
|
||||
u32 i18 : 18; // 7..24
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
s32 : 14; // 18..31
|
||||
s32 si7 : 7; // 11..17
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
s32 : 14; // 18..31
|
||||
s32 si8 : 8; // 10..17
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
s32 : 14; // 18..31
|
||||
s32 si10 : 10; // 8..17
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
s32 : 7; // 25..31
|
||||
s32 si16 : 16; // 9..24
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
s32 : 7; // 25..31
|
||||
s32 si18 : 18; // 7..24
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 : 18; // 14..31
|
||||
u32 e : 1; // 13, "enable interrupts" bit
|
||||
u32 d : 1; // 12, "disable interrupts" bit
|
||||
};
|
||||
};
|
||||
|
||||
using spu_inter_func_t = void(*)(SPUThread& CPU, spu_opcode_t opcode);
|
||||
|
||||
namespace spu_interpreter
|
||||
{
|
||||
void DEFAULT(SPUThread& CPU, spu_opcode_t op);
|
||||
|
||||
void set_interrupt_status(SPUThread& CPU, spu_opcode_t op);
|
||||
|
||||
void STOP(SPUThread& CPU, spu_opcode_t op);
|
||||
void LNOP(SPUThread& CPU, spu_opcode_t op);
|
||||
void SYNC(SPUThread& CPU, spu_opcode_t op);
|
||||
void DSYNC(SPUThread& CPU, spu_opcode_t op);
|
||||
void MFSPR(SPUThread& CPU, spu_opcode_t op);
|
||||
void RDCH(SPUThread& CPU, spu_opcode_t op);
|
||||
void RCHCNT(SPUThread& CPU, spu_opcode_t op);
|
||||
void SF(SPUThread& CPU, spu_opcode_t op);
|
||||
void OR(SPUThread& CPU, spu_opcode_t op);
|
||||
void BG(SPUThread& CPU, spu_opcode_t op);
|
||||
void SFH(SPUThread& CPU, spu_opcode_t op);
|
||||
void NOR(SPUThread& CPU, spu_opcode_t op);
|
||||
void ABSDB(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROT(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTM(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTMA(SPUThread& CPU, spu_opcode_t op);
|
||||
void SHL(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTH(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTHM(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTMAH(SPUThread& CPU, spu_opcode_t op);
|
||||
void SHLH(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTI(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTMI(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTMAI(SPUThread& CPU, spu_opcode_t op);
|
||||
void SHLI(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTHI(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTHMI(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTMAHI(SPUThread& CPU, spu_opcode_t op);
|
||||
void SHLHI(SPUThread& CPU, spu_opcode_t op);
|
||||
void A(SPUThread& CPU, spu_opcode_t op);
|
||||
void AND(SPUThread& CPU, spu_opcode_t op);
|
||||
void CG(SPUThread& CPU, spu_opcode_t op);
|
||||
void AH(SPUThread& CPU, spu_opcode_t op);
|
||||
void NAND(SPUThread& CPU, spu_opcode_t op);
|
||||
void AVGB(SPUThread& CPU, spu_opcode_t op);
|
||||
void MTSPR(SPUThread& CPU, spu_opcode_t op);
|
||||
void WRCH(SPUThread& CPU, spu_opcode_t op);
|
||||
void BIZ(SPUThread& CPU, spu_opcode_t op);
|
||||
void BINZ(SPUThread& CPU, spu_opcode_t op);
|
||||
void BIHZ(SPUThread& CPU, spu_opcode_t op);
|
||||
void BIHNZ(SPUThread& CPU, spu_opcode_t op);
|
||||
void STOPD(SPUThread& CPU, spu_opcode_t op);
|
||||
void STQX(SPUThread& CPU, spu_opcode_t op);
|
||||
void BI(SPUThread& CPU, spu_opcode_t op);
|
||||
void BISL(SPUThread& CPU, spu_opcode_t op);
|
||||
void IRET(SPUThread& CPU, spu_opcode_t op);
|
||||
void BISLED(SPUThread& CPU, spu_opcode_t op);
|
||||
void HBR(SPUThread& CPU, spu_opcode_t op);
|
||||
void GB(SPUThread& CPU, spu_opcode_t op);
|
||||
void GBH(SPUThread& CPU, spu_opcode_t op);
|
||||
void GBB(SPUThread& CPU, spu_opcode_t op);
|
||||
void FSM(SPUThread& CPU, spu_opcode_t op);
|
||||
void FSMH(SPUThread& CPU, spu_opcode_t op);
|
||||
void FSMB(SPUThread& CPU, spu_opcode_t op);
|
||||
void FREST(SPUThread& CPU, spu_opcode_t op);
|
||||
void FRSQEST(SPUThread& CPU, spu_opcode_t op);
|
||||
void LQX(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTQBYBI(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTQMBYBI(SPUThread& CPU, spu_opcode_t op);
|
||||
void SHLQBYBI(SPUThread& CPU, spu_opcode_t op);
|
||||
void CBX(SPUThread& CPU, spu_opcode_t op);
|
||||
void CHX(SPUThread& CPU, spu_opcode_t op);
|
||||
void CWX(SPUThread& CPU, spu_opcode_t op);
|
||||
void CDX(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTQBI(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTQMBI(SPUThread& CPU, spu_opcode_t op);
|
||||
void SHLQBI(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTQBY(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTQMBY(SPUThread& CPU, spu_opcode_t op);
|
||||
void SHLQBY(SPUThread& CPU, spu_opcode_t op);
|
||||
void ORX(SPUThread& CPU, spu_opcode_t op);
|
||||
void CBD(SPUThread& CPU, spu_opcode_t op);
|
||||
void CHD(SPUThread& CPU, spu_opcode_t op);
|
||||
void CWD(SPUThread& CPU, spu_opcode_t op);
|
||||
void CDD(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTQBII(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTQMBII(SPUThread& CPU, spu_opcode_t op);
|
||||
void SHLQBII(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTQBYI(SPUThread& CPU, spu_opcode_t op);
|
||||
void ROTQMBYI(SPUThread& CPU, spu_opcode_t op);
|
||||
void SHLQBYI(SPUThread& CPU, spu_opcode_t op);
|
||||
void NOP(SPUThread& CPU, spu_opcode_t op);
|
||||
void CGT(SPUThread& CPU, spu_opcode_t op);
|
||||
void XOR(SPUThread& CPU, spu_opcode_t op);
|
||||
void CGTH(SPUThread& CPU, spu_opcode_t op);
|
||||
void EQV(SPUThread& CPU, spu_opcode_t op);
|
||||
void CGTB(SPUThread& CPU, spu_opcode_t op);
|
||||
void SUMB(SPUThread& CPU, spu_opcode_t op);
|
||||
void HGT(SPUThread& CPU, spu_opcode_t op);
|
||||
void CLZ(SPUThread& CPU, spu_opcode_t op);
|
||||
void XSWD(SPUThread& CPU, spu_opcode_t op);
|
||||
void XSHW(SPUThread& CPU, spu_opcode_t op);
|
||||
void CNTB(SPUThread& CPU, spu_opcode_t op);
|
||||
void XSBH(SPUThread& CPU, spu_opcode_t op);
|
||||
void CLGT(SPUThread& CPU, spu_opcode_t op);
|
||||
void ANDC(SPUThread& CPU, spu_opcode_t op);
|
||||
void FCGT(SPUThread& CPU, spu_opcode_t op);
|
||||
void DFCGT(SPUThread& CPU, spu_opcode_t op);
|
||||
void FA(SPUThread& CPU, spu_opcode_t op);
|
||||
void FS(SPUThread& CPU, spu_opcode_t op);
|
||||
void FM(SPUThread& CPU, spu_opcode_t op);
|
||||
void CLGTH(SPUThread& CPU, spu_opcode_t op);
|
||||
void ORC(SPUThread& CPU, spu_opcode_t op);
|
||||
void FCMGT(SPUThread& CPU, spu_opcode_t op);
|
||||
void DFCMGT(SPUThread& CPU, spu_opcode_t op);
|
||||
void DFA(SPUThread& CPU, spu_opcode_t op);
|
||||
void DFS(SPUThread& CPU, spu_opcode_t op);
|
||||
void DFM(SPUThread& CPU, spu_opcode_t op);
|
||||
void CLGTB(SPUThread& CPU, spu_opcode_t op);
|
||||
void HLGT(SPUThread& CPU, spu_opcode_t op);
|
||||
void DFMA(SPUThread& CPU, spu_opcode_t op);
|
||||
void DFMS(SPUThread& CPU, spu_opcode_t op);
|
||||
void DFNMS(SPUThread& CPU, spu_opcode_t op);
|
||||
void DFNMA(SPUThread& CPU, spu_opcode_t op);
|
||||
void CEQ(SPUThread& CPU, spu_opcode_t op);
|
||||
void MPYHHU(SPUThread& CPU, spu_opcode_t op);
|
||||
void ADDX(SPUThread& CPU, spu_opcode_t op);
|
||||
void SFX(SPUThread& CPU, spu_opcode_t op);
|
||||
void CGX(SPUThread& CPU, spu_opcode_t op);
|
||||
void BGX(SPUThread& CPU, spu_opcode_t op);
|
||||
void MPYHHA(SPUThread& CPU, spu_opcode_t op);
|
||||
void MPYHHAU(SPUThread& CPU, spu_opcode_t op);
|
||||
void FSCRRD(SPUThread& CPU, spu_opcode_t op);
|
||||
void FESD(SPUThread& CPU, spu_opcode_t op);
|
||||
void FRDS(SPUThread& CPU, spu_opcode_t op);
|
||||
void FSCRWR(SPUThread& CPU, spu_opcode_t op);
|
||||
void DFTSV(SPUThread& CPU, spu_opcode_t op);
|
||||
void FCEQ(SPUThread& CPU, spu_opcode_t op);
|
||||
void DFCEQ(SPUThread& CPU, spu_opcode_t op);
|
||||
void MPY(SPUThread& CPU, spu_opcode_t op);
|
||||
void MPYH(SPUThread& CPU, spu_opcode_t op);
|
||||
void MPYHH(SPUThread& CPU, spu_opcode_t op);
|
||||
void MPYS(SPUThread& CPU, spu_opcode_t op);
|
||||
void CEQH(SPUThread& CPU, spu_opcode_t op);
|
||||
void FCMEQ(SPUThread& CPU, spu_opcode_t op);
|
||||
void DFCMEQ(SPUThread& CPU, spu_opcode_t op);
|
||||
void MPYU(SPUThread& CPU, spu_opcode_t op);
|
||||
void CEQB(SPUThread& CPU, spu_opcode_t op);
|
||||
void FI(SPUThread& CPU, spu_opcode_t op);
|
||||
void HEQ(SPUThread& CPU, spu_opcode_t op);
|
||||
|
||||
void CFLTS(SPUThread& CPU, spu_opcode_t op);
|
||||
void CFLTU(SPUThread& CPU, spu_opcode_t op);
|
||||
void CSFLT(SPUThread& CPU, spu_opcode_t op);
|
||||
void CUFLT(SPUThread& CPU, spu_opcode_t op);
|
||||
|
||||
void BRZ(SPUThread& CPU, spu_opcode_t op);
|
||||
void STQA(SPUThread& CPU, spu_opcode_t op);
|
||||
void BRNZ(SPUThread& CPU, spu_opcode_t op);
|
||||
void BRHZ(SPUThread& CPU, spu_opcode_t op);
|
||||
void BRHNZ(SPUThread& CPU, spu_opcode_t op);
|
||||
void STQR(SPUThread& CPU, spu_opcode_t op);
|
||||
void BRA(SPUThread& CPU, spu_opcode_t op);
|
||||
void LQA(SPUThread& CPU, spu_opcode_t op);
|
||||
void BRASL(SPUThread& CPU, spu_opcode_t op);
|
||||
void BR(SPUThread& CPU, spu_opcode_t op);
|
||||
void FSMBI(SPUThread& CPU, spu_opcode_t op);
|
||||
void BRSL(SPUThread& CPU, spu_opcode_t op);
|
||||
void LQR(SPUThread& CPU, spu_opcode_t op);
|
||||
void IL(SPUThread& CPU, spu_opcode_t op);
|
||||
void ILHU(SPUThread& CPU, spu_opcode_t op);
|
||||
void ILH(SPUThread& CPU, spu_opcode_t op);
|
||||
void IOHL(SPUThread& CPU, spu_opcode_t op);
|
||||
|
||||
void ORI(SPUThread& CPU, spu_opcode_t op);
|
||||
void ORHI(SPUThread& CPU, spu_opcode_t op);
|
||||
void ORBI(SPUThread& CPU, spu_opcode_t op);
|
||||
void SFI(SPUThread& CPU, spu_opcode_t op);
|
||||
void SFHI(SPUThread& CPU, spu_opcode_t op);
|
||||
void ANDI(SPUThread& CPU, spu_opcode_t op);
|
||||
void ANDHI(SPUThread& CPU, spu_opcode_t op);
|
||||
void ANDBI(SPUThread& CPU, spu_opcode_t op);
|
||||
void AI(SPUThread& CPU, spu_opcode_t op);
|
||||
void AHI(SPUThread& CPU, spu_opcode_t op);
|
||||
void STQD(SPUThread& CPU, spu_opcode_t op);
|
||||
void LQD(SPUThread& CPU, spu_opcode_t op);
|
||||
void XORI(SPUThread& CPU, spu_opcode_t op);
|
||||
void XORHI(SPUThread& CPU, spu_opcode_t op);
|
||||
void XORBI(SPUThread& CPU, spu_opcode_t op);
|
||||
void CGTI(SPUThread& CPU, spu_opcode_t op);
|
||||
void CGTHI(SPUThread& CPU, spu_opcode_t op);
|
||||
void CGTBI(SPUThread& CPU, spu_opcode_t op);
|
||||
void HGTI(SPUThread& CPU, spu_opcode_t op);
|
||||
void CLGTI(SPUThread& CPU, spu_opcode_t op);
|
||||
void CLGTHI(SPUThread& CPU, spu_opcode_t op);
|
||||
void CLGTBI(SPUThread& CPU, spu_opcode_t op);
|
||||
void HLGTI(SPUThread& CPU, spu_opcode_t op);
|
||||
void MPYI(SPUThread& CPU, spu_opcode_t op);
|
||||
void MPYUI(SPUThread& CPU, spu_opcode_t op);
|
||||
void CEQI(SPUThread& CPU, spu_opcode_t op);
|
||||
void CEQHI(SPUThread& CPU, spu_opcode_t op);
|
||||
void CEQBI(SPUThread& CPU, spu_opcode_t op);
|
||||
void HEQI(SPUThread& CPU, spu_opcode_t op);
|
||||
|
||||
void HBRA(SPUThread& CPU, spu_opcode_t op);
|
||||
void HBRR(SPUThread& CPU, spu_opcode_t op);
|
||||
void ILA(SPUThread& CPU, spu_opcode_t op);
|
||||
|
||||
void SELB(SPUThread& CPU, spu_opcode_t op);
|
||||
void SHUFB(SPUThread& CPU, spu_opcode_t op);
|
||||
void MPYA(SPUThread& CPU, spu_opcode_t op);
|
||||
void FNMS(SPUThread& CPU, spu_opcode_t op);
|
||||
void FMA(SPUThread& CPU, spu_opcode_t op);
|
||||
void FMS(SPUThread& CPU, spu_opcode_t op);
|
||||
|
||||
void UNK(SPUThread& CPU, spu_opcode_t op);
|
||||
}
|
||||
|
||||
class SPUInterpreter2 : public SPUOpcodes
|
||||
{
|
||||
public:
|
||||
virtual ~SPUInterpreter2() {}
|
||||
|
||||
spu_inter_func_t func;
|
||||
|
||||
virtual void STOP(u32 code) { func = spu_interpreter::STOP; }
|
||||
virtual void LNOP() { func = spu_interpreter::LNOP; }
|
||||
virtual void SYNC(u32 Cbit) { func = spu_interpreter::SYNC; }
|
||||
virtual void DSYNC() { func = spu_interpreter::DSYNC; }
|
||||
virtual void MFSPR(u32 rt, u32 sa) { func = spu_interpreter::MFSPR; }
|
||||
virtual void RDCH(u32 rt, u32 ra) { func = spu_interpreter::RDCH; }
|
||||
virtual void RCHCNT(u32 rt, u32 ra) { func = spu_interpreter::RCHCNT; }
|
||||
virtual void SF(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::SF; }
|
||||
virtual void OR(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::OR; }
|
||||
virtual void BG(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::BG; }
|
||||
virtual void SFH(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::SFH; }
|
||||
virtual void NOR(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::NOR; }
|
||||
virtual void ABSDB(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::ABSDB; }
|
||||
virtual void ROT(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::ROT; }
|
||||
virtual void ROTM(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::ROTM; }
|
||||
virtual void ROTMA(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::ROTMA; }
|
||||
virtual void SHL(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::SHL; }
|
||||
virtual void ROTH(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::ROTH; }
|
||||
virtual void ROTHM(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::ROTHM; }
|
||||
virtual void ROTMAH(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::ROTMAH; }
|
||||
virtual void SHLH(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::SHLH; }
|
||||
virtual void ROTI(u32 rt, u32 ra, s32 i7) { func = spu_interpreter::ROTI; }
|
||||
virtual void ROTMI(u32 rt, u32 ra, s32 i7) { func = spu_interpreter::ROTMI; }
|
||||
virtual void ROTMAI(u32 rt, u32 ra, s32 i7) { func = spu_interpreter::ROTMAI; }
|
||||
virtual void SHLI(u32 rt, u32 ra, s32 i7) { func = spu_interpreter::SHLI; }
|
||||
virtual void ROTHI(u32 rt, u32 ra, s32 i7) { func = spu_interpreter::ROTHI; }
|
||||
virtual void ROTHMI(u32 rt, u32 ra, s32 i7) { func = spu_interpreter::ROTHMI; }
|
||||
virtual void ROTMAHI(u32 rt, u32 ra, s32 i7) { func = spu_interpreter::ROTMAHI; }
|
||||
virtual void SHLHI(u32 rt, u32 ra, s32 i7) { func = spu_interpreter::SHLHI; }
|
||||
virtual void A(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::A; }
|
||||
virtual void AND(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::AND; }
|
||||
virtual void CG(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::CG; }
|
||||
virtual void AH(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::AH; }
|
||||
virtual void NAND(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::NAND; }
|
||||
virtual void AVGB(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::AVGB; }
|
||||
virtual void MTSPR(u32 rt, u32 sa) { func = spu_interpreter::MTSPR; }
|
||||
virtual void WRCH(u32 ra, u32 rt) { func = spu_interpreter::WRCH; }
|
||||
virtual void BIZ(u32 intr, u32 rt, u32 ra) { func = spu_interpreter::BIZ; }
|
||||
virtual void BINZ(u32 intr, u32 rt, u32 ra) { func = spu_interpreter::BINZ; }
|
||||
virtual void BIHZ(u32 intr, u32 rt, u32 ra) { func = spu_interpreter::BIHZ; }
|
||||
virtual void BIHNZ(u32 intr, u32 rt, u32 ra) { func = spu_interpreter::BIHNZ; }
|
||||
virtual void STOPD(u32 rc, u32 ra, u32 rb) { func = spu_interpreter::STOPD; }
|
||||
virtual void STQX(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::STQX; }
|
||||
virtual void BI(u32 intr, u32 ra) { func = spu_interpreter::BI; }
|
||||
virtual void BISL(u32 intr, u32 rt, u32 ra) { func = spu_interpreter::BISL; }
|
||||
virtual void IRET(u32 ra) { func = spu_interpreter::IRET; }
|
||||
virtual void BISLED(u32 intr, u32 rt, u32 ra) { func = spu_interpreter::BISLED; }
|
||||
virtual void HBR(u32 p, u32 ro, u32 ra) { func = spu_interpreter::HBR; }
|
||||
virtual void GB(u32 rt, u32 ra) { func = spu_interpreter::GB; }
|
||||
virtual void GBH(u32 rt, u32 ra) { func = spu_interpreter::GBH; }
|
||||
virtual void GBB(u32 rt, u32 ra) { func = spu_interpreter::GBB; }
|
||||
virtual void FSM(u32 rt, u32 ra) { func = spu_interpreter::FSM; }
|
||||
virtual void FSMH(u32 rt, u32 ra) { func = spu_interpreter::FSMH; }
|
||||
virtual void FSMB(u32 rt, u32 ra) { func = spu_interpreter::FSMB; }
|
||||
virtual void FREST(u32 rt, u32 ra) { func = spu_interpreter::FREST; }
|
||||
virtual void FRSQEST(u32 rt, u32 ra) { func = spu_interpreter::FRSQEST; }
|
||||
virtual void LQX(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::LQX; }
|
||||
virtual void ROTQBYBI(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::ROTQBYBI; }
|
||||
virtual void ROTQMBYBI(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::ROTQMBYBI; }
|
||||
virtual void SHLQBYBI(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::SHLQBYBI; }
|
||||
virtual void CBX(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::CBX; }
|
||||
virtual void CHX(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::CHX; }
|
||||
virtual void CWX(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::CWX; }
|
||||
virtual void CDX(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::CDX; }
|
||||
virtual void ROTQBI(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::ROTQBI; }
|
||||
virtual void ROTQMBI(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::ROTQMBI; }
|
||||
virtual void SHLQBI(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::SHLQBI; }
|
||||
virtual void ROTQBY(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::ROTQBY; }
|
||||
virtual void ROTQMBY(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::ROTQMBY; }
|
||||
virtual void SHLQBY(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::SHLQBY; }
|
||||
virtual void ORX(u32 rt, u32 ra) { func = spu_interpreter::ORX; }
|
||||
virtual void CBD(u32 rt, u32 ra, s32 i7) { func = spu_interpreter::CBD; }
|
||||
virtual void CHD(u32 rt, u32 ra, s32 i7) { func = spu_interpreter::CHD; }
|
||||
virtual void CWD(u32 rt, u32 ra, s32 i7) { func = spu_interpreter::CWD; }
|
||||
virtual void CDD(u32 rt, u32 ra, s32 i7) { func = spu_interpreter::CDD; }
|
||||
virtual void ROTQBII(u32 rt, u32 ra, s32 i7) { func = spu_interpreter::ROTQBII; }
|
||||
virtual void ROTQMBII(u32 rt, u32 ra, s32 i7) { func = spu_interpreter::ROTQMBII; }
|
||||
virtual void SHLQBII(u32 rt, u32 ra, s32 i7) { func = spu_interpreter::SHLQBII; }
|
||||
virtual void ROTQBYI(u32 rt, u32 ra, s32 i7) { func = spu_interpreter::ROTQBYI; }
|
||||
virtual void ROTQMBYI(u32 rt, u32 ra, s32 i7) { func = spu_interpreter::ROTQMBYI; }
|
||||
virtual void SHLQBYI(u32 rt, u32 ra, s32 i7) { func = spu_interpreter::SHLQBYI; }
|
||||
virtual void NOP(u32 rt) { func = spu_interpreter::NOP; }
|
||||
virtual void CGT(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::CGT; }
|
||||
virtual void XOR(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::XOR; }
|
||||
virtual void CGTH(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::CGTH; }
|
||||
virtual void EQV(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::EQV; }
|
||||
virtual void CGTB(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::CGTB; }
|
||||
virtual void SUMB(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::SUMB; }
|
||||
virtual void HGT(u32 rt, s32 ra, s32 rb) { func = spu_interpreter::HGT; }
|
||||
virtual void CLZ(u32 rt, u32 ra) { func = spu_interpreter::CLZ; }
|
||||
virtual void XSWD(u32 rt, u32 ra) { func = spu_interpreter::XSWD; }
|
||||
virtual void XSHW(u32 rt, u32 ra) { func = spu_interpreter::XSHW; }
|
||||
virtual void CNTB(u32 rt, u32 ra) { func = spu_interpreter::CNTB; }
|
||||
virtual void XSBH(u32 rt, u32 ra) { func = spu_interpreter::XSBH; }
|
||||
virtual void CLGT(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::CLGT; }
|
||||
virtual void ANDC(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::ANDC; }
|
||||
virtual void FCGT(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::FCGT; }
|
||||
virtual void DFCGT(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::DFCGT; }
|
||||
virtual void FA(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::FA; }
|
||||
virtual void FS(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::FS; }
|
||||
virtual void FM(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::FM; }
|
||||
virtual void CLGTH(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::CLGTH; }
|
||||
virtual void ORC(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::ORC; }
|
||||
virtual void FCMGT(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::FCMGT; }
|
||||
virtual void DFCMGT(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::DFCMGT; }
|
||||
virtual void DFA(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::DFA; }
|
||||
virtual void DFS(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::DFS; }
|
||||
virtual void DFM(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::DFM; }
|
||||
virtual void CLGTB(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::CLGTB; }
|
||||
virtual void HLGT(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::HLGT; }
|
||||
virtual void DFMA(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::DFMA; }
|
||||
virtual void DFMS(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::DFMS; }
|
||||
virtual void DFNMS(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::DFNMS; }
|
||||
virtual void DFNMA(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::DFNMA; }
|
||||
virtual void CEQ(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::CEQ; }
|
||||
virtual void MPYHHU(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::MPYHHU; }
|
||||
virtual void ADDX(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::ADDX; }
|
||||
virtual void SFX(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::SFX; }
|
||||
virtual void CGX(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::CGX; }
|
||||
virtual void BGX(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::BGX; }
|
||||
virtual void MPYHHA(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::MPYHHA; }
|
||||
virtual void MPYHHAU(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::MPYHHAU; }
|
||||
virtual void FSCRRD(u32 rt) { func = spu_interpreter::FSCRRD; }
|
||||
virtual void FESD(u32 rt, u32 ra) { func = spu_interpreter::FESD; }
|
||||
virtual void FRDS(u32 rt, u32 ra) { func = spu_interpreter::FRDS; }
|
||||
virtual void FSCRWR(u32 rt, u32 ra) { func = spu_interpreter::FSCRWR; }
|
||||
virtual void DFTSV(u32 rt, u32 ra, s32 i7) { func = spu_interpreter::DFTSV; }
|
||||
virtual void FCEQ(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::FCEQ; }
|
||||
virtual void DFCEQ(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::DFCEQ; }
|
||||
virtual void MPY(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::MPY; }
|
||||
virtual void MPYH(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::MPYH; }
|
||||
virtual void MPYHH(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::MPYHH; }
|
||||
virtual void MPYS(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::MPYS; }
|
||||
virtual void CEQH(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::CEQH; }
|
||||
virtual void FCMEQ(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::FCMEQ; }
|
||||
virtual void DFCMEQ(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::DFCMEQ; }
|
||||
virtual void MPYU(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::MPYU; }
|
||||
virtual void CEQB(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::CEQB; }
|
||||
virtual void FI(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::FI; }
|
||||
virtual void HEQ(u32 rt, u32 ra, u32 rb) { func = spu_interpreter::HEQ; }
|
||||
|
||||
virtual void CFLTS(u32 rt, u32 ra, s32 i8) { func = spu_interpreter::CFLTS; }
|
||||
virtual void CFLTU(u32 rt, u32 ra, s32 i8) { func = spu_interpreter::CFLTU; }
|
||||
virtual void CSFLT(u32 rt, u32 ra, s32 i8) { func = spu_interpreter::CSFLT; }
|
||||
virtual void CUFLT(u32 rt, u32 ra, s32 i8) { func = spu_interpreter::CUFLT; }
|
||||
|
||||
virtual void BRZ(u32 rt, s32 i16) { func = spu_interpreter::BRZ; }
|
||||
virtual void STQA(u32 rt, s32 i16) { func = spu_interpreter::STQA; }
|
||||
virtual void BRNZ(u32 rt, s32 i16) { func = spu_interpreter::BRNZ; }
|
||||
virtual void BRHZ(u32 rt, s32 i16) { func = spu_interpreter::BRHZ; }
|
||||
virtual void BRHNZ(u32 rt, s32 i16) { func = spu_interpreter::BRHNZ; }
|
||||
virtual void STQR(u32 rt, s32 i16) { func = spu_interpreter::STQR; }
|
||||
virtual void BRA(s32 i16) { func = spu_interpreter::BRA; }
|
||||
virtual void LQA(u32 rt, s32 i16) { func = spu_interpreter::LQA; }
|
||||
virtual void BRASL(u32 rt, s32 i16) { func = spu_interpreter::BRASL; }
|
||||
virtual void BR(s32 i16) { func = spu_interpreter::BR; }
|
||||
virtual void FSMBI(u32 rt, s32 i16) { func = spu_interpreter::FSMBI; }
|
||||
virtual void BRSL(u32 rt, s32 i16) { func = spu_interpreter::BRSL; }
|
||||
virtual void LQR(u32 rt, s32 i16) { func = spu_interpreter::LQR; }
|
||||
virtual void IL(u32 rt, s32 i16) { func = spu_interpreter::IL; }
|
||||
virtual void ILHU(u32 rt, s32 i16) { func = spu_interpreter::ILHU; }
|
||||
virtual void ILH(u32 rt, s32 i16) { func = spu_interpreter::ILH; }
|
||||
virtual void IOHL(u32 rt, s32 i16) { func = spu_interpreter::IOHL; }
|
||||
|
||||
virtual void ORI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::ORI; }
|
||||
virtual void ORHI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::ORHI; }
|
||||
virtual void ORBI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::ORBI; }
|
||||
virtual void SFI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::SFI; }
|
||||
virtual void SFHI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::SFHI; }
|
||||
virtual void ANDI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::ANDI; }
|
||||
virtual void ANDHI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::ANDHI; }
|
||||
virtual void ANDBI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::ANDBI; }
|
||||
virtual void AI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::AI; }
|
||||
virtual void AHI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::AHI; }
|
||||
virtual void STQD(u32 rt, s32 i10, u32 ra) { func = spu_interpreter::STQD; }
|
||||
virtual void LQD(u32 rt, s32 i10, u32 ra) { func = spu_interpreter::LQD; }
|
||||
virtual void XORI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::XORI; }
|
||||
virtual void XORHI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::XORHI; }
|
||||
virtual void XORBI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::XORBI; }
|
||||
virtual void CGTI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::CGTI; }
|
||||
virtual void CGTHI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::CGTHI; }
|
||||
virtual void CGTBI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::CGTBI; }
|
||||
virtual void HGTI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::HGTI; }
|
||||
virtual void CLGTI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::CLGTI; }
|
||||
virtual void CLGTHI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::CLGTHI; }
|
||||
virtual void CLGTBI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::CLGTBI; }
|
||||
virtual void HLGTI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::HLGTI; }
|
||||
virtual void MPYI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::MPYI; }
|
||||
virtual void MPYUI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::MPYUI; }
|
||||
virtual void CEQI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::CEQI; }
|
||||
virtual void CEQHI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::CEQHI; }
|
||||
virtual void CEQBI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::CEQBI; }
|
||||
virtual void HEQI(u32 rt, u32 ra, s32 i10) { func = spu_interpreter::HEQI; }
|
||||
|
||||
virtual void HBRA(s32 ro, s32 i16) { func = spu_interpreter::HBRA; }
|
||||
virtual void HBRR(s32 ro, s32 i16) { func = spu_interpreter::HBRR; }
|
||||
virtual void ILA(u32 rt, u32 i18) { func = spu_interpreter::ILA; }
|
||||
|
||||
virtual void SELB(u32 rc, u32 ra, u32 rb, u32 rt) { func = spu_interpreter::SELB; }
|
||||
virtual void SHUFB(u32 rc, u32 ra, u32 rb, u32 rt) { func = spu_interpreter::SHUFB; }
|
||||
virtual void MPYA(u32 rc, u32 ra, u32 rb, u32 rt) { func = spu_interpreter::MPYA; }
|
||||
virtual void FNMS(u32 rc, u32 ra, u32 rb, u32 rt) { func = spu_interpreter::FNMS; }
|
||||
virtual void FMA(u32 rc, u32 ra, u32 rb, u32 rt) { func = spu_interpreter::FMA; }
|
||||
virtual void FMS(u32 rc, u32 ra, u32 rb, u32 rt) { func = spu_interpreter::FMS; }
|
||||
|
||||
virtual void UNK(u32 code, u32 opcode, u32 gcode) { func = spu_interpreter::UNK; }
|
||||
};
|
@ -1,451 +1,322 @@
|
||||
#pragma once
|
||||
|
||||
namespace SPU_opcodes
|
||||
union spu_opcode_t
|
||||
{
|
||||
enum SPU_0_10_Opcodes
|
||||
u32 opcode;
|
||||
|
||||
struct
|
||||
{
|
||||
STOP = 0x0,
|
||||
LNOP = 0x1,
|
||||
SYNC = 0x2,
|
||||
DSYNC = 0x3,
|
||||
MFSPR = 0xc,
|
||||
RDCH = 0xd,
|
||||
RCHCNT = 0xf,
|
||||
SF = 0x40,
|
||||
OR = 0x41,
|
||||
BG = 0x42,
|
||||
SFH = 0x48,
|
||||
NOR = 0x49,
|
||||
ABSDB = 0x53,
|
||||
ROT = 0x58,
|
||||
ROTM = 0x59,
|
||||
ROTMA = 0x5a,
|
||||
SHL = 0x5b,
|
||||
ROTH = 0x5c,
|
||||
ROTHM = 0x5d,
|
||||
ROTMAH = 0x5e,
|
||||
SHLH = 0x5f,
|
||||
ROTI = 0x78,
|
||||
ROTMI = 0x79,
|
||||
ROTMAI = 0x7a,
|
||||
SHLI = 0x7b,
|
||||
ROTHI = 0x7c,
|
||||
ROTHMI = 0x7d,
|
||||
ROTMAHI = 0x7e,
|
||||
SHLHI = 0x7f,
|
||||
A = 0xc0,
|
||||
AND = 0xc1,
|
||||
CG = 0xc2,
|
||||
AH = 0xc8,
|
||||
NAND = 0xc9,
|
||||
AVGB = 0xd3,
|
||||
MTSPR = 0x10c,
|
||||
WRCH = 0x10d,
|
||||
BIZ = 0x128,
|
||||
BINZ = 0x129,
|
||||
BIHZ = 0x12a,
|
||||
BIHNZ = 0x12b,
|
||||
STOPD = 0x140,
|
||||
STQX = 0x144,
|
||||
BI = 0x1a8,
|
||||
BISL = 0x1a9,
|
||||
IRET = 0x1aa,
|
||||
BISLED = 0x1ab,
|
||||
HBR = 0x1ac,
|
||||
GB = 0x1b0,
|
||||
GBH = 0x1b1,
|
||||
GBB = 0x1b2,
|
||||
FSM = 0x1b4,
|
||||
FSMH = 0x1b5,
|
||||
FSMB = 0x1b6,
|
||||
FREST = 0x1b8,
|
||||
FRSQEST = 0x1b9,
|
||||
LQX = 0x1c4,
|
||||
ROTQBYBI = 0x1cc,
|
||||
ROTQMBYBI = 0x1cd,
|
||||
SHLQBYBI = 0x1cf,
|
||||
CBX = 0x1d4,
|
||||
CHX = 0x1d5,
|
||||
CWX = 0x1d6,
|
||||
CDX = 0x1d7,
|
||||
ROTQBI = 0x1d8,
|
||||
ROTQMBI = 0x1d9,
|
||||
SHLQBI = 0x1db,
|
||||
ROTQBY = 0x1dc,
|
||||
ROTQMBY = 0x1dd,
|
||||
SHLQBY = 0x1df,
|
||||
ORX = 0x1f0,
|
||||
CBD = 0x1f4,
|
||||
CHD = 0x1f5,
|
||||
CWD = 0x1f6,
|
||||
CDD = 0x1f7,
|
||||
ROTQBII = 0x1f8,
|
||||
ROTQMBII = 0x1f9,
|
||||
SHLQBII = 0x1fb,
|
||||
ROTQBYI = 0x1fc,
|
||||
ROTQMBYI = 0x1fd,
|
||||
SHLQBYI = 0x1ff,
|
||||
NOP = 0x201,
|
||||
CGT = 0x240,
|
||||
XOR = 0x241,
|
||||
CGTH = 0x248,
|
||||
EQV = 0x249,
|
||||
CGTB = 0x250,
|
||||
SUMB = 0x253,
|
||||
HGT = 0x258,
|
||||
CLZ = 0x2a5,
|
||||
XSWD = 0x2a6,
|
||||
XSHW = 0x2ae,
|
||||
CNTB = 0x2b4,
|
||||
XSBH = 0x2b6,
|
||||
CLGT = 0x2c0,
|
||||
ANDC = 0x2c1,
|
||||
FCGT = 0x2c2,
|
||||
DFCGT = 0x2c3,
|
||||
FA = 0x2c4,
|
||||
FS = 0x2c5,
|
||||
FM = 0x2c6,
|
||||
CLGTH = 0x2c8,
|
||||
ORC = 0x2c9,
|
||||
FCMGT = 0x2ca,
|
||||
DFCMGT = 0x2cb,
|
||||
DFA = 0x2cc,
|
||||
DFS = 0x2cd,
|
||||
DFM = 0x2ce,
|
||||
CLGTB = 0x2d0,
|
||||
HLGT = 0x2d8,
|
||||
DFMA = 0x35c,
|
||||
DFMS = 0x35d,
|
||||
DFNMS = 0x35e,
|
||||
DFNMA = 0x35f,
|
||||
CEQ = 0x3c0,
|
||||
MPYHHU = 0x3ce,
|
||||
ADDX = 0x340,
|
||||
SFX = 0x341,
|
||||
CGX = 0x342,
|
||||
BGX = 0x343,
|
||||
MPYHHA = 0x346,
|
||||
MPYHHAU = 0x34e,
|
||||
FSCRRD = 0x398,
|
||||
FESD = 0x3b8,
|
||||
FRDS = 0x3b9,
|
||||
FSCRWR = 0x3ba,
|
||||
DFTSV = 0x3bf,
|
||||
FCEQ = 0x3c2,
|
||||
DFCEQ = 0x3c3,
|
||||
MPY = 0x3c4,
|
||||
MPYH = 0x3c5,
|
||||
MPYHH = 0x3c6,
|
||||
MPYS = 0x3c7,
|
||||
CEQH = 0x3c8,
|
||||
FCMEQ = 0x3ca,
|
||||
DFCMEQ = 0x3cb,
|
||||
MPYU = 0x3cc,
|
||||
CEQB = 0x3d0,
|
||||
FI = 0x3d4,
|
||||
HEQ = 0x3d8,
|
||||
u32 rt : 7; // 25..31, it's actually RC in 4-op instructions
|
||||
u32 ra : 7; // 18..24
|
||||
u32 rb : 7; // 11..17
|
||||
u32 rc : 7; // 4..10, it's actually RT in 4-op instructions
|
||||
};
|
||||
|
||||
enum SPU_0_9_Opcodes
|
||||
struct
|
||||
{
|
||||
CFLTS = 0x1d8,
|
||||
CFLTU = 0x1d9,
|
||||
CSFLT = 0x1da,
|
||||
CUFLT = 0x1db,
|
||||
u32 : 14; // 18..31
|
||||
u32 i7 : 7; // 11..17
|
||||
};
|
||||
|
||||
enum SPU_0_8_Opcodes
|
||||
struct
|
||||
{
|
||||
BRZ = 0x40,
|
||||
STQA = 0x41,
|
||||
BRNZ = 0x42,
|
||||
BRHZ = 0x44,
|
||||
BRHNZ = 0x46,
|
||||
STQR = 0x47,
|
||||
BRA = 0x60,
|
||||
LQA = 0x61,
|
||||
BRASL = 0x62,
|
||||
BR = 0x64,
|
||||
FSMBI = 0x65,
|
||||
BRSL = 0x66,
|
||||
LQR = 0x67,
|
||||
IL = 0x81,
|
||||
ILHU = 0x82,
|
||||
ILH = 0x83,
|
||||
IOHL = 0xc1,
|
||||
u32 : 14; // 18..31
|
||||
u32 i8 : 8; // 10..17
|
||||
};
|
||||
|
||||
enum SPU_0_7_Opcodes
|
||||
struct
|
||||
{
|
||||
ORI = 0x4,
|
||||
ORHI = 0x5,
|
||||
ORBI = 0x6,
|
||||
SFI = 0xc,
|
||||
SFHI = 0xd,
|
||||
ANDI = 0x14,
|
||||
ANDHI = 0x15,
|
||||
ANDBI = 0x16,
|
||||
AI = 0x1c,
|
||||
AHI = 0x1d,
|
||||
STQD = 0x24,
|
||||
LQD = 0x34,
|
||||
XORI = 0x44,
|
||||
XORHI = 0x45,
|
||||
XORBI = 0x46,
|
||||
CGTI = 0x4c,
|
||||
CGTHI = 0x4d,
|
||||
CGTBI = 0x4e,
|
||||
HGTI = 0x4f,
|
||||
CLGTI = 0x5c,
|
||||
CLGTHI = 0x5d,
|
||||
CLGTBI = 0x5e,
|
||||
HLGTI = 0x5f,
|
||||
MPYI = 0x74,
|
||||
MPYUI = 0x75,
|
||||
CEQI = 0x7c,
|
||||
CEQHI = 0x7d,
|
||||
CEQBI = 0x7e,
|
||||
HEQI = 0x7f,
|
||||
u32 : 7; // 25..31
|
||||
u32 i16 : 16; // 9..24
|
||||
};
|
||||
|
||||
enum SPU_0_6_Opcodes
|
||||
struct
|
||||
{
|
||||
HBRA = 0x8,
|
||||
HBRR = 0x9,
|
||||
ILA = 0x21,
|
||||
u32 : 7; // 25..31
|
||||
u32 i18 : 18; // 7..24
|
||||
};
|
||||
|
||||
enum SPU_0_3_Opcodes
|
||||
struct
|
||||
{
|
||||
SELB = 0x8,
|
||||
SHUFB = 0xb,
|
||||
MPYA = 0xc,
|
||||
FNMS = 0xd,
|
||||
FMA = 0xe,
|
||||
FMS = 0xf,
|
||||
s32 : 14; // 18..31
|
||||
s32 si7 : 7; // 11..17
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
s32 : 14; // 18..31
|
||||
s32 si8 : 8; // 10..17
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
s32 : 14; // 18..31
|
||||
s32 si10 : 10; // 8..17
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
s32 : 7; // 25..31
|
||||
s32 si16 : 16; // 9..24
|
||||
s32 r0h : 2; // 7..8
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
s32 : 14; // 18..31
|
||||
s32 roh : 2; // 16..17
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 : 18; // 14..31
|
||||
u32 e : 1; // 13, "enable interrupts" bit
|
||||
u32 d : 1; // 12, "disable interrupts" bit
|
||||
u32 c : 1; // 11, "C" bit for SYNC instruction
|
||||
};
|
||||
};
|
||||
|
||||
class SPUOpcodes
|
||||
{
|
||||
public:
|
||||
virtual ~SPUOpcodes() {}
|
||||
#define DEFINE_SPU_OPCODES(ns) { \
|
||||
{ 10, 0x0, ns STOP }, \
|
||||
{ 10, 0x1, ns LNOP }, \
|
||||
{ 10, 0x2, ns SYNC }, \
|
||||
{ 10, 0x3, ns DSYNC }, \
|
||||
{ 10, 0xc, ns MFSPR }, \
|
||||
{ 10, 0xd, ns RDCH }, \
|
||||
{ 10, 0xf, ns RCHCNT }, \
|
||||
{ 10, 0x40, ns SF }, \
|
||||
{ 10, 0x41, ns OR }, \
|
||||
{ 10, 0x42, ns BG }, \
|
||||
{ 10, 0x48, ns SFH }, \
|
||||
{ 10, 0x49, ns NOR }, \
|
||||
{ 10, 0x53, ns ABSDB }, \
|
||||
{ 10, 0x58, ns ROT }, \
|
||||
{ 10, 0x59, ns ROTM }, \
|
||||
{ 10, 0x5a, ns ROTMA }, \
|
||||
{ 10, 0x5b, ns SHL }, \
|
||||
{ 10, 0x5c, ns ROTH }, \
|
||||
{ 10, 0x5d, ns ROTHM }, \
|
||||
{ 10, 0x5e, ns ROTMAH }, \
|
||||
{ 10, 0x5f, ns SHLH }, \
|
||||
{ 10, 0x78, ns ROTI }, \
|
||||
{ 10, 0x79, ns ROTMI }, \
|
||||
{ 10, 0x7a, ns ROTMAI }, \
|
||||
{ 10, 0x7b, ns SHLI }, \
|
||||
{ 10, 0x7c, ns ROTHI }, \
|
||||
{ 10, 0x7d, ns ROTHMI }, \
|
||||
{ 10, 0x7e, ns ROTMAHI }, \
|
||||
{ 10, 0x7f, ns SHLHI }, \
|
||||
{ 10, 0xc0, ns A }, \
|
||||
{ 10, 0xc1, ns AND }, \
|
||||
{ 10, 0xc2, ns CG }, \
|
||||
{ 10, 0xc8, ns AH }, \
|
||||
{ 10, 0xc9, ns NAND }, \
|
||||
{ 10, 0xd3, ns AVGB }, \
|
||||
{ 10, 0x10c, ns MTSPR }, \
|
||||
{ 10, 0x10d, ns WRCH }, \
|
||||
{ 10, 0x128, ns BIZ }, \
|
||||
{ 10, 0x129, ns BINZ }, \
|
||||
{ 10, 0x12a, ns BIHZ }, \
|
||||
{ 10, 0x12b, ns BIHNZ }, \
|
||||
{ 10, 0x140, ns STOPD }, \
|
||||
{ 10, 0x144, ns STQX }, \
|
||||
{ 10, 0x1a8, ns BI }, \
|
||||
{ 10, 0x1a9, ns BISL }, \
|
||||
{ 10, 0x1aa, ns IRET }, \
|
||||
{ 10, 0x1ab, ns BISLED }, \
|
||||
{ 10, 0x1ac, ns HBR }, \
|
||||
{ 10, 0x1b0, ns GB }, \
|
||||
{ 10, 0x1b1, ns GBH }, \
|
||||
{ 10, 0x1b2, ns GBB }, \
|
||||
{ 10, 0x1b4, ns FSM }, \
|
||||
{ 10, 0x1b5, ns FSMH }, \
|
||||
{ 10, 0x1b6, ns FSMB }, \
|
||||
{ 10, 0x1b8, ns FREST }, \
|
||||
{ 10, 0x1b9, ns FRSQEST }, \
|
||||
{ 10, 0x1c4, ns LQX }, \
|
||||
{ 10, 0x1cc, ns ROTQBYBI }, \
|
||||
{ 10, 0x1cd, ns ROTQMBYBI }, \
|
||||
{ 10, 0x1cf, ns SHLQBYBI }, \
|
||||
{ 10, 0x1d4, ns CBX }, \
|
||||
{ 10, 0x1d5, ns CHX }, \
|
||||
{ 10, 0x1d6, ns CWX }, \
|
||||
{ 10, 0x1d7, ns CDX }, \
|
||||
{ 10, 0x1d8, ns ROTQBI }, \
|
||||
{ 10, 0x1d9, ns ROTQMBI }, \
|
||||
{ 10, 0x1db, ns SHLQBI }, \
|
||||
{ 10, 0x1dc, ns ROTQBY }, \
|
||||
{ 10, 0x1dd, ns ROTQMBY }, \
|
||||
{ 10, 0x1df, ns SHLQBY }, \
|
||||
{ 10, 0x1f0, ns ORX }, \
|
||||
{ 10, 0x1f4, ns CBD }, \
|
||||
{ 10, 0x1f5, ns CHD }, \
|
||||
{ 10, 0x1f6, ns CWD }, \
|
||||
{ 10, 0x1f7, ns CDD }, \
|
||||
{ 10, 0x1f8, ns ROTQBII }, \
|
||||
{ 10, 0x1f9, ns ROTQMBII }, \
|
||||
{ 10, 0x1fb, ns SHLQBII }, \
|
||||
{ 10, 0x1fc, ns ROTQBYI }, \
|
||||
{ 10, 0x1fd, ns ROTQMBYI }, \
|
||||
{ 10, 0x1ff, ns SHLQBYI }, \
|
||||
{ 10, 0x201, ns NOP }, \
|
||||
{ 10, 0x240, ns CGT }, \
|
||||
{ 10, 0x241, ns XOR }, \
|
||||
{ 10, 0x248, ns CGTH }, \
|
||||
{ 10, 0x249, ns EQV }, \
|
||||
{ 10, 0x250, ns CGTB }, \
|
||||
{ 10, 0x253, ns SUMB }, \
|
||||
{ 10, 0x258, ns HGT }, \
|
||||
{ 10, 0x2a5, ns CLZ }, \
|
||||
{ 10, 0x2a6, ns XSWD }, \
|
||||
{ 10, 0x2ae, ns XSHW }, \
|
||||
{ 10, 0x2b4, ns CNTB }, \
|
||||
{ 10, 0x2b6, ns XSBH }, \
|
||||
{ 10, 0x2c0, ns CLGT }, \
|
||||
{ 10, 0x2c1, ns ANDC }, \
|
||||
{ 10, 0x2c2, ns FCGT }, \
|
||||
{ 10, 0x2c3, ns DFCGT }, \
|
||||
{ 10, 0x2c4, ns FA }, \
|
||||
{ 10, 0x2c5, ns FS }, \
|
||||
{ 10, 0x2c6, ns FM }, \
|
||||
{ 10, 0x2c8, ns CLGTH }, \
|
||||
{ 10, 0x2c9, ns ORC }, \
|
||||
{ 10, 0x2ca, ns FCMGT }, \
|
||||
{ 10, 0x2cb, ns DFCMGT }, \
|
||||
{ 10, 0x2cc, ns DFA }, \
|
||||
{ 10, 0x2cd, ns DFS }, \
|
||||
{ 10, 0x2ce, ns DFM }, \
|
||||
{ 10, 0x2d0, ns CLGTB }, \
|
||||
{ 10, 0x2d8, ns HLGT }, \
|
||||
{ 10, 0x35c, ns DFMA }, \
|
||||
{ 10, 0x35d, ns DFMS }, \
|
||||
{ 10, 0x35e, ns DFNMS }, \
|
||||
{ 10, 0x35f, ns DFNMA }, \
|
||||
{ 10, 0x3c0, ns CEQ }, \
|
||||
{ 10, 0x3ce, ns MPYHHU }, \
|
||||
{ 10, 0x340, ns ADDX }, \
|
||||
{ 10, 0x341, ns SFX }, \
|
||||
{ 10, 0x342, ns CGX }, \
|
||||
{ 10, 0x343, ns BGX }, \
|
||||
{ 10, 0x346, ns MPYHHA }, \
|
||||
{ 10, 0x34e, ns MPYHHAU }, \
|
||||
{ 10, 0x398, ns FSCRRD }, \
|
||||
{ 10, 0x3b8, ns FESD }, \
|
||||
{ 10, 0x3b9, ns FRDS }, \
|
||||
{ 10, 0x3ba, ns FSCRWR }, \
|
||||
{ 10, 0x3bf, ns DFTSV }, \
|
||||
{ 10, 0x3c2, ns FCEQ }, \
|
||||
{ 10, 0x3c3, ns DFCEQ }, \
|
||||
{ 10, 0x3c4, ns MPY }, \
|
||||
{ 10, 0x3c5, ns MPYH }, \
|
||||
{ 10, 0x3c6, ns MPYHH }, \
|
||||
{ 10, 0x3c7, ns MPYS }, \
|
||||
{ 10, 0x3c8, ns CEQH }, \
|
||||
{ 10, 0x3ca, ns FCMEQ }, \
|
||||
{ 10, 0x3cb, ns DFCMEQ }, \
|
||||
{ 10, 0x3cc, ns MPYU }, \
|
||||
{ 10, 0x3d0, ns CEQB }, \
|
||||
{ 10, 0x3d4, ns FI }, \
|
||||
{ 10, 0x3d8, ns HEQ }, \
|
||||
{ 9, 0x1d8, ns CFLTS }, \
|
||||
{ 9, 0x1d9, ns CFLTU }, \
|
||||
{ 9, 0x1da, ns CSFLT }, \
|
||||
{ 9, 0x1db, ns CUFLT }, \
|
||||
{ 8, 0x40, ns BRZ }, \
|
||||
{ 8, 0x41, ns STQA }, \
|
||||
{ 8, 0x42, ns BRNZ }, \
|
||||
{ 8, 0x44, ns BRHZ }, \
|
||||
{ 8, 0x46, ns BRHNZ }, \
|
||||
{ 8, 0x47, ns STQR }, \
|
||||
{ 8, 0x60, ns BRA }, \
|
||||
{ 8, 0x61, ns LQA }, \
|
||||
{ 8, 0x62, ns BRASL }, \
|
||||
{ 8, 0x64, ns BR }, \
|
||||
{ 8, 0x65, ns FSMBI }, \
|
||||
{ 8, 0x66, ns BRSL }, \
|
||||
{ 8, 0x67, ns LQR }, \
|
||||
{ 8, 0x81, ns IL }, \
|
||||
{ 8, 0x82, ns ILHU }, \
|
||||
{ 8, 0x83, ns ILH }, \
|
||||
{ 8, 0xc1, ns IOHL }, \
|
||||
{ 7, 0x4, ns ORI }, \
|
||||
{ 7, 0x5, ns ORHI }, \
|
||||
{ 7, 0x6, ns ORBI }, \
|
||||
{ 7, 0xc, ns SFI }, \
|
||||
{ 7, 0xd, ns SFHI }, \
|
||||
{ 7, 0x14, ns ANDI }, \
|
||||
{ 7, 0x15, ns ANDHI }, \
|
||||
{ 7, 0x16, ns ANDBI }, \
|
||||
{ 7, 0x1c, ns AI }, \
|
||||
{ 7, 0x1d, ns AHI }, \
|
||||
{ 7, 0x24, ns STQD }, \
|
||||
{ 7, 0x34, ns LQD }, \
|
||||
{ 7, 0x44, ns XORI }, \
|
||||
{ 7, 0x45, ns XORHI }, \
|
||||
{ 7, 0x46, ns XORBI }, \
|
||||
{ 7, 0x4c, ns CGTI }, \
|
||||
{ 7, 0x4d, ns CGTHI }, \
|
||||
{ 7, 0x4e, ns CGTBI }, \
|
||||
{ 7, 0x4f, ns HGTI }, \
|
||||
{ 7, 0x5c, ns CLGTI }, \
|
||||
{ 7, 0x5d, ns CLGTHI }, \
|
||||
{ 7, 0x5e, ns CLGTBI }, \
|
||||
{ 7, 0x5f, ns HLGTI }, \
|
||||
{ 7, 0x74, ns MPYI }, \
|
||||
{ 7, 0x75, ns MPYUI }, \
|
||||
{ 7, 0x7c, ns CEQI }, \
|
||||
{ 7, 0x7d, ns CEQHI }, \
|
||||
{ 7, 0x7e, ns CEQBI }, \
|
||||
{ 7, 0x7f, ns HEQI }, \
|
||||
{ 6, 0x8, ns HBRA }, \
|
||||
{ 6, 0x9, ns HBRR }, \
|
||||
{ 6, 0x21, ns ILA }, \
|
||||
{ 3, 0x8, ns SELB }, \
|
||||
{ 3, 0xb, ns SHUFB }, \
|
||||
{ 3, 0xc, ns MPYA }, \
|
||||
{ 3, 0xd, ns FNMS }, \
|
||||
{ 3, 0xe, ns FMA }, \
|
||||
{ 3, 0xf, ns FMS }, \
|
||||
}
|
||||
|
||||
static u32 branchTarget(const u32 pc, const s32 imm)
|
||||
template<typename T> class spu_opcode_table_t
|
||||
{
|
||||
std::array<T, 2048> m_data;
|
||||
|
||||
struct opcode_entry_t
|
||||
{
|
||||
return (pc + (imm << 2)) & 0x3fffc;
|
||||
u32 group;
|
||||
u32 value;
|
||||
T pointer;
|
||||
};
|
||||
|
||||
public:
|
||||
// opcode table initialization (TODO: optimize it a bit)
|
||||
spu_opcode_table_t(std::initializer_list<opcode_entry_t> opcodes, T default_value = {})
|
||||
{
|
||||
for (u32 i = 0; i < 2048; i++)
|
||||
{
|
||||
m_data[i] = default_value;
|
||||
|
||||
for (auto& op : opcodes)
|
||||
{
|
||||
if (((i << 21) & (INT_MIN >> op.group)) == (op.value << (31 - op.group)))
|
||||
{
|
||||
m_data[i] = op.pointer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//0 - 10
|
||||
virtual void STOP(u32 code) = 0;
|
||||
virtual void LNOP() = 0;
|
||||
virtual void SYNC(u32 Cbit) = 0;
|
||||
virtual void DSYNC() = 0;
|
||||
virtual void MFSPR(u32 rt, u32 sa) = 0;
|
||||
virtual void RDCH(u32 rt, u32 ra) = 0;
|
||||
virtual void RCHCNT(u32 rt, u32 ra) = 0;
|
||||
virtual void SF(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void OR(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void BG(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void SFH(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void NOR(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void ABSDB(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void ROT(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void ROTM(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void ROTMA(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void SHL(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void ROTH(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void ROTHM(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void ROTMAH(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void SHLH(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void ROTI(u32 rt, u32 ra, s32 i7) = 0;
|
||||
virtual void ROTMI(u32 rt, u32 ra, s32 i7) = 0;
|
||||
virtual void ROTMAI(u32 rt, u32 ra, s32 i7) = 0;
|
||||
virtual void SHLI(u32 rt, u32 ra, s32 i7) = 0;
|
||||
virtual void ROTHI(u32 rt, u32 ra, s32 i7) = 0;
|
||||
virtual void ROTHMI(u32 rt, u32 ra, s32 i7) = 0;
|
||||
virtual void ROTMAHI(u32 rt, u32 ra, s32 i7) = 0;
|
||||
virtual void SHLHI(u32 rt, u32 ra, s32 i7) = 0;
|
||||
virtual void A(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void AND(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void CG(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void AH(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void NAND(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void AVGB(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void MTSPR(u32 rt, u32 sa) = 0;
|
||||
virtual void WRCH(u32 ra, u32 rt) = 0;
|
||||
virtual void BIZ(u32 intr, u32 rt, u32 ra) = 0;
|
||||
virtual void BINZ(u32 intr, u32 rt, u32 ra) = 0;
|
||||
virtual void BIHZ(u32 intr, u32 rt, u32 ra) = 0;
|
||||
virtual void BIHNZ(u32 intr, u32 rt, u32 ra) = 0;
|
||||
virtual void STOPD(u32 rc, u32 ra, u32 rb) = 0;
|
||||
virtual void STQX(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void BI(u32 intr, u32 ra) = 0;
|
||||
virtual void BISL(u32 intr, u32 rt, u32 ra) = 0;
|
||||
virtual void IRET(u32 ra) = 0;
|
||||
virtual void BISLED(u32 intr, u32 rt, u32 ra) = 0;
|
||||
virtual void HBR(u32 p, u32 ro, u32 ra) = 0;
|
||||
virtual void GB(u32 rt, u32 ra) = 0;
|
||||
virtual void GBH(u32 rt, u32 ra) = 0;
|
||||
virtual void GBB(u32 rt, u32 ra) = 0;
|
||||
virtual void FSM(u32 rt, u32 ra) = 0;
|
||||
virtual void FSMH(u32 rt, u32 ra) = 0;
|
||||
virtual void FSMB(u32 rt, u32 ra) = 0;
|
||||
virtual void FREST(u32 rt, u32 ra) = 0;
|
||||
virtual void FRSQEST(u32 rt, u32 ra) = 0;
|
||||
virtual void LQX(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void ROTQBYBI(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void ROTQMBYBI(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void SHLQBYBI(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void CBX(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void CHX(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void CWX(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void CDX(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void ROTQBI(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void ROTQMBI(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void SHLQBI(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void ROTQBY(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void ROTQMBY(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void SHLQBY(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void ORX(u32 rt, u32 ra) = 0;
|
||||
virtual void CBD(u32 rt, u32 ra, s32 i7) = 0;
|
||||
virtual void CHD(u32 rt, u32 ra, s32 i7) = 0;
|
||||
virtual void CWD(u32 rt, u32 ra, s32 i7) = 0;
|
||||
virtual void CDD(u32 rt, u32 ra, s32 i7) = 0;
|
||||
virtual void ROTQBII(u32 rt, u32 ra, s32 i7) = 0;
|
||||
virtual void ROTQMBII(u32 rt, u32 ra, s32 i7) = 0;
|
||||
virtual void SHLQBII(u32 rt, u32 ra, s32 i7) = 0;
|
||||
virtual void ROTQBYI(u32 rt, u32 ra, s32 i7) = 0;
|
||||
virtual void ROTQMBYI(u32 rt, u32 ra, s32 i7) = 0;
|
||||
virtual void SHLQBYI(u32 rt, u32 ra, s32 i7) = 0;
|
||||
virtual void NOP(u32 rt) = 0;
|
||||
virtual void CGT(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void XOR(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void CGTH(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void EQV(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void CGTB(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void SUMB(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void HGT(u32 rt, s32 ra, s32 rb) = 0;
|
||||
virtual void CLZ(u32 rt, u32 ra) = 0;
|
||||
virtual void XSWD(u32 rt, u32 ra) = 0;
|
||||
virtual void XSHW(u32 rt, u32 ra) = 0;
|
||||
virtual void CNTB(u32 rt, u32 ra) = 0;
|
||||
virtual void XSBH(u32 rt, u32 ra) = 0;
|
||||
virtual void CLGT(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void ANDC(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void FCGT(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void DFCGT(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void FA(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void FS(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void FM(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void CLGTH(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void ORC(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void FCMGT(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void DFCMGT(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void DFA(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void DFS(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void DFM(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void CLGTB(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void HLGT(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void DFMA(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void DFMS(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void DFNMS(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void DFNMA(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void CEQ(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void MPYHHU(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void ADDX(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void SFX(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void CGX(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void BGX(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void MPYHHA(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void MPYHHAU(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void FSCRRD(u32 rt) = 0;
|
||||
virtual void FESD(u32 rt, u32 ra) = 0;
|
||||
virtual void FRDS(u32 rt, u32 ra) = 0;
|
||||
virtual void FSCRWR(u32 rt, u32 ra) = 0;
|
||||
virtual void DFTSV(u32 rt, u32 ra, s32 i7) = 0;
|
||||
virtual void FCEQ(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void DFCEQ(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void MPY(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void MPYH(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void MPYHH(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void MPYS(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void CEQH(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void FCMEQ(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void DFCMEQ(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void MPYU(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void CEQB(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void FI(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void HEQ(u32 rt, u32 ra, u32 rb) = 0;
|
||||
|
||||
//0 - 9
|
||||
virtual void CFLTS(u32 rt, u32 ra, s32 i8) = 0;
|
||||
virtual void CFLTU(u32 rt, u32 ra, s32 i8) = 0;
|
||||
virtual void CSFLT(u32 rt, u32 ra, s32 i8) = 0;
|
||||
virtual void CUFLT(u32 rt, u32 ra, s32 i8) = 0;
|
||||
|
||||
//0 - 8
|
||||
virtual void BRZ(u32 rt, s32 i16) = 0;
|
||||
virtual void STQA(u32 rt, s32 i16) = 0;
|
||||
virtual void BRNZ(u32 rt, s32 i16) = 0;
|
||||
virtual void BRHZ(u32 rt, s32 i16) = 0;
|
||||
virtual void BRHNZ(u32 rt, s32 i16) = 0;
|
||||
virtual void STQR(u32 rt, s32 i16) = 0;
|
||||
virtual void BRA(s32 i16) = 0;
|
||||
virtual void LQA(u32 rt, s32 i16) = 0;
|
||||
virtual void BRASL(u32 rt, s32 i16) = 0;
|
||||
virtual void BR(s32 i16) = 0;
|
||||
virtual void FSMBI(u32 rt, s32 i16) = 0;
|
||||
virtual void BRSL(u32 rt, s32 i16) = 0;
|
||||
virtual void LQR(u32 rt, s32 i16) = 0;
|
||||
virtual void IL(u32 rt, s32 i16) = 0;
|
||||
virtual void ILHU(u32 rt, s32 i16) = 0;
|
||||
virtual void ILH(u32 rt, s32 i16) = 0;
|
||||
virtual void IOHL(u32 rt, s32 i16) = 0;
|
||||
|
||||
//0 - 7
|
||||
virtual void ORI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void ORHI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void ORBI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void SFI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void SFHI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void ANDI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void ANDHI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void ANDBI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void AI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void AHI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void STQD(u32 rt, s32 i10, u32 ra) = 0;
|
||||
virtual void LQD(u32 rt, s32 i10, u32 ra) = 0;
|
||||
virtual void XORI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void XORHI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void XORBI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void CGTI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void CGTHI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void CGTBI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void HGTI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void CLGTI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void CLGTHI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void CLGTBI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void HLGTI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void MPYI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void MPYUI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void CEQI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void CEQHI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void CEQBI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
virtual void HEQI(u32 rt, u32 ra, s32 i10) = 0;
|
||||
|
||||
//0 - 6
|
||||
virtual void HBRA(s32 ro, s32 i16) = 0;
|
||||
virtual void HBRR(s32 ro, s32 i16) = 0;
|
||||
virtual void ILA(u32 rt, u32 i18) = 0;
|
||||
|
||||
//0 - 3
|
||||
virtual void SELB(u32 rc, u32 ra, u32 rb, u32 rt) = 0;
|
||||
virtual void SHUFB(u32 rc, u32 ra, u32 rb, u32 rt) = 0;
|
||||
virtual void MPYA(u32 rc, u32 ra, u32 rb, u32 rt) = 0;
|
||||
virtual void FNMS(u32 rc, u32 ra, u32 rb, u32 rt) = 0;
|
||||
virtual void FMA(u32 rc, u32 ra, u32 rb, u32 rt) = 0;
|
||||
virtual void FMS(u32 rc, u32 ra, u32 rb, u32 rt) = 0;
|
||||
|
||||
virtual void UNK(u32 code, u32 opcode, u32 gcode) = 0;
|
||||
// access opcode table
|
||||
inline T operator [](u32 opcode_data) const
|
||||
{
|
||||
// the whole decoding process is shifting opcode data
|
||||
return m_data[opcode_data >> 21];
|
||||
}
|
||||
};
|
||||
|
||||
inline u32 spu_branch_target(u32 pc, s32 imm)
|
||||
{
|
||||
return (pc + (imm << 2)) & 0x3fffc;
|
||||
}
|
||||
|
75
rpcs3/Emu/Cell/SPURecompiler.cpp
Normal file
75
rpcs3/Emu/Cell/SPURecompiler.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
|
||||
#include "SPUThread.h"
|
||||
#include "SPURecompiler.h"
|
||||
#include "SPUASMJITRecompiler.h"
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
SPURecompilerDecoder::SPURecompilerDecoder(SPUThread& spu)
|
||||
: db(fxm::get_always<SPUDatabase>())
|
||||
, rec(fxm::get_always<spu_recompiler>())
|
||||
, spu(spu)
|
||||
{
|
||||
}
|
||||
|
||||
u32 SPURecompilerDecoder::DecodeMemory(const u32 address)
|
||||
{
|
||||
if (spu.offset != address - spu.pc || spu.pc >= 0x40000 || spu.pc % 4)
|
||||
{
|
||||
throw EXCEPTION("Invalid address or PC (address=0x%x, PC=0x%05x)", address, spu.pc);
|
||||
}
|
||||
|
||||
const auto _ls = vm::get_ptr<be_t<u32>>(spu.offset);
|
||||
|
||||
const u32 index = spu.pc / 4;
|
||||
|
||||
if (!m_entries.at(index) || true) // always validate (TODO)
|
||||
{
|
||||
const auto func = db->analyse(_ls, spu.pc);
|
||||
|
||||
if (!func->compiled) rec->compile(*func);
|
||||
|
||||
if (!func->compiled) throw EXCEPTION("Compilation failed");
|
||||
|
||||
m_entries[index] = func->compiled;
|
||||
}
|
||||
|
||||
const u32 res = m_entries[index](&spu, _ls);
|
||||
|
||||
if (const auto exception = spu.pending_exception)
|
||||
{
|
||||
spu.pending_exception = nullptr;
|
||||
std::rethrow_exception(exception);
|
||||
}
|
||||
|
||||
if (res & 0x1000000)
|
||||
{
|
||||
spu.halt();
|
||||
}
|
||||
|
||||
if (res & 0x2000000)
|
||||
{
|
||||
}
|
||||
|
||||
if (res & 0x4000000)
|
||||
{
|
||||
if (res & 0x8000000)
|
||||
{
|
||||
throw EXCEPTION("Undefined behaviour");
|
||||
}
|
||||
|
||||
spu.set_interrupt_status(true);
|
||||
}
|
||||
else if (res & 0x8000000)
|
||||
{
|
||||
spu.set_interrupt_status(false);
|
||||
}
|
||||
|
||||
spu.pc = res & 0x3fffc;
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,325 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include "Emu/CPU/CPUDecoder.h"
|
||||
#include "Emu/Cell/SPUOpcodes.h"
|
||||
#include "SPUAnalyser.h"
|
||||
|
||||
namespace asmjit
|
||||
class SPUThread;
|
||||
|
||||
// SPU Recompiler instance base (must be global or PS3 process-local)
|
||||
class SPURecompilerBase
|
||||
{
|
||||
struct JitRuntime;
|
||||
struct X86Compiler;
|
||||
struct X86GpVar;
|
||||
struct X86XmmVar;
|
||||
struct X86Mem;
|
||||
}
|
||||
protected:
|
||||
std::mutex m_mutex; // must be locked in compile()
|
||||
|
||||
class SPURecompiler;
|
||||
class SPUInterpreter;
|
||||
const spu_function_t* m_func; // current function
|
||||
|
||||
class SPURecompilerCore : public CPUDecoder
|
||||
{
|
||||
std::unique_ptr<SPURecompiler> m_enc;
|
||||
std::unique_ptr<SPUInterpreter> m_int;
|
||||
std::unique_ptr<asmjit::JitRuntime> m_jit;
|
||||
SPUThread& CPU;
|
||||
u32 m_pos; // current position
|
||||
|
||||
public:
|
||||
bool first = true;
|
||||
bool need_check = false;
|
||||
|
||||
struct SPURecEntry
|
||||
{
|
||||
u32 count; // count of instructions compiled from current point (and to be checked)
|
||||
be_t<u32> _valid; // copy of valid opcode for validation
|
||||
void* pointer; // pointer to executable memory object
|
||||
};
|
||||
|
||||
std::array<SPURecEntry, 0x10000> entry = {};
|
||||
|
||||
std::vector<v128> imm_table;
|
||||
|
||||
SPURecompilerCore(SPUThread& cpu);
|
||||
|
||||
void Compile(u16 pos);
|
||||
|
||||
virtual void Decode(const u32 code);
|
||||
|
||||
virtual u32 DecodeMemory(const u32 address);
|
||||
virtual void compile(spu_function_t& f) = 0; // compile specified function
|
||||
virtual ~SPURecompilerBase() {};
|
||||
};
|
||||
|
||||
class SPURecompiler : public SPUOpcodes
|
||||
// SPU Decoder instance (created per SPU thread)
|
||||
class SPURecompilerDecoder final : public CPUDecoder
|
||||
{
|
||||
private:
|
||||
SPUThread& CPU;
|
||||
SPURecompilerCore& rec;
|
||||
std::array<spu_jit_func_t, 0x10000> m_entries = {}; // currently useless
|
||||
|
||||
public:
|
||||
asmjit::X86Compiler* compiler;
|
||||
bool do_finalize;
|
||||
// input:
|
||||
asmjit::X86GpVar* cpu_var;
|
||||
asmjit::X86GpVar* ls_var;
|
||||
asmjit::X86GpVar* imm_var;
|
||||
asmjit::X86GpVar* g_imm_var;
|
||||
// output:
|
||||
asmjit::X86GpVar* pos_var;
|
||||
// temporary:
|
||||
asmjit::X86GpVar* addr;
|
||||
asmjit::X86GpVar* qw0;
|
||||
asmjit::X86GpVar* qw1;
|
||||
asmjit::X86GpVar* qw2;
|
||||
const std::shared_ptr<SPUDatabase> db; // associated SPU Analyser instance
|
||||
|
||||
struct XmmLink
|
||||
{
|
||||
asmjit::X86XmmVar* data = nullptr;
|
||||
s8 reg = -1;
|
||||
bool taken = false;
|
||||
mutable bool got = false;
|
||||
mutable u32 access = 0;
|
||||
const std::shared_ptr<SPURecompilerBase> rec; // assiciated SPU Recompiler instance
|
||||
|
||||
const asmjit::X86XmmVar& get() const
|
||||
{
|
||||
assert(data);
|
||||
if (!taken) throw EXCEPTION("Register not taken");
|
||||
got = true;
|
||||
return *data;
|
||||
}
|
||||
SPUThread& spu; // associated SPU Thread
|
||||
|
||||
const asmjit::X86XmmVar& read() const
|
||||
{
|
||||
assert(data);
|
||||
return *data;
|
||||
}
|
||||
}
|
||||
xmm_var[16];
|
||||
SPURecompilerDecoder(SPUThread& spu);
|
||||
|
||||
SPURecompiler(SPUThread& cpu, SPURecompilerCore& rec)
|
||||
: CPU(cpu)
|
||||
, rec(rec)
|
||||
, compiler(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
const XmmLink& XmmAlloc(s8 pref = -1);
|
||||
const XmmLink* XmmRead(const s8 reg) const;
|
||||
const XmmLink& XmmGet(s8 reg, s8 target = -1);
|
||||
const XmmLink& XmmCopy(const XmmLink& from, s8 pref = -1);
|
||||
void XmmInvalidate(const s8 reg);
|
||||
void XmmFinalize(const XmmLink& var, s8 reg = -1);
|
||||
void XmmRelease();
|
||||
asmjit::X86Mem XmmConst(v128 data);
|
||||
|
||||
private:
|
||||
|
||||
//0 - 10
|
||||
virtual void STOP(u32 code) override;
|
||||
virtual void LNOP() override;
|
||||
virtual void SYNC(u32 Cbit) override;
|
||||
virtual void DSYNC() override;
|
||||
virtual void MFSPR(u32 rt, u32 sa) override;
|
||||
virtual void RDCH(u32 rt, u32 ra) override;
|
||||
virtual void RCHCNT(u32 rt, u32 ra) override;
|
||||
virtual void SF(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void OR(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void BG(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void SFH(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void NOR(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void ABSDB(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void ROT(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void ROTM(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void ROTMA(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void SHL(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void ROTH(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void ROTHM(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void ROTMAH(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void SHLH(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void ROTI(u32 rt, u32 ra, s32 i7) override;
|
||||
virtual void ROTMI(u32 rt, u32 ra, s32 i7) override;
|
||||
virtual void ROTMAI(u32 rt, u32 ra, s32 i7) override;
|
||||
virtual void SHLI(u32 rt, u32 ra, s32 i7) override;
|
||||
virtual void ROTHI(u32 rt, u32 ra, s32 i7) override;
|
||||
virtual void ROTHMI(u32 rt, u32 ra, s32 i7) override;
|
||||
virtual void ROTMAHI(u32 rt, u32 ra, s32 i7) override;
|
||||
virtual void SHLHI(u32 rt, u32 ra, s32 i7) override;
|
||||
virtual void A(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void AND(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void CG(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void AH(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void NAND(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void AVGB(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void MTSPR(u32 rt, u32 sa) override;
|
||||
virtual void WRCH(u32 ra, u32 rt) override;
|
||||
virtual void BIZ(u32 intr, u32 rt, u32 ra) override;
|
||||
virtual void BINZ(u32 intr, u32 rt, u32 ra) override;
|
||||
virtual void BIHZ(u32 intr, u32 rt, u32 ra) override;
|
||||
virtual void BIHNZ(u32 intr, u32 rt, u32 ra) override;
|
||||
virtual void STOPD(u32 rc, u32 ra, u32 rb) override;
|
||||
virtual void STQX(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void BI(u32 intr, u32 ra) override;
|
||||
virtual void BISL(u32 intr, u32 rt, u32 ra) override;
|
||||
virtual void IRET(u32 ra) override;
|
||||
virtual void BISLED(u32 intr, u32 rt, u32 ra) override;
|
||||
virtual void HBR(u32 p, u32 ro, u32 ra) override;
|
||||
virtual void GB(u32 rt, u32 ra) override;
|
||||
virtual void GBH(u32 rt, u32 ra) override;
|
||||
virtual void GBB(u32 rt, u32 ra) override;
|
||||
virtual void FSM(u32 rt, u32 ra) override;
|
||||
virtual void FSMH(u32 rt, u32 ra) override;
|
||||
virtual void FSMB(u32 rt, u32 ra) override;
|
||||
virtual void FREST(u32 rt, u32 ra) override;
|
||||
virtual void FRSQEST(u32 rt, u32 ra) override;
|
||||
virtual void LQX(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void ROTQBYBI(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void ROTQMBYBI(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void SHLQBYBI(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void CBX(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void CHX(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void CWX(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void CDX(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void ROTQBI(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void ROTQMBI(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void SHLQBI(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void ROTQBY(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void ROTQMBY(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void SHLQBY(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void ORX(u32 rt, u32 ra) override;
|
||||
virtual void CBD(u32 rt, u32 ra, s32 i7) override;
|
||||
virtual void CHD(u32 rt, u32 ra, s32 i7) override;
|
||||
virtual void CWD(u32 rt, u32 ra, s32 i7) override;
|
||||
virtual void CDD(u32 rt, u32 ra, s32 i7) override;
|
||||
virtual void ROTQBII(u32 rt, u32 ra, s32 i7) override;
|
||||
virtual void ROTQMBII(u32 rt, u32 ra, s32 i7) override;
|
||||
virtual void SHLQBII(u32 rt, u32 ra, s32 i7) override;
|
||||
virtual void ROTQBYI(u32 rt, u32 ra, s32 i7) override;
|
||||
virtual void ROTQMBYI(u32 rt, u32 ra, s32 i7) override;
|
||||
virtual void SHLQBYI(u32 rt, u32 ra, s32 i7) override;
|
||||
virtual void NOP(u32 rt) override;
|
||||
virtual void CGT(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void XOR(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void CGTH(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void EQV(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void CGTB(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void SUMB(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void HGT(u32 rt, s32 ra, s32 rb) override;
|
||||
virtual void CLZ(u32 rt, u32 ra) override;
|
||||
virtual void XSWD(u32 rt, u32 ra) override;
|
||||
virtual void XSHW(u32 rt, u32 ra) override;
|
||||
virtual void CNTB(u32 rt, u32 ra) override;
|
||||
virtual void XSBH(u32 rt, u32 ra) override;
|
||||
virtual void CLGT(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void ANDC(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void FCGT(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void DFCGT(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void FA(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void FS(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void FM(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void CLGTH(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void ORC(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void FCMGT(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void DFCMGT(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void DFA(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void DFS(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void DFM(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void CLGTB(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void HLGT(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void DFMA(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void DFMS(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void DFNMS(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void DFNMA(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void CEQ(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void MPYHHU(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void ADDX(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void SFX(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void CGX(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void BGX(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void MPYHHA(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void MPYHHAU(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void FSCRRD(u32 rt) override;
|
||||
virtual void FESD(u32 rt, u32 ra) override;
|
||||
virtual void FRDS(u32 rt, u32 ra) override;
|
||||
virtual void FSCRWR(u32 rt, u32 ra) override;
|
||||
virtual void DFTSV(u32 rt, u32 ra, s32 i7) override;
|
||||
virtual void FCEQ(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void DFCEQ(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void MPY(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void MPYH(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void MPYHH(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void MPYS(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void CEQH(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void FCMEQ(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void DFCMEQ(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void MPYU(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void CEQB(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void FI(u32 rt, u32 ra, u32 rb) override;
|
||||
virtual void HEQ(u32 rt, u32 ra, u32 rb) override;
|
||||
|
||||
//0 - 9
|
||||
virtual void CFLTS(u32 rt, u32 ra, s32 i8) override;
|
||||
virtual void CFLTU(u32 rt, u32 ra, s32 i8) override;
|
||||
virtual void CSFLT(u32 rt, u32 ra, s32 i8) override;
|
||||
virtual void CUFLT(u32 rt, u32 ra, s32 i8) override;
|
||||
|
||||
//0 - 8
|
||||
virtual void BRZ(u32 rt, s32 i16) override;
|
||||
virtual void STQA(u32 rt, s32 i16) override;
|
||||
virtual void BRNZ(u32 rt, s32 i16) override;
|
||||
virtual void BRHZ(u32 rt, s32 i16) override;
|
||||
virtual void BRHNZ(u32 rt, s32 i16) override;
|
||||
virtual void STQR(u32 rt, s32 i16) override;
|
||||
virtual void BRA(s32 i16) override;
|
||||
virtual void LQA(u32 rt, s32 i16) override;
|
||||
virtual void BRASL(u32 rt, s32 i16) override;
|
||||
virtual void BR(s32 i16) override;
|
||||
virtual void FSMBI(u32 rt, s32 i16) override;
|
||||
virtual void BRSL(u32 rt, s32 i16) override;
|
||||
virtual void LQR(u32 rt, s32 i16) override;
|
||||
virtual void IL(u32 rt, s32 i16) override;
|
||||
virtual void ILHU(u32 rt, s32 i16) override;
|
||||
virtual void ILH(u32 rt, s32 i16) override;
|
||||
virtual void IOHL(u32 rt, s32 i16) override;
|
||||
|
||||
//0 - 7
|
||||
virtual void ORI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void ORHI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void ORBI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void SFI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void SFHI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void ANDI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void ANDHI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void ANDBI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void AI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void AHI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void STQD(u32 rt, s32 i10, u32 ra) override;
|
||||
virtual void LQD(u32 rt, s32 i10, u32 ra) override;
|
||||
virtual void XORI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void XORHI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void XORBI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void CGTI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void CGTHI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void CGTBI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void HGTI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void CLGTI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void CLGTHI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void CLGTBI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void HLGTI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void MPYI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void MPYUI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void CEQI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void CEQHI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void CEQBI(u32 rt, u32 ra, s32 i10) override;
|
||||
virtual void HEQI(u32 rt, u32 ra, s32 i10) override;
|
||||
|
||||
//0 - 6
|
||||
virtual void HBRA(s32 ro, s32 i16) override;
|
||||
virtual void HBRR(s32 ro, s32 i16) override;
|
||||
virtual void ILA(u32 rt, u32 i18) override;
|
||||
|
||||
//0 - 3
|
||||
virtual void SELB(u32 rc, u32 ra, u32 rb, u32 rt) override;
|
||||
virtual void SHUFB(u32 rc, u32 ra, u32 rb, u32 rt) override;
|
||||
virtual void MPYA(u32 rc, u32 ra, u32 rb, u32 rt) override;
|
||||
virtual void FNMS(u32 rc, u32 ra, u32 rb, u32 rt) override;
|
||||
virtual void FMA(u32 rc, u32 ra, u32 rb, u32 rt) override;
|
||||
virtual void FMS(u32 rc, u32 ra, u32 rb, u32 rt) override;
|
||||
|
||||
virtual void UNK(u32 code, u32 opcode, u32 gcode) override;
|
||||
virtual void UNK(const std::string& error);
|
||||
u32 DecodeMemory(const u32 address) override; // non-virtual override (to avoid virtual call whenever possible)
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -14,15 +14,18 @@
|
||||
|
||||
#include "Emu/Cell/SPUDisAsm.h"
|
||||
#include "Emu/Cell/SPUThread.h"
|
||||
#include "Emu/Cell/SPUDecoder.h"
|
||||
#include "Emu/Cell/SPUInterpreter.h"
|
||||
#include "Emu/Cell/SPUInterpreter2.h"
|
||||
#include "Emu/Cell/SPURecompiler.h"
|
||||
|
||||
#include <cfenv>
|
||||
|
||||
extern u64 get_timebased_time();
|
||||
|
||||
// defined here since SPUDisAsm.cpp doesn't exist
|
||||
const spu_opcode_table_t<void(SPUDisAsm::*)(spu_opcode_t)> SPUDisAsm::opcodes{ DEFINE_SPU_OPCODES(&SPUDisAsm::), &SPUDisAsm::UNK };
|
||||
|
||||
thread_local bool spu_channel_t::notification_required;
|
||||
|
||||
void spu_int_ctrl_t::set(u64 ints)
|
||||
{
|
||||
// leave only enabled interrupts
|
||||
@ -47,40 +50,7 @@ void spu_int_ctrl_t::clear(u64 ints)
|
||||
stat &= ~ints;
|
||||
}
|
||||
|
||||
const g_spu_imm_table_t g_spu_imm;
|
||||
|
||||
class spu_inter_func_list_t
|
||||
{
|
||||
std::array<spu_inter_func_t, 2048> funcs = {};
|
||||
|
||||
std::mutex m_mutex;
|
||||
|
||||
public:
|
||||
void initialize()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
if (funcs[0]) return; // check if already initialized
|
||||
|
||||
auto inter = new SPUInterpreter2;
|
||||
SPUDecoder dec(*inter);
|
||||
|
||||
for (u32 i = 0; i < funcs.size(); i++)
|
||||
{
|
||||
inter->func = spu_interpreter::DEFAULT;
|
||||
|
||||
dec.Decode(i << 21);
|
||||
|
||||
funcs[i] = inter->func;
|
||||
}
|
||||
}
|
||||
|
||||
force_inline spu_inter_func_t operator [](u32 opcode) const
|
||||
{
|
||||
return funcs[opcode >> 21];
|
||||
}
|
||||
}
|
||||
g_spu_inter_func_list;
|
||||
const spu_imm_table_t g_spu_imm;
|
||||
|
||||
SPUThread::SPUThread(CPUThreadType type, const std::string& name, std::function<std::string()> thread_name, u32 index, u32 offset)
|
||||
: CPUThread(type, name, std::move(thread_name))
|
||||
@ -90,7 +60,7 @@ SPUThread::SPUThread(CPUThreadType type, const std::string& name, std::function<
|
||||
}
|
||||
|
||||
SPUThread::SPUThread(const std::string& name, u32 index)
|
||||
: CPUThread(CPU_THREAD_SPU, name, WRAP_EXPR(fmt::format("SPU[0x%x] Thread (%s)[0x%08x]", m_id, m_name.c_str(), PC)))
|
||||
: CPUThread(CPU_THREAD_SPU, name, WRAP_EXPR(fmt::format("SPU[0x%x] Thread (%s)[0x%05x]", m_id, m_name.c_str(), pc)))
|
||||
, index(index)
|
||||
, offset(vm::alloc(0x40000, vm::main))
|
||||
{
|
||||
@ -138,51 +108,55 @@ void SPUThread::task()
|
||||
{
|
||||
std::fesetround(FE_TOWARDZERO);
|
||||
|
||||
if (!custom_task && !m_dec)
|
||||
{
|
||||
// Select opcode table (TODO)
|
||||
const auto& table = Ini.SPUDecoderMode.GetValue() == 0 ? spu_interpreter::precise::g_spu_opcode_table : spu_interpreter::fast::g_spu_opcode_table;
|
||||
|
||||
// LS base address
|
||||
const auto base = vm::get_ptr<const be_t<u32>>(offset);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!m_state.load())
|
||||
{
|
||||
// read opcode
|
||||
const u32 opcode = base[pc / 4];
|
||||
|
||||
// call interpreter function
|
||||
table[opcode](*this, { opcode });
|
||||
|
||||
// next instruction
|
||||
pc += 4;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (check_status())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (custom_task)
|
||||
{
|
||||
if (check_status()) return;
|
||||
|
||||
return custom_task(*this);
|
||||
}
|
||||
|
||||
if (m_dec)
|
||||
|
||||
while (!m_state.load() || !check_status())
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (m_state.load() && check_status()) break;
|
||||
|
||||
// decode instruction using specified decoder
|
||||
m_dec->DecodeMemory(PC + offset);
|
||||
|
||||
// next instruction
|
||||
PC += 4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (m_state.load() && check_status()) break;
|
||||
|
||||
// read opcode
|
||||
const spu_opcode_t opcode = { vm::read32(PC + offset) };
|
||||
|
||||
// get interpreter function
|
||||
const auto func = g_spu_inter_func_list[opcode.opcode];
|
||||
|
||||
// call interpreter function
|
||||
func(*this, opcode);
|
||||
|
||||
// next instruction
|
||||
PC += 4;
|
||||
}
|
||||
// decode instruction using specified decoder
|
||||
pc += m_dec->DecodeMemory(pc + offset);
|
||||
}
|
||||
}
|
||||
|
||||
void SPUThread::init_regs()
|
||||
{
|
||||
memset(GPR, 0, sizeof(GPR));
|
||||
FPSCR.Reset();
|
||||
gpr = {};
|
||||
fpscr.Reset();
|
||||
|
||||
ch_mfc_args = {};
|
||||
mfc_queue.clear();
|
||||
@ -215,7 +189,7 @@ void SPUThread::init_regs()
|
||||
|
||||
int_ctrl = {};
|
||||
|
||||
GPR[1]._u32[3] = 0x3FFF0; // initial stack frame pointer
|
||||
gpr[1]._u32[3] = 0x3FFF0; // initial stack frame pointer
|
||||
}
|
||||
|
||||
void SPUThread::init_stack()
|
||||
@ -230,25 +204,19 @@ void SPUThread::close_stack()
|
||||
|
||||
void SPUThread::do_run()
|
||||
{
|
||||
m_dec = nullptr;
|
||||
m_dec.reset();
|
||||
|
||||
switch (auto mode = Ini.SPUDecoderMode.GetValue())
|
||||
{
|
||||
case 0: // original interpreter
|
||||
case 0: // Interpreter 1 (Precise)
|
||||
case 1: // Interpreter 2 (Fast)
|
||||
{
|
||||
m_dec.reset(new SPUDecoder(*new SPUInterpreter(*this)));
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: // alternative interpreter
|
||||
{
|
||||
g_spu_inter_func_list.initialize(); // initialize helper table
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
m_dec.reset(new SPURecompilerCore(*this));
|
||||
m_dec.reset(new SPURecompilerDecoder(*this));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -267,15 +235,16 @@ void SPUThread::fast_call(u32 ls_addr)
|
||||
throw EXCEPTION("Called from the wrong thread");
|
||||
}
|
||||
|
||||
// LS:0x0: this is originally the entry point of the interrupt handler, but interrupts are not implemented
|
||||
write32(0x0, 2);
|
||||
|
||||
auto old_PC = PC;
|
||||
auto old_LR = GPR[0]._u32[3];
|
||||
auto old_stack = GPR[1]._u32[3]; // only saved and restored (may be wrong)
|
||||
auto old_pc = pc;
|
||||
auto old_lr = gpr[0]._u32[3];
|
||||
auto old_stack = gpr[1]._u32[3]; // only saved and restored (may be wrong)
|
||||
auto old_task = std::move(custom_task);
|
||||
|
||||
PC = ls_addr;
|
||||
GPR[0]._u32[3] = 0x0;
|
||||
pc = ls_addr;
|
||||
gpr[0]._u32[3] = 0x0;
|
||||
custom_task = nullptr;
|
||||
|
||||
try
|
||||
@ -288,9 +257,9 @@ void SPUThread::fast_call(u32 ls_addr)
|
||||
|
||||
m_state &= ~CPU_STATE_RETURN;
|
||||
|
||||
PC = old_PC;
|
||||
GPR[0]._u32[3] = old_LR;
|
||||
GPR[1]._u32[3] = old_stack;
|
||||
pc = old_pc;
|
||||
gpr[0]._u32[3] = old_lr;
|
||||
gpr[1]._u32[3] = old_stack;
|
||||
custom_task = std::move(old_task);
|
||||
}
|
||||
|
||||
@ -1218,14 +1187,18 @@ void SPUThread::stop_and_signal(u32 code)
|
||||
|
||||
case 0x003:
|
||||
{
|
||||
auto iter = m_addr_to_hle_function_map.find(PC);
|
||||
assert(iter != m_addr_to_hle_function_map.end());
|
||||
const auto found = m_addr_to_hle_function_map.find(pc);
|
||||
|
||||
auto return_to_caller = iter->second(*this);
|
||||
if (return_to_caller)
|
||||
if (found == m_addr_to_hle_function_map.end())
|
||||
{
|
||||
PC = (GPR[0]._u32[3] & 0x3fffc) - 4;
|
||||
throw EXCEPTION("HLE function not registered (PC=0x%05x)", pc);
|
||||
}
|
||||
|
||||
if (const auto return_to_caller = found->second(*this))
|
||||
{
|
||||
pc = (gpr[0]._u32[3] & 0x3fffc) - 4;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1472,7 +1445,7 @@ spu_thread::spu_thread(u32 entry, const std::string& name, u32 stack_size, u32 p
|
||||
{
|
||||
auto spu = idm::make_ptr<SPUThread>(name, 0x13370666);
|
||||
|
||||
spu->PC = entry;
|
||||
spu->pc = entry;
|
||||
|
||||
thread = std::move(spu);
|
||||
}
|
||||
|
@ -135,16 +135,15 @@ enum
|
||||
SPU_RdSigNotify2_offs = 0x1C00C,
|
||||
};
|
||||
|
||||
union spu_channel_t
|
||||
struct spu_channel_t
|
||||
{
|
||||
// set to true if SPU thread must be notified after SPU channel operation
|
||||
thread_local static bool notification_required;
|
||||
|
||||
struct sync_var_t
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 waiting : 1; // waiting flag (0..1)
|
||||
u32 count : 1; // channel count (0..1)
|
||||
};
|
||||
|
||||
bool count; // value available
|
||||
bool wait; // notification required
|
||||
u32 value;
|
||||
};
|
||||
|
||||
@ -154,93 +153,75 @@ public:
|
||||
// returns true on success
|
||||
bool try_push(u32 value)
|
||||
{
|
||||
return sync_var.atomic_op([=](sync_var_t& data) -> bool
|
||||
const auto old = sync_var.atomic_op([=](sync_var_t& data)
|
||||
{
|
||||
if (data.count == 0)
|
||||
if ((data.wait = data.count) == false)
|
||||
{
|
||||
data.waiting = 0;
|
||||
data.count = 1;
|
||||
data.count = true;
|
||||
data.value = value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
data.waiting = 1;
|
||||
return false;
|
||||
});
|
||||
|
||||
return !old.count;
|
||||
}
|
||||
|
||||
// push performing bitwise OR with previous value, returns true if needs signaling
|
||||
bool push_or(u32 value)
|
||||
// push performing bitwise OR with previous value, may require notification
|
||||
void push_or(u32 value)
|
||||
{
|
||||
return sync_var.atomic_op([=](sync_var_t& data) -> bool
|
||||
const auto old = sync_var.atomic_op([=](sync_var_t& data)
|
||||
{
|
||||
data.count = 1;
|
||||
data.count = true;
|
||||
data.wait = false;
|
||||
data.value |= value;
|
||||
|
||||
if (data.waiting)
|
||||
{
|
||||
data.waiting = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
notification_required = old.wait;
|
||||
}
|
||||
|
||||
// push unconditionally (overwriting previous value), returns true if needs signaling
|
||||
bool push(u32 value)
|
||||
// push unconditionally (overwriting previous value), may require notification
|
||||
void push(u32 value)
|
||||
{
|
||||
return sync_var.atomic_op([=](sync_var_t& data) -> bool
|
||||
const auto old = sync_var.atomic_op([=](sync_var_t& data)
|
||||
{
|
||||
data.count = 1;
|
||||
data.count = true;
|
||||
data.wait = false;
|
||||
data.value = value;
|
||||
|
||||
if (data.waiting)
|
||||
{
|
||||
data.waiting = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
notification_required = old.wait;
|
||||
}
|
||||
|
||||
// returns true on success and u32 value
|
||||
// returns true on success and loaded value
|
||||
std::tuple<bool, u32> try_pop()
|
||||
{
|
||||
return sync_var.atomic_op([](sync_var_t& data)
|
||||
const auto old = sync_var.atomic_op([](sync_var_t& data)
|
||||
{
|
||||
const auto result = std::make_tuple(data.count != 0, u32{ data.value });
|
||||
|
||||
data.waiting = data.count == 0;
|
||||
data.count = 0;
|
||||
data.value = 0;
|
||||
|
||||
return result;
|
||||
data.wait = !data.count;
|
||||
data.count = false;
|
||||
data.value = 0; // ???
|
||||
});
|
||||
|
||||
return std::tie(old.count, old.value);
|
||||
}
|
||||
|
||||
// pop unconditionally (loading last value), returns u32 value and bool value (true if needs signaling)
|
||||
std::tuple<u32, bool> pop()
|
||||
// pop unconditionally (loading last value), may require notification
|
||||
u32 pop()
|
||||
{
|
||||
return sync_var.atomic_op([](sync_var_t& data)
|
||||
const auto old = sync_var.atomic_op([](sync_var_t& data)
|
||||
{
|
||||
const auto result = std::make_tuple(u32{ data.value }, data.waiting != 0);
|
||||
|
||||
data.waiting = 0;
|
||||
data.count = 0;
|
||||
data.wait = false;
|
||||
data.count = false;
|
||||
// value is not cleared and may be read again
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
notification_required = old.wait;
|
||||
|
||||
return old.value;
|
||||
}
|
||||
|
||||
void set_value(u32 value, u32 count = 1)
|
||||
void set_value(u32 value, bool count = true)
|
||||
{
|
||||
sync_var.store({ { 0, count }, value });
|
||||
sync_var.store({ count, false, value });
|
||||
}
|
||||
|
||||
u32 get_value() volatile
|
||||
@ -358,7 +339,7 @@ struct spu_int_ctrl_t
|
||||
void clear(u64 ints);
|
||||
};
|
||||
|
||||
struct g_spu_imm_table_t
|
||||
struct spu_imm_table_t
|
||||
{
|
||||
v128 fsmb[65536]; // table for FSMB, FSMBI instructions
|
||||
v128 fsmh[256]; // table for FSMH instruction
|
||||
@ -388,7 +369,7 @@ struct g_spu_imm_table_t
|
||||
}
|
||||
const scale;
|
||||
|
||||
g_spu_imm_table_t()
|
||||
spu_imm_table_t()
|
||||
{
|
||||
for (u32 i = 0; i < sizeof(fsm) / sizeof(fsm[0]); i++)
|
||||
{
|
||||
@ -440,7 +421,7 @@ struct g_spu_imm_table_t
|
||||
}
|
||||
};
|
||||
|
||||
extern const g_spu_imm_table_t g_spu_imm;
|
||||
extern const spu_imm_table_t g_spu_imm;
|
||||
|
||||
enum FPSCR_EX
|
||||
{
|
||||
@ -543,9 +524,11 @@ public:
|
||||
|
||||
class SPUThread : public CPUThread
|
||||
{
|
||||
friend class spu_recompiler;
|
||||
|
||||
public:
|
||||
v128 GPR[128]; // General-Purpose Registers
|
||||
SPU_FPSCR FPSCR;
|
||||
std::array<v128, 128> gpr; // General-Purpose Registers
|
||||
SPU_FPSCR fpscr;
|
||||
|
||||
std::unordered_map<u32, std::function<bool(SPUThread& SPU)>> m_addr_to_hle_function_map;
|
||||
|
||||
@ -586,43 +569,34 @@ public:
|
||||
std::array<std::pair<u32, std::weak_ptr<lv2_event_queue_t>>, 32> spuq; // Event Queue Keys for SPU Thread
|
||||
std::weak_ptr<lv2_event_queue_t> spup[64]; // SPU Ports
|
||||
|
||||
u32 PC = 0;
|
||||
u32 pc = 0; //
|
||||
const u32 index; // SPU index
|
||||
const u32 offset; // SPU LS offset
|
||||
|
||||
void push_snr(u32 number, u32 value)
|
||||
{
|
||||
if (number == 0)
|
||||
// get channel
|
||||
const auto channel =
|
||||
number == 0 ? &ch_snr1 :
|
||||
number == 1 ? &ch_snr2 : throw EXCEPTION("Unexpected");
|
||||
|
||||
// check corresponding SNR register settings
|
||||
if ((snr_config >> number) & 1)
|
||||
{
|
||||
if (snr_config & 1)
|
||||
{
|
||||
if (!ch_snr1.push_or(value)) return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ch_snr1.push(value)) return;
|
||||
}
|
||||
}
|
||||
else if (number == 1)
|
||||
{
|
||||
if (snr_config & 2)
|
||||
{
|
||||
if (!ch_snr2.push_or(value)) return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ch_snr2.push(value)) return;
|
||||
}
|
||||
channel->push_or(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw EXCEPTION("Unexpected");
|
||||
channel->push(value);
|
||||
}
|
||||
|
||||
// notify if required
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
if (channel->notification_required)
|
||||
{
|
||||
// lock for reliable notification
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
|
||||
cv.notify_one();
|
||||
cv.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
void do_dma_transfer(u32 cmd, spu_mfc_arg_t args);
|
||||
@ -683,6 +657,7 @@ public:
|
||||
}
|
||||
|
||||
std::function<void(SPUThread&)> custom_task;
|
||||
std::exception_ptr pending_exception;
|
||||
|
||||
protected:
|
||||
SPUThread(CPUThreadType type, const std::string& name, std::function<std::string()> thread_name, u32 index, u32 offset);
|
||||
@ -694,7 +669,7 @@ public:
|
||||
virtual bool is_paused() const override;
|
||||
|
||||
virtual void dump_info() const override;
|
||||
virtual u32 get_pc() const override { return PC; }
|
||||
virtual u32 get_pc() const override { return pc; }
|
||||
virtual u32 get_offset() const override { return offset; }
|
||||
virtual void do_run() override;
|
||||
virtual void task() override;
|
||||
@ -709,7 +684,7 @@ public:
|
||||
{
|
||||
std::string ret = "Registers:\n=========\n";
|
||||
|
||||
for(uint i=0; i<128; ++i) ret += fmt::format("GPR[%d] = 0x%s\n", i, GPR[i].to_hex().c_str());
|
||||
for(uint i=0; i<128; ++i) ret += fmt::format("GPR[%d] = 0x%s\n", i, gpr[i].to_hex().c_str());
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -721,7 +696,7 @@ public:
|
||||
{
|
||||
long reg_index;
|
||||
reg_index = atol(reg.substr(first_brk + 1, reg.length()-2).c_str());
|
||||
if (reg.find("GPR")==0) return fmt::format("%016llx%016llx", GPR[reg_index]._u64[1], GPR[reg_index]._u64[0]);
|
||||
if (reg.find("GPR")==0) return fmt::format("%016llx%016llx", gpr[reg_index]._u64[1], gpr[reg_index]._u64[0]);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@ -747,8 +722,8 @@ public:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
GPR[reg_index]._u64[0] = (u64)reg_value0;
|
||||
GPR[reg_index]._u64[1] = (u64)reg_value1;
|
||||
gpr[reg_index]._u64[0] = (u64)reg_value0;
|
||||
gpr[reg_index]._u64[1] = (u64)reg_value1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1083,17 +1083,17 @@ namespace vm
|
||||
{
|
||||
SPUThread& context = static_cast<SPUThread&>(cpu);
|
||||
|
||||
old_pos = context.GPR[1]._u32[3];
|
||||
context.GPR[1]._u32[3] -= align(size, 16);
|
||||
context.GPR[1]._u32[3] &= ~(align_v - 1);
|
||||
old_pos = context.gpr[1]._u32[3];
|
||||
context.gpr[1]._u32[3] -= align(size, 16);
|
||||
context.gpr[1]._u32[3] &= ~(align_v - 1);
|
||||
|
||||
if (context.GPR[1]._u32[3] >= 0x40000) // extremely rough
|
||||
if (context.gpr[1]._u32[3] >= 0x40000) // extremely rough
|
||||
{
|
||||
throw EXCEPTION("Stack overflow (size=0x%x, align=0x%x, SP=LS:0x%05x)", size, align_v, old_pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
return context.GPR[1]._u32[3] + context.offset;
|
||||
return context.gpr[1]._u32[3] + context.offset;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1144,12 +1144,12 @@ namespace vm
|
||||
{
|
||||
SPUThread& context = static_cast<SPUThread&>(cpu);
|
||||
|
||||
if (context.GPR[1]._u32[3] + context.offset != addr)
|
||||
if (context.gpr[1]._u32[3] + context.offset != addr)
|
||||
{
|
||||
throw EXCEPTION("Stack inconsistency (addr=0x%x, SP=LS:0x%05x, old_pos=LS:0x%05x)", addr, context.GPR[1]._u32[3], old_pos);
|
||||
throw EXCEPTION("Stack inconsistency (addr=0x%x, SP=LS:0x%05x, old_pos=LS:0x%05x)", addr, context.gpr[1]._u32[3], old_pos);
|
||||
}
|
||||
|
||||
context.GPR[1]._u32[3] = old_pos;
|
||||
context.gpr[1]._u32[3] = old_pos;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -600,24 +600,24 @@ s32 spursWakeUpShutdownCompletionWaiter(PPUThread& ppu, vm::ptr<CellSpurs> spurs
|
||||
return CELL_SPURS_POLICY_MODULE_ERROR_STAT;
|
||||
}
|
||||
|
||||
auto& wklF = wid < CELL_SPURS_MAX_WORKLOAD ? spurs->wklF1[wid] : spurs->wklF2[wid & 0x0F];
|
||||
auto& wklEvent = wid < CELL_SPURS_MAX_WORKLOAD ? spurs->wklEvent1[wid] : spurs->wklEvent2[wid & 0x0F];
|
||||
const auto wklF = wid < CELL_SPURS_MAX_WORKLOAD ? &spurs->wklF1[wid] : &spurs->wklF2[wid & 0x0F];
|
||||
const auto wklEvent = wid < CELL_SPURS_MAX_WORKLOAD ? &spurs->wklEvent1[wid] : &spurs->wklEvent2[wid & 0x0F];
|
||||
|
||||
if (wklF.hook)
|
||||
if (wklF->hook)
|
||||
{
|
||||
wklF.hook(ppu, spurs, wid, wklF.hookArg);
|
||||
wklF->hook(ppu, spurs, wid, wklF->hookArg);
|
||||
|
||||
assert(wklEvent.load() & 0x01);
|
||||
assert(wklEvent.load() & 0x02);
|
||||
assert((wklEvent.load() & 0x20) == 0);
|
||||
wklEvent |= 0x20;
|
||||
assert(wklEvent->load() & 0x01);
|
||||
assert(wklEvent->load() & 0x02);
|
||||
assert((wklEvent->load() & 0x20) == 0);
|
||||
*wklEvent |= 0x20;
|
||||
}
|
||||
|
||||
s32 rc = CELL_OK;
|
||||
if (!wklF.hook || wklEvent.load() & 0x10)
|
||||
if (!wklF->hook || wklEvent->load() & 0x10)
|
||||
{
|
||||
assert(wklF.x28 == 2);
|
||||
rc = sys_semaphore_post((u32)wklF.sem, 1);
|
||||
assert(wklF->x28 == 2);
|
||||
rc = sys_semaphore_post((u32)wklF->sem, 1);
|
||||
}
|
||||
|
||||
return rc;
|
||||
@ -1724,8 +1724,8 @@ s32 cellSpursSetPriorities(vm::ptr<CellSpurs> spurs, u32 wid, vm::cptr<u8> prior
|
||||
prio <<= 8;
|
||||
}
|
||||
|
||||
auto& wklInfo = wid < CELL_SPURS_MAX_WORKLOAD ? spurs->wklInfo1[wid] : spurs->wklInfo2[wid];
|
||||
*((be_t<u64>*)wklInfo.priority) = prio;
|
||||
const auto wklInfo = wid < CELL_SPURS_MAX_WORKLOAD ? &spurs->wklInfo1[wid] : &spurs->wklInfo2[wid];
|
||||
*((be_t<u64>*)wklInfo->priority) = prio;
|
||||
|
||||
spurs->sysSrvMsgUpdateWorkload.store(0xFF);
|
||||
spurs->sysSrvMessage.store(0xFF);
|
||||
@ -2296,8 +2296,8 @@ s32 spursAddWorkload(
|
||||
spurs->wklFlagReceiver.compare_and_swap(wnum, 0xff);
|
||||
|
||||
u32 res_wkl;
|
||||
CellSpurs::WorkloadInfo& wkl = wnum <= 15 ? spurs->wklInfo1[wnum] : spurs->wklInfo2[wnum & 0xf];
|
||||
spurs->wklMskB.atomic_op([spurs, &wkl, wnum, &res_wkl](be_t<u32>& v)
|
||||
const auto wkl = wnum <= 15 ? &spurs->wklInfo1[wnum] : &spurs->wklInfo2[wnum & 0xf];
|
||||
spurs->wklMskB.atomic_op([spurs, wkl, wnum, &res_wkl](be_t<u32>& v)
|
||||
{
|
||||
const u32 mask = v & ~(0x80000000u >> wnum);
|
||||
res_wkl = 0;
|
||||
@ -2306,22 +2306,22 @@ s32 spursAddWorkload(
|
||||
{
|
||||
if (mask & m)
|
||||
{
|
||||
CellSpurs::WorkloadInfo& current = i <= 15 ? spurs->wklInfo1[i] : spurs->wklInfo2[i & 0xf];
|
||||
if (current.addr == wkl.addr)
|
||||
const auto current = i <= 15 ? &spurs->wklInfo1[i] : &spurs->wklInfo2[i & 0xf];
|
||||
if (current->addr == wkl->addr)
|
||||
{
|
||||
// if a workload with identical policy module found
|
||||
res_wkl = current.uniqueId.load();
|
||||
res_wkl = current->uniqueId.load();
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
k |= 0x80000000 >> current.uniqueId.load();
|
||||
k |= 0x80000000 >> current->uniqueId.load();
|
||||
res_wkl = cntlz32(~k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wkl.uniqueId.exchange((u8)res_wkl);
|
||||
wkl->uniqueId.exchange((u8)res_wkl);
|
||||
v = mask | (0x80000000u >> wnum);
|
||||
});
|
||||
assert(res_wkl <= 31);
|
||||
|
@ -90,14 +90,14 @@ void cellSpursModulePutTrace(CellSpursTracePacket * packet, u32 dmaTagId) {
|
||||
u32 cellSpursModulePollStatus(SPUThread & spu, u32 * status) {
|
||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
|
||||
spu.GPR[3]._u32[3] = 1;
|
||||
spu.gpr[3]._u32[3] = 1;
|
||||
if (ctxt->spurs->flags1 & SF1_32_WORKLOADS) {
|
||||
spursKernel2SelectWorkload(spu);
|
||||
} else {
|
||||
spursKernel1SelectWorkload(spu);
|
||||
}
|
||||
|
||||
auto result = spu.GPR[3]._u64[1];
|
||||
auto result = spu.gpr[3]._u64[1];
|
||||
if (status) {
|
||||
*status = (u32)result;
|
||||
}
|
||||
@ -109,7 +109,7 @@ u32 cellSpursModulePollStatus(SPUThread & spu, u32 * status) {
|
||||
/// Exit current workload
|
||||
void cellSpursModuleExit(SPUThread & spu) {
|
||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
|
||||
spu.PC = ctxt->exitToKernelAddr - 4;
|
||||
spu.pc = ctxt->exitToKernelAddr - 4;
|
||||
throw SpursModuleExit();
|
||||
}
|
||||
|
||||
@ -164,7 +164,7 @@ bool spursKernel1SelectWorkload(SPUThread & spu) {
|
||||
// The first and only argument to this function is a boolean that is set to false if the function
|
||||
// is called by the SPURS kernel and set to true if called by cellSpursModulePollStatus.
|
||||
// If the first argument is true then the shared data is not updated with the result.
|
||||
const auto isPoll = spu.GPR[3]._u32[3];
|
||||
const auto isPoll = spu.gpr[3]._u32[3];
|
||||
|
||||
u32 wklSelectedId;
|
||||
u32 pollStatus;
|
||||
@ -310,7 +310,7 @@ bool spursKernel1SelectWorkload(SPUThread & spu) {
|
||||
|
||||
u64 result = (u64)wklSelectedId << 32;
|
||||
result |= pollStatus;
|
||||
spu.GPR[3]._u64[1] = result;
|
||||
spu.gpr[3]._u64[1] = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -321,7 +321,7 @@ bool spursKernel2SelectWorkload(SPUThread & spu) {
|
||||
// The first and only argument to this function is a boolean that is set to false if the function
|
||||
// is called by the SPURS kernel and set to true if called by cellSpursModulePollStatus.
|
||||
// If the first argument is true then the shared data is not updated with the result.
|
||||
const auto isPoll = spu.GPR[3]._u32[3];
|
||||
const auto isPoll = spu.gpr[3]._u32[3];
|
||||
|
||||
u32 wklSelectedId;
|
||||
u32 pollStatus;
|
||||
@ -457,7 +457,7 @@ bool spursKernel2SelectWorkload(SPUThread & spu) {
|
||||
|
||||
u64 result = (u64)wklSelectedId << 32;
|
||||
result |= pollStatus;
|
||||
spu.GPR[3]._u64[1] = result;
|
||||
spu.gpr[3]._u64[1] = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -501,12 +501,12 @@ void spursKernelDispatchWorkload(SPUThread & spu, u64 widAndPollStatus) {
|
||||
}
|
||||
|
||||
// Run workload
|
||||
spu.GPR[0]._u32[3] = ctxt->exitToKernelAddr;
|
||||
spu.GPR[1]._u32[3] = 0x3FFB0;
|
||||
spu.GPR[3]._u32[3] = 0x100;
|
||||
spu.GPR[4]._u64[1] = wklInfo->arg;
|
||||
spu.GPR[5]._u32[3] = pollStatus;
|
||||
spu.PC = 0xA00 - 4;
|
||||
spu.gpr[0]._u32[3] = ctxt->exitToKernelAddr;
|
||||
spu.gpr[1]._u32[3] = 0x3FFB0;
|
||||
spu.gpr[3]._u32[3] = 0x100;
|
||||
spu.gpr[4]._u64[1] = wklInfo->arg;
|
||||
spu.gpr[5]._u32[3] = pollStatus;
|
||||
spu.pc = 0xA00 - 4;
|
||||
}
|
||||
|
||||
/// SPURS kernel workload exit
|
||||
@ -515,14 +515,14 @@ bool spursKernelWorkloadExit(SPUThread & spu) {
|
||||
auto isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false;
|
||||
|
||||
// Select next workload to run
|
||||
spu.GPR[3].clear();
|
||||
spu.gpr[3].clear();
|
||||
if (isKernel2) {
|
||||
spursKernel2SelectWorkload(spu);
|
||||
} else {
|
||||
spursKernel1SelectWorkload(spu);
|
||||
}
|
||||
|
||||
spursKernelDispatchWorkload(spu, spu.GPR[3]._u64[1]);
|
||||
spursKernelDispatchWorkload(spu, spu.gpr[3]._u64[1]);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -537,8 +537,8 @@ bool spursKernelEntry(SPUThread & spu) {
|
||||
memset(ctxt, 0, sizeof(SpursKernelContext));
|
||||
|
||||
// Save arguments
|
||||
ctxt->spuNum = spu.GPR[3]._u32[3];
|
||||
ctxt->spurs.set(spu.GPR[4]._u64[1]);
|
||||
ctxt->spuNum = spu.gpr[3]._u32[3];
|
||||
ctxt->spurs.set(spu.gpr[4]._u64[1]);
|
||||
|
||||
auto isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false;
|
||||
|
||||
@ -579,9 +579,9 @@ bool spursKernelEntry(SPUThread & spu) {
|
||||
|
||||
/// Entry point of the system service
|
||||
bool spursSysServiceEntry(SPUThread & spu) {
|
||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + spu.GPR[3]._u32[3]);
|
||||
auto arg = spu.GPR[4]._u64[1];
|
||||
auto pollStatus = spu.GPR[5]._u32[3];
|
||||
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + spu.gpr[3]._u32[3]);
|
||||
auto arg = spu.gpr[4]._u64[1];
|
||||
auto pollStatus = spu.gpr[5]._u32[3];
|
||||
|
||||
try {
|
||||
if (ctxt->wklCurrentId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) {
|
||||
@ -1080,16 +1080,16 @@ enum SpursTasksetRequest {
|
||||
/// Taskset PM entry point
|
||||
bool spursTasksetEntry(SPUThread & spu) {
|
||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
auto kernelCtxt = vm::get_ptr<SpursKernelContext>(spu.offset + spu.GPR[3]._u32[3]);
|
||||
auto kernelCtxt = vm::get_ptr<SpursKernelContext>(spu.offset + spu.gpr[3]._u32[3]);
|
||||
|
||||
auto arg = spu.GPR[4]._u64[1];
|
||||
auto pollStatus = spu.GPR[5]._u32[3];
|
||||
auto arg = spu.gpr[4]._u64[1];
|
||||
auto pollStatus = spu.gpr[5]._u32[3];
|
||||
|
||||
// Initialise memory and save args
|
||||
memset(ctxt, 0, sizeof(*ctxt));
|
||||
ctxt->taskset.set(arg);
|
||||
memcpy(ctxt->moduleId, "SPURSTASK MODULE", sizeof(ctxt->moduleId));
|
||||
ctxt->kernelMgmtAddr = spu.GPR[3]._u32[3];
|
||||
ctxt->kernelMgmtAddr = spu.gpr[3]._u32[3];
|
||||
ctxt->syscallAddr = CELL_SPURS_TASKSET_PM_SYSCALL_ADDR;
|
||||
ctxt->spuNum = kernelCtxt->spuNum;
|
||||
ctxt->dmaTagId = kernelCtxt->dmaTagId;
|
||||
@ -1120,14 +1120,14 @@ bool spursTasksetSyscallEntry(SPUThread & spu) {
|
||||
|
||||
try {
|
||||
// Save task context
|
||||
ctxt->savedContextLr = spu.GPR[0];
|
||||
ctxt->savedContextSp = spu.GPR[1];
|
||||
ctxt->savedContextLr = spu.gpr[0];
|
||||
ctxt->savedContextSp = spu.gpr[1];
|
||||
for (auto i = 0; i < 48; i++) {
|
||||
ctxt->savedContextR80ToR127[i] = spu.GPR[80 + i];
|
||||
ctxt->savedContextR80ToR127[i] = spu.gpr[80 + i];
|
||||
}
|
||||
|
||||
// Handle the syscall
|
||||
spu.GPR[3]._u32[3] = spursTasksetProcessSyscall(spu, spu.GPR[3]._u32[3], spu.GPR[4]._u32[3]);
|
||||
spu.gpr[3]._u32[3] = spursTasksetProcessSyscall(spu, spu.gpr[3]._u32[3], spu.gpr[4]._u32[3]);
|
||||
|
||||
// Resume the previously executing task if the syscall did not cause a context switch
|
||||
throw EXCEPTION("Broken (TODO)");
|
||||
@ -1147,13 +1147,13 @@ void spursTasksetResumeTask(SPUThread & spu) {
|
||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
|
||||
// Restore task context
|
||||
spu.GPR[0] = ctxt->savedContextLr;
|
||||
spu.GPR[1] = ctxt->savedContextSp;
|
||||
spu.gpr[0] = ctxt->savedContextLr;
|
||||
spu.gpr[1] = ctxt->savedContextSp;
|
||||
for (auto i = 0; i < 48; i++) {
|
||||
spu.GPR[80 + i] = ctxt->savedContextR80ToR127[i];
|
||||
spu.gpr[80 + i] = ctxt->savedContextR80ToR127[i];
|
||||
}
|
||||
|
||||
spu.PC = spu.GPR[0]._u32[3] - 4;
|
||||
spu.pc = spu.gpr[0]._u32[3] - 4;
|
||||
}
|
||||
|
||||
/// Start a task
|
||||
@ -1161,15 +1161,15 @@ void spursTasksetStartTask(SPUThread & spu, CellSpursTaskArgument & taskArgs) {
|
||||
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
|
||||
auto taskset = vm::get_ptr<CellSpursTaskset>(spu.offset + 0x2700);
|
||||
|
||||
spu.GPR[2].clear();
|
||||
spu.GPR[3] = v128::from64r(taskArgs._u64[0], taskArgs._u64[1]);
|
||||
spu.GPR[4]._u64[1] = taskset->args;
|
||||
spu.GPR[4]._u64[0] = taskset->spurs.addr();
|
||||
spu.gpr[2].clear();
|
||||
spu.gpr[3] = v128::from64r(taskArgs._u64[0], taskArgs._u64[1]);
|
||||
spu.gpr[4]._u64[1] = taskset->args;
|
||||
spu.gpr[4]._u64[0] = taskset->spurs.addr();
|
||||
for (auto i = 5; i < 128; i++) {
|
||||
spu.GPR[i].clear();
|
||||
spu.gpr[i].clear();
|
||||
}
|
||||
|
||||
spu.PC = ctxt->savedContextLr.value()._u32[3] - 4;
|
||||
spu.pc = ctxt->savedContextLr.value()._u32[3] - 4;
|
||||
}
|
||||
|
||||
/// Process a request and update the state of the taskset
|
||||
@ -1382,10 +1382,10 @@ void spursTasksetOnTaskExit(SPUThread & spu, u64 addr, u32 taskId, s32 exitCode,
|
||||
|
||||
memcpy(vm::get_ptr(spu.offset + 0x10000), vm::get_ptr(addr & -0x80), (addr & 0x7F) << 11);
|
||||
|
||||
spu.GPR[3]._u64[1] = ctxt->taskset.addr();
|
||||
spu.GPR[4]._u32[3] = taskId;
|
||||
spu.GPR[5]._u32[3] = exitCode;
|
||||
spu.GPR[6]._u64[1] = args;
|
||||
spu.gpr[3]._u64[1] = ctxt->taskset.addr();
|
||||
spu.gpr[4]._u32[3] = taskId;
|
||||
spu.gpr[5]._u32[3] = exitCode;
|
||||
spu.gpr[6]._u64[1] = args;
|
||||
spu.fast_call(0x10000);
|
||||
}
|
||||
|
||||
@ -1422,7 +1422,7 @@ s32 spursTasketSaveTaskContext(SPUThread & spu) {
|
||||
|
||||
// Get the processor context
|
||||
v128 r;
|
||||
spu.FPSCR.Read(r);
|
||||
spu.fpscr.Read(r);
|
||||
ctxt->savedContextFpscr = r;
|
||||
ctxt->savedSpuWriteEventMask = spu.get_ch_value(SPU_RdEventMask);
|
||||
ctxt->savedWriteTagGroupQueryMask = spu.get_ch_value(MFC_RdTagMask);
|
||||
@ -1539,7 +1539,7 @@ void spursTasksetDispatch(SPUThread & spu) {
|
||||
//spursDmaWaitForCompletion(spu, 1 << ctxt->dmaTagId);
|
||||
|
||||
// Restore saved registers
|
||||
spu.FPSCR.Write(ctxt->savedContextFpscr.value());
|
||||
spu.fpscr.Write(ctxt->savedContextFpscr.value());
|
||||
spu.set_ch_value(MFC_WrTagMask, ctxt->savedWriteTagGroupQueryMask);
|
||||
spu.set_ch_value(SPU_WrEventMask, ctxt->savedSpuWriteEventMask);
|
||||
|
||||
@ -1555,7 +1555,7 @@ void spursTasksetDispatch(SPUThread & spu) {
|
||||
return;
|
||||
}
|
||||
|
||||
spu.GPR[3].clear();
|
||||
spu.gpr[3].clear();
|
||||
spursTasksetResumeTask(spu);
|
||||
}
|
||||
}
|
||||
|
@ -209,11 +209,9 @@ s32 sys_spu_thread_get_exit_status(u32 id, vm::ptr<u32> status)
|
||||
|
||||
// TODO: check CELL_ESTAT condition
|
||||
|
||||
bool notify;
|
||||
*status = thread->ch_out_mbox.pop();
|
||||
|
||||
std::tie(*status, notify) = thread->ch_out_mbox.pop();
|
||||
|
||||
if (notify)
|
||||
if (thread->ch_out_mbox.notification_required)
|
||||
{
|
||||
throw EXCEPTION("Unexpected");
|
||||
}
|
||||
@ -316,12 +314,12 @@ s32 sys_spu_thread_group_start(u32 id)
|
||||
// TODO: use segment info
|
||||
std::memcpy(vm::get_ptr<void>(t->offset), vm::get_ptr<void>(image->addr), 256 * 1024);
|
||||
|
||||
t->PC = image->entry_point;
|
||||
t->pc = image->entry_point;
|
||||
t->run();
|
||||
t->GPR[3] = v128::from64(0, args.arg1);
|
||||
t->GPR[4] = v128::from64(0, args.arg2);
|
||||
t->GPR[5] = v128::from64(0, args.arg3);
|
||||
t->GPR[6] = v128::from64(0, args.arg4);
|
||||
t->gpr[3] = v128::from64(0, args.arg1);
|
||||
t->gpr[4] = v128::from64(0, args.arg2);
|
||||
t->gpr[5] = v128::from64(0, args.arg3);
|
||||
t->gpr[6] = v128::from64(0, args.arg4);
|
||||
|
||||
t->status.exchange(SPU_STATUS_RUNNING);
|
||||
}
|
||||
@ -708,7 +706,7 @@ s32 sys_spu_thread_write_spu_mb(u32 id, u32 value)
|
||||
|
||||
if (thread->ch_in_mbox.push(value))
|
||||
{
|
||||
// notify if necessary
|
||||
// lock for reliable notification
|
||||
std::lock_guard<std::mutex> lock(thread->mutex);
|
||||
|
||||
thread->cv.notify_one();
|
||||
@ -1323,13 +1321,11 @@ s32 sys_raw_spu_read_puint_mb(u32 id, vm::ptr<u32> value)
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
bool notify;
|
||||
*value = thread->ch_out_intr_mbox.pop();
|
||||
|
||||
std::tie(*value, notify) = thread->ch_out_intr_mbox.pop();
|
||||
|
||||
if (notify)
|
||||
if (thread->ch_out_intr_mbox.notification_required)
|
||||
{
|
||||
// notify if necessary
|
||||
// lock for reliable notification
|
||||
std::lock_guard<std::mutex> lock(thread->mutex);
|
||||
|
||||
thread->cv.notify_one();
|
||||
|
@ -142,8 +142,7 @@ public:
|
||||
|
||||
void ResetInfo()
|
||||
{
|
||||
m_info.~EmuInfo();
|
||||
new (&m_info) EmuInfo();
|
||||
m_info = {};
|
||||
}
|
||||
|
||||
void SetTLSData(u32 addr, u32 filesz, u32 memsz)
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "Emu/CPU/CPUThreadManager.h"
|
||||
#include "Emu/Cell/PPUDecoder.h"
|
||||
#include "Emu/Cell/PPUDisAsm.h"
|
||||
#include "Emu/Cell/SPUDecoder.h"
|
||||
#include "Emu/Cell/SPUDisAsm.h"
|
||||
#include "Emu/ARMv7/ARMv7DisAsm.h"
|
||||
#include "Emu/ARMv7/ARMv7Decoder.h"
|
||||
@ -27,7 +26,6 @@ InterpreterDisAsmFrame::InterpreterDisAsmFrame(wxWindow* parent)
|
||||
, PC(0)
|
||||
, CPU(nullptr)
|
||||
, m_item_count(30)
|
||||
, decoder(nullptr)
|
||||
, disasm(nullptr)
|
||||
{
|
||||
wxBoxSizer* s_p_main = new wxBoxSizer(wxVERTICAL);
|
||||
@ -121,11 +119,27 @@ void InterpreterDisAsmFrame::OnSelectUnit(wxCommandEvent& event)
|
||||
{
|
||||
CPU = (CPUThread*)event.GetClientData();
|
||||
|
||||
delete decoder;
|
||||
//delete disasm;
|
||||
decoder = nullptr;
|
||||
decoder.reset();
|
||||
disasm = nullptr;
|
||||
|
||||
class SPUDecoder : public CPUDecoder
|
||||
{
|
||||
std::unique_ptr<SPUDisAsm> disasm;
|
||||
|
||||
public:
|
||||
SPUDecoder(SPUDisAsm* disasm)
|
||||
: disasm(disasm)
|
||||
{
|
||||
}
|
||||
|
||||
virtual u32 DecodeMemory(const u32 address) override
|
||||
{
|
||||
disasm->do_disasm(vm::ps3::read32(address));
|
||||
|
||||
return 4;
|
||||
}
|
||||
};
|
||||
|
||||
if(CPU)
|
||||
{
|
||||
switch(CPU->get_type())
|
||||
@ -133,7 +147,7 @@ void InterpreterDisAsmFrame::OnSelectUnit(wxCommandEvent& event)
|
||||
case CPU_THREAD_PPU:
|
||||
{
|
||||
PPUDisAsm* dis_asm = new PPUDisAsm(CPUDisAsm_InterpreterMode);
|
||||
decoder = new PPUDecoder(dis_asm);
|
||||
decoder = std::make_unique<PPUDecoder>(dis_asm);
|
||||
disasm = dis_asm;
|
||||
}
|
||||
break;
|
||||
@ -141,9 +155,9 @@ void InterpreterDisAsmFrame::OnSelectUnit(wxCommandEvent& event)
|
||||
case CPU_THREAD_SPU:
|
||||
case CPU_THREAD_RAW_SPU:
|
||||
{
|
||||
SPUDisAsm& dis_asm = *new SPUDisAsm(CPUDisAsm_InterpreterMode);
|
||||
decoder = new SPUDecoder(dis_asm);
|
||||
disasm = &dis_asm;
|
||||
SPUDisAsm* dis_asm = new SPUDisAsm(CPUDisAsm_InterpreterMode);
|
||||
decoder = std::make_unique<SPUDecoder>(dis_asm);
|
||||
disasm = dis_asm;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -511,12 +525,12 @@ void InterpreterDisAsmFrame::InstrKey(wxListEvent& event)
|
||||
{
|
||||
case 'E':
|
||||
// TODO:: Syphurith: It is said the InstructionEditorDialog would be immediately destroyed.
|
||||
InstructionEditorDialog(this, pc, CPU, decoder, disasm);
|
||||
InstructionEditorDialog(this, pc, CPU, decoder.get(), disasm);
|
||||
DoUpdate();
|
||||
return;
|
||||
case 'R':
|
||||
// TODO:: Syphurith: Eh Similiar for this one.
|
||||
RegisterEditorDialog(this, pc, CPU, decoder, disasm);
|
||||
RegisterEditorDialog(this, pc, CPU, decoder.get(), disasm);
|
||||
DoUpdate();
|
||||
return;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ class InterpreterDisAsmFrame : public wxPanel
|
||||
{
|
||||
wxListView* m_list;
|
||||
CPUDisAsm* disasm;
|
||||
CPUDecoder* decoder;
|
||||
std::unique_ptr<CPUDecoder> decoder;
|
||||
u64 PC;
|
||||
std::vector<u32> remove_markedPC;
|
||||
wxTextCtrl* m_regs;
|
||||
|
@ -148,8 +148,8 @@ SettingsDialog::SettingsDialog(wxWindow *parent)
|
||||
#endif
|
||||
|
||||
wxArrayString spu_decoder_modes;
|
||||
spu_decoder_modes.Add("Interpreter");
|
||||
spu_decoder_modes.Add("Interpreter 2");
|
||||
spu_decoder_modes.Add("Interpreter (precise)");
|
||||
spu_decoder_modes.Add("Interpreter (fast)");
|
||||
spu_decoder_modes.Add("Recompiler (ASMJIT)");
|
||||
rbox_spu_decoder = new wxRadioBox(p_core, wxID_ANY, "SPU Decoder", wxDefaultPosition, wxSize(215, -1), spu_decoder_modes, 1);
|
||||
|
||||
|
@ -330,6 +330,14 @@ namespace loader
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Ini.LoadLibLv2.GetValue())
|
||||
{
|
||||
if (module->name != "liblv2.sprx")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
elf64 sprx_handler;
|
||||
|
||||
vfsFile fsprx(lle_dir.GetPath() + "/" + module->name);
|
||||
@ -340,19 +348,19 @@ namespace loader
|
||||
|
||||
if (sprx_handler.is_sprx())
|
||||
{
|
||||
IniEntry<bool> load_lib;
|
||||
load_lib.Init(sprx_handler.sprx_get_module_name(), "LLE");
|
||||
if (!Ini.LoadLibLv2.GetValue())
|
||||
{
|
||||
IniEntry<bool> load_lib;
|
||||
load_lib.Init(sprx_handler.sprx_get_module_name(), "LLE");
|
||||
|
||||
if (!load_lib.LoadValue(false))
|
||||
{
|
||||
LOG_WARNING(LOADER, "Skipped LLE library '%s'", sprx_handler.sprx_get_module_name().c_str());
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_WARNING(LOADER, "Loading LLE library '%s'", sprx_handler.sprx_get_module_name().c_str());
|
||||
if (!load_lib.LoadValue(false))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_WARNING(LOADER, "Loading LLE library '%s'", sprx_handler.sprx_get_module_name().c_str());
|
||||
|
||||
sprx_info info;
|
||||
sprx_handler.load_sprx(info);
|
||||
|
||||
|
@ -53,6 +53,8 @@
|
||||
<ClCompile Include="..\Utilities\VirtualMemory.cpp" />
|
||||
<ClCompile Include="Emu\Cell\PPUInterpreter.cpp" />
|
||||
<ClCompile Include="Emu\Cell\PPULLVMRecompilerCore.cpp" />
|
||||
<ClCompile Include="Emu\Cell\SPUAnalyser.cpp" />
|
||||
<ClCompile Include="Emu\Cell\SPUASMJITRecompiler.cpp" />
|
||||
<ClCompile Include="Emu\Cell\SPUInterpreter.cpp" />
|
||||
<ClCompile Include="Emu\IdManager.cpp" />
|
||||
<ClCompile Include="Emu\RSX\CgBinaryFragmentProgram.cpp" />
|
||||
@ -183,7 +185,7 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\Cell\PPUThread.cpp" />
|
||||
<ClCompile Include="Emu\Cell\RawSPUThread.cpp" />
|
||||
<ClCompile Include="Emu\Cell\SPURecompilerCore.cpp" />
|
||||
<ClCompile Include="Emu\Cell\SPURecompiler.cpp" />
|
||||
<ClCompile Include="Emu\Cell\SPUThread.cpp" />
|
||||
<ClCompile Include="Emu\CPU\CPUThread.cpp" />
|
||||
<ClCompile Include="Emu\CPU\CPUThreadManager.cpp" />
|
||||
@ -485,12 +487,11 @@
|
||||
<ClInclude Include="Emu\Cell\PPUOpcodes.h" />
|
||||
<ClInclude Include="Emu\Cell\PPUThread.h" />
|
||||
<ClInclude Include="Emu\Cell\RawSPUThread.h" />
|
||||
<ClInclude Include="Emu\Cell\SPUAnalyser.h" />
|
||||
<ClInclude Include="Emu\Cell\SPUASMJITRecompiler.h" />
|
||||
<ClInclude Include="Emu\Cell\SPUContext.h" />
|
||||
<ClInclude Include="Emu\Cell\SPUDecoder.h" />
|
||||
<ClInclude Include="Emu\Cell\SPUDisAsm.h" />
|
||||
<ClInclude Include="Emu\Cell\SPUInstrTable.h" />
|
||||
<ClInclude Include="Emu\Cell\SPUInterpreter.h" />
|
||||
<ClInclude Include="Emu\Cell\SPUInterpreter2.h" />
|
||||
<ClInclude Include="Emu\Cell\SPUOpcodes.h" />
|
||||
<ClInclude Include="Emu\Cell\SPURecompiler.h" />
|
||||
<ClInclude Include="Emu\Cell\SPUThread.h" />
|
||||
|
@ -350,9 +350,6 @@
|
||||
<ClCompile Include="Emu\Cell\RawSPUThread.cpp">
|
||||
<Filter>Emu\CPU\Cell</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\Cell\SPURecompilerCore.cpp">
|
||||
<Filter>Emu\CPU\Cell</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\Cell\SPUThread.cpp">
|
||||
<Filter>Emu\CPU\Cell</Filter>
|
||||
</ClCompile>
|
||||
@ -986,6 +983,15 @@
|
||||
<ClCompile Include="..\Utilities\VirtualMemory.cpp">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\Cell\SPURecompiler.cpp">
|
||||
<Filter>Emu\CPU\Cell</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\Cell\SPUAnalyser.cpp">
|
||||
<Filter>Emu\CPU\Cell</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\Cell\SPUASMJITRecompiler.cpp">
|
||||
<Filter>Emu\CPU\Cell</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Crypto\aes.h">
|
||||
@ -1252,15 +1258,9 @@
|
||||
<ClInclude Include="Emu\Cell\RawSPUThread.h">
|
||||
<Filter>Emu\CPU\Cell</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\Cell\SPUDecoder.h">
|
||||
<Filter>Emu\CPU\Cell</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\Cell\SPUDisAsm.h">
|
||||
<Filter>Emu\CPU\Cell</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\Cell\SPUInstrTable.h">
|
||||
<Filter>Emu\CPU\Cell</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\Cell\SPUInterpreter.h">
|
||||
<Filter>Emu\CPU\Cell</Filter>
|
||||
</ClInclude>
|
||||
@ -1627,9 +1627,6 @@
|
||||
<ClInclude Include="Emu\Cell\PPUInterpreter2.h">
|
||||
<Filter>Emu\CPU\Cell</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\Cell\SPUInterpreter2.h">
|
||||
<Filter>Emu\CPU\Cell</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Utilities\File.h">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClInclude>
|
||||
@ -1873,5 +1870,11 @@
|
||||
<ClInclude Include="..\Utilities\VirtualMemory.h">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\Cell\SPUASMJITRecompiler.h">
|
||||
<Filter>Emu\CPU\Cell</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\Cell\SPUAnalyser.h">
|
||||
<Filter>Emu\CPU\Cell</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Reference in New Issue
Block a user