]>
Commit | Line | Data |
---|---|---|
4acb54ba EI |
1 | /* |
2 | * Microblaze helper routines. | |
3 | * | |
4 | * Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com>. | |
dadc1064 | 5 | * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd. |
4acb54ba EI |
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 | |
8167ee88 | 18 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
4acb54ba EI |
19 | */ |
20 | ||
8fd9dece | 21 | #include "qemu/osdep.h" |
3e457172 | 22 | #include "cpu.h" |
2ef6175a | 23 | #include "exec/helper-proto.h" |
1de7afc9 | 24 | #include "qemu/host-utils.h" |
63c91552 | 25 | #include "exec/exec-all.h" |
f08b6170 | 26 | #include "exec/cpu_ldst.h" |
24f91e81 | 27 | #include "fpu/softfloat.h" |
4acb54ba | 28 | |
6d76d23e EI |
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 | ||
1d512a65 | 37 | qemu_log_mask(LOG_UNIMP, "Unhandled stream put to stream-id=%d data=%x %s%s%s%s%s\n", |
6d76d23e EI |
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 | ||
1d512a65 | 54 | qemu_log_mask(LOG_UNIMP, "Unhandled stream get from stream-id=%d %s%s%s%s%s\n", |
6d76d23e EI |
55 | id, |
56 | test ? "t" : "", | |
57 | nonblock ? "n" : "", | |
58 | exception ? "e" : "", | |
59 | control ? "c" : "", | |
60 | atomic ? "a" : ""); | |
61 | return 0xdead0000 | id; | |
62 | } | |
63 | ||
64254eba | 64 | void helper_raise_exception(CPUMBState *env, uint32_t index) |
4acb54ba | 65 | { |
f5c7e93a | 66 | CPUState *cs = env_cpu(env); |
27103424 AF |
67 | |
68 | cs->exception_index = index; | |
5638d180 | 69 | cpu_loop_exit(cs); |
4acb54ba EI |
70 | } |
71 | ||
e98651d9 | 72 | static bool check_divz(CPUMBState *env, uint32_t a, uint32_t b, uintptr_t ra) |
4acb54ba | 73 | { |
e98651d9 | 74 | if (unlikely(b == 0)) { |
2e5282ca | 75 | env->msr |= MSR_DZ; |
821ebb33 | 76 | |
e98651d9 RH |
77 | if ((env->msr & MSR_EE) && |
78 | env_archcpu(env)->cfg.div_zero_exception) { | |
79 | CPUState *cs = env_cpu(env); | |
80 | ||
78e9caf2 | 81 | env->esr = ESR_EC_DIVZERO; |
e98651d9 RH |
82 | cs->exception_index = EXCP_HW_EXCP; |
83 | cpu_loop_exit_restore(cs, ra); | |
821ebb33 | 84 | } |
e98651d9 | 85 | return false; |
4acb54ba | 86 | } |
e98651d9 | 87 | return true; |
4acb54ba EI |
88 | } |
89 | ||
64254eba | 90 | uint32_t helper_divs(CPUMBState *env, uint32_t a, uint32_t b) |
4acb54ba | 91 | { |
e98651d9 | 92 | if (!check_divz(env, a, b, GETPC())) { |
4acb54ba | 93 | return 0; |
64254eba | 94 | } |
4acb54ba EI |
95 | return (int32_t)a / (int32_t)b; |
96 | } | |
97 | ||
64254eba | 98 | uint32_t helper_divu(CPUMBState *env, uint32_t a, uint32_t b) |
4acb54ba | 99 | { |
e98651d9 | 100 | if (!check_divz(env, a, b, GETPC())) { |
4acb54ba | 101 | return 0; |
64254eba | 102 | } |
4acb54ba EI |
103 | return a / b; |
104 | } | |
105 | ||
97694c57 | 106 | /* raise FPU exception. */ |
7bca6ddf | 107 | static void raise_fpu_exception(CPUMBState *env, uintptr_t ra) |
97694c57 | 108 | { |
7bca6ddf RH |
109 | CPUState *cs = env_cpu(env); |
110 | ||
78e9caf2 | 111 | env->esr = ESR_EC_FPU; |
7bca6ddf RH |
112 | cs->exception_index = EXCP_HW_EXCP; |
113 | cpu_loop_exit_restore(cs, ra); | |
97694c57 EI |
114 | } |
115 | ||
7bca6ddf | 116 | static void update_fpu_flags(CPUMBState *env, int flags, uintptr_t ra) |
97694c57 EI |
117 | { |
118 | int raise = 0; | |
119 | ||
120 | if (flags & float_flag_invalid) { | |
5a8e0136 | 121 | env->fsr |= FSR_IO; |
97694c57 EI |
122 | raise = 1; |
123 | } | |
124 | if (flags & float_flag_divbyzero) { | |
5a8e0136 | 125 | env->fsr |= FSR_DZ; |
97694c57 EI |
126 | raise = 1; |
127 | } | |
128 | if (flags & float_flag_overflow) { | |
5a8e0136 | 129 | env->fsr |= FSR_OF; |
97694c57 EI |
130 | raise = 1; |
131 | } | |
132 | if (flags & float_flag_underflow) { | |
5a8e0136 | 133 | env->fsr |= FSR_UF; |
97694c57 EI |
134 | raise = 1; |
135 | } | |
136 | if (raise | |
137 | && (env->pvr.regs[2] & PVR2_FPU_EXC_MASK) | |
2e5282ca | 138 | && (env->msr & MSR_EE)) { |
7bca6ddf | 139 | raise_fpu_exception(env, ra); |
97694c57 EI |
140 | } |
141 | } | |
142 | ||
64254eba | 143 | uint32_t helper_fadd(CPUMBState *env, uint32_t a, uint32_t b) |
97694c57 EI |
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); | |
7bca6ddf | 154 | update_fpu_flags(env, flags, GETPC()); |
97694c57 EI |
155 | return fd.l; |
156 | } | |
157 | ||
64254eba | 158 | uint32_t helper_frsub(CPUMBState *env, uint32_t a, uint32_t b) |
97694c57 EI |
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); | |
7bca6ddf | 168 | update_fpu_flags(env, flags, GETPC()); |
97694c57 EI |
169 | return fd.l; |
170 | } | |
171 | ||
64254eba | 172 | uint32_t helper_fmul(CPUMBState *env, uint32_t a, uint32_t b) |
97694c57 EI |
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); | |
7bca6ddf | 182 | update_fpu_flags(env, flags, GETPC()); |
97694c57 EI |
183 | |
184 | return fd.l; | |
185 | } | |
186 | ||
64254eba | 187 | uint32_t helper_fdiv(CPUMBState *env, uint32_t a, uint32_t b) |
97694c57 EI |
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); | |
7bca6ddf | 197 | update_fpu_flags(env, flags, GETPC()); |
97694c57 EI |
198 | |
199 | return fd.l; | |
200 | } | |
201 | ||
64254eba | 202 | uint32_t helper_fcmp_un(CPUMBState *env, uint32_t a, uint32_t b) |
97694c57 | 203 | { |
ef9d48da EI |
204 | CPU_FloatU fa, fb; |
205 | uint32_t r = 0; | |
206 | ||
207 | fa.l = a; | |
208 | fb.l = b; | |
209 | ||
af39bc8c AM |
210 | if (float32_is_signaling_nan(fa.f, &env->fp_status) || |
211 | float32_is_signaling_nan(fb.f, &env->fp_status)) { | |
7bca6ddf | 212 | update_fpu_flags(env, float_flag_invalid, GETPC()); |
ef9d48da EI |
213 | r = 1; |
214 | } | |
215 | ||
af39bc8c AM |
216 | if (float32_is_quiet_nan(fa.f, &env->fp_status) || |
217 | float32_is_quiet_nan(fb.f, &env->fp_status)) { | |
ef9d48da EI |
218 | r = 1; |
219 | } | |
220 | ||
221 | return r; | |
97694c57 EI |
222 | } |
223 | ||
64254eba | 224 | uint32_t helper_fcmp_lt(CPUMBState *env, uint32_t a, uint32_t b) |
97694c57 EI |
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); | |
7bca6ddf | 235 | update_fpu_flags(env, flags & float_flag_invalid, GETPC()); |
97694c57 EI |
236 | |
237 | return r; | |
238 | } | |
239 | ||
64254eba | 240 | uint32_t helper_fcmp_eq(CPUMBState *env, uint32_t a, uint32_t b) |
97694c57 EI |
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; | |
211315fb | 249 | r = float32_eq_quiet(fa.f, fb.f, &env->fp_status); |
97694c57 | 250 | flags = get_float_exception_flags(&env->fp_status); |
7bca6ddf | 251 | update_fpu_flags(env, flags & float_flag_invalid, GETPC()); |
97694c57 EI |
252 | |
253 | return r; | |
254 | } | |
255 | ||
64254eba | 256 | uint32_t helper_fcmp_le(CPUMBState *env, uint32_t a, uint32_t b) |
97694c57 EI |
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); | |
7bca6ddf | 267 | update_fpu_flags(env, flags & float_flag_invalid, GETPC()); |
97694c57 EI |
268 | |
269 | ||
270 | return r; | |
271 | } | |
272 | ||
64254eba | 273 | uint32_t helper_fcmp_gt(CPUMBState *env, uint32_t a, uint32_t b) |
97694c57 EI |
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); | |
7bca6ddf | 283 | update_fpu_flags(env, flags & float_flag_invalid, GETPC()); |
97694c57 EI |
284 | return r; |
285 | } | |
286 | ||
64254eba | 287 | uint32_t helper_fcmp_ne(CPUMBState *env, uint32_t a, uint32_t b) |
97694c57 EI |
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); | |
211315fb | 295 | r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status); |
97694c57 | 296 | flags = get_float_exception_flags(&env->fp_status); |
7bca6ddf | 297 | update_fpu_flags(env, flags & float_flag_invalid, GETPC()); |
97694c57 EI |
298 | |
299 | return r; | |
300 | } | |
301 | ||
64254eba | 302 | uint32_t helper_fcmp_ge(CPUMBState *env, uint32_t a, uint32_t b) |
97694c57 EI |
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); | |
7bca6ddf | 312 | update_fpu_flags(env, flags & float_flag_invalid, GETPC()); |
97694c57 EI |
313 | |
314 | return r; | |
315 | } | |
316 | ||
64254eba | 317 | uint32_t helper_flt(CPUMBState *env, uint32_t a) |
97694c57 EI |
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 | ||
64254eba | 326 | uint32_t helper_fint(CPUMBState *env, uint32_t a) |
97694c57 EI |
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); | |
7bca6ddf | 336 | update_fpu_flags(env, flags, GETPC()); |
97694c57 EI |
337 | |
338 | return r; | |
339 | } | |
340 | ||
64254eba | 341 | uint32_t helper_fsqrt(CPUMBState *env, uint32_t a) |
97694c57 EI |
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); | |
7bca6ddf | 350 | update_fpu_flags(env, flags, GETPC()); |
97694c57 EI |
351 | |
352 | return fd.l; | |
353 | } | |
354 | ||
4acb54ba EI |
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 | ||
403322ea | 368 | void helper_stackprot(CPUMBState *env, target_ulong addr) |
5818dee5 EI |
369 | { |
370 | if (addr < env->slr || addr > env->shr) { | |
3f203194 RH |
371 | CPUState *cs = env_cpu(env); |
372 | ||
403322ea EI |
373 | qemu_log_mask(CPU_LOG_INT, "Stack protector violation at " |
374 | TARGET_FMT_lx " %x %x\n", | |
1d512a65 | 375 | addr, env->slr, env->shr); |
3f203194 | 376 | |
b2e80a3c | 377 | env->ear = addr; |
78e9caf2 | 378 | env->esr = ESR_EC_STACKPROT; |
3f203194 RH |
379 | cs->exception_index = EXCP_HW_EXCP; |
380 | cpu_loop_exit_restore(cs, GETPC()); | |
5818dee5 EI |
381 | } |
382 | } | |
383 | ||
4acb54ba EI |
384 | #if !defined(CONFIG_USER_ONLY) |
385 | /* Writes/reads to the MMU's special regs end up here. */ | |
f0f7e7f7 | 386 | uint32_t helper_mmu_read(CPUMBState *env, uint32_t ext, uint32_t rn) |
4acb54ba | 387 | { |
f0f7e7f7 | 388 | return mmu_read(env, ext, rn); |
4acb54ba EI |
389 | } |
390 | ||
f0f7e7f7 | 391 | void helper_mmu_write(CPUMBState *env, uint32_t ext, uint32_t rn, uint32_t v) |
4acb54ba | 392 | { |
f0f7e7f7 | 393 | mmu_write(env, ext, rn, v); |
4acb54ba | 394 | } |
faed1c2a | 395 | |
bdff8123 PM |
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) | |
faed1c2a | 400 | { |
5318223d RH |
401 | MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); |
402 | CPUMBState *env = &cpu->env; | |
403 | ||
bdff8123 PM |
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")); | |
bdff8123 | 409 | |
2e5282ca | 410 | if (!(env->msr & MSR_EE)) { |
faed1c2a EI |
411 | return; |
412 | } | |
413 | ||
bdff8123 | 414 | if (access_type == MMU_INST_FETCH) { |
5318223d RH |
415 | if (!cpu->cfg.iopb_bus_exception) { |
416 | return; | |
faed1c2a | 417 | } |
5318223d | 418 | env->esr = ESR_EC_INSN_BUS; |
faed1c2a | 419 | } else { |
5318223d RH |
420 | if (!cpu->cfg.dopb_bus_exception) { |
421 | return; | |
faed1c2a | 422 | } |
5318223d | 423 | env->esr = ESR_EC_DATA_BUS; |
faed1c2a | 424 | } |
5318223d RH |
425 | |
426 | env->ear = addr; | |
427 | cs->exception_index = EXCP_HW_EXCP; | |
428 | cpu_loop_exit_restore(cs, retaddr); | |
faed1c2a | 429 | } |
3c7b48b7 | 430 | #endif |