Merge pull request #11671 from AdmiralCurtiss/deglobal-interpreter
Deglobalize Interpreter
This commit is contained in:
commit
9807961ff2
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
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),
|
||||
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),
|
||||
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());
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue