[JIT]: First compiled block! Figure out why scheduling an event from the emitted code makes the underlying queue point to 0x0...

This commit is contained in:
SimoneN64
2025-01-20 22:27:18 +01:00
parent e065558147
commit f67f968f91
10 changed files with 452 additions and 290 deletions

View File

@@ -22,22 +22,52 @@ void JIT::CheckCompareInterrupt() {
}
}
void JIT::InvalidateBlock(const u32 paddr) {
if (const u32 index = paddr >> kUpperShift; !blockCache[index].empty())
blockCache[index].erase(blockCache[index].begin(), blockCache[index].end());
}
int JIT::Step() {
blockPC = regs.pc;
u32 paddr = 0;
if (!blockCache[blockPC >> 8].empty()) {
if (blockCache[blockPC >> 8][blockPC >> 20]) {
return blockCache[blockPC >> 8][blockPC >> 20]();
}
} else {
blockCache[blockPC >> 8].resize(kLowerSize);
if (!regs.cop0.MapVAddr(Cop0::LOAD, blockPC, paddr)) {
/*regs.cop0.HandleTLBException(blockPC);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, blockPC);
return 1;*/
Util::panic(
"[JIT]: Unhandled exception TLB exception {} when retrieving PC physical address! (virtual: 0x{:016lX})",
static_cast<int>(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD)), static_cast<u64>(blockPC));
}
regs.block_delaySlot = false;
u32 upperIndex = paddr >> kUpperShift;
u32 lowerIndex = paddr & 0xff;
u32 instruction;
if (!blockCache[upperIndex].empty()) {
if (blockCache[upperIndex][lowerIndex]) {
return blockCache[upperIndex][lowerIndex]();
}
} else {
blockCache[upperIndex].resize(kLowerSize);
}
do {
const auto block = code.getCurr<BlockFn>();
blockCache[upperIndex][lowerIndex] = block;
code.setProtectModeRW();
u32 instructionsInBlock = 0;
bool instrEndsBlock = false;
bool instrInDelaySlot = false;
bool branchWasLikely = false;
bool blockEndsOnBranch = false;
code.sub(code.rsp, 56);
code.push(code.rbp);
code.mov(code.rbp, reinterpret_cast<uintptr_t>(this)); // Load context pointer
while (!instrInDelaySlot) {
// CheckCompareInterrupt();
if (check_address_error(0b11, u64(blockPC))) [[unlikely]] {
@@ -45,37 +75,61 @@ int JIT::Step() {
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, blockPC);
return 1;*/
Util::panic("[JIT]: Unhandled exception ADL due to unaligned PC virtual value! (0x{:016lX})",
static_cast<u64>(regs.pc));
Util::panic("[JIT]: Unhandled exception ADL due to unaligned PC virtual value! (0x{:016lX})", blockPC);
}
u32 paddr = 0;
if (!regs.cop0.MapVAddr(Cop0::LOAD, blockPC, paddr)) {
/*regs.cop0.HandleTLBException(blockPC);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, blockPC);
return 1;*/
Util::panic(
"[JIT]: Unhandled exception TLB exception {} when retrieving PC physical address! (virtual: 0x{:016lX})",
static_cast<int>(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD)), static_cast<u64>(regs.pc));
static_cast<int>(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD)), static_cast<u64>(blockPC));
}
instruction = mem.Read<u32>(regs, paddr);
const u32 instruction = mem.Read<u32>(regs, paddr);
/*if(ShouldServiceInterrupt()) {
regs.cop0.FireException(ExceptionCode::Interrupt, 0, regs.pc);
regs.cop0.FireException(ExceptionCode::Interrupt, 0, blockPC);
return 1;
}*/
blockPC += 4;
instructionsInBlock++;
Emit(instruction);
instrInDelaySlot = instrEndsBlock;
instrEndsBlock = InstrEndsBlock(instruction);
if (instrEndsBlock) {
branchWasLikely = IsBranchLikely(instruction);
}
if (instrInDelaySlot) {
blockEndsOnBranch = true;
}
if (instrInDelaySlot && branchWasLikely) {
branchWasLikely = false;
code.L("not_taken");
code.mov(code.rax, blockPC);
code.mov(REG(qword, pc), code.rax);
}
}
while (!InstrEndsBlock(instruction));
// emit code to store the value of pc
blockCache[regs.pc >> 8][regs.pc >> 20] = code.getCurr<BlockFn>();
return blockCache[regs.pc >> 8][regs.pc >> 20]();
if (!blockEndsOnBranch) {
code.mov(code.rax, blockPC);
code.mov(REG(qword, pc), code.rax);
}
code.mov(code.rax, instructionsInBlock);
code.pop(code.rbp);
code.add(code.rsp, 56);
code.ret();
code.setProtectModeRE();
// const auto dump = code.getCode();
// Util::WriteFileBinary(dump, code.getSize(), "jit.dump");
// Util::panic("");
return block();
}
std::vector<u8> JIT::Serialize() {

View File

@@ -7,12 +7,14 @@
namespace n64 {
struct Core;
static constexpr u32 kAddressSpaceSize = 0x8000'0000; // >> 20 = 0x800
static constexpr u32 kLowerSize = kAddressSpaceSize >> 20; // 0x800
static constexpr u32 kUpperSize = kAddressSpaceSize >> 8; // 0x100000
static constexpr u64 kAddressSpaceSize = 0x8000'0000;
static constexpr u8 kUpperShift = 8;
static constexpr u8 kLowerMask = 0xff;
static constexpr u32 kUpperSize = kAddressSpaceSize >> kUpperShift; // 0x800000
static constexpr u32 kLowerSize = 0x100; // 0x80
static constexpr u32 kCodeCacheSize = 32_mb;
static constexpr u32 kCodeCacheAllocSize = kCodeCacheSize + 4096;
#define REG(acc, x) code.acc[reinterpret_cast<uintptr_t>(&regs.x)]
static constexpr u32 kCodeCacheAllocSize = kCodeCacheSize + 4_kb;
#define REG(acc, x) code.acc[code.rbp + (reinterpret_cast<uintptr_t>(&regs.x) - (uintptr_t)this)]
struct JIT : BaseCPU {
explicit JIT(ParallelRDP &);
@@ -46,13 +48,13 @@ private:
template <typename T>
Xbyak::Address GPR(const size_t index) const {
if constexpr (sizeof(T) == 1) {
return code.byte[reinterpret_cast<uintptr_t>(&regs.gpr[index])];
return code.byte[code.rbp + (reinterpret_cast<uintptr_t>(&regs.gpr[index]) - reinterpret_cast<uintptr_t>(this))];
} else if constexpr (sizeof(T) == 2) {
return code.word[reinterpret_cast<uintptr_t>(&regs.gpr[index])];
return code.word[code.rbp + (reinterpret_cast<uintptr_t>(&regs.gpr[index]) - reinterpret_cast<uintptr_t>(this))];
} else if constexpr (sizeof(T) == 4) {
return code.dword[reinterpret_cast<uintptr_t>(&regs.gpr[index])];
return code.dword[code.rbp + (reinterpret_cast<uintptr_t>(&regs.gpr[index]) - reinterpret_cast<uintptr_t>(this))];
} else if constexpr (sizeof(T) == 8) {
return code.qword[reinterpret_cast<uintptr_t>(&regs.gpr[index])];
return code.qword[code.rbp + (reinterpret_cast<uintptr_t>(&regs.gpr[index]) - reinterpret_cast<uintptr_t>(this))];
}
Util::panic("[JIT]: Invalid register addressing");
@@ -60,18 +62,11 @@ private:
return Xbyak::Address{0};
}
// Credits to PCSX-Redux: https://github.com/grumpycoders/pcsx-redux
// Sets dest to "pointer"
void loadAddress(const Xbyak::Reg64 dest, void *pointer) { code.mov(dest, reinterpret_cast<uintptr_t>(pointer)); }
// Thanks to https://github.com/grumpycoders/pcsx-redux
// Load a pointer to the JIT object in "reg"
void loadThisPointer(const Xbyak::Reg64 reg) { code.mov(reg, code.rbp); }
// Emit a call to a class member function, passing "thisObject" (+ an adjustment if necessary)
// As the function's "this" pointer. Only works with classes with single, non-virtual inheritance
// Hence the static asserts. Those are all we need though, thankfully.
template <typename T>
void emitMemberFunctionCall(T func, void *thisObject) {
void *functionPtr;
uintptr_t functionPtr;
auto thisPtr = reinterpret_cast<uintptr_t>(thisObject);
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
@@ -82,24 +77,22 @@ private:
uintptr_t arr[2];
std::memcpy(arr, &func, sizeof(T));
// First 8 bytes correspond to the actual pointer to the function
functionPtr = reinterpret_cast<void *>(arr[0]);
functionPtr = reinterpret_cast<uintptr_t>(reinterpret_cast<void *>(arr[0]));
// Next 8 bytes correspond to the "this" pointer adjustment
thisPtr += arr[1];
#endif
// Load this pointer to arg1
if (thisPtr == reinterpret_cast<uintptr_t>(this)) {
loadThisPointer(code.rdi);
} else {
loadAddress(code.rdi, reinterpret_cast<void *>(thisPtr));
}
code.call(functionPtr);
code.mov(code.rdi, thisPtr);
code.mov(code.rax, functionPtr);
code.call(code.rax);
}
void SkipSlot();
void SkipSlotConstant();
void BranchTaken(s64 offs);
void BranchTaken(const Xbyak::Reg &offs);
void BranchTaken(const Xbyak::Reg64 &offs);
void BranchAbsTaken(s64 addr);
void BranchAbsTaken(const Xbyak::Reg64 &addr);
#define check_address_error(mask, vaddr) \
(((!regs.cop0.is64BitAddressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0))
@@ -118,8 +111,9 @@ private:
void addiu(u32);
void andi(u32);
void and_(u32);
void branch_constant(bool cond, s64 address);
void branch_likely_constant(bool cond, s64 address);
void branch_constant(bool cond, s64 offset);
void branch_likely_constant(bool cond, s64 offset);
void branch_abs_constant(bool cond, s64 address);
void bltz(u32);
void bgez(u32);
void bltzl(u32);
@@ -188,17 +182,17 @@ private:
void mthi(u32);
void mtlo(u32);
void nor(u32);
void sb(u32);
void sc(u32);
void scd(u32);
void sd(u32);
void sdc1(u32);
void sdl(u32);
void sdr(u32);
void sh(u32);
void sb(u32) {}
void sc(u32) {}
void scd(u32) {}
void sd(u32) {}
void sdc1(u32) {}
void sdl(u32) {}
void sdr(u32) {}
void sh(u32) {}
void sw(u32);
void swl(u32);
void swr(u32);
void swl(u32) {}
void swr(u32) {}
void slti(u32);
void sltiu(u32);
void slt(u32);
@@ -207,12 +201,12 @@ private:
void sllv(u32);
void sub(u32);
void subu(u32);
void swc1(u32);
void swc1(u32) {}
void sra(u32);
void srav(u32);
void srl(u32);
void srlv(u32);
void trap(bool);
void trap(bool) {}
void or_(u32);
void ori(u32);
void xor_(u32);

View File

@@ -316,19 +316,6 @@ u64 Mem::Read(Registers &regs, const u32 paddr) {
}
}
template <>
void Mem::WriteJIT<u8>(Registers &regs, const u32 paddr, const u32 val) {
if (jit)
jit->InvalidateBlock(paddr);
WriteInterpreter<u8>(regs, paddr, val);
}
template <>
void Mem::Write<u8>(Registers &regs, const u32 paddr, const u32 val) {
WriteInterpreter<u8>(regs, paddr, val);
}
template <>
void Mem::WriteInterpreter<u8>(Registers &regs, u32 paddr, u32 val) {
SI &si = mmio.si;
@@ -371,16 +358,15 @@ void Mem::WriteInterpreter<u8>(Registers &regs, u32 paddr, u32 val) {
}
template <>
void Mem::WriteJIT<u16>(Registers &regs, const u32 paddr, const u32 val) {
void Mem::WriteJIT<u8>(Registers &regs, const u32 paddr, const u32 val) {
WriteInterpreter<u8>(regs, paddr, val);
if (jit)
jit->InvalidateBlock(paddr);
WriteInterpreter<u16>(regs, paddr, val);
}
template <>
void Mem::Write<u16>(Registers &regs, const u32 paddr, const u32 val) {
WriteInterpreter<u16>(regs, paddr, val);
void Mem::Write<u8>(Registers &regs, const u32 paddr, const u32 val) {
WriteInterpreter<u8>(regs, paddr, val);
}
template <>
@@ -425,16 +411,15 @@ void Mem::WriteInterpreter<u16>(Registers &regs, u32 paddr, u32 val) {
}
template <>
void Mem::WriteJIT<u32>(Registers &regs, const u32 paddr, const u32 val) {
void Mem::WriteJIT<u16>(Registers &regs, const u32 paddr, const u32 val) {
WriteInterpreter<u16>(regs, paddr, val);
if (jit)
jit->InvalidateBlock(paddr);
WriteInterpreter<u32>(regs, paddr, val);
}
template <>
void Mem::Write<u32>(Registers &regs, const u32 paddr, const u32 val) {
WriteInterpreter<u32>(regs, paddr, val);
void Mem::Write<u16>(Registers &regs, const u32 paddr, const u32 val) {
WriteInterpreter<u16>(regs, paddr, val);
}
template <>
@@ -475,11 +460,22 @@ void Mem::WriteInterpreter<u32>(Registers &regs, const u32 paddr, const u32 val)
}
}
void Mem::WriteJIT(const Registers &regs, const u32 paddr, const u64 val) {
template <>
void Mem::WriteJIT<u32>(Registers &regs, const u32 paddr, const u32 val) {
WriteInterpreter<u32>(regs, paddr, val);
if (jit)
jit->InvalidateBlock(paddr);
}
template <>
void Mem::Write<u32>(Registers &regs, const u32 paddr, const u32 val) {
WriteInterpreter<u32>(regs, paddr, val);
}
void Mem::WriteJIT(const Registers &regs, const u32 paddr, const u64 val) {
WriteInterpreter(regs, paddr, val);
if (jit)
jit->InvalidateBlock(paddr);
}
void Mem::Write(const Registers &regs, const u32 paddr, const u64 val) { WriteInterpreter(regs, paddr, val); }

View File

@@ -143,6 +143,7 @@ private:
friend struct PI;
friend struct AI;
friend struct RSP;
friend struct JIT;
friend struct Core;
std::array<u8, ISVIEWER_SIZE> isviewer{};
std::string sramPath{};

View File

@@ -602,10 +602,8 @@ void Interpreter::jal(const u32 instr) {
}
void Interpreter::jalr(const u32 instr) {
const u64 addr = regs.Read<s64>(RS(instr));
const s64 currentNextPC = regs.nextPC;
branch(true, addr);
regs.Write(RD(instr), currentNextPC);
regs.Write(RD(instr), regs.nextPC);
jr(instr);
}
void Interpreter::jr(const u32 instr) {

View File

@@ -20,24 +20,11 @@ static bool SpecialEndsBlock(const u32 instr) {
}
}
static bool RegimmEndsBlock(const u32 instr) {
switch (instr >> 16 & 0x1F) {
case BLTZL:
case BGEZL:
case BLTZALL:
case BGEZALL:
return false;
default:
return true;
}
}
static bool InstrEndsBlock(const u32 instr) {
switch (instr >> 26 & 0x3f) {
case SPECIAL:
return SpecialEndsBlock(instr);
case REGIMM:
return RegimmEndsBlock(instr);
case J:
case JAL:
case BEQ:
@@ -49,4 +36,37 @@ static bool InstrEndsBlock(const u32 instr) {
return false;
}
}
static bool IsBranchLikely(const u32 instr) {
switch (instr >> 26 & 0x1F) {
case BEQL:
case BNEL:
case BLEZL:
case BGTZL:
return true;
case COP1:
{
const u8 mask_sub = (instr >> 21) & 0x1F;
const u8 mask_branch = (instr >> 16) & 0x1F;
if (mask_sub == 0x08) {
if (mask_branch == 2 || mask_branch == 3)
return true;
return false;
}
return false;
}
default:
switch (instr >> 16 & 0x1F) {
case BLTZL:
case BGEZL:
case BLTZALL:
case BGEZALL:
return true;
default:
return false;
}
}
}
} // namespace n64

View File

@@ -10,7 +10,8 @@ using namespace Xbyak::util;
void JIT::lui(const u32 instr) {
u64 val = static_cast<s64>(static_cast<s16>(instr));
val <<= 16;
regs.Write(RT(instr), val, true);
regs.gpr[RT(instr)] = val;
regs.gprIsConstant[RT(instr)] = true;
}
void JIT::add(const u32 instr) {
@@ -57,7 +58,7 @@ void JIT::addu(u32 instr) {
const s32 rt = regs.Read<s32>(RT(instr));
const s32 result = rs + rt;
regs.Write<s32>(RD(instr), result);
regs.Write<s32>(RD(instr), result, true);
return;
}
@@ -106,7 +107,7 @@ void JIT::addiu(u32 instr) {
if (regs.IsRegConstant(RS(instr))) {
auto rs = regs.Read<u32>(RS(instr));
u32 result = rs + imm;
regs.Write(RT(instr), s32(result));
regs.Write(RT(instr), s32(result), true);
return;
}
@@ -119,7 +120,7 @@ void JIT::addiu(u32 instr) {
void JIT::andi(u32 instr) {
const s64 imm = static_cast<u16>(instr);
if (regs.IsRegConstant(RS(instr))) {
regs.Write(RT(instr), regs.Read<s64>(RS(instr)) & imm);
regs.Write(RT(instr), regs.Read<s64>(RS(instr)) & imm, true);
return;
}
@@ -130,7 +131,7 @@ void JIT::andi(u32 instr) {
void JIT::and_(u32 instr) {
if (regs.IsRegConstant(RS(instr), RT(instr))) {
regs.Write(RD(instr), regs.Read<s64>(RS(instr)) & regs.Read<s64>(RT(instr)));
regs.Write(RD(instr), regs.Read<s64>(RS(instr)) & regs.Read<s64>(RT(instr)), true);
return;
}
@@ -156,59 +157,60 @@ void JIT::and_(u32 instr) {
regs.Write<s64>(RD(instr), code.rdi);
}
void JIT::SkipSlot() {
code.mov(code.rax, REG(qword, pc));
code.mov(REG(qword, oldPC), code.rax);
code.mov(code.rax, REG(qword, nextPC));
code.mov(REG(qword, pc), code.rax);
code.add(code.rax, 4);
code.mov(REG(qword, nextPC), code.rax);
}
void JIT::SkipSlot() { code.jmp("not_taken"); }
void JIT::SkipSlotConstant() { blockPC += 4; }
void JIT::BranchTaken(const s64 offs) {
code.mov(code.rax, REG(qword, pc));
code.add(code.rax, offs);
code.mov(REG(qword, nextPC), code.rax);
code.mov(REG(qword, pc), code.rax);
}
void JIT::BranchTaken(const Xbyak::Reg &offs) {
code.mov(code.rax, REG(qword, pc));
code.add(code.rax, offs);
code.mov(REG(qword, nextPC), code.rax);
void JIT::BranchTaken(const Xbyak::Reg64 &offs) { code.add(REG(qword, pc), offs); }
void JIT::BranchAbsTaken(const s64 addr) {
code.mov(code.rax, addr);
code.mov(REG(qword, pc), code.rax);
}
void JIT::BranchAbsTaken(const Xbyak::Reg64 &addr) { code.mov(REG(qword, nextPC), addr); }
#define branch(offs, cond) \
do { \
code.mov(code.al, 1); \
code.mov(REG(byte, delaySlot), code.al); \
code.j##cond("taken"); \
code.jmp("not taken"); \
code.mov(code.rax, blockPC); \
code.mov(REG(qword, pc), code.rax); \
code.jmp("not_taken"); \
code.L("taken"); \
BranchTaken(offs); \
code.L("not_taken"); \
} \
while (0)
#define branch_abs(addr, cond) \
do { \
code.j##cond("taken"); \
code.mov(code.rax, blockPC); \
code.mov(REG(qword, pc), code.rax); \
code.jmp("not_taken"); \
code.L("taken"); \
BranchAbsTaken(addr); \
code.L("not_taken"); \
} \
while (0)
#define branch_likely(offs, cond) \
do { \
code.j##cond("taken"); \
SkipSlot(); \
code.jmp("not_taken"); \
code.L("taken"); \
code.mov(code.al, 1); \
code.mov(REG(byte, delaySlot), code.al); \
BranchTaken(offs); \
code.L("not_taken"); \
} \
while (0)
void JIT::branch_constant(const bool cond, const s64 offset) {
code.mov(code.al, 1);
code.mov(REG(byte, delaySlot), code.al);
if (cond) {
BranchTaken(offset);
}
@@ -216,14 +218,18 @@ void JIT::branch_constant(const bool cond, const s64 offset) {
void JIT::branch_likely_constant(const bool cond, const s64 offset) {
if (cond) {
code.mov(code.al, 1);
code.mov(REG(byte, delaySlot), code.al);
BranchTaken(offset);
} else {
SkipSlotConstant();
}
}
void JIT::branch_abs_constant(const bool cond, const s64 address) {
if (cond) {
BranchAbsTaken(address);
}
}
void JIT::bfc0(u32 instr) {
const s16 imm = instr;
const s64 offset = u64((s64)imm) << 2;
@@ -260,7 +266,7 @@ void JIT::bltz(const u32 instr) {
return;
}
code.mov(code.rax, GPR<s64>(RS(instr)));
regs.Read<s64>(RS(instr), code.rax);
code.cmp(code.rax, 0);
branch(offset, l);
}
@@ -273,7 +279,7 @@ void JIT::bgez(const u32 instr) {
return;
}
code.mov(code.rax, GPR(RS(instr)));
regs.Read<s64>(RS(instr), code.rax);
code.cmp(code.rax, 0);
branch(offset, ge);
}
@@ -286,7 +292,7 @@ void JIT::bltzl(const u32 instr) {
return;
}
code.mov(code.rax, GPR(RS(instr)));
regs.Read<s64>(RS(instr), code.rax);
code.cmp(code.rax, 0);
branch_likely(offset, l);
}
@@ -299,18 +305,66 @@ void JIT::bgezl(const u32 instr) {
return;
}
code.mov(code.rax, GPR(RS(instr)));
regs.Read<s64>(RS(instr), code.rax);
code.cmp(code.rax, 0);
branch_likely(offset, ge);
}
void JIT::bltzal(const u32 instr) {}
void JIT::bltzal(const u32 instr) {
const s16 imm = instr;
const s64 offset = u64((s64)imm) << 2;
regs.Write<s64>(31, blockPC + 4, true);
if (regs.IsRegConstant(RS(instr))) {
branch_constant(regs.Read<s64>(RS(instr)) < 0, offset);
return;
}
void JIT::bgezal(const u32 instr) {}
regs.Read<s64>(RS(instr), code.rax);
code.cmp(code.rax, 0);
branch(offset, l);
}
void JIT::bltzall(const u32 instr) {}
void JIT::bgezal(const u32 instr) {
const s16 imm = instr;
const s64 offset = u64((s64)imm) << 2;
regs.Write<s64>(31, blockPC + 4, true);
if (regs.IsRegConstant(RS(instr))) {
branch_constant(regs.Read<s64>(RS(instr)) >= 0, offset);
return;
}
void JIT::bgezall(const u32 instr) {}
regs.Read<s64>(RS(instr), code.rax);
code.cmp(code.rax, 0);
branch(offset, ge);
}
void JIT::bltzall(const u32 instr) {
const s16 imm = instr;
const s64 offset = u64((s64)imm) << 2;
regs.Write<s64>(31, blockPC + 4, true);
if (regs.IsRegConstant(RS(instr))) {
branch_likely_constant(regs.Read<s64>(RS(instr)) < 0, offset);
return;
}
regs.Read<s64>(RS(instr), code.rax);
code.cmp(code.rax, 0);
branch_likely(offset, l);
}
void JIT::bgezall(const u32 instr) {
const s16 imm = instr;
const s64 offset = u64((s64)imm) << 2;
regs.Write<s64>(31, blockPC + 4, true);
if (regs.IsRegConstant(RS(instr))) {
branch_likely_constant(regs.Read<s64>(RS(instr)) >= 0, offset);
return;
}
regs.Read<s64>(RS(instr), code.rax);
code.cmp(code.rax, 0);
branch_likely(offset, ge);
}
void JIT::beq(const u32 instr) {
const s16 imm = instr;
@@ -321,21 +375,21 @@ void JIT::beq(const u32 instr) {
}
if (regs.IsRegConstant(RS(instr))) {
code.mov(code.rax, GPR(RT(instr)));
regs.Read<s64>(RT(instr), code.rax);
code.cmp(code.rax, regs.Read<s64>(RS(instr)));
branch(offset, e);
return;
}
if (regs.IsRegConstant(RT(instr))) {
code.mov(code.rax, GPR(RS(instr)));
regs.Read<s64>(RS(instr), code.rax);
code.cmp(code.rax, regs.Read<s64>(RT(instr)));
branch(offset, e);
return;
}
code.mov(code.rax, GPR(RS(instr)));
code.mov(code.rdi, GPR(RT(instr)));
regs.Read<s64>(RS(instr), code.rax);
regs.Read<s64>(RT(instr), code.rdi);
code.cmp(code.rax, code.rdi);
branch(offset, e);
}
@@ -349,21 +403,21 @@ void JIT::beql(const u32 instr) {
}
if (regs.IsRegConstant(RS(instr))) {
code.mov(code.rax, GPR(RT(instr)));
regs.Read<s64>(RT(instr), code.rax);
code.cmp(code.rax, regs.Read<s64>(RS(instr)));
branch_likely(offset, e);
return;
}
if (regs.IsRegConstant(RT(instr))) {
code.mov(code.rax, GPR(RS(instr)));
regs.Read<s64>(RS(instr), code.rax);
code.cmp(code.rax, regs.Read<s64>(RT(instr)));
branch_likely(offset, e);
return;
}
code.mov(code.rax, GPR(RS(instr)));
code.mov(code.rdi, GPR(RT(instr)));
regs.Read<s64>(RS(instr), code.rax);
regs.Read<s64>(RT(instr), code.rdi);
code.cmp(code.rax, code.rdi);
branch_likely(offset, e);
}
@@ -372,26 +426,26 @@ void JIT::bne(const u32 instr) {
const s16 imm = instr;
const s64 offset = u64((s64)imm) << 2;
if (regs.IsRegConstant(RS(instr)) && regs.IsRegConstant(RT(instr))) {
branch_constant(regs.Read<s64>(RS(instr)) == regs.Read<s64>(RT(instr)), offset);
branch_constant(regs.Read<s64>(RS(instr)) != regs.Read<s64>(RT(instr)), offset);
return;
}
if (regs.IsRegConstant(RS(instr))) {
code.mov(code.rax, GPR(RT(instr)));
regs.Read<s64>(RT(instr), code.rax);
code.cmp(code.rax, regs.Read<s64>(RS(instr)));
branch(offset, ne);
return;
}
if (regs.IsRegConstant(RT(instr))) {
code.mov(code.rax, GPR(RS(instr)));
regs.Read<s64>(RS(instr), code.rax);
code.cmp(code.rax, regs.Read<s64>(RT(instr)));
branch(offset, ne);
return;
}
code.mov(code.rax, GPR(RS(instr)));
code.mov(code.rdi, GPR(RT(instr)));
regs.Read<s64>(RS(instr), code.rax);
regs.Read<s64>(RT(instr), code.rdi);
code.cmp(code.rax, code.rdi);
branch(offset, ne);
}
@@ -400,26 +454,26 @@ void JIT::bnel(const u32 instr) {
const s16 imm = instr;
const s64 offset = u64((s64)imm) << 2;
if (regs.IsRegConstant(RS(instr)) && regs.IsRegConstant(RT(instr))) {
branch_likely_constant(regs.Read<s64>(RS(instr)) == regs.Read<s64>(RT(instr)), offset);
branch_likely_constant(regs.Read<s64>(RS(instr)) != regs.Read<s64>(RT(instr)), offset);
return;
}
if (regs.IsRegConstant(RS(instr))) {
code.mov(code.rax, GPR(RT(instr)));
regs.Read<s64>(RT(instr), code.rax);
code.cmp(code.rax, regs.Read<s64>(RS(instr)));
branch_likely(offset, ne);
return;
}
if (regs.IsRegConstant(RT(instr))) {
code.mov(code.rax, GPR(RS(instr)));
regs.Read<s64>(RS(instr), code.rax);
code.cmp(code.rax, regs.Read<s64>(RT(instr)));
branch_likely(offset, ne);
return;
}
code.mov(code.rax, GPR(RS(instr)));
code.mov(code.rdi, GPR(RT(instr)));
regs.Read<s64>(RS(instr), code.rax);
regs.Read<s64>(RT(instr), code.rdi);
code.cmp(code.rax, code.rdi);
branch_likely(offset, ne);
}
@@ -432,7 +486,7 @@ void JIT::blez(const u32 instr) {
return;
}
code.mov(code.rax, GPR(RS(instr)));
regs.Read<s64>(RS(instr), code.rax);
code.cmp(code.rax, 0);
branch(offset, le);
}
@@ -445,7 +499,7 @@ void JIT::blezl(const u32 instr) {
return;
}
code.mov(code.rax, GPR(RS(instr)));
regs.Read<s64>(RS(instr), code.rax);
code.cmp(code.rax, 0);
branch_likely(offset, le);
}
@@ -458,7 +512,7 @@ void JIT::bgtz(const u32 instr) {
return;
}
code.mov(code.rax, GPR(RS(instr)));
regs.Read<s64>(RS(instr), code.rax);
code.cmp(code.rax, 0);
branch(offset, g);
}
@@ -471,7 +525,7 @@ void JIT::bgtzl(const u32 instr) {
return;
}
code.mov(code.rax, GPR(RS(instr)));
regs.Read<s64>(RS(instr), code.rax);
code.cmp(code.rax, 0);
branch_likely(offset, g);
}
@@ -485,7 +539,7 @@ void JIT::dadd(u32 instr) {
// regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
Util::panic("[JIT]: Unhandled Overflow exception in DADD!");
}
regs.Write(RD(instr), result);
regs.Write(RD(instr), result, true);
} else {
Util::panic("[JIT]: Implement non constant DADD!");
}
@@ -495,7 +549,7 @@ void JIT::daddu(u32 instr) {
if (regs.IsRegConstant(RS(instr), RT(instr))) {
auto rs = regs.Read<s64>(RS(instr));
auto rt = regs.Read<s64>(RT(instr));
regs.Write(RD(instr), rt + rs);
regs.Write(RD(instr), rt + rs, true);
} else {
Util::panic("[JIT]: Implement non constant DADD!");
}
@@ -510,7 +564,7 @@ void JIT::daddi(u32 instr) {
// regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
Util::panic("[JIT]: Unhandled Overflow exception in DADDI!");
}
regs.Write(RT(instr), result);
regs.Write(RT(instr), result, true);
} else {
Util::panic("[JIT]: Implement non constant DADDI!");
}
@@ -520,7 +574,7 @@ void JIT::daddiu(u32 instr) {
if (regs.IsRegConstant(RS(instr))) {
s16 imm = s16(instr);
auto rs = regs.Read<s64>(RS(instr));
regs.Write(RT(instr), imm + rs);
regs.Write(RT(instr), imm + rs, true);
} else {
Util::panic("[JIT]: Implement non constant DADDI!");
}
@@ -654,7 +708,7 @@ void JIT::dsll(u32 instr) {
if (regs.IsRegConstant(RT(instr))) {
u8 sa = ((instr >> 6) & 0x1f);
auto result = regs.Read<s64>(RT(instr)) << sa;
regs.Write(RD(instr), result);
regs.Write(RD(instr), result, true);
} else {
Util::panic("[JIT]: Implement non constant DSLL!");
}
@@ -664,7 +718,7 @@ void JIT::dsllv(u32 instr) {
if (regs.IsRegConstant(RT(instr), RS(instr))) {
auto sa = regs.Read<s64>(RS(instr)) & 63;
auto result = regs.Read<s64>(RT(instr)) << sa;
regs.Write(RD(instr), result);
regs.Write(RD(instr), result, true);
} else {
Util::panic("[JIT]: Implement non constant DSLLV!");
}
@@ -674,7 +728,7 @@ void JIT::dsll32(u32 instr) {
if (regs.IsRegConstant(RT(instr))) {
u8 sa = ((instr >> 6) & 0x1f);
auto result = regs.Read<s64>(RT(instr)) << (sa + 32);
regs.Write(RD(instr), result);
regs.Write(RD(instr), result, true);
} else {
Util::panic("[JIT]: Implement non constant DSLL32!");
}
@@ -685,7 +739,7 @@ void JIT::dsra(u32 instr) {
auto rt = regs.Read<s64>(RT(instr));
u8 sa = ((instr >> 6) & 0x1f);
s64 result = rt >> sa;
regs.Write(RD(instr), result);
regs.Write(RD(instr), result, true);
} else {
Util::panic("[JIT]: Implement non constant DSRA!");
}
@@ -697,7 +751,7 @@ void JIT::dsrav(u32 instr) {
auto rs = regs.Read<s64>(RS(instr));
s64 sa = rs & 63;
s64 result = rt >> sa;
regs.Write(RD(instr), result);
regs.Write(RD(instr), result, true);
} else {
Util::panic("[JIT]: Implement non constant DSRAV!");
}
@@ -708,7 +762,7 @@ void JIT::dsra32(u32 instr) {
auto rt = regs.Read<s64>(RT(instr));
u8 sa = ((instr >> 6) & 0x1f);
s64 result = rt >> (sa + 32);
regs.Write(RD(instr), result);
regs.Write(RD(instr), result, true);
} else {
Util::panic("[JIT]: Implement non constant DSRA32!");
}
@@ -719,7 +773,7 @@ void JIT::dsrl(u32 instr) {
auto rt = regs.Read<u64>(RT(instr));
u8 sa = ((instr >> 6) & 0x1f);
u64 result = rt >> sa;
regs.Write(RD(instr), s64(result));
regs.Write(RD(instr), s64(result), true);
} else {
Util::panic("[JIT]: Implement non constant DSRL!");
}
@@ -730,7 +784,7 @@ void JIT::dsrlv(u32 instr) {
u8 amount = regs.Read<u8>(RS(instr)) & 63;
auto rt = regs.Read<u64>(RT(instr));
u64 result = rt >> amount;
regs.Write(RD(instr), s64(result));
regs.Write(RD(instr), s64(result), true);
} else {
Util::panic("[JIT]: Implement non constant DSRLV!");
}
@@ -741,7 +795,7 @@ void JIT::dsrl32(u32 instr) {
auto rt = regs.Read<u64>(RT(instr));
u8 sa = ((instr >> 6) & 0x1f);
u64 result = rt >> (sa + 32);
regs.Write(RD(instr), s64(result));
regs.Write(RD(instr), s64(result), true);
} else {
Util::panic("[JIT]: Implement non constant DSRL32!");
}
@@ -756,7 +810,7 @@ void JIT::dsub(u32 instr) {
// regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
Util::panic("[JIT]: Unhandled Overflow exception in DSUB!");
} else {
regs.Write(RD(instr), result);
regs.Write(RD(instr), result, true);
}
} else {
Util::panic("[JIT]: Implement non constant DSUB!");
@@ -768,7 +822,7 @@ void JIT::dsubu(u32 instr) {
auto rt = regs.Read<s64>(RT(instr));
auto rs = regs.Read<s64>(RS(instr));
s64 result = rs - rt;
regs.Write(RD(instr), result);
regs.Write(RD(instr), result, true);
} else {
Util::panic("[JIT]: Implement non constant DSUBU!");
}
@@ -779,39 +833,28 @@ void JIT::j(const u32 instr) {
code.mov(code.rax, REG(qword, oldPC));
code.and_(code.rax, ~0xfffffff);
code.or_(code.rax, target);
code.mov(code.dl, 1);
code.mov(REG(byte, delaySlot), code.dl);
code.mov(code.rdi, target);
code.mov(REG(qword, nextPC), code.rdi);
branch_abs(target, mp);
}
void JIT::jr(const u32 instr) {
if (regs.IsRegConstant(RS(instr))) {
const u64 address = regs.Read<s64>(RS(instr));
code.mov(code.dl, 1);
code.mov(REG(byte, delaySlot), code.dl);
code.mov(code.rdi, address);
code.mov(REG(qword, nextPC), code.rdi);
branch_abs_constant(true, address);
return;
}
code.mov(code.dl, 1);
code.mov(REG(byte, delaySlot), code.dl);
code.mov(code.rdi, GPR(RS(instr)));
code.mov(REG(qword, nextPC), code.rdi);
regs.Read<s64>(RS(instr), code.rax);
branch_abs(code.rax, mp);
}
void JIT::jal(const u32 instr) {
code.mov(code.rax, REG(qword, nextPC));
code.mov(GPR(31), code.rax);
regs.Write<s64>(31, blockPC + 4, true);
j(instr);
}
void JIT::jalr(const u32 instr) {
if (regs.IsRegConstant(RS(instr))) {
const u64 addr = regs.Read<s64>(RS(instr));
return;
}
regs.Write<s64>(RD(instr), blockPC + 4, true);
jr(instr);
}
void JIT::lbu(u32 instr) {
@@ -824,7 +867,7 @@ void JIT::lbu(u32 instr) {
Util::panic("[JIT]: Unhandled TLBL exception in LBU!");
} else {
const u8 value = mem.Read<u8>(regs, paddr);
regs.Write(RT(instr), value);
regs.Write(RT(instr), value, true);
}
} else {
Util::panic("[JIT]: Implement non constant LBU!");
@@ -839,7 +882,7 @@ void JIT::lb(u32 instr) {
// regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
Util::panic("[JIT]: Unhandled TLBL exception in LB!");
} else {
regs.Write(RT(instr), (s8)mem.Read<u8>(regs, paddr));
regs.Write(RT(instr), (s8)mem.Read<u8>(regs, paddr), true);
}
} else {
Util::panic("[JIT]: Implement non constant LB!");
@@ -863,7 +906,7 @@ void JIT::ld(u32 instr) {
Util::panic("[JIT]: Unhandled TLBL exception in LD!");
} else {
const s64 value = mem.Read<u64>(regs, paddr);
regs.Write(RT(instr), value);
regs.Write(RT(instr), value, true);
}
} else {
Util::panic("[JIT]: Implement non constant LD!");
@@ -901,7 +944,7 @@ void JIT::ldl(u32 instr) {
const u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
const u64 data = mem.Read<u64>(regs, paddr & ~7);
const s64 result = (s64)((regs.Read<s64>(RT(instr)) & ~mask) | (data << shift));
regs.Write(RT(instr), result);
regs.Write(RT(instr), result, true);
}
} else {
Util::panic("[JIT]: Implement non constant LDL!");
@@ -921,7 +964,7 @@ void JIT::ldr(u32 instr) {
const u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
const u64 data = mem.Read<u64>(regs, paddr & ~7);
const s64 result = (s64)((regs.Read<s64>(RT(instr)) & ~mask) | (data >> shift));
regs.Write(RT(instr), result);
regs.Write(RT(instr), result, true);
}
} else {
Util::panic("[JIT]: Implement non constant LDR!");
@@ -929,21 +972,32 @@ void JIT::ldr(u32 instr) {
}
void JIT::lh(u32 instr) {
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
if (check_address_error(0b1, address)) {
// regs.cop0.HandleTLBException(address);
// regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
// return;
Util::panic("[JIT]: Unhandled ADEL exception in LH!");
if (regs.IsRegConstant(RS(instr))) {
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
if (check_address_error(0b1, address)) {
// regs.cop0.HandleTLBException(address);
// regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
// return;
Util::panic("[JIT]: Unhandled ADEL exception in LH!");
return;
}
u32 paddr = 0;
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
// regs.cop0.HandleTLBException(address);
// regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
Util::panic("[JIT]: Unhandled TLBL exception in LH!");
return;
}
code.mov(code.rsi, code.ptr[code.rbp + (reinterpret_cast<uintptr_t>(&regs) - reinterpret_cast<uintptr_t>(this))]);
code.mov(code.edx, paddr);
emitMemberFunctionCall(&Mem::Read<u16>, &mem);
regs.Write<s16>(RT(instr), code.rax);
return;
}
u32 paddr = 0;
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
// regs.cop0.HandleTLBException(address);
// regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
regs.Write(RT(instr), (s16)mem.Read<u16>(regs, paddr));
}
Util::panic("[JIT]: Implement non constant LH!");
}
void JIT::lhu(u32) {}
@@ -952,7 +1006,35 @@ void JIT::ll(u32) {}
void JIT::lld(u32) {}
void JIT::lw(u32) {}
void JIT::lw(u32 instr) {
if (regs.IsRegConstant(RS(instr))) {
const s16 offset = instr;
const u64 address = regs.Read<s64>(RS(instr)) + offset;
if (check_address_error(0b11, address)) {
// regs.cop0.HandleTLBException(address);
// regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
// return;
Util::panic("[JIT]: Unhandled ADEL exception in LW!");
return;
}
u32 paddr = 0;
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
// regs.cop0.HandleTLBException(address);
// regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
Util::panic("[JIT]: Unhandled TLBL exception in LW!");
return;
}
code.mov(code.rsi, code.ptr[code.rbp + (reinterpret_cast<uintptr_t>(&regs) - reinterpret_cast<uintptr_t>(this))]);
code.mov(code.edx, paddr);
emitMemberFunctionCall(&Mem::Read<u32>, &mem);
regs.Write<s32>(RT(instr), code.rax);
return;
}
Util::panic("[JIT]: Implement non constant LW!");
}
void JIT::lwc1(u32) {}
@@ -964,7 +1046,7 @@ void JIT::lwr(u32) {}
void JIT::mfhi(u32 instr) {
if (regs.hiIsConstant) {
regs.Write(RD(instr), regs.hi);
regs.Write(RD(instr), regs.hi, true);
} else {
Util::panic("[JIT]: Implement non constant MFHI!");
}
@@ -972,7 +1054,7 @@ void JIT::mfhi(u32 instr) {
void JIT::mflo(u32 instr) {
if (regs.loIsConstant) {
regs.Write(RD(instr), regs.lo);
regs.Write(RD(instr), regs.lo, true);
} else {
Util::panic("[JIT]: Implement non constant MFLO!");
}
@@ -1026,7 +1108,7 @@ void JIT::mtlo(u32 instr) {
void JIT::nor(u32 instr) {
if (regs.IsRegConstant(RS(instr), RT(instr))) {
regs.Write(RD(instr), ~(regs.Read<s64>(RS(instr)) | regs.Read<s64>(RT(instr))));
regs.Write(RD(instr), ~(regs.Read<s64>(RS(instr)) | regs.Read<s64>(RT(instr))), true);
} else {
Util::panic("[JIT]: Implement non constant NOR!");
}
@@ -1035,7 +1117,7 @@ void JIT::nor(u32 instr) {
void JIT::slti(u32 instr) {
if (regs.IsRegConstant(RS(instr))) {
s16 imm = instr;
regs.Write(RT(instr), regs.Read<s64>(RS(instr)) < imm);
regs.Write(RT(instr), regs.Read<s64>(RS(instr)) < imm, true);
} else {
Util::panic("[JIT]: Implement non constant SLTI!");
}
@@ -1044,7 +1126,7 @@ void JIT::slti(u32 instr) {
void JIT::sltiu(u32 instr) {
if (regs.IsRegConstant(RS(instr))) {
s16 imm = instr;
regs.Write(RT(instr), regs.Read<u64>(RS(instr)) < imm);
regs.Write(RT(instr), regs.Read<u64>(RS(instr)) < imm, true);
} else {
Util::panic("[JIT]: Implement non constant SLTIU!");
}
@@ -1052,7 +1134,7 @@ void JIT::sltiu(u32 instr) {
void JIT::slt(u32 instr) {
if (regs.IsRegConstant(RS(instr), RT(instr))) {
regs.Write(RD(instr), regs.Read<s64>(RS(instr)) < regs.Read<s64>(RT(instr)));
regs.Write(RD(instr), regs.Read<s64>(RS(instr)) < regs.Read<s64>(RT(instr)), true);
} else {
Util::panic("[JIT]: Implement non constant SLT!");
}
@@ -1060,7 +1142,7 @@ void JIT::slt(u32 instr) {
void JIT::sltu(u32 instr) {
if (regs.IsRegConstant(RS(instr), RT(instr))) {
regs.Write(RD(instr), regs.Read<u64>(RS(instr)) < regs.Read<u64>(RT(instr)));
regs.Write(RD(instr), regs.Read<u64>(RS(instr)) < regs.Read<u64>(RT(instr)), true);
} else {
Util::panic("[JIT]: Implement non constant SLT!");
}
@@ -1070,7 +1152,7 @@ void JIT::sll(u32 instr) {
if (regs.IsRegConstant(RT(instr))) {
u8 sa = ((instr >> 6) & 0x1f);
s32 result = regs.Read<s64>(RT(instr)) << sa;
regs.Write(RD(instr), (s64)result);
regs.Write(RD(instr), (s64)result, true);
} else {
Util::panic("[JIT]: Implement non constant SLL!");
}
@@ -1081,7 +1163,7 @@ void JIT::sllv(u32 instr) {
u8 sa = (regs.Read<s64>(RS(instr))) & 0x1F;
u32 rt = regs.Read<s64>(RT(instr));
s32 result = rt << sa;
regs.Write(RD(instr), (s64)result);
regs.Write(RD(instr), (s64)result, true);
} else {
Util::panic("[JIT]: Implement non constant SLLV!");
}
@@ -1095,7 +1177,7 @@ void JIT::sub(u32 instr) {
if (check_signed_underflow(rs, rt, result)) {
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
} else {
regs.Write(RD(instr), result);
regs.Write(RD(instr), result, true);
}
} else {
Util::panic("[JIT]: Implement non constant SUB!");
@@ -1107,7 +1189,7 @@ void JIT::subu(u32 instr) {
u32 rt = regs.Read<s64>(RT(instr));
u32 rs = regs.Read<s64>(RS(instr));
u32 result = rs - rt;
regs.Write(RD(instr), (s64)((s32)result));
regs.Write(RD(instr), (s64)((s32)result), true);
} else {
Util::panic("[JIT]: Implement non constant SUBU!");
}
@@ -1118,7 +1200,7 @@ void JIT::sra(u32 instr) {
s64 rt = regs.Read<s64>(RT(instr));
u8 sa = ((instr >> 6) & 0x1f);
s32 result = rt >> sa;
regs.Write(RD(instr), result);
regs.Write(RD(instr), result, true);
} else {
Util::panic("[JIT]: Implement non constant SRA!");
}
@@ -1130,7 +1212,7 @@ void JIT::srav(u32 instr) {
s64 rt = regs.Read<s64>(RT(instr));
u8 sa = rs & 0x1f;
s32 result = rt >> sa;
regs.Write(RD(instr), result);
regs.Write(RD(instr), result, true);
} else {
Util::panic("[JIT]: Implement non constant SRAV!");
}
@@ -1141,14 +1223,14 @@ void JIT::srl(u32 instr) {
u32 rt = regs.Read<s64>(RT(instr));
u8 sa = ((instr >> 6) & 0x1f);
u32 result = rt >> sa;
regs.Write(RD(instr), (s32)result);
regs.Write(RD(instr), (s32)result, true);
} else {
Util::panic("[JIT]: Implement non constant SRL!");
}
}
void JIT::sw(const u32 instr) {
if (regs.IsRegConstant(RS(instr)) && regs.IsRegConstant(RT(instr))) {
if (regs.IsRegConstant(RS(instr), RT(instr))) {
const s16 offset = instr;
const u64 address = regs.Read<s64>(RS(instr)) + offset;
if (check_address_error(0b11, address)) {
@@ -1164,7 +1246,7 @@ void JIT::sw(const u32 instr) {
// regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
Util::panic("[JIT]: Unhandled TLBS exception in SW!");
} else {
code.mov(code.rsi, reinterpret_cast<uintptr_t>(&regs));
code.lea(code.rsi, code.ptr[code.rbp + (reinterpret_cast<uintptr_t>(&regs) - reinterpret_cast<uintptr_t>(this))]);
code.mov(code.edx, physical);
code.mov(code.rcx, regs.Read<s64>(RT(instr)));
emitMemberFunctionCall(&Mem::WriteJIT<u32>, &mem);
@@ -1189,9 +1271,9 @@ void JIT::sw(const u32 instr) {
// regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
Util::panic("[JIT]: Unhandled TLBS exception in SW!");
} else {
code.mov(code.rsi, reinterpret_cast<uintptr_t>(&regs));
code.mov(code.rsi, code.ptr[code.rbp + (reinterpret_cast<uintptr_t>(&regs) - reinterpret_cast<uintptr_t>(this))]);
code.mov(code.edx, physical);
code.mov(code.rcx, GPR(RT(instr)));
regs.Read<s64>(RT(instr), code.rcx);
emitMemberFunctionCall(&Mem::WriteJIT<u32>, &mem);
}
@@ -1200,7 +1282,7 @@ void JIT::sw(const u32 instr) {
if (regs.IsRegConstant(RT(instr))) {
const s16 offset = instr;
code.mov(code.rdx, GPR(RS(instr)));
regs.Read<s64>(RS(instr), code.rdx);
code.add(code.rdx, offset);
code.mov(code.esi, Cop0::STORE);
@@ -1209,7 +1291,7 @@ void JIT::sw(const u32 instr) {
code.mov(code.rcx, reinterpret_cast<uintptr_t>(&physical));
emitMemberFunctionCall(&Cop0::MapVAddr, &regs.cop0);
code.mov(code.rsi, reinterpret_cast<uintptr_t>(&regs));
code.mov(code.rsi, code.ptr[code.rbp + (reinterpret_cast<uintptr_t>(&regs) - reinterpret_cast<uintptr_t>(this))]);
code.mov(code.edx, physical);
code.mov(code.rcx, regs.Read<s64>(RT(instr)));
emitMemberFunctionCall(&Mem::WriteJIT<u32>, &mem);
@@ -1218,7 +1300,7 @@ void JIT::sw(const u32 instr) {
}
const s16 offset = instr;
code.mov(code.rdx, GPR(RS(instr)));
regs.Read<s64>(RS(instr), code.rdx);
code.add(code.rdx, offset);
code.mov(code.esi, Cop0::STORE);
@@ -1227,9 +1309,9 @@ void JIT::sw(const u32 instr) {
code.mov(code.rcx, reinterpret_cast<uintptr_t>(&physical));
emitMemberFunctionCall(&Cop0::MapVAddr, &regs.cop0);
code.mov(code.rsi, reinterpret_cast<uintptr_t>(&regs));
code.mov(code.rsi, code.ptr[code.rbp + (reinterpret_cast<uintptr_t>(&regs) - reinterpret_cast<uintptr_t>(this))]);
code.mov(code.edx, physical);
code.mov(code.rcx, GPR(RT(instr)));
regs.Read<s64>(RT(instr), code.rcx);
emitMemberFunctionCall(&Mem::WriteJIT<u32>, &mem);
}
@@ -1238,7 +1320,7 @@ void JIT::srlv(u32 instr) {
u8 sa = (regs.Read<s64>(RS(instr)) & 0x1F);
u32 rt = regs.Read<s64>(RT(instr));
s32 result = rt >> sa;
regs.Write(RD(instr), (s64)result);
regs.Write(RD(instr), (s64)result, true);
} else {
Util::panic("[JIT]: Implement non constant SRLV!");
}
@@ -1246,7 +1328,7 @@ void JIT::srlv(u32 instr) {
void JIT::or_(u32 instr) {
if (regs.IsRegConstant(RS(instr), RT(instr))) {
regs.Write(RD(instr), regs.Read<s64>(RS(instr)) | regs.Read<s64>(RT(instr)));
regs.Write(RD(instr), regs.Read<s64>(RS(instr)) | regs.Read<s64>(RT(instr)), true);
} else {
Util::panic("[JIT]: Implement non constant OR!");
}
@@ -1256,19 +1338,22 @@ void JIT::ori(u32 instr) {
if (RT(instr) == 0)
return;
s64 imm = (u16)instr;
if (regs.IsRegConstant(RS(instr))) {
s64 imm = (u16)instr;
s64 result = imm | regs.Read<s64>(RS(instr));
code.mov(GPR(RT(instr)), result);
} else {
Util::panic("[JIT]: Implement non constant ORI!");
regs.Write(RT(instr), result, true);
return;
}
regs.Read<s64>(RS(instr), code.rax);
code.or_(code.rax, imm);
regs.Write<s64>(RT(instr), code.rax);
}
void JIT::xori(u32 instr) {
if (regs.IsRegConstant(RS(instr))) {
s64 imm = (u16)instr;
regs.Write(RT(instr), regs.Read<s64>(RS(instr)) ^ imm);
regs.Write(RT(instr), regs.Read<s64>(RS(instr)) ^ imm, true);
} else {
Util::panic("[JIT]: Implement non constant XORI!");
}
@@ -1276,7 +1361,7 @@ void JIT::xori(u32 instr) {
void JIT::xor_(u32 instr) {
if (regs.IsRegConstant(RS(instr), RT(instr))) {
regs.Write(RD(instr), regs.Read<s64>(RT(instr)) ^ regs.Read<s64>(RS(instr)));
regs.Write(RD(instr), regs.Read<s64>(RT(instr)) ^ regs.Read<s64>(RS(instr)), true);
} else {
Util::panic("[JIT]: Implement non constant XOR!");
}

View File

@@ -40,6 +40,41 @@ u64 Registers::Read<u64>(size_t idx) {
return idx == 0 ? 0 : gpr[idx];
}
template <>
s64 Registers::Read<s64>(const size_t idx) {
return static_cast<s64>(Read<u64>(idx));
}
template <>
u32 Registers::Read<u32>(size_t idx) {
return idx == 0 ? 0 : gpr[idx];
}
template <>
s32 Registers::Read<s32>(size_t idx) {
return static_cast<s32>(Read<u32>(idx));
}
template <>
u16 Registers::Read<u16>(size_t idx) {
return idx == 0 ? 0 : gpr[idx];
}
template <>
s16 Registers::Read<s16>(size_t idx) {
return static_cast<s16>(Read<u16>(idx));
}
template <>
u8 Registers::Read<u8>(size_t idx) {
return idx == 0 ? 0 : gpr[idx];
}
template <>
s8 Registers::Read<s8>(size_t idx) {
return static_cast<s8>(Read<u8>(idx));
}
template <>
void Registers::Read<u64>(size_t idx, Xbyak::Reg reg) {
jit->code.mov(reg.cvt64(), jit->GPR<u64>(idx));
@@ -80,41 +115,6 @@ void Registers::Read<s8>(size_t idx, Xbyak::Reg reg) {
jit->code.mov(reg.cvt8(), jit->GPR<s8>(idx));
}
template <>
s64 Registers::Read<s64>(const size_t idx) {
return static_cast<s64>(Read<u64>(idx));
}
template <>
u32 Registers::Read<u32>(size_t idx) {
return idx == 0 ? 0 : gpr[idx];
}
template <>
s32 Registers::Read<s32>(size_t idx) {
return static_cast<s32>(Read<u32>(idx));
}
template <>
u16 Registers::Read<u16>(size_t idx) {
return idx == 0 ? 0 : gpr[idx];
}
template <>
s16 Registers::Read<s16>(size_t idx) {
return static_cast<s16>(Read<u16>(idx));
}
template <>
u8 Registers::Read<u8>(size_t idx) {
return idx == 0 ? 0 : gpr[idx];
}
template <>
s8 Registers::Read<s8>(size_t idx) {
return static_cast<s8>(Read<u8>(idx));
}
template <>
void Registers::WriteJIT<bool>(size_t idx, bool v) {
jit->code.mov(jit->code.al, v);
@@ -126,10 +126,11 @@ void Registers::Write<bool>(size_t idx, bool v, bool isConstant) {
if (idx == 0)
return;
bool oldIsConstant = gprIsConstant[idx];
gprIsConstant[idx] = isConstant;
if (jit) {
if (isConstant) {
if (oldIsConstant) {
gpr[idx] = v;
return;
}
@@ -152,10 +153,11 @@ void Registers::Write<u64>(size_t idx, u64 v, bool isConstant) {
if (idx == 0)
return;
bool oldIsConstant = gprIsConstant[idx];
gprIsConstant[idx] = isConstant;
if (jit) {
if (isConstant) {
if (oldIsConstant) {
gpr[idx] = v;
return;
}
@@ -183,10 +185,11 @@ void Registers::Write<u32>(size_t idx, u32 v, bool isConstant) {
if (idx == 0)
return;
bool oldIsConstant = gprIsConstant[idx];
gprIsConstant[idx] = isConstant;
if (jit) {
if (isConstant) {
if (oldIsConstant) {
gpr[idx] = v;
return;
}
@@ -210,10 +213,11 @@ void Registers::Write<s32>(size_t idx, s32 v, bool isConstant) {
if (idx == 0)
return;
bool oldIsConstant = gprIsConstant[idx];
gprIsConstant[idx] = isConstant;
if (jit) {
if (isConstant) {
if (oldIsConstant) {
gpr[idx] = v;
return;
}
@@ -236,10 +240,11 @@ void Registers::Write<u16>(size_t idx, u16 v, bool isConstant) {
if (idx == 0)
return;
bool oldIsConstant = gprIsConstant[idx];
gprIsConstant[idx] = isConstant;
if (jit) {
if (isConstant) {
if (oldIsConstant) {
gpr[idx] = v;
return;
}
@@ -263,10 +268,11 @@ void Registers::Write<s16>(size_t idx, s16 v, bool isConstant) {
if (idx == 0)
return;
bool oldIsConstant = gprIsConstant[idx];
gprIsConstant[idx] = isConstant;
if (jit) {
if (isConstant) {
if (oldIsConstant) {
gpr[idx] = v;
return;
}
@@ -289,10 +295,11 @@ void Registers::Write<u8>(size_t idx, u8 v, bool isConstant) {
if (idx == 0)
return;
bool oldIsConstant = gprIsConstant[idx];
gprIsConstant[idx] = isConstant;
if (jit) {
if (isConstant) {
if (oldIsConstant) {
gpr[idx] = v;
return;
}
@@ -316,10 +323,11 @@ void Registers::Write<s8>(size_t idx, s8 v, bool isConstant) {
if (idx == 0)
return;
bool oldIsConstant = gprIsConstant[idx];
gprIsConstant[idx] = isConstant;
if (jit) {
if (isConstant) {
if (oldIsConstant) {
gpr[idx] = v;
return;
}

View File

@@ -29,7 +29,7 @@ struct Registers {
Cop1 cop1;
s64 oldPC{}, pc{}, nextPC{};
s64 hi{}, lo{};
bool prevDelaySlot{}, delaySlot{}, block_delaySlot{};
bool prevDelaySlot{}, delaySlot{};
u32 steps = 0;
u32 extraCycles = 0;

View File

@@ -14,6 +14,12 @@ FORCE_INLINE void WriteFileBinary(const std::vector<u8> &data, const std::string
std::copy(data.begin(), data.end(), std::ostreambuf_iterator{file});
}
FORCE_INLINE void WriteFileBinary(const u8 *data, const size_t size, const std::string &path) {
FILE *out = fopen(path.c_str(), "wb");
fwrite(data, size, 1, out);
fclose(out);
}
template <size_t Size>
FORCE_INLINE void WriteFileBinary(const std::array<u8, Size> &data, const std::string &path) {
std::ofstream file(path, std::ios::binary);