]> git.proxmox.com Git - mirror_qemu.git/blob - target/microblaze/op_helper.c
target/microblaze: Split out MicroBlazeCPUConfig
[mirror_qemu.git] / target / microblaze / op_helper.c
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