master
inc 981 lines 27.7 KB
Raw
1 /*
2 * translate-fp.c
3 *
4 * Standard FPU translation
5 */
6
7 static inline void gen_reset_fpstatus(void)
8 {
9 gen_helper_reset_fpstatus(tcg_env);
10 }
11
12 static inline void gen_compute_fprf_float64(TCGv_i64 arg)
13 {
14 gen_helper_compute_fprf_float64(tcg_env, arg);
15 gen_helper_float_check_status(tcg_env);
16 }
17
18 #if defined(TARGET_PPC64)
19 static 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 }
25 #else
26 static void gen_set_cr1_from_fpscr(DisasContext *ctx)
27 {
28 tcg_gen_shri_tl(cpu_crf[1], cpu_fpscr, 28);
29 }
30 #endif
31
32 /*** Floating-Point arithmetic ***/
33 static bool do_helper_acb(DisasContext *ctx, arg_A *a,
34 void (*helper)(TCGv_i64, TCGv_ptr, TCGv_i64,
35 TCGv_i64, TCGv_i64))
36 {
37 TCGv_i64 t0, t1, t2, t3;
38 REQUIRE_INSNS_FLAGS(ctx, FLOAT);
39 REQUIRE_FPU(ctx);
40 t0 = tcg_temp_new_i64();
41 t1 = tcg_temp_new_i64();
42 t2 = tcg_temp_new_i64();
43 t3 = tcg_temp_new_i64();
44 gen_reset_fpstatus();
45 get_fpr(t0, a->fra);
46 get_fpr(t1, a->frc);
47 get_fpr(t2, a->frb);
48 helper(t3, tcg_env, t0, t1, t2);
49 set_fpr(a->frt, t3);
50 gen_compute_fprf_float64(t3);
51 if (unlikely(a->rc)) {
52 gen_set_cr1_from_fpscr(ctx);
53 }
54 return true;
55 }
56
57 static bool do_helper_ab(DisasContext *ctx, arg_A_tab *a,
58 void (*helper)(TCGv_i64, TCGv_ptr, TCGv_i64,
59 TCGv_i64))
60 {
61 TCGv_i64 t0, t1, t2;
62 REQUIRE_INSNS_FLAGS(ctx, FLOAT);
63 REQUIRE_FPU(ctx);
64 t0 = tcg_temp_new_i64();
65 t1 = tcg_temp_new_i64();
66 t2 = tcg_temp_new_i64();
67 gen_reset_fpstatus();
68 get_fpr(t0, a->fra);
69 get_fpr(t1, a->frb);
70 helper(t2, tcg_env, t0, t1);
71 set_fpr(a->frt, t2);
72 gen_compute_fprf_float64(t2);
73 if (unlikely(a->rc)) {
74 gen_set_cr1_from_fpscr(ctx);
75 }
76 return true;
77 }
78
79 static bool do_helper_ac(DisasContext *ctx, arg_A_tac *a,
80 void (*helper)(TCGv_i64, TCGv_ptr, TCGv_i64,
81 TCGv_i64))
82 {
83 TCGv_i64 t0, t1, t2;
84 REQUIRE_INSNS_FLAGS(ctx, FLOAT);
85 REQUIRE_FPU(ctx);
86 t0 = tcg_temp_new_i64();
87 t1 = tcg_temp_new_i64();
88 t2 = tcg_temp_new_i64();
89 gen_reset_fpstatus();
90 get_fpr(t0, a->fra);
91 get_fpr(t1, a->frc);
92 helper(t2, tcg_env, t0, t1);
93 set_fpr(a->frt, t2);
94 gen_compute_fprf_float64(t2);
95 if (unlikely(a->rc)) {
96 gen_set_cr1_from_fpscr(ctx);
97 }
98 return true;
99 }
100
101 static bool do_round_convert(DisasContext *ctx, arg_X_tb_rc *a,
102 void (*helper)(TCGv_i64, TCGv_env, TCGv_i64),
103 bool set_fprf)
104 {
105 TCGv_i64 t0, t1;
106 REQUIRE_FPU(ctx);
107 t0 = tcg_temp_new_i64();
108 t1 = tcg_temp_new_i64();
109 gen_reset_fpstatus();
110 get_fpr(t0, a->rb);
111 helper(t1, tcg_env, t0);
112 set_fpr(a->rt, t1);
113 if (set_fprf) {
114 gen_helper_compute_fprf_float64(tcg_env, t1);
115 }
116 gen_helper_float_check_status(tcg_env);
117 if (unlikely(a->rc)) {
118 gen_set_cr1_from_fpscr(ctx);
119 }
120 return true;
121 }
122
123 static bool do_helper_bs(DisasContext *ctx, arg_A_tb *a,
124 void (*helper)(TCGv_i64, TCGv_ptr, TCGv_i64))
125 {
126 TCGv_i64 t0, t1;
127 REQUIRE_FPU(ctx);
128 t0 = tcg_temp_new_i64();
129 t1 = tcg_temp_new_i64();
130 gen_reset_fpstatus();
131 get_fpr(t0, a->frb);
132 helper(t1, tcg_env, t0);
133 set_fpr(a->frt, t1);
134 gen_compute_fprf_float64(t1);
135 if (unlikely(a->rc)) {
136 gen_set_cr1_from_fpscr(ctx);
137 }
138 return true;
139 }
140
141 static bool trans_FSEL(DisasContext *ctx, arg_A *a)
142 {
143 TCGv_i64 t0, t1, t2;
144
145 REQUIRE_INSNS_FLAGS(ctx, FLOAT_FSEL);
146 REQUIRE_FPU(ctx);
147
148 t0 = tcg_temp_new_i64();
149 t1 = tcg_temp_new_i64();
150 t2 = tcg_temp_new_i64();
151
152 get_fpr(t0, a->fra);
153 get_fpr(t1, a->frb);
154 get_fpr(t2, a->frc);
155
156 gen_helper_FSEL(t0, t0, t1, t2);
157 set_fpr(a->frt, t0);
158 if (a->rc) {
159 gen_set_cr1_from_fpscr(ctx);
160 }
161 return true;
162 }
163
164 static bool do_helper_fsqrt(DisasContext *ctx, arg_A_tb *a,
165 void (*helper)(TCGv_i64, TCGv_ptr, TCGv_i64))
166 {
167 TCGv_i64 t0, t1;
168
169 REQUIRE_INSNS_FLAGS(ctx, FLOAT_FSQRT);
170 REQUIRE_FPU(ctx);
171
172 t0 = tcg_temp_new_i64();
173 t1 = tcg_temp_new_i64();
174
175 gen_reset_fpstatus();
176 get_fpr(t0, a->frb);
177 helper(t1, tcg_env, t0);
178 set_fpr(a->frt, t1);
179 gen_compute_fprf_float64(t1);
180 if (unlikely(a->rc != 0)) {
181 gen_set_cr1_from_fpscr(ctx);
182 }
183 return true;
184 }
185
186 TRANS(FADD, do_helper_ab, gen_helper_FADD);
187 TRANS(FADDS, do_helper_ab, gen_helper_FADDS);
188 TRANS(FSUB, do_helper_ab, gen_helper_FSUB);
189 TRANS(FSUBS, do_helper_ab, gen_helper_FSUBS);
190 TRANS(FDIV, do_helper_ab, gen_helper_FDIV);
191 TRANS(FDIVS, do_helper_ab, gen_helper_FDIVS);
192 TRANS(FMUL, do_helper_ac, gen_helper_FMUL);
193 TRANS(FMULS, do_helper_ac, gen_helper_FMULS);
194
195 TRANS(FMADD, do_helper_acb, gen_helper_FMADD);
196 TRANS(FMADDS, do_helper_acb, gen_helper_FMADDS);
197 TRANS(FMSUB, do_helper_acb, gen_helper_FMSUB);
198 TRANS(FMSUBS, do_helper_acb, gen_helper_FMSUBS);
199
200 TRANS(FNMADD, do_helper_acb, gen_helper_FNMADD);
201 TRANS(FNMADDS, do_helper_acb, gen_helper_FNMADDS);
202 TRANS(FNMSUB, do_helper_acb, gen_helper_FNMSUB);
203 TRANS(FNMSUBS, do_helper_acb, gen_helper_FNMSUBS);
204
205 TRANS_FLAGS(FLOAT_EXT, FRE, do_helper_bs, gen_helper_FRE);
206 TRANS_FLAGS(FLOAT_FRES, FRES, do_helper_bs, gen_helper_FRES);
207 TRANS_FLAGS(FLOAT_FRSQRTE, FRSQRTE, do_helper_bs, gen_helper_FRSQRTE);
208 TRANS_FLAGS(FLOAT_FRSQRTES, FRSQRTES, do_helper_bs, gen_helper_FRSQRTES);
209
210 TRANS(FSQRT, do_helper_fsqrt, gen_helper_FSQRT);
211 TRANS(FSQRTS, do_helper_fsqrt, gen_helper_FSQRTS);
212
213 /*** Floating-Point round & convert ***/
214 TRANS_FLAGS(FLOAT, FRSP, do_round_convert, gen_helper_FRSP, true);
215 TRANS_FLAGS(FLOAT_EXT, FRIN, do_round_convert, gen_helper_FRIN, true);
216 TRANS_FLAGS(FLOAT_EXT, FRIZ, do_round_convert, gen_helper_FRIZ, true);
217 TRANS_FLAGS(FLOAT_EXT, FRIP, do_round_convert, gen_helper_FRIP, true);
218 TRANS_FLAGS(FLOAT_EXT, FRIM, do_round_convert, gen_helper_FRIM, true);
219
220 TRANS_FLAGS(FLOAT, FCTIW, do_round_convert, gen_helper_FCTIW, false);
221 TRANS_FLAGS2(FP_CVT_ISA206, FCTIWU, do_round_convert, gen_helper_FCTIWU, false);
222 TRANS_FLAGS(FLOAT, FCTIWZ, do_round_convert, gen_helper_FCTIWZ, false);
223 TRANS_FLAGS2(FP_CVT_ISA206, FCTIWUZ, do_round_convert, gen_helper_FCTIWUZ, false);
224
225 TRANS_FLAGS2(FP_CVT_S64, FCTID, do_round_convert, gen_helper_FCTID, false);
226 TRANS_FLAGS2(FP_CVT_ISA206, FCTIDU, do_round_convert, gen_helper_FCTIDU, false);
227 TRANS_FLAGS2(FP_CVT_S64, FCTIDZ, do_round_convert, gen_helper_FCTIDZ, false);
228 TRANS_FLAGS2(FP_CVT_ISA206, FCTIDUZ, do_round_convert, gen_helper_FCTIDUZ, false);
229
230 TRANS_FLAGS2(FP_CVT_S64, FCFID, do_round_convert, gen_helper_FCFID, true);
231 TRANS_FLAGS2(FP_CVT_ISA206, FCFIDS, do_round_convert, gen_helper_FCFIDS, false);
232 TRANS_FLAGS2(FP_CVT_ISA206, FCFIDU, do_round_convert, gen_helper_FCFIDU, false);
233 TRANS_FLAGS2(FP_CVT_ISA206, FCFIDUS, do_round_convert, gen_helper_FCFIDUS, false);
234
235 static bool trans_FTDIV(DisasContext *ctx, arg_X_bf *a)
236 {
237 TCGv_i64 t0, t1;
238 REQUIRE_INSNS_FLAGS2(ctx, FP_TST_ISA206);
239 REQUIRE_FPU(ctx);
240 t0 = tcg_temp_new_i64();
241 t1 = tcg_temp_new_i64();
242 get_fpr(t0, a->ra);
243 get_fpr(t1, a->rb);
244 gen_helper_FTDIV(cpu_crf[a->bf], t0, t1);
245 return true;
246 }
247
248 static bool trans_FTSQRT(DisasContext *ctx, arg_X_bf_b *a)
249 {
250 TCGv_i64 t0;
251 REQUIRE_INSNS_FLAGS2(ctx, FP_TST_ISA206);
252 REQUIRE_FPU(ctx);
253 t0 = tcg_temp_new_i64();
254 get_fpr(t0, a->rb);
255 gen_helper_FTSQRT(cpu_crf[a->bf], t0);
256 return true;
257 }
258
259 /*** Floating-Point compare ***/
260 static bool do_helper_cmp(DisasContext *ctx, arg_X_bf *a,
261 void (*helper)(TCGv_env, TCGv_i64, TCGv_i64,
262 TCGv_i32))
263 {
264 TCGv_i32 crf;
265 TCGv_i64 t0, t1;
266 REQUIRE_INSNS_FLAGS(ctx, FLOAT);
267 REQUIRE_FPU(ctx);
268 t0 = tcg_temp_new_i64();
269 t1 = tcg_temp_new_i64();
270 gen_reset_fpstatus();
271 crf = tcg_constant_i32(a->bf);
272 get_fpr(t0, a->ra);
273 get_fpr(t1, a->rb);
274 helper(tcg_env, t0, t1, crf);
275 gen_helper_float_check_status(tcg_env);
276 return true;
277 }
278
279 TRANS(FCMPU, do_helper_cmp, gen_helper_FCMPU);
280 TRANS(FCMPO, do_helper_cmp, gen_helper_FCMPO);
281
282 /*** Floating-point move ***/
283
284 /* fmr - fmr. */
285 /* XXX: beware that fmr never checks for NaNs nor update FPSCR */
286 static bool trans_FMR(DisasContext *ctx, arg_FMR *a)
287 {
288 TCGv_i64 t0;
289 REQUIRE_INSNS_FLAGS(ctx, FLOAT);
290 REQUIRE_FPU(ctx);
291 t0 = tcg_temp_new_i64();
292 get_fpr(t0, a->rb);
293 set_fpr(a->rt, t0);
294 if (unlikely(a->rc)) {
295 gen_set_cr1_from_fpscr(ctx);
296 }
297 return true;
298 }
299
300 /* XXX: beware that f{neg, abs, nabs} never checks for NaNs nor update FPSCR */
301 static bool do_move_b(DisasContext *ctx, arg_X_tb_rc *a, int64_t val,
302 void (*tcg_op)(TCGv_i64, TCGv_i64, int64_t))
303 {
304 TCGv_i64 t0, t1;
305 REQUIRE_INSNS_FLAGS(ctx, FLOAT);
306 REQUIRE_FPU(ctx);
307 t0 = tcg_temp_new_i64();
308 t1 = tcg_temp_new_i64();
309 get_fpr(t0, a->rb);
310 tcg_op(t1, t0, val);
311 set_fpr(a->rt, t1);
312 if (unlikely(a->rc)) {
313 gen_set_cr1_from_fpscr(ctx);
314 }
315 return true;
316 }
317
318 TRANS(FNEG, do_move_b, 1ULL << 63, tcg_gen_xori_i64);
319 TRANS(FABS, do_move_b, ~(1ULL << 63), tcg_gen_andi_i64);
320 TRANS(FNABS, do_move_b, 1ULL << 63, tcg_gen_ori_i64);
321
322 /* fcpsgn: PowerPC 2.05 specification */
323 /* XXX: beware that fcpsgn never checks for NaNs nor update FPSCR */
324 static bool trans_FCPSGN(DisasContext *ctx, arg_FCPSGN *a)
325 {
326 TCGv_i64 t0, t1, t2;
327 REQUIRE_INSNS_FLAGS2(ctx, ISA205);
328 REQUIRE_FPU(ctx);
329 t0 = tcg_temp_new_i64();
330 t1 = tcg_temp_new_i64();
331 t2 = tcg_temp_new_i64();
332 get_fpr(t0, a->ra);
333 get_fpr(t1, a->rb);
334 tcg_gen_deposit_i64(t2, t0, t1, 0, 63);
335 set_fpr(a->rt, t2);
336 if (unlikely(a->rc)) {
337 gen_set_cr1_from_fpscr(ctx);
338 }
339 return true;
340 }
341
342 static bool trans_FMRGEW(DisasContext *ctx, arg_FMRGEW *a)
343 {
344 TCGv_i64 t0, t1, t2;
345 REQUIRE_INSNS_FLAGS2(ctx, ISA207);
346 REQUIRE_FPU(ctx);
347 t0 = tcg_temp_new_i64();
348 t1 = tcg_temp_new_i64();
349 t2 = tcg_temp_new_i64();
350 get_fpr(t1, a->rb);
351 tcg_gen_shri_i64(t0, t1, 32);
352 get_fpr(t1, a->ra);
353 tcg_gen_deposit_i64(t2, t1, t0, 0, 32);
354 set_fpr(a->rt, t2);
355 return true;
356 }
357
358 static bool trans_FMRGOW(DisasContext *ctx, arg_FMRGOW *a)
359 {
360 TCGv_i64 t0, t1, t2;
361 REQUIRE_INSNS_FLAGS2(ctx, ISA207);
362 REQUIRE_FPU(ctx);
363 t0 = tcg_temp_new_i64();
364 t1 = tcg_temp_new_i64();
365 t2 = tcg_temp_new_i64();
366 get_fpr(t0, a->rb);
367 get_fpr(t1, a->ra);
368 tcg_gen_deposit_i64(t2, t0, t1, 32, 32);
369 set_fpr(a->rt, t2);
370 return true;
371 }
372
373 /*** Floating-Point status & ctrl register ***/
374
375 /* mcrfs */
376 static void gen_mcrfs(DisasContext *ctx)
377 {
378 TCGv tmp = tcg_temp_new();
379 TCGv_i32 tmask;
380 TCGv_i64 tnew_fpscr = tcg_temp_new_i64();
381 int bfa;
382 int nibble;
383 int shift;
384
385 if (unlikely(!ctx->fpu_enabled)) {
386 gen_exception(ctx, POWERPC_EXCP_FPU);
387 return;
388 }
389 bfa = crfS(ctx->opcode);
390 nibble = 7 - bfa;
391 shift = 4 * nibble;
392 tcg_gen_shri_tl(tmp, cpu_fpscr, shift);
393 tcg_gen_trunc_tl_i32(cpu_crf[crfD(ctx->opcode)], tmp);
394 tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)],
395 0xf);
396 tcg_gen_extu_tl_i64(tnew_fpscr, cpu_fpscr);
397 /* Only the exception bits (including FX) should be cleared if read */
398 tcg_gen_andi_i64(tnew_fpscr, tnew_fpscr,
399 ~(MAKE_64BIT_MASK(shift, 4) & FP_EX_CLEAR_BITS));
400 /* FEX and VX need to be updated, so don't set fpscr directly */
401 tmask = tcg_constant_i32(1 << nibble);
402 gen_helper_store_fpscr(tcg_env, tnew_fpscr, tmask);
403 }
404
405 static TCGv_i64 place_from_fpscr(int rt, uint64_t mask)
406 {
407 TCGv_i64 fpscr = tcg_temp_new_i64();
408 TCGv_i64 fpscr_masked = tcg_temp_new_i64();
409
410 tcg_gen_extu_tl_i64(fpscr, cpu_fpscr);
411 tcg_gen_andi_i64(fpscr_masked, fpscr, mask);
412 set_fpr(rt, fpscr_masked);
413
414 return fpscr;
415 }
416
417 static void store_fpscr_masked(TCGv_i64 fpscr, uint64_t clear_mask,
418 TCGv_i64 set_mask, uint32_t store_mask)
419 {
420 TCGv_i64 fpscr_masked = tcg_temp_new_i64();
421 TCGv_i32 st_mask = tcg_constant_i32(store_mask);
422
423 tcg_gen_andi_i64(fpscr_masked, fpscr, ~clear_mask);
424 tcg_gen_or_i64(fpscr_masked, fpscr_masked, set_mask);
425 gen_helper_store_fpscr(tcg_env, fpscr_masked, st_mask);
426 }
427
428 static bool trans_MFFS_ISA207(DisasContext *ctx, arg_X_t_rc *a)
429 {
430 if (!(ctx->insns_flags2 & PPC2_ISA300)) {
431 /*
432 * Before Power ISA v3.0, MFFS bits 11~15 were reserved, any instruction
433 * with OPCD=63 and XO=583 should be decoded as MFFS.
434 */
435 return trans_MFFS(ctx, a);
436 }
437 /*
438 * For Power ISA v3.0+, return false and let the pattern group
439 * select the correct instruction.
440 */
441 return false;
442 }
443
444 static bool trans_MFFS(DisasContext *ctx, arg_X_t_rc *a)
445 {
446 REQUIRE_FPU(ctx);
447
448 gen_reset_fpstatus();
449 place_from_fpscr(a->rt, UINT64_MAX);
450 if (a->rc) {
451 gen_set_cr1_from_fpscr(ctx);
452 }
453 return true;
454 }
455
456 static bool trans_MFFSCE(DisasContext *ctx, arg_X_t *a)
457 {
458 TCGv_i64 fpscr;
459
460 REQUIRE_FPU(ctx);
461
462 gen_reset_fpstatus();
463 fpscr = place_from_fpscr(a->rt, UINT64_MAX);
464 store_fpscr_masked(fpscr, FP_ENABLES, tcg_constant_i64(0), 0x0003);
465 return true;
466 }
467
468 static bool trans_MFFSCRN(DisasContext *ctx, arg_X_tb *a)
469 {
470 TCGv_i64 t1, fpscr;
471
472 REQUIRE_FPU(ctx);
473
474 t1 = tcg_temp_new_i64();
475 get_fpr(t1, a->rb);
476 tcg_gen_andi_i64(t1, t1, FP_RN);
477
478 gen_reset_fpstatus();
479 fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN);
480 store_fpscr_masked(fpscr, FP_RN, t1, 0x0001);
481 return true;
482 }
483
484 static bool trans_MFFSCDRN(DisasContext *ctx, arg_X_tb *a)
485 {
486 TCGv_i64 t1, fpscr;
487
488 REQUIRE_FPU(ctx);
489
490 t1 = tcg_temp_new_i64();
491 get_fpr(t1, a->rb);
492 tcg_gen_andi_i64(t1, t1, FP_DRN);
493
494 gen_reset_fpstatus();
495 fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN);
496 store_fpscr_masked(fpscr, FP_DRN, t1, 0x0100);
497 return true;
498 }
499
500 static bool trans_MFFSCRNI(DisasContext *ctx, arg_X_imm2 *a)
501 {
502 TCGv_i64 t1, fpscr;
503
504 REQUIRE_FPU(ctx);
505
506 t1 = tcg_temp_new_i64();
507 tcg_gen_movi_i64(t1, a->imm);
508
509 gen_reset_fpstatus();
510 fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN);
511 store_fpscr_masked(fpscr, FP_RN, t1, 0x0001);
512 return true;
513 }
514
515 static bool trans_MFFSCDRNI(DisasContext *ctx, arg_X_imm3 *a)
516 {
517 TCGv_i64 t1, fpscr;
518
519 REQUIRE_FPU(ctx);
520
521 t1 = tcg_temp_new_i64();
522 tcg_gen_movi_i64(t1, (uint64_t)a->imm << FPSCR_DRN0);
523
524 gen_reset_fpstatus();
525 fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN);
526 store_fpscr_masked(fpscr, FP_DRN, t1, 0x0100);
527 return true;
528 }
529
530 static bool trans_MFFSL(DisasContext *ctx, arg_X_t *a)
531 {
532 REQUIRE_FPU(ctx);
533
534 gen_reset_fpstatus();
535 place_from_fpscr(a->rt, FP_DRN | FP_STATUS | FP_ENABLES | FP_NI | FP_RN);
536 return true;
537 }
538
539 /* mtfsb0 */
540 static void gen_mtfsb0(DisasContext *ctx)
541 {
542 uint8_t crb;
543
544 if (unlikely(!ctx->fpu_enabled)) {
545 gen_exception(ctx, POWERPC_EXCP_FPU);
546 return;
547 }
548 crb = 31 - crbD(ctx->opcode);
549 gen_reset_fpstatus();
550 if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) {
551 gen_helper_fpscr_clrbit(tcg_env, tcg_constant_i32(crb));
552 }
553 if (unlikely(Rc(ctx->opcode) != 0)) {
554 tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
555 tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
556 }
557 }
558
559 /* mtfsb1 */
560 static void gen_mtfsb1(DisasContext *ctx)
561 {
562 uint8_t crb;
563
564 if (unlikely(!ctx->fpu_enabled)) {
565 gen_exception(ctx, POWERPC_EXCP_FPU);
566 return;
567 }
568 crb = 31 - crbD(ctx->opcode);
569 /* XXX: we pretend we can only do IEEE floating-point computations */
570 if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) {
571 gen_helper_fpscr_setbit(tcg_env, tcg_constant_i32(crb));
572 }
573 if (unlikely(Rc(ctx->opcode) != 0)) {
574 tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
575 tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
576 }
577 /* We can raise a deferred exception */
578 gen_helper_fpscr_check_status(tcg_env);
579 }
580
581 /* mtfsf */
582 static void gen_mtfsf(DisasContext *ctx)
583 {
584 TCGv_i32 t0;
585 TCGv_i64 t1;
586 int flm, l, w;
587
588 if (unlikely(!ctx->fpu_enabled)) {
589 gen_exception(ctx, POWERPC_EXCP_FPU);
590 return;
591 }
592 flm = FPFLM(ctx->opcode);
593 l = FPL(ctx->opcode);
594 w = FPW(ctx->opcode);
595 if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) {
596 gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
597 return;
598 }
599 if (!l) {
600 t0 = tcg_constant_i32(flm << (w * 8));
601 } else if (ctx->insns_flags2 & PPC2_ISA205) {
602 t0 = tcg_constant_i32(0xffff);
603 } else {
604 t0 = tcg_constant_i32(0xff);
605 }
606 t1 = tcg_temp_new_i64();
607 get_fpr(t1, rB(ctx->opcode));
608 gen_helper_store_fpscr(tcg_env, t1, t0);
609 if (unlikely(Rc(ctx->opcode) != 0)) {
610 tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
611 tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
612 }
613 /* We can raise a deferred exception */
614 gen_helper_fpscr_check_status(tcg_env);
615 }
616
617 /* mtfsfi */
618 static void gen_mtfsfi(DisasContext *ctx)
619 {
620 int bf, sh, w;
621 TCGv_i64 t0;
622 TCGv_i32 t1;
623
624 if (unlikely(!ctx->fpu_enabled)) {
625 gen_exception(ctx, POWERPC_EXCP_FPU);
626 return;
627 }
628 w = FPW(ctx->opcode);
629 bf = FPBF(ctx->opcode);
630 if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) {
631 gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
632 return;
633 }
634 sh = (8 * w) + 7 - bf;
635 t0 = tcg_constant_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh));
636 t1 = tcg_constant_i32(1 << sh);
637 gen_helper_store_fpscr(tcg_env, t0, t1);
638 if (unlikely(Rc(ctx->opcode) != 0)) {
639 tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr);
640 tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX);
641 }
642 /* We can raise a deferred exception */
643 gen_helper_fpscr_check_status(tcg_env);
644 }
645
646 static void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 dest, TCGv addr)
647 {
648 TCGv_i32 tmp = tcg_temp_new_i32();
649 tcg_gen_qemu_ld_i32(tmp, addr, ctx->mem_idx, DEF_MEMOP(MO_UL));
650 gen_helper_todouble(dest, tmp);
651 }
652
653 /* lfdepx (external PID lfdx) */
654 static void gen_lfdepx(DisasContext *ctx)
655 {
656 TCGv EA;
657 TCGv_i64 t0;
658 CHK_SV(ctx);
659 if (unlikely(!ctx->fpu_enabled)) {
660 gen_exception(ctx, POWERPC_EXCP_FPU);
661 return;
662 }
663 gen_set_access_type(ctx, ACCESS_FLOAT);
664 EA = tcg_temp_new();
665 t0 = tcg_temp_new_i64();
666 gen_addr_reg_index(ctx, EA);
667 tcg_gen_qemu_ld_i64(t0, EA, PPC_TLB_EPID_LOAD, DEF_MEMOP(MO_UQ));
668 set_fpr(rD(ctx->opcode), t0);
669 }
670
671 /* lfdp */
672 static void gen_lfdp(DisasContext *ctx)
673 {
674 TCGv EA;
675 TCGv_i64 t0;
676 if (unlikely(!ctx->fpu_enabled)) {
677 gen_exception(ctx, POWERPC_EXCP_FPU);
678 return;
679 }
680 gen_set_access_type(ctx, ACCESS_FLOAT);
681 EA = tcg_temp_new();
682 gen_addr_imm_index(ctx, EA, 0);
683 t0 = tcg_temp_new_i64();
684 /*
685 * We only need to swap high and low halves. gen_qemu_ld64_i64
686 * does necessary 64-bit byteswap already.
687 */
688 if (unlikely(ctx->le_mode)) {
689 gen_qemu_ld64_i64(ctx, t0, EA);
690 set_fpr(rD(ctx->opcode) + 1, t0);
691 tcg_gen_addi_tl(EA, EA, 8);
692 gen_qemu_ld64_i64(ctx, t0, EA);
693 set_fpr(rD(ctx->opcode), t0);
694 } else {
695 gen_qemu_ld64_i64(ctx, t0, EA);
696 set_fpr(rD(ctx->opcode), t0);
697 tcg_gen_addi_tl(EA, EA, 8);
698 gen_qemu_ld64_i64(ctx, t0, EA);
699 set_fpr(rD(ctx->opcode) + 1, t0);
700 }
701 }
702
703 /* lfdpx */
704 static void gen_lfdpx(DisasContext *ctx)
705 {
706 TCGv EA;
707 TCGv_i64 t0;
708 if (unlikely(!ctx->fpu_enabled)) {
709 gen_exception(ctx, POWERPC_EXCP_FPU);
710 return;
711 }
712 gen_set_access_type(ctx, ACCESS_FLOAT);
713 EA = tcg_temp_new();
714 gen_addr_reg_index(ctx, EA);
715 t0 = tcg_temp_new_i64();
716 /*
717 * We only need to swap high and low halves. gen_qemu_ld64_i64
718 * does necessary 64-bit byteswap already.
719 */
720 if (unlikely(ctx->le_mode)) {
721 gen_qemu_ld64_i64(ctx, t0, EA);
722 set_fpr(rD(ctx->opcode) + 1, t0);
723 tcg_gen_addi_tl(EA, EA, 8);
724 gen_qemu_ld64_i64(ctx, t0, EA);
725 set_fpr(rD(ctx->opcode), t0);
726 } else {
727 gen_qemu_ld64_i64(ctx, t0, EA);
728 set_fpr(rD(ctx->opcode), t0);
729 tcg_gen_addi_tl(EA, EA, 8);
730 gen_qemu_ld64_i64(ctx, t0, EA);
731 set_fpr(rD(ctx->opcode) + 1, t0);
732 }
733 }
734
735 /* lfiwax */
736 static void gen_lfiwax(DisasContext *ctx)
737 {
738 TCGv EA;
739 TCGv t0;
740 TCGv_i64 t1;
741 if (unlikely(!ctx->fpu_enabled)) {
742 gen_exception(ctx, POWERPC_EXCP_FPU);
743 return;
744 }
745 gen_set_access_type(ctx, ACCESS_FLOAT);
746 EA = tcg_temp_new();
747 t0 = tcg_temp_new();
748 t1 = tcg_temp_new_i64();
749 gen_addr_reg_index(ctx, EA);
750 gen_qemu_ld32s(ctx, t0, EA);
751 tcg_gen_ext_tl_i64(t1, t0);
752 set_fpr(rD(ctx->opcode), t1);
753 }
754
755 /* lfiwzx */
756 static void gen_lfiwzx(DisasContext *ctx)
757 {
758 TCGv EA;
759 TCGv_i64 t0;
760 if (unlikely(!ctx->fpu_enabled)) {
761 gen_exception(ctx, POWERPC_EXCP_FPU);
762 return;
763 }
764 gen_set_access_type(ctx, ACCESS_FLOAT);
765 EA = tcg_temp_new();
766 t0 = tcg_temp_new_i64();
767 gen_addr_reg_index(ctx, EA);
768 gen_qemu_ld32u_i64(ctx, t0, EA);
769 set_fpr(rD(ctx->opcode), t0);
770 }
771
772 #define GEN_STXF(name, stop, opc2, opc3, type) \
773 static void glue(gen_, name##x)(DisasContext *ctx) \
774 { \
775 TCGv EA; \
776 TCGv_i64 t0; \
777 if (unlikely(!ctx->fpu_enabled)) { \
778 gen_exception(ctx, POWERPC_EXCP_FPU); \
779 return; \
780 } \
781 gen_set_access_type(ctx, ACCESS_FLOAT); \
782 EA = tcg_temp_new(); \
783 t0 = tcg_temp_new_i64(); \
784 gen_addr_reg_index(ctx, EA); \
785 get_fpr(t0, rS(ctx->opcode)); \
786 gen_qemu_##stop(ctx, t0, EA); \
787 }
788
789 static void gen_qemu_st32fs(DisasContext *ctx, TCGv_i64 src, TCGv addr)
790 {
791 TCGv_i32 tmp = tcg_temp_new_i32();
792 gen_helper_tosingle(tmp, src);
793 tcg_gen_qemu_st_i32(tmp, addr, ctx->mem_idx, DEF_MEMOP(MO_UL));
794 }
795
796 /* stfdepx (external PID lfdx) */
797 static void gen_stfdepx(DisasContext *ctx)
798 {
799 TCGv EA;
800 TCGv_i64 t0;
801 CHK_SV(ctx);
802 if (unlikely(!ctx->fpu_enabled)) {
803 gen_exception(ctx, POWERPC_EXCP_FPU);
804 return;
805 }
806 gen_set_access_type(ctx, ACCESS_FLOAT);
807 EA = tcg_temp_new();
808 t0 = tcg_temp_new_i64();
809 gen_addr_reg_index(ctx, EA);
810 get_fpr(t0, rD(ctx->opcode));
811 tcg_gen_qemu_st_i64(t0, EA, PPC_TLB_EPID_STORE, DEF_MEMOP(MO_UQ));
812 }
813
814 /* stfdp */
815 static void gen_stfdp(DisasContext *ctx)
816 {
817 TCGv EA;
818 TCGv_i64 t0;
819 if (unlikely(!ctx->fpu_enabled)) {
820 gen_exception(ctx, POWERPC_EXCP_FPU);
821 return;
822 }
823 gen_set_access_type(ctx, ACCESS_FLOAT);
824 EA = tcg_temp_new();
825 t0 = tcg_temp_new_i64();
826 gen_addr_imm_index(ctx, EA, 0);
827 /*
828 * We only need to swap high and low halves. gen_qemu_st64_i64
829 * does necessary 64-bit byteswap already.
830 */
831 if (unlikely(ctx->le_mode)) {
832 get_fpr(t0, rD(ctx->opcode) + 1);
833 gen_qemu_st64_i64(ctx, t0, EA);
834 tcg_gen_addi_tl(EA, EA, 8);
835 get_fpr(t0, rD(ctx->opcode));
836 gen_qemu_st64_i64(ctx, t0, EA);
837 } else {
838 get_fpr(t0, rD(ctx->opcode));
839 gen_qemu_st64_i64(ctx, t0, EA);
840 tcg_gen_addi_tl(EA, EA, 8);
841 get_fpr(t0, rD(ctx->opcode) + 1);
842 gen_qemu_st64_i64(ctx, t0, EA);
843 }
844 }
845
846 /* stfdpx */
847 static void gen_stfdpx(DisasContext *ctx)
848 {
849 TCGv EA;
850 TCGv_i64 t0;
851 if (unlikely(!ctx->fpu_enabled)) {
852 gen_exception(ctx, POWERPC_EXCP_FPU);
853 return;
854 }
855 gen_set_access_type(ctx, ACCESS_FLOAT);
856 EA = tcg_temp_new();
857 t0 = tcg_temp_new_i64();
858 gen_addr_reg_index(ctx, EA);
859 /*
860 * We only need to swap high and low halves. gen_qemu_st64_i64
861 * does necessary 64-bit byteswap already.
862 */
863 if (unlikely(ctx->le_mode)) {
864 get_fpr(t0, rD(ctx->opcode) + 1);
865 gen_qemu_st64_i64(ctx, t0, EA);
866 tcg_gen_addi_tl(EA, EA, 8);
867 get_fpr(t0, rD(ctx->opcode));
868 gen_qemu_st64_i64(ctx, t0, EA);
869 } else {
870 get_fpr(t0, rD(ctx->opcode));
871 gen_qemu_st64_i64(ctx, t0, EA);
872 tcg_gen_addi_tl(EA, EA, 8);
873 get_fpr(t0, rD(ctx->opcode) + 1);
874 gen_qemu_st64_i64(ctx, t0, EA);
875 }
876 }
877
878 /* Optional: */
879 static inline void gen_qemu_st32fiw(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
880 {
881 TCGv t0 = tcg_temp_new();
882 tcg_gen_trunc_i64_tl(t0, arg1),
883 gen_qemu_st32(ctx, t0, arg2);
884 }
885 /* stfiwx */
886 GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX);
887
888 /* Floating-point Load/Store Instructions */
889 static bool do_lsfpsd(DisasContext *ctx, int rt, int ra, TCGv displ,
890 bool update, bool store, bool single)
891 {
892 TCGv ea;
893 TCGv_i64 t0;
894 REQUIRE_INSNS_FLAGS(ctx, FLOAT);
895 REQUIRE_FPU(ctx);
896 if (update && ra == 0) {
897 gen_invalid(ctx);
898 return true;
899 }
900 gen_set_access_type(ctx, ACCESS_FLOAT);
901 t0 = tcg_temp_new_i64();
902 ea = do_ea_calc(ctx, ra, displ);
903 if (store) {
904 get_fpr(t0, rt);
905 if (single) {
906 gen_qemu_st32fs(ctx, t0, ea);
907 } else {
908 gen_qemu_st64_i64(ctx, t0, ea);
909 }
910 } else {
911 if (single) {
912 gen_qemu_ld32fs(ctx, t0, ea);
913 } else {
914 gen_qemu_ld64_i64(ctx, t0, ea);
915 }
916 set_fpr(rt, t0);
917 }
918 if (update) {
919 tcg_gen_mov_tl(cpu_gpr[ra], ea);
920 }
921 return true;
922 }
923
924 static bool do_lsfp_D(DisasContext *ctx, arg_D *a, bool update, bool store,
925 bool single)
926 {
927 return do_lsfpsd(ctx, a->rt, a->ra, tcg_constant_tl(a->si), update, store,
928 single);
929 }
930
931 static bool do_lsfp_PLS_D(DisasContext *ctx, arg_PLS_D *a, bool update,
932 bool store, bool single)
933 {
934 arg_D d;
935 if (!resolve_PLS_D(ctx, &d, a)) {
936 return true;
937 }
938 return do_lsfp_D(ctx, &d, update, store, single);
939 }
940
941 static bool do_lsfp_X(DisasContext *ctx, arg_X *a, bool update,
942 bool store, bool single)
943 {
944 return do_lsfpsd(ctx, a->rt, a->ra, cpu_gpr[a->rb], update, store, single);
945 }
946
947 TRANS(LFS, do_lsfp_D, false, false, true)
948 TRANS(LFSU, do_lsfp_D, true, false, true)
949 TRANS(LFSX, do_lsfp_X, false, false, true)
950 TRANS(LFSUX, do_lsfp_X, true, false, true)
951 TRANS(PLFS, do_lsfp_PLS_D, false, false, true)
952
953 TRANS(LFD, do_lsfp_D, false, false, false)
954 TRANS(LFDU, do_lsfp_D, true, false, false)
955 TRANS(LFDX, do_lsfp_X, false, false, false)
956 TRANS(LFDUX, do_lsfp_X, true, false, false)
957 TRANS(PLFD, do_lsfp_PLS_D, false, false, false)
958
959 TRANS(STFS, do_lsfp_D, false, true, true)
960 TRANS(STFSU, do_lsfp_D, true, true, true)
961 TRANS(STFSX, do_lsfp_X, false, true, true)
962 TRANS(STFSUX, do_lsfp_X, true, true, true)
963 TRANS(PSTFS, do_lsfp_PLS_D, false, true, true)
964
965 TRANS(STFD, do_lsfp_D, false, true, false)
966 TRANS(STFDU, do_lsfp_D, true, true, false)
967 TRANS(STFDX, do_lsfp_X, false, true, false)
968 TRANS(STFDUX, do_lsfp_X, true, true, false)
969 TRANS(PSTFD, do_lsfp_PLS_D, false, true, false)
970
971 #undef GEN_LDF
972 #undef GEN_LDUF
973 #undef GEN_LDUXF
974 #undef GEN_LDXF
975 #undef GEN_LDFS
976
977 #undef GEN_STF
978 #undef GEN_STUF
979 #undef GEN_STUXF
980 #undef GEN_STXF
981 #undef GEN_STFS