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

View File

@@ -11,7 +11,7 @@ struct Core {
Interpreted,
DynamicRecompiler,
CachedInterpreter
};
} cpuType = Interpreted;
explicit Core();
@@ -28,6 +28,20 @@ struct Core {
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();
void StepRSP(int cpuCycles);
void Stop();

View File

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

View File

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

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();
const u8 mask_cop = instr >> 21 & 0x1F;
const u8 mask_cop2 = instr & 0x3F;
switch (mask_cop) {
switch (instr.cop_rs()) {
case 0x00:
mfc0(instr);
mfc0(u32(instr));
break;
case 0x01:
dmfc0(instr);
dmfc0(u32(instr));
break;
case 0x04:
mtc0(instr);
mtc0(u32(instr));
break;
case 0x05:
dmtc0(instr);
dmtc0(u32(instr));
break;
case 0x10 ... 0x1F:
switch (mask_cop2) {
switch (instr.cop_funct()) {
case 0x01:
tlbr();
break;
@@ -486,7 +484,7 @@ void Cop0::decode(const u32 instr) {
eret();
break;
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);
}
break;

View File

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

View File

@@ -10,11 +10,9 @@ void Cop1::Reset() {
memset(fgr, 0, 32 * sizeof(FloatingPointReg));
}
void Cop1::decode(const u32 instr) {
const u8 mask_sub = (instr >> 21) & 0x1F;
const u8 mask_fun = instr & 0x3F;
const u8 mask_branch = (instr >> 16) & 0x1F;
switch (mask_sub) {
void Cop1::decode(const Instruction instr) {
auto cpu = Core::GetInstance().cpuType == Core::Interpreted ? Core::GetInterpreter() : Core::GetDynamicRecompiler();
switch (instr.cop_rs()) {
// 000r_rccc
case 0x00:
mfc1(instr);
@@ -40,8 +38,34 @@ void Cop1::decode(const u32 instr) {
case 0x07:
unimplemented();
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
switch (mask_fun) {
switch (instr.cop_funct()) {
case 0x00:
adds(instr);
break;
@@ -152,7 +176,7 @@ void Cop1::decode(const u32 instr) {
}
break;
case 0x11: // d
switch (mask_fun) {
switch (instr.cop_funct()) {
case 0x00:
addd(instr);
break;
@@ -263,7 +287,7 @@ void Cop1::decode(const u32 instr) {
}
break;
case 0x14: // w
switch (mask_fun) {
switch (instr.cop_funct()) {
case 0x20:
cvtsw(instr);
break;
@@ -275,7 +299,7 @@ void Cop1::decode(const u32 instr) {
}
break;
case 0x15: // l
switch (mask_fun) {
switch (instr.cop_funct()) {
case 0x20:
cvtsl(instr);
break;
@@ -287,7 +311,7 @@ void Cop1::decode(const u32 instr) {
}
break;
default:
panic("Unimplemented COP1 instruction {} {}", mask_sub >> 3, mask_sub & 7);
panic("Unimplemented COP1 instruction {}", instr.cop_rs());
}
}
} // namespace n64

View File

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

View File

@@ -4,17 +4,82 @@
namespace n64 {
struct Instruction {
Instruction(u32 v) : raw(v) {}
void operator=(u32 v) { raw = v; }
Instruction(u32 v) { instr.raw = v; }
void operator=(u32 v) { instr.raw = v; }
auto operator u32() { return instr.raw; }
u32 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; }
FORCE_INLINE u8 special() const { return raw & 0x3F; }
FORCE_INLINE u8 cop_funct() const { return special(); }
FORCE_INLINE u8 regimm() const { return (raw >> 16) & 0x1F; }
FORCE_INLINE u8 branch() const { return regimm(); }
FORCE_INLINE u8 decode() const { return (raw >> 26) & 0x3F; }
FORCE_INLINE u8 cop() const { return (raw >> 21) & 0x1F; }
union {
struct {
unsigned imm:16;
unsigned rt:5;
unsigned rs:5;
unsigned op:6;
} itype;
struct {
unsigned target:26;
unsigned op:6;
} jtype;
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 REGIMM = 0b000001;