Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 204f0e13b0 | |||
| cb8bb634ae |
@@ -19,7 +19,7 @@ struct Core {
|
||||
return instance;
|
||||
}
|
||||
|
||||
static inline bool IsAddressError(u8 mask, u64 vaddr) {
|
||||
static inline bool IsAddressError(u8 mask, s64 vaddr) {
|
||||
auto regs = GetRegs();
|
||||
return (!regs.cop0.is64BitAddressing && s32(vaddr) != vaddr) || (vaddr & mask) != 0;
|
||||
}
|
||||
|
||||
@@ -116,8 +116,8 @@ u32 Interpreter::CacheBlock(u32 addr) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (InstrEndsBlock(instr)) {
|
||||
if (InstrHasDelaySlot(instr) && !fetchDelaySlot) {
|
||||
if (instr.EndsBlock()) {
|
||||
if (instr.HasDelaySlot() && !fetchDelaySlot) {
|
||||
fetchDelaySlot = true;
|
||||
continue;
|
||||
}
|
||||
@@ -129,6 +129,45 @@ u32 Interpreter::CacheBlock(u32 addr) {
|
||||
}
|
||||
}
|
||||
|
||||
auto delay = line.code[i - 1];
|
||||
|
||||
if (i == 2) {
|
||||
// branch to itself
|
||||
// _nop
|
||||
|
||||
auto branch = line.code[i - 2];
|
||||
line.idleSkip = branch.IsBranch() && branch.offset() == -4 && delay.instr.raw == 0;
|
||||
}
|
||||
|
||||
if (i == 3) {
|
||||
// load reg1, [some location]
|
||||
// bcond reg2
|
||||
// _andi reg2, reg1, immediate
|
||||
|
||||
auto branch = line.code[i - 2];
|
||||
auto load = line.code[i - 3]; // load
|
||||
|
||||
line.idleSkip = (load.opcode() == Instruction::LW || load.opcode() == Instruction::LWU) &&
|
||||
delay.opcode() == Instruction::ANDI && branch.IsBranch() && branch.offset() == -16 &&
|
||||
load.rt() == delay.rs() && delay.rt() == branch.rs();
|
||||
}
|
||||
|
||||
if (i == 5) {
|
||||
// lui reg1
|
||||
// load reg2, [reg1(offset)]
|
||||
// andi reg3, reg2, immediate
|
||||
// bcond reg3
|
||||
// _nop
|
||||
|
||||
auto branch = line.code[i - 2];
|
||||
auto andi = line.code[i - 3]; // andi
|
||||
auto load = line.code[i - 4]; // load
|
||||
|
||||
line.idleSkip = (load.opcode() == Instruction::LW || load.opcode() == Instruction::LWU) &&
|
||||
andi.opcode() == Instruction::ANDI && branch.IsBranch() && branch.offset() == -16 &&
|
||||
load.rt() == andi.rs() && andi.rt() == branch.rs();
|
||||
}
|
||||
|
||||
line.cycles = i;
|
||||
line.len = i;
|
||||
cachedState.blocks[CACHE_GET_BLOCK(blockAddr)]->lines[CACHE_GET_LINE(blockAddr)] = new CachedLine(line);
|
||||
@@ -162,7 +201,7 @@ u32 Interpreter::ExecuteCached() {
|
||||
return i + 1;
|
||||
|
||||
// Branch likely with false condition, it wasn't taken so don't execute the delay slot
|
||||
if (IsBranchLikely(instr) && !regs.delaySlot)
|
||||
if (instr.IsBranchLikely() && !regs.delaySlot)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ void JIT::InvalidateBlock(const u32 paddr) {
|
||||
blockCache[index] = {};
|
||||
}
|
||||
|
||||
std::optional<u32> JIT::FetchInstruction(s64 vaddr) {
|
||||
std::optional<Instruction> JIT::FetchInstruction(s64 vaddr) {
|
||||
u32 paddr = 0;
|
||||
|
||||
if (Core::IsAddressError(0b11, vaddr)) [[unlikely]] {
|
||||
@@ -62,7 +62,7 @@ std::optional<u32> JIT::FetchInstruction(s64 vaddr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const u32 instr = Core::GetMem().Read<u32>(paddr);
|
||||
const Instruction instr = Core::GetMem().Read<u32>(paddr);
|
||||
|
||||
info("{}", Disassembler::GetInstance().DisassembleSimple(paddr, instr).full);
|
||||
|
||||
@@ -169,12 +169,12 @@ u32 JIT::Step() {
|
||||
blockPC = blockNextPC;
|
||||
blockNextPC += 4;
|
||||
|
||||
if (InstrEndsBlock(instruction.value())) {
|
||||
const auto delay_instruction = FetchInstruction(blockPC); // get instruction in delay slot
|
||||
if (instruction.value().EndsBlock()) {
|
||||
auto delay_instruction = FetchInstruction(blockPC); // get instruction in delay slot
|
||||
if (!delay_instruction)
|
||||
return 0;
|
||||
|
||||
if (InstrEndsBlock(delay_instruction.value())) {
|
||||
if (delay_instruction.value().EndsBlock()) {
|
||||
Util::Error::GetInstance().Throw({Util::Error::Severity::NON_FATAL},
|
||||
{Util::Error::Type::JIT_BRANCH_INSIDE_DELAY_SLOT}, blockPC, {},
|
||||
"[JIT]: Unhandled case of branch from delay slot!");
|
||||
|
||||
@@ -118,7 +118,7 @@ struct JIT final {
|
||||
|
||||
[[nodiscard]] bool ShouldServiceInterrupt() const;
|
||||
void CheckCompareInterrupt() const;
|
||||
std::optional<u32> FetchInstruction(s64);
|
||||
std::optional<Instruction> FetchInstruction(s64);
|
||||
|
||||
void Emit(Instruction);
|
||||
void special(Instruction);
|
||||
|
||||
@@ -2,144 +2,6 @@
|
||||
#include <Instruction.hpp>
|
||||
|
||||
namespace n64 {
|
||||
static bool SpecialEndsBlock(const Instruction instr) {
|
||||
switch (instr.special()) {
|
||||
case Instruction::JR:
|
||||
case Instruction::JALR:
|
||||
case Instruction::SYSCALL:
|
||||
case Instruction::BREAK:
|
||||
case Instruction::TGE:
|
||||
case Instruction::TGEU:
|
||||
case Instruction::TLT:
|
||||
case Instruction::TLTU:
|
||||
case Instruction::TEQ:
|
||||
case Instruction::TNE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool InstrHasDelaySlot(const Instruction instr) {
|
||||
switch (instr.opcode()) {
|
||||
case Instruction::SPECIAL:
|
||||
if (instr.special() == Instruction::JR || instr.special() == Instruction::JALR)
|
||||
return true;
|
||||
return false;
|
||||
case Instruction::REGIMM:
|
||||
case Instruction::J:
|
||||
case Instruction::JAL:
|
||||
case Instruction::BEQ:
|
||||
case Instruction::BNE:
|
||||
case Instruction::BLEZ:
|
||||
case Instruction::BGTZ:
|
||||
case Instruction::BEQL:
|
||||
case Instruction::BNEL:
|
||||
case Instruction::BLEZL:
|
||||
case Instruction::BGTZL:
|
||||
return true;
|
||||
case Instruction::COP1:
|
||||
if (instr.cop_rs() == 8)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool InstrEndsBlock(const Instruction instr) {
|
||||
switch (instr.opcode()) {
|
||||
case Instruction::SPECIAL:
|
||||
return SpecialEndsBlock(instr);
|
||||
case Instruction::REGIMM:
|
||||
case Instruction::J:
|
||||
case Instruction::JAL:
|
||||
case Instruction::BEQ:
|
||||
case Instruction::BNE:
|
||||
case Instruction::BLEZ:
|
||||
case Instruction::BGTZ:
|
||||
case Instruction::BEQL:
|
||||
case Instruction::BNEL:
|
||||
case Instruction::BLEZL:
|
||||
case Instruction::BGTZL:
|
||||
return true;
|
||||
case Instruction::COP1:
|
||||
if (instr.cop_rs() == 8)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
case Instruction::COP0:
|
||||
switch (instr.cop_rs()) {
|
||||
case 0x10 ... 0x1F:
|
||||
switch (instr.cop_funct()) {
|
||||
case 0x18: // eret
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsBranchLikely(const Instruction instr) {
|
||||
switch (instr.opcode()) {
|
||||
case Instruction::BEQL:
|
||||
case Instruction::BNEL:
|
||||
case Instruction::BLEZL:
|
||||
case Instruction::BGTZL:
|
||||
return true;
|
||||
case Instruction::REGIMM:
|
||||
switch (instr.regimm()) {
|
||||
case Instruction::BLTZL:
|
||||
case Instruction::BGEZL:
|
||||
case Instruction::BLTZALL:
|
||||
case Instruction::BGEZALL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case Instruction::COP1:
|
||||
if (instr.cop_rs() == 8 && (instr.cop_rt() == 2 || instr.cop_rt() == 3))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsBranch(const Instruction instr) {
|
||||
switch (instr.opcode()) {
|
||||
case Instruction::BEQ:
|
||||
case Instruction::BNE:
|
||||
case Instruction::BLEZ:
|
||||
case Instruction::BGTZ:
|
||||
return true;
|
||||
case Instruction::REGIMM:
|
||||
switch (instr.regimm()) {
|
||||
case Instruction::BLTZ:
|
||||
case Instruction::BGEZ:
|
||||
case Instruction::BLTZAL:
|
||||
case Instruction::BGEZAL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case Instruction::COP1:
|
||||
if (instr.cop_rs() == 8 && (instr.cop_rt() == 0 || instr.cop_rt() == 1))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#define ARG1 rcx
|
||||
#define ARG2 rdx
|
||||
|
||||
+137
-2
@@ -24,8 +24,8 @@ struct Instruction {
|
||||
inline u8 e1() const { return (instr.raw >> 7) & 0x0f; }
|
||||
inline u8 e2() const { return rs() & 0x0f; }
|
||||
inline u8 op() const { return rt(); }
|
||||
inline u16 imm() const { return instr.itype.imm; }
|
||||
inline u16 offset() const { return imm(); }
|
||||
inline s16 imm() const { return instr.itype.imm; }
|
||||
inline s64 offset() const { return s64(imm()) << 2; }
|
||||
inline u32 target() const { return instr.jtype.target; }
|
||||
inline u8 opcode() const { return instr.opcode.op; }
|
||||
inline u8 special() const { return instr.opcode.special; }
|
||||
@@ -99,6 +99,141 @@ struct Instruction {
|
||||
u32 raw;
|
||||
} instr{};
|
||||
|
||||
bool IsBranch() {
|
||||
switch (opcode()) {
|
||||
case Instruction::BEQ:
|
||||
case Instruction::BNE:
|
||||
case Instruction::BLEZ:
|
||||
case Instruction::BGTZ:
|
||||
return true;
|
||||
case Instruction::REGIMM:
|
||||
switch (regimm()) {
|
||||
case Instruction::BLTZ:
|
||||
case Instruction::BGEZ:
|
||||
case Instruction::BLTZAL:
|
||||
case Instruction::BGEZAL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case Instruction::COP1:
|
||||
if (cop_rs() == 8 && (cop_rt() == 0 || cop_rt() == 1))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool HasDelaySlot() {
|
||||
switch (opcode()) {
|
||||
case Instruction::SPECIAL:
|
||||
if (special() == Instruction::JR || special() == Instruction::JALR)
|
||||
return true;
|
||||
return false;
|
||||
case Instruction::REGIMM:
|
||||
case Instruction::J:
|
||||
case Instruction::JAL:
|
||||
case Instruction::BEQ:
|
||||
case Instruction::BNE:
|
||||
case Instruction::BLEZ:
|
||||
case Instruction::BGTZ:
|
||||
case Instruction::BEQL:
|
||||
case Instruction::BNEL:
|
||||
case Instruction::BLEZL:
|
||||
case Instruction::BGTZL:
|
||||
return true;
|
||||
case Instruction::COP1:
|
||||
if (cop_rs() == 8)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool EndsBlock() {
|
||||
switch (opcode()) {
|
||||
case Instruction::SPECIAL:
|
||||
switch (special()) {
|
||||
case Instruction::JR:
|
||||
case Instruction::JALR:
|
||||
case Instruction::SYSCALL:
|
||||
case Instruction::BREAK:
|
||||
case Instruction::TGE:
|
||||
case Instruction::TGEU:
|
||||
case Instruction::TLT:
|
||||
case Instruction::TLTU:
|
||||
case Instruction::TEQ:
|
||||
case Instruction::TNE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case Instruction::REGIMM:
|
||||
case Instruction::J:
|
||||
case Instruction::JAL:
|
||||
case Instruction::BEQ:
|
||||
case Instruction::BNE:
|
||||
case Instruction::BLEZ:
|
||||
case Instruction::BGTZ:
|
||||
case Instruction::BEQL:
|
||||
case Instruction::BNEL:
|
||||
case Instruction::BLEZL:
|
||||
case Instruction::BGTZL:
|
||||
return true;
|
||||
case Instruction::COP1:
|
||||
if (cop_rs() == 8)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
case Instruction::COP0:
|
||||
switch (cop_rs()) {
|
||||
case 0x10 ... 0x1F:
|
||||
switch (cop_funct()) {
|
||||
case 0x18: // eret
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsBranchLikely() {
|
||||
switch (opcode()) {
|
||||
case Instruction::BEQL:
|
||||
case Instruction::BNEL:
|
||||
case Instruction::BLEZL:
|
||||
case Instruction::BGTZL:
|
||||
return true;
|
||||
case Instruction::REGIMM:
|
||||
switch (regimm()) {
|
||||
case Instruction::BLTZL:
|
||||
case Instruction::BGEZL:
|
||||
case Instruction::BLTZALL:
|
||||
case Instruction::BGEZALL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case Instruction::COP1:
|
||||
if (cop_rs() == 8 && (cop_rt() == 2 || cop_rt() == 3))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static constexpr u8 SPECIAL = 0b000000;
|
||||
static constexpr u8 REGIMM = 0b000001;
|
||||
static constexpr u8 J = 0b000010;
|
||||
|
||||
Reference in New Issue
Block a user