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