[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() { int JIT::Step() {
blockPC = regs.pc; blockPC = regs.pc;
u32 paddr = 0;
if (!blockCache[blockPC >> 8].empty()) { if (!regs.cop0.MapVAddr(Cop0::LOAD, blockPC, paddr)) {
if (blockCache[blockPC >> 8][blockPC >> 20]) { /*regs.cop0.HandleTLBException(blockPC);
return blockCache[blockPC >> 8][blockPC >> 20](); regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, blockPC);
} return 1;*/
} else { Util::panic(
blockCache[blockPC >> 8].resize(kLowerSize); "[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(); // CheckCompareInterrupt();
if (check_address_error(0b11, u64(blockPC))) [[unlikely]] { if (check_address_error(0b11, u64(blockPC))) [[unlikely]] {
@@ -45,37 +75,61 @@ int JIT::Step() {
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, blockPC); regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, blockPC);
return 1;*/ return 1;*/
Util::panic("[JIT]: Unhandled exception ADL due to unaligned PC virtual value! (0x{:016lX})", Util::panic("[JIT]: Unhandled exception ADL due to unaligned PC virtual value! (0x{:016lX})", blockPC);
static_cast<u64>(regs.pc));
} }
u32 paddr = 0;
if (!regs.cop0.MapVAddr(Cop0::LOAD, blockPC, paddr)) { if (!regs.cop0.MapVAddr(Cop0::LOAD, blockPC, paddr)) {
/*regs.cop0.HandleTLBException(blockPC); /*regs.cop0.HandleTLBException(blockPC);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, blockPC); regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, blockPC);
return 1;*/ return 1;*/
Util::panic( Util::panic(
"[JIT]: Unhandled exception TLB exception {} when retrieving PC physical address! (virtual: 0x{:016lX})", "[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()) { /*if(ShouldServiceInterrupt()) {
regs.cop0.FireException(ExceptionCode::Interrupt, 0, regs.pc); regs.cop0.FireException(ExceptionCode::Interrupt, 0, blockPC);
return 1; return 1;
}*/ }*/
blockPC += 4; blockPC += 4;
instructionsInBlock++;
Emit(instruction); 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 // emit code to store the value of pc
blockCache[regs.pc >> 8][regs.pc >> 20] = code.getCurr<BlockFn>(); if (!blockEndsOnBranch) {
return blockCache[regs.pc >> 8][regs.pc >> 20](); 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() { std::vector<u8> JIT::Serialize() {

View File

@@ -7,12 +7,14 @@
namespace n64 { namespace n64 {
struct Core; struct Core;
static constexpr u32 kAddressSpaceSize = 0x8000'0000; // >> 20 = 0x800 static constexpr u64 kAddressSpaceSize = 0x8000'0000;
static constexpr u32 kLowerSize = kAddressSpaceSize >> 20; // 0x800 static constexpr u8 kUpperShift = 8;
static constexpr u32 kUpperSize = kAddressSpaceSize >> 8; // 0x100000 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 kCodeCacheSize = 32_mb;
static constexpr u32 kCodeCacheAllocSize = kCodeCacheSize + 4096; static constexpr u32 kCodeCacheAllocSize = kCodeCacheSize + 4_kb;
#define REG(acc, x) code.acc[reinterpret_cast<uintptr_t>(&regs.x)] #define REG(acc, x) code.acc[code.rbp + (reinterpret_cast<uintptr_t>(&regs.x) - (uintptr_t)this)]
struct JIT : BaseCPU { struct JIT : BaseCPU {
explicit JIT(ParallelRDP &); explicit JIT(ParallelRDP &);
@@ -46,13 +48,13 @@ private:
template <typename T> template <typename T>
Xbyak::Address GPR(const size_t index) const { Xbyak::Address GPR(const size_t index) const {
if constexpr (sizeof(T) == 1) { 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) { } 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) { } 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) { } 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"); Util::panic("[JIT]: Invalid register addressing");
@@ -60,18 +62,11 @@ private:
return Xbyak::Address{0}; return Xbyak::Address{0};
} }
// Credits to PCSX-Redux: https://github.com/grumpycoders/pcsx-redux // Thanks to 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)); }
// Load a pointer to the JIT object in "reg" // 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> template <typename T>
void emitMemberFunctionCall(T func, void *thisObject) { void emitMemberFunctionCall(T func, void *thisObject) {
void *functionPtr; uintptr_t functionPtr;
auto thisPtr = reinterpret_cast<uintptr_t>(thisObject); auto thisPtr = reinterpret_cast<uintptr_t>(thisObject);
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) #if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
@@ -82,24 +77,22 @@ private:
uintptr_t arr[2]; uintptr_t arr[2];
std::memcpy(arr, &func, sizeof(T)); std::memcpy(arr, &func, sizeof(T));
// First 8 bytes correspond to the actual pointer to the function // 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 // Next 8 bytes correspond to the "this" pointer adjustment
thisPtr += arr[1]; thisPtr += arr[1];
#endif #endif
// Load this pointer to arg1 code.mov(code.rdi, thisPtr);
if (thisPtr == reinterpret_cast<uintptr_t>(this)) { code.mov(code.rax, functionPtr);
loadThisPointer(code.rdi); code.call(code.rax);
} else {
loadAddress(code.rdi, reinterpret_cast<void *>(thisPtr));
}
code.call(functionPtr);
} }
void SkipSlot(); void SkipSlot();
void SkipSlotConstant(); void SkipSlotConstant();
void BranchTaken(s64 offs); 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) \ #define check_address_error(mask, vaddr) \
(((!regs.cop0.is64BitAddressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0)) (((!regs.cop0.is64BitAddressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0))
@@ -118,8 +111,9 @@ private:
void addiu(u32); void addiu(u32);
void andi(u32); void andi(u32);
void and_(u32); void and_(u32);
void branch_constant(bool cond, s64 address); void branch_constant(bool cond, s64 offset);
void branch_likely_constant(bool cond, s64 address); void branch_likely_constant(bool cond, s64 offset);
void branch_abs_constant(bool cond, s64 address);
void bltz(u32); void bltz(u32);
void bgez(u32); void bgez(u32);
void bltzl(u32); void bltzl(u32);
@@ -188,17 +182,17 @@ private:
void mthi(u32); void mthi(u32);
void mtlo(u32); void mtlo(u32);
void nor(u32); void nor(u32);
void sb(u32); void sb(u32) {}
void sc(u32); void sc(u32) {}
void scd(u32); void scd(u32) {}
void sd(u32); void sd(u32) {}
void sdc1(u32); void sdc1(u32) {}
void sdl(u32); void sdl(u32) {}
void sdr(u32); void sdr(u32) {}
void sh(u32); void sh(u32) {}
void sw(u32); void sw(u32);
void swl(u32); void swl(u32) {}
void swr(u32); void swr(u32) {}
void slti(u32); void slti(u32);
void sltiu(u32); void sltiu(u32);
void slt(u32); void slt(u32);
@@ -207,12 +201,12 @@ private:
void sllv(u32); void sllv(u32);
void sub(u32); void sub(u32);
void subu(u32); void subu(u32);
void swc1(u32); void swc1(u32) {}
void sra(u32); void sra(u32);
void srav(u32); void srav(u32);
void srl(u32); void srl(u32);
void srlv(u32); void srlv(u32);
void trap(bool); void trap(bool) {}
void or_(u32); void or_(u32);
void ori(u32); void ori(u32);
void xor_(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 <> template <>
void Mem::WriteInterpreter<u8>(Registers &regs, u32 paddr, u32 val) { void Mem::WriteInterpreter<u8>(Registers &regs, u32 paddr, u32 val) {
SI &si = mmio.si; SI &si = mmio.si;
@@ -371,16 +358,15 @@ void Mem::WriteInterpreter<u8>(Registers &regs, u32 paddr, u32 val) {
} }
template <> 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) if (jit)
jit->InvalidateBlock(paddr); jit->InvalidateBlock(paddr);
WriteInterpreter<u16>(regs, paddr, val);
} }
template <> template <>
void Mem::Write<u16>(Registers &regs, const u32 paddr, const u32 val) { void Mem::Write<u8>(Registers &regs, const u32 paddr, const u32 val) {
WriteInterpreter<u16>(regs, paddr, val); WriteInterpreter<u8>(regs, paddr, val);
} }
template <> template <>
@@ -425,16 +411,15 @@ void Mem::WriteInterpreter<u16>(Registers &regs, u32 paddr, u32 val) {
} }
template <> 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) if (jit)
jit->InvalidateBlock(paddr); jit->InvalidateBlock(paddr);
WriteInterpreter<u32>(regs, paddr, val);
} }
template <> template <>
void Mem::Write<u32>(Registers &regs, const u32 paddr, const u32 val) { void Mem::Write<u16>(Registers &regs, const u32 paddr, const u32 val) {
WriteInterpreter<u32>(regs, paddr, val); WriteInterpreter<u16>(regs, paddr, val);
} }
template <> 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) if (jit)
jit->InvalidateBlock(paddr); 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); 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); } 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 PI;
friend struct AI; friend struct AI;
friend struct RSP; friend struct RSP;
friend struct JIT;
friend struct Core; friend struct Core;
std::array<u8, ISVIEWER_SIZE> isviewer{}; std::array<u8, ISVIEWER_SIZE> isviewer{};
std::string sramPath{}; std::string sramPath{};

View File

@@ -602,10 +602,8 @@ void Interpreter::jal(const u32 instr) {
} }
void Interpreter::jalr(const u32 instr) { void Interpreter::jalr(const u32 instr) {
const u64 addr = regs.Read<s64>(RS(instr)); regs.Write(RD(instr), regs.nextPC);
const s64 currentNextPC = regs.nextPC; jr(instr);
branch(true, addr);
regs.Write(RD(instr), currentNextPC);
} }
void Interpreter::jr(const u32 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) { static bool InstrEndsBlock(const u32 instr) {
switch (instr >> 26 & 0x3f) { switch (instr >> 26 & 0x3f) {
case SPECIAL: case SPECIAL:
return SpecialEndsBlock(instr); return SpecialEndsBlock(instr);
case REGIMM: case REGIMM:
return RegimmEndsBlock(instr);
case J: case J:
case JAL: case JAL:
case BEQ: case BEQ:
@@ -49,4 +36,37 @@ static bool InstrEndsBlock(const u32 instr) {
return false; 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 } // namespace n64

View File

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

View File

@@ -29,7 +29,7 @@ struct Registers {
Cop1 cop1; Cop1 cop1;
s64 oldPC{}, pc{}, nextPC{}; s64 oldPC{}, pc{}, nextPC{};
s64 hi{}, lo{}; s64 hi{}, lo{};
bool prevDelaySlot{}, delaySlot{}, block_delaySlot{}; bool prevDelaySlot{}, delaySlot{};
u32 steps = 0; u32 steps = 0;
u32 extraCycles = 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}); 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> template <size_t Size>
FORCE_INLINE void WriteFileBinary(const std::array<u8, Size> &data, const std::string &path) { FORCE_INLINE void WriteFileBinary(const std::array<u8, Size> &data, const std::string &path) {
std::ofstream file(path, std::ios::binary); std::ofstream file(path, std::ios::binary);