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