xref: /openbmc/qemu/target/microblaze/op_helper.c (revision 883f2c59)
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