Revisión | ebe9383caefd56d519e965a5d87bca29f0aeffe3 (tree) |
---|---|
Tiempo | 2017-01-24 02:52:40 |
Autor | Richard Henderson <rth@twid...> |
Commiter | Richard Henderson |
target-hppa: Implement floating-point insns
Signed-off-by: Richard Henderson <rth@twiddle.net>
@@ -9,3 +9,58 @@ DEF_HELPER_FLAGS_1(probe_r, TCG_CALL_NO_RWG_SE, tl, tl) | ||
9 | 9 | DEF_HELPER_FLAGS_1(probe_w, TCG_CALL_NO_RWG_SE, tl, tl) |
10 | 10 | |
11 | 11 | DEF_HELPER_FLAGS_1(loaded_fr0, TCG_CALL_NO_RWG, void, env) |
12 | + | |
13 | +DEF_HELPER_FLAGS_2(fsqrt_s, TCG_CALL_NO_RWG, f32, env, f32) | |
14 | +DEF_HELPER_FLAGS_2(frnd_s, TCG_CALL_NO_RWG, f32, env, f32) | |
15 | +DEF_HELPER_FLAGS_3(fadd_s, TCG_CALL_NO_RWG, f32, env, f32, f32) | |
16 | +DEF_HELPER_FLAGS_3(fsub_s, TCG_CALL_NO_RWG, f32, env, f32, f32) | |
17 | +DEF_HELPER_FLAGS_3(fmpy_s, TCG_CALL_NO_RWG, f32, env, f32, f32) | |
18 | +DEF_HELPER_FLAGS_3(fdiv_s, TCG_CALL_NO_RWG, f32, env, f32, f32) | |
19 | + | |
20 | +DEF_HELPER_FLAGS_2(fsqrt_d, TCG_CALL_NO_RWG, f64, env, f64) | |
21 | +DEF_HELPER_FLAGS_2(frnd_d, TCG_CALL_NO_RWG, f64, env, f64) | |
22 | +DEF_HELPER_FLAGS_3(fadd_d, TCG_CALL_NO_RWG, f64, env, f64, f64) | |
23 | +DEF_HELPER_FLAGS_3(fsub_d, TCG_CALL_NO_RWG, f64, env, f64, f64) | |
24 | +DEF_HELPER_FLAGS_3(fmpy_d, TCG_CALL_NO_RWG, f64, env, f64, f64) | |
25 | +DEF_HELPER_FLAGS_3(fdiv_d, TCG_CALL_NO_RWG, f64, env, f64, f64) | |
26 | + | |
27 | +DEF_HELPER_FLAGS_2(fcnv_s_d, TCG_CALL_NO_RWG, f64, env, f32) | |
28 | +DEF_HELPER_FLAGS_2(fcnv_d_s, TCG_CALL_NO_RWG, f32, env, f64) | |
29 | + | |
30 | +DEF_HELPER_FLAGS_2(fcnv_w_s, TCG_CALL_NO_RWG, f32, env, s32) | |
31 | +DEF_HELPER_FLAGS_2(fcnv_dw_s, TCG_CALL_NO_RWG, f32, env, s64) | |
32 | +DEF_HELPER_FLAGS_2(fcnv_w_d, TCG_CALL_NO_RWG, f64, env, s32) | |
33 | +DEF_HELPER_FLAGS_2(fcnv_dw_d, TCG_CALL_NO_RWG, f64, env, s64) | |
34 | + | |
35 | +DEF_HELPER_FLAGS_2(fcnv_s_w, TCG_CALL_NO_RWG, s32, env, f32) | |
36 | +DEF_HELPER_FLAGS_2(fcnv_d_w, TCG_CALL_NO_RWG, s32, env, f64) | |
37 | +DEF_HELPER_FLAGS_2(fcnv_s_dw, TCG_CALL_NO_RWG, s64, env, f32) | |
38 | +DEF_HELPER_FLAGS_2(fcnv_d_dw, TCG_CALL_NO_RWG, s64, env, f64) | |
39 | + | |
40 | +DEF_HELPER_FLAGS_2(fcnv_t_s_w, TCG_CALL_NO_RWG, s32, env, f32) | |
41 | +DEF_HELPER_FLAGS_2(fcnv_t_d_w, TCG_CALL_NO_RWG, s32, env, f64) | |
42 | +DEF_HELPER_FLAGS_2(fcnv_t_s_dw, TCG_CALL_NO_RWG, s64, env, f32) | |
43 | +DEF_HELPER_FLAGS_2(fcnv_t_d_dw, TCG_CALL_NO_RWG, s64, env, f64) | |
44 | + | |
45 | +DEF_HELPER_FLAGS_2(fcnv_uw_s, TCG_CALL_NO_RWG, f32, env, i32) | |
46 | +DEF_HELPER_FLAGS_2(fcnv_udw_s, TCG_CALL_NO_RWG, f32, env, i64) | |
47 | +DEF_HELPER_FLAGS_2(fcnv_uw_d, TCG_CALL_NO_RWG, f64, env, i32) | |
48 | +DEF_HELPER_FLAGS_2(fcnv_udw_d, TCG_CALL_NO_RWG, f64, env, i64) | |
49 | + | |
50 | +DEF_HELPER_FLAGS_2(fcnv_s_uw, TCG_CALL_NO_RWG, i32, env, f32) | |
51 | +DEF_HELPER_FLAGS_2(fcnv_d_uw, TCG_CALL_NO_RWG, i32, env, f64) | |
52 | +DEF_HELPER_FLAGS_2(fcnv_s_udw, TCG_CALL_NO_RWG, i64, env, f32) | |
53 | +DEF_HELPER_FLAGS_2(fcnv_d_udw, TCG_CALL_NO_RWG, i64, env, f64) | |
54 | + | |
55 | +DEF_HELPER_FLAGS_2(fcnv_t_s_uw, TCG_CALL_NO_RWG, i32, env, f32) | |
56 | +DEF_HELPER_FLAGS_2(fcnv_t_d_uw, TCG_CALL_NO_RWG, i32, env, f64) | |
57 | +DEF_HELPER_FLAGS_2(fcnv_t_s_udw, TCG_CALL_NO_RWG, i64, env, f32) | |
58 | +DEF_HELPER_FLAGS_2(fcnv_t_d_udw, TCG_CALL_NO_RWG, i64, env, f64) | |
59 | + | |
60 | +DEF_HELPER_FLAGS_5(fcmp_s, TCG_CALL_NO_RWG, void, env, f32, f32, i32, i32) | |
61 | +DEF_HELPER_FLAGS_5(fcmp_d, TCG_CALL_NO_RWG, void, env, f64, f64, i32, i32) | |
62 | + | |
63 | +DEF_HELPER_FLAGS_4(fmpyfadd_s, TCG_CALL_NO_RWG, i32, env, i32, i32, i32) | |
64 | +DEF_HELPER_FLAGS_4(fmpynfadd_s, TCG_CALL_NO_RWG, i32, env, i32, i32, i32) | |
65 | +DEF_HELPER_FLAGS_4(fmpyfadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) | |
66 | +DEF_HELPER_FLAGS_4(fmpynfadd_d, TCG_CALL_NO_RWG, i64, env, i64, i64, i64) |
@@ -174,3 +174,397 @@ void cpu_hppa_loaded_fr0(CPUHPPAState *env) | ||
174 | 174 | { |
175 | 175 | helper_loaded_fr0(env); |
176 | 176 | } |
177 | + | |
178 | +#define CONVERT_BIT(X, SRC, DST) \ | |
179 | + ((SRC) > (DST) \ | |
180 | + ? (X) / ((SRC) / (DST)) & (DST) \ | |
181 | + : ((X) & (SRC)) * ((DST) / (SRC))) | |
182 | + | |
183 | +static void update_fr0_op(CPUHPPAState *env, uintptr_t ra) | |
184 | +{ | |
185 | + uint32_t soft_exp = get_float_exception_flags(&env->fp_status); | |
186 | + uint32_t hard_exp = 0; | |
187 | + uint32_t shadow = env->fr0_shadow; | |
188 | + | |
189 | + if (likely(soft_exp == 0)) { | |
190 | + env->fr[0] = (uint64_t)shadow << 32; | |
191 | + return; | |
192 | + } | |
193 | + set_float_exception_flags(0, &env->fp_status); | |
194 | + | |
195 | + hard_exp |= CONVERT_BIT(soft_exp, float_flag_inexact, 1u << 0); | |
196 | + hard_exp |= CONVERT_BIT(soft_exp, float_flag_underflow, 1u << 1); | |
197 | + hard_exp |= CONVERT_BIT(soft_exp, float_flag_overflow, 1u << 2); | |
198 | + hard_exp |= CONVERT_BIT(soft_exp, float_flag_divbyzero, 1u << 3); | |
199 | + hard_exp |= CONVERT_BIT(soft_exp, float_flag_invalid, 1u << 4); | |
200 | + shadow |= hard_exp << (32 - 5); | |
201 | + env->fr0_shadow = shadow; | |
202 | + env->fr[0] = (uint64_t)shadow << 32; | |
203 | + | |
204 | + if (hard_exp & shadow) { | |
205 | + dynexcp(env, EXCP_SIGFPE, ra); | |
206 | + } | |
207 | +} | |
208 | + | |
209 | +float32 HELPER(fsqrt_s)(CPUHPPAState *env, float32 arg) | |
210 | +{ | |
211 | + float32 ret = float32_sqrt(arg, &env->fp_status); | |
212 | + update_fr0_op(env, GETPC()); | |
213 | + return ret; | |
214 | +} | |
215 | + | |
216 | +float32 HELPER(frnd_s)(CPUHPPAState *env, float32 arg) | |
217 | +{ | |
218 | + float32 ret = float32_round_to_int(arg, &env->fp_status); | |
219 | + update_fr0_op(env, GETPC()); | |
220 | + return ret; | |
221 | +} | |
222 | + | |
223 | +float32 HELPER(fadd_s)(CPUHPPAState *env, float32 a, float32 b) | |
224 | +{ | |
225 | + float32 ret = float32_add(a, b, &env->fp_status); | |
226 | + update_fr0_op(env, GETPC()); | |
227 | + return ret; | |
228 | +} | |
229 | + | |
230 | +float32 HELPER(fsub_s)(CPUHPPAState *env, float32 a, float32 b) | |
231 | +{ | |
232 | + float32 ret = float32_sub(a, b, &env->fp_status); | |
233 | + update_fr0_op(env, GETPC()); | |
234 | + return ret; | |
235 | +} | |
236 | + | |
237 | +float32 HELPER(fmpy_s)(CPUHPPAState *env, float32 a, float32 b) | |
238 | +{ | |
239 | + float32 ret = float32_mul(a, b, &env->fp_status); | |
240 | + update_fr0_op(env, GETPC()); | |
241 | + return ret; | |
242 | +} | |
243 | + | |
244 | +float32 HELPER(fdiv_s)(CPUHPPAState *env, float32 a, float32 b) | |
245 | +{ | |
246 | + float32 ret = float32_div(a, b, &env->fp_status); | |
247 | + update_fr0_op(env, GETPC()); | |
248 | + return ret; | |
249 | +} | |
250 | + | |
251 | +float64 HELPER(fsqrt_d)(CPUHPPAState *env, float64 arg) | |
252 | +{ | |
253 | + float64 ret = float64_sqrt(arg, &env->fp_status); | |
254 | + update_fr0_op(env, GETPC()); | |
255 | + return ret; | |
256 | +} | |
257 | + | |
258 | +float64 HELPER(frnd_d)(CPUHPPAState *env, float64 arg) | |
259 | +{ | |
260 | + float64 ret = float64_round_to_int(arg, &env->fp_status); | |
261 | + update_fr0_op(env, GETPC()); | |
262 | + return ret; | |
263 | +} | |
264 | + | |
265 | +float64 HELPER(fadd_d)(CPUHPPAState *env, float64 a, float64 b) | |
266 | +{ | |
267 | + float64 ret = float64_add(a, b, &env->fp_status); | |
268 | + update_fr0_op(env, GETPC()); | |
269 | + return ret; | |
270 | +} | |
271 | + | |
272 | +float64 HELPER(fsub_d)(CPUHPPAState *env, float64 a, float64 b) | |
273 | +{ | |
274 | + float64 ret = float64_sub(a, b, &env->fp_status); | |
275 | + update_fr0_op(env, GETPC()); | |
276 | + return ret; | |
277 | +} | |
278 | + | |
279 | +float64 HELPER(fmpy_d)(CPUHPPAState *env, float64 a, float64 b) | |
280 | +{ | |
281 | + float64 ret = float64_mul(a, b, &env->fp_status); | |
282 | + update_fr0_op(env, GETPC()); | |
283 | + return ret; | |
284 | +} | |
285 | + | |
286 | +float64 HELPER(fdiv_d)(CPUHPPAState *env, float64 a, float64 b) | |
287 | +{ | |
288 | + float64 ret = float64_div(a, b, &env->fp_status); | |
289 | + update_fr0_op(env, GETPC()); | |
290 | + return ret; | |
291 | +} | |
292 | + | |
293 | +float64 HELPER(fcnv_s_d)(CPUHPPAState *env, float32 arg) | |
294 | +{ | |
295 | + float64 ret = float32_to_float64(arg, &env->fp_status); | |
296 | + ret = float64_maybe_silence_nan(ret, &env->fp_status); | |
297 | + update_fr0_op(env, GETPC()); | |
298 | + return ret; | |
299 | +} | |
300 | + | |
301 | +float32 HELPER(fcnv_d_s)(CPUHPPAState *env, float64 arg) | |
302 | +{ | |
303 | + float32 ret = float64_to_float32(arg, &env->fp_status); | |
304 | + ret = float32_maybe_silence_nan(ret, &env->fp_status); | |
305 | + update_fr0_op(env, GETPC()); | |
306 | + return ret; | |
307 | +} | |
308 | + | |
309 | +float32 HELPER(fcnv_w_s)(CPUHPPAState *env, int32_t arg) | |
310 | +{ | |
311 | + float32 ret = int32_to_float32(arg, &env->fp_status); | |
312 | + update_fr0_op(env, GETPC()); | |
313 | + return ret; | |
314 | +} | |
315 | + | |
316 | +float32 HELPER(fcnv_dw_s)(CPUHPPAState *env, int64_t arg) | |
317 | +{ | |
318 | + float32 ret = int64_to_float32(arg, &env->fp_status); | |
319 | + update_fr0_op(env, GETPC()); | |
320 | + return ret; | |
321 | +} | |
322 | + | |
323 | +float64 HELPER(fcnv_w_d)(CPUHPPAState *env, int32_t arg) | |
324 | +{ | |
325 | + float64 ret = int32_to_float64(arg, &env->fp_status); | |
326 | + update_fr0_op(env, GETPC()); | |
327 | + return ret; | |
328 | +} | |
329 | + | |
330 | +float64 HELPER(fcnv_dw_d)(CPUHPPAState *env, int64_t arg) | |
331 | +{ | |
332 | + float64 ret = int64_to_float64(arg, &env->fp_status); | |
333 | + update_fr0_op(env, GETPC()); | |
334 | + return ret; | |
335 | +} | |
336 | + | |
337 | +int32_t HELPER(fcnv_s_w)(CPUHPPAState *env, float32 arg) | |
338 | +{ | |
339 | + int32_t ret = float32_to_int32(arg, &env->fp_status); | |
340 | + update_fr0_op(env, GETPC()); | |
341 | + return ret; | |
342 | +} | |
343 | + | |
344 | +int32_t HELPER(fcnv_d_w)(CPUHPPAState *env, float64 arg) | |
345 | +{ | |
346 | + int32_t ret = float64_to_int32(arg, &env->fp_status); | |
347 | + update_fr0_op(env, GETPC()); | |
348 | + return ret; | |
349 | +} | |
350 | + | |
351 | +int64_t HELPER(fcnv_s_dw)(CPUHPPAState *env, float32 arg) | |
352 | +{ | |
353 | + int64_t ret = float32_to_int64(arg, &env->fp_status); | |
354 | + update_fr0_op(env, GETPC()); | |
355 | + return ret; | |
356 | +} | |
357 | + | |
358 | +int64_t HELPER(fcnv_d_dw)(CPUHPPAState *env, float64 arg) | |
359 | +{ | |
360 | + int64_t ret = float64_to_int64(arg, &env->fp_status); | |
361 | + update_fr0_op(env, GETPC()); | |
362 | + return ret; | |
363 | +} | |
364 | + | |
365 | +int32_t HELPER(fcnv_t_s_w)(CPUHPPAState *env, float32 arg) | |
366 | +{ | |
367 | + int32_t ret = float32_to_int32_round_to_zero(arg, &env->fp_status); | |
368 | + update_fr0_op(env, GETPC()); | |
369 | + return ret; | |
370 | +} | |
371 | + | |
372 | +int32_t HELPER(fcnv_t_d_w)(CPUHPPAState *env, float64 arg) | |
373 | +{ | |
374 | + int32_t ret = float64_to_int32_round_to_zero(arg, &env->fp_status); | |
375 | + update_fr0_op(env, GETPC()); | |
376 | + return ret; | |
377 | +} | |
378 | + | |
379 | +int64_t HELPER(fcnv_t_s_dw)(CPUHPPAState *env, float32 arg) | |
380 | +{ | |
381 | + int64_t ret = float32_to_int64_round_to_zero(arg, &env->fp_status); | |
382 | + update_fr0_op(env, GETPC()); | |
383 | + return ret; | |
384 | +} | |
385 | + | |
386 | +int64_t HELPER(fcnv_t_d_dw)(CPUHPPAState *env, float64 arg) | |
387 | +{ | |
388 | + int64_t ret = float64_to_int64_round_to_zero(arg, &env->fp_status); | |
389 | + update_fr0_op(env, GETPC()); | |
390 | + return ret; | |
391 | +} | |
392 | + | |
393 | +float32 HELPER(fcnv_uw_s)(CPUHPPAState *env, uint32_t arg) | |
394 | +{ | |
395 | + float32 ret = uint32_to_float32(arg, &env->fp_status); | |
396 | + update_fr0_op(env, GETPC()); | |
397 | + return ret; | |
398 | +} | |
399 | + | |
400 | +float32 HELPER(fcnv_udw_s)(CPUHPPAState *env, uint64_t arg) | |
401 | +{ | |
402 | + float32 ret = uint64_to_float32(arg, &env->fp_status); | |
403 | + update_fr0_op(env, GETPC()); | |
404 | + return ret; | |
405 | +} | |
406 | + | |
407 | +float64 HELPER(fcnv_uw_d)(CPUHPPAState *env, uint32_t arg) | |
408 | +{ | |
409 | + float64 ret = uint32_to_float64(arg, &env->fp_status); | |
410 | + update_fr0_op(env, GETPC()); | |
411 | + return ret; | |
412 | +} | |
413 | + | |
414 | +float64 HELPER(fcnv_udw_d)(CPUHPPAState *env, uint64_t arg) | |
415 | +{ | |
416 | + float64 ret = uint64_to_float64(arg, &env->fp_status); | |
417 | + update_fr0_op(env, GETPC()); | |
418 | + return ret; | |
419 | +} | |
420 | + | |
421 | +uint32_t HELPER(fcnv_s_uw)(CPUHPPAState *env, float32 arg) | |
422 | +{ | |
423 | + uint32_t ret = float32_to_uint32(arg, &env->fp_status); | |
424 | + update_fr0_op(env, GETPC()); | |
425 | + return ret; | |
426 | +} | |
427 | + | |
428 | +uint32_t HELPER(fcnv_d_uw)(CPUHPPAState *env, float64 arg) | |
429 | +{ | |
430 | + uint32_t ret = float64_to_uint32(arg, &env->fp_status); | |
431 | + update_fr0_op(env, GETPC()); | |
432 | + return ret; | |
433 | +} | |
434 | + | |
435 | +uint64_t HELPER(fcnv_s_udw)(CPUHPPAState *env, float32 arg) | |
436 | +{ | |
437 | + uint64_t ret = float32_to_uint64(arg, &env->fp_status); | |
438 | + update_fr0_op(env, GETPC()); | |
439 | + return ret; | |
440 | +} | |
441 | + | |
442 | +uint64_t HELPER(fcnv_d_udw)(CPUHPPAState *env, float64 arg) | |
443 | +{ | |
444 | + uint64_t ret = float64_to_uint64(arg, &env->fp_status); | |
445 | + update_fr0_op(env, GETPC()); | |
446 | + return ret; | |
447 | +} | |
448 | + | |
449 | +uint32_t HELPER(fcnv_t_s_uw)(CPUHPPAState *env, float32 arg) | |
450 | +{ | |
451 | + uint32_t ret = float32_to_uint32_round_to_zero(arg, &env->fp_status); | |
452 | + update_fr0_op(env, GETPC()); | |
453 | + return ret; | |
454 | +} | |
455 | + | |
456 | +uint32_t HELPER(fcnv_t_d_uw)(CPUHPPAState *env, float64 arg) | |
457 | +{ | |
458 | + uint32_t ret = float64_to_uint32_round_to_zero(arg, &env->fp_status); | |
459 | + update_fr0_op(env, GETPC()); | |
460 | + return ret; | |
461 | +} | |
462 | + | |
463 | +uint64_t HELPER(fcnv_t_s_udw)(CPUHPPAState *env, float32 arg) | |
464 | +{ | |
465 | + uint64_t ret = float32_to_uint64_round_to_zero(arg, &env->fp_status); | |
466 | + update_fr0_op(env, GETPC()); | |
467 | + return ret; | |
468 | +} | |
469 | + | |
470 | +uint64_t HELPER(fcnv_t_d_udw)(CPUHPPAState *env, float64 arg) | |
471 | +{ | |
472 | + uint64_t ret = float64_to_uint64_round_to_zero(arg, &env->fp_status); | |
473 | + update_fr0_op(env, GETPC()); | |
474 | + return ret; | |
475 | +} | |
476 | + | |
477 | +static void update_fr0_cmp(CPUHPPAState *env, uint32_t y, uint32_t c, int r) | |
478 | +{ | |
479 | + uint32_t shadow = env->fr0_shadow; | |
480 | + | |
481 | + switch (r) { | |
482 | + case float_relation_greater: | |
483 | + c = extract32(c, 4, 1); | |
484 | + break; | |
485 | + case float_relation_less: | |
486 | + c = extract32(c, 3, 1); | |
487 | + break; | |
488 | + case float_relation_equal: | |
489 | + c = extract32(c, 2, 1); | |
490 | + break; | |
491 | + case float_relation_unordered: | |
492 | + c = extract32(c, 1, 1); | |
493 | + break; | |
494 | + default: | |
495 | + g_assert_not_reached(); | |
496 | + } | |
497 | + | |
498 | + if (y) { | |
499 | + /* targeted comparison */ | |
500 | + /* set fpsr[ca[y - 1]] to current compare */ | |
501 | + shadow = deposit32(shadow, 21 - (y - 1), 1, c); | |
502 | + } else { | |
503 | + /* queued comparison */ | |
504 | + /* shift cq right by one place */ | |
505 | + shadow = deposit32(shadow, 11, 10, extract32(shadow, 12, 10)); | |
506 | + /* move fpsr[c] to fpsr[cq[0]] */ | |
507 | + shadow = deposit32(shadow, 21, 1, extract32(shadow, 26, 1)); | |
508 | + /* set fpsr[c] to current compare */ | |
509 | + shadow = deposit32(shadow, 26, 1, c); | |
510 | + } | |
511 | + | |
512 | + env->fr0_shadow = shadow; | |
513 | + env->fr[0] = (uint64_t)shadow << 32; | |
514 | +} | |
515 | + | |
516 | +void HELPER(fcmp_s)(CPUHPPAState *env, float32 a, float32 b, | |
517 | + uint32_t y, uint32_t c) | |
518 | +{ | |
519 | + int r; | |
520 | + if (c & 1) { | |
521 | + r = float32_compare(a, b, &env->fp_status); | |
522 | + } else { | |
523 | + r = float32_compare_quiet(a, b, &env->fp_status); | |
524 | + } | |
525 | + update_fr0_op(env, GETPC()); | |
526 | + update_fr0_cmp(env, y, c, r); | |
527 | +} | |
528 | + | |
529 | +void HELPER(fcmp_d)(CPUHPPAState *env, float64 a, float64 b, | |
530 | + uint32_t y, uint32_t c) | |
531 | +{ | |
532 | + int r; | |
533 | + if (c & 1) { | |
534 | + r = float64_compare(a, b, &env->fp_status); | |
535 | + } else { | |
536 | + r = float64_compare_quiet(a, b, &env->fp_status); | |
537 | + } | |
538 | + update_fr0_op(env, GETPC()); | |
539 | + update_fr0_cmp(env, y, c, r); | |
540 | +} | |
541 | + | |
542 | +float32 HELPER(fmpyfadd_s)(CPUHPPAState *env, float32 a, float32 b, float32 c) | |
543 | +{ | |
544 | + float32 ret = float32_muladd(a, b, c, 0, &env->fp_status); | |
545 | + update_fr0_op(env, GETPC()); | |
546 | + return ret; | |
547 | +} | |
548 | + | |
549 | +float32 HELPER(fmpynfadd_s)(CPUHPPAState *env, float32 a, float32 b, float32 c) | |
550 | +{ | |
551 | + float32 ret = float32_muladd(a, b, c, float_muladd_negate_product, | |
552 | + &env->fp_status); | |
553 | + update_fr0_op(env, GETPC()); | |
554 | + return ret; | |
555 | +} | |
556 | + | |
557 | +float64 HELPER(fmpyfadd_d)(CPUHPPAState *env, float64 a, float64 b, float64 c) | |
558 | +{ | |
559 | + float64 ret = float64_muladd(a, b, c, 0, &env->fp_status); | |
560 | + update_fr0_op(env, GETPC()); | |
561 | + return ret; | |
562 | +} | |
563 | + | |
564 | +float64 HELPER(fmpynfadd_d)(CPUHPPAState *env, float64 a, float64 b, float64 c) | |
565 | +{ | |
566 | + float64 ret = float64_muladd(a, b, c, float_muladd_negate_product, | |
567 | + &env->fp_status); | |
568 | + update_fr0_op(env, GETPC()); | |
569 | + return ret; | |
570 | +} |
@@ -85,6 +85,12 @@ typedef struct DisasInsn { | ||
85 | 85 | const struct DisasInsn *f); |
86 | 86 | union { |
87 | 87 | void (*f_ttt)(TCGv, TCGv, TCGv); |
88 | + void (*f_weww)(TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32); | |
89 | + void (*f_dedd)(TCGv_i64, TCGv_env, TCGv_i64, TCGv_i64); | |
90 | + void (*f_wew)(TCGv_i32, TCGv_env, TCGv_i32); | |
91 | + void (*f_ded)(TCGv_i64, TCGv_env, TCGv_i64); | |
92 | + void (*f_wed)(TCGv_i32, TCGv_env, TCGv_i64); | |
93 | + void (*f_dew)(TCGv_i64, TCGv_env, TCGv_i32); | |
88 | 94 | }; |
89 | 95 | } DisasInsn; |
90 | 96 |
@@ -295,6 +301,28 @@ static TCGv_i32 load_frw_i32(unsigned rt) | ||
295 | 301 | return ret; |
296 | 302 | } |
297 | 303 | |
304 | +static TCGv_i32 load_frw0_i32(unsigned rt) | |
305 | +{ | |
306 | + if (rt == 0) { | |
307 | + return tcg_const_i32(0); | |
308 | + } else { | |
309 | + return load_frw_i32(rt); | |
310 | + } | |
311 | +} | |
312 | + | |
313 | +static TCGv_i64 load_frw0_i64(unsigned rt) | |
314 | +{ | |
315 | + if (rt == 0) { | |
316 | + return tcg_const_i64(0); | |
317 | + } else { | |
318 | + TCGv_i64 ret = tcg_temp_new_i64(); | |
319 | + tcg_gen_ld32u_i64(ret, cpu_env, | |
320 | + offsetof(CPUHPPAState, fr[rt & 31]) | |
321 | + + (rt & 32 ? LO_OFS : HI_OFS)); | |
322 | + return ret; | |
323 | + } | |
324 | +} | |
325 | + | |
298 | 326 | static void save_frw_i32(unsigned rt, TCGv_i32 val) |
299 | 327 | { |
300 | 328 | tcg_gen_st_i32(val, cpu_env, |
@@ -312,6 +340,15 @@ static TCGv_i64 load_frd(unsigned rt) | ||
312 | 340 | return ret; |
313 | 341 | } |
314 | 342 | |
343 | +static TCGv_i64 load_frd0(unsigned rt) | |
344 | +{ | |
345 | + if (rt == 0) { | |
346 | + return tcg_const_i64(0); | |
347 | + } else { | |
348 | + return load_frd(rt); | |
349 | + } | |
350 | +} | |
351 | + | |
315 | 352 | static void save_frd(unsigned rt, TCGv_i64 val) |
316 | 353 | { |
317 | 354 | tcg_gen_st_i64(val, cpu_env, offsetof(CPUHPPAState, fr[rt])); |
@@ -494,6 +531,35 @@ static target_long low_sextract(uint32_t val, int pos, int len) | ||
494 | 531 | return x; |
495 | 532 | } |
496 | 533 | |
534 | +static unsigned assemble_rt64(uint32_t insn) | |
535 | +{ | |
536 | + unsigned r1 = extract32(insn, 6, 1); | |
537 | + unsigned r0 = extract32(insn, 0, 5); | |
538 | + return r1 * 32 + r0; | |
539 | +} | |
540 | + | |
541 | +static unsigned assemble_ra64(uint32_t insn) | |
542 | +{ | |
543 | + unsigned r1 = extract32(insn, 7, 1); | |
544 | + unsigned r0 = extract32(insn, 21, 5); | |
545 | + return r1 * 32 + r0; | |
546 | +} | |
547 | + | |
548 | +static unsigned assemble_rb64(uint32_t insn) | |
549 | +{ | |
550 | + unsigned r1 = extract32(insn, 12, 1); | |
551 | + unsigned r0 = extract32(insn, 16, 5); | |
552 | + return r1 * 32 + r0; | |
553 | +} | |
554 | + | |
555 | +static unsigned assemble_rc64(uint32_t insn) | |
556 | +{ | |
557 | + unsigned r2 = extract32(insn, 8, 1); | |
558 | + unsigned r1 = extract32(insn, 13, 3); | |
559 | + unsigned r0 = extract32(insn, 9, 2); | |
560 | + return r2 * 32 + r1 * 4 + r0; | |
561 | +} | |
562 | + | |
497 | 563 | static target_long assemble_12(uint32_t insn) |
498 | 564 | { |
499 | 565 | target_ulong x = -(target_ulong)(insn & 1); |
@@ -1218,6 +1284,110 @@ static ExitStatus do_fstored(DisasContext *ctx, unsigned rt, unsigned rb, | ||
1218 | 1284 | return nullify_end(ctx, NO_EXIT); |
1219 | 1285 | } |
1220 | 1286 | |
1287 | +static ExitStatus do_fop_wew(DisasContext *ctx, unsigned rt, unsigned ra, | |
1288 | + void (*func)(TCGv_i32, TCGv_env, TCGv_i32)) | |
1289 | +{ | |
1290 | + TCGv_i32 tmp; | |
1291 | + | |
1292 | + nullify_over(ctx); | |
1293 | + tmp = load_frw0_i32(ra); | |
1294 | + | |
1295 | + func(tmp, cpu_env, tmp); | |
1296 | + | |
1297 | + save_frw_i32(rt, tmp); | |
1298 | + tcg_temp_free_i32(tmp); | |
1299 | + return nullify_end(ctx, NO_EXIT); | |
1300 | +} | |
1301 | + | |
1302 | +static ExitStatus do_fop_wed(DisasContext *ctx, unsigned rt, unsigned ra, | |
1303 | + void (*func)(TCGv_i32, TCGv_env, TCGv_i64)) | |
1304 | +{ | |
1305 | + TCGv_i32 dst; | |
1306 | + TCGv_i64 src; | |
1307 | + | |
1308 | + nullify_over(ctx); | |
1309 | + src = load_frd(ra); | |
1310 | + dst = tcg_temp_new_i32(); | |
1311 | + | |
1312 | + func(dst, cpu_env, src); | |
1313 | + | |
1314 | + tcg_temp_free_i64(src); | |
1315 | + save_frw_i32(rt, dst); | |
1316 | + tcg_temp_free_i32(dst); | |
1317 | + return nullify_end(ctx, NO_EXIT); | |
1318 | +} | |
1319 | + | |
1320 | +static ExitStatus do_fop_ded(DisasContext *ctx, unsigned rt, unsigned ra, | |
1321 | + void (*func)(TCGv_i64, TCGv_env, TCGv_i64)) | |
1322 | +{ | |
1323 | + TCGv_i64 tmp; | |
1324 | + | |
1325 | + nullify_over(ctx); | |
1326 | + tmp = load_frd0(ra); | |
1327 | + | |
1328 | + func(tmp, cpu_env, tmp); | |
1329 | + | |
1330 | + save_frd(rt, tmp); | |
1331 | + tcg_temp_free_i64(tmp); | |
1332 | + return nullify_end(ctx, NO_EXIT); | |
1333 | +} | |
1334 | + | |
1335 | +static ExitStatus do_fop_dew(DisasContext *ctx, unsigned rt, unsigned ra, | |
1336 | + void (*func)(TCGv_i64, TCGv_env, TCGv_i32)) | |
1337 | +{ | |
1338 | + TCGv_i32 src; | |
1339 | + TCGv_i64 dst; | |
1340 | + | |
1341 | + nullify_over(ctx); | |
1342 | + src = load_frw0_i32(ra); | |
1343 | + dst = tcg_temp_new_i64(); | |
1344 | + | |
1345 | + func(dst, cpu_env, src); | |
1346 | + | |
1347 | + tcg_temp_free_i32(src); | |
1348 | + save_frd(rt, dst); | |
1349 | + tcg_temp_free_i64(dst); | |
1350 | + return nullify_end(ctx, NO_EXIT); | |
1351 | +} | |
1352 | + | |
1353 | +static ExitStatus do_fop_weww(DisasContext *ctx, unsigned rt, | |
1354 | + unsigned ra, unsigned rb, | |
1355 | + void (*func)(TCGv_i32, TCGv_env, | |
1356 | + TCGv_i32, TCGv_i32)) | |
1357 | +{ | |
1358 | + TCGv_i32 a, b; | |
1359 | + | |
1360 | + nullify_over(ctx); | |
1361 | + a = load_frw0_i32(ra); | |
1362 | + b = load_frw0_i32(rb); | |
1363 | + | |
1364 | + func(a, cpu_env, a, b); | |
1365 | + | |
1366 | + tcg_temp_free_i32(b); | |
1367 | + save_frw_i32(rt, a); | |
1368 | + tcg_temp_free_i32(a); | |
1369 | + return nullify_end(ctx, NO_EXIT); | |
1370 | +} | |
1371 | + | |
1372 | +static ExitStatus do_fop_dedd(DisasContext *ctx, unsigned rt, | |
1373 | + unsigned ra, unsigned rb, | |
1374 | + void (*func)(TCGv_i64, TCGv_env, | |
1375 | + TCGv_i64, TCGv_i64)) | |
1376 | +{ | |
1377 | + TCGv_i64 a, b; | |
1378 | + | |
1379 | + nullify_over(ctx); | |
1380 | + a = load_frd0(ra); | |
1381 | + b = load_frd0(rb); | |
1382 | + | |
1383 | + func(a, cpu_env, a, b); | |
1384 | + | |
1385 | + tcg_temp_free_i64(b); | |
1386 | + save_frd(rt, a); | |
1387 | + tcg_temp_free_i64(a); | |
1388 | + return nullify_end(ctx, NO_EXIT); | |
1389 | +} | |
1390 | + | |
1221 | 1391 | /* Emit an unconditional branch to a direct target, which may or may not |
1222 | 1392 | have already had nullification handled. */ |
1223 | 1393 | static ExitStatus do_dbranch(DisasContext *ctx, target_ulong dest, |
@@ -2893,6 +3063,554 @@ static const DisasInsn table_branch[] = { | ||
2893 | 3063 | { 0xe800d000u, 0xfc00dffcu, trans_bve }, |
2894 | 3064 | }; |
2895 | 3065 | |
3066 | +static ExitStatus trans_fop_wew_0c(DisasContext *ctx, uint32_t insn, | |
3067 | + const DisasInsn *di) | |
3068 | +{ | |
3069 | + unsigned rt = extract32(insn, 0, 5); | |
3070 | + unsigned ra = extract32(insn, 21, 5); | |
3071 | + return do_fop_wew(ctx, rt, ra, di->f_wew); | |
3072 | +} | |
3073 | + | |
3074 | +static ExitStatus trans_fop_wew_0e(DisasContext *ctx, uint32_t insn, | |
3075 | + const DisasInsn *di) | |
3076 | +{ | |
3077 | + unsigned rt = assemble_rt64(insn); | |
3078 | + unsigned ra = assemble_ra64(insn); | |
3079 | + return do_fop_wew(ctx, rt, ra, di->f_wew); | |
3080 | +} | |
3081 | + | |
3082 | +static ExitStatus trans_fop_ded(DisasContext *ctx, uint32_t insn, | |
3083 | + const DisasInsn *di) | |
3084 | +{ | |
3085 | + unsigned rt = extract32(insn, 0, 5); | |
3086 | + unsigned ra = extract32(insn, 21, 5); | |
3087 | + return do_fop_ded(ctx, rt, ra, di->f_ded); | |
3088 | +} | |
3089 | + | |
3090 | +static ExitStatus trans_fop_wed_0c(DisasContext *ctx, uint32_t insn, | |
3091 | + const DisasInsn *di) | |
3092 | +{ | |
3093 | + unsigned rt = extract32(insn, 0, 5); | |
3094 | + unsigned ra = extract32(insn, 21, 5); | |
3095 | + return do_fop_wed(ctx, rt, ra, di->f_wed); | |
3096 | +} | |
3097 | + | |
3098 | +static ExitStatus trans_fop_wed_0e(DisasContext *ctx, uint32_t insn, | |
3099 | + const DisasInsn *di) | |
3100 | +{ | |
3101 | + unsigned rt = assemble_rt64(insn); | |
3102 | + unsigned ra = extract32(insn, 21, 5); | |
3103 | + return do_fop_wed(ctx, rt, ra, di->f_wed); | |
3104 | +} | |
3105 | + | |
3106 | +static ExitStatus trans_fop_dew_0c(DisasContext *ctx, uint32_t insn, | |
3107 | + const DisasInsn *di) | |
3108 | +{ | |
3109 | + unsigned rt = extract32(insn, 0, 5); | |
3110 | + unsigned ra = extract32(insn, 21, 5); | |
3111 | + return do_fop_dew(ctx, rt, ra, di->f_dew); | |
3112 | +} | |
3113 | + | |
3114 | +static ExitStatus trans_fop_dew_0e(DisasContext *ctx, uint32_t insn, | |
3115 | + const DisasInsn *di) | |
3116 | +{ | |
3117 | + unsigned rt = extract32(insn, 0, 5); | |
3118 | + unsigned ra = assemble_ra64(insn); | |
3119 | + return do_fop_dew(ctx, rt, ra, di->f_dew); | |
3120 | +} | |
3121 | + | |
3122 | +static ExitStatus trans_fop_weww_0c(DisasContext *ctx, uint32_t insn, | |
3123 | + const DisasInsn *di) | |
3124 | +{ | |
3125 | + unsigned rt = extract32(insn, 0, 5); | |
3126 | + unsigned rb = extract32(insn, 16, 5); | |
3127 | + unsigned ra = extract32(insn, 21, 5); | |
3128 | + return do_fop_weww(ctx, rt, ra, rb, di->f_weww); | |
3129 | +} | |
3130 | + | |
3131 | +static ExitStatus trans_fop_weww_0e(DisasContext *ctx, uint32_t insn, | |
3132 | + const DisasInsn *di) | |
3133 | +{ | |
3134 | + unsigned rt = assemble_rt64(insn); | |
3135 | + unsigned rb = assemble_rb64(insn); | |
3136 | + unsigned ra = assemble_ra64(insn); | |
3137 | + return do_fop_weww(ctx, rt, ra, rb, di->f_weww); | |
3138 | +} | |
3139 | + | |
3140 | +static ExitStatus trans_fop_dedd(DisasContext *ctx, uint32_t insn, | |
3141 | + const DisasInsn *di) | |
3142 | +{ | |
3143 | + unsigned rt = extract32(insn, 0, 5); | |
3144 | + unsigned rb = extract32(insn, 16, 5); | |
3145 | + unsigned ra = extract32(insn, 21, 5); | |
3146 | + return do_fop_dedd(ctx, rt, ra, rb, di->f_dedd); | |
3147 | +} | |
3148 | + | |
3149 | +static void gen_fcpy_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) | |
3150 | +{ | |
3151 | + tcg_gen_mov_i32(dst, src); | |
3152 | +} | |
3153 | + | |
3154 | +static void gen_fcpy_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) | |
3155 | +{ | |
3156 | + tcg_gen_mov_i64(dst, src); | |
3157 | +} | |
3158 | + | |
3159 | +static void gen_fabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) | |
3160 | +{ | |
3161 | + tcg_gen_andi_i32(dst, src, INT32_MAX); | |
3162 | +} | |
3163 | + | |
3164 | +static void gen_fabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) | |
3165 | +{ | |
3166 | + tcg_gen_andi_i64(dst, src, INT64_MAX); | |
3167 | +} | |
3168 | + | |
3169 | +static void gen_fneg_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) | |
3170 | +{ | |
3171 | + tcg_gen_xori_i32(dst, src, INT32_MIN); | |
3172 | +} | |
3173 | + | |
3174 | +static void gen_fneg_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) | |
3175 | +{ | |
3176 | + tcg_gen_xori_i64(dst, src, INT64_MIN); | |
3177 | +} | |
3178 | + | |
3179 | +static void gen_fnegabs_s(TCGv_i32 dst, TCGv_env unused, TCGv_i32 src) | |
3180 | +{ | |
3181 | + tcg_gen_ori_i32(dst, src, INT32_MIN); | |
3182 | +} | |
3183 | + | |
3184 | +static void gen_fnegabs_d(TCGv_i64 dst, TCGv_env unused, TCGv_i64 src) | |
3185 | +{ | |
3186 | + tcg_gen_ori_i64(dst, src, INT64_MIN); | |
3187 | +} | |
3188 | + | |
3189 | +static ExitStatus do_fcmp_s(DisasContext *ctx, unsigned ra, unsigned rb, | |
3190 | + unsigned y, unsigned c) | |
3191 | +{ | |
3192 | + TCGv_i32 ta, tb, tc, ty; | |
3193 | + | |
3194 | + nullify_over(ctx); | |
3195 | + | |
3196 | + ta = load_frw0_i32(ra); | |
3197 | + tb = load_frw0_i32(rb); | |
3198 | + ty = tcg_const_i32(y); | |
3199 | + tc = tcg_const_i32(c); | |
3200 | + | |
3201 | + gen_helper_fcmp_s(cpu_env, ta, tb, ty, tc); | |
3202 | + | |
3203 | + tcg_temp_free_i32(ta); | |
3204 | + tcg_temp_free_i32(tb); | |
3205 | + tcg_temp_free_i32(ty); | |
3206 | + tcg_temp_free_i32(tc); | |
3207 | + | |
3208 | + return nullify_end(ctx, NO_EXIT); | |
3209 | +} | |
3210 | + | |
3211 | +static ExitStatus trans_fcmp_s_0c(DisasContext *ctx, uint32_t insn, | |
3212 | + const DisasInsn *di) | |
3213 | +{ | |
3214 | + unsigned c = extract32(insn, 0, 5); | |
3215 | + unsigned y = extract32(insn, 13, 3); | |
3216 | + unsigned rb = extract32(insn, 16, 5); | |
3217 | + unsigned ra = extract32(insn, 21, 5); | |
3218 | + return do_fcmp_s(ctx, ra, rb, y, c); | |
3219 | +} | |
3220 | + | |
3221 | +static ExitStatus trans_fcmp_s_0e(DisasContext *ctx, uint32_t insn, | |
3222 | + const DisasInsn *di) | |
3223 | +{ | |
3224 | + unsigned c = extract32(insn, 0, 5); | |
3225 | + unsigned y = extract32(insn, 13, 3); | |
3226 | + unsigned rb = assemble_rb64(insn); | |
3227 | + unsigned ra = assemble_ra64(insn); | |
3228 | + return do_fcmp_s(ctx, ra, rb, y, c); | |
3229 | +} | |
3230 | + | |
3231 | +static ExitStatus trans_fcmp_d(DisasContext *ctx, uint32_t insn, | |
3232 | + const DisasInsn *di) | |
3233 | +{ | |
3234 | + unsigned c = extract32(insn, 0, 5); | |
3235 | + unsigned y = extract32(insn, 13, 3); | |
3236 | + unsigned rb = extract32(insn, 16, 5); | |
3237 | + unsigned ra = extract32(insn, 21, 5); | |
3238 | + TCGv_i64 ta, tb; | |
3239 | + TCGv_i32 tc, ty; | |
3240 | + | |
3241 | + nullify_over(ctx); | |
3242 | + | |
3243 | + ta = load_frd0(ra); | |
3244 | + tb = load_frd0(rb); | |
3245 | + ty = tcg_const_i32(y); | |
3246 | + tc = tcg_const_i32(c); | |
3247 | + | |
3248 | + gen_helper_fcmp_d(cpu_env, ta, tb, ty, tc); | |
3249 | + | |
3250 | + tcg_temp_free_i64(ta); | |
3251 | + tcg_temp_free_i64(tb); | |
3252 | + tcg_temp_free_i32(ty); | |
3253 | + tcg_temp_free_i32(tc); | |
3254 | + | |
3255 | + return nullify_end(ctx, NO_EXIT); | |
3256 | +} | |
3257 | + | |
3258 | +static ExitStatus trans_ftest_t(DisasContext *ctx, uint32_t insn, | |
3259 | + const DisasInsn *di) | |
3260 | +{ | |
3261 | + unsigned y = extract32(insn, 13, 3); | |
3262 | + unsigned cbit = (y ^ 1) - 1; | |
3263 | + TCGv t; | |
3264 | + | |
3265 | + nullify_over(ctx); | |
3266 | + | |
3267 | + t = tcg_temp_new(); | |
3268 | + tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow)); | |
3269 | + tcg_gen_extract_tl(t, t, 21 - cbit, 1); | |
3270 | + ctx->null_cond = cond_make_0(TCG_COND_NE, t); | |
3271 | + tcg_temp_free(t); | |
3272 | + | |
3273 | + return nullify_end(ctx, NO_EXIT); | |
3274 | +} | |
3275 | + | |
3276 | +static ExitStatus trans_ftest_q(DisasContext *ctx, uint32_t insn, | |
3277 | + const DisasInsn *di) | |
3278 | +{ | |
3279 | + unsigned c = extract32(insn, 0, 5); | |
3280 | + int mask; | |
3281 | + bool inv = false; | |
3282 | + TCGv t; | |
3283 | + | |
3284 | + nullify_over(ctx); | |
3285 | + | |
3286 | + t = tcg_temp_new(); | |
3287 | + tcg_gen_ld32u_tl(t, cpu_env, offsetof(CPUHPPAState, fr0_shadow)); | |
3288 | + | |
3289 | + switch (c) { | |
3290 | + case 0: /* simple */ | |
3291 | + tcg_gen_andi_tl(t, t, 0x4000000); | |
3292 | + ctx->null_cond = cond_make_0(TCG_COND_NE, t); | |
3293 | + goto done; | |
3294 | + case 2: /* rej */ | |
3295 | + inv = true; | |
3296 | + /* fallthru */ | |
3297 | + case 1: /* acc */ | |
3298 | + mask = 0x43ff800; | |
3299 | + break; | |
3300 | + case 6: /* rej8 */ | |
3301 | + inv = true; | |
3302 | + /* fallthru */ | |
3303 | + case 5: /* acc8 */ | |
3304 | + mask = 0x43f8000; | |
3305 | + break; | |
3306 | + case 9: /* acc6 */ | |
3307 | + mask = 0x43e0000; | |
3308 | + break; | |
3309 | + case 13: /* acc4 */ | |
3310 | + mask = 0x4380000; | |
3311 | + break; | |
3312 | + case 17: /* acc2 */ | |
3313 | + mask = 0x4200000; | |
3314 | + break; | |
3315 | + default: | |
3316 | + return gen_illegal(ctx); | |
3317 | + } | |
3318 | + if (inv) { | |
3319 | + TCGv c = load_const(ctx, mask); | |
3320 | + tcg_gen_or_tl(t, t, c); | |
3321 | + ctx->null_cond = cond_make(TCG_COND_EQ, t, c); | |
3322 | + } else { | |
3323 | + tcg_gen_andi_tl(t, t, mask); | |
3324 | + ctx->null_cond = cond_make_0(TCG_COND_EQ, t); | |
3325 | + } | |
3326 | + done: | |
3327 | + return nullify_end(ctx, NO_EXIT); | |
3328 | +} | |
3329 | + | |
3330 | +static ExitStatus trans_xmpyu(DisasContext *ctx, uint32_t insn, | |
3331 | + const DisasInsn *di) | |
3332 | +{ | |
3333 | + unsigned rt = extract32(insn, 0, 5); | |
3334 | + unsigned rb = assemble_rb64(insn); | |
3335 | + unsigned ra = assemble_ra64(insn); | |
3336 | + TCGv_i64 a, b; | |
3337 | + | |
3338 | + nullify_over(ctx); | |
3339 | + | |
3340 | + a = load_frw0_i64(ra); | |
3341 | + b = load_frw0_i64(rb); | |
3342 | + tcg_gen_mul_i64(a, a, b); | |
3343 | + save_frd(rt, a); | |
3344 | + tcg_temp_free_i64(a); | |
3345 | + tcg_temp_free_i64(b); | |
3346 | + | |
3347 | + return nullify_end(ctx, NO_EXIT); | |
3348 | +} | |
3349 | + | |
3350 | +#define FOP_DED trans_fop_ded, .f_ded | |
3351 | +#define FOP_DEDD trans_fop_dedd, .f_dedd | |
3352 | + | |
3353 | +#define FOP_WEW trans_fop_wew_0c, .f_wew | |
3354 | +#define FOP_DEW trans_fop_dew_0c, .f_dew | |
3355 | +#define FOP_WED trans_fop_wed_0c, .f_wed | |
3356 | +#define FOP_WEWW trans_fop_weww_0c, .f_weww | |
3357 | + | |
3358 | +static const DisasInsn table_float_0c[] = { | |
3359 | + /* floating point class zero */ | |
3360 | + { 0x30004000, 0xfc1fffe0, FOP_WEW = gen_fcpy_s }, | |
3361 | + { 0x30006000, 0xfc1fffe0, FOP_WEW = gen_fabs_s }, | |
3362 | + { 0x30008000, 0xfc1fffe0, FOP_WEW = gen_helper_fsqrt_s }, | |
3363 | + { 0x3000a000, 0xfc1fffe0, FOP_WEW = gen_helper_frnd_s }, | |
3364 | + { 0x3000c000, 0xfc1fffe0, FOP_WEW = gen_fneg_s }, | |
3365 | + { 0x3000e000, 0xfc1fffe0, FOP_WEW = gen_fnegabs_s }, | |
3366 | + | |
3367 | + { 0x30004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d }, | |
3368 | + { 0x30006800, 0xfc1fffe0, FOP_DED = gen_fabs_d }, | |
3369 | + { 0x30008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d }, | |
3370 | + { 0x3000a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d }, | |
3371 | + { 0x3000c800, 0xfc1fffe0, FOP_DED = gen_fneg_d }, | |
3372 | + { 0x3000e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d }, | |
3373 | + | |
3374 | + /* floating point class three */ | |
3375 | + { 0x30000600, 0xfc00ffe0, FOP_WEWW = gen_helper_fadd_s }, | |
3376 | + { 0x30002600, 0xfc00ffe0, FOP_WEWW = gen_helper_fsub_s }, | |
3377 | + { 0x30004600, 0xfc00ffe0, FOP_WEWW = gen_helper_fmpy_s }, | |
3378 | + { 0x30006600, 0xfc00ffe0, FOP_WEWW = gen_helper_fdiv_s }, | |
3379 | + | |
3380 | + { 0x30000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d }, | |
3381 | + { 0x30002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d }, | |
3382 | + { 0x30004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d }, | |
3383 | + { 0x30006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d }, | |
3384 | + | |
3385 | + /* floating point class one */ | |
3386 | + /* float/float */ | |
3387 | + { 0x30000a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_s }, | |
3388 | + { 0x30002200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_d }, | |
3389 | + /* int/float */ | |
3390 | + { 0x30008200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_w_s }, | |
3391 | + { 0x30008a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_dw_s }, | |
3392 | + { 0x3000a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_w_d }, | |
3393 | + { 0x3000aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d }, | |
3394 | + /* float/int */ | |
3395 | + { 0x30010200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_w }, | |
3396 | + { 0x30010a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_w }, | |
3397 | + { 0x30012200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_dw }, | |
3398 | + { 0x30012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw }, | |
3399 | + /* float/int truncate */ | |
3400 | + { 0x30018200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_w }, | |
3401 | + { 0x30018a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_w }, | |
3402 | + { 0x3001a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_dw }, | |
3403 | + { 0x3001aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw }, | |
3404 | + /* uint/float */ | |
3405 | + { 0x30028200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_uw_s }, | |
3406 | + { 0x30028a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_udw_s }, | |
3407 | + { 0x3002a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_uw_d }, | |
3408 | + { 0x3002aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d }, | |
3409 | + /* float/uint */ | |
3410 | + { 0x30030200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_s_uw }, | |
3411 | + { 0x30030a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_d_uw }, | |
3412 | + { 0x30032200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_s_udw }, | |
3413 | + { 0x30032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw }, | |
3414 | + /* float/uint truncate */ | |
3415 | + { 0x30038200, 0xfc1fffe0, FOP_WEW = gen_helper_fcnv_t_s_uw }, | |
3416 | + { 0x30038a00, 0xfc1fffe0, FOP_WED = gen_helper_fcnv_t_d_uw }, | |
3417 | + { 0x3003a200, 0xfc1fffe0, FOP_DEW = gen_helper_fcnv_t_s_udw }, | |
3418 | + { 0x3003aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw }, | |
3419 | + | |
3420 | + /* floating point class two */ | |
3421 | + { 0x30000400, 0xfc001fe0, trans_fcmp_s_0c }, | |
3422 | + { 0x30000c00, 0xfc001fe0, trans_fcmp_d }, | |
3423 | + { 0x30002420, 0xffffffe0, trans_ftest_q }, | |
3424 | + { 0x30000420, 0xffff1fff, trans_ftest_t }, | |
3425 | + | |
3426 | + /* FID. Note that ra == rt == 0, which via fcpy puts 0 into fr0. | |
3427 | + This is machine/revision == 0, which is reserved for simulator. */ | |
3428 | + { 0x30000000, 0xffffffff, FOP_WEW = gen_fcpy_s }, | |
3429 | +}; | |
3430 | + | |
3431 | +#undef FOP_WEW | |
3432 | +#undef FOP_DEW | |
3433 | +#undef FOP_WED | |
3434 | +#undef FOP_WEWW | |
3435 | +#define FOP_WEW trans_fop_wew_0e, .f_wew | |
3436 | +#define FOP_DEW trans_fop_dew_0e, .f_dew | |
3437 | +#define FOP_WED trans_fop_wed_0e, .f_wed | |
3438 | +#define FOP_WEWW trans_fop_weww_0e, .f_weww | |
3439 | + | |
3440 | +static const DisasInsn table_float_0e[] = { | |
3441 | + /* floating point class zero */ | |
3442 | + { 0x38004000, 0xfc1fff20, FOP_WEW = gen_fcpy_s }, | |
3443 | + { 0x38006000, 0xfc1fff20, FOP_WEW = gen_fabs_s }, | |
3444 | + { 0x38008000, 0xfc1fff20, FOP_WEW = gen_helper_fsqrt_s }, | |
3445 | + { 0x3800a000, 0xfc1fff20, FOP_WEW = gen_helper_frnd_s }, | |
3446 | + { 0x3800c000, 0xfc1fff20, FOP_WEW = gen_fneg_s }, | |
3447 | + { 0x3800e000, 0xfc1fff20, FOP_WEW = gen_fnegabs_s }, | |
3448 | + | |
3449 | + { 0x38004800, 0xfc1fffe0, FOP_DED = gen_fcpy_d }, | |
3450 | + { 0x38006800, 0xfc1fffe0, FOP_DED = gen_fabs_d }, | |
3451 | + { 0x38008800, 0xfc1fffe0, FOP_DED = gen_helper_fsqrt_d }, | |
3452 | + { 0x3800a800, 0xfc1fffe0, FOP_DED = gen_helper_frnd_d }, | |
3453 | + { 0x3800c800, 0xfc1fffe0, FOP_DED = gen_fneg_d }, | |
3454 | + { 0x3800e800, 0xfc1fffe0, FOP_DED = gen_fnegabs_d }, | |
3455 | + | |
3456 | + /* floating point class three */ | |
3457 | + { 0x38000600, 0xfc00ef20, FOP_WEWW = gen_helper_fadd_s }, | |
3458 | + { 0x38002600, 0xfc00ef20, FOP_WEWW = gen_helper_fsub_s }, | |
3459 | + { 0x38004600, 0xfc00ef20, FOP_WEWW = gen_helper_fmpy_s }, | |
3460 | + { 0x38006600, 0xfc00ef20, FOP_WEWW = gen_helper_fdiv_s }, | |
3461 | + | |
3462 | + { 0x38000e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fadd_d }, | |
3463 | + { 0x38002e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fsub_d }, | |
3464 | + { 0x38004e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fmpy_d }, | |
3465 | + { 0x38006e00, 0xfc00ffe0, FOP_DEDD = gen_helper_fdiv_d }, | |
3466 | + | |
3467 | + { 0x38004700, 0xfc00ef60, trans_xmpyu }, | |
3468 | + | |
3469 | + /* floating point class one */ | |
3470 | + /* float/float */ | |
3471 | + { 0x38000a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_s }, | |
3472 | + { 0x38002200, 0xfc1fffc0, FOP_DEW = gen_helper_fcnv_s_d }, | |
3473 | + /* int/float */ | |
3474 | + { 0x38008200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_w_s }, | |
3475 | + { 0x38008a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_dw_s }, | |
3476 | + { 0x3800a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_w_d }, | |
3477 | + { 0x3800aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_dw_d }, | |
3478 | + /* float/int */ | |
3479 | + { 0x38010200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_w }, | |
3480 | + { 0x38010a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_w }, | |
3481 | + { 0x38012200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_dw }, | |
3482 | + { 0x38012a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_dw }, | |
3483 | + /* float/int truncate */ | |
3484 | + { 0x38018200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_w }, | |
3485 | + { 0x38018a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_w }, | |
3486 | + { 0x3801a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_dw }, | |
3487 | + { 0x3801aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_dw }, | |
3488 | + /* uint/float */ | |
3489 | + { 0x38028200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_uw_s }, | |
3490 | + { 0x38028a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_udw_s }, | |
3491 | + { 0x3802a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_uw_d }, | |
3492 | + { 0x3802aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_udw_d }, | |
3493 | + /* float/uint */ | |
3494 | + { 0x38030200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_s_uw }, | |
3495 | + { 0x38030a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_d_uw }, | |
3496 | + { 0x38032200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_s_udw }, | |
3497 | + { 0x38032a00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_d_udw }, | |
3498 | + /* float/uint truncate */ | |
3499 | + { 0x38038200, 0xfc1ffe60, FOP_WEW = gen_helper_fcnv_t_s_uw }, | |
3500 | + { 0x38038a00, 0xfc1fffa0, FOP_WED = gen_helper_fcnv_t_d_uw }, | |
3501 | + { 0x3803a200, 0xfc1fff60, FOP_DEW = gen_helper_fcnv_t_s_udw }, | |
3502 | + { 0x3803aa00, 0xfc1fffe0, FOP_DED = gen_helper_fcnv_t_d_udw }, | |
3503 | + | |
3504 | + /* floating point class two */ | |
3505 | + { 0x38000400, 0xfc000f60, trans_fcmp_s_0e }, | |
3506 | + { 0x38000c00, 0xfc001fe0, trans_fcmp_d }, | |
3507 | +}; | |
3508 | + | |
3509 | +#undef FOP_WEW | |
3510 | +#undef FOP_DEW | |
3511 | +#undef FOP_WED | |
3512 | +#undef FOP_WEWW | |
3513 | +#undef FOP_DED | |
3514 | +#undef FOP_DEDD | |
3515 | + | |
3516 | +/* Convert the fmpyadd single-precision register encodings to standard. */ | |
3517 | +static inline int fmpyadd_s_reg(unsigned r) | |
3518 | +{ | |
3519 | + return (r & 16) * 2 + 16 + (r & 15); | |
3520 | +} | |
3521 | + | |
3522 | +static ExitStatus trans_fmpyadd(DisasContext *ctx, uint32_t insn, bool is_sub) | |
3523 | +{ | |
3524 | + unsigned tm = extract32(insn, 0, 5); | |
3525 | + unsigned f = extract32(insn, 5, 1); | |
3526 | + unsigned ra = extract32(insn, 6, 5); | |
3527 | + unsigned ta = extract32(insn, 11, 5); | |
3528 | + unsigned rm2 = extract32(insn, 16, 5); | |
3529 | + unsigned rm1 = extract32(insn, 21, 5); | |
3530 | + | |
3531 | + nullify_over(ctx); | |
3532 | + | |
3533 | + /* Independent multiply & add/sub, with undefined behaviour | |
3534 | + if outputs overlap inputs. */ | |
3535 | + if (f == 0) { | |
3536 | + tm = fmpyadd_s_reg(tm); | |
3537 | + ra = fmpyadd_s_reg(ra); | |
3538 | + ta = fmpyadd_s_reg(ta); | |
3539 | + rm2 = fmpyadd_s_reg(rm2); | |
3540 | + rm1 = fmpyadd_s_reg(rm1); | |
3541 | + do_fop_weww(ctx, tm, rm1, rm2, gen_helper_fmpy_s); | |
3542 | + do_fop_weww(ctx, ta, ta, ra, | |
3543 | + is_sub ? gen_helper_fsub_s : gen_helper_fadd_s); | |
3544 | + } else { | |
3545 | + do_fop_dedd(ctx, tm, rm1, rm2, gen_helper_fmpy_d); | |
3546 | + do_fop_dedd(ctx, ta, ta, ra, | |
3547 | + is_sub ? gen_helper_fsub_d : gen_helper_fadd_d); | |
3548 | + } | |
3549 | + | |
3550 | + return nullify_end(ctx, NO_EXIT); | |
3551 | +} | |
3552 | + | |
3553 | +static ExitStatus trans_fmpyfadd_s(DisasContext *ctx, uint32_t insn, | |
3554 | + const DisasInsn *di) | |
3555 | +{ | |
3556 | + unsigned rt = assemble_rt64(insn); | |
3557 | + unsigned neg = extract32(insn, 5, 1); | |
3558 | + unsigned rm1 = assemble_ra64(insn); | |
3559 | + unsigned rm2 = assemble_rb64(insn); | |
3560 | + unsigned ra3 = assemble_rc64(insn); | |
3561 | + TCGv_i32 a, b, c; | |
3562 | + | |
3563 | + nullify_over(ctx); | |
3564 | + a = load_frw0_i32(rm1); | |
3565 | + b = load_frw0_i32(rm2); | |
3566 | + c = load_frw0_i32(ra3); | |
3567 | + | |
3568 | + if (neg) { | |
3569 | + gen_helper_fmpynfadd_s(a, cpu_env, a, b, c); | |
3570 | + } else { | |
3571 | + gen_helper_fmpyfadd_s(a, cpu_env, a, b, c); | |
3572 | + } | |
3573 | + | |
3574 | + tcg_temp_free_i32(b); | |
3575 | + tcg_temp_free_i32(c); | |
3576 | + save_frw_i32(rt, a); | |
3577 | + tcg_temp_free_i32(a); | |
3578 | + return nullify_end(ctx, NO_EXIT); | |
3579 | +} | |
3580 | + | |
3581 | +static ExitStatus trans_fmpyfadd_d(DisasContext *ctx, uint32_t insn, | |
3582 | + const DisasInsn *di) | |
3583 | +{ | |
3584 | + unsigned rt = extract32(insn, 0, 5); | |
3585 | + unsigned neg = extract32(insn, 5, 1); | |
3586 | + unsigned rm1 = extract32(insn, 21, 5); | |
3587 | + unsigned rm2 = extract32(insn, 16, 5); | |
3588 | + unsigned ra3 = assemble_rc64(insn); | |
3589 | + TCGv_i64 a, b, c; | |
3590 | + | |
3591 | + nullify_over(ctx); | |
3592 | + a = load_frd0(rm1); | |
3593 | + b = load_frd0(rm2); | |
3594 | + c = load_frd0(ra3); | |
3595 | + | |
3596 | + if (neg) { | |
3597 | + gen_helper_fmpynfadd_d(a, cpu_env, a, b, c); | |
3598 | + } else { | |
3599 | + gen_helper_fmpyfadd_d(a, cpu_env, a, b, c); | |
3600 | + } | |
3601 | + | |
3602 | + tcg_temp_free_i64(b); | |
3603 | + tcg_temp_free_i64(c); | |
3604 | + save_frd(rt, a); | |
3605 | + tcg_temp_free_i64(a); | |
3606 | + return nullify_end(ctx, NO_EXIT); | |
3607 | +} | |
3608 | + | |
3609 | +static const DisasInsn table_fp_fused[] = { | |
3610 | + { 0xb8000000u, 0xfc000800u, trans_fmpyfadd_s }, | |
3611 | + { 0xb8000800u, 0xfc0019c0u, trans_fmpyfadd_d } | |
3612 | +}; | |
3613 | + | |
2896 | 3614 | static ExitStatus translate_table_int(DisasContext *ctx, uint32_t insn, |
2897 | 3615 | const DisasInsn table[], size_t n) |
2898 | 3616 | { |
@@ -2921,6 +3639,8 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) | ||
2921 | 3639 | return translate_table(ctx, insn, table_arith_log); |
2922 | 3640 | case 0x03: |
2923 | 3641 | return translate_table(ctx, insn, table_index_mem); |
3642 | + case 0x06: | |
3643 | + return trans_fmpyadd(ctx, insn, false); | |
2924 | 3644 | case 0x08: |
2925 | 3645 | return trans_ldil(ctx, insn); |
2926 | 3646 | case 0x09: |
@@ -2929,8 +3649,12 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) | ||
2929 | 3649 | return trans_addil(ctx, insn); |
2930 | 3650 | case 0x0B: |
2931 | 3651 | return trans_copr_dw(ctx, insn); |
3652 | + case 0x0C: | |
3653 | + return translate_table(ctx, insn, table_float_0c); | |
2932 | 3654 | case 0x0D: |
2933 | 3655 | return trans_ldo(ctx, insn); |
3656 | + case 0x0E: | |
3657 | + return translate_table(ctx, insn, table_float_0e); | |
2934 | 3658 | |
2935 | 3659 | case 0x10: |
2936 | 3660 | return trans_load(ctx, insn, false, MO_UB); |
@@ -2969,6 +3693,8 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) | ||
2969 | 3693 | return trans_cmpiclr(ctx, insn); |
2970 | 3694 | case 0x25: |
2971 | 3695 | return trans_subi(ctx, insn); |
3696 | + case 0x26: | |
3697 | + return trans_fmpyadd(ctx, insn, true); | |
2972 | 3698 | case 0x27: |
2973 | 3699 | return trans_cmpb(ctx, insn, true, false, true); |
2974 | 3700 | case 0x28: |
@@ -2982,6 +3708,8 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) | ||
2982 | 3708 | case 0x2C: |
2983 | 3709 | case 0x2D: |
2984 | 3710 | return trans_addi(ctx, insn); |
3711 | + case 0x2E: | |
3712 | + return translate_table(ctx, insn, table_fp_fused); | |
2985 | 3713 | case 0x2F: |
2986 | 3714 | return trans_cmpb(ctx, insn, false, false, true); |
2987 | 3715 |