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