Added PC histogram option.
[riscv-isa-sim.git] / riscv / processor.cc
1 // See LICENSE for license details.
2
3 #include "processor.h"
4 #include "extension.h"
5 #include "common.h"
6 #include "config.h"
7 #include "sim.h"
8 #include "htif.h"
9 #include "disasm.h"
10 #include "icache.h"
11 #include <cinttypes>
12 #include <cmath>
13 #include <cstdlib>
14 #include <iostream>
15 #include <assert.h>
16 #include <limits.h>
17 #include <stdexcept>
18 #include <algorithm>
19
20 #undef STATE
21 #define STATE state
22
23 processor_t::processor_t(sim_t* _sim, mmu_t* _mmu, uint32_t _id)
24 : sim(_sim), mmu(_mmu), ext(NULL), disassembler(new disassembler_t),
25 id(_id), run(false), debug(false)
26 {
27 reset(true);
28 mmu->set_processor(this);
29
30 #define DECLARE_INSN(name, match, mask) REGISTER_INSN(this, name, match, mask)
31 #include "encoding.h"
32 #undef DECLARE_INSN
33 build_opcode_map();
34 }
35
36 processor_t::~processor_t()
37 {
38 #ifdef RISCV_ENABLE_HISTOGRAM
39 if (histogram_enabled)
40 {
41 fprintf(stderr, "PC Histogram size:%lu\n", pc_histogram.size());
42 for(auto iterator = pc_histogram.begin(); iterator != pc_histogram.end(); ++iterator) {
43 fprintf(stderr, "%0lx %lu\n", (iterator->first << 2), iterator->second);
44 }
45 }
46 #endif
47
48 delete disassembler;
49 }
50
51 void state_t::reset()
52 {
53 // the ISA guarantees on boot that the PC is 0x2000 and the the processor
54 // is in supervisor mode, and in 64-bit mode, if supported, with traps
55 // and virtual memory disabled.
56 sr = SR_S | SR_S64 | SR_U64;
57 pc = 0x2000;
58
59 // the following state is undefined upon boot-up,
60 // but we zero it for determinism
61 XPR.reset();
62 FPR.reset();
63
64 epc = 0;
65 badvaddr = 0;
66 evec = 0;
67 ptbr = 0;
68 pcr_k0 = 0;
69 pcr_k1 = 0;
70 cause = 0;
71 tohost = 0;
72 fromhost = 0;
73 count = 0;
74 compare = 0;
75 fflags = 0;
76 frm = 0;
77
78 load_reservation = -1;
79 }
80
81 void processor_t::set_debug(bool value)
82 {
83 debug = value;
84 if (ext)
85 ext->set_debug(value);
86 }
87
88 void processor_t::set_histogram(bool value)
89 {
90 histogram_enabled = value;
91 }
92
93 void processor_t::reset(bool value)
94 {
95 if (run == !value)
96 return;
97 run = !value;
98
99 state.reset(); // reset the core
100 set_pcr(CSR_STATUS, state.sr);
101
102 if (ext)
103 ext->reset(); // reset the extension
104 }
105
106 void processor_t::take_interrupt()
107 {
108 uint32_t interrupts = (state.sr & SR_IP) >> SR_IP_SHIFT;
109 interrupts &= (state.sr & SR_IM) >> SR_IM_SHIFT;
110
111 if (interrupts && (state.sr & SR_EI))
112 for (int i = 0; ; i++, interrupts >>= 1)
113 if (interrupts & 1)
114 throw trap_t((1ULL << ((state.sr & SR_S64) ? 63 : 31)) + i);
115 }
116
117 static void commit_log(state_t* state, insn_t insn)
118 {
119 #ifdef RISCV_ENABLE_COMMITLOG
120 if (state->sr & SR_EI) {
121 if (state->log_reg_write.addr) {
122 fprintf(stderr, "0x%016" PRIx64 " (0x%08" PRIx32 ") %c%2u 0x%016" PRIx64 "\n",
123 state->pc, insn.bits(),
124 state->log_reg_write.addr & 1 ? 'f' : 'x',
125 state->log_reg_write.addr >> 1, state->log_reg_write.data);
126 }
127 else {
128 fprintf(stderr, "0x%016" PRIx64 " (0x%08" PRIx32 ")\n",
129 state->pc, insn.bits());
130 }
131 }
132 state->log_reg_write.addr = 0;
133 #endif
134 }
135
136 inline void processor_t::update_histogram(size_t pc)
137 {
138 #ifdef RISCV_ENABLE_HISTOGRAM
139 size_t idx = pc >> 2;
140 pc_histogram[idx]++;
141 #endif
142 }
143
144 static inline void execute_insn(processor_t* p, state_t* st, insn_fetch_t fetch)
145 {
146 reg_t npc = fetch.func(p, fetch.insn.insn, st->pc);
147 commit_log(st, fetch.insn.insn);
148 p->update_histogram(st->pc);
149 st->pc = npc;
150 }
151
152 void processor_t::step(size_t n0)
153 {
154 if(!run)
155 return;
156
157 mmu_t* _mmu = mmu;
158 auto count32 = decltype(state.compare)(state.count);
159 bool count_le_compare = count32 <= state.compare;
160 ssize_t n = std::min(ssize_t(n0), ssize_t((state.compare - count32) | 1));
161
162 try
163 {
164 take_interrupt();
165
166 if (debug) // print out instructions as we go
167 {
168 for (ssize_t i = 0; i < n; state.count++, i++)
169 {
170 insn_fetch_t fetch = mmu->load_insn(state.pc);
171 disasm(fetch.insn.insn);
172 execute_insn(this, &state, fetch);
173 }
174 }
175 else while (n > 0)
176 {
177 size_t idx = (state.pc / sizeof(insn_t)) % ICACHE_SIZE;
178 auto ic_entry = _mmu->access_icache(state.pc), ic_entry_init = ic_entry;
179
180 #define ICACHE_ACCESS(idx) { \
181 insn_fetch_t fetch = ic_entry->data; \
182 ic_entry++; \
183 execute_insn(this, &state, fetch); \
184 if (idx < ICACHE_SIZE-1 && unlikely(ic_entry->tag != state.pc)) break; \
185 }
186
187 switch (idx)
188 {
189 ICACHE_SWITCH; // auto-generated into icache.h
190 }
191
192 size_t i = ic_entry - ic_entry_init;
193 state.count += i;
194 n -= i;
195 }
196 }
197 catch(trap_t& t)
198 {
199 take_trap(t);
200 }
201
202 bool count_ge_compare =
203 uint64_t(n) + decltype(state.compare)(state.count) >= state.compare;
204 if (count_le_compare && count_ge_compare)
205 set_interrupt(IRQ_TIMER, true);
206 }
207
208 void processor_t::take_trap(trap_t& t)
209 {
210 if (debug)
211 fprintf(stderr, "core %3d: exception %s, epc 0x%016" PRIx64 "\n",
212 id, t.name(), state.pc);
213
214 // switch to supervisor, set previous supervisor bit, disable interrupts
215 set_pcr(CSR_STATUS, (((state.sr & ~SR_EI) | SR_S) & ~SR_PS & ~SR_PEI) |
216 ((state.sr & SR_S) ? SR_PS : 0) |
217 ((state.sr & SR_EI) ? SR_PEI : 0));
218
219 yield_load_reservation();
220 state.cause = t.cause();
221 state.epc = state.pc;
222 state.pc = state.evec;
223
224 t.side_effects(&state); // might set badvaddr etc.
225 }
226
227 void processor_t::deliver_ipi()
228 {
229 if (run)
230 set_pcr(CSR_CLEAR_IPI, 1);
231 }
232
233 void processor_t::disasm(insn_t insn)
234 {
235 // the disassembler is stateless, so we share it
236 fprintf(stderr, "core %3d: 0x%016" PRIx64 " (0x%08" PRIx32 ") %s\n",
237 id, state.pc, insn.bits(), disassembler->disassemble(insn).c_str());
238 }
239
240 reg_t processor_t::set_pcr(int which, reg_t val)
241 {
242 reg_t old_pcr = get_pcr(which);
243
244 switch (which)
245 {
246 case CSR_FFLAGS:
247 state.fflags = val & (FSR_AEXC >> FSR_AEXC_SHIFT);
248 break;
249 case CSR_FRM:
250 state.frm = val & (FSR_RD >> FSR_RD_SHIFT);
251 break;
252 case CSR_FCSR:
253 state.fflags = (val & FSR_AEXC) >> FSR_AEXC_SHIFT;
254 state.frm = (val & FSR_RD) >> FSR_RD_SHIFT;
255 break;
256 case CSR_STATUS:
257 state.sr = (val & ~SR_IP) | (state.sr & SR_IP);
258 #ifndef RISCV_ENABLE_64BIT
259 state.sr &= ~(SR_S64 | SR_U64);
260 #endif
261 #ifndef RISCV_ENABLE_FPU
262 state.sr &= ~SR_EF;
263 #endif
264 if (!ext)
265 state.sr &= ~SR_EA;
266 state.sr &= ~SR_ZERO;
267 rv64 = (state.sr & SR_S) ? (state.sr & SR_S64) : (state.sr & SR_U64);
268 mmu->flush_tlb();
269 break;
270 case CSR_EPC:
271 state.epc = val;
272 break;
273 case CSR_EVEC:
274 state.evec = val & ~3;
275 break;
276 case CSR_COUNT:
277 state.count = val;
278 break;
279 case CSR_COUNTH:
280 state.count = (val << 32) | (uint32_t)state.count;
281 break;
282 case CSR_COMPARE:
283 set_interrupt(IRQ_TIMER, false);
284 state.compare = val;
285 break;
286 case CSR_PTBR:
287 state.ptbr = val & ~(PGSIZE-1);
288 break;
289 case CSR_SEND_IPI:
290 sim->send_ipi(val);
291 break;
292 case CSR_CLEAR_IPI:
293 set_interrupt(IRQ_IPI, val & 1);
294 break;
295 case CSR_SUP0:
296 state.pcr_k0 = val;
297 break;
298 case CSR_SUP1:
299 state.pcr_k1 = val;
300 break;
301 case CSR_TOHOST:
302 if (state.tohost == 0)
303 state.tohost = val;
304 break;
305 case CSR_FROMHOST:
306 set_fromhost(val);
307 break;
308 }
309
310 return old_pcr;
311 }
312
313 void processor_t::set_fromhost(reg_t val)
314 {
315 set_interrupt(IRQ_HOST, val != 0);
316 state.fromhost = val;
317 }
318
319 reg_t processor_t::get_pcr(int which)
320 {
321 switch (which)
322 {
323 case CSR_FFLAGS:
324 require_fp;
325 return state.fflags;
326 case CSR_FRM:
327 require_fp;
328 return state.frm;
329 case CSR_FCSR:
330 require_fp;
331 return (state.fflags << FSR_AEXC_SHIFT) | (state.frm << FSR_RD_SHIFT);
332 case CSR_STATUS:
333 return state.sr;
334 case CSR_EPC:
335 return state.epc;
336 case CSR_BADVADDR:
337 return state.badvaddr;
338 case CSR_EVEC:
339 return state.evec;
340 case CSR_CYCLE:
341 case CSR_TIME:
342 case CSR_INSTRET:
343 case CSR_COUNT:
344 return state.count;
345 case CSR_CYCLEH:
346 case CSR_TIMEH:
347 case CSR_INSTRETH:
348 case CSR_COUNTH:
349 if (rv64)
350 break;
351 return state.count >> 32;
352 case CSR_COMPARE:
353 return state.compare;
354 case CSR_CAUSE:
355 return state.cause;
356 case CSR_PTBR:
357 return state.ptbr;
358 case CSR_SEND_IPI:
359 case CSR_CLEAR_IPI:
360 return 0;
361 case CSR_ASID:
362 return 0;
363 case CSR_FATC:
364 mmu->flush_tlb();
365 return 0;
366 case CSR_HARTID:
367 return id;
368 case CSR_IMPL:
369 return 1;
370 case CSR_SUP0:
371 return state.pcr_k0;
372 case CSR_SUP1:
373 return state.pcr_k1;
374 case CSR_TOHOST:
375 sim->get_htif()->tick(); // not necessary, but faster
376 return state.tohost;
377 case CSR_FROMHOST:
378 sim->get_htif()->tick(); // not necessary, but faster
379 return state.fromhost;
380 case CSR_UARCH0:
381 case CSR_UARCH1:
382 case CSR_UARCH2:
383 case CSR_UARCH3:
384 case CSR_UARCH4:
385 case CSR_UARCH5:
386 case CSR_UARCH6:
387 case CSR_UARCH7:
388 case CSR_UARCH8:
389 case CSR_UARCH9:
390 case CSR_UARCH10:
391 case CSR_UARCH11:
392 case CSR_UARCH12:
393 case CSR_UARCH13:
394 case CSR_UARCH14:
395 case CSR_UARCH15:
396 return 0;
397 }
398 throw trap_illegal_instruction();
399 }
400
401 void processor_t::set_interrupt(int which, bool on)
402 {
403 uint32_t mask = (1 << (which + SR_IP_SHIFT)) & SR_IP;
404 if (on)
405 state.sr |= mask;
406 else
407 state.sr &= ~mask;
408 }
409
410 reg_t illegal_instruction(processor_t* p, insn_t insn, reg_t pc)
411 {
412 throw trap_illegal_instruction();
413 }
414
415 insn_func_t processor_t::decode_insn(insn_t insn)
416 {
417 size_t mask = opcode_map.size()-1;
418 insn_desc_t* desc = opcode_map[insn.bits() & mask];
419
420 while ((insn.bits() & desc->mask) != desc->match)
421 desc++;
422
423 return rv64 ? desc->rv64 : desc->rv32;
424 }
425
426 void processor_t::register_insn(insn_desc_t desc)
427 {
428 assert(desc.mask & 1);
429 instructions.push_back(desc);
430 }
431
432 void processor_t::build_opcode_map()
433 {
434 size_t buckets = -1;
435 for (auto& inst : instructions)
436 while ((inst.mask & buckets) != buckets)
437 buckets /= 2;
438 buckets++;
439
440 struct cmp {
441 decltype(insn_desc_t::match) mask;
442 cmp(decltype(mask) mask) : mask(mask) {}
443 bool operator()(const insn_desc_t& lhs, const insn_desc_t& rhs) {
444 if ((lhs.match & mask) != (rhs.match & mask))
445 return (lhs.match & mask) < (rhs.match & mask);
446 return lhs.match < rhs.match;
447 }
448 };
449 std::sort(instructions.begin(), instructions.end(), cmp(buckets-1));
450
451 opcode_map.resize(buckets);
452 opcode_store.resize(instructions.size() + 1);
453
454 size_t j = 0;
455 for (size_t b = 0, i = 0; b < buckets; b++)
456 {
457 opcode_map[b] = &opcode_store[j];
458 while (i < instructions.size() && b == (instructions[i].match & (buckets-1)))
459 opcode_store[j++] = instructions[i++];
460 }
461
462 assert(j == opcode_store.size()-1);
463 opcode_store[j].match = opcode_store[j].mask = 0;
464 opcode_store[j].rv32 = &illegal_instruction;
465 opcode_store[j].rv64 = &illegal_instruction;
466 }
467
468 void processor_t::register_extension(extension_t* x)
469 {
470 for (auto insn : x->get_instructions())
471 register_insn(insn);
472 build_opcode_map();
473 for (auto disasm_insn : x->get_disasms())
474 disassembler->add_insn(disasm_insn);
475 if (ext != NULL)
476 throw std::logic_error("only one extension may be registered");
477 ext = x;
478 x->set_processor(this);
479 }