This rewrite is working (tested with Super Mario 64)
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
#include <backend/core/JIT.hpp>
|
#include <backend/core/JIT.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
struct Core {
|
struct Core {
|
||||||
@@ -28,20 +29,6 @@ struct Core {
|
|||||||
return *GetInstance().mem;
|
return *GetInstance().mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Interpreter& GetInterpreter() {
|
|
||||||
if(GetInstance().cpuType == Interpreted)
|
|
||||||
return *dynamic_cast<Interpreter*>(GetInstance().cpu.get());
|
|
||||||
|
|
||||||
panic("Tried to get interpreter when other cpu type is used.");
|
|
||||||
}
|
|
||||||
|
|
||||||
static JIT& GetDynamicRecompiler() {
|
|
||||||
if(GetInstance().cpuType == DynamicRecompiler)
|
|
||||||
return *dynamic_cast<JIT*>(GetInstance().cpu.get());
|
|
||||||
|
|
||||||
panic("Tried to get interpreter when other cpu type is used.");
|
|
||||||
}
|
|
||||||
|
|
||||||
int StepCPU();
|
int StepCPU();
|
||||||
void StepRSP(int cpuCycles);
|
void StepRSP(int cpuCycles);
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <common.hpp>
|
|
||||||
|
|
||||||
namespace n64 {
|
|
||||||
|
|
||||||
} // namespace n64
|
|
||||||
@@ -109,163 +109,163 @@ private:
|
|||||||
void CheckCompareInterrupt();
|
void CheckCompareInterrupt();
|
||||||
u32 FetchInstruction();
|
u32 FetchInstruction();
|
||||||
|
|
||||||
void Emit(u32);
|
void Emit(const Instruction);
|
||||||
void special(u32);
|
void special(const Instruction);
|
||||||
void regimm(u32);
|
void regimm(const Instruction);
|
||||||
void add(u32);
|
void add(const Instruction);
|
||||||
void addu(u32);
|
void addu(const Instruction);
|
||||||
void addi(u32);
|
void addi(const Instruction);
|
||||||
void addiu(u32);
|
void addiu(const Instruction);
|
||||||
void andi(u32);
|
void andi(const Instruction);
|
||||||
void and_(u32);
|
void and_(const Instruction);
|
||||||
void branch_constant(bool cond, s64 offset);
|
void branch_constant(bool cond, s64 offset);
|
||||||
void branch_likely_constant(bool cond, s64 offset);
|
void branch_likely_constant(bool cond, s64 offset);
|
||||||
void branch_abs_constant(bool cond, s64 address);
|
void branch_abs_constant(bool cond, s64 address);
|
||||||
void bltz(u32);
|
void bltz(const Instruction);
|
||||||
void bgez(u32);
|
void bgez(const Instruction);
|
||||||
void bltzl(u32);
|
void bltzl(const Instruction);
|
||||||
void bgezl(u32);
|
void bgezl(const Instruction);
|
||||||
void bltzal(u32);
|
void bltzal(const Instruction);
|
||||||
void bgezal(u32);
|
void bgezal(const Instruction);
|
||||||
void bltzall(u32);
|
void bltzall(const Instruction);
|
||||||
void bgezall(u32);
|
void bgezall(const Instruction);
|
||||||
void beq(u32);
|
void beq(const Instruction);
|
||||||
void beql(u32);
|
void beql(const Instruction);
|
||||||
void bne(u32);
|
void bne(const Instruction);
|
||||||
void bnel(u32);
|
void bnel(const Instruction);
|
||||||
void blez(u32);
|
void blez(const Instruction);
|
||||||
void blezl(u32);
|
void blezl(const Instruction);
|
||||||
void bgtz(u32);
|
void bgtz(const Instruction);
|
||||||
void bgtzl(u32);
|
void bgtzl(const Instruction);
|
||||||
void bfc1(u32 instr);
|
void bfc1(const Instruction);
|
||||||
void blfc1(u32 instr);
|
void blfc1(const Instruction);
|
||||||
void bfc0(u32 instr);
|
void bfc0(const Instruction);
|
||||||
void blfc0(u32 instr);
|
void blfc0(const Instruction);
|
||||||
void dadd(u32);
|
void dadd(const Instruction);
|
||||||
void daddu(u32);
|
void daddu(const Instruction);
|
||||||
void daddi(u32);
|
void daddi(const Instruction);
|
||||||
void daddiu(u32);
|
void daddiu(const Instruction);
|
||||||
void ddiv(u32);
|
void ddiv(const Instruction);
|
||||||
void ddivu(u32);
|
void ddivu(const Instruction);
|
||||||
void div(u32);
|
void div(const Instruction);
|
||||||
void divu(u32);
|
void divu(const Instruction);
|
||||||
void dmult(u32);
|
void dmult(const Instruction);
|
||||||
void dmultu(u32);
|
void dmultu(const Instruction);
|
||||||
void dsll(u32);
|
void dsll(const Instruction);
|
||||||
void dsllv(u32);
|
void dsllv(const Instruction);
|
||||||
void dsll32(u32);
|
void dsll32(const Instruction);
|
||||||
void dsra(u32);
|
void dsra(const Instruction);
|
||||||
void dsrav(u32);
|
void dsrav(const Instruction);
|
||||||
void dsra32(u32);
|
void dsra32(const Instruction);
|
||||||
void dsrl(u32);
|
void dsrl(const Instruction);
|
||||||
void dsrlv(u32);
|
void dsrlv(const Instruction);
|
||||||
void dsrl32(u32);
|
void dsrl32(const Instruction);
|
||||||
void dsub(u32);
|
void dsub(const Instruction);
|
||||||
void dsubu(u32);
|
void dsubu(const Instruction);
|
||||||
void j(u32);
|
void j(const Instruction);
|
||||||
void jr(u32);
|
void jr(const Instruction);
|
||||||
void jal(u32);
|
void jal(const Instruction);
|
||||||
void jalr(u32);
|
void jalr(const Instruction);
|
||||||
void lui(u32);
|
void lui(const Instruction);
|
||||||
void lbu(u32);
|
void lbu(const Instruction);
|
||||||
void lb(u32);
|
void lb(const Instruction);
|
||||||
void ld(u32);
|
void ld(const Instruction);
|
||||||
void ldc1(u32);
|
void ldc1(const Instruction);
|
||||||
void ldl(u32);
|
void ldl(const Instruction);
|
||||||
void ldr(u32);
|
void ldr(const Instruction);
|
||||||
void lh(u32);
|
void lh(const Instruction);
|
||||||
void lhu(u32);
|
void lhu(const Instruction);
|
||||||
void ll(u32);
|
void ll(const Instruction);
|
||||||
void lld(u32);
|
void lld(const Instruction);
|
||||||
void lw(u32);
|
void lw(const Instruction);
|
||||||
void lwc1(u32);
|
void lwc1(const Instruction);
|
||||||
void lwl(u32);
|
void lwl(const Instruction);
|
||||||
void lwu(u32);
|
void lwu(const Instruction);
|
||||||
void lwr(u32);
|
void lwr(const Instruction);
|
||||||
void mfhi(u32);
|
void mfhi(const Instruction);
|
||||||
void mflo(u32);
|
void mflo(const Instruction);
|
||||||
void mult(u32);
|
void mult(const Instruction);
|
||||||
void multu(u32);
|
void multu(const Instruction);
|
||||||
void mthi(u32);
|
void mthi(const Instruction);
|
||||||
void mtlo(u32);
|
void mtlo(const Instruction);
|
||||||
void nor(u32);
|
void nor(const Instruction);
|
||||||
void sb(u32) {
|
void sb(const Instruction) {
|
||||||
Util::Error::GetInstance().Throw(
|
Util::Error::GetInstance().Throw(
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
||||||
blockPC, {}, "[JIT]: Unhandled 'sb'!");
|
blockPC, {}, "[JIT]: Unhandled 'sb'!");
|
||||||
}
|
}
|
||||||
void sc(u32) {
|
void sc(const Instruction) {
|
||||||
Util::Error::GetInstance().Throw(
|
Util::Error::GetInstance().Throw(
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
||||||
blockPC, {}, "[JIT]: Unhandled 'sc'!");
|
blockPC, {}, "[JIT]: Unhandled 'sc'!");
|
||||||
}
|
}
|
||||||
void scd(u32) {
|
void scd(const Instruction) {
|
||||||
Util::Error::GetInstance().Throw(
|
Util::Error::GetInstance().Throw(
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
||||||
blockPC, {}, "[JIT]: Unhandled 'scd'!");
|
blockPC, {}, "[JIT]: Unhandled 'scd'!");
|
||||||
}
|
}
|
||||||
void sd(u32) {
|
void sd(const Instruction) {
|
||||||
Util::Error::GetInstance().Throw(
|
Util::Error::GetInstance().Throw(
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
||||||
blockPC, {}, "[JIT]: Unhandled 'sd'!");
|
blockPC, {}, "[JIT]: Unhandled 'sd'!");
|
||||||
}
|
}
|
||||||
void sdc1(u32) {
|
void sdc1(const Instruction) {
|
||||||
Util::Error::GetInstance().Throw(
|
Util::Error::GetInstance().Throw(
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
||||||
blockPC, {}, "[JIT]: Unhandled 'sdc1'!");
|
blockPC, {}, "[JIT]: Unhandled 'sdc1'!");
|
||||||
}
|
}
|
||||||
void sdl(u32) {
|
void sdl(const Instruction) {
|
||||||
Util::Error::GetInstance().Throw(
|
Util::Error::GetInstance().Throw(
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
||||||
blockPC, {}, "[JIT]: Unhandled 'sdl'!");
|
blockPC, {}, "[JIT]: Unhandled 'sdl'!");
|
||||||
}
|
}
|
||||||
void sdr(u32) {
|
void sdr(const Instruction) {
|
||||||
Util::Error::GetInstance().Throw(
|
Util::Error::GetInstance().Throw(
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
||||||
blockPC, {}, "[JIT]: Unhandled 'sdr'!");
|
blockPC, {}, "[JIT]: Unhandled 'sdr'!");
|
||||||
}
|
}
|
||||||
void sh(u32) {
|
void sh(const Instruction) {
|
||||||
Util::Error::GetInstance().Throw(
|
Util::Error::GetInstance().Throw(
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
||||||
blockPC, {}, "[JIT]: Unhandled 'sh'!");
|
blockPC, {}, "[JIT]: Unhandled 'sh'!");
|
||||||
}
|
}
|
||||||
void sw(u32);
|
void sw(const Instruction);
|
||||||
void swl(u32) {
|
void swl(const Instruction) {
|
||||||
Util::Error::GetInstance().Throw(
|
Util::Error::GetInstance().Throw(
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
||||||
blockPC, {}, "[JIT]: Unhandled 'swl'!");
|
blockPC, {}, "[JIT]: Unhandled 'swl'!");
|
||||||
}
|
}
|
||||||
void swr(u32) {
|
void swr(const Instruction) {
|
||||||
Util::Error::GetInstance().Throw(
|
Util::Error::GetInstance().Throw(
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
||||||
blockPC, {}, "[JIT]: Unhandled 'swr'!");
|
blockPC, {}, "[JIT]: Unhandled 'swr'!");
|
||||||
}
|
}
|
||||||
void slti(u32);
|
void slti(const Instruction);
|
||||||
void sltiu(u32);
|
void sltiu(const Instruction);
|
||||||
void slt(u32);
|
void slt(const Instruction);
|
||||||
void sltu(u32);
|
void sltu(const Instruction);
|
||||||
void sll(u32);
|
void sll(const Instruction);
|
||||||
void sllv(u32);
|
void sllv(const Instruction);
|
||||||
void sub(u32);
|
void sub(const Instruction);
|
||||||
void subu(u32);
|
void subu(const Instruction);
|
||||||
void swc1(u32) {
|
void swc1(const Instruction) {
|
||||||
Util::Error::GetInstance().Throw(
|
Util::Error::GetInstance().Throw(
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::JIT_BRANCH_INSIDE_DELAY_SLOT},
|
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::JIT_BRANCH_INSIDE_DELAY_SLOT},
|
||||||
blockPC, {}, "[JIT]: Unhandled case of branch from delay slot!");
|
blockPC, {}, "[JIT]: Unhandled case of branch from delay slot!");
|
||||||
}
|
}
|
||||||
void sra(u32);
|
void sra(const Instruction);
|
||||||
void srav(u32);
|
void srav(const Instruction);
|
||||||
void srl(u32);
|
void srl(const Instruction);
|
||||||
void srlv(u32);
|
void srlv(const Instruction);
|
||||||
void trap(bool) {
|
void trap(bool) {
|
||||||
Util::Error::GetInstance().Throw(
|
Util::Error::GetInstance().Throw(
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::JIT_BRANCH_INSIDE_DELAY_SLOT},
|
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::JIT_BRANCH_INSIDE_DELAY_SLOT},
|
||||||
blockPC, {}, "[JIT]: Unhandled case of branch from delay slot!");
|
blockPC, {}, "[JIT]: Unhandled case of branch from delay slot!");
|
||||||
}
|
}
|
||||||
void or_(u32);
|
void or_(const Instruction);
|
||||||
void ori(u32);
|
void ori(const Instruction);
|
||||||
void xor_(u32);
|
void xor_(const Instruction);
|
||||||
void xori(u32);
|
void xori(const Instruction);
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -3,24 +3,24 @@
|
|||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
void Cop0::mtc0(const u32 instr) {
|
void Cop0::mtc0(const Instruction instr) {
|
||||||
Registers& regs = Core::GetRegs();
|
Registers& regs = Core::GetRegs();
|
||||||
SetReg32(RD(instr), regs.Read<u32>(RT(instr)));
|
SetReg32(instr.rd(), regs.Read<u32>(instr.rt()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop0::dmtc0(const u32 instr) {
|
void Cop0::dmtc0(const Instruction instr) {
|
||||||
Registers& regs = Core::GetRegs();
|
Registers& regs = Core::GetRegs();
|
||||||
SetReg64(RD(instr), regs.Read<u64>(RT(instr)));
|
SetReg64(instr.rd(), regs.Read<u64>(instr.rt()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop0::mfc0(const u32 instr) {
|
void Cop0::mfc0(const Instruction instr) {
|
||||||
Registers& regs = Core::GetRegs();
|
Registers& regs = Core::GetRegs();
|
||||||
regs.Write(RT(instr), s32(GetReg32(RD(instr))));
|
regs.Write(instr.rt(), s32(GetReg32(instr.rd())));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop0::dmfc0(const u32 instr) const {
|
void Cop0::dmfc0(const Instruction instr) const {
|
||||||
Registers& regs = Core::GetRegs();
|
Registers& regs = Core::GetRegs();
|
||||||
regs.Write(RT(instr), s64(GetReg64(RD(instr))));
|
regs.Write(instr.rt(), s64(GetReg64(instr.rd())));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop0::eret() {
|
void Cop0::eret() {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,11 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
#include <CpuDefinitions.hpp>
|
|
||||||
#include <log.hpp>
|
#include <log.hpp>
|
||||||
#include <Instruction.hpp>
|
#include <Instruction.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
void Interpreter::special(const Instruction instr) {
|
void Interpreter::special(const Instruction instr) {
|
||||||
// 00rr_rccc
|
// 00rr_rccc
|
||||||
switch (instr.instr.opcode.special) {
|
switch (instr.special()) {
|
||||||
case Instruction::SLL:
|
case Instruction::SLL:
|
||||||
if (instr.instr.raw != 0) {
|
if (instr.instr.raw != 0) {
|
||||||
sll(instr);
|
sll(instr);
|
||||||
@@ -172,7 +171,7 @@ void Interpreter::special(const Instruction instr) {
|
|||||||
|
|
||||||
void Interpreter::regimm(const Instruction instr) {
|
void Interpreter::regimm(const Instruction instr) {
|
||||||
// 000r_rccc
|
// 000r_rccc
|
||||||
switch (instr.instr.opcode.regimm) {
|
switch (instr.regimm()) {
|
||||||
case Instruction::BLTZ:
|
case Instruction::BLTZ:
|
||||||
b(instr, regs.Read<s64>(instr.rs()) < 0);
|
b(instr, regs.Read<s64>(instr.rs()) < 0);
|
||||||
break;
|
break;
|
||||||
@@ -217,7 +216,7 @@ void Interpreter::regimm(const Instruction instr) {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})", instr.instr.opcode.regimm_hi,
|
panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})", instr.instr.opcode.regimm_hi,
|
||||||
instr.instr.opcode.regimm_lo, instr, static_cast<u64>(regs.oldPC));
|
instr.instr.opcode.regimm_lo, u32(instr), static_cast<u64>(regs.oldPC));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,7 +251,7 @@ void Interpreter::cop2Decode(const u32 instr) {
|
|||||||
|
|
||||||
void Interpreter::Exec(const Instruction instr) {
|
void Interpreter::Exec(const Instruction instr) {
|
||||||
// 00rr_rccc
|
// 00rr_rccc
|
||||||
switch (instr.instr.opcode.op) {
|
switch (instr.opcode()) {
|
||||||
case Instruction::SPECIAL:
|
case Instruction::SPECIAL:
|
||||||
special(instr);
|
special(instr);
|
||||||
break;
|
break;
|
||||||
@@ -305,6 +304,33 @@ void Interpreter::Exec(const Instruction instr) {
|
|||||||
regs.cop0.decode(instr);
|
regs.cop0.decode(instr);
|
||||||
break;
|
break;
|
||||||
case Instruction::COP1:
|
case Instruction::COP1:
|
||||||
|
if(instr.cop_rs() == 0x08) {
|
||||||
|
switch (instr.cop_rt()) {
|
||||||
|
case 0:
|
||||||
|
if (!regs.cop1.CheckFPUUsable())
|
||||||
|
return;
|
||||||
|
b(instr, !regs.cop1.fcr31.compare);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (!regs.cop1.CheckFPUUsable())
|
||||||
|
return;
|
||||||
|
b(instr, regs.cop1.fcr31.compare);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (!regs.cop1.CheckFPUUsable())
|
||||||
|
return;
|
||||||
|
bl(instr, !regs.cop1.fcr31.compare);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (!regs.cop1.CheckFPUUsable())
|
||||||
|
return;
|
||||||
|
bl(instr, regs.cop1.fcr31.compare);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
panic("Undefined BC COP1 {:02X}", instr.cop_rt());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
regs.cop1.decode(instr);
|
regs.cop1.decode(instr);
|
||||||
break;
|
break;
|
||||||
case Instruction::COP2:
|
case Instruction::COP2:
|
||||||
|
|||||||
@@ -4,76 +4,76 @@
|
|||||||
#define check_signed_underflow(op1, op2, res) (((((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1)
|
#define check_signed_underflow(op1, op2, res) (((((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1)
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
void Interpreter::add(const u32 instr) {
|
void Interpreter::add(const Instruction instr) {
|
||||||
const u32 rs = regs.Read<s32>(RS(instr));
|
const u32 rs = regs.Read<s32>(instr.rs());
|
||||||
const u32 rt = regs.Read<s32>(RT(instr));
|
const u32 rt = regs.Read<s32>(instr.rt());
|
||||||
if (const u32 result = rs + rt; check_signed_overflow(rs, rt, result)) {
|
if (const u32 result = rs + rt; check_signed_overflow(rs, rt, result)) {
|
||||||
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
regs.Write(RD(instr), static_cast<s32>(result));
|
regs.Write(instr.rd(), static_cast<s32>(result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::addu(const u32 instr) {
|
void Interpreter::addu(const Instruction instr) {
|
||||||
const s32 rs = regs.Read<s32>(RS(instr));
|
const s32 rs = regs.Read<s32>(instr.rs());
|
||||||
const s32 rt = regs.Read<s32>(RT(instr));
|
const s32 rt = regs.Read<s32>(instr.rt());
|
||||||
const s32 result = rs + rt;
|
const s32 result = rs + rt;
|
||||||
regs.Write(RD(instr), result);
|
regs.Write(instr.rd(), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::addi(const u32 instr) {
|
void Interpreter::addi(const Instruction instr) {
|
||||||
const u32 rs = regs.Read<s64>(RS(instr));
|
const u32 rs = regs.Read<s64>(instr.rs());
|
||||||
const u32 imm = static_cast<s32>(static_cast<s16>(instr));
|
const u32 imm = static_cast<s32>(static_cast<s16>(instr));
|
||||||
if (const u32 result = rs + imm; check_signed_overflow(rs, imm, result)) {
|
if (const u32 result = rs + imm; check_signed_overflow(rs, imm, result)) {
|
||||||
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
regs.Write(RT(instr), static_cast<s32>(result));
|
regs.Write(instr.rt(), static_cast<s32>(result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::addiu(const u32 instr) {
|
void Interpreter::addiu(const Instruction instr) {
|
||||||
const s32 rs = regs.Read<s32>(RS(instr));
|
const s32 rs = regs.Read<s32>(instr.rs());
|
||||||
const s16 imm = static_cast<s16>(instr);
|
const s16 imm = static_cast<s16>(instr);
|
||||||
const s32 result = rs + imm;
|
const s32 result = rs + imm;
|
||||||
regs.Write(RT(instr), result);
|
regs.Write(instr.rt(), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dadd(const u32 instr) {
|
void Interpreter::dadd(const Instruction instr) {
|
||||||
const u64 rs = regs.Read<s64>(RS(instr));
|
const u64 rs = regs.Read<s64>(instr.rs());
|
||||||
const u64 rt = regs.Read<s64>(RT(instr));
|
const u64 rt = regs.Read<s64>(instr.rt());
|
||||||
if (const u64 result = rt + rs; check_signed_overflow(rs, rt, result)) {
|
if (const u64 result = rt + rs; check_signed_overflow(rs, rt, result)) {
|
||||||
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
regs.Write(RD(instr), result);
|
regs.Write(instr.rd(), result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::daddu(const u32 instr) {
|
void Interpreter::daddu(const Instruction instr) {
|
||||||
const s64 rs = regs.Read<s64>(RS(instr));
|
const s64 rs = regs.Read<s64>(instr.rs());
|
||||||
const s64 rt = regs.Read<s64>(RT(instr));
|
const s64 rt = regs.Read<s64>(instr.rt());
|
||||||
regs.Write(RD(instr), rs + rt);
|
regs.Write(instr.rd(), rs + rt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::daddi(const u32 instr) {
|
void Interpreter::daddi(const Instruction instr) {
|
||||||
const u64 imm = s64(s16(instr));
|
const u64 imm = s64(s16(instr));
|
||||||
const u64 rs = regs.Read<s64>(RS(instr));
|
const u64 rs = regs.Read<s64>(instr.rs());
|
||||||
if (const u64 result = imm + rs; check_signed_overflow(rs, imm, result)) {
|
if (const u64 result = imm + rs; check_signed_overflow(rs, imm, result)) {
|
||||||
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
regs.Write(RT(instr), result);
|
regs.Write(instr.rt(), result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::daddiu(const u32 instr) {
|
void Interpreter::daddiu(const Instruction instr) {
|
||||||
const s16 imm = static_cast<s16>(instr);
|
const s16 imm = static_cast<s16>(instr);
|
||||||
const s64 rs = regs.Read<s64>(RS(instr));
|
const s64 rs = regs.Read<s64>(instr.rs());
|
||||||
regs.Write(RT(instr), rs + imm);
|
regs.Write(instr.rt(), rs + imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::div(const u32 instr) {
|
void Interpreter::div(const Instruction instr) {
|
||||||
const s64 dividend = regs.Read<s32>(RS(instr));
|
const s64 dividend = regs.Read<s32>(instr.rs());
|
||||||
|
|
||||||
if (const s64 divisor = regs.Read<s32>(RT(instr)); divisor == 0) {
|
if (const s64 divisor = regs.Read<s32>(instr.rt()); divisor == 0) {
|
||||||
regs.hi = dividend;
|
regs.hi = dividend;
|
||||||
if (dividend >= 0) {
|
if (dividend >= 0) {
|
||||||
regs.lo = static_cast<s64>(-1);
|
regs.lo = static_cast<s64>(-1);
|
||||||
@@ -88,9 +88,9 @@ void Interpreter::div(const u32 instr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::divu(const u32 instr) {
|
void Interpreter::divu(const Instruction instr) {
|
||||||
const u32 dividend = regs.Read<s64>(RS(instr));
|
const u32 dividend = regs.Read<s64>(instr.rs());
|
||||||
if (const u32 divisor = regs.Read<s64>(RT(instr)); divisor == 0) {
|
if (const u32 divisor = regs.Read<s64>(instr.rt()); divisor == 0) {
|
||||||
regs.lo = -1;
|
regs.lo = -1;
|
||||||
regs.hi = (s32)dividend;
|
regs.hi = (s32)dividend;
|
||||||
} else {
|
} else {
|
||||||
@@ -101,9 +101,9 @@ void Interpreter::divu(const u32 instr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::ddiv(const u32 instr) {
|
void Interpreter::ddiv(const Instruction instr) {
|
||||||
const s64 dividend = regs.Read<s64>(RS(instr));
|
const s64 dividend = regs.Read<s64>(instr.rs());
|
||||||
const s64 divisor = regs.Read<s64>(RT(instr));
|
const s64 divisor = regs.Read<s64>(instr.rt());
|
||||||
if (dividend == 0x8000000000000000 && divisor == 0xFFFFFFFFFFFFFFFF) {
|
if (dividend == 0x8000000000000000 && divisor == 0xFFFFFFFFFFFFFFFF) {
|
||||||
regs.lo = dividend;
|
regs.lo = dividend;
|
||||||
regs.hi = 0;
|
regs.hi = 0;
|
||||||
@@ -122,9 +122,9 @@ void Interpreter::ddiv(const u32 instr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::ddivu(const u32 instr) {
|
void Interpreter::ddivu(const Instruction instr) {
|
||||||
const u64 dividend = regs.Read<s64>(RS(instr));
|
const u64 dividend = regs.Read<s64>(instr.rs());
|
||||||
const u64 divisor = regs.Read<s64>(RT(instr));
|
const u64 divisor = regs.Read<s64>(instr.rt());
|
||||||
if (divisor == 0) {
|
if (divisor == 0) {
|
||||||
regs.lo = -1;
|
regs.lo = -1;
|
||||||
regs.hi = (s64)dividend;
|
regs.hi = (s64)dividend;
|
||||||
@@ -152,14 +152,14 @@ void Interpreter::branch_likely(const bool cond, const s64 address) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::b(const u32 instr, const bool cond) {
|
void Interpreter::b(const Instruction instr, const bool cond) {
|
||||||
const s16 imm = instr;
|
const s16 imm = instr;
|
||||||
const s64 offset = u64((s64)imm) << 2;
|
const s64 offset = u64((s64)imm) << 2;
|
||||||
const s64 address = regs.pc + offset;
|
const s64 address = regs.pc + offset;
|
||||||
branch(cond, address);
|
branch(cond, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::blink(const u32 instr, const bool cond) {
|
void Interpreter::blink(const Instruction instr, const bool cond) {
|
||||||
regs.Write(31, regs.nextPC);
|
regs.Write(31, regs.nextPC);
|
||||||
const s16 imm = instr;
|
const s16 imm = instr;
|
||||||
const s64 offset = u64((s64)imm) << 2;
|
const s64 offset = u64((s64)imm) << 2;
|
||||||
@@ -167,14 +167,14 @@ void Interpreter::blink(const u32 instr, const bool cond) {
|
|||||||
branch(cond, address);
|
branch(cond, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::bl(const u32 instr, const bool cond) {
|
void Interpreter::bl(const Instruction instr, const bool cond) {
|
||||||
const s16 imm = instr;
|
const s16 imm = instr;
|
||||||
const s64 offset = u64((s64)imm) << 2;
|
const s64 offset = u64((s64)imm) << 2;
|
||||||
const s64 address = regs.pc + offset;
|
const s64 address = regs.pc + offset;
|
||||||
branch_likely(cond, address);
|
branch_likely(cond, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::bllink(const u32 instr, const bool cond) {
|
void Interpreter::bllink(const Instruction instr, const bool cond) {
|
||||||
regs.Write(31, regs.nextPC);
|
regs.Write(31, regs.nextPC);
|
||||||
const s16 imm = instr;
|
const s16 imm = instr;
|
||||||
const s64 offset = u64((s64)imm) << 2;
|
const s64 offset = u64((s64)imm) << 2;
|
||||||
@@ -182,24 +182,24 @@ void Interpreter::bllink(const u32 instr, const bool cond) {
|
|||||||
branch_likely(cond, address);
|
branch_likely(cond, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::lui(const u32 instr) {
|
void Interpreter::lui(const Instruction instr) {
|
||||||
u64 val = s64((s16)instr);
|
u64 val = s64((s16)instr);
|
||||||
val <<= 16;
|
val <<= 16;
|
||||||
regs.Write(RT(instr), val);
|
regs.Write(instr.rt(), val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::lb(const u32 instr) {
|
void Interpreter::lb(const Instruction instr) {
|
||||||
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
if (u32 paddr = 0; !regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
if (u32 paddr = 0; !regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
regs.Write(RT(instr), (s8)mem.Read<u8>(paddr));
|
regs.Write(instr.rt(), (s8)mem.Read<u8>(paddr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::lh(const u32 instr) {
|
void Interpreter::lh(const Instruction instr) {
|
||||||
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
if (check_address_error(0b1, address)) {
|
if (check_address_error(0b1, address)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
@@ -211,13 +211,13 @@ void Interpreter::lh(const u32 instr) {
|
|||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
regs.Write(RT(instr), (s16)mem.Read<u16>(paddr));
|
regs.Write(instr.rt(), (s16)mem.Read<u16>(paddr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::lw(const u32 instr) {
|
void Interpreter::lw(const Instruction instr) {
|
||||||
const s16 offset = instr;
|
const s16 offset = instr;
|
||||||
const u64 address = regs.Read<s64>(RS(instr)) + offset;
|
const u64 address = regs.Read<s64>(instr.rs()) + offset;
|
||||||
if (check_address_error(0b11, address)) {
|
if (check_address_error(0b11, address)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
@@ -229,12 +229,12 @@ void Interpreter::lw(const u32 instr) {
|
|||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
regs.Write(RT(instr), (s32)mem.Read<u32>(physical));
|
regs.Write(instr.rt(), (s32)mem.Read<u32>(physical));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::ll(const u32 instr) {
|
void Interpreter::ll(const Instruction instr) {
|
||||||
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
u32 physical;
|
u32 physical;
|
||||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, physical)) {
|
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, physical)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
@@ -246,15 +246,15 @@ void Interpreter::ll(const u32 instr) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
regs.Write(RT(instr), result);
|
regs.Write(instr.rt(), result);
|
||||||
|
|
||||||
regs.cop0.llbit = true;
|
regs.cop0.llbit = true;
|
||||||
regs.cop0.LLAddr = physical >> 4;
|
regs.cop0.LLAddr = physical >> 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::lwl(const u32 instr) {
|
void Interpreter::lwl(const Instruction instr) {
|
||||||
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
u32 paddr = 0;
|
u32 paddr = 0;
|
||||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
@@ -263,13 +263,13 @@ void Interpreter::lwl(const u32 instr) {
|
|||||||
const u32 shift = 8 * ((address ^ 0) & 3);
|
const u32 shift = 8 * ((address ^ 0) & 3);
|
||||||
const u32 mask = 0xFFFFFFFF << shift;
|
const u32 mask = 0xFFFFFFFF << shift;
|
||||||
const u32 data = mem.Read<u32>(paddr & ~3);
|
const u32 data = mem.Read<u32>(paddr & ~3);
|
||||||
const s32 result = s32((regs.Read<s64>(RT(instr)) & ~mask) | (data << shift));
|
const s32 result = s32((regs.Read<s64>(instr.rt()) & ~mask) | (data << shift));
|
||||||
regs.Write(RT(instr), result);
|
regs.Write(instr.rt(), result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::lwr(const u32 instr) {
|
void Interpreter::lwr(const Instruction instr) {
|
||||||
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
u32 paddr = 0;
|
u32 paddr = 0;
|
||||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
@@ -278,13 +278,13 @@ void Interpreter::lwr(const u32 instr) {
|
|||||||
const u32 shift = 8 * ((address ^ 3) & 3);
|
const u32 shift = 8 * ((address ^ 3) & 3);
|
||||||
const u32 mask = 0xFFFFFFFF >> shift;
|
const u32 mask = 0xFFFFFFFF >> shift;
|
||||||
const u32 data = mem.Read<u32>(paddr & ~3);
|
const u32 data = mem.Read<u32>(paddr & ~3);
|
||||||
const s32 result = s32((regs.Read<s64>(RT(instr)) & ~mask) | (data >> shift));
|
const s32 result = s32((regs.Read<s64>(instr.rt()) & ~mask) | (data >> shift));
|
||||||
regs.Write(RT(instr), result);
|
regs.Write(instr.rt(), result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::ld(const u32 instr) {
|
void Interpreter::ld(const Instruction instr) {
|
||||||
const s64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
if (check_address_error(0b111, address)) {
|
if (check_address_error(0b111, address)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
@@ -297,17 +297,17 @@ void Interpreter::ld(const u32 instr) {
|
|||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
const s64 value = mem.Read<u64>(paddr);
|
const s64 value = mem.Read<u64>(paddr);
|
||||||
regs.Write(RT(instr), value);
|
regs.Write(instr.rt(), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::lld(const u32 instr) {
|
void Interpreter::lld(const Instruction instr) {
|
||||||
if (!regs.cop0.is64BitAddressing && !regs.cop0.kernelMode) {
|
if (!regs.cop0.is64BitAddressing && !regs.cop0.kernelMode) {
|
||||||
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
u32 paddr;
|
u32 paddr;
|
||||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
@@ -316,15 +316,15 @@ void Interpreter::lld(const u32 instr) {
|
|||||||
if (check_address_error(0b111, address)) {
|
if (check_address_error(0b111, address)) {
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
regs.Write(RT(instr), mem.Read<u64>(paddr));
|
regs.Write(instr.rt(), mem.Read<u64>(paddr));
|
||||||
regs.cop0.llbit = true;
|
regs.cop0.llbit = true;
|
||||||
regs.cop0.LLAddr = paddr >> 4;
|
regs.cop0.LLAddr = paddr >> 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::ldl(const u32 instr) {
|
void Interpreter::ldl(const Instruction instr) {
|
||||||
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
u32 paddr = 0;
|
u32 paddr = 0;
|
||||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
@@ -333,13 +333,13 @@ void Interpreter::ldl(const u32 instr) {
|
|||||||
const s32 shift = 8 * ((address ^ 0) & 7);
|
const s32 shift = 8 * ((address ^ 0) & 7);
|
||||||
const u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
|
const u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
|
||||||
const u64 data = mem.Read<u64>(paddr & ~7);
|
const u64 data = mem.Read<u64>(paddr & ~7);
|
||||||
const s64 result = (s64)((regs.Read<s64>(RT(instr)) & ~mask) | (data << shift));
|
const s64 result = (s64)((regs.Read<s64>(instr.rt()) & ~mask) | (data << shift));
|
||||||
regs.Write(RT(instr), result);
|
regs.Write(instr.rt(), result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::ldr(const u32 instr) {
|
void Interpreter::ldr(const Instruction instr) {
|
||||||
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
u32 paddr;
|
u32 paddr;
|
||||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
@@ -348,25 +348,25 @@ void Interpreter::ldr(const u32 instr) {
|
|||||||
const s32 shift = 8 * ((address ^ 7) & 7);
|
const s32 shift = 8 * ((address ^ 7) & 7);
|
||||||
const u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
|
const u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
|
||||||
const u64 data = mem.Read<u64>(paddr & ~7);
|
const u64 data = mem.Read<u64>(paddr & ~7);
|
||||||
const s64 result = (s64)((regs.Read<s64>(RT(instr)) & ~mask) | (data >> shift));
|
const s64 result = (s64)((regs.Read<s64>(instr.rt()) & ~mask) | (data >> shift));
|
||||||
regs.Write(RT(instr), result);
|
regs.Write(instr.rt(), result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::lbu(const u32 instr) {
|
void Interpreter::lbu(const Instruction instr) {
|
||||||
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
u32 paddr;
|
u32 paddr;
|
||||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
const u8 value = mem.Read<u8>(paddr);
|
const u8 value = mem.Read<u8>(paddr);
|
||||||
regs.Write(RT(instr), value);
|
regs.Write(instr.rt(), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::lhu(const u32 instr) {
|
void Interpreter::lhu(const Instruction instr) {
|
||||||
const s64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
if (check_address_error(0b1, address)) {
|
if (check_address_error(0b1, address)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
@@ -378,12 +378,12 @@ void Interpreter::lhu(const u32 instr) {
|
|||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
const u16 value = mem.Read<u16>(paddr);
|
const u16 value = mem.Read<u16>(paddr);
|
||||||
regs.Write(RT(instr), value);
|
regs.Write(instr.rt(), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::lwu(const u32 instr) {
|
void Interpreter::lwu(const Instruction instr) {
|
||||||
const s64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
if (check_address_error(0b11, address)) {
|
if (check_address_error(0b11, address)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
@@ -396,29 +396,29 @@ void Interpreter::lwu(const u32 instr) {
|
|||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
const u32 value = mem.Read<u32>(paddr);
|
const u32 value = mem.Read<u32>(paddr);
|
||||||
regs.Write(RT(instr), value);
|
regs.Write(instr.rt(), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::sb(const u32 instr) {
|
void Interpreter::sb(const Instruction instr) {
|
||||||
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
u32 paddr;
|
u32 paddr;
|
||||||
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
mem.Write<u8>(paddr, regs.Read<s64>(RT(instr)));
|
mem.Write<u8>(paddr, regs.Read<s64>(instr.rt()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::sc(const u32 instr) {
|
void Interpreter::sc(const Instruction instr) {
|
||||||
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
|
|
||||||
if (regs.cop0.llbit) {
|
if (regs.cop0.llbit) {
|
||||||
regs.cop0.llbit = false;
|
regs.cop0.llbit = false;
|
||||||
|
|
||||||
if (check_address_error(0b11, address)) {
|
if (check_address_error(0b11, address)) {
|
||||||
regs.Write(RT(instr), 0);
|
regs.Write(instr.rt(), 0);
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||||
return;
|
return;
|
||||||
@@ -426,31 +426,31 @@ void Interpreter::sc(const u32 instr) {
|
|||||||
|
|
||||||
u32 paddr = 0;
|
u32 paddr = 0;
|
||||||
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
||||||
regs.Write(RT(instr), 0);
|
regs.Write(instr.rt(), 0);
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
mem.Write<u32>(paddr, regs.Read<s64>(RT(instr)));
|
mem.Write<u32>(paddr, regs.Read<s64>(instr.rt()));
|
||||||
regs.Write(RT(instr), 1);
|
regs.Write(instr.rt(), 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
regs.Write(RT(instr), 0);
|
regs.Write(instr.rt(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::scd(const u32 instr) {
|
void Interpreter::scd(const Instruction instr) {
|
||||||
if (!regs.cop0.is64BitAddressing && !regs.cop0.kernelMode) {
|
if (!regs.cop0.is64BitAddressing && !regs.cop0.kernelMode) {
|
||||||
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const s64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
|
|
||||||
if (regs.cop0.llbit) {
|
if (regs.cop0.llbit) {
|
||||||
regs.cop0.llbit = false;
|
regs.cop0.llbit = false;
|
||||||
|
|
||||||
if (check_address_error(0b111, address)) {
|
if (check_address_error(0b111, address)) {
|
||||||
regs.Write(RT(instr), 0);
|
regs.Write(instr.rt(), 0);
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||||
return;
|
return;
|
||||||
@@ -458,33 +458,33 @@ void Interpreter::scd(const u32 instr) {
|
|||||||
|
|
||||||
u32 paddr = 0;
|
u32 paddr = 0;
|
||||||
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
||||||
regs.Write(RT(instr), 0);
|
regs.Write(instr.rt(), 0);
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
mem.Write<u32>(paddr, regs.Read<s64>(RT(instr)));
|
mem.Write<u32>(paddr, regs.Read<s64>(instr.rt()));
|
||||||
regs.Write(RT(instr), 1);
|
regs.Write(instr.rt(), 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
regs.Write(RT(instr), 0);
|
regs.Write(instr.rt(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::sh(const u32 instr) {
|
void Interpreter::sh(const Instruction instr) {
|
||||||
const s64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
|
|
||||||
u32 physical;
|
u32 physical;
|
||||||
if (!regs.cop0.MapVAddr(Cop0::STORE, address, physical)) {
|
if (!regs.cop0.MapVAddr(Cop0::STORE, address, physical)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
mem.Write<u16>(physical, regs.Read<s64>(RT(instr)));
|
mem.Write<u16>(physical, regs.Read<s64>(instr.rt()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::sw(const u32 instr) {
|
void Interpreter::sw(const Instruction instr) {
|
||||||
const s16 offset = instr;
|
const s16 offset = instr;
|
||||||
const u64 address = regs.Read<s64>(RS(instr)) + offset;
|
const u64 address = regs.Read<s64>(instr.rs()) + offset;
|
||||||
if (check_address_error(0b11, address)) {
|
if (check_address_error(0b11, address)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||||
@@ -496,12 +496,12 @@ void Interpreter::sw(const u32 instr) {
|
|||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
mem.Write<u32>(physical, regs.Read<s64>(RT(instr)));
|
mem.Write<u32>(physical, regs.Read<s64>(instr.rt()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::sd(const u32 instr) {
|
void Interpreter::sd(const Instruction instr) {
|
||||||
const s64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
if (check_address_error(0b111, address)) {
|
if (check_address_error(0b111, address)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||||
@@ -513,12 +513,12 @@ void Interpreter::sd(const u32 instr) {
|
|||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
mem.Write(physical, regs.Read<s64>(RT(instr)));
|
mem.Write(physical, regs.Read<s64>(instr.rt()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::sdl(const u32 instr) {
|
void Interpreter::sdl(const Instruction instr) {
|
||||||
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
u32 paddr;
|
u32 paddr;
|
||||||
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
@@ -527,13 +527,13 @@ void Interpreter::sdl(const u32 instr) {
|
|||||||
const s32 shift = 8 * ((address ^ 0) & 7);
|
const s32 shift = 8 * ((address ^ 0) & 7);
|
||||||
const u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
|
const u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
|
||||||
const u64 data = mem.Read<u64>(paddr & ~7);
|
const u64 data = mem.Read<u64>(paddr & ~7);
|
||||||
const u64 rt = regs.Read<s64>(RT(instr));
|
const u64 rt = regs.Read<s64>(instr.rt());
|
||||||
mem.Write(paddr & ~7, (data & ~mask) | (rt >> shift));
|
mem.Write(paddr & ~7, (data & ~mask) | (rt >> shift));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::sdr(const u32 instr) {
|
void Interpreter::sdr(const Instruction instr) {
|
||||||
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
u32 paddr;
|
u32 paddr;
|
||||||
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
@@ -542,13 +542,13 @@ void Interpreter::sdr(const u32 instr) {
|
|||||||
const s32 shift = 8 * ((address ^ 7) & 7);
|
const s32 shift = 8 * ((address ^ 7) & 7);
|
||||||
const u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
|
const u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
|
||||||
const u64 data = mem.Read<u64>(paddr & ~7);
|
const u64 data = mem.Read<u64>(paddr & ~7);
|
||||||
const u64 rt = regs.Read<s64>(RT(instr));
|
const u64 rt = regs.Read<s64>(instr.rt());
|
||||||
mem.Write(paddr & ~7, (data & ~mask) | (rt << shift));
|
mem.Write(paddr & ~7, (data & ~mask) | (rt << shift));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::swl(const u32 instr) {
|
void Interpreter::swl(const Instruction instr) {
|
||||||
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
u32 paddr;
|
u32 paddr;
|
||||||
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
@@ -557,13 +557,13 @@ void Interpreter::swl(const u32 instr) {
|
|||||||
const u32 shift = 8 * ((address ^ 0) & 3);
|
const u32 shift = 8 * ((address ^ 0) & 3);
|
||||||
const u32 mask = 0xFFFFFFFF >> shift;
|
const u32 mask = 0xFFFFFFFF >> shift;
|
||||||
const u32 data = mem.Read<u32>(paddr & ~3);
|
const u32 data = mem.Read<u32>(paddr & ~3);
|
||||||
const u32 rt = regs.Read<s64>(RT(instr));
|
const u32 rt = regs.Read<s64>(instr.rt());
|
||||||
mem.Write<u32>(paddr & ~3, (data & ~mask) | (rt >> shift));
|
mem.Write<u32>(paddr & ~3, (data & ~mask) | (rt >> shift));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::swr(const u32 instr) {
|
void Interpreter::swr(const Instruction instr) {
|
||||||
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
|
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
|
||||||
u32 paddr;
|
u32 paddr;
|
||||||
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
||||||
regs.cop0.HandleTLBException(address);
|
regs.cop0.HandleTLBException(address);
|
||||||
@@ -572,256 +572,256 @@ void Interpreter::swr(const u32 instr) {
|
|||||||
const u32 shift = 8 * ((address ^ 3) & 3);
|
const u32 shift = 8 * ((address ^ 3) & 3);
|
||||||
const u32 mask = 0xFFFFFFFF << shift;
|
const u32 mask = 0xFFFFFFFF << shift;
|
||||||
const u32 data = mem.Read<u32>(paddr & ~3);
|
const u32 data = mem.Read<u32>(paddr & ~3);
|
||||||
const u32 rt = regs.Read<s64>(RT(instr));
|
const u32 rt = regs.Read<s64>(instr.rt());
|
||||||
mem.Write<u32>(paddr & ~3, (data & ~mask) | (rt << shift));
|
mem.Write<u32>(paddr & ~3, (data & ~mask) | (rt << shift));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::ori(const u32 instr) {
|
void Interpreter::ori(const Instruction instr) {
|
||||||
const s64 imm = (u16)instr;
|
const s64 imm = (u16)instr;
|
||||||
const s64 result = imm | regs.Read<s64>(RS(instr));
|
const s64 result = imm | regs.Read<s64>(instr.rs());
|
||||||
regs.Write(RT(instr), result);
|
regs.Write(instr.rt(), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::or_(const u32 instr) { regs.Write(RD(instr), regs.Read<s64>(RS(instr)) | regs.Read<s64>(RT(instr))); }
|
void Interpreter::or_(const Instruction instr) { regs.Write(instr.rd(), regs.Read<s64>(instr.rs()) | regs.Read<s64>(instr.rt())); }
|
||||||
|
|
||||||
void Interpreter::nor(const u32 instr) {
|
void Interpreter::nor(const Instruction instr) {
|
||||||
regs.Write(RD(instr), ~(regs.Read<s64>(RS(instr)) | regs.Read<s64>(RT(instr))));
|
regs.Write(instr.rd(), ~(regs.Read<s64>(instr.rs()) | regs.Read<s64>(instr.rt())));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::j(const u32 instr) {
|
void Interpreter::j(const Instruction instr) {
|
||||||
const s32 target = (instr & 0x3ffffff) << 2;
|
const s32 target = (instr & 0x3ffffff) << 2;
|
||||||
const s64 address = (regs.oldPC & ~0xfffffff) | target;
|
const s64 address = (regs.oldPC & ~0xfffffff) | target;
|
||||||
|
|
||||||
branch(true, address);
|
branch(true, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::jal(const u32 instr) {
|
void Interpreter::jal(const Instruction instr) {
|
||||||
regs.Write(31, regs.nextPC);
|
regs.Write(31, regs.nextPC);
|
||||||
j(instr);
|
j(instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::jalr(const u32 instr) {
|
void Interpreter::jalr(const Instruction instr) {
|
||||||
regs.Write(RD(instr), regs.nextPC);
|
regs.Write(instr.rd(), regs.nextPC);
|
||||||
jr(instr);
|
jr(instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::jr(const u32 instr) {
|
void Interpreter::jr(const Instruction instr) {
|
||||||
const u64 address = regs.Read<s64>(RS(instr));
|
const u64 address = regs.Read<s64>(instr.rs());
|
||||||
branch(true, address);
|
branch(true, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::slti(const u32 instr) {
|
void Interpreter::slti(const Instruction instr) {
|
||||||
const s16 imm = instr;
|
const s16 imm = instr;
|
||||||
regs.Write(RT(instr), regs.Read<s64>(RS(instr)) < imm);
|
regs.Write(instr.rt(), regs.Read<s64>(instr.rs()) < imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::sltiu(const u32 instr) {
|
void Interpreter::sltiu(const Instruction instr) {
|
||||||
const s16 imm = instr;
|
const s16 imm = instr;
|
||||||
regs.Write(RT(instr), regs.Read<u64>(RS(instr)) < imm);
|
regs.Write(instr.rt(), regs.Read<u64>(instr.rs()) < imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::slt(const u32 instr) { regs.Write(RD(instr), regs.Read<s64>(RS(instr)) < regs.Read<s64>(RT(instr))); }
|
void Interpreter::slt(const Instruction instr) { regs.Write(instr.rd(), regs.Read<s64>(instr.rs()) < regs.Read<s64>(instr.rt())); }
|
||||||
|
|
||||||
void Interpreter::sltu(const u32 instr) {
|
void Interpreter::sltu(const Instruction instr) {
|
||||||
regs.Write(RD(instr), regs.Read<u64>(RS(instr)) < regs.Read<u64>(RT(instr)));
|
regs.Write(instr.rd(), regs.Read<u64>(instr.rs()) < regs.Read<u64>(instr.rt()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::xori(const u32 instr) {
|
void Interpreter::xori(const Instruction instr) {
|
||||||
const s64 imm = (u16)instr;
|
const s64 imm = (u16)instr;
|
||||||
regs.Write(RT(instr), regs.Read<s64>(RS(instr)) ^ imm);
|
regs.Write(instr.rt(), regs.Read<s64>(instr.rs()) ^ imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::xor_(const u32 instr) {
|
void Interpreter::xor_(const Instruction instr) {
|
||||||
regs.Write(RD(instr), regs.Read<s64>(RT(instr)) ^ regs.Read<s64>(RS(instr)));
|
regs.Write(instr.rd(), regs.Read<s64>(instr.rt()) ^ regs.Read<s64>(instr.rs()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::andi(const u32 instr) {
|
void Interpreter::andi(const Instruction instr) {
|
||||||
const s64 imm = (u16)instr;
|
const s64 imm = (u16)instr;
|
||||||
regs.Write(RT(instr), regs.Read<s64>(RS(instr)) & imm);
|
regs.Write(instr.rt(), regs.Read<s64>(instr.rs()) & imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::and_(const u32 instr) {
|
void Interpreter::and_(const Instruction instr) {
|
||||||
regs.Write(RD(instr), regs.Read<s64>(RS(instr)) & regs.Read<s64>(RT(instr)));
|
regs.Write(instr.rd(), regs.Read<s64>(instr.rs()) & regs.Read<s64>(instr.rt()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::sll(const u32 instr) {
|
void Interpreter::sll(const Instruction instr) {
|
||||||
const u8 sa = ((instr >> 6) & 0x1f);
|
const u8 sa = ((instr >> 6) & 0x1f);
|
||||||
const s32 result = regs.Read<s64>(RT(instr)) << sa;
|
const s32 result = regs.Read<s64>(instr.rt()) << sa;
|
||||||
regs.Write(RD(instr), (s64)result);
|
regs.Write(instr.rd(), (s64)result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::sllv(const u32 instr) {
|
void Interpreter::sllv(const Instruction instr) {
|
||||||
const u8 sa = (regs.Read<s64>(RS(instr))) & 0x1F;
|
const u8 sa = (regs.Read<s64>(instr.rs())) & 0x1F;
|
||||||
const u32 rt = regs.Read<s64>(RT(instr));
|
const u32 rt = regs.Read<s64>(instr.rt());
|
||||||
const s32 result = rt << sa;
|
const s32 result = rt << sa;
|
||||||
regs.Write(RD(instr), (s64)result);
|
regs.Write(instr.rd(), (s64)result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsll32(const u32 instr) {
|
void Interpreter::dsll32(const Instruction instr) {
|
||||||
const u8 sa = ((instr >> 6) & 0x1f);
|
const u8 sa = ((instr >> 6) & 0x1f);
|
||||||
const s64 result = regs.Read<s64>(RT(instr)) << (sa + 32);
|
const s64 result = regs.Read<s64>(instr.rt()) << (sa + 32);
|
||||||
regs.Write(RD(instr), result);
|
regs.Write(instr.rd(), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsll(const u32 instr) {
|
void Interpreter::dsll(const Instruction instr) {
|
||||||
const u8 sa = ((instr >> 6) & 0x1f);
|
const u8 sa = ((instr >> 6) & 0x1f);
|
||||||
const s64 result = regs.Read<s64>(RT(instr)) << sa;
|
const s64 result = regs.Read<s64>(instr.rt()) << sa;
|
||||||
regs.Write(RD(instr), result);
|
regs.Write(instr.rd(), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsllv(const u32 instr) {
|
void Interpreter::dsllv(const Instruction instr) {
|
||||||
const s64 sa = regs.Read<s64>(RS(instr)) & 63;
|
const s64 sa = regs.Read<s64>(instr.rs()) & 63;
|
||||||
const s64 result = regs.Read<s64>(RT(instr)) << sa;
|
const s64 result = regs.Read<s64>(instr.rt()) << sa;
|
||||||
regs.Write(RD(instr), result);
|
regs.Write(instr.rd(), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::srl(const u32 instr) {
|
void Interpreter::srl(const Instruction instr) {
|
||||||
const u32 rt = regs.Read<s64>(RT(instr));
|
const u32 rt = regs.Read<s64>(instr.rt());
|
||||||
const u8 sa = ((instr >> 6) & 0x1f);
|
const u8 sa = ((instr >> 6) & 0x1f);
|
||||||
const u32 result = rt >> sa;
|
const u32 result = rt >> sa;
|
||||||
regs.Write(RD(instr), (s32)result);
|
regs.Write(instr.rd(), (s32)result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::srlv(const u32 instr) {
|
void Interpreter::srlv(const Instruction instr) {
|
||||||
const u8 sa = (regs.Read<s64>(RS(instr)) & 0x1F);
|
const u8 sa = (regs.Read<s64>(instr.rs()) & 0x1F);
|
||||||
const u32 rt = regs.Read<s64>(RT(instr));
|
const u32 rt = regs.Read<s64>(instr.rt());
|
||||||
const s32 result = rt >> sa;
|
const s32 result = rt >> sa;
|
||||||
regs.Write(RD(instr), (s64)result);
|
regs.Write(instr.rd(), (s64)result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsrl(const u32 instr) {
|
void Interpreter::dsrl(const Instruction instr) {
|
||||||
const u64 rt = regs.Read<s64>(RT(instr));
|
const u64 rt = regs.Read<s64>(instr.rt());
|
||||||
const u8 sa = ((instr >> 6) & 0x1f);
|
const u8 sa = ((instr >> 6) & 0x1f);
|
||||||
const u64 result = rt >> sa;
|
const u64 result = rt >> sa;
|
||||||
regs.Write(RD(instr), s64(result));
|
regs.Write(instr.rd(), s64(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsrlv(const u32 instr) {
|
void Interpreter::dsrlv(const Instruction instr) {
|
||||||
const u8 amount = (regs.Read<s64>(RS(instr)) & 63);
|
const u8 amount = (regs.Read<s64>(instr.rs()) & 63);
|
||||||
const u64 rt = regs.Read<s64>(RT(instr));
|
const u64 rt = regs.Read<s64>(instr.rt());
|
||||||
const u64 result = rt >> amount;
|
const u64 result = rt >> amount;
|
||||||
regs.Write(RD(instr), s64(result));
|
regs.Write(instr.rd(), s64(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsrl32(const u32 instr) {
|
void Interpreter::dsrl32(const Instruction instr) {
|
||||||
const u64 rt = regs.Read<s64>(RT(instr));
|
const u64 rt = regs.Read<s64>(instr.rt());
|
||||||
const u8 sa = ((instr >> 6) & 0x1f);
|
const u8 sa = ((instr >> 6) & 0x1f);
|
||||||
const u64 result = rt >> (sa + 32);
|
const u64 result = rt >> (sa + 32);
|
||||||
regs.Write(RD(instr), s64(result));
|
regs.Write(instr.rd(), s64(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::sra(const u32 instr) {
|
void Interpreter::sra(const Instruction instr) {
|
||||||
const s64 rt = regs.Read<s64>(RT(instr));
|
const s64 rt = regs.Read<s64>(instr.rt());
|
||||||
const u8 sa = ((instr >> 6) & 0x1f);
|
const u8 sa = ((instr >> 6) & 0x1f);
|
||||||
const s32 result = rt >> sa;
|
const s32 result = rt >> sa;
|
||||||
regs.Write(RD(instr), result);
|
regs.Write(instr.rd(), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::srav(const u32 instr) {
|
void Interpreter::srav(const Instruction instr) {
|
||||||
const s64 rs = regs.Read<s64>(RS(instr));
|
const s64 rs = regs.Read<s64>(instr.rs());
|
||||||
const s64 rt = regs.Read<s64>(RT(instr));
|
const s64 rt = regs.Read<s64>(instr.rt());
|
||||||
const u8 sa = rs & 0x1f;
|
const u8 sa = rs & 0x1f;
|
||||||
const s32 result = rt >> sa;
|
const s32 result = rt >> sa;
|
||||||
regs.Write(RD(instr), result);
|
regs.Write(instr.rd(), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsra(const u32 instr) {
|
void Interpreter::dsra(const Instruction instr) {
|
||||||
const s64 rt = regs.Read<s64>(RT(instr));
|
const s64 rt = regs.Read<s64>(instr.rt());
|
||||||
const u8 sa = ((instr >> 6) & 0x1f);
|
const u8 sa = ((instr >> 6) & 0x1f);
|
||||||
const s64 result = rt >> sa;
|
const s64 result = rt >> sa;
|
||||||
regs.Write(RD(instr), result);
|
regs.Write(instr.rd(), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsrav(const u32 instr) {
|
void Interpreter::dsrav(const Instruction instr) {
|
||||||
const s64 rt = regs.Read<s64>(RT(instr));
|
const s64 rt = regs.Read<s64>(instr.rt());
|
||||||
const s64 rs = regs.Read<s64>(RS(instr));
|
const s64 rs = regs.Read<s64>(instr.rs());
|
||||||
const s64 sa = rs & 63;
|
const s64 sa = rs & 63;
|
||||||
const s64 result = rt >> sa;
|
const s64 result = rt >> sa;
|
||||||
regs.Write(RD(instr), result);
|
regs.Write(instr.rd(), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsra32(const u32 instr) {
|
void Interpreter::dsra32(const Instruction instr) {
|
||||||
const s64 rt = regs.Read<s64>(RT(instr));
|
const s64 rt = regs.Read<s64>(instr.rt());
|
||||||
const u8 sa = ((instr >> 6) & 0x1f);
|
const u8 sa = ((instr >> 6) & 0x1f);
|
||||||
const s64 result = rt >> (sa + 32);
|
const s64 result = rt >> (sa + 32);
|
||||||
regs.Write(RD(instr), result);
|
regs.Write(instr.rd(), result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsub(const u32 instr) {
|
void Interpreter::dsub(const Instruction instr) {
|
||||||
const s64 rt = regs.Read<s64>(RT(instr));
|
const s64 rt = regs.Read<s64>(instr.rt());
|
||||||
const s64 rs = regs.Read<s64>(RS(instr));
|
const s64 rs = regs.Read<s64>(instr.rs());
|
||||||
if (const s64 result = rs - rt; check_signed_underflow(rs, rt, result)) {
|
if (const s64 result = rs - rt; check_signed_underflow(rs, rt, result)) {
|
||||||
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
regs.Write(RD(instr), result);
|
regs.Write(instr.rd(), result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dsubu(const u32 instr) {
|
void Interpreter::dsubu(const Instruction instr) {
|
||||||
const u64 rt = regs.Read<s64>(RT(instr));
|
const u64 rt = regs.Read<s64>(instr.rt());
|
||||||
const u64 rs = regs.Read<s64>(RS(instr));
|
const u64 rs = regs.Read<s64>(instr.rs());
|
||||||
const u64 result = rs - rt;
|
const u64 result = rs - rt;
|
||||||
regs.Write(RD(instr), s64(result));
|
regs.Write(instr.rd(), s64(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::sub(const u32 instr) {
|
void Interpreter::sub(const Instruction instr) {
|
||||||
const s32 rt = regs.Read<s64>(RT(instr));
|
const s32 rt = regs.Read<s64>(instr.rt());
|
||||||
const s32 rs = regs.Read<s64>(RS(instr));
|
const s32 rs = regs.Read<s64>(instr.rs());
|
||||||
const s32 result = rs - rt;
|
const s32 result = rs - rt;
|
||||||
if (check_signed_underflow(rs, rt, result)) {
|
if (check_signed_underflow(rs, rt, result)) {
|
||||||
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||||
} else {
|
} else {
|
||||||
regs.Write(RD(instr), result);
|
regs.Write(instr.rd(), result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::subu(const u32 instr) {
|
void Interpreter::subu(const Instruction instr) {
|
||||||
const u32 rt = regs.Read<s64>(RT(instr));
|
const u32 rt = regs.Read<s64>(instr.rt());
|
||||||
const u32 rs = regs.Read<s64>(RS(instr));
|
const u32 rs = regs.Read<s64>(instr.rs());
|
||||||
const u32 result = rs - rt;
|
const u32 result = rs - rt;
|
||||||
regs.Write(RD(instr), (s64)((s32)result));
|
regs.Write(instr.rd(), (s64)((s32)result));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dmultu(const u32 instr) {
|
void Interpreter::dmultu(const Instruction instr) {
|
||||||
const u64 rt = regs.Read<s64>(RT(instr));
|
const u64 rt = regs.Read<s64>(instr.rt());
|
||||||
const u64 rs = regs.Read<s64>(RS(instr));
|
const u64 rs = regs.Read<s64>(instr.rs());
|
||||||
const u128 result = (u128)rt * (u128)rs;
|
const u128 result = (u128)rt * (u128)rs;
|
||||||
regs.lo = (s64)(result & 0xFFFFFFFFFFFFFFFF);
|
regs.lo = (s64)(result & 0xFFFFFFFFFFFFFFFF);
|
||||||
regs.hi = (s64)(result >> 64);
|
regs.hi = (s64)(result >> 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dmult(const u32 instr) {
|
void Interpreter::dmult(const Instruction instr) {
|
||||||
const s64 rt = regs.Read<s64>(RT(instr));
|
const s64 rt = regs.Read<s64>(instr.rt());
|
||||||
const s64 rs = regs.Read<s64>(RS(instr));
|
const s64 rs = regs.Read<s64>(instr.rs());
|
||||||
const s128 result = (s128)rt * (s128)rs;
|
const s128 result = (s128)rt * (s128)rs;
|
||||||
regs.lo = result & 0xFFFFFFFFFFFFFFFF;
|
regs.lo = result & 0xFFFFFFFFFFFFFFFF;
|
||||||
regs.hi = result >> 64;
|
regs.hi = result >> 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::multu(const u32 instr) {
|
void Interpreter::multu(const Instruction instr) {
|
||||||
const u32 rt = regs.Read<s64>(RT(instr));
|
const u32 rt = regs.Read<s64>(instr.rt());
|
||||||
const u32 rs = regs.Read<s64>(RS(instr));
|
const u32 rs = regs.Read<s64>(instr.rs());
|
||||||
const u64 result = (u64)rt * (u64)rs;
|
const u64 result = (u64)rt * (u64)rs;
|
||||||
regs.lo = (s64)((s32)result);
|
regs.lo = (s64)((s32)result);
|
||||||
regs.hi = (s64)((s32)(result >> 32));
|
regs.hi = (s64)((s32)(result >> 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::mult(const u32 instr) {
|
void Interpreter::mult(const Instruction instr) {
|
||||||
const s32 rt = regs.Read<s64>(RT(instr));
|
const s32 rt = regs.Read<s64>(instr.rt());
|
||||||
const s32 rs = regs.Read<s64>(RS(instr));
|
const s32 rs = regs.Read<s64>(instr.rs());
|
||||||
const s64 result = (s64)rt * (s64)rs;
|
const s64 result = (s64)rt * (s64)rs;
|
||||||
regs.lo = (s64)((s32)result);
|
regs.lo = (s64)((s32)result);
|
||||||
regs.hi = (s64)((s32)(result >> 32));
|
regs.hi = (s64)((s32)(result >> 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::mflo(const u32 instr) { regs.Write(RD(instr), regs.lo); }
|
void Interpreter::mflo(const Instruction instr) { regs.Write(instr.rd(), regs.lo); }
|
||||||
|
|
||||||
void Interpreter::mfhi(const u32 instr) { regs.Write(RD(instr), regs.hi); }
|
void Interpreter::mfhi(const Instruction instr) { regs.Write(instr.rd(), regs.hi); }
|
||||||
|
|
||||||
void Interpreter::mtlo(const u32 instr) { regs.lo = regs.Read<s64>(RS(instr)); }
|
void Interpreter::mtlo(const Instruction instr) { regs.lo = regs.Read<s64>(instr.rs()); }
|
||||||
|
|
||||||
void Interpreter::mthi(const u32 instr) { regs.hi = regs.Read<s64>(RS(instr)); }
|
void Interpreter::mthi(const Instruction instr) { regs.hi = regs.Read<s64>(instr.rs()); }
|
||||||
|
|
||||||
void Interpreter::trap(const bool cond) const {
|
void Interpreter::trap(const bool cond) const {
|
||||||
Cop0& cop0 = Core::GetRegs().cop0;
|
Cop0& cop0 = Core::GetRegs().cop0;
|
||||||
@@ -830,18 +830,18 @@ void Interpreter::trap(const bool cond) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::mtc2(const u32 instr) { cop2Latch = regs.Read<s64>(RT(instr)); }
|
void Interpreter::mtc2(const Instruction instr) { cop2Latch = regs.Read<s64>(instr.rt()); }
|
||||||
|
|
||||||
void Interpreter::mfc2(const u32 instr) {
|
void Interpreter::mfc2(const Instruction instr) {
|
||||||
const s32 value = cop2Latch;
|
const s32 value = cop2Latch;
|
||||||
regs.Write(RT(instr), value);
|
regs.Write(instr.rt(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::dmtc2(const u32 instr) { cop2Latch = regs.Read<s64>(RT(instr)); }
|
void Interpreter::dmtc2(const Instruction instr) { cop2Latch = regs.Read<s64>(instr.rt()); }
|
||||||
|
|
||||||
void Interpreter::dmfc2(const u32 instr) { regs.Write(RT(instr), cop2Latch); }
|
void Interpreter::dmfc2(const Instruction instr) { regs.Write(instr.rt(), cop2Latch); }
|
||||||
|
|
||||||
void Interpreter::ctc2(u32) {}
|
void Interpreter::ctc2(const Instruction) {}
|
||||||
|
|
||||||
void Interpreter::cfc2(u32) {}
|
void Interpreter::cfc2(const Instruction) {}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -1,283 +1,281 @@
|
|||||||
#include <JIT.hpp>
|
#include <JIT.hpp>
|
||||||
#include <CpuDefinitions.hpp>
|
#include <Instruction.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
void JIT::special(const u32 instr) {
|
void JIT::special(const Instruction instr) {
|
||||||
// 00rr_rccc
|
// 00rr_rccc
|
||||||
switch (const u8 mask = instr & 0x3F) {
|
switch (instr.special()) {
|
||||||
case SLL:
|
case Instruction::SLL:
|
||||||
if (instr != 0) {
|
if (instr != 0) {
|
||||||
sll(instr);
|
sll(instr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SRL:
|
case Instruction::SRL:
|
||||||
srl(instr);
|
srl(instr);
|
||||||
break;
|
break;
|
||||||
case SRA:
|
case Instruction::SRA:
|
||||||
sra(instr);
|
sra(instr);
|
||||||
break;
|
break;
|
||||||
case SLLV:
|
case Instruction::SLLV:
|
||||||
sllv(instr);
|
sllv(instr);
|
||||||
break;
|
break;
|
||||||
case SRLV:
|
case Instruction::SRLV:
|
||||||
srlv(instr);
|
srlv(instr);
|
||||||
break;
|
break;
|
||||||
case SRAV:
|
case Instruction::SRAV:
|
||||||
srav(instr);
|
srav(instr);
|
||||||
break;
|
break;
|
||||||
case JR:
|
case Instruction::JR:
|
||||||
jr(instr);
|
jr(instr);
|
||||||
break;
|
break;
|
||||||
case JALR:
|
case Instruction::JALR:
|
||||||
jalr(instr);
|
jalr(instr);
|
||||||
break;
|
break;
|
||||||
case SYSCALL:
|
case Instruction::SYSCALL:
|
||||||
regs.cop0.FireException(ExceptionCode::Syscall, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::Syscall, 0, regs.oldPC);
|
||||||
break;
|
break;
|
||||||
case BREAK:
|
case Instruction::BREAK:
|
||||||
regs.cop0.FireException(ExceptionCode::Breakpoint, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::Breakpoint, 0, regs.oldPC);
|
||||||
break;
|
break;
|
||||||
case SYNC:
|
case Instruction::SYNC:
|
||||||
break; // SYNC
|
break; // SYNC
|
||||||
case MFHI:
|
case Instruction::MFHI:
|
||||||
mfhi(instr);
|
mfhi(instr);
|
||||||
break;
|
break;
|
||||||
case MTHI:
|
case Instruction::MTHI:
|
||||||
mthi(instr);
|
mthi(instr);
|
||||||
break;
|
break;
|
||||||
case MFLO:
|
case Instruction::MFLO:
|
||||||
mflo(instr);
|
mflo(instr);
|
||||||
break;
|
break;
|
||||||
case MTLO:
|
case Instruction::MTLO:
|
||||||
mtlo(instr);
|
mtlo(instr);
|
||||||
break;
|
break;
|
||||||
case DSLLV:
|
case Instruction::DSLLV:
|
||||||
dsllv(instr);
|
dsllv(instr);
|
||||||
break;
|
break;
|
||||||
case DSRLV:
|
case Instruction::DSRLV:
|
||||||
dsrlv(instr);
|
dsrlv(instr);
|
||||||
break;
|
break;
|
||||||
case DSRAV:
|
case Instruction::DSRAV:
|
||||||
dsrav(instr);
|
dsrav(instr);
|
||||||
break;
|
break;
|
||||||
case MULT:
|
case Instruction::MULT:
|
||||||
mult(instr);
|
mult(instr);
|
||||||
break;
|
break;
|
||||||
case MULTU:
|
case Instruction::MULTU:
|
||||||
multu(instr);
|
multu(instr);
|
||||||
break;
|
break;
|
||||||
case DIV:
|
case Instruction::DIV:
|
||||||
div(instr);
|
div(instr);
|
||||||
break;
|
break;
|
||||||
case DIVU:
|
case Instruction::DIVU:
|
||||||
divu(instr);
|
divu(instr);
|
||||||
break;
|
break;
|
||||||
case DMULT:
|
case Instruction::DMULT:
|
||||||
dmult(instr);
|
dmult(instr);
|
||||||
break;
|
break;
|
||||||
case DMULTU:
|
case Instruction::DMULTU:
|
||||||
dmultu(instr);
|
dmultu(instr);
|
||||||
break;
|
break;
|
||||||
case DDIV:
|
case Instruction::DDIV:
|
||||||
ddiv(instr);
|
ddiv(instr);
|
||||||
break;
|
break;
|
||||||
case DDIVU:
|
case Instruction::DDIVU:
|
||||||
ddivu(instr);
|
ddivu(instr);
|
||||||
break;
|
break;
|
||||||
case ADD:
|
case Instruction::ADD:
|
||||||
add(instr);
|
add(instr);
|
||||||
break;
|
break;
|
||||||
case ADDU:
|
case Instruction::ADDU:
|
||||||
addu(instr);
|
addu(instr);
|
||||||
break;
|
break;
|
||||||
case SUB:
|
case Instruction::SUB:
|
||||||
sub(instr);
|
sub(instr);
|
||||||
break;
|
break;
|
||||||
case SUBU:
|
case Instruction::SUBU:
|
||||||
subu(instr);
|
subu(instr);
|
||||||
break;
|
break;
|
||||||
case AND:
|
case Instruction::AND:
|
||||||
and_(instr);
|
and_(instr);
|
||||||
break;
|
break;
|
||||||
case OR:
|
case Instruction::OR:
|
||||||
or_(instr);
|
or_(instr);
|
||||||
break;
|
break;
|
||||||
case XOR:
|
case Instruction::XOR:
|
||||||
xor_(instr);
|
xor_(instr);
|
||||||
break;
|
break;
|
||||||
case NOR:
|
case Instruction::NOR:
|
||||||
nor(instr);
|
nor(instr);
|
||||||
break;
|
break;
|
||||||
case SLT:
|
case Instruction::SLT:
|
||||||
slt(instr);
|
slt(instr);
|
||||||
break;
|
break;
|
||||||
case SLTU:
|
case Instruction::SLTU:
|
||||||
sltu(instr);
|
sltu(instr);
|
||||||
break;
|
break;
|
||||||
case DADD:
|
case Instruction::DADD:
|
||||||
dadd(instr);
|
dadd(instr);
|
||||||
break;
|
break;
|
||||||
case DADDU:
|
case Instruction::DADDU:
|
||||||
daddu(instr);
|
daddu(instr);
|
||||||
break;
|
break;
|
||||||
case DSUB:
|
case Instruction::DSUB:
|
||||||
dsub(instr);
|
dsub(instr);
|
||||||
break;
|
break;
|
||||||
case DSUBU:
|
case Instruction::DSUBU:
|
||||||
dsubu(instr);
|
dsubu(instr);
|
||||||
break;
|
break;
|
||||||
case TGE:
|
case Instruction::TGE:
|
||||||
trap(regs.Read<s64>(RS(instr)) >= regs.Read<s64>(RT(instr)));
|
trap(regs.Read<s64>(RS(instr)) >= regs.Read<s64>(RT(instr)));
|
||||||
break;
|
break;
|
||||||
case TGEU:
|
case Instruction::TGEU:
|
||||||
trap(regs.Read<u64>(RS(instr)) >= regs.Read<u64>(RT(instr)));
|
trap(regs.Read<u64>(RS(instr)) >= regs.Read<u64>(RT(instr)));
|
||||||
break;
|
break;
|
||||||
case TLT:
|
case Instruction::TLT:
|
||||||
trap(regs.Read<s64>(RS(instr)) < regs.Read<s64>(RT(instr)));
|
trap(regs.Read<s64>(RS(instr)) < regs.Read<s64>(RT(instr)));
|
||||||
break;
|
break;
|
||||||
case TLTU:
|
case Instruction::TLTU:
|
||||||
trap(regs.Read<u64>(RS(instr)) < regs.Read<u64>(RT(instr)));
|
trap(regs.Read<u64>(RS(instr)) < regs.Read<u64>(RT(instr)));
|
||||||
break;
|
break;
|
||||||
case TEQ:
|
case Instruction::TEQ:
|
||||||
trap(regs.Read<s64>(RS(instr)) == regs.Read<s64>(RT(instr)));
|
trap(regs.Read<s64>(RS(instr)) == regs.Read<s64>(RT(instr)));
|
||||||
break;
|
break;
|
||||||
case TNE:
|
case Instruction::TNE:
|
||||||
trap(regs.Read<s64>(RS(instr)) != regs.Read<s64>(RT(instr)));
|
trap(regs.Read<s64>(RS(instr)) != regs.Read<s64>(RT(instr)));
|
||||||
break;
|
break;
|
||||||
case DSLL:
|
case Instruction::DSLL:
|
||||||
dsll(instr);
|
dsll(instr);
|
||||||
break;
|
break;
|
||||||
case DSRL:
|
case Instruction::DSRL:
|
||||||
dsrl(instr);
|
dsrl(instr);
|
||||||
break;
|
break;
|
||||||
case DSRA:
|
case Instruction::DSRA:
|
||||||
dsra(instr);
|
dsra(instr);
|
||||||
break;
|
break;
|
||||||
case DSLL32:
|
case Instruction::DSLL32:
|
||||||
dsll32(instr);
|
dsll32(instr);
|
||||||
break;
|
break;
|
||||||
case DSRL32:
|
case Instruction::DSRL32:
|
||||||
dsrl32(instr);
|
dsrl32(instr);
|
||||||
break;
|
break;
|
||||||
case DSRA32:
|
case Instruction::DSRA32:
|
||||||
dsra32(instr);
|
dsra32(instr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unimplemented special {} {} ({:08X}) (pc: {:016X})", (mask >> 3) & 7, mask & 7, instr,
|
panic("Unimplemented special {} ({:08X}) (pc: {:016X})", instr.special(), u32(instr),
|
||||||
static_cast<u64>(regs.oldPC));
|
static_cast<u64>(regs.oldPC));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JIT::regimm(const u32 instr) {
|
void JIT::regimm(const Instruction instr) {
|
||||||
// 000r_rccc
|
// 000r_rccc
|
||||||
switch (const u8 mask = instr >> 16 & 0x1F) {
|
switch (instr.regimm()) {
|
||||||
case BLTZ:
|
case Instruction::BLTZ:
|
||||||
bltz(instr);
|
bltz(instr);
|
||||||
break;
|
break;
|
||||||
case BGEZ:
|
case Instruction::BGEZ:
|
||||||
bgez(instr);
|
bgez(instr);
|
||||||
break;
|
break;
|
||||||
case BLTZL:
|
case Instruction::BLTZL:
|
||||||
bltzl(instr);
|
bltzl(instr);
|
||||||
break;
|
break;
|
||||||
case BGEZL:
|
case Instruction::BGEZL:
|
||||||
bgezl(instr);
|
bgezl(instr);
|
||||||
break;
|
break;
|
||||||
case TGEI:
|
case Instruction::TGEI:
|
||||||
trap(regs.Read<s64>(RS(instr)) >= static_cast<s64>(static_cast<s16>(instr)));
|
trap(regs.Read<s64>(RS(instr)) >= static_cast<s64>(static_cast<s16>(instr)));
|
||||||
break;
|
break;
|
||||||
case TGEIU:
|
case Instruction::TGEIU:
|
||||||
trap(regs.Read<u64>(RS(instr)) >= static_cast<u64>(static_cast<s64>(static_cast<s16>(instr))));
|
trap(regs.Read<u64>(RS(instr)) >= static_cast<u64>(static_cast<s64>(static_cast<s16>(instr))));
|
||||||
break;
|
break;
|
||||||
case TLTI:
|
case Instruction::TLTI:
|
||||||
trap(regs.Read<s64>(RS(instr)) < static_cast<s64>(static_cast<s16>(instr)));
|
trap(regs.Read<s64>(RS(instr)) < static_cast<s64>(static_cast<s16>(instr)));
|
||||||
break;
|
break;
|
||||||
case TLTIU:
|
case Instruction::TLTIU:
|
||||||
trap(regs.Read<u64>(RS(instr)) < static_cast<u64>(static_cast<s64>(static_cast<s16>(instr))));
|
trap(regs.Read<u64>(RS(instr)) < static_cast<u64>(static_cast<s64>(static_cast<s16>(instr))));
|
||||||
break;
|
break;
|
||||||
case TEQI:
|
case Instruction::TEQI:
|
||||||
trap(regs.Read<s64>(RS(instr)) == static_cast<s64>(static_cast<s16>(instr)));
|
trap(regs.Read<s64>(RS(instr)) == static_cast<s64>(static_cast<s16>(instr)));
|
||||||
break;
|
break;
|
||||||
case TNEI:
|
case Instruction::TNEI:
|
||||||
trap(regs.Read<s64>(RS(instr)) != static_cast<s64>(static_cast<s16>(instr)));
|
trap(regs.Read<s64>(RS(instr)) != static_cast<s64>(static_cast<s16>(instr)));
|
||||||
break;
|
break;
|
||||||
case BLTZAL:
|
case Instruction::BLTZAL:
|
||||||
bltzal(instr);
|
bltzal(instr);
|
||||||
break;
|
break;
|
||||||
case BGEZAL:
|
case Instruction::BGEZAL:
|
||||||
bgezal(instr);
|
bgezal(instr);
|
||||||
break;
|
break;
|
||||||
case BLTZALL:
|
case Instruction::BLTZALL:
|
||||||
bltzall(instr);
|
bltzall(instr);
|
||||||
break;
|
break;
|
||||||
case BGEZALL:
|
case Instruction::BGEZALL:
|
||||||
bgezall(instr);
|
bgezall(instr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})", (mask >> 3) & 3, mask & 7, instr,
|
panic("Unimplemented regimm {} ({:08X}) (pc: {:016X})", instr.regimm(), u32(instr),
|
||||||
static_cast<u64>(regs.oldPC));
|
static_cast<u64>(regs.oldPC));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JIT::Emit(const u32 instr) {
|
void JIT::Emit(const Instruction instr) {
|
||||||
switch (const u8 mask = instr >> 26 & 0x3f) {
|
switch (instr.opcode()) {
|
||||||
case SPECIAL:
|
case Instruction::SPECIAL:
|
||||||
special(instr);
|
special(instr);
|
||||||
break;
|
break;
|
||||||
case REGIMM:
|
case Instruction::REGIMM:
|
||||||
regimm(instr);
|
regimm(instr);
|
||||||
break;
|
break;
|
||||||
case J:
|
case Instruction::J:
|
||||||
j(instr);
|
j(instr);
|
||||||
break;
|
break;
|
||||||
case JAL:
|
case Instruction::JAL:
|
||||||
jal(instr);
|
jal(instr);
|
||||||
break;
|
break;
|
||||||
case BEQ:
|
case Instruction::BEQ:
|
||||||
beq(instr);
|
beq(instr);
|
||||||
break;
|
break;
|
||||||
case BNE:
|
case Instruction::BNE:
|
||||||
bne(instr);
|
bne(instr);
|
||||||
break;
|
break;
|
||||||
case BLEZ:
|
case Instruction::BLEZ:
|
||||||
blez(instr);
|
blez(instr);
|
||||||
break;
|
break;
|
||||||
case BGTZ:
|
case Instruction::BGTZ:
|
||||||
bgtz(instr);
|
bgtz(instr);
|
||||||
break;
|
break;
|
||||||
case ADDI:
|
case Instruction::ADDI:
|
||||||
addi(instr);
|
addi(instr);
|
||||||
break;
|
break;
|
||||||
case ADDIU:
|
case Instruction::ADDIU:
|
||||||
addiu(instr);
|
addiu(instr);
|
||||||
break;
|
break;
|
||||||
case SLTI:
|
case Instruction::SLTI:
|
||||||
slti(instr);
|
slti(instr);
|
||||||
break;
|
break;
|
||||||
case SLTIU:
|
case Instruction::SLTIU:
|
||||||
sltiu(instr);
|
sltiu(instr);
|
||||||
break;
|
break;
|
||||||
case ANDI:
|
case Instruction::ANDI:
|
||||||
andi(instr);
|
andi(instr);
|
||||||
break;
|
break;
|
||||||
case ORI:
|
case Instruction::ORI:
|
||||||
ori(instr);
|
ori(instr);
|
||||||
break;
|
break;
|
||||||
case XORI:
|
case Instruction::XORI:
|
||||||
xori(instr);
|
xori(instr);
|
||||||
break;
|
break;
|
||||||
case LUI:
|
case Instruction::LUI:
|
||||||
lui(instr);
|
lui(instr);
|
||||||
break;
|
break;
|
||||||
case COP0:
|
case Instruction::COP0:
|
||||||
panic("[JIT]: Unimplemented Cop0 decode");
|
panic("[JIT]: Unimplemented Cop0 decode");
|
||||||
break;
|
break;
|
||||||
case COP1:
|
case Instruction::COP1:
|
||||||
{
|
{
|
||||||
const u8 mask_sub = (instr >> 21) & 0x1F;
|
if (instr.cop_rs() == 0x08) {
|
||||||
const u8 mask_branch = (instr >> 16) & 0x1F;
|
switch (instr.cop_rt()) {
|
||||||
if (mask_sub == 0x08) {
|
|
||||||
switch (mask_branch) {
|
|
||||||
case 0:
|
case 0:
|
||||||
// if (!regs.cop1.CheckFPUUsable())
|
// if (!regs.cop1.CheckFPUUsable())
|
||||||
// return;
|
// return;
|
||||||
@@ -299,121 +297,121 @@ void JIT::Emit(const u32 instr) {
|
|||||||
blfc1(instr);
|
blfc1(instr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Undefined BC COP1 {:02X}", mask_branch);
|
panic("Undefined BC COP1 {:02X}", instr.cop_rt());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
regs.cop1.decode(instr);
|
regs.cop1.decode(instr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case COP2:
|
case Instruction::COP2:
|
||||||
break;
|
break;
|
||||||
case BEQL:
|
case Instruction::BEQL:
|
||||||
beql(instr);
|
beql(instr);
|
||||||
break;
|
break;
|
||||||
case BNEL:
|
case Instruction::BNEL:
|
||||||
bnel(instr);
|
bnel(instr);
|
||||||
break;
|
break;
|
||||||
case BLEZL:
|
case Instruction::BLEZL:
|
||||||
blezl(instr);
|
blezl(instr);
|
||||||
break;
|
break;
|
||||||
case BGTZL:
|
case Instruction::BGTZL:
|
||||||
bgtzl(instr);
|
bgtzl(instr);
|
||||||
break;
|
break;
|
||||||
case DADDI:
|
case Instruction::DADDI:
|
||||||
daddi(instr);
|
daddi(instr);
|
||||||
break;
|
break;
|
||||||
case DADDIU:
|
case Instruction::DADDIU:
|
||||||
daddiu(instr);
|
daddiu(instr);
|
||||||
break;
|
break;
|
||||||
case LDL:
|
case Instruction::LDL:
|
||||||
ldl(instr);
|
ldl(instr);
|
||||||
break;
|
break;
|
||||||
case LDR:
|
case Instruction::LDR:
|
||||||
ldr(instr);
|
ldr(instr);
|
||||||
break;
|
break;
|
||||||
case 0x1F:
|
case 0x1F:
|
||||||
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
||||||
break;
|
break;
|
||||||
case LB:
|
case Instruction::LB:
|
||||||
lb(instr);
|
lb(instr);
|
||||||
break;
|
break;
|
||||||
case LH:
|
case Instruction::LH:
|
||||||
lh(instr);
|
lh(instr);
|
||||||
break;
|
break;
|
||||||
case LWL:
|
case Instruction::LWL:
|
||||||
lwl(instr);
|
lwl(instr);
|
||||||
break;
|
break;
|
||||||
case LW:
|
case Instruction::LW:
|
||||||
lw(instr);
|
lw(instr);
|
||||||
break;
|
break;
|
||||||
case LBU:
|
case Instruction::LBU:
|
||||||
lbu(instr);
|
lbu(instr);
|
||||||
break;
|
break;
|
||||||
case LHU:
|
case Instruction::LHU:
|
||||||
lhu(instr);
|
lhu(instr);
|
||||||
break;
|
break;
|
||||||
case LWR:
|
case Instruction::LWR:
|
||||||
lwr(instr);
|
lwr(instr);
|
||||||
break;
|
break;
|
||||||
case LWU:
|
case Instruction::LWU:
|
||||||
lwu(instr);
|
lwu(instr);
|
||||||
break;
|
break;
|
||||||
case SB:
|
case Instruction::SB:
|
||||||
sb(instr);
|
sb(instr);
|
||||||
break;
|
break;
|
||||||
case SH:
|
case Instruction::SH:
|
||||||
sh(instr);
|
sh(instr);
|
||||||
break;
|
break;
|
||||||
case SWL:
|
case Instruction::SWL:
|
||||||
swl(instr);
|
swl(instr);
|
||||||
break;
|
break;
|
||||||
case SW:
|
case Instruction::SW:
|
||||||
sw(instr);
|
sw(instr);
|
||||||
break;
|
break;
|
||||||
case SDL:
|
case Instruction::SDL:
|
||||||
sdl(instr);
|
sdl(instr);
|
||||||
break;
|
break;
|
||||||
case SDR:
|
case Instruction::SDR:
|
||||||
sdr(instr);
|
sdr(instr);
|
||||||
break;
|
break;
|
||||||
case SWR:
|
case Instruction::SWR:
|
||||||
swr(instr);
|
swr(instr);
|
||||||
break;
|
break;
|
||||||
case CACHE:
|
case Instruction::CACHE:
|
||||||
break; // CACHE
|
break; // CACHE
|
||||||
case LL:
|
case Instruction::LL:
|
||||||
ll(instr);
|
ll(instr);
|
||||||
break;
|
break;
|
||||||
case LWC1:
|
case Instruction::LWC1:
|
||||||
lwc1(instr);
|
lwc1(instr);
|
||||||
break;
|
break;
|
||||||
case LLD:
|
case Instruction::LLD:
|
||||||
lld(instr);
|
lld(instr);
|
||||||
break;
|
break;
|
||||||
case LDC1:
|
case Instruction::LDC1:
|
||||||
ldc1(instr);
|
ldc1(instr);
|
||||||
break;
|
break;
|
||||||
case LD:
|
case Instruction::LD:
|
||||||
ld(instr);
|
ld(instr);
|
||||||
break;
|
break;
|
||||||
case SC:
|
case Instruction::SC:
|
||||||
sc(instr);
|
sc(instr);
|
||||||
break;
|
break;
|
||||||
case SWC1:
|
case Instruction::SWC1:
|
||||||
swc1(instr);
|
swc1(instr);
|
||||||
break;
|
break;
|
||||||
case SCD:
|
case Instruction::SCD:
|
||||||
scd(instr);
|
scd(instr);
|
||||||
break;
|
break;
|
||||||
case SDC1:
|
case Instruction::SDC1:
|
||||||
sdc1(instr);
|
sdc1(instr);
|
||||||
break;
|
break;
|
||||||
case SD:
|
case Instruction::SD:
|
||||||
sd(instr);
|
sd(instr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})", mask, instr, static_cast<u64>(regs.oldPC));
|
panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})", instr.opcode(), u32(instr), static_cast<u64>(regs.oldPC));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -1,65 +1,63 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <CpuDefinitions.hpp>
|
#include <Instruction.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
static bool SpecialEndsBlock(const u32 instr) {
|
static bool SpecialEndsBlock(const Instruction instr) {
|
||||||
switch (instr & 0x3F) {
|
switch (instr.special()) {
|
||||||
case JR:
|
case Instruction::JR:
|
||||||
case JALR:
|
case Instruction::JALR:
|
||||||
case SYSCALL:
|
case Instruction::SYSCALL:
|
||||||
case BREAK:
|
case Instruction::BREAK:
|
||||||
case TGE:
|
case Instruction::TGE:
|
||||||
case TGEU:
|
case Instruction::TGEU:
|
||||||
case TLT:
|
case Instruction::TLT:
|
||||||
case TLTU:
|
case Instruction::TLTU:
|
||||||
case TEQ:
|
case Instruction::TEQ:
|
||||||
case TNE:
|
case Instruction::TNE:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool InstrEndsBlock(const u32 instr) {
|
static bool InstrEndsBlock(const Instruction instr) {
|
||||||
switch (instr >> 26 & 0x3f) {
|
switch (instr.opcode()) {
|
||||||
case SPECIAL:
|
case Instruction::SPECIAL:
|
||||||
return SpecialEndsBlock(instr);
|
return SpecialEndsBlock(instr);
|
||||||
case REGIMM:
|
case Instruction::REGIMM:
|
||||||
case J:
|
case Instruction::J:
|
||||||
case JAL:
|
case Instruction::JAL:
|
||||||
case BEQ:
|
case Instruction::BEQ:
|
||||||
case BNE:
|
case Instruction::BNE:
|
||||||
case BLEZ:
|
case Instruction::BLEZ:
|
||||||
case BGTZ:
|
case Instruction::BGTZ:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsBranchLikely(const u32 instr) {
|
static bool IsBranchLikely(const Instruction instr) {
|
||||||
switch (instr >> 26 & 0x3F) {
|
switch (instr.opcode()) {
|
||||||
case BEQL:
|
case Instruction::BEQL:
|
||||||
case BNEL:
|
case Instruction::BNEL:
|
||||||
case BLEZL:
|
case Instruction::BLEZL:
|
||||||
case BGTZL:
|
case Instruction::BGTZL:
|
||||||
return true;
|
return true;
|
||||||
case REGIMM:
|
case Instruction::REGIMM:
|
||||||
switch (instr >> 16 & 0x1f) {
|
switch (instr.regimm()) {
|
||||||
case BLTZL:
|
case Instruction::BLTZL:
|
||||||
case BGEZL:
|
case Instruction::BGEZL:
|
||||||
case BLTZALL:
|
case Instruction::BLTZALL:
|
||||||
case BGEZALL:
|
case Instruction::BGEZALL:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
case COP1:
|
case Instruction::COP1:
|
||||||
{
|
{
|
||||||
const u8 mask_sub = (instr >> 21) & 0x1F;
|
if (instr.cop_rs() == 0x08) {
|
||||||
const u8 mask_branch = (instr >> 16) & 0x1F;
|
if (instr.cop_rt() == 2 || instr.cop_rt() == 3)
|
||||||
if (mask_sub == 0x08) {
|
|
||||||
if (mask_branch == 2 || mask_branch == 3)
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -489,7 +489,7 @@ void Cop0::decode(const Instruction instr) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("Unimplemented COP0 instruction {} {}", mask_cop >> 4, mask_cop & 7);
|
panic("Unimplemented COP0 instruction {}", instr.cop_rs());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -271,10 +271,10 @@ private:
|
|||||||
[[nodiscard]] FORCE_INLINE u32 GetWired() const { return wired & 0x3F; }
|
[[nodiscard]] FORCE_INLINE u32 GetWired() const { return wired & 0x3F; }
|
||||||
[[nodiscard]] FORCE_INLINE u32 GetCount() const { return u32(u64(count >> 1)); }
|
[[nodiscard]] FORCE_INLINE u32 GetCount() const { return u32(u64(count >> 1)); }
|
||||||
|
|
||||||
void mtc0(u32);
|
void mtc0(const Instruction);
|
||||||
void dmtc0(u32);
|
void dmtc0(const Instruction);
|
||||||
void mfc0(u32);
|
void mfc0(const Instruction);
|
||||||
void dmfc0(u32) const;
|
void dmfc0(const Instruction) const;
|
||||||
void eret();
|
void eret();
|
||||||
|
|
||||||
void tlbr();
|
void tlbr();
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ void Cop1::Reset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::decode(const Instruction instr) {
|
void Cop1::decode(const Instruction instr) {
|
||||||
auto cpu = Core::GetInstance().cpuType == Core::Interpreted ? Core::GetInterpreter() : Core::GetDynamicRecompiler();
|
|
||||||
switch (instr.cop_rs()) {
|
switch (instr.cop_rs()) {
|
||||||
// 000r_rccc
|
// 000r_rccc
|
||||||
case 0x00:
|
case 0x00:
|
||||||
@@ -38,32 +37,6 @@ void Cop1::decode(const Instruction instr) {
|
|||||||
case 0x07:
|
case 0x07:
|
||||||
unimplemented();
|
unimplemented();
|
||||||
break;
|
break;
|
||||||
case 0x08:
|
|
||||||
switch (instr.cop_rt()) {
|
|
||||||
case 0:
|
|
||||||
if (!regs.cop1.CheckFPUUsable())
|
|
||||||
return;
|
|
||||||
cpu.b(instr, !regs.cop1.fcr31.compare);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
if (!regs.cop1.CheckFPUUsable())
|
|
||||||
return;
|
|
||||||
cpu.b(instr, regs.cop1.fcr31.compare);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (!regs.cop1.CheckFPUUsable())
|
|
||||||
return;
|
|
||||||
cpu.bl(instr, !regs.cop1.fcr31.compare);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
if (!regs.cop1.CheckFPUUsable())
|
|
||||||
return;
|
|
||||||
cpu.bl(instr, regs.cop1.fcr31.compare);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
panic("Undefined BC COP1 {:02X}", instr.cop_rt());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x10: // s
|
case 0x10: // s
|
||||||
switch (instr.cop_funct()) {
|
switch (instr.cop_funct()) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
|
|||||||
@@ -230,10 +230,10 @@ private:
|
|||||||
void negd(const Instruction instr);
|
void negd(const Instruction instr);
|
||||||
void sqrts(const Instruction instr);
|
void sqrts(const Instruction instr);
|
||||||
void sqrtd(const Instruction instr);
|
void sqrtd(const Instruction instr);
|
||||||
void lwc1(u32);
|
void lwc1(const Instruction instr);
|
||||||
void swc1(u32);
|
void swc1(const Instruction instr);
|
||||||
void ldc1(u32);
|
void ldc1(const Instruction instr);
|
||||||
void sdc1(u32);
|
void sdc1(const Instruction instr);
|
||||||
|
|
||||||
void mfc1(const Instruction instr);
|
void mfc1(const Instruction instr);
|
||||||
void dmfc1(const Instruction instr);
|
void dmfc1(const Instruction instr);
|
||||||
|
|||||||
@@ -6,14 +6,21 @@ namespace n64 {
|
|||||||
struct Instruction {
|
struct Instruction {
|
||||||
Instruction(u32 v) { instr.raw = v; }
|
Instruction(u32 v) { instr.raw = v; }
|
||||||
void operator=(u32 v) { instr.raw = v; }
|
void operator=(u32 v) { instr.raw = v; }
|
||||||
auto operator u32() { return instr.raw; }
|
operator u32() const { return instr.raw; }
|
||||||
|
|
||||||
inline u8 rs() const { return instr.rtype.rs; }
|
inline u8 rs() const { return instr.rtype.rs; }
|
||||||
inline u8 rt() const { return instr.rtype.rt; }
|
inline u8 rt() const { return instr.rtype.rt; }
|
||||||
inline u8 rd() const { return instr.rtype.rd; }
|
inline u8 rd() const { return instr.rtype.rd; }
|
||||||
inline u8 sa() const { return instr.rtype.sa; }
|
inline u8 sa() const { return instr.rtype.sa; }
|
||||||
|
inline u8 fs() const { return rd(); }
|
||||||
|
inline u8 ft() const { return rt(); }
|
||||||
|
inline u8 fd() const { return sa(); }
|
||||||
|
inline u8 base() const { return rs(); }
|
||||||
inline u16 imm() const { return instr.itype.imm; }
|
inline u16 imm() const { return instr.itype.imm; }
|
||||||
inline u32 target() const { return instr.jtype.target; }
|
inline u32 target() const { return instr.jtype.target; }
|
||||||
|
inline u8 opcode() const { return instr.opcode.op; }
|
||||||
|
inline u8 special() const { return instr.opcode.special; }
|
||||||
|
inline u8 regimm() const { return instr.opcode.regimm; }
|
||||||
inline u8 cop_rs() const { return instr.opcode.cop_rs; }
|
inline u8 cop_rs() const { return instr.opcode.cop_rs; }
|
||||||
inline u8 cop_rt() const { return instr.opcode.cop_rt; }
|
inline u8 cop_rt() const { return instr.opcode.cop_rt; }
|
||||||
inline u8 cop_funct() const { return instr.opcode.funct; }
|
inline u8 cop_funct() const { return instr.opcode.funct; }
|
||||||
@@ -76,6 +83,8 @@ struct Instruction {
|
|||||||
unsigned cop_rs:5;
|
unsigned cop_rs:5;
|
||||||
unsigned:6;
|
unsigned:6;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
u32 raw;
|
||||||
} opcode;
|
} opcode;
|
||||||
|
|
||||||
u32 raw;
|
u32 raw;
|
||||||
|
|||||||
Reference in New Issue
Block a user