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