fix jit boogs
This commit is contained in:
@@ -13,6 +13,7 @@ if(APPLE)
|
|||||||
enable_language(OBJC)
|
enable_language(OBJC)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(VULKAN_VALIDATION FALSE)
|
||||||
set(SANITIZERS FALSE)
|
set(SANITIZERS FALSE)
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
@@ -102,7 +103,8 @@ if (HAS_SIMD)
|
|||||||
add_compile_options(${SIMD_FLAG})
|
add_compile_options(${SIMD_FLAG})
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (${CMAKE_BUILD_TYPE} MATCHES Debug)
|
if (${CMAKE_BUILD_TYPE} MATCHES Debug AND VULKAN_VALIDATION)
|
||||||
|
message("VALIDATION LAYERS: ON")
|
||||||
add_compile_definitions(VULKAN_DEBUG)
|
add_compile_definitions(VULKAN_DEBUG)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,14 @@
|
|||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
Core::Core() {
|
Core::Core() {
|
||||||
auto cpuType = Options::GetInstance().GetValue<std::string>("cpu", "type");
|
const auto selectedCpu = Options::GetInstance().GetValue<std::string>("cpu", "type");
|
||||||
if (cpuType == "interpreter") {
|
if (selectedCpu == "interpreter") {
|
||||||
cpuType = Interpreted;
|
cpuType = Interpreted;
|
||||||
cpu = std::make_unique<Interpreter>(parallel, *mem, regs);
|
cpu = std::make_unique<Interpreter>(*mem, regs);
|
||||||
} else if(cpuType == "jit") {
|
} else if(selectedCpu == "jit") {
|
||||||
#ifndef __aarch64__
|
#ifndef __aarch64__
|
||||||
cpuType = DynamicRecompiler;
|
cpuType = DynamicRecompiler;
|
||||||
cpu = std::make_unique<JIT>(parallel, *mem, regs);
|
cpu = std::make_unique<JIT>(*mem, regs);
|
||||||
#else
|
#else
|
||||||
panic("JIT currently unsupported on aarch64");
|
panic("JIT currently unsupported on aarch64");
|
||||||
#endif
|
#endif
|
||||||
@@ -62,11 +62,11 @@ void Core::LoadROM(const std::string &rom_) {
|
|||||||
romLoaded = true;
|
romLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Core::StepCPU() {
|
u32 Core::StepCPU() {
|
||||||
return cpu->Step() + regs.PopStalledCycles();
|
return cpu->Step() + regs.PopStalledCycles();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::StepRSP(int cpuCycles) {
|
void Core::StepRSP(const u32 cpuCycles) {
|
||||||
MMIO &mmio = mem->mmio;
|
MMIO &mmio = mem->mmio;
|
||||||
|
|
||||||
if (mmio.rsp.spStatus.halt) {
|
if (mmio.rsp.spStatus.halt) {
|
||||||
@@ -75,10 +75,10 @@ void Core::StepRSP(int cpuCycles) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr int cpuRatio = 3, rspRatio = 2;
|
static constexpr u32 cpuRatio = 3, rspRatio = 2;
|
||||||
|
|
||||||
regs.steps += cpuCycles;
|
regs.steps += cpuCycles;
|
||||||
int sets = regs.steps / cpuRatio;
|
const auto sets = regs.steps / cpuRatio;
|
||||||
mmio.rsp.steps += sets * rspRatio;
|
mmio.rsp.steps += sets * rspRatio;
|
||||||
regs.steps -= sets * cpuRatio;
|
regs.steps -= sets * cpuRatio;
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ void Core::StepRSP(int cpuCycles) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Run(float volumeL, float volumeR) {
|
void Core::Run(const float volumeL, const float volumeR) {
|
||||||
MMIO &mmio = mem->mmio;
|
MMIO &mmio = mem->mmio;
|
||||||
|
|
||||||
bool broken = false;
|
bool broken = false;
|
||||||
@@ -102,7 +102,7 @@ void Core::Run(float volumeL, float volumeR) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while(cycles < mem->mmio.vi.cyclesPerHalfline) {
|
while(cycles < mem->mmio.vi.cyclesPerHalfline) {
|
||||||
u32 taken = StepCPU();
|
const u32 taken = StepCPU();
|
||||||
cycles += taken;
|
cycles += taken;
|
||||||
|
|
||||||
if((broken = breakpoints.contains(regs.nextPC)))
|
if((broken = breakpoints.contains(regs.nextPC)))
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ struct Core {
|
|||||||
return *GetInstance().mem;
|
return *GetInstance().mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
int StepCPU();
|
u32 StepCPU();
|
||||||
void StepRSP(int cpuCycles);
|
void StepRSP(u32 cpuCycles);
|
||||||
void Stop();
|
void Stop();
|
||||||
void Reset();
|
void Reset();
|
||||||
void LoadROM(const std::string &);
|
void LoadROM(const std::string &);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
namespace n64 {
|
namespace n64 {
|
||||||
struct BaseCPU {
|
struct BaseCPU {
|
||||||
virtual ~BaseCPU() = default;
|
virtual ~BaseCPU() = default;
|
||||||
virtual int Step() = 0;
|
virtual u32 Step() = 0;
|
||||||
virtual void Reset() = 0;
|
virtual void Reset() = 0;
|
||||||
};
|
};
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include <Core.hpp>
|
#include <Core.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
Interpreter::Interpreter(ParallelRDP& parallel, Mem& mem, Registers& regs) : mem(mem), regs(regs) {}
|
Interpreter::Interpreter(Mem& mem, Registers& regs) : regs(regs), mem(mem) {}
|
||||||
|
|
||||||
bool Interpreter::ShouldServiceInterrupt() const {
|
bool Interpreter::ShouldServiceInterrupt() const {
|
||||||
const bool interrupts_pending = (regs.cop0.status.im & regs.cop0.cause.interruptPending) != 0;
|
const bool interrupts_pending = (regs.cop0.status.im & regs.cop0.cause.interruptPending) != 0;
|
||||||
@@ -12,7 +12,7 @@ bool Interpreter::ShouldServiceInterrupt() const {
|
|||||||
return interrupts_pending && interrupts_enabled && !currently_handling_exception && !currently_handling_error;
|
return interrupts_pending && interrupts_enabled && !currently_handling_exception && !currently_handling_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::CheckCompareInterrupt() {
|
void Interpreter::CheckCompareInterrupt() const {
|
||||||
regs.cop0.count++;
|
regs.cop0.count++;
|
||||||
regs.cop0.count &= 0x1FFFFFFFF;
|
regs.cop0.count &= 0x1FFFFFFFF;
|
||||||
if (regs.cop0.count == static_cast<u64>(regs.cop0.compare) << 1) {
|
if (regs.cop0.count == static_cast<u64>(regs.cop0.compare) << 1) {
|
||||||
@@ -21,7 +21,7 @@ void Interpreter::CheckCompareInterrupt() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int Interpreter::Step() {
|
u32 Interpreter::Step() {
|
||||||
CheckCompareInterrupt();
|
CheckCompareInterrupt();
|
||||||
|
|
||||||
regs.prevDelaySlot = regs.delaySlot;
|
regs.prevDelaySlot = regs.delaySlot;
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
namespace n64 {
|
namespace n64 {
|
||||||
struct Core;
|
struct Core;
|
||||||
|
|
||||||
struct Interpreter : BaseCPU {
|
struct Interpreter final : BaseCPU {
|
||||||
explicit Interpreter(ParallelRDP&, Mem&, Registers&);
|
explicit Interpreter(Mem&, Registers&);
|
||||||
~Interpreter() override = default;
|
~Interpreter() override = default;
|
||||||
int Step() override;
|
u32 Step() override;
|
||||||
|
|
||||||
void Reset() override {
|
void Reset() override {
|
||||||
cop2Latch = {};
|
cop2Latch = {};
|
||||||
@@ -22,8 +22,8 @@ private:
|
|||||||
friend struct Cop1;
|
friend struct Cop1;
|
||||||
#define check_address_error(mask, vaddr) \
|
#define check_address_error(mask, vaddr) \
|
||||||
(((!regs.cop0.is64BitAddressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0))
|
(((!regs.cop0.is64BitAddressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0))
|
||||||
bool ShouldServiceInterrupt() const;
|
[[nodiscard]] bool ShouldServiceInterrupt() const;
|
||||||
void CheckCompareInterrupt();
|
void CheckCompareInterrupt() const;
|
||||||
|
|
||||||
void cop2Decode(Instruction);
|
void cop2Decode(Instruction);
|
||||||
void special(Instruction);
|
void special(Instruction);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
#ifndef __aarch64__
|
#ifndef __aarch64__
|
||||||
JIT::JIT(ParallelRDP& parallel, Mem& mem, Registers& regs) : mem(mem), regs(regs) {
|
JIT::JIT(Mem& mem, Registers& regs) : regs(regs), mem(mem) {
|
||||||
regs.SetJIT(this);
|
regs.SetJIT(this);
|
||||||
blockCache.resize(kUpperSize);
|
blockCache.resize(kUpperSize);
|
||||||
if (cs_open(CS_ARCH_MIPS, static_cast<cs_mode>(CS_MODE_MIPS64 | CS_MODE_BIG_ENDIAN), &disassemblerMips) !=
|
if (cs_open(CS_ARCH_MIPS, static_cast<cs_mode>(CS_MODE_MIPS64 | CS_MODE_BIG_ENDIAN), &disassemblerMips) !=
|
||||||
@@ -25,7 +25,7 @@ bool JIT::ShouldServiceInterrupt() const {
|
|||||||
return interrupts_pending && interrupts_enabled && !currently_handling_exception && !currently_handling_error;
|
return interrupts_pending && interrupts_enabled && !currently_handling_exception && !currently_handling_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JIT::CheckCompareInterrupt() {
|
void JIT::CheckCompareInterrupt() const {
|
||||||
regs.cop0.count++;
|
regs.cop0.count++;
|
||||||
regs.cop0.count &= 0x1FFFFFFFF;
|
regs.cop0.count &= 0x1FFFFFFFF;
|
||||||
if (regs.cop0.count == static_cast<u64>(regs.cop0.compare) << 1) {
|
if (regs.cop0.count == static_cast<u64>(regs.cop0.compare) << 1) {
|
||||||
@@ -63,19 +63,23 @@ u32 JIT::FetchInstruction() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Core::GetMem().Read<u32>(paddr);
|
const u32 instr = Core::GetMem().Read<u32>(paddr);
|
||||||
|
|
||||||
|
info("{}", Disassembler::GetInstance().DisassembleSimple(paddr, instr).full);
|
||||||
|
|
||||||
|
return instr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JIT::SetPC32(s32 val) {
|
void JIT::SetPC32(const s32 val) {
|
||||||
code.mov(code.SCR1, REG(qword, pc));
|
code.mov(code.SCR1, REG(qword, pc));
|
||||||
code.mov(REG(qword, oldPC), code.SCR1);
|
code.mov(REG(qword, oldPC), code.SCR1);
|
||||||
code.mov(code.SCR1, s64(val));
|
code.mov(code.SCR1, val);
|
||||||
code.mov(REG(qword, pc), code.SCR1);
|
code.mov(REG(qword, pc), code.SCR1);
|
||||||
code.mov(code.SCR1, s64(val) + 4);
|
code.mov(code.SCR1, val + 4);
|
||||||
code.mov(REG(qword, nextPC), code.SCR1);
|
code.mov(REG(qword, nextPC), code.SCR1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JIT::SetPC64(s64 val) {
|
void JIT::SetPC64(const s64 val) {
|
||||||
code.mov(code.SCR1, REG(qword, pc));
|
code.mov(code.SCR1, REG(qword, pc));
|
||||||
code.mov(REG(qword, oldPC), code.SCR1);
|
code.mov(REG(qword, oldPC), code.SCR1);
|
||||||
code.mov(code.SCR1, val);
|
code.mov(code.SCR1, val);
|
||||||
@@ -101,7 +105,7 @@ void JIT::SetPC64(const Xbyak::Reg64& val) {
|
|||||||
code.mov(REG(qword, nextPC), val);
|
code.mov(REG(qword, nextPC), val);
|
||||||
}
|
}
|
||||||
|
|
||||||
int JIT::Step() {
|
u32 JIT::Step() {
|
||||||
blockOldPC = regs.oldPC;
|
blockOldPC = regs.oldPC;
|
||||||
blockPC = regs.pc;
|
blockPC = regs.pc;
|
||||||
blockNextPC = regs.nextPC;
|
blockNextPC = regs.nextPC;
|
||||||
@@ -111,15 +115,15 @@ int JIT::Step() {
|
|||||||
/*regs.cop0.HandleTLBException(blockPC);
|
/*regs.cop0.HandleTLBException(blockPC);
|
||||||
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, blockPC);
|
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, blockPC);
|
||||||
return 1;*/
|
return 1;*/
|
||||||
Util::Error::GetInstance().Throw(
|
Util::Error::GetInstance().Throw({Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_EXCEPTION},
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_EXCEPTION}, blockPC, {},
|
blockPC, {},
|
||||||
"[JIT]: Unhandled exception TLB exception {} when retrieving PC physical address!",
|
"[JIT]: Unhandled exception TLB exception {} when retrieving PC physical address!",
|
||||||
static_cast<int>(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD)));
|
static_cast<int>(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD)));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 upperIndex = paddr >> kUpperShift;
|
const u32 upperIndex = paddr >> kUpperShift;
|
||||||
u32 lowerIndex = paddr & kLowerMask;
|
const u32 lowerIndex = paddr & kLowerMask;
|
||||||
|
|
||||||
if (!blockCache[upperIndex].empty()) {
|
if (!blockCache[upperIndex].empty()) {
|
||||||
if (blockCache[upperIndex][lowerIndex]) {
|
if (blockCache[upperIndex][lowerIndex]) {
|
||||||
@@ -130,7 +134,7 @@ int JIT::Step() {
|
|||||||
blockCache[upperIndex].resize(kLowerSize);
|
blockCache[upperIndex].resize(kLowerSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
info("[JIT]: Compiling block @ 0x{:016X}:", blockPC);
|
info("[JIT]: Compiling block @ 0x{:016X}:", static_cast<u64>(blockPC));
|
||||||
const auto blockInfo = code.getCurr();
|
const auto blockInfo = code.getCurr();
|
||||||
const auto block = code.getCurr<BlockFn>();
|
const auto block = code.getCurr<BlockFn>();
|
||||||
blockCache[upperIndex][lowerIndex] = block;
|
blockCache[upperIndex][lowerIndex] = block;
|
||||||
@@ -147,8 +151,12 @@ int JIT::Step() {
|
|||||||
code.mov(code.rbp, reinterpret_cast<uintptr_t>(this)); // Load context pointer
|
code.mov(code.rbp, reinterpret_cast<uintptr_t>(this)); // Load context pointer
|
||||||
|
|
||||||
cs_insn *insn;
|
cs_insn *insn;
|
||||||
info("\tMIPS code (guest PC = 0x{:016X}):", blockPC);
|
info("\tMIPS code (guest PC = 0x{:016X}):", static_cast<u64>(blockPC));
|
||||||
while (!instrEndsBlock) {
|
while (!instrEndsBlock) {
|
||||||
|
code.mov(code.SCR1, REG(byte, delaySlot));
|
||||||
|
code.mov(REG(byte, prevDelaySlot), code.SCR1);
|
||||||
|
code.mov(REG(byte, delaySlot), 0);
|
||||||
|
|
||||||
// CheckCompareInterrupt();
|
// CheckCompareInterrupt();
|
||||||
paddr = 0;
|
paddr = 0;
|
||||||
|
|
||||||
@@ -194,6 +202,7 @@ int JIT::Step() {
|
|||||||
|
|
||||||
instructionsInBlock++;
|
instructionsInBlock++;
|
||||||
const u32 delay_instruction = FetchInstruction();
|
const u32 delay_instruction = FetchInstruction();
|
||||||
|
|
||||||
instrEndsBlock = InstrEndsBlock(delay_instruction);
|
instrEndsBlock = InstrEndsBlock(delay_instruction);
|
||||||
if(instrEndsBlock) {
|
if(instrEndsBlock) {
|
||||||
Util::Error::GetInstance().Throw(
|
Util::Error::GetInstance().Throw(
|
||||||
@@ -210,25 +219,30 @@ int JIT::Step() {
|
|||||||
|
|
||||||
Emit(instruction);
|
Emit(instruction);
|
||||||
|
|
||||||
if(!regs.delaySlot) {
|
Xbyak::Label clearDelaySlot;
|
||||||
|
|
||||||
|
code.mov(code.SCR1, REG(byte, delaySlot));
|
||||||
|
code.cmp(code.SCR1, 0);
|
||||||
|
code.jne(clearDelaySlot);
|
||||||
code.mov(code.SCR1, blockOldPC);
|
code.mov(code.SCR1, blockOldPC);
|
||||||
code.mov(REG(qword, oldPC), code.SCR1);
|
code.mov(REG(qword, oldPC), code.SCR1);
|
||||||
code.mov(code.SCR1, blockPC);
|
code.mov(code.SCR1, blockPC);
|
||||||
code.mov(REG(qword, pc), code.SCR1);
|
code.mov(REG(qword, pc), code.SCR1);
|
||||||
code.mov(code.SCR1, blockNextPC);
|
code.mov(code.SCR1, blockNextPC);
|
||||||
code.mov(REG(qword, nextPC), code.SCR1);
|
code.mov(REG(qword, nextPC), code.SCR1);
|
||||||
}
|
code.L(clearDelaySlot);
|
||||||
|
code.mov(REG(byte, delaySlot), 0);
|
||||||
|
|
||||||
code.mov(code.rax, instructionsInBlock);
|
code.mov(code.rax, instructionsInBlock);
|
||||||
code.pop(code.rbp);
|
code.pop(code.rbp);
|
||||||
code.add(code.rsp, 8);
|
code.add(code.rsp, 8);
|
||||||
code.ret();
|
code.ret();
|
||||||
code.setProtectModeRE();
|
code.setProtectModeRE();
|
||||||
static auto blockInfoSize = 0;
|
static size_t blockInfoSize = 0;
|
||||||
blockInfoSize = code.getSize() - blockInfoSize;
|
blockInfoSize = code.getSize() - blockInfoSize;
|
||||||
|
|
||||||
info("\tX86 code (block address = 0x{:016X}):", (uintptr_t)block);
|
info("\tX86 code (block address = 0x{:016X}):", reinterpret_cast<uintptr_t>(block));
|
||||||
auto count = cs_disasm(disassemblerX86, blockInfo, blockInfoSize, (uintptr_t)block, 0, &insn);
|
const auto count = cs_disasm(disassemblerX86, blockInfo, blockInfoSize, reinterpret_cast<uintptr_t>(block), 0, &insn);
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
for (size_t j = 0; j < count; j++) {
|
for (size_t j = 0; j < count; j++) {
|
||||||
info("\t\t0x{:016X}:\t{}\t\t{}", insn[j].address, insn[j].mnemonic, insn[j].op_str);
|
info("\t\t0x{:016X}:\t{}\t\t{}", insn[j].address, insn[j].mnemonic, insn[j].op_str);
|
||||||
@@ -241,7 +255,7 @@ int JIT::Step() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void JIT::DumpBlockCacheToDisk() {
|
void JIT::DumpBlockCacheToDisk() const {
|
||||||
Util::WriteFileBinary(code.getCode<u8*>(), code.getSize(), "jit.dump");
|
Util::WriteFileBinary(code.getCode<u8*>(), code.getSize(), "jit.dump");
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -16,15 +16,15 @@ static constexpr u32 kUpperSize = kAddressSpaceSize >> kUpperShift; // 0x800000
|
|||||||
static constexpr u32 kLowerSize = 0x100; // 0x80
|
static constexpr u32 kLowerSize = 0x100; // 0x80
|
||||||
static constexpr u32 kCodeCacheSize = 32_mb;
|
static constexpr u32 kCodeCacheSize = 32_mb;
|
||||||
static constexpr u32 kCodeCacheAllocSize = kCodeCacheSize + 4_kb;
|
static constexpr u32 kCodeCacheAllocSize = kCodeCacheSize + 4_kb;
|
||||||
#define REG(acc, x) code.acc[reinterpret_cast<uintptr_t>(®s.x)]
|
#define REG(acc, x) code.acc[code.rbp + (reinterpret_cast<uintptr_t>(®s.x) - reinterpret_cast<uintptr_t>(this))]
|
||||||
|
|
||||||
#ifdef __aarch64__
|
#ifdef __aarch64__
|
||||||
struct JIT : BaseCPU {};
|
struct JIT : BaseCPU {};
|
||||||
#else
|
#else
|
||||||
struct JIT : BaseCPU {
|
struct JIT final : BaseCPU {
|
||||||
explicit JIT(ParallelRDP&, Mem&, Registers&);
|
explicit JIT(Mem&, Registers&);
|
||||||
~JIT() override = default;
|
~JIT() override = default;
|
||||||
int Step() override;
|
u32 Step() override;
|
||||||
|
|
||||||
void Reset() override {
|
void Reset() override {
|
||||||
code.reset();
|
code.reset();
|
||||||
@@ -32,7 +32,7 @@ struct JIT : BaseCPU {
|
|||||||
blockCache.resize(kUpperSize);
|
blockCache.resize(kUpperSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DumpBlockCacheToDisk();
|
void DumpBlockCacheToDisk() const;
|
||||||
|
|
||||||
void InvalidateBlock(u32);
|
void InvalidateBlock(u32);
|
||||||
private:
|
private:
|
||||||
@@ -40,13 +40,13 @@ private:
|
|||||||
Mem& mem;
|
Mem& mem;
|
||||||
Xbyak::CodeGenerator code{kCodeCacheAllocSize};
|
Xbyak::CodeGenerator code{kCodeCacheAllocSize};
|
||||||
u64 cop2Latch{};
|
u64 cop2Latch{};
|
||||||
u64 blockOldPC = 0, blockPC = 0, blockNextPC = 0;
|
s64 blockOldPC = 0, blockPC = 0, blockNextPC = 0;
|
||||||
friend struct Cop1;
|
friend struct Cop1;
|
||||||
friend struct Registers;
|
friend struct Registers;
|
||||||
using BlockFn = int (*)();
|
using BlockFn = int (*)();
|
||||||
std::vector<std::vector<BlockFn>> blockCache;
|
std::vector<std::vector<BlockFn>> blockCache;
|
||||||
Xbyak::Label branch_likely_not_taken;
|
Xbyak::Label branch_likely_not_taken;
|
||||||
csh disassemblerMips, disassemblerX86;
|
csh disassemblerMips{}, disassemblerX86{};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Xbyak::Address GPR(const size_t index) const {
|
Xbyak::Address GPR(const size_t index) const {
|
||||||
@@ -108,89 +108,89 @@ private:
|
|||||||
(((!regs.cop0.is64BitAddressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0))
|
(((!regs.cop0.is64BitAddressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0))
|
||||||
|
|
||||||
[[nodiscard]] bool ShouldServiceInterrupt() const;
|
[[nodiscard]] bool ShouldServiceInterrupt() const;
|
||||||
void CheckCompareInterrupt();
|
void CheckCompareInterrupt() const;
|
||||||
u32 FetchInstruction();
|
u32 FetchInstruction();
|
||||||
|
|
||||||
void Emit(const Instruction);
|
void Emit(Instruction);
|
||||||
void special(const Instruction);
|
void special(Instruction);
|
||||||
void regimm(const Instruction);
|
void regimm(Instruction);
|
||||||
void add(const Instruction);
|
void add(Instruction);
|
||||||
void addu(const Instruction);
|
void addu(Instruction);
|
||||||
void addi(const Instruction);
|
void addi(Instruction);
|
||||||
void addiu(const Instruction);
|
void addiu(Instruction);
|
||||||
void andi(const Instruction);
|
void andi(Instruction);
|
||||||
void and_(const Instruction);
|
void and_(Instruction);
|
||||||
void branch_constant(bool cond, s64 offset);
|
void branch_constant(bool cond, s64 offset);
|
||||||
void branch_likely_constant(bool cond, s64 offset);
|
void branch_likely_constant(bool cond, s64 offset);
|
||||||
void branch_abs_constant(bool cond, s64 address);
|
void branch_abs_constant(bool cond, s64 address);
|
||||||
void bltz(const Instruction);
|
void bltz(Instruction);
|
||||||
void bgez(const Instruction);
|
void bgez(Instruction);
|
||||||
void bltzl(const Instruction);
|
void bltzl(Instruction);
|
||||||
void bgezl(const Instruction);
|
void bgezl(Instruction);
|
||||||
void bltzal(const Instruction);
|
void bltzal(Instruction);
|
||||||
void bgezal(const Instruction);
|
void bgezal(Instruction);
|
||||||
void bltzall(const Instruction);
|
void bltzall(Instruction);
|
||||||
void bgezall(const Instruction);
|
void bgezall(Instruction);
|
||||||
void beq(const Instruction);
|
void beq(Instruction);
|
||||||
void beql(const Instruction);
|
void beql(Instruction);
|
||||||
void bne(const Instruction);
|
void bne(Instruction);
|
||||||
void bnel(const Instruction);
|
void bnel(Instruction);
|
||||||
void blez(const Instruction);
|
void blez(Instruction);
|
||||||
void blezl(const Instruction);
|
void blezl(Instruction);
|
||||||
void bgtz(const Instruction);
|
void bgtz(Instruction);
|
||||||
void bgtzl(const Instruction);
|
void bgtzl(Instruction);
|
||||||
void bfc1(const Instruction);
|
void bfc1(Instruction);
|
||||||
void blfc1(const Instruction);
|
void blfc1(Instruction);
|
||||||
void bfc0(const Instruction);
|
void bfc0(Instruction);
|
||||||
void blfc0(const Instruction);
|
void blfc0(Instruction);
|
||||||
void dadd(const Instruction);
|
void dadd(Instruction);
|
||||||
void daddu(const Instruction);
|
void daddu(Instruction);
|
||||||
void daddi(const Instruction);
|
void daddi(Instruction);
|
||||||
void daddiu(const Instruction);
|
void daddiu(Instruction);
|
||||||
void ddiv(const Instruction);
|
void ddiv(Instruction);
|
||||||
void ddivu(const Instruction);
|
void ddivu(Instruction);
|
||||||
void div(const Instruction);
|
void div(Instruction);
|
||||||
void divu(const Instruction);
|
void divu(Instruction);
|
||||||
void dmult(const Instruction);
|
void dmult(Instruction);
|
||||||
void dmultu(const Instruction);
|
void dmultu(Instruction);
|
||||||
void dsll(const Instruction);
|
void dsll(Instruction);
|
||||||
void dsllv(const Instruction);
|
void dsllv(Instruction);
|
||||||
void dsll32(const Instruction);
|
void dsll32(Instruction);
|
||||||
void dsra(const Instruction);
|
void dsra(Instruction);
|
||||||
void dsrav(const Instruction);
|
void dsrav(Instruction);
|
||||||
void dsra32(const Instruction);
|
void dsra32(Instruction);
|
||||||
void dsrl(const Instruction);
|
void dsrl(Instruction);
|
||||||
void dsrlv(const Instruction);
|
void dsrlv(Instruction);
|
||||||
void dsrl32(const Instruction);
|
void dsrl32(Instruction);
|
||||||
void dsub(const Instruction);
|
void dsub(Instruction);
|
||||||
void dsubu(const Instruction);
|
void dsubu(Instruction);
|
||||||
void j(const Instruction);
|
void j(Instruction);
|
||||||
void jr(const Instruction);
|
void jr(Instruction);
|
||||||
void jal(const Instruction);
|
void jal(Instruction);
|
||||||
void jalr(const Instruction);
|
void jalr(Instruction);
|
||||||
void lui(const Instruction);
|
void lui(Instruction);
|
||||||
void lbu(const Instruction);
|
void lbu(Instruction);
|
||||||
void lb(const Instruction);
|
void lb(Instruction);
|
||||||
void ld(const Instruction);
|
void ld(Instruction);
|
||||||
void ldc1(const Instruction);
|
void ldc1(Instruction);
|
||||||
void ldl(const Instruction);
|
void ldl(Instruction);
|
||||||
void ldr(const Instruction);
|
void ldr(Instruction);
|
||||||
void lh(const Instruction);
|
void lh(Instruction);
|
||||||
void lhu(const Instruction);
|
void lhu(Instruction);
|
||||||
void ll(const Instruction);
|
void ll(Instruction);
|
||||||
void lld(const Instruction);
|
void lld(Instruction);
|
||||||
void lw(const Instruction);
|
void lw(Instruction);
|
||||||
void lwc1(const Instruction);
|
void lwc1(Instruction);
|
||||||
void lwl(const Instruction);
|
void lwl(Instruction);
|
||||||
void lwu(const Instruction);
|
void lwu(Instruction);
|
||||||
void lwr(const Instruction);
|
void lwr(Instruction);
|
||||||
void mfhi(const Instruction);
|
void mfhi(Instruction);
|
||||||
void mflo(const Instruction);
|
void mflo(Instruction);
|
||||||
void mult(const Instruction);
|
void mult(Instruction);
|
||||||
void multu(const Instruction);
|
void multu(Instruction);
|
||||||
void mthi(const Instruction);
|
void mthi(Instruction);
|
||||||
void mtlo(const Instruction);
|
void mtlo(Instruction);
|
||||||
void nor(const Instruction);
|
void nor(Instruction);
|
||||||
void sb(const Instruction) {
|
void sb(const Instruction) {
|
||||||
Util::Error::GetInstance().Throw(
|
Util::Error::GetInstance().Throw(
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
||||||
@@ -231,7 +231,7 @@ private:
|
|||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
||||||
blockPC, {}, "[JIT]: Unhandled 'sh'!");
|
blockPC, {}, "[JIT]: Unhandled 'sh'!");
|
||||||
}
|
}
|
||||||
void sw(const Instruction);
|
void sw(Instruction);
|
||||||
void swl(const Instruction) {
|
void swl(const Instruction) {
|
||||||
Util::Error::GetInstance().Throw(
|
Util::Error::GetInstance().Throw(
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
||||||
@@ -242,32 +242,32 @@ private:
|
|||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::UNHANDLED_INSTRUCTION},
|
||||||
blockPC, {}, "[JIT]: Unhandled 'swr'!");
|
blockPC, {}, "[JIT]: Unhandled 'swr'!");
|
||||||
}
|
}
|
||||||
void slti(const Instruction);
|
void slti(Instruction);
|
||||||
void sltiu(const Instruction);
|
void sltiu(Instruction);
|
||||||
void slt(const Instruction);
|
void slt(Instruction);
|
||||||
void sltu(const Instruction);
|
void sltu(Instruction);
|
||||||
void sll(const Instruction);
|
void sll(Instruction);
|
||||||
void sllv(const Instruction);
|
void sllv(Instruction);
|
||||||
void sub(const Instruction);
|
void sub(Instruction);
|
||||||
void subu(const Instruction);
|
void subu(Instruction);
|
||||||
void swc1(const Instruction) {
|
void swc1(const Instruction) {
|
||||||
Util::Error::GetInstance().Throw(
|
Util::Error::GetInstance().Throw(
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::JIT_BRANCH_INSIDE_DELAY_SLOT},
|
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::JIT_BRANCH_INSIDE_DELAY_SLOT},
|
||||||
blockPC, {}, "[JIT]: Unhandled case of branch from delay slot!");
|
blockPC, {}, "[JIT]: Unhandled case of branch from delay slot!");
|
||||||
}
|
}
|
||||||
void sra(const Instruction);
|
void sra(Instruction);
|
||||||
void srav(const Instruction);
|
void srav(Instruction);
|
||||||
void srl(const Instruction);
|
void srl(Instruction);
|
||||||
void srlv(const Instruction);
|
void srlv(Instruction);
|
||||||
void trap(bool) {
|
void trap(bool) {
|
||||||
Util::Error::GetInstance().Throw(
|
Util::Error::GetInstance().Throw(
|
||||||
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::JIT_BRANCH_INSIDE_DELAY_SLOT},
|
{Util::Error::Severity::NON_FATAL}, {Util::Error::Type::JIT_BRANCH_INSIDE_DELAY_SLOT},
|
||||||
blockPC, {}, "[JIT]: Unhandled case of branch from delay slot!");
|
blockPC, {}, "[JIT]: Unhandled case of branch from delay slot!");
|
||||||
}
|
}
|
||||||
void or_(const Instruction);
|
void or_(Instruction);
|
||||||
void ori(const Instruction);
|
void ori(Instruction);
|
||||||
void xor_(const Instruction);
|
void xor_(Instruction);
|
||||||
void xori(const Instruction);
|
void xori(Instruction);
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ struct RSP {
|
|||||||
void SetVTE(const VPR &vt, u8 e);
|
void SetVTE(const VPR &vt, u8 e);
|
||||||
auto Read(u32 addr) -> u32;
|
auto Read(u32 addr) -> u32;
|
||||||
void Write(u32 addr, u32 val);
|
void Write(u32 addr, u32 val);
|
||||||
void Exec(const Instruction instr);
|
void Exec(Instruction instr);
|
||||||
SPStatus spStatus{};
|
SPStatus spStatus{};
|
||||||
u16 oldPC{}, pc{}, nextPC{};
|
u16 oldPC{}, pc{}, nextPC{};
|
||||||
SPDMASPAddr spDMASPAddr{};
|
SPDMASPAddr spDMASPAddr{};
|
||||||
@@ -151,7 +151,7 @@ struct RSP {
|
|||||||
VPR vce{};
|
VPR vce{};
|
||||||
s16 divIn{}, divOut{};
|
s16 divIn{}, divOut{};
|
||||||
bool divInLoaded = false;
|
bool divInLoaded = false;
|
||||||
int steps = 0;
|
u32 steps = 0;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
VPR h{}, m{}, l{};
|
VPR h{}, m{}, l{};
|
||||||
@@ -257,12 +257,12 @@ struct RSP {
|
|||||||
|
|
||||||
FORCE_INLINE void ReleaseSemaphore() { semaphore = false; }
|
FORCE_INLINE void ReleaseSemaphore() { semaphore = false; }
|
||||||
|
|
||||||
void special(const Instruction instr);
|
void special(Instruction instr);
|
||||||
void regimm(const Instruction instr);
|
void regimm(Instruction instr);
|
||||||
void lwc2(const Instruction instr);
|
void lwc2(Instruction instr);
|
||||||
void swc2(const Instruction instr);
|
void swc2(Instruction instr);
|
||||||
void cop2(const Instruction instr);
|
void cop2(Instruction instr);
|
||||||
void cop0(const Instruction instr);
|
void cop0(Instruction instr);
|
||||||
|
|
||||||
void add(Instruction instr);
|
void add(Instruction instr);
|
||||||
void addi(Instruction instr);
|
void addi(Instruction instr);
|
||||||
|
|||||||
@@ -192,35 +192,35 @@ void JIT::blfc1(const Instruction instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void JIT::BranchNotTaken() {}
|
void JIT::BranchNotTaken() {}
|
||||||
void JIT::BranchTaken(s64 offs) {
|
|
||||||
|
void JIT::BranchTaken(const s64 offs) {
|
||||||
code.mov(code.SCR1, REG(qword, pc));
|
code.mov(code.SCR1, REG(qword, pc));
|
||||||
code.add(code.SCR1, offs);
|
code.add(code.SCR1, offs);
|
||||||
SetPC64(offs);
|
SetPC64(code.SCR1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JIT::BranchTaken(const Xbyak::Reg64 &offs) {
|
void JIT::BranchTaken(const Xbyak::Reg64 &offs) {
|
||||||
code.mov(code.SCR1, REG(qword, pc));
|
code.mov(code.SCR1, REG(qword, pc));
|
||||||
code.add(code.SCR1, offs);
|
code.add(code.SCR1, offs);
|
||||||
SetPC64(offs);
|
SetPC64(code.SCR1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JIT::BranchAbsTaken(s64 addr) {
|
void JIT::BranchAbsTaken(const s64 addr) {
|
||||||
code.add(code.SCR1, addr);
|
SetPC64(addr);
|
||||||
code.mov(REG(qword, nextPC), code.SCR1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JIT::BranchAbsTaken(const Xbyak::Reg64 &addr) {
|
void JIT::BranchAbsTaken(const Xbyak::Reg64 &addr) {
|
||||||
code.mov(REG(qword, nextPC), addr);
|
SetPC64(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JIT::branch_constant(const bool cond, s64 offset) {
|
void JIT::branch_constant(const bool cond, const s64 offset) {
|
||||||
if(cond) {
|
if(cond) {
|
||||||
regs.delaySlot = true;
|
regs.delaySlot = true;
|
||||||
BranchTaken(offset);
|
BranchTaken(offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JIT::branch_likely_constant(bool cond, s64 offset) {
|
void JIT::branch_likely_constant(const bool cond, const s64 offset) {
|
||||||
if(cond) {
|
if(cond) {
|
||||||
regs.delaySlot = true;
|
regs.delaySlot = true;
|
||||||
BranchTaken(offset);
|
BranchTaken(offset);
|
||||||
@@ -229,7 +229,7 @@ void JIT::branch_likely_constant(bool cond, s64 offset) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JIT::branch_abs_constant(bool cond, s64 address) {
|
void JIT::branch_abs_constant(const bool cond, const s64 address) {
|
||||||
if(cond) {
|
if(cond) {
|
||||||
regs.delaySlot = true;
|
regs.delaySlot = true;
|
||||||
BranchAbsTaken(address);
|
BranchAbsTaken(address);
|
||||||
@@ -266,7 +266,7 @@ void JIT::branch_abs_constant(bool cond, s64 address) {
|
|||||||
|
|
||||||
void JIT::bltz(const Instruction instr) {
|
void JIT::bltz(const Instruction instr) {
|
||||||
const s16 imm = instr;
|
const s16 imm = instr;
|
||||||
const s64 offset = u64((s64)imm) << 2;
|
const s64 offset = static_cast<s64>(imm) << 2;
|
||||||
if (regs.IsRegConstant(instr.rs())) {
|
if (regs.IsRegConstant(instr.rs())) {
|
||||||
branch_constant(regs.Read<s64>(instr.rs()) < 0, offset);
|
branch_constant(regs.Read<s64>(instr.rs()) < 0, offset);
|
||||||
return;
|
return;
|
||||||
@@ -435,7 +435,7 @@ void JIT::beql(const Instruction instr) {
|
|||||||
|
|
||||||
void JIT::bne(const Instruction instr) {
|
void JIT::bne(const Instruction instr) {
|
||||||
const s16 imm = instr;
|
const s16 imm = instr;
|
||||||
const s64 offset = u64((s64)imm) << 2;
|
const s64 offset = static_cast<s64>(imm) << 2;
|
||||||
if (regs.IsRegConstant(instr.rs()) && regs.IsRegConstant(instr.rt())) {
|
if (regs.IsRegConstant(instr.rs()) && regs.IsRegConstant(instr.rt())) {
|
||||||
branch_constant(regs.Read<s64>(instr.rs()) != regs.Read<s64>(instr.rt()), offset);
|
branch_constant(regs.Read<s64>(instr.rs()) != regs.Read<s64>(instr.rt()), offset);
|
||||||
return;
|
return;
|
||||||
@@ -857,13 +857,13 @@ void JIT::dsubu(const Instruction instr) {
|
|||||||
|
|
||||||
void JIT::j(const Instruction instr) {
|
void JIT::j(const Instruction instr) {
|
||||||
const s32 target = (instr & 0x3ffffff) << 2;
|
const s32 target = (instr & 0x3ffffff) << 2;
|
||||||
const s64 address = (blockOldPC & ~0xfffffff) | target;
|
const s64 address = blockOldPC & ~0xfffffff | target;
|
||||||
branch_abs_constant(true, address);
|
branch_abs_constant(true, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JIT::jr(const Instruction instr) {
|
void JIT::jr(const Instruction instr) {
|
||||||
if (regs.IsRegConstant(instr.rs())) {
|
if (regs.IsRegConstant(instr.rs())) {
|
||||||
const u64 address = regs.Read<s64>(instr.rs());
|
const auto address = regs.Read<s64>(instr.rs());
|
||||||
branch_abs_constant(true, address);
|
branch_abs_constant(true, address);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user