More progress on JIT constant instructions implementations
This commit is contained in:
388
src/backend/core/jit/decode.cpp
Normal file
388
src/backend/core/jit/decode.cpp
Normal file
@@ -0,0 +1,388 @@
|
||||
#include <JIT.hpp>
|
||||
#include <CpuDefinitions.hpp>
|
||||
|
||||
namespace n64 {
|
||||
void JIT::special(const u32 instr) {
|
||||
// 00rr_rccc
|
||||
switch (const u8 mask = instr & 0x3F) {
|
||||
case SLL:
|
||||
if (instr != 0) {
|
||||
sll(instr);
|
||||
}
|
||||
break;
|
||||
case SRL:
|
||||
srl(instr);
|
||||
break;
|
||||
case SRA:
|
||||
sra(instr);
|
||||
break;
|
||||
case SLLV:
|
||||
sllv(instr);
|
||||
break;
|
||||
case SRLV:
|
||||
srlv(instr);
|
||||
break;
|
||||
case SRAV:
|
||||
srav(instr);
|
||||
break;
|
||||
case JR:
|
||||
jr(instr);
|
||||
break;
|
||||
case JALR:
|
||||
jalr(instr);
|
||||
break;
|
||||
case SYSCALL:
|
||||
regs.cop0.FireException(ExceptionCode::Syscall, 0, regs.oldPC);
|
||||
break;
|
||||
case BREAK:
|
||||
regs.cop0.FireException(ExceptionCode::Breakpoint, 0, regs.oldPC);
|
||||
break;
|
||||
case SYNC:
|
||||
break; // SYNC
|
||||
case MFHI:
|
||||
mfhi(instr);
|
||||
break;
|
||||
case MTHI:
|
||||
mthi(instr);
|
||||
break;
|
||||
case MFLO:
|
||||
mflo(instr);
|
||||
break;
|
||||
case MTLO:
|
||||
mtlo(instr);
|
||||
break;
|
||||
case DSLLV:
|
||||
dsllv(instr);
|
||||
break;
|
||||
case DSRLV:
|
||||
dsrlv(instr);
|
||||
break;
|
||||
case DSRAV:
|
||||
dsrav(instr);
|
||||
break;
|
||||
case MULT:
|
||||
mult(instr);
|
||||
break;
|
||||
case MULTU:
|
||||
multu(instr);
|
||||
break;
|
||||
case DIV:
|
||||
div(instr);
|
||||
break;
|
||||
case DIVU:
|
||||
divu(instr);
|
||||
break;
|
||||
case DMULT:
|
||||
dmult(instr);
|
||||
break;
|
||||
case DMULTU:
|
||||
dmultu(instr);
|
||||
break;
|
||||
case DDIV:
|
||||
ddiv(instr);
|
||||
break;
|
||||
case DDIVU:
|
||||
ddivu(instr);
|
||||
break;
|
||||
case ADD:
|
||||
add(instr);
|
||||
break;
|
||||
case ADDU:
|
||||
addu(instr);
|
||||
break;
|
||||
case SUB:
|
||||
sub(instr);
|
||||
break;
|
||||
case SUBU:
|
||||
subu(instr);
|
||||
break;
|
||||
case AND:
|
||||
and_(instr);
|
||||
break;
|
||||
case OR:
|
||||
or_(instr);
|
||||
break;
|
||||
case XOR:
|
||||
xor_(instr);
|
||||
break;
|
||||
case NOR:
|
||||
nor(instr);
|
||||
break;
|
||||
case SLT:
|
||||
slt(instr);
|
||||
break;
|
||||
case SLTU:
|
||||
sltu(instr);
|
||||
break;
|
||||
case DADD:
|
||||
dadd(instr);
|
||||
break;
|
||||
case DADDU:
|
||||
daddu(instr);
|
||||
break;
|
||||
case DSUB:
|
||||
dsub(instr);
|
||||
break;
|
||||
case DSUBU:
|
||||
dsubu(instr);
|
||||
break;
|
||||
case TGE:
|
||||
trap(regs.Read<s64>(RS(instr)) >= regs.Read<s64>(RT(instr)));
|
||||
break;
|
||||
case TGEU:
|
||||
trap(regs.Read<u64>(RS(instr)) >= regs.Read<u64>(RT(instr)));
|
||||
break;
|
||||
case TLT:
|
||||
trap(regs.Read<s64>(RS(instr)) < regs.Read<s64>(RT(instr)));
|
||||
break;
|
||||
case TLTU:
|
||||
trap(regs.Read<u64>(RS(instr)) < regs.Read<u64>(RT(instr)));
|
||||
break;
|
||||
case TEQ:
|
||||
trap(regs.Read<s64>(RS(instr)) == regs.Read<s64>(RT(instr)));
|
||||
break;
|
||||
case TNE:
|
||||
trap(regs.Read<s64>(RS(instr)) != regs.Read<s64>(RT(instr)));
|
||||
break;
|
||||
case DSLL:
|
||||
dsll(instr);
|
||||
break;
|
||||
case DSRL:
|
||||
dsrl(instr);
|
||||
break;
|
||||
case DSRA:
|
||||
dsra(instr);
|
||||
break;
|
||||
case DSLL32:
|
||||
dsll32(instr);
|
||||
break;
|
||||
case DSRL32:
|
||||
dsrl32(instr);
|
||||
break;
|
||||
case DSRA32:
|
||||
dsra32(instr);
|
||||
break;
|
||||
default:
|
||||
Util::panic("Unimplemented special {} {} ({:08X}) (pc: {:016X})", (mask >> 3) & 7, mask & 7, instr,
|
||||
static_cast<u64>(regs.oldPC));
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::regimm(const u32 instr) {
|
||||
// 000r_rccc
|
||||
switch (const u8 mask = instr >> 16 & 0x1F) {
|
||||
case BLTZ:
|
||||
b(instr, LT, RS(instr));
|
||||
break;
|
||||
case BGEZ:
|
||||
b(instr, GE, RS(instr));
|
||||
break;
|
||||
case BLTZL:
|
||||
bl(instr, LT, RS(instr));
|
||||
break;
|
||||
case BGEZL:
|
||||
bl(instr, GE, RS(instr));
|
||||
break;
|
||||
case TGEI:
|
||||
trap(regs.Read<s64>(RS(instr)) >= static_cast<s64>(static_cast<s16>(instr)));
|
||||
break;
|
||||
case TGEIU:
|
||||
trap(regs.Read<u64>(RS(instr)) >= static_cast<u64>(static_cast<s64>(static_cast<s16>(instr))));
|
||||
break;
|
||||
case TLTI:
|
||||
trap(regs.Read<s64>(RS(instr)) < static_cast<s64>(static_cast<s16>(instr)));
|
||||
break;
|
||||
case TLTIU:
|
||||
trap(regs.Read<u64>(RS(instr)) < static_cast<u64>(static_cast<s64>(static_cast<s16>(instr))));
|
||||
break;
|
||||
case TEQI:
|
||||
trap(regs.Read<s64>(RS(instr)) == static_cast<s64>(static_cast<s16>(instr)));
|
||||
break;
|
||||
case TNEI:
|
||||
trap(regs.Read<s64>(RS(instr)) != static_cast<s64>(static_cast<s16>(instr)));
|
||||
break;
|
||||
case BLTZAL:
|
||||
blink(instr, LT, RS(instr));
|
||||
break;
|
||||
case BGEZAL:
|
||||
blink(instr, GE, RS(instr));
|
||||
break;
|
||||
case BLTZALL:
|
||||
bllink(instr, LT, RS(instr));
|
||||
break;
|
||||
case BGEZALL:
|
||||
bllink(instr, GE, RS(instr));
|
||||
break;
|
||||
default:
|
||||
Util::panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})", (mask >> 3) & 3, mask & 7, instr,
|
||||
static_cast<u64>(regs.oldPC));
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::Emit(const u32 instr) {
|
||||
switch (const u8 mask = instr >> 26 & 0x3f) {
|
||||
case SPECIAL:
|
||||
special(instr);
|
||||
break;
|
||||
case REGIMM:
|
||||
regimm(instr);
|
||||
break;
|
||||
case J:
|
||||
j(instr);
|
||||
break;
|
||||
case JAL:
|
||||
jal(instr);
|
||||
break;
|
||||
case BEQ:
|
||||
b(instr, EQ, RS(instr), RT(instr));
|
||||
break;
|
||||
case BNE:
|
||||
b(instr, NE, RS(instr), RT(instr));
|
||||
break;
|
||||
case BLEZ:
|
||||
b(instr, LE, RS(instr));
|
||||
break;
|
||||
case BGTZ:
|
||||
b(instr, GT, RS(instr));
|
||||
break;
|
||||
case ADDI:
|
||||
addi(instr);
|
||||
break;
|
||||
case ADDIU:
|
||||
addiu(instr);
|
||||
break;
|
||||
case SLTI:
|
||||
slti(instr);
|
||||
break;
|
||||
case SLTIU:
|
||||
sltiu(instr);
|
||||
break;
|
||||
case ANDI:
|
||||
andi(instr);
|
||||
break;
|
||||
case ORI:
|
||||
ori(instr);
|
||||
break;
|
||||
case XORI:
|
||||
xori(instr);
|
||||
break;
|
||||
case LUI:
|
||||
lui(instr);
|
||||
break;
|
||||
case COP0:
|
||||
regs.cop0.decode(*this, instr);
|
||||
break;
|
||||
case COP1:
|
||||
regs.cop1.decode(*this, instr);
|
||||
break;
|
||||
case COP2:
|
||||
break;
|
||||
case BEQL:
|
||||
bl(instr, EQ, RS(instr), RT(instr));
|
||||
break;
|
||||
case BNEL:
|
||||
bl(instr, NE, RS(instr), RT(instr));
|
||||
break;
|
||||
case BLEZL:
|
||||
bl(instr, LE, RS(instr));
|
||||
break;
|
||||
case BGTZL:
|
||||
bl(instr, GT, RS(instr));
|
||||
break;
|
||||
case DADDI:
|
||||
daddi(instr);
|
||||
break;
|
||||
case DADDIU:
|
||||
daddiu(instr);
|
||||
break;
|
||||
case LDL:
|
||||
ldl(instr);
|
||||
break;
|
||||
case LDR:
|
||||
ldr(instr);
|
||||
break;
|
||||
case 0x1F:
|
||||
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
||||
break;
|
||||
case LB:
|
||||
lb(instr);
|
||||
break;
|
||||
case LH:
|
||||
lh(instr);
|
||||
break;
|
||||
case LWL:
|
||||
lwl(instr);
|
||||
break;
|
||||
case LW:
|
||||
lw(instr);
|
||||
break;
|
||||
case LBU:
|
||||
lbu(instr);
|
||||
break;
|
||||
case LHU:
|
||||
lhu(instr);
|
||||
break;
|
||||
case LWR:
|
||||
lwr(instr);
|
||||
break;
|
||||
case LWU:
|
||||
lwu(instr);
|
||||
break;
|
||||
case SB:
|
||||
sb(instr);
|
||||
break;
|
||||
case SH:
|
||||
sh(instr);
|
||||
break;
|
||||
case SWL:
|
||||
swl(instr);
|
||||
break;
|
||||
case SW:
|
||||
sw(instr);
|
||||
break;
|
||||
case SDL:
|
||||
sdl(instr);
|
||||
break;
|
||||
case SDR:
|
||||
sdr(instr);
|
||||
break;
|
||||
case SWR:
|
||||
swr(instr);
|
||||
break;
|
||||
case CACHE:
|
||||
break; // CACHE
|
||||
case LL:
|
||||
ll(instr);
|
||||
break;
|
||||
case LWC1:
|
||||
lwc1(instr);
|
||||
break;
|
||||
case LLD:
|
||||
lld(instr);
|
||||
break;
|
||||
case LDC1:
|
||||
ldc1(instr);
|
||||
break;
|
||||
case LD:
|
||||
ld(instr);
|
||||
break;
|
||||
case SC:
|
||||
sc(instr);
|
||||
break;
|
||||
case SWC1:
|
||||
swc1(instr);
|
||||
break;
|
||||
case SCD:
|
||||
scd(instr);
|
||||
break;
|
||||
case SDC1:
|
||||
sdc1(instr);
|
||||
break;
|
||||
case SD:
|
||||
sd(instr);
|
||||
break;
|
||||
default:
|
||||
Util::panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})", mask, instr, static_cast<u64>(regs.oldPC));
|
||||
}
|
||||
}
|
||||
} // namespace n64
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
#include <CpuDefinitions.hpp>
|
||||
|
||||
namespace n64 {
|
||||
static inline bool SpecialEndsBlock(u32 instr) {
|
||||
u8 mask = instr & 0x3F;
|
||||
switch (mask) {
|
||||
static bool SpecialEndsBlock(const u32 instr) {
|
||||
switch (instr & 0x3F) {
|
||||
case JR:
|
||||
case JALR:
|
||||
case SYSCALL:
|
||||
@@ -20,9 +20,8 @@ static inline bool SpecialEndsBlock(u32 instr) {
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool InstrEndsBlock(u32 instr) {
|
||||
u8 mask = (instr >> 26) & 0x3f;
|
||||
switch (mask) {
|
||||
static bool InstrEndsBlock(const u32 instr) {
|
||||
switch (instr >> 26 & 0x3f) {
|
||||
case SPECIAL:
|
||||
return SpecialEndsBlock(instr);
|
||||
case REGIMM:
|
||||
|
||||
@@ -79,6 +79,75 @@ void JIT::and_(u32 instr) {
|
||||
}
|
||||
}
|
||||
|
||||
void branch(Registers ®s, const bool cond, const s64 address) {
|
||||
regs.delaySlot = true;
|
||||
if (cond) {
|
||||
regs.nextPC = address;
|
||||
}
|
||||
}
|
||||
|
||||
void branch_likely(Registers ®s, const bool cond, const s64 address) {
|
||||
if (cond) {
|
||||
regs.delaySlot = true;
|
||||
regs.nextPC = address;
|
||||
} else {
|
||||
regs.SetPC64(regs.nextPC);
|
||||
}
|
||||
}
|
||||
|
||||
bool EvaluateCondition(Registers ®s, BranchCondition, u32, u32) {
|
||||
Util::panic("[JIT]: non-constant EvaluateCondition!");
|
||||
}
|
||||
|
||||
bool EvaluateConditionConstant(Registers ®s, const BranchCondition cond, const u32 reg1, const u32 reg2) {
|
||||
switch (cond) {
|
||||
case EQ:
|
||||
return regs.Read<s64>(reg1) == regs.Read<s64>(reg2);
|
||||
case NE:
|
||||
return regs.Read<s64>(reg1) != regs.Read<s64>(reg2);
|
||||
case LT:
|
||||
return regs.Read<s64>(reg1) < regs.Read<s64>(reg2);
|
||||
case LE:
|
||||
return regs.Read<s64>(reg1) <= regs.Read<s64>(reg2);
|
||||
case GT:
|
||||
return regs.Read<s64>(reg1) > regs.Read<s64>(reg2);
|
||||
case GE:
|
||||
return regs.Read<s64>(reg1) >= regs.Read<s64>(reg2);
|
||||
case LTU:
|
||||
return regs.Read<u64>(reg1) < regs.Read<u64>(reg2);
|
||||
case LEU:
|
||||
return regs.Read<u64>(reg1) <= regs.Read<u64>(reg2);
|
||||
case GTU:
|
||||
return regs.Read<u64>(reg1) > regs.Read<u64>(reg2);
|
||||
case GEU:
|
||||
return regs.Read<u64>(reg1) >= regs.Read<u64>(reg2);
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::b(u32 instr, BranchCondition cond, u32 reg1, u32 reg2) {
|
||||
bool isConstant = regs.IsRegConstant(reg1, reg2);
|
||||
if (isConstant) {
|
||||
const s16 imm = instr;
|
||||
const s64 offset = u64((s64)imm) << 2;
|
||||
const s64 address = regs.pc + offset;
|
||||
branch(regs, EvaluateConditionConstant(regs, cond, reg1, reg2), address);
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::b(u32 instr, BranchCondition cond, u32 reg) {}
|
||||
|
||||
void JIT::blink(u32 instr, BranchCondition cond, u32 reg1, u32 reg2) {}
|
||||
|
||||
void JIT::blink(u32 instr, BranchCondition cond, u32 reg) {}
|
||||
|
||||
void JIT::bl(u32 instr, BranchCondition cond, u32 reg1, u32 reg2) {}
|
||||
|
||||
void JIT::bl(u32 instr, BranchCondition cond, u32 reg) {}
|
||||
|
||||
void JIT::bllink(u32 instr, BranchCondition cond, u32 reg1, u32 reg2) {}
|
||||
|
||||
void JIT::bllink(u32 instr, BranchCondition cond, u32 reg) {}
|
||||
|
||||
void JIT::dadd(u32 instr) {
|
||||
if (regs.IsRegConstant(RS(instr), RT(instr))) {
|
||||
auto rs = regs.Read<u64>(RS(instr));
|
||||
|
||||
Reference in New Issue
Block a user