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

View File

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

View File

@@ -130,7 +130,7 @@ void Interpreter::Exec(u32 instr) {
case 0x0D: ori(instr); break; case 0x0D: ori(instr); break;
case 0x0E: xori(instr); break; case 0x0E: xori(instr); break;
case 0x0F: lui(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 0x11: regs.cop1.decode(regs, *this, instr); break;
case 0x12: cop2Decode(instr); break; case 0x12: cop2Decode(instr); break;
case 0x14: bl(instr, regs.gpr[RS(instr)] == regs.gpr[RT(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() { void JIT::InvalidateCache() {
sizeUsed = 0; sizeUsed = 0;
for(int i = 0; i < 0x80000; i++) { for(auto &i : blockCache) {
blockCache[i] = nullptr; i = nullptr;
} }
} }

View File

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

View File

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

View File

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

View File

@@ -2,5 +2,5 @@
#include <jit/cop/cop1instructions.hpp> #include <jit/cop/cop1instructions.hpp>
namespace n64 { 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) } while(0)
void absd(JIT& cpu, u32 instr) { void absd(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
auto fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr)); double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), std::abs(fs)); regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), std::abs(fs));
} }
void abss(JIT& cpu, u32 instr) { void abss(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
auto fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr)); float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), std::abs(fs)); regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), std::abs(fs));
} }
void absw(JIT& cpu, u32 instr) { void absw(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
s32 fs = regs.cop1.GetReg<s32>(regs.cop0, FS(instr)); s32 fs = regs.cop1.GetReg<s32>(regs.cop0, FS(instr));
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), std::abs(fs)); regs.cop1.SetReg<u32>(regs.cop0, FD(instr), std::abs(fs));
} }
void absl(JIT& cpu, u32 instr) { void absl(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
s64 fs = regs.cop1.GetReg<s64>(regs.cop0, FS(instr)); s64 fs = regs.cop1.GetReg<s64>(regs.cop0, FS(instr));
regs.cop1.SetReg(regs.cop0, FD(instr), std::abs(fs)); regs.cop1.SetReg(regs.cop0, FD(instr), std::abs(fs));
} }
void adds(JIT& cpu, u32 instr) { void adds(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
auto fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr)); float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
auto ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr)); float ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr));
checknanregs(fs, ft); checknanregs(fs, ft);
float result = fs + ft; float result = fs + ft;
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), result); regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), result);
} }
void addd(JIT& cpu, u32 instr) { void addd(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
auto fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr)); double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
auto ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr)); double ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr));
checknanregs(fs, ft); checknanregs(fs, ft);
double result = fs + ft; double result = fs + ft;
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), result); regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), result);
} }
void ceills(JIT& cpu, u32 instr) { void ceills(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
auto fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr)); float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
s64 result = std::ceil(fs); s64 result = std::ceil(fs);
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result); regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result);
} }
void ceilws(JIT& cpu, u32 instr) { void ceilws(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
auto fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr)); float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
s32 result = std::ceil(fs); s32 result = std::ceil(fs);
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result); regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result);
} }
void ceilld(JIT& cpu, u32 instr) { void ceilld(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
auto fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr)); double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
s64 result = std::ceil(fs); s64 result = std::ceil(fs);
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result); regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result);
} }
void ceilwd(JIT& cpu, u32 instr) { void ceilwd(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
auto fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr)); double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
s32 result = std::ceil(fs); s32 result = std::ceil(fs);
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result); regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result);
} }
void cfc1(JIT& cpu, u32 instr) { void cfc1(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
u8 fd = RD(instr); u8 fd = RD(instr);
s32 val = 0; s32 val = 0;
switch(fd) { switch(fd) {
case 0: val = regs.cop1.fcr0; break; 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"); default: Util::panic("Undefined CFC1 with rd != 0 or 31\n");
} }
regs.gpr[RT(instr)] = val; regs.gpr[RT(instr)] = val;
} }
void ctc1(JIT& cpu, u32 instr) { void ctc1(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
u8 fs = FS(instr); u8 fs = RD(instr);
u32 val = regs.gpr[RT(instr)]; u32 val = regs.gpr[RT(instr)];
switch(fs) { switch(fs) {
case 0: break; case 0: break;
@@ -125,8 +127,8 @@ void ctc1(JIT& cpu, u32 instr) {
} }
} }
void cvtds(JIT& cpu, u32 instr) { void cvtds(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
regs.cop1.SetCop1Reg<double>( regs.cop1.SetCop1Reg<double>(
regs.cop0, regs.cop0,
FD(instr), FD(instr),
@@ -137,8 +139,8 @@ void cvtds(JIT& cpu, u32 instr) {
); );
} }
void cvtsd(JIT& cpu, u32 instr) { void cvtsd(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
regs.cop1.SetCop1Reg<float>( regs.cop1.SetCop1Reg<float>(
regs.cop0, regs.cop0,
FD(instr), FD(instr),
@@ -149,8 +151,8 @@ void cvtsd(JIT& cpu, u32 instr) {
); );
} }
void cvtwd(JIT& cpu, u32 instr) { void cvtwd(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
regs.cop1.SetReg<u32>( regs.cop1.SetReg<u32>(
regs.cop0, regs.cop0,
FD(instr), FD(instr),
@@ -161,8 +163,8 @@ void cvtwd(JIT& cpu, u32 instr) {
); );
} }
void cvtws(JIT& cpu, u32 instr) { void cvtws(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
regs.cop1.SetReg<u32>( regs.cop1.SetReg<u32>(
regs.cop0, regs.cop0,
FD(instr), FD(instr),
@@ -173,8 +175,8 @@ void cvtws(JIT& cpu, u32 instr) {
); );
} }
void cvtls(JIT& cpu, u32 instr) { void cvtls(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
regs.cop1.SetReg<u64>( regs.cop1.SetReg<u64>(
regs.cop0, regs.cop0,
FD(instr), FD(instr),
@@ -185,8 +187,8 @@ void cvtls(JIT& cpu, u32 instr) {
); );
} }
void cvtsl(JIT& cpu, u32 instr) { void cvtsl(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
regs.cop1.SetCop1Reg<float>( regs.cop1.SetCop1Reg<float>(
regs.cop0, regs.cop0,
FD(instr), FD(instr),
@@ -197,8 +199,8 @@ void cvtsl(JIT& cpu, u32 instr) {
); );
} }
void cvtdw(JIT& cpu, u32 instr) { void cvtdw(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
regs.cop1.SetCop1Reg<double>( regs.cop1.SetCop1Reg<double>(
regs.cop0, regs.cop0,
FD(instr), FD(instr),
@@ -209,8 +211,8 @@ void cvtdw(JIT& cpu, u32 instr) {
); );
} }
void cvtsw(JIT& cpu, u32 instr) { void cvtsw(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
regs.cop1.SetCop1Reg<float>( regs.cop1.SetCop1Reg<float>(
regs.cop0, regs.cop0,
FD(instr), FD(instr),
@@ -221,8 +223,8 @@ void cvtsw(JIT& cpu, u32 instr) {
); );
} }
void cvtdl(JIT& cpu, u32 instr) { void cvtdl(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
regs.cop1.SetCop1Reg<double>( regs.cop1.SetCop1Reg<double>(
regs.cop0, regs.cop0,
FD(instr), FD(instr),
@@ -233,8 +235,8 @@ void cvtdl(JIT& cpu, u32 instr) {
); );
} }
void cvtld(JIT& cpu, u32 instr) { void cvtld(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
regs.cop1.SetReg<u64>( regs.cop1.SetReg<u64>(
regs.cop0, regs.cop0,
FD(instr), FD(instr),
@@ -246,8 +248,7 @@ void cvtld(JIT& cpu, u32 instr) {
} }
template <typename T> template <typename T>
inline bool CalculateCondition(JIT& cpu, T fs, T ft, CompConds cond) { inline bool CalculateCondition(Registers& regs, T fs, T ft, CompConds cond) {
Registers& regs = cpu.regs;
switch(cond) { switch(cond) {
case F: return false; case F: return false;
case UN: return std::isnan(fs) || std::isnan(ft); 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 false;
} }
return CalculateCondition(cpu, fs, ft, static_cast<CompConds>(cond - 8)); return CalculateCondition(regs, fs, ft, static_cast<CompConds>(cond - 8));
} }
} }
template <typename T> template <typename T>
void ccond(JIT& cpu, u32 instr, CompConds cond) { void ccond(JIT& dyn, u32 instr, CompConds cond) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
T fs = regs.cop1.GetCop1Reg<T>(regs.cop0, FS(instr)); T fs = regs.cop1.GetCop1Reg<T>(regs.cop0, FS(instr));
T ft = regs.cop1.GetCop1Reg<T>(regs.cop0, FT(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<float>(JIT& dyn, u32 instr, CompConds cond);
template void ccond<double>(JIT& cpu, u32 instr, CompConds cond); template void ccond<double>(JIT& dyn, u32 instr, CompConds cond);
void divs(JIT& cpu, u32 instr) { void divs(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr)); float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
float ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr)); float ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr));
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), fs / ft); regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), fs / ft);
} }
void divd(JIT& cpu, u32 instr) { void divd(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr)); double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
double ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr)); double ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr));
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), fs / ft); regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), fs / ft);
} }
void muls(JIT& cpu, u32 instr) { void muls(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr)); float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
float ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr)); float ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr));
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), fs * ft); regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), fs * ft);
} }
void muld(JIT& cpu, u32 instr) { void muld(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr)); double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
double ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr)); double ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr));
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), fs * ft); regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), fs * ft);
} }
void mulw(JIT& cpu, u32 instr) { void mulw(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
u32 fs = regs.cop1.GetReg<u32>(regs.cop0, FS(instr)); u32 fs = regs.cop1.GetReg<u32>(regs.cop0, FS(instr));
u32 ft = regs.cop1.GetReg<u32>(regs.cop0, FT(instr)); u32 ft = regs.cop1.GetReg<u32>(regs.cop0, FT(instr));
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), fs * ft); regs.cop1.SetReg<u32>(regs.cop0, FD(instr), fs * ft);
} }
void mull(JIT& cpu, u32 instr) { void mull(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
u64 fs = regs.cop1.GetReg<u64>(regs.cop0, FS(instr)); u64 fs = regs.cop1.GetReg<u64>(regs.cop0, FS(instr));
u64 ft = regs.cop1.GetReg<u64>(regs.cop0, FT(instr)); u64 ft = regs.cop1.GetReg<u64>(regs.cop0, FT(instr));
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), fs * ft); regs.cop1.SetReg<u64>(regs.cop0, FD(instr), fs * ft);
} }
void subs(JIT& cpu, u32 instr) { void subs(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr)); float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
float ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr)); float ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr));
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), fs - ft); regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), fs - ft);
} }
void subd(JIT& cpu, u32 instr) { void subd(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr)); double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
double ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr)); double ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr));
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), fs - ft); regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), fs - ft);
} }
void subw(JIT& cpu, u32 instr) { void subw(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
u32 fs = regs.cop1.GetReg<u32>(regs.cop0, FS(instr)); u32 fs = regs.cop1.GetReg<u32>(regs.cop0, FS(instr));
u32 ft = regs.cop1.GetReg<u32>(regs.cop0, FT(instr)); u32 ft = regs.cop1.GetReg<u32>(regs.cop0, FT(instr));
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), fs - ft); regs.cop1.SetReg<u32>(regs.cop0, FD(instr), fs - ft);
} }
void subl(JIT& cpu, u32 instr) { void subl(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
u64 fs = regs.cop1.GetReg<u64>(regs.cop0, FS(instr)); u64 fs = regs.cop1.GetReg<u64>(regs.cop0, FS(instr));
u64 ft = regs.cop1.GetReg<u64>(regs.cop0, FT(instr)); u64 ft = regs.cop1.GetReg<u64>(regs.cop0, FT(instr));
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), fs - ft); regs.cop1.SetReg<u64>(regs.cop0, FD(instr), fs - ft);
} }
void movs(JIT& cpu, u32 instr) { void movs(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
regs.cop1.SetCop1Reg<float>( regs.cop1.SetCop1Reg<float>(
regs.cop0, regs.cop0,
FD(instr), FD(instr),
@@ -363,8 +364,8 @@ void movs(JIT& cpu, u32 instr) {
); );
} }
void movd(JIT& cpu, u32 instr) { void movd(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
regs.cop1.SetCop1Reg<double>( regs.cop1.SetCop1Reg<double>(
regs.cop0, regs.cop0,
FD(instr), FD(instr),
@@ -375,8 +376,8 @@ void movd(JIT& cpu, u32 instr) {
); );
} }
void movw(JIT& cpu, u32 instr) { void movw(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
regs.cop1.SetReg<u32>( regs.cop1.SetReg<u32>(
regs.cop0, regs.cop0,
FD(instr), FD(instr),
@@ -387,8 +388,8 @@ void movw(JIT& cpu, u32 instr) {
); );
} }
void movl(JIT& cpu, u32 instr) { void movl(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
regs.cop1.SetReg<u64>( regs.cop1.SetReg<u64>(
regs.cop0, regs.cop0,
FD(instr), FD(instr),
@@ -399,8 +400,8 @@ void movl(JIT& cpu, u32 instr) {
); );
} }
void negs(JIT& cpu, u32 instr) { void negs(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
regs.cop1.SetCop1Reg<float>( regs.cop1.SetCop1Reg<float>(
regs.cop0, regs.cop0,
FD(instr), FD(instr),
@@ -411,8 +412,8 @@ void negs(JIT& cpu, u32 instr) {
); );
} }
void negd(JIT& cpu, u32 instr) { void negd(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
regs.cop1.SetCop1Reg<double>( regs.cop1.SetCop1Reg<double>(
regs.cop0, regs.cop0,
FD(instr), FD(instr),
@@ -423,77 +424,76 @@ void negd(JIT& cpu, u32 instr) {
); );
} }
void sqrts(JIT& cpu, u32 instr) { void sqrts(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr)); float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), std::sqrt(fs)); regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), std::sqrt(fs));
} }
void sqrtd(JIT& cpu, u32 instr) { void sqrtd(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr)); double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), std::sqrt(fs)); regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), std::sqrt(fs));
} }
void roundls(JIT& cpu, u32 instr) { void roundls(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr)); float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
PUSHROUNDINGMODE; PUSHROUNDINGMODE;
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s32)std::nearbyint(fs)); regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s32)std::nearbyint(fs));
POPROUNDINGMODE; POPROUNDINGMODE;
} }
void roundld(JIT& cpu, u32 instr) { void roundld(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr)); double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
PUSHROUNDINGMODE; PUSHROUNDINGMODE;
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s64)std::nearbyint(fs)); regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s64)std::nearbyint(fs));
POPROUNDINGMODE; POPROUNDINGMODE;
} }
void roundws(JIT& cpu, u32 instr) { void roundws(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr)); float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
PUSHROUNDINGMODE; PUSHROUNDINGMODE;
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s32)std::nearbyint(fs)); regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s32)std::nearbyint(fs));
POPROUNDINGMODE; POPROUNDINGMODE;
} }
void roundwd(JIT& cpu, u32 instr) { void roundwd(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr)); double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
PUSHROUNDINGMODE; PUSHROUNDINGMODE;
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s32)std::nearbyint(fs)); regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s32)std::nearbyint(fs));
POPROUNDINGMODE; POPROUNDINGMODE;
} }
void floorls(JIT& cpu, u32 instr) { void floorls(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr)); float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s64)std::floor(fs)); regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s64)std::floor(fs));
} }
void floorld(JIT& cpu, u32 instr) { void floorld(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr)); double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s64)std::floor(fs)); regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s64)std::floor(fs));
} }
void floorws(JIT& cpu, u32 instr) { void floorws(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr)); float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s64)std::floor(fs)); regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s64)std::floor(fs));
} }
void floorwd(JIT& cpu, u32 instr) { void floorwd(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr)); double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s64)std::floor(fs)); regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s64)std::floor(fs));
} }
void lwc1(JIT& cpu, u32 instr) { void lwc1(JIT& dyn, u32 instr) {
Mem& mem = cpu.mem; Registers& regs = dyn.regs;
Registers& regs = cpu.regs;
if(!regs.cop0.status.cu1) { if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true); FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
return; return;
@@ -506,14 +506,13 @@ void lwc1(JIT& cpu, u32 instr) {
HandleTLBException(regs, addr); HandleTLBException(regs, addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else { } else {
u32 data = mem.Read32(regs, physical); u32 data = dyn.mem.Read32(regs, physical);
regs.cop1.SetReg<u32>(regs.cop0, FT(instr), data); regs.cop1.SetReg<u32>(regs.cop0, FT(instr), data);
} }
} }
void swc1(JIT& cpu, u32 instr) { void swc1(JIT& dyn, u32 instr) {
Mem& mem = cpu.mem; Registers& regs = dyn.regs;
Registers& regs = cpu.regs;
if(!regs.cop0.status.cu1) { if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true); FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
return; return;
@@ -526,13 +525,12 @@ void swc1(JIT& cpu, u32 instr) {
HandleTLBException(regs, addr); HandleTLBException(regs, addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } 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) { void ldc1(JIT& dyn, u32 instr) {
Mem& mem = cpu.mem; Registers& regs = dyn.regs;
Registers& regs = cpu.regs;
if(!regs.cop0.status.cu1) { if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true); FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
return; return;
@@ -545,14 +543,13 @@ void ldc1(JIT& cpu, u32 instr) {
HandleTLBException(regs, addr); HandleTLBException(regs, addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else { } else {
u64 data = mem.Read64(regs, physical); u64 data = dyn.mem.Read64(regs, physical);
regs.cop1.SetReg<u64>(regs.cop0, FT(instr), data); regs.cop1.SetReg<u64>(regs.cop0, FT(instr), data);
} }
} }
void sdc1(JIT& cpu, u32 instr) { void sdc1(JIT& dyn, u32 instr) {
Mem& mem = cpu.mem; Registers& regs = dyn.regs;
Registers& regs = cpu.regs;
if(!regs.cop0.status.cu1) { if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true); FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
return; return;
@@ -565,55 +562,56 @@ void sdc1(JIT& cpu, u32 instr) {
HandleTLBException(regs, addr); HandleTLBException(regs, addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } 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) { void truncws(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr)); float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
s32 result = (s32)std::trunc(fs); s32 result = (s32)std::trunc(fs);
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result); regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result);
} }
void truncwd(JIT& cpu, u32 instr) { void truncwd(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr)); double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
s32 result = (s32)std::trunc(fs); s32 result = (s32)std::trunc(fs);
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result); regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result);
} }
void truncls(JIT& cpu, u32 instr) { void truncls(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr)); float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
s64 result = (s64)std::trunc(fs); s64 result = (s64)std::trunc(fs);
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result); regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result);
} }
void truncld(JIT& cpu, u32 instr) { void truncld(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr)); double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
s64 result = (s64)std::trunc(fs); s64 result = (s64)std::trunc(fs);
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result); regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result);
} }
void mfc1(JIT& cpu, u32 instr) { void mfc1(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
regs.gpr[RT(instr)] = (s32)regs.cop1.GetReg<u32>(regs.cop0, FS(instr)); regs.gpr[RT(instr)] = (s32)regs.cop1.GetReg<u32>(regs.cop0, FS(instr));
} }
void dmfc1(JIT& cpu, u32 instr) { void dmfc1(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
regs.gpr[RT(instr)] = (s64)regs.cop1.GetReg<u64>(regs.cop0, FS(instr)); regs.gpr[RT(instr)] = (s64)regs.cop1.GetReg<u64>(regs.cop0, FS(instr));
} }
void mtc1(JIT& cpu, u32 instr) { void mtc1(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
regs.cop1.SetReg<u32>(regs.cop0, FS(instr), regs.gpr[RT(instr)]); regs.cop1.SetReg<u32>(regs.cop0, FS(instr), regs.gpr[RT(instr)]);
} }
void dmtc1(JIT& cpu, u32 instr) { void dmtc1(JIT& dyn, u32 instr) {
Registers& regs = cpu.regs; Registers& regs = dyn.regs;
regs.cop1.SetReg<u64>(regs.cop0, FS(instr), regs.gpr[RT(instr)]); 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); code.call(rax);
break; break;
case 0x30: case 0x30:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]); code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]); code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
code.xor_(rsi, rsi); code.xor_(rsi, rsi);
code.cmp(r8, rcx); code.cmp(r8, rcx);
code.setge(sil); code.setge(sil);
@@ -200,8 +200,8 @@ bool JIT::special(u32 instr) {
res = true; res = true;
break; break;
case 0x31: case 0x31:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]); code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]); code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
code.xor_(rsi, rsi); code.xor_(rsi, rsi);
code.cmp(r8, rcx); code.cmp(r8, rcx);
code.setae(sil); code.setae(sil);
@@ -210,8 +210,8 @@ bool JIT::special(u32 instr) {
res = true; res = true;
break; break;
case 0x32: case 0x32:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]); code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]); code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
code.xor_(rsi, rsi); code.xor_(rsi, rsi);
code.cmp(r8, rcx); code.cmp(r8, rcx);
code.setl(sil); code.setl(sil);
@@ -220,8 +220,8 @@ bool JIT::special(u32 instr) {
res = true; res = true;
break; break;
case 0x33: case 0x33:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]); code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]); code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
code.xor_(rsi, rsi); code.xor_(rsi, rsi);
code.cmp(r8, rcx); code.cmp(r8, rcx);
code.setb(sil); code.setb(sil);
@@ -230,8 +230,8 @@ bool JIT::special(u32 instr) {
res = true; res = true;
break; break;
case 0x34: case 0x34:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]); code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]); code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
code.xor_(rsi, rsi); code.xor_(rsi, rsi);
code.cmp(r8, rcx); code.cmp(r8, rcx);
code.sete(sil); code.sete(sil);
@@ -240,8 +240,8 @@ bool JIT::special(u32 instr) {
res = true; res = true;
break; break;
case 0x36: case 0x36:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]); code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]); code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
code.xor_(rsi, rsi); code.xor_(rsi, rsi);
code.cmp(r8, rcx); code.cmp(r8, rcx);
code.setne(sil); code.setne(sil);
@@ -285,7 +285,7 @@ bool JIT::regimm(u32 instr) {
// 000r_rccc // 000r_rccc
switch (mask) { // TODO: named constants for clearer code switch (mask) { // TODO: named constants for clearer code
case 0x00: 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.xor_(rdx, rdx);
code.cmp(r8, 0); code.cmp(r8, 0);
code.setl(dl); code.setl(dl);
@@ -293,7 +293,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax); code.call(rax);
break; break;
case 0x01: 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.xor_(rdx, rdx);
code.cmp(r8, 0); code.cmp(r8, 0);
code.setge(dl); code.setge(dl);
@@ -301,7 +301,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax); code.call(rax);
break; break;
case 0x02: 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.xor_(rdx, rdx);
code.cmp(r8, 0); code.cmp(r8, 0);
code.setl(dl); code.setl(dl);
@@ -309,7 +309,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax); code.call(rax);
break; break;
case 0x03: 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.xor_(rdx, rdx);
code.cmp(r8, 0); code.cmp(r8, 0);
code.setge(dl); code.setge(dl);
@@ -317,7 +317,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax); code.call(rax);
break; break;
case 0x08: 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.xor_(rsi, rsi);
code.cmp(r8, s64(s16(instr))); code.cmp(r8, s64(s16(instr)));
code.setge(sil); code.setge(sil);
@@ -325,7 +325,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax); code.call(rax);
break; break;
case 0x09: 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.xor_(rsi, rsi);
code.cmp(r8, u64(s64(s16(instr)))); code.cmp(r8, u64(s64(s16(instr))));
code.setae(sil); code.setae(sil);
@@ -333,7 +333,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax); code.call(rax);
break; break;
case 0x0A: 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.xor_(rsi, rsi);
code.cmp(r8, s64(s16(instr))); code.cmp(r8, s64(s16(instr)));
code.setl(sil); code.setl(sil);
@@ -341,7 +341,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax); code.call(rax);
break; break;
case 0x0B: 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.xor_(rsi, rsi);
code.cmp(r8, u64(s64(s16(instr)))); code.cmp(r8, u64(s64(s16(instr))));
code.setb(sil); code.setb(sil);
@@ -349,7 +349,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax); code.call(rax);
break; break;
case 0x0C: 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.xor_(rsi, rsi);
code.cmp(r8, s64(s16(instr))); code.cmp(r8, s64(s16(instr)));
code.sete(sil); code.sete(sil);
@@ -357,7 +357,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax); code.call(rax);
break; break;
case 0x0E: 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.xor_(rsi, rsi);
code.cmp(r8, s64(s16(instr))); code.cmp(r8, s64(s16(instr)));
code.setne(sil); code.setne(sil);
@@ -365,7 +365,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax); code.call(rax);
break; break;
case 0x10: 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.xor_(rdx, rdx);
code.cmp(rcx, 0); code.cmp(rcx, 0);
code.setl(dl); code.setl(dl);
@@ -373,7 +373,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax); code.call(rax);
break; break;
case 0x11: 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.xor_(rdx, rdx);
code.cmp(rcx, 0); code.cmp(rcx, 0);
code.setge(dl); code.setge(dl);
@@ -381,7 +381,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax); code.call(rax);
break; break;
case 0x12: 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.xor_(rdx, rdx);
code.cmp(rcx, 0); code.cmp(rcx, 0);
code.setl(dl); code.setl(dl);
@@ -389,7 +389,7 @@ bool JIT::regimm(u32 instr) {
code.call(rax); code.call(rax);
break; break;
case 0x13: 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.xor_(rdx, rdx);
code.cmp(rcx, 0); code.cmp(rcx, 0);
code.setge(dl); code.setge(dl);
@@ -422,27 +422,27 @@ bool JIT::Exec(Mem& mem, u32 instr) {
res = true; res = true;
break; break;
case 0x04: case 0x04:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]); code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]); code.mov(r9, qword[rdi + GPR_OFFSET(RT(instr), this)]);
code.xor_(rdx, rdx); code.xor_(rdx, rdx);
code.cmp(r8, rcx); code.cmp(r8, r9);
code.sete(dl); code.sete(dl);
code.mov(rax, (u64)b); code.mov(rax, (u64)b);
code.call(rax); code.call(rax);
res = true; res = true;
break; break;
case 0x05: case 0x05:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]); code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]); code.mov(r9, qword[rdi + GPR_OFFSET(RT(instr), this)]);
code.xor_(rdx, rdx); code.xor_(rdx, rdx);
code.cmp(r8, rcx); code.cmp(r8, r9);
code.setne(dl); code.setne(dl);
code.mov(rax, (u64)b); code.mov(rax, (u64)b);
code.call(rax); code.call(rax);
res = true; res = true;
break; break;
case 0x06: 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.xor_(rdx, rdx);
code.test(r8, r8); code.test(r8, r8);
code.setnz(dl); code.setnz(dl);
@@ -451,7 +451,7 @@ bool JIT::Exec(Mem& mem, u32 instr) {
res = true; res = true;
break; break;
case 0x07: 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.xor_(rdx, rdx);
code.test(r8, r8); code.test(r8, r8);
code.setg(dl); code.setg(dl);
@@ -491,12 +491,12 @@ bool JIT::Exec(Mem& mem, u32 instr) {
code.mov(rax, (u64)lui); code.mov(rax, (u64)lui);
code.call(rax); code.call(rax);
break; break;
case 0x10: cop0Decode(regs, *this, instr); break; case 0x10: cop0Decode(*this, instr); break;
case 0x11: res = cop1Decode(regs, *this, instr); break; case 0x11: res = cop1Decode(*this, instr); break;
case 0x12: cop2Decode(instr); break; case 0x12: cop2Decode(instr); break;
case 0x14: case 0x14:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]); code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]); code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
code.xor_(rdx, rdx); code.xor_(rdx, rdx);
code.cmp(r8, rcx); code.cmp(r8, rcx);
code.sete(dl); code.sete(dl);
@@ -504,8 +504,8 @@ bool JIT::Exec(Mem& mem, u32 instr) {
code.call(rax); code.call(rax);
break; break;
case 0x15: case 0x15:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]); code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]); code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
code.xor_(rdx, rdx); code.xor_(rdx, rdx);
code.cmp(r8, rcx); code.cmp(r8, rcx);
code.setne(dl); code.setne(dl);
@@ -513,7 +513,7 @@ bool JIT::Exec(Mem& mem, u32 instr) {
code.call(rax); code.call(rax);
break; break;
case 0x16: 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.xor_(rdx, rdx);
code.cmp(r8, 0); code.cmp(r8, 0);
code.setle(dl); code.setle(dl);
@@ -521,7 +521,7 @@ bool JIT::Exec(Mem& mem, u32 instr) {
code.call(rax); code.call(rax);
break; break;
case 0x17: 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.xor_(rdx, rdx);
code.cmp(r8, 0); code.cmp(r8, 0);
code.setg(dl); code.setg(dl);

View File

@@ -1,7 +1,6 @@
#include <core/JIT.hpp> #include <core/JIT.hpp>
#define se_imm(x) ((s16)((x) & 0xFFFF)) #define check_address_error(mask, vaddr) (((!regs.cop0.is_64bit_addressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0))
#define check_address_error(mask, addr) (((!regs.cop0.is_64bit_addressing) && (s32)(addr) != (addr)) || (((addr) & (mask)) != 0))
#define check_signed_overflow(op1, op2, res) (((~((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1) #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) #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 rs = (s32)regs.gpr[RS(instr)];
u32 rt = (s32)regs.gpr[RT(instr)]; u32 rt = (s32)regs.gpr[RT(instr)];
u32 result = rs + rt; 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)) { if(check_signed_overflow(rs, rt, result)) {
FireException(regs, ExceptionCode::Overflow, 0, true); FireException(regs, ExceptionCode::Overflow, 0, true);
} else { } else {
@@ -27,6 +29,7 @@ void addu(JIT& dyn, u32 instr) {
s32 rt = (s32)regs.gpr[RT(instr)]; s32 rt = (s32)regs.gpr[RT(instr)];
s32 result = rs + rt; s32 result = rs + rt;
regs.gpr[RD(instr)] = result; 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 rs = regs.gpr[RS(instr)];
u32 imm = s32(s16(instr)); u32 imm = s32(s16(instr));
u32 result = rs + imm; 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)) { if(check_signed_overflow(rs, imm, result)) {
FireException(regs, ExceptionCode::Overflow, 0, true); FireException(regs, ExceptionCode::Overflow, 0, true);
} else { } else {
@@ -174,8 +178,8 @@ void branch(JIT& dyn, bool cond, s64 address) {
void branch_likely(JIT& dyn, bool cond, s64 address) { void branch_likely(JIT& dyn, bool cond, s64 address) {
Registers& regs = dyn.regs; Registers& regs = dyn.regs;
regs.delaySlot = true;
if (cond) { if (cond) {
regs.delaySlot = true;
regs.nextPC = address; regs.nextPC = address;
} else { } else {
regs.SetPC64(regs.nextPC); 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) { void b(JIT& dyn, u32 instr, bool cond) {
Registers& regs = dyn.regs; Registers& regs = dyn.regs;
s64 offset = (s64)se_imm(instr) << 2; s16 imm = instr;
s64 offset = (s64)imm << 2;
s64 address = regs.pc + offset; s64 address = regs.pc + offset;
branch(dyn, cond, address); branch(dyn, cond, address);
} }
@@ -192,14 +197,16 @@ void b(JIT& dyn, u32 instr, bool cond) {
void blink(JIT& dyn, u32 instr, bool cond) { void blink(JIT& dyn, u32 instr, bool cond) {
Registers& regs = dyn.regs; Registers& regs = dyn.regs;
regs.gpr[31] = regs.nextPC; 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; s64 address = regs.pc + offset;
branch(dyn, cond, address); branch(dyn, cond, address);
} }
void bl(JIT& dyn, u32 instr, bool cond) { void bl(JIT& dyn, u32 instr, bool cond) {
Registers& regs = dyn.regs; Registers& regs = dyn.regs;
s64 offset = (s64)se_imm(instr) << 2; s16 imm = instr;
s64 offset = (s64)imm << 2;
s64 address = regs.pc + offset; s64 address = regs.pc + offset;
branch_likely(dyn, cond, address); 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) { void bllink(JIT& dyn, u32 instr, bool cond) {
Registers& regs = dyn.regs; Registers& regs = dyn.regs;
regs.gpr[31] = regs.nextPC; 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; s64 address = regs.pc + offset;
branch_likely(dyn, cond, address); branch_likely(dyn, cond, address);
} }
@@ -247,7 +255,7 @@ void lh(JIT& dyn, u32 instr) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else { } 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; Mem& mem = dyn.mem;
s16 offset = instr; s16 offset = instr;
u64 address = regs.gpr[RS(instr)] + offset; u64 address = regs.gpr[RS(instr)] + offset;
if (check_address_error(address, 0b11)) { if (check_address_error(0b11, address)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
return; return;
@@ -330,14 +338,20 @@ void ld(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs; Registers& regs = dyn.regs;
Mem& mem = dyn.mem; Mem& mem = dyn.mem;
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b111)) { if (check_address_error(0b111, address)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
return; return;
} }
s64 value = mem.Read64(regs, address); u32 paddr = 0;
regs.gpr[RT(instr)] = value; 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) { void lld(JIT& dyn, u32 instr) {
@@ -402,43 +416,66 @@ void lbu(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs; Registers& regs = dyn.regs;
Mem& mem = dyn.mem; Mem& mem = dyn.mem;
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u8 value = mem.Read8(regs, address); u32 paddr;
regs.gpr[RT(instr)] = value; 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) { void lhu(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs; Registers& regs = dyn.regs;
Mem& mem = dyn.mem; Mem& mem = dyn.mem;
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b1)) { if ((address & 0b1) > 0) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
return; return;
} }
u32 paddr;
u16 value = mem.Read16(regs, address); if (!MapVAddr(regs, LOAD, address, paddr)) {
regs.gpr[RT(instr)] = value; 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) { void lwu(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs; Registers& regs = dyn.regs;
Mem& mem = dyn.mem; Mem& mem = dyn.mem;
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b11)) { if ((address & 0b11) > 0) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
return; return;
} }
u32 value = mem.Read32(regs, address); u32 paddr;
regs.gpr[RT(instr)] = value; 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) { void sb(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs; Registers& regs = dyn.regs;
Mem& mem = dyn.mem; Mem& mem = dyn.mem;
u32 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
mem.Write8(regs, dyn, address, regs.gpr[RT(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) { void sc(JIT& dyn, u32 instr) {
@@ -458,7 +495,7 @@ void sc(JIT& dyn, u32 instr) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } else {
mem.Write32(regs, dyn, paddr, regs.gpr[RT(instr)]); mem.Write32(regs, paddr, regs.gpr[RT(instr)]);
regs.gpr[RT(instr)] = 1; regs.gpr[RT(instr)] = 1;
} }
} else { } else {
@@ -469,37 +506,44 @@ void sc(JIT& dyn, u32 instr) {
void scd(JIT& dyn, u32 instr) { void scd(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs; Registers& regs = dyn.regs;
Mem& mem = dyn.mem; 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; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b111)) { if ((address & 0b111) > 0) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, true); FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
return; return;
} }
if(regs.cop0.llbit) { 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) { void sh(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs; Registers& regs = dyn.regs;
Mem& mem = dyn.mem; Mem& mem = dyn.mem;
s64 address = regs.gpr[RS(instr)] + (s16)instr; 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; u32 physical;
if(!MapVAddr(regs, STORE, address, physical)) { if(!MapVAddr(regs, STORE, address, physical)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } 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; Mem& mem = dyn.mem;
s16 offset = instr; s16 offset = instr;
u64 address = regs.gpr[RS(instr)] + offset; u64 address = regs.gpr[RS(instr)] + offset;
if (check_address_error(address, 0b11)) { if (check_address_error(0b11, address)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, true); FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
return; return;
@@ -519,7 +563,7 @@ void sw(JIT& dyn, u32 instr) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } 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; Registers& regs = dyn.regs;
Mem& mem = dyn.mem; Mem& mem = dyn.mem;
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b11)) { if (check_address_error(0b111, address)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, true); FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
return; return;
@@ -538,9 +582,8 @@ void sd(JIT& dyn, u32 instr) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } else {
mem.Write64(regs, dyn, physical, regs.gpr[RT(instr)]); mem.Write64(regs, physical, regs.gpr[RT(instr)]);
} }
} }
void sdl(JIT& dyn, u32 instr) { void sdl(JIT& dyn, u32 instr) {
@@ -556,7 +599,7 @@ void sdl(JIT& dyn, u32 instr) {
u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
u64 data = mem.Read64(regs, paddr & ~7); u64 data = mem.Read64(regs, paddr & ~7);
u64 rt = regs.gpr[RT(instr)]; 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 mask = 0xFFFFFFFFFFFFFFFF << shift;
u64 data = mem.Read64(regs, paddr & ~7); u64 data = mem.Read64(regs, paddr & ~7);
u64 rt = regs.gpr[RT(instr)]; 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 mask = 0xFFFFFFFF >> shift;
u32 data = mem.Read32(regs, paddr & ~3); u32 data = mem.Read32(regs, paddr & ~3);
u32 rt = regs.gpr[RT(instr)]; 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 mask = 0xFFFFFFFF << shift;
u32 data = mem.Read32(regs, paddr & ~3); u32 data = mem.Read32(regs, paddr & ~3);
u32 rt = regs.gpr[RT(instr)]; 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) { void j(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs; Registers& regs = dyn.regs;
u64 target = (instr & 0x3ffffff) << 2; Mem& mem = dyn.mem;
u64 address = ((regs.pc - 4) & ~0xfffffff) | target; s32 target = (instr & 0x3ffffff) << 2;
s64 address = (regs.oldPC & ~0xfffffff) | target;
branch(dyn, true, address); branch(dyn, true, address);
} }
@@ -648,6 +692,7 @@ void jal(JIT& dyn, u32 instr) {
void jalr(JIT& dyn, u32 instr) { void jalr(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs; Registers& regs = dyn.regs;
Mem& mem = dyn.mem;
branch(dyn, true, regs.gpr[RS(instr)]); branch(dyn, true, regs.gpr[RS(instr)]);
if(likely(RD(instr) != 0)) { if(likely(RD(instr) != 0)) {
regs.gpr[RD(instr)] = regs.pc + 4; regs.gpr[RD(instr)] = regs.pc + 4;
@@ -656,12 +701,14 @@ void jalr(JIT& dyn, u32 instr) {
void slti(JIT& dyn, u32 instr) { void slti(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs; 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) { void sltiu(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs; 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) { void slt(JIT& dyn, u32 instr) {
@@ -812,8 +859,8 @@ void sra(JIT& dyn, u32 instr) {
void srav(JIT& dyn, u32 instr) { void srav(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs; Registers& regs = dyn.regs;
s64 rt = regs.gpr[RT(instr)];
if(likely(RD(instr) != 0)) { if(likely(RD(instr) != 0)) {
s64 rt = regs.gpr[RT(instr)];
s64 rs = regs.gpr[RS(instr)]; s64 rs = regs.gpr[RS(instr)];
u8 sa = rs & 0x1f; u8 sa = rs & 0x1f;
s32 result = rt >> sa; s32 result = rt >> sa;
@@ -855,11 +902,6 @@ void dsra32(JIT& dyn, u32 instr) {
void jr(JIT& dyn, u32 instr) { void jr(JIT& dyn, u32 instr) {
Registers& regs = dyn.regs; Registers& regs = dyn.regs;
s64 address = regs.gpr[RS(instr)]; 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); branch(dyn, true, address);
} }
@@ -972,9 +1014,8 @@ void mthi(JIT& dyn, u32 instr) {
} }
void trap(JIT& dyn, bool cond) { void trap(JIT& dyn, bool cond) {
Registers& regs = dyn.regs;
if(cond) { 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); InterruptLower(mem.mmio.mi, regs, Interrupt::SI);
break; break;
default: 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_cop = (instr >> 21) & 0x1F;
u8 mask_cop2 = instr & 0x3F; u8 mask_cop2 = instr & 0x3F;
switch(mask_cop) { switch(mask_cop) {

View File

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

View File

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