Reformat all the things. Have fun with merge conflicts.
This commit is contained in:
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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
Reference in new issue
Block a user