more instructions in IR

This commit is contained in:
Simone
2023-12-21 11:52:35 +01:00
parent 7a680da620
commit f8ecf79c2f
3 changed files with 153 additions and 87 deletions

View File

@@ -3,7 +3,8 @@
#include <vector> #include <vector>
#include <BaseCPU.hpp> #include <BaseCPU.hpp>
#include <xbyak.h> #include <xbyak.h>
#include "CpuDefinitions.hpp" #include <CpuDefinitions.hpp>
#include <IR.hpp>
namespace n64 { namespace n64 {
using Fn = int(*)(); using Fn = int(*)();
@@ -29,6 +30,7 @@ struct JIT : BaseCPU, Xbyak::CodeGenerator {
friend struct Cop1; friend struct Cop1;
friend struct Cop0; friend struct Cop0;
private: private:
IR ir{};
int cycles = 0; int cycles = 0;
bool ShouldServiceInterrupt() override; bool ShouldServiceInterrupt() override;
void CheckCompareInterrupt() override; void CheckCompareInterrupt() override;

View File

@@ -1,17 +1,47 @@
#pragma once #pragma once
#include <common.hpp> #include <common.hpp>
#include <vector> #include <vector>
#include <optional>
namespace n64 { namespace n64 {
struct Entry { struct Entry {
u16 type; enum : u8 {
LINK = 0x10,
LIKELY = 0x20,
REGISTER = 0x40
};
enum Opcode : u16 {
MOV, ADD, SUB, MUL, DIV, AND, NOR, XOR, OR, SRL, SLL, SRA,
LOAD, STORE, BRANCH, JUMP
} op;
struct Operand { struct Operand {
enum { enum Type {
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,
} type; } type;
u8 index; std::optional<u64> index_or_imm;
} dst, op1, op2;
Operand(Type t, std::optional<u64> i = std::nullopt)
: type(t), index_or_imm(i) {}
} dst = Operand::NONE, op1, op2;
enum BranchCond {
EQ, NE, LT, GT, LE, GE
};
std::optional<BranchCond> branchCond = std::nullopt;
Entry(Opcode op, Operand dst, Operand op1, Operand op2)
: op(op), dst(dst), op1(op1), op2(op2) {}
Entry(Opcode op, Operand op1, Operand op2)
: op(op), op1(op1), op2(op2) {}
Entry(Opcode op, Operand op1, std::optional<BranchCond> bc, Operand op2)
: op(op), op1(op1), branchCond(bc), op2(op2) {}
}; };
struct IR { struct IR {

View File

@@ -6,12 +6,11 @@
namespace n64 { namespace n64 {
void JIT::add(u32 instr) { void JIT::add(u32 instr) {
if (RD(instr) != 0) [[likely]] { auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RD(instr)) };
movsx(eax, GPR(dword, RS(instr))); // rs auto op1 = Entry::Operand{ Entry::Operand::REG_U32, u8(RS(instr)) };
movsx(ecx, GPR(dword, RT(instr))); // rt auto op2 = Entry::Operand{ Entry::Operand::REG_U32, u8(RT(instr)) };
CodeGenerator::add(eax, ecx); Entry e(Entry::ADD, dst, op1, op2);
mov(GPR(dword, RD(instr)), eax); // rd ir.push(e);
}
} }
void JIT::addu(u32 instr) { void JIT::addu(u32 instr) {
@@ -19,12 +18,11 @@ void JIT::addu(u32 instr) {
} }
void JIT::addi(u32 instr) { void JIT::addi(u32 instr) {
if (RT(instr) != 0) [[likely]] { auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) };
movsx(eax, GPR(dword, RS(instr))); auto op1 = Entry::Operand{ Entry::Operand::REG_U32, u8(RS(instr)) };
mov(ecx, s32(s16(instr))); auto op2 = Entry::Operand{ Entry::Operand::IMM_S16, s16(instr) };
CodeGenerator::add(eax, ecx); Entry e(Entry::ADD, dst, op1, op2);
mov(GPR(dword, RT(instr)), eax); ir.push(e);
}
} }
void JIT::addiu(u32 instr) { void JIT::addiu(u32 instr) {
@@ -32,76 +30,133 @@ void JIT::addiu(u32 instr) {
} }
void JIT::dadd(u32 instr) { void JIT::dadd(u32 instr) {
if (RD(instr) != 0) [[likely]] { auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RD(instr)) };
mov(rax, GPR(qword, RS(instr))); // rs auto op1 = Entry::Operand{ Entry::Operand::REG_U64, u8(RS(instr)) };
mov(rcx, GPR(qword, RT(instr))); // rt auto op2 = Entry::Operand{ Entry::Operand::REG_U64, u8(RT(instr)) };
CodeGenerator::add(rax, rcx); Entry e(Entry::ADD, dst, op1, op2);
mov(GPR(qword, RD(instr)), rax); // rd ir.push(e);
}
} }
void JIT::bltz(u32) { void JIT::bltz(u32 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);
ir.push(e);
} }
void JIT::bgez(u32) { void JIT::bgez(u32 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);
ir.push(e);
} }
void JIT::bltzl(u32) { void JIT::bltzl(u32 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);
ir.push(e);
} }
void JIT::bgezl(u32) { void JIT::bgezl(u32 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);
ir.push(e);
} }
void JIT::bltzal(u32) { void JIT::bltzal(u32 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);
ir.push(e);
} }
void JIT::bgezal(u32) { void JIT::bgezal(u32 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);
ir.push(e);
} }
void JIT::bltzall(u32) { void JIT::bltzall(u32 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);
ir.push(e);
} }
void JIT::bgezall(u32) { void JIT::bgezall(u32 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);
ir.push(e);
} }
void JIT::beq(u32) { void JIT::beq(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::BRANCH, op1, Entry::BranchCond::EQ, op2);
ir.push(e);
} }
void JIT::bne(u32) { void JIT::bne(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::BRANCH, op1, Entry::BranchCond::NE, op2);
ir.push(e);
} }
void JIT::blez(u32) { void JIT::blez(u32 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);
ir.push(e);
} }
void JIT::bgtz(u32) { void JIT::bgtz(u32 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);
ir.push(e);
} }
void JIT::beql(u32) { void JIT::beql(u32 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);
ir.push(e);
} }
void JIT::bnel(u32) { void JIT::bnel(u32 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);
ir.push(e);
} }
void JIT::blezl(u32) { void JIT::blezl(u32 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);
ir.push(e);
} }
void JIT::bgtzl(u32) { void JIT::bgtzl(u32 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);
ir.push(e);
} }
void JIT::daddu(u32 instr) { void JIT::daddu(u32 instr) {
@@ -109,12 +164,11 @@ void JIT::daddu(u32 instr) {
} }
void JIT::daddi(u32 instr) { void JIT::daddi(u32 instr) {
if (RT(instr) != 0) [[likely]] { auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) };
mov(rax, GPR(qword, RS(instr))); auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) };
mov(rcx, s64(s16(instr))); auto op2 = Entry::Operand{ Entry::Operand::IMM_S16, s16(instr) };
CodeGenerator::add(rax, rcx); Entry e(Entry::ADD, dst, op1, op2);
mov(GPR(qword, RT(instr)), rax); ir.push(e);
}
} }
void JIT::daddiu(u32 instr) { void JIT::daddiu(u32 instr) {
@@ -122,25 +176,7 @@ void JIT::daddiu(u32 instr) {
} }
void JIT::div(u32 instr) { void JIT::div(u32 instr) {
movsxd(rax, GPR(dword, RS(instr))); // dividend
movsxd(rcx, GPR(dword, RT(instr))); // divisor
cmp(rcx, 0);
je("div_divisor==0");
CodeGenerator::div(rcx);
mov(qword[rdi + offsetof(Registers, lo)], eax);
mov(qword[rdi + offsetof(Registers, hi)], edx);
jmp("div_exit");
L("div_divisor==0");
mov(qword[rdi + offsetof(Registers, hi)], rax);
cmp(rax, 0);
jge("div_dividend>=0");
mov(qword[rdi + offsetof(Registers, lo)], s64(1));
L("div_dividend>=0");
mov(qword[rdi + offsetof(Registers, lo)], s64(-1));
L("div_exit");
} }
void JIT::divu(u32 instr) { void JIT::divu(u32 instr) {
@@ -731,13 +767,11 @@ void JIT::and_(u32 instr) {
} }
void JIT::sll(u32 instr) { void JIT::sll(u32 instr) {
if (RD(instr) != 0) [[likely]] { auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RD(instr)) };
u8 sa = ((instr >> 6) & 0x1f); auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) };
mov(rax, GPR(qword, RT(instr))); auto op2 = Entry::Operand{ Entry::Operand::IMM_U5, std::nullopt };
sal(rax, sa); Entry e(Entry::SLL, dst, op1, op2);
movsxd(rcx, eax); ir.push(e);
mov(GPR(qword, RD(instr)), rcx);
}
} }
void JIT::sllv(u32 instr) { void JIT::sllv(u32 instr) {