Rename dynarec to JIT everywhere
This commit is contained in:
4
src/backend/core/jit/CMakeLists.txt
Normal file
4
src/backend/core/jit/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
file(GLOB_RECURSE SOURCES *.cpp)
|
||||
file(GLOB_RECURSE HEADERS *.hpp)
|
||||
|
||||
add_library(jit ${SOURCES} ${HEADERS})
|
||||
27
src/backend/core/jit/MemoryManagement.cpp
Normal file
27
src/backend/core/jit/MemoryManagement.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
64
src/backend/core/jit/cop/cop0decode.cpp
Normal file
64
src/backend/core/jit/cop/cop0decode.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
7
src/backend/core/jit/cop/cop0decode.hpp
Normal file
7
src/backend/core/jit/cop/cop0decode.hpp
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include <JIT.hpp>
|
||||
|
||||
namespace n64 {
|
||||
struct Registers;
|
||||
void cop0Decode(Registers&, JIT& cpu, u32 instr);
|
||||
}
|
||||
89
src/backend/core/jit/cop/cop0instructions.cpp
Normal file
89
src/backend/core/jit/cop/cop0instructions.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
13
src/backend/core/jit/cop/cop0instructions.hpp
Normal file
13
src/backend/core/jit/cop/cop0instructions.hpp
Normal 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&);
|
||||
}
|
||||
466
src/backend/core/jit/cop/cop1decode.cpp
Normal file
466
src/backend/core/jit/cop/cop1decode.cpp
Normal 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)®s);
|
||||
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;
|
||||
}
|
||||
}
|
||||
6
src/backend/core/jit/cop/cop1decode.hpp
Normal file
6
src/backend/core/jit/cop/cop1decode.hpp
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include <jit/cop/cop1instructions.hpp>
|
||||
|
||||
namespace n64 {
|
||||
bool cop1Decode(Registers&, JIT& cpu, u32 instr);
|
||||
}
|
||||
619
src/backend/core/jit/cop/cop1instructions.cpp
Normal file
619
src/backend/core/jit/cop/cop1instructions.cpp
Normal 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)]);
|
||||
}
|
||||
}
|
||||
68
src/backend/core/jit/cop/cop1instructions.hpp
Normal file
68
src/backend/core/jit/cop/cop1instructions.hpp
Normal 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);
|
||||
}
|
||||
794
src/backend/core/jit/decode.cpp
Normal file
794
src/backend/core/jit/decode.cpp
Normal 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)®s);
|
||||
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;
|
||||
}
|
||||
}
|
||||
1010
src/backend/core/jit/instructions.cpp
Normal file
1010
src/backend/core/jit/instructions.cpp
Normal file
File diff suppressed because it is too large
Load Diff
94
src/backend/core/jit/instructions.hpp
Normal file
94
src/backend/core/jit/instructions.hpp
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user