Some restructuring
This commit is contained in:
@@ -17,8 +17,6 @@ struct CodeGenerator : Xbyak::CodeGenerator {
|
|||||||
CodeGenerator() : Xbyak::CodeGenerator{kCodeCacheSize} {}
|
CodeGenerator() : Xbyak::CodeGenerator{kCodeCacheSize} {}
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BranchCondition { EQ, NE, GT, GE, LT, LE, GTU, GEU, LTU, LEU };
|
|
||||||
|
|
||||||
struct JIT : BaseCPU {
|
struct JIT : BaseCPU {
|
||||||
explicit JIT(ParallelRDP &);
|
explicit JIT(ParallelRDP &);
|
||||||
~JIT() override = default;
|
~JIT() override = default;
|
||||||
@@ -42,6 +40,47 @@ private:
|
|||||||
u64 cop2Latch{};
|
u64 cop2Latch{};
|
||||||
friend struct Cop1;
|
friend struct Cop1;
|
||||||
|
|
||||||
|
|
||||||
|
// Credits to PCSX-Redux: https://github.com/grumpycoders/pcsx-redux
|
||||||
|
// Sets dest to "pointer"
|
||||||
|
void loadAddress(const Xbyak::Reg64 dest, void *pointer) { code.mov(dest, reinterpret_cast<uintptr_t>(pointer)); }
|
||||||
|
|
||||||
|
// Load a pointer to the JIT object in "reg"
|
||||||
|
void loadThisPointer(const Xbyak::Reg64 reg) { code.mov(reg, code.rbp); }
|
||||||
|
// Emit a call to a class member function, passing "thisObject" (+ an adjustment if necessary)
|
||||||
|
// As the function's "this" pointer. Only works with classes with single, non-virtual inheritance
|
||||||
|
// Hence the static asserts. Those are all we need though, thankfully.
|
||||||
|
template <typename T>
|
||||||
|
void emitMemberFunctionCall(T func, void *thisObject) {
|
||||||
|
void *functionPtr;
|
||||||
|
auto thisPtr = reinterpret_cast<uintptr_t>(thisObject);
|
||||||
|
|
||||||
|
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
|
||||||
|
static_assert(sizeof(T) == 8, "[x64 JIT] Invalid size for member function pointer");
|
||||||
|
std::memcpy(&functionPtr, &func, sizeof(T));
|
||||||
|
#else
|
||||||
|
static_assert(sizeof(T) == 16, "[x64 JIT] Invalid size for member function pointer");
|
||||||
|
uintptr_t arr[2];
|
||||||
|
std::memcpy(arr, &func, sizeof(T));
|
||||||
|
// First 8 bytes correspond to the actual pointer to the function
|
||||||
|
functionPtr = reinterpret_cast<void *>(arr[0]);
|
||||||
|
// Next 8 bytes correspond to the "this" pointer adjustment
|
||||||
|
thisPtr += arr[1];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Load this pointer to arg1
|
||||||
|
if (thisPtr == reinterpret_cast<uintptr_t>(this)) {
|
||||||
|
loadThisPointer(code.rdi);
|
||||||
|
} else {
|
||||||
|
loadAddress(code.rdi, reinterpret_cast<void *>(thisPtr));
|
||||||
|
}
|
||||||
|
|
||||||
|
code.call(functionPtr);
|
||||||
|
}
|
||||||
|
void SkipSlot();
|
||||||
|
void BranchTaken(s64 offs);
|
||||||
|
void BranchTaken(const Xbyak::Reg &offs);
|
||||||
|
|
||||||
#define check_address_error(mask, vaddr) \
|
#define check_address_error(mask, vaddr) \
|
||||||
(((!regs.cop0.is64BitAddressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0))
|
(((!regs.cop0.is64BitAddressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0))
|
||||||
|
|
||||||
@@ -59,14 +98,30 @@ private:
|
|||||||
void addiu(u32);
|
void addiu(u32);
|
||||||
void andi(u32);
|
void andi(u32);
|
||||||
void and_(u32);
|
void and_(u32);
|
||||||
void b(u32 instr, BranchCondition, u32 reg1, u32 reg2);
|
void branch(const Xbyak::Reg &address);
|
||||||
void b(u32 instr, BranchCondition, u32 reg);
|
void branch_likely(const Xbyak::Reg &address);
|
||||||
void blink(u32 instr, BranchCondition, u32 reg1, u32 reg2);
|
void branch_constant(const bool cond, const s64 address);
|
||||||
void blink(u32 instr, BranchCondition, u32 reg);
|
void branch_likely_constant(const bool cond, const s64 address);
|
||||||
void bl(u32 instr, BranchCondition, u32 reg1, u32 reg2);
|
void bltz(u32);
|
||||||
void bl(u32 instr, BranchCondition, u32 reg);
|
void bgez(u32);
|
||||||
void bllink(u32 instr, BranchCondition, u32 reg1, u32 reg2);
|
void bltzl(u32);
|
||||||
void bllink(u32 instr, BranchCondition, u32 reg);
|
void bgezl(u32);
|
||||||
|
void bltzal(u32);
|
||||||
|
void bgezal(u32);
|
||||||
|
void bltzall(u32);
|
||||||
|
void bgezall(u32);
|
||||||
|
void beq(u32);
|
||||||
|
void beql(u32);
|
||||||
|
void bne(u32);
|
||||||
|
void bnel(u32);
|
||||||
|
void blez(u32);
|
||||||
|
void blezl(u32);
|
||||||
|
void bgtz(u32);
|
||||||
|
void bgtzl(u32);
|
||||||
|
void bfc1(u32 instr);
|
||||||
|
void blfc1(u32 instr);
|
||||||
|
void bfc0(u32 instr);
|
||||||
|
void blfc0(u32 instr);
|
||||||
void dadd(u32);
|
void dadd(u32);
|
||||||
void daddu(u32);
|
void daddu(u32);
|
||||||
void daddi(u32);
|
void daddi(u32);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <core/registers/Cop0.hpp>
|
#include <registers/Cop0.hpp>
|
||||||
#include <core/registers/Registers.hpp>
|
#include <registers/Registers.hpp>
|
||||||
#include <log.hpp>
|
#include <log.hpp>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
#include <cfenv>
|
#include <cfenv>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <core/Interpreter.hpp>
|
#include <Interpreter.hpp>
|
||||||
#include <core/registers/Cop1.hpp>
|
#include <registers/Cop1.hpp>
|
||||||
#include <core/registers/Registers.hpp>
|
#include <registers/Registers.hpp>
|
||||||
#include <utils/FloatingPoint.hpp>
|
#include <utils/FloatingPoint.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
@@ -1220,71 +1220,7 @@ void Cop1::truncld(const u32 instr) {
|
|||||||
FGR_D<s64>(regs.cop0.status, FD(instr)) = fd;
|
FGR_D<s64>(regs.cop0.status, FD(instr)) = fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
void Cop1::lwc1(Mem &mem, u32 instr) {
|
||||||
void Cop1::lwc1(T &cpu, Mem &mem, u32 instr) {
|
|
||||||
if constexpr (std::is_same_v<decltype(cpu), Interpreter &>) {
|
|
||||||
if (!CheckFPUUsable<true>())
|
|
||||||
return;
|
|
||||||
lwc1Interp(mem, instr);
|
|
||||||
} else if constexpr (std::is_same_v<decltype(cpu), JIT &>) {
|
|
||||||
lwc1JIT(cpu, mem, instr);
|
|
||||||
} else {
|
|
||||||
Util::panic("What the fuck did you just give me?!!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template void Cop1::lwc1<Interpreter>(Interpreter &, Mem &, u32);
|
|
||||||
template void Cop1::lwc1<JIT>(JIT &, Mem &, u32);
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void Cop1::swc1(T &cpu, Mem &mem, u32 instr) {
|
|
||||||
if constexpr (std::is_same_v<decltype(cpu), Interpreter &>) {
|
|
||||||
if (!CheckFPUUsable<true>())
|
|
||||||
return;
|
|
||||||
swc1Interp(mem, instr);
|
|
||||||
} else if constexpr (std::is_same_v<decltype(cpu), JIT &>) {
|
|
||||||
swc1JIT(cpu, mem, instr);
|
|
||||||
} else {
|
|
||||||
Util::panic("What the fuck did you just give me?!!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template void Cop1::swc1<Interpreter>(Interpreter &, Mem &, u32);
|
|
||||||
template void Cop1::swc1<JIT>(JIT &, Mem &, u32);
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void Cop1::ldc1(T &cpu, Mem &mem, u32 instr) {
|
|
||||||
if constexpr (std::is_same_v<decltype(cpu), Interpreter &>) {
|
|
||||||
if (!CheckFPUUsable<true>())
|
|
||||||
return;
|
|
||||||
ldc1Interp(mem, instr);
|
|
||||||
} else if constexpr (std::is_same_v<decltype(cpu), JIT &>) {
|
|
||||||
ldc1JIT(cpu, mem, instr);
|
|
||||||
} else {
|
|
||||||
Util::panic("What the fuck did you just give me?!!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template void Cop1::ldc1<Interpreter>(Interpreter &, Mem &, u32);
|
|
||||||
template void Cop1::ldc1<JIT>(JIT &, Mem &, u32);
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void Cop1::sdc1(T &cpu, Mem &mem, u32 instr) {
|
|
||||||
if constexpr (std::is_same_v<decltype(cpu), Interpreter &>) {
|
|
||||||
if (!CheckFPUUsable<true>())
|
|
||||||
return;
|
|
||||||
sdc1Interp(mem, instr);
|
|
||||||
} else if constexpr (std::is_same_v<decltype(cpu), JIT &>) {
|
|
||||||
sdc1JIT(cpu, mem, instr);
|
|
||||||
} else {
|
|
||||||
Util::panic("What the fuck did you just give me?!!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template void Cop1::sdc1<Interpreter>(Interpreter &, Mem &, u32);
|
|
||||||
template void Cop1::sdc1<JIT>(JIT &, Mem &, u32);
|
|
||||||
|
|
||||||
void Cop1::lwc1Interp(Mem &mem, const u32 instr) {
|
|
||||||
const u64 addr = static_cast<s64>(static_cast<s16>(instr)) + regs.Read<s64>(BASE(instr));
|
const u64 addr = static_cast<s64>(static_cast<s16>(instr)) + regs.Read<s64>(BASE(instr));
|
||||||
|
|
||||||
if (u32 physical; !regs.cop0.MapVAddr(Cop0::LOAD, addr, physical)) {
|
if (u32 physical; !regs.cop0.MapVAddr(Cop0::LOAD, addr, physical)) {
|
||||||
@@ -1296,7 +1232,7 @@ void Cop1::lwc1Interp(Mem &mem, const u32 instr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::swc1Interp(Mem &mem, const u32 instr) {
|
void Cop1::swc1(Mem &mem, u32 instr) {
|
||||||
const u64 addr = static_cast<s64>(static_cast<s16>(instr)) + regs.Read<s64>(BASE(instr));
|
const u64 addr = static_cast<s64>(static_cast<s16>(instr)) + regs.Read<s64>(BASE(instr));
|
||||||
|
|
||||||
if (u32 physical; !regs.cop0.MapVAddr(Cop0::STORE, addr, physical)) {
|
if (u32 physical; !regs.cop0.MapVAddr(Cop0::STORE, addr, physical)) {
|
||||||
@@ -1307,14 +1243,7 @@ void Cop1::swc1Interp(Mem &mem, const u32 instr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::unimplemented() {
|
void Cop1::ldc1(Mem &mem, u32 instr) {
|
||||||
if (!CheckFPUUsable())
|
|
||||||
return;
|
|
||||||
SetCauseUnimplemented();
|
|
||||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cop1::ldc1Interp(Mem &mem, const u32 instr) {
|
|
||||||
const u64 addr = static_cast<s64>(static_cast<s16>(instr)) + regs.Read<s64>(BASE(instr));
|
const u64 addr = static_cast<s64>(static_cast<s16>(instr)) + regs.Read<s64>(BASE(instr));
|
||||||
|
|
||||||
if (u32 physical; !regs.cop0.MapVAddr(Cop0::LOAD, addr, physical)) {
|
if (u32 physical; !regs.cop0.MapVAddr(Cop0::LOAD, addr, physical)) {
|
||||||
@@ -1326,7 +1255,7 @@ void Cop1::ldc1Interp(Mem &mem, const u32 instr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cop1::sdc1Interp(Mem &mem, const u32 instr) {
|
void Cop1::sdc1(Mem &mem, u32 instr) {
|
||||||
const u64 addr = static_cast<s64>(static_cast<s16>(instr)) + regs.Read<s64>(BASE(instr));
|
const u64 addr = static_cast<s64>(static_cast<s16>(instr)) + regs.Read<s64>(BASE(instr));
|
||||||
|
|
||||||
if (u32 physical; !regs.cop0.MapVAddr(Cop0::STORE, addr, physical)) {
|
if (u32 physical; !regs.cop0.MapVAddr(Cop0::STORE, addr, physical)) {
|
||||||
@@ -1337,6 +1266,13 @@ void Cop1::sdc1Interp(Mem &mem, const u32 instr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Cop1::unimplemented() {
|
||||||
|
if (!CheckFPUUsable())
|
||||||
|
return;
|
||||||
|
SetCauseUnimplemented();
|
||||||
|
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||||
|
}
|
||||||
|
|
||||||
void Cop1::mfc1(const u32 instr) {
|
void Cop1::mfc1(const u32 instr) {
|
||||||
if (!CheckFPUUsable<true>())
|
if (!CheckFPUUsable<true>())
|
||||||
return;
|
return;
|
||||||
@@ -304,7 +304,38 @@ void Interpreter::Exec(const u32 instr) {
|
|||||||
regs.cop0.decode(*this, instr);
|
regs.cop0.decode(*this, instr);
|
||||||
break;
|
break;
|
||||||
case COP1:
|
case COP1:
|
||||||
regs.cop1.decode(*this, instr);
|
{
|
||||||
|
const u8 mask_sub = (instr >> 21) & 0x1F;
|
||||||
|
const u8 mask_branch = (instr >> 16) & 0x1F;
|
||||||
|
if (mask_sub == 0x08) {
|
||||||
|
switch (mask_branch) {
|
||||||
|
case 0:
|
||||||
|
if (!regs.cop1.CheckFPUUsable())
|
||||||
|
return;
|
||||||
|
b(instr, !regs.cop1.fcr31.compare);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (!regs.cop1.CheckFPUUsable())
|
||||||
|
return;
|
||||||
|
b(instr, regs.cop1.fcr31.compare);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (!regs.cop1.CheckFPUUsable())
|
||||||
|
return;
|
||||||
|
bl(instr, !regs.cop1.fcr31.compare);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (!regs.cop1.CheckFPUUsable())
|
||||||
|
return;
|
||||||
|
bl(instr, regs.cop1.fcr31.compare);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Util::panic("Undefined BC COP1 {:02X}", mask_branch);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
regs.cop1.decode(instr);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case COP2:
|
case COP2:
|
||||||
cop2Decode(instr);
|
cop2Decode(instr);
|
||||||
@@ -387,13 +418,13 @@ void Interpreter::Exec(const u32 instr) {
|
|||||||
ll(instr);
|
ll(instr);
|
||||||
break;
|
break;
|
||||||
case LWC1:
|
case LWC1:
|
||||||
regs.cop1.lwc1(*this, mem, instr);
|
regs.cop1.lwc1(mem, instr);
|
||||||
break;
|
break;
|
||||||
case LLD:
|
case LLD:
|
||||||
lld(instr);
|
lld(instr);
|
||||||
break;
|
break;
|
||||||
case LDC1:
|
case LDC1:
|
||||||
regs.cop1.ldc1(*this, mem, instr);
|
regs.cop1.ldc1(mem, instr);
|
||||||
break;
|
break;
|
||||||
case LD:
|
case LD:
|
||||||
ld(instr);
|
ld(instr);
|
||||||
@@ -402,13 +433,13 @@ void Interpreter::Exec(const u32 instr) {
|
|||||||
sc(instr);
|
sc(instr);
|
||||||
break;
|
break;
|
||||||
case SWC1:
|
case SWC1:
|
||||||
regs.cop1.swc1(*this, mem, instr);
|
regs.cop1.swc1(mem, instr);
|
||||||
break;
|
break;
|
||||||
case SCD:
|
case SCD:
|
||||||
scd(instr);
|
scd(instr);
|
||||||
break;
|
break;
|
||||||
case SDC1:
|
case SDC1:
|
||||||
regs.cop1.sdc1(*this, mem, instr);
|
regs.cop1.sdc1(mem, instr);
|
||||||
break;
|
break;
|
||||||
case SD:
|
case SD:
|
||||||
sd(instr);
|
sd(instr);
|
||||||
|
|||||||
@@ -172,16 +172,16 @@ void JIT::regimm(const u32 instr) {
|
|||||||
// 000r_rccc
|
// 000r_rccc
|
||||||
switch (const u8 mask = instr >> 16 & 0x1F) {
|
switch (const u8 mask = instr >> 16 & 0x1F) {
|
||||||
case BLTZ:
|
case BLTZ:
|
||||||
b(instr, LT, RS(instr));
|
bltz(instr);
|
||||||
break;
|
break;
|
||||||
case BGEZ:
|
case BGEZ:
|
||||||
b(instr, GE, RS(instr));
|
bgez(instr);
|
||||||
break;
|
break;
|
||||||
case BLTZL:
|
case BLTZL:
|
||||||
bl(instr, LT, RS(instr));
|
bltzl(instr);
|
||||||
break;
|
break;
|
||||||
case BGEZL:
|
case BGEZL:
|
||||||
bl(instr, GE, RS(instr));
|
bgezl(instr);
|
||||||
break;
|
break;
|
||||||
case TGEI:
|
case TGEI:
|
||||||
trap(regs.Read<s64>(RS(instr)) >= static_cast<s64>(static_cast<s16>(instr)));
|
trap(regs.Read<s64>(RS(instr)) >= static_cast<s64>(static_cast<s16>(instr)));
|
||||||
@@ -202,16 +202,16 @@ void JIT::regimm(const u32 instr) {
|
|||||||
trap(regs.Read<s64>(RS(instr)) != static_cast<s64>(static_cast<s16>(instr)));
|
trap(regs.Read<s64>(RS(instr)) != static_cast<s64>(static_cast<s16>(instr)));
|
||||||
break;
|
break;
|
||||||
case BLTZAL:
|
case BLTZAL:
|
||||||
blink(instr, LT, RS(instr));
|
bltzal(instr);
|
||||||
break;
|
break;
|
||||||
case BGEZAL:
|
case BGEZAL:
|
||||||
blink(instr, GE, RS(instr));
|
bgezal(instr);
|
||||||
break;
|
break;
|
||||||
case BLTZALL:
|
case BLTZALL:
|
||||||
bllink(instr, LT, RS(instr));
|
bltzall(instr);
|
||||||
break;
|
break;
|
||||||
case BGEZALL:
|
case BGEZALL:
|
||||||
bllink(instr, GE, RS(instr));
|
bgezall(instr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Util::panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})", (mask >> 3) & 3, mask & 7, instr,
|
Util::panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})", (mask >> 3) & 3, mask & 7, instr,
|
||||||
@@ -234,16 +234,16 @@ void JIT::Emit(const u32 instr) {
|
|||||||
jal(instr);
|
jal(instr);
|
||||||
break;
|
break;
|
||||||
case BEQ:
|
case BEQ:
|
||||||
b(instr, EQ, RS(instr), RT(instr));
|
beq(instr);
|
||||||
break;
|
break;
|
||||||
case BNE:
|
case BNE:
|
||||||
b(instr, NE, RS(instr), RT(instr));
|
bne(instr);
|
||||||
break;
|
break;
|
||||||
case BLEZ:
|
case BLEZ:
|
||||||
b(instr, LE, RS(instr));
|
blez(instr);
|
||||||
break;
|
break;
|
||||||
case BGTZ:
|
case BGTZ:
|
||||||
b(instr, GT, RS(instr));
|
bgtz(instr);
|
||||||
break;
|
break;
|
||||||
case ADDI:
|
case ADDI:
|
||||||
addi(instr);
|
addi(instr);
|
||||||
@@ -273,21 +273,52 @@ void JIT::Emit(const u32 instr) {
|
|||||||
regs.cop0.decode(*this, instr);
|
regs.cop0.decode(*this, instr);
|
||||||
break;
|
break;
|
||||||
case COP1:
|
case COP1:
|
||||||
regs.cop1.decode(*this, instr);
|
{
|
||||||
|
const u8 mask_sub = (instr >> 21) & 0x1F;
|
||||||
|
const u8 mask_branch = (instr >> 16) & 0x1F;
|
||||||
|
if (mask_sub == 0x08) {
|
||||||
|
switch (mask_branch) {
|
||||||
|
case 0:
|
||||||
|
// if (!regs.cop1.CheckFPUUsable())
|
||||||
|
// return;
|
||||||
|
bfc0(instr);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
// if (!regs.cop1.CheckFPUUsable())
|
||||||
|
// return;
|
||||||
|
bfc1(instr);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
// if (!regs.cop1.CheckFPUUsable())
|
||||||
|
// return;
|
||||||
|
blfc0(instr);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
// if (!regs.cop1.CheckFPUUsable())
|
||||||
|
// return;
|
||||||
|
blfc1(instr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Util::panic("Undefined BC COP1 {:02X}", mask_branch);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
regs.cop1.decode(instr);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case COP2:
|
case COP2:
|
||||||
break;
|
break;
|
||||||
case BEQL:
|
case BEQL:
|
||||||
bl(instr, EQ, RS(instr), RT(instr));
|
beql(instr);
|
||||||
break;
|
break;
|
||||||
case BNEL:
|
case BNEL:
|
||||||
bl(instr, NE, RS(instr), RT(instr));
|
bnel(instr);
|
||||||
break;
|
break;
|
||||||
case BLEZL:
|
case BLEZL:
|
||||||
bl(instr, LE, RS(instr));
|
blezl(instr);
|
||||||
break;
|
break;
|
||||||
case BGTZL:
|
case BGTZL:
|
||||||
bl(instr, GT, RS(instr));
|
bgtzl(instr);
|
||||||
break;
|
break;
|
||||||
case DADDI:
|
case DADDI:
|
||||||
daddi(instr);
|
daddi(instr);
|
||||||
|
|||||||
@@ -12,20 +12,7 @@ void Cop1::Reset() {
|
|||||||
memset(fgr, 0, 32 * sizeof(FloatingPointReg));
|
memset(fgr, 0, 32 * sizeof(FloatingPointReg));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
void Cop1::decode(const u32 instr) {
|
||||||
void Cop1::decode(T &cpu, u32 instr) {
|
|
||||||
if constexpr (std::is_same_v<decltype(cpu), Interpreter &>) {
|
|
||||||
decodeInterp(cpu, instr);
|
|
||||||
} else {
|
|
||||||
Util::panic("What the fuck did you just give me?!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template void Cop1::decode<Interpreter>(Interpreter &, u32);
|
|
||||||
template void Cop1::decode<JIT>(JIT &, u32);
|
|
||||||
|
|
||||||
void Cop1::decodeInterp(Interpreter &cpu, u32 instr) {
|
|
||||||
|
|
||||||
const u8 mask_sub = (instr >> 21) & 0x1F;
|
const u8 mask_sub = (instr >> 21) & 0x1F;
|
||||||
const u8 mask_fun = instr & 0x3F;
|
const u8 mask_fun = instr & 0x3F;
|
||||||
const u8 mask_branch = (instr >> 16) & 0x1F;
|
const u8 mask_branch = (instr >> 16) & 0x1F;
|
||||||
@@ -55,32 +42,6 @@ void Cop1::decodeInterp(Interpreter &cpu, u32 instr) {
|
|||||||
case 0x07:
|
case 0x07:
|
||||||
unimplemented();
|
unimplemented();
|
||||||
break;
|
break;
|
||||||
case 0x08:
|
|
||||||
switch (mask_branch) {
|
|
||||||
case 0:
|
|
||||||
if (!CheckFPUUsable())
|
|
||||||
return;
|
|
||||||
cpu.b(instr, !fcr31.compare);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
if (!CheckFPUUsable())
|
|
||||||
return;
|
|
||||||
cpu.b(instr, fcr31.compare);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (!CheckFPUUsable())
|
|
||||||
return;
|
|
||||||
cpu.bl(instr, !fcr31.compare);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
if (!CheckFPUUsable())
|
|
||||||
return;
|
|
||||||
cpu.bl(instr, fcr31.compare);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Util::panic("Undefined BC COP1 {:02X}", mask_branch);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x10: // s
|
case 0x10: // s
|
||||||
switch (mask_fun) {
|
switch (mask_fun) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
|
|||||||
@@ -118,11 +118,12 @@ struct Cop1 {
|
|||||||
u32 fcr0{};
|
u32 fcr0{};
|
||||||
FCR31 fcr31{};
|
FCR31 fcr31{};
|
||||||
FloatingPointReg fgr[32]{};
|
FloatingPointReg fgr[32]{};
|
||||||
|
bool fgrIsConstant[32]{};
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
template <class T> // either JIT or Interpreter
|
void decode(u32);
|
||||||
void decode(T &, u32);
|
|
||||||
friend struct Interpreter;
|
friend struct Interpreter;
|
||||||
|
friend struct JIT;
|
||||||
|
|
||||||
template <bool preserveCause = false>
|
template <bool preserveCause = false>
|
||||||
bool CheckFPUUsable();
|
bool CheckFPUUsable();
|
||||||
@@ -159,8 +160,6 @@ private:
|
|||||||
auto FGR_S(const Cop0Status &, u32) -> T &;
|
auto FGR_S(const Cop0Status &, u32) -> T &;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
auto FGR_D(const Cop0Status &, u32) -> T &;
|
auto FGR_D(const Cop0Status &, u32) -> T &;
|
||||||
void decodeInterp(Interpreter &, u32);
|
|
||||||
void decodeJIT(JIT &, u32);
|
|
||||||
void absd(u32 instr);
|
void absd(u32 instr);
|
||||||
void abss(u32 instr);
|
void abss(u32 instr);
|
||||||
void adds(u32 instr);
|
void adds(u32 instr);
|
||||||
@@ -234,23 +233,11 @@ private:
|
|||||||
void negd(u32 instr);
|
void negd(u32 instr);
|
||||||
void sqrts(u32 instr);
|
void sqrts(u32 instr);
|
||||||
void sqrtd(u32 instr);
|
void sqrtd(u32 instr);
|
||||||
template <class T>
|
void lwc1(Mem &, u32);
|
||||||
void lwc1(T &, Mem &, u32);
|
void swc1(Mem &, u32);
|
||||||
template <class T>
|
void ldc1(Mem &, u32);
|
||||||
void swc1(T &, Mem &, u32);
|
void sdc1(Mem &, u32);
|
||||||
template <class T>
|
|
||||||
void ldc1(T &, Mem &, u32);
|
|
||||||
template <class T>
|
|
||||||
void sdc1(T &, Mem &, u32);
|
|
||||||
|
|
||||||
void lwc1Interp(Mem &, u32);
|
|
||||||
void swc1Interp(Mem &, u32);
|
|
||||||
void ldc1Interp(Mem &, u32);
|
|
||||||
void sdc1Interp(Mem &, u32);
|
|
||||||
void lwc1JIT(JIT &, Mem &, u32) { Util::panic("[JIT]: lwc1 not implemented!"); }
|
|
||||||
void swc1JIT(JIT &, Mem &, u32) { Util::panic("[JIT]: swc1 not implemented!"); }
|
|
||||||
void ldc1JIT(JIT &, Mem &, u32) { Util::panic("[JIT]: ldc1 not implemented!"); }
|
|
||||||
void sdc1JIT(JIT &, Mem &, u32) { Util::panic("[JIT]: sdc1 not implemented!"); }
|
|
||||||
void mfc1(u32 instr);
|
void mfc1(u32 instr);
|
||||||
void dmfc1(u32 instr);
|
void dmfc1(u32 instr);
|
||||||
void mtc1(u32 instr);
|
void mtc1(u32 instr);
|
||||||
|
|||||||
Reference in New Issue
Block a user