From 80c7e46a38b028622fe32309e4f7d33cd3ef56f4 Mon Sep 17 00:00:00 2001 From: SimoneN64 Date: Mon, 25 Dec 2023 22:49:24 +0100 Subject: [PATCH] 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) {