This rewrite is working (tested with Super Mario 64)

This commit is contained in:
irisz64
2025-08-29 10:57:01 +02:00
parent dd98e19c95
commit b8d691efb8
15 changed files with 1240 additions and 1255 deletions

View File

@@ -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();

View File

@@ -1,6 +0,0 @@
#pragma once
#include <common.hpp>
namespace n64 {
} // namespace n64

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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());
} }
} }

View File

@@ -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();

View File

@@ -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:

View File

@@ -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);

View File

@@ -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;