xref: /qemu/target/ppc/translate/fp-impl.c.inc (revision 8f9abdf5)
1/*
2 * translate-fp.c
3 *
4 * Standard FPU translation
5 */
6
7static inline void gen_reset_fpstatus(void)
8{
9    gen_helper_reset_fpstatus(cpu_env);
10}
11
12static inline void gen_compute_fprf_float64(TCGv_i64 arg)
13{
14    gen_helper_compute_fprf_float64(cpu_env, arg);
15    gen_helper_float_check_status(cpu_env);
16}
17
18#if defined(TARGET_PPC64)
19static void gen_set_cr1_from_fpscr(DisasContext *ctx)
20{
21    TCGv_i32 tmp = tcg_temp_new_i32();
22    tcg_gen_trunc_tl_i32(tmp, cpu_fpscr);
23    tcg_gen_shri_i32(cpu_crf[1], tmp, 28);
24    tcg_temp_free_i32(tmp);
25}
26#else
27static void gen_set_cr1_from_fpscr(DisasContext *ctx)
28{
29    tcg_gen_shri_tl(cpu_crf[1], cpu_fpscr, 28);
30}
31#endif
32
33/***                       Floating-Point arithmetic                       ***/
34#define _GEN_FLOAT_ACB(name, op1, op2, set_fprf, type)                        \
35static void gen_f##name(DisasContext *ctx)                                    \
36{                                                                             \
37    TCGv_i64 t0;                                                              \
38    TCGv_i64 t1;                                                              \
39    TCGv_i64 t2;                                                              \
40    TCGv_i64 t3;                                                              \
41    if (unlikely(!ctx->fpu_enabled)) {                                        \
42        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
43        return;                                                               \
44    }                                                                         \
45    t0 = tcg_temp_new_i64();                                                  \
46    t1 = tcg_temp_new_i64();                                                  \
47    t2 = tcg_temp_new_i64();                                                  \
48    t3 = tcg_temp_new_i64();                                                  \
49    gen_reset_fpstatus();                                                     \
50    get_fpr(t0, rA(ctx->opcode));                                             \
51    get_fpr(t1, rC(ctx->opcode));                                             \
52    get_fpr(t2, rB(ctx->opcode));                                             \
53    gen_helper_f##name(t3, cpu_env, t0, t1, t2);                              \
54    set_fpr(rD(ctx->opcode), t3);                                             \
55    if (set_fprf) {                                                           \
56        gen_compute_fprf_float64(t3);                                         \
57    }                                                                         \
58    if (unlikely(Rc(ctx->opcode) != 0)) {                                     \
59        gen_set_cr1_from_fpscr(ctx);                                          \
60    }                                                                         \
61    tcg_temp_free_i64(t0);                                                    \
62    tcg_temp_free_i64(t1);                                                    \
63    tcg_temp_free_i64(t2);                                                    \
64    tcg_temp_free_i64(t3);                                                    \
65}
66
67#define GEN_FLOAT_ACB(name, op2, set_fprf, type)                              \
68_GEN_FLOAT_ACB(name, 0x3F, op2, set_fprf, type);                              \
69_GEN_FLOAT_ACB(name##s, 0x3B, op2, set_fprf, type);
70
71#define _GEN_FLOAT_AB(name, op1, op2, inval, set_fprf, type)                  \
72static void gen_f##name(DisasContext *ctx)                                    \
73{                                                                             \
74    TCGv_i64 t0;                                                              \
75    TCGv_i64 t1;                                                              \
76    TCGv_i64 t2;                                                              \
77    if (unlikely(!ctx->fpu_enabled)) {                                        \
78        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
79        return;                                                               \
80    }                                                                         \
81    t0 = tcg_temp_new_i64();                                                  \
82    t1 = tcg_temp_new_i64();                                                  \
83    t2 = tcg_temp_new_i64();                                                  \
84    gen_reset_fpstatus();                                                     \
85    get_fpr(t0, rA(ctx->opcode));                                             \
86    get_fpr(t1, rB(ctx->opcode));                                             \
87    gen_helper_f##name(t2, cpu_env, t0, t1);                                  \
88    set_fpr(rD(ctx->opcode), t2);                                             \
89    if (set_fprf) {                                                           \
90        gen_compute_fprf_float64(t2);                                         \
91    }                                                                         \
92    if (unlikely(Rc(ctx->opcode) != 0)) {                                     \
93        gen_set_cr1_from_fpscr(ctx);                                          \
94    }                                                                         \
95    tcg_temp_free_i64(t0);                                                    \
96    tcg_temp_free_i64(t1);                                                    \
97    tcg_temp_free_i64(t2);                                                    \
98}
99#define GEN_FLOAT_AB(name, op2, inval, set_fprf, type)                        \
100_GEN_FLOAT_AB(name, 0x3F, op2, inval, set_fprf, type);                        \
101_GEN_FLOAT_AB(name##s, 0x3B, op2, inval, set_fprf, type);
102
103#define _GEN_FLOAT_AC(name, op1, op2, inval, set_fprf, type)                  \
104static void gen_f##name(DisasContext *ctx)                                    \
105{                                                                             \
106    TCGv_i64 t0;                                                              \
107    TCGv_i64 t1;                                                              \
108    TCGv_i64 t2;                                                              \
109    if (unlikely(!ctx->fpu_enabled)) {                                        \
110        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
111        return;                                                               \
112    }                                                                         \
113    t0 = tcg_temp_new_i64();                                                  \
114    t1 = tcg_temp_new_i64();                                                  \
115    t2 = tcg_temp_new_i64();                                                  \
116    gen_reset_fpstatus();                                                     \
117    get_fpr(t0, rA(ctx->opcode));                                             \
118    get_fpr(t1, rC(ctx->opcode));                                             \
119    gen_helper_f##name(t2, cpu_env, t0, t1);                                  \
120    set_fpr(rD(ctx->opcode), t2);                                             \
121    if (set_fprf) {                                                           \
122        gen_compute_fprf_float64(t2);                                         \
123    }                                                                         \
124    if (unlikely(Rc(ctx->opcode) != 0)) {                                     \
125        gen_set_cr1_from_fpscr(ctx);                                          \
126    }                                                                         \
127    tcg_temp_free_i64(t0);                                                    \
128    tcg_temp_free_i64(t1);                                                    \
129    tcg_temp_free_i64(t2);                                                    \
130}
131#define GEN_FLOAT_AC(name, op2, inval, set_fprf, type)                        \
132_GEN_FLOAT_AC(name, 0x3F, op2, inval, set_fprf, type);                        \
133_GEN_FLOAT_AC(name##s, 0x3B, op2, inval, set_fprf, type);
134
135#define GEN_FLOAT_B(name, op2, op3, set_fprf, type)                           \
136static void gen_f##name(DisasContext *ctx)                                    \
137{                                                                             \
138    TCGv_i64 t0;                                                              \
139    TCGv_i64 t1;                                                              \
140    if (unlikely(!ctx->fpu_enabled)) {                                        \
141        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
142        return;                                                               \
143    }                                                                         \
144    t0 = tcg_temp_new_i64();                                                  \
145    t1 = tcg_temp_new_i64();                                                  \
146    gen_reset_fpstatus();                                                     \
147    get_fpr(t0, rB(ctx->opcode));                                             \
148    gen_helper_f##name(t1, cpu_env, t0);                                      \
149    set_fpr(rD(ctx->opcode), t1);                                             \
150    if (set_fprf) {                                                           \
151        gen_helper_compute_fprf_float64(cpu_env, t1);                         \
152    }                                                                         \
153    gen_helper_float_check_status(cpu_env);                                   \
154    if (unlikely(Rc(ctx->opcode) != 0)) {                                     \
155        gen_set_cr1_from_fpscr(ctx);                                          \
156    }                                                                         \
157    tcg_temp_free_i64(t0);                                                    \
158    tcg_temp_free_i64(t1);                                                    \
159}
160
161#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type)                          \
162static void gen_f##name(DisasContext *ctx)                                    \
163{                                                                             \
164    TCGv_i64 t0;                                                              \
165    TCGv_i64 t1;                                                              \
166    if (unlikely(!ctx->fpu_enabled)) {                                        \
167        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
168        return;                                                               \
169    }                                                                         \
170    t0 = tcg_temp_new_i64();                                                  \
171    t1 = tcg_temp_new_i64();                                                  \
172    gen_reset_fpstatus();                                                     \
173    get_fpr(t0, rB(ctx->opcode));                                             \
174    gen_helper_f##name(t1, cpu_env, t0);                                      \
175    set_fpr(rD(ctx->opcode), t1);                                             \
176    if (set_fprf) {                                                           \
177        gen_compute_fprf_float64(t1);                                         \
178    }                                                                         \
179    if (unlikely(Rc(ctx->opcode) != 0)) {                                     \
180        gen_set_cr1_from_fpscr(ctx);                                          \
181    }                                                                         \
182    tcg_temp_free_i64(t0);                                                    \
183    tcg_temp_free_i64(t1);                                                    \
184}
185
186/* fadd - fadds */
187GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT);
188/* fdiv - fdivs */
189GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT);
190/* fmul - fmuls */
191GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT);
192
193/* fre */
194GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT);
195
196/* fres */
197GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES);
198
199/* frsqrte */
200GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE);
201
202/* frsqrtes */
203static void gen_frsqrtes(DisasContext *ctx)
204{
205    TCGv_i64 t0;
206    TCGv_i64 t1;
207    if (unlikely(!ctx->fpu_enabled)) {
208        gen_exception(ctx, POWERPC_EXCP_FPU);
209        return;
210    }
211    t0 = tcg_temp_new_i64();
212    t1 = tcg_temp_new_i64();
213    gen_reset_fpstatus();
214    get_fpr(t0, rB(ctx->opcode));
215    gen_helper_frsqrtes(t1, cpu_env, t0);
216    set_fpr(rD(ctx->opcode), t1);
217    gen_compute_fprf_float64(t1);
218    if (unlikely(Rc(ctx->opcode) != 0)) {
219        gen_set_cr1_from_fpscr(ctx);
220    }
221    tcg_temp_free_i64(t0);
222    tcg_temp_free_i64(t1);
223}
224
225static bool trans_FSEL(DisasContext *ctx, arg_A *a)
226{
227    TCGv_i64 t0, t1, t2;
228
229    REQUIRE_INSNS_FLAGS(ctx, FLOAT_FSEL);
230    REQUIRE_FPU(ctx);
231
232    t0 = tcg_temp_new_i64();
233    t1 = tcg_temp_new_i64();
234    t2 = tcg_temp_new_i64();
235
236    get_fpr(t0, a->fra);
237    get_fpr(t1, a->frb);
238    get_fpr(t2, a->frc);
239
240    gen_helper_FSEL(t0, t0, t1, t2);
241    set_fpr(a->frt, t0);
242    if (a->rc) {
243        gen_set_cr1_from_fpscr(ctx);
244    }
245
246    tcg_temp_free_i64(t0);
247    tcg_temp_free_i64(t1);
248    tcg_temp_free_i64(t2);
249
250    return true;
251}
252
253/* fsub - fsubs */
254GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT);
255/* Optional: */
256
257static bool do_helper_fsqrt(DisasContext *ctx, arg_A_tb *a,
258                            void (*helper)(TCGv_i64, TCGv_ptr, TCGv_i64))
259{
260    TCGv_i64 t0, t1;
261
262    REQUIRE_INSNS_FLAGS(ctx, FLOAT_FSQRT);
263    REQUIRE_FPU(ctx);
264
265    t0 = tcg_temp_new_i64();
266    t1 = tcg_temp_new_i64();
267
268    gen_reset_fpstatus();
269    get_fpr(t0, a->frb);
270    helper(t1, cpu_env, t0);
271    set_fpr(a->frt, t1);
272    gen_compute_fprf_float64(t1);
273    if (unlikely(a->rc != 0)) {
274        gen_set_cr1_from_fpscr(ctx);
275    }
276
277    tcg_temp_free_i64(t0);
278    tcg_temp_free_i64(t1);
279
280    return true;
281}
282
283TRANS(FSQRT, do_helper_fsqrt, gen_helper_FSQRT);
284TRANS(FSQRTS, do_helper_fsqrt, gen_helper_FSQRTS);
285
286/***                     Floating-Point multiply-and-add                   ***/
287/* fmadd - fmadds */
288GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT);
289/* fmsub - fmsubs */
290GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT);
291/* fnmadd - fnmadds */
292GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT);
293/* fnmsub - fnmsubs */
294GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT);
295
296/***                     Floating-Point round & convert                    ***/
297/* fctiw */
298GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT);
299/* fctiwu */
300GEN_FLOAT_B(ctiwu, 0x0E, 0x04, 0, PPC2_FP_CVT_ISA206);
301/* fctiwz */
302GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT);
303/* fctiwuz */
304GEN_FLOAT_B(ctiwuz, 0x0F, 0x04, 0, PPC2_FP_CVT_ISA206);
305/* frsp */
306GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT);
307/* fcfid */
308GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC2_FP_CVT_S64);
309/* fcfids */
310GEN_FLOAT_B(cfids, 0x0E, 0x1A, 0, PPC2_FP_CVT_ISA206);
311/* fcfidu */
312GEN_FLOAT_B(cfidu, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206);
313/* fcfidus */
314GEN_FLOAT_B(cfidus, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206);
315/* fctid */
316GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC2_FP_CVT_S64);
317/* fctidu */
318GEN_FLOAT_B(ctidu, 0x0E, 0x1D, 0, PPC2_FP_CVT_ISA206);
319/* fctidz */
320GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC2_FP_CVT_S64);
321/* fctidu */
322GEN_FLOAT_B(ctiduz, 0x0F, 0x1D, 0, PPC2_FP_CVT_ISA206);
323
324/* frin */
325GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT);
326/* friz */
327GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT);
328/* frip */
329GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT);
330/* frim */
331GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT);
332
333static void gen_ftdiv(DisasContext *ctx)
334{
335    TCGv_i64 t0;
336    TCGv_i64 t1;
337    if (unlikely(!ctx->fpu_enabled)) {
338        gen_exception(ctx, POWERPC_EXCP_FPU);
339        return;
340    }
341    t0 = tcg_temp_new_i64();
342    t1 = tcg_temp_new_i64();
343    get_fpr(t0, rA(ctx->opcode));
344    get_fpr(t1, rB(ctx->opcode));
345    gen_helper_ftdiv(cpu_crf[crfD(ctx->opcode)], t0, t1);
346    tcg_temp_free_i64(t0);
347    tcg_temp_free_i64(t1);
348}
349
350static void gen_ftsqrt(DisasContext *ctx)
351{
352    TCGv_i64 t0;
353    if (unlikely(!ctx->fpu_enabled)) {
354        gen_exception(ctx, POWERPC_EXCP_FPU);
355        return;
356    }
357    t0 = tcg_temp_new_i64();
358    get_fpr(t0, rB(ctx->opcode));
359    gen_helper_ftsqrt(cpu_crf[crfD(ctx->opcode)], t0);
360    tcg_temp_free_i64(t0);
361}
362
363
364
365/***                         Floating-Point compare                        ***/
366
367/* fcmpo */
368static void gen_fcmpo(DisasContext *ctx)
369{
370    TCGv_i32 crf;
371    TCGv_i64 t0;
372    TCGv_i64 t1;
373    if (unlikely(!ctx->fpu_enabled)) {
374        gen_exception(ctx, POWERPC_EXCP_FPU);
375        return;
376    }
377    t0 = tcg_temp_new_i64();
378    t1 = tcg_temp_new_i64();
379    gen_reset_fpstatus();
380    crf = tcg_const_i32(crfD(ctx->opcode));
381    get_fpr(t0, rA(ctx->opcode));
382    get_fpr(t1, rB(ctx->opcode));
383    gen_helper_fcmpo(cpu_env, t0, t1, crf);
384    tcg_temp_free_i32(crf);
385    gen_helper_float_check_status(cpu_env);
386    tcg_temp_free_i64(t0);
387    tcg_temp_free_i64(t1);
388}
389
390/* fcmpu */
391static void gen_fcmpu(DisasContext *ctx)
392{
393    TCGv_i32 crf;
394    TCGv_i64 t0;
395    TCGv_i64 t1;
396    if (unlikely(!ctx->fpu_enabled)) {
397        gen_exception(ctx, POWERPC_EXCP_FPU);
398        return;
399    }
400    t0 = tcg_temp_new_i64();
401    t1 = tcg_temp_new_i64();
402    gen_reset_fpstatus();
403    crf = tcg_const_i32(crfD(ctx->opcode));
404    get_fpr(t0, rA(ctx->opcode));
405    get_fpr(t1, rB(ctx->opcode));
406    gen_helper_fcmpu(cpu_env, t0, t1, crf);
407    tcg_temp_free_i32(crf);
408    gen_helper_float_check_status(cpu_env);
409    tcg_temp_free_i64(t0);
410    tcg_temp_free_i64(t1);
411}
412
413/***                         Floating-point move                           ***/
414/* fabs */
415/* XXX: beware that fabs never checks for NaNs nor update FPSCR */
416static void gen_fabs(DisasContext *ctx)
417{
418    TCGv_i64 t0;
419    TCGv_i64 t1;
420    if (unlikely(!ctx->fpu_enabled)) {
421        gen_exception(ctx, POWERPC_EXCP_FPU);
422        return;
423    }
424    t0 = tcg_temp_new_i64();
425    t1 = tcg_temp_new_i64();
426    get_fpr(t0, rB(ctx->opcode));
427    tcg_gen_andi_i64(t1, t0, ~(1ULL << 63));
428    set_fpr(rD(ctx->opcode), t1);
429    if (unlikely(Rc(ctx->opcode))) {
430        gen_set_cr1_from_fpscr(ctx);
431    }
432    tcg_temp_free_i64(t0);
433    tcg_temp_free_i64(t1);
434}
435
436/* fmr  - fmr. */
437/* XXX: beware that fmr never checks for NaNs nor update FPSCR */
438static void gen_fmr(DisasContext *ctx)
439{
440    TCGv_i64 t0;
441    if (unlikely(!ctx->fpu_enabled)) {
442        gen_exception(ctx, POWERPC_EXCP_FPU);
443        return;
444    }
445    t0 = tcg_temp_new_i64();
446    get_fpr(t0, rB(ctx->opcode));
447    set_fpr(rD(ctx->opcode), t0);
448    if (unlikely(Rc(ctx->opcode))) {
449        gen_set_cr1_from_fpscr(ctx);
450    }
451    tcg_temp_free_i64(t0);
452}
453
454/* fnabs */
455/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */
456static void gen_fnabs(DisasContext *ctx)
457{
458    TCGv_i64 t0;
459    TCGv_i64 t1;
460    if (unlikely(!ctx->fpu_enabled)) {
461        gen_exception(ctx, POWERPC_EXCP_FPU);
462        return;
463    }
464    t0 = tcg_temp_new_i64();
465    t1 = tcg_temp_new_i64();
466    get_fpr(t0, rB(ctx->opcode));
467    tcg_gen_ori_i64(t1, t0, 1ULL << 63);
468    set_fpr(rD(ctx->opcode), t1);
469    if (unlikely(Rc(ctx->opcode))) {
470        gen_set_cr1_from_fpscr(ctx);
471    }
472    tcg_temp_free_i64(t0);
473    tcg_temp_free_i64(t1);
474}
475
476/* fneg */
477/* XXX: beware that fneg never checks for NaNs nor update FPSCR */
478static void gen_fneg(DisasContext *ctx)
479{
480    TCGv_i64 t0;
481    TCGv_i64 t1;
482    if (unlikely(!ctx->fpu_enabled)) {
483        gen_exception(ctx, POWERPC_EXCP_FPU);
484        return;
485    }
486    t0 = tcg_temp_new_i64();
487    t1 = tcg_temp_new_i64();
488    get_fpr(t0, rB(ctx->opcode));
489    tcg_gen_xori_i64(t1, t0, 1ULL << 63);
490    set_fpr(rD(ctx->opcode), t1);
491    if (unlikely(Rc(ctx->opcode))) {
492        gen_set_cr1_from_fpscr(ctx);
493    }
494    tcg_temp_free_i64(t0);
495    tcg_temp_free_i64(t1);
496}
497
498/* fcpsgn: PowerPC 2.05 specification */
499/* XXX: beware that fcpsgn never checks for NaNs nor update FPSCR */
500static void gen_fcpsgn(DisasContext *ctx)
501{
502    TCGv_i64 t0;
503    TCGv_i64 t1;
504    TCGv_i64 t2;
505    if (unlikely(!ctx->fpu_enabled)) {
506        gen_exception(ctx, POWERPC_EXCP_FPU);
507        return;
508    }
509    t0 = tcg_temp_new_i64();
510    t1 = tcg_temp_new_i64();
511    t2 = tcg_temp_new_i64();
512    get_fpr(t0, rA(ctx->opcode));
513    get_fpr(t1, rB(ctx->opcode));
514    tcg_gen_deposit_i64(t2, t0, t1, 0, 63);
515    set_fpr(rD(ctx->opcode), t2);
516    if (unlikely(Rc(ctx->opcode))) {
517        gen_set_cr1_from_fpscr(ctx);
518    }
519    tcg_temp_free_i64(t0);
520    tcg_temp_free_i64(t1);
521    tcg_temp_free_i64(t2);
522}
523
524static void gen_fmrgew(DisasContext *ctx)
525{
526    TCGv_i64 b0;
527    TCGv_i64 t0;
528    TCGv_i64 t1;
529    if (unlikely(!ctx->fpu_enabled)) {
530        gen_exception(ctx, POWERPC_EXCP_FPU);
531        return;
532    }
533    b0 = tcg_temp_new_i64();
534    t0 = tcg_temp_new_i64();
535    t1 = tcg_temp_new_i64();
536    get_fpr(t0, rB(ctx->opcode));
537    tcg_gen_shri_i64(b0, t0, 32);
538    get_fpr(t0, rA(ctx->opcode));
539    tcg_gen_deposit_i64(t1, t0, b0, 0, 32);
540    set_fpr(rD(ctx->opcode), t1);
541    tcg_temp_free_i64(b0);
542    tcg_temp_free_i64(t0);
543    tcg_temp_free_i64(t1);
544}
545
546static void gen_fmrgow(DisasContext *ctx)
547{
548    TCGv_i64 t0;
549    TCGv_i64 t1;
550    TCGv_i64 t2;
551    if (unlikely(!ctx->fpu_enabled)) {
552        gen_exception(ctx, POWERPC_EXCP_FPU);
553        return;
554    }
555    t0 = tcg_temp_new_i64();
556    t1 = tcg_temp_new_i64();
557    t2 = tcg_temp_new_i64();
558    get_fpr(t0, rB(ctx->opcode));
559    get_fpr(t1, rA(ctx->opcode));
560    tcg_gen_deposit_i64(t2, t0, t1, 32, 32);
561    set_fpr(rD(ctx->opcode), t2);
562    tcg_temp_free_i64(t0);
563    tcg_temp_free_i64(t1);
564    tcg_temp_free_i64(t2);
565}
566
567/***                  Floating-Point status & ctrl register                ***/
568
569/* mcrfs */
570static void gen_mcrfs(DisasContext *ctx)
571{
572    TCGv tmp = tcg_temp_new();
573    TCGv_i32 tmask;
574    TCGv_i64 tnew_fpscr = tcg_temp_new_i64();
575    int bfa;
576    int nibble;
577    int shift;
578
579    if (unlikely(!ctx->fpu_enabled)) {
580        gen_exception(ctx, POWERPC_EXCP_FPU);
581        return;
582    }
583    bfa = crfS(ctx->opcode);
584    nibble = 7 - bfa;
585    shift = 4 * nibble;
586    tcg_gen_shri_tl(tmp, cpu_fpscr, shift);
587    tcg_gen_trunc_tl_i32(cpu_crf[crfD(ctx->opcode)], tmp);
588    tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)],
589                     0xf);
590    tcg_temp_free(tmp);
591    tcg_gen_extu_tl_i64(tnew_fpscr, cpu_fpscr);
592    /* Only the exception bits (including FX) should be cleared if read */
593    tcg_gen_andi_i64(tnew_fpscr, tnew_fpscr,
594                     ~((0xF << shift) & FP_EX_CLEAR_BITS));
595    /* FEX and VX need to be updated, so don't set fpscr directly */
596    tmask = tcg_const_i32(1 << nibble);
597    gen_helper_store_fpscr(cpu_env, tnew_fpscr, tmask);
598    tcg_temp_free_i32(tmask);
599    tcg_temp_free_i64(tnew_fpscr);
600}
601
602static TCGv_i64 place_from_fpscr(int rt, uint64_t mask)
603{
604    TCGv_i64 fpscr = tcg_temp_new_i64();
605    TCGv_i64 fpscr_masked = tcg_temp_new_i64();
606
607    tcg_gen_extu_tl_i64(fpscr, cpu_fpscr);
608    tcg_gen_andi_i64(fpscr_masked, fpscr, mask);
609    set_fpr(rt, fpscr_masked);
610
611    tcg_temp_free_i64(fpscr_masked);
612
613    return fpscr;
614}
615
616static void store_fpscr_masked(TCGv_i64 fpscr, uint64_t clear_mask,
617                               TCGv_i64 set_mask, uint32_t store_mask)
618{
619    TCGv_i64 fpscr_masked = tcg_temp_new_i64();
620    TCGv_i32 st_mask = tcg_constant_i32(store_mask);
621
622    tcg_gen_andi_i64(fpscr_masked, fpscr, ~clear_mask);
623    tcg_gen_or_i64(fpscr_masked, fpscr_masked, set_mask);
624    gen_helper_store_fpscr(cpu_env, fpscr_masked, st_mask);
625
626    tcg_temp_free_i64(fpscr_masked);
627}
628
629static bool trans_MFFS(DisasContext *ctx, arg_X_t_rc *a)
630{
631    TCGv_i64 fpscr;
632
633    REQUIRE_FPU(ctx);
634
635    gen_reset_fpstatus();
636    fpscr = place_from_fpscr(a->rt, UINT64_MAX);
637    if (a->rc) {
638        gen_set_cr1_from_fpscr(ctx);
639    }
640
641    tcg_temp_free_i64(fpscr);
642
643    return true;
644}
645
646static bool trans_MFFSCE(DisasContext *ctx, arg_X_t *a)
647{
648    TCGv_i64 fpscr;
649
650    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
651    REQUIRE_FPU(ctx);
652
653    gen_reset_fpstatus();
654    fpscr = place_from_fpscr(a->rt, UINT64_MAX);
655    store_fpscr_masked(fpscr, FP_ENABLES, tcg_constant_i64(0), 0x0003);
656
657    tcg_temp_free_i64(fpscr);
658
659    return true;
660}
661
662static bool trans_MFFSCRN(DisasContext *ctx, arg_X_tb *a)
663{
664    TCGv_i64 t1, fpscr;
665
666    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
667    REQUIRE_FPU(ctx);
668
669    t1 = tcg_temp_new_i64();
670    get_fpr(t1, a->rb);
671    tcg_gen_andi_i64(t1, t1, FP_RN);
672
673    gen_reset_fpstatus();
674    fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN);
675    store_fpscr_masked(fpscr, FP_RN, t1, 0x0001);
676
677    tcg_temp_free_i64(t1);
678    tcg_temp_free_i64(fpscr);
679
680    return true;
681}
682
683static bool trans_MFFSCDRN(DisasContext *ctx, arg_X_tb *a)
684{
685    TCGv_i64 t1, fpscr;
686
687    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
688    REQUIRE_FPU(ctx);
689
690    t1 = tcg_temp_new_i64();
691    get_fpr(t1, a->rb);
692    tcg_gen_andi_i64(t1, t1, FP_DRN);
693
694    gen_reset_fpstatus();
695    fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN);
696    store_fpscr_masked(fpscr, FP_DRN, t1, 0x0100);
697
698    tcg_temp_free_i64(t1);
699    tcg_temp_free_i64(fpscr);
700
701    return true;
702}
703
704static bool trans_MFFSCRNI(DisasContext *ctx, arg_X_imm2 *a)
705{
706    TCGv_i64 t1, fpscr;
707
708    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
709    REQUIRE_FPU(ctx);
710
711    t1 = tcg_temp_new_i64();
712    tcg_gen_movi_i64(t1, a->imm);
713
714    gen_reset_fpstatus();
715    fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN);
716    store_fpscr_masked(fpscr, FP_RN, t1, 0x0001);
717
718    tcg_temp_free_i64(t1);
719    tcg_temp_free_i64(fpscr);
720
721    return true;
722}
723
724static bool trans_MFFSCDRNI(DisasContext *ctx, arg_X_imm3 *a)
725{
726    TCGv_i64 t1, fpscr;
727
728    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
729    REQUIRE_FPU(ctx);
730
731    t1 = tcg_temp_new_i64();
732    tcg_gen_movi_i64(t1, (uint64_t)a->imm << FPSCR_DRN0);
733
734    gen_reset_fpstatus();
735    fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN);
736    store_fpscr_masked(fpscr, FP_DRN, t1, 0x0100);
737
738    tcg_temp_free_i64(t1);
739    tcg_temp_free_i64(fpscr);
740
741    return true;
742}
743
744static bool trans_MFFSL(DisasContext *ctx, arg_X_t *a)
745{
746    TCGv_i64 fpscr;
747
748    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
749    REQUIRE_FPU(ctx);
750
751    gen_reset_fpstatus();
752    fpscr = place_from_fpscr(a->rt,
753        FP_DRN | FP_STATUS | FP_ENABLES | FP_NI | FP_RN);
754
755    tcg_temp_free_i64(fpscr);
756
757    return true;
758}
759
760/* mtfsb0 */
761static void gen_mtfsb0(DisasContext *ctx)
762{
763    uint8_t crb;
764
765    if (unlikely(!ctx->fpu_enabled)) {
766        gen_exception(ctx, POWERPC_EXCP_FPU);
767        return;
768    }
769    crb = 31 - crbD(ctx->opcode);
770    gen_reset_fpstatus();
771    if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) {
772        TCGv_i32 t0;
773        t0 = tcg_const_i32(crb);
774        gen_helper_fpscr_clrbit(cpu_env, t0);
775        tcg_temp_free_i32(t0);
776    }
777    if (unlikely(Rc(ctx->opcode) != 0)) {
778        tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
779        tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
780    }
781}
782
783/* mtfsb1 */
784static void gen_mtfsb1(DisasContext *ctx)
785{
786    uint8_t crb;
787
788    if (unlikely(!ctx->fpu_enabled)) {
789        gen_exception(ctx, POWERPC_EXCP_FPU);
790        return;
791    }
792    crb = 31 - crbD(ctx->opcode);
793    /* XXX: we pretend we can only do IEEE floating-point computations */
794    if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) {
795        TCGv_i32 t0;
796        t0 = tcg_const_i32(crb);
797        gen_helper_fpscr_setbit(cpu_env, t0);
798        tcg_temp_free_i32(t0);
799    }
800    if (unlikely(Rc(ctx->opcode) != 0)) {
801        tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
802        tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
803    }
804    /* We can raise a deferred exception */
805    gen_helper_fpscr_check_status(cpu_env);
806}
807
808/* mtfsf */
809static void gen_mtfsf(DisasContext *ctx)
810{
811    TCGv_i32 t0;
812    TCGv_i64 t1;
813    int flm, l, w;
814
815    if (unlikely(!ctx->fpu_enabled)) {
816        gen_exception(ctx, POWERPC_EXCP_FPU);
817        return;
818    }
819    flm = FPFLM(ctx->opcode);
820    l = FPL(ctx->opcode);
821    w = FPW(ctx->opcode);
822    if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) {
823        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
824        return;
825    }
826    if (l) {
827        t0 = tcg_const_i32((ctx->insns_flags2 & PPC2_ISA205) ? 0xffff : 0xff);
828    } else {
829        t0 = tcg_const_i32(flm << (w * 8));
830    }
831    t1 = tcg_temp_new_i64();
832    get_fpr(t1, rB(ctx->opcode));
833    gen_helper_store_fpscr(cpu_env, t1, t0);
834    tcg_temp_free_i32(t0);
835    if (unlikely(Rc(ctx->opcode) != 0)) {
836        tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
837        tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
838    }
839    /* We can raise a deferred exception */
840    gen_helper_fpscr_check_status(cpu_env);
841    tcg_temp_free_i64(t1);
842}
843
844/* mtfsfi */
845static void gen_mtfsfi(DisasContext *ctx)
846{
847    int bf, sh, w;
848    TCGv_i64 t0;
849    TCGv_i32 t1;
850
851    if (unlikely(!ctx->fpu_enabled)) {
852        gen_exception(ctx, POWERPC_EXCP_FPU);
853        return;
854    }
855    w = FPW(ctx->opcode);
856    bf = FPBF(ctx->opcode);
857    if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) {
858        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
859        return;
860    }
861    sh = (8 * w) + 7 - bf;
862    t0 = tcg_const_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh));
863    t1 = tcg_const_i32(1 << sh);
864    gen_helper_store_fpscr(cpu_env, t0, t1);
865    tcg_temp_free_i64(t0);
866    tcg_temp_free_i32(t1);
867    if (unlikely(Rc(ctx->opcode) != 0)) {
868        tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
869        tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
870    }
871    /* We can raise a deferred exception */
872    gen_helper_fpscr_check_status(cpu_env);
873}
874
875static void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 dest, TCGv addr)
876{
877    TCGv_i32 tmp = tcg_temp_new_i32();
878    tcg_gen_qemu_ld_i32(tmp, addr, ctx->mem_idx, DEF_MEMOP(MO_UL));
879    gen_helper_todouble(dest, tmp);
880    tcg_temp_free_i32(tmp);
881}
882
883/* lfdepx (external PID lfdx) */
884static void gen_lfdepx(DisasContext *ctx)
885{
886    TCGv EA;
887    TCGv_i64 t0;
888    CHK_SV(ctx);
889    if (unlikely(!ctx->fpu_enabled)) {
890        gen_exception(ctx, POWERPC_EXCP_FPU);
891        return;
892    }
893    gen_set_access_type(ctx, ACCESS_FLOAT);
894    EA = tcg_temp_new();
895    t0 = tcg_temp_new_i64();
896    gen_addr_reg_index(ctx, EA);
897    tcg_gen_qemu_ld_i64(t0, EA, PPC_TLB_EPID_LOAD, DEF_MEMOP(MO_UQ));
898    set_fpr(rD(ctx->opcode), t0);
899    tcg_temp_free(EA);
900    tcg_temp_free_i64(t0);
901}
902
903/* lfdp */
904static void gen_lfdp(DisasContext *ctx)
905{
906    TCGv EA;
907    TCGv_i64 t0;
908    if (unlikely(!ctx->fpu_enabled)) {
909        gen_exception(ctx, POWERPC_EXCP_FPU);
910        return;
911    }
912    gen_set_access_type(ctx, ACCESS_FLOAT);
913    EA = tcg_temp_new();
914    gen_addr_imm_index(ctx, EA, 0);
915    t0 = tcg_temp_new_i64();
916    /*
917     * We only need to swap high and low halves. gen_qemu_ld64_i64
918     * does necessary 64-bit byteswap already.
919     */
920    if (unlikely(ctx->le_mode)) {
921        gen_qemu_ld64_i64(ctx, t0, EA);
922        set_fpr(rD(ctx->opcode) + 1, t0);
923        tcg_gen_addi_tl(EA, EA, 8);
924        gen_qemu_ld64_i64(ctx, t0, EA);
925        set_fpr(rD(ctx->opcode), t0);
926    } else {
927        gen_qemu_ld64_i64(ctx, t0, EA);
928        set_fpr(rD(ctx->opcode), t0);
929        tcg_gen_addi_tl(EA, EA, 8);
930        gen_qemu_ld64_i64(ctx, t0, EA);
931        set_fpr(rD(ctx->opcode) + 1, t0);
932    }
933    tcg_temp_free(EA);
934    tcg_temp_free_i64(t0);
935}
936
937/* lfdpx */
938static void gen_lfdpx(DisasContext *ctx)
939{
940    TCGv EA;
941    TCGv_i64 t0;
942    if (unlikely(!ctx->fpu_enabled)) {
943        gen_exception(ctx, POWERPC_EXCP_FPU);
944        return;
945    }
946    gen_set_access_type(ctx, ACCESS_FLOAT);
947    EA = tcg_temp_new();
948    gen_addr_reg_index(ctx, EA);
949    t0 = tcg_temp_new_i64();
950    /*
951     * We only need to swap high and low halves. gen_qemu_ld64_i64
952     * does necessary 64-bit byteswap already.
953     */
954    if (unlikely(ctx->le_mode)) {
955        gen_qemu_ld64_i64(ctx, t0, EA);
956        set_fpr(rD(ctx->opcode) + 1, t0);
957        tcg_gen_addi_tl(EA, EA, 8);
958        gen_qemu_ld64_i64(ctx, t0, EA);
959        set_fpr(rD(ctx->opcode), t0);
960    } else {
961        gen_qemu_ld64_i64(ctx, t0, EA);
962        set_fpr(rD(ctx->opcode), t0);
963        tcg_gen_addi_tl(EA, EA, 8);
964        gen_qemu_ld64_i64(ctx, t0, EA);
965        set_fpr(rD(ctx->opcode) + 1, t0);
966    }
967    tcg_temp_free(EA);
968    tcg_temp_free_i64(t0);
969}
970
971/* lfiwax */
972static void gen_lfiwax(DisasContext *ctx)
973{
974    TCGv EA;
975    TCGv t0;
976    TCGv_i64 t1;
977    if (unlikely(!ctx->fpu_enabled)) {
978        gen_exception(ctx, POWERPC_EXCP_FPU);
979        return;
980    }
981    gen_set_access_type(ctx, ACCESS_FLOAT);
982    EA = tcg_temp_new();
983    t0 = tcg_temp_new();
984    t1 = tcg_temp_new_i64();
985    gen_addr_reg_index(ctx, EA);
986    gen_qemu_ld32s(ctx, t0, EA);
987    tcg_gen_ext_tl_i64(t1, t0);
988    set_fpr(rD(ctx->opcode), t1);
989    tcg_temp_free(EA);
990    tcg_temp_free(t0);
991    tcg_temp_free_i64(t1);
992}
993
994/* lfiwzx */
995static void gen_lfiwzx(DisasContext *ctx)
996{
997    TCGv EA;
998    TCGv_i64 t0;
999    if (unlikely(!ctx->fpu_enabled)) {
1000        gen_exception(ctx, POWERPC_EXCP_FPU);
1001        return;
1002    }
1003    gen_set_access_type(ctx, ACCESS_FLOAT);
1004    EA = tcg_temp_new();
1005    t0 = tcg_temp_new_i64();
1006    gen_addr_reg_index(ctx, EA);
1007    gen_qemu_ld32u_i64(ctx, t0, EA);
1008    set_fpr(rD(ctx->opcode), t0);
1009    tcg_temp_free(EA);
1010    tcg_temp_free_i64(t0);
1011}
1012
1013#define GEN_STXF(name, stop, opc2, opc3, type)                                \
1014static void glue(gen_, name##x)(DisasContext *ctx)                            \
1015{                                                                             \
1016    TCGv EA;                                                                  \
1017    TCGv_i64 t0;                                                              \
1018    if (unlikely(!ctx->fpu_enabled)) {                                        \
1019        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
1020        return;                                                               \
1021    }                                                                         \
1022    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
1023    EA = tcg_temp_new();                                                      \
1024    t0 = tcg_temp_new_i64();                                                  \
1025    gen_addr_reg_index(ctx, EA);                                              \
1026    get_fpr(t0, rS(ctx->opcode));                                             \
1027    gen_qemu_##stop(ctx, t0, EA);                                             \
1028    tcg_temp_free(EA);                                                        \
1029    tcg_temp_free_i64(t0);                                                    \
1030}
1031
1032static void gen_qemu_st32fs(DisasContext *ctx, TCGv_i64 src, TCGv addr)
1033{
1034    TCGv_i32 tmp = tcg_temp_new_i32();
1035    gen_helper_tosingle(tmp, src);
1036    tcg_gen_qemu_st_i32(tmp, addr, ctx->mem_idx, DEF_MEMOP(MO_UL));
1037    tcg_temp_free_i32(tmp);
1038}
1039
1040/* stfdepx (external PID lfdx) */
1041static void gen_stfdepx(DisasContext *ctx)
1042{
1043    TCGv EA;
1044    TCGv_i64 t0;
1045    CHK_SV(ctx);
1046    if (unlikely(!ctx->fpu_enabled)) {
1047        gen_exception(ctx, POWERPC_EXCP_FPU);
1048        return;
1049    }
1050    gen_set_access_type(ctx, ACCESS_FLOAT);
1051    EA = tcg_temp_new();
1052    t0 = tcg_temp_new_i64();
1053    gen_addr_reg_index(ctx, EA);
1054    get_fpr(t0, rD(ctx->opcode));
1055    tcg_gen_qemu_st_i64(t0, EA, PPC_TLB_EPID_STORE, DEF_MEMOP(MO_UQ));
1056    tcg_temp_free(EA);
1057    tcg_temp_free_i64(t0);
1058}
1059
1060/* stfdp */
1061static void gen_stfdp(DisasContext *ctx)
1062{
1063    TCGv EA;
1064    TCGv_i64 t0;
1065    if (unlikely(!ctx->fpu_enabled)) {
1066        gen_exception(ctx, POWERPC_EXCP_FPU);
1067        return;
1068    }
1069    gen_set_access_type(ctx, ACCESS_FLOAT);
1070    EA = tcg_temp_new();
1071    t0 = tcg_temp_new_i64();
1072    gen_addr_imm_index(ctx, EA, 0);
1073    /*
1074     * We only need to swap high and low halves. gen_qemu_st64_i64
1075     * does necessary 64-bit byteswap already.
1076     */
1077    if (unlikely(ctx->le_mode)) {
1078        get_fpr(t0, rD(ctx->opcode) + 1);
1079        gen_qemu_st64_i64(ctx, t0, EA);
1080        tcg_gen_addi_tl(EA, EA, 8);
1081        get_fpr(t0, rD(ctx->opcode));
1082        gen_qemu_st64_i64(ctx, t0, EA);
1083    } else {
1084        get_fpr(t0, rD(ctx->opcode));
1085        gen_qemu_st64_i64(ctx, t0, EA);
1086        tcg_gen_addi_tl(EA, EA, 8);
1087        get_fpr(t0, rD(ctx->opcode) + 1);
1088        gen_qemu_st64_i64(ctx, t0, EA);
1089    }
1090    tcg_temp_free(EA);
1091    tcg_temp_free_i64(t0);
1092}
1093
1094/* stfdpx */
1095static void gen_stfdpx(DisasContext *ctx)
1096{
1097    TCGv EA;
1098    TCGv_i64 t0;
1099    if (unlikely(!ctx->fpu_enabled)) {
1100        gen_exception(ctx, POWERPC_EXCP_FPU);
1101        return;
1102    }
1103    gen_set_access_type(ctx, ACCESS_FLOAT);
1104    EA = tcg_temp_new();
1105    t0 = tcg_temp_new_i64();
1106    gen_addr_reg_index(ctx, EA);
1107    /*
1108     * We only need to swap high and low halves. gen_qemu_st64_i64
1109     * does necessary 64-bit byteswap already.
1110     */
1111    if (unlikely(ctx->le_mode)) {
1112        get_fpr(t0, rD(ctx->opcode) + 1);
1113        gen_qemu_st64_i64(ctx, t0, EA);
1114        tcg_gen_addi_tl(EA, EA, 8);
1115        get_fpr(t0, rD(ctx->opcode));
1116        gen_qemu_st64_i64(ctx, t0, EA);
1117    } else {
1118        get_fpr(t0, rD(ctx->opcode));
1119        gen_qemu_st64_i64(ctx, t0, EA);
1120        tcg_gen_addi_tl(EA, EA, 8);
1121        get_fpr(t0, rD(ctx->opcode) + 1);
1122        gen_qemu_st64_i64(ctx, t0, EA);
1123    }
1124    tcg_temp_free(EA);
1125    tcg_temp_free_i64(t0);
1126}
1127
1128/* Optional: */
1129static inline void gen_qemu_st32fiw(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
1130{
1131    TCGv t0 = tcg_temp_new();
1132    tcg_gen_trunc_i64_tl(t0, arg1),
1133    gen_qemu_st32(ctx, t0, arg2);
1134    tcg_temp_free(t0);
1135}
1136/* stfiwx */
1137GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX);
1138
1139/*            Floating-point Load/Store Instructions                         */
1140static bool do_lsfpsd(DisasContext *ctx, int rt, int ra, TCGv displ,
1141                      bool update, bool store, bool single)
1142{
1143    TCGv ea;
1144    TCGv_i64 t0;
1145    REQUIRE_INSNS_FLAGS(ctx, FLOAT);
1146    REQUIRE_FPU(ctx);
1147    if (update && ra == 0) {
1148        gen_invalid(ctx);
1149        return true;
1150    }
1151    gen_set_access_type(ctx, ACCESS_FLOAT);
1152    t0 = tcg_temp_new_i64();
1153    ea = do_ea_calc(ctx, ra, displ);
1154    if (store) {
1155        get_fpr(t0, rt);
1156        if (single) {
1157            gen_qemu_st32fs(ctx, t0, ea);
1158        } else {
1159            gen_qemu_st64_i64(ctx, t0, ea);
1160        }
1161    } else {
1162        if (single) {
1163            gen_qemu_ld32fs(ctx, t0, ea);
1164        } else {
1165            gen_qemu_ld64_i64(ctx, t0, ea);
1166        }
1167        set_fpr(rt, t0);
1168    }
1169    if (update) {
1170        tcg_gen_mov_tl(cpu_gpr[ra], ea);
1171    }
1172    tcg_temp_free_i64(t0);
1173    tcg_temp_free(ea);
1174    return true;
1175}
1176
1177static bool do_lsfp_D(DisasContext *ctx, arg_D *a, bool update, bool store,
1178                      bool single)
1179{
1180    return do_lsfpsd(ctx, a->rt, a->ra, tcg_constant_tl(a->si), update, store,
1181                     single);
1182}
1183
1184static bool do_lsfp_PLS_D(DisasContext *ctx, arg_PLS_D *a, bool update,
1185                          bool store, bool single)
1186{
1187    arg_D d;
1188    if (!resolve_PLS_D(ctx, &d, a)) {
1189        return true;
1190    }
1191    return do_lsfp_D(ctx, &d, update, store, single);
1192}
1193
1194static bool do_lsfp_X(DisasContext *ctx, arg_X *a, bool update,
1195                      bool store, bool single)
1196{
1197    return do_lsfpsd(ctx, a->rt, a->ra, cpu_gpr[a->rb], update, store, single);
1198}
1199
1200TRANS(LFS, do_lsfp_D, false, false, true)
1201TRANS(LFSU, do_lsfp_D, true, false, true)
1202TRANS(LFSX, do_lsfp_X, false, false, true)
1203TRANS(LFSUX, do_lsfp_X, true, false, true)
1204TRANS(PLFS, do_lsfp_PLS_D, false, false, true)
1205
1206TRANS(LFD, do_lsfp_D, false, false, false)
1207TRANS(LFDU, do_lsfp_D, true, false, false)
1208TRANS(LFDX, do_lsfp_X, false, false, false)
1209TRANS(LFDUX, do_lsfp_X, true, false, false)
1210TRANS(PLFD, do_lsfp_PLS_D, false, false, false)
1211
1212TRANS(STFS, do_lsfp_D, false, true, true)
1213TRANS(STFSU, do_lsfp_D, true, true, true)
1214TRANS(STFSX, do_lsfp_X, false, true, true)
1215TRANS(STFSUX, do_lsfp_X, true, true, true)
1216TRANS(PSTFS, do_lsfp_PLS_D, false, true, true)
1217
1218TRANS(STFD, do_lsfp_D, false, true, false)
1219TRANS(STFDU, do_lsfp_D, true, true, false)
1220TRANS(STFDX, do_lsfp_X, false, true, false)
1221TRANS(STFDUX, do_lsfp_X, true, true, false)
1222TRANS(PSTFD, do_lsfp_PLS_D, false, true, false)
1223
1224#undef _GEN_FLOAT_ACB
1225#undef GEN_FLOAT_ACB
1226#undef _GEN_FLOAT_AB
1227#undef GEN_FLOAT_AB
1228#undef _GEN_FLOAT_AC
1229#undef GEN_FLOAT_AC
1230#undef GEN_FLOAT_B
1231#undef GEN_FLOAT_BS
1232
1233#undef GEN_LDF
1234#undef GEN_LDUF
1235#undef GEN_LDUXF
1236#undef GEN_LDXF
1237#undef GEN_LDFS
1238
1239#undef GEN_STF
1240#undef GEN_STUF
1241#undef GEN_STUXF
1242#undef GEN_STXF
1243#undef GEN_STFS
1244