better print, some cop0
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -6,141 +6,66 @@ template <> struct fmt::formatter<Entry> : formatter<string_view> {
|
||||
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<string_view>::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.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<Entry> : formatter<string_view> {
|
||||
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<Entry> : formatter<string_view> {
|
||||
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<Entry> : formatter<string_view> {
|
||||
std::string op2 = fmt::format("0x{:0X}", e.op2.index_or_imm.value());
|
||||
if(put_comma) {
|
||||
op += ", ";
|
||||
} else {
|
||||
put_comma = true;
|
||||
}
|
||||
op += op2;
|
||||
}
|
||||
@@ -214,15 +142,15 @@ void IR::push(const Entry& e) {
|
||||
code.push_back(e);
|
||||
}
|
||||
|
||||
void IR::optimize() {
|
||||
std::vector<Entry> optimized{};
|
||||
|
||||
void IR::dead_code_elimination(std::vector<Entry>& 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;
|
||||
@@ -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()) {
|
||||
return;
|
||||
|
||||
@@ -9,7 +9,8 @@ struct Entry {
|
||||
LINK = 0x100,
|
||||
LIKELY = 0x200,
|
||||
REGISTER = 0x400,
|
||||
SET_LLBIT = 0x800
|
||||
SET_LLBIT = 0x800,
|
||||
UNSET_LLBIT = 0x1000,
|
||||
};
|
||||
|
||||
enum Shift {
|
||||
@@ -26,7 +27,7 @@ struct Entry {
|
||||
LOADU16, LOADU16_SHIFT,
|
||||
LOADU32, LOADU32_SHIFT,
|
||||
LOADU64, LOADU64_SHIFT,
|
||||
BRANCH, JUMP,
|
||||
BRANCH, JUMP, MTC0, MFC0
|
||||
} op;
|
||||
|
||||
struct Operand {
|
||||
@@ -83,6 +84,7 @@ struct IR {
|
||||
void print();
|
||||
void optimize();
|
||||
private:
|
||||
void dead_code_elimination(std::vector<Entry>&);
|
||||
std::vector<Entry> code{};
|
||||
};
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <log.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
#include <core/Interpreter.hpp>
|
||||
#include <core/JIT.hpp>
|
||||
|
||||
namespace n64 {
|
||||
Cop0::Cop0() {
|
||||
@@ -336,7 +337,25 @@ template void Cop0::decode<Interpreter>(Interpreter&, u32);
|
||||
template void Cop0::decode<JIT>(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) {
|
||||
|
||||
Reference in New Issue
Block a user