target-arm: A64: Implement CRC instructions
Implement the optional A64 CRC instructions. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 1401458125-27977-6-git-send-email-peter.maydell@linaro.org
This commit is contained in:
parent
da5141fc45
commit
130f2e7dcb
@ -540,6 +540,7 @@ static uint32_t get_elf_hwcap(void)
|
|||||||
#define GET_FEATURE(feat, hwcap) \
|
#define GET_FEATURE(feat, hwcap) \
|
||||||
do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0)
|
do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0)
|
||||||
GET_FEATURE(ARM_FEATURE_V8_PMULL, ARM_HWCAP_A64_PMULL);
|
GET_FEATURE(ARM_FEATURE_V8_PMULL, ARM_HWCAP_A64_PMULL);
|
||||||
|
GET_FEATURE(ARM_FEATURE_CRC, ARM_HWCAP_A64_CRC32);
|
||||||
#undef GET_FEATURE
|
#undef GET_FEATURE
|
||||||
|
|
||||||
return hwcaps;
|
return hwcaps;
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "qemu/bitops.h"
|
#include "qemu/bitops.h"
|
||||||
#include "internals.h"
|
#include "internals.h"
|
||||||
|
#include "qemu/crc32c.h"
|
||||||
|
#include <zlib.h> /* For crc32 */
|
||||||
|
|
||||||
/* C2.4.7 Multiply and divide */
|
/* C2.4.7 Multiply and divide */
|
||||||
/* special cases for 0 and LLONG_MIN are mandated by the standard */
|
/* special cases for 0 and LLONG_MIN are mandated by the standard */
|
||||||
@ -408,6 +410,34 @@ float32 HELPER(fcvtx_f64_to_f32)(float64 a, CPUARMState *env)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 64-bit versions of the CRC helpers. Note that although the operation
|
||||||
|
* (and the prototypes of crc32c() and crc32() mean that only the bottom
|
||||||
|
* 32 bits of the accumulator and result are used, we pass and return
|
||||||
|
* uint64_t for convenience of the generated code. Unlike the 32-bit
|
||||||
|
* instruction set versions, val may genuinely have 64 bits of data in it.
|
||||||
|
* The upper bytes of val (above the number specified by 'bytes') must have
|
||||||
|
* been zeroed out by the caller.
|
||||||
|
*/
|
||||||
|
uint64_t HELPER(crc32_64)(uint64_t acc, uint64_t val, uint32_t bytes)
|
||||||
|
{
|
||||||
|
uint8_t buf[8];
|
||||||
|
|
||||||
|
stq_le_p(buf, val);
|
||||||
|
|
||||||
|
/* zlib crc32 converts the accumulator and output to one's complement. */
|
||||||
|
return crc32(acc ^ 0xffffffff, buf, bytes) ^ 0xffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t HELPER(crc32c_64)(uint64_t acc, uint64_t val, uint32_t bytes)
|
||||||
|
{
|
||||||
|
uint8_t buf[8];
|
||||||
|
|
||||||
|
stq_le_p(buf, val);
|
||||||
|
|
||||||
|
/* Linux crc32c converts the output to one's complement. */
|
||||||
|
return crc32c(acc, buf, bytes) ^ 0xffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
/* Handle a CPU exception. */
|
/* Handle a CPU exception. */
|
||||||
void aarch64_cpu_do_interrupt(CPUState *cs)
|
void aarch64_cpu_do_interrupt(CPUState *cs)
|
||||||
{
|
{
|
||||||
|
@ -44,3 +44,5 @@ DEF_HELPER_FLAGS_1(neon_addlp_u16, TCG_CALL_NO_RWG_SE, i64, i64)
|
|||||||
DEF_HELPER_FLAGS_2(frecpx_f64, TCG_CALL_NO_RWG, f64, f64, ptr)
|
DEF_HELPER_FLAGS_2(frecpx_f64, TCG_CALL_NO_RWG, f64, f64, ptr)
|
||||||
DEF_HELPER_FLAGS_2(frecpx_f32, TCG_CALL_NO_RWG, f32, f32, ptr)
|
DEF_HELPER_FLAGS_2(frecpx_f32, TCG_CALL_NO_RWG, f32, f32, ptr)
|
||||||
DEF_HELPER_FLAGS_2(fcvtx_f64_to_f32, TCG_CALL_NO_RWG, f32, f64, env)
|
DEF_HELPER_FLAGS_2(fcvtx_f64_to_f32, TCG_CALL_NO_RWG, f32, f64, env)
|
||||||
|
DEF_HELPER_FLAGS_3(crc32_64, TCG_CALL_NO_RWG_SE, i64, i64, i64, i32)
|
||||||
|
DEF_HELPER_FLAGS_3(crc32c_64, TCG_CALL_NO_RWG_SE, i64, i64, i64, i32)
|
||||||
|
@ -3774,6 +3774,54 @@ static void handle_shift_reg(DisasContext *s,
|
|||||||
tcg_temp_free_i64(tcg_shift);
|
tcg_temp_free_i64(tcg_shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* CRC32[BHWX], CRC32C[BHWX] */
|
||||||
|
static void handle_crc32(DisasContext *s,
|
||||||
|
unsigned int sf, unsigned int sz, bool crc32c,
|
||||||
|
unsigned int rm, unsigned int rn, unsigned int rd)
|
||||||
|
{
|
||||||
|
TCGv_i64 tcg_acc, tcg_val;
|
||||||
|
TCGv_i32 tcg_bytes;
|
||||||
|
|
||||||
|
if (!arm_dc_feature(s, ARM_FEATURE_CRC)
|
||||||
|
|| (sf == 1 && sz != 3)
|
||||||
|
|| (sf == 0 && sz == 3)) {
|
||||||
|
unallocated_encoding(s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sz == 3) {
|
||||||
|
tcg_val = cpu_reg(s, rm);
|
||||||
|
} else {
|
||||||
|
uint64_t mask;
|
||||||
|
switch (sz) {
|
||||||
|
case 0:
|
||||||
|
mask = 0xFF;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
mask = 0xFFFF;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
mask = 0xFFFFFFFF;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
tcg_val = new_tmp_a64(s);
|
||||||
|
tcg_gen_andi_i64(tcg_val, cpu_reg(s, rm), mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
tcg_acc = cpu_reg(s, rn);
|
||||||
|
tcg_bytes = tcg_const_i32(1 << sz);
|
||||||
|
|
||||||
|
if (crc32c) {
|
||||||
|
gen_helper_crc32c_64(cpu_reg(s, rd), tcg_acc, tcg_val, tcg_bytes);
|
||||||
|
} else {
|
||||||
|
gen_helper_crc32_64(cpu_reg(s, rd), tcg_acc, tcg_val, tcg_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
tcg_temp_free_i32(tcg_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
/* C3.5.8 Data-processing (2 source)
|
/* C3.5.8 Data-processing (2 source)
|
||||||
* 31 30 29 28 21 20 16 15 10 9 5 4 0
|
* 31 30 29 28 21 20 16 15 10 9 5 4 0
|
||||||
* +----+---+---+-----------------+------+--------+------+------+
|
* +----+---+---+-----------------+------+--------+------+------+
|
||||||
@ -3821,8 +3869,12 @@ static void disas_data_proc_2src(DisasContext *s, uint32_t insn)
|
|||||||
case 21:
|
case 21:
|
||||||
case 22:
|
case 22:
|
||||||
case 23: /* CRC32 */
|
case 23: /* CRC32 */
|
||||||
unsupported_encoding(s, insn);
|
{
|
||||||
|
int sz = extract32(opcode, 0, 2);
|
||||||
|
bool crc32c = extract32(opcode, 2, 1);
|
||||||
|
handle_crc32(s, sf, sz, crc32c, rm, rn, rd);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
unallocated_encoding(s);
|
unallocated_encoding(s);
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user