diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-06-09 15:43:25 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-06-09 16:06:12 +0100 |
commit | 130f2e7dcb4a5f9534fc65200121f06983435a77 (patch) | |
tree | 24d33bae4c819916142f6b9ccc21164c64393bcc | |
parent | da5141fc45937fa358ca4554a335ae6a4c4453ec (diff) |
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
-rw-r--r-- | linux-user/elfload.c | 1 | ||||
-rw-r--r-- | target-arm/helper-a64.c | 30 | ||||
-rw-r--r-- | target-arm/helper-a64.h | 2 | ||||
-rw-r--r-- | target-arm/translate-a64.c | 54 |
4 files changed, 86 insertions, 1 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c index e8724939f8..f2d5955230 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -540,6 +540,7 @@ static uint32_t get_elf_hwcap(void) #define GET_FEATURE(feat, hwcap) \ 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_CRC, ARM_HWCAP_A64_CRC32); #undef GET_FEATURE return hwcaps; diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c index f0d27229d4..2b4ce6ac60 100644 --- a/target-arm/helper-a64.c +++ b/target-arm/helper-a64.c @@ -24,6 +24,8 @@ #include "sysemu/sysemu.h" #include "qemu/bitops.h" #include "internals.h" +#include "qemu/crc32c.h" +#include <zlib.h> /* For crc32 */ /* C2.4.7 Multiply and divide */ /* 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; } +/* 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. */ void aarch64_cpu_do_interrupt(CPUState *cs) { diff --git a/target-arm/helper-a64.h b/target-arm/helper-a64.h index 8de7536ff7..1d3d10fffb 100644 --- a/target-arm/helper-a64.h +++ b/target-arm/helper-a64.h @@ -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_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_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) diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index 9832cc3c22..6af593a26e 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -3774,6 +3774,54 @@ static void handle_shift_reg(DisasContext *s, 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) * 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 22: 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; + } default: unallocated_encoding(s); break; |