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