• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Commit MetaInfo

Revisiónebe9383caefd56d519e965a5d87bca29f0aeffe3 (tree)
Tiempo2017-01-24 02:52:40
AutorRichard Henderson <rth@twid...>
CommiterRichard Henderson

Log Message

target-hppa: Implement floating-point insns

Signed-off-by: Richard Henderson <rth@twiddle.net>

Cambiar Resumen

Diferencia incremental

--- a/target/hppa/helper.h
+++ b/target/hppa/helper.h
@@ -9,3 +9,58 @@ DEF_HELPER_FLAGS_1(probe_r, TCG_CALL_NO_RWG_SE, tl, tl)
99 DEF_HELPER_FLAGS_1(probe_w, TCG_CALL_NO_RWG_SE, tl, tl)
1010
1111 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)
--- a/target/hppa/op_helper.c
+++ b/target/hppa/op_helper.c
@@ -174,3 +174,397 @@ void cpu_hppa_loaded_fr0(CPUHPPAState *env)
174174 {
175175 helper_loaded_fr0(env);
176176 }
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+}
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -85,6 +85,12 @@ typedef struct DisasInsn {
8585 const struct DisasInsn *f);
8686 union {
8787 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);
8894 };
8995 } DisasInsn;
9096
@@ -295,6 +301,28 @@ static TCGv_i32 load_frw_i32(unsigned rt)
295301 return ret;
296302 }
297303
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+
298326 static void save_frw_i32(unsigned rt, TCGv_i32 val)
299327 {
300328 tcg_gen_st_i32(val, cpu_env,
@@ -312,6 +340,15 @@ static TCGv_i64 load_frd(unsigned rt)
312340 return ret;
313341 }
314342
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+
315352 static void save_frd(unsigned rt, TCGv_i64 val)
316353 {
317354 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)
494531 return x;
495532 }
496533
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+
497563 static target_long assemble_12(uint32_t insn)
498564 {
499565 target_ulong x = -(target_ulong)(insn & 1);
@@ -1218,6 +1284,110 @@ static ExitStatus do_fstored(DisasContext *ctx, unsigned rt, unsigned rb,
12181284 return nullify_end(ctx, NO_EXIT);
12191285 }
12201286
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+
12211391 /* Emit an unconditional branch to a direct target, which may or may not
12221392 have already had nullification handled. */
12231393 static ExitStatus do_dbranch(DisasContext *ctx, target_ulong dest,
@@ -2893,6 +3063,554 @@ static const DisasInsn table_branch[] = {
28933063 { 0xe800d000u, 0xfc00dffcu, trans_bve },
28943064 };
28953065
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+
28963614 static ExitStatus translate_table_int(DisasContext *ctx, uint32_t insn,
28973615 const DisasInsn table[], size_t n)
28983616 {
@@ -2921,6 +3639,8 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
29213639 return translate_table(ctx, insn, table_arith_log);
29223640 case 0x03:
29233641 return translate_table(ctx, insn, table_index_mem);
3642+ case 0x06:
3643+ return trans_fmpyadd(ctx, insn, false);
29243644 case 0x08:
29253645 return trans_ldil(ctx, insn);
29263646 case 0x09:
@@ -2929,8 +3649,12 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
29293649 return trans_addil(ctx, insn);
29303650 case 0x0B:
29313651 return trans_copr_dw(ctx, insn);
3652+ case 0x0C:
3653+ return translate_table(ctx, insn, table_float_0c);
29323654 case 0x0D:
29333655 return trans_ldo(ctx, insn);
3656+ case 0x0E:
3657+ return translate_table(ctx, insn, table_float_0e);
29343658
29353659 case 0x10:
29363660 return trans_load(ctx, insn, false, MO_UB);
@@ -2969,6 +3693,8 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
29693693 return trans_cmpiclr(ctx, insn);
29703694 case 0x25:
29713695 return trans_subi(ctx, insn);
3696+ case 0x26:
3697+ return trans_fmpyadd(ctx, insn, true);
29723698 case 0x27:
29733699 return trans_cmpb(ctx, insn, true, false, true);
29743700 case 0x28:
@@ -2982,6 +3708,8 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
29823708 case 0x2C:
29833709 case 0x2D:
29843710 return trans_addi(ctx, insn);
3711+ case 0x2E:
3712+ return translate_table(ctx, insn, table_fp_fused);
29853713 case 0x2F:
29863714 return trans_cmpb(ctx, insn, false, false, true);
29873715