aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target-arm/helper.c245
-rw-r--r--target-arm/helpers.h46
-rw-r--r--target-arm/op.c321
-rw-r--r--target-arm/op_addsub.h67
-rw-r--r--target-arm/op_helper.c67
-rw-r--r--target-arm/translate.c240
-rw-r--r--tcg/tcg-op.h19
7 files changed, 556 insertions, 449 deletions
diff --git a/target-arm/helper.c b/target-arm/helper.c
index c61c610919..ee6cd598fd 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1922,3 +1922,248 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
}
#endif
+
+/* Note that signed overflow is undefined in C. The following routines are
+ careful to use unsigned types where modulo arithmetic is required.
+ Failure to do so _will_ break on newer gcc. */
+
+/* Signed saturating arithmetic. */
+
+/* Perform 16-bit signed satruating addition. */
+static inline uint16_t add16_sat(uint16_t a, uint16_t b)
+{
+ uint16_t res;
+
+ res = a + b;
+ if (((res ^ a) & 0x8000) && !((a ^ b) & 0x8000)) {
+ if (a & 0x8000)
+ res = 0x8000;
+ else
+ res = 0x7fff;
+ }
+ return res;
+}
+
+/* Perform 8-bit signed satruating addition. */
+static inline uint8_t add8_sat(uint8_t a, uint8_t b)
+{
+ uint8_t res;
+
+ res = a + b;
+ if (((res ^ a) & 0x80) && !((a ^ b) & 0x80)) {
+ if (a & 0x80)
+ res = 0x80;
+ else
+ res = 0x7f;
+ }
+ return res;
+}
+
+/* Perform 16-bit signed satruating subtraction. */
+static inline uint16_t sub16_sat(uint16_t a, uint16_t b)
+{
+ uint16_t res;
+
+ res = a - b;
+ if (((res ^ a) & 0x8000) && ((a ^ b) & 0x8000)) {
+ if (a & 0x8000)
+ res = 0x8000;
+ else
+ res = 0x7fff;
+ }
+ return res;
+}
+
+/* Perform 8-bit signed satruating subtraction. */
+static inline uint8_t sub8_sat(uint8_t a, uint8_t b)
+{
+ uint8_t res;
+
+ res = a - b;
+ if (((res ^ a) & 0x80) && ((a ^ b) & 0x80)) {
+ if (a & 0x80)
+ res = 0x80;
+ else
+ res = 0x7f;
+ }
+ return res;
+}
+
+#define ADD16(a, b, n) RESULT(add16_sat(a, b), n, 16);
+#define SUB16(a, b, n) RESULT(sub16_sat(a, b), n, 16);
+#define ADD8(a, b, n) RESULT(add8_sat(a, b), n, 8);
+#define SUB8(a, b, n) RESULT(sub8_sat(a, b), n, 8);
+#define PFX q
+
+#include "op_addsub.h"
+
+/* Unsigned saturating arithmetic. */
+static inline uint16_t add16_usat(uint16_t a, uint8_t b)
+{
+ uint16_t res;
+ res = a + b;
+ if (res < a)
+ res = 0xffff;
+ return res;
+}
+
+static inline uint16_t sub16_usat(uint16_t a, uint8_t b)
+{
+ if (a < b)
+ return a - b;
+ else
+ return 0;
+}
+
+static inline uint8_t add8_usat(uint8_t a, uint8_t b)
+{
+ uint8_t res;
+ res = a + b;
+ if (res < a)
+ res = 0xff;
+ return res;
+}
+
+static inline uint8_t sub8_usat(uint8_t a, uint8_t b)
+{
+ if (a < b)
+ return a - b;
+ else
+ return 0;
+}
+
+#define ADD16(a, b, n) RESULT(add16_usat(a, b), n, 16);
+#define SUB16(a, b, n) RESULT(sub16_usat(a, b), n, 16);
+#define ADD8(a, b, n) RESULT(add8_usat(a, b), n, 8);
+#define SUB8(a, b, n) RESULT(sub8_usat(a, b), n, 8);
+#define PFX uq
+
+#include "op_addsub.h"
+
+/* Signed modulo arithmetic. */
+#define SARITH16(a, b, n, op) do { \
+ int32_t sum; \
+ sum = (int16_t)((uint16_t)(a) op (uint16_t)(b)); \
+ RESULT(sum, n, 16); \
+ if (sum >= 0) \
+ ge |= 3 << (n * 2); \
+ } while(0)
+
+#define SARITH8(a, b, n, op) do { \
+ int32_t sum; \
+ sum = (int8_t)((uint8_t)(a) op (uint8_t)(b)); \
+ RESULT(sum, n, 8); \
+ if (sum >= 0) \
+ ge |= 1 << n; \
+ } while(0)
+
+
+#define ADD16(a, b, n) SARITH16(a, b, n, +)
+#define SUB16(a, b, n) SARITH16(a, b, n, -)
+#define ADD8(a, b, n) SARITH8(a, b, n, +)
+#define SUB8(a, b, n) SARITH8(a, b, n, -)
+#define PFX s
+#define ARITH_GE
+
+#include "op_addsub.h"
+
+/* Unsigned modulo arithmetic. */
+#define ADD16(a, b, n) do { \
+ uint32_t sum; \
+ sum = (uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b); \
+ RESULT(sum, n, 16); \
+ if ((sum >> 16) == 0) \
+ ge |= 3 << (n * 2); \
+ } while(0)
+
+#define ADD8(a, b, n) do { \
+ uint32_t sum; \
+ sum = (uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b); \
+ RESULT(sum, n, 8); \
+ if ((sum >> 8) == 0) \
+ ge |= 3 << (n * 2); \
+ } while(0)
+
+#define SUB16(a, b, n) do { \
+ uint32_t sum; \
+ sum = (uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b); \
+ RESULT(sum, n, 16); \
+ if ((sum >> 16) == 0) \
+ ge |= 3 << (n * 2); \
+ } while(0)
+
+#define SUB8(a, b, n) do { \
+ uint32_t sum; \
+ sum = (uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b); \
+ RESULT(sum, n, 8); \
+ if ((sum >> 8) == 0) \
+ ge |= 3 << (n * 2); \
+ } while(0)
+
+#define PFX u
+#define ARITH_GE
+
+#include "op_addsub.h"
+
+/* Halved signed arithmetic. */
+#define ADD16(a, b, n) \
+ RESULT(((int32_t)(int16_t)(a) + (int32_t)(int16_t)(b)) >> 1, n, 16)
+#define SUB16(a, b, n) \
+ RESULT(((int32_t)(int16_t)(a) - (int32_t)(int16_t)(b)) >> 1, n, 16)
+#define ADD8(a, b, n) \
+ RESULT(((int32_t)(int8_t)(a) + (int32_t)(int8_t)(b)) >> 1, n, 8)
+#define SUB8(a, b, n) \
+ RESULT(((int32_t)(int8_t)(a) - (int32_t)(int8_t)(b)) >> 1, n, 8)
+#define PFX sh
+
+#include "op_addsub.h"
+
+/* Halved unsigned arithmetic. */
+#define ADD16(a, b, n) \
+ RESULT(((uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b)) >> 1, n, 16)
+#define SUB16(a, b, n) \
+ RESULT(((uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b)) >> 1, n, 16)
+#define ADD8(a, b, n) \
+ RESULT(((uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b)) >> 1, n, 8)
+#define SUB8(a, b, n) \
+ RESULT(((uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b)) >> 1, n, 8)
+#define PFX uh
+
+#include "op_addsub.h"
+
+static inline uint8_t do_usad(uint8_t a, uint8_t b)
+{
+ if (a > b)
+ return a - b;
+ else
+ return b - a;
+}
+
+/* Unsigned sum of absolute byte differences. */
+uint32_t HELPER(usad8)(uint32_t a, uint32_t b)
+{
+ uint32_t sum;
+ sum = do_usad(a, b);
+ sum += do_usad(a >> 8, b >> 8);
+ sum += do_usad(a >> 16, b >>16);
+ sum += do_usad(a >> 24, b >> 24);
+ return sum;
+}
+
+/* For ARMv6 SEL instruction. */
+uint32_t HELPER(sel_flags)(uint32_t flags, uint32_t a, uint32_t b)
+{
+ uint32_t mask;
+
+ mask = 0;
+ if (flags & 1)
+ mask |= 0xff;
+ if (flags & 2)
+ mask |= 0xff00;
+ if (flags & 4)
+ mask |= 0xff0000;
+ if (flags & 8)
+ mask |= 0xff000000;
+ return (a & mask) | (b & ~mask);
+}
+
diff --git a/target-arm/helpers.h b/target-arm/helpers.h
index 9f608147a6..854b67c835 100644
--- a/target-arm/helpers.h
+++ b/target-arm/helpers.h
@@ -1,4 +1,4 @@
-#define DEF_HELPER(name, ret, args) ret helper_##name args;
+#define DEF_HELPER(name, ret, args) ret glue(helper_,name) args;
#ifdef GEN_HELPER
#define DEF_HELPER_1_1(name, ret, args) \
@@ -13,10 +13,18 @@ static inline void gen_helper_##name(TCGv ret, TCGv arg1, TCGv arg2) \
{ \
tcg_gen_helper_1_2(helper_##name, ret, arg1, arg2); \
}
+#define DEF_HELPER_1_3(name, ret, args) \
+DEF_HELPER(name, ret, args) \
+static inline void gen_helper_##name(TCGv ret, \
+ TCGv arg1, TCGv arg2, TCGv arg3) \
+{ \
+ tcg_gen_helper_1_3(helper_##name, ret, arg1, arg2, arg3); \
+}
#else /* !GEN_HELPER */
#define DEF_HELPER_1_1 DEF_HELPER
#define DEF_HELPER_1_2 DEF_HELPER
-#define HELPER(x) helper_##x
+#define DEF_HELPER_1_3 DEF_HELPER
+#define HELPER(x) glue(helper_,x)
#endif
DEF_HELPER_1_1(clz, uint32_t, (uint32_t))
@@ -33,6 +41,40 @@ DEF_HELPER_1_2(sdiv, int32_t, (int32_t, int32_t))
DEF_HELPER_1_2(udiv, uint32_t, (uint32_t, uint32_t))
DEF_HELPER_1_1(rbit, uint32_t, (uint32_t))
+#define PAS_OP(pfx) \
+ DEF_HELPER_1_3(pfx ## add8, uint32_t, (uint32_t, uint32_t, uint32_t *)) \
+ DEF_HELPER_1_3(pfx ## sub8, uint32_t, (uint32_t, uint32_t, uint32_t *)) \
+ DEF_HELPER_1_3(pfx ## sub16, uint32_t, (uint32_t, uint32_t, uint32_t *)) \
+ DEF_HELPER_1_3(pfx ## add16, uint32_t, (uint32_t, uint32_t, uint32_t *)) \
+ DEF_HELPER_1_3(pfx ## addsubx, uint32_t, (uint32_t, uint32_t, uint32_t *)) \
+ DEF_HELPER_1_3(pfx ## subaddx, uint32_t, (uint32_t, uint32_t, uint32_t *))
+
+PAS_OP(s)
+PAS_OP(u)
+#undef PAS_OP
+
+#define PAS_OP(pfx) \
+ DEF_HELPER_1_2(pfx ## add8, uint32_t, (uint32_t, uint32_t)) \
+ DEF_HELPER_1_2(pfx ## sub8, uint32_t, (uint32_t, uint32_t)) \
+ DEF_HELPER_1_2(pfx ## sub16, uint32_t, (uint32_t, uint32_t)) \
+ DEF_HELPER_1_2(pfx ## add16, uint32_t, (uint32_t, uint32_t)) \
+ DEF_HELPER_1_2(pfx ## addsubx, uint32_t, (uint32_t, uint32_t)) \
+ DEF_HELPER_1_2(pfx ## subaddx, uint32_t, (uint32_t, uint32_t))
+PAS_OP(q)
+PAS_OP(sh)
+PAS_OP(uq)
+PAS_OP(uh)
+#undef PAS_OP
+
+DEF_HELPER_1_2(ssat, uint32_t, (uint32_t, uint32_t))
+DEF_HELPER_1_2(usat, uint32_t, (uint32_t, uint32_t))
+DEF_HELPER_1_2(ssat16, uint32_t, (uint32_t, uint32_t))
+DEF_HELPER_1_2(usat16, uint32_t, (uint32_t, uint32_t))
+
+DEF_HELPER_1_2(usad8, uint32_t, (uint32_t, uint32_t))
+
+DEF_HELPER_1_3(sel_flags, uint32_t, (uint32_t, uint32_t, uint32_t))
+
#undef DEF_HELPER
#undef DEF_HELPER_1_1
#undef DEF_HELPER_1_2
diff --git a/target-arm/op.c b/target-arm/op.c
index e714d41deb..c3150ada33 100644
--- a/target-arm/op.c
+++ b/target-arm/op.c
@@ -805,327 +805,6 @@ void OPPROTO op_movl_user_T0(void)
FORCE_RET();
}
-/* ARMv6 Media instructions. */
-
-/* Note that signed overflow is undefined in C. The following routines are
- careful to use unsigned types where modulo arithmetic is required.
- Failure to do so _will_ break on newer gcc. */
-
-/* Signed saturating arithmetic. */
-
-/* Perform 16-bit signed satruating addition. */
-static inline uint16_t add16_sat(uint16_t a, uint16_t b)
-{
- uint16_t res;
-
- res = a + b;
- if (((res ^ a) & 0x8000) && !((a ^ b) & 0x8000)) {
- if (a & 0x8000)
- res = 0x8000;
- else
- res = 0x7fff;
- }
- return res;
-}
-
-/* Perform 8-bit signed satruating addition. */
-static inline uint8_t add8_sat(uint8_t a, uint8_t b)
-{
- uint8_t res;
-
- res = a + b;
- if (((res ^ a) & 0x80) && !((a ^ b) & 0x80)) {
- if (a & 0x80)
- res = 0x80;
- else
- res = 0x7f;
- }
- return res;
-}
-
-/* Perform 16-bit signed satruating subtraction. */
-static inline uint16_t sub16_sat(uint16_t a, uint16_t b)
-{
- uint16_t res;
-
- res = a - b;
- if (((res ^ a) & 0x8000) && ((a ^ b) & 0x8000)) {
- if (a & 0x8000)
- res = 0x8000;
- else
- res = 0x7fff;
- }
- return res;
-}
-
-/* Perform 8-bit signed satruating subtraction. */
-static inline uint8_t sub8_sat(uint8_t a, uint8_t b)
-{
- uint8_t res;
-
- res = a - b;
- if (((res ^ a) & 0x80) && ((a ^ b) & 0x80)) {
- if (a & 0x80)
- res = 0x80;
- else
- res = 0x7f;
- }
- return res;
-}
-
-#define ADD16(a, b, n) RESULT(add16_sat(a, b), n, 16);
-#define SUB16(a, b, n) RESULT(sub16_sat(a, b), n, 16);
-#define ADD8(a, b, n) RESULT(add8_sat(a, b), n, 8);
-#define SUB8(a, b, n) RESULT(sub8_sat(a, b), n, 8);
-#define PFX q
-
-#include "op_addsub.h"
-
-/* Unsigned saturating arithmetic. */
-static inline uint16_t add16_usat(uint16_t a, uint8_t b)
-{
- uint16_t res;
- res = a + b;
- if (res < a)
- res = 0xffff;
- return res;
-}
-
-static inline uint16_t sub16_usat(uint16_t a, uint8_t b)
-{
- if (a < b)
- return a - b;
- else
- return 0;
-}
-
-static inline uint8_t add8_usat(uint8_t a, uint8_t b)
-{
- uint8_t res;
- res = a + b;
- if (res < a)
- res = 0xff;
- return res;
-}
-
-static inline uint8_t sub8_usat(uint8_t a, uint8_t b)
-{
- if (a < b)
- return a - b;
- else
- return 0;
-}
-
-#define ADD16(a, b, n) RESULT(add16_usat(a, b), n, 16);
-#define SUB16(a, b, n) RESULT(sub16_usat(a, b), n, 16);
-#define ADD8(a, b, n) RESULT(add8_usat(a, b), n, 8);
-#define SUB8(a, b, n) RESULT(sub8_usat(a, b), n, 8);
-#define PFX uq
-
-#include "op_addsub.h"
-
-/* Signed modulo arithmetic. */
-#define SARITH16(a, b, n, op) do { \
- int32_t sum; \
- sum = (int16_t)((uint16_t)(a) op (uint16_t)(b)); \
- RESULT(sum, n, 16); \
- if (sum >= 0) \
- ge |= 3 << (n * 2); \
- } while(0)
-
-#define SARITH8(a, b, n, op) do { \
- int32_t sum; \
- sum = (int8_t)((uint8_t)(a) op (uint8_t)(b)); \
- RESULT(sum, n, 8); \
- if (sum >= 0) \
- ge |= 1 << n; \
- } while(0)
-
-
-#define ADD16(a, b, n) SARITH16(a, b, n, +)
-#define SUB16(a, b, n) SARITH16(a, b, n, -)
-#define ADD8(a, b, n) SARITH8(a, b, n, +)
-#define SUB8(a, b, n) SARITH8(a, b, n, -)
-#define PFX s
-#define ARITH_GE
-
-#include "op_addsub.h"
-
-/* Unsigned modulo arithmetic. */
-#define ADD16(a, b, n) do { \
- uint32_t sum; \
- sum = (uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b); \
- RESULT(sum, n, 16); \
- if ((sum >> 16) == 0) \
- ge |= 3 << (n * 2); \
- } while(0)
-
-#define ADD8(a, b, n) do { \
- uint32_t sum; \
- sum = (uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b); \
- RESULT(sum, n, 8); \
- if ((sum >> 8) == 0) \
- ge |= 3 << (n * 2); \
- } while(0)
-
-#define SUB16(a, b, n) do { \
- uint32_t sum; \
- sum = (uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b); \
- RESULT(sum, n, 16); \
- if ((sum >> 16) == 0) \
- ge |= 3 << (n * 2); \
- } while(0)
-
-#define SUB8(a, b, n) do { \
- uint32_t sum; \
- sum = (uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b); \
- RESULT(sum, n, 8); \
- if ((sum >> 8) == 0) \
- ge |= 3 << (n * 2); \
- } while(0)
-
-#define PFX u
-#define ARITH_GE
-
-#include "op_addsub.h"
-
-/* Halved signed arithmetic. */
-#define ADD16(a, b, n) \
- RESULT(((int32_t)(int16_t)(a) + (int32_t)(int16_t)(b)) >> 1, n, 16)
-#define SUB16(a, b, n) \
- RESULT(((int32_t)(int16_t)(a) - (int32_t)(int16_t)(b)) >> 1, n, 16)
-#define ADD8(a, b, n) \
- RESULT(((int32_t)(int8_t)(a) + (int32_t)(int8_t)(b)) >> 1, n, 8)
-#define SUB8(a, b, n) \
- RESULT(((int32_t)(int8_t)(a) - (int32_t)(int8_t)(b)) >> 1, n, 8)
-#define PFX sh
-
-#include "op_addsub.h"
-
-/* Halved unsigned arithmetic. */
-#define ADD16(a, b, n) \
- RESULT(((uint32_t)(uint16_t)(a) + (uint32_t)(uint16_t)(b)) >> 1, n, 16)
-#define SUB16(a, b, n) \
- RESULT(((uint32_t)(uint16_t)(a) - (uint32_t)(uint16_t)(b)) >> 1, n, 16)
-#define ADD8(a, b, n) \
- RESULT(((uint32_t)(uint8_t)(a) + (uint32_t)(uint8_t)(b)) >> 1, n, 8)
-#define SUB8(a, b, n) \
- RESULT(((uint32_t)(uint8_t)(a) - (uint32_t)(uint8_t)(b)) >> 1, n, 8)
-#define PFX uh
-
-#include "op_addsub.h"
-
-void OPPROTO op_sel_T0_T1(void)
-{
- uint32_t mask;
- uint32_t flags;
-
- flags = env->GE;
- mask = 0;
- if (flags & 1)
- mask |= 0xff;
- if (flags & 2)
- mask |= 0xff00;
- if (flags & 4)
- mask |= 0xff0000;
- if (flags & 8)
- mask |= 0xff000000;
- T0 = (T0 & mask) | (T1 & ~mask);
- FORCE_RET();
-}
-
-/* Signed saturation. */
-static inline uint32_t do_ssat(int32_t val, int shift)
-{
- int32_t top;
- uint32_t mask;
-
- shift = PARAM1;
- top = val >> shift;
- mask = (1u << shift) - 1;
- if (top > 0) {
- env->QF = 1;
- return mask;
- } else if (top < -1) {
- env->QF = 1;
- return ~mask;
- }
- return val;
-}
-
-/* Unsigned saturation. */
-static inline uint32_t do_usat(int32_t val, int shift)
-{
- uint32_t max;
-
- shift = PARAM1;
- max = (1u << shift) - 1;
- if (val < 0) {
- env->QF = 1;
- return 0;
- } else if (val > max) {
- env->QF = 1;
- return max;
- }
- return val;
-}
-
-/* Signed saturate. */
-void OPPROTO op_ssat_T1(void)
-{
- T0 = do_ssat(T0, PARAM1);
- FORCE_RET();
-}
-
-/* Dual halfword signed saturate. */
-void OPPROTO op_ssat16_T1(void)
-{
- uint32_t res;
-
- res = (uint16_t)do_ssat((int16_t)T0, PARAM1);
- res |= do_ssat(((int32_t)T0) >> 16, PARAM1) << 16;
- T0 = res;
- FORCE_RET();
-}
-
-/* Unsigned saturate. */
-void OPPROTO op_usat_T1(void)
-{
- T0 = do_usat(T0, PARAM1);
- FORCE_RET();
-}
-
-/* Dual halfword unsigned saturate. */
-void OPPROTO op_usat16_T1(void)
-{
- uint32_t res;
-
- res = (uint16_t)do_usat((int16_t)T0, PARAM1);
- res |= do_usat(((int32_t)T0) >> 16, PARAM1) << 16;
- T0 = res;
- FORCE_RET();
-}
-
-/* Dual 16-bit add. */
-static inline uint8_t do_usad(uint8_t a, uint8_t b)
-{
- if (a > b)
- return a - b;
- else
- return b - a;
-}
-
-/* Unsigned sum of absolute byte differences. */
-void OPPROTO op_usad8_T0_T1(void)
-{
- uint32_t sum;
- sum = do_usad(T0, T1);
- sum += do_usad(T0 >> 8, T1 >> 8);
- sum += do_usad(T0 >> 16, T1 >>16);
- sum += do_usad(T0 >> 24, T1 >> 24);
- T0 = sum;
-}
-
void OPPROTO op_movl_T1_r13_banked(void)
{
T1 = helper_get_r13_banked(env, PARAM1);
diff --git a/target-arm/op_addsub.h b/target-arm/op_addsub.h
index d15360d807..376ee27edc 100644
--- a/target-arm/op_addsub.h
+++ b/target-arm/op_addsub.h
@@ -8,9 +8,11 @@
*/
#ifdef ARITH_GE
+#define GE_ARG , uint32_t *gep
#define DECLARE_GE uint32_t ge = 0
-#define SET_GE env->GE = ge
+#define SET_GE *gep = ge
#else
+#define GE_ARG
#define DECLARE_GE do{}while(0)
#define SET_GE do{}while(0)
#endif
@@ -18,82 +20,77 @@
#define RESULT(val, n, width) \
res |= ((uint32_t)(glue(glue(uint,width),_t))(val)) << (n * width)
-void OPPROTO glue(glue(op_,PFX),add16_T0_T1)(void)
+uint32_t HELPER(glue(PFX,add16))(uint32_t a, uint32_t b GE_ARG)
{
uint32_t res = 0;
DECLARE_GE;
- ADD16(T0, T1, 0);
- ADD16(T0 >> 16, T1 >> 16, 1);
+ ADD16(a, b, 0);
+ ADD16(a >> 16, b >> 16, 1);
SET_GE;
- T0 = res;
- FORCE_RET();
+ return res;
}
-void OPPROTO glue(glue(op_,PFX),add8_T0_T1)(void)
+uint32_t HELPER(glue(PFX,add8))(uint32_t a, uint32_t b GE_ARG)
{
uint32_t res = 0;
DECLARE_GE;
- ADD8(T0, T1, 0);
- ADD8(T0 >> 8, T1 >> 8, 1);
- ADD8(T0 >> 16, T1 >> 16, 2);
- ADD8(T0 >> 24, T1 >> 24, 3);
+ ADD8(a, b, 0);
+ ADD8(a >> 8, b >> 8, 1);
+ ADD8(a >> 16, b >> 16, 2);
+ ADD8(a >> 24, b >> 24, 3);
SET_GE;
- T0 = res;
- FORCE_RET();
+ return res;
}
-void OPPROTO glue(glue(op_,PFX),sub16_T0_T1)(void)
+uint32_t HELPER(glue(PFX,sub16))(uint32_t a, uint32_t b GE_ARG)
{
uint32_t res = 0;
DECLARE_GE;
- SUB16(T0, T1, 0);
- SUB16(T0 >> 16, T1 >> 16, 1);
+ SUB16(a, b, 0);
+ SUB16(a >> 16, b >> 16, 1);
SET_GE;
- T0 = res;
- FORCE_RET();
+ return res;
}
-void OPPROTO glue(glue(op_,PFX),sub8_T0_T1)(void)
+uint32_t HELPER(glue(PFX,sub8))(uint32_t a, uint32_t b GE_ARG)
{
uint32_t res = 0;
DECLARE_GE;
- SUB8(T0, T1, 0);
- SUB8(T0 >> 8, T1 >> 8, 1);
- SUB8(T0 >> 16, T1 >> 16, 2);
- SUB8(T0 >> 24, T1 >> 24, 3);
+ SUB8(a, b, 0);
+ SUB8(a >> 8, b >> 8, 1);
+ SUB8(a >> 16, b >> 16, 2);
+ SUB8(a >> 24, b >> 24, 3);
SET_GE;
- T0 = res;
- FORCE_RET();
+ return res;
}
-void OPPROTO glue(glue(op_,PFX),subaddx_T0_T1)(void)
+uint32_t HELPER(glue(PFX,subaddx))(uint32_t a, uint32_t b GE_ARG)
{
uint32_t res = 0;
DECLARE_GE;
- ADD16(T0, T1, 0);
- SUB16(T0 >> 16, T1 >> 16, 1);
+ ADD16(a, b, 0);
+ SUB16(a >> 16, b >> 16, 1);
SET_GE;
- T0 = res;
- FORCE_RET();
+ return res;
}
-void OPPROTO glue(glue(op_,PFX),addsubx_T0_T1)(void)
+uint32_t HELPER(glue(PFX,addsubx))(uint32_t a, uint32_t b GE_ARG)
{
uint32_t res = 0;
DECLARE_GE;
- SUB16(T0, T1, 0);
- ADD16(T0 >> 16, T1 >> 16, 1);
+ SUB16(a, b, 0);
+ ADD16(a >> 16, b >> 16, 1);
SET_GE;
- T0 = res;
- FORCE_RET();
+ return res;
}
+#undef GE_ARG
#undef DECLARE_GE
#undef SET_GE
#undef RESULT
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 1b90f58296..2d3abfd79b 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -369,3 +369,70 @@ uint32_t HELPER(sub_usaturate)(uint32_t a, uint32_t b)
return res;
}
+/* Signed saturation. */
+static inline uint32_t do_ssat(int32_t val, int shift)
+{
+ int32_t top;
+ uint32_t mask;
+
+ shift = PARAM1;
+ top = val >> shift;
+ mask = (1u << shift) - 1;
+ if (top > 0) {
+ env->QF = 1;
+ return mask;
+ } else if (top < -1) {
+ env->QF = 1;
+ return ~mask;
+ }
+ return val;
+}
+
+/* Unsigned saturation. */
+static inline uint32_t do_usat(int32_t val, int shift)
+{
+ uint32_t max;
+
+ shift = PARAM1;
+ max = (1u << shift) - 1;
+ if (val < 0) {
+ env->QF = 1;
+ return 0;
+ } else if (val > max) {
+ env->QF = 1;
+ return max;
+ }
+ return val;
+}
+
+/* Signed saturate. */
+uint32_t HELPER(ssat)(uint32_t x, uint32_t shift)
+{
+ return do_ssat(x, shift);
+}
+
+/* Dual halfword signed saturate. */
+uint32_t HELPER(ssat16)(uint32_t x, uint32_t shift)
+{
+ uint32_t res;
+
+ res = (uint16_t)do_ssat((int16_t)x, shift);
+ res |= do_ssat(((int32_t)x) >> 16, shift) << 16;
+ return res;
+}
+
+/* Unsigned saturate. */
+uint32_t HELPER(usat)(uint32_t x, uint32_t shift)
+{
+ return do_usat(x, shift);
+}
+
+/* Dual halfword unsigned saturate. */
+uint32_t HELPER(usat16)(uint32_t x, uint32_t shift)
+{
+ uint32_t res;
+
+ res = (uint16_t)do_usat((int16_t)x, shift);
+ res |= do_usat(((int32_t)x) >> 16, shift) << 16;
+ return res;
+}
diff --git a/target-arm/translate.c b/target-arm/translate.c
index e46cfb9ea1..f732f91e7d 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -226,7 +226,6 @@ static void gen_smul_dual(TCGv a, TCGv b)
{
TCGv tmp1 = new_tmp();
TCGv tmp2 = new_tmp();
- TCGv res;
tcg_gen_ext8s_i32(tmp1, a);
tcg_gen_ext8s_i32(tmp2, b);
tcg_gen_mul_i32(tmp1, tmp1, tmp2);
@@ -495,49 +494,93 @@ static inline void gen_arm_shift_im(TCGv var, int shiftop, int shift, int flags)
}
};
-#define PAS_OP(pfx) { \
- gen_op_ ## pfx ## add16_T0_T1, \
- gen_op_ ## pfx ## addsubx_T0_T1, \
- gen_op_ ## pfx ## subaddx_T0_T1, \
- gen_op_ ## pfx ## sub16_T0_T1, \
- gen_op_ ## pfx ## add8_T0_T1, \
- NULL, \
- NULL, \
- gen_op_ ## pfx ## sub8_T0_T1 }
-
-static GenOpFunc *gen_arm_parallel_addsub[8][8] = {
- {},
- PAS_OP(s),
- PAS_OP(q),
- PAS_OP(sh),
- {},
- PAS_OP(u),
- PAS_OP(uq),
- PAS_OP(uh),
-};
+#define PAS_OP(pfx) \
+ switch (op2) { \
+ case 0: gen_pas_helper(glue(pfx,add16)); break; \
+ case 1: gen_pas_helper(glue(pfx,addsubx)); break; \
+ case 2: gen_pas_helper(glue(pfx,subaddx)); break; \
+ case 3: gen_pas_helper(glue(pfx,sub16)); break; \
+ case 4: gen_pas_helper(glue(pfx,add8)); break; \
+ case 7: gen_pas_helper(glue(pfx,sub8)); break; \
+ }
+void gen_arm_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
+{
+ TCGv tmp;
+
+ switch (op1) {
+#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
+ case 1:
+ tmp = tcg_temp_new(TCG_TYPE_PTR);
+ tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
+ PAS_OP(s)
+ break;
+ case 5:
+ tmp = tcg_temp_new(TCG_TYPE_PTR);
+ tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
+ PAS_OP(u)
+ break;
+#undef gen_pas_helper
+#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b)
+ case 2:
+ PAS_OP(q);
+ break;
+ case 3:
+ PAS_OP(sh);
+ break;
+ case 6:
+ PAS_OP(uq);
+ break;
+ case 7:
+ PAS_OP(uh);
+ break;
+#undef gen_pas_helper
+ }
+}
#undef PAS_OP
-/* For unknown reasons Arm and Thumb-2 use arbitrarily diffenet encodings. */
-#define PAS_OP(pfx) { \
- gen_op_ ## pfx ## add8_T0_T1, \
- gen_op_ ## pfx ## add16_T0_T1, \
- gen_op_ ## pfx ## addsubx_T0_T1, \
- NULL, \
- gen_op_ ## pfx ## sub8_T0_T1, \
- gen_op_ ## pfx ## sub16_T0_T1, \
- gen_op_ ## pfx ## subaddx_T0_T1, \
- NULL }
-
-static GenOpFunc *gen_thumb2_parallel_addsub[8][8] = {
- PAS_OP(s),
- PAS_OP(q),
- PAS_OP(sh),
- {},
- PAS_OP(u),
- PAS_OP(uq),
- PAS_OP(uh),
- {}
-};
+/* For unknown reasons Arm and Thumb-2 use arbitrarily different encodings. */
+#define PAS_OP(pfx) \
+ switch (op2) { \
+ case 0: gen_pas_helper(glue(pfx,add8)); break; \
+ case 1: gen_pas_helper(glue(pfx,add16)); break; \
+ case 2: gen_pas_helper(glue(pfx,addsubx)); break; \
+ case 4: gen_pas_helper(glue(pfx,sub8)); break; \
+ case 5: gen_pas_helper(glue(pfx,sub16)); break; \
+ case 6: gen_pas_helper(glue(pfx,subaddx)); break; \
+ }
+void gen_thumb2_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
+{
+ TCGv tmp;
+
+ switch (op1) {
+#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
+ case 0:
+ tmp = tcg_temp_new(TCG_TYPE_PTR);
+ tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
+ PAS_OP(s)
+ break;
+ case 4:
+ tmp = tcg_temp_new(TCG_TYPE_PTR);
+ tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
+ PAS_OP(u)
+ break;
+#undef gen_pas_helper
+#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b)
+ case 1:
+ PAS_OP(q);
+ break;
+ case 2:
+ PAS_OP(sh);
+ break;
+ case 5:
+ PAS_OP(uq);
+ break;
+ case 6:
+ PAS_OP(uh);
+ break;
+#undef gen_pas_helper
+ }
+}
#undef PAS_OP
static GenOpFunc1 *gen_test_cc[14] = {
@@ -4906,6 +4949,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
TCGv tmp;
TCGv tmp2;
+ TCGv tmp3;
insn = ldl_code(s->pc);
s->pc += 4;
@@ -5591,13 +5635,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
switch ((insn >> 23) & 3) {
case 0: /* Parallel add/subtract. */
op1 = (insn >> 20) & 7;
- gen_movl_T0_reg(s, rn);
- gen_movl_T1_reg(s, rm);
+ tmp = load_reg(s, rn);
+ tmp2 = load_reg(s, rm);
sh = (insn >> 5) & 7;
if ((op1 & 3) == 0 || sh == 5 || sh == 6)
goto illegal_op;
- gen_arm_parallel_addsub[op1][sh]();
- gen_movl_reg_T0(s, rd);
+ gen_arm_parallel_addsub(op1, sh, tmp, tmp2);
+ dead_tmp(tmp2);
+ store_reg(s, rd, tmp);
break;
case 1:
if ((insn & 0x00700020) == 0) {
@@ -5620,40 +5665,44 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
store_reg(s, rd, tmp);
} else if ((insn & 0x00200020) == 0x00200000) {
/* [us]sat */
- gen_movl_T1_reg(s, rm);
+ tmp = load_reg(s, rm);
shift = (insn >> 7) & 0x1f;
if (insn & (1 << 6)) {
if (shift == 0)
shift = 31;
- gen_op_sarl_T1_im(shift);
+ tcg_gen_sari_i32(tmp, tmp, shift);
} else {
- gen_op_shll_T1_im(shift);
+ tcg_gen_shli_i32(tmp, tmp, shift);
}
sh = (insn >> 16) & 0x1f;
if (sh != 0) {
if (insn & (1 << 22))
- gen_op_usat_T1(sh);
+ gen_helper_usat(tmp, tmp, tcg_const_i32(sh));
else
- gen_op_ssat_T1(sh);
+ gen_helper_ssat(tmp, tmp, tcg_const_i32(sh));
}
- gen_movl_T1_reg(s, rd);
+ store_reg(s, rd, tmp);
} else if ((insn & 0x00300fe0) == 0x00200f20) {
/* [us]sat16 */
- gen_movl_T1_reg(s, rm);
+ tmp = load_reg(s, rm);
sh = (insn >> 16) & 0x1f;
if (sh != 0) {
if (insn & (1 << 22))
- gen_op_usat16_T1(sh);
+ gen_helper_usat16(tmp, tmp, tcg_const_i32(sh));
else
- gen_op_ssat16_T1(sh);
+ gen_helper_ssat16(tmp, tmp, tcg_const_i32(sh));
}
- gen_movl_T1_reg(s, rd);
+ store_reg(s, rd, tmp);
} else if ((insn & 0x00700fe0) == 0x00000fa0) {
/* Select bytes. */
- gen_movl_T0_reg(s, rn);
- gen_movl_T1_reg(s, rm);
- gen_op_sel_T0_T1();
- gen_movl_reg_T0(s, rd);
+ tmp = load_reg(s, rn);
+ tmp2 = load_reg(s, rm);
+ tmp3 = new_tmp();
+ tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE));
+ gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
+ dead_tmp(tmp3);
+ dead_tmp(tmp2);
+ store_reg(s, rd, tmp);
} else if ((insn & 0x000003e0) == 0x00000060) {
gen_movl_T1_reg(s, rm);
shift = (insn >> 10) & 3;
@@ -5755,15 +5804,17 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7);
switch (op1) {
case 0: /* Unsigned sum of absolute differences. */
- goto illegal_op;
- gen_movl_T0_reg(s, rm);
- gen_movl_T1_reg(s, rs);
- gen_op_usad8_T0_T1();
+ ARCH(6);
+ tmp = load_reg(s, rm);
+ tmp2 = load_reg(s, rs);
+ gen_helper_usad8(tmp, tmp, tmp2);
+ dead_tmp(tmp2);
if (rn != 15) {
- gen_movl_T1_reg(s, rn);
- gen_op_addl_T0_T1();
+ tmp2 = load_reg(s, rn);
+ tcg_gen_add_i32(tmp, tmp, tmp2);
+ dead_tmp(tmp2);
}
- gen_movl_reg_T0(s, rd);
+ store_reg(s, rd, tmp);
break;
case 0x20: case 0x24: case 0x28: case 0x2c:
/* Bitfield insert/clear. */
@@ -6120,6 +6171,8 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
uint32_t insn, imm, shift, offset, addr;
uint32_t rd, rn, rm, rs;
TCGv tmp;
+ TCGv tmp2;
+ TCGv tmp3;
int op;
int shiftop;
int conds;
@@ -6464,10 +6517,11 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
shift = (insn >> 4) & 7;
if ((op & 3) == 3 || (shift & 3) == 3)
goto illegal_op;
- gen_movl_T0_reg(s, rn);
- gen_movl_T1_reg(s, rm);
- gen_thumb2_parallel_addsub[op][shift]();
- gen_movl_reg_T0(s, rd);
+ tmp = load_reg(s, rn);
+ tmp2 = load_reg(s, rm);
+ gen_thumb2_parallel_addsub(op, shift, tmp, tmp2);
+ dead_tmp(tmp2);
+ store_reg(s, rd, tmp);
break;
case 3: /* Other data processing. */
op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7);
@@ -6498,7 +6552,10 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
break;
case 0x10: /* sel */
gen_movl_T1_reg(s, rm);
- gen_op_sel_T0_T1();
+ tmp3 = new_tmp();
+ tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE));
+ gen_helper_sel_flags(cpu_T[0], tmp3, cpu_T[0], cpu_T[1]);
+ dead_tmp(tmp3);
break;
case 0x18: /* clz */
gen_helper_clz(cpu_T[0], cpu_T[0]);
@@ -6581,7 +6638,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
gen_movl_reg_T0(s, rd);
break;
case 7: /* Unsigned sum of absolute differences. */
- gen_op_usad8_T0_T1();
+ gen_helper_usad8(cpu_T[0], cpu_T[0], cpu_T[1]);
if (rs != 15) {
gen_movl_T1_reg(s, rs);
gen_op_addl_T0_T1();
@@ -6821,63 +6878,64 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
op = (insn >> 21) & 7;
imm = insn & 0x1f;
shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
- if (rn == 15)
- gen_op_movl_T1_im(0);
- else
- gen_movl_T1_reg(s, rn);
+ if (rn == 15) {
+ tmp = new_tmp();
+ tcg_gen_movi_i32(tmp, 0);
+ } else {
+ tmp = load_reg(s, rn);
+ }
switch (op) {
case 2: /* Signed bitfield extract. */
imm++;
if (shift + imm > 32)
goto illegal_op;
if (imm < 32)
- gen_sbfx(cpu_T[1], shift, imm);
+ gen_sbfx(tmp, shift, imm);
break;
case 6: /* Unsigned bitfield extract. */
imm++;
if (shift + imm > 32)
goto illegal_op;
if (imm < 32)
- gen_ubfx(cpu_T[1], shift, (1u << imm) - 1);
+ gen_ubfx(tmp, shift, (1u << imm) - 1);
break;
case 3: /* Bitfield insert/clear. */
if (imm < shift)
goto illegal_op;
imm = imm + 1 - shift;
if (imm != 32) {
- gen_movl_T0_reg(s, rd);
- gen_bfi(cpu_T[1], cpu_T[0], cpu_T[1],
+ tmp2 = load_reg(s, rd);
+ gen_bfi(tmp, tmp2, tmp,
shift, ((1u << imm) - 1) << shift);
+ dead_tmp(tmp2);
}
break;
case 7:
goto illegal_op;
default: /* Saturate. */
- gen_movl_T1_reg(s, rn);
if (shift) {
if (op & 1)
- gen_op_sarl_T1_im(shift);
+ tcg_gen_sari_i32(tmp, tmp, shift);
else
- gen_op_shll_T1_im(shift);
+ tcg_gen_shli_i32(tmp, tmp, shift);
}
+ tmp2 = tcg_const_i32(imm);
if (op & 4) {
/* Unsigned. */
- gen_op_ssat_T1(imm);
if ((op & 1) && shift == 0)
- gen_op_usat16_T1(imm);
+ gen_helper_usat16(tmp, tmp, tmp2);
else
- gen_op_usat_T1(imm);
+ gen_helper_usat(tmp, tmp, tmp2);
} else {
/* Signed. */
- gen_op_ssat_T1(imm);
if ((op & 1) && shift == 0)
- gen_op_ssat16_T1(imm);
+ gen_helper_ssat16(tmp, tmp, tmp2);
else
- gen_op_ssat_T1(imm);
+ gen_helper_ssat(tmp, tmp, tmp2);
}
break;
}
- gen_movl_reg_T1(s, rd);
+ store_reg(s, rd, tmp);
} else {
imm = ((insn & 0x04000000) >> 15)
| ((insn & 0x7000) >> 4) | (insn & 0xff);
diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index f05c135e4a..27f83b5b23 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -237,6 +237,18 @@ static inline void tcg_gen_helper_1_2(void *func, TCGv ret,
1, &ret, 2, args);
}
+static inline void tcg_gen_helper_1_3(void *func, TCGv ret,
+ TCGv arg1, TCGv arg2, TCGv arg3)
+{
+ TCGv args[3];
+ args[0] = arg1;
+ args[1] = arg2;
+ args[2] = arg3;
+ tcg_gen_call(&tcg_ctx,
+ tcg_const_ptr((tcg_target_long)func), TCG_HELPER_CALL_FLAGS,
+ 1, &ret, 3, args);
+}
+
static inline void tcg_gen_helper_1_4(void *func, TCGv ret,
TCGv arg1, TCGv arg2, TCGv arg3,
TCGv arg4)
@@ -1416,3 +1428,10 @@ static inline void tcg_gen_qemu_st64(TCGv arg, TCGv addr, int mem_index)
#define tcg_gen_ext_tl_i64 tcg_gen_ext_i32_i64
#define tcg_const_tl tcg_const_i32
#endif
+
+#if TCG_TARGET_REG_BITS == 32
+#define tcg_gen_addi_ptr tcg_gen_addi_i32
+#else /* TCG_TARGET_REG_BITS == 32 */
+#define tcg_gen_addi_ptr tcg_gen_addi_i64
+#endif /* TCG_TARGET_REG_BITS != 32 */
+