target/ppc: move resolve_PLS_D to translate.c
[qemu/rayw.git] / target / ppc / translate / fixedpoint-impl.c.inc
blob812b7ddd0a4ec853c75be527771d953356f49e9b
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 /* Load Byte and Zero */
73 TRANS(LBZ, do_ldst_D, false, false, MO_UB)
74 TRANS(LBZX, do_ldst_X, false, false, MO_UB)
75 TRANS(LBZU, do_ldst_D, true, false, MO_UB)
76 TRANS(LBZUX, do_ldst_X, true, false, MO_UB)
77 TRANS(PLBZ, do_ldst_PLS_D, false, false, MO_UB)
79 /* Load Halfword and Zero */
80 TRANS(LHZ, do_ldst_D, false, false, MO_UW)
81 TRANS(LHZX, do_ldst_X, false, false, MO_UW)
82 TRANS(LHZU, do_ldst_D, true, false, MO_UW)
83 TRANS(LHZUX, do_ldst_X, true, false, MO_UW)
84 TRANS(PLHZ, do_ldst_PLS_D, false, false, MO_UW)
86 /* Load Halfword Algebraic */
87 TRANS(LHA, do_ldst_D, false, false, MO_SW)
88 TRANS(LHAX, do_ldst_X, false, false, MO_SW)
89 TRANS(LHAU, do_ldst_D, true, false, MO_SW)
90 TRANS(LHAXU, do_ldst_X, true, false, MO_SW)
91 TRANS(PLHA, do_ldst_PLS_D, false, false, MO_SW)
93 /* Load Word and Zero */
94 TRANS(LWZ, do_ldst_D, false, false, MO_UL)
95 TRANS(LWZX, do_ldst_X, false, false, MO_UL)
96 TRANS(LWZU, do_ldst_D, true, false, MO_UL)
97 TRANS(LWZUX, do_ldst_X, true, false, MO_UL)
98 TRANS(PLWZ, do_ldst_PLS_D, false, false, MO_UL)
100 /* Load Word Algebraic */
101 TRANS64(LWA, do_ldst_D, false, false, MO_SL)
102 TRANS64(LWAX, do_ldst_X, false, false, MO_SL)
103 TRANS64(LWAUX, do_ldst_X, true, false, MO_SL)
104 TRANS64(PLWA, do_ldst_PLS_D, false, false, MO_SL)
106 /* Load Doubleword */
107 TRANS64(LD, do_ldst_D, false, false, MO_Q)
108 TRANS64(LDX, do_ldst_X, false, false, MO_Q)
109 TRANS64(LDU, do_ldst_D, true, false, MO_Q)
110 TRANS64(LDUX, do_ldst_X, true, false, MO_Q)
111 TRANS64(PLD, do_ldst_PLS_D, false, false, MO_Q)
113 /* Store Byte */
114 TRANS(STB, do_ldst_D, false, true, MO_UB)
115 TRANS(STBX, do_ldst_X, false, true, MO_UB)
116 TRANS(STBU, do_ldst_D, true, true, MO_UB)
117 TRANS(STBUX, do_ldst_X, true, true, MO_UB)
118 TRANS(PSTB, do_ldst_PLS_D, false, true, MO_UB)
120 /* Store Halfword */
121 TRANS(STH, do_ldst_D, false, true, MO_UW)
122 TRANS(STHX, do_ldst_X, false, true, MO_UW)
123 TRANS(STHU, do_ldst_D, true, true, MO_UW)
124 TRANS(STHUX, do_ldst_X, true, true, MO_UW)
125 TRANS(PSTH, do_ldst_PLS_D, false, true, MO_UW)
127 /* Store Word */
128 TRANS(STW, do_ldst_D, false, true, MO_UL)
129 TRANS(STWX, do_ldst_X, false, true, MO_UL)
130 TRANS(STWU, do_ldst_D, true, true, MO_UL)
131 TRANS(STWUX, do_ldst_X, true, true, MO_UL)
132 TRANS(PSTW, do_ldst_PLS_D, false, true, MO_UL)
134 /* Store Doubleword */
135 TRANS64(STD, do_ldst_D, false, true, MO_Q)
136 TRANS64(STDX, do_ldst_X, false, true, MO_Q)
137 TRANS64(STDU, do_ldst_D, true, true, MO_Q)
138 TRANS64(STDUX, do_ldst_X, true, true, MO_Q)
139 TRANS64(PSTD, do_ldst_PLS_D, false, true, MO_Q)
142  * Fixed-Point Compare Instructions
143  */
145 static bool do_cmp_X(DisasContext *ctx, arg_X_bfl *a, bool s)
147     if ((ctx->insns_flags & PPC_64B) == 0) {
148         /*
149          * For 32-bit implementations, The Programming Environments Manual says
150          * that "the L field must be cleared, otherwise the instruction form is
151          * invalid." It seems, however, that most 32-bit CPUs ignore invalid
152          * forms (e.g., section "Instruction Formats" of the 405 and 440
153          * manuals, "Integer Compare Instructions" of the 601 manual), with the
154          * notable exception of the e500 and e500mc, where L=1 was reported to
155          * cause an exception.
156          */
157         if (a->l) {
158             if ((ctx->insns_flags2 & PPC2_BOOKE206)) {
159                 /*
160                  * For 32-bit Book E v2.06 implementations (i.e. e500/e500mc),
161                  * generate an illegal instruction exception.
162                  */
163                 return false;
164             } else {
165                 qemu_log_mask(LOG_GUEST_ERROR,
166                         "Invalid form of CMP%s at 0x" TARGET_FMT_lx ", L = 1\n",
167                         s ? "" : "L", ctx->cia);
168             }
169         }
170         gen_op_cmp32(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf);
171         return true;
172     }
174     /* For 64-bit implementations, deal with bit L accordingly. */
175     if (a->l) {
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;
183 static bool do_cmp_D(DisasContext *ctx, arg_D_bf *a, bool s)
185     if ((ctx->insns_flags & PPC_64B) == 0) {
186         /*
187          * For 32-bit implementations, The Programming Environments Manual says
188          * that "the L field must be cleared, otherwise the instruction form is
189          * invalid." It seems, however, that most 32-bit CPUs ignore invalid
190          * forms (e.g., section "Instruction Formats" of the 405 and 440
191          * manuals, "Integer Compare Instructions" of the 601 manual), with the
192          * notable exception of the e500 and e500mc, where L=1 was reported to
193          * cause an exception.
194          */
195         if (a->l) {
196             if ((ctx->insns_flags2 & PPC2_BOOKE206)) {
197                 /*
198                  * For 32-bit Book E v2.06 implementations (i.e. e500/e500mc),
199                  * generate an illegal instruction exception.
200                  */
201                 return false;
202             } else {
203                 qemu_log_mask(LOG_GUEST_ERROR,
204                         "Invalid form of CMP%s at 0x" TARGET_FMT_lx ", L = 1\n",
205                         s ? "I" : "LI", ctx->cia);
206             }
207         }
208         gen_op_cmp32(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf);
209         return true;
210     }
212     /* For 64-bit implementations, deal with bit L accordingly. */
213     if (a->l) {
214         gen_op_cmp(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf);
215     } else {
216         gen_op_cmp32(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf);
217     }
218     return true;
221 TRANS(CMP, do_cmp_X, true);
222 TRANS(CMPL, do_cmp_X, false);
223 TRANS(CMPI, do_cmp_D, true);
224 TRANS(CMPLI, do_cmp_D, false);
227  * Fixed-Point Arithmetic Instructions
228  */
230 static bool trans_ADDI(DisasContext *ctx, arg_D *a)
232     if (a->ra) {
233         tcg_gen_addi_tl(cpu_gpr[a->rt], cpu_gpr[a->ra], a->si);
234     } else {
235         tcg_gen_movi_tl(cpu_gpr[a->rt], a->si);
236     }
237     return true;
240 static bool trans_PADDI(DisasContext *ctx, arg_PLS_D *a)
242     arg_D d;
243     if (!resolve_PLS_D(ctx, &d, a)) {
244         return true;
245     }
246     return trans_ADDI(ctx, &d);
249 static bool trans_ADDIS(DisasContext *ctx, arg_D *a)
251     a->si <<= 16;
252     return trans_ADDI(ctx, a);
255 static bool trans_ADDPCIS(DisasContext *ctx, arg_DX *a)
257     REQUIRE_INSNS_FLAGS2(ctx, ISA300);
258     tcg_gen_movi_tl(cpu_gpr[a->rt], ctx->base.pc_next + (a->d << 16));
259     return true;
262 static bool trans_INVALID(DisasContext *ctx, arg_INVALID *a)
264     gen_invalid(ctx);
265     return true;
268 static bool trans_PNOP(DisasContext *ctx, arg_PNOP *a)
270     return true;
273 static bool do_set_bool_cond(DisasContext *ctx, arg_X_bi *a, bool neg, bool rev)
275     REQUIRE_INSNS_FLAGS2(ctx, ISA310);
276     uint32_t mask = 0x08 >> (a->bi & 0x03);
277     TCGCond cond = rev ? TCG_COND_EQ : TCG_COND_NE;
278     TCGv temp = tcg_temp_new();
280     tcg_gen_extu_i32_tl(temp, cpu_crf[a->bi >> 2]);
281     tcg_gen_andi_tl(temp, temp, mask);
282     tcg_gen_setcondi_tl(cond, cpu_gpr[a->rt], temp, 0);
283     if (neg) {
284         tcg_gen_neg_tl(cpu_gpr[a->rt], cpu_gpr[a->rt]);
285     }
286     tcg_temp_free(temp);
288     return true;
291 TRANS(SETBC, do_set_bool_cond, false, false)
292 TRANS(SETBCR, do_set_bool_cond, false, true)
293 TRANS(SETNBC, do_set_bool_cond, true, false)
294 TRANS(SETNBCR, do_set_bool_cond, true, true)
296 static bool trans_CFUGED(DisasContext *ctx, arg_X *a)
298     REQUIRE_64BIT(ctx);
299     REQUIRE_INSNS_FLAGS2(ctx, ISA310);
300 #if defined(TARGET_PPC64)
301     gen_helper_cfuged(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]);
302 #else
303     qemu_build_not_reached();
304 #endif
305     return true;