From: Giacomo Travaglini Date: Fri, 13 Oct 2017 09:03:14 +0000 (+0100) Subject: arm: Add support for armv8 CRC32 instructions X-Git-Tag: v19.0.0.0~2561 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=ef0490081fa7ebcda2e1c7adccb05b3a14014cf1;p=gem5.git arm: Add support for armv8 CRC32 instructions This patch introduces the ARM A32/T32/A64 CRC Instructions, which are mandatory since ARMv8.1. The UNPREDICTABLE behaviours are implemented as follows: 1) CRC32(C)X (64 bit) instructions are decoded as Undefined in Aarch32 2) The instructions support predication in Aarch32 3) Using R15(PC) as source/dest operand is permitted in Aarch32 Change-Id: Iaf29b05874e1370c7615da79a07f111ded17b6cc Signed-off-by: Giacomo Travaglini Reviewed-by: Andreas Sandberg Reviewed-by: Nikos Nikoleris Reviewed-by: Giacomo Gabrielli Reviewed-on: https://gem5-review.googlesource.com/5521 Maintainer: Andreas Sandberg --- diff --git a/src/arch/arm/isa/decoder/arm.isa b/src/arch/arm/isa/decoder/arm.isa index f0c0dec18..9b8b37a9c 100644 --- a/src/arch/arm/isa/decoder/arm.isa +++ b/src/arch/arm/isa/decoder/arm.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010-2013 ARM Limited +// Copyright (c) 2010-2013,2017 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -72,6 +72,7 @@ format DataOp { 0x3: decode OPCODE { 0x9: ArmBlxReg::armBlxReg(); } + 0x4: Crc32::crc32(); 0x5: ArmSatAddSub::armSatAddSub(); 0x6: ArmERet::armERet(); 0x7: decode OPCODE_22 { diff --git a/src/arch/arm/isa/formats/aarch64.isa b/src/arch/arm/isa/formats/aarch64.isa index 38e5b15a0..2c33e2441 100644 --- a/src/arch/arm/isa/formats/aarch64.isa +++ b/src/arch/arm/isa/formats/aarch64.isa @@ -1202,6 +1202,22 @@ namespace Aarch64 return new Asrv64(machInst, rdzr, rn, rm); case 0xb: return new Rorv64(machInst, rdzr, rn, rm); + case 0x10: + return new Crc32b64(machInst, rdzr, rn, rm); + case 0x11: + return new Crc32h64(machInst, rdzr, rn, rm); + case 0x12: + return new Crc32w64(machInst, rdzr, rn, rm); + case 0x13: + return new Crc32x64(machInst, rdzr, rn, rm); + case 0x14: + return new Crc32cb64(machInst, rdzr, rn, rm); + case 0x15: + return new Crc32ch64(machInst, rdzr, rn, rm); + case 0x16: + return new Crc32cw64(machInst, rdzr, rn, rm); + case 0x17: + return new Crc32cx64(machInst, rdzr, rn, rm); default: return new Unknown64(machInst); } diff --git a/src/arch/arm/isa/formats/data.isa b/src/arch/arm/isa/formats/data.isa index 3ee178f0e..909a52593 100644 --- a/src/arch/arm/isa/formats/data.isa +++ b/src/arch/arm/isa/formats/data.isa @@ -1,4 +1,4 @@ -// Copyright (c) 2010 ARM Limited +// Copyright (c) 2010,2017 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -788,7 +788,7 @@ def format Thumb32DataProcReg() {{ } } } else if (bits(op1, 3, 2) == 0x2 && bits(op2, 3, 2) == 0x2) { - const uint32_t op1 = bits(machInst, 21, 20); + const uint32_t op1 = bits(machInst, 22, 20); const uint32_t op2 = bits(machInst, 5, 4); const IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 11, 8); @@ -832,6 +832,27 @@ def format Thumb32DataProcReg() {{ if (op2 == 0) { return new Clz(machInst, rd, rm); } + break; + case 0x4: + switch (op2) { + case 0x0: + return new Crc32b(machInst, rd, rn, rm); + case 0x1: + return new Crc32h(machInst, rd, rn, rm); + case 0x2: + return new Crc32w(machInst, rd, rn, rm); + } + break; + case 0x5: + switch (op2) { + case 0x0: + return new Crc32cb(machInst, rd, rn, rm); + case 0x1: + return new Crc32ch(machInst, rd, rn, rm); + case 0x2: + return new Crc32cw(machInst, rd, rn, rm); + } + break; } } return new Unknown(machInst); diff --git a/src/arch/arm/isa/formats/misc.isa b/src/arch/arm/isa/formats/misc.isa index 43a7cc975..26681e40f 100644 --- a/src/arch/arm/isa/formats/misc.isa +++ b/src/arch/arm/isa/formats/misc.isa @@ -38,6 +38,37 @@ // Authors: Gabe Black // Giacomo Gabrielli +def format Crc32() {{ + decode_block = ''' + { + const IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 3, 0); + const IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 19, 16); + const IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); + + uint8_t c_poly = bits(machInst, 9); + uint8_t sz = bits(machInst, 22, 21); + uint8_t crc_select = (c_poly << 2) | sz; + + switch(crc_select) { + case 0x0: + return new Crc32b(machInst, rd, rn, rm); + case 0x1: + return new Crc32h(machInst, rd, rn, rm); + case 0x2: + return new Crc32w(machInst, rd, rn, rm); + case 0x4: + return new Crc32cb(machInst, rd, rn, rm); + case 0x5: + return new Crc32ch(machInst, rd, rn, rm); + case 0x6: + return new Crc32cw(machInst, rd, rn, rm); + default: + return new Unknown(machInst); + } + } + ''' +}}; + def format ArmERet() {{ decode_block = "return new Eret(machInst);" }}; diff --git a/src/arch/arm/isa/includes.isa b/src/arch/arm/isa/includes.isa index fe0b3ea2b..caba46de9 100644 --- a/src/arch/arm/isa/includes.isa +++ b/src/arch/arm/isa/includes.isa @@ -1,6 +1,6 @@ // -*- mode:c++ -*- -// Copyright (c) 2010, 2012 ARM Limited +// Copyright (c) 2010, 2012, 2017 ARM Limited // All rights reserved // // The license below extends only to copyright in the software and shall @@ -95,6 +95,7 @@ output exec {{ #include "arch/arm/utility.hh" #include "arch/generic/memhelpers.hh" #include "base/condcodes.hh" +#include "base/crc.hh" #include "cpu/base.hh" #include "sim/pseudo_inst.hh" #if defined(linux) diff --git a/src/arch/arm/isa/insts/data64.isa b/src/arch/arm/isa/insts/data64.isa index 3284d5b2a..d0ee439cb 100644 --- a/src/arch/arm/isa/insts/data64.isa +++ b/src/arch/arm/isa/insts/data64.isa @@ -226,6 +226,42 @@ let {{ "Dest64 = shiftReg64(Op164, Op264, LSR, intWidth)") buildDataXRegInst("rorv", 2, "Dest64 = shiftReg64(Op164, Op264, ROR, intWidth)") + + crcCode = ''' + constexpr uint8_t size_bytes = %(sz)d; + constexpr uint32_t poly = %(polynom)s; + + // Initial value is often a previously evaluated + // crc value hence is always 32bit in CRC32 + uint32_t initial_crc = Op164 & 0xFFFFFFFF; + + uint64_t data = htole(Op264); + auto data_buffer = reinterpret_cast(&data); + + Dest = crc32( + data_buffer, /* Message register */ + initial_crc, /* Initial value of the CRC */ + size_bytes /* Size of the original Message */ + ); + ''' + buildDataXRegInst("crc32b", 2, + crcCode % {"sz": 1, "polynom": "0x04C11DB7"}) + buildDataXRegInst("crc32h", 2, + crcCode % {"sz": 2, "polynom": "0x04C11DB7"}) + buildDataXRegInst("crc32w", 2, + crcCode % {"sz": 4, "polynom": "0x04C11DB7"}) + buildDataXRegInst("crc32x", 2, + crcCode % {"sz": 8, "polynom": "0x04C11DB7"}) + + buildDataXRegInst("crc32cb", 2, + crcCode % {"sz": 1, "polynom": "0x1EDC6F41"}) + buildDataXRegInst("crc32ch", 2, + crcCode % {"sz": 2, "polynom": "0x1EDC6F41"}) + buildDataXRegInst("crc32cw", 2, + crcCode % {"sz": 4, "polynom": "0x1EDC6F41"}) + buildDataXRegInst("crc32cx", 2, + crcCode % {"sz": 8, "polynom": "0x1EDC6F41"}) + buildDataXRegInst("sdiv", 2, ''' int64_t op1 = Op164; int64_t op2 = Op264; diff --git a/src/arch/arm/isa/insts/misc.isa b/src/arch/arm/isa/insts/misc.isa index edeb0f6d3..4681d50a9 100644 --- a/src/arch/arm/isa/insts/misc.isa +++ b/src/arch/arm/isa/insts/misc.isa @@ -136,7 +136,47 @@ let {{ decoder_output += BasicConstructor.subst(eretIop) exec_output += PredOpExecute.subst(eretIop) + crcCode = ''' + constexpr uint8_t size_bytes = %(sz)d; + constexpr uint32_t poly = %(polynom)s; + + uint32_t data = htole(Op2); + auto data_buffer = reinterpret_cast(&data); + + Dest = crc32( + data_buffer, /* Message Register */ + Op1, /* Initial Value of the CRC */ + size_bytes /* Size of the original Message */ + ); + ''' + + def crc32Emit(mnem, implCode, castagnoli, size): + global header_output, decoder_output, exec_output + + if castagnoli: + # crc32c instructions + poly = "0x1EDC6F41" + else: + # crc32 instructions + poly = "0x04C11DB7" + data = {'sz' : size, 'polynom': poly} + + instCode = implCode % data + + crcIop = InstObjParams(mnem, mnem.capitalize(), "RegRegRegOp", + { "code": instCode, + "predicate_test": predicateTest }, []) + header_output += RegRegRegOpDeclare.subst(crcIop) + decoder_output += RegRegRegOpConstructor.subst(crcIop) + exec_output += PredOpExecute.subst(crcIop) + + crc32Emit("crc32b", crcCode, False, 1); + crc32Emit("crc32h", crcCode, False, 2); + crc32Emit("crc32w", crcCode, False, 4); + crc32Emit("crc32cb", crcCode, True, 1); + crc32Emit("crc32ch", crcCode, True, 2); + crc32Emit("crc32cw", crcCode, True, 4); }}; diff --git a/src/base/crc.hh b/src/base/crc.hh new file mode 100644 index 000000000..132a15c13 --- /dev/null +++ b/src/base/crc.hh @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2017 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Giacomo Travaglini + */ + +#ifndef __BASE_CRC_HH__ +#define __BASE_CRC_HH__ + +#include "base/bitfield.hh" + +/** + * Evaluate the CRC32 of the first size bytes of a data buffer, + * using a specific polynomium and an initial value. + * The crc is accomplished by reversing the input, the initial value + * and the output (remainder). + * + * @param data: Input data buffer pointer + * @param crc: Initial value of the checksum + * @param size: Number of bytes + * + * @return 32-bit remainder of the checksum + */ +template +uint32_t +crc32(const uint8_t* data, uint32_t crc, std::size_t size) +{ + uint32_t byte = 0; + + crc = reverseBits(crc); + for (auto i = 0; i < size; i++) { + byte = data[i]; + + // 32-bit reverse + byte = reverseBits(byte); + for (auto j = 0; j <= 7; j++) { + if ((int)(crc ^ byte) < 0) { + crc = (crc << 1) ^ Poly; + } else { + crc = crc << 1; + } + byte = byte << 1; + } + } + return reverseBits(crc); +} + +#endif // __BASE_CRC_HH__