JIT: Passing first 2 tests in basic_simpleboot

This commit is contained in:
SimoneN64
2023-03-20 23:37:54 +01:00
parent 0f2a999f00
commit 94ce40429f
15 changed files with 319 additions and 289 deletions

View File

@@ -2,7 +2,6 @@
#include <filesystem>
#include <JIT.hpp>
namespace n64 {
namespace fs = std::filesystem;
@@ -25,6 +24,7 @@ JIT::JIT() : code(CODECACHE_SIZE, codeCache) {
dump.open("jit.dump", std::ios::ate | std::ios::binary);
dump.unsetf(std::ios::skipws);
regs.Reset();
}
inline bool ShouldServiceInterrupt(Registers& regs) {
@@ -64,23 +64,21 @@ void JIT::Recompile(Mem& mem, u32 pc) {
instrInBlock++;
prevBranch = branch;
u32 instr = mem.Read32(regs, loopPC);
loopPC += 4;
emitBreakpoint();
code.mov(rdi, (uintptr_t)this);
code.mov(rsi, instr);
code.mov(r8, qword[rdi + REG_OFFSET(oldPC)]);
code.mov(r9, qword[rdi + REG_OFFSET(pc)]);
code.mov(r10, qword[rdi + REG_OFFSET(nextPC)]);
code.mov(qword[rdi + GPR_OFFSET(0, this)], 0);
code.mov(r8, qword[rdi + REG_OFFSET(oldPC, this)]);
code.mov(r9, qword[rdi + REG_OFFSET(pc, this)]);
code.mov(r10, qword[rdi + REG_OFFSET(nextPC, this)]);
code.mov(r8, r9);
code.mov(r9, r10);
code.add(r10, 4);
code.mov(qword[rdi + REG_OFFSET(oldPC)], r8);
code.mov(qword[rdi + REG_OFFSET(pc)], r9);
code.mov(qword[rdi + REG_OFFSET(nextPC)], r10);
loopPC += 4;
code.mov(qword[rdi + REG_OFFSET(oldPC, this)], r8);
code.mov(qword[rdi + REG_OFFSET(pc, this)], r9);
code.mov( qword[rdi + REG_OFFSET(nextPC, this)], r10);
code.mov(esi, instr);
branch = Exec(mem, instr);
}
@@ -89,7 +87,6 @@ void JIT::Recompile(Mem& mem, u32 pc) {
dump.write(code.getCode<char*>(), code.getSize());
blockCache[startPC >> 20][startPC & 0xFFF] = block;
blockCache[startPC >> 20][startPC & 0xFFF]();
}
void JIT::AllocateOuter(u32 pc) {
@@ -98,7 +95,6 @@ void JIT::AllocateOuter(u32 pc) {
int JIT::Run() {
instrInBlock = 0;
regs.gpr[0] = 0;
regs.prevDelaySlot = regs.delaySlot;
regs.delaySlot = false;
@@ -110,23 +106,22 @@ int JIT::Run() {
return 0;
}
if(blockCache[pc >> 20]) {
if(blockCache[pc >> 20][pc & 0xfff]) {
blockCache[pc >> 20][pc & 0xfff]();
} else {
Recompile(mem, pc);
}
} else {
if(!blockCache[pc >> 20]) {
AllocateOuter(pc);
}
if(!blockCache[pc >> 20][pc & 0xfff]) {
Recompile(mem, pc);
}
CheckCompareInterrupt(mem.mmio.mi, regs);
if(ShouldServiceInterrupt(regs)) {
FireException(regs, ExceptionCode::Interrupt, 0, false);
return 0;
}
blockCache[pc >> 20][pc & 0xfff]();
return instrInBlock;
}

View File

@@ -9,8 +9,8 @@ using namespace Xbyak;
using namespace Xbyak::util;
using Fn = void (*)();
#define GPR_OFFSET(x) ((uintptr_t)&regs.gpr[(x)] - (uintptr_t)&regs)
#define REG_OFFSET(kind) ((uintptr_t)&regs.kind - (uintptr_t)&regs)
#define GPR_OFFSET(x, jit) ((uintptr_t)&regs.gpr[(x)] - (uintptr_t)jit)
#define REG_OFFSET(kind, jit) ((uintptr_t)&regs.kind - (uintptr_t)jit)
#define CODECACHE_SIZE (2 << 25)
#define CODECACHE_OVERHEAD (CODECACHE_SIZE - 1_kb)
@@ -28,17 +28,9 @@ private:
Fn* blockCache[0x80000]{};
u8* codeCache;
int instrInBlock = 0;
bool enableBreakpoints = false;
u64 sizeUsed = 0;
std::ofstream dump;
inline void emitBreakpoint() {
#ifndef NDEBUG
if(enableBreakpoints)
code.int3();
#endif
}
void* bumpAlloc(u64 size, u8 val = 0);
void Recompile(Mem&, u32 pc);
void AllocateOuter(u32 pc);

View File

@@ -130,7 +130,7 @@ void Interpreter::Exec(u32 instr) {
case 0x0D: ori(instr); break;
case 0x0E: xori(instr); break;
case 0x0F: lui(instr); break;
case 0x10: regs.cop0.decode(regs, mem, instr); break;
case 0x10: regs.cop0.decode(regs, instr); break;
case 0x11: regs.cop1.decode(regs, *this, instr); break;
case 0x12: cop2Decode(instr); break;
case 0x14: bl(instr, regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); break;

View File

@@ -7,8 +7,8 @@ void JIT::InvalidatePage(u32 paddr) {
void JIT::InvalidateCache() {
sizeUsed = 0;
for(int i = 0; i < 0x80000; i++) {
blockCache[i] = nullptr;
for(auto &i : blockCache) {
i = nullptr;
}
}

View File

@@ -3,10 +3,11 @@
#include <Registers.hpp>
namespace n64 {
void cop0Decode(Registers& regs, JIT& cpu, u32 instr) {
void cop0Decode(JIT& cpu, u32 instr) {
u8 mask_cop = (instr >> 21) & 0x1F;
u8 mask_cop2 = instr & 0x3F;
Xbyak::CodeGenerator& code = cpu.code;
Registers& regs = cpu.regs;
switch(mask_cop) {
case 0x00:
@@ -32,7 +33,7 @@ void cop0Decode(Registers& regs, JIT& cpu, u32 instr) {
code.call(code.rax);
break;
case 0x02:
code.mov(code.rcx, code.dword[code.rdi + offsetof(Registers, cop0.index)]);
code.mov(code.rcx, code.dword[code.rdi + REG_OFFSET(cop0.index, &cpu)]);
code.and_(code.rcx, 0x3F);
code.mov(code.rsi, code.rcx);
code.mov(code.rax, (u64)tlbw);

View File

@@ -3,5 +3,5 @@
namespace n64 {
struct Registers;
void cop0Decode(Registers&, JIT& cpu, u32 instr);
void cop0Decode(JIT& cpu, u32 instr);
}

View File

@@ -3,8 +3,9 @@
#include <Registers.hpp>
namespace n64 {
bool cop1Decode(Registers& regs, JIT& cpu, u32 instr) {
bool cop1Decode(JIT& cpu, u32 instr) {
Xbyak::CodeGenerator& code = cpu.code;
Registers& regs = cpu.regs;
u8 mask_sub = (instr >> 21) & 0x1F;
u8 mask_fun = instr & 0x3F;

View File

@@ -2,5 +2,5 @@
#include <jit/cop/cop1instructions.hpp>
namespace n64 {
bool cop1Decode(Registers&, JIT& cpu, u32 instr);
bool cop1Decode(JIT& cpu, u32 instr);
}

View File

@@ -29,91 +29,93 @@ inline int PushRoundingMode(const FCR31& fcr31) {
} \
} while(0)
void absd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
auto fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
void absd(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), std::abs(fs));
}
void abss(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
auto fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
void abss(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), std::abs(fs));
}
void absw(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void absw(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
s32 fs = regs.cop1.GetReg<s32>(regs.cop0, FS(instr));
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), std::abs(fs));
}
void absl(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void absl(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
s64 fs = regs.cop1.GetReg<s64>(regs.cop0, FS(instr));
regs.cop1.SetReg(regs.cop0, FD(instr), std::abs(fs));
}
void adds(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
auto fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
auto ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr));
void adds(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
float ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr));
checknanregs(fs, ft);
float result = fs + ft;
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), result);
}
void addd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
auto fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
auto ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr));
void addd(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
double ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr));
checknanregs(fs, ft);
double result = fs + ft;
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), result);
}
void ceills(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
auto fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
void ceills(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
s64 result = std::ceil(fs);
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result);
}
void ceilws(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
auto fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
void ceilws(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
s32 result = std::ceil(fs);
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result);
}
void ceilld(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
auto fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
void ceilld(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
s64 result = std::ceil(fs);
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result);
}
void ceilwd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
auto fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
void ceilwd(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
s32 result = std::ceil(fs);
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result);
}
void cfc1(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void cfc1(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
u8 fd = RD(instr);
s32 val = 0;
switch(fd) {
case 0: val = regs.cop1.fcr0; break;
case 31: val = regs.cop1.fcr31.raw; break;
case 31:
val = regs.cop1.fcr31.raw;
break;
default: Util::panic("Undefined CFC1 with rd != 0 or 31\n");
}
regs.gpr[RT(instr)] = val;
}
void ctc1(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
u8 fs = FS(instr);
void ctc1(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
u8 fs = RD(instr);
u32 val = regs.gpr[RT(instr)];
switch(fs) {
case 0: break;
@@ -125,8 +127,8 @@ void ctc1(JIT& cpu, u32 instr) {
}
}
void cvtds(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void cvtds(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.cop1.SetCop1Reg<double>(
regs.cop0,
FD(instr),
@@ -137,8 +139,8 @@ void cvtds(JIT& cpu, u32 instr) {
);
}
void cvtsd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void cvtsd(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.cop1.SetCop1Reg<float>(
regs.cop0,
FD(instr),
@@ -149,8 +151,8 @@ void cvtsd(JIT& cpu, u32 instr) {
);
}
void cvtwd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void cvtwd(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.cop1.SetReg<u32>(
regs.cop0,
FD(instr),
@@ -161,8 +163,8 @@ void cvtwd(JIT& cpu, u32 instr) {
);
}
void cvtws(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void cvtws(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.cop1.SetReg<u32>(
regs.cop0,
FD(instr),
@@ -173,8 +175,8 @@ void cvtws(JIT& cpu, u32 instr) {
);
}
void cvtls(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void cvtls(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.cop1.SetReg<u64>(
regs.cop0,
FD(instr),
@@ -185,8 +187,8 @@ void cvtls(JIT& cpu, u32 instr) {
);
}
void cvtsl(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void cvtsl(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.cop1.SetCop1Reg<float>(
regs.cop0,
FD(instr),
@@ -197,8 +199,8 @@ void cvtsl(JIT& cpu, u32 instr) {
);
}
void cvtdw(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void cvtdw(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.cop1.SetCop1Reg<double>(
regs.cop0,
FD(instr),
@@ -209,8 +211,8 @@ void cvtdw(JIT& cpu, u32 instr) {
);
}
void cvtsw(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void cvtsw(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.cop1.SetCop1Reg<float>(
regs.cop0,
FD(instr),
@@ -221,8 +223,8 @@ void cvtsw(JIT& cpu, u32 instr) {
);
}
void cvtdl(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void cvtdl(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.cop1.SetCop1Reg<double>(
regs.cop0,
FD(instr),
@@ -233,8 +235,8 @@ void cvtdl(JIT& cpu, u32 instr) {
);
}
void cvtld(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void cvtld(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.cop1.SetReg<u64>(
regs.cop0,
FD(instr),
@@ -246,8 +248,7 @@ void cvtld(JIT& cpu, u32 instr) {
}
template <typename T>
inline bool CalculateCondition(JIT& cpu, T fs, T ft, CompConds cond) {
Registers& regs = cpu.regs;
inline bool CalculateCondition(Registers& regs, T fs, T ft, CompConds cond) {
switch(cond) {
case F: return false;
case UN: return std::isnan(fs) || std::isnan(ft);
@@ -265,94 +266,94 @@ inline bool CalculateCondition(JIT& cpu, T fs, T ft, CompConds cond) {
return false;
}
return CalculateCondition(cpu, fs, ft, static_cast<CompConds>(cond - 8));
return CalculateCondition(regs, fs, ft, static_cast<CompConds>(cond - 8));
}
}
template <typename T>
void ccond(JIT& cpu, u32 instr, CompConds cond) {
Registers& regs = cpu.regs;
void ccond(JIT& dyn, u32 instr, CompConds cond) {
Registers& regs = dyn.regs;
T fs = regs.cop1.GetCop1Reg<T>(regs.cop0, FS(instr));
T ft = regs.cop1.GetCop1Reg<T>(regs.cop0, FT(instr));
regs.cop1.fcr31.compare = CalculateCondition(cpu, fs, ft, cond);
regs.cop1.fcr31.compare = CalculateCondition(regs, fs, ft, cond);
}
template void ccond<float>(JIT& cpu, u32 instr, CompConds cond);
template void ccond<double>(JIT& cpu, u32 instr, CompConds cond);
template void ccond<float>(JIT& dyn, u32 instr, CompConds cond);
template void ccond<double>(JIT& dyn, u32 instr, CompConds cond);
void divs(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void divs(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
float ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr));
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), fs / ft);
}
void divd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void divd(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
double ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr));
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), fs / ft);
}
void muls(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void muls(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
float ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr));
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), fs * ft);
}
void muld(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void muld(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
double ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr));
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), fs * ft);
}
void mulw(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void mulw(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
u32 fs = regs.cop1.GetReg<u32>(regs.cop0, FS(instr));
u32 ft = regs.cop1.GetReg<u32>(regs.cop0, FT(instr));
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), fs * ft);
}
void mull(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void mull(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
u64 fs = regs.cop1.GetReg<u64>(regs.cop0, FS(instr));
u64 ft = regs.cop1.GetReg<u64>(regs.cop0, FT(instr));
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), fs * ft);
}
void subs(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void subs(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
float ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr));
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), fs - ft);
}
void subd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void subd(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
double ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr));
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), fs - ft);
}
void subw(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void subw(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
u32 fs = regs.cop1.GetReg<u32>(regs.cop0, FS(instr));
u32 ft = regs.cop1.GetReg<u32>(regs.cop0, FT(instr));
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), fs - ft);
}
void subl(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void subl(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
u64 fs = regs.cop1.GetReg<u64>(regs.cop0, FS(instr));
u64 ft = regs.cop1.GetReg<u64>(regs.cop0, FT(instr));
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), fs - ft);
}
void movs(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void movs(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.cop1.SetCop1Reg<float>(
regs.cop0,
FD(instr),
@@ -363,8 +364,8 @@ void movs(JIT& cpu, u32 instr) {
);
}
void movd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void movd(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.cop1.SetCop1Reg<double>(
regs.cop0,
FD(instr),
@@ -375,8 +376,8 @@ void movd(JIT& cpu, u32 instr) {
);
}
void movw(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void movw(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.cop1.SetReg<u32>(
regs.cop0,
FD(instr),
@@ -387,8 +388,8 @@ void movw(JIT& cpu, u32 instr) {
);
}
void movl(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void movl(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.cop1.SetReg<u64>(
regs.cop0,
FD(instr),
@@ -399,8 +400,8 @@ void movl(JIT& cpu, u32 instr) {
);
}
void negs(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void negs(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.cop1.SetCop1Reg<float>(
regs.cop0,
FD(instr),
@@ -411,8 +412,8 @@ void negs(JIT& cpu, u32 instr) {
);
}
void negd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void negd(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.cop1.SetCop1Reg<double>(
regs.cop0,
FD(instr),
@@ -423,77 +424,76 @@ void negd(JIT& cpu, u32 instr) {
);
}
void sqrts(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void sqrts(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), std::sqrt(fs));
}
void sqrtd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void sqrtd(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), std::sqrt(fs));
}
void roundls(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void roundls(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
PUSHROUNDINGMODE;
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s32)std::nearbyint(fs));
POPROUNDINGMODE;
}
void roundld(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void roundld(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
PUSHROUNDINGMODE;
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s64)std::nearbyint(fs));
POPROUNDINGMODE;
}
void roundws(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void roundws(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
PUSHROUNDINGMODE;
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s32)std::nearbyint(fs));
POPROUNDINGMODE;
}
void roundwd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void roundwd(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
PUSHROUNDINGMODE;
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s32)std::nearbyint(fs));
POPROUNDINGMODE;
}
void floorls(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void floorls(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s64)std::floor(fs));
}
void floorld(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void floorld(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s64)std::floor(fs));
}
void floorws(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void floorws(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s64)std::floor(fs));
}
void floorwd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void floorwd(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s64)std::floor(fs));
}
void lwc1(JIT& cpu, u32 instr) {
Mem& mem = cpu.mem;
Registers& regs = cpu.regs;
void lwc1(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
return;
@@ -506,14 +506,13 @@ void lwc1(JIT& cpu, u32 instr) {
HandleTLBException(regs, addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else {
u32 data = mem.Read32(regs, physical);
u32 data = dyn.mem.Read32(regs, physical);
regs.cop1.SetReg<u32>(regs.cop0, FT(instr), data);
}
}
void swc1(JIT& cpu, u32 instr) {
Mem& mem = cpu.mem;
Registers& regs = cpu.regs;
void swc1(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
return;
@@ -526,13 +525,12 @@ void swc1(JIT& cpu, u32 instr) {
HandleTLBException(regs, addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else {
mem.Write32(regs, physical, regs.cop1.GetReg<u32>(regs.cop0, FT(instr)));
dyn.mem.Write32(regs, physical, regs.cop1.GetReg<u32>(regs.cop0, FT(instr)));
}
}
void ldc1(JIT& cpu, u32 instr) {
Mem& mem = cpu.mem;
Registers& regs = cpu.regs;
void ldc1(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
return;
@@ -545,14 +543,13 @@ void ldc1(JIT& cpu, u32 instr) {
HandleTLBException(regs, addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else {
u64 data = mem.Read64(regs, physical);
u64 data = dyn.mem.Read64(regs, physical);
regs.cop1.SetReg<u64>(regs.cop0, FT(instr), data);
}
}
void sdc1(JIT& cpu, u32 instr) {
Mem& mem = cpu.mem;
Registers& regs = cpu.regs;
void sdc1(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
return;
@@ -565,55 +562,56 @@ void sdc1(JIT& cpu, u32 instr) {
HandleTLBException(regs, addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else {
mem.Write64(regs, physical, regs.cop1.GetReg<u64>(regs.cop0, FT(instr)));
dyn.mem.Write64(regs, physical, regs.cop1.GetReg<u64>(regs.cop0, FT(instr)));
}
}
void truncws(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void truncws(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
s32 result = (s32)std::trunc(fs);
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result);
}
void truncwd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void truncwd(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
s32 result = (s32)std::trunc(fs);
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result);
}
void truncls(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void truncls(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
s64 result = (s64)std::trunc(fs);
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result);
}
void truncld(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void truncld(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
s64 result = (s64)std::trunc(fs);
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result);
}
void mfc1(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void mfc1(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.gpr[RT(instr)] = (s32)regs.cop1.GetReg<u32>(regs.cop0, FS(instr));
}
void dmfc1(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void dmfc1(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.gpr[RT(instr)] = (s64)regs.cop1.GetReg<u64>(regs.cop0, FS(instr));
}
void mtc1(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void mtc1(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.cop1.SetReg<u32>(regs.cop0, FS(instr), regs.gpr[RT(instr)]);
}
void dmtc1(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
void dmtc1(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.cop1.SetReg<u64>(regs.cop0, FS(instr), regs.gpr[RT(instr)]);
}
}

View File

@@ -190,8 +190,8 @@ bool JIT::special(u32 instr) {
code.call(rax);
break;
case 0x30:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
code.xor_(rsi, rsi);
code.cmp(r8, rcx);
code.setge(sil);
@@ -200,8 +200,8 @@ bool JIT::special(u32 instr) {
res = true;
break;
case 0x31:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
code.xor_(rsi, rsi);
code.cmp(r8, rcx);
code.setae(sil);
@@ -210,8 +210,8 @@ bool JIT::special(u32 instr) {
res = true;
break;
case 0x32:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
code.xor_(rsi, rsi);
code.cmp(r8, rcx);
code.setl(sil);
@@ -220,8 +220,8 @@ bool JIT::special(u32 instr) {
res = true;
break;
case 0x33:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
code.xor_(rsi, rsi);
code.cmp(r8, rcx);
code.setb(sil);
@@ -230,8 +230,8 @@ bool JIT::special(u32 instr) {
res = true;
break;
case 0x34:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
code.xor_(rsi, rsi);
code.cmp(r8, rcx);
code.sete(sil);
@@ -240,8 +240,8 @@ bool JIT::special(u32 instr) {
res = true;
break;
case 0x36:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
code.xor_(rsi, rsi);
code.cmp(r8, rcx);
code.setne(sil);
@@ -285,7 +285,7 @@ bool JIT::regimm(u32 instr) {
// 000r_rccc
switch (mask) { // TODO: named constants for clearer code
case 0x00:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.xor_(rdx, rdx);
code.cmp(r8, 0);
code.setl(dl);
@@ -293,7 +293,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax);
break;
case 0x01:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.xor_(rdx, rdx);
code.cmp(r8, 0);
code.setge(dl);
@@ -301,7 +301,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax);
break;
case 0x02:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.xor_(rdx, rdx);
code.cmp(r8, 0);
code.setl(dl);
@@ -309,7 +309,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax);
break;
case 0x03:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.xor_(rdx, rdx);
code.cmp(r8, 0);
code.setge(dl);
@@ -317,7 +317,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax);
break;
case 0x08:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.xor_(rsi, rsi);
code.cmp(r8, s64(s16(instr)));
code.setge(sil);
@@ -325,7 +325,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax);
break;
case 0x09:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.xor_(rsi, rsi);
code.cmp(r8, u64(s64(s16(instr))));
code.setae(sil);
@@ -333,7 +333,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax);
break;
case 0x0A:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.xor_(rsi, rsi);
code.cmp(r8, s64(s16(instr)));
code.setl(sil);
@@ -341,7 +341,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax);
break;
case 0x0B:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.xor_(rsi, rsi);
code.cmp(r8, u64(s64(s16(instr))));
code.setb(sil);
@@ -349,7 +349,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax);
break;
case 0x0C:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.xor_(rsi, rsi);
code.cmp(r8, s64(s16(instr)));
code.sete(sil);
@@ -357,7 +357,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax);
break;
case 0x0E:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.xor_(rsi, rsi);
code.cmp(r8, s64(s16(instr)));
code.setne(sil);
@@ -365,7 +365,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax);
break;
case 0x10:
code.mov(rcx, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.xor_(rdx, rdx);
code.cmp(rcx, 0);
code.setl(dl);
@@ -373,7 +373,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax);
break;
case 0x11:
code.mov(rcx, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.xor_(rdx, rdx);
code.cmp(rcx, 0);
code.setge(dl);
@@ -381,7 +381,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax);
break;
case 0x12:
code.mov(rcx, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.xor_(rdx, rdx);
code.cmp(rcx, 0);
code.setl(dl);
@@ -389,7 +389,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax);
break;
case 0x13:
code.mov(rcx, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.xor_(rdx, rdx);
code.cmp(rcx, 0);
code.setge(dl);
@@ -422,27 +422,27 @@ bool JIT::Exec(Mem& mem, u32 instr) {
res = true;
break;
case 0x04:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.mov(r9, qword[rdi + GPR_OFFSET(RT(instr), this)]);
code.xor_(rdx, rdx);
code.cmp(r8, rcx);
code.cmp(r8, r9);
code.sete(dl);
code.mov(rax, (u64)b);
code.call(rax);
res = true;
break;
case 0x05:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.mov(r9, qword[rdi + GPR_OFFSET(RT(instr), this)]);
code.xor_(rdx, rdx);
code.cmp(r8, rcx);
code.cmp(r8, r9);
code.setne(dl);
code.mov(rax, (u64)b);
code.call(rax);
res = true;
break;
case 0x06:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.xor_(rdx, rdx);
code.test(r8, r8);
code.setnz(dl);
@@ -451,7 +451,7 @@ bool JIT::Exec(Mem& mem, u32 instr) {
res = true;
break;
case 0x07:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.xor_(rdx, rdx);
code.test(r8, r8);
code.setg(dl);
@@ -491,12 +491,12 @@ bool JIT::Exec(Mem& mem, u32 instr) {
code.mov(rax, (u64)lui);
code.call(rax);
break;
case 0x10: cop0Decode(regs, *this, instr); break;
case 0x11: res = cop1Decode(regs, *this, instr); break;
case 0x10: cop0Decode(*this, instr); break;
case 0x11: res = cop1Decode(*this, instr); break;
case 0x12: cop2Decode(instr); break;
case 0x14:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
code.xor_(rdx, rdx);
code.cmp(r8, rcx);
code.sete(dl);
@@ -504,8 +504,8 @@ bool JIT::Exec(Mem& mem, u32 instr) {
code.call(rax);
break;
case 0x15:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
code.xor_(rdx, rdx);
code.cmp(r8, rcx);
code.setne(dl);
@@ -513,7 +513,7 @@ bool JIT::Exec(Mem& mem, u32 instr) {
code.call(rax);
break;
case 0x16:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.xor_(rdx, rdx);
code.cmp(r8, 0);
code.setle(dl);
@@ -521,7 +521,7 @@ bool JIT::Exec(Mem& mem, u32 instr) {
code.call(rax);
break;
case 0x17:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.xor_(rdx, rdx);
code.cmp(r8, 0);
code.setg(dl);

View File

@@ -1,7 +1,6 @@
#include <core/JIT.hpp>
#define se_imm(x) ((s16)((x) & 0xFFFF))
#define check_address_error(mask, addr) (((!regs.cop0.is_64bit_addressing) && (s32)(addr) != (addr)) || (((addr) & (mask)) != 0))
#define check_address_error(mask, vaddr) (((!regs.cop0.is_64bit_addressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0))
#define check_signed_overflow(op1, op2, res) (((~((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1)
#define check_signed_underflow(op1, op2, res) (((((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1)
@@ -11,6 +10,9 @@ void add(JIT& dyn, u32 instr) {
u32 rs = (s32)regs.gpr[RS(instr)];
u32 rt = (s32)regs.gpr[RT(instr)];
u32 result = rs + rt;
Util::debug("add r{}, r{}, r{} = {:08X}\n", RD(instr), RS(instr), RT(instr), result);
if(check_signed_overflow(rs, rt, result)) {
FireException(regs, ExceptionCode::Overflow, 0, true);
} else {
@@ -27,6 +29,7 @@ void addu(JIT& dyn, u32 instr) {
s32 rt = (s32)regs.gpr[RT(instr)];
s32 result = rs + rt;
regs.gpr[RD(instr)] = result;
Util::debug("addu r{}, r{}, r{} = {:08X}\n", RD(instr), RS(instr), RT(instr), (u32)result);
}
}
@@ -35,6 +38,7 @@ void addi(JIT& dyn, u32 instr) {
u32 rs = regs.gpr[RS(instr)];
u32 imm = s32(s16(instr));
u32 result = rs + imm;
Util::debug("addi r{}, r{}, {:08X} = {:08X}\n", RT(instr), RS(instr), imm, result);
if(check_signed_overflow(rs, imm, result)) {
FireException(regs, ExceptionCode::Overflow, 0, true);
} else {
@@ -174,8 +178,8 @@ void branch(JIT& dyn, bool cond, s64 address) {
void branch_likely(JIT& dyn, bool cond, s64 address) {
Registers& regs = dyn.regs;
regs.delaySlot = true;
if (cond) {
regs.delaySlot = true;
regs.nextPC = address;
} else {
regs.SetPC64(regs.nextPC);
@@ -184,7 +188,8 @@ void branch_likely(JIT& dyn, bool cond, s64 address) {
void b(JIT& dyn, u32 instr, bool cond) {
Registers& regs = dyn.regs;
s64 offset = (s64)se_imm(instr) << 2;
s16 imm = instr;
s64 offset = (s64)imm << 2;
s64 address = regs.pc + offset;
branch(dyn, cond, address);
}
@@ -192,14 +197,16 @@ void b(JIT& dyn, u32 instr, bool cond) {
void blink(JIT& dyn, u32 instr, bool cond) {
Registers& regs = dyn.regs;
regs.gpr[31] = regs.nextPC;
s64 offset = (s64)se_imm(instr) << 2;
s16 imm = instr;
s64 offset = (s64)imm << 2;
s64 address = regs.pc + offset;
branch(dyn, cond, address);
}
void bl(JIT& dyn, u32 instr, bool cond) {
Registers& regs = dyn.regs;
s64 offset = (s64)se_imm(instr) << 2;
s16 imm = instr;
s64 offset = (s64)imm << 2;
s64 address = regs.pc + offset;
branch_likely(dyn, cond, address);
}
@@ -207,7 +214,8 @@ void bl(JIT& dyn, u32 instr, bool cond) {
void bllink(JIT& dyn, u32 instr, bool cond) {
Registers& regs = dyn.regs;
regs.gpr[31] = regs.nextPC;
s64 offset = (s64)se_imm(instr) << 2;
s16 imm = instr;
s64 offset = (s64)imm << 2;
s64 address = regs.pc + offset;
branch_likely(dyn, cond, address);
}
@@ -247,7 +255,7 @@ void lh(JIT& dyn, u32 instr) {
HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else {
regs.gpr[RT(instr)] = (s16)mem.Read16(regs, address);
regs.gpr[RT(instr)] = (s16)mem.Read16(regs, paddr);
}
}
@@ -256,7 +264,7 @@ void lw(JIT& dyn, u32 instr) {
Mem& mem = dyn.mem;
s16 offset = instr;
u64 address = regs.gpr[RS(instr)] + offset;
if (check_address_error(address, 0b11)) {
if (check_address_error(0b11, address)) {
HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
return;
@@ -330,14 +338,20 @@ void ld(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
Mem& mem = dyn.mem;
s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b111)) {
if (check_address_error(0b111, address)) {
HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
return;
}
s64 value = mem.Read64(regs, address);
regs.gpr[RT(instr)] = value;
u32 paddr = 0;
if(!MapVAddr(regs, LOAD, address, paddr)) {
HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else {
s64 value = mem.Read64(regs, paddr);
regs.gpr[RT(instr)] = value;
}
}
void lld(JIT& dyn, u32 instr) {
@@ -402,43 +416,66 @@ void lbu(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
Mem& mem = dyn.mem;
u64 address = regs.gpr[RS(instr)] + (s16)instr;
u8 value = mem.Read8(regs, address);
regs.gpr[RT(instr)] = value;
u32 paddr;
if (!MapVAddr(regs, LOAD, address, paddr)) {
HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else {
u8 value = mem.Read8(regs, paddr);
regs.gpr[RT(instr)] = value;
}
}
void lhu(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
Mem& mem = dyn.mem;
s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b1)) {
if ((address & 0b1) > 0) {
HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
return;
}
u16 value = mem.Read16(regs, address);
regs.gpr[RT(instr)] = value;
u32 paddr;
if (!MapVAddr(regs, LOAD, address, paddr)) {
HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else {
u16 value = mem.Read16(regs, paddr);
regs.gpr[RT(instr)] = value;
}
}
void lwu(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
Mem& mem = dyn.mem;
s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b11)) {
if ((address & 0b11) > 0) {
HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
return;
}
u32 value = mem.Read32(regs, address);
regs.gpr[RT(instr)] = value;
u32 paddr;
if (!MapVAddr(regs, LOAD, address, paddr)) {
HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else {
u32 value = mem.Read32(regs, paddr);
regs.gpr[RT(instr)] = value;
}
}
void sb(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
Mem& mem = dyn.mem;
u32 address = regs.gpr[RS(instr)] + (s16)instr;
mem.Write8(regs, dyn, address, regs.gpr[RT(instr)]);
u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr;
if (!MapVAddr(regs, STORE, address, paddr)) {
HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else {
mem.Write8(regs, paddr, regs.gpr[RT(instr)]);
}
}
void sc(JIT& dyn, u32 instr) {
@@ -458,7 +495,7 @@ void sc(JIT& dyn, u32 instr) {
HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else {
mem.Write32(regs, dyn, paddr, regs.gpr[RT(instr)]);
mem.Write32(regs, paddr, regs.gpr[RT(instr)]);
regs.gpr[RT(instr)] = 1;
}
} else {
@@ -469,37 +506,44 @@ void sc(JIT& dyn, u32 instr) {
void scd(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
Mem& mem = dyn.mem;
if (!regs.cop0.is_64bit_addressing && !regs.cop0.kernel_mode) {
FireException(regs, ExceptionCode::ReservedInstruction, 0, true);
return;
}
s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b111)) {
if ((address & 0b111) > 0) {
HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
return;
}
if(regs.cop0.llbit) {
mem.Write64(regs, dyn, address, regs.gpr[RT(instr)]);
regs.cop0.llbit = false;
u32 paddr = 0;
if(!MapVAddr(regs, STORE, address, paddr)) {
HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else {
mem.Write32(regs, paddr, regs.gpr[RT(instr)]);
regs.gpr[RT(instr)] = 1;
}
} else {
regs.gpr[RT(instr)] = 0;
}
regs.gpr[RT(instr)] = (s64)((u64)regs.cop0.llbit);
regs.cop0.llbit = false;
}
void sh(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
Mem& mem = dyn.mem;
s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b1)) {
HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
return;
}
u32 physical;
if(!MapVAddr(regs, STORE, address, physical)) {
HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else {
mem.Write16(regs, dyn, physical, regs.gpr[RT(instr)]);
mem.Write16(regs, physical, regs.gpr[RT(instr)]);
}
}
@@ -508,7 +552,7 @@ void sw(JIT& dyn, u32 instr) {
Mem& mem = dyn.mem;
s16 offset = instr;
u64 address = regs.gpr[RS(instr)] + offset;
if (check_address_error(address, 0b11)) {
if (check_address_error(0b11, address)) {
HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
return;
@@ -519,7 +563,7 @@ void sw(JIT& dyn, u32 instr) {
HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else {
mem.Write32(regs, dyn, physical, regs.gpr[RT(instr)]);
mem.Write32(regs, physical, regs.gpr[RT(instr)]);
}
}
@@ -527,7 +571,7 @@ void sd(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
Mem& mem = dyn.mem;
s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b11)) {
if (check_address_error(0b111, address)) {
HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
return;
@@ -538,9 +582,8 @@ void sd(JIT& dyn, u32 instr) {
HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else {
mem.Write64(regs, dyn, physical, regs.gpr[RT(instr)]);
mem.Write64(regs, physical, regs.gpr[RT(instr)]);
}
}
void sdl(JIT& dyn, u32 instr) {
@@ -556,7 +599,7 @@ void sdl(JIT& dyn, u32 instr) {
u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
u64 data = mem.Read64(regs, paddr & ~7);
u64 rt = regs.gpr[RT(instr)];
mem.Write64(regs, dyn, paddr & ~7, (data & ~mask) | (rt >> shift));
mem.Write64(regs, paddr & ~7, (data & ~mask) | (rt >> shift));
}
}
@@ -573,7 +616,7 @@ void sdr(JIT& dyn, u32 instr) {
u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
u64 data = mem.Read64(regs, paddr & ~7);
u64 rt = regs.gpr[RT(instr)];
mem.Write64(regs, dyn, paddr & ~7, (data & ~mask) | (rt << shift));
mem.Write64(regs, paddr & ~7, (data & ~mask) | (rt << shift));
}
}
@@ -590,7 +633,7 @@ void swl(JIT& dyn, u32 instr) {
u32 mask = 0xFFFFFFFF >> shift;
u32 data = mem.Read32(regs, paddr & ~3);
u32 rt = regs.gpr[RT(instr)];
mem.Write32(regs, dyn, paddr & ~3, (data & ~mask) | (rt >> shift));
mem.Write32(regs, paddr & ~3, (data & ~mask) | (rt >> shift));
}
}
@@ -607,7 +650,7 @@ void swr(JIT& dyn, u32 instr) {
u32 mask = 0xFFFFFFFF << shift;
u32 data = mem.Read32(regs, paddr & ~3);
u32 rt = regs.gpr[RT(instr)];
mem.Write32(regs, dyn, paddr & ~3, (data & ~mask) | (rt << shift));
mem.Write32(regs, paddr & ~3, (data & ~mask) | (rt << shift));
}
}
@@ -634,8 +677,9 @@ void nor(JIT& dyn, u32 instr) {
void j(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
u64 target = (instr & 0x3ffffff) << 2;
u64 address = ((regs.pc - 4) & ~0xfffffff) | target;
Mem& mem = dyn.mem;
s32 target = (instr & 0x3ffffff) << 2;
s64 address = (regs.oldPC & ~0xfffffff) | target;
branch(dyn, true, address);
}
@@ -648,6 +692,7 @@ void jal(JIT& dyn, u32 instr) {
void jalr(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
Mem& mem = dyn.mem;
branch(dyn, true, regs.gpr[RS(instr)]);
if(likely(RD(instr) != 0)) {
regs.gpr[RD(instr)] = regs.pc + 4;
@@ -656,12 +701,14 @@ void jalr(JIT& dyn, u32 instr) {
void slti(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.gpr[RT(instr)] = regs.gpr[RS(instr)] < se_imm(instr);
s16 imm = instr;
regs.gpr[RT(instr)] = regs.gpr[RS(instr)] < imm;
}
void sltiu(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
regs.gpr[RT(instr)] = (u64)regs.gpr[RS(instr)] < se_imm(instr);
s16 imm = instr;
regs.gpr[RT(instr)] = (u64)regs.gpr[RS(instr)] < imm;
}
void slt(JIT& dyn, u32 instr) {
@@ -812,8 +859,8 @@ void sra(JIT& dyn, u32 instr) {
void srav(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
s64 rt = regs.gpr[RT(instr)];
if(likely(RD(instr) != 0)) {
s64 rt = regs.gpr[RT(instr)];
s64 rs = regs.gpr[RS(instr)];
u8 sa = rs & 0x1f;
s32 result = rt >> sa;
@@ -855,11 +902,6 @@ void dsra32(JIT& dyn, u32 instr) {
void jr(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs;
s64 address = regs.gpr[RS(instr)];
if (check_address_error(address, 0b11)) {
HandleTLBException(regs, address);
FireException(regs, ExceptionCode::DataBusError, 0, true);
}
branch(dyn, true, address);
}
@@ -972,9 +1014,8 @@ void mthi(JIT& dyn, u32 instr) {
}
void trap(JIT& dyn, bool cond) {
Registers& regs = dyn.regs;
if(cond) {
FireException(regs, ExceptionCode::Trap, 0, true);
FireException(dyn.regs, ExceptionCode::Trap, 0, true);
}
}

View File

@@ -74,7 +74,7 @@ void SI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) {
InterruptLower(mem.mmio.mi, regs, Interrupt::SI);
break;
default:
Util::panic("Unhandled SI[%08X] write (%08X)\n", addr, val);
Util::panic("Unhandled SI[{:08X}] write ({:08X})\n", addr, val);
}
}
}

View File

@@ -323,7 +323,7 @@ ExceptionCode GetTLBExceptionCode(TLBError error, TLBAccessType accessType) {
}
}
void Cop0::decode(Registers& regs, Mem& mem, u32 instr) {
void Cop0::decode(Registers& regs, u32 instr) {
u8 mask_cop = (instr >> 21) & 0x1F;
u8 mask_cop2 = instr & 0x3F;
switch(mask_cop) {

View File

@@ -235,7 +235,7 @@ struct Cop0 {
TLBEntry tlb[32]{};
TLBError tlbError = NONE;
s64 openbus{};
void decode(Registers&, Mem&, u32);
void decode(Registers&, u32);
inline u32 GetRandom() {
int val = rand();
int wired = GetWired();

View File

@@ -6,6 +6,8 @@ Registers::Registers() {
}
void Registers::Reset() {
hi = 0;
lo = 0;
delaySlot = false;
prevDelaySlot = false;
memset(gpr, 0, 32*sizeof(s64));