Merge pull request #11671 from AdmiralCurtiss/deglobal-interpreter

Deglobalize Interpreter
This commit is contained in:
Mai 2023-03-20 15:55:14 -04:00 committed by GitHub
commit 9807961ff2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 1856 additions and 1632 deletions

View File

@ -19,6 +19,7 @@ struct CachedInterpreter::Instruction
{
using CommonCallback = void (*)(UGeckoInstruction);
using ConditionalCallback = bool (*)(u32);
using InterpreterCallback = void (*)(Interpreter&, UGeckoInstruction);
Instruction() {}
Instruction(const CommonCallback c, UGeckoInstruction i)
@ -31,17 +32,24 @@ struct CachedInterpreter::Instruction
{
}
Instruction(const InterpreterCallback c, UGeckoInstruction i)
: interpreter_callback(c), data(i.hex), type(Type::Interpreter)
{
}
enum class Type
{
Abort,
Common,
Conditional,
Interpreter,
};
union
{
const CommonCallback common_callback = nullptr;
const ConditionalCallback conditional_callback;
const InterpreterCallback interpreter_callback;
};
u32 data = 0;
@ -100,6 +108,11 @@ void CachedInterpreter::ExecuteOneBlock()
return;
break;
case Instruction::Type::Interpreter:
code->interpreter_callback(Core::System::GetInstance().GetInterpreter(),
UGeckoInstruction(code->data));
break;
default:
ERROR_LOG_FMT(POWERPC, "Unknown CachedInterpreter Instruction: {}",
static_cast<int>(code->type));

View File

@ -27,13 +27,6 @@
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
namespace
{
u32 last_pc;
}
bool Interpreter::m_end_block;
namespace
{
// Determines whether or not the given instruction is one where its execution
@ -49,27 +42,34 @@ bool IsPairedSingleInstruction(UGeckoInstruction inst)
{
return inst.OPCD == 4 || IsPairedSingleQuantizedNonIndexedInstruction(inst);
}
} // namespace
// Checks if a given instruction would be illegal to execute if it's a paired single instruction.
//
// Paired single instructions are illegal to execute if HID2.PSE is not set.
// It's also illegal to execute psq_l, psq_lu, psq_st, and psq_stu if HID2.PSE is enabled,
// but HID2.LSQE is not set.
bool IsInvalidPairedSingleExecution(UGeckoInstruction inst)
bool Interpreter::IsInvalidPairedSingleExecution(UGeckoInstruction inst)
{
if (!HID2(PowerPC::ppcState).PSE && IsPairedSingleInstruction(inst))
if (!HID2(m_ppc_state).PSE && IsPairedSingleInstruction(inst))
return true;
return HID2(PowerPC::ppcState).PSE && !HID2(PowerPC::ppcState).LSQE &&
return HID2(m_ppc_state).PSE && !HID2(m_ppc_state).LSQE &&
IsPairedSingleQuantizedNonIndexedInstruction(inst);
}
void UpdatePC()
void Interpreter::UpdatePC()
{
last_pc = PowerPC::ppcState.pc;
PowerPC::ppcState.pc = PowerPC::ppcState.npc;
m_last_pc = m_ppc_state.pc;
m_ppc_state.pc = m_ppc_state.npc;
}
} // Anonymous namespace
Interpreter::Interpreter(Core::System& system, PowerPC::PowerPCState& ppc_state)
: m_system(system), m_ppc_state(ppc_state)
{
}
Interpreter::~Interpreter() = default;
void Interpreter::Init()
{
@ -80,44 +80,41 @@ void Interpreter::Shutdown()
{
}
static bool s_start_trace = false;
static void Trace(const UGeckoInstruction& inst)
void Interpreter::Trace(const UGeckoInstruction& inst)
{
std::string regs;
for (size_t i = 0; i < std::size(PowerPC::ppcState.gpr); i++)
for (size_t i = 0; i < std::size(m_ppc_state.gpr); i++)
{
regs += fmt::format("r{:02d}: {:08x} ", i, PowerPC::ppcState.gpr[i]);
regs += fmt::format("r{:02d}: {:08x} ", i, m_ppc_state.gpr[i]);
}
std::string fregs;
for (size_t i = 0; i < std::size(PowerPC::ppcState.ps); i++)
for (size_t i = 0; i < std::size(m_ppc_state.ps); i++)
{
const auto& ps = PowerPC::ppcState.ps[i];
const auto& ps = m_ppc_state.ps[i];
fregs += fmt::format("f{:02d}: {:08x} {:08x} ", i, ps.PS0AsU64(), ps.PS1AsU64());
}
const std::string ppc_inst =
Common::GekkoDisassembler::Disassemble(inst.hex, PowerPC::ppcState.pc);
const std::string ppc_inst = Common::GekkoDisassembler::Disassemble(inst.hex, m_ppc_state.pc);
DEBUG_LOG_FMT(POWERPC,
"INTER PC: {:08x} SRR0: {:08x} SRR1: {:08x} CRval: {:016x} "
"FPSCR: {:08x} MSR: {:08x} LR: {:08x} {} {:08x} {}",
PowerPC::ppcState.pc, SRR0(PowerPC::ppcState), SRR1(PowerPC::ppcState),
PowerPC::ppcState.cr.fields[0], PowerPC::ppcState.fpscr.Hex,
PowerPC::ppcState.msr.Hex, PowerPC::ppcState.spr[8], regs, inst.hex, ppc_inst);
m_ppc_state.pc, SRR0(m_ppc_state), SRR1(m_ppc_state), m_ppc_state.cr.fields[0],
m_ppc_state.fpscr.Hex, m_ppc_state.msr.Hex, m_ppc_state.spr[8], regs, inst.hex,
ppc_inst);
}
bool Interpreter::HandleFunctionHooking(u32 address)
{
return HLE::ReplaceFunctionIfPossible(address, [](u32 hook_index, HLE::HookType type) {
HLEFunction(hook_index);
return HLE::ReplaceFunctionIfPossible(address, [this](u32 hook_index, HLE::HookType type) {
HLEFunction(*this, hook_index);
return type != HLE::HookType::Start;
});
}
int Interpreter::SingleStepInner()
{
if (HandleFunctionHooking(PowerPC::ppcState.pc))
if (HandleFunctionHooking(m_ppc_state.pc))
{
UpdatePC();
// TODO: Does it make sense to use m_prev_inst here?
@ -126,23 +123,23 @@ int Interpreter::SingleStepInner()
return PPCTables::GetOpInfo(m_prev_inst)->num_cycles;
}
PowerPC::ppcState.npc = PowerPC::ppcState.pc + sizeof(UGeckoInstruction);
m_prev_inst.hex = PowerPC::Read_Opcode(PowerPC::ppcState.pc);
m_ppc_state.npc = m_ppc_state.pc + sizeof(UGeckoInstruction);
m_prev_inst.hex = PowerPC::Read_Opcode(m_ppc_state.pc);
const GekkoOPInfo* opinfo = PPCTables::GetOpInfo(m_prev_inst);
// Uncomment to trace the interpreter
// if ((PowerPC::ppcState.pc & 0x00FFFFFF) >= 0x000AB54C &&
// (PowerPC::ppcState.pc & 0x00FFFFFF) <= 0x000AB624)
// if ((m_ppc_state.pc & 0x00FFFFFF) >= 0x000AB54C &&
// (m_ppc_state.pc & 0x00FFFFFF) <= 0x000AB624)
// {
// s_start_trace = true;
// m_start_trace = true;
// }
// else
// {
// s_start_trace = false;
// m_start_trace = false;
// }
if (s_start_trace)
if (m_start_trace)
{
Trace(m_prev_inst);
}
@ -154,10 +151,10 @@ int Interpreter::SingleStepInner()
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
CheckExceptions();
}
else if (PowerPC::ppcState.msr.FP)
else if (m_ppc_state.msr.FP)
{
RunInterpreterOp(m_prev_inst);
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
RunInterpreterOp(*this, m_prev_inst);
if ((m_ppc_state.Exceptions & EXCEPTION_DSI) != 0)
{
CheckExceptions();
}
@ -167,13 +164,13 @@ int Interpreter::SingleStepInner()
// check if we have to generate a FPU unavailable exception or a program exception.
if ((opinfo->flags & FL_USE_FPU) != 0)
{
PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
m_ppc_state.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
CheckExceptions();
}
else
{
RunInterpreterOp(m_prev_inst);
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
RunInterpreterOp(*this, m_prev_inst);
if ((m_ppc_state.Exceptions & EXCEPTION_DSI) != 0)
{
CheckExceptions();
}
@ -189,13 +186,13 @@ int Interpreter::SingleStepInner()
UpdatePC();
PowerPC::UpdatePerformanceMonitor(opinfo->num_cycles, (opinfo->flags & FL_LOADSTORE) != 0,
(opinfo->flags & FL_USE_FPU) != 0, PowerPC::ppcState);
(opinfo->flags & FL_USE_FPU) != 0, m_ppc_state);
return opinfo->num_cycles;
}
void Interpreter::SingleStep()
{
auto& core_timing = Core::System::GetInstance().GetCoreTiming();
auto& core_timing = m_system.GetCoreTiming();
auto& core_timing_globals = core_timing.GetGlobals();
// Declare start of new slice
@ -205,12 +202,12 @@ void Interpreter::SingleStep()
// The interpreter ignores instruction timing information outside the 'fast runloop'.
core_timing_globals.slice_length = 1;
PowerPC::ppcState.downcount = 0;
m_ppc_state.downcount = 0;
if (PowerPC::ppcState.Exceptions != 0)
if (m_ppc_state.Exceptions != 0)
{
PowerPC::CheckExceptions();
PowerPC::ppcState.pc = PowerPC::ppcState.npc;
m_ppc_state.pc = m_ppc_state.npc;
}
}
@ -225,9 +222,8 @@ constexpr u32 s_show_steps = 300;
// FastRun - inspired by GCemu (to imitate the JIT so that they can be compared).
void Interpreter::Run()
{
auto& system = Core::System::GetInstance();
auto& core_timing = system.GetCoreTiming();
auto& cpu = system.GetCPU();
auto& core_timing = m_system.GetCoreTiming();
auto& cpu = m_system.GetCPU();
while (cpu.GetState() == CPU::State::Running)
{
// CoreTiming Advance() ends the previous slice and declares the start of the next
@ -239,27 +235,27 @@ void Interpreter::Run()
if (Config::Get(Config::MAIN_ENABLE_DEBUGGING))
{
#ifdef SHOW_HISTORY
s_pc_block_vec.push_back(PowerPC::ppcState.pc);
s_pc_block_vec.push_back(m_ppc_state.pc);
if (s_pc_block_vec.size() > s_show_blocks)
s_pc_block_vec.erase(s_pc_block_vec.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)
while (m_ppc_state.downcount > 0)
{
m_end_block = false;
int cycles = 0;
while (!m_end_block)
{
#ifdef SHOW_HISTORY
s_pc_vec.push_back(PowerPC::ppcState.pc);
s_pc_vec.push_back(m_ppc_state.pc);
if (s_pc_vec.size() > s_show_steps)
s_pc_vec.erase(s_pc_vec.begin());
#endif
// 2: check for breakpoint
if (PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc))
if (PowerPC::breakpoints.IsAddressBreakPoint(m_ppc_state.pc))
{
#ifdef SHOW_HISTORY
NOTICE_LOG_FMT(POWERPC, "----------------------------");
@ -280,25 +276,25 @@ void Interpreter::Run()
NOTICE_LOG_FMT(POWERPC, "PC: {:#010x}", s_pc_vec[j]);
}
#endif
INFO_LOG_FMT(POWERPC, "Hit Breakpoint - {:08x}", PowerPC::ppcState.pc);
INFO_LOG_FMT(POWERPC, "Hit Breakpoint - {:08x}", m_ppc_state.pc);
cpu.Break();
if (GDBStub::IsActive())
GDBStub::TakeControl();
if (PowerPC::breakpoints.IsTempBreakPoint(PowerPC::ppcState.pc))
PowerPC::breakpoints.Remove(PowerPC::ppcState.pc);
if (PowerPC::breakpoints.IsTempBreakPoint(m_ppc_state.pc))
PowerPC::breakpoints.Remove(m_ppc_state.pc);
Host_UpdateDisasmDialog();
return;
}
cycles += SingleStepInner();
}
PowerPC::ppcState.downcount -= cycles;
m_ppc_state.downcount -= cycles;
}
}
else
{
// "fast" version of inner loop. well, it's not so fast.
while (PowerPC::ppcState.downcount > 0)
while (m_ppc_state.downcount > 0)
{
m_end_block = false;
@ -307,36 +303,39 @@ void Interpreter::Run()
{
cycles += SingleStepInner();
}
PowerPC::ppcState.downcount -= cycles;
m_ppc_state.downcount -= cycles;
}
}
}
}
void Interpreter::unknown_instruction(UGeckoInstruction inst)
void Interpreter::unknown_instruction(Interpreter& interpreter, UGeckoInstruction inst)
{
ASSERT(Core::IsCPUThread());
auto& system = Core::System::GetInstance();
auto& system = interpreter.m_system;
Core::CPUThreadGuard guard(system);
const u32 last_pc = interpreter.m_last_pc;
const u32 opcode = PowerPC::HostRead_U32(guard, last_pc);
const std::string disasm = Common::GekkoDisassembler::Disassemble(opcode, last_pc);
NOTICE_LOG_FMT(POWERPC, "Last PC = {:08x} : {}", last_pc, disasm);
Dolphin_Debugger::PrintCallstack(system, guard, Common::Log::LogType::POWERPC,
Common::Log::LogLevel::LNOTICE);
const auto& ppc_state = interpreter.m_ppc_state;
NOTICE_LOG_FMT(
POWERPC,
"\nIntCPU: Unknown instruction {:08x} at PC = {:08x} last_PC = {:08x} LR = {:08x}\n",
inst.hex, PowerPC::ppcState.pc, last_pc, LR(PowerPC::ppcState));
inst.hex, ppc_state.pc, last_pc, LR(ppc_state));
for (int i = 0; i < 32; i += 4)
{
NOTICE_LOG_FMT(POWERPC, "r{}: {:#010x} r{}: {:#010x} r{}: {:#010x} r{}: {:#010x}", i,
PowerPC::ppcState.gpr[i], i + 1, PowerPC::ppcState.gpr[i + 1], i + 2,
PowerPC::ppcState.gpr[i + 2], i + 3, PowerPC::ppcState.gpr[i + 3]);
ppc_state.gpr[i], i + 1, ppc_state.gpr[i + 1], i + 2, ppc_state.gpr[i + 2],
i + 3, ppc_state.gpr[i + 3]);
}
ASSERT_MSG(POWERPC, 0,
"\nIntCPU: Unknown instruction {:08x} at PC = {:08x} last_PC = {:08x} LR = {:08x}\n",
inst.hex, PowerPC::ppcState.pc, last_pc, LR(PowerPC::ppcState));
inst.hex, ppc_state.pc, last_pc, LR(ppc_state));
if (system.IsPauseOnPanicMode())
system.GetCPU().Break();
}
@ -360,9 +359,3 @@ const char* Interpreter::GetName() const
return "Interpreter32";
#endif
}
Interpreter* Interpreter::getInstance()
{
static Interpreter instance;
return &instance;
}

View File

@ -9,9 +9,25 @@
#include "Core/PowerPC/CPUCoreBase.h"
#include "Core/PowerPC/Gekko.h"
namespace Core
{
class System;
}
namespace PowerPC
{
struct PowerPCState;
}
class Interpreter : public CPUCoreBase
{
public:
Interpreter(Core::System& system, PowerPC::PowerPCState& ppc_state);
Interpreter(const Interpreter&) = delete;
Interpreter(Interpreter&&) = delete;
Interpreter& operator=(const Interpreter&) = delete;
Interpreter& operator=(Interpreter&&) = delete;
~Interpreter();
void Init() override;
void Shutdown() override;
void SingleStep() override;
@ -21,276 +37,284 @@ public:
void ClearCache() override;
const char* GetName() const override;
static void unknown_instruction(UGeckoInstruction inst);
static void unknown_instruction(Interpreter& interpreter, 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);
static void bx(Interpreter& interpreter, UGeckoInstruction inst);
static void bcx(Interpreter& interpreter, UGeckoInstruction inst);
static void bcctrx(Interpreter& interpreter, UGeckoInstruction inst);
static void bclrx(Interpreter& interpreter, UGeckoInstruction inst);
static void HLEFunction(Interpreter& interpreter, UGeckoInstruction inst);
// Syscall Instruction
static void sc(UGeckoInstruction inst);
static void sc(Interpreter& interpreter, 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);
static void faddsx(Interpreter& interpreter, UGeckoInstruction inst);
static void fdivsx(Interpreter& interpreter, UGeckoInstruction inst);
static void fmaddsx(Interpreter& interpreter, UGeckoInstruction inst);
static void fmsubsx(Interpreter& interpreter, UGeckoInstruction inst);
static void fmulsx(Interpreter& interpreter, UGeckoInstruction inst);
static void fnmaddsx(Interpreter& interpreter, UGeckoInstruction inst);
static void fnmsubsx(Interpreter& interpreter, UGeckoInstruction inst);
static void fresx(Interpreter& interpreter, UGeckoInstruction inst);
static void fsubsx(Interpreter& interpreter, UGeckoInstruction inst);
static void fabsx(Interpreter& interpreter, UGeckoInstruction inst);
static void fcmpo(Interpreter& interpreter, UGeckoInstruction inst);
static void fcmpu(Interpreter& interpreter, UGeckoInstruction inst);
static void fctiwx(Interpreter& interpreter, UGeckoInstruction inst);
static void fctiwzx(Interpreter& interpreter, UGeckoInstruction inst);
static void fmrx(Interpreter& interpreter, UGeckoInstruction inst);
static void fnabsx(Interpreter& interpreter, UGeckoInstruction inst);
static void fnegx(Interpreter& interpreter, UGeckoInstruction inst);
static void frspx(Interpreter& interpreter, UGeckoInstruction inst);
static void faddx(Interpreter& interpreter, UGeckoInstruction inst);
static void fdivx(Interpreter& interpreter, UGeckoInstruction inst);
static void fmaddx(Interpreter& interpreter, UGeckoInstruction inst);
static void fmsubx(Interpreter& interpreter, UGeckoInstruction inst);
static void fmulx(Interpreter& interpreter, UGeckoInstruction inst);
static void fnmaddx(Interpreter& interpreter, UGeckoInstruction inst);
static void fnmsubx(Interpreter& interpreter, UGeckoInstruction inst);
static void frsqrtex(Interpreter& interpreter, UGeckoInstruction inst);
static void fselx(Interpreter& interpreter, UGeckoInstruction inst);
static void fsubx(Interpreter& interpreter, 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);
static void addi(Interpreter& interpreter, UGeckoInstruction inst);
static void addic(Interpreter& interpreter, UGeckoInstruction inst);
static void addic_rc(Interpreter& interpreter, UGeckoInstruction inst);
static void addis(Interpreter& interpreter, UGeckoInstruction inst);
static void andi_rc(Interpreter& interpreter, UGeckoInstruction inst);
static void andis_rc(Interpreter& interpreter, UGeckoInstruction inst);
static void cmpi(Interpreter& interpreter, UGeckoInstruction inst);
static void cmpli(Interpreter& interpreter, UGeckoInstruction inst);
static void mulli(Interpreter& interpreter, UGeckoInstruction inst);
static void ori(Interpreter& interpreter, UGeckoInstruction inst);
static void oris(Interpreter& interpreter, UGeckoInstruction inst);
static void subfic(Interpreter& interpreter, UGeckoInstruction inst);
static void twi(Interpreter& interpreter, UGeckoInstruction inst);
static void xori(Interpreter& interpreter, UGeckoInstruction inst);
static void xoris(Interpreter& interpreter, UGeckoInstruction inst);
static void rlwimix(Interpreter& interpreter, UGeckoInstruction inst);
static void rlwinmx(Interpreter& interpreter, UGeckoInstruction inst);
static void rlwnmx(Interpreter& interpreter, UGeckoInstruction inst);
static void andx(Interpreter& interpreter, UGeckoInstruction inst);
static void andcx(Interpreter& interpreter, UGeckoInstruction inst);
static void cmp(Interpreter& interpreter, UGeckoInstruction inst);
static void cmpl(Interpreter& interpreter, UGeckoInstruction inst);
static void cntlzwx(Interpreter& interpreter, UGeckoInstruction inst);
static void eqvx(Interpreter& interpreter, UGeckoInstruction inst);
static void extsbx(Interpreter& interpreter, UGeckoInstruction inst);
static void extshx(Interpreter& interpreter, UGeckoInstruction inst);
static void nandx(Interpreter& interpreter, UGeckoInstruction inst);
static void norx(Interpreter& interpreter, UGeckoInstruction inst);
static void orx(Interpreter& interpreter, UGeckoInstruction inst);
static void orcx(Interpreter& interpreter, UGeckoInstruction inst);
static void slwx(Interpreter& interpreter, UGeckoInstruction inst);
static void srawx(Interpreter& interpreter, UGeckoInstruction inst);
static void srawix(Interpreter& interpreter, UGeckoInstruction inst);
static void srwx(Interpreter& interpreter, UGeckoInstruction inst);
static void tw(Interpreter& interpreter, UGeckoInstruction inst);
static void xorx(Interpreter& interpreter, UGeckoInstruction inst);
static void addx(Interpreter& interpreter, UGeckoInstruction inst);
static void addcx(Interpreter& interpreter, UGeckoInstruction inst);
static void addex(Interpreter& interpreter, UGeckoInstruction inst);
static void addmex(Interpreter& interpreter, UGeckoInstruction inst);
static void addzex(Interpreter& interpreter, UGeckoInstruction inst);
static void divwx(Interpreter& interpreter, UGeckoInstruction inst);
static void divwux(Interpreter& interpreter, UGeckoInstruction inst);
static void mulhwx(Interpreter& interpreter, UGeckoInstruction inst);
static void mulhwux(Interpreter& interpreter, UGeckoInstruction inst);
static void mullwx(Interpreter& interpreter, UGeckoInstruction inst);
static void negx(Interpreter& interpreter, UGeckoInstruction inst);
static void subfx(Interpreter& interpreter, UGeckoInstruction inst);
static void subfcx(Interpreter& interpreter, UGeckoInstruction inst);
static void subfex(Interpreter& interpreter, UGeckoInstruction inst);
static void subfmex(Interpreter& interpreter, UGeckoInstruction inst);
static void subfzex(Interpreter& interpreter, 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);
static void lbz(Interpreter& interpreter, UGeckoInstruction inst);
static void lbzu(Interpreter& interpreter, UGeckoInstruction inst);
static void lfd(Interpreter& interpreter, UGeckoInstruction inst);
static void lfdu(Interpreter& interpreter, UGeckoInstruction inst);
static void lfs(Interpreter& interpreter, UGeckoInstruction inst);
static void lfsu(Interpreter& interpreter, UGeckoInstruction inst);
static void lha(Interpreter& interpreter, UGeckoInstruction inst);
static void lhau(Interpreter& interpreter, UGeckoInstruction inst);
static void lhz(Interpreter& interpreter, UGeckoInstruction inst);
static void lhzu(Interpreter& interpreter, UGeckoInstruction inst);
static void lmw(Interpreter& interpreter, UGeckoInstruction inst);
static void lwz(Interpreter& interpreter, UGeckoInstruction inst);
static void lwzu(Interpreter& interpreter, UGeckoInstruction inst);
static void stb(Interpreter& interpreter, UGeckoInstruction inst);
static void stbu(Interpreter& interpreter, UGeckoInstruction inst);
static void stfd(Interpreter& interpreter, UGeckoInstruction inst);
static void stfdu(Interpreter& interpreter, UGeckoInstruction inst);
static void stfs(Interpreter& interpreter, UGeckoInstruction inst);
static void stfsu(Interpreter& interpreter, UGeckoInstruction inst);
static void sth(Interpreter& interpreter, UGeckoInstruction inst);
static void sthu(Interpreter& interpreter, UGeckoInstruction inst);
static void stmw(Interpreter& interpreter, UGeckoInstruction inst);
static void stw(Interpreter& interpreter, UGeckoInstruction inst);
static void stwu(Interpreter& interpreter, UGeckoInstruction inst);
static void dcba(Interpreter& interpreter, UGeckoInstruction inst);
static void dcbf(Interpreter& interpreter, UGeckoInstruction inst);
static void dcbi(Interpreter& interpreter, UGeckoInstruction inst);
static void dcbst(Interpreter& interpreter, UGeckoInstruction inst);
static void dcbt(Interpreter& interpreter, UGeckoInstruction inst);
static void dcbtst(Interpreter& interpreter, UGeckoInstruction inst);
static void dcbz(Interpreter& interpreter, UGeckoInstruction inst);
static void eciwx(Interpreter& interpreter, UGeckoInstruction inst);
static void ecowx(Interpreter& interpreter, UGeckoInstruction inst);
static void eieio(Interpreter& interpreter, UGeckoInstruction inst);
static void icbi(Interpreter& interpreter, UGeckoInstruction inst);
static void lbzux(Interpreter& interpreter, UGeckoInstruction inst);
static void lbzx(Interpreter& interpreter, UGeckoInstruction inst);
static void lfdux(Interpreter& interpreter, UGeckoInstruction inst);
static void lfdx(Interpreter& interpreter, UGeckoInstruction inst);
static void lfsux(Interpreter& interpreter, UGeckoInstruction inst);
static void lfsx(Interpreter& interpreter, UGeckoInstruction inst);
static void lhaux(Interpreter& interpreter, UGeckoInstruction inst);
static void lhax(Interpreter& interpreter, UGeckoInstruction inst);
static void lhbrx(Interpreter& interpreter, UGeckoInstruction inst);
static void lhzux(Interpreter& interpreter, UGeckoInstruction inst);
static void lhzx(Interpreter& interpreter, UGeckoInstruction inst);
static void lswi(Interpreter& interpreter, UGeckoInstruction inst);
static void lswx(Interpreter& interpreter, UGeckoInstruction inst);
static void lwarx(Interpreter& interpreter, UGeckoInstruction inst);
static void lwbrx(Interpreter& interpreter, UGeckoInstruction inst);
static void lwzux(Interpreter& interpreter, UGeckoInstruction inst);
static void lwzx(Interpreter& interpreter, UGeckoInstruction inst);
static void stbux(Interpreter& interpreter, UGeckoInstruction inst);
static void stbx(Interpreter& interpreter, UGeckoInstruction inst);
static void stfdux(Interpreter& interpreter, UGeckoInstruction inst);
static void stfdx(Interpreter& interpreter, UGeckoInstruction inst);
static void stfiwx(Interpreter& interpreter, UGeckoInstruction inst);
static void stfsux(Interpreter& interpreter, UGeckoInstruction inst);
static void stfsx(Interpreter& interpreter, UGeckoInstruction inst);
static void sthbrx(Interpreter& interpreter, UGeckoInstruction inst);
static void sthux(Interpreter& interpreter, UGeckoInstruction inst);
static void sthx(Interpreter& interpreter, UGeckoInstruction inst);
static void stswi(Interpreter& interpreter, UGeckoInstruction inst);
static void stswx(Interpreter& interpreter, UGeckoInstruction inst);
static void stwbrx(Interpreter& interpreter, UGeckoInstruction inst);
static void stwcxd(Interpreter& interpreter, UGeckoInstruction inst);
static void stwux(Interpreter& interpreter, UGeckoInstruction inst);
static void stwx(Interpreter& interpreter, UGeckoInstruction inst);
static void tlbie(Interpreter& interpreter, UGeckoInstruction inst);
static void tlbsync(Interpreter& interpreter, 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);
static void psq_l(Interpreter& interpreter, UGeckoInstruction inst);
static void psq_lu(Interpreter& interpreter, UGeckoInstruction inst);
static void psq_st(Interpreter& interpreter, UGeckoInstruction inst);
static void psq_stu(Interpreter& interpreter, UGeckoInstruction inst);
static void psq_lx(Interpreter& interpreter, UGeckoInstruction inst);
static void psq_stx(Interpreter& interpreter, UGeckoInstruction inst);
static void psq_lux(Interpreter& interpreter, UGeckoInstruction inst);
static void psq_stux(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_div(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_sub(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_add(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_sel(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_res(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_mul(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_rsqrte(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_msub(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_madd(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_nmsub(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_nmadd(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_neg(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_mr(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_nabs(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_abs(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_sum0(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_sum1(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_muls0(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_muls1(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_madds0(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_madds1(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_cmpu0(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_cmpo0(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_cmpu1(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_cmpo1(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_merge00(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_merge01(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_merge10(Interpreter& interpreter, UGeckoInstruction inst);
static void ps_merge11(Interpreter& interpreter, UGeckoInstruction inst);
static void dcbz_l(Interpreter& interpreter, 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);
static void mcrfs(Interpreter& interpreter, UGeckoInstruction inst);
static void mffsx(Interpreter& interpreter, UGeckoInstruction inst);
static void mtfsb0x(Interpreter& interpreter, UGeckoInstruction inst);
static void mtfsb1x(Interpreter& interpreter, UGeckoInstruction inst);
static void mtfsfix(Interpreter& interpreter, UGeckoInstruction inst);
static void mtfsfx(Interpreter& interpreter, UGeckoInstruction inst);
static void mcrxr(Interpreter& interpreter, UGeckoInstruction inst);
static void mfcr(Interpreter& interpreter, UGeckoInstruction inst);
static void mfmsr(Interpreter& interpreter, UGeckoInstruction inst);
static void mfsr(Interpreter& interpreter, UGeckoInstruction inst);
static void mfsrin(Interpreter& interpreter, UGeckoInstruction inst);
static void mtmsr(Interpreter& interpreter, UGeckoInstruction inst);
static void mtsr(Interpreter& interpreter, UGeckoInstruction inst);
static void mtsrin(Interpreter& interpreter, UGeckoInstruction inst);
static void mfspr(Interpreter& interpreter, UGeckoInstruction inst);
static void mftb(Interpreter& interpreter, UGeckoInstruction inst);
static void mtcrf(Interpreter& interpreter, UGeckoInstruction inst);
static void mtspr(Interpreter& interpreter, UGeckoInstruction inst);
static void crand(Interpreter& interpreter, UGeckoInstruction inst);
static void crandc(Interpreter& interpreter, UGeckoInstruction inst);
static void creqv(Interpreter& interpreter, UGeckoInstruction inst);
static void crnand(Interpreter& interpreter, UGeckoInstruction inst);
static void crnor(Interpreter& interpreter, UGeckoInstruction inst);
static void cror(Interpreter& interpreter, UGeckoInstruction inst);
static void crorc(Interpreter& interpreter, UGeckoInstruction inst);
static void crxor(Interpreter& interpreter, UGeckoInstruction inst);
static void mcrf(Interpreter& interpreter, UGeckoInstruction inst);
static void rfi(Interpreter& interpreter, UGeckoInstruction inst);
static void sync(Interpreter& interpreter, UGeckoInstruction inst);
static void isync(Interpreter& interpreter, UGeckoInstruction inst);
using Instruction = void (*)(UGeckoInstruction inst);
using Instruction = void (*)(Interpreter& interpreter, UGeckoInstruction inst);
static Instruction GetInterpreterOp(UGeckoInstruction inst);
static void RunInterpreterOp(UGeckoInstruction inst);
static void RunInterpreterOp(Interpreter& interpreter, UGeckoInstruction inst);
// singleton
static Interpreter* getInstance();
static void RunTable4(UGeckoInstruction inst);
static void RunTable19(UGeckoInstruction inst);
static void RunTable31(UGeckoInstruction inst);
static void RunTable59(UGeckoInstruction inst);
static void RunTable63(UGeckoInstruction inst);
static void RunTable4(Interpreter& interpreter, UGeckoInstruction inst);
static void RunTable19(Interpreter& interpreter, UGeckoInstruction inst);
static void RunTable31(Interpreter& interpreter, UGeckoInstruction inst);
static void RunTable59(Interpreter& interpreter, UGeckoInstruction inst);
static void RunTable63(Interpreter& interpreter, UGeckoInstruction inst);
static u32 Helper_Carry(u32 value1, u32 value2);
private:
void CheckExceptions();
static bool HandleFunctionHooking(u32 address);
bool HandleFunctionHooking(u32 address);
// flag helper
static void Helper_UpdateCR0(u32 value);
static void Helper_UpdateCR0(PowerPC::PowerPCState& ppc_state, u32 value);
template <typename T>
static void Helper_IntCompare(UGeckoInstruction inst, T a, T b);
static void Helper_FloatCompareOrdered(UGeckoInstruction inst, double a, double b);
static void Helper_FloatCompareUnordered(UGeckoInstruction inst, double a, double b);
static void Helper_IntCompare(PowerPC::PowerPCState& ppc_state, UGeckoInstruction inst, T a, T b);
static void Helper_FloatCompareOrdered(PowerPC::PowerPCState& ppc_state, UGeckoInstruction inst,
double a, double b);
static void Helper_FloatCompareUnordered(PowerPC::PowerPCState& ppc_state, UGeckoInstruction inst,
double a, double b);
void UpdatePC();
bool IsInvalidPairedSingleExecution(UGeckoInstruction inst);
void Trace(const UGeckoInstruction& inst);
Core::System& m_system;
PowerPC::PowerPCState& m_ppc_state;
UGeckoInstruction m_prev_inst{};
static bool m_end_block;
u32 m_last_pc = 0;
bool m_end_block = false;
bool m_start_trace = false;
};

View File

@ -12,101 +12,110 @@
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
void Interpreter::bx(UGeckoInstruction inst)
void Interpreter::bx(Interpreter& interpreter, UGeckoInstruction inst)
{
auto& ppc_state = interpreter.m_ppc_state;
if (inst.LK)
LR(PowerPC::ppcState) = PowerPC::ppcState.pc + 4;
LR(ppc_state) = ppc_state.pc + 4;
const auto address = u32(SignExt26(inst.LI << 2));
if (inst.AA)
PowerPC::ppcState.npc = address;
ppc_state.npc = address;
else
PowerPC::ppcState.npc = PowerPC::ppcState.pc + address;
ppc_state.npc = ppc_state.pc + address;
m_end_block = true;
interpreter.m_end_block = true;
}
// bcx - ugly, straight from PPC manual equations :)
void Interpreter::bcx(UGeckoInstruction inst)
void Interpreter::bcx(Interpreter& interpreter, UGeckoInstruction inst)
{
auto& ppc_state = interpreter.m_ppc_state;
if ((inst.BO & BO_DONT_DECREMENT_FLAG) == 0)
CTR(PowerPC::ppcState)--;
CTR(ppc_state)--;
const bool true_false = ((inst.BO >> 3) & 1) != 0;
const bool only_counter_check = ((inst.BO >> 4) & 1) != 0;
const bool only_condition_check = ((inst.BO >> 2) & 1) != 0;
const u32 ctr_check = ((CTR(PowerPC::ppcState) != 0) ^ (inst.BO >> 1)) & 1;
const u32 ctr_check = ((CTR(ppc_state) != 0) ^ (inst.BO >> 1)) & 1;
const bool counter = only_condition_check || ctr_check != 0;
const bool condition =
only_counter_check || (PowerPC::ppcState.cr.GetBit(inst.BI) == u32(true_false));
const bool condition = only_counter_check || (ppc_state.cr.GetBit(inst.BI) == u32(true_false));
if (counter && condition)
{
if (inst.LK)
LR(PowerPC::ppcState) = PowerPC::ppcState.pc + 4;
LR(ppc_state) = ppc_state.pc + 4;
const auto address = u32(SignExt16(s16(inst.BD << 2)));
if (inst.AA)
PowerPC::ppcState.npc = address;
ppc_state.npc = address;
else
PowerPC::ppcState.npc = PowerPC::ppcState.pc + address;
ppc_state.npc = ppc_state.pc + address;
}
m_end_block = true;
interpreter.m_end_block = true;
}
void Interpreter::bcctrx(UGeckoInstruction inst)
void Interpreter::bcctrx(Interpreter& interpreter, UGeckoInstruction inst)
{
auto& ppc_state = interpreter.m_ppc_state;
DEBUG_ASSERT_MSG(POWERPC, (inst.BO_2 & BO_DONT_DECREMENT_FLAG) != 0,
"bcctrx with decrement and test CTR option is invalid!");
const u32 condition =
((inst.BO_2 >> 4) | (PowerPC::ppcState.cr.GetBit(inst.BI_2) == ((inst.BO_2 >> 3) & 1))) & 1;
((inst.BO_2 >> 4) | (ppc_state.cr.GetBit(inst.BI_2) == ((inst.BO_2 >> 3) & 1))) & 1;
if (condition != 0)
{
PowerPC::ppcState.npc = CTR(PowerPC::ppcState) & (~3);
ppc_state.npc = CTR(ppc_state) & (~3);
if (inst.LK_3)
LR(PowerPC::ppcState) = PowerPC::ppcState.pc + 4;
LR(ppc_state) = ppc_state.pc + 4;
}
m_end_block = true;
interpreter.m_end_block = true;
}
void Interpreter::bclrx(UGeckoInstruction inst)
void Interpreter::bclrx(Interpreter& interpreter, UGeckoInstruction inst)
{
if ((inst.BO_2 & BO_DONT_DECREMENT_FLAG) == 0)
CTR(PowerPC::ppcState)--;
auto& ppc_state = interpreter.m_ppc_state;
const u32 counter = ((inst.BO_2 >> 2) | ((CTR(PowerPC::ppcState) != 0) ^ (inst.BO_2 >> 1))) & 1;
if ((inst.BO_2 & BO_DONT_DECREMENT_FLAG) == 0)
CTR(ppc_state)--;
const u32 counter = ((inst.BO_2 >> 2) | ((CTR(ppc_state) != 0) ^ (inst.BO_2 >> 1))) & 1;
const u32 condition =
((inst.BO_2 >> 4) | (PowerPC::ppcState.cr.GetBit(inst.BI_2) == ((inst.BO_2 >> 3) & 1))) & 1;
((inst.BO_2 >> 4) | (ppc_state.cr.GetBit(inst.BI_2) == ((inst.BO_2 >> 3) & 1))) & 1;
if ((counter & condition) != 0)
{
PowerPC::ppcState.npc = LR(PowerPC::ppcState) & (~3);
ppc_state.npc = LR(ppc_state) & (~3);
if (inst.LK_3)
LR(PowerPC::ppcState) = PowerPC::ppcState.pc + 4;
LR(ppc_state) = ppc_state.pc + 4;
}
m_end_block = true;
interpreter.m_end_block = true;
}
void Interpreter::HLEFunction(UGeckoInstruction inst)
void Interpreter::HLEFunction(Interpreter& interpreter, UGeckoInstruction inst)
{
m_end_block = true;
interpreter.m_end_block = true;
ASSERT(Core::IsCPUThread());
Core::CPUThreadGuard guard(Core::System::GetInstance());
Core::CPUThreadGuard guard(interpreter.m_system);
HLE::Execute(guard, PowerPC::ppcState.pc, inst.hex);
HLE::Execute(guard, interpreter.m_ppc_state.pc, inst.hex);
}
void Interpreter::rfi(UGeckoInstruction inst)
void Interpreter::rfi(Interpreter& interpreter, UGeckoInstruction inst)
{
if (PowerPC::ppcState.msr.PR)
auto& ppc_state = interpreter.m_ppc_state;
if (ppc_state.msr.PR)
{
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
return;
@ -115,26 +124,27 @@ 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 u32 mask = 0x87C0FFFF;
PowerPC::ppcState.msr.Hex =
(PowerPC::ppcState.msr.Hex & ~mask) | (SRR1(PowerPC::ppcState) & mask);
ppc_state.msr.Hex = (ppc_state.msr.Hex & ~mask) | (SRR1(ppc_state) & mask);
// MSR[13] is set to 0.
PowerPC::ppcState.msr.Hex &= 0xFFFBFFFF;
ppc_state.msr.Hex &= 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
PowerPC::ppcState.npc = SRR0(PowerPC::ppcState);
m_end_block = true;
ppc_state.npc = SRR0(ppc_state);
interpreter.m_end_block = 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.
// We do it anyway, though :P
void Interpreter::sc(UGeckoInstruction inst)
void Interpreter::sc(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.Exceptions |= EXCEPTION_SYSCALL;
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.Exceptions |= EXCEPTION_SYSCALL;
PowerPC::CheckExceptions();
m_end_block = true;
interpreter.m_end_block = true;
}

View File

@ -35,33 +35,34 @@ void SetFI(UReg_FPSCR* fpscr, u32 FI)
// Note that the convert to integer operation is defined
// in Appendix C.4.2 in PowerPC Microprocessor Family:
// The Programming Environments Manual for 32 and 64-bit Microprocessors
void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode)
void ConvertToInteger(PowerPC::PowerPCState& ppc_state, UGeckoInstruction inst,
RoundingMode rounding_mode)
{
const double b = PowerPC::ppcState.ps[inst.FB].PS0AsDouble();
const double b = ppc_state.ps[inst.FB].PS0AsDouble();
u32 value;
bool exception_occurred = false;
if (std::isnan(b))
{
if (Common::IsSNAN(b))
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
SetFPException(&ppc_state.fpscr, FPSCR_VXSNAN);
value = 0x80000000;
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXCVI);
SetFPException(&ppc_state.fpscr, FPSCR_VXCVI);
exception_occurred = true;
}
else if (b > static_cast<double>(0x7fffffff))
{
// Positive large operand or +inf
value = 0x7fffffff;
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXCVI);
SetFPException(&ppc_state.fpscr, FPSCR_VXCVI);
exception_occurred = true;
}
else if (b < -static_cast<double>(0x80000000))
{
// Negative large operand or -inf
value = 0x80000000;
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXCVI);
SetFPException(&ppc_state.fpscr, FPSCR_VXCVI);
exception_occurred = true;
}
else
@ -103,22 +104,22 @@ void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode)
const double di = i;
if (di == b)
{
PowerPC::ppcState.fpscr.ClearFIFR();
ppc_state.fpscr.ClearFIFR();
}
else
{
// Also sets FPSCR[XX]
SetFI(&PowerPC::ppcState.fpscr, 1);
PowerPC::ppcState.fpscr.FR = fabs(di) > fabs(b);
SetFI(&ppc_state.fpscr, 1);
ppc_state.fpscr.FR = fabs(di) > fabs(b);
}
}
if (exception_occurred)
{
PowerPC::ppcState.fpscr.ClearFIFR();
ppc_state.fpscr.ClearFIFR();
}
if (!exception_occurred || PowerPC::ppcState.fpscr.VE == 0)
if (!exception_occurred || ppc_state.fpscr.VE == 0)
{
// Based on HW tests
// FPRF is not affected
@ -126,15 +127,16 @@ void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode)
if (value == 0 && std::signbit(b))
result |= 0x100000000ull;
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
ppc_state.ps[inst.FD].SetPS0(result);
}
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
} // Anonymous namespace
void Interpreter::Helper_FloatCompareOrdered(UGeckoInstruction inst, double fa, double fb)
void Interpreter::Helper_FloatCompareOrdered(PowerPC::PowerPCState& ppc_state,
UGeckoInstruction inst, double fa, double fb)
{
FPCC compare_result;
@ -143,15 +145,15 @@ void Interpreter::Helper_FloatCompareOrdered(UGeckoInstruction inst, double fa,
compare_result = FPCC::FU;
if (Common::IsSNAN(fa) || Common::IsSNAN(fb))
{
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
if (PowerPC::ppcState.fpscr.VE == 0)
SetFPException(&ppc_state.fpscr, FPSCR_VXSNAN);
if (ppc_state.fpscr.VE == 0)
{
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXVC);
SetFPException(&ppc_state.fpscr, FPSCR_VXVC);
}
}
else // QNaN
{
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXVC);
SetFPException(&ppc_state.fpscr, FPSCR_VXVC);
}
}
else if (fa < fb)
@ -170,12 +172,13 @@ void Interpreter::Helper_FloatCompareOrdered(UGeckoInstruction inst, double fa,
const u32 compare_value = static_cast<u32>(compare_result);
// Clear and set the FPCC bits accordingly.
PowerPC::ppcState.fpscr.FPRF = (PowerPC::ppcState.fpscr.FPRF & ~FPCC_MASK) | compare_value;
ppc_state.fpscr.FPRF = (ppc_state.fpscr.FPRF & ~FPCC_MASK) | compare_value;
PowerPC::ppcState.cr.SetField(inst.CRFD, compare_value);
ppc_state.cr.SetField(inst.CRFD, compare_value);
}
void Interpreter::Helper_FloatCompareUnordered(UGeckoInstruction inst, double fa, double fb)
void Interpreter::Helper_FloatCompareUnordered(PowerPC::PowerPCState& ppc_state,
UGeckoInstruction inst, double fa, double fb)
{
FPCC compare_result;
@ -185,7 +188,7 @@ void Interpreter::Helper_FloatCompareUnordered(UGeckoInstruction inst, double fa
if (Common::IsSNAN(fa) || Common::IsSNAN(fb))
{
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
SetFPException(&ppc_state.fpscr, FPSCR_VXSNAN);
}
}
else if (fa < fb)
@ -204,532 +207,553 @@ void Interpreter::Helper_FloatCompareUnordered(UGeckoInstruction inst, double fa
const u32 compare_value = static_cast<u32>(compare_result);
// Clear and set the FPCC bits accordingly.
PowerPC::ppcState.fpscr.FPRF = (PowerPC::ppcState.fpscr.FPRF & ~FPCC_MASK) | compare_value;
ppc_state.fpscr.FPRF = (ppc_state.fpscr.FPRF & ~FPCC_MASK) | compare_value;
PowerPC::ppcState.cr.SetField(inst.CRFD, compare_value);
ppc_state.cr.SetField(inst.CRFD, compare_value);
}
void Interpreter::fcmpo(UGeckoInstruction inst)
void Interpreter::fcmpo(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
Helper_FloatCompareOrdered(inst, a.PS0AsDouble(), b.PS0AsDouble());
Helper_FloatCompareOrdered(ppc_state, inst, a.PS0AsDouble(), b.PS0AsDouble());
}
void Interpreter::fcmpu(UGeckoInstruction inst)
void Interpreter::fcmpu(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
Helper_FloatCompareUnordered(inst, a.PS0AsDouble(), b.PS0AsDouble());
Helper_FloatCompareUnordered(ppc_state, inst, a.PS0AsDouble(), b.PS0AsDouble());
}
void Interpreter::fctiwx(UGeckoInstruction inst)
void Interpreter::fctiwx(Interpreter& interpreter, UGeckoInstruction inst)
{
ConvertToInteger(inst, static_cast<RoundingMode>(PowerPC::ppcState.fpscr.RN.Value()));
auto& ppc_state = interpreter.m_ppc_state;
ConvertToInteger(ppc_state, inst, static_cast<RoundingMode>(ppc_state.fpscr.RN.Value()));
}
void Interpreter::fctiwzx(UGeckoInstruction inst)
void Interpreter::fctiwzx(Interpreter& interpreter, UGeckoInstruction inst)
{
ConvertToInteger(inst, RoundingMode::TowardsZero);
auto& ppc_state = interpreter.m_ppc_state;
ConvertToInteger(ppc_state, inst, RoundingMode::TowardsZero);
}
void Interpreter::fmrx(UGeckoInstruction inst)
void Interpreter::fmrx(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.ps[inst.FD].SetPS0(PowerPC::ppcState.ps[inst.FB].PS0AsU64());
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.ps[inst.FD].SetPS0(ppc_state.ps[inst.FB].PS0AsU64());
// This is a binary instruction. Does not alter FPSCR
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::fabsx(UGeckoInstruction inst)
void Interpreter::fabsx(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.ps[inst.FD].SetPS0(fabs(PowerPC::ppcState.ps[inst.FB].PS0AsDouble()));
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.ps[inst.FD].SetPS0(fabs(ppc_state.ps[inst.FB].PS0AsDouble()));
// This is a binary instruction. Does not alter FPSCR
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::fnabsx(UGeckoInstruction inst)
void Interpreter::fnabsx(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.ps[inst.FD].SetPS0(PowerPC::ppcState.ps[inst.FB].PS0AsU64() |
(UINT64_C(1) << 63));
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.ps[inst.FD].SetPS0(ppc_state.ps[inst.FB].PS0AsU64() | (UINT64_C(1) << 63));
// This is a binary instruction. Does not alter FPSCR
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::fnegx(UGeckoInstruction inst)
void Interpreter::fnegx(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.ps[inst.FD].SetPS0(PowerPC::ppcState.ps[inst.FB].PS0AsU64() ^
(UINT64_C(1) << 63));
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.ps[inst.FD].SetPS0(ppc_state.ps[inst.FB].PS0AsU64() ^ (UINT64_C(1) << 63));
// This is a binary instruction. Does not alter FPSCR
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::fselx(UGeckoInstruction inst)
void Interpreter::fselx(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = PowerPC::ppcState.ps[inst.FC];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const auto& c = ppc_state.ps[inst.FC];
PowerPC::ppcState.ps[inst.FD].SetPS0((a.PS0AsDouble() >= -0.0) ? c.PS0AsDouble() :
b.PS0AsDouble());
ppc_state.ps[inst.FD].SetPS0((a.PS0AsDouble() >= -0.0) ? c.PS0AsDouble() : b.PS0AsDouble());
// This is a binary instruction. Does not alter FPSCR
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
// !!! warning !!!
// PS1 must be set to the value of PS0 or DragonballZ will be f**ked up
// PS1 is said to be undefined
void Interpreter::frspx(UGeckoInstruction inst) // round to single
void Interpreter::frspx(Interpreter& interpreter, UGeckoInstruction inst) // round to single
{
const double b = PowerPC::ppcState.ps[inst.FB].PS0AsDouble();
const float rounded = ForceSingle(PowerPC::ppcState.fpscr, b);
auto& ppc_state = interpreter.m_ppc_state;
const double b = ppc_state.ps[inst.FB].PS0AsDouble();
const float rounded = ForceSingle(ppc_state.fpscr, b);
if (std::isnan(b))
{
const bool is_snan = Common::IsSNAN(b);
if (is_snan)
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
SetFPException(&ppc_state.fpscr, FPSCR_VXSNAN);
if (!is_snan || PowerPC::ppcState.fpscr.VE == 0)
if (!is_snan || ppc_state.fpscr.VE == 0)
{
PowerPC::ppcState.ps[inst.FD].Fill(rounded);
PowerPC::ppcState.UpdateFPRFSingle(rounded);
ppc_state.ps[inst.FD].Fill(rounded);
ppc_state.UpdateFPRFSingle(rounded);
}
PowerPC::ppcState.fpscr.ClearFIFR();
ppc_state.fpscr.ClearFIFR();
}
else
{
SetFI(&PowerPC::ppcState.fpscr, b != rounded);
PowerPC::ppcState.fpscr.FR = fabs(rounded) > fabs(b);
PowerPC::ppcState.UpdateFPRFSingle(rounded);
PowerPC::ppcState.ps[inst.FD].Fill(rounded);
SetFI(&ppc_state.fpscr, b != rounded);
ppc_state.fpscr.FR = fabs(rounded) > fabs(b);
ppc_state.UpdateFPRFSingle(rounded);
ppc_state.ps[inst.FD].Fill(rounded);
}
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::fmulx(UGeckoInstruction inst)
void Interpreter::fmulx(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& c = PowerPC::ppcState.ps[inst.FC];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& c = ppc_state.ps[inst.FC];
const FPResult product = NI_mul(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c.PS0AsDouble());
const FPResult product = NI_mul(&ppc_state.fpscr, a.PS0AsDouble(), c.PS0AsDouble());
if (PowerPC::ppcState.fpscr.VE == 0 || product.HasNoInvalidExceptions())
if (ppc_state.fpscr.VE == 0 || product.HasNoInvalidExceptions())
{
const double result = ForceDouble(PowerPC::ppcState.fpscr, product.value);
const double result = ForceDouble(ppc_state.fpscr, product.value);
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
PowerPC::ppcState.fpscr.FI = 0; // are these flags important?
PowerPC::ppcState.fpscr.FR = 0;
PowerPC::ppcState.UpdateFPRFDouble(result);
ppc_state.ps[inst.FD].SetPS0(result);
ppc_state.fpscr.FI = 0; // are these flags important?
ppc_state.fpscr.FR = 0;
ppc_state.UpdateFPRFDouble(result);
}
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::fmulsx(UGeckoInstruction inst)
void Interpreter::fmulsx(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& c = PowerPC::ppcState.ps[inst.FC];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& c = ppc_state.ps[inst.FC];
const double c_value = Force25Bit(c.PS0AsDouble());
const FPResult d_value = NI_mul(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c_value);
const FPResult d_value = NI_mul(&ppc_state.fpscr, a.PS0AsDouble(), c_value);
if (PowerPC::ppcState.fpscr.VE == 0 || d_value.HasNoInvalidExceptions())
if (ppc_state.fpscr.VE == 0 || d_value.HasNoInvalidExceptions())
{
const float result = ForceSingle(PowerPC::ppcState.fpscr, d_value.value);
const float result = ForceSingle(ppc_state.fpscr, d_value.value);
PowerPC::ppcState.ps[inst.FD].Fill(result);
PowerPC::ppcState.fpscr.FI = 0;
PowerPC::ppcState.fpscr.FR = 0;
PowerPC::ppcState.UpdateFPRFSingle(result);
ppc_state.ps[inst.FD].Fill(result);
ppc_state.fpscr.FI = 0;
ppc_state.fpscr.FR = 0;
ppc_state.UpdateFPRFSingle(result);
}
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::fmaddx(UGeckoInstruction inst)
void Interpreter::fmaddx(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = PowerPC::ppcState.ps[inst.FC];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const auto& c = ppc_state.ps[inst.FC];
const FPResult product =
NI_madd(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble());
NI_madd(&ppc_state.fpscr, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble());
if (PowerPC::ppcState.fpscr.VE == 0 || product.HasNoInvalidExceptions())
if (ppc_state.fpscr.VE == 0 || product.HasNoInvalidExceptions())
{
const double result = ForceDouble(PowerPC::ppcState.fpscr, product.value);
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
PowerPC::ppcState.UpdateFPRFDouble(result);
const double result = ForceDouble(ppc_state.fpscr, product.value);
ppc_state.ps[inst.FD].SetPS0(result);
ppc_state.UpdateFPRFDouble(result);
}
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::fmaddsx(UGeckoInstruction inst)
void Interpreter::fmaddsx(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = PowerPC::ppcState.ps[inst.FC];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const auto& c = ppc_state.ps[inst.FC];
const double c_value = Force25Bit(c.PS0AsDouble());
const FPResult d_value =
NI_madd(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c_value, b.PS0AsDouble());
const FPResult d_value = NI_madd(&ppc_state.fpscr, a.PS0AsDouble(), c_value, b.PS0AsDouble());
if (PowerPC::ppcState.fpscr.VE == 0 || d_value.HasNoInvalidExceptions())
if (ppc_state.fpscr.VE == 0 || d_value.HasNoInvalidExceptions())
{
const float result = ForceSingle(PowerPC::ppcState.fpscr, d_value.value);
const float result = ForceSingle(ppc_state.fpscr, d_value.value);
PowerPC::ppcState.ps[inst.FD].Fill(result);
PowerPC::ppcState.fpscr.FI = d_value.value != result;
PowerPC::ppcState.fpscr.FR = 0;
PowerPC::ppcState.UpdateFPRFSingle(result);
ppc_state.ps[inst.FD].Fill(result);
ppc_state.fpscr.FI = d_value.value != result;
ppc_state.fpscr.FR = 0;
ppc_state.UpdateFPRFSingle(result);
}
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::faddx(UGeckoInstruction inst)
void Interpreter::faddx(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const FPResult sum = NI_add(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
const FPResult sum = NI_add(&ppc_state.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
if (PowerPC::ppcState.fpscr.VE == 0 || sum.HasNoInvalidExceptions())
if (ppc_state.fpscr.VE == 0 || sum.HasNoInvalidExceptions())
{
const double result = ForceDouble(PowerPC::ppcState.fpscr, sum.value);
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
PowerPC::ppcState.UpdateFPRFDouble(result);
const double result = ForceDouble(ppc_state.fpscr, sum.value);
ppc_state.ps[inst.FD].SetPS0(result);
ppc_state.UpdateFPRFDouble(result);
}
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::faddsx(UGeckoInstruction inst)
void Interpreter::faddsx(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const FPResult sum = NI_add(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
const FPResult sum = NI_add(&ppc_state.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
if (PowerPC::ppcState.fpscr.VE == 0 || sum.HasNoInvalidExceptions())
if (ppc_state.fpscr.VE == 0 || sum.HasNoInvalidExceptions())
{
const float result = ForceSingle(PowerPC::ppcState.fpscr, sum.value);
PowerPC::ppcState.ps[inst.FD].Fill(result);
PowerPC::ppcState.UpdateFPRFSingle(result);
const float result = ForceSingle(ppc_state.fpscr, sum.value);
ppc_state.ps[inst.FD].Fill(result);
ppc_state.UpdateFPRFSingle(result);
}
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::fdivx(UGeckoInstruction inst)
void Interpreter::fdivx(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const FPResult quotient = NI_div(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
const bool not_divide_by_zero = PowerPC::ppcState.fpscr.ZE == 0 || quotient.exception != FPSCR_ZX;
const bool not_invalid = PowerPC::ppcState.fpscr.VE == 0 || quotient.HasNoInvalidExceptions();
const FPResult quotient = NI_div(&ppc_state.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
const bool not_divide_by_zero = ppc_state.fpscr.ZE == 0 || quotient.exception != FPSCR_ZX;
const bool not_invalid = ppc_state.fpscr.VE == 0 || quotient.HasNoInvalidExceptions();
if (not_divide_by_zero && not_invalid)
{
const double result = ForceDouble(PowerPC::ppcState.fpscr, quotient.value);
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
PowerPC::ppcState.UpdateFPRFDouble(result);
const double result = ForceDouble(ppc_state.fpscr, quotient.value);
ppc_state.ps[inst.FD].SetPS0(result);
ppc_state.UpdateFPRFDouble(result);
}
// FR,FI,OX,UX???
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::fdivsx(UGeckoInstruction inst)
void Interpreter::fdivsx(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const FPResult quotient = NI_div(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
const bool not_divide_by_zero = PowerPC::ppcState.fpscr.ZE == 0 || quotient.exception != FPSCR_ZX;
const bool not_invalid = PowerPC::ppcState.fpscr.VE == 0 || quotient.HasNoInvalidExceptions();
const FPResult quotient = NI_div(&ppc_state.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
const bool not_divide_by_zero = ppc_state.fpscr.ZE == 0 || quotient.exception != FPSCR_ZX;
const bool not_invalid = ppc_state.fpscr.VE == 0 || quotient.HasNoInvalidExceptions();
if (not_divide_by_zero && not_invalid)
{
const float result = ForceSingle(PowerPC::ppcState.fpscr, quotient.value);
PowerPC::ppcState.ps[inst.FD].Fill(result);
PowerPC::ppcState.UpdateFPRFSingle(result);
const float result = ForceSingle(ppc_state.fpscr, quotient.value);
ppc_state.ps[inst.FD].Fill(result);
ppc_state.UpdateFPRFSingle(result);
}
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
// Single precision only.
void Interpreter::fresx(UGeckoInstruction inst)
void Interpreter::fresx(Interpreter& interpreter, UGeckoInstruction inst)
{
const double b = PowerPC::ppcState.ps[inst.FB].PS0AsDouble();
auto& ppc_state = interpreter.m_ppc_state;
const double b = ppc_state.ps[inst.FB].PS0AsDouble();
const auto compute_result = [inst](double value) {
const auto compute_result = [&ppc_state, inst](double value) {
const double result = Common::ApproximateReciprocal(value);
PowerPC::ppcState.ps[inst.FD].Fill(result);
PowerPC::ppcState.UpdateFPRFSingle(float(result));
ppc_state.ps[inst.FD].Fill(result);
ppc_state.UpdateFPRFSingle(float(result));
};
if (b == 0.0)
{
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_ZX);
PowerPC::ppcState.fpscr.ClearFIFR();
SetFPException(&ppc_state.fpscr, FPSCR_ZX);
ppc_state.fpscr.ClearFIFR();
if (PowerPC::ppcState.fpscr.ZE == 0)
if (ppc_state.fpscr.ZE == 0)
compute_result(b);
}
else if (Common::IsSNAN(b))
{
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
PowerPC::ppcState.fpscr.ClearFIFR();
SetFPException(&ppc_state.fpscr, FPSCR_VXSNAN);
ppc_state.fpscr.ClearFIFR();
if (PowerPC::ppcState.fpscr.VE == 0)
if (ppc_state.fpscr.VE == 0)
compute_result(b);
}
else
{
if (std::isnan(b) || std::isinf(b))
PowerPC::ppcState.fpscr.ClearFIFR();
ppc_state.fpscr.ClearFIFR();
compute_result(b);
}
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::frsqrtex(UGeckoInstruction inst)
void Interpreter::frsqrtex(Interpreter& interpreter, UGeckoInstruction inst)
{
const double b = PowerPC::ppcState.ps[inst.FB].PS0AsDouble();
auto& ppc_state = interpreter.m_ppc_state;
const double b = ppc_state.ps[inst.FB].PS0AsDouble();
const auto compute_result = [inst](double value) {
const auto compute_result = [&ppc_state, inst](double value) {
const double result = Common::ApproximateReciprocalSquareRoot(value);
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
PowerPC::ppcState.UpdateFPRFDouble(result);
ppc_state.ps[inst.FD].SetPS0(result);
ppc_state.UpdateFPRFDouble(result);
};
if (b < 0.0)
{
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSQRT);
PowerPC::ppcState.fpscr.ClearFIFR();
SetFPException(&ppc_state.fpscr, FPSCR_VXSQRT);
ppc_state.fpscr.ClearFIFR();
if (PowerPC::ppcState.fpscr.VE == 0)
if (ppc_state.fpscr.VE == 0)
compute_result(b);
}
else if (b == 0.0)
{
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_ZX);
PowerPC::ppcState.fpscr.ClearFIFR();
SetFPException(&ppc_state.fpscr, FPSCR_ZX);
ppc_state.fpscr.ClearFIFR();
if (PowerPC::ppcState.fpscr.ZE == 0)
if (ppc_state.fpscr.ZE == 0)
compute_result(b);
}
else if (Common::IsSNAN(b))
{
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
PowerPC::ppcState.fpscr.ClearFIFR();
SetFPException(&ppc_state.fpscr, FPSCR_VXSNAN);
ppc_state.fpscr.ClearFIFR();
if (PowerPC::ppcState.fpscr.VE == 0)
if (ppc_state.fpscr.VE == 0)
compute_result(b);
}
else
{
if (std::isnan(b) || std::isinf(b))
PowerPC::ppcState.fpscr.ClearFIFR();
ppc_state.fpscr.ClearFIFR();
compute_result(b);
}
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::fmsubx(UGeckoInstruction inst)
void Interpreter::fmsubx(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = PowerPC::ppcState.ps[inst.FC];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const auto& c = ppc_state.ps[inst.FC];
const FPResult product =
NI_msub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble());
NI_msub(&ppc_state.fpscr, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble());
if (PowerPC::ppcState.fpscr.VE == 0 || product.HasNoInvalidExceptions())
if (ppc_state.fpscr.VE == 0 || product.HasNoInvalidExceptions())
{
const double result = ForceDouble(PowerPC::ppcState.fpscr, product.value);
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
PowerPC::ppcState.UpdateFPRFDouble(result);
const double result = ForceDouble(ppc_state.fpscr, product.value);
ppc_state.ps[inst.FD].SetPS0(result);
ppc_state.UpdateFPRFDouble(result);
}
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::fmsubsx(UGeckoInstruction inst)
void Interpreter::fmsubsx(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = PowerPC::ppcState.ps[inst.FC];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const auto& c = ppc_state.ps[inst.FC];
const double c_value = Force25Bit(c.PS0AsDouble());
const FPResult product =
NI_msub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c_value, b.PS0AsDouble());
const FPResult product = NI_msub(&ppc_state.fpscr, a.PS0AsDouble(), c_value, b.PS0AsDouble());
if (PowerPC::ppcState.fpscr.VE == 0 || product.HasNoInvalidExceptions())
if (ppc_state.fpscr.VE == 0 || product.HasNoInvalidExceptions())
{
const float result = ForceSingle(PowerPC::ppcState.fpscr, product.value);
PowerPC::ppcState.ps[inst.FD].Fill(result);
PowerPC::ppcState.UpdateFPRFSingle(result);
const float result = ForceSingle(ppc_state.fpscr, product.value);
ppc_state.ps[inst.FD].Fill(result);
ppc_state.UpdateFPRFSingle(result);
}
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::fnmaddx(UGeckoInstruction inst)
void Interpreter::fnmaddx(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = PowerPC::ppcState.ps[inst.FC];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const auto& c = ppc_state.ps[inst.FC];
const FPResult product =
NI_madd(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble());
NI_madd(&ppc_state.fpscr, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble());
if (PowerPC::ppcState.fpscr.VE == 0 || product.HasNoInvalidExceptions())
if (ppc_state.fpscr.VE == 0 || product.HasNoInvalidExceptions())
{
const double tmp = ForceDouble(PowerPC::ppcState.fpscr, product.value);
const double tmp = ForceDouble(ppc_state.fpscr, product.value);
const double result = std::isnan(tmp) ? tmp : -tmp;
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
PowerPC::ppcState.UpdateFPRFDouble(result);
ppc_state.ps[inst.FD].SetPS0(result);
ppc_state.UpdateFPRFDouble(result);
}
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::fnmaddsx(UGeckoInstruction inst)
void Interpreter::fnmaddsx(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = PowerPC::ppcState.ps[inst.FC];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const auto& c = ppc_state.ps[inst.FC];
const double c_value = Force25Bit(c.PS0AsDouble());
const FPResult product =
NI_madd(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c_value, b.PS0AsDouble());
const FPResult product = NI_madd(&ppc_state.fpscr, a.PS0AsDouble(), c_value, b.PS0AsDouble());
if (PowerPC::ppcState.fpscr.VE == 0 || product.HasNoInvalidExceptions())
if (ppc_state.fpscr.VE == 0 || product.HasNoInvalidExceptions())
{
const float tmp = ForceSingle(PowerPC::ppcState.fpscr, product.value);
const float tmp = ForceSingle(ppc_state.fpscr, product.value);
const float result = std::isnan(tmp) ? tmp : -tmp;
PowerPC::ppcState.ps[inst.FD].Fill(result);
PowerPC::ppcState.UpdateFPRFSingle(result);
ppc_state.ps[inst.FD].Fill(result);
ppc_state.UpdateFPRFSingle(result);
}
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::fnmsubx(UGeckoInstruction inst)
void Interpreter::fnmsubx(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = PowerPC::ppcState.ps[inst.FC];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const auto& c = ppc_state.ps[inst.FC];
const FPResult product =
NI_msub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble());
NI_msub(&ppc_state.fpscr, a.PS0AsDouble(), c.PS0AsDouble(), b.PS0AsDouble());
if (PowerPC::ppcState.fpscr.VE == 0 || product.HasNoInvalidExceptions())
if (ppc_state.fpscr.VE == 0 || product.HasNoInvalidExceptions())
{
const double tmp = ForceDouble(PowerPC::ppcState.fpscr, product.value);
const double tmp = ForceDouble(ppc_state.fpscr, product.value);
const double result = std::isnan(tmp) ? tmp : -tmp;
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
PowerPC::ppcState.UpdateFPRFDouble(result);
ppc_state.ps[inst.FD].SetPS0(result);
ppc_state.UpdateFPRFDouble(result);
}
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::fnmsubsx(UGeckoInstruction inst)
void Interpreter::fnmsubsx(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = PowerPC::ppcState.ps[inst.FC];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const auto& c = ppc_state.ps[inst.FC];
const double c_value = Force25Bit(c.PS0AsDouble());
const FPResult product =
NI_msub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c_value, b.PS0AsDouble());
const FPResult product = NI_msub(&ppc_state.fpscr, a.PS0AsDouble(), c_value, b.PS0AsDouble());
if (PowerPC::ppcState.fpscr.VE == 0 || product.HasNoInvalidExceptions())
if (ppc_state.fpscr.VE == 0 || product.HasNoInvalidExceptions())
{
const float tmp = ForceSingle(PowerPC::ppcState.fpscr, product.value);
const float tmp = ForceSingle(ppc_state.fpscr, product.value);
const float result = std::isnan(tmp) ? tmp : -tmp;
PowerPC::ppcState.ps[inst.FD].Fill(result);
PowerPC::ppcState.UpdateFPRFSingle(result);
ppc_state.ps[inst.FD].Fill(result);
ppc_state.UpdateFPRFSingle(result);
}
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::fsubx(UGeckoInstruction inst)
void Interpreter::fsubx(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const FPResult difference = NI_sub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
const FPResult difference = NI_sub(&ppc_state.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
if (PowerPC::ppcState.fpscr.VE == 0 || difference.HasNoInvalidExceptions())
if (ppc_state.fpscr.VE == 0 || difference.HasNoInvalidExceptions())
{
const double result = ForceDouble(PowerPC::ppcState.fpscr, difference.value);
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
PowerPC::ppcState.UpdateFPRFDouble(result);
const double result = ForceDouble(ppc_state.fpscr, difference.value);
ppc_state.ps[inst.FD].SetPS0(result);
ppc_state.UpdateFPRFDouble(result);
}
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::fsubsx(UGeckoInstruction inst)
void Interpreter::fsubsx(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const FPResult difference = NI_sub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
const FPResult difference = NI_sub(&ppc_state.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
if (PowerPC::ppcState.fpscr.VE == 0 || difference.HasNoInvalidExceptions())
if (ppc_state.fpscr.VE == 0 || difference.HasNoInvalidExceptions())
{
const float result = ForceSingle(PowerPC::ppcState.fpscr, difference.value);
PowerPC::ppcState.ps[inst.FD].Fill(result);
PowerPC::ppcState.UpdateFPRFSingle(result);
const float result = ForceSingle(ppc_state.fpscr, difference.value);
ppc_state.ps[inst.FD].Fill(result);
ppc_state.UpdateFPRFSingle(result);
}
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}

View File

@ -11,14 +11,14 @@
#include "Core/PowerPC/Interpreter/ExceptionUtils.h"
#include "Core/PowerPC/PowerPC.h"
void Interpreter::Helper_UpdateCR0(u32 value)
void Interpreter::Helper_UpdateCR0(PowerPC::PowerPCState& ppc_state, u32 value)
{
const s64 sign_extended = s64{s32(value)};
u64 cr_val = u64(sign_extended);
cr_val = (cr_val & ~(1ULL << PowerPC::CR_EMU_SO_BIT)) |
(u64{PowerPC::ppcState.GetXER_SO()} << PowerPC::CR_EMU_SO_BIT);
(u64{ppc_state.GetXER_SO()} << PowerPC::CR_EMU_SO_BIT);
PowerPC::ppcState.cr.fields[0] = cr_val;
ppc_state.cr.fields[0] = cr_val;
}
u32 Interpreter::Helper_Carry(u32 value1, u32 value2)
@ -26,51 +26,58 @@ u32 Interpreter::Helper_Carry(u32 value1, u32 value2)
return value2 > (~value1);
}
void Interpreter::addi(UGeckoInstruction inst)
void Interpreter::addi(Interpreter& interpreter, UGeckoInstruction inst)
{
auto& ppc_state = interpreter.m_ppc_state;
if (inst.RA)
PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.gpr[inst.RA] + u32(inst.SIMM_16);
ppc_state.gpr[inst.RD] = ppc_state.gpr[inst.RA] + u32(inst.SIMM_16);
else
PowerPC::ppcState.gpr[inst.RD] = u32(inst.SIMM_16);
ppc_state.gpr[inst.RD] = u32(inst.SIMM_16);
}
void Interpreter::addic(UGeckoInstruction inst)
void Interpreter::addic(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 a = PowerPC::ppcState.gpr[inst.RA];
auto& ppc_state = interpreter.m_ppc_state;
const u32 a = ppc_state.gpr[inst.RA];
const u32 imm = u32(s32{inst.SIMM_16});
PowerPC::ppcState.gpr[inst.RD] = a + imm;
PowerPC::ppcState.SetCarry(Helper_Carry(a, imm));
ppc_state.gpr[inst.RD] = a + imm;
ppc_state.SetCarry(Helper_Carry(a, imm));
}
void Interpreter::addic_rc(UGeckoInstruction inst)
void Interpreter::addic_rc(Interpreter& interpreter, UGeckoInstruction inst)
{
addic(inst);
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RD]);
addic(interpreter, inst);
auto& ppc_state = interpreter.m_ppc_state;
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RD]);
}
void Interpreter::addis(UGeckoInstruction inst)
void Interpreter::addis(Interpreter& interpreter, UGeckoInstruction inst)
{
auto& ppc_state = interpreter.m_ppc_state;
if (inst.RA)
PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.gpr[inst.RA] + u32(inst.SIMM_16 << 16);
ppc_state.gpr[inst.RD] = ppc_state.gpr[inst.RA] + u32(inst.SIMM_16 << 16);
else
PowerPC::ppcState.gpr[inst.RD] = u32(inst.SIMM_16 << 16);
ppc_state.gpr[inst.RD] = u32(inst.SIMM_16 << 16);
}
void Interpreter::andi_rc(UGeckoInstruction inst)
void Interpreter::andi_rc(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] & inst.UIMM;
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RA] = ppc_state.gpr[inst.RS] & inst.UIMM;
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RA]);
}
void Interpreter::andis_rc(UGeckoInstruction inst)
void Interpreter::andis_rc(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] & (u32{inst.UIMM} << 16);
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RA] = ppc_state.gpr[inst.RS] & (u32{inst.UIMM} << 16);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RA]);
}
template <typename T>
void Interpreter::Helper_IntCompare(UGeckoInstruction inst, T a, T b)
void Interpreter::Helper_IntCompare(PowerPC::PowerPCState& ppc_state, UGeckoInstruction inst, T a,
T b)
{
u32 cr_field;
@ -81,52 +88,59 @@ void Interpreter::Helper_IntCompare(UGeckoInstruction inst, T a, T b)
else
cr_field = PowerPC::CR_EQ;
if (PowerPC::ppcState.GetXER_SO())
if (ppc_state.GetXER_SO())
cr_field |= PowerPC::CR_SO;
PowerPC::ppcState.cr.SetField(inst.CRFD, cr_field);
ppc_state.cr.SetField(inst.CRFD, cr_field);
}
void Interpreter::cmpi(UGeckoInstruction inst)
void Interpreter::cmpi(Interpreter& interpreter, UGeckoInstruction inst)
{
const s32 a = static_cast<s32>(PowerPC::ppcState.gpr[inst.RA]);
auto& ppc_state = interpreter.m_ppc_state;
const s32 a = static_cast<s32>(ppc_state.gpr[inst.RA]);
const s32 b = inst.SIMM_16;
Helper_IntCompare(inst, a, b);
Helper_IntCompare(ppc_state, inst, a, b);
}
void Interpreter::cmpli(UGeckoInstruction inst)
void Interpreter::cmpli(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 a = PowerPC::ppcState.gpr[inst.RA];
auto& ppc_state = interpreter.m_ppc_state;
const u32 a = ppc_state.gpr[inst.RA];
const u32 b = inst.UIMM;
Helper_IntCompare(inst, a, b);
Helper_IntCompare(ppc_state, inst, a, b);
}
void Interpreter::mulli(UGeckoInstruction inst)
void Interpreter::mulli(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.gpr[inst.RD] = u32(s32(PowerPC::ppcState.gpr[inst.RA]) * inst.SIMM_16);
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RD] = u32(s32(ppc_state.gpr[inst.RA]) * inst.SIMM_16);
}
void Interpreter::ori(UGeckoInstruction inst)
void Interpreter::ori(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] | inst.UIMM;
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RA] = ppc_state.gpr[inst.RS] | inst.UIMM;
}
void Interpreter::oris(UGeckoInstruction inst)
void Interpreter::oris(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] | (u32{inst.UIMM} << 16);
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RA] = ppc_state.gpr[inst.RS] | (u32{inst.UIMM} << 16);
}
void Interpreter::subfic(UGeckoInstruction inst)
void Interpreter::subfic(Interpreter& interpreter, UGeckoInstruction inst)
{
auto& ppc_state = interpreter.m_ppc_state;
const s32 immediate = inst.SIMM_16;
PowerPC::ppcState.gpr[inst.RD] = u32(immediate - s32(PowerPC::ppcState.gpr[inst.RA]));
PowerPC::ppcState.SetCarry((PowerPC::ppcState.gpr[inst.RA] == 0) ||
(Helper_Carry(0 - PowerPC::ppcState.gpr[inst.RA], u32(immediate))));
ppc_state.gpr[inst.RD] = u32(immediate - s32(ppc_state.gpr[inst.RA]));
ppc_state.SetCarry((ppc_state.gpr[inst.RA] == 0) ||
(Helper_Carry(0 - ppc_state.gpr[inst.RA], u32(immediate))));
}
void Interpreter::twi(UGeckoInstruction inst)
void Interpreter::twi(Interpreter& interpreter, UGeckoInstruction inst)
{
const s32 a = s32(PowerPC::ppcState.gpr[inst.RA]);
auto& ppc_state = interpreter.m_ppc_state;
const s32 a = s32(ppc_state.gpr[inst.RA]);
const s32 b = inst.SIMM_16;
const u32 TO = inst.TO;
@ -137,213 +151,228 @@ void Interpreter::twi(UGeckoInstruction inst)
{
GenerateProgramException(ProgramExceptionCause::Trap);
PowerPC::CheckExceptions();
m_end_block = true; // Dunno about this
interpreter.m_end_block = true; // Dunno about this
}
}
void Interpreter::xori(UGeckoInstruction inst)
void Interpreter::xori(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] ^ inst.UIMM;
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RA] = ppc_state.gpr[inst.RS] ^ inst.UIMM;
}
void Interpreter::xoris(UGeckoInstruction inst)
void Interpreter::xoris(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] ^ (u32{inst.UIMM} << 16);
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RA] = ppc_state.gpr[inst.RS] ^ (u32{inst.UIMM} << 16);
}
void Interpreter::rlwimix(UGeckoInstruction inst)
void Interpreter::rlwimix(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 mask = MakeRotationMask(inst.MB, inst.ME);
PowerPC::ppcState.gpr[inst.RA] = (PowerPC::ppcState.gpr[inst.RA] & ~mask) |
(std::rotl(PowerPC::ppcState.gpr[inst.RS], inst.SH) & mask);
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RA] =
(ppc_state.gpr[inst.RA] & ~mask) | (std::rotl(ppc_state.gpr[inst.RS], inst.SH) & mask);
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RA]);
}
void Interpreter::rlwinmx(UGeckoInstruction inst)
void Interpreter::rlwinmx(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 mask = MakeRotationMask(inst.MB, inst.ME);
PowerPC::ppcState.gpr[inst.RA] = std::rotl(PowerPC::ppcState.gpr[inst.RS], inst.SH) & mask;
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RA] = std::rotl(ppc_state.gpr[inst.RS], inst.SH) & mask;
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RA]);
}
void Interpreter::rlwnmx(UGeckoInstruction inst)
void Interpreter::rlwnmx(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 mask = MakeRotationMask(inst.MB, inst.ME);
PowerPC::ppcState.gpr[inst.RA] =
std::rotl(PowerPC::ppcState.gpr[inst.RS], PowerPC::ppcState.gpr[inst.RB] & 0x1F) & mask;
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RA] = std::rotl(ppc_state.gpr[inst.RS], ppc_state.gpr[inst.RB] & 0x1F) & mask;
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RA]);
}
void Interpreter::andx(UGeckoInstruction inst)
void Interpreter::andx(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] & PowerPC::ppcState.gpr[inst.RB];
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RA] = ppc_state.gpr[inst.RS] & ppc_state.gpr[inst.RB];
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RA]);
}
void Interpreter::andcx(UGeckoInstruction inst)
void Interpreter::andcx(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] & ~PowerPC::ppcState.gpr[inst.RB];
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RA] = ppc_state.gpr[inst.RS] & ~ppc_state.gpr[inst.RB];
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RA]);
}
void Interpreter::cmp(UGeckoInstruction inst)
void Interpreter::cmp(Interpreter& interpreter, UGeckoInstruction inst)
{
const s32 a = static_cast<s32>(PowerPC::ppcState.gpr[inst.RA]);
const s32 b = static_cast<s32>(PowerPC::ppcState.gpr[inst.RB]);
Helper_IntCompare(inst, a, b);
auto& ppc_state = interpreter.m_ppc_state;
const s32 a = static_cast<s32>(ppc_state.gpr[inst.RA]);
const s32 b = static_cast<s32>(ppc_state.gpr[inst.RB]);
Helper_IntCompare(ppc_state, inst, a, b);
}
void Interpreter::cmpl(UGeckoInstruction inst)
void Interpreter::cmpl(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 a = PowerPC::ppcState.gpr[inst.RA];
const u32 b = PowerPC::ppcState.gpr[inst.RB];
Helper_IntCompare(inst, a, b);
auto& ppc_state = interpreter.m_ppc_state;
const u32 a = ppc_state.gpr[inst.RA];
const u32 b = ppc_state.gpr[inst.RB];
Helper_IntCompare(ppc_state, inst, a, b);
}
void Interpreter::cntlzwx(UGeckoInstruction inst)
void Interpreter::cntlzwx(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.gpr[inst.RA] = u32(std::countl_zero(PowerPC::ppcState.gpr[inst.RS]));
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RA] = u32(std::countl_zero(ppc_state.gpr[inst.RS]));
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RA]);
}
void Interpreter::eqvx(UGeckoInstruction inst)
void Interpreter::eqvx(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.gpr[inst.RA] =
~(PowerPC::ppcState.gpr[inst.RS] ^ PowerPC::ppcState.gpr[inst.RB]);
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RA] = ~(ppc_state.gpr[inst.RS] ^ ppc_state.gpr[inst.RB]);
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RA]);
}
void Interpreter::extsbx(UGeckoInstruction inst)
void Interpreter::extsbx(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.gpr[inst.RA] = u32(s32(s8(PowerPC::ppcState.gpr[inst.RS])));
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RA] = u32(s32(s8(ppc_state.gpr[inst.RS])));
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RA]);
}
void Interpreter::extshx(UGeckoInstruction inst)
void Interpreter::extshx(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.gpr[inst.RA] = u32(s32(s16(PowerPC::ppcState.gpr[inst.RS])));
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RA] = u32(s32(s16(ppc_state.gpr[inst.RS])));
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RA]);
}
void Interpreter::nandx(UGeckoInstruction inst)
void Interpreter::nandx(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.gpr[inst.RA] =
~(PowerPC::ppcState.gpr[inst.RS] & PowerPC::ppcState.gpr[inst.RB]);
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RA] = ~(ppc_state.gpr[inst.RS] & ppc_state.gpr[inst.RB]);
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RA]);
}
void Interpreter::norx(UGeckoInstruction inst)
void Interpreter::norx(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.gpr[inst.RA] =
~(PowerPC::ppcState.gpr[inst.RS] | PowerPC::ppcState.gpr[inst.RB]);
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RA] = ~(ppc_state.gpr[inst.RS] | ppc_state.gpr[inst.RB]);
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RA]);
}
void Interpreter::orx(UGeckoInstruction inst)
void Interpreter::orx(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] | PowerPC::ppcState.gpr[inst.RB];
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RA] = ppc_state.gpr[inst.RS] | ppc_state.gpr[inst.RB];
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RA]);
}
void Interpreter::orcx(UGeckoInstruction inst)
void Interpreter::orcx(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.gpr[inst.RA] =
PowerPC::ppcState.gpr[inst.RS] | (~PowerPC::ppcState.gpr[inst.RB]);
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RA] = ppc_state.gpr[inst.RS] | (~ppc_state.gpr[inst.RB]);
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RA]);
}
void Interpreter::slwx(UGeckoInstruction inst)
void Interpreter::slwx(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 amount = PowerPC::ppcState.gpr[inst.RB];
PowerPC::ppcState.gpr[inst.RA] =
(amount & 0x20) != 0 ? 0 : PowerPC::ppcState.gpr[inst.RS] << (amount & 0x1f);
auto& ppc_state = interpreter.m_ppc_state;
const u32 amount = ppc_state.gpr[inst.RB];
ppc_state.gpr[inst.RA] = (amount & 0x20) != 0 ? 0 : ppc_state.gpr[inst.RS] << (amount & 0x1f);
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RA]);
}
void Interpreter::srawx(UGeckoInstruction inst)
void Interpreter::srawx(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 rb = PowerPC::ppcState.gpr[inst.RB];
auto& ppc_state = interpreter.m_ppc_state;
const u32 rb = ppc_state.gpr[inst.RB];
if ((rb & 0x20) != 0)
{
if ((PowerPC::ppcState.gpr[inst.RS] & 0x80000000) != 0)
if ((ppc_state.gpr[inst.RS] & 0x80000000) != 0)
{
PowerPC::ppcState.gpr[inst.RA] = 0xFFFFFFFF;
PowerPC::ppcState.SetCarry(1);
ppc_state.gpr[inst.RA] = 0xFFFFFFFF;
ppc_state.SetCarry(1);
}
else
{
PowerPC::ppcState.gpr[inst.RA] = 0x00000000;
PowerPC::ppcState.SetCarry(0);
ppc_state.gpr[inst.RA] = 0x00000000;
ppc_state.SetCarry(0);
}
}
else
{
const u32 amount = rb & 0x1f;
const s32 rrs = s32(PowerPC::ppcState.gpr[inst.RS]);
PowerPC::ppcState.gpr[inst.RA] = u32(rrs >> amount);
const s32 rrs = s32(ppc_state.gpr[inst.RS]);
ppc_state.gpr[inst.RA] = u32(rrs >> amount);
PowerPC::ppcState.SetCarry(rrs < 0 && amount > 0 && (u32(rrs) << (32 - amount)) != 0);
ppc_state.SetCarry(rrs < 0 && amount > 0 && (u32(rrs) << (32 - amount)) != 0);
}
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RA]);
}
void Interpreter::srawix(UGeckoInstruction inst)
void Interpreter::srawix(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 amount = inst.SH;
const s32 rrs = s32(PowerPC::ppcState.gpr[inst.RS]);
auto& ppc_state = interpreter.m_ppc_state;
const s32 rrs = s32(ppc_state.gpr[inst.RS]);
PowerPC::ppcState.gpr[inst.RA] = u32(rrs >> amount);
PowerPC::ppcState.SetCarry(rrs < 0 && amount > 0 && (u32(rrs) << (32 - amount)) != 0);
ppc_state.gpr[inst.RA] = u32(rrs >> amount);
ppc_state.SetCarry(rrs < 0 && amount > 0 && (u32(rrs) << (32 - amount)) != 0);
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RA]);
}
void Interpreter::srwx(UGeckoInstruction inst)
void Interpreter::srwx(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 amount = PowerPC::ppcState.gpr[inst.RB];
PowerPC::ppcState.gpr[inst.RA] =
(amount & 0x20) != 0 ? 0 : (PowerPC::ppcState.gpr[inst.RS] >> (amount & 0x1f));
auto& ppc_state = interpreter.m_ppc_state;
const u32 amount = ppc_state.gpr[inst.RB];
ppc_state.gpr[inst.RA] = (amount & 0x20) != 0 ? 0 : (ppc_state.gpr[inst.RS] >> (amount & 0x1f));
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RA]);
}
void Interpreter::tw(UGeckoInstruction inst)
void Interpreter::tw(Interpreter& interpreter, UGeckoInstruction inst)
{
const s32 a = s32(PowerPC::ppcState.gpr[inst.RA]);
const s32 b = s32(PowerPC::ppcState.gpr[inst.RB]);
auto& ppc_state = interpreter.m_ppc_state;
const s32 a = s32(ppc_state.gpr[inst.RA]);
const s32 b = s32(ppc_state.gpr[inst.RB]);
const u32 TO = inst.TO;
DEBUG_LOG_FMT(POWERPC, "tw rA {:x} rB {:x} TO {:x}", a, b, TO);
@ -353,16 +382,17 @@ void Interpreter::tw(UGeckoInstruction inst)
{
GenerateProgramException(ProgramExceptionCause::Trap);
PowerPC::CheckExceptions();
m_end_block = true; // Dunno about this
interpreter.m_end_block = true; // Dunno about this
}
}
void Interpreter::xorx(UGeckoInstruction inst)
void Interpreter::xorx(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.gpr[inst.RA] = PowerPC::ppcState.gpr[inst.RS] ^ PowerPC::ppcState.gpr[inst.RB];
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RA] = ppc_state.gpr[inst.RS] ^ ppc_state.gpr[inst.RB];
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RA]);
}
static bool HasAddOverflowed(u32 x, u32 y, u32 result)
@ -372,265 +402,281 @@ static bool HasAddOverflowed(u32 x, u32 y, u32 result)
return (((x ^ result) & (y ^ result)) >> 31) != 0;
}
void Interpreter::addx(UGeckoInstruction inst)
void Interpreter::addx(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 a = PowerPC::ppcState.gpr[inst.RA];
const u32 b = PowerPC::ppcState.gpr[inst.RB];
auto& ppc_state = interpreter.m_ppc_state;
const u32 a = ppc_state.gpr[inst.RA];
const u32 b = ppc_state.gpr[inst.RB];
const u32 result = a + b;
PowerPC::ppcState.gpr[inst.RD] = result;
ppc_state.gpr[inst.RD] = result;
if (inst.OE)
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
ppc_state.SetXER_OV(HasAddOverflowed(a, b, result));
if (inst.Rc)
Helper_UpdateCR0(result);
Helper_UpdateCR0(ppc_state, result);
}
void Interpreter::addcx(UGeckoInstruction inst)
void Interpreter::addcx(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 a = PowerPC::ppcState.gpr[inst.RA];
const u32 b = PowerPC::ppcState.gpr[inst.RB];
auto& ppc_state = interpreter.m_ppc_state;
const u32 a = ppc_state.gpr[inst.RA];
const u32 b = ppc_state.gpr[inst.RB];
const u32 result = a + b;
PowerPC::ppcState.gpr[inst.RD] = result;
PowerPC::ppcState.SetCarry(Helper_Carry(a, b));
ppc_state.gpr[inst.RD] = result;
ppc_state.SetCarry(Helper_Carry(a, b));
if (inst.OE)
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
ppc_state.SetXER_OV(HasAddOverflowed(a, b, result));
if (inst.Rc)
Helper_UpdateCR0(result);
Helper_UpdateCR0(ppc_state, result);
}
void Interpreter::addex(UGeckoInstruction inst)
void Interpreter::addex(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 carry = PowerPC::ppcState.GetCarry();
const u32 a = PowerPC::ppcState.gpr[inst.RA];
const u32 b = PowerPC::ppcState.gpr[inst.RB];
auto& ppc_state = interpreter.m_ppc_state;
const u32 carry = ppc_state.GetCarry();
const u32 a = ppc_state.gpr[inst.RA];
const u32 b = ppc_state.gpr[inst.RB];
const u32 result = a + b + carry;
PowerPC::ppcState.gpr[inst.RD] = result;
PowerPC::ppcState.SetCarry(Helper_Carry(a, b) || (carry != 0 && Helper_Carry(a + b, carry)));
ppc_state.gpr[inst.RD] = result;
ppc_state.SetCarry(Helper_Carry(a, b) || (carry != 0 && Helper_Carry(a + b, carry)));
if (inst.OE)
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
ppc_state.SetXER_OV(HasAddOverflowed(a, b, result));
if (inst.Rc)
Helper_UpdateCR0(result);
Helper_UpdateCR0(ppc_state, result);
}
void Interpreter::addmex(UGeckoInstruction inst)
void Interpreter::addmex(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 carry = PowerPC::ppcState.GetCarry();
const u32 a = PowerPC::ppcState.gpr[inst.RA];
auto& ppc_state = interpreter.m_ppc_state;
const u32 carry = ppc_state.GetCarry();
const u32 a = ppc_state.gpr[inst.RA];
const u32 b = 0xFFFFFFFF;
const u32 result = a + b + carry;
PowerPC::ppcState.gpr[inst.RD] = result;
PowerPC::ppcState.SetCarry(Helper_Carry(a, carry - 1));
ppc_state.gpr[inst.RD] = result;
ppc_state.SetCarry(Helper_Carry(a, carry - 1));
if (inst.OE)
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
ppc_state.SetXER_OV(HasAddOverflowed(a, b, result));
if (inst.Rc)
Helper_UpdateCR0(result);
Helper_UpdateCR0(ppc_state, result);
}
void Interpreter::addzex(UGeckoInstruction inst)
void Interpreter::addzex(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 carry = PowerPC::ppcState.GetCarry();
const u32 a = PowerPC::ppcState.gpr[inst.RA];
auto& ppc_state = interpreter.m_ppc_state;
const u32 carry = ppc_state.GetCarry();
const u32 a = ppc_state.gpr[inst.RA];
const u32 result = a + carry;
PowerPC::ppcState.gpr[inst.RD] = result;
PowerPC::ppcState.SetCarry(Helper_Carry(a, carry));
ppc_state.gpr[inst.RD] = result;
ppc_state.SetCarry(Helper_Carry(a, carry));
if (inst.OE)
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, 0, result));
ppc_state.SetXER_OV(HasAddOverflowed(a, 0, result));
if (inst.Rc)
Helper_UpdateCR0(result);
Helper_UpdateCR0(ppc_state, result);
}
void Interpreter::divwx(UGeckoInstruction inst)
void Interpreter::divwx(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto a = s32(PowerPC::ppcState.gpr[inst.RA]);
const auto b = s32(PowerPC::ppcState.gpr[inst.RB]);
auto& ppc_state = interpreter.m_ppc_state;
const auto a = s32(ppc_state.gpr[inst.RA]);
const auto b = s32(ppc_state.gpr[inst.RB]);
const bool overflow = b == 0 || (static_cast<u32>(a) == 0x80000000 && b == -1);
if (overflow)
{
if (a < 0)
PowerPC::ppcState.gpr[inst.RD] = UINT32_MAX;
ppc_state.gpr[inst.RD] = UINT32_MAX;
else
PowerPC::ppcState.gpr[inst.RD] = 0;
ppc_state.gpr[inst.RD] = 0;
}
else
{
PowerPC::ppcState.gpr[inst.RD] = static_cast<u32>(a / b);
ppc_state.gpr[inst.RD] = static_cast<u32>(a / b);
}
if (inst.OE)
PowerPC::ppcState.SetXER_OV(overflow);
ppc_state.SetXER_OV(overflow);
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RD]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RD]);
}
void Interpreter::divwux(UGeckoInstruction inst)
void Interpreter::divwux(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 a = PowerPC::ppcState.gpr[inst.RA];
const u32 b = PowerPC::ppcState.gpr[inst.RB];
auto& ppc_state = interpreter.m_ppc_state;
const u32 a = ppc_state.gpr[inst.RA];
const u32 b = ppc_state.gpr[inst.RB];
const bool overflow = b == 0;
if (overflow)
{
PowerPC::ppcState.gpr[inst.RD] = 0;
ppc_state.gpr[inst.RD] = 0;
}
else
{
PowerPC::ppcState.gpr[inst.RD] = a / b;
ppc_state.gpr[inst.RD] = a / b;
}
if (inst.OE)
PowerPC::ppcState.SetXER_OV(overflow);
ppc_state.SetXER_OV(overflow);
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RD]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RD]);
}
void Interpreter::mulhwx(UGeckoInstruction inst)
void Interpreter::mulhwx(Interpreter& interpreter, UGeckoInstruction inst)
{
const s64 a = static_cast<s32>(PowerPC::ppcState.gpr[inst.RA]);
const s64 b = static_cast<s32>(PowerPC::ppcState.gpr[inst.RB]);
auto& ppc_state = interpreter.m_ppc_state;
const s64 a = static_cast<s32>(ppc_state.gpr[inst.RA]);
const s64 b = static_cast<s32>(ppc_state.gpr[inst.RB]);
const u32 d = static_cast<u32>((a * b) >> 32);
PowerPC::ppcState.gpr[inst.RD] = d;
ppc_state.gpr[inst.RD] = d;
if (inst.Rc)
Helper_UpdateCR0(d);
Helper_UpdateCR0(ppc_state, d);
}
void Interpreter::mulhwux(UGeckoInstruction inst)
void Interpreter::mulhwux(Interpreter& interpreter, UGeckoInstruction inst)
{
const u64 a = PowerPC::ppcState.gpr[inst.RA];
const u64 b = PowerPC::ppcState.gpr[inst.RB];
auto& ppc_state = interpreter.m_ppc_state;
const u64 a = ppc_state.gpr[inst.RA];
const u64 b = ppc_state.gpr[inst.RB];
const u32 d = static_cast<u32>((a * b) >> 32);
PowerPC::ppcState.gpr[inst.RD] = d;
ppc_state.gpr[inst.RD] = d;
if (inst.Rc)
Helper_UpdateCR0(d);
Helper_UpdateCR0(ppc_state, d);
}
void Interpreter::mullwx(UGeckoInstruction inst)
void Interpreter::mullwx(Interpreter& interpreter, UGeckoInstruction inst)
{
const s64 a = static_cast<s32>(PowerPC::ppcState.gpr[inst.RA]);
const s64 b = static_cast<s32>(PowerPC::ppcState.gpr[inst.RB]);
auto& ppc_state = interpreter.m_ppc_state;
const s64 a = static_cast<s32>(ppc_state.gpr[inst.RA]);
const s64 b = static_cast<s32>(ppc_state.gpr[inst.RB]);
const s64 result = a * b;
PowerPC::ppcState.gpr[inst.RD] = static_cast<u32>(result);
ppc_state.gpr[inst.RD] = static_cast<u32>(result);
if (inst.OE)
PowerPC::ppcState.SetXER_OV(result < -0x80000000LL || result > 0x7FFFFFFFLL);
ppc_state.SetXER_OV(result < -0x80000000LL || result > 0x7FFFFFFFLL);
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RD]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RD]);
}
void Interpreter::negx(UGeckoInstruction inst)
void Interpreter::negx(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 a = PowerPC::ppcState.gpr[inst.RA];
auto& ppc_state = interpreter.m_ppc_state;
const u32 a = ppc_state.gpr[inst.RA];
PowerPC::ppcState.gpr[inst.RD] = (~a) + 1;
ppc_state.gpr[inst.RD] = (~a) + 1;
if (inst.OE)
PowerPC::ppcState.SetXER_OV(a == 0x80000000);
ppc_state.SetXER_OV(a == 0x80000000);
if (inst.Rc)
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RD]);
Helper_UpdateCR0(ppc_state, ppc_state.gpr[inst.RD]);
}
void Interpreter::subfx(UGeckoInstruction inst)
void Interpreter::subfx(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 a = ~PowerPC::ppcState.gpr[inst.RA];
const u32 b = PowerPC::ppcState.gpr[inst.RB];
auto& ppc_state = interpreter.m_ppc_state;
const u32 a = ~ppc_state.gpr[inst.RA];
const u32 b = ppc_state.gpr[inst.RB];
const u32 result = a + b + 1;
PowerPC::ppcState.gpr[inst.RD] = result;
ppc_state.gpr[inst.RD] = result;
if (inst.OE)
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
ppc_state.SetXER_OV(HasAddOverflowed(a, b, result));
if (inst.Rc)
Helper_UpdateCR0(result);
Helper_UpdateCR0(ppc_state, result);
}
void Interpreter::subfcx(UGeckoInstruction inst)
void Interpreter::subfcx(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 a = ~PowerPC::ppcState.gpr[inst.RA];
const u32 b = PowerPC::ppcState.gpr[inst.RB];
auto& ppc_state = interpreter.m_ppc_state;
const u32 a = ~ppc_state.gpr[inst.RA];
const u32 b = ppc_state.gpr[inst.RB];
const u32 result = a + b + 1;
PowerPC::ppcState.gpr[inst.RD] = result;
PowerPC::ppcState.SetCarry(a == 0xFFFFFFFF || Helper_Carry(b, a + 1));
ppc_state.gpr[inst.RD] = result;
ppc_state.SetCarry(a == 0xFFFFFFFF || Helper_Carry(b, a + 1));
if (inst.OE)
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
ppc_state.SetXER_OV(HasAddOverflowed(a, b, result));
if (inst.Rc)
Helper_UpdateCR0(result);
Helper_UpdateCR0(ppc_state, result);
}
void Interpreter::subfex(UGeckoInstruction inst)
void Interpreter::subfex(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 a = ~PowerPC::ppcState.gpr[inst.RA];
const u32 b = PowerPC::ppcState.gpr[inst.RB];
const u32 carry = PowerPC::ppcState.GetCarry();
auto& ppc_state = interpreter.m_ppc_state;
const u32 a = ~ppc_state.gpr[inst.RA];
const u32 b = ppc_state.gpr[inst.RB];
const u32 carry = ppc_state.GetCarry();
const u32 result = a + b + carry;
PowerPC::ppcState.gpr[inst.RD] = result;
PowerPC::ppcState.SetCarry(Helper_Carry(a, b) || Helper_Carry(a + b, carry));
ppc_state.gpr[inst.RD] = result;
ppc_state.SetCarry(Helper_Carry(a, b) || Helper_Carry(a + b, carry));
if (inst.OE)
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
ppc_state.SetXER_OV(HasAddOverflowed(a, b, result));
if (inst.Rc)
Helper_UpdateCR0(result);
Helper_UpdateCR0(ppc_state, result);
}
// sub from minus one
void Interpreter::subfmex(UGeckoInstruction inst)
void Interpreter::subfmex(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 a = ~PowerPC::ppcState.gpr[inst.RA];
auto& ppc_state = interpreter.m_ppc_state;
const u32 a = ~ppc_state.gpr[inst.RA];
const u32 b = 0xFFFFFFFF;
const u32 carry = PowerPC::ppcState.GetCarry();
const u32 carry = ppc_state.GetCarry();
const u32 result = a + b + carry;
PowerPC::ppcState.gpr[inst.RD] = result;
PowerPC::ppcState.SetCarry(Helper_Carry(a, carry - 1));
ppc_state.gpr[inst.RD] = result;
ppc_state.SetCarry(Helper_Carry(a, carry - 1));
if (inst.OE)
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
ppc_state.SetXER_OV(HasAddOverflowed(a, b, result));
if (inst.Rc)
Helper_UpdateCR0(result);
Helper_UpdateCR0(ppc_state, result);
}
// sub from zero
void Interpreter::subfzex(UGeckoInstruction inst)
void Interpreter::subfzex(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 a = ~PowerPC::ppcState.gpr[inst.RA];
const u32 carry = PowerPC::ppcState.GetCarry();
auto& ppc_state = interpreter.m_ppc_state;
const u32 a = ~ppc_state.gpr[inst.RA];
const u32 carry = ppc_state.GetCarry();
const u32 result = a + carry;
PowerPC::ppcState.gpr[inst.RD] = result;
PowerPC::ppcState.SetCarry(Helper_Carry(a, carry));
ppc_state.gpr[inst.RD] = result;
ppc_state.SetCarry(Helper_Carry(a, carry));
if (inst.OE)
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, 0, result));
ppc_state.SetXER_OV(HasAddOverflowed(a, 0, result));
if (inst.Rc)
Helper_UpdateCR0(result);
Helper_UpdateCR0(ppc_state, result);
}

View File

@ -308,104 +308,112 @@ static void Helper_Dequantize(PowerPC::PowerPCState* ppcs, u32 addr, u32 instI,
ppcs->ps[instRD].SetBoth(ps0, ps1);
}
void Interpreter::psq_l(UGeckoInstruction inst)
void Interpreter::psq_l(Interpreter& interpreter, UGeckoInstruction inst)
{
if (HID2(PowerPC::ppcState).LSQE == 0)
auto& ppc_state = interpreter.m_ppc_state;
if (HID2(ppc_state).LSQE == 0)
{
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
return;
}
const u32 EA = inst.RA ? (PowerPC::ppcState.gpr[inst.RA] + u32(inst.SIMM_12)) : u32(inst.SIMM_12);
Helper_Dequantize(&PowerPC::ppcState, EA, inst.I, inst.RD, inst.W);
const u32 EA = inst.RA ? (ppc_state.gpr[inst.RA] + u32(inst.SIMM_12)) : u32(inst.SIMM_12);
Helper_Dequantize(&ppc_state, EA, inst.I, inst.RD, inst.W);
}
void Interpreter::psq_lu(UGeckoInstruction inst)
void Interpreter::psq_lu(Interpreter& interpreter, UGeckoInstruction inst)
{
if (HID2(PowerPC::ppcState).LSQE == 0)
auto& ppc_state = interpreter.m_ppc_state;
if (HID2(ppc_state).LSQE == 0)
{
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
return;
}
const u32 EA = PowerPC::ppcState.gpr[inst.RA] + u32(inst.SIMM_12);
Helper_Dequantize(&PowerPC::ppcState, EA, inst.I, inst.RD, inst.W);
const u32 EA = ppc_state.gpr[inst.RA] + u32(inst.SIMM_12);
Helper_Dequantize(&ppc_state, EA, inst.I, inst.RD, inst.W);
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
if ((ppc_state.Exceptions & EXCEPTION_DSI) != 0)
{
return;
}
PowerPC::ppcState.gpr[inst.RA] = EA;
ppc_state.gpr[inst.RA] = EA;
}
void Interpreter::psq_st(UGeckoInstruction inst)
void Interpreter::psq_st(Interpreter& interpreter, UGeckoInstruction inst)
{
if (HID2(PowerPC::ppcState).LSQE == 0)
auto& ppc_state = interpreter.m_ppc_state;
if (HID2(ppc_state).LSQE == 0)
{
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
return;
}
const u32 EA = inst.RA ? (PowerPC::ppcState.gpr[inst.RA] + u32(inst.SIMM_12)) : u32(inst.SIMM_12);
Helper_Quantize(&PowerPC::ppcState, EA, inst.I, inst.RS, inst.W);
const u32 EA = inst.RA ? (ppc_state.gpr[inst.RA] + u32(inst.SIMM_12)) : u32(inst.SIMM_12);
Helper_Quantize(&ppc_state, EA, inst.I, inst.RS, inst.W);
}
void Interpreter::psq_stu(UGeckoInstruction inst)
void Interpreter::psq_stu(Interpreter& interpreter, UGeckoInstruction inst)
{
if (HID2(PowerPC::ppcState).LSQE == 0)
auto& ppc_state = interpreter.m_ppc_state;
if (HID2(ppc_state).LSQE == 0)
{
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
return;
}
const u32 EA = PowerPC::ppcState.gpr[inst.RA] + u32(inst.SIMM_12);
Helper_Quantize(&PowerPC::ppcState, EA, inst.I, inst.RS, inst.W);
const u32 EA = ppc_state.gpr[inst.RA] + u32(inst.SIMM_12);
Helper_Quantize(&ppc_state, EA, inst.I, inst.RS, inst.W);
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
if ((ppc_state.Exceptions & EXCEPTION_DSI) != 0)
{
return;
}
PowerPC::ppcState.gpr[inst.RA] = EA;
ppc_state.gpr[inst.RA] = EA;
}
void Interpreter::psq_lx(UGeckoInstruction inst)
void Interpreter::psq_lx(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 EA = inst.RA ? (PowerPC::ppcState.gpr[inst.RA] + PowerPC::ppcState.gpr[inst.RB]) :
PowerPC::ppcState.gpr[inst.RB];
Helper_Dequantize(&PowerPC::ppcState, EA, inst.Ix, inst.RD, inst.Wx);
auto& ppc_state = interpreter.m_ppc_state;
const u32 EA =
inst.RA ? (ppc_state.gpr[inst.RA] + ppc_state.gpr[inst.RB]) : ppc_state.gpr[inst.RB];
Helper_Dequantize(&ppc_state, EA, inst.Ix, inst.RD, inst.Wx);
}
void Interpreter::psq_stx(UGeckoInstruction inst)
void Interpreter::psq_stx(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 EA = inst.RA ? (PowerPC::ppcState.gpr[inst.RA] + PowerPC::ppcState.gpr[inst.RB]) :
PowerPC::ppcState.gpr[inst.RB];
Helper_Quantize(&PowerPC::ppcState, EA, inst.Ix, inst.RS, inst.Wx);
auto& ppc_state = interpreter.m_ppc_state;
const u32 EA =
inst.RA ? (ppc_state.gpr[inst.RA] + ppc_state.gpr[inst.RB]) : ppc_state.gpr[inst.RB];
Helper_Quantize(&ppc_state, EA, inst.Ix, inst.RS, inst.Wx);
}
void Interpreter::psq_lux(UGeckoInstruction inst)
void Interpreter::psq_lux(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 EA = PowerPC::ppcState.gpr[inst.RA] + PowerPC::ppcState.gpr[inst.RB];
Helper_Dequantize(&PowerPC::ppcState, EA, inst.Ix, inst.RD, inst.Wx);
auto& ppc_state = interpreter.m_ppc_state;
const u32 EA = ppc_state.gpr[inst.RA] + ppc_state.gpr[inst.RB];
Helper_Dequantize(&ppc_state, EA, inst.Ix, inst.RD, inst.Wx);
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
if ((ppc_state.Exceptions & EXCEPTION_DSI) != 0)
{
return;
}
PowerPC::ppcState.gpr[inst.RA] = EA;
ppc_state.gpr[inst.RA] = EA;
}
void Interpreter::psq_stux(UGeckoInstruction inst)
void Interpreter::psq_stux(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 EA = PowerPC::ppcState.gpr[inst.RA] + PowerPC::ppcState.gpr[inst.RB];
Helper_Quantize(&PowerPC::ppcState, EA, inst.Ix, inst.RS, inst.Wx);
auto& ppc_state = interpreter.m_ppc_state;
const u32 EA = ppc_state.gpr[inst.RA] + ppc_state.gpr[inst.RB];
Helper_Quantize(&ppc_state, EA, inst.Ix, inst.RS, inst.Wx);
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
if ((ppc_state.Exceptions & EXCEPTION_DSI) != 0)
{
return;
}
PowerPC::ppcState.gpr[inst.RA] = EA;
ppc_state.gpr[inst.RA] = EA;
}

View File

@ -11,487 +11,493 @@
#include "Core/PowerPC/PowerPC.h"
// These "binary instructions" do not alter FPSCR.
void Interpreter::ps_sel(UGeckoInstruction inst)
void Interpreter::ps_sel(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = PowerPC::ppcState.ps[inst.FC];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const auto& c = ppc_state.ps[inst.FC];
PowerPC::ppcState.ps[inst.FD].SetBoth(a.PS0AsDouble() >= -0.0 ? c.PS0AsDouble() : b.PS0AsDouble(),
a.PS1AsDouble() >= -0.0 ? c.PS1AsDouble() :
b.PS1AsDouble());
ppc_state.ps[inst.FD].SetBoth(a.PS0AsDouble() >= -0.0 ? c.PS0AsDouble() : b.PS0AsDouble(),
a.PS1AsDouble() >= -0.0 ? c.PS1AsDouble() : b.PS1AsDouble());
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::ps_neg(UGeckoInstruction inst)
void Interpreter::ps_neg(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& b = ppc_state.ps[inst.FB];
PowerPC::ppcState.ps[inst.FD].SetBoth(b.PS0AsU64() ^ (UINT64_C(1) << 63),
b.PS1AsU64() ^ (UINT64_C(1) << 63));
ppc_state.ps[inst.FD].SetBoth(b.PS0AsU64() ^ (UINT64_C(1) << 63),
b.PS1AsU64() ^ (UINT64_C(1) << 63));
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::ps_mr(UGeckoInstruction inst)
void Interpreter::ps_mr(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.ps[inst.FD] = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.ps[inst.FD] = ppc_state.ps[inst.FB];
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::ps_nabs(UGeckoInstruction inst)
void Interpreter::ps_nabs(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& b = ppc_state.ps[inst.FB];
PowerPC::ppcState.ps[inst.FD].SetBoth(b.PS0AsU64() | (UINT64_C(1) << 63),
b.PS1AsU64() | (UINT64_C(1) << 63));
ppc_state.ps[inst.FD].SetBoth(b.PS0AsU64() | (UINT64_C(1) << 63),
b.PS1AsU64() | (UINT64_C(1) << 63));
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::ps_abs(UGeckoInstruction inst)
void Interpreter::ps_abs(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& b = ppc_state.ps[inst.FB];
PowerPC::ppcState.ps[inst.FD].SetBoth(b.PS0AsU64() & ~(UINT64_C(1) << 63),
b.PS1AsU64() & ~(UINT64_C(1) << 63));
ppc_state.ps[inst.FD].SetBoth(b.PS0AsU64() & ~(UINT64_C(1) << 63),
b.PS1AsU64() & ~(UINT64_C(1) << 63));
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
// These are just moves, double is OK.
void Interpreter::ps_merge00(UGeckoInstruction inst)
void Interpreter::ps_merge00(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
PowerPC::ppcState.ps[inst.FD].SetBoth(a.PS0AsDouble(), b.PS0AsDouble());
ppc_state.ps[inst.FD].SetBoth(a.PS0AsDouble(), b.PS0AsDouble());
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::ps_merge01(UGeckoInstruction inst)
void Interpreter::ps_merge01(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
PowerPC::ppcState.ps[inst.FD].SetBoth(a.PS0AsDouble(), b.PS1AsDouble());
ppc_state.ps[inst.FD].SetBoth(a.PS0AsDouble(), b.PS1AsDouble());
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::ps_merge10(UGeckoInstruction inst)
void Interpreter::ps_merge10(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
PowerPC::ppcState.ps[inst.FD].SetBoth(a.PS1AsDouble(), b.PS0AsDouble());
ppc_state.ps[inst.FD].SetBoth(a.PS1AsDouble(), b.PS0AsDouble());
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::ps_merge11(UGeckoInstruction inst)
void Interpreter::ps_merge11(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
PowerPC::ppcState.ps[inst.FD].SetBoth(a.PS1AsDouble(), b.PS1AsDouble());
ppc_state.ps[inst.FD].SetBoth(a.PS1AsDouble(), b.PS1AsDouble());
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
// From here on, the real deal.
void Interpreter::ps_div(UGeckoInstruction inst)
void Interpreter::ps_div(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const float ps0 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_div(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble()).value);
const float ps1 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_div(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), b.PS1AsDouble()).value);
const float ps0 = ForceSingle(ppc_state.fpscr,
NI_div(&ppc_state.fpscr, a.PS0AsDouble(), b.PS0AsDouble()).value);
const float ps1 = ForceSingle(ppc_state.fpscr,
NI_div(&ppc_state.fpscr, a.PS1AsDouble(), b.PS1AsDouble()).value);
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::ppcState.UpdateFPRFSingle(ps0);
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
ppc_state.UpdateFPRFSingle(ps0);
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::ps_res(UGeckoInstruction inst)
void Interpreter::ps_res(Interpreter& interpreter, UGeckoInstruction inst)
{
// this code is based on the real hardware tests
const double a = PowerPC::ppcState.ps[inst.FB].PS0AsDouble();
const double b = PowerPC::ppcState.ps[inst.FB].PS1AsDouble();
auto& ppc_state = interpreter.m_ppc_state;
const double a = ppc_state.ps[inst.FB].PS0AsDouble();
const double b = ppc_state.ps[inst.FB].PS1AsDouble();
if (a == 0.0 || b == 0.0)
{
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_ZX);
PowerPC::ppcState.fpscr.ClearFIFR();
SetFPException(&ppc_state.fpscr, FPSCR_ZX);
ppc_state.fpscr.ClearFIFR();
}
if (std::isnan(a) || std::isinf(a) || std::isnan(b) || std::isinf(b))
PowerPC::ppcState.fpscr.ClearFIFR();
ppc_state.fpscr.ClearFIFR();
if (Common::IsSNAN(a) || Common::IsSNAN(b))
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
SetFPException(&ppc_state.fpscr, FPSCR_VXSNAN);
const double ps0 = Common::ApproximateReciprocal(a);
const double ps1 = Common::ApproximateReciprocal(b);
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::ppcState.UpdateFPRFSingle(float(ps0));
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
ppc_state.UpdateFPRFSingle(float(ps0));
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::ps_rsqrte(UGeckoInstruction inst)
void Interpreter::ps_rsqrte(Interpreter& interpreter, UGeckoInstruction inst)
{
const double ps0 = PowerPC::ppcState.ps[inst.FB].PS0AsDouble();
const double ps1 = PowerPC::ppcState.ps[inst.FB].PS1AsDouble();
auto& ppc_state = interpreter.m_ppc_state;
const double ps0 = ppc_state.ps[inst.FB].PS0AsDouble();
const double ps1 = ppc_state.ps[inst.FB].PS1AsDouble();
if (ps0 == 0.0 || ps1 == 0.0)
{
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_ZX);
PowerPC::ppcState.fpscr.ClearFIFR();
SetFPException(&ppc_state.fpscr, FPSCR_ZX);
ppc_state.fpscr.ClearFIFR();
}
if (ps0 < 0.0 || ps1 < 0.0)
{
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSQRT);
PowerPC::ppcState.fpscr.ClearFIFR();
SetFPException(&ppc_state.fpscr, FPSCR_VXSQRT);
ppc_state.fpscr.ClearFIFR();
}
if (std::isnan(ps0) || std::isinf(ps0) || std::isnan(ps1) || std::isinf(ps1))
PowerPC::ppcState.fpscr.ClearFIFR();
ppc_state.fpscr.ClearFIFR();
if (Common::IsSNAN(ps0) || Common::IsSNAN(ps1))
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
SetFPException(&ppc_state.fpscr, FPSCR_VXSNAN);
const float dst_ps0 =
ForceSingle(PowerPC::ppcState.fpscr, Common::ApproximateReciprocalSquareRoot(ps0));
const float dst_ps1 =
ForceSingle(PowerPC::ppcState.fpscr, Common::ApproximateReciprocalSquareRoot(ps1));
const float dst_ps0 = ForceSingle(ppc_state.fpscr, Common::ApproximateReciprocalSquareRoot(ps0));
const float dst_ps1 = ForceSingle(ppc_state.fpscr, Common::ApproximateReciprocalSquareRoot(ps1));
PowerPC::ppcState.ps[inst.FD].SetBoth(dst_ps0, dst_ps1);
PowerPC::ppcState.UpdateFPRFSingle(dst_ps0);
ppc_state.ps[inst.FD].SetBoth(dst_ps0, dst_ps1);
ppc_state.UpdateFPRFSingle(dst_ps0);
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::ps_sub(UGeckoInstruction inst)
void Interpreter::ps_sub(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const float ps0 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_sub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble()).value);
const float ps1 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_sub(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), b.PS1AsDouble()).value);
const float ps0 = ForceSingle(ppc_state.fpscr,
NI_sub(&ppc_state.fpscr, a.PS0AsDouble(), b.PS0AsDouble()).value);
const float ps1 = ForceSingle(ppc_state.fpscr,
NI_sub(&ppc_state.fpscr, a.PS1AsDouble(), b.PS1AsDouble()).value);
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::ppcState.UpdateFPRFSingle(ps0);
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
ppc_state.UpdateFPRFSingle(ps0);
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::ps_add(UGeckoInstruction inst)
void Interpreter::ps_add(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const float ps0 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_add(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble()).value);
const float ps1 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_add(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), b.PS1AsDouble()).value);
const float ps0 = ForceSingle(ppc_state.fpscr,
NI_add(&ppc_state.fpscr, a.PS0AsDouble(), b.PS0AsDouble()).value);
const float ps1 = ForceSingle(ppc_state.fpscr,
NI_add(&ppc_state.fpscr, a.PS1AsDouble(), b.PS1AsDouble()).value);
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::ppcState.UpdateFPRFSingle(ps0);
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
ppc_state.UpdateFPRFSingle(ps0);
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::ps_mul(UGeckoInstruction inst)
void Interpreter::ps_mul(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& c = PowerPC::ppcState.ps[inst.FC];
const double c0 = Force25Bit(c.PS0AsDouble());
const double c1 = Force25Bit(c.PS1AsDouble());
const float ps0 = ForceSingle(PowerPC::ppcState.fpscr,
NI_mul(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c0).value);
const float ps1 = ForceSingle(PowerPC::ppcState.fpscr,
NI_mul(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c1).value);
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::ppcState.UpdateFPRFSingle(ps0);
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
}
void Interpreter::ps_msub(UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = PowerPC::ppcState.ps[inst.FC];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& c = ppc_state.ps[inst.FC];
const double c0 = Force25Bit(c.PS0AsDouble());
const double c1 = Force25Bit(c.PS1AsDouble());
const float ps0 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_msub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
ForceSingle(ppc_state.fpscr, NI_mul(&ppc_state.fpscr, a.PS0AsDouble(), c0).value);
const float ps1 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_msub(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
ForceSingle(ppc_state.fpscr, NI_mul(&ppc_state.fpscr, a.PS1AsDouble(), c1).value);
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::ppcState.UpdateFPRFSingle(ps0);
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
ppc_state.UpdateFPRFSingle(ps0);
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::ps_madd(UGeckoInstruction inst)
void Interpreter::ps_msub(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = PowerPC::ppcState.ps[inst.FC];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const auto& c = ppc_state.ps[inst.FC];
const double c0 = Force25Bit(c.PS0AsDouble());
const double c1 = Force25Bit(c.PS1AsDouble());
const float ps0 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_madd(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
const float ps1 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_madd(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
const float ps0 = ForceSingle(
ppc_state.fpscr, NI_msub(&ppc_state.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
const float ps1 = ForceSingle(
ppc_state.fpscr, NI_msub(&ppc_state.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::ppcState.UpdateFPRFSingle(ps0);
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
ppc_state.UpdateFPRFSingle(ps0);
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::ps_nmsub(UGeckoInstruction inst)
void Interpreter::ps_madd(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = PowerPC::ppcState.ps[inst.FC];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const auto& c = ppc_state.ps[inst.FC];
const double c0 = Force25Bit(c.PS0AsDouble());
const double c1 = Force25Bit(c.PS1AsDouble());
const float tmp0 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_msub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
const float tmp1 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_msub(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
const float ps0 = ForceSingle(
ppc_state.fpscr, NI_madd(&ppc_state.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
const float ps1 = ForceSingle(
ppc_state.fpscr, NI_madd(&ppc_state.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
ppc_state.UpdateFPRFSingle(ps0);
if (inst.Rc)
ppc_state.UpdateCR1();
}
void Interpreter::ps_nmsub(Interpreter& interpreter, UGeckoInstruction inst)
{
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const auto& c = ppc_state.ps[inst.FC];
const double c0 = Force25Bit(c.PS0AsDouble());
const double c1 = Force25Bit(c.PS1AsDouble());
const float tmp0 = ForceSingle(
ppc_state.fpscr, NI_msub(&ppc_state.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
const float tmp1 = ForceSingle(
ppc_state.fpscr, NI_msub(&ppc_state.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
const float ps0 = std::isnan(tmp0) ? tmp0 : -tmp0;
const float ps1 = std::isnan(tmp1) ? tmp1 : -tmp1;
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::ppcState.UpdateFPRFSingle(ps0);
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
ppc_state.UpdateFPRFSingle(ps0);
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::ps_nmadd(UGeckoInstruction inst)
void Interpreter::ps_nmadd(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = PowerPC::ppcState.ps[inst.FC];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const auto& c = ppc_state.ps[inst.FC];
const double c0 = Force25Bit(c.PS0AsDouble());
const double c1 = Force25Bit(c.PS1AsDouble());
const float tmp0 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_madd(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
const float tmp1 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_madd(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
const float tmp0 = ForceSingle(
ppc_state.fpscr, NI_madd(&ppc_state.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
const float tmp1 = ForceSingle(
ppc_state.fpscr, NI_madd(&ppc_state.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
const float ps0 = std::isnan(tmp0) ? tmp0 : -tmp0;
const float ps1 = std::isnan(tmp1) ? tmp1 : -tmp1;
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::ppcState.UpdateFPRFSingle(ps0);
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
ppc_state.UpdateFPRFSingle(ps0);
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::ps_sum0(UGeckoInstruction inst)
void Interpreter::ps_sum0(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = PowerPC::ppcState.ps[inst.FC];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const auto& c = ppc_state.ps[inst.FC];
const float ps0 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_add(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS1AsDouble()).value);
const float ps1 = ForceSingle(PowerPC::ppcState.fpscr, c.PS1AsDouble());
const float ps0 = ForceSingle(ppc_state.fpscr,
NI_add(&ppc_state.fpscr, a.PS0AsDouble(), b.PS1AsDouble()).value);
const float ps1 = ForceSingle(ppc_state.fpscr, c.PS1AsDouble());
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::ppcState.UpdateFPRFSingle(ps0);
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
ppc_state.UpdateFPRFSingle(ps0);
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::ps_sum1(UGeckoInstruction inst)
void Interpreter::ps_sum1(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = PowerPC::ppcState.ps[inst.FC];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const auto& c = ppc_state.ps[inst.FC];
const float ps0 = ForceSingle(PowerPC::ppcState.fpscr, c.PS0AsDouble());
const float ps1 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_add(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS1AsDouble()).value);
const float ps0 = ForceSingle(ppc_state.fpscr, c.PS0AsDouble());
const float ps1 = ForceSingle(ppc_state.fpscr,
NI_add(&ppc_state.fpscr, a.PS0AsDouble(), b.PS1AsDouble()).value);
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::ppcState.UpdateFPRFSingle(ps1);
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
ppc_state.UpdateFPRFSingle(ps1);
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::ps_muls0(UGeckoInstruction inst)
void Interpreter::ps_muls0(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& c = PowerPC::ppcState.ps[inst.FC];
const double c0 = Force25Bit(c.PS0AsDouble());
const float ps0 = ForceSingle(PowerPC::ppcState.fpscr,
NI_mul(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c0).value);
const float ps1 = ForceSingle(PowerPC::ppcState.fpscr,
NI_mul(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c0).value);
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::ppcState.UpdateFPRFSingle(ps0);
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
}
void Interpreter::ps_muls1(UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& c = PowerPC::ppcState.ps[inst.FC];
const double c1 = Force25Bit(c.PS1AsDouble());
const float ps0 = ForceSingle(PowerPC::ppcState.fpscr,
NI_mul(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c1).value);
const float ps1 = ForceSingle(PowerPC::ppcState.fpscr,
NI_mul(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c1).value);
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::ppcState.UpdateFPRFSingle(ps0);
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
}
void Interpreter::ps_madds0(UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = PowerPC::ppcState.ps[inst.FC];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& c = ppc_state.ps[inst.FC];
const double c0 = Force25Bit(c.PS0AsDouble());
const float ps0 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_madd(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
ForceSingle(ppc_state.fpscr, NI_mul(&ppc_state.fpscr, a.PS0AsDouble(), c0).value);
const float ps1 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_madd(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c0, b.PS1AsDouble()).value);
ForceSingle(ppc_state.fpscr, NI_mul(&ppc_state.fpscr, a.PS1AsDouble(), c0).value);
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::ppcState.UpdateFPRFSingle(ps0);
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
ppc_state.UpdateFPRFSingle(ps0);
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::ps_madds1(UGeckoInstruction inst)
void Interpreter::ps_muls1(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
const auto& c = PowerPC::ppcState.ps[inst.FC];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& c = ppc_state.ps[inst.FC];
const double c1 = Force25Bit(c.PS1AsDouble());
const float ps0 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_madd(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c1, b.PS0AsDouble()).value);
ForceSingle(ppc_state.fpscr, NI_mul(&ppc_state.fpscr, a.PS0AsDouble(), c1).value);
const float ps1 =
ForceSingle(PowerPC::ppcState.fpscr,
NI_madd(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
ForceSingle(ppc_state.fpscr, NI_mul(&ppc_state.fpscr, a.PS1AsDouble(), c1).value);
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
PowerPC::ppcState.UpdateFPRFSingle(ps0);
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
ppc_state.UpdateFPRFSingle(ps0);
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::ps_cmpu0(UGeckoInstruction inst)
void Interpreter::ps_madds0(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const auto& c = ppc_state.ps[inst.FC];
Helper_FloatCompareUnordered(inst, a.PS0AsDouble(), b.PS0AsDouble());
const double c0 = Force25Bit(c.PS0AsDouble());
const float ps0 = ForceSingle(
ppc_state.fpscr, NI_madd(&ppc_state.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
const float ps1 = ForceSingle(
ppc_state.fpscr, NI_madd(&ppc_state.fpscr, a.PS1AsDouble(), c0, b.PS1AsDouble()).value);
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
ppc_state.UpdateFPRFSingle(ps0);
if (inst.Rc)
ppc_state.UpdateCR1();
}
void Interpreter::ps_cmpo0(UGeckoInstruction inst)
void Interpreter::ps_madds1(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
const auto& c = ppc_state.ps[inst.FC];
Helper_FloatCompareOrdered(inst, a.PS0AsDouble(), b.PS0AsDouble());
const double c1 = Force25Bit(c.PS1AsDouble());
const float ps0 = ForceSingle(
ppc_state.fpscr, NI_madd(&ppc_state.fpscr, a.PS0AsDouble(), c1, b.PS0AsDouble()).value);
const float ps1 = ForceSingle(
ppc_state.fpscr, NI_madd(&ppc_state.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
ppc_state.UpdateFPRFSingle(ps0);
if (inst.Rc)
ppc_state.UpdateCR1();
}
void Interpreter::ps_cmpu1(UGeckoInstruction inst)
void Interpreter::ps_cmpu0(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
Helper_FloatCompareUnordered(inst, a.PS1AsDouble(), b.PS1AsDouble());
Helper_FloatCompareUnordered(ppc_state, inst, a.PS0AsDouble(), b.PS0AsDouble());
}
void Interpreter::ps_cmpo1(UGeckoInstruction inst)
void Interpreter::ps_cmpo0(Interpreter& interpreter, UGeckoInstruction inst)
{
const auto& a = PowerPC::ppcState.ps[inst.FA];
const auto& b = PowerPC::ppcState.ps[inst.FB];
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
Helper_FloatCompareOrdered(inst, a.PS1AsDouble(), b.PS1AsDouble());
Helper_FloatCompareOrdered(ppc_state, inst, a.PS0AsDouble(), b.PS0AsDouble());
}
void Interpreter::ps_cmpu1(Interpreter& interpreter, UGeckoInstruction inst)
{
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
Helper_FloatCompareUnordered(ppc_state, inst, a.PS1AsDouble(), b.PS1AsDouble());
}
void Interpreter::ps_cmpo1(Interpreter& interpreter, UGeckoInstruction inst)
{
auto& ppc_state = interpreter.m_ppc_state;
const auto& a = ppc_state.ps[inst.FA];
const auto& b = ppc_state.ps[inst.FB];
Helper_FloatCompareOrdered(ppc_state, inst, a.PS1AsDouble(), b.PS1AsDouble());
}

View File

@ -32,51 +32,55 @@ static void FPSCRUpdated(UReg_FPSCR* fpscr)
PowerPC::RoundingModeUpdated();
}
void Interpreter::mtfsb0x(UGeckoInstruction inst)
void Interpreter::mtfsb0x(Interpreter& interpreter, UGeckoInstruction inst)
{
auto& ppc_state = interpreter.m_ppc_state;
u32 b = 0x80000000 >> inst.CRBD;
PowerPC::ppcState.fpscr.Hex &= ~b;
FPSCRUpdated(&PowerPC::ppcState.fpscr);
ppc_state.fpscr.Hex &= ~b;
FPSCRUpdated(&ppc_state.fpscr);
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
// This instruction can affect FX
void Interpreter::mtfsb1x(UGeckoInstruction inst)
void Interpreter::mtfsb1x(Interpreter& interpreter, UGeckoInstruction inst)
{
auto& ppc_state = interpreter.m_ppc_state;
const u32 bit = inst.CRBD;
const u32 b = 0x80000000 >> bit;
if ((b & FPSCR_ANY_X) != 0)
SetFPException(&PowerPC::ppcState.fpscr, b);
SetFPException(&ppc_state.fpscr, b);
else
PowerPC::ppcState.fpscr |= b;
ppc_state.fpscr |= b;
FPSCRUpdated(&PowerPC::ppcState.fpscr);
FPSCRUpdated(&ppc_state.fpscr);
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::mtfsfix(UGeckoInstruction inst)
void Interpreter::mtfsfix(Interpreter& interpreter, UGeckoInstruction inst)
{
auto& ppc_state = interpreter.m_ppc_state;
const u32 field = inst.CRFD;
const u32 pre_shifted_mask = 0xF0000000;
const u32 mask = (pre_shifted_mask >> (4 * field));
const u32 imm = (inst.hex << 16) & pre_shifted_mask;
PowerPC::ppcState.fpscr = (PowerPC::ppcState.fpscr.Hex & ~mask) | (imm >> (4 * field));
ppc_state.fpscr = (ppc_state.fpscr.Hex & ~mask) | (imm >> (4 * field));
FPSCRUpdated(&PowerPC::ppcState.fpscr);
FPSCRUpdated(&ppc_state.fpscr);
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::mtfsfx(UGeckoInstruction inst)
void Interpreter::mtfsfx(Interpreter& interpreter, UGeckoInstruction inst)
{
auto& ppc_state = interpreter.m_ppc_state;
const u32 fm = inst.FM;
u32 m = 0;
for (u32 i = 0; i < 8; i++)
@ -85,32 +89,35 @@ void Interpreter::mtfsfx(UGeckoInstruction inst)
m |= (0xFU << (i * 4));
}
PowerPC::ppcState.fpscr = (PowerPC::ppcState.fpscr.Hex & ~m) |
(static_cast<u32>(PowerPC::ppcState.ps[inst.FB].PS0AsU64()) & m);
FPSCRUpdated(&PowerPC::ppcState.fpscr);
ppc_state.fpscr =
(ppc_state.fpscr.Hex & ~m) | (static_cast<u32>(ppc_state.ps[inst.FB].PS0AsU64()) & m);
FPSCRUpdated(&ppc_state.fpscr);
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}
void Interpreter::mcrxr(UGeckoInstruction inst)
void Interpreter::mcrxr(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.cr.SetField(inst.CRFD, PowerPC::ppcState.GetXER().Hex >> 28);
PowerPC::ppcState.xer_ca = 0;
PowerPC::ppcState.xer_so_ov = 0;
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.cr.SetField(inst.CRFD, ppc_state.GetXER().Hex >> 28);
ppc_state.xer_ca = 0;
ppc_state.xer_so_ov = 0;
}
void Interpreter::mfcr(UGeckoInstruction inst)
void Interpreter::mfcr(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.cr.Get();
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.gpr[inst.RD] = ppc_state.cr.Get();
}
void Interpreter::mtcrf(UGeckoInstruction inst)
void Interpreter::mtcrf(Interpreter& interpreter, UGeckoInstruction inst)
{
auto& ppc_state = interpreter.m_ppc_state;
const u32 crm = inst.CRM;
if (crm == 0xFF)
{
PowerPC::ppcState.cr.Set(PowerPC::ppcState.gpr[inst.RS]);
ppc_state.cr.Set(ppc_state.gpr[inst.RS]);
}
else
{
@ -122,103 +129,109 @@ void Interpreter::mtcrf(UGeckoInstruction inst)
mask |= 0xFU << (i * 4);
}
PowerPC::ppcState.cr.Set((PowerPC::ppcState.cr.Get() & ~mask) |
(PowerPC::ppcState.gpr[inst.RS] & mask));
ppc_state.cr.Set((ppc_state.cr.Get() & ~mask) | (ppc_state.gpr[inst.RS] & mask));
}
}
void Interpreter::mfmsr(UGeckoInstruction inst)
void Interpreter::mfmsr(Interpreter& interpreter, UGeckoInstruction inst)
{
if (PowerPC::ppcState.msr.PR)
auto& ppc_state = interpreter.m_ppc_state;
if (ppc_state.msr.PR)
{
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
return;
}
PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.msr.Hex;
ppc_state.gpr[inst.RD] = ppc_state.msr.Hex;
}
void Interpreter::mfsr(UGeckoInstruction inst)
void Interpreter::mfsr(Interpreter& interpreter, UGeckoInstruction inst)
{
if (PowerPC::ppcState.msr.PR)
auto& ppc_state = interpreter.m_ppc_state;
if (ppc_state.msr.PR)
{
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
return;
}
PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.sr[inst.SR];
ppc_state.gpr[inst.RD] = ppc_state.sr[inst.SR];
}
void Interpreter::mfsrin(UGeckoInstruction inst)
void Interpreter::mfsrin(Interpreter& interpreter, UGeckoInstruction inst)
{
if (PowerPC::ppcState.msr.PR)
auto& ppc_state = interpreter.m_ppc_state;
if (ppc_state.msr.PR)
{
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
return;
}
const u32 index = (PowerPC::ppcState.gpr[inst.RB] >> 28) & 0xF;
PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.sr[index];
const u32 index = (ppc_state.gpr[inst.RB] >> 28) & 0xF;
ppc_state.gpr[inst.RD] = ppc_state.sr[index];
}
void Interpreter::mtmsr(UGeckoInstruction inst)
void Interpreter::mtmsr(Interpreter& interpreter, UGeckoInstruction inst)
{
if (PowerPC::ppcState.msr.PR)
auto& ppc_state = interpreter.m_ppc_state;
if (ppc_state.msr.PR)
{
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
return;
}
PowerPC::ppcState.msr.Hex = PowerPC::ppcState.gpr[inst.RS];
ppc_state.msr.Hex = ppc_state.gpr[inst.RS];
// FE0/FE1 may have been set
CheckFPExceptions(PowerPC::ppcState.fpscr);
CheckFPExceptions(ppc_state.fpscr);
PowerPC::CheckExceptions();
m_end_block = true;
interpreter.m_end_block = true;
}
// Segment registers. MMU control.
void Interpreter::mtsr(UGeckoInstruction inst)
void Interpreter::mtsr(Interpreter& interpreter, UGeckoInstruction inst)
{
if (PowerPC::ppcState.msr.PR)
auto& ppc_state = interpreter.m_ppc_state;
if (ppc_state.msr.PR)
{
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
return;
}
const u32 index = inst.SR;
const u32 value = PowerPC::ppcState.gpr[inst.RS];
PowerPC::ppcState.SetSR(index, value);
const u32 value = ppc_state.gpr[inst.RS];
ppc_state.SetSR(index, value);
}
void Interpreter::mtsrin(UGeckoInstruction inst)
void Interpreter::mtsrin(Interpreter& interpreter, UGeckoInstruction inst)
{
if (PowerPC::ppcState.msr.PR)
auto& ppc_state = interpreter.m_ppc_state;
if (ppc_state.msr.PR)
{
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
return;
}
const u32 index = (PowerPC::ppcState.gpr[inst.RB] >> 28) & 0xF;
const u32 value = PowerPC::ppcState.gpr[inst.RS];
PowerPC::ppcState.SetSR(index, value);
const u32 index = (ppc_state.gpr[inst.RB] >> 28) & 0xF;
const u32 value = ppc_state.gpr[inst.RS];
ppc_state.SetSR(index, value);
}
void Interpreter::mftb(UGeckoInstruction inst)
void Interpreter::mftb(Interpreter& interpreter, UGeckoInstruction inst)
{
[[maybe_unused]] const u32 index = (inst.TBR >> 5) | ((inst.TBR & 0x1F) << 5);
DEBUG_ASSERT_MSG(POWERPC, (index == SPR_TL) || (index == SPR_TU), "Invalid mftb");
mfspr(inst);
mfspr(interpreter, inst);
}
void Interpreter::mfspr(UGeckoInstruction inst)
void Interpreter::mfspr(Interpreter& interpreter, UGeckoInstruction inst)
{
auto& ppc_state = interpreter.m_ppc_state;
const u32 index = ((inst.SPR & 0x1F) << 5) + ((inst.SPR >> 5) & 0x1F);
// XER, LR, CTR, and timebase halves are the only ones available in user mode.
if (PowerPC::ppcState.msr.PR && index != SPR_XER && index != SPR_LR && index != SPR_CTR &&
if (ppc_state.msr.PR && index != SPR_XER && index != SPR_LR && index != SPR_CTR &&
index != SPR_TL && index != SPR_TU)
{
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
@ -228,9 +241,9 @@ void Interpreter::mfspr(UGeckoInstruction inst)
switch (index)
{
case SPR_DEC:
if ((PowerPC::ppcState.spr[index] & 0x80000000) == 0) // We are still decrementing
if ((ppc_state.spr[index] & 0x80000000) == 0) // We are still decrementing
{
PowerPC::ppcState.spr[index] = SystemTimers::GetFakeDecrementer();
ppc_state.spr[index] = SystemTimers::GetFakeDecrementer();
}
break;
@ -248,55 +261,56 @@ void Interpreter::mfspr(UGeckoInstruction inst)
// Currently, we always treat the buffer as not empty, as the exact behavior is unclear
// (and games that use display lists will hang if the bit doesn't eventually become zero).
if (Core::System::GetInstance().GetGPFifo().IsBNE())
PowerPC::ppcState.spr[index] |= 1;
ppc_state.spr[index] |= 1;
else
PowerPC::ppcState.spr[index] &= ~1;
ppc_state.spr[index] &= ~1;
}
break;
case SPR_XER:
PowerPC::ppcState.spr[index] = PowerPC::ppcState.GetXER().Hex;
ppc_state.spr[index] = ppc_state.GetXER().Hex;
break;
case SPR_UPMC1:
PowerPC::ppcState.spr[index] = PowerPC::ppcState.spr[SPR_PMC1];
ppc_state.spr[index] = ppc_state.spr[SPR_PMC1];
break;
case SPR_UPMC2:
PowerPC::ppcState.spr[index] = PowerPC::ppcState.spr[SPR_PMC2];
ppc_state.spr[index] = ppc_state.spr[SPR_PMC2];
break;
case SPR_UPMC3:
PowerPC::ppcState.spr[index] = PowerPC::ppcState.spr[SPR_PMC3];
ppc_state.spr[index] = ppc_state.spr[SPR_PMC3];
break;
case SPR_UPMC4:
PowerPC::ppcState.spr[index] = PowerPC::ppcState.spr[SPR_PMC4];
ppc_state.spr[index] = ppc_state.spr[SPR_PMC4];
break;
case SPR_IABR:
// A strange quirk: reading back this register on hardware will always have the TE (Translation
// enabled) bit set to 0 (despite the bit appearing to function normally when set). This does
// not apply to the DABR.
PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.spr[index] & ~1;
ppc_state.gpr[inst.RD] = ppc_state.spr[index] & ~1;
return;
}
PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.spr[index];
ppc_state.gpr[inst.RD] = ppc_state.spr[index];
}
void Interpreter::mtspr(UGeckoInstruction inst)
void Interpreter::mtspr(Interpreter& interpreter, UGeckoInstruction inst)
{
auto& ppc_state = interpreter.m_ppc_state;
const u32 index = (inst.SPRU << 5) | (inst.SPRL & 0x1F);
// XER, LR, and CTR are the only ones available to be written to in user mode
if (PowerPC::ppcState.msr.PR && index != SPR_XER && index != SPR_LR && index != SPR_CTR)
if (ppc_state.msr.PR && index != SPR_XER && index != SPR_LR && index != SPR_CTR)
{
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
return;
}
const u32 old_value = PowerPC::ppcState.spr[index];
PowerPC::ppcState.spr[index] = PowerPC::ppcState.gpr[inst.RD];
const u32 old_value = ppc_state.spr[index];
ppc_state.spr[index] = ppc_state.gpr[inst.RD];
// Our DMA emulation is highly inaccurate - instead of properly emulating the queue
// and so on, we simply make all DMA:s complete instantaneously.
@ -309,41 +323,39 @@ void Interpreter::mtspr(UGeckoInstruction inst)
break;
case SPR_TL_W:
TL(PowerPC::ppcState) = PowerPC::ppcState.gpr[inst.RD];
TL(ppc_state) = ppc_state.gpr[inst.RD];
SystemTimers::TimeBaseSet();
break;
case SPR_TU_W:
TU(PowerPC::ppcState) = PowerPC::ppcState.gpr[inst.RD];
TU(ppc_state) = ppc_state.gpr[inst.RD];
SystemTimers::TimeBaseSet();
break;
case SPR_PVR:
// PVR is a read-only register so maintain its value.
PowerPC::ppcState.spr[index] = old_value;
ppc_state.spr[index] = old_value;
break;
case SPR_HID0: // HID0
{
UReg_HID0 old_hid0;
old_hid0.Hex = old_value;
if (HID0(PowerPC::ppcState).ICE != old_hid0.ICE)
if (HID0(ppc_state).ICE != old_hid0.ICE)
{
INFO_LOG_FMT(POWERPC, "Instruction Cache Enable (HID0.ICE) = {}",
HID0(PowerPC::ppcState).ICE);
INFO_LOG_FMT(POWERPC, "Instruction Cache Enable (HID0.ICE) = {}", HID0(ppc_state).ICE);
}
if (HID0(PowerPC::ppcState).ILOCK != old_hid0.ILOCK)
if (HID0(ppc_state).ILOCK != old_hid0.ILOCK)
{
INFO_LOG_FMT(POWERPC, "Instruction Cache Lock (HID0.ILOCK) = {}",
HID0(PowerPC::ppcState).ILOCK);
INFO_LOG_FMT(POWERPC, "Instruction Cache Lock (HID0.ILOCK) = {}", HID0(ppc_state).ILOCK);
}
if (HID0(PowerPC::ppcState).ICFI)
if (HID0(ppc_state).ICFI)
{
HID0(PowerPC::ppcState).ICFI = 0;
INFO_LOG_FMT(POWERPC, "Flush Instruction Cache! ICE={}", HID0(PowerPC::ppcState).ICE);
HID0(ppc_state).ICFI = 0;
INFO_LOG_FMT(POWERPC, "Flush Instruction Cache! ICE={}", HID0(ppc_state).ICE);
// this is rather slow
// most games do it only once during initialization
PowerPC::ppcState.iCache.Reset();
ppc_state.iCache.Reset();
}
}
break;
@ -352,7 +364,7 @@ void Interpreter::mtspr(UGeckoInstruction inst)
// Despite being documented as a read-only register, it actually isn't. Bits
// 0-4 (27-31 from a little endian perspective) are modifiable. The rest are not
// affected, as those bits are reserved and ignore writes to them.
PowerPC::ppcState.spr[index] &= 0xF8000000;
ppc_state.spr[index] &= 0xF8000000;
break;
case SPR_HID2:
@ -360,23 +372,22 @@ void Interpreter::mtspr(UGeckoInstruction inst)
// TODO: emulate locked cache and DMA bits.
// Only the lower half of the register (upper half from a little endian perspective)
// is modifiable, except for the DMAQL field.
PowerPC::ppcState.spr[index] =
(PowerPC::ppcState.spr[index] & 0xF0FF0000) | (old_value & 0x0F000000);
ppc_state.spr[index] = (ppc_state.spr[index] & 0xF0FF0000) | (old_value & 0x0F000000);
break;
case SPR_HID4:
if (old_value != PowerPC::ppcState.spr[index])
if (old_value != ppc_state.spr[index])
{
INFO_LOG_FMT(POWERPC, "HID4 updated {:x} {:x}", old_value, PowerPC::ppcState.spr[index]);
INFO_LOG_FMT(POWERPC, "HID4 updated {:x} {:x}", old_value, ppc_state.spr[index]);
PowerPC::IBATUpdated();
PowerPC::DBATUpdated();
}
break;
case SPR_WPAR:
ASSERT_MSG(POWERPC, PowerPC::ppcState.spr[SPR_WPAR] == GPFifo::GATHER_PIPE_PHYSICAL_ADDRESS,
ASSERT_MSG(POWERPC, ppc_state.spr[SPR_WPAR] == GPFifo::GATHER_PIPE_PHYSICAL_ADDRESS,
"Gather pipe changed to unexpected address {:08x} @ PC {:08x}",
PowerPC::ppcState.spr[SPR_WPAR], PowerPC::ppcState.pc);
ppc_state.spr[SPR_WPAR], ppc_state.pc);
Core::System::GetInstance().GetGPFifo().ResetGatherPipe();
break;
@ -394,20 +405,20 @@ void Interpreter::mtspr(UGeckoInstruction inst)
case SPR_DMAL:
// Locked cache<->Memory DMA
// Total fake, we ignore that DMAs take time.
if (DMAL(PowerPC::ppcState).DMA_T)
if (DMAL(ppc_state).DMA_T)
{
const u32 mem_address = DMAU(PowerPC::ppcState).MEM_ADDR << 5;
const u32 cache_address = DMAL(PowerPC::ppcState).LC_ADDR << 5;
u32 length = ((DMAU(PowerPC::ppcState).DMA_LEN_U << 2) | DMAL(PowerPC::ppcState).DMA_LEN_L);
const u32 mem_address = DMAU(ppc_state).MEM_ADDR << 5;
const u32 cache_address = DMAL(ppc_state).LC_ADDR << 5;
u32 length = ((DMAU(ppc_state).DMA_LEN_U << 2) | DMAL(ppc_state).DMA_LEN_L);
if (length == 0)
length = 128;
if (DMAL(PowerPC::ppcState).DMA_LD)
if (DMAL(ppc_state).DMA_LD)
PowerPC::DMA_MemoryToLC(cache_address, mem_address, length);
else
PowerPC::DMA_LCToMemory(mem_address, cache_address, length);
}
DMAL(PowerPC::ppcState).DMA_T = 0;
DMAL(ppc_state).DMA_T = 0;
break;
case SPR_L2CR:
@ -415,10 +426,10 @@ void Interpreter::mtspr(UGeckoInstruction inst)
case SPR_DEC:
// Top bit from 0 to 1
if ((old_value >> 31) == 0 && (PowerPC::ppcState.gpr[inst.RD] >> 31) != 0)
if ((old_value >> 31) == 0 && (ppc_state.gpr[inst.RD] >> 31) != 0)
{
INFO_LOG_FMT(POWERPC, "Software triggered Decrementer exception");
PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER;
ppc_state.Exceptions |= EXCEPTION_DECREMENTER;
}
SystemTimers::DecrementerSet();
break;
@ -429,7 +440,7 @@ void Interpreter::mtspr(UGeckoInstruction inst)
break;
case SPR_XER:
PowerPC::ppcState.SetXER(UReg_XER{PowerPC::ppcState.spr[index]});
ppc_state.SetXER(UReg_XER{ppc_state.spr[index]});
break;
case SPR_DBAT0L:
@ -448,10 +459,9 @@ void Interpreter::mtspr(UGeckoInstruction inst)
case SPR_DBAT6U:
case SPR_DBAT7L:
case SPR_DBAT7U:
if (old_value != PowerPC::ppcState.spr[index])
if (old_value != ppc_state.spr[index])
{
INFO_LOG_FMT(POWERPC, "DBAT updated {} {:x} {:x}", index, old_value,
PowerPC::ppcState.spr[index]);
INFO_LOG_FMT(POWERPC, "DBAT updated {} {:x} {:x}", index, old_value, ppc_state.spr[index]);
PowerPC::DBATUpdated();
}
break;
@ -472,10 +482,9 @@ void Interpreter::mtspr(UGeckoInstruction inst)
case SPR_IBAT6U:
case SPR_IBAT7L:
case SPR_IBAT7U:
if (old_value != PowerPC::ppcState.spr[index])
if (old_value != ppc_state.spr[index])
{
INFO_LOG_FMT(POWERPC, "IBAT updated {} {:x} {:x}", index, old_value,
PowerPC::ppcState.spr[index]);
INFO_LOG_FMT(POWERPC, "IBAT updated {} {:x} {:x}", index, old_value, ppc_state.spr[index]);
PowerPC::IBATUpdated();
}
break;
@ -491,8 +500,8 @@ void Interpreter::mtspr(UGeckoInstruction inst)
// TODO: Support thermal interrupts when enabled.
constexpr u32 SIMULATED_TEMP = 42; // °C
auto UpdateThermalReg = [](UReg_THRM12* reg) {
if (!THRM3(PowerPC::ppcState).E || !reg->V)
auto UpdateThermalReg = [&ppc_state](UReg_THRM12* reg) {
if (!THRM3(ppc_state).E || !reg->V)
{
reg->TIV = 0;
}
@ -506,106 +515,117 @@ void Interpreter::mtspr(UGeckoInstruction inst)
}
};
UpdateThermalReg(&THRM1(PowerPC::ppcState));
UpdateThermalReg(&THRM2(PowerPC::ppcState));
UpdateThermalReg(&THRM1(ppc_state));
UpdateThermalReg(&THRM2(ppc_state));
break;
}
}
}
void Interpreter::crand(UGeckoInstruction inst)
void Interpreter::crand(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 a = PowerPC::ppcState.cr.GetBit(inst.CRBA);
const u32 b = PowerPC::ppcState.cr.GetBit(inst.CRBB);
auto& ppc_state = interpreter.m_ppc_state;
const u32 a = ppc_state.cr.GetBit(inst.CRBA);
const u32 b = ppc_state.cr.GetBit(inst.CRBB);
PowerPC::ppcState.cr.SetBit(inst.CRBD, a & b);
ppc_state.cr.SetBit(inst.CRBD, a & b);
}
void Interpreter::crandc(UGeckoInstruction inst)
void Interpreter::crandc(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 a = PowerPC::ppcState.cr.GetBit(inst.CRBA);
const u32 b = PowerPC::ppcState.cr.GetBit(inst.CRBB);
auto& ppc_state = interpreter.m_ppc_state;
const u32 a = ppc_state.cr.GetBit(inst.CRBA);
const u32 b = ppc_state.cr.GetBit(inst.CRBB);
PowerPC::ppcState.cr.SetBit(inst.CRBD, a & (1 ^ b));
ppc_state.cr.SetBit(inst.CRBD, a & (1 ^ b));
}
void Interpreter::creqv(UGeckoInstruction inst)
void Interpreter::creqv(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 a = PowerPC::ppcState.cr.GetBit(inst.CRBA);
const u32 b = PowerPC::ppcState.cr.GetBit(inst.CRBB);
auto& ppc_state = interpreter.m_ppc_state;
const u32 a = ppc_state.cr.GetBit(inst.CRBA);
const u32 b = ppc_state.cr.GetBit(inst.CRBB);
PowerPC::ppcState.cr.SetBit(inst.CRBD, 1 ^ (a ^ b));
ppc_state.cr.SetBit(inst.CRBD, 1 ^ (a ^ b));
}
void Interpreter::crnand(UGeckoInstruction inst)
void Interpreter::crnand(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 a = PowerPC::ppcState.cr.GetBit(inst.CRBA);
const u32 b = PowerPC::ppcState.cr.GetBit(inst.CRBB);
auto& ppc_state = interpreter.m_ppc_state;
const u32 a = ppc_state.cr.GetBit(inst.CRBA);
const u32 b = ppc_state.cr.GetBit(inst.CRBB);
PowerPC::ppcState.cr.SetBit(inst.CRBD, 1 ^ (a & b));
ppc_state.cr.SetBit(inst.CRBD, 1 ^ (a & b));
}
void Interpreter::crnor(UGeckoInstruction inst)
void Interpreter::crnor(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 a = PowerPC::ppcState.cr.GetBit(inst.CRBA);
const u32 b = PowerPC::ppcState.cr.GetBit(inst.CRBB);
auto& ppc_state = interpreter.m_ppc_state;
const u32 a = ppc_state.cr.GetBit(inst.CRBA);
const u32 b = ppc_state.cr.GetBit(inst.CRBB);
PowerPC::ppcState.cr.SetBit(inst.CRBD, 1 ^ (a | b));
ppc_state.cr.SetBit(inst.CRBD, 1 ^ (a | b));
}
void Interpreter::cror(UGeckoInstruction inst)
void Interpreter::cror(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 a = PowerPC::ppcState.cr.GetBit(inst.CRBA);
const u32 b = PowerPC::ppcState.cr.GetBit(inst.CRBB);
auto& ppc_state = interpreter.m_ppc_state;
const u32 a = ppc_state.cr.GetBit(inst.CRBA);
const u32 b = ppc_state.cr.GetBit(inst.CRBB);
PowerPC::ppcState.cr.SetBit(inst.CRBD, a | b);
ppc_state.cr.SetBit(inst.CRBD, a | b);
}
void Interpreter::crorc(UGeckoInstruction inst)
void Interpreter::crorc(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 a = PowerPC::ppcState.cr.GetBit(inst.CRBA);
const u32 b = PowerPC::ppcState.cr.GetBit(inst.CRBB);
auto& ppc_state = interpreter.m_ppc_state;
const u32 a = ppc_state.cr.GetBit(inst.CRBA);
const u32 b = ppc_state.cr.GetBit(inst.CRBB);
PowerPC::ppcState.cr.SetBit(inst.CRBD, a | (1 ^ b));
ppc_state.cr.SetBit(inst.CRBD, a | (1 ^ b));
}
void Interpreter::crxor(UGeckoInstruction inst)
void Interpreter::crxor(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 a = PowerPC::ppcState.cr.GetBit(inst.CRBA);
const u32 b = PowerPC::ppcState.cr.GetBit(inst.CRBB);
auto& ppc_state = interpreter.m_ppc_state;
const u32 a = ppc_state.cr.GetBit(inst.CRBA);
const u32 b = ppc_state.cr.GetBit(inst.CRBB);
PowerPC::ppcState.cr.SetBit(inst.CRBD, a ^ b);
ppc_state.cr.SetBit(inst.CRBD, a ^ b);
}
void Interpreter::mcrf(UGeckoInstruction inst)
void Interpreter::mcrf(Interpreter& interpreter, UGeckoInstruction inst)
{
const u32 cr_f = PowerPC::ppcState.cr.GetField(inst.CRFS);
PowerPC::ppcState.cr.SetField(inst.CRFD, cr_f);
auto& ppc_state = interpreter.m_ppc_state;
const u32 cr_f = ppc_state.cr.GetField(inst.CRFS);
ppc_state.cr.SetField(inst.CRFD, cr_f);
}
void Interpreter::isync(UGeckoInstruction inst)
void Interpreter::isync(Interpreter& interpreter, UGeckoInstruction inst)
{
// shouldn't do anything
}
// the following commands read from FPSCR
void Interpreter::mcrfs(UGeckoInstruction inst)
void Interpreter::mcrfs(Interpreter& interpreter, UGeckoInstruction inst)
{
auto& ppc_state = interpreter.m_ppc_state;
const u32 shift = 4 * (7 - inst.CRFS);
const u32 fpflags = (PowerPC::ppcState.fpscr.Hex >> shift) & 0xF;
const u32 fpflags = (ppc_state.fpscr.Hex >> shift) & 0xF;
// If any exception bits were read, clear them
PowerPC::ppcState.fpscr.Hex &= ~((0xF << shift) & (FPSCR_FX | FPSCR_ANY_X));
FPSCRUpdated(&PowerPC::ppcState.fpscr);
ppc_state.fpscr.Hex &= ~((0xF << shift) & (FPSCR_FX | FPSCR_ANY_X));
FPSCRUpdated(&ppc_state.fpscr);
PowerPC::ppcState.cr.SetField(inst.CRFD, fpflags);
ppc_state.cr.SetField(inst.CRFD, fpflags);
}
void Interpreter::mffsx(UGeckoInstruction inst)
void Interpreter::mffsx(Interpreter& interpreter, UGeckoInstruction inst)
{
PowerPC::ppcState.ps[inst.FD].SetPS0(UINT64_C(0xFFF8000000000000) | PowerPC::ppcState.fpscr.Hex);
auto& ppc_state = interpreter.m_ppc_state;
ppc_state.ps[inst.FD].SetPS0(UINT64_C(0xFFF8000000000000) | ppc_state.fpscr.Hex);
if (inst.Rc)
PowerPC::ppcState.UpdateCR1();
ppc_state.UpdateCR1();
}

View File

@ -468,29 +468,29 @@ Interpreter::Instruction Interpreter::GetInterpreterOp(UGeckoInstruction inst)
return result;
}
void Interpreter::RunInterpreterOp(UGeckoInstruction inst)
void Interpreter::RunInterpreterOp(Interpreter& interpreter, UGeckoInstruction inst)
{
// Will handle subtables using RunTable4 etc.
s_interpreter_op_table[inst.OPCD](inst);
s_interpreter_op_table[inst.OPCD](interpreter, inst);
}
void Interpreter::RunTable4(UGeckoInstruction inst)
void Interpreter::RunTable4(Interpreter& interpreter, UGeckoInstruction inst)
{
s_interpreter_op_table4[inst.SUBOP10](inst);
s_interpreter_op_table4[inst.SUBOP10](interpreter, inst);
}
void Interpreter::RunTable19(UGeckoInstruction inst)
void Interpreter::RunTable19(Interpreter& interpreter, UGeckoInstruction inst)
{
s_interpreter_op_table19[inst.SUBOP10](inst);
s_interpreter_op_table19[inst.SUBOP10](interpreter, inst);
}
void Interpreter::RunTable31(UGeckoInstruction inst)
void Interpreter::RunTable31(Interpreter& interpreter, UGeckoInstruction inst)
{
s_interpreter_op_table31[inst.SUBOP10](inst);
s_interpreter_op_table31[inst.SUBOP10](interpreter, inst);
}
void Interpreter::RunTable59(UGeckoInstruction inst)
void Interpreter::RunTable59(Interpreter& interpreter, UGeckoInstruction inst)
{
s_interpreter_op_table59[inst.SUBOP5](inst);
s_interpreter_op_table59[inst.SUBOP5](interpreter, inst);
}
void Interpreter::RunTable63(UGeckoInstruction inst)
void Interpreter::RunTable63(Interpreter& interpreter, UGeckoInstruction inst)
{
s_interpreter_op_table63[inst.SUBOP10](inst);
s_interpreter_op_table63[inst.SUBOP10](interpreter, inst);
}

View File

@ -344,7 +344,7 @@ void Jit64::FallBackToInterpreter(UGeckoInstruction inst)
Interpreter::Instruction instr = Interpreter::GetInterpreterOp(inst);
ABI_PushRegistersAndAdjustStack({}, 0);
ABI_CallFunctionC(instr, inst.hex);
ABI_CallFunctionPC(instr, &Core::System::GetInstance().GetInterpreter(), inst.hex);
ABI_PopRegistersAndAdjustStack({}, 0);
// If the instruction wrote to any registers which were marked as discarded,

View File

@ -199,7 +199,8 @@ void JitArm64::FallBackToInterpreter(UGeckoInstruction inst)
Interpreter::Instruction instr = Interpreter::GetInterpreterOp(inst);
MOVP2R(ARM64Reg::X8, instr);
MOVI2R(ARM64Reg::W0, inst.hex);
MOVP2R(ARM64Reg::W0, &Core::System::GetInstance().GetInterpreter());
MOVI2R(ARM64Reg::W1, inst.hex);
BLR(ARM64Reg::X8);
// If the instruction wrote to any registers which were marked as discarded,

View File

@ -40,7 +40,6 @@ PowerPCState ppcState;
static CPUCoreBase* s_cpu_core_base = nullptr;
static bool s_cpu_core_base_is_injected = false;
Interpreter* const s_interpreter = Interpreter::getInstance();
static CoreMode s_mode = CoreMode::Interpreter;
BreakPoints breakpoints;
@ -220,12 +219,13 @@ static void InitializeCPUCore(CPUCore cpu_core)
{
// We initialize the interpreter because
// it is used on boot and code window independently.
s_interpreter->Init();
auto& interpreter = Core::System::GetInstance().GetInterpreter();
interpreter.Init();
switch (cpu_core)
{
case CPUCore::Interpreter:
s_cpu_core_base = s_interpreter;
s_cpu_core_base = &interpreter;
break;
default:
@ -239,7 +239,7 @@ static void InitializeCPUCore(CPUCore cpu_core)
break;
}
s_mode = s_cpu_core_base == s_interpreter ? CoreMode::Interpreter : CoreMode::JIT;
s_mode = s_cpu_core_base == &interpreter ? CoreMode::Interpreter : CoreMode::JIT;
}
const std::vector<CPUCore>& AvailableCPUCores()
@ -316,7 +316,8 @@ void Shutdown()
{
InjectExternalCPUCore(nullptr);
JitInterface::Shutdown();
s_interpreter->Shutdown();
auto& interpreter = Core::System::GetInstance().GetInterpreter();
interpreter.Shutdown();
s_cpu_core_base = nullptr;
}
@ -327,17 +328,19 @@ CoreMode GetMode()
static void ApplyMode()
{
auto& interpreter = Core::System::GetInstance().GetInterpreter();
switch (s_mode)
{
case CoreMode::Interpreter: // Switching from JIT to interpreter
s_cpu_core_base = s_interpreter;
s_cpu_core_base = &interpreter;
break;
case CoreMode::JIT: // Switching from interpreter to JIT.
// Don't really need to do much. It'll work, the cache will refill itself.
s_cpu_core_base = JitInterface::GetCore();
if (!s_cpu_core_base) // Has a chance to not get a working JIT core if one isn't active on host
s_cpu_core_base = s_interpreter;
s_cpu_core_base = &interpreter;
break;
}
}

View File

@ -22,6 +22,7 @@
#include "Core/HW/SI/SI.h"
#include "Core/HW/Sram.h"
#include "Core/HW/VideoInterface.h"
#include "Core/PowerPC/Interpreter/Interpreter.h"
#include "Core/PowerPC/PowerPC.h"
#include "IOS/USB/Emulated/Skylander.h"
#include "VideoCommon/CommandProcessor.h"
@ -39,7 +40,7 @@ struct System::Impl
: m_audio_interface(system), m_core_timing(system), m_dsp(system), m_dvd_interface(system),
m_dvd_thread(system), m_expansion_interface(system), m_gp_fifo(system), m_memory(system),
m_ppc_state(PowerPC::ppcState), m_processor_interface(system), m_serial_interface(system),
m_video_interface(system)
m_video_interface(system), m_interpreter(system, m_ppc_state)
{
}
@ -70,6 +71,7 @@ struct System::Impl
Sram m_sram;
VertexShaderManager m_vertex_shader_manager;
VideoInterface::VideoInterfaceManager m_video_interface;
Interpreter m_interpreter;
};
System::System() : m_impl{std::make_unique<Impl>(*this)}
@ -175,6 +177,11 @@ HSP::HSPManager& System::GetHSP() const
return m_impl->m_hsp;
}
Interpreter& System::GetInterpreter() const
{
return m_impl->m_interpreter;
}
IOS::HLE::USB::SkylanderPortal& System::GetSkylanderPortal() const
{
return m_impl->m_skylander_portal;

View File

@ -6,6 +6,7 @@
#include <memory>
class GeometryShaderManager;
class Interpreter;
class PixelShaderManager;
class SoundStream;
struct Sram;
@ -131,6 +132,7 @@ public:
GeometryShaderManager& GetGeometryShaderManager() const;
GPFifo::GPFifoManager& GetGPFifo() const;
HSP::HSPManager& GetHSP() const;
Interpreter& GetInterpreter() const;
IOS::HLE::USB::SkylanderPortal& GetSkylanderPortal() const;
Memory::MemoryManager& GetMemory() const;
MemoryInterface::MemoryInterfaceManager& GetMemoryInterface() const;