Add xspike program
[riscv-isa-sim.git] / riscv / processor.cc
1 // See LICENSE for license details.
2
3 #include "processor.h"
4 #include "common.h"
5 #include "config.h"
6 #include "sim.h"
7 #include "disasm.h"
8 #include <cinttypes>
9 #include <cmath>
10 #include <cstdlib>
11 #include <iostream>
12 #include <assert.h>
13 #include <limits.h>
14
15 processor_t::processor_t(sim_t* _sim, mmu_t* _mmu, uint32_t _id)
16 : sim(*_sim), mmu(*_mmu), id(_id), utidx(0)
17 {
18 reset(true);
19
20 // create microthreads
21 for (int i=0; i<MAX_UTS; i++)
22 uts[i] = new processor_t(&sim, &mmu, id, i);
23 }
24
25 processor_t::processor_t(sim_t* _sim, mmu_t* _mmu, uint32_t _id,
26 uint32_t _utidx)
27 : sim(*_sim), mmu(*_mmu), id(_id)
28 {
29 reset(true);
30 set_pcr(PCR_SR, SR_U64 | SR_EF | SR_EV);
31 utidx = _utidx;
32
33 // microthreads don't possess their own microthreads
34 for (int i=0; i<MAX_UTS; i++)
35 uts[i] = NULL;
36 }
37
38 processor_t::~processor_t()
39 {
40 }
41
42 void processor_t::reset(bool value)
43 {
44 if (run == !value)
45 return;
46 run = !value;
47
48 // the ISA guarantees on boot that the PC is 0x2000 and the the processor
49 // is in supervisor mode, and in 64-bit mode, if supported, with traps
50 // and virtual memory disabled.
51 sr = 0;
52 set_pcr(PCR_SR, SR_S | SR_S64 | SR_IM);
53 pc = 0x2000;
54
55 // the following state is undefined upon boot-up,
56 // but we zero it for determinism
57 XPR.reset();
58 FPR.reset();
59
60 evec = 0;
61 epc = 0;
62 badvaddr = 0;
63 cause = 0;
64 pcr_k0 = 0;
65 pcr_k1 = 0;
66 count = 0;
67 compare = 0;
68 cycle = 0;
69 set_fsr(0);
70
71 // vector stuff
72 vecbanks = 0xff;
73 vecbanks_count = 8;
74 utidx = -1;
75 vlmax = 32;
76 vl = 0;
77 nxfpr_bank = 256;
78 nxpr_use = 32;
79 nfpr_use = 32;
80 }
81
82 void processor_t::set_fsr(uint32_t val)
83 {
84 fsr = val & ~FSR_ZERO; // clear FSR bits that read as zero
85 }
86
87 void processor_t::vcfg()
88 {
89 if (nxpr_use + nfpr_use < 2)
90 vlmax = nxfpr_bank * vecbanks_count;
91 else
92 vlmax = (nxfpr_bank / (nxpr_use + nfpr_use - 1)) * vecbanks_count;
93
94 vlmax = std::min(vlmax, MAX_UTS);
95 }
96
97 void processor_t::setvl(int vlapp)
98 {
99 vl = std::min(vlmax, vlapp);
100 }
101
102 void processor_t::take_interrupt()
103 {
104 uint32_t interrupts = (sr & SR_IP) >> SR_IP_SHIFT;
105 interrupts &= (sr & SR_IM) >> SR_IM_SHIFT;
106
107 if(interrupts && (sr & SR_ET))
108 for(int i = 0; ; i++, interrupts >>= 1)
109 if(interrupts & 1)
110 throw interrupt_t(i);
111 }
112
113 void processor_t::step(size_t n, bool noisy)
114 {
115 if(!run)
116 return;
117
118 size_t i = 0;
119 try
120 {
121 take_interrupt();
122
123 mmu_t& _mmu = mmu;
124 reg_t npc = pc;
125
126 // execute_insn fetches and executes one instruction
127 #define execute_insn(noisy) \
128 do { \
129 mmu_t::insn_fetch_t fetch = _mmu.load_insn(npc, sr & SR_EC); \
130 if(noisy) disasm(fetch.insn, npc); \
131 npc = fetch.func(this, fetch.insn, npc); \
132 pc = npc; \
133 } while(0)
134
135 if(noisy) for( ; i < n; i++) // print out instructions as we go
136 execute_insn(true);
137 else
138 {
139 // unrolled for speed
140 for( ; n > 3 && i < n-3; i+=4)
141 {
142 execute_insn(false);
143 execute_insn(false);
144 execute_insn(false);
145 execute_insn(false);
146 }
147 for( ; i < n; i++)
148 execute_insn(false);
149 }
150 }
151 catch(trap_t t)
152 {
153 // an exception occurred in the target processor
154 take_trap(t,noisy);
155 }
156 catch(interrupt_t t)
157 {
158 take_trap((1ULL << (8*sizeof(reg_t)-1)) + t.i, noisy);
159 }
160 catch(vt_command_t cmd)
161 {
162 // this microthread has finished
163 assert(cmd == vt_command_stop);
164 }
165
166 cycle += i;
167
168 // update timer and possibly register a timer interrupt
169 uint32_t old_count = count;
170 count += i;
171 if(old_count < compare && uint64_t(old_count) + i >= compare)
172 set_interrupt(IRQ_TIMER, true);
173 }
174
175 void processor_t::take_trap(reg_t t, bool noisy)
176 {
177 if(noisy)
178 {
179 if ((sreg_t)t < 0)
180 fprintf(stderr, "core %3d: interrupt %d, epc 0x%016" PRIx64 "\n",
181 id, uint8_t(t), pc);
182 else
183 fprintf(stderr, "core %3d: trap %s, epc 0x%016" PRIx64 "\n",
184 id, trap_name(trap_t(t)), pc);
185 }
186
187 // switch to supervisor, set previous supervisor bit, disable traps
188 set_pcr(PCR_SR, (((sr & ~SR_ET) | SR_S) & ~SR_PS) | ((sr & SR_S) ? SR_PS : 0));
189 cause = t;
190 epc = pc;
191 pc = evec;
192 badvaddr = mmu.get_badvaddr();
193 }
194
195 void processor_t::deliver_ipi()
196 {
197 if (run)
198 set_pcr(PCR_CLR_IPI, 1);
199 }
200
201 void processor_t::disasm(insn_t insn, reg_t pc)
202 {
203 // the disassembler is stateless, so we share it
204 static disassembler disasm;
205 fprintf(stderr, "core %3d: 0x%016" PRIx64 " (0x%08" PRIx32 ") %s\n",
206 id, pc, insn.bits, disasm.disassemble(insn).c_str());
207 }
208
209 void processor_t::set_pcr(int which, reg_t val)
210 {
211 switch (which)
212 {
213 case PCR_SR:
214 sr = (val & ~SR_IP) | (sr & SR_IP);
215 #ifndef RISCV_ENABLE_64BIT
216 sr &= ~(SR_S64 | SR_U64);
217 #endif
218 #ifndef RISCV_ENABLE_FPU
219 sr &= ~SR_EF;
220 #endif
221 #ifndef RISCV_ENABLE_RVC
222 sr &= ~SR_EC;
223 #endif
224 #ifndef RISCV_ENABLE_VEC
225 sr &= ~SR_EV;
226 #endif
227 sr &= ~SR_ZERO;
228 mmu.set_sr(sr);
229 break;
230 case PCR_EPC:
231 epc = val;
232 break;
233 case PCR_EVEC:
234 evec = val;
235 break;
236 case PCR_COUNT:
237 count = val;
238 break;
239 case PCR_COMPARE:
240 set_interrupt(IRQ_TIMER, false);
241 compare = val;
242 break;
243 case PCR_PTBR:
244 mmu.set_ptbr(val);
245 break;
246 case PCR_SEND_IPI:
247 sim.send_ipi(val);
248 break;
249 case PCR_CLR_IPI:
250 set_interrupt(IRQ_IPI, val & 1);
251 break;
252 case PCR_K0:
253 pcr_k0 = val;
254 break;
255 case PCR_K1:
256 pcr_k1 = val;
257 break;
258 case PCR_VECBANK:
259 vecbanks = val & 0xff;
260 vecbanks_count = __builtin_popcountll(vecbanks);
261 break;
262 case PCR_TOHOST:
263 if (tohost == 0)
264 tohost = val;
265 break;
266 case PCR_FROMHOST:
267 set_interrupt(IRQ_HOST, val != 0);
268 fromhost = val;
269 break;
270 }
271 }
272
273 reg_t processor_t::get_pcr(int which)
274 {
275 switch (which)
276 {
277 case PCR_SR:
278 return sr;
279 case PCR_EPC:
280 return epc;
281 case PCR_BADVADDR:
282 return badvaddr;
283 case PCR_EVEC:
284 return evec;
285 case PCR_COUNT:
286 return count;
287 case PCR_COMPARE:
288 return compare;
289 case PCR_CAUSE:
290 return cause;
291 case PCR_PTBR:
292 return mmu.get_ptbr();
293 case PCR_COREID:
294 return id;
295 case PCR_IMPL:
296 return 1;
297 case PCR_K0:
298 return pcr_k0;
299 case PCR_K1:
300 return pcr_k1;
301 case PCR_VECBANK:
302 return vecbanks;
303 case PCR_VECCFG:
304 return nfpr_use << 18 | nxpr_use << 12 | vl;
305 case PCR_TOHOST:
306 return tohost;
307 case PCR_FROMHOST:
308 return fromhost;
309 }
310 return -1;
311 }
312
313 void processor_t::set_interrupt(int which, bool on)
314 {
315 uint32_t mask = (1 << (which + SR_IP_SHIFT)) & SR_IP;
316 if (on)
317 sr |= mask;
318 else
319 sr &= ~mask;
320 }