better print, some cop0
This commit is contained in:
@@ -239,6 +239,16 @@ private:
|
|||||||
void xor_(u32);
|
void xor_(u32);
|
||||||
void xori(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 mtc2(u32);
|
||||||
void mfc2(u32);
|
void mfc2(u32);
|
||||||
void dmtc2(u32);
|
void dmtc2(u32);
|
||||||
|
|||||||
@@ -6,141 +6,66 @@ template <> struct fmt::formatter<Entry> : formatter<string_view> {
|
|||||||
auto format(Entry e, format_context& ctx) const {
|
auto format(Entry e, format_context& ctx) const {
|
||||||
std::string op = "Unknown";
|
std::string op = "Unknown";
|
||||||
switch (e.op) {
|
switch (e.op) {
|
||||||
case Entry::MOV:
|
case Entry::MOV: op = "MOV"; break;
|
||||||
op = "MOV";
|
case Entry::ADD: op = "ADD"; break;
|
||||||
break;
|
case Entry::SUB: op = "SUB"; break;
|
||||||
case Entry::ADD:
|
case Entry::UMUL: op = "UMUL"; break;
|
||||||
op = "ADD";
|
case Entry::SMUL: op = "SMUL"; break;
|
||||||
break;
|
case Entry::DIV: op = "DIV"; break;
|
||||||
case Entry::SUB:
|
case Entry::AND: op = "AND"; break;
|
||||||
op = "SUB";
|
case Entry::NOR: op = "NOR"; break;
|
||||||
break;
|
case Entry::XOR: op = "XOR"; break;
|
||||||
case Entry::UMUL:
|
case Entry::OR: op = "OR"; break;
|
||||||
op = "UMUL";
|
case Entry::SRL: op = "SRL"; break;
|
||||||
break;
|
case Entry::SLL: op = "SLL"; break;
|
||||||
case Entry::SMUL:
|
case Entry::SRA: op = "SRA"; break;
|
||||||
op = "SMUL";
|
case Entry::LOADS8: op = "LOADS8"; break;
|
||||||
break;
|
case Entry::LOADS8_SHIFT: op = "LOADS8_SHIFT"; break;
|
||||||
case Entry::DIV:
|
case Entry::STORE8: op = "STORE8"; break;
|
||||||
op = "DIV";
|
case Entry::STORE8_SHIFT: op = "STORE8_SHIFT"; break;
|
||||||
break;
|
case Entry::LOADS16: op = "LOADS16"; break;
|
||||||
case Entry::AND:
|
case Entry::LOADS16_SHIFT: op = "LOADS16_SHIFT"; break;
|
||||||
op = "AND";
|
case Entry::STORE16: op = "STORE16"; break;
|
||||||
break;
|
case Entry::STORE16_SHIFT: op = "STORE16_SHIFT"; break;
|
||||||
case Entry::NOR:
|
case Entry::LOADS32: op = "LOADS32"; break;
|
||||||
op = "NOR";
|
case Entry::LOADS32_SHIFT: op = "LOADS32_SHIFT"; break;
|
||||||
break;
|
case Entry::STORE32: op = "STORE32"; break;
|
||||||
case Entry::XOR:
|
case Entry::STORE32_SHIFT: op = "STORE32_SHIFT"; break;
|
||||||
op = "XOR";
|
case Entry::LOADS64: op = "LOADS64"; break;
|
||||||
break;
|
case Entry::LOADS64_SHIFT: op = "LOADS64_SHIFT"; break;
|
||||||
case Entry::OR:
|
case Entry::STORE64: op = "STORE64"; break;
|
||||||
op = "OR";
|
case Entry::STORE64_SHIFT: op = "STORE64_SHIFT"; break;
|
||||||
break;
|
case Entry::LOADU8: op = "LOADU8"; break;
|
||||||
case Entry::SRL:
|
case Entry::LOADU8_SHIFT: op = "LOADU8_SHIFT"; break;
|
||||||
op = "SRL";
|
case Entry::LOADU16: op = "LOADU16"; break;
|
||||||
break;
|
case Entry::LOADU16_SHIFT: op = "LOADU16_SHIFT"; break;
|
||||||
case Entry::SLL:
|
case Entry::LOADU32: op = "LOADU32"; break;
|
||||||
op = "SLL";
|
case Entry::LOADU32_SHIFT: op = "LOADU32_SHIFT"; break;
|
||||||
break;
|
case Entry::LOADU64: op = "LOADU64"; break;
|
||||||
case Entry::SRA:
|
case Entry::LOADU64_SHIFT: op = "LOADU64_SHIFT"; break;
|
||||||
op = "SRA";
|
case Entry::BRANCH: op = "BRANCH"; break;
|
||||||
break;
|
case Entry::JUMP: op = "JUMP"; break;
|
||||||
case Entry::LOADS8:
|
case Entry::MTC0: op = "MTC0"; break;
|
||||||
op = "LOADS8";
|
case Entry::MFC0: op = "MFC0"; break;
|
||||||
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;
|
bool put_comma = false;
|
||||||
op += " ";
|
op += " ";
|
||||||
if (e.dst.isReg()) {
|
if (e.dst.isReg()) {
|
||||||
if (e.dst.index_or_imm.has_value()) {
|
if (e.dst.index_or_imm.has_value()) {
|
||||||
if (e.dst.index_or_imm.value() == 0) {
|
std::string dst = fmt::format("R{}", e.dst.index_or_imm.value());
|
||||||
op = "NOP";
|
op += dst;
|
||||||
return formatter<string_view>::format(op, ctx);
|
put_comma = true;
|
||||||
} else {
|
}
|
||||||
std::string dst = fmt::format("R{}", e.dst.index_or_imm.value());
|
} else if(e.dst.isImm()) {
|
||||||
op += dst;
|
if(e.dst.type != Entry::Operand::NONE) {
|
||||||
put_comma = true;
|
std::string dst = fmt::format("0x{:0X}", e.dst.index_or_imm.value());
|
||||||
}
|
op += dst;
|
||||||
|
put_comma = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(e.dst.type != Entry::Operand::NONE) {
|
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;
|
op += dst;
|
||||||
put_comma = true;
|
put_comma = true;
|
||||||
}
|
}
|
||||||
@@ -151,20 +76,27 @@ template <> struct fmt::formatter<Entry> : formatter<string_view> {
|
|||||||
std::string op1 = fmt::format("R{}", e.op1.index_or_imm.value());
|
std::string op1 = fmt::format("R{}", e.op1.index_or_imm.value());
|
||||||
if(put_comma) {
|
if(put_comma) {
|
||||||
op += ", ";
|
op += ", ";
|
||||||
} else {
|
|
||||||
put_comma = true;
|
|
||||||
}
|
}
|
||||||
op += op1;
|
op += op1;
|
||||||
|
put_comma = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else if(e.op1.isImm()) {
|
||||||
if (e.op1.index_or_imm.has_value()) {
|
if (e.op1.index_or_imm.has_value()) {
|
||||||
std::string op1 = fmt::format("0x{:0X}", e.op1.index_or_imm.value());
|
std::string op1 = fmt::format("0x{:0X}", e.op1.index_or_imm.value());
|
||||||
if(put_comma) {
|
if(put_comma) {
|
||||||
op += ", ";
|
op += ", ";
|
||||||
} else {
|
|
||||||
put_comma = true;
|
|
||||||
}
|
}
|
||||||
op += op1;
|
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<Entry> : formatter<string_view> {
|
|||||||
std::string op2 = fmt::format("R{}", e.op2.index_or_imm.value());
|
std::string op2 = fmt::format("R{}", e.op2.index_or_imm.value());
|
||||||
if(put_comma) {
|
if(put_comma) {
|
||||||
op += ", ";
|
op += ", ";
|
||||||
} else {
|
|
||||||
put_comma = true;
|
|
||||||
}
|
}
|
||||||
op += op2;
|
op += op2;
|
||||||
}
|
}
|
||||||
@@ -183,8 +113,6 @@ template <> struct fmt::formatter<Entry> : formatter<string_view> {
|
|||||||
std::string op2 = fmt::format("0x{:0X}", e.op2.index_or_imm.value());
|
std::string op2 = fmt::format("0x{:0X}", e.op2.index_or_imm.value());
|
||||||
if(put_comma) {
|
if(put_comma) {
|
||||||
op += ", ";
|
op += ", ";
|
||||||
} else {
|
|
||||||
put_comma = true;
|
|
||||||
}
|
}
|
||||||
op += op2;
|
op += op2;
|
||||||
}
|
}
|
||||||
@@ -214,18 +142,18 @@ void IR::push(const Entry& e) {
|
|||||||
code.push_back(e);
|
code.push_back(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IR::optimize() {
|
void IR::dead_code_elimination(std::vector<Entry>& code_) {
|
||||||
std::vector<Entry> optimized{};
|
|
||||||
|
|
||||||
for(const auto& i : code) {
|
for(const auto& i : code) {
|
||||||
bool isOp1Reg = i.op1.isReg();
|
bool isOp1Reg = i.op1.isReg();
|
||||||
bool isOp2Reg = i.op2.isReg();
|
bool isOp2Reg = i.op2.isReg();
|
||||||
bool isDstReg = i.dst.isReg();
|
bool isDstReg = i.dst.isReg();
|
||||||
|
|
||||||
if(isDstReg) {
|
if(isDstReg) {
|
||||||
|
if(i.zeroRendersItUseless() && i.dst.index_or_imm == 0) continue;
|
||||||
|
|
||||||
if(isOp1Reg) {
|
if(isOp1Reg) {
|
||||||
if(i.op1.index_or_imm == i.dst.index_or_imm
|
if(i.op1.index_or_imm == i.dst.index_or_imm
|
||||||
&& i.zeroRendersItUseless()) continue;
|
&& i.zeroRendersItUseless()) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isOp2Reg) {
|
if(isOp2Reg) {
|
||||||
@@ -234,8 +162,14 @@ void IR::optimize() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
optimized.push_back(i);
|
code_.push_back(i);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IR::optimize() {
|
||||||
|
std::vector<Entry> optimized{};
|
||||||
|
|
||||||
|
dead_code_elimination(optimized);
|
||||||
|
|
||||||
if(optimized.size() == code.size()) {
|
if(optimized.size() == code.size()) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ struct Entry {
|
|||||||
LINK = 0x100,
|
LINK = 0x100,
|
||||||
LIKELY = 0x200,
|
LIKELY = 0x200,
|
||||||
REGISTER = 0x400,
|
REGISTER = 0x400,
|
||||||
SET_LLBIT = 0x800
|
SET_LLBIT = 0x800,
|
||||||
|
UNSET_LLBIT = 0x1000,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Shift {
|
enum Shift {
|
||||||
@@ -26,8 +27,8 @@ struct Entry {
|
|||||||
LOADU16, LOADU16_SHIFT,
|
LOADU16, LOADU16_SHIFT,
|
||||||
LOADU32, LOADU32_SHIFT,
|
LOADU32, LOADU32_SHIFT,
|
||||||
LOADU64, LOADU64_SHIFT,
|
LOADU64, LOADU64_SHIFT,
|
||||||
BRANCH, JUMP,
|
BRANCH, JUMP, MTC0, MFC0
|
||||||
} op;
|
} op;
|
||||||
|
|
||||||
struct Operand {
|
struct Operand {
|
||||||
enum Type {
|
enum Type {
|
||||||
@@ -83,6 +84,7 @@ struct IR {
|
|||||||
void print();
|
void print();
|
||||||
void optimize();
|
void optimize();
|
||||||
private:
|
private:
|
||||||
|
void dead_code_elimination(std::vector<Entry>&);
|
||||||
std::vector<Entry> code{};
|
std::vector<Entry> code{};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -813,6 +813,91 @@ void JIT::mthi(u32 instr) {
|
|||||||
ir.push({Entry::MOV, dst, src});
|
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) {
|
void JIT::mtc2(u32 instr) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <log.hpp>
|
#include <log.hpp>
|
||||||
#include <core/registers/Registers.hpp>
|
#include <core/registers/Registers.hpp>
|
||||||
#include <core/Interpreter.hpp>
|
#include <core/Interpreter.hpp>
|
||||||
|
#include <core/JIT.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
Cop0::Cop0() {
|
Cop0::Cop0() {
|
||||||
@@ -336,7 +337,25 @@ template void Cop0::decode<Interpreter>(Interpreter&, u32);
|
|||||||
template void Cop0::decode<JIT>(JIT&, u32);
|
template void Cop0::decode<JIT>(JIT&, u32);
|
||||||
|
|
||||||
void Cop0::decodeJIT(JIT& cpu, u32 instr) {
|
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) {
|
void Cop0::decodeInterp(Registers& regs, u32 instr) {
|
||||||
|
|||||||
Reference in New Issue
Block a user