cb2188b1c694a3614ce94e1056fc0cff240b3ce3
[riscv-isa-sim.git] / riscv / processor.cc
1 #include "processor.h"
2 #include <bfd.h>
3 #include <dis-asm.h>
4 #include <cmath>
5 #include <cstdlib>
6 #include <iostream>
7 #include "common.h"
8 #include "config.h"
9 #include "sim.h"
10 #include "icsim.h"
11
12 processor_t::processor_t(sim_t* _sim, char* _mem, size_t _memsz)
13 : sim(_sim), mmu(_mem,_memsz)
14 {
15 initialize_dispatch_table();
16 // a few assumptions about endianness, including freg_t union
17 static_assert(BYTE_ORDER == LITTLE_ENDIAN);
18 static_assert(sizeof(freg_t) == 8);
19 static_assert(sizeof(reg_t) == 8);
20
21 static_assert(sizeof(insn_t) == 4);
22 static_assert(sizeof(uint128_t) == 16 && sizeof(int128_t) == 16);
23
24 icsim = NULL;
25 dcsim = NULL;
26 itlbsim = NULL;
27 dtlbsim = NULL;
28
29 reset();
30 }
31
32 processor_t::~processor_t()
33 {
34 if(icsim)
35 icsim->print_stats();
36 delete icsim;
37
38 if(itlbsim)
39 itlbsim->print_stats();
40 delete itlbsim;
41
42 if(dcsim)
43 dcsim->print_stats();
44 delete dcsim;
45
46 if(dtlbsim)
47 dtlbsim->print_stats();
48 delete dtlbsim;
49 }
50
51 void processor_t::init(uint32_t _id, icsim_t* default_icache,
52 icsim_t* default_dcache)
53 {
54 id = _id;
55
56 for (int i=0; i<MAX_UTS; i++)
57 {
58 uts[i] = new processor_t(sim, mmu.mem, mmu.memsz);
59 uts[i]->id = id;
60 uts[i]->set_sr(uts[i]->sr | SR_EF);
61 uts[i]->set_sr(uts[i]->sr | SR_EV);
62 uts[i]->utidx = i;
63 }
64
65 #ifdef RISCV_ENABLE_ICSIM
66 icsim = new icsim_t(*default_icache);
67 mmu.set_icsim(icsim);
68 itlbsim = new icsim_t(1, 8, 4096, "ITLB");
69 mmu.set_itlbsim(itlbsim);
70 #endif
71 #ifdef RISCV_ENABLE_ICSIM
72 dcsim = new icsim_t(*default_dcache);
73 mmu.set_dcsim(dcsim);
74 dtlbsim = new icsim_t(1, 8, 4096, "DTLB");
75 mmu.set_dtlbsim(dtlbsim);
76 #endif
77 }
78
79 void processor_t::reset()
80 {
81 run = false;
82
83 memset(XPR,0,sizeof(XPR));
84 memset(FPR,0,sizeof(FPR));
85
86 pc = 0;
87 evec = 0;
88 epc = 0;
89 badvaddr = 0;
90 cause = 0;
91 pcr_k0 = 0;
92 pcr_k1 = 0;
93 tohost = 0;
94 fromhost = 0;
95 count = 0;
96 compare = 0;
97 cycle = 0;
98 set_sr(SR_S | SR_SX); // SX ignored if 64b mode not supported
99 set_fsr(0);
100
101 // vector stuff
102 vecbanks = 0xff;
103 vecbanks_count = 8;
104 utidx = -1;
105 vlmax = 32;
106 vl = 0;
107 nxfpr_bank = 256;
108 nxpr_use = 32;
109 nfpr_use = 32;
110 for (int i=0; i<MAX_UTS; i++)
111 uts[i] = NULL;
112 }
113
114 void processor_t::set_sr(uint32_t val)
115 {
116 sr = val & ~SR_ZERO;
117 #ifndef RISCV_ENABLE_64BIT
118 sr &= ~(SR_SX | SR_UX);
119 #endif
120 #ifndef RISCV_ENABLE_FPU
121 sr &= ~SR_EF;
122 #endif
123 #ifndef RISCV_ENABLE_RVC
124 sr &= ~SR_EC;
125 #endif
126 #ifndef RISCV_ENABLE_VEC
127 sr &= ~SR_EV;
128 #endif
129
130 mmu.set_vm_enabled(sr & SR_VM);
131 mmu.set_supervisor(sr & SR_S);
132 mmu.flush_tlb();
133
134 xprlen = ((sr & SR_S) ? (sr & SR_SX) : (sr & SR_UX)) ? 64 : 32;
135 }
136
137 void processor_t::set_fsr(uint32_t val)
138 {
139 fsr = val & ~FSR_ZERO;
140 }
141
142 void processor_t::vcfg()
143 {
144 if (nxpr_use + nfpr_use < 2)
145 vlmax = nxfpr_bank * vecbanks_count;
146 else
147 vlmax = (nxfpr_bank / (nxpr_use + nfpr_use - 1)) * vecbanks_count;
148
149 vlmax = std::min(vlmax, MAX_UTS);
150 }
151
152 void processor_t::setvl(int vlapp)
153 {
154 vl = std::min(vlmax, vlapp);
155 }
156
157 void processor_t::take_interrupt()
158 {
159 uint32_t interrupts = (cause & CAUSE_IP) >> CAUSE_IP_SHIFT;
160 interrupts &= (sr & SR_IM) >> SR_IM_SHIFT;
161
162 if(interrupts && (sr & SR_ET))
163 throw trap_interrupt;
164 }
165
166 void processor_t::step(size_t n, bool noisy)
167 {
168 if(!run)
169 return;
170
171 size_t i = 0;
172 while(1) try
173 {
174 take_interrupt();
175
176 #define execute_insn(noisy) \
177 do { insn_t insn = mmu.load_insn(pc, sr & SR_EC); \
178 if(noisy) disasm(insn,pc); \
179 pc = dispatch_table[insn.bits % DISPATCH_TABLE_SIZE](this, insn, pc); \
180 XPR[0] = 0; } while(0)
181
182 if(noisy) for( ; i < n; i++)
183 execute_insn(true);
184 else
185 {
186 for( ; n > 3 && i < n-3; i+=4)
187 {
188 execute_insn(false);
189 execute_insn(false);
190 execute_insn(false);
191 execute_insn(false);
192 }
193 for( ; i < n; i++)
194 execute_insn(false);
195 }
196
197 break;
198 }
199 catch(trap_t t)
200 {
201 i++;
202 take_trap(t,noisy);
203 }
204 catch(vt_command_t cmd)
205 {
206 i++;
207 if (cmd == vt_command_stop)
208 break;
209 }
210 catch(halt_t t)
211 {
212 reset();
213 return;
214 }
215
216 cycle += i;
217
218 typeof(count) old_count = count;
219 typeof(count) max_count = -1;
220 count += i;
221 if(old_count < compare && (count >= compare || old_count > max_count-i))
222 cause |= 1 << (TIMER_IRQ+CAUSE_IP_SHIFT);
223 }
224
225 void processor_t::take_trap(trap_t t, bool noisy)
226 {
227 demand(t < NUM_TRAPS, "internal error: bad trap number %d", int(t));
228 demand(sr & SR_ET, "error mode on core %d!\ntrap %s, pc 0x%016llx",
229 id, trap_name(t), (unsigned long long)pc);
230 if(noisy)
231 printf("core %3d: trap %s, pc 0x%016llx\n",
232 id, trap_name(t), (unsigned long long)pc);
233
234 set_sr((((sr & ~SR_ET) | SR_S) & ~SR_PS) | ((sr & SR_S) ? SR_PS : 0));
235 cause = (cause & ~CAUSE_EXCCODE) | (t << CAUSE_EXCCODE_SHIFT);
236 epc = pc;
237 pc = evec;
238 badvaddr = mmu.get_badvaddr();
239 }
240
241 void processor_t::deliver_ipi()
242 {
243 cause |= 1 << (IPI_IRQ+CAUSE_IP_SHIFT);
244 run = true;
245 }
246
247 void processor_t::disasm(insn_t insn, reg_t pc)
248 {
249 printf("core %3d: 0x%016llx (0x%08x) ",id,(unsigned long long)pc,insn.bits);
250
251 #ifdef RISCV_HAVE_LIBOPCODES
252 disassemble_info info;
253 INIT_DISASSEMBLE_INFO(info, stdout, fprintf);
254 info.flavour = bfd_target_unknown_flavour;
255 info.arch = bfd_arch_mips;
256 info.mach = 101; // XXX bfd_mach_mips_riscv requires modified bfd.h
257 info.endian = BFD_ENDIAN_LITTLE;
258 info.buffer = (bfd_byte*)&insn;
259 info.buffer_length = sizeof(insn);
260 info.buffer_vma = pc;
261
262 int ret = print_insn_little_mips(pc, &info);
263 demand(ret == insn_length(insn.bits), "disasm bug!");
264 #else
265 printf("unknown");
266 #endif
267 printf("\n");
268 }
269
270 // if the lower log2(DISPATCH_TABLE_SIZE) bits of an instruction
271 // uniquely identify that instruction, the dispatch table points
272 // directly to that insn_func. otherwise, we search the short
273 // list of instructions that match.
274
275 insn_func_t processor_t::dispatch_table[DISPATCH_TABLE_SIZE];
276
277 struct insn_chain_t
278 {
279 insn_func_t func;
280 uint32_t opcode;
281 uint32_t mask;
282 };
283 static std::vector<insn_chain_t> dispatch_chain[DISPATCH_TABLE_SIZE];
284
285 reg_t processor_t::dispatch(insn_t insn, reg_t pc)
286 {
287 size_t idx = insn.bits % DISPATCH_TABLE_SIZE;
288 for(size_t i = 0; i < dispatch_chain[idx].size(); i++)
289 {
290 insn_chain_t& c = dispatch_chain[idx][i];
291 if((insn.bits & c.mask) == c.opcode)
292 return c.func(this, insn, pc);
293 }
294 throw trap_illegal_instruction;
295 }
296
297 void processor_t::initialize_dispatch_table()
298 {
299 if(dispatch_table[0] != NULL)
300 return;
301
302 for(size_t i = 0; i < DISPATCH_TABLE_SIZE; i++)
303 {
304 #define DECLARE_INSN(name, opcode, mask) \
305 if((i & (mask)) == ((opcode) & (mask) & (DISPATCH_TABLE_SIZE-1))) \
306 dispatch_chain[i].push_back( \
307 (insn_chain_t){&processor_t::insn_func_ ## name, opcode, mask});
308 #include "opcodes.h"
309 #undef DECLARE_INSN
310 }
311
312 for(size_t i = 0; i < DISPATCH_TABLE_SIZE; i++)
313 {
314 if(dispatch_chain[i].size() == 1)
315 dispatch_table[i] = dispatch_chain[i][0].func;
316 else
317 dispatch_table[i] = &processor_t::dispatch;
318 }
319 }