Reformat all the things. Have fun with merge conflicts.

This commit is contained in:
Pierre Bourdon committed 2016-06-24 10:43:46 +02:00
1 parent 2115e8a4a6
commit 3570c7f03a
1116 files changed
+187350 -180289

No files matched your search

@@ -9,17 +9,17 @@
#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "Common/GekkoDisassembler.h"
#include "Common/StringUtil.h"
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
#include "Core/ConfigManager.h"
#include "Core/CoreTiming.h"
#include "Core/Host.h"
#include "Core/Debugger/Debugger_SymbolMap.h"
#include "Core/HLE/HLE.h"
#include "Core/HW/CPU.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/PowerPC/PPCTables.h"
#include "Core/Host.h"
#include "Core/PowerPC/Interpreter/Interpreter.h"
#include "Core/PowerPC/PPCTables.h"
#include "Core/PowerPC/PowerPC.h"
#ifdef USE_GDBSTUB
#include "Core/PowerPC/GDBStub.h"
@@ -27,7 +27,7 @@
namespace
{
u32 last_pc;
u32 last_pc;
}
bool Interpreter::m_EndBlock;
@@ -40,16 +40,31 @@ Interpreter::Instruction Interpreter::m_opTable31[1024];
Interpreter::Instruction Interpreter::m_opTable59[32];
Interpreter::Instruction Interpreter::m_opTable63[1024];
void Interpreter::RunTable4(UGeckoInstruction _inst) { m_opTable4 [_inst.SUBOP10](_inst); }
void Interpreter::RunTable19(UGeckoInstruction _inst) { m_opTable19[_inst.SUBOP10](_inst); }
void Interpreter::RunTable31(UGeckoInstruction _inst) { m_opTable31[_inst.SUBOP10](_inst); }
void Interpreter::RunTable59(UGeckoInstruction _inst) { m_opTable59[_inst.SUBOP5 ](_inst); }
void Interpreter::RunTable63(UGeckoInstruction _inst) { m_opTable63[_inst.SUBOP10](_inst); }
void Interpreter::RunTable4(UGeckoInstruction _inst)
{
m_opTable4[_inst.SUBOP10](_inst);
}
void Interpreter::RunTable19(UGeckoInstruction _inst)
{
m_opTable19[_inst.SUBOP10](_inst);
}
void Interpreter::RunTable31(UGeckoInstruction _inst)
{
m_opTable31[_inst.SUBOP10](_inst);
}
void Interpreter::RunTable59(UGeckoInstruction _inst)
{
m_opTable59[_inst.SUBOP5](_inst);
}
void Interpreter::RunTable63(UGeckoInstruction _inst)
{
m_opTable63[_inst.SUBOP10](_inst);
}
void Interpreter::Init()
{
g_bReserve = false;
m_EndBlock = false;
g_bReserve = false;
m_EndBlock = false;
}
void Interpreter::Shutdown()
@@ -60,139 +75,144 @@ static int startTrace = 0;
static void Trace(UGeckoInstruction& instCode)
{
std::string regs = "";
for (int i = 0; i < 32; i++)
{
regs += StringFromFormat("r%02d: %08x ", i, PowerPC::ppcState.gpr[i]);
}
std::string regs = "";
for (int i = 0; i < 32; i++)
{
regs += StringFromFormat("r%02d: %08x ", i, PowerPC::ppcState.gpr[i]);
}
std::string fregs = "";
for (int i = 0; i < 32; i++)
{
fregs += StringFromFormat("f%02d: %08" PRIx64 " %08" PRIx64 " ", i, PowerPC::ppcState.ps[i][0], PowerPC::ppcState.ps[i][1]);
}
std::string fregs = "";
for (int i = 0; i < 32; i++)
{
fregs += StringFromFormat("f%02d: %08" PRIx64 " %08" PRIx64 " ", i, PowerPC::ppcState.ps[i][0],
PowerPC::ppcState.ps[i][1]);
}
std::string ppc_inst = GekkoDisassembler::Disassemble(instCode.hex, PC);
DEBUG_LOG(POWERPC, "INTER PC: %08x SRR0: %08x SRR1: %08x CRval: %016lx FPSCR: %08x MSR: %08x LR: %08x %s %08x %s", PC, SRR0, SRR1, (unsigned long) PowerPC::ppcState.cr_val[0], PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs.c_str(), instCode.hex, ppc_inst.c_str());
std::string ppc_inst = GekkoDisassembler::Disassemble(instCode.hex, PC);
DEBUG_LOG(POWERPC, "INTER PC: %08x SRR0: %08x SRR1: %08x CRval: %016lx FPSCR: %08x MSR: %08x LR: "
"%08x %s %08x %s",
PC, SRR0, SRR1, (unsigned long)PowerPC::ppcState.cr_val[0], PowerPC::ppcState.fpscr,
PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs.c_str(), instCode.hex,
ppc_inst.c_str());
}
int Interpreter::SingleStepInner()
{
static UGeckoInstruction instCode;
u32 function = HLE::GetFunctionIndex(PC);
if (function != 0)
{
int type = HLE::GetFunctionTypeByIndex(function);
if (type == HLE::HLE_HOOK_START || type == HLE::HLE_HOOK_REPLACE)
{
int flags = HLE::GetFunctionFlagsByIndex(function);
if (HLE::IsEnabled(flags))
{
HLEFunction(function);
if (type == HLE::HLE_HOOK_START)
{
// Run the original.
function = 0;
}
}
else
{
function = 0;
}
}
}
static UGeckoInstruction instCode;
u32 function = HLE::GetFunctionIndex(PC);
if (function != 0)
{
int type = HLE::GetFunctionTypeByIndex(function);
if (type == HLE::HLE_HOOK_START || type == HLE::HLE_HOOK_REPLACE)
{
int flags = HLE::GetFunctionFlagsByIndex(function);
if (HLE::IsEnabled(flags))
{
HLEFunction(function);
if (type == HLE::HLE_HOOK_START)
{
// Run the original.
function = 0;
}
}
else
{
function = 0;
}
}
}
if (function == 0)
{
#ifdef USE_GDBSTUB
if (gdb_active() && gdb_bp_x(PC))
{
Host_UpdateDisasmDialog();
if (function == 0)
{
#ifdef USE_GDBSTUB
if (gdb_active() && gdb_bp_x(PC))
{
Host_UpdateDisasmDialog();
gdb_signal(SIGTRAP);
gdb_handle_exception();
}
#endif
gdb_signal(SIGTRAP);
gdb_handle_exception();
}
#endif
NPC = PC + sizeof(UGeckoInstruction);
instCode.hex = PowerPC::Read_Opcode(PC);
NPC = PC + sizeof(UGeckoInstruction);
instCode.hex = PowerPC::Read_Opcode(PC);
// Uncomment to trace the interpreter
//if ((PC & 0xffffff)>=0x0ab54c && (PC & 0xffffff)<=0x0ab624)
// startTrace = 1;
//else
// startTrace = 0;
// Uncomment to trace the interpreter
// if ((PC & 0xffffff)>=0x0ab54c && (PC & 0xffffff)<=0x0ab624)
// startTrace = 1;
// else
// startTrace = 0;
if (startTrace)
{
Trace(instCode);
}
if (startTrace)
{
Trace(instCode);
}
if (instCode.hex != 0)
{
UReg_MSR& msr = (UReg_MSR&)MSR;
if (msr.FP) //If FPU is enabled, just execute
{
m_opTable[instCode.OPCD](instCode);
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
PowerPC::CheckExceptions();
m_EndBlock = true;
}
}
else
{
// check if we have to generate a FPU unavailable exception
if (!PPCTables::UsesFPU(instCode))
{
m_opTable[instCode.OPCD](instCode);
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
PowerPC::CheckExceptions();
m_EndBlock = true;
}
}
else
{
PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
PowerPC::CheckExceptions();
m_EndBlock = true;
}
}
}
else
{
// Memory exception on instruction fetch
PowerPC::CheckExceptions();
m_EndBlock = true;
}
}
last_pc = PC;
PC = NPC;
if (instCode.hex != 0)
{
UReg_MSR& msr = (UReg_MSR&)MSR;
if (msr.FP) // If FPU is enabled, just execute
{
m_opTable[instCode.OPCD](instCode);
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
PowerPC::CheckExceptions();
m_EndBlock = true;
}
}
else
{
// check if we have to generate a FPU unavailable exception
if (!PPCTables::UsesFPU(instCode))
{
m_opTable[instCode.OPCD](instCode);
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
PowerPC::CheckExceptions();
m_EndBlock = true;
}
}
else
{
PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
PowerPC::CheckExceptions();
m_EndBlock = true;
}
}
}
else
{
// Memory exception on instruction fetch
PowerPC::CheckExceptions();
m_EndBlock = true;
}
}
last_pc = PC;
PC = NPC;
GekkoOPInfo *opinfo = GetOpInfo(instCode);
return opinfo->numCycles;
GekkoOPInfo* opinfo = GetOpInfo(instCode);
return opinfo->numCycles;
}
void Interpreter::SingleStep()
{
SingleStepInner();
SingleStepInner();
CoreTiming::g_slicelength = 1;
PowerPC::ppcState.downcount = 0;
CoreTiming::Advance();
CoreTiming::g_slicelength = 1;
PowerPC::ppcState.downcount = 0;
CoreTiming::Advance();
if (PowerPC::ppcState.Exceptions)
{
PowerPC::CheckExceptions();
PC = NPC;
}
if (PowerPC::ppcState.Exceptions)
{
PowerPC::CheckExceptions();
PC = NPC;
}
}
//#define SHOW_HISTORY
#ifdef SHOW_HISTORY
std::vector <int> PCVec;
std::vector <int> PCBlockVec;
std::vector<int> PCVec;
std::vector<int> PCBlockVec;
int ShowBlocks = 30;
int ShowSteps = 300;
#endif
@@ -200,118 +220,118 @@ int ShowSteps = 300;
// FastRun - inspired by GCemu (to imitate the JIT so that they can be compared).
void Interpreter::Run()
{
while (!CPU::GetState())
{
//we have to check exceptions at branches apparently (or maybe just rfi?)
if (SConfig::GetInstance().bEnableDebugging)
{
#ifdef SHOW_HISTORY
PCBlockVec.push_back(PC);
if (PCBlockVec.size() > ShowBlocks)
PCBlockVec.erase(PCBlockVec.begin());
#endif
while (!CPU::GetState())
{
// we have to check exceptions at branches apparently (or maybe just rfi?)
if (SConfig::GetInstance().bEnableDebugging)
{
#ifdef SHOW_HISTORY
PCBlockVec.push_back(PC);
if (PCBlockVec.size() > ShowBlocks)
PCBlockVec.erase(PCBlockVec.begin());
#endif
// Debugging friendly version of inner loop. Tries to do the timing as similarly to the
// JIT as possible. Does not take into account that some instructions take multiple cycles.
while (PowerPC::ppcState.downcount > 0)
{
m_EndBlock = false;
int i;
for (i = 0; !m_EndBlock; i++)
{
#ifdef SHOW_HISTORY
PCVec.push_back(PC);
if (PCVec.size() > ShowSteps)
PCVec.erase(PCVec.begin());
#endif
// Debugging friendly version of inner loop. Tries to do the timing as similarly to the
// JIT as possible. Does not take into account that some instructions take multiple cycles.
while (PowerPC::ppcState.downcount > 0)
{
m_EndBlock = false;
int i;
for (i = 0; !m_EndBlock; i++)
{
#ifdef SHOW_HISTORY
PCVec.push_back(PC);
if (PCVec.size() > ShowSteps)
PCVec.erase(PCVec.begin());
#endif
// 2: check for breakpoint
if (PowerPC::breakpoints.IsAddressBreakPoint(PC))
{
#ifdef SHOW_HISTORY
NOTICE_LOG(POWERPC, "----------------------------");
NOTICE_LOG(POWERPC, "Blocks:");
for (int j = 0; j < PCBlockVec.size(); j++)
NOTICE_LOG(POWERPC, "PC: 0x%08x", PCBlockVec.at(j));
NOTICE_LOG(POWERPC, "----------------------------");
NOTICE_LOG(POWERPC, "Steps:");
for (int j = 0; j < PCVec.size(); j++)
{
// Write space
if (j > 0)
{
if (PCVec.at(j) != PCVec.at(j - 1) + 4)
NOTICE_LOG(POWERPC, "");
}
//2: check for breakpoint
if (PowerPC::breakpoints.IsAddressBreakPoint(PC))
{
#ifdef SHOW_HISTORY
NOTICE_LOG(POWERPC, "----------------------------");
NOTICE_LOG(POWERPC, "Blocks:");
for (int j = 0; j < PCBlockVec.size(); j++)
NOTICE_LOG(POWERPC, "PC: 0x%08x", PCBlockVec.at(j));
NOTICE_LOG(POWERPC, "----------------------------");
NOTICE_LOG(POWERPC, "Steps:");
for (int j = 0; j < PCVec.size(); j++)
{
// Write space
if (j > 0)
{
if (PCVec.at(j) != PCVec.at(j-1) + 4)
NOTICE_LOG(POWERPC, "");
}
NOTICE_LOG(POWERPC, "PC: 0x%08x", PCVec.at(j));
}
#endif
INFO_LOG(POWERPC, "Hit Breakpoint - %08x", PC);
CPU::Break();
if (PowerPC::breakpoints.IsTempBreakPoint(PC))
PowerPC::breakpoints.Remove(PC);
NOTICE_LOG(POWERPC, "PC: 0x%08x", PCVec.at(j));
}
#endif
INFO_LOG(POWERPC, "Hit Breakpoint - %08x", PC);
CPU::Break();
if (PowerPC::breakpoints.IsTempBreakPoint(PC))
PowerPC::breakpoints.Remove(PC);
Host_UpdateDisasmDialog();
return;
}
SingleStepInner();
}
PowerPC::ppcState.downcount -= i;
}
}
else
{
// "fast" version of inner loop. well, it's not so fast.
while (PowerPC::ppcState.downcount > 0)
{
m_EndBlock = false;
Host_UpdateDisasmDialog();
return;
}
SingleStepInner();
}
PowerPC::ppcState.downcount -= i;
}
}
else
{
// "fast" version of inner loop. well, it's not so fast.
while (PowerPC::ppcState.downcount > 0)
{
m_EndBlock = false;
int cycles = 0;
while (!m_EndBlock)
{
cycles += SingleStepInner();
}
PowerPC::ppcState.downcount -= cycles;
}
}
int cycles = 0;
while (!m_EndBlock)
{
cycles += SingleStepInner();
}
PowerPC::ppcState.downcount -= cycles;
}
}
CoreTiming::Advance();
}
CoreTiming::Advance();
}
}
void Interpreter::unknown_instruction(UGeckoInstruction _inst)
{
std::string disasm = GekkoDisassembler::Disassemble(PowerPC::HostRead_U32(last_pc), last_pc);
NOTICE_LOG(POWERPC, "Last PC = %08x : %s", last_pc, disasm.c_str());
Dolphin_Debugger::PrintCallstack();
NOTICE_LOG(POWERPC, "\nIntCPU: Unknown instruction %08x at PC = %08x last_PC = %08x LR = %08x\n", _inst.hex, PC, last_pc, LR);
for (int i = 0; i < 32; i += 4)
NOTICE_LOG(POWERPC, "r%d: 0x%08x r%d: 0x%08x r%d:0x%08x r%d: 0x%08x",
i, rGPR[i],
i + 1, rGPR[i + 1],
i + 2, rGPR[i + 2],
i + 3, rGPR[i + 3]);
_assert_msg_(POWERPC, 0, "\nIntCPU: Unknown instruction %08x at PC = %08x last_PC = %08x LR = %08x\n", _inst.hex, PC, last_pc, LR);
std::string disasm = GekkoDisassembler::Disassemble(PowerPC::HostRead_U32(last_pc), last_pc);
NOTICE_LOG(POWERPC, "Last PC = %08x : %s", last_pc, disasm.c_str());
Dolphin_Debugger::PrintCallstack();
NOTICE_LOG(POWERPC,
"\nIntCPU: Unknown instruction %08x at PC = %08x last_PC = %08x LR = %08x\n",
_inst.hex, PC, last_pc, LR);
for (int i = 0; i < 32; i += 4)
NOTICE_LOG(POWERPC, "r%d: 0x%08x r%d: 0x%08x r%d:0x%08x r%d: 0x%08x", i, rGPR[i], i + 1,
rGPR[i + 1], i + 2, rGPR[i + 2], i + 3, rGPR[i + 3]);
_assert_msg_(POWERPC, 0,
"\nIntCPU: Unknown instruction %08x at PC = %08x last_PC = %08x LR = %08x\n",
_inst.hex, PC, last_pc, LR);
}
void Interpreter::ClearCache()
{
// Do nothing.
// Do nothing.
}
const char *Interpreter::GetName()
const char* Interpreter::GetName()
{
#ifdef _ARCH_64
return "Interpreter64";
return "Interpreter64";
#else
return "Interpreter32";
return "Interpreter32";
#endif
}
Interpreter *Interpreter::getInstance()
Interpreter* Interpreter::getInstance()
{
static Interpreter instance;
return &instance;
static Interpreter instance;
return &instance;
}
+275 -275
View File
@@ -11,300 +11,300 @@
class Interpreter : public CPUCoreBase
{
public:
void Init() override;
void Shutdown() override;
void SingleStep() override;
int SingleStepInner();
void Init() override;
void Shutdown() override;
void SingleStep() override;
int SingleStepInner();
void Run() override;
void ClearCache() override;
const char *GetName() override;
void Run() override;
void ClearCache() override;
const char* GetName() override;
static bool m_EndBlock;
static bool m_EndBlock;
static void unknown_instruction(UGeckoInstruction _inst);
static void unknown_instruction(UGeckoInstruction _inst);
// Branch Instructions
static void bx(UGeckoInstruction _inst);
static void bcx(UGeckoInstruction _inst);
static void bcctrx(UGeckoInstruction _inst);
static void bclrx(UGeckoInstruction _inst);
static void HLEFunction(UGeckoInstruction _inst);
// Branch Instructions
static void bx(UGeckoInstruction _inst);
static void bcx(UGeckoInstruction _inst);
static void bcctrx(UGeckoInstruction _inst);
static void bclrx(UGeckoInstruction _inst);
static void HLEFunction(UGeckoInstruction _inst);
// Syscall Instruction
static void sc(UGeckoInstruction _inst);
// Syscall Instruction
static void sc(UGeckoInstruction _inst);
// Floating Point Instructions
static void faddsx(UGeckoInstruction _inst);
static void fdivsx(UGeckoInstruction _inst);
static void fmaddsx(UGeckoInstruction _inst);
static void fmsubsx(UGeckoInstruction _inst);
static void fmulsx(UGeckoInstruction _inst);
static void fnmaddsx(UGeckoInstruction _inst);
static void fnmsubsx(UGeckoInstruction _inst);
static void fresx(UGeckoInstruction _inst);
static void fsubsx(UGeckoInstruction _inst);
static void fabsx(UGeckoInstruction _inst);
static void fcmpo(UGeckoInstruction _inst);
static void fcmpu(UGeckoInstruction _inst);
static void fctiwx(UGeckoInstruction _inst);
static void fctiwzx(UGeckoInstruction _inst);
static void fmrx(UGeckoInstruction _inst);
static void fnabsx(UGeckoInstruction _inst);
static void fnegx(UGeckoInstruction _inst);
static void frspx(UGeckoInstruction _inst);
static void faddx(UGeckoInstruction _inst);
static void fdivx(UGeckoInstruction _inst);
static void fmaddx(UGeckoInstruction _inst);
static void fmsubx(UGeckoInstruction _inst);
static void fmulx(UGeckoInstruction _inst);
static void fnmaddx(UGeckoInstruction _inst);
static void fnmsubx(UGeckoInstruction _inst);
static void frsqrtex(UGeckoInstruction _inst);
static void fselx(UGeckoInstruction _inst);
static void fsubx(UGeckoInstruction _inst);
// Floating Point Instructions
static void faddsx(UGeckoInstruction _inst);
static void fdivsx(UGeckoInstruction _inst);
static void fmaddsx(UGeckoInstruction _inst);
static void fmsubsx(UGeckoInstruction _inst);
static void fmulsx(UGeckoInstruction _inst);
static void fnmaddsx(UGeckoInstruction _inst);
static void fnmsubsx(UGeckoInstruction _inst);
static void fresx(UGeckoInstruction _inst);
static void fsubsx(UGeckoInstruction _inst);
static void fabsx(UGeckoInstruction _inst);
static void fcmpo(UGeckoInstruction _inst);
static void fcmpu(UGeckoInstruction _inst);
static void fctiwx(UGeckoInstruction _inst);
static void fctiwzx(UGeckoInstruction _inst);
static void fmrx(UGeckoInstruction _inst);
static void fnabsx(UGeckoInstruction _inst);
static void fnegx(UGeckoInstruction _inst);
static void frspx(UGeckoInstruction _inst);
static void faddx(UGeckoInstruction _inst);
static void fdivx(UGeckoInstruction _inst);
static void fmaddx(UGeckoInstruction _inst);
static void fmsubx(UGeckoInstruction _inst);
static void fmulx(UGeckoInstruction _inst);
static void fnmaddx(UGeckoInstruction _inst);
static void fnmsubx(UGeckoInstruction _inst);
static void frsqrtex(UGeckoInstruction _inst);
static void fselx(UGeckoInstruction _inst);
static void fsubx(UGeckoInstruction _inst);
// Integer Instructions
static void addi(UGeckoInstruction _inst);
static void addic(UGeckoInstruction _inst);
static void addic_rc(UGeckoInstruction _inst);
static void addis(UGeckoInstruction _inst);
static void andi_rc(UGeckoInstruction _inst);
static void andis_rc(UGeckoInstruction _inst);
static void cmpi(UGeckoInstruction _inst);
static void cmpli(UGeckoInstruction _inst);
static void mulli(UGeckoInstruction _inst);
static void ori(UGeckoInstruction _inst);
static void oris(UGeckoInstruction _inst);
static void subfic(UGeckoInstruction _inst);
static void twi(UGeckoInstruction _inst);
static void xori(UGeckoInstruction _inst);
static void xoris(UGeckoInstruction _inst);
static void rlwimix(UGeckoInstruction _inst);
static void rlwinmx(UGeckoInstruction _inst);
static void rlwnmx(UGeckoInstruction _inst);
static void andx(UGeckoInstruction _inst);
static void andcx(UGeckoInstruction _inst);
static void cmp(UGeckoInstruction _inst);
static void cmpl(UGeckoInstruction _inst);
static void cntlzwx(UGeckoInstruction _inst);
static void eqvx(UGeckoInstruction _inst);
static void extsbx(UGeckoInstruction _inst);
static void extshx(UGeckoInstruction _inst);
static void nandx(UGeckoInstruction _inst);
static void norx(UGeckoInstruction _inst);
static void orx(UGeckoInstruction _inst);
static void orcx(UGeckoInstruction _inst);
static void slwx(UGeckoInstruction _inst);
static void srawx(UGeckoInstruction _inst);
static void srawix(UGeckoInstruction _inst);
static void srwx(UGeckoInstruction _inst);
static void tw(UGeckoInstruction _inst);
static void xorx(UGeckoInstruction _inst);
static void addx(UGeckoInstruction _inst);
static void addcx(UGeckoInstruction _inst);
static void addex(UGeckoInstruction _inst);
static void addmex(UGeckoInstruction _inst);
static void addzex(UGeckoInstruction _inst);
static void divwx(UGeckoInstruction _inst);
static void divwux(UGeckoInstruction _inst);
static void mulhwx(UGeckoInstruction _inst);
static void mulhwux(UGeckoInstruction _inst);
static void mullwx(UGeckoInstruction _inst);
static void negx(UGeckoInstruction _inst);
static void subfx(UGeckoInstruction _inst);
static void subfcx(UGeckoInstruction _inst);
static void subfex(UGeckoInstruction _inst);
static void subfmex(UGeckoInstruction _inst);
static void subfzex(UGeckoInstruction _inst);
// Integer Instructions
static void addi(UGeckoInstruction _inst);
static void addic(UGeckoInstruction _inst);
static void addic_rc(UGeckoInstruction _inst);
static void addis(UGeckoInstruction _inst);
static void andi_rc(UGeckoInstruction _inst);
static void andis_rc(UGeckoInstruction _inst);
static void cmpi(UGeckoInstruction _inst);
static void cmpli(UGeckoInstruction _inst);
static void mulli(UGeckoInstruction _inst);
static void ori(UGeckoInstruction _inst);
static void oris(UGeckoInstruction _inst);
static void subfic(UGeckoInstruction _inst);
static void twi(UGeckoInstruction _inst);
static void xori(UGeckoInstruction _inst);
static void xoris(UGeckoInstruction _inst);
static void rlwimix(UGeckoInstruction _inst);
static void rlwinmx(UGeckoInstruction _inst);
static void rlwnmx(UGeckoInstruction _inst);
static void andx(UGeckoInstruction _inst);
static void andcx(UGeckoInstruction _inst);
static void cmp(UGeckoInstruction _inst);
static void cmpl(UGeckoInstruction _inst);
static void cntlzwx(UGeckoInstruction _inst);
static void eqvx(UGeckoInstruction _inst);
static void extsbx(UGeckoInstruction _inst);
static void extshx(UGeckoInstruction _inst);
static void nandx(UGeckoInstruction _inst);
static void norx(UGeckoInstruction _inst);
static void orx(UGeckoInstruction _inst);
static void orcx(UGeckoInstruction _inst);
static void slwx(UGeckoInstruction _inst);
static void srawx(UGeckoInstruction _inst);
static void srawix(UGeckoInstruction _inst);
static void srwx(UGeckoInstruction _inst);
static void tw(UGeckoInstruction _inst);
static void xorx(UGeckoInstruction _inst);
static void addx(UGeckoInstruction _inst);
static void addcx(UGeckoInstruction _inst);
static void addex(UGeckoInstruction _inst);
static void addmex(UGeckoInstruction _inst);
static void addzex(UGeckoInstruction _inst);
static void divwx(UGeckoInstruction _inst);
static void divwux(UGeckoInstruction _inst);
static void mulhwx(UGeckoInstruction _inst);
static void mulhwux(UGeckoInstruction _inst);
static void mullwx(UGeckoInstruction _inst);
static void negx(UGeckoInstruction _inst);
static void subfx(UGeckoInstruction _inst);
static void subfcx(UGeckoInstruction _inst);
static void subfex(UGeckoInstruction _inst);
static void subfmex(UGeckoInstruction _inst);
static void subfzex(UGeckoInstruction _inst);
// Load/Store Instructions
static void lbz(UGeckoInstruction _inst);
static void lbzu(UGeckoInstruction _inst);
static void lfd(UGeckoInstruction _inst);
static void lfdu(UGeckoInstruction _inst);
static void lfs(UGeckoInstruction _inst);
static void lfsu(UGeckoInstruction _inst);
static void lha(UGeckoInstruction _inst);
static void lhau(UGeckoInstruction _inst);
static void lhz(UGeckoInstruction _inst);
static void lhzu(UGeckoInstruction _inst);
static void lmw(UGeckoInstruction _inst);
static void lwz(UGeckoInstruction _inst);
static void lwzu(UGeckoInstruction _inst);
static void stb(UGeckoInstruction _inst);
static void stbu(UGeckoInstruction _inst);
static void stfd(UGeckoInstruction _inst);
static void stfdu(UGeckoInstruction _inst);
static void stfs(UGeckoInstruction _inst);
static void stfsu(UGeckoInstruction _inst);
static void sth(UGeckoInstruction _inst);
static void sthu(UGeckoInstruction _inst);
static void stmw(UGeckoInstruction _inst);
static void stw(UGeckoInstruction _inst);
static void stwu(UGeckoInstruction _inst);
static void dcba(UGeckoInstruction _inst);
static void dcbf(UGeckoInstruction _inst);
static void dcbi(UGeckoInstruction _inst);
static void dcbst(UGeckoInstruction _inst);
static void dcbt(UGeckoInstruction _inst);
static void dcbtst(UGeckoInstruction _inst);
static void dcbz(UGeckoInstruction _inst);
static void eciwx(UGeckoInstruction _inst);
static void ecowx(UGeckoInstruction _inst);
static void eieio(UGeckoInstruction _inst);
static void icbi(UGeckoInstruction _inst);
static void lbzux(UGeckoInstruction _inst);
static void lbzx(UGeckoInstruction _inst);
static void lfdux(UGeckoInstruction _inst);
static void lfdx(UGeckoInstruction _inst);
static void lfsux(UGeckoInstruction _inst);
static void lfsx(UGeckoInstruction _inst);
static void lhaux(UGeckoInstruction _inst);
static void lhax(UGeckoInstruction _inst);
static void lhbrx(UGeckoInstruction _inst);
static void lhzux(UGeckoInstruction _inst);
static void lhzx(UGeckoInstruction _inst);
static void lswi(UGeckoInstruction _inst);
static void lswx(UGeckoInstruction _inst);
static void lwarx(UGeckoInstruction _inst);
static void lwbrx(UGeckoInstruction _inst);
static void lwzux(UGeckoInstruction _inst);
static void lwzx(UGeckoInstruction _inst);
static void stbux(UGeckoInstruction _inst);
static void stbx(UGeckoInstruction _inst);
static void stfdux(UGeckoInstruction _inst);
static void stfdx(UGeckoInstruction _inst);
static void stfiwx(UGeckoInstruction _inst);
static void stfsux(UGeckoInstruction _inst);
static void stfsx(UGeckoInstruction _inst);
static void sthbrx(UGeckoInstruction _inst);
static void sthux(UGeckoInstruction _inst);
static void sthx(UGeckoInstruction _inst);
static void stswi(UGeckoInstruction _inst);
static void stswx(UGeckoInstruction _inst);
static void stwbrx(UGeckoInstruction _inst);
static void stwcxd(UGeckoInstruction _inst);
static void stwux(UGeckoInstruction _inst);
static void stwx(UGeckoInstruction _inst);
static void tlbie(UGeckoInstruction _inst);
static void tlbsync(UGeckoInstruction _inst);
// Load/Store Instructions
static void lbz(UGeckoInstruction _inst);
static void lbzu(UGeckoInstruction _inst);
static void lfd(UGeckoInstruction _inst);
static void lfdu(UGeckoInstruction _inst);
static void lfs(UGeckoInstruction _inst);
static void lfsu(UGeckoInstruction _inst);
static void lha(UGeckoInstruction _inst);
static void lhau(UGeckoInstruction _inst);
static void lhz(UGeckoInstruction _inst);
static void lhzu(UGeckoInstruction _inst);
static void lmw(UGeckoInstruction _inst);
static void lwz(UGeckoInstruction _inst);
static void lwzu(UGeckoInstruction _inst);
static void stb(UGeckoInstruction _inst);
static void stbu(UGeckoInstruction _inst);
static void stfd(UGeckoInstruction _inst);
static void stfdu(UGeckoInstruction _inst);
static void stfs(UGeckoInstruction _inst);
static void stfsu(UGeckoInstruction _inst);
static void sth(UGeckoInstruction _inst);
static void sthu(UGeckoInstruction _inst);
static void stmw(UGeckoInstruction _inst);
static void stw(UGeckoInstruction _inst);
static void stwu(UGeckoInstruction _inst);
static void dcba(UGeckoInstruction _inst);
static void dcbf(UGeckoInstruction _inst);
static void dcbi(UGeckoInstruction _inst);
static void dcbst(UGeckoInstruction _inst);
static void dcbt(UGeckoInstruction _inst);
static void dcbtst(UGeckoInstruction _inst);
static void dcbz(UGeckoInstruction _inst);
static void eciwx(UGeckoInstruction _inst);
static void ecowx(UGeckoInstruction _inst);
static void eieio(UGeckoInstruction _inst);
static void icbi(UGeckoInstruction _inst);
static void lbzux(UGeckoInstruction _inst);
static void lbzx(UGeckoInstruction _inst);
static void lfdux(UGeckoInstruction _inst);
static void lfdx(UGeckoInstruction _inst);
static void lfsux(UGeckoInstruction _inst);
static void lfsx(UGeckoInstruction _inst);
static void lhaux(UGeckoInstruction _inst);
static void lhax(UGeckoInstruction _inst);
static void lhbrx(UGeckoInstruction _inst);
static void lhzux(UGeckoInstruction _inst);
static void lhzx(UGeckoInstruction _inst);
static void lswi(UGeckoInstruction _inst);
static void lswx(UGeckoInstruction _inst);
static void lwarx(UGeckoInstruction _inst);
static void lwbrx(UGeckoInstruction _inst);
static void lwzux(UGeckoInstruction _inst);
static void lwzx(UGeckoInstruction _inst);
static void stbux(UGeckoInstruction _inst);
static void stbx(UGeckoInstruction _inst);
static void stfdux(UGeckoInstruction _inst);
static void stfdx(UGeckoInstruction _inst);
static void stfiwx(UGeckoInstruction _inst);
static void stfsux(UGeckoInstruction _inst);
static void stfsx(UGeckoInstruction _inst);
static void sthbrx(UGeckoInstruction _inst);
static void sthux(UGeckoInstruction _inst);
static void sthx(UGeckoInstruction _inst);
static void stswi(UGeckoInstruction _inst);
static void stswx(UGeckoInstruction _inst);
static void stwbrx(UGeckoInstruction _inst);
static void stwcxd(UGeckoInstruction _inst);
static void stwux(UGeckoInstruction _inst);
static void stwx(UGeckoInstruction _inst);
static void tlbie(UGeckoInstruction _inst);
static void tlbsync(UGeckoInstruction _inst);
// Paired Instructions
static void psq_l(UGeckoInstruction _inst);
static void psq_lu(UGeckoInstruction _inst);
static void psq_st(UGeckoInstruction _inst);
static void psq_stu(UGeckoInstruction _inst);
static void psq_lx(UGeckoInstruction _inst);
static void psq_stx(UGeckoInstruction _inst);
static void psq_lux(UGeckoInstruction _inst);
static void psq_stux(UGeckoInstruction _inst);
static void ps_div(UGeckoInstruction _inst);
static void ps_sub(UGeckoInstruction _inst);
static void ps_add(UGeckoInstruction _inst);
static void ps_sel(UGeckoInstruction _inst);
static void ps_res(UGeckoInstruction _inst);
static void ps_mul(UGeckoInstruction _inst);
static void ps_rsqrte(UGeckoInstruction _inst);
static void ps_msub(UGeckoInstruction _inst);
static void ps_madd(UGeckoInstruction _inst);
static void ps_nmsub(UGeckoInstruction _inst);
static void ps_nmadd(UGeckoInstruction _inst);
static void ps_neg(UGeckoInstruction _inst);
static void ps_mr(UGeckoInstruction _inst);
static void ps_nabs(UGeckoInstruction _inst);
static void ps_abs(UGeckoInstruction _inst);
static void ps_sum0(UGeckoInstruction _inst);
static void ps_sum1(UGeckoInstruction _inst);
static void ps_muls0(UGeckoInstruction _inst);
static void ps_muls1(UGeckoInstruction _inst);
static void ps_madds0(UGeckoInstruction _inst);
static void ps_madds1(UGeckoInstruction _inst);
static void ps_cmpu0(UGeckoInstruction _inst);
static void ps_cmpo0(UGeckoInstruction _inst);
static void ps_cmpu1(UGeckoInstruction _inst);
static void ps_cmpo1(UGeckoInstruction _inst);
static void ps_merge00(UGeckoInstruction _inst);
static void ps_merge01(UGeckoInstruction _inst);
static void ps_merge10(UGeckoInstruction _inst);
static void ps_merge11(UGeckoInstruction _inst);
static void dcbz_l(UGeckoInstruction _inst);
// Paired Instructions
static void psq_l(UGeckoInstruction _inst);
static void psq_lu(UGeckoInstruction _inst);
static void psq_st(UGeckoInstruction _inst);
static void psq_stu(UGeckoInstruction _inst);
static void psq_lx(UGeckoInstruction _inst);
static void psq_stx(UGeckoInstruction _inst);
static void psq_lux(UGeckoInstruction _inst);
static void psq_stux(UGeckoInstruction _inst);
static void ps_div(UGeckoInstruction _inst);
static void ps_sub(UGeckoInstruction _inst);
static void ps_add(UGeckoInstruction _inst);
static void ps_sel(UGeckoInstruction _inst);
static void ps_res(UGeckoInstruction _inst);
static void ps_mul(UGeckoInstruction _inst);
static void ps_rsqrte(UGeckoInstruction _inst);
static void ps_msub(UGeckoInstruction _inst);
static void ps_madd(UGeckoInstruction _inst);
static void ps_nmsub(UGeckoInstruction _inst);
static void ps_nmadd(UGeckoInstruction _inst);
static void ps_neg(UGeckoInstruction _inst);
static void ps_mr(UGeckoInstruction _inst);
static void ps_nabs(UGeckoInstruction _inst);
static void ps_abs(UGeckoInstruction _inst);
static void ps_sum0(UGeckoInstruction _inst);
static void ps_sum1(UGeckoInstruction _inst);
static void ps_muls0(UGeckoInstruction _inst);
static void ps_muls1(UGeckoInstruction _inst);
static void ps_madds0(UGeckoInstruction _inst);
static void ps_madds1(UGeckoInstruction _inst);
static void ps_cmpu0(UGeckoInstruction _inst);
static void ps_cmpo0(UGeckoInstruction _inst);
static void ps_cmpu1(UGeckoInstruction _inst);
static void ps_cmpo1(UGeckoInstruction _inst);
static void ps_merge00(UGeckoInstruction _inst);
static void ps_merge01(UGeckoInstruction _inst);
static void ps_merge10(UGeckoInstruction _inst);
static void ps_merge11(UGeckoInstruction _inst);
static void dcbz_l(UGeckoInstruction _inst);
// System Registers Instructions
static void mcrfs(UGeckoInstruction _inst);
static void mffsx(UGeckoInstruction _inst);
static void mtfsb0x(UGeckoInstruction _inst);
static void mtfsb1x(UGeckoInstruction _inst);
static void mtfsfix(UGeckoInstruction _inst);
static void mtfsfx(UGeckoInstruction _inst);
static void mcrxr(UGeckoInstruction _inst);
static void mfcr(UGeckoInstruction _inst);
static void mfmsr(UGeckoInstruction _inst);
static void mfsr(UGeckoInstruction _inst);
static void mfsrin(UGeckoInstruction _inst);
static void mtmsr(UGeckoInstruction _inst);
static void mtsr(UGeckoInstruction _inst);
static void mtsrin(UGeckoInstruction _inst);
static void mfspr(UGeckoInstruction _inst);
static void mftb(UGeckoInstruction _inst);
static void mtcrf(UGeckoInstruction _inst);
static void mtspr(UGeckoInstruction _inst);
static void crand(UGeckoInstruction _inst);
static void crandc(UGeckoInstruction _inst);
static void creqv(UGeckoInstruction _inst);
static void crnand(UGeckoInstruction _inst);
static void crnor(UGeckoInstruction _inst);
static void cror(UGeckoInstruction _inst);
static void crorc(UGeckoInstruction _inst);
static void crxor(UGeckoInstruction _inst);
static void mcrf(UGeckoInstruction _inst);
static void rfi(UGeckoInstruction _inst);
static void sync(UGeckoInstruction _inst);
static void isync(UGeckoInstruction _inst);
// System Registers Instructions
static void mcrfs(UGeckoInstruction _inst);
static void mffsx(UGeckoInstruction _inst);
static void mtfsb0x(UGeckoInstruction _inst);
static void mtfsb1x(UGeckoInstruction _inst);
static void mtfsfix(UGeckoInstruction _inst);
static void mtfsfx(UGeckoInstruction _inst);
static void mcrxr(UGeckoInstruction _inst);
static void mfcr(UGeckoInstruction _inst);
static void mfmsr(UGeckoInstruction _inst);
static void mfsr(UGeckoInstruction _inst);
static void mfsrin(UGeckoInstruction _inst);
static void mtmsr(UGeckoInstruction _inst);
static void mtsr(UGeckoInstruction _inst);
static void mtsrin(UGeckoInstruction _inst);
static void mfspr(UGeckoInstruction _inst);
static void mftb(UGeckoInstruction _inst);
static void mtcrf(UGeckoInstruction _inst);
static void mtspr(UGeckoInstruction _inst);
static void crand(UGeckoInstruction _inst);
static void crandc(UGeckoInstruction _inst);
static void creqv(UGeckoInstruction _inst);
static void crnand(UGeckoInstruction _inst);
static void crnor(UGeckoInstruction _inst);
static void cror(UGeckoInstruction _inst);
static void crorc(UGeckoInstruction _inst);
static void crxor(UGeckoInstruction _inst);
static void mcrf(UGeckoInstruction _inst);
static void rfi(UGeckoInstruction _inst);
static void sync(UGeckoInstruction _inst);
static void isync(UGeckoInstruction _inst);
using Instruction = void (*)(UGeckoInstruction instCode);
static Instruction m_opTable[64];
static Instruction m_opTable4[1024];
static Instruction m_opTable19[1024];
static Instruction m_opTable31[1024];
static Instruction m_opTable59[32];
static Instruction m_opTable63[1024];
using Instruction = void (*)(UGeckoInstruction instCode);
static Instruction m_opTable[64];
static Instruction m_opTable4[1024];
static Instruction m_opTable19[1024];
static Instruction m_opTable31[1024];
static Instruction m_opTable59[32];
static Instruction m_opTable63[1024];
// singleton
static Interpreter* getInstance();
// singleton
static Interpreter* getInstance();
static void RunTable4(UGeckoInstruction _instCode);
static void RunTable19(UGeckoInstruction _instCode);
static void RunTable31(UGeckoInstruction _instCode);
static void RunTable59(UGeckoInstruction _instCode);
static void RunTable63(UGeckoInstruction _instCode);
static void RunTable4(UGeckoInstruction _instCode);
static void RunTable19(UGeckoInstruction _instCode);
static void RunTable31(UGeckoInstruction _instCode);
static void RunTable59(UGeckoInstruction _instCode);
static void RunTable63(UGeckoInstruction _instCode);
static u32 Helper_Carry(u32 _uValue1, u32 _uValue2);
static u32 Helper_Carry(u32 _uValue1, u32 _uValue2);
private:
// flag helper
static void Helper_UpdateCR0(u32 _uValue);
static void Helper_UpdateCR1();
static void Helper_UpdateCRx(int _x, u32 _uValue);
// flag helper
static void Helper_UpdateCR0(u32 _uValue);
static void Helper_UpdateCR1();
static void Helper_UpdateCRx(int _x, u32 _uValue);
// address helper
static u32 Helper_Get_EA (const UGeckoInstruction _inst);
static u32 Helper_Get_EA_U (const UGeckoInstruction _inst);
static u32 Helper_Get_EA_X (const UGeckoInstruction _inst);
static u32 Helper_Get_EA_UX(const UGeckoInstruction _inst);
// address helper
static u32 Helper_Get_EA(const UGeckoInstruction _inst);
static u32 Helper_Get_EA_U(const UGeckoInstruction _inst);
static u32 Helper_Get_EA_X(const UGeckoInstruction _inst);
static u32 Helper_Get_EA_UX(const UGeckoInstruction _inst);
// paired helper
static void Helper_Dequantize(u32 addr, u32 instI, u32 instRD, u32 instW);
static void Helper_Quantize(u32 addr, u32 instI, u32 instRS, u32 instW);
// paired helper
static void Helper_Dequantize(u32 addr, u32 instI, u32 instRD, u32 instW);
static void Helper_Quantize(u32 addr, u32 instI, u32 instRS, u32 instW);
// other helper
static u32 Helper_Mask(int mb, int me);
// other helper
static u32 Helper_Mask(int mb, int me);
static void Helper_FloatCompareOrdered(UGeckoInstruction _inst, double a, double b);
static void Helper_FloatCompareUnordered(UGeckoInstruction _inst, double a, double b);
static void Helper_FloatCompareOrdered(UGeckoInstruction _inst, double a, double b);
static void Helper_FloatCompareUnordered(UGeckoInstruction _inst, double a, double b);
// TODO: These should really be in the save state, although it's unlikely to matter much.
// They are for lwarx and its friend stwcxd.
static bool g_bReserve;
static u32 g_reserveAddr;
// TODO: These should really be in the save state, although it's unlikely to matter much.
// They are for lwarx and its friend stwcxd.
static bool g_bReserve;
static u32 g_reserveAddr;
};
@@ -2,138 +2,142 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/PowerPC/Interpreter/Interpreter.h"
#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "Core/ConfigManager.h"
#include "Core/CoreTiming.h"
#include "Core/HLE/HLE.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/PowerPC/Interpreter/Interpreter.h"
void Interpreter::bx(UGeckoInstruction _inst)
{
if (_inst.LK)
LR = PC + 4;
if (_inst.LK)
LR = PC + 4;
if (_inst.AA)
NPC = SignExt26(_inst.LI << 2);
else
NPC = PC+SignExt26(_inst.LI << 2);
if (_inst.AA)
NPC = SignExt26(_inst.LI << 2);
else
NPC = PC + SignExt26(_inst.LI << 2);
m_EndBlock = true;
m_EndBlock = true;
if (NPC == PC && SConfig::GetInstance().bSkipIdle)
{
CoreTiming::Idle();
}
if (NPC == PC && SConfig::GetInstance().bSkipIdle)
{
CoreTiming::Idle();
}
}
// bcx - ugly, straight from PPC manual equations :)
void Interpreter::bcx(UGeckoInstruction _inst)
{
if ((_inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
CTR--;
if ((_inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
CTR--;
const bool true_false = ((_inst.BO >> 3) & 1);
const bool only_counter_check = ((_inst.BO >> 4) & 1);
const bool only_condition_check = ((_inst.BO >> 2) & 1);
int ctr_check = ((CTR != 0) ^ (_inst.BO >> 1)) & 1;
bool counter = only_condition_check || ctr_check;
bool condition = only_counter_check || (GetCRBit(_inst.BI) == u32(true_false));
const bool true_false = ((_inst.BO >> 3) & 1);
const bool only_counter_check = ((_inst.BO >> 4) & 1);
const bool only_condition_check = ((_inst.BO >> 2) & 1);
int ctr_check = ((CTR != 0) ^ (_inst.BO >> 1)) & 1;
bool counter = only_condition_check || ctr_check;
bool condition = only_counter_check || (GetCRBit(_inst.BI) == u32(true_false));
if (counter && condition)
{
if (_inst.LK)
LR = PC + 4;
if (counter && condition)
{
if (_inst.LK)
LR = PC + 4;
if (_inst.AA)
NPC = SignExt16(_inst.BD << 2);
else
NPC = PC + SignExt16(_inst.BD << 2);
}
if (_inst.AA)
NPC = SignExt16(_inst.BD << 2);
else
NPC = PC + SignExt16(_inst.BD << 2);
}
m_EndBlock = true;
m_EndBlock = true;
// this code trys to detect the most common idle loop:
// lwz r0, XXXX(r13)
// cmpXwi r0,0
// beq -8
if (NPC == PC - 8 && _inst.hex == 0x4182fff8 /* beq */ && SConfig::GetInstance().bSkipIdle)
{
if (PowerPC::HostRead_U32(PC - 8) >> 16 == 0x800D /* lwz */ )
{
u32 last_inst = PowerPC::HostRead_U32(PC - 4);
// this code trys to detect the most common idle loop:
// lwz r0, XXXX(r13)
// cmpXwi r0,0
// beq -8
if (NPC == PC - 8 && _inst.hex == 0x4182fff8 /* beq */ && SConfig::GetInstance().bSkipIdle)
{
if (PowerPC::HostRead_U32(PC - 8) >> 16 == 0x800D /* lwz */)
{
u32 last_inst = PowerPC::HostRead_U32(PC - 4);
if (last_inst == 0x28000000 /* cmplwi */ || (last_inst == 0x2C000000 /* cmpwi */ && SConfig::GetInstance().bWii))
{
CoreTiming::Idle();
}
}
}
if (last_inst == 0x28000000 /* cmplwi */ ||
(last_inst == 0x2C000000 /* cmpwi */ && SConfig::GetInstance().bWii))
{
CoreTiming::Idle();
}
}
}
}
void Interpreter::bcctrx(UGeckoInstruction _inst)
{
_dbg_assert_msg_(POWERPC, _inst.BO_2 & BO_DONT_DECREMENT_FLAG, "bcctrx with decrement and test CTR option is invalid!");
_dbg_assert_msg_(POWERPC, _inst.BO_2 & BO_DONT_DECREMENT_FLAG,
"bcctrx with decrement and test CTR option is invalid!");
int condition = ((_inst.BO_2>>4) | (GetCRBit(_inst.BI_2) == ((_inst.BO_2>>3) & 1))) & 1;
int condition = ((_inst.BO_2 >> 4) | (GetCRBit(_inst.BI_2) == ((_inst.BO_2 >> 3) & 1))) & 1;
if (condition)
{
NPC = CTR & (~3);
if (_inst.LK_3)
LR = PC + 4;
}
if (condition)
{
NPC = CTR & (~3);
if (_inst.LK_3)
LR = PC + 4;
}
m_EndBlock = true;
m_EndBlock = true;
}
void Interpreter::bclrx(UGeckoInstruction _inst)
{
if ((_inst.BO_2 & BO_DONT_DECREMENT_FLAG) == 0)
CTR--;
if ((_inst.BO_2 & BO_DONT_DECREMENT_FLAG) == 0)
CTR--;
int counter = ((_inst.BO_2 >> 2) | ((CTR != 0) ^ (_inst.BO_2 >> 1))) & 1;
int condition = ((_inst.BO_2 >> 4) | (GetCRBit(_inst.BI_2) == ((_inst.BO_2 >> 3) & 1))) & 1;
int counter = ((_inst.BO_2 >> 2) | ((CTR != 0) ^ (_inst.BO_2 >> 1))) & 1;
int condition = ((_inst.BO_2 >> 4) | (GetCRBit(_inst.BI_2) == ((_inst.BO_2 >> 3) & 1))) & 1;
if (counter & condition)
{
NPC = LR & (~3);
if (_inst.LK_3)
LR = PC + 4;
}
if (counter & condition)
{
NPC = LR & (~3);
if (_inst.LK_3)
LR = PC + 4;
}
m_EndBlock = true;
m_EndBlock = true;
}
void Interpreter::HLEFunction(UGeckoInstruction _inst)
{
m_EndBlock = true;
HLE::Execute(PC, _inst.hex);
m_EndBlock = true;
HLE::Execute(PC, _inst.hex);
}
void Interpreter::rfi(UGeckoInstruction _inst)
{
// Restore saved bits from SRR1 to MSR.
// Gecko/Broadway can save more bits than explicitly defined in ppc spec
const int mask = 0x87C0FFFF;
MSR = (MSR & ~mask) | (SRR1 & mask);
//MSR[13] is set to 0.
MSR &= 0xFFFBFFFF;
// Here we should check if there are pending exceptions, and if their corresponding enable bits are set
// if above is true, we'd do:
//PowerPC::CheckExceptions();
//else
// set NPC to saved offset and resume
NPC = SRR0;
m_EndBlock = true;
// Restore saved bits from SRR1 to MSR.
// Gecko/Broadway can save more bits than explicitly defined in ppc spec
const int mask = 0x87C0FFFF;
MSR = (MSR & ~mask) | (SRR1 & mask);
// MSR[13] is set to 0.
MSR &= 0xFFFBFFFF;
// Here we should check if there are pending exceptions, and if their corresponding enable bits
// are set
// if above is true, we'd do:
// PowerPC::CheckExceptions();
// else
// set NPC to saved offset and resume
NPC = SRR0;
m_EndBlock = true;
}
// sc isn't really used for anything important in GameCube games (just for a write barrier) so we really don't have to emulate it.
// sc isn't really used for anything important in GameCube games (just for a write barrier) so we
// really don't have to emulate it.
// We do it anyway, though :P
void Interpreter::sc(UGeckoInstruction _inst)
{
PowerPC::ppcState.Exceptions |= EXCEPTION_SYSCALL;
PowerPC::CheckExceptions();
m_EndBlock = true;
PowerPC::ppcState.Exceptions |= EXCEPTION_SYSCALL;
PowerPC::CheckExceptions();
m_EndBlock = true;
}
@@ -7,81 +7,81 @@
#include <cmath>
#include <limits>
#include "Common/CommonTypes.h"
#include "Common/CPUDetect.h"
#include "Common/CommonTypes.h"
#include "Common/MathUtil.h"
#include "Core/PowerPC/Gekko.h"
#include "Core/PowerPC/PowerPC.h"
const u64 PPC_NAN_U64 = 0x7ff8000000000000ull;
const double PPC_NAN = *(double* const)&PPC_NAN_U64;
const double PPC_NAN = *(double* const) & PPC_NAN_U64;
// the 4 less-significand bits in FPSCR[FPRF]
enum FPCC
{
FL = 8, // <
FG = 4, // >
FE = 2, // =
FU = 1, // ?
FL = 8, // <
FG = 4, // >
FE = 2, // =
FU = 1, // ?
};
inline void SetFPException(u32 mask)
{
if ((FPSCR.Hex & mask) != mask)
{
FPSCR.FX = 1;
}
FPSCR.Hex |= mask;
if ((FPSCR.Hex & mask) != mask)
{
FPSCR.FX = 1;
}
FPSCR.Hex |= mask;
}
inline void SetFI(int FI)
{
if (FI)
{
SetFPException(FPSCR_XX);
}
FPSCR.FI = FI;
if (FI)
{
SetFPException(FPSCR_XX);
}
FPSCR.FI = FI;
}
inline void UpdateFPSCR()
{
FPSCR.VX = (FPSCR.Hex & FPSCR_VX_ANY) != 0;
FPSCR.FEX = 0; // we assume that "?E" bits are always 0
FPSCR.VX = (FPSCR.Hex & FPSCR_VX_ANY) != 0;
FPSCR.FEX = 0; // we assume that "?E" bits are always 0
}
inline double ForceSingle(double _x)
{
// convert to float...
float x = (float) _x;
if (!cpu_info.bFlushToZero && FPSCR.NI)
{
x = MathUtil::FlushToZero(x);
}
// ...and back to double:
return x;
// convert to float...
float x = (float)_x;
if (!cpu_info.bFlushToZero && FPSCR.NI)
{
x = MathUtil::FlushToZero(x);
}
// ...and back to double:
return x;
}
inline double ForceDouble(double d)
{
if (!cpu_info.bFlushToZero && FPSCR.NI)
{
d = MathUtil::FlushToZero(d);
}
return d;
if (!cpu_info.bFlushToZero && FPSCR.NI)
{
d = MathUtil::FlushToZero(d);
}
return d;
}
inline double Force25Bit(double d)
{
MathUtil::IntDouble x(d);
x.i = (x.i & 0xFFFFFFFFF8000000ULL) + (x.i & 0x8000000);
return x.d;
MathUtil::IntDouble x(d);
x.i = (x.i & 0xFFFFFFFFF8000000ULL) + (x.i & 0x8000000);
return x.d;
}
inline double MakeQuiet(double d)
{
MathUtil::IntDouble x(d);
x.i |= MathUtil::DOUBLE_QBIT;
return x.d;
MathUtil::IntDouble x(d);
x.i |= MathUtil::DOUBLE_QBIT;
return x.d;
}
// these functions allow globally modify operations behaviour
@@ -89,63 +89,71 @@ inline double MakeQuiet(double d)
inline double NI_mul(double a, double b)
{
double t = a * b;
if (std::isnan(t))
{
if (std::isnan(a)) return MakeQuiet(a);
if (std::isnan(b)) return MakeQuiet(b);
SetFPException(FPSCR_VXIMZ);
return PPC_NAN;
}
return t;
double t = a * b;
if (std::isnan(t))
{
if (std::isnan(a))
return MakeQuiet(a);
if (std::isnan(b))
return MakeQuiet(b);
SetFPException(FPSCR_VXIMZ);
return PPC_NAN;
}
return t;
}
inline double NI_div(double a, double b)
{
double t = a / b;
if (std::isnan(t))
{
if (std::isnan(a)) return MakeQuiet(a);
if (std::isnan(b)) return MakeQuiet(b);
if (b == 0.0)
{
SetFPException(FPSCR_ZX);
if (a == 0.0)
SetFPException(FPSCR_VXZDZ);
}
else if (std::isinf(a) && std::isinf(b))
{
SetFPException(FPSCR_VXIDI);
}
return PPC_NAN;
}
return t;
double t = a / b;
if (std::isnan(t))
{
if (std::isnan(a))
return MakeQuiet(a);
if (std::isnan(b))
return MakeQuiet(b);
if (b == 0.0)
{
SetFPException(FPSCR_ZX);
if (a == 0.0)
SetFPException(FPSCR_VXZDZ);
}
else if (std::isinf(a) && std::isinf(b))
{
SetFPException(FPSCR_VXIDI);
}
return PPC_NAN;
}
return t;
}
inline double NI_add(double a, double b)
{
double t = a + b;
if (std::isnan(t))
{
if (std::isnan(a)) return MakeQuiet(a);
if (std::isnan(b)) return MakeQuiet(b);
SetFPException(FPSCR_VXISI);
return PPC_NAN;
}
return t;
double t = a + b;
if (std::isnan(t))
{
if (std::isnan(a))
return MakeQuiet(a);
if (std::isnan(b))
return MakeQuiet(b);
SetFPException(FPSCR_VXISI);
return PPC_NAN;
}
return t;
}
inline double NI_sub(double a, double b)
{
double t = a - b;
if (std::isnan(t))
{
if (std::isnan(a)) return MakeQuiet(a);
if (std::isnan(b)) return MakeQuiet(b);
SetFPException(FPSCR_VXISI);
return PPC_NAN;
}
return t;
double t = a - b;
if (std::isnan(t))
{
if (std::isnan(a))
return MakeQuiet(a);
if (std::isnan(b))
return MakeQuiet(b);
SetFPException(FPSCR_VXISI);
return PPC_NAN;
}
return t;
}
// FMA instructions on PowerPC are weird:
@@ -153,117 +161,124 @@ inline double NI_sub(double a, double b)
// inputs are checked for NaN is still a, b, c.
inline double NI_madd(double a, double c, double b)
{
double t = a * c;
if (std::isnan(t))
{
if (std::isnan(a)) return MakeQuiet(a);
if (std::isnan(b)) return MakeQuiet(b); // !
if (std::isnan(c)) return MakeQuiet(c);
SetFPException(FPSCR_VXIMZ);
return PPC_NAN;
}
t += b;
if (std::isnan(t))
{
if (std::isnan(b)) return MakeQuiet(b);
SetFPException(FPSCR_VXISI);
return PPC_NAN;
}
return t;
double t = a * c;
if (std::isnan(t))
{
if (std::isnan(a))
return MakeQuiet(a);
if (std::isnan(b))
return MakeQuiet(b); // !
if (std::isnan(c))
return MakeQuiet(c);
SetFPException(FPSCR_VXIMZ);
return PPC_NAN;
}
t += b;
if (std::isnan(t))
{
if (std::isnan(b))
return MakeQuiet(b);
SetFPException(FPSCR_VXISI);
return PPC_NAN;
}
return t;
}
inline double NI_msub(double a, double c, double b)
{
double t = a * c;
if (std::isnan(t))
{
if (std::isnan(a)) return MakeQuiet(a);
if (std::isnan(b)) return MakeQuiet(b); // !
if (std::isnan(c)) return MakeQuiet(c);
SetFPException(FPSCR_VXIMZ);
return PPC_NAN;
}
double t = a * c;
if (std::isnan(t))
{
if (std::isnan(a))
return MakeQuiet(a);
if (std::isnan(b))
return MakeQuiet(b); // !
if (std::isnan(c))
return MakeQuiet(c);
SetFPException(FPSCR_VXIMZ);
return PPC_NAN;
}
t -= b;
if (std::isnan(t))
{
if (std::isnan(b)) return MakeQuiet(b);
SetFPException(FPSCR_VXISI);
return PPC_NAN;
}
return t;
t -= b;
if (std::isnan(t))
{
if (std::isnan(b))
return MakeQuiet(b);
SetFPException(FPSCR_VXISI);
return PPC_NAN;
}
return t;
}
// used by stfsXX instructions and ps_rsqrte
inline u32 ConvertToSingle(u64 x)
{
u32 exp = (x >> 52) & 0x7ff;
if (exp > 896 || (x & ~MathUtil::DOUBLE_SIGN) == 0)
{
return ((x >> 32) & 0xc0000000) | ((x >> 29) & 0x3fffffff);
}
else if (exp >= 874)
{
u32 t = (u32)(0x80000000 | ((x & MathUtil::DOUBLE_FRAC) >> 21));
t = t >> (905 - exp);
t |= (x >> 32) & 0x80000000;
return t;
}
else
{
// This is said to be undefined.
// The code is based on hardware tests.
return ((x >> 32) & 0xc0000000) | ((x >> 29) & 0x3fffffff);
}
u32 exp = (x >> 52) & 0x7ff;
if (exp > 896 || (x & ~MathUtil::DOUBLE_SIGN) == 0)
{
return ((x >> 32) & 0xc0000000) | ((x >> 29) & 0x3fffffff);
}
else if (exp >= 874)
{
u32 t = (u32)(0x80000000 | ((x & MathUtil::DOUBLE_FRAC) >> 21));
t = t >> (905 - exp);
t |= (x >> 32) & 0x80000000;
return t;
}
else
{
// This is said to be undefined.
// The code is based on hardware tests.
return ((x >> 32) & 0xc0000000) | ((x >> 29) & 0x3fffffff);
}
}
// used by psq_stXX operations.
inline u32 ConvertToSingleFTZ(u64 x)
{
u32 exp = (x >> 52) & 0x7ff;
if (exp > 896 || (x & ~MathUtil::DOUBLE_SIGN) == 0)
{
return ((x >> 32) & 0xc0000000) | ((x >> 29) & 0x3fffffff);
}
else
{
return (x >> 32) & 0x80000000;
}
u32 exp = (x >> 52) & 0x7ff;
if (exp > 896 || (x & ~MathUtil::DOUBLE_SIGN) == 0)
{
return ((x >> 32) & 0xc0000000) | ((x >> 29) & 0x3fffffff);
}
else
{
return (x >> 32) & 0x80000000;
}
}
inline u64 ConvertToDouble(u32 _x)
{
// This is a little-endian re-implementation of the algorithm described in
// the PowerPC Programming Environments Manual for loading single
// precision floating point numbers.
// See page 566 of http://www.freescale.com/files/product/doc/MPCFPE32B.pdf
// This is a little-endian re-implementation of the algorithm described in
// the PowerPC Programming Environments Manual for loading single
// precision floating point numbers.
// See page 566 of http://www.freescale.com/files/product/doc/MPCFPE32B.pdf
u64 x = _x;
u64 exp = (x >> 23) & 0xff;
u64 frac = x & 0x007fffff;
u64 x = _x;
u64 exp = (x >> 23) & 0xff;
u64 frac = x & 0x007fffff;
if (exp > 0 && exp < 255) // Normal number
{
u64 y = !(exp >> 7);
u64 z = y << 61 | y << 60 | y << 59;
return ((x & 0xc0000000) << 32) | z | ((x & 0x3fffffff) << 29);
}
else if (exp == 0 && frac != 0) // Subnormal number
{
exp = 1023 - 126;
do
{
frac <<= 1;
exp -= 1;
} while ((frac & 0x00800000) == 0);
if (exp > 0 && exp < 255) // Normal number
{
u64 y = !(exp >> 7);
u64 z = y << 61 | y << 60 | y << 59;
return ((x & 0xc0000000) << 32) | z | ((x & 0x3fffffff) << 29);
}
else if (exp == 0 && frac != 0) // Subnormal number
{
exp = 1023 - 126;
do
{
frac <<= 1;
exp -= 1;
} while ((frac & 0x00800000) == 0);
return ((x & 0x80000000) << 32) | (exp << 52) | ((frac & 0x007fffff) << 29);
}
else // QNaN, SNaN or Zero
{
u64 y = exp >> 7;
u64 z = y << 61 | y << 60 | y << 59;
return ((x & 0xc0000000) << 32) | z | ((x & 0x3fffffff) << 29);
}
return ((x & 0x80000000) << 32) | (exp << 52) | ((frac & 0x007fffff) << 29);
}
else // QNaN, SNaN or Zero
{
u64 y = exp >> 7;
u64 z = y << 61 | y << 60 | y << 59;
return ((x & 0xc0000000) << 32) | z | ((x & 0x3fffffff) << 29);
}
}
@@ -7,9 +7,9 @@
#include "Common/CommonTypes.h"
#include "Common/MathUtil.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/PowerPC/Interpreter/Interpreter.h"
#include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h"
#include "Core/PowerPC/PowerPC.h"
using namespace MathUtil;
@@ -17,256 +17,256 @@ using namespace MathUtil;
// Star Wars : Rogue Leader spams that at some point :|
void Interpreter::Helper_UpdateCR1()
{
SetCRField(1, (FPSCR.FX << 3) | (FPSCR.FEX << 2) | (FPSCR.VX << 1) | FPSCR.OX);
SetCRField(1, (FPSCR.FX << 3) | (FPSCR.FEX << 2) | (FPSCR.VX << 1) | FPSCR.OX);
}
void Interpreter::Helper_FloatCompareOrdered(UGeckoInstruction _inst, double fa, double fb)
{
int compareResult;
int compareResult;
if (std::isnan(fa) || std::isnan(fb))
{
compareResult = FPCC::FU;
if (IsSNAN(fa) || IsSNAN(fb))
{
SetFPException(FPSCR_VXSNAN);
if (FPSCR.VE == 0)
{
SetFPException(FPSCR_VXVC);
}
}
else // QNaN
{
SetFPException(FPSCR_VXVC);
}
}
else if (fa < fb)
{
compareResult = FPCC::FL;
}
else if (fa > fb)
{
compareResult = FPCC::FG;
}
else // Equals
{
compareResult = FPCC::FE;
}
if (std::isnan(fa) || std::isnan(fb))
{
compareResult = FPCC::FU;
if (IsSNAN(fa) || IsSNAN(fb))
{
SetFPException(FPSCR_VXSNAN);
if (FPSCR.VE == 0)
{
SetFPException(FPSCR_VXVC);
}
}
else // QNaN
{
SetFPException(FPSCR_VXVC);
}
}
else if (fa < fb)
{
compareResult = FPCC::FL;
}
else if (fa > fb)
{
compareResult = FPCC::FG;
}
else // Equals
{
compareResult = FPCC::FE;
}
// Clear and set the FPCC bits accordingly.
FPSCR.FPRF = (FPSCR.FPRF & ~0xF) | compareResult;
// Clear and set the FPCC bits accordingly.
FPSCR.FPRF = (FPSCR.FPRF & ~0xF) | compareResult;
SetCRField(_inst.CRFD, compareResult);
SetCRField(_inst.CRFD, compareResult);
}
void Interpreter::Helper_FloatCompareUnordered(UGeckoInstruction _inst, double fa, double fb)
{
int compareResult;
int compareResult;
if (std::isnan(fa) || std::isnan(fb))
{
compareResult = FPCC::FU;
if (std::isnan(fa) || std::isnan(fb))
{
compareResult = FPCC::FU;
if (IsSNAN(fa) || IsSNAN(fb))
{
SetFPException(FPSCR_VXSNAN);
}
}
else if (fa < fb)
{
compareResult = FPCC::FL;
}
else if (fa > fb)
{
compareResult = FPCC::FG;
}
else // Equals
{
compareResult = FPCC::FE;
}
if (IsSNAN(fa) || IsSNAN(fb))
{
SetFPException(FPSCR_VXSNAN);
}
}
else if (fa < fb)
{
compareResult = FPCC::FL;
}
else if (fa > fb)
{
compareResult = FPCC::FG;
}
else // Equals
{
compareResult = FPCC::FE;
}
// Clear and set the FPCC bits accordingly.
FPSCR.FPRF = (FPSCR.FPRF & ~0xF) | compareResult;
// Clear and set the FPCC bits accordingly.
FPSCR.FPRF = (FPSCR.FPRF & ~0xF) | compareResult;
SetCRField(_inst.CRFD, compareResult);
SetCRField(_inst.CRFD, compareResult);
}
void Interpreter::fcmpo(UGeckoInstruction _inst)
{
Helper_FloatCompareOrdered(_inst, rPS0(_inst.FA), rPS0(_inst.FB));
Helper_FloatCompareOrdered(_inst, rPS0(_inst.FA), rPS0(_inst.FB));
}
void Interpreter::fcmpu(UGeckoInstruction _inst)
{
Helper_FloatCompareUnordered(_inst, rPS0(_inst.FA), rPS0(_inst.FB));
Helper_FloatCompareUnordered(_inst, rPS0(_inst.FA), rPS0(_inst.FB));
}
// Apply current rounding mode
void Interpreter::fctiwx(UGeckoInstruction _inst)
{
const double b = rPS0(_inst.FB);
u32 value;
const double b = rPS0(_inst.FB);
u32 value;
if (b > (double)0x7fffffff)
{
value = 0x7fffffff;
SetFPException(FPSCR_VXCVI);
FPSCR.FI = 0;
FPSCR.FR = 0;
}
else if (b < -(double)0x80000000)
{
value = 0x80000000;
SetFPException(FPSCR_VXCVI);
FPSCR.FI = 0;
FPSCR.FR = 0;
}
else
{
s32 i = 0;
switch (FPSCR.RN)
{
case 0: // nearest
{
double t = b + 0.5;
i = (s32)t;
if (b > (double)0x7fffffff)
{
value = 0x7fffffff;
SetFPException(FPSCR_VXCVI);
FPSCR.FI = 0;
FPSCR.FR = 0;
}
else if (b < -(double)0x80000000)
{
value = 0x80000000;
SetFPException(FPSCR_VXCVI);
FPSCR.FI = 0;
FPSCR.FR = 0;
}
else
{
s32 i = 0;
switch (FPSCR.RN)
{
case 0: // nearest
{
double t = b + 0.5;
i = (s32)t;
if (t - i < 0 || (t - i == 0 && b > 0))
{
i--;
}
break;
}
case 1: // zero
i = (s32)b;
break;
case 2: // +inf
i = (s32)b;
if (b - i > 0)
{
i++;
}
break;
case 3: // -inf
i = (s32)b;
if (b - i < 0)
{
i--;
}
break;
}
value = (u32)i;
double di = i;
if (di == b)
{
FPSCR.FI = 0;
FPSCR.FR = 0;
}
else
{
SetFI(1);
FPSCR.FR = fabs(di) > fabs(b);
}
}
if (t - i < 0 || (t - i == 0 && b > 0))
{
i--;
}
break;
}
case 1: // zero
i = (s32)b;
break;
case 2: // +inf
i = (s32)b;
if (b - i > 0)
{
i++;
}
break;
case 3: // -inf
i = (s32)b;
if (b - i < 0)
{
i--;
}
break;
}
value = (u32)i;
double di = i;
if (di == b)
{
FPSCR.FI = 0;
FPSCR.FR = 0;
}
else
{
SetFI(1);
FPSCR.FR = fabs(di) > fabs(b);
}
}
// based on HW tests
// FPRF is not affected
riPS0(_inst.FD) = 0xfff8000000000000ull | value;
if (value == 0 && std::signbit(b))
riPS0(_inst.FD) |= 0x100000000ull;
if (_inst.Rc)
Helper_UpdateCR1();
// based on HW tests
// FPRF is not affected
riPS0(_inst.FD) = 0xfff8000000000000ull | value;
if (value == 0 && std::signbit(b))
riPS0(_inst.FD) |= 0x100000000ull;
if (_inst.Rc)
Helper_UpdateCR1();
}
// Always round toward zero
void Interpreter::fctiwzx(UGeckoInstruction _inst)
{
const double b = rPS0(_inst.FB);
u32 value;
const double b = rPS0(_inst.FB);
u32 value;
if (b > (double)0x7fffffff)
{
value = 0x7fffffff;
SetFPException(FPSCR_VXCVI);
FPSCR.FI = 0;
FPSCR.FR = 0;
}
else if (b < -(double)0x80000000)
{
value = 0x80000000;
SetFPException(FPSCR_VXCVI);
FPSCR.FI = 0;
FPSCR.FR = 0;
}
else
{
s32 i = (s32)b;
double di = i;
if (di == b)
{
FPSCR.FI = 0;
FPSCR.FR = 0;
}
else
{
SetFI(1);
FPSCR.FR = fabs(di) > fabs(b);
}
value = (u32)i;
}
if (b > (double)0x7fffffff)
{
value = 0x7fffffff;
SetFPException(FPSCR_VXCVI);
FPSCR.FI = 0;
FPSCR.FR = 0;
}
else if (b < -(double)0x80000000)
{
value = 0x80000000;
SetFPException(FPSCR_VXCVI);
FPSCR.FI = 0;
FPSCR.FR = 0;
}
else
{
s32 i = (s32)b;
double di = i;
if (di == b)
{
FPSCR.FI = 0;
FPSCR.FR = 0;
}
else
{
SetFI(1);
FPSCR.FR = fabs(di) > fabs(b);
}
value = (u32)i;
}
// based on HW tests
// FPRF is not affected
riPS0(_inst.FD) = 0xfff8000000000000ull | value;
if (value == 0 && std::signbit(b))
riPS0(_inst.FD) |= 0x100000000ull;
if (_inst.Rc)
Helper_UpdateCR1();
// based on HW tests
// FPRF is not affected
riPS0(_inst.FD) = 0xfff8000000000000ull | value;
if (value == 0 && std::signbit(b))
riPS0(_inst.FD) |= 0x100000000ull;
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fmrx(UGeckoInstruction _inst)
{
riPS0(_inst.FD) = riPS0(_inst.FB);
riPS0(_inst.FD) = riPS0(_inst.FB);
// This is a binary instruction. Does not alter FPSCR
if (_inst.Rc)
Helper_UpdateCR1();
// This is a binary instruction. Does not alter FPSCR
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fabsx(UGeckoInstruction _inst)
{
rPS0(_inst.FD) = fabs(rPS0(_inst.FB));
rPS0(_inst.FD) = fabs(rPS0(_inst.FB));
// This is a binary instruction. Does not alter FPSCR
if (_inst.Rc)
Helper_UpdateCR1();
// This is a binary instruction. Does not alter FPSCR
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fnabsx(UGeckoInstruction _inst)
{
riPS0(_inst.FD) = riPS0(_inst.FB) | (1ULL << 63);
riPS0(_inst.FD) = riPS0(_inst.FB) | (1ULL << 63);
// This is a binary instruction. Does not alter FPSCR
if (_inst.Rc)
Helper_UpdateCR1();
// This is a binary instruction. Does not alter FPSCR
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fnegx(UGeckoInstruction _inst)
{
riPS0(_inst.FD) = riPS0(_inst.FB) ^ (1ULL << 63);
riPS0(_inst.FD) = riPS0(_inst.FB) ^ (1ULL << 63);
// This is a binary instruction. Does not alter FPSCR
if (_inst.Rc)
Helper_UpdateCR1();
// This is a binary instruction. Does not alter FPSCR
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fselx(UGeckoInstruction _inst)
{
rPS0(_inst.FD) = (rPS0(_inst.FA) >= -0.0) ? rPS0(_inst.FC) : rPS0(_inst.FB);
rPS0(_inst.FD) = (rPS0(_inst.FA) >= -0.0) ? rPS0(_inst.FC) : rPS0(_inst.FB);
// This is a binary instruction. Does not alter FPSCR
if (_inst.Rc)
Helper_UpdateCR1();
// This is a binary instruction. Does not alter FPSCR
if (_inst.Rc)
Helper_UpdateCR1();
}
// !!! warning !!!
@@ -274,213 +274,211 @@ void Interpreter::fselx(UGeckoInstruction _inst)
// PS1 is said to be undefined
void Interpreter::frspx(UGeckoInstruction inst) // round to single
{
double b = rPS0(inst.FB);
double rounded = ForceSingle(b);
SetFI(b != rounded);
FPSCR.FR = fabs(rounded) > fabs(b);
UpdateFPRF(rounded);
rPS0(inst.FD) = rPS1(inst.FD) = rounded;
double b = rPS0(inst.FB);
double rounded = ForceSingle(b);
SetFI(b != rounded);
FPSCR.FR = fabs(rounded) > fabs(b);
UpdateFPRF(rounded);
rPS0(inst.FD) = rPS1(inst.FD) = rounded;
if (inst.Rc)
Helper_UpdateCR1();
if (inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fmulx(UGeckoInstruction _inst)
{
rPS0(_inst.FD) = ForceDouble(NI_mul(rPS0(_inst.FA), rPS0(_inst.FC)));
FPSCR.FI = 0; // are these flags important?
FPSCR.FR = 0;
UpdateFPRF(rPS0(_inst.FD));
rPS0(_inst.FD) = ForceDouble(NI_mul(rPS0(_inst.FA), rPS0(_inst.FC)));
FPSCR.FI = 0; // are these flags important?
FPSCR.FR = 0;
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fmulsx(UGeckoInstruction _inst)
{
double c_value = Force25Bit(rPS0(_inst.FC));
double d_value = NI_mul(rPS0(_inst.FA), c_value);
rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(d_value);
//FPSCR.FI = d_value != rPS0(_inst.FD);
FPSCR.FI = 0;
FPSCR.FR = 0;
UpdateFPRF(rPS0(_inst.FD));
double c_value = Force25Bit(rPS0(_inst.FC));
double d_value = NI_mul(rPS0(_inst.FA), c_value);
rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(d_value);
// FPSCR.FI = d_value != rPS0(_inst.FD);
FPSCR.FI = 0;
FPSCR.FR = 0;
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fmaddx(UGeckoInstruction _inst)
{
double result = ForceDouble(NI_madd(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB)));
rPS0(_inst.FD) = result;
UpdateFPRF(result);
double result = ForceDouble(NI_madd(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB)));
rPS0(_inst.FD) = result;
UpdateFPRF(result);
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fmaddsx(UGeckoInstruction _inst)
{
double c_value = Force25Bit(rPS0(_inst.FC));
double d_value = NI_madd(rPS0(_inst.FA), c_value, rPS0(_inst.FB));
rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(d_value);
FPSCR.FI = d_value != rPS0(_inst.FD);
FPSCR.FR = 0;
UpdateFPRF(rPS0(_inst.FD));
double c_value = Force25Bit(rPS0(_inst.FC));
double d_value = NI_madd(rPS0(_inst.FA), c_value, rPS0(_inst.FB));
rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(d_value);
FPSCR.FI = d_value != rPS0(_inst.FD);
FPSCR.FR = 0;
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::faddx(UGeckoInstruction _inst)
{
rPS0(_inst.FD) = ForceDouble(NI_add(rPS0(_inst.FA), rPS0(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
rPS0(_inst.FD) = ForceDouble(NI_add(rPS0(_inst.FA), rPS0(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::faddsx(UGeckoInstruction _inst)
{
rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_add(rPS0(_inst.FA), rPS0(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_add(rPS0(_inst.FA), rPS0(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fdivx(UGeckoInstruction _inst)
{
rPS0(_inst.FD) = ForceDouble(NI_div(rPS0(_inst.FA), rPS0(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
rPS0(_inst.FD) = ForceDouble(NI_div(rPS0(_inst.FA), rPS0(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
// FR,FI,OX,UX???
if (_inst.Rc)
Helper_UpdateCR1();
// FR,FI,OX,UX???
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fdivsx(UGeckoInstruction _inst)
{
rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_div(rPS0(_inst.FA), rPS0(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_div(rPS0(_inst.FA), rPS0(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
// Single precision only.
void Interpreter::fresx(UGeckoInstruction _inst)
{
double b = rPS0(_inst.FB);
rPS0(_inst.FD) = rPS1(_inst.FD) = ApproximateReciprocal(b);
double b = rPS0(_inst.FB);
rPS0(_inst.FD) = rPS1(_inst.FD) = ApproximateReciprocal(b);
if (b == 0.0)
{
SetFPException(FPSCR_ZX);
}
if (b == 0.0)
{
SetFPException(FPSCR_ZX);
}
UpdateFPRF(rPS0(_inst.FD));
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::frsqrtex(UGeckoInstruction _inst)
{
double b = rPS0(_inst.FB);
double b = rPS0(_inst.FB);
if (b < 0.0)
{
SetFPException(FPSCR_VXSQRT);
}
else if (b == 0.0)
{
SetFPException(FPSCR_ZX);
}
if (b < 0.0)
{
SetFPException(FPSCR_VXSQRT);
}
else if (b == 0.0)
{
SetFPException(FPSCR_ZX);
}
rPS0(_inst.FD) = ApproximateReciprocalSquareRoot(b);
UpdateFPRF(rPS0(_inst.FD));
rPS0(_inst.FD) = ApproximateReciprocalSquareRoot(b);
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fmsubx(UGeckoInstruction _inst)
{
rPS0(_inst.FD) = ForceDouble(NI_msub(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
rPS0(_inst.FD) = ForceDouble(NI_msub(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fmsubsx(UGeckoInstruction _inst)
{
double c_value = Force25Bit(rPS0(_inst.FC));
rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_msub(rPS0(_inst.FA), c_value, rPS0(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
double c_value = Force25Bit(rPS0(_inst.FC));
rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_msub(rPS0(_inst.FA), c_value, rPS0(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fnmaddx(UGeckoInstruction _inst)
{
double result = ForceDouble(NI_madd(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB)));
rPS0(_inst.FD) = std::isnan(result) ? result : -result;
UpdateFPRF(rPS0(_inst.FD));
double result = ForceDouble(NI_madd(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB)));
rPS0(_inst.FD) = std::isnan(result) ? result : -result;
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fnmaddsx(UGeckoInstruction _inst)
{
double c_value = Force25Bit(rPS0(_inst.FC));
double result = ForceSingle(NI_madd(rPS0(_inst.FA), c_value, rPS0(_inst.FB)));
rPS0(_inst.FD) = rPS1(_inst.FD) = std::isnan(result) ? result : -result;
UpdateFPRF(rPS0(_inst.FD));
double c_value = Force25Bit(rPS0(_inst.FC));
double result = ForceSingle(NI_madd(rPS0(_inst.FA), c_value, rPS0(_inst.FB)));
rPS0(_inst.FD) = rPS1(_inst.FD) = std::isnan(result) ? result : -result;
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fnmsubx(UGeckoInstruction _inst)
{
double result = ForceDouble(NI_msub(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB)));
rPS0(_inst.FD) = std::isnan(result) ? result : -result;
UpdateFPRF(rPS0(_inst.FD));
double result = ForceDouble(NI_msub(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB)));
rPS0(_inst.FD) = std::isnan(result) ? result : -result;
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fnmsubsx(UGeckoInstruction _inst)
{
double c_value = Force25Bit(rPS0(_inst.FC));
double result = ForceSingle(NI_msub(rPS0(_inst.FA), c_value, rPS0(_inst.FB)));
rPS0(_inst.FD) = rPS1(_inst.FD) = std::isnan(result) ? result : -result;
UpdateFPRF(rPS0(_inst.FD));
double c_value = Force25Bit(rPS0(_inst.FC));
double result = ForceSingle(NI_msub(rPS0(_inst.FA), c_value, rPS0(_inst.FB)));
rPS0(_inst.FD) = rPS1(_inst.FD) = std::isnan(result) ? result : -result;
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fsubx(UGeckoInstruction _inst)
{
rPS0(_inst.FD) = ForceDouble(NI_sub(rPS0(_inst.FA), rPS0(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
rPS0(_inst.FD) = ForceDouble(NI_sub(rPS0(_inst.FA), rPS0(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::fsubsx(UGeckoInstruction _inst)
{
rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_sub(rPS0(_inst.FA), rPS0(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
rPS0(_inst.FD) = rPS1(_inst.FD) = ForceSingle(NI_sub(rPS0(_inst.FA), rPS0(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -9,347 +9,360 @@
#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "Common/MathUtil.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/PowerPC/Interpreter/Interpreter.h"
#include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h"
#include "Core/PowerPC/PowerPC.h"
// dequantize table
const float m_dequantizeTable[] =
{
1.0 / (1ULL << 0), 1.0 / (1ULL << 1), 1.0 / (1ULL << 2), 1.0 / (1ULL << 3),
1.0 / (1ULL << 4), 1.0 / (1ULL << 5), 1.0 / (1ULL << 6), 1.0 / (1ULL << 7),
1.0 / (1ULL << 8), 1.0 / (1ULL << 9), 1.0 / (1ULL << 10), 1.0 / (1ULL << 11),
1.0 / (1ULL << 12), 1.0 / (1ULL << 13), 1.0 / (1ULL << 14), 1.0 / (1ULL << 15),
1.0 / (1ULL << 16), 1.0 / (1ULL << 17), 1.0 / (1ULL << 18), 1.0 / (1ULL << 19),
1.0 / (1ULL << 20), 1.0 / (1ULL << 21), 1.0 / (1ULL << 22), 1.0 / (1ULL << 23),
1.0 / (1ULL << 24), 1.0 / (1ULL << 25), 1.0 / (1ULL << 26), 1.0 / (1ULL << 27),
1.0 / (1ULL << 28), 1.0 / (1ULL << 29), 1.0 / (1ULL << 30), 1.0 / (1ULL << 31),
(1ULL << 32), (1ULL << 31), (1ULL << 30), (1ULL << 29),
(1ULL << 28), (1ULL << 27), (1ULL << 26), (1ULL << 25),
(1ULL << 24), (1ULL << 23), (1ULL << 22), (1ULL << 21),
(1ULL << 20), (1ULL << 19), (1ULL << 18), (1ULL << 17),
(1ULL << 16), (1ULL << 15), (1ULL << 14), (1ULL << 13),
(1ULL << 12), (1ULL << 11), (1ULL << 10), (1ULL << 9),
(1ULL << 8), (1ULL << 7), (1ULL << 6), (1ULL << 5),
(1ULL << 4), (1ULL << 3), (1ULL << 2), (1ULL << 1),
const float m_dequantizeTable[] = {
1.0 / (1ULL << 0), 1.0 / (1ULL << 1), 1.0 / (1ULL << 2), 1.0 / (1ULL << 3),
1.0 / (1ULL << 4), 1.0 / (1ULL << 5), 1.0 / (1ULL << 6), 1.0 / (1ULL << 7),
1.0 / (1ULL << 8), 1.0 / (1ULL << 9), 1.0 / (1ULL << 10), 1.0 / (1ULL << 11),
1.0 / (1ULL << 12), 1.0 / (1ULL << 13), 1.0 / (1ULL << 14), 1.0 / (1ULL << 15),
1.0 / (1ULL << 16), 1.0 / (1ULL << 17), 1.0 / (1ULL << 18), 1.0 / (1ULL << 19),
1.0 / (1ULL << 20), 1.0 / (1ULL << 21), 1.0 / (1ULL << 22), 1.0 / (1ULL << 23),
1.0 / (1ULL << 24), 1.0 / (1ULL << 25), 1.0 / (1ULL << 26), 1.0 / (1ULL << 27),
1.0 / (1ULL << 28), 1.0 / (1ULL << 29), 1.0 / (1ULL << 30), 1.0 / (1ULL << 31),
(1ULL << 32), (1ULL << 31), (1ULL << 30), (1ULL << 29),
(1ULL << 28), (1ULL << 27), (1ULL << 26), (1ULL << 25),
(1ULL << 24), (1ULL << 23), (1ULL << 22), (1ULL << 21),
(1ULL << 20), (1ULL << 19), (1ULL << 18), (1ULL << 17),
(1ULL << 16), (1ULL << 15), (1ULL << 14), (1ULL << 13),
(1ULL << 12), (1ULL << 11), (1ULL << 10), (1ULL << 9),
(1ULL << 8), (1ULL << 7), (1ULL << 6), (1ULL << 5),
(1ULL << 4), (1ULL << 3), (1ULL << 2), (1ULL << 1),
};
// quantize table
const float m_quantizeTable[] =
{
(1ULL << 0), (1ULL << 1), (1ULL << 2), (1ULL << 3),
(1ULL << 4), (1ULL << 5), (1ULL << 6), (1ULL << 7),
(1ULL << 8), (1ULL << 9), (1ULL << 10), (1ULL << 11),
(1ULL << 12), (1ULL << 13), (1ULL << 14), (1ULL << 15),
(1ULL << 16), (1ULL << 17), (1ULL << 18), (1ULL << 19),
(1ULL << 20), (1ULL << 21), (1ULL << 22), (1ULL << 23),
(1ULL << 24), (1ULL << 25), (1ULL << 26), (1ULL << 27),
(1ULL << 28), (1ULL << 29), (1ULL << 30), (1ULL << 31),
1.0 / (1ULL << 32), 1.0 / (1ULL << 31), 1.0 / (1ULL << 30), 1.0 / (1ULL << 29),
1.0 / (1ULL << 28), 1.0 / (1ULL << 27), 1.0 / (1ULL << 26), 1.0 / (1ULL << 25),
1.0 / (1ULL << 24), 1.0 / (1ULL << 23), 1.0 / (1ULL << 22), 1.0 / (1ULL << 21),
1.0 / (1ULL << 20), 1.0 / (1ULL << 19), 1.0 / (1ULL << 18), 1.0 / (1ULL << 17),
1.0 / (1ULL << 16), 1.0 / (1ULL << 15), 1.0 / (1ULL << 14), 1.0 / (1ULL << 13),
1.0 / (1ULL << 12), 1.0 / (1ULL << 11), 1.0 / (1ULL << 10), 1.0 / (1ULL << 9),
1.0 / (1ULL << 8), 1.0 / (1ULL << 7), 1.0 / (1ULL << 6), 1.0 / (1ULL << 5),
1.0 / (1ULL << 4), 1.0 / (1ULL << 3), 1.0 / (1ULL << 2), 1.0 / (1ULL << 1),
const float m_quantizeTable[] = {
(1ULL << 0), (1ULL << 1), (1ULL << 2), (1ULL << 3),
(1ULL << 4), (1ULL << 5), (1ULL << 6), (1ULL << 7),
(1ULL << 8), (1ULL << 9), (1ULL << 10), (1ULL << 11),
(1ULL << 12), (1ULL << 13), (1ULL << 14), (1ULL << 15),
(1ULL << 16), (1ULL << 17), (1ULL << 18), (1ULL << 19),
(1ULL << 20), (1ULL << 21), (1ULL << 22), (1ULL << 23),
(1ULL << 24), (1ULL << 25), (1ULL << 26), (1ULL << 27),
(1ULL << 28), (1ULL << 29), (1ULL << 30), (1ULL << 31),
1.0 / (1ULL << 32), 1.0 / (1ULL << 31), 1.0 / (1ULL << 30), 1.0 / (1ULL << 29),
1.0 / (1ULL << 28), 1.0 / (1ULL << 27), 1.0 / (1ULL << 26), 1.0 / (1ULL << 25),
1.0 / (1ULL << 24), 1.0 / (1ULL << 23), 1.0 / (1ULL << 22), 1.0 / (1ULL << 21),
1.0 / (1ULL << 20), 1.0 / (1ULL << 19), 1.0 / (1ULL << 18), 1.0 / (1ULL << 17),
1.0 / (1ULL << 16), 1.0 / (1ULL << 15), 1.0 / (1ULL << 14), 1.0 / (1ULL << 13),
1.0 / (1ULL << 12), 1.0 / (1ULL << 11), 1.0 / (1ULL << 10), 1.0 / (1ULL << 9),
1.0 / (1ULL << 8), 1.0 / (1ULL << 7), 1.0 / (1ULL << 6), 1.0 / (1ULL << 5),
1.0 / (1ULL << 4), 1.0 / (1ULL << 3), 1.0 / (1ULL << 2), 1.0 / (1ULL << 1),
};
template<typename SType> SType ScaleAndClamp(double ps, u32 stScale)
template <typename SType>
SType ScaleAndClamp(double ps, u32 stScale)
{
float convPS = (float)ps * m_quantizeTable[stScale];
float min = (float)std::numeric_limits<SType>::min();
float max = (float)std::numeric_limits<SType>::max();
float convPS = (float)ps * m_quantizeTable[stScale];
float min = (float)std::numeric_limits<SType>::min();
float max = (float)std::numeric_limits<SType>::max();
return (SType)MathUtil::Clamp(convPS, min, max);
return (SType)MathUtil::Clamp(convPS, min, max);
}
template<typename T> static T ReadUnpaired(u32 addr);
template <typename T>
static T ReadUnpaired(u32 addr);
template<> u8 ReadUnpaired<u8>(u32 addr)
template <>
u8 ReadUnpaired<u8>(u32 addr)
{
return PowerPC::Read_U8(addr);
return PowerPC::Read_U8(addr);
}
template<> u16 ReadUnpaired<u16>(u32 addr)
template <>
u16 ReadUnpaired<u16>(u32 addr)
{
return PowerPC::Read_U16(addr);
return PowerPC::Read_U16(addr);
}
template<> u32 ReadUnpaired<u32>(u32 addr)
template <>
u32 ReadUnpaired<u32>(u32 addr)
{
return PowerPC::Read_U32(addr);
return PowerPC::Read_U32(addr);
}
template<typename T> static std::pair<T, T> ReadPair(u32 addr);
template <typename T>
static std::pair<T, T> ReadPair(u32 addr);
template<> std::pair<u8, u8> ReadPair<u8>(u32 addr)
template <>
std::pair<u8, u8> ReadPair<u8>(u32 addr)
{
u16 val = PowerPC::Read_U16(addr);
return { (u8)(val >> 8), (u8)val };
u16 val = PowerPC::Read_U16(addr);
return {(u8)(val >> 8), (u8)val};
}
template<> std::pair<u16, u16> ReadPair<u16>(u32 addr)
template <>
std::pair<u16, u16> ReadPair<u16>(u32 addr)
{
u32 val = PowerPC::Read_U32(addr);
return { (u16)(val >> 16), (u16)val };
u32 val = PowerPC::Read_U32(addr);
return {(u16)(val >> 16), (u16)val};
}
template<> std::pair<u32, u32> ReadPair<u32>(u32 addr)
template <>
std::pair<u32, u32> ReadPair<u32>(u32 addr)
{
u64 val = PowerPC::Read_U64(addr);
return { (u32)(val >> 32), (u32)val };
u64 val = PowerPC::Read_U64(addr);
return {(u32)(val >> 32), (u32)val};
}
template<typename T> static void WriteUnpaired(T val, u32 addr);
template <typename T>
static void WriteUnpaired(T val, u32 addr);
template<> void WriteUnpaired<u8>(u8 val, u32 addr)
template <>
void WriteUnpaired<u8>(u8 val, u32 addr)
{
PowerPC::Write_U8(val, addr);
PowerPC::Write_U8(val, addr);
}
template<> void WriteUnpaired<u16>(u16 val, u32 addr)
template <>
void WriteUnpaired<u16>(u16 val, u32 addr)
{
PowerPC::Write_U16(val, addr);
PowerPC::Write_U16(val, addr);
}
template<> void WriteUnpaired<u32>(u32 val, u32 addr)
template <>
void WriteUnpaired<u32>(u32 val, u32 addr)
{
PowerPC::Write_U32(val, addr);
PowerPC::Write_U32(val, addr);
}
template<typename T> static void WritePair(T val1, T val2, u32 addr);
template <typename T>
static void WritePair(T val1, T val2, u32 addr);
template<> void WritePair<u8>(u8 val1, u8 val2, u32 addr)
template <>
void WritePair<u8>(u8 val1, u8 val2, u32 addr)
{
PowerPC::Write_U16(((u16)val1 << 8) | (u16)val2, addr);
PowerPC::Write_U16(((u16)val1 << 8) | (u16)val2, addr);
}
template<> void WritePair<u16>(u16 val1, u16 val2, u32 addr)
template <>
void WritePair<u16>(u16 val1, u16 val2, u32 addr)
{
PowerPC::Write_U32(((u32)val1 << 16) | (u32)val2, addr);
PowerPC::Write_U32(((u32)val1 << 16) | (u32)val2, addr);
}
template<> void WritePair<u32>(u32 val1, u32 val2, u32 addr)
template <>
void WritePair<u32>(u32 val1, u32 val2, u32 addr)
{
PowerPC::Write_U64(((u64)val1 << 32) | (u64)val2, addr);
PowerPC::Write_U64(((u64)val1 << 32) | (u64)val2, addr);
}
template<typename T>
template <typename T>
void QuantizeAndStore(double ps0, double ps1, u32 addr, u32 instW, u32 stScale)
{
typedef typename std::make_unsigned<T>::type U;
U convPS0 = (U)ScaleAndClamp<T>(ps0, stScale);
if (instW)
{
WriteUnpaired<U>(convPS0, addr);
}
else
{
U convPS1 = (U)ScaleAndClamp<T>(ps1, stScale);
WritePair<U>(convPS0, convPS1, addr);
}
typedef typename std::make_unsigned<T>::type U;
U convPS0 = (U)ScaleAndClamp<T>(ps0, stScale);
if (instW)
{
WriteUnpaired<U>(convPS0, addr);
}
else
{
U convPS1 = (U)ScaleAndClamp<T>(ps1, stScale);
WritePair<U>(convPS0, convPS1, addr);
}
}
void Interpreter::Helper_Quantize(u32 addr, u32 instI, u32 instRS, u32 instW)
{
const UGQR gqr(rSPR(SPR_GQR0 + instI));
const EQuantizeType stType = gqr.st_type;
const unsigned int stScale = gqr.st_scale;
const UGQR gqr(rSPR(SPR_GQR0 + instI));
const EQuantizeType stType = gqr.st_type;
const unsigned int stScale = gqr.st_scale;
double ps0 = rPS0(instRS);
double ps1 = rPS1(instRS);
switch (stType)
{
case QUANTIZE_FLOAT:
{
u32 convPS0 = ConvertToSingleFTZ(MathUtil::IntDouble(ps0).i);
if (instW)
{
WriteUnpaired<u32>(convPS0, addr);
}
else
{
u32 convPS1 = ConvertToSingleFTZ(MathUtil::IntDouble(ps1).i);
WritePair<u32>(convPS0, convPS1, addr);
}
break;
}
double ps0 = rPS0(instRS);
double ps1 = rPS1(instRS);
switch (stType)
{
case QUANTIZE_FLOAT:
{
u32 convPS0 = ConvertToSingleFTZ(MathUtil::IntDouble(ps0).i);
if (instW)
{
WriteUnpaired<u32>(convPS0, addr);
}
else
{
u32 convPS1 = ConvertToSingleFTZ(MathUtil::IntDouble(ps1).i);
WritePair<u32>(convPS0, convPS1, addr);
}
break;
}
case QUANTIZE_U8:
QuantizeAndStore<u8>(ps0, ps1, addr, instW, stScale);
break;
case QUANTIZE_U8:
QuantizeAndStore<u8>(ps0, ps1, addr, instW, stScale);
break;
case QUANTIZE_U16:
QuantizeAndStore<u16>(ps0, ps1, addr, instW, stScale);
break;
case QUANTIZE_U16:
QuantizeAndStore<u16>(ps0, ps1, addr, instW, stScale);
break;
case QUANTIZE_S8:
QuantizeAndStore<s8>(ps0, ps1, addr, instW, stScale);
break;
case QUANTIZE_S8:
QuantizeAndStore<s8>(ps0, ps1, addr, instW, stScale);
break;
case QUANTIZE_S16:
QuantizeAndStore<s16>(ps0, ps1, addr, instW, stScale);
break;
case QUANTIZE_S16:
QuantizeAndStore<s16>(ps0, ps1, addr, instW, stScale);
break;
case QUANTIZE_INVALID1:
case QUANTIZE_INVALID2:
case QUANTIZE_INVALID3:
_assert_msg_(POWERPC, 0, "PS dequantize - unknown type to read");
break;
}
case QUANTIZE_INVALID1:
case QUANTIZE_INVALID2:
case QUANTIZE_INVALID3:
_assert_msg_(POWERPC, 0, "PS dequantize - unknown type to read");
break;
}
}
template<typename T>
template <typename T>
std::pair<float, float> LoadAndDequantize(u32 addr, u32 instW, u32 ldScale)
{
typedef typename std::make_unsigned<T>::type U;
float ps0, ps1;
if (instW)
{
U value = ReadUnpaired<U>(addr);
ps0 = (float)(T)(value) * m_dequantizeTable[ldScale];
ps1 = 1.0f;
}
else
{
std::pair<U, U> value = ReadPair<U>(addr);
ps0 = (float)(T)(value.first) * m_dequantizeTable[ldScale];
ps1 = (float)(T)(value.second) * m_dequantizeTable[ldScale];
}
return { ps0, ps1 };
typedef typename std::make_unsigned<T>::type U;
float ps0, ps1;
if (instW)
{
U value = ReadUnpaired<U>(addr);
ps0 = (float)(T)(value)*m_dequantizeTable[ldScale];
ps1 = 1.0f;
}
else
{
std::pair<U, U> value = ReadPair<U>(addr);
ps0 = (float)(T)(value.first) * m_dequantizeTable[ldScale];
ps1 = (float)(T)(value.second) * m_dequantizeTable[ldScale];
}
return {ps0, ps1};
}
void Interpreter::Helper_Dequantize(u32 addr, u32 instI, u32 instRD, u32 instW)
{
UGQR gqr(rSPR(SPR_GQR0 + instI));
EQuantizeType ldType = gqr.ld_type;
unsigned int ldScale = gqr.ld_scale;
UGQR gqr(rSPR(SPR_GQR0 + instI));
EQuantizeType ldType = gqr.ld_type;
unsigned int ldScale = gqr.ld_scale;
float ps0 = 0.0f;
float ps1 = 0.0f;
float ps0 = 0.0f;
float ps1 = 0.0f;
switch (ldType)
{
case QUANTIZE_FLOAT:
if (instW)
{
u32 value = ReadUnpaired<u32>(addr);
ps0 = MathUtil::IntFloat(value).f;
ps1 = 1.0f;
}
else
{
std::pair<u32, u32> value = ReadPair<u32>(addr);
ps0 = MathUtil::IntFloat(value.first).f;
ps1 = MathUtil::IntFloat(value.second).f;
}
break;
switch (ldType)
{
case QUANTIZE_FLOAT:
if (instW)
{
u32 value = ReadUnpaired<u32>(addr);
ps0 = MathUtil::IntFloat(value).f;
ps1 = 1.0f;
}
else
{
std::pair<u32, u32> value = ReadPair<u32>(addr);
ps0 = MathUtil::IntFloat(value.first).f;
ps1 = MathUtil::IntFloat(value.second).f;
}
break;
case QUANTIZE_U8:
std::tie(ps0, ps1) = LoadAndDequantize<u8>(addr, instW, ldScale);
break;
case QUANTIZE_U8:
std::tie(ps0, ps1) = LoadAndDequantize<u8>(addr, instW, ldScale);
break;
case QUANTIZE_U16:
std::tie(ps0, ps1) = LoadAndDequantize<u16>(addr, instW, ldScale);
break;
case QUANTIZE_U16:
std::tie(ps0, ps1) = LoadAndDequantize<u16>(addr, instW, ldScale);
break;
case QUANTIZE_S8:
std::tie(ps0, ps1) = LoadAndDequantize<s8>(addr, instW, ldScale);
break;
case QUANTIZE_S8:
std::tie(ps0, ps1) = LoadAndDequantize<s8>(addr, instW, ldScale);
break;
case QUANTIZE_S16:
std::tie(ps0, ps1) = LoadAndDequantize<s16>(addr, instW, ldScale);
break;
case QUANTIZE_S16:
std::tie(ps0, ps1) = LoadAndDequantize<s16>(addr, instW, ldScale);
break;
case QUANTIZE_INVALID1:
case QUANTIZE_INVALID2:
case QUANTIZE_INVALID3:
_assert_msg_(POWERPC, 0, "PS dequantize - unknown type to read");
ps0 = 0.f;
ps1 = 0.f;
break;
}
case QUANTIZE_INVALID1:
case QUANTIZE_INVALID2:
case QUANTIZE_INVALID3:
_assert_msg_(POWERPC, 0, "PS dequantize - unknown type to read");
ps0 = 0.f;
ps1 = 0.f;
break;
}
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
rPS0(instRD) = ps0;
rPS1(instRD) = ps1;
rPS0(instRD) = ps0;
rPS1(instRD) = ps1;
}
void Interpreter::psq_l(UGeckoInstruction _inst)
{
const u32 EA = _inst.RA ?
(rGPR[_inst.RA] + _inst.SIMM_12) : (u32)_inst.SIMM_12;
Helper_Dequantize(EA, _inst.I, _inst.RD, _inst.W);
const u32 EA = _inst.RA ? (rGPR[_inst.RA] + _inst.SIMM_12) : (u32)_inst.SIMM_12;
Helper_Dequantize(EA, _inst.I, _inst.RD, _inst.W);
}
void Interpreter::psq_lu(UGeckoInstruction _inst)
{
const u32 EA = rGPR[_inst.RA] + _inst.SIMM_12;
Helper_Dequantize(EA, _inst.I, _inst.RD, _inst.W);
const u32 EA = rGPR[_inst.RA] + _inst.SIMM_12;
Helper_Dequantize(EA, _inst.I, _inst.RD, _inst.W);
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
rGPR[_inst.RA] = EA;
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
rGPR[_inst.RA] = EA;
}
void Interpreter::psq_st(UGeckoInstruction _inst)
{
const u32 EA = _inst.RA ?
(rGPR[_inst.RA] + _inst.SIMM_12) : (u32)_inst.SIMM_12;
Helper_Quantize(EA, _inst.I, _inst.RS, _inst.W);
const u32 EA = _inst.RA ? (rGPR[_inst.RA] + _inst.SIMM_12) : (u32)_inst.SIMM_12;
Helper_Quantize(EA, _inst.I, _inst.RS, _inst.W);
}
void Interpreter::psq_stu(UGeckoInstruction _inst)
{
const u32 EA = rGPR[_inst.RA] + _inst.SIMM_12;
Helper_Quantize(EA, _inst.I, _inst.RS, _inst.W);
const u32 EA = rGPR[_inst.RA] + _inst.SIMM_12;
Helper_Quantize(EA, _inst.I, _inst.RS, _inst.W);
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
rGPR[_inst.RA] = EA;
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
rGPR[_inst.RA] = EA;
}
void Interpreter::psq_lx(UGeckoInstruction _inst)
{
const u32 EA = _inst.RA ? (rGPR[_inst.RA] + rGPR[_inst.RB]) : rGPR[_inst.RB];
Helper_Dequantize(EA, _inst.Ix, _inst.RD, _inst.Wx);
const u32 EA = _inst.RA ? (rGPR[_inst.RA] + rGPR[_inst.RB]) : rGPR[_inst.RB];
Helper_Dequantize(EA, _inst.Ix, _inst.RD, _inst.Wx);
}
void Interpreter::psq_stx(UGeckoInstruction _inst)
{
const u32 EA = _inst.RA ? (rGPR[_inst.RA] + rGPR[_inst.RB]) : rGPR[_inst.RB];
Helper_Quantize(EA, _inst.Ix, _inst.RS, _inst.Wx);
const u32 EA = _inst.RA ? (rGPR[_inst.RA] + rGPR[_inst.RB]) : rGPR[_inst.RB];
Helper_Quantize(EA, _inst.Ix, _inst.RS, _inst.Wx);
}
void Interpreter::psq_lux(UGeckoInstruction _inst)
{
const u32 EA = rGPR[_inst.RA] + rGPR[_inst.RB];
Helper_Dequantize(EA, _inst.Ix, _inst.RD, _inst.Wx);
const u32 EA = rGPR[_inst.RA] + rGPR[_inst.RB];
Helper_Dequantize(EA, _inst.Ix, _inst.RD, _inst.Wx);
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
rGPR[_inst.RA] = EA;
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
rGPR[_inst.RA] = EA;
}
void Interpreter::psq_stux(UGeckoInstruction _inst)
{
const u32 EA = rGPR[_inst.RA] + rGPR[_inst.RB];
Helper_Quantize(EA, _inst.Ix, _inst.RS, _inst.Wx);
const u32 EA = rGPR[_inst.RA] + rGPR[_inst.RB];
Helper_Quantize(EA, _inst.Ix, _inst.RS, _inst.Wx);
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
rGPR[_inst.RA] = EA;
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
rGPR[_inst.RA] = EA;
}
@@ -6,334 +6,332 @@
#include "Common/CommonTypes.h"
#include "Common/MathUtil.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/PowerPC/Interpreter/Interpreter.h"
#include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h"
#include "Core/PowerPC/PowerPC.h"
using namespace MathUtil;
// These "binary instructions" do not alter FPSCR.
void Interpreter::ps_sel(UGeckoInstruction _inst)
{
rPS0(_inst.FD) = rPS0(_inst.FA) >= -0.0 ? rPS0(_inst.FC) : rPS0(_inst.FB);
rPS1(_inst.FD) = rPS1(_inst.FA) >= -0.0 ? rPS1(_inst.FC) : rPS1(_inst.FB);
rPS0(_inst.FD) = rPS0(_inst.FA) >= -0.0 ? rPS0(_inst.FC) : rPS0(_inst.FB);
rPS1(_inst.FD) = rPS1(_inst.FA) >= -0.0 ? rPS1(_inst.FC) : rPS1(_inst.FB);
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_neg(UGeckoInstruction _inst)
{
riPS0(_inst.FD) = riPS0(_inst.FB) ^ (1ULL << 63);
riPS1(_inst.FD) = riPS1(_inst.FB) ^ (1ULL << 63);
riPS0(_inst.FD) = riPS0(_inst.FB) ^ (1ULL << 63);
riPS1(_inst.FD) = riPS1(_inst.FB) ^ (1ULL << 63);
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_mr(UGeckoInstruction _inst)
{
rPS0(_inst.FD) = rPS0(_inst.FB);
rPS1(_inst.FD) = rPS1(_inst.FB);
rPS0(_inst.FD) = rPS0(_inst.FB);
rPS1(_inst.FD) = rPS1(_inst.FB);
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_nabs(UGeckoInstruction _inst)
{
riPS0(_inst.FD) = riPS0(_inst.FB) | (1ULL << 63);
riPS1(_inst.FD) = riPS1(_inst.FB) | (1ULL << 63);
riPS0(_inst.FD) = riPS0(_inst.FB) | (1ULL << 63);
riPS1(_inst.FD) = riPS1(_inst.FB) | (1ULL << 63);
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_abs(UGeckoInstruction _inst)
{
riPS0(_inst.FD) = riPS0(_inst.FB) & ~(1ULL << 63);
riPS1(_inst.FD) = riPS1(_inst.FB) & ~(1ULL << 63);
riPS0(_inst.FD) = riPS0(_inst.FB) & ~(1ULL << 63);
riPS1(_inst.FD) = riPS1(_inst.FB) & ~(1ULL << 63);
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
// These are just moves, double is OK.
void Interpreter::ps_merge00(UGeckoInstruction _inst)
{
double p0 = rPS0(_inst.FA);
double p1 = rPS0(_inst.FB);
rPS0(_inst.FD) = p0;
rPS1(_inst.FD) = p1;
double p0 = rPS0(_inst.FA);
double p1 = rPS0(_inst.FB);
rPS0(_inst.FD) = p0;
rPS1(_inst.FD) = p1;
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_merge01(UGeckoInstruction _inst)
{
double p0 = rPS0(_inst.FA);
double p1 = rPS1(_inst.FB);
rPS0(_inst.FD) = p0;
rPS1(_inst.FD) = p1;
double p0 = rPS0(_inst.FA);
double p1 = rPS1(_inst.FB);
rPS0(_inst.FD) = p0;
rPS1(_inst.FD) = p1;
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_merge10(UGeckoInstruction _inst)
{
double p0 = rPS1(_inst.FA);
double p1 = rPS0(_inst.FB);
rPS0(_inst.FD) = p0;
rPS1(_inst.FD) = p1;
double p0 = rPS1(_inst.FA);
double p1 = rPS0(_inst.FB);
rPS0(_inst.FD) = p0;
rPS1(_inst.FD) = p1;
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_merge11(UGeckoInstruction _inst)
{
double p0 = rPS1(_inst.FA);
double p1 = rPS1(_inst.FB);
rPS0(_inst.FD) = p0;
rPS1(_inst.FD) = p1;
double p0 = rPS1(_inst.FA);
double p1 = rPS1(_inst.FB);
rPS0(_inst.FD) = p0;
rPS1(_inst.FD) = p1;
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
// From here on, the real deal.
void Interpreter::ps_div(UGeckoInstruction _inst)
{
rPS0(_inst.FD) = ForceSingle(NI_div(rPS0(_inst.FA), rPS0(_inst.FB)));
rPS1(_inst.FD) = ForceSingle(NI_div(rPS1(_inst.FA), rPS1(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
rPS0(_inst.FD) = ForceSingle(NI_div(rPS0(_inst.FA), rPS0(_inst.FB)));
rPS1(_inst.FD) = ForceSingle(NI_div(rPS1(_inst.FA), rPS1(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_res(UGeckoInstruction _inst)
{
// this code is based on the real hardware tests
double a = rPS0(_inst.FB);
double b = rPS1(_inst.FB);
// this code is based on the real hardware tests
double a = rPS0(_inst.FB);
double b = rPS1(_inst.FB);
if (a == 0.0 || b == 0.0)
{
SetFPException(FPSCR_ZX);
}
if (a == 0.0 || b == 0.0)
{
SetFPException(FPSCR_ZX);
}
rPS0(_inst.FD) = ApproximateReciprocal(a);
rPS1(_inst.FD) = ApproximateReciprocal(b);
UpdateFPRF(rPS0(_inst.FD));
rPS0(_inst.FD) = ApproximateReciprocal(a);
rPS1(_inst.FD) = ApproximateReciprocal(b);
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_rsqrte(UGeckoInstruction _inst)
{
if (rPS0(_inst.FB) == 0.0 || rPS1(_inst.FB) == 0.0)
{
SetFPException(FPSCR_ZX);
}
if (rPS0(_inst.FB) == 0.0 || rPS1(_inst.FB) == 0.0)
{
SetFPException(FPSCR_ZX);
}
if (rPS0(_inst.FB) < 0.0 || rPS1(_inst.FB) < 0.0)
{
SetFPException(FPSCR_VXSQRT);
}
if (rPS0(_inst.FB) < 0.0 || rPS1(_inst.FB) < 0.0)
{
SetFPException(FPSCR_VXSQRT);
}
rPS0(_inst.FD) = ForceSingle(ApproximateReciprocalSquareRoot(rPS0(_inst.FB)));
rPS1(_inst.FD) = ForceSingle(ApproximateReciprocalSquareRoot(rPS1(_inst.FB)));
rPS0(_inst.FD) = ForceSingle(ApproximateReciprocalSquareRoot(rPS0(_inst.FB)));
rPS1(_inst.FD) = ForceSingle(ApproximateReciprocalSquareRoot(rPS1(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_sub(UGeckoInstruction _inst)
{
rPS0(_inst.FD) = ForceSingle(NI_sub(rPS0(_inst.FA), rPS0(_inst.FB)));
rPS1(_inst.FD) = ForceSingle(NI_sub(rPS1(_inst.FA), rPS1(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
rPS0(_inst.FD) = ForceSingle(NI_sub(rPS0(_inst.FA), rPS0(_inst.FB)));
rPS1(_inst.FD) = ForceSingle(NI_sub(rPS1(_inst.FA), rPS1(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_add(UGeckoInstruction _inst)
{
rPS0(_inst.FD) = ForceSingle(NI_add(rPS0(_inst.FA), rPS0(_inst.FB)));
rPS1(_inst.FD) = ForceSingle(NI_add(rPS1(_inst.FA), rPS1(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
rPS0(_inst.FD) = ForceSingle(NI_add(rPS0(_inst.FA), rPS0(_inst.FB)));
rPS1(_inst.FD) = ForceSingle(NI_add(rPS1(_inst.FA), rPS1(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_mul(UGeckoInstruction _inst)
{
double c0 = Force25Bit(rPS0(_inst.FC));
double c1 = Force25Bit(rPS1(_inst.FC));
rPS0(_inst.FD) = ForceSingle(NI_mul(rPS0(_inst.FA), c0));
rPS1(_inst.FD) = ForceSingle(NI_mul(rPS1(_inst.FA), c1));
UpdateFPRF(rPS0(_inst.FD));
double c0 = Force25Bit(rPS0(_inst.FC));
double c1 = Force25Bit(rPS1(_inst.FC));
rPS0(_inst.FD) = ForceSingle(NI_mul(rPS0(_inst.FA), c0));
rPS1(_inst.FD) = ForceSingle(NI_mul(rPS1(_inst.FA), c1));
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_msub(UGeckoInstruction _inst)
{
double c0 = Force25Bit(rPS0(_inst.FC));
double c1 = Force25Bit(rPS1(_inst.FC));
rPS0(_inst.FD) = ForceSingle(NI_msub(rPS0(_inst.FA), c0, rPS0(_inst.FB)));
rPS1(_inst.FD) = ForceSingle(NI_msub(rPS1(_inst.FA), c1, rPS1(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
double c0 = Force25Bit(rPS0(_inst.FC));
double c1 = Force25Bit(rPS1(_inst.FC));
rPS0(_inst.FD) = ForceSingle(NI_msub(rPS0(_inst.FA), c0, rPS0(_inst.FB)));
rPS1(_inst.FD) = ForceSingle(NI_msub(rPS1(_inst.FA), c1, rPS1(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_madd(UGeckoInstruction _inst)
{
double c0 = Force25Bit(rPS0(_inst.FC));
double c1 = Force25Bit(rPS1(_inst.FC));
rPS0(_inst.FD) = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB)));
rPS1(_inst.FD) = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
double c0 = Force25Bit(rPS0(_inst.FC));
double c1 = Force25Bit(rPS1(_inst.FC));
rPS0(_inst.FD) = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB)));
rPS1(_inst.FD) = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB)));
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_nmsub(UGeckoInstruction _inst)
{
double c0 = Force25Bit(rPS0(_inst.FC));
double c1 = Force25Bit(rPS1(_inst.FC));
double result0 = ForceSingle(NI_msub(rPS0(_inst.FA), c0, rPS0(_inst.FB)));
double result1 = ForceSingle(NI_msub(rPS1(_inst.FA), c1, rPS1(_inst.FB)));
rPS0(_inst.FD) = std::isnan(result0) ? result0 : -result0;
rPS1(_inst.FD) = std::isnan(result1) ? result1 : -result1;
UpdateFPRF(rPS0(_inst.FD));
double c0 = Force25Bit(rPS0(_inst.FC));
double c1 = Force25Bit(rPS1(_inst.FC));
double result0 = ForceSingle(NI_msub(rPS0(_inst.FA), c0, rPS0(_inst.FB)));
double result1 = ForceSingle(NI_msub(rPS1(_inst.FA), c1, rPS1(_inst.FB)));
rPS0(_inst.FD) = std::isnan(result0) ? result0 : -result0;
rPS1(_inst.FD) = std::isnan(result1) ? result1 : -result1;
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_nmadd(UGeckoInstruction _inst)
{
double c0 = Force25Bit(rPS0(_inst.FC));
double c1 = Force25Bit(rPS1(_inst.FC));
double result0 = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB)));
double result1 = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB)));
rPS0(_inst.FD) = std::isnan(result0) ? result0 : -result0;
rPS1(_inst.FD) = std::isnan(result1) ? result1 : -result1;
UpdateFPRF(rPS0(_inst.FD));
double c0 = Force25Bit(rPS0(_inst.FC));
double c1 = Force25Bit(rPS1(_inst.FC));
double result0 = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB)));
double result1 = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB)));
rPS0(_inst.FD) = std::isnan(result0) ? result0 : -result0;
rPS1(_inst.FD) = std::isnan(result1) ? result1 : -result1;
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_sum0(UGeckoInstruction _inst)
{
double p0 = ForceSingle(NI_add(rPS0(_inst.FA), rPS1(_inst.FB)));
double p1 = ForceSingle(rPS1(_inst.FC));
rPS0(_inst.FD) = p0;
rPS1(_inst.FD) = p1;
UpdateFPRF(rPS0(_inst.FD));
double p0 = ForceSingle(NI_add(rPS0(_inst.FA), rPS1(_inst.FB)));
double p1 = ForceSingle(rPS1(_inst.FC));
rPS0(_inst.FD) = p0;
rPS1(_inst.FD) = p1;
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_sum1(UGeckoInstruction _inst)
{
double p0 = ForceSingle(rPS0(_inst.FC));
double p1 = ForceSingle(NI_add(rPS0(_inst.FA), rPS1(_inst.FB)));
rPS0(_inst.FD) = p0;
rPS1(_inst.FD) = p1;
UpdateFPRF(rPS1(_inst.FD));
double p0 = ForceSingle(rPS0(_inst.FC));
double p1 = ForceSingle(NI_add(rPS0(_inst.FA), rPS1(_inst.FB)));
rPS0(_inst.FD) = p0;
rPS1(_inst.FD) = p1;
UpdateFPRF(rPS1(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_muls0(UGeckoInstruction _inst)
{
double c0 = Force25Bit(rPS0(_inst.FC));
double p0 = ForceSingle(NI_mul(rPS0(_inst.FA), c0));
double p1 = ForceSingle(NI_mul(rPS1(_inst.FA), c0));
rPS0(_inst.FD) = p0;
rPS1(_inst.FD) = p1;
UpdateFPRF(rPS0(_inst.FD));
double c0 = Force25Bit(rPS0(_inst.FC));
double p0 = ForceSingle(NI_mul(rPS0(_inst.FA), c0));
double p1 = ForceSingle(NI_mul(rPS1(_inst.FA), c0));
rPS0(_inst.FD) = p0;
rPS1(_inst.FD) = p1;
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_muls1(UGeckoInstruction _inst)
{
double c1 = Force25Bit(rPS1(_inst.FC));
double p0 = ForceSingle(NI_mul(rPS0(_inst.FA), c1));
double p1 = ForceSingle(NI_mul(rPS1(_inst.FA), c1));
rPS0(_inst.FD) = p0;
rPS1(_inst.FD) = p1;
UpdateFPRF(rPS0(_inst.FD));
double c1 = Force25Bit(rPS1(_inst.FC));
double p0 = ForceSingle(NI_mul(rPS0(_inst.FA), c1));
double p1 = ForceSingle(NI_mul(rPS1(_inst.FA), c1));
rPS0(_inst.FD) = p0;
rPS1(_inst.FD) = p1;
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_madds0(UGeckoInstruction _inst)
{
double c0 = Force25Bit(rPS0(_inst.FC));
double p0 = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB)));
double p1 = ForceSingle(NI_madd(rPS1(_inst.FA), c0, rPS1(_inst.FB)));
rPS0(_inst.FD) = p0;
rPS1(_inst.FD) = p1;
UpdateFPRF(rPS0(_inst.FD));
double c0 = Force25Bit(rPS0(_inst.FC));
double p0 = ForceSingle(NI_madd(rPS0(_inst.FA), c0, rPS0(_inst.FB)));
double p1 = ForceSingle(NI_madd(rPS1(_inst.FA), c0, rPS1(_inst.FB)));
rPS0(_inst.FD) = p0;
rPS1(_inst.FD) = p1;
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_madds1(UGeckoInstruction _inst)
{
double c1 = Force25Bit(rPS1(_inst.FC));
double p0 = ForceSingle(NI_madd(rPS0(_inst.FA), c1, rPS0(_inst.FB)));
double p1 = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB)));
rPS0(_inst.FD) = p0;
rPS1(_inst.FD) = p1;
UpdateFPRF(rPS0(_inst.FD));
double c1 = Force25Bit(rPS1(_inst.FC));
double p0 = ForceSingle(NI_madd(rPS0(_inst.FA), c1, rPS0(_inst.FB)));
double p1 = ForceSingle(NI_madd(rPS1(_inst.FA), c1, rPS1(_inst.FB)));
rPS0(_inst.FD) = p0;
rPS1(_inst.FD) = p1;
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc)
Helper_UpdateCR1();
if (_inst.Rc)
Helper_UpdateCR1();
}
void Interpreter::ps_cmpu0(UGeckoInstruction _inst)
{
Helper_FloatCompareUnordered(_inst, rPS0(_inst.FA), rPS0(_inst.FB));
Helper_FloatCompareUnordered(_inst, rPS0(_inst.FA), rPS0(_inst.FB));
}
void Interpreter::ps_cmpo0(UGeckoInstruction _inst)
{
Helper_FloatCompareOrdered(_inst, rPS0(_inst.FA), rPS0(_inst.FB));
Helper_FloatCompareOrdered(_inst, rPS0(_inst.FA), rPS0(_inst.FB));
}
void Interpreter::ps_cmpu1(UGeckoInstruction _inst)
{
Helper_FloatCompareUnordered(_inst, rPS1(_inst.FA), rPS1(_inst.FB));
Helper_FloatCompareUnordered(_inst, rPS1(_inst.FA), rPS1(_inst.FB));
}
void Interpreter::ps_cmpo1(UGeckoInstruction _inst)
{
Helper_FloatCompareOrdered(_inst, rPS1(_inst.FA), rPS1(_inst.FB));
Helper_FloatCompareOrdered(_inst, rPS1(_inst.FA), rPS1(_inst.FB));
}
// __________________________________________________________________________________________________
@@ -341,6 +339,6 @@ void Interpreter::ps_cmpo1(UGeckoInstruction _inst)
// TODO(ector) check docs
void Interpreter::dcbz_l(UGeckoInstruction _inst)
{
//FAKE: clear memory instead of clearing the cache block
PowerPC::ClearCacheLine(Helper_Get_EA_X(_inst) & (~31));
// FAKE: clear memory instead of clearing the cache block
PowerPC::ClearCacheLine(Helper_Get_EA_X(_inst) & (~31));
}
@@ -2,15 +2,15 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/PowerPC/Interpreter/Interpreter.h"
#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "Common/FPURoundMode.h"
#include "Common/Logging/Log.h"
#include "Core/HW/GPFifo.h"
#include "Core/HW/SystemTimers.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/PowerPC/Interpreter/Interpreter.h"
#include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h"
#include "Core/PowerPC/PowerPC.h"
/*
@@ -29,433 +29,432 @@ mffsx: 80036650 (huh?)
static void FPSCRtoFPUSettings(UReg_FPSCR fp)
{
FPURoundMode::SetRoundMode(fp.RN);
FPURoundMode::SetRoundMode(fp.RN);
if (fp.VE || fp.OE || fp.UE || fp.ZE || fp.XE)
{
//PanicAlert("FPSCR - exceptions enabled. Please report. VE=%i OE=%i UE=%i ZE=%i XE=%i",
// fp.VE, fp.OE, fp.UE, fp.ZE, fp.XE);
// Pokemon Colosseum does this. Gah.
}
if (fp.VE || fp.OE || fp.UE || fp.ZE || fp.XE)
{
// PanicAlert("FPSCR - exceptions enabled. Please report. VE=%i OE=%i UE=%i ZE=%i XE=%i",
// fp.VE, fp.OE, fp.UE, fp.ZE, fp.XE);
// Pokemon Colosseum does this. Gah.
}
// Set SSE rounding mode and denormal handling
FPURoundMode::SetSIMDMode(fp.RN, fp.NI);
// Set SSE rounding mode and denormal handling
FPURoundMode::SetSIMDMode(fp.RN, fp.NI);
}
void Interpreter::mtfsb0x(UGeckoInstruction _inst)
{
u32 b = 0x80000000 >> _inst.CRBD;
u32 b = 0x80000000 >> _inst.CRBD;
/*if (b & 0x9ff80700)
PanicAlert("mtfsb0 clears bit %d, PC=%x", _inst.CRBD, PC);*/
/*if (b & 0x9ff80700)
PanicAlert("mtfsb0 clears bit %d, PC=%x", _inst.CRBD, PC);*/
FPSCR.Hex &= ~b;
FPSCRtoFPUSettings(FPSCR);
FPSCR.Hex &= ~b;
FPSCRtoFPUSettings(FPSCR);
if (_inst.Rc)
PanicAlert("mtfsb0x: inst_.Rc");
if (_inst.Rc)
PanicAlert("mtfsb0x: inst_.Rc");
}
void Interpreter::mtfsb1x(UGeckoInstruction _inst)
{
// this instruction can affect FX
u32 b = 0x80000000 >> _inst.CRBD;
if (b & FPSCR_ANY_X)
SetFPException(b);
else
FPSCR.Hex |= b;
FPSCRtoFPUSettings(FPSCR);
// this instruction can affect FX
u32 b = 0x80000000 >> _inst.CRBD;
if (b & FPSCR_ANY_X)
SetFPException(b);
else
FPSCR.Hex |= b;
FPSCRtoFPUSettings(FPSCR);
if (_inst.Rc)
PanicAlert("mtfsb1x: inst_.Rc");
if (_inst.Rc)
PanicAlert("mtfsb1x: inst_.Rc");
}
void Interpreter::mtfsfix(UGeckoInstruction _inst)
{
u32 mask = (0xF0000000 >> (4 * _inst.CRFD));
u32 imm = (_inst.hex << 16) & 0xF0000000;
u32 mask = (0xF0000000 >> (4 * _inst.CRFD));
u32 imm = (_inst.hex << 16) & 0xF0000000;
/*u32 cleared = ~(imm >> (4 * _inst.CRFD)) & FPSCR.Hex & mask;
if (cleared & 0x9ff80700)
PanicAlert("mtfsfi clears %08x, PC=%x", cleared, PC);*/
/*u32 cleared = ~(imm >> (4 * _inst.CRFD)) & FPSCR.Hex & mask;
if (cleared & 0x9ff80700)
PanicAlert("mtfsfi clears %08x, PC=%x", cleared, PC);*/
FPSCR.Hex = (FPSCR.Hex & ~mask) | (imm >> (4 * _inst.CRFD));
FPSCR.Hex = (FPSCR.Hex & ~mask) | (imm >> (4 * _inst.CRFD));
FPSCRtoFPUSettings(FPSCR);
FPSCRtoFPUSettings(FPSCR);
if (_inst.Rc)
PanicAlert("mtfsfix: inst_.Rc");
if (_inst.Rc)
PanicAlert("mtfsfix: inst_.Rc");
}
void Interpreter::mtfsfx(UGeckoInstruction _inst)
{
u32 fm = _inst.FM;
u32 m = 0;
for (int i = 0; i < 8; i++)
{
if (fm & (1 << i))
m |= (0xF << (i * 4));
}
u32 fm = _inst.FM;
u32 m = 0;
for (int i = 0; i < 8; i++)
{
if (fm & (1 << i))
m |= (0xF << (i * 4));
}
/*u32 cleared = ~((u32)(riPS0(_inst.FB))) & FPSCR.Hex & m;
if (cleared & 0x9ff80700)
PanicAlert("mtfsf clears %08x, PC=%x", cleared, PC);*/
/*u32 cleared = ~((u32)(riPS0(_inst.FB))) & FPSCR.Hex & m;
if (cleared & 0x9ff80700)
PanicAlert("mtfsf clears %08x, PC=%x", cleared, PC);*/
FPSCR.Hex = (FPSCR.Hex & ~m) | ((u32)(riPS0(_inst.FB)) & m);
FPSCRtoFPUSettings(FPSCR);
FPSCR.Hex = (FPSCR.Hex & ~m) | ((u32)(riPS0(_inst.FB)) & m);
FPSCRtoFPUSettings(FPSCR);
if (_inst.Rc)
PanicAlert("mtfsfx: inst_.Rc");
if (_inst.Rc)
PanicAlert("mtfsfx: inst_.Rc");
}
void Interpreter::mcrxr(UGeckoInstruction _inst)
{
SetCRField(_inst.CRFD, GetXER().Hex >> 28);
PowerPC::ppcState.xer_ca = 0;
PowerPC::ppcState.xer_so_ov = 0;
SetCRField(_inst.CRFD, GetXER().Hex >> 28);
PowerPC::ppcState.xer_ca = 0;
PowerPC::ppcState.xer_so_ov = 0;
}
void Interpreter::mfcr(UGeckoInstruction _inst)
{
rGPR[_inst.RD] = GetCR();
rGPR[_inst.RD] = GetCR();
}
void Interpreter::mtcrf(UGeckoInstruction _inst)
{
u32 crm = _inst.CRM;
if (crm == 0xFF)
{
SetCR(rGPR[_inst.RS]);
}
else
{
//TODO: use lookup table? probably not worth it
u32 mask = 0;
for (int i = 0; i < 8; i++)
{
if (crm & (1 << i))
mask |= 0xF << (i*4);
}
u32 crm = _inst.CRM;
if (crm == 0xFF)
{
SetCR(rGPR[_inst.RS]);
}
else
{
// TODO: use lookup table? probably not worth it
u32 mask = 0;
for (int i = 0; i < 8; i++)
{
if (crm & (1 << i))
mask |= 0xF << (i * 4);
}
SetCR((GetCR() & ~mask) | (rGPR[_inst.RS] & mask));
}
SetCR((GetCR() & ~mask) | (rGPR[_inst.RS] & mask));
}
}
void Interpreter::mfmsr(UGeckoInstruction _inst)
{
//Privileged?
rGPR[_inst.RD] = MSR;
// Privileged?
rGPR[_inst.RD] = MSR;
}
void Interpreter::mfsr(UGeckoInstruction _inst)
{
rGPR[_inst.RD] = PowerPC::ppcState.sr[_inst.SR];
rGPR[_inst.RD] = PowerPC::ppcState.sr[_inst.SR];
}
void Interpreter::mfsrin(UGeckoInstruction _inst)
{
int index = (rGPR[_inst.RB] >> 28) & 0xF;
rGPR[_inst.RD] = PowerPC::ppcState.sr[index];
int index = (rGPR[_inst.RB] >> 28) & 0xF;
rGPR[_inst.RD] = PowerPC::ppcState.sr[index];
}
void Interpreter::mtmsr(UGeckoInstruction _inst)
{
// Privileged?
MSR = rGPR[_inst.RS];
PowerPC::CheckExceptions();
m_EndBlock = true;
// Privileged?
MSR = rGPR[_inst.RS];
PowerPC::CheckExceptions();
m_EndBlock = true;
}
// Segment registers. MMU control.
static void SetSR(int index, u32 value)
{
DEBUG_LOG(POWERPC, "%08x: MMU: Segment register %i set to %08x", PowerPC::ppcState.pc, index, value);
PowerPC::ppcState.sr[index] = value;
DEBUG_LOG(POWERPC, "%08x: MMU: Segment register %i set to %08x", PowerPC::ppcState.pc, index,
value);
PowerPC::ppcState.sr[index] = value;
}
void Interpreter::mtsr(UGeckoInstruction _inst)
{
int index = _inst.SR;
u32 value = rGPR[_inst.RS];
SetSR(index, value);
int index = _inst.SR;
u32 value = rGPR[_inst.RS];
SetSR(index, value);
}
void Interpreter::mtsrin(UGeckoInstruction _inst)
{
int index = (rGPR[_inst.RB] >> 28) & 0xF;
u32 value = rGPR[_inst.RS];
SetSR(index, value);
int index = (rGPR[_inst.RB] >> 28) & 0xF;
u32 value = rGPR[_inst.RS];
SetSR(index, value);
}
void Interpreter::mftb(UGeckoInstruction _inst)
{
int iIndex = (_inst.TBR >> 5) | ((_inst.TBR & 0x1F) << 5);
_dbg_assert_msg_(POWERPC, (iIndex == SPR_TL) || (iIndex == SPR_TU), "Invalid mftb");
(void)iIndex;
mfspr(_inst);
int iIndex = (_inst.TBR >> 5) | ((_inst.TBR & 0x1F) << 5);
_dbg_assert_msg_(POWERPC, (iIndex == SPR_TL) || (iIndex == SPR_TU), "Invalid mftb");
(void)iIndex;
mfspr(_inst);
}
void Interpreter::mfspr(UGeckoInstruction _inst)
{
u32 iIndex = ((_inst.SPR & 0x1F) << 5) + ((_inst.SPR >> 5) & 0x1F);
u32 iIndex = ((_inst.SPR & 0x1F) << 5) + ((_inst.SPR >> 5) & 0x1F);
//TODO - check processor privilege level - many of these require privilege
//XER LR CTR are the only ones available in user mode, time base can be read too.
//GameCube games always run in superuser mode, but hey....
// TODO - check processor privilege level - many of these require privilege
// XER LR CTR are the only ones available in user mode, time base can be read too.
// GameCube games always run in superuser mode, but hey....
switch (iIndex)
{
case SPR_DEC:
if ((rSPR(iIndex) & 0x80000000) == 0) // We are still decrementing
{
rSPR(iIndex) = SystemTimers::GetFakeDecrementer();
}
break;
switch (iIndex)
{
case SPR_DEC:
if ((rSPR(iIndex) & 0x80000000) == 0) // We are still decrementing
{
rSPR(iIndex) = SystemTimers::GetFakeDecrementer();
}
break;
case SPR_TL:
case SPR_TU:
*((u64 *)&TL) = SystemTimers::GetFakeTimeBase(); //works since we are little endian and TL comes first :)
break;
case SPR_TL:
case SPR_TU:
*((u64*)&TL) =
SystemTimers::GetFakeTimeBase(); // works since we are little endian and TL comes first :)
break;
case SPR_WPAR:
{
// TODO: If wpar_empty ever is false, Paper Mario hangs. Strange.
// Maybe WPAR is automatically flushed after a certain amount of time?
bool wpar_empty = true; //GPFifo::IsEmpty();
if (!wpar_empty)
rSPR(iIndex) |= 1; // BNE = buffer not empty
else
rSPR(iIndex) &= ~1;
}
break;
case SPR_XER:
rSPR(iIndex) = GetXER().Hex;
break;
}
rGPR[_inst.RD] = rSPR(iIndex);
case SPR_WPAR:
{
// TODO: If wpar_empty ever is false, Paper Mario hangs. Strange.
// Maybe WPAR is automatically flushed after a certain amount of time?
bool wpar_empty = true; // GPFifo::IsEmpty();
if (!wpar_empty)
rSPR(iIndex) |= 1; // BNE = buffer not empty
else
rSPR(iIndex) &= ~1;
}
break;
case SPR_XER:
rSPR(iIndex) = GetXER().Hex;
break;
}
rGPR[_inst.RD] = rSPR(iIndex);
}
void Interpreter::mtspr(UGeckoInstruction _inst)
{
u32 iIndex = (_inst.SPRU << 5) | (_inst.SPRL & 0x1F);
u32 oldValue = rSPR(iIndex);
rSPR(iIndex) = rGPR[_inst.RD];
u32 iIndex = (_inst.SPRU << 5) | (_inst.SPRL & 0x1F);
u32 oldValue = rSPR(iIndex);
rSPR(iIndex) = rGPR[_inst.RD];
//TODO - check processor privilege level - many of these require privilege
//XER LR CTR are the only ones available in user mode, time base can be read too.
//GameCube games always run in superuser mode, but hey....
// TODO - check processor privilege level - many of these require privilege
// XER LR CTR are the only ones available in user mode, time base can be read too.
// GameCube games always run in superuser mode, but hey....
//Our DMA emulation is highly inaccurate - instead of properly emulating the queue
//and so on, we simply make all DMA:s complete instantaneously.
// Our DMA emulation is highly inaccurate - instead of properly emulating the queue
// and so on, we simply make all DMA:s complete instantaneously.
switch (iIndex)
{
case SPR_TL:
case SPR_TU:
PanicAlert("Illegal Write to TL/TU");
break;
switch (iIndex)
{
case SPR_TL:
case SPR_TU:
PanicAlert("Illegal Write to TL/TU");
break;
case SPR_TL_W:
TL = rGPR[_inst.RD];
SystemTimers::TimeBaseSet();
break;
case SPR_TL_W:
TL = rGPR[_inst.RD];
SystemTimers::TimeBaseSet();
break;
case SPR_TU_W:
TU = rGPR[_inst.RD];
SystemTimers::TimeBaseSet();
break;
case SPR_TU_W:
TU = rGPR[_inst.RD];
SystemTimers::TimeBaseSet();
break;
case SPR_HID0: // HID0
{
UReg_HID0 old_hid0;
old_hid0.Hex = oldValue;
if (HID0.ICE != old_hid0.ICE)
{
INFO_LOG(POWERPC, "Instruction Cache Enable (HID0.ICE) = %d", (int)HID0.ICE);
}
if (HID0.ILOCK != old_hid0.ILOCK)
{
INFO_LOG(POWERPC, "Instruction Cache Lock (HID0.ILOCK) = %d", (int)HID0.ILOCK);
}
if (HID0.ICFI)
{
HID0.ICFI = 0;
INFO_LOG(POWERPC, "Flush Instruction Cache! ICE=%d", (int)HID0.ICE);
// this is rather slow
// most games do it only once during initialization
PowerPC::ppcState.iCache.Reset();
}
}
break;
case SPR_HID2: // HID2
// TODO: generate illegal instruction for paired inst if PSE or LSQE
// not set.
// TODO: disable write gather pipe if WPE not set
// TODO: emulate locked cache and DMA bits.
break;
case SPR_HID0: // HID0
{
UReg_HID0 old_hid0;
old_hid0.Hex = oldValue;
if (HID0.ICE != old_hid0.ICE)
{
INFO_LOG(POWERPC, "Instruction Cache Enable (HID0.ICE) = %d", (int)HID0.ICE);
}
if (HID0.ILOCK != old_hid0.ILOCK)
{
INFO_LOG(POWERPC, "Instruction Cache Lock (HID0.ILOCK) = %d", (int)HID0.ILOCK);
}
if (HID0.ICFI)
{
HID0.ICFI = 0;
INFO_LOG(POWERPC, "Flush Instruction Cache! ICE=%d", (int)HID0.ICE);
// this is rather slow
// most games do it only once during initialization
PowerPC::ppcState.iCache.Reset();
}
}
break;
case SPR_HID2: // HID2
// TODO: generate illegal instruction for paired inst if PSE or LSQE
// not set.
// TODO: disable write gather pipe if WPE not set
// TODO: emulate locked cache and DMA bits.
break;
case SPR_WPAR:
_assert_msg_(POWERPC, rGPR[_inst.RD] == 0x0C008000, "Gather pipe @ %08x", PC);
GPFifo::ResetGatherPipe();
break;
case SPR_WPAR:
_assert_msg_(POWERPC, rGPR[_inst.RD] == 0x0C008000, "Gather pipe @ %08x", PC);
GPFifo::ResetGatherPipe();
break;
// Graphics Quantization Registers
case SPR_GQR0:
case SPR_GQR0 + 1:
case SPR_GQR0 + 2:
case SPR_GQR0 + 3:
case SPR_GQR0 + 4:
case SPR_GQR0 + 5:
case SPR_GQR0 + 6:
case SPR_GQR0 + 7:
break;
// Graphics Quantization Registers
case SPR_GQR0:
case SPR_GQR0 + 1:
case SPR_GQR0 + 2:
case SPR_GQR0 + 3:
case SPR_GQR0 + 4:
case SPR_GQR0 + 5:
case SPR_GQR0 + 6:
case SPR_GQR0 + 7:
break;
case SPR_DMAL:
// Locked cache<->Memory DMA
// Total fake, we ignore that DMAs take time.
if (DMAL.DMA_T)
{
u32 dwMemAddress = DMAU.MEM_ADDR << 5;
u32 dwCacheAddress = DMAL.LC_ADDR << 5;
u32 iLength = ((DMAU.DMA_LEN_U << 2) | DMAL.DMA_LEN_L);
// INFO_LOG(POWERPC, "DMA: mem = %x, cache = %x, len = %u, LD = %d, PC=%x", dwMemAddress, dwCacheAddress, iLength, (int)DMAL.DMA_LD, PC);
if (iLength == 0)
iLength = 128;
if (DMAL.DMA_LD)
PowerPC::DMA_MemoryToLC(dwCacheAddress, dwMemAddress, iLength);
else
PowerPC::DMA_LCToMemory(dwMemAddress, dwCacheAddress, iLength);
}
DMAL.DMA_T = 0;
break;
case SPR_DMAL:
// Locked cache<->Memory DMA
// Total fake, we ignore that DMAs take time.
if (DMAL.DMA_T)
{
u32 dwMemAddress = DMAU.MEM_ADDR << 5;
u32 dwCacheAddress = DMAL.LC_ADDR << 5;
u32 iLength = ((DMAU.DMA_LEN_U << 2) | DMAL.DMA_LEN_L);
// INFO_LOG(POWERPC, "DMA: mem = %x, cache = %x, len = %u, LD = %d, PC=%x", dwMemAddress,
// dwCacheAddress, iLength, (int)DMAL.DMA_LD, PC);
if (iLength == 0)
iLength = 128;
if (DMAL.DMA_LD)
PowerPC::DMA_MemoryToLC(dwCacheAddress, dwMemAddress, iLength);
else
PowerPC::DMA_LCToMemory(dwMemAddress, dwCacheAddress, iLength);
}
DMAL.DMA_T = 0;
break;
case SPR_L2CR:
//PanicAlert("mtspr( L2CR )!");
break;
case SPR_L2CR:
// PanicAlert("mtspr( L2CR )!");
break;
case SPR_DEC:
if (!(oldValue >> 31) && (rGPR[_inst.RD]>>31)) //top bit from 0 to 1
{
PanicAlert("Interesting - Software triggered Decrementer exception");
PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER;
}
SystemTimers::DecrementerSet();
break;
case SPR_DEC:
if (!(oldValue >> 31) && (rGPR[_inst.RD] >> 31)) // top bit from 0 to 1
{
PanicAlert("Interesting - Software triggered Decrementer exception");
PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER;
}
SystemTimers::DecrementerSet();
break;
// Page table base etc
case SPR_SDR:
PowerPC::SDRUpdated();
break;
// Page table base etc
case SPR_SDR:
PowerPC::SDRUpdated();
break;
case SPR_XER:
SetXER(rSPR(iIndex));
break;
}
case SPR_XER:
SetXER(rSPR(iIndex));
break;
}
}
void Interpreter::crand(UGeckoInstruction _inst)
{
SetCRBit(_inst.CRBD, GetCRBit(_inst.CRBA) & GetCRBit(_inst.CRBB));
SetCRBit(_inst.CRBD, GetCRBit(_inst.CRBA) & GetCRBit(_inst.CRBB));
}
void Interpreter::crandc(UGeckoInstruction _inst)
{
SetCRBit(_inst.CRBD, GetCRBit(_inst.CRBA) & (1 ^ GetCRBit(_inst.CRBB)));
SetCRBit(_inst.CRBD, GetCRBit(_inst.CRBA) & (1 ^ GetCRBit(_inst.CRBB)));
}
void Interpreter::creqv(UGeckoInstruction _inst)
{
SetCRBit(_inst.CRBD, 1 ^ (GetCRBit(_inst.CRBA) ^ GetCRBit(_inst.CRBB)));
SetCRBit(_inst.CRBD, 1 ^ (GetCRBit(_inst.CRBA) ^ GetCRBit(_inst.CRBB)));
}
void Interpreter::crnand(UGeckoInstruction _inst)
{
SetCRBit(_inst.CRBD, 1 ^ (GetCRBit(_inst.CRBA) & GetCRBit(_inst.CRBB)));
SetCRBit(_inst.CRBD, 1 ^ (GetCRBit(_inst.CRBA) & GetCRBit(_inst.CRBB)));
}
void Interpreter::crnor(UGeckoInstruction _inst)
{
SetCRBit(_inst.CRBD, 1 ^ (GetCRBit(_inst.CRBA) | GetCRBit(_inst.CRBB)));
SetCRBit(_inst.CRBD, 1 ^ (GetCRBit(_inst.CRBA) | GetCRBit(_inst.CRBB)));
}
void Interpreter::cror(UGeckoInstruction _inst)
{
SetCRBit(_inst.CRBD, (GetCRBit(_inst.CRBA) | GetCRBit(_inst.CRBB)));
SetCRBit(_inst.CRBD, (GetCRBit(_inst.CRBA) | GetCRBit(_inst.CRBB)));
}
void Interpreter::crorc(UGeckoInstruction _inst)
{
SetCRBit(_inst.CRBD, (GetCRBit(_inst.CRBA) | (1 ^ GetCRBit(_inst.CRBB))));
SetCRBit(_inst.CRBD, (GetCRBit(_inst.CRBA) | (1 ^ GetCRBit(_inst.CRBB))));
}
void Interpreter::crxor(UGeckoInstruction _inst)
{
SetCRBit(_inst.CRBD, (GetCRBit(_inst.CRBA) ^ GetCRBit(_inst.CRBB)));
SetCRBit(_inst.CRBD, (GetCRBit(_inst.CRBA) ^ GetCRBit(_inst.CRBB)));
}
void Interpreter::mcrf(UGeckoInstruction _inst)
{
int cr_f = GetCRField(_inst.CRFS);
SetCRField(_inst.CRFD, cr_f);
int cr_f = GetCRField(_inst.CRFS);
SetCRField(_inst.CRFD, cr_f);
}
void Interpreter::isync(UGeckoInstruction _inst)
{
//shouldn't do anything
// shouldn't do anything
}
// the following commands read from FPSCR
void Interpreter::mcrfs(UGeckoInstruction _inst)
{
//if (_inst.CRFS != 3 && _inst.CRFS != 4)
// PanicAlert("msrfs at %x, CRFS = %d, CRFD = %d", PC, (int)_inst.CRFS, (int)_inst.CRFD);
// if (_inst.CRFS != 3 && _inst.CRFS != 4)
// PanicAlert("msrfs at %x, CRFS = %d, CRFD = %d", PC, (int)_inst.CRFS, (int)_inst.CRFD);
UpdateFPSCR();
u32 fpflags = ((FPSCR.Hex >> (4 * (7 - _inst.CRFS))) & 0xF);
switch (_inst.CRFS)
{
case 0:
FPSCR.FX = 0;
FPSCR.OX = 0;
break;
case 1:
FPSCR.UX = 0;
FPSCR.ZX = 0;
FPSCR.XX = 0;
FPSCR.VXSNAN = 0;
break;
case 2:
FPSCR.VXISI = 0;
FPSCR.VXIDI = 0;
FPSCR.VXZDZ = 0;
FPSCR.VXIMZ = 0;
break;
case 3:
FPSCR.VXVC = 0;
break;
case 5:
FPSCR.VXSOFT = 0;
FPSCR.VXSQRT = 0;
FPSCR.VXCVI = 0;
break;
}
SetCRField(_inst.CRFD, fpflags);
UpdateFPSCR();
u32 fpflags = ((FPSCR.Hex >> (4 * (7 - _inst.CRFS))) & 0xF);
switch (_inst.CRFS)
{
case 0:
FPSCR.FX = 0;
FPSCR.OX = 0;
break;
case 1:
FPSCR.UX = 0;
FPSCR.ZX = 0;
FPSCR.XX = 0;
FPSCR.VXSNAN = 0;
break;
case 2:
FPSCR.VXISI = 0;
FPSCR.VXIDI = 0;
FPSCR.VXZDZ = 0;
FPSCR.VXIMZ = 0;
break;
case 3:
FPSCR.VXVC = 0;
break;
case 5:
FPSCR.VXSOFT = 0;
FPSCR.VXSQRT = 0;
FPSCR.VXCVI = 0;
break;
}
SetCRField(_inst.CRFD, fpflags);
}
void Interpreter::mffsx(UGeckoInstruction _inst)
{
// load from FPSCR
// TODO(ector): grab all overflow flags etc and set them in FPSCR
// load from FPSCR
// TODO(ector): grab all overflow flags etc and set them in FPSCR
UpdateFPSCR();
riPS0(_inst.FD) = 0xFFF8000000000000 | FPSCR.Hex;
UpdateFPSCR();
riPS0(_inst.FD) = 0xFFF8000000000000 | FPSCR.Hex;
if (_inst.Rc)
PanicAlert("mffsx: inst_.Rc");
if (_inst.Rc)
PanicAlert("mffsx: inst_.Rc");
}
@@ -2,17 +2,17 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/PowerPC/Interpreter/Interpreter.h"
#include "Common/MsgHandler.h"
#include "Core/PowerPC/Gekko.h"
#include "Core/PowerPC/PPCTables.h"
#include "Core/PowerPC/Interpreter/Interpreter.h"
#include "Core/PowerPC/Interpreter/Interpreter_Tables.h"
#include "Core/PowerPC/PPCTables.h"
struct GekkoOPTemplate
{
int opcode;
Interpreter::Instruction Inst;
GekkoOPInfo opinfo;
int opcode;
Interpreter::Instruction Inst;
GekkoOPInfo opinfo;
};
// clang-format off
@@ -357,140 +357,138 @@ static GekkoOPTemplate table63_2[] =
namespace InterpreterTables
{
void InitTables()
{
// once initialized, tables are read-only
static bool initialized = false;
if (initialized)
return;
// once initialized, tables are read-only
static bool initialized = false;
if (initialized)
return;
//clear
for (int i = 0; i < 64; i++)
{
Interpreter::m_opTable[i] = Interpreter::unknown_instruction;
m_infoTable[i] = &unknownopinfo;
}
// clear
for (int i = 0; i < 64; i++)
{
Interpreter::m_opTable[i] = Interpreter::unknown_instruction;
m_infoTable[i] = &unknownopinfo;
}
for (int i = 0; i < 32; i++)
{
Interpreter::m_opTable59[i] = Interpreter::unknown_instruction;
m_infoTable59[i] = &unknownopinfo;
}
for (int i = 0; i < 32; i++)
{
Interpreter::m_opTable59[i] = Interpreter::unknown_instruction;
m_infoTable59[i] = &unknownopinfo;
}
for (int i = 0; i < 1024; i++)
{
Interpreter::m_opTable4 [i] = Interpreter::unknown_instruction;
Interpreter::m_opTable19[i] = Interpreter::unknown_instruction;
Interpreter::m_opTable31[i] = Interpreter::unknown_instruction;
Interpreter::m_opTable63[i] = Interpreter::unknown_instruction;
m_infoTable4[i] = &unknownopinfo;
m_infoTable19[i] = &unknownopinfo;
m_infoTable31[i] = &unknownopinfo;
m_infoTable63[i] = &unknownopinfo;
}
for (int i = 0; i < 1024; i++)
{
Interpreter::m_opTable4[i] = Interpreter::unknown_instruction;
Interpreter::m_opTable19[i] = Interpreter::unknown_instruction;
Interpreter::m_opTable31[i] = Interpreter::unknown_instruction;
Interpreter::m_opTable63[i] = Interpreter::unknown_instruction;
m_infoTable4[i] = &unknownopinfo;
m_infoTable19[i] = &unknownopinfo;
m_infoTable31[i] = &unknownopinfo;
m_infoTable63[i] = &unknownopinfo;
}
for (auto& tpl : primarytable)
{
Interpreter::m_opTable[tpl.opcode] = tpl.Inst;
m_infoTable[tpl.opcode] = &tpl.opinfo;
}
for (auto& tpl : primarytable)
{
Interpreter::m_opTable[tpl.opcode] = tpl.Inst;
m_infoTable[tpl.opcode] = &tpl.opinfo;
}
for (int i = 0; i < 32; i++)
{
int fill = i << 5;
for (auto& tpl : table4_2)
{
int op = fill+tpl.opcode;
Interpreter::m_opTable4[op] = tpl.Inst;
m_infoTable4[op] = &tpl.opinfo;
}
}
for (int i = 0; i < 32; i++)
{
int fill = i << 5;
for (auto& tpl : table4_2)
{
int op = fill + tpl.opcode;
Interpreter::m_opTable4[op] = tpl.Inst;
m_infoTable4[op] = &tpl.opinfo;
}
}
for (int i = 0; i < 16; i++)
{
int fill = i << 6;
for (auto& tpl : table4_3)
{
int op = fill+tpl.opcode;
Interpreter::m_opTable4[op] = tpl.Inst;
m_infoTable4[op] = &tpl.opinfo;
}
}
for (int i = 0; i < 16; i++)
{
int fill = i << 6;
for (auto& tpl : table4_3)
{
int op = fill + tpl.opcode;
Interpreter::m_opTable4[op] = tpl.Inst;
m_infoTable4[op] = &tpl.opinfo;
}
}
for (auto& tpl : table4)
{
int op = tpl.opcode;
Interpreter::m_opTable4[op] = tpl.Inst;
m_infoTable4[op] = &tpl.opinfo;
}
for (auto& tpl : table4)
{
int op = tpl.opcode;
Interpreter::m_opTable4[op] = tpl.Inst;
m_infoTable4[op] = &tpl.opinfo;
}
for (auto& tpl : table31)
{
int op = tpl.opcode;
Interpreter::m_opTable31[op] = tpl.Inst;
m_infoTable31[op] = &tpl.opinfo;
}
for (auto& tpl : table31)
{
int op = tpl.opcode;
Interpreter::m_opTable31[op] = tpl.Inst;
m_infoTable31[op] = &tpl.opinfo;
}
for (auto& tpl : table19)
{
int op = tpl.opcode;
Interpreter::m_opTable19[op] = tpl.Inst;
m_infoTable19[op] = &tpl.opinfo;
}
for (auto& tpl : table19)
{
int op = tpl.opcode;
Interpreter::m_opTable19[op] = tpl.Inst;
m_infoTable19[op] = &tpl.opinfo;
}
for (auto& tpl : table59)
{
int op = tpl.opcode;
Interpreter::m_opTable59[op] = tpl.Inst;
m_infoTable59[op] = &tpl.opinfo;
}
for (auto& tpl : table59)
{
int op = tpl.opcode;
Interpreter::m_opTable59[op] = tpl.Inst;
m_infoTable59[op] = &tpl.opinfo;
}
for (auto& tpl : table63)
{
int op = tpl.opcode;
Interpreter::m_opTable63[op] = tpl.Inst;
m_infoTable63[op] = &tpl.opinfo;
}
for (auto& tpl : table63)
{
int op = tpl.opcode;
Interpreter::m_opTable63[op] = tpl.Inst;
m_infoTable63[op] = &tpl.opinfo;
}
for (int i = 0; i < 32; i++)
{
int fill = i << 5;
for (auto& tpl : table63_2)
{
int op = fill + tpl.opcode;
Interpreter::m_opTable63[op] = tpl.Inst;
m_infoTable63[op] = &tpl.opinfo;
}
}
for (int i = 0; i < 32; i++)
{
int fill = i << 5;
for (auto& tpl : table63_2)
{
int op = fill + tpl.opcode;
Interpreter::m_opTable63[op] = tpl.Inst;
m_infoTable63[op] = &tpl.opinfo;
}
}
m_numInstructions = 0;
for (auto& tpl : primarytable)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table4_2)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table4_3)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table4)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table31)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table19)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table59)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table63)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table63_2)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
m_numInstructions = 0;
for (auto& tpl : primarytable)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table4_2)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table4_3)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table4)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table31)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table19)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table59)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table63)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
for (auto& tpl : table63_2)
m_allInstructions[m_numInstructions++] = &tpl.opinfo;
if (m_numInstructions >= 512)
{
PanicAlert("m_allInstructions underdimensioned");
}
if (m_numInstructions >= 512)
{
PanicAlert("m_allInstructions underdimensioned");
}
initialized = true;
initialized = true;
}
}
//remove
// remove
@@ -6,5 +6,5 @@
namespace InterpreterTables
{
void InitTables();
void InitTables();
}