xref: /openbmc/qemu/target/microblaze/op_helper.c (revision ca0fc784)
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 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 "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"
28 
29 void helper_put(uint32_t id, uint32_t ctrl, uint32_t data)
30 {
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;
36 
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" : "");
44 }
45 
46 uint32_t helper_get(uint32_t id, uint32_t ctrl)
47 {
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;
53 
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;
62 }
63 
64 void helper_raise_exception(CPUMBState *env, uint32_t index)
65 {
66     CPUState *cs = env_cpu(env);
67 
68     cs->exception_index = index;
69     cpu_loop_exit(cs);
70 }
71 
72 static bool check_divz(CPUMBState *env, uint32_t a, uint32_t b, uintptr_t ra)
73 {
74     if (unlikely(b == 0)) {
75         env->msr |= MSR_DZ;
76 
77         if ((env->msr & MSR_EE) &&
78             env_archcpu(env)->cfg.div_zero_exception) {
79             CPUState *cs = env_cpu(env);
80 
81             env->esr = ESR_EC_DIVZERO;
82             cs->exception_index = EXCP_HW_EXCP;
83             cpu_loop_exit_restore(cs, ra);
84         }
85         return false;
86     }
87     return true;
88 }
89 
90 uint32_t helper_divs(CPUMBState *env, uint32_t a, uint32_t b)
91 {
92     if (!check_divz(env, a, b, GETPC())) {
93         return 0;
94     }
95     return (int32_t)a / (int32_t)b;
96 }
97 
98 uint32_t helper_divu(CPUMBState *env, uint32_t a, uint32_t b)
99 {
100     if (!check_divz(env, a, b, GETPC())) {
101         return 0;
102     }
103     return a / b;
104 }
105 
106 /* raise FPU exception.  */
107 static void raise_fpu_exception(CPUMBState *env, uintptr_t ra)
108 {
109     CPUState *cs = env_cpu(env);
110 
111     env->esr = ESR_EC_FPU;
112     cs->exception_index = EXCP_HW_EXCP;
113     cpu_loop_exit_restore(cs, ra);
114 }
115 
116 static void update_fpu_flags(CPUMBState *env, int flags, uintptr_t ra)
117 {
118     int raise = 0;
119 
120     if (flags & float_flag_invalid) {
121         env->fsr |= FSR_IO;
122         raise = 1;
123     }
124     if (flags & float_flag_divbyzero) {
125         env->fsr |= FSR_DZ;
126         raise = 1;
127     }
128     if (flags & float_flag_overflow) {
129         env->fsr |= FSR_OF;
130         raise = 1;
131     }
132     if (flags & float_flag_underflow) {
133         env->fsr |= FSR_UF;
134         raise = 1;
135     }
136     if (raise
137         && (env->pvr.regs[2] & PVR2_FPU_EXC_MASK)
138         && (env->msr & MSR_EE)) {
139         raise_fpu_exception(env, ra);
140     }
141 }
142 
143 uint32_t helper_fadd(CPUMBState *env, uint32_t a, uint32_t b)
144 {
145     CPU_FloatU fd, fa, fb;
146     int flags;
147 
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);
152 
153     flags = get_float_exception_flags(&env->fp_status);
154     update_fpu_flags(env, flags, GETPC());
155     return fd.l;
156 }
157 
158 uint32_t helper_frsub(CPUMBState *env, uint32_t a, uint32_t b)
159 {
160     CPU_FloatU fd, fa, fb;
161     int flags;
162 
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;
170 }
171 
172 uint32_t helper_fmul(CPUMBState *env, uint32_t a, uint32_t b)
173 {
174     CPU_FloatU fd, fa, fb;
175     int flags;
176 
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());
183 
184     return fd.l;
185 }
186 
187 uint32_t helper_fdiv(CPUMBState *env, uint32_t a, uint32_t b)
188 {
189     CPU_FloatU fd, fa, fb;
190     int flags;
191 
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());
198 
199     return fd.l;
200 }
201 
202 uint32_t helper_fcmp_un(CPUMBState *env, uint32_t a, uint32_t b)
203 {
204     CPU_FloatU fa, fb;
205     uint32_t r = 0;
206 
207     fa.l = a;
208     fb.l = b;
209 
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;
214     }
215 
216     if (float32_is_quiet_nan(fa.f, &env->fp_status) ||
217         float32_is_quiet_nan(fb.f, &env->fp_status)) {
218         r = 1;
219     }
220 
221     return r;
222 }
223 
224 uint32_t helper_fcmp_lt(CPUMBState *env, uint32_t a, uint32_t b)
225 {
226     CPU_FloatU fa, fb;
227     int r;
228     int flags;
229 
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());
236 
237     return r;
238 }
239 
240 uint32_t helper_fcmp_eq(CPUMBState *env, uint32_t a, uint32_t b)
241 {
242     CPU_FloatU fa, fb;
243     int flags;
244     int r;
245 
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());
252 
253     return r;
254 }
255 
256 uint32_t helper_fcmp_le(CPUMBState *env, uint32_t a, uint32_t b)
257 {
258     CPU_FloatU fa, fb;
259     int flags;
260     int r;
261 
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());
268 
269 
270     return r;
271 }
272 
273 uint32_t helper_fcmp_gt(CPUMBState *env, uint32_t a, uint32_t b)
274 {
275     CPU_FloatU fa, fb;
276     int flags, r;
277 
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;
285 }
286 
287 uint32_t helper_fcmp_ne(CPUMBState *env, uint32_t a, uint32_t b)
288 {
289     CPU_FloatU fa, fb;
290     int flags, r;
291 
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());
298 
299     return r;
300 }
301 
302 uint32_t helper_fcmp_ge(CPUMBState *env, uint32_t a, uint32_t b)
303 {
304     CPU_FloatU fa, fb;
305     int flags, r;
306 
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());
313 
314     return r;
315 }
316 
317 uint32_t helper_flt(CPUMBState *env, uint32_t a)
318 {
319     CPU_FloatU fd, fa;
320 
321     fa.l = a;
322     fd.f = int32_to_float32(fa.l, &env->fp_status);
323     return fd.l;
324 }
325 
326 uint32_t helper_fint(CPUMBState *env, uint32_t a)
327 {
328     CPU_FloatU fa;
329     uint32_t r;
330     int flags;
331 
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());
337 
338     return r;
339 }
340 
341 uint32_t helper_fsqrt(CPUMBState *env, uint32_t a)
342 {
343     CPU_FloatU fd, fa;
344     int flags;
345 
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());
351 
352     return fd.l;
353 }
354 
355 uint32_t helper_pcmpbf(uint32_t a, uint32_t b)
356 {
357     unsigned int i;
358     uint32_t mask = 0xff000000;
359 
360     for (i = 0; i < 4; i++) {
361         if ((a & mask) == (b & mask))
362             return i + 1;
363         mask >>= 8;
364     }
365     return 0;
366 }
367 
368 void helper_stackprot(CPUMBState *env, target_ulong addr)
369 {
370     if (addr < env->slr || addr > env->shr) {
371         CPUState *cs = env_cpu(env);
372 
373         qemu_log_mask(CPU_LOG_INT, "Stack protector violation at "
374                       TARGET_FMT_lx " %x %x\n",
375                       addr, env->slr, env->shr);
376 
377         env->ear = addr;
378         env->esr = ESR_EC_STACKPROT;
379         cs->exception_index = EXCP_HW_EXCP;
380         cpu_loop_exit_restore(cs, GETPC());
381     }
382 }
383 
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)
387 {
388     return mmu_read(env, ext, rn);
389 }
390 
391 void helper_mmu_write(CPUMBState *env, uint32_t ext, uint32_t rn, uint32_t v)
392 {
393     mmu_write(env, ext, rn, v);
394 }
395 
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)
400 {
401     MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
402     CPUMBState *env = &cpu->env;
403 
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"));
409 
410     if (!(env->msr & MSR_EE)) {
411         return;
412     }
413 
414     if (access_type == MMU_INST_FETCH) {
415         if (!cpu->cfg.iopb_bus_exception) {
416             return;
417         }
418         env->esr = ESR_EC_INSN_BUS;
419     } else {
420         if (!cpu->cfg.dopb_bus_exception) {
421             return;
422         }
423         env->esr = ESR_EC_DATA_BUS;
424     }
425 
426     env->ear = addr;
427     cs->exception_index = EXCP_HW_EXCP;
428     cpu_loop_exit_restore(cs, retaddr);
429 }
430 #endif
431