xref: /openbmc/qemu/target/ppc/translate/fp-impl.c.inc (revision 6a8654d6c215f410cfd5c7dd853e6cf311156b5f)
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);
284
285static void gen_fsqrts(DisasContext *ctx)
286{
287    TCGv_i64 t0;
288    TCGv_i64 t1;
289    if (unlikely(!ctx->fpu_enabled)) {
290        gen_exception(ctx, POWERPC_EXCP_FPU);
291        return;
292    }
293    t0 = tcg_temp_new_i64();
294    t1 = tcg_temp_new_i64();
295    gen_reset_fpstatus();
296    get_fpr(t0, rB(ctx->opcode));
297    gen_helper_fsqrts(t1, cpu_env, t0);
298    set_fpr(rD(ctx->opcode), t1);
299    gen_compute_fprf_float64(t1);
300    if (unlikely(Rc(ctx->opcode) != 0)) {
301        gen_set_cr1_from_fpscr(ctx);
302    }
303    tcg_temp_free_i64(t0);
304    tcg_temp_free_i64(t1);
305}
306
307/***                     Floating-Point multiply-and-add                   ***/
308/* fmadd - fmadds */
309GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT);
310/* fmsub - fmsubs */
311GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT);
312/* fnmadd - fnmadds */
313GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT);
314/* fnmsub - fnmsubs */
315GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT);
316
317/***                     Floating-Point round & convert                    ***/
318/* fctiw */
319GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT);
320/* fctiwu */
321GEN_FLOAT_B(ctiwu, 0x0E, 0x04, 0, PPC2_FP_CVT_ISA206);
322/* fctiwz */
323GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT);
324/* fctiwuz */
325GEN_FLOAT_B(ctiwuz, 0x0F, 0x04, 0, PPC2_FP_CVT_ISA206);
326/* frsp */
327GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT);
328/* fcfid */
329GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC2_FP_CVT_S64);
330/* fcfids */
331GEN_FLOAT_B(cfids, 0x0E, 0x1A, 0, PPC2_FP_CVT_ISA206);
332/* fcfidu */
333GEN_FLOAT_B(cfidu, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206);
334/* fcfidus */
335GEN_FLOAT_B(cfidus, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206);
336/* fctid */
337GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC2_FP_CVT_S64);
338/* fctidu */
339GEN_FLOAT_B(ctidu, 0x0E, 0x1D, 0, PPC2_FP_CVT_ISA206);
340/* fctidz */
341GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC2_FP_CVT_S64);
342/* fctidu */
343GEN_FLOAT_B(ctiduz, 0x0F, 0x1D, 0, PPC2_FP_CVT_ISA206);
344
345/* frin */
346GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT);
347/* friz */
348GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT);
349/* frip */
350GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT);
351/* frim */
352GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT);
353
354static void gen_ftdiv(DisasContext *ctx)
355{
356    TCGv_i64 t0;
357    TCGv_i64 t1;
358    if (unlikely(!ctx->fpu_enabled)) {
359        gen_exception(ctx, POWERPC_EXCP_FPU);
360        return;
361    }
362    t0 = tcg_temp_new_i64();
363    t1 = tcg_temp_new_i64();
364    get_fpr(t0, rA(ctx->opcode));
365    get_fpr(t1, rB(ctx->opcode));
366    gen_helper_ftdiv(cpu_crf[crfD(ctx->opcode)], t0, t1);
367    tcg_temp_free_i64(t0);
368    tcg_temp_free_i64(t1);
369}
370
371static void gen_ftsqrt(DisasContext *ctx)
372{
373    TCGv_i64 t0;
374    if (unlikely(!ctx->fpu_enabled)) {
375        gen_exception(ctx, POWERPC_EXCP_FPU);
376        return;
377    }
378    t0 = tcg_temp_new_i64();
379    get_fpr(t0, rB(ctx->opcode));
380    gen_helper_ftsqrt(cpu_crf[crfD(ctx->opcode)], t0);
381    tcg_temp_free_i64(t0);
382}
383
384
385
386/***                         Floating-Point compare                        ***/
387
388/* fcmpo */
389static void gen_fcmpo(DisasContext *ctx)
390{
391    TCGv_i32 crf;
392    TCGv_i64 t0;
393    TCGv_i64 t1;
394    if (unlikely(!ctx->fpu_enabled)) {
395        gen_exception(ctx, POWERPC_EXCP_FPU);
396        return;
397    }
398    t0 = tcg_temp_new_i64();
399    t1 = tcg_temp_new_i64();
400    gen_reset_fpstatus();
401    crf = tcg_const_i32(crfD(ctx->opcode));
402    get_fpr(t0, rA(ctx->opcode));
403    get_fpr(t1, rB(ctx->opcode));
404    gen_helper_fcmpo(cpu_env, t0, t1, crf);
405    tcg_temp_free_i32(crf);
406    gen_helper_float_check_status(cpu_env);
407    tcg_temp_free_i64(t0);
408    tcg_temp_free_i64(t1);
409}
410
411/* fcmpu */
412static void gen_fcmpu(DisasContext *ctx)
413{
414    TCGv_i32 crf;
415    TCGv_i64 t0;
416    TCGv_i64 t1;
417    if (unlikely(!ctx->fpu_enabled)) {
418        gen_exception(ctx, POWERPC_EXCP_FPU);
419        return;
420    }
421    t0 = tcg_temp_new_i64();
422    t1 = tcg_temp_new_i64();
423    gen_reset_fpstatus();
424    crf = tcg_const_i32(crfD(ctx->opcode));
425    get_fpr(t0, rA(ctx->opcode));
426    get_fpr(t1, rB(ctx->opcode));
427    gen_helper_fcmpu(cpu_env, t0, t1, crf);
428    tcg_temp_free_i32(crf);
429    gen_helper_float_check_status(cpu_env);
430    tcg_temp_free_i64(t0);
431    tcg_temp_free_i64(t1);
432}
433
434/***                         Floating-point move                           ***/
435/* fabs */
436/* XXX: beware that fabs never checks for NaNs nor update FPSCR */
437static void gen_fabs(DisasContext *ctx)
438{
439    TCGv_i64 t0;
440    TCGv_i64 t1;
441    if (unlikely(!ctx->fpu_enabled)) {
442        gen_exception(ctx, POWERPC_EXCP_FPU);
443        return;
444    }
445    t0 = tcg_temp_new_i64();
446    t1 = tcg_temp_new_i64();
447    get_fpr(t0, rB(ctx->opcode));
448    tcg_gen_andi_i64(t1, t0, ~(1ULL << 63));
449    set_fpr(rD(ctx->opcode), t1);
450    if (unlikely(Rc(ctx->opcode))) {
451        gen_set_cr1_from_fpscr(ctx);
452    }
453    tcg_temp_free_i64(t0);
454    tcg_temp_free_i64(t1);
455}
456
457/* fmr  - fmr. */
458/* XXX: beware that fmr never checks for NaNs nor update FPSCR */
459static void gen_fmr(DisasContext *ctx)
460{
461    TCGv_i64 t0;
462    if (unlikely(!ctx->fpu_enabled)) {
463        gen_exception(ctx, POWERPC_EXCP_FPU);
464        return;
465    }
466    t0 = tcg_temp_new_i64();
467    get_fpr(t0, rB(ctx->opcode));
468    set_fpr(rD(ctx->opcode), t0);
469    if (unlikely(Rc(ctx->opcode))) {
470        gen_set_cr1_from_fpscr(ctx);
471    }
472    tcg_temp_free_i64(t0);
473}
474
475/* fnabs */
476/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */
477static void gen_fnabs(DisasContext *ctx)
478{
479    TCGv_i64 t0;
480    TCGv_i64 t1;
481    if (unlikely(!ctx->fpu_enabled)) {
482        gen_exception(ctx, POWERPC_EXCP_FPU);
483        return;
484    }
485    t0 = tcg_temp_new_i64();
486    t1 = tcg_temp_new_i64();
487    get_fpr(t0, rB(ctx->opcode));
488    tcg_gen_ori_i64(t1, t0, 1ULL << 63);
489    set_fpr(rD(ctx->opcode), t1);
490    if (unlikely(Rc(ctx->opcode))) {
491        gen_set_cr1_from_fpscr(ctx);
492    }
493    tcg_temp_free_i64(t0);
494    tcg_temp_free_i64(t1);
495}
496
497/* fneg */
498/* XXX: beware that fneg never checks for NaNs nor update FPSCR */
499static void gen_fneg(DisasContext *ctx)
500{
501    TCGv_i64 t0;
502    TCGv_i64 t1;
503    if (unlikely(!ctx->fpu_enabled)) {
504        gen_exception(ctx, POWERPC_EXCP_FPU);
505        return;
506    }
507    t0 = tcg_temp_new_i64();
508    t1 = tcg_temp_new_i64();
509    get_fpr(t0, rB(ctx->opcode));
510    tcg_gen_xori_i64(t1, t0, 1ULL << 63);
511    set_fpr(rD(ctx->opcode), t1);
512    if (unlikely(Rc(ctx->opcode))) {
513        gen_set_cr1_from_fpscr(ctx);
514    }
515    tcg_temp_free_i64(t0);
516    tcg_temp_free_i64(t1);
517}
518
519/* fcpsgn: PowerPC 2.05 specification */
520/* XXX: beware that fcpsgn never checks for NaNs nor update FPSCR */
521static void gen_fcpsgn(DisasContext *ctx)
522{
523    TCGv_i64 t0;
524    TCGv_i64 t1;
525    TCGv_i64 t2;
526    if (unlikely(!ctx->fpu_enabled)) {
527        gen_exception(ctx, POWERPC_EXCP_FPU);
528        return;
529    }
530    t0 = tcg_temp_new_i64();
531    t1 = tcg_temp_new_i64();
532    t2 = tcg_temp_new_i64();
533    get_fpr(t0, rA(ctx->opcode));
534    get_fpr(t1, rB(ctx->opcode));
535    tcg_gen_deposit_i64(t2, t0, t1, 0, 63);
536    set_fpr(rD(ctx->opcode), t2);
537    if (unlikely(Rc(ctx->opcode))) {
538        gen_set_cr1_from_fpscr(ctx);
539    }
540    tcg_temp_free_i64(t0);
541    tcg_temp_free_i64(t1);
542    tcg_temp_free_i64(t2);
543}
544
545static void gen_fmrgew(DisasContext *ctx)
546{
547    TCGv_i64 b0;
548    TCGv_i64 t0;
549    TCGv_i64 t1;
550    if (unlikely(!ctx->fpu_enabled)) {
551        gen_exception(ctx, POWERPC_EXCP_FPU);
552        return;
553    }
554    b0 = tcg_temp_new_i64();
555    t0 = tcg_temp_new_i64();
556    t1 = tcg_temp_new_i64();
557    get_fpr(t0, rB(ctx->opcode));
558    tcg_gen_shri_i64(b0, t0, 32);
559    get_fpr(t0, rA(ctx->opcode));
560    tcg_gen_deposit_i64(t1, t0, b0, 0, 32);
561    set_fpr(rD(ctx->opcode), t1);
562    tcg_temp_free_i64(b0);
563    tcg_temp_free_i64(t0);
564    tcg_temp_free_i64(t1);
565}
566
567static void gen_fmrgow(DisasContext *ctx)
568{
569    TCGv_i64 t0;
570    TCGv_i64 t1;
571    TCGv_i64 t2;
572    if (unlikely(!ctx->fpu_enabled)) {
573        gen_exception(ctx, POWERPC_EXCP_FPU);
574        return;
575    }
576    t0 = tcg_temp_new_i64();
577    t1 = tcg_temp_new_i64();
578    t2 = tcg_temp_new_i64();
579    get_fpr(t0, rB(ctx->opcode));
580    get_fpr(t1, rA(ctx->opcode));
581    tcg_gen_deposit_i64(t2, t0, t1, 32, 32);
582    set_fpr(rD(ctx->opcode), t2);
583    tcg_temp_free_i64(t0);
584    tcg_temp_free_i64(t1);
585    tcg_temp_free_i64(t2);
586}
587
588/***                  Floating-Point status & ctrl register                ***/
589
590/* mcrfs */
591static void gen_mcrfs(DisasContext *ctx)
592{
593    TCGv tmp = tcg_temp_new();
594    TCGv_i32 tmask;
595    TCGv_i64 tnew_fpscr = tcg_temp_new_i64();
596    int bfa;
597    int nibble;
598    int shift;
599
600    if (unlikely(!ctx->fpu_enabled)) {
601        gen_exception(ctx, POWERPC_EXCP_FPU);
602        return;
603    }
604    bfa = crfS(ctx->opcode);
605    nibble = 7 - bfa;
606    shift = 4 * nibble;
607    tcg_gen_shri_tl(tmp, cpu_fpscr, shift);
608    tcg_gen_trunc_tl_i32(cpu_crf[crfD(ctx->opcode)], tmp);
609    tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)],
610                     0xf);
611    tcg_temp_free(tmp);
612    tcg_gen_extu_tl_i64(tnew_fpscr, cpu_fpscr);
613    /* Only the exception bits (including FX) should be cleared if read */
614    tcg_gen_andi_i64(tnew_fpscr, tnew_fpscr,
615                     ~((0xF << shift) & FP_EX_CLEAR_BITS));
616    /* FEX and VX need to be updated, so don't set fpscr directly */
617    tmask = tcg_const_i32(1 << nibble);
618    gen_helper_store_fpscr(cpu_env, tnew_fpscr, tmask);
619    tcg_temp_free_i32(tmask);
620    tcg_temp_free_i64(tnew_fpscr);
621}
622
623static TCGv_i64 place_from_fpscr(int rt, uint64_t mask)
624{
625    TCGv_i64 fpscr = tcg_temp_new_i64();
626    TCGv_i64 fpscr_masked = tcg_temp_new_i64();
627
628    tcg_gen_extu_tl_i64(fpscr, cpu_fpscr);
629    tcg_gen_andi_i64(fpscr_masked, fpscr, mask);
630    set_fpr(rt, fpscr_masked);
631
632    tcg_temp_free_i64(fpscr_masked);
633
634    return fpscr;
635}
636
637static void store_fpscr_masked(TCGv_i64 fpscr, uint64_t clear_mask,
638                               TCGv_i64 set_mask, uint32_t store_mask)
639{
640    TCGv_i64 fpscr_masked = tcg_temp_new_i64();
641    TCGv_i32 st_mask = tcg_constant_i32(store_mask);
642
643    tcg_gen_andi_i64(fpscr_masked, fpscr, ~clear_mask);
644    tcg_gen_or_i64(fpscr_masked, fpscr_masked, set_mask);
645    gen_helper_store_fpscr(cpu_env, fpscr_masked, st_mask);
646
647    tcg_temp_free_i64(fpscr_masked);
648}
649
650static bool trans_MFFS(DisasContext *ctx, arg_X_t_rc *a)
651{
652    TCGv_i64 fpscr;
653
654    REQUIRE_FPU(ctx);
655
656    gen_reset_fpstatus();
657    fpscr = place_from_fpscr(a->rt, UINT64_MAX);
658    if (a->rc) {
659        gen_set_cr1_from_fpscr(ctx);
660    }
661
662    tcg_temp_free_i64(fpscr);
663
664    return true;
665}
666
667static bool trans_MFFSCE(DisasContext *ctx, arg_X_t *a)
668{
669    TCGv_i64 fpscr;
670
671    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
672    REQUIRE_FPU(ctx);
673
674    gen_reset_fpstatus();
675    fpscr = place_from_fpscr(a->rt, UINT64_MAX);
676    store_fpscr_masked(fpscr, FP_ENABLES, tcg_constant_i64(0), 0x0003);
677
678    tcg_temp_free_i64(fpscr);
679
680    return true;
681}
682
683static bool trans_MFFSCRN(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_RN);
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_RN, t1, 0x0001);
697
698    tcg_temp_free_i64(t1);
699    tcg_temp_free_i64(fpscr);
700
701    return true;
702}
703
704static bool trans_MFFSCDRN(DisasContext *ctx, arg_X_tb *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    get_fpr(t1, a->rb);
713    tcg_gen_andi_i64(t1, t1, FP_DRN);
714
715    gen_reset_fpstatus();
716    fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN);
717    store_fpscr_masked(fpscr, FP_DRN, t1, 0x0100);
718
719    tcg_temp_free_i64(t1);
720    tcg_temp_free_i64(fpscr);
721
722    return true;
723}
724
725static bool trans_MFFSCRNI(DisasContext *ctx, arg_X_imm2 *a)
726{
727    TCGv_i64 t1, fpscr;
728
729    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
730    REQUIRE_FPU(ctx);
731
732    t1 = tcg_temp_new_i64();
733    tcg_gen_movi_i64(t1, a->imm);
734
735    gen_reset_fpstatus();
736    fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN);
737    store_fpscr_masked(fpscr, FP_RN, t1, 0x0001);
738
739    tcg_temp_free_i64(t1);
740    tcg_temp_free_i64(fpscr);
741
742    return true;
743}
744
745static bool trans_MFFSCDRNI(DisasContext *ctx, arg_X_imm3 *a)
746{
747    TCGv_i64 t1, fpscr;
748
749    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
750    REQUIRE_FPU(ctx);
751
752    t1 = tcg_temp_new_i64();
753    tcg_gen_movi_i64(t1, (uint64_t)a->imm << FPSCR_DRN0);
754
755    gen_reset_fpstatus();
756    fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN);
757    store_fpscr_masked(fpscr, FP_DRN, t1, 0x0100);
758
759    tcg_temp_free_i64(t1);
760    tcg_temp_free_i64(fpscr);
761
762    return true;
763}
764
765static bool trans_MFFSL(DisasContext *ctx, arg_X_t *a)
766{
767    TCGv_i64 fpscr;
768
769    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
770    REQUIRE_FPU(ctx);
771
772    gen_reset_fpstatus();
773    fpscr = place_from_fpscr(a->rt,
774        FP_DRN | FP_STATUS | FP_ENABLES | FP_NI | FP_RN);
775
776    tcg_temp_free_i64(fpscr);
777
778    return true;
779}
780
781/* mtfsb0 */
782static void gen_mtfsb0(DisasContext *ctx)
783{
784    uint8_t crb;
785
786    if (unlikely(!ctx->fpu_enabled)) {
787        gen_exception(ctx, POWERPC_EXCP_FPU);
788        return;
789    }
790    crb = 31 - crbD(ctx->opcode);
791    gen_reset_fpstatus();
792    if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) {
793        TCGv_i32 t0;
794        t0 = tcg_const_i32(crb);
795        gen_helper_fpscr_clrbit(cpu_env, t0);
796        tcg_temp_free_i32(t0);
797    }
798    if (unlikely(Rc(ctx->opcode) != 0)) {
799        tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
800        tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
801    }
802}
803
804/* mtfsb1 */
805static void gen_mtfsb1(DisasContext *ctx)
806{
807    uint8_t crb;
808
809    if (unlikely(!ctx->fpu_enabled)) {
810        gen_exception(ctx, POWERPC_EXCP_FPU);
811        return;
812    }
813    crb = 31 - crbD(ctx->opcode);
814    /* XXX: we pretend we can only do IEEE floating-point computations */
815    if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) {
816        TCGv_i32 t0;
817        t0 = tcg_const_i32(crb);
818        gen_helper_fpscr_setbit(cpu_env, t0);
819        tcg_temp_free_i32(t0);
820    }
821    if (unlikely(Rc(ctx->opcode) != 0)) {
822        tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
823        tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
824    }
825    /* We can raise a deferred exception */
826    gen_helper_fpscr_check_status(cpu_env);
827}
828
829/* mtfsf */
830static void gen_mtfsf(DisasContext *ctx)
831{
832    TCGv_i32 t0;
833    TCGv_i64 t1;
834    int flm, l, w;
835
836    if (unlikely(!ctx->fpu_enabled)) {
837        gen_exception(ctx, POWERPC_EXCP_FPU);
838        return;
839    }
840    flm = FPFLM(ctx->opcode);
841    l = FPL(ctx->opcode);
842    w = FPW(ctx->opcode);
843    if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) {
844        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
845        return;
846    }
847    if (l) {
848        t0 = tcg_const_i32((ctx->insns_flags2 & PPC2_ISA205) ? 0xffff : 0xff);
849    } else {
850        t0 = tcg_const_i32(flm << (w * 8));
851    }
852    t1 = tcg_temp_new_i64();
853    get_fpr(t1, rB(ctx->opcode));
854    gen_helper_store_fpscr(cpu_env, t1, t0);
855    tcg_temp_free_i32(t0);
856    if (unlikely(Rc(ctx->opcode) != 0)) {
857        tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
858        tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
859    }
860    /* We can raise a deferred exception */
861    gen_helper_fpscr_check_status(cpu_env);
862    tcg_temp_free_i64(t1);
863}
864
865/* mtfsfi */
866static void gen_mtfsfi(DisasContext *ctx)
867{
868    int bf, sh, w;
869    TCGv_i64 t0;
870    TCGv_i32 t1;
871
872    if (unlikely(!ctx->fpu_enabled)) {
873        gen_exception(ctx, POWERPC_EXCP_FPU);
874        return;
875    }
876    w = FPW(ctx->opcode);
877    bf = FPBF(ctx->opcode);
878    if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) {
879        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
880        return;
881    }
882    sh = (8 * w) + 7 - bf;
883    t0 = tcg_const_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh));
884    t1 = tcg_const_i32(1 << sh);
885    gen_helper_store_fpscr(cpu_env, t0, t1);
886    tcg_temp_free_i64(t0);
887    tcg_temp_free_i32(t1);
888    if (unlikely(Rc(ctx->opcode) != 0)) {
889        tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
890        tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
891    }
892    /* We can raise a deferred exception */
893    gen_helper_fpscr_check_status(cpu_env);
894}
895
896static void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 dest, TCGv addr)
897{
898    TCGv_i32 tmp = tcg_temp_new_i32();
899    tcg_gen_qemu_ld_i32(tmp, addr, ctx->mem_idx, DEF_MEMOP(MO_UL));
900    gen_helper_todouble(dest, tmp);
901    tcg_temp_free_i32(tmp);
902}
903
904/* lfdepx (external PID lfdx) */
905static void gen_lfdepx(DisasContext *ctx)
906{
907    TCGv EA;
908    TCGv_i64 t0;
909    CHK_SV(ctx);
910    if (unlikely(!ctx->fpu_enabled)) {
911        gen_exception(ctx, POWERPC_EXCP_FPU);
912        return;
913    }
914    gen_set_access_type(ctx, ACCESS_FLOAT);
915    EA = tcg_temp_new();
916    t0 = tcg_temp_new_i64();
917    gen_addr_reg_index(ctx, EA);
918    tcg_gen_qemu_ld_i64(t0, EA, PPC_TLB_EPID_LOAD, DEF_MEMOP(MO_UQ));
919    set_fpr(rD(ctx->opcode), t0);
920    tcg_temp_free(EA);
921    tcg_temp_free_i64(t0);
922}
923
924/* lfdp */
925static void gen_lfdp(DisasContext *ctx)
926{
927    TCGv EA;
928    TCGv_i64 t0;
929    if (unlikely(!ctx->fpu_enabled)) {
930        gen_exception(ctx, POWERPC_EXCP_FPU);
931        return;
932    }
933    gen_set_access_type(ctx, ACCESS_FLOAT);
934    EA = tcg_temp_new();
935    gen_addr_imm_index(ctx, EA, 0);
936    t0 = tcg_temp_new_i64();
937    /*
938     * We only need to swap high and low halves. gen_qemu_ld64_i64
939     * does necessary 64-bit byteswap already.
940     */
941    if (unlikely(ctx->le_mode)) {
942        gen_qemu_ld64_i64(ctx, t0, EA);
943        set_fpr(rD(ctx->opcode) + 1, t0);
944        tcg_gen_addi_tl(EA, EA, 8);
945        gen_qemu_ld64_i64(ctx, t0, EA);
946        set_fpr(rD(ctx->opcode), t0);
947    } else {
948        gen_qemu_ld64_i64(ctx, t0, EA);
949        set_fpr(rD(ctx->opcode), t0);
950        tcg_gen_addi_tl(EA, EA, 8);
951        gen_qemu_ld64_i64(ctx, t0, EA);
952        set_fpr(rD(ctx->opcode) + 1, t0);
953    }
954    tcg_temp_free(EA);
955    tcg_temp_free_i64(t0);
956}
957
958/* lfdpx */
959static void gen_lfdpx(DisasContext *ctx)
960{
961    TCGv EA;
962    TCGv_i64 t0;
963    if (unlikely(!ctx->fpu_enabled)) {
964        gen_exception(ctx, POWERPC_EXCP_FPU);
965        return;
966    }
967    gen_set_access_type(ctx, ACCESS_FLOAT);
968    EA = tcg_temp_new();
969    gen_addr_reg_index(ctx, EA);
970    t0 = tcg_temp_new_i64();
971    /*
972     * We only need to swap high and low halves. gen_qemu_ld64_i64
973     * does necessary 64-bit byteswap already.
974     */
975    if (unlikely(ctx->le_mode)) {
976        gen_qemu_ld64_i64(ctx, t0, EA);
977        set_fpr(rD(ctx->opcode) + 1, t0);
978        tcg_gen_addi_tl(EA, EA, 8);
979        gen_qemu_ld64_i64(ctx, t0, EA);
980        set_fpr(rD(ctx->opcode), t0);
981    } else {
982        gen_qemu_ld64_i64(ctx, t0, EA);
983        set_fpr(rD(ctx->opcode), t0);
984        tcg_gen_addi_tl(EA, EA, 8);
985        gen_qemu_ld64_i64(ctx, t0, EA);
986        set_fpr(rD(ctx->opcode) + 1, t0);
987    }
988    tcg_temp_free(EA);
989    tcg_temp_free_i64(t0);
990}
991
992/* lfiwax */
993static void gen_lfiwax(DisasContext *ctx)
994{
995    TCGv EA;
996    TCGv t0;
997    TCGv_i64 t1;
998    if (unlikely(!ctx->fpu_enabled)) {
999        gen_exception(ctx, POWERPC_EXCP_FPU);
1000        return;
1001    }
1002    gen_set_access_type(ctx, ACCESS_FLOAT);
1003    EA = tcg_temp_new();
1004    t0 = tcg_temp_new();
1005    t1 = tcg_temp_new_i64();
1006    gen_addr_reg_index(ctx, EA);
1007    gen_qemu_ld32s(ctx, t0, EA);
1008    tcg_gen_ext_tl_i64(t1, t0);
1009    set_fpr(rD(ctx->opcode), t1);
1010    tcg_temp_free(EA);
1011    tcg_temp_free(t0);
1012    tcg_temp_free_i64(t1);
1013}
1014
1015/* lfiwzx */
1016static void gen_lfiwzx(DisasContext *ctx)
1017{
1018    TCGv EA;
1019    TCGv_i64 t0;
1020    if (unlikely(!ctx->fpu_enabled)) {
1021        gen_exception(ctx, POWERPC_EXCP_FPU);
1022        return;
1023    }
1024    gen_set_access_type(ctx, ACCESS_FLOAT);
1025    EA = tcg_temp_new();
1026    t0 = tcg_temp_new_i64();
1027    gen_addr_reg_index(ctx, EA);
1028    gen_qemu_ld32u_i64(ctx, t0, EA);
1029    set_fpr(rD(ctx->opcode), t0);
1030    tcg_temp_free(EA);
1031    tcg_temp_free_i64(t0);
1032}
1033
1034#define GEN_STXF(name, stop, opc2, opc3, type)                                \
1035static void glue(gen_, name##x)(DisasContext *ctx)                            \
1036{                                                                             \
1037    TCGv EA;                                                                  \
1038    TCGv_i64 t0;                                                              \
1039    if (unlikely(!ctx->fpu_enabled)) {                                        \
1040        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
1041        return;                                                               \
1042    }                                                                         \
1043    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
1044    EA = tcg_temp_new();                                                      \
1045    t0 = tcg_temp_new_i64();                                                  \
1046    gen_addr_reg_index(ctx, EA);                                              \
1047    get_fpr(t0, rS(ctx->opcode));                                             \
1048    gen_qemu_##stop(ctx, t0, EA);                                             \
1049    tcg_temp_free(EA);                                                        \
1050    tcg_temp_free_i64(t0);                                                    \
1051}
1052
1053static void gen_qemu_st32fs(DisasContext *ctx, TCGv_i64 src, TCGv addr)
1054{
1055    TCGv_i32 tmp = tcg_temp_new_i32();
1056    gen_helper_tosingle(tmp, src);
1057    tcg_gen_qemu_st_i32(tmp, addr, ctx->mem_idx, DEF_MEMOP(MO_UL));
1058    tcg_temp_free_i32(tmp);
1059}
1060
1061/* stfdepx (external PID lfdx) */
1062static void gen_stfdepx(DisasContext *ctx)
1063{
1064    TCGv EA;
1065    TCGv_i64 t0;
1066    CHK_SV(ctx);
1067    if (unlikely(!ctx->fpu_enabled)) {
1068        gen_exception(ctx, POWERPC_EXCP_FPU);
1069        return;
1070    }
1071    gen_set_access_type(ctx, ACCESS_FLOAT);
1072    EA = tcg_temp_new();
1073    t0 = tcg_temp_new_i64();
1074    gen_addr_reg_index(ctx, EA);
1075    get_fpr(t0, rD(ctx->opcode));
1076    tcg_gen_qemu_st_i64(t0, EA, PPC_TLB_EPID_STORE, DEF_MEMOP(MO_UQ));
1077    tcg_temp_free(EA);
1078    tcg_temp_free_i64(t0);
1079}
1080
1081/* stfdp */
1082static void gen_stfdp(DisasContext *ctx)
1083{
1084    TCGv EA;
1085    TCGv_i64 t0;
1086    if (unlikely(!ctx->fpu_enabled)) {
1087        gen_exception(ctx, POWERPC_EXCP_FPU);
1088        return;
1089    }
1090    gen_set_access_type(ctx, ACCESS_FLOAT);
1091    EA = tcg_temp_new();
1092    t0 = tcg_temp_new_i64();
1093    gen_addr_imm_index(ctx, EA, 0);
1094    /*
1095     * We only need to swap high and low halves. gen_qemu_st64_i64
1096     * does necessary 64-bit byteswap already.
1097     */
1098    if (unlikely(ctx->le_mode)) {
1099        get_fpr(t0, rD(ctx->opcode) + 1);
1100        gen_qemu_st64_i64(ctx, t0, EA);
1101        tcg_gen_addi_tl(EA, EA, 8);
1102        get_fpr(t0, rD(ctx->opcode));
1103        gen_qemu_st64_i64(ctx, t0, EA);
1104    } else {
1105        get_fpr(t0, rD(ctx->opcode));
1106        gen_qemu_st64_i64(ctx, t0, EA);
1107        tcg_gen_addi_tl(EA, EA, 8);
1108        get_fpr(t0, rD(ctx->opcode) + 1);
1109        gen_qemu_st64_i64(ctx, t0, EA);
1110    }
1111    tcg_temp_free(EA);
1112    tcg_temp_free_i64(t0);
1113}
1114
1115/* stfdpx */
1116static void gen_stfdpx(DisasContext *ctx)
1117{
1118    TCGv EA;
1119    TCGv_i64 t0;
1120    if (unlikely(!ctx->fpu_enabled)) {
1121        gen_exception(ctx, POWERPC_EXCP_FPU);
1122        return;
1123    }
1124    gen_set_access_type(ctx, ACCESS_FLOAT);
1125    EA = tcg_temp_new();
1126    t0 = tcg_temp_new_i64();
1127    gen_addr_reg_index(ctx, EA);
1128    /*
1129     * We only need to swap high and low halves. gen_qemu_st64_i64
1130     * does necessary 64-bit byteswap already.
1131     */
1132    if (unlikely(ctx->le_mode)) {
1133        get_fpr(t0, rD(ctx->opcode) + 1);
1134        gen_qemu_st64_i64(ctx, t0, EA);
1135        tcg_gen_addi_tl(EA, EA, 8);
1136        get_fpr(t0, rD(ctx->opcode));
1137        gen_qemu_st64_i64(ctx, t0, EA);
1138    } else {
1139        get_fpr(t0, rD(ctx->opcode));
1140        gen_qemu_st64_i64(ctx, t0, EA);
1141        tcg_gen_addi_tl(EA, EA, 8);
1142        get_fpr(t0, rD(ctx->opcode) + 1);
1143        gen_qemu_st64_i64(ctx, t0, EA);
1144    }
1145    tcg_temp_free(EA);
1146    tcg_temp_free_i64(t0);
1147}
1148
1149/* Optional: */
1150static inline void gen_qemu_st32fiw(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
1151{
1152    TCGv t0 = tcg_temp_new();
1153    tcg_gen_trunc_i64_tl(t0, arg1),
1154    gen_qemu_st32(ctx, t0, arg2);
1155    tcg_temp_free(t0);
1156}
1157/* stfiwx */
1158GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX);
1159
1160/*            Floating-point Load/Store Instructions                         */
1161static bool do_lsfpsd(DisasContext *ctx, int rt, int ra, TCGv displ,
1162                      bool update, bool store, bool single)
1163{
1164    TCGv ea;
1165    TCGv_i64 t0;
1166    REQUIRE_INSNS_FLAGS(ctx, FLOAT);
1167    REQUIRE_FPU(ctx);
1168    if (update && ra == 0) {
1169        gen_invalid(ctx);
1170        return true;
1171    }
1172    gen_set_access_type(ctx, ACCESS_FLOAT);
1173    t0 = tcg_temp_new_i64();
1174    ea = do_ea_calc(ctx, ra, displ);
1175    if (store) {
1176        get_fpr(t0, rt);
1177        if (single) {
1178            gen_qemu_st32fs(ctx, t0, ea);
1179        } else {
1180            gen_qemu_st64_i64(ctx, t0, ea);
1181        }
1182    } else {
1183        if (single) {
1184            gen_qemu_ld32fs(ctx, t0, ea);
1185        } else {
1186            gen_qemu_ld64_i64(ctx, t0, ea);
1187        }
1188        set_fpr(rt, t0);
1189    }
1190    if (update) {
1191        tcg_gen_mov_tl(cpu_gpr[ra], ea);
1192    }
1193    tcg_temp_free_i64(t0);
1194    tcg_temp_free(ea);
1195    return true;
1196}
1197
1198static bool do_lsfp_D(DisasContext *ctx, arg_D *a, bool update, bool store,
1199                      bool single)
1200{
1201    return do_lsfpsd(ctx, a->rt, a->ra, tcg_constant_tl(a->si), update, store,
1202                     single);
1203}
1204
1205static bool do_lsfp_PLS_D(DisasContext *ctx, arg_PLS_D *a, bool update,
1206                          bool store, bool single)
1207{
1208    arg_D d;
1209    if (!resolve_PLS_D(ctx, &d, a)) {
1210        return true;
1211    }
1212    return do_lsfp_D(ctx, &d, update, store, single);
1213}
1214
1215static bool do_lsfp_X(DisasContext *ctx, arg_X *a, bool update,
1216                      bool store, bool single)
1217{
1218    return do_lsfpsd(ctx, a->rt, a->ra, cpu_gpr[a->rb], update, store, single);
1219}
1220
1221TRANS(LFS, do_lsfp_D, false, false, true)
1222TRANS(LFSU, do_lsfp_D, true, false, true)
1223TRANS(LFSX, do_lsfp_X, false, false, true)
1224TRANS(LFSUX, do_lsfp_X, true, false, true)
1225TRANS(PLFS, do_lsfp_PLS_D, false, false, true)
1226
1227TRANS(LFD, do_lsfp_D, false, false, false)
1228TRANS(LFDU, do_lsfp_D, true, false, false)
1229TRANS(LFDX, do_lsfp_X, false, false, false)
1230TRANS(LFDUX, do_lsfp_X, true, false, false)
1231TRANS(PLFD, do_lsfp_PLS_D, false, false, false)
1232
1233TRANS(STFS, do_lsfp_D, false, true, true)
1234TRANS(STFSU, do_lsfp_D, true, true, true)
1235TRANS(STFSX, do_lsfp_X, false, true, true)
1236TRANS(STFSUX, do_lsfp_X, true, true, true)
1237TRANS(PSTFS, do_lsfp_PLS_D, false, true, true)
1238
1239TRANS(STFD, do_lsfp_D, false, true, false)
1240TRANS(STFDU, do_lsfp_D, true, true, false)
1241TRANS(STFDX, do_lsfp_X, false, true, false)
1242TRANS(STFDUX, do_lsfp_X, true, true, false)
1243TRANS(PSTFD, do_lsfp_PLS_D, false, true, false)
1244
1245#undef _GEN_FLOAT_ACB
1246#undef GEN_FLOAT_ACB
1247#undef _GEN_FLOAT_AB
1248#undef GEN_FLOAT_AB
1249#undef _GEN_FLOAT_AC
1250#undef GEN_FLOAT_AC
1251#undef GEN_FLOAT_B
1252#undef GEN_FLOAT_BS
1253
1254#undef GEN_LDF
1255#undef GEN_LDUF
1256#undef GEN_LDUXF
1257#undef GEN_LDXF
1258#undef GEN_LDFS
1259
1260#undef GEN_STF
1261#undef GEN_STUF
1262#undef GEN_STUXF
1263#undef GEN_STXF
1264#undef GEN_STFS
1265