Rename badaddr to tval
[riscv-isa-sim.git] / riscv / processor.h
1 // See LICENSE for license details.
2 #ifndef _RISCV_PROCESSOR_H
3 #define _RISCV_PROCESSOR_H
4
5 #include "decode.h"
6 #include "config.h"
7 #include "devices.h"
8 #include <string>
9 #include <vector>
10 #include <map>
11 #include "debug_rom/debug_rom_defines.h"
12
13 class processor_t;
14 class mmu_t;
15 typedef reg_t (*insn_func_t)(processor_t*, insn_t, reg_t);
16 class sim_t;
17 class trap_t;
18 class extension_t;
19 class disassembler_t;
20
21 struct insn_desc_t
22 {
23 insn_bits_t match;
24 insn_bits_t mask;
25 insn_func_t rv32;
26 insn_func_t rv64;
27 };
28
29 struct commit_log_reg_t
30 {
31 reg_t addr;
32 freg_t data;
33 };
34
35 typedef struct
36 {
37 uint8_t prv;
38 bool step;
39 bool ebreakm;
40 bool ebreakh;
41 bool ebreaks;
42 bool ebreaku;
43 bool halt;
44 uint8_t cause;
45 } dcsr_t;
46
47 typedef enum
48 {
49 ACTION_DEBUG_EXCEPTION = MCONTROL_ACTION_DEBUG_EXCEPTION,
50 ACTION_DEBUG_MODE = MCONTROL_ACTION_DEBUG_MODE,
51 ACTION_TRACE_START = MCONTROL_ACTION_TRACE_START,
52 ACTION_TRACE_STOP = MCONTROL_ACTION_TRACE_STOP,
53 ACTION_TRACE_EMIT = MCONTROL_ACTION_TRACE_EMIT
54 } mcontrol_action_t;
55
56 typedef enum
57 {
58 MATCH_EQUAL = MCONTROL_MATCH_EQUAL,
59 MATCH_NAPOT = MCONTROL_MATCH_NAPOT,
60 MATCH_GE = MCONTROL_MATCH_GE,
61 MATCH_LT = MCONTROL_MATCH_LT,
62 MATCH_MASK_LOW = MCONTROL_MATCH_MASK_LOW,
63 MATCH_MASK_HIGH = MCONTROL_MATCH_MASK_HIGH
64 } mcontrol_match_t;
65
66 typedef struct
67 {
68 uint8_t type;
69 bool dmode;
70 uint8_t maskmax;
71 bool select;
72 bool timing;
73 mcontrol_action_t action;
74 bool chain;
75 mcontrol_match_t match;
76 bool m;
77 bool h;
78 bool s;
79 bool u;
80 bool execute;
81 bool store;
82 bool load;
83 } mcontrol_t;
84
85 // architectural state of a RISC-V hart
86 struct state_t
87 {
88 void reset();
89
90 static const int num_triggers = 4;
91
92 reg_t pc;
93 regfile_t<reg_t, NXPR, true> XPR;
94 regfile_t<freg_t, NFPR, false> FPR;
95
96 // control and status registers
97 reg_t prv; // TODO: Can this be an enum instead?
98 reg_t mstatus;
99 reg_t mepc;
100 reg_t mtval;
101 reg_t mscratch;
102 reg_t mtvec;
103 reg_t mcause;
104 reg_t minstret;
105 reg_t mie;
106 reg_t mip;
107 reg_t medeleg;
108 reg_t mideleg;
109 uint32_t mcounteren;
110 uint32_t scounteren;
111 reg_t sepc;
112 reg_t stval;
113 reg_t sscratch;
114 reg_t stvec;
115 reg_t satp;
116 reg_t scause;
117 reg_t dpc;
118 reg_t dscratch;
119 dcsr_t dcsr;
120 reg_t tselect;
121 mcontrol_t mcontrol[num_triggers];
122 reg_t tdata2[num_triggers];
123
124 uint32_t fflags;
125 uint32_t frm;
126 bool serialized; // whether timer CSRs are in a well-defined state
127
128 // When true, execute a single instruction and then enter debug mode. This
129 // can only be set by executing dret.
130 enum {
131 STEP_NONE,
132 STEP_STEPPING,
133 STEP_STEPPED
134 } single_step;
135
136 reg_t load_reservation;
137
138 #ifdef RISCV_ENABLE_COMMITLOG
139 commit_log_reg_t log_reg_write;
140 reg_t last_inst_priv;
141 int last_inst_xlen;
142 int last_inst_flen;
143 #endif
144 };
145
146 typedef enum {
147 OPERATION_EXECUTE,
148 OPERATION_STORE,
149 OPERATION_LOAD,
150 } trigger_operation_t;
151
152 // Count number of contiguous 1 bits starting from the LSB.
153 static int cto(reg_t val)
154 {
155 int res = 0;
156 while ((val & 1) == 1)
157 val >>= 1, res++;
158 return res;
159 }
160
161 // this class represents one processor in a RISC-V machine.
162 class processor_t : public abstract_device_t
163 {
164 public:
165 processor_t(const char* isa, sim_t* sim, uint32_t id, bool halt_on_reset=false);
166 ~processor_t();
167
168 void set_debug(bool value);
169 void set_histogram(bool value);
170 void reset();
171 void step(size_t n); // run for n cycles
172 void set_csr(int which, reg_t val);
173 reg_t get_csr(int which);
174 mmu_t* get_mmu() { return mmu; }
175 state_t* get_state() { return &state; }
176 unsigned get_xlen() { return xlen; }
177 unsigned get_flen() {
178 return supports_extension('Q') ? 128 :
179 supports_extension('D') ? 64 :
180 supports_extension('F') ? 32 : 0;
181 }
182 extension_t* get_extension() { return ext; }
183 bool supports_extension(unsigned char ext) {
184 if (ext >= 'a' && ext <= 'z') ext += 'A' - 'a';
185 return ext >= 'A' && ext <= 'Z' && ((isa >> (ext - 'A')) & 1);
186 }
187 reg_t legalize_privilege(reg_t);
188 void set_privilege(reg_t);
189 void yield_load_reservation() { state.load_reservation = (reg_t)-1; }
190 void update_histogram(reg_t pc);
191 const disassembler_t* get_disassembler() { return disassembler; }
192
193 void register_insn(insn_desc_t);
194 void register_extension(extension_t*);
195
196 // MMIO slave interface
197 bool load(reg_t addr, size_t len, uint8_t* bytes);
198 bool store(reg_t addr, size_t len, const uint8_t* bytes);
199
200 // When true, display disassembly of each instruction that's executed.
201 bool debug;
202 // When true, take the slow simulation path.
203 bool slow_path();
204 bool halted() { return state.dcsr.cause ? true : false; }
205 bool halt_request;
206
207 // Return the index of a trigger that matched, or -1.
208 inline int trigger_match(trigger_operation_t operation, reg_t address, reg_t data)
209 {
210 if (state.dcsr.cause)
211 return -1;
212
213 bool chain_ok = true;
214
215 for (unsigned int i = 0; i < state.num_triggers; i++) {
216 if (!chain_ok) {
217 chain_ok |= !state.mcontrol[i].chain;
218 continue;
219 }
220
221 if ((operation == OPERATION_EXECUTE && !state.mcontrol[i].execute) ||
222 (operation == OPERATION_STORE && !state.mcontrol[i].store) ||
223 (operation == OPERATION_LOAD && !state.mcontrol[i].load) ||
224 (state.prv == PRV_M && !state.mcontrol[i].m) ||
225 (state.prv == PRV_S && !state.mcontrol[i].s) ||
226 (state.prv == PRV_U && !state.mcontrol[i].u)) {
227 continue;
228 }
229
230 reg_t value;
231 if (state.mcontrol[i].select) {
232 value = data;
233 } else {
234 value = address;
235 }
236
237 // We need this because in 32-bit mode sometimes the PC bits get sign
238 // extended.
239 if (xlen == 32) {
240 value &= 0xffffffff;
241 }
242
243 switch (state.mcontrol[i].match) {
244 case MATCH_EQUAL:
245 if (value != state.tdata2[i])
246 continue;
247 break;
248 case MATCH_NAPOT:
249 {
250 reg_t mask = ~((1 << cto(state.tdata2[i])) - 1);
251 if ((value & mask) != (state.tdata2[i] & mask))
252 continue;
253 }
254 break;
255 case MATCH_GE:
256 if (value < state.tdata2[i])
257 continue;
258 break;
259 case MATCH_LT:
260 if (value >= state.tdata2[i])
261 continue;
262 break;
263 case MATCH_MASK_LOW:
264 {
265 reg_t mask = state.tdata2[i] >> (xlen/2);
266 if ((value & mask) != (state.tdata2[i] & mask))
267 continue;
268 }
269 break;
270 case MATCH_MASK_HIGH:
271 {
272 reg_t mask = state.tdata2[i] >> (xlen/2);
273 if (((value >> (xlen/2)) & mask) != (state.tdata2[i] & mask))
274 continue;
275 }
276 break;
277 }
278
279 if (!state.mcontrol[i].chain) {
280 return i;
281 }
282 chain_ok = true;
283 }
284 return -1;
285 }
286
287 void trigger_updated();
288
289 private:
290 sim_t* sim;
291 mmu_t* mmu; // main memory is always accessed via the mmu
292 extension_t* ext;
293 disassembler_t* disassembler;
294 state_t state;
295 uint32_t id;
296 unsigned max_xlen;
297 unsigned xlen;
298 reg_t isa;
299 reg_t max_isa;
300 std::string isa_string;
301 bool histogram_enabled;
302 bool halt_on_reset;
303
304 std::vector<insn_desc_t> instructions;
305 std::map<reg_t,uint64_t> pc_histogram;
306
307 static const size_t OPCODE_CACHE_SIZE = 8191;
308 insn_desc_t opcode_cache[OPCODE_CACHE_SIZE];
309
310 void take_pending_interrupt() { take_interrupt(state.mip & state.mie); }
311 void take_interrupt(reg_t mask); // take first enabled interrupt in mask
312 void take_trap(trap_t& t, reg_t epc); // take an exception
313 void disasm(insn_t insn); // disassemble and print an instruction
314 int paddr_bits();
315
316 void enter_debug_mode(uint8_t cause);
317
318 friend class sim_t;
319 friend class mmu_t;
320 friend class clint_t;
321 friend class extension_t;
322
323 void parse_isa_string(const char* isa);
324 void build_opcode_map();
325 void register_base_instructions();
326 insn_func_t decode_insn(insn_t insn);
327
328 // Track repeated executions for processor_t::disasm()
329 uint64_t last_pc, last_bits, executions;
330 };
331
332 reg_t illegal_instruction(processor_t* p, insn_t insn, reg_t pc);
333
334 #define REGISTER_INSN(proc, name, match, mask) \
335 extern reg_t rv32_##name(processor_t*, insn_t, reg_t); \
336 extern reg_t rv64_##name(processor_t*, insn_t, reg_t); \
337 proc->register_insn((insn_desc_t){match, mask, rv32_##name, rv64_##name});
338
339 #endif