CPU/CodeCache: Rewrite using new-rec's block management
This commit is contained in:
@ -1,160 +1,42 @@
|
||||
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bus.h"
|
||||
#include "common/bitfield.h"
|
||||
#include "cpu_types.h"
|
||||
#include "util/jit_code_buffer.h"
|
||||
#include "util/page_fault_handler.h"
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#ifdef ENABLE_RECOMPILER
|
||||
#include "cpu_recompiler_types.h"
|
||||
#endif
|
||||
namespace CPU::CodeCache {
|
||||
|
||||
namespace CPU {
|
||||
/// Returns true if any recompiler is in use.
|
||||
bool IsUsingAnyRecompiler();
|
||||
|
||||
union CodeBlockKey
|
||||
{
|
||||
u32 bits;
|
||||
/// Returns true if any recompiler and fastmem is in use.
|
||||
bool IsUsingFastmem();
|
||||
|
||||
BitField<u32, bool, 0, 1> user_mode;
|
||||
BitField<u32, u32, 2, 30> aligned_pc;
|
||||
/// Allocates resources, call once at startup.
|
||||
void ProcessStartup();
|
||||
|
||||
ALWAYS_INLINE u32 GetPC() const { return aligned_pc << 2; }
|
||||
ALWAYS_INLINE void SetPC(u32 pc) { aligned_pc = pc >> 2; }
|
||||
|
||||
ALWAYS_INLINE u32 GetPCPhysicalAddress() const { return (aligned_pc << 2) & PHYSICAL_MEMORY_ADDRESS_MASK; }
|
||||
|
||||
ALWAYS_INLINE CodeBlockKey() = default;
|
||||
|
||||
ALWAYS_INLINE CodeBlockKey(const CodeBlockKey& rhs) : bits(rhs.bits) {}
|
||||
|
||||
ALWAYS_INLINE CodeBlockKey& operator=(const CodeBlockKey& rhs)
|
||||
{
|
||||
bits = rhs.bits;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool operator==(const CodeBlockKey& rhs) const { return bits == rhs.bits; }
|
||||
ALWAYS_INLINE bool operator!=(const CodeBlockKey& rhs) const { return bits != rhs.bits; }
|
||||
ALWAYS_INLINE bool operator<(const CodeBlockKey& rhs) const { return bits < rhs.bits; }
|
||||
};
|
||||
|
||||
struct CodeBlockInstruction
|
||||
{
|
||||
Instruction instruction;
|
||||
u32 pc;
|
||||
|
||||
bool is_branch_instruction : 1;
|
||||
bool is_direct_branch_instruction : 1;
|
||||
bool is_unconditional_branch_instruction : 1;
|
||||
bool is_branch_delay_slot : 1;
|
||||
bool is_load_instruction : 1;
|
||||
bool is_store_instruction : 1;
|
||||
bool is_load_delay_slot : 1;
|
||||
bool is_last_instruction : 1;
|
||||
bool has_load_delay : 1;
|
||||
bool can_trap : 1;
|
||||
};
|
||||
|
||||
struct CodeBlock
|
||||
{
|
||||
using HostCodePointer = void (*)();
|
||||
|
||||
struct LinkInfo
|
||||
{
|
||||
CodeBlock* block;
|
||||
void* host_pc;
|
||||
void* host_resolve_pc;
|
||||
u32 host_pc_size;
|
||||
};
|
||||
|
||||
CodeBlock(const CodeBlockKey key_) : key(key_) {}
|
||||
|
||||
CodeBlockKey key;
|
||||
u32 host_code_size = 0;
|
||||
HostCodePointer host_code = nullptr;
|
||||
|
||||
std::vector<CodeBlockInstruction> instructions;
|
||||
std::vector<LinkInfo> link_predecessors;
|
||||
std::vector<LinkInfo> link_successors;
|
||||
|
||||
TickCount uncached_fetch_ticks = 0;
|
||||
u32 icache_line_count = 0;
|
||||
|
||||
#ifdef ENABLE_RECOMPILER
|
||||
std::vector<Recompiler::LoadStoreBackpatchInfo> loadstore_backpatch_info;
|
||||
#endif
|
||||
|
||||
bool contains_loadstore_instructions = false;
|
||||
bool contains_double_branches = false;
|
||||
bool invalidated = false;
|
||||
bool can_link = true;
|
||||
|
||||
u32 recompile_frame_number = 0;
|
||||
u32 recompile_count = 0;
|
||||
u32 invalidate_frame_number = 0;
|
||||
|
||||
u32 GetPC() const { return key.GetPC(); }
|
||||
u32 GetSizeInBytes() const { return static_cast<u32>(instructions.size()) * sizeof(Instruction); }
|
||||
u32 GetStartPageIndex() const { return (key.GetPCPhysicalAddress() / HOST_PAGE_SIZE); }
|
||||
u32 GetEndPageIndex() const { return ((key.GetPCPhysicalAddress() + GetSizeInBytes()) / HOST_PAGE_SIZE); }
|
||||
bool IsInRAM() const
|
||||
{
|
||||
// TODO: Constant
|
||||
return key.GetPCPhysicalAddress() < 0x200000;
|
||||
}
|
||||
};
|
||||
|
||||
namespace CodeCache {
|
||||
|
||||
enum : u32
|
||||
{
|
||||
FAST_MAP_TABLE_COUNT = 0x10000,
|
||||
FAST_MAP_TABLE_SIZE = 0x10000 / 4, // 16384
|
||||
FAST_MAP_TABLE_SHIFT = 16,
|
||||
};
|
||||
|
||||
using FastMapTable = CodeBlock::HostCodePointer*;
|
||||
/// Frees resources, call once at shutdown.
|
||||
void ProcessShutdown();
|
||||
|
||||
/// Initializes resources for the system.
|
||||
void Initialize();
|
||||
|
||||
/// Frees resources used by the system.
|
||||
void Shutdown();
|
||||
|
||||
/// Runs the system.
|
||||
[[noreturn]] void Execute();
|
||||
|
||||
#ifdef ENABLE_RECOMPILER
|
||||
using DispatcherFunction = void (*)();
|
||||
using SingleBlockDispatcherFunction = void (*)(const CodeBlock::HostCodePointer);
|
||||
|
||||
FastMapTable* GetFastMapPointer();
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_RECOMPILER)
|
||||
JitCodeBuffer& GetCodeBuffer();
|
||||
#endif
|
||||
|
||||
/// Flushes the code cache, forcing all blocks to be recompiled.
|
||||
void Flush();
|
||||
|
||||
/// Changes whether the recompiler is enabled.
|
||||
void Reinitialize();
|
||||
void Reset();
|
||||
|
||||
/// Invalidates all blocks which are in the range of the specified code page.
|
||||
void InvalidateBlocksWithPageIndex(u32 page_index);
|
||||
|
||||
/// Invalidates all blocks in the cache.
|
||||
void InvalidateAll();
|
||||
|
||||
template<PGXPMode pgxp_mode>
|
||||
void InterpretCachedBlock(const CodeBlock& block);
|
||||
|
||||
template<PGXPMode pgxp_mode>
|
||||
void InterpretUncachedBlock();
|
||||
void InvalidateAllRAMBlocks();
|
||||
|
||||
/// Invalidates any code pages which overlap the specified range.
|
||||
ALWAYS_INLINE void InvalidateCodePages(PhysicalMemoryAddress address, u32 word_count)
|
||||
@ -168,6 +50,4 @@ ALWAYS_INLINE void InvalidateCodePages(PhysicalMemoryAddress address, u32 word_c
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace CodeCache
|
||||
|
||||
} // namespace CPU
|
||||
} // namespace CPU::CodeCache
|
||||
|
||||
Reference in New Issue
Block a user