aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target/arm/a32.decode20
-rw-r--r--target/arm/t32.decode19
-rw-r--r--target/arm/translate.c201
3 files changed, 144 insertions, 96 deletions
diff --git a/target/arm/a32.decode b/target/arm/a32.decode
index c76cbad569..285c08ca22 100644
--- a/target/arm/a32.decode
+++ b/target/arm/a32.decode
@@ -41,6 +41,8 @@
&ldst_ri p w u rn rt imm
&strex rn rd rt rt2 imm
&ldrex rn rt rt2 imm
+&bfx rd rn lsb widthm1
+&bfi rd rn lsb msb
# Data-processing (register)
@@ -390,3 +392,21 @@ LDAEXH .... 0001 1111 .... .... 1110 1001 1111 @ldrex
LDA .... 0001 1001 .... .... 1100 1001 1111 @ldrex
LDAB .... 0001 1101 .... .... 1100 1001 1111 @ldrex
LDAH .... 0001 1111 .... .... 1100 1001 1111 @ldrex
+
+# Media instructions
+
+# usad8 is usada8 w/ ra=15
+USADA8 ---- 0111 1000 rd:4 ra:4 rm:4 0001 rn:4
+
+# ubfx and sbfx
+@bfx ---- .... ... widthm1:5 rd:4 lsb:5 ... rn:4 &bfx
+
+SBFX .... 0111 101 ..... .... ..... 101 .... @bfx
+UBFX .... 0111 111 ..... .... ..... 101 .... @bfx
+
+# bfc is bfi w/ rn=15
+BFCI ---- 0111 110 msb:5 rd:4 lsb:5 001 rn:4 &bfi
+
+# While we could get UDEF by not including this, add the pattern for
+# documentation and to conflict with any other typos in this file.
+UDF 1110 0111 1111 ---- ---- ---- 1111 ----
diff --git a/target/arm/t32.decode b/target/arm/t32.decode
index 70cf8039d7..682fc5c2c4 100644
--- a/target/arm/t32.decode
+++ b/target/arm/t32.decode
@@ -38,6 +38,8 @@
&ldst_ri !extern p w u rn rt imm
&strex !extern rn rd rt rt2 imm
&ldrex !extern rn rt rt2 imm
+&bfx !extern rd rn lsb widthm1
+&bfi !extern rd rn lsb msb
# Data-processing (register)
@@ -144,6 +146,19 @@ RSB_rri 1111 0.0 1110 . .... 0 ... .... ........ @s_rri_rot
SUB_rri 1111 0.1 0101 0 .... 0 ... .... ........ @s0_rri_12
}
+# Saturate, bitfield
+
+@bfx .... .... ... . rn:4 . ... rd:4 .. . widthm1:5 \
+ &bfx lsb=%imm5_12_6
+@bfi .... .... ... . rn:4 . ... rd:4 .. . msb:5 \
+ &bfi lsb=%imm5_12_6
+
+SBFX 1111 0011 010 0 .... 0 ... .... ..0..... @bfx
+UBFX 1111 0011 110 0 .... 0 ... .... ..0..... @bfx
+
+# bfc is bfi w/ rn=15
+BFCI 1111 0011 011 0 .... 0 ... .... ..0..... @bfi
+
# Multiply and multiply accumulate
@s0_rnadm .... .... .... rn:4 ra:4 rd:4 .... rm:4 &s_rrrr s=0
@@ -192,6 +207,9 @@ SMLALBT 1111 1011 1100 .... .... .... 1001 .... @rnadm
SMLALTB 1111 1011 1100 .... .... .... 1010 .... @rnadm
SMLALTT 1111 1011 1100 .... .... .... 1011 .... @rnadm
+# usad8 is usada8 w/ ra=15
+USADA8 1111 1011 0111 .... .... .... 0000 .... @rnadm
+
# Data-processing (two source registers)
QADD 1111 1010 1000 .... 1111 .... 1000 .... @rndm
@@ -254,6 +272,7 @@ CLZ 1111 1010 1011 ---- 1111 .... 1000 .... @rdm
SMC 1111 0111 1111 imm:4 1000 0000 0000 0000 &i
HVC 1111 0111 1110 .... 1000 .... .... .... \
&i imm=%imm16_16_0
+ UDF 1111 0111 1111 ---- 1010 ---- ---- ----
}
# Load/store (register, immediate, literal)
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 9338873a4a..1c50ea232a 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -9221,6 +9221,104 @@ static bool trans_LDAH(DisasContext *s, arg_LDA *a)
}
/*
+ * Media instructions
+ */
+
+static bool trans_USADA8(DisasContext *s, arg_USADA8 *a)
+{
+ TCGv_i32 t1, t2;
+
+ if (!ENABLE_ARCH_6) {
+ return false;
+ }
+
+ t1 = load_reg(s, a->rn);
+ t2 = load_reg(s, a->rm);
+ gen_helper_usad8(t1, t1, t2);
+ tcg_temp_free_i32(t2);
+ if (a->ra != 15) {
+ t2 = load_reg(s, a->ra);
+ tcg_gen_add_i32(t1, t1, t2);
+ tcg_temp_free_i32(t2);
+ }
+ store_reg(s, a->rd, t1);
+ return true;
+}
+
+static bool op_bfx(DisasContext *s, arg_UBFX *a, bool u)
+{
+ TCGv_i32 tmp;
+ int width = a->widthm1 + 1;
+ int shift = a->lsb;
+
+ if (!ENABLE_ARCH_6T2) {
+ return false;
+ }
+ if (shift + width > 32) {
+ /* UNPREDICTABLE; we choose to UNDEF */
+ unallocated_encoding(s);
+ return true;
+ }
+
+ tmp = load_reg(s, a->rn);
+ if (u) {
+ tcg_gen_extract_i32(tmp, tmp, shift, width);
+ } else {
+ tcg_gen_sextract_i32(tmp, tmp, shift, width);
+ }
+ store_reg(s, a->rd, tmp);
+ return true;
+}
+
+static bool trans_SBFX(DisasContext *s, arg_SBFX *a)
+{
+ return op_bfx(s, a, false);
+}
+
+static bool trans_UBFX(DisasContext *s, arg_UBFX *a)
+{
+ return op_bfx(s, a, true);
+}
+
+static bool trans_BFCI(DisasContext *s, arg_BFCI *a)
+{
+ TCGv_i32 tmp;
+ int msb = a->msb, lsb = a->lsb;
+ int width;
+
+ if (!ENABLE_ARCH_6T2) {
+ return false;
+ }
+ if (msb < lsb) {
+ /* UNPREDICTABLE; we choose to UNDEF */
+ unallocated_encoding(s);
+ return true;
+ }
+
+ width = msb + 1 - lsb;
+ if (a->rn == 15) {
+ /* BFC */
+ tmp = tcg_const_i32(0);
+ } else {
+ /* BFI */
+ tmp = load_reg(s, a->rn);
+ }
+ if (width != 32) {
+ TCGv_i32 tmp2 = load_reg(s, a->rd);
+ tcg_gen_deposit_i32(tmp, tmp2, tmp, lsb, width);
+ tcg_temp_free_i32(tmp2);
+ }
+ store_reg(s, a->rd, tmp);
+ return true;
+}
+
+static bool trans_UDF(DisasContext *s, arg_UDF *a)
+{
+ unallocated_encoding(s);
+ return true;
+}
+
+/*
* Legacy decoder.
*/
@@ -9769,65 +9867,9 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
}
break;
case 3:
- op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7);
- switch (op1) {
- case 0: /* Unsigned sum of absolute differences. */
- ARCH(6);
- tmp = load_reg(s, rm);
- tmp2 = load_reg(s, rs);
- gen_helper_usad8(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- if (rd != 15) {
- tmp2 = load_reg(s, rd);
- tcg_gen_add_i32(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- }
- store_reg(s, rn, tmp);
- break;
- case 0x20: case 0x24: case 0x28: case 0x2c:
- /* Bitfield insert/clear. */
- ARCH(6T2);
- shift = (insn >> 7) & 0x1f;
- i = (insn >> 16) & 0x1f;
- if (i < shift) {
- /* UNPREDICTABLE; we choose to UNDEF */
- goto illegal_op;
- }
- i = i + 1 - shift;
- if (rm == 15) {
- tmp = tcg_temp_new_i32();
- tcg_gen_movi_i32(tmp, 0);
- } else {
- tmp = load_reg(s, rm);
- }
- if (i != 32) {
- tmp2 = load_reg(s, rd);
- tcg_gen_deposit_i32(tmp, tmp2, tmp, shift, i);
- tcg_temp_free_i32(tmp2);
- }
- store_reg(s, rd, tmp);
- break;
- case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */
- case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */
- ARCH(6T2);
- tmp = load_reg(s, rm);
- shift = (insn >> 7) & 0x1f;
- i = ((insn >> 16) & 0x1f) + 1;
- if (shift + i > 32)
- goto illegal_op;
- if (i < 32) {
- if (op1 & 0x20) {
- tcg_gen_extract_i32(tmp, tmp, shift, i);
- } else {
- tcg_gen_sextract_i32(tmp, tmp, shift, i);
- }
- }
- store_reg(s, rd, tmp);
- break;
- default:
- goto illegal_op;
- }
- break;
+ /* USAD, BFI, BFC, SBFX, UBFX */
+ /* Done by decodetree */
+ goto illegal_op;
}
break;
}
@@ -10466,10 +10508,9 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
case 0: /* 32 x 32 -> 32 */
case 1: /* 16 x 16 -> 32 */
case 3: /* 32 * 16 -> 32msb */
+ case 7: /* Unsigned sum of absolute differences. */
/* in decodetree */
goto illegal_op;
- case 7: /* Unsigned sum of absolute differences. */
- break;
case 2: /* Dual multiply add. */
case 4: /* Dual multiply subtract. */
case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */
@@ -10534,15 +10575,6 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
}
tcg_temp_free_i32(tmp2);
break;
- case 7: /* Unsigned sum of absolute differences. */
- gen_helper_usad8(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- if (rs != 15) {
- tmp2 = load_reg(s, rs);
- tcg_gen_add_i32(tmp, tmp, tmp2);
- tcg_temp_free_i32(tmp2);
- }
- break;
}
store_reg(s, rd, tmp);
break;
@@ -10837,32 +10869,9 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
tmp = load_reg(s, rn);
}
switch (op) {
- case 2: /* Signed bitfield extract. */
- imm++;
- if (shift + imm > 32)
- goto illegal_op;
- if (imm < 32) {
- tcg_gen_sextract_i32(tmp, tmp, shift, imm);
- }
- break;
- case 6: /* Unsigned bitfield extract. */
- imm++;
- if (shift + imm > 32)
- goto illegal_op;
- if (imm < 32) {
- tcg_gen_extract_i32(tmp, tmp, shift, imm);
- }
- break;
- case 3: /* Bitfield insert/clear. */
- if (imm < shift)
- goto illegal_op;
- imm = imm + 1 - shift;
- if (imm != 32) {
- tmp2 = load_reg(s, rd);
- tcg_gen_deposit_i32(tmp, tmp2, tmp, shift, imm);
- tcg_temp_free_i32(tmp2);
- }
- break;
+ case 2: /* Signed bitfield extract, in decodetree */
+ case 6: /* Unsigned bitfield extract, in decodetree */
+ case 3: /* Bitfield insert/clear, in decodetree */
case 7:
goto illegal_op;
default: /* Saturate. */