2019-11-19 10:30:04 +00:00
|
|
|
#pragma once
|
|
|
|
#include "common/bitfield.h"
|
2020-07-31 07:09:18 +00:00
|
|
|
#include "common/jit_code_buffer.h"
|
2019-11-19 10:30:04 +00:00
|
|
|
#include "cpu_types.h"
|
|
|
|
#include <array>
|
|
|
|
#include <memory>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace CPU {
|
|
|
|
|
2019-11-27 15:55:33 +00:00
|
|
|
union CodeBlockKey
|
|
|
|
{
|
|
|
|
u32 bits;
|
|
|
|
|
|
|
|
BitField<u32, bool, 0, 1> user_mode;
|
|
|
|
BitField<u32, u32, 2, 30> aligned_pc;
|
|
|
|
|
|
|
|
ALWAYS_INLINE u32 GetPC() const { return aligned_pc << 2; }
|
|
|
|
ALWAYS_INLINE void SetPC(u32 pc) { aligned_pc = pc >> 2; }
|
|
|
|
|
2019-12-12 13:34:53 +00:00
|
|
|
ALWAYS_INLINE u32 GetPCPhysicalAddress() const { return (aligned_pc << 2) & PHYSICAL_MEMORY_ADDRESS_MASK; }
|
|
|
|
|
2019-11-27 15:55:33 +00:00
|
|
|
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_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
|
|
|
|
{
|
2020-07-31 07:09:18 +00:00
|
|
|
using HostCodePointer = void (*)();
|
2019-11-27 15:55:33 +00:00
|
|
|
|
|
|
|
CodeBlock(const CodeBlockKey key_) : key(key_) {}
|
|
|
|
|
|
|
|
CodeBlockKey key;
|
|
|
|
u32 host_code_size = 0;
|
|
|
|
HostCodePointer host_code = nullptr;
|
|
|
|
|
|
|
|
std::vector<CodeBlockInstruction> instructions;
|
|
|
|
std::vector<CodeBlock*> link_predecessors;
|
|
|
|
std::vector<CodeBlock*> link_successors;
|
|
|
|
|
|
|
|
bool invalidated = false;
|
|
|
|
|
|
|
|
const u32 GetPC() const { return key.GetPC(); }
|
|
|
|
const u32 GetSizeInBytes() const { return static_cast<u32>(instructions.size()) * sizeof(Instruction); }
|
2019-12-12 13:34:53 +00:00
|
|
|
const u32 GetStartPageIndex() const { return (key.GetPCPhysicalAddress() / CPU_CODE_CACHE_PAGE_SIZE); }
|
|
|
|
const u32 GetEndPageIndex() const
|
|
|
|
{
|
|
|
|
return ((key.GetPCPhysicalAddress() + GetSizeInBytes()) / CPU_CODE_CACHE_PAGE_SIZE);
|
|
|
|
}
|
2019-11-27 15:55:33 +00:00
|
|
|
bool IsInRAM() const
|
|
|
|
{
|
|
|
|
// TODO: Constant
|
2019-12-12 13:34:53 +00:00
|
|
|
return key.GetPCPhysicalAddress() < 0x200000;
|
2019-11-27 15:55:33 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-07-31 07:09:18 +00:00
|
|
|
namespace CodeCache {
|
2019-11-19 10:30:04 +00:00
|
|
|
|
2020-07-31 07:09:18 +00:00
|
|
|
void Initialize(bool use_recompiler);
|
|
|
|
void Shutdown();
|
|
|
|
void Execute();
|
2019-11-21 13:33:58 +00:00
|
|
|
|
2020-07-31 07:09:18 +00:00
|
|
|
/// Flushes the code cache, forcing all blocks to be recompiled.
|
|
|
|
void Flush();
|
2019-11-23 03:16:43 +00:00
|
|
|
|
2020-07-31 07:09:18 +00:00
|
|
|
/// Changes whether the recompiler is enabled.
|
|
|
|
void SetUseRecompiler(bool enable);
|
2019-11-23 03:16:43 +00:00
|
|
|
|
2020-07-31 07:09:18 +00:00
|
|
|
/// Invalidates all blocks which are in the range of the specified code page.
|
|
|
|
void InvalidateBlocksWithPageIndex(u32 page_index);
|
2019-11-23 03:16:43 +00:00
|
|
|
|
2020-07-31 07:09:18 +00:00
|
|
|
void InterpretCachedBlock(const CodeBlock& block);
|
|
|
|
void InterpretUncachedBlock();
|
2019-11-23 03:16:43 +00:00
|
|
|
|
2020-07-31 07:09:18 +00:00
|
|
|
}; // namespace CodeCache
|
2019-11-19 10:30:04 +00:00
|
|
|
|
2020-07-31 07:09:18 +00:00
|
|
|
} // namespace CPU
|