471afabecd559e6f0c7784bb0ac7cb6ace2a2572
[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 set_sr(SR_S | SR_SX); // SX ignored if 64b mode not supported
32 set_fsr(0);
33
34 memset(counters,0,sizeof(counters));
35
36 // vector stuff
37 utidx = -1;
38 vlmax = 8;
39 vl = 0;
40 nxpr_all = 256;
41 nfpr_all = 256;
42 nxpr_use = 0;
43 nfpr_use = 0;
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 }
57
58 processor_t::~processor_t()
59 {
60 delete icsim;
61 }
62
63 void processor_t::init(uint32_t _id)
64 {
65 id = _id;
66
67 for (int i=0; i<MAX_UTS; i++)
68 {
69 uts[i] = new processor_t(sim, mmu.mem, mmu.memsz);
70 uts[i]->id = id;
71 uts[i]->set_sr(uts[i]->sr | SR_EF);
72 uts[i]->set_sr(uts[i]->sr | SR_EV);
73 uts[i]->utidx = i;
74 }
75
76 #ifdef RISCV_ENABLE_ICSIM
77 icsim = new icsim_t(1024, 1, 32);
78 #endif
79 }
80
81 void processor_t::set_sr(uint32_t val)
82 {
83 sr = val & ~SR_ZERO;
84 #ifndef RISCV_ENABLE_64BIT
85 sr &= ~(SR_SX | SR_UX);
86 #endif
87 #ifndef RISCV_ENABLE_FPU
88 sr &= ~SR_EF;
89 #endif
90 #ifndef RISCV_ENABLE_RVC
91 sr &= ~SR_EC;
92 #endif
93 #ifndef RISCV_ENABLE_VEC
94 sr &= ~SR_EV;
95 #endif
96
97 xprlen = ((sr & SR_S) ? (sr & SR_SX) : (sr & SR_UX)) ? 64 : 32;
98 }
99
100 void processor_t::set_fsr(uint32_t val)
101 {
102 fsr = val & ~FSR_ZERO;
103 }
104
105 void processor_t::vcfg()
106 {
107 if (nxpr_use == 0 && nfpr_use == 0)
108 vlmax = 8;
109 else if (nfpr_use == 0)
110 vlmax = (nxpr_all-1) / (nxpr_use-1);
111 else if (nxpr_use == 0)
112 vlmax = (nfpr_all-1) / (nfpr_use-1);
113 else
114 vlmax = std::min((nxpr_all-1) / (nxpr_use-1), (nfpr_all-1) / (nfpr_use-1));
115
116 vlmax = std::min(vlmax, MAX_UTS);
117 }
118
119 void processor_t::setvl(int vlapp)
120 {
121 vl = std::min(vlmax, vlapp);
122 }
123
124 void processor_t::step(size_t n, bool noisy)
125 {
126 size_t i = 0;
127 while(1) try
128 {
129 for( ; i < n; i++)
130 {
131 uint32_t interrupts = (cause & CAUSE_IP) >> CAUSE_IP_SHIFT;
132 interrupts &= (sr & SR_IM) >> SR_IM_SHIFT;
133 if(interrupts && (sr & SR_ET))
134 take_trap(trap_interrupt,noisy);
135
136 insn_t insn = mmu.load_insn(pc, sr & SR_EC);
137 #ifdef RISCV_ENABLE_ICSIM
138 icsim->tick(pc, insn_length(insn));
139 #endif
140
141 reg_t npc = pc + insn_length(insn);
142
143 if(noisy)
144 disasm(insn,pc);
145
146 #include "execute.h"
147
148 pc = npc;
149 XPR[0] = 0;
150
151 if(count++ == compare)
152 cause |= 1 << (TIMER_IRQ+CAUSE_IP_SHIFT);
153 }
154 return;
155 }
156 catch(trap_t t)
157 {
158 i++;
159 take_trap(t,noisy);
160 }
161 catch(vt_command_t cmd)
162 {
163 if (cmd == vt_command_stop)
164 return;
165 }
166 }
167
168 void processor_t::take_trap(trap_t t, bool noisy)
169 {
170 demand(t < NUM_TRAPS, "internal error: bad trap number %d", int(t));
171 demand(sr & SR_ET, "error mode on core %d!\ntrap %s, pc 0x%016llx",
172 id, trap_name(t), (unsigned long long)pc);
173 if(noisy)
174 printf("core %3d: trap %s, pc 0x%016llx\n",
175 id, trap_name(t), (unsigned long long)pc);
176
177 set_sr((((sr & ~SR_ET) | SR_S) & ~SR_PS) | ((sr & SR_S) ? SR_PS : 0));
178 cause = (cause & ~CAUSE_EXCCODE) | (t << CAUSE_EXCCODE_SHIFT);
179 epc = pc;
180 pc = evec;
181 badvaddr = mmu.get_badvaddr();
182 }
183
184 void processor_t::disasm(insn_t insn, reg_t pc)
185 {
186 printf("core %3d: 0x%016llx (0x%08x) ",id,(unsigned long long)pc,insn.bits);
187
188 #ifdef RISCV_HAVE_LIBOPCODES
189 disassemble_info info;
190 INIT_DISASSEMBLE_INFO(info, stdout, fprintf);
191 info.flavour = bfd_target_unknown_flavour;
192 info.arch = bfd_arch_mips;
193 info.mach = 101; // XXX bfd_mach_mips_riscv requires modified bfd.h
194 info.endian = BFD_ENDIAN_LITTLE;
195 info.buffer = (bfd_byte*)&insn;
196 info.buffer_length = sizeof(insn);
197 info.buffer_vma = pc;
198
199 int ret = print_insn_little_mips(pc, &info);
200 demand(ret == (INSN_IS_RVC(insn.bits) ? 2 : 4), "disasm bug!");
201 #else
202 printf("unknown");
203 #endif
204 printf("\n");
205 }