199082815SRichard Henderson/* 299082815SRichard Henderson * Power ISA decode for Fixed-Point Facility instructions 399082815SRichard Henderson * 499082815SRichard Henderson * Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br) 599082815SRichard Henderson * 699082815SRichard Henderson * This library is free software; you can redistribute it and/or 799082815SRichard Henderson * modify it under the terms of the GNU Lesser General Public 899082815SRichard Henderson * License as published by the Free Software Foundation; either 999082815SRichard Henderson * version 2.1 of the License, or (at your option) any later version. 1099082815SRichard Henderson * 1199082815SRichard Henderson * This library is distributed in the hope that it will be useful, 1299082815SRichard Henderson * but WITHOUT ANY WARRANTY; without even the implied warranty of 1399082815SRichard Henderson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1499082815SRichard Henderson * Lesser General Public License for more details. 1599082815SRichard Henderson * 1699082815SRichard Henderson * You should have received a copy of the GNU Lesser General Public 1799082815SRichard Henderson * License along with this library; if not, see <http://www.gnu.org/licenses/>. 1899082815SRichard Henderson */ 195e560864SRichard Henderson 205e560864SRichard Henderson/* 21f2aabda8SRichard Henderson * Fixed-Point Load/Store Instructions 22f2aabda8SRichard Henderson */ 23f2aabda8SRichard Henderson 24f2aabda8SRichard Hendersonstatic bool do_ldst(DisasContext *ctx, int rt, int ra, TCGv displ, bool update, 25f2aabda8SRichard Henderson bool store, MemOp mop) 26f2aabda8SRichard Henderson{ 27f2aabda8SRichard Henderson TCGv ea; 28f2aabda8SRichard Henderson 29f2aabda8SRichard Henderson if (update && (ra == 0 || (!store && ra == rt))) { 30f2aabda8SRichard Henderson gen_invalid(ctx); 31f2aabda8SRichard Henderson return true; 32f2aabda8SRichard Henderson } 33f2aabda8SRichard Henderson gen_set_access_type(ctx, ACCESS_INT); 34f2aabda8SRichard Henderson 35eb63efd9SFernando Eckhardt Valle ea = do_ea_calc(ctx, ra, displ); 36f2aabda8SRichard Henderson mop ^= ctx->default_tcg_memop_mask; 37f2aabda8SRichard Henderson if (store) { 38f2aabda8SRichard Henderson tcg_gen_qemu_st_tl(cpu_gpr[rt], ea, ctx->mem_idx, mop); 39f2aabda8SRichard Henderson } else { 40f2aabda8SRichard Henderson tcg_gen_qemu_ld_tl(cpu_gpr[rt], ea, ctx->mem_idx, mop); 41f2aabda8SRichard Henderson } 42f2aabda8SRichard Henderson if (update) { 43f2aabda8SRichard Henderson tcg_gen_mov_tl(cpu_gpr[ra], ea); 44f2aabda8SRichard Henderson } 45f2aabda8SRichard Henderson tcg_temp_free(ea); 46f2aabda8SRichard Henderson 47f2aabda8SRichard Henderson return true; 48f2aabda8SRichard Henderson} 49f2aabda8SRichard Henderson 50f2aabda8SRichard Hendersonstatic bool do_ldst_D(DisasContext *ctx, arg_D *a, bool update, bool store, 51f2aabda8SRichard Henderson MemOp mop) 52f2aabda8SRichard Henderson{ 53f2aabda8SRichard Henderson return do_ldst(ctx, a->rt, a->ra, tcg_constant_tl(a->si), update, store, mop); 54f2aabda8SRichard Henderson} 55f2aabda8SRichard Henderson 5600e03265SRichard Hendersonstatic bool do_ldst_PLS_D(DisasContext *ctx, arg_PLS_D *a, bool update, 5700e03265SRichard Henderson bool store, MemOp mop) 5800e03265SRichard Henderson{ 5900e03265SRichard Henderson arg_D d; 6000e03265SRichard Henderson if (!resolve_PLS_D(ctx, &d, a)) { 6100e03265SRichard Henderson return true; 6200e03265SRichard Henderson } 6300e03265SRichard Henderson return do_ldst_D(ctx, &d, update, store, mop); 6400e03265SRichard Henderson} 6500e03265SRichard Henderson 66f2aabda8SRichard Hendersonstatic bool do_ldst_X(DisasContext *ctx, arg_X *a, bool update, 67f2aabda8SRichard Henderson bool store, MemOp mop) 68f2aabda8SRichard Henderson{ 69f2aabda8SRichard Henderson return do_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], update, store, mop); 70f2aabda8SRichard Henderson} 71f2aabda8SRichard Henderson 72e10271e1SMatheus Ferststatic bool do_ldst_quad(DisasContext *ctx, arg_D *a, bool store, bool prefixed) 73e10271e1SMatheus Ferst{ 74e10271e1SMatheus Ferst#if defined(TARGET_PPC64) 75e10271e1SMatheus Ferst TCGv ea; 76e10271e1SMatheus Ferst TCGv_i64 low_addr_gpr, high_addr_gpr; 77e10271e1SMatheus Ferst MemOp mop; 78e10271e1SMatheus Ferst 79e10271e1SMatheus Ferst REQUIRE_INSNS_FLAGS(ctx, 64BX); 80e10271e1SMatheus Ferst 81e10271e1SMatheus Ferst if (!prefixed && !(ctx->insns_flags2 & PPC2_LSQ_ISA207)) { 82e10271e1SMatheus Ferst /* lq and stq were privileged prior to V. 2.07 */ 83fc34e81aSMatheus Ferst REQUIRE_SV(ctx); 84e10271e1SMatheus Ferst 85e10271e1SMatheus Ferst if (ctx->le_mode) { 86e10271e1SMatheus Ferst gen_align_no_le(ctx); 87e10271e1SMatheus Ferst return true; 88e10271e1SMatheus Ferst } 89e10271e1SMatheus Ferst } 90e10271e1SMatheus Ferst 91e10271e1SMatheus Ferst if (!store && unlikely(a->ra == a->rt)) { 92e10271e1SMatheus Ferst gen_invalid(ctx); 93e10271e1SMatheus Ferst return true; 94e10271e1SMatheus Ferst } 95e10271e1SMatheus Ferst 96e10271e1SMatheus Ferst gen_set_access_type(ctx, ACCESS_INT); 97e10271e1SMatheus Ferst ea = do_ea_calc(ctx, a->ra, tcg_constant_tl(a->si)); 98e10271e1SMatheus Ferst 99e10271e1SMatheus Ferst if (prefixed || !ctx->le_mode) { 100e10271e1SMatheus Ferst low_addr_gpr = cpu_gpr[a->rt]; 101e10271e1SMatheus Ferst high_addr_gpr = cpu_gpr[a->rt + 1]; 102e10271e1SMatheus Ferst } else { 103e10271e1SMatheus Ferst low_addr_gpr = cpu_gpr[a->rt + 1]; 104e10271e1SMatheus Ferst high_addr_gpr = cpu_gpr[a->rt]; 105e10271e1SMatheus Ferst } 106e10271e1SMatheus Ferst 107e10271e1SMatheus Ferst if (tb_cflags(ctx->base.tb) & CF_PARALLEL) { 108e10271e1SMatheus Ferst if (HAVE_ATOMIC128) { 109e10271e1SMatheus Ferst mop = DEF_MEMOP(MO_128); 110e10271e1SMatheus Ferst TCGv_i32 oi = tcg_constant_i32(make_memop_idx(mop, ctx->mem_idx)); 111e10271e1SMatheus Ferst if (store) { 112e10271e1SMatheus Ferst if (ctx->le_mode) { 113e10271e1SMatheus Ferst gen_helper_stq_le_parallel(cpu_env, ea, low_addr_gpr, 114e10271e1SMatheus Ferst high_addr_gpr, oi); 115e10271e1SMatheus Ferst } else { 116e10271e1SMatheus Ferst gen_helper_stq_be_parallel(cpu_env, ea, high_addr_gpr, 117e10271e1SMatheus Ferst low_addr_gpr, oi); 118e10271e1SMatheus Ferst 119e10271e1SMatheus Ferst } 120e10271e1SMatheus Ferst } else { 121e10271e1SMatheus Ferst if (ctx->le_mode) { 122e10271e1SMatheus Ferst gen_helper_lq_le_parallel(low_addr_gpr, cpu_env, ea, oi); 123e10271e1SMatheus Ferst tcg_gen_ld_i64(high_addr_gpr, cpu_env, 124e10271e1SMatheus Ferst offsetof(CPUPPCState, retxh)); 125e10271e1SMatheus Ferst } else { 126e10271e1SMatheus Ferst gen_helper_lq_be_parallel(high_addr_gpr, cpu_env, ea, oi); 127e10271e1SMatheus Ferst tcg_gen_ld_i64(low_addr_gpr, cpu_env, 128e10271e1SMatheus Ferst offsetof(CPUPPCState, retxh)); 129e10271e1SMatheus Ferst } 130e10271e1SMatheus Ferst } 131e10271e1SMatheus Ferst } else { 132e10271e1SMatheus Ferst /* Restart with exclusive lock. */ 133e10271e1SMatheus Ferst gen_helper_exit_atomic(cpu_env); 134e10271e1SMatheus Ferst ctx->base.is_jmp = DISAS_NORETURN; 135e10271e1SMatheus Ferst } 136e10271e1SMatheus Ferst } else { 137fc313c64SFrédéric Pétrot mop = DEF_MEMOP(MO_UQ); 138e10271e1SMatheus Ferst if (store) { 139e10271e1SMatheus Ferst tcg_gen_qemu_st_i64(low_addr_gpr, ea, ctx->mem_idx, mop); 140e10271e1SMatheus Ferst } else { 141e10271e1SMatheus Ferst tcg_gen_qemu_ld_i64(low_addr_gpr, ea, ctx->mem_idx, mop); 142e10271e1SMatheus Ferst } 143e10271e1SMatheus Ferst 144e10271e1SMatheus Ferst gen_addr_add(ctx, ea, ea, 8); 145e10271e1SMatheus Ferst 146e10271e1SMatheus Ferst if (store) { 147e10271e1SMatheus Ferst tcg_gen_qemu_st_i64(high_addr_gpr, ea, ctx->mem_idx, mop); 148e10271e1SMatheus Ferst } else { 149e10271e1SMatheus Ferst tcg_gen_qemu_ld_i64(high_addr_gpr, ea, ctx->mem_idx, mop); 150e10271e1SMatheus Ferst } 151e10271e1SMatheus Ferst } 152e10271e1SMatheus Ferst tcg_temp_free(ea); 153e10271e1SMatheus Ferst#else 154e10271e1SMatheus Ferst qemu_build_not_reached(); 155e10271e1SMatheus Ferst#endif 156e10271e1SMatheus Ferst 157e10271e1SMatheus Ferst return true; 158e10271e1SMatheus Ferst} 159e10271e1SMatheus Ferst 16049de0648SMatheus Ferststatic bool do_ldst_quad_PLS_D(DisasContext *ctx, arg_PLS_D *a, bool store) 16149de0648SMatheus Ferst{ 16249de0648SMatheus Ferst arg_D d; 16349de0648SMatheus Ferst if (!resolve_PLS_D(ctx, &d, a)) { 16449de0648SMatheus Ferst return true; 16549de0648SMatheus Ferst } 16649de0648SMatheus Ferst 16749de0648SMatheus Ferst return do_ldst_quad(ctx, &d, store, true); 16849de0648SMatheus Ferst} 16949de0648SMatheus Ferst 170f2aabda8SRichard Henderson/* Load Byte and Zero */ 171f2aabda8SRichard HendersonTRANS(LBZ, do_ldst_D, false, false, MO_UB) 172f2aabda8SRichard HendersonTRANS(LBZX, do_ldst_X, false, false, MO_UB) 173f2aabda8SRichard HendersonTRANS(LBZU, do_ldst_D, true, false, MO_UB) 174f2aabda8SRichard HendersonTRANS(LBZUX, do_ldst_X, true, false, MO_UB) 17500e03265SRichard HendersonTRANS(PLBZ, do_ldst_PLS_D, false, false, MO_UB) 176f2aabda8SRichard Henderson 177f2aabda8SRichard Henderson/* Load Halfword and Zero */ 178f2aabda8SRichard HendersonTRANS(LHZ, do_ldst_D, false, false, MO_UW) 179f2aabda8SRichard HendersonTRANS(LHZX, do_ldst_X, false, false, MO_UW) 180f2aabda8SRichard HendersonTRANS(LHZU, do_ldst_D, true, false, MO_UW) 181f2aabda8SRichard HendersonTRANS(LHZUX, do_ldst_X, true, false, MO_UW) 18200e03265SRichard HendersonTRANS(PLHZ, do_ldst_PLS_D, false, false, MO_UW) 183f2aabda8SRichard Henderson 184f2aabda8SRichard Henderson/* Load Halfword Algebraic */ 185f2aabda8SRichard HendersonTRANS(LHA, do_ldst_D, false, false, MO_SW) 186f2aabda8SRichard HendersonTRANS(LHAX, do_ldst_X, false, false, MO_SW) 187f2aabda8SRichard HendersonTRANS(LHAU, do_ldst_D, true, false, MO_SW) 188f2aabda8SRichard HendersonTRANS(LHAXU, do_ldst_X, true, false, MO_SW) 18900e03265SRichard HendersonTRANS(PLHA, do_ldst_PLS_D, false, false, MO_SW) 190f2aabda8SRichard Henderson 191f2aabda8SRichard Henderson/* Load Word and Zero */ 192f2aabda8SRichard HendersonTRANS(LWZ, do_ldst_D, false, false, MO_UL) 193f2aabda8SRichard HendersonTRANS(LWZX, do_ldst_X, false, false, MO_UL) 194f2aabda8SRichard HendersonTRANS(LWZU, do_ldst_D, true, false, MO_UL) 195f2aabda8SRichard HendersonTRANS(LWZUX, do_ldst_X, true, false, MO_UL) 19600e03265SRichard HendersonTRANS(PLWZ, do_ldst_PLS_D, false, false, MO_UL) 197f2aabda8SRichard Henderson 198f2aabda8SRichard Henderson/* Load Word Algebraic */ 199f2aabda8SRichard HendersonTRANS64(LWA, do_ldst_D, false, false, MO_SL) 200f2aabda8SRichard HendersonTRANS64(LWAX, do_ldst_X, false, false, MO_SL) 201f2aabda8SRichard HendersonTRANS64(LWAUX, do_ldst_X, true, false, MO_SL) 20200e03265SRichard HendersonTRANS64(PLWA, do_ldst_PLS_D, false, false, MO_SL) 203f2aabda8SRichard Henderson 204f2aabda8SRichard Henderson/* Load Doubleword */ 205fc313c64SFrédéric PétrotTRANS64(LD, do_ldst_D, false, false, MO_UQ) 206fc313c64SFrédéric PétrotTRANS64(LDX, do_ldst_X, false, false, MO_UQ) 207fc313c64SFrédéric PétrotTRANS64(LDU, do_ldst_D, true, false, MO_UQ) 208fc313c64SFrédéric PétrotTRANS64(LDUX, do_ldst_X, true, false, MO_UQ) 209fc313c64SFrédéric PétrotTRANS64(PLD, do_ldst_PLS_D, false, false, MO_UQ) 210f2aabda8SRichard Henderson 211e10271e1SMatheus Ferst/* Load Quadword */ 212e10271e1SMatheus FerstTRANS64(LQ, do_ldst_quad, false, false); 21349de0648SMatheus FerstTRANS64(PLQ, do_ldst_quad_PLS_D, false); 214e10271e1SMatheus Ferst 215e8f4c8d6SRichard Henderson/* Store Byte */ 216e8f4c8d6SRichard HendersonTRANS(STB, do_ldst_D, false, true, MO_UB) 217e8f4c8d6SRichard HendersonTRANS(STBX, do_ldst_X, false, true, MO_UB) 218e8f4c8d6SRichard HendersonTRANS(STBU, do_ldst_D, true, true, MO_UB) 219e8f4c8d6SRichard HendersonTRANS(STBUX, do_ldst_X, true, true, MO_UB) 220b0f7bebcSRichard HendersonTRANS(PSTB, do_ldst_PLS_D, false, true, MO_UB) 221e8f4c8d6SRichard Henderson 222e8f4c8d6SRichard Henderson/* Store Halfword */ 223e8f4c8d6SRichard HendersonTRANS(STH, do_ldst_D, false, true, MO_UW) 224e8f4c8d6SRichard HendersonTRANS(STHX, do_ldst_X, false, true, MO_UW) 225e8f4c8d6SRichard HendersonTRANS(STHU, do_ldst_D, true, true, MO_UW) 226e8f4c8d6SRichard HendersonTRANS(STHUX, do_ldst_X, true, true, MO_UW) 227b0f7bebcSRichard HendersonTRANS(PSTH, do_ldst_PLS_D, false, true, MO_UW) 228e8f4c8d6SRichard Henderson 229e8f4c8d6SRichard Henderson/* Store Word */ 230e8f4c8d6SRichard HendersonTRANS(STW, do_ldst_D, false, true, MO_UL) 231e8f4c8d6SRichard HendersonTRANS(STWX, do_ldst_X, false, true, MO_UL) 232e8f4c8d6SRichard HendersonTRANS(STWU, do_ldst_D, true, true, MO_UL) 233e8f4c8d6SRichard HendersonTRANS(STWUX, do_ldst_X, true, true, MO_UL) 234b0f7bebcSRichard HendersonTRANS(PSTW, do_ldst_PLS_D, false, true, MO_UL) 235e8f4c8d6SRichard Henderson 236e8f4c8d6SRichard Henderson/* Store Doubleword */ 237fc313c64SFrédéric PétrotTRANS64(STD, do_ldst_D, false, true, MO_UQ) 238fc313c64SFrédéric PétrotTRANS64(STDX, do_ldst_X, false, true, MO_UQ) 239fc313c64SFrédéric PétrotTRANS64(STDU, do_ldst_D, true, true, MO_UQ) 240fc313c64SFrédéric PétrotTRANS64(STDUX, do_ldst_X, true, true, MO_UQ) 241fc313c64SFrédéric PétrotTRANS64(PSTD, do_ldst_PLS_D, false, true, MO_UQ) 242e8f4c8d6SRichard Henderson 243e10271e1SMatheus Ferst/* Store Quadword */ 244e10271e1SMatheus FerstTRANS64(STQ, do_ldst_quad, true, false); 24549de0648SMatheus FerstTRANS64(PSTQ, do_ldst_quad_PLS_D, true); 246e10271e1SMatheus Ferst 247f2aabda8SRichard Henderson/* 2488f0a4b6aSMatheus Ferst * Fixed-Point Compare Instructions 2498f0a4b6aSMatheus Ferst */ 2508f0a4b6aSMatheus Ferst 2518f0a4b6aSMatheus Ferststatic bool do_cmp_X(DisasContext *ctx, arg_X_bfl *a, bool s) 2528f0a4b6aSMatheus Ferst{ 2532d1154bdSMatheus Ferst if ((ctx->insns_flags & PPC_64B) == 0) { 2542d1154bdSMatheus Ferst /* 2552d1154bdSMatheus Ferst * For 32-bit implementations, The Programming Environments Manual says 2562d1154bdSMatheus Ferst * that "the L field must be cleared, otherwise the instruction form is 2572d1154bdSMatheus Ferst * invalid." It seems, however, that most 32-bit CPUs ignore invalid 2582d1154bdSMatheus Ferst * forms (e.g., section "Instruction Formats" of the 405 and 440 2592d1154bdSMatheus Ferst * manuals, "Integer Compare Instructions" of the 601 manual), with the 2602d1154bdSMatheus Ferst * notable exception of the e500 and e500mc, where L=1 was reported to 2612d1154bdSMatheus Ferst * cause an exception. 2622d1154bdSMatheus Ferst */ 2638f0a4b6aSMatheus Ferst if (a->l) { 2642d1154bdSMatheus Ferst if ((ctx->insns_flags2 & PPC2_BOOKE206)) { 2652d1154bdSMatheus Ferst /* 2662d1154bdSMatheus Ferst * For 32-bit Book E v2.06 implementations (i.e. e500/e500mc), 2672d1154bdSMatheus Ferst * generate an illegal instruction exception. 2682d1154bdSMatheus Ferst */ 2692d1154bdSMatheus Ferst return false; 2702d1154bdSMatheus Ferst } else { 2712d1154bdSMatheus Ferst qemu_log_mask(LOG_GUEST_ERROR, 2722d1154bdSMatheus Ferst "Invalid form of CMP%s at 0x" TARGET_FMT_lx ", L = 1\n", 2732d1154bdSMatheus Ferst s ? "" : "L", ctx->cia); 2742d1154bdSMatheus Ferst } 2752d1154bdSMatheus Ferst } 2762d1154bdSMatheus Ferst gen_op_cmp32(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf); 2772d1154bdSMatheus Ferst return true; 2782d1154bdSMatheus Ferst } 2792d1154bdSMatheus Ferst 2802d1154bdSMatheus Ferst /* For 64-bit implementations, deal with bit L accordingly. */ 2812d1154bdSMatheus Ferst if (a->l) { 2828f0a4b6aSMatheus Ferst gen_op_cmp(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf); 2838f0a4b6aSMatheus Ferst } else { 2848f0a4b6aSMatheus Ferst gen_op_cmp32(cpu_gpr[a->ra], cpu_gpr[a->rb], s, a->bf); 2858f0a4b6aSMatheus Ferst } 2868f0a4b6aSMatheus Ferst return true; 2878f0a4b6aSMatheus Ferst} 2888f0a4b6aSMatheus Ferst 2898f0a4b6aSMatheus Ferststatic bool do_cmp_D(DisasContext *ctx, arg_D_bf *a, bool s) 2908f0a4b6aSMatheus Ferst{ 2912d1154bdSMatheus Ferst if ((ctx->insns_flags & PPC_64B) == 0) { 2922d1154bdSMatheus Ferst /* 2932d1154bdSMatheus Ferst * For 32-bit implementations, The Programming Environments Manual says 2942d1154bdSMatheus Ferst * that "the L field must be cleared, otherwise the instruction form is 2952d1154bdSMatheus Ferst * invalid." It seems, however, that most 32-bit CPUs ignore invalid 2962d1154bdSMatheus Ferst * forms (e.g., section "Instruction Formats" of the 405 and 440 2972d1154bdSMatheus Ferst * manuals, "Integer Compare Instructions" of the 601 manual), with the 2982d1154bdSMatheus Ferst * notable exception of the e500 and e500mc, where L=1 was reported to 2992d1154bdSMatheus Ferst * cause an exception. 3002d1154bdSMatheus Ferst */ 3018f0a4b6aSMatheus Ferst if (a->l) { 3022d1154bdSMatheus Ferst if ((ctx->insns_flags2 & PPC2_BOOKE206)) { 3032d1154bdSMatheus Ferst /* 3042d1154bdSMatheus Ferst * For 32-bit Book E v2.06 implementations (i.e. e500/e500mc), 3052d1154bdSMatheus Ferst * generate an illegal instruction exception. 3062d1154bdSMatheus Ferst */ 3072d1154bdSMatheus Ferst return false; 3082d1154bdSMatheus Ferst } else { 3092d1154bdSMatheus Ferst qemu_log_mask(LOG_GUEST_ERROR, 3102d1154bdSMatheus Ferst "Invalid form of CMP%s at 0x" TARGET_FMT_lx ", L = 1\n", 3112d1154bdSMatheus Ferst s ? "I" : "LI", ctx->cia); 3122d1154bdSMatheus Ferst } 3132d1154bdSMatheus Ferst } 3142d1154bdSMatheus Ferst gen_op_cmp32(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf); 3152d1154bdSMatheus Ferst return true; 3162d1154bdSMatheus Ferst } 3172d1154bdSMatheus Ferst 3182d1154bdSMatheus Ferst /* For 64-bit implementations, deal with bit L accordingly. */ 3192d1154bdSMatheus Ferst if (a->l) { 3208f0a4b6aSMatheus Ferst gen_op_cmp(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf); 3218f0a4b6aSMatheus Ferst } else { 3228f0a4b6aSMatheus Ferst gen_op_cmp32(cpu_gpr[a->ra], tcg_constant_tl(a->imm), s, a->bf); 3238f0a4b6aSMatheus Ferst } 3248f0a4b6aSMatheus Ferst return true; 3258f0a4b6aSMatheus Ferst} 3268f0a4b6aSMatheus Ferst 3278f0a4b6aSMatheus FerstTRANS(CMP, do_cmp_X, true); 3288f0a4b6aSMatheus FerstTRANS(CMPL, do_cmp_X, false); 3298f0a4b6aSMatheus FerstTRANS(CMPI, do_cmp_D, true); 3308f0a4b6aSMatheus FerstTRANS(CMPLI, do_cmp_D, false); 3318f0a4b6aSMatheus Ferst 3328f0a4b6aSMatheus Ferst/* 333f2aabda8SRichard Henderson * Fixed-Point Arithmetic Instructions 334f2aabda8SRichard Henderson */ 335f2aabda8SRichard Henderson 3365e560864SRichard Hendersonstatic bool trans_ADDI(DisasContext *ctx, arg_D *a) 3375e560864SRichard Henderson{ 3385e560864SRichard Henderson if (a->ra) { 3395e560864SRichard Henderson tcg_gen_addi_tl(cpu_gpr[a->rt], cpu_gpr[a->ra], a->si); 3405e560864SRichard Henderson } else { 3415e560864SRichard Henderson tcg_gen_movi_tl(cpu_gpr[a->rt], a->si); 3425e560864SRichard Henderson } 3435e560864SRichard Henderson return true; 3445e560864SRichard Henderson} 3455e560864SRichard Henderson 3465e560864SRichard Hendersonstatic bool trans_PADDI(DisasContext *ctx, arg_PLS_D *a) 3475e560864SRichard Henderson{ 3485e560864SRichard Henderson arg_D d; 3495e560864SRichard Henderson if (!resolve_PLS_D(ctx, &d, a)) { 3505e560864SRichard Henderson return true; 3515e560864SRichard Henderson } 3525e560864SRichard Henderson return trans_ADDI(ctx, &d); 3535e560864SRichard Henderson} 3545e560864SRichard Henderson 3555e560864SRichard Hendersonstatic bool trans_ADDIS(DisasContext *ctx, arg_D *a) 3565e560864SRichard Henderson{ 3575e560864SRichard Henderson a->si <<= 16; 3585e560864SRichard Henderson return trans_ADDI(ctx, a); 3595e560864SRichard Henderson} 3600a11bb7aSRichard Henderson 361e7a5d578SMatheus Ferststatic bool trans_ADDPCIS(DisasContext *ctx, arg_DX *a) 362e7a5d578SMatheus Ferst{ 363e7a5d578SMatheus Ferst REQUIRE_INSNS_FLAGS2(ctx, ISA300); 364e7a5d578SMatheus Ferst tcg_gen_movi_tl(cpu_gpr[a->rt], ctx->base.pc_next + (a->d << 16)); 365e7a5d578SMatheus Ferst return true; 366e7a5d578SMatheus Ferst} 367e7a5d578SMatheus Ferst 3680a11bb7aSRichard Hendersonstatic bool trans_INVALID(DisasContext *ctx, arg_INVALID *a) 3690a11bb7aSRichard Henderson{ 3700a11bb7aSRichard Henderson gen_invalid(ctx); 3710a11bb7aSRichard Henderson return true; 3720a11bb7aSRichard Henderson} 3730a11bb7aSRichard Henderson 3740a11bb7aSRichard Hendersonstatic bool trans_PNOP(DisasContext *ctx, arg_PNOP *a) 3750a11bb7aSRichard Henderson{ 3760a11bb7aSRichard Henderson return true; 3770a11bb7aSRichard Henderson} 3789a14365eSMatheus Ferst 3799a14365eSMatheus Ferststatic bool do_set_bool_cond(DisasContext *ctx, arg_X_bi *a, bool neg, bool rev) 3809a14365eSMatheus Ferst{ 3819a14365eSMatheus Ferst REQUIRE_INSNS_FLAGS2(ctx, ISA310); 3829a14365eSMatheus Ferst uint32_t mask = 0x08 >> (a->bi & 0x03); 3839a14365eSMatheus Ferst TCGCond cond = rev ? TCG_COND_EQ : TCG_COND_NE; 3849a14365eSMatheus Ferst TCGv temp = tcg_temp_new(); 3859a14365eSMatheus Ferst 3869a14365eSMatheus Ferst tcg_gen_extu_i32_tl(temp, cpu_crf[a->bi >> 2]); 3879a14365eSMatheus Ferst tcg_gen_andi_tl(temp, temp, mask); 3889a14365eSMatheus Ferst tcg_gen_setcondi_tl(cond, cpu_gpr[a->rt], temp, 0); 3899a14365eSMatheus Ferst if (neg) { 3909a14365eSMatheus Ferst tcg_gen_neg_tl(cpu_gpr[a->rt], cpu_gpr[a->rt]); 3919a14365eSMatheus Ferst } 3929a14365eSMatheus Ferst tcg_temp_free(temp); 3939a14365eSMatheus Ferst 3949a14365eSMatheus Ferst return true; 3959a14365eSMatheus Ferst} 3969a14365eSMatheus Ferst 3979a14365eSMatheus FerstTRANS(SETBC, do_set_bool_cond, false, false) 3989a14365eSMatheus FerstTRANS(SETBCR, do_set_bool_cond, false, true) 3999a14365eSMatheus FerstTRANS(SETNBC, do_set_bool_cond, true, false) 4009a14365eSMatheus FerstTRANS(SETNBCR, do_set_bool_cond, true, true) 40189ccd7dcSMatheus Ferst 40289ccd7dcSMatheus Ferststatic bool trans_CFUGED(DisasContext *ctx, arg_X *a) 40389ccd7dcSMatheus Ferst{ 40489ccd7dcSMatheus Ferst REQUIRE_64BIT(ctx); 40589ccd7dcSMatheus Ferst REQUIRE_INSNS_FLAGS2(ctx, ISA310); 40689ccd7dcSMatheus Ferst#if defined(TARGET_PPC64) 4076e0bbc40SMatheus Ferst gen_helper_CFUGED(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]); 40889ccd7dcSMatheus Ferst#else 40989ccd7dcSMatheus Ferst qemu_build_not_reached(); 41089ccd7dcSMatheus Ferst#endif 41189ccd7dcSMatheus Ferst return true; 41289ccd7dcSMatheus Ferst} 41382be6e02SLuis Pires 414a2c975e1SMatheus Ferststatic void do_cntzdm(TCGv_i64 dst, TCGv_i64 src, TCGv_i64 mask, int64_t trail) 41582be6e02SLuis Pires{ 416ab1e25adSMatheus Ferst TCGv_i64 t0, t1; 41782be6e02SLuis Pires 418ab1e25adSMatheus Ferst t0 = tcg_temp_new_i64(); 419ab1e25adSMatheus Ferst t1 = tcg_temp_new_i64(); 42082be6e02SLuis Pires 421ab1e25adSMatheus Ferst tcg_gen_and_i64(t0, src, mask); 422f356b3baSLuis Pires if (trail) { 423ab1e25adSMatheus Ferst tcg_gen_ctzi_i64(t0, t0, -1); 424f356b3baSLuis Pires } else { 425ab1e25adSMatheus Ferst tcg_gen_clzi_i64(t0, t0, -1); 426f356b3baSLuis Pires } 42782be6e02SLuis Pires 428ab1e25adSMatheus Ferst tcg_gen_setcondi_i64(TCG_COND_NE, t1, t0, -1); 429ab1e25adSMatheus Ferst tcg_gen_andi_i64(t0, t0, 63); 430ab1e25adSMatheus Ferst tcg_gen_xori_i64(t0, t0, 63); 431f356b3baSLuis Pires if (trail) { 432ab1e25adSMatheus Ferst tcg_gen_shl_i64(t0, mask, t0); 433ab1e25adSMatheus Ferst tcg_gen_shl_i64(t0, t0, t1); 434f356b3baSLuis Pires } else { 435ab1e25adSMatheus Ferst tcg_gen_shr_i64(t0, mask, t0); 436ab1e25adSMatheus Ferst tcg_gen_shr_i64(t0, t0, t1); 437f356b3baSLuis Pires } 43882be6e02SLuis Pires 439ab1e25adSMatheus Ferst tcg_gen_ctpop_i64(dst, t0); 44082be6e02SLuis Pires 441ab1e25adSMatheus Ferst tcg_temp_free_i64(t0); 442ab1e25adSMatheus Ferst tcg_temp_free_i64(t1); 44382be6e02SLuis Pires} 44482be6e02SLuis Pires 44582be6e02SLuis Piresstatic bool trans_CNTLZDM(DisasContext *ctx, arg_X *a) 44682be6e02SLuis Pires{ 44782be6e02SLuis Pires REQUIRE_64BIT(ctx); 44882be6e02SLuis Pires REQUIRE_INSNS_FLAGS2(ctx, ISA310); 44982be6e02SLuis Pires#if defined(TARGET_PPC64) 450f356b3baSLuis Pires do_cntzdm(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb], false); 451f356b3baSLuis Pires#else 452f356b3baSLuis Pires qemu_build_not_reached(); 453f356b3baSLuis Pires#endif 454f356b3baSLuis Pires return true; 455f356b3baSLuis Pires} 456f356b3baSLuis Pires 457f356b3baSLuis Piresstatic bool trans_CNTTZDM(DisasContext *ctx, arg_X *a) 458f356b3baSLuis Pires{ 459f356b3baSLuis Pires REQUIRE_64BIT(ctx); 460f356b3baSLuis Pires REQUIRE_INSNS_FLAGS2(ctx, ISA310); 461f356b3baSLuis Pires#if defined(TARGET_PPC64) 462f356b3baSLuis Pires do_cntzdm(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb], true); 46382be6e02SLuis Pires#else 46482be6e02SLuis Pires qemu_build_not_reached(); 46582be6e02SLuis Pires#endif 46682be6e02SLuis Pires return true; 46782be6e02SLuis Pires} 46821ba6e58SMatheus Ferst 46921ba6e58SMatheus Ferststatic bool trans_PDEPD(DisasContext *ctx, arg_X *a) 47021ba6e58SMatheus Ferst{ 47121ba6e58SMatheus Ferst REQUIRE_64BIT(ctx); 47221ba6e58SMatheus Ferst REQUIRE_INSNS_FLAGS2(ctx, ISA310); 47321ba6e58SMatheus Ferst#if defined(TARGET_PPC64) 47421ba6e58SMatheus Ferst gen_helper_PDEPD(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]); 47521ba6e58SMatheus Ferst#else 47621ba6e58SMatheus Ferst qemu_build_not_reached(); 47721ba6e58SMatheus Ferst#endif 47821ba6e58SMatheus Ferst return true; 47921ba6e58SMatheus Ferst} 4808bdb7606SMatheus Ferst 4818bdb7606SMatheus Ferststatic bool trans_PEXTD(DisasContext *ctx, arg_X *a) 4828bdb7606SMatheus Ferst{ 4838bdb7606SMatheus Ferst REQUIRE_64BIT(ctx); 4848bdb7606SMatheus Ferst REQUIRE_INSNS_FLAGS2(ctx, ISA310); 4858bdb7606SMatheus Ferst#if defined(TARGET_PPC64) 4868bdb7606SMatheus Ferst gen_helper_PEXTD(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]); 4878bdb7606SMatheus Ferst#else 4888bdb7606SMatheus Ferst qemu_build_not_reached(); 4898bdb7606SMatheus Ferst#endif 4908bdb7606SMatheus Ferst return true; 4918bdb7606SMatheus Ferst} 4926addef4dSMatheus Ferst 4936addef4dSMatheus Ferststatic bool trans_ADDG6S(DisasContext *ctx, arg_X *a) 4946addef4dSMatheus Ferst{ 4956addef4dSMatheus Ferst const uint64_t carry_bits = 0x1111111111111111ULL; 4966addef4dSMatheus Ferst TCGv t0, t1, carry, zero = tcg_constant_tl(0); 4976addef4dSMatheus Ferst 4986addef4dSMatheus Ferst REQUIRE_INSNS_FLAGS2(ctx, BCDA_ISA206); 4996addef4dSMatheus Ferst 5006addef4dSMatheus Ferst t0 = tcg_temp_new(); 5016addef4dSMatheus Ferst t1 = tcg_const_tl(0); 5026addef4dSMatheus Ferst carry = tcg_const_tl(0); 5036addef4dSMatheus Ferst 5046addef4dSMatheus Ferst for (int i = 0; i < 16; i++) { 5056addef4dSMatheus Ferst tcg_gen_shri_tl(t0, cpu_gpr[a->ra], i * 4); 5066addef4dSMatheus Ferst tcg_gen_andi_tl(t0, t0, 0xf); 5076addef4dSMatheus Ferst tcg_gen_add_tl(t1, t1, t0); 5086addef4dSMatheus Ferst 5096addef4dSMatheus Ferst tcg_gen_shri_tl(t0, cpu_gpr[a->rb], i * 4); 5106addef4dSMatheus Ferst tcg_gen_andi_tl(t0, t0, 0xf); 5116addef4dSMatheus Ferst tcg_gen_add_tl(t1, t1, t0); 5126addef4dSMatheus Ferst 5136addef4dSMatheus Ferst tcg_gen_andi_tl(t1, t1, 0x10); 5146addef4dSMatheus Ferst tcg_gen_setcond_tl(TCG_COND_NE, t1, t1, zero); 5156addef4dSMatheus Ferst 5166addef4dSMatheus Ferst tcg_gen_shli_tl(t0, t1, i * 4); 5176addef4dSMatheus Ferst tcg_gen_or_tl(carry, carry, t0); 5186addef4dSMatheus Ferst } 5196addef4dSMatheus Ferst 5206addef4dSMatheus Ferst tcg_gen_xori_tl(carry, carry, (target_long)carry_bits); 5216addef4dSMatheus Ferst tcg_gen_muli_tl(cpu_gpr[a->rt], carry, 6); 5226addef4dSMatheus Ferst 5236addef4dSMatheus Ferst tcg_temp_free(t0); 5246addef4dSMatheus Ferst tcg_temp_free(t1); 5256addef4dSMatheus Ferst tcg_temp_free(carry); 5266addef4dSMatheus Ferst 5276addef4dSMatheus Ferst return true; 5286addef4dSMatheus Ferst} 52938d3690bSMatheus Ferst 5306b924d4aSMatheus Ferststatic bool trans_CDTBCD(DisasContext *ctx, arg_X_sa *a) 5316b924d4aSMatheus Ferst{ 5326b924d4aSMatheus Ferst REQUIRE_INSNS_FLAGS2(ctx, BCDA_ISA206); 5336b924d4aSMatheus Ferst gen_helper_CDTBCD(cpu_gpr[a->ra], cpu_gpr[a->rs]); 5346b924d4aSMatheus Ferst return true; 5356b924d4aSMatheus Ferst} 5366b924d4aSMatheus Ferst 53738d3690bSMatheus Ferststatic bool trans_CBCDTD(DisasContext *ctx, arg_X_sa *a) 53838d3690bSMatheus Ferst{ 53938d3690bSMatheus Ferst REQUIRE_INSNS_FLAGS2(ctx, BCDA_ISA206); 54038d3690bSMatheus Ferst gen_helper_CBCDTD(cpu_gpr[a->ra], cpu_gpr[a->rs]); 54138d3690bSMatheus Ferst return true; 54238d3690bSMatheus Ferst} 543*670f1da3SVíctor Colombo 544*670f1da3SVíctor Colombostatic bool do_hash(DisasContext *ctx, arg_X *a, bool priv, 545*670f1da3SVíctor Colombo void (*helper)(TCGv_ptr, TCGv, TCGv, TCGv)) 546*670f1da3SVíctor Colombo{ 547*670f1da3SVíctor Colombo TCGv ea; 548*670f1da3SVíctor Colombo 549*670f1da3SVíctor Colombo if (!(ctx->insns_flags2 & PPC2_ISA310)) { 550*670f1da3SVíctor Colombo /* if version is before v3.1, this operation is a nop */ 551*670f1da3SVíctor Colombo return true; 552*670f1da3SVíctor Colombo } 553*670f1da3SVíctor Colombo 554*670f1da3SVíctor Colombo if (priv) { 555*670f1da3SVíctor Colombo /* if instruction is privileged but the context is in user space */ 556*670f1da3SVíctor Colombo REQUIRE_SV(ctx); 557*670f1da3SVíctor Colombo } 558*670f1da3SVíctor Colombo 559*670f1da3SVíctor Colombo if (unlikely(a->ra == 0)) { 560*670f1da3SVíctor Colombo /* if RA=0, the instruction form is invalid */ 561*670f1da3SVíctor Colombo gen_invalid(ctx); 562*670f1da3SVíctor Colombo return true; 563*670f1da3SVíctor Colombo } 564*670f1da3SVíctor Colombo 565*670f1da3SVíctor Colombo ea = do_ea_calc(ctx, a->ra, tcg_constant_tl(a->rt)); 566*670f1da3SVíctor Colombo helper(cpu_env, ea, cpu_gpr[a->ra], cpu_gpr[a->rb]); 567*670f1da3SVíctor Colombo 568*670f1da3SVíctor Colombo tcg_temp_free(ea); 569*670f1da3SVíctor Colombo 570*670f1da3SVíctor Colombo return true; 571*670f1da3SVíctor Colombo} 572*670f1da3SVíctor Colombo 573*670f1da3SVíctor ColomboTRANS(HASHST, do_hash, false, gen_helper_HASHST) 574*670f1da3SVíctor ColomboTRANS(HASHCHK, do_hash, false, gen_helper_HASHCHK) 575