diff options
Diffstat (limited to 'target/ppc/translate')
-rw-r--r-- | target/ppc/translate/branch-impl.c.inc | 33 | ||||
-rw-r--r-- | target/ppc/translate/dfp-impl.c.inc | 401 | ||||
-rw-r--r-- | target/ppc/translate/dfp-ops.c.inc | 165 | ||||
-rw-r--r-- | target/ppc/translate/fixedpoint-impl.c.inc | 354 | ||||
-rw-r--r-- | target/ppc/translate/fp-impl.c.inc | 842 | ||||
-rw-r--r-- | target/ppc/translate/fp-ops.c.inc | 41 | ||||
-rw-r--r-- | target/ppc/translate/processor-ctrl-impl.c.inc | 105 | ||||
-rw-r--r-- | target/ppc/translate/spe-impl.c.inc | 97 | ||||
-rw-r--r-- | target/ppc/translate/storage-ctrl-impl.c.inc | 248 | ||||
-rw-r--r-- | target/ppc/translate/vector-impl.c.inc | 56 | ||||
-rw-r--r-- | target/ppc/translate/vmx-impl.c.inc | 2504 | ||||
-rw-r--r-- | target/ppc/translate/vmx-ops.c.inc | 97 | ||||
-rw-r--r-- | target/ppc/translate/vsx-impl.c.inc | 2342 | ||||
-rw-r--r-- | target/ppc/translate/vsx-ops.c.inc | 101 |
14 files changed, 4894 insertions, 2492 deletions
diff --git a/target/ppc/translate/branch-impl.c.inc b/target/ppc/translate/branch-impl.c.inc new file mode 100644 index 0000000000..fb0fcf30cc --- /dev/null +++ b/target/ppc/translate/branch-impl.c.inc @@ -0,0 +1,33 @@ +/* + * Power ISA decode for branch instructions + * + * Copyright IBM Corp. 2021 + * + * Authors: + * Daniel Henrique Barboza <danielhb413@gmail.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) + +static bool trans_RFEBB(DisasContext *ctx, arg_XL_s *arg) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA207S); + + translator_io_start(&ctx->base); + gen_update_cfar(ctx, ctx->cia); + gen_helper_rfebb(tcg_env, cpu_gpr[arg->s]); + + ctx->base.is_jmp = DISAS_CHAIN; + + return true; +} +#else +static bool trans_RFEBB(DisasContext *ctx, arg_XL_s *arg) +{ + gen_invalid(ctx); + return true; +} +#endif diff --git a/target/ppc/translate/dfp-impl.c.inc b/target/ppc/translate/dfp-impl.c.inc index 6c556dc2e1..371076582b 100644 --- a/target/ppc/translate/dfp-impl.c.inc +++ b/target/ppc/translate/dfp-impl.c.inc @@ -3,230 +3,207 @@ static inline TCGv_ptr gen_fprp_ptr(int reg) { TCGv_ptr r = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, vsr[reg].u64[0])); + tcg_gen_addi_ptr(r, tcg_env, offsetof(CPUPPCState, vsr[reg].u64[0])); return r; } -#define GEN_DFP_T_A_B_Rc(name) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_ptr rd, ra, rb; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_update_nip(ctx, ctx->base.pc_next - 4); \ - rd = gen_fprp_ptr(rD(ctx->opcode)); \ - ra = gen_fprp_ptr(rA(ctx->opcode)); \ - rb = gen_fprp_ptr(rB(ctx->opcode)); \ - gen_helper_##name(cpu_env, rd, ra, rb); \ - if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr1_from_fpscr(ctx); \ - } \ - tcg_temp_free_ptr(rd); \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_ptr(rb); \ +#define TRANS_DFP_T_A_B_Rc(NAME) \ +static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ +{ \ + TCGv_ptr rt, ra, rb; \ + REQUIRE_INSNS_FLAGS2(ctx, DFP); \ + REQUIRE_FPU(ctx); \ + rt = gen_fprp_ptr(a->rt); \ + ra = gen_fprp_ptr(a->ra); \ + rb = gen_fprp_ptr(a->rb); \ + gen_helper_##NAME(tcg_env, rt, ra, rb); \ + if (unlikely(a->rc)) { \ + gen_set_cr1_from_fpscr(ctx); \ + } \ + return true; \ } -#define GEN_DFP_BF_A_B(name) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_ptr ra, rb; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_update_nip(ctx, ctx->base.pc_next - 4); \ - ra = gen_fprp_ptr(rA(ctx->opcode)); \ - rb = gen_fprp_ptr(rB(ctx->opcode)); \ - gen_helper_##name(cpu_crf[crfD(ctx->opcode)], \ - cpu_env, ra, rb); \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_ptr(rb); \ +#define TRANS_DFP_BF_A_B(NAME) \ +static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ +{ \ + TCGv_ptr ra, rb; \ + REQUIRE_INSNS_FLAGS2(ctx, DFP); \ + REQUIRE_FPU(ctx); \ + ra = gen_fprp_ptr(a->ra); \ + rb = gen_fprp_ptr(a->rb); \ + gen_helper_##NAME(cpu_crf[a->bf], \ + tcg_env, ra, rb); \ + return true; \ } -#define GEN_DFP_BF_I_B(name) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_i32 uim; \ - TCGv_ptr rb; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_update_nip(ctx, ctx->base.pc_next - 4); \ - uim = tcg_const_i32(UIMM5(ctx->opcode)); \ - rb = gen_fprp_ptr(rB(ctx->opcode)); \ - gen_helper_##name(cpu_crf[crfD(ctx->opcode)], \ - cpu_env, uim, rb); \ - tcg_temp_free_i32(uim); \ - tcg_temp_free_ptr(rb); \ +#define TRANS_DFP_BF_I_B(NAME) \ +static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ +{ \ + TCGv_ptr rb; \ + REQUIRE_INSNS_FLAGS2(ctx, DFP); \ + REQUIRE_FPU(ctx); \ + rb = gen_fprp_ptr(a->rb); \ + gen_helper_##NAME(cpu_crf[a->bf], \ + tcg_env, tcg_constant_i32(a->uim), rb);\ + return true; \ } -#define GEN_DFP_BF_A_DCM(name) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_ptr ra; \ - TCGv_i32 dcm; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_update_nip(ctx, ctx->base.pc_next - 4); \ - ra = gen_fprp_ptr(rA(ctx->opcode)); \ - dcm = tcg_const_i32(DCM(ctx->opcode)); \ - gen_helper_##name(cpu_crf[crfD(ctx->opcode)], \ - cpu_env, ra, dcm); \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_i32(dcm); \ +#define TRANS_DFP_BF_A_DCM(NAME) \ +static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ +{ \ + TCGv_ptr ra; \ + REQUIRE_INSNS_FLAGS2(ctx, DFP); \ + REQUIRE_FPU(ctx); \ + ra = gen_fprp_ptr(a->fra); \ + gen_helper_##NAME(cpu_crf[a->bf], \ + tcg_env, ra, tcg_constant_i32(a->dm)); \ + return true; \ } -#define GEN_DFP_T_B_U32_U32_Rc(name, u32f1, u32f2) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_ptr rt, rb; \ - TCGv_i32 u32_1, u32_2; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_update_nip(ctx, ctx->base.pc_next - 4); \ - rt = gen_fprp_ptr(rD(ctx->opcode)); \ - rb = gen_fprp_ptr(rB(ctx->opcode)); \ - u32_1 = tcg_const_i32(u32f1(ctx->opcode)); \ - u32_2 = tcg_const_i32(u32f2(ctx->opcode)); \ - gen_helper_##name(cpu_env, rt, rb, u32_1, u32_2); \ - if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr1_from_fpscr(ctx); \ - } \ - tcg_temp_free_ptr(rt); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_i32(u32_1); \ - tcg_temp_free_i32(u32_2); \ +#define TRANS_DFP_T_B_U32_U32_Rc(NAME, U32F1, U32F2) \ +static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ +{ \ + TCGv_ptr rt, rb; \ + REQUIRE_INSNS_FLAGS2(ctx, DFP); \ + REQUIRE_FPU(ctx); \ + rt = gen_fprp_ptr(a->frt); \ + rb = gen_fprp_ptr(a->frb); \ + gen_helper_##NAME(tcg_env, rt, rb, \ + tcg_constant_i32(a->U32F1), \ + tcg_constant_i32(a->U32F2)); \ + if (unlikely(a->rc)) { \ + gen_set_cr1_from_fpscr(ctx); \ + } \ + return true; \ } -#define GEN_DFP_T_A_B_I32_Rc(name, i32fld) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_ptr rt, ra, rb; \ - TCGv_i32 i32; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_update_nip(ctx, ctx->base.pc_next - 4); \ - rt = gen_fprp_ptr(rD(ctx->opcode)); \ - ra = gen_fprp_ptr(rA(ctx->opcode)); \ - rb = gen_fprp_ptr(rB(ctx->opcode)); \ - i32 = tcg_const_i32(i32fld(ctx->opcode)); \ - gen_helper_##name(cpu_env, rt, ra, rb, i32); \ - if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr1_from_fpscr(ctx); \ - } \ - tcg_temp_free_ptr(rt); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_i32(i32); \ - } - -#define GEN_DFP_T_B_Rc(name) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_ptr rt, rb; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_update_nip(ctx, ctx->base.pc_next - 4); \ - rt = gen_fprp_ptr(rD(ctx->opcode)); \ - rb = gen_fprp_ptr(rB(ctx->opcode)); \ - gen_helper_##name(cpu_env, rt, rb); \ - if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr1_from_fpscr(ctx); \ - } \ - tcg_temp_free_ptr(rt); \ - tcg_temp_free_ptr(rb); \ - } - -#define GEN_DFP_T_FPR_I32_Rc(name, fprfld, i32fld) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_ptr rt, rs; \ - TCGv_i32 i32; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_update_nip(ctx, ctx->base.pc_next - 4); \ - rt = gen_fprp_ptr(rD(ctx->opcode)); \ - rs = gen_fprp_ptr(fprfld(ctx->opcode)); \ - i32 = tcg_const_i32(i32fld(ctx->opcode)); \ - gen_helper_##name(cpu_env, rt, rs, i32); \ - if (unlikely(Rc(ctx->opcode) != 0)) { \ - gen_set_cr1_from_fpscr(ctx); \ - } \ - tcg_temp_free_ptr(rt); \ - tcg_temp_free_ptr(rs); \ - tcg_temp_free_i32(i32); \ +#define TRANS_DFP_T_A_B_I32_Rc(NAME, I32FLD) \ +static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ +{ \ + TCGv_ptr rt, ra, rb; \ + REQUIRE_INSNS_FLAGS2(ctx, DFP); \ + REQUIRE_FPU(ctx); \ + rt = gen_fprp_ptr(a->frt); \ + ra = gen_fprp_ptr(a->fra); \ + rb = gen_fprp_ptr(a->frb); \ + gen_helper_##NAME(tcg_env, rt, ra, rb, \ + tcg_constant_i32(a->I32FLD)); \ + if (unlikely(a->rc)) { \ + gen_set_cr1_from_fpscr(ctx); \ + } \ + return true; \ } -GEN_DFP_T_A_B_Rc(dadd) -GEN_DFP_T_A_B_Rc(daddq) -GEN_DFP_T_A_B_Rc(dsub) -GEN_DFP_T_A_B_Rc(dsubq) -GEN_DFP_T_A_B_Rc(dmul) -GEN_DFP_T_A_B_Rc(dmulq) -GEN_DFP_T_A_B_Rc(ddiv) -GEN_DFP_T_A_B_Rc(ddivq) -GEN_DFP_BF_A_B(dcmpu) -GEN_DFP_BF_A_B(dcmpuq) -GEN_DFP_BF_A_B(dcmpo) -GEN_DFP_BF_A_B(dcmpoq) -GEN_DFP_BF_A_DCM(dtstdc) -GEN_DFP_BF_A_DCM(dtstdcq) -GEN_DFP_BF_A_DCM(dtstdg) -GEN_DFP_BF_A_DCM(dtstdgq) -GEN_DFP_BF_A_B(dtstex) -GEN_DFP_BF_A_B(dtstexq) -GEN_DFP_BF_A_B(dtstsf) -GEN_DFP_BF_A_B(dtstsfq) -GEN_DFP_BF_I_B(dtstsfi) -GEN_DFP_BF_I_B(dtstsfiq) -GEN_DFP_T_B_U32_U32_Rc(dquai, SIMM5, RMC) -GEN_DFP_T_B_U32_U32_Rc(dquaiq, SIMM5, RMC) -GEN_DFP_T_A_B_I32_Rc(dqua, RMC) -GEN_DFP_T_A_B_I32_Rc(dquaq, RMC) -GEN_DFP_T_A_B_I32_Rc(drrnd, RMC) -GEN_DFP_T_A_B_I32_Rc(drrndq, RMC) -GEN_DFP_T_B_U32_U32_Rc(drintx, FPW, RMC) -GEN_DFP_T_B_U32_U32_Rc(drintxq, FPW, RMC) -GEN_DFP_T_B_U32_U32_Rc(drintn, FPW, RMC) -GEN_DFP_T_B_U32_U32_Rc(drintnq, FPW, RMC) -GEN_DFP_T_B_Rc(dctdp) -GEN_DFP_T_B_Rc(dctqpq) -GEN_DFP_T_B_Rc(drsp) -GEN_DFP_T_B_Rc(drdpq) -GEN_DFP_T_B_Rc(dcffix) -GEN_DFP_T_B_Rc(dcffixq) -GEN_DFP_T_B_Rc(dctfix) -GEN_DFP_T_B_Rc(dctfixq) -GEN_DFP_T_FPR_I32_Rc(ddedpd, rB, SP) -GEN_DFP_T_FPR_I32_Rc(ddedpdq, rB, SP) -GEN_DFP_T_FPR_I32_Rc(denbcd, rB, SP) -GEN_DFP_T_FPR_I32_Rc(denbcdq, rB, SP) -GEN_DFP_T_B_Rc(dxex) -GEN_DFP_T_B_Rc(dxexq) -GEN_DFP_T_A_B_Rc(diex) -GEN_DFP_T_A_B_Rc(diexq) -GEN_DFP_T_FPR_I32_Rc(dscli, rA, DCM) -GEN_DFP_T_FPR_I32_Rc(dscliq, rA, DCM) -GEN_DFP_T_FPR_I32_Rc(dscri, rA, DCM) -GEN_DFP_T_FPR_I32_Rc(dscriq, rA, DCM) - -#undef GEN_DFP_T_A_B_Rc -#undef GEN_DFP_BF_A_B -#undef GEN_DFP_BF_A_DCM -#undef GEN_DFP_T_B_U32_U32_Rc -#undef GEN_DFP_T_A_B_I32_Rc -#undef GEN_DFP_T_B_Rc -#undef GEN_DFP_T_FPR_I32_Rc +#define TRANS_DFP_T_B_Rc(NAME) \ +static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ +{ \ + TCGv_ptr rt, rb; \ + REQUIRE_INSNS_FLAGS2(ctx, DFP); \ + REQUIRE_FPU(ctx); \ + rt = gen_fprp_ptr(a->rt); \ + rb = gen_fprp_ptr(a->rb); \ + gen_helper_##NAME(tcg_env, rt, rb); \ + if (unlikely(a->rc)) { \ + gen_set_cr1_from_fpscr(ctx); \ + } \ + return true; \ +} + +#define TRANS_DFP_T_FPR_I32_Rc(NAME, FPRFLD, I32FLD) \ +static bool trans_##NAME(DisasContext *ctx, arg_##NAME *a) \ +{ \ + TCGv_ptr rt, rx; \ + REQUIRE_INSNS_FLAGS2(ctx, DFP); \ + REQUIRE_FPU(ctx); \ + rt = gen_fprp_ptr(a->rt); \ + rx = gen_fprp_ptr(a->FPRFLD); \ + gen_helper_##NAME(tcg_env, rt, rx, \ + tcg_constant_i32(a->I32FLD)); \ + if (unlikely(a->rc)) { \ + gen_set_cr1_from_fpscr(ctx); \ + } \ + return true; \ +} + +TRANS_DFP_T_A_B_Rc(DADD) +TRANS_DFP_T_A_B_Rc(DADDQ) +TRANS_DFP_T_A_B_Rc(DSUB) +TRANS_DFP_T_A_B_Rc(DSUBQ) +TRANS_DFP_T_A_B_Rc(DMUL) +TRANS_DFP_T_A_B_Rc(DMULQ) +TRANS_DFP_T_A_B_Rc(DDIV) +TRANS_DFP_T_A_B_Rc(DDIVQ) +TRANS_DFP_BF_A_B(DCMPU) +TRANS_DFP_BF_A_B(DCMPUQ) +TRANS_DFP_BF_A_B(DCMPO) +TRANS_DFP_BF_A_B(DCMPOQ) +TRANS_DFP_BF_A_DCM(DTSTDC) +TRANS_DFP_BF_A_DCM(DTSTDCQ) +TRANS_DFP_BF_A_DCM(DTSTDG) +TRANS_DFP_BF_A_DCM(DTSTDGQ) +TRANS_DFP_BF_A_B(DTSTEX) +TRANS_DFP_BF_A_B(DTSTEXQ) +TRANS_DFP_BF_A_B(DTSTSF) +TRANS_DFP_BF_A_B(DTSTSFQ) +TRANS_DFP_BF_I_B(DTSTSFI) +TRANS_DFP_BF_I_B(DTSTSFIQ) +TRANS_DFP_T_B_U32_U32_Rc(DQUAI, te, rmc) +TRANS_DFP_T_B_U32_U32_Rc(DQUAIQ, te, rmc) +TRANS_DFP_T_A_B_I32_Rc(DQUA, rmc) +TRANS_DFP_T_A_B_I32_Rc(DQUAQ, rmc) +TRANS_DFP_T_A_B_I32_Rc(DRRND, rmc) +TRANS_DFP_T_A_B_I32_Rc(DRRNDQ, rmc) +TRANS_DFP_T_B_U32_U32_Rc(DRINTX, r, rmc) +TRANS_DFP_T_B_U32_U32_Rc(DRINTXQ, r, rmc) +TRANS_DFP_T_B_U32_U32_Rc(DRINTN, r, rmc) +TRANS_DFP_T_B_U32_U32_Rc(DRINTNQ, r, rmc) +TRANS_DFP_T_B_Rc(DCTDP) +TRANS_DFP_T_B_Rc(DCTQPQ) +TRANS_DFP_T_B_Rc(DRSP) +TRANS_DFP_T_B_Rc(DRDPQ) +TRANS_DFP_T_B_Rc(DCFFIX) +TRANS_DFP_T_B_Rc(DCFFIXQ) +TRANS_DFP_T_B_Rc(DCTFIX) +TRANS_DFP_T_B_Rc(DCTFIXQ) +TRANS_DFP_T_FPR_I32_Rc(DDEDPD, rb, sp) +TRANS_DFP_T_FPR_I32_Rc(DDEDPDQ, rb, sp) +TRANS_DFP_T_FPR_I32_Rc(DENBCD, rb, s) +TRANS_DFP_T_FPR_I32_Rc(DENBCDQ, rb, s) +TRANS_DFP_T_B_Rc(DXEX) +TRANS_DFP_T_B_Rc(DXEXQ) +TRANS_DFP_T_A_B_Rc(DIEX) +TRANS_DFP_T_A_B_Rc(DIEXQ) +TRANS_DFP_T_FPR_I32_Rc(DSCLI, ra, sh) +TRANS_DFP_T_FPR_I32_Rc(DSCLIQ, ra, sh) +TRANS_DFP_T_FPR_I32_Rc(DSCRI, ra, sh) +TRANS_DFP_T_FPR_I32_Rc(DSCRIQ, ra, sh) + +static bool trans_DCFFIXQQ(DisasContext *ctx, arg_DCFFIXQQ *a) +{ + TCGv_ptr rt, rb; + + REQUIRE_INSNS_FLAGS2(ctx, DFP); + REQUIRE_FPU(ctx); + REQUIRE_VECTOR(ctx); + + rt = gen_fprp_ptr(a->frtp); + rb = gen_avr_ptr(a->vrb); + gen_helper_DCFFIXQQ(tcg_env, rt, rb); + + return true; +} + +static bool trans_DCTFIXQQ(DisasContext *ctx, arg_DCTFIXQQ *a) +{ + TCGv_ptr rt, rb; + + REQUIRE_INSNS_FLAGS2(ctx, DFP); + REQUIRE_FPU(ctx); + REQUIRE_VECTOR(ctx); + + rt = gen_avr_ptr(a->vrt); + rb = gen_fprp_ptr(a->frbp); + gen_helper_DCTFIXQQ(tcg_env, rt, rb); + + return true; +} diff --git a/target/ppc/translate/dfp-ops.c.inc b/target/ppc/translate/dfp-ops.c.inc deleted file mode 100644 index 6ef38e5712..0000000000 --- a/target/ppc/translate/dfp-ops.c.inc +++ /dev/null @@ -1,165 +0,0 @@ -#define _GEN_DFP_LONG(name, op1, op2, mask) \ -GEN_HANDLER_E(name, 0x3B, op1, op2, mask, PPC_NONE, PPC2_DFP) - -#define _GEN_DFP_LONG_300(name, op1, op2, mask) \ -GEN_HANDLER_E(name, 0x3B, op1, op2, mask, PPC_NONE, PPC2_ISA300) - -#define _GEN_DFP_LONGx2(name, op1, op2, mask) \ -GEN_HANDLER_E(name, 0x3B, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \ -GEN_HANDLER_E(name, 0x3B, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP) - -#define _GEN_DFP_LONGx4(name, op1, op2, mask) \ -GEN_HANDLER_E(name, 0x3B, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \ -GEN_HANDLER_E(name, 0x3B, op1, 0x08 | op2, mask, PPC_NONE, PPC2_DFP), \ -GEN_HANDLER_E(name, 0x3B, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP), \ -GEN_HANDLER_E(name, 0x3B, op1, 0x18 | op2, mask, PPC_NONE, PPC2_DFP) - -#define _GEN_DFP_QUAD(name, op1, op2, mask) \ -GEN_HANDLER_E(name, 0x3F, op1, op2, mask, PPC_NONE, PPC2_DFP) - -#define _GEN_DFP_QUAD_300(name, op1, op2, mask) \ -GEN_HANDLER_E(name, 0x3F, op1, op2, mask, PPC_NONE, PPC2_ISA300) - -#define _GEN_DFP_QUADx2(name, op1, op2, mask) \ -GEN_HANDLER_E(name, 0x3F, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \ -GEN_HANDLER_E(name, 0x3F, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP) - -#define _GEN_DFP_QUADx4(name, op1, op2, mask) \ -GEN_HANDLER_E(name, 0x3F, op1, 0x00 | op2, mask, PPC_NONE, PPC2_DFP), \ -GEN_HANDLER_E(name, 0x3F, op1, 0x08 | op2, mask, PPC_NONE, PPC2_DFP), \ -GEN_HANDLER_E(name, 0x3F, op1, 0x10 | op2, mask, PPC_NONE, PPC2_DFP), \ -GEN_HANDLER_E(name, 0x3F, op1, 0x18 | op2, mask, PPC_NONE, PPC2_DFP) - -#define GEN_DFP_T_A_B_Rc(name, op1, op2) \ -_GEN_DFP_LONG(name, op1, op2, 0x00000000) - -#define GEN_DFP_Tp_Ap_Bp_Rc(name, op1, op2) \ -_GEN_DFP_QUAD(name, op1, op2, 0x00210800) - -#define GEN_DFP_Tp_A_Bp_Rc(name, op1, op2) \ -_GEN_DFP_QUAD(name, op1, op2, 0x00200800) - -#define GEN_DFP_T_B_Rc(name, op1, op2) \ -_GEN_DFP_LONG(name, op1, op2, 0x001F0000) - -#define GEN_DFP_Tp_Bp_Rc(name, op1, op2) \ -_GEN_DFP_QUAD(name, op1, op2, 0x003F0800) - -#define GEN_DFP_Tp_B_Rc(name, op1, op2) \ -_GEN_DFP_QUAD(name, op1, op2, 0x003F0000) - -#define GEN_DFP_T_Bp_Rc(name, op1, op2) \ -_GEN_DFP_QUAD(name, op1, op2, 0x001F0800) - -#define GEN_DFP_BF_A_B(name, op1, op2) \ -_GEN_DFP_LONG(name, op1, op2, 0x00000001) - -#define GEN_DFP_BF_A_B_300(name, op1, op2) \ -_GEN_DFP_LONG_300(name, op1, op2, 0x00400001) - -#define GEN_DFP_BF_Ap_Bp(name, op1, op2) \ -_GEN_DFP_QUAD(name, op1, op2, 0x00610801) - -#define GEN_DFP_BF_A_Bp(name, op1, op2) \ -_GEN_DFP_QUAD(name, op1, op2, 0x00600801) - -#define GEN_DFP_BF_A_Bp_300(name, op1, op2) \ -_GEN_DFP_QUAD_300(name, op1, op2, 0x00400001) - -#define GEN_DFP_BF_A_DCM(name, op1, op2) \ -_GEN_DFP_LONGx2(name, op1, op2, 0x00600001) - -#define GEN_DFP_BF_Ap_DCM(name, op1, op2) \ -_GEN_DFP_QUADx2(name, op1, op2, 0x00610001) - -#define GEN_DFP_T_A_B_RMC_Rc(name, op1, op2) \ -_GEN_DFP_LONGx4(name, op1, op2, 0x00000000) - -#define GEN_DFP_Tp_Ap_Bp_RMC_Rc(name, op1, op2) \ -_GEN_DFP_QUADx4(name, op1, op2, 0x02010800) - -#define GEN_DFP_Tp_A_Bp_RMC_Rc(name, op1, op2) \ -_GEN_DFP_QUADx4(name, op1, op2, 0x02000800) - -#define GEN_DFP_TE_T_B_RMC_Rc(name, op1, op2) \ -_GEN_DFP_LONGx4(name, op1, op2, 0x00000000) - -#define GEN_DFP_TE_Tp_Bp_RMC_Rc(name, op1, op2) \ -_GEN_DFP_QUADx4(name, op1, op2, 0x00200800) - -#define GEN_DFP_R_T_B_RMC_Rc(name, op1, op2) \ -_GEN_DFP_LONGx4(name, op1, op2, 0x001E0000) - -#define GEN_DFP_R_Tp_Bp_RMC_Rc(name, op1, op2) \ -_GEN_DFP_QUADx4(name, op1, op2, 0x003E0800) - -#define GEN_DFP_SP_T_B_Rc(name, op1, op2) \ -_GEN_DFP_LONG(name, op1, op2, 0x00070000) - -#define GEN_DFP_SP_Tp_Bp_Rc(name, op1, op2) \ -_GEN_DFP_QUAD(name, op1, op2, 0x00270800) - -#define GEN_DFP_S_T_B_Rc(name, op1, op2) \ -_GEN_DFP_LONG(name, op1, op2, 0x000F0000) - -#define GEN_DFP_S_Tp_Bp_Rc(name, op1, op2) \ -_GEN_DFP_QUAD(name, op1, op2, 0x002F0800) - -#define GEN_DFP_T_A_SH_Rc(name, op1, op2) \ -_GEN_DFP_LONGx2(name, op1, op2, 0x00000000) - -#define GEN_DFP_Tp_Ap_SH_Rc(name, op1, op2) \ -_GEN_DFP_QUADx2(name, op1, op2, 0x00210000) - -GEN_DFP_T_A_B_Rc(dadd, 0x02, 0x00), -GEN_DFP_Tp_Ap_Bp_Rc(daddq, 0x02, 0x00), -GEN_DFP_T_A_B_Rc(dsub, 0x02, 0x10), -GEN_DFP_Tp_Ap_Bp_Rc(dsubq, 0x02, 0x10), -GEN_DFP_T_A_B_Rc(dmul, 0x02, 0x01), -GEN_DFP_Tp_Ap_Bp_Rc(dmulq, 0x02, 0x01), -GEN_DFP_T_A_B_Rc(ddiv, 0x02, 0x11), -GEN_DFP_Tp_Ap_Bp_Rc(ddivq, 0x02, 0x11), -GEN_DFP_BF_A_B(dcmpu, 0x02, 0x14), -GEN_DFP_BF_Ap_Bp(dcmpuq, 0x02, 0x14), -GEN_DFP_BF_A_B(dcmpo, 0x02, 0x04), -GEN_DFP_BF_Ap_Bp(dcmpoq, 0x02, 0x04), -GEN_DFP_BF_A_DCM(dtstdc, 0x02, 0x06), -GEN_DFP_BF_Ap_DCM(dtstdcq, 0x02, 0x06), -GEN_DFP_BF_A_DCM(dtstdg, 0x02, 0x07), -GEN_DFP_BF_Ap_DCM(dtstdgq, 0x02, 0x07), -GEN_DFP_BF_A_B(dtstex, 0x02, 0x05), -GEN_DFP_BF_Ap_Bp(dtstexq, 0x02, 0x05), -GEN_DFP_BF_A_B(dtstsf, 0x02, 0x15), -GEN_DFP_BF_A_Bp(dtstsfq, 0x02, 0x15), -GEN_DFP_BF_A_B_300(dtstsfi, 0x03, 0x15), -GEN_DFP_BF_A_Bp_300(dtstsfiq, 0x03, 0x15), -GEN_DFP_TE_T_B_RMC_Rc(dquai, 0x03, 0x02), -GEN_DFP_TE_Tp_Bp_RMC_Rc(dquaiq, 0x03, 0x02), -GEN_DFP_T_A_B_RMC_Rc(dqua, 0x03, 0x00), -GEN_DFP_Tp_Ap_Bp_RMC_Rc(dquaq, 0x03, 0x00), -GEN_DFP_T_A_B_RMC_Rc(drrnd, 0x03, 0x01), -GEN_DFP_Tp_A_Bp_RMC_Rc(drrndq, 0x03, 0x01), -GEN_DFP_R_T_B_RMC_Rc(drintx, 0x03, 0x03), -GEN_DFP_R_Tp_Bp_RMC_Rc(drintxq, 0x03, 0x03), -GEN_DFP_R_T_B_RMC_Rc(drintn, 0x03, 0x07), -GEN_DFP_R_Tp_Bp_RMC_Rc(drintnq, 0x03, 0x07), -GEN_DFP_T_B_Rc(dctdp, 0x02, 0x08), -GEN_DFP_Tp_B_Rc(dctqpq, 0x02, 0x08), -GEN_DFP_T_B_Rc(drsp, 0x02, 0x18), -GEN_DFP_Tp_Bp_Rc(drdpq, 0x02, 0x18), -GEN_DFP_T_B_Rc(dcffix, 0x02, 0x19), -GEN_DFP_Tp_B_Rc(dcffixq, 0x02, 0x19), -GEN_DFP_T_B_Rc(dctfix, 0x02, 0x09), -GEN_DFP_T_Bp_Rc(dctfixq, 0x02, 0x09), -GEN_DFP_SP_T_B_Rc(ddedpd, 0x02, 0x0a), -GEN_DFP_SP_Tp_Bp_Rc(ddedpdq, 0x02, 0x0a), -GEN_DFP_S_T_B_Rc(denbcd, 0x02, 0x1a), -GEN_DFP_S_Tp_Bp_Rc(denbcdq, 0x02, 0x1a), -GEN_DFP_T_B_Rc(dxex, 0x02, 0x0b), -GEN_DFP_T_Bp_Rc(dxexq, 0x02, 0x0b), -GEN_DFP_T_A_B_Rc(diex, 0x02, 0x1b), -GEN_DFP_Tp_A_Bp_Rc(diexq, 0x02, 0x1b), -GEN_DFP_T_A_SH_Rc(dscli, 0x02, 0x02), -GEN_DFP_Tp_Ap_SH_Rc(dscliq, 0x02, 0x02), -GEN_DFP_T_A_SH_Rc(dscri, 0x02, 0x03), -GEN_DFP_Tp_Ap_SH_Rc(dscriq, 0x02, 0x03), diff --git a/target/ppc/translate/fixedpoint-impl.c.inc b/target/ppc/translate/fixedpoint-impl.c.inc index 2e2518ee15..0c66465d96 100644 --- a/target/ppc/translate/fixedpoint-impl.c.inc +++ b/target/ppc/translate/fixedpoint-impl.c.inc @@ -18,25 +18,6 @@ */ /* - * Incorporate CIA into the constant when R=1. - * Validate that when R=1, RA=0. - */ -static bool resolve_PLS_D(DisasContext *ctx, arg_D *d, arg_PLS_D *a) -{ - d->rt = a->rt; - d->ra = a->ra; - d->si = a->si; - if (a->r) { - if (unlikely(a->ra != 0)) { - gen_invalid(ctx); - return false; - } - d->si += ctx->cia; - } - return true; -} - -/* * Fixed-Point Load/Store Instructions */ @@ -51,15 +32,7 @@ static bool do_ldst(DisasContext *ctx, int rt, int ra, TCGv displ, bool update, } gen_set_access_type(ctx, ACCESS_INT); - ea = tcg_temp_new(); - if (ra) { - tcg_gen_add_tl(ea, cpu_gpr[ra], displ); - } else { - tcg_gen_mov_tl(ea, displ); - } - if (NARROW_MODE(ctx)) { - tcg_gen_ext32u_tl(ea, ea); - } + ea = do_ea_calc(ctx, ra, displ); mop ^= ctx->default_tcg_memop_mask; if (store) { tcg_gen_qemu_st_tl(cpu_gpr[rt], ea, ctx->mem_idx, mop); @@ -69,8 +42,6 @@ static bool do_ldst(DisasContext *ctx, int rt, int ra, TCGv displ, bool update, if (update) { tcg_gen_mov_tl(cpu_gpr[ra], ea); } - tcg_temp_free(ea); - return true; } @@ -96,6 +67,66 @@ static bool do_ldst_X(DisasContext *ctx, arg_X *a, bool update, return do_ldst(ctx, a->rt, a->ra, cpu_gpr[a->rb], update, store, mop); } +static bool do_ldst_quad(DisasContext *ctx, arg_D *a, bool store, bool prefixed) +{ +#if defined(TARGET_PPC64) + TCGv ea; + TCGv_i64 lo, hi; + TCGv_i128 t16; + + REQUIRE_INSNS_FLAGS(ctx, 64BX); + + if (!prefixed && !(ctx->insns_flags2 & PPC2_LSQ_ISA207)) { + /* lq and stq were privileged prior to V. 2.07 */ + REQUIRE_SV(ctx); + + if (ctx->le_mode) { + gen_align_no_le(ctx); + return true; + } + } + + if (!store && unlikely(a->ra == a->rt)) { + gen_invalid(ctx); + return true; + } + + gen_set_access_type(ctx, ACCESS_INT); + ea = do_ea_calc(ctx, a->ra, tcg_constant_tl(a->si)); + + if (ctx->le_mode && prefixed) { + lo = cpu_gpr[a->rt]; + hi = cpu_gpr[a->rt + 1]; + } else { + lo = cpu_gpr[a->rt + 1]; + hi = cpu_gpr[a->rt]; + } + t16 = tcg_temp_new_i128(); + + if (store) { + tcg_gen_concat_i64_i128(t16, lo, hi); + tcg_gen_qemu_st_i128(t16, ea, ctx->mem_idx, DEF_MEMOP(MO_128)); + } else { + tcg_gen_qemu_ld_i128(t16, ea, ctx->mem_idx, DEF_MEMOP(MO_128)); + tcg_gen_extr_i128_i64(lo, hi, t16); + } +#else + qemu_build_not_reached(); +#endif + + return true; +} + +static bool do_ldst_quad_PLS_D(DisasContext *ctx, arg_PLS_D *a, bool store) +{ + arg_D d; + if (!resolve_PLS_D(ctx, &d, a)) { + return true; + } + + return do_ldst_quad(ctx, &d, store, true); +} + /* Load Byte and Zero */ TRANS(LBZ, do_ldst_D, false, false, MO_UB) TRANS(LBZX, do_ldst_X, false, false, MO_UB) @@ -131,11 +162,15 @@ TRANS64(LWAUX, do_ldst_X, true, false, MO_SL) TRANS64(PLWA, do_ldst_PLS_D, false, false, MO_SL) /* Load Doubleword */ -TRANS64(LD, do_ldst_D, false, false, MO_Q) -TRANS64(LDX, do_ldst_X, false, false, MO_Q) -TRANS64(LDU, do_ldst_D, true, false, MO_Q) -TRANS64(LDUX, do_ldst_X, true, false, MO_Q) -TRANS64(PLD, do_ldst_PLS_D, false, false, MO_Q) +TRANS64(LD, do_ldst_D, false, false, MO_UQ) +TRANS64(LDX, do_ldst_X, false, false, MO_UQ) +TRANS64(LDU, do_ldst_D, true, false, MO_UQ) +TRANS64(LDUX, do_ldst_X, true, false, MO_UQ) +TRANS64(PLD, do_ldst_PLS_D, false, false, MO_UQ) + +/* Load Quadword */ +TRANS64(LQ, do_ldst_quad, false, false); +TRANS64(PLQ, do_ldst_quad_PLS_D, false); /* Store Byte */ TRANS(STB, do_ldst_D, false, true, MO_UB) @@ -159,11 +194,15 @@ TRANS(STWUX, do_ldst_X, true, true, MO_UL) TRANS(PSTW, do_ldst_PLS_D, false, true, MO_UL) /* Store Doubleword */ -TRANS64(STD, do_ldst_D, false, true, MO_Q) -TRANS64(STDX, do_ldst_X, false, true, MO_Q) -TRANS64(STDU, do_ldst_D, true, true, MO_Q) -TRANS64(STDUX, do_ldst_X, true, true, MO_Q) -TRANS64(PSTD, do_ldst_PLS_D, false, true, MO_Q) +TRANS64(STD, do_ldst_D, false, true, MO_UQ) +TRANS64(STDX, do_ldst_X, false, true, MO_UQ) +TRANS64(STDU, do_ldst_D, true, true, MO_UQ) +TRANS64(STDUX, do_ldst_X, true, true, MO_UQ) +TRANS64(PSTD, do_ldst_PLS_D, false, true, MO_UQ) + +/* Store Quadword */ +TRANS64(STQ, do_ldst_quad, true, false); +TRANS64(PSTQ, do_ldst_quad_PLS_D, true); /* * Fixed-Point Compare Instructions @@ -286,6 +325,76 @@ static bool trans_ADDPCIS(DisasContext *ctx, arg_DX *a) return true; } +static bool trans_ADDEX(DisasContext *ctx, arg_X *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + gen_op_arith_add(ctx, cpu_gpr[a->rt], cpu_gpr[a->ra], cpu_gpr[a->rb], + cpu_ov, cpu_ov32, true, true, false, false); + return true; +} + +static bool do_add_D(DisasContext *ctx, arg_D *a, bool add_ca, bool compute_ca, + bool compute_ov, bool compute_rc0) +{ + gen_op_arith_add(ctx, cpu_gpr[a->rt], cpu_gpr[a->ra], + tcg_constant_tl(a->si), cpu_ca, cpu_ca32, + add_ca, compute_ca, compute_ov, compute_rc0); + return true; +} + +static bool do_add_XO(DisasContext *ctx, arg_XO *a, bool add_ca, + bool compute_ca) +{ + gen_op_arith_add(ctx, cpu_gpr[a->rt], cpu_gpr[a->ra], cpu_gpr[a->rb], + cpu_ca, cpu_ca32, add_ca, compute_ca, a->oe, a->rc); + return true; +} + +static bool do_add_const_XO(DisasContext *ctx, arg_XO_ta *a, TCGv const_val, + bool add_ca, bool compute_ca) +{ + gen_op_arith_add(ctx, cpu_gpr[a->rt], cpu_gpr[a->ra], const_val, + cpu_ca, cpu_ca32, add_ca, compute_ca, a->oe, a->rc); + return true; +} + +TRANS(ADD, do_add_XO, false, false); +TRANS(ADDC, do_add_XO, false, true); +TRANS(ADDE, do_add_XO, true, true); +TRANS(ADDME, do_add_const_XO, tcg_constant_tl(-1LL), true, true); +TRANS(ADDZE, do_add_const_XO, tcg_constant_tl(0), true, true); +TRANS(ADDIC, do_add_D, false, true, false, false); +TRANS(ADDIC_, do_add_D, false, true, false, true); + +static bool trans_SUBFIC(DisasContext *ctx, arg_D *a) +{ + gen_op_arith_subf(ctx, cpu_gpr[a->rt], cpu_gpr[a->ra], + tcg_constant_tl(a->si), false, true, false, false); + return true; +} + +static bool do_subf_XO(DisasContext *ctx, arg_XO *a, bool add_ca, + bool compute_ca) +{ + gen_op_arith_subf(ctx, cpu_gpr[a->rt], cpu_gpr[a->ra], cpu_gpr[a->rb], + add_ca, compute_ca, a->oe, a->rc); + return true; +} + +static bool do_subf_const_XO(DisasContext *ctx, arg_XO_ta *a, TCGv const_val, + bool add_ca, bool compute_ca) +{ + gen_op_arith_subf(ctx, cpu_gpr[a->rt], cpu_gpr[a->ra], const_val, + add_ca, compute_ca, a->oe, a->rc); + return true; +} + +TRANS(SUBF, do_subf_XO, false, false) +TRANS(SUBFC, do_subf_XO, false, true) +TRANS(SUBFE, do_subf_XO, true, true) +TRANS(SUBFME, do_subf_const_XO, tcg_constant_tl(-1LL), true, true) +TRANS(SUBFZE, do_subf_const_XO, tcg_constant_tl(0), true, true) + static bool trans_INVALID(DisasContext *ctx, arg_INVALID *a) { gen_invalid(ctx); @@ -303,15 +412,15 @@ static bool do_set_bool_cond(DisasContext *ctx, arg_X_bi *a, bool neg, bool rev) uint32_t mask = 0x08 >> (a->bi & 0x03); TCGCond cond = rev ? TCG_COND_EQ : TCG_COND_NE; TCGv temp = tcg_temp_new(); + TCGv zero = tcg_constant_tl(0); tcg_gen_extu_i32_tl(temp, cpu_crf[a->bi >> 2]); tcg_gen_andi_tl(temp, temp, mask); - tcg_gen_setcondi_tl(cond, cpu_gpr[a->rt], temp, 0); if (neg) { - tcg_gen_neg_tl(cpu_gpr[a->rt], cpu_gpr[a->rt]); + tcg_gen_negsetcond_tl(cond, cpu_gpr[a->rt], temp, zero); + } else { + tcg_gen_setcond_tl(cond, cpu_gpr[a->rt], temp, zero); } - tcg_temp_free(temp); - return true; } @@ -325,9 +434,164 @@ static bool trans_CFUGED(DisasContext *ctx, arg_X *a) REQUIRE_64BIT(ctx); REQUIRE_INSNS_FLAGS2(ctx, ISA310); #if defined(TARGET_PPC64) - gen_helper_cfuged(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]); + gen_helper_CFUGED(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static void do_cntzdm(TCGv_i64 dst, TCGv_i64 src, TCGv_i64 mask, int64_t trail) +{ + TCGv_i64 t0, t1; + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + + tcg_gen_and_i64(t0, src, mask); + if (trail) { + tcg_gen_ctzi_i64(t0, t0, -1); + } else { + tcg_gen_clzi_i64(t0, t0, -1); + } + + tcg_gen_setcondi_i64(TCG_COND_NE, t1, t0, -1); + tcg_gen_andi_i64(t0, t0, 63); + tcg_gen_xori_i64(t0, t0, 63); + if (trail) { + tcg_gen_shl_i64(t0, mask, t0); + tcg_gen_shl_i64(t0, t0, t1); + } else { + tcg_gen_shr_i64(t0, mask, t0); + tcg_gen_shr_i64(t0, t0, t1); + } + + tcg_gen_ctpop_i64(dst, t0); +} + +static bool trans_CNTLZDM(DisasContext *ctx, arg_X *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS2(ctx, ISA310); +#if defined(TARGET_PPC64) + do_cntzdm(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb], false); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_CNTTZDM(DisasContext *ctx, arg_X *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS2(ctx, ISA310); +#if defined(TARGET_PPC64) + do_cntzdm(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb], true); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_PDEPD(DisasContext *ctx, arg_X *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS2(ctx, ISA310); +#if defined(TARGET_PPC64) + gen_helper_PDEPD(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_PEXTD(DisasContext *ctx, arg_X *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS2(ctx, ISA310); +#if defined(TARGET_PPC64) + gen_helper_PEXTD(cpu_gpr[a->ra], cpu_gpr[a->rt], cpu_gpr[a->rb]); #else qemu_build_not_reached(); #endif return true; } + +static bool trans_ADDG6S(DisasContext *ctx, arg_X *a) +{ + const target_ulong carry_bits = (target_ulong)-1 / 0xf; + TCGv in1, in2, carryl, carryh, tmp; + TCGv zero = tcg_constant_tl(0); + + REQUIRE_INSNS_FLAGS2(ctx, BCDA_ISA206); + + in1 = cpu_gpr[a->ra]; + in2 = cpu_gpr[a->rb]; + tmp = tcg_temp_new(); + carryl = tcg_temp_new(); + carryh = tcg_temp_new(); + + /* Addition with carry. */ + tcg_gen_add2_tl(carryl, carryh, in1, zero, in2, zero); + /* Addition without carry. */ + tcg_gen_xor_tl(tmp, in1, in2); + /* Difference between the two is carry in to each bit. */ + tcg_gen_xor_tl(carryl, carryl, tmp); + + /* + * The carry-out that we're looking for is the carry-in to + * the next nibble. Shift the double-word down one nibble, + * which puts all of the bits back into one word. + */ + tcg_gen_extract2_tl(carryl, carryl, carryh, 4); + + /* Invert, isolate the carry bits, and produce 6's. */ + tcg_gen_andc_tl(carryl, tcg_constant_tl(carry_bits), carryl); + tcg_gen_muli_tl(cpu_gpr[a->rt], carryl, 6); + return true; +} + +static bool trans_CDTBCD(DisasContext *ctx, arg_X_sa *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, BCDA_ISA206); + gen_helper_CDTBCD(cpu_gpr[a->ra], cpu_gpr[a->rs]); + return true; +} + +static bool trans_CBCDTD(DisasContext *ctx, arg_X_sa *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, BCDA_ISA206); + gen_helper_CBCDTD(cpu_gpr[a->ra], cpu_gpr[a->rs]); + return true; +} + +static bool do_hash(DisasContext *ctx, arg_X *a, bool priv, + void (*helper)(TCGv_ptr, TCGv, TCGv, TCGv)) +{ + TCGv ea; + + if (!(ctx->insns_flags2 & PPC2_ISA310)) { + /* if version is before v3.1, this operation is a nop */ + return true; + } + + if (priv) { + /* if instruction is privileged but the context is in user space */ + REQUIRE_SV(ctx); + } + + if (unlikely(a->ra == 0)) { + /* if RA=0, the instruction form is invalid */ + gen_invalid(ctx); + return true; + } + + ea = do_ea_calc(ctx, a->ra, tcg_constant_tl(a->rt)); + helper(tcg_env, ea, cpu_gpr[a->ra], cpu_gpr[a->rb]); + return true; +} + +TRANS(HASHST, do_hash, false, gen_helper_HASHST) +TRANS(HASHCHK, do_hash, false, gen_helper_HASHCHK) +TRANS(HASHSTP, do_hash, true, gen_helper_HASHSTP) +TRANS(HASHCHKP, do_hash, true, gen_helper_HASHCHKP) diff --git a/target/ppc/translate/fp-impl.c.inc b/target/ppc/translate/fp-impl.c.inc index 9f7868ee28..189cd8c979 100644 --- a/target/ppc/translate/fp-impl.c.inc +++ b/target/ppc/translate/fp-impl.c.inc @@ -6,13 +6,13 @@ static inline void gen_reset_fpstatus(void) { - gen_helper_reset_fpstatus(cpu_env); + gen_helper_reset_fpstatus(tcg_env); } static inline void gen_compute_fprf_float64(TCGv_i64 arg) { - gen_helper_compute_fprf_float64(cpu_env, arg); - gen_helper_float_check_status(cpu_env); + gen_helper_compute_fprf_float64(tcg_env, arg); + gen_helper_float_check_status(tcg_env); } #if defined(TARGET_PPC64) @@ -21,7 +21,6 @@ static void gen_set_cr1_from_fpscr(DisasContext *ctx) TCGv_i32 tmp = tcg_temp_new_i32(); tcg_gen_trunc_tl_i32(tmp, cpu_fpscr); tcg_gen_shri_i32(cpu_crf[1], tmp, 28); - tcg_temp_free_i32(tmp); } #else static void gen_set_cr1_from_fpscr(DisasContext *ctx) @@ -31,7 +30,7 @@ static void gen_set_cr1_from_fpscr(DisasContext *ctx) #endif /*** Floating-Point arithmetic ***/ -#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type) \ +#define _GEN_FLOAT_ACB(name, op1, op2, set_fprf, type) \ static void gen_f##name(DisasContext *ctx) \ { \ TCGv_i64 t0; \ @@ -50,10 +49,7 @@ static void gen_f##name(DisasContext *ctx) \ get_fpr(t0, rA(ctx->opcode)); \ get_fpr(t1, rC(ctx->opcode)); \ get_fpr(t2, rB(ctx->opcode)); \ - gen_helper_f##op(t3, cpu_env, t0, t1, t2); \ - if (isfloat) { \ - gen_helper_frsp(t3, cpu_env, t3); \ - } \ + gen_helper_f##name(t3, tcg_env, t0, t1, t2); \ set_fpr(rD(ctx->opcode), t3); \ if (set_fprf) { \ gen_compute_fprf_float64(t3); \ @@ -61,17 +57,13 @@ static void gen_f##name(DisasContext *ctx) \ if (unlikely(Rc(ctx->opcode) != 0)) { \ gen_set_cr1_from_fpscr(ctx); \ } \ - tcg_temp_free_i64(t0); \ - tcg_temp_free_i64(t1); \ - tcg_temp_free_i64(t2); \ - tcg_temp_free_i64(t3); \ } #define GEN_FLOAT_ACB(name, op2, set_fprf, type) \ -_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0, set_fprf, type); \ -_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, set_fprf, type); +_GEN_FLOAT_ACB(name, 0x3F, op2, set_fprf, type); \ +_GEN_FLOAT_ACB(name##s, 0x3B, op2, set_fprf, type); -#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat, set_fprf, type) \ +#define _GEN_FLOAT_AB(name, op1, op2, inval, set_fprf, type) \ static void gen_f##name(DisasContext *ctx) \ { \ TCGv_i64 t0; \ @@ -87,10 +79,7 @@ static void gen_f##name(DisasContext *ctx) \ gen_reset_fpstatus(); \ get_fpr(t0, rA(ctx->opcode)); \ get_fpr(t1, rB(ctx->opcode)); \ - gen_helper_f##op(t2, cpu_env, t0, t1); \ - if (isfloat) { \ - gen_helper_frsp(t2, cpu_env, t2); \ - } \ + gen_helper_f##name(t2, tcg_env, t0, t1); \ set_fpr(rD(ctx->opcode), t2); \ if (set_fprf) { \ gen_compute_fprf_float64(t2); \ @@ -98,15 +87,12 @@ static void gen_f##name(DisasContext *ctx) \ if (unlikely(Rc(ctx->opcode) != 0)) { \ gen_set_cr1_from_fpscr(ctx); \ } \ - tcg_temp_free_i64(t0); \ - tcg_temp_free_i64(t1); \ - tcg_temp_free_i64(t2); \ } #define GEN_FLOAT_AB(name, op2, inval, set_fprf, type) \ -_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0, set_fprf, type); \ -_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1, set_fprf, type); +_GEN_FLOAT_AB(name, 0x3F, op2, inval, set_fprf, type); \ +_GEN_FLOAT_AB(name##s, 0x3B, op2, inval, set_fprf, type); -#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat, set_fprf, type) \ +#define _GEN_FLOAT_AC(name, op1, op2, inval, set_fprf, type) \ static void gen_f##name(DisasContext *ctx) \ { \ TCGv_i64 t0; \ @@ -122,10 +108,7 @@ static void gen_f##name(DisasContext *ctx) \ gen_reset_fpstatus(); \ get_fpr(t0, rA(ctx->opcode)); \ get_fpr(t1, rC(ctx->opcode)); \ - gen_helper_f##op(t2, cpu_env, t0, t1); \ - if (isfloat) { \ - gen_helper_frsp(t2, cpu_env, t2); \ - } \ + gen_helper_f##name(t2, tcg_env, t0, t1); \ set_fpr(rD(ctx->opcode), t2); \ if (set_fprf) { \ gen_compute_fprf_float64(t2); \ @@ -133,13 +116,10 @@ static void gen_f##name(DisasContext *ctx) \ if (unlikely(Rc(ctx->opcode) != 0)) { \ gen_set_cr1_from_fpscr(ctx); \ } \ - tcg_temp_free_i64(t0); \ - tcg_temp_free_i64(t1); \ - tcg_temp_free_i64(t2); \ } #define GEN_FLOAT_AC(name, op2, inval, set_fprf, type) \ -_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0, set_fprf, type); \ -_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1, set_fprf, type); +_GEN_FLOAT_AC(name, 0x3F, op2, inval, set_fprf, type); \ +_GEN_FLOAT_AC(name##s, 0x3B, op2, inval, set_fprf, type); #define GEN_FLOAT_B(name, op2, op3, set_fprf, type) \ static void gen_f##name(DisasContext *ctx) \ @@ -154,16 +134,15 @@ static void gen_f##name(DisasContext *ctx) \ t1 = tcg_temp_new_i64(); \ gen_reset_fpstatus(); \ get_fpr(t0, rB(ctx->opcode)); \ - gen_helper_f##name(t1, cpu_env, t0); \ + gen_helper_f##name(t1, tcg_env, t0); \ set_fpr(rD(ctx->opcode), t1); \ if (set_fprf) { \ - gen_compute_fprf_float64(t1); \ + gen_helper_compute_fprf_float64(tcg_env, t1); \ } \ + gen_helper_float_check_status(tcg_env); \ if (unlikely(Rc(ctx->opcode) != 0)) { \ gen_set_cr1_from_fpscr(ctx); \ } \ - tcg_temp_free_i64(t0); \ - tcg_temp_free_i64(t1); \ } #define GEN_FLOAT_BS(name, op1, op2, set_fprf, type) \ @@ -179,7 +158,7 @@ static void gen_f##name(DisasContext *ctx) \ t1 = tcg_temp_new_i64(); \ gen_reset_fpstatus(); \ get_fpr(t0, rB(ctx->opcode)); \ - gen_helper_f##name(t1, cpu_env, t0); \ + gen_helper_f##name(t1, tcg_env, t0); \ set_fpr(rD(ctx->opcode), t1); \ if (set_fprf) { \ gen_compute_fprf_float64(t1); \ @@ -187,8 +166,6 @@ static void gen_f##name(DisasContext *ctx) \ if (unlikely(Rc(ctx->opcode) != 0)) { \ gen_set_cr1_from_fpscr(ctx); \ } \ - tcg_temp_free_i64(t0); \ - tcg_temp_free_i64(t1); \ } /* fadd - fadds */ @@ -220,69 +197,66 @@ static void gen_frsqrtes(DisasContext *ctx) t1 = tcg_temp_new_i64(); gen_reset_fpstatus(); get_fpr(t0, rB(ctx->opcode)); - gen_helper_frsqrte(t1, cpu_env, t0); - gen_helper_frsp(t1, cpu_env, t1); + gen_helper_frsqrtes(t1, tcg_env, t0); set_fpr(rD(ctx->opcode), t1); gen_compute_fprf_float64(t1); if (unlikely(Rc(ctx->opcode) != 0)) { gen_set_cr1_from_fpscr(ctx); } - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); } -/* fsel */ -_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL); -/* fsub - fsubs */ -GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT); -/* Optional: */ - -/* fsqrt */ -static void gen_fsqrt(DisasContext *ctx) +static bool trans_FSEL(DisasContext *ctx, arg_A *a) { - TCGv_i64 t0; - TCGv_i64 t1; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } + TCGv_i64 t0, t1, t2; + + REQUIRE_INSNS_FLAGS(ctx, FLOAT_FSEL); + REQUIRE_FPU(ctx); + t0 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); - gen_reset_fpstatus(); - get_fpr(t0, rB(ctx->opcode)); - gen_helper_fsqrt(t1, cpu_env, t0); - set_fpr(rD(ctx->opcode), t1); - gen_compute_fprf_float64(t1); - if (unlikely(Rc(ctx->opcode) != 0)) { + t2 = tcg_temp_new_i64(); + + get_fpr(t0, a->fra); + get_fpr(t1, a->frb); + get_fpr(t2, a->frc); + + gen_helper_FSEL(t0, t0, t1, t2); + set_fpr(a->frt, t0); + if (a->rc) { gen_set_cr1_from_fpscr(ctx); } - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); + return true; } -static void gen_fsqrts(DisasContext *ctx) +/* fsub - fsubs */ +GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT); +/* Optional: */ + +static bool do_helper_fsqrt(DisasContext *ctx, arg_A_tb *a, + void (*helper)(TCGv_i64, TCGv_ptr, TCGv_i64)) { - TCGv_i64 t0; - TCGv_i64 t1; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } + TCGv_i64 t0, t1; + + REQUIRE_INSNS_FLAGS(ctx, FLOAT_FSQRT); + REQUIRE_FPU(ctx); + t0 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); + gen_reset_fpstatus(); - get_fpr(t0, rB(ctx->opcode)); - gen_helper_fsqrt(t1, cpu_env, t0); - gen_helper_frsp(t1, cpu_env, t1); - set_fpr(rD(ctx->opcode), t1); + get_fpr(t0, a->frb); + helper(t1, tcg_env, t0); + set_fpr(a->frt, t1); gen_compute_fprf_float64(t1); - if (unlikely(Rc(ctx->opcode) != 0)) { + if (unlikely(a->rc != 0)) { gen_set_cr1_from_fpscr(ctx); } - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); + return true; } +TRANS(FSQRT, do_helper_fsqrt, gen_helper_FSQRT); +TRANS(FSQRTS, do_helper_fsqrt, gen_helper_FSQRTS); + /*** Floating-Point multiply-and-add ***/ /* fmadd - fmadds */ GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT); @@ -343,8 +317,6 @@ static void gen_ftdiv(DisasContext *ctx) get_fpr(t0, rA(ctx->opcode)); get_fpr(t1, rB(ctx->opcode)); gen_helper_ftdiv(cpu_crf[crfD(ctx->opcode)], t0, t1); - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); } static void gen_ftsqrt(DisasContext *ctx) @@ -357,7 +329,6 @@ static void gen_ftsqrt(DisasContext *ctx) t0 = tcg_temp_new_i64(); get_fpr(t0, rB(ctx->opcode)); gen_helper_ftsqrt(cpu_crf[crfD(ctx->opcode)], t0); - tcg_temp_free_i64(t0); } @@ -377,14 +348,11 @@ static void gen_fcmpo(DisasContext *ctx) t0 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); gen_reset_fpstatus(); - crf = tcg_const_i32(crfD(ctx->opcode)); + crf = tcg_constant_i32(crfD(ctx->opcode)); get_fpr(t0, rA(ctx->opcode)); get_fpr(t1, rB(ctx->opcode)); - gen_helper_fcmpo(cpu_env, t0, t1, crf); - tcg_temp_free_i32(crf); - gen_helper_float_check_status(cpu_env); - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); + gen_helper_fcmpo(tcg_env, t0, t1, crf); + gen_helper_float_check_status(tcg_env); } /* fcmpu */ @@ -400,14 +368,11 @@ static void gen_fcmpu(DisasContext *ctx) t0 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); gen_reset_fpstatus(); - crf = tcg_const_i32(crfD(ctx->opcode)); + crf = tcg_constant_i32(crfD(ctx->opcode)); get_fpr(t0, rA(ctx->opcode)); get_fpr(t1, rB(ctx->opcode)); - gen_helper_fcmpu(cpu_env, t0, t1, crf); - tcg_temp_free_i32(crf); - gen_helper_float_check_status(cpu_env); - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); + gen_helper_fcmpu(tcg_env, t0, t1, crf); + gen_helper_float_check_status(tcg_env); } /*** Floating-point move ***/ @@ -429,8 +394,6 @@ static void gen_fabs(DisasContext *ctx) if (unlikely(Rc(ctx->opcode))) { gen_set_cr1_from_fpscr(ctx); } - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); } /* fmr - fmr. */ @@ -448,7 +411,6 @@ static void gen_fmr(DisasContext *ctx) if (unlikely(Rc(ctx->opcode))) { gen_set_cr1_from_fpscr(ctx); } - tcg_temp_free_i64(t0); } /* fnabs */ @@ -469,8 +431,6 @@ static void gen_fnabs(DisasContext *ctx) if (unlikely(Rc(ctx->opcode))) { gen_set_cr1_from_fpscr(ctx); } - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); } /* fneg */ @@ -491,8 +451,6 @@ static void gen_fneg(DisasContext *ctx) if (unlikely(Rc(ctx->opcode))) { gen_set_cr1_from_fpscr(ctx); } - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); } /* fcpsgn: PowerPC 2.05 specification */ @@ -516,9 +474,6 @@ static void gen_fcpsgn(DisasContext *ctx) if (unlikely(Rc(ctx->opcode))) { gen_set_cr1_from_fpscr(ctx); } - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); - tcg_temp_free_i64(t2); } static void gen_fmrgew(DisasContext *ctx) @@ -538,9 +493,6 @@ static void gen_fmrgew(DisasContext *ctx) get_fpr(t0, rA(ctx->opcode)); tcg_gen_deposit_i64(t1, t0, b0, 0, 32); set_fpr(rD(ctx->opcode), t1); - tcg_temp_free_i64(b0); - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); } static void gen_fmrgow(DisasContext *ctx) @@ -559,9 +511,6 @@ static void gen_fmrgow(DisasContext *ctx) get_fpr(t1, rA(ctx->opcode)); tcg_gen_deposit_i64(t2, t0, t1, 32, 32); set_fpr(rD(ctx->opcode), t2); - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); - tcg_temp_free_i64(t2); } /*** Floating-Point status & ctrl register ***/ @@ -587,153 +536,147 @@ static void gen_mcrfs(DisasContext *ctx) tcg_gen_trunc_tl_i32(cpu_crf[crfD(ctx->opcode)], tmp); tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], 0xf); - tcg_temp_free(tmp); tcg_gen_extu_tl_i64(tnew_fpscr, cpu_fpscr); /* Only the exception bits (including FX) should be cleared if read */ tcg_gen_andi_i64(tnew_fpscr, tnew_fpscr, ~((0xF << shift) & FP_EX_CLEAR_BITS)); /* FEX and VX need to be updated, so don't set fpscr directly */ - tmask = tcg_const_i32(1 << nibble); - gen_helper_store_fpscr(cpu_env, tnew_fpscr, tmask); - tcg_temp_free_i32(tmask); - tcg_temp_free_i64(tnew_fpscr); + tmask = tcg_constant_i32(1 << nibble); + gen_helper_store_fpscr(tcg_env, tnew_fpscr, tmask); } -/* mffs */ -static void gen_mffs(DisasContext *ctx) +static TCGv_i64 place_from_fpscr(int rt, uint64_t mask) { - TCGv_i64 t0; - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } - t0 = tcg_temp_new_i64(); - gen_reset_fpstatus(); - tcg_gen_extu_tl_i64(t0, cpu_fpscr); - set_fpr(rD(ctx->opcode), t0); - if (unlikely(Rc(ctx->opcode))) { - gen_set_cr1_from_fpscr(ctx); - } - tcg_temp_free_i64(t0); + TCGv_i64 fpscr = tcg_temp_new_i64(); + TCGv_i64 fpscr_masked = tcg_temp_new_i64(); + + tcg_gen_extu_tl_i64(fpscr, cpu_fpscr); + tcg_gen_andi_i64(fpscr_masked, fpscr, mask); + set_fpr(rt, fpscr_masked); + + return fpscr; } -/* mffsl */ -static void gen_mffsl(DisasContext *ctx) +static void store_fpscr_masked(TCGv_i64 fpscr, uint64_t clear_mask, + TCGv_i64 set_mask, uint32_t store_mask) { - TCGv_i64 t0; + TCGv_i64 fpscr_masked = tcg_temp_new_i64(); + TCGv_i32 st_mask = tcg_constant_i32(store_mask); - if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) { - return gen_mffs(ctx); - } + tcg_gen_andi_i64(fpscr_masked, fpscr, ~clear_mask); + tcg_gen_or_i64(fpscr_masked, fpscr_masked, set_mask); + gen_helper_store_fpscr(tcg_env, fpscr_masked, st_mask); +} - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; +static bool trans_MFFS_ISA207(DisasContext *ctx, arg_X_t_rc *a) +{ + if (!(ctx->insns_flags2 & PPC2_ISA300)) { + /* + * Before Power ISA v3.0, MFFS bits 11~15 were reserved, any instruction + * with OPCD=63 and XO=583 should be decoded as MFFS. + */ + return trans_MFFS(ctx, a); } - t0 = tcg_temp_new_i64(); - gen_reset_fpstatus(); - tcg_gen_extu_tl_i64(t0, cpu_fpscr); - /* Mask everything except mode, status, and enables. */ - tcg_gen_andi_i64(t0, t0, FP_DRN | FP_STATUS | FP_ENABLES | FP_RN); - set_fpr(rD(ctx->opcode), t0); - tcg_temp_free_i64(t0); + /* + * For Power ISA v3.0+, return false and let the pattern group + * select the correct instruction. + */ + return false; } -/* mffsce */ -static void gen_mffsce(DisasContext *ctx) +static bool trans_MFFS(DisasContext *ctx, arg_X_t_rc *a) { - TCGv_i64 t0; - TCGv_i32 mask; + REQUIRE_FPU(ctx); - if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) { - return gen_mffs(ctx); + gen_reset_fpstatus(); + place_from_fpscr(a->rt, UINT64_MAX); + if (a->rc) { + gen_set_cr1_from_fpscr(ctx); } + return true; +} - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } +static bool trans_MFFSCE(DisasContext *ctx, arg_X_t *a) +{ + TCGv_i64 fpscr; - t0 = tcg_temp_new_i64(); + REQUIRE_FPU(ctx); gen_reset_fpstatus(); - tcg_gen_extu_tl_i64(t0, cpu_fpscr); - set_fpr(rD(ctx->opcode), t0); - - /* Clear exception enable bits in the FPSCR. */ - tcg_gen_andi_i64(t0, t0, ~FP_ENABLES); - mask = tcg_const_i32(0x0003); - gen_helper_store_fpscr(cpu_env, t0, mask); - - tcg_temp_free_i32(mask); - tcg_temp_free_i64(t0); + fpscr = place_from_fpscr(a->rt, UINT64_MAX); + store_fpscr_masked(fpscr, FP_ENABLES, tcg_constant_i64(0), 0x0003); + return true; } -static void gen_helper_mffscrn(DisasContext *ctx, TCGv_i64 t1) +static bool trans_MFFSCRN(DisasContext *ctx, arg_X_tb *a) { - TCGv_i64 t0 = tcg_temp_new_i64(); - TCGv_i32 mask = tcg_const_i32(0x0001); + TCGv_i64 t1, fpscr; + + REQUIRE_FPU(ctx); + + t1 = tcg_temp_new_i64(); + get_fpr(t1, a->rb); + tcg_gen_andi_i64(t1, t1, FP_RN); gen_reset_fpstatus(); - tcg_gen_extu_tl_i64(t0, cpu_fpscr); - tcg_gen_andi_i64(t0, t0, FP_DRN | FP_ENABLES | FP_RN); - set_fpr(rD(ctx->opcode), t0); + fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN); + store_fpscr_masked(fpscr, FP_RN, t1, 0x0001); + return true; +} - /* Mask FPSCR value to clear RN. */ - tcg_gen_andi_i64(t0, t0, ~FP_RN); +static bool trans_MFFSCDRN(DisasContext *ctx, arg_X_tb *a) +{ + TCGv_i64 t1, fpscr; - /* Merge RN into FPSCR value. */ - tcg_gen_or_i64(t0, t0, t1); + REQUIRE_FPU(ctx); - gen_helper_store_fpscr(cpu_env, t0, mask); + t1 = tcg_temp_new_i64(); + get_fpr(t1, a->rb); + tcg_gen_andi_i64(t1, t1, FP_DRN); - tcg_temp_free_i32(mask); - tcg_temp_free_i64(t0); + gen_reset_fpstatus(); + fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN); + store_fpscr_masked(fpscr, FP_DRN, t1, 0x0100); + return true; } -/* mffscrn */ -static void gen_mffscrn(DisasContext *ctx) +static bool trans_MFFSCRNI(DisasContext *ctx, arg_X_imm2 *a) { - TCGv_i64 t1; + TCGv_i64 t1, fpscr; - if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) { - return gen_mffs(ctx); - } - - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } + REQUIRE_FPU(ctx); t1 = tcg_temp_new_i64(); - get_fpr(t1, rB(ctx->opcode)); - /* Mask FRB to get just RN. */ - tcg_gen_andi_i64(t1, t1, FP_RN); - - gen_helper_mffscrn(ctx, t1); + tcg_gen_movi_i64(t1, a->imm); - tcg_temp_free_i64(t1); + gen_reset_fpstatus(); + fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN); + store_fpscr_masked(fpscr, FP_RN, t1, 0x0001); + return true; } -/* mffscrni */ -static void gen_mffscrni(DisasContext *ctx) +static bool trans_MFFSCDRNI(DisasContext *ctx, arg_X_imm3 *a) { - TCGv_i64 t1; + TCGv_i64 t1, fpscr; - if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) { - return gen_mffs(ctx); - } + REQUIRE_FPU(ctx); - if (unlikely(!ctx->fpu_enabled)) { - gen_exception(ctx, POWERPC_EXCP_FPU); - return; - } + t1 = tcg_temp_new_i64(); + tcg_gen_movi_i64(t1, (uint64_t)a->imm << FPSCR_DRN0); - t1 = tcg_const_i64((uint64_t)RM(ctx->opcode)); + gen_reset_fpstatus(); + fpscr = place_from_fpscr(a->rt, FP_DRN | FP_ENABLES | FP_NI | FP_RN); + store_fpscr_masked(fpscr, FP_DRN, t1, 0x0100); + return true; +} - gen_helper_mffscrn(ctx, t1); +static bool trans_MFFSL(DisasContext *ctx, arg_X_t *a) +{ + REQUIRE_FPU(ctx); - tcg_temp_free_i64(t1); + gen_reset_fpstatus(); + place_from_fpscr(a->rt, FP_DRN | FP_STATUS | FP_ENABLES | FP_NI | FP_RN); + return true; } /* mtfsb0 */ @@ -748,10 +691,7 @@ static void gen_mtfsb0(DisasContext *ctx) crb = 31 - crbD(ctx->opcode); gen_reset_fpstatus(); if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) { - TCGv_i32 t0; - t0 = tcg_const_i32(crb); - gen_helper_fpscr_clrbit(cpu_env, t0); - tcg_temp_free_i32(t0); + gen_helper_fpscr_clrbit(tcg_env, tcg_constant_i32(crb)); } if (unlikely(Rc(ctx->opcode) != 0)) { tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); @@ -769,20 +709,16 @@ static void gen_mtfsb1(DisasContext *ctx) return; } crb = 31 - crbD(ctx->opcode); - gen_reset_fpstatus(); /* XXX: we pretend we can only do IEEE floating-point computations */ if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) { - TCGv_i32 t0; - t0 = tcg_const_i32(crb); - gen_helper_fpscr_setbit(cpu_env, t0); - tcg_temp_free_i32(t0); + gen_helper_fpscr_setbit(tcg_env, tcg_constant_i32(crb)); } if (unlikely(Rc(ctx->opcode) != 0)) { tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); } /* We can raise a deferred exception */ - gen_helper_float_check_status(cpu_env); + gen_helper_fpscr_check_status(tcg_env); } /* mtfsf */ @@ -803,23 +739,22 @@ static void gen_mtfsf(DisasContext *ctx) gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); return; } - gen_reset_fpstatus(); - if (l) { - t0 = tcg_const_i32((ctx->insns_flags2 & PPC2_ISA205) ? 0xffff : 0xff); + if (!l) { + t0 = tcg_constant_i32(flm << (w * 8)); + } else if (ctx->insns_flags2 & PPC2_ISA205) { + t0 = tcg_constant_i32(0xffff); } else { - t0 = tcg_const_i32(flm << (w * 8)); + t0 = tcg_constant_i32(0xff); } t1 = tcg_temp_new_i64(); get_fpr(t1, rB(ctx->opcode)); - gen_helper_store_fpscr(cpu_env, t1, t0); - tcg_temp_free_i32(t0); + gen_helper_store_fpscr(tcg_env, t1, t0); if (unlikely(Rc(ctx->opcode) != 0)) { tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); } /* We can raise a deferred exception */ - gen_helper_float_check_status(cpu_env); - tcg_temp_free_i64(t1); + gen_helper_fpscr_check_status(tcg_env); } /* mtfsfi */ @@ -840,132 +775,30 @@ static void gen_mtfsfi(DisasContext *ctx) return; } sh = (8 * w) + 7 - bf; - gen_reset_fpstatus(); - t0 = tcg_const_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh)); - t1 = tcg_const_i32(1 << sh); - gen_helper_store_fpscr(cpu_env, t0, t1); - tcg_temp_free_i64(t0); - tcg_temp_free_i32(t1); + t0 = tcg_constant_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh)); + t1 = tcg_constant_i32(1 << sh); + gen_helper_store_fpscr(tcg_env, t0, t1); if (unlikely(Rc(ctx->opcode) != 0)) { tcg_gen_trunc_tl_i32(cpu_crf[1], cpu_fpscr); tcg_gen_shri_i32(cpu_crf[1], cpu_crf[1], FPSCR_OX); } /* We can raise a deferred exception */ - gen_helper_float_check_status(cpu_env); -} - -/*** Floating-point load ***/ -#define GEN_LDF(name, ldop, opc, type) \ -static void glue(gen_, name)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - TCGv_i64 t0; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_FLOAT); \ - EA = tcg_temp_new(); \ - t0 = tcg_temp_new_i64(); \ - gen_addr_imm_index(ctx, EA, 0); \ - gen_qemu_##ldop(ctx, t0, EA); \ - set_fpr(rD(ctx->opcode), t0); \ - tcg_temp_free(EA); \ - tcg_temp_free_i64(t0); \ -} - -#define GEN_LDUF(name, ldop, opc, type) \ -static void glue(gen_, name##u)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - TCGv_i64 t0; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - if (unlikely(rA(ctx->opcode) == 0)) { \ - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_FLOAT); \ - EA = tcg_temp_new(); \ - t0 = tcg_temp_new_i64(); \ - gen_addr_imm_index(ctx, EA, 0); \ - gen_qemu_##ldop(ctx, t0, EA); \ - set_fpr(rD(ctx->opcode), t0); \ - tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ - tcg_temp_free(EA); \ - tcg_temp_free_i64(t0); \ -} - -#define GEN_LDUXF(name, ldop, opc, type) \ -static void glue(gen_, name##ux)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - TCGv_i64 t0; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - t0 = tcg_temp_new_i64(); \ - if (unlikely(rA(ctx->opcode) == 0)) { \ - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_FLOAT); \ - EA = tcg_temp_new(); \ - gen_addr_reg_index(ctx, EA); \ - gen_qemu_##ldop(ctx, t0, EA); \ - set_fpr(rD(ctx->opcode), t0); \ - tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ - tcg_temp_free(EA); \ - tcg_temp_free_i64(t0); \ + gen_helper_fpscr_check_status(tcg_env); } -#define GEN_LDXF(name, ldop, opc2, opc3, type) \ -static void glue(gen_, name##x)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - TCGv_i64 t0; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_FLOAT); \ - EA = tcg_temp_new(); \ - t0 = tcg_temp_new_i64(); \ - gen_addr_reg_index(ctx, EA); \ - gen_qemu_##ldop(ctx, t0, EA); \ - set_fpr(rD(ctx->opcode), t0); \ - tcg_temp_free(EA); \ - tcg_temp_free_i64(t0); \ -} - -#define GEN_LDFS(name, ldop, op, type) \ -GEN_LDF(name, ldop, op | 0x20, type); \ -GEN_LDUF(name, ldop, op | 0x21, type); \ -GEN_LDUXF(name, ldop, op | 0x01, type); \ -GEN_LDXF(name, ldop, 0x17, op | 0x00, type) - static void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 dest, TCGv addr) { TCGv_i32 tmp = tcg_temp_new_i32(); tcg_gen_qemu_ld_i32(tmp, addr, ctx->mem_idx, DEF_MEMOP(MO_UL)); gen_helper_todouble(dest, tmp); - tcg_temp_free_i32(tmp); } - /* lfd lfdu lfdux lfdx */ -GEN_LDFS(lfd, ld64_i64, 0x12, PPC_FLOAT); - /* lfs lfsu lfsux lfsx */ -GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT); - /* lfdepx (external PID lfdx) */ static void gen_lfdepx(DisasContext *ctx) { TCGv EA; TCGv_i64 t0; - CHK_SV; + CHK_SV(ctx); if (unlikely(!ctx->fpu_enabled)) { gen_exception(ctx, POWERPC_EXCP_FPU); return; @@ -974,10 +807,8 @@ static void gen_lfdepx(DisasContext *ctx) EA = tcg_temp_new(); t0 = tcg_temp_new_i64(); gen_addr_reg_index(ctx, EA); - tcg_gen_qemu_ld_i64(t0, EA, PPC_TLB_EPID_LOAD, DEF_MEMOP(MO_Q)); + tcg_gen_qemu_ld_i64(t0, EA, PPC_TLB_EPID_LOAD, DEF_MEMOP(MO_UQ)); set_fpr(rD(ctx->opcode), t0); - tcg_temp_free(EA); - tcg_temp_free_i64(t0); } /* lfdp */ @@ -1010,8 +841,6 @@ static void gen_lfdp(DisasContext *ctx) gen_qemu_ld64_i64(ctx, t0, EA); set_fpr(rD(ctx->opcode) + 1, t0); } - tcg_temp_free(EA); - tcg_temp_free_i64(t0); } /* lfdpx */ @@ -1044,8 +873,6 @@ static void gen_lfdpx(DisasContext *ctx) gen_qemu_ld64_i64(ctx, t0, EA); set_fpr(rD(ctx->opcode) + 1, t0); } - tcg_temp_free(EA); - tcg_temp_free_i64(t0); } /* lfiwax */ @@ -1066,9 +893,6 @@ static void gen_lfiwax(DisasContext *ctx) gen_qemu_ld32s(ctx, t0, EA); tcg_gen_ext_tl_i64(t1, t0); set_fpr(rD(ctx->opcode), t1); - tcg_temp_free(EA); - tcg_temp_free(t0); - tcg_temp_free_i64(t1); } /* lfiwzx */ @@ -1086,75 +910,6 @@ static void gen_lfiwzx(DisasContext *ctx) gen_addr_reg_index(ctx, EA); gen_qemu_ld32u_i64(ctx, t0, EA); set_fpr(rD(ctx->opcode), t0); - tcg_temp_free(EA); - tcg_temp_free_i64(t0); -} -/*** Floating-point store ***/ -#define GEN_STF(name, stop, opc, type) \ -static void glue(gen_, name)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - TCGv_i64 t0; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_FLOAT); \ - EA = tcg_temp_new(); \ - t0 = tcg_temp_new_i64(); \ - gen_addr_imm_index(ctx, EA, 0); \ - get_fpr(t0, rS(ctx->opcode)); \ - gen_qemu_##stop(ctx, t0, EA); \ - tcg_temp_free(EA); \ - tcg_temp_free_i64(t0); \ -} - -#define GEN_STUF(name, stop, opc, type) \ -static void glue(gen_, name##u)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - TCGv_i64 t0; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - if (unlikely(rA(ctx->opcode) == 0)) { \ - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_FLOAT); \ - EA = tcg_temp_new(); \ - t0 = tcg_temp_new_i64(); \ - gen_addr_imm_index(ctx, EA, 0); \ - get_fpr(t0, rS(ctx->opcode)); \ - gen_qemu_##stop(ctx, t0, EA); \ - tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ - tcg_temp_free(EA); \ - tcg_temp_free_i64(t0); \ -} - -#define GEN_STUXF(name, stop, opc, type) \ -static void glue(gen_, name##ux)(DisasContext *ctx) \ -{ \ - TCGv EA; \ - TCGv_i64 t0; \ - if (unlikely(!ctx->fpu_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_FPU); \ - return; \ - } \ - if (unlikely(rA(ctx->opcode) == 0)) { \ - gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \ - return; \ - } \ - gen_set_access_type(ctx, ACCESS_FLOAT); \ - EA = tcg_temp_new(); \ - t0 = tcg_temp_new_i64(); \ - gen_addr_reg_index(ctx, EA); \ - get_fpr(t0, rS(ctx->opcode)); \ - gen_qemu_##stop(ctx, t0, EA); \ - tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA); \ - tcg_temp_free(EA); \ - tcg_temp_free_i64(t0); \ } #define GEN_STXF(name, stop, opc2, opc3, type) \ @@ -1172,35 +927,21 @@ static void glue(gen_, name##x)(DisasContext *ctx) \ gen_addr_reg_index(ctx, EA); \ get_fpr(t0, rS(ctx->opcode)); \ gen_qemu_##stop(ctx, t0, EA); \ - tcg_temp_free(EA); \ - tcg_temp_free_i64(t0); \ } -#define GEN_STFS(name, stop, op, type) \ -GEN_STF(name, stop, op | 0x20, type); \ -GEN_STUF(name, stop, op | 0x21, type); \ -GEN_STUXF(name, stop, op | 0x01, type); \ -GEN_STXF(name, stop, 0x17, op | 0x00, type) - static void gen_qemu_st32fs(DisasContext *ctx, TCGv_i64 src, TCGv addr) { TCGv_i32 tmp = tcg_temp_new_i32(); gen_helper_tosingle(tmp, src); tcg_gen_qemu_st_i32(tmp, addr, ctx->mem_idx, DEF_MEMOP(MO_UL)); - tcg_temp_free_i32(tmp); } -/* stfd stfdu stfdux stfdx */ -GEN_STFS(stfd, st64_i64, 0x16, PPC_FLOAT); -/* stfs stfsu stfsux stfsx */ -GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT); - /* stfdepx (external PID lfdx) */ static void gen_stfdepx(DisasContext *ctx) { TCGv EA; TCGv_i64 t0; - CHK_SV; + CHK_SV(ctx); if (unlikely(!ctx->fpu_enabled)) { gen_exception(ctx, POWERPC_EXCP_FPU); return; @@ -1210,9 +951,7 @@ static void gen_stfdepx(DisasContext *ctx) t0 = tcg_temp_new_i64(); gen_addr_reg_index(ctx, EA); get_fpr(t0, rD(ctx->opcode)); - tcg_gen_qemu_st_i64(t0, EA, PPC_TLB_EPID_STORE, DEF_MEMOP(MO_Q)); - tcg_temp_free(EA); - tcg_temp_free_i64(t0); + tcg_gen_qemu_st_i64(t0, EA, PPC_TLB_EPID_STORE, DEF_MEMOP(MO_UQ)); } /* stfdp */ @@ -1245,8 +984,6 @@ static void gen_stfdp(DisasContext *ctx) get_fpr(t0, rD(ctx->opcode) + 1); gen_qemu_st64_i64(ctx, t0, EA); } - tcg_temp_free(EA); - tcg_temp_free_i64(t0); } /* stfdpx */ @@ -1279,8 +1016,6 @@ static void gen_stfdpx(DisasContext *ctx) get_fpr(t0, rD(ctx->opcode) + 1); gen_qemu_st64_i64(ctx, t0, EA); } - tcg_temp_free(EA); - tcg_temp_free_i64(t0); } /* Optional: */ @@ -1289,189 +1024,92 @@ static inline void gen_qemu_st32fiw(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) TCGv t0 = tcg_temp_new(); tcg_gen_trunc_i64_tl(t0, arg1), gen_qemu_st32(ctx, t0, arg2); - tcg_temp_free(t0); } /* stfiwx */ GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX); -/* POWER2 specific instructions */ -/* Quad manipulation (load/store two floats at a time) */ - -/* lfq */ -static void gen_lfq(DisasContext *ctx) -{ - int rd = rD(ctx->opcode); - TCGv t0; - TCGv_i64 t1; - gen_set_access_type(ctx, ACCESS_FLOAT); - t0 = tcg_temp_new(); - t1 = tcg_temp_new_i64(); - gen_addr_imm_index(ctx, t0, 0); - gen_qemu_ld64_i64(ctx, t1, t0); - set_fpr(rd, t1); - gen_addr_add(ctx, t0, t0, 8); - gen_qemu_ld64_i64(ctx, t1, t0); - set_fpr((rd + 1) % 32, t1); - tcg_temp_free(t0); - tcg_temp_free_i64(t1); -} - -/* lfqu */ -static void gen_lfqu(DisasContext *ctx) +/* Floating-point Load/Store Instructions */ +static bool do_lsfpsd(DisasContext *ctx, int rt, int ra, TCGv displ, + bool update, bool store, bool single) { - int ra = rA(ctx->opcode); - int rd = rD(ctx->opcode); - TCGv t0, t1; - TCGv_i64 t2; - gen_set_access_type(ctx, ACCESS_FLOAT); - t0 = tcg_temp_new(); - t1 = tcg_temp_new(); - t2 = tcg_temp_new_i64(); - gen_addr_imm_index(ctx, t0, 0); - gen_qemu_ld64_i64(ctx, t2, t0); - set_fpr(rd, t2); - gen_addr_add(ctx, t1, t0, 8); - gen_qemu_ld64_i64(ctx, t2, t1); - set_fpr((rd + 1) % 32, t2); - if (ra != 0) { - tcg_gen_mov_tl(cpu_gpr[ra], t0); + TCGv ea; + TCGv_i64 t0; + REQUIRE_INSNS_FLAGS(ctx, FLOAT); + REQUIRE_FPU(ctx); + if (update && ra == 0) { + gen_invalid(ctx); + return true; } - tcg_temp_free(t0); - tcg_temp_free(t1); - tcg_temp_free_i64(t2); -} - -/* lfqux */ -static void gen_lfqux(DisasContext *ctx) -{ - int ra = rA(ctx->opcode); - int rd = rD(ctx->opcode); gen_set_access_type(ctx, ACCESS_FLOAT); - TCGv t0, t1; - TCGv_i64 t2; - t2 = tcg_temp_new_i64(); - t0 = tcg_temp_new(); - gen_addr_reg_index(ctx, t0); - gen_qemu_ld64_i64(ctx, t2, t0); - set_fpr(rd, t2); - t1 = tcg_temp_new(); - gen_addr_add(ctx, t1, t0, 8); - gen_qemu_ld64_i64(ctx, t2, t1); - set_fpr((rd + 1) % 32, t2); - tcg_temp_free(t1); - if (ra != 0) { - tcg_gen_mov_tl(cpu_gpr[ra], t0); + t0 = tcg_temp_new_i64(); + ea = do_ea_calc(ctx, ra, displ); + if (store) { + get_fpr(t0, rt); + if (single) { + gen_qemu_st32fs(ctx, t0, ea); + } else { + gen_qemu_st64_i64(ctx, t0, ea); + } + } else { + if (single) { + gen_qemu_ld32fs(ctx, t0, ea); + } else { + gen_qemu_ld64_i64(ctx, t0, ea); + } + set_fpr(rt, t0); } - tcg_temp_free(t0); - tcg_temp_free_i64(t2); -} - -/* lfqx */ -static void gen_lfqx(DisasContext *ctx) -{ - int rd = rD(ctx->opcode); - TCGv t0; - TCGv_i64 t1; - gen_set_access_type(ctx, ACCESS_FLOAT); - t0 = tcg_temp_new(); - t1 = tcg_temp_new_i64(); - gen_addr_reg_index(ctx, t0); - gen_qemu_ld64_i64(ctx, t1, t0); - set_fpr(rd, t1); - gen_addr_add(ctx, t0, t0, 8); - gen_qemu_ld64_i64(ctx, t1, t0); - set_fpr((rd + 1) % 32, t1); - tcg_temp_free(t0); - tcg_temp_free_i64(t1); + if (update) { + tcg_gen_mov_tl(cpu_gpr[ra], ea); + } + return true; } -/* stfq */ -static void gen_stfq(DisasContext *ctx) +static bool do_lsfp_D(DisasContext *ctx, arg_D *a, bool update, bool store, + bool single) { - int rd = rD(ctx->opcode); - TCGv t0; - TCGv_i64 t1; - gen_set_access_type(ctx, ACCESS_FLOAT); - t0 = tcg_temp_new(); - t1 = tcg_temp_new_i64(); - gen_addr_imm_index(ctx, t0, 0); - get_fpr(t1, rd); - gen_qemu_st64_i64(ctx, t1, t0); - gen_addr_add(ctx, t0, t0, 8); - get_fpr(t1, (rd + 1) % 32); - gen_qemu_st64_i64(ctx, t1, t0); - tcg_temp_free(t0); - tcg_temp_free_i64(t1); + return do_lsfpsd(ctx, a->rt, a->ra, tcg_constant_tl(a->si), update, store, + single); } -/* stfqu */ -static void gen_stfqu(DisasContext *ctx) +static bool do_lsfp_PLS_D(DisasContext *ctx, arg_PLS_D *a, bool update, + bool store, bool single) { - int ra = rA(ctx->opcode); - int rd = rD(ctx->opcode); - TCGv t0, t1; - TCGv_i64 t2; - gen_set_access_type(ctx, ACCESS_FLOAT); - t2 = tcg_temp_new_i64(); - t0 = tcg_temp_new(); - gen_addr_imm_index(ctx, t0, 0); - get_fpr(t2, rd); - gen_qemu_st64_i64(ctx, t2, t0); - t1 = tcg_temp_new(); - gen_addr_add(ctx, t1, t0, 8); - get_fpr(t2, (rd + 1) % 32); - gen_qemu_st64_i64(ctx, t2, t1); - tcg_temp_free(t1); - if (ra != 0) { - tcg_gen_mov_tl(cpu_gpr[ra], t0); + arg_D d; + if (!resolve_PLS_D(ctx, &d, a)) { + return true; } - tcg_temp_free(t0); - tcg_temp_free_i64(t2); + return do_lsfp_D(ctx, &d, update, store, single); } -/* stfqux */ -static void gen_stfqux(DisasContext *ctx) +static bool do_lsfp_X(DisasContext *ctx, arg_X *a, bool update, + bool store, bool single) { - int ra = rA(ctx->opcode); - int rd = rD(ctx->opcode); - TCGv t0, t1; - TCGv_i64 t2; - gen_set_access_type(ctx, ACCESS_FLOAT); - t2 = tcg_temp_new_i64(); - t0 = tcg_temp_new(); - gen_addr_reg_index(ctx, t0); - get_fpr(t2, rd); - gen_qemu_st64_i64(ctx, t2, t0); - t1 = tcg_temp_new(); - gen_addr_add(ctx, t1, t0, 8); - get_fpr(t2, (rd + 1) % 32); - gen_qemu_st64_i64(ctx, t2, t1); - tcg_temp_free(t1); - if (ra != 0) { - tcg_gen_mov_tl(cpu_gpr[ra], t0); - } - tcg_temp_free(t0); - tcg_temp_free_i64(t2); + return do_lsfpsd(ctx, a->rt, a->ra, cpu_gpr[a->rb], update, store, single); } -/* stfqx */ -static void gen_stfqx(DisasContext *ctx) -{ - int rd = rD(ctx->opcode); - TCGv t0; - TCGv_i64 t1; - gen_set_access_type(ctx, ACCESS_FLOAT); - t1 = tcg_temp_new_i64(); - t0 = tcg_temp_new(); - gen_addr_reg_index(ctx, t0); - get_fpr(t1, rd); - gen_qemu_st64_i64(ctx, t1, t0); - gen_addr_add(ctx, t0, t0, 8); - get_fpr(t1, (rd + 1) % 32); - gen_qemu_st64_i64(ctx, t1, t0); - tcg_temp_free(t0); - tcg_temp_free_i64(t1); -} +TRANS(LFS, do_lsfp_D, false, false, true) +TRANS(LFSU, do_lsfp_D, true, false, true) +TRANS(LFSX, do_lsfp_X, false, false, true) +TRANS(LFSUX, do_lsfp_X, true, false, true) +TRANS(PLFS, do_lsfp_PLS_D, false, false, true) + +TRANS(LFD, do_lsfp_D, false, false, false) +TRANS(LFDU, do_lsfp_D, true, false, false) +TRANS(LFDX, do_lsfp_X, false, false, false) +TRANS(LFDUX, do_lsfp_X, true, false, false) +TRANS(PLFD, do_lsfp_PLS_D, false, false, false) + +TRANS(STFS, do_lsfp_D, false, true, true) +TRANS(STFSU, do_lsfp_D, true, true, true) +TRANS(STFSX, do_lsfp_X, false, true, true) +TRANS(STFSUX, do_lsfp_X, true, true, true) +TRANS(PSTFS, do_lsfp_PLS_D, false, true, true) + +TRANS(STFD, do_lsfp_D, false, true, false) +TRANS(STFDU, do_lsfp_D, true, true, false) +TRANS(STFDX, do_lsfp_X, false, true, false) +TRANS(STFDUX, do_lsfp_X, true, true, false) +TRANS(PSTFD, do_lsfp_PLS_D, false, true, false) #undef _GEN_FLOAT_ACB #undef GEN_FLOAT_ACB diff --git a/target/ppc/translate/fp-ops.c.inc b/target/ppc/translate/fp-ops.c.inc index 88fab65628..d4c6c4bed1 100644 --- a/target/ppc/translate/fp-ops.c.inc +++ b/target/ppc/translate/fp-ops.c.inc @@ -24,7 +24,6 @@ GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT), GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT), GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES), GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE), -_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL), GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT), GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT), GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT), @@ -50,50 +49,19 @@ GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT), GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT), GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT), -#define GEN_LDF(name, ldop, opc, type) \ -GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type), -#define GEN_LDUF(name, ldop, opc, type) \ -GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type), -#define GEN_LDUXF(name, ldop, opc, type) \ -GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type), -#define GEN_LDXF(name, ldop, opc2, opc3, type) \ -GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type), -#define GEN_LDFS(name, ldop, op, type) \ -GEN_LDF(name, ldop, op | 0x20, type) \ -GEN_LDUF(name, ldop, op | 0x21, type) \ -GEN_LDUXF(name, ldop, op | 0x01, type) \ -GEN_LDXF(name, ldop, 0x17, op | 0x00, type) - -GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT) -GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT) GEN_HANDLER_E(lfdepx, 0x1F, 0x1F, 0x12, 0x00000001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER_E(lfiwax, 0x1f, 0x17, 0x1a, 0x00000001, PPC_NONE, PPC2_ISA205), GEN_HANDLER_E(lfiwzx, 0x1f, 0x17, 0x1b, 0x1, PPC_NONE, PPC2_FP_CVT_ISA206), GEN_HANDLER_E(lfdpx, 0x1F, 0x17, 0x18, 0x00200001, PPC_NONE, PPC2_ISA205), -#define GEN_STF(name, stop, opc, type) \ -GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type), -#define GEN_STUF(name, stop, opc, type) \ -GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type), -#define GEN_STUXF(name, stop, opc, type) \ -GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type), #define GEN_STXF(name, stop, opc2, opc3, type) \ GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type), -#define GEN_STFS(name, stop, op, type) \ -GEN_STF(name, stop, op | 0x20, type) \ -GEN_STUF(name, stop, op | 0x21, type) \ -GEN_STUXF(name, stop, op | 0x01, type) \ -GEN_STXF(name, stop, 0x17, op | 0x00, type) -GEN_STFS(stfd, st64_i64, 0x16, PPC_FLOAT) -GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT) GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX) GEN_HANDLER_E(stfdepx, 0x1F, 0x1F, 0x16, 0x00000001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER_E(stfdpx, 0x1F, 0x17, 0x1C, 0x00200001, PPC_NONE, PPC2_ISA205), GEN_HANDLER(frsqrtes, 0x3B, 0x1A, 0xFF, 0x001F07C0, PPC_FLOAT_FRSQRTES), -GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT), -GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT), GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT), GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT), GEN_HANDLER(fabs, 0x3F, 0x08, 0x08, 0x001F0000, PPC_FLOAT), @@ -104,15 +72,6 @@ GEN_HANDLER_E(fcpsgn, 0x3F, 0x08, 0x00, 0x00000000, PPC_NONE, PPC2_ISA205), GEN_HANDLER_E(fmrgew, 0x3F, 0x06, 0x1E, 0x00000001, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(fmrgow, 0x3F, 0x06, 0x1A, 0x00000001, PPC_NONE, PPC2_VSX207), GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT), -GEN_HANDLER_E_2(mffs, 0x3F, 0x07, 0x12, 0x00, 0x00000000, PPC_FLOAT, PPC_NONE), -GEN_HANDLER_E_2(mffsce, 0x3F, 0x07, 0x12, 0x01, 0x00000000, PPC_FLOAT, - PPC2_ISA300), -GEN_HANDLER_E_2(mffsl, 0x3F, 0x07, 0x12, 0x18, 0x00000000, PPC_FLOAT, - PPC2_ISA300), -GEN_HANDLER_E_2(mffscrn, 0x3F, 0x07, 0x12, 0x16, 0x00000000, PPC_FLOAT, - PPC_NONE), -GEN_HANDLER_E_2(mffscrni, 0x3F, 0x07, 0x12, 0x17, 0x00000000, PPC_FLOAT, - PPC_NONE), GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT), GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT), GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x00000000, PPC_FLOAT), diff --git a/target/ppc/translate/processor-ctrl-impl.c.inc b/target/ppc/translate/processor-ctrl-impl.c.inc new file mode 100644 index 0000000000..0142801985 --- /dev/null +++ b/target/ppc/translate/processor-ctrl-impl.c.inc @@ -0,0 +1,105 @@ +/* + * Power ISA decode for Storage Control instructions + * + * Copyright (c) 2022 Instituto de Pesquisas Eldorado (eldorado.org.br) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +/* + * Processor Control Instructions + */ + +static bool trans_MSGCLR(DisasContext *ctx, arg_X_rb *a) +{ + if (!(ctx->insns_flags2 & PPC2_ISA207S)) { + /* + * Before Power ISA 2.07, processor control instructions were only + * implemented in the "Embedded.Processor Control" category. + */ + REQUIRE_INSNS_FLAGS2(ctx, PRCNTL); + } + + REQUIRE_HV(ctx); + +#if !defined(CONFIG_USER_ONLY) + if (is_book3s_arch2x(ctx)) { + gen_helper_book3s_msgclr(tcg_env, cpu_gpr[a->rb]); + } else { + gen_helper_msgclr(tcg_env, cpu_gpr[a->rb]); + } +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_MSGSND(DisasContext *ctx, arg_X_rb *a) +{ + if (!(ctx->insns_flags2 & PPC2_ISA207S)) { + /* + * Before Power ISA 2.07, processor control instructions were only + * implemented in the "Embedded.Processor Control" category. + */ + REQUIRE_INSNS_FLAGS2(ctx, PRCNTL); + } + + REQUIRE_HV(ctx); + +#if !defined(CONFIG_USER_ONLY) + if (is_book3s_arch2x(ctx)) { + gen_helper_book3s_msgsnd(cpu_gpr[a->rb]); + } else { + gen_helper_msgsnd(cpu_gpr[a->rb]); + } +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_MSGCLRP(DisasContext *ctx, arg_X_rb *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS2(ctx, ISA207S); + REQUIRE_SV(ctx); +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_helper_book3s_msgclrp(tcg_env, cpu_gpr[a->rb]); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_MSGSNDP(DisasContext *ctx, arg_X_rb *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS2(ctx, ISA207S); + REQUIRE_SV(ctx); +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_helper_book3s_msgsndp(tcg_env, cpu_gpr[a->rb]); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_MSGSYNC(DisasContext *ctx, arg_MSGSYNC *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_HV(ctx); + + /* interpreted as no-op */ + return true; +} diff --git a/target/ppc/translate/spe-impl.c.inc b/target/ppc/translate/spe-impl.c.inc index 2e6e799a25..454dac823e 100644 --- a/target/ppc/translate/spe-impl.c.inc +++ b/target/ppc/translate/spe-impl.c.inc @@ -22,8 +22,7 @@ static inline void gen_evmra(DisasContext *ctx) cpu_gprh[rA(ctx->opcode)]); /* spe_acc := tmp */ - tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUPPCState, spe_acc)); - tcg_temp_free_i64(tmp); + tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUPPCState, spe_acc)); /* rD := rA */ tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); @@ -96,8 +95,6 @@ static inline void gen_##name(DisasContext *ctx) \ tcg_gen_trunc_tl_i32(t0, cpu_gprh[rA(ctx->opcode)]); \ tcg_opi(t0, t0, rB(ctx->opcode)); \ tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0); \ - \ - tcg_temp_free_i32(t0); \ } GEN_SPEOP_TCG_LOGIC_IMM2(evslwi, tcg_gen_shli_i32); GEN_SPEOP_TCG_LOGIC_IMM2(evsrwiu, tcg_gen_shri_i32); @@ -122,8 +119,6 @@ static inline void gen_##name(DisasContext *ctx) \ tcg_gen_trunc_tl_i32(t0, cpu_gprh[rA(ctx->opcode)]); \ tcg_op(t0, t0); \ tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0); \ - \ - tcg_temp_free_i32(t0); \ } GEN_SPEOP_ARITH1(evabs, tcg_gen_abs_i32); @@ -159,16 +154,13 @@ static inline void gen_##name(DisasContext *ctx) \ tcg_gen_trunc_tl_i32(t1, cpu_gprh[rB(ctx->opcode)]); \ tcg_op(t0, t0, t1); \ tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0); \ - \ - tcg_temp_free_i32(t0); \ - tcg_temp_free_i32(t1); \ } static inline void gen_op_evsrwu(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { TCGLabel *l1 = gen_new_label(); TCGLabel *l2 = gen_new_label(); - TCGv_i32 t0 = tcg_temp_local_new_i32(); + TCGv_i32 t0 = tcg_temp_new_i32(); /* No error here: 6 bits are used */ tcg_gen_andi_i32(t0, arg2, 0x3F); @@ -178,14 +170,13 @@ static inline void gen_op_evsrwu(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) gen_set_label(l1); tcg_gen_movi_i32(ret, 0); gen_set_label(l2); - tcg_temp_free_i32(t0); } GEN_SPEOP_ARITH2(evsrwu, gen_op_evsrwu); static inline void gen_op_evsrws(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { TCGLabel *l1 = gen_new_label(); TCGLabel *l2 = gen_new_label(); - TCGv_i32 t0 = tcg_temp_local_new_i32(); + TCGv_i32 t0 = tcg_temp_new_i32(); /* No error here: 6 bits are used */ tcg_gen_andi_i32(t0, arg2, 0x3F); @@ -195,14 +186,13 @@ static inline void gen_op_evsrws(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) gen_set_label(l1); tcg_gen_movi_i32(ret, 0); gen_set_label(l2); - tcg_temp_free_i32(t0); } GEN_SPEOP_ARITH2(evsrws, gen_op_evsrws); static inline void gen_op_evslw(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { TCGLabel *l1 = gen_new_label(); TCGLabel *l2 = gen_new_label(); - TCGv_i32 t0 = tcg_temp_local_new_i32(); + TCGv_i32 t0 = tcg_temp_new_i32(); /* No error here: 6 bits are used */ tcg_gen_andi_i32(t0, arg2, 0x3F); @@ -212,7 +202,6 @@ static inline void gen_op_evslw(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) gen_set_label(l1); tcg_gen_movi_i32(ret, 0); gen_set_label(l2); - tcg_temp_free_i32(t0); } GEN_SPEOP_ARITH2(evslw, gen_op_evslw); static inline void gen_op_evrlw(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) @@ -220,7 +209,6 @@ static inline void gen_op_evrlw(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) TCGv_i32 t0 = tcg_temp_new_i32(); tcg_gen_andi_i32(t0, arg2, 0x1F); tcg_gen_rotl_i32(ret, arg1, t0); - tcg_temp_free_i32(t0); } GEN_SPEOP_ARITH2(evrlw, gen_op_evrlw); static inline void gen_evmergehi(DisasContext *ctx) @@ -257,8 +245,6 @@ static inline void gen_##name(DisasContext *ctx) \ tcg_gen_trunc_tl_i32(t0, cpu_gprh[rB(ctx->opcode)]); \ tcg_op(t0, t0, rA(ctx->opcode)); \ tcg_gen_extu_i32_tl(cpu_gprh[rD(ctx->opcode)], t0); \ - \ - tcg_temp_free_i32(t0); \ } GEN_SPEOP_ARITH_IMM2(evaddiw, tcg_gen_addi_i32); GEN_SPEOP_ARITH_IMM2(evsubifw, tcg_gen_subi_i32); @@ -341,7 +327,6 @@ static inline void gen_evmergelohi(DisasContext *ctx) tcg_gen_mov_tl(tmp, cpu_gpr[rA(ctx->opcode)]); tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], tmp); - tcg_temp_free(tmp); } else { tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]); tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]); @@ -378,7 +363,7 @@ static inline void gen_evsel(DisasContext *ctx) TCGLabel *l2 = gen_new_label(); TCGLabel *l3 = gen_new_label(); TCGLabel *l4 = gen_new_label(); - TCGv_i32 t0 = tcg_temp_local_new_i32(); + TCGv_i32 t0 = tcg_temp_new_i32(); tcg_gen_andi_i32(t0, cpu_crf[ctx->opcode & 0x07], 1 << 3); tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1); @@ -394,7 +379,6 @@ static inline void gen_evsel(DisasContext *ctx) gen_set_label(l3); tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]); gen_set_label(l4); - tcg_temp_free_i32(t0); } static void gen_evsel0(DisasContext *ctx) @@ -456,9 +440,6 @@ static inline void gen_evmwumi(DisasContext *ctx) tcg_gen_mul_i64(t0, t0, t1); /* t0 := rA * rB */ gen_store_gpr64(rD(ctx->opcode), t0); /* rD := t0 */ - - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); } static inline void gen_evmwumia(DisasContext *ctx) @@ -476,8 +457,7 @@ static inline void gen_evmwumia(DisasContext *ctx) /* acc := rD */ gen_load_gpr64(tmp, rD(ctx->opcode)); - tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUPPCState, spe_acc)); - tcg_temp_free_i64(tmp); + tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUPPCState, spe_acc)); } static inline void gen_evmwumiaa(DisasContext *ctx) @@ -499,19 +479,16 @@ static inline void gen_evmwumiaa(DisasContext *ctx) gen_load_gpr64(tmp, rD(ctx->opcode)); /* Load acc */ - tcg_gen_ld_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc)); + tcg_gen_ld_i64(acc, tcg_env, offsetof(CPUPPCState, spe_acc)); /* acc := tmp + acc */ tcg_gen_add_i64(acc, acc, tmp); /* Store acc */ - tcg_gen_st_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc)); + tcg_gen_st_i64(acc, tcg_env, offsetof(CPUPPCState, spe_acc)); /* rD := acc */ gen_store_gpr64(rD(ctx->opcode), acc); - - tcg_temp_free_i64(acc); - tcg_temp_free_i64(tmp); } static inline void gen_evmwsmi(DisasContext *ctx) @@ -535,9 +512,6 @@ static inline void gen_evmwsmi(DisasContext *ctx) tcg_gen_mul_i64(t0, t0, t1); /* t0 := rA * rB */ gen_store_gpr64(rD(ctx->opcode), t0); /* rD := t0 */ - - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); } static inline void gen_evmwsmia(DisasContext *ctx) @@ -555,9 +529,7 @@ static inline void gen_evmwsmia(DisasContext *ctx) /* acc := rD */ gen_load_gpr64(tmp, rD(ctx->opcode)); - tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUPPCState, spe_acc)); - - tcg_temp_free_i64(tmp); + tcg_gen_st_i64(tmp, tcg_env, offsetof(CPUPPCState, spe_acc)); } static inline void gen_evmwsmiaa(DisasContext *ctx) @@ -579,19 +551,16 @@ static inline void gen_evmwsmiaa(DisasContext *ctx) gen_load_gpr64(tmp, rD(ctx->opcode)); /* Load acc */ - tcg_gen_ld_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc)); + tcg_gen_ld_i64(acc, tcg_env, offsetof(CPUPPCState, spe_acc)); /* acc := tmp + acc */ tcg_gen_add_i64(acc, acc, tmp); /* Store acc */ - tcg_gen_st_i64(acc, cpu_env, offsetof(CPUPPCState, spe_acc)); + tcg_gen_st_i64(acc, tcg_env, offsetof(CPUPPCState, spe_acc)); /* rD := acc */ gen_store_gpr64(rD(ctx->opcode), acc); - - tcg_temp_free_i64(acc); - tcg_temp_free_i64(tmp); } GEN_SPE(evaddw, speundef, 0x00, 0x08, 0x00000000, 0xFFFFFFFF, PPC_SPE); //// @@ -644,7 +613,6 @@ static inline void gen_op_evldd(DisasContext *ctx, TCGv addr) TCGv_i64 t0 = tcg_temp_new_i64(); gen_qemu_ld64_i64(ctx, t0, addr); gen_store_gpr64(rD(ctx->opcode), t0); - tcg_temp_free_i64(t0); } static inline void gen_op_evldw(DisasContext *ctx, TCGv addr) @@ -668,7 +636,6 @@ static inline void gen_op_evldh(DisasContext *ctx, TCGv addr) gen_addr_add(ctx, addr, addr, 2); gen_qemu_ld16u(ctx, t0, addr); tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0); - tcg_temp_free(t0); } static inline void gen_op_evlhhesplat(DisasContext *ctx, TCGv addr) @@ -678,7 +645,6 @@ static inline void gen_op_evlhhesplat(DisasContext *ctx, TCGv addr) tcg_gen_shli_tl(t0, t0, 16); tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0); tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0); - tcg_temp_free(t0); } static inline void gen_op_evlhhousplat(DisasContext *ctx, TCGv addr) @@ -687,7 +653,6 @@ static inline void gen_op_evlhhousplat(DisasContext *ctx, TCGv addr) gen_qemu_ld16u(ctx, t0, addr); tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0); tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0); - tcg_temp_free(t0); } static inline void gen_op_evlhhossplat(DisasContext *ctx, TCGv addr) @@ -696,7 +661,6 @@ static inline void gen_op_evlhhossplat(DisasContext *ctx, TCGv addr) gen_qemu_ld16s(ctx, t0, addr); tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0); tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0); - tcg_temp_free(t0); } static inline void gen_op_evlwhe(DisasContext *ctx, TCGv addr) @@ -707,7 +671,6 @@ static inline void gen_op_evlwhe(DisasContext *ctx, TCGv addr) gen_addr_add(ctx, addr, addr, 2); gen_qemu_ld16u(ctx, t0, addr); tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 16); - tcg_temp_free(t0); } static inline void gen_op_evlwhou(DisasContext *ctx, TCGv addr) @@ -730,7 +693,6 @@ static inline void gen_op_evlwwsplat(DisasContext *ctx, TCGv addr) gen_qemu_ld32u(ctx, t0, addr); tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0); tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0); - tcg_temp_free(t0); } static inline void gen_op_evlwhsplat(DisasContext *ctx, TCGv addr) @@ -743,7 +705,6 @@ static inline void gen_op_evlwhsplat(DisasContext *ctx, TCGv addr) gen_qemu_ld16u(ctx, t0, addr); tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 16); tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0); - tcg_temp_free(t0); } static inline void gen_op_evstdd(DisasContext *ctx, TCGv addr) @@ -751,7 +712,6 @@ static inline void gen_op_evstdd(DisasContext *ctx, TCGv addr) TCGv_i64 t0 = tcg_temp_new_i64(); gen_load_gpr64(t0, rS(ctx->opcode)); gen_qemu_st64_i64(ctx, t0, addr); - tcg_temp_free_i64(t0); } static inline void gen_op_evstdw(DisasContext *ctx, TCGv addr) @@ -771,7 +731,6 @@ static inline void gen_op_evstdh(DisasContext *ctx, TCGv addr) gen_addr_add(ctx, addr, addr, 2); tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16); gen_qemu_st16(ctx, t0, addr); - tcg_temp_free(t0); gen_addr_add(ctx, addr, addr, 2); gen_qemu_st16(ctx, cpu_gpr[rS(ctx->opcode)], addr); } @@ -784,7 +743,6 @@ static inline void gen_op_evstwhe(DisasContext *ctx, TCGv addr) gen_addr_add(ctx, addr, addr, 2); tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16); gen_qemu_st16(ctx, t0, addr); - tcg_temp_free(t0); } static inline void gen_op_evstwho(DisasContext *ctx, TCGv addr) @@ -820,7 +778,6 @@ static void glue(gen_, name)(DisasContext *ctx) \ gen_addr_reg_index(ctx, t0); \ } \ gen_op_##name(ctx, t0); \ - tcg_temp_free(t0); \ } GEN_SPEOP_LDST(evldd, 0x00, 3); @@ -921,9 +878,8 @@ static inline void gen_##name(DisasContext *ctx) \ { \ TCGv_i32 t0 = tcg_temp_new_i32(); \ tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]); \ - gen_helper_##name(t0, cpu_env, t0); \ + gen_helper_##name(t0, tcg_env, t0); \ tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ - tcg_temp_free_i32(t0); \ } #define GEN_SPEFPUOP_CONV_32_64(name) \ static inline void gen_##name(DisasContext *ctx) \ @@ -937,10 +893,8 @@ static inline void gen_##name(DisasContext *ctx) \ t0 = tcg_temp_new_i64(); \ t1 = tcg_temp_new_i32(); \ gen_load_gpr64(t0, rB(ctx->opcode)); \ - gen_helper_##name(t1, cpu_env, t0); \ + gen_helper_##name(t1, tcg_env, t0); \ tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t1); \ - tcg_temp_free_i64(t0); \ - tcg_temp_free_i32(t1); \ } #define GEN_SPEFPUOP_CONV_64_32(name) \ static inline void gen_##name(DisasContext *ctx) \ @@ -954,10 +908,8 @@ static inline void gen_##name(DisasContext *ctx) \ t0 = tcg_temp_new_i64(); \ t1 = tcg_temp_new_i32(); \ tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ - gen_helper_##name(t0, cpu_env, t1); \ + gen_helper_##name(t0, tcg_env, t1); \ gen_store_gpr64(rD(ctx->opcode), t0); \ - tcg_temp_free_i64(t0); \ - tcg_temp_free_i32(t1); \ } #define GEN_SPEFPUOP_CONV_64_64(name) \ static inline void gen_##name(DisasContext *ctx) \ @@ -969,9 +921,8 @@ static inline void gen_##name(DisasContext *ctx) \ } \ t0 = tcg_temp_new_i64(); \ gen_load_gpr64(t0, rB(ctx->opcode)); \ - gen_helper_##name(t0, cpu_env, t0); \ + gen_helper_##name(t0, tcg_env, t0); \ gen_store_gpr64(rD(ctx->opcode), t0); \ - tcg_temp_free_i64(t0); \ } #define GEN_SPEFPUOP_ARITH2_32_32(name) \ static inline void gen_##name(DisasContext *ctx) \ @@ -980,11 +931,8 @@ static inline void gen_##name(DisasContext *ctx) \ TCGv_i32 t1 = tcg_temp_new_i32(); \ tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ - gen_helper_##name(t0, cpu_env, t0, t1); \ + gen_helper_##name(t0, tcg_env, t0, t1); \ tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], t0); \ - \ - tcg_temp_free_i32(t0); \ - tcg_temp_free_i32(t1); \ } #define GEN_SPEFPUOP_ARITH2_64_64(name) \ static inline void gen_##name(DisasContext *ctx) \ @@ -998,10 +946,8 @@ static inline void gen_##name(DisasContext *ctx) \ t1 = tcg_temp_new_i64(); \ gen_load_gpr64(t0, rA(ctx->opcode)); \ gen_load_gpr64(t1, rB(ctx->opcode)); \ - gen_helper_##name(t0, cpu_env, t0, t1); \ + gen_helper_##name(t0, tcg_env, t0, t1); \ gen_store_gpr64(rD(ctx->opcode), t0); \ - tcg_temp_free_i64(t0); \ - tcg_temp_free_i64(t1); \ } #define GEN_SPEFPUOP_COMP_32(name) \ static inline void gen_##name(DisasContext *ctx) \ @@ -1011,10 +957,7 @@ static inline void gen_##name(DisasContext *ctx) \ \ tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]); \ tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]); \ - gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, t0, t1); \ - \ - tcg_temp_free_i32(t0); \ - tcg_temp_free_i32(t1); \ + gen_helper_##name(cpu_crf[crfD(ctx->opcode)], tcg_env, t0, t1); \ } #define GEN_SPEFPUOP_COMP_64(name) \ static inline void gen_##name(DisasContext *ctx) \ @@ -1028,9 +971,7 @@ static inline void gen_##name(DisasContext *ctx) \ t1 = tcg_temp_new_i64(); \ gen_load_gpr64(t0, rA(ctx->opcode)); \ gen_load_gpr64(t1, rB(ctx->opcode)); \ - gen_helper_##name(cpu_crf[crfD(ctx->opcode)], cpu_env, t0, t1); \ - tcg_temp_free_i64(t0); \ - tcg_temp_free_i64(t1); \ + gen_helper_##name(cpu_crf[crfD(ctx->opcode)], tcg_env, t0, t1); \ } /* Single precision floating-point vectors operations */ diff --git a/target/ppc/translate/storage-ctrl-impl.c.inc b/target/ppc/translate/storage-ctrl-impl.c.inc new file mode 100644 index 0000000000..74c23a4191 --- /dev/null +++ b/target/ppc/translate/storage-ctrl-impl.c.inc @@ -0,0 +1,248 @@ +/* + * Power ISA decode for Storage Control instructions + * + * Copyright (c) 2022 Instituto de Pesquisas Eldorado (eldorado.org.br) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +/* + * Store Control Instructions + */ + +#include "mmu-book3s-v3.h" + +static bool trans_SLBIE(DisasContext *ctx, arg_SLBIE *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS(ctx, SLBI); + REQUIRE_SV(ctx); + +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_helper_SLBIE(tcg_env, cpu_gpr[a->rb]); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_SLBIEG(DisasContext *ctx, arg_SLBIEG *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_SV(ctx); + +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_helper_SLBIEG(tcg_env, cpu_gpr[a->rb]); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_SLBIA(DisasContext *ctx, arg_SLBIA *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS(ctx, SLBI); + REQUIRE_SV(ctx); + +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_helper_SLBIA(tcg_env, tcg_constant_i32(a->ih)); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_SLBIAG(DisasContext *ctx, arg_SLBIAG *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_SV(ctx); + +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_helper_SLBIAG(tcg_env, cpu_gpr[a->rs], tcg_constant_i32(a->l)); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_SLBMTE(DisasContext *ctx, arg_SLBMTE *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B); + REQUIRE_SV(ctx); + +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_helper_SLBMTE(tcg_env, cpu_gpr[a->rb], cpu_gpr[a->rt]); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_SLBMFEV(DisasContext *ctx, arg_SLBMFEV *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B); + REQUIRE_SV(ctx); + +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_helper_SLBMFEV(cpu_gpr[a->rt], tcg_env, cpu_gpr[a->rb]); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_SLBMFEE(DisasContext *ctx, arg_SLBMFEE *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B); + REQUIRE_SV(ctx); + +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_helper_SLBMFEE(cpu_gpr[a->rt], tcg_env, cpu_gpr[a->rb]); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_SLBFEE(DisasContext *ctx, arg_SLBFEE *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B); + +#if defined(CONFIG_USER_ONLY) + gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); +#else + +#if defined(TARGET_PPC64) + TCGLabel *l1, *l2; + + if (unlikely(ctx->pr)) { + gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); + return true; + } + gen_helper_SLBFEE(cpu_gpr[a->rt], tcg_env, + cpu_gpr[a->rb]); + l1 = gen_new_label(); + l2 = gen_new_label(); + tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so); + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[a->rt], -1, l1); + tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], CRF_EQ); + tcg_gen_br(l2); + gen_set_label(l1); + tcg_gen_movi_tl(cpu_gpr[a->rt], 0); + gen_set_label(l2); +#else + qemu_build_not_reached(); +#endif +#endif + return true; +} + +static bool trans_SLBSYNC(DisasContext *ctx, arg_SLBSYNC *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_SV(ctx); + +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_check_tlb_flush(ctx, true); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool do_tlbie(DisasContext *ctx, arg_X_tlbie *a, bool local) +{ +#if defined(CONFIG_USER_ONLY) + gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); + return true; +#else + TCGv_i32 t1; + int rb; + + rb = a->rb; + + if ((ctx->insns_flags2 & PPC2_ISA300) == 0) { + /* + * Before Power ISA 3.0, the corresponding bits of RIC, PRS, and R + * (and RS for tlbiel) were reserved fields and should be ignored. + */ + a->ric = 0; + a->prs = false; + a->r = false; + if (local) { + a->rs = 0; + } + } + + if (ctx->pr) { + /* tlbie[l] is privileged... */ + gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); + return true; + } else if (!ctx->hv) { + if ((!a->prs && ctx->hr) || (!local && !ctx->gtse)) { + /* + * ... except when PRS=0 and HR=1, or when GTSE=0 for tlbie, + * making it hypervisor privileged. + */ + gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC); + return true; + } + } + + if (!local && NARROW_MODE(ctx)) { + TCGv t0 = tcg_temp_new(); + tcg_gen_ext32u_tl(t0, cpu_gpr[rb]); + gen_helper_tlbie(tcg_env, t0); + +#if defined(TARGET_PPC64) + /* + * ISA 3.1B says that MSR SF must be 1 when this instruction is executed; + * otherwise the results are undefined. + */ + } else if (a->r) { + gen_helper_tlbie_isa300(tcg_env, cpu_gpr[rb], cpu_gpr[a->rs], + tcg_constant_i32(a->ric << TLBIE_F_RIC_SHIFT | + a->prs << TLBIE_F_PRS_SHIFT | + a->r << TLBIE_F_R_SHIFT | + local << TLBIE_F_LOCAL_SHIFT)); + return true; +#endif + + } else { + gen_helper_tlbie(tcg_env, cpu_gpr[rb]); + } + + if (local) { + return true; + } + + t1 = tcg_temp_new_i32(); + tcg_gen_ld_i32(t1, tcg_env, offsetof(CPUPPCState, tlb_need_flush)); + tcg_gen_ori_i32(t1, t1, TLB_NEED_GLOBAL_FLUSH); + tcg_gen_st_i32(t1, tcg_env, offsetof(CPUPPCState, tlb_need_flush)); + + return true; +#endif +} + +TRANS_FLAGS(MEM_TLBIE, TLBIE, do_tlbie, false) +TRANS_FLAGS(MEM_TLBIE, TLBIEL, do_tlbie, true) diff --git a/target/ppc/translate/vector-impl.c.inc b/target/ppc/translate/vector-impl.c.inc deleted file mode 100644 index 117ce9b137..0000000000 --- a/target/ppc/translate/vector-impl.c.inc +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Power ISA decode for Vector Facility instructions - * - * Copyright (c) 2021 Instituto de Pesquisas Eldorado (eldorado.org.br) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#define REQUIRE_ALTIVEC(CTX) \ - do { \ - if (unlikely(!(CTX)->altivec_enabled)) { \ - gen_exception((CTX), POWERPC_EXCP_VPU); \ - return true; \ - } \ - } while (0) - -static bool trans_VCFUGED(DisasContext *ctx, arg_VX *a) -{ - TCGv_i64 tgt, src, mask; - - REQUIRE_INSNS_FLAGS2(ctx, ISA310); - REQUIRE_ALTIVEC(ctx); - - tgt = tcg_temp_new_i64(); - src = tcg_temp_new_i64(); - mask = tcg_temp_new_i64(); - - /* centrifuge lower double word */ - get_cpu_vsrl(src, a->vra + 32); - get_cpu_vsrl(mask, a->vrb + 32); - gen_helper_cfuged(tgt, src, mask); - set_cpu_vsrl(a->vrt + 32, tgt); - - /* centrifuge higher double word */ - get_cpu_vsrh(src, a->vra + 32); - get_cpu_vsrh(mask, a->vrb + 32); - gen_helper_cfuged(tgt, src, mask); - set_cpu_vsrh(a->vrt + 32, tgt); - - tcg_temp_free_i64(tgt); - tcg_temp_free_i64(src); - tcg_temp_free_i64(mask); - - return true; -} diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc index 92b9527aff..b56e615c24 100644 --- a/target/ppc/translate/vmx-impl.c.inc +++ b/target/ppc/translate/vmx-impl.c.inc @@ -10,7 +10,7 @@ static inline TCGv_ptr gen_avr_ptr(int reg) { TCGv_ptr r = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(r, cpu_env, avr_full_offset(reg)); + tcg_gen_addi_ptr(r, tcg_env, avr_full_offset(reg)); return r; } @@ -45,8 +45,6 @@ static void glue(gen_, name)(DisasContext *ctx) \ gen_qemu_ld64_i64(ctx, avr, EA); \ set_avr64(rD(ctx->opcode), avr, false); \ } \ - tcg_temp_free(EA); \ - tcg_temp_free_i64(avr); \ } #define GEN_VR_STX(name, opc2, opc3) \ @@ -80,8 +78,6 @@ static void gen_st##name(DisasContext *ctx) \ get_avr64(avr, rD(ctx->opcode), false); \ gen_qemu_st64_i64(ctx, avr, EA); \ } \ - tcg_temp_free(EA); \ - tcg_temp_free_i64(avr); \ } #define GEN_VR_LVE(name, opc2, opc3, size) \ @@ -100,9 +96,7 @@ static void gen_lve##name(DisasContext *ctx) \ tcg_gen_andi_tl(EA, EA, ~(size - 1)); \ } \ rs = gen_avr_ptr(rS(ctx->opcode)); \ - gen_helper_lve##name(cpu_env, rs, EA); \ - tcg_temp_free(EA); \ - tcg_temp_free_ptr(rs); \ + gen_helper_lve##name(tcg_env, rs, EA); \ } #define GEN_VR_STVE(name, opc2, opc3, size) \ @@ -121,13 +115,11 @@ static void gen_stve##name(DisasContext *ctx) \ tcg_gen_andi_tl(EA, EA, ~(size - 1)); \ } \ rs = gen_avr_ptr(rS(ctx->opcode)); \ - gen_helper_stve##name(cpu_env, rs, EA); \ - tcg_temp_free(EA); \ - tcg_temp_free_ptr(rs); \ + gen_helper_stve##name(tcg_env, rs, EA); \ } GEN_VR_LDX(lvx, 0x07, 0x03); -/* As we don't emulate the cache, lvxl is stricly equivalent to lvx */ +/* As we don't emulate the cache, lvxl is strictly equivalent to lvx */ GEN_VR_LDX(lvxl, 0x07, 0x0B); GEN_VR_LVE(bx, 0x07, 0x00, 1); @@ -135,7 +127,7 @@ GEN_VR_LVE(hx, 0x07, 0x01, 2); GEN_VR_LVE(wx, 0x07, 0x02, 4); GEN_VR_STX(svx, 0x07, 0x07); -/* As we don't emulate the cache, stvxl is stricly equivalent to stvx */ +/* As we don't emulate the cache, stvxl is strictly equivalent to stvx */ GEN_VR_STX(svxl, 0x07, 0x0F); GEN_VR_STVE(bx, 0x07, 0x04, 1); @@ -154,11 +146,9 @@ static void gen_mfvscr(DisasContext *ctx) tcg_gen_movi_i64(avr, 0); set_avr64(rD(ctx->opcode), avr, true); t = tcg_temp_new_i32(); - gen_helper_mfvscr(t, cpu_env); + gen_helper_mfvscr(t, tcg_env); tcg_gen_extu_i32_i64(avr, t); set_avr64(rD(ctx->opcode), avr, false); - tcg_temp_free_i32(t); - tcg_temp_free_i64(avr); } static void gen_mtvscr(DisasContext *ctx) @@ -173,69 +163,64 @@ static void gen_mtvscr(DisasContext *ctx) val = tcg_temp_new_i32(); bofs = avr_full_offset(rB(ctx->opcode)); -#ifdef HOST_WORDS_BIGENDIAN +#if HOST_BIG_ENDIAN bofs += 3 * 4; #endif - tcg_gen_ld_i32(val, cpu_env, bofs); - gen_helper_mtvscr(cpu_env, val); - tcg_temp_free_i32(val); + tcg_gen_ld_i32(val, tcg_env, bofs); + gen_helper_mtvscr(tcg_env, val); +} + +static void gen_vx_vmul10(DisasContext *ctx, bool add_cin, bool ret_carry) +{ + TCGv_i64 t0; + TCGv_i64 t1; + TCGv_i64 t2; + TCGv_i64 avr; + TCGv_i64 ten, z; + + if (unlikely(!ctx->altivec_enabled)) { + gen_exception(ctx, POWERPC_EXCP_VPU); + return; + } + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + t2 = tcg_temp_new_i64(); + avr = tcg_temp_new_i64(); + ten = tcg_constant_i64(10); + z = tcg_constant_i64(0); + + if (add_cin) { + get_avr64(avr, rA(ctx->opcode), false); + tcg_gen_mulu2_i64(t0, t1, avr, ten); + get_avr64(avr, rB(ctx->opcode), false); + tcg_gen_andi_i64(t2, avr, 0xF); + tcg_gen_add2_i64(avr, t2, t0, t1, t2, z); + set_avr64(rD(ctx->opcode), avr, false); + } else { + get_avr64(avr, rA(ctx->opcode), false); + tcg_gen_mulu2_i64(avr, t2, avr, ten); + set_avr64(rD(ctx->opcode), avr, false); + } + + if (ret_carry) { + get_avr64(avr, rA(ctx->opcode), true); + tcg_gen_mulu2_i64(t0, t1, avr, ten); + tcg_gen_add2_i64(t0, avr, t0, t1, t2, z); + set_avr64(rD(ctx->opcode), avr, false); + set_avr64(rD(ctx->opcode), z, true); + } else { + get_avr64(avr, rA(ctx->opcode), true); + tcg_gen_mul_i64(t0, avr, ten); + tcg_gen_add_i64(avr, t0, t2); + set_avr64(rD(ctx->opcode), avr, true); + } } #define GEN_VX_VMUL10(name, add_cin, ret_carry) \ -static void glue(gen_, name)(DisasContext *ctx) \ -{ \ - TCGv_i64 t0; \ - TCGv_i64 t1; \ - TCGv_i64 t2; \ - TCGv_i64 avr; \ - TCGv_i64 ten, z; \ - \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - \ - t0 = tcg_temp_new_i64(); \ - t1 = tcg_temp_new_i64(); \ - t2 = tcg_temp_new_i64(); \ - avr = tcg_temp_new_i64(); \ - ten = tcg_const_i64(10); \ - z = tcg_const_i64(0); \ - \ - if (add_cin) { \ - get_avr64(avr, rA(ctx->opcode), false); \ - tcg_gen_mulu2_i64(t0, t1, avr, ten); \ - get_avr64(avr, rB(ctx->opcode), false); \ - tcg_gen_andi_i64(t2, avr, 0xF); \ - tcg_gen_add2_i64(avr, t2, t0, t1, t2, z); \ - set_avr64(rD(ctx->opcode), avr, false); \ - } else { \ - get_avr64(avr, rA(ctx->opcode), false); \ - tcg_gen_mulu2_i64(avr, t2, avr, ten); \ - set_avr64(rD(ctx->opcode), avr, false); \ - } \ - \ - if (ret_carry) { \ - get_avr64(avr, rA(ctx->opcode), true); \ - tcg_gen_mulu2_i64(t0, t1, avr, ten); \ - tcg_gen_add2_i64(t0, avr, t0, t1, t2, z); \ - set_avr64(rD(ctx->opcode), avr, false); \ - set_avr64(rD(ctx->opcode), z, true); \ - } else { \ - get_avr64(avr, rA(ctx->opcode), true); \ - tcg_gen_mul_i64(t0, avr, ten); \ - tcg_gen_add_i64(avr, t0, t2); \ - set_avr64(rD(ctx->opcode), avr, true); \ - } \ - \ - tcg_temp_free_i64(t0); \ - tcg_temp_free_i64(t1); \ - tcg_temp_free_i64(t2); \ - tcg_temp_free_i64(avr); \ - tcg_temp_free_i64(ten); \ - tcg_temp_free_i64(z); \ -} \ + static void glue(gen_, name)(DisasContext *ctx) \ + { gen_vx_vmul10(ctx, add_cin, ret_carry); } GEN_VX_VMUL10(vmul10uq, 0, 0); GEN_VX_VMUL10(vmul10euq, 1, 0); @@ -279,9 +264,6 @@ static void glue(gen_, name)(DisasContext *ctx) \ rb = gen_avr_ptr(rB(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ gen_helper_##name(rd, ra, rb); \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rd); \ } #define GEN_VXFORM_TRANS(name, opc2, opc3) \ @@ -305,10 +287,7 @@ static void glue(gen_, name)(DisasContext *ctx) \ ra = gen_avr_ptr(rA(ctx->opcode)); \ rb = gen_avr_ptr(rB(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##name(cpu_env, rd, ra, rb); \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rd); \ + gen_helper_##name(tcg_env, rd, ra, rb); \ } #define GEN_VXFORM3(name, opc2, opc3) \ @@ -324,10 +303,6 @@ static void glue(gen_, name)(DisasContext *ctx) \ rc = gen_avr_ptr(rC(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ gen_helper_##name(rd, ra, rb, rc); \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rc); \ - tcg_temp_free_ptr(rd); \ } /* @@ -400,7 +375,6 @@ static void glue(gen_, name)(DisasContext *ctx) \ } \ rb = gen_avr_ptr(rB(ctx->opcode)); \ gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], rb); \ - tcg_temp_free_ptr(rb); \ } GEN_VXFORM_V(vaddubm, MO_8, tcg_gen_gvec_add, 0, 0); @@ -431,21 +405,6 @@ GEN_VXFORM_V(vminsb, MO_8, tcg_gen_gvec_smin, 1, 12); GEN_VXFORM_V(vminsh, MO_16, tcg_gen_gvec_smin, 1, 13); GEN_VXFORM_V(vminsw, MO_32, tcg_gen_gvec_smin, 1, 14); GEN_VXFORM_V(vminsd, MO_64, tcg_gen_gvec_smin, 1, 15); -GEN_VXFORM(vavgub, 1, 16); -GEN_VXFORM(vabsdub, 1, 16); -GEN_VXFORM_DUAL(vavgub, PPC_ALTIVEC, PPC_NONE, \ - vabsdub, PPC_NONE, PPC2_ISA300) -GEN_VXFORM(vavguh, 1, 17); -GEN_VXFORM(vabsduh, 1, 17); -GEN_VXFORM_DUAL(vavguh, PPC_ALTIVEC, PPC_NONE, \ - vabsduh, PPC_NONE, PPC2_ISA300) -GEN_VXFORM(vavguw, 1, 18); -GEN_VXFORM(vabsduw, 1, 18); -GEN_VXFORM_DUAL(vavguw, PPC_ALTIVEC, PPC_NONE, \ - vabsduw, PPC_NONE, PPC2_ISA300) -GEN_VXFORM(vavgsb, 1, 20); -GEN_VXFORM(vavgsh, 1, 21); -GEN_VXFORM(vavgsw, 1, 22); GEN_VXFORM(vmrghb, 6, 0); GEN_VXFORM(vmrghh, 6, 1); GEN_VXFORM(vmrghw, 6, 2); @@ -472,9 +431,6 @@ static void trans_vmrgew(DisasContext *ctx) get_avr64(avr, VA, false); tcg_gen_deposit_i64(avr, avr, tmp, 0, 32); set_avr64(VT, avr, false); - - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(avr); } static void trans_vmrgow(DisasContext *ctx) @@ -495,10 +451,6 @@ static void trans_vmrgow(DisasContext *ctx) get_avr64(t1, VA, false); tcg_gen_deposit_i64(avr, t0, t1, 32, 32); set_avr64(VT, avr, false); - - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); - tcg_temp_free_i64(avr); } /* @@ -533,10 +485,6 @@ static void trans_lvsl(DisasContext *ctx) */ tcg_gen_addi_i64(result, sh, 0x08090a0b0c0d0e0fULL); set_avr64(VT, result, false); - - tcg_temp_free_i64(result); - tcg_temp_free_i64(sh); - tcg_temp_free(EA); } /* @@ -572,10 +520,6 @@ static void trans_lvsr(DisasContext *ctx) */ tcg_gen_subfi_i64(result, 0x18191a1b1c1d1e1fULL, sh); set_avr64(VT, result, false); - - tcg_temp_free_i64(result); - tcg_temp_free_i64(sh); - tcg_temp_free(EA); } /* @@ -618,11 +562,6 @@ static void trans_vsl(DisasContext *ctx) tcg_gen_shl_i64(avr, avr, sh); tcg_gen_or_i64(avr, avr, carry); set_avr64(VT, avr, true); - - tcg_temp_free_i64(avr); - tcg_temp_free_i64(sh); - tcg_temp_free_i64(carry); - tcg_temp_free_i64(tmp); } /* @@ -664,11 +603,6 @@ static void trans_vsr(DisasContext *ctx) tcg_gen_shr_i64(avr, avr, sh); tcg_gen_or_i64(avr, avr, carry); set_avr64(VT, avr, false); - - tcg_temp_free_i64(avr); - tcg_temp_free_i64(sh); - tcg_temp_free_i64(carry); - tcg_temp_free_i64(tmp); } /* @@ -737,13 +671,6 @@ static void trans_vgbbd(DisasContext *ctx) for (j = 0; j < 2; j++) { set_avr64(VT, result[j], j); } - - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(tcg_mask); - tcg_temp_free_i64(result[0]); - tcg_temp_free_i64(result[1]); - tcg_temp_free_i64(avr[0]); - tcg_temp_free_i64(avr[1]); } /* @@ -762,14 +689,12 @@ static void trans_vclzw(DisasContext *ctx) /* Perform count for every word element using tcg_gen_clzi_i32. */ for (i = 0; i < 4; i++) { - tcg_gen_ld_i32(tmp, cpu_env, + tcg_gen_ld_i32(tmp, tcg_env, offsetof(CPUPPCState, vsr[32 + VB].u64[0]) + i * 4); tcg_gen_clzi_i32(tmp, tmp, 32); - tcg_gen_st_i32(tmp, cpu_env, + tcg_gen_st_i32(tmp, tcg_env, offsetof(CPUPPCState, vsr[32 + VT].u64[0]) + i * 4); } - - tcg_temp_free_i32(tmp); } /* @@ -794,55 +719,360 @@ static void trans_vclzd(DisasContext *ctx) get_avr64(avr, VB, false); tcg_gen_clzi_i64(avr, avr, 64); set_avr64(VT, avr, false); - - tcg_temp_free_i64(avr); } -GEN_VXFORM(vmuloub, 4, 0); -GEN_VXFORM(vmulouh, 4, 1); -GEN_VXFORM(vmulouw, 4, 2); GEN_VXFORM_V(vmuluwm, MO_32, tcg_gen_gvec_mul, 4, 2); -GEN_VXFORM_DUAL(vmulouw, PPC_ALTIVEC, PPC_NONE, - vmuluwm, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXFORM(vmulosb, 4, 4); -GEN_VXFORM(vmulosh, 4, 5); -GEN_VXFORM(vmulosw, 4, 6); -GEN_VXFORM_V(vmulld, MO_64, tcg_gen_gvec_mul, 4, 7); -GEN_VXFORM(vmuleub, 4, 8); -GEN_VXFORM(vmuleuh, 4, 9); -GEN_VXFORM(vmuleuw, 4, 10); -GEN_VXFORM(vmulhuw, 4, 10); -GEN_VXFORM(vmulhud, 4, 11); -GEN_VXFORM_DUAL(vmuleuw, PPC_ALTIVEC, PPC_NONE, - vmulhuw, PPC_NONE, PPC2_ISA310); -GEN_VXFORM(vmulesb, 4, 12); -GEN_VXFORM(vmulesh, 4, 13); -GEN_VXFORM(vmulesw, 4, 14); -GEN_VXFORM(vmulhsw, 4, 14); -GEN_VXFORM_DUAL(vmulesw, PPC_ALTIVEC, PPC_NONE, - vmulhsw, PPC_NONE, PPC2_ISA310); -GEN_VXFORM(vmulhsd, 4, 15); -GEN_VXFORM_V(vslb, MO_8, tcg_gen_gvec_shlv, 2, 4); -GEN_VXFORM_V(vslh, MO_16, tcg_gen_gvec_shlv, 2, 5); -GEN_VXFORM_V(vslw, MO_32, tcg_gen_gvec_shlv, 2, 6); -GEN_VXFORM(vrlwnm, 2, 6); -GEN_VXFORM_DUAL(vslw, PPC_ALTIVEC, PPC_NONE, \ - vrlwnm, PPC_NONE, PPC2_ISA300) -GEN_VXFORM_V(vsld, MO_64, tcg_gen_gvec_shlv, 2, 23); -GEN_VXFORM_V(vsrb, MO_8, tcg_gen_gvec_shrv, 2, 8); -GEN_VXFORM_V(vsrh, MO_16, tcg_gen_gvec_shrv, 2, 9); -GEN_VXFORM_V(vsrw, MO_32, tcg_gen_gvec_shrv, 2, 10); -GEN_VXFORM_V(vsrd, MO_64, tcg_gen_gvec_shrv, 2, 27); -GEN_VXFORM_V(vsrab, MO_8, tcg_gen_gvec_sarv, 2, 12); -GEN_VXFORM_V(vsrah, MO_16, tcg_gen_gvec_sarv, 2, 13); -GEN_VXFORM_V(vsraw, MO_32, tcg_gen_gvec_sarv, 2, 14); -GEN_VXFORM_V(vsrad, MO_64, tcg_gen_gvec_sarv, 2, 15); GEN_VXFORM(vsrv, 2, 28); GEN_VXFORM(vslv, 2, 29); GEN_VXFORM(vslo, 6, 16); GEN_VXFORM(vsro, 6, 17); -GEN_VXFORM(vaddcuw, 0, 6); -GEN_VXFORM(vsubcuw, 0, 22); + +static bool do_vector_gvec3_VX(DisasContext *ctx, arg_VX *a, int vece, + void (*gen_gvec)(unsigned, uint32_t, uint32_t, + uint32_t, uint32_t, uint32_t)) +{ + REQUIRE_VECTOR(ctx); + + gen_gvec(vece, avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16); + + return true; +} + +TRANS_FLAGS(ALTIVEC, VSLB, do_vector_gvec3_VX, MO_8, tcg_gen_gvec_shlv); +TRANS_FLAGS(ALTIVEC, VSLH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_shlv); +TRANS_FLAGS(ALTIVEC, VSLW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_shlv); +TRANS_FLAGS2(ALTIVEC_207, VSLD, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_shlv); + +TRANS_FLAGS(ALTIVEC, VSRB, do_vector_gvec3_VX, MO_8, tcg_gen_gvec_shrv); +TRANS_FLAGS(ALTIVEC, VSRH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_shrv); +TRANS_FLAGS(ALTIVEC, VSRW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_shrv); +TRANS_FLAGS2(ALTIVEC_207, VSRD, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_shrv); + +TRANS_FLAGS(ALTIVEC, VSRAB, do_vector_gvec3_VX, MO_8, tcg_gen_gvec_sarv); +TRANS_FLAGS(ALTIVEC, VSRAH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_sarv); +TRANS_FLAGS(ALTIVEC, VSRAW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_sarv); +TRANS_FLAGS2(ALTIVEC_207, VSRAD, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_sarv); + +TRANS_FLAGS(ALTIVEC, VRLB, do_vector_gvec3_VX, MO_8, tcg_gen_gvec_rotlv) +TRANS_FLAGS(ALTIVEC, VRLH, do_vector_gvec3_VX, MO_16, tcg_gen_gvec_rotlv) +TRANS_FLAGS(ALTIVEC, VRLW, do_vector_gvec3_VX, MO_32, tcg_gen_gvec_rotlv) +TRANS_FLAGS2(ALTIVEC_207, VRLD, do_vector_gvec3_VX, MO_64, tcg_gen_gvec_rotlv) + +static TCGv_vec do_vrl_mask_vec(unsigned vece, TCGv_vec vrb) +{ + TCGv_vec t0 = tcg_temp_new_vec_matching(vrb), + t1 = tcg_temp_new_vec_matching(vrb), + t2 = tcg_temp_new_vec_matching(vrb), + ones = tcg_constant_vec_matching(vrb, vece, -1); + + /* Extract b and e */ + tcg_gen_dupi_vec(vece, t2, (8 << vece) - 1); + + tcg_gen_shri_vec(vece, t0, vrb, 16); + tcg_gen_and_vec(vece, t0, t0, t2); + + tcg_gen_shri_vec(vece, t1, vrb, 8); + tcg_gen_and_vec(vece, t1, t1, t2); + + /* Compare b and e to negate the mask where begin > end */ + tcg_gen_cmp_vec(TCG_COND_GT, vece, t2, t0, t1); + + /* Create the mask with (~0 >> b) ^ ((~0 >> e) >> 1) */ + tcg_gen_shrv_vec(vece, t0, ones, t0); + tcg_gen_shrv_vec(vece, t1, ones, t1); + tcg_gen_shri_vec(vece, t1, t1, 1); + tcg_gen_xor_vec(vece, t0, t0, t1); + + /* negate the mask */ + tcg_gen_xor_vec(vece, t0, t0, t2); + + return t0; +} + +static void gen_vrlnm_vec(unsigned vece, TCGv_vec vrt, TCGv_vec vra, + TCGv_vec vrb) +{ + TCGv_vec mask, n = tcg_temp_new_vec_matching(vrt); + + /* Create the mask */ + mask = do_vrl_mask_vec(vece, vrb); + + /* Extract n */ + tcg_gen_dupi_vec(vece, n, (8 << vece) - 1); + tcg_gen_and_vec(vece, n, vrb, n); + + /* Rotate and mask */ + tcg_gen_rotlv_vec(vece, vrt, vra, n); + tcg_gen_and_vec(vece, vrt, vrt, mask); +} + +static bool do_vrlnm(DisasContext *ctx, arg_VX *a, int vece) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_cmp_vec, INDEX_op_rotlv_vec, INDEX_op_sari_vec, + INDEX_op_shli_vec, INDEX_op_shri_vec, INDEX_op_shrv_vec, 0 + }; + static const GVecGen3 ops[2] = { + { + .fniv = gen_vrlnm_vec, + .fno = gen_helper_VRLWNM, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_32 + }, + { + .fniv = gen_vrlnm_vec, + .fno = gen_helper_VRLDNM, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_64 + } + }; + + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VSX(ctx); + + tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16, &ops[vece - 2]); + + return true; +} + +TRANS(VRLWNM, do_vrlnm, MO_32) +TRANS(VRLDNM, do_vrlnm, MO_64) + +static void gen_vrlmi_vec(unsigned vece, TCGv_vec vrt, TCGv_vec vra, + TCGv_vec vrb) +{ + TCGv_vec mask, n = tcg_temp_new_vec_matching(vrt), + tmp = tcg_temp_new_vec_matching(vrt); + + /* Create the mask */ + mask = do_vrl_mask_vec(vece, vrb); + + /* Extract n */ + tcg_gen_dupi_vec(vece, n, (8 << vece) - 1); + tcg_gen_and_vec(vece, n, vrb, n); + + /* Rotate and insert */ + tcg_gen_rotlv_vec(vece, tmp, vra, n); + tcg_gen_bitsel_vec(vece, vrt, mask, tmp, vrt); +} + +static bool do_vrlmi(DisasContext *ctx, arg_VX *a, int vece) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_cmp_vec, INDEX_op_rotlv_vec, INDEX_op_sari_vec, + INDEX_op_shli_vec, INDEX_op_shri_vec, INDEX_op_shrv_vec, 0 + }; + static const GVecGen3 ops[2] = { + { + .fniv = gen_vrlmi_vec, + .fno = gen_helper_VRLWMI, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_32 + }, + { + .fniv = gen_vrlnm_vec, + .fno = gen_helper_VRLDMI, + .opt_opc = vecop_list, + .load_dest = true, + .vece = MO_64 + } + }; + + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VSX(ctx); + + tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16, &ops[vece - 2]); + + return true; +} + +TRANS(VRLWMI, do_vrlmi, MO_32) +TRANS(VRLDMI, do_vrlmi, MO_64) + +static bool do_vector_shift_quad(DisasContext *ctx, arg_VX *a, bool right, + bool alg) +{ + TCGv_i64 hi, lo, t0, t1, n, zero = tcg_constant_i64(0); + + REQUIRE_VECTOR(ctx); + + n = tcg_temp_new_i64(); + hi = tcg_temp_new_i64(); + lo = tcg_temp_new_i64(); + t0 = tcg_temp_new_i64(); + + get_avr64(lo, a->vra, false); + get_avr64(hi, a->vra, true); + + get_avr64(n, a->vrb, true); + + tcg_gen_andi_i64(t0, n, 64); + if (right) { + tcg_gen_movcond_i64(TCG_COND_NE, lo, t0, zero, hi, lo); + if (alg) { + t1 = tcg_temp_new_i64(); + tcg_gen_sari_i64(t1, lo, 63); + } else { + t1 = zero; + } + tcg_gen_movcond_i64(TCG_COND_NE, hi, t0, zero, t1, hi); + } else { + tcg_gen_movcond_i64(TCG_COND_NE, hi, t0, zero, lo, hi); + tcg_gen_movcond_i64(TCG_COND_NE, lo, t0, zero, zero, lo); + } + tcg_gen_andi_i64(n, n, 0x3F); + + if (right) { + if (alg) { + tcg_gen_sar_i64(t0, hi, n); + } else { + tcg_gen_shr_i64(t0, hi, n); + } + } else { + tcg_gen_shl_i64(t0, lo, n); + } + set_avr64(a->vrt, t0, right); + + if (right) { + tcg_gen_shr_i64(lo, lo, n); + } else { + tcg_gen_shl_i64(hi, hi, n); + } + tcg_gen_xori_i64(n, n, 63); + if (right) { + tcg_gen_shl_i64(hi, hi, n); + tcg_gen_shli_i64(hi, hi, 1); + } else { + tcg_gen_shr_i64(lo, lo, n); + tcg_gen_shri_i64(lo, lo, 1); + } + tcg_gen_or_i64(hi, hi, lo); + set_avr64(a->vrt, hi, !right); + return true; +} + +TRANS_FLAGS2(ISA310, VSLQ, do_vector_shift_quad, false, false); +TRANS_FLAGS2(ISA310, VSRQ, do_vector_shift_quad, true, false); +TRANS_FLAGS2(ISA310, VSRAQ, do_vector_shift_quad, true, true); + +static void do_vrlq_mask(TCGv_i64 mh, TCGv_i64 ml, TCGv_i64 b, TCGv_i64 e) +{ + TCGv_i64 th, tl, t0, t1, zero = tcg_constant_i64(0), + ones = tcg_constant_i64(-1); + + th = tcg_temp_new_i64(); + tl = tcg_temp_new_i64(); + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + + /* m = ~0 >> b */ + tcg_gen_andi_i64(t0, b, 64); + tcg_gen_movcond_i64(TCG_COND_NE, t1, t0, zero, zero, ones); + tcg_gen_andi_i64(t0, b, 0x3F); + tcg_gen_shr_i64(mh, t1, t0); + tcg_gen_shr_i64(ml, ones, t0); + tcg_gen_xori_i64(t0, t0, 63); + tcg_gen_shl_i64(t1, t1, t0); + tcg_gen_shli_i64(t1, t1, 1); + tcg_gen_or_i64(ml, t1, ml); + + /* t = ~0 >> e */ + tcg_gen_andi_i64(t0, e, 64); + tcg_gen_movcond_i64(TCG_COND_NE, t1, t0, zero, zero, ones); + tcg_gen_andi_i64(t0, e, 0x3F); + tcg_gen_shr_i64(th, t1, t0); + tcg_gen_shr_i64(tl, ones, t0); + tcg_gen_xori_i64(t0, t0, 63); + tcg_gen_shl_i64(t1, t1, t0); + tcg_gen_shli_i64(t1, t1, 1); + tcg_gen_or_i64(tl, t1, tl); + + /* t = t >> 1 */ + tcg_gen_extract2_i64(tl, tl, th, 1); + tcg_gen_shri_i64(th, th, 1); + + /* m = m ^ t */ + tcg_gen_xor_i64(mh, mh, th); + tcg_gen_xor_i64(ml, ml, tl); + + /* Negate the mask if begin > end */ + tcg_gen_movcond_i64(TCG_COND_GT, t0, b, e, ones, zero); + + tcg_gen_xor_i64(mh, mh, t0); + tcg_gen_xor_i64(ml, ml, t0); +} + +static bool do_vector_rotl_quad(DisasContext *ctx, arg_VX *a, bool mask, + bool insert) +{ + TCGv_i64 ah, al, vrb, n, t0, t1, zero = tcg_constant_i64(0); + + REQUIRE_VECTOR(ctx); + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + + ah = tcg_temp_new_i64(); + al = tcg_temp_new_i64(); + vrb = tcg_temp_new_i64(); + n = tcg_temp_new_i64(); + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + + get_avr64(ah, a->vra, true); + get_avr64(al, a->vra, false); + get_avr64(vrb, a->vrb, true); + + tcg_gen_mov_i64(t0, ah); + tcg_gen_andi_i64(t1, vrb, 64); + tcg_gen_movcond_i64(TCG_COND_NE, ah, t1, zero, al, ah); + tcg_gen_movcond_i64(TCG_COND_NE, al, t1, zero, t0, al); + tcg_gen_andi_i64(n, vrb, 0x3F); + + tcg_gen_shl_i64(t0, ah, n); + tcg_gen_shl_i64(t1, al, n); + + tcg_gen_xori_i64(n, n, 63); + + tcg_gen_shr_i64(al, al, n); + tcg_gen_shri_i64(al, al, 1); + tcg_gen_or_i64(t0, al, t0); + + tcg_gen_shr_i64(ah, ah, n); + tcg_gen_shri_i64(ah, ah, 1); + tcg_gen_or_i64(t1, ah, t1); + + if (mask || insert) { + tcg_gen_extract_i64(n, vrb, 8, 7); + tcg_gen_extract_i64(vrb, vrb, 16, 7); + + do_vrlq_mask(ah, al, vrb, n); + + tcg_gen_and_i64(t0, t0, ah); + tcg_gen_and_i64(t1, t1, al); + + if (insert) { + get_avr64(n, a->vrt, true); + get_avr64(vrb, a->vrt, false); + tcg_gen_andc_i64(n, n, ah); + tcg_gen_andc_i64(vrb, vrb, al); + tcg_gen_or_i64(t0, t0, n); + tcg_gen_or_i64(t1, t1, vrb); + } + } + + set_avr64(a->vrt, t0, true); + set_avr64(a->vrt, t1, false); + return true; +} + +TRANS(VRLQ, do_vector_rotl_quad, false, false) +TRANS(VRLQNM, do_vector_rotl_quad, true, false) +TRANS(VRLQMI, do_vector_rotl_quad, false, true) #define GEN_VXFORM_SAT(NAME, VECE, NORM, SAT, OPC2, OPC3) \ static void glue(glue(gen_, NAME), _vec)(unsigned vece, TCGv_vec t, \ @@ -854,7 +1084,6 @@ static void glue(glue(gen_, NAME), _vec)(unsigned vece, TCGv_vec t, \ glue(glue(tcg_gen_, SAT), _vec)(VECE, t, a, b); \ tcg_gen_cmp_vec(TCG_COND_NE, VECE, x, x, t); \ tcg_gen_or_vec(VECE, sat, sat, x); \ - tcg_temp_free_vec(x); \ } \ static void glue(gen_, NAME)(DisasContext *ctx) \ { \ @@ -897,32 +1126,7 @@ GEN_VXFORM_SAT(vsubuws, MO_32, sub, ussub, 0, 26); GEN_VXFORM_SAT(vsubsbs, MO_8, sub, sssub, 0, 28); GEN_VXFORM_SAT(vsubshs, MO_16, sub, sssub, 0, 29); GEN_VXFORM_SAT(vsubsws, MO_32, sub, sssub, 0, 30); -GEN_VXFORM(vadduqm, 0, 4); -GEN_VXFORM(vaddcuq, 0, 5); -GEN_VXFORM3(vaddeuqm, 30, 0); -GEN_VXFORM3(vaddecuq, 30, 0); -GEN_VXFORM_DUAL(vaddeuqm, PPC_NONE, PPC2_ALTIVEC_207, \ - vaddecuq, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXFORM(vsubuqm, 0, 20); -GEN_VXFORM(vsubcuq, 0, 21); -GEN_VXFORM3(vsubeuqm, 31, 0); -GEN_VXFORM3(vsubecuq, 31, 0); -GEN_VXFORM_DUAL(vsubeuqm, PPC_NONE, PPC2_ALTIVEC_207, \ - vsubecuq, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXFORM_V(vrlb, MO_8, tcg_gen_gvec_rotlv, 2, 0); -GEN_VXFORM_V(vrlh, MO_16, tcg_gen_gvec_rotlv, 2, 1); -GEN_VXFORM_V(vrlw, MO_32, tcg_gen_gvec_rotlv, 2, 2); -GEN_VXFORM(vrlwmi, 2, 2); -GEN_VXFORM_DUAL(vrlw, PPC_ALTIVEC, PPC_NONE, \ - vrlwmi, PPC_NONE, PPC2_ISA300) -GEN_VXFORM_V(vrld, MO_64, tcg_gen_gvec_rotlv, 2, 3); -GEN_VXFORM(vrldmi, 2, 3); -GEN_VXFORM_DUAL(vrld, PPC_NONE, PPC2_ALTIVEC_207, \ - vrldmi, PPC_NONE, PPC2_ISA300) GEN_VXFORM_TRANS(vsl, 2, 7); -GEN_VXFORM(vrldnm, 2, 7); -GEN_VXFORM_DUAL(vsl, PPC_ALTIVEC, PPC_NONE, \ - vrldnm, PPC_NONE, PPC2_ISA300) GEN_VXFORM_TRANS(vsr, 2, 11); GEN_VXFORM_ENV(vpkuhum, 7, 0); GEN_VXFORM_ENV(vpkuwum, 7, 1); @@ -970,10 +1174,7 @@ static void glue(gen_, name)(DisasContext *ctx) \ ra = gen_avr_ptr(rA(ctx->opcode)); \ rb = gen_avr_ptr(rB(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##opname(cpu_env, rd, ra, rb); \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rd); \ + gen_helper_##opname(tcg_env, rd, ra, rb); \ } #define GEN_VXRFORM(name, opc2, opc3) \ @@ -982,7 +1183,7 @@ static void glue(gen_, name)(DisasContext *ctx) \ /* * Support for Altivec instructions that use bit 31 (Rc) as an opcode - * bit but also use bit 21 as an actual Rc bit. In general, thse pairs + * bit but also use bit 21 as an actual Rc bit. In general, these pairs * come from different versions of the ISA, so we must also support a * pair of flags for each instruction. */ @@ -1008,41 +1209,230 @@ static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ } \ } -GEN_VXRFORM(vcmpequb, 3, 0) -GEN_VXRFORM(vcmpequh, 3, 1) -GEN_VXRFORM(vcmpequw, 3, 2) -GEN_VXRFORM(vcmpequd, 3, 3) -GEN_VXRFORM(vcmpnezb, 3, 4) -GEN_VXRFORM(vcmpnezh, 3, 5) -GEN_VXRFORM(vcmpnezw, 3, 6) -GEN_VXRFORM(vcmpgtsb, 3, 12) -GEN_VXRFORM(vcmpgtsh, 3, 13) -GEN_VXRFORM(vcmpgtsw, 3, 14) -GEN_VXRFORM(vcmpgtsd, 3, 15) -GEN_VXRFORM(vcmpgtub, 3, 8) -GEN_VXRFORM(vcmpgtuh, 3, 9) -GEN_VXRFORM(vcmpgtuw, 3, 10) -GEN_VXRFORM(vcmpgtud, 3, 11) +static void do_vcmp_rc(int vrt) +{ + TCGv_i64 tmp, set, clr; + + tmp = tcg_temp_new_i64(); + set = tcg_temp_new_i64(); + clr = tcg_temp_new_i64(); + + get_avr64(tmp, vrt, true); + tcg_gen_mov_i64(set, tmp); + get_avr64(tmp, vrt, false); + tcg_gen_or_i64(clr, set, tmp); + tcg_gen_and_i64(set, set, tmp); + + tcg_gen_setcondi_i64(TCG_COND_EQ, clr, clr, 0); + tcg_gen_shli_i64(clr, clr, 1); + + tcg_gen_setcondi_i64(TCG_COND_EQ, set, set, -1); + tcg_gen_shli_i64(set, set, 3); + + tcg_gen_or_i64(tmp, set, clr); + tcg_gen_extrl_i64_i32(cpu_crf[6], tmp); +} + +static bool do_vcmp(DisasContext *ctx, arg_VC *a, TCGCond cond, int vece) +{ + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_cmp(cond, vece, avr_full_offset(a->vrt), + avr_full_offset(a->vra), avr_full_offset(a->vrb), 16, 16); + + if (a->rc) { + do_vcmp_rc(a->vrt); + } + + return true; +} + +TRANS_FLAGS(ALTIVEC, VCMPEQUB, do_vcmp, TCG_COND_EQ, MO_8) +TRANS_FLAGS(ALTIVEC, VCMPEQUH, do_vcmp, TCG_COND_EQ, MO_16) +TRANS_FLAGS(ALTIVEC, VCMPEQUW, do_vcmp, TCG_COND_EQ, MO_32) +TRANS_FLAGS2(ALTIVEC_207, VCMPEQUD, do_vcmp, TCG_COND_EQ, MO_64) + +TRANS_FLAGS(ALTIVEC, VCMPGTSB, do_vcmp, TCG_COND_GT, MO_8) +TRANS_FLAGS(ALTIVEC, VCMPGTSH, do_vcmp, TCG_COND_GT, MO_16) +TRANS_FLAGS(ALTIVEC, VCMPGTSW, do_vcmp, TCG_COND_GT, MO_32) +TRANS_FLAGS2(ALTIVEC_207, VCMPGTSD, do_vcmp, TCG_COND_GT, MO_64) +TRANS_FLAGS(ALTIVEC, VCMPGTUB, do_vcmp, TCG_COND_GTU, MO_8) +TRANS_FLAGS(ALTIVEC, VCMPGTUH, do_vcmp, TCG_COND_GTU, MO_16) +TRANS_FLAGS(ALTIVEC, VCMPGTUW, do_vcmp, TCG_COND_GTU, MO_32) +TRANS_FLAGS2(ALTIVEC_207, VCMPGTUD, do_vcmp, TCG_COND_GTU, MO_64) + +TRANS_FLAGS2(ISA300, VCMPNEB, do_vcmp, TCG_COND_NE, MO_8) +TRANS_FLAGS2(ISA300, VCMPNEH, do_vcmp, TCG_COND_NE, MO_16) +TRANS_FLAGS2(ISA300, VCMPNEW, do_vcmp, TCG_COND_NE, MO_32) + +static void gen_vcmpnez_vec(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +{ + TCGv_vec t0, t1, zero; + + t0 = tcg_temp_new_vec_matching(t); + t1 = tcg_temp_new_vec_matching(t); + zero = tcg_constant_vec_matching(t, vece, 0); + + tcg_gen_cmp_vec(TCG_COND_EQ, vece, t0, a, zero); + tcg_gen_cmp_vec(TCG_COND_EQ, vece, t1, b, zero); + tcg_gen_cmp_vec(TCG_COND_NE, vece, t, a, b); + + tcg_gen_or_vec(vece, t, t, t0); + tcg_gen_or_vec(vece, t, t, t1); +} + +static bool do_vcmpnez(DisasContext *ctx, arg_VC *a, int vece) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_cmp_vec, 0 + }; + static const GVecGen3 ops[3] = { + { + .fniv = gen_vcmpnez_vec, + .fno = gen_helper_VCMPNEZB, + .opt_opc = vecop_list, + .vece = MO_8 + }, + { + .fniv = gen_vcmpnez_vec, + .fno = gen_helper_VCMPNEZH, + .opt_opc = vecop_list, + .vece = MO_16 + }, + { + .fniv = gen_vcmpnez_vec, + .fno = gen_helper_VCMPNEZW, + .opt_opc = vecop_list, + .vece = MO_32 + } + }; + + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16, &ops[vece]); + + if (a->rc) { + do_vcmp_rc(a->vrt); + } + + return true; +} + +TRANS(VCMPNEZB, do_vcmpnez, MO_8) +TRANS(VCMPNEZH, do_vcmpnez, MO_16) +TRANS(VCMPNEZW, do_vcmpnez, MO_32) + +static bool trans_VCMPEQUQ(DisasContext *ctx, arg_VC *a) +{ + TCGv_i64 t0, t1, t2; + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + t2 = tcg_temp_new_i64(); + + get_avr64(t0, a->vra, true); + get_avr64(t1, a->vrb, true); + tcg_gen_xor_i64(t2, t0, t1); + + get_avr64(t0, a->vra, false); + get_avr64(t1, a->vrb, false); + tcg_gen_xor_i64(t1, t0, t1); + + tcg_gen_or_i64(t1, t1, t2); + tcg_gen_negsetcond_i64(TCG_COND_EQ, t1, t1, tcg_constant_i64(0)); + + set_avr64(a->vrt, t1, true); + set_avr64(a->vrt, t1, false); + + if (a->rc) { + tcg_gen_extrl_i64_i32(cpu_crf[6], t1); + tcg_gen_andi_i32(cpu_crf[6], cpu_crf[6], 0xa); + tcg_gen_xori_i32(cpu_crf[6], cpu_crf[6], 0x2); + } + return true; +} + +static bool do_vcmpgtq(DisasContext *ctx, arg_VC *a, bool sign) +{ + TCGv_i64 t0, t1, t2; + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + t2 = tcg_temp_new_i64(); + + get_avr64(t0, a->vra, false); + get_avr64(t1, a->vrb, false); + tcg_gen_negsetcond_i64(TCG_COND_GTU, t2, t0, t1); + + get_avr64(t0, a->vra, true); + get_avr64(t1, a->vrb, true); + tcg_gen_movcond_i64(TCG_COND_EQ, t2, t0, t1, t2, tcg_constant_i64(0)); + tcg_gen_negsetcond_i64(sign ? TCG_COND_GT : TCG_COND_GTU, t1, t0, t1); + + tcg_gen_or_i64(t1, t1, t2); + + set_avr64(a->vrt, t1, true); + set_avr64(a->vrt, t1, false); + + if (a->rc) { + tcg_gen_extrl_i64_i32(cpu_crf[6], t1); + tcg_gen_andi_i32(cpu_crf[6], cpu_crf[6], 0xa); + tcg_gen_xori_i32(cpu_crf[6], cpu_crf[6], 0x2); + } + return true; +} + +TRANS(VCMPGTSQ, do_vcmpgtq, true) +TRANS(VCMPGTUQ, do_vcmpgtq, false) + +static bool do_vcmpq(DisasContext *ctx, arg_VX_bf *a, bool sign) +{ + TCGv_i64 vra, vrb; + TCGLabel *gt, *lt, *done; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + vra = tcg_temp_new_i64(); + vrb = tcg_temp_new_i64(); + gt = gen_new_label(); + lt = gen_new_label(); + done = gen_new_label(); + + get_avr64(vra, a->vra, true); + get_avr64(vrb, a->vrb, true); + tcg_gen_brcond_i64((sign ? TCG_COND_GT : TCG_COND_GTU), vra, vrb, gt); + tcg_gen_brcond_i64((sign ? TCG_COND_LT : TCG_COND_LTU), vra, vrb, lt); + + get_avr64(vra, a->vra, false); + get_avr64(vrb, a->vrb, false); + tcg_gen_brcond_i64(TCG_COND_GTU, vra, vrb, gt); + tcg_gen_brcond_i64(TCG_COND_LTU, vra, vrb, lt); + + tcg_gen_movi_i32(cpu_crf[a->bf], CRF_EQ); + tcg_gen_br(done); + + gen_set_label(gt); + tcg_gen_movi_i32(cpu_crf[a->bf], CRF_GT); + tcg_gen_br(done); + + gen_set_label(lt); + tcg_gen_movi_i32(cpu_crf[a->bf], CRF_LT); + tcg_gen_br(done); + + gen_set_label(done); + return true; +} + +TRANS(VCMPSQ, do_vcmpq, true) +TRANS(VCMPUQ, do_vcmpq, false) + GEN_VXRFORM(vcmpeqfp, 3, 3) GEN_VXRFORM(vcmpgefp, 3, 7) GEN_VXRFORM(vcmpgtfp, 3, 11) GEN_VXRFORM(vcmpbfp, 3, 15) -GEN_VXRFORM(vcmpneb, 3, 0) -GEN_VXRFORM(vcmpneh, 3, 1) -GEN_VXRFORM(vcmpnew, 3, 2) - -GEN_VXRFORM_DUAL(vcmpequb, PPC_ALTIVEC, PPC_NONE, \ - vcmpneb, PPC_NONE, PPC2_ISA300) -GEN_VXRFORM_DUAL(vcmpequh, PPC_ALTIVEC, PPC_NONE, \ - vcmpneh, PPC_NONE, PPC2_ISA300) -GEN_VXRFORM_DUAL(vcmpequw, PPC_ALTIVEC, PPC_NONE, \ - vcmpnew, PPC_NONE, PPC2_ISA300) -GEN_VXRFORM_DUAL(vcmpeqfp, PPC_ALTIVEC, PPC_NONE, \ - vcmpequd, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXRFORM_DUAL(vcmpbfp, PPC_ALTIVEC, PPC_NONE, \ - vcmpgtsd, PPC_NONE, PPC2_ALTIVEC_207) -GEN_VXRFORM_DUAL(vcmpgtfp, PPC_ALTIVEC, PPC_NONE, \ - vcmpgtud, PPC_NONE, PPC2_ALTIVEC_207) static void gen_vsplti(DisasContext *ctx, int vece) { @@ -1075,8 +1465,6 @@ static void glue(gen_, name)(DisasContext *ctx) \ rb = gen_avr_ptr(rB(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ gen_helper_##name(rd, rb); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rd); \ } #define GEN_VXFORM_NOA_ENV(name, opc2, opc3) \ @@ -1090,9 +1478,7 @@ static void glue(gen_, name)(DisasContext *ctx) \ } \ rb = gen_avr_ptr(rB(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##name(cpu_env, rd, rb); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rd); \ + gen_helper_##name(tcg_env, rd, rb); \ } #define GEN_VXFORM_NOA_2(name, opc2, opc3, opc4) \ @@ -1106,8 +1492,6 @@ static void glue(gen_, name)(DisasContext *ctx) \ rb = gen_avr_ptr(rB(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ gen_helper_##name(rd, rb); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rd); \ } #define GEN_VXFORM_NOA_3(name, opc2, opc3, opc4) \ @@ -1120,7 +1504,6 @@ static void glue(gen_, name)(DisasContext *ctx) \ } \ rb = gen_avr_ptr(rB(ctx->opcode)); \ gen_helper_##name(cpu_gpr[rD(ctx->opcode)], rb); \ - tcg_temp_free_ptr(rb); \ } GEN_VXFORM_NOA(vupkhsb, 7, 8); GEN_VXFORM_NOA(vupkhsh, 7, 9); @@ -1138,9 +1521,70 @@ GEN_VXFORM_NOA_ENV(vrfim, 5, 11); GEN_VXFORM_NOA_ENV(vrfin, 5, 8); GEN_VXFORM_NOA_ENV(vrfip, 5, 10); GEN_VXFORM_NOA_ENV(vrfiz, 5, 9); -GEN_VXFORM_NOA(vprtybw, 1, 24); -GEN_VXFORM_NOA(vprtybd, 1, 24); -GEN_VXFORM_NOA(vprtybq, 1, 24); + +static void gen_vprtyb_vec(unsigned vece, TCGv_vec t, TCGv_vec b) +{ + int i; + TCGv_vec tmp = tcg_temp_new_vec_matching(b); + /* MO_32 is 2, so 2 iterations for MO_32 and 3 for MO_64 */ + for (i = 0; i < vece; i++) { + tcg_gen_shri_vec(vece, tmp, b, (4 << (vece - i))); + tcg_gen_xor_vec(vece, b, tmp, b); + } + tcg_gen_and_vec(vece, t, b, tcg_constant_vec_matching(t, vece, 1)); +} + +/* vprtybw */ +static void gen_vprtyb_i32(TCGv_i32 t, TCGv_i32 b) +{ + tcg_gen_ctpop_i32(t, b); + tcg_gen_and_i32(t, t, tcg_constant_i32(1)); +} + +/* vprtybd */ +static void gen_vprtyb_i64(TCGv_i64 t, TCGv_i64 b) +{ + tcg_gen_ctpop_i64(t, b); + tcg_gen_and_i64(t, t, tcg_constant_i64(1)); +} + +static bool do_vx_vprtyb(DisasContext *ctx, arg_VX_tb *a, unsigned vece) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_shri_vec, 0 + }; + + static const GVecGen2 op[] = { + { + .fniv = gen_vprtyb_vec, + .fni4 = gen_vprtyb_i32, + .opt_opc = vecop_list, + .vece = MO_32 + }, + { + .fniv = gen_vprtyb_vec, + .fni8 = gen_vprtyb_i64, + .opt_opc = vecop_list, + .vece = MO_64 + }, + { + .fno = gen_helper_VPRTYBQ, + .vece = MO_128 + }, + }; + + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_2(avr_full_offset(a->vrt), avr_full_offset(a->vrb), + 16, 16, &op[vece - MO_32]); + + return true; +} + +TRANS(VPRTYBW, do_vx_vprtyb, MO_32) +TRANS(VPRTYBD, do_vx_vprtyb, MO_64) +TRANS(VPRTYBQ, do_vx_vprtyb, MO_128) static void gen_vsplt(DisasContext *ctx, int vece) { @@ -1157,7 +1601,7 @@ static void gen_vsplt(DisasContext *ctx, int vece) /* Experimental testing shows that hardware masks the immediate. */ bofs += (uimm << vece) & 15; -#ifndef HOST_WORDS_BIGENDIAN +#if !HOST_BIG_ENDIAN bofs ^= 15; bofs &= ~((1 << vece) - 1); #endif @@ -1178,13 +1622,10 @@ static void glue(gen_, name)(DisasContext *ctx) \ gen_exception(ctx, POWERPC_EXCP_VPU); \ return; \ } \ - uimm = tcg_const_i32(UIMM5(ctx->opcode)); \ + uimm = tcg_constant_i32(UIMM5(ctx->opcode)); \ rb = gen_avr_ptr(rB(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ - gen_helper_##name(cpu_env, rd, rb, uimm); \ - tcg_temp_free_i32(uimm); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rd); \ + gen_helper_##name(tcg_env, rd, rb, uimm); \ } #define GEN_VXFORM_UIMM_SPLAT(name, opc2, opc3, splat_max) \ @@ -1205,9 +1646,6 @@ static void glue(gen_, name)(DisasContext *ctx) \ rb = gen_avr_ptr(rB(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ gen_helper_##name(rd, rb, t0); \ - tcg_temp_free_i32(t0); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rd); \ } GEN_VXFORM_VSPLT(vspltb, MO_8, 6, 8); @@ -1217,10 +1655,6 @@ GEN_VXFORM_UIMM_SPLAT(vextractub, 6, 8, 15); GEN_VXFORM_UIMM_SPLAT(vextractuh, 6, 9, 14); GEN_VXFORM_UIMM_SPLAT(vextractuw, 6, 10, 12); GEN_VXFORM_UIMM_SPLAT(vextractd, 6, 11, 8); -GEN_VXFORM_UIMM_SPLAT(vinsertb, 6, 12, 15); -GEN_VXFORM_UIMM_SPLAT(vinserth, 6, 13, 14); -GEN_VXFORM_UIMM_SPLAT(vinsertw, 6, 14, 12); -GEN_VXFORM_UIMM_SPLAT(vinsertd, 6, 15, 8); GEN_VXFORM_UIMM_ENV(vcfux, 5, 12); GEN_VXFORM_UIMM_ENV(vcfsx, 5, 13); GEN_VXFORM_UIMM_ENV(vctuxs, 5, 14); @@ -1231,12 +1665,292 @@ GEN_VXFORM_DUAL(vsplth, PPC_ALTIVEC, PPC_NONE, vextractuh, PPC_NONE, PPC2_ISA300); GEN_VXFORM_DUAL(vspltw, PPC_ALTIVEC, PPC_NONE, vextractuw, PPC_NONE, PPC2_ISA300); -GEN_VXFORM_DUAL(vspltisb, PPC_ALTIVEC, PPC_NONE, - vinsertb, PPC_NONE, PPC2_ISA300); -GEN_VXFORM_DUAL(vspltish, PPC_ALTIVEC, PPC_NONE, - vinserth, PPC_NONE, PPC2_ISA300); -GEN_VXFORM_DUAL(vspltisw, PPC_ALTIVEC, PPC_NONE, - vinsertw, PPC_NONE, PPC2_ISA300); + +static bool trans_VGNB(DisasContext *ctx, arg_VX_n *a) +{ + /* + * Similar to do_vextractm, we'll use a sequence of mask-shift-or operations + * to gather the bits. The masks can be created with + * + * uint64_t mask(uint64_t n, uint64_t step) + * { + * uint64_t p = ((1UL << (1UL << step)) - 1UL) << ((n - 1UL) << step), + * plen = n << step, m = 0; + * for(int i = 0; i < 64/plen; i++) { + * m |= p; + * m = ror64(m, plen); + * } + * p >>= plen * DIV_ROUND_UP(64, plen) - 64; + * return m | p; + * } + * + * But since there are few values of N, we'll use a lookup table to avoid + * these calculations at runtime. + */ + static const uint64_t mask[6][5] = { + { + 0xAAAAAAAAAAAAAAAAULL, 0xccccccccccccccccULL, 0xf0f0f0f0f0f0f0f0ULL, + 0xff00ff00ff00ff00ULL, 0xffff0000ffff0000ULL + }, + { + 0x9249249249249249ULL, 0xC30C30C30C30C30CULL, 0xF00F00F00F00F00FULL, + 0xFF0000FF0000FF00ULL, 0xFFFF00000000FFFFULL + }, + { + /* For N >= 4, some mask operations can be elided */ + 0x8888888888888888ULL, 0, 0xf000f000f000f000ULL, 0, + 0xFFFF000000000000ULL + }, + { + 0x8421084210842108ULL, 0, 0xF0000F0000F0000FULL, 0, 0 + }, + { + 0x8208208208208208ULL, 0, 0xF00000F00000F000ULL, 0, 0 + }, + { + 0x8102040810204081ULL, 0, 0xF000000F000000F0ULL, 0, 0 + } + }; + uint64_t m; + int i, sh, nbits = DIV_ROUND_UP(64, a->n); + TCGv_i64 hi, lo, t0, t1; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + if (a->n < 2) { + /* + * "N can be any value between 2 and 7, inclusive." Otherwise, the + * result is undefined, so we don't need to change RT. Also, N > 7 is + * impossible since the immediate field is 3 bits only. + */ + return true; + } + + hi = tcg_temp_new_i64(); + lo = tcg_temp_new_i64(); + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + + get_avr64(hi, a->vrb, true); + get_avr64(lo, a->vrb, false); + + /* Align the lower doubleword so we can use the same mask */ + tcg_gen_shli_i64(lo, lo, a->n * nbits - 64); + + /* + * Starting from the most significant bit, gather every Nth bit with a + * sequence of mask-shift-or operation. E.g.: for N=3 + * AxxBxxCxxDxxExxFxxGxxHxxIxxJxxKxxLxxMxxNxxOxxPxxQxxRxxSxxTxxUxxV + * & rep(0b100) + * A..B..C..D..E..F..G..H..I..J..K..L..M..N..O..P..Q..R..S..T..U..V + * << 2 + * .B..C..D..E..F..G..H..I..J..K..L..M..N..O..P..Q..R..S..T..U..V.. + * | + * AB.BC.CD.DE.EF.FG.GH.HI.IJ.JK.KL.LM.MN.NO.OP.PQ.QR.RS.ST.TU.UV.V + * & rep(0b110000) + * AB....CD....EF....GH....IJ....KL....MN....OP....QR....ST....UV.. + * << 4 + * ..CD....EF....GH....IJ....KL....MN....OP....QR....ST....UV...... + * | + * ABCD..CDEF..EFGH..GHIJ..IJKL..KLMN..MNOP..OPQR..QRST..STUV..UV.. + * & rep(0b111100000000) + * ABCD........EFGH........IJKL........MNOP........QRST........UV.. + * << 8 + * ....EFGH........IJKL........MNOP........QRST........UV.......... + * | + * ABCDEFGH....EFGHIJKL....IJKLMNOP....MNOPQRST....QRSTUV......UV.. + * & rep(0b111111110000000000000000) + * ABCDEFGH................IJKLMNOP................QRSTUV.......... + * << 16 + * ........IJKLMNOP................QRSTUV.......................... + * | + * ABCDEFGHIJKLMNOP........IJKLMNOPQRSTUV..........QRSTUV.......... + * & rep(0b111111111111111100000000000000000000000000000000) + * ABCDEFGHIJKLMNOP................................QRSTUV.......... + * << 32 + * ................QRSTUV.......................................... + * | + * ABCDEFGHIJKLMNOPQRSTUV..........................QRSTUV.......... + */ + for (i = 0, sh = a->n - 1; i < 5; i++, sh <<= 1) { + m = mask[a->n - 2][i]; + if (m) { + tcg_gen_andi_i64(hi, hi, m); + tcg_gen_andi_i64(lo, lo, m); + } + if (sh < 64) { + tcg_gen_shli_i64(t0, hi, sh); + tcg_gen_shli_i64(t1, lo, sh); + tcg_gen_or_i64(hi, t0, hi); + tcg_gen_or_i64(lo, t1, lo); + } + } + + tcg_gen_andi_i64(hi, hi, ~(~0ULL >> nbits)); + tcg_gen_andi_i64(lo, lo, ~(~0ULL >> nbits)); + tcg_gen_shri_i64(lo, lo, nbits); + tcg_gen_or_i64(hi, hi, lo); + tcg_gen_trunc_i64_tl(cpu_gpr[a->rt], hi); + return true; +} + +static bool do_vextdx(DisasContext *ctx, arg_VA *a, int size, bool right, + void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv)) +{ + TCGv_ptr vrt, vra, vrb; + TCGv rc; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + vrt = gen_avr_ptr(a->vrt); + vra = gen_avr_ptr(a->vra); + vrb = gen_avr_ptr(a->vrb); + rc = tcg_temp_new(); + + tcg_gen_andi_tl(rc, cpu_gpr[a->rc], 0x1F); + if (right) { + tcg_gen_subfi_tl(rc, 32 - size, rc); + } + gen_helper(tcg_env, vrt, vra, vrb, rc); + return true; +} + +TRANS(VEXTDUBVLX, do_vextdx, 1, false, gen_helper_VEXTDUBVLX) +TRANS(VEXTDUHVLX, do_vextdx, 2, false, gen_helper_VEXTDUHVLX) +TRANS(VEXTDUWVLX, do_vextdx, 4, false, gen_helper_VEXTDUWVLX) +TRANS(VEXTDDVLX, do_vextdx, 8, false, gen_helper_VEXTDDVLX) + +TRANS(VEXTDUBVRX, do_vextdx, 1, true, gen_helper_VEXTDUBVLX) +TRANS(VEXTDUHVRX, do_vextdx, 2, true, gen_helper_VEXTDUHVLX) +TRANS(VEXTDUWVRX, do_vextdx, 4, true, gen_helper_VEXTDUWVLX) +TRANS(VEXTDDVRX, do_vextdx, 8, true, gen_helper_VEXTDDVLX) + +static bool do_vinsx(DisasContext *ctx, int vrt, int size, bool right, TCGv ra, + TCGv_i64 rb, void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv)) +{ + TCGv_ptr t; + TCGv idx; + + t = gen_avr_ptr(vrt); + idx = tcg_temp_new(); + + tcg_gen_andi_tl(idx, ra, 0xF); + if (right) { + tcg_gen_subfi_tl(idx, 16 - size, idx); + } + + gen_helper(tcg_env, t, rb, idx); + return true; +} + +static bool do_vinsvx(DisasContext *ctx, int vrt, int size, bool right, TCGv ra, + int vrb, void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv)) +{ + TCGv_i64 val; + + val = tcg_temp_new_i64(); + get_avr64(val, vrb, true); + return do_vinsx(ctx, vrt, size, right, ra, val, gen_helper); +} + +static bool do_vinsx_VX(DisasContext *ctx, arg_VX *a, int size, bool right, + void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv)) +{ + TCGv_i64 val; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + val = tcg_temp_new_i64(); + tcg_gen_extu_tl_i64(val, cpu_gpr[a->vrb]); + + return do_vinsx(ctx, a->vrt, size, right, cpu_gpr[a->vra], val, gen_helper); +} + +static bool do_vinsvx_VX(DisasContext *ctx, arg_VX *a, int size, bool right, + void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv)) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + return do_vinsvx(ctx, a->vrt, size, right, cpu_gpr[a->vra], a->vrb, + gen_helper); +} + +static bool do_vins_VX_uim4(DisasContext *ctx, arg_VX_uim4 *a, int size, + void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv)) +{ + TCGv_i64 val; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + if (a->uim > (16 - size)) { + /* + * PowerISA v3.1 says that the resulting value is undefined in this + * case, so just log a guest error and leave VRT unchanged. The + * real hardware would do a partial insert, e.g. if VRT is zeroed and + * RB is 0x12345678, executing "vinsw VRT,RB,14" results in + * VRT = 0x0000...00001234, but we don't bother to reproduce this + * behavior as software shouldn't rely on it. + */ + qemu_log_mask(LOG_GUEST_ERROR, "Invalid index for VINS* at" + " 0x" TARGET_FMT_lx ", UIM = %d > %d\n", ctx->cia, a->uim, + 16 - size); + return true; + } + + val = tcg_temp_new_i64(); + tcg_gen_extu_tl_i64(val, cpu_gpr[a->vrb]); + + return do_vinsx(ctx, a->vrt, size, false, tcg_constant_tl(a->uim), val, + gen_helper); +} + +static bool do_vinsert_VX_uim4(DisasContext *ctx, arg_VX_uim4 *a, int size, + void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv)) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VECTOR(ctx); + + if (a->uim > (16 - size)) { + qemu_log_mask(LOG_GUEST_ERROR, "Invalid index for VINSERT* at" + " 0x" TARGET_FMT_lx ", UIM = %d > %d\n", ctx->cia, a->uim, + 16 - size); + return true; + } + + return do_vinsvx(ctx, a->vrt, size, false, tcg_constant_tl(a->uim), a->vrb, + gen_helper); +} + +TRANS(VINSBLX, do_vinsx_VX, 1, false, gen_helper_VINSBLX) +TRANS(VINSHLX, do_vinsx_VX, 2, false, gen_helper_VINSHLX) +TRANS(VINSWLX, do_vinsx_VX, 4, false, gen_helper_VINSWLX) +TRANS(VINSDLX, do_vinsx_VX, 8, false, gen_helper_VINSDLX) + +TRANS(VINSBRX, do_vinsx_VX, 1, true, gen_helper_VINSBLX) +TRANS(VINSHRX, do_vinsx_VX, 2, true, gen_helper_VINSHLX) +TRANS(VINSWRX, do_vinsx_VX, 4, true, gen_helper_VINSWLX) +TRANS(VINSDRX, do_vinsx_VX, 8, true, gen_helper_VINSDLX) + +TRANS(VINSW, do_vins_VX_uim4, 4, gen_helper_VINSWLX) +TRANS(VINSD, do_vins_VX_uim4, 8, gen_helper_VINSDLX) + +TRANS(VINSBVLX, do_vinsvx_VX, 1, false, gen_helper_VINSBLX) +TRANS(VINSHVLX, do_vinsvx_VX, 2, false, gen_helper_VINSHLX) +TRANS(VINSWVLX, do_vinsvx_VX, 4, false, gen_helper_VINSWLX) + +TRANS(VINSBVRX, do_vinsvx_VX, 1, true, gen_helper_VINSBLX) +TRANS(VINSHVRX, do_vinsvx_VX, 2, true, gen_helper_VINSHLX) +TRANS(VINSWVRX, do_vinsvx_VX, 4, true, gen_helper_VINSWLX) + +TRANS(VINSERTB, do_vinsert_VX_uim4, 1, gen_helper_VINSBLX) +TRANS(VINSERTH, do_vinsert_VX_uim4, 2, gen_helper_VINSHLX) +TRANS(VINSERTW, do_vinsert_VX_uim4, 4, gen_helper_VINSWLX) +TRANS(VINSERTD, do_vinsert_VX_uim4, 8, gen_helper_VINSDLX) static void gen_vsldoi(DisasContext *ctx) { @@ -1249,14 +1963,379 @@ static void gen_vsldoi(DisasContext *ctx) ra = gen_avr_ptr(rA(ctx->opcode)); rb = gen_avr_ptr(rB(ctx->opcode)); rd = gen_avr_ptr(rD(ctx->opcode)); - sh = tcg_const_i32(VSH(ctx->opcode)); + sh = tcg_constant_i32(VSH(ctx->opcode)); gen_helper_vsldoi(rd, ra, rb, sh); - tcg_temp_free_ptr(ra); - tcg_temp_free_ptr(rb); - tcg_temp_free_ptr(rd); - tcg_temp_free_i32(sh); } +static bool trans_VSLDBI(DisasContext *ctx, arg_VN *a) +{ + TCGv_i64 t0, t1, t2; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + + get_avr64(t0, a->vra, true); + get_avr64(t1, a->vra, false); + + if (a->sh != 0) { + t2 = tcg_temp_new_i64(); + + get_avr64(t2, a->vrb, true); + + tcg_gen_extract2_i64(t0, t1, t0, 64 - a->sh); + tcg_gen_extract2_i64(t1, t2, t1, 64 - a->sh); + } + + set_avr64(a->vrt, t0, true); + set_avr64(a->vrt, t1, false); + return true; +} + +static bool trans_VSRDBI(DisasContext *ctx, arg_VN *a) +{ + TCGv_i64 t2, t1, t0; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + + get_avr64(t0, a->vrb, false); + get_avr64(t1, a->vrb, true); + + if (a->sh != 0) { + t2 = tcg_temp_new_i64(); + + get_avr64(t2, a->vra, false); + + tcg_gen_extract2_i64(t0, t0, t1, a->sh); + tcg_gen_extract2_i64(t1, t1, t2, a->sh); + } + + set_avr64(a->vrt, t0, false); + set_avr64(a->vrt, t1, true); + return true; +} + +static bool do_vexpand(DisasContext *ctx, arg_VX_tb *a, unsigned vece) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_sari(vece, avr_full_offset(a->vrt), avr_full_offset(a->vrb), + (8 << vece) - 1, 16, 16); + + return true; +} + +TRANS(VEXPANDBM, do_vexpand, MO_8) +TRANS(VEXPANDHM, do_vexpand, MO_16) +TRANS(VEXPANDWM, do_vexpand, MO_32) +TRANS(VEXPANDDM, do_vexpand, MO_64) + +static bool trans_VEXPANDQM(DisasContext *ctx, arg_VX_tb *a) +{ + TCGv_i64 tmp; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + tmp = tcg_temp_new_i64(); + + get_avr64(tmp, a->vrb, true); + tcg_gen_sari_i64(tmp, tmp, 63); + set_avr64(a->vrt, tmp, false); + set_avr64(a->vrt, tmp, true); + return true; +} + +static bool do_vextractm(DisasContext *ctx, arg_VX_tb *a, unsigned vece) +{ + const uint64_t elem_width = 8 << vece, elem_count_half = 8 >> vece, + mask = dup_const(vece, 1ULL << (elem_width - 1)); + uint64_t i, j; + TCGv_i64 lo, hi, t0, t1; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + hi = tcg_temp_new_i64(); + lo = tcg_temp_new_i64(); + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + + get_avr64(lo, a->vrb, false); + get_avr64(hi, a->vrb, true); + + tcg_gen_andi_i64(lo, lo, mask); + tcg_gen_andi_i64(hi, hi, mask); + + /* + * Gather the most significant bit of each element in the highest element + * element. E.g. for bytes: + * aXXXXXXXbXXXXXXXcXXXXXXXdXXXXXXXeXXXXXXXfXXXXXXXgXXXXXXXhXXXXXXX + * & dup(1 << (elem_width - 1)) + * a0000000b0000000c0000000d0000000e0000000f0000000g0000000h0000000 + * << 32 - 4 + * 0000e0000000f0000000g0000000h00000000000000000000000000000000000 + * | + * a000e000b000f000c000g000d000h000e0000000f0000000g0000000h0000000 + * << 16 - 2 + * 00c000g000d000h000e0000000f0000000g0000000h000000000000000000000 + * | + * a0c0e0g0b0d0f0h0c0e0g000d0f0h000e0g00000f0h00000g0000000h0000000 + * << 8 - 1 + * 0b0d0f0h0c0e0g000d0f0h000e0g00000f0h00000g0000000h00000000000000 + * | + * abcdefghbcdefgh0cdefgh00defgh000efgh0000fgh00000gh000000h0000000 + */ + for (i = elem_count_half / 2, j = 32; i > 0; i >>= 1, j >>= 1) { + tcg_gen_shli_i64(t0, hi, j - i); + tcg_gen_shli_i64(t1, lo, j - i); + tcg_gen_or_i64(hi, hi, t0); + tcg_gen_or_i64(lo, lo, t1); + } + + tcg_gen_shri_i64(hi, hi, 64 - elem_count_half); + tcg_gen_extract2_i64(lo, lo, hi, 64 - elem_count_half); + tcg_gen_trunc_i64_tl(cpu_gpr[a->vrt], lo); + return true; +} + +TRANS(VEXTRACTBM, do_vextractm, MO_8) +TRANS(VEXTRACTHM, do_vextractm, MO_16) +TRANS(VEXTRACTWM, do_vextractm, MO_32) +TRANS(VEXTRACTDM, do_vextractm, MO_64) + +static bool trans_VEXTRACTQM(DisasContext *ctx, arg_VX_tb *a) +{ + TCGv_i64 tmp; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + tmp = tcg_temp_new_i64(); + + get_avr64(tmp, a->vrb, true); + tcg_gen_shri_i64(tmp, tmp, 63); + tcg_gen_trunc_i64_tl(cpu_gpr[a->vrt], tmp); + return true; +} + +static bool do_mtvsrm(DisasContext *ctx, arg_VX_tb *a, unsigned vece) +{ + const uint64_t elem_width = 8 << vece, elem_count_half = 8 >> vece; + uint64_t c; + int i, j; + TCGv_i64 hi, lo, t0, t1; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + hi = tcg_temp_new_i64(); + lo = tcg_temp_new_i64(); + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + + tcg_gen_extu_tl_i64(t0, cpu_gpr[a->vrb]); + tcg_gen_extract_i64(hi, t0, elem_count_half, elem_count_half); + tcg_gen_extract_i64(lo, t0, 0, elem_count_half); + + /* + * Spread the bits into their respective elements. + * E.g. for bytes: + * 00000000000000000000000000000000000000000000000000000000abcdefgh + * << 32 - 4 + * 0000000000000000000000000000abcdefgh0000000000000000000000000000 + * | + * 0000000000000000000000000000abcdefgh00000000000000000000abcdefgh + * << 16 - 2 + * 00000000000000abcdefgh00000000000000000000abcdefgh00000000000000 + * | + * 00000000000000abcdefgh000000abcdefgh000000abcdefgh000000abcdefgh + * << 8 - 1 + * 0000000abcdefgh000000abcdefgh000000abcdefgh000000abcdefgh0000000 + * | + * 0000000abcdefgXbcdefgXbcdefgXbcdefgXbcdefgXbcdefgXbcdefgXbcdefgh + * & dup(1) + * 0000000a0000000b0000000c0000000d0000000e0000000f0000000g0000000h + * * 0xff + * aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhh + */ + for (i = elem_count_half / 2, j = 32; i > 0; i >>= 1, j >>= 1) { + tcg_gen_shli_i64(t0, hi, j - i); + tcg_gen_shli_i64(t1, lo, j - i); + tcg_gen_or_i64(hi, hi, t0); + tcg_gen_or_i64(lo, lo, t1); + } + + c = dup_const(vece, 1); + tcg_gen_andi_i64(hi, hi, c); + tcg_gen_andi_i64(lo, lo, c); + + c = MAKE_64BIT_MASK(0, elem_width); + tcg_gen_muli_i64(hi, hi, c); + tcg_gen_muli_i64(lo, lo, c); + + set_avr64(a->vrt, lo, false); + set_avr64(a->vrt, hi, true); + return true; +} + +TRANS(MTVSRBM, do_mtvsrm, MO_8) +TRANS(MTVSRHM, do_mtvsrm, MO_16) +TRANS(MTVSRWM, do_mtvsrm, MO_32) +TRANS(MTVSRDM, do_mtvsrm, MO_64) + +static bool trans_MTVSRQM(DisasContext *ctx, arg_VX_tb *a) +{ + TCGv_i64 tmp; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + tmp = tcg_temp_new_i64(); + + tcg_gen_ext_tl_i64(tmp, cpu_gpr[a->vrb]); + tcg_gen_sextract_i64(tmp, tmp, 0, 1); + set_avr64(a->vrt, tmp, false); + set_avr64(a->vrt, tmp, true); + return true; +} + +static bool trans_MTVSRBMI(DisasContext *ctx, arg_DX_b *a) +{ + const uint64_t mask = dup_const(MO_8, 1); + uint64_t hi, lo; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + hi = extract16(a->b, 8, 8); + lo = extract16(a->b, 0, 8); + + for (int i = 4, j = 32; i > 0; i >>= 1, j >>= 1) { + hi |= hi << (j - i); + lo |= lo << (j - i); + } + + hi = (hi & mask) * 0xFF; + lo = (lo & mask) * 0xFF; + + set_avr64(a->vrt, tcg_constant_i64(hi), true); + set_avr64(a->vrt, tcg_constant_i64(lo), false); + + return true; +} + +static bool do_vcntmb(DisasContext *ctx, arg_VX_mp *a, int vece) +{ + TCGv_i64 r[2], mask; + + r[0] = tcg_temp_new_i64(); + r[1] = tcg_temp_new_i64(); + mask = tcg_constant_i64(dup_const(vece, 1ULL << ((8 << vece) - 1))); + + for (int i = 0; i < 2; i++) { + get_avr64(r[i], a->vrb, i); + if (a->mp) { + tcg_gen_and_i64(r[i], mask, r[i]); + } else { + tcg_gen_andc_i64(r[i], mask, r[i]); + } + tcg_gen_ctpop_i64(r[i], r[i]); + } + + tcg_gen_add_i64(r[0], r[0], r[1]); + tcg_gen_shli_i64(r[0], r[0], TARGET_LONG_BITS - 8 + vece); + tcg_gen_trunc_i64_tl(cpu_gpr[a->rt], r[0]); + return true; +} + +TRANS(VCNTMBB, do_vcntmb, MO_8) +TRANS(VCNTMBH, do_vcntmb, MO_16) +TRANS(VCNTMBW, do_vcntmb, MO_32) +TRANS(VCNTMBD, do_vcntmb, MO_64) + +static bool do_vstri(DisasContext *ctx, arg_VX_tb_rc *a, + void (*gen_helper)(TCGv_i32, TCGv_ptr, TCGv_ptr)) +{ + TCGv_ptr vrt, vrb; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + vrt = gen_avr_ptr(a->vrt); + vrb = gen_avr_ptr(a->vrb); + + if (a->rc) { + gen_helper(cpu_crf[6], vrt, vrb); + } else { + TCGv_i32 discard = tcg_temp_new_i32(); + gen_helper(discard, vrt, vrb); + } + return true; +} + +TRANS(VSTRIBL, do_vstri, gen_helper_VSTRIBL) +TRANS(VSTRIBR, do_vstri, gen_helper_VSTRIBR) +TRANS(VSTRIHL, do_vstri, gen_helper_VSTRIHL) +TRANS(VSTRIHR, do_vstri, gen_helper_VSTRIHR) + +static bool do_vclrb(DisasContext *ctx, arg_VX *a, bool right) +{ + TCGv_i64 rb, mh, ml, tmp, + ones = tcg_constant_i64(-1), + zero = tcg_constant_i64(0); + + rb = tcg_temp_new_i64(); + mh = tcg_temp_new_i64(); + ml = tcg_temp_new_i64(); + tmp = tcg_temp_new_i64(); + + tcg_gen_extu_tl_i64(rb, cpu_gpr[a->vrb]); + tcg_gen_andi_i64(tmp, rb, 7); + tcg_gen_shli_i64(tmp, tmp, 3); + if (right) { + tcg_gen_shr_i64(tmp, ones, tmp); + } else { + tcg_gen_shl_i64(tmp, ones, tmp); + } + tcg_gen_not_i64(tmp, tmp); + + if (right) { + tcg_gen_movcond_i64(TCG_COND_LTU, mh, rb, tcg_constant_i64(8), + tmp, ones); + tcg_gen_movcond_i64(TCG_COND_LTU, ml, rb, tcg_constant_i64(8), + zero, tmp); + tcg_gen_movcond_i64(TCG_COND_LTU, ml, rb, tcg_constant_i64(16), + ml, ones); + } else { + tcg_gen_movcond_i64(TCG_COND_LTU, ml, rb, tcg_constant_i64(8), + tmp, ones); + tcg_gen_movcond_i64(TCG_COND_LTU, mh, rb, tcg_constant_i64(8), + zero, tmp); + tcg_gen_movcond_i64(TCG_COND_LTU, mh, rb, tcg_constant_i64(16), + mh, ones); + } + + get_avr64(tmp, a->vra, true); + tcg_gen_and_i64(tmp, tmp, mh); + set_avr64(a->vrt, tmp, true); + + get_avr64(tmp, a->vra, false); + tcg_gen_and_i64(tmp, tmp, ml); + set_avr64(a->vrt, tmp, false); + return true; +} + +TRANS(VCLRLB, do_vclrb, false) +TRANS(VCLRRB, do_vclrb, true) + #define GEN_VAFORM_PAIRED(name0, name1, opc2) \ static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ { \ @@ -1270,71 +2349,190 @@ static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ rc = gen_avr_ptr(rC(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ if (Rc(ctx->opcode)) { \ - gen_helper_##name1(cpu_env, rd, ra, rb, rc); \ + gen_helper_##name1(tcg_env, rd, ra, rb, rc); \ } else { \ - gen_helper_##name0(cpu_env, rd, ra, rb, rc); \ + gen_helper_##name0(tcg_env, rd, ra, rb, rc); \ } \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rc); \ - tcg_temp_free_ptr(rd); \ } -GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16) +GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23) -static void gen_vmladduhm(DisasContext *ctx) +static bool do_va_helper(DisasContext *ctx, arg_VA *a, + void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr)) { - TCGv_ptr ra, rb, rc, rd; - if (unlikely(!ctx->altivec_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VPU); - return; - } - ra = gen_avr_ptr(rA(ctx->opcode)); - rb = gen_avr_ptr(rB(ctx->opcode)); - rc = gen_avr_ptr(rC(ctx->opcode)); - rd = gen_avr_ptr(rD(ctx->opcode)); - gen_helper_vmladduhm(rd, ra, rb, rc); - tcg_temp_free_ptr(ra); - tcg_temp_free_ptr(rb); - tcg_temp_free_ptr(rc); - tcg_temp_free_ptr(rd); + TCGv_ptr vrt, vra, vrb, vrc; + REQUIRE_VECTOR(ctx); + + vrt = gen_avr_ptr(a->vrt); + vra = gen_avr_ptr(a->vra); + vrb = gen_avr_ptr(a->vrb); + vrc = gen_avr_ptr(a->rc); + gen_helper(vrt, vra, vrb, vrc); + return true; } -static void gen_vpermr(DisasContext *ctx) +TRANS_FLAGS2(ALTIVEC_207, VADDECUQ, do_va_helper, gen_helper_VADDECUQ) +TRANS_FLAGS2(ALTIVEC_207, VADDEUQM, do_va_helper, gen_helper_VADDEUQM) + +TRANS_FLAGS2(ALTIVEC_207, VSUBEUQM, do_va_helper, gen_helper_VSUBEUQM) +TRANS_FLAGS2(ALTIVEC_207, VSUBECUQ, do_va_helper, gen_helper_VSUBECUQ) + +TRANS_FLAGS(ALTIVEC, VPERM, do_va_helper, gen_helper_VPERM) +TRANS_FLAGS2(ISA300, VPERMR, do_va_helper, gen_helper_VPERMR) + +static void gen_vmladduhm_vec(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b, + TCGv_vec c) { - TCGv_ptr ra, rb, rc, rd; - if (unlikely(!ctx->altivec_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VPU); - return; - } - ra = gen_avr_ptr(rA(ctx->opcode)); - rb = gen_avr_ptr(rB(ctx->opcode)); - rc = gen_avr_ptr(rC(ctx->opcode)); - rd = gen_avr_ptr(rD(ctx->opcode)); - gen_helper_vpermr(cpu_env, rd, ra, rb, rc); - tcg_temp_free_ptr(ra); - tcg_temp_free_ptr(rb); - tcg_temp_free_ptr(rc); - tcg_temp_free_ptr(rd); + tcg_gen_mul_vec(vece, t, a, b); + tcg_gen_add_vec(vece, t, t, c); } -GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18) -GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19) -GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20) -GEN_VAFORM_PAIRED(vsel, vperm, 21) -GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23) +static bool trans_VMLADDUHM(DisasContext *ctx, arg_VA *a) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_add_vec, INDEX_op_mul_vec, 0 + }; + + static const GVecGen4 op = { + .fno = gen_helper_VMLADDUHM, + .fniv = gen_vmladduhm_vec, + .opt_opc = vecop_list, + .vece = MO_16 + }; + + REQUIRE_INSNS_FLAGS(ctx, ALTIVEC); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_4(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), avr_full_offset(a->rc), + 16, 16, &op); + + return true; +} + +static bool trans_VSEL(DisasContext *ctx, arg_VA *a) +{ + REQUIRE_INSNS_FLAGS(ctx, ALTIVEC); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_bitsel(MO_64, avr_full_offset(a->vrt), avr_full_offset(a->rc), + avr_full_offset(a->vrb), avr_full_offset(a->vra), + 16, 16); + + return true; +} + +TRANS_FLAGS(ALTIVEC, VMSUMUBM, do_va_helper, gen_helper_VMSUMUBM) +TRANS_FLAGS(ALTIVEC, VMSUMMBM, do_va_helper, gen_helper_VMSUMMBM) +TRANS_FLAGS(ALTIVEC, VMSUMSHM, do_va_helper, gen_helper_VMSUMSHM) +TRANS_FLAGS(ALTIVEC, VMSUMUHM, do_va_helper, gen_helper_VMSUMUHM) + +static bool do_va_env_helper(DisasContext *ctx, arg_VA *a, + void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr)) +{ + TCGv_ptr vrt, vra, vrb, vrc; + REQUIRE_VECTOR(ctx); + + vrt = gen_avr_ptr(a->vrt); + vra = gen_avr_ptr(a->vra); + vrb = gen_avr_ptr(a->vrb); + vrc = gen_avr_ptr(a->rc); + gen_helper(tcg_env, vrt, vra, vrb, vrc); + return true; +} + +TRANS_FLAGS(ALTIVEC, VMSUMUHS, do_va_env_helper, gen_helper_VMSUMUHS) +TRANS_FLAGS(ALTIVEC, VMSUMSHS, do_va_env_helper, gen_helper_VMSUMSHS) + +TRANS_FLAGS(ALTIVEC, VMHADDSHS, do_va_env_helper, gen_helper_VMHADDSHS) +TRANS_FLAGS(ALTIVEC, VMHRADDSHS, do_va_env_helper, gen_helper_VMHRADDSHS) GEN_VXFORM_NOA(vclzb, 1, 28) GEN_VXFORM_NOA(vclzh, 1, 29) GEN_VXFORM_TRANS(vclzw, 1, 30) GEN_VXFORM_TRANS(vclzd, 1, 31) -GEN_VXFORM_NOA_2(vnegw, 1, 24, 6) -GEN_VXFORM_NOA_2(vnegd, 1, 24, 7) -GEN_VXFORM_NOA_2(vextsb2w, 1, 24, 16) -GEN_VXFORM_NOA_2(vextsh2w, 1, 24, 17) -GEN_VXFORM_NOA_2(vextsb2d, 1, 24, 24) -GEN_VXFORM_NOA_2(vextsh2d, 1, 24, 25) -GEN_VXFORM_NOA_2(vextsw2d, 1, 24, 26) + +static bool do_vneg(DisasContext *ctx, arg_VX_tb *a, unsigned vece) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_neg(vece, avr_full_offset(a->vrt), avr_full_offset(a->vrb), + 16, 16); + return true; +} + +TRANS(VNEGW, do_vneg, MO_32) +TRANS(VNEGD, do_vneg, MO_64) + +static void gen_vexts_i64(TCGv_i64 t, TCGv_i64 b, int64_t s) +{ + tcg_gen_sextract_i64(t, b, 0, 64 - s); +} + +static void gen_vexts_i32(TCGv_i32 t, TCGv_i32 b, int32_t s) +{ + tcg_gen_sextract_i32(t, b, 0, 32 - s); +} + +static void gen_vexts_vec(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t s) +{ + tcg_gen_shli_vec(vece, t, b, s); + tcg_gen_sari_vec(vece, t, t, s); +} + +static bool do_vexts(DisasContext *ctx, arg_VX_tb *a, unsigned vece, int64_t s) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_shli_vec, INDEX_op_sari_vec, 0 + }; + + static const GVecGen2i op[2] = { + { + .fni4 = gen_vexts_i32, + .fniv = gen_vexts_vec, + .opt_opc = vecop_list, + .vece = MO_32 + }, + { + .fni8 = gen_vexts_i64, + .fniv = gen_vexts_vec, + .opt_opc = vecop_list, + .vece = MO_64 + }, + }; + + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_2i(avr_full_offset(a->vrt), avr_full_offset(a->vrb), + 16, 16, s, &op[vece - MO_32]); + + return true; +} + +TRANS(VEXTSB2W, do_vexts, MO_32, 24); +TRANS(VEXTSH2W, do_vexts, MO_32, 16); +TRANS(VEXTSB2D, do_vexts, MO_64, 56); +TRANS(VEXTSH2D, do_vexts, MO_64, 48); +TRANS(VEXTSW2D, do_vexts, MO_64, 32); + +static bool trans_VEXTSD2Q(DisasContext *ctx, arg_VX_tb *a) +{ + TCGv_i64 tmp; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + tmp = tcg_temp_new_i64(); + + get_avr64(tmp, a->vrb, false); + set_avr64(a->vrt, tmp, false); + tcg_gen_sari_i64(tmp, tmp, 63); + set_avr64(a->vrt, tmp, true); + return true; +} + GEN_VXFORM_NOA_2(vctzb, 1, 24, 28) GEN_VXFORM_NOA_2(vctzh, 1, 24, 29) GEN_VXFORM_NOA_2(vctzw, 1, 24, 30) @@ -1359,7 +2557,6 @@ GEN_VXFORM_TRANS(vgbbd, 6, 20); GEN_VXFORM(vpmsumb, 4, 16) GEN_VXFORM(vpmsumh, 4, 17) GEN_VXFORM(vpmsumw, 4, 18) -GEN_VXFORM(vpmsumd, 4, 19) #define GEN_BCD(op) \ static void gen_##op(DisasContext *ctx) \ @@ -1376,14 +2573,9 @@ static void gen_##op(DisasContext *ctx) \ rb = gen_avr_ptr(rB(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ \ - ps = tcg_const_i32((ctx->opcode & 0x200) != 0); \ + ps = tcg_constant_i32((ctx->opcode & 0x200) != 0); \ \ gen_helper_##op(cpu_crf[6], rd, ra, rb, ps); \ - \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rd); \ - tcg_temp_free_i32(ps); \ } #define GEN_BCD2(op) \ @@ -1400,13 +2592,9 @@ static void gen_##op(DisasContext *ctx) \ rb = gen_avr_ptr(rB(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ \ - ps = tcg_const_i32((ctx->opcode & 0x200) != 0); \ + ps = tcg_constant_i32((ctx->opcode & 0x200) != 0); \ \ gen_helper_##op(cpu_crf[6], rd, rb, ps); \ - \ - tcg_temp_free_ptr(rb); \ - tcg_temp_free_ptr(rd); \ - tcg_temp_free_i32(ps); \ } GEN_BCD(bcdadd) @@ -1483,8 +2671,6 @@ static void gen_xpnd04_2(DisasContext *ctx) } -GEN_VXFORM_DUAL(vsubcuw, PPC_ALTIVEC, PPC_NONE, \ - xpnd04_1, PPC_NONE, PPC2_ISA300) GEN_VXFORM_DUAL(vsubsws, PPC_ALTIVEC, PPC_NONE, \ xpnd04_2, PPC_NONE, PPC2_ISA300) @@ -1504,11 +2690,6 @@ GEN_VXFORM_DUAL(vsubuwm, PPC_ALTIVEC, PPC_NONE, \ bcdus, PPC_NONE, PPC2_ISA300) GEN_VXFORM_DUAL(vsubsbs, PPC_ALTIVEC, PPC_NONE, \ bcdtrunc, PPC_NONE, PPC2_ISA300) -GEN_VXFORM_DUAL(vsubuqm, PPC2_ALTIVEC_207, PPC_NONE, \ - bcdtrunc, PPC_NONE, PPC2_ISA300) -GEN_VXFORM_DUAL(vsubcuq, PPC2_ALTIVEC_207, PPC_NONE, \ - bcdutrunc, PPC_NONE, PPC2_ISA300) - static void gen_vsbox(DisasContext *ctx) { @@ -1520,8 +2701,6 @@ static void gen_vsbox(DisasContext *ctx) ra = gen_avr_ptr(rA(ctx->opcode)); rd = gen_avr_ptr(rD(ctx->opcode)); gen_helper_vsbox(rd, ra); - tcg_temp_free_ptr(ra); - tcg_temp_free_ptr(rd); } GEN_VXFORM(vcipher, 4, 20) @@ -1545,11 +2724,8 @@ static void gen_##op(DisasContext *ctx) \ } \ ra = gen_avr_ptr(rA(ctx->opcode)); \ rd = gen_avr_ptr(rD(ctx->opcode)); \ - st_six = tcg_const_i32(rB(ctx->opcode)); \ + st_six = tcg_constant_i32(rB(ctx->opcode)); \ gen_helper_##op(rd, ra, st_six); \ - tcg_temp_free_ptr(ra); \ - tcg_temp_free_ptr(rd); \ - tcg_temp_free_i32(st_six); \ } VSHASIGMA(vshasigmaw) @@ -1559,6 +2735,636 @@ GEN_VXFORM3(vpermxor, 22, 0xFF) GEN_VXFORM_DUAL(vsldoi, PPC_ALTIVEC, PPC_NONE, vpermxor, PPC_NONE, PPC2_ALTIVEC_207) +static bool trans_VCFUGED(DisasContext *ctx, arg_VX *a) +{ + static const GVecGen3 g = { + .fni8 = gen_helper_CFUGED, + .vece = MO_64, + }; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16, &g); + + return true; +} + +static bool trans_VCLZDM(DisasContext *ctx, arg_VX *a) +{ + static const GVecGen3i g = { + .fni8 = do_cntzdm, + .vece = MO_64, + }; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_3i(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16, false, &g); + + return true; +} + +static bool trans_VCTZDM(DisasContext *ctx, arg_VX *a) +{ + static const GVecGen3i g = { + .fni8 = do_cntzdm, + .vece = MO_64, + }; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_3i(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16, true, &g); + + return true; +} + +static bool trans_VPDEPD(DisasContext *ctx, arg_VX *a) +{ + static const GVecGen3 g = { + .fni8 = gen_helper_PDEPD, + .vece = MO_64, + }; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16, &g); + + return true; +} + +static bool trans_VPEXTD(DisasContext *ctx, arg_VX *a) +{ + static const GVecGen3 g = { + .fni8 = gen_helper_PEXTD, + .vece = MO_64, + }; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16, &g); + + return true; +} + +static bool trans_VMSUMUDM(DisasContext *ctx, arg_VA *a) +{ + TCGv_i64 rl, rh, src1, src2; + int dw; + + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VECTOR(ctx); + + rh = tcg_temp_new_i64(); + rl = tcg_temp_new_i64(); + src1 = tcg_temp_new_i64(); + src2 = tcg_temp_new_i64(); + + get_avr64(rl, a->rc, false); + get_avr64(rh, a->rc, true); + + for (dw = 0; dw < 2; dw++) { + get_avr64(src1, a->vra, dw); + get_avr64(src2, a->vrb, dw); + tcg_gen_mulu2_i64(src1, src2, src1, src2); + tcg_gen_add2_i64(rl, rh, rl, rh, src1, src2); + } + + set_avr64(a->vrt, rl, false); + set_avr64(a->vrt, rh, true); + return true; +} + +static bool trans_VMSUMCUD(DisasContext *ctx, arg_VA *a) +{ + TCGv_i64 tmp0, tmp1, prod1h, prod1l, prod0h, prod0l, zero; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + tmp0 = tcg_temp_new_i64(); + tmp1 = tcg_temp_new_i64(); + prod1h = tcg_temp_new_i64(); + prod1l = tcg_temp_new_i64(); + prod0h = tcg_temp_new_i64(); + prod0l = tcg_temp_new_i64(); + zero = tcg_constant_i64(0); + + /* prod1 = vsr[vra+32].dw[1] * vsr[vrb+32].dw[1] */ + get_avr64(tmp0, a->vra, false); + get_avr64(tmp1, a->vrb, false); + tcg_gen_mulu2_i64(prod1l, prod1h, tmp0, tmp1); + + /* prod0 = vsr[vra+32].dw[0] * vsr[vrb+32].dw[0] */ + get_avr64(tmp0, a->vra, true); + get_avr64(tmp1, a->vrb, true); + tcg_gen_mulu2_i64(prod0l, prod0h, tmp0, tmp1); + + /* Sum lower 64-bits elements */ + get_avr64(tmp1, a->rc, false); + tcg_gen_add2_i64(tmp1, tmp0, tmp1, zero, prod1l, zero); + tcg_gen_add2_i64(tmp1, tmp0, tmp1, tmp0, prod0l, zero); + + /* + * Discard lower 64-bits, leaving the carry into bit 64. + * Then sum the higher 64-bit elements. + */ + get_avr64(tmp1, a->rc, true); + tcg_gen_add2_i64(tmp1, tmp0, tmp0, zero, tmp1, zero); + tcg_gen_add2_i64(tmp1, tmp0, tmp1, tmp0, prod1h, zero); + tcg_gen_add2_i64(tmp1, tmp0, tmp1, tmp0, prod0h, zero); + + /* Discard 64 more bits to complete the CHOP128(temp >> 128) */ + set_avr64(a->vrt, tmp0, false); + set_avr64(a->vrt, zero, true); + return true; +} + +static bool do_vx_helper(DisasContext *ctx, arg_VX *a, + void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr)) +{ + TCGv_ptr ra, rb, rd; + REQUIRE_VECTOR(ctx); + + ra = gen_avr_ptr(a->vra); + rb = gen_avr_ptr(a->vrb); + rd = gen_avr_ptr(a->vrt); + gen_helper(rd, ra, rb); + return true; +} + +TRANS_FLAGS2(ALTIVEC_207, VADDCUQ, do_vx_helper, gen_helper_VADDCUQ) +TRANS_FLAGS2(ALTIVEC_207, VADDUQM, do_vx_helper, gen_helper_VADDUQM) + +TRANS_FLAGS2(ALTIVEC_207, VPMSUMD, do_vx_helper, gen_helper_VPMSUMD) + +TRANS_FLAGS2(ALTIVEC_207, VSUBCUQ, do_vx_helper, gen_helper_VSUBCUQ) +TRANS_FLAGS2(ALTIVEC_207, VSUBUQM, do_vx_helper, gen_helper_VSUBUQM) + +static void gen_VADDCUW_vec(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +{ + tcg_gen_not_vec(vece, a, a); + tcg_gen_cmp_vec(TCG_COND_LTU, vece, t, a, b); + tcg_gen_and_vec(vece, t, t, tcg_constant_vec_matching(t, vece, 1)); +} + +static void gen_VADDCUW_i32(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +{ + tcg_gen_not_i32(a, a); + tcg_gen_setcond_i32(TCG_COND_LTU, t, a, b); +} + +static void gen_VSUBCUW_vec(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +{ + tcg_gen_cmp_vec(TCG_COND_GEU, vece, t, a, b); + tcg_gen_and_vec(vece, t, t, tcg_constant_vec_matching(t, vece, 1)); +} + +static void gen_VSUBCUW_i32(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +{ + tcg_gen_setcond_i32(TCG_COND_GEU, t, a, b); +} + +static bool do_vx_vaddsubcuw(DisasContext *ctx, arg_VX *a, int add) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_cmp_vec, 0 + }; + + static const GVecGen3 op[] = { + { + .fniv = gen_VSUBCUW_vec, + .fni4 = gen_VSUBCUW_i32, + .opt_opc = vecop_list, + .vece = MO_32 + }, + { + .fniv = gen_VADDCUW_vec, + .fni4 = gen_VADDCUW_i32, + .opt_opc = vecop_list, + .vece = MO_32 + }, + }; + + REQUIRE_INSNS_FLAGS(ctx, ALTIVEC); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16, &op[add]); + + return true; +} + +TRANS(VSUBCUW, do_vx_vaddsubcuw, 0) +TRANS(VADDCUW, do_vx_vaddsubcuw, 1) + +static bool do_vx_vmuleo(DisasContext *ctx, arg_VX *a, bool even, + void (*gen_mul)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64)) +{ + TCGv_i64 vra, vrb, vrt0, vrt1; + REQUIRE_VECTOR(ctx); + + vra = tcg_temp_new_i64(); + vrb = tcg_temp_new_i64(); + vrt0 = tcg_temp_new_i64(); + vrt1 = tcg_temp_new_i64(); + + get_avr64(vra, a->vra, even); + get_avr64(vrb, a->vrb, even); + gen_mul(vrt0, vrt1, vra, vrb); + set_avr64(a->vrt, vrt0, false); + set_avr64(a->vrt, vrt1, true); + return true; +} + +static bool trans_VMULLD(DisasContext *ctx, arg_VX *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_mul(MO_64, avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16); + + return true; +} + +TRANS_FLAGS(ALTIVEC, VMULESB, do_vx_helper, gen_helper_VMULESB) +TRANS_FLAGS(ALTIVEC, VMULOSB, do_vx_helper, gen_helper_VMULOSB) +TRANS_FLAGS(ALTIVEC, VMULEUB, do_vx_helper, gen_helper_VMULEUB) +TRANS_FLAGS(ALTIVEC, VMULOUB, do_vx_helper, gen_helper_VMULOUB) +TRANS_FLAGS(ALTIVEC, VMULESH, do_vx_helper, gen_helper_VMULESH) +TRANS_FLAGS(ALTIVEC, VMULOSH, do_vx_helper, gen_helper_VMULOSH) +TRANS_FLAGS(ALTIVEC, VMULEUH, do_vx_helper, gen_helper_VMULEUH) +TRANS_FLAGS(ALTIVEC, VMULOUH, do_vx_helper, gen_helper_VMULOUH) +TRANS_FLAGS2(ALTIVEC_207, VMULESW, do_vx_helper, gen_helper_VMULESW) +TRANS_FLAGS2(ALTIVEC_207, VMULOSW, do_vx_helper, gen_helper_VMULOSW) +TRANS_FLAGS2(ALTIVEC_207, VMULEUW, do_vx_helper, gen_helper_VMULEUW) +TRANS_FLAGS2(ALTIVEC_207, VMULOUW, do_vx_helper, gen_helper_VMULOUW) +TRANS_FLAGS2(ISA310, VMULESD, do_vx_vmuleo, true , tcg_gen_muls2_i64) +TRANS_FLAGS2(ISA310, VMULOSD, do_vx_vmuleo, false, tcg_gen_muls2_i64) +TRANS_FLAGS2(ISA310, VMULEUD, do_vx_vmuleo, true , tcg_gen_mulu2_i64) +TRANS_FLAGS2(ISA310, VMULOUD, do_vx_vmuleo, false, tcg_gen_mulu2_i64) + +static void do_vx_vmulhw_i64(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b, bool sign) +{ + TCGv_i64 hh, lh, temp; + + hh = tcg_temp_new_i64(); + lh = tcg_temp_new_i64(); + temp = tcg_temp_new_i64(); + + if (sign) { + tcg_gen_ext32s_i64(lh, a); + tcg_gen_ext32s_i64(temp, b); + } else { + tcg_gen_ext32u_i64(lh, a); + tcg_gen_ext32u_i64(temp, b); + } + tcg_gen_mul_i64(lh, lh, temp); + + if (sign) { + tcg_gen_sari_i64(hh, a, 32); + tcg_gen_sari_i64(temp, b, 32); + } else { + tcg_gen_shri_i64(hh, a, 32); + tcg_gen_shri_i64(temp, b, 32); + } + tcg_gen_mul_i64(hh, hh, temp); + + tcg_gen_shri_i64(lh, lh, 32); + tcg_gen_deposit_i64(t, hh, lh, 0, 32); +} + +static void do_vx_vmulhd_i64(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b, bool sign) +{ + TCGv_i64 tlow; + + tlow = tcg_temp_new_i64(); + if (sign) { + tcg_gen_muls2_i64(tlow, t, a, b); + } else { + tcg_gen_mulu2_i64(tlow, t, a, b); + } +} + +static bool do_vx_mulh(DisasContext *ctx, arg_VX *a, bool sign, + void (*func)(TCGv_i64, TCGv_i64, TCGv_i64, bool)) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VECTOR(ctx); + + TCGv_i64 vra, vrb, vrt; + int i; + + vra = tcg_temp_new_i64(); + vrb = tcg_temp_new_i64(); + vrt = tcg_temp_new_i64(); + + for (i = 0; i < 2; i++) { + get_avr64(vra, a->vra, i); + get_avr64(vrb, a->vrb, i); + get_avr64(vrt, a->vrt, i); + + func(vrt, vra, vrb, sign); + + set_avr64(a->vrt, vrt, i); + } + return true; +} + +TRANS(VMULHSW, do_vx_mulh, true , do_vx_vmulhw_i64) +TRANS(VMULHSD, do_vx_mulh, true , do_vx_vmulhd_i64) +TRANS(VMULHUW, do_vx_mulh, false, do_vx_vmulhw_i64) +TRANS(VMULHUD, do_vx_mulh, false, do_vx_vmulhd_i64) + +static void do_vavg(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b, + void (*gen_shr_vec)(unsigned, TCGv_vec, TCGv_vec, int64_t)) +{ + TCGv_vec tmp = tcg_temp_new_vec_matching(t); + tcg_gen_or_vec(vece, tmp, a, b); + tcg_gen_and_vec(vece, tmp, tmp, tcg_constant_vec_matching(t, vece, 1)); + gen_shr_vec(vece, a, a, 1); + gen_shr_vec(vece, b, b, 1); + tcg_gen_add_vec(vece, t, a, b); + tcg_gen_add_vec(vece, t, t, tmp); +} + +QEMU_FLATTEN +static void gen_vavgu(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +{ + do_vavg(vece, t, a, b, tcg_gen_shri_vec); +} + +QEMU_FLATTEN +static void gen_vavgs(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +{ + do_vavg(vece, t, a, b, tcg_gen_sari_vec); +} + +static bool do_vx_vavg(DisasContext *ctx, arg_VX *a, int sign, int vece) +{ + static const TCGOpcode vecop_list_s[] = { + INDEX_op_add_vec, INDEX_op_sari_vec, 0 + }; + static const TCGOpcode vecop_list_u[] = { + INDEX_op_add_vec, INDEX_op_shri_vec, 0 + }; + + static const GVecGen3 op[2][3] = { + { + { + .fniv = gen_vavgu, + .fno = gen_helper_VAVGUB, + .opt_opc = vecop_list_u, + .vece = MO_8 + }, + { + .fniv = gen_vavgu, + .fno = gen_helper_VAVGUH, + .opt_opc = vecop_list_u, + .vece = MO_16 + }, + { + .fniv = gen_vavgu, + .fno = gen_helper_VAVGUW, + .opt_opc = vecop_list_u, + .vece = MO_32 + }, + }, + { + { + .fniv = gen_vavgs, + .fno = gen_helper_VAVGSB, + .opt_opc = vecop_list_s, + .vece = MO_8 + }, + { + .fniv = gen_vavgs, + .fno = gen_helper_VAVGSH, + .opt_opc = vecop_list_s, + .vece = MO_16 + }, + { + .fniv = gen_vavgs, + .fno = gen_helper_VAVGSW, + .opt_opc = vecop_list_s, + .vece = MO_32 + }, + }, + }; + + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16, &op[sign][vece]); + + + return true; +} + + +TRANS_FLAGS(ALTIVEC, VAVGSB, do_vx_vavg, 1, MO_8) +TRANS_FLAGS(ALTIVEC, VAVGSH, do_vx_vavg, 1, MO_16) +TRANS_FLAGS(ALTIVEC, VAVGSW, do_vx_vavg, 1, MO_32) +TRANS_FLAGS(ALTIVEC, VAVGUB, do_vx_vavg, 0, MO_8) +TRANS_FLAGS(ALTIVEC, VAVGUH, do_vx_vavg, 0, MO_16) +TRANS_FLAGS(ALTIVEC, VAVGUW, do_vx_vavg, 0, MO_32) + +static void gen_vabsdu(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +{ + tcg_gen_umax_vec(vece, t, a, b); + tcg_gen_umin_vec(vece, a, a, b); + tcg_gen_sub_vec(vece, t, t, a); +} + +static bool do_vabsdu(DisasContext *ctx, arg_VX *a, const int vece) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_umax_vec, INDEX_op_umin_vec, INDEX_op_sub_vec, 0 + }; + + static const GVecGen3 op[] = { + { + .fniv = gen_vabsdu, + .fno = gen_helper_VABSDUB, + .opt_opc = vecop_list, + .vece = MO_8 + }, + { + .fniv = gen_vabsdu, + .fno = gen_helper_VABSDUH, + .opt_opc = vecop_list, + .vece = MO_16 + }, + { + .fniv = gen_vabsdu, + .fno = gen_helper_VABSDUW, + .opt_opc = vecop_list, + .vece = MO_32 + }, + }; + + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16, &op[vece]); + + return true; +} + +TRANS_FLAGS2(ISA300, VABSDUB, do_vabsdu, MO_8) +TRANS_FLAGS2(ISA300, VABSDUH, do_vabsdu, MO_16) +TRANS_FLAGS2(ISA300, VABSDUW, do_vabsdu, MO_32) + +static bool do_vdiv_vmod(DisasContext *ctx, arg_VX *a, const int vece, + void (*func_32)(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b), + void (*func_64)(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b)) +{ + const GVecGen3 op = { + .fni4 = func_32, + .fni8 = func_64, + .vece = vece + }; + + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16, &op); + + return true; +} + +#define DIVU32(NAME, DIV) \ +static void NAME(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) \ +{ \ + TCGv_i32 zero = tcg_constant_i32(0); \ + TCGv_i32 one = tcg_constant_i32(1); \ + tcg_gen_movcond_i32(TCG_COND_EQ, b, b, zero, one, b); \ + DIV(t, a, b); \ +} + +#define DIVS32(NAME, DIV) \ +static void NAME(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) \ +{ \ + TCGv_i32 t0 = tcg_temp_new_i32(); \ + TCGv_i32 t1 = tcg_temp_new_i32(); \ + tcg_gen_setcondi_i32(TCG_COND_EQ, t0, a, INT32_MIN); \ + tcg_gen_setcondi_i32(TCG_COND_EQ, t1, b, -1); \ + tcg_gen_and_i32(t0, t0, t1); \ + tcg_gen_setcondi_i32(TCG_COND_EQ, t1, b, 0); \ + tcg_gen_or_i32(t0, t0, t1); \ + tcg_gen_movi_i32(t1, 0); \ + tcg_gen_movcond_i32(TCG_COND_NE, b, t0, t1, t0, b); \ + DIV(t, a, b); \ +} + +#define DIVU64(NAME, DIV) \ +static void NAME(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) \ +{ \ + TCGv_i64 zero = tcg_constant_i64(0); \ + TCGv_i64 one = tcg_constant_i64(1); \ + tcg_gen_movcond_i64(TCG_COND_EQ, b, b, zero, one, b); \ + DIV(t, a, b); \ +} + +#define DIVS64(NAME, DIV) \ +static void NAME(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) \ +{ \ + TCGv_i64 t0 = tcg_temp_new_i64(); \ + TCGv_i64 t1 = tcg_temp_new_i64(); \ + tcg_gen_setcondi_i64(TCG_COND_EQ, t0, a, INT64_MIN); \ + tcg_gen_setcondi_i64(TCG_COND_EQ, t1, b, -1); \ + tcg_gen_and_i64(t0, t0, t1); \ + tcg_gen_setcondi_i64(TCG_COND_EQ, t1, b, 0); \ + tcg_gen_or_i64(t0, t0, t1); \ + tcg_gen_movi_i64(t1, 0); \ + tcg_gen_movcond_i64(TCG_COND_NE, b, t0, t1, t0, b); \ + DIV(t, a, b); \ +} + +DIVS32(do_divsw, tcg_gen_div_i32) +DIVU32(do_divuw, tcg_gen_divu_i32) +DIVS64(do_divsd, tcg_gen_div_i64) +DIVU64(do_divud, tcg_gen_divu_i64) + +TRANS_FLAGS2(ISA310, VDIVSW, do_vdiv_vmod, MO_32, do_divsw, NULL) +TRANS_FLAGS2(ISA310, VDIVUW, do_vdiv_vmod, MO_32, do_divuw, NULL) +TRANS_FLAGS2(ISA310, VDIVSD, do_vdiv_vmod, MO_64, NULL, do_divsd) +TRANS_FLAGS2(ISA310, VDIVUD, do_vdiv_vmod, MO_64, NULL, do_divud) +TRANS_FLAGS2(ISA310, VDIVSQ, do_vx_helper, gen_helper_VDIVSQ) +TRANS_FLAGS2(ISA310, VDIVUQ, do_vx_helper, gen_helper_VDIVUQ) + +static void do_dives_i32(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +{ + TCGv_i64 val1, val2; + + val1 = tcg_temp_new_i64(); + val2 = tcg_temp_new_i64(); + + tcg_gen_ext_i32_i64(val1, a); + tcg_gen_ext_i32_i64(val2, b); + + /* (a << 32)/b */ + tcg_gen_shli_i64(val1, val1, 32); + tcg_gen_div_i64(val1, val1, val2); + + /* if quotient doesn't fit in 32 bits the result is undefined */ + tcg_gen_extrl_i64_i32(t, val1); +} + +static void do_diveu_i32(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +{ + TCGv_i64 val1, val2; + + val1 = tcg_temp_new_i64(); + val2 = tcg_temp_new_i64(); + + tcg_gen_extu_i32_i64(val1, a); + tcg_gen_extu_i32_i64(val2, b); + + /* (a << 32)/b */ + tcg_gen_shli_i64(val1, val1, 32); + tcg_gen_divu_i64(val1, val1, val2); + + /* if quotient doesn't fit in 32 bits the result is undefined */ + tcg_gen_extrl_i64_i32(t, val1); +} + +DIVS32(do_divesw, do_dives_i32) +DIVU32(do_diveuw, do_diveu_i32) + +DIVS32(do_modsw, tcg_gen_rem_i32) +DIVU32(do_moduw, tcg_gen_remu_i32) +DIVS64(do_modsd, tcg_gen_rem_i64) +DIVU64(do_modud, tcg_gen_remu_i64) + +TRANS_FLAGS2(ISA310, VDIVESW, do_vdiv_vmod, MO_32, do_divesw, NULL) +TRANS_FLAGS2(ISA310, VDIVEUW, do_vdiv_vmod, MO_32, do_diveuw, NULL) +TRANS_FLAGS2(ISA310, VDIVESD, do_vx_helper, gen_helper_VDIVESD) +TRANS_FLAGS2(ISA310, VDIVEUD, do_vx_helper, gen_helper_VDIVEUD) +TRANS_FLAGS2(ISA310, VDIVESQ, do_vx_helper, gen_helper_VDIVESQ) +TRANS_FLAGS2(ISA310, VDIVEUQ, do_vx_helper, gen_helper_VDIVEUQ) + +TRANS_FLAGS2(ISA310, VMODSW, do_vdiv_vmod, MO_32, do_modsw , NULL) +TRANS_FLAGS2(ISA310, VMODUW, do_vdiv_vmod, MO_32, do_moduw, NULL) +TRANS_FLAGS2(ISA310, VMODSD, do_vdiv_vmod, MO_64, NULL, do_modsd) +TRANS_FLAGS2(ISA310, VMODUD, do_vdiv_vmod, MO_64, NULL, do_modud) +TRANS_FLAGS2(ISA310, VMODSQ, do_vx_helper, gen_helper_VMODSQ) +TRANS_FLAGS2(ISA310, VMODUQ, do_vx_helper, gen_helper_VMODUQ) + +#undef DIVS32 +#undef DIVU32 +#undef DIVS64 +#undef DIVU64 + #undef GEN_VR_LDX #undef GEN_VR_STX #undef GEN_VR_LVE diff --git a/target/ppc/translate/vmx-ops.c.inc b/target/ppc/translate/vmx-ops.c.inc index f3f4855111..33fec8aca4 100644 --- a/target/ppc/translate/vmx-ops.c.inc +++ b/target/ppc/translate/vmx-ops.c.inc @@ -83,12 +83,6 @@ GEN_VXFORM(vminsb, 1, 12), GEN_VXFORM(vminsh, 1, 13), GEN_VXFORM(vminsw, 1, 14), GEN_VXFORM_207(vminsd, 1, 15), -GEN_VXFORM_DUAL(vavgub, vabsdub, 1, 16, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM_DUAL(vavguh, vabsduh, 1, 17, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM_DUAL(vavguw, vabsduw, 1, 18, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM(vavgsb, 1, 20), -GEN_VXFORM(vavgsh, 1, 21), -GEN_VXFORM(vavgsw, 1, 22), GEN_VXFORM(vmrghb, 6, 0), GEN_VXFORM(vmrghh, 6, 1), GEN_VXFORM(vmrghw, 6, 2), @@ -101,43 +95,13 @@ GEN_VXFORM_DUAL(vmrgow, vextuwlx, 6, 26, PPC_NONE, PPC2_ALTIVEC_207), GEN_VXFORM_300(vextubrx, 6, 28), GEN_VXFORM_300(vextuhrx, 6, 29), GEN_VXFORM_DUAL(vmrgew, vextuwrx, 6, 30, PPC_NONE, PPC2_ALTIVEC_207), -GEN_VXFORM(vmuloub, 4, 0), -GEN_VXFORM(vmulouh, 4, 1), -GEN_VXFORM_DUAL(vmulouw, vmuluwm, 4, 2, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM(vmulosb, 4, 4), -GEN_VXFORM(vmulosh, 4, 5), -GEN_VXFORM_207(vmulosw, 4, 6), -GEN_VXFORM_310(vmulld, 4, 7), -GEN_VXFORM(vmuleub, 4, 8), -GEN_VXFORM(vmuleuh, 4, 9), -GEN_VXFORM_DUAL(vmuleuw, vmulhuw, 4, 10, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM_310(vmulhud, 4, 11), -GEN_VXFORM(vmulesb, 4, 12), -GEN_VXFORM(vmulesh, 4, 13), -GEN_VXFORM_DUAL(vmulesw, vmulhsw, 4, 14, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM_310(vmulhsd, 4, 15), -GEN_VXFORM(vslb, 2, 4), -GEN_VXFORM(vslh, 2, 5), -GEN_VXFORM_DUAL(vslw, vrlwnm, 2, 6, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM_207(vsld, 2, 23), -GEN_VXFORM(vsrb, 2, 8), -GEN_VXFORM(vsrh, 2, 9), -GEN_VXFORM(vsrw, 2, 10), -GEN_VXFORM_207(vsrd, 2, 27), -GEN_VXFORM(vsrab, 2, 12), -GEN_VXFORM(vsrah, 2, 13), -GEN_VXFORM(vsraw, 2, 14), -GEN_VXFORM_207(vsrad, 2, 15), +GEN_VXFORM_207(vmuluwm, 4, 2), GEN_VXFORM_300(vsrv, 2, 28), GEN_VXFORM_300(vslv, 2, 29), GEN_VXFORM(vslo, 6, 16), GEN_VXFORM(vsro, 6, 17), -GEN_VXFORM(vaddcuw, 0, 6), -GEN_HANDLER_E_2(vprtybw, 0x4, 0x1, 0x18, 8, 0, PPC_NONE, PPC2_ISA300), -GEN_HANDLER_E_2(vprtybd, 0x4, 0x1, 0x18, 9, 0, PPC_NONE, PPC2_ISA300), -GEN_HANDLER_E_2(vprtybq, 0x4, 0x1, 0x18, 10, 0, PPC_NONE, PPC2_ISA300), -GEN_VXFORM_DUAL(vsubcuw, xpnd04_1, 0, 22, PPC_ALTIVEC, PPC_NONE), +GEN_VXFORM(xpnd04_1, 0, 22), GEN_VXFORM_300(bcdsr, 0, 23), GEN_VXFORM_300(bcdsr, 0, 31), GEN_VXFORM_DUAL(vaddubs, vmul10uq, 0, 8, PPC_ALTIVEC, PPC_NONE), @@ -152,17 +116,9 @@ GEN_VXFORM(vsubuws, 0, 26), GEN_VXFORM_DUAL(vsubsbs, bcdtrunc, 0, 28, PPC_ALTIVEC, PPC2_ISA300), GEN_VXFORM(vsubshs, 0, 29), GEN_VXFORM_DUAL(vsubsws, xpnd04_2, 0, 30, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM_207(vadduqm, 0, 4), -GEN_VXFORM_207(vaddcuq, 0, 5), -GEN_VXFORM_DUAL(vaddeuqm, vaddecuq, 30, 0xFF, PPC_NONE, PPC2_ALTIVEC_207), -GEN_VXFORM_DUAL(vsubuqm, bcdtrunc, 0, 20, PPC2_ALTIVEC_207, PPC2_ISA300), -GEN_VXFORM_DUAL(vsubcuq, bcdutrunc, 0, 21, PPC2_ALTIVEC_207, PPC2_ISA300), -GEN_VXFORM_DUAL(vsubeuqm, vsubecuq, 31, 0xFF, PPC_NONE, PPC2_ALTIVEC_207), -GEN_VXFORM(vrlb, 2, 0), -GEN_VXFORM(vrlh, 2, 1), -GEN_VXFORM_DUAL(vrlw, vrlwmi, 2, 2, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM_DUAL(vrld, vrldmi, 2, 3, PPC_NONE, PPC2_ALTIVEC_207), -GEN_VXFORM_DUAL(vsl, vrldnm, 2, 7, PPC_ALTIVEC, PPC_NONE), +GEN_VXFORM_300(bcdtrunc, 0, 20), +GEN_VXFORM_300(bcdutrunc, 0, 21), +GEN_VXFORM(vsl, 2, 7), GEN_VXFORM(vsr, 2, 11), GEN_VXFORM(vpkuhum, 7, 0), GEN_VXFORM(vpkuwum, 7, 1), @@ -198,22 +154,10 @@ GEN_HANDLER2_E(name, str, 0x4, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ISA300), GEN_VXRFORM1_300(name, name, #name, opc2, opc3) \ GEN_VXRFORM1_300(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4))) -GEN_VXRFORM_300(vcmpnezb, 3, 4) -GEN_VXRFORM_300(vcmpnezh, 3, 5) -GEN_VXRFORM_300(vcmpnezw, 3, 6) -GEN_VXRFORM(vcmpgtsb, 3, 12) -GEN_VXRFORM(vcmpgtsh, 3, 13) -GEN_VXRFORM(vcmpgtsw, 3, 14) -GEN_VXRFORM(vcmpgtub, 3, 8) -GEN_VXRFORM(vcmpgtuh, 3, 9) -GEN_VXRFORM(vcmpgtuw, 3, 10) -GEN_VXRFORM_DUAL(vcmpeqfp, vcmpequd, 3, 3, PPC_ALTIVEC, PPC_NONE) +GEN_VXRFORM(vcmpeqfp, 3, 3) GEN_VXRFORM(vcmpgefp, 3, 7) -GEN_VXRFORM_DUAL(vcmpgtfp, vcmpgtud, 3, 11, PPC_ALTIVEC, PPC_NONE) -GEN_VXRFORM_DUAL(vcmpbfp, vcmpgtsd, 3, 15, PPC_ALTIVEC, PPC_NONE) -GEN_VXRFORM_DUAL(vcmpequb, vcmpneb, 3, 0, PPC_ALTIVEC, PPC_NONE) -GEN_VXRFORM_DUAL(vcmpequh, vcmpneh, 3, 1, PPC_ALTIVEC, PPC_NONE) -GEN_VXRFORM_DUAL(vcmpequw, vcmpnew, 3, 2, PPC_ALTIVEC, PPC_NONE) +GEN_VXRFORM(vcmpgtfp, 3, 11) +GEN_VXRFORM(vcmpbfp, 3, 15) #define GEN_VXFORM_DUAL_INV(name0, name1, opc2, opc3, inval0, inval1, type) \ GEN_OPCODE_DUAL(name0##_##name1, 0x04, opc2, opc3, inval0, inval1, type, \ @@ -225,27 +169,15 @@ GEN_VXFORM_DUAL_INV(vsplth, vextractuh, 6, 9, 0x00000000, 0x100000, GEN_VXFORM_DUAL_INV(vspltw, vextractuw, 6, 10, 0x00000000, 0x100000, PPC_ALTIVEC), GEN_VXFORM_300_EXT(vextractd, 6, 11, 0x100000), -GEN_VXFORM_DUAL_INV(vspltisb, vinsertb, 6, 12, 0x00000000, 0x100000, - PPC_ALTIVEC), -GEN_VXFORM_DUAL_INV(vspltish, vinserth, 6, 13, 0x00000000, 0x100000, - PPC_ALTIVEC), -GEN_VXFORM_DUAL_INV(vspltisw, vinsertw, 6, 14, 0x00000000, 0x100000, - PPC_ALTIVEC), -GEN_VXFORM_300_EXT(vinsertd, 6, 15, 0x100000), -GEN_VXFORM_300_EO(vnegw, 0x01, 0x18, 0x06), -GEN_VXFORM_300_EO(vnegd, 0x01, 0x18, 0x07), -GEN_VXFORM_300_EO(vextsb2w, 0x01, 0x18, 0x10), -GEN_VXFORM_300_EO(vextsh2w, 0x01, 0x18, 0x11), -GEN_VXFORM_300_EO(vextsb2d, 0x01, 0x18, 0x18), -GEN_VXFORM_300_EO(vextsh2d, 0x01, 0x18, 0x19), -GEN_VXFORM_300_EO(vextsw2d, 0x01, 0x18, 0x1A), +GEN_VXFORM(vspltisb, 6, 12), +GEN_VXFORM(vspltish, 6, 13), +GEN_VXFORM(vspltisw, 6, 14), GEN_VXFORM_300_EO(vctzb, 0x01, 0x18, 0x1C), GEN_VXFORM_300_EO(vctzh, 0x01, 0x18, 0x1D), GEN_VXFORM_300_EO(vctzw, 0x01, 0x18, 0x1E), GEN_VXFORM_300_EO(vctzd, 0x01, 0x18, 0x1F), GEN_VXFORM_300_EO(vclzlsbb, 0x01, 0x18, 0x0), GEN_VXFORM_300_EO(vctzlsbb, 0x01, 0x18, 0x1), -GEN_VXFORM_300(vpermr, 0x1D, 0xFF), #define GEN_VXFORM_NOA(name, opc2, opc3) \ GEN_HANDLER(name, 0x04, opc2, opc3, 0x001f0000, PPC_ALTIVEC) @@ -273,14 +205,8 @@ GEN_VXFORM_UIMM(vcfsx, 5, 13), GEN_VXFORM_UIMM(vctuxs, 5, 14), GEN_VXFORM_UIMM(vctsxs, 5, 15), - #define GEN_VAFORM_PAIRED(name0, name1, opc2) \ GEN_HANDLER(name0##_##name1, 0x04, opc2, 0xFF, 0x00000000, PPC_ALTIVEC) -GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16), -GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18), -GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19), -GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20), -GEN_VAFORM_PAIRED(vsel, vperm, 21), GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23), GEN_VXFORM_DUAL(vclzb, vpopcntb, 1, 28, PPC_NONE, PPC2_ALTIVEC_207), @@ -294,7 +220,6 @@ GEN_VXFORM_207(vgbbd, 6, 20), GEN_VXFORM_207(vpmsumb, 4, 16), GEN_VXFORM_207(vpmsumh, 4, 17), GEN_VXFORM_207(vpmsumw, 4, 18), -GEN_VXFORM_207(vpmsumd, 4, 19), GEN_VXFORM_207(vsbox, 4, 23), diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index 57a7f73bba..0266f09119 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -1,29 +1,26 @@ /*** VSX extension ***/ -static inline void get_cpu_vsrh(TCGv_i64 dst, int n) +static inline void get_cpu_vsr(TCGv_i64 dst, int n, bool high) { - tcg_gen_ld_i64(dst, cpu_env, vsr64_offset(n, true)); + tcg_gen_ld_i64(dst, tcg_env, vsr64_offset(n, high)); } -static inline void get_cpu_vsrl(TCGv_i64 dst, int n) +static inline void set_cpu_vsr(int n, TCGv_i64 src, bool high) { - tcg_gen_ld_i64(dst, cpu_env, vsr64_offset(n, false)); + tcg_gen_st_i64(src, tcg_env, vsr64_offset(n, high)); } -static inline void set_cpu_vsrh(int n, TCGv_i64 src) -{ - tcg_gen_st_i64(src, cpu_env, vsr64_offset(n, true)); -} - -static inline void set_cpu_vsrl(int n, TCGv_i64 src) +static inline TCGv_ptr gen_vsr_ptr(int reg) { - tcg_gen_st_i64(src, cpu_env, vsr64_offset(n, false)); + TCGv_ptr r = tcg_temp_new_ptr(); + tcg_gen_addi_ptr(r, tcg_env, vsr_full_offset(reg)); + return r; } -static inline TCGv_ptr gen_vsr_ptr(int reg) +static inline TCGv_ptr gen_acc_ptr(int reg) { TCGv_ptr r = tcg_temp_new_ptr(); - tcg_gen_addi_ptr(r, cpu_env, vsr_full_offset(reg)); + tcg_gen_addi_ptr(r, tcg_env, acc_full_offset(reg)); return r; } @@ -41,10 +38,8 @@ static void gen_##name(DisasContext *ctx) \ EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ gen_qemu_##operation(ctx, t0, EA); \ - set_cpu_vsrh(xT(ctx->opcode), t0); \ + set_cpu_vsr(xT(ctx->opcode), t0, true); \ /* NOTE: cpu_vsrl is undefined */ \ - tcg_temp_free(EA); \ - tcg_temp_free_i64(t0); \ } VSX_LOAD_SCALAR(lxsdx, ld64_i64) @@ -67,12 +62,10 @@ static void gen_lxvd2x(DisasContext *ctx) EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); gen_qemu_ld64_i64(ctx, t0, EA); - set_cpu_vsrh(xT(ctx->opcode), t0); + set_cpu_vsr(xT(ctx->opcode), t0, true); tcg_gen_addi_tl(EA, EA, 8); gen_qemu_ld64_i64(ctx, t0, EA); - set_cpu_vsrl(xT(ctx->opcode), t0); - tcg_temp_free(EA); - tcg_temp_free_i64(t0); + set_cpu_vsr(xT(ctx->opcode), t0, false); } static void gen_lxvw4x(DisasContext *ctx) @@ -95,25 +88,20 @@ static void gen_lxvw4x(DisasContext *ctx) TCGv_i64 t0 = tcg_temp_new_i64(); TCGv_i64 t1 = tcg_temp_new_i64(); - tcg_gen_qemu_ld_i64(t0, EA, ctx->mem_idx, MO_LEQ); + tcg_gen_qemu_ld_i64(t0, EA, ctx->mem_idx, MO_LEUQ); tcg_gen_shri_i64(t1, t0, 32); tcg_gen_deposit_i64(xth, t1, t0, 32, 32); tcg_gen_addi_tl(EA, EA, 8); - tcg_gen_qemu_ld_i64(t0, EA, ctx->mem_idx, MO_LEQ); + tcg_gen_qemu_ld_i64(t0, EA, ctx->mem_idx, MO_LEUQ); tcg_gen_shri_i64(t1, t0, 32); tcg_gen_deposit_i64(xtl, t1, t0, 32, 32); - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); } else { - tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEUQ); tcg_gen_addi_tl(EA, EA, 8); - tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEUQ); } - set_cpu_vsrh(xT(ctx->opcode), xth); - set_cpu_vsrl(xT(ctx->opcode), xtl); - tcg_temp_free(EA); - tcg_temp_free_i64(xth); - tcg_temp_free_i64(xtl); + set_cpu_vsr(xT(ctx->opcode), xth, true); + set_cpu_vsr(xT(ctx->opcode), xtl, false); } static void gen_lxvwsx(DisasContext *ctx) @@ -141,9 +129,6 @@ static void gen_lxvwsx(DisasContext *ctx) data = tcg_temp_new_i32(); tcg_gen_qemu_ld_i32(data, EA, ctx->mem_idx, DEF_MEMOP(MO_UL)); tcg_gen_gvec_dup_i32(MO_UL, vsr_full_offset(xT(ctx->opcode)), 16, 16, data); - - tcg_temp_free(EA); - tcg_temp_free_i32(data); } static void gen_lxvdsx(DisasContext *ctx) @@ -162,17 +147,14 @@ static void gen_lxvdsx(DisasContext *ctx) gen_addr_reg_index(ctx, EA); data = tcg_temp_new_i64(); - tcg_gen_qemu_ld_i64(data, EA, ctx->mem_idx, DEF_MEMOP(MO_Q)); - tcg_gen_gvec_dup_i64(MO_Q, vsr_full_offset(xT(ctx->opcode)), 16, 16, data); - - tcg_temp_free(EA); - tcg_temp_free_i64(data); + tcg_gen_qemu_ld_i64(data, EA, ctx->mem_idx, DEF_MEMOP(MO_UQ)); + tcg_gen_gvec_dup_i64(MO_UQ, vsr_full_offset(xT(ctx->opcode)), 16, 16, data); } static void gen_bswap16x8(TCGv_i64 outh, TCGv_i64 outl, TCGv_i64 inh, TCGv_i64 inl) { - TCGv_i64 mask = tcg_const_i64(0x00FF00FF00FF00FF); + TCGv_i64 mask = tcg_constant_i64(0x00FF00FF00FF00FF); TCGv_i64 t0 = tcg_temp_new_i64(); TCGv_i64 t1 = tcg_temp_new_i64(); @@ -189,10 +171,6 @@ static void gen_bswap16x8(TCGv_i64 outh, TCGv_i64 outl, tcg_gen_shri_i64(t1, inl, 8); tcg_gen_and_i64(t1, t1, mask); tcg_gen_or_i64(outl, t0, t1); - - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); - tcg_temp_free_i64(mask); } static void gen_bswap32x4(TCGv_i64 outh, TCGv_i64 outl, @@ -207,10 +185,8 @@ static void gen_bswap32x4(TCGv_i64 outh, TCGv_i64 outl, tcg_gen_deposit_i64(outh, outh, hi, 32, 32); tcg_gen_shri_i64(outl, lo, 32); tcg_gen_deposit_i64(outl, outl, lo, 32, 32); - - tcg_temp_free_i64(hi); - tcg_temp_free_i64(lo); } + static void gen_lxvh8x(DisasContext *ctx) { TCGv EA; @@ -227,17 +203,14 @@ static void gen_lxvh8x(DisasContext *ctx) EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); - tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEUQ); tcg_gen_addi_tl(EA, EA, 8); - tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEUQ); if (ctx->le_mode) { gen_bswap16x8(xth, xtl, xth, xtl); } - set_cpu_vsrh(xT(ctx->opcode), xth); - set_cpu_vsrl(xT(ctx->opcode), xtl); - tcg_temp_free(EA); - tcg_temp_free_i64(xth); - tcg_temp_free_i64(xtl); + set_cpu_vsr(xT(ctx->opcode), xth, true); + set_cpu_vsr(xT(ctx->opcode), xtl, false); } static void gen_lxvb16x(DisasContext *ctx) @@ -255,123 +228,12 @@ static void gen_lxvb16x(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); - tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_qemu_ld_i64(xth, EA, ctx->mem_idx, MO_BEUQ); tcg_gen_addi_tl(EA, EA, 8); - tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEQ); - set_cpu_vsrh(xT(ctx->opcode), xth); - set_cpu_vsrl(xT(ctx->opcode), xtl); - tcg_temp_free(EA); - tcg_temp_free_i64(xth); - tcg_temp_free_i64(xtl); -} - -#define VSX_VECTOR_LOAD(name, op, indexed) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - int xt; \ - TCGv EA; \ - TCGv_i64 xth; \ - TCGv_i64 xtl; \ - \ - if (indexed) { \ - xt = xT(ctx->opcode); \ - } else { \ - xt = DQxT(ctx->opcode); \ - } \ - \ - if (xt < 32) { \ - if (unlikely(!ctx->vsx_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VSXU); \ - return; \ - } \ - } else { \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - } \ - xth = tcg_temp_new_i64(); \ - xtl = tcg_temp_new_i64(); \ - gen_set_access_type(ctx, ACCESS_INT); \ - EA = tcg_temp_new(); \ - if (indexed) { \ - gen_addr_reg_index(ctx, EA); \ - } else { \ - gen_addr_imm_index(ctx, EA, 0x0F); \ - } \ - if (ctx->le_mode) { \ - tcg_gen_qemu_##op(xtl, EA, ctx->mem_idx, MO_LEQ); \ - set_cpu_vsrl(xt, xtl); \ - tcg_gen_addi_tl(EA, EA, 8); \ - tcg_gen_qemu_##op(xth, EA, ctx->mem_idx, MO_LEQ); \ - set_cpu_vsrh(xt, xth); \ - } else { \ - tcg_gen_qemu_##op(xth, EA, ctx->mem_idx, MO_BEQ); \ - set_cpu_vsrh(xt, xth); \ - tcg_gen_addi_tl(EA, EA, 8); \ - tcg_gen_qemu_##op(xtl, EA, ctx->mem_idx, MO_BEQ); \ - set_cpu_vsrl(xt, xtl); \ - } \ - tcg_temp_free(EA); \ - tcg_temp_free_i64(xth); \ - tcg_temp_free_i64(xtl); \ -} - -VSX_VECTOR_LOAD(lxv, ld_i64, 0) -VSX_VECTOR_LOAD(lxvx, ld_i64, 1) - -#define VSX_VECTOR_STORE(name, op, indexed) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - int xt; \ - TCGv EA; \ - TCGv_i64 xth; \ - TCGv_i64 xtl; \ - \ - if (indexed) { \ - xt = xT(ctx->opcode); \ - } else { \ - xt = DQxT(ctx->opcode); \ - } \ - \ - if (xt < 32) { \ - if (unlikely(!ctx->vsx_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VSXU); \ - return; \ - } \ - } else { \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - } \ - xth = tcg_temp_new_i64(); \ - xtl = tcg_temp_new_i64(); \ - get_cpu_vsrh(xth, xt); \ - get_cpu_vsrl(xtl, xt); \ - gen_set_access_type(ctx, ACCESS_INT); \ - EA = tcg_temp_new(); \ - if (indexed) { \ - gen_addr_reg_index(ctx, EA); \ - } else { \ - gen_addr_imm_index(ctx, EA, 0x0F); \ - } \ - if (ctx->le_mode) { \ - tcg_gen_qemu_##op(xtl, EA, ctx->mem_idx, MO_LEQ); \ - tcg_gen_addi_tl(EA, EA, 8); \ - tcg_gen_qemu_##op(xth, EA, ctx->mem_idx, MO_LEQ); \ - } else { \ - tcg_gen_qemu_##op(xth, EA, ctx->mem_idx, MO_BEQ); \ - tcg_gen_addi_tl(EA, EA, 8); \ - tcg_gen_qemu_##op(xtl, EA, ctx->mem_idx, MO_BEQ); \ - } \ - tcg_temp_free(EA); \ - tcg_temp_free_i64(xth); \ - tcg_temp_free_i64(xtl); \ -} - -VSX_VECTOR_STORE(stxv, st_i64, 0) -VSX_VECTOR_STORE(stxvx, st_i64, 1) + tcg_gen_qemu_ld_i64(xtl, EA, ctx->mem_idx, MO_BEUQ); + set_cpu_vsr(xT(ctx->opcode), xth, true); + set_cpu_vsr(xT(ctx->opcode), xtl, false); +} #ifdef TARGET_PPC64 #define VSX_VECTOR_LOAD_STORE_LENGTH(name) \ @@ -395,9 +257,7 @@ static void gen_##name(DisasContext *ctx) \ xt = gen_vsr_ptr(xT(ctx->opcode)); \ gen_set_access_type(ctx, ACCESS_INT); \ gen_addr_register(ctx, EA); \ - gen_helper_##name(cpu_env, EA, xt, cpu_gpr[rB(ctx->opcode)]); \ - tcg_temp_free(EA); \ - tcg_temp_free_ptr(xt); \ + gen_helper_##name(tcg_env, EA, xt, cpu_gpr[rB(ctx->opcode)]); \ } VSX_VECTOR_LOAD_STORE_LENGTH(lxvl) @@ -406,30 +266,6 @@ VSX_VECTOR_LOAD_STORE_LENGTH(stxvl) VSX_VECTOR_LOAD_STORE_LENGTH(stxvll) #endif -#define VSX_LOAD_SCALAR_DS(name, operation) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv EA; \ - TCGv_i64 xth; \ - \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - xth = tcg_temp_new_i64(); \ - gen_set_access_type(ctx, ACCESS_INT); \ - EA = tcg_temp_new(); \ - gen_addr_imm_index(ctx, EA, 0x03); \ - gen_qemu_##operation(ctx, xth, EA); \ - set_cpu_vsrh(rD(ctx->opcode) + 32, xth); \ - /* NOTE: cpu_vsrl is undefined */ \ - tcg_temp_free(EA); \ - tcg_temp_free_i64(xth); \ -} - -VSX_LOAD_SCALAR_DS(lxsd, ld64_i64) -VSX_LOAD_SCALAR_DS(lxssp, ld32fs) - #define VSX_STORE_SCALAR(name, operation) \ static void gen_##name(DisasContext *ctx) \ { \ @@ -443,10 +279,8 @@ static void gen_##name(DisasContext *ctx) \ gen_set_access_type(ctx, ACCESS_INT); \ EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ - get_cpu_vsrh(t0, xS(ctx->opcode)); \ + get_cpu_vsr(t0, xS(ctx->opcode), true); \ gen_qemu_##operation(ctx, t0, EA); \ - tcg_temp_free(EA); \ - tcg_temp_free_i64(t0); \ } VSX_STORE_SCALAR(stxsdx, st64_i64) @@ -468,13 +302,11 @@ static void gen_stxvd2x(DisasContext *ctx) gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); - get_cpu_vsrh(t0, xS(ctx->opcode)); + get_cpu_vsr(t0, xS(ctx->opcode), true); gen_qemu_st64_i64(ctx, t0, EA); tcg_gen_addi_tl(EA, EA, 8); - get_cpu_vsrl(t0, xS(ctx->opcode)); + get_cpu_vsr(t0, xS(ctx->opcode), false); gen_qemu_st64_i64(ctx, t0, EA); - tcg_temp_free(EA); - tcg_temp_free_i64(t0); } static void gen_stxvw4x(DisasContext *ctx) @@ -489,8 +321,8 @@ static void gen_stxvw4x(DisasContext *ctx) } xsh = tcg_temp_new_i64(); xsl = tcg_temp_new_i64(); - get_cpu_vsrh(xsh, xS(ctx->opcode)); - get_cpu_vsrl(xsl, xS(ctx->opcode)); + get_cpu_vsr(xsh, xS(ctx->opcode), true); + get_cpu_vsr(xsl, xS(ctx->opcode), false); gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); @@ -500,21 +332,16 @@ static void gen_stxvw4x(DisasContext *ctx) tcg_gen_shri_i64(t0, xsh, 32); tcg_gen_deposit_i64(t1, t0, xsh, 32, 32); - tcg_gen_qemu_st_i64(t1, EA, ctx->mem_idx, MO_LEQ); + tcg_gen_qemu_st_i64(t1, EA, ctx->mem_idx, MO_LEUQ); tcg_gen_addi_tl(EA, EA, 8); tcg_gen_shri_i64(t0, xsl, 32); tcg_gen_deposit_i64(t1, t0, xsl, 32, 32); - tcg_gen_qemu_st_i64(t1, EA, ctx->mem_idx, MO_LEQ); - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); + tcg_gen_qemu_st_i64(t1, EA, ctx->mem_idx, MO_LEUQ); } else { - tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEUQ); tcg_gen_addi_tl(EA, EA, 8); - tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEUQ); } - tcg_temp_free(EA); - tcg_temp_free_i64(xsh); - tcg_temp_free_i64(xsl); } static void gen_stxvh8x(DisasContext *ctx) @@ -529,8 +356,8 @@ static void gen_stxvh8x(DisasContext *ctx) } xsh = tcg_temp_new_i64(); xsl = tcg_temp_new_i64(); - get_cpu_vsrh(xsh, xS(ctx->opcode)); - get_cpu_vsrl(xsl, xS(ctx->opcode)); + get_cpu_vsr(xsh, xS(ctx->opcode), true); + get_cpu_vsr(xsl, xS(ctx->opcode), false); gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); @@ -539,19 +366,14 @@ static void gen_stxvh8x(DisasContext *ctx) TCGv_i64 outl = tcg_temp_new_i64(); gen_bswap16x8(outh, outl, xsh, xsl); - tcg_gen_qemu_st_i64(outh, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_qemu_st_i64(outh, EA, ctx->mem_idx, MO_BEUQ); tcg_gen_addi_tl(EA, EA, 8); - tcg_gen_qemu_st_i64(outl, EA, ctx->mem_idx, MO_BEQ); - tcg_temp_free_i64(outh); - tcg_temp_free_i64(outl); + tcg_gen_qemu_st_i64(outl, EA, ctx->mem_idx, MO_BEUQ); } else { - tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEUQ); tcg_gen_addi_tl(EA, EA, 8); - tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEUQ); } - tcg_temp_free(EA); - tcg_temp_free_i64(xsh); - tcg_temp_free_i64(xsl); } static void gen_stxvb16x(DisasContext *ctx) @@ -566,43 +388,16 @@ static void gen_stxvb16x(DisasContext *ctx) } xsh = tcg_temp_new_i64(); xsl = tcg_temp_new_i64(); - get_cpu_vsrh(xsh, xS(ctx->opcode)); - get_cpu_vsrl(xsl, xS(ctx->opcode)); + get_cpu_vsr(xsh, xS(ctx->opcode), true); + get_cpu_vsr(xsl, xS(ctx->opcode), false); gen_set_access_type(ctx, ACCESS_INT); EA = tcg_temp_new(); gen_addr_reg_index(ctx, EA); - tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEQ); + tcg_gen_qemu_st_i64(xsh, EA, ctx->mem_idx, MO_BEUQ); tcg_gen_addi_tl(EA, EA, 8); - tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEQ); - tcg_temp_free(EA); - tcg_temp_free_i64(xsh); - tcg_temp_free_i64(xsl); + tcg_gen_qemu_st_i64(xsl, EA, ctx->mem_idx, MO_BEUQ); } -#define VSX_STORE_SCALAR_DS(name, operation) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv EA; \ - TCGv_i64 xth; \ - \ - if (unlikely(!ctx->altivec_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VPU); \ - return; \ - } \ - xth = tcg_temp_new_i64(); \ - get_cpu_vsrh(xth, rD(ctx->opcode) + 32); \ - gen_set_access_type(ctx, ACCESS_INT); \ - EA = tcg_temp_new(); \ - gen_addr_imm_index(ctx, EA, 0x03); \ - gen_qemu_##operation(ctx, xth, EA); \ - /* NOTE: cpu_vsrl is undefined */ \ - tcg_temp_free(EA); \ - tcg_temp_free_i64(xth); \ -} - -VSX_STORE_SCALAR_DS(stxsd, st64_i64) -VSX_STORE_SCALAR_DS(stxssp, st32fs) - static void gen_mfvsrwz(DisasContext *ctx) { if (xS(ctx->opcode) < 32) { @@ -618,11 +413,9 @@ static void gen_mfvsrwz(DisasContext *ctx) } TCGv_i64 tmp = tcg_temp_new_i64(); TCGv_i64 xsh = tcg_temp_new_i64(); - get_cpu_vsrh(xsh, xS(ctx->opcode)); + get_cpu_vsr(xsh, xS(ctx->opcode), true); tcg_gen_ext32u_i64(tmp, xsh); tcg_gen_trunc_i64_tl(cpu_gpr[rA(ctx->opcode)], tmp); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(xsh); } static void gen_mtvsrwa(DisasContext *ctx) @@ -642,9 +435,7 @@ static void gen_mtvsrwa(DisasContext *ctx) TCGv_i64 xsh = tcg_temp_new_i64(); tcg_gen_extu_tl_i64(tmp, cpu_gpr[rA(ctx->opcode)]); tcg_gen_ext32s_i64(xsh, tmp); - set_cpu_vsrh(xT(ctx->opcode), xsh); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(xsh); + set_cpu_vsr(xT(ctx->opcode), xsh, true); } static void gen_mtvsrwz(DisasContext *ctx) @@ -664,9 +455,7 @@ static void gen_mtvsrwz(DisasContext *ctx) TCGv_i64 xsh = tcg_temp_new_i64(); tcg_gen_extu_tl_i64(tmp, cpu_gpr[rA(ctx->opcode)]); tcg_gen_ext32u_i64(xsh, tmp); - set_cpu_vsrh(xT(ctx->opcode), xsh); - tcg_temp_free_i64(tmp); - tcg_temp_free_i64(xsh); + set_cpu_vsr(xT(ctx->opcode), xsh, true); } #if defined(TARGET_PPC64) @@ -685,9 +474,8 @@ static void gen_mfvsrd(DisasContext *ctx) } } t0 = tcg_temp_new_i64(); - get_cpu_vsrh(t0, xS(ctx->opcode)); + get_cpu_vsr(t0, xS(ctx->opcode), true); tcg_gen_mov_i64(cpu_gpr[rA(ctx->opcode)], t0); - tcg_temp_free_i64(t0); } static void gen_mtvsrd(DisasContext *ctx) @@ -706,8 +494,7 @@ static void gen_mtvsrd(DisasContext *ctx) } t0 = tcg_temp_new_i64(); tcg_gen_mov_i64(t0, cpu_gpr[rA(ctx->opcode)]); - set_cpu_vsrh(xT(ctx->opcode), t0); - tcg_temp_free_i64(t0); + set_cpu_vsr(xT(ctx->opcode), t0, true); } static void gen_mfvsrld(DisasContext *ctx) @@ -725,9 +512,8 @@ static void gen_mfvsrld(DisasContext *ctx) } } t0 = tcg_temp_new_i64(); - get_cpu_vsrl(t0, xS(ctx->opcode)); + get_cpu_vsr(t0, xS(ctx->opcode), false); tcg_gen_mov_i64(cpu_gpr[rA(ctx->opcode)], t0); - tcg_temp_free_i64(t0); } static void gen_mtvsrdd(DisasContext *ctx) @@ -751,11 +537,10 @@ static void gen_mtvsrdd(DisasContext *ctx) } else { tcg_gen_mov_i64(t0, cpu_gpr[rA(ctx->opcode)]); } - set_cpu_vsrh(xT(ctx->opcode), t0); + set_cpu_vsr(xT(ctx->opcode), t0, true); tcg_gen_mov_i64(t0, cpu_gpr[rB(ctx->opcode)]); - set_cpu_vsrl(xT(ctx->opcode), t0); - tcg_temp_free_i64(t0); + set_cpu_vsr(xT(ctx->opcode), t0, false); } static void gen_mtvsrws(DisasContext *ctx) @@ -776,66 +561,22 @@ static void gen_mtvsrws(DisasContext *ctx) t0 = tcg_temp_new_i64(); tcg_gen_deposit_i64(t0, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 32, 32); - set_cpu_vsrl(xT(ctx->opcode), t0); - set_cpu_vsrh(xT(ctx->opcode), t0); - tcg_temp_free_i64(t0); + set_cpu_vsr(xT(ctx->opcode), t0, false); + set_cpu_vsr(xT(ctx->opcode), t0, true); } #endif -static void gen_xxpermdi(DisasContext *ctx) -{ - TCGv_i64 xh, xl; - - if (unlikely(!ctx->vsx_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VSXU); - return; - } - - xh = tcg_temp_new_i64(); - xl = tcg_temp_new_i64(); - - if (unlikely((xT(ctx->opcode) == xA(ctx->opcode)) || - (xT(ctx->opcode) == xB(ctx->opcode)))) { - if ((DM(ctx->opcode) & 2) == 0) { - get_cpu_vsrh(xh, xA(ctx->opcode)); - } else { - get_cpu_vsrl(xh, xA(ctx->opcode)); - } - if ((DM(ctx->opcode) & 1) == 0) { - get_cpu_vsrh(xl, xB(ctx->opcode)); - } else { - get_cpu_vsrl(xl, xB(ctx->opcode)); - } - - set_cpu_vsrh(xT(ctx->opcode), xh); - set_cpu_vsrl(xT(ctx->opcode), xl); - } else { - if ((DM(ctx->opcode) & 2) == 0) { - get_cpu_vsrh(xh, xA(ctx->opcode)); - set_cpu_vsrh(xT(ctx->opcode), xh); - } else { - get_cpu_vsrl(xh, xA(ctx->opcode)); - set_cpu_vsrh(xT(ctx->opcode), xh); - } - if ((DM(ctx->opcode) & 1) == 0) { - get_cpu_vsrh(xl, xB(ctx->opcode)); - set_cpu_vsrl(xT(ctx->opcode), xl); - } else { - get_cpu_vsrl(xl, xB(ctx->opcode)); - set_cpu_vsrl(xT(ctx->opcode), xl); - } - } - tcg_temp_free_i64(xh); - tcg_temp_free_i64(xl); -} - #define OP_ABS 1 #define OP_NABS 2 #define OP_NEG 3 #define OP_CPSGN 4 #define SGN_MASK_DP 0x8000000000000000ull #define SGN_MASK_SP 0x8000000080000000ull +#define EXP_MASK_DP 0x7FF0000000000000ull +#define EXP_MASK_SP 0x7F8000007F800000ull +#define FRC_MASK_DP (~(SGN_MASK_DP | EXP_MASK_DP)) +#define FRC_MASK_SP (~(SGN_MASK_SP | EXP_MASK_SP)) #define VSX_SCALAR_MOVE(name, op, sgn_mask) \ static void glue(gen_, name)(DisasContext *ctx) \ @@ -847,7 +588,7 @@ static void glue(gen_, name)(DisasContext *ctx) \ } \ xb = tcg_temp_new_i64(); \ sgm = tcg_temp_new_i64(); \ - get_cpu_vsrh(xb, xB(ctx->opcode)); \ + get_cpu_vsr(xb, xB(ctx->opcode), true); \ tcg_gen_movi_i64(sgm, sgn_mask); \ switch (op) { \ case OP_ABS: { \ @@ -864,17 +605,15 @@ static void glue(gen_, name)(DisasContext *ctx) \ } \ case OP_CPSGN: { \ TCGv_i64 xa = tcg_temp_new_i64(); \ - get_cpu_vsrh(xa, xA(ctx->opcode)); \ + get_cpu_vsr(xa, xA(ctx->opcode), true); \ tcg_gen_and_i64(xa, xa, sgm); \ tcg_gen_andc_i64(xb, xb, sgm); \ tcg_gen_or_i64(xb, xb, xa); \ - tcg_temp_free_i64(xa); \ break; \ } \ } \ - set_cpu_vsrh(xT(ctx->opcode), xb); \ - tcg_temp_free_i64(xb); \ - tcg_temp_free_i64(sgm); \ + set_cpu_vsr(xT(ctx->opcode), xb, true); \ + set_cpu_vsr(xT(ctx->opcode), tcg_constant_i64(0), false); \ } VSX_SCALAR_MOVE(xsabsdp, OP_ABS, SGN_MASK_DP) @@ -898,8 +637,8 @@ static void glue(gen_, name)(DisasContext *ctx) \ xbl = tcg_temp_new_i64(); \ sgm = tcg_temp_new_i64(); \ tmp = tcg_temp_new_i64(); \ - get_cpu_vsrh(xbh, xb); \ - get_cpu_vsrl(xbl, xb); \ + get_cpu_vsr(xbh, xb, true); \ + get_cpu_vsr(xbl, xb, false); \ tcg_gen_movi_i64(sgm, sgn_mask); \ switch (op) { \ case OP_ABS: \ @@ -914,19 +653,14 @@ static void glue(gen_, name)(DisasContext *ctx) \ case OP_CPSGN: \ xah = tcg_temp_new_i64(); \ xa = rA(ctx->opcode) + 32; \ - get_cpu_vsrh(tmp, xa); \ + get_cpu_vsr(tmp, xa, true); \ tcg_gen_and_i64(xah, tmp, sgm); \ tcg_gen_andc_i64(xbh, xbh, sgm); \ tcg_gen_or_i64(xbh, xbh, xah); \ - tcg_temp_free_i64(xah); \ break; \ } \ - set_cpu_vsrh(xt, xbh); \ - set_cpu_vsrl(xt, xbl); \ - tcg_temp_free_i64(xbl); \ - tcg_temp_free_i64(xbh); \ - tcg_temp_free_i64(sgm); \ - tcg_temp_free_i64(tmp); \ + set_cpu_vsr(xt, xbh, true); \ + set_cpu_vsr(xt, xbl, false); \ } VSX_SCALAR_MOVE_QP(xsabsqp, OP_ABS, SGN_MASK_DP) @@ -934,67 +668,125 @@ VSX_SCALAR_MOVE_QP(xsnabsqp, OP_NABS, SGN_MASK_DP) VSX_SCALAR_MOVE_QP(xsnegqp, OP_NEG, SGN_MASK_DP) VSX_SCALAR_MOVE_QP(xscpsgnqp, OP_CPSGN, SGN_MASK_DP) -#define VSX_VECTOR_MOVE(name, op, sgn_mask) \ -static void glue(gen_, name)(DisasContext *ctx) \ - { \ - TCGv_i64 xbh, xbl, sgm; \ - if (unlikely(!ctx->vsx_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VSXU); \ - return; \ - } \ - xbh = tcg_temp_new_i64(); \ - xbl = tcg_temp_new_i64(); \ - sgm = tcg_temp_new_i64(); \ - get_cpu_vsrh(xbh, xB(ctx->opcode)); \ - get_cpu_vsrl(xbl, xB(ctx->opcode)); \ - tcg_gen_movi_i64(sgm, sgn_mask); \ - switch (op) { \ - case OP_ABS: { \ - tcg_gen_andc_i64(xbh, xbh, sgm); \ - tcg_gen_andc_i64(xbl, xbl, sgm); \ - break; \ - } \ - case OP_NABS: { \ - tcg_gen_or_i64(xbh, xbh, sgm); \ - tcg_gen_or_i64(xbl, xbl, sgm); \ - break; \ - } \ - case OP_NEG: { \ - tcg_gen_xor_i64(xbh, xbh, sgm); \ - tcg_gen_xor_i64(xbl, xbl, sgm); \ - break; \ - } \ - case OP_CPSGN: { \ - TCGv_i64 xah = tcg_temp_new_i64(); \ - TCGv_i64 xal = tcg_temp_new_i64(); \ - get_cpu_vsrh(xah, xA(ctx->opcode)); \ - get_cpu_vsrl(xal, xA(ctx->opcode)); \ - tcg_gen_and_i64(xah, xah, sgm); \ - tcg_gen_and_i64(xal, xal, sgm); \ - tcg_gen_andc_i64(xbh, xbh, sgm); \ - tcg_gen_andc_i64(xbl, xbl, sgm); \ - tcg_gen_or_i64(xbh, xbh, xah); \ - tcg_gen_or_i64(xbl, xbl, xal); \ - tcg_temp_free_i64(xah); \ - tcg_temp_free_i64(xal); \ - break; \ - } \ - } \ - set_cpu_vsrh(xT(ctx->opcode), xbh); \ - set_cpu_vsrl(xT(ctx->opcode), xbl); \ - tcg_temp_free_i64(xbh); \ - tcg_temp_free_i64(xbl); \ - tcg_temp_free_i64(sgm); \ - } - -VSX_VECTOR_MOVE(xvabsdp, OP_ABS, SGN_MASK_DP) -VSX_VECTOR_MOVE(xvnabsdp, OP_NABS, SGN_MASK_DP) -VSX_VECTOR_MOVE(xvnegdp, OP_NEG, SGN_MASK_DP) -VSX_VECTOR_MOVE(xvcpsgndp, OP_CPSGN, SGN_MASK_DP) -VSX_VECTOR_MOVE(xvabssp, OP_ABS, SGN_MASK_SP) -VSX_VECTOR_MOVE(xvnabssp, OP_NABS, SGN_MASK_SP) -VSX_VECTOR_MOVE(xvnegsp, OP_NEG, SGN_MASK_SP) -VSX_VECTOR_MOVE(xvcpsgnsp, OP_CPSGN, SGN_MASK_SP) +#define TCG_OP_IMM_i64(FUNC, OP, IMM) \ + static void FUNC(TCGv_i64 t, TCGv_i64 b) \ + { \ + OP(t, b, IMM); \ + } + +TCG_OP_IMM_i64(do_xvabssp_i64, tcg_gen_andi_i64, ~SGN_MASK_SP) +TCG_OP_IMM_i64(do_xvnabssp_i64, tcg_gen_ori_i64, SGN_MASK_SP) +TCG_OP_IMM_i64(do_xvnegsp_i64, tcg_gen_xori_i64, SGN_MASK_SP) +TCG_OP_IMM_i64(do_xvabsdp_i64, tcg_gen_andi_i64, ~SGN_MASK_DP) +TCG_OP_IMM_i64(do_xvnabsdp_i64, tcg_gen_ori_i64, SGN_MASK_DP) +TCG_OP_IMM_i64(do_xvnegdp_i64, tcg_gen_xori_i64, SGN_MASK_DP) +#undef TCG_OP_IMM_i64 + +static void xv_msb_op1(unsigned vece, TCGv_vec t, TCGv_vec b, + void (*tcg_gen_op_vec)(unsigned, TCGv_vec, TCGv_vec, TCGv_vec)) +{ + uint64_t msb = (vece == MO_32) ? SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_op_vec(vece, t, b, tcg_constant_vec_matching(t, vece, msb)); +} + +static void do_xvabs_vec(unsigned vece, TCGv_vec t, TCGv_vec b) +{ + xv_msb_op1(vece, t, b, tcg_gen_andc_vec); +} + +static void do_xvnabs_vec(unsigned vece, TCGv_vec t, TCGv_vec b) +{ + xv_msb_op1(vece, t, b, tcg_gen_or_vec); +} + +static void do_xvneg_vec(unsigned vece, TCGv_vec t, TCGv_vec b) +{ + xv_msb_op1(vece, t, b, tcg_gen_xor_vec); +} + +static bool do_vsx_msb_op(DisasContext *ctx, arg_XX2 *a, unsigned vece, + void (*vec)(unsigned, TCGv_vec, TCGv_vec), + void (*i64)(TCGv_i64, TCGv_i64)) +{ + static const TCGOpcode vecop_list[] = { + 0 + }; + + const GVecGen2 op = { + .fni8 = i64, + .fniv = vec, + .opt_opc = vecop_list, + .vece = vece + }; + + REQUIRE_INSNS_FLAGS2(ctx, VSX); + REQUIRE_VSX(ctx); + + tcg_gen_gvec_2(vsr_full_offset(a->xt), vsr_full_offset(a->xb), + 16, 16, &op); + + return true; +} + +TRANS(XVABSDP, do_vsx_msb_op, MO_64, do_xvabs_vec, do_xvabsdp_i64) +TRANS(XVNABSDP, do_vsx_msb_op, MO_64, do_xvnabs_vec, do_xvnabsdp_i64) +TRANS(XVNEGDP, do_vsx_msb_op, MO_64, do_xvneg_vec, do_xvnegdp_i64) +TRANS(XVABSSP, do_vsx_msb_op, MO_32, do_xvabs_vec, do_xvabssp_i64) +TRANS(XVNABSSP, do_vsx_msb_op, MO_32, do_xvnabs_vec, do_xvnabssp_i64) +TRANS(XVNEGSP, do_vsx_msb_op, MO_32, do_xvneg_vec, do_xvnegsp_i64) + +static void do_xvcpsgndp_i64(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +{ + tcg_gen_andi_i64(a, a, SGN_MASK_DP); + tcg_gen_andi_i64(b, b, ~SGN_MASK_DP); + tcg_gen_or_i64(t, a, b); +} + +static void do_xvcpsgnsp_i64(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +{ + tcg_gen_andi_i64(a, a, SGN_MASK_SP); + tcg_gen_andi_i64(b, b, ~SGN_MASK_SP); + tcg_gen_or_i64(t, a, b); +} + +static void do_xvcpsgn_vec(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +{ + uint64_t msb = (vece == MO_32) ? SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_bitsel_vec(vece, t, tcg_constant_vec_matching(t, vece, msb), a, b); +} + +static bool do_xvcpsgn(DisasContext *ctx, arg_XX3 *a, unsigned vece) +{ + static const TCGOpcode vecop_list[] = { + 0 + }; + + static const GVecGen3 op[] = { + { + .fni8 = do_xvcpsgnsp_i64, + .fniv = do_xvcpsgn_vec, + .opt_opc = vecop_list, + .vece = MO_32 + }, + { + .fni8 = do_xvcpsgndp_i64, + .fniv = do_xvcpsgn_vec, + .opt_opc = vecop_list, + .vece = MO_64 + }, + }; + + REQUIRE_INSNS_FLAGS2(ctx, VSX); + REQUIRE_VSX(ctx); + + tcg_gen_gvec_3(vsr_full_offset(a->xt), vsr_full_offset(a->xa), + vsr_full_offset(a->xb), 16, 16, &op[vece - MO_32]); + + return true; +} + +TRANS(XVCPSGNSP, do_xvcpsgn, MO_32) +TRANS(XVCPSGNDP, do_xvcpsgn, MO_64) #define VSX_CMP(name, op1, op2, inval, type) \ static void gen_##name(DisasContext *ctx) \ @@ -1009,16 +801,11 @@ static void gen_##name(DisasContext *ctx) \ xa = gen_vsr_ptr(xA(ctx->opcode)); \ xb = gen_vsr_ptr(xB(ctx->opcode)); \ if ((ctx->opcode >> (31 - 21)) & 1) { \ - gen_helper_##name(cpu_crf[6], cpu_env, xt, xa, xb); \ + gen_helper_##name(cpu_crf[6], tcg_env, xt, xa, xb); \ } else { \ ignored = tcg_temp_new_i32(); \ - gen_helper_##name(ignored, cpu_env, xt, xa, xb); \ - tcg_temp_free_i32(ignored); \ + gen_helper_##name(ignored, tcg_env, xt, xa, xb); \ } \ - gen_helper_float_check_status(cpu_env); \ - tcg_temp_free_ptr(xt); \ - tcg_temp_free_ptr(xa); \ - tcg_temp_free_ptr(xb); \ } VSX_CMP(xvcmpeqdp, 0x0C, 0x0C, 0, PPC2_VSX) @@ -1030,23 +817,41 @@ VSX_CMP(xvcmpgesp, 0x0C, 0x0A, 0, PPC2_VSX) VSX_CMP(xvcmpgtsp, 0x0C, 0x09, 0, PPC2_VSX) VSX_CMP(xvcmpnesp, 0x0C, 0x0B, 0, PPC2_VSX) -static void gen_xscvqpdp(DisasContext *ctx) +static bool trans_XSCVQPDP(DisasContext *ctx, arg_X_tb_rc *a) { - TCGv_i32 opc; + TCGv_i32 ro; TCGv_ptr xt, xb; - if (unlikely(!ctx->vsx_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VSXU); - return; - } - opc = tcg_const_i32(ctx->opcode); - xt = gen_vsr_ptr(xT(ctx->opcode)); - xb = gen_vsr_ptr(xB(ctx->opcode)); - gen_helper_xscvqpdp(cpu_env, opc, xt, xb); - tcg_temp_free_i32(opc); - tcg_temp_free_ptr(xt); - tcg_temp_free_ptr(xb); + + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VSX(ctx); + + ro = tcg_constant_i32(a->rc); + + xt = gen_avr_ptr(a->rt); + xb = gen_avr_ptr(a->rb); + gen_helper_XSCVQPDP(tcg_env, ro, xt, xb); + return true; +} + +static bool do_helper_env_X_tb(DisasContext *ctx, arg_X_tb *a, + void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr)) +{ + TCGv_ptr xt, xb; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + + xt = gen_avr_ptr(a->rt); + xb = gen_avr_ptr(a->rb); + gen_helper(tcg_env, xt, xb); + return true; } +TRANS(XSCVUQQP, do_helper_env_X_tb, gen_helper_XSCVUQQP) +TRANS(XSCVSQQP, do_helper_env_X_tb, gen_helper_XSCVSQQP) +TRANS(XSCVQPUQZ, do_helper_env_X_tb, gen_helper_XSCVQPUQZ) +TRANS(XSCVQPSQZ, do_helper_env_X_tb, gen_helper_XSCVQPSQZ) + #define GEN_VSX_HELPER_2(name, op1, op2, inval, type) \ static void gen_##name(DisasContext *ctx) \ { \ @@ -1055,9 +860,8 @@ static void gen_##name(DisasContext *ctx) \ gen_exception(ctx, POWERPC_EXCP_VSXU); \ return; \ } \ - opc = tcg_const_i32(ctx->opcode); \ - gen_helper_##name(cpu_env, opc); \ - tcg_temp_free_i32(opc); \ + opc = tcg_constant_i32(ctx->opcode); \ + gen_helper_##name(tcg_env, opc); \ } #define GEN_VSX_HELPER_X3(name, op1, op2, inval, type) \ @@ -1071,10 +875,7 @@ static void gen_##name(DisasContext *ctx) \ xt = gen_vsr_ptr(xT(ctx->opcode)); \ xa = gen_vsr_ptr(xA(ctx->opcode)); \ xb = gen_vsr_ptr(xB(ctx->opcode)); \ - gen_helper_##name(cpu_env, xt, xa, xb); \ - tcg_temp_free_ptr(xt); \ - tcg_temp_free_ptr(xa); \ - tcg_temp_free_ptr(xb); \ + gen_helper_##name(tcg_env, xt, xa, xb); \ } #define GEN_VSX_HELPER_X2(name, op1, op2, inval, type) \ @@ -1087,9 +888,7 @@ static void gen_##name(DisasContext *ctx) \ } \ xt = gen_vsr_ptr(xT(ctx->opcode)); \ xb = gen_vsr_ptr(xB(ctx->opcode)); \ - gen_helper_##name(cpu_env, xt, xb); \ - tcg_temp_free_ptr(xt); \ - tcg_temp_free_ptr(xb); \ + gen_helper_##name(tcg_env, xt, xb); \ } #define GEN_VSX_HELPER_X2_AB(name, op1, op2, inval, type) \ @@ -1101,13 +900,10 @@ static void gen_##name(DisasContext *ctx) \ gen_exception(ctx, POWERPC_EXCP_VSXU); \ return; \ } \ - opc = tcg_const_i32(ctx->opcode); \ + opc = tcg_constant_i32(ctx->opcode); \ xa = gen_vsr_ptr(xA(ctx->opcode)); \ xb = gen_vsr_ptr(xB(ctx->opcode)); \ - gen_helper_##name(cpu_env, opc, xa, xb); \ - tcg_temp_free_i32(opc); \ - tcg_temp_free_ptr(xa); \ - tcg_temp_free_ptr(xb); \ + gen_helper_##name(tcg_env, opc, xa, xb); \ } #define GEN_VSX_HELPER_X1(name, op1, op2, inval, type) \ @@ -1119,11 +915,9 @@ static void gen_##name(DisasContext *ctx) \ gen_exception(ctx, POWERPC_EXCP_VSXU); \ return; \ } \ - opc = tcg_const_i32(ctx->opcode); \ + opc = tcg_constant_i32(ctx->opcode); \ xb = gen_vsr_ptr(xB(ctx->opcode)); \ - gen_helper_##name(cpu_env, opc, xb); \ - tcg_temp_free_i32(opc); \ - tcg_temp_free_ptr(xb); \ + gen_helper_##name(tcg_env, opc, xb); \ } #define GEN_VSX_HELPER_R3(name, op1, op2, inval, type) \ @@ -1135,15 +929,11 @@ static void gen_##name(DisasContext *ctx) \ gen_exception(ctx, POWERPC_EXCP_VSXU); \ return; \ } \ - opc = tcg_const_i32(ctx->opcode); \ + opc = tcg_constant_i32(ctx->opcode); \ xt = gen_vsr_ptr(rD(ctx->opcode) + 32); \ xa = gen_vsr_ptr(rA(ctx->opcode) + 32); \ xb = gen_vsr_ptr(rB(ctx->opcode) + 32); \ - gen_helper_##name(cpu_env, opc, xt, xa, xb); \ - tcg_temp_free_i32(opc); \ - tcg_temp_free_ptr(xt); \ - tcg_temp_free_ptr(xa); \ - tcg_temp_free_ptr(xb); \ + gen_helper_##name(tcg_env, opc, xt, xa, xb); \ } #define GEN_VSX_HELPER_R2(name, op1, op2, inval, type) \ @@ -1155,13 +945,10 @@ static void gen_##name(DisasContext *ctx) \ gen_exception(ctx, POWERPC_EXCP_VSXU); \ return; \ } \ - opc = tcg_const_i32(ctx->opcode); \ + opc = tcg_constant_i32(ctx->opcode); \ xt = gen_vsr_ptr(rD(ctx->opcode) + 32); \ xb = gen_vsr_ptr(rB(ctx->opcode) + 32); \ - gen_helper_##name(cpu_env, opc, xt, xb); \ - tcg_temp_free_i32(opc); \ - tcg_temp_free_ptr(xt); \ - tcg_temp_free_ptr(xb); \ + gen_helper_##name(tcg_env, opc, xt, xb); \ } #define GEN_VSX_HELPER_R2_AB(name, op1, op2, inval, type) \ @@ -1173,13 +960,10 @@ static void gen_##name(DisasContext *ctx) \ gen_exception(ctx, POWERPC_EXCP_VSXU); \ return; \ } \ - opc = tcg_const_i32(ctx->opcode); \ + opc = tcg_constant_i32(ctx->opcode); \ xa = gen_vsr_ptr(rA(ctx->opcode) + 32); \ xb = gen_vsr_ptr(rB(ctx->opcode) + 32); \ - gen_helper_##name(cpu_env, opc, xa, xb); \ - tcg_temp_free_i32(opc); \ - tcg_temp_free_ptr(xa); \ - tcg_temp_free_ptr(xb); \ + gen_helper_##name(tcg_env, opc, xa, xb); \ } #define GEN_VSX_HELPER_XT_XB_ENV(name, op1, op2, inval, type) \ @@ -1193,11 +977,10 @@ static void gen_##name(DisasContext *ctx) \ } \ t0 = tcg_temp_new_i64(); \ t1 = tcg_temp_new_i64(); \ - get_cpu_vsrh(t0, xB(ctx->opcode)); \ - gen_helper_##name(t1, cpu_env, t0); \ - set_cpu_vsrh(xT(ctx->opcode), t1); \ - tcg_temp_free_i64(t0); \ - tcg_temp_free_i64(t1); \ + get_cpu_vsr(t0, xB(ctx->opcode), true); \ + gen_helper_##name(t1, tcg_env, t0); \ + set_cpu_vsr(xT(ctx->opcode), t1, true); \ + set_cpu_vsr(xT(ctx->opcode), tcg_constant_i64(0), false); \ } GEN_VSX_HELPER_X3(xsadddp, 0x00, 0x04, 0, PPC2_VSX) @@ -1212,10 +995,6 @@ GEN_VSX_HELPER_X2(xssqrtdp, 0x16, 0x04, 0, PPC2_VSX) GEN_VSX_HELPER_X2(xsrsqrtedp, 0x14, 0x04, 0, PPC2_VSX) GEN_VSX_HELPER_X2_AB(xstdivdp, 0x14, 0x07, 0, PPC2_VSX) GEN_VSX_HELPER_X1(xstsqrtdp, 0x14, 0x06, 0, PPC2_VSX) -GEN_VSX_HELPER_X3(xscmpeqdp, 0x0C, 0x00, 0, PPC2_ISA300) -GEN_VSX_HELPER_X3(xscmpgtdp, 0x0C, 0x01, 0, PPC2_ISA300) -GEN_VSX_HELPER_X3(xscmpgedp, 0x0C, 0x02, 0, PPC2_ISA300) -GEN_VSX_HELPER_X3(xscmpnedp, 0x0C, 0x03, 0, PPC2_ISA300) GEN_VSX_HELPER_X2_AB(xscmpexpdp, 0x0C, 0x07, 0, PPC2_ISA300) GEN_VSX_HELPER_R2_AB(xscmpexpqp, 0x04, 0x05, 0, PPC2_ISA300) GEN_VSX_HELPER_X2_AB(xscmpodp, 0x0C, 0x05, 0, PPC2_VSX) @@ -1224,10 +1003,6 @@ GEN_VSX_HELPER_R2_AB(xscmpoqp, 0x04, 0x04, 0, PPC2_VSX) GEN_VSX_HELPER_R2_AB(xscmpuqp, 0x04, 0x14, 0, PPC2_VSX) GEN_VSX_HELPER_X3(xsmaxdp, 0x00, 0x14, 0, PPC2_VSX) GEN_VSX_HELPER_X3(xsmindp, 0x00, 0x15, 0, PPC2_VSX) -GEN_VSX_HELPER_R3(xsmaxcdp, 0x00, 0x10, 0, PPC2_ISA300) -GEN_VSX_HELPER_R3(xsmincdp, 0x00, 0x11, 0, PPC2_ISA300) -GEN_VSX_HELPER_R3(xsmaxjdp, 0x00, 0x12, 0, PPC2_ISA300) -GEN_VSX_HELPER_R3(xsminjdp, 0x00, 0x12, 0, PPC2_ISA300) GEN_VSX_HELPER_X2(xscvdphp, 0x16, 0x15, 0x11, PPC2_ISA300) GEN_VSX_HELPER_X2(xscvdpsp, 0x12, 0x10, 0, PPC2_VSX) GEN_VSX_HELPER_R2(xscvdpqp, 0x04, 0x1A, 0x16, PPC2_ISA300) @@ -1239,7 +1014,208 @@ GEN_VSX_HELPER_R2(xscvqpuwz, 0x04, 0x1A, 0x01, PPC2_ISA300) GEN_VSX_HELPER_X2(xscvhpdp, 0x16, 0x15, 0x10, PPC2_ISA300) GEN_VSX_HELPER_R2(xscvsdqp, 0x04, 0x1A, 0x0A, PPC2_ISA300) GEN_VSX_HELPER_X2(xscvspdp, 0x12, 0x14, 0, PPC2_VSX) -GEN_VSX_HELPER_XT_XB_ENV(xscvspdpn, 0x16, 0x14, 0, PPC2_VSX207) + +/* test if +Inf */ +static void gen_is_pos_inf(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + uint64_t exp_msk = (vece == MO_32) ? (uint32_t)EXP_MASK_SP : EXP_MASK_DP; + tcg_gen_cmp_vec(TCG_COND_EQ, vece, t, b, + tcg_constant_vec_matching(t, vece, exp_msk)); +} + +/* test if -Inf */ +static void gen_is_neg_inf(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + uint64_t exp_msk = (vece == MO_32) ? (uint32_t)EXP_MASK_SP : EXP_MASK_DP; + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_cmp_vec(TCG_COND_EQ, vece, t, b, + tcg_constant_vec_matching(t, vece, sgn_msk | exp_msk)); +} + +/* test if +Inf or -Inf */ +static void gen_is_any_inf(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + uint64_t exp_msk = (vece == MO_32) ? (uint32_t)EXP_MASK_SP : EXP_MASK_DP; + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_andc_vec(vece, b, b, tcg_constant_vec_matching(t, vece, sgn_msk)); + tcg_gen_cmp_vec(TCG_COND_EQ, vece, t, b, + tcg_constant_vec_matching(t, vece, exp_msk)); +} + +/* test if +0 */ +static void gen_is_pos_zero(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + tcg_gen_cmp_vec(TCG_COND_EQ, vece, t, b, + tcg_constant_vec_matching(t, vece, 0)); +} + +/* test if -0 */ +static void gen_is_neg_zero(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_cmp_vec(TCG_COND_EQ, vece, t, b, + tcg_constant_vec_matching(t, vece, sgn_msk)); +} + +/* test if +0 or -0 */ +static void gen_is_any_zero(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_andc_vec(vece, b, b, tcg_constant_vec_matching(t, vece, sgn_msk)); + tcg_gen_cmp_vec(TCG_COND_EQ, vece, t, b, + tcg_constant_vec_matching(t, vece, 0)); +} + +/* test if +Denormal */ +static void gen_is_pos_denormal(unsigned vece, TCGv_vec t, + TCGv_vec b, int64_t v) +{ + uint64_t frc_msk = (vece == MO_32) ? (uint32_t)FRC_MASK_SP : FRC_MASK_DP; + tcg_gen_cmp_vec(TCG_COND_LEU, vece, t, b, + tcg_constant_vec_matching(t, vece, frc_msk)); + tcg_gen_cmp_vec(TCG_COND_NE, vece, b, b, + tcg_constant_vec_matching(t, vece, 0)); + tcg_gen_and_vec(vece, t, t, b); +} + +/* test if -Denormal */ +static void gen_is_neg_denormal(unsigned vece, TCGv_vec t, + TCGv_vec b, int64_t v) +{ + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + uint64_t frc_msk = (vece == MO_32) ? (uint32_t)FRC_MASK_SP : FRC_MASK_DP; + tcg_gen_cmp_vec(TCG_COND_LEU, vece, t, b, + tcg_constant_vec_matching(t, vece, sgn_msk | frc_msk)); + tcg_gen_cmp_vec(TCG_COND_GTU, vece, b, b, + tcg_constant_vec_matching(t, vece, sgn_msk)); + tcg_gen_and_vec(vece, t, t, b); +} + +/* test if +Denormal or -Denormal */ +static void gen_is_any_denormal(unsigned vece, TCGv_vec t, + TCGv_vec b, int64_t v) +{ + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + uint64_t frc_msk = (vece == MO_32) ? (uint32_t)FRC_MASK_SP : FRC_MASK_DP; + tcg_gen_andc_vec(vece, b, b, tcg_constant_vec_matching(t, vece, sgn_msk)); + tcg_gen_cmp_vec(TCG_COND_LE, vece, t, b, + tcg_constant_vec_matching(t, vece, frc_msk)); + tcg_gen_cmp_vec(TCG_COND_NE, vece, b, b, + tcg_constant_vec_matching(t, vece, 0)); + tcg_gen_and_vec(vece, t, t, b); +} + +/* test if NaN */ +static void gen_is_nan(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + uint64_t exp_msk = (vece == MO_32) ? (uint32_t)EXP_MASK_SP : EXP_MASK_DP; + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_and_vec(vece, b, b, tcg_constant_vec_matching(t, vece, ~sgn_msk)); + tcg_gen_cmp_vec(TCG_COND_GT, vece, t, b, + tcg_constant_vec_matching(t, vece, exp_msk)); +} + +static bool do_xvtstdc(DisasContext *ctx, arg_XX2_uim *a, unsigned vece) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_cmp_vec, 0 + }; + + GVecGen2i op = { + .fnoi = (vece == MO_32) ? gen_helper_XVTSTDCSP : gen_helper_XVTSTDCDP, + .vece = vece, + .opt_opc = vecop_list + }; + + REQUIRE_VSX(ctx); + + switch (a->uim) { + case 0: + set_cpu_vsr(a->xt, tcg_constant_i64(0), true); + set_cpu_vsr(a->xt, tcg_constant_i64(0), false); + return true; + case ((1 << 0) | (1 << 1)): + /* test if +Denormal or -Denormal */ + op.fniv = gen_is_any_denormal; + break; + case (1 << 0): + /* test if -Denormal */ + op.fniv = gen_is_neg_denormal; + break; + case (1 << 1): + /* test if +Denormal */ + op.fniv = gen_is_pos_denormal; + break; + case ((1 << 2) | (1 << 3)): + /* test if +0 or -0 */ + op.fniv = gen_is_any_zero; + break; + case (1 << 2): + /* test if -0 */ + op.fniv = gen_is_neg_zero; + break; + case (1 << 3): + /* test if +0 */ + op.fniv = gen_is_pos_zero; + break; + case ((1 << 4) | (1 << 5)): + /* test if +Inf or -Inf */ + op.fniv = gen_is_any_inf; + break; + case (1 << 4): + /* test if -Inf */ + op.fniv = gen_is_neg_inf; + break; + case (1 << 5): + /* test if +Inf */ + op.fniv = gen_is_pos_inf; + break; + case (1 << 6): + /* test if NaN */ + op.fniv = gen_is_nan; + break; + } + tcg_gen_gvec_2i(vsr_full_offset(a->xt), vsr_full_offset(a->xb), + 16, 16, a->uim, &op); + + return true; +} + +TRANS_FLAGS2(VSX, XVTSTDCSP, do_xvtstdc, MO_32) +TRANS_FLAGS2(VSX, XVTSTDCDP, do_xvtstdc, MO_64) + +static bool do_XX2_bf_uim(DisasContext *ctx, arg_XX2_bf_uim *a, bool vsr, + void (*gen_helper)(TCGv_env, TCGv_i32, TCGv_i32, TCGv_ptr)) +{ + TCGv_ptr xb; + + REQUIRE_VSX(ctx); + xb = vsr ? gen_vsr_ptr(a->xb) : gen_avr_ptr(a->xb); + gen_helper(tcg_env, tcg_constant_i32(a->bf), tcg_constant_i32(a->uim), xb); + return true; +} + +TRANS_FLAGS2(ISA300, XSTSTDCSP, do_XX2_bf_uim, true, gen_helper_XSTSTDCSP) +TRANS_FLAGS2(ISA300, XSTSTDCDP, do_XX2_bf_uim, true, gen_helper_XSTSTDCDP) +TRANS_FLAGS2(ISA300, XSTSTDCQP, do_XX2_bf_uim, false, gen_helper_XSTSTDCQP) + +bool trans_XSCVSPDPN(DisasContext *ctx, arg_XX2 *a) +{ + TCGv_i64 tmp; + + REQUIRE_INSNS_FLAGS2(ctx, VSX207); + REQUIRE_VSX(ctx); + + tmp = tcg_temp_new_i64(); + get_cpu_vsr(tmp, a->xb, true); + + gen_helper_XSCVSPDPN(tmp, tmp); + + set_cpu_vsr(a->xt, tmp, true); + set_cpu_vsr(a->xt, tcg_constant_i64(0), false); + return true; +} + GEN_VSX_HELPER_X2(xscvdpsxds, 0x10, 0x15, 0, PPC2_VSX) GEN_VSX_HELPER_X2(xscvdpsxws, 0x10, 0x05, 0, PPC2_VSX) GEN_VSX_HELPER_X2(xscvdpuxds, 0x10, 0x14, 0, PPC2_VSX) @@ -1266,9 +1242,6 @@ GEN_VSX_HELPER_X2(xssqrtsp, 0x16, 0x00, 0, PPC2_VSX207) GEN_VSX_HELPER_X2(xsrsqrtesp, 0x14, 0x00, 0, PPC2_VSX207) GEN_VSX_HELPER_X2(xscvsxdsp, 0x10, 0x13, 0, PPC2_VSX207) GEN_VSX_HELPER_X2(xscvuxdsp, 0x10, 0x12, 0, PPC2_VSX207) -GEN_VSX_HELPER_X1(xststdcsp, 0x14, 0x12, 0, PPC2_ISA300) -GEN_VSX_HELPER_2(xststdcdp, 0x14, 0x16, 0, PPC2_ISA300) -GEN_VSX_HELPER_2(xststdcqp, 0x04, 0x16, 0, PPC2_ISA300) GEN_VSX_HELPER_X3(xvadddp, 0x00, 0x0C, 0, PPC2_VSX) GEN_VSX_HELPER_X3(xvsubdp, 0x00, 0x0D, 0, PPC2_VSX) @@ -1323,49 +1296,213 @@ GEN_VSX_HELPER_X2(xvrspic, 0x16, 0x0A, 0, PPC2_VSX) GEN_VSX_HELPER_X2(xvrspim, 0x12, 0x0B, 0, PPC2_VSX) GEN_VSX_HELPER_X2(xvrspip, 0x12, 0x0A, 0, PPC2_VSX) GEN_VSX_HELPER_X2(xvrspiz, 0x12, 0x09, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvtstdcsp, 0x14, 0x1A, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvtstdcdp, 0x14, 0x1E, 0, PPC2_VSX) -GEN_VSX_HELPER_X3(xxperm, 0x08, 0x03, 0, PPC2_ISA300) -GEN_VSX_HELPER_X3(xxpermr, 0x08, 0x07, 0, PPC2_ISA300) + +static bool trans_XXPERM(DisasContext *ctx, arg_XX3 *a) +{ + TCGv_ptr xt, xa, xb; + + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VSX(ctx); + + xt = gen_vsr_ptr(a->xt); + xa = gen_vsr_ptr(a->xa); + xb = gen_vsr_ptr(a->xb); + + gen_helper_VPERM(xt, xa, xt, xb); + return true; +} + +static bool trans_XXPERMR(DisasContext *ctx, arg_XX3 *a) +{ + TCGv_ptr xt, xa, xb; + + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VSX(ctx); + + xt = gen_vsr_ptr(a->xt); + xa = gen_vsr_ptr(a->xa); + xb = gen_vsr_ptr(a->xb); + + gen_helper_VPERMR(xt, xa, xt, xb); + return true; +} + +static bool trans_XXPERMDI(DisasContext *ctx, arg_XX3_dm *a) +{ + TCGv_i64 t0, t1; + + REQUIRE_INSNS_FLAGS2(ctx, VSX); + REQUIRE_VSX(ctx); + + t0 = tcg_temp_new_i64(); + + if (unlikely(a->xt == a->xa || a->xt == a->xb)) { + t1 = tcg_temp_new_i64(); + + get_cpu_vsr(t0, a->xa, (a->dm & 2) == 0); + get_cpu_vsr(t1, a->xb, (a->dm & 1) == 0); + + set_cpu_vsr(a->xt, t0, true); + set_cpu_vsr(a->xt, t1, false); + } else { + get_cpu_vsr(t0, a->xa, (a->dm & 2) == 0); + set_cpu_vsr(a->xt, t0, true); + + get_cpu_vsr(t0, a->xb, (a->dm & 1) == 0); + set_cpu_vsr(a->xt, t0, false); + } + return true; +} + +static bool trans_XXPERMX(DisasContext *ctx, arg_8RR_XX4_uim3 *a) +{ + TCGv_ptr xt, xa, xb, xc; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + + xt = gen_vsr_ptr(a->xt); + xa = gen_vsr_ptr(a->xa); + xb = gen_vsr_ptr(a->xb); + xc = gen_vsr_ptr(a->xc); + + gen_helper_XXPERMX(xt, xa, xb, xc, tcg_constant_tl(a->uim3)); + return true; +} + +typedef void (*xxgenpcv_genfn)(TCGv_ptr, TCGv_ptr); + +static bool do_xxgenpcv(DisasContext *ctx, arg_X_imm5 *a, + const xxgenpcv_genfn fn[4]) +{ + TCGv_ptr xt, vrb; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + + if (a->imm & ~0x3) { + gen_invalid(ctx); + return true; + } + + xt = gen_vsr_ptr(a->xt); + vrb = gen_avr_ptr(a->vrb); + + fn[a->imm](xt, vrb); + return true; +} + +#define XXGENPCV(NAME) \ + static bool trans_##NAME(DisasContext *ctx, arg_X_imm5 *a) \ + { \ + static const xxgenpcv_genfn fn[4] = { \ + gen_helper_##NAME##_be_exp, \ + gen_helper_##NAME##_be_comp, \ + gen_helper_##NAME##_le_exp, \ + gen_helper_##NAME##_le_comp, \ + }; \ + return do_xxgenpcv(ctx, a, fn); \ + } + +XXGENPCV(XXGENPCVBM) +XXGENPCV(XXGENPCVHM) +XXGENPCV(XXGENPCVWM) +XXGENPCV(XXGENPCVDM) +#undef XXGENPCV + +static bool do_xsmadd(DisasContext *ctx, int tgt, int src1, int src2, int src3, + void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr)) +{ + TCGv_ptr t, s1, s2, s3; + + t = gen_vsr_ptr(tgt); + s1 = gen_vsr_ptr(src1); + s2 = gen_vsr_ptr(src2); + s3 = gen_vsr_ptr(src3); + + gen_helper(tcg_env, t, s1, s2, s3); + return true; +} + +static bool do_xsmadd_XX3(DisasContext *ctx, arg_XX3 *a, bool type_a, + void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr)) +{ + REQUIRE_VSX(ctx); + + if (type_a) { + return do_xsmadd(ctx, a->xt, a->xa, a->xt, a->xb, gen_helper); + } + return do_xsmadd(ctx, a->xt, a->xa, a->xb, a->xt, gen_helper); +} + +TRANS_FLAGS2(VSX, XSMADDADP, do_xsmadd_XX3, true, gen_helper_XSMADDDP) +TRANS_FLAGS2(VSX, XSMADDMDP, do_xsmadd_XX3, false, gen_helper_XSMADDDP) +TRANS_FLAGS2(VSX, XSMSUBADP, do_xsmadd_XX3, true, gen_helper_XSMSUBDP) +TRANS_FLAGS2(VSX, XSMSUBMDP, do_xsmadd_XX3, false, gen_helper_XSMSUBDP) +TRANS_FLAGS2(VSX, XSNMADDADP, do_xsmadd_XX3, true, gen_helper_XSNMADDDP) +TRANS_FLAGS2(VSX, XSNMADDMDP, do_xsmadd_XX3, false, gen_helper_XSNMADDDP) +TRANS_FLAGS2(VSX, XSNMSUBADP, do_xsmadd_XX3, true, gen_helper_XSNMSUBDP) +TRANS_FLAGS2(VSX, XSNMSUBMDP, do_xsmadd_XX3, false, gen_helper_XSNMSUBDP) +TRANS_FLAGS2(VSX207, XSMADDASP, do_xsmadd_XX3, true, gen_helper_XSMADDSP) +TRANS_FLAGS2(VSX207, XSMADDMSP, do_xsmadd_XX3, false, gen_helper_XSMADDSP) +TRANS_FLAGS2(VSX207, XSMSUBASP, do_xsmadd_XX3, true, gen_helper_XSMSUBSP) +TRANS_FLAGS2(VSX207, XSMSUBMSP, do_xsmadd_XX3, false, gen_helper_XSMSUBSP) +TRANS_FLAGS2(VSX207, XSNMADDASP, do_xsmadd_XX3, true, gen_helper_XSNMADDSP) +TRANS_FLAGS2(VSX207, XSNMADDMSP, do_xsmadd_XX3, false, gen_helper_XSNMADDSP) +TRANS_FLAGS2(VSX207, XSNMSUBASP, do_xsmadd_XX3, true, gen_helper_XSNMSUBSP) +TRANS_FLAGS2(VSX207, XSNMSUBMSP, do_xsmadd_XX3, false, gen_helper_XSNMSUBSP) + +static bool do_xsmadd_X(DisasContext *ctx, arg_X_rc *a, + void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr), + void (*gen_helper_ro)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr)) +{ + int vrt, vra, vrb; + + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VSX(ctx); + + vrt = a->rt + 32; + vra = a->ra + 32; + vrb = a->rb + 32; + + if (a->rc) { + return do_xsmadd(ctx, vrt, vra, vrt, vrb, gen_helper_ro); + } + + return do_xsmadd(ctx, vrt, vra, vrt, vrb, gen_helper); +} + +TRANS(XSMADDQP, do_xsmadd_X, gen_helper_XSMADDQP, gen_helper_XSMADDQPO) +TRANS(XSMSUBQP, do_xsmadd_X, gen_helper_XSMSUBQP, gen_helper_XSMSUBQPO) +TRANS(XSNMADDQP, do_xsmadd_X, gen_helper_XSNMADDQP, gen_helper_XSNMADDQPO) +TRANS(XSNMSUBQP, do_xsmadd_X, gen_helper_XSNMSUBQP, gen_helper_XSNMSUBQPO) #define GEN_VSX_HELPER_VSX_MADD(name, op1, aop, mop, inval, type) \ static void gen_##name(DisasContext *ctx) \ { \ - TCGv_ptr xt, xa, b, c; \ + TCGv_ptr xt, s1, s2, s3; \ if (unlikely(!ctx->vsx_enabled)) { \ gen_exception(ctx, POWERPC_EXCP_VSXU); \ return; \ } \ xt = gen_vsr_ptr(xT(ctx->opcode)); \ - xa = gen_vsr_ptr(xA(ctx->opcode)); \ + s1 = gen_vsr_ptr(xA(ctx->opcode)); \ if (ctx->opcode & PPC_BIT32(25)) { \ /* \ * AxT + B \ */ \ - b = gen_vsr_ptr(xT(ctx->opcode)); \ - c = gen_vsr_ptr(xB(ctx->opcode)); \ + s2 = gen_vsr_ptr(xB(ctx->opcode)); \ + s3 = gen_vsr_ptr(xT(ctx->opcode)); \ } else { \ /* \ * AxB + T \ */ \ - b = gen_vsr_ptr(xB(ctx->opcode)); \ - c = gen_vsr_ptr(xT(ctx->opcode)); \ + s2 = gen_vsr_ptr(xT(ctx->opcode)); \ + s3 = gen_vsr_ptr(xB(ctx->opcode)); \ } \ - gen_helper_##name(cpu_env, xt, xa, b, c); \ - tcg_temp_free_ptr(xt); \ - tcg_temp_free_ptr(xa); \ - tcg_temp_free_ptr(b); \ - tcg_temp_free_ptr(c); \ -} - -GEN_VSX_HELPER_VSX_MADD(xsmadddp, 0x04, 0x04, 0x05, 0, PPC2_VSX) -GEN_VSX_HELPER_VSX_MADD(xsmsubdp, 0x04, 0x06, 0x07, 0, PPC2_VSX) -GEN_VSX_HELPER_VSX_MADD(xsnmadddp, 0x04, 0x14, 0x15, 0, PPC2_VSX) -GEN_VSX_HELPER_VSX_MADD(xsnmsubdp, 0x04, 0x16, 0x17, 0, PPC2_VSX) -GEN_VSX_HELPER_VSX_MADD(xsmaddsp, 0x04, 0x00, 0x01, 0, PPC2_VSX207) -GEN_VSX_HELPER_VSX_MADD(xsmsubsp, 0x04, 0x02, 0x03, 0, PPC2_VSX207) -GEN_VSX_HELPER_VSX_MADD(xsnmaddsp, 0x04, 0x10, 0x11, 0, PPC2_VSX207) -GEN_VSX_HELPER_VSX_MADD(xsnmsubsp, 0x04, 0x12, 0x13, 0, PPC2_VSX207) + gen_helper_##name(tcg_env, xt, s1, s2, s3); \ +} + GEN_VSX_HELPER_VSX_MADD(xvmadddp, 0x04, 0x0C, 0x0D, 0, PPC2_VSX) GEN_VSX_HELPER_VSX_MADD(xvmsubdp, 0x04, 0x0E, 0x0F, 0, PPC2_VSX) GEN_VSX_HELPER_VSX_MADD(xvnmadddp, 0x04, 0x1C, 0x1D, 0, PPC2_VSX) @@ -1390,18 +1527,13 @@ static void gen_xxbrd(DisasContext *ctx) xtl = tcg_temp_new_i64(); xbh = tcg_temp_new_i64(); xbl = tcg_temp_new_i64(); - get_cpu_vsrh(xbh, xB(ctx->opcode)); - get_cpu_vsrl(xbl, xB(ctx->opcode)); + get_cpu_vsr(xbh, xB(ctx->opcode), true); + get_cpu_vsr(xbl, xB(ctx->opcode), false); tcg_gen_bswap64_i64(xth, xbh); tcg_gen_bswap64_i64(xtl, xbl); - set_cpu_vsrh(xT(ctx->opcode), xth); - set_cpu_vsrl(xT(ctx->opcode), xtl); - - tcg_temp_free_i64(xth); - tcg_temp_free_i64(xtl); - tcg_temp_free_i64(xbh); - tcg_temp_free_i64(xbl); + set_cpu_vsr(xT(ctx->opcode), xth, true); + set_cpu_vsr(xT(ctx->opcode), xtl, false); } static void gen_xxbrh(DisasContext *ctx) @@ -1419,17 +1551,12 @@ static void gen_xxbrh(DisasContext *ctx) xtl = tcg_temp_new_i64(); xbh = tcg_temp_new_i64(); xbl = tcg_temp_new_i64(); - get_cpu_vsrh(xbh, xB(ctx->opcode)); - get_cpu_vsrl(xbl, xB(ctx->opcode)); + get_cpu_vsr(xbh, xB(ctx->opcode), true); + get_cpu_vsr(xbl, xB(ctx->opcode), false); gen_bswap16x8(xth, xtl, xbh, xbl); - set_cpu_vsrh(xT(ctx->opcode), xth); - set_cpu_vsrl(xT(ctx->opcode), xtl); - - tcg_temp_free_i64(xth); - tcg_temp_free_i64(xtl); - tcg_temp_free_i64(xbh); - tcg_temp_free_i64(xbl); + set_cpu_vsr(xT(ctx->opcode), xth, true); + set_cpu_vsr(xT(ctx->opcode), xtl, false); } static void gen_xxbrq(DisasContext *ctx) @@ -1448,21 +1575,15 @@ static void gen_xxbrq(DisasContext *ctx) xtl = tcg_temp_new_i64(); xbh = tcg_temp_new_i64(); xbl = tcg_temp_new_i64(); - get_cpu_vsrh(xbh, xB(ctx->opcode)); - get_cpu_vsrl(xbl, xB(ctx->opcode)); + get_cpu_vsr(xbh, xB(ctx->opcode), true); + get_cpu_vsr(xbl, xB(ctx->opcode), false); t0 = tcg_temp_new_i64(); tcg_gen_bswap64_i64(t0, xbl); tcg_gen_bswap64_i64(xtl, xbh); - set_cpu_vsrl(xT(ctx->opcode), xtl); + set_cpu_vsr(xT(ctx->opcode), xtl, false); tcg_gen_mov_i64(xth, t0); - set_cpu_vsrh(xT(ctx->opcode), xth); - - tcg_temp_free_i64(t0); - tcg_temp_free_i64(xth); - tcg_temp_free_i64(xtl); - tcg_temp_free_i64(xbh); - tcg_temp_free_i64(xbl); + set_cpu_vsr(xT(ctx->opcode), xth, true); } static void gen_xxbrw(DisasContext *ctx) @@ -1480,17 +1601,12 @@ static void gen_xxbrw(DisasContext *ctx) xtl = tcg_temp_new_i64(); xbh = tcg_temp_new_i64(); xbl = tcg_temp_new_i64(); - get_cpu_vsrh(xbh, xB(ctx->opcode)); - get_cpu_vsrl(xbl, xB(ctx->opcode)); + get_cpu_vsr(xbh, xB(ctx->opcode), true); + get_cpu_vsr(xbl, xB(ctx->opcode), false); gen_bswap32x4(xth, xtl, xbh, xbl); - set_cpu_vsrh(xT(ctx->opcode), xth); - set_cpu_vsrl(xT(ctx->opcode), xtl); - - tcg_temp_free_i64(xth); - tcg_temp_free_i64(xtl); - tcg_temp_free_i64(xbh); - tcg_temp_free_i64(xbl); + set_cpu_vsr(xT(ctx->opcode), xth, true); + set_cpu_vsr(xT(ctx->opcode), xtl, false); } #define VSX_LOGICAL(name, vece, tcg_op) \ @@ -1527,89 +1643,173 @@ static void glue(gen_, name)(DisasContext *ctx) \ b0 = tcg_temp_new_i64(); \ b1 = tcg_temp_new_i64(); \ tmp = tcg_temp_new_i64(); \ - if (high) { \ - get_cpu_vsrh(a0, xA(ctx->opcode)); \ - get_cpu_vsrh(a1, xA(ctx->opcode)); \ - get_cpu_vsrh(b0, xB(ctx->opcode)); \ - get_cpu_vsrh(b1, xB(ctx->opcode)); \ - } else { \ - get_cpu_vsrl(a0, xA(ctx->opcode)); \ - get_cpu_vsrl(a1, xA(ctx->opcode)); \ - get_cpu_vsrl(b0, xB(ctx->opcode)); \ - get_cpu_vsrl(b1, xB(ctx->opcode)); \ - } \ + get_cpu_vsr(a0, xA(ctx->opcode), high); \ + get_cpu_vsr(a1, xA(ctx->opcode), high); \ + get_cpu_vsr(b0, xB(ctx->opcode), high); \ + get_cpu_vsr(b1, xB(ctx->opcode), high); \ tcg_gen_shri_i64(a0, a0, 32); \ tcg_gen_shri_i64(b0, b0, 32); \ tcg_gen_deposit_i64(tmp, b0, a0, 32, 32); \ - set_cpu_vsrh(xT(ctx->opcode), tmp); \ + set_cpu_vsr(xT(ctx->opcode), tmp, true); \ tcg_gen_deposit_i64(tmp, b1, a1, 32, 32); \ - set_cpu_vsrl(xT(ctx->opcode), tmp); \ - tcg_temp_free_i64(a0); \ - tcg_temp_free_i64(a1); \ - tcg_temp_free_i64(b0); \ - tcg_temp_free_i64(b1); \ - tcg_temp_free_i64(tmp); \ + set_cpu_vsr(xT(ctx->opcode), tmp, false); \ } VSX_XXMRG(xxmrghw, 1) VSX_XXMRG(xxmrglw, 0) -static void gen_xxsel(DisasContext *ctx) +static bool trans_XXSEL(DisasContext *ctx, arg_XX4 *a) { - int rt = xT(ctx->opcode); - int ra = xA(ctx->opcode); - int rb = xB(ctx->opcode); - int rc = xC(ctx->opcode); + REQUIRE_INSNS_FLAGS2(ctx, VSX); + REQUIRE_VSX(ctx); - if (unlikely(!ctx->vsx_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VSXU); - return; - } - tcg_gen_gvec_bitsel(MO_64, vsr_full_offset(rt), vsr_full_offset(rc), - vsr_full_offset(rb), vsr_full_offset(ra), 16, 16); + tcg_gen_gvec_bitsel(MO_64, vsr_full_offset(a->xt), vsr_full_offset(a->xc), + vsr_full_offset(a->xb), vsr_full_offset(a->xa), 16, 16); + + return true; } -static void gen_xxspltw(DisasContext *ctx) +static bool trans_XXSPLTW(DisasContext *ctx, arg_XX2_uim *a) { - int rt = xT(ctx->opcode); - int rb = xB(ctx->opcode); - int uim = UIM(ctx->opcode); int tofs, bofs; - if (unlikely(!ctx->vsx_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VSXU); - return; - } + REQUIRE_VSX(ctx); - tofs = vsr_full_offset(rt); - bofs = vsr_full_offset(rb); - bofs += uim << MO_32; -#ifndef HOST_WORDS_BIG_ENDIAN + tofs = vsr_full_offset(a->xt); + bofs = vsr_full_offset(a->xb); + bofs += a->uim << MO_32; +#if !HOST_BIG_ENDIAN bofs ^= 8 | 4; #endif tcg_gen_gvec_dup_mem(MO_32, tofs, bofs, 16, 16); + return true; } #define pattern(x) (((x) & 0xff) * (~(uint64_t)0 / 0xff)) -static void gen_xxspltib(DisasContext *ctx) +static bool trans_XXSPLTIB(DisasContext *ctx, arg_X_imm8 *a) { - uint8_t uim8 = IMM8(ctx->opcode); - int rt = xT(ctx->opcode); + if (a->xt < 32) { + REQUIRE_VSX(ctx); + } else { + REQUIRE_VECTOR(ctx); + } + tcg_gen_gvec_dup_imm(MO_8, vsr_full_offset(a->xt), 16, 16, a->imm); + return true; +} - if (rt < 32) { - if (unlikely(!ctx->vsx_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VSXU); - return; - } +static bool trans_XXSPLTIW(DisasContext *ctx, arg_8RR_D *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + + tcg_gen_gvec_dup_imm(MO_32, vsr_full_offset(a->xt), 16, 16, a->si); + + return true; +} + +static bool trans_XXSPLTIDP(DisasContext *ctx, arg_8RR_D *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + + tcg_gen_gvec_dup_imm(MO_64, vsr_full_offset(a->xt), 16, 16, + helper_todouble(a->si)); + return true; +} + +static bool trans_XXSPLTI32DX(DisasContext *ctx, arg_8RR_D_IX *a) +{ + TCGv_i32 imm; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + + imm = tcg_constant_i32(a->si); + + tcg_gen_st_i32(imm, tcg_env, + offsetof(CPUPPCState, vsr[a->xt].VsrW(0 + a->ix))); + tcg_gen_st_i32(imm, tcg_env, + offsetof(CPUPPCState, vsr[a->xt].VsrW(2 + a->ix))); + + return true; +} + +static bool trans_LXVKQ(DisasContext *ctx, arg_X_uim5 *a) +{ + static const uint64_t values[32] = { + 0, /* Unspecified */ + 0x3FFF000000000000llu, /* QP +1.0 */ + 0x4000000000000000llu, /* QP +2.0 */ + 0x4000800000000000llu, /* QP +3.0 */ + 0x4001000000000000llu, /* QP +4.0 */ + 0x4001400000000000llu, /* QP +5.0 */ + 0x4001800000000000llu, /* QP +6.0 */ + 0x4001C00000000000llu, /* QP +7.0 */ + 0x7FFF000000000000llu, /* QP +Inf */ + 0x7FFF800000000000llu, /* QP dQNaN */ + 0, /* Unspecified */ + 0, /* Unspecified */ + 0, /* Unspecified */ + 0, /* Unspecified */ + 0, /* Unspecified */ + 0, /* Unspecified */ + 0x8000000000000000llu, /* QP -0.0 */ + 0xBFFF000000000000llu, /* QP -1.0 */ + 0xC000000000000000llu, /* QP -2.0 */ + 0xC000800000000000llu, /* QP -3.0 */ + 0xC001000000000000llu, /* QP -4.0 */ + 0xC001400000000000llu, /* QP -5.0 */ + 0xC001800000000000llu, /* QP -6.0 */ + 0xC001C00000000000llu, /* QP -7.0 */ + 0xFFFF000000000000llu, /* QP -Inf */ + }; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + + if (values[a->uim]) { + set_cpu_vsr(a->xt, tcg_constant_i64(0x0), false); + set_cpu_vsr(a->xt, tcg_constant_i64(values[a->uim]), true); } else { - if (unlikely(!ctx->altivec_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VPU); - return; - } + gen_invalid(ctx); } - tcg_gen_gvec_dup_imm(MO_8, vsr_full_offset(rt), 16, 16, uim8); + + return true; +} + +static bool trans_XVTLSBB(DisasContext *ctx, arg_XX2_bf_xb *a) +{ + TCGv_i64 xb, t0, t1, all_true, all_false, mask, zero; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + + xb = tcg_temp_new_i64(); + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + all_true = tcg_temp_new_i64(); + all_false = tcg_temp_new_i64(); + mask = tcg_constant_i64(dup_const(MO_8, 1)); + zero = tcg_constant_i64(0); + + get_cpu_vsr(xb, a->xb, true); + tcg_gen_and_i64(t0, mask, xb); + get_cpu_vsr(xb, a->xb, false); + tcg_gen_and_i64(t1, mask, xb); + + tcg_gen_or_i64(all_false, t0, t1); + tcg_gen_and_i64(all_true, t0, t1); + + tcg_gen_setcond_i64(TCG_COND_EQ, all_false, all_false, zero); + tcg_gen_shli_i64(all_false, all_false, 1); + tcg_gen_setcond_i64(TCG_COND_EQ, all_true, all_true, mask); + tcg_gen_shli_i64(all_true, all_true, 3); + + tcg_gen_or_i64(t0, all_false, all_true); + tcg_gen_extrl_i64_i32(cpu_crf[a->bf], t0); + return true; } static void gen_xxsldwi(DisasContext *ctx) @@ -1624,90 +1824,75 @@ static void gen_xxsldwi(DisasContext *ctx) switch (SHW(ctx->opcode)) { case 0: { - get_cpu_vsrh(xth, xA(ctx->opcode)); - get_cpu_vsrl(xtl, xA(ctx->opcode)); + get_cpu_vsr(xth, xA(ctx->opcode), true); + get_cpu_vsr(xtl, xA(ctx->opcode), false); break; } case 1: { TCGv_i64 t0 = tcg_temp_new_i64(); - get_cpu_vsrh(xth, xA(ctx->opcode)); + get_cpu_vsr(xth, xA(ctx->opcode), true); tcg_gen_shli_i64(xth, xth, 32); - get_cpu_vsrl(t0, xA(ctx->opcode)); + get_cpu_vsr(t0, xA(ctx->opcode), false); tcg_gen_shri_i64(t0, t0, 32); tcg_gen_or_i64(xth, xth, t0); - get_cpu_vsrl(xtl, xA(ctx->opcode)); + get_cpu_vsr(xtl, xA(ctx->opcode), false); tcg_gen_shli_i64(xtl, xtl, 32); - get_cpu_vsrh(t0, xB(ctx->opcode)); + get_cpu_vsr(t0, xB(ctx->opcode), true); tcg_gen_shri_i64(t0, t0, 32); tcg_gen_or_i64(xtl, xtl, t0); - tcg_temp_free_i64(t0); break; } case 2: { - get_cpu_vsrl(xth, xA(ctx->opcode)); - get_cpu_vsrh(xtl, xB(ctx->opcode)); + get_cpu_vsr(xth, xA(ctx->opcode), false); + get_cpu_vsr(xtl, xB(ctx->opcode), true); break; } case 3: { TCGv_i64 t0 = tcg_temp_new_i64(); - get_cpu_vsrl(xth, xA(ctx->opcode)); + get_cpu_vsr(xth, xA(ctx->opcode), false); tcg_gen_shli_i64(xth, xth, 32); - get_cpu_vsrh(t0, xB(ctx->opcode)); + get_cpu_vsr(t0, xB(ctx->opcode), true); tcg_gen_shri_i64(t0, t0, 32); tcg_gen_or_i64(xth, xth, t0); - get_cpu_vsrh(xtl, xB(ctx->opcode)); + get_cpu_vsr(xtl, xB(ctx->opcode), true); tcg_gen_shli_i64(xtl, xtl, 32); - get_cpu_vsrl(t0, xB(ctx->opcode)); + get_cpu_vsr(t0, xB(ctx->opcode), false); tcg_gen_shri_i64(t0, t0, 32); tcg_gen_or_i64(xtl, xtl, t0); - tcg_temp_free_i64(t0); break; } } - set_cpu_vsrh(xT(ctx->opcode), xth); - set_cpu_vsrl(xT(ctx->opcode), xtl); - - tcg_temp_free_i64(xth); - tcg_temp_free_i64(xtl); -} - -#define VSX_EXTRACT_INSERT(name) \ -static void gen_##name(DisasContext *ctx) \ -{ \ - TCGv_ptr xt, xb; \ - TCGv_i32 t0; \ - TCGv_i64 t1; \ - uint8_t uimm = UIMM4(ctx->opcode); \ - \ - if (unlikely(!ctx->vsx_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VSXU); \ - return; \ - } \ - xt = gen_vsr_ptr(xT(ctx->opcode)); \ - xb = gen_vsr_ptr(xB(ctx->opcode)); \ - t0 = tcg_temp_new_i32(); \ - t1 = tcg_temp_new_i64(); \ - /* \ - * uimm > 15 out of bound and for \ - * uimm > 12 handle as per hardware in helper \ - */ \ - if (uimm > 15) { \ - tcg_gen_movi_i64(t1, 0); \ - set_cpu_vsrh(xT(ctx->opcode), t1); \ - set_cpu_vsrl(xT(ctx->opcode), t1); \ - return; \ - } \ - tcg_gen_movi_i32(t0, uimm); \ - gen_helper_##name(cpu_env, xt, xb, t0); \ - tcg_temp_free_ptr(xb); \ - tcg_temp_free_ptr(xt); \ - tcg_temp_free_i32(t0); \ - tcg_temp_free_i64(t1); \ -} - -VSX_EXTRACT_INSERT(xxextractuw) -VSX_EXTRACT_INSERT(xxinsertw) + set_cpu_vsr(xT(ctx->opcode), xth, true); + set_cpu_vsr(xT(ctx->opcode), xtl, false); +} + +static bool do_vsx_extract_insert(DisasContext *ctx, arg_XX2_uim *a, + void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_i32)) +{ + TCGv_i64 zero = tcg_constant_i64(0); + TCGv_ptr xt, xb; + + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VSX(ctx); + + /* + * uim > 15 out of bound and for + * uim > 12 handle as per hardware in helper + */ + if (a->uim > 15) { + set_cpu_vsr(a->xt, zero, true); + set_cpu_vsr(a->xt, zero, false); + } else { + xt = gen_vsr_ptr(a->xt); + xb = gen_vsr_ptr(a->xb); + gen_helper(xt, xb, tcg_constant_i32(a->uim)); + } + return true; +} + +TRANS(XXEXTRACTUW, do_vsx_extract_insert, gen_helper_XXEXTRACTUW) +TRANS(XXINSERTW, do_vsx_extract_insert, gen_helper_XXINSERTW) #ifdef TARGET_PPC64 static void gen_xsxexpdp(DisasContext *ctx) @@ -1719,9 +1904,8 @@ static void gen_xsxexpdp(DisasContext *ctx) return; } t0 = tcg_temp_new_i64(); - get_cpu_vsrh(t0, xB(ctx->opcode)); + get_cpu_vsr(t0, xB(ctx->opcode), true); tcg_gen_extract_i64(rt, t0, 52, 11); - tcg_temp_free_i64(t0); } static void gen_xsxexpqp(DisasContext *ctx) @@ -1737,16 +1921,12 @@ static void gen_xsxexpqp(DisasContext *ctx) xth = tcg_temp_new_i64(); xtl = tcg_temp_new_i64(); xbh = tcg_temp_new_i64(); - get_cpu_vsrh(xbh, rB(ctx->opcode) + 32); + get_cpu_vsr(xbh, rB(ctx->opcode) + 32, true); tcg_gen_extract_i64(xth, xbh, 48, 15); - set_cpu_vsrh(rD(ctx->opcode) + 32, xth); + set_cpu_vsr(rD(ctx->opcode) + 32, xth, true); tcg_gen_movi_i64(xtl, 0); - set_cpu_vsrl(rD(ctx->opcode) + 32, xtl); - - tcg_temp_free_i64(xbh); - tcg_temp_free_i64(xth); - tcg_temp_free_i64(xtl); + set_cpu_vsr(rD(ctx->opcode) + 32, xtl, false); } static void gen_xsiexpdp(DisasContext *ctx) @@ -1766,10 +1946,8 @@ static void gen_xsiexpdp(DisasContext *ctx) tcg_gen_andi_i64(t0, rb, 0x7FF); tcg_gen_shli_i64(t0, t0, 52); tcg_gen_or_i64(xth, xth, t0); - set_cpu_vsrh(xT(ctx->opcode), xth); - /* dword[1] is undefined */ - tcg_temp_free_i64(t0); - tcg_temp_free_i64(xth); + set_cpu_vsr(xT(ctx->opcode), xth, true); + set_cpu_vsr(xT(ctx->opcode), tcg_constant_i64(0), false); } static void gen_xsiexpqp(DisasContext *ctx) @@ -1789,26 +1967,19 @@ static void gen_xsiexpqp(DisasContext *ctx) xtl = tcg_temp_new_i64(); xah = tcg_temp_new_i64(); xal = tcg_temp_new_i64(); - get_cpu_vsrh(xah, rA(ctx->opcode) + 32); - get_cpu_vsrl(xal, rA(ctx->opcode) + 32); + get_cpu_vsr(xah, rA(ctx->opcode) + 32, true); + get_cpu_vsr(xal, rA(ctx->opcode) + 32, false); xbh = tcg_temp_new_i64(); - get_cpu_vsrh(xbh, rB(ctx->opcode) + 32); + get_cpu_vsr(xbh, rB(ctx->opcode) + 32, true); t0 = tcg_temp_new_i64(); tcg_gen_andi_i64(xth, xah, 0x8000FFFFFFFFFFFF); tcg_gen_andi_i64(t0, xbh, 0x7FFF); tcg_gen_shli_i64(t0, t0, 48); tcg_gen_or_i64(xth, xth, t0); - set_cpu_vsrh(rD(ctx->opcode) + 32, xth); + set_cpu_vsr(rD(ctx->opcode) + 32, xth, true); tcg_gen_mov_i64(xtl, xal); - set_cpu_vsrl(rD(ctx->opcode) + 32, xtl); - - tcg_temp_free_i64(t0); - tcg_temp_free_i64(xth); - tcg_temp_free_i64(xtl); - tcg_temp_free_i64(xah); - tcg_temp_free_i64(xal); - tcg_temp_free_i64(xbh); + set_cpu_vsr(rD(ctx->opcode) + 32, xtl, false); } static void gen_xsxsigdp(DisasContext *ctx) @@ -1823,22 +1994,16 @@ static void gen_xsxsigdp(DisasContext *ctx) exp = tcg_temp_new_i64(); t0 = tcg_temp_new_i64(); t1 = tcg_temp_new_i64(); - zr = tcg_const_i64(0); - nan = tcg_const_i64(2047); + zr = tcg_constant_i64(0); + nan = tcg_constant_i64(2047); - get_cpu_vsrh(t1, xB(ctx->opcode)); + get_cpu_vsr(t1, xB(ctx->opcode), true); tcg_gen_extract_i64(exp, t1, 52, 11); tcg_gen_movi_i64(t0, 0x0010000000000000); tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, zr, zr, t0); tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, nan, zr, t0); - get_cpu_vsrh(t1, xB(ctx->opcode)); + get_cpu_vsr(t1, xB(ctx->opcode), true); tcg_gen_deposit_i64(rt, t0, t1, 0, 52); - - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); - tcg_temp_free_i64(exp); - tcg_temp_free_i64(zr); - tcg_temp_free_i64(nan); } static void gen_xsxsigqp(DisasContext *ctx) @@ -1857,30 +2022,21 @@ static void gen_xsxsigqp(DisasContext *ctx) xtl = tcg_temp_new_i64(); xbh = tcg_temp_new_i64(); xbl = tcg_temp_new_i64(); - get_cpu_vsrh(xbh, rB(ctx->opcode) + 32); - get_cpu_vsrl(xbl, rB(ctx->opcode) + 32); + get_cpu_vsr(xbh, rB(ctx->opcode) + 32, true); + get_cpu_vsr(xbl, rB(ctx->opcode) + 32, false); exp = tcg_temp_new_i64(); t0 = tcg_temp_new_i64(); - zr = tcg_const_i64(0); - nan = tcg_const_i64(32767); + zr = tcg_constant_i64(0); + nan = tcg_constant_i64(32767); tcg_gen_extract_i64(exp, xbh, 48, 15); tcg_gen_movi_i64(t0, 0x0001000000000000); tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, zr, zr, t0); tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, nan, zr, t0); tcg_gen_deposit_i64(xth, t0, xbh, 0, 48); - set_cpu_vsrh(rD(ctx->opcode) + 32, xth); + set_cpu_vsr(rD(ctx->opcode) + 32, xth, true); tcg_gen_mov_i64(xtl, xbl); - set_cpu_vsrl(rD(ctx->opcode) + 32, xtl); - - tcg_temp_free_i64(t0); - tcg_temp_free_i64(exp); - tcg_temp_free_i64(zr); - tcg_temp_free_i64(nan); - tcg_temp_free_i64(xth); - tcg_temp_free_i64(xtl); - tcg_temp_free_i64(xbh); - tcg_temp_free_i64(xbl); + set_cpu_vsr(rD(ctx->opcode) + 32, xtl, false); } #endif @@ -1904,30 +2060,22 @@ static void gen_xviexpsp(DisasContext *ctx) xal = tcg_temp_new_i64(); xbh = tcg_temp_new_i64(); xbl = tcg_temp_new_i64(); - get_cpu_vsrh(xah, xA(ctx->opcode)); - get_cpu_vsrl(xal, xA(ctx->opcode)); - get_cpu_vsrh(xbh, xB(ctx->opcode)); - get_cpu_vsrl(xbl, xB(ctx->opcode)); + get_cpu_vsr(xah, xA(ctx->opcode), true); + get_cpu_vsr(xal, xA(ctx->opcode), false); + get_cpu_vsr(xbh, xB(ctx->opcode), true); + get_cpu_vsr(xbl, xB(ctx->opcode), false); t0 = tcg_temp_new_i64(); tcg_gen_andi_i64(xth, xah, 0x807FFFFF807FFFFF); tcg_gen_andi_i64(t0, xbh, 0xFF000000FF); tcg_gen_shli_i64(t0, t0, 23); tcg_gen_or_i64(xth, xth, t0); - set_cpu_vsrh(xT(ctx->opcode), xth); + set_cpu_vsr(xT(ctx->opcode), xth, true); tcg_gen_andi_i64(xtl, xal, 0x807FFFFF807FFFFF); tcg_gen_andi_i64(t0, xbl, 0xFF000000FF); tcg_gen_shli_i64(t0, t0, 23); tcg_gen_or_i64(xtl, xtl, t0); - set_cpu_vsrl(xT(ctx->opcode), xtl); - - tcg_temp_free_i64(t0); - tcg_temp_free_i64(xth); - tcg_temp_free_i64(xtl); - tcg_temp_free_i64(xah); - tcg_temp_free_i64(xal); - tcg_temp_free_i64(xbh); - tcg_temp_free_i64(xbl); + set_cpu_vsr(xT(ctx->opcode), xtl, false); } static void gen_xviexpdp(DisasContext *ctx) @@ -1949,23 +2097,16 @@ static void gen_xviexpdp(DisasContext *ctx) xal = tcg_temp_new_i64(); xbh = tcg_temp_new_i64(); xbl = tcg_temp_new_i64(); - get_cpu_vsrh(xah, xA(ctx->opcode)); - get_cpu_vsrl(xal, xA(ctx->opcode)); - get_cpu_vsrh(xbh, xB(ctx->opcode)); - get_cpu_vsrl(xbl, xB(ctx->opcode)); + get_cpu_vsr(xah, xA(ctx->opcode), true); + get_cpu_vsr(xal, xA(ctx->opcode), false); + get_cpu_vsr(xbh, xB(ctx->opcode), true); + get_cpu_vsr(xbl, xB(ctx->opcode), false); tcg_gen_deposit_i64(xth, xah, xbh, 52, 11); - set_cpu_vsrh(xT(ctx->opcode), xth); + set_cpu_vsr(xT(ctx->opcode), xth, true); tcg_gen_deposit_i64(xtl, xal, xbl, 52, 11); - set_cpu_vsrl(xT(ctx->opcode), xtl); - - tcg_temp_free_i64(xth); - tcg_temp_free_i64(xtl); - tcg_temp_free_i64(xah); - tcg_temp_free_i64(xal); - tcg_temp_free_i64(xbh); - tcg_temp_free_i64(xbl); + set_cpu_vsr(xT(ctx->opcode), xtl, false); } static void gen_xvxexpsp(DisasContext *ctx) @@ -1983,20 +2124,15 @@ static void gen_xvxexpsp(DisasContext *ctx) xtl = tcg_temp_new_i64(); xbh = tcg_temp_new_i64(); xbl = tcg_temp_new_i64(); - get_cpu_vsrh(xbh, xB(ctx->opcode)); - get_cpu_vsrl(xbl, xB(ctx->opcode)); + get_cpu_vsr(xbh, xB(ctx->opcode), true); + get_cpu_vsr(xbl, xB(ctx->opcode), false); tcg_gen_shri_i64(xth, xbh, 23); tcg_gen_andi_i64(xth, xth, 0xFF000000FF); - set_cpu_vsrh(xT(ctx->opcode), xth); + set_cpu_vsr(xT(ctx->opcode), xth, true); tcg_gen_shri_i64(xtl, xbl, 23); tcg_gen_andi_i64(xtl, xtl, 0xFF000000FF); - set_cpu_vsrl(xT(ctx->opcode), xtl); - - tcg_temp_free_i64(xth); - tcg_temp_free_i64(xtl); - tcg_temp_free_i64(xbh); - tcg_temp_free_i64(xbl); + set_cpu_vsr(xT(ctx->opcode), xtl, false); } static void gen_xvxexpdp(DisasContext *ctx) @@ -2014,21 +2150,28 @@ static void gen_xvxexpdp(DisasContext *ctx) xtl = tcg_temp_new_i64(); xbh = tcg_temp_new_i64(); xbl = tcg_temp_new_i64(); - get_cpu_vsrh(xbh, xB(ctx->opcode)); - get_cpu_vsrl(xbl, xB(ctx->opcode)); + get_cpu_vsr(xbh, xB(ctx->opcode), true); + get_cpu_vsr(xbl, xB(ctx->opcode), false); tcg_gen_extract_i64(xth, xbh, 52, 11); - set_cpu_vsrh(xT(ctx->opcode), xth); + set_cpu_vsr(xT(ctx->opcode), xth, true); tcg_gen_extract_i64(xtl, xbl, 52, 11); - set_cpu_vsrl(xT(ctx->opcode), xtl); - - tcg_temp_free_i64(xth); - tcg_temp_free_i64(xtl); - tcg_temp_free_i64(xbh); - tcg_temp_free_i64(xbl); + set_cpu_vsr(xT(ctx->opcode), xtl, false); } -GEN_VSX_HELPER_X2(xvxsigsp, 0x00, 0x04, 0, PPC2_ISA300) +static bool trans_XVXSIGSP(DisasContext *ctx, arg_XX2 *a) +{ + TCGv_ptr t, b; + + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VSX(ctx); + + t = gen_vsr_ptr(a->xt); + b = gen_vsr_ptr(a->xb); + + gen_helper_XVXSIGSP(t, b); + return true; +} static void gen_xvxsigdp(DisasContext *ctx) { @@ -2046,37 +2189,722 @@ static void gen_xvxsigdp(DisasContext *ctx) xtl = tcg_temp_new_i64(); xbh = tcg_temp_new_i64(); xbl = tcg_temp_new_i64(); - get_cpu_vsrh(xbh, xB(ctx->opcode)); - get_cpu_vsrl(xbl, xB(ctx->opcode)); + get_cpu_vsr(xbh, xB(ctx->opcode), true); + get_cpu_vsr(xbl, xB(ctx->opcode), false); exp = tcg_temp_new_i64(); t0 = tcg_temp_new_i64(); - zr = tcg_const_i64(0); - nan = tcg_const_i64(2047); + zr = tcg_constant_i64(0); + nan = tcg_constant_i64(2047); tcg_gen_extract_i64(exp, xbh, 52, 11); tcg_gen_movi_i64(t0, 0x0010000000000000); tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, zr, zr, t0); tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, nan, zr, t0); tcg_gen_deposit_i64(xth, t0, xbh, 0, 52); - set_cpu_vsrh(xT(ctx->opcode), xth); + set_cpu_vsr(xT(ctx->opcode), xth, true); tcg_gen_extract_i64(exp, xbl, 52, 11); tcg_gen_movi_i64(t0, 0x0010000000000000); tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, zr, zr, t0); tcg_gen_movcond_i64(TCG_COND_EQ, t0, exp, nan, zr, t0); tcg_gen_deposit_i64(xtl, t0, xbl, 0, 52); - set_cpu_vsrl(xT(ctx->opcode), xtl); + set_cpu_vsr(xT(ctx->opcode), xtl, false); +} + +static bool do_lstxv(DisasContext *ctx, int ra, TCGv displ, + int rt, bool store, bool paired) +{ + TCGv ea; + TCGv_i64 xt; + MemOp mop; + int rt1, rt2; + + xt = tcg_temp_new_i64(); + + mop = DEF_MEMOP(MO_UQ); + + gen_set_access_type(ctx, ACCESS_INT); + ea = do_ea_calc(ctx, ra, displ); + + if (paired && ctx->le_mode) { + rt1 = rt + 1; + rt2 = rt; + } else { + rt1 = rt; + rt2 = rt + 1; + } + + if (store) { + get_cpu_vsr(xt, rt1, !ctx->le_mode); + tcg_gen_qemu_st_i64(xt, ea, ctx->mem_idx, mop); + gen_addr_add(ctx, ea, ea, 8); + get_cpu_vsr(xt, rt1, ctx->le_mode); + tcg_gen_qemu_st_i64(xt, ea, ctx->mem_idx, mop); + if (paired) { + gen_addr_add(ctx, ea, ea, 8); + get_cpu_vsr(xt, rt2, !ctx->le_mode); + tcg_gen_qemu_st_i64(xt, ea, ctx->mem_idx, mop); + gen_addr_add(ctx, ea, ea, 8); + get_cpu_vsr(xt, rt2, ctx->le_mode); + tcg_gen_qemu_st_i64(xt, ea, ctx->mem_idx, mop); + } + } else { + tcg_gen_qemu_ld_i64(xt, ea, ctx->mem_idx, mop); + set_cpu_vsr(rt1, xt, !ctx->le_mode); + gen_addr_add(ctx, ea, ea, 8); + tcg_gen_qemu_ld_i64(xt, ea, ctx->mem_idx, mop); + set_cpu_vsr(rt1, xt, ctx->le_mode); + if (paired) { + gen_addr_add(ctx, ea, ea, 8); + tcg_gen_qemu_ld_i64(xt, ea, ctx->mem_idx, mop); + set_cpu_vsr(rt2, xt, !ctx->le_mode); + gen_addr_add(ctx, ea, ea, 8); + tcg_gen_qemu_ld_i64(xt, ea, ctx->mem_idx, mop); + set_cpu_vsr(rt2, xt, ctx->le_mode); + } + } + return true; +} + +static bool do_lstxv_D(DisasContext *ctx, arg_D *a, bool store, bool paired) +{ + if (paired || a->rt < 32) { + REQUIRE_VSX(ctx); + } else { + REQUIRE_VECTOR(ctx); + } + + return do_lstxv(ctx, a->ra, tcg_constant_tl(a->si), a->rt, store, paired); +} + +static bool do_lstxv_PLS_D(DisasContext *ctx, arg_PLS_D *a, + bool store, bool paired) +{ + arg_D d; + REQUIRE_VSX(ctx); + + if (!resolve_PLS_D(ctx, &d, a)) { + return true; + } + + return do_lstxv(ctx, d.ra, tcg_constant_tl(d.si), d.rt, store, paired); +} + +static bool do_lstxv_X(DisasContext *ctx, arg_X *a, bool store, bool paired) +{ + if (paired || a->rt >= 32) { + REQUIRE_VSX(ctx); + } else { + REQUIRE_VECTOR(ctx); + } + + return do_lstxv(ctx, a->ra, cpu_gpr[a->rb], a->rt, store, paired); +} + +static bool do_lstxsd(DisasContext *ctx, int rt, int ra, TCGv displ, bool store) +{ + TCGv ea; + TCGv_i64 xt; + MemOp mop; + + if (store) { + REQUIRE_VECTOR(ctx); + } else { + REQUIRE_VSX(ctx); + } + + xt = tcg_temp_new_i64(); + mop = DEF_MEMOP(MO_UQ); + + gen_set_access_type(ctx, ACCESS_INT); + ea = do_ea_calc(ctx, ra, displ); + + if (store) { + get_cpu_vsr(xt, rt + 32, true); + tcg_gen_qemu_st_i64(xt, ea, ctx->mem_idx, mop); + } else { + tcg_gen_qemu_ld_i64(xt, ea, ctx->mem_idx, mop); + set_cpu_vsr(rt + 32, xt, true); + set_cpu_vsr(rt + 32, tcg_constant_i64(0), false); + } + return true; +} + +static bool do_lstxsd_DS(DisasContext *ctx, arg_D *a, bool store) +{ + return do_lstxsd(ctx, a->rt, a->ra, tcg_constant_tl(a->si), store); +} + +static bool do_plstxsd_PLS_D(DisasContext *ctx, arg_PLS_D *a, bool store) +{ + arg_D d; + + if (!resolve_PLS_D(ctx, &d, a)) { + return true; + } + + return do_lstxsd(ctx, d.rt, d.ra, tcg_constant_tl(d.si), store); +} + +static bool do_lstxssp(DisasContext *ctx, int rt, int ra, TCGv displ, bool store) +{ + TCGv ea; + TCGv_i64 xt; + + REQUIRE_VECTOR(ctx); + + xt = tcg_temp_new_i64(); + + gen_set_access_type(ctx, ACCESS_INT); + ea = do_ea_calc(ctx, ra, displ); + + if (store) { + get_cpu_vsr(xt, rt + 32, true); + gen_qemu_st32fs(ctx, xt, ea); + } else { + gen_qemu_ld32fs(ctx, xt, ea); + set_cpu_vsr(rt + 32, xt, true); + set_cpu_vsr(rt + 32, tcg_constant_i64(0), false); + } + return true; +} + +static bool do_lstxssp_DS(DisasContext *ctx, arg_D *a, bool store) +{ + return do_lstxssp(ctx, a->rt, a->ra, tcg_constant_tl(a->si), store); +} + +static bool do_plstxssp_PLS_D(DisasContext *ctx, arg_PLS_D *a, bool store) +{ + arg_D d; + + if (!resolve_PLS_D(ctx, &d, a)) { + return true; + } + + return do_lstxssp(ctx, d.rt, d.ra, tcg_constant_tl(d.si), store); +} + +TRANS_FLAGS2(ISA300, LXSD, do_lstxsd_DS, false) +TRANS_FLAGS2(ISA300, STXSD, do_lstxsd_DS, true) +TRANS_FLAGS2(ISA300, LXSSP, do_lstxssp_DS, false) +TRANS_FLAGS2(ISA300, STXSSP, do_lstxssp_DS, true) +TRANS_FLAGS2(ISA300, STXV, do_lstxv_D, true, false) +TRANS_FLAGS2(ISA300, LXV, do_lstxv_D, false, false) +TRANS_FLAGS2(ISA310, STXVP, do_lstxv_D, true, true) +TRANS_FLAGS2(ISA310, LXVP, do_lstxv_D, false, true) +TRANS_FLAGS2(ISA300, STXVX, do_lstxv_X, true, false) +TRANS_FLAGS2(ISA300, LXVX, do_lstxv_X, false, false) +TRANS_FLAGS2(ISA310, STXVPX, do_lstxv_X, true, true) +TRANS_FLAGS2(ISA310, LXVPX, do_lstxv_X, false, true) +TRANS64_FLAGS2(ISA310, PLXSD, do_plstxsd_PLS_D, false) +TRANS64_FLAGS2(ISA310, PSTXSD, do_plstxsd_PLS_D, true) +TRANS64_FLAGS2(ISA310, PLXSSP, do_plstxssp_PLS_D, false) +TRANS64_FLAGS2(ISA310, PSTXSSP, do_plstxssp_PLS_D, true) +TRANS64_FLAGS2(ISA310, PSTXV, do_lstxv_PLS_D, true, false) +TRANS64_FLAGS2(ISA310, PLXV, do_lstxv_PLS_D, false, false) +TRANS64_FLAGS2(ISA310, PSTXVP, do_lstxv_PLS_D, true, true) +TRANS64_FLAGS2(ISA310, PLXVP, do_lstxv_PLS_D, false, true) + +static bool do_lstrm(DisasContext *ctx, arg_X *a, MemOp mop, bool store) +{ + TCGv ea; + TCGv_i64 xt; + + REQUIRE_VSX(ctx); + + xt = tcg_temp_new_i64(); + + gen_set_access_type(ctx, ACCESS_INT); + ea = do_ea_calc(ctx, a->ra , cpu_gpr[a->rb]); - tcg_temp_free_i64(t0); - tcg_temp_free_i64(exp); - tcg_temp_free_i64(zr); - tcg_temp_free_i64(nan); - tcg_temp_free_i64(xth); - tcg_temp_free_i64(xtl); - tcg_temp_free_i64(xbh); - tcg_temp_free_i64(xbl); + if (store) { + get_cpu_vsr(xt, a->rt, false); + tcg_gen_qemu_st_i64(xt, ea, ctx->mem_idx, mop); + } else { + tcg_gen_qemu_ld_i64(xt, ea, ctx->mem_idx, mop); + set_cpu_vsr(a->rt, xt, false); + set_cpu_vsr(a->rt, tcg_constant_i64(0), true); + } + return true; } +TRANS_FLAGS2(ISA310, LXVRBX, do_lstrm, DEF_MEMOP(MO_UB), false) +TRANS_FLAGS2(ISA310, LXVRHX, do_lstrm, DEF_MEMOP(MO_UW), false) +TRANS_FLAGS2(ISA310, LXVRWX, do_lstrm, DEF_MEMOP(MO_UL), false) +TRANS_FLAGS2(ISA310, LXVRDX, do_lstrm, DEF_MEMOP(MO_UQ), false) +TRANS_FLAGS2(ISA310, STXVRBX, do_lstrm, DEF_MEMOP(MO_UB), true) +TRANS_FLAGS2(ISA310, STXVRHX, do_lstrm, DEF_MEMOP(MO_UW), true) +TRANS_FLAGS2(ISA310, STXVRWX, do_lstrm, DEF_MEMOP(MO_UL), true) +TRANS_FLAGS2(ISA310, STXVRDX, do_lstrm, DEF_MEMOP(MO_UQ), true) + +static void gen_xxeval_i64(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b, TCGv_i64 c, + int64_t imm) +{ + /* + * Instead of processing imm bit-by-bit, we'll skip the computation of + * conjunctions whose corresponding bit is unset. + */ + int bit; + TCGv_i64 conj, disj; + + conj = tcg_temp_new_i64(); + disj = tcg_temp_new_i64(); + tcg_gen_movi_i64(disj, 0); + + /* Iterate over set bits from the least to the most significant bit */ + while (imm) { + /* + * Get the next bit to be processed with ctz64. Invert the result of + * ctz64 to match the indexing used by PowerISA. + */ + bit = 7 - ctz64(imm); + if (bit & 0x4) { + tcg_gen_mov_i64(conj, a); + } else { + tcg_gen_not_i64(conj, a); + } + if (bit & 0x2) { + tcg_gen_and_i64(conj, conj, b); + } else { + tcg_gen_andc_i64(conj, conj, b); + } + if (bit & 0x1) { + tcg_gen_and_i64(conj, conj, c); + } else { + tcg_gen_andc_i64(conj, conj, c); + } + tcg_gen_or_i64(disj, disj, conj); + + /* Unset the least significant bit that is set */ + imm &= imm - 1; + } + + tcg_gen_mov_i64(t, disj); +} + +static void gen_xxeval_vec(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b, + TCGv_vec c, int64_t imm) +{ + /* + * Instead of processing imm bit-by-bit, we'll skip the computation of + * conjunctions whose corresponding bit is unset. + */ + int bit; + TCGv_vec disj, conj; + + conj = tcg_temp_new_vec_matching(t); + disj = tcg_temp_new_vec_matching(t); + tcg_gen_dupi_vec(vece, disj, 0); + + /* Iterate over set bits from the least to the most significant bit */ + while (imm) { + /* + * Get the next bit to be processed with ctz64. Invert the result of + * ctz64 to match the indexing used by PowerISA. + */ + bit = 7 - ctz64(imm); + if (bit & 0x4) { + tcg_gen_mov_vec(conj, a); + } else { + tcg_gen_not_vec(vece, conj, a); + } + if (bit & 0x2) { + tcg_gen_and_vec(vece, conj, conj, b); + } else { + tcg_gen_andc_vec(vece, conj, conj, b); + } + if (bit & 0x1) { + tcg_gen_and_vec(vece, conj, conj, c); + } else { + tcg_gen_andc_vec(vece, conj, conj, c); + } + tcg_gen_or_vec(vece, disj, disj, conj); + + /* Unset the least significant bit that is set */ + imm &= imm - 1; + } + + tcg_gen_mov_vec(t, disj); +} + +static bool trans_XXEVAL(DisasContext *ctx, arg_8RR_XX4_imm *a) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_andc_vec, 0 + }; + static const GVecGen4i op = { + .fniv = gen_xxeval_vec, + .fno = gen_helper_XXEVAL, + .fni8 = gen_xxeval_i64, + .opt_opc = vecop_list, + .vece = MO_64 + }; + int xt = vsr_full_offset(a->xt), xa = vsr_full_offset(a->xa), + xb = vsr_full_offset(a->xb), xc = vsr_full_offset(a->xc); + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + + /* Equivalent functions that can be implemented with a single gen_gvec */ + switch (a->imm) { + case 0b00000000: /* false */ + set_cpu_vsr(a->xt, tcg_constant_i64(0), true); + set_cpu_vsr(a->xt, tcg_constant_i64(0), false); + break; + case 0b00000011: /* and(B,A) */ + tcg_gen_gvec_and(MO_64, xt, xb, xa, 16, 16); + break; + case 0b00000101: /* and(C,A) */ + tcg_gen_gvec_and(MO_64, xt, xc, xa, 16, 16); + break; + case 0b00001111: /* A */ + tcg_gen_gvec_mov(MO_64, xt, xa, 16, 16); + break; + case 0b00010001: /* and(C,B) */ + tcg_gen_gvec_and(MO_64, xt, xc, xb, 16, 16); + break; + case 0b00011011: /* C?B:A */ + tcg_gen_gvec_bitsel(MO_64, xt, xc, xb, xa, 16, 16); + break; + case 0b00011101: /* B?C:A */ + tcg_gen_gvec_bitsel(MO_64, xt, xb, xc, xa, 16, 16); + break; + case 0b00100111: /* C?A:B */ + tcg_gen_gvec_bitsel(MO_64, xt, xc, xa, xb, 16, 16); + break; + case 0b00110011: /* B */ + tcg_gen_gvec_mov(MO_64, xt, xb, 16, 16); + break; + case 0b00110101: /* A?C:B */ + tcg_gen_gvec_bitsel(MO_64, xt, xa, xc, xb, 16, 16); + break; + case 0b00111100: /* xor(B,A) */ + tcg_gen_gvec_xor(MO_64, xt, xb, xa, 16, 16); + break; + case 0b00111111: /* or(B,A) */ + tcg_gen_gvec_or(MO_64, xt, xb, xa, 16, 16); + break; + case 0b01000111: /* B?A:C */ + tcg_gen_gvec_bitsel(MO_64, xt, xb, xa, xc, 16, 16); + break; + case 0b01010011: /* A?B:C */ + tcg_gen_gvec_bitsel(MO_64, xt, xa, xb, xc, 16, 16); + break; + case 0b01010101: /* C */ + tcg_gen_gvec_mov(MO_64, xt, xc, 16, 16); + break; + case 0b01011010: /* xor(C,A) */ + tcg_gen_gvec_xor(MO_64, xt, xc, xa, 16, 16); + break; + case 0b01011111: /* or(C,A) */ + tcg_gen_gvec_or(MO_64, xt, xc, xa, 16, 16); + break; + case 0b01100110: /* xor(C,B) */ + tcg_gen_gvec_xor(MO_64, xt, xc, xb, 16, 16); + break; + case 0b01110111: /* or(C,B) */ + tcg_gen_gvec_or(MO_64, xt, xc, xb, 16, 16); + break; + case 0b10001000: /* nor(C,B) */ + tcg_gen_gvec_nor(MO_64, xt, xc, xb, 16, 16); + break; + case 0b10011001: /* eqv(C,B) */ + tcg_gen_gvec_eqv(MO_64, xt, xc, xb, 16, 16); + break; + case 0b10100000: /* nor(C,A) */ + tcg_gen_gvec_nor(MO_64, xt, xc, xa, 16, 16); + break; + case 0b10100101: /* eqv(C,A) */ + tcg_gen_gvec_eqv(MO_64, xt, xc, xa, 16, 16); + break; + case 0b10101010: /* not(C) */ + tcg_gen_gvec_not(MO_64, xt, xc, 16, 16); + break; + case 0b11000000: /* nor(B,A) */ + tcg_gen_gvec_nor(MO_64, xt, xb, xa, 16, 16); + break; + case 0b11000011: /* eqv(B,A) */ + tcg_gen_gvec_eqv(MO_64, xt, xb, xa, 16, 16); + break; + case 0b11001100: /* not(B) */ + tcg_gen_gvec_not(MO_64, xt, xb, 16, 16); + break; + case 0b11101110: /* nand(C,B) */ + tcg_gen_gvec_nand(MO_64, xt, xc, xb, 16, 16); + break; + case 0b11110000: /* not(A) */ + tcg_gen_gvec_not(MO_64, xt, xa, 16, 16); + break; + case 0b11111010: /* nand(C,A) */ + tcg_gen_gvec_nand(MO_64, xt, xc, xa, 16, 16); + break; + case 0b11111100: /* nand(B,A) */ + tcg_gen_gvec_nand(MO_64, xt, xb, xa, 16, 16); + break; + case 0b11111111: /* true */ + set_cpu_vsr(a->xt, tcg_constant_i64(-1), true); + set_cpu_vsr(a->xt, tcg_constant_i64(-1), false); + break; + default: + /* Fallback to compute all conjunctions/disjunctions */ + tcg_gen_gvec_4i(xt, xa, xb, xc, 16, 16, a->imm, &op); + } + + return true; +} + +static void gen_xxblendv_vec(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b, + TCGv_vec c) +{ + TCGv_vec tmp = tcg_temp_new_vec_matching(c); + tcg_gen_sari_vec(vece, tmp, c, (8 << vece) - 1); + tcg_gen_bitsel_vec(vece, t, tmp, b, a); +} + +static bool do_xxblendv(DisasContext *ctx, arg_8RR_XX4 *a, unsigned vece) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_sari_vec, 0 + }; + static const GVecGen4 ops[4] = { + { + .fniv = gen_xxblendv_vec, + .fno = gen_helper_XXBLENDVB, + .opt_opc = vecop_list, + .vece = MO_8 + }, + { + .fniv = gen_xxblendv_vec, + .fno = gen_helper_XXBLENDVH, + .opt_opc = vecop_list, + .vece = MO_16 + }, + { + .fniv = gen_xxblendv_vec, + .fno = gen_helper_XXBLENDVW, + .opt_opc = vecop_list, + .vece = MO_32 + }, + { + .fniv = gen_xxblendv_vec, + .fno = gen_helper_XXBLENDVD, + .opt_opc = vecop_list, + .vece = MO_64 + } + }; + + REQUIRE_VSX(ctx); + + tcg_gen_gvec_4(vsr_full_offset(a->xt), vsr_full_offset(a->xa), + vsr_full_offset(a->xb), vsr_full_offset(a->xc), + 16, 16, &ops[vece]); + + return true; +} + +TRANS(XXBLENDVB, do_xxblendv, MO_8) +TRANS(XXBLENDVH, do_xxblendv, MO_16) +TRANS(XXBLENDVW, do_xxblendv, MO_32) +TRANS(XXBLENDVD, do_xxblendv, MO_64) + +static bool do_helper_XX3(DisasContext *ctx, arg_XX3 *a, + void (*helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr)) +{ + TCGv_ptr xt, xa, xb; + + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VSX(ctx); + + xt = gen_vsr_ptr(a->xt); + xa = gen_vsr_ptr(a->xa); + xb = gen_vsr_ptr(a->xb); + + helper(tcg_env, xt, xa, xb); + return true; +} + +TRANS(XSCMPEQDP, do_helper_XX3, gen_helper_XSCMPEQDP) +TRANS(XSCMPGEDP, do_helper_XX3, gen_helper_XSCMPGEDP) +TRANS(XSCMPGTDP, do_helper_XX3, gen_helper_XSCMPGTDP) +TRANS(XSMAXCDP, do_helper_XX3, gen_helper_XSMAXCDP) +TRANS(XSMINCDP, do_helper_XX3, gen_helper_XSMINCDP) +TRANS(XSMAXJDP, do_helper_XX3, gen_helper_XSMAXJDP) +TRANS(XSMINJDP, do_helper_XX3, gen_helper_XSMINJDP) + +static bool do_helper_X(arg_X *a, + void (*helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr)) +{ + TCGv_ptr rt, ra, rb; + + rt = gen_avr_ptr(a->rt); + ra = gen_avr_ptr(a->ra); + rb = gen_avr_ptr(a->rb); + + helper(tcg_env, rt, ra, rb); + return true; +} + +static bool do_xscmpqp(DisasContext *ctx, arg_X *a, + void (*helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr)) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + + return do_helper_X(a, helper); +} + +TRANS(XSCMPEQQP, do_xscmpqp, gen_helper_XSCMPEQQP) +TRANS(XSCMPGEQP, do_xscmpqp, gen_helper_XSCMPGEQP) +TRANS(XSCMPGTQP, do_xscmpqp, gen_helper_XSCMPGTQP) +TRANS(XSMAXCQP, do_xscmpqp, gen_helper_XSMAXCQP) +TRANS(XSMINCQP, do_xscmpqp, gen_helper_XSMINCQP) + +static bool trans_XVCVSPBF16(DisasContext *ctx, arg_XX2 *a) +{ + TCGv_ptr xt, xb; + + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + + xt = gen_vsr_ptr(a->xt); + xb = gen_vsr_ptr(a->xb); + + gen_helper_XVCVSPBF16(tcg_env, xt, xb); + return true; +} + +static bool trans_XVCVBF16SPN(DisasContext *ctx, arg_XX2 *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + + tcg_gen_gvec_shli(MO_32, vsr_full_offset(a->xt), vsr_full_offset(a->xb), + 16, 16, 16); + + return true; +} + + /* + * The PowerISA 3.1 mentions that for the current version of the + * architecture, "the hardware implementation provides the effect of + * ACC[i] and VSRs 4*i to 4*i + 3 logically containing the same data" + * and "The Accumulators introduce no new logical state at this time" + * (page 501). For now it seems unnecessary to create new structures, + * so ACC[i] is the same as VSRs 4*i to 4*i+3 and therefore + * move to and from accumulators are no-ops. + */ +static bool trans_XXMFACC(DisasContext *ctx, arg_X_a *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + return true; +} + +static bool trans_XXMTACC(DisasContext *ctx, arg_X_a *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + return true; +} + +static bool trans_XXSETACCZ(DisasContext *ctx, arg_X_a *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + tcg_gen_gvec_dup_imm(MO_64, acc_full_offset(a->ra), 64, 64, 0); + return true; +} + +static bool do_ger(DisasContext *ctx, arg_MMIRR_XX3 *a, + void (*helper)(TCGv_env, TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i32)) +{ + uint32_t mask; + TCGv_ptr xt, xa, xb; + REQUIRE_INSNS_FLAGS2(ctx, ISA310); + REQUIRE_VSX(ctx); + if (unlikely((a->xa / 4 == a->xt) || (a->xb / 4 == a->xt))) { + gen_invalid(ctx); + return true; + } + + xt = gen_acc_ptr(a->xt); + xa = gen_vsr_ptr(a->xa); + xb = gen_vsr_ptr(a->xb); + + mask = ger_pack_masks(a->pmsk, a->ymsk, a->xmsk); + helper(tcg_env, xa, xb, xt, tcg_constant_i32(mask)); + return true; +} + +TRANS(XVI4GER8, do_ger, gen_helper_XVI4GER8) +TRANS(XVI4GER8PP, do_ger, gen_helper_XVI4GER8PP) +TRANS(XVI8GER4, do_ger, gen_helper_XVI8GER4) +TRANS(XVI8GER4PP, do_ger, gen_helper_XVI8GER4PP) +TRANS(XVI8GER4SPP, do_ger, gen_helper_XVI8GER4SPP) +TRANS(XVI16GER2, do_ger, gen_helper_XVI16GER2) +TRANS(XVI16GER2PP, do_ger, gen_helper_XVI16GER2PP) +TRANS(XVI16GER2S, do_ger, gen_helper_XVI16GER2S) +TRANS(XVI16GER2SPP, do_ger, gen_helper_XVI16GER2SPP) + +TRANS64(PMXVI4GER8, do_ger, gen_helper_XVI4GER8) +TRANS64(PMXVI4GER8PP, do_ger, gen_helper_XVI4GER8PP) +TRANS64(PMXVI8GER4, do_ger, gen_helper_XVI8GER4) +TRANS64(PMXVI8GER4PP, do_ger, gen_helper_XVI8GER4PP) +TRANS64(PMXVI8GER4SPP, do_ger, gen_helper_XVI8GER4SPP) +TRANS64(PMXVI16GER2, do_ger, gen_helper_XVI16GER2) +TRANS64(PMXVI16GER2PP, do_ger, gen_helper_XVI16GER2PP) +TRANS64(PMXVI16GER2S, do_ger, gen_helper_XVI16GER2S) +TRANS64(PMXVI16GER2SPP, do_ger, gen_helper_XVI16GER2SPP) + +TRANS(XVBF16GER2, do_ger, gen_helper_XVBF16GER2) +TRANS(XVBF16GER2PP, do_ger, gen_helper_XVBF16GER2PP) +TRANS(XVBF16GER2PN, do_ger, gen_helper_XVBF16GER2PN) +TRANS(XVBF16GER2NP, do_ger, gen_helper_XVBF16GER2NP) +TRANS(XVBF16GER2NN, do_ger, gen_helper_XVBF16GER2NN) + +TRANS(XVF16GER2, do_ger, gen_helper_XVF16GER2) +TRANS(XVF16GER2PP, do_ger, gen_helper_XVF16GER2PP) +TRANS(XVF16GER2PN, do_ger, gen_helper_XVF16GER2PN) +TRANS(XVF16GER2NP, do_ger, gen_helper_XVF16GER2NP) +TRANS(XVF16GER2NN, do_ger, gen_helper_XVF16GER2NN) + +TRANS(XVF32GER, do_ger, gen_helper_XVF32GER) +TRANS(XVF32GERPP, do_ger, gen_helper_XVF32GERPP) +TRANS(XVF32GERPN, do_ger, gen_helper_XVF32GERPN) +TRANS(XVF32GERNP, do_ger, gen_helper_XVF32GERNP) +TRANS(XVF32GERNN, do_ger, gen_helper_XVF32GERNN) + +TRANS(XVF64GER, do_ger, gen_helper_XVF64GER) +TRANS(XVF64GERPP, do_ger, gen_helper_XVF64GERPP) +TRANS(XVF64GERPN, do_ger, gen_helper_XVF64GERPN) +TRANS(XVF64GERNP, do_ger, gen_helper_XVF64GERNP) +TRANS(XVF64GERNN, do_ger, gen_helper_XVF64GERNN) + +TRANS64(PMXVBF16GER2, do_ger, gen_helper_XVBF16GER2) +TRANS64(PMXVBF16GER2PP, do_ger, gen_helper_XVBF16GER2PP) +TRANS64(PMXVBF16GER2PN, do_ger, gen_helper_XVBF16GER2PN) +TRANS64(PMXVBF16GER2NP, do_ger, gen_helper_XVBF16GER2NP) +TRANS64(PMXVBF16GER2NN, do_ger, gen_helper_XVBF16GER2NN) + +TRANS64(PMXVF16GER2, do_ger, gen_helper_XVF16GER2) +TRANS64(PMXVF16GER2PP, do_ger, gen_helper_XVF16GER2PP) +TRANS64(PMXVF16GER2PN, do_ger, gen_helper_XVF16GER2PN) +TRANS64(PMXVF16GER2NP, do_ger, gen_helper_XVF16GER2NP) +TRANS64(PMXVF16GER2NN, do_ger, gen_helper_XVF16GER2NN) + +TRANS64(PMXVF32GER, do_ger, gen_helper_XVF32GER) +TRANS64(PMXVF32GERPP, do_ger, gen_helper_XVF32GERPP) +TRANS64(PMXVF32GERPN, do_ger, gen_helper_XVF32GERPN) +TRANS64(PMXVF32GERNP, do_ger, gen_helper_XVF32GERNP) +TRANS64(PMXVF32GERNN, do_ger, gen_helper_XVF32GERNN) + +TRANS64(PMXVF64GER, do_ger, gen_helper_XVF64GER) +TRANS64(PMXVF64GERPP, do_ger, gen_helper_XVF64GERPP) +TRANS64(PMXVF64GERPN, do_ger, gen_helper_XVF64GERPN) +TRANS64(PMXVF64GERNP, do_ger, gen_helper_XVF64GERNP) +TRANS64(PMXVF64GERNN, do_ger, gen_helper_XVF64GERNN) + #undef GEN_XX2FORM #undef GEN_XX3FORM #undef GEN_XX2IFORM diff --git a/target/ppc/translate/vsx-ops.c.inc b/target/ppc/translate/vsx-ops.c.inc index 1d41beef26..a3ba094d62 100644 --- a/target/ppc/translate/vsx-ops.c.inc +++ b/target/ppc/translate/vsx-ops.c.inc @@ -10,7 +10,6 @@ GEN_HANDLER_E(lxvdsx, 0x1F, 0x0C, 0x0A, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(lxvw4x, 0x1F, 0x0C, 0x18, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(lxvh8x, 0x1F, 0x0C, 0x19, 0, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(lxvb16x, 0x1F, 0x0C, 0x1B, 0, PPC_NONE, PPC2_ISA300), -GEN_HANDLER_E(lxvx, 0x1F, 0x0C, 0x08, 0x00000040, PPC_NONE, PPC2_ISA300), #if defined(TARGET_PPC64) GEN_HANDLER_E(lxvl, 0x1F, 0x0D, 0x08, 0, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(lxvll, 0x1F, 0x0D, 0x09, 0, PPC_NONE, PPC2_ISA300), @@ -25,7 +24,6 @@ GEN_HANDLER_E(stxvd2x, 0x1F, 0xC, 0x1E, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(stxvw4x, 0x1F, 0xC, 0x1C, 0, PPC_NONE, PPC2_VSX), GEN_HANDLER_E(stxvh8x, 0x1F, 0x0C, 0x1D, 0, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(stxvb16x, 0x1F, 0x0C, 0x1F, 0, PPC_NONE, PPC2_ISA300), -GEN_HANDLER_E(stxvx, 0x1F, 0x0C, 0x0C, 0, PPC_NONE, PPC2_ISA300), #if defined(TARGET_PPC64) GEN_HANDLER_E(stxvl, 0x1F, 0x0D, 0x0C, 0, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(stxvll, 0x1F, 0x0D, 0x0D, 0, PPC_NONE, PPC2_ISA300), @@ -135,7 +133,6 @@ GEN_VSX_XFORM_300_EO(xsnabsqp, 0x04, 0x19, 0x08, 0x00000001), GEN_VSX_XFORM_300_EO(xsnegqp, 0x04, 0x19, 0x10, 0x00000001), GEN_VSX_XFORM_300(xscpsgnqp, 0x04, 0x03, 0x00000001), GEN_VSX_XFORM_300_EO(xscvdpqp, 0x04, 0x1A, 0x16, 0x00000001), -GEN_VSX_XFORM_300_EO(xscvqpdp, 0x04, 0x1A, 0x14, 0x0), GEN_VSX_XFORM_300_EO(xscvqpsdz, 0x04, 0x1A, 0x19, 0x00000001), GEN_VSX_XFORM_300_EO(xscvqpswz, 0x04, 0x1A, 0x09, 0x00000001), GEN_VSX_XFORM_300_EO(xscvqpudz, 0x04, 0x1A, 0x11, 0x00000001), @@ -150,33 +147,11 @@ GEN_HANDLER_E(xsiexpdp, 0x3C, 0x16, 0x1C, 0, PPC_NONE, PPC2_ISA300), GEN_VSX_XFORM_300(xsiexpqp, 0x4, 0x1B, 0x00000001), #endif -GEN_XX2FORM(xststdcdp, 0x14, 0x16, PPC2_ISA300), -GEN_XX2FORM(xststdcsp, 0x14, 0x12, PPC2_ISA300), -GEN_VSX_XFORM_300(xststdcqp, 0x04, 0x16, 0x00000001), - GEN_XX3FORM(xviexpsp, 0x00, 0x1B, PPC2_ISA300), GEN_XX3FORM(xviexpdp, 0x00, 0x1F, PPC2_ISA300), GEN_XX2FORM_EO(xvxexpdp, 0x16, 0x1D, 0x00, PPC2_ISA300), GEN_XX2FORM_EO(xvxsigdp, 0x16, 0x1D, 0x01, PPC2_ISA300), GEN_XX2FORM_EO(xvxexpsp, 0x16, 0x1D, 0x08, PPC2_ISA300), -GEN_XX2FORM_EO(xvxsigsp, 0x16, 0x1D, 0x09, PPC2_ISA300), - -/* DCMX = bit[25] << 6 | bit[29] << 5 | bit[11:15] */ -#define GEN_XX2FORM_DCMX(name, opc2, opc3, fl2) \ -GEN_XX3FORM(name, opc2, opc3 | 0, fl2), \ -GEN_XX3FORM(name, opc2, opc3 | 1, fl2) - -GEN_XX2FORM_DCMX(xvtstdcdp, 0x14, 0x1E, PPC2_ISA300), -GEN_XX2FORM_DCMX(xvtstdcsp, 0x14, 0x1A, PPC2_ISA300), - -GEN_XX2FORM(xvabsdp, 0x12, 0x1D, PPC2_VSX), -GEN_XX2FORM(xvnabsdp, 0x12, 0x1E, PPC2_VSX), -GEN_XX2FORM(xvnegdp, 0x12, 0x1F, PPC2_VSX), -GEN_XX3FORM(xvcpsgndp, 0x00, 0x1E, PPC2_VSX), -GEN_XX2FORM(xvabssp, 0x12, 0x19, PPC2_VSX), -GEN_XX2FORM(xvnabssp, 0x12, 0x1A, PPC2_VSX), -GEN_XX2FORM(xvnegsp, 0x12, 0x1B, PPC2_VSX), -GEN_XX3FORM(xvcpsgnsp, 0x00, 0x1A, PPC2_VSX), GEN_XX3FORM(xsadddp, 0x00, 0x04, PPC2_VSX), GEN_VSX_XFORM_300(xsaddqp, 0x04, 0x00, 0x0), @@ -189,18 +164,6 @@ GEN_XX2FORM(xssqrtdp, 0x16, 0x04, PPC2_VSX), GEN_XX2FORM(xsrsqrtedp, 0x14, 0x04, PPC2_VSX), GEN_XX3FORM(xstdivdp, 0x14, 0x07, PPC2_VSX), GEN_XX2FORM(xstsqrtdp, 0x14, 0x06, PPC2_VSX), -GEN_XX3FORM_NAME(xsmadddp, "xsmaddadp", 0x04, 0x04, PPC2_VSX), -GEN_XX3FORM_NAME(xsmadddp, "xsmaddmdp", 0x04, 0x05, PPC2_VSX), -GEN_XX3FORM_NAME(xsmsubdp, "xsmsubadp", 0x04, 0x06, PPC2_VSX), -GEN_XX3FORM_NAME(xsmsubdp, "xsmsubmdp", 0x04, 0x07, PPC2_VSX), -GEN_XX3FORM_NAME(xsnmadddp, "xsnmaddadp", 0x04, 0x14, PPC2_VSX), -GEN_XX3FORM_NAME(xsnmadddp, "xsnmaddmdp", 0x04, 0x15, PPC2_VSX), -GEN_XX3FORM_NAME(xsnmsubdp, "xsnmsubadp", 0x04, 0x16, PPC2_VSX), -GEN_XX3FORM_NAME(xsnmsubdp, "xsnmsubmdp", 0x04, 0x17, PPC2_VSX), -GEN_XX3FORM(xscmpeqdp, 0x0C, 0x00, PPC2_ISA300), -GEN_XX3FORM(xscmpgtdp, 0x0C, 0x01, PPC2_ISA300), -GEN_XX3FORM(xscmpgedp, 0x0C, 0x02, PPC2_ISA300), -GEN_XX3FORM(xscmpnedp, 0x0C, 0x03, PPC2_ISA300), GEN_XX3FORM(xscmpexpdp, 0x0C, 0x07, PPC2_ISA300), GEN_VSX_XFORM_300(xscmpexpqp, 0x04, 0x05, 0x00600001), GEN_XX2IFORM(xscmpodp, 0x0C, 0x05, PPC2_VSX), @@ -209,17 +172,12 @@ GEN_VSX_XFORM_300(xscmpoqp, 0x04, 0x04, 0x00600001), GEN_VSX_XFORM_300(xscmpuqp, 0x04, 0x14, 0x00600001), GEN_XX3FORM(xsmaxdp, 0x00, 0x14, PPC2_VSX), GEN_XX3FORM(xsmindp, 0x00, 0x15, PPC2_VSX), -GEN_XX3FORM(xsmaxcdp, 0x00, 0x10, PPC2_ISA300), -GEN_XX3FORM(xsmincdp, 0x00, 0x11, PPC2_ISA300), -GEN_XX3FORM(xsmaxjdp, 0x00, 0x12, PPC2_ISA300), -GEN_XX3FORM(xsminjdp, 0x00, 0x13, PPC2_ISA300), GEN_XX2FORM_EO(xscvdphp, 0x16, 0x15, 0x11, PPC2_ISA300), GEN_XX2FORM(xscvdpsp, 0x12, 0x10, PPC2_VSX), GEN_XX2FORM(xscvdpspn, 0x16, 0x10, PPC2_VSX207), GEN_XX2FORM_EO(xscvhpdp, 0x16, 0x15, 0x10, PPC2_ISA300), GEN_VSX_XFORM_300_EO(xscvsdqp, 0x04, 0x1A, 0x0A, 0x00000001), GEN_XX2FORM(xscvspdp, 0x12, 0x14, PPC2_VSX), -GEN_XX2FORM(xscvspdpn, 0x16, 0x14, PPC2_VSX207), GEN_XX2FORM(xscvdpsxds, 0x10, 0x15, PPC2_VSX), GEN_XX2FORM(xscvdpsxws, 0x10, 0x05, PPC2_VSX), GEN_XX2FORM(xscvdpuxds, 0x10, 0x14, PPC2_VSX), @@ -242,14 +200,6 @@ GEN_XX2FORM(xsresp, 0x14, 0x01, PPC2_VSX207), GEN_XX2FORM(xsrsp, 0x12, 0x11, PPC2_VSX207), GEN_XX2FORM(xssqrtsp, 0x16, 0x00, PPC2_VSX207), GEN_XX2FORM(xsrsqrtesp, 0x14, 0x00, PPC2_VSX207), -GEN_XX3FORM_NAME(xsmaddsp, "xsmaddasp", 0x04, 0x00, PPC2_VSX207), -GEN_XX3FORM_NAME(xsmaddsp, "xsmaddmsp", 0x04, 0x01, PPC2_VSX207), -GEN_XX3FORM_NAME(xsmsubsp, "xsmsubasp", 0x04, 0x02, PPC2_VSX207), -GEN_XX3FORM_NAME(xsmsubsp, "xsmsubmsp", 0x04, 0x03, PPC2_VSX207), -GEN_XX3FORM_NAME(xsnmaddsp, "xsnmaddasp", 0x04, 0x10, PPC2_VSX207), -GEN_XX3FORM_NAME(xsnmaddsp, "xsnmaddmsp", 0x04, 0x11, PPC2_VSX207), -GEN_XX3FORM_NAME(xsnmsubsp, "xsnmsubasp", 0x04, 0x12, PPC2_VSX207), -GEN_XX3FORM_NAME(xsnmsubsp, "xsnmsubmsp", 0x04, 0x13, PPC2_VSX207), GEN_XX2FORM(xscvsxdsp, 0x10, 0x13, PPC2_VSX207), GEN_XX2FORM(xscvuxdsp, 0x10, 0x12, PPC2_VSX207), @@ -348,55 +298,4 @@ VSX_LOGICAL(xxlnand, 0x8, 0x16, PPC2_VSX207), VSX_LOGICAL(xxlorc, 0x8, 0x15, PPC2_VSX207), GEN_XX3FORM(xxmrghw, 0x08, 0x02, PPC2_VSX), GEN_XX3FORM(xxmrglw, 0x08, 0x06, PPC2_VSX), -GEN_XX3FORM(xxperm, 0x08, 0x03, PPC2_ISA300), -GEN_XX3FORM(xxpermr, 0x08, 0x07, PPC2_ISA300), -GEN_XX2FORM(xxspltw, 0x08, 0x0A, PPC2_VSX), -GEN_XX1FORM(xxspltib, 0x08, 0x0B, PPC2_ISA300), GEN_XX3FORM_DM(xxsldwi, 0x08, 0x00), -GEN_XX2FORM_EXT(xxextractuw, 0x0A, 0x0A, PPC2_ISA300), -GEN_XX2FORM_EXT(xxinsertw, 0x0A, 0x0B, PPC2_ISA300), - -#define GEN_XXSEL_ROW(opc3) \ -GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x18, opc3, 0, PPC_NONE, PPC2_VSX), \ -GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x19, opc3, 0, PPC_NONE, PPC2_VSX), \ -GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1A, opc3, 0, PPC_NONE, PPC2_VSX), \ -GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1B, opc3, 0, PPC_NONE, PPC2_VSX), \ -GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1C, opc3, 0, PPC_NONE, PPC2_VSX), \ -GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1D, opc3, 0, PPC_NONE, PPC2_VSX), \ -GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1E, opc3, 0, PPC_NONE, PPC2_VSX), \ -GEN_HANDLER2_E(xxsel, "xxsel", 0x3C, 0x1F, opc3, 0, PPC_NONE, PPC2_VSX), \ - -GEN_XXSEL_ROW(0x00) -GEN_XXSEL_ROW(0x01) -GEN_XXSEL_ROW(0x02) -GEN_XXSEL_ROW(0x03) -GEN_XXSEL_ROW(0x04) -GEN_XXSEL_ROW(0x05) -GEN_XXSEL_ROW(0x06) -GEN_XXSEL_ROW(0x07) -GEN_XXSEL_ROW(0x08) -GEN_XXSEL_ROW(0x09) -GEN_XXSEL_ROW(0x0A) -GEN_XXSEL_ROW(0x0B) -GEN_XXSEL_ROW(0x0C) -GEN_XXSEL_ROW(0x0D) -GEN_XXSEL_ROW(0x0E) -GEN_XXSEL_ROW(0x0F) -GEN_XXSEL_ROW(0x10) -GEN_XXSEL_ROW(0x11) -GEN_XXSEL_ROW(0x12) -GEN_XXSEL_ROW(0x13) -GEN_XXSEL_ROW(0x14) -GEN_XXSEL_ROW(0x15) -GEN_XXSEL_ROW(0x16) -GEN_XXSEL_ROW(0x17) -GEN_XXSEL_ROW(0x18) -GEN_XXSEL_ROW(0x19) -GEN_XXSEL_ROW(0x1A) -GEN_XXSEL_ROW(0x1B) -GEN_XXSEL_ROW(0x1C) -GEN_XXSEL_ROW(0x1D) -GEN_XXSEL_ROW(0x1E) -GEN_XXSEL_ROW(0x1F) - -GEN_XX3FORM_DM(xxpermdi, 0x08, 0x01), |