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