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);
}
for(; cycles < mem.mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) {
for(; cycles < mem.mmio.vi.cyclesPerHalfline;) {
u32 taken = cpu->Step();
taken += PopStalledCycles();
static u32 cpuSteps = 0;

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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{};
};

View File

@@ -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) {