From 7a680da62093277af6b577a118f75f573a0a65c8 Mon Sep 17 00:00:00 2001 From: Simone Date: Wed, 20 Dec 2023 17:02:53 +0100 Subject: [PATCH 01/20] IR --- CMakeLists.txt | 1 + src/backend/core/JIT/IR.cpp | 15 +++++++++++++++ src/backend/core/JIT/IR.hpp | 24 ++++++++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 src/backend/core/JIT/IR.cpp create mode 100644 src/backend/core/JIT/IR.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 835f891e..fa6d4d91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,7 @@ include_directories( src/frontend/imgui src/backend src/backend/core + src/backend/core/JIT src/backend/core/mmio src/backend/core/registers src/backend/core/rsp diff --git a/src/backend/core/JIT/IR.cpp b/src/backend/core/JIT/IR.cpp new file mode 100644 index 00000000..195fc2d4 --- /dev/null +++ b/src/backend/core/JIT/IR.cpp @@ -0,0 +1,15 @@ +#include + +namespace n64 { +void IR::push(const Entry& e) { + code.push_back(e); +} + +auto IR::begin() { + return code.begin(); +} + +auto IR::end() { + return code.end(); +} +} \ No newline at end of file diff --git a/src/backend/core/JIT/IR.hpp b/src/backend/core/JIT/IR.hpp new file mode 100644 index 00000000..2f43e217 --- /dev/null +++ b/src/backend/core/JIT/IR.hpp @@ -0,0 +1,24 @@ +#pragma once +#include +#include + +namespace n64 { +struct Entry { + u16 type; + struct Operand { + enum { + 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; +}; + +struct IR { + void push(const Entry&); + auto begin(); + auto end(); +private: + std::vector code{}; +}; +} \ No newline at end of file From f8ecf79c2f703cbbfe9a95cc4a98869022e510b2 Mon Sep 17 00:00:00 2001 From: Simone Date: Thu, 21 Dec 2023 11:52:35 +0100 Subject: [PATCH 02/20] more instructions in IR --- src/backend/core/JIT.hpp | 4 +- src/backend/core/JIT/IR.hpp | 38 ++++- src/backend/core/JIT/instructions.cpp | 198 +++++++++++++++----------- 3 files changed, 153 insertions(+), 87 deletions(-) diff --git a/src/backend/core/JIT.hpp b/src/backend/core/JIT.hpp index f78f600f..d2430bac 100644 --- a/src/backend/core/JIT.hpp +++ b/src/backend/core/JIT.hpp @@ -3,7 +3,8 @@ #include #include #include -#include "CpuDefinitions.hpp" +#include +#include 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; diff --git a/src/backend/core/JIT/IR.hpp b/src/backend/core/JIT/IR.hpp index 2f43e217..b7436d83 100644 --- a/src/backend/core/JIT/IR.hpp +++ b/src/backend/core/JIT/IR.hpp @@ -1,17 +1,47 @@ #pragma once #include #include +#include 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 index_or_imm; + + Operand(Type t, std::optional 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 = 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 bc, Operand op2) + : op(op), op1(op1), branchCond(bc), op2(op2) {} }; struct IR { diff --git a/src/backend/core/JIT/instructions.cpp b/src/backend/core/JIT/instructions.cpp index 7ec1f46c..eebb477b 100644 --- a/src/backend/core/JIT/instructions.cpp +++ b/src/backend/core/JIT/instructions.cpp @@ -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) { From 2a3e4d56f6f107ae48479ee4dbf0f83066e7f193 Mon Sep 17 00:00:00 2001 From: Simone Date: Thu, 21 Dec 2023 17:10:52 +0100 Subject: [PATCH 03/20] more instructions --- src/backend/core/JIT/IR.cpp | 12 + src/backend/core/JIT/IR.hpp | 48 +- src/backend/core/JIT/instructions.cpp | 661 ++++++++------------------ 3 files changed, 242 insertions(+), 479 deletions(-) diff --git a/src/backend/core/JIT/IR.cpp b/src/backend/core/JIT/IR.cpp index 195fc2d4..bd36dccc 100644 --- a/src/backend/core/JIT/IR.cpp +++ b/src/backend/core/JIT/IR.cpp @@ -1,6 +1,18 @@ #include namespace n64 { +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 bc, Operand op2) + : op(op), op1(op1), branchCond(bc), op2(op2) {} + +Entry::Entry(Opcode op, Operand dst, Operand op1, Operand op2, Shift s) + : op(op), dst(dst), op1(op1), op2(op2), shift(s) {} + void IR::push(const Entry& e) { code.push_back(e); } diff --git a/src/backend/core/JIT/IR.hpp b/src/backend/core/JIT/IR.hpp index b7436d83..e47d96c2 100644 --- a/src/backend/core/JIT/IR.hpp +++ b/src/backend/core/JIT/IR.hpp @@ -5,15 +5,28 @@ namespace n64 { struct Entry { - enum : u8 { - LINK = 0x10, - LIKELY = 0x20, - REGISTER = 0x40 + enum : u16 { + LINK = 0x100, + LIKELY = 0x200, + REGISTER = 0x400, + SET_LLBIT = 0x800 + }; + + enum Shift { + LEFT, RIGHT }; enum Opcode : u16 { - MOV, ADD, SUB, MUL, DIV, AND, NOR, XOR, OR, SRL, SLL, SRA, - LOAD, STORE, BRANCH, JUMP + MOV, ADD, SUB, UMUL, SMUL, DIV, AND, NOR, XOR, OR, SRL, SLL, SRA, + LOADS8, LOADS8_SHIFT, STORE8, STORE8_SHIFT, + LOADS16, LOADS16_SHIFT, STORE16, STORE16_SHIFT, + LOADS32, LOADS32_SHIFT, STORE32, STORE32_SHIFT, + LOADS64, LOADS64_SHIFT, STORE64, STORE64_SHIFT, + LOADU8, LOADU8_SHIFT, + LOADU16, LOADU16_SHIFT, + LOADU32, LOADU32_SHIFT, + LOADU64, LOADU64_SHIFT, + BRANCH, JUMP, } op; struct Operand { @@ -21,27 +34,26 @@ 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; - std::optional index_or_imm; - Operand(Type t, std::optional i = std::nullopt) - : type(t), index_or_imm(i) {} - } dst = Operand::NONE, op1, op2; + std::optional index_or_imm = std::nullopt; + + Operand(Type t, std::optional imm = std::nullopt) + : type(t), index_or_imm(imm) {} + } dst = Operand::NONE, op1 = Operand::NONE, op2 = Operand::NONE; enum BranchCond { EQ, NE, LT, GT, LE, GE }; std::optional branchCond = std::nullopt; + std::optional shift = 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 bc, Operand op2) - : op(op), op1(op1), branchCond(bc), op2(op2) {} + Entry(Opcode op, Operand dst, Operand op1, Operand op2); + Entry(Opcode op, Operand op1, Operand op2); + Entry(Opcode op, Operand op1, std::optional bc, Operand op2); + Entry(Opcode op, Operand dst, Operand op1, Operand op2, Shift s); }; struct IR { diff --git a/src/backend/core/JIT/instructions.cpp b/src/backend/core/JIT/instructions.cpp index eebb477b..8c58e1d6 100644 --- a/src/backend/core/JIT/instructions.cpp +++ b/src/backend/core/JIT/instructions.cpp @@ -176,502 +176,250 @@ void JIT::daddiu(u32 instr) { } void JIT::div(u32 instr) { - + auto op1 = Entry::Operand{ Entry::Operand::REG_S32, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S32, u8(RT(instr)) }; + Entry e(Entry::DIV, op1, op2); + ir.push(e); } void JIT::divu(u32 instr) { - movsxd(rax, GPR(dword, RS(instr))); // dividend - movsxd(rcx, GPR(dword, RT(instr))); // divisor - cmp(rcx, 0); - je("divu_divisor==0"); - - CodeGenerator::div(rcx); - mov(qword[rdi + offsetof(Registers, lo)], eax); - mov(qword[rdi + offsetof(Registers, hi)], edx); - jmp("divu_exit"); - - L("divu_divisor==0"); - mov(qword[rdi + offsetof(Registers, hi)], rax); - mov(qword[rdi + offsetof(Registers, lo)], -1); - - L("divu_exit"); + 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::DIV, op1, op2); + ir.push(e); } void JIT::ddiv(u32 instr) { - mov(rax, GPR(qword, RS(instr))); - mov(rcx, GPR(qword, RT(instr))); - mov(r8, 0x8000000000000000); - mov(r9, rax); - CodeGenerator::xor_(r9, r8); - mov(r8, 0xFFFFFFFFFFFFFFFF); - mov(r10, rcx); - CodeGenerator::xor_(r10, r8); - CodeGenerator::xor_(r9, r10); - cmp(rcx, 0); - je("ddiv_else_if"); - cmp(r9, 1); - jne("ddiv_else"); - mov(qword[rdi + offsetof(Registers, lo)], rax); - mov(qword[rdi + offsetof(Registers, hi)], 0); - jmp("ddiv_exit"); - L("ddiv_else_if"); - mov(qword[rdi + offsetof(Registers, hi)], rax); - cmp(rax, 0); - jge("ddiv_dividend>=0"); - mov(qword[rdi + offsetof(Registers, lo)], 1); - L("ddiv_dividend>=0"); - mov(qword[rdi + offsetof(Registers, lo)], -1); - L("ddiv_else"); - CodeGenerator::div(rcx); - mov(qword[rdi + offsetof(Registers, lo)], rax); - mov(qword[rdi + offsetof(Registers, hi)], rdx); - L("ddiv_exit"); + 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::DIV, op1, op2); + ir.push(e); } void JIT::ddivu(u32 instr) { - mov(rax, GPR(qword, RS(instr))); - mov(rcx, GPR(qword, RT(instr))); - cmp(rcx, 0); - je("ddivu_divisor==0"); - CodeGenerator::div(rcx); - mov(qword[rdi + offsetof(Registers, lo)], rax); - mov(qword[rdi + offsetof(Registers, hi)], rdx); - jmp("ddivu_exit"); - L("ddivu_divisor==0"); - mov(qword[rdi + offsetof(Registers, lo)], -1); - mov(qword[rdi + offsetof(Registers, hi)], rax); - L("ddivu_exit"); + 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::DIV, op1, op2); + ir.push(e); } void JIT::lui(u32 instr) { - u64 val = s64(s16(instr)); - val <<= 16; - mov(GPR(qword, RT(instr)), val); + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::IMM_S16, u64(s16(instr)) << 16 }; + Entry e(Entry::LOADS64, dst, op1); + ir.push(e); } void JIT::lb(u32 instr) { - mov(rdx, GPR(qword, RS(instr))); - CodeGenerator::add(rdx, s64(s16(instr))); - mov(rsi, LOAD); - push(rcx); - lea(rcx, dword[rbp-4]); - emitCall(MapVAddr); - pop(rcx); - cmp(rax, 0); - je("lb_exception"); - mov(rsi, dword[rbp-4]); - push(rcx); - emitMemberCall(&Mem::Read, &mem); - pop(rcx); - mov(GPR(qword, RT(instr)), rax.cvt8()); - L("lb_exception"); - mov(rsi, rdx); - emitCall(HandleTLBException); - push(rsi); - mov(rdi, REG(byte, cop0.tlbError)); - mov(rsi, LOAD); - emitCall(GetTLBExceptionCode); - pop(rsi); - mov(rsi, rax); - mov(rdx, 0); - mov(rcx, 1); - emitCall(FireException); + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U8, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr))}; + Entry e(Entry::LOADS8, dst, op1, op2); + ir.push(e); } void JIT::lh(u32 instr) { - u64 address = regs.gpr[RS(instr)] + (s16)instr; - if ((address & 0b1) > 0) { - HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); - return; - } - - u32 paddr = 0; - if(!MapVAddr(regs, LOAD, address, paddr)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); - } else { - regs.gpr[RT(instr)] = (s16)mem.Read(regs, paddr); - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U16, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::LOADS16, dst, op1, op2); + ir.push(e); } void JIT::lw(u32 instr) { - s16 offset = instr; - u64 address = regs.gpr[RS(instr)] + offset; - if (check_address_error(0b11, address)) { - HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); - return; - } - - u32 physical = 0; - if (!MapVAddr(regs, LOAD, address, physical)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); - } else { - regs.gpr[RT(instr)] = (s32)mem.Read(regs, physical); - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::LOADS32, dst, op1, op2); + ir.push(e); } void JIT::ll(u32 instr) { - u64 address = regs.gpr[RS(instr)] + (s16)instr; - u32 physical; - if (!MapVAddr(regs, LOAD, address, physical)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); - } else { - if ((address & 0b11) > 0) { - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); - return; - } else { - regs.gpr[RT(instr)] = (s32)mem.Read(regs, physical); - } - } - - regs.cop0.llbit = true; - regs.cop0.LLAddr = physical >> 4; + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto opc = Entry::Opcode(u16(Entry::LOADS64) | Entry::SET_LLBIT); + Entry e(opc, dst, op1, op2); + ir.push(e); } void JIT::lwl(u32 instr) { - u64 address = regs.gpr[RS(instr)] + (s16)instr; - u32 paddr = 0; - if(!MapVAddr(regs, LOAD, address, paddr)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); - } else { - u32 shift = 8 * ((address ^ 0) & 3); - u32 mask = 0xFFFFFFFF << shift; - u32 data = mem.Read(regs, paddr & ~3); - s32 result = s32((regs.gpr[RT(instr)] & ~mask) | (data << shift)); - regs.gpr[RT(instr)] = result; - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::LOADS32_SHIFT, dst, op1, op2, Entry::LEFT); + ir.push(e); } void JIT::lwr(u32 instr) { - u64 address = regs.gpr[RS(instr)] + (s16)instr; - u32 paddr = 0; - if(!MapVAddr(regs, LOAD, address, paddr)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); - } else { - u32 shift = 8 * ((address ^ 3) & 3); - u32 mask = 0xFFFFFFFF >> shift; - u32 data = mem.Read(regs, paddr & ~3); - s32 result = s32((regs.gpr[RT(instr)] & ~mask) | (data >> shift)); - regs.gpr[RT(instr)] = result; - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::LOADS32_SHIFT, dst, op1, op2, Entry::RIGHT); + ir.push(e); } void JIT::ld(u32 instr) { - s64 address = regs.gpr[RS(instr)] + (s16)instr; - if (check_address_error(0b111, address)) { - HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); - return; - } - - u32 paddr = 0; - if(!MapVAddr(regs, LOAD, address, paddr)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); - } else { - s64 value = mem.Read(regs, paddr); - regs.gpr[RT(instr)] = value; - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U64, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::LOADS64, dst, op1, op2); + ir.push(e); } void JIT::lld(u32 instr) { - if (!regs.cop0.is_64bit_addressing && !regs.cop0.kernel_mode) { - FireException(regs, ExceptionCode::ReservedInstruction, 0, regs.oldPC); - return; - } - - u64 address = regs.gpr[RS(instr)] + (s16)instr; - u32 paddr; - if (!MapVAddr(regs, LOAD, address, paddr)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); - } else { - if ((address & 0b111) > 0) { - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); - } else { - regs.gpr[RT(instr)] = mem.Read(regs, paddr); - regs.cop0.llbit = true; - regs.cop0.LLAddr = paddr >> 4; - } - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto opc = Entry::Opcode(u16(Entry::Opcode::LOADS64) | Entry::SET_LLBIT); + Entry e(opc, dst, op1, op2); + ir.push(e); } void JIT::ldl(u32 instr) { - u64 address = regs.gpr[RS(instr)] + (s16)instr; - u32 paddr = 0; - if (!MapVAddr(regs, LOAD, address, paddr)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); - } else { - s32 shift = 8 * ((address ^ 0) & 7); - u64 mask = 0xFFFFFFFFFFFFFFFF << shift; - u64 data = mem.Read(regs, paddr & ~7); - s64 result = (s64) ((regs.gpr[RT(instr)] & ~mask) | (data << shift)); - regs.gpr[RT(instr)] = result; - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::LOADS64_SHIFT, dst, op1, op2, Entry::LEFT); + ir.push(e); } void JIT::ldr(u32 instr) { - u64 address = regs.gpr[RS(instr)] + (s16)instr; - u32 paddr; - if (!MapVAddr(regs, LOAD, address, paddr)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); - } else { - s32 shift = 8 * ((address ^ 7) & 7); - u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; - u64 data = mem.Read(regs, paddr & ~7); - s64 result = (s64) ((regs.gpr[RT(instr)] & ~mask) | (data >> shift)); - regs.gpr[RT(instr)] = result; - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::LOADS64_SHIFT, dst, op1, op2, Entry::RIGHT); + ir.push(e); } void JIT::lbu(u32 instr) { - u64 address = regs.gpr[RS(instr)] + (s16)instr; - u32 paddr; - if (!MapVAddr(regs, LOAD, address, paddr)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); - } else { - u8 value = mem.Read(regs, paddr); - regs.gpr[RT(instr)] = value; - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U8, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::LOADU8, dst, op1, op2); + ir.push(e); } void JIT::lhu(u32 instr) { - s64 address = regs.gpr[RS(instr)] + (s16)instr; - if ((address & 0b1) > 0) { - HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); - return; - } - u32 paddr; - if (!MapVAddr(regs, LOAD, address, paddr)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); - } else { - u16 value = mem.Read(regs, paddr); - regs.gpr[RT(instr)] = value; - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U16, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::LOADU16, dst, op1, op2); + ir.push(e); } void JIT::lwu(u32 instr) { - s64 address = regs.gpr[RS(instr)] + (s16)instr; - if ((address & 0b11) > 0) { - HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); - return; - } - - u32 paddr; - if (!MapVAddr(regs, LOAD, address, paddr)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); - } else { - u32 value = mem.Read(regs, paddr); - regs.gpr[RT(instr)] = value; - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::LOADU16, dst, op1, op2); + ir.push(e); } void JIT::sb(u32 instr) { - u64 address = regs.gpr[RS(instr)] + (s16)instr; - u32 paddr; - if (!MapVAddr(regs, STORE, address, paddr)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); - } else { - mem.Write(regs, paddr, regs.gpr[RT(instr)]); - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U8, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::STORE8, dst, op1, op2); + ir.push(e); } void JIT::sc(u32 instr) { - u64 address = regs.gpr[RS(instr)] + (s16)instr; - - if ((address & 0b11) > 0) { - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); - return; - } - - if(regs.cop0.llbit) { - regs.cop0.llbit = false; - u32 paddr = 0; - if(!MapVAddr(regs, STORE, address, paddr)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); - } else { - mem.Write(regs, paddr, regs.gpr[RT(instr)]); - regs.gpr[RT(instr)] = 1; - } - } else { - regs.gpr[RT(instr)] = 0; - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto opc = Entry::Opcode(u16(Entry::STORE32) | Entry::SET_LLBIT); + Entry e(opc, dst, op1, op2); + ir.push(e); } void JIT::scd(u32 instr) { - if (!regs.cop0.is_64bit_addressing && !regs.cop0.kernel_mode) { - FireException(regs, ExceptionCode::ReservedInstruction, 0, regs.oldPC); - return; - } - - s64 address = regs.gpr[RS(instr)] + (s16)instr; - if ((address & 0b111) > 0) { - HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); - return; - } - - if(regs.cop0.llbit) { - regs.cop0.llbit = false; - u32 paddr = 0; - if(!MapVAddr(regs, STORE, address, paddr)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); - } else { - mem.Write(regs, paddr, regs.gpr[RT(instr)]); - regs.gpr[RT(instr)] = 1; - } - } else { - regs.gpr[RT(instr)] = 0; - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + auto opc = Entry::Opcode(u16(Entry::STORE64) | Entry::SET_LLBIT); + Entry e(opc, dst, op1, op2); + ir.push(e); } void JIT::sh(u32 instr) { - s64 address = regs.gpr[RS(instr)] + (s16)instr; - - u32 physical; - if(!MapVAddr(regs, STORE, address, physical)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); - } else { - mem.Write(regs, physical, regs.gpr[RT(instr)]); - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U16, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::STORE16, dst, op1, op2); + ir.push(e); } void JIT::sw(u32 instr) { - s16 offset = instr; - u64 address = regs.gpr[RS(instr)] + offset; - if (check_address_error(0b11, address)) { - HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); - return; - } - - u32 physical; - if(!MapVAddr(regs, STORE, address, physical)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); - } else { - mem.Write(regs, physical, regs.gpr[RT(instr)]); - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::STORE32, dst, op1, op2); + ir.push(e); } void JIT::sd(u32 instr) { - s64 address = regs.gpr[RS(instr)] + (s16)instr; - if (check_address_error(0b111, address)) { - HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); - return; - } - - u32 physical; - if(!MapVAddr(regs, STORE, address, physical)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); - } else { - mem.Write(regs, physical, regs.gpr[RT(instr)]); - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U64, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::STORE64, dst, op1, op2); + ir.push(e); } void JIT::sdl(u32 instr) { - u64 address = regs.gpr[RS(instr)] + (s16)instr; - u32 paddr; - if (!MapVAddr(regs, STORE, address, paddr)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); - } else { - s32 shift = 8 * ((address ^ 0) & 7); - u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; - u64 data = mem.Read(regs, paddr & ~7); - u64 rt = regs.gpr[RT(instr)]; - mem.Write(regs, paddr & ~7, (data & ~mask) | (rt >> shift)); - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U64, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::STORE64, dst, op1, op2, Entry::LEFT); + ir.push(e); } void JIT::sdr(u32 instr) { - u64 address = regs.gpr[RS(instr)] + (s16)instr; - u32 paddr; - if (!MapVAddr(regs, STORE, address, paddr)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); - } else { - s32 shift = 8 * ((address ^ 7) & 7); - u64 mask = 0xFFFFFFFFFFFFFFFF << shift; - u64 data = mem.Read(regs, paddr & ~7); - u64 rt = regs.gpr[RT(instr)]; - mem.Write(regs, paddr & ~7, (data & ~mask) | (rt << shift)); - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U64, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::STORE64, dst, op1, op2, Entry::RIGHT); + ir.push(e); } void JIT::swl(u32 instr) { - u64 address = regs.gpr[RS(instr)] + (s16)instr; - u32 paddr; - if (!MapVAddr(regs, STORE, address, paddr)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); - } else { - u32 shift = 8 * ((address ^ 0) & 3); - u32 mask = 0xFFFFFFFF >> shift; - u32 data = mem.Read(regs, paddr & ~3); - u32 rt = regs.gpr[RT(instr)]; - mem.Write(regs, paddr & ~3, (data & ~mask) | (rt >> shift)); - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::STORE32, dst, op1, op2, Entry::LEFT); + ir.push(e); } void JIT::swr(u32 instr) { - u64 address = regs.gpr[RS(instr)] + (s16)instr; - u32 paddr; - if (!MapVAddr(regs, STORE, address, paddr)) { - HandleTLBException(regs, address); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); - } else { - u32 shift = 8 * ((address ^ 3) & 3); - u32 mask = 0xFFFFFFFF << shift; - u32 data = mem.Read(regs, paddr & ~3); - u32 rt = regs.gpr[RT(instr)]; - mem.Write(regs, paddr & ~3, (data & ~mask) | (rt << shift)); - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::MEM_U32, s16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::STORE32, dst, op1, op2, Entry::RIGHT); + ir.push(e); } void JIT::ori(u32 instr) { - s64 imm = (u16)instr; - mov(rax, GPR(qword, RS(instr))); - CodeGenerator::or_(rax, imm); - mov(GPR(qword, RT(instr)), rax); + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::IMM_U16, u16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::OR, dst, op1, op2); + ir.push(e); } void JIT::or_(u32 instr) { - if (RD(instr) != 0) [[likely]] { - mov(rax, GPR(qword, RS(instr))); - mov(rcx, GPR(qword, RT(instr))); - CodeGenerator::or_(rax, rcx); - mov(GPR(qword, RD(instr)), rax); - } + 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::REG_S64, u8(RS(instr)) }; + Entry e(Entry::OR, dst, op1, op2); + ir.push(e); } void JIT::nor(u32 instr) { - if (RD(instr) != 0) [[likely]] { - mov(rax, GPR(qword, RS(instr))); - mov(rcx, GPR(qword, RT(instr))); - CodeGenerator::or_(rax, rcx); - not_(rax); - mov(GPR(qword, RD(instr)), rax); - } + 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::REG_S64, u8(RS(instr)) }; + Entry e(Entry::NOR, dst, op1, op2); + ir.push(e); } void JIT::j(u32 instr) { @@ -733,37 +481,35 @@ void JIT::sltu(u32 instr) { } void JIT::xori(u32 instr) { - s64 imm = (u16)instr; - mov(rax, imm); - mov(rcx, GPR(qword, RS(instr))); - CodeGenerator::xor_(rcx, rax); - mov(GPR(qword, RT(instr)), rcx); + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::IMM_U16, u16(instr)}; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::XOR, dst, op1, op2); + ir.push(e); } void JIT::xor_(u32 instr) { - if (RD(instr) != 0) [[likely]] { - mov(rax, GPR(qword, RT(instr))); - mov(rcx, GPR(qword, RS(instr))); - CodeGenerator::xor_(rax, rcx); - mov(GPR(qword, RD(instr)), rax); - } + 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::REG_S64, u8(RS(instr)) }; + Entry e(Entry::XOR, dst, op1, op2); + ir.push(e); } void JIT::andi(u32 instr) { - s64 imm = (u16)instr; - mov(rax, (u16)instr); - mov(rcx, GPR(qword, RS(instr))); - CodeGenerator::and_(rcx, rax); - mov(GPR(qword, RT(instr)), rcx); + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::IMM_U16, u16(instr) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RS(instr)) }; + Entry e(Entry::AND, dst, op1, op2); + ir.push(e); } void JIT::and_(u32 instr) { - if (RD(instr) != 0) [[likely]] { - mov(rax, GPR(qword, RT(instr))); - mov(rcx, GPR(qword, RS(instr))); - CodeGenerator::and_(rax, rcx); - mov(GPR(qword, RD(instr)), rax); - } + 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::REG_S64, u8(RS(instr)) }; + Entry e(Entry::AND, dst, op1, op2); + ir.push(e); } void JIT::sll(u32 instr) { @@ -966,12 +712,11 @@ void JIT::jr(u32 instr) { } void JIT::dsub(u32 instr) { - if (RD(instr) != 0) [[likely]] { - mov(rax, GPR(qword, RT(instr))); - mov(rcx, GPR(qword, RS(instr))); - CodeGenerator::sub(rcx, rax); - 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(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S64, u8(RT(instr)) }; + Entry e(Entry::SUB, dst, op1, op2); + ir.push(e); } void JIT::dsubu(u32 instr) { @@ -979,13 +724,11 @@ void JIT::dsubu(u32 instr) { } void JIT::sub(u32 instr) { - if (RD(instr) != 0) [[likely]] { - mov(eax, GPR(qword, RT(instr))); - mov(ecx, GPR(qword, RS(instr))); - CodeGenerator::sub(ecx, eax); - movsxd(rax, ecx); - mov(GPR(qword, RD(instr)), rax); - } + auto dst = Entry::Operand{ Entry::Operand::REG_S64, u8(RD(instr)) }; + auto op1 = Entry::Operand{ Entry::Operand::REG_S32, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S32, u8(RT(instr)) }; + Entry e(Entry::SUB, dst, op1, op2); + ir.push(e); } void JIT::subu(u32 instr) { @@ -993,35 +736,31 @@ void JIT::subu(u32 instr) { } void JIT::dmultu(u32 instr) { - u64 rt = regs.gpr[RT(instr)]; - u64 rs = regs.gpr[RS(instr)]; - u128 result = (u128)rt * (u128)rs; - regs.lo = (s64)(result & 0xFFFFFFFFFFFFFFFF); - regs.hi = (s64)(result >> 64); + 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::UMUL, op1, op2); + ir.push(e); } void JIT::dmult(u32 instr) { - s64 rt = regs.gpr[RT(instr)]; - s64 rs = regs.gpr[RS(instr)]; - s128 result = (s128)rt * (s128)rs; - regs.lo = result & 0xFFFFFFFFFFFFFFFF; - regs.hi = result >> 64; + 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::SMUL, op1, op2); + ir.push(e); } void JIT::multu(u32 instr) { - u32 rt = regs.gpr[RT(instr)]; - u32 rs = regs.gpr[RS(instr)]; - u64 result = (u64)rt * (u64)rs; - regs.lo = (s64)((s32)result); - regs.hi = (s64)((s32)(result >> 32)); + auto op1 = Entry::Operand{ Entry::Operand::REG_S32, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S32, u8(RT(instr)) }; + Entry e(Entry::UMUL, op1, op2); + ir.push(e); } void JIT::mult(u32 instr) { - s32 rt = regs.gpr[RT(instr)]; - s32 rs = regs.gpr[RS(instr)]; - s64 result = (s64)rt * (s64)rs; - regs.lo = (s64)((s32)result); - regs.hi = (s64)((s32)(result >> 32)); + auto op1 = Entry::Operand{ Entry::Operand::REG_S32, u8(RS(instr)) }; + auto op2 = Entry::Operand{ Entry::Operand::REG_S32, u8(RT(instr)) }; + Entry e(Entry::SMUL, op1, op2); + ir.push(e); } void JIT::mflo(u32 instr) { From 1f84b969090d67f796581ef4a42544d0422d8ba9 Mon Sep 17 00:00:00 2001 From: SimoneN64 Date: Mon, 25 Dec 2023 03:43:17 +0100 Subject: [PATCH 04/20] more instructions and formatter --- src/backend/Core.cpp | 2 +- src/backend/core/JIT.cpp | 64 ++++---- src/backend/core/JIT.hpp | 1 + src/backend/core/JIT/IR.cpp | 203 +++++++++++++++++++++++++- src/backend/core/JIT/IR.hpp | 22 ++- src/backend/core/JIT/instructions.cpp | 116 +++++++++------ 6 files changed, 328 insertions(+), 80 deletions(-) diff --git a/src/backend/Core.cpp b/src/backend/Core.cpp index 1882f977..8bae5209 100644 --- a/src/backend/Core.cpp +++ b/src/backend/Core.cpp @@ -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; diff --git a/src/backend/core/JIT.cpp b/src/backend/core/JIT.cpp index ff2ac465..767755b1 100644 --- a/src/backend/core/JIT.cpp +++ b/src/backend/core/JIT.cpp @@ -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(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(); + //epilogue(); + //ready(); + //return getCode(); + 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; } } diff --git a/src/backend/core/JIT.hpp b/src/backend/core/JIT.hpp index d2430bac..c780b92e 100644 --- a/src/backend/core/JIT.hpp +++ b/src/backend/core/JIT.hpp @@ -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); diff --git a/src/backend/core/JIT/IR.cpp b/src/backend/core/JIT/IR.cpp index bd36dccc..3cf75e60 100644 --- a/src/backend/core/JIT/IR.cpp +++ b/src/backend/core/JIT/IR.cpp @@ -1,14 +1,207 @@ #include +#include namespace n64 { +template <> struct fmt::formatter : formatter { + 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::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::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 bc, Operand op2) - : op(op), op1(op1), branchCond(bc), op2(op2) {} +Entry::Entry(Opcode op, Operand bDest, Operand op1, std::optional 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(); } diff --git a/src/backend/core/JIT/IR.hpp b/src/backend/core/JIT/IR.hpp index e47d96c2..b75f7eb8 100644 --- a/src/backend/core/JIT/IR.hpp +++ b/src/backend/core/JIT/IR.hpp @@ -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 index_or_imm = std::nullopt; + Operand() = default; Operand(Type t, std::optional 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 = std::nullopt; std::optional 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 bc, Operand op2); + Entry(Opcode op, Operand bDest, Operand op1, std::optional 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 code{}; }; diff --git a/src/backend/core/JIT/instructions.cpp b/src/backend/core/JIT/instructions.cpp index 8c58e1d6..5bc4e20d 100644 --- a/src/backend/core/JIT/instructions.cpp +++ b/src/backend/core/JIT/instructions.cpp @@ -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) { From 360d7a7ccd1bf5a619c194ec2e7931b6afa56be5 Mon Sep 17 00:00:00 2001 From: SimoneN64 Date: Mon, 25 Dec 2023 21:59:47 +0100 Subject: [PATCH 05/20] first optimization --- src/backend/core/JIT.cpp | 1 + src/backend/core/JIT/IR.cpp | 43 +++++++++++++++++++++++++++++++++---- src/backend/core/JIT/IR.hpp | 12 ++++++++++- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/backend/core/JIT.cpp b/src/backend/core/JIT.cpp index 767755b1..9fe222db 100644 --- a/src/backend/core/JIT.cpp +++ b/src/backend/core/JIT.cpp @@ -81,6 +81,7 @@ _epilogue: //ready(); //return getCode(); ir.optimize(); + ir.print(); exit(1); return nullptr; } diff --git a/src/backend/core/JIT/IR.cpp b/src/backend/core/JIT/IR.cpp index 3cf75e60..f383f696 100644 --- a/src/backend/core/JIT/IR.cpp +++ b/src/backend/core/JIT/IR.cpp @@ -151,18 +151,20 @@ template <> struct fmt::formatter : formatter { std::string op1 = fmt::format("R{}", e.op1.index_or_imm.value()); if(put_comma) { op += ", "; + } else { + put_comma = true; } 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 += ", "; + } else { + put_comma = true; } op += op1; - put_comma = true; } } @@ -171,18 +173,20 @@ template <> struct fmt::formatter : formatter { std::string op2 = fmt::format("R{}", e.op2.index_or_imm.value()); if(put_comma) { op += ", "; + } else { + put_comma = true; } 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 += ", "; + } else { + put_comma = true; } op += op2; - put_comma = true; } } @@ -211,6 +215,37 @@ void IR::push(const Entry& e) { } void IR::optimize() { + std::vector optimized{}; + + for(const auto& i : code) { + bool isOp1Reg = i.op1.isReg(); + bool isOp2Reg = i.op2.isReg(); + bool isDstReg = i.dst.isReg(); + + if(isDstReg) { + if(isOp1Reg) { + if(i.op1.index_or_imm == i.dst.index_or_imm + && i.zeroRendersItUseless()) continue; + } + + if(isOp2Reg) { + if(i.op2.index_or_imm == i.dst.index_or_imm + && i.zeroRendersItUseless()) continue; + } + } + + optimized.push_back(i); + } + + if(optimized.size() == code.size()) { + return; + } + + code = optimized; + optimize(); +} + +void IR::print() { for(auto e : code) { fmt::print("{}", e); } diff --git a/src/backend/core/JIT/IR.hpp b/src/backend/core/JIT/IR.hpp index b75f7eb8..77b4ff0f 100644 --- a/src/backend/core/JIT/IR.hpp +++ b/src/backend/core/JIT/IR.hpp @@ -38,11 +38,16 @@ struct Entry { LO, HI } type = NONE; - bool isReg() { + bool isReg() const { return type == REG_S64 || type == REG_F32 || type == REG_F64 || type == REG_S32 || type == REG_U64 || type == REG_U32 || type == REG_U5; } + bool isImm() const { + return type == IMM_S64 || type == IMM_F32 || type == IMM_F64 || type == IMM_S32 + || type == IMM_U64 || type == IMM_U32 || type == IMM_U5; + } + std::optional index_or_imm = std::nullopt; Operand() = default; @@ -50,6 +55,10 @@ struct Entry { : type(t), index_or_imm(imm) {} } dst, op1, op2; + bool zeroRendersItUseless() const { + return op == ADD || op == OR || op == SRL || op == SLL || op == SRA; + } + [[nodiscard]] const Operand& GetDst() const { return dst; } enum BranchCond { @@ -71,6 +80,7 @@ struct IR { void push(const Entry&); auto begin(); auto end(); + void print(); void optimize(); private: std::vector code{}; From 80c7e46a38b028622fe32309e4f7d33cd3ef56f4 Mon Sep 17 00:00:00 2001 From: SimoneN64 Date: Mon, 25 Dec 2023 22:49:24 +0100 Subject: [PATCH 06/20] better print, some cop0 --- src/backend/core/JIT.hpp | 10 ++ src/backend/core/JIT/IR.cpp | 214 +++++++++----------------- src/backend/core/JIT/IR.hpp | 8 +- src/backend/core/JIT/instructions.cpp | 85 ++++++++++ src/backend/core/registers/Cop0.cpp | 21 ++- 5 files changed, 194 insertions(+), 144 deletions(-) diff --git a/src/backend/core/JIT.hpp b/src/backend/core/JIT.hpp index c780b92e..50497fda 100644 --- a/src/backend/core/JIT.hpp +++ b/src/backend/core/JIT.hpp @@ -239,6 +239,16 @@ private: void xor_(u32); void xori(u32); + void mtc0(u32); + void dmtc0(u32); + void mfc0(u32); + void dmfc0(u32); + void eret(); + + void tlbr(); + void tlbw(int); + void tlbp(); + void mtc2(u32); void mfc2(u32); void dmtc2(u32); diff --git a/src/backend/core/JIT/IR.cpp b/src/backend/core/JIT/IR.cpp index f383f696..edb89b43 100644 --- a/src/backend/core/JIT/IR.cpp +++ b/src/backend/core/JIT/IR.cpp @@ -6,141 +6,66 @@ template <> struct fmt::formatter : formatter { 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; + 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; + case Entry::MTC0: op = "MTC0"; break; + case Entry::MFC0: op = "MFC0"; 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::format(op, ctx); - } else { - std::string dst = fmt::format("R{}", e.dst.index_or_imm.value()); - op += dst; - put_comma = true; - } + std::string dst = fmt::format("R{}", e.dst.index_or_imm.value()); + op += dst; + put_comma = true; + } + } else if(e.dst.isImm()) { + 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; } } else { if(e.dst.type != Entry::Operand::NONE) { - std::string dst = fmt::format("0x{:0X}", e.dst.index_or_imm.value()); + std::string dst = fmt::format("(0x{:0X})", e.dst.index_or_imm.value()); op += dst; put_comma = true; } @@ -151,20 +76,27 @@ template <> struct fmt::formatter : formatter { std::string op1 = fmt::format("R{}", e.op1.index_or_imm.value()); if(put_comma) { op += ", "; - } else { - put_comma = true; } op += op1; + put_comma = true; } - } else { + } else if(e.op1.isImm()) { 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 += ", "; - } else { - put_comma = true; } 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 = false; } } @@ -173,8 +105,6 @@ template <> struct fmt::formatter : formatter { std::string op2 = fmt::format("R{}", e.op2.index_or_imm.value()); if(put_comma) { op += ", "; - } else { - put_comma = true; } op += op2; } @@ -183,8 +113,6 @@ template <> struct fmt::formatter : formatter { std::string op2 = fmt::format("0x{:0X}", e.op2.index_or_imm.value()); if(put_comma) { op += ", "; - } else { - put_comma = true; } op += op2; } @@ -214,18 +142,18 @@ void IR::push(const Entry& e) { code.push_back(e); } -void IR::optimize() { - std::vector optimized{}; - +void IR::dead_code_elimination(std::vector& code_) { for(const auto& i : code) { bool isOp1Reg = i.op1.isReg(); bool isOp2Reg = i.op2.isReg(); bool isDstReg = i.dst.isReg(); if(isDstReg) { + if(i.zeroRendersItUseless() && i.dst.index_or_imm == 0) continue; + if(isOp1Reg) { if(i.op1.index_or_imm == i.dst.index_or_imm - && i.zeroRendersItUseless()) continue; + && i.zeroRendersItUseless()) continue; } if(isOp2Reg) { @@ -234,8 +162,14 @@ void IR::optimize() { } } - optimized.push_back(i); + code_.push_back(i); } +} + +void IR::optimize() { + std::vector optimized{}; + + dead_code_elimination(optimized); if(optimized.size() == code.size()) { return; diff --git a/src/backend/core/JIT/IR.hpp b/src/backend/core/JIT/IR.hpp index 77b4ff0f..802f9834 100644 --- a/src/backend/core/JIT/IR.hpp +++ b/src/backend/core/JIT/IR.hpp @@ -9,7 +9,8 @@ struct Entry { LINK = 0x100, LIKELY = 0x200, REGISTER = 0x400, - SET_LLBIT = 0x800 + SET_LLBIT = 0x800, + UNSET_LLBIT = 0x1000, }; enum Shift { @@ -26,8 +27,8 @@ struct Entry { LOADU16, LOADU16_SHIFT, LOADU32, LOADU32_SHIFT, LOADU64, LOADU64_SHIFT, - BRANCH, JUMP, - } op; + BRANCH, JUMP, MTC0, MFC0 + } op; struct Operand { enum Type { @@ -83,6 +84,7 @@ struct IR { void print(); void optimize(); private: + void dead_code_elimination(std::vector&); std::vector code{}; }; } \ No newline at end of file diff --git a/src/backend/core/JIT/instructions.cpp b/src/backend/core/JIT/instructions.cpp index 5bc4e20d..af108de8 100644 --- a/src/backend/core/JIT/instructions.cpp +++ b/src/backend/core/JIT/instructions.cpp @@ -813,6 +813,91 @@ void JIT::mthi(u32 instr) { ir.push({Entry::MOV, dst, src}); } +void JIT::mtc0(u32 instr) { + ir.push({Entry::MTC0, + {Entry::Operand::IMM_U5, RD(instr)}, + {Entry::Operand::REG_S32, RT(instr)}}); +} + +void JIT::dmtc0(u32 instr) { + ir.push({Entry::MTC0, + {Entry::Operand::IMM_U5, RD(instr)}, + {Entry::Operand::REG_S64, RT(instr)}}); +} + +void JIT::mfc0(u32 instr) { + ir.push({Entry::MFC0, + {Entry::Operand::REG_S32, RT(instr)}, + {Entry::Operand::IMM_U5, RD(instr)}}); +} + +void JIT::dmfc0(u32 instr) { + ir.push({Entry::MFC0, + {Entry::Operand::REG_S64, RT(instr)}, + {Entry::Operand::IMM_U5, RD(instr)}}); +} + +void JIT::eret() { + /*if(status.erl) { + regs.SetPC64(ErrorEPC); + status.erl = false; + } else { + regs.SetPC64(EPC); + status.exl = false; + } + regs.cop0.Update(); + llbit = false;*/ +} + + +void JIT::tlbr() { + /*if (index.i >= 32) { + Util::panic("TLBR with TLB index {}", index.i); + } + + TLBEntry entry = tlb[index.i]; + + entryHi.raw = entry.entryHi.raw; + entryLo0.raw = entry.entryLo0.raw & 0x3FFFFFFF; + entryLo1.raw = entry.entryLo1.raw & 0x3FFFFFFF; + + entryLo0.g = entry.global; + entryLo1.g = entry.global; + pageMask.raw = entry.pageMask.raw;*/ +} + +void JIT::tlbw(int index_) { + /*PageMask page_mask{}; + page_mask = pageMask; + u32 top = page_mask.mask & 0xAAA; + page_mask.mask = top | (top >> 1); + + if(index_ >= 32) { + Util::panic("TLBWI with TLB index {}", index_); + } + + tlb[index_].entryHi.raw = entryHi.raw; + tlb[index_].entryHi.vpn2 &= ~page_mask.mask; + + tlb[index_].entryLo0.raw = entryLo0.raw & 0x03FFFFFE; + tlb[index_].entryLo1.raw = entryLo1.raw & 0x03FFFFFE; + tlb[index_].pageMask.raw = page_mask.raw; + + tlb[index_].global = entryLo0.g && entryLo1.g; + tlb[index_].initialized = true;*/ +} + +void JIT::tlbp() { + /*int match = -1; + TLBEntry* entry = TLBTryMatch(regs, entryHi.raw, &match); + if(entry && match >= 0) { + index.raw = match; + } else { + index.raw = 0; + index.p = 1; + }*/ +} + void JIT::mtc2(u32 instr) { } diff --git a/src/backend/core/registers/Cop0.cpp b/src/backend/core/registers/Cop0.cpp index bf041c05..b504522f 100644 --- a/src/backend/core/registers/Cop0.cpp +++ b/src/backend/core/registers/Cop0.cpp @@ -1,6 +1,7 @@ #include #include #include +#include namespace n64 { Cop0::Cop0() { @@ -336,7 +337,25 @@ template void Cop0::decode(Interpreter&, u32); template void Cop0::decode(JIT&, u32); void Cop0::decodeJIT(JIT& cpu, u32 instr) { - + u8 mask_cop = (instr >> 21) & 0x1F; + u8 mask_cop2 = instr & 0x3F; + switch(mask_cop) { + case 0x00: cpu.mfc0(instr); break; + case 0x01: cpu.dmfc0(instr); break; + case 0x04: cpu.mtc0(instr); break; + case 0x05: cpu.dmtc0(instr); break; + case 0x10 ... 0x1F: + switch(mask_cop2) { + case 0x01: cpu.tlbr(); break; + case 0x02: cpu.tlbw(index.i); break; + case 0x06: cpu.tlbw(GetRandom()); break; + case 0x08: cpu.tlbp(); break; + case 0x18: cpu.eret(); break; + default: Util::panic("Unimplemented COP0 function {} {} ({:08X}) ({:016lX})", mask_cop2 >> 3, mask_cop2 & 7, instr, cpu.regs.oldPC); + } + break; + default: Util::panic("Unimplemented COP0 instruction {} {}", mask_cop >> 4, mask_cop & 7); + } } void Cop0::decodeInterp(Registers& regs, u32 instr) { From dacb76ca8573764956c240acc8fb997916bc9214 Mon Sep 17 00:00:00 2001 From: Simone Date: Wed, 27 Dec 2023 10:13:11 +0100 Subject: [PATCH 07/20] improve dead code elimination and implement SLT --- src/backend/core/JIT.cpp | 7 +++-- src/backend/core/JIT/IR.cpp | 22 +++++++++------ src/backend/core/JIT/IR.hpp | 10 ++++--- src/backend/core/JIT/instructions.cpp | 40 +++++++++++++-------------- 4 files changed, 44 insertions(+), 35 deletions(-) diff --git a/src/backend/core/JIT.cpp b/src/backend/core/JIT.cpp index 9fe222db..64760ce0 100644 --- a/src/backend/core/JIT.cpp +++ b/src/backend/core/JIT.cpp @@ -32,12 +32,15 @@ void JIT::CheckCompareInterrupt() { Fn JIT::Recompile() { bool stable = true; + bool old_stable = stable; cycles = 0; //prologue(); //mov(rbp, u64(this)); //mov(rdi, u64(this) + THIS_OFFSET(regs)); - u64 pc = regs.pc; - while(stable) { + u64 pc = regs.pc + 0x3D0; + while(old_stable) { + old_stable = stable; + cycles++; CheckCompareInterrupt(); diff --git a/src/backend/core/JIT/IR.cpp b/src/backend/core/JIT/IR.cpp index edb89b43..513e29c9 100644 --- a/src/backend/core/JIT/IR.cpp +++ b/src/backend/core/JIT/IR.cpp @@ -47,6 +47,7 @@ template <> struct fmt::formatter : formatter { case Entry::JUMP: op = "JUMP"; break; case Entry::MTC0: op = "MTC0"; break; case Entry::MFC0: op = "MFC0"; break; + case Entry::SLT: op = "SLT"; break; } bool put_comma = false; @@ -148,17 +149,20 @@ void IR::dead_code_elimination(std::vector& code_) { bool isOp2Reg = i.op2.isReg(); bool isDstReg = i.dst.isReg(); + // check for operations like "add rx, rx, 0" or "add r0, anything" if(isDstReg) { - if(i.zeroRendersItUseless() && i.dst.index_or_imm == 0) continue; + bool isDstR0 = i.dst.isReg() && i.dst.index_or_imm.has_value() && i.dst.index_or_imm.value() == 0; + bool areDstAndOp1Same = i.dst.isReg() && i.op1.isReg() && i.dst.index_or_imm.has_value() && i.op1.index_or_imm.has_value() && i.op1.index_or_imm.value() == i.dst.index_or_imm.value(); + bool areDstAndOp2Same = i.dst.isReg() && i.op2.isReg() && i.dst.index_or_imm.has_value() && i.op2.index_or_imm.has_value() && i.op2.index_or_imm.value() == i.dst.index_or_imm.value(); + if (isDstR0) continue; + if (i.canDoDCE()) { + if (areDstAndOp1Same) { + if (i.op2.isImm() && i.op2.index_or_imm.value() == 0) continue; + } - if(isOp1Reg) { - if(i.op1.index_or_imm == i.dst.index_or_imm - && i.zeroRendersItUseless()) continue; - } - - if(isOp2Reg) { - if(i.op2.index_or_imm == i.dst.index_or_imm - && i.zeroRendersItUseless()) continue; + if (areDstAndOp2Same) { + if (i.op1.isImm() && i.op1.index_or_imm.value() == 0) continue; + } } } diff --git a/src/backend/core/JIT/IR.hpp b/src/backend/core/JIT/IR.hpp index 802f9834..b0dea0ec 100644 --- a/src/backend/core/JIT/IR.hpp +++ b/src/backend/core/JIT/IR.hpp @@ -18,7 +18,8 @@ struct Entry { }; enum Opcode : u16 { - MOV, ADD, SUB, UMUL, SMUL, DIV, AND, NOR, XOR, OR, SRL, SLL, SRA, + MOV, SLT, ADD, SUB, UMUL, SMUL, DIV, AND, NOR, + XOR, OR, SRL, SLL, SRA, LOADS8, LOADS8_SHIFT, STORE8, STORE8_SHIFT, LOADS16, LOADS16_SHIFT, STORE16, STORE16_SHIFT, LOADS32, LOADS32_SHIFT, STORE32, STORE32_SHIFT, @@ -45,8 +46,9 @@ struct Entry { } bool isImm() const { - return type == IMM_S64 || type == IMM_F32 || type == IMM_F64 || type == IMM_S32 - || type == IMM_U64 || type == IMM_U32 || type == IMM_U5; + return type == IMM_S64 || type == IMM_U16 || type == IMM_S16 || + type == IMM_F32 || type == IMM_F64 || type == IMM_S32 || + type == IMM_U64 || type == IMM_U32 || type == IMM_U5; } std::optional index_or_imm = std::nullopt; @@ -56,7 +58,7 @@ struct Entry { : type(t), index_or_imm(imm) {} } dst, op1, op2; - bool zeroRendersItUseless() const { + bool canDoDCE() const { return op == ADD || op == OR || op == SRL || op == SLL || op == SRA; } diff --git a/src/backend/core/JIT/instructions.cpp b/src/backend/core/JIT/instructions.cpp index af108de8..6c49eda2 100644 --- a/src/backend/core/JIT/instructions.cpp +++ b/src/backend/core/JIT/instructions.cpp @@ -476,35 +476,35 @@ void JIT::jalr(u32 instr) { } void JIT::slti(u32 instr) { - mov(rax, s64(s16(instr))); - mov(rcx, GPR(qword, RS(instr))); - cmp(rcx, rax); - setl(GPR(qword, RT(instr))); + Entry e(Entry::SLT, + { Entry::Operand::REG_U5, RT(instr) }, + { Entry::Operand::REG_S64, RS(instr) }, + { Entry::Operand::IMM_S64, s64(s16(instr)) }); + ir.push(e); } void JIT::sltiu(u32 instr) { - mov(rax, s64(s16(instr))); - mov(rcx, GPR(qword, RS(instr))); - cmp(rcx, rax); - setb(GPR(qword, RT(instr))); + Entry e(Entry::SLT, + { Entry::Operand::REG_U5, RT(instr) }, + { Entry::Operand::REG_U64, RS(instr) }, + { Entry::Operand::IMM_U64, u64(s64(s16(instr))) }); + ir.push(e); } void JIT::slt(u32 instr) { - if (RD(instr) != 0) [[likely]] { - mov(rax, GPR(qword, RS(instr))); - mov(rcx, GPR(qword, RT(instr))); - cmp(rax, rcx); - setl(GPR(qword, RD(instr))); - } + Entry e(Entry::SLT, + { Entry::Operand::REG_U5, RD(instr) }, + { Entry::Operand::REG_S64, RS(instr) }, + { Entry::Operand::REG_S64, RT(instr) }); + ir.push(e); } void JIT::sltu(u32 instr) { - if (RD(instr) != 0) [[likely]] { - mov(rax, GPR(qword, RS(instr))); - mov(rcx, GPR(qword, RT(instr))); - cmp(rax, rcx); - setb(GPR(qword, RD(instr))); - } + Entry e(Entry::SLT, + { Entry::Operand::REG_U5, RD(instr) }, + { Entry::Operand::REG_U64, RS(instr) }, + { Entry::Operand::REG_U64, RT(instr) }); + ir.push(e); } void JIT::xori(u32 instr) { From fb3146744f218d188c58a7342d4aed0ef02c60f9 Mon Sep 17 00:00:00 2001 From: Simone Date: Wed, 27 Dec 2023 10:30:59 +0100 Subject: [PATCH 08/20] improve branch, doesn't need extra add in IR --- src/backend/core/JIT.hpp | 2 +- src/backend/core/JIT/IR.cpp | 47 ++++++++++++++++++++++----- src/backend/core/JIT/IR.hpp | 10 ++++-- src/backend/core/JIT/instructions.cpp | 41 +++++++++++------------ 4 files changed, 65 insertions(+), 35 deletions(-) diff --git a/src/backend/core/JIT.hpp b/src/backend/core/JIT.hpp index 50497fda..fdbca9dc 100644 --- a/src/backend/core/JIT.hpp +++ b/src/backend/core/JIT.hpp @@ -137,7 +137,7 @@ private: void addiu(u32); void andi(u32); void and_(u32); - Entry branch(u32); + Entry::Operand branch(u32); void bltz(u32); void bgez(u32); void bltzl(u32); diff --git a/src/backend/core/JIT/IR.cpp b/src/backend/core/JIT/IR.cpp index 513e29c9..6ec205b9 100644 --- a/src/backend/core/JIT/IR.cpp +++ b/src/backend/core/JIT/IR.cpp @@ -59,11 +59,13 @@ template <> struct fmt::formatter : formatter { put_comma = true; } } else if(e.dst.isImm()) { - 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; - } + std::string dst = fmt::format("0x{:0X}", e.dst.index_or_imm.value()); + op += dst; + put_comma = true; + } else if(e.dst.type == Entry::Operand::PC64) { + std::string dst = fmt::format("PC"); + 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()); @@ -72,6 +74,12 @@ template <> struct fmt::formatter : formatter { } } + if (e.bOffs.index_or_imm.has_value()) { + std::string dst = fmt::format("0x{:0X}", e.bOffs.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()); @@ -90,6 +98,13 @@ template <> struct fmt::formatter : formatter { op += op1; put_comma = true; } + } else if (e.dst.type == Entry::Operand::PC64) { + std::string dst = fmt::format("PC"); + if (put_comma) { + op += ", "; + } + op += dst; + 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()); @@ -101,6 +116,20 @@ template <> struct fmt::formatter : formatter { } } + if (e.branchCond.has_value()) { + put_comma = false; + op += " "; + switch (e.branchCond.value()) { + case Entry::AL: op += " "; break; + case Entry::EQ: op += "== "; break; + case Entry::NE: op += "!= "; break; + case Entry::LT: op += "< "; break; + case Entry::GT: op += "> "; break; + case Entry::LE: op += "<= "; break; + case Entry::GE: op += ">= "; break; + } + } + if (e.op2.isReg()) { if (e.op2.index_or_imm.has_value()) { std::string op2 = fmt::format("R{}", e.op2.index_or_imm.value()); @@ -130,11 +159,11 @@ Entry::Entry(Opcode op, Operand dst, Operand op1, Operand op2) Entry::Entry(Opcode op, Operand op1, Operand op2) : op(op), op1(op1), op2(op2) {} -Entry::Entry(Opcode op, Operand bDest, Operand op1, std::optional bc, Operand op2) - : op(op), bDest(bDest), op1(op1), branchCond(bc), op2(op2) {} +Entry::Entry(Opcode op, Operand bOffs, Operand op1, std::optional bc, Operand op2) + : op(op), bOffs(bOffs), op1(op1), branchCond(bc), op2(op2) {} -Entry::Entry(Opcode op, Operand bDest) -: op(op), bDest(bDest) {} +Entry::Entry(Opcode op, Operand bOffs) +: op(op), bOffs(bOffs) {} Entry::Entry(Opcode op, Operand dst, Operand op1, Operand op2, Shift s) : op(op), dst(dst), op1(op1), op2(op2), shift(s) {} diff --git a/src/backend/core/JIT/IR.hpp b/src/backend/core/JIT/IR.hpp index b0dea0ec..77408a00 100644 --- a/src/backend/core/JIT/IR.hpp +++ b/src/backend/core/JIT/IR.hpp @@ -51,6 +51,10 @@ struct Entry { type == IMM_U64 || type == IMM_U32 || type == IMM_U5; } + bool isMem() const { + return type == MEM_U8 || type == MEM_U16 || type == MEM_U32 || type == MEM_U64; + } + std::optional index_or_imm = std::nullopt; Operand() = default; @@ -70,12 +74,12 @@ struct Entry { std::optional branchCond = std::nullopt; std::optional shift = std::nullopt; - Operand bDest = Operand::NONE; + Operand bOffs = Operand::NONE; Entry(Opcode op, Operand dst, Operand op1, Operand op2); Entry(Opcode op, Operand op1, Operand op2); - Entry(Opcode op, Operand bDest, Operand op1, std::optional bc, Operand op2); - Entry(Opcode op, Operand bDest); + Entry(Opcode op, Operand bOffs, Operand op1, std::optional bc, Operand op2); + Entry(Opcode op, Operand bOffs); Entry(Opcode op, Operand dst, Operand op1, Operand op2, Shift s); }; diff --git a/src/backend/core/JIT/instructions.cpp b/src/backend/core/JIT/instructions.cpp index 6c49eda2..96c93f80 100644 --- a/src/backend/core/JIT/instructions.cpp +++ b/src/backend/core/JIT/instructions.cpp @@ -37,19 +37,16 @@ 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_; +Entry::Operand JIT::branch(u32 instr) { + auto addr = Entry::Operand{ Entry::Operand::IMM_S64, u64(s64(s16(instr))) << 2 }; + return addr; } 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, dst.GetDst(), op1, Entry::BranchCond::LT, op2); + Entry e(Entry::BRANCH, dst, op1, Entry::BranchCond::LT, op2); ir.push(e); } @@ -57,7 +54,7 @@ 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, dst.GetDst(), op1, Entry::BranchCond::GE, op2); + Entry e(Entry::BRANCH, dst, op1, Entry::BranchCond::GE, op2); ir.push(e); } @@ -66,7 +63,7 @@ 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, dst.GetDst(), op1, Entry::BranchCond::LT, op2); + Entry e(opc, dst, op1, Entry::BranchCond::LT, op2); ir.push(e); } @@ -75,7 +72,7 @@ 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, dst.GetDst(), op1, Entry::BranchCond::GE, op2); + Entry e(opc, dst, op1, Entry::BranchCond::GE, op2); ir.push(e); } @@ -84,7 +81,7 @@ 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, dst.GetDst(), op1, Entry::BranchCond::LT, op2); + Entry e(opc, dst, op1, Entry::BranchCond::LT, op2); ir.push(e); } @@ -93,7 +90,7 @@ 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, dst.GetDst(), op1, Entry::BranchCond::GE, op2); + Entry e(opc, dst, op1, Entry::BranchCond::GE, op2); ir.push(e); } @@ -102,7 +99,7 @@ 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, dst.GetDst(), op1, Entry::BranchCond::LT, op2); + Entry e(opc, dst, op1, Entry::BranchCond::LT, op2); ir.push(e); } @@ -111,7 +108,7 @@ 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, dst.GetDst(), op1, Entry::BranchCond::GE, op2); + Entry e(opc, dst, op1, Entry::BranchCond::GE, op2); ir.push(e); } @@ -119,7 +116,7 @@ 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, dst.GetDst(), op1, Entry::BranchCond::EQ, op2); + Entry e(Entry::BRANCH, dst, op1, Entry::BranchCond::EQ, op2); ir.push(e); } @@ -127,7 +124,7 @@ 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, dst.GetDst(), op1, Entry::BranchCond::NE, op2); + Entry e(Entry::BRANCH, dst, op1, Entry::BranchCond::NE, op2); ir.push(e); } @@ -135,7 +132,7 @@ 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, dst.GetDst(), op1, Entry::BranchCond::LE, op2); + Entry e(Entry::BRANCH, dst, op1, Entry::BranchCond::LE, op2); ir.push(e); } @@ -143,7 +140,7 @@ 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, dst.GetDst(), op1, Entry::BranchCond::GT, op2); + Entry e(Entry::BRANCH, dst, op1, Entry::BranchCond::GT, op2); ir.push(e); } @@ -152,7 +149,7 @@ 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, dst.GetDst(), op1, Entry::BranchCond::EQ, op2); + Entry e(opc, dst, op1, Entry::BranchCond::EQ, op2); ir.push(e); } @@ -161,7 +158,7 @@ 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, dst.GetDst(), op1, Entry::BranchCond::NE, op2); + Entry e(opc, dst, op1, Entry::BranchCond::NE, op2); ir.push(e); } @@ -170,7 +167,7 @@ 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, dst.GetDst(), op1, Entry::BranchCond::LE, op2); + Entry e(opc, dst, op1, Entry::BranchCond::LE, op2); ir.push(e); } @@ -179,7 +176,7 @@ 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, dst.GetDst(), op1, Entry::BranchCond::GT, op2); + Entry e(opc, dst, op1, Entry::BranchCond::GT, op2); ir.push(e); } From 9d8ecdc953425bce9249de145f96a25ea88eddde Mon Sep 17 00:00:00 2001 From: Simone Date: Wed, 27 Dec 2023 11:00:20 +0100 Subject: [PATCH 09/20] jumps weren't actually being pushed to the vector --- src/backend/core/JIT.cpp | 2 +- src/backend/core/JIT/IR.cpp | 7 ++++++- src/backend/core/JIT/instructions.cpp | 3 +++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/backend/core/JIT.cpp b/src/backend/core/JIT.cpp index 64760ce0..74946b01 100644 --- a/src/backend/core/JIT.cpp +++ b/src/backend/core/JIT.cpp @@ -37,7 +37,7 @@ Fn JIT::Recompile() { //prologue(); //mov(rbp, u64(this)); //mov(rdi, u64(this) + THIS_OFFSET(regs)); - u64 pc = regs.pc + 0x3D0; + u64 pc = regs.pc; while(old_stable) { old_stable = stable; diff --git a/src/backend/core/JIT/IR.cpp b/src/backend/core/JIT/IR.cpp index 6ec205b9..1b49206d 100644 --- a/src/backend/core/JIT/IR.cpp +++ b/src/backend/core/JIT/IR.cpp @@ -75,7 +75,12 @@ template <> struct fmt::formatter : formatter { } if (e.bOffs.index_or_imm.has_value()) { - std::string dst = fmt::format("0x{:0X}", e.bOffs.index_or_imm.value()); + std::string dst; + if (e.bOffs.isReg()) { + dst = fmt::format("R{}", e.bOffs.index_or_imm.value()); + } else if (e.bOffs.isImm()) { + dst = fmt::format("0x{:0X}", e.bOffs.index_or_imm.value()); + } op += dst; put_comma = true; } diff --git a/src/backend/core/JIT/instructions.cpp b/src/backend/core/JIT/instructions.cpp index 96c93f80..dacfadac 100644 --- a/src/backend/core/JIT/instructions.cpp +++ b/src/backend/core/JIT/instructions.cpp @@ -453,6 +453,7 @@ void JIT::j(u32 instr) { Entry or_(Entry::OR, dst, dst, op2); ir.push(or_); Entry e(Entry::BRANCH, or_.GetDst()); + ir.push(e); } void JIT::jal(u32 instr) { @@ -470,6 +471,7 @@ void JIT::jalr(u32 instr) { Entry::Operand{Entry::Operand::REG_S64, RD(instr)}, Entry::Operand{Entry::Operand::PC64}); ir.push(link); + j(instr); } void JIT::slti(u32 instr) { @@ -732,6 +734,7 @@ void JIT::dsra32(u32 instr) { void JIT::jr(u32 instr) { auto addr = Entry::Operand{Entry::Operand::REG_U64, RS(instr)}; Entry e(Entry::BRANCH, addr); + ir.push(e); } void JIT::dsub(u32 instr) { From 52914d9b780cbd62ebf69b51a1bb1308f5cc7fd1 Mon Sep 17 00:00:00 2001 From: Simone Date: Wed, 27 Dec 2023 14:50:34 +0100 Subject: [PATCH 10/20] like this form better --- src/backend/core/JIT/IR.cpp | 28 ++++++++++++++++++---------- src/backend/core/JIT/IR.hpp | 3 ++- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/backend/core/JIT/IR.cpp b/src/backend/core/JIT/IR.cpp index 1b49206d..81aab37d 100644 --- a/src/backend/core/JIT/IR.cpp +++ b/src/backend/core/JIT/IR.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include namespace n64 { template <> struct fmt::formatter : formatter { @@ -177,8 +179,15 @@ void IR::push(const Entry& e) { code.push_back(e); } -void IR::dead_code_elimination(std::vector& code_) { - for(const auto& i : code) { +std::vector IR::constant_propagation(std::vector& code_) { + std::vector optimized{}; + + return optimized; +} + +std::vector IR::dead_code_elimination(std::vector& code_) { + std::vector optimized{}; + for(const auto& i : code_) { bool isOp1Reg = i.op1.isReg(); bool isOp2Reg = i.op2.isReg(); bool isDstReg = i.dst.isReg(); @@ -200,21 +209,20 @@ void IR::dead_code_elimination(std::vector& code_) { } } - code_.push_back(i); + optimized.push_back(i); } + + return optimized; } void IR::optimize() { std::vector optimized{}; - dead_code_elimination(optimized); - - if(optimized.size() == code.size()) { - return; + while (optimized.size() < code.size()) { + optimized = dead_code_elimination(code); + //optimized = constant_propagation(optimized); + code = optimized; } - - code = optimized; - optimize(); } void IR::print() { diff --git a/src/backend/core/JIT/IR.hpp b/src/backend/core/JIT/IR.hpp index 77408a00..62a9ea74 100644 --- a/src/backend/core/JIT/IR.hpp +++ b/src/backend/core/JIT/IR.hpp @@ -90,7 +90,8 @@ struct IR { void print(); void optimize(); private: - void dead_code_elimination(std::vector&); + std::vector constant_propagation(std::vector&); + std::vector dead_code_elimination(std::vector&); std::vector code{}; }; } \ No newline at end of file From 578bb3b45bd3b9f6a714facdfb0ac289b3657f82 Mon Sep 17 00:00:00 2001 From: Simone Date: Thu, 28 Dec 2023 15:11:12 +0100 Subject: [PATCH 11/20] better representation (inspired by fleroviux's Lunatic) --- src/backend/core/JIT/IR/Opcode.hpp | 42 ++++++++++++ src/backend/core/JIT/IR/Register.hpp | 11 ++++ src/backend/core/JIT/IR/Value.hpp | 98 ++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 src/backend/core/JIT/IR/Opcode.hpp create mode 100644 src/backend/core/JIT/IR/Register.hpp create mode 100644 src/backend/core/JIT/IR/Value.hpp diff --git a/src/backend/core/JIT/IR/Opcode.hpp b/src/backend/core/JIT/IR/Opcode.hpp new file mode 100644 index 00000000..12ffd354 --- /dev/null +++ b/src/backend/core/JIT/IR/Opcode.hpp @@ -0,0 +1,42 @@ +#pragma once +#include + +namespace n64 { +enum class IROpcodeClass { + Normal, Special, Regimm, COP0, COP1 +}; + +struct IROpcode { + virtual ~IROpcode() = default; + virtual auto GetClass() const -> IROpcodeClass = 0; + virtual auto Reads (IRVariable const& var) -> bool = 0; + virtual auto Writes(IRVariable const& var) -> bool = 0; + virtual void Repoint(IRVariable const& var_old, IRVariable const& var_new) = 0; + virtual void PropagateConstant(IRVariable const& var, IRConstant const& constant) {} +}; + +template +struct IROpcodeBase : IROpcode { + auto GetClass() const -> IROpcodeClass override { return _class; } +}; + +struct IRNoOp final : IROpcodeBase { + auto Reads(IRVariable const& var) -> bool override { + return false; + } + + auto Writes(IRVariable const& var) -> bool override { + return false; + } + + void Repoint( + IRVariable const& var_old, + IRVariable const& var_new + ) override { + } + + auto ToString() -> std::string override { + return "nop"; + } +}; +} \ No newline at end of file diff --git a/src/backend/core/JIT/IR/Register.hpp b/src/backend/core/JIT/IR/Register.hpp new file mode 100644 index 00000000..e42adccb --- /dev/null +++ b/src/backend/core/JIT/IR/Register.hpp @@ -0,0 +1,11 @@ +#pragma once +#include + +namespace n64 { +struct IRGuestReg { + IRGuestReg(u8 reg) : reg(reg) {} + + /// The ARM general purpose register + const u8 reg; +}; +} \ No newline at end of file diff --git a/src/backend/core/JIT/IR/Value.hpp b/src/backend/core/JIT/IR/Value.hpp new file mode 100644 index 00000000..94b853bd --- /dev/null +++ b/src/backend/core/JIT/IR/Value.hpp @@ -0,0 +1,98 @@ +#pragma once +#include + +namespace n64 { +enum IRPrimitive { + Uint32, Sint32, Uint64, Sint32, Uint128, Sint128 +}; + +struct IRVariable { + IRVariable(IRPrimitive type, const u32 id, char const* const label) : type(type), id(id), label(label) {} +private: + IRPrimitive type; + const u32 id; + char const* const label; +}; + +struct IRConstant { + IRConstant() {} + IRConstant(IRPrimitive type, u128 value) : type(type), value(value) {} +private: + IRPrimitive type = Uint128; + u128 value = 0; +}; + +struct IRAnyRef { + IRAnyRef() {} + IRAnyRef(IRVariable const& variable) : type(Type::Variable), var(&variable) {} + IRAnyRef(IRConstant const& constant) : type(Type::Constant), constant(constant) {} + + auto operator=(IRAnyRef const& other) -> IRAnyRef& { + type = other.type; + if (IsConstant()) { + constant = other.constant; + } else { + var = other.var; + } + return *this; + } + + bool IsNull() const { return type == Type::Null; } + bool IsVariable() const { return type == Type::Variable; } + bool IsConstant() const { return type == Type::Constant; } + + auto GetVar() const -> IRVariable const& { + if (!IsVariable()) { + Util::panic("called GetVar() but value is a constant or null"); + } + return *var; + } + + auto GetConst() const -> IRConstant const& { + if (!IsConstant()) { + Util::panic("called GetConst() but value is a variable or null"); + } + return constant; + } + + void Repoint(IRVariable const& var_old, IRVariable const& var_new) { + if (IsVariable() && (&GetVar() == &var_old)) { + var = &var_new; + } + } + + void PropagateConstant(IRVariable const& var, IRConstant const& constant) { + if (IsVariable() && (&GetVar() == &var)) { + type = Type::Constant; + this->constant = constant; + } + } +private: + enum Type { + Null, Variable, Constant + }; + + Type type; + + union { + IRVariable const* var; + IRConstant constant; + }; +}; + +struct IRVarRef { + IRVarRef(IRVariable const& var) : p_var(&var) {} + + auto Get() const -> IRVariable const& { + return *p_var; + } + + void Repoint(IRVariable const& var_old, IRVariable const& var_new) { + if (&var_old == p_var) { + p_var = &var_new; + } + } +private: + IRVariable const* p_var; +}; +} \ No newline at end of file From 463b53f0e4bc5f96d5549e4971f1dd7b719a2f91 Mon Sep 17 00:00:00 2001 From: SimoneN64 Date: Tue, 2 Jan 2024 23:57:06 +0100 Subject: [PATCH 12/20] to dev --- src/backend/Core.cpp | 12 +++++------- src/backend/Scheduler.cpp | 17 +++++++---------- src/backend/Scheduler.hpp | 21 ++++++++++++++++----- src/backend/core/Mem.cpp | 4 +++- src/common.hpp | 3 --- 5 files changed, 31 insertions(+), 26 deletions(-) diff --git a/src/backend/Core.cpp b/src/backend/Core.cpp index 8bae5209..abffeabb 100644 --- a/src/backend/Core.cpp +++ b/src/backend/Core.cpp @@ -33,14 +33,12 @@ void Core::LoadROM(const std::string& rom_) { pause = false; romLoaded = true; + std::string archive_types[] = {".zip",".7z",".rar",".tar"}; + auto extension = fs::path(rom).extension().string(); - bool isArchive = false; - for(const auto i : ARCHIVE_TYPES) { - if(extension == i) { - isArchive = true; - break; - } - } + bool isArchive = std::any_of(std::begin(archive_types), std::end(archive_types), [&extension](const auto& e) { + return e == extension; + }); cpu->mem.LoadROM(isArchive, rom); GameDB::match(cpu->mem); diff --git a/src/backend/Scheduler.cpp b/src/backend/Scheduler.cpp index ccfce290..80fc7b9c 100644 --- a/src/backend/Scheduler.cpp +++ b/src/backend/Scheduler.cpp @@ -13,16 +13,13 @@ void Scheduler::enqueueAbsolute(u64 t, const EventType type) { } u64 Scheduler::remove(EventType type) { - auto copy = events; - while(!copy.empty()) { - if(copy.top().type == type) { - u64 ret = copy.top().time - ticks; - copy.pop(); - events.swap(copy); + for (auto& e : events) { + if(e.type == type) { + u64 ret = e.time - ticks; + e.type = NONE; + e.time = ticks; return ret; } - - copy.pop(); } return 0; @@ -35,7 +32,7 @@ void Scheduler::tick(u64 t, n64::Mem& mem, n64::Registers& regs) { n64::PI& pi = mem.mmio.pi; while(ticks >= events.top().time) { - switch(events.top().type) { + switch(auto type = events.top().type) { case SI_DMA: si.status.dmaBusy = false; si.DMA(mem, regs); @@ -53,7 +50,7 @@ void Scheduler::tick(u64 t, n64::Mem& mem, n64::Registers& regs) { case IMPOSSIBLE: Util::panic("Congratulations on keeping the emulator on for about 5 billion years, I guess, nerd."); default: - Util::panic("Unknown scheduler event type"); + Util::panic("Unknown scheduler event type {}", static_cast(type)); } events.pop(); } diff --git a/src/backend/Scheduler.hpp b/src/backend/Scheduler.hpp index 6de92d94..e7feaa30 100644 --- a/src/backend/Scheduler.hpp +++ b/src/backend/Scheduler.hpp @@ -34,17 +34,28 @@ struct Event { } }; +struct IterableEvents { + std::priority_queue, std::greater<>> events; +public: + explicit IterableEvents() = default; + auto top() { return events.top(); } + auto pop() { events.pop(); } + auto begin() { return (Event*)(&events.top()); } + auto end() { return begin() + events.size(); } + auto push(Event e) { events.push(e); } +}; + struct Scheduler { Scheduler() { enqueueAbsolute(std::numeric_limits::max(), IMPOSSIBLE); } - void enqueueRelative(u64, const EventType); - void enqueueAbsolute(u64, const EventType); - u64 remove(const EventType); + void enqueueRelative(u64, EventType); + void enqueueAbsolute(u64, EventType); + u64 remove(EventType); void tick(u64 t, n64::Mem&, n64::Registers&); - - std::priority_queue, std::greater<>> events; + + IterableEvents events; u64 ticks = 0; u8 index = 0; }; diff --git a/src/backend/core/Mem.cpp b/src/backend/core/Mem.cpp index f6c4e191..6ef5b6b4 100644 --- a/src/backend/core/Mem.cpp +++ b/src/backend/core/Mem.cpp @@ -99,11 +99,13 @@ std::vector Mem::OpenArchive(const std::string &path, size_t& sizeAdjusted) std::vector buf{}; + std::string rom_exts[] = {".n64",".z64",".v64",".N64",".Z64",".V64"}; + while(ar_parse_entry(archive)) { auto filename = ar_entry_get_name(archive); auto extension = fs::path(filename).extension(); - if(std::any_of(std::begin(ROM_EXTENSIONS), std::end(ROM_EXTENSIONS), [&](auto x) { + if(std::any_of(std::begin(rom_exts), std::end(rom_exts), [&](auto x) { return extension == x; })) { auto size = ar_entry_get_size(archive); diff --git a/src/common.hpp b/src/common.hpp index 0ba6cad6..989ae9d9 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -39,9 +39,6 @@ static FORCE_INLINE constexpr u32 GetVideoFrequency(bool pal) { #define HALF_ADDRESS(addr) ((addr) ^ 2) #define BYTE_ADDRESS(addr) ((addr) ^ 3) -#define ARCHIVE_TYPES {".zip",".7z",".rar",".tar"} -#define ROM_EXTENSIONS {".n64",".z64",".v64",".N64",".Z64",".V64"} - #define RD(x) (((x) >> 11) & 0x1F) #define RT(x) (((x) >> 16) & 0x1F) #define RS(x) (((x) >> 21) & 0x1F) From d1b4da3de2a847d835875ba2e956e27c916c56fd Mon Sep 17 00:00:00 2001 From: SimoneN64 Date: Tue, 2 Jan 2024 23:57:58 +0100 Subject: [PATCH 13/20] IR work --- src/backend/core/JIT/IR.hpp | 1 + src/backend/core/JIT/IR/Opcode.hpp | 70 ++++++++++++++++++++++++++++-- src/backend/core/JIT/IR/Value.hpp | 63 +++++++++++++++++++++++---- 3 files changed, 122 insertions(+), 12 deletions(-) diff --git a/src/backend/core/JIT/IR.hpp b/src/backend/core/JIT/IR.hpp index 62a9ea74..4cd60a82 100644 --- a/src/backend/core/JIT/IR.hpp +++ b/src/backend/core/JIT/IR.hpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace n64 { struct Entry { diff --git a/src/backend/core/JIT/IR/Opcode.hpp b/src/backend/core/JIT/IR/Opcode.hpp index 12ffd354..9bfc90bc 100644 --- a/src/backend/core/JIT/IR/Opcode.hpp +++ b/src/backend/core/JIT/IR/Opcode.hpp @@ -1,9 +1,11 @@ #pragma once #include +#include +#include namespace n64 { enum class IROpcodeClass { - Normal, Special, Regimm, COP0, COP1 + StorePC, Add, Special, Regimm, COP0, COP1 }; struct IROpcode { @@ -13,6 +15,7 @@ struct IROpcode { virtual auto Writes(IRVariable const& var) -> bool = 0; virtual void Repoint(IRVariable const& var_old, IRVariable const& var_new) = 0; virtual void PropagateConstant(IRVariable const& var, IRConstant const& constant) {} + virtual auto ToString() -> std::string = 0; }; template @@ -20,13 +23,59 @@ struct IROpcodeBase : IROpcode { auto GetClass() const -> IROpcodeClass override { return _class; } }; -struct IRNoOp final : IROpcodeBase { +template +struct IRBinaryOpBase : IROpcodeBase<_class> { + IRBinaryOpBase(IRVariable const& result, IRVariable lhs, IRAnyRef rhs) + : result(const_cast(result)), lhs(lhs), rhs(rhs) {} + + IRVariable& result; + IRVarRef lhs; + IRAnyRef rhs; + auto Reads(IRVariable const& var) -> bool override { + return &lhs.Get() == &var || + (rhs.IsVariable() && (&rhs.GetVar() == &var)); + } + + auto Writes(IRVariable const& var) -> bool override { + return result.HasValue() && (&result == &var); + } + + void Repoint( + IRVariable const& var_old, + IRVariable const& var_new + ) override { + // TODO: make this reusable? + if (result.HasValue() && (&result == &var_old)) { + result = var_new; + } + + lhs.Repoint(var_old, var_new); + rhs.Repoint(var_old, var_new); + } + + void PropagateConstant( + IRVariable const& var, + IRConstant const& constant + ) override { + rhs.PropagateConstant(var, constant); + } +}; + +struct IRStorePC final : IROpcodeBase { + IRStorePC(IRAnyRef val) : val(val) {} + + IRAnyRef val; + + auto Reads(IRVariable const& var) -> bool override { + if(val.IsVariable()) { + return &var == &val.GetVar(); + } return false; } auto Writes(IRVariable const& var) -> bool override { - return false; + return true; } void Repoint( @@ -36,7 +85,20 @@ struct IRNoOp final : IROpcodeBase { } auto ToString() -> std::string override { - return "nop"; + return fmt::format("str_pc {}", std::to_string(val)); + } +}; + +struct IRAdd final : IRBinaryOpBase { + using IRBinaryOpBase::IRBinaryOpBase; + + auto ToString() -> std::string override { + return fmt::format( + "add {}, {}, {}", + std::to_string(result), + std::to_string(lhs), + std::to_string(rhs) + ); } }; } \ No newline at end of file diff --git a/src/backend/core/JIT/IR/Value.hpp b/src/backend/core/JIT/IR/Value.hpp index 94b853bd..a801fd7e 100644 --- a/src/backend/core/JIT/IR/Value.hpp +++ b/src/backend/core/JIT/IR/Value.hpp @@ -3,23 +3,27 @@ namespace n64 { enum IRPrimitive { - Uint32, Sint32, Uint64, Sint32, Uint128, Sint128 + Uint32, Sint32, Uint64, Sint64 }; struct IRVariable { - IRVariable(IRPrimitive type, const u32 id, char const* const label) : type(type), id(id), label(label) {} -private: + IRVariable(IRPrimitive type, const u32 id, char const* const label) : type(type), id(id), label(label), assigned(false) {} IRPrimitive type; - const u32 id; - char const* const label; + u32 id; + char const* label; + bool assigned; + + bool HasValue() const { return assigned; } + bool IsNull() const { return !assigned; } }; struct IRConstant { IRConstant() {} - IRConstant(IRPrimitive type, u128 value) : type(type), value(value) {} + IRConstant(IRPrimitive type, u64 value) : type(type), value(value) {} + + u64 value = 0; private: - IRPrimitive type = Uint128; - u128 value = 0; + IRPrimitive type = Uint64; }; struct IRAnyRef { @@ -95,4 +99,47 @@ struct IRVarRef { private: IRVariable const* p_var; }; +} + + +namespace std { +inline auto to_string(n64::IRPrimitive data_type) -> std::string { + switch (data_type) { + case n64::IRPrimitive::Uint32: + return "u32"; + case n64::IRPrimitive::Sint32: + return "s32"; + case n64::IRPrimitive::Uint64: + return "u64"; + case n64::IRPrimitive::Sint64: + return "s64"; + default: + return "???"; + } +} + +inline auto to_string(n64::IRVariable const &variable) -> std::string { + if (variable.label) { + return fmt::format("var{}_{}", variable.id, variable.label); + } + return fmt::format("var{}", variable.id); +} + +inline auto to_string(n64::IRConstant const &constant) -> std::string { + return fmt::format("0x{:0X}", constant.value); +} + +inline auto to_string(n64::IRAnyRef const &value) -> std::string { + if (value.IsNull()) { + return "(null)"; + } + if (value.IsConstant()) { + return std::to_string(value.GetConst()); + } + return std::to_string(value.GetVar()); +} + +inline auto to_string(n64::IRVarRef const &variable) -> std::string { + return std::to_string(variable.Get()); +} } \ No newline at end of file From d7a94b41e0924825630f781ba8422f537e07a670 Mon Sep 17 00:00:00 2001 From: SimoneN64 Date: Wed, 3 Jan 2024 14:22:06 +0100 Subject: [PATCH 14/20] fix a bunch of warnings --- CMakeLists.txt | 1 + src/backend/Core.hpp | 5 +- src/backend/Scheduler.hpp | 6 +- src/backend/core/Mem.cpp | 2 +- src/backend/core/Mem.hpp | 6 +- src/backend/core/RSP.hpp | 4 +- src/backend/core/mem/Flash.cpp | 2 +- src/backend/core/mmio/MI.hpp | 2 +- src/backend/core/mmio/PI.cpp | 2 +- src/backend/core/mmio/PI.hpp | 11 +- src/backend/core/mmio/PIF/Device.cpp | 2 +- src/backend/core/mmio/SI.cpp | 2 +- src/backend/core/mmio/SI.hpp | 2 +- src/backend/core/registers/Cop0.hpp | 20 +-- src/backend/core/registers/Cop1.hpp | 14 +-- .../core/registers/cop/cop0instructions.cpp | 2 +- .../core/registers/cop/cop1instructions.cpp | 118 +++++++++--------- src/frontend/imgui/Settings.hpp | 2 +- src/utils/MemoryHelpers.hpp | 12 +- 19 files changed, 108 insertions(+), 107 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fa6d4d91..05a15432 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,3 +83,4 @@ file(REMOVE target_link_libraries(kaizen PUBLIC frontend frontend-imgui discord-rpc imgui nfd parallel-rdp backend fmt::fmt mio::mio nlohmann_json::nlohmann_json core registers jit interpreter mem unarr mmio rsp SDL2::SDL2main SDL2::SDL2) +target_compile_options(kaizen PUBLIC -Wextra) diff --git a/src/backend/Core.hpp b/src/backend/Core.hpp index ad4746f8..b79a1139 100644 --- a/src/backend/Core.hpp +++ b/src/backend/Core.hpp @@ -18,8 +18,7 @@ struct Core { void Serialize(); void Deserialize(); void TogglePause() { pause = !pause; } - void HandleEvents(Event*); - [[nodiscard]] VI& GetVI() { return cpu->mem.mmio.vi; } + [[nodiscard]] VI& GetVI() const { return cpu->mem.mmio.vi; } u32 breakpoint = 0; @@ -30,7 +29,7 @@ struct Core { std::string rom; std::unique_ptr cpu; std::vector serialized[10]{}; - int memSize, cpuSize, verSize; + size_t memSize{}, cpuSize{}, verSize{}; int slot = 0; }; diff --git a/src/backend/Scheduler.hpp b/src/backend/Scheduler.hpp index e7feaa30..6cb1a869 100644 --- a/src/backend/Scheduler.hpp +++ b/src/backend/Scheduler.hpp @@ -38,10 +38,10 @@ struct IterableEvents { std::priority_queue, std::greater<>> events; public: explicit IterableEvents() = default; - auto top() { return events.top(); } + [[nodiscard]] auto top() const { return events.top(); } auto pop() { events.pop(); } - auto begin() { return (Event*)(&events.top()); } - auto end() { return begin() + events.size(); } + [[nodiscard]] auto begin() const { return (Event*)(&events.top()); } + [[nodiscard]] auto end() const { return begin() + events.size(); } auto push(Event e) { events.push(e); } }; diff --git a/src/backend/core/Mem.cpp b/src/backend/core/Mem.cpp index 6ef5b6b4..eab71c2d 100644 --- a/src/backend/core/Mem.cpp +++ b/src/backend/core/Mem.cpp @@ -12,7 +12,7 @@ Mem::Mem() : flash(saveData) { memset(readPages, 0, PAGE_COUNT); memset(writePages, 0, PAGE_COUNT); - for(int i = 0; i < RDRAM_SIZE / PAGE_SIZE; i++) { + for(u64 i = 0; i < RDRAM_SIZE / PAGE_SIZE; i++) { const auto addr = (i * PAGE_SIZE) & RDRAM_DSIZE; const auto pointer = (uintptr_t) &mmio.rdp.rdram[addr]; readPages[i] = pointer; diff --git a/src/backend/core/Mem.hpp b/src/backend/core/Mem.hpp index d8da8fa9..ee1b0597 100644 --- a/src/backend/core/Mem.hpp +++ b/src/backend/core/Mem.hpp @@ -42,7 +42,7 @@ enum class FlashState : u8 { }; struct Flash { - Flash(mio::mmap_sink&); + explicit Flash(mio::mmap_sink&); ~Flash() = default; void Reset(); void Load(SaveType, const std::string&); @@ -148,8 +148,8 @@ private: friend struct Core; u8 isviewer[ISVIEWER_SIZE]{}; std::string sramPath{}; - mio::mmap_sink saveData; - int mmioSize, flashSize; + mio::mmap_sink saveData{}; + int mmioSize{}, flashSize{}; FORCE_INLINE bool IsROMPAL() { static const char pal_codes[] = {'D', 'F', 'I', 'P', 'S', 'U', 'X', 'Y'}; diff --git a/src/backend/core/RSP.hpp b/src/backend/core/RSP.hpp index d691e9c8..e099d355 100644 --- a/src/backend/core/RSP.hpp +++ b/src/backend/core/RSP.hpp @@ -374,8 +374,8 @@ struct RSP { u32 mem_address = rsp.spDMASPAddr.address & 0xFF8; u32 dram_address = rsp.spDMADRAMAddr.address & 0xFFFFF8; - for (int i = 0; i < len.count + 1; i++) { - for(int j = 0; j < length; j++) { + for (u32 i = 0; i < len.count + 1; i++) { + for(u32 j = 0; j < length; j++) { if constexpr (isDRAMdest) { dst[dram_address + j] = src[(mem_address + j) & 0xFFF]; } else { diff --git a/src/backend/core/mem/Flash.cpp b/src/backend/core/mem/Flash.cpp index 8bc81f0c..84c67891 100644 --- a/src/backend/core/mem/Flash.cpp +++ b/src/backend/core/mem/Flash.cpp @@ -48,7 +48,7 @@ void Flash::CommandExecute() { case FlashState::Erase: if(saveData.is_mapped()) { for (int i = 0; i < 128; i++) { - saveData[eraseOffs + i] = 0xFF; + saveData[eraseOffs + i] = 0xFFi8; } } else { Util::panic("Accessing flash when not mapped!"); diff --git a/src/backend/core/mmio/MI.hpp b/src/backend/core/mmio/MI.hpp index c8b5b04a..1dad8bba 100644 --- a/src/backend/core/mmio/MI.hpp +++ b/src/backend/core/mmio/MI.hpp @@ -24,7 +24,7 @@ struct MI { [[nodiscard]] auto Read(u32) const -> u32; void Write(Registers& regs, u32, u32); - u32 miMode; + u32 miMode{}; MIIntr miIntr{}, miIntrMask{}; }; } \ No newline at end of file diff --git a/src/backend/core/mmio/PI.cpp b/src/backend/core/mmio/PI.cpp index acf5077d..50c59f1c 100644 --- a/src/backend/core/mmio/PI.cpp +++ b/src/backend/core/mmio/PI.cpp @@ -464,7 +464,7 @@ void PI::Write(Mem& mem, Registers& regs, u32 addr, u32 val) { cartAddrInternal = SREGION_PI_SRAM | ((cartAddrInternal & 0xFFFFF) << 1); } - for(int i = 0; i < len; i++) { + for(u32 i = 0; i < len; i++) { mem.mmio.rdp.rdram[BYTE_ADDRESS(dramAddrInternal + i) & RDRAM_DSIZE] = BusRead(mem, cartAddrInternal + i); } dmaBusy = true; diff --git a/src/backend/core/mmio/PI.hpp b/src/backend/core/mmio/PI.hpp index 8440a4fe..b1befbf5 100644 --- a/src/backend/core/mmio/PI.hpp +++ b/src/backend/core/mmio/PI.hpp @@ -12,17 +12,20 @@ struct PI { void Reset(); auto Read(MI&, u32) const -> u32; void Write(Mem&, Registers&, u32, u32); - template - auto BusRead(Mem&, u32) -> T; + template void BusWrite(Mem&, u32, T); + + template + auto BusRead(Mem&, u32) -> T; + bool ReadLatch(); bool WriteLatch(u32 val); static u8 GetDomain(u32 address); - u32 AccessTiming(u8 domain, u32 length) const; + [[nodiscard]] u32 AccessTiming(u8 domain, u32 length) const; bool dmaBusy{}, ioBusy{}, toCart{}; - u32 latch; + u32 latch{}; u32 dramAddr{}, cartAddr{}, dramAddrInternal{}, cartAddrInternal{}; u32 rdLen{}, wrLen{}; u32 pi_bsd_dom1_lat{}, pi_bsd_dom2_lat{}; diff --git a/src/backend/core/mmio/PIF/Device.cpp b/src/backend/core/mmio/PIF/Device.cpp index 77234255..8c02d470 100644 --- a/src/backend/core/mmio/PIF/Device.cpp +++ b/src/backend/core/mmio/PIF/Device.cpp @@ -103,7 +103,7 @@ void PIF::PollController() { joybusDevices[channel].controller.c_left = state[SDL_SCANCODE_J]; joybusDevices[channel].controller.c_right = state[SDL_SCANCODE_L]; - s16 xaxis = 0, yaxis = 0; + s8 xaxis = 0, yaxis = 0; if (state[SDL_SCANCODE_LEFT]) { xaxis = -86; } else if (state[SDL_SCANCODE_RIGHT]) { diff --git a/src/backend/core/mmio/SI.cpp b/src/backend/core/mmio/SI.cpp index f18491e6..46acc6cd 100644 --- a/src/backend/core/mmio/SI.cpp +++ b/src/backend/core/mmio/SI.cpp @@ -32,7 +32,7 @@ auto SI::Read(MI& mi, u32 addr) const -> u32 { } } -void SI::DMA(Mem& mem, Registers& regs) { +void SI::DMA(Mem& mem, Registers& regs) const { SI& si = mem.mmio.si; si.status.dmaBusy = false; if (toDram) { diff --git a/src/backend/core/mmio/SI.hpp b/src/backend/core/mmio/SI.hpp index cd9a6b2e..e19e642b 100644 --- a/src/backend/core/mmio/SI.hpp +++ b/src/backend/core/mmio/SI.hpp @@ -30,7 +30,7 @@ struct SI { auto Read(MI&, u32) const -> u32; void Write(Mem&, Registers&, u32, u32); - void DMA(Mem&, Registers&); + void DMA(Mem&, Registers&) const; PIF pif; }; diff --git a/src/backend/core/registers/Cop0.hpp b/src/backend/core/registers/Cop0.hpp index ccec09bd..80cc6b96 100644 --- a/src/backend/core/registers/Cop0.hpp +++ b/src/backend/core/registers/Cop0.hpp @@ -214,7 +214,7 @@ struct Cop0 { Cop0(); u32 GetReg32(u8); - u64 GetReg64(u8) const; + [[nodiscard]] u64 GetReg64(u8) const; void SetReg32(u8, u32); void SetReg64(u8, u64); @@ -249,15 +249,15 @@ struct Cop0 { template void decode(T&, u32); FORCE_INLINE u32 GetRandom() { - int val = rand(); - int wired = GetWired(); - int lower, upper; - if(wired > 31) { + u32 val = rand(); + auto wired_ = GetWired(); + u32 lower, upper; + if(wired_ > 31) { lower = 0; upper = 64; } else { - lower = wired; - upper = 32 - wired; + lower = wired_; + upper = 32 - wired_; } val = (val % upper) + lower; @@ -276,15 +276,15 @@ struct Cop0 { || (user_mode && status.ux); } private: - FORCE_INLINE u32 GetWired() { return wired & 0x3F; } - FORCE_INLINE u32 GetCount() { return u32(u64(count >> 1)); } + [[nodiscard]] FORCE_INLINE u32 GetWired() const { return wired & 0x3F; } + [[nodiscard]] FORCE_INLINE u32 GetCount() const { return u32(u64(count >> 1)); } void decodeInterp(Registers&, u32); void decodeJIT(JIT&, u32); void mtc0(Registers&, u32); void dmtc0(Registers&, u32); void mfc0(Registers&, u32); - void dmfc0(Registers&, u32); + void dmfc0(Registers&, u32) const; void eret(Registers&); void tlbr(); diff --git a/src/backend/core/registers/Cop1.hpp b/src/backend/core/registers/Cop1.hpp index c6fe91b7..a4a85434 100644 --- a/src/backend/core/registers/Cop1.hpp +++ b/src/backend/core/registers/Cop1.hpp @@ -39,7 +39,7 @@ union FCR31 { unsigned:14; } __attribute__((__packed__)); - u32 read() const { + [[nodiscard]] u32 read() const { return (fs << 24) | (compare << 23) | (cause << 12) | (enable << 7) | (flag << 2) | rounding_mode; } @@ -101,12 +101,12 @@ struct Cop1 { friend struct Interpreter; friend struct JIT; - void SetCauseUnimplemented(Registers&); - void SetCauseUnderflow(Registers&); - void SetCauseInexact(Registers&); - void SetCauseDivisionByZero(Registers&); - void SetCauseOverflow(Registers&); - void SetCauseInvalid(Registers&); + void SetCauseUnimplemented(); + void SetCauseUnderflow(); + void SetCauseInexact(); + void SetCauseDivisionByZero(); + void SetCauseOverflow(); + void SetCauseInvalid(); private: template auto FGR(Cop0Status&, u32) -> T&; void decodeInterp(Interpreter&, u32); diff --git a/src/backend/core/registers/cop/cop0instructions.cpp b/src/backend/core/registers/cop/cop0instructions.cpp index 7e410d85..9f901eee 100644 --- a/src/backend/core/registers/cop/cop0instructions.cpp +++ b/src/backend/core/registers/cop/cop0instructions.cpp @@ -15,7 +15,7 @@ void Cop0::mfc0(Registers& regs, u32 instr) { regs.gpr[RT(instr)] = s32(GetReg32(RD(instr))); } -void Cop0::dmfc0(Registers& regs, u32 instr) { +void Cop0::dmfc0(Registers& regs, u32 instr) const { regs.gpr[RT(instr)] = s64(GetReg64(RD(instr))); } diff --git a/src/backend/core/registers/cop/cop1instructions.cpp b/src/backend/core/registers/cop/cop1instructions.cpp index be4bc955..519ec31b 100644 --- a/src/backend/core/registers/cop/cop1instructions.cpp +++ b/src/backend/core/registers/cop/cop1instructions.cpp @@ -10,12 +10,12 @@ namespace n64 { template<> auto Cop1::FGR(Cop0Status& status, u32 index) -> s32& { if (status.fr) { return fgr[index].int32; - } - else if (index & 1) { - return fgr[index & ~1].int32h; - } - else { - return fgr[index].int32; + } else { + if (index & 1) { + return fgr[index & ~1].int32h; + } else { + return fgr[index].int32; + } } } @@ -26,20 +26,19 @@ template<> auto Cop1::FGR(Cop0Status& status, u32 index) -> u32& { template<> auto Cop1::FGR(Cop0Status& status, u32 index) -> float& { if (status.fr) { return fgr[index].float32; - } - else if (index & 1) { - return fgr[index & ~1].float32h; - } - else { - return fgr[index & ~1].float32; + } else { + if (index & 1) { + return fgr[index & ~1].float32h; + } else { + return fgr[index].float32; + } } } template<> auto Cop1::FGR(Cop0Status& status, u32 index) -> s64& { if (status.fr) { return fgr[index].int64; - } - else { + } else { return fgr[index & ~1].int64; } } @@ -51,8 +50,7 @@ template<> auto Cop1::FGR(Cop0Status& status, u32 index) -> u64& { template<> auto Cop1::FGR(Cop0Status& status, u32 index) -> double& { if (status.fr) { return fgr[index].float64; - } - else { + } else { return fgr[index & ~1].float64; } } @@ -82,42 +80,42 @@ FORCE_INLINE int PushRoundingMode(const FCR31& fcr31) { return og; } -void Cop1::SetCauseUnimplemented(Registers& regs) { - regs.cop1.fcr31.cause_unimplemented_operation = true; +void Cop1::SetCauseUnimplemented() { + fcr31.cause_unimplemented_operation = true; } -void Cop1::SetCauseUnderflow(Registers& regs) { - regs.cop1.fcr31.cause_underflow = true; - if(!regs.cop1.fcr31.enable_underflow) { - regs.cop1.fcr31.flag_underflow = true; +void Cop1::SetCauseUnderflow() { + fcr31.cause_underflow = true; + if(!fcr31.enable_underflow) { + fcr31.flag_underflow = true; } } -void Cop1::SetCauseInexact(Registers& regs) { - regs.cop1.fcr31.cause_inexact_operation = true; - if(!regs.cop1.fcr31.enable_inexact_operation) { - regs.cop1.fcr31.flag_inexact_operation = true; +void Cop1::SetCauseInexact() { + fcr31.cause_inexact_operation = true; + if(!fcr31.enable_inexact_operation) { + fcr31.flag_inexact_operation = true; } } -void Cop1::SetCauseDivisionByZero(Registers& regs) { - regs.cop1.fcr31.cause_division_by_zero = true; - if(!regs.cop1.fcr31.enable_division_by_zero) { - regs.cop1.fcr31.flag_division_by_zero = true; +void Cop1::SetCauseDivisionByZero() { + fcr31.cause_division_by_zero = true; + if(!fcr31.enable_division_by_zero) { + fcr31.flag_division_by_zero = true; } } -void Cop1::SetCauseOverflow(Registers& regs) { - regs.cop1.fcr31.cause_overflow = true; - if(!regs.cop1.fcr31.enable_overflow) { - regs.cop1.fcr31.flag_overflow = true; +void Cop1::SetCauseOverflow() { + fcr31.cause_overflow = true; + if(!fcr31.enable_overflow) { + fcr31.flag_overflow = true; } } -void Cop1::SetCauseInvalid(Registers& regs) { - regs.cop1.fcr31.cause_invalid_operation = true; - if(!regs.cop1.fcr31.enable_invalid_operation) { - regs.cop1.fcr31.flag_invalid_operation = true; +void Cop1::SetCauseInvalid() { + fcr31.cause_invalid_operation = true; + if(!fcr31.enable_invalid_operation) { + fcr31.flag_invalid_operation = true; } } @@ -144,14 +142,14 @@ FORCE_INLINE void SetCauseByArgWCVT(Registers& regs, T f) { case FP_NAN: case FP_INFINITE: case FP_SUBNORMAL: - regs.cop1.SetCauseUnimplemented(regs); + regs.cop1.SetCauseUnimplemented(); CheckFPUException(); break; case FP_NORMAL: // Check overflow if (f >= 2147483648.0f || f < -2147483648.0f) { - regs.cop1.SetCauseUnimplemented(regs); + regs.cop1.SetCauseUnimplemented(); CheckFPUException(); } break; @@ -167,14 +165,14 @@ FORCE_INLINE void SetCauseByArgLCVT(Registers& regs, T f) { case FP_NAN: case FP_INFINITE: case FP_SUBNORMAL: - regs.cop1.SetCauseUnimplemented(regs); + regs.cop1.SetCauseUnimplemented(); CheckFPUException(); break; case FP_NORMAL: // Check overflow if (f >= 9007199254740992.000000 || f <= -9007199254740992.000000) { - regs.cop1.SetCauseUnimplemented(regs); + regs.cop1.SetCauseUnimplemented(); CheckFPUException(); } break; @@ -194,33 +192,33 @@ FORCE_INLINE void SetFPUCauseRaised(Registers& regs, int raised) { if (raised & FE_UNDERFLOW) { if (!regs.cop1.fcr31.fs || regs.cop1.fcr31.enable_underflow || regs.cop1.fcr31.enable_inexact_operation) { - regs.cop1.SetCauseUnimplemented(regs); + regs.cop1.SetCauseUnimplemented(); return; } else { - regs.cop1.SetCauseUnderflow(regs); + regs.cop1.SetCauseUnderflow(); } } if (raised & FE_INEXACT) { - regs.cop1.SetCauseInexact(regs); + regs.cop1.SetCauseInexact(); } if (raised & FE_DIVBYZERO) { - regs.cop1.SetCauseDivisionByZero(regs); + regs.cop1.SetCauseDivisionByZero(); } if (raised & FE_OVERFLOW) { - regs.cop1.SetCauseOverflow(regs); + regs.cop1.SetCauseOverflow(); } if (raised & FE_INVALID) { - regs.cop1.SetCauseInvalid(regs); + regs.cop1.SetCauseInvalid(); } } FORCE_INLINE void SetFPUCauseCVTRaised(Registers& regs, int raised) { if(raised & FE_INVALID) { - regs.cop1.SetCauseUnimplemented(regs); + regs.cop1.SetCauseUnimplemented(); return; } @@ -251,15 +249,15 @@ FORCE_INLINE void SetCauseByArg(Registers& regs, T f) { switch(c) { case FP_NAN: if(isqnan(f)) { - regs.cop1.SetCauseInvalid(regs); + regs.cop1.SetCauseInvalid(); CheckFPUException(); } else { - regs.cop1.SetCauseUnimplemented(regs); + regs.cop1.SetCauseUnimplemented(); CheckFPUException(); } break; case FP_SUBNORMAL: - regs.cop1.SetCauseUnimplemented(regs); + regs.cop1.SetCauseUnimplemented(); CheckFPUException(); break; case FP_INFINITE: @@ -293,12 +291,12 @@ FORCE_INLINE void SetCauseOnResult(Registers& regs, T& d) { break; case FP_SUBNORMAL: if (!cop1.fcr31.fs || cop1.fcr31.enable_underflow || cop1.fcr31.enable_inexact_operation) { - regs.cop1.SetCauseUnimplemented(regs); + regs.cop1.SetCauseUnimplemented(); CheckFPUException(); } else { // Since the if statement checks for the corresponding enable bits, it's safe to turn these cause bits on here. - regs.cop1.SetCauseUnderflow(regs); - regs.cop1.SetCauseInexact(regs); + regs.cop1.SetCauseUnderflow(); + regs.cop1.SetCauseInexact(); switch (cop1.fcr31.rounding_mode) { case 0: case 1: @@ -333,7 +331,7 @@ FORCE_INLINE void SetCauseOnResult(Registers& regs, T& d) { #define CheckResult(f) do { SetCauseOnResult(regs, (f)); CheckFPUException(); } while(0) #define any_unordered(fs, ft) (std::isnan(fs) || std::isnan(ft)) -#define CheckRound(a, b) do { if ((a) != (b)) { SetCauseInexact(regs); } CheckFPUException(); } while(0) +#define CheckRound(a, b) do { if ((a) != (b)) { SetCauseInexact(); } CheckFPUException(); } while(0) template FORCE_INLINE bool is_nan(T f) { @@ -350,14 +348,14 @@ FORCE_INLINE bool is_nan(T f) { #define checknanregs(fs, ft) do { \ if(is_nan(fs) || is_nan(ft)) { \ - regs.cop1.SetCauseInvalid(regs); \ + regs.cop1.SetCauseInvalid(); \ CheckFPUException(); \ } \ } while(0) #define checkqnanregs(fs, ft) do { \ if(isqnan(fs) || isqnan(ft)) { \ - regs.cop1.SetCauseInvalid(regs); \ + regs.cop1.SetCauseInvalid(); \ CheckFPUException(); \ } \ } while(0) @@ -488,7 +486,7 @@ void Cop1::cvtsl(Registers& regs, u32 instr) { CheckFPUUsable(); auto fs = FGR(regs.cop0.status, FS(instr)); if (fs >= s64(0x0080000000000000) || fs < s64(0xff80000000000000)) { - SetCauseUnimplemented(regs); + SetCauseUnimplemented(); CheckFPUException(); } float result; @@ -547,7 +545,7 @@ void Cop1::cvtdl(Registers& regs, u32 instr) { auto fs = FGR(regs.cop0.status, FS(instr)); if (fs >= s64(0x0080000000000000) || fs < s64(0xff80000000000000)) { - SetCauseUnimplemented(regs); + SetCauseUnimplemented(); CheckFPUException(); } double result; diff --git a/src/frontend/imgui/Settings.hpp b/src/frontend/imgui/Settings.hpp index c076932d..365c3b32 100644 --- a/src/frontend/imgui/Settings.hpp +++ b/src/frontend/imgui/Settings.hpp @@ -6,7 +6,7 @@ namespace n64 { struct Core; } using namespace nlohmann; struct Settings { - Settings(n64::Core& core); + explicit Settings(n64::Core& core); ~Settings(); [[nodiscard]] FORCE_INLINE float GetVolumeL() const { return volumeL; }; diff --git a/src/utils/MemoryHelpers.hpp b/src/utils/MemoryHelpers.hpp index dd3f3bd9..a08221a2 100644 --- a/src/utils/MemoryHelpers.hpp +++ b/src/utils/MemoryHelpers.hpp @@ -6,14 +6,14 @@ namespace Util { template -static FORCE_INLINE T ReadAccess(u8 *data, u32 index) { +static FORCE_INLINE T ReadAccess(const u8 *data, u32 index) { if constexpr (sizeof(T) == 8) { - u32 hi = *reinterpret_cast(&data[index + 0]); - u32 lo = *reinterpret_cast(&data[index + 4]); + u32 hi = *reinterpret_cast(&data[index + 0]); + u32 lo = *reinterpret_cast(&data[index + 4]); T result = ((T)hi << 32) | (T)lo; return result; } else { - return *reinterpret_cast(&data[index]); + return *reinterpret_cast(&data[index]); } } @@ -31,14 +31,14 @@ static FORCE_INLINE void WriteAccess(u8 *data, u32 index, T val) { } FORCE_INLINE void SwapBuffer32(size_t size, u8 *data) { - for (int i = 0; i < size; i += 4) { + for (size_t i = 0; i < size; i += 4) { u32 original = *(u32 *) &data[i]; *(u32 *) &data[i] = bswap_32(original); } } FORCE_INLINE void SwapBuffer16(size_t size, u8 *data) { - for (int i = 0; i < size; i += 2) { + for (size_t i = 0; i < size; i += 2) { u16 original = *(u16 *) &data[i]; *(u16 *) &data[i] = bswap_16(original); } From 57a079392e5f9db130b580116c51580be1bc1dfe Mon Sep 17 00:00:00 2001 From: SimoneN64 Date: Thu, 4 Jan 2024 02:03:52 +0100 Subject: [PATCH 15/20] PI fixes and various smaller fixes --- src/backend/Scheduler.cpp | 2 - src/backend/core/Mem.cpp | 16 +++-- src/backend/core/mem/Flash.cpp | 4 +- src/backend/core/mmio/PI.cpp | 66 +++++++++---------- src/backend/core/mmio/PI.hpp | 4 +- src/backend/core/mmio/SI.cpp | 4 +- src/backend/core/registers/Cop1.hpp | 1 + .../core/registers/cop/cop1instructions.cpp | 22 ++++--- 8 files changed, 63 insertions(+), 56 deletions(-) diff --git a/src/backend/Scheduler.cpp b/src/backend/Scheduler.cpp index 80fc7b9c..19b686cd 100644 --- a/src/backend/Scheduler.cpp +++ b/src/backend/Scheduler.cpp @@ -34,9 +34,7 @@ void Scheduler::tick(u64 t, n64::Mem& mem, n64::Registers& regs) { while(ticks >= events.top().time) { switch(auto type = events.top().type) { case SI_DMA: - si.status.dmaBusy = false; si.DMA(mem, regs); - InterruptRaise(mi, regs, n64::Interrupt::SI); break; case PI_DMA_COMPLETE: InterruptRaise(mi, regs, n64::Interrupt::PI); diff --git a/src/backend/core/Mem.cpp b/src/backend/core/Mem.cpp index eab71c2d..4657075c 100644 --- a/src/backend/core/Mem.cpp +++ b/src/backend/core/Mem.cpp @@ -368,7 +368,7 @@ template<> void Mem::Write(Registers& regs, u32 paddr, u32 val) { } } break; case REGION_CART: - Util::debug("BusWrite @ {:08X} = {:02X}", paddr, val); + Util::trace("BusWrite @ {:08X} = {:02X}", paddr, val); mmio.pi.BusWrite(*this, paddr, val); break; case MMIO_REGION: @@ -417,7 +417,7 @@ template<> void Mem::Write(Registers& regs, u32 paddr, u32 val) { } } break; case REGION_CART: - Util::debug("BusWrite @ {:08X} = {:04X}", paddr, val); + Util::trace("BusWrite @ {:08X} = {:04X}", paddr, val); mmio.pi.BusWrite(*this, paddr, val); break; case MMIO_REGION: @@ -464,7 +464,7 @@ template<> void Mem::Write(Registers& regs, u32 paddr, u32 val) { } } break; case REGION_CART: - Util::debug("BusWrite @ {:08X} = {:08X}", paddr, val); + Util::trace("BusWrite @ {:08X} = {:08X}", paddr, val); mmio.pi.BusWrite(*this, paddr, val); break; case MMIO_REGION: @@ -508,8 +508,8 @@ void Mem::Write(Registers& regs, u32 paddr, u64 val) { } } break; case REGION_CART: - Util::debug("BusWrite @ {:08X} = {:016X}", paddr, val); - mmio.pi.BusWrite(*this, paddr, val); + Util::trace("BusWrite @ {:08X} = {:016X}", paddr, val); + mmio.pi.BusWrite(*this, paddr, val); break; case MMIO_REGION: Util::panic("MMIO Write!"); @@ -569,7 +569,8 @@ template <> u8 Mem::BackupRead(u32 addr) { template <> void Mem::BackupWrite(u32 addr, u32 val) { switch(saveType) { case SAVE_NONE: - Util::panic("Accessing cartridge with save type SAVE_NONE in write word"); + Util::warn("Accessing cartridge with save type SAVE_NONE in write word"); + break; case SAVE_EEPROM_4k: case SAVE_EEPROM_16k: Util::panic("Accessing cartridge with save type SAVE_EEPROM in write word"); case SAVE_FLASH_1m: @@ -585,7 +586,8 @@ template <> void Mem::BackupWrite(u32 addr, u32 val) { template <> void Mem::BackupWrite(u32 addr, u8 val) { switch(saveType) { case SAVE_NONE: - Util::panic("Accessing cartridge with save type SAVE_NONE in write word"); + Util::warn("Accessing cartridge with save type SAVE_NONE in write word"); + break; case SAVE_EEPROM_4k: case SAVE_EEPROM_16k: Util::panic("Accessing cartridge with save type SAVE_EEPROM in write word"); case SAVE_FLASH_1m: diff --git a/src/backend/core/mem/Flash.cpp b/src/backend/core/mem/Flash.cpp index 84c67891..9718dd79 100644 --- a/src/backend/core/mem/Flash.cpp +++ b/src/backend/core/mem/Flash.cpp @@ -1,4 +1,5 @@ #include +#include namespace n64 { constexpr auto FLASH_SIZE = 1_mb; @@ -159,10 +160,11 @@ template <> void Flash::Write(u32 index, u8 val) { case FlashState::Idle: Util::panic("Invalid FlashState::Idle with Write"); case FlashState::Status: Util::panic("Invalid FlashState::Status with Write"); case FlashState::Erase: Util::panic("Invalid FlashState::Erase with Write"); + case FlashState::Read: Util::panic("Invalid FlashState::Read with Write"); case FlashState::Write: + assert(index <= 0x7F && "Out of range flash Write8"); writeBuf[index] = val; break; - case FlashState::Read: Util::panic("Invalid FlashState::Read with Write"); default: Util::warn("Invalid flash state on Write: {:02X}", static_cast(state)); } } diff --git a/src/backend/core/mmio/PI.cpp b/src/backend/core/mmio/PI.cpp index 50c59f1c..8eb916ff 100644 --- a/src/backend/core/mmio/PI.cpp +++ b/src/backend/core/mmio/PI.cpp @@ -62,7 +62,7 @@ template<> auto PI::BusRead(Mem& mem, u32 addr) -> u8 { case REGION_PI_ROM: { // round to nearest 4 byte boundary, keeping old LSB u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM; - if (index > mem.rom.size) { + if (index >= mem.rom.size) { Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr, index, index, mem.rom.size, mem.rom.size); return 0xFF; } @@ -92,7 +92,7 @@ template<> auto PI::BusRead(Mem& mem, u32 addr) -> u8 { addr = (addr + 2) & ~2; // round to nearest 4 byte boundary, keeping old LSB u32 index = BYTE_ADDRESS(addr) - SREGION_PI_ROM; - if (index > mem.rom.size) { + if (index >= mem.rom.size) { Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM! ({}/0x{:016X})", addr, index, index, mem.rom.size, mem.rom.size); return 0xFF; } @@ -103,33 +103,32 @@ template<> auto PI::BusRead(Mem& mem, u32 addr) -> u8 { } } -template<> void PI::BusWrite(Mem& mem, u32 addr, u8 val) { +template<> void PI::BusWrite(Mem& mem, u32 addr, u32 val) { switch (addr) { - case REGION_PI_UNKNOWN: - Util::panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); - case REGION_PI_64DD_REG: - if (addr == 0x05000020) { - fprintf(stderr, "%c", val); - } - else { - Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val, addr); - } - return; - case REGION_PI_64DD_ROM: - Util::panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr); - case REGION_PI_SRAM: - mem.BackupWrite(addr - SREGION_PI_SRAM, val); - return; - case REGION_PI_ROM: - Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); - return; - default: - Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); + case REGION_PI_UNKNOWN: + Util::panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_UNKNOWN", val, addr); + case REGION_PI_64DD_REG: + if (addr == 0x05000020) { + fprintf(stderr, "%c", val); + } else { + Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in region: REGION_PI_64DD_ROM, this is the 64DD, ignoring!", val, addr); + } + break; + case REGION_PI_64DD_ROM: + Util::panic("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_64DD_ROM", val, addr); + case REGION_PI_SRAM: + mem.BackupWrite(addr - SREGION_PI_SRAM, val); + break; + case REGION_PI_ROM: + Util::warn("Writing byte 0x{:02X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); + break; + default: + Util::panic("Should never end up here! Access to address {:08X} which did not match any PI bus regions!", addr); } } -template<> void PI::BusWrite(Mem& mem, u32 addr, u8 val) { - int latch_shift = 24 - (addr & 1) * 8; +template<> void PI::BusWrite(Mem& mem, u32 addr, u32 val) { + u8 latch_shift = 24 - (addr & 1) * 8; if (!WriteLatch(val << latch_shift) && addr != 0x05000020) [[unlikely]] { return; @@ -169,7 +168,7 @@ template <> auto PI::BusRead(Mem& mem, u32 addr) -> u16 { return BusRead(mem, addr); } -template <> void PI::BusWrite(Mem&, u32 addr, u16 val) { +template <> void PI::BusWrite(Mem&, u32 addr, u32 val) { if (!WriteLatch(val << 16)) [[unlikely]] { return; } @@ -191,7 +190,7 @@ template <> void PI::BusWrite(Mem&, u32 addr, u16 val) { } } -template <> void PI::BusWrite(Mem& mem, u32 addr, u16 val) { +template <> void PI::BusWrite(Mem& mem, u32 addr, u32 val) { BusWrite(mem, addr, val); } @@ -220,8 +219,7 @@ template <> auto PI::BusRead(Mem& mem, u32 addr) -> u32 { return htobe32(Util::ReadAccess(mem.isviewer, addr - SREGION_CART_ISVIEWER_BUFFER)); case CART_ISVIEWER_FLUSH: Util::panic("Read from ISViewer flush!"); - default: - Util::panic("Read from unknown address {:08X} in REGION_PI_ROM!", addr); + default: break; } Util::warn("Address 0x{:08X} accessed an index {}/0x{:X} outside the bounds of the ROM!", addr, index, index); return 0; @@ -283,6 +281,7 @@ template <> void PI::BusWrite(Mem& mem, u32 addr, u32 val) { } default: if (!WriteLatch(val)) [[unlikely]] { + Util::warn("Couldn't latch PI bus, ignoring write to REGION_PI_ROM"); return; } Util::warn("Writing word 0x{:08X} to address 0x{:08X} in unsupported region: REGION_PI_ROM", val, addr); @@ -293,7 +292,8 @@ template <> void PI::BusWrite(Mem& mem, u32 addr, u32 val) { } } -template <> void PI::BusWrite(Mem& mem, u32 addr, u32 val) { +template <> +void PI::BusWrite(Mem& mem, u32 addr, u32 val) { BusWrite(mem, addr, val); } @@ -327,7 +327,7 @@ template <> auto PI::BusRead(Mem& mem, u32 addr) -> u64 { return BusRead(mem, addr); } -template <> void PI::BusWrite(Mem&, u32 addr, u64 val) { +template <> void PI::BusWrite(Mem&, u32 addr, u64 val) { if (!WriteLatch(val >> 32)) [[unlikely]] { return; } @@ -349,8 +349,8 @@ template <> void PI::BusWrite(Mem&, u32 addr, u64 val) { } } -template <> void PI::BusWrite(Mem& mem, u32 addr, u64 val) { - BusWrite(mem, addr, val); +template <> void PI::BusWrite(Mem& mem, u32 addr, u64 val) { + BusWrite(mem, addr, val); } auto PI::Read(MI& mi, u32 addr) const -> u32 { diff --git a/src/backend/core/mmio/PI.hpp b/src/backend/core/mmio/PI.hpp index b1befbf5..8577509a 100644 --- a/src/backend/core/mmio/PI.hpp +++ b/src/backend/core/mmio/PI.hpp @@ -14,7 +14,9 @@ struct PI { void Write(Mem&, Registers&, u32, u32); template - void BusWrite(Mem&, u32, T); + void BusWrite(Mem&, u32, u32); + template + void BusWrite(Mem&, u32, u64); template auto BusRead(Mem&, u32) -> T; diff --git a/src/backend/core/mmio/SI.cpp b/src/backend/core/mmio/SI.cpp index 46acc6cd..8a0814d8 100644 --- a/src/backend/core/mmio/SI.cpp +++ b/src/backend/core/mmio/SI.cpp @@ -40,12 +40,12 @@ void SI::DMA(Mem& mem, Registers& regs) const { for(int i = 0; i < 64; i++) { mem.mmio.rdp.rdram[BYTE_ADDRESS(si.dramAddr + i)] = si.pif.Read(si.pifAddr + i); } - //Util::debug("SI DMA from PIF RAM to RDRAM ({:08X} to {:08X})", si.pifAddr, si.dramAddr); + Util::trace("SI DMA from PIF RAM to RDRAM ({:08X} to {:08X})", si.pifAddr, si.dramAddr); } else { for(int i = 0; i < 64; i++) { si.pif.Write(si.pifAddr + i, mem.mmio.rdp.rdram[BYTE_ADDRESS(si.dramAddr + i)]); } - //Util::debug("SI DMA from RDRAM to PIF RAM ({:08X} to {:08X})", si.dramAddr, si.pifAddr); + Util::trace("SI DMA from RDRAM to PIF RAM ({:08X} to {:08X})", si.dramAddr, si.pifAddr); si.pif.ProcessCommands(mem); } InterruptRaise(mem.mmio.mi, regs, Interrupt::SI); diff --git a/src/backend/core/registers/Cop1.hpp b/src/backend/core/registers/Cop1.hpp index a4a85434..93203850 100644 --- a/src/backend/core/registers/Cop1.hpp +++ b/src/backend/core/registers/Cop1.hpp @@ -107,6 +107,7 @@ struct Cop1 { void SetCauseDivisionByZero(); void SetCauseOverflow(); void SetCauseInvalid(); + int fp_class=0; private: template auto FGR(Cop0Status&, u32) -> T&; void decodeInterp(Interpreter&, u32); diff --git a/src/backend/core/registers/cop/cop1instructions.cpp b/src/backend/core/registers/cop/cop1instructions.cpp index 519ec31b..740aa2ec 100644 --- a/src/backend/core/registers/cop/cop1instructions.cpp +++ b/src/backend/core/registers/cop/cop1instructions.cpp @@ -121,7 +121,7 @@ void Cop1::SetCauseInvalid() { #define PUSHROUNDING int orig_round = PushRoundingMode(fcr31) #define POPROUNDING fesetround(orig_round) -#define OP_CheckExcept(op) do { PUSHROUNDING; feclearexcept(FE_ALL_EXCEPT); op; SetFPUCauseRaised(regs, fetestexcept(FE_ALL_EXCEPT)); POPROUNDING; } while(0) +#define OP_CheckExcept(op) do { feclearexcept(FE_ALL_EXCEPT); PUSHROUNDING; op; SetFPUCauseRaised(regs, fetestexcept(FE_ALL_EXCEPT)); POPROUNDING; } while(0) #define CVT_OP_CheckExcept(op) do { feclearexcept(FE_ALL_EXCEPT); op; SetFPUCauseCVTRaised(regs, fetestexcept(FE_ALL_EXCEPT)); CheckFPUException(); } while(0) #define OP(T, op) do { \ @@ -138,7 +138,8 @@ void Cop1::SetCauseInvalid() { template FORCE_INLINE void SetCauseByArgWCVT(Registers& regs, T f) { - switch (std::fpclassify(f)) { + regs.cop1.fp_class = std::fpclassify(f); + switch (regs.cop1.fp_class) { case FP_NAN: case FP_INFINITE: case FP_SUBNORMAL: @@ -161,7 +162,8 @@ FORCE_INLINE void SetCauseByArgWCVT(Registers& regs, T f) { template FORCE_INLINE void SetCauseByArgLCVT(Registers& regs, T f) { - switch (std::fpclassify(f)) { + regs.cop1.fp_class = std::fpclassify(f); + switch (regs.cop1.fp_class) { case FP_NAN: case FP_INFINITE: case FP_SUBNORMAL: @@ -190,7 +192,7 @@ FORCE_INLINE void SetFPUCauseRaised(Registers& regs, int raised) { return; } - if (raised & FE_UNDERFLOW) { + if (((raised & FE_UNDERFLOW) != 0) || regs.cop1.fp_class == FP_SUBNORMAL) { if (!regs.cop1.fcr31.fs || regs.cop1.fcr31.enable_underflow || regs.cop1.fcr31.enable_inexact_operation) { regs.cop1.SetCauseUnimplemented(); return; @@ -245,8 +247,8 @@ FORCE_INLINE bool isqnan(T f) { template FORCE_INLINE void SetCauseByArg(Registers& regs, T f) { - int c = std::fpclassify(f); - switch(c) { + regs.cop1.fp_class = std::fpclassify(f); + switch(regs.cop1.fp_class) { case FP_NAN: if(isqnan(f)) { regs.cop1.SetCauseInvalid(); @@ -265,7 +267,7 @@ FORCE_INLINE void SetCauseByArg(Registers& regs, T f) { case FP_NORMAL: break; // No-op, these are fine. default: - Util::panic("Unknown floating point classification: {}", c); + Util::panic("Unknown floating point classification: {}", regs.cop1.fp_class); } } @@ -274,7 +276,7 @@ FORCE_INLINE void SetCauseByArg(Registers& regs, T f) { template FORCE_INLINE void SetCauseOnResult(Registers& regs, T& d) { Cop1& cop1 = regs.cop1; - int classification = std::fpclassify(d); + regs.cop1.fp_class = std::fpclassify(d); T magic, min; if constexpr(std::is_same_v) { u32 c = 0x7FBFFFFF; @@ -285,7 +287,7 @@ FORCE_INLINE void SetCauseOnResult(Registers& regs, T& d) { magic = U64_TO_D(c); min = DBL_MIN; } - switch (classification) { + switch (regs.cop1.fp_class) { case FP_NAN: d = magic; // set result to sNAN break; @@ -324,7 +326,7 @@ FORCE_INLINE void SetCauseOnResult(Registers& regs, T& d) { case FP_NORMAL: break; // No-op, these are fine. default: - Util::panic("Unknown FP classification: {}", classification); + Util::panic("Unknown FP classification: {}", regs.cop1.fp_class); } } From 6b84ca576d1e6f2368e3c0cf9408ad586f717694 Mon Sep 17 00:00:00 2001 From: SimoneN64 Date: Thu, 4 Jan 2024 02:41:22 +0100 Subject: [PATCH 16/20] small cleaning --- .gitignore | 2 +- src/backend/core/mem/Flash.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 99803463..3ac25b94 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,7 @@ vgcore.* *.dump *.data disasm.txt -log.txt +*log.txt .vs/ CMakeSettings.json out/ diff --git a/src/backend/core/mem/Flash.cpp b/src/backend/core/mem/Flash.cpp index 9718dd79..d6ff50f7 100644 --- a/src/backend/core/mem/Flash.cpp +++ b/src/backend/core/mem/Flash.cpp @@ -42,7 +42,7 @@ void Flash::Load(SaveType saveType, const std::string& path) { } void Flash::CommandExecute() { - Util::debug("Flash::CommandExecute"); + Util::trace("Flash::CommandExecute"); switch (state) { case FlashState::Idle: break; @@ -176,7 +176,7 @@ template <> u8 Flash::Read(u32 index) const { case FlashState::Read: { if(saveData.is_mapped()) { u8 value = saveData[index]; - Util::debug("Flash read byte in state read: index {:08X} = {:02X}", index, value); + Util::trace("Flash read byte in state read: index {:08X} = {:02X}", index, value); return value; } else { Util::panic("Accessing flash when not mapped!"); @@ -185,7 +185,7 @@ template <> u8 Flash::Read(u32 index) const { case FlashState::Status: { u32 offset = (7 - (index % 8)) * 8; u8 value = (status >> offset) & 0xFF; - Util::debug("Flash read byte in state status: index {:08X} = {:02X}", index, value); + Util::trace("Flash read byte in state status: index {:08X} = {:02X}", index, value); return value; } default: Util::panic("Flash read byte while in unknown state"); From dcf223c150197d1dd9276c06e73783d99825cf71 Mon Sep 17 00:00:00 2001 From: SimoneN64 Date: Wed, 10 Jan 2024 20:59:51 +0100 Subject: [PATCH 17/20] revert these --- src/backend/core/registers/Cop1.hpp | 4 ++-- .../core/registers/cop/cop1instructions.cpp | 20 +++++++++---------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/backend/core/registers/Cop1.hpp b/src/backend/core/registers/Cop1.hpp index 93203850..053b17da 100644 --- a/src/backend/core/registers/Cop1.hpp +++ b/src/backend/core/registers/Cop1.hpp @@ -107,9 +107,9 @@ struct Cop1 { void SetCauseDivisionByZero(); void SetCauseOverflow(); void SetCauseInvalid(); - int fp_class=0; private: - template auto FGR(Cop0Status&, u32) -> T&; + template + auto FGR(Cop0Status&, u32) -> T&; void decodeInterp(Interpreter&, u32); void decodeJIT(JIT&, u32); void absd(Registers&, u32 instr); diff --git a/src/backend/core/registers/cop/cop1instructions.cpp b/src/backend/core/registers/cop/cop1instructions.cpp index 740aa2ec..6138e5b7 100644 --- a/src/backend/core/registers/cop/cop1instructions.cpp +++ b/src/backend/core/registers/cop/cop1instructions.cpp @@ -138,8 +138,7 @@ void Cop1::SetCauseInvalid() { template FORCE_INLINE void SetCauseByArgWCVT(Registers& regs, T f) { - regs.cop1.fp_class = std::fpclassify(f); - switch (regs.cop1.fp_class) { + switch (std::fpclassify(f)) { case FP_NAN: case FP_INFINITE: case FP_SUBNORMAL: @@ -162,8 +161,7 @@ FORCE_INLINE void SetCauseByArgWCVT(Registers& regs, T f) { template FORCE_INLINE void SetCauseByArgLCVT(Registers& regs, T f) { - regs.cop1.fp_class = std::fpclassify(f); - switch (regs.cop1.fp_class) { + switch (std::fpclassify(f)) { case FP_NAN: case FP_INFINITE: case FP_SUBNORMAL: @@ -192,7 +190,7 @@ FORCE_INLINE void SetFPUCauseRaised(Registers& regs, int raised) { return; } - if (((raised & FE_UNDERFLOW) != 0) || regs.cop1.fp_class == FP_SUBNORMAL) { + if (raised & FE_UNDERFLOW) { if (!regs.cop1.fcr31.fs || regs.cop1.fcr31.enable_underflow || regs.cop1.fcr31.enable_inexact_operation) { regs.cop1.SetCauseUnimplemented(); return; @@ -247,8 +245,8 @@ FORCE_INLINE bool isqnan(T f) { template FORCE_INLINE void SetCauseByArg(Registers& regs, T f) { - regs.cop1.fp_class = std::fpclassify(f); - switch(regs.cop1.fp_class) { + auto fp_class = std::fpclassify(f); + switch(fp_class) { case FP_NAN: if(isqnan(f)) { regs.cop1.SetCauseInvalid(); @@ -267,7 +265,7 @@ FORCE_INLINE void SetCauseByArg(Registers& regs, T f) { case FP_NORMAL: break; // No-op, these are fine. default: - Util::panic("Unknown floating point classification: {}", regs.cop1.fp_class); + Util::panic("Unknown floating point classification: {}", fp_class); } } @@ -276,7 +274,7 @@ FORCE_INLINE void SetCauseByArg(Registers& regs, T f) { template FORCE_INLINE void SetCauseOnResult(Registers& regs, T& d) { Cop1& cop1 = regs.cop1; - regs.cop1.fp_class = std::fpclassify(d); + auto fp_class = std::fpclassify(d); T magic, min; if constexpr(std::is_same_v) { u32 c = 0x7FBFFFFF; @@ -287,7 +285,7 @@ FORCE_INLINE void SetCauseOnResult(Registers& regs, T& d) { magic = U64_TO_D(c); min = DBL_MIN; } - switch (regs.cop1.fp_class) { + switch (fp_class) { case FP_NAN: d = magic; // set result to sNAN break; @@ -326,7 +324,7 @@ FORCE_INLINE void SetCauseOnResult(Registers& regs, T& d) { case FP_NORMAL: break; // No-op, these are fine. default: - Util::panic("Unknown FP classification: {}", regs.cop1.fp_class); + Util::panic("Unknown FP classification: {}", fp_class); } } From deb83f3695faba6f629a4c42f36dc868a6986a4d Mon Sep 17 00:00:00 2001 From: SimoneN64 Date: Thu, 4 Jan 2024 02:51:31 +0100 Subject: [PATCH 18/20] avoid enabling sse if not supported --- CMakeLists.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 05a15432..b8b7bb6f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,16 @@ if(WIN32) add_definitions(-DNOMINMAX) add_definitions(-D_CRT_SECURE_NO_WARNINGS) endif () -add_compile_options(-mssse3 -msse4.1) + +include(CheckCCompilerFlag) + +check_c_compiler_flag(-mssse3 HAS_SSSE3) +check_c_compiler_flag(-msse4.1 HAS_SSE4_1) + +if (HAS_SSSE3 AND HAS_SSE4_1) + add_compile_options(-mssse3 -msse4.1) +endif () + if(${CMAKE_BUILD_TYPE} MATCHES Debug) #add_compile_options(-fsanitize=address -fsanitize=undefined) #add_link_options(-fsanitize=address -fsanitize=undefined) From ee1fd7baf318709eebb22555e21f8aeae4cd3759 Mon Sep 17 00:00:00 2001 From: Simone Date: Tue, 16 Jan 2024 12:15:31 +0100 Subject: [PATCH 19/20] FGR improvements --- src/backend/core/registers/Cop1.hpp | 5 +- .../core/registers/cop/cop1instructions.cpp | 278 ++++++++++-------- src/common.hpp | 6 +- 3 files changed, 169 insertions(+), 120 deletions(-) diff --git a/src/backend/core/registers/Cop1.hpp b/src/backend/core/registers/Cop1.hpp index 053b17da..a42bb4c7 100644 --- a/src/backend/core/registers/Cop1.hpp +++ b/src/backend/core/registers/Cop1.hpp @@ -108,8 +108,9 @@ struct Cop1 { void SetCauseOverflow(); void SetCauseInvalid(); private: - template - auto FGR(Cop0Status&, u32) -> T&; + template auto FGR_T(Cop0Status&, u32) -> T&; + template auto FGR_S(Cop0Status&, u32) -> T&; + template auto FGR_D(Cop0Status&, u32) -> T&; void decodeInterp(Interpreter&, u32); void decodeJIT(JIT&, u32); void absd(Registers&, u32 instr); diff --git a/src/backend/core/registers/cop/cop1instructions.cpp b/src/backend/core/registers/cop/cop1instructions.cpp index 6138e5b7..266d6aec 100644 --- a/src/backend/core/registers/cop/cop1instructions.cpp +++ b/src/backend/core/registers/cop/cop1instructions.cpp @@ -7,7 +7,7 @@ #include namespace n64 { -template<> auto Cop1::FGR(Cop0Status& status, u32 index) -> s32& { +template<> auto Cop1::FGR_T(Cop0Status& status, u32 index) -> s32& { if (status.fr) { return fgr[index].int32; } else { @@ -19,38 +19,86 @@ template<> auto Cop1::FGR(Cop0Status& status, u32 index) -> s32& { } } -template<> auto Cop1::FGR(Cop0Status& status, u32 index) -> u32& { - return (u32&)FGR(status, index); +template<> auto Cop1::FGR_T(Cop0Status& status, u32 index) -> u32& { + return (u32&)FGR_T(status, index); } -template<> auto Cop1::FGR(Cop0Status& status, u32 index) -> float& { +template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> s32& { if (status.fr) { - return fgr[index].float32; + return fgr[index].int32; } else { - if (index & 1) { - return fgr[index & ~1].float32h; - } else { - return fgr[index].float32; - } + return fgr[index & ~1].int32; } } -template<> auto Cop1::FGR(Cop0Status& status, u32 index) -> s64& { +template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> u32& { + return (u32&)FGR_S(status, index); +} + +template<> auto Cop1::FGR_D(Cop0Status& status, u32 index) -> s32& { + fgr[index].int32h = 0; + return fgr[index].int32; +} + +template<> auto Cop1::FGR_T(Cop0Status& status, u32 index) -> float& { + return fgr[index].float32; +} + +template<> auto Cop1::FGR_D(Cop0Status& status, u32 index) -> float& { + fgr[index].float32h = 0; + return fgr[index].float32; +} + +template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> float& { + if (status.fr) { + return fgr[index].float32; + } else { + return fgr[index & ~1].float32; + } +} + +template<> auto Cop1::FGR_T(Cop0Status& status, u32 index) -> s64& { if (status.fr) { return fgr[index].int64; - } else { + } + else { return fgr[index & ~1].int64; } } -template<> auto Cop1::FGR(Cop0Status& status, u32 index) -> u64& { - return (u64&)FGR(status, index); +template<> auto Cop1::FGR_D(Cop0Status&, u32 index) -> s64& { + return fgr[index].int64; } -template<> auto Cop1::FGR(Cop0Status& status, u32 index) -> double& { +template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> s64& { + return FGR_T(status, index); +} + +template<> auto Cop1::FGR_T(Cop0Status& status, u32 index) -> u64& { + return (u64&)FGR_T(status, index); +} + +template<> auto Cop1::FGR_D(Cop0Status& status, u32 index) -> u64& { + return (u64&)FGR_D(status, index); +} + +template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> u64& { + return FGR_T(status, index); +} + +template<> auto Cop1::FGR_T(Cop0Status&, u32 index) -> double& { + return fgr[index].float64; +} + +template<> auto Cop1::FGR_D(Cop0Status& status, u32 index) -> double& { + return FGR_T(status, index); +} + +template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> double& { if (status.fr) { return fgr[index].float64; - } else { + } + else { return fgr[index & ~1].float64; } } @@ -126,14 +174,14 @@ void Cop1::SetCauseInvalid() { #define OP(T, op) do { \ CheckFPUUsable(); \ - auto fs = FGR(regs.cop0.status, FS(instr)); \ - auto ft = FGR(regs.cop0.status, FT(instr)); \ + auto fs = FS(T, instr); \ + auto ft = FT(T, instr); \ CheckArg(fs); \ CheckArg(ft); \ T result; \ OP_CheckExcept({result = (op);}); \ CheckResult(result); \ - FGR(regs.cop0.status, FD(instr)) = result; \ + FD(T, instr) = result; \ } while(0) template @@ -378,42 +426,42 @@ void Cop1::addd(Registers& regs, u32 instr) { void Cop1::ceills(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(float, instr); CheckLCVTArg(fs); s64 result; CVT_OP_CheckExcept({ result = std::ceil(fs); }); CheckRound(fs, result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(s64, instr) = result; } void Cop1::ceilws(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(float, instr); CheckWCVTArg(fs); s32 result; CVT_OP_CheckExcept({ result = std::ceil(fs); }); CheckRound(fs, result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(s32, instr) = result; } void Cop1::ceilld(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(double, instr); CheckLCVTArg(fs); s64 result; CVT_OP_CheckExcept({ result = std::ceil(fs); }); CheckRound(fs, result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(s64, instr) = result; } void Cop1::ceilwd(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(double, instr); CheckWCVTArg(fs); s32 result; CVT_OP_CheckExcept({ result = std::ceil(fs); }); CheckRound(fs, result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(s32, instr) = result; } void Cop1::cfc1(Registers& regs, u32 instr) const { @@ -455,36 +503,36 @@ void Cop1::ctc1(Registers& regs, u32 instr) { void Cop1::cvtds(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(float, instr); CheckArg(fs); double result; OP_CheckExcept({ result = double(fs); }); CheckResult(result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(double, instr) = result; } void Cop1::cvtsd(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(double, instr); CheckArg(fs); float result; OP_CheckExcept({ result = float(fs); }); CheckResult(result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(float, instr) = result; } void Cop1::cvtsw(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(s32, instr); float result; OP_CheckExcept({ result = float(fs); }); CheckResult(result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(float, instr) = result; } void Cop1::cvtsl(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(s64, instr); if (fs >= s64(0x0080000000000000) || fs < s64(0xff80000000000000)) { SetCauseUnimplemented(); CheckFPUException(); @@ -492,57 +540,57 @@ void Cop1::cvtsl(Registers& regs, u32 instr) { float result; OP_CheckExcept({ result = float(fs); }); CheckResult(result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(float, instr) = result; } void Cop1::cvtwd(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(double, instr); CheckWCVTArg(fs); s32 result; PUSHROUNDING; CVT_OP_CheckExcept({ result = std::rint(fs); }); POPROUNDING; CheckRound(fs, result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(s32, instr) = result; } void Cop1::cvtws(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(float, instr); CheckWCVTArg(fs); s32 result; PUSHROUNDING; CVT_OP_CheckExcept({ result = std::rint(fs); }); POPROUNDING; CheckRound(fs, result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(s32, instr) = result; } void Cop1::cvtls(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(float, instr); CheckLCVTArg(fs); s64 result; PUSHROUNDING; CVT_OP_CheckExcept({ result = std::rint(fs); }); POPROUNDING; CheckRound(fs, result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(s64, instr) = result; } void Cop1::cvtdw(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(s32, instr); double result; OP_CheckExcept({ result = double(fs); }); CheckResult(result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(double, instr) = result; } void Cop1::cvtdl(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(s64, instr); if (fs >= s64(0x0080000000000000) || fs < s64(0xff80000000000000)) { SetCauseUnimplemented(); @@ -551,26 +599,26 @@ void Cop1::cvtdl(Registers& regs, u32 instr) { double result; OP_CheckExcept({ result = double(fs); }); CheckResult(result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(double, instr) = result; } void Cop1::cvtld(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(double, instr); CheckLCVTArg(fs); s64 result; PUSHROUNDING; CVT_OP_CheckExcept({ result = std::rint(fs); }); POPROUNDING; CheckRound(fs, result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(s64, instr) = result; } template void Cop1::cf(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FGR(regs.cop0.status, FS(instr)); - T ft = FGR(regs.cop0.status, FT(instr)); + T fs = FS(T, instr); + T ft = FT(T, instr); checkqnanregs(fs, ft); fcr31.compare = false; } @@ -578,8 +626,8 @@ void Cop1::cf(Registers& regs, u32 instr) { template void Cop1::cun(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FGR(regs.cop0.status, FS(instr)); - T ft = FGR(regs.cop0.status, FT(instr)); + T fs = FS(T, instr); + T ft = FT(T, instr); checkqnanregs(fs, ft); fcr31.compare = any_unordered(fs, ft); } @@ -587,8 +635,8 @@ void Cop1::cun(Registers& regs, u32 instr) { template void Cop1::ceq(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FGR(regs.cop0.status, FS(instr)); - T ft = FGR(regs.cop0.status, FT(instr)); + T fs = FS(T, instr); + T ft = FT(T, instr); checkqnanregs(fs, ft); fcr31.compare = fs == ft; } @@ -596,8 +644,8 @@ void Cop1::ceq(Registers& regs, u32 instr) { template void Cop1::cueq(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FGR(regs.cop0.status, FS(instr)); - T ft = FGR(regs.cop0.status, FT(instr)); + T fs = FS(T, instr); + T ft = FT(T, instr); checkqnanregs(fs, ft); fcr31.compare = fs == ft || any_unordered(fs, ft); } @@ -605,8 +653,8 @@ void Cop1::cueq(Registers& regs, u32 instr) { template void Cop1::colt(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FGR(regs.cop0.status, FS(instr)); - T ft = FGR(regs.cop0.status, FT(instr)); + T fs = FS(T, instr); + T ft = FT(T, instr); checkqnanregs(fs, ft); fcr31.compare = fs < ft; } @@ -614,8 +662,8 @@ void Cop1::colt(Registers& regs, u32 instr) { template void Cop1::cult(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FGR(regs.cop0.status, FS(instr)); - T ft = FGR(regs.cop0.status, FT(instr)); + T fs = FS(T, instr); + T ft = FT(T, instr); checkqnanregs(fs, ft); fcr31.compare = fs < ft || any_unordered(fs, ft); } @@ -623,8 +671,8 @@ void Cop1::cult(Registers& regs, u32 instr) { template void Cop1::cole(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FGR(regs.cop0.status, FS(instr)); - T ft = FGR(regs.cop0.status, FT(instr)); + T fs = FS(T, instr); + T ft = FT(T, instr); checkqnanregs(fs, ft); fcr31.compare = fs <= ft; } @@ -632,8 +680,8 @@ void Cop1::cole(Registers& regs, u32 instr) { template void Cop1::cule(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FGR(regs.cop0.status, FS(instr)); - T ft = FGR(regs.cop0.status, FT(instr)); + T fs = FS(T, instr); + T ft = FT(T, instr); checkqnanregs(fs, ft); fcr31.compare = fs <= ft || any_unordered(fs, ft); } @@ -641,8 +689,8 @@ void Cop1::cule(Registers& regs, u32 instr) { template void Cop1::csf(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FGR(regs.cop0.status, FS(instr)); - T ft = FGR(regs.cop0.status, FT(instr)); + T fs = FS(T, instr); + T ft = FT(T, instr); checknanregs(fs, ft); fcr31.compare = false; } @@ -650,8 +698,8 @@ void Cop1::csf(Registers& regs, u32 instr) { template void Cop1::cngle(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FGR(regs.cop0.status, FS(instr)); - T ft = FGR(regs.cop0.status, FT(instr)); + T fs = FS(T, instr); + T ft = FT(T, instr); checknanregs(fs, ft); fcr31.compare = any_unordered(fs, ft); } @@ -659,8 +707,8 @@ void Cop1::cngle(Registers& regs, u32 instr) { template void Cop1::cseq(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FGR(regs.cop0.status, FS(instr)); - T ft = FGR(regs.cop0.status, FT(instr)); + T fs = FS(T, instr); + T ft = FT(T, instr); checknanregs(fs, ft); fcr31.compare = fs == ft; } @@ -668,8 +716,8 @@ void Cop1::cseq(Registers& regs, u32 instr) { template void Cop1::cngl(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FGR(regs.cop0.status, FS(instr)); - T ft = FGR(regs.cop0.status, FT(instr)); + T fs = FS(T, instr); + T ft = FT(T, instr); checknanregs(fs, ft); fcr31.compare = fs == ft || any_unordered(fs, ft); } @@ -677,8 +725,8 @@ void Cop1::cngl(Registers& regs, u32 instr) { template void Cop1::clt(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FGR(regs.cop0.status, FS(instr)); - T ft = FGR(regs.cop0.status, FT(instr)); + T fs = FS(T, instr); + T ft = FT(T, instr); checknanregs(fs, ft); fcr31.compare = fs < ft; } @@ -686,8 +734,8 @@ void Cop1::clt(Registers& regs, u32 instr) { template void Cop1::cnge(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FGR(regs.cop0.status, FS(instr)); - T ft = FGR(regs.cop0.status, FT(instr)); + T fs = FS(T, instr); + T ft = FT(T, instr); checknanregs(fs, ft); fcr31.compare = fs < ft || any_unordered(fs, ft); } @@ -695,8 +743,8 @@ void Cop1::cnge(Registers& regs, u32 instr) { template void Cop1::cle(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FGR(regs.cop0.status, FS(instr)); - T ft = FGR(regs.cop0.status, FT(instr)); + T fs = FS(T, instr); + T ft = FT(T, instr); checknanregs(fs, ft); fcr31.compare = fs <= ft; } @@ -704,8 +752,8 @@ void Cop1::cle(Registers& regs, u32 instr) { template void Cop1::cngt(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FGR(regs.cop0.status, FS(instr)); - T ft = FGR(regs.cop0.status, FT(instr)); + T fs = FS(T, instr); + T ft = FT(T, instr); checknanregs(fs, ft); fcr31.compare = fs <= ft || any_unordered(fs, ft); } @@ -769,14 +817,14 @@ void Cop1::subd(Registers ®s, u32 instr) { void Cop1::movs(Registers& regs, u32 instr) { CheckFPUUsable_PreserveCause(); - auto val = FGR(regs.cop0.status, FS(instr)); - FGR(regs.cop0.status, FD(instr)) = val; + auto val = FS(u64, instr); + FD(u64, instr) = val; } void Cop1::movd(Registers& regs, u32 instr) { CheckFPUUsable_PreserveCause(); - auto val = FGR(regs.cop0.status, FS(instr)); - FGR(regs.cop0.status, FD(instr)) = val; + auto val = FS(double, instr); + FD(double, instr) = val; } void Cop1::negs(Registers ®s, u32 instr) { @@ -797,122 +845,122 @@ void Cop1::sqrtd(Registers ®s, u32 instr) { void Cop1::roundls(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(float, instr); CheckLCVTArg(fs); s64 result; CVT_OP_CheckExcept({ result = std::nearbyint(fs); }); CheckRound(fs, result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(s64, instr) = result; } void Cop1::roundld(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(double, instr); CheckLCVTArg(fs); s64 result; CVT_OP_CheckExcept({ result = std::nearbyint(fs); }); CheckRound(fs, result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(s64, instr) = result; } void Cop1::roundws(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(float, instr); CheckWCVTArg(fs); s32 result; CVT_OP_CheckExcept({ result = std::nearbyint(fs); }); CheckRound(fs, result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(s32, instr) = result; } void Cop1::roundwd(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(double, instr); CheckWCVTArg(fs); s32 result; CVT_OP_CheckExcept({ result = std::nearbyint(fs); }); CheckRound(fs, result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(s32, instr) = result; } void Cop1::floorls(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(float, instr); CheckLCVTArg(fs); s64 result; CVT_OP_CheckExcept({ result = std::floor(fs); }); CheckRound(fs, result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(s64, instr) = result; } void Cop1::floorld(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(double, instr); CheckLCVTArg(fs); s64 result; CVT_OP_CheckExcept({ result = std::floor(fs); }); CheckRound(fs, result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(s64, instr) = result; } void Cop1::floorws(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(float, instr); CheckWCVTArg(fs); s32 result; CVT_OP_CheckExcept({ result = std::floor(fs); }); CheckRound(fs, result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(s32, instr) = result; } void Cop1::floorwd(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(double, instr); CheckWCVTArg(fs); s32 result; CVT_OP_CheckExcept({ result = std::floor(fs); }); CheckRound(fs, result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(s32, instr) = result; } void Cop1::truncws(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(float, instr); CheckWCVTArg(fs); s32 result; CVT_OP_CheckExcept({ result = std::trunc(fs); }); CheckRound(fs, result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(s32, instr) = result; } void Cop1::truncwd(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(double, instr); CheckWCVTArg(fs); s32 result; CVT_OP_CheckExcept({ result = std::trunc(fs); }); CheckRound(fs, result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(s32, instr) = result; } void Cop1::truncls(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(float, instr); CheckLCVTArg(fs); s64 result; CVT_OP_CheckExcept({ result = std::trunc(fs); }); CheckRound(fs, result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(s64, instr) = result; } void Cop1::truncld(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FGR(regs.cop0.status, FS(instr)); + auto fs = FS(double, instr); CheckLCVTArg(fs); s64 result; CVT_OP_CheckExcept({ result = std::trunc(fs); }); CheckRound(fs, result); - FGR(regs.cop0.status, FD(instr)) = result; + FD(s64, instr) = result; } template @@ -988,7 +1036,7 @@ void Cop1::lwc1Interp(Registers& regs, Mem& mem, u32 instr) { FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); } else { u32 data = mem.Read(regs, physical); - FGR(regs.cop0.status, FT(instr)) = data; + FT(u32, instr) = data; } } @@ -1000,7 +1048,7 @@ void Cop1::swc1Interp(Registers& regs, Mem& mem, u32 instr) { HandleTLBException(regs, addr); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); } else { - mem.Write(regs, physical, FGR(regs.cop0.status, FT(instr))); + mem.Write(regs, physical, FT(u32, instr)); } } @@ -1019,7 +1067,7 @@ void Cop1::ldc1Interp(Registers& regs, Mem& mem, u32 instr) { FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); } else { u64 data = mem.Read(regs, physical); - FGR(regs.cop0.status, FT(instr)) = data; + FT(u64, instr) = data; } } @@ -1031,28 +1079,28 @@ void Cop1::sdc1Interp(Registers& regs, Mem& mem, u32 instr) { HandleTLBException(regs, addr); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); } else { - mem.Write(regs, physical, FGR(regs.cop0.status, FT(instr))); + mem.Write(regs, physical, FT(u64, instr)); } } void Cop1::mfc1(Registers& regs, u32 instr) { CheckFPUUsable_PreserveCause(); - regs.gpr[RT(instr)] = FGR(regs.cop0.status, FS(instr)); + regs.gpr[RT(instr)] = (u64)FS(s32, instr); } void Cop1::dmfc1(Registers& regs, u32 instr) { CheckFPUUsable_PreserveCause(); - regs.gpr[RT(instr)] = FGR(regs.cop0.status, FS(instr)); + regs.gpr[RT(instr)] = (u64)FS(s64, instr); } void Cop1::mtc1(Registers& regs, u32 instr) { CheckFPUUsable_PreserveCause(); - FGR(regs.cop0.status, FS(instr)) = regs.gpr[RT(instr)]; + FS(u32, instr) = (u64)regs.gpr[RT(instr)]; } void Cop1::dmtc1(Registers& regs, u32 instr) { CheckFPUUsable_PreserveCause(); - FGR(regs.cop0.status, FS(instr)) = regs.gpr[RT(instr)]; + FS(u64, instr) = (u64)regs.gpr[RT(instr)]; } } diff --git a/src/common.hpp b/src/common.hpp index 989ae9d9..e90e8239 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -42,9 +42,9 @@ static FORCE_INLINE constexpr u32 GetVideoFrequency(bool pal) { #define RD(x) (((x) >> 11) & 0x1F) #define RT(x) (((x) >> 16) & 0x1F) #define RS(x) (((x) >> 21) & 0x1F) -#define FD(x) (((x) >> 6) & 0x1F) -#define FT(x) RT(x) -#define FS(x) RD(x) +#define FD(type, x) FGR_D(regs.cop0.status, (((x) >> 6) & 0x1F)) +#define FT(type, x) FGR_T(regs.cop0.status, RT((x))) +#define FS(type, x) FGR_S(regs.cop0.status, RD((x))) #define BASE(x) RS(x) #define VT(x) (((x) >> 16) & 0x1F) #define VS(x) (((x) >> 11) & 0x1F) From 2f0a3f08cdb41923ca9a1010737e4ca94071d3d7 Mon Sep 17 00:00:00 2001 From: SimoneN64 Date: Fri, 19 Jan 2024 01:05:35 +0100 Subject: [PATCH 20/20] Revert "FGR improvements" This reverts commit ee1fd7baf318709eebb22555e21f8aeae4cd3759. --- src/backend/core/registers/Cop1.hpp | 5 +- .../core/registers/cop/cop1instructions.cpp | 276 ++++++++---------- src/common.hpp | 6 +- 3 files changed, 119 insertions(+), 168 deletions(-) diff --git a/src/backend/core/registers/Cop1.hpp b/src/backend/core/registers/Cop1.hpp index a42bb4c7..053b17da 100644 --- a/src/backend/core/registers/Cop1.hpp +++ b/src/backend/core/registers/Cop1.hpp @@ -108,9 +108,8 @@ struct Cop1 { void SetCauseOverflow(); void SetCauseInvalid(); private: - template auto FGR_T(Cop0Status&, u32) -> T&; - template auto FGR_S(Cop0Status&, u32) -> T&; - template auto FGR_D(Cop0Status&, u32) -> T&; + template + auto FGR(Cop0Status&, u32) -> T&; void decodeInterp(Interpreter&, u32); void decodeJIT(JIT&, u32); void absd(Registers&, u32 instr); diff --git a/src/backend/core/registers/cop/cop1instructions.cpp b/src/backend/core/registers/cop/cop1instructions.cpp index 266d6aec..6138e5b7 100644 --- a/src/backend/core/registers/cop/cop1instructions.cpp +++ b/src/backend/core/registers/cop/cop1instructions.cpp @@ -7,7 +7,7 @@ #include namespace n64 { -template<> auto Cop1::FGR_T(Cop0Status& status, u32 index) -> s32& { +template<> auto Cop1::FGR(Cop0Status& status, u32 index) -> s32& { if (status.fr) { return fgr[index].int32; } else { @@ -19,86 +19,38 @@ template<> auto Cop1::FGR_T(Cop0Status& status, u32 index) -> s32& { } } -template<> auto Cop1::FGR_T(Cop0Status& status, u32 index) -> u32& { - return (u32&)FGR_T(status, index); +template<> auto Cop1::FGR(Cop0Status& status, u32 index) -> u32& { + return (u32&)FGR(status, index); } -template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> s32& { - if (status.fr) { - return fgr[index].int32; - } else { - return fgr[index & ~1].int32; - } -} - -template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> u32& { - return (u32&)FGR_S(status, index); -} - -template<> auto Cop1::FGR_D(Cop0Status& status, u32 index) -> s32& { - fgr[index].int32h = 0; - return fgr[index].int32; -} - -template<> auto Cop1::FGR_T(Cop0Status& status, u32 index) -> float& { - return fgr[index].float32; -} - -template<> auto Cop1::FGR_D(Cop0Status& status, u32 index) -> float& { - fgr[index].float32h = 0; - return fgr[index].float32; -} - -template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> float& { +template<> auto Cop1::FGR(Cop0Status& status, u32 index) -> float& { if (status.fr) { return fgr[index].float32; } else { - return fgr[index & ~1].float32; + if (index & 1) { + return fgr[index & ~1].float32h; + } else { + return fgr[index].float32; + } } } -template<> auto Cop1::FGR_T(Cop0Status& status, u32 index) -> s64& { +template<> auto Cop1::FGR(Cop0Status& status, u32 index) -> s64& { if (status.fr) { return fgr[index].int64; - } - else { + } else { return fgr[index & ~1].int64; } } -template<> auto Cop1::FGR_D(Cop0Status&, u32 index) -> s64& { - return fgr[index].int64; +template<> auto Cop1::FGR(Cop0Status& status, u32 index) -> u64& { + return (u64&)FGR(status, index); } -template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> s64& { - return FGR_T(status, index); -} - -template<> auto Cop1::FGR_T(Cop0Status& status, u32 index) -> u64& { - return (u64&)FGR_T(status, index); -} - -template<> auto Cop1::FGR_D(Cop0Status& status, u32 index) -> u64& { - return (u64&)FGR_D(status, index); -} - -template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> u64& { - return FGR_T(status, index); -} - -template<> auto Cop1::FGR_T(Cop0Status&, u32 index) -> double& { - return fgr[index].float64; -} - -template<> auto Cop1::FGR_D(Cop0Status& status, u32 index) -> double& { - return FGR_T(status, index); -} - -template<> auto Cop1::FGR_S(Cop0Status& status, u32 index) -> double& { +template<> auto Cop1::FGR(Cop0Status& status, u32 index) -> double& { if (status.fr) { return fgr[index].float64; - } - else { + } else { return fgr[index & ~1].float64; } } @@ -174,14 +126,14 @@ void Cop1::SetCauseInvalid() { #define OP(T, op) do { \ CheckFPUUsable(); \ - auto fs = FS(T, instr); \ - auto ft = FT(T, instr); \ + auto fs = FGR(regs.cop0.status, FS(instr)); \ + auto ft = FGR(regs.cop0.status, FT(instr)); \ CheckArg(fs); \ CheckArg(ft); \ T result; \ OP_CheckExcept({result = (op);}); \ CheckResult(result); \ - FD(T, instr) = result; \ + FGR(regs.cop0.status, FD(instr)) = result; \ } while(0) template @@ -426,42 +378,42 @@ void Cop1::addd(Registers& regs, u32 instr) { void Cop1::ceills(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(float, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckLCVTArg(fs); s64 result; CVT_OP_CheckExcept({ result = std::ceil(fs); }); CheckRound(fs, result); - FD(s64, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::ceilws(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(float, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckWCVTArg(fs); s32 result; CVT_OP_CheckExcept({ result = std::ceil(fs); }); CheckRound(fs, result); - FD(s32, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::ceilld(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(double, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckLCVTArg(fs); s64 result; CVT_OP_CheckExcept({ result = std::ceil(fs); }); CheckRound(fs, result); - FD(s64, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::ceilwd(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(double, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckWCVTArg(fs); s32 result; CVT_OP_CheckExcept({ result = std::ceil(fs); }); CheckRound(fs, result); - FD(s32, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::cfc1(Registers& regs, u32 instr) const { @@ -503,36 +455,36 @@ void Cop1::ctc1(Registers& regs, u32 instr) { void Cop1::cvtds(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(float, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckArg(fs); double result; OP_CheckExcept({ result = double(fs); }); CheckResult(result); - FD(double, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::cvtsd(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(double, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckArg(fs); float result; OP_CheckExcept({ result = float(fs); }); CheckResult(result); - FD(float, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::cvtsw(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(s32, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); float result; OP_CheckExcept({ result = float(fs); }); CheckResult(result); - FD(float, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::cvtsl(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(s64, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); if (fs >= s64(0x0080000000000000) || fs < s64(0xff80000000000000)) { SetCauseUnimplemented(); CheckFPUException(); @@ -540,57 +492,57 @@ void Cop1::cvtsl(Registers& regs, u32 instr) { float result; OP_CheckExcept({ result = float(fs); }); CheckResult(result); - FD(float, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::cvtwd(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(double, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckWCVTArg(fs); s32 result; PUSHROUNDING; CVT_OP_CheckExcept({ result = std::rint(fs); }); POPROUNDING; CheckRound(fs, result); - FD(s32, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::cvtws(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(float, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckWCVTArg(fs); s32 result; PUSHROUNDING; CVT_OP_CheckExcept({ result = std::rint(fs); }); POPROUNDING; CheckRound(fs, result); - FD(s32, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::cvtls(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(float, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckLCVTArg(fs); s64 result; PUSHROUNDING; CVT_OP_CheckExcept({ result = std::rint(fs); }); POPROUNDING; CheckRound(fs, result); - FD(s64, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::cvtdw(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(s32, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); double result; OP_CheckExcept({ result = double(fs); }); CheckResult(result); - FD(double, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::cvtdl(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(s64, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); if (fs >= s64(0x0080000000000000) || fs < s64(0xff80000000000000)) { SetCauseUnimplemented(); @@ -599,26 +551,26 @@ void Cop1::cvtdl(Registers& regs, u32 instr) { double result; OP_CheckExcept({ result = double(fs); }); CheckResult(result); - FD(double, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::cvtld(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(double, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckLCVTArg(fs); s64 result; PUSHROUNDING; CVT_OP_CheckExcept({ result = std::rint(fs); }); POPROUNDING; CheckRound(fs, result); - FD(s64, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } template void Cop1::cf(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FS(T, instr); - T ft = FT(T, instr); + T fs = FGR(regs.cop0.status, FS(instr)); + T ft = FGR(regs.cop0.status, FT(instr)); checkqnanregs(fs, ft); fcr31.compare = false; } @@ -626,8 +578,8 @@ void Cop1::cf(Registers& regs, u32 instr) { template void Cop1::cun(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FS(T, instr); - T ft = FT(T, instr); + T fs = FGR(regs.cop0.status, FS(instr)); + T ft = FGR(regs.cop0.status, FT(instr)); checkqnanregs(fs, ft); fcr31.compare = any_unordered(fs, ft); } @@ -635,8 +587,8 @@ void Cop1::cun(Registers& regs, u32 instr) { template void Cop1::ceq(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FS(T, instr); - T ft = FT(T, instr); + T fs = FGR(regs.cop0.status, FS(instr)); + T ft = FGR(regs.cop0.status, FT(instr)); checkqnanregs(fs, ft); fcr31.compare = fs == ft; } @@ -644,8 +596,8 @@ void Cop1::ceq(Registers& regs, u32 instr) { template void Cop1::cueq(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FS(T, instr); - T ft = FT(T, instr); + T fs = FGR(regs.cop0.status, FS(instr)); + T ft = FGR(regs.cop0.status, FT(instr)); checkqnanregs(fs, ft); fcr31.compare = fs == ft || any_unordered(fs, ft); } @@ -653,8 +605,8 @@ void Cop1::cueq(Registers& regs, u32 instr) { template void Cop1::colt(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FS(T, instr); - T ft = FT(T, instr); + T fs = FGR(regs.cop0.status, FS(instr)); + T ft = FGR(regs.cop0.status, FT(instr)); checkqnanregs(fs, ft); fcr31.compare = fs < ft; } @@ -662,8 +614,8 @@ void Cop1::colt(Registers& regs, u32 instr) { template void Cop1::cult(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FS(T, instr); - T ft = FT(T, instr); + T fs = FGR(regs.cop0.status, FS(instr)); + T ft = FGR(regs.cop0.status, FT(instr)); checkqnanregs(fs, ft); fcr31.compare = fs < ft || any_unordered(fs, ft); } @@ -671,8 +623,8 @@ void Cop1::cult(Registers& regs, u32 instr) { template void Cop1::cole(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FS(T, instr); - T ft = FT(T, instr); + T fs = FGR(regs.cop0.status, FS(instr)); + T ft = FGR(regs.cop0.status, FT(instr)); checkqnanregs(fs, ft); fcr31.compare = fs <= ft; } @@ -680,8 +632,8 @@ void Cop1::cole(Registers& regs, u32 instr) { template void Cop1::cule(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FS(T, instr); - T ft = FT(T, instr); + T fs = FGR(regs.cop0.status, FS(instr)); + T ft = FGR(regs.cop0.status, FT(instr)); checkqnanregs(fs, ft); fcr31.compare = fs <= ft || any_unordered(fs, ft); } @@ -689,8 +641,8 @@ void Cop1::cule(Registers& regs, u32 instr) { template void Cop1::csf(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FS(T, instr); - T ft = FT(T, instr); + T fs = FGR(regs.cop0.status, FS(instr)); + T ft = FGR(regs.cop0.status, FT(instr)); checknanregs(fs, ft); fcr31.compare = false; } @@ -698,8 +650,8 @@ void Cop1::csf(Registers& regs, u32 instr) { template void Cop1::cngle(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FS(T, instr); - T ft = FT(T, instr); + T fs = FGR(regs.cop0.status, FS(instr)); + T ft = FGR(regs.cop0.status, FT(instr)); checknanregs(fs, ft); fcr31.compare = any_unordered(fs, ft); } @@ -707,8 +659,8 @@ void Cop1::cngle(Registers& regs, u32 instr) { template void Cop1::cseq(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FS(T, instr); - T ft = FT(T, instr); + T fs = FGR(regs.cop0.status, FS(instr)); + T ft = FGR(regs.cop0.status, FT(instr)); checknanregs(fs, ft); fcr31.compare = fs == ft; } @@ -716,8 +668,8 @@ void Cop1::cseq(Registers& regs, u32 instr) { template void Cop1::cngl(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FS(T, instr); - T ft = FT(T, instr); + T fs = FGR(regs.cop0.status, FS(instr)); + T ft = FGR(regs.cop0.status, FT(instr)); checknanregs(fs, ft); fcr31.compare = fs == ft || any_unordered(fs, ft); } @@ -725,8 +677,8 @@ void Cop1::cngl(Registers& regs, u32 instr) { template void Cop1::clt(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FS(T, instr); - T ft = FT(T, instr); + T fs = FGR(regs.cop0.status, FS(instr)); + T ft = FGR(regs.cop0.status, FT(instr)); checknanregs(fs, ft); fcr31.compare = fs < ft; } @@ -734,8 +686,8 @@ void Cop1::clt(Registers& regs, u32 instr) { template void Cop1::cnge(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FS(T, instr); - T ft = FT(T, instr); + T fs = FGR(regs.cop0.status, FS(instr)); + T ft = FGR(regs.cop0.status, FT(instr)); checknanregs(fs, ft); fcr31.compare = fs < ft || any_unordered(fs, ft); } @@ -743,8 +695,8 @@ void Cop1::cnge(Registers& regs, u32 instr) { template void Cop1::cle(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FS(T, instr); - T ft = FT(T, instr); + T fs = FGR(regs.cop0.status, FS(instr)); + T ft = FGR(regs.cop0.status, FT(instr)); checknanregs(fs, ft); fcr31.compare = fs <= ft; } @@ -752,8 +704,8 @@ void Cop1::cle(Registers& regs, u32 instr) { template void Cop1::cngt(Registers& regs, u32 instr) { CheckFPUUsable(); - T fs = FS(T, instr); - T ft = FT(T, instr); + T fs = FGR(regs.cop0.status, FS(instr)); + T ft = FGR(regs.cop0.status, FT(instr)); checknanregs(fs, ft); fcr31.compare = fs <= ft || any_unordered(fs, ft); } @@ -817,14 +769,14 @@ void Cop1::subd(Registers ®s, u32 instr) { void Cop1::movs(Registers& regs, u32 instr) { CheckFPUUsable_PreserveCause(); - auto val = FS(u64, instr); - FD(u64, instr) = val; + auto val = FGR(regs.cop0.status, FS(instr)); + FGR(regs.cop0.status, FD(instr)) = val; } void Cop1::movd(Registers& regs, u32 instr) { CheckFPUUsable_PreserveCause(); - auto val = FS(double, instr); - FD(double, instr) = val; + auto val = FGR(regs.cop0.status, FS(instr)); + FGR(regs.cop0.status, FD(instr)) = val; } void Cop1::negs(Registers ®s, u32 instr) { @@ -845,122 +797,122 @@ void Cop1::sqrtd(Registers ®s, u32 instr) { void Cop1::roundls(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(float, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckLCVTArg(fs); s64 result; CVT_OP_CheckExcept({ result = std::nearbyint(fs); }); CheckRound(fs, result); - FD(s64, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::roundld(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(double, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckLCVTArg(fs); s64 result; CVT_OP_CheckExcept({ result = std::nearbyint(fs); }); CheckRound(fs, result); - FD(s64, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::roundws(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(float, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckWCVTArg(fs); s32 result; CVT_OP_CheckExcept({ result = std::nearbyint(fs); }); CheckRound(fs, result); - FD(s32, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::roundwd(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(double, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckWCVTArg(fs); s32 result; CVT_OP_CheckExcept({ result = std::nearbyint(fs); }); CheckRound(fs, result); - FD(s32, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::floorls(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(float, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckLCVTArg(fs); s64 result; CVT_OP_CheckExcept({ result = std::floor(fs); }); CheckRound(fs, result); - FD(s64, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::floorld(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(double, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckLCVTArg(fs); s64 result; CVT_OP_CheckExcept({ result = std::floor(fs); }); CheckRound(fs, result); - FD(s64, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::floorws(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(float, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckWCVTArg(fs); s32 result; CVT_OP_CheckExcept({ result = std::floor(fs); }); CheckRound(fs, result); - FD(s32, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::floorwd(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(double, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckWCVTArg(fs); s32 result; CVT_OP_CheckExcept({ result = std::floor(fs); }); CheckRound(fs, result); - FD(s32, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::truncws(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(float, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckWCVTArg(fs); s32 result; CVT_OP_CheckExcept({ result = std::trunc(fs); }); CheckRound(fs, result); - FD(s32, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::truncwd(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(double, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckWCVTArg(fs); s32 result; CVT_OP_CheckExcept({ result = std::trunc(fs); }); CheckRound(fs, result); - FD(s32, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::truncls(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(float, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckLCVTArg(fs); s64 result; CVT_OP_CheckExcept({ result = std::trunc(fs); }); CheckRound(fs, result); - FD(s64, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } void Cop1::truncld(Registers& regs, u32 instr) { CheckFPUUsable(); - auto fs = FS(double, instr); + auto fs = FGR(regs.cop0.status, FS(instr)); CheckLCVTArg(fs); s64 result; CVT_OP_CheckExcept({ result = std::trunc(fs); }); CheckRound(fs, result); - FD(s64, instr) = result; + FGR(regs.cop0.status, FD(instr)) = result; } template @@ -1036,7 +988,7 @@ void Cop1::lwc1Interp(Registers& regs, Mem& mem, u32 instr) { FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); } else { u32 data = mem.Read(regs, physical); - FT(u32, instr) = data; + FGR(regs.cop0.status, FT(instr)) = data; } } @@ -1048,7 +1000,7 @@ void Cop1::swc1Interp(Registers& regs, Mem& mem, u32 instr) { HandleTLBException(regs, addr); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); } else { - mem.Write(regs, physical, FT(u32, instr)); + mem.Write(regs, physical, FGR(regs.cop0.status, FT(instr))); } } @@ -1067,7 +1019,7 @@ void Cop1::ldc1Interp(Registers& regs, Mem& mem, u32 instr) { FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); } else { u64 data = mem.Read(regs, physical); - FT(u64, instr) = data; + FGR(regs.cop0.status, FT(instr)) = data; } } @@ -1079,28 +1031,28 @@ void Cop1::sdc1Interp(Registers& regs, Mem& mem, u32 instr) { HandleTLBException(regs, addr); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); } else { - mem.Write(regs, physical, FT(u64, instr)); + mem.Write(regs, physical, FGR(regs.cop0.status, FT(instr))); } } void Cop1::mfc1(Registers& regs, u32 instr) { CheckFPUUsable_PreserveCause(); - regs.gpr[RT(instr)] = (u64)FS(s32, instr); + regs.gpr[RT(instr)] = FGR(regs.cop0.status, FS(instr)); } void Cop1::dmfc1(Registers& regs, u32 instr) { CheckFPUUsable_PreserveCause(); - regs.gpr[RT(instr)] = (u64)FS(s64, instr); + regs.gpr[RT(instr)] = FGR(regs.cop0.status, FS(instr)); } void Cop1::mtc1(Registers& regs, u32 instr) { CheckFPUUsable_PreserveCause(); - FS(u32, instr) = (u64)regs.gpr[RT(instr)]; + FGR(regs.cop0.status, FS(instr)) = regs.gpr[RT(instr)]; } void Cop1::dmtc1(Registers& regs, u32 instr) { CheckFPUUsable_PreserveCause(); - FS(u64, instr) = (u64)regs.gpr[RT(instr)]; + FGR(regs.cop0.status, FS(instr)) = regs.gpr[RT(instr)]; } } diff --git a/src/common.hpp b/src/common.hpp index e90e8239..989ae9d9 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -42,9 +42,9 @@ static FORCE_INLINE constexpr u32 GetVideoFrequency(bool pal) { #define RD(x) (((x) >> 11) & 0x1F) #define RT(x) (((x) >> 16) & 0x1F) #define RS(x) (((x) >> 21) & 0x1F) -#define FD(type, x) FGR_D(regs.cop0.status, (((x) >> 6) & 0x1F)) -#define FT(type, x) FGR_T(regs.cop0.status, RT((x))) -#define FS(type, x) FGR_S(regs.cop0.status, RD((x))) +#define FD(x) (((x) >> 6) & 0x1F) +#define FT(x) RT(x) +#define FS(x) RD(x) #define BASE(x) RS(x) #define VT(x) (((x) >> 16) & 0x1F) #define VS(x) (((x) >> 11) & 0x1F)