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