mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-12-23 05:05:36 +00:00
target/arm: Convert packing, unpacking, saturation, and reversal
Backports commit 46497f6af73bb33c1064d43a28a48cbb4d233a23 from qemu
This commit is contained in:
parent
83cced6170
commit
987641cf10
|
@ -28,6 +28,7 @@
|
|||
&s_rri_rot s rn rd imm rot
|
||||
&s_rrrr s rd rn rm ra
|
||||
&rrrr rd rn rm ra
|
||||
&rrr_rot rd rn rm rot
|
||||
&rrr rd rn rm
|
||||
&rr rd rm
|
||||
&ri rd imm
|
||||
|
@ -43,6 +44,8 @@
|
|||
&ldrex rn rt rt2 imm
|
||||
&bfx rd rn lsb widthm1
|
||||
&bfi rd rn lsb msb
|
||||
&sat rd rn satimm imm sh
|
||||
&pkh rd rn rm imm tb
|
||||
|
||||
# Data-processing (register)
|
||||
|
||||
|
@ -454,3 +457,32 @@ UHSAX .... 0110 0111 .... .... 1111 0101 .... @rndm
|
|||
UHSUB16 .... 0110 0111 .... .... 1111 0111 .... @rndm
|
||||
UHADD8 .... 0110 0111 .... .... 1111 1001 .... @rndm
|
||||
UHSUB8 .... 0110 0111 .... .... 1111 1111 .... @rndm
|
||||
|
||||
# Packing, unpacking, saturation, and reversal
|
||||
|
||||
PKH ---- 0110 1000 rn:4 rd:4 imm:5 tb:1 01 rm:4 &pkh
|
||||
|
||||
@sat ---- .... ... satimm:5 rd:4 imm:5 sh:1 .. rn:4 &sat
|
||||
@sat16 ---- .... .... satimm:4 rd:4 .... .... rn:4 \
|
||||
&sat imm=0 sh=0
|
||||
|
||||
SSAT .... 0110 101. .... .... .... ..01 .... @sat
|
||||
USAT .... 0110 111. .... .... .... ..01 .... @sat
|
||||
|
||||
SSAT16 .... 0110 1010 .... .... 1111 0011 .... @sat16
|
||||
USAT16 .... 0110 1110 .... .... 1111 0011 .... @sat16
|
||||
|
||||
@rrr_rot ---- .... .... rn:4 rd:4 rot:2 ...... rm:4 &rrr_rot
|
||||
|
||||
SXTAB16 .... 0110 1000 .... .... ..00 0111 .... @rrr_rot
|
||||
SXTAB .... 0110 1010 .... .... ..00 0111 .... @rrr_rot
|
||||
SXTAH .... 0110 1011 .... .... ..00 0111 .... @rrr_rot
|
||||
UXTAB16 .... 0110 1100 .... .... ..00 0111 .... @rrr_rot
|
||||
UXTAB .... 0110 1110 .... .... ..00 0111 .... @rrr_rot
|
||||
UXTAH .... 0110 1111 .... .... ..00 0111 .... @rrr_rot
|
||||
|
||||
SEL .... 0110 1000 .... .... 1111 1011 .... @rndm
|
||||
REV .... 0110 1011 1111 .... 1111 0011 .... @rdm
|
||||
REV16 .... 0110 1011 1111 .... 1111 1011 .... @rdm
|
||||
REVSH .... 0110 1111 1111 .... 1111 1011 .... @rdm
|
||||
RBIT .... 0110 1111 1111 .... 1111 0011 .... @rdm
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
&s_rri_rot !extern s rn rd imm rot
|
||||
&s_rrrr !extern s rd rn rm ra
|
||||
&rrrr !extern rd rn rm ra
|
||||
&rrr_rot !extern rd rn rm rot
|
||||
&rrr !extern rd rn rm
|
||||
&rr !extern rd rm
|
||||
&ri !extern rd imm
|
||||
|
@ -40,6 +41,8 @@
|
|||
&ldrex !extern rn rt rt2 imm
|
||||
&bfx !extern rd rn lsb widthm1
|
||||
&bfi !extern rd rn lsb msb
|
||||
&sat !extern rd rn satimm imm sh
|
||||
&pkh !extern rd rn rm imm tb
|
||||
|
||||
# Data-processing (register)
|
||||
|
||||
|
@ -69,7 +72,8 @@ BIC_rrri 1110101 0001 . .... 0 ... .... .... .... @s_rrr_shi
|
|||
TEQ_xrri 1110101 0100 1 .... 0 ... 1111 .... .... @S_xrr_shi
|
||||
EOR_rrri 1110101 0100 . .... 0 ... .... .... .... @s_rrr_shi
|
||||
}
|
||||
# PKHBT, PKHTB at opc1 = 0110
|
||||
PKH 1110101 0110 0 rn:4 0 ... rd:4 .. tb:1 0 rm:4 \
|
||||
&pkh imm=%imm5_12_6
|
||||
{
|
||||
CMN_xrri 1110101 1000 1 .... 0 ... 1111 .... .... @S_xrr_shi
|
||||
ADD_rrri 1110101 1000 . .... 0 ... .... .... .... @s_rrr_shi
|
||||
|
@ -148,6 +152,20 @@ RSB_rri 1111 0.0 1110 . .... 0 ... .... ........ @s_rri_rot
|
|||
|
||||
# Saturate, bitfield
|
||||
|
||||
@sat .... .... .. sh:1 . rn:4 . ... rd:4 .. . satimm:5 \
|
||||
&sat imm=%imm5_12_6
|
||||
@sat16 .... .... .. . . rn:4 . ... rd:4 .. . satimm:5 \
|
||||
&sat sh=0 imm=0
|
||||
|
||||
{
|
||||
SSAT16 1111 0011 001 0 .... 0 000 .... 00 0 ..... @sat16
|
||||
SSAT 1111 0011 00. 0 .... 0 ... .... .. 0 ..... @sat
|
||||
}
|
||||
{
|
||||
USAT16 1111 0011 101 0 .... 0 000 .... 00 0 ..... @sat16
|
||||
USAT 1111 0011 10. 0 .... 0 ... .... .. 0 ..... @sat
|
||||
}
|
||||
|
||||
@bfx .... .... ... . rn:4 . ... rd:4 .. . widthm1:5 \
|
||||
&bfx lsb=%imm5_12_6
|
||||
@bfi .... .... ... . rn:4 . ... rd:4 .. . msb:5 \
|
||||
|
@ -224,7 +242,13 @@ CRC32CB 1111 1010 1101 .... 1111 .... 1000 .... @rndm
|
|||
CRC32CH 1111 1010 1101 .... 1111 .... 1001 .... @rndm
|
||||
CRC32CW 1111 1010 1101 .... 1111 .... 1010 .... @rndm
|
||||
|
||||
SEL 1111 1010 1010 .... 1111 .... 1000 .... @rndm
|
||||
|
||||
# Note rn != rm is CONSTRAINED UNPREDICTABLE; we choose to ignore rn.
|
||||
REV 1111 1010 1001 ---- 1111 .... 1000 .... @rdm
|
||||
REV16 1111 1010 1001 ---- 1111 .... 1001 .... @rdm
|
||||
RBIT 1111 1010 1001 ---- 1111 .... 1010 .... @rdm
|
||||
REVSH 1111 1010 1001 ---- 1111 .... 1011 .... @rdm
|
||||
CLZ 1111 1010 1011 ---- 1111 .... 1000 .... @rdm
|
||||
|
||||
# Branches and miscellaneous control
|
||||
|
@ -501,3 +525,14 @@ SHSAX 1111 1010 1110 .... 1111 .... 0010 .... @rndm
|
|||
USAX 1111 1010 1110 .... 1111 .... 0100 .... @rndm
|
||||
UQSAX 1111 1010 1110 .... 1111 .... 0101 .... @rndm
|
||||
UHSAX 1111 1010 1110 .... 1111 .... 0110 .... @rndm
|
||||
|
||||
# Register extends
|
||||
|
||||
@rrr_rot .... .... .... rn:4 .... rd:4 .. rot:2 rm:4 &rrr_rot
|
||||
|
||||
SXTAH 1111 1010 0000 .... 1111 .... 10.. .... @rrr_rot
|
||||
UXTAH 1111 1010 0001 .... 1111 .... 10.. .... @rrr_rot
|
||||
SXTAB16 1111 1010 0010 .... 1111 .... 10.. .... @rrr_rot
|
||||
UXTAB16 1111 1010 0011 .... 1111 .... 10.. .... @rrr_rot
|
||||
SXTAB 1111 1010 0100 .... 1111 .... 10.. .... @rrr_rot
|
||||
UXTAB 1111 1010 0101 .... 1111 .... 10.. .... @rrr_rot
|
||||
|
|
|
@ -361,7 +361,7 @@ static void gen_smul_dual(DisasContext *s, TCGv_i32 a, TCGv_i32 b)
|
|||
}
|
||||
|
||||
/* Byteswap each halfword. */
|
||||
static void gen_rev16(DisasContext *s, TCGv_i32 var)
|
||||
static void gen_rev16(DisasContext *s, TCGv_i32 dest, TCGv_i32 var)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv_i32 tmp = tcg_temp_new_i32(tcg_ctx);
|
||||
|
@ -370,18 +370,18 @@ static void gen_rev16(DisasContext *s, TCGv_i32 var)
|
|||
tcg_gen_and_i32(tcg_ctx, tmp, tmp, mask);
|
||||
tcg_gen_and_i32(tcg_ctx, var, var, mask);
|
||||
tcg_gen_shli_i32(tcg_ctx, var, var, 8);
|
||||
tcg_gen_or_i32(tcg_ctx, var, var, tmp);
|
||||
tcg_gen_or_i32(tcg_ctx, dest, var, tmp);
|
||||
tcg_temp_free_i32(tcg_ctx, mask);
|
||||
tcg_temp_free_i32(tcg_ctx, tmp);
|
||||
}
|
||||
|
||||
/* Byteswap low halfword and sign extend. */
|
||||
static void gen_revsh(DisasContext *s, TCGv_i32 var)
|
||||
static void gen_revsh(DisasContext *s, TCGv_i32 dest, TCGv_i32 var)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
tcg_gen_ext16u_i32(tcg_ctx, var, var);
|
||||
tcg_gen_bswap16_i32(tcg_ctx, var, var);
|
||||
tcg_gen_ext16s_i32(tcg_ctx, var, var);
|
||||
tcg_gen_ext16s_i32(tcg_ctx, dest, var);
|
||||
}
|
||||
|
||||
/* 32x32->64 multiply. Marks inputs as dead. */
|
||||
|
@ -437,7 +437,7 @@ static void gen_swap_half(DisasContext *s, TCGv_i32 var)
|
|||
t0 = (t0 + t1) ^ tmp;
|
||||
*/
|
||||
|
||||
static void gen_add16(DisasContext *s, TCGv_i32 t0, TCGv_i32 t1)
|
||||
static void gen_add16(DisasContext *s, TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv_i32 tmp = tcg_temp_new_i32(tcg_ctx);
|
||||
|
@ -446,9 +446,8 @@ static void gen_add16(DisasContext *s, TCGv_i32 t0, TCGv_i32 t1)
|
|||
tcg_gen_andi_i32(tcg_ctx, t0, t0, ~0x8000);
|
||||
tcg_gen_andi_i32(tcg_ctx, t1, t1, ~0x8000);
|
||||
tcg_gen_add_i32(tcg_ctx, t0, t0, t1);
|
||||
tcg_gen_xor_i32(tcg_ctx, t0, t0, tmp);
|
||||
tcg_gen_xor_i32(tcg_ctx, dest, t0, tmp);
|
||||
tcg_temp_free_i32(tcg_ctx, tmp);
|
||||
tcg_temp_free_i32(tcg_ctx, t1);
|
||||
}
|
||||
|
||||
/* Set N and Z flags from var. */
|
||||
|
@ -6490,7 +6489,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
break;
|
||||
case NEON_2RM_VREV16:
|
||||
gen_rev16(s, tmp);
|
||||
gen_rev16(s, tmp, tmp);
|
||||
break;
|
||||
case NEON_2RM_VCLS:
|
||||
switch (size) {
|
||||
|
@ -7780,6 +7779,78 @@ static void gen_xor_i32(DisasContext *s, TCGv_i32 dest, TCGv_i32 a, TCGv_i32 b)
|
|||
tcg_gen_xor_i32(tcg_ctx, dest, a, b);
|
||||
}
|
||||
|
||||
static void gen_ext8s_i32(DisasContext *s, TCGv_i32 dest, TCGv_i32 src)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
tcg_gen_ext8s_i32(tcg_ctx, dest, src);
|
||||
}
|
||||
|
||||
static void gen_ext16s_i32(DisasContext *s, TCGv_i32 dest, TCGv_i32 src)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
tcg_gen_ext16s_i32(tcg_ctx, dest, src);
|
||||
}
|
||||
|
||||
static void gen_ext8u_i32(DisasContext *s, TCGv_i32 dest, TCGv_i32 src)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
tcg_gen_ext8u_i32(tcg_ctx, dest, src);
|
||||
}
|
||||
|
||||
static void gen_ext16u_i32(DisasContext *s, TCGv_i32 dest, TCGv_i32 src)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
tcg_gen_ext16u_i32(tcg_ctx, dest, src);
|
||||
}
|
||||
|
||||
static void gen_bswap32_i32(DisasContext *s, TCGv_i32 dest, TCGv_i32 src)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
tcg_gen_bswap32_i32(tcg_ctx, dest, src);
|
||||
}
|
||||
|
||||
static void gen_ssat_dectree(DisasContext *s, TCGv_i32 dest, TCGv_env env, TCGv_i32 a, TCGv_i32 b)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
gen_helper_ssat(tcg_ctx, dest, env, a, b);
|
||||
}
|
||||
|
||||
static void gen_usat_dectree(DisasContext *s, TCGv_i32 dest, TCGv_env env, TCGv_i32 a, TCGv_i32 b)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
gen_helper_usat(tcg_ctx, dest, env, a, b);
|
||||
}
|
||||
|
||||
static void gen_ssat16_dectree(DisasContext *s, TCGv_i32 dest, TCGv_env env, TCGv_i32 a, TCGv_i32 b)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
gen_helper_ssat16(tcg_ctx, dest, env, a, b);
|
||||
}
|
||||
|
||||
static void gen_usat16_dectree(DisasContext *s, TCGv_i32 dest, TCGv_env env, TCGv_i32 a, TCGv_i32 b)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
gen_helper_usat16(tcg_ctx, dest, env, a, b);
|
||||
}
|
||||
|
||||
static void gen_sxtb16_dectree(DisasContext *s, TCGv_i32 dest, TCGv_i32 src)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
gen_helper_sxtb16(tcg_ctx, dest, src);
|
||||
}
|
||||
|
||||
static void gen_uxtb16_dectree(DisasContext *s, TCGv_i32 dest, TCGv_i32 src)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
gen_helper_uxtb16(tcg_ctx, dest, src);
|
||||
}
|
||||
|
||||
static void gen_rbit_dectree(DisasContext* s, TCGv_i32 dest, TCGv_i32 src)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
gen_helper_rbit(tcg_ctx, dest, src);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helpers for the data processing routines.
|
||||
*
|
||||
|
@ -9580,6 +9651,222 @@ DO_PAR_ADDSUB(UHSUB8, gen_helper_uhsub8)
|
|||
#undef DO_PAR_ADDSUB
|
||||
#undef DO_PAR_ADDSUB_GE
|
||||
|
||||
/*
|
||||
* Packing, unpacking, saturation, and reversal
|
||||
*/
|
||||
|
||||
static bool trans_PKH(DisasContext *s, arg_PKH *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv_i32 tn, tm;
|
||||
int shift = a->imm;
|
||||
|
||||
if (s->thumb
|
||||
? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)
|
||||
: !ENABLE_ARCH_6) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tn = load_reg(s, a->rn);
|
||||
tm = load_reg(s, a->rm);
|
||||
if (a->tb) {
|
||||
/* PKHTB */
|
||||
if (shift == 0) {
|
||||
shift = 31;
|
||||
}
|
||||
tcg_gen_sari_i32(tcg_ctx, tm, tm, shift);
|
||||
tcg_gen_deposit_i32(tcg_ctx, tn, tn, tm, 0, 16);
|
||||
} else {
|
||||
/* PKHBT */
|
||||
tcg_gen_shli_i32(tcg_ctx, tm, tm, shift);
|
||||
tcg_gen_deposit_i32(tcg_ctx, tn, tm, tn, 0, 16);
|
||||
}
|
||||
tcg_temp_free_i32(tcg_ctx, tm);
|
||||
store_reg(s, a->rd, tn);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool op_sat(DisasContext *s, arg_sat *a,
|
||||
void (*gen)(DisasContext *, TCGv_i32, TCGv_env, TCGv_i32, TCGv_i32))
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv_i32 tmp, satimm;
|
||||
int shift = a->imm;
|
||||
|
||||
if (!ENABLE_ARCH_6) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tmp = load_reg(s, a->rn);
|
||||
if (a->sh) {
|
||||
tcg_gen_sari_i32(tcg_ctx, tmp, tmp, shift ? shift : 31);
|
||||
} else {
|
||||
tcg_gen_shli_i32(tcg_ctx, tmp, tmp, shift);
|
||||
}
|
||||
|
||||
satimm = tcg_const_i32(tcg_ctx, a->satimm);
|
||||
gen(s, tmp, tcg_ctx->cpu_env, tmp, satimm);
|
||||
tcg_temp_free_i32(tcg_ctx, satimm);
|
||||
|
||||
store_reg(s, a->rd, tmp);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_SSAT(DisasContext *s, arg_sat *a)
|
||||
{
|
||||
return op_sat(s, a, gen_ssat_dectree);
|
||||
}
|
||||
|
||||
static bool trans_USAT(DisasContext *s, arg_sat *a)
|
||||
{
|
||||
return op_sat(s, a, gen_usat_dectree);
|
||||
}
|
||||
|
||||
static bool trans_SSAT16(DisasContext *s, arg_sat *a)
|
||||
{
|
||||
if (s->thumb && !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
|
||||
return false;
|
||||
}
|
||||
return op_sat(s, a, gen_ssat16_dectree);
|
||||
}
|
||||
|
||||
static bool trans_USAT16(DisasContext *s, arg_sat *a)
|
||||
{
|
||||
if (s->thumb && !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
|
||||
return false;
|
||||
}
|
||||
return op_sat(s, a, gen_usat16_dectree);
|
||||
}
|
||||
|
||||
static bool op_xta(DisasContext *s, arg_rrr_rot *a,
|
||||
void (*gen_extract)(DisasContext *, TCGv_i32, TCGv_i32),
|
||||
void (*gen_add)(DisasContext*, TCGv_i32, TCGv_i32, TCGv_i32))
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv_i32 tmp;
|
||||
|
||||
if (!ENABLE_ARCH_6) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tmp = load_reg(s, a->rm);
|
||||
/*
|
||||
* TODO: In many cases we could do a shift instead of a rotate.
|
||||
* Combined with a simple extend, that becomes an extract.
|
||||
*/
|
||||
tcg_gen_rotri_i32(tcg_ctx, tmp, tmp, a->rot * 8);
|
||||
gen_extract(s, tmp, tmp);
|
||||
|
||||
if (a->rn != 15) {
|
||||
TCGv_i32 tmp2 = load_reg(s, a->rn);
|
||||
gen_add(s, tmp, tmp, tmp2);
|
||||
tcg_temp_free_i32(tcg_ctx, tmp2);
|
||||
}
|
||||
store_reg(s, a->rd, tmp);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_SXTAB(DisasContext *s, arg_rrr_rot *a)
|
||||
{
|
||||
return op_xta(s, a, gen_ext8s_i32, gen_add_i32);
|
||||
}
|
||||
|
||||
static bool trans_SXTAH(DisasContext *s, arg_rrr_rot *a)
|
||||
{
|
||||
return op_xta(s, a, gen_ext16s_i32, gen_add_i32);
|
||||
}
|
||||
|
||||
static bool trans_SXTAB16(DisasContext *s, arg_rrr_rot *a)
|
||||
{
|
||||
if (s->thumb && !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
|
||||
return false;
|
||||
}
|
||||
return op_xta(s, a, gen_sxtb16_dectree, gen_add16);
|
||||
}
|
||||
|
||||
static bool trans_UXTAB(DisasContext *s, arg_rrr_rot *a)
|
||||
{
|
||||
return op_xta(s, a, gen_ext8u_i32, gen_add_i32);
|
||||
}
|
||||
|
||||
static bool trans_UXTAH(DisasContext *s, arg_rrr_rot *a)
|
||||
{
|
||||
return op_xta(s, a, gen_ext16u_i32, gen_add_i32);
|
||||
}
|
||||
|
||||
static bool trans_UXTAB16(DisasContext *s, arg_rrr_rot *a)
|
||||
{
|
||||
if (s->thumb && !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
|
||||
return false;
|
||||
}
|
||||
return op_xta(s, a, gen_uxtb16_dectree, gen_add16);
|
||||
}
|
||||
|
||||
static bool trans_SEL(DisasContext *s, arg_rrr *a)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv_i32 t1, t2, t3;
|
||||
|
||||
if (s->thumb
|
||||
? !arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)
|
||||
: !ENABLE_ARCH_6) {
|
||||
return false;
|
||||
}
|
||||
|
||||
t1 = load_reg(s, a->rn);
|
||||
t2 = load_reg(s, a->rm);
|
||||
t3 = tcg_temp_new_i32(tcg_ctx);
|
||||
tcg_gen_ld_i32(tcg_ctx, t3, tcg_ctx->cpu_env, offsetof(CPUARMState, GE));
|
||||
gen_helper_sel_flags(tcg_ctx, t1, t3, t1, t2);
|
||||
tcg_temp_free_i32(tcg_ctx, t3);
|
||||
tcg_temp_free_i32(tcg_ctx, t2);
|
||||
store_reg(s, a->rd, t1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool op_rr(DisasContext *s, arg_rr *a,
|
||||
void (*gen)(DisasContext* s, TCGv_i32, TCGv_i32))
|
||||
{
|
||||
TCGv_i32 tmp;
|
||||
|
||||
tmp = load_reg(s, a->rm);
|
||||
gen(s, tmp, tmp);
|
||||
store_reg(s, a->rd, tmp);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_REV(DisasContext *s, arg_rr *a)
|
||||
{
|
||||
if (!ENABLE_ARCH_6) {
|
||||
return false;
|
||||
}
|
||||
return op_rr(s, a, gen_bswap32_i32);
|
||||
}
|
||||
|
||||
static bool trans_REV16(DisasContext *s, arg_rr *a)
|
||||
{
|
||||
if (!ENABLE_ARCH_6) {
|
||||
return false;
|
||||
}
|
||||
return op_rr(s, a, gen_rev16);
|
||||
}
|
||||
|
||||
static bool trans_REVSH(DisasContext *s, arg_rr *a)
|
||||
{
|
||||
if (!ENABLE_ARCH_6) {
|
||||
return false;
|
||||
}
|
||||
return op_rr(s, a, gen_revsh);
|
||||
}
|
||||
|
||||
static bool trans_RBIT(DisasContext *s, arg_rr *a)
|
||||
{
|
||||
if (!ENABLE_ARCH_6T2) {
|
||||
return false;
|
||||
}
|
||||
return op_rr(s, a, gen_rbit_dectree);
|
||||
}
|
||||
|
||||
/*
|
||||
* Legacy decoder.
|
||||
*/
|
||||
|
@ -9587,7 +9874,7 @@ DO_PAR_ADDSUB(UHSUB8, gen_helper_uhsub8)
|
|||
static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
unsigned int cond, val, op1, i, shift, rm, rs, rn, rd, sh;
|
||||
unsigned int cond, val, op1, i, rm, rs, rn, rd;
|
||||
TCGv_i32 tmp;
|
||||
TCGv_i32 tmp2;
|
||||
TCGv_i32 tmp3;
|
||||
|
@ -9902,112 +10189,9 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
|||
/* Done by decodetree */
|
||||
goto illegal_op;
|
||||
case 1:
|
||||
if ((insn & 0x00700020) == 0) {
|
||||
/* Halfword pack. */
|
||||
tmp = load_reg(s, rn);
|
||||
tmp2 = load_reg(s, rm);
|
||||
shift = (insn >> 7) & 0x1f;
|
||||
if (insn & (1 << 6)) {
|
||||
/* pkhtb */
|
||||
if (shift == 0) {
|
||||
shift = 31;
|
||||
}
|
||||
tcg_gen_sari_i32(tcg_ctx, tmp2, tmp2, shift);
|
||||
tcg_gen_deposit_i32(tcg_ctx, tmp, tmp, tmp2, 0, 16);
|
||||
} else {
|
||||
/* pkhbt */
|
||||
tcg_gen_shli_i32(tcg_ctx, tmp2, tmp2, shift);
|
||||
tcg_gen_deposit_i32(tcg_ctx, tmp, tmp2, tmp, 0, 16);
|
||||
}
|
||||
tcg_temp_free_i32(tcg_ctx, tmp2);
|
||||
store_reg(s, rd, tmp);
|
||||
} else if ((insn & 0x00200020) == 0x00200000) {
|
||||
/* [us]sat */
|
||||
tmp = load_reg(s, rm);
|
||||
shift = (insn >> 7) & 0x1f;
|
||||
if (insn & (1 << 6)) {
|
||||
if (shift == 0)
|
||||
shift = 31;
|
||||
tcg_gen_sari_i32(tcg_ctx, tmp, tmp, shift);
|
||||
} else {
|
||||
tcg_gen_shli_i32(tcg_ctx, tmp, tmp, shift);
|
||||
}
|
||||
sh = (insn >> 16) & 0x1f;
|
||||
tmp2 = tcg_const_i32(tcg_ctx, sh);
|
||||
if (insn & (1 << 22))
|
||||
gen_helper_usat(tcg_ctx, tmp, tcg_ctx->cpu_env, tmp, tmp2);
|
||||
else
|
||||
gen_helper_ssat(tcg_ctx, tmp, tcg_ctx->cpu_env, tmp, tmp2);
|
||||
tcg_temp_free_i32(tcg_ctx, tmp2);
|
||||
store_reg(s, rd, tmp);
|
||||
} else if ((insn & 0x00300fe0) == 0x00200f20) {
|
||||
/* [us]sat16 */
|
||||
tmp = load_reg(s, rm);
|
||||
sh = (insn >> 16) & 0x1f;
|
||||
tmp2 = tcg_const_i32(tcg_ctx, sh);
|
||||
if (insn & (1 << 22))
|
||||
gen_helper_usat16(tcg_ctx, tmp, tcg_ctx->cpu_env, tmp, tmp2);
|
||||
else
|
||||
gen_helper_ssat16(tcg_ctx, tmp, tcg_ctx->cpu_env, tmp, tmp2);
|
||||
tcg_temp_free_i32(tcg_ctx, tmp2);
|
||||
store_reg(s, rd, tmp);
|
||||
} else if ((insn & 0x00700fe0) == 0x00000fa0) {
|
||||
/* Select bytes. */
|
||||
tmp = load_reg(s, rn);
|
||||
tmp2 = load_reg(s, rm);
|
||||
tmp3 = tcg_temp_new_i32(tcg_ctx);
|
||||
tcg_gen_ld_i32(tcg_ctx, tmp3, tcg_ctx->cpu_env, offsetof(CPUARMState, GE));
|
||||
gen_helper_sel_flags(tcg_ctx, tmp, tmp3, tmp, tmp2);
|
||||
tcg_temp_free_i32(tcg_ctx, tmp3);
|
||||
tcg_temp_free_i32(tcg_ctx, tmp2);
|
||||
store_reg(s, rd, tmp);
|
||||
} else if ((insn & 0x000003e0) == 0x00000060) {
|
||||
tmp = load_reg(s, rm);
|
||||
shift = (insn >> 10) & 3;
|
||||
/* ??? In many cases it's not necessary to do a
|
||||
rotate, a shift is sufficient. */
|
||||
tcg_gen_rotri_i32(tcg_ctx, tmp, tmp, shift * 8);
|
||||
op1 = (insn >> 20) & 7;
|
||||
switch (op1) {
|
||||
case 0: gen_sxtb16(tmp); break;
|
||||
case 2: gen_sxtb(tmp); break;
|
||||
case 3: gen_sxth(tmp); break;
|
||||
case 4: gen_uxtb16(tmp); break;
|
||||
case 6: gen_uxtb(tmp); break;
|
||||
case 7: gen_uxth(tmp); break;
|
||||
default: goto illegal_op;
|
||||
}
|
||||
if (rn != 15) {
|
||||
tmp2 = load_reg(s, rn);
|
||||
if ((op1 & 3) == 0) {
|
||||
gen_add16(s, tmp, tmp2);
|
||||
} else {
|
||||
tcg_gen_add_i32(tcg_ctx, tmp, tmp, tmp2);
|
||||
tcg_temp_free_i32(tcg_ctx, tmp2);
|
||||
}
|
||||
}
|
||||
store_reg(s, rd, tmp);
|
||||
} else if ((insn & 0x003f0f60) == 0x003f0f20) {
|
||||
/* rev */
|
||||
tmp = load_reg(s, rm);
|
||||
if (insn & (1 << 22)) {
|
||||
if (insn & (1 << 7)) {
|
||||
gen_revsh(s, tmp);
|
||||
} else {
|
||||
ARCH(6T2);
|
||||
gen_helper_rbit(tcg_ctx, tmp, tmp);
|
||||
}
|
||||
} else {
|
||||
if (insn & (1 << 7))
|
||||
gen_rev16(s, tmp);
|
||||
else
|
||||
tcg_gen_bswap32_i32(tcg_ctx, tmp, tmp);
|
||||
}
|
||||
store_reg(s, rd, tmp);
|
||||
} else {
|
||||
goto illegal_op;
|
||||
}
|
||||
break;
|
||||
/* Halfword pack, [US]SAT, [US]SAT16, SEL, REV et al */
|
||||
/* Done by decodetree */
|
||||
goto illegal_op;
|
||||
case 2: /* Multiplies (Type 3). */
|
||||
switch ((insn >> 20) & 0x7) {
|
||||
case 5:
|
||||
|
@ -10350,7 +10534,7 @@ static bool thumb_insn_is_16bit(DisasContext *s, uint32_t pc, uint32_t insn)
|
|||
static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
uint32_t imm, shift, offset;
|
||||
uint32_t imm, offset;
|
||||
uint32_t rd, rn, rm, rs;
|
||||
TCGv_i32 tmp;
|
||||
TCGv_i32 tmp2;
|
||||
|
@ -10605,36 +10789,8 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
|
|||
}
|
||||
break;
|
||||
case 5:
|
||||
|
||||
op = (insn >> 21) & 0xf;
|
||||
if (op == 6) {
|
||||
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
|
||||
goto illegal_op;
|
||||
}
|
||||
/* Halfword pack. */
|
||||
tmp = load_reg(s, rn);
|
||||
tmp2 = load_reg(s, rm);
|
||||
shift = ((insn >> 10) & 0x1c) | ((insn >> 6) & 0x3);
|
||||
if (insn & (1 << 5)) {
|
||||
/* pkhtb */
|
||||
if (shift == 0) {
|
||||
shift = 31;
|
||||
}
|
||||
tcg_gen_sari_i32(tcg_ctx, tmp2, tmp2, shift);
|
||||
tcg_gen_deposit_i32(tcg_ctx, tmp, tmp, tmp2, 0, 16);
|
||||
} else {
|
||||
/* pkhbt */
|
||||
tcg_gen_shli_i32(tcg_ctx, tmp2, tmp2, shift);
|
||||
tcg_gen_deposit_i32(tcg_ctx, tmp, tmp2, tmp, 0, 16);
|
||||
}
|
||||
tcg_temp_free_i32(tcg_ctx, tmp2);
|
||||
store_reg(s, rd, tmp);
|
||||
} else {
|
||||
/* Data processing register constant shift. */
|
||||
/* All done in decodetree. Reach here for illegal ops. */
|
||||
goto illegal_op;
|
||||
}
|
||||
break;
|
||||
/* All in decodetree */
|
||||
goto illegal_op;
|
||||
case 13: /* Misc data processing. */
|
||||
op = ((insn >> 22) & 6) | ((insn >> 7) & 1);
|
||||
if (op < 4 && (insn & 0xf000) != 0xf000)
|
||||
|
@ -10642,114 +10798,10 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
|
|||
switch (op) {
|
||||
case 0: /* Register controlled shift, in decodetree */
|
||||
goto illegal_op;
|
||||
case 1: /* Sign/zero extend. */
|
||||
op = (insn >> 20) & 7;
|
||||
switch (op) {
|
||||
case 0: /* SXTAH, SXTH */
|
||||
case 1: /* UXTAH, UXTH */
|
||||
case 4: /* SXTAB, SXTB */
|
||||
case 5: /* UXTAB, UXTB */
|
||||
break;
|
||||
case 2: /* SXTAB16, SXTB16 */
|
||||
case 3: /* UXTAB16, UXTB16 */
|
||||
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
|
||||
goto illegal_op;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto illegal_op;
|
||||
}
|
||||
if (rn != 15) {
|
||||
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
|
||||
goto illegal_op;
|
||||
}
|
||||
}
|
||||
tmp = load_reg(s, rm);
|
||||
shift = (insn >> 4) & 3;
|
||||
/* ??? In many cases it's not necessary to do a
|
||||
rotate, a shift is sufficient. */
|
||||
tcg_gen_rotri_i32(tcg_ctx, tmp, tmp, shift * 8);
|
||||
op = (insn >> 20) & 7;
|
||||
switch (op) {
|
||||
case 0: gen_sxth(tmp); break;
|
||||
case 1: gen_uxth(tmp); break;
|
||||
case 2: gen_sxtb16(tmp); break;
|
||||
case 3: gen_uxtb16(tmp); break;
|
||||
case 4: gen_sxtb(tmp); break;
|
||||
case 5: gen_uxtb(tmp); break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
if (rn != 15) {
|
||||
tmp2 = load_reg(s, rn);
|
||||
if ((op >> 1) == 1) {
|
||||
gen_add16(s, tmp, tmp2);
|
||||
} else {
|
||||
tcg_gen_add_i32(tcg_ctx, tmp, tmp, tmp2);
|
||||
tcg_temp_free_i32(tcg_ctx, tmp2);
|
||||
}
|
||||
}
|
||||
store_reg(s, rd, tmp);
|
||||
break;
|
||||
case 1: /* Sign/zero extend, in decodetree */
|
||||
case 2: /* SIMD add/subtract, in decodetree */
|
||||
case 3: /* Other data processing, in decodetree */
|
||||
goto illegal_op;
|
||||
case 3: /* Other data processing. */
|
||||
op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7);
|
||||
if (op < 4) {
|
||||
/* Saturating add/subtract. */
|
||||
/* All done in decodetree. Reach here for illegal ops. */
|
||||
goto illegal_op;
|
||||
} else {
|
||||
switch (op) {
|
||||
case 0x0a: /* rbit */
|
||||
case 0x08: /* rev */
|
||||
case 0x09: /* rev16 */
|
||||
case 0x0b: /* revsh */
|
||||
break;
|
||||
case 0x10: /* sel */
|
||||
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
|
||||
goto illegal_op;
|
||||
}
|
||||
break;
|
||||
case 0x18: /* clz, in decodetree */
|
||||
case 0x20: /* crc32/crc32c, in decodetree */
|
||||
case 0x21:
|
||||
case 0x22:
|
||||
case 0x28:
|
||||
case 0x29:
|
||||
case 0x2a:
|
||||
goto illegal_op;
|
||||
default:
|
||||
goto illegal_op;
|
||||
}
|
||||
tmp = load_reg(s, rn);
|
||||
switch (op) {
|
||||
case 0x0a: /* rbit */
|
||||
gen_helper_rbit(tcg_ctx, tmp, tmp);
|
||||
break;
|
||||
case 0x08: /* rev */
|
||||
tcg_gen_bswap32_i32(tcg_ctx, tmp, tmp);
|
||||
break;
|
||||
case 0x09: /* rev16 */
|
||||
gen_rev16(s, tmp);
|
||||
break;
|
||||
case 0x0b: /* revsh */
|
||||
gen_revsh(s, tmp);
|
||||
break;
|
||||
case 0x10: /* sel */
|
||||
tmp2 = load_reg(s, rm);
|
||||
tmp3 = tcg_temp_new_i32(tcg_ctx);
|
||||
tcg_gen_ld_i32(tcg_ctx, tmp3, tcg_ctx->cpu_env, offsetof(CPUARMState, GE));
|
||||
gen_helper_sel_flags(tcg_ctx, tmp, tmp3, tmp, tmp2);
|
||||
tcg_temp_free_i32(tcg_ctx, tmp3);
|
||||
tcg_temp_free_i32(tcg_ctx, tmp2);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
store_reg(s, rd, tmp);
|
||||
break;
|
||||
case 4: case 5: /* 32-bit multiply. Sum of absolute differences. */
|
||||
switch ((insn >> 20) & 7) {
|
||||
case 0: /* 32 x 32 -> 32 */
|
||||
|
@ -11103,60 +11155,8 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
|
|||
* - Data-processing (plain binary immediate)
|
||||
*/
|
||||
if (insn & (1 << 24)) {
|
||||
if (insn & (1 << 20))
|
||||
goto illegal_op;
|
||||
/* Bitfield/Saturate. */
|
||||
op = (insn >> 21) & 7;
|
||||
imm = insn & 0x1f;
|
||||
shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
|
||||
if (rn == 15) {
|
||||
tmp = tcg_temp_new_i32(tcg_ctx);
|
||||
tcg_gen_movi_i32(tcg_ctx, tmp, 0);
|
||||
} else {
|
||||
tmp = load_reg(s, rn);
|
||||
}
|
||||
switch (op) {
|
||||
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. */
|
||||
if (op & 1) {
|
||||
tcg_gen_sari_i32(tcg_ctx, tmp, tmp, shift);
|
||||
} else {
|
||||
tcg_gen_shli_i32(tcg_ctx, tmp, tmp, shift);
|
||||
}
|
||||
tmp2 = tcg_const_i32(tcg_ctx, imm);
|
||||
if (op & 4) {
|
||||
/* Unsigned. */
|
||||
if ((op & 1) && shift == 0) {
|
||||
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
|
||||
tcg_temp_free_i32(tcg_ctx, tmp);
|
||||
tcg_temp_free_i32(tcg_ctx, tmp2);
|
||||
goto illegal_op;
|
||||
}
|
||||
gen_helper_usat16(tcg_ctx, tmp, tcg_ctx->cpu_env, tmp, tmp2);
|
||||
} else {
|
||||
gen_helper_usat(tcg_ctx, tmp, tcg_ctx->cpu_env, tmp, tmp2);
|
||||
}
|
||||
} else {
|
||||
/* Signed. */
|
||||
if ((op & 1) && shift == 0) {
|
||||
if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
|
||||
tcg_temp_free_i32(tcg_ctx, tmp);
|
||||
tcg_temp_free_i32(tcg_ctx, tmp2);
|
||||
goto illegal_op;
|
||||
}
|
||||
gen_helper_ssat16(tcg_ctx, tmp, tcg_ctx->cpu_env, tmp, tmp2);
|
||||
} else {
|
||||
gen_helper_ssat(tcg_ctx, tmp, tcg_ctx->cpu_env, tmp, tmp2);
|
||||
}
|
||||
}
|
||||
tcg_temp_free_i32(tcg_ctx, tmp2);
|
||||
break;
|
||||
}
|
||||
store_reg(s, rd, tmp);
|
||||
/* Bitfield/Saturate, in decodetree */
|
||||
goto illegal_op;
|
||||
} else {
|
||||
imm = ((insn & 0x04000000) >> 15)
|
||||
| ((insn & 0x7000) >> 4) | (insn & 0xff);
|
||||
|
@ -11849,8 +11849,8 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn)
|
|||
tmp = load_reg(s, rn);
|
||||
switch (op1) {
|
||||
case 0: tcg_gen_bswap32_i32(tcg_ctx, tmp, tmp); break;
|
||||
case 1: gen_rev16(s, tmp); break;
|
||||
case 3: gen_revsh(s, tmp); break;
|
||||
case 1: gen_rev16(s, tmp, tmp); break;
|
||||
case 3: gen_revsh(s, tmp, tmp); break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue