target-arm: A64: Add SIMD copy operations

This adds support for the all the AdvSIMD vector copy operations
(ARM ARM 3.6.5).

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Alex Bennée 2014-01-31 14:47:31 +00:00 committed by Peter Maydell
parent 4a0ff1ce73
commit 67bb93890d

View File

@ -5069,6 +5069,173 @@ static void disas_simd_across_lanes(DisasContext *s, uint32_t insn)
tcg_temp_free_i64(tcg_res); tcg_temp_free_i64(tcg_res);
} }
/* C6.3.31 DUP (Element, Vector)
*
* 31 30 29 21 20 16 15 10 9 5 4 0
* +---+---+-------------------+--------+-------------+------+------+
* | 0 | Q | 0 0 1 1 1 0 0 0 0 | imm5 | 0 0 0 0 0 1 | Rn | Rd |
* +---+---+-------------------+--------+-------------+------+------+
*
* size: encoded in imm5 (see ARM ARM LowestSetBit())
*/
static void handle_simd_dupe(DisasContext *s, int is_q, int rd, int rn,
int imm5)
{
int size = ctz32(imm5);
int esize = 8 << size;
int elements = (is_q ? 128 : 64) / esize;
int index, i;
TCGv_i64 tmp;
if (size > 3 || (size == 3 && !is_q)) {
unallocated_encoding(s);
return;
}
index = imm5 >> (size + 1);
tmp = tcg_temp_new_i64();
read_vec_element(s, tmp, rn, index, size);
for (i = 0; i < elements; i++) {
write_vec_element(s, tmp, rd, i, size);
}
if (!is_q) {
clear_vec_high(s, rd);
}
tcg_temp_free_i64(tmp);
}
/* C6.3.32 DUP (General)
*
* 31 30 29 21 20 16 15 10 9 5 4 0
* +---+---+-------------------+--------+-------------+------+------+
* | 0 | Q | 0 0 1 1 1 0 0 0 0 | imm5 | 0 0 0 0 1 1 | Rn | Rd |
* +---+---+-------------------+--------+-------------+------+------+
*
* size: encoded in imm5 (see ARM ARM LowestSetBit())
*/
static void handle_simd_dupg(DisasContext *s, int is_q, int rd, int rn,
int imm5)
{
int size = ctz32(imm5);
int esize = 8 << size;
int elements = (is_q ? 128 : 64)/esize;
int i = 0;
if (size > 3 || ((size == 3) && !is_q)) {
unallocated_encoding(s);
return;
}
for (i = 0; i < elements; i++) {
write_vec_element(s, cpu_reg(s, rn), rd, i, size);
}
if (!is_q) {
clear_vec_high(s, rd);
}
}
/* C6.3.150 INS (Element)
*
* 31 21 20 16 15 14 11 10 9 5 4 0
* +-----------------------+--------+------------+---+------+------+
* | 0 1 1 0 1 1 1 0 0 0 0 | imm5 | 0 | imm4 | 1 | Rn | Rd |
* +-----------------------+--------+------------+---+------+------+
*
* size: encoded in imm5 (see ARM ARM LowestSetBit())
* index: encoded in imm5<4:size+1>
*/
static void handle_simd_inse(DisasContext *s, int rd, int rn,
int imm4, int imm5)
{
int size = ctz32(imm5);
int src_index, dst_index;
TCGv_i64 tmp;
if (size > 3) {
unallocated_encoding(s);
return;
}
dst_index = extract32(imm5, 1+size, 5);
src_index = extract32(imm4, size, 4);
tmp = tcg_temp_new_i64();
read_vec_element(s, tmp, rn, src_index, size);
write_vec_element(s, tmp, rd, dst_index, size);
tcg_temp_free_i64(tmp);
}
/* C6.3.151 INS (General)
*
* 31 21 20 16 15 10 9 5 4 0
* +-----------------------+--------+-------------+------+------+
* | 0 1 0 0 1 1 1 0 0 0 0 | imm5 | 0 0 0 1 1 1 | Rn | Rd |
* +-----------------------+--------+-------------+------+------+
*
* size: encoded in imm5 (see ARM ARM LowestSetBit())
* index: encoded in imm5<4:size+1>
*/
static void handle_simd_insg(DisasContext *s, int rd, int rn, int imm5)
{
int size = ctz32(imm5);
int idx;
if (size > 3) {
unallocated_encoding(s);
return;
}
idx = extract32(imm5, 1 + size, 4 - size);
write_vec_element(s, cpu_reg(s, rn), rd, idx, size);
}
/*
* C6.3.321 UMOV (General)
* C6.3.237 SMOV (General)
*
* 31 30 29 21 20 16 15 12 10 9 5 4 0
* +---+---+-------------------+--------+-------------+------+------+
* | 0 | Q | 0 0 1 1 1 0 0 0 0 | imm5 | 0 0 1 U 1 1 | Rn | Rd |
* +---+---+-------------------+--------+-------------+------+------+
*
* U: unsigned when set
* size: encoded in imm5 (see ARM ARM LowestSetBit())
*/
static void handle_simd_umov_smov(DisasContext *s, int is_q, int is_signed,
int rn, int rd, int imm5)
{
int size = ctz32(imm5);
int element;
TCGv_i64 tcg_rd;
/* Check for UnallocatedEncodings */
if (is_signed) {
if (size > 2 || (size == 2 && !is_q)) {
unallocated_encoding(s);
return;
}
} else {
if (size > 3
|| (size < 3 && is_q)
|| (size == 3 && !is_q)) {
unallocated_encoding(s);
return;
}
}
element = extract32(imm5, 1+size, 4);
tcg_rd = cpu_reg(s, rd);
read_vec_element(s, tcg_rd, rn, element, size | (is_signed ? MO_SIGN : 0));
if (is_signed && !is_q) {
tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
}
}
/* C3.6.5 AdvSIMD copy /* C3.6.5 AdvSIMD copy
* 31 30 29 28 21 20 16 15 14 11 10 9 5 4 0 * 31 30 29 28 21 20 16 15 14 11 10 9 5 4 0
* +---+---+----+-----------------+------+---+------+---+------+------+ * +---+---+----+-----------------+------+---+------+---+------+------+
@ -5077,7 +5244,48 @@ static void disas_simd_across_lanes(DisasContext *s, uint32_t insn)
*/ */
static void disas_simd_copy(DisasContext *s, uint32_t insn) static void disas_simd_copy(DisasContext *s, uint32_t insn)
{ {
unsupported_encoding(s, insn); int rd = extract32(insn, 0, 5);
int rn = extract32(insn, 5, 5);
int imm4 = extract32(insn, 11, 4);
int op = extract32(insn, 29, 1);
int is_q = extract32(insn, 30, 1);
int imm5 = extract32(insn, 16, 5);
if (op) {
if (is_q) {
/* INS (element) */
handle_simd_inse(s, rd, rn, imm4, imm5);
} else {
unallocated_encoding(s);
}
} else {
switch (imm4) {
case 0:
/* DUP (element - vector) */
handle_simd_dupe(s, is_q, rd, rn, imm5);
break;
case 1:
/* DUP (general) */
handle_simd_dupg(s, is_q, rd, rn, imm5);
break;
case 3:
if (is_q) {
/* INS (general) */
handle_simd_insg(s, rd, rn, imm5);
} else {
unallocated_encoding(s);
}
break;
case 5:
case 7:
/* UMOV/SMOV (is_q indicates 32/64; imm4 indicates signedness) */
handle_simd_umov_smov(s, is_q, (imm4 == 5), rn, rd, imm5);
break;
default:
unallocated_encoding(s);
break;
}
}
} }
/* C3.6.6 AdvSIMD modified immediate /* C3.6.6 AdvSIMD modified immediate