1 /*
2 * Microblaze helper routines.
3 *
4 * Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com>.
5 * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "qemu/osdep.h"
22 #include "qemu/log.h"
23 #include "cpu.h"
24 #include "exec/helper-proto.h"
25 #include "qemu/host-utils.h"
26 #include "exec/exec-all.h"
27 #include "exec/cpu_ldst.h"
28 #include "fpu/softfloat.h"
29
helper_put(uint32_t id,uint32_t ctrl,uint32_t data)30 void helper_put(uint32_t id, uint32_t ctrl, uint32_t data)
31 {
32 int test = ctrl & STREAM_TEST;
33 int atomic = ctrl & STREAM_ATOMIC;
34 int control = ctrl & STREAM_CONTROL;
35 int nonblock = ctrl & STREAM_NONBLOCK;
36 int exception = ctrl & STREAM_EXCEPTION;
37
38 qemu_log_mask(LOG_UNIMP, "Unhandled stream put to stream-id=%d data=%x %s%s%s%s%s\n",
39 id, data,
40 test ? "t" : "",
41 nonblock ? "n" : "",
42 exception ? "e" : "",
43 control ? "c" : "",
44 atomic ? "a" : "");
45 }
46
helper_get(uint32_t id,uint32_t ctrl)47 uint32_t helper_get(uint32_t id, uint32_t ctrl)
48 {
49 int test = ctrl & STREAM_TEST;
50 int atomic = ctrl & STREAM_ATOMIC;
51 int control = ctrl & STREAM_CONTROL;
52 int nonblock = ctrl & STREAM_NONBLOCK;
53 int exception = ctrl & STREAM_EXCEPTION;
54
55 qemu_log_mask(LOG_UNIMP, "Unhandled stream get from stream-id=%d %s%s%s%s%s\n",
56 id,
57 test ? "t" : "",
58 nonblock ? "n" : "",
59 exception ? "e" : "",
60 control ? "c" : "",
61 atomic ? "a" : "");
62 return 0xdead0000 | id;
63 }
64
helper_raise_exception(CPUMBState * env,uint32_t index)65 void helper_raise_exception(CPUMBState *env, uint32_t index)
66 {
67 CPUState *cs = env_cpu(env);
68
69 cs->exception_index = index;
70 cpu_loop_exit(cs);
71 }
72
check_divz(CPUMBState * env,uint32_t a,uint32_t b,uintptr_t ra)73 static bool check_divz(CPUMBState *env, uint32_t a, uint32_t b, uintptr_t ra)
74 {
75 if (unlikely(b == 0)) {
76 env->msr |= MSR_DZ;
77
78 if ((env->msr & MSR_EE) &&
79 env_archcpu(env)->cfg.div_zero_exception) {
80 CPUState *cs = env_cpu(env);
81
82 env->esr = ESR_EC_DIVZERO;
83 cs->exception_index = EXCP_HW_EXCP;
84 cpu_loop_exit_restore(cs, ra);
85 }
86 return false;
87 }
88 return true;
89 }
90
helper_divs(CPUMBState * env,uint32_t a,uint32_t b)91 uint32_t helper_divs(CPUMBState *env, uint32_t a, uint32_t b)
92 {
93 if (!check_divz(env, a, b, GETPC())) {
94 return 0;
95 }
96 return (int32_t)a / (int32_t)b;
97 }
98
helper_divu(CPUMBState * env,uint32_t a,uint32_t b)99 uint32_t helper_divu(CPUMBState *env, uint32_t a, uint32_t b)
100 {
101 if (!check_divz(env, a, b, GETPC())) {
102 return 0;
103 }
104 return a / b;
105 }
106
107 /* raise FPU exception. */
raise_fpu_exception(CPUMBState * env,uintptr_t ra)108 static void raise_fpu_exception(CPUMBState *env, uintptr_t ra)
109 {
110 CPUState *cs = env_cpu(env);
111
112 env->esr = ESR_EC_FPU;
113 cs->exception_index = EXCP_HW_EXCP;
114 cpu_loop_exit_restore(cs, ra);
115 }
116
update_fpu_flags(CPUMBState * env,int flags,uintptr_t ra)117 static void update_fpu_flags(CPUMBState *env, int flags, uintptr_t ra)
118 {
119 int raise = 0;
120
121 if (flags & float_flag_invalid) {
122 env->fsr |= FSR_IO;
123 raise = 1;
124 }
125 if (flags & float_flag_divbyzero) {
126 env->fsr |= FSR_DZ;
127 raise = 1;
128 }
129 if (flags & float_flag_overflow) {
130 env->fsr |= FSR_OF;
131 raise = 1;
132 }
133 if (flags & float_flag_underflow) {
134 env->fsr |= FSR_UF;
135 raise = 1;
136 }
137 if (raise
138 && (env_archcpu(env)->cfg.pvr_regs[2] & PVR2_FPU_EXC_MASK)
139 && (env->msr & MSR_EE)) {
140 raise_fpu_exception(env, ra);
141 }
142 }
143
helper_fadd(CPUMBState * env,uint32_t a,uint32_t b)144 uint32_t helper_fadd(CPUMBState *env, uint32_t a, uint32_t b)
145 {
146 CPU_FloatU fd, fa, fb;
147 int flags;
148
149 set_float_exception_flags(0, &env->fp_status);
150 fa.l = a;
151 fb.l = b;
152 fd.f = float32_add(fa.f, fb.f, &env->fp_status);
153
154 flags = get_float_exception_flags(&env->fp_status);
155 update_fpu_flags(env, flags, GETPC());
156 return fd.l;
157 }
158
helper_frsub(CPUMBState * env,uint32_t a,uint32_t b)159 uint32_t helper_frsub(CPUMBState *env, uint32_t a, uint32_t b)
160 {
161 CPU_FloatU fd, fa, fb;
162 int flags;
163
164 set_float_exception_flags(0, &env->fp_status);
165 fa.l = a;
166 fb.l = b;
167 fd.f = float32_sub(fb.f, fa.f, &env->fp_status);
168 flags = get_float_exception_flags(&env->fp_status);
169 update_fpu_flags(env, flags, GETPC());
170 return fd.l;
171 }
172
helper_fmul(CPUMBState * env,uint32_t a,uint32_t b)173 uint32_t helper_fmul(CPUMBState *env, uint32_t a, uint32_t b)
174 {
175 CPU_FloatU fd, fa, fb;
176 int flags;
177
178 set_float_exception_flags(0, &env->fp_status);
179 fa.l = a;
180 fb.l = b;
181 fd.f = float32_mul(fa.f, fb.f, &env->fp_status);
182 flags = get_float_exception_flags(&env->fp_status);
183 update_fpu_flags(env, flags, GETPC());
184
185 return fd.l;
186 }
187
helper_fdiv(CPUMBState * env,uint32_t a,uint32_t b)188 uint32_t helper_fdiv(CPUMBState *env, uint32_t a, uint32_t b)
189 {
190 CPU_FloatU fd, fa, fb;
191 int flags;
192
193 set_float_exception_flags(0, &env->fp_status);
194 fa.l = a;
195 fb.l = b;
196 fd.f = float32_div(fb.f, fa.f, &env->fp_status);
197 flags = get_float_exception_flags(&env->fp_status);
198 update_fpu_flags(env, flags, GETPC());
199
200 return fd.l;
201 }
202
helper_fcmp_un(CPUMBState * env,uint32_t a,uint32_t b)203 uint32_t helper_fcmp_un(CPUMBState *env, uint32_t a, uint32_t b)
204 {
205 CPU_FloatU fa, fb;
206 uint32_t r = 0;
207
208 fa.l = a;
209 fb.l = b;
210
211 if (float32_is_signaling_nan(fa.f, &env->fp_status) ||
212 float32_is_signaling_nan(fb.f, &env->fp_status)) {
213 update_fpu_flags(env, float_flag_invalid, GETPC());
214 r = 1;
215 }
216
217 if (float32_is_quiet_nan(fa.f, &env->fp_status) ||
218 float32_is_quiet_nan(fb.f, &env->fp_status)) {
219 r = 1;
220 }
221
222 return r;
223 }
224
helper_fcmp_lt(CPUMBState * env,uint32_t a,uint32_t b)225 uint32_t helper_fcmp_lt(CPUMBState *env, uint32_t a, uint32_t b)
226 {
227 CPU_FloatU fa, fb;
228 int r;
229 int flags;
230
231 set_float_exception_flags(0, &env->fp_status);
232 fa.l = a;
233 fb.l = b;
234 r = float32_lt(fb.f, fa.f, &env->fp_status);
235 flags = get_float_exception_flags(&env->fp_status);
236 update_fpu_flags(env, flags & float_flag_invalid, GETPC());
237
238 return r;
239 }
240
helper_fcmp_eq(CPUMBState * env,uint32_t a,uint32_t b)241 uint32_t helper_fcmp_eq(CPUMBState *env, uint32_t a, uint32_t b)
242 {
243 CPU_FloatU fa, fb;
244 int flags;
245 int r;
246
247 set_float_exception_flags(0, &env->fp_status);
248 fa.l = a;
249 fb.l = b;
250 r = float32_eq_quiet(fa.f, fb.f, &env->fp_status);
251 flags = get_float_exception_flags(&env->fp_status);
252 update_fpu_flags(env, flags & float_flag_invalid, GETPC());
253
254 return r;
255 }
256
helper_fcmp_le(CPUMBState * env,uint32_t a,uint32_t b)257 uint32_t helper_fcmp_le(CPUMBState *env, uint32_t a, uint32_t b)
258 {
259 CPU_FloatU fa, fb;
260 int flags;
261 int r;
262
263 fa.l = a;
264 fb.l = b;
265 set_float_exception_flags(0, &env->fp_status);
266 r = float32_le(fa.f, fb.f, &env->fp_status);
267 flags = get_float_exception_flags(&env->fp_status);
268 update_fpu_flags(env, flags & float_flag_invalid, GETPC());
269
270
271 return r;
272 }
273
helper_fcmp_gt(CPUMBState * env,uint32_t a,uint32_t b)274 uint32_t helper_fcmp_gt(CPUMBState *env, uint32_t a, uint32_t b)
275 {
276 CPU_FloatU fa, fb;
277 int flags, r;
278
279 fa.l = a;
280 fb.l = b;
281 set_float_exception_flags(0, &env->fp_status);
282 r = float32_lt(fa.f, fb.f, &env->fp_status);
283 flags = get_float_exception_flags(&env->fp_status);
284 update_fpu_flags(env, flags & float_flag_invalid, GETPC());
285 return r;
286 }
287
helper_fcmp_ne(CPUMBState * env,uint32_t a,uint32_t b)288 uint32_t helper_fcmp_ne(CPUMBState *env, uint32_t a, uint32_t b)
289 {
290 CPU_FloatU fa, fb;
291 int flags, r;
292
293 fa.l = a;
294 fb.l = b;
295 set_float_exception_flags(0, &env->fp_status);
296 r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status);
297 flags = get_float_exception_flags(&env->fp_status);
298 update_fpu_flags(env, flags & float_flag_invalid, GETPC());
299
300 return r;
301 }
302
helper_fcmp_ge(CPUMBState * env,uint32_t a,uint32_t b)303 uint32_t helper_fcmp_ge(CPUMBState *env, uint32_t a, uint32_t b)
304 {
305 CPU_FloatU fa, fb;
306 int flags, r;
307
308 fa.l = a;
309 fb.l = b;
310 set_float_exception_flags(0, &env->fp_status);
311 r = !float32_lt(fa.f, fb.f, &env->fp_status);
312 flags = get_float_exception_flags(&env->fp_status);
313 update_fpu_flags(env, flags & float_flag_invalid, GETPC());
314
315 return r;
316 }
317
helper_flt(CPUMBState * env,uint32_t a)318 uint32_t helper_flt(CPUMBState *env, uint32_t a)
319 {
320 CPU_FloatU fd, fa;
321
322 fa.l = a;
323 fd.f = int32_to_float32(fa.l, &env->fp_status);
324 return fd.l;
325 }
326
helper_fint(CPUMBState * env,uint32_t a)327 uint32_t helper_fint(CPUMBState *env, uint32_t a)
328 {
329 CPU_FloatU fa;
330 uint32_t r;
331 int flags;
332
333 set_float_exception_flags(0, &env->fp_status);
334 fa.l = a;
335 r = float32_to_int32(fa.f, &env->fp_status);
336 flags = get_float_exception_flags(&env->fp_status);
337 update_fpu_flags(env, flags, GETPC());
338
339 return r;
340 }
341
helper_fsqrt(CPUMBState * env,uint32_t a)342 uint32_t helper_fsqrt(CPUMBState *env, uint32_t a)
343 {
344 CPU_FloatU fd, fa;
345 int flags;
346
347 set_float_exception_flags(0, &env->fp_status);
348 fa.l = a;
349 fd.l = float32_sqrt(fa.f, &env->fp_status);
350 flags = get_float_exception_flags(&env->fp_status);
351 update_fpu_flags(env, flags, GETPC());
352
353 return fd.l;
354 }
355
helper_pcmpbf(uint32_t a,uint32_t b)356 uint32_t helper_pcmpbf(uint32_t a, uint32_t b)
357 {
358 unsigned int i;
359 uint32_t mask = 0xff000000;
360
361 for (i = 0; i < 4; i++) {
362 if ((a & mask) == (b & mask))
363 return i + 1;
364 mask >>= 8;
365 }
366 return 0;
367 }
368
helper_stackprot(CPUMBState * env,target_ulong addr)369 void helper_stackprot(CPUMBState *env, target_ulong addr)
370 {
371 if (addr < env->slr || addr > env->shr) {
372 CPUState *cs = env_cpu(env);
373
374 qemu_log_mask(CPU_LOG_INT, "Stack protector violation at "
375 TARGET_FMT_lx " %x %x\n",
376 addr, env->slr, env->shr);
377
378 env->ear = addr;
379 env->esr = ESR_EC_STACKPROT;
380 cs->exception_index = EXCP_HW_EXCP;
381 cpu_loop_exit_restore(cs, GETPC());
382 }
383 }
384
385 #if !defined(CONFIG_USER_ONLY)
386 /* Writes/reads to the MMU's special regs end up here. */
helper_mmu_read(CPUMBState * env,uint32_t ext,uint32_t rn)387 uint32_t helper_mmu_read(CPUMBState *env, uint32_t ext, uint32_t rn)
388 {
389 return mmu_read(env, ext, rn);
390 }
391
helper_mmu_write(CPUMBState * env,uint32_t ext,uint32_t rn,uint32_t v)392 void helper_mmu_write(CPUMBState *env, uint32_t ext, uint32_t rn, uint32_t v)
393 {
394 mmu_write(env, ext, rn, v);
395 }
396
mb_cpu_transaction_failed(CPUState * cs,hwaddr physaddr,vaddr addr,unsigned size,MMUAccessType access_type,int mmu_idx,MemTxAttrs attrs,MemTxResult response,uintptr_t retaddr)397 void mb_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr,
398 unsigned size, MMUAccessType access_type,
399 int mmu_idx, MemTxAttrs attrs,
400 MemTxResult response, uintptr_t retaddr)
401 {
402 MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
403 CPUMBState *env = &cpu->env;
404
405 qemu_log_mask(CPU_LOG_INT, "Transaction failed: vaddr 0x%" VADDR_PRIx
406 " physaddr 0x" HWADDR_FMT_plx " size %d access type %s\n",
407 addr, physaddr, size,
408 access_type == MMU_INST_FETCH ? "INST_FETCH" :
409 (access_type == MMU_DATA_LOAD ? "DATA_LOAD" : "DATA_STORE"));
410
411 if (!(env->msr & MSR_EE)) {
412 return;
413 }
414
415 if (access_type == MMU_INST_FETCH) {
416 if (!cpu->cfg.iopb_bus_exception) {
417 return;
418 }
419 env->esr = ESR_EC_INSN_BUS;
420 } else {
421 if (!cpu->cfg.dopb_bus_exception) {
422 return;
423 }
424 env->esr = ESR_EC_DATA_BUS;
425 }
426
427 env->ear = addr;
428 cs->exception_index = EXCP_HW_EXCP;
429 cpu_loop_exit_restore(cs, retaddr);
430 }
431 #endif
432