385e329d8bce3e91a61512d8a13914d0567cf0ef
[riscv-isa-sim.git] / riscv / processor.cc
1 #include "processor.h"
2 #include "common.h"
3 #include "config.h"
4 #include "sim.h"
5 #include <bfd.h>
6 #include <dis-asm.h>
7 #include <cmath>
8 #include <cstdlib>
9 #include <iostream>
10 #include <assert.h>
11
12 processor_t::processor_t(sim_t* _sim, mmu_t* _mmu, uint32_t _id)
13 : sim(*_sim), mmu(*_mmu), id(_id), utidx(0)
14 {
15 reset();
16
17 // create microthreads
18 for (int i=0; i<MAX_UTS; i++)
19 uts[i] = new processor_t(&sim, &mmu, id, i);
20 }
21
22 processor_t::processor_t(sim_t* _sim, mmu_t* _mmu, uint32_t _id,
23 uint32_t _utidx)
24 : sim(*_sim), mmu(*_mmu), id(_id), utidx(_utidx)
25 {
26 reset();
27 set_sr(sr | SR_EF | SR_EV);
28
29 // microthreads don't possess their own microthreads
30 for (int i=0; i<MAX_UTS; i++)
31 uts[i] = NULL;
32 }
33
34 processor_t::~processor_t()
35 {
36 }
37
38 void processor_t::reset()
39 {
40 run = false;
41
42 // the ISA guarantees on boot that the PC is 0x2000 and the the processor
43 // is in supervisor mode, and in 64-bit mode, if supported, with traps
44 // and virtual memory disabled. we accomplish this by setting EVEC to
45 // 0x2000 and *enabling* traps, then sending the core an IPI.
46 set_sr(SR_S | SR_SX | SR_ET | SR_IM);
47 evec = 0x2000;
48
49 // the following state is undefined upon boot-up,
50 // but we zero it for determinism
51 memset(XPR,0,sizeof(XPR));
52 memset(FPR,0,sizeof(FPR));
53
54 pc = 0;
55 epc = 0;
56 badvaddr = 0;
57 cause = 0;
58 pcr_k0 = 0;
59 pcr_k1 = 0;
60 count = 0;
61 compare = 0;
62 cycle = 0;
63 set_fsr(0);
64
65 // vector stuff
66 vecbanks = 0xff;
67 vecbanks_count = 8;
68 utidx = -1;
69 vlmax = 32;
70 vl = 0;
71 nxfpr_bank = 256;
72 nxpr_use = 32;
73 nfpr_use = 32;
74 }
75
76 void processor_t::set_sr(uint32_t val)
77 {
78 sr = val & ~SR_ZERO; // clear SR bits that read as zero
79
80 #ifndef RISCV_ENABLE_64BIT
81 sr &= ~(SR_SX | SR_UX); // SX=UX=0 for RV32 implementations
82 #endif
83 #ifndef RISCV_ENABLE_FPU
84 sr &= ~SR_EF;
85 #endif
86 #ifndef RISCV_ENABLE_RVC
87 sr &= ~SR_EC;
88 #endif
89 #ifndef RISCV_ENABLE_VEC
90 sr &= ~SR_EV;
91 #endif
92
93 // update MMU state and flush TLB
94 mmu.set_vm_enabled(sr & SR_VM);
95 mmu.set_supervisor(sr & SR_S);
96 mmu.flush_tlb();
97
98 // set the fixed-point register length
99 xprlen = ((sr & SR_S) ? (sr & SR_SX) : (sr & SR_UX)) ? 64 : 32;
100 }
101
102 void processor_t::set_fsr(uint32_t val)
103 {
104 fsr = val & ~FSR_ZERO; // clear FSR bits that read as zero
105 }
106
107 void processor_t::vcfg()
108 {
109 if (nxpr_use + nfpr_use < 2)
110 vlmax = nxfpr_bank * vecbanks_count;
111 else
112 vlmax = (nxfpr_bank / (nxpr_use + nfpr_use - 1)) * vecbanks_count;
113
114 vlmax = std::min(vlmax, MAX_UTS);
115 }
116
117 void processor_t::setvl(int vlapp)
118 {
119 vl = std::min(vlmax, vlapp);
120 }
121
122 void processor_t::take_interrupt()
123 {
124 uint32_t interrupts = interrupts_pending;
125 interrupts &= (sr & SR_IM) >> SR_IM_SHIFT;
126
127 if(interrupts && (sr & SR_ET))
128 for(int i = 0; ; i++, interrupts >>= 1)
129 if(interrupts & 1)
130 throw (trap_t)(trap_irq0 + i);
131 }
132
133 void processor_t::step(size_t n, bool noisy)
134 {
135 if(!run)
136 return;
137
138 size_t i = 0;
139 while(1) try
140 {
141 take_interrupt();
142
143 mmu_t& _mmu = mmu;
144 insn_t insn;
145 insn_func_t func;
146 reg_t npc = pc;
147
148 // execute_insn fetches and executes one instruction
149 #define execute_insn(noisy) \
150 do { \
151 insn = _mmu.load_insn(npc, sr & SR_EC, &func); \
152 if(noisy) disasm(insn,pc); \
153 npc = func(this, insn, npc); \
154 pc = npc; \
155 } while(0)
156
157 if(noisy) for( ; i < n; i++) // print out instructions as we go
158 execute_insn(true);
159 else
160 {
161 // unrolled for speed
162 for( ; n > 3 && i < n-3; i+=4)
163 {
164 execute_insn(false);
165 execute_insn(false);
166 execute_insn(false);
167 execute_insn(false);
168 }
169 for( ; i < n; i++)
170 execute_insn(false);
171 }
172
173 break;
174 }
175 catch(trap_t t)
176 {
177 // an exception occurred in the target processor
178 i++;
179 take_trap(t,noisy);
180 }
181 catch(vt_command_t cmd)
182 {
183 // this microthread has finished
184 i++;
185 assert(cmd == vt_command_stop);
186 break;
187 }
188 catch(halt_t t)
189 {
190 // sleep until IPI
191 reset();
192 return;
193 }
194
195 cycle += i;
196
197 // update timer and possibly register a timer interrupt
198 uint32_t old_count = count;
199 count += i;
200 if(old_count < compare && uint64_t(old_count) + i >= compare)
201 interrupts_pending |= 1 << TIMER_IRQ;
202 }
203
204 void processor_t::take_trap(trap_t t, bool noisy)
205 {
206 if(noisy)
207 printf("core %3d: trap %s, pc 0x%016llx\n",
208 id, trap_name(t), (unsigned long long)pc);
209
210 // switch to supervisor, set previous supervisor bit, disable traps
211 set_sr((((sr & ~SR_ET) | SR_S) & ~SR_PS) | ((sr & SR_S) ? SR_PS : 0));
212 cause = t;
213 epc = pc;
214 pc = evec;
215 badvaddr = mmu.get_badvaddr();
216 }
217
218 void processor_t::deliver_ipi()
219 {
220 interrupts_pending |= 1 << IPI_IRQ;
221 run = true;
222 }
223
224 extern "C" int print_insn_little_riscv(bfd_vma, disassemble_info*);
225
226 void processor_t::disasm(insn_t insn, reg_t pc)
227 {
228 printf("core %3d: 0x%016llx (0x%08x) ",id,(unsigned long long)pc,insn.bits);
229
230 #ifdef RISCV_HAVE_LIBOPCODES
231 disassemble_info info;
232 INIT_DISASSEMBLE_INFO(info, stdout, fprintf);
233 info.flavour = bfd_target_unknown_flavour;
234 info.arch = bfd_architecture(25); // bfd_arch_riscv
235 info.mach = 164; // bfd_mach_riscv_rocket64
236 info.endian = BFD_ENDIAN_LITTLE;
237 info.buffer = (bfd_byte*)&insn;
238 info.buffer_length = sizeof(insn);
239 info.buffer_vma = pc;
240
241 int ret = print_insn_little_riscv(pc, &info);
242 assert(ret == insn_length(insn.bits));
243 #else
244 printf("unknown");
245 #endif
246 printf("\n");
247 }