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