diff --git a/src/backend/Core.cpp b/src/backend/Core.cpp index 1882f977..8bae5209 100644 --- a/src/backend/Core.cpp +++ b/src/backend/Core.cpp @@ -67,7 +67,7 @@ void Core::Run(float volumeL, float volumeR) { InterruptRaise(mmio.mi, regs, Interrupt::VI); } - for(; cycles < mem.mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) { + for(; cycles < mem.mmio.vi.cyclesPerHalfline;) { u32 taken = cpu->Step(); taken += PopStalledCycles(); static u32 cpuSteps = 0; diff --git a/src/backend/core/JIT.cpp b/src/backend/core/JIT.cpp index ff2ac465..767755b1 100644 --- a/src/backend/core/JIT.cpp +++ b/src/backend/core/JIT.cpp @@ -33,51 +33,56 @@ void JIT::CheckCompareInterrupt() { Fn JIT::Recompile() { bool stable = true; cycles = 0; - prologue(); - mov(rbp, u64(this)); - mov(rdi, u64(this) + THIS_OFFSET(regs)); + //prologue(); + //mov(rbp, u64(this)); + //mov(rdi, u64(this) + THIS_OFFSET(regs)); + u64 pc = regs.pc; while(stable) { cycles++; CheckCompareInterrupt(); - mov(rax, REG(byte, delaySlot)); - mov(REG(byte, prevDelaySlot), rax); - mov(REG(byte, delaySlot), 0); + // mov(rax, REG(byte, delaySlot)); + // mov(REG(byte, prevDelaySlot), rax); + // mov(REG(byte, delaySlot), 0); u32 paddr = 0; - if (!MapVAddr(regs, LOAD, regs.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; + 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(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); + //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(); + //epilogue(); + //ready(); + //return getCode(); + ir.optimize(); + exit(1); + return nullptr; } int JIT::Step() { @@ -90,6 +95,7 @@ int JIT::Step() { 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 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 index d2430bac..c780b92e 100644 --- a/src/backend/core/JIT.hpp +++ b/src/backend/core/JIT.hpp @@ -137,6 +137,7 @@ private: void addiu(u32); void andi(u32); void and_(u32); + Entry branch(u32); void bltz(u32); void bgez(u32); void bltzl(u32); diff --git a/src/backend/core/JIT/IR.cpp b/src/backend/core/JIT/IR.cpp index bd36dccc..3cf75e60 100644 --- a/src/backend/core/JIT/IR.cpp +++ b/src/backend/core/JIT/IR.cpp @@ -1,14 +1,207 @@ #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; + } + + bool put_comma = false; + op += " "; + if (e.dst.isReg()) { + if (e.dst.index_or_imm.has_value()) { + if (e.dst.index_or_imm.value() == 0) { + op = "NOP"; + return formatter::format(op, ctx); + } else { + std::string dst = fmt::format("R{}", e.dst.index_or_imm.value()); + 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.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.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; + } + } + + 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; + put_comma = true; + } + } 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; + put_comma = true; + } + } + + 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 op1, std::optional bc, Operand op2) - : op(op), op1(op1), branchCond(bc), op2(op2) {} +Entry::Entry(Opcode op, Operand bDest, Operand op1, std::optional bc, Operand op2) + : op(op), bDest(bDest), op1(op1), branchCond(bc), op2(op2) {} + +Entry::Entry(Opcode op, Operand bDest) +: op(op), bDest(bDest) {} Entry::Entry(Opcode op, Operand dst, Operand op1, Operand op2, Shift s) : op(op), dst(dst), op1(op1), op2(op2), shift(s) {} @@ -17,6 +210,12 @@ void IR::push(const Entry& e) { code.push_back(e); } +void IR::optimize() { + for(auto e : code) { + fmt::print("{}", e); + } +} + auto IR::begin() { return code.begin(); } diff --git a/src/backend/core/JIT/IR.hpp b/src/backend/core/JIT/IR.hpp index e47d96c2..b75f7eb8 100644 --- a/src/backend/core/JIT/IR.hpp +++ b/src/backend/core/JIT/IR.hpp @@ -34,25 +34,36 @@ struct Entry { 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 - } type; + MEM_U8, MEM_U16, MEM_U32, MEM_U64, PC64, NEXTPC64, + LO, HI + } type = NONE; + + bool isReg() { + return type == REG_S64 || type == REG_F32 || type == REG_F64 || type == REG_S32 + || type == REG_U64 || type == REG_U32 || type == REG_U5; + } std::optional index_or_imm = std::nullopt; + Operand() = default; Operand(Type t, std::optional imm = std::nullopt) : type(t), index_or_imm(imm) {} - } dst = Operand::NONE, op1 = Operand::NONE, op2 = Operand::NONE; + } dst, op1, op2; + + [[nodiscard]] const Operand& GetDst() const { return dst; } enum BranchCond { - EQ, NE, LT, GT, LE, GE + AL, EQ, NE, LT, GT, LE, GE }; std::optional branchCond = std::nullopt; std::optional shift = std::nullopt; + Operand bDest = Operand::NONE; Entry(Opcode op, Operand dst, Operand op1, Operand op2); Entry(Opcode op, Operand op1, Operand op2); - Entry(Opcode op, Operand op1, std::optional bc, Operand op2); + Entry(Opcode op, Operand bDest, Operand op1, std::optional bc, Operand op2); + Entry(Opcode op, Operand bDest); Entry(Opcode op, Operand dst, Operand op1, Operand op2, Shift s); }; @@ -60,6 +71,7 @@ struct IR { void push(const Entry&); auto begin(); auto end(); + void optimize(); private: std::vector code{}; }; diff --git a/src/backend/core/JIT/instructions.cpp b/src/backend/core/JIT/instructions.cpp index 8c58e1d6..5bc4e20d 100644 --- a/src/backend/core/JIT/instructions.cpp +++ b/src/backend/core/JIT/instructions.cpp @@ -37,125 +37,149 @@ void JIT::dadd(u32 instr) { ir.push(e); } +Entry JIT::branch(u32 instr) { + auto dst = Entry::Operand{ Entry::Operand::IMM_S64, u64(s64(s16(instr))) << 2 }; + auto pc = Entry::Operand{Entry::Operand::PC64}; + Entry add_(Entry::ADD, dst, dst, pc); + ir.push(add_); + return add_; +} + 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, op1, Entry::BranchCond::LT, op2); + Entry e(Entry::BRANCH, dst.GetDst(), 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, op1, Entry::BranchCond::GE, op2); + Entry e(Entry::BRANCH, dst.GetDst(), 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, op1, Entry::BranchCond::LT, op2); + Entry e(opc, dst.GetDst(), 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, op1, Entry::BranchCond::GE, op2); + Entry e(opc, dst.GetDst(), 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, op1, Entry::BranchCond::LT, op2); + Entry e(opc, dst.GetDst(), 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, op1, Entry::BranchCond::GE, op2); + Entry e(opc, dst.GetDst(), 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, op1, Entry::BranchCond::LT, op2); + Entry e(opc, dst.GetDst(), 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, op1, Entry::BranchCond::GE, op2); + Entry e(opc, dst.GetDst(), 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, op1, Entry::BranchCond::EQ, op2); + Entry e(Entry::BRANCH, dst.GetDst(), 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, op1, Entry::BranchCond::NE, op2); + Entry e(Entry::BRANCH, dst.GetDst(), 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, op1, Entry::BranchCond::LE, op2); + Entry e(Entry::BRANCH, dst.GetDst(), 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, op1, Entry::BranchCond::GT, op2); + Entry e(Entry::BRANCH, dst.GetDst(), 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, op1, Entry::BranchCond::EQ, op2); + Entry e(opc, dst.GetDst(), 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, op1, Entry::BranchCond::NE, op2); + Entry e(opc, dst.GetDst(), 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, op1, Entry::BranchCond::LE, op2); + Entry e(opc, dst.GetDst(), 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, op1, Entry::BranchCond::GT, op2); + Entry e(opc, dst.GetDst(), op1, Entry::BranchCond::GT, op2); ir.push(e); } @@ -423,29 +447,32 @@ void JIT::nor(u32 instr) { } void JIT::j(u32 instr) { - s32 target = (instr & 0x3ffffff) << 2; - s64 address = (regs.oldPC & ~0xfffffff) | target; - - mov(byte[rdi + offsetof(Registers, delaySlot)], 1); - mov(qword[rdi + offsetof(Registers, nextPC)], address); + 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()); } void JIT::jal(u32 instr) { - mov(rax, qword[rdi + offsetof(Registers, nextPC)]); - mov(GPR(qword, 31), rax); + 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) { - mov(byte[rdi + offsetof(Registers, delaySlot)], 1); - mov(rax, GPR(qword, RS(instr))); - mov(qword[rdi + offsetof(Registers, nextPC)], rax); - - if (RD(instr) != 0) [[likely]] { - mov(rax, qword[rdi + offsetof(Registers, pc)]); - CodeGenerator::add(rax, 4); - mov(GPR(qword, RD(instr)), rax); - } + 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); } void JIT::slti(u32 instr) { @@ -706,9 +733,8 @@ void JIT::dsra32(u32 instr) { } void JIT::jr(u32 instr) { - mov(rax, GPR(qword, RS(instr))); - mov(REG(byte, delaySlot), 1); - mov(REG(qword, nextPC), rax); + auto addr = Entry::Operand{Entry::Operand::REG_U64, RS(instr)}; + Entry e(Entry::BRANCH, addr); } void JIT::dsub(u32 instr) { @@ -764,23 +790,27 @@ void JIT::mult(u32 instr) { } void JIT::mflo(u32 instr) { - if (RD(instr) != 0) [[likely]] { - regs.gpr[RD(instr)] = regs.lo; - } + 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) { - if (RD(instr) != 0) [[likely]] { - regs.gpr[RD(instr)] = regs.hi; - } + 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) { - regs.lo = regs.gpr[RS(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) { - regs.hi = regs.gpr[RS(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::mtc2(u32 instr) {