more instructions and formatter

This commit is contained in:
SimoneN64
2023-12-25 03:43:17 +01:00
parent 2a3e4d56f6
commit 1f84b96909
6 changed files with 328 additions and 80 deletions

View File

@@ -67,7 +67,7 @@ void Core::Run(float volumeL, float volumeR) {
InterruptRaise(mmio.mi, regs, Interrupt::VI); InterruptRaise(mmio.mi, regs, Interrupt::VI);
} }
for(; cycles < mem.mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) { for(; cycles < mem.mmio.vi.cyclesPerHalfline;) {
u32 taken = cpu->Step(); u32 taken = cpu->Step();
taken += PopStalledCycles(); taken += PopStalledCycles();
static u32 cpuSteps = 0; static u32 cpuSteps = 0;

View File

@@ -33,51 +33,56 @@ void JIT::CheckCompareInterrupt() {
Fn JIT::Recompile() { Fn JIT::Recompile() {
bool stable = true; bool stable = true;
cycles = 0; cycles = 0;
prologue(); //prologue();
mov(rbp, u64(this)); //mov(rbp, u64(this));
mov(rdi, u64(this) + THIS_OFFSET(regs)); //mov(rdi, u64(this) + THIS_OFFSET(regs));
u64 pc = regs.pc;
while(stable) { while(stable) {
cycles++; cycles++;
CheckCompareInterrupt(); CheckCompareInterrupt();
mov(rax, REG(byte, delaySlot)); // mov(rax, REG(byte, delaySlot));
mov(REG(byte, prevDelaySlot), rax); // mov(REG(byte, prevDelaySlot), rax);
mov(REG(byte, delaySlot), 0); // mov(REG(byte, delaySlot), 0);
u32 paddr = 0; u32 paddr = 0;
if (!MapVAddr(regs, LOAD, regs.pc, paddr)) { if (!MapVAddr(regs, LOAD, pc, paddr)) {
mov(rsi, regs.pc); //mov(rsi, regs.pc);
emitCall(HandleTLBException); //emitCall(HandleTLBException);
mov(rsi, u64(GetTLBExceptionCode(regs.cop0.tlbError, LOAD))); //mov(rsi, u64(GetTLBExceptionCode(regs.cop0.tlbError, LOAD)));
CodeGenerator::xor_(rdx, rdx); //CodeGenerator::xor_(rdx, rdx);
CodeGenerator::xor_(rcx, rcx); //CodeGenerator::xor_(rcx, rcx);
emitCall(FireException); //emitCall(FireException);
goto _epilogue; //goto _epilogue;
} }
pc += 4;
u32 instr = mem.Read<u32>(regs, paddr); u32 instr = mem.Read<u32>(regs, paddr);
stable = isStable(instr); stable = isStable(instr);
Emit(instr); Emit(instr);
if (ShouldServiceInterrupt()) { if (ShouldServiceInterrupt()) {
mov(rsi, u64(ExceptionCode::Interrupt)); //mov(rsi, u64(ExceptionCode::Interrupt));
CodeGenerator::xor_(rdx, rdx); //CodeGenerator::xor_(rdx, rdx);
CodeGenerator::xor_(rcx, rcx); //CodeGenerator::xor_(rcx, rcx);
push(rax); //push(rax);
call(FireException); //call(FireException);
goto _epilogue; //goto _epilogue;
} }
mov(rax, REG(qword, pc)); //mov(rax, REG(qword, pc));
mov(REG(qword, oldPC), rax); //mov(REG(qword, oldPC), rax);
mov(rax, REG(qword, nextPC)); //mov(rax, REG(qword, nextPC));
mov(REG(qword, pc), rax); //mov(REG(qword, pc), rax);
CodeGenerator::add(REG(qword, nextPC), 4); //CodeGenerator::add(REG(qword, nextPC), 4);
} }
_epilogue: _epilogue:
epilogue(); //epilogue();
ready(); //ready();
return getCode<Fn>(); //return getCode<Fn>();
ir.optimize();
exit(1);
return nullptr;
} }
int JIT::Step() { int JIT::Step() {
@@ -90,6 +95,7 @@ int JIT::Step() {
blocks[BLOCKCACHE_OUTER_INDEX(regs.pc)][BLOCKCACHE_INNER_INDEX(regs.pc)] = Recompile(); 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;
} }
} }

View File

@@ -137,6 +137,7 @@ private:
void addiu(u32); void addiu(u32);
void andi(u32); void andi(u32);
void and_(u32); void and_(u32);
Entry branch(u32);
void bltz(u32); void bltz(u32);
void bgez(u32); void bgez(u32);
void bltzl(u32); void bltzl(u32);

View File

@@ -1,14 +1,207 @@
#include <IR.hpp> #include <IR.hpp>
#include <fmt/format.h>
namespace n64 { namespace n64 {
template <> struct fmt::formatter<Entry> : formatter<string_view> {
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<string_view>::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<string_view>::format(op, ctx);
}
};
Entry::Entry(Opcode op, Operand dst, Operand op1, Operand op2) Entry::Entry(Opcode op, Operand dst, Operand op1, Operand op2)
: op(op), dst(dst), op1(op1), op2(op2) {} : op(op), dst(dst), op1(op1), op2(op2) {}
Entry::Entry(Opcode op, Operand op1, Operand op2) Entry::Entry(Opcode op, Operand op1, Operand op2)
: op(op), op1(op1), op2(op2) {} : op(op), op1(op1), op2(op2) {}
Entry::Entry(Opcode op, Operand op1, std::optional<BranchCond> bc, Operand op2) Entry::Entry(Opcode op, Operand bDest, Operand op1, std::optional<BranchCond> bc, Operand op2)
: op(op), op1(op1), branchCond(bc), op2(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) Entry::Entry(Opcode op, Operand dst, Operand op1, Operand op2, Shift s)
: op(op), dst(dst), op1(op1), op2(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); code.push_back(e);
} }
void IR::optimize() {
for(auto e : code) {
fmt::print("{}", e);
}
}
auto IR::begin() { auto IR::begin() {
return code.begin(); return code.begin();
} }

View File

@@ -34,25 +34,36 @@ struct Entry {
NONE, REG_F64, REG_F32, IMM_F64, IMM_F32, NONE, REG_F64, REG_F32, IMM_F64, IMM_F32,
REG_S64, REG_S32, REG_U64, REG_U32, REG_U5, IMM_S16, REG_S64, REG_S32, REG_U64, REG_U32, REG_U5, IMM_S16,
IMM_S32, IMM_S64, IMM_U16, IMM_U32, IMM_U64, IMM_U5, IMM_S32, IMM_S64, IMM_U16, IMM_U32, IMM_U64, IMM_U5,
MEM_U8, MEM_U16, MEM_U32, MEM_U64 MEM_U8, MEM_U16, MEM_U32, MEM_U64, PC64, NEXTPC64,
} type; 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<u64> index_or_imm = std::nullopt; std::optional<u64> index_or_imm = std::nullopt;
Operand() = default;
Operand(Type t, std::optional <u64> imm = std::nullopt) Operand(Type t, std::optional <u64> imm = std::nullopt)
: type(t), index_or_imm(imm) {} : 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 { enum BranchCond {
EQ, NE, LT, GT, LE, GE AL, EQ, NE, LT, GT, LE, GE
}; };
std::optional<BranchCond> branchCond = std::nullopt; std::optional<BranchCond> branchCond = std::nullopt;
std::optional<Shift> shift = std::nullopt; std::optional<Shift> shift = std::nullopt;
Operand bDest = Operand::NONE;
Entry(Opcode op, Operand dst, Operand op1, Operand op2); Entry(Opcode op, Operand dst, Operand op1, Operand op2);
Entry(Opcode op, Operand op1, Operand op2); Entry(Opcode op, Operand op1, Operand op2);
Entry(Opcode op, Operand op1, std::optional<BranchCond> bc, Operand op2); Entry(Opcode op, Operand bDest, Operand op1, std::optional<BranchCond> bc, Operand op2);
Entry(Opcode op, Operand bDest);
Entry(Opcode op, Operand dst, Operand op1, Operand op2, Shift s); Entry(Opcode op, Operand dst, Operand op1, Operand op2, Shift s);
}; };
@@ -60,6 +71,7 @@ struct IR {
void push(const Entry&); void push(const Entry&);
auto begin(); auto begin();
auto end(); auto end();
void optimize();
private: private:
std::vector<Entry> code{}; std::vector<Entry> code{};
}; };

View File

@@ -37,125 +37,149 @@ void JIT::dadd(u32 instr) {
ir.push(e); 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) { void JIT::bltz(u32 instr) {
auto dst = branch(instr);
auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; 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); ir.push(e);
} }
void JIT::bgez(u32 instr) { void JIT::bgez(u32 instr) {
auto dst = branch(instr);
auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; 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); ir.push(e);
} }
void JIT::bltzl(u32 instr) { void JIT::bltzl(u32 instr) {
auto dst = branch(instr);
auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 };
auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LIKELY); 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); ir.push(e);
} }
void JIT::bgezl(u32 instr) { void JIT::bgezl(u32 instr) {
auto dst = branch(instr);
auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 };
auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LIKELY); 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); ir.push(e);
} }
void JIT::bltzal(u32 instr) { void JIT::bltzal(u32 instr) {
auto dst = branch(instr);
auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 };
auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LINK); 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); ir.push(e);
} }
void JIT::bgezal(u32 instr) { void JIT::bgezal(u32 instr) {
auto dst = branch(instr);
auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 };
auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LINK); 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); ir.push(e);
} }
void JIT::bltzall(u32 instr) { void JIT::bltzall(u32 instr) {
auto dst = branch(instr);
auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 };
auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LINK | Entry::LIKELY); 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); ir.push(e);
} }
void JIT::bgezall(u32 instr) { void JIT::bgezall(u32 instr) {
auto dst = branch(instr);
auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 }; auto op2 = Entry::Operand{ Entry::Operand::IMM_U64, 0 };
auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LINK | Entry::LIKELY); 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); ir.push(e);
} }
void JIT::beq(u32 instr) { void JIT::beq(u32 instr) {
auto dst = branch(instr);
auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(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); ir.push(e);
} }
void JIT::bne(u32 instr) { void JIT::bne(u32 instr) {
auto dst = branch(instr);
auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(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); ir.push(e);
} }
void JIT::blez(u32 instr) { void JIT::blez(u32 instr) {
auto dst = branch(instr);
auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::IMM_S64, 0 }; 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); ir.push(e);
} }
void JIT::bgtz(u32 instr) { void JIT::bgtz(u32 instr) {
auto dst = branch(instr);
auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::IMM_S64, 0 }; 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); ir.push(e);
} }
void JIT::beql(u32 instr) { void JIT::beql(u32 instr) {
auto dst = branch(instr);
auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) };
auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LIKELY); 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); ir.push(e);
} }
void JIT::bnel(u32 instr) { void JIT::bnel(u32 instr) {
auto dst = branch(instr);
auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) };
auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LIKELY); 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); ir.push(e);
} }
void JIT::blezl(u32 instr) { void JIT::blezl(u32 instr) {
auto dst = branch(instr);
auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::IMM_S64, 0 }; auto op2 = Entry::Operand{ Entry::Operand::IMM_S64, 0 };
auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LIKELY); 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); ir.push(e);
} }
void JIT::bgtzl(u32 instr) { void JIT::bgtzl(u32 instr) {
auto dst = branch(instr);
auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::IMM_S64, 0 }; auto op2 = Entry::Operand{ Entry::Operand::IMM_S64, 0 };
auto opc = Entry::Opcode(u16(Entry::BRANCH) | Entry::LIKELY); 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); ir.push(e);
} }
@@ -423,29 +447,32 @@ void JIT::nor(u32 instr) {
} }
void JIT::j(u32 instr) { void JIT::j(u32 instr) {
s32 target = (instr & 0x3ffffff) << 2; auto dst = Entry::Operand{Entry::Operand::IMM_S64};
s64 address = (regs.oldPC & ~0xfffffff) | target; auto op1 = Entry::Operand{Entry::Operand::PC64};
auto op2 = Entry::Operand{Entry::Operand::IMM_S64, ~0xfffffff};
mov(byte[rdi + offsetof(Registers, delaySlot)], 1); Entry and_(Entry::AND, dst, op1, op2);
mov(qword[rdi + offsetof(Registers, nextPC)], address); 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) { void JIT::jal(u32 instr) {
mov(rax, qword[rdi + offsetof(Registers, nextPC)]); Entry link(Entry::MOV,
mov(GPR(qword, 31), rax); Entry::Operand{Entry::Operand::REG_S64, 31},
Entry::Operand{Entry::Operand::NEXTPC64});
ir.push(link);
j(instr); j(instr);
} }
void JIT::jalr(u32 instr) { void JIT::jalr(u32 instr) {
mov(byte[rdi + offsetof(Registers, delaySlot)], 1); auto addr = Entry::Operand{Entry::Operand::REG_U64, RS(instr)};
mov(rax, GPR(qword, RS(instr))); Entry e(Entry::BRANCH, addr);
mov(qword[rdi + offsetof(Registers, nextPC)], rax); Entry link(Entry::MOV,
Entry::Operand{Entry::Operand::REG_S64, RD(instr)},
if (RD(instr) != 0) [[likely]] { Entry::Operand{Entry::Operand::PC64});
mov(rax, qword[rdi + offsetof(Registers, pc)]); ir.push(link);
CodeGenerator::add(rax, 4);
mov(GPR(qword, RD(instr)), rax);
}
} }
void JIT::slti(u32 instr) { void JIT::slti(u32 instr) {
@@ -706,9 +733,8 @@ void JIT::dsra32(u32 instr) {
} }
void JIT::jr(u32 instr) { void JIT::jr(u32 instr) {
mov(rax, GPR(qword, RS(instr))); auto addr = Entry::Operand{Entry::Operand::REG_U64, RS(instr)};
mov(REG(byte, delaySlot), 1); Entry e(Entry::BRANCH, addr);
mov(REG(qword, nextPC), rax);
} }
void JIT::dsub(u32 instr) { void JIT::dsub(u32 instr) {
@@ -764,23 +790,27 @@ void JIT::mult(u32 instr) {
} }
void JIT::mflo(u32 instr) { void JIT::mflo(u32 instr) {
if (RD(instr) != 0) [[likely]] { auto dst = Entry::Operand{Entry::Operand::REG_S64, RD(instr)};
regs.gpr[RD(instr)] = regs.lo; auto src = Entry::Operand{Entry::Operand::LO};
} ir.push({Entry::MOV, dst, src});
} }
void JIT::mfhi(u32 instr) { void JIT::mfhi(u32 instr) {
if (RD(instr) != 0) [[likely]] { auto dst = Entry::Operand{Entry::Operand::REG_S64, RD(instr)};
regs.gpr[RD(instr)] = regs.hi; auto src = Entry::Operand{Entry::Operand::HI};
} ir.push({Entry::MOV, dst, src});
} }
void JIT::mtlo(u32 instr) { 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) { 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) { void JIT::mtc2(u32 instr) {