aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/ppc/helper.h2
-rw-r--r--target/ppc/int_helper.c35
-rw-r--r--target/ppc/translate/vmx-impl.inc.c101
3 files changed, 99 insertions, 39 deletions
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 121d7868d0..6fb823c7b4 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -217,8 +217,6 @@ DEF_HELPER_3(vrlb, void, avr, avr, avr)
DEF_HELPER_3(vrlh, void, avr, avr, avr)
DEF_HELPER_3(vrlw, void, avr, avr, avr)
DEF_HELPER_3(vrld, void, avr, avr, avr)
-DEF_HELPER_3(vsl, void, avr, avr, avr)
-DEF_HELPER_3(vsr, void, avr, avr, avr)
DEF_HELPER_4(vsldoi, void, avr, avr, avr, i32)
DEF_HELPER_3(vextractub, void, avr, avr, i32)
DEF_HELPER_3(vextractuh, void, avr, avr, i32)
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index 5dcca5362b..d2cad787ad 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -1740,41 +1740,6 @@ VEXTU_X_DO(vextuhrx, 16, 0)
VEXTU_X_DO(vextuwrx, 32, 0)
#undef VEXTU_X_DO
-/*
- * The specification says that the results are undefined if all of the
- * shift counts are not identical. We check to make sure that they
- * are to conform to what real hardware appears to do.
- */
-#define VSHIFT(suffix, leftp) \
- void helper_vs##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
- { \
- int shift = b->VsrB(15) & 0x7; \
- int doit = 1; \
- int i; \
- \
- for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \
- doit = doit && ((b->u8[i] & 0x7) == shift); \
- } \
- if (doit) { \
- if (shift == 0) { \
- *r = *a; \
- } else if (leftp) { \
- uint64_t carry = a->VsrD(1) >> (64 - shift); \
- \
- r->VsrD(0) = (a->VsrD(0) << shift) | carry; \
- r->VsrD(1) = a->VsrD(1) << shift; \
- } else { \
- uint64_t carry = a->VsrD(0) << (64 - shift); \
- \
- r->VsrD(1) = (a->VsrD(1) >> shift) | carry; \
- r->VsrD(0) = a->VsrD(0) >> shift; \
- } \
- } \
- }
-VSHIFT(l, 1)
-VSHIFT(r, 0)
-#undef VSHIFT
-
void helper_vslv(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
{
int i;
diff --git a/target/ppc/translate/vmx-impl.inc.c b/target/ppc/translate/vmx-impl.inc.c
index a9fe3c7834..e06e65adb2 100644
--- a/target/ppc/translate/vmx-impl.inc.c
+++ b/target/ppc/translate/vmx-impl.inc.c
@@ -570,6 +570,103 @@ static void trans_lvsr(DisasContext *ctx)
tcg_temp_free(EA);
}
+/*
+ * vsl VRT,VRA,VRB - Vector Shift Left
+ *
+ * Shifting left 128 bit value of vA by value specified in bits 125-127 of vB.
+ * Lowest 3 bits in each byte element of register vB must be identical or
+ * result is undefined.
+ */
+static void trans_vsl(DisasContext *ctx)
+{
+ int VT = rD(ctx->opcode);
+ int VA = rA(ctx->opcode);
+ int VB = rB(ctx->opcode);
+ TCGv_i64 avrA = tcg_temp_new_i64();
+ TCGv_i64 avrB = tcg_temp_new_i64();
+ TCGv_i64 sh = tcg_temp_new_i64();
+ TCGv_i64 shifted = tcg_temp_new_i64();
+ TCGv_i64 tmp = tcg_temp_new_i64();
+
+ /* Place bits 125-127 of vB in sh. */
+ get_avr64(avrB, VB, false);
+ tcg_gen_andi_i64(sh, avrB, 0x07ULL);
+
+ /*
+ * Save highest sh bits of lower doubleword element of vA in variable
+ * shifted and perform shift on lower doubleword.
+ */
+ get_avr64(avrA, VA, false);
+ tcg_gen_subfi_i64(tmp, 64, sh);
+ tcg_gen_shr_i64(shifted, avrA, tmp);
+ tcg_gen_andi_i64(shifted, shifted, 0x7fULL);
+ tcg_gen_shl_i64(avrA, avrA, sh);
+ set_avr64(VT, avrA, false);
+
+ /*
+ * Perform shift on higher doubleword element of vA and replace lowest
+ * sh bits with shifted.
+ */
+ get_avr64(avrA, VA, true);
+ tcg_gen_shl_i64(avrA, avrA, sh);
+ tcg_gen_or_i64(avrA, avrA, shifted);
+ set_avr64(VT, avrA, true);
+
+ tcg_temp_free_i64(avrA);
+ tcg_temp_free_i64(avrB);
+ tcg_temp_free_i64(sh);
+ tcg_temp_free_i64(shifted);
+ tcg_temp_free_i64(tmp);
+}
+
+/*
+ * vsr VRT,VRA,VRB - Vector Shift Right
+ *
+ * Shifting right 128 bit value of vA by value specified in bits 125-127 of vB.
+ * Lowest 3 bits in each byte element of register vB must be identical or
+ * result is undefined.
+ */
+static void trans_vsr(DisasContext *ctx)
+{
+ int VT = rD(ctx->opcode);
+ int VA = rA(ctx->opcode);
+ int VB = rB(ctx->opcode);
+ TCGv_i64 avrA = tcg_temp_new_i64();
+ TCGv_i64 avrB = tcg_temp_new_i64();
+ TCGv_i64 sh = tcg_temp_new_i64();
+ TCGv_i64 shifted = tcg_temp_new_i64();
+ TCGv_i64 tmp = tcg_temp_new_i64();
+
+ /* Place bits 125-127 of vB in sh. */
+ get_avr64(avrB, VB, false);
+ tcg_gen_andi_i64(sh, avrB, 0x07ULL);
+
+ /*
+ * Save lowest sh bits of higher doubleword element of vA in variable
+ * shifted and perform shift on higher doubleword.
+ */
+ get_avr64(avrA, VA, true);
+ tcg_gen_subfi_i64(tmp, 64, sh);
+ tcg_gen_shl_i64(shifted, avrA, tmp);
+ tcg_gen_andi_i64(shifted, shifted, 0xfe00000000000000ULL);
+ tcg_gen_shr_i64(avrA, avrA, sh);
+ set_avr64(VT, avrA, true);
+ /*
+ * Perform shift on lower doubleword element of vA and replace highest
+ * sh bits with shifted.
+ */
+ get_avr64(avrA, VA, false);
+ tcg_gen_shr_i64(avrA, avrA, sh);
+ tcg_gen_or_i64(avrA, avrA, shifted);
+ set_avr64(VT, avrA, false);
+
+ tcg_temp_free_i64(avrA);
+ tcg_temp_free_i64(avrB);
+ tcg_temp_free_i64(sh);
+ tcg_temp_free_i64(shifted);
+ tcg_temp_free_i64(tmp);
+}
+
GEN_VXFORM(vmuloub, 4, 0);
GEN_VXFORM(vmulouh, 4, 1);
GEN_VXFORM(vmulouw, 4, 2);
@@ -682,11 +779,11 @@ GEN_VXFORM(vrld, 2, 3);
GEN_VXFORM(vrldmi, 2, 3);
GEN_VXFORM_DUAL(vrld, PPC_NONE, PPC2_ALTIVEC_207, \
vrldmi, PPC_NONE, PPC2_ISA300)
-GEN_VXFORM(vsl, 2, 7);
+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(vsr, 2, 11);
+GEN_VXFORM_TRANS(vsr, 2, 11);
GEN_VXFORM_ENV(vpkuhum, 7, 0);
GEN_VXFORM_ENV(vpkuwum, 7, 1);
GEN_VXFORM_ENV(vpkudum, 7, 17);