Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ares/n64/cpu/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ auto CPU::Context::setMode() -> void {
break;
}

self.recompiler.jitContext.update(self);

if(bits == 32) {
physMask = 0x1fff'ffff;
segment[0] = Segment::Mapped;
Expand Down
2 changes: 1 addition & 1 deletion ares/n64/cpu/cpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ auto CPU::instruction() -> void {

if(Accuracy::CPU::Recompiler && recompiler.enabled && access.cache) {
if(vaddrAlignedError<Word>(access.vaddr, false)) return;
auto block = recompiler.block(ipu.pc, access.paddr, GDB::server.hasBreakpoints());
auto block = recompiler.block(ipu.pc, access.paddr);
if(block) {
block->execute(*this);
return;
Expand Down
56 changes: 51 additions & 5 deletions ares/n64/cpu/cpu.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -883,13 +883,34 @@ struct CPU : Thread {
u8* code;
};

struct PoolRow {
Block* block;
u32 stateBits;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider moving stateBits to Block and getting rid of PoolRow to save an extra pointer indirection.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well it could be done but both the PoolRow and Block are allocated from the same bump allocator and usually are even neighboring, so it's not like the pointer indirection is random access to to heap.

};

struct Pool {
Block* blocks[1 << 6];
PoolRow* rows[1 << 6];
};

struct JITContext {
bool singleInstruction;
Context::Endian endian;
Context::Mode mode;
bool cop1Enabled;
bool floatingPointMode;
bool is64bit;

u32 stateBits; //the above state, compressed

auto update(const CPU& cpu) -> void;
auto toBits() const -> u32;
};

auto reset() -> void {
pools.resize(1 << 21); //2_MiB * sizeof(void*) == 16_MiB
std::ranges::fill(pools, nullptr);
blockCache.clear();
poolBlockKeys.clear();
}

auto invalidate(u32 address) -> void {
Expand All @@ -905,13 +926,24 @@ struct CPU : Thread {
auto pool = pools[address >> 8 & 0x1fffff];
if(!pool) return;
memory::jitprotect(false);
pool->blocks[address >> 2 & 0x3f] = nullptr;
pool->rows[address >> 2 & 0x3f] = nullptr;
memory::jitprotect(true);
#endif
}

auto invalidatePool(u32 address) -> void {
pools[address >> 8 & 0x1fffff] = nullptr;
u32 pool = address >> 8 & 0x1fffff;

if (pools[pool]) {
auto range = poolBlockKeys.equal_range(pool);
for (auto it = range.first; it != range.second; ++it) {
u64 cacheKey = it->second;
blockCache.erase(cacheKey);
}
}

pools[pool] = nullptr;

}

auto invalidateRange(u32 address, u32 length) -> void {
Expand All @@ -921,10 +953,13 @@ struct CPU : Thread {
}

auto pool(u32 address) -> Pool*;
auto block(u64 vaddr, u32 address, bool singleInstruction = false) -> Block*;
auto blockCacheKey(u32 address, u32 state) -> u64;
auto block(u64 vaddr, u32 address) -> Block*;

auto emit(u64 vaddr, u32 address, bool singleInstruction = false) -> Block*;
auto emit(u64 vaddr, u32 address) -> Block*;
auto emitOverflowCheck() -> sljit_jump*;
auto emitZeroClear(u32 n) -> void;
auto checkDualAllowed() -> bool;
auto emitEXECUTE(u32 instruction) -> bool;
auto emitSPECIAL(u32 instruction) -> bool;
auto emitREGIMM(u32 instruction) -> bool;
Expand All @@ -936,8 +971,19 @@ struct CPU : Thread {
bool callInstructionPrologue = false;
bump_allocator allocator;
std::vector<Pool*> pools;
std::unordered_map<u64, Block*> blockCache;
std::unordered_multimap<u32, u64> poolBlockKeys;
JITContext jitContext;
} recompiler{*this};

auto arithmeticOverflowException() -> void {
exception.arithmeticOverflow();
}

auto reservedInstructionException() -> void {
exception.reservedInstruction();
}

struct Disassembler {
CPU& self;
Disassembler(CPU& self) : self(self) {}
Expand Down
Loading
Loading