2 * Power ISA decode for Fixed-Point Facility instructions
4 * Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br)
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.
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.
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/>.
21 * Fixed-Point Load/Store Instructions
24 static bool do_ldst(DisasContext *ctx, int rt, int ra, TCGv displ, bool update,
25 bool store, MemOp mop)
29 if (update && (ra == 0 || (!store && ra == rt))) {
33 gen_set_access_type(ctx, ACCESS_INT);
35 ea = do_ea_calc(ctx, ra, displ);
36 mop ^= ctx->default_tcg_memop_mask;
38 tcg_gen_qemu_st_tl(cpu_gpr[rt], ea, ctx->mem_idx, mop);
40 tcg_gen_qemu_ld_tl(cpu_gpr[rt], ea, ctx->mem_idx, mop);
43 tcg_gen_mov_tl(cpu_gpr[ra], ea);
50 static bool do_ldst_D(DisasContext *ctx, arg_D *a, bool update, bool store,
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)
60 if (!resolve_PLS_D(ctx, &d, a)) {
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)
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)
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)
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
145 static bool do_cmp_X(DisasContext *ctx, arg_X_bfl *a, bool s)
147 if ((ctx->insns_flags & PPC_64B) == 0) {
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.
158 if ((ctx->insns_flags2 & PPC2_BOOKE206)) {
160 * For 32-bit Book E v2.06 implementations (i.e. e500/e500mc),
161 * generate an illegal instruction exception.
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);
170 gen_op_cmp32(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf);
174 /* For 64-bit implementations, deal with bit L accordingly. */
176 gen_op_cmp(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf);
178 gen_op_cmp32(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf);
183 static bool do_cmp_D(DisasContext *ctx, arg_D_bf *a, bool s)
185 if ((ctx->insns_flags & PPC_64B) == 0) {
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.
196 if ((ctx->insns_flags2 & PPC2_BOOKE206)) {
198 * For 32-bit Book E v2.06 implementations (i.e. e500/e500mc),
199 * generate an illegal instruction exception.
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);
208 gen_op_cmp32(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf);
212 /* For 64-bit implementations, deal with bit L accordingly. */
214 gen_op_cmp(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf);
216 gen_op_cmp32(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf);
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
230 static bool trans_ADDI(DisasContext *ctx, arg_D *a)
233 tcg_gen_addi_tl(cpu_gpr[a->rt], cpu_gpr[a->ra], a->si);
235 tcg_gen_movi_tl(cpu_gpr[a->rt], a->si);
240 static bool trans_PADDI(DisasContext *ctx, arg_PLS_D *a)
243 if (!resolve_PLS_D(ctx, &d, a)) {
246 return trans_ADDI(ctx, &d);
249 static bool trans_ADDIS(DisasContext *ctx, arg_D *a)
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));
262 static bool trans_INVALID(DisasContext *ctx, arg_INVALID *a)
268 static bool trans_PNOP(DisasContext *ctx, arg_PNOP *a)
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);
284 tcg_gen_neg_tl(cpu_gpr[a->rt], cpu_gpr[a->rt]);
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)
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]);
303 qemu_build_not_reached();