More JIT work
This commit is contained in:
@@ -34,8 +34,9 @@ Fn JIT::Recompile() {
|
||||
bool stable = true;
|
||||
cycles = 0;
|
||||
prologue();
|
||||
mov(rbp, u64(this));
|
||||
mov(rdi, u64(this) + offsetof(JIT, regs));
|
||||
while(stable) {
|
||||
mov(rdi, u64(this) + offsetof(JIT, regs));
|
||||
cycles++;
|
||||
CheckCompareInterrupt();
|
||||
|
||||
|
||||
@@ -23,6 +23,33 @@ private:
|
||||
void CheckCompareInterrupt() override;
|
||||
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) {
|
||||
u8 mask = (instr >> 26) & 0x3f;
|
||||
switch(mask) {
|
||||
@@ -70,6 +97,10 @@ private:
|
||||
LT, GT, GE, LE, EQ, NE
|
||||
};
|
||||
|
||||
u8 Read8(u64 addr) {
|
||||
return mem.Read8(regs, addr);
|
||||
}
|
||||
|
||||
void cop2Decode(u32);
|
||||
void special(u32);
|
||||
void regimm(u32);
|
||||
@@ -82,22 +113,22 @@ private:
|
||||
void and_(u32);
|
||||
void emitCondition(const std::string&, BranchCond);
|
||||
template <class T>
|
||||
void branch(const Xbyak::Operand&, const T&, s64, BranchCond);
|
||||
void branch(const Xbyak::Reg64&, const T&, s64, BranchCond);
|
||||
|
||||
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>
|
||||
void b(u32, const Xbyak::Operand&, const T&, BranchCond);
|
||||
void b(u32, const Xbyak::Reg64&, const T&, BranchCond);
|
||||
|
||||
template <class T>
|
||||
void blink(u32, const Xbyak::Operand&, const T&, BranchCond);
|
||||
void blink(u32, const Xbyak::Reg64&, const T&, BranchCond);
|
||||
|
||||
template <class T>
|
||||
void bl(u32, const Xbyak::Operand&, const T&, BranchCond);
|
||||
void bl(u32, const Xbyak::Reg64&, const T&, BranchCond);
|
||||
|
||||
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 daddu(u32);
|
||||
void daddi(u32);
|
||||
|
||||
@@ -168,10 +168,24 @@ void JIT::Emit(u32 instr) {
|
||||
case 0x10: regs.cop0.decode(*this, instr); break;
|
||||
case 0x11: regs.cop1.decode(*this, instr); break;
|
||||
case 0x12: cop2Decode(instr); break;
|
||||
case 0x14: bl(instr, regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); break;
|
||||
case 0x15: bl(instr, regs.gpr[RS(instr)] != regs.gpr[RT(instr)]); break;
|
||||
case 0x16: bl(instr, regs.gpr[RS(instr)] <= 0); break;
|
||||
case 0x17: bl(instr, regs.gpr[RS(instr)] > 0); break;
|
||||
case 0x14: {
|
||||
mov(rax, GPR(RS(instr)));
|
||||
mov(rcx, GPR(RT(instr)));
|
||||
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 0x19: daddiu(instr); break;
|
||||
case 0x1A: ldl(instr); break;
|
||||
|
||||
@@ -61,40 +61,40 @@ void JIT::div(u32 instr) {
|
||||
movsxd(rax, dword[rdi + offsetof(Registers, gpr[RS(instr)])]); // dividend
|
||||
movsxd(rcx, dword[rdi + offsetof(Registers, gpr[RT(instr)])]); // divisor
|
||||
cmp(rcx, 0);
|
||||
je("divisor==0");
|
||||
je("div_divisor==0");
|
||||
|
||||
CodeGenerator::div(rcx);
|
||||
mov(qword[rdi + offsetof(Registers, lo)], eax);
|
||||
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);
|
||||
cmp(rax, 0);
|
||||
jge("dividend>=0");
|
||||
jge("div_dividend>=0");
|
||||
mov(qword[rdi + offsetof(Registers, lo)], s64(1));
|
||||
L("dividend>=0");
|
||||
L("div_dividend>=0");
|
||||
mov(qword[rdi + offsetof(Registers, lo)], s64(-1));
|
||||
|
||||
L("exit");
|
||||
L("div_exit");
|
||||
}
|
||||
|
||||
void JIT::divu(u32 instr) {
|
||||
movsxd(rax, dword[rdi + offsetof(Registers, gpr[RS(instr)])]); // dividend
|
||||
movsxd(rcx, dword[rdi + offsetof(Registers, gpr[RT(instr)])]); // divisor
|
||||
cmp(rcx, 0);
|
||||
je("divisor==0");
|
||||
je("divu_divisor==0");
|
||||
|
||||
CodeGenerator::div(rcx);
|
||||
mov(qword[rdi + offsetof(Registers, lo)], eax);
|
||||
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, lo)], -1);
|
||||
|
||||
L("exit");
|
||||
L("divu_exit");
|
||||
}
|
||||
|
||||
void JIT::ddiv(u32 instr) {
|
||||
@@ -108,39 +108,39 @@ void JIT::ddiv(u32 instr) {
|
||||
CodeGenerator::xor_(r10, r8);
|
||||
CodeGenerator::xor_(r9, r10);
|
||||
cmp(rcx, 0);
|
||||
je("else if");
|
||||
je("ddiv_else_if");
|
||||
cmp(r9, 1);
|
||||
jne("else");
|
||||
jne("ddiv_else");
|
||||
mov(qword[rdi + offsetof(Registers, lo)], rax);
|
||||
mov(qword[rdi + offsetof(Registers, hi)], 0);
|
||||
jmp("exit");
|
||||
L("else if");
|
||||
jmp("ddiv_exit");
|
||||
L("ddiv_else_if");
|
||||
mov(qword[rdi + offsetof(Registers, hi)], rax);
|
||||
cmp(rax, 0);
|
||||
jge("dividend>=0");
|
||||
jge("ddiv_dividend>=0");
|
||||
mov(qword[rdi + offsetof(Registers, lo)], 1);
|
||||
L("dividend>=0");
|
||||
L("ddiv_dividend>=0");
|
||||
mov(qword[rdi + offsetof(Registers, lo)], -1);
|
||||
L("else");
|
||||
L("ddiv_else");
|
||||
CodeGenerator::div(rcx);
|
||||
mov(qword[rdi + offsetof(Registers, lo)], rax);
|
||||
mov(qword[rdi + offsetof(Registers, hi)], rdx);
|
||||
L("exit");
|
||||
L("ddiv_exit");
|
||||
}
|
||||
|
||||
void JIT::ddivu(u32 instr) {
|
||||
mov(rax, GPR(RS(instr)));
|
||||
mov(rcx, GPR(RT(instr)));
|
||||
cmp(rcx, 0);
|
||||
je("divisor==0");
|
||||
je("ddivu_divisor==0");
|
||||
CodeGenerator::div(rcx);
|
||||
mov(qword[rdi + offsetof(Registers, lo)], rax);
|
||||
mov(qword[rdi + offsetof(Registers, hi)], rdx);
|
||||
jmp("exit");
|
||||
L("divisor==0");
|
||||
jmp("ddivu_exit");
|
||||
L("ddivu_divisor==0");
|
||||
mov(qword[rdi + offsetof(Registers, lo)], -1);
|
||||
mov(qword[rdi + offsetof(Registers, hi)], rax);
|
||||
L("exit");
|
||||
L("ddivu_exit");
|
||||
}
|
||||
|
||||
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>
|
||||
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);
|
||||
emitCondition("false", cond);
|
||||
emitCondition("branch_false", cond);
|
||||
|
||||
mov(byte[rdi + offsetof(Registers, delaySlot)], 1);
|
||||
mov(rax, qword[rdi + offsetof(Registers, pc)]);
|
||||
CodeGenerator::add(rax, offset);
|
||||
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<int>(const Xbyak::Operand& op1, const int& 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::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)]);
|
||||
cmp(op1, op2);
|
||||
emitCondition("false", cond);
|
||||
emitCondition("branch_likely_false", cond);
|
||||
|
||||
mov(byte[rdi + offsetof(Registers, delaySlot)], 1);
|
||||
CodeGenerator::add(rax, offset);
|
||||
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(rcx, qword[rdi + offsetof(Registers, nextPC)]);
|
||||
mov(qword[rdi + offsetof(Registers, pc)], rcx);
|
||||
CodeGenerator::add(rcx, 4);
|
||||
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;
|
||||
s64 offset = u64((s64)imm) << 2;
|
||||
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;
|
||||
s64 offset = u64((s64)imm) << 2;
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
s64 offset = u64((s64)imm) << 2;
|
||||
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(GPR(31), rcx);
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
u64 val = s64(s16(instr));
|
||||
val <<= 16;
|
||||
@@ -235,14 +255,36 @@ void JIT::lui(u32 instr) {
|
||||
}
|
||||
|
||||
void JIT::lb(u32 instr) {
|
||||
u64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
u32 paddr = 0;
|
||||
if(!MapVAddr(regs, LOAD, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||
} else {
|
||||
regs.gpr[RT(instr)] = (s8)mem.Read8(regs, paddr);
|
||||
}
|
||||
mov(rdx, GPR(RS(instr)));
|
||||
CodeGenerator::add(rdx, s64(s16(instr)));
|
||||
mov(rsi, LOAD);
|
||||
push(rcx);
|
||||
lea(rcx, dword[rbp-4]);
|
||||
call(MapVAddr);
|
||||
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) {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <log.hpp>
|
||||
|
||||
namespace n64 {
|
||||
using namespace Xbyak;
|
||||
Cop1::Cop1() {
|
||||
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) {
|
||||
Registers ®s = cpu.regs;
|
||||
if(!regs.cop0.status.cu1) {
|
||||
@@ -197,13 +203,22 @@ void Cop1::decodeJIT(JIT &cpu, u32 instr) {
|
||||
case 0x06: ctc1(regs, instr); break;
|
||||
case 0x07: FireException(regs, ExceptionCode::ReservedInstruction, 1, true); break;
|
||||
case 0x08:
|
||||
switch(mask_branch) {
|
||||
case 0: cpu.b(instr, !regs.cop1.fcr31.compare); 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;
|
||||
/*switch(mask_branch) {
|
||||
case 0: {
|
||||
cpu.mov(cpu.rax, REG(byte, cop1.fcr31.compare));
|
||||
cpu.b(instr, !regs.cop1.fcr31.compare);
|
||||
} 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);
|
||||
}
|
||||
}*/
|
||||
break;
|
||||
case 0x10: // s
|
||||
switch(mask_fun) {
|
||||
|
||||
Reference in New Issue
Block a user