Continue big Instruction struct rewrite

This commit is contained in:
irisz64
2025-08-28 09:25:22 +02:00
parent 68620ce893
commit dd98e19c95
9 changed files with 399 additions and 326 deletions

View File

@@ -7,9 +7,11 @@ namespace n64 {
Core::Core() { Core::Core() {
auto cpuType = Options::GetInstance().GetValue<std::string>("cpu", "type"); auto cpuType = Options::GetInstance().GetValue<std::string>("cpu", "type");
if (cpuType == "interpreter") { if (cpuType == "interpreter") {
cpuType = Interpreted;
cpu = std::make_unique<Interpreter>(parallel, *mem, regs); cpu = std::make_unique<Interpreter>(parallel, *mem, regs);
} else if(cpuType == "jit") { } else if(cpuType == "jit") {
#ifndef __aarch64__ #ifndef __aarch64__
cpuType = DynamicRecompiler;
cpu = std::make_unique<JIT>(parallel, *mem, regs); cpu = std::make_unique<JIT>(parallel, *mem, regs);
#else #else
panic("JIT currently unsupported on aarch64"); panic("JIT currently unsupported on aarch64");

View File

@@ -11,7 +11,7 @@ struct Core {
Interpreted, Interpreted,
DynamicRecompiler, DynamicRecompiler,
CachedInterpreter CachedInterpreter
}; } cpuType = Interpreted;
explicit Core(); explicit Core();
@@ -28,6 +28,20 @@ struct Core {
return *GetInstance().mem; return *GetInstance().mem;
} }
static Interpreter& GetInterpreter() {
if(GetInstance().cpuType == Interpreted)
return *dynamic_cast<Interpreter*>(GetInstance().cpu.get());
panic("Tried to get interpreter when other cpu type is used.");
}
static JIT& GetDynamicRecompiler() {
if(GetInstance().cpuType == DynamicRecompiler)
return *dynamic_cast<JIT*>(GetInstance().cpu.get());
panic("Tried to get interpreter when other cpu type is used.");
}
int StepCPU(); int StepCPU();
void StepRSP(int cpuCycles); void StepRSP(int cpuCycles);
void Stop(); void Stop();

View File

@@ -26,100 +26,100 @@ private:
void CheckCompareInterrupt(); void CheckCompareInterrupt();
void cop2Decode(u32); void cop2Decode(u32);
void special(u32); void special(Instruction);
void regimm(u32); void regimm(Instruction);
void Exec(u32); void Exec(Instruction);
void add(u32); void add(Instruction);
void addu(u32); void addu(Instruction);
void addi(u32); void addi(Instruction);
void addiu(u32); void addiu(Instruction);
void andi(u32); void andi(Instruction);
void and_(u32); void and_(Instruction);
void branch(bool, s64); void branch(bool, s64);
void branch_likely(bool, s64); void branch_likely(bool, s64);
void b(u32, bool); void b(Instruction, bool);
void blink(u32, bool); void blink(Instruction, bool);
void bl(u32, bool); void bl(Instruction, bool);
void bllink(u32, bool); void bllink(Instruction, bool);
void dadd(u32); void dadd(Instruction);
void daddu(u32); void daddu(Instruction);
void daddi(u32); void daddi(Instruction);
void daddiu(u32); void daddiu(Instruction);
void ddiv(u32); void ddiv(Instruction);
void ddivu(u32); void ddivu(Instruction);
void div(u32); void div(Instruction);
void divu(u32); void divu(Instruction);
void dmult(u32); void dmult(Instruction);
void dmultu(u32); void dmultu(Instruction);
void dsll(u32); void dsll(Instruction);
void dsllv(u32); void dsllv(Instruction);
void dsll32(u32); void dsll32(Instruction);
void dsra(u32); void dsra(Instruction);
void dsrav(u32); void dsrav(Instruction);
void dsra32(u32); void dsra32(Instruction);
void dsrl(u32); void dsrl(Instruction);
void dsrlv(u32); void dsrlv(Instruction);
void dsrl32(u32); void dsrl32(Instruction);
void dsub(u32); void dsub(Instruction);
void dsubu(u32); void dsubu(Instruction);
void j(u32); void j(Instruction);
void jr(u32); void jr(Instruction);
void jal(u32); void jal(Instruction);
void jalr(u32); void jalr(Instruction);
void lui(u32); void lui(Instruction);
void lbu(u32); void lbu(Instruction);
void lb(u32); void lb(Instruction);
void ld(u32); void ld(Instruction);
void ldl(u32); void ldl(Instruction);
void ldr(u32); void ldr(Instruction);
void lh(u32); void lh(Instruction);
void lhu(u32); void lhu(Instruction);
void ll(u32); void ll(Instruction);
void lld(u32); void lld(Instruction);
void lw(u32); void lw(Instruction);
void lwl(u32); void lwl(Instruction);
void lwu(u32); void lwu(Instruction);
void lwr(u32); void lwr(Instruction);
void mfhi(u32); void mfhi(Instruction);
void mflo(u32); void mflo(Instruction);
void mult(u32); void mult(Instruction);
void multu(u32); void multu(Instruction);
void mthi(u32); void mthi(Instruction);
void mtlo(u32); void mtlo(Instruction);
void nor(u32); void nor(Instruction);
void sb(u32); void sb(Instruction);
void sc(u32); void sc(Instruction);
void scd(u32); void scd(Instruction);
void sd(u32); void sd(Instruction);
void sdl(u32); void sdl(Instruction);
void sdr(u32); void sdr(Instruction);
void sh(u32); void sh(Instruction);
void sw(u32); void sw(Instruction);
void swl(u32); void swl(Instruction);
void swr(u32); void swr(Instruction);
void slti(u32); void slti(Instruction);
void sltiu(u32); void sltiu(Instruction);
void slt(u32); void slt(Instruction);
void sltu(u32); void sltu(Instruction);
void sll(u32); void sll(Instruction);
void sllv(u32); void sllv(Instruction);
void sub(u32); void sub(Instruction);
void subu(u32); void subu(Instruction);
void sra(u32); void sra(Instruction);
void srav(u32); void srav(Instruction);
void srl(u32); void srl(Instruction);
void srlv(u32); void srlv(Instruction);
void trap(bool) const; void trap(bool) const;
void or_(u32); void or_(Instruction);
void ori(u32); void ori(Instruction);
void xor_(u32); void xor_(Instruction);
void xori(u32); void xori(Instruction);
void mtc2(u32); void mtc2(Instruction);
void mfc2(u32); void mfc2(Instruction);
void dmtc2(u32); void dmtc2(Instruction);
void dmfc2(u32); void dmfc2(Instruction);
void ctc2(u32); void ctc2(Instruction);
void cfc2(u32); void cfc2(Instruction);
}; };
} // namespace n64 } // namespace n64

View File

@@ -4,12 +4,11 @@
#include <Instruction.hpp> #include <Instruction.hpp>
namespace n64 { namespace n64 {
void Interpreter::special(const u32 instr) { void Interpreter::special(const Instruction instr) {
Instruction helper(instr);
// 00rr_rccc // 00rr_rccc
switch (helper.special()) { switch (instr.instr.opcode.special) {
case Instruction::SLL: case Instruction::SLL:
if (instr != 0) { if (instr.instr.raw != 0) {
sll(instr); sll(instr);
} }
break; break;
@@ -130,22 +129,22 @@ void Interpreter::special(const u32 instr) {
dsubu(instr); dsubu(instr);
break; break;
case Instruction::TGE: case Instruction::TGE:
trap(regs.Read<s64>(RS(instr)) >= regs.Read<s64>(RT(instr))); trap(regs.Read<s64>(instr.rs()) >= regs.Read<s64>(instr.rt()));
break; break;
case Instruction::TGEU: case Instruction::TGEU:
trap(regs.Read<u64>(RS(instr)) >= regs.Read<u64>(RT(instr))); trap(regs.Read<u64>(instr.rs()) >= regs.Read<u64>(instr.rt()));
break; break;
case Instruction::TLT: case Instruction::TLT:
trap(regs.Read<s64>(RS(instr)) < regs.Read<s64>(RT(instr))); trap(regs.Read<s64>(instr.rs()) < regs.Read<s64>(instr.rt()));
break; break;
case Instruction::TLTU: case Instruction::TLTU:
trap(regs.Read<u64>(RS(instr)) < regs.Read<u64>(RT(instr))); trap(regs.Read<u64>(instr.rs()) < regs.Read<u64>(instr.rt()));
break; break;
case Instruction::TEQ: case Instruction::TEQ:
trap(regs.Read<s64>(RS(instr)) == regs.Read<s64>(RT(instr))); trap(regs.Read<s64>(instr.rs()) == regs.Read<s64>(instr.rt()));
break; break;
case Instruction::TNE: case Instruction::TNE:
trap(regs.Read<s64>(RS(instr)) != regs.Read<s64>(RT(instr))); trap(regs.Read<s64>(instr.rs()) != regs.Read<s64>(instr.rt()));
break; break;
case Instruction::DSLL: case Instruction::DSLL:
dsll(instr); dsll(instr);
@@ -166,59 +165,59 @@ void Interpreter::special(const u32 instr) {
dsra32(instr); dsra32(instr);
break; break;
default: default:
panic("Unimplemented special {} {} ({:08X}) (pc: {:016X})", (mask >> 3) & 7, mask & 7, instr, panic("Unimplemented special {} {} ({:08X}) (pc: {:016X})", instr.instr.opcode.special_hi, instr.instr.opcode.special_lo, instr.instr.raw,
static_cast<u64>(regs.oldPC)); static_cast<u64>(regs.oldPC));
} }
} }
void Interpreter::regimm(const u32 instr) { void Interpreter::regimm(const Instruction instr) {
// 000r_rccc // 000r_rccc
switch (const u8 mask = instr >> 16 & 0x1F) { switch (instr.instr.opcode.regimm) {
case BLTZ: case Instruction::BLTZ:
b(instr, regs.Read<s64>(RS(instr)) < 0); b(instr, regs.Read<s64>(instr.rs()) < 0);
break; break;
case BGEZ: case Instruction::BGEZ:
b(instr, regs.Read<s64>(RS(instr)) >= 0); b(instr, regs.Read<s64>(instr.rs()) >= 0);
break; break;
case BLTZL: case Instruction::BLTZL:
bl(instr, regs.Read<s64>(RS(instr)) < 0); bl(instr, regs.Read<s64>(instr.rs()) < 0);
break; break;
case BGEZL: case Instruction::BGEZL:
bl(instr, regs.Read<s64>(RS(instr)) >= 0); bl(instr, regs.Read<s64>(instr.rs()) >= 0);
break; break;
case TGEI: case Instruction::TGEI:
trap(regs.Read<s64>(RS(instr)) >= static_cast<s64>(static_cast<s16>(instr))); trap(regs.Read<s64>(instr.rs()) >= static_cast<s64>(static_cast<s16>(instr.instr.itype.imm)));
break; break;
case TGEIU: case Instruction::TGEIU:
trap(regs.Read<u64>(RS(instr)) >= static_cast<u64>(static_cast<s64>(static_cast<s16>(instr)))); trap(regs.Read<u64>(instr.rs()) >= static_cast<u64>(static_cast<s64>(static_cast<s16>(instr.instr.itype.imm))));
break; break;
case TLTI: case Instruction::TLTI:
trap(regs.Read<s64>(RS(instr)) < static_cast<s64>(static_cast<s16>(instr))); trap(regs.Read<s64>(instr.rs()) < static_cast<s64>(static_cast<s16>(instr.instr.itype.imm)));
break; break;
case TLTIU: case Instruction::TLTIU:
trap(regs.Read<u64>(RS(instr)) < static_cast<u64>(static_cast<s64>(static_cast<s16>(instr)))); trap(regs.Read<u64>(instr.rs()) < static_cast<u64>(static_cast<s64>(static_cast<s16>(instr.instr.itype.imm))));
break; break;
case TEQI: case Instruction::TEQI:
trap(regs.Read<s64>(RS(instr)) == static_cast<s64>(static_cast<s16>(instr))); trap(regs.Read<s64>(instr.rs()) == static_cast<s64>(static_cast<s16>(instr.instr.itype.imm)));
break; break;
case TNEI: case Instruction::TNEI:
trap(regs.Read<s64>(RS(instr)) != static_cast<s64>(static_cast<s16>(instr))); trap(regs.Read<s64>(instr.rs()) != static_cast<s64>(static_cast<s16>(instr.instr.itype.imm)));
break; break;
case BLTZAL: case Instruction::BLTZAL:
blink(instr, regs.Read<s64>(RS(instr)) < 0); blink(instr, regs.Read<s64>(instr.rs()) < 0);
break; break;
case BGEZAL: case Instruction::BGEZAL:
blink(instr, regs.Read<s64>(RS(instr)) >= 0); blink(instr, regs.Read<s64>(instr.rs()) >= 0);
break; break;
case BLTZALL: case Instruction::BLTZALL:
bllink(instr, regs.Read<s64>(RS(instr)) < 0); bllink(instr, regs.Read<s64>(instr.rs()) < 0);
break; break;
case BGEZALL: case Instruction::BGEZALL:
bllink(instr, regs.Read<s64>(RS(instr)) >= 0); bllink(instr, regs.Read<s64>(instr.rs()) >= 0);
break; break;
default: default:
panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})", (mask >> 3) & 3, mask & 7, instr, panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})", instr.instr.opcode.regimm_hi,
static_cast<u64>(regs.oldPC)); instr.instr.opcode.regimm_lo, instr, static_cast<u64>(regs.oldPC));
} }
} }
@@ -251,203 +250,172 @@ void Interpreter::cop2Decode(const u32 instr) {
} }
} }
void Interpreter::Exec(const u32 instr) { void Interpreter::Exec(const Instruction instr) {
// 00rr_rccc // 00rr_rccc
switch (const u8 mask = instr >> 26 & 0x3f) { switch (instr.instr.opcode.op) {
case SPECIAL: case Instruction::SPECIAL:
special(instr); special(instr);
break; break;
case REGIMM: case Instruction::REGIMM:
regimm(instr); regimm(instr);
break; break;
case J: case Instruction::J:
j(instr); j(instr);
break; break;
case JAL: case Instruction::JAL:
jal(instr); jal(instr);
break; break;
case BEQ: case Instruction::BEQ:
b(instr, regs.Read<s64>(RS(instr)) == regs.Read<s64>(RT(instr))); b(instr, regs.Read<s64>(instr.rs()) == regs.Read<s64>(instr.rt()));
break; break;
case BNE: case Instruction::BNE:
b(instr, regs.Read<s64>(RS(instr)) != regs.Read<s64>(RT(instr))); b(instr, regs.Read<s64>(instr.rs()) != regs.Read<s64>(instr.rt()));
break; break;
case BLEZ: case Instruction::BLEZ:
b(instr, regs.Read<s64>(RS(instr)) <= 0); b(instr, regs.Read<s64>(instr.rs()) <= 0);
break; break;
case BGTZ: case Instruction::BGTZ:
b(instr, regs.Read<s64>(RS(instr)) > 0); b(instr, regs.Read<s64>(instr.rs()) > 0);
break; break;
case ADDI: case Instruction::ADDI:
addi(instr); addi(instr);
break; break;
case ADDIU: case Instruction::ADDIU:
addiu(instr); addiu(instr);
break; break;
case SLTI: case Instruction::SLTI:
slti(instr); slti(instr);
break; break;
case SLTIU: case Instruction::SLTIU:
sltiu(instr); sltiu(instr);
break; break;
case ANDI: case Instruction::ANDI:
andi(instr); andi(instr);
break; break;
case ORI: case Instruction::ORI:
ori(instr); ori(instr);
break; break;
case XORI: case Instruction::XORI:
xori(instr); xori(instr);
break; break;
case LUI: case Instruction::LUI:
lui(instr); lui(instr);
break; break;
case COP0: case Instruction::COP0:
regs.cop0.decode(instr); regs.cop0.decode(instr);
break; break;
case COP1: case Instruction::COP1:
{ regs.cop1.decode(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:
panic("Undefined BC COP1 {:02X}", mask_branch);
}
break;
}
regs.cop1.decode(instr);
}
break; break;
case COP2: case Instruction::COP2:
cop2Decode(instr); cop2Decode(instr);
break; break;
case BEQL: case Instruction::BEQL:
bl(instr, regs.Read<s64>(RS(instr)) == regs.Read<s64>(RT(instr))); bl(instr, regs.Read<s64>(instr.rs()) == regs.Read<s64>(instr.rt()));
break; break;
case BNEL: case Instruction::BNEL:
bl(instr, regs.Read<s64>(RS(instr)) != regs.Read<s64>(RT(instr))); bl(instr, regs.Read<s64>(instr.rs()) != regs.Read<s64>(instr.rt()));
break; break;
case BLEZL: case Instruction::BLEZL:
bl(instr, regs.Read<s64>(RS(instr)) <= 0); bl(instr, regs.Read<s64>(instr.rs()) <= 0);
break; break;
case BGTZL: case Instruction::BGTZL:
bl(instr, regs.Read<s64>(RS(instr)) > 0); bl(instr, regs.Read<s64>(instr.rs()) > 0);
break; break;
case DADDI: case Instruction::DADDI:
daddi(instr); daddi(instr);
break; break;
case DADDIU: case Instruction::DADDIU:
daddiu(instr); daddiu(instr);
break; break;
case LDL: case Instruction::LDL:
ldl(instr); ldl(instr);
break; break;
case LDR: case Instruction::LDR:
ldr(instr); ldr(instr);
break; break;
case 0x1F: case 0x1F:
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
break; break;
case LB: case Instruction::LB:
lb(instr); lb(instr);
break; break;
case LH: case Instruction::LH:
lh(instr); lh(instr);
break; break;
case LWL: case Instruction::LWL:
lwl(instr); lwl(instr);
break; break;
case LW: case Instruction::LW:
lw(instr); lw(instr);
break; break;
case LBU: case Instruction::LBU:
lbu(instr); lbu(instr);
break; break;
case LHU: case Instruction::LHU:
lhu(instr); lhu(instr);
break; break;
case LWR: case Instruction::LWR:
lwr(instr); lwr(instr);
break; break;
case LWU: case Instruction::LWU:
lwu(instr); lwu(instr);
break; break;
case SB: case Instruction::SB:
sb(instr); sb(instr);
break; break;
case SH: case Instruction::SH:
sh(instr); sh(instr);
break; break;
case SWL: case Instruction::SWL:
swl(instr); swl(instr);
break; break;
case SW: case Instruction::SW:
sw(instr); sw(instr);
break; break;
case SDL: case Instruction::SDL:
sdl(instr); sdl(instr);
break; break;
case SDR: case Instruction::SDR:
sdr(instr); sdr(instr);
break; break;
case SWR: case Instruction::SWR:
swr(instr); swr(instr);
break; break;
case CACHE: case Instruction::CACHE:
break; // CACHE break; // CACHE
case LL: case Instruction::LL:
ll(instr); ll(instr);
break; break;
case LWC1: case Instruction::LWC1:
regs.cop1.lwc1(instr); regs.cop1.lwc1(instr);
break; break;
case LLD: case Instruction::LLD:
lld(instr); lld(instr);
break; break;
case LDC1: case Instruction::LDC1:
regs.cop1.ldc1(instr); regs.cop1.ldc1(instr);
break; break;
case LD: case Instruction::LD:
ld(instr); ld(instr);
break; break;
case SC: case Instruction::SC:
sc(instr); sc(instr);
break; break;
case SWC1: case Instruction::SWC1:
regs.cop1.swc1(instr); regs.cop1.swc1(instr);
break; break;
case SCD: case Instruction::SCD:
scd(instr); scd(instr);
break; break;
case SDC1: case Instruction::SDC1:
regs.cop1.sdc1(instr); regs.cop1.sdc1(instr);
break; break;
case SD: case Instruction::SD:
sd(instr); sd(instr);
break; break;
default: default:
panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})", mask, instr, static_cast<u64>(regs.oldPC)); panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})", instr.instr.opcode.op, u32(instr), static_cast<u64>(regs.oldPC));
} }
} }
} // namespace n64 } // namespace n64

View File

@@ -451,25 +451,23 @@ ExceptionCode Cop0::GetTLBExceptionCode(const TLBError error, const TLBAccessTyp
} }
} }
void Cop0::decode(const u32 instr) { void Cop0::decode(const Instruction instr) {
Registers& regs = Core::GetRegs(); Registers& regs = Core::GetRegs();
const u8 mask_cop = instr >> 21 & 0x1F; switch (instr.cop_rs()) {
const u8 mask_cop2 = instr & 0x3F;
switch (mask_cop) {
case 0x00: case 0x00:
mfc0(instr); mfc0(u32(instr));
break; break;
case 0x01: case 0x01:
dmfc0(instr); dmfc0(u32(instr));
break; break;
case 0x04: case 0x04:
mtc0(instr); mtc0(u32(instr));
break; break;
case 0x05: case 0x05:
dmtc0(instr); dmtc0(u32(instr));
break; break;
case 0x10 ... 0x1F: case 0x10 ... 0x1F:
switch (mask_cop2) { switch (instr.cop_funct()) {
case 0x01: case 0x01:
tlbr(); tlbr();
break; break;
@@ -486,7 +484,7 @@ void Cop0::decode(const u32 instr) {
eret(); eret();
break; break;
default: default:
panic("Unimplemented COP0 function {} {} ({:08X}) ({:016X})", mask_cop2 >> 3, mask_cop2 & 7, instr, panic("Unimplemented COP0 function {} ({:08X}) ({:016X})", instr.cop_funct(), u32(instr),
regs.oldPC); regs.oldPC);
} }
break; break;

View File

@@ -2,6 +2,7 @@
#include <common.hpp> #include <common.hpp>
#include <log.hpp> #include <log.hpp>
#include <unordered_map> #include <unordered_map>
#include <Instruction.hpp>
namespace n64 { namespace n64 {
#define STATUS_MASK 0xFF57FFFF #define STATUS_MASK 0xFF57FFFF
@@ -264,7 +265,7 @@ struct Cop0 {
TLBEntry *TLBTryMatch(u64 vaddr); TLBEntry *TLBTryMatch(u64 vaddr);
void HandleTLBException(u64 vaddr); void HandleTLBException(u64 vaddr);
static ExceptionCode GetTLBExceptionCode(TLBError error, TLBAccessType accessType); static ExceptionCode GetTLBExceptionCode(TLBError error, TLBAccessType accessType);
void decode(u32); void decode(const Instruction);
private: private:
[[nodiscard]] FORCE_INLINE u32 GetWired() const { return wired & 0x3F; } [[nodiscard]] FORCE_INLINE u32 GetWired() const { return wired & 0x3F; }

View File

@@ -10,11 +10,9 @@ void Cop1::Reset() {
memset(fgr, 0, 32 * sizeof(FloatingPointReg)); memset(fgr, 0, 32 * sizeof(FloatingPointReg));
} }
void Cop1::decode(const u32 instr) { void Cop1::decode(const Instruction instr) {
const u8 mask_sub = (instr >> 21) & 0x1F; auto cpu = Core::GetInstance().cpuType == Core::Interpreted ? Core::GetInterpreter() : Core::GetDynamicRecompiler();
const u8 mask_fun = instr & 0x3F; switch (instr.cop_rs()) {
const u8 mask_branch = (instr >> 16) & 0x1F;
switch (mask_sub) {
// 000r_rccc // 000r_rccc
case 0x00: case 0x00:
mfc1(instr); mfc1(instr);
@@ -40,8 +38,34 @@ void Cop1::decode(const u32 instr) {
case 0x07: case 0x07:
unimplemented(); unimplemented();
break; break;
case 0x08:
switch (instr.cop_rt()) {
case 0:
if (!regs.cop1.CheckFPUUsable())
return;
cpu.b(instr, !regs.cop1.fcr31.compare);
break;
case 1:
if (!regs.cop1.CheckFPUUsable())
return;
cpu.b(instr, regs.cop1.fcr31.compare);
break;
case 2:
if (!regs.cop1.CheckFPUUsable())
return;
cpu.bl(instr, !regs.cop1.fcr31.compare);
break;
case 3:
if (!regs.cop1.CheckFPUUsable())
return;
cpu.bl(instr, regs.cop1.fcr31.compare);
break;
default:
panic("Undefined BC COP1 {:02X}", instr.cop_rt());
}
break;
case 0x10: // s case 0x10: // s
switch (mask_fun) { switch (instr.cop_funct()) {
case 0x00: case 0x00:
adds(instr); adds(instr);
break; break;
@@ -152,7 +176,7 @@ void Cop1::decode(const u32 instr) {
} }
break; break;
case 0x11: // d case 0x11: // d
switch (mask_fun) { switch (instr.cop_funct()) {
case 0x00: case 0x00:
addd(instr); addd(instr);
break; break;
@@ -263,7 +287,7 @@ void Cop1::decode(const u32 instr) {
} }
break; break;
case 0x14: // w case 0x14: // w
switch (mask_fun) { switch (instr.cop_funct()) {
case 0x20: case 0x20:
cvtsw(instr); cvtsw(instr);
break; break;
@@ -275,7 +299,7 @@ void Cop1::decode(const u32 instr) {
} }
break; break;
case 0x15: // l case 0x15: // l
switch (mask_fun) { switch (instr.cop_funct()) {
case 0x20: case 0x20:
cvtsl(instr); cvtsl(instr);
break; break;
@@ -287,7 +311,7 @@ void Cop1::decode(const u32 instr) {
} }
break; break;
default: default:
panic("Unimplemented COP1 instruction {} {}", mask_sub >> 3, mask_sub & 7); panic("Unimplemented COP1 instruction {}", instr.cop_rs());
} }
} }
} // namespace n64 } // namespace n64

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <core/registers/Cop0.hpp> #include <core/registers/Cop0.hpp>
#include <cstring> #include <cstring>
#include <Instruction.hpp>
namespace n64 { namespace n64 {
struct Cop1; struct Cop1;
@@ -117,7 +118,7 @@ struct Cop1 {
bool fgrIsConstant[32]{}; bool fgrIsConstant[32]{};
void Reset(); void Reset();
void decode(u32); void decode(const Instruction);
friend struct Interpreter; friend struct Interpreter;
friend struct JIT; friend struct JIT;
@@ -156,91 +157,91 @@ 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 absd(u32 instr); void absd(const Instruction instr);
void abss(u32 instr); void abss(const Instruction instr);
void adds(u32 instr); void adds(const Instruction instr);
void addd(u32 instr); void addd(const Instruction instr);
void subs(u32 instr); void subs(const Instruction instr);
void subd(u32 instr); void subd(const Instruction instr);
void ceills(u32 instr); void ceills(const Instruction instr);
void ceilws(u32 instr); void ceilws(const Instruction instr);
void ceilld(u32 instr); void ceilld(const Instruction instr);
void ceilwd(u32 instr); void ceilwd(const Instruction instr);
void cfc1(u32 instr); void cfc1(const Instruction instr);
void ctc1(u32 instr); void ctc1(const Instruction instr);
void unimplemented(); void unimplemented();
void roundls(u32 instr); void roundls(const Instruction instr);
void roundld(u32 instr); void roundld(const Instruction instr);
void roundws(u32 instr); void roundws(const Instruction instr);
void roundwd(u32 instr); void roundwd(const Instruction instr);
void floorls(u32 instr); void floorls(const Instruction instr);
void floorld(u32 instr); void floorld(const Instruction instr);
void floorws(u32 instr); void floorws(const Instruction instr);
void floorwd(u32 instr); void floorwd(const Instruction instr);
void cvtls(u32 instr); void cvtls(const Instruction instr);
void cvtws(u32 instr); void cvtws(const Instruction instr);
void cvtds(u32 instr); void cvtds(const Instruction instr);
void cvtsw(u32 instr); void cvtsw(const Instruction instr);
void cvtdw(u32 instr); void cvtdw(const Instruction instr);
void cvtsd(u32 instr); void cvtsd(const Instruction instr);
void cvtwd(u32 instr); void cvtwd(const Instruction instr);
void cvtld(u32 instr); void cvtld(const Instruction instr);
void cvtdl(u32 instr); void cvtdl(const Instruction instr);
void cvtsl(u32 instr); void cvtsl(const Instruction instr);
template <typename T> template <typename T>
void cf(u32 instr); void cf(const Instruction instr);
template <typename T> template <typename T>
void cun(u32 instr); void cun(const Instruction instr);
template <typename T> template <typename T>
void ceq(u32 instr); void ceq(const Instruction instr);
template <typename T> template <typename T>
void cueq(u32 instr); void cueq(const Instruction instr);
template <typename T> template <typename T>
void colt(u32 instr); void colt(const Instruction instr);
template <typename T> template <typename T>
void cult(u32 instr); void cult(const Instruction instr);
template <typename T> template <typename T>
void cole(u32 instr); void cole(const Instruction instr);
template <typename T> template <typename T>
void cule(u32 instr); void cule(const Instruction instr);
template <typename T> template <typename T>
void csf(u32 instr); void csf(const Instruction instr);
template <typename T> template <typename T>
void cngle(u32 instr); void cngle(const Instruction instr);
template <typename T> template <typename T>
void cseq(u32 instr); void cseq(const Instruction instr);
template <typename T> template <typename T>
void cngl(u32 instr); void cngl(const Instruction instr);
template <typename T> template <typename T>
void clt(u32 instr); void clt(const Instruction instr);
template <typename T> template <typename T>
void cnge(u32 instr); void cnge(const Instruction instr);
template <typename T> template <typename T>
void cle(u32 instr); void cle(const Instruction instr);
template <typename T> template <typename T>
void cngt(u32 instr); void cngt(const Instruction instr);
void divs(u32 instr); void divs(const Instruction instr);
void divd(u32 instr); void divd(const Instruction instr);
void muls(u32 instr); void muls(const Instruction instr);
void muld(u32 instr); void muld(const Instruction instr);
void movs(u32 instr); void movs(const Instruction instr);
void movd(u32 instr); void movd(const Instruction instr);
void negs(u32 instr); void negs(const Instruction instr);
void negd(u32 instr); void negd(const Instruction instr);
void sqrts(u32 instr); void sqrts(const Instruction instr);
void sqrtd(u32 instr); void sqrtd(const Instruction instr);
void lwc1(u32); void lwc1(u32);
void swc1(u32); void swc1(u32);
void ldc1(u32); void ldc1(u32);
void sdc1(u32); void sdc1(u32);
void mfc1(u32 instr); void mfc1(const Instruction instr);
void dmfc1(u32 instr); void dmfc1(const Instruction instr);
void mtc1(u32 instr); void mtc1(const Instruction instr);
void dmtc1(u32 instr); void dmtc1(const Instruction instr);
void truncws(u32 instr); void truncws(const Instruction instr);
void truncwd(u32 instr); void truncwd(const Instruction instr);
void truncls(u32 instr); void truncls(const Instruction instr);
void truncld(u32 instr); void truncld(const Instruction instr);
}; };
} // namespace n64 } // namespace n64

View File

@@ -4,17 +4,82 @@
namespace n64 { namespace n64 {
struct Instruction { struct Instruction {
Instruction(u32 v) : raw(v) {} Instruction(u32 v) { instr.raw = v; }
void operator=(u32 v) { raw = v; } void operator=(u32 v) { instr.raw = v; }
auto operator u32() { return instr.raw; }
inline u8 rs() const { return instr.rtype.rs; }
inline u8 rt() const { return instr.rtype.rt; }
inline u8 rd() const { return instr.rtype.rd; }
inline u8 sa() const { return instr.rtype.sa; }
inline u16 imm() const { return instr.itype.imm; }
inline u32 target() const { return instr.jtype.target; }
inline u8 cop_rs() const { return instr.opcode.cop_rs; }
inline u8 cop_rt() const { return instr.opcode.cop_rt; }
inline u8 cop_funct() const { return instr.opcode.funct; }
u32 raw; union {
struct {
unsigned imm:16;
unsigned rt:5;
unsigned rs:5;
unsigned op:6;
} itype;
FORCE_INLINE u8 special() const { return raw & 0x3F; } struct {
FORCE_INLINE u8 cop_funct() const { return special(); } unsigned target:26;
FORCE_INLINE u8 regimm() const { return (raw >> 16) & 0x1F; } unsigned op:6;
FORCE_INLINE u8 branch() const { return regimm(); } } jtype;
FORCE_INLINE u8 decode() const { return (raw >> 26) & 0x3F; }
FORCE_INLINE u8 cop() const { return (raw >> 21) & 0x1F; } struct {
unsigned funct:6;
unsigned sa:5;
unsigned rd:5;
unsigned rt:5;
unsigned rs:5;
unsigned op:6;
} rtype;
union {
struct {
unsigned special_lo:3;
unsigned special_hi:3;
unsigned:26;
};
struct {
unsigned special:6;
unsigned:26;
};
struct {
unsigned:16;
unsigned regimm_lo:3;
unsigned regimm_hi:2;
unsigned:11;
};
struct {
unsigned:16;
unsigned regimm:5;
unsigned:11;
};
struct {
unsigned:26;
unsigned op:6;
};
struct {
unsigned funct:6;
unsigned:10;
unsigned cop_rt:5;
unsigned cop_rs:5;
unsigned:6;
};
} opcode;
u32 raw;
} instr{};
static constexpr u8 SPECIAL = 0b000000; static constexpr u8 SPECIAL = 0b000000;
static constexpr u8 REGIMM = 0b000001; static constexpr u8 REGIMM = 0b000001;