Use physical address for indexing into blocks

This commit is contained in:
CocoSimone
2023-01-13 19:19:51 +01:00
parent 60d0dd2c31
commit ea5e4895ba
11 changed files with 422 additions and 79 deletions

View File

@@ -24,6 +24,7 @@ struct Core {
VI& GetVI() { return mem.mmio.vi; }
void CpuReset() {
cpuDynarec.Reset();
regs.Reset();
}

View File

@@ -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");
Dynarec::Dynarec() : code(CODECACHE_SIZE, codeCache) {
codeCache = (u8*)Util::aligned_alloc(4096, CODECACHE_SIZE);
CodeArray::protect(
codeCache,
CODECACHE_SIZE,
CodeArray::PROTECT_RWE
);
}
dumpCode.open("jit.dump", std::ios::app | std::ios::binary);
code.ready();
}
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)&regs);
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;

View File

@@ -10,6 +10,7 @@ using Fn = void (*)();
#define GPR_OFFSET(x) ((uintptr_t)&regs.gpr[(x)] - (uintptr_t)&regs)
#define REG_OFFSET(kind) ((uintptr_t)&regs.kind - (uintptr_t)&regs)
#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);

View File

@@ -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 &regs, u64 vaddr, s64 pc);
template u64 Mem::Read64<false>(n64::Registers &regs, u64 vaddr, s64 pc);
template u64 Mem::Read64<true>(n64::Registers &regs, 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;

View File

@@ -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);

View 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;
}
}

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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
}

View File

@@ -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>