target/ppc: Implement pextd instruction
[qemu/rayw.git] / target / ppc / translate / fixedpoint-impl.c.inc
blob220b099fcd9fe2ae6665763713c3b5c6b573f18a
1 /*
2  * Power ISA decode for Fixed-Point Facility instructions
3  *
4  * Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  */
21  * Fixed-Point Load/Store Instructions
22  */
24 static bool do_ldst(DisasContext *ctx, int rt, int ra, TCGv displ, bool update,
25                     bool store, MemOp mop)
27     TCGv ea;
29     if (update && (ra == 0 || (!store && ra == rt))) {
30         gen_invalid(ctx);
31         return true;
32     }
33     gen_set_access_type(ctx, ACCESS_INT);
35     ea = do_ea_calc(ctx, ra, displ);
36     mop ^= ctx->default_tcg_memop_mask;
37     if (store) {
38         tcg_gen_qemu_st_tl(cpu_gpr[rt], ea, ctx->mem_idx, mop);
39     } else {
40         tcg_gen_qemu_ld_tl(cpu_gpr[rt], ea, ctx->mem_idx, mop);
41     }
42     if (update) {
43         tcg_gen_mov_tl(cpu_gpr[ra], ea);
44     }
45     tcg_temp_free(ea);
47     return true;
50 static bool do_ldst_D(DisasContext *ctx, arg_D *a, bool update, bool store,
51                       MemOp mop)
53     return do_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), update, store, mop);
56 static bool do_ldst_PLS_D(DisasContext *ctx, arg_PLS_D *a, bool update,
57                           bool store, MemOp mop)
59     arg_D d;
60     if (!resolve_PLS_D(ctx, &d, a)) {
61         return true;
62     }
63     return do_ldst_D(ctx, &d, update, store, mop);
66 static bool do_ldst_X(DisasContext *ctx, arg_X *a, bool update,
67                       bool store, MemOp mop)
69     return do_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], update, store, mop);
72 static bool do_ldst_quad(DisasContext *ctx, arg_D *a, bool store, bool prefixed)
74 #if defined(TARGET_PPC64)
75     TCGv ea;
76     TCGv_i64 low_addr_gpr, high_addr_gpr;
77     MemOp mop;
79     REQUIRE_INSNS_FLAGS(ctx, 64BX);
81     if (!prefixed && !(ctx->insns_flags2 & PPC2_LSQ_ISA207)) {
82         if (ctx->pr) {
83             /* lq and stq were privileged prior to V. 2.07 */
84             gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC);
85             return true;
86         }
88         if (ctx->le_mode) {
89             gen_align_no_le(ctx);
90             return true;
91         }
92     }
94     if (!store && unlikely(a->ra == a->rt)) {
95         gen_invalid(ctx);
96         return true;
97     }
99     gen_set_access_type(ctx, ACCESS_INT);
100     ea = do_ea_calc(ctx, a->ra, tcg_constant_tl(a->si));
102     if (prefixed || !ctx->le_mode) {
103         low_addr_gpr = cpu_gpr[a->rt];
104         high_addr_gpr = cpu_gpr[a->rt + 1];
105     } else {
106         low_addr_gpr = cpu_gpr[a->rt + 1];
107         high_addr_gpr = cpu_gpr[a->rt];
108     }
110     if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
111         if (HAVE_ATOMIC128) {
112             mop = DEF_MEMOP(MO_128);
113             TCGv_i32 oi = tcg_constant_i32(make_memop_idx(mop, ctx->mem_idx));
114             if (store) {
115                 if (ctx->le_mode) {
116                     gen_helper_stq_le_parallel(cpu_env, ea, low_addr_gpr,
117                                                high_addr_gpr, oi);
118                 } else {
119                     gen_helper_stq_be_parallel(cpu_env, ea, high_addr_gpr,
120                                                low_addr_gpr, oi);
122                 }
123             } else {
124                 if (ctx->le_mode) {
125                     gen_helper_lq_le_parallel(low_addr_gpr, cpu_env, ea, oi);
126                     tcg_gen_ld_i64(high_addr_gpr, cpu_env,
127                                    offsetof(CPUPPCState, retxh));
128                 } else {
129                     gen_helper_lq_be_parallel(high_addr_gpr, cpu_env, ea, oi);
130                     tcg_gen_ld_i64(low_addr_gpr, cpu_env,
131                                    offsetof(CPUPPCState, retxh));
132                 }
133             }
134         } else {
135             /* Restart with exclusive lock.  */
136             gen_helper_exit_atomic(cpu_env);
137             ctx->base.is_jmp = DISAS_NORETURN;
138         }
139     } else {
140         mop = DEF_MEMOP(MO_Q);
141         if (store) {
142             tcg_gen_qemu_st_i64(low_addr_gpr, ea, ctx->mem_idx, mop);
143         } else {
144             tcg_gen_qemu_ld_i64(low_addr_gpr, ea, ctx->mem_idx, mop);
145         }
147         gen_addr_add(ctx, ea, ea, 8);
149         if (store) {
150             tcg_gen_qemu_st_i64(high_addr_gpr, ea, ctx->mem_idx, mop);
151         } else {
152             tcg_gen_qemu_ld_i64(high_addr_gpr, ea, ctx->mem_idx, mop);
153         }
154     }
155     tcg_temp_free(ea);
156 #else
157     qemu_build_not_reached();
158 #endif
160     return true;
163 static bool do_ldst_quad_PLS_D(DisasContext *ctx, arg_PLS_D *a, bool store)
165     arg_D d;
166     if (!resolve_PLS_D(ctx, &d, a)) {
167         return true;
168     }
170     return do_ldst_quad(ctx, &d, store, true);
173 /* Load Byte and Zero */
174 TRANS(LBZ, do_ldst_D, false, false, MO_UB)
175 TRANS(LBZX, do_ldst_X, false, false, MO_UB)
176 TRANS(LBZU, do_ldst_D, true, false, MO_UB)
177 TRANS(LBZUX, do_ldst_X, true, false, MO_UB)
178 TRANS(PLBZ, do_ldst_PLS_D, false, false, MO_UB)
180 /* Load Halfword and Zero */
181 TRANS(LHZ, do_ldst_D, false, false, MO_UW)
182 TRANS(LHZX, do_ldst_X, false, false, MO_UW)
183 TRANS(LHZU, do_ldst_D, true, false, MO_UW)
184 TRANS(LHZUX, do_ldst_X, true, false, MO_UW)
185 TRANS(PLHZ, do_ldst_PLS_D, false, false, MO_UW)
187 /* Load Halfword Algebraic */
188 TRANS(LHA, do_ldst_D, false, false, MO_SW)
189 TRANS(LHAX, do_ldst_X, false, false, MO_SW)
190 TRANS(LHAU, do_ldst_D, true, false, MO_SW)
191 TRANS(LHAXU, do_ldst_X, true, false, MO_SW)
192 TRANS(PLHA, do_ldst_PLS_D, false, false, MO_SW)
194 /* Load Word and Zero */
195 TRANS(LWZ, do_ldst_D, false, false, MO_UL)
196 TRANS(LWZX, do_ldst_X, false, false, MO_UL)
197 TRANS(LWZU, do_ldst_D, true, false, MO_UL)
198 TRANS(LWZUX, do_ldst_X, true, false, MO_UL)
199 TRANS(PLWZ, do_ldst_PLS_D, false, false, MO_UL)
201 /* Load Word Algebraic */
202 TRANS64(LWA, do_ldst_D, false, false, MO_SL)
203 TRANS64(LWAX, do_ldst_X, false, false, MO_SL)
204 TRANS64(LWAUX, do_ldst_X, true, false, MO_SL)
205 TRANS64(PLWA, do_ldst_PLS_D, false, false, MO_SL)
207 /* Load Doubleword */
208 TRANS64(LD, do_ldst_D, false, false, MO_Q)
209 TRANS64(LDX, do_ldst_X, false, false, MO_Q)
210 TRANS64(LDU, do_ldst_D, true, false, MO_Q)
211 TRANS64(LDUX, do_ldst_X, true, false, MO_Q)
212 TRANS64(PLD, do_ldst_PLS_D, false, false, MO_Q)
214 /* Load Quadword */
215 TRANS64(LQ, do_ldst_quad, false, false);
216 TRANS64(PLQ, do_ldst_quad_PLS_D, false);
218 /* Store Byte */
219 TRANS(STB, do_ldst_D, false, true, MO_UB)
220 TRANS(STBX, do_ldst_X, false, true, MO_UB)
221 TRANS(STBU, do_ldst_D, true, true, MO_UB)
222 TRANS(STBUX, do_ldst_X, true, true, MO_UB)
223 TRANS(PSTB, do_ldst_PLS_D, false, true, MO_UB)
225 /* Store Halfword */
226 TRANS(STH, do_ldst_D, false, true, MO_UW)
227 TRANS(STHX, do_ldst_X, false, true, MO_UW)
228 TRANS(STHU, do_ldst_D, true, true, MO_UW)
229 TRANS(STHUX, do_ldst_X, true, true, MO_UW)
230 TRANS(PSTH, do_ldst_PLS_D, false, true, MO_UW)
232 /* Store Word */
233 TRANS(STW, do_ldst_D, false, true, MO_UL)
234 TRANS(STWX, do_ldst_X, false, true, MO_UL)
235 TRANS(STWU, do_ldst_D, true, true, MO_UL)
236 TRANS(STWUX, do_ldst_X, true, true, MO_UL)
237 TRANS(PSTW, do_ldst_PLS_D, false, true, MO_UL)
239 /* Store Doubleword */
240 TRANS64(STD, do_ldst_D, false, true, MO_Q)
241 TRANS64(STDX, do_ldst_X, false, true, MO_Q)
242 TRANS64(STDU, do_ldst_D, true, true, MO_Q)
243 TRANS64(STDUX, do_ldst_X, true, true, MO_Q)
244 TRANS64(PSTD, do_ldst_PLS_D, false, true, MO_Q)
246 /* Store Quadword */
247 TRANS64(STQ, do_ldst_quad, true, false);
248 TRANS64(PSTQ, do_ldst_quad_PLS_D, true);
251  * Fixed-Point Compare Instructions
252  */
254 static bool do_cmp_X(DisasContext *ctx, arg_X_bfl *a, bool s)
256     if ((ctx->insns_flags & PPC_64B) == 0) {
257         /*
258          * For 32-bit implementations, The Programming Environments Manual says
259          * that "the L field must be cleared, otherwise the instruction form is
260          * invalid." It seems, however, that most 32-bit CPUs ignore invalid
261          * forms (e.g., section "Instruction Formats" of the 405 and 440
262          * manuals, "Integer Compare Instructions" of the 601 manual), with the
263          * notable exception of the e500 and e500mc, where L=1 was reported to
264          * cause an exception.
265          */
266         if (a->l) {
267             if ((ctx->insns_flags2 & PPC2_BOOKE206)) {
268                 /*
269                  * For 32-bit Book E v2.06 implementations (i.e. e500/e500mc),
270                  * generate an illegal instruction exception.
271                  */
272                 return false;
273             } else {
274                 qemu_log_mask(LOG_GUEST_ERROR,
275                         "Invalid form of CMP%s at 0x" TARGET_FMT_lx ", L = 1\n",
276                         s ? "" : "L", ctx->cia);
277             }
278         }
279         gen_op_cmp32(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf);
280         return true;
281     }
283     /* For 64-bit implementations, deal with bit L accordingly. */
284     if (a->l) {
285         gen_op_cmp(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf);
286     } else {
287         gen_op_cmp32(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf);
288     }
289     return true;
292 static bool do_cmp_D(DisasContext *ctx, arg_D_bf *a, bool s)
294     if ((ctx->insns_flags & PPC_64B) == 0) {
295         /*
296          * For 32-bit implementations, The Programming Environments Manual says
297          * that "the L field must be cleared, otherwise the instruction form is
298          * invalid." It seems, however, that most 32-bit CPUs ignore invalid
299          * forms (e.g., section "Instruction Formats" of the 405 and 440
300          * manuals, "Integer Compare Instructions" of the 601 manual), with the
301          * notable exception of the e500 and e500mc, where L=1 was reported to
302          * cause an exception.
303          */
304         if (a->l) {
305             if ((ctx->insns_flags2 & PPC2_BOOKE206)) {
306                 /*
307                  * For 32-bit Book E v2.06 implementations (i.e. e500/e500mc),
308                  * generate an illegal instruction exception.
309                  */
310                 return false;
311             } else {
312                 qemu_log_mask(LOG_GUEST_ERROR,
313                         "Invalid form of CMP%s at 0x" TARGET_FMT_lx ", L = 1\n",
314                         s ? "I" : "LI", ctx->cia);
315             }
316         }
317         gen_op_cmp32(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf);
318         return true;
319     }
321     /* For 64-bit implementations, deal with bit L accordingly. */
322     if (a->l) {
323         gen_op_cmp(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf);
324     } else {
325         gen_op_cmp32(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf);
326     }
327     return true;
330 TRANS(CMP, do_cmp_X, true);
331 TRANS(CMPL, do_cmp_X, false);
332 TRANS(CMPI, do_cmp_D, true);
333 TRANS(CMPLI, do_cmp_D, false);
336  * Fixed-Point Arithmetic Instructions
337  */
339 static bool trans_ADDI(DisasContext *ctx, arg_D *a)
341     if (a->ra) {
342         tcg_gen_addi_tl(cpu_gpr[a->rt], cpu_gpr[a->ra], a->si);
343     } else {
344         tcg_gen_movi_tl(cpu_gpr[a->rt], a->si);
345     }
346     return true;
349 static bool trans_PADDI(DisasContext *ctx, arg_PLS_D *a)
351     arg_D d;
352     if (!resolve_PLS_D(ctx, &d, a)) {
353         return true;
354     }
355     return trans_ADDI(ctx, &d);
358 static bool trans_ADDIS(DisasContext *ctx, arg_D *a)
360     a->si <<= 16;
361     return trans_ADDI(ctx, a);
364 static bool trans_ADDPCIS(DisasContext *ctx, arg_DX *a)
366     REQUIRE_INSNS_FLAGS2(ctx, ISA300);
367     tcg_gen_movi_tl(cpu_gpr[a->rt], ctx->base.pc_next + (a->d << 16));
368     return true;
371 static bool trans_INVALID(DisasContext *ctx, arg_INVALID *a)
373     gen_invalid(ctx);
374     return true;
377 static bool trans_PNOP(DisasContext *ctx, arg_PNOP *a)
379     return true;
382 static bool do_set_bool_cond(DisasContext *ctx, arg_X_bi *a, bool neg, bool rev)
384     REQUIRE_INSNS_FLAGS2(ctx, ISA310);
385     uint32_t mask = 0x08 >> (a->bi & 0x03);
386     TCGCond cond = rev ? TCG_COND_EQ : TCG_COND_NE;
387     TCGv temp = tcg_temp_new();
389     tcg_gen_extu_i32_tl(temp, cpu_crf[a->bi >> 2]);
390     tcg_gen_andi_tl(temp, temp, mask);
391     tcg_gen_setcondi_tl(cond, cpu_gpr[a->rt], temp, 0);
392     if (neg) {
393         tcg_gen_neg_tl(cpu_gpr[a->rt], cpu_gpr[a->rt]);
394     }
395     tcg_temp_free(temp);
397     return true;
400 TRANS(SETBC, do_set_bool_cond, false, false)
401 TRANS(SETBCR, do_set_bool_cond, false, true)
402 TRANS(SETNBC, do_set_bool_cond, true, false)
403 TRANS(SETNBCR, do_set_bool_cond, true, true)
405 static bool trans_CFUGED(DisasContext *ctx, arg_X *a)
407     REQUIRE_64BIT(ctx);
408     REQUIRE_INSNS_FLAGS2(ctx, ISA310);
409 #if defined(TARGET_PPC64)
410     gen_helper_cfuged(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]);
411 #else
412     qemu_build_not_reached();
413 #endif
414     return true;
417 #if defined(TARGET_PPC64)
418 static void do_cntzdm(TCGv_i64 dst, TCGv_i64 src, TCGv_i64 mask, bool trail)
420     TCGv_i64 tmp;
421     TCGLabel *l1;
423     tmp = tcg_temp_local_new_i64();
424     l1 = gen_new_label();
426     tcg_gen_and_i64(tmp, src, mask);
427     if (trail) {
428         tcg_gen_ctzi_i64(tmp, tmp, 64);
429     } else {
430         tcg_gen_clzi_i64(tmp, tmp, 64);
431     }
433     tcg_gen_brcondi_i64(TCG_COND_EQ, tmp, 0, l1);
435     tcg_gen_subfi_i64(tmp, 64, tmp);
436     if (trail) {
437         tcg_gen_shl_i64(tmp, mask, tmp);
438     } else {
439         tcg_gen_shr_i64(tmp, mask, tmp);
440     }
441     tcg_gen_ctpop_i64(tmp, tmp);
443     gen_set_label(l1);
445     tcg_gen_mov_i64(dst, tmp);
447 #endif
449 static bool trans_CNTLZDM(DisasContext *ctx, arg_X *a)
451     REQUIRE_64BIT(ctx);
452     REQUIRE_INSNS_FLAGS2(ctx, ISA310);
453 #if defined(TARGET_PPC64)
454     do_cntzdm(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb], false);
455 #else
456     qemu_build_not_reached();
457 #endif
458     return true;
461 static bool trans_CNTTZDM(DisasContext *ctx, arg_X *a)
463     REQUIRE_64BIT(ctx);
464     REQUIRE_INSNS_FLAGS2(ctx, ISA310);
465 #if defined(TARGET_PPC64)
466     do_cntzdm(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb], true);
467 #else
468     qemu_build_not_reached();
469 #endif
470     return true;
473 static bool trans_PDEPD(DisasContext *ctx, arg_X *a)
475     REQUIRE_64BIT(ctx);
476     REQUIRE_INSNS_FLAGS2(ctx, ISA310);
477 #if defined(TARGET_PPC64)
478     gen_helper_PDEPD(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]);
479 #else
480     qemu_build_not_reached();
481 #endif
482     return true;
485 static bool trans_PEXTD(DisasContext *ctx, arg_X *a)
487     REQUIRE_64BIT(ctx);
488     REQUIRE_INSNS_FLAGS2(ctx, ISA310);
489 #if defined(TARGET_PPC64)
490     gen_helper_PEXTD(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]);
491 #else
492     qemu_build_not_reached();
493 #endif
494     return true;