temporary undoing of renaming
[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 the following initial state
43 set_sr(SR_S | SR_SX);
44 pc = 0;
45
46 // the following state is undefined upon boot-up,
47 // but we zero it for determinism
48 memset(XPR,0,sizeof(XPR));
49 memset(FPR,0,sizeof(FPR));
50
51 evec = 0;
52 epc = 0;
53 badvaddr = 0;
54 cause = 0;
55 pcr_k0 = 0;
56 pcr_k1 = 0;
57 count = 0;
58 compare = 0;
59 cycle = 0;
60 set_fsr(0);
61
62 // vector stuff
63 vecbanks = 0xff;
64 vecbanks_count = 8;
65 utidx = -1;
66 vlmax = 32;
67 vl = 0;
68 nxfpr_bank = 256;
69 nxpr_use = 32;
70 nfpr_use = 32;
71 }
72
73 void processor_t::set_sr(uint32_t val)
74 {
75 sr = val & ~SR_ZERO; // clear SR bits that read as zero
76
77 #ifndef RISCV_ENABLE_64BIT
78 sr &= ~(SR_SX | SR_UX); // SX=UX=0 for RV32 implementations
79 #endif
80 #ifndef RISCV_ENABLE_FPU
81 sr &= ~SR_EF;
82 #endif
83 #ifndef RISCV_ENABLE_RVC
84 sr &= ~SR_EC;
85 #endif
86 #ifndef RISCV_ENABLE_VEC
87 sr &= ~SR_EV;
88 #endif
89
90 // update MMU state and flush TLB
91 mmu.set_vm_enabled(sr & SR_VM);
92 mmu.set_supervisor(sr & SR_S);
93 mmu.flush_tlb();
94
95 // set the fixed-point register length
96 xprlen = ((sr & SR_S) ? (sr & SR_SX) : (sr & SR_UX)) ? 64 : 32;
97 }
98
99 void processor_t::set_fsr(uint32_t val)
100 {
101 fsr = val & ~FSR_ZERO; // clear FSR bits that read as zero
102 }
103
104 void processor_t::vcfg()
105 {
106 if (nxpr_use + nfpr_use < 2)
107 vlmax = nxfpr_bank * vecbanks_count;
108 else
109 vlmax = (nxfpr_bank / (nxpr_use + nfpr_use - 1)) * vecbanks_count;
110
111 vlmax = std::min(vlmax, MAX_UTS);
112 }
113
114 void processor_t::setvl(int vlapp)
115 {
116 vl = std::min(vlmax, vlapp);
117 }
118
119 void processor_t::take_interrupt()
120 {
121 uint32_t interrupts = (cause & CAUSE_IP) >> CAUSE_IP_SHIFT;
122 interrupts &= (sr & SR_IM) >> SR_IM_SHIFT;
123
124 if(interrupts && (sr & SR_ET))
125 throw trap_interrupt;
126 }
127
128 void processor_t::step(size_t n, bool noisy)
129 {
130 if(!run)
131 return;
132
133 size_t i = 0;
134 while(1) try
135 {
136 take_interrupt();
137
138 mmu_t& _mmu = mmu;
139 insn_t insn;
140 insn_func_t func;
141 reg_t npc = pc;
142
143 // execute_insn fetches and executes one instruction
144 #define execute_insn(noisy) \
145 do { \
146 insn = _mmu.load_insn(npc, sr & SR_EC, &func); \
147 if(noisy) disasm(insn,pc); \
148 npc = func(this, insn, npc); \
149 pc = npc; \
150 } while(0)
151
152 if(noisy) for( ; i < n; i++) // print out instructions as we go
153 execute_insn(true);
154 else
155 {
156 // unrolled for speed
157 for( ; n > 3 && i < n-3; i+=4)
158 {
159 execute_insn(false);
160 execute_insn(false);
161 execute_insn(false);
162 execute_insn(false);
163 }
164 for( ; i < n; i++)
165 execute_insn(false);
166 }
167
168 break;
169 }
170 catch(trap_t t)
171 {
172 // an exception occurred in the target processor
173 i++;
174 take_trap(t,noisy);
175 }
176 catch(vt_command_t cmd)
177 {
178 // this microthread has finished
179 i++;
180 assert(cmd == vt_command_stop);
181 break;
182 }
183 catch(halt_t t)
184 {
185 // sleep until IPI
186 reset();
187 return;
188 }
189
190 cycle += i;
191
192 // update timer and possibly register a timer interrupt
193 uint32_t old_count = count;
194 count += i;
195 if(old_count < compare && uint64_t(old_count) + i >= compare)
196 cause |= 1 << (TIMER_IRQ+CAUSE_IP_SHIFT);
197 }
198
199 void processor_t::take_trap(trap_t t, bool noisy)
200 {
201 if(noisy)
202 printf("core %3d: trap %s, pc 0x%016llx\n",
203 id, trap_name(t), (unsigned long long)pc);
204
205 // switch to supervisor, set previous supervisor bit, disable traps
206 set_sr((((sr & ~SR_ET) | SR_S) & ~SR_PS) | ((sr & SR_S) ? SR_PS : 0));
207 cause = (cause & ~CAUSE_EXCCODE) | (t << CAUSE_EXCCODE_SHIFT);
208 epc = pc;
209 pc = evec;
210 badvaddr = mmu.get_badvaddr();
211 }
212
213 void processor_t::deliver_ipi()
214 {
215 cause |= 1 << (IPI_IRQ+CAUSE_IP_SHIFT);
216 run = true;
217 }
218
219 void processor_t::disasm(insn_t insn, reg_t pc)
220 {
221 printf("core %3d: 0x%016llx (0x%08x) ",id,(unsigned long long)pc,insn.bits);
222
223 #ifdef RISCV_HAVE_LIBOPCODES
224 disassemble_info info;
225 INIT_DISASSEMBLE_INFO(info, stdout, fprintf);
226 info.flavour = bfd_target_unknown_flavour;
227 info.arch = bfd_arch_mips;
228 info.mach = 101; // XXX bfd_mach_mips_riscv requires modified bfd.h
229 info.endian = BFD_ENDIAN_LITTLE;
230 info.buffer = (bfd_byte*)&insn;
231 info.buffer_length = sizeof(insn);
232 info.buffer_vma = pc;
233
234 int ret = print_insn_little_mips(pc, &info);
235 assert(ret == insn_length(insn.bits));
236 #else
237 printf("unknown");
238 #endif
239 printf("\n");
240 }