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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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