more instructions and formatter
This commit is contained in:
@@ -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<u32>(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<Fn>();
|
||||
//epilogue();
|
||||
//ready();
|
||||
//return getCode<Fn>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,14 +1,207 @@
|
||||
#include <IR.hpp>
|
||||
#include <fmt/format.h>
|
||||
|
||||
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)
|
||||
: 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<BranchCond> bc, Operand op2)
|
||||
: op(op), op1(op1), branchCond(bc), op2(op2) {}
|
||||
Entry::Entry(Opcode op, Operand bDest, Operand op1, std::optional<BranchCond> 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();
|
||||
}
|
||||
|
||||
@@ -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<u64> index_or_imm = std::nullopt;
|
||||
|
||||
Operand() = default;
|
||||
Operand(Type t, std::optional <u64> 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> branchCond = 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 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);
|
||||
};
|
||||
|
||||
@@ -60,6 +71,7 @@ struct IR {
|
||||
void push(const Entry&);
|
||||
auto begin();
|
||||
auto end();
|
||||
void optimize();
|
||||
private:
|
||||
std::vector<Entry> code{};
|
||||
};
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user