-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathrsp_jit.hpp
205 lines (158 loc) · 5.93 KB
/
rsp_jit.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#ifndef RSP_JIT_HPP__
#define RSP_JIT_HPP__
#include <memory>
#include <stdint.h>
#include <string.h>
#include <string>
#include <unordered_map>
#include <vector>
#include "rsp_op.hpp"
#include "state.hpp"
#include "jit_allocator.hpp"
extern "C"
{
#include <lightning.h>
}
namespace RSP
{
namespace JIT
{
using Func = jit_pointer_t;
class RegisterCache
{
public:
enum { COND_BRANCH_TAKEN = 32, SCRATCH_REGISTER0 = 33, SCRATCH_REGISTER1 = 34 };
// Ensures a mips register is present in a JIT register, lock it,
// and ensure register extend state is correct for opcodes which care.
unsigned load_mips_register_noext(jit_state_t *_jit, unsigned mips_reg);
unsigned load_mips_register_sext(jit_state_t *_jit, unsigned mips_reg);
unsigned load_mips_register_zext(jit_state_t *_jit, unsigned mips_reg);
// Prepare to modify the register and lock it.
unsigned modify_mips_register(jit_state_t *_jit, unsigned mips_reg);
// modify_mips_register + jit_movi helper.
unsigned immediate_mips_register(jit_state_t *_jit, unsigned mips_reg, jit_word_t value);
// Once we no longer require the register to be in register file, free it.
void unlock_mips_register(unsigned mips_reg);
// Before leaving a JIT block, or before branching, we must flush out all live registers.
void flush_register_window(jit_state_t *_jit);
// Similar, but we only need to invalidate caller save registers (JIT_R).
void flush_caller_save_registers(jit_state_t *_jit);
// Flush a single MIPS register.
void flush_mips_register(jit_state_t *_jit, unsigned mips_reg);
void reset();
private:
enum { NumFreeRegisters = JIT_R_NUM + (JIT_V_NUM - 3) };
enum SignState { SExt, ZExt, Unknown };
struct CacheEntry
{
unsigned mips_register;
unsigned timestamp;
unsigned num_locks;
SignState sign;
bool is_live;
bool modified;
};
CacheEntry entries[NumFreeRegisters] = {};
unsigned timestamp = 0;
CacheEntry *find_live_mips_register(unsigned mips_reg);
CacheEntry *find_free_register();
CacheEntry *find_oldest_unlocked_register();
CacheEntry &find_register(unsigned mips_reg);
void writeback_register(jit_state_t *_jit, CacheEntry &entry);
static unsigned jit_register_to_index(unsigned jit_reg);
unsigned entry_to_jit_register(const CacheEntry &entry);
};
class alignas(64) CPU
{
public:
CPU();
~CPU();
CPU(CPU &&) = delete;
void operator=(CPU &&) = delete;
void set_dmem(uint32_t *dmem)
{
state.dmem = dmem;
}
void set_imem(uint32_t *imem)
{
state.imem = imem;
}
void set_rdram(uint32_t *rdram)
{
state.rdram = rdram;
}
void invalidate_imem();
CPUState &get_state()
{
return state;
}
ReturnMode run();
void print_registers();
Func get_jit_block(uint32_t pc);
private:
CPUState state;
Func blocks[IMEM_WORDS] = {};
void invalidate_code();
uint64_t hash_imem(unsigned pc, unsigned count) const;
alignas(64) uint32_t cached_imem[IMEM_WORDS] = {};
std::unordered_map<uint64_t, Func> cached_blocks[IMEM_WORDS];
Func jit_region(uint64_t hash, unsigned pc_word, unsigned instruction_count);
int enter(uint32_t pc);
void init_jit_thunks();
struct
{
int (*enter_frame)(void *state) = nullptr;
Func enter_thunk = nullptr;
Func return_thunk = nullptr;
} thunks;
unsigned analyze_static_end(unsigned pc, unsigned end);
struct InstructionInfo
{
uint32_t branch_target;
bool indirect;
bool branch;
bool conditional;
bool handles_delay_slot;
};
void jit_instruction(jit_state_t *_jit, uint32_t pc, uint32_t instr, InstructionInfo &info, const InstructionInfo &last_info,
bool first_instruction, bool next_instruction_is_target);
void jit_exit(jit_state_t *_jit, uint32_t pc, const InstructionInfo &last_info, ReturnMode mode, bool first_instruction);
void jit_exit_dynamic(jit_state_t *_jit, uint32_t pc, const InstructionInfo &last_info, bool first_instruction);
void jit_end_of_block(jit_state_t *_jit, uint32_t pc, const InstructionInfo &last_info);
void jit_handle_delay_slot(jit_state_t *_jit, const InstructionInfo &last_info, uint32_t base_pc, uint32_t end_pc);
void jit_handle_impossible_delay_slot(jit_state_t *_jit, const InstructionInfo &info, const InstructionInfo &last_info,
uint32_t base_pc, uint32_t end_pc);
void jit_handle_latent_delay_slot(jit_state_t *_jit, const InstructionInfo &last_info);
void jit_mark_block_entries(uint32_t pc, uint32_t end, bool *block_entries);
void jit_emit_load_operation(jit_state_t *_jit, uint32_t pc, uint32_t instr,
void (*jit_emitter)(jit_state_t *_jit, unsigned, unsigned, unsigned), const char *asmop,
jit_pointer_t rsp_unaligned_op,
uint32_t endian_flip,
const InstructionInfo &last_info);
void jit_emit_store_operation(jit_state_t *_jit, uint32_t pc, uint32_t instr,
void (*jit_emitter)(jit_state_t *_jit, unsigned, unsigned, unsigned), const char *asmop,
jit_pointer_t rsp_unaligned_op,
uint32_t endian_flip,
const InstructionInfo &last_info);
static void jit_begin_call(jit_state_t *_jit);
static void jit_end_call(jit_state_t *_jit, jit_pointer_t ptr);
void jit_save_illegal_cond_branch_taken(jit_state_t *_jit);
static void jit_restore_illegal_cond_branch_taken(jit_state_t *_jit, unsigned reg);
static void jit_clear_illegal_cond_branch_taken(jit_state_t *_jit, unsigned tmp_reg);
void jit_save_indirect_register(jit_state_t *_jit, unsigned mips_register);
static void jit_load_indirect_register(jit_state_t *_jit, unsigned jit_reg);
static void jit_save_illegal_indirect_register(jit_state_t *_jit);
static void jit_load_illegal_indirect_register(jit_state_t *_jit, unsigned jit_reg);
std::string mips_disasm;
struct Link
{
jit_node_t *node;
unsigned local_index;
};
std::vector<Link> local_branches;
RegisterCache regs;
Allocator allocator;
};
} // namespace JIT
} // namespace RSP
#endif