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 */
19
20/*
21 * Fixed-Point Load/Store Instructions
22 */
23
24static bool do_ldst(DisasContext *ctx, int rt, int ra, TCGv displ, bool update,
25                    bool store, MemOp mop)
26{
27    TCGv ea;
28
29    if (update && (ra == 0 || (!store && ra == rt))) {
30        gen_invalid(ctx);
31        return true;
32    }
33    gen_set_access_type(ctx, ACCESS_INT);
34
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);
46
47    return true;
48}
49
50static bool do_ldst_D(DisasContext *ctx, arg_D *a, bool update, bool store,
51                      MemOp mop)
52{
53    return do_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), update, store, mop);
54}
55
56static bool do_ldst_PLS_D(DisasContext *ctx, arg_PLS_D *a, bool update,
57                          bool store, MemOp mop)
58{
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);
64}
65
66static bool do_ldst_X(DisasContext *ctx, arg_X *a, bool update,
67                      bool store, MemOp mop)
68{
69    return do_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], update, store, mop);
70}
71
72static bool do_ldst_quad(DisasContext *ctx, arg_D *a, bool store, bool prefixed)
73{
74#if defined(TARGET_PPC64)
75    TCGv ea;
76    TCGv_i64 low_addr_gpr, high_addr_gpr;
77    MemOp mop;
78
79    REQUIRE_INSNS_FLAGS(ctx, 64BX);
80
81    if (!prefixed && !(ctx->insns_flags2 & PPC2_LSQ_ISA207)) {
82        /* lq and stq were privileged prior to V. 2.07 */
83        REQUIRE_SV(ctx);
84
85        if (ctx->le_mode) {
86            gen_align_no_le(ctx);
87            return true;
88        }
89    }
90
91    if (!store && unlikely(a->ra == a->rt)) {
92        gen_invalid(ctx);
93        return true;
94    }
95
96    gen_set_access_type(ctx, ACCESS_INT);
97    ea = do_ea_calc(ctx, a->ra, tcg_constant_tl(a->si));
98
99    if (prefixed || !ctx->le_mode) {
100        low_addr_gpr = cpu_gpr[a->rt];
101        high_addr_gpr = cpu_gpr[a->rt + 1];
102    } else {
103        low_addr_gpr = cpu_gpr[a->rt + 1];
104        high_addr_gpr = cpu_gpr[a->rt];
105    }
106
107    if (tb_cflags(ctx->base.tb) & CF_PARALLEL) {
108        if (HAVE_ATOMIC128) {
109            mop = DEF_MEMOP(MO_128);
110            TCGv_i32 oi = tcg_constant_i32(make_memop_idx(mop, ctx->mem_idx));
111            if (store) {
112                if (ctx->le_mode) {
113                    gen_helper_stq_le_parallel(cpu_env, ea, low_addr_gpr,
114                                               high_addr_gpr, oi);
115                } else {
116                    gen_helper_stq_be_parallel(cpu_env, ea, high_addr_gpr,
117                                               low_addr_gpr, oi);
118
119                }
120            } else {
121                if (ctx->le_mode) {
122                    gen_helper_lq_le_parallel(low_addr_gpr, cpu_env, ea, oi);
123                    tcg_gen_ld_i64(high_addr_gpr, cpu_env,
124                                   offsetof(CPUPPCState, retxh));
125                } else {
126                    gen_helper_lq_be_parallel(high_addr_gpr, cpu_env, ea, oi);
127                    tcg_gen_ld_i64(low_addr_gpr, cpu_env,
128                                   offsetof(CPUPPCState, retxh));
129                }
130            }
131        } else {
132            /* Restart with exclusive lock.  */
133            gen_helper_exit_atomic(cpu_env);
134            ctx->base.is_jmp = DISAS_NORETURN;
135        }
136    } else {
137        mop = DEF_MEMOP(MO_UQ);
138        if (store) {
139            tcg_gen_qemu_st_i64(low_addr_gpr, ea, ctx->mem_idx, mop);
140        } else {
141            tcg_gen_qemu_ld_i64(low_addr_gpr, ea, ctx->mem_idx, mop);
142        }
143
144        gen_addr_add(ctx, ea, ea, 8);
145
146        if (store) {
147            tcg_gen_qemu_st_i64(high_addr_gpr, ea, ctx->mem_idx, mop);
148        } else {
149            tcg_gen_qemu_ld_i64(high_addr_gpr, ea, ctx->mem_idx, mop);
150        }
151    }
152    tcg_temp_free(ea);
153#else
154    qemu_build_not_reached();
155#endif
156
157    return true;
158}
159
160static bool do_ldst_quad_PLS_D(DisasContext *ctx, arg_PLS_D *a, bool store)
161{
162    arg_D d;
163    if (!resolve_PLS_D(ctx, &d, a)) {
164        return true;
165    }
166
167    return do_ldst_quad(ctx, &d, store, true);
168}
169
170/* Load Byte and Zero */
171TRANS(LBZ, do_ldst_D, false, false, MO_UB)
172TRANS(LBZX, do_ldst_X, false, false, MO_UB)
173TRANS(LBZU, do_ldst_D, true, false, MO_UB)
174TRANS(LBZUX, do_ldst_X, true, false, MO_UB)
175TRANS(PLBZ, do_ldst_PLS_D, false, false, MO_UB)
176
177/* Load Halfword and Zero */
178TRANS(LHZ, do_ldst_D, false, false, MO_UW)
179TRANS(LHZX, do_ldst_X, false, false, MO_UW)
180TRANS(LHZU, do_ldst_D, true, false, MO_UW)
181TRANS(LHZUX, do_ldst_X, true, false, MO_UW)
182TRANS(PLHZ, do_ldst_PLS_D, false, false, MO_UW)
183
184/* Load Halfword Algebraic */
185TRANS(LHA, do_ldst_D, false, false, MO_SW)
186TRANS(LHAX, do_ldst_X, false, false, MO_SW)
187TRANS(LHAU, do_ldst_D, true, false, MO_SW)
188TRANS(LHAXU, do_ldst_X, true, false, MO_SW)
189TRANS(PLHA, do_ldst_PLS_D, false, false, MO_SW)
190
191/* Load Word and Zero */
192TRANS(LWZ, do_ldst_D, false, false, MO_UL)
193TRANS(LWZX, do_ldst_X, false, false, MO_UL)
194TRANS(LWZU, do_ldst_D, true, false, MO_UL)
195TRANS(LWZUX, do_ldst_X, true, false, MO_UL)
196TRANS(PLWZ, do_ldst_PLS_D, false, false, MO_UL)
197
198/* Load Word Algebraic */
199TRANS64(LWA, do_ldst_D, false, false, MO_SL)
200TRANS64(LWAX, do_ldst_X, false, false, MO_SL)
201TRANS64(LWAUX, do_ldst_X, true, false, MO_SL)
202TRANS64(PLWA, do_ldst_PLS_D, false, false, MO_SL)
203
204/* Load Doubleword */
205TRANS64(LD, do_ldst_D, false, false, MO_UQ)
206TRANS64(LDX, do_ldst_X, false, false, MO_UQ)
207TRANS64(LDU, do_ldst_D, true, false, MO_UQ)
208TRANS64(LDUX, do_ldst_X, true, false, MO_UQ)
209TRANS64(PLD, do_ldst_PLS_D, false, false, MO_UQ)
210
211/* Load Quadword */
212TRANS64(LQ, do_ldst_quad, false, false);
213TRANS64(PLQ, do_ldst_quad_PLS_D, false);
214
215/* Store Byte */
216TRANS(STB, do_ldst_D, false, true, MO_UB)
217TRANS(STBX, do_ldst_X, false, true, MO_UB)
218TRANS(STBU, do_ldst_D, true, true, MO_UB)
219TRANS(STBUX, do_ldst_X, true, true, MO_UB)
220TRANS(PSTB, do_ldst_PLS_D, false, true, MO_UB)
221
222/* Store Halfword */
223TRANS(STH, do_ldst_D, false, true, MO_UW)
224TRANS(STHX, do_ldst_X, false, true, MO_UW)
225TRANS(STHU, do_ldst_D, true, true, MO_UW)
226TRANS(STHUX, do_ldst_X, true, true, MO_UW)
227TRANS(PSTH, do_ldst_PLS_D, false, true, MO_UW)
228
229/* Store Word */
230TRANS(STW, do_ldst_D, false, true, MO_UL)
231TRANS(STWX, do_ldst_X, false, true, MO_UL)
232TRANS(STWU, do_ldst_D, true, true, MO_UL)
233TRANS(STWUX, do_ldst_X, true, true, MO_UL)
234TRANS(PSTW, do_ldst_PLS_D, false, true, MO_UL)
235
236/* Store Doubleword */
237TRANS64(STD, do_ldst_D, false, true, MO_UQ)
238TRANS64(STDX, do_ldst_X, false, true, MO_UQ)
239TRANS64(STDU, do_ldst_D, true, true, MO_UQ)
240TRANS64(STDUX, do_ldst_X, true, true, MO_UQ)
241TRANS64(PSTD, do_ldst_PLS_D, false, true, MO_UQ)
242
243/* Store Quadword */
244TRANS64(STQ, do_ldst_quad, true, false);
245TRANS64(PSTQ, do_ldst_quad_PLS_D, true);
246
247/*
248 * Fixed-Point Compare Instructions
249 */
250
251static bool do_cmp_X(DisasContext *ctx, arg_X_bfl *a, bool s)
252{
253    if ((ctx->insns_flags & PPC_64B) == 0) {
254        /*
255         * For 32-bit implementations, The Programming Environments Manual says
256         * that "the L field must be cleared, otherwise the instruction form is
257         * invalid." It seems, however, that most 32-bit CPUs ignore invalid
258         * forms (e.g., section "Instruction Formats" of the 405 and 440
259         * manuals, "Integer Compare Instructions" of the 601 manual), with the
260         * notable exception of the e500 and e500mc, where L=1 was reported to
261         * cause an exception.
262         */
263        if (a->l) {
264            if ((ctx->insns_flags2 & PPC2_BOOKE206)) {
265                /*
266                 * For 32-bit Book E v2.06 implementations (i.e. e500/e500mc),
267                 * generate an illegal instruction exception.
268                 */
269                return false;
270            } else {
271                qemu_log_mask(LOG_GUEST_ERROR,
272                        "Invalid form of CMP%s at 0x" TARGET_FMT_lx ", L = 1\n",
273                        s ? "" : "L", ctx->cia);
274            }
275        }
276        gen_op_cmp32(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf);
277        return true;
278    }
279
280    /* For 64-bit implementations, deal with bit L accordingly. */
281    if (a->l) {
282        gen_op_cmp(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf);
283    } else {
284        gen_op_cmp32(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf);
285    }
286    return true;
287}
288
289static bool do_cmp_D(DisasContext *ctx, arg_D_bf *a, bool s)
290{
291    if ((ctx->insns_flags & PPC_64B) == 0) {
292        /*
293         * For 32-bit implementations, The Programming Environments Manual says
294         * that "the L field must be cleared, otherwise the instruction form is
295         * invalid." It seems, however, that most 32-bit CPUs ignore invalid
296         * forms (e.g., section "Instruction Formats" of the 405 and 440
297         * manuals, "Integer Compare Instructions" of the 601 manual), with the
298         * notable exception of the e500 and e500mc, where L=1 was reported to
299         * cause an exception.
300         */
301        if (a->l) {
302            if ((ctx->insns_flags2 & PPC2_BOOKE206)) {
303                /*
304                 * For 32-bit Book E v2.06 implementations (i.e. e500/e500mc),
305                 * generate an illegal instruction exception.
306                 */
307                return false;
308            } else {
309                qemu_log_mask(LOG_GUEST_ERROR,
310                        "Invalid form of CMP%s at 0x" TARGET_FMT_lx ", L = 1\n",
311                        s ? "I" : "LI", ctx->cia);
312            }
313        }
314        gen_op_cmp32(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf);
315        return true;
316    }
317
318    /* For 64-bit implementations, deal with bit L accordingly. */
319    if (a->l) {
320        gen_op_cmp(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf);
321    } else {
322        gen_op_cmp32(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf);
323    }
324    return true;
325}
326
327TRANS(CMP, do_cmp_X, true);
328TRANS(CMPL, do_cmp_X, false);
329TRANS(CMPI, do_cmp_D, true);
330TRANS(CMPLI, do_cmp_D, false);
331
332/*
333 * Fixed-Point Arithmetic Instructions
334 */
335
336static bool trans_ADDI(DisasContext *ctx, arg_D *a)
337{
338    if (a->ra) {
339        tcg_gen_addi_tl(cpu_gpr[a->rt], cpu_gpr[a->ra], a->si);
340    } else {
341        tcg_gen_movi_tl(cpu_gpr[a->rt], a->si);
342    }
343    return true;
344}
345
346static bool trans_PADDI(DisasContext *ctx, arg_PLS_D *a)
347{
348    arg_D d;
349    if (!resolve_PLS_D(ctx, &d, a)) {
350        return true;
351    }
352    return trans_ADDI(ctx, &d);
353}
354
355static bool trans_ADDIS(DisasContext *ctx, arg_D *a)
356{
357    a->si <<= 16;
358    return trans_ADDI(ctx, a);
359}
360
361static bool trans_ADDPCIS(DisasContext *ctx, arg_DX *a)
362{
363    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
364    tcg_gen_movi_tl(cpu_gpr[a->rt], ctx->base.pc_next + (a->d << 16));
365    return true;
366}
367
368static bool trans_INVALID(DisasContext *ctx, arg_INVALID *a)
369{
370    gen_invalid(ctx);
371    return true;
372}
373
374static bool trans_PNOP(DisasContext *ctx, arg_PNOP *a)
375{
376    return true;
377}
378
379static bool do_set_bool_cond(DisasContext *ctx, arg_X_bi *a, bool neg, bool rev)
380{
381    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
382    uint32_t mask = 0x08 >> (a->bi & 0x03);
383    TCGCond cond = rev ? TCG_COND_EQ : TCG_COND_NE;
384    TCGv temp = tcg_temp_new();
385
386    tcg_gen_extu_i32_tl(temp, cpu_crf[a->bi >> 2]);
387    tcg_gen_andi_tl(temp, temp, mask);
388    tcg_gen_setcondi_tl(cond, cpu_gpr[a->rt], temp, 0);
389    if (neg) {
390        tcg_gen_neg_tl(cpu_gpr[a->rt], cpu_gpr[a->rt]);
391    }
392    tcg_temp_free(temp);
393
394    return true;
395}
396
397TRANS(SETBC, do_set_bool_cond, false, false)
398TRANS(SETBCR, do_set_bool_cond, false, true)
399TRANS(SETNBC, do_set_bool_cond, true, false)
400TRANS(SETNBCR, do_set_bool_cond, true, true)
401
402static bool trans_CFUGED(DisasContext *ctx, arg_X *a)
403{
404    REQUIRE_64BIT(ctx);
405    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
406#if defined(TARGET_PPC64)
407    gen_helper_CFUGED(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]);
408#else
409    qemu_build_not_reached();
410#endif
411    return true;
412}
413
414static void do_cntzdm(TCGv_i64 dst, TCGv_i64 src, TCGv_i64 mask, int64_t trail)
415{
416    TCGv_i64 t0, t1;
417
418    t0 = tcg_temp_new_i64();
419    t1 = tcg_temp_new_i64();
420
421    tcg_gen_and_i64(t0, src, mask);
422    if (trail) {
423        tcg_gen_ctzi_i64(t0, t0, -1);
424    } else {
425        tcg_gen_clzi_i64(t0, t0, -1);
426    }
427
428    tcg_gen_setcondi_i64(TCG_COND_NE, t1, t0, -1);
429    tcg_gen_andi_i64(t0, t0, 63);
430    tcg_gen_xori_i64(t0, t0, 63);
431    if (trail) {
432        tcg_gen_shl_i64(t0, mask, t0);
433        tcg_gen_shl_i64(t0, t0, t1);
434    } else {
435        tcg_gen_shr_i64(t0, mask, t0);
436        tcg_gen_shr_i64(t0, t0, t1);
437    }
438
439    tcg_gen_ctpop_i64(dst, t0);
440
441    tcg_temp_free_i64(t0);
442    tcg_temp_free_i64(t1);
443}
444
445static bool trans_CNTLZDM(DisasContext *ctx, arg_X *a)
446{
447    REQUIRE_64BIT(ctx);
448    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
449#if defined(TARGET_PPC64)
450    do_cntzdm(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb], false);
451#else
452    qemu_build_not_reached();
453#endif
454    return true;
455}
456
457static bool trans_CNTTZDM(DisasContext *ctx, arg_X *a)
458{
459    REQUIRE_64BIT(ctx);
460    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
461#if defined(TARGET_PPC64)
462    do_cntzdm(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb], true);
463#else
464    qemu_build_not_reached();
465#endif
466    return true;
467}
468
469static bool trans_PDEPD(DisasContext *ctx, arg_X *a)
470{
471    REQUIRE_64BIT(ctx);
472    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
473#if defined(TARGET_PPC64)
474    gen_helper_PDEPD(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]);
475#else
476    qemu_build_not_reached();
477#endif
478    return true;
479}
480
481static bool trans_PEXTD(DisasContext *ctx, arg_X *a)
482{
483    REQUIRE_64BIT(ctx);
484    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
485#if defined(TARGET_PPC64)
486    gen_helper_PEXTD(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]);
487#else
488    qemu_build_not_reached();
489#endif
490    return true;
491}
492
493static bool trans_ADDG6S(DisasContext *ctx, arg_X *a)
494{
495    const uint64_t carry_bits = 0x1111111111111111ULL;
496    TCGv t0, t1, carry, zero = tcg_constant_tl(0);
497
498    REQUIRE_INSNS_FLAGS2(ctx, BCDA_ISA206);
499
500    t0 = tcg_temp_new();
501    t1 = tcg_const_tl(0);
502    carry = tcg_const_tl(0);
503
504    for (int i = 0; i < 16; i++) {
505        tcg_gen_shri_tl(t0, cpu_gpr[a->ra], i * 4);
506        tcg_gen_andi_tl(t0, t0, 0xf);
507        tcg_gen_add_tl(t1, t1, t0);
508
509        tcg_gen_shri_tl(t0, cpu_gpr[a->rb], i * 4);
510        tcg_gen_andi_tl(t0, t0, 0xf);
511        tcg_gen_add_tl(t1, t1, t0);
512
513        tcg_gen_andi_tl(t1, t1, 0x10);
514        tcg_gen_setcond_tl(TCG_COND_NE, t1, t1, zero);
515
516        tcg_gen_shli_tl(t0, t1, i * 4);
517        tcg_gen_or_tl(carry, carry, t0);
518    }
519
520    tcg_gen_xori_tl(carry, carry, (target_long)carry_bits);
521    tcg_gen_muli_tl(cpu_gpr[a->rt], carry, 6);
522
523    tcg_temp_free(t0);
524    tcg_temp_free(t1);
525    tcg_temp_free(carry);
526
527    return true;
528}
529
530static bool trans_CDTBCD(DisasContext *ctx, arg_X_sa *a)
531{
532    REQUIRE_INSNS_FLAGS2(ctx, BCDA_ISA206);
533    gen_helper_CDTBCD(cpu_gpr[a->ra], cpu_gpr[a->rs]);
534    return true;
535}
536
537static bool trans_CBCDTD(DisasContext *ctx, arg_X_sa *a)
538{
539    REQUIRE_INSNS_FLAGS2(ctx, BCDA_ISA206);
540    gen_helper_CBCDTD(cpu_gpr[a->ra], cpu_gpr[a->rs]);
541    return true;
542}
543