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