Rename dynarec to JIT everywhere

This commit is contained in:
CocoSimone
2023-02-21 02:20:35 +01:00
parent 1c42170810
commit 030f04df03
25 changed files with 437 additions and 429 deletions

View File

@@ -0,0 +1,4 @@
file(GLOB_RECURSE SOURCES *.cpp)
file(GLOB_RECURSE HEADERS *.hpp)
add_library(jit ${SOURCES} ${HEADERS})

View File

@@ -0,0 +1,27 @@
#include <core/JIT.hpp>
namespace n64 {
void JIT::InvalidatePage(u32 paddr) {
blockCache[paddr >> 20] = nullptr;
}
void JIT::InvalidateCache() {
sizeUsed = 0;
for(int i = 0; i < 0x80000; i++) {
blockCache[i] = nullptr;
}
}
void* JIT::bumpAlloc(u64 size, u8 val) {
if(sizeUsed + size >= CODECACHE_SIZE) {
InvalidateCache();
}
void* ptr = &codeCache[sizeUsed];
sizeUsed += size;
memset(ptr, val, size);
return ptr;
}
}

View File

@@ -0,0 +1,64 @@
#include <jit/cop/cop0decode.hpp>
#include <jit/cop/cop0instructions.hpp>
#include <Registers.hpp>
namespace n64 {
void cop0Decode(Registers& regs, JIT& cpu, u32 instr) {
u8 mask_cop = (instr >> 21) & 0x1F;
u8 mask_cop2 = instr & 0x3F;
Xbyak::CodeGenerator& code = cpu.code;
switch(mask_cop) {
case 0x00:
code.mov(code.rsi, (u64)instr);
code.mov(code.rax, (u64)mfc0);
code.call(code.rax);
break;
case 0x01:
code.mov(code.rsi, (u64)instr);
code.mov(code.rax, (u64)dmfc0);
code.call(code.rax);
break;
case 0x04:
code.mov(code.rsi, (u64)instr);
code.mov(code.rax, (uintptr_t)mtc0);
code.call(code.rax);
break;
case 0x05:
code.mov(code.rsi, (u64)instr);
code.mov(code.rax, (u64)dmtc0);
code.call(code.rax);
break;
case 0x10 ... 0x1F:
switch(mask_cop2) {
case 0x01:
code.mov(code.rax, (u64)tlbr);
code.call(code.rax);
break;
case 0x02:
code.and_(code.dword[code.rdi + offsetof(Registers, cop0.index)], 0x3F);
code.mov(code.rsi, code.dword[code.rdi]);
code.mov(code.rax, (u64)tlbw);
code.call(code.rax);
break;
case 0x06:
code.mov(code.rax, (u64)regs.cop0.GetRandom());
code.mov(code.rsi, code.rax);
code.mov(code.rax, (u64)tlbw);
code.call(code.rax);
break;
case 0x08:
code.mov(code.rax, (u64)tlbp);
code.call(code.rax);
break;
case 0x18:
code.mov(code.rax, (u64)eret);
code.call(code.rax);
break;
default: Util::panic("Unimplemented COP0 function {} {} ({:08X}) ({:016lX})", mask_cop2 >> 3, mask_cop2 & 7, instr, regs.oldPC);
}
break;
default: Util::panic("Unimplemented COP0 instruction {} {}", mask_cop >> 4, mask_cop & 7);
}
}
}

View File

@@ -0,0 +1,7 @@
#pragma once
#include <JIT.hpp>
namespace n64 {
struct Registers;
void cop0Decode(Registers&, JIT& cpu, u32 instr);
}

View File

@@ -0,0 +1,89 @@
#include <jit/cop/cop0instructions.hpp>
#include <log.hpp>
#include <Registers.hpp>
namespace n64 {
void mtc0(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.cop0.SetReg32(RD(instr), regs.gpr[RT(instr)]);
}
void dmtc0(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.cop0.SetReg64(RD(instr), regs.gpr[RT(instr)]);
}
void mfc0(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.gpr[RT(instr)] = s32(regs.cop0.GetReg32(RD(instr)));
}
void dmfc0(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.gpr[RT(instr)] = s64(regs.cop0.GetReg64(RD(instr)));
}
void eret(JIT& cpu) {
Registers& regs = cpu.regs;
if(regs.cop0.status.erl) {
regs.SetPC64(regs.cop0.ErrorEPC);
regs.cop0.status.erl = false;
} else {
regs.SetPC64(regs.cop0.EPC);
regs.cop0.status.exl = false;
}
regs.cop0.llbit = false;
}
void tlbr(JIT& cpu) {
Registers& regs = cpu.regs;
u8 Index = regs.cop0.index & 0b111111;
if (Index >= 32) {
Util::panic("TLBR with TLB index {}", Index);
}
TLBEntry entry = regs.cop0.tlb[Index];
regs.cop0.entryHi.raw = entry.entryHi.raw;
regs.cop0.entryLo0.raw = entry.entryLo0.raw & 0x3FFFFFFF;
regs.cop0.entryLo1.raw = entry.entryLo1.raw & 0x3FFFFFFF;
regs.cop0.entryLo0.g = entry.global;
regs.cop0.entryLo1.g = entry.global;
regs.cop0.pageMask.raw = entry.pageMask.raw;
}
void tlbw(JIT& cpu, int index_) {
Registers& regs = cpu.regs;
PageMask page_mask = regs.cop0.pageMask;
u32 top = page_mask.mask & 0xAAA;
page_mask.mask = top | (top >> 1);
if(index_ >= 32) {
Util::panic("TLBWI with TLB index {}", index_);
}
regs.cop0.tlb[index_].entryHi.raw = regs.cop0.entryHi.raw;
regs.cop0.tlb[index_].entryHi.vpn2 &= ~page_mask.mask;
regs.cop0.tlb[index_].entryLo0.raw = regs.cop0.entryLo0.raw & 0x03FFFFFE;
regs.cop0.tlb[index_].entryLo1.raw = regs.cop0.entryLo1.raw & 0x03FFFFFE;
regs.cop0.tlb[index_].pageMask.raw = page_mask.raw;
regs.cop0.tlb[index_].global = regs.cop0.entryLo0.g && regs.cop0.entryLo1.g;
regs.cop0.tlb[index_].initialized = true;
}
void tlbp(JIT& cpu) {
Registers& regs = cpu.regs;
int match = -1;
TLBEntry* entry = TLBTryMatch(regs, regs.cop0.entryHi.raw, &match);
if(entry && match >= 0) {
regs.cop0.index = match;
} else {
regs.cop0.index = 0x80000000;
}
}
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include <JIT.hpp>
namespace n64 {
void mtc0(JIT&, u32);
void dmtc0(JIT&, u32);
void mfc0(JIT&, u32);
void dmfc0(JIT&, u32);
void eret(JIT&);
void tlbr(JIT&);
void tlbw(JIT&, int);
void tlbp(JIT&);
}

View File

@@ -0,0 +1,466 @@
#include <jit/cop/cop1decode.hpp>
#include <jit/instructions.hpp>
#include <Registers.hpp>
namespace n64 {
bool cop1Decode(Registers& regs, JIT& cpu, u32 instr) {
Xbyak::CodeGenerator& code = cpu.code;
u8 mask_sub = (instr >> 21) & 0x1F;
u8 mask_fun = instr & 0x3F;
u8 mask_branch = (instr >> 16) & 0x1F;
code.mov(code.rdi, (u64)&regs);
code.mov(code.esi, instr);
switch(mask_sub) {
// 000r_rccc
case 0x00:
code.mov(code.rax, (u64)mfc1);
code.call(code.rax);
break;
case 0x01:
code.mov(code.rax, (u64)dmfc1);
code.call(code.rax);
break;
case 0x02:
code.mov(code.rax, (u64)cfc1);
code.call(code.rax);
break;
case 0x03:
Util::panic("[RECOMPILER] FPU Reserved instruction exception!\n");
case 0x04:
code.mov(code.rax, (u64)mtc1);
code.call(code.rax);
break;
case 0x05:
code.mov(code.rax, (u64)dmtc1);
code.call(code.rax);
break;
case 0x06:
code.mov(code.rax, (u64)ctc1);
code.call(code.rax);
break;
case 0x07:
Util::panic("[RECOMPILER] FPU Reserved instruction exception!\n");
case 0x08:
switch(mask_branch) {
case 0:
code.mov(code.rdi, !regs.cop1.fcr31.compare);
code.mov(code.rax, (u64)b);
code.call(code.rax);
return true;
case 1:
code.mov(code.rdi, regs.cop1.fcr31.compare);
code.mov(code.rax, (u64)b);
code.call(code.rax);
return true;
case 2:
code.mov(code.rdi, !regs.cop1.fcr31.compare);
code.mov(code.rax, (u64)bl);
code.call(code.rax);
return true;
case 3:
code.mov(code.rdi, regs.cop1.fcr31.compare);
code.mov(code.rax, (u64)bl);
code.call(code.rax);
return true;
default: Util::panic("Undefined BC COP1 {:02X}\n", mask_branch);
}
break;
case 0x10: // s
switch(mask_fun) {
case 0x00:
code.mov(code.rax, (u64)adds);
code.call(code.rax);
break;
case 0x01:
code.mov(code.rax, (u64)subs);
code.call(code.rax);
break;
case 0x02:
code.mov(code.rax, (u64)muls);
code.call(code.rax);
break;
case 0x03:
code.mov(code.rax, (u64)divs);
code.call(code.rax);
break;
case 0x04:
code.mov(code.rax, (u64)sqrts);
code.call(code.rax);
break;
case 0x05:
code.mov(code.rax, (u64)abss);
code.call(code.rax);
break;
case 0x06:
code.mov(code.rax, (u64)movs);
code.call(code.rax);
break;
case 0x07:
code.mov(code.rax, (u64)negs);
code.call(code.rax);
break;
case 0x08:
code.mov(code.rax, (u64)roundls);
code.call(code.rax);
break;
case 0x09:
code.mov(code.rax, (u64)truncls);
code.call(code.rax);
break;
case 0x0A:
code.mov(code.rax, (u64)ceills);
code.call(code.rax);
break;
case 0x0B:
code.mov(code.rax, (u64)floorls);
code.call(code.rax);
break;
case 0x0C:
code.mov(code.rax, (u64)roundws);
code.call(code.rax);
break;
case 0x0D:
code.mov(code.rax, (u64)truncws);
code.call(code.rax);
break;
case 0x0E:
code.mov(code.rax, (u64)ceilws);
code.call(code.rax);
break;
case 0x0F:
code.mov(code.rax, (u64)floorws);
code.call(code.rax);
break;
case 0x20:
Util::panic("[RECOMPILER] FPU Reserved instruction exception!\n");
case 0x21:
code.mov(code.rax, (u64)cvtds);
code.call(code.rax);
break;
case 0x24:
code.mov(code.rax, (u64)cvtws);
code.call(code.rax);
break;
case 0x25:
code.mov(code.rax, (u64)cvtls);
code.call(code.rax);
break;
case 0x30:
code.mov(code.rax, (u64)ccond<float>);
code.mov(code.rdx, F);
code.call(code.rax);
break;
case 0x31:
code.mov(code.rax, (u64)ccond<float>);
code.mov(code.rdx, UN);
code.call(code.rax);
break;
case 0x32:
code.mov(code.rax, (u64)ccond<float>);
code.mov(code.rdx, EQ);
code.call(code.rax);
break;
case 0x33:
code.mov(code.rax, (u64)ccond<float>);
code.mov(code.rdx, UEQ);
code.call(code.rax);
break;
case 0x34:
code.mov(code.rax, (u64)ccond<float>);
code.mov(code.rdx, OLT);
code.call(code.rax);
break;
case 0x35:
code.mov(code.rax, (u64)ccond<float>);
code.mov(code.rdx, ULT);
code.call(code.rax);
break;
case 0x36:
code.mov(code.rax, (u64)ccond<float>);
code.mov(code.rdx, OLE);
code.call(code.rax);
break;
case 0x37:
code.mov(code.rax, (u64)ccond<float>);
code.mov(code.rdx, ULE);
code.call(code.rax);
break;
case 0x38:
code.mov(code.rax, (u64)ccond<float>);
code.mov(code.rdx, SF);
code.call(code.rax);
break;
case 0x39:
code.mov(code.rax, (u64)ccond<float>);
code.mov(code.rdx, NGLE);
code.call(code.rax);
break;
case 0x3A:
code.mov(code.rax, (u64)ccond<float>);
code.mov(code.rdx, SEQ);
code.call(code.rax);
break;
case 0x3B:
code.mov(code.rax, (u64)ccond<float>);
code.mov(code.rdx, NGL);
code.call(code.rax);
break;
case 0x3C:
code.mov(code.rax, (u64)ccond<float>);
code.mov(code.rdx, LT);
code.call(code.rax);
break;
case 0x3D:
code.mov(code.rax, (u64)ccond<float>);
code.mov(code.rdx, NGE);
code.call(code.rax);
break;
case 0x3E:
code.mov(code.rax, (u64)ccond<float>);
code.mov(code.rdx, LE);
code.call(code.rax);
break;
case 0x3F:
code.mov(code.rax, (u64)ccond<float>);
code.mov(code.rdx, NGT);
code.call(code.rax);
break;
default: Util::panic("Unimplemented COP1 function S[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
}
break;
case 0x11: // d
switch(mask_fun) {
case 0x00:
code.mov(code.rax, (u64)addd);
code.call(code.rax);
break;
case 0x01:
code.mov(code.rax, (u64)subd);
code.call(code.rax);
break;
case 0x02:
code.mov(code.rax, (u64)muld);
code.call(code.rax);
break;
case 0x03:
code.mov(code.rax, (u64)divd);
code.call(code.rax);
break;
case 0x04:
code.mov(code.rax, (u64)sqrtd);
code.call(code.rax);
break;
case 0x05:
code.mov(code.rax, (u64)absd);
code.call(code.rax);
break;
case 0x06:
code.mov(code.rax, (u64)movd);
code.call(code.rax);
break;
case 0x07:
code.mov(code.rax, (u64)negd);
code.call(code.rax);
break;
case 0x08:
code.mov(code.rax, (u64)roundld);
code.call(code.rax);
break;
case 0x09:
code.mov(code.rax, (u64)truncld);
code.call(code.rax);
break;
case 0x0A:
code.mov(code.rax, (u64)ceilld);
code.call(code.rax);
break;
case 0x0B:
code.mov(code.rax, (u64)floorld);
code.call(code.rax);
break;
case 0x0C:
code.mov(code.rax, (u64)roundwd);
code.call(code.rax);
break;
case 0x0D:
code.mov(code.rax, (u64)truncwd);
code.call(code.rax);
break;
case 0x0E:
code.mov(code.rax, (u64)ceilwd);
code.call(code.rax);
break;
case 0x0F:
code.mov(code.rax, (u64)floorwd);
code.call(code.rax);
break;
case 0x20:
code.mov(code.rax, (u64)cvtsd);
code.call(code.rax);
break;
case 0x21:
Util::panic("[RECOMPILER] FPU Reserved instruction exception!\n");
case 0x24:
code.mov(code.rax, (u64)cvtwd);
code.call(code.rax);
break;
case 0x25:
code.mov(code.rax, (u64)cvtld);
code.call(code.rax);
break;
case 0x30:
code.mov(code.rax, (u64)ccond<double>);
code.mov(code.rdx, F);
code.call(code.rax);
break;
case 0x31:
code.mov(code.rax, (u64)ccond<double>);
code.mov(code.rdx, UN);
code.call(code.rax);
break;
case 0x32:
code.mov(code.rax, (u64)ccond<double>);
code.mov(code.rdx, EQ);
code.call(code.rax);
break;
case 0x33:
code.mov(code.rax, (u64)ccond<double>);
code.mov(code.rdx, UEQ);
code.call(code.rax);
break;
case 0x34:
code.mov(code.rax, (u64)ccond<double>);
code.mov(code.rdx, OLT);
code.call(code.rax);
break;
case 0x35:
code.mov(code.rax, (u64)ccond<double>);
code.mov(code.rdx, ULT);
code.call(code.rax);
break;
case 0x36:
code.mov(code.rax, (u64)ccond<double>);
code.mov(code.rdx, OLE);
code.call(code.rax);
break;
case 0x37:
code.mov(code.rax, (u64)ccond<double>);
code.mov(code.rdx, ULE);
code.call(code.rax);
break;
case 0x38:
code.mov(code.rax, (u64)ccond<double>);
code.mov(code.rdx, SF);
code.call(code.rax);
break;
case 0x39:
code.mov(code.rax, (u64)ccond<double>);
code.mov(code.rdx, NGLE);
code.call(code.rax);
break;
case 0x3A:
code.mov(code.rax, (u64)ccond<double>);
code.mov(code.rdx, SEQ);
code.call(code.rax);
break;
case 0x3B:
code.mov(code.rax, (u64)ccond<double>);
code.mov(code.rdx, NGL);
code.call(code.rax);
break;
case 0x3C:
code.mov(code.rax, (u64)ccond<double>);
code.mov(code.rdx, LT);
code.call(code.rax);
break;
case 0x3D:
code.mov(code.rax, (u64)ccond<double>);
code.mov(code.rdx, NGE);
code.call(code.rax);
break;
case 0x3E:
code.mov(code.rax, (u64)ccond<double>);
code.mov(code.rdx, LE);
code.call(code.rax);
break;
case 0x3F:
code.mov(code.rax, (u64)ccond<double>);
code.mov(code.rdx, NGT);
code.call(code.rax);
break;
default: Util::panic("Unimplemented COP1 function D[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
}
break;
case 0x14: // w
switch(mask_fun) {
case 0x01:
code.mov(code.rax, (u64)subw);
code.call(code.rax);
break;
case 0x05:
code.mov(code.rax, (u64)absw);
code.call(code.rax);
break;
case 0x02:
code.mov(code.rax, (u64)mulw);
code.call(code.rax);
break;
case 0x06:
code.mov(code.rax, (u64)movw);
code.call(code.rax);
break;
case 0x20:
code.mov(code.rax, (u64)cvtsw);
code.call(code.rax);
break;
case 0x21:
code.mov(code.rax, (u64)cvtdw);
code.call(code.rax);
break;
case 0x24:
Util::panic("[RECOMPILER] FPU reserved instruction exception!\n");
default: Util::panic("Unimplemented COP1 function W[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
}
break;
case 0x15: // l
switch(mask_fun) {
case 0x01:
code.mov(code.rax, (u64)subl);
code.call(code.rax);
break;
case 0x05:
code.mov(code.rax, (u64)absl);
code.call(code.rax);
break;
case 0x02:
code.mov(code.rax, (u64)mull);
code.call(code.rax);
break;
case 0x06:
code.mov(code.rax, (u64)movl);
code.call(code.rax);
break;
case 0x20:
code.mov(code.rax, (u64)cvtsl);
code.call(code.rax);
break;
case 0x21:
code.mov(code.rax, (u64)cvtdl);
code.call(code.rax);
break;
case 0x24:
Util::panic("[RECOMPILER] FPU reserved instruction exception!\n");
case 0x25:
Util::panic("[RECOMPILER] FPU reserved instruction exception!\n");
default: Util::panic("Unimplemented COP1 function L[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
}
break;
default: Util::panic("Unimplemented COP1 instruction {} {}", mask_sub >> 3, mask_sub & 7);
}
return false;
}
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include <jit/cop/cop1instructions.hpp>
namespace n64 {
bool cop1Decode(Registers&, JIT& cpu, u32 instr);
}

View File

@@ -0,0 +1,619 @@
#include <jit/cop/cop1instructions.hpp>
#include <cfenv>
#include <cmath>
#include <Cop1.hpp>
#include <Registers.hpp>
namespace n64 {
inline int PushRoundingMode(const FCR31& fcr31) {
int og = fegetround();
switch(fcr31.rounding_mode) {
case 0: fesetround(FE_TONEAREST); break;
case 1: fesetround(FE_TOWARDZERO); break;
case 2: fesetround(FE_UPWARD); break;
case 3: fesetround(FE_DOWNWARD); break;
}
return og;
}
#define PUSHROUNDINGMODE int og = PushRoundingMode(regs.cop1.fcr31)
#define POPROUNDINGMODE fesetround(og)
#define checknanregs(fs, ft) do { \
if(std::isnan(fs) || std::isnan(ft)) { \
regs.cop1.fcr31.flag_invalid_operation = true; \
regs.cop1.fcr31.cause_invalid_operation = true; \
FireException(regs, ExceptionCode::FloatingPointError, 1, true); \
return; \
} \
} while(0)
void absd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
auto fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), std::abs(fs));
}
void abss(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
auto fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), std::abs(fs));
}
void absw(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
s32 fs = regs.cop1.GetReg<s32>(regs.cop0, FS(instr));
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), std::abs(fs));
}
void absl(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
s64 fs = regs.cop1.GetReg<s64>(regs.cop0, FS(instr));
regs.cop1.SetReg(regs.cop0, FD(instr), std::abs(fs));
}
void adds(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
auto fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
auto ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr));
checknanregs(fs, ft);
float result = fs + ft;
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), result);
}
void addd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
auto fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
auto ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr));
checknanregs(fs, ft);
double result = fs + ft;
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), result);
}
void ceills(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
auto fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
s64 result = std::ceil(fs);
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result);
}
void ceilws(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
auto fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
s32 result = std::ceil(fs);
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result);
}
void ceilld(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
auto fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
s64 result = std::ceil(fs);
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result);
}
void ceilwd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
auto fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
s32 result = std::ceil(fs);
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result);
}
void cfc1(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
u8 fd = RD(instr);
s32 val = 0;
switch(fd) {
case 0: val = regs.cop1.fcr0; break;
case 31: val = regs.cop1.fcr31.raw; break;
default: Util::panic("Undefined CFC1 with rd != 0 or 31\n");
}
regs.gpr[RT(instr)] = val;
}
void ctc1(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
u8 fs = FS(instr);
u32 val = regs.gpr[RT(instr)];
switch(fs) {
case 0: break;
case 31: {
val &= 0x183ffff;
regs.cop1.fcr31.raw = val;
} break;
default: Util::panic("Undefined CTC1 with rd != 0 or 31\n");
}
}
void cvtds(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.cop1.SetCop1Reg<double>(
regs.cop0,
FD(instr),
regs.cop1.GetCop1Reg<float>(
regs.cop0,
FS(instr)
)
);
}
void cvtsd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.cop1.SetCop1Reg<float>(
regs.cop0,
FD(instr),
regs.cop1.GetCop1Reg<double>(
regs.cop0,
FS(instr)
)
);
}
void cvtwd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.cop1.SetReg<u32>(
regs.cop0,
FD(instr),
regs.cop1.GetCop1Reg<double>(
regs.cop0,
FS(instr)
)
);
}
void cvtws(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.cop1.SetReg<u32>(
regs.cop0,
FD(instr),
regs.cop1.GetCop1Reg<float>(
regs.cop0,
FS(instr)
)
);
}
void cvtls(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.cop1.SetReg<u64>(
regs.cop0,
FD(instr),
regs.cop1.GetCop1Reg<float>(
regs.cop0,
FS(instr)
)
);
}
void cvtsl(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.cop1.SetCop1Reg<float>(
regs.cop0,
FD(instr),
(s64)regs.cop1.GetReg<u64>(
regs.cop0,
FS(instr)
)
);
}
void cvtdw(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.cop1.SetCop1Reg<double>(
regs.cop0,
FD(instr),
(s32)regs.cop1.GetReg<u32>(
regs.cop0,
FS(instr)
)
);
}
void cvtsw(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.cop1.SetCop1Reg<float>(
regs.cop0,
FD(instr),
(s32)regs.cop1.GetReg<u32>(
regs.cop0,
FS(instr)
)
);
}
void cvtdl(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.cop1.SetCop1Reg<double>(
regs.cop0,
FD(instr),
(s64)regs.cop1.GetReg<u64>(
regs.cop0,
FS(instr)
)
);
}
void cvtld(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.cop1.SetReg<u64>(
regs.cop0,
FD(instr),
regs.cop1.GetCop1Reg<double>(
regs.cop0,
FS(instr)
)
);
}
template <typename T>
inline bool CalculateCondition(JIT& cpu, T fs, T ft, CompConds cond) {
Registers& regs = cpu.regs;
switch(cond) {
case F: return false;
case UN: return std::isnan(fs) || std::isnan(ft);
case EQ: return fs == ft;
case UEQ: return (std::isnan(fs) || std::isnan(ft)) || (fs == ft);
case OLT: return (!std::isnan(fs) && !std::isnan(ft)) && (fs < ft);
case ULT: return (std::isnan(fs) || std::isnan(ft)) || (fs < ft);
case OLE: return (!std::isnan(fs) && !std::isnan(ft)) && (fs <= ft);
case ULE: return (std::isnan(fs) || std::isnan(ft)) || (fs <= ft);
default:
if(std::isnan(fs) || std::isnan(ft)) {
regs.cop1.fcr31.flag_invalid_operation = true;
regs.cop1.fcr31.cause_invalid_operation = true;
FireException(regs, ExceptionCode::FloatingPointError, 1, true);
return false;
}
return CalculateCondition(cpu, fs, ft, static_cast<CompConds>(cond - 8));
}
}
template <typename T>
void ccond(JIT& cpu, u32 instr, CompConds cond) {
Registers& regs = cpu.regs;
T fs = regs.cop1.GetCop1Reg<T>(regs.cop0, FS(instr));
T ft = regs.cop1.GetCop1Reg<T>(regs.cop0, FT(instr));
regs.cop1.fcr31.compare = CalculateCondition(cpu, fs, ft, cond);
}
template void ccond<float>(JIT& cpu, u32 instr, CompConds cond);
template void ccond<double>(JIT& cpu, u32 instr, CompConds cond);
void divs(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
float ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr));
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), fs / ft);
}
void divd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
double ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr));
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), fs / ft);
}
void muls(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
float ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr));
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), fs * ft);
}
void muld(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
double ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr));
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), fs * ft);
}
void mulw(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
u32 fs = regs.cop1.GetReg<u32>(regs.cop0, FS(instr));
u32 ft = regs.cop1.GetReg<u32>(regs.cop0, FT(instr));
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), fs * ft);
}
void mull(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
u64 fs = regs.cop1.GetReg<u64>(regs.cop0, FS(instr));
u64 ft = regs.cop1.GetReg<u64>(regs.cop0, FT(instr));
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), fs * ft);
}
void subs(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
float ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr));
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), fs - ft);
}
void subd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
double ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr));
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), fs - ft);
}
void subw(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
u32 fs = regs.cop1.GetReg<u32>(regs.cop0, FS(instr));
u32 ft = regs.cop1.GetReg<u32>(regs.cop0, FT(instr));
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), fs - ft);
}
void subl(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
u64 fs = regs.cop1.GetReg<u64>(regs.cop0, FS(instr));
u64 ft = regs.cop1.GetReg<u64>(regs.cop0, FT(instr));
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), fs - ft);
}
void movs(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.cop1.SetCop1Reg<float>(
regs.cop0,
FD(instr),
regs.cop1.GetCop1Reg<float>(
regs.cop0,
FS(instr)
)
);
}
void movd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.cop1.SetCop1Reg<double>(
regs.cop0,
FD(instr),
regs.cop1.GetCop1Reg<double>(
regs.cop0,
FS(instr)
)
);
}
void movw(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.cop1.SetReg<u32>(
regs.cop0,
FD(instr),
regs.cop1.GetReg<u32>(
regs.cop0,
FS(instr)
)
);
}
void movl(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.cop1.SetReg<u64>(
regs.cop0,
FD(instr),
regs.cop1.GetReg<u64>(
regs.cop0,
FS(instr)
)
);
}
void negs(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.cop1.SetCop1Reg<float>(
regs.cop0,
FD(instr),
-regs.cop1.GetCop1Reg<float>(
regs.cop0,
FS(instr)
)
);
}
void negd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.cop1.SetCop1Reg<double>(
regs.cop0,
FD(instr),
-regs.cop1.GetCop1Reg<double>(
regs.cop0,
FS(instr)
)
);
}
void sqrts(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), std::sqrt(fs));
}
void sqrtd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), std::sqrt(fs));
}
void roundls(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
PUSHROUNDINGMODE;
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s32)std::nearbyint(fs));
POPROUNDINGMODE;
}
void roundld(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
PUSHROUNDINGMODE;
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s64)std::nearbyint(fs));
POPROUNDINGMODE;
}
void roundws(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
PUSHROUNDINGMODE;
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s32)std::nearbyint(fs));
POPROUNDINGMODE;
}
void roundwd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
PUSHROUNDINGMODE;
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s32)std::nearbyint(fs));
POPROUNDINGMODE;
}
void floorls(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s64)std::floor(fs));
}
void floorld(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s64)std::floor(fs));
}
void floorws(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s64)std::floor(fs));
}
void floorwd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s64)std::floor(fs));
}
void lwc1(JIT& cpu, u32 instr) {
Mem& mem = cpu.mem;
Registers& regs = cpu.regs;
if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
return;
}
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
u32 physical;
if(!MapVAddr(regs, LOAD, addr, physical)) {
HandleTLBException(regs, addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else {
u32 data = mem.Read32(regs, physical);
regs.cop1.SetReg<u32>(regs.cop0, FT(instr), data);
}
}
void swc1(JIT& cpu, u32 instr) {
Mem& mem = cpu.mem;
Registers& regs = cpu.regs;
if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
return;
}
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
u32 physical;
if(!MapVAddr(regs, STORE, addr, physical)) {
HandleTLBException(regs, addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else {
mem.Write32(regs, physical, regs.cop1.GetReg<u32>(regs.cop0, FT(instr)));
}
}
void ldc1(JIT& cpu, u32 instr) {
Mem& mem = cpu.mem;
Registers& regs = cpu.regs;
if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
return;
}
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
u32 physical;
if(!MapVAddr(regs, LOAD, addr, physical)) {
HandleTLBException(regs, addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else {
u64 data = mem.Read64(regs, physical);
regs.cop1.SetReg<u64>(regs.cop0, FT(instr), data);
}
}
void sdc1(JIT& cpu, u32 instr) {
Mem& mem = cpu.mem;
Registers& regs = cpu.regs;
if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
return;
}
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
u32 physical;
if(!MapVAddr(regs, STORE, addr, physical)) {
HandleTLBException(regs, addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else {
mem.Write64(regs, physical, regs.cop1.GetReg<u64>(regs.cop0, FT(instr)));
}
}
void truncws(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
s32 result = (s32)std::trunc(fs);
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result);
}
void truncwd(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
s32 result = (s32)std::trunc(fs);
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result);
}
void truncls(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
s64 result = (s64)std::trunc(fs);
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result);
}
void truncld(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
s64 result = (s64)std::trunc(fs);
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result);
}
void mfc1(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.gpr[RT(instr)] = (s32)regs.cop1.GetReg<u32>(regs.cop0, FS(instr));
}
void dmfc1(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.gpr[RT(instr)] = (s64)regs.cop1.GetReg<u64>(regs.cop0, FS(instr));
}
void mtc1(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.cop1.SetReg<u32>(regs.cop0, FS(instr), regs.gpr[RT(instr)]);
}
void dmtc1(JIT& cpu, u32 instr) {
Registers& regs = cpu.regs;
regs.cop1.SetReg<u64>(regs.cop0, FS(instr), regs.gpr[RT(instr)]);
}
}

View File

@@ -0,0 +1,68 @@
#pragma once
#include <JIT.hpp>
#include <Cop1.hpp>
namespace n64 {
void absd(JIT&, u32 instr);
void abss(JIT&, u32 instr);
void absw(JIT&, u32 instr);
void absl(JIT&, u32 instr);
void adds(JIT&, u32 instr);
void addd(JIT&, u32 instr);
void subs(JIT&, u32 instr);
void subd(JIT&, u32 instr);
void subw(JIT&, u32 instr);
void subl(JIT&, u32 instr);
void ceills(JIT&, u32 instr);
void ceilws(JIT&, u32 instr);
void ceilld(JIT&, u32 instr);
void ceilwd(JIT&, u32 instr);
void cfc1(JIT&, u32 instr);
void ctc1(JIT&, u32 instr);
void roundls(JIT&, u32 instr);
void roundld(JIT&, u32 instr);
void roundws(JIT&, u32 instr);
void roundwd(JIT&, u32 instr);
void floorls(JIT&, u32 instr);
void floorld(JIT&, u32 instr);
void floorws(JIT&, u32 instr);
void floorwd(JIT&, u32 instr);
void cvtls(JIT&, u32 instr);
void cvtws(JIT&, u32 instr);
void cvtds(JIT&, u32 instr);
void cvtsw(JIT&, u32 instr);
void cvtdw(JIT&, u32 instr);
void cvtsd(JIT&, u32 instr);
void cvtwd(JIT&, u32 instr);
void cvtld(JIT&, u32 instr);
void cvtdl(JIT&, u32 instr);
void cvtsl(JIT&, u32 instr);
template <typename T>
void ccond(JIT&, u32 instr, CompConds);
void divs(JIT&, u32 instr);
void divd(JIT&, u32 instr);
void muls(JIT&, u32 instr);
void muld(JIT&, u32 instr);
void mulw(JIT&, u32 instr);
void mull(JIT&, u32 instr);
void movs(JIT&, u32 instr);
void movd(JIT&, u32 instr);
void movw(JIT&, u32 instr);
void movl(JIT&, u32 instr);
void negs(JIT&, u32 instr);
void negd(JIT&, u32 instr);
void sqrts(JIT&, u32 instr);
void sqrtd(JIT&, u32 instr);
void lwc1(JIT&, u32 instr);
void swc1(JIT&, u32 instr);
void ldc1(JIT&, u32 instr);
void mfc1(JIT&, u32 instr);
void dmfc1(JIT&, u32 instr);
void mtc1(JIT&, u32 instr);
void dmtc1(JIT&, u32 instr);
void sdc1(JIT&, u32 instr);
void truncws(JIT&, u32 instr);
void truncwd(JIT&, u32 instr);
void truncls(JIT&, u32 instr);
void truncld(JIT&, u32 instr);
}

View File

@@ -0,0 +1,794 @@
#include <jit/instructions.hpp>
#include <jit/cop/cop1decode.hpp>
#include <jit/cop/cop0decode.hpp>
#include <Registers.hpp>
namespace n64 {
void JIT::cop2Decode(u32 instr) {
code.mov(rdi, (u64)this);
code.mov(rsi, (u64)&regs);
code.mov(rdx, instr);
switch(RS(instr)) {
case 0x00:
code.mov(rax, (u64)mfc2);
code.call(rax);
break;
case 0x01:
code.mov(rax, (u64)dmfc2);
code.call(rax);
break;
case 0x02: case 0x06: break;
case 0x04:
code.mov(rax, (u64)mtc2);
code.call(rax);
break;
case 0x05:
code.mov(rax, (u64)dmtc2);
code.call(rax);
break;
default:
Util::panic("[RECOMPILER] Unhandled reserved instruction exception {:016X}\n", (u64)regs.pc);
}
}
bool JIT::special(u32 instr) {
u8 mask = (instr & 0x3F);
bool res = false;
// 00rr_rccc
switch (mask) { // TODO: named constants for clearer code
case 0:
if (instr != 0) {
code.mov(rsi, instr);
code.mov(rax, (u64)sll);
code.call(rax);
}
break;
case 0x02:
code.mov(rsi, instr);
code.mov(rax, (u64)srl);
code.call(rax);
break;
case 0x03:
code.mov(rsi, instr);
code.mov(rax, (u64)sra);
code.call(rax);
break;
case 0x04:
code.mov(rsi, instr);
code.mov(rax, (u64)sllv);
code.call(rax);
break;
case 0x06:
code.mov(rsi, instr);
code.mov(rax, (u64)srlv);
code.call(rax);
break;
case 0x07:
code.mov(rsi, instr);
code.mov(rax, (u64)srav);
code.call(rax);
break;
case 0x08:
code.mov(rsi, instr);
code.mov(rax, (u64)jr);
code.call(rax);
res = true;
break;
case 0x09:
code.mov(rsi, instr);
code.mov(rax, (u64)jalr);
code.call(rax);
res = true;
break;
case 0x0C: Util::print<Util::Error>("[RECOMPILER] Unhandled syscall instruction {:016X}\n", (u64)regs.pc); /*dumpCode.close();*/ exit(1);
case 0x0D: Util::panic("[RECOMPILER] Unhandled break instruction {:016X}\n", (u64)regs.pc);
case 0x0F: break; // SYNC
case 0x10:
code.mov(rsi, instr);
code.mov(rax, (u64)mfhi);
code.call(rax);
break;
case 0x11:
code.mov(rsi, instr);
code.mov(rax, (u64)mthi);
code.call(rax);
break;
case 0x12:
code.mov(rsi, instr);
code.mov(rax, (u64)mflo);
code.call(rax);
break;
case 0x13:
code.mov(rsi, instr);
code.mov(rax, (u64)mtlo);
code.call(rax);
break;
case 0x14:
code.mov(rsi, instr);
code.mov(rax, (u64)dsllv);
code.call(rax);
break;
case 0x16:
code.mov(rsi, instr);
code.mov(rax, (u64)dsrlv);
code.call(rax);
break;
case 0x17:
code.mov(rsi, instr);
code.mov(rax, (u64)dsrav);
code.call(rax);
break;
case 0x18:
code.mov(rsi, instr);
code.mov(rax, (u64)mult);
code.call(rax);
break;
case 0x19:
code.mov(rsi, instr);
code.mov(rax, (u64)multu);
code.call(rax);
break;
case 0x1A:
code.mov(rsi, instr);
code.mov(rax, (u64)div);
code.call(rax);
break;
case 0x1B:
code.mov(rsi, instr);
code.mov(rax, (u64)divu);
code.call(rax);
break;
case 0x1C:
code.mov(rsi, instr);
code.mov(rax, (u64)dmult);
code.call(rax);
break;
case 0x1D:
code.mov(rsi, instr);
code.mov(rax, (u64)dmultu);
code.call(rax);
break;
case 0x1E:
code.mov(rsi, instr);
code.mov(rax, (u64)ddiv);
code.call(rax);
break;
case 0x1F:
code.mov(rsi, instr);
code.mov(rax, (u64)ddivu);
code.call(rax);
break;
case 0x20:
code.mov(rsi, instr);
code.mov(rax, (u64)add);
code.call(rax);
break;
case 0x21:
code.mov(rsi, instr);
code.mov(rax, (u64)addu);
code.call(rax);
break;
case 0x22:
code.mov(rsi, instr);
code.mov(rax, (u64)sub);
code.call(rax);
break;
case 0x23:
code.mov(rsi, instr);
code.mov(rax, (u64)subu);
code.call(rax);
break;
case 0x24:
code.mov(rsi, instr);
code.mov(rax, (u64)and_);
code.call(rax);
break;
case 0x25:
code.mov(rsi, instr);
code.mov(rax, (u64)or_);
code.call(rax);
break;
case 0x26:
code.mov(rsi, instr);
code.mov(rax, (u64)xor_);
code.call(rax);
break;
case 0x27:
code.mov(rsi, instr);
code.mov(rax, (u64)nor);
code.call(rax);
break;
case 0x2A:
code.mov(rsi, instr);
code.mov(rax, (u64)slt);
code.call(rax);
break;
case 0x2B:
code.mov(rsi, instr);
code.mov(rax, (u64)sltu);
code.call(rax);
break;
case 0x2C:
code.mov(rsi, instr);
code.mov(rax, (u64)dadd);
code.call(rax);
break;
case 0x2D:
code.mov(rsi, instr);
code.mov(rax, (u64)daddu);
code.call(rax);
break;
case 0x2E:
code.mov(rsi, instr);
code.mov(rax, (u64)dsub);
code.call(rax);
break;
case 0x2F:
code.mov(rsi, instr);
code.mov(rax, (u64)dsubu);
code.call(rax);
break;
case 0x30:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]);
code.xor_(rsi, rsi);
code.cmp(r8, rcx);
code.setge(sil);
code.mov(rax, (u64)trap);
code.call(rax);
res = true;
break;
case 0x31:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]);
code.xor_(rsi, rsi);
code.cmp(r8, rcx);
code.setae(sil);
code.mov(rax, (u64)trap);
code.call(rax);
res = true;
break;
case 0x32:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]);
code.xor_(rsi, rsi);
code.cmp(r8, rcx);
code.setl(sil);
code.mov(rax, (u64)trap);
code.call(rax);
res = true;
break;
case 0x33:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]);
code.xor_(rsi, rsi);
code.cmp(r8, rcx);
code.setb(sil);
code.mov(rax, (u64)trap);
code.call(rax);
res = true;
break;
case 0x34:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]);
code.xor_(rsi, rsi);
code.cmp(r8, rcx);
code.sete(sil);
code.mov(rax, (u64)trap);
code.call(rax);
res = true;
break;
case 0x36:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]);
code.xor_(rsi, rsi);
code.cmp(r8, rcx);
code.setne(sil);
code.mov(rax, (u64)trap);
code.call(rax);
res = true;
break;
case 0x38:
code.mov(rsi, instr);
code.mov(rax, (u64)dsll);
code.call(rax);
break;
case 0x3A:
code.mov(rsi, instr);
code.mov(rax, (u64)dsrl);
code.call(rax);
break;
case 0x3B:
code.mov(rsi, instr);
code.mov(rax, (u64)dsra);
code.call(rax);
break;
case 0x3C:
code.mov(rsi, instr);
code.mov(rax, (u64)dsll32);
code.call(rax);
break;
case 0x3E:
code.mov(rsi, instr);
code.mov(rax, (u64)dsrl32);
code.call(rax);
break;
case 0x3F:
code.mov(rsi, instr);
code.mov(rax, (u64)dsra32);
code.call(rax);
break;
default:
Util::panic("Unimplemented special {} {} ({:08X}) (pc: {:016X})\n", (mask >> 3) & 7, mask & 7, instr, (u64)regs.oldPC);
}
return res;
}
bool JIT::regimm(u32 instr) {
u8 mask = ((instr >> 16) & 0x1F);
// 000r_rccc
switch (mask) { // TODO: named constants for clearer code
case 0x00:
code.mov(rsi, instr);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.xor_(rdx, rdx);
code.cmp(r8, 0);
code.setl(dl);
code.mov(rax, (u64)b);
code.call(rax);
break;
case 0x01:
code.mov(rsi, instr);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.xor_(rdx, rdx);
code.cmp(r8, 0);
code.setge(dl);
code.mov(rax, (u64)b);
code.call(rax);
break;
case 0x02:
code.mov(rsi, instr);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.xor_(rdx, rdx);
code.cmp(r8, 0);
code.setl(dl);
code.mov(rax, (u64)bl);
code.call(rax);
break;
case 0x03:
code.mov(rsi, instr);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.xor_(rdx, rdx);
code.cmp(r8, 0);
code.setge(dl);
code.mov(rax, (u64)bl);
code.call(rax);
break;
case 0x08:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.xor_(rsi, rsi);
code.cmp(r8, s64(s16(instr)));
code.setge(sil);
code.mov(rax, (u64)trap);
code.call(rax);
break;
case 0x09:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.xor_(rsi, rsi);
code.cmp(r8, u64(s64(s16(instr))));
code.setae(sil);
code.mov(rax, (u64)trap);
code.call(rax);
break;
case 0x0A:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.xor_(rsi, rsi);
code.cmp(r8, s64(s16(instr)));
code.setl(sil);
code.mov(rax, (u64)trap);
code.call(rax);
break;
case 0x0B:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.xor_(rsi, rsi);
code.cmp(r8, u64(s64(s16(instr))));
code.setb(sil);
code.mov(rax, (u64)trap);
code.call(rax);
break;
case 0x0C:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.xor_(rsi, rsi);
code.cmp(r8, s64(s16(instr)));
code.sete(sil);
code.mov(rax, (u64)trap);
code.call(rax);
break;
case 0x0E:
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.xor_(rsi, rsi);
code.cmp(r8, s64(s16(instr)));
code.setne(sil);
code.mov(rax, (u64)trap);
code.call(rax);
break;
case 0x10:
code.mov(rsi, instr);
code.mov(rcx, qword[rdi + GPR_OFFSET(RS(instr))]);
code.xor_(rdx, rdx);
code.cmp(rcx, 0);
code.setl(dl);
code.mov(rax, (u64)blink);
code.call(rax);
break;
case 0x11:
code.mov(rsi, instr);
code.mov(rcx, qword[rdi + GPR_OFFSET(RS(instr))]);
code.xor_(rdx, rdx);
code.cmp(rcx, 0);
code.setge(dl);
code.mov(rax, (u64)blink);
code.call(rax);
break;
case 0x12:
code.mov(rsi, instr);
code.mov(rcx, qword[rdi + GPR_OFFSET(RS(instr))]);
code.xor_(rdx, rdx);
code.cmp(rcx, 0);
code.setl(dl);
code.mov(rax, (u64)bllink);
code.call(rax);
break;
case 0x13:
code.mov(rsi, instr);
code.mov(rcx, qword[rdi + GPR_OFFSET(RS(instr))]);
code.xor_(rdx, rdx);
code.cmp(rcx, 0);
code.setge(dl);
code.mov(rax, (u64)bllink);
code.call(rax);
break;
default:
Util::panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})\n", (mask >> 3) & 3, mask & 7, instr, (u64)regs.oldPC);
}
return true;
}
bool JIT::Exec(Mem& mem, u32 instr) {
u8 mask = (instr >> 26) & 0x3f;
bool res = false;
// 00rr_rccc
switch(mask) { // TODO: named constants for clearer code
case 0x00: res = special(instr); break;
case 0x01: res = regimm(instr); break;
case 0x02:
code.mov(rsi, instr);
code.mov(rax, (u64)j);
code.call(rax);
res = true;
break;
case 0x03:
code.mov(rsi, instr);
code.mov(rax, (u64)jal);
code.call(rax);
res = true;
break;
case 0x04:
code.mov(rsi, instr);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]);
code.xor_(rdx, rdx);
code.cmp(r8, rcx);
code.sete(dl);
code.mov(rax, (u64)b);
code.call(rax);
res = true;
break;
case 0x05:
code.mov(rsi, instr);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]);
code.xor_(rdx, rdx);
code.cmp(r8, rcx);
code.setne(dl);
code.mov(rax, (u64)b);
code.call(rax);
res = true;
break;
case 0x06:
code.mov(rsi, instr);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.xor_(rdx, rdx);
code.test(r8, r8);
code.setnz(dl);
code.mov(rax, (u64)b);
code.call(rax);
res = true;
break;
case 0x07:
code.mov(rsi, instr);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.xor_(rdx, rdx);
code.test(r8, r8);
code.setg(dl);
code.mov(rax, (u64)b);
code.call(rax);
res = true;
break;
case 0x08:
code.mov(rsi, instr);
code.mov(rax, (u64)addi);
code.call(rax);
break;
case 0x09:
code.mov(rsi, instr);
code.mov(rax, (u64)addiu);
code.call(rax);
break;
case 0x0A:
code.mov(rsi, instr);
code.mov(rax, (u64)slti);
code.call(rax);
break;
case 0x0B:
code.mov(rsi, instr);
code.mov(rax, (u64)sltiu);
code.call(rax);
break;
case 0x0C:
code.mov(rsi, instr);
code.mov(rax, (u64)andi);
code.call(rax);
break;
case 0x0D:
code.mov(rsi, instr);
code.mov(rax, (u64)ori);
code.call(rax);
break;
case 0x0E:
code.mov(rsi, instr);
code.mov(rax, (u64)xori);
code.call(rax);
break;
case 0x0F:
code.mov(rsi, instr);
code.mov(rax, (u64)lui);
code.call(rax);
break;
case 0x10: cop0Decode(regs, *this, instr); break;
case 0x11: res = cop1Decode(regs, *this, instr); break;
case 0x12: cop2Decode(instr); break;
case 0x14:
code.mov(rsi, instr);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]);
code.xor_(rdx, rdx);
code.cmp(r8, rcx);
code.sete(dl);
code.mov(rax, (u64)bl);
code.call(rax);
break;
case 0x15:
code.mov(rsi, instr);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr))]);
code.xor_(rdx, rdx);
code.cmp(r8, rcx);
code.setne(dl);
code.mov(rax, (u64)bl);
code.call(rax);
break;
case 0x16:
code.mov(rsi, instr);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.xor_(rdx, rdx);
code.cmp(r8, 0);
code.setle(dl);
code.mov(rax, (u64)bl);
code.call(rax);
break;
case 0x17:
code.mov(rsi, instr);
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr))]);
code.xor_(rdx, rdx);
code.cmp(r8, 0);
code.setg(dl);
code.mov(rax, (u64)b);
code.call(rax);
break;
case 0x18:
code.mov(rsi, instr);
code.mov(rax, (u64)daddi);
code.call(rax);
break;
case 0x19:
code.mov(rsi, instr);
code.mov(rax, (u64)daddiu);
code.call(rax);
break;
case 0x1A:
code.mov(rsi, (u64)&mem);
code.mov(rdx, instr);
code.mov(rax, (u64)ldl);
code.call(rax);
break;
case 0x1B:
code.mov(rsi, (u64)&mem);
code.mov(rdx, instr);
code.mov(rax, (u64)ldr);
code.call(rax);
break;
case 0x1F: Util::panic("[RECOMPILER] Unhandled reserved instruction exception {:016X}\n", regs.oldPC); break;
case 0x20:
code.mov(rsi, (u64)&mem);
code.mov(rdx, instr);
code.mov(rax, (u64)lb);
code.call(rax);
break;
case 0x21:
code.mov(rsi, (u64)&mem);
code.mov(rdx, instr);
code.mov(rax, (u64)lh);
code.call(rax);
break;
case 0x22:
code.mov(rsi, (u64)&mem);
code.mov(rdx, instr);
code.mov(rax, (u64)lwl);
code.call(rax);
break;
case 0x23:
code.mov(rsi, (u64)&mem);
code.mov(rdx, instr);
code.mov(rax, (u64)lw);
code.call(rax);
break;
case 0x24:
code.mov(rsi, (u64)&mem);
code.mov(rdx, instr);
code.mov(rax, (u64)lbu);
code.call(rax);
break;
case 0x25:
code.mov(rsi, (u64)&mem);
code.mov(rdx, instr);
code.mov(rax, (u64)lhu);
code.call(rax);
break;
case 0x26:
code.mov(rsi, (u64)&mem);
code.mov(rdx, instr);
code.mov(rax, (u64)lwr);
code.call(rax);
break;
case 0x27:
code.mov(rsi, (u64)&mem);
code.mov(rdx, instr);
code.mov(rax, (u64)lwu);
code.call(rax);
break;
case 0x28:
code.mov(rsi, (u64)&mem);
code.mov(rdx, (u64)this);
code.mov(rcx, instr);
code.mov(rax, (u64)sb);
code.call(rax);
break;
case 0x29:
code.mov(rsi, (u64)&mem);
code.mov(rdx, (u64)this);
code.mov(rcx, instr);
code.mov(rax, (u64)sh);
code.call(rax);
break;
case 0x2A:
code.mov(rsi, (u64)&mem);
code.mov(rdx, (u64)this);
code.mov(rcx, instr);
code.mov(rax, (u64)swl);
code.call(rax);
break;
case 0x2B:
code.mov(rsi, (u64)&mem);
code.mov(rdx, (u64)this);
code.mov(rcx, instr);
code.mov(rax, (u64)sw);
code.call(rax);
break;
case 0x2C:
code.mov(rsi, (u64)&mem);
code.mov(rdx, (u64)this);
code.mov(rcx, instr);
code.mov(rax, (u64)sdl);
code.call(rax);
break;
case 0x2D:
code.mov(rsi, (u64)&mem);
code.mov(rdx, (u64)this);
code.mov(rcx, instr);
code.mov(rax, (u64)sdr);
code.call(rax);
break;
case 0x2E:
code.mov(rsi, (u64)&mem);
code.mov(rdx, (u64)this);
code.mov(rcx, instr);
code.mov(rax, (u64)swr);
code.call(rax);
break;
case 0x2F: break; // CACHE
case 0x30:
code.mov(rsi, (u64)&mem);
code.mov(rdx, instr);
code.mov(rax, (u64)ll);
code.call(rax);
break;
case 0x31:
code.mov(rsi, (u64)&mem);
code.mov(rdx, instr);
code.mov(rax, (u64)lwc1);
code.call(rax);
break;
case 0x34:
code.mov(rsi, (u64)&mem);
code.mov(rdx, instr);
code.mov(rax, (u64)lld);
code.call(rax);
break;
case 0x35:
code.mov(rsi, (u64)&mem);
code.mov(rdx, instr);
code.mov(rax, (u64)ldc1);
code.call(rax);
break;
case 0x37:
code.mov(rsi, (u64)&mem);
code.mov(rdx, instr);
code.mov(rax, (u64)ld);
code.call(rax);
break;
case 0x38:
code.mov(rsi, (u64)&mem);
code.mov(rdx, (u64)this);
code.mov(rcx, instr);
code.mov(rax, (u64)sc);
code.call(rax);
break;
case 0x39:
code.mov(rsi, (u64)&mem);
code.mov(rdx, instr);
code.mov(rax, (u64)swc1);
code.call(rax);
break;
case 0x3C:
code.mov(rsi, (u64)&mem);
code.mov(rdx, (u64)this);
code.mov(rcx, instr);
code.mov(rax, (u64)scd);
code.call(rax);
break;
case 0x3D:
code.mov(rsi, (u64)&mem);
code.mov(rdx, instr);
code.mov(rax, (u64)sdc1);
code.call(rax);
break;
case 0x3F:
code.mov(rsi, (u64)&mem);
code.mov(rdx, (u64)this);
code.mov(rcx, instr);
code.mov(rax, (u64)sd);
code.call(rax);
break;
default:
Util::panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})\n", mask, instr, (u64)regs.oldPC);
}
return res;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,94 @@
#pragma once
#include <JIT.hpp>
namespace n64 {
void add(JIT&, u32);
void addu(JIT&, u32);
void addi(JIT&, u32);
void addiu(JIT&, u32);
void andi(JIT&, u32);
void and_(JIT&, u32);
void branch(JIT&, bool, s64);
void branch_likely(JIT&, bool, s64);
void b(JIT&, u32, bool);
void blink(JIT&, u32, bool);
void bl(JIT&, u32, bool);
void bllink(JIT&, u32, bool);
void dadd(JIT&, u32);
void daddu(JIT&, u32);
void daddi(JIT&, u32);
void daddiu(JIT&, u32);
void ddiv(JIT&, u32);
void ddivu(JIT&, u32);
void div(JIT&, u32);
void divu(JIT&, u32);
void dmult(JIT&, u32);
void dmultu(JIT&, u32);
void dsll(JIT&, u32);
void dsllv(JIT&, u32);
void dsll32(JIT&, u32);
void dsra(JIT&, u32);
void dsrav(JIT&, u32);
void dsra32(JIT&, u32);
void dsrl(JIT&, u32);
void dsrlv(JIT&, u32);
void dsrl32(JIT&, u32);
void dsub(JIT&, u32);
void dsubu(JIT&, u32);
void j(JIT&, u32);
void jr(JIT&, u32);
void jal(JIT&, u32);
void jalr(JIT&, u32);
void lui(JIT&, u32);
void lbu(JIT&, u32);
void lb(JIT&, u32);
void ld(JIT&, u32);
void ldl(JIT&, u32);
void ldr(JIT&, u32);
void lh(JIT&, u32);
void lhu(JIT&, u32);
void ll(JIT&, u32);
void lld(JIT&, u32);
void lw(JIT&, u32);
void lwl(JIT&, u32);
void lwu(JIT&, u32);
void lwr(JIT&, u32);
void mfhi(JIT&, u32);
void mflo(JIT&, u32);
void mult(JIT&, u32);
void multu(JIT&, u32);
void mthi(JIT&, u32);
void mtlo(JIT&, u32);
void nor(JIT&, u32);
void sb(JIT&, u32);
void sc(JIT&, u32);
void scd(JIT&, u32);
void sd(JIT&, u32);
void sdl(JIT&, u32);
void sdr(JIT&, u32);
void sh(JIT&, u32);
void sw(JIT&, u32);
void swl(JIT&, u32);
void swr(JIT&, u32);
void slti(JIT&, u32);
void sltiu(JIT&, u32);
void slt(JIT&, u32);
void sltu(JIT&, u32);
void sll(JIT&, u32);
void sllv(JIT&, u32);
void sub(JIT&, u32);
void subu(JIT&, u32);
void sra(JIT&, u32);
void srav(JIT&, u32);
void srl(JIT&, u32);
void srlv(JIT&, u32);
void trap(JIT&, bool);
void or_(JIT&, u32);
void ori(JIT&, u32);
void xor_(JIT&, u32);
void xori(JIT&, u32);
void mtc2(JIT&, u32);
void mfc2(JIT&, u32);
void dmtc2(JIT&, u32);
void dmfc2(JIT&, u32);
}