print out current privilege level (if commit log enabled)
[riscv-isa-sim.git] / riscv / execute.cc
1 // See LICENSE for license details.
2
3 #include "processor.h"
4 #include "mmu.h"
5 #include <cassert>
6
7 static void commit_log(state_t* state, reg_t pc, insn_t insn)
8 {
9 #ifdef RISCV_ENABLE_COMMITLOG
10 int32_t priv = get_field(state->mstatus, MSTATUS_PRV);
11 uint64_t mask = (insn.length() == 8 ? uint64_t(0) : (uint64_t(1) << (insn.length() * 8))) - 1;
12 if (state->log_reg_write.addr) {
13 fprintf(stderr, "%1d 0x%016" PRIx64 " (0x%08" PRIx64 ") %c%2" PRIu64 " 0x%016" PRIx64 "\n",
14 priv,
15 pc,
16 insn.bits() & mask,
17 state->log_reg_write.addr & 1 ? 'f' : 'x',
18 state->log_reg_write.addr >> 1,
19 state->log_reg_write.data);
20 } else {
21 fprintf(stderr, "%1d 0x%016" PRIx64 " (0x%08" PRIx64 ")\n", priv, pc, insn.bits() & mask);
22 }
23 state->log_reg_write.addr = 0;
24 #endif
25 }
26
27 inline void processor_t::update_histogram(size_t pc)
28 {
29 #ifdef RISCV_ENABLE_HISTOGRAM
30 size_t idx = pc >> 2;
31 pc_histogram[idx]++;
32 #endif
33 }
34
35 static reg_t execute_insn(processor_t* p, reg_t pc, insn_fetch_t fetch)
36 {
37 reg_t npc = fetch.func(p, fetch.insn, pc);
38 if (npc != PC_SERIALIZE) {
39 commit_log(p->get_state(), pc, fetch.insn);
40 p->update_histogram(pc);
41 }
42 return npc;
43 }
44
45 // fetch/decode/execute loop
46 void processor_t::step(size_t n)
47 {
48 while (run && n > 0) {
49 size_t instret = 0;
50 reg_t pc = state.pc;
51 mmu_t* _mmu = mmu;
52
53 #define advance_pc() \
54 if (unlikely(pc == PC_SERIALIZE)) { \
55 pc = state.pc; \
56 state.serialized = true; \
57 break; \
58 } else { \
59 state.pc = pc; \
60 instret++; \
61 }
62
63 try
64 {
65 check_timer();
66 take_interrupt();
67
68 if (unlikely(debug))
69 {
70 while (instret < n)
71 {
72 insn_fetch_t fetch = mmu->load_insn(pc);
73 if (!state.serialized)
74 disasm(fetch.insn);
75 pc = execute_insn(this, pc, fetch);
76 advance_pc();
77 }
78 }
79 else while (instret < n)
80 {
81 size_t idx = _mmu->icache_index(pc);
82 auto ic_entry = _mmu->access_icache(pc);
83
84 #define ICACHE_ACCESS(i) { \
85 insn_fetch_t fetch = ic_entry->data; \
86 ic_entry++; \
87 pc = execute_insn(this, pc, fetch); \
88 if (i == mmu_t::ICACHE_ENTRIES-1) break; \
89 if (unlikely(ic_entry->tag != pc)) goto miss; \
90 if (unlikely(instret+1 == n)) break; \
91 instret++; \
92 state.pc = pc; \
93 }
94
95 switch (idx) {
96 #include "icache.h"
97 }
98
99 advance_pc();
100 continue;
101
102 miss:
103 advance_pc();
104 // refill I$ if it looks like there wasn't a taken branch
105 if (pc > (ic_entry-1)->tag && pc <= (ic_entry-1)->tag + MAX_INSN_LENGTH)
106 _mmu->refill_icache(pc, ic_entry);
107 }
108 }
109 catch(trap_t& t)
110 {
111 take_trap(t, pc);
112 }
113
114 state.minstret += instret;
115 n -= instret;
116 }
117 }