ARM TCG conversion 7/16.

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4144 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
pbrook 2008-03-31 03:46:33 +00:00
parent 3670669ce2
commit 6ddbc6e4cf
7 changed files with 554 additions and 447 deletions

View File

@ -1922,3 +1922,248 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
} }
#endif #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);
}

View File

@ -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 #ifdef GEN_HELPER
#define DEF_HELPER_1_1(name, ret, args) \ #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); \ 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 */ #else /* !GEN_HELPER */
#define DEF_HELPER_1_1 DEF_HELPER #define DEF_HELPER_1_1 DEF_HELPER
#define DEF_HELPER_1_2 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 #endif
DEF_HELPER_1_1(clz, uint32_t, (uint32_t)) 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_2(udiv, uint32_t, (uint32_t, uint32_t))
DEF_HELPER_1_1(rbit, 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
#undef DEF_HELPER_1_1 #undef DEF_HELPER_1_1
#undef DEF_HELPER_1_2 #undef DEF_HELPER_1_2

View File

@ -805,327 +805,6 @@ void OPPROTO op_movl_user_T0(void)
FORCE_RET(); 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) void OPPROTO op_movl_T1_r13_banked(void)
{ {
T1 = helper_get_r13_banked(env, PARAM1); T1 = helper_get_r13_banked(env, PARAM1);

View File

@ -8,9 +8,11 @@
*/ */
#ifdef ARITH_GE #ifdef ARITH_GE
#define GE_ARG , uint32_t *gep
#define DECLARE_GE uint32_t ge = 0 #define DECLARE_GE uint32_t ge = 0
#define SET_GE env->GE = ge #define SET_GE *gep = ge
#else #else
#define GE_ARG
#define DECLARE_GE do{}while(0) #define DECLARE_GE do{}while(0)
#define SET_GE do{}while(0) #define SET_GE do{}while(0)
#endif #endif
@ -18,82 +20,77 @@
#define RESULT(val, n, width) \ #define RESULT(val, n, width) \
res |= ((uint32_t)(glue(glue(uint,width),_t))(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; uint32_t res = 0;
DECLARE_GE; DECLARE_GE;
ADD16(T0, T1, 0); ADD16(a, b, 0);
ADD16(T0 >> 16, T1 >> 16, 1); ADD16(a >> 16, b >> 16, 1);
SET_GE; SET_GE;
T0 = res; return res;
FORCE_RET();
} }
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; uint32_t res = 0;
DECLARE_GE; DECLARE_GE;
ADD8(T0, T1, 0); ADD8(a, b, 0);
ADD8(T0 >> 8, T1 >> 8, 1); ADD8(a >> 8, b >> 8, 1);
ADD8(T0 >> 16, T1 >> 16, 2); ADD8(a >> 16, b >> 16, 2);
ADD8(T0 >> 24, T1 >> 24, 3); ADD8(a >> 24, b >> 24, 3);
SET_GE; SET_GE;
T0 = res; return res;
FORCE_RET();
} }
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; uint32_t res = 0;
DECLARE_GE; DECLARE_GE;
SUB16(T0, T1, 0); SUB16(a, b, 0);
SUB16(T0 >> 16, T1 >> 16, 1); SUB16(a >> 16, b >> 16, 1);
SET_GE; SET_GE;
T0 = res; return res;
FORCE_RET();
} }
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; uint32_t res = 0;
DECLARE_GE; DECLARE_GE;
SUB8(T0, T1, 0); SUB8(a, b, 0);
SUB8(T0 >> 8, T1 >> 8, 1); SUB8(a >> 8, b >> 8, 1);
SUB8(T0 >> 16, T1 >> 16, 2); SUB8(a >> 16, b >> 16, 2);
SUB8(T0 >> 24, T1 >> 24, 3); SUB8(a >> 24, b >> 24, 3);
SET_GE; SET_GE;
T0 = res; return res;
FORCE_RET();
} }
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; uint32_t res = 0;
DECLARE_GE; DECLARE_GE;
ADD16(T0, T1, 0); ADD16(a, b, 0);
SUB16(T0 >> 16, T1 >> 16, 1); SUB16(a >> 16, b >> 16, 1);
SET_GE; SET_GE;
T0 = res; return res;
FORCE_RET();
} }
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; uint32_t res = 0;
DECLARE_GE; DECLARE_GE;
SUB16(T0, T1, 0); SUB16(a, b, 0);
ADD16(T0 >> 16, T1 >> 16, 1); ADD16(a >> 16, b >> 16, 1);
SET_GE; SET_GE;
T0 = res; return res;
FORCE_RET();
} }
#undef GE_ARG
#undef DECLARE_GE #undef DECLARE_GE
#undef SET_GE #undef SET_GE
#undef RESULT #undef RESULT

View File

@ -369,3 +369,70 @@ uint32_t HELPER(sub_usaturate)(uint32_t a, uint32_t b)
return res; 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;
}

View File

@ -226,7 +226,6 @@ static void gen_smul_dual(TCGv a, TCGv b)
{ {
TCGv tmp1 = new_tmp(); TCGv tmp1 = new_tmp();
TCGv tmp2 = new_tmp(); TCGv tmp2 = new_tmp();
TCGv res;
tcg_gen_ext8s_i32(tmp1, a); tcg_gen_ext8s_i32(tmp1, a);
tcg_gen_ext8s_i32(tmp2, b); tcg_gen_ext8s_i32(tmp2, b);
tcg_gen_mul_i32(tmp1, tmp1, tmp2); 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) { \ #define PAS_OP(pfx) \
gen_op_ ## pfx ## add16_T0_T1, \ switch (op2) { \
gen_op_ ## pfx ## addsubx_T0_T1, \ case 0: gen_pas_helper(glue(pfx,add16)); break; \
gen_op_ ## pfx ## subaddx_T0_T1, \ case 1: gen_pas_helper(glue(pfx,addsubx)); break; \
gen_op_ ## pfx ## sub16_T0_T1, \ case 2: gen_pas_helper(glue(pfx,subaddx)); break; \
gen_op_ ## pfx ## add8_T0_T1, \ case 3: gen_pas_helper(glue(pfx,sub16)); break; \
NULL, \ case 4: gen_pas_helper(glue(pfx,add8)); break; \
NULL, \ case 7: gen_pas_helper(glue(pfx,sub8)); break; \
gen_op_ ## pfx ## sub8_T0_T1 } }
void gen_arm_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
{
TCGv tmp;
static GenOpFunc *gen_arm_parallel_addsub[8][8] = { switch (op1) {
{}, #define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
PAS_OP(s), case 1:
PAS_OP(q), tmp = tcg_temp_new(TCG_TYPE_PTR);
PAS_OP(sh), tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
{}, PAS_OP(s)
PAS_OP(u), break;
PAS_OP(uq), case 5:
PAS_OP(uh), 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 #undef PAS_OP
/* For unknown reasons Arm and Thumb-2 use arbitrarily diffenet encodings. */ /* For unknown reasons Arm and Thumb-2 use arbitrarily different encodings. */
#define PAS_OP(pfx) { \ #define PAS_OP(pfx) \
gen_op_ ## pfx ## add8_T0_T1, \ switch (op2) { \
gen_op_ ## pfx ## add16_T0_T1, \ case 0: gen_pas_helper(glue(pfx,add8)); break; \
gen_op_ ## pfx ## addsubx_T0_T1, \ case 1: gen_pas_helper(glue(pfx,add16)); break; \
NULL, \ case 2: gen_pas_helper(glue(pfx,addsubx)); break; \
gen_op_ ## pfx ## sub8_T0_T1, \ case 4: gen_pas_helper(glue(pfx,sub8)); break; \
gen_op_ ## pfx ## sub16_T0_T1, \ case 5: gen_pas_helper(glue(pfx,sub16)); break; \
gen_op_ ## pfx ## subaddx_T0_T1, \ case 6: gen_pas_helper(glue(pfx,subaddx)); break; \
NULL } }
void gen_thumb2_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
{
TCGv tmp;
static GenOpFunc *gen_thumb2_parallel_addsub[8][8] = { switch (op1) {
PAS_OP(s), #define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
PAS_OP(q), case 0:
PAS_OP(sh), tmp = tcg_temp_new(TCG_TYPE_PTR);
{}, tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
PAS_OP(u), PAS_OP(s)
PAS_OP(uq), break;
PAS_OP(uh), 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 #undef PAS_OP
static GenOpFunc1 *gen_test_cc[14] = { 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; unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
TCGv tmp; TCGv tmp;
TCGv tmp2; TCGv tmp2;
TCGv tmp3;
insn = ldl_code(s->pc); insn = ldl_code(s->pc);
s->pc += 4; s->pc += 4;
@ -5591,13 +5635,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
switch ((insn >> 23) & 3) { switch ((insn >> 23) & 3) {
case 0: /* Parallel add/subtract. */ case 0: /* Parallel add/subtract. */
op1 = (insn >> 20) & 7; op1 = (insn >> 20) & 7;
gen_movl_T0_reg(s, rn); tmp = load_reg(s, rn);
gen_movl_T1_reg(s, rm); tmp2 = load_reg(s, rm);
sh = (insn >> 5) & 7; sh = (insn >> 5) & 7;
if ((op1 & 3) == 0 || sh == 5 || sh == 6) if ((op1 & 3) == 0 || sh == 5 || sh == 6)
goto illegal_op; goto illegal_op;
gen_arm_parallel_addsub[op1][sh](); gen_arm_parallel_addsub(op1, sh, tmp, tmp2);
gen_movl_reg_T0(s, rd); dead_tmp(tmp2);
store_reg(s, rd, tmp);
break; break;
case 1: case 1:
if ((insn & 0x00700020) == 0) { if ((insn & 0x00700020) == 0) {
@ -5620,40 +5665,44 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
store_reg(s, rd, tmp); store_reg(s, rd, tmp);
} else if ((insn & 0x00200020) == 0x00200000) { } else if ((insn & 0x00200020) == 0x00200000) {
/* [us]sat */ /* [us]sat */
gen_movl_T1_reg(s, rm); tmp = load_reg(s, rm);
shift = (insn >> 7) & 0x1f; shift = (insn >> 7) & 0x1f;
if (insn & (1 << 6)) { if (insn & (1 << 6)) {
if (shift == 0) if (shift == 0)
shift = 31; shift = 31;
gen_op_sarl_T1_im(shift); tcg_gen_sari_i32(tmp, tmp, shift);
} else { } else {
gen_op_shll_T1_im(shift); tcg_gen_shli_i32(tmp, tmp, shift);
} }
sh = (insn >> 16) & 0x1f; sh = (insn >> 16) & 0x1f;
if (sh != 0) { if (sh != 0) {
if (insn & (1 << 22)) if (insn & (1 << 22))
gen_op_usat_T1(sh); gen_helper_usat(tmp, tmp, tcg_const_i32(sh));
else 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) { } else if ((insn & 0x00300fe0) == 0x00200f20) {
/* [us]sat16 */ /* [us]sat16 */
gen_movl_T1_reg(s, rm); tmp = load_reg(s, rm);
sh = (insn >> 16) & 0x1f; sh = (insn >> 16) & 0x1f;
if (sh != 0) { if (sh != 0) {
if (insn & (1 << 22)) if (insn & (1 << 22))
gen_op_usat16_T1(sh); gen_helper_usat16(tmp, tmp, tcg_const_i32(sh));
else 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) { } else if ((insn & 0x00700fe0) == 0x00000fa0) {
/* Select bytes. */ /* Select bytes. */
gen_movl_T0_reg(s, rn); tmp = load_reg(s, rn);
gen_movl_T1_reg(s, rm); tmp2 = load_reg(s, rm);
gen_op_sel_T0_T1(); tmp3 = new_tmp();
gen_movl_reg_T0(s, rd); 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) { } else if ((insn & 0x000003e0) == 0x00000060) {
gen_movl_T1_reg(s, rm); gen_movl_T1_reg(s, rm);
shift = (insn >> 10) & 3; shift = (insn >> 10) & 3;
@ -5755,15 +5804,17 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7); op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7);
switch (op1) { switch (op1) {
case 0: /* Unsigned sum of absolute differences. */ case 0: /* Unsigned sum of absolute differences. */
goto illegal_op; ARCH(6);
gen_movl_T0_reg(s, rm); tmp = load_reg(s, rm);
gen_movl_T1_reg(s, rs); tmp2 = load_reg(s, rs);
gen_op_usad8_T0_T1(); gen_helper_usad8(tmp, tmp, tmp2);
dead_tmp(tmp2);
if (rn != 15) { if (rn != 15) {
gen_movl_T1_reg(s, rn); tmp2 = load_reg(s, rn);
gen_op_addl_T0_T1(); tcg_gen_add_i32(tmp, tmp, tmp2);
dead_tmp(tmp2);
} }
gen_movl_reg_T0(s, rd); store_reg(s, rd, tmp);
break; break;
case 0x20: case 0x24: case 0x28: case 0x2c: case 0x20: case 0x24: case 0x28: case 0x2c:
/* Bitfield insert/clear. */ /* 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 insn, imm, shift, offset, addr;
uint32_t rd, rn, rm, rs; uint32_t rd, rn, rm, rs;
TCGv tmp; TCGv tmp;
TCGv tmp2;
TCGv tmp3;
int op; int op;
int shiftop; int shiftop;
int conds; int conds;
@ -6464,10 +6517,11 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
shift = (insn >> 4) & 7; shift = (insn >> 4) & 7;
if ((op & 3) == 3 || (shift & 3) == 3) if ((op & 3) == 3 || (shift & 3) == 3)
goto illegal_op; goto illegal_op;
gen_movl_T0_reg(s, rn); tmp = load_reg(s, rn);
gen_movl_T1_reg(s, rm); tmp2 = load_reg(s, rm);
gen_thumb2_parallel_addsub[op][shift](); gen_thumb2_parallel_addsub(op, shift, tmp, tmp2);
gen_movl_reg_T0(s, rd); dead_tmp(tmp2);
store_reg(s, rd, tmp);
break; break;
case 3: /* Other data processing. */ case 3: /* Other data processing. */
op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7); 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; break;
case 0x10: /* sel */ case 0x10: /* sel */
gen_movl_T1_reg(s, rm); 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; break;
case 0x18: /* clz */ case 0x18: /* clz */
gen_helper_clz(cpu_T[0], cpu_T[0]); 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); gen_movl_reg_T0(s, rd);
break; break;
case 7: /* Unsigned sum of absolute differences. */ 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) { if (rs != 15) {
gen_movl_T1_reg(s, rs); gen_movl_T1_reg(s, rs);
gen_op_addl_T0_T1(); 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; op = (insn >> 21) & 7;
imm = insn & 0x1f; imm = insn & 0x1f;
shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c); shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
if (rn == 15) if (rn == 15) {
gen_op_movl_T1_im(0); tmp = new_tmp();
else tcg_gen_movi_i32(tmp, 0);
gen_movl_T1_reg(s, rn); } else {
tmp = load_reg(s, rn);
}
switch (op) { switch (op) {
case 2: /* Signed bitfield extract. */ case 2: /* Signed bitfield extract. */
imm++; imm++;
if (shift + imm > 32) if (shift + imm > 32)
goto illegal_op; goto illegal_op;
if (imm < 32) if (imm < 32)
gen_sbfx(cpu_T[1], shift, imm); gen_sbfx(tmp, shift, imm);
break; break;
case 6: /* Unsigned bitfield extract. */ case 6: /* Unsigned bitfield extract. */
imm++; imm++;
if (shift + imm > 32) if (shift + imm > 32)
goto illegal_op; goto illegal_op;
if (imm < 32) if (imm < 32)
gen_ubfx(cpu_T[1], shift, (1u << imm) - 1); gen_ubfx(tmp, shift, (1u << imm) - 1);
break; break;
case 3: /* Bitfield insert/clear. */ case 3: /* Bitfield insert/clear. */
if (imm < shift) if (imm < shift)
goto illegal_op; goto illegal_op;
imm = imm + 1 - shift; imm = imm + 1 - shift;
if (imm != 32) { if (imm != 32) {
gen_movl_T0_reg(s, rd); tmp2 = load_reg(s, rd);
gen_bfi(cpu_T[1], cpu_T[0], cpu_T[1], gen_bfi(tmp, tmp2, tmp,
shift, ((1u << imm) - 1) << shift); shift, ((1u << imm) - 1) << shift);
dead_tmp(tmp2);
} }
break; break;
case 7: case 7:
goto illegal_op; goto illegal_op;
default: /* Saturate. */ default: /* Saturate. */
gen_movl_T1_reg(s, rn);
if (shift) { if (shift) {
if (op & 1) if (op & 1)
gen_op_sarl_T1_im(shift); tcg_gen_sari_i32(tmp, tmp, shift);
else else
gen_op_shll_T1_im(shift); tcg_gen_shli_i32(tmp, tmp, shift);
} }
tmp2 = tcg_const_i32(imm);
if (op & 4) { if (op & 4) {
/* Unsigned. */ /* Unsigned. */
gen_op_ssat_T1(imm);
if ((op & 1) && shift == 0) if ((op & 1) && shift == 0)
gen_op_usat16_T1(imm); gen_helper_usat16(tmp, tmp, tmp2);
else else
gen_op_usat_T1(imm); gen_helper_usat(tmp, tmp, tmp2);
} else { } else {
/* Signed. */ /* Signed. */
gen_op_ssat_T1(imm);
if ((op & 1) && shift == 0) if ((op & 1) && shift == 0)
gen_op_ssat16_T1(imm); gen_helper_ssat16(tmp, tmp, tmp2);
else else
gen_op_ssat_T1(imm); gen_helper_ssat(tmp, tmp, tmp2);
} }
break; break;
} }
gen_movl_reg_T1(s, rd); store_reg(s, rd, tmp);
} else { } else {
imm = ((insn & 0x04000000) >> 15) imm = ((insn & 0x04000000) >> 15)
| ((insn & 0x7000) >> 4) | (insn & 0xff); | ((insn & 0x7000) >> 4) | (insn & 0xff);

View File

@ -237,6 +237,18 @@ static inline void tcg_gen_helper_1_2(void *func, TCGv ret,
1, &ret, 2, args); 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, static inline void tcg_gen_helper_1_4(void *func, TCGv ret,
TCGv arg1, TCGv arg2, TCGv arg3, TCGv arg1, TCGv arg2, TCGv arg3,
TCGv arg4) 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_gen_ext_tl_i64 tcg_gen_ext_i32_i64
#define tcg_const_tl tcg_const_i32 #define tcg_const_tl tcg_const_i32
#endif #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 */