Use physical address for indexing into blocks
This commit is contained in:
@@ -24,6 +24,7 @@ struct Core {
|
||||
VI& GetVI() { return mem.mmio.vi; }
|
||||
|
||||
void CpuReset() {
|
||||
cpuDynarec.Reset();
|
||||
regs.Reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,47 +6,66 @@ namespace n64::JIT {
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
Dynarec::~Dynarec() {
|
||||
dumpCode.close();
|
||||
std::free(codeCache);
|
||||
}
|
||||
|
||||
Dynarec::Dynarec() : code(DEFAULT_MAX_CODE_SIZE, AutoGrow) {
|
||||
if(fs::exists("jit.dump")) {
|
||||
fs::remove("jit.dump");
|
||||
}
|
||||
|
||||
dumpCode.open("jit.dump", std::ios::app | std::ios::binary);
|
||||
code.ready();
|
||||
Dynarec::Dynarec() : code(CODECACHE_SIZE, codeCache) {
|
||||
codeCache = (u8*)Util::aligned_alloc(4096, CODECACHE_SIZE);
|
||||
CodeArray::protect(
|
||||
codeCache,
|
||||
CODECACHE_SIZE,
|
||||
CodeArray::PROTECT_RWE
|
||||
);
|
||||
}
|
||||
|
||||
void Dynarec::Recompile(Registers& regs, Mem& mem) {
|
||||
void Dynarec::Recompile(Registers& regs, Mem& mem, u32 pc) {
|
||||
bool branch = false, prevBranch = false;
|
||||
u32 start_addr = regs.pc;
|
||||
u32 startPC = pc;
|
||||
u32 loopPC = pc;
|
||||
Fn block = code.getCurr<Fn>();
|
||||
|
||||
if(code.getSize() >= CODECACHE_SIZE) {
|
||||
Util::print("Code cache overflow!\n");
|
||||
code.setSize(code.getSize() & (CODECACHE_SIZE - 1));
|
||||
InvalidateCache();
|
||||
}
|
||||
|
||||
Util::print("Start of block @ PC {:08X}\n", loopPC);
|
||||
code.sub(rsp, 8);
|
||||
|
||||
while(!prevBranch) {
|
||||
instrInBlock++;
|
||||
prevBranch = branch;
|
||||
u32 instr = mem.Read32(regs, start_addr, start_addr);
|
||||
|
||||
start_addr += 4;
|
||||
u32 instr = mem.Read32<false>(regs, loopPC, loopPC);
|
||||
|
||||
code.mov(rdi, (u64)®s);
|
||||
|
||||
Util::print("\tInstr: {:08X}, PC: {:08X}\n", instr, loopPC);
|
||||
code.mov(r8, qword[rdi + REG_OFFSET(oldPC)]);
|
||||
code.mov(r9, qword[rdi + REG_OFFSET(pc)]);
|
||||
code.mov(r10, qword[rdi + REG_OFFSET(nextPC)]);
|
||||
code.mov(r8, r9);
|
||||
code.mov(r9, r10);
|
||||
code.add(r10, 4);
|
||||
code.mov(qword[rdi + REG_OFFSET(oldPC)], r8);
|
||||
code.mov(qword[rdi + REG_OFFSET(pc)], r9);
|
||||
code.mov(qword[rdi + REG_OFFSET(nextPC)], r10);
|
||||
|
||||
loopPC += 4;
|
||||
|
||||
branch = Exec(regs, mem, instr);
|
||||
}
|
||||
|
||||
code.add(rsp, 8);
|
||||
code.ret();
|
||||
dumpCode.write(code.getCode<char*>(), code.getSize());
|
||||
u32 pc = regs.pc & 0xffffffff;
|
||||
codeCache[pc >> 20][pc & 0xFFF] = block;
|
||||
block();
|
||||
Util::print("End of block @ PC {:08X}, len: {}\n", loopPC, instrInBlock);
|
||||
|
||||
blockCache[startPC >> 20][startPC & 0xFFF] = block;
|
||||
blockCache[startPC >> 20][startPC & 0xFFF]();
|
||||
}
|
||||
|
||||
void Dynarec::AllocateOuter(Registers& regs) {
|
||||
u32 pc = regs.pc & 0xffffffff;
|
||||
codeCache[pc >> 20] = (Fn*)calloc(0xFFF, sizeof(Fn));
|
||||
void Dynarec::AllocateOuter(u32 pc) {
|
||||
blockCache[pc >> 20] = (Fn*)bumpAlloc(0x1000 * sizeof(Fn));
|
||||
}
|
||||
|
||||
int Dynarec::Step(Mem &mem, Registers& regs) {
|
||||
@@ -55,17 +74,20 @@ int Dynarec::Step(Mem &mem, Registers& regs) {
|
||||
regs.prevDelaySlot = regs.delaySlot;
|
||||
regs.delaySlot = false;
|
||||
|
||||
u32 pc = regs.pc & 0xffffffff;
|
||||
u32 pc{};
|
||||
if(!MapVAddr(regs, LOAD, regs.pc, pc)) {
|
||||
Util::panic("[RECOMPILER] Failed to translate PC to physical address (v: {:08X})\n", regs.pc);
|
||||
}
|
||||
|
||||
if(codeCache[pc >> 20]) {
|
||||
if(codeCache[pc >> 20][pc & 0xfff]) {
|
||||
codeCache[pc >> 20][pc & 0xfff]();
|
||||
if(blockCache[pc >> 20]) {
|
||||
if(blockCache[pc >> 20][pc & 0xfff]) {
|
||||
blockCache[pc >> 20][pc & 0xfff]();
|
||||
} else {
|
||||
Recompile(regs, mem);
|
||||
Recompile(regs, mem, pc);
|
||||
}
|
||||
} else {
|
||||
AllocateOuter(regs);
|
||||
Recompile(regs, mem);
|
||||
AllocateOuter(pc);
|
||||
Recompile(regs, mem, pc);
|
||||
}
|
||||
|
||||
return instrInBlock;
|
||||
|
||||
@@ -10,6 +10,7 @@ using Fn = void (*)();
|
||||
|
||||
#define GPR_OFFSET(x) ((uintptr_t)®s.gpr[(x)] - (uintptr_t)®s)
|
||||
#define REG_OFFSET(kind) ((uintptr_t)®s.kind - (uintptr_t)®s)
|
||||
#define CODECACHE_SIZE (2 << 25)
|
||||
|
||||
struct Dynarec {
|
||||
Dynarec();
|
||||
@@ -17,17 +18,30 @@ struct Dynarec {
|
||||
int Step(Mem&, n64::Registers&);
|
||||
void Reset() {
|
||||
code.reset();
|
||||
InvalidateCache();
|
||||
}
|
||||
u64 cop2Latch{};
|
||||
CodeGenerator code;
|
||||
void InvalidatePage(u32);
|
||||
void InvalidateCache();
|
||||
private:
|
||||
friend struct Cop1;
|
||||
Fn* codeCache[0x80000]{};
|
||||
Fn* blockCache[0x80000]{};
|
||||
u8* codeCache;
|
||||
int instrInBlock = 0;
|
||||
std::ofstream dumpCode;
|
||||
bool enableBreakpoints = false;
|
||||
u64 sizeUsed = 0;
|
||||
|
||||
void Recompile(n64::Registers&, Mem&);
|
||||
void AllocateOuter(n64::Registers&);
|
||||
inline void emitBreakpoint() {
|
||||
#ifndef NDEBUG
|
||||
if(enableBreakpoints)
|
||||
code.int3();
|
||||
#endif
|
||||
}
|
||||
|
||||
void* bumpAlloc(u64 size, u8 val = 0);
|
||||
void Recompile(n64::Registers&, Mem&, u32 pc);
|
||||
void AllocateOuter(u32 pc);
|
||||
void cop2Decode(n64::Registers&, u32);
|
||||
bool special(n64::Registers&, u32);
|
||||
bool regimm(n64::Registers&, u32);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <core/registers/Registers.hpp>
|
||||
#include <core/registers/Cop0.hpp>
|
||||
#include <core/Interpreter.hpp>
|
||||
#include <core/Dynarec.hpp>
|
||||
#include <File.hpp>
|
||||
|
||||
namespace n64 {
|
||||
@@ -279,6 +280,246 @@ template u32 Mem::Read32<true>(n64::Registers ®s, u64 vaddr, s64 pc);
|
||||
template u64 Mem::Read64<false>(n64::Registers ®s, u64 vaddr, s64 pc);
|
||||
template u64 Mem::Read64<true>(n64::Registers ®s, u64 vaddr, s64 pc);
|
||||
|
||||
template <bool tlb>
|
||||
void Mem::Write8(Registers& regs, n64::JIT::Dynarec& dyn, u64 vaddr, u32 val, s64 pc) {
|
||||
u32 paddr = vaddr;
|
||||
if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
|
||||
HandleTLBException(regs, vaddr);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false);
|
||||
}
|
||||
|
||||
dyn.InvalidatePage(paddr);
|
||||
|
||||
const auto page = paddr >> 12;
|
||||
auto offset = paddr & 0xFFF;
|
||||
const auto pointer = readPages[page];
|
||||
|
||||
if(pointer) {
|
||||
if(paddr >= 0x04000000 && paddr <= 0x0403FFFF) {
|
||||
val = val << (8 * (3 - (paddr & 3)));
|
||||
offset = (offset & DMEM_DSIZE) & ~3;
|
||||
}
|
||||
|
||||
((u8*)pointer)[BYTE_ADDRESS(offset)] = val;
|
||||
} else {
|
||||
switch (paddr) {
|
||||
case 0x00000000 ... 0x007FFFFF:
|
||||
mmio.rdp.rdram[BYTE_ADDRESS(paddr)] = val;
|
||||
break;
|
||||
case 0x04000000 ... 0x0403FFFF:
|
||||
val = val << (8 * (3 - (paddr & 3)));
|
||||
paddr = (paddr & DMEM_DSIZE) & ~3;
|
||||
if (paddr & 0x1000)
|
||||
Util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
|
||||
else
|
||||
Util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
|
||||
break;
|
||||
case 0x04040000 ... 0x040FFFFF:
|
||||
case 0x04100000 ... 0x041FFFFF:
|
||||
case 0x04300000 ... 0x044FFFFF:
|
||||
case 0x04500000 ... 0x048FFFFF:
|
||||
Util::panic("MMIO Write8!\n");
|
||||
case 0x10000000 ... 0x13FFFFFF:
|
||||
break;
|
||||
case 0x1FC007C0 ... 0x1FC007FF:
|
||||
val = val << (8 * (3 - (paddr & 3)));
|
||||
paddr = (paddr - 0x1FC007C0) & ~3;
|
||||
Util::WriteAccess<u32>(pifRam, paddr, htobe32(val));
|
||||
ProcessPIFCommands(pifRam, mmio.si.controller, *this);
|
||||
break;
|
||||
case 0x00800000 ... 0x03FFFFFF:
|
||||
case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x08000000 ... 0x0FFFFFFF:
|
||||
case 0x04900000 ... 0x07FFFFFF:
|
||||
case 0x1FC00800 ... 0x7FFFFFFF:
|
||||
case 0x80000000 ... 0xFFFFFFFF:
|
||||
break;
|
||||
default:
|
||||
Util::panic("Unimplemented 8-bit write at address {:08X} with value {:0X} (PC = {:016X})\n", paddr, val,
|
||||
(u64) regs.pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <bool tlb>
|
||||
void Mem::Write16(Registers& regs, n64::JIT::Dynarec& dyn, u64 vaddr, u32 val, s64 pc) {
|
||||
u32 paddr = vaddr;
|
||||
if (!MapVAddr<tlb>(regs, STORE, vaddr, paddr)) {
|
||||
HandleTLBException(regs, vaddr);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, false);
|
||||
}
|
||||
|
||||
dyn.InvalidatePage(paddr);
|
||||
|
||||
const auto page = paddr >> 12;
|
||||
auto offset = paddr & 0xFFF;
|
||||
const auto pointer = readPages[page];
|
||||
|
||||
if(pointer) {
|
||||
if(paddr >= 0x04000000 && paddr <= 0x0403FFFF) {
|
||||
val = val << (16 * !(paddr & 2));
|
||||
offset &= ~3;
|
||||
}
|
||||
|
||||
Util::WriteAccess<u16>((u8*)pointer, HALF_ADDRESS(offset), val);
|
||||
} else {
|
||||
switch (paddr) {
|
||||
case 0x00000000 ... 0x007FFFFF:
|
||||
Util::WriteAccess<u16>(mmio.rdp.rdram.data(), HALF_ADDRESS(paddr), val);
|
||||
break;
|
||||
case 0x04000000 ... 0x0403FFFF:
|
||||
val = val << (16 * !(paddr & 2));
|
||||
paddr &= ~3;
|
||||
if (paddr & 0x1000)
|
||||
Util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
|
||||
else
|
||||
Util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
|
||||
break;
|
||||
case 0x04040000 ... 0x040FFFFF:
|
||||
case 0x04100000 ... 0x041FFFFF:
|
||||
case 0x04300000 ... 0x044FFFFF:
|
||||
case 0x04500000 ... 0x048FFFFF:
|
||||
Util::panic("MMIO Write16!\n");
|
||||
case 0x10000000 ... 0x13FFFFFF:
|
||||
break;
|
||||
case 0x1FC007C0 ... 0x1FC007FF:
|
||||
val = val << (16 * !(paddr & 2));
|
||||
paddr &= ~3;
|
||||
Util::WriteAccess<u32>(pifRam, paddr - 0x1FC007C0, htobe32(val));
|
||||
ProcessPIFCommands(pifRam, mmio.si.controller, *this);
|
||||
break;
|
||||
case 0x00800000 ... 0x03FFFFFF:
|
||||
case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x08000000 ... 0x0FFFFFFF:
|
||||
case 0x04900000 ... 0x07FFFFFF:
|
||||
case 0x1FC00800 ... 0x7FFFFFFF:
|
||||
case 0x80000000 ... 0xFFFFFFFF:
|
||||
break;
|
||||
default:
|
||||
Util::panic("Unimplemented 16-bit write at address {:08X} with value {:0X} (PC = {:016X})\n", paddr, val,
|
||||
(u64) regs.pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <bool tlb>
|
||||
void Mem::Write32(Registers& regs, n64::JIT::Dynarec& dyn, u64 vaddr, u32 val, s64 pc) {
|
||||
u32 paddr = vaddr;
|
||||
if(!MapVAddr<tlb>(regs, STORE, vaddr, paddr)) {
|
||||
HandleTLBException(regs, vaddr);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, false);
|
||||
}
|
||||
|
||||
dyn.InvalidatePage(paddr);
|
||||
|
||||
const auto page = paddr >> 12;
|
||||
auto offset = paddr & 0xFFF;
|
||||
const auto pointer = readPages[page];
|
||||
|
||||
if(pointer) {
|
||||
Util::WriteAccess<u32>((u8*)pointer, offset, val);
|
||||
} else {
|
||||
switch(paddr) {
|
||||
case 0x00000000 ... 0x007FFFFF:
|
||||
Util::WriteAccess<u32>(mmio.rdp.rdram.data(), paddr, val);
|
||||
break;
|
||||
case 0x04000000 ... 0x0403FFFF:
|
||||
if(paddr & 0x1000)
|
||||
Util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
|
||||
else
|
||||
Util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
|
||||
break;
|
||||
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
|
||||
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: mmio.Write(*this, regs, paddr, val); break;
|
||||
case 0x10000000 ... 0x13FF0013: break;
|
||||
case 0x13FF0014: {
|
||||
if(val < ISVIEWER_SIZE) {
|
||||
char* message = (char*)calloc(val + 1, 1);
|
||||
memcpy(message, isviewer, val);
|
||||
fmt::print("{}", message);
|
||||
free(message);
|
||||
}
|
||||
} break;
|
||||
case 0x13FF0020 ... 0x13FFFFFF:
|
||||
Util::WriteAccess<u32>(isviewer, paddr - 0x13FF0020, htobe32(val));
|
||||
break;
|
||||
case 0x1FC007C0 ... 0x1FC007FF:
|
||||
Util::WriteAccess<u32>(pifRam, paddr - 0x1FC007C0, htobe32(val));
|
||||
ProcessPIFCommands(pifRam, mmio.si.controller, *this);
|
||||
break;
|
||||
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x08000000 ... 0x0FFFFFFF: case 0x04900000 ... 0x07FFFFFF:
|
||||
case 0x1FC00800 ... 0x7FFFFFFF: case 0x80000000 ... 0xFFFFFFFF: break;
|
||||
default: Util::panic("Unimplemented 32-bit write at address {:08X} with value {:0X} (PC = {:016X})\n", paddr, val, (u64)regs.pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <bool tlb>
|
||||
void Mem::Write64(Registers& regs, n64::JIT::Dynarec& dyn, u64 vaddr, u64 val, s64 pc) {
|
||||
u32 paddr = vaddr;
|
||||
if(!MapVAddr<tlb>(regs, STORE, vaddr, paddr)) {
|
||||
HandleTLBException(regs, vaddr);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, false);
|
||||
}
|
||||
|
||||
dyn.InvalidatePage(paddr);
|
||||
|
||||
const auto page = paddr >> 12;
|
||||
auto offset = paddr & 0xFFF;
|
||||
const auto pointer = readPages[page];
|
||||
|
||||
if(pointer) {
|
||||
if(paddr >= 0x04000000 && paddr <= 0x0403FFFF) {
|
||||
val >>= 32;
|
||||
}
|
||||
Util::WriteAccess<u64>((u8*)pointer, offset, val);
|
||||
} else {
|
||||
switch (paddr) {
|
||||
case 0x00000000 ... 0x007FFFFF:
|
||||
Util::WriteAccess<u64>(mmio.rdp.rdram.data(), paddr, val);
|
||||
break;
|
||||
case 0x04000000 ... 0x0403FFFF:
|
||||
val >>= 32;
|
||||
if (paddr & 0x1000)
|
||||
Util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
|
||||
else
|
||||
Util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
|
||||
break;
|
||||
case 0x04040000 ... 0x040FFFFF:
|
||||
case 0x04100000 ... 0x041FFFFF:
|
||||
case 0x04300000 ... 0x044FFFFF:
|
||||
case 0x04500000 ... 0x048FFFFF:
|
||||
Util::panic("MMIO Write64!\n");
|
||||
case 0x10000000 ... 0x13FFFFFF:
|
||||
break;
|
||||
case 0x1FC007C0 ... 0x1FC007FF:
|
||||
Util::WriteAccess<u64>(pifRam, paddr - 0x1FC007C0, htobe64(val));
|
||||
ProcessPIFCommands(pifRam, mmio.si.controller, *this);
|
||||
break;
|
||||
case 0x00800000 ... 0x03FFFFFF:
|
||||
case 0x04200000 ... 0x042FFFFF:
|
||||
case 0x08000000 ... 0x0FFFFFFF:
|
||||
case 0x04900000 ... 0x07FFFFFF:
|
||||
case 0x1FC00800 ... 0x7FFFFFFF:
|
||||
case 0x80000000 ... 0xFFFFFFFF:
|
||||
break;
|
||||
default:
|
||||
Util::panic("Unimplemented 64-bit write at address {:08X} with value {:0X} (PC = {:016X})\n", paddr, val,
|
||||
(u64) regs.pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template void Mem::Write8<false>(Registers& regs, JIT::Dynarec&, u64 vaddr, u32 val, s64 pc);
|
||||
template void Mem::Write8<true>(Registers& regs, JIT::Dynarec&, u64 vaddr, u32 val, s64 pc);
|
||||
template void Mem::Write16<false>(Registers& regs, JIT::Dynarec&, u64 vaddr, u32 val, s64 pc);
|
||||
template void Mem::Write16<true>(Registers& regs, JIT::Dynarec&, u64 vaddr, u32 val, s64 pc);
|
||||
template void Mem::Write32<false>(Registers& regs, JIT::Dynarec&, u64 vaddr, u32 val, s64 pc);
|
||||
template void Mem::Write32<true>(Registers& regs, JIT::Dynarec&, u64 vaddr, u32 val, s64 pc);
|
||||
template void Mem::Write64<false>(Registers& regs, JIT::Dynarec&, u64 vaddr, u64 val, s64 pc);
|
||||
template void Mem::Write64<true>(Registers& regs, JIT::Dynarec&, u64 vaddr, u64 val, s64 pc);
|
||||
|
||||
template <bool tlb>
|
||||
void Mem::Write8(Registers& regs, u64 vaddr, u32 val, s64 pc) {
|
||||
u32 paddr = vaddr;
|
||||
|
||||
@@ -15,6 +15,10 @@ struct CartInfo {
|
||||
u32 crc;
|
||||
};
|
||||
|
||||
namespace JIT {
|
||||
struct Dynarec;
|
||||
}
|
||||
|
||||
struct Mem {
|
||||
~Mem() = default;
|
||||
Mem();
|
||||
@@ -33,6 +37,14 @@ struct Mem {
|
||||
template <bool tlb = true>
|
||||
u64 Read64(Registers&, u64, s64);
|
||||
template <bool tlb = true>
|
||||
void Write8(Registers&, JIT::Dynarec&, u64, u32, s64);
|
||||
template <bool tlb = true>
|
||||
void Write16(Registers&, JIT::Dynarec&, u64, u32, s64);
|
||||
template <bool tlb = true>
|
||||
void Write32(Registers&, JIT::Dynarec&, u64, u32, s64);
|
||||
template <bool tlb = true>
|
||||
void Write64(Registers&, JIT::Dynarec&, u64, u64, s64);
|
||||
template <bool tlb = true>
|
||||
void Write8(Registers&, u64, u32, s64);
|
||||
template <bool tlb = true>
|
||||
void Write16(Registers&, u64, u32, s64);
|
||||
|
||||
27
src/backend/core/dynarec/MemoryManagement.cpp
Normal file
27
src/backend/core/dynarec/MemoryManagement.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include <core/Dynarec.hpp>
|
||||
|
||||
namespace n64::JIT {
|
||||
void Dynarec::InvalidatePage(u32 paddr) {
|
||||
blockCache[paddr >> 20] = nullptr;
|
||||
}
|
||||
|
||||
void Dynarec::InvalidateCache() {
|
||||
sizeUsed = 0;
|
||||
for(int i = 0; i < 0x80000; i++) {
|
||||
blockCache[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void* Dynarec::bumpAlloc(u64 size, u8 val) {
|
||||
if(sizeUsed + size >= CODECACHE_SIZE) {
|
||||
InvalidateCache();
|
||||
}
|
||||
|
||||
void* ptr = &codeCache[sizeUsed];
|
||||
sizeUsed += size;
|
||||
|
||||
memset(ptr, val, size);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
@@ -82,7 +82,7 @@ bool Dynarec::special(n64::Registers& regs, u32 instr) {
|
||||
code.call(rax);
|
||||
res = true;
|
||||
break;
|
||||
case 0x0C: Util::panic("[RECOMPILER] Unhandled syscall instruction {:016X}\n", (u64)regs.pc);
|
||||
case 0x0C: Util::print<Util::Error>("[RECOMPILER] Unhandled syscall instruction {:016X}\n", (u64)regs.pc); /*dumpCode.close();*/ exit(1);
|
||||
case 0x0D: Util::panic("[RECOMPILER] Unhandled break instruction {:016X}\n", (u64)regs.pc);
|
||||
case 0x0F: break; // SYNC
|
||||
case 0x10:
|
||||
@@ -526,6 +526,7 @@ bool Dynarec::Exec(n64::Registers& regs, Mem& mem, u32 instr) {
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x09:
|
||||
emitBreakpoint();
|
||||
code.mov(rsi, (u64)instr);
|
||||
code.mov(rax, (u64)addiu);
|
||||
code.call(rax);
|
||||
@@ -674,43 +675,50 @@ bool Dynarec::Exec(n64::Registers& regs, Mem& mem, u32 instr) {
|
||||
break;
|
||||
case 0x28:
|
||||
code.mov(rsi, (u64)&mem);
|
||||
code.mov(rdx, (u64)instr);
|
||||
code.mov(rdx, (u64)this);
|
||||
code.mov(rcx, (u64)instr);
|
||||
code.mov(rax, (u64)sb);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x29:
|
||||
code.mov(rsi, (u64)&mem);
|
||||
code.mov(rdx, (u64)instr);
|
||||
code.mov(rdx, (u64)this);
|
||||
code.mov(rcx, (u64)instr);
|
||||
code.mov(rax, (u64)sh);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x2A:
|
||||
code.mov(rsi, (u64)&mem);
|
||||
code.mov(rdx, (u64)instr);
|
||||
code.mov(rdx, (u64)this);
|
||||
code.mov(rcx, (u64)instr);
|
||||
code.mov(rax, (u64)swl);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x2B:
|
||||
code.mov(rsi, (u64)&mem);
|
||||
code.mov(rdx, (u64)instr);
|
||||
code.mov(rdx, (u64)this);
|
||||
code.mov(rcx, (u64)instr);
|
||||
code.mov(rax, (u64)sw);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x2C:
|
||||
code.mov(rsi, (u64)&mem);
|
||||
code.mov(rdx, (u64)instr);
|
||||
code.mov(rdx, (u64)this);
|
||||
code.mov(rcx, (u64)instr);
|
||||
code.mov(rax, (u64)sdl);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x2D:
|
||||
code.mov(rsi, (u64)&mem);
|
||||
code.mov(rdx, (u64)instr);
|
||||
code.mov(rdx, (u64)this);
|
||||
code.mov(rcx, (u64)instr);
|
||||
code.mov(rax, (u64)sdr);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x2E:
|
||||
code.mov(rsi, (u64)&mem);
|
||||
code.mov(rdx, (u64)instr);
|
||||
code.mov(rdx, (u64)this);
|
||||
code.mov(rcx, (u64)instr);
|
||||
code.mov(rax, (u64)swr);
|
||||
code.call(rax);
|
||||
break;
|
||||
@@ -747,7 +755,8 @@ bool Dynarec::Exec(n64::Registers& regs, Mem& mem, u32 instr) {
|
||||
break;
|
||||
case 0x38:
|
||||
code.mov(rsi, (u64)&mem);
|
||||
code.mov(rdx, (u64)instr);
|
||||
code.mov(rdx, (u64)this);
|
||||
code.mov(rcx, (u64)instr);
|
||||
code.mov(rax, (u64)sc);
|
||||
code.call(rax);
|
||||
break;
|
||||
@@ -759,7 +768,8 @@ bool Dynarec::Exec(n64::Registers& regs, Mem& mem, u32 instr) {
|
||||
break;
|
||||
case 0x3C:
|
||||
code.mov(rsi, (u64)&mem);
|
||||
code.mov(rdx, (u64)instr);
|
||||
code.mov(rdx, (u64)this);
|
||||
code.mov(rcx, (u64)instr);
|
||||
code.mov(rax, (u64)scd);
|
||||
code.call(rax);
|
||||
break;
|
||||
@@ -771,7 +781,8 @@ bool Dynarec::Exec(n64::Registers& regs, Mem& mem, u32 instr) {
|
||||
break;
|
||||
case 0x3F:
|
||||
code.mov(rsi, (u64)&mem);
|
||||
code.mov(rdx, (u64)instr);
|
||||
code.mov(rdx, (u64)this);
|
||||
code.mov(rcx, (u64)instr);
|
||||
code.mov(rax, (u64)sd);
|
||||
code.call(rax);
|
||||
break;
|
||||
|
||||
@@ -148,14 +148,14 @@ void ddivu(Registers& regs, u32 instr) {
|
||||
void branch(Registers& regs, bool cond, s64 address) {
|
||||
regs.delaySlot = true;
|
||||
if (cond) {
|
||||
regs.pc = address;
|
||||
regs.nextPC = address;
|
||||
}
|
||||
}
|
||||
|
||||
void branch_likely(Registers& regs, bool cond, s64 address) {
|
||||
regs.delaySlot = true;
|
||||
if (cond) {
|
||||
regs.pc = address;
|
||||
regs.nextPC = address;
|
||||
} else {
|
||||
regs.SetPC(regs.nextPC);
|
||||
}
|
||||
@@ -357,12 +357,12 @@ void lwu(Registers& regs, Mem& mem, u32 instr) {
|
||||
regs.gpr[RT(instr)] = value;
|
||||
}
|
||||
|
||||
void sb(Registers& regs, Mem& mem, u32 instr) {
|
||||
void sb(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) {
|
||||
u32 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
mem.Write8(regs, address, regs.gpr[RT(instr)], regs.oldPC);
|
||||
mem.Write8(regs, dyn, address, regs.gpr[RT(instr)], regs.oldPC);
|
||||
}
|
||||
|
||||
void sc(Registers& regs, Mem& mem, u32 instr) {
|
||||
void sc(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) {
|
||||
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
if (check_address_error(address, 0b11)) {
|
||||
HandleTLBException(regs, address);
|
||||
@@ -370,14 +370,14 @@ void sc(Registers& regs, Mem& mem, u32 instr) {
|
||||
}
|
||||
|
||||
if(regs.cop0.llbit) {
|
||||
mem.Write32(regs, address, regs.gpr[RT(instr)], regs.oldPC);
|
||||
mem.Write32(regs, dyn, address, regs.gpr[RT(instr)], regs.oldPC);
|
||||
}
|
||||
|
||||
regs.gpr[RT(instr)] = (u64)regs.cop0.llbit;
|
||||
regs.cop0.llbit = false;
|
||||
}
|
||||
|
||||
void scd(Registers& regs, Mem& mem, u32 instr) {
|
||||
void scd(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) {
|
||||
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
if (check_address_error(address, 0b111)) {
|
||||
HandleTLBException(regs, address);
|
||||
@@ -386,14 +386,14 @@ void scd(Registers& regs, Mem& mem, u32 instr) {
|
||||
}
|
||||
|
||||
if(regs.cop0.llbit) {
|
||||
mem.Write64(regs, address, regs.gpr[RT(instr)], regs.oldPC);
|
||||
mem.Write64(regs, dyn, address, regs.gpr[RT(instr)], regs.oldPC);
|
||||
}
|
||||
|
||||
regs.gpr[RT(instr)] = (s64)((u64)regs.cop0.llbit);
|
||||
regs.cop0.llbit = false;
|
||||
}
|
||||
|
||||
void sh(Registers& regs, Mem& mem, u32 instr) {
|
||||
void sh(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) {
|
||||
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
if (check_address_error(address, 0b1)) {
|
||||
HandleTLBException(regs, address);
|
||||
@@ -406,11 +406,11 @@ void sh(Registers& regs, Mem& mem, u32 instr) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||
} else {
|
||||
mem.Write16<false>(regs, physical, regs.gpr[RT(instr)], regs.oldPC);
|
||||
mem.Write16<false>(regs, dyn, physical, regs.gpr[RT(instr)], regs.oldPC);
|
||||
}
|
||||
}
|
||||
|
||||
void sw(Registers& regs, Mem& mem, u32 instr) {
|
||||
void sw(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) {
|
||||
s16 offset = instr;
|
||||
u64 address = regs.gpr[RS(instr)] + offset;
|
||||
if (check_address_error(address, 0b11)) {
|
||||
@@ -424,11 +424,11 @@ void sw(Registers& regs, Mem& mem, u32 instr) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||
} else {
|
||||
mem.Write32<false>(regs, physical, regs.gpr[RT(instr)], regs.oldPC);
|
||||
mem.Write32<false>(regs, dyn, physical, regs.gpr[RT(instr)], regs.oldPC);
|
||||
}
|
||||
}
|
||||
|
||||
void sd(Registers& regs, Mem& mem, u32 instr) {
|
||||
void sd(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) {
|
||||
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
if (check_address_error(address, 0b11)) {
|
||||
HandleTLBException(regs, address);
|
||||
@@ -441,12 +441,12 @@ void sd(Registers& regs, Mem& mem, u32 instr) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||
} else {
|
||||
mem.Write64<false>(regs, physical, regs.gpr[RT(instr)], regs.oldPC);
|
||||
mem.Write64<false>(regs, dyn, physical, regs.gpr[RT(instr)], regs.oldPC);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void sdl(Registers& regs, Mem& mem, u32 instr) {
|
||||
void sdl(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) {
|
||||
u64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
u32 paddr;
|
||||
if (!MapVAddr(regs, STORE, address, paddr)) {
|
||||
@@ -457,11 +457,11 @@ void sdl(Registers& regs, Mem& mem, u32 instr) {
|
||||
u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
|
||||
u64 data = mem.Read64<false>(regs, paddr & ~7, regs.oldPC);
|
||||
u64 rt = regs.gpr[RT(instr)];
|
||||
mem.Write64<false>(regs, paddr & ~7, (data & ~mask) | (rt >> shift), regs.oldPC);
|
||||
mem.Write64<false>(regs, dyn, paddr & ~7, (data & ~mask) | (rt >> shift), regs.oldPC);
|
||||
}
|
||||
}
|
||||
|
||||
void sdr(Registers& regs, Mem& mem, u32 instr) {
|
||||
void sdr(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) {
|
||||
u64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
u32 paddr;
|
||||
if (!MapVAddr(regs, STORE, address, paddr)) {
|
||||
@@ -472,11 +472,11 @@ void sdr(Registers& regs, Mem& mem, u32 instr) {
|
||||
u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
|
||||
u64 data = mem.Read64<false>(regs, paddr & ~7, regs.oldPC);
|
||||
u64 rt = regs.gpr[RT(instr)];
|
||||
mem.Write64<false>(regs, paddr & ~7, (data & ~mask) | (rt << shift), regs.oldPC);
|
||||
mem.Write64<false>(regs, dyn, paddr & ~7, (data & ~mask) | (rt << shift), regs.oldPC);
|
||||
}
|
||||
}
|
||||
|
||||
void swl(Registers& regs, Mem& mem, u32 instr) {
|
||||
void swl(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) {
|
||||
u64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
u32 paddr;
|
||||
if (!MapVAddr(regs, STORE, address, paddr)) {
|
||||
@@ -487,11 +487,11 @@ void swl(Registers& regs, Mem& mem, u32 instr) {
|
||||
u32 mask = 0xFFFFFFFF >> shift;
|
||||
u32 data = mem.Read32<false>(regs, paddr & ~3, regs.oldPC);
|
||||
u32 rt = regs.gpr[RT(instr)];
|
||||
mem.Write32<false>(regs, paddr & ~3, (data & ~mask) | (rt >> shift), regs.oldPC);
|
||||
mem.Write32<false>(regs, dyn, paddr & ~3, (data & ~mask) | (rt >> shift), regs.oldPC);
|
||||
}
|
||||
}
|
||||
|
||||
void swr(Registers& regs, Mem& mem, u32 instr) {
|
||||
void swr(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) {
|
||||
u64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
u32 paddr;
|
||||
if (!MapVAddr(regs, STORE, address, paddr)) {
|
||||
@@ -502,7 +502,7 @@ void swr(Registers& regs, Mem& mem, u32 instr) {
|
||||
u32 mask = 0xFFFFFFFF << shift;
|
||||
u32 data = mem.Read32<false>(regs, paddr & ~3, regs.oldPC);
|
||||
u32 rt = regs.gpr[RT(instr)];
|
||||
mem.Write32<false>(regs, paddr & ~3, (data & ~mask) | (rt << shift), regs.oldPC);
|
||||
mem.Write32<false>(regs, dyn, paddr & ~3, (data & ~mask) | (rt << shift), regs.oldPC);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,16 +60,16 @@ void multu(Registers&, u32);
|
||||
void mthi(Registers&, u32);
|
||||
void mtlo(Registers&, u32);
|
||||
void nor(Registers&, u32);
|
||||
void sb(Registers&, Mem&, u32);
|
||||
void sc(Registers&, Mem&, u32);
|
||||
void scd(Registers&, Mem&, u32);
|
||||
void sd(Registers&, Mem&, u32);
|
||||
void sdl(Registers&, Mem&, u32);
|
||||
void sdr(Registers&, Mem&, u32);
|
||||
void sh(Registers&, Mem&, u32);
|
||||
void sw(Registers&, Mem&, u32);
|
||||
void swl(Registers&, Mem&, u32);
|
||||
void swr(Registers&, Mem&, u32);
|
||||
void sb(Registers&, Mem&, Dynarec&, u32);
|
||||
void sc(Registers&, Mem&, Dynarec&, u32);
|
||||
void scd(Registers&, Mem&, Dynarec&, u32);
|
||||
void sd(Registers&, Mem&, Dynarec&, u32);
|
||||
void sdl(Registers&, Mem&, Dynarec&, u32);
|
||||
void sdr(Registers&, Mem&, Dynarec&, u32);
|
||||
void sh(Registers&, Mem&, Dynarec&, u32);
|
||||
void sw(Registers&, Mem&, Dynarec&, u32);
|
||||
void swl(Registers&, Mem&, Dynarec&, u32);
|
||||
void swr(Registers&, Mem&, Dynarec&, u32);
|
||||
void slti(Registers&, u32);
|
||||
void sltiu(Registers&, u32);
|
||||
void slt(Registers&, u32);
|
||||
|
||||
@@ -85,4 +85,22 @@ inline u32 crc32(u32 crc, const u8 *buf, size_t len) {
|
||||
}
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
inline void* aligned_alloc(size_t alignment, size_t size) {
|
||||
return _aligned_malloc(size, alignment);
|
||||
}
|
||||
|
||||
inline void free(void* ptr) {
|
||||
_aligned_free(ptr);
|
||||
}
|
||||
#else
|
||||
inline void* aligned_alloc(size_t alignment, size_t size) {
|
||||
return std::aligned_alloc(alignment, size);
|
||||
}
|
||||
|
||||
inline void free(void* ptr) {
|
||||
std::free(ptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -13,7 +13,6 @@ constexpr void print(const std::string& fmt, Args... args) {
|
||||
#ifndef _WIN32
|
||||
if constexpr(messageType == Error) {
|
||||
fmt::print(fmt::emphasis::bold | fg(fmt::color::red), fmt, args...);
|
||||
exit(-1);
|
||||
} else if constexpr(messageType == Warn) {
|
||||
fmt::print(fg(fmt::color::yellow), fmt, args...);
|
||||
} else if constexpr(messageType == Info) {
|
||||
@@ -24,10 +23,7 @@ constexpr void print(const std::string& fmt, Args... args) {
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
if constexpr(messageType == Error) {
|
||||
fmt::print(fmt, args...);
|
||||
exit(-1);
|
||||
} else if constexpr(messageType == Debug) {
|
||||
if constexpr(messageType == Debug) {
|
||||
#ifndef NDEBUG
|
||||
fmt::print(fmt, args...);
|
||||
#endif
|
||||
@@ -40,6 +36,7 @@ constexpr void print(const std::string& fmt, Args... args) {
|
||||
template <typename ...Args>
|
||||
constexpr void panic(const std::string& fmt, Args... args) {
|
||||
print<Error>(fmt, args...);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
template <typename ...Args>
|
||||
|
||||
Reference in New Issue
Block a user