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 ((ctx->insns_flags & PPC_64B) == 0) { 175 /* 176 * For 32-bit implementations, The Programming Environments Manual says 177 * that "the L field must be cleared, otherwise the instruction form is 178 * invalid." It seems, however, that most 32-bit CPUs ignore invalid 179 * forms (e.g., section "Instruction Formats" of the 405 and 440 180 * manuals, "Integer Compare Instructions" of the 601 manual), with the 181 * notable exception of the e500 and e500mc, where L=1 was reported to 182 * cause an exception. 183 */ 184 if (a->l) { 185 if ((ctx->insns_flags2 & PPC2_BOOKE206)) { 186 /* 187 * For 32-bit Book E v2.06 implementations (i.e. e500/e500mc), 188 * generate an illegal instruction exception. 189 */ 190 return false; 191 } else { 192 qemu_log_mask(LOG_GUEST_ERROR, 193 "Invalid form of CMP%s at 0x" TARGET_FMT_lx ", L = 1\n", 194 s ? "" : "L", ctx->cia); 195 } 196 } 197 gen_op_cmp32(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf); 198 return true; 199 } 200 201 /* For 64-bit implementations, deal with bit L accordingly. */ 202 if (a->l) { 203 gen_op_cmp(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf); 204 } else { 205 gen_op_cmp32(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf); 206 } 207 return true; 208} 209 210static bool do_cmp_D(DisasContext *ctx, arg_D_bf *a, bool s) 211{ 212 if ((ctx->insns_flags & PPC_64B) == 0) { 213 /* 214 * For 32-bit implementations, The Programming Environments Manual says 215 * that "the L field must be cleared, otherwise the instruction form is 216 * invalid." It seems, however, that most 32-bit CPUs ignore invalid 217 * forms (e.g., section "Instruction Formats" of the 405 and 440 218 * manuals, "Integer Compare Instructions" of the 601 manual), with the 219 * notable exception of the e500 and e500mc, where L=1 was reported to 220 * cause an exception. 221 */ 222 if (a->l) { 223 if ((ctx->insns_flags2 & PPC2_BOOKE206)) { 224 /* 225 * For 32-bit Book E v2.06 implementations (i.e. e500/e500mc), 226 * generate an illegal instruction exception. 227 */ 228 return false; 229 } else { 230 qemu_log_mask(LOG_GUEST_ERROR, 231 "Invalid form of CMP%s at 0x" TARGET_FMT_lx ", L = 1\n", 232 s ? "I" : "LI", ctx->cia); 233 } 234 } 235 gen_op_cmp32(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf); 236 return true; 237 } 238 239 /* For 64-bit implementations, deal with bit L accordingly. */ 240 if (a->l) { 241 gen_op_cmp(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf); 242 } else { 243 gen_op_cmp32(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf); 244 } 245 return true; 246} 247 248TRANS(CMP, do_cmp_X, true); 249TRANS(CMPL, do_cmp_X, false); 250TRANS(CMPI, do_cmp_D, true); 251TRANS(CMPLI, do_cmp_D, false); 252 253/* 254 * Fixed-Point Arithmetic Instructions 255 */ 256 257static bool trans_ADDI(DisasContext *ctx, arg_D *a) 258{ 259 if (a->ra) { 260 tcg_gen_addi_tl(cpu_gpr[a->rt], cpu_gpr[a->ra], a->si); 261 } else { 262 tcg_gen_movi_tl(cpu_gpr[a->rt], a->si); 263 } 264 return true; 265} 266 267static bool trans_PADDI(DisasContext *ctx, arg_PLS_D *a) 268{ 269 arg_D d; 270 if (!resolve_PLS_D(ctx, &d, a)) { 271 return true; 272 } 273 return trans_ADDI(ctx, &d); 274} 275 276static bool trans_ADDIS(DisasContext *ctx, arg_D *a) 277{ 278 a->si <<= 16; 279 return trans_ADDI(ctx, a); 280} 281 282static bool trans_ADDPCIS(DisasContext *ctx, arg_DX *a) 283{ 284 REQUIRE_INSNS_FLAGS2(ctx, ISA300); 285 tcg_gen_movi_tl(cpu_gpr[a->rt], ctx->base.pc_next + (a->d << 16)); 286 return true; 287} 288 289static bool trans_INVALID(DisasContext *ctx, arg_INVALID *a) 290{ 291 gen_invalid(ctx); 292 return true; 293} 294 295static bool trans_PNOP(DisasContext *ctx, arg_PNOP *a) 296{ 297 return true; 298} 299 300static bool do_set_bool_cond(DisasContext *ctx, arg_X_bi *a, bool neg, bool rev) 301{ 302 REQUIRE_INSNS_FLAGS2(ctx, ISA310); 303 uint32_t mask = 0x08 >> (a->bi & 0x03); 304 TCGCond cond = rev ? TCG_COND_EQ : TCG_COND_NE; 305 TCGv temp = tcg_temp_new(); 306 307 tcg_gen_extu_i32_tl(temp, cpu_crf[a->bi >> 2]); 308 tcg_gen_andi_tl(temp, temp, mask); 309 tcg_gen_setcondi_tl(cond, cpu_gpr[a->rt], temp, 0); 310 if (neg) { 311 tcg_gen_neg_tl(cpu_gpr[a->rt], cpu_gpr[a->rt]); 312 } 313 tcg_temp_free(temp); 314 315 return true; 316} 317 318TRANS(SETBC, do_set_bool_cond, false, false) 319TRANS(SETBCR, do_set_bool_cond, false, true) 320TRANS(SETNBC, do_set_bool_cond, true, false) 321TRANS(SETNBCR, do_set_bool_cond, true, true) 322 323static bool trans_CFUGED(DisasContext *ctx, arg_X *a) 324{ 325 REQUIRE_64BIT(ctx); 326 REQUIRE_INSNS_FLAGS2(ctx, ISA310); 327#if defined(TARGET_PPC64) 328 gen_helper_cfuged(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]); 329#else 330 qemu_build_not_reached(); 331#endif 332 return true; 333} 334