mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-03-12 14:46:49 +01:00
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 CommonCallback = void (*)(UGeckoInstruction);
|
||||||
using ConditionalCallback = bool (*)(u32);
|
using ConditionalCallback = bool (*)(u32);
|
||||||
|
using InterpreterCallback = void (*)(Interpreter&, UGeckoInstruction);
|
||||||
|
|
||||||
Instruction() {}
|
Instruction() {}
|
||||||
Instruction(const CommonCallback c, UGeckoInstruction i)
|
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
|
enum class Type
|
||||||
{
|
{
|
||||||
Abort,
|
Abort,
|
||||||
Common,
|
Common,
|
||||||
Conditional,
|
Conditional,
|
||||||
|
Interpreter,
|
||||||
};
|
};
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
const CommonCallback common_callback = nullptr;
|
const CommonCallback common_callback = nullptr;
|
||||||
const ConditionalCallback conditional_callback;
|
const ConditionalCallback conditional_callback;
|
||||||
|
const InterpreterCallback interpreter_callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
u32 data = 0;
|
u32 data = 0;
|
||||||
@ -100,6 +108,11 @@ void CachedInterpreter::ExecuteOneBlock()
|
|||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Instruction::Type::Interpreter:
|
||||||
|
code->interpreter_callback(Core::System::GetInstance().GetInterpreter(),
|
||||||
|
UGeckoInstruction(code->data));
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ERROR_LOG_FMT(POWERPC, "Unknown CachedInterpreter Instruction: {}",
|
ERROR_LOG_FMT(POWERPC, "Unknown CachedInterpreter Instruction: {}",
|
||||||
static_cast<int>(code->type));
|
static_cast<int>(code->type));
|
||||||
|
@ -27,13 +27,6 @@
|
|||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
#include "Core/System.h"
|
#include "Core/System.h"
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
u32 last_pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Interpreter::m_end_block;
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
// Determines whether or not the given instruction is one where its execution
|
// 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);
|
return inst.OPCD == 4 || IsPairedSingleQuantizedNonIndexedInstruction(inst);
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
// Checks if a given instruction would be illegal to execute if it's a paired single instruction.
|
// 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.
|
// 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,
|
// 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.
|
// 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 true;
|
||||||
|
|
||||||
return HID2(PowerPC::ppcState).PSE && !HID2(PowerPC::ppcState).LSQE &&
|
return HID2(m_ppc_state).PSE && !HID2(m_ppc_state).LSQE &&
|
||||||
IsPairedSingleQuantizedNonIndexedInstruction(inst);
|
IsPairedSingleQuantizedNonIndexedInstruction(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdatePC()
|
void Interpreter::UpdatePC()
|
||||||
{
|
{
|
||||||
last_pc = PowerPC::ppcState.pc;
|
m_last_pc = m_ppc_state.pc;
|
||||||
PowerPC::ppcState.pc = PowerPC::ppcState.npc;
|
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()
|
void Interpreter::Init()
|
||||||
{
|
{
|
||||||
@ -80,44 +80,41 @@ void Interpreter::Shutdown()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool s_start_trace = false;
|
void Interpreter::Trace(const UGeckoInstruction& inst)
|
||||||
|
|
||||||
static void Trace(const UGeckoInstruction& inst)
|
|
||||||
{
|
{
|
||||||
std::string regs;
|
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;
|
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());
|
fregs += fmt::format("f{:02d}: {:08x} {:08x} ", i, ps.PS0AsU64(), ps.PS1AsU64());
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string ppc_inst =
|
const std::string ppc_inst = Common::GekkoDisassembler::Disassemble(inst.hex, m_ppc_state.pc);
|
||||||
Common::GekkoDisassembler::Disassemble(inst.hex, PowerPC::ppcState.pc);
|
|
||||||
DEBUG_LOG_FMT(POWERPC,
|
DEBUG_LOG_FMT(POWERPC,
|
||||||
"INTER PC: {:08x} SRR0: {:08x} SRR1: {:08x} CRval: {:016x} "
|
"INTER PC: {:08x} SRR0: {:08x} SRR1: {:08x} CRval: {:016x} "
|
||||||
"FPSCR: {:08x} MSR: {:08x} LR: {:08x} {} {:08x} {}",
|
"FPSCR: {:08x} MSR: {:08x} LR: {:08x} {} {:08x} {}",
|
||||||
PowerPC::ppcState.pc, SRR0(PowerPC::ppcState), SRR1(PowerPC::ppcState),
|
m_ppc_state.pc, SRR0(m_ppc_state), SRR1(m_ppc_state), m_ppc_state.cr.fields[0],
|
||||||
PowerPC::ppcState.cr.fields[0], PowerPC::ppcState.fpscr.Hex,
|
m_ppc_state.fpscr.Hex, m_ppc_state.msr.Hex, m_ppc_state.spr[8], regs, inst.hex,
|
||||||
PowerPC::ppcState.msr.Hex, PowerPC::ppcState.spr[8], regs, inst.hex, ppc_inst);
|
ppc_inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Interpreter::HandleFunctionHooking(u32 address)
|
bool Interpreter::HandleFunctionHooking(u32 address)
|
||||||
{
|
{
|
||||||
return HLE::ReplaceFunctionIfPossible(address, [](u32 hook_index, HLE::HookType type) {
|
return HLE::ReplaceFunctionIfPossible(address, [this](u32 hook_index, HLE::HookType type) {
|
||||||
HLEFunction(hook_index);
|
HLEFunction(*this, hook_index);
|
||||||
return type != HLE::HookType::Start;
|
return type != HLE::HookType::Start;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
int Interpreter::SingleStepInner()
|
int Interpreter::SingleStepInner()
|
||||||
{
|
{
|
||||||
if (HandleFunctionHooking(PowerPC::ppcState.pc))
|
if (HandleFunctionHooking(m_ppc_state.pc))
|
||||||
{
|
{
|
||||||
UpdatePC();
|
UpdatePC();
|
||||||
// TODO: Does it make sense to use m_prev_inst here?
|
// 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;
|
return PPCTables::GetOpInfo(m_prev_inst)->num_cycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
PowerPC::ppcState.npc = PowerPC::ppcState.pc + sizeof(UGeckoInstruction);
|
m_ppc_state.npc = m_ppc_state.pc + sizeof(UGeckoInstruction);
|
||||||
m_prev_inst.hex = PowerPC::Read_Opcode(PowerPC::ppcState.pc);
|
m_prev_inst.hex = PowerPC::Read_Opcode(m_ppc_state.pc);
|
||||||
|
|
||||||
const GekkoOPInfo* opinfo = PPCTables::GetOpInfo(m_prev_inst);
|
const GekkoOPInfo* opinfo = PPCTables::GetOpInfo(m_prev_inst);
|
||||||
|
|
||||||
// Uncomment to trace the interpreter
|
// Uncomment to trace the interpreter
|
||||||
// if ((PowerPC::ppcState.pc & 0x00FFFFFF) >= 0x000AB54C &&
|
// if ((m_ppc_state.pc & 0x00FFFFFF) >= 0x000AB54C &&
|
||||||
// (PowerPC::ppcState.pc & 0x00FFFFFF) <= 0x000AB624)
|
// (m_ppc_state.pc & 0x00FFFFFF) <= 0x000AB624)
|
||||||
// {
|
// {
|
||||||
// s_start_trace = true;
|
// m_start_trace = true;
|
||||||
// }
|
// }
|
||||||
// else
|
// else
|
||||||
// {
|
// {
|
||||||
// s_start_trace = false;
|
// m_start_trace = false;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (s_start_trace)
|
if (m_start_trace)
|
||||||
{
|
{
|
||||||
Trace(m_prev_inst);
|
Trace(m_prev_inst);
|
||||||
}
|
}
|
||||||
@ -154,10 +151,10 @@ int Interpreter::SingleStepInner()
|
|||||||
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
|
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
|
||||||
CheckExceptions();
|
CheckExceptions();
|
||||||
}
|
}
|
||||||
else if (PowerPC::ppcState.msr.FP)
|
else if (m_ppc_state.msr.FP)
|
||||||
{
|
{
|
||||||
RunInterpreterOp(m_prev_inst);
|
RunInterpreterOp(*this, m_prev_inst);
|
||||||
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
|
if ((m_ppc_state.Exceptions & EXCEPTION_DSI) != 0)
|
||||||
{
|
{
|
||||||
CheckExceptions();
|
CheckExceptions();
|
||||||
}
|
}
|
||||||
@ -167,13 +164,13 @@ int Interpreter::SingleStepInner()
|
|||||||
// check if we have to generate a FPU unavailable exception or a program exception.
|
// check if we have to generate a FPU unavailable exception or a program exception.
|
||||||
if ((opinfo->flags & FL_USE_FPU) != 0)
|
if ((opinfo->flags & FL_USE_FPU) != 0)
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
|
m_ppc_state.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
|
||||||
CheckExceptions();
|
CheckExceptions();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RunInterpreterOp(m_prev_inst);
|
RunInterpreterOp(*this, m_prev_inst);
|
||||||
if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0)
|
if ((m_ppc_state.Exceptions & EXCEPTION_DSI) != 0)
|
||||||
{
|
{
|
||||||
CheckExceptions();
|
CheckExceptions();
|
||||||
}
|
}
|
||||||
@ -189,13 +186,13 @@ int Interpreter::SingleStepInner()
|
|||||||
UpdatePC();
|
UpdatePC();
|
||||||
|
|
||||||
PowerPC::UpdatePerformanceMonitor(opinfo->num_cycles, (opinfo->flags & FL_LOADSTORE) != 0,
|
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;
|
return opinfo->num_cycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::SingleStep()
|
void Interpreter::SingleStep()
|
||||||
{
|
{
|
||||||
auto& core_timing = Core::System::GetInstance().GetCoreTiming();
|
auto& core_timing = m_system.GetCoreTiming();
|
||||||
auto& core_timing_globals = core_timing.GetGlobals();
|
auto& core_timing_globals = core_timing.GetGlobals();
|
||||||
|
|
||||||
// Declare start of new slice
|
// Declare start of new slice
|
||||||
@ -205,12 +202,12 @@ void Interpreter::SingleStep()
|
|||||||
|
|
||||||
// The interpreter ignores instruction timing information outside the 'fast runloop'.
|
// The interpreter ignores instruction timing information outside the 'fast runloop'.
|
||||||
core_timing_globals.slice_length = 1;
|
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::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).
|
// FastRun - inspired by GCemu (to imitate the JIT so that they can be compared).
|
||||||
void Interpreter::Run()
|
void Interpreter::Run()
|
||||||
{
|
{
|
||||||
auto& system = Core::System::GetInstance();
|
auto& core_timing = m_system.GetCoreTiming();
|
||||||
auto& core_timing = system.GetCoreTiming();
|
auto& cpu = m_system.GetCPU();
|
||||||
auto& cpu = system.GetCPU();
|
|
||||||
while (cpu.GetState() == CPU::State::Running)
|
while (cpu.GetState() == CPU::State::Running)
|
||||||
{
|
{
|
||||||
// CoreTiming Advance() ends the previous slice and declares the start of the next
|
// 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))
|
if (Config::Get(Config::MAIN_ENABLE_DEBUGGING))
|
||||||
{
|
{
|
||||||
#ifdef SHOW_HISTORY
|
#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)
|
if (s_pc_block_vec.size() > s_show_blocks)
|
||||||
s_pc_block_vec.erase(s_pc_block_vec.begin());
|
s_pc_block_vec.erase(s_pc_block_vec.begin());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Debugging friendly version of inner loop. Tries to do the timing as similarly to the
|
// 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.
|
// 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;
|
m_end_block = false;
|
||||||
int cycles = 0;
|
int cycles = 0;
|
||||||
while (!m_end_block)
|
while (!m_end_block)
|
||||||
{
|
{
|
||||||
#ifdef SHOW_HISTORY
|
#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)
|
if (s_pc_vec.size() > s_show_steps)
|
||||||
s_pc_vec.erase(s_pc_vec.begin());
|
s_pc_vec.erase(s_pc_vec.begin());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// 2: check for breakpoint
|
// 2: check for breakpoint
|
||||||
if (PowerPC::breakpoints.IsAddressBreakPoint(PowerPC::ppcState.pc))
|
if (PowerPC::breakpoints.IsAddressBreakPoint(m_ppc_state.pc))
|
||||||
{
|
{
|
||||||
#ifdef SHOW_HISTORY
|
#ifdef SHOW_HISTORY
|
||||||
NOTICE_LOG_FMT(POWERPC, "----------------------------");
|
NOTICE_LOG_FMT(POWERPC, "----------------------------");
|
||||||
@ -280,25 +276,25 @@ void Interpreter::Run()
|
|||||||
NOTICE_LOG_FMT(POWERPC, "PC: {:#010x}", s_pc_vec[j]);
|
NOTICE_LOG_FMT(POWERPC, "PC: {:#010x}", s_pc_vec[j]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
INFO_LOG_FMT(POWERPC, "Hit Breakpoint - {:08x}", PowerPC::ppcState.pc);
|
INFO_LOG_FMT(POWERPC, "Hit Breakpoint - {:08x}", m_ppc_state.pc);
|
||||||
cpu.Break();
|
cpu.Break();
|
||||||
if (GDBStub::IsActive())
|
if (GDBStub::IsActive())
|
||||||
GDBStub::TakeControl();
|
GDBStub::TakeControl();
|
||||||
if (PowerPC::breakpoints.IsTempBreakPoint(PowerPC::ppcState.pc))
|
if (PowerPC::breakpoints.IsTempBreakPoint(m_ppc_state.pc))
|
||||||
PowerPC::breakpoints.Remove(PowerPC::ppcState.pc);
|
PowerPC::breakpoints.Remove(m_ppc_state.pc);
|
||||||
|
|
||||||
Host_UpdateDisasmDialog();
|
Host_UpdateDisasmDialog();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cycles += SingleStepInner();
|
cycles += SingleStepInner();
|
||||||
}
|
}
|
||||||
PowerPC::ppcState.downcount -= cycles;
|
m_ppc_state.downcount -= cycles;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// "fast" version of inner loop. well, it's not so fast.
|
// "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;
|
m_end_block = false;
|
||||||
|
|
||||||
@ -307,36 +303,39 @@ void Interpreter::Run()
|
|||||||
{
|
{
|
||||||
cycles += SingleStepInner();
|
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());
|
ASSERT(Core::IsCPUThread());
|
||||||
auto& system = Core::System::GetInstance();
|
auto& system = interpreter.m_system;
|
||||||
Core::CPUThreadGuard guard(system);
|
Core::CPUThreadGuard guard(system);
|
||||||
|
|
||||||
|
const u32 last_pc = interpreter.m_last_pc;
|
||||||
const u32 opcode = PowerPC::HostRead_U32(guard, last_pc);
|
const u32 opcode = PowerPC::HostRead_U32(guard, last_pc);
|
||||||
const std::string disasm = Common::GekkoDisassembler::Disassemble(opcode, last_pc);
|
const std::string disasm = Common::GekkoDisassembler::Disassemble(opcode, last_pc);
|
||||||
NOTICE_LOG_FMT(POWERPC, "Last PC = {:08x} : {}", last_pc, disasm);
|
NOTICE_LOG_FMT(POWERPC, "Last PC = {:08x} : {}", last_pc, disasm);
|
||||||
Dolphin_Debugger::PrintCallstack(system, guard, Common::Log::LogType::POWERPC,
|
Dolphin_Debugger::PrintCallstack(system, guard, Common::Log::LogType::POWERPC,
|
||||||
Common::Log::LogLevel::LNOTICE);
|
Common::Log::LogLevel::LNOTICE);
|
||||||
|
|
||||||
|
const auto& ppc_state = interpreter.m_ppc_state;
|
||||||
NOTICE_LOG_FMT(
|
NOTICE_LOG_FMT(
|
||||||
POWERPC,
|
POWERPC,
|
||||||
"\nIntCPU: Unknown instruction {:08x} at PC = {:08x} last_PC = {:08x} LR = {:08x}\n",
|
"\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)
|
for (int i = 0; i < 32; i += 4)
|
||||||
{
|
{
|
||||||
NOTICE_LOG_FMT(POWERPC, "r{}: {:#010x} r{}: {:#010x} r{}: {:#010x} r{}: {:#010x}", i,
|
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,
|
ppc_state.gpr[i], i + 1, ppc_state.gpr[i + 1], i + 2, ppc_state.gpr[i + 2],
|
||||||
PowerPC::ppcState.gpr[i + 2], i + 3, PowerPC::ppcState.gpr[i + 3]);
|
i + 3, ppc_state.gpr[i + 3]);
|
||||||
}
|
}
|
||||||
ASSERT_MSG(POWERPC, 0,
|
ASSERT_MSG(POWERPC, 0,
|
||||||
"\nIntCPU: Unknown instruction {:08x} at PC = {:08x} last_PC = {:08x} LR = {:08x}\n",
|
"\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())
|
if (system.IsPauseOnPanicMode())
|
||||||
system.GetCPU().Break();
|
system.GetCPU().Break();
|
||||||
}
|
}
|
||||||
@ -360,9 +359,3 @@ const char* Interpreter::GetName() const
|
|||||||
return "Interpreter32";
|
return "Interpreter32";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Interpreter* Interpreter::getInstance()
|
|
||||||
{
|
|
||||||
static Interpreter instance;
|
|
||||||
return &instance;
|
|
||||||
}
|
|
||||||
|
@ -9,9 +9,25 @@
|
|||||||
#include "Core/PowerPC/CPUCoreBase.h"
|
#include "Core/PowerPC/CPUCoreBase.h"
|
||||||
#include "Core/PowerPC/Gekko.h"
|
#include "Core/PowerPC/Gekko.h"
|
||||||
|
|
||||||
|
namespace Core
|
||||||
|
{
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
namespace PowerPC
|
||||||
|
{
|
||||||
|
struct PowerPCState;
|
||||||
|
}
|
||||||
|
|
||||||
class Interpreter : public CPUCoreBase
|
class Interpreter : public CPUCoreBase
|
||||||
{
|
{
|
||||||
public:
|
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 Init() override;
|
||||||
void Shutdown() override;
|
void Shutdown() override;
|
||||||
void SingleStep() override;
|
void SingleStep() override;
|
||||||
@ -21,276 +37,284 @@ public:
|
|||||||
void ClearCache() override;
|
void ClearCache() override;
|
||||||
const char* GetName() const override;
|
const char* GetName() const override;
|
||||||
|
|
||||||
static void unknown_instruction(UGeckoInstruction inst);
|
static void unknown_instruction(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
|
|
||||||
// Branch Instructions
|
// Branch Instructions
|
||||||
static void bx(UGeckoInstruction inst);
|
static void bx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void bcx(UGeckoInstruction inst);
|
static void bcx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void bcctrx(UGeckoInstruction inst);
|
static void bcctrx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void bclrx(UGeckoInstruction inst);
|
static void bclrx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void HLEFunction(UGeckoInstruction inst);
|
static void HLEFunction(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
|
|
||||||
// Syscall Instruction
|
// Syscall Instruction
|
||||||
static void sc(UGeckoInstruction inst);
|
static void sc(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
|
|
||||||
// Floating Point Instructions
|
// Floating Point Instructions
|
||||||
static void faddsx(UGeckoInstruction inst);
|
static void faddsx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fdivsx(UGeckoInstruction inst);
|
static void fdivsx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fmaddsx(UGeckoInstruction inst);
|
static void fmaddsx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fmsubsx(UGeckoInstruction inst);
|
static void fmsubsx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fmulsx(UGeckoInstruction inst);
|
static void fmulsx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fnmaddsx(UGeckoInstruction inst);
|
static void fnmaddsx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fnmsubsx(UGeckoInstruction inst);
|
static void fnmsubsx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fresx(UGeckoInstruction inst);
|
static void fresx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fsubsx(UGeckoInstruction inst);
|
static void fsubsx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fabsx(UGeckoInstruction inst);
|
static void fabsx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fcmpo(UGeckoInstruction inst);
|
static void fcmpo(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fcmpu(UGeckoInstruction inst);
|
static void fcmpu(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fctiwx(UGeckoInstruction inst);
|
static void fctiwx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fctiwzx(UGeckoInstruction inst);
|
static void fctiwzx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fmrx(UGeckoInstruction inst);
|
static void fmrx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fnabsx(UGeckoInstruction inst);
|
static void fnabsx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fnegx(UGeckoInstruction inst);
|
static void fnegx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void frspx(UGeckoInstruction inst);
|
static void frspx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void faddx(UGeckoInstruction inst);
|
static void faddx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fdivx(UGeckoInstruction inst);
|
static void fdivx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fmaddx(UGeckoInstruction inst);
|
static void fmaddx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fmsubx(UGeckoInstruction inst);
|
static void fmsubx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fmulx(UGeckoInstruction inst);
|
static void fmulx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fnmaddx(UGeckoInstruction inst);
|
static void fnmaddx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fnmsubx(UGeckoInstruction inst);
|
static void fnmsubx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void frsqrtex(UGeckoInstruction inst);
|
static void frsqrtex(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fselx(UGeckoInstruction inst);
|
static void fselx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void fsubx(UGeckoInstruction inst);
|
static void fsubx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
|
|
||||||
// Integer Instructions
|
// Integer Instructions
|
||||||
static void addi(UGeckoInstruction inst);
|
static void addi(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void addic(UGeckoInstruction inst);
|
static void addic(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void addic_rc(UGeckoInstruction inst);
|
static void addic_rc(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void addis(UGeckoInstruction inst);
|
static void addis(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void andi_rc(UGeckoInstruction inst);
|
static void andi_rc(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void andis_rc(UGeckoInstruction inst);
|
static void andis_rc(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void cmpi(UGeckoInstruction inst);
|
static void cmpi(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void cmpli(UGeckoInstruction inst);
|
static void cmpli(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mulli(UGeckoInstruction inst);
|
static void mulli(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ori(UGeckoInstruction inst);
|
static void ori(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void oris(UGeckoInstruction inst);
|
static void oris(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void subfic(UGeckoInstruction inst);
|
static void subfic(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void twi(UGeckoInstruction inst);
|
static void twi(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void xori(UGeckoInstruction inst);
|
static void xori(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void xoris(UGeckoInstruction inst);
|
static void xoris(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void rlwimix(UGeckoInstruction inst);
|
static void rlwimix(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void rlwinmx(UGeckoInstruction inst);
|
static void rlwinmx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void rlwnmx(UGeckoInstruction inst);
|
static void rlwnmx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void andx(UGeckoInstruction inst);
|
static void andx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void andcx(UGeckoInstruction inst);
|
static void andcx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void cmp(UGeckoInstruction inst);
|
static void cmp(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void cmpl(UGeckoInstruction inst);
|
static void cmpl(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void cntlzwx(UGeckoInstruction inst);
|
static void cntlzwx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void eqvx(UGeckoInstruction inst);
|
static void eqvx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void extsbx(UGeckoInstruction inst);
|
static void extsbx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void extshx(UGeckoInstruction inst);
|
static void extshx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void nandx(UGeckoInstruction inst);
|
static void nandx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void norx(UGeckoInstruction inst);
|
static void norx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void orx(UGeckoInstruction inst);
|
static void orx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void orcx(UGeckoInstruction inst);
|
static void orcx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void slwx(UGeckoInstruction inst);
|
static void slwx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void srawx(UGeckoInstruction inst);
|
static void srawx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void srawix(UGeckoInstruction inst);
|
static void srawix(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void srwx(UGeckoInstruction inst);
|
static void srwx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void tw(UGeckoInstruction inst);
|
static void tw(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void xorx(UGeckoInstruction inst);
|
static void xorx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void addx(UGeckoInstruction inst);
|
static void addx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void addcx(UGeckoInstruction inst);
|
static void addcx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void addex(UGeckoInstruction inst);
|
static void addex(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void addmex(UGeckoInstruction inst);
|
static void addmex(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void addzex(UGeckoInstruction inst);
|
static void addzex(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void divwx(UGeckoInstruction inst);
|
static void divwx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void divwux(UGeckoInstruction inst);
|
static void divwux(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mulhwx(UGeckoInstruction inst);
|
static void mulhwx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mulhwux(UGeckoInstruction inst);
|
static void mulhwux(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mullwx(UGeckoInstruction inst);
|
static void mullwx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void negx(UGeckoInstruction inst);
|
static void negx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void subfx(UGeckoInstruction inst);
|
static void subfx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void subfcx(UGeckoInstruction inst);
|
static void subfcx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void subfex(UGeckoInstruction inst);
|
static void subfex(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void subfmex(UGeckoInstruction inst);
|
static void subfmex(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void subfzex(UGeckoInstruction inst);
|
static void subfzex(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
|
|
||||||
// Load/Store Instructions
|
// Load/Store Instructions
|
||||||
static void lbz(UGeckoInstruction inst);
|
static void lbz(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lbzu(UGeckoInstruction inst);
|
static void lbzu(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lfd(UGeckoInstruction inst);
|
static void lfd(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lfdu(UGeckoInstruction inst);
|
static void lfdu(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lfs(UGeckoInstruction inst);
|
static void lfs(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lfsu(UGeckoInstruction inst);
|
static void lfsu(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lha(UGeckoInstruction inst);
|
static void lha(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lhau(UGeckoInstruction inst);
|
static void lhau(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lhz(UGeckoInstruction inst);
|
static void lhz(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lhzu(UGeckoInstruction inst);
|
static void lhzu(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lmw(UGeckoInstruction inst);
|
static void lmw(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lwz(UGeckoInstruction inst);
|
static void lwz(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lwzu(UGeckoInstruction inst);
|
static void lwzu(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stb(UGeckoInstruction inst);
|
static void stb(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stbu(UGeckoInstruction inst);
|
static void stbu(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stfd(UGeckoInstruction inst);
|
static void stfd(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stfdu(UGeckoInstruction inst);
|
static void stfdu(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stfs(UGeckoInstruction inst);
|
static void stfs(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stfsu(UGeckoInstruction inst);
|
static void stfsu(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void sth(UGeckoInstruction inst);
|
static void sth(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void sthu(UGeckoInstruction inst);
|
static void sthu(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stmw(UGeckoInstruction inst);
|
static void stmw(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stw(UGeckoInstruction inst);
|
static void stw(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stwu(UGeckoInstruction inst);
|
static void stwu(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void dcba(UGeckoInstruction inst);
|
static void dcba(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void dcbf(UGeckoInstruction inst);
|
static void dcbf(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void dcbi(UGeckoInstruction inst);
|
static void dcbi(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void dcbst(UGeckoInstruction inst);
|
static void dcbst(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void dcbt(UGeckoInstruction inst);
|
static void dcbt(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void dcbtst(UGeckoInstruction inst);
|
static void dcbtst(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void dcbz(UGeckoInstruction inst);
|
static void dcbz(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void eciwx(UGeckoInstruction inst);
|
static void eciwx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ecowx(UGeckoInstruction inst);
|
static void ecowx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void eieio(UGeckoInstruction inst);
|
static void eieio(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void icbi(UGeckoInstruction inst);
|
static void icbi(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lbzux(UGeckoInstruction inst);
|
static void lbzux(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lbzx(UGeckoInstruction inst);
|
static void lbzx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lfdux(UGeckoInstruction inst);
|
static void lfdux(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lfdx(UGeckoInstruction inst);
|
static void lfdx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lfsux(UGeckoInstruction inst);
|
static void lfsux(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lfsx(UGeckoInstruction inst);
|
static void lfsx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lhaux(UGeckoInstruction inst);
|
static void lhaux(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lhax(UGeckoInstruction inst);
|
static void lhax(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lhbrx(UGeckoInstruction inst);
|
static void lhbrx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lhzux(UGeckoInstruction inst);
|
static void lhzux(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lhzx(UGeckoInstruction inst);
|
static void lhzx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lswi(UGeckoInstruction inst);
|
static void lswi(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lswx(UGeckoInstruction inst);
|
static void lswx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lwarx(UGeckoInstruction inst);
|
static void lwarx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lwbrx(UGeckoInstruction inst);
|
static void lwbrx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lwzux(UGeckoInstruction inst);
|
static void lwzux(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void lwzx(UGeckoInstruction inst);
|
static void lwzx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stbux(UGeckoInstruction inst);
|
static void stbux(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stbx(UGeckoInstruction inst);
|
static void stbx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stfdux(UGeckoInstruction inst);
|
static void stfdux(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stfdx(UGeckoInstruction inst);
|
static void stfdx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stfiwx(UGeckoInstruction inst);
|
static void stfiwx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stfsux(UGeckoInstruction inst);
|
static void stfsux(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stfsx(UGeckoInstruction inst);
|
static void stfsx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void sthbrx(UGeckoInstruction inst);
|
static void sthbrx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void sthux(UGeckoInstruction inst);
|
static void sthux(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void sthx(UGeckoInstruction inst);
|
static void sthx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stswi(UGeckoInstruction inst);
|
static void stswi(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stswx(UGeckoInstruction inst);
|
static void stswx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stwbrx(UGeckoInstruction inst);
|
static void stwbrx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stwcxd(UGeckoInstruction inst);
|
static void stwcxd(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stwux(UGeckoInstruction inst);
|
static void stwux(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void stwx(UGeckoInstruction inst);
|
static void stwx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void tlbie(UGeckoInstruction inst);
|
static void tlbie(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void tlbsync(UGeckoInstruction inst);
|
static void tlbsync(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
|
|
||||||
// Paired Instructions
|
// Paired Instructions
|
||||||
static void psq_l(UGeckoInstruction inst);
|
static void psq_l(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void psq_lu(UGeckoInstruction inst);
|
static void psq_lu(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void psq_st(UGeckoInstruction inst);
|
static void psq_st(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void psq_stu(UGeckoInstruction inst);
|
static void psq_stu(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void psq_lx(UGeckoInstruction inst);
|
static void psq_lx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void psq_stx(UGeckoInstruction inst);
|
static void psq_stx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void psq_lux(UGeckoInstruction inst);
|
static void psq_lux(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void psq_stux(UGeckoInstruction inst);
|
static void psq_stux(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_div(UGeckoInstruction inst);
|
static void ps_div(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_sub(UGeckoInstruction inst);
|
static void ps_sub(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_add(UGeckoInstruction inst);
|
static void ps_add(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_sel(UGeckoInstruction inst);
|
static void ps_sel(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_res(UGeckoInstruction inst);
|
static void ps_res(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_mul(UGeckoInstruction inst);
|
static void ps_mul(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_rsqrte(UGeckoInstruction inst);
|
static void ps_rsqrte(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_msub(UGeckoInstruction inst);
|
static void ps_msub(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_madd(UGeckoInstruction inst);
|
static void ps_madd(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_nmsub(UGeckoInstruction inst);
|
static void ps_nmsub(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_nmadd(UGeckoInstruction inst);
|
static void ps_nmadd(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_neg(UGeckoInstruction inst);
|
static void ps_neg(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_mr(UGeckoInstruction inst);
|
static void ps_mr(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_nabs(UGeckoInstruction inst);
|
static void ps_nabs(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_abs(UGeckoInstruction inst);
|
static void ps_abs(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_sum0(UGeckoInstruction inst);
|
static void ps_sum0(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_sum1(UGeckoInstruction inst);
|
static void ps_sum1(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_muls0(UGeckoInstruction inst);
|
static void ps_muls0(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_muls1(UGeckoInstruction inst);
|
static void ps_muls1(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_madds0(UGeckoInstruction inst);
|
static void ps_madds0(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_madds1(UGeckoInstruction inst);
|
static void ps_madds1(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_cmpu0(UGeckoInstruction inst);
|
static void ps_cmpu0(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_cmpo0(UGeckoInstruction inst);
|
static void ps_cmpo0(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_cmpu1(UGeckoInstruction inst);
|
static void ps_cmpu1(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_cmpo1(UGeckoInstruction inst);
|
static void ps_cmpo1(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_merge00(UGeckoInstruction inst);
|
static void ps_merge00(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_merge01(UGeckoInstruction inst);
|
static void ps_merge01(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_merge10(UGeckoInstruction inst);
|
static void ps_merge10(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void ps_merge11(UGeckoInstruction inst);
|
static void ps_merge11(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void dcbz_l(UGeckoInstruction inst);
|
static void dcbz_l(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
|
|
||||||
// System Registers Instructions
|
// System Registers Instructions
|
||||||
static void mcrfs(UGeckoInstruction inst);
|
static void mcrfs(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mffsx(UGeckoInstruction inst);
|
static void mffsx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mtfsb0x(UGeckoInstruction inst);
|
static void mtfsb0x(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mtfsb1x(UGeckoInstruction inst);
|
static void mtfsb1x(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mtfsfix(UGeckoInstruction inst);
|
static void mtfsfix(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mtfsfx(UGeckoInstruction inst);
|
static void mtfsfx(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mcrxr(UGeckoInstruction inst);
|
static void mcrxr(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mfcr(UGeckoInstruction inst);
|
static void mfcr(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mfmsr(UGeckoInstruction inst);
|
static void mfmsr(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mfsr(UGeckoInstruction inst);
|
static void mfsr(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mfsrin(UGeckoInstruction inst);
|
static void mfsrin(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mtmsr(UGeckoInstruction inst);
|
static void mtmsr(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mtsr(UGeckoInstruction inst);
|
static void mtsr(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mtsrin(UGeckoInstruction inst);
|
static void mtsrin(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mfspr(UGeckoInstruction inst);
|
static void mfspr(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mftb(UGeckoInstruction inst);
|
static void mftb(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mtcrf(UGeckoInstruction inst);
|
static void mtcrf(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mtspr(UGeckoInstruction inst);
|
static void mtspr(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void crand(UGeckoInstruction inst);
|
static void crand(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void crandc(UGeckoInstruction inst);
|
static void crandc(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void creqv(UGeckoInstruction inst);
|
static void creqv(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void crnand(UGeckoInstruction inst);
|
static void crnand(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void crnor(UGeckoInstruction inst);
|
static void crnor(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void cror(UGeckoInstruction inst);
|
static void cror(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void crorc(UGeckoInstruction inst);
|
static void crorc(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void crxor(UGeckoInstruction inst);
|
static void crxor(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void mcrf(UGeckoInstruction inst);
|
static void mcrf(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void rfi(UGeckoInstruction inst);
|
static void rfi(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void sync(UGeckoInstruction inst);
|
static void sync(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void isync(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 Instruction GetInterpreterOp(UGeckoInstruction inst);
|
||||||
static void RunInterpreterOp(UGeckoInstruction inst);
|
static void RunInterpreterOp(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
|
|
||||||
// singleton
|
static void RunTable4(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static Interpreter* getInstance();
|
static void RunTable19(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
|
static void RunTable31(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void RunTable4(UGeckoInstruction inst);
|
static void RunTable59(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void RunTable19(UGeckoInstruction inst);
|
static void RunTable63(Interpreter& interpreter, UGeckoInstruction inst);
|
||||||
static void RunTable31(UGeckoInstruction inst);
|
|
||||||
static void RunTable59(UGeckoInstruction inst);
|
|
||||||
static void RunTable63(UGeckoInstruction inst);
|
|
||||||
|
|
||||||
static u32 Helper_Carry(u32 value1, u32 value2);
|
static u32 Helper_Carry(u32 value1, u32 value2);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void CheckExceptions();
|
void CheckExceptions();
|
||||||
|
|
||||||
static bool HandleFunctionHooking(u32 address);
|
bool HandleFunctionHooking(u32 address);
|
||||||
|
|
||||||
// flag helper
|
// flag helper
|
||||||
static void Helper_UpdateCR0(u32 value);
|
static void Helper_UpdateCR0(PowerPC::PowerPCState& ppc_state, u32 value);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static void Helper_IntCompare(UGeckoInstruction inst, T a, T b);
|
static void Helper_IntCompare(PowerPC::PowerPCState& ppc_state, UGeckoInstruction inst, T a, T b);
|
||||||
static void Helper_FloatCompareOrdered(UGeckoInstruction inst, double a, double b);
|
static void Helper_FloatCompareOrdered(PowerPC::PowerPCState& ppc_state, UGeckoInstruction inst,
|
||||||
static void Helper_FloatCompareUnordered(UGeckoInstruction inst, double a, double b);
|
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{};
|
UGeckoInstruction m_prev_inst{};
|
||||||
|
u32 m_last_pc = 0;
|
||||||
static bool m_end_block;
|
bool m_end_block = false;
|
||||||
|
bool m_start_trace = false;
|
||||||
};
|
};
|
||||||
|
@ -12,101 +12,110 @@
|
|||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
#include "Core/System.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)
|
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));
|
const auto address = u32(SignExt26(inst.LI << 2));
|
||||||
|
|
||||||
if (inst.AA)
|
if (inst.AA)
|
||||||
PowerPC::ppcState.npc = address;
|
ppc_state.npc = address;
|
||||||
else
|
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 :)
|
// 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)
|
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 true_false = ((inst.BO >> 3) & 1) != 0;
|
||||||
const bool only_counter_check = ((inst.BO >> 4) & 1) != 0;
|
const bool only_counter_check = ((inst.BO >> 4) & 1) != 0;
|
||||||
const bool only_condition_check = ((inst.BO >> 2) & 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 counter = only_condition_check || ctr_check != 0;
|
||||||
const bool condition =
|
const bool condition = only_counter_check || (ppc_state.cr.GetBit(inst.BI) == u32(true_false));
|
||||||
only_counter_check || (PowerPC::ppcState.cr.GetBit(inst.BI) == u32(true_false));
|
|
||||||
|
|
||||||
if (counter && condition)
|
if (counter && condition)
|
||||||
{
|
{
|
||||||
if (inst.LK)
|
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)));
|
const auto address = u32(SignExt16(s16(inst.BD << 2)));
|
||||||
|
|
||||||
if (inst.AA)
|
if (inst.AA)
|
||||||
PowerPC::ppcState.npc = address;
|
ppc_state.npc = address;
|
||||||
else
|
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,
|
DEBUG_ASSERT_MSG(POWERPC, (inst.BO_2 & BO_DONT_DECREMENT_FLAG) != 0,
|
||||||
"bcctrx with decrement and test CTR option is invalid!");
|
"bcctrx with decrement and test CTR option is invalid!");
|
||||||
|
|
||||||
const u32 condition =
|
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)
|
if (condition != 0)
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.npc = CTR(PowerPC::ppcState) & (~3);
|
ppc_state.npc = CTR(ppc_state) & (~3);
|
||||||
if (inst.LK_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)
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
CTR(PowerPC::ppcState)--;
|
|
||||||
|
|
||||||
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 =
|
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)
|
if ((counter & condition) != 0)
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.npc = LR(PowerPC::ppcState) & (~3);
|
ppc_state.npc = LR(ppc_state) & (~3);
|
||||||
if (inst.LK_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());
|
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);
|
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
||||||
return;
|
return;
|
||||||
@ -115,26 +124,27 @@ void Interpreter::rfi(UGeckoInstruction inst)
|
|||||||
// Restore saved bits from SRR1 to MSR.
|
// Restore saved bits from SRR1 to MSR.
|
||||||
// Gecko/Broadway can save more bits than explicitly defined in ppc spec
|
// Gecko/Broadway can save more bits than explicitly defined in ppc spec
|
||||||
const u32 mask = 0x87C0FFFF;
|
const u32 mask = 0x87C0FFFF;
|
||||||
PowerPC::ppcState.msr.Hex =
|
ppc_state.msr.Hex = (ppc_state.msr.Hex & ~mask) | (SRR1(ppc_state) & mask);
|
||||||
(PowerPC::ppcState.msr.Hex & ~mask) | (SRR1(PowerPC::ppcState) & mask);
|
|
||||||
// MSR[13] is set to 0.
|
// 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
|
// Here we should check if there are pending exceptions, and if their corresponding enable bits
|
||||||
// are set
|
// are set
|
||||||
// if above is true, we'd do:
|
// if above is true, we'd do:
|
||||||
// PowerPC::CheckExceptions();
|
// PowerPC::CheckExceptions();
|
||||||
// else
|
// else
|
||||||
// set NPC to saved offset and resume
|
// set NPC to saved offset and resume
|
||||||
PowerPC::ppcState.npc = SRR0(PowerPC::ppcState);
|
ppc_state.npc = SRR0(ppc_state);
|
||||||
m_end_block = true;
|
interpreter.m_end_block = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sc isn't really used for anything important in GameCube games (just for a write barrier) so we
|
// 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.
|
// really don't have to emulate it.
|
||||||
// We do it anyway, though :P
|
// 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();
|
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
|
// Note that the convert to integer operation is defined
|
||||||
// in Appendix C.4.2 in PowerPC Microprocessor Family:
|
// in Appendix C.4.2 in PowerPC Microprocessor Family:
|
||||||
// The Programming Environments Manual for 32 and 64-bit Microprocessors
|
// 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;
|
u32 value;
|
||||||
bool exception_occurred = false;
|
bool exception_occurred = false;
|
||||||
|
|
||||||
if (std::isnan(b))
|
if (std::isnan(b))
|
||||||
{
|
{
|
||||||
if (Common::IsSNAN(b))
|
if (Common::IsSNAN(b))
|
||||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
|
SetFPException(&ppc_state.fpscr, FPSCR_VXSNAN);
|
||||||
|
|
||||||
value = 0x80000000;
|
value = 0x80000000;
|
||||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXCVI);
|
SetFPException(&ppc_state.fpscr, FPSCR_VXCVI);
|
||||||
exception_occurred = true;
|
exception_occurred = true;
|
||||||
}
|
}
|
||||||
else if (b > static_cast<double>(0x7fffffff))
|
else if (b > static_cast<double>(0x7fffffff))
|
||||||
{
|
{
|
||||||
// Positive large operand or +inf
|
// Positive large operand or +inf
|
||||||
value = 0x7fffffff;
|
value = 0x7fffffff;
|
||||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXCVI);
|
SetFPException(&ppc_state.fpscr, FPSCR_VXCVI);
|
||||||
exception_occurred = true;
|
exception_occurred = true;
|
||||||
}
|
}
|
||||||
else if (b < -static_cast<double>(0x80000000))
|
else if (b < -static_cast<double>(0x80000000))
|
||||||
{
|
{
|
||||||
// Negative large operand or -inf
|
// Negative large operand or -inf
|
||||||
value = 0x80000000;
|
value = 0x80000000;
|
||||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXCVI);
|
SetFPException(&ppc_state.fpscr, FPSCR_VXCVI);
|
||||||
exception_occurred = true;
|
exception_occurred = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -103,22 +104,22 @@ void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode)
|
|||||||
const double di = i;
|
const double di = i;
|
||||||
if (di == b)
|
if (di == b)
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
ppc_state.fpscr.ClearFIFR();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Also sets FPSCR[XX]
|
// Also sets FPSCR[XX]
|
||||||
SetFI(&PowerPC::ppcState.fpscr, 1);
|
SetFI(&ppc_state.fpscr, 1);
|
||||||
PowerPC::ppcState.fpscr.FR = fabs(di) > fabs(b);
|
ppc_state.fpscr.FR = fabs(di) > fabs(b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exception_occurred)
|
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
|
// Based on HW tests
|
||||||
// FPRF is not affected
|
// FPRF is not affected
|
||||||
@ -126,15 +127,16 @@ void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode)
|
|||||||
if (value == 0 && std::signbit(b))
|
if (value == 0 && std::signbit(b))
|
||||||
result |= 0x100000000ull;
|
result |= 0x100000000ull;
|
||||||
|
|
||||||
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
|
ppc_state.ps[inst.FD].SetPS0(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
PowerPC::ppcState.UpdateCR1();
|
ppc_state.UpdateCR1();
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // 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;
|
FPCC compare_result;
|
||||||
|
|
||||||
@ -143,15 +145,15 @@ void Interpreter::Helper_FloatCompareOrdered(UGeckoInstruction inst, double fa,
|
|||||||
compare_result = FPCC::FU;
|
compare_result = FPCC::FU;
|
||||||
if (Common::IsSNAN(fa) || Common::IsSNAN(fb))
|
if (Common::IsSNAN(fa) || Common::IsSNAN(fb))
|
||||||
{
|
{
|
||||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
|
SetFPException(&ppc_state.fpscr, FPSCR_VXSNAN);
|
||||||
if (PowerPC::ppcState.fpscr.VE == 0)
|
if (ppc_state.fpscr.VE == 0)
|
||||||
{
|
{
|
||||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXVC);
|
SetFPException(&ppc_state.fpscr, FPSCR_VXVC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // QNaN
|
else // QNaN
|
||||||
{
|
{
|
||||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXVC);
|
SetFPException(&ppc_state.fpscr, FPSCR_VXVC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (fa < fb)
|
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);
|
const u32 compare_value = static_cast<u32>(compare_result);
|
||||||
|
|
||||||
// Clear and set the FPCC bits accordingly.
|
// 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;
|
FPCC compare_result;
|
||||||
|
|
||||||
@ -185,7 +188,7 @@ void Interpreter::Helper_FloatCompareUnordered(UGeckoInstruction inst, double fa
|
|||||||
|
|
||||||
if (Common::IsSNAN(fa) || Common::IsSNAN(fb))
|
if (Common::IsSNAN(fa) || Common::IsSNAN(fb))
|
||||||
{
|
{
|
||||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
|
SetFPException(&ppc_state.fpscr, FPSCR_VXSNAN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (fa < fb)
|
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);
|
const u32 compare_value = static_cast<u32>(compare_result);
|
||||||
|
|
||||||
// Clear and set the FPCC bits accordingly.
|
// 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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
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
|
// This is a binary instruction. Does not alter FPSCR
|
||||||
if (inst.Rc)
|
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
|
// This is a binary instruction. Does not alter FPSCR
|
||||||
if (inst.Rc)
|
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() |
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
(UINT64_C(1) << 63));
|
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
|
// This is a binary instruction. Does not alter FPSCR
|
||||||
if (inst.Rc)
|
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() ^
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
(UINT64_C(1) << 63));
|
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
|
// This is a binary instruction. Does not alter FPSCR
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
const auto& a = ppc_state.ps[inst.FA];
|
||||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
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() :
|
ppc_state.ps[inst.FD].SetPS0((a.PS0AsDouble() >= -0.0) ? c.PS0AsDouble() : b.PS0AsDouble());
|
||||||
b.PS0AsDouble());
|
|
||||||
|
|
||||||
// This is a binary instruction. Does not alter FPSCR
|
// This is a binary instruction. Does not alter FPSCR
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
PowerPC::ppcState.UpdateCR1();
|
ppc_state.UpdateCR1();
|
||||||
}
|
}
|
||||||
|
|
||||||
// !!! warning !!!
|
// !!! warning !!!
|
||||||
// PS1 must be set to the value of PS0 or DragonballZ will be f**ked up
|
// PS1 must be set to the value of PS0 or DragonballZ will be f**ked up
|
||||||
// PS1 is said to be undefined
|
// 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();
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const float rounded = ForceSingle(PowerPC::ppcState.fpscr, b);
|
const double b = ppc_state.ps[inst.FB].PS0AsDouble();
|
||||||
|
const float rounded = ForceSingle(ppc_state.fpscr, b);
|
||||||
|
|
||||||
if (std::isnan(b))
|
if (std::isnan(b))
|
||||||
{
|
{
|
||||||
const bool is_snan = Common::IsSNAN(b);
|
const bool is_snan = Common::IsSNAN(b);
|
||||||
|
|
||||||
if (is_snan)
|
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);
|
ppc_state.ps[inst.FD].Fill(rounded);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(rounded);
|
ppc_state.UpdateFPRFSingle(rounded);
|
||||||
}
|
}
|
||||||
|
|
||||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
ppc_state.fpscr.ClearFIFR();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SetFI(&PowerPC::ppcState.fpscr, b != rounded);
|
SetFI(&ppc_state.fpscr, b != rounded);
|
||||||
PowerPC::ppcState.fpscr.FR = fabs(rounded) > fabs(b);
|
ppc_state.fpscr.FR = fabs(rounded) > fabs(b);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(rounded);
|
ppc_state.UpdateFPRFSingle(rounded);
|
||||||
PowerPC::ppcState.ps[inst.FD].Fill(rounded);
|
ppc_state.ps[inst.FD].Fill(rounded);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
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);
|
ppc_state.ps[inst.FD].SetPS0(result);
|
||||||
PowerPC::ppcState.fpscr.FI = 0; // are these flags important?
|
ppc_state.fpscr.FI = 0; // are these flags important?
|
||||||
PowerPC::ppcState.fpscr.FR = 0;
|
ppc_state.fpscr.FR = 0;
|
||||||
PowerPC::ppcState.UpdateFPRFDouble(result);
|
ppc_state.UpdateFPRFDouble(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
const auto& a = ppc_state.ps[inst.FA];
|
||||||
|
const auto& c = ppc_state.ps[inst.FC];
|
||||||
|
|
||||||
const double c_value = Force25Bit(c.PS0AsDouble());
|
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);
|
ppc_state.ps[inst.FD].Fill(result);
|
||||||
PowerPC::ppcState.fpscr.FI = 0;
|
ppc_state.fpscr.FI = 0;
|
||||||
PowerPC::ppcState.fpscr.FR = 0;
|
ppc_state.fpscr.FR = 0;
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(result);
|
ppc_state.UpdateFPRFSingle(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
const auto& a = ppc_state.ps[inst.FA];
|
||||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
const auto& b = ppc_state.ps[inst.FB];
|
||||||
|
const auto& c = ppc_state.ps[inst.FC];
|
||||||
const FPResult product =
|
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);
|
const double result = ForceDouble(ppc_state.fpscr, product.value);
|
||||||
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
|
ppc_state.ps[inst.FD].SetPS0(result);
|
||||||
PowerPC::ppcState.UpdateFPRFDouble(result);
|
ppc_state.UpdateFPRFDouble(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
const auto& a = ppc_state.ps[inst.FA];
|
||||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
const auto& b = ppc_state.ps[inst.FB];
|
||||||
|
const auto& c = ppc_state.ps[inst.FC];
|
||||||
|
|
||||||
const double c_value = Force25Bit(c.PS0AsDouble());
|
const double c_value = Force25Bit(c.PS0AsDouble());
|
||||||
const FPResult d_value =
|
const FPResult d_value = NI_madd(&ppc_state.fpscr, a.PS0AsDouble(), c_value, b.PS0AsDouble());
|
||||||
NI_madd(&PowerPC::ppcState.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);
|
ppc_state.ps[inst.FD].Fill(result);
|
||||||
PowerPC::ppcState.fpscr.FI = d_value.value != result;
|
ppc_state.fpscr.FI = d_value.value != result;
|
||||||
PowerPC::ppcState.fpscr.FR = 0;
|
ppc_state.fpscr.FR = 0;
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(result);
|
ppc_state.UpdateFPRFSingle(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
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);
|
const double result = ForceDouble(ppc_state.fpscr, sum.value);
|
||||||
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
|
ppc_state.ps[inst.FD].SetPS0(result);
|
||||||
PowerPC::ppcState.UpdateFPRFDouble(result);
|
ppc_state.UpdateFPRFDouble(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
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);
|
const float result = ForceSingle(ppc_state.fpscr, sum.value);
|
||||||
PowerPC::ppcState.ps[inst.FD].Fill(result);
|
ppc_state.ps[inst.FD].Fill(result);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(result);
|
ppc_state.UpdateFPRFSingle(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
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 FPResult quotient = NI_div(&ppc_state.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
|
||||||
const bool not_divide_by_zero = PowerPC::ppcState.fpscr.ZE == 0 || quotient.exception != FPSCR_ZX;
|
const bool not_divide_by_zero = ppc_state.fpscr.ZE == 0 || quotient.exception != FPSCR_ZX;
|
||||||
const bool not_invalid = PowerPC::ppcState.fpscr.VE == 0 || quotient.HasNoInvalidExceptions();
|
const bool not_invalid = ppc_state.fpscr.VE == 0 || quotient.HasNoInvalidExceptions();
|
||||||
|
|
||||||
if (not_divide_by_zero && not_invalid)
|
if (not_divide_by_zero && not_invalid)
|
||||||
{
|
{
|
||||||
const double result = ForceDouble(PowerPC::ppcState.fpscr, quotient.value);
|
const double result = ForceDouble(ppc_state.fpscr, quotient.value);
|
||||||
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
|
ppc_state.ps[inst.FD].SetPS0(result);
|
||||||
PowerPC::ppcState.UpdateFPRFDouble(result);
|
ppc_state.UpdateFPRFDouble(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FR,FI,OX,UX???
|
// FR,FI,OX,UX???
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
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 FPResult quotient = NI_div(&ppc_state.fpscr, a.PS0AsDouble(), b.PS0AsDouble());
|
||||||
const bool not_divide_by_zero = PowerPC::ppcState.fpscr.ZE == 0 || quotient.exception != FPSCR_ZX;
|
const bool not_divide_by_zero = ppc_state.fpscr.ZE == 0 || quotient.exception != FPSCR_ZX;
|
||||||
const bool not_invalid = PowerPC::ppcState.fpscr.VE == 0 || quotient.HasNoInvalidExceptions();
|
const bool not_invalid = ppc_state.fpscr.VE == 0 || quotient.HasNoInvalidExceptions();
|
||||||
|
|
||||||
if (not_divide_by_zero && not_invalid)
|
if (not_divide_by_zero && not_invalid)
|
||||||
{
|
{
|
||||||
const float result = ForceSingle(PowerPC::ppcState.fpscr, quotient.value);
|
const float result = ForceSingle(ppc_state.fpscr, quotient.value);
|
||||||
PowerPC::ppcState.ps[inst.FD].Fill(result);
|
ppc_state.ps[inst.FD].Fill(result);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(result);
|
ppc_state.UpdateFPRFSingle(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
PowerPC::ppcState.UpdateCR1();
|
ppc_state.UpdateCR1();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Single precision only.
|
// 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);
|
const double result = Common::ApproximateReciprocal(value);
|
||||||
PowerPC::ppcState.ps[inst.FD].Fill(result);
|
ppc_state.ps[inst.FD].Fill(result);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(float(result));
|
ppc_state.UpdateFPRFSingle(float(result));
|
||||||
};
|
};
|
||||||
|
|
||||||
if (b == 0.0)
|
if (b == 0.0)
|
||||||
{
|
{
|
||||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_ZX);
|
SetFPException(&ppc_state.fpscr, FPSCR_ZX);
|
||||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
ppc_state.fpscr.ClearFIFR();
|
||||||
|
|
||||||
if (PowerPC::ppcState.fpscr.ZE == 0)
|
if (ppc_state.fpscr.ZE == 0)
|
||||||
compute_result(b);
|
compute_result(b);
|
||||||
}
|
}
|
||||||
else if (Common::IsSNAN(b))
|
else if (Common::IsSNAN(b))
|
||||||
{
|
{
|
||||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
|
SetFPException(&ppc_state.fpscr, FPSCR_VXSNAN);
|
||||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
ppc_state.fpscr.ClearFIFR();
|
||||||
|
|
||||||
if (PowerPC::ppcState.fpscr.VE == 0)
|
if (ppc_state.fpscr.VE == 0)
|
||||||
compute_result(b);
|
compute_result(b);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (std::isnan(b) || std::isinf(b))
|
if (std::isnan(b) || std::isinf(b))
|
||||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
ppc_state.fpscr.ClearFIFR();
|
||||||
|
|
||||||
compute_result(b);
|
compute_result(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
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);
|
const double result = Common::ApproximateReciprocalSquareRoot(value);
|
||||||
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
|
ppc_state.ps[inst.FD].SetPS0(result);
|
||||||
PowerPC::ppcState.UpdateFPRFDouble(result);
|
ppc_state.UpdateFPRFDouble(result);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (b < 0.0)
|
if (b < 0.0)
|
||||||
{
|
{
|
||||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSQRT);
|
SetFPException(&ppc_state.fpscr, FPSCR_VXSQRT);
|
||||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
ppc_state.fpscr.ClearFIFR();
|
||||||
|
|
||||||
if (PowerPC::ppcState.fpscr.VE == 0)
|
if (ppc_state.fpscr.VE == 0)
|
||||||
compute_result(b);
|
compute_result(b);
|
||||||
}
|
}
|
||||||
else if (b == 0.0)
|
else if (b == 0.0)
|
||||||
{
|
{
|
||||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_ZX);
|
SetFPException(&ppc_state.fpscr, FPSCR_ZX);
|
||||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
ppc_state.fpscr.ClearFIFR();
|
||||||
|
|
||||||
if (PowerPC::ppcState.fpscr.ZE == 0)
|
if (ppc_state.fpscr.ZE == 0)
|
||||||
compute_result(b);
|
compute_result(b);
|
||||||
}
|
}
|
||||||
else if (Common::IsSNAN(b))
|
else if (Common::IsSNAN(b))
|
||||||
{
|
{
|
||||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
|
SetFPException(&ppc_state.fpscr, FPSCR_VXSNAN);
|
||||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
ppc_state.fpscr.ClearFIFR();
|
||||||
|
|
||||||
if (PowerPC::ppcState.fpscr.VE == 0)
|
if (ppc_state.fpscr.VE == 0)
|
||||||
compute_result(b);
|
compute_result(b);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (std::isnan(b) || std::isinf(b))
|
if (std::isnan(b) || std::isinf(b))
|
||||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
ppc_state.fpscr.ClearFIFR();
|
||||||
|
|
||||||
compute_result(b);
|
compute_result(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
const auto& a = ppc_state.ps[inst.FA];
|
||||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
const auto& b = ppc_state.ps[inst.FB];
|
||||||
|
const auto& c = ppc_state.ps[inst.FC];
|
||||||
|
|
||||||
const FPResult product =
|
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);
|
const double result = ForceDouble(ppc_state.fpscr, product.value);
|
||||||
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
|
ppc_state.ps[inst.FD].SetPS0(result);
|
||||||
PowerPC::ppcState.UpdateFPRFDouble(result);
|
ppc_state.UpdateFPRFDouble(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
const auto& a = ppc_state.ps[inst.FA];
|
||||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
const auto& b = ppc_state.ps[inst.FB];
|
||||||
|
const auto& c = ppc_state.ps[inst.FC];
|
||||||
|
|
||||||
const double c_value = Force25Bit(c.PS0AsDouble());
|
const double c_value = Force25Bit(c.PS0AsDouble());
|
||||||
const FPResult product =
|
const FPResult product = NI_msub(&ppc_state.fpscr, a.PS0AsDouble(), c_value, b.PS0AsDouble());
|
||||||
NI_msub(&PowerPC::ppcState.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);
|
const float result = ForceSingle(ppc_state.fpscr, product.value);
|
||||||
PowerPC::ppcState.ps[inst.FD].Fill(result);
|
ppc_state.ps[inst.FD].Fill(result);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(result);
|
ppc_state.UpdateFPRFSingle(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
const auto& a = ppc_state.ps[inst.FA];
|
||||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
const auto& b = ppc_state.ps[inst.FB];
|
||||||
|
const auto& c = ppc_state.ps[inst.FC];
|
||||||
|
|
||||||
const FPResult product =
|
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;
|
const double result = std::isnan(tmp) ? tmp : -tmp;
|
||||||
|
|
||||||
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
|
ppc_state.ps[inst.FD].SetPS0(result);
|
||||||
PowerPC::ppcState.UpdateFPRFDouble(result);
|
ppc_state.UpdateFPRFDouble(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
const auto& a = ppc_state.ps[inst.FA];
|
||||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
const auto& b = ppc_state.ps[inst.FB];
|
||||||
|
const auto& c = ppc_state.ps[inst.FC];
|
||||||
|
|
||||||
const double c_value = Force25Bit(c.PS0AsDouble());
|
const double c_value = Force25Bit(c.PS0AsDouble());
|
||||||
const FPResult product =
|
const FPResult product = NI_madd(&ppc_state.fpscr, a.PS0AsDouble(), c_value, b.PS0AsDouble());
|
||||||
NI_madd(&PowerPC::ppcState.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;
|
const float result = std::isnan(tmp) ? tmp : -tmp;
|
||||||
|
|
||||||
PowerPC::ppcState.ps[inst.FD].Fill(result);
|
ppc_state.ps[inst.FD].Fill(result);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(result);
|
ppc_state.UpdateFPRFSingle(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
const auto& a = ppc_state.ps[inst.FA];
|
||||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
const auto& b = ppc_state.ps[inst.FB];
|
||||||
|
const auto& c = ppc_state.ps[inst.FC];
|
||||||
|
|
||||||
const FPResult product =
|
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;
|
const double result = std::isnan(tmp) ? tmp : -tmp;
|
||||||
|
|
||||||
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
|
ppc_state.ps[inst.FD].SetPS0(result);
|
||||||
PowerPC::ppcState.UpdateFPRFDouble(result);
|
ppc_state.UpdateFPRFDouble(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
const auto& a = ppc_state.ps[inst.FA];
|
||||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
const auto& b = ppc_state.ps[inst.FB];
|
||||||
|
const auto& c = ppc_state.ps[inst.FC];
|
||||||
|
|
||||||
const double c_value = Force25Bit(c.PS0AsDouble());
|
const double c_value = Force25Bit(c.PS0AsDouble());
|
||||||
const FPResult product =
|
const FPResult product = NI_msub(&ppc_state.fpscr, a.PS0AsDouble(), c_value, b.PS0AsDouble());
|
||||||
NI_msub(&PowerPC::ppcState.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;
|
const float result = std::isnan(tmp) ? tmp : -tmp;
|
||||||
|
|
||||||
PowerPC::ppcState.ps[inst.FD].Fill(result);
|
ppc_state.ps[inst.FD].Fill(result);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(result);
|
ppc_state.UpdateFPRFSingle(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
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);
|
const double result = ForceDouble(ppc_state.fpscr, difference.value);
|
||||||
PowerPC::ppcState.ps[inst.FD].SetPS0(result);
|
ppc_state.ps[inst.FD].SetPS0(result);
|
||||||
PowerPC::ppcState.UpdateFPRFDouble(result);
|
ppc_state.UpdateFPRFDouble(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
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);
|
const float result = ForceSingle(ppc_state.fpscr, difference.value);
|
||||||
PowerPC::ppcState.ps[inst.FD].Fill(result);
|
ppc_state.ps[inst.FD].Fill(result);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(result);
|
ppc_state.UpdateFPRFSingle(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
PowerPC::ppcState.UpdateCR1();
|
ppc_state.UpdateCR1();
|
||||||
}
|
}
|
||||||
|
@ -11,14 +11,14 @@
|
|||||||
#include "Core/PowerPC/Interpreter/ExceptionUtils.h"
|
#include "Core/PowerPC/Interpreter/ExceptionUtils.h"
|
||||||
#include "Core/PowerPC/PowerPC.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)};
|
const s64 sign_extended = s64{s32(value)};
|
||||||
u64 cr_val = u64(sign_extended);
|
u64 cr_val = u64(sign_extended);
|
||||||
cr_val = (cr_val & ~(1ULL << PowerPC::CR_EMU_SO_BIT)) |
|
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)
|
u32 Interpreter::Helper_Carry(u32 value1, u32 value2)
|
||||||
@ -26,51 +26,58 @@ u32 Interpreter::Helper_Carry(u32 value1, u32 value2)
|
|||||||
return value2 > (~value1);
|
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)
|
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
|
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});
|
const u32 imm = u32(s32{inst.SIMM_16});
|
||||||
|
|
||||||
PowerPC::ppcState.gpr[inst.RD] = a + imm;
|
ppc_state.gpr[inst.RD] = a + imm;
|
||||||
PowerPC::ppcState.SetCarry(Helper_Carry(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);
|
addic(interpreter, inst);
|
||||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RD]);
|
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)
|
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
|
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;
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
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);
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
Helper_UpdateCR0(PowerPC::ppcState.gpr[inst.RA]);
|
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>
|
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;
|
u32 cr_field;
|
||||||
|
|
||||||
@ -81,52 +88,59 @@ void Interpreter::Helper_IntCompare(UGeckoInstruction inst, T a, T b)
|
|||||||
else
|
else
|
||||||
cr_field = PowerPC::CR_EQ;
|
cr_field = PowerPC::CR_EQ;
|
||||||
|
|
||||||
if (PowerPC::ppcState.GetXER_SO())
|
if (ppc_state.GetXER_SO())
|
||||||
cr_field |= PowerPC::CR_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;
|
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;
|
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;
|
const s32 immediate = inst.SIMM_16;
|
||||||
PowerPC::ppcState.gpr[inst.RD] = u32(immediate - s32(PowerPC::ppcState.gpr[inst.RA]));
|
ppc_state.gpr[inst.RD] = u32(immediate - s32(ppc_state.gpr[inst.RA]));
|
||||||
PowerPC::ppcState.SetCarry((PowerPC::ppcState.gpr[inst.RA] == 0) ||
|
ppc_state.SetCarry((ppc_state.gpr[inst.RA] == 0) ||
|
||||||
(Helper_Carry(0 - PowerPC::ppcState.gpr[inst.RA], u32(immediate))));
|
(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 s32 b = inst.SIMM_16;
|
||||||
const u32 TO = inst.TO;
|
const u32 TO = inst.TO;
|
||||||
|
|
||||||
@ -137,213 +151,228 @@ void Interpreter::twi(UGeckoInstruction inst)
|
|||||||
{
|
{
|
||||||
GenerateProgramException(ProgramExceptionCause::Trap);
|
GenerateProgramException(ProgramExceptionCause::Trap);
|
||||||
PowerPC::CheckExceptions();
|
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);
|
const u32 mask = MakeRotationMask(inst.MB, inst.ME);
|
||||||
PowerPC::ppcState.gpr[inst.RA] = (PowerPC::ppcState.gpr[inst.RA] & ~mask) |
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
(std::rotl(PowerPC::ppcState.gpr[inst.RS], inst.SH) & mask);
|
ppc_state.gpr[inst.RA] =
|
||||||
|
(ppc_state.gpr[inst.RA] & ~mask) | (std::rotl(ppc_state.gpr[inst.RS], inst.SH) & mask);
|
||||||
|
|
||||||
if (inst.Rc)
|
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);
|
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)
|
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);
|
const u32 mask = MakeRotationMask(inst.MB, inst.ME);
|
||||||
PowerPC::ppcState.gpr[inst.RA] =
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
std::rotl(PowerPC::ppcState.gpr[inst.RS], PowerPC::ppcState.gpr[inst.RB] & 0x1F) & mask;
|
ppc_state.gpr[inst.RA] = std::rotl(ppc_state.gpr[inst.RS], ppc_state.gpr[inst.RB] & 0x1F) & mask;
|
||||||
|
|
||||||
if (inst.Rc)
|
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)
|
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)
|
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]);
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const s32 b = static_cast<s32>(PowerPC::ppcState.gpr[inst.RB]);
|
const s32 a = static_cast<s32>(ppc_state.gpr[inst.RA]);
|
||||||
Helper_IntCompare(inst, a, b);
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const u32 b = PowerPC::ppcState.gpr[inst.RB];
|
const u32 a = ppc_state.gpr[inst.RA];
|
||||||
Helper_IntCompare(inst, a, b);
|
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)
|
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] =
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
~(PowerPC::ppcState.gpr[inst.RS] ^ PowerPC::ppcState.gpr[inst.RB]);
|
ppc_state.gpr[inst.RA] = ~(ppc_state.gpr[inst.RS] ^ ppc_state.gpr[inst.RB]);
|
||||||
|
|
||||||
if (inst.Rc)
|
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)
|
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)
|
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] =
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
~(PowerPC::ppcState.gpr[inst.RS] & PowerPC::ppcState.gpr[inst.RB]);
|
ppc_state.gpr[inst.RA] = ~(ppc_state.gpr[inst.RS] & ppc_state.gpr[inst.RB]);
|
||||||
|
|
||||||
if (inst.Rc)
|
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] =
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
~(PowerPC::ppcState.gpr[inst.RS] | PowerPC::ppcState.gpr[inst.RB]);
|
ppc_state.gpr[inst.RA] = ~(ppc_state.gpr[inst.RS] | ppc_state.gpr[inst.RB]);
|
||||||
|
|
||||||
if (inst.Rc)
|
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)
|
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] =
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
PowerPC::ppcState.gpr[inst.RS] | (~PowerPC::ppcState.gpr[inst.RB]);
|
ppc_state.gpr[inst.RA] = ppc_state.gpr[inst.RS] | (~ppc_state.gpr[inst.RB]);
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
PowerPC::ppcState.gpr[inst.RA] =
|
const u32 amount = ppc_state.gpr[inst.RB];
|
||||||
(amount & 0x20) != 0 ? 0 : PowerPC::ppcState.gpr[inst.RS] << (amount & 0x1f);
|
ppc_state.gpr[inst.RA] = (amount & 0x20) != 0 ? 0 : ppc_state.gpr[inst.RS] << (amount & 0x1f);
|
||||||
|
|
||||||
if (inst.Rc)
|
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 ((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;
|
ppc_state.gpr[inst.RA] = 0xFFFFFFFF;
|
||||||
PowerPC::ppcState.SetCarry(1);
|
ppc_state.SetCarry(1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.gpr[inst.RA] = 0x00000000;
|
ppc_state.gpr[inst.RA] = 0x00000000;
|
||||||
PowerPC::ppcState.SetCarry(0);
|
ppc_state.SetCarry(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const u32 amount = rb & 0x1f;
|
const u32 amount = rb & 0x1f;
|
||||||
const s32 rrs = s32(PowerPC::ppcState.gpr[inst.RS]);
|
const s32 rrs = s32(ppc_state.gpr[inst.RS]);
|
||||||
PowerPC::ppcState.gpr[inst.RA] = u32(rrs >> amount);
|
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)
|
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 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);
|
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)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
PowerPC::ppcState.gpr[inst.RA] =
|
const u32 amount = ppc_state.gpr[inst.RB];
|
||||||
(amount & 0x20) != 0 ? 0 : (PowerPC::ppcState.gpr[inst.RS] >> (amount & 0x1f));
|
ppc_state.gpr[inst.RA] = (amount & 0x20) != 0 ? 0 : (ppc_state.gpr[inst.RS] >> (amount & 0x1f));
|
||||||
|
|
||||||
if (inst.Rc)
|
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]);
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const s32 b = s32(PowerPC::ppcState.gpr[inst.RB]);
|
const s32 a = s32(ppc_state.gpr[inst.RA]);
|
||||||
|
const s32 b = s32(ppc_state.gpr[inst.RB]);
|
||||||
const u32 TO = inst.TO;
|
const u32 TO = inst.TO;
|
||||||
|
|
||||||
DEBUG_LOG_FMT(POWERPC, "tw rA {:x} rB {:x} TO {:x}", a, b, 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);
|
GenerateProgramException(ProgramExceptionCause::Trap);
|
||||||
PowerPC::CheckExceptions();
|
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)
|
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)
|
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;
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const u32 b = PowerPC::ppcState.gpr[inst.RB];
|
const u32 a = ppc_state.gpr[inst.RA];
|
||||||
|
const u32 b = ppc_state.gpr[inst.RB];
|
||||||
const u32 result = a + b;
|
const u32 result = a + b;
|
||||||
|
|
||||||
PowerPC::ppcState.gpr[inst.RD] = result;
|
ppc_state.gpr[inst.RD] = result;
|
||||||
|
|
||||||
if (inst.OE)
|
if (inst.OE)
|
||||||
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
|
ppc_state.SetXER_OV(HasAddOverflowed(a, b, result));
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const u32 b = PowerPC::ppcState.gpr[inst.RB];
|
const u32 a = ppc_state.gpr[inst.RA];
|
||||||
|
const u32 b = ppc_state.gpr[inst.RB];
|
||||||
const u32 result = a + b;
|
const u32 result = a + b;
|
||||||
|
|
||||||
PowerPC::ppcState.gpr[inst.RD] = result;
|
ppc_state.gpr[inst.RD] = result;
|
||||||
PowerPC::ppcState.SetCarry(Helper_Carry(a, b));
|
ppc_state.SetCarry(Helper_Carry(a, b));
|
||||||
|
|
||||||
if (inst.OE)
|
if (inst.OE)
|
||||||
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
|
ppc_state.SetXER_OV(HasAddOverflowed(a, b, result));
|
||||||
|
|
||||||
if (inst.Rc)
|
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();
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const u32 a = PowerPC::ppcState.gpr[inst.RA];
|
const u32 carry = ppc_state.GetCarry();
|
||||||
const u32 b = PowerPC::ppcState.gpr[inst.RB];
|
const u32 a = ppc_state.gpr[inst.RA];
|
||||||
|
const u32 b = ppc_state.gpr[inst.RB];
|
||||||
const u32 result = a + b + carry;
|
const u32 result = a + b + carry;
|
||||||
|
|
||||||
PowerPC::ppcState.gpr[inst.RD] = result;
|
ppc_state.gpr[inst.RD] = result;
|
||||||
PowerPC::ppcState.SetCarry(Helper_Carry(a, b) || (carry != 0 && Helper_Carry(a + b, carry)));
|
ppc_state.SetCarry(Helper_Carry(a, b) || (carry != 0 && Helper_Carry(a + b, carry)));
|
||||||
|
|
||||||
if (inst.OE)
|
if (inst.OE)
|
||||||
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
|
ppc_state.SetXER_OV(HasAddOverflowed(a, b, result));
|
||||||
|
|
||||||
if (inst.Rc)
|
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();
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const u32 a = PowerPC::ppcState.gpr[inst.RA];
|
const u32 carry = ppc_state.GetCarry();
|
||||||
|
const u32 a = ppc_state.gpr[inst.RA];
|
||||||
const u32 b = 0xFFFFFFFF;
|
const u32 b = 0xFFFFFFFF;
|
||||||
const u32 result = a + b + carry;
|
const u32 result = a + b + carry;
|
||||||
|
|
||||||
PowerPC::ppcState.gpr[inst.RD] = result;
|
ppc_state.gpr[inst.RD] = result;
|
||||||
PowerPC::ppcState.SetCarry(Helper_Carry(a, carry - 1));
|
ppc_state.SetCarry(Helper_Carry(a, carry - 1));
|
||||||
|
|
||||||
if (inst.OE)
|
if (inst.OE)
|
||||||
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
|
ppc_state.SetXER_OV(HasAddOverflowed(a, b, result));
|
||||||
|
|
||||||
if (inst.Rc)
|
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();
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const u32 a = PowerPC::ppcState.gpr[inst.RA];
|
const u32 carry = ppc_state.GetCarry();
|
||||||
|
const u32 a = ppc_state.gpr[inst.RA];
|
||||||
const u32 result = a + carry;
|
const u32 result = a + carry;
|
||||||
|
|
||||||
PowerPC::ppcState.gpr[inst.RD] = result;
|
ppc_state.gpr[inst.RD] = result;
|
||||||
PowerPC::ppcState.SetCarry(Helper_Carry(a, carry));
|
ppc_state.SetCarry(Helper_Carry(a, carry));
|
||||||
|
|
||||||
if (inst.OE)
|
if (inst.OE)
|
||||||
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, 0, result));
|
ppc_state.SetXER_OV(HasAddOverflowed(a, 0, result));
|
||||||
|
|
||||||
if (inst.Rc)
|
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]);
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto b = s32(PowerPC::ppcState.gpr[inst.RB]);
|
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);
|
const bool overflow = b == 0 || (static_cast<u32>(a) == 0x80000000 && b == -1);
|
||||||
|
|
||||||
if (overflow)
|
if (overflow)
|
||||||
{
|
{
|
||||||
if (a < 0)
|
if (a < 0)
|
||||||
PowerPC::ppcState.gpr[inst.RD] = UINT32_MAX;
|
ppc_state.gpr[inst.RD] = UINT32_MAX;
|
||||||
else
|
else
|
||||||
PowerPC::ppcState.gpr[inst.RD] = 0;
|
ppc_state.gpr[inst.RD] = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.gpr[inst.RD] = static_cast<u32>(a / b);
|
ppc_state.gpr[inst.RD] = static_cast<u32>(a / b);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.OE)
|
if (inst.OE)
|
||||||
PowerPC::ppcState.SetXER_OV(overflow);
|
ppc_state.SetXER_OV(overflow);
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const u32 b = PowerPC::ppcState.gpr[inst.RB];
|
const u32 a = ppc_state.gpr[inst.RA];
|
||||||
|
const u32 b = ppc_state.gpr[inst.RB];
|
||||||
const bool overflow = b == 0;
|
const bool overflow = b == 0;
|
||||||
|
|
||||||
if (overflow)
|
if (overflow)
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.gpr[inst.RD] = 0;
|
ppc_state.gpr[inst.RD] = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.gpr[inst.RD] = a / b;
|
ppc_state.gpr[inst.RD] = a / b;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst.OE)
|
if (inst.OE)
|
||||||
PowerPC::ppcState.SetXER_OV(overflow);
|
ppc_state.SetXER_OV(overflow);
|
||||||
|
|
||||||
if (inst.Rc)
|
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]);
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const s64 b = static_cast<s32>(PowerPC::ppcState.gpr[inst.RB]);
|
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);
|
const u32 d = static_cast<u32>((a * b) >> 32);
|
||||||
|
|
||||||
PowerPC::ppcState.gpr[inst.RD] = d;
|
ppc_state.gpr[inst.RD] = d;
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const u64 b = PowerPC::ppcState.gpr[inst.RB];
|
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);
|
const u32 d = static_cast<u32>((a * b) >> 32);
|
||||||
|
|
||||||
PowerPC::ppcState.gpr[inst.RD] = d;
|
ppc_state.gpr[inst.RD] = d;
|
||||||
|
|
||||||
if (inst.Rc)
|
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]);
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const s64 b = static_cast<s32>(PowerPC::ppcState.gpr[inst.RB]);
|
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;
|
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)
|
if (inst.OE)
|
||||||
PowerPC::ppcState.SetXER_OV(result < -0x80000000LL || result > 0x7FFFFFFFLL);
|
ppc_state.SetXER_OV(result < -0x80000000LL || result > 0x7FFFFFFFLL);
|
||||||
|
|
||||||
if (inst.Rc)
|
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)
|
if (inst.OE)
|
||||||
PowerPC::ppcState.SetXER_OV(a == 0x80000000);
|
ppc_state.SetXER_OV(a == 0x80000000);
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const u32 b = PowerPC::ppcState.gpr[inst.RB];
|
const u32 a = ~ppc_state.gpr[inst.RA];
|
||||||
|
const u32 b = ppc_state.gpr[inst.RB];
|
||||||
const u32 result = a + b + 1;
|
const u32 result = a + b + 1;
|
||||||
|
|
||||||
PowerPC::ppcState.gpr[inst.RD] = result;
|
ppc_state.gpr[inst.RD] = result;
|
||||||
|
|
||||||
if (inst.OE)
|
if (inst.OE)
|
||||||
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
|
ppc_state.SetXER_OV(HasAddOverflowed(a, b, result));
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const u32 b = PowerPC::ppcState.gpr[inst.RB];
|
const u32 a = ~ppc_state.gpr[inst.RA];
|
||||||
|
const u32 b = ppc_state.gpr[inst.RB];
|
||||||
const u32 result = a + b + 1;
|
const u32 result = a + b + 1;
|
||||||
|
|
||||||
PowerPC::ppcState.gpr[inst.RD] = result;
|
ppc_state.gpr[inst.RD] = result;
|
||||||
PowerPC::ppcState.SetCarry(a == 0xFFFFFFFF || Helper_Carry(b, a + 1));
|
ppc_state.SetCarry(a == 0xFFFFFFFF || Helper_Carry(b, a + 1));
|
||||||
|
|
||||||
if (inst.OE)
|
if (inst.OE)
|
||||||
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
|
ppc_state.SetXER_OV(HasAddOverflowed(a, b, result));
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const u32 b = PowerPC::ppcState.gpr[inst.RB];
|
const u32 a = ~ppc_state.gpr[inst.RA];
|
||||||
const u32 carry = PowerPC::ppcState.GetCarry();
|
const u32 b = ppc_state.gpr[inst.RB];
|
||||||
|
const u32 carry = ppc_state.GetCarry();
|
||||||
const u32 result = a + b + carry;
|
const u32 result = a + b + carry;
|
||||||
|
|
||||||
PowerPC::ppcState.gpr[inst.RD] = result;
|
ppc_state.gpr[inst.RD] = result;
|
||||||
PowerPC::ppcState.SetCarry(Helper_Carry(a, b) || Helper_Carry(a + b, carry));
|
ppc_state.SetCarry(Helper_Carry(a, b) || Helper_Carry(a + b, carry));
|
||||||
|
|
||||||
if (inst.OE)
|
if (inst.OE)
|
||||||
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
|
ppc_state.SetXER_OV(HasAddOverflowed(a, b, result));
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
Helper_UpdateCR0(result);
|
Helper_UpdateCR0(ppc_state, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// sub from minus one
|
// 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 b = 0xFFFFFFFF;
|
||||||
const u32 carry = PowerPC::ppcState.GetCarry();
|
const u32 carry = ppc_state.GetCarry();
|
||||||
const u32 result = a + b + carry;
|
const u32 result = a + b + carry;
|
||||||
|
|
||||||
PowerPC::ppcState.gpr[inst.RD] = result;
|
ppc_state.gpr[inst.RD] = result;
|
||||||
PowerPC::ppcState.SetCarry(Helper_Carry(a, carry - 1));
|
ppc_state.SetCarry(Helper_Carry(a, carry - 1));
|
||||||
|
|
||||||
if (inst.OE)
|
if (inst.OE)
|
||||||
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, b, result));
|
ppc_state.SetXER_OV(HasAddOverflowed(a, b, result));
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
Helper_UpdateCR0(result);
|
Helper_UpdateCR0(ppc_state, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// sub from zero
|
// sub from zero
|
||||||
void Interpreter::subfzex(UGeckoInstruction inst)
|
void Interpreter::subfzex(Interpreter& interpreter, UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
const u32 a = ~PowerPC::ppcState.gpr[inst.RA];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const u32 carry = PowerPC::ppcState.GetCarry();
|
const u32 a = ~ppc_state.gpr[inst.RA];
|
||||||
|
const u32 carry = ppc_state.GetCarry();
|
||||||
const u32 result = a + carry;
|
const u32 result = a + carry;
|
||||||
|
|
||||||
PowerPC::ppcState.gpr[inst.RD] = result;
|
ppc_state.gpr[inst.RD] = result;
|
||||||
PowerPC::ppcState.SetCarry(Helper_Carry(a, carry));
|
ppc_state.SetCarry(Helper_Carry(a, carry));
|
||||||
|
|
||||||
if (inst.OE)
|
if (inst.OE)
|
||||||
PowerPC::ppcState.SetXER_OV(HasAddOverflowed(a, 0, result));
|
ppc_state.SetXER_OV(HasAddOverflowed(a, 0, result));
|
||||||
|
|
||||||
if (inst.Rc)
|
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);
|
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);
|
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 EA = inst.RA ? (PowerPC::ppcState.gpr[inst.RA] + u32(inst.SIMM_12)) : u32(inst.SIMM_12);
|
const u32 EA = inst.RA ? (ppc_state.gpr[inst.RA] + u32(inst.SIMM_12)) : u32(inst.SIMM_12);
|
||||||
Helper_Dequantize(&PowerPC::ppcState, EA, inst.I, inst.RD, inst.W);
|
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);
|
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 EA = PowerPC::ppcState.gpr[inst.RA] + u32(inst.SIMM_12);
|
const u32 EA = ppc_state.gpr[inst.RA] + u32(inst.SIMM_12);
|
||||||
Helper_Dequantize(&PowerPC::ppcState, EA, inst.I, inst.RD, inst.W);
|
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;
|
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);
|
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 EA = inst.RA ? (PowerPC::ppcState.gpr[inst.RA] + u32(inst.SIMM_12)) : u32(inst.SIMM_12);
|
const u32 EA = inst.RA ? (ppc_state.gpr[inst.RA] + u32(inst.SIMM_12)) : u32(inst.SIMM_12);
|
||||||
Helper_Quantize(&PowerPC::ppcState, EA, inst.I, inst.RS, inst.W);
|
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);
|
GenerateProgramException(ProgramExceptionCause::IllegalInstruction);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 EA = PowerPC::ppcState.gpr[inst.RA] + u32(inst.SIMM_12);
|
const u32 EA = ppc_state.gpr[inst.RA] + u32(inst.SIMM_12);
|
||||||
Helper_Quantize(&PowerPC::ppcState, EA, inst.I, inst.RS, inst.W);
|
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;
|
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]) :
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
PowerPC::ppcState.gpr[inst.RB];
|
const u32 EA =
|
||||||
Helper_Dequantize(&PowerPC::ppcState, EA, inst.Ix, inst.RD, inst.Wx);
|
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]) :
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
PowerPC::ppcState.gpr[inst.RB];
|
const u32 EA =
|
||||||
Helper_Quantize(&PowerPC::ppcState, EA, inst.Ix, inst.RS, inst.Wx);
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
Helper_Dequantize(&PowerPC::ppcState, EA, inst.Ix, inst.RD, inst.Wx);
|
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;
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
Helper_Quantize(&PowerPC::ppcState, EA, inst.Ix, inst.RS, inst.Wx);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PowerPC::ppcState.gpr[inst.RA] = EA;
|
ppc_state.gpr[inst.RA] = EA;
|
||||||
}
|
}
|
||||||
|
@ -11,487 +11,493 @@
|
|||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
|
|
||||||
// These "binary instructions" do not alter FPSCR.
|
// 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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
const auto& a = ppc_state.ps[inst.FA];
|
||||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
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(),
|
ppc_state.ps[inst.FD].SetBoth(a.PS0AsDouble() >= -0.0 ? c.PS0AsDouble() : b.PS0AsDouble(),
|
||||||
a.PS1AsDouble() >= -0.0 ? c.PS1AsDouble() :
|
a.PS1AsDouble() >= -0.0 ? c.PS1AsDouble() : b.PS1AsDouble());
|
||||||
b.PS1AsDouble());
|
|
||||||
|
|
||||||
if (inst.Rc)
|
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));
|
b.PS1AsU64() ^ (UINT64_C(1) << 63));
|
||||||
|
|
||||||
if (inst.Rc)
|
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)
|
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));
|
b.PS1AsU64() | (UINT64_C(1) << 63));
|
||||||
|
|
||||||
if (inst.Rc)
|
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));
|
b.PS1AsU64() & ~(UINT64_C(1) << 63));
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
PowerPC::ppcState.UpdateCR1();
|
ppc_state.UpdateCR1();
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are just moves, double is OK.
|
// 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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
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)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
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)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
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)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
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)
|
if (inst.Rc)
|
||||||
PowerPC::ppcState.UpdateCR1();
|
ppc_state.UpdateCR1();
|
||||||
}
|
}
|
||||||
|
|
||||||
// From here on, the real deal.
|
// 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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
const auto& a = ppc_state.ps[inst.FA];
|
||||||
|
const auto& b = ppc_state.ps[inst.FB];
|
||||||
|
|
||||||
const float ps0 =
|
const float ps0 = ForceSingle(ppc_state.fpscr,
|
||||||
ForceSingle(PowerPC::ppcState.fpscr,
|
NI_div(&ppc_state.fpscr, a.PS0AsDouble(), b.PS0AsDouble()).value);
|
||||||
NI_div(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble()).value);
|
const float ps1 = ForceSingle(ppc_state.fpscr,
|
||||||
const float ps1 =
|
NI_div(&ppc_state.fpscr, a.PS1AsDouble(), b.PS1AsDouble()).value);
|
||||||
ForceSingle(PowerPC::ppcState.fpscr,
|
|
||||||
NI_div(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), b.PS1AsDouble()).value);
|
|
||||||
|
|
||||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
ppc_state.UpdateFPRFSingle(ps0);
|
||||||
|
|
||||||
if (inst.Rc)
|
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
|
// this code is based on the real hardware tests
|
||||||
const double a = PowerPC::ppcState.ps[inst.FB].PS0AsDouble();
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const double b = PowerPC::ppcState.ps[inst.FB].PS1AsDouble();
|
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)
|
if (a == 0.0 || b == 0.0)
|
||||||
{
|
{
|
||||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_ZX);
|
SetFPException(&ppc_state.fpscr, FPSCR_ZX);
|
||||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
ppc_state.fpscr.ClearFIFR();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::isnan(a) || std::isinf(a) || std::isnan(b) || std::isinf(b))
|
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))
|
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 ps0 = Common::ApproximateReciprocal(a);
|
||||||
const double ps1 = Common::ApproximateReciprocal(b);
|
const double ps1 = Common::ApproximateReciprocal(b);
|
||||||
|
|
||||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(float(ps0));
|
ppc_state.UpdateFPRFSingle(float(ps0));
|
||||||
|
|
||||||
if (inst.Rc)
|
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();
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const double ps1 = PowerPC::ppcState.ps[inst.FB].PS1AsDouble();
|
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)
|
if (ps0 == 0.0 || ps1 == 0.0)
|
||||||
{
|
{
|
||||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_ZX);
|
SetFPException(&ppc_state.fpscr, FPSCR_ZX);
|
||||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
ppc_state.fpscr.ClearFIFR();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps0 < 0.0 || ps1 < 0.0)
|
if (ps0 < 0.0 || ps1 < 0.0)
|
||||||
{
|
{
|
||||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSQRT);
|
SetFPException(&ppc_state.fpscr, FPSCR_VXSQRT);
|
||||||
PowerPC::ppcState.fpscr.ClearFIFR();
|
ppc_state.fpscr.ClearFIFR();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::isnan(ps0) || std::isinf(ps0) || std::isnan(ps1) || std::isinf(ps1))
|
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))
|
if (Common::IsSNAN(ps0) || Common::IsSNAN(ps1))
|
||||||
SetFPException(&PowerPC::ppcState.fpscr, FPSCR_VXSNAN);
|
SetFPException(&ppc_state.fpscr, FPSCR_VXSNAN);
|
||||||
|
|
||||||
const float dst_ps0 =
|
const float dst_ps0 = ForceSingle(ppc_state.fpscr, Common::ApproximateReciprocalSquareRoot(ps0));
|
||||||
ForceSingle(PowerPC::ppcState.fpscr, Common::ApproximateReciprocalSquareRoot(ps0));
|
const float dst_ps1 = ForceSingle(ppc_state.fpscr, Common::ApproximateReciprocalSquareRoot(ps1));
|
||||||
const float dst_ps1 =
|
|
||||||
ForceSingle(PowerPC::ppcState.fpscr, Common::ApproximateReciprocalSquareRoot(ps1));
|
|
||||||
|
|
||||||
PowerPC::ppcState.ps[inst.FD].SetBoth(dst_ps0, dst_ps1);
|
ppc_state.ps[inst.FD].SetBoth(dst_ps0, dst_ps1);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(dst_ps0);
|
ppc_state.UpdateFPRFSingle(dst_ps0);
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
const auto& a = ppc_state.ps[inst.FA];
|
||||||
|
const auto& b = ppc_state.ps[inst.FB];
|
||||||
|
|
||||||
const float ps0 =
|
const float ps0 = ForceSingle(ppc_state.fpscr,
|
||||||
ForceSingle(PowerPC::ppcState.fpscr,
|
NI_sub(&ppc_state.fpscr, a.PS0AsDouble(), b.PS0AsDouble()).value);
|
||||||
NI_sub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble()).value);
|
const float ps1 = ForceSingle(ppc_state.fpscr,
|
||||||
const float ps1 =
|
NI_sub(&ppc_state.fpscr, a.PS1AsDouble(), b.PS1AsDouble()).value);
|
||||||
ForceSingle(PowerPC::ppcState.fpscr,
|
|
||||||
NI_sub(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), b.PS1AsDouble()).value);
|
|
||||||
|
|
||||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
ppc_state.UpdateFPRFSingle(ps0);
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
const auto& a = ppc_state.ps[inst.FA];
|
||||||
|
const auto& b = ppc_state.ps[inst.FB];
|
||||||
|
|
||||||
const float ps0 =
|
const float ps0 = ForceSingle(ppc_state.fpscr,
|
||||||
ForceSingle(PowerPC::ppcState.fpscr,
|
NI_add(&ppc_state.fpscr, a.PS0AsDouble(), b.PS0AsDouble()).value);
|
||||||
NI_add(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS0AsDouble()).value);
|
const float ps1 = ForceSingle(ppc_state.fpscr,
|
||||||
const float ps1 =
|
NI_add(&ppc_state.fpscr, a.PS1AsDouble(), b.PS1AsDouble()).value);
|
||||||
ForceSingle(PowerPC::ppcState.fpscr,
|
|
||||||
NI_add(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), b.PS1AsDouble()).value);
|
|
||||||
|
|
||||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
ppc_state.UpdateFPRFSingle(ps0);
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
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_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];
|
|
||||||
|
|
||||||
const double c0 = Force25Bit(c.PS0AsDouble());
|
const double c0 = Force25Bit(c.PS0AsDouble());
|
||||||
const double c1 = Force25Bit(c.PS1AsDouble());
|
const double c1 = Force25Bit(c.PS1AsDouble());
|
||||||
|
|
||||||
const float ps0 =
|
const float ps0 =
|
||||||
ForceSingle(PowerPC::ppcState.fpscr,
|
ForceSingle(ppc_state.fpscr, NI_mul(&ppc_state.fpscr, a.PS0AsDouble(), c0).value);
|
||||||
NI_msub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
|
||||||
const float ps1 =
|
const float ps1 =
|
||||||
ForceSingle(PowerPC::ppcState.fpscr,
|
ForceSingle(ppc_state.fpscr, NI_mul(&ppc_state.fpscr, a.PS1AsDouble(), c1).value);
|
||||||
NI_msub(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
|
|
||||||
|
|
||||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
ppc_state.UpdateFPRFSingle(ps0);
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
const auto& a = ppc_state.ps[inst.FA];
|
||||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
const auto& b = ppc_state.ps[inst.FB];
|
||||||
|
const auto& c = ppc_state.ps[inst.FC];
|
||||||
|
|
||||||
const double c0 = Force25Bit(c.PS0AsDouble());
|
const double c0 = Force25Bit(c.PS0AsDouble());
|
||||||
const double c1 = Force25Bit(c.PS1AsDouble());
|
const double c1 = Force25Bit(c.PS1AsDouble());
|
||||||
|
|
||||||
const float ps0 =
|
const float ps0 = ForceSingle(
|
||||||
ForceSingle(PowerPC::ppcState.fpscr,
|
ppc_state.fpscr, NI_msub(&ppc_state.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
||||||
NI_madd(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
const float ps1 = ForceSingle(
|
||||||
const float ps1 =
|
ppc_state.fpscr, NI_msub(&ppc_state.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
|
||||||
ForceSingle(PowerPC::ppcState.fpscr,
|
|
||||||
NI_madd(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
|
|
||||||
|
|
||||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
ppc_state.UpdateFPRFSingle(ps0);
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
const auto& a = ppc_state.ps[inst.FA];
|
||||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
const auto& b = ppc_state.ps[inst.FB];
|
||||||
|
const auto& c = ppc_state.ps[inst.FC];
|
||||||
|
|
||||||
const double c0 = Force25Bit(c.PS0AsDouble());
|
const double c0 = Force25Bit(c.PS0AsDouble());
|
||||||
const double c1 = Force25Bit(c.PS1AsDouble());
|
const double c1 = Force25Bit(c.PS1AsDouble());
|
||||||
|
|
||||||
const float tmp0 =
|
const float ps0 = ForceSingle(
|
||||||
ForceSingle(PowerPC::ppcState.fpscr,
|
ppc_state.fpscr, NI_madd(&ppc_state.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
||||||
NI_msub(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
const float ps1 = ForceSingle(
|
||||||
const float tmp1 =
|
ppc_state.fpscr, NI_madd(&ppc_state.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
|
||||||
ForceSingle(PowerPC::ppcState.fpscr,
|
|
||||||
NI_msub(&PowerPC::ppcState.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 ps0 = std::isnan(tmp0) ? tmp0 : -tmp0;
|
||||||
const float ps1 = std::isnan(tmp1) ? tmp1 : -tmp1;
|
const float ps1 = std::isnan(tmp1) ? tmp1 : -tmp1;
|
||||||
|
|
||||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
ppc_state.UpdateFPRFSingle(ps0);
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
const auto& a = ppc_state.ps[inst.FA];
|
||||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
const auto& b = ppc_state.ps[inst.FB];
|
||||||
|
const auto& c = ppc_state.ps[inst.FC];
|
||||||
|
|
||||||
const double c0 = Force25Bit(c.PS0AsDouble());
|
const double c0 = Force25Bit(c.PS0AsDouble());
|
||||||
const double c1 = Force25Bit(c.PS1AsDouble());
|
const double c1 = Force25Bit(c.PS1AsDouble());
|
||||||
|
|
||||||
const float tmp0 =
|
const float tmp0 = ForceSingle(
|
||||||
ForceSingle(PowerPC::ppcState.fpscr,
|
ppc_state.fpscr, NI_madd(&ppc_state.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
||||||
NI_madd(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
const float tmp1 = ForceSingle(
|
||||||
const float tmp1 =
|
ppc_state.fpscr, NI_madd(&ppc_state.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
|
||||||
ForceSingle(PowerPC::ppcState.fpscr,
|
|
||||||
NI_madd(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
|
|
||||||
|
|
||||||
const float ps0 = std::isnan(tmp0) ? tmp0 : -tmp0;
|
const float ps0 = std::isnan(tmp0) ? tmp0 : -tmp0;
|
||||||
const float ps1 = std::isnan(tmp1) ? tmp1 : -tmp1;
|
const float ps1 = std::isnan(tmp1) ? tmp1 : -tmp1;
|
||||||
|
|
||||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
ppc_state.UpdateFPRFSingle(ps0);
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
const auto& a = ppc_state.ps[inst.FA];
|
||||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
const auto& b = ppc_state.ps[inst.FB];
|
||||||
|
const auto& c = ppc_state.ps[inst.FC];
|
||||||
|
|
||||||
const float ps0 =
|
const float ps0 = ForceSingle(ppc_state.fpscr,
|
||||||
ForceSingle(PowerPC::ppcState.fpscr,
|
NI_add(&ppc_state.fpscr, a.PS0AsDouble(), b.PS1AsDouble()).value);
|
||||||
NI_add(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS1AsDouble()).value);
|
const float ps1 = ForceSingle(ppc_state.fpscr, c.PS1AsDouble());
|
||||||
const float ps1 = ForceSingle(PowerPC::ppcState.fpscr, c.PS1AsDouble());
|
|
||||||
|
|
||||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
ppc_state.UpdateFPRFSingle(ps0);
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
const auto& a = ppc_state.ps[inst.FA];
|
||||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
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 ps0 = ForceSingle(ppc_state.fpscr, c.PS0AsDouble());
|
||||||
const float ps1 =
|
const float ps1 = ForceSingle(ppc_state.fpscr,
|
||||||
ForceSingle(PowerPC::ppcState.fpscr,
|
NI_add(&ppc_state.fpscr, a.PS0AsDouble(), b.PS1AsDouble()).value);
|
||||||
NI_add(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), b.PS1AsDouble()).value);
|
|
||||||
|
|
||||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(ps1);
|
ppc_state.UpdateFPRFSingle(ps1);
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
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_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];
|
|
||||||
|
|
||||||
const double c0 = Force25Bit(c.PS0AsDouble());
|
const double c0 = Force25Bit(c.PS0AsDouble());
|
||||||
const float ps0 =
|
const float ps0 =
|
||||||
ForceSingle(PowerPC::ppcState.fpscr,
|
ForceSingle(ppc_state.fpscr, NI_mul(&ppc_state.fpscr, a.PS0AsDouble(), c0).value);
|
||||||
NI_madd(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
|
||||||
const float ps1 =
|
const float ps1 =
|
||||||
ForceSingle(PowerPC::ppcState.fpscr,
|
ForceSingle(ppc_state.fpscr, NI_mul(&ppc_state.fpscr, a.PS1AsDouble(), c0).value);
|
||||||
NI_madd(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c0, b.PS1AsDouble()).value);
|
|
||||||
|
|
||||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
ppc_state.UpdateFPRFSingle(ps0);
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
const auto& a = ppc_state.ps[inst.FA];
|
||||||
const auto& c = PowerPC::ppcState.ps[inst.FC];
|
const auto& c = ppc_state.ps[inst.FC];
|
||||||
|
|
||||||
const double c1 = Force25Bit(c.PS1AsDouble());
|
const double c1 = Force25Bit(c.PS1AsDouble());
|
||||||
const float ps0 =
|
const float ps0 =
|
||||||
ForceSingle(PowerPC::ppcState.fpscr,
|
ForceSingle(ppc_state.fpscr, NI_mul(&ppc_state.fpscr, a.PS0AsDouble(), c1).value);
|
||||||
NI_madd(&PowerPC::ppcState.fpscr, a.PS0AsDouble(), c1, b.PS0AsDouble()).value);
|
|
||||||
const float ps1 =
|
const float ps1 =
|
||||||
ForceSingle(PowerPC::ppcState.fpscr,
|
ForceSingle(ppc_state.fpscr, NI_mul(&ppc_state.fpscr, a.PS1AsDouble(), c1).value);
|
||||||
NI_madd(&PowerPC::ppcState.fpscr, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
|
|
||||||
|
|
||||||
PowerPC::ppcState.ps[inst.FD].SetBoth(ps0, ps1);
|
ppc_state.ps[inst.FD].SetBoth(ps0, ps1);
|
||||||
PowerPC::ppcState.UpdateFPRFSingle(ps0);
|
ppc_state.UpdateFPRFSingle(ps0);
|
||||||
|
|
||||||
if (inst.Rc)
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
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];
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const auto& b = PowerPC::ppcState.ps[inst.FB];
|
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();
|
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;
|
u32 b = 0x80000000 >> inst.CRBD;
|
||||||
|
|
||||||
PowerPC::ppcState.fpscr.Hex &= ~b;
|
ppc_state.fpscr.Hex &= ~b;
|
||||||
FPSCRUpdated(&PowerPC::ppcState.fpscr);
|
FPSCRUpdated(&ppc_state.fpscr);
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
PowerPC::ppcState.UpdateCR1();
|
ppc_state.UpdateCR1();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This instruction can affect FX
|
// 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 bit = inst.CRBD;
|
||||||
const u32 b = 0x80000000 >> bit;
|
const u32 b = 0x80000000 >> bit;
|
||||||
|
|
||||||
if ((b & FPSCR_ANY_X) != 0)
|
if ((b & FPSCR_ANY_X) != 0)
|
||||||
SetFPException(&PowerPC::ppcState.fpscr, b);
|
SetFPException(&ppc_state.fpscr, b);
|
||||||
else
|
else
|
||||||
PowerPC::ppcState.fpscr |= b;
|
ppc_state.fpscr |= b;
|
||||||
|
|
||||||
FPSCRUpdated(&PowerPC::ppcState.fpscr);
|
FPSCRUpdated(&ppc_state.fpscr);
|
||||||
|
|
||||||
if (inst.Rc)
|
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 field = inst.CRFD;
|
||||||
const u32 pre_shifted_mask = 0xF0000000;
|
const u32 pre_shifted_mask = 0xF0000000;
|
||||||
const u32 mask = (pre_shifted_mask >> (4 * field));
|
const u32 mask = (pre_shifted_mask >> (4 * field));
|
||||||
const u32 imm = (inst.hex << 16) & pre_shifted_mask;
|
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)
|
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;
|
const u32 fm = inst.FM;
|
||||||
u32 m = 0;
|
u32 m = 0;
|
||||||
for (u32 i = 0; i < 8; i++)
|
for (u32 i = 0; i < 8; i++)
|
||||||
@ -85,32 +89,35 @@ void Interpreter::mtfsfx(UGeckoInstruction inst)
|
|||||||
m |= (0xFU << (i * 4));
|
m |= (0xFU << (i * 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
PowerPC::ppcState.fpscr = (PowerPC::ppcState.fpscr.Hex & ~m) |
|
ppc_state.fpscr =
|
||||||
(static_cast<u32>(PowerPC::ppcState.ps[inst.FB].PS0AsU64()) & m);
|
(ppc_state.fpscr.Hex & ~m) | (static_cast<u32>(ppc_state.ps[inst.FB].PS0AsU64()) & m);
|
||||||
FPSCRUpdated(&PowerPC::ppcState.fpscr);
|
FPSCRUpdated(&ppc_state.fpscr);
|
||||||
|
|
||||||
if (inst.Rc)
|
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);
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
PowerPC::ppcState.xer_ca = 0;
|
ppc_state.cr.SetField(inst.CRFD, ppc_state.GetXER().Hex >> 28);
|
||||||
PowerPC::ppcState.xer_so_ov = 0;
|
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;
|
const u32 crm = inst.CRM;
|
||||||
if (crm == 0xFF)
|
if (crm == 0xFF)
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.cr.Set(PowerPC::ppcState.gpr[inst.RS]);
|
ppc_state.cr.Set(ppc_state.gpr[inst.RS]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -122,103 +129,109 @@ void Interpreter::mtcrf(UGeckoInstruction inst)
|
|||||||
mask |= 0xFU << (i * 4);
|
mask |= 0xFU << (i * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
PowerPC::ppcState.cr.Set((PowerPC::ppcState.cr.Get() & ~mask) |
|
ppc_state.cr.Set((ppc_state.cr.Get() & ~mask) | (ppc_state.gpr[inst.RS] & mask));
|
||||||
(PowerPC::ppcState.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);
|
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
||||||
return;
|
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);
|
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
||||||
return;
|
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);
|
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 index = (PowerPC::ppcState.gpr[inst.RB] >> 28) & 0xF;
|
const u32 index = (ppc_state.gpr[inst.RB] >> 28) & 0xF;
|
||||||
PowerPC::ppcState.gpr[inst.RD] = PowerPC::ppcState.sr[index];
|
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);
|
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
||||||
return;
|
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
|
// FE0/FE1 may have been set
|
||||||
CheckFPExceptions(PowerPC::ppcState.fpscr);
|
CheckFPExceptions(ppc_state.fpscr);
|
||||||
|
|
||||||
PowerPC::CheckExceptions();
|
PowerPC::CheckExceptions();
|
||||||
m_end_block = true;
|
interpreter.m_end_block = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Segment registers. MMU control.
|
// 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);
|
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 index = inst.SR;
|
const u32 index = inst.SR;
|
||||||
const u32 value = PowerPC::ppcState.gpr[inst.RS];
|
const u32 value = ppc_state.gpr[inst.RS];
|
||||||
PowerPC::ppcState.SetSR(index, value);
|
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);
|
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 index = (PowerPC::ppcState.gpr[inst.RB] >> 28) & 0xF;
|
const u32 index = (ppc_state.gpr[inst.RB] >> 28) & 0xF;
|
||||||
const u32 value = PowerPC::ppcState.gpr[inst.RS];
|
const u32 value = ppc_state.gpr[inst.RS];
|
||||||
PowerPC::ppcState.SetSR(index, value);
|
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);
|
[[maybe_unused]] const u32 index = (inst.TBR >> 5) | ((inst.TBR & 0x1F) << 5);
|
||||||
DEBUG_ASSERT_MSG(POWERPC, (index == SPR_TL) || (index == SPR_TU), "Invalid mftb");
|
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);
|
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.
|
// 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)
|
index != SPR_TL && index != SPR_TU)
|
||||||
{
|
{
|
||||||
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
||||||
@ -228,9 +241,9 @@ void Interpreter::mfspr(UGeckoInstruction inst)
|
|||||||
switch (index)
|
switch (index)
|
||||||
{
|
{
|
||||||
case SPR_DEC:
|
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;
|
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
|
// 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).
|
// (and games that use display lists will hang if the bit doesn't eventually become zero).
|
||||||
if (Core::System::GetInstance().GetGPFifo().IsBNE())
|
if (Core::System::GetInstance().GetGPFifo().IsBNE())
|
||||||
PowerPC::ppcState.spr[index] |= 1;
|
ppc_state.spr[index] |= 1;
|
||||||
else
|
else
|
||||||
PowerPC::ppcState.spr[index] &= ~1;
|
ppc_state.spr[index] &= ~1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPR_XER:
|
case SPR_XER:
|
||||||
PowerPC::ppcState.spr[index] = PowerPC::ppcState.GetXER().Hex;
|
ppc_state.spr[index] = ppc_state.GetXER().Hex;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPR_UPMC1:
|
case SPR_UPMC1:
|
||||||
PowerPC::ppcState.spr[index] = PowerPC::ppcState.spr[SPR_PMC1];
|
ppc_state.spr[index] = ppc_state.spr[SPR_PMC1];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPR_UPMC2:
|
case SPR_UPMC2:
|
||||||
PowerPC::ppcState.spr[index] = PowerPC::ppcState.spr[SPR_PMC2];
|
ppc_state.spr[index] = ppc_state.spr[SPR_PMC2];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPR_UPMC3:
|
case SPR_UPMC3:
|
||||||
PowerPC::ppcState.spr[index] = PowerPC::ppcState.spr[SPR_PMC3];
|
ppc_state.spr[index] = ppc_state.spr[SPR_PMC3];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPR_UPMC4:
|
case SPR_UPMC4:
|
||||||
PowerPC::ppcState.spr[index] = PowerPC::ppcState.spr[SPR_PMC4];
|
ppc_state.spr[index] = ppc_state.spr[SPR_PMC4];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPR_IABR:
|
case SPR_IABR:
|
||||||
// A strange quirk: reading back this register on hardware will always have the TE (Translation
|
// 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
|
// enabled) bit set to 0 (despite the bit appearing to function normally when set). This does
|
||||||
// not apply to the DABR.
|
// 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;
|
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);
|
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
|
// 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);
|
GenerateProgramException(ProgramExceptionCause::PrivilegedInstruction);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u32 old_value = PowerPC::ppcState.spr[index];
|
const u32 old_value = ppc_state.spr[index];
|
||||||
PowerPC::ppcState.spr[index] = PowerPC::ppcState.gpr[inst.RD];
|
ppc_state.spr[index] = ppc_state.gpr[inst.RD];
|
||||||
|
|
||||||
// Our DMA emulation is highly inaccurate - instead of properly emulating the queue
|
// Our DMA emulation is highly inaccurate - instead of properly emulating the queue
|
||||||
// and so on, we simply make all DMA:s complete instantaneously.
|
// and so on, we simply make all DMA:s complete instantaneously.
|
||||||
@ -309,41 +323,39 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SPR_TL_W:
|
case SPR_TL_W:
|
||||||
TL(PowerPC::ppcState) = PowerPC::ppcState.gpr[inst.RD];
|
TL(ppc_state) = ppc_state.gpr[inst.RD];
|
||||||
SystemTimers::TimeBaseSet();
|
SystemTimers::TimeBaseSet();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPR_TU_W:
|
case SPR_TU_W:
|
||||||
TU(PowerPC::ppcState) = PowerPC::ppcState.gpr[inst.RD];
|
TU(ppc_state) = ppc_state.gpr[inst.RD];
|
||||||
SystemTimers::TimeBaseSet();
|
SystemTimers::TimeBaseSet();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPR_PVR:
|
case SPR_PVR:
|
||||||
// PVR is a read-only register so maintain its value.
|
// PVR is a read-only register so maintain its value.
|
||||||
PowerPC::ppcState.spr[index] = old_value;
|
ppc_state.spr[index] = old_value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPR_HID0: // HID0
|
case SPR_HID0: // HID0
|
||||||
{
|
{
|
||||||
UReg_HID0 old_hid0;
|
UReg_HID0 old_hid0;
|
||||||
old_hid0.Hex = old_value;
|
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) = {}",
|
INFO_LOG_FMT(POWERPC, "Instruction Cache Enable (HID0.ICE) = {}", HID0(ppc_state).ICE);
|
||||||
HID0(PowerPC::ppcState).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) = {}",
|
INFO_LOG_FMT(POWERPC, "Instruction Cache Lock (HID0.ILOCK) = {}", HID0(ppc_state).ILOCK);
|
||||||
HID0(PowerPC::ppcState).ILOCK);
|
|
||||||
}
|
}
|
||||||
if (HID0(PowerPC::ppcState).ICFI)
|
if (HID0(ppc_state).ICFI)
|
||||||
{
|
{
|
||||||
HID0(PowerPC::ppcState).ICFI = 0;
|
HID0(ppc_state).ICFI = 0;
|
||||||
INFO_LOG_FMT(POWERPC, "Flush Instruction Cache! ICE={}", HID0(PowerPC::ppcState).ICE);
|
INFO_LOG_FMT(POWERPC, "Flush Instruction Cache! ICE={}", HID0(ppc_state).ICE);
|
||||||
// this is rather slow
|
// this is rather slow
|
||||||
// most games do it only once during initialization
|
// most games do it only once during initialization
|
||||||
PowerPC::ppcState.iCache.Reset();
|
ppc_state.iCache.Reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -352,7 +364,7 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
|||||||
// Despite being documented as a read-only register, it actually isn't. Bits
|
// 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
|
// 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.
|
// affected, as those bits are reserved and ignore writes to them.
|
||||||
PowerPC::ppcState.spr[index] &= 0xF8000000;
|
ppc_state.spr[index] &= 0xF8000000;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPR_HID2:
|
case SPR_HID2:
|
||||||
@ -360,23 +372,22 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
|||||||
// TODO: emulate locked cache and DMA bits.
|
// TODO: emulate locked cache and DMA bits.
|
||||||
// Only the lower half of the register (upper half from a little endian perspective)
|
// Only the lower half of the register (upper half from a little endian perspective)
|
||||||
// is modifiable, except for the DMAQL field.
|
// is modifiable, except for the DMAQL field.
|
||||||
PowerPC::ppcState.spr[index] =
|
ppc_state.spr[index] = (ppc_state.spr[index] & 0xF0FF0000) | (old_value & 0x0F000000);
|
||||||
(PowerPC::ppcState.spr[index] & 0xF0FF0000) | (old_value & 0x0F000000);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPR_HID4:
|
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::IBATUpdated();
|
||||||
PowerPC::DBATUpdated();
|
PowerPC::DBATUpdated();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPR_WPAR:
|
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}",
|
"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();
|
Core::System::GetInstance().GetGPFifo().ResetGatherPipe();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -394,20 +405,20 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
|||||||
case SPR_DMAL:
|
case SPR_DMAL:
|
||||||
// Locked cache<->Memory DMA
|
// Locked cache<->Memory DMA
|
||||||
// Total fake, we ignore that DMAs take time.
|
// 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 mem_address = DMAU(ppc_state).MEM_ADDR << 5;
|
||||||
const u32 cache_address = DMAL(PowerPC::ppcState).LC_ADDR << 5;
|
const u32 cache_address = DMAL(ppc_state).LC_ADDR << 5;
|
||||||
u32 length = ((DMAU(PowerPC::ppcState).DMA_LEN_U << 2) | DMAL(PowerPC::ppcState).DMA_LEN_L);
|
u32 length = ((DMAU(ppc_state).DMA_LEN_U << 2) | DMAL(ppc_state).DMA_LEN_L);
|
||||||
|
|
||||||
if (length == 0)
|
if (length == 0)
|
||||||
length = 128;
|
length = 128;
|
||||||
if (DMAL(PowerPC::ppcState).DMA_LD)
|
if (DMAL(ppc_state).DMA_LD)
|
||||||
PowerPC::DMA_MemoryToLC(cache_address, mem_address, length);
|
PowerPC::DMA_MemoryToLC(cache_address, mem_address, length);
|
||||||
else
|
else
|
||||||
PowerPC::DMA_LCToMemory(mem_address, cache_address, length);
|
PowerPC::DMA_LCToMemory(mem_address, cache_address, length);
|
||||||
}
|
}
|
||||||
DMAL(PowerPC::ppcState).DMA_T = 0;
|
DMAL(ppc_state).DMA_T = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPR_L2CR:
|
case SPR_L2CR:
|
||||||
@ -415,10 +426,10 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
|||||||
|
|
||||||
case SPR_DEC:
|
case SPR_DEC:
|
||||||
// Top bit from 0 to 1
|
// 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");
|
INFO_LOG_FMT(POWERPC, "Software triggered Decrementer exception");
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER;
|
ppc_state.Exceptions |= EXCEPTION_DECREMENTER;
|
||||||
}
|
}
|
||||||
SystemTimers::DecrementerSet();
|
SystemTimers::DecrementerSet();
|
||||||
break;
|
break;
|
||||||
@ -429,7 +440,7 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SPR_XER:
|
case SPR_XER:
|
||||||
PowerPC::ppcState.SetXER(UReg_XER{PowerPC::ppcState.spr[index]});
|
ppc_state.SetXER(UReg_XER{ppc_state.spr[index]});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPR_DBAT0L:
|
case SPR_DBAT0L:
|
||||||
@ -448,10 +459,9 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
|||||||
case SPR_DBAT6U:
|
case SPR_DBAT6U:
|
||||||
case SPR_DBAT7L:
|
case SPR_DBAT7L:
|
||||||
case SPR_DBAT7U:
|
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,
|
INFO_LOG_FMT(POWERPC, "DBAT updated {} {:x} {:x}", index, old_value, ppc_state.spr[index]);
|
||||||
PowerPC::ppcState.spr[index]);
|
|
||||||
PowerPC::DBATUpdated();
|
PowerPC::DBATUpdated();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -472,10 +482,9 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
|||||||
case SPR_IBAT6U:
|
case SPR_IBAT6U:
|
||||||
case SPR_IBAT7L:
|
case SPR_IBAT7L:
|
||||||
case SPR_IBAT7U:
|
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,
|
INFO_LOG_FMT(POWERPC, "IBAT updated {} {:x} {:x}", index, old_value, ppc_state.spr[index]);
|
||||||
PowerPC::ppcState.spr[index]);
|
|
||||||
PowerPC::IBATUpdated();
|
PowerPC::IBATUpdated();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -491,8 +500,8 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
|||||||
// TODO: Support thermal interrupts when enabled.
|
// TODO: Support thermal interrupts when enabled.
|
||||||
constexpr u32 SIMULATED_TEMP = 42; // °C
|
constexpr u32 SIMULATED_TEMP = 42; // °C
|
||||||
|
|
||||||
auto UpdateThermalReg = [](UReg_THRM12* reg) {
|
auto UpdateThermalReg = [&ppc_state](UReg_THRM12* reg) {
|
||||||
if (!THRM3(PowerPC::ppcState).E || !reg->V)
|
if (!THRM3(ppc_state).E || !reg->V)
|
||||||
{
|
{
|
||||||
reg->TIV = 0;
|
reg->TIV = 0;
|
||||||
}
|
}
|
||||||
@ -506,106 +515,117 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
UpdateThermalReg(&THRM1(PowerPC::ppcState));
|
UpdateThermalReg(&THRM1(ppc_state));
|
||||||
UpdateThermalReg(&THRM2(PowerPC::ppcState));
|
UpdateThermalReg(&THRM2(ppc_state));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::crand(UGeckoInstruction inst)
|
void Interpreter::crand(Interpreter& interpreter, UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
const u32 a = PowerPC::ppcState.cr.GetBit(inst.CRBA);
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const u32 b = PowerPC::ppcState.cr.GetBit(inst.CRBB);
|
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);
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const u32 b = PowerPC::ppcState.cr.GetBit(inst.CRBB);
|
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);
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const u32 b = PowerPC::ppcState.cr.GetBit(inst.CRBB);
|
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);
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const u32 b = PowerPC::ppcState.cr.GetBit(inst.CRBB);
|
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);
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const u32 b = PowerPC::ppcState.cr.GetBit(inst.CRBB);
|
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);
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const u32 b = PowerPC::ppcState.cr.GetBit(inst.CRBB);
|
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);
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const u32 b = PowerPC::ppcState.cr.GetBit(inst.CRBB);
|
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);
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
const u32 b = PowerPC::ppcState.cr.GetBit(inst.CRBB);
|
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);
|
auto& ppc_state = interpreter.m_ppc_state;
|
||||||
PowerPC::ppcState.cr.SetField(inst.CRFD, cr_f);
|
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
|
// shouldn't do anything
|
||||||
}
|
}
|
||||||
|
|
||||||
// the following commands read from FPSCR
|
// 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 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
|
// If any exception bits were read, clear them
|
||||||
PowerPC::ppcState.fpscr.Hex &= ~((0xF << shift) & (FPSCR_FX | FPSCR_ANY_X));
|
ppc_state.fpscr.Hex &= ~((0xF << shift) & (FPSCR_FX | FPSCR_ANY_X));
|
||||||
FPSCRUpdated(&PowerPC::ppcState.fpscr);
|
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)
|
if (inst.Rc)
|
||||||
PowerPC::ppcState.UpdateCR1();
|
ppc_state.UpdateCR1();
|
||||||
}
|
}
|
||||||
|
@ -468,29 +468,29 @@ Interpreter::Instruction Interpreter::GetInterpreterOp(UGeckoInstruction inst)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::RunInterpreterOp(UGeckoInstruction inst)
|
void Interpreter::RunInterpreterOp(Interpreter& interpreter, UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
// Will handle subtables using RunTable4 etc.
|
// 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);
|
Interpreter::Instruction instr = Interpreter::GetInterpreterOp(inst);
|
||||||
ABI_PushRegistersAndAdjustStack({}, 0);
|
ABI_PushRegistersAndAdjustStack({}, 0);
|
||||||
ABI_CallFunctionC(instr, inst.hex);
|
ABI_CallFunctionPC(instr, &Core::System::GetInstance().GetInterpreter(), inst.hex);
|
||||||
ABI_PopRegistersAndAdjustStack({}, 0);
|
ABI_PopRegistersAndAdjustStack({}, 0);
|
||||||
|
|
||||||
// If the instruction wrote to any registers which were marked as discarded,
|
// 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);
|
Interpreter::Instruction instr = Interpreter::GetInterpreterOp(inst);
|
||||||
MOVP2R(ARM64Reg::X8, instr);
|
MOVP2R(ARM64Reg::X8, instr);
|
||||||
MOVI2R(ARM64Reg::W0, inst.hex);
|
MOVP2R(ARM64Reg::W0, &Core::System::GetInstance().GetInterpreter());
|
||||||
|
MOVI2R(ARM64Reg::W1, inst.hex);
|
||||||
BLR(ARM64Reg::X8);
|
BLR(ARM64Reg::X8);
|
||||||
|
|
||||||
// If the instruction wrote to any registers which were marked as discarded,
|
// 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 CPUCoreBase* s_cpu_core_base = nullptr;
|
||||||
static bool s_cpu_core_base_is_injected = false;
|
static bool s_cpu_core_base_is_injected = false;
|
||||||
Interpreter* const s_interpreter = Interpreter::getInstance();
|
|
||||||
static CoreMode s_mode = CoreMode::Interpreter;
|
static CoreMode s_mode = CoreMode::Interpreter;
|
||||||
|
|
||||||
BreakPoints breakpoints;
|
BreakPoints breakpoints;
|
||||||
@ -220,12 +219,13 @@ static void InitializeCPUCore(CPUCore cpu_core)
|
|||||||
{
|
{
|
||||||
// We initialize the interpreter because
|
// We initialize the interpreter because
|
||||||
// it is used on boot and code window independently.
|
// it is used on boot and code window independently.
|
||||||
s_interpreter->Init();
|
auto& interpreter = Core::System::GetInstance().GetInterpreter();
|
||||||
|
interpreter.Init();
|
||||||
|
|
||||||
switch (cpu_core)
|
switch (cpu_core)
|
||||||
{
|
{
|
||||||
case CPUCore::Interpreter:
|
case CPUCore::Interpreter:
|
||||||
s_cpu_core_base = s_interpreter;
|
s_cpu_core_base = &interpreter;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -239,7 +239,7 @@ static void InitializeCPUCore(CPUCore cpu_core)
|
|||||||
break;
|
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()
|
const std::vector<CPUCore>& AvailableCPUCores()
|
||||||
@ -316,7 +316,8 @@ void Shutdown()
|
|||||||
{
|
{
|
||||||
InjectExternalCPUCore(nullptr);
|
InjectExternalCPUCore(nullptr);
|
||||||
JitInterface::Shutdown();
|
JitInterface::Shutdown();
|
||||||
s_interpreter->Shutdown();
|
auto& interpreter = Core::System::GetInstance().GetInterpreter();
|
||||||
|
interpreter.Shutdown();
|
||||||
s_cpu_core_base = nullptr;
|
s_cpu_core_base = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,17 +328,19 @@ CoreMode GetMode()
|
|||||||
|
|
||||||
static void ApplyMode()
|
static void ApplyMode()
|
||||||
{
|
{
|
||||||
|
auto& interpreter = Core::System::GetInstance().GetInterpreter();
|
||||||
|
|
||||||
switch (s_mode)
|
switch (s_mode)
|
||||||
{
|
{
|
||||||
case CoreMode::Interpreter: // Switching from JIT to interpreter
|
case CoreMode::Interpreter: // Switching from JIT to interpreter
|
||||||
s_cpu_core_base = s_interpreter;
|
s_cpu_core_base = &interpreter;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CoreMode::JIT: // Switching from interpreter to JIT.
|
case CoreMode::JIT: // Switching from interpreter to JIT.
|
||||||
// Don't really need to do much. It'll work, the cache will refill itself.
|
// Don't really need to do much. It'll work, the cache will refill itself.
|
||||||
s_cpu_core_base = JitInterface::GetCore();
|
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
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "Core/HW/SI/SI.h"
|
#include "Core/HW/SI/SI.h"
|
||||||
#include "Core/HW/Sram.h"
|
#include "Core/HW/Sram.h"
|
||||||
#include "Core/HW/VideoInterface.h"
|
#include "Core/HW/VideoInterface.h"
|
||||||
|
#include "Core/PowerPC/Interpreter/Interpreter.h"
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
#include "IOS/USB/Emulated/Skylander.h"
|
#include "IOS/USB/Emulated/Skylander.h"
|
||||||
#include "VideoCommon/CommandProcessor.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_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_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_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;
|
Sram m_sram;
|
||||||
VertexShaderManager m_vertex_shader_manager;
|
VertexShaderManager m_vertex_shader_manager;
|
||||||
VideoInterface::VideoInterfaceManager m_video_interface;
|
VideoInterface::VideoInterfaceManager m_video_interface;
|
||||||
|
Interpreter m_interpreter;
|
||||||
};
|
};
|
||||||
|
|
||||||
System::System() : m_impl{std::make_unique<Impl>(*this)}
|
System::System() : m_impl{std::make_unique<Impl>(*this)}
|
||||||
@ -175,6 +177,11 @@ HSP::HSPManager& System::GetHSP() const
|
|||||||
return m_impl->m_hsp;
|
return m_impl->m_hsp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Interpreter& System::GetInterpreter() const
|
||||||
|
{
|
||||||
|
return m_impl->m_interpreter;
|
||||||
|
}
|
||||||
|
|
||||||
IOS::HLE::USB::SkylanderPortal& System::GetSkylanderPortal() const
|
IOS::HLE::USB::SkylanderPortal& System::GetSkylanderPortal() const
|
||||||
{
|
{
|
||||||
return m_impl->m_skylander_portal;
|
return m_impl->m_skylander_portal;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class GeometryShaderManager;
|
class GeometryShaderManager;
|
||||||
|
class Interpreter;
|
||||||
class PixelShaderManager;
|
class PixelShaderManager;
|
||||||
class SoundStream;
|
class SoundStream;
|
||||||
struct Sram;
|
struct Sram;
|
||||||
@ -131,6 +132,7 @@ public:
|
|||||||
GeometryShaderManager& GetGeometryShaderManager() const;
|
GeometryShaderManager& GetGeometryShaderManager() const;
|
||||||
GPFifo::GPFifoManager& GetGPFifo() const;
|
GPFifo::GPFifoManager& GetGPFifo() const;
|
||||||
HSP::HSPManager& GetHSP() const;
|
HSP::HSPManager& GetHSP() const;
|
||||||
|
Interpreter& GetInterpreter() const;
|
||||||
IOS::HLE::USB::SkylanderPortal& GetSkylanderPortal() const;
|
IOS::HLE::USB::SkylanderPortal& GetSkylanderPortal() const;
|
||||||
Memory::MemoryManager& GetMemory() const;
|
Memory::MemoryManager& GetMemory() const;
|
||||||
MemoryInterface::MemoryInterfaceManager& GetMemoryInterface() const;
|
MemoryInterface::MemoryInterfaceManager& GetMemoryInterface() const;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user