1
0
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:
Nekotekina 2015-08-26 05:54:06 +03:00
parent 58181c5c17
commit 817fec9684
30 changed files with 6117 additions and 8261 deletions

2
asmjit

@ -1 +1 @@
Subproject commit bd0d261e8b72d1915e64da8a6b5bebae5637fa20 Subproject commit b0dad1af25fb141bf2b20cf29392194886448832

View File

@ -6,10 +6,11 @@
#include "Emu/Cell/RawSPUThread.h" #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] = {}; thread_local spu_mfc_arg_t raw_spu_mfc[8] = {};
RawSPUThread::RawSPUThread(const std::string& name, u32 index) 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)) if (!vm::falloc(offset, 0x40000))
{ {
@ -45,13 +46,11 @@ bool RawSPUThread::read_reg(const u32 addr, u32& value)
case SPU_Out_MBox_offs: case SPU_Out_MBox_offs:
{ {
bool notify; value = ch_out_mbox.pop();
std::tie(value, notify) = ch_out_mbox.pop(); if (ch_out_mbox.notification_required)
if (notify)
{ {
// notify if necessary // lock for reliable notification
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
cv.notify_one(); cv.notify_one();
@ -170,7 +169,6 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value)
case Prxy_QueryMask_offs: case Prxy_QueryMask_offs:
{ {
//proxy_tag_mask = value;
return true; return true;
} }
@ -178,7 +176,7 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value)
{ {
if (ch_in_mbox.push(value)) if (ch_in_mbox.push(value))
{ {
// notify if necessary // lock for reliable notification
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
cv.notify_one(); cv.notify_one();
@ -238,14 +236,14 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value)
void RawSPUThread::task() void RawSPUThread::task()
{ {
// get next PC and SPU Interrupt status // 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(); SPUThread::task();
// save next PC and current SPU Interrupt status // 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 });
} }

File diff suppressed because it is too large Load Diff

View 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;
};

View 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;
}

View 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);
};

View File

@ -1,6 +1,5 @@
#pragma once #pragma once
struct SPUContext struct spu_context_t
{ {
v128 gpr[128];
}; };

View File

@ -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

View File

@ -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

View File

@ -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; }
};

View File

@ -1,451 +1,322 @@
#pragma once #pragma once
namespace SPU_opcodes union spu_opcode_t
{ {
enum SPU_0_10_Opcodes u32 opcode;
struct
{ {
STOP = 0x0, u32 rt : 7; // 25..31, it's actually RC in 4-op instructions
LNOP = 0x1, u32 ra : 7; // 18..24
SYNC = 0x2, u32 rb : 7; // 11..17
DSYNC = 0x3, u32 rc : 7; // 4..10, it's actually RT in 4-op instructions
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,
}; };
enum SPU_0_9_Opcodes struct
{ {
CFLTS = 0x1d8, u32 : 14; // 18..31
CFLTU = 0x1d9, u32 i7 : 7; // 11..17
CSFLT = 0x1da,
CUFLT = 0x1db,
}; };
enum SPU_0_8_Opcodes struct
{ {
BRZ = 0x40, u32 : 14; // 18..31
STQA = 0x41, u32 i8 : 8; // 10..17
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,
}; };
enum SPU_0_7_Opcodes struct
{ {
ORI = 0x4, u32 : 7; // 25..31
ORHI = 0x5, u32 i16 : 16; // 9..24
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,
}; };
enum SPU_0_6_Opcodes struct
{ {
HBRA = 0x8, u32 : 7; // 25..31
HBRR = 0x9, u32 i18 : 18; // 7..24
ILA = 0x21,
}; };
enum SPU_0_3_Opcodes struct
{ {
SELB = 0x8, s32 : 14; // 18..31
SHUFB = 0xb, s32 si7 : 7; // 11..17
MPYA = 0xc, };
FNMS = 0xd,
FMA = 0xe, struct
FMS = 0xf, {
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 #define DEFINE_SPU_OPCODES(ns) { \
{ { 10, 0x0, ns STOP }, \
public: { 10, 0x1, ns LNOP }, \
virtual ~SPUOpcodes() {} { 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 // access opcode table
virtual void STOP(u32 code) = 0; inline T operator [](u32 opcode_data) const
virtual void LNOP() = 0; {
virtual void SYNC(u32 Cbit) = 0; // the whole decoding process is shifting opcode data
virtual void DSYNC() = 0; return m_data[opcode_data >> 21];
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;
}; };
inline u32 spu_branch_target(u32 pc, s32 imm)
{
return (pc + (imm << 2)) & 0x3fffc;
}

View 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;
}

View File

@ -1,325 +1,38 @@
#pragma once #pragma once
#include "Emu/CPU/CPUDecoder.h" #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; protected:
struct X86Compiler; std::mutex m_mutex; // must be locked in compile()
struct X86GpVar;
struct X86XmmVar;
struct X86Mem;
}
class SPURecompiler; const spu_function_t* m_func; // current function
class SPUInterpreter;
class SPURecompilerCore : public CPUDecoder u32 m_pos; // current position
{
std::unique_ptr<SPURecompiler> m_enc;
std::unique_ptr<SPUInterpreter> m_int;
std::unique_ptr<asmjit::JitRuntime> m_jit;
SPUThread& CPU;
public: public:
bool first = true; virtual void compile(spu_function_t& f) = 0; // compile specified function
bool need_check = false; virtual ~SPURecompilerBase() {};
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);
}; };
class SPURecompiler : public SPUOpcodes // SPU Decoder instance (created per SPU thread)
class SPURecompilerDecoder final : public CPUDecoder
{ {
private: std::array<spu_jit_func_t, 0x10000> m_entries = {}; // currently useless
SPUThread& CPU;
SPURecompilerCore& rec;
public: public:
asmjit::X86Compiler* compiler; const std::shared_ptr<SPUDatabase> db; // associated SPU Analyser instance
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;
struct XmmLink const std::shared_ptr<SPURecompilerBase> rec; // assiciated SPU Recompiler instance
{
asmjit::X86XmmVar* data = nullptr;
s8 reg = -1;
bool taken = false;
mutable bool got = false;
mutable u32 access = 0;
const asmjit::X86XmmVar& get() const SPUThread& spu; // associated SPU Thread
{
assert(data);
if (!taken) throw EXCEPTION("Register not taken");
got = true;
return *data;
}
const asmjit::X86XmmVar& read() const SPURecompilerDecoder(SPUThread& spu);
{
assert(data);
return *data;
}
}
xmm_var[16];
SPURecompiler(SPUThread& cpu, SPURecompilerCore& rec) u32 DecodeMemory(const u32 address) override; // non-virtual override (to avoid virtual call whenever possible)
: 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);
}; };

File diff suppressed because it is too large Load Diff

View File

@ -14,15 +14,18 @@
#include "Emu/Cell/SPUDisAsm.h" #include "Emu/Cell/SPUDisAsm.h"
#include "Emu/Cell/SPUThread.h" #include "Emu/Cell/SPUThread.h"
#include "Emu/Cell/SPUDecoder.h"
#include "Emu/Cell/SPUInterpreter.h" #include "Emu/Cell/SPUInterpreter.h"
#include "Emu/Cell/SPUInterpreter2.h"
#include "Emu/Cell/SPURecompiler.h" #include "Emu/Cell/SPURecompiler.h"
#include <cfenv> #include <cfenv>
extern u64 get_timebased_time(); 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) void spu_int_ctrl_t::set(u64 ints)
{ {
// leave only enabled interrupts // leave only enabled interrupts
@ -47,40 +50,7 @@ void spu_int_ctrl_t::clear(u64 ints)
stat &= ~ints; stat &= ~ints;
} }
const g_spu_imm_table_t g_spu_imm; const 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;
SPUThread::SPUThread(CPUThreadType type, const std::string& name, std::function<std::string()> thread_name, u32 index, u32 offset) 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)) : 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) 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) , index(index)
, offset(vm::alloc(0x40000, vm::main)) , offset(vm::alloc(0x40000, vm::main))
{ {
@ -138,51 +108,55 @@ void SPUThread::task()
{ {
std::fesetround(FE_TOWARDZERO); 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 (custom_task)
{ {
if (check_status()) return; if (check_status()) return;
return custom_task(*this); return custom_task(*this);
} }
if (m_dec) while (!m_state.load() || !check_status())
{ {
while (true) // decode instruction using specified decoder
{ pc += m_dec->DecodeMemory(pc + offset);
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;
}
} }
} }
void SPUThread::init_regs() void SPUThread::init_regs()
{ {
memset(GPR, 0, sizeof(GPR)); gpr = {};
FPSCR.Reset(); fpscr.Reset();
ch_mfc_args = {}; ch_mfc_args = {};
mfc_queue.clear(); mfc_queue.clear();
@ -215,7 +189,7 @@ void SPUThread::init_regs()
int_ctrl = {}; int_ctrl = {};
GPR[1]._u32[3] = 0x3FFF0; // initial stack frame pointer gpr[1]._u32[3] = 0x3FFF0; // initial stack frame pointer
} }
void SPUThread::init_stack() void SPUThread::init_stack()
@ -230,25 +204,19 @@ void SPUThread::close_stack()
void SPUThread::do_run() void SPUThread::do_run()
{ {
m_dec = nullptr; m_dec.reset();
switch (auto mode = Ini.SPUDecoderMode.GetValue()) 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; break;
} }
case 2: case 2:
{ {
m_dec.reset(new SPURecompilerCore(*this)); m_dec.reset(new SPURecompilerDecoder(*this));
break; break;
} }
@ -267,15 +235,16 @@ void SPUThread::fast_call(u32 ls_addr)
throw EXCEPTION("Called from the wrong thread"); 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); write32(0x0, 2);
auto old_PC = PC; auto old_pc = pc;
auto old_LR = GPR[0]._u32[3]; auto old_lr = gpr[0]._u32[3];
auto old_stack = GPR[1]._u32[3]; // only saved and restored (may be wrong) auto old_stack = gpr[1]._u32[3]; // only saved and restored (may be wrong)
auto old_task = std::move(custom_task); auto old_task = std::move(custom_task);
PC = ls_addr; pc = ls_addr;
GPR[0]._u32[3] = 0x0; gpr[0]._u32[3] = 0x0;
custom_task = nullptr; custom_task = nullptr;
try try
@ -288,9 +257,9 @@ void SPUThread::fast_call(u32 ls_addr)
m_state &= ~CPU_STATE_RETURN; m_state &= ~CPU_STATE_RETURN;
PC = old_PC; pc = old_pc;
GPR[0]._u32[3] = old_LR; gpr[0]._u32[3] = old_lr;
GPR[1]._u32[3] = old_stack; gpr[1]._u32[3] = old_stack;
custom_task = std::move(old_task); custom_task = std::move(old_task);
} }
@ -1218,14 +1187,18 @@ void SPUThread::stop_and_signal(u32 code)
case 0x003: case 0x003:
{ {
auto iter = m_addr_to_hle_function_map.find(PC); const auto found = m_addr_to_hle_function_map.find(pc);
assert(iter != m_addr_to_hle_function_map.end());
auto return_to_caller = iter->second(*this); if (found == m_addr_to_hle_function_map.end())
if (return_to_caller)
{ {
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; 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); auto spu = idm::make_ptr<SPUThread>(name, 0x13370666);
spu->PC = entry; spu->pc = entry;
thread = std::move(spu); thread = std::move(spu);
} }

View File

@ -135,16 +135,15 @@ enum
SPU_RdSigNotify2_offs = 0x1C00C, 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 sync_var_t
{ {
struct bool count; // value available
{ bool wait; // notification required
u32 waiting : 1; // waiting flag (0..1)
u32 count : 1; // channel count (0..1)
};
u32 value; u32 value;
}; };
@ -154,93 +153,75 @@ public:
// returns true on success // returns true on success
bool try_push(u32 value) 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 = true;
data.count = 1;
data.value = value; 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 // push performing bitwise OR with previous value, may require notification
bool push_or(u32 value) 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; 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 // push unconditionally (overwriting previous value), may require notification
bool push(u32 value) 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; 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() 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.wait = !data.count;
data.count = false;
data.waiting = data.count == 0; data.value = 0; // ???
data.count = 0;
data.value = 0;
return result;
}); });
return std::tie(old.count, old.value);
} }
// pop unconditionally (loading last value), returns u32 value and bool value (true if needs signaling) // pop unconditionally (loading last value), may require notification
std::tuple<u32, bool> pop() 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.wait = false;
data.count = false;
data.waiting = 0;
data.count = 0;
// value is not cleared and may be read again // 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 u32 get_value() volatile
@ -358,7 +339,7 @@ struct spu_int_ctrl_t
void clear(u64 ints); void clear(u64 ints);
}; };
struct g_spu_imm_table_t struct spu_imm_table_t
{ {
v128 fsmb[65536]; // table for FSMB, FSMBI instructions v128 fsmb[65536]; // table for FSMB, FSMBI instructions
v128 fsmh[256]; // table for FSMH instruction v128 fsmh[256]; // table for FSMH instruction
@ -388,7 +369,7 @@ struct g_spu_imm_table_t
} }
const scale; const scale;
g_spu_imm_table_t() spu_imm_table_t()
{ {
for (u32 i = 0; i < sizeof(fsm) / sizeof(fsm[0]); i++) 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 enum FPSCR_EX
{ {
@ -543,9 +524,11 @@ public:
class SPUThread : public CPUThread class SPUThread : public CPUThread
{ {
friend class spu_recompiler;
public: public:
v128 GPR[128]; // General-Purpose Registers std::array<v128, 128> gpr; // General-Purpose Registers
SPU_FPSCR FPSCR; SPU_FPSCR fpscr;
std::unordered_map<u32, std::function<bool(SPUThread& SPU)>> m_addr_to_hle_function_map; 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::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 std::weak_ptr<lv2_event_queue_t> spup[64]; // SPU Ports
u32 PC = 0; u32 pc = 0; //
const u32 index; // SPU index const u32 index; // SPU index
const u32 offset; // SPU LS offset const u32 offset; // SPU LS offset
void push_snr(u32 number, u32 value) 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) channel->push_or(value);
{
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;
}
} }
else else
{ {
throw EXCEPTION("Unexpected"); channel->push(value);
} }
// notify if required if (channel->notification_required)
std::lock_guard<std::mutex> lock(mutex); {
// 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); void do_dma_transfer(u32 cmd, spu_mfc_arg_t args);
@ -683,6 +657,7 @@ public:
} }
std::function<void(SPUThread&)> custom_task; std::function<void(SPUThread&)> custom_task;
std::exception_ptr pending_exception;
protected: protected:
SPUThread(CPUThreadType type, const std::string& name, std::function<std::string()> thread_name, u32 index, u32 offset); 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 bool is_paused() const override;
virtual void dump_info() 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 u32 get_offset() const override { return offset; }
virtual void do_run() override; virtual void do_run() override;
virtual void task() override; virtual void task() override;
@ -709,7 +684,7 @@ public:
{ {
std::string ret = "Registers:\n=========\n"; 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; return ret;
} }
@ -721,7 +696,7 @@ public:
{ {
long reg_index; long reg_index;
reg_index = atol(reg.substr(first_brk + 1, reg.length()-2).c_str()); 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 ""; return "";
} }
@ -747,8 +722,8 @@ public:
{ {
return false; return false;
} }
GPR[reg_index]._u64[0] = (u64)reg_value0; gpr[reg_index]._u64[0] = (u64)reg_value0;
GPR[reg_index]._u64[1] = (u64)reg_value1; gpr[reg_index]._u64[1] = (u64)reg_value1;
return true; return true;
} }
} }

View File

@ -1083,17 +1083,17 @@ namespace vm
{ {
SPUThread& context = static_cast<SPUThread&>(cpu); SPUThread& context = static_cast<SPUThread&>(cpu);
old_pos = context.GPR[1]._u32[3]; old_pos = context.gpr[1]._u32[3];
context.GPR[1]._u32[3] -= align(size, 16); context.gpr[1]._u32[3] -= align(size, 16);
context.GPR[1]._u32[3] &= ~(align_v - 1); 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); throw EXCEPTION("Stack overflow (size=0x%x, align=0x%x, SP=LS:0x%05x)", size, align_v, old_pos);
} }
else 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); 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; return;
} }

View File

@ -600,24 +600,24 @@ s32 spursWakeUpShutdownCompletionWaiter(PPUThread& ppu, vm::ptr<CellSpurs> spurs
return CELL_SPURS_POLICY_MODULE_ERROR_STAT; return CELL_SPURS_POLICY_MODULE_ERROR_STAT;
} }
auto& wklF = wid < CELL_SPURS_MAX_WORKLOAD ? spurs->wklF1[wid] : spurs->wklF2[wid & 0x0F]; const 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 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() & 0x01);
assert(wklEvent.load() & 0x02); assert(wklEvent->load() & 0x02);
assert((wklEvent.load() & 0x20) == 0); assert((wklEvent->load() & 0x20) == 0);
wklEvent |= 0x20; *wklEvent |= 0x20;
} }
s32 rc = CELL_OK; s32 rc = CELL_OK;
if (!wklF.hook || wklEvent.load() & 0x10) if (!wklF->hook || wklEvent->load() & 0x10)
{ {
assert(wklF.x28 == 2); assert(wklF->x28 == 2);
rc = sys_semaphore_post((u32)wklF.sem, 1); rc = sys_semaphore_post((u32)wklF->sem, 1);
} }
return rc; return rc;
@ -1724,8 +1724,8 @@ s32 cellSpursSetPriorities(vm::ptr<CellSpurs> spurs, u32 wid, vm::cptr<u8> prior
prio <<= 8; prio <<= 8;
} }
auto& wklInfo = wid < CELL_SPURS_MAX_WORKLOAD ? spurs->wklInfo1[wid] : spurs->wklInfo2[wid]; const auto wklInfo = wid < CELL_SPURS_MAX_WORKLOAD ? &spurs->wklInfo1[wid] : &spurs->wklInfo2[wid];
*((be_t<u64>*)wklInfo.priority) = prio; *((be_t<u64>*)wklInfo->priority) = prio;
spurs->sysSrvMsgUpdateWorkload.store(0xFF); spurs->sysSrvMsgUpdateWorkload.store(0xFF);
spurs->sysSrvMessage.store(0xFF); spurs->sysSrvMessage.store(0xFF);
@ -2296,8 +2296,8 @@ s32 spursAddWorkload(
spurs->wklFlagReceiver.compare_and_swap(wnum, 0xff); spurs->wklFlagReceiver.compare_and_swap(wnum, 0xff);
u32 res_wkl; u32 res_wkl;
CellSpurs::WorkloadInfo& wkl = wnum <= 15 ? spurs->wklInfo1[wnum] : spurs->wklInfo2[wnum & 0xf]; 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) spurs->wklMskB.atomic_op([spurs, wkl, wnum, &res_wkl](be_t<u32>& v)
{ {
const u32 mask = v & ~(0x80000000u >> wnum); const u32 mask = v & ~(0x80000000u >> wnum);
res_wkl = 0; res_wkl = 0;
@ -2306,22 +2306,22 @@ s32 spursAddWorkload(
{ {
if (mask & m) if (mask & m)
{ {
CellSpurs::WorkloadInfo& current = i <= 15 ? spurs->wklInfo1[i] : spurs->wklInfo2[i & 0xf]; const auto current = i <= 15 ? &spurs->wklInfo1[i] : &spurs->wklInfo2[i & 0xf];
if (current.addr == wkl.addr) if (current->addr == wkl->addr)
{ {
// if a workload with identical policy module found // if a workload with identical policy module found
res_wkl = current.uniqueId.load(); res_wkl = current->uniqueId.load();
break; break;
} }
else else
{ {
k |= 0x80000000 >> current.uniqueId.load(); k |= 0x80000000 >> current->uniqueId.load();
res_wkl = cntlz32(~k); res_wkl = cntlz32(~k);
} }
} }
} }
wkl.uniqueId.exchange((u8)res_wkl); wkl->uniqueId.exchange((u8)res_wkl);
v = mask | (0x80000000u >> wnum); v = mask | (0x80000000u >> wnum);
}); });
assert(res_wkl <= 31); assert(res_wkl <= 31);

View File

@ -90,14 +90,14 @@ void cellSpursModulePutTrace(CellSpursTracePacket * packet, u32 dmaTagId) {
u32 cellSpursModulePollStatus(SPUThread & spu, u32 * status) { u32 cellSpursModulePollStatus(SPUThread & spu, u32 * status) {
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100); 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) { if (ctxt->spurs->flags1 & SF1_32_WORKLOADS) {
spursKernel2SelectWorkload(spu); spursKernel2SelectWorkload(spu);
} else { } else {
spursKernel1SelectWorkload(spu); spursKernel1SelectWorkload(spu);
} }
auto result = spu.GPR[3]._u64[1]; auto result = spu.gpr[3]._u64[1];
if (status) { if (status) {
*status = (u32)result; *status = (u32)result;
} }
@ -109,7 +109,7 @@ u32 cellSpursModulePollStatus(SPUThread & spu, u32 * status) {
/// Exit current workload /// Exit current workload
void cellSpursModuleExit(SPUThread & spu) { void cellSpursModuleExit(SPUThread & spu) {
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100); auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
spu.PC = ctxt->exitToKernelAddr - 4; spu.pc = ctxt->exitToKernelAddr - 4;
throw SpursModuleExit(); 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 // 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. // 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. // 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 wklSelectedId;
u32 pollStatus; u32 pollStatus;
@ -310,7 +310,7 @@ bool spursKernel1SelectWorkload(SPUThread & spu) {
u64 result = (u64)wklSelectedId << 32; u64 result = (u64)wklSelectedId << 32;
result |= pollStatus; result |= pollStatus;
spu.GPR[3]._u64[1] = result; spu.gpr[3]._u64[1] = result;
return true; 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 // 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. // 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. // 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 wklSelectedId;
u32 pollStatus; u32 pollStatus;
@ -457,7 +457,7 @@ bool spursKernel2SelectWorkload(SPUThread & spu) {
u64 result = (u64)wklSelectedId << 32; u64 result = (u64)wklSelectedId << 32;
result |= pollStatus; result |= pollStatus;
spu.GPR[3]._u64[1] = result; spu.gpr[3]._u64[1] = result;
return true; return true;
} }
@ -501,12 +501,12 @@ void spursKernelDispatchWorkload(SPUThread & spu, u64 widAndPollStatus) {
} }
// Run workload // Run workload
spu.GPR[0]._u32[3] = ctxt->exitToKernelAddr; spu.gpr[0]._u32[3] = ctxt->exitToKernelAddr;
spu.GPR[1]._u32[3] = 0x3FFB0; spu.gpr[1]._u32[3] = 0x3FFB0;
spu.GPR[3]._u32[3] = 0x100; spu.gpr[3]._u32[3] = 0x100;
spu.GPR[4]._u64[1] = wklInfo->arg; spu.gpr[4]._u64[1] = wklInfo->arg;
spu.GPR[5]._u32[3] = pollStatus; spu.gpr[5]._u32[3] = pollStatus;
spu.PC = 0xA00 - 4; spu.pc = 0xA00 - 4;
} }
/// SPURS kernel workload exit /// SPURS kernel workload exit
@ -515,14 +515,14 @@ bool spursKernelWorkloadExit(SPUThread & spu) {
auto isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false; auto isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false;
// Select next workload to run // Select next workload to run
spu.GPR[3].clear(); spu.gpr[3].clear();
if (isKernel2) { if (isKernel2) {
spursKernel2SelectWorkload(spu); spursKernel2SelectWorkload(spu);
} else { } else {
spursKernel1SelectWorkload(spu); spursKernel1SelectWorkload(spu);
} }
spursKernelDispatchWorkload(spu, spu.GPR[3]._u64[1]); spursKernelDispatchWorkload(spu, spu.gpr[3]._u64[1]);
return false; return false;
} }
@ -537,8 +537,8 @@ bool spursKernelEntry(SPUThread & spu) {
memset(ctxt, 0, sizeof(SpursKernelContext)); memset(ctxt, 0, sizeof(SpursKernelContext));
// Save arguments // Save arguments
ctxt->spuNum = spu.GPR[3]._u32[3]; ctxt->spuNum = spu.gpr[3]._u32[3];
ctxt->spurs.set(spu.GPR[4]._u64[1]); ctxt->spurs.set(spu.gpr[4]._u64[1]);
auto isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false; auto isKernel2 = ctxt->spurs->flags1 & SF1_32_WORKLOADS ? true : false;
@ -579,9 +579,9 @@ bool spursKernelEntry(SPUThread & spu) {
/// Entry point of the system service /// Entry point of the system service
bool spursSysServiceEntry(SPUThread & spu) { bool spursSysServiceEntry(SPUThread & spu) {
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + spu.GPR[3]._u32[3]); auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + spu.gpr[3]._u32[3]);
auto arg = spu.GPR[4]._u64[1]; auto arg = spu.gpr[4]._u64[1];
auto pollStatus = spu.GPR[5]._u32[3]; auto pollStatus = spu.gpr[5]._u32[3];
try { try {
if (ctxt->wklCurrentId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) { if (ctxt->wklCurrentId == CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) {
@ -1080,16 +1080,16 @@ enum SpursTasksetRequest {
/// Taskset PM entry point /// Taskset PM entry point
bool spursTasksetEntry(SPUThread & spu) { bool spursTasksetEntry(SPUThread & spu) {
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700); 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 arg = spu.gpr[4]._u64[1];
auto pollStatus = spu.GPR[5]._u32[3]; auto pollStatus = spu.gpr[5]._u32[3];
// Initialise memory and save args // Initialise memory and save args
memset(ctxt, 0, sizeof(*ctxt)); memset(ctxt, 0, sizeof(*ctxt));
ctxt->taskset.set(arg); ctxt->taskset.set(arg);
memcpy(ctxt->moduleId, "SPURSTASK MODULE", sizeof(ctxt->moduleId)); 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->syscallAddr = CELL_SPURS_TASKSET_PM_SYSCALL_ADDR;
ctxt->spuNum = kernelCtxt->spuNum; ctxt->spuNum = kernelCtxt->spuNum;
ctxt->dmaTagId = kernelCtxt->dmaTagId; ctxt->dmaTagId = kernelCtxt->dmaTagId;
@ -1120,14 +1120,14 @@ bool spursTasksetSyscallEntry(SPUThread & spu) {
try { try {
// Save task context // Save task context
ctxt->savedContextLr = spu.GPR[0]; ctxt->savedContextLr = spu.gpr[0];
ctxt->savedContextSp = spu.GPR[1]; ctxt->savedContextSp = spu.gpr[1];
for (auto i = 0; i < 48; i++) { for (auto i = 0; i < 48; i++) {
ctxt->savedContextR80ToR127[i] = spu.GPR[80 + i]; ctxt->savedContextR80ToR127[i] = spu.gpr[80 + i];
} }
// Handle the syscall // 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 // Resume the previously executing task if the syscall did not cause a context switch
throw EXCEPTION("Broken (TODO)"); throw EXCEPTION("Broken (TODO)");
@ -1147,13 +1147,13 @@ void spursTasksetResumeTask(SPUThread & spu) {
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700); auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
// Restore task context // Restore task context
spu.GPR[0] = ctxt->savedContextLr; spu.gpr[0] = ctxt->savedContextLr;
spu.GPR[1] = ctxt->savedContextSp; spu.gpr[1] = ctxt->savedContextSp;
for (auto i = 0; i < 48; i++) { 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 /// Start a task
@ -1161,15 +1161,15 @@ void spursTasksetStartTask(SPUThread & spu, CellSpursTaskArgument & taskArgs) {
auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700); auto ctxt = vm::get_ptr<SpursTasksetContext>(spu.offset + 0x2700);
auto taskset = vm::get_ptr<CellSpursTaskset>(spu.offset + 0x2700); auto taskset = vm::get_ptr<CellSpursTaskset>(spu.offset + 0x2700);
spu.GPR[2].clear(); spu.gpr[2].clear();
spu.GPR[3] = v128::from64r(taskArgs._u64[0], taskArgs._u64[1]); spu.gpr[3] = v128::from64r(taskArgs._u64[0], taskArgs._u64[1]);
spu.GPR[4]._u64[1] = taskset->args; spu.gpr[4]._u64[1] = taskset->args;
spu.GPR[4]._u64[0] = taskset->spurs.addr(); spu.gpr[4]._u64[0] = taskset->spurs.addr();
for (auto i = 5; i < 128; i++) { 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 /// 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); 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[3]._u64[1] = ctxt->taskset.addr();
spu.GPR[4]._u32[3] = taskId; spu.gpr[4]._u32[3] = taskId;
spu.GPR[5]._u32[3] = exitCode; spu.gpr[5]._u32[3] = exitCode;
spu.GPR[6]._u64[1] = args; spu.gpr[6]._u64[1] = args;
spu.fast_call(0x10000); spu.fast_call(0x10000);
} }
@ -1422,7 +1422,7 @@ s32 spursTasketSaveTaskContext(SPUThread & spu) {
// Get the processor context // Get the processor context
v128 r; v128 r;
spu.FPSCR.Read(r); spu.fpscr.Read(r);
ctxt->savedContextFpscr = r; ctxt->savedContextFpscr = r;
ctxt->savedSpuWriteEventMask = spu.get_ch_value(SPU_RdEventMask); ctxt->savedSpuWriteEventMask = spu.get_ch_value(SPU_RdEventMask);
ctxt->savedWriteTagGroupQueryMask = spu.get_ch_value(MFC_RdTagMask); ctxt->savedWriteTagGroupQueryMask = spu.get_ch_value(MFC_RdTagMask);
@ -1539,7 +1539,7 @@ void spursTasksetDispatch(SPUThread & spu) {
//spursDmaWaitForCompletion(spu, 1 << ctxt->dmaTagId); //spursDmaWaitForCompletion(spu, 1 << ctxt->dmaTagId);
// Restore saved registers // 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(MFC_WrTagMask, ctxt->savedWriteTagGroupQueryMask);
spu.set_ch_value(SPU_WrEventMask, ctxt->savedSpuWriteEventMask); spu.set_ch_value(SPU_WrEventMask, ctxt->savedSpuWriteEventMask);
@ -1555,7 +1555,7 @@ void spursTasksetDispatch(SPUThread & spu) {
return; return;
} }
spu.GPR[3].clear(); spu.gpr[3].clear();
spursTasksetResumeTask(spu); spursTasksetResumeTask(spu);
} }
} }

View File

@ -209,11 +209,9 @@ s32 sys_spu_thread_get_exit_status(u32 id, vm::ptr<u32> status)
// TODO: check CELL_ESTAT condition // TODO: check CELL_ESTAT condition
bool notify; *status = thread->ch_out_mbox.pop();
std::tie(*status, notify) = thread->ch_out_mbox.pop(); if (thread->ch_out_mbox.notification_required)
if (notify)
{ {
throw EXCEPTION("Unexpected"); throw EXCEPTION("Unexpected");
} }
@ -316,12 +314,12 @@ s32 sys_spu_thread_group_start(u32 id)
// TODO: use segment info // TODO: use segment info
std::memcpy(vm::get_ptr<void>(t->offset), vm::get_ptr<void>(image->addr), 256 * 1024); 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->run();
t->GPR[3] = v128::from64(0, args.arg1); t->gpr[3] = v128::from64(0, args.arg1);
t->GPR[4] = v128::from64(0, args.arg2); t->gpr[4] = v128::from64(0, args.arg2);
t->GPR[5] = v128::from64(0, args.arg3); t->gpr[5] = v128::from64(0, args.arg3);
t->GPR[6] = v128::from64(0, args.arg4); t->gpr[6] = v128::from64(0, args.arg4);
t->status.exchange(SPU_STATUS_RUNNING); 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)) if (thread->ch_in_mbox.push(value))
{ {
// notify if necessary // lock for reliable notification
std::lock_guard<std::mutex> lock(thread->mutex); std::lock_guard<std::mutex> lock(thread->mutex);
thread->cv.notify_one(); thread->cv.notify_one();
@ -1323,13 +1321,11 @@ s32 sys_raw_spu_read_puint_mb(u32 id, vm::ptr<u32> value)
return CELL_ESRCH; return CELL_ESRCH;
} }
bool notify; *value = thread->ch_out_intr_mbox.pop();
std::tie(*value, notify) = thread->ch_out_intr_mbox.pop(); if (thread->ch_out_intr_mbox.notification_required)
if (notify)
{ {
// notify if necessary // lock for reliable notification
std::lock_guard<std::mutex> lock(thread->mutex); std::lock_guard<std::mutex> lock(thread->mutex);
thread->cv.notify_one(); thread->cv.notify_one();

View File

@ -142,8 +142,7 @@ public:
void ResetInfo() void ResetInfo()
{ {
m_info.~EmuInfo(); m_info = {};
new (&m_info) EmuInfo();
} }
void SetTLSData(u32 addr, u32 filesz, u32 memsz) void SetTLSData(u32 addr, u32 filesz, u32 memsz)

View File

@ -7,7 +7,6 @@
#include "Emu/CPU/CPUThreadManager.h" #include "Emu/CPU/CPUThreadManager.h"
#include "Emu/Cell/PPUDecoder.h" #include "Emu/Cell/PPUDecoder.h"
#include "Emu/Cell/PPUDisAsm.h" #include "Emu/Cell/PPUDisAsm.h"
#include "Emu/Cell/SPUDecoder.h"
#include "Emu/Cell/SPUDisAsm.h" #include "Emu/Cell/SPUDisAsm.h"
#include "Emu/ARMv7/ARMv7DisAsm.h" #include "Emu/ARMv7/ARMv7DisAsm.h"
#include "Emu/ARMv7/ARMv7Decoder.h" #include "Emu/ARMv7/ARMv7Decoder.h"
@ -27,7 +26,6 @@ InterpreterDisAsmFrame::InterpreterDisAsmFrame(wxWindow* parent)
, PC(0) , PC(0)
, CPU(nullptr) , CPU(nullptr)
, m_item_count(30) , m_item_count(30)
, decoder(nullptr)
, disasm(nullptr) , disasm(nullptr)
{ {
wxBoxSizer* s_p_main = new wxBoxSizer(wxVERTICAL); wxBoxSizer* s_p_main = new wxBoxSizer(wxVERTICAL);
@ -121,11 +119,27 @@ void InterpreterDisAsmFrame::OnSelectUnit(wxCommandEvent& event)
{ {
CPU = (CPUThread*)event.GetClientData(); CPU = (CPUThread*)event.GetClientData();
delete decoder; decoder.reset();
//delete disasm;
decoder = nullptr;
disasm = nullptr; 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) if(CPU)
{ {
switch(CPU->get_type()) switch(CPU->get_type())
@ -133,7 +147,7 @@ void InterpreterDisAsmFrame::OnSelectUnit(wxCommandEvent& event)
case CPU_THREAD_PPU: case CPU_THREAD_PPU:
{ {
PPUDisAsm* dis_asm = new PPUDisAsm(CPUDisAsm_InterpreterMode); PPUDisAsm* dis_asm = new PPUDisAsm(CPUDisAsm_InterpreterMode);
decoder = new PPUDecoder(dis_asm); decoder = std::make_unique<PPUDecoder>(dis_asm);
disasm = dis_asm; disasm = dis_asm;
} }
break; break;
@ -141,9 +155,9 @@ void InterpreterDisAsmFrame::OnSelectUnit(wxCommandEvent& event)
case CPU_THREAD_SPU: case CPU_THREAD_SPU:
case CPU_THREAD_RAW_SPU: case CPU_THREAD_RAW_SPU:
{ {
SPUDisAsm& dis_asm = *new SPUDisAsm(CPUDisAsm_InterpreterMode); SPUDisAsm* dis_asm = new SPUDisAsm(CPUDisAsm_InterpreterMode);
decoder = new SPUDecoder(dis_asm); decoder = std::make_unique<SPUDecoder>(dis_asm);
disasm = &dis_asm; disasm = dis_asm;
} }
break; break;
@ -511,12 +525,12 @@ void InterpreterDisAsmFrame::InstrKey(wxListEvent& event)
{ {
case 'E': case 'E':
// TODO:: Syphurith: It is said the InstructionEditorDialog would be immediately destroyed. // 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(); DoUpdate();
return; return;
case 'R': case 'R':
// TODO:: Syphurith: Eh Similiar for this one. // TODO:: Syphurith: Eh Similiar for this one.
RegisterEditorDialog(this, pc, CPU, decoder, disasm); RegisterEditorDialog(this, pc, CPU, decoder.get(), disasm);
DoUpdate(); DoUpdate();
return; return;
} }

View File

@ -7,7 +7,7 @@ class InterpreterDisAsmFrame : public wxPanel
{ {
wxListView* m_list; wxListView* m_list;
CPUDisAsm* disasm; CPUDisAsm* disasm;
CPUDecoder* decoder; std::unique_ptr<CPUDecoder> decoder;
u64 PC; u64 PC;
std::vector<u32> remove_markedPC; std::vector<u32> remove_markedPC;
wxTextCtrl* m_regs; wxTextCtrl* m_regs;

View File

@ -148,8 +148,8 @@ SettingsDialog::SettingsDialog(wxWindow *parent)
#endif #endif
wxArrayString spu_decoder_modes; wxArrayString spu_decoder_modes;
spu_decoder_modes.Add("Interpreter"); spu_decoder_modes.Add("Interpreter (precise)");
spu_decoder_modes.Add("Interpreter 2"); spu_decoder_modes.Add("Interpreter (fast)");
spu_decoder_modes.Add("Recompiler (ASMJIT)"); 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); rbox_spu_decoder = new wxRadioBox(p_core, wxID_ANY, "SPU Decoder", wxDefaultPosition, wxSize(215, -1), spu_decoder_modes, 1);

View File

@ -330,6 +330,14 @@ namespace loader
continue; continue;
} }
if (Ini.LoadLibLv2.GetValue())
{
if (module->name != "liblv2.sprx")
{
continue;
}
}
elf64 sprx_handler; elf64 sprx_handler;
vfsFile fsprx(lle_dir.GetPath() + "/" + module->name); vfsFile fsprx(lle_dir.GetPath() + "/" + module->name);
@ -340,19 +348,19 @@ namespace loader
if (sprx_handler.is_sprx()) if (sprx_handler.is_sprx())
{ {
IniEntry<bool> load_lib; if (!Ini.LoadLibLv2.GetValue())
load_lib.Init(sprx_handler.sprx_get_module_name(), "LLE"); {
IniEntry<bool> load_lib;
load_lib.Init(sprx_handler.sprx_get_module_name(), "LLE");
if (!load_lib.LoadValue(false)) if (!load_lib.LoadValue(false))
{ {
LOG_WARNING(LOADER, "Skipped LLE library '%s'", sprx_handler.sprx_get_module_name().c_str()); continue;
continue; }
}
else
{
LOG_WARNING(LOADER, "Loading LLE library '%s'", sprx_handler.sprx_get_module_name().c_str());
} }
LOG_WARNING(LOADER, "Loading LLE library '%s'", sprx_handler.sprx_get_module_name().c_str());
sprx_info info; sprx_info info;
sprx_handler.load_sprx(info); sprx_handler.load_sprx(info);

View File

@ -53,6 +53,8 @@
<ClCompile Include="..\Utilities\VirtualMemory.cpp" /> <ClCompile Include="..\Utilities\VirtualMemory.cpp" />
<ClCompile Include="Emu\Cell\PPUInterpreter.cpp" /> <ClCompile Include="Emu\Cell\PPUInterpreter.cpp" />
<ClCompile Include="Emu\Cell\PPULLVMRecompilerCore.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\Cell\SPUInterpreter.cpp" />
<ClCompile Include="Emu\IdManager.cpp" /> <ClCompile Include="Emu\IdManager.cpp" />
<ClCompile Include="Emu\RSX\CgBinaryFragmentProgram.cpp" /> <ClCompile Include="Emu\RSX\CgBinaryFragmentProgram.cpp" />
@ -183,7 +185,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="Emu\Cell\PPUThread.cpp" /> <ClCompile Include="Emu\Cell\PPUThread.cpp" />
<ClCompile Include="Emu\Cell\RawSPUThread.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\Cell\SPUThread.cpp" />
<ClCompile Include="Emu\CPU\CPUThread.cpp" /> <ClCompile Include="Emu\CPU\CPUThread.cpp" />
<ClCompile Include="Emu\CPU\CPUThreadManager.cpp" /> <ClCompile Include="Emu\CPU\CPUThreadManager.cpp" />
@ -485,12 +487,11 @@
<ClInclude Include="Emu\Cell\PPUOpcodes.h" /> <ClInclude Include="Emu\Cell\PPUOpcodes.h" />
<ClInclude Include="Emu\Cell\PPUThread.h" /> <ClInclude Include="Emu\Cell\PPUThread.h" />
<ClInclude Include="Emu\Cell\RawSPUThread.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\SPUContext.h" />
<ClInclude Include="Emu\Cell\SPUDecoder.h" />
<ClInclude Include="Emu\Cell\SPUDisAsm.h" /> <ClInclude Include="Emu\Cell\SPUDisAsm.h" />
<ClInclude Include="Emu\Cell\SPUInstrTable.h" />
<ClInclude Include="Emu\Cell\SPUInterpreter.h" /> <ClInclude Include="Emu\Cell\SPUInterpreter.h" />
<ClInclude Include="Emu\Cell\SPUInterpreter2.h" />
<ClInclude Include="Emu\Cell\SPUOpcodes.h" /> <ClInclude Include="Emu\Cell\SPUOpcodes.h" />
<ClInclude Include="Emu\Cell\SPURecompiler.h" /> <ClInclude Include="Emu\Cell\SPURecompiler.h" />
<ClInclude Include="Emu\Cell\SPUThread.h" /> <ClInclude Include="Emu\Cell\SPUThread.h" />

View File

@ -350,9 +350,6 @@
<ClCompile Include="Emu\Cell\RawSPUThread.cpp"> <ClCompile Include="Emu\Cell\RawSPUThread.cpp">
<Filter>Emu\CPU\Cell</Filter> <Filter>Emu\CPU\Cell</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\Cell\SPURecompilerCore.cpp">
<Filter>Emu\CPU\Cell</Filter>
</ClCompile>
<ClCompile Include="Emu\Cell\SPUThread.cpp"> <ClCompile Include="Emu\Cell\SPUThread.cpp">
<Filter>Emu\CPU\Cell</Filter> <Filter>Emu\CPU\Cell</Filter>
</ClCompile> </ClCompile>
@ -986,6 +983,15 @@
<ClCompile Include="..\Utilities\VirtualMemory.cpp"> <ClCompile Include="..\Utilities\VirtualMemory.cpp">
<Filter>Utilities</Filter> <Filter>Utilities</Filter>
</ClCompile> </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>
<ItemGroup> <ItemGroup>
<ClInclude Include="Crypto\aes.h"> <ClInclude Include="Crypto\aes.h">
@ -1252,15 +1258,9 @@
<ClInclude Include="Emu\Cell\RawSPUThread.h"> <ClInclude Include="Emu\Cell\RawSPUThread.h">
<Filter>Emu\CPU\Cell</Filter> <Filter>Emu\CPU\Cell</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Emu\Cell\SPUDecoder.h">
<Filter>Emu\CPU\Cell</Filter>
</ClInclude>
<ClInclude Include="Emu\Cell\SPUDisAsm.h"> <ClInclude Include="Emu\Cell\SPUDisAsm.h">
<Filter>Emu\CPU\Cell</Filter> <Filter>Emu\CPU\Cell</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Emu\Cell\SPUInstrTable.h">
<Filter>Emu\CPU\Cell</Filter>
</ClInclude>
<ClInclude Include="Emu\Cell\SPUInterpreter.h"> <ClInclude Include="Emu\Cell\SPUInterpreter.h">
<Filter>Emu\CPU\Cell</Filter> <Filter>Emu\CPU\Cell</Filter>
</ClInclude> </ClInclude>
@ -1627,9 +1627,6 @@
<ClInclude Include="Emu\Cell\PPUInterpreter2.h"> <ClInclude Include="Emu\Cell\PPUInterpreter2.h">
<Filter>Emu\CPU\Cell</Filter> <Filter>Emu\CPU\Cell</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Emu\Cell\SPUInterpreter2.h">
<Filter>Emu\CPU\Cell</Filter>
</ClInclude>
<ClInclude Include="..\Utilities\File.h"> <ClInclude Include="..\Utilities\File.h">
<Filter>Utilities</Filter> <Filter>Utilities</Filter>
</ClInclude> </ClInclude>
@ -1873,5 +1870,11 @@
<ClInclude Include="..\Utilities\VirtualMemory.h"> <ClInclude Include="..\Utilities\VirtualMemory.h">
<Filter>Utilities</Filter> <Filter>Utilities</Filter>
</ClInclude> </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> </ItemGroup>
</Project> </Project>