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

View File

@@ -1,17 +1,47 @@
#pragma once
#include <common.hpp>
#include <vector>
#include <optional>
namespace n64 {
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 {
enum {
enum Type {
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,
} type;
u8 index;
} dst, op1, op2;
std::optional<u64> index_or_imm;
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 {

View File

@@ -6,12 +6,11 @@
namespace n64 {
void JIT::add(u32 instr) {
if (RD(instr) != 0) [[likely]] {
movsx(eax, GPR(dword, RS(instr))); // rs
movsx(ecx, GPR(dword, RT(instr))); // rt
CodeGenerator::add(eax, ecx);
mov(GPR(dword, RD(instr)), eax); // rd
}
auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RD(instr)) };
auto op1 = Entry::Operand{ Entry::Operand::REG_U32, u8(RS(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::REG_U32, u8(RT(instr)) };
Entry e(Entry::ADD, dst, op1, op2);
ir.push(e);
}
void JIT::addu(u32 instr) {
@@ -19,12 +18,11 @@ void JIT::addu(u32 instr) {
}
void JIT::addi(u32 instr) {
if (RT(instr) != 0) [[likely]] {
movsx(eax, GPR(dword, RS(instr)));
mov(ecx, s32(s16(instr)));
CodeGenerator::add(eax, ecx);
mov(GPR(dword, RT(instr)), eax);
}
auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) };
auto op1 = Entry::Operand{ Entry::Operand::REG_U32, u8(RS(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::IMM_S16, s16(instr) };
Entry e(Entry::ADD, dst, op1, op2);
ir.push(e);
}
void JIT::addiu(u32 instr) {
@@ -32,76 +30,133 @@ void JIT::addiu(u32 instr) {
}
void JIT::dadd(u32 instr) {
if (RD(instr) != 0) [[likely]] {
mov(rax, GPR(qword, RS(instr))); // rs
mov(rcx, GPR(qword, RT(instr))); // rt
CodeGenerator::add(rax, rcx);
mov(GPR(qword, RD(instr)), rax); // rd
}
auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RD(instr)) };
auto op1 = Entry::Operand{ Entry::Operand::REG_U64, u8(RS(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::REG_U64, u8(RT(instr)) };
Entry e(Entry::ADD, dst, op1, op2);
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) {
@@ -109,12 +164,11 @@ void JIT::daddu(u32 instr) {
}
void JIT::daddi(u32 instr) {
if (RT(instr) != 0) [[likely]] {
mov(rax, GPR(qword, RS(instr)));
mov(rcx, s64(s16(instr)));
CodeGenerator::add(rax, rcx);
mov(GPR(qword, RT(instr)), rax);
}
auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) };
auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::IMM_S16, s16(instr) };
Entry e(Entry::ADD, dst, op1, op2);
ir.push(e);
}
void JIT::daddiu(u32 instr) {
@@ -122,25 +176,7 @@ void JIT::daddiu(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) {
@@ -731,13 +767,11 @@ void JIT::and_(u32 instr) {
}
void JIT::sll(u32 instr) {
if (RD(instr) != 0) [[likely]] {
u8 sa = ((instr >> 6) & 0x1f);
mov(rax, GPR(qword, RT(instr)));
sal(rax, sa);
movsxd(rcx, eax);
mov(GPR(qword, RD(instr)), rcx);
}
auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RD(instr)) };
auto op1 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) };
auto op2 = Entry::Operand{ Entry::Operand::IMM_U5, std::nullopt };
Entry e(Entry::SLL, dst, op1, op2);
ir.push(e);
}
void JIT::sllv(u32 instr) {