diff --git a/CMakeLists.txt b/CMakeLists.txt index 41b06896..511a7379 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,4 +26,4 @@ find_package(Qt6 COMPONENTS Core Gui Widgets) if (Qt6_FOUND) add_subdirectory(src/frontend) -endif() +endif() \ No newline at end of file diff --git a/src/backend/Core.cpp b/src/backend/Core.cpp index e0d59403..aebab03b 100644 --- a/src/backend/Core.cpp +++ b/src/backend/Core.cpp @@ -65,7 +65,7 @@ void Core::Run(float volumeL, float volumeR) { InterruptRaise(mmio.mi, regs, Interrupt::VI); } - for(; cycles < mem.mmio.vi.cyclesPerHalfline;) { + for(; cycles < mem.mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) { u32 taken = cpu->Step(); taken += PopStalledCycles(); static u32 cpuSteps = 0; diff --git a/src/backend/core/JIT.cpp b/src/backend/core/JIT.cpp deleted file mode 100644 index 74946b01..00000000 --- a/src/backend/core/JIT.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include -#include - -namespace n64 { -using namespace Xbyak; -JIT::JIT() : CodeGenerator(32*1024*1024, AutoGrow) { } - -void JIT::Reset() { - reset(); - regs.Reset(); - mem.Reset(); -} - -bool JIT::ShouldServiceInterrupt() { - bool interrupts_pending = (regs.cop0.status.im & regs.cop0.cause.interruptPending) != 0; - bool interrupts_enabled = regs.cop0.status.ie == 1; - bool currently_handling_exception = regs.cop0.status.exl == 1; - bool currently_handling_error = regs.cop0.status.erl == 1; - - return interrupts_pending && interrupts_enabled && - !currently_handling_exception && !currently_handling_error; -} - -void JIT::CheckCompareInterrupt() { - regs.cop0.count++; - regs.cop0.count &= 0x1FFFFFFFF; - if(regs.cop0.count == (u64)regs.cop0.compare << 1) { - regs.cop0.cause.ip7 = 1; - UpdateInterrupt(mem.mmio.mi, regs); - } -} - -Fn JIT::Recompile() { - bool stable = true; - bool old_stable = stable; - cycles = 0; - //prologue(); - //mov(rbp, u64(this)); - //mov(rdi, u64(this) + THIS_OFFSET(regs)); - u64 pc = regs.pc; - while(old_stable) { - old_stable = stable; - - cycles++; - CheckCompareInterrupt(); - - // mov(rax, REG(byte, delaySlot)); - // mov(REG(byte, prevDelaySlot), rax); - // mov(REG(byte, delaySlot), 0); - - u32 paddr = 0; - if (!MapVAddr(regs, LOAD, pc, paddr)) { - //mov(rsi, regs.pc); - //emitCall(HandleTLBException); - //mov(rsi, u64(GetTLBExceptionCode(regs.cop0.tlbError, LOAD))); - //CodeGenerator::xor_(rdx, rdx); - //CodeGenerator::xor_(rcx, rcx); - //emitCall(FireException); - //goto _epilogue; - } - - pc += 4; - u32 instr = mem.Read(regs, paddr); - stable = isStable(instr); - Emit(instr); - - if (ShouldServiceInterrupt()) { - //mov(rsi, u64(ExceptionCode::Interrupt)); - //CodeGenerator::xor_(rdx, rdx); - //CodeGenerator::xor_(rcx, rcx); - //push(rax); - //call(FireException); - //goto _epilogue; - } - - //mov(rax, REG(qword, pc)); - //mov(REG(qword, oldPC), rax); - //mov(rax, REG(qword, nextPC)); - //mov(REG(qword, pc), rax); - //CodeGenerator::add(REG(qword, nextPC), 4); - } -_epilogue: - //epilogue(); - //ready(); - //return getCode(); - ir.optimize(); - ir.print(); - exit(1); - return nullptr; -} - -int JIT::Step() { - if(!blocks[BLOCKCACHE_OUTER_INDEX(regs.pc)]) { - blocks[BLOCKCACHE_OUTER_INDEX(regs.pc)] = (Fn*)calloc(BLOCKCACHE_INNER_SIZE, 1); - blocks[BLOCKCACHE_OUTER_INDEX(regs.pc)][BLOCKCACHE_INNER_INDEX(regs.pc)] = Recompile(); - } - - if (!blocks[BLOCKCACHE_OUTER_INDEX(regs.pc)][BLOCKCACHE_INNER_INDEX(regs.pc)]) { - blocks[BLOCKCACHE_OUTER_INDEX(regs.pc)][BLOCKCACHE_INNER_INDEX(regs.pc)] = Recompile(); - } - - //return blocks[BLOCKCACHE_OUTER_INDEX(regs.pc)][BLOCKCACHE_INNER_INDEX(regs.pc)](); - return 1; -} -} diff --git a/src/backend/core/JIT.hpp b/src/backend/core/JIT.hpp deleted file mode 100644 index fdbca9dc..00000000 --- a/src/backend/core/JIT.hpp +++ /dev/null @@ -1,259 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include - -namespace n64 { -using Fn = int(*)(); -#define THIS_OFFSET(x) ((uintptr_t)(&x) - (uintptr_t)this) -#define GPR_OFFSET(x) ((uintptr_t)®s.gpr[(x)] - (uintptr_t)this) -#define REG_OFFSET(member) ((uintptr_t)®s.member - (uintptr_t)this) -#define GPR(ptr, x) ptr[rdi + GPR_OFFSET(x)] -#define REG(ptr, member) ptr[rdi + REG_OFFSET(member)] -// 4KiB aligned pages -#define BLOCKCACHE_OUTER_SHIFT 12 -#define BLOCKCACHE_PAGE_SIZE (1 << BLOCKCACHE_OUTER_SHIFT) -#define BLOCKCACHE_OUTER_SIZE (0x80000000 >> BLOCKCACHE_OUTER_SHIFT) -// word aligned instructions -#define BLOCKCACHE_INNER_SIZE (BLOCKCACHE_PAGE_SIZE >> 2) -#define BLOCKCACHE_INNER_INDEX(physical) (((physical) & (BLOCKCACHE_PAGE_SIZE - 1)) >> 2) -#define BLOCKCACHE_OUTER_INDEX(physical) ((physical) >> BLOCKCACHE_OUTER_SHIFT) - -struct JIT : BaseCPU, Xbyak::CodeGenerator { - JIT(); - ~JIT() override = default; - int Step() override; - void Reset() override; - friend struct Cop1; - friend struct Cop0; -private: - IR ir{}; - int cycles = 0; - bool ShouldServiceInterrupt() override; - void CheckCompareInterrupt() override; - Fn Recompile(); - - template - void emitMemberCall(T func, void* thisObj) { - T* funcPtr; - auto thisPtr = reinterpret_cast(thisObj); -#ifdef ABI_WINDOWS - static_assert(sizeof(T) == 8, "[JIT]: Invalid size for member function pointer"); - std::memcpy(&funcPtr, &func, sizeof(T)); -#elif defined(ABI_UNIX) - static_assert(sizeof(T) == 16, "[JIT]: Invalid size for member function pointer"); - uintptr_t tmpArr[2]; - std::memcpy(tmpArr, &func, sizeof(T)); - funcPtr = reinterpret_cast(tmpArr[0]); - thisPtr += tmpArr[1]; -#else - Util::panic("Huh?!"); -#endif - - push(rdi); - if(thisPtr == reinterpret_cast(this)) { - mov(rdi, rbp); - } else { - mov(rdi, (uintptr_t)thisPtr); - } - call(funcPtr); - pop(rdi); - } - - template - void emitCall(T func) { - T* funcPtr; -#ifdef ABI_WINDOWS - std::memcpy(&funcPtr, &func, sizeof(T)); -#elif defined(ABI_UNIX) - uintptr_t tmpArr[2]; - std::memcpy(tmpArr, &func, sizeof(T)); - funcPtr = reinterpret_cast(tmpArr[0]); -#else - Util::panic("Huh?!"); -#endif - - push(rdi); - call(funcPtr); - pop(rdi); - } - - bool isStable(u32 instr) { - u8 mask = (instr >> 26) & 0x3f; - switch(mask) { - case SPECIAL: - mask = instr & 0x3f; - switch(mask) { - case JR ... JALR: - case SYSCALL: case BREAK: - case TGE ... TNE: - return false; - default: return true; - } - case REGIMM: - case J ... BGTZ: - case BEQL ... BGTZL: - return false; - case COP1: - mask = (instr >> 16) & 0x1f; - if(mask >= 0 && mask <= 3) { - return false; - } - default: return true; - } - } - - FORCE_INLINE void prologue() { - const Xbyak::Reg64 allRegs[]{rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15}; - for(auto r : allRegs) { - push(r); - } - } - - FORCE_INLINE void epilogue() { - const Xbyak::Reg64 allRegs[]{r15, r14, r13, r12, r11, r10, r9, r8, rdi, rsi, rbp, rsp, rbx, rdx, rcx, rax}; - for(auto r : allRegs) { - pop(r); - } - mov(rax, cycles); - ret(); - } - - Fn* blocks[BLOCKCACHE_OUTER_SIZE]{}; - - std::vector Serialize() override { return {}; } - void Deserialize(const std::vector&) override { } - - void cop2Decode(u32); - void special(u32); - void regimm(u32); - void Emit(u32); - void add(u32); - void addu(u32); - void addi(u32); - void addiu(u32); - void andi(u32); - void and_(u32); - Entry::Operand branch(u32); - void bltz(u32); - void bgez(u32); - void bltzl(u32); - void bgezl(u32); - void bltzal(u32); - void bgezal(u32); - void bltzall(u32); - void bgezall(u32); - void beq(u32); - void bne(u32); - void blez(u32); - void bgtz(u32); - void beql(u32); - void bnel(u32); - void blezl(u32); - void bgtzl(u32); - void dadd(u32); - void daddu(u32); - void daddi(u32); - void daddiu(u32); - void ddiv(u32); - void ddivu(u32); - void div(u32); - void divu(u32); - void dmult(u32); - void dmultu(u32); - void dsll(u32); - void dsllv(u32); - void dsll32(u32); - void dsra(u32); - void dsrav(u32); - void dsra32(u32); - void dsrl(u32); - void dsrlv(u32); - void dsrl32(u32); - void dsub(u32); - void dsubu(u32); - void j(u32); - void jr(u32); - void jal(u32); - void jalr(u32); - void lui(u32); - void lbu(u32); - void lb(u32); - void ld(u32); - void ldl(u32); - void ldr(u32); - void lh(u32); - void lhu(u32); - void ll(u32); - void lld(u32); - void lw(u32); - void lwl(u32); - void lwu(u32); - void lwr(u32); - void mfhi(u32); - void mflo(u32); - void mult(u32); - void multu(u32); - void mthi(u32); - void mtlo(u32); - void nor(u32); - void sb(u32); - void sc(u32); - void scd(u32); - void sd(u32); - void sdl(u32); - void sdr(u32); - void sh(u32); - void sw(u32); - void swl(u32); - void swr(u32); - void slti(u32); - void sltiu(u32); - void slt(u32); - void sltu(u32); - void sll(u32); - void sllv(u32); - void sub(u32); - void subu(u32); - void sra(u32); - void srav(u32); - void srl(u32); - void srlv(u32); - void tgei(u32); - void tgeiu(u32); - void tlti(u32); - void tltiu(u32); - void teqi(u32); - void tnei(u32); - void tge(u32); - void tgeu(u32); - void tlt(u32); - void tltu(u32); - void teq(u32); - void tne(u32); - void or_(u32); - void ori(u32); - void xor_(u32); - void xori(u32); - - void mtc0(u32); - void dmtc0(u32); - void mfc0(u32); - void dmfc0(u32); - void eret(); - - void tlbr(); - void tlbw(int); - void tlbp(); - - void mtc2(u32); - void mfc2(u32); - void dmtc2(u32); - void dmfc2(u32); - void ctc2(u32); - void cfc2(u32); -}; -} diff --git a/src/backend/core/JIT/IR.cpp b/src/backend/core/JIT/IR.cpp deleted file mode 100644 index 81aab37d..00000000 --- a/src/backend/core/JIT/IR.cpp +++ /dev/null @@ -1,241 +0,0 @@ -#include -#include -#include -#include - -namespace n64 { -template <> struct fmt::formatter : formatter { - auto format(Entry e, format_context& ctx) const { - std::string op = "Unknown"; - switch (e.op) { - case Entry::MOV: op = "MOV"; break; - case Entry::ADD: op = "ADD"; break; - case Entry::SUB: op = "SUB"; break; - case Entry::UMUL: op = "UMUL"; break; - case Entry::SMUL: op = "SMUL"; break; - case Entry::DIV: op = "DIV"; break; - case Entry::AND: op = "AND"; break; - case Entry::NOR: op = "NOR"; break; - case Entry::XOR: op = "XOR"; break; - case Entry::OR: op = "OR"; break; - case Entry::SRL: op = "SRL"; break; - case Entry::SLL: op = "SLL"; break; - case Entry::SRA: op = "SRA"; break; - case Entry::LOADS8: op = "LOADS8"; break; - case Entry::LOADS8_SHIFT: op = "LOADS8_SHIFT"; break; - case Entry::STORE8: op = "STORE8"; break; - case Entry::STORE8_SHIFT: op = "STORE8_SHIFT"; break; - case Entry::LOADS16: op = "LOADS16"; break; - case Entry::LOADS16_SHIFT: op = "LOADS16_SHIFT"; break; - case Entry::STORE16: op = "STORE16"; break; - case Entry::STORE16_SHIFT: op = "STORE16_SHIFT"; break; - case Entry::LOADS32: op = "LOADS32"; break; - case Entry::LOADS32_SHIFT: op = "LOADS32_SHIFT"; break; - case Entry::STORE32: op = "STORE32"; break; - case Entry::STORE32_SHIFT: op = "STORE32_SHIFT"; break; - case Entry::LOADS64: op = "LOADS64"; break; - case Entry::LOADS64_SHIFT: op = "LOADS64_SHIFT"; break; - case Entry::STORE64: op = "STORE64"; break; - case Entry::STORE64_SHIFT: op = "STORE64_SHIFT"; break; - case Entry::LOADU8: op = "LOADU8"; break; - case Entry::LOADU8_SHIFT: op = "LOADU8_SHIFT"; break; - case Entry::LOADU16: op = "LOADU16"; break; - case Entry::LOADU16_SHIFT: op = "LOADU16_SHIFT"; break; - case Entry::LOADU32: op = "LOADU32"; break; - case Entry::LOADU32_SHIFT: op = "LOADU32_SHIFT"; break; - case Entry::LOADU64: op = "LOADU64"; break; - case Entry::LOADU64_SHIFT: op = "LOADU64_SHIFT"; break; - case Entry::BRANCH: op = "BRANCH"; break; - case Entry::JUMP: op = "JUMP"; break; - case Entry::MTC0: op = "MTC0"; break; - case Entry::MFC0: op = "MFC0"; break; - case Entry::SLT: op = "SLT"; break; - } - - bool put_comma = false; - op += " "; - if (e.dst.isReg()) { - if (e.dst.index_or_imm.has_value()) { - std::string dst = fmt::format("R{}", e.dst.index_or_imm.value()); - op += dst; - put_comma = true; - } - } else if(e.dst.isImm()) { - std::string dst = fmt::format("0x{:0X}", e.dst.index_or_imm.value()); - op += dst; - put_comma = true; - } else if(e.dst.type == Entry::Operand::PC64) { - std::string dst = fmt::format("PC"); - op += dst; - put_comma = true; - } else { - if(e.dst.type != Entry::Operand::NONE) { - std::string dst = fmt::format("(0x{:0X})", e.dst.index_or_imm.value()); - op += dst; - put_comma = true; - } - } - - if (e.bOffs.index_or_imm.has_value()) { - std::string dst; - if (e.bOffs.isReg()) { - dst = fmt::format("R{}", e.bOffs.index_or_imm.value()); - } else if (e.bOffs.isImm()) { - dst = fmt::format("0x{:0X}", e.bOffs.index_or_imm.value()); - } - op += dst; - put_comma = true; - } - - if (e.op1.isReg()) { - if (e.op1.index_or_imm.has_value()) { - std::string op1 = fmt::format("R{}", e.op1.index_or_imm.value()); - if(put_comma) { - op += ", "; - } - op += op1; - put_comma = true; - } - } else if(e.op1.isImm()) { - if (e.op1.index_or_imm.has_value()) { - std::string op1 = fmt::format("0x{:0X}", e.op1.index_or_imm.value()); - if(put_comma) { - op += ", "; - } - op += op1; - put_comma = true; - } - } else if (e.dst.type == Entry::Operand::PC64) { - std::string dst = fmt::format("PC"); - if (put_comma) { - op += ", "; - } - op += dst; - put_comma = true; - } else { - if (e.op1.index_or_imm.has_value()) { - std::string op1 = fmt::format("(0x{:0X})", e.op1.index_or_imm.value()); - if(put_comma) { - op += ", "; - } - op += op1; - put_comma = false; - } - } - - if (e.branchCond.has_value()) { - put_comma = false; - op += " "; - switch (e.branchCond.value()) { - case Entry::AL: op += " "; break; - case Entry::EQ: op += "== "; break; - case Entry::NE: op += "!= "; break; - case Entry::LT: op += "< "; break; - case Entry::GT: op += "> "; break; - case Entry::LE: op += "<= "; break; - case Entry::GE: op += ">= "; break; - } - } - - if (e.op2.isReg()) { - if (e.op2.index_or_imm.has_value()) { - std::string op2 = fmt::format("R{}", e.op2.index_or_imm.value()); - if(put_comma) { - op += ", "; - } - op += op2; - } - } else { - if (e.op2.index_or_imm.has_value()) { - std::string op2 = fmt::format("0x{:0X}", e.op2.index_or_imm.value()); - if(put_comma) { - op += ", "; - } - op += op2; - } - } - - op += '\n'; - return formatter::format(op, ctx); - } -}; - -Entry::Entry(Opcode op, Operand dst, Operand op1, Operand op2) - : op(op), dst(dst), op1(op1), op2(op2) {} - -Entry::Entry(Opcode op, Operand op1, Operand op2) - : op(op), op1(op1), op2(op2) {} - -Entry::Entry(Opcode op, Operand bOffs, Operand op1, std::optional bc, Operand op2) - : op(op), bOffs(bOffs), op1(op1), branchCond(bc), op2(op2) {} - -Entry::Entry(Opcode op, Operand bOffs) -: op(op), bOffs(bOffs) {} - -Entry::Entry(Opcode op, Operand dst, Operand op1, Operand op2, Shift s) - : op(op), dst(dst), op1(op1), op2(op2), shift(s) {} - -void IR::push(const Entry& e) { - code.push_back(e); -} - -std::vector IR::constant_propagation(std::vector& code_) { - std::vector optimized{}; - - return optimized; -} - -std::vector IR::dead_code_elimination(std::vector& code_) { - std::vector optimized{}; - for(const auto& i : code_) { - bool isOp1Reg = i.op1.isReg(); - bool isOp2Reg = i.op2.isReg(); - bool isDstReg = i.dst.isReg(); - - // check for operations like "add rx, rx, 0" or "add r0, anything" - if(isDstReg) { - bool isDstR0 = i.dst.isReg() && i.dst.index_or_imm.has_value() && i.dst.index_or_imm.value() == 0; - bool areDstAndOp1Same = i.dst.isReg() && i.op1.isReg() && i.dst.index_or_imm.has_value() && i.op1.index_or_imm.has_value() && i.op1.index_or_imm.value() == i.dst.index_or_imm.value(); - bool areDstAndOp2Same = i.dst.isReg() && i.op2.isReg() && i.dst.index_or_imm.has_value() && i.op2.index_or_imm.has_value() && i.op2.index_or_imm.value() == i.dst.index_or_imm.value(); - if (isDstR0) continue; - if (i.canDoDCE()) { - if (areDstAndOp1Same) { - if (i.op2.isImm() && i.op2.index_or_imm.value() == 0) continue; - } - - if (areDstAndOp2Same) { - if (i.op1.isImm() && i.op1.index_or_imm.value() == 0) continue; - } - } - } - - optimized.push_back(i); - } - - return optimized; -} - -void IR::optimize() { - std::vector optimized{}; - - while (optimized.size() < code.size()) { - optimized = dead_code_elimination(code); - //optimized = constant_propagation(optimized); - code = optimized; - } -} - -void IR::print() { - for(auto e : code) { - fmt::print("{}", e); - } -} - -auto IR::begin() { - return code.begin(); -} - -auto IR::end() { - return code.end(); -} -} \ No newline at end of file diff --git a/src/backend/core/JIT/IR.hpp b/src/backend/core/JIT/IR.hpp deleted file mode 100644 index 4cd60a82..00000000 --- a/src/backend/core/JIT/IR.hpp +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace n64 { -struct Entry { - enum : u16 { - LINK = 0x100, - LIKELY = 0x200, - REGISTER = 0x400, - SET_LLBIT = 0x800, - UNSET_LLBIT = 0x1000, - }; - - enum Shift { - LEFT, RIGHT - }; - - enum Opcode : u16 { - MOV, SLT, ADD, SUB, UMUL, SMUL, DIV, AND, NOR, - XOR, OR, SRL, SLL, SRA, - LOADS8, LOADS8_SHIFT, STORE8, STORE8_SHIFT, - LOADS16, LOADS16_SHIFT, STORE16, STORE16_SHIFT, - LOADS32, LOADS32_SHIFT, STORE32, STORE32_SHIFT, - LOADS64, LOADS64_SHIFT, STORE64, STORE64_SHIFT, - LOADU8, LOADU8_SHIFT, - LOADU16, LOADU16_SHIFT, - LOADU32, LOADU32_SHIFT, - LOADU64, LOADU64_SHIFT, - BRANCH, JUMP, MTC0, MFC0 - } op; - - struct Operand { - enum Type { - NONE, REG_F64, REG_F32, IMM_F64, IMM_F32, - REG_S64, REG_S32, REG_U64, REG_U32, REG_U5, IMM_S16, - IMM_S32, IMM_S64, IMM_U16, IMM_U32, IMM_U64, IMM_U5, - MEM_U8, MEM_U16, MEM_U32, MEM_U64, PC64, NEXTPC64, - LO, HI - } type = NONE; - - bool isReg() const { - return type == REG_S64 || type == REG_F32 || type == REG_F64 || type == REG_S32 - || type == REG_U64 || type == REG_U32 || type == REG_U5; - } - - bool isImm() const { - return type == IMM_S64 || type == IMM_U16 || type == IMM_S16 || - type == IMM_F32 || type == IMM_F64 || type == IMM_S32 || - type == IMM_U64 || type == IMM_U32 || type == IMM_U5; - } - - bool isMem() const { - return type == MEM_U8 || type == MEM_U16 || type == MEM_U32 || type == MEM_U64; - } - - std::optional index_or_imm = std::nullopt; - - Operand() = default; - Operand(Type t, std::optional imm = std::nullopt) - : type(t), index_or_imm(imm) {} - } dst, op1, op2; - - bool canDoDCE() const { - return op == ADD || op == OR || op == SRL || op == SLL || op == SRA; - } - - [[nodiscard]] const Operand& GetDst() const { return dst; } - - enum BranchCond { - AL, EQ, NE, LT, GT, LE, GE - }; - - std::optional branchCond = std::nullopt; - std::optional shift = std::nullopt; - Operand bOffs = Operand::NONE; - - Entry(Opcode op, Operand dst, Operand op1, Operand op2); - Entry(Opcode op, Operand op1, Operand op2); - Entry(Opcode op, Operand bOffs, Operand op1, std::optional bc, Operand op2); - Entry(Opcode op, Operand bOffs); - Entry(Opcode op, Operand dst, Operand op1, Operand op2, Shift s); -}; - -struct IR { - void push(const Entry&); - auto begin(); - auto end(); - void print(); - void optimize(); -private: - std::vector constant_propagation(std::vector&); - std::vector dead_code_elimination(std::vector&); - std::vector code{}; -}; -} \ No newline at end of file diff --git a/src/backend/core/JIT/IR/Opcode.hpp b/src/backend/core/JIT/IR/Opcode.hpp deleted file mode 100644 index 9bfc90bc..00000000 --- a/src/backend/core/JIT/IR/Opcode.hpp +++ /dev/null @@ -1,104 +0,0 @@ -#pragma once -#include -#include -#include - -namespace n64 { -enum class IROpcodeClass { - StorePC, Add, Special, Regimm, COP0, COP1 -}; - -struct IROpcode { - virtual ~IROpcode() = default; - virtual auto GetClass() const -> IROpcodeClass = 0; - virtual auto Reads (IRVariable const& var) -> bool = 0; - virtual auto Writes(IRVariable const& var) -> bool = 0; - virtual void Repoint(IRVariable const& var_old, IRVariable const& var_new) = 0; - virtual void PropagateConstant(IRVariable const& var, IRConstant const& constant) {} - virtual auto ToString() -> std::string = 0; -}; - -template -struct IROpcodeBase : IROpcode { - auto GetClass() const -> IROpcodeClass override { return _class; } -}; - -template -struct IRBinaryOpBase : IROpcodeBase<_class> { - IRBinaryOpBase(IRVariable const& result, IRVariable lhs, IRAnyRef rhs) - : result(const_cast(result)), lhs(lhs), rhs(rhs) {} - - IRVariable& result; - IRVarRef lhs; - IRAnyRef rhs; - - auto Reads(IRVariable const& var) -> bool override { - return &lhs.Get() == &var || - (rhs.IsVariable() && (&rhs.GetVar() == &var)); - } - - auto Writes(IRVariable const& var) -> bool override { - return result.HasValue() && (&result == &var); - } - - void Repoint( - IRVariable const& var_old, - IRVariable const& var_new - ) override { - // TODO: make this reusable? - if (result.HasValue() && (&result == &var_old)) { - result = var_new; - } - - lhs.Repoint(var_old, var_new); - rhs.Repoint(var_old, var_new); - } - - void PropagateConstant( - IRVariable const& var, - IRConstant const& constant - ) override { - rhs.PropagateConstant(var, constant); - } -}; - -struct IRStorePC final : IROpcodeBase { - IRStorePC(IRAnyRef val) : val(val) {} - - IRAnyRef val; - - auto Reads(IRVariable const& var) -> bool override { - if(val.IsVariable()) { - return &var == &val.GetVar(); - } - return false; - } - - auto Writes(IRVariable const& var) -> bool override { - return true; - } - - void Repoint( - IRVariable const& var_old, - IRVariable const& var_new - ) override { - } - - auto ToString() -> std::string override { - return fmt::format("str_pc {}", std::to_string(val)); - } -}; - -struct IRAdd final : IRBinaryOpBase { - using IRBinaryOpBase::IRBinaryOpBase; - - auto ToString() -> std::string override { - return fmt::format( - "add {}, {}, {}", - std::to_string(result), - std::to_string(lhs), - std::to_string(rhs) - ); - } -}; -} \ No newline at end of file diff --git a/src/backend/core/JIT/IR/Register.hpp b/src/backend/core/JIT/IR/Register.hpp deleted file mode 100644 index e42adccb..00000000 --- a/src/backend/core/JIT/IR/Register.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include - -namespace n64 { -struct IRGuestReg { - IRGuestReg(u8 reg) : reg(reg) {} - - /// The ARM general purpose register - const u8 reg; -}; -} \ No newline at end of file diff --git a/src/backend/core/JIT/IR/Value.hpp b/src/backend/core/JIT/IR/Value.hpp deleted file mode 100644 index a801fd7e..00000000 --- a/src/backend/core/JIT/IR/Value.hpp +++ /dev/null @@ -1,145 +0,0 @@ -#pragma once -#include - -namespace n64 { -enum IRPrimitive { - Uint32, Sint32, Uint64, Sint64 -}; - -struct IRVariable { - IRVariable(IRPrimitive type, const u32 id, char const* const label) : type(type), id(id), label(label), assigned(false) {} - IRPrimitive type; - u32 id; - char const* label; - bool assigned; - - bool HasValue() const { return assigned; } - bool IsNull() const { return !assigned; } -}; - -struct IRConstant { - IRConstant() {} - IRConstant(IRPrimitive type, u64 value) : type(type), value(value) {} - - u64 value = 0; -private: - IRPrimitive type = Uint64; -}; - -struct IRAnyRef { - IRAnyRef() {} - IRAnyRef(IRVariable const& variable) : type(Type::Variable), var(&variable) {} - IRAnyRef(IRConstant const& constant) : type(Type::Constant), constant(constant) {} - - auto operator=(IRAnyRef const& other) -> IRAnyRef& { - type = other.type; - if (IsConstant()) { - constant = other.constant; - } else { - var = other.var; - } - return *this; - } - - bool IsNull() const { return type == Type::Null; } - bool IsVariable() const { return type == Type::Variable; } - bool IsConstant() const { return type == Type::Constant; } - - auto GetVar() const -> IRVariable const& { - if (!IsVariable()) { - Util::panic("called GetVar() but value is a constant or null"); - } - return *var; - } - - auto GetConst() const -> IRConstant const& { - if (!IsConstant()) { - Util::panic("called GetConst() but value is a variable or null"); - } - return constant; - } - - void Repoint(IRVariable const& var_old, IRVariable const& var_new) { - if (IsVariable() && (&GetVar() == &var_old)) { - var = &var_new; - } - } - - void PropagateConstant(IRVariable const& var, IRConstant const& constant) { - if (IsVariable() && (&GetVar() == &var)) { - type = Type::Constant; - this->constant = constant; - } - } -private: - enum Type { - Null, Variable, Constant - }; - - Type type; - - union { - IRVariable const* var; - IRConstant constant; - }; -}; - -struct IRVarRef { - IRVarRef(IRVariable const& var) : p_var(&var) {} - - auto Get() const -> IRVariable const& { - return *p_var; - } - - void Repoint(IRVariable const& var_old, IRVariable const& var_new) { - if (&var_old == p_var) { - p_var = &var_new; - } - } -private: - IRVariable const* p_var; -}; -} - - -namespace std { -inline auto to_string(n64::IRPrimitive data_type) -> std::string { - switch (data_type) { - case n64::IRPrimitive::Uint32: - return "u32"; - case n64::IRPrimitive::Sint32: - return "s32"; - case n64::IRPrimitive::Uint64: - return "u64"; - case n64::IRPrimitive::Sint64: - return "s64"; - default: - return "???"; - } -} - -inline auto to_string(n64::IRVariable const &variable) -> std::string { - if (variable.label) { - return fmt::format("var{}_{}", variable.id, variable.label); - } - return fmt::format("var{}", variable.id); -} - -inline auto to_string(n64::IRConstant const &constant) -> std::string { - return fmt::format("0x{:0X}", constant.value); -} - -inline auto to_string(n64::IRAnyRef const &value) -> std::string { - if (value.IsNull()) { - return "(null)"; - } - if (value.IsConstant()) { - return std::to_string(value.GetConst()); - } - return std::to_string(value.GetVar()); -} - -inline auto to_string(n64::IRVarRef const &variable) -> std::string { - return std::to_string(variable.Get()); -} -} \ No newline at end of file diff --git a/src/backend/core/JIT/instructions.cpp b/src/backend/core/JIT/instructions.cpp deleted file mode 100644 index dacfadac..00000000 --- a/src/backend/core/JIT/instructions.cpp +++ /dev/null @@ -1,925 +0,0 @@ -#include - -#define check_address_error(mask, vaddr) (((!regs.cop0.is_64bit_addressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0)) -#define check_signed_overflow(op1, op2, res) (((~((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1) -#define check_signed_underflow(op1, op2, res) (((((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1) - -namespace n64 { -void JIT::add(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RD(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::REG_U32, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_U32, u8(RT(instr)) }; - Entry e(Entry::ADD, dst, op1, op2); - ir.push(e); -} - -void JIT::addu(u32 instr) { - add(instr); -} - -void JIT::addi(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::REG_U32, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::IMM_S16, s16(instr) }; - Entry e(Entry::ADD, dst, op1, op2); - ir.push(e); -} - -void JIT::addiu(u32 instr) { - addi(instr); -} - -void JIT::dadd(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RD(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::REG_U64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_U64, u8(RT(instr)) }; - Entry e(Entry::ADD, dst, op1, op2); - ir.push(e); -} - -Entry::Operand JIT::branch(u32 instr) { - auto addr = Entry::Operand{ Entry::Operand::IMM_S64, u64(s64(s16(instr))) << 2 }; - return addr; -} - -void JIT::bltz(u32 instr) { - auto dst = branch(instr); - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; - Entry e(Entry::BRANCH, dst, op1, Entry::BranchCond::LT, op2); - ir.push(e); -} - -void JIT::bgez(u32 instr) { - auto dst = branch(instr); - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; - Entry e(Entry::BRANCH, dst, op1, Entry::BranchCond::GE, op2); - ir.push(e); -} - -void JIT::bltzl(u32 instr) { - auto dst = branch(instr); - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; - auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LIKELY); - Entry e(opc, dst, op1, Entry::BranchCond::LT, op2); - ir.push(e); -} - -void JIT::bgezl(u32 instr) { - auto dst = branch(instr); - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; - auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LIKELY); - Entry e(opc, dst, op1, Entry::BranchCond::GE, op2); - ir.push(e); -} - -void JIT::bltzal(u32 instr) { - auto dst = branch(instr); - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; - auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LINK); - Entry e(opc, dst, op1, Entry::BranchCond::LT, op2); - ir.push(e); -} - -void JIT::bgezal(u32 instr) { - auto dst = branch(instr); - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; - auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LINK); - Entry e(opc, dst, op1, Entry::BranchCond::GE, op2); - ir.push(e); -} - -void JIT::bltzall(u32 instr) { - auto dst = branch(instr); - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; - auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LINK | Entry::LIKELY); - Entry e(opc, dst, op1, Entry::BranchCond::LT, op2); - ir.push(e); -} - -void JIT::bgezall(u32 instr) { - auto dst = branch(instr); - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; - auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LINK | Entry::LIKELY); - Entry e(opc, dst, op1, Entry::BranchCond::GE, op2); - ir.push(e); -} - -void JIT::beq(u32 instr) { - auto dst = branch(instr); - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - Entry e(Entry::BRANCH, dst, op1, Entry::BranchCond::EQ, op2); - ir.push(e); -} - -void JIT::bne(u32 instr) { - auto dst = branch(instr); - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - Entry e(Entry::BRANCH, dst, op1, Entry::BranchCond::NE, op2); - ir.push(e); -} - -void JIT::blez(u32 instr) { - auto dst = branch(instr); - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::IMM_S64, 0 }; - Entry e(Entry::BRANCH, dst, op1, Entry::BranchCond::LE, op2); - ir.push(e); -} - -void JIT::bgtz(u32 instr) { - auto dst = branch(instr); - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::IMM_S64, 0 }; - Entry e(Entry::BRANCH, dst, op1, Entry::BranchCond::GT, op2); - ir.push(e); -} - -void JIT::beql(u32 instr) { - auto dst = branch(instr); - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LIKELY); - Entry e(opc, dst, op1, Entry::BranchCond::EQ, op2); - ir.push(e); -} - -void JIT::bnel(u32 instr) { - auto dst = branch(instr); - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LIKELY); - Entry e(opc, dst, op1, Entry::BranchCond::NE, op2); - ir.push(e); -} - -void JIT::blezl(u32 instr) { - auto dst = branch(instr); - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::IMM_S64, 0 }; - auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LIKELY); - Entry e(opc, dst, op1, Entry::BranchCond::LE, op2); - ir.push(e); -} - -void JIT::bgtzl(u32 instr) { - auto dst = branch(instr); - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::IMM_S64, 0 }; - auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LIKELY); - Entry e(opc, dst, op1, Entry::BranchCond::GT, op2); - ir.push(e); -} - -void JIT::daddu(u32 instr) { - dadd(instr); -} - -void JIT::daddi(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::IMM_S16, s16(instr) }; - Entry e(Entry::ADD, dst, op1, op2); - ir.push(e); -} - -void JIT::daddiu(u32 instr) { - daddi(instr); -} - -void JIT::div(u32 instr) { - auto op1 = Entry::Operand{ Entry::Operand::REG_S32, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S32, u8(RT(instr)) }; - Entry e(Entry::DIV, op1, op2); - ir.push(e); -} - -void JIT::divu(u32 instr) { - auto op1 = Entry::Operand{ Entry::Operand::REG_U32, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_U32, u8(RT(instr)) }; - Entry e(Entry::DIV, op1, op2); - ir.push(e); -} - -void JIT::ddiv(u32 instr) { - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - Entry e(Entry::DIV, op1, op2); - ir.push(e); -} - -void JIT::ddivu(u32 instr) { - auto op1 = Entry::Operand{ Entry::Operand::REG_U64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_U64, u8(RT(instr)) }; - Entry e(Entry::DIV, op1, op2); - ir.push(e); -} - -void JIT::lui(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::IMM_S16, u64(s16(instr)) << 16 }; - Entry e(Entry::LOADS64, dst, op1); - ir.push(e); -} - -void JIT::lb(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U8, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr))}; - Entry e(Entry::LOADS8, dst, op1, op2); - ir.push(e); -} - -void JIT::lh(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U16, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::LOADS16, dst, op1, op2); - ir.push(e); -} - -void JIT::lw(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::LOADS32, dst, op1, op2); - ir.push(e); -} - -void JIT::ll(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto opc = Entry::Opcode(u16(Entry::LOADS64) | Entry::SET_LLBIT); - Entry e(opc, dst, op1, op2); - ir.push(e); -} - -void JIT::lwl(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::LOADS32_SHIFT, dst, op1, op2, Entry::LEFT); - ir.push(e); -} - -void JIT::lwr(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::LOADS32_SHIFT, dst, op1, op2, Entry::RIGHT); - ir.push(e); -} - -void JIT::ld(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U64, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::LOADS64, dst, op1, op2); - ir.push(e); -} - -void JIT::lld(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto opc = Entry::Opcode(u16(Entry::Opcode::LOADS64) | Entry::SET_LLBIT); - Entry e(opc, dst, op1, op2); - ir.push(e); -} - -void JIT::ldl(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::LOADS64_SHIFT, dst, op1, op2, Entry::LEFT); - ir.push(e); -} - -void JIT::ldr(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::LOADS64_SHIFT, dst, op1, op2, Entry::RIGHT); - ir.push(e); -} - -void JIT::lbu(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U8, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::LOADU8, dst, op1, op2); - ir.push(e); -} - -void JIT::lhu(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U16, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::LOADU16, dst, op1, op2); - ir.push(e); -} - -void JIT::lwu(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::LOADU16, dst, op1, op2); - ir.push(e); -} - -void JIT::sb(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U8, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::STORE8, dst, op1, op2); - ir.push(e); -} - -void JIT::sc(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto opc = Entry::Opcode(u16(Entry::STORE32) | Entry::SET_LLBIT); - Entry e(opc, dst, op1, op2); - ir.push(e); -} - -void JIT::scd(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto opc = Entry::Opcode(u16(Entry::STORE64) | Entry::SET_LLBIT); - Entry e(opc, dst, op1, op2); - ir.push(e); -} - -void JIT::sh(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U16, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::STORE16, dst, op1, op2); - ir.push(e); -} - -void JIT::sw(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::STORE32, dst, op1, op2); - ir.push(e); -} - -void JIT::sd(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U64, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::STORE64, dst, op1, op2); - ir.push(e); -} - -void JIT::sdl(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U64, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::STORE64, dst, op1, op2, Entry::LEFT); - ir.push(e); -} - -void JIT::sdr(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U64, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::STORE64, dst, op1, op2, Entry::RIGHT); - ir.push(e); -} - -void JIT::swl(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::STORE32, dst, op1, op2, Entry::LEFT); - ir.push(e); -} - -void JIT::swr(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::STORE32, dst, op1, op2, Entry::RIGHT); - ir.push(e); -} - -void JIT::ori(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::IMM_U16, u16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::OR, dst, op1, op2); - ir.push(e); -} - -void JIT::or_(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RD(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::OR, dst, op1, op2); - ir.push(e); -} - -void JIT::nor(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RD(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::NOR, dst, op1, op2); - ir.push(e); -} - -void JIT::j(u32 instr) { - auto dst = Entry::Operand{Entry::Operand::IMM_S64}; - auto op1 = Entry::Operand{Entry::Operand::PC64}; - auto op2 = Entry::Operand{Entry::Operand::IMM_S64, ~0xfffffff}; - Entry and_(Entry::AND, dst, op1, op2); - ir.push(and_); - op2 = Entry::Operand{Entry::Operand::IMM_S64, (instr & 0x3ffffff) << 2}; - Entry or_(Entry::OR, dst, dst, op2); - ir.push(or_); - Entry e(Entry::BRANCH, or_.GetDst()); - ir.push(e); -} - -void JIT::jal(u32 instr) { - Entry link(Entry::MOV, - Entry::Operand{Entry::Operand::REG_S64, 31}, - Entry::Operand{Entry::Operand::NEXTPC64}); - ir.push(link); - j(instr); -} - -void JIT::jalr(u32 instr) { - auto addr = Entry::Operand{Entry::Operand::REG_U64, RS(instr)}; - Entry e(Entry::BRANCH, addr); - Entry link(Entry::MOV, - Entry::Operand{Entry::Operand::REG_S64, RD(instr)}, - Entry::Operand{Entry::Operand::PC64}); - ir.push(link); - j(instr); -} - -void JIT::slti(u32 instr) { - Entry e(Entry::SLT, - { Entry::Operand::REG_U5, RT(instr) }, - { Entry::Operand::REG_S64, RS(instr) }, - { Entry::Operand::IMM_S64, s64(s16(instr)) }); - ir.push(e); -} - -void JIT::sltiu(u32 instr) { - Entry e(Entry::SLT, - { Entry::Operand::REG_U5, RT(instr) }, - { Entry::Operand::REG_U64, RS(instr) }, - { Entry::Operand::IMM_U64, u64(s64(s16(instr))) }); - ir.push(e); -} - -void JIT::slt(u32 instr) { - Entry e(Entry::SLT, - { Entry::Operand::REG_U5, RD(instr) }, - { Entry::Operand::REG_S64, RS(instr) }, - { Entry::Operand::REG_S64, RT(instr) }); - ir.push(e); -} - -void JIT::sltu(u32 instr) { - Entry e(Entry::SLT, - { Entry::Operand::REG_U5, RD(instr) }, - { Entry::Operand::REG_U64, RS(instr) }, - { Entry::Operand::REG_U64, RT(instr) }); - ir.push(e); -} - -void JIT::xori(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::IMM_U16, u16(instr)}; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::XOR, dst, op1, op2); - ir.push(e); -} - -void JIT::xor_(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RD(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::XOR, dst, op1, op2); - ir.push(e); -} - -void JIT::andi(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::IMM_U16, u16(instr) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::AND, dst, op1, op2); - ir.push(e); -} - -void JIT::and_(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RD(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - Entry e(Entry::AND, dst, op1, op2); - ir.push(e); -} - -void JIT::sll(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RD(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::IMM_U5, std::nullopt }; - Entry e(Entry::SLL, dst, op1, op2); - ir.push(e); -} - -void JIT::sllv(u32 instr) { - if (RD(instr) != 0) [[likely]] { - mov(rcx, GPR(qword, RS(instr))); - CodeGenerator::and_(cl, 0x1F); - mov(rax, GPR(qword, RT(instr))); - sal(rax, cl); - movsxd(rcx, eax); - mov(GPR(qword, RD(instr)), rcx); - } -} - -void JIT::dsll32(u32 instr) { - if (RD(instr) != 0) [[likely]] { - u8 sa = ((instr >> 6) & 0x1f) + 32; - mov(rax, GPR(qword, RT(instr))); - sal(rax, sa); - mov(GPR(qword, RT(instr)), rax); - } -} - -void JIT::dsll(u32 instr) { - if (RD(instr) != 0) [[likely]] { - u8 sa = ((instr >> 6) & 0x1f); - mov(rax, GPR(qword, RT(instr))); - sal(rax, sa); - mov(GPR(qword, RT(instr)), rax); - } -} - -void JIT::dsllv(u32 instr) { - if (RD(instr) != 0) [[likely]] { - mov(rcx, GPR(qword, RS(instr))); - CodeGenerator::and_(cl, 63); - mov(rax, GPR(qword, RT(instr))); - sal(rax, cl); - mov(GPR(qword, RD(instr)), rax); - } -} - -void JIT::srl(u32 instr) { - if (RD(instr) != 0) [[likely]] { - u8 sa = ((instr >> 6) & 0x1f); - mov(rax, GPR(qword, RT(instr))); - CodeGenerator::shr(rax, sa); - movsxd(rcx, eax); - mov(GPR(qword, RD(instr)), rcx); - } -} - -void JIT::srlv(u32 instr) { - if (RD(instr) != 0) [[likely]] { - mov(rcx, GPR(qword, RS(instr))); - CodeGenerator::and_(cl, 0x1F); - mov(rax, GPR(qword, RT(instr))); - shr(rax, cl); - movsxd(rcx, eax); - mov(GPR(qword, RD(instr)), rcx); - } -} - -void JIT::tgei(u32) { - -} - -void JIT::tgeiu(u32) { - -} - -void JIT::tlti(u32) { - -} - -void JIT::tltiu(u32) { - -} - -void JIT::teqi(u32) { - -} - -void JIT::tnei(u32) { - -} - -void JIT::tge(u32) { - -} - -void JIT::tgeu(u32) { - -} - -void JIT::tlt(u32) { - -} - -void JIT::tltu(u32) { - -} - -void JIT::teq(u32) { - -} - -void JIT::tne(u32) { - -} - -void JIT::dsrl(u32 instr) { - if (RD(instr) != 0) [[likely]] { - u8 sa = ((instr >> 6) & 0x1f); - mov(rax, GPR(qword, RT(instr))); - CodeGenerator::shr(rax, sa); - mov(GPR(qword, RD(instr)), rax); - } -} - -void JIT::dsrlv(u32 instr) { - if (RD(instr) != 0) [[likely]] { - mov(rcx, GPR(qword, RS(instr))); - CodeGenerator::and_(cl, 63); - mov(rax, GPR(qword, RT(instr))); - shr(rax, cl); - mov(GPR(qword, RD(instr)), rax); - } -} - -void JIT::dsrl32(u32 instr) { - if (RD(instr) != 0) [[likely]] { - u8 sa = ((instr >> 6) & 0x1f) + 32; - mov(rax, GPR(qword, RT(instr))); - CodeGenerator::shr(rax, sa); - mov(GPR(qword, RD(instr)), rax); - } -} - -void JIT::sra(u32 instr) { - if (RD(instr) != 0) [[likely]] { - u8 sa = ((instr >> 6) & 0x1f); - mov(rax, GPR(qword, RT(instr))); - sar(rax, sa); - movsxd(rcx, eax); - mov(GPR(qword, RD(instr)), rcx); - } -} - -void JIT::srav(u32 instr) { - if (RD(instr) != 0) [[likely]] { - mov(rcx, GPR(qword, RS(instr))); - CodeGenerator::and_(cl, 0x1F); - mov(rax, GPR(qword, RT(instr))); - sar(rax, cl); - movsxd(rcx, eax); - mov(GPR(qword, RD(instr)), rcx); - } -} - -void JIT::dsra(u32 instr) { - if (RD(instr) != 0) [[likely]] { - u8 sa = ((instr >> 6) & 0x1f); - mov(rax, GPR(qword, RT(instr))); - sar(rax, sa); - mov(GPR(qword, RD(instr)), rax); - } -} - -void JIT::dsrav(u32 instr) { - if (RD(instr) != 0) [[likely]] { - mov(rcx, GPR(qword, RS(instr))); - CodeGenerator::and_(cl, 63); - mov(rax, GPR(qword, RT(instr))); - sar(rax, cl); - mov(GPR(qword, RD(instr)), rax); - } -} - -void JIT::dsra32(u32 instr) { - if (RD(instr) != 0) [[likely]] { - u8 sa = ((instr >> 6) & 0x1f) + 32; - mov(rax, GPR(qword, RT(instr))); - sar(rax, sa); - mov(GPR(qword, RD(instr)), rax); - } -} - -void JIT::jr(u32 instr) { - auto addr = Entry::Operand{Entry::Operand::REG_U64, RS(instr)}; - Entry e(Entry::BRANCH, addr); - ir.push(e); -} - -void JIT::dsub(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RD(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - Entry e(Entry::SUB, dst, op1, op2); - ir.push(e); -} - -void JIT::dsubu(u32 instr) { - dsub(instr); -} - -void JIT::sub(u32 instr) { - auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RD(instr)) }; - auto op1 = Entry::Operand{ Entry::Operand::REG_S32, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S32, u8(RT(instr)) }; - Entry e(Entry::SUB, dst, op1, op2); - ir.push(e); -} - -void JIT::subu(u32 instr) { - sub(instr); -} - -void JIT::dmultu(u32 instr) { - auto op1 = Entry::Operand{ Entry::Operand::REG_U64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_U64, u8(RT(instr)) }; - Entry e(Entry::UMUL, op1, op2); - ir.push(e); -} - -void JIT::dmult(u32 instr) { - auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; - Entry e(Entry::SMUL, op1, op2); - ir.push(e); -} - -void JIT::multu(u32 instr) { - auto op1 = Entry::Operand{ Entry::Operand::REG_S32, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S32, u8(RT(instr)) }; - Entry e(Entry::UMUL, op1, op2); - ir.push(e); -} - -void JIT::mult(u32 instr) { - auto op1 = Entry::Operand{ Entry::Operand::REG_S32, u8(RS(instr)) }; - auto op2 = Entry::Operand{ Entry::Operand::REG_S32, u8(RT(instr)) }; - Entry e(Entry::SMUL, op1, op2); - ir.push(e); -} - -void JIT::mflo(u32 instr) { - auto dst = Entry::Operand{Entry::Operand::REG_S64, RD(instr)}; - auto src = Entry::Operand{Entry::Operand::LO}; - ir.push({Entry::MOV, dst, src}); -} - -void JIT::mfhi(u32 instr) { - auto dst = Entry::Operand{Entry::Operand::REG_S64, RD(instr)}; - auto src = Entry::Operand{Entry::Operand::HI}; - ir.push({Entry::MOV, dst, src}); -} - -void JIT::mtlo(u32 instr) { - auto dst = Entry::Operand{Entry::Operand::LO}; - auto src = Entry::Operand{Entry::Operand::REG_S64, RS(instr)}; - ir.push({Entry::MOV, dst, src}); -} - -void JIT::mthi(u32 instr) { - auto dst = Entry::Operand{Entry::Operand::HI}; - auto src = Entry::Operand{Entry::Operand::REG_S64, RS(instr)}; - ir.push({Entry::MOV, dst, src}); -} - -void JIT::mtc0(u32 instr) { - ir.push({Entry::MTC0, - {Entry::Operand::IMM_U5, RD(instr)}, - {Entry::Operand::REG_S32, RT(instr)}}); -} - -void JIT::dmtc0(u32 instr) { - ir.push({Entry::MTC0, - {Entry::Operand::IMM_U5, RD(instr)}, - {Entry::Operand::REG_S64, RT(instr)}}); -} - -void JIT::mfc0(u32 instr) { - ir.push({Entry::MFC0, - {Entry::Operand::REG_S32, RT(instr)}, - {Entry::Operand::IMM_U5, RD(instr)}}); -} - -void JIT::dmfc0(u32 instr) { - ir.push({Entry::MFC0, - {Entry::Operand::REG_S64, RT(instr)}, - {Entry::Operand::IMM_U5, RD(instr)}}); -} - -void JIT::eret() { - /*if(status.erl) { - regs.SetPC64(ErrorEPC); - status.erl = false; - } else { - regs.SetPC64(EPC); - status.exl = false; - } - regs.cop0.Update(); - llbit = false;*/ -} - - -void JIT::tlbr() { - /*if (index.i >= 32) { - Util::panic("TLBR with TLB index {}", index.i); - } - - TLBEntry entry = tlb[index.i]; - - entryHi.raw = entry.entryHi.raw; - entryLo0.raw = entry.entryLo0.raw & 0x3FFFFFFF; - entryLo1.raw = entry.entryLo1.raw & 0x3FFFFFFF; - - entryLo0.g = entry.global; - entryLo1.g = entry.global; - pageMask.raw = entry.pageMask.raw;*/ -} - -void JIT::tlbw(int index_) { - /*PageMask page_mask{}; - page_mask = pageMask; - u32 top = page_mask.mask & 0xAAA; - page_mask.mask = top | (top >> 1); - - if(index_ >= 32) { - Util::panic("TLBWI with TLB index {}", index_); - } - - tlb[index_].entryHi.raw = entryHi.raw; - tlb[index_].entryHi.vpn2 &= ~page_mask.mask; - - tlb[index_].entryLo0.raw = entryLo0.raw & 0x03FFFFFE; - tlb[index_].entryLo1.raw = entryLo1.raw & 0x03FFFFFE; - tlb[index_].pageMask.raw = page_mask.raw; - - tlb[index_].global = entryLo0.g && entryLo1.g; - tlb[index_].initialized = true;*/ -} - -void JIT::tlbp() { - /*int match = -1; - TLBEntry* entry = TLBTryMatch(regs, entryHi.raw, &match); - if(entry && match >= 0) { - index.raw = match; - } else { - index.raw = 0; - index.p = 1; - }*/ -} - -void JIT::mtc2(u32 instr) { - -} - -void JIT::mfc2(u32 instr) { - -} - -void JIT::dmtc2(u32 instr) { - -} - -void JIT::dmfc2(u32 instr) { - -} - -void JIT::ctc2(u32) { - -} - -void JIT::cfc2(u32) { - -} - -} \ No newline at end of file diff --git a/src/backend/core/mem/Flash.cpp b/src/backend/core/mem/Flash.cpp index d6ff50f7..e0df02f2 100644 --- a/src/backend/core/mem/Flash.cpp +++ b/src/backend/core/mem/Flash.cpp @@ -49,7 +49,7 @@ void Flash::CommandExecute() { case FlashState::Erase: if(saveData.is_mapped()) { for (int i = 0; i < 128; i++) { - saveData[eraseOffs + i] = 0xFFi8; + saveData[eraseOffs + i] = 0xFF; } } else { Util::panic("Accessing flash when not mapped!"); diff --git a/src/backend/core/registers/Cop0.cpp b/src/backend/core/registers/Cop0.cpp index b504522f..bf041c05 100644 --- a/src/backend/core/registers/Cop0.cpp +++ b/src/backend/core/registers/Cop0.cpp @@ -1,7 +1,6 @@ #include #include #include -#include namespace n64 { Cop0::Cop0() { @@ -337,25 +336,7 @@ template void Cop0::decode(Interpreter&, u32); template void Cop0::decode(JIT&, u32); void Cop0::decodeJIT(JIT& cpu, u32 instr) { - u8 mask_cop = (instr >> 21) & 0x1F; - u8 mask_cop2 = instr & 0x3F; - switch(mask_cop) { - case 0x00: cpu.mfc0(instr); break; - case 0x01: cpu.dmfc0(instr); break; - case 0x04: cpu.mtc0(instr); break; - case 0x05: cpu.dmtc0(instr); break; - case 0x10 ... 0x1F: - switch(mask_cop2) { - case 0x01: cpu.tlbr(); break; - case 0x02: cpu.tlbw(index.i); break; - case 0x06: cpu.tlbw(GetRandom()); break; - case 0x08: cpu.tlbp(); break; - case 0x18: cpu.eret(); break; - default: Util::panic("Unimplemented COP0 function {} {} ({:08X}) ({:016lX})", mask_cop2 >> 3, mask_cop2 & 7, instr, cpu.regs.oldPC); - } - break; - default: Util::panic("Unimplemented COP0 instruction {} {}", mask_cop >> 4, mask_cop & 7); - } + } void Cop0::decodeInterp(Registers& regs, u32 instr) {