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 * Incorporate CIA into the constant when R=1.
22 * Validate that when R=1, RA=0.
23 */
24static bool resolve_PLS_D(DisasContext *ctx, arg_D *d, arg_PLS_D *a)
25{
26    d->rt = a->rt;
27    d->ra = a->ra;
28    d->si = a->si;
29    if (a->r) {
30        if (unlikely(a->ra != 0)) {
31            gen_invalid(ctx);
32            return false;
33        }
34        d->si += ctx->cia;
35    }
36    return true;
37}
38
39/*
40 * Fixed-Point Load/Store Instructions
41 */
42
43static bool do_ldst(DisasContext *ctx, int rt, int ra, TCGv displ, bool update,
44                    bool store, MemOp mop)
45{
46    TCGv ea;
47
48    if (update && (ra == 0 || (!store && ra == rt))) {
49        gen_invalid(ctx);
50        return true;
51    }
52    gen_set_access_type(ctx, ACCESS_INT);
53
54    ea = tcg_temp_new();
55    if (ra) {
56        tcg_gen_add_tl(ea, cpu_gpr[ra], displ);
57    } else {
58        tcg_gen_mov_tl(ea, displ);
59    }
60    if (NARROW_MODE(ctx)) {
61        tcg_gen_ext32u_tl(ea, ea);
62    }
63    mop ^= ctx->default_tcg_memop_mask;
64    if (store) {
65        tcg_gen_qemu_st_tl(cpu_gpr[rt], ea, ctx->mem_idx, mop);
66    } else {
67        tcg_gen_qemu_ld_tl(cpu_gpr[rt], ea, ctx->mem_idx, mop);
68    }
69    if (update) {
70        tcg_gen_mov_tl(cpu_gpr[ra], ea);
71    }
72    tcg_temp_free(ea);
73
74    return true;
75}
76
77static bool do_ldst_D(DisasContext *ctx, arg_D *a, bool update, bool store,
78                      MemOp mop)
79{
80    return do_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), update, store, mop);
81}
82
83static bool do_ldst_PLS_D(DisasContext *ctx, arg_PLS_D *a, bool update,
84                          bool store, MemOp mop)
85{
86    arg_D d;
87    if (!resolve_PLS_D(ctx, &d, a)) {
88        return true;
89    }
90    return do_ldst_D(ctx, &d, update, store, mop);
91}
92
93static bool do_ldst_X(DisasContext *ctx, arg_X *a, bool update,
94                      bool store, MemOp mop)
95{
96    return do_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], update, store, mop);
97}
98
99/* Load Byte and Zero */
100TRANS(LBZ, do_ldst_D, false, false, MO_UB)
101TRANS(LBZX, do_ldst_X, false, false, MO_UB)
102TRANS(LBZU, do_ldst_D, true, false, MO_UB)
103TRANS(LBZUX, do_ldst_X, true, false, MO_UB)
104TRANS(PLBZ, do_ldst_PLS_D, false, false, MO_UB)
105
106/* Load Halfword and Zero */
107TRANS(LHZ, do_ldst_D, false, false, MO_UW)
108TRANS(LHZX, do_ldst_X, false, false, MO_UW)
109TRANS(LHZU, do_ldst_D, true, false, MO_UW)
110TRANS(LHZUX, do_ldst_X, true, false, MO_UW)
111TRANS(PLHZ, do_ldst_PLS_D, false, false, MO_UW)
112
113/* Load Halfword Algebraic */
114TRANS(LHA, do_ldst_D, false, false, MO_SW)
115TRANS(LHAX, do_ldst_X, false, false, MO_SW)
116TRANS(LHAU, do_ldst_D, true, false, MO_SW)
117TRANS(LHAXU, do_ldst_X, true, false, MO_SW)
118TRANS(PLHA, do_ldst_PLS_D, false, false, MO_SW)
119
120/* Load Word and Zero */
121TRANS(LWZ, do_ldst_D, false, false, MO_UL)
122TRANS(LWZX, do_ldst_X, false, false, MO_UL)
123TRANS(LWZU, do_ldst_D, true, false, MO_UL)
124TRANS(LWZUX, do_ldst_X, true, false, MO_UL)
125TRANS(PLWZ, do_ldst_PLS_D, false, false, MO_UL)
126
127/* Load Word Algebraic */
128TRANS64(LWA, do_ldst_D, false, false, MO_SL)
129TRANS64(LWAX, do_ldst_X, false, false, MO_SL)
130TRANS64(LWAUX, do_ldst_X, true, false, MO_SL)
131TRANS64(PLWA, do_ldst_PLS_D, false, false, MO_SL)
132
133/* Load Doubleword */
134TRANS64(LD, do_ldst_D, false, false, MO_Q)
135TRANS64(LDX, do_ldst_X, false, false, MO_Q)
136TRANS64(LDU, do_ldst_D, true, false, MO_Q)
137TRANS64(LDUX, do_ldst_X, true, false, MO_Q)
138TRANS64(PLD, do_ldst_PLS_D, false, false, MO_Q)
139
140/* Store Byte */
141TRANS(STB, do_ldst_D, false, true, MO_UB)
142TRANS(STBX, do_ldst_X, false, true, MO_UB)
143TRANS(STBU, do_ldst_D, true, true, MO_UB)
144TRANS(STBUX, do_ldst_X, true, true, MO_UB)
145TRANS(PSTB, do_ldst_PLS_D, false, true, MO_UB)
146
147/* Store Halfword */
148TRANS(STH, do_ldst_D, false, true, MO_UW)
149TRANS(STHX, do_ldst_X, false, true, MO_UW)
150TRANS(STHU, do_ldst_D, true, true, MO_UW)
151TRANS(STHUX, do_ldst_X, true, true, MO_UW)
152TRANS(PSTH, do_ldst_PLS_D, false, true, MO_UW)
153
154/* Store Word */
155TRANS(STW, do_ldst_D, false, true, MO_UL)
156TRANS(STWX, do_ldst_X, false, true, MO_UL)
157TRANS(STWU, do_ldst_D, true, true, MO_UL)
158TRANS(STWUX, do_ldst_X, true, true, MO_UL)
159TRANS(PSTW, do_ldst_PLS_D, false, true, MO_UL)
160
161/* Store Doubleword */
162TRANS64(STD, do_ldst_D, false, true, MO_Q)
163TRANS64(STDX, do_ldst_X, false, true, MO_Q)
164TRANS64(STDU, do_ldst_D, true, true, MO_Q)
165TRANS64(STDUX, do_ldst_X, true, true, MO_Q)
166TRANS64(PSTD, do_ldst_PLS_D, false, true, MO_Q)
167
168/*
169 * Fixed-Point Compare Instructions
170 */
171
172static bool do_cmp_X(DisasContext *ctx, arg_X_bfl *a, bool s)
173{
174    if (a->l) {
175        REQUIRE_64BIT(ctx);
176        gen_op_cmp(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf);
177    } else {
178        gen_op_cmp32(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf);
179    }
180    return true;
181}
182
183static bool do_cmp_D(DisasContext *ctx, arg_D_bf *a, bool s)
184{
185    if (a->l) {
186        REQUIRE_64BIT(ctx);
187        gen_op_cmp(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf);
188    } else {
189        gen_op_cmp32(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf);
190    }
191    return true;
192}
193
194TRANS(CMP, do_cmp_X, true);
195TRANS(CMPL, do_cmp_X, false);
196TRANS(CMPI, do_cmp_D, true);
197TRANS(CMPLI, do_cmp_D, false);
198
199/*
200 * Fixed-Point Arithmetic Instructions
201 */
202
203static bool trans_ADDI(DisasContext *ctx, arg_D *a)
204{
205    if (a->ra) {
206        tcg_gen_addi_tl(cpu_gpr[a->rt], cpu_gpr[a->ra], a->si);
207    } else {
208        tcg_gen_movi_tl(cpu_gpr[a->rt], a->si);
209    }
210    return true;
211}
212
213static bool trans_PADDI(DisasContext *ctx, arg_PLS_D *a)
214{
215    arg_D d;
216    if (!resolve_PLS_D(ctx, &d, a)) {
217        return true;
218    }
219    return trans_ADDI(ctx, &d);
220}
221
222static bool trans_ADDIS(DisasContext *ctx, arg_D *a)
223{
224    a->si <<= 16;
225    return trans_ADDI(ctx, a);
226}
227
228static bool trans_ADDPCIS(DisasContext *ctx, arg_DX *a)
229{
230    REQUIRE_INSNS_FLAGS2(ctx, ISA300);
231    tcg_gen_movi_tl(cpu_gpr[a->rt], ctx->base.pc_next + (a->d << 16));
232    return true;
233}
234
235static bool trans_INVALID(DisasContext *ctx, arg_INVALID *a)
236{
237    gen_invalid(ctx);
238    return true;
239}
240
241static bool trans_PNOP(DisasContext *ctx, arg_PNOP *a)
242{
243    return true;
244}
245
246static bool do_set_bool_cond(DisasContext *ctx, arg_X_bi *a, bool neg, bool rev)
247{
248    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
249    uint32_t mask = 0x08 >> (a->bi & 0x03);
250    TCGCond cond = rev ? TCG_COND_EQ : TCG_COND_NE;
251    TCGv temp = tcg_temp_new();
252
253    tcg_gen_extu_i32_tl(temp, cpu_crf[a->bi >> 2]);
254    tcg_gen_andi_tl(temp, temp, mask);
255    tcg_gen_setcondi_tl(cond, cpu_gpr[a->rt], temp, 0);
256    if (neg) {
257        tcg_gen_neg_tl(cpu_gpr[a->rt], cpu_gpr[a->rt]);
258    }
259    tcg_temp_free(temp);
260
261    return true;
262}
263
264TRANS(SETBC, do_set_bool_cond, false, false)
265TRANS(SETBCR, do_set_bool_cond, false, true)
266TRANS(SETNBC, do_set_bool_cond, true, false)
267TRANS(SETNBCR, do_set_bool_cond, true, true)
268
269static bool trans_CFUGED(DisasContext *ctx, arg_X *a)
270{
271    REQUIRE_64BIT(ctx);
272    REQUIRE_INSNS_FLAGS2(ctx, ISA310);
273#if defined(TARGET_PPC64)
274    gen_helper_cfuged(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]);
275#else
276    qemu_build_not_reached();
277#endif
278    return true;
279}
280