Continue big Instruction struct rewrite
This commit is contained in:
@@ -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");
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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; }
|
||||
|
||||
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; }
|
||||
|
||||
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;
|
||||
|
||||
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; }
|
||||
} instr{};
|
||||
|
||||
static constexpr u8 SPECIAL = 0b000000;
|
||||
static constexpr u8 REGIMM = 0b000001;
|
||||
|
||||
Reference in New Issue
Block a user