JIT: Passing first 2 tests in basic_simpleboot
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)®s.gpr[(x)] - (uintptr_t)®s)
|
#define GPR_OFFSET(x, jit) ((uintptr_t)®s.gpr[(x)] - (uintptr_t)jit)
|
||||||
#define REG_OFFSET(kind) ((uintptr_t)®s.kind - (uintptr_t)®s)
|
#define REG_OFFSET(kind, jit) ((uintptr_t)®s.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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
@@ -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)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
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;
|
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;
|
||||||
|
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;
|
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)) {
|
||||||
|
HandleTLBException(regs, address);
|
||||||
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||||
|
} else {
|
||||||
|
u16 value = mem.Read16(regs, paddr);
|
||||||
regs.gpr[RT(instr)] = value;
|
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;
|
||||||
|
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;
|
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.gpr[RT(instr)] = (s64)((u64)regs.cop0.llbit);
|
|
||||||
regs.cop0.llbit = false;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
if(likely(RD(instr) != 0)) {
|
|
||||||
s64 rt = regs.gpr[RT(instr)];
|
s64 rt = regs.gpr[RT(instr)];
|
||||||
|
if(likely(RD(instr) != 0)) {
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
Reference in New Issue
Block a user