More JIT work

This commit is contained in:
SimoneN64
2023-08-28 20:12:17 +02:00
parent 92342feeda
commit 28d49812fa
5 changed files with 164 additions and 61 deletions

View File

@@ -34,8 +34,9 @@ Fn JIT::Recompile() {
bool stable = true; bool stable = true;
cycles = 0; cycles = 0;
prologue(); prologue();
mov(rbp, u64(this));
mov(rdi, u64(this) + offsetof(JIT, regs));
while(stable) { while(stable) {
mov(rdi, u64(this) + offsetof(JIT, regs));
cycles++; cycles++;
CheckCompareInterrupt(); CheckCompareInterrupt();

View File

@@ -23,6 +23,33 @@ private:
void CheckCompareInterrupt() override; void CheckCompareInterrupt() override;
Fn Recompile(); Fn Recompile();
template<class T>
void emitMemberCall(T func, void* thisObj) {
void* funcPtr;
auto thisPtr = reinterpret_cast<uintptr_t>(thisObj);
/*#ifdef ABI_WINDOWS
static_assert(sizeof(T) == 8, "[JIT]: Invalid size for member function pointer");
std::memcpy(&funcPtr, &func, sizeof(T));
#elif defined(ABI_UNIX)
static_assert(sizeof(T) == 16, "[JIT]: Invalid size for member function pointer");
uintptr_t tmpArr[2];
std::memcpy(tmpArr, &func, sizeof(T));
funcPtr = reinterpret_cast<void*>(tmpArr[0]);
thisPtr += tmpArr[1];
#else
Util::panic("Huh?!");
#endif*/
push(rdi);
if(thisPtr == reinterpret_cast<uintptr_t>(this)) {
mov(rdi, rbp);
} else {
mov(rdi, (uintptr_t)thisPtr);
}
call(funcPtr);
pop(rdi);
}
bool isStable(u32 instr) { bool isStable(u32 instr) {
u8 mask = (instr >> 26) & 0x3f; u8 mask = (instr >> 26) & 0x3f;
switch(mask) { switch(mask) {
@@ -70,6 +97,10 @@ private:
LT, GT, GE, LE, EQ, NE LT, GT, GE, LE, EQ, NE
}; };
u8 Read8(u64 addr) {
return mem.Read8(regs, addr);
}
void cop2Decode(u32); void cop2Decode(u32);
void special(u32); void special(u32);
void regimm(u32); void regimm(u32);
@@ -82,22 +113,22 @@ private:
void and_(u32); void and_(u32);
void emitCondition(const std::string&, BranchCond); void emitCondition(const std::string&, BranchCond);
template <class T> template <class T>
void branch(const Xbyak::Operand&, const T&, s64, BranchCond); void branch(const Xbyak::Reg64&, const T&, s64, BranchCond);
template <class T> template <class T>
void branch_likely(const Xbyak::Operand&, const T&, s64, BranchCond); void branch_likely(const Xbyak::Reg64&, const T&, s64, BranchCond);
template <class T> template <class T>
void b(u32, const Xbyak::Operand&, const T&, BranchCond); void b(u32, const Xbyak::Reg64&, const T&, BranchCond);
template <class T> template <class T>
void blink(u32, const Xbyak::Operand&, const T&, BranchCond); void blink(u32, const Xbyak::Reg64&, const T&, BranchCond);
template <class T> template <class T>
void bl(u32, const Xbyak::Operand&, const T&, BranchCond); void bl(u32, const Xbyak::Reg64&, const T&, BranchCond);
template <class T> template <class T>
void bllink(u32, const Xbyak::Operand&, const T&, BranchCond); void bllink(u32, const Xbyak::Reg64&, const T&, BranchCond);
void dadd(u32); void dadd(u32);
void daddu(u32); void daddu(u32);
void daddi(u32); void daddi(u32);

View File

@@ -168,10 +168,24 @@ void JIT::Emit(u32 instr) {
case 0x10: regs.cop0.decode(*this, instr); break; case 0x10: regs.cop0.decode(*this, instr); break;
case 0x11: regs.cop1.decode(*this, instr); break; case 0x11: regs.cop1.decode(*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: {
case 0x15: bl(instr, regs.gpr[RS(instr)] != regs.gpr[RT(instr)]); break; mov(rax, GPR(RS(instr)));
case 0x16: bl(instr, regs.gpr[RS(instr)] <= 0); break; mov(rcx, GPR(RT(instr)));
case 0x17: bl(instr, regs.gpr[RS(instr)] > 0); break; bl(instr, rax, rcx, EQ);
} break;
case 0x15: {
mov(rax, GPR(RS(instr)));
mov(rcx, GPR(RT(instr)));
bl(instr, rax, rcx, NE);
} break;
case 0x16: {
mov(rax, GPR(RS(instr)));
bl(instr, rax, 0, LE);
} break;
case 0x17: {
mov(rax, GPR(RS(instr)));
bl(instr, rax, 0, GT);
} break;
case 0x18: daddi(instr); break; case 0x18: daddi(instr); break;
case 0x19: daddiu(instr); break; case 0x19: daddiu(instr); break;
case 0x1A: ldl(instr); break; case 0x1A: ldl(instr); break;

View File

@@ -61,40 +61,40 @@ void JIT::div(u32 instr) {
movsxd(rax, dword[rdi + offsetof(Registers, gpr[RS(instr)])]); // dividend movsxd(rax, dword[rdi + offsetof(Registers, gpr[RS(instr)])]); // dividend
movsxd(rcx, dword[rdi + offsetof(Registers, gpr[RT(instr)])]); // divisor movsxd(rcx, dword[rdi + offsetof(Registers, gpr[RT(instr)])]); // divisor
cmp(rcx, 0); cmp(rcx, 0);
je("divisor==0"); je("div_divisor==0");
CodeGenerator::div(rcx); CodeGenerator::div(rcx);
mov(qword[rdi + offsetof(Registers, lo)], eax); mov(qword[rdi + offsetof(Registers, lo)], eax);
mov(qword[rdi + offsetof(Registers, hi)], edx); mov(qword[rdi + offsetof(Registers, hi)], edx);
jmp("exit"); jmp("div_exit");
L("divisor==0"); L("div_divisor==0");
mov(qword[rdi + offsetof(Registers, hi)], rax); mov(qword[rdi + offsetof(Registers, hi)], rax);
cmp(rax, 0); cmp(rax, 0);
jge("dividend>=0"); jge("div_dividend>=0");
mov(qword[rdi + offsetof(Registers, lo)], s64(1)); mov(qword[rdi + offsetof(Registers, lo)], s64(1));
L("dividend>=0"); L("div_dividend>=0");
mov(qword[rdi + offsetof(Registers, lo)], s64(-1)); mov(qword[rdi + offsetof(Registers, lo)], s64(-1));
L("exit"); L("div_exit");
} }
void JIT::divu(u32 instr) { void JIT::divu(u32 instr) {
movsxd(rax, dword[rdi + offsetof(Registers, gpr[RS(instr)])]); // dividend movsxd(rax, dword[rdi + offsetof(Registers, gpr[RS(instr)])]); // dividend
movsxd(rcx, dword[rdi + offsetof(Registers, gpr[RT(instr)])]); // divisor movsxd(rcx, dword[rdi + offsetof(Registers, gpr[RT(instr)])]); // divisor
cmp(rcx, 0); cmp(rcx, 0);
je("divisor==0"); je("divu_divisor==0");
CodeGenerator::div(rcx); CodeGenerator::div(rcx);
mov(qword[rdi + offsetof(Registers, lo)], eax); mov(qword[rdi + offsetof(Registers, lo)], eax);
mov(qword[rdi + offsetof(Registers, hi)], edx); mov(qword[rdi + offsetof(Registers, hi)], edx);
jmp("exit"); jmp("divu_exit");
L("divisor==0"); L("divu_divisor==0");
mov(qword[rdi + offsetof(Registers, hi)], rax); mov(qword[rdi + offsetof(Registers, hi)], rax);
mov(qword[rdi + offsetof(Registers, lo)], -1); mov(qword[rdi + offsetof(Registers, lo)], -1);
L("exit"); L("divu_exit");
} }
void JIT::ddiv(u32 instr) { void JIT::ddiv(u32 instr) {
@@ -108,39 +108,39 @@ void JIT::ddiv(u32 instr) {
CodeGenerator::xor_(r10, r8); CodeGenerator::xor_(r10, r8);
CodeGenerator::xor_(r9, r10); CodeGenerator::xor_(r9, r10);
cmp(rcx, 0); cmp(rcx, 0);
je("else if"); je("ddiv_else_if");
cmp(r9, 1); cmp(r9, 1);
jne("else"); jne("ddiv_else");
mov(qword[rdi + offsetof(Registers, lo)], rax); mov(qword[rdi + offsetof(Registers, lo)], rax);
mov(qword[rdi + offsetof(Registers, hi)], 0); mov(qword[rdi + offsetof(Registers, hi)], 0);
jmp("exit"); jmp("ddiv_exit");
L("else if"); L("ddiv_else_if");
mov(qword[rdi + offsetof(Registers, hi)], rax); mov(qword[rdi + offsetof(Registers, hi)], rax);
cmp(rax, 0); cmp(rax, 0);
jge("dividend>=0"); jge("ddiv_dividend>=0");
mov(qword[rdi + offsetof(Registers, lo)], 1); mov(qword[rdi + offsetof(Registers, lo)], 1);
L("dividend>=0"); L("ddiv_dividend>=0");
mov(qword[rdi + offsetof(Registers, lo)], -1); mov(qword[rdi + offsetof(Registers, lo)], -1);
L("else"); L("ddiv_else");
CodeGenerator::div(rcx); CodeGenerator::div(rcx);
mov(qword[rdi + offsetof(Registers, lo)], rax); mov(qword[rdi + offsetof(Registers, lo)], rax);
mov(qword[rdi + offsetof(Registers, hi)], rdx); mov(qword[rdi + offsetof(Registers, hi)], rdx);
L("exit"); L("ddiv_exit");
} }
void JIT::ddivu(u32 instr) { void JIT::ddivu(u32 instr) {
mov(rax, GPR(RS(instr))); mov(rax, GPR(RS(instr)));
mov(rcx, GPR(RT(instr))); mov(rcx, GPR(RT(instr)));
cmp(rcx, 0); cmp(rcx, 0);
je("divisor==0"); je("ddivu_divisor==0");
CodeGenerator::div(rcx); CodeGenerator::div(rcx);
mov(qword[rdi + offsetof(Registers, lo)], rax); mov(qword[rdi + offsetof(Registers, lo)], rax);
mov(qword[rdi + offsetof(Registers, hi)], rdx); mov(qword[rdi + offsetof(Registers, hi)], rdx);
jmp("exit"); jmp("ddivu_exit");
L("divisor==0"); L("ddivu_divisor==0");
mov(qword[rdi + offsetof(Registers, lo)], -1); mov(qword[rdi + offsetof(Registers, lo)], -1);
mov(qword[rdi + offsetof(Registers, hi)], rax); mov(qword[rdi + offsetof(Registers, hi)], rax);
L("exit"); L("ddivu_exit");
} }
void JIT::emitCondition(const std::string& name, BranchCond cond) { void JIT::emitCondition(const std::string& name, BranchCond cond) {
@@ -167,46 +167,55 @@ void JIT::emitCondition(const std::string& name, BranchCond cond) {
} }
template <class T> template <class T>
void JIT::branch(const Xbyak::Operand& op1, const T& op2, s64 offset, BranchCond cond) { void JIT::branch(const Xbyak::Reg64& op1, const T& op2, s64 offset, BranchCond cond) {
cmp(op1, op2); cmp(op1, op2);
emitCondition("false", cond); emitCondition("branch_false", cond);
mov(byte[rdi + offsetof(Registers, delaySlot)], 1); mov(byte[rdi + offsetof(Registers, delaySlot)], 1);
mov(rax, qword[rdi + offsetof(Registers, pc)]); mov(rax, qword[rdi + offsetof(Registers, pc)]);
CodeGenerator::add(rax, offset); CodeGenerator::add(rax, offset);
mov(qword[rdi + offsetof(Registers, nextPC)], rax); mov(qword[rdi + offsetof(Registers, nextPC)], rax);
L("false"); L("branch_false");
} }
template void JIT::branch<Xbyak::Operand>(const Xbyak::Operand& op1, const Xbyak::Operand& op2, s64 offset, BranchCond cond); template void JIT::branch<Xbyak::Reg64>(const Xbyak::Reg64& op1, const Xbyak::Reg64& op2, s64 offset, BranchCond cond);
template void JIT::branch<int>(const Xbyak::Operand& op1, const int& op2, s64 offset, BranchCond cond); template void JIT::branch<int>(const Xbyak::Reg64& op1, const int& op2, s64 offset, BranchCond cond);
void JIT::branch_likely(const Xbyak::Operand& op1, const Xbyak::Operand& op2, s64 offset, BranchCond cond) { template <class T>
void JIT::branch_likely(const Xbyak::Reg64& op1, const T& op2, s64 offset, BranchCond cond) {
mov(rax, qword[rdi + offsetof(Registers, pc)]); mov(rax, qword[rdi + offsetof(Registers, pc)]);
cmp(op1, op2); cmp(op1, op2);
emitCondition("false", cond); emitCondition("branch_likely_false", cond);
mov(byte[rdi + offsetof(Registers, delaySlot)], 1); mov(byte[rdi + offsetof(Registers, delaySlot)], 1);
CodeGenerator::add(rax, offset); CodeGenerator::add(rax, offset);
mov(qword[rdi + offsetof(Registers, nextPC)], rax); mov(qword[rdi + offsetof(Registers, nextPC)], rax);
jmp("exit"); jmp("branch_likely_exit");
L("false"); L("branch_likely_false");
mov(qword[rdi + offsetof(Registers, oldPC)], rax); mov(qword[rdi + offsetof(Registers, oldPC)], rax);
mov(rcx, qword[rdi + offsetof(Registers, nextPC)]); mov(rcx, qword[rdi + offsetof(Registers, nextPC)]);
mov(qword[rdi + offsetof(Registers, pc)], rcx); mov(qword[rdi + offsetof(Registers, pc)], rcx);
CodeGenerator::add(rcx, 4); CodeGenerator::add(rcx, 4);
mov(qword[rdi + offsetof(Registers, nextPC)], rcx); mov(qword[rdi + offsetof(Registers, nextPC)], rcx);
L("exit"); L("branch_likely_exit");
} }
void JIT::b(u32 instr, const Xbyak::Operand& op1, const Xbyak::Operand& op2, BranchCond cond) { template void JIT::branch_likely<Xbyak::Reg64>(const Xbyak::Reg64& op1, const Xbyak::Reg64& op2, s64 offset, BranchCond cond);
template void JIT::branch_likely<int>(const Xbyak::Reg64& op1, const int& op2, s64 offset, BranchCond cond);
template <class T>
void JIT::b(u32 instr, const Xbyak::Reg64& op1, const T& op2, BranchCond cond) {
s16 imm = instr; s16 imm = instr;
s64 offset = u64((s64)imm) << 2; s64 offset = u64((s64)imm) << 2;
branch(op1, op2, offset, cond); branch(op1, op2, offset, cond);
} }
void JIT::blink(u32 instr, const Xbyak::Operand& op1, const Xbyak::Operand& op2, BranchCond cond) { template void JIT::b<Xbyak::Reg64>(u32, const Xbyak::Reg64& op1, const Xbyak::Reg64& op2, BranchCond cond);
template void JIT::b<int>(u32, const Xbyak::Reg64& op1, const int& op2, BranchCond cond);
template <class T>
void JIT::blink(u32 instr, const Xbyak::Reg64& op1, const T& op2, BranchCond cond) {
s16 imm = instr; s16 imm = instr;
s64 offset = u64((s64)imm) << 2; s64 offset = u64((s64)imm) << 2;
mov(rcx, qword[rdi + offsetof(Registers, nextPC)]); mov(rcx, qword[rdi + offsetof(Registers, nextPC)]);
@@ -214,13 +223,21 @@ void JIT::blink(u32 instr, const Xbyak::Operand& op1, const Xbyak::Operand& op2,
branch(op1, op2, offset, cond); branch(op1, op2, offset, cond);
} }
void JIT::bl(u32 instr, const Xbyak::Operand& op1, const Xbyak::Operand& op2, BranchCond cond) { template void JIT::blink<Xbyak::Reg64>(u32, const Xbyak::Reg64& op1, const Xbyak::Reg64& op2, BranchCond cond);
template void JIT::blink<int>(u32, const Xbyak::Reg64& op1, const int& op2, BranchCond cond);
template <class T>
void JIT::bl(u32 instr, const Xbyak::Reg64& op1, const T& op2, BranchCond cond) {
s16 imm = instr; s16 imm = instr;
s64 offset = u64((s64)imm) << 2; s64 offset = u64((s64)imm) << 2;
branch_likely(op1, op2, offset, cond); branch_likely(op1, op2, offset, cond);
} }
void JIT::bllink(u32 instr, const Xbyak::Operand& op1, const Xbyak::Operand& op2, BranchCond cond) { template void JIT::bl<Xbyak::Reg64>(u32, const Xbyak::Reg64& op1, const Xbyak::Reg64& op2, BranchCond cond);
template void JIT::bl<int>(u32, const Xbyak::Reg64& op1, const int& op2, BranchCond cond);
template <class T>
void JIT::bllink(u32 instr, const Xbyak::Reg64& op1, const T& op2, BranchCond cond) {
mov(rcx, qword[rdi + offsetof(Registers, nextPC)]); mov(rcx, qword[rdi + offsetof(Registers, nextPC)]);
mov(GPR(31), rcx); mov(GPR(31), rcx);
s16 imm = instr; s16 imm = instr;
@@ -228,6 +245,9 @@ void JIT::bllink(u32 instr, const Xbyak::Operand& op1, const Xbyak::Operand& op2
branch_likely(op1, op2, offset, cond); branch_likely(op1, op2, offset, cond);
} }
template void JIT::bllink<Xbyak::Reg64>(u32, const Xbyak::Reg64& op1, const Xbyak::Reg64& op2, BranchCond cond);
template void JIT::bllink<int>(u32, const Xbyak::Reg64& op1, const int& op2, BranchCond cond);
void JIT::lui(u32 instr) { void JIT::lui(u32 instr) {
u64 val = s64(s16(instr)); u64 val = s64(s16(instr));
val <<= 16; val <<= 16;
@@ -235,14 +255,36 @@ void JIT::lui(u32 instr) {
} }
void JIT::lb(u32 instr) { void JIT::lb(u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; mov(rdx, GPR(RS(instr)));
u32 paddr = 0; CodeGenerator::add(rdx, s64(s16(instr)));
if(!MapVAddr(regs, LOAD, address, paddr)) { mov(rsi, LOAD);
HandleTLBException(regs, address); push(rcx);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); lea(rcx, dword[rbp-4]);
} else { call(MapVAddr);
regs.gpr[RT(instr)] = (s8)mem.Read8(regs, paddr); pop(rcx);
} cmp(rax, 0);
je("lb_exception");
mov(rsi, dword[rbp-4]);
push(rcx);
emitMemberCall(&JIT::Read8, this);
pop(rcx);
mov(GPR(RT(instr)), rax.cvt8());
L("lb_exception");
mov(rsi, rdx);
push(rax);
call(HandleTLBException);
pop(rax);
push(rsi);
mov(rdi, REG(byte, cop0.tlbError));
mov(rsi, LOAD);
call(GetTLBExceptionCode);
pop(rsi);
mov(rsi, rax);
mov(rdx, 0);
mov(rcx, 1);
push(rax);
call(FireException);
pop(rax);
} }
void JIT::lh(u32 instr) { void JIT::lh(u32 instr) {

View File

@@ -5,6 +5,7 @@
#include <log.hpp> #include <log.hpp>
namespace n64 { namespace n64 {
using namespace Xbyak;
Cop1::Cop1() { Cop1::Cop1() {
Reset(); Reset();
} }
@@ -176,6 +177,11 @@ void Cop1::decodeInterp(Interpreter &cpu, u32 instr) {
} }
} }
#ifdef REG
#undef REG
#define REG(ptr, member) cpu.ptr[cpu.rdi + offsetof(Registers, member)]
#endif
void Cop1::decodeJIT(JIT &cpu, u32 instr) { void Cop1::decodeJIT(JIT &cpu, u32 instr) {
Registers &regs = cpu.regs; Registers &regs = cpu.regs;
if(!regs.cop0.status.cu1) { if(!regs.cop0.status.cu1) {
@@ -197,13 +203,22 @@ void Cop1::decodeJIT(JIT &cpu, u32 instr) {
case 0x06: ctc1(regs, instr); break; case 0x06: ctc1(regs, instr); break;
case 0x07: FireException(regs, ExceptionCode::ReservedInstruction, 1, true); break; case 0x07: FireException(regs, ExceptionCode::ReservedInstruction, 1, true); break;
case 0x08: case 0x08:
switch(mask_branch) { /*switch(mask_branch) {
case 0: cpu.b(instr, !regs.cop1.fcr31.compare); break; case 0: {
case 1: cpu.b(instr, regs.cop1.fcr31.compare); break; cpu.mov(cpu.rax, REG(byte, cop1.fcr31.compare));
case 2: cpu.bl(instr, !regs.cop1.fcr31.compare); break; cpu.b(instr, !regs.cop1.fcr31.compare);
case 3: cpu.bl(instr, regs.cop1.fcr31.compare); break; } break;
case 1: {
cpu.b(instr, regs.cop1.fcr31.compare);
} break;
case 2: {
cpu.bl(instr, !regs.cop1.fcr31.compare);
} break;
case 3: {
cpu.bl(instr, regs.cop1.fcr31.compare);
} break;
default: Util::panic("Undefined BC COP1 {:02X}", mask_branch); default: Util::panic("Undefined BC COP1 {:02X}", mask_branch);
} }*/
break; break;
case 0x10: // s case 0x10: // s
switch(mask_fun) { switch(mask_fun) {