Merge remote-tracking branch 'remotes/bonzini-gitlab/tags/for-upstream' into staging
[qemu/ar7.git] / target / microblaze / op_helper.c
blob58d633584d37fb62fc7ac35c605e752861cca8fc
1 /*
2 * Microblaze helper routines.
4 * Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com>.
5 * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
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.
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.
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/>.
21 #include "qemu/osdep.h"
22 #include "cpu.h"
23 #include "exec/helper-proto.h"
24 #include "qemu/host-utils.h"
25 #include "exec/exec-all.h"
26 #include "exec/cpu_ldst.h"
27 #include "fpu/softfloat.h"
29 void helper_put(uint32_t id, uint32_t ctrl, uint32_t data)
31 int test = ctrl & STREAM_TEST;
32 int atomic = ctrl & STREAM_ATOMIC;
33 int control = ctrl & STREAM_CONTROL;
34 int nonblock = ctrl & STREAM_NONBLOCK;
35 int exception = ctrl & STREAM_EXCEPTION;
37 qemu_log_mask(LOG_UNIMP, "Unhandled stream put to stream-id=%d data=%x %s%s%s%s%s\n",
38 id, data,
39 test ? "t" : "",
40 nonblock ? "n" : "",
41 exception ? "e" : "",
42 control ? "c" : "",
43 atomic ? "a" : "");
46 uint32_t helper_get(uint32_t id, uint32_t ctrl)
48 int test = ctrl & STREAM_TEST;
49 int atomic = ctrl & STREAM_ATOMIC;
50 int control = ctrl & STREAM_CONTROL;
51 int nonblock = ctrl & STREAM_NONBLOCK;
52 int exception = ctrl & STREAM_EXCEPTION;
54 qemu_log_mask(LOG_UNIMP, "Unhandled stream get from stream-id=%d %s%s%s%s%s\n",
55 id,
56 test ? "t" : "",
57 nonblock ? "n" : "",
58 exception ? "e" : "",
59 control ? "c" : "",
60 atomic ? "a" : "");
61 return 0xdead0000 | id;
64 void helper_raise_exception(CPUMBState *env, uint32_t index)
66 CPUState *cs = env_cpu(env);
68 cs->exception_index = index;
69 cpu_loop_exit(cs);
72 static bool check_divz(CPUMBState *env, uint32_t a, uint32_t b, uintptr_t ra)
74 if (unlikely(b == 0)) {
75 env->msr |= MSR_DZ;
77 if ((env->msr & MSR_EE) &&
78 env_archcpu(env)->cfg.div_zero_exception) {
79 CPUState *cs = env_cpu(env);
81 env->esr = ESR_EC_DIVZERO;
82 cs->exception_index = EXCP_HW_EXCP;
83 cpu_loop_exit_restore(cs, ra);
85 return false;
87 return true;
90 uint32_t helper_divs(CPUMBState *env, uint32_t a, uint32_t b)
92 if (!check_divz(env, a, b, GETPC())) {
93 return 0;
95 return (int32_t)a / (int32_t)b;
98 uint32_t helper_divu(CPUMBState *env, uint32_t a, uint32_t b)
100 if (!check_divz(env, a, b, GETPC())) {
101 return 0;
103 return a / b;
106 /* raise FPU exception. */
107 static void raise_fpu_exception(CPUMBState *env, uintptr_t ra)
109 CPUState *cs = env_cpu(env);
111 env->esr = ESR_EC_FPU;
112 cs->exception_index = EXCP_HW_EXCP;
113 cpu_loop_exit_restore(cs, ra);
116 static void update_fpu_flags(CPUMBState *env, int flags, uintptr_t ra)
118 int raise = 0;
120 if (flags & float_flag_invalid) {
121 env->fsr |= FSR_IO;
122 raise = 1;
124 if (flags & float_flag_divbyzero) {
125 env->fsr |= FSR_DZ;
126 raise = 1;
128 if (flags & float_flag_overflow) {
129 env->fsr |= FSR_OF;
130 raise = 1;
132 if (flags & float_flag_underflow) {
133 env->fsr |= FSR_UF;
134 raise = 1;
136 if (raise
137 && (env_archcpu(env)->cfg.pvr_regs[2] & PVR2_FPU_EXC_MASK)
138 && (env->msr & MSR_EE)) {
139 raise_fpu_exception(env, ra);
143 uint32_t helper_fadd(CPUMBState *env, uint32_t a, uint32_t b)
145 CPU_FloatU fd, fa, fb;
146 int flags;
148 set_float_exception_flags(0, &env->fp_status);
149 fa.l = a;
150 fb.l = b;
151 fd.f = float32_add(fa.f, fb.f, &env->fp_status);
153 flags = get_float_exception_flags(&env->fp_status);
154 update_fpu_flags(env, flags, GETPC());
155 return fd.l;
158 uint32_t helper_frsub(CPUMBState *env, uint32_t a, uint32_t b)
160 CPU_FloatU fd, fa, fb;
161 int flags;
163 set_float_exception_flags(0, &env->fp_status);
164 fa.l = a;
165 fb.l = b;
166 fd.f = float32_sub(fb.f, fa.f, &env->fp_status);
167 flags = get_float_exception_flags(&env->fp_status);
168 update_fpu_flags(env, flags, GETPC());
169 return fd.l;
172 uint32_t helper_fmul(CPUMBState *env, uint32_t a, uint32_t b)
174 CPU_FloatU fd, fa, fb;
175 int flags;
177 set_float_exception_flags(0, &env->fp_status);
178 fa.l = a;
179 fb.l = b;
180 fd.f = float32_mul(fa.f, fb.f, &env->fp_status);
181 flags = get_float_exception_flags(&env->fp_status);
182 update_fpu_flags(env, flags, GETPC());
184 return fd.l;
187 uint32_t helper_fdiv(CPUMBState *env, uint32_t a, uint32_t b)
189 CPU_FloatU fd, fa, fb;
190 int flags;
192 set_float_exception_flags(0, &env->fp_status);
193 fa.l = a;
194 fb.l = b;
195 fd.f = float32_div(fb.f, fa.f, &env->fp_status);
196 flags = get_float_exception_flags(&env->fp_status);
197 update_fpu_flags(env, flags, GETPC());
199 return fd.l;
202 uint32_t helper_fcmp_un(CPUMBState *env, uint32_t a, uint32_t b)
204 CPU_FloatU fa, fb;
205 uint32_t r = 0;
207 fa.l = a;
208 fb.l = b;
210 if (float32_is_signaling_nan(fa.f, &env->fp_status) ||
211 float32_is_signaling_nan(fb.f, &env->fp_status)) {
212 update_fpu_flags(env, float_flag_invalid, GETPC());
213 r = 1;
216 if (float32_is_quiet_nan(fa.f, &env->fp_status) ||
217 float32_is_quiet_nan(fb.f, &env->fp_status)) {
218 r = 1;
221 return r;
224 uint32_t helper_fcmp_lt(CPUMBState *env, uint32_t a, uint32_t b)
226 CPU_FloatU fa, fb;
227 int r;
228 int flags;
230 set_float_exception_flags(0, &env->fp_status);
231 fa.l = a;
232 fb.l = b;
233 r = float32_lt(fb.f, fa.f, &env->fp_status);
234 flags = get_float_exception_flags(&env->fp_status);
235 update_fpu_flags(env, flags & float_flag_invalid, GETPC());
237 return r;
240 uint32_t helper_fcmp_eq(CPUMBState *env, uint32_t a, uint32_t b)
242 CPU_FloatU fa, fb;
243 int flags;
244 int r;
246 set_float_exception_flags(0, &env->fp_status);
247 fa.l = a;
248 fb.l = b;
249 r = float32_eq_quiet(fa.f, fb.f, &env->fp_status);
250 flags = get_float_exception_flags(&env->fp_status);
251 update_fpu_flags(env, flags & float_flag_invalid, GETPC());
253 return r;
256 uint32_t helper_fcmp_le(CPUMBState *env, uint32_t a, uint32_t b)
258 CPU_FloatU fa, fb;
259 int flags;
260 int r;
262 fa.l = a;
263 fb.l = b;
264 set_float_exception_flags(0, &env->fp_status);
265 r = float32_le(fa.f, fb.f, &env->fp_status);
266 flags = get_float_exception_flags(&env->fp_status);
267 update_fpu_flags(env, flags & float_flag_invalid, GETPC());
270 return r;
273 uint32_t helper_fcmp_gt(CPUMBState *env, uint32_t a, uint32_t b)
275 CPU_FloatU fa, fb;
276 int flags, r;
278 fa.l = a;
279 fb.l = b;
280 set_float_exception_flags(0, &env->fp_status);
281 r = float32_lt(fa.f, fb.f, &env->fp_status);
282 flags = get_float_exception_flags(&env->fp_status);
283 update_fpu_flags(env, flags & float_flag_invalid, GETPC());
284 return r;
287 uint32_t helper_fcmp_ne(CPUMBState *env, uint32_t a, uint32_t b)
289 CPU_FloatU fa, fb;
290 int flags, r;
292 fa.l = a;
293 fb.l = b;
294 set_float_exception_flags(0, &env->fp_status);
295 r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status);
296 flags = get_float_exception_flags(&env->fp_status);
297 update_fpu_flags(env, flags & float_flag_invalid, GETPC());
299 return r;
302 uint32_t helper_fcmp_ge(CPUMBState *env, uint32_t a, uint32_t b)
304 CPU_FloatU fa, fb;
305 int flags, r;
307 fa.l = a;
308 fb.l = b;
309 set_float_exception_flags(0, &env->fp_status);
310 r = !float32_lt(fa.f, fb.f, &env->fp_status);
311 flags = get_float_exception_flags(&env->fp_status);
312 update_fpu_flags(env, flags & float_flag_invalid, GETPC());
314 return r;
317 uint32_t helper_flt(CPUMBState *env, uint32_t a)
319 CPU_FloatU fd, fa;
321 fa.l = a;
322 fd.f = int32_to_float32(fa.l, &env->fp_status);
323 return fd.l;
326 uint32_t helper_fint(CPUMBState *env, uint32_t a)
328 CPU_FloatU fa;
329 uint32_t r;
330 int flags;
332 set_float_exception_flags(0, &env->fp_status);
333 fa.l = a;
334 r = float32_to_int32(fa.f, &env->fp_status);
335 flags = get_float_exception_flags(&env->fp_status);
336 update_fpu_flags(env, flags, GETPC());
338 return r;
341 uint32_t helper_fsqrt(CPUMBState *env, uint32_t a)
343 CPU_FloatU fd, fa;
344 int flags;
346 set_float_exception_flags(0, &env->fp_status);
347 fa.l = a;
348 fd.l = float32_sqrt(fa.f, &env->fp_status);
349 flags = get_float_exception_flags(&env->fp_status);
350 update_fpu_flags(env, flags, GETPC());
352 return fd.l;
355 uint32_t helper_pcmpbf(uint32_t a, uint32_t b)
357 unsigned int i;
358 uint32_t mask = 0xff000000;
360 for (i = 0; i < 4; i++) {
361 if ((a & mask) == (b & mask))
362 return i + 1;
363 mask >>= 8;
365 return 0;
368 void helper_stackprot(CPUMBState *env, target_ulong addr)
370 if (addr < env->slr || addr > env->shr) {
371 CPUState *cs = env_cpu(env);
373 qemu_log_mask(CPU_LOG_INT, "Stack protector violation at "
374 TARGET_FMT_lx " %x %x\n",
375 addr, env->slr, env->shr);
377 env->ear = addr;
378 env->esr = ESR_EC_STACKPROT;
379 cs->exception_index = EXCP_HW_EXCP;
380 cpu_loop_exit_restore(cs, GETPC());
384 #if !defined(CONFIG_USER_ONLY)
385 /* Writes/reads to the MMU's special regs end up here. */
386 uint32_t helper_mmu_read(CPUMBState *env, uint32_t ext, uint32_t rn)
388 return mmu_read(env, ext, rn);
391 void helper_mmu_write(CPUMBState *env, uint32_t ext, uint32_t rn, uint32_t v)
393 mmu_write(env, ext, rn, v);
396 void mb_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr,
397 unsigned size, MMUAccessType access_type,
398 int mmu_idx, MemTxAttrs attrs,
399 MemTxResult response, uintptr_t retaddr)
401 MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
402 CPUMBState *env = &cpu->env;
404 qemu_log_mask(CPU_LOG_INT, "Transaction failed: vaddr 0x%" VADDR_PRIx
405 " physaddr 0x" TARGET_FMT_plx " size %d access type %s\n",
406 addr, physaddr, size,
407 access_type == MMU_INST_FETCH ? "INST_FETCH" :
408 (access_type == MMU_DATA_LOAD ? "DATA_LOAD" : "DATA_STORE"));
410 if (!(env->msr & MSR_EE)) {
411 return;
414 if (access_type == MMU_INST_FETCH) {
415 if (!cpu->cfg.iopb_bus_exception) {
416 return;
418 env->esr = ESR_EC_INSN_BUS;
419 } else {
420 if (!cpu->cfg.dopb_bus_exception) {
421 return;
423 env->esr = ESR_EC_DATA_BUS;
426 env->ear = addr;
427 cs->exception_index = EXCP_HW_EXCP;
428 cpu_loop_exit_restore(cs, retaddr);
430 #endif