From b0e05ec7c0048ee02c286d39b13dd60670a926aa Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Mon, 8 Jun 2026 17:16:14 +0200 Subject: [PATCH 1/3] [hardware] Add crypto extension parametrization scaffold Introduce the configuration mechanism for the RISC-V vector crypto extensions ahead of the actual instruction implementations. This adds the crypto_support_e enumeration to ara_pkg and threads a CryptoSupport parameter (defaulting to CryptoSupportNone) through the full module hierarchy: ara_soc -> ara_system -> ara -> {ara_dispatcher, lane -> vector_fus_stage -> valu -> simd_alu}. No instructions are implemented yet; subsequent commits enable specific extensions by adding enum values, helper predicates, and datapath logic gated on this parameter. Co-Authored-By: Claude Opus 4.8 (1M context) --- hardware/include/ara_pkg.sv | 6 ++++++ hardware/src/ara.sv | 4 ++++ hardware/src/ara_dispatcher.sv | 2 ++ hardware/src/ara_soc.sv | 3 +++ hardware/src/ara_system.sv | 3 +++ hardware/src/lane/lane.sv | 3 +++ hardware/src/lane/simd_alu.sv | 1 + hardware/src/lane/valu.sv | 5 ++++- hardware/src/lane/vector_fus_stage.sv | 3 +++ 9 files changed, 29 insertions(+), 1 deletion(-) diff --git a/hardware/include/ara_pkg.sv b/hardware/include/ara_pkg.sv index 3b269e714..551e8e6d8 100644 --- a/hardware/include/ara_pkg.sv +++ b/hardware/include/ara_pkg.sv @@ -79,6 +79,12 @@ package ara_pkg; return e[0]; endfunction : RVVBA + // Support for the vector crypto extensions. + // 16 bits correspond to {Zvbb, Zvbc, Zvkb, Zvkg, Zvkned, Zvknha, Zvknhb, Zvksed, Zvksh, Zvkn, Zvknc, Zvkng, Zvks, Zvksc, Zvksg, Zvkt} + typedef enum bit [15:0] { + CryptoSupportNone = 16'h0000 + } crypto_support_e; + // Multiplier latencies. localparam int unsigned LatMultiplierEW64 = 1; localparam int unsigned LatMultiplierEW32 = 1; diff --git a/hardware/src/ara.sv b/hardware/src/ara.sv index 4cb9a9506..af5497c5d 100644 --- a/hardware/src/ara.sv +++ b/hardware/src/ara.sv @@ -19,6 +19,8 @@ module ara import ara_pkg::*; #( parameter fixpt_support_e FixPtSupport = FixedPointEnable, // Support for segment memory operations parameter seg_support_e SegSupport = SegSupportEnable, + // Support for crypto extension + parameter crypto_support_e CryptoSupport = CryptoSupportNone, // CVA6 configuration parameter config_pkg::cva6_cfg_t CVA6Cfg = cva6_config_pkg::cva6_cfg, // CVA6-related parameters @@ -204,6 +206,7 @@ module ara import ara_pkg::*; #( .VLEN (VLEN ), .FPUSupport (FPUSupport ), .SegSupport (SegSupport ), + .CryptoSupport (CryptoSupport ), .ara_req_t (ara_req_t ), .ara_resp_t (ara_resp_t ), .accelerator_req_t (accelerator_req_t ), @@ -374,6 +377,7 @@ module ara import ara_pkg::*; #( .FPUSupport (FPUSupport ), .FPExtSupport (FPExtSupport ), .FixPtSupport (FixPtSupport ), + .CryptoSupport (CryptoSupport ), .pe_req_t_bits ($bits(pe_req_t) ), .pe_resp_t_bits ($bits(pe_resp_t) ) ) i_lane ( diff --git a/hardware/src/ara_dispatcher.sv b/hardware/src/ara_dispatcher.sv index e5f9e06d5..027a94a0c 100644 --- a/hardware/src/ara_dispatcher.sv +++ b/hardware/src/ara_dispatcher.sv @@ -26,6 +26,8 @@ module ara_dispatcher import ara_pkg::*; import rvv_pkg::*; #( parameter fixpt_support_e FixPtSupport = FixedPointEnable, // Support for segment memory operations parameter seg_support_e SegSupport = SegSupportEnable, + // Support for crypto extension + parameter crypto_support_e CryptoSupport = CryptoSupportNone, // Dependent parameters: DO NOT CHANGE localparam type vlen_t = logic[$clog2(VLEN+1)-1:0], localparam int unsigned VLENB = VLEN / 8 diff --git a/hardware/src/ara_soc.sv b/hardware/src/ara_soc.sv index 5ee64e17c..3fdca205e 100644 --- a/hardware/src/ara_soc.sv +++ b/hardware/src/ara_soc.sv @@ -19,6 +19,8 @@ module ara_soc import axi_pkg::*; import ara_pkg::*; #( parameter fixpt_support_e FixPtSupport = FixedPointEnable, // Support for segment memory operations parameter seg_support_e SegSupport = SegSupportEnable, + // Support for crypto extension + parameter crypto_support_e CryptoSupport = CryptoSupportNone, // AXI Interface parameter int unsigned AxiDataWidth = 32*NrLanes, parameter int unsigned AxiAddrWidth = 64, @@ -503,6 +505,7 @@ module ara_soc import axi_pkg::*; import ara_pkg::*; #( .FPExtSupport (FPExtSupport ), .FixPtSupport (FixPtSupport ), .SegSupport (SegSupport ), + .CryptoSupport (CryptoSupport ), .CVA6Cfg (CVA6AraConfig ), .exception_t (exception_t ), .accelerator_req_t (accelerator_req_t ), diff --git a/hardware/src/ara_system.sv b/hardware/src/ara_system.sv index 4accbd77c..aa956734a 100644 --- a/hardware/src/ara_system.sv +++ b/hardware/src/ara_system.sv @@ -18,6 +18,8 @@ module ara_system import axi_pkg::*; import ara_pkg::*; #( parameter fixpt_support_e FixPtSupport = FixedPointEnable, // Support for segment memory operations parameter seg_support_e SegSupport = SegSupportEnable, + // Support for crypto extension + parameter crypto_support_e CryptoSupport = CryptoSupportNone, // Ariane configuration parameter config_pkg::cva6_cfg_t CVA6Cfg = cva6_config_pkg::cva6_cfg, // CVA6-related parameters @@ -228,6 +230,7 @@ module ara_system import axi_pkg::*; import ara_pkg::*; #( .FPExtSupport (FPExtSupport ), .FixPtSupport (FixPtSupport ), .SegSupport (SegSupport ), + .CryptoSupport (CryptoSupport ), .CVA6Cfg (CVA6Cfg ), .exception_t (exception_t ), .accelerator_req_t (accelerator_req_t ), diff --git a/hardware/src/lane/lane.sv b/hardware/src/lane/lane.sv index c17d87fad..7afe4df68 100644 --- a/hardware/src/lane/lane.sv +++ b/hardware/src/lane/lane.sv @@ -19,6 +19,8 @@ module lane import ara_pkg::*; import rvv_pkg::*; #( parameter fpext_support_e FPExtSupport = FPExtSupportEnable, // Support for fixed-point data types parameter fixpt_support_e FixPtSupport = FixedPointEnable, + // Support for crypto extension + parameter crypto_support_e CryptoSupport = CryptoSupportNone, // To please Verilator parameter int unsigned pe_req_t_bits = 0, parameter int unsigned pe_resp_t_bits = 0, @@ -498,6 +500,7 @@ module lane import ara_pkg::*; import rvv_pkg::*; #( .FPUSupport (FPUSupport ), .FPExtSupport (FPExtSupport ), .FixPtSupport (FixPtSupport ), + .CryptoSupport (CryptoSupport ), .vaddr_t (vaddr_t ), .vfu_operation_t(vfu_operation_t) ) i_vfus ( diff --git a/hardware/src/lane/simd_alu.sv b/hardware/src/lane/simd_alu.sv index b97016542..63c0023cc 100644 --- a/hardware/src/lane/simd_alu.sv +++ b/hardware/src/lane/simd_alu.sv @@ -9,6 +9,7 @@ module simd_alu import ara_pkg::*; import rvv_pkg::*; #( // Support for fixed-point data types parameter fixpt_support_e FixPtSupport = FixedPointEnable, + parameter crypto_support_e CryptoSupport = CryptoSupportNone, // Dependant parameters. DO NOT CHANGE! localparam int unsigned DataWidth = $bits(elen_t), localparam int unsigned StrbWidth = DataWidth/8, diff --git a/hardware/src/lane/valu.sv b/hardware/src/lane/valu.sv index 623f3c40a..3478fa6e2 100644 --- a/hardware/src/lane/valu.sv +++ b/hardware/src/lane/valu.sv @@ -12,6 +12,8 @@ module valu import ara_pkg::*; import rvv_pkg::*; import cf_math_pkg::idx_width; parameter int unsigned VLEN = 0, // Support for fixed-point data types parameter fixpt_support_e FixPtSupport = FixedPointEnable, + // Support for crypto extension + parameter crypto_support_e CryptoSupport = CryptoSupportNone, // Type used to address vector register file elements parameter type vaddr_t = logic, parameter type vfu_operation_t = logic, @@ -380,7 +382,8 @@ module valu import ara_pkg::*; import rvv_pkg::*; import cf_math_pkg::idx_width; assign alu_vxsat_d = alu_vxsat; simd_alu #( - .FixPtSupport (FixPtSupport ) + .FixPtSupport (FixPtSupport ), + .CryptoSupport (CryptoSupport ) ) i_simd_alu ( .operand_a_i (alu_operand_a ), .operand_b_i (alu_operand_b ), diff --git a/hardware/src/lane/vector_fus_stage.sv b/hardware/src/lane/vector_fus_stage.sv index df73e9267..57d41a314 100644 --- a/hardware/src/lane/vector_fus_stage.sv +++ b/hardware/src/lane/vector_fus_stage.sv @@ -17,6 +17,8 @@ module vector_fus_stage import ara_pkg::*; import rvv_pkg::*; import cf_math_pkg parameter fpext_support_e FPExtSupport = FPExtSupportEnable, // Support for fixed-point data types parameter fixpt_support_e FixPtSupport = FixedPointEnable, + // Support for crypto extension + parameter crypto_support_e CryptoSupport = CryptoSupportNone, // Type used to address vector register file elements parameter type vaddr_t = logic, parameter type vfu_operation_t = logic, @@ -108,6 +110,7 @@ module vector_fus_stage import ara_pkg::*; import rvv_pkg::*; import cf_math_pkg .NrLanes (NrLanes ), .VLEN (VLEN ), .FixPtSupport (FixPtSupport ), + .CryptoSupport (CryptoSupport ), .vaddr_t (vaddr_t ), .vfu_operation_t(vfu_operation_t) ) i_valu ( From e98d8013ee28723233e2b5b454f8ef5a072156b7 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Mon, 8 Jun 2026 17:19:39 +0200 Subject: [PATCH 2/3] [hardware] Add Zvkb vector crypto bit-manipulation extension Add the Zvkb (Vector Cryptography Bit-manipulation) extension, gated behind the CryptoSupportBitmanip configuration. Implements the following instructions in the SIMD ALU, with dispatch for .vv, .vx, and .vi encodings: - vandn.vv/vx: bitwise AND-with-complement - vrol.vv/vx, vror.vv/vx/vi: element-wise rotate left/right - vbrev8.v: bit-reverse within each byte - vrev8.v: byte-reverse within each element (endian swap) Adds a Zvkb() predicate over crypto_support_e, the new ALU op enums, and a riscv-tests suite (zvkb.c) covering all instructions across e8/e16/e32/e64 with masked variants. Enables zvkb in the LLVM and spike ISA strings. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/common/runtime.mk | 6 +- apps/riscv-tests/isa/Makefile | 4 +- apps/riscv-tests/isa/rv64uv/Makefrag | 1 + apps/riscv-tests/isa/rv64uv/zvkb.c | 653 +++++++++++++++++++++++++++ hardware/include/ara_pkg.sv | 9 +- hardware/src/ara_dispatcher.sv | 53 +++ hardware/src/ara_soc.sv | 2 +- hardware/src/lane/simd_alu.sv | 72 +++ 8 files changed, 793 insertions(+), 7 deletions(-) create mode 100644 apps/riscv-tests/isa/rv64uv/zvkb.c diff --git a/apps/common/runtime.mk b/apps/common/runtime.mk index b1316902a..2964c4b0c 100644 --- a/apps/common/runtime.mk +++ b/apps/common/runtime.mk @@ -79,8 +79,8 @@ RISCV_SIM ?= $(ISA_SIM_INSTALL_DIR)/bin/spike RISCV_SIM_MOD ?= $(ISA_SIM_MOD_INSTALL_DIR)/bin/spike # VLEN should be lower or equal than 4096 because of spike restrictions vlen_spike := $(shell vlen=$$(grep vlen $(ARA_DIR)/config/$(config).mk | cut -d" " -f3) && echo "$$(( $$vlen < 4096 ? $$vlen : 4096 ))") -RISCV_SIM_OPT ?= --isa=rv64gcv_zfh_zvfh_zvl$(vlen_spike)b -RISCV_SIM_MOD_OPT ?= --isa=rv64gcv_zfh_zvfh_zvl$(vlen_spike)b -d +RISCV_SIM_OPT ?= --isa=rv64gcv_zfh_zvfh_zvkb_zvl$(vlen_spike)b +RISCV_SIM_MOD_OPT ?= --isa=rv64gcv_zfh_zvfh_zvkb_zvl$(vlen_spike)b -d # Python PYTHON ?= python3 @@ -100,7 +100,7 @@ DEFINES += $(ENV_DEFINES) $(MAKE_DEFINES) RISCV_WARNINGS += -Wunused-variable -Wall -Wextra -Wno-unused-command-line-argument # -Werror # LLVM Flags -LLVM_FLAGS ?= -march=rv64gcv_zfh_zvfh -mabi=$(RISCV_ABI) -mno-relax -fuse-ld=lld +LLVM_FLAGS ?= -march=rv64gcv_zfh_zvfh_zvkb -mabi=$(RISCV_ABI) -mno-relax -fuse-ld=lld LLVM_V_FLAGS ?= -fno-vectorize -mllvm -scalable-vectorization=off -mllvm -riscv-v-vector-bits-min=0 -mno-implicit-float RISCV_FLAGS ?= $(LLVM_FLAGS) $(LLVM_V_FLAGS) -mcmodel=medany -I$(CURDIR)/common -O3 -ffast-math -fno-common -fno-builtin-printf $(DEFINES) $(RISCV_WARNINGS) ifeq ($(LINUX),1) diff --git a/apps/riscv-tests/isa/Makefile b/apps/riscv-tests/isa/Makefile index 96157046b..5767d7169 100644 --- a/apps/riscv-tests/isa/Makefile +++ b/apps/riscv-tests/isa/Makefile @@ -43,7 +43,7 @@ RISCV_LLVM ?= clang -fuse-ld=lld RISCV_CC_OPTS ?= -mcmodel=medany -fvisibility=hidden -mno-relax -nostdlib -nostartfiles RISCV_CC_OPTS_C ?= -O2 -mno-relax -nostdlib -nostartfiles -fno-vectorize -mllvm -scalable-vectorization=off -mllvm -riscv-v-vector-bits-min=0 -mno-implicit-float RISCV_CC_DEFS_C ?= $(ARA_DEFINES) -LLVM_V_VERSION ?= v_zfh_zvfh +LLVM_V_VERSION ?= v_zfh_zvfh_zvkb # Original objdump + spike variables RISCV_OBJDUMP ?= llvm-objdump --disassemble-all --disassemble-zeroes --section=.text --section=.text.startup --section=.text.init --section=.data @@ -64,7 +64,7 @@ vpath %.S $(src_dir) $(RISCV_SIM) --isa=rv32gcv $< 2> $@ %.cout: % - $(RISCV_SIM) --isa=rv64gcv_zfh_zvfh_zvl4096b $< 2> $@ + $(RISCV_SIM) --isa=rv64gcv_zfh_zvfh_zvkb_zvl4096b $< 2> $@ %.cout32: % $(RISCV_SIM) --isa=rv32gcv $< 2> $@ diff --git a/apps/riscv-tests/isa/rv64uv/Makefrag b/apps/riscv-tests/isa/rv64uv/Makefrag index f2c133600..0e491be99 100644 --- a/apps/riscv-tests/isa/rv64uv/Makefrag +++ b/apps/riscv-tests/isa/rv64uv/Makefrag @@ -180,6 +180,7 @@ rv64uv_sc_tests = vaadd \ vle_vse_hazards \ vfrec7 \ vfrsqrt7 \ + zvkb \ vrgather \ vcompress diff --git a/apps/riscv-tests/isa/rv64uv/zvkb.c b/apps/riscv-tests/isa/rv64uv/zvkb.c new file mode 100644 index 000000000..861aac848 --- /dev/null +++ b/apps/riscv-tests/isa/rv64uv/zvkb.c @@ -0,0 +1,653 @@ +// Copyright 2024 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 +// +// Zvkb instruction tests. + +#include "vector_macros.h" + +#define kElems 12 + +static const uint8_t kSrc8[kElems] = {0x00, 0x01, 0x5a, 0x80, 0xff, 0x3c, + 0xc3, 0x69, 0x96, 0x0f, 0xf0, 0xa5}; +static const uint8_t kAux8[kElems] = {0xff, 0x55, 0x0f, 0x01, 0x33, 0xaa, + 0x3c, 0x81, 0x10, 0xf0, 0x7e, 0x5a}; +static const uint16_t kSrc16[kElems] = {0x0001, 0x1234, 0xabcd, 0x00ff, + 0xff00, 0x5aa5, 0x1357, 0x2468, + 0x8001, 0x7ffe, 0xc33c, 0xdead}; +static const uint16_t kAux16[kElems] = {0xffff, 0x0f0f, 0x3333, 0x00f0, + 0xf00f, 0xa55a, 0x1111, 0x8888, + 0x0001, 0x7fff, 0x3cc3, 0xbeef}; +static const uint32_t kSrc32[kElems] = {0x00000001u, 0x12345678u, 0x89abcdefu, + 0x00ff00ffu, 0xff00ff00u, 0x5aa55aa5u, + 0x13579bdfu, 0x2468ace0u, 0x80000001u, + 0x7ffffffeu, 0xc33cc33cu, 0xdeadbeefu}; +static const uint32_t kAux32[kElems] = {0xffffffffu, 0x0f0f0f0fu, 0x33333333u, + 0x00f000f0u, 0xf00ff00fu, 0xa55aa55au, + 0x11111111u, 0x88888888u, 0x00000001u, + 0x7fffffffu, 0x3cc33cc3u, 0xbeefcafeu}; +static const uint64_t kSrc64[kElems] = { + 0x0000000000000001ull, 0x1234567890abcdefull, 0xfedcba9876543210ull, + 0x00ff00ff00ff00ffull, 0xff00ff00ff00ff00ull, 0x5aa55aa55aa55aa5ull, + 0x13579bdf2468ace0ull, 0x2468ace013579bdfull, 0x8000000000000001ull, + 0x7ffffffffffffffeull, 0xc33cc33cc33cc33cull, 0xdeadbeefcafebabeull}; +static const uint64_t kAux64[kElems] = { + 0xffffffffffffffffull, 0x0f0f0f0f0f0f0f0full, 0x3333333333333333ull, + 0x00f000f000f000f0ull, 0xf00ff00ff00ff00full, 0xa55aa55aa55aa55aull, + 0x1111111111111111ull, 0x8888888888888888ull, 0x0000000000000001ull, + 0x7fffffffffffffffull, 0x3cc33cc33cc33cc3ull, 0xbeefcafedeadfaceull}; + +static volatile uint8_t buf8_a[kElems] __attribute__((aligned(128))); +static volatile uint8_t buf8_b[kElems] __attribute__((aligned(128))); +static volatile uint8_t buf8_out[kElems] __attribute__((aligned(128))); +static uint8_t exp8[kElems]; + +static volatile uint16_t buf16_a[kElems] __attribute__((aligned(128))); +static volatile uint16_t buf16_b[kElems] __attribute__((aligned(128))); +static volatile uint16_t buf16_out[kElems] __attribute__((aligned(128))); +static uint16_t exp16[kElems]; + +static volatile uint32_t buf32_a[kElems] __attribute__((aligned(128))); +static volatile uint32_t buf32_b[kElems] __attribute__((aligned(128))); +static volatile uint32_t buf32_out[kElems] __attribute__((aligned(128))); +static uint32_t exp32[kElems]; + +static volatile uint64_t buf64_a[kElems] __attribute__((aligned(128))); +static volatile uint64_t buf64_b[kElems] __attribute__((aligned(128))); +static volatile uint64_t buf64_out[kElems] __attribute__((aligned(128))); +static uint64_t exp64[kElems]; + +static void start_case(const char *name) { + ++test_case; + printf("Test %d: %s\n", test_case, name); +} + +static void load_mask(void) { VLOAD_8(v0, 0x6D, 0x0B); } + +static inline void vset8(void) { + long avl = kElems; + asm volatile("vsetvli zero, %0, e8, m1, ta, ma" ::"r"(avl) : "memory"); +} + +static inline void vset16(void) { + long avl = kElems; + asm volatile("vsetvli zero, %0, e16, m1, ta, ma" ::"r"(avl) : "memory"); +} + +static inline void vset32(void) { + long avl = kElems; + asm volatile("vsetvli zero, %0, e32, m1, ta, ma" ::"r"(avl) : "memory"); +} + +static inline void vset64(void) { + long avl = kElems; + asm volatile("vsetvli zero, %0, e64, m1, ta, ma" ::"r"(avl) : "memory"); +} + +static uint64_t bit_mask(int bits) { + return bits == 64 ? ~0ull : ((1ull << bits) - 1); +} + +static uint8_t bitrev8(uint8_t x) { + x = (uint8_t)(((x & 0xaa) >> 1) | ((x & 0x55) << 1)); + x = (uint8_t)(((x & 0xcc) >> 2) | ((x & 0x33) << 2)); + x = (uint8_t)(((x & 0xf0) >> 4) | ((x & 0x0f) << 4)); + return x; +} + +static uint64_t vbrev8_ref(uint64_t x, int bits) { + uint64_t out = 0; + for (int i = 0; i < bits / 8; ++i) + out |= (uint64_t)bitrev8((uint8_t)(x >> (i * 8))) << (i * 8); + return out; +} + +static uint64_t vrev8_ref(uint64_t x, int bits) { + uint64_t out = 0; + int bytes = bits / 8; + for (int i = 0; i < bytes; ++i) + out |= ((x >> (i * 8)) & 0xffull) << ((bytes - 1 - i) * 8); + return out & bit_mask(bits); +} + +static uint64_t rol_ref(uint64_t x, uint64_t sh, int bits) { + uint64_t mask = bit_mask(bits); + unsigned rot = (unsigned)(sh & (bits - 1)); + x &= mask; + if (rot == 0) + return x; + return ((x << rot) | (x >> (bits - rot))) & mask; +} + +static uint64_t ror_ref(uint64_t x, uint64_t sh, int bits) { + uint64_t mask = bit_mask(bits); + unsigned rot = (unsigned)(sh & (bits - 1)); + x &= mask; + if (rot == 0) + return x; + return ((x >> rot) | (x << (bits - rot))) & mask; +} + +static int mask_active(int idx) { + static const uint8_t mask_bits[2] = {0x6D, 0x0B}; + return (mask_bits[idx / 8] >> (idx % 8)) & 1; +} + +static void copy_u8(volatile uint8_t *dst, const uint8_t *src) { + for (int i = 0; i < kElems; ++i) + dst[i] = src[i]; +} + +static void copy_u16(volatile uint16_t *dst, const uint16_t *src) { + for (int i = 0; i < kElems; ++i) + dst[i] = src[i]; +} + +static void copy_u32(volatile uint32_t *dst, const uint32_t *src) { + for (int i = 0; i < kElems; ++i) + dst[i] = src[i]; +} + +static void copy_u64(volatile uint64_t *dst, const uint64_t *src) { + for (int i = 0; i < kElems; ++i) + dst[i] = src[i]; +} + +static int check_u8(const uint8_t *expected) { + for (int i = 0; i < kElems; ++i) { + if (buf8_out[i] != expected[i]) { + printf(" FAILED at element %d: got 0x%02x expected 0x%02x\n", i, + buf8_out[i], expected[i]); + ++num_failed; + return 0; + } + } + printf(" PASSED.\n"); + return 1; +} + +static int check_u16(const uint16_t *expected) { + for (int i = 0; i < kElems; ++i) { + if (buf16_out[i] != expected[i]) { + printf(" FAILED at element %d: got 0x%04x expected 0x%04x\n", i, + buf16_out[i], expected[i]); + ++num_failed; + return 0; + } + } + printf(" PASSED.\n"); + return 1; +} + +static int check_u32(const uint32_t *expected) { + for (int i = 0; i < kElems; ++i) { + if (buf32_out[i] != expected[i]) { + printf(" FAILED at element %d: got 0x%08x expected 0x%08x\n", i, + buf32_out[i], expected[i]); + ++num_failed; + return 0; + } + } + printf(" PASSED.\n"); + return 1; +} + +static int check_u64(const uint64_t *expected) { + for (int i = 0; i < kElems; ++i) { + if (buf64_out[i] != expected[i]) { + printf(" FAILED at element %d: got 0x%016llx expected 0x%016llx\n", i, + (unsigned long long)buf64_out[i], (unsigned long long)expected[i]); + ++num_failed; + return 0; + } + } + printf(" PASSED.\n"); + return 1; +} + +static void test_u8(void) { + const uint64_t scalar = 13; + const uint64_t imm = 45; + + start_case("vandn.vv e8"); + copy_u8(buf8_a, kSrc8); + copy_u8(buf8_b, kAux8); + for (int i = 0; i < kElems; ++i) + exp8[i] = (uint8_t)(kSrc8[i] & (uint8_t)~kAux8[i]); + vset8(); + asm volatile("vle8.v v2, (%0)" ::"r"(buf8_a) : "memory"); + asm volatile("vle8.v v3, (%0)" ::"r"(buf8_b) : "memory"); + asm volatile("vandn.vv v1, v2, v3"); + asm volatile("vse8.v v1, (%0)" ::"r"(buf8_out) : "memory"); + check_u8(exp8); + + start_case("vandn.vx masked e8"); + copy_u8(buf8_a, kSrc8); + for (int i = 0; i < kElems; ++i) + exp8[i] = mask_active(i) ? (uint8_t)(kSrc8[i] & (uint8_t)~scalar) : 0xeeu; + vset8(); + load_mask(); + asm volatile("vle8.v v1, (%0)" ::"r"(exp8) : "memory"); + asm volatile("vle8.v v2, (%0)" ::"r"(buf8_a) : "memory"); + asm volatile("vandn.vx v1, v2, %[S], v0.t" ::[S] "r"(scalar)); + asm volatile("vse8.v v1, (%0)" ::"r"(buf8_out) : "memory"); + check_u8(exp8); + + start_case("vbrev8.v masked e8"); + copy_u8(buf8_a, kSrc8); + for (int i = 0; i < kElems; ++i) + exp8[i] = mask_active(i) ? bitrev8(kSrc8[i]) : 0xeeu; + vset8(); + load_mask(); + asm volatile("vle8.v v1, (%0)" ::"r"(exp8) : "memory"); + asm volatile("vle8.v v2, (%0)" ::"r"(buf8_a) : "memory"); + asm volatile("vbrev8.v v1, v2, v0.t"); + asm volatile("vse8.v v1, (%0)" ::"r"(buf8_out) : "memory"); + check_u8(exp8); + + start_case("vrev8.v e8"); + copy_u8(buf8_a, kSrc8); + for (int i = 0; i < kElems; ++i) + exp8[i] = kSrc8[i]; + vset8(); + asm volatile("vle8.v v2, (%0)" ::"r"(buf8_a) : "memory"); + asm volatile("vrev8.v v1, v2"); + asm volatile("vse8.v v1, (%0)" ::"r"(buf8_out) : "memory"); + check_u8(exp8); + + start_case("vrol.vv e8"); + copy_u8(buf8_a, kSrc8); + copy_u8(buf8_b, kAux8); + for (int i = 0; i < kElems; ++i) + exp8[i] = (uint8_t)rol_ref(kSrc8[i], kAux8[i], 8); + vset8(); + asm volatile("vle8.v v2, (%0)" ::"r"(buf8_a) : "memory"); + asm volatile("vle8.v v3, (%0)" ::"r"(buf8_b) : "memory"); + asm volatile("vrol.vv v1, v2, v3"); + asm volatile("vse8.v v1, (%0)" ::"r"(buf8_out) : "memory"); + check_u8(exp8); + + start_case("vrol.vx masked e8"); + copy_u8(buf8_a, kSrc8); + for (int i = 0; i < kElems; ++i) + exp8[i] = mask_active(i) ? (uint8_t)rol_ref(kSrc8[i], scalar, 8) : 0xeeu; + vset8(); + load_mask(); + asm volatile("vle8.v v1, (%0)" ::"r"(exp8) : "memory"); + asm volatile("vle8.v v2, (%0)" ::"r"(buf8_a) : "memory"); + asm volatile("vrol.vx v1, v2, %[S], v0.t" ::[S] "r"(scalar)); + asm volatile("vse8.v v1, (%0)" ::"r"(buf8_out) : "memory"); + check_u8(exp8); + + start_case("vror.vv e8"); + copy_u8(buf8_a, kSrc8); + copy_u8(buf8_b, kAux8); + for (int i = 0; i < kElems; ++i) + exp8[i] = (uint8_t)ror_ref(kSrc8[i], kAux8[i], 8); + vset8(); + asm volatile("vle8.v v2, (%0)" ::"r"(buf8_a) : "memory"); + asm volatile("vle8.v v3, (%0)" ::"r"(buf8_b) : "memory"); + asm volatile("vror.vv v1, v2, v3"); + asm volatile("vse8.v v1, (%0)" ::"r"(buf8_out) : "memory"); + check_u8(exp8); + + start_case("vror.vx e8"); + copy_u8(buf8_a, kSrc8); + for (int i = 0; i < kElems; ++i) + exp8[i] = (uint8_t)ror_ref(kSrc8[i], scalar, 8); + vset8(); + asm volatile("vle8.v v2, (%0)" ::"r"(buf8_a) : "memory"); + asm volatile("vror.vx v1, v2, %[S]" ::[S] "r"(scalar)); + asm volatile("vse8.v v1, (%0)" ::"r"(buf8_out) : "memory"); + check_u8(exp8); + + start_case("vror.vi e8"); + copy_u8(buf8_a, kSrc8); + for (int i = 0; i < kElems; ++i) + exp8[i] = (uint8_t)ror_ref(kSrc8[i], imm, 8); + vset8(); + asm volatile("vle8.v v2, (%0)" ::"r"(buf8_a) : "memory"); + asm volatile("vror.vi v1, v2, 45"); + asm volatile("vse8.v v1, (%0)" ::"r"(buf8_out) : "memory"); + check_u8(exp8); +} + +static void test_u16(void) { + const uint64_t scalar = 13; + const uint64_t imm = 45; + + start_case("vandn.vv e16"); + copy_u16(buf16_a, kSrc16); + copy_u16(buf16_b, kAux16); + for (int i = 0; i < kElems; ++i) + exp16[i] = (uint16_t)(kSrc16[i] & (uint16_t)~kAux16[i]); + vset16(); + asm volatile("vle16.v v2, (%0)" ::"r"(buf16_a) : "memory"); + asm volatile("vle16.v v3, (%0)" ::"r"(buf16_b) : "memory"); + asm volatile("vandn.vv v1, v2, v3"); + asm volatile("vse16.v v1, (%0)" ::"r"(buf16_out) : "memory"); + check_u16(exp16); + + start_case("vandn.vx masked e16"); + copy_u16(buf16_a, kSrc16); + for (int i = 0; i < kElems; ++i) + exp16[i] = + mask_active(i) ? (uint16_t)(kSrc16[i] & (uint16_t)~scalar) : 0xbeefu; + vset16(); + load_mask(); + asm volatile("vle16.v v1, (%0)" ::"r"(exp16) : "memory"); + asm volatile("vle16.v v2, (%0)" ::"r"(buf16_a) : "memory"); + asm volatile("vandn.vx v1, v2, %[S], v0.t" ::[S] "r"(scalar)); + asm volatile("vse16.v v1, (%0)" ::"r"(buf16_out) : "memory"); + check_u16(exp16); + + start_case("vbrev8.v masked e16"); + copy_u16(buf16_a, kSrc16); + for (int i = 0; i < kElems; ++i) + exp16[i] = mask_active(i) ? (uint16_t)vbrev8_ref(kSrc16[i], 16) : 0xbeefu; + vset16(); + load_mask(); + asm volatile("vle16.v v1, (%0)" ::"r"(exp16) : "memory"); + asm volatile("vle16.v v2, (%0)" ::"r"(buf16_a) : "memory"); + asm volatile("vbrev8.v v1, v2, v0.t"); + asm volatile("vse16.v v1, (%0)" ::"r"(buf16_out) : "memory"); + check_u16(exp16); + + start_case("vrev8.v e16"); + copy_u16(buf16_a, kSrc16); + for (int i = 0; i < kElems; ++i) + exp16[i] = (uint16_t)vrev8_ref(kSrc16[i], 16); + vset16(); + asm volatile("vle16.v v2, (%0)" ::"r"(buf16_a) : "memory"); + asm volatile("vrev8.v v1, v2"); + asm volatile("vse16.v v1, (%0)" ::"r"(buf16_out) : "memory"); + check_u16(exp16); + + start_case("vrol.vv e16"); + copy_u16(buf16_a, kSrc16); + copy_u16(buf16_b, kAux16); + for (int i = 0; i < kElems; ++i) + exp16[i] = (uint16_t)rol_ref(kSrc16[i], kAux16[i], 16); + vset16(); + asm volatile("vle16.v v2, (%0)" ::"r"(buf16_a) : "memory"); + asm volatile("vle16.v v3, (%0)" ::"r"(buf16_b) : "memory"); + asm volatile("vrol.vv v1, v2, v3"); + asm volatile("vse16.v v1, (%0)" ::"r"(buf16_out) : "memory"); + check_u16(exp16); + + start_case("vrol.vx masked e16"); + copy_u16(buf16_a, kSrc16); + for (int i = 0; i < kElems; ++i) + exp16[i] = + mask_active(i) ? (uint16_t)rol_ref(kSrc16[i], scalar, 16) : 0xbeefu; + vset16(); + load_mask(); + asm volatile("vle16.v v1, (%0)" ::"r"(exp16) : "memory"); + asm volatile("vle16.v v2, (%0)" ::"r"(buf16_a) : "memory"); + asm volatile("vrol.vx v1, v2, %[S], v0.t" ::[S] "r"(scalar)); + asm volatile("vse16.v v1, (%0)" ::"r"(buf16_out) : "memory"); + check_u16(exp16); + + start_case("vror.vv e16"); + copy_u16(buf16_a, kSrc16); + copy_u16(buf16_b, kAux16); + for (int i = 0; i < kElems; ++i) + exp16[i] = (uint16_t)ror_ref(kSrc16[i], kAux16[i], 16); + vset16(); + asm volatile("vle16.v v2, (%0)" ::"r"(buf16_a) : "memory"); + asm volatile("vle16.v v3, (%0)" ::"r"(buf16_b) : "memory"); + asm volatile("vror.vv v1, v2, v3"); + asm volatile("vse16.v v1, (%0)" ::"r"(buf16_out) : "memory"); + check_u16(exp16); + + start_case("vror.vx e16"); + copy_u16(buf16_a, kSrc16); + for (int i = 0; i < kElems; ++i) + exp16[i] = (uint16_t)ror_ref(kSrc16[i], scalar, 16); + vset16(); + asm volatile("vle16.v v2, (%0)" ::"r"(buf16_a) : "memory"); + asm volatile("vror.vx v1, v2, %[S]" ::[S] "r"(scalar)); + asm volatile("vse16.v v1, (%0)" ::"r"(buf16_out) : "memory"); + check_u16(exp16); + + start_case("vror.vi e16"); + copy_u16(buf16_a, kSrc16); + for (int i = 0; i < kElems; ++i) + exp16[i] = (uint16_t)ror_ref(kSrc16[i], imm, 16); + vset16(); + asm volatile("vle16.v v2, (%0)" ::"r"(buf16_a) : "memory"); + asm volatile("vror.vi v1, v2, 45"); + asm volatile("vse16.v v1, (%0)" ::"r"(buf16_out) : "memory"); + check_u16(exp16); +} + +static void test_u32(void) { + const uint64_t scalar = 13; + const uint64_t imm = 45; + + start_case("vandn.vv e32"); + copy_u32(buf32_a, kSrc32); + copy_u32(buf32_b, kAux32); + for (int i = 0; i < kElems; ++i) + exp32[i] = kSrc32[i] & ~kAux32[i]; + vset32(); + asm volatile("vle32.v v2, (%0)" ::"r"(buf32_a) : "memory"); + asm volatile("vle32.v v3, (%0)" ::"r"(buf32_b) : "memory"); + asm volatile("vandn.vv v1, v2, v3"); + asm volatile("vse32.v v1, (%0)" ::"r"(buf32_out) : "memory"); + check_u32(exp32); + + start_case("vandn.vx masked e32"); + copy_u32(buf32_a, kSrc32); + for (int i = 0; i < kElems; ++i) + exp32[i] = mask_active(i) ? (kSrc32[i] & ~(uint32_t)scalar) : 0xdeadbeefu; + vset32(); + load_mask(); + asm volatile("vle32.v v1, (%0)" ::"r"(exp32) : "memory"); + asm volatile("vle32.v v2, (%0)" ::"r"(buf32_a) : "memory"); + asm volatile("vandn.vx v1, v2, %[S], v0.t" ::[S] "r"(scalar)); + asm volatile("vse32.v v1, (%0)" ::"r"(buf32_out) : "memory"); + check_u32(exp32); + + start_case("vbrev8.v masked e32"); + copy_u32(buf32_a, kSrc32); + for (int i = 0; i < kElems; ++i) + exp32[i] = + mask_active(i) ? (uint32_t)vbrev8_ref(kSrc32[i], 32) : 0xdeadbeefu; + vset32(); + load_mask(); + asm volatile("vle32.v v1, (%0)" ::"r"(exp32) : "memory"); + asm volatile("vle32.v v2, (%0)" ::"r"(buf32_a) : "memory"); + asm volatile("vbrev8.v v1, v2, v0.t"); + asm volatile("vse32.v v1, (%0)" ::"r"(buf32_out) : "memory"); + check_u32(exp32); + + start_case("vrev8.v e32"); + copy_u32(buf32_a, kSrc32); + for (int i = 0; i < kElems; ++i) + exp32[i] = (uint32_t)vrev8_ref(kSrc32[i], 32); + vset32(); + asm volatile("vle32.v v2, (%0)" ::"r"(buf32_a) : "memory"); + asm volatile("vrev8.v v1, v2"); + asm volatile("vse32.v v1, (%0)" ::"r"(buf32_out) : "memory"); + check_u32(exp32); + + start_case("vrol.vv e32"); + copy_u32(buf32_a, kSrc32); + copy_u32(buf32_b, kAux32); + for (int i = 0; i < kElems; ++i) + exp32[i] = (uint32_t)rol_ref(kSrc32[i], kAux32[i], 32); + vset32(); + asm volatile("vle32.v v2, (%0)" ::"r"(buf32_a) : "memory"); + asm volatile("vle32.v v3, (%0)" ::"r"(buf32_b) : "memory"); + asm volatile("vrol.vv v1, v2, v3"); + asm volatile("vse32.v v1, (%0)" ::"r"(buf32_out) : "memory"); + check_u32(exp32); + + start_case("vrol.vx masked e32"); + copy_u32(buf32_a, kSrc32); + for (int i = 0; i < kElems; ++i) + exp32[i] = + mask_active(i) ? (uint32_t)rol_ref(kSrc32[i], scalar, 32) : 0xdeadbeefu; + vset32(); + load_mask(); + asm volatile("vle32.v v1, (%0)" ::"r"(exp32) : "memory"); + asm volatile("vle32.v v2, (%0)" ::"r"(buf32_a) : "memory"); + asm volatile("vrol.vx v1, v2, %[S], v0.t" ::[S] "r"(scalar)); + asm volatile("vse32.v v1, (%0)" ::"r"(buf32_out) : "memory"); + check_u32(exp32); + + start_case("vror.vv e32"); + copy_u32(buf32_a, kSrc32); + copy_u32(buf32_b, kAux32); + for (int i = 0; i < kElems; ++i) + exp32[i] = (uint32_t)ror_ref(kSrc32[i], kAux32[i], 32); + vset32(); + asm volatile("vle32.v v2, (%0)" ::"r"(buf32_a) : "memory"); + asm volatile("vle32.v v3, (%0)" ::"r"(buf32_b) : "memory"); + asm volatile("vror.vv v1, v2, v3"); + asm volatile("vse32.v v1, (%0)" ::"r"(buf32_out) : "memory"); + check_u32(exp32); + + start_case("vror.vx e32"); + copy_u32(buf32_a, kSrc32); + for (int i = 0; i < kElems; ++i) + exp32[i] = (uint32_t)ror_ref(kSrc32[i], scalar, 32); + vset32(); + asm volatile("vle32.v v2, (%0)" ::"r"(buf32_a) : "memory"); + asm volatile("vror.vx v1, v2, %[S]" ::[S] "r"(scalar)); + asm volatile("vse32.v v1, (%0)" ::"r"(buf32_out) : "memory"); + check_u32(exp32); + + start_case("vror.vi e32"); + copy_u32(buf32_a, kSrc32); + for (int i = 0; i < kElems; ++i) + exp32[i] = (uint32_t)ror_ref(kSrc32[i], imm, 32); + vset32(); + asm volatile("vle32.v v2, (%0)" ::"r"(buf32_a) : "memory"); + asm volatile("vror.vi v1, v2, 45"); + asm volatile("vse32.v v1, (%0)" ::"r"(buf32_out) : "memory"); + check_u32(exp32); +} + +static void test_u64(void) { + const uint64_t scalar = 13; + const uint64_t imm = 45; + + start_case("vandn.vv e64"); + copy_u64(buf64_a, kSrc64); + copy_u64(buf64_b, kAux64); + for (int i = 0; i < kElems; ++i) + exp64[i] = kSrc64[i] & ~kAux64[i]; + vset64(); + asm volatile("vle64.v v2, (%0)" ::"r"(buf64_a) : "memory"); + asm volatile("vle64.v v3, (%0)" ::"r"(buf64_b) : "memory"); + asm volatile("vandn.vv v1, v2, v3"); + asm volatile("vse64.v v1, (%0)" ::"r"(buf64_out) : "memory"); + check_u64(exp64); + + start_case("vandn.vx masked e64"); + copy_u64(buf64_a, kSrc64); + for (int i = 0; i < kElems; ++i) + exp64[i] = mask_active(i) ? (kSrc64[i] & ~scalar) : 0xdeadbeefdeadbeefull; + vset64(); + load_mask(); + asm volatile("vle64.v v1, (%0)" ::"r"(exp64) : "memory"); + asm volatile("vle64.v v2, (%0)" ::"r"(buf64_a) : "memory"); + asm volatile("vandn.vx v1, v2, %[S], v0.t" ::[S] "r"(scalar)); + asm volatile("vse64.v v1, (%0)" ::"r"(buf64_out) : "memory"); + check_u64(exp64); + + start_case("vbrev8.v masked e64"); + copy_u64(buf64_a, kSrc64); + for (int i = 0; i < kElems; ++i) + exp64[i] = + mask_active(i) ? vbrev8_ref(kSrc64[i], 64) : 0xdeadbeefdeadbeefull; + vset64(); + load_mask(); + asm volatile("vle64.v v1, (%0)" ::"r"(exp64) : "memory"); + asm volatile("vle64.v v2, (%0)" ::"r"(buf64_a) : "memory"); + asm volatile("vbrev8.v v1, v2, v0.t"); + asm volatile("vse64.v v1, (%0)" ::"r"(buf64_out) : "memory"); + check_u64(exp64); + + start_case("vrev8.v e64"); + copy_u64(buf64_a, kSrc64); + for (int i = 0; i < kElems; ++i) + exp64[i] = vrev8_ref(kSrc64[i], 64); + vset64(); + asm volatile("vle64.v v2, (%0)" ::"r"(buf64_a) : "memory"); + asm volatile("vrev8.v v1, v2"); + asm volatile("vse64.v v1, (%0)" ::"r"(buf64_out) : "memory"); + check_u64(exp64); + + start_case("vrol.vv e64"); + copy_u64(buf64_a, kSrc64); + copy_u64(buf64_b, kAux64); + for (int i = 0; i < kElems; ++i) + exp64[i] = rol_ref(kSrc64[i], kAux64[i], 64); + vset64(); + asm volatile("vle64.v v2, (%0)" ::"r"(buf64_a) : "memory"); + asm volatile("vle64.v v3, (%0)" ::"r"(buf64_b) : "memory"); + asm volatile("vrol.vv v1, v2, v3"); + asm volatile("vse64.v v1, (%0)" ::"r"(buf64_out) : "memory"); + check_u64(exp64); + + start_case("vrol.vx masked e64"); + copy_u64(buf64_a, kSrc64); + for (int i = 0; i < kElems; ++i) + exp64[i] = + mask_active(i) ? rol_ref(kSrc64[i], scalar, 64) : 0xdeadbeefdeadbeefull; + vset64(); + load_mask(); + asm volatile("vle64.v v1, (%0)" ::"r"(exp64) : "memory"); + asm volatile("vle64.v v2, (%0)" ::"r"(buf64_a) : "memory"); + asm volatile("vrol.vx v1, v2, %[S], v0.t" ::[S] "r"(scalar)); + asm volatile("vse64.v v1, (%0)" ::"r"(buf64_out) : "memory"); + check_u64(exp64); + + start_case("vror.vv e64"); + copy_u64(buf64_a, kSrc64); + copy_u64(buf64_b, kAux64); + for (int i = 0; i < kElems; ++i) + exp64[i] = ror_ref(kSrc64[i], kAux64[i], 64); + vset64(); + asm volatile("vle64.v v2, (%0)" ::"r"(buf64_a) : "memory"); + asm volatile("vle64.v v3, (%0)" ::"r"(buf64_b) : "memory"); + asm volatile("vror.vv v1, v2, v3"); + asm volatile("vse64.v v1, (%0)" ::"r"(buf64_out) : "memory"); + check_u64(exp64); + + start_case("vror.vx e64"); + copy_u64(buf64_a, kSrc64); + for (int i = 0; i < kElems; ++i) + exp64[i] = ror_ref(kSrc64[i], scalar, 64); + vset64(); + asm volatile("vle64.v v2, (%0)" ::"r"(buf64_a) : "memory"); + asm volatile("vror.vx v1, v2, %[S]" ::[S] "r"(scalar)); + asm volatile("vse64.v v1, (%0)" ::"r"(buf64_out) : "memory"); + check_u64(exp64); + + start_case("vror.vi e64"); + copy_u64(buf64_a, kSrc64); + for (int i = 0; i < kElems; ++i) + exp64[i] = ror_ref(kSrc64[i], imm, 64); + vset64(); + asm volatile("vle64.v v2, (%0)" ::"r"(buf64_a) : "memory"); + asm volatile("vror.vi v1, v2, 45"); + asm volatile("vse64.v v1, (%0)" ::"r"(buf64_out) : "memory"); + check_u64(exp64); +} + +int main(void) { + INIT_CHECK(); + enable_vec(); + enable_fp(); + + test_u8(); + test_u16(); + test_u32(); + test_u64(); + + EXIT_CHECK(); +} diff --git a/hardware/include/ara_pkg.sv b/hardware/include/ara_pkg.sv index 551e8e6d8..e66b820c0 100644 --- a/hardware/include/ara_pkg.sv +++ b/hardware/include/ara_pkg.sv @@ -82,9 +82,14 @@ package ara_pkg; // Support for the vector crypto extensions. // 16 bits correspond to {Zvbb, Zvbc, Zvkb, Zvkg, Zvkned, Zvknha, Zvknhb, Zvksed, Zvksh, Zvkn, Zvknc, Zvkng, Zvks, Zvksc, Zvksg, Zvkt} typedef enum bit [15:0] { - CryptoSupportNone = 16'h0000 + CryptoSupportNone = 16'h0000, + CryptoSupportBitmanip = 16'h2000 } crypto_support_e; + function automatic bit Zvkb(crypto_support_e e); + return e[13]; + endfunction + // Multiplier latencies. localparam int unsigned LatMultiplierEW64 = 1; localparam int unsigned LatMultiplierEW32 = 1; @@ -132,6 +137,8 @@ package ara_pkg; typedef enum logic [7:0] { // Arithmetic and logic instructions VADD, VSUB, VADC, VSBC, VRSUB, VMINU, VMIN, VMAXU, VMAX, VAND, VOR, VXOR, + // Zvkb + VANDN, VBREV8, VREV8, VROL, VROR, // Fixed point VSADDU, VSADD, VSSUBU, VSSUB, VAADDU, VAADD, VASUBU, VASUB, VSSRL, VSSRA, VNCLIP, VNCLIPU, // Shifts, diff --git a/hardware/src/ara_dispatcher.sv b/hardware/src/ara_dispatcher.sv index 027a94a0c..6846f12a1 100644 --- a/hardware/src/ara_dispatcher.sv +++ b/hardware/src/ara_dispatcher.sv @@ -712,6 +712,11 @@ module ara_dispatcher import ara_pkg::*; import rvv_pkg::*; #( // Decode based on the func6 field unique case (insn.varith_type.func6) 6'b000000: ara_req.op = ara_pkg::VADD; + 6'b000001: if (Zvkb(CryptoSupport)) begin + ara_req.op = ara_pkg::VANDN; + end else begin + illegal_insn = 1'b1; + end 6'b000010: ara_req.op = ara_pkg::VSUB; 6'b000100: ara_req.op = ara_pkg::VMINU; 6'b000101: ara_req.op = ara_pkg::VMIN; @@ -843,6 +848,16 @@ module ara_dispatcher import ara_pkg::*; import rvv_pkg::*; #( ara_req.eew_vd_op = eew_q[ara_req.vd]; ara_req.vtype.vsew = eew_q[ara_req.vd]; end + 6'b010100: if (Zvkb(CryptoSupport)) begin + ara_req.op = ara_pkg::VROR; + end else begin + illegal_insn = 1'b1; + end + 6'b010101: if (Zvkb(CryptoSupport)) begin + ara_req.op = ara_pkg::VROL; + end else begin + illegal_insn = 1'b1; + end 6'b010111: begin ara_req.op = ara_pkg::VMERGE; ara_req.use_vs2 = !insn.varith_type.vm; // vmv.v.v does not use vs2 @@ -965,6 +980,11 @@ module ara_dispatcher import ara_pkg::*; import rvv_pkg::*; #( // Decode based on the func6 field unique case (insn.varith_type.func6) 6'b000000: ara_req.op = ara_pkg::VADD; + 6'b000001: if (Zvkb(CryptoSupport)) begin + ara_req.op = ara_pkg::VANDN; + end else begin + illegal_insn = 1'b1; + end 6'b000010: ara_req.op = ara_pkg::VSUB; 6'b000011: ara_req.op = ara_pkg::VRSUB; 6'b000100: ara_req.op = ara_pkg::VMINU; @@ -1119,6 +1139,16 @@ module ara_dispatcher import ara_pkg::*; import rvv_pkg::*; #( ara_req.eew_vd_op = eew_q[ara_req.vd]; ara_req.vtype.vsew = eew_q[ara_req.vd]; end + 6'b010100: if (Zvkb(CryptoSupport)) begin + ara_req.op = ara_pkg::VROR; + end else begin + illegal_insn = 1'b1; + end + 6'b010101: if (Zvkb(CryptoSupport)) begin + ara_req.op = ara_pkg::VROL; + end else begin + illegal_insn = 1'b1; + end 6'b010111: begin ara_req.op = ara_pkg::VMERGE; ara_req.use_vs2 = !insn.varith_type.vm; // vmv.v.x does not use vs2 @@ -1319,6 +1349,14 @@ module ara_dispatcher import ara_pkg::*; import rvv_pkg::*; #( ara_req.eew_vd_op = eew_q[ara_req.vd]; ara_req.vtype.vsew = eew_q[ara_req.vd]; end + 6'b010100, 6'b010101: if (Zvkb(CryptoSupport)) begin // Zvkb vror.vi (6-bit unsigned immediate) + automatic logic [5:0] func6; + func6 = insn.varith_type.func6; + ara_req.op = ara_pkg::VROR; + ara_req.scalar_op = {{ELEN-6{1'b0}}, func6[0], insn.varith_type.rs1}; + end else begin + illegal_insn = 1'b1; + end 6'b010111: begin ara_req.op = ara_pkg::VMERGE; ara_req.use_vs2 = !insn.varith_type.vm; // vmv.v.i does not use vs2 @@ -1728,6 +1766,21 @@ module ara_dispatcher import ara_pkg::*; import rvv_pkg::*; #( if (int'(csr_vtype_q.vsew) < int'(EW16) || int'(csr_vtype_q.vlmul) inside {LMUL_1_8}) illegal_insn = 1'b1; end + // Zvkb: VBREV8, VREV8 + 5'b01000: if (Zvkb(CryptoSupport)) begin + ara_req.op = ara_pkg::VBREV8; + ara_req.use_scalar_op = 1'b0; + ara_req.emul = csr_vtype_q.vlmul; + end else begin + illegal_insn = 1'b1; + end + 5'b01001: if (Zvkb(CryptoSupport)) begin + ara_req.op = ara_pkg::VREV8; + ara_req.use_scalar_op = 1'b0; + ara_req.emul = csr_vtype_q.vlmul; + end else begin + illegal_insn = 1'b1; + end default: illegal_insn = 1'b1; endcase end diff --git a/hardware/src/ara_soc.sv b/hardware/src/ara_soc.sv index 3fdca205e..0ee2f5ba5 100644 --- a/hardware/src/ara_soc.sv +++ b/hardware/src/ara_soc.sv @@ -20,7 +20,7 @@ module ara_soc import axi_pkg::*; import ara_pkg::*; #( // Support for segment memory operations parameter seg_support_e SegSupport = SegSupportEnable, // Support for crypto extension - parameter crypto_support_e CryptoSupport = CryptoSupportNone, + parameter crypto_support_e CryptoSupport = CryptoSupportBitmanip, // AXI Interface parameter int unsigned AxiDataWidth = 32*NrLanes, parameter int unsigned AxiAddrWidth = 64, diff --git a/hardware/src/lane/simd_alu.sv b/hardware/src/lane/simd_alu.sv index 63c0023cc..5d59f7c88 100644 --- a/hardware/src/lane/simd_alu.sv +++ b/hardware/src/lane/simd_alu.sv @@ -123,6 +123,78 @@ module simd_alu import ara_pkg::*; import rvv_pkg::*; #( VOR, VREDOR : res = operand_a_i | operand_b_i; VXOR, VREDXOR: res = operand_a_i ^ operand_b_i; + // Zvkb: AND-NOT + VANDN: if (Zvkb(CryptoSupport)) begin + res = ~operand_a_i & operand_b_i; + end + + // Zvkb: Rotate left + VROL: if (Zvkb(CryptoSupport)) begin + unique case (vew_i) + EW8 : for (int b = 0; b < 8; b++) begin + automatic logic [2:0] sh = opa.w8[b][2:0]; + res.w8[b] = (opb.w8[b] << sh) | (opb.w8[b] >> (3'd0 - sh)); + end + EW16: for (int b = 0; b < 4; b++) begin + automatic logic [3:0] sh = opa.w16[b][3:0]; + res.w16[b] = (opb.w16[b] << sh) | (opb.w16[b] >> (4'd0 - sh)); + end + EW32: for (int b = 0; b < 2; b++) begin + automatic logic [4:0] sh = opa.w32[b][4:0]; + res.w32[b] = (opb.w32[b] << sh) | (opb.w32[b] >> (5'd0 - sh)); + end + EW64: for (int b = 0; b < 1; b++) begin + automatic logic [5:0] sh = opa.w64[b][5:0]; + res.w64[b] = (opb.w64[b] << sh) | (opb.w64[b] >> (6'd0 - sh)); + end + endcase + end + + // Zvkb: Rotate right + VROR: if (Zvkb(CryptoSupport)) begin + unique case (vew_i) + EW8 : for (int b = 0; b < 8; b++) begin + automatic logic [2:0] sh = opa.w8[b][2:0]; + res.w8[b] = (opb.w8[b] >> sh) | (opb.w8[b] << (3'd0 - sh)); + end + EW16: for (int b = 0; b < 4; b++) begin + automatic logic [3:0] sh = opa.w16[b][3:0]; + res.w16[b] = (opb.w16[b] >> sh) | (opb.w16[b] << (4'd0 - sh)); + end + EW32: for (int b = 0; b < 2; b++) begin + automatic logic [4:0] sh = opa.w32[b][4:0]; + res.w32[b] = (opb.w32[b] >> sh) | (opb.w32[b] << (5'd0 - sh)); + end + EW64: for (int b = 0; b < 1; b++) begin + automatic logic [5:0] sh = opa.w64[b][5:0]; + res.w64[b] = (opb.w64[b] >> sh) | (opb.w64[b] << (6'd0 - sh)); + end + endcase + end + + // Zvkb: Bit-reverse within bytes + VBREV8: if (Zvkb(CryptoSupport)) begin + for (int b = 0; b < 8; b++) + for (int i = 0; i < 8; i++) + res.w8[b][i] = opb.w8[b][7-i]; + end + + // Zvkb: Byte-reverse within elements (endian swap) + VREV8: if (Zvkb(CryptoSupport)) begin + unique case (vew_i) + EW8 : res = opb; // no-op for single-byte elements + EW16: for (int b = 0; b < 4; b++) begin + res.w8[2*b] = opb.w8[2*b+1]; + res.w8[2*b+1] = opb.w8[2*b]; + end + EW32: for (int b = 0; b < 2; b++) + for (int i = 0; i < 4; i++) + res.w8[4*b+i] = opb.w8[4*b+3-i]; + EW64: for (int i = 0; i < 8; i++) + res.w8[i] = opb.w8[7-i]; + endcase + end + // Mask logical operations VMAND : res = operand_a_i & operand_b_i; VMANDNOT: res = ~operand_a_i & operand_b_i; From 8365c784163c151445622fe90ae5666d62b6ed24 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Mon, 8 Jun 2026 17:22:34 +0200 Subject: [PATCH 3/3] [hardware] Add Zvbb vector basic bit-manipulation extension Add the Zvbb (Vector Basic Bit-manipulation) extension on top of Zvkb, gated behind the CryptoSupportBasicBit configuration. Since Zvbb implies Zvkb, the Zvkb() predicate is widened to also match Zvbb. Adds: - vbrev.v: full bit-reverse within each element - vclz.v / vctz.v: count leading / trailing zeros - vcpop.v: population count per element - vwsll.vv/vx/vi: widening shift-left-logical, with per-operand LMUL alignment checks Adds the supporting SIMD ALU helper functions and a riscv-tests suite (zvbb.c) covering all instructions with masking variants. Switches the toolchain and spike ISA strings from zvkb to zvbb (which subsumes it). Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/common/runtime.mk | 6 +- apps/riscv-tests/isa/Makefile | 4 +- apps/riscv-tests/isa/rv64uv/Makefrag | 1 + apps/riscv-tests/isa/rv64uv/zvbb.c | 541 +++++++++++++++++++++++++++ hardware/include/ara_pkg.sv | 13 +- hardware/src/ara_dispatcher.sv | 128 +++++-- hardware/src/ara_soc.sv | 2 +- hardware/src/lane/simd_alu.sv | 165 ++++++++ 8 files changed, 825 insertions(+), 35 deletions(-) create mode 100644 apps/riscv-tests/isa/rv64uv/zvbb.c diff --git a/apps/common/runtime.mk b/apps/common/runtime.mk index 2964c4b0c..fb791737f 100644 --- a/apps/common/runtime.mk +++ b/apps/common/runtime.mk @@ -79,8 +79,8 @@ RISCV_SIM ?= $(ISA_SIM_INSTALL_DIR)/bin/spike RISCV_SIM_MOD ?= $(ISA_SIM_MOD_INSTALL_DIR)/bin/spike # VLEN should be lower or equal than 4096 because of spike restrictions vlen_spike := $(shell vlen=$$(grep vlen $(ARA_DIR)/config/$(config).mk | cut -d" " -f3) && echo "$$(( $$vlen < 4096 ? $$vlen : 4096 ))") -RISCV_SIM_OPT ?= --isa=rv64gcv_zfh_zvfh_zvkb_zvl$(vlen_spike)b -RISCV_SIM_MOD_OPT ?= --isa=rv64gcv_zfh_zvfh_zvkb_zvl$(vlen_spike)b -d +RISCV_SIM_OPT ?= --isa=rv64gcv_zfh_zvfh_zvbb_zvl$(vlen_spike)b +RISCV_SIM_MOD_OPT ?= --isa=rv64gcv_zfh_zvfh_zvbb_zvl$(vlen_spike)b -d # Python PYTHON ?= python3 @@ -100,7 +100,7 @@ DEFINES += $(ENV_DEFINES) $(MAKE_DEFINES) RISCV_WARNINGS += -Wunused-variable -Wall -Wextra -Wno-unused-command-line-argument # -Werror # LLVM Flags -LLVM_FLAGS ?= -march=rv64gcv_zfh_zvfh_zvkb -mabi=$(RISCV_ABI) -mno-relax -fuse-ld=lld +LLVM_FLAGS ?= -march=rv64gcv_zfh_zvfh_zvbb -mabi=$(RISCV_ABI) -mno-relax -fuse-ld=lld LLVM_V_FLAGS ?= -fno-vectorize -mllvm -scalable-vectorization=off -mllvm -riscv-v-vector-bits-min=0 -mno-implicit-float RISCV_FLAGS ?= $(LLVM_FLAGS) $(LLVM_V_FLAGS) -mcmodel=medany -I$(CURDIR)/common -O3 -ffast-math -fno-common -fno-builtin-printf $(DEFINES) $(RISCV_WARNINGS) ifeq ($(LINUX),1) diff --git a/apps/riscv-tests/isa/Makefile b/apps/riscv-tests/isa/Makefile index 5767d7169..007e74871 100644 --- a/apps/riscv-tests/isa/Makefile +++ b/apps/riscv-tests/isa/Makefile @@ -43,7 +43,7 @@ RISCV_LLVM ?= clang -fuse-ld=lld RISCV_CC_OPTS ?= -mcmodel=medany -fvisibility=hidden -mno-relax -nostdlib -nostartfiles RISCV_CC_OPTS_C ?= -O2 -mno-relax -nostdlib -nostartfiles -fno-vectorize -mllvm -scalable-vectorization=off -mllvm -riscv-v-vector-bits-min=0 -mno-implicit-float RISCV_CC_DEFS_C ?= $(ARA_DEFINES) -LLVM_V_VERSION ?= v_zfh_zvfh_zvkb +LLVM_V_VERSION ?= v_zfh_zvfh_zvbb # Original objdump + spike variables RISCV_OBJDUMP ?= llvm-objdump --disassemble-all --disassemble-zeroes --section=.text --section=.text.startup --section=.text.init --section=.data @@ -64,7 +64,7 @@ vpath %.S $(src_dir) $(RISCV_SIM) --isa=rv32gcv $< 2> $@ %.cout: % - $(RISCV_SIM) --isa=rv64gcv_zfh_zvfh_zvkb_zvl4096b $< 2> $@ + $(RISCV_SIM) --isa=rv64gcv_zfh_zvfh_zvbb_zvl4096b $< 2> $@ %.cout32: % $(RISCV_SIM) --isa=rv32gcv $< 2> $@ diff --git a/apps/riscv-tests/isa/rv64uv/Makefrag b/apps/riscv-tests/isa/rv64uv/Makefrag index 0e491be99..fbfe51c52 100644 --- a/apps/riscv-tests/isa/rv64uv/Makefrag +++ b/apps/riscv-tests/isa/rv64uv/Makefrag @@ -181,6 +181,7 @@ rv64uv_sc_tests = vaadd \ vfrec7 \ vfrsqrt7 \ zvkb \ + zvbb \ vrgather \ vcompress diff --git a/apps/riscv-tests/isa/rv64uv/zvbb.c b/apps/riscv-tests/isa/rv64uv/zvbb.c new file mode 100644 index 000000000..ff01f72a6 --- /dev/null +++ b/apps/riscv-tests/isa/rv64uv/zvbb.c @@ -0,0 +1,541 @@ +// Copyright 2024 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 +// +// Zvbb instruction tests. + +#include "vector_macros.h" + +#define kElems 12 + +static const uint8_t kSrc8[kElems] = {0x00, 0x01, 0x5a, 0x80, 0xff, 0x3c, + 0xc3, 0x69, 0x96, 0x0f, 0xf0, 0xa5}; +static const uint8_t kAux8[kElems] = {0xff, 0x55, 0x0f, 0x01, 0x33, 0xaa, + 0x3c, 0x81, 0x10, 0xf0, 0x7e, 0x5a}; +static const uint16_t kSrc16[kElems] = {0x0001, 0x1234, 0xabcd, 0x00ff, + 0xff00, 0x5aa5, 0x1357, 0x2468, + 0x8001, 0x7ffe, 0xc33c, 0xdead}; +static const uint16_t kAux16[kElems] = {0xffff, 0x0f0f, 0x3333, 0x00f0, + 0xf00f, 0xa55a, 0x1111, 0x8888, + 0x0001, 0x7fff, 0x3cc3, 0xbeef}; +static const uint32_t kSrc32[kElems] = {0x00000001u, 0x12345678u, 0x89abcdefu, + 0x00ff00ffu, 0xff00ff00u, 0x5aa55aa5u, + 0x13579bdfu, 0x2468ace0u, 0x80000001u, + 0x7ffffffeu, 0xc33cc33cu, 0xdeadbeefu}; +static const uint32_t kAux32[kElems] = {0xffffffffu, 0x0f0f0f0fu, 0x33333333u, + 0x00f000f0u, 0xf00ff00fu, 0xa55aa55au, + 0x11111111u, 0x88888888u, 0x00000001u, + 0x7fffffffu, 0x3cc33cc3u, 0xbeefcafeu}; +static const uint64_t kSrc64[kElems] = { + 0x0000000000000001ull, 0x1234567890abcdefull, 0xfedcba9876543210ull, + 0x00ff00ff00ff00ffull, 0xff00ff00ff00ff00ull, 0x5aa55aa55aa55aa5ull, + 0x13579bdf2468ace0ull, 0x2468ace013579bdfull, 0x8000000000000001ull, + 0x7ffffffffffffffeull, 0xc33cc33cc33cc33cull, 0xdeadbeefcafebabeull}; + +static volatile uint8_t buf8_a[kElems] __attribute__((aligned(128))); +static volatile uint8_t buf8_b[kElems] __attribute__((aligned(128))); +static volatile uint8_t buf8_out[kElems] __attribute__((aligned(128))); +static uint8_t exp8[kElems]; + +static volatile uint16_t buf16_a[kElems] __attribute__((aligned(128))); +static volatile uint16_t buf16_b[kElems] __attribute__((aligned(128))); +static volatile uint16_t buf16_out[kElems] __attribute__((aligned(128))); +static uint16_t exp16[kElems]; + +static volatile uint32_t buf32_a[kElems] __attribute__((aligned(128))); +static volatile uint32_t buf32_b[kElems] __attribute__((aligned(128))); +static volatile uint32_t buf32_out[kElems] __attribute__((aligned(128))); +static uint32_t exp32[kElems]; + +static volatile uint64_t buf64_a[kElems] __attribute__((aligned(128))); +static volatile uint64_t buf64_out[kElems] __attribute__((aligned(128))); +static uint64_t exp64[kElems]; + +static void start_case(const char *name) { + ++test_case; + printf("Test %d: %s\n", test_case, name); +} + +static void load_mask(void) { VLOAD_8(v0, 0x6D, 0x0B); } + +static inline void vset8_m1(void) { + long avl = kElems; + asm volatile("vsetvli zero, %0, e8, m1, ta, ma" ::"r"(avl) : "memory"); +} + +static inline void vset16_m1(void) { + long avl = kElems; + asm volatile("vsetvli zero, %0, e16, m1, ta, ma" ::"r"(avl) : "memory"); +} + +static inline void vset16_m2(void) { + long avl = kElems; + asm volatile("vsetvli zero, %0, e16, m2, ta, ma" ::"r"(avl) : "memory"); +} + +static inline void vset32_m1(void) { + long avl = kElems; + asm volatile("vsetvli zero, %0, e32, m1, ta, ma" ::"r"(avl) : "memory"); +} + +static inline void vset32_m2(void) { + long avl = kElems; + asm volatile("vsetvli zero, %0, e32, m2, ta, ma" ::"r"(avl) : "memory"); +} + +static inline void vset64_m1(void) { + long avl = kElems; + asm volatile("vsetvli zero, %0, e64, m1, ta, ma" ::"r"(avl) : "memory"); +} + +static inline void vset64_m2(void) { + long avl = kElems; + asm volatile("vsetvli zero, %0, e64, m2, ta, ma" ::"r"(avl) : "memory"); +} + +static uint64_t bit_mask(int bits) { + return bits == 64 ? ~0ull : ((1ull << bits) - 1); +} + +static uint8_t bitrev8(uint8_t x) { + x = (uint8_t)(((x & 0xaa) >> 1) | ((x & 0x55) << 1)); + x = (uint8_t)(((x & 0xcc) >> 2) | ((x & 0x33) << 2)); + x = (uint8_t)(((x & 0xf0) >> 4) | ((x & 0x0f) << 4)); + return x; +} + +static uint64_t vbrev_ref(uint64_t x, int bits) { + uint64_t out = 0; + for (int i = 0; i < bits / 8; ++i) + out |= (uint64_t)bitrev8((uint8_t)(x >> (i * 8))) << ((bits - 8) - i * 8); + return out & bit_mask(bits); +} + +static uint64_t clz_ref(uint64_t x, int bits) { + uint64_t mask = bit_mask(bits); + x &= mask; + for (int i = 0; i < bits; ++i) + if ((x >> (bits - 1 - i)) & 1ull) + return (uint64_t)i; + return (uint64_t)bits; +} + +static uint64_t ctz_ref(uint64_t x, int bits) { + uint64_t mask = bit_mask(bits); + x &= mask; + for (int i = 0; i < bits; ++i) + if ((x >> i) & 1ull) + return (uint64_t)i; + return (uint64_t)bits; +} + +static uint64_t cpop_ref(uint64_t x, int bits) { + uint64_t mask = bit_mask(bits); + uint64_t count = 0; + x &= mask; + for (int i = 0; i < bits; ++i) + count += (x >> i) & 1ull; + return count; +} + +static uint64_t vwsll_ref(uint64_t x, uint64_t sh, int src_bits) { + int dst_bits = src_bits * 2; + uint64_t mask = bit_mask(dst_bits); + unsigned amt = (unsigned)(sh & (uint64_t)(dst_bits - 1)); + return ((x & bit_mask(src_bits)) << amt) & mask; +} + +static int mask_active(int idx) { + static const uint8_t mask_bits[2] = {0x6D, 0x0B}; + return (mask_bits[idx / 8] >> (idx % 8)) & 1; +} + +static void copy_u8(volatile uint8_t *dst, const uint8_t *src) { + for (int i = 0; i < kElems; ++i) + dst[i] = src[i]; +} + +static void copy_u16(volatile uint16_t *dst, const uint16_t *src) { + for (int i = 0; i < kElems; ++i) + dst[i] = src[i]; +} + +static void copy_u32(volatile uint32_t *dst, const uint32_t *src) { + for (int i = 0; i < kElems; ++i) + dst[i] = src[i]; +} + +static void copy_u64(volatile uint64_t *dst, const uint64_t *src) { + for (int i = 0; i < kElems; ++i) + dst[i] = src[i]; +} + +static int check_u8(const uint8_t *expected) { + for (int i = 0; i < kElems; ++i) { + if (buf8_out[i] != expected[i]) { + printf(" FAILED at element %d: got 0x%02x expected 0x%02x\n", i, + buf8_out[i], expected[i]); + ++num_failed; + return 0; + } + } + printf(" PASSED.\n"); + return 1; +} + +static int check_u16(const uint16_t *expected) { + for (int i = 0; i < kElems; ++i) { + if (buf16_out[i] != expected[i]) { + printf(" FAILED at element %d: got 0x%04x expected 0x%04x\n", i, + buf16_out[i], expected[i]); + ++num_failed; + return 0; + } + } + printf(" PASSED.\n"); + return 1; +} + +static int check_u32(const uint32_t *expected) { + for (int i = 0; i < kElems; ++i) { + if (buf32_out[i] != expected[i]) { + printf(" FAILED at element %d: got 0x%08x expected 0x%08x\n", i, + buf32_out[i], expected[i]); + ++num_failed; + return 0; + } + } + printf(" PASSED.\n"); + return 1; +} + +static int check_u64(const uint64_t *expected) { + for (int i = 0; i < kElems; ++i) { + if (buf64_out[i] != expected[i]) { + printf(" FAILED at element %d: got 0x%016llx expected 0x%016llx\n", i, + (unsigned long long)buf64_out[i], (unsigned long long)expected[i]); + ++num_failed; + return 0; + } + } + printf(" PASSED.\n"); + return 1; +} + +static void test_u8(void) { + const uint64_t scalar = 13; + + start_case("vbrev.v masked e8"); + copy_u8(buf8_a, kSrc8); + for (int i = 0; i < kElems; ++i) + exp8[i] = mask_active(i) ? (uint8_t)vbrev_ref(kSrc8[i], 8) : 0xeeu; + vset8_m1(); + load_mask(); + asm volatile("vle8.v v1, (%0)" ::"r"(exp8) : "memory"); + asm volatile("vle8.v v2, (%0)" ::"r"(buf8_a) : "memory"); + asm volatile("vbrev.v v1, v2, v0.t"); + asm volatile("vse8.v v1, (%0)" ::"r"(buf8_out) : "memory"); + check_u8(exp8); + + start_case("vclz.v e8"); + copy_u8(buf8_a, kSrc8); + for (int i = 0; i < kElems; ++i) + exp8[i] = (uint8_t)clz_ref(kSrc8[i], 8); + vset8_m1(); + asm volatile("vle8.v v2, (%0)" ::"r"(buf8_a) : "memory"); + asm volatile("vclz.v v1, v2"); + asm volatile("vse8.v v1, (%0)" ::"r"(buf8_out) : "memory"); + check_u8(exp8); + + start_case("vctz.v masked e8"); + copy_u8(buf8_a, kSrc8); + for (int i = 0; i < kElems; ++i) + exp8[i] = mask_active(i) ? (uint8_t)ctz_ref(kSrc8[i], 8) : 0xeeu; + vset8_m1(); + load_mask(); + asm volatile("vle8.v v1, (%0)" ::"r"(exp8) : "memory"); + asm volatile("vle8.v v2, (%0)" ::"r"(buf8_a) : "memory"); + asm volatile("vctz.v v1, v2, v0.t"); + asm volatile("vse8.v v1, (%0)" ::"r"(buf8_out) : "memory"); + check_u8(exp8); + + start_case("vcpop.v e8"); + copy_u8(buf8_a, kSrc8); + for (int i = 0; i < kElems; ++i) + exp8[i] = (uint8_t)cpop_ref(kSrc8[i], 8); + vset8_m1(); + asm volatile("vle8.v v2, (%0)" ::"r"(buf8_a) : "memory"); + asm volatile("vcpop.v v1, v2"); + asm volatile("vse8.v v1, (%0)" ::"r"(buf8_out) : "memory"); + check_u8(exp8); + + start_case("vwsll.vv e8->e16"); + copy_u8(buf8_a, kSrc8); + copy_u8(buf8_b, kAux8); + for (int i = 0; i < kElems; ++i) + exp16[i] = (uint16_t)vwsll_ref(kSrc8[i], kAux8[i], 8); + vset8_m1(); + asm volatile("vle8.v v2, (%0)" ::"r"(buf8_a) : "memory"); + asm volatile("vle8.v v4, (%0)" ::"r"(buf8_b) : "memory"); + asm volatile("vwsll.vv v8, v2, v4"); + vset16_m2(); + asm volatile("vse16.v v8, (%0)" ::"r"(buf16_out) : "memory"); + check_u16(exp16); + + start_case("vwsll.vx masked e8->e16"); + copy_u8(buf8_a, kSrc8); + for (int i = 0; i < kElems; ++i) + exp16[i] = + mask_active(i) ? (uint16_t)vwsll_ref(kSrc8[i], scalar, 8) : 0xbeefu; + vset16_m2(); + load_mask(); + asm volatile("vle16.v v8, (%0)" ::"r"(exp16) : "memory"); + vset8_m1(); + asm volatile("vle8.v v2, (%0)" ::"r"(buf8_a) : "memory"); + asm volatile("vwsll.vx v8, v2, %[S], v0.t" ::[S] "r"(scalar)); + vset16_m2(); + asm volatile("vse16.v v8, (%0)" ::"r"(buf16_out) : "memory"); + check_u16(exp16); + + start_case("vwsll.vi e8->e16"); + copy_u8(buf8_a, kSrc8); + for (int i = 0; i < kElems; ++i) + exp16[i] = (uint16_t)vwsll_ref(kSrc8[i], 11, 8); + vset8_m1(); + asm volatile("vle8.v v2, (%0)" ::"r"(buf8_a) : "memory"); + asm volatile("vwsll.vi v8, v2, 11"); + vset16_m2(); + asm volatile("vse16.v v8, (%0)" ::"r"(buf16_out) : "memory"); + check_u16(exp16); +} + +static void test_u16(void) { + const uint64_t scalar = 29; + + start_case("vbrev.v e16"); + copy_u16(buf16_a, kSrc16); + for (int i = 0; i < kElems; ++i) + exp16[i] = (uint16_t)vbrev_ref(kSrc16[i], 16); + vset16_m1(); + asm volatile("vle16.v v2, (%0)" ::"r"(buf16_a) : "memory"); + asm volatile("vbrev.v v1, v2"); + asm volatile("vse16.v v1, (%0)" ::"r"(buf16_out) : "memory"); + check_u16(exp16); + + start_case("vclz.v masked e16"); + copy_u16(buf16_a, kSrc16); + for (int i = 0; i < kElems; ++i) + exp16[i] = mask_active(i) ? (uint16_t)clz_ref(kSrc16[i], 16) : 0xbeefu; + vset16_m1(); + load_mask(); + asm volatile("vle16.v v1, (%0)" ::"r"(exp16) : "memory"); + asm volatile("vle16.v v2, (%0)" ::"r"(buf16_a) : "memory"); + asm volatile("vclz.v v1, v2, v0.t"); + asm volatile("vse16.v v1, (%0)" ::"r"(buf16_out) : "memory"); + check_u16(exp16); + + start_case("vctz.v e16"); + copy_u16(buf16_a, kSrc16); + for (int i = 0; i < kElems; ++i) + exp16[i] = (uint16_t)ctz_ref(kSrc16[i], 16); + vset16_m1(); + asm volatile("vle16.v v2, (%0)" ::"r"(buf16_a) : "memory"); + asm volatile("vctz.v v1, v2"); + asm volatile("vse16.v v1, (%0)" ::"r"(buf16_out) : "memory"); + check_u16(exp16); + + start_case("vcpop.v masked e16"); + copy_u16(buf16_a, kSrc16); + for (int i = 0; i < kElems; ++i) + exp16[i] = mask_active(i) ? (uint16_t)cpop_ref(kSrc16[i], 16) : 0xbeefu; + vset16_m1(); + load_mask(); + asm volatile("vle16.v v1, (%0)" ::"r"(exp16) : "memory"); + asm volatile("vle16.v v2, (%0)" ::"r"(buf16_a) : "memory"); + asm volatile("vcpop.v v1, v2, v0.t"); + asm volatile("vse16.v v1, (%0)" ::"r"(buf16_out) : "memory"); + check_u16(exp16); + + start_case("vwsll.vv e16->e32"); + copy_u16(buf16_a, kSrc16); + copy_u16(buf16_b, kAux16); + for (int i = 0; i < kElems; ++i) + exp32[i] = (uint32_t)vwsll_ref(kSrc16[i], kAux16[i], 16); + vset16_m1(); + asm volatile("vle16.v v2, (%0)" ::"r"(buf16_a) : "memory"); + asm volatile("vle16.v v4, (%0)" ::"r"(buf16_b) : "memory"); + asm volatile("vwsll.vv v8, v2, v4"); + vset32_m2(); + asm volatile("vse32.v v8, (%0)" ::"r"(buf32_out) : "memory"); + check_u32(exp32); + + start_case("vwsll.vx e16->e32"); + copy_u16(buf16_a, kSrc16); + for (int i = 0; i < kElems; ++i) + exp32[i] = (uint32_t)vwsll_ref(kSrc16[i], scalar, 16); + vset16_m1(); + asm volatile("vle16.v v2, (%0)" ::"r"(buf16_a) : "memory"); + asm volatile("vwsll.vx v8, v2, %[S]" ::[S] "r"(scalar)); + vset32_m2(); + asm volatile("vse32.v v8, (%0)" ::"r"(buf32_out) : "memory"); + check_u32(exp32); + + start_case("vwsll.vi masked e16->e32"); + copy_u16(buf16_a, kSrc16); + for (int i = 0; i < kElems; ++i) + exp32[i] = + mask_active(i) ? (uint32_t)vwsll_ref(kSrc16[i], 21, 16) : 0xdeadbeefu; + vset32_m2(); + load_mask(); + asm volatile("vle32.v v8, (%0)" ::"r"(exp32) : "memory"); + vset16_m1(); + asm volatile("vle16.v v2, (%0)" ::"r"(buf16_a) : "memory"); + asm volatile("vwsll.vi v8, v2, 21, v0.t"); + vset32_m2(); + asm volatile("vse32.v v8, (%0)" ::"r"(buf32_out) : "memory"); + check_u32(exp32); +} + +static void test_u32(void) { + const uint64_t scalar = 37; + + start_case("vbrev.v e32"); + copy_u32(buf32_a, kSrc32); + for (int i = 0; i < kElems; ++i) + exp32[i] = (uint32_t)vbrev_ref(kSrc32[i], 32); + vset32_m1(); + asm volatile("vle32.v v2, (%0)" ::"r"(buf32_a) : "memory"); + asm volatile("vbrev.v v1, v2"); + asm volatile("vse32.v v1, (%0)" ::"r"(buf32_out) : "memory"); + check_u32(exp32); + + start_case("vclz.v e32"); + copy_u32(buf32_a, kSrc32); + for (int i = 0; i < kElems; ++i) + exp32[i] = (uint32_t)clz_ref(kSrc32[i], 32); + vset32_m1(); + asm volatile("vle32.v v2, (%0)" ::"r"(buf32_a) : "memory"); + asm volatile("vclz.v v1, v2"); + asm volatile("vse32.v v1, (%0)" ::"r"(buf32_out) : "memory"); + check_u32(exp32); + + start_case("vctz.v masked e32"); + copy_u32(buf32_a, kSrc32); + for (int i = 0; i < kElems; ++i) + exp32[i] = mask_active(i) ? (uint32_t)ctz_ref(kSrc32[i], 32) : 0xdeadbeefu; + vset32_m1(); + load_mask(); + asm volatile("vle32.v v1, (%0)" ::"r"(exp32) : "memory"); + asm volatile("vle32.v v2, (%0)" ::"r"(buf32_a) : "memory"); + asm volatile("vctz.v v1, v2, v0.t"); + asm volatile("vse32.v v1, (%0)" ::"r"(buf32_out) : "memory"); + check_u32(exp32); + + start_case("vcpop.v e32"); + copy_u32(buf32_a, kSrc32); + for (int i = 0; i < kElems; ++i) + exp32[i] = (uint32_t)cpop_ref(kSrc32[i], 32); + vset32_m1(); + asm volatile("vle32.v v2, (%0)" ::"r"(buf32_a) : "memory"); + asm volatile("vcpop.v v1, v2"); + asm volatile("vse32.v v1, (%0)" ::"r"(buf32_out) : "memory"); + check_u32(exp32); + + start_case("vwsll.vv e32->e64"); + copy_u32(buf32_a, kSrc32); + copy_u32(buf32_b, kAux32); + for (int i = 0; i < kElems; ++i) + exp64[i] = vwsll_ref(kSrc32[i], kAux32[i], 32); + vset32_m1(); + asm volatile("vle32.v v2, (%0)" ::"r"(buf32_a) : "memory"); + asm volatile("vle32.v v4, (%0)" ::"r"(buf32_b) : "memory"); + asm volatile("vwsll.vv v8, v2, v4"); + vset64_m2(); + asm volatile("vse64.v v8, (%0)" ::"r"(buf64_out) : "memory"); + check_u64(exp64); + + start_case("vwsll.vx masked e32->e64"); + copy_u32(buf32_a, kSrc32); + for (int i = 0; i < kElems; ++i) + exp64[i] = mask_active(i) ? vwsll_ref(kSrc32[i], scalar, 32) + : 0xdeadbeefdeadbeefull; + vset64_m2(); + load_mask(); + asm volatile("vle64.v v8, (%0)" ::"r"(exp64) : "memory"); + vset32_m1(); + asm volatile("vle32.v v2, (%0)" ::"r"(buf32_a) : "memory"); + asm volatile("vwsll.vx v8, v2, %[S], v0.t" ::[S] "r"(scalar)); + vset64_m2(); + asm volatile("vse64.v v8, (%0)" ::"r"(buf64_out) : "memory"); + check_u64(exp64); + + start_case("vwsll.vi e32->e64"); + copy_u32(buf32_a, kSrc32); + for (int i = 0; i < kElems; ++i) + exp64[i] = vwsll_ref(kSrc32[i], 21, 32); + vset32_m1(); + asm volatile("vle32.v v2, (%0)" ::"r"(buf32_a) : "memory"); + asm volatile("vwsll.vi v8, v2, 21"); + vset64_m2(); + asm volatile("vse64.v v8, (%0)" ::"r"(buf64_out) : "memory"); + check_u64(exp64); +} + +static void test_u64(void) { + start_case("vbrev.v e64"); + copy_u64(buf64_a, kSrc64); + for (int i = 0; i < kElems; ++i) + exp64[i] = vbrev_ref(kSrc64[i], 64); + vset64_m1(); + asm volatile("vle64.v v2, (%0)" ::"r"(buf64_a) : "memory"); + asm volatile("vbrev.v v1, v2"); + asm volatile("vse64.v v1, (%0)" ::"r"(buf64_out) : "memory"); + check_u64(exp64); + + start_case("vclz.v masked e64"); + copy_u64(buf64_a, kSrc64); + for (int i = 0; i < kElems; ++i) + exp64[i] = mask_active(i) ? clz_ref(kSrc64[i], 64) : 0xdeadbeefdeadbeefull; + vset64_m1(); + load_mask(); + asm volatile("vle64.v v1, (%0)" ::"r"(exp64) : "memory"); + asm volatile("vle64.v v2, (%0)" ::"r"(buf64_a) : "memory"); + asm volatile("vclz.v v1, v2, v0.t"); + asm volatile("vse64.v v1, (%0)" ::"r"(buf64_out) : "memory"); + check_u64(exp64); + + start_case("vctz.v e64"); + copy_u64(buf64_a, kSrc64); + for (int i = 0; i < kElems; ++i) + exp64[i] = ctz_ref(kSrc64[i], 64); + vset64_m1(); + asm volatile("vle64.v v2, (%0)" ::"r"(buf64_a) : "memory"); + asm volatile("vctz.v v1, v2"); + asm volatile("vse64.v v1, (%0)" ::"r"(buf64_out) : "memory"); + check_u64(exp64); + + start_case("vcpop.v masked e64"); + copy_u64(buf64_a, kSrc64); + for (int i = 0; i < kElems; ++i) + exp64[i] = mask_active(i) ? cpop_ref(kSrc64[i], 64) : 0xdeadbeefdeadbeefull; + vset64_m1(); + load_mask(); + asm volatile("vle64.v v1, (%0)" ::"r"(exp64) : "memory"); + asm volatile("vle64.v v2, (%0)" ::"r"(buf64_a) : "memory"); + asm volatile("vcpop.v v1, v2, v0.t"); + asm volatile("vse64.v v1, (%0)" ::"r"(buf64_out) : "memory"); + check_u64(exp64); +} + +int main(void) { + INIT_CHECK(); + enable_vec(); + enable_fp(); + + test_u8(); + test_u16(); + test_u32(); + test_u64(); + + EXIT_CHECK(); +} diff --git a/hardware/include/ara_pkg.sv b/hardware/include/ara_pkg.sv index e66b820c0..03da64a60 100644 --- a/hardware/include/ara_pkg.sv +++ b/hardware/include/ara_pkg.sv @@ -83,11 +83,16 @@ package ara_pkg; // 16 bits correspond to {Zvbb, Zvbc, Zvkb, Zvkg, Zvkned, Zvknha, Zvknhb, Zvksed, Zvksh, Zvkn, Zvknc, Zvkng, Zvks, Zvksc, Zvksg, Zvkt} typedef enum bit [15:0] { CryptoSupportNone = 16'h0000, - CryptoSupportBitmanip = 16'h2000 + CryptoSupportBitmanip = 16'h2000, + CryptoSupportBasicBit = 16'hA000 } crypto_support_e; + function automatic bit Zvbb(crypto_support_e e); + return e[15]; + endfunction + function automatic bit Zvkb(crypto_support_e e); - return e[13]; + return e[15] | e[13]; endfunction // Multiplier latencies. @@ -137,8 +142,8 @@ package ara_pkg; typedef enum logic [7:0] { // Arithmetic and logic instructions VADD, VSUB, VADC, VSBC, VRSUB, VMINU, VMIN, VMAXU, VMAX, VAND, VOR, VXOR, - // Zvkb - VANDN, VBREV8, VREV8, VROL, VROR, + // Zvbb / Zvkb + VANDN, VBREV8, VBREV, VCLZ, VCTZ, VCPOPV, VREV8, VROL, VROR, VWSLL, // Fixed point VSADDU, VSADD, VSSUBU, VSSUB, VAADDU, VAADD, VASUBU, VASUB, VSSRL, VSSRA, VNCLIP, VNCLIPU, // Shifts, diff --git a/hardware/src/ara_dispatcher.sv b/hardware/src/ara_dispatcher.sv index 6846f12a1..d40a48928 100644 --- a/hardware/src/ara_dispatcher.sv +++ b/hardware/src/ara_dispatcher.sv @@ -943,21 +943,40 @@ module ara_dispatcher import ara_pkg::*; import rvv_pkg::*; #( ara_req.conversion_vs2 = OpQueueConversionSExt2; ara_req.cvt_resize = CVT_WIDE; end + 6'b110101: if (Zvbb(CryptoSupport)) begin + ara_req.op = ara_pkg::VWSLL; + ara_req.emul = next_lmul(csr_vtype_q.vlmul); + ara_req.vtype.vsew = csr_vtype_q.vsew.next(); + ara_req.conversion_vs1 = OpQueueConversionZExt2; + ara_req.conversion_vs2 = OpQueueConversionZExt2; + ara_req.cvt_resize = CVT_WIDE; + + if (int'(csr_vtype_q.vsew) > int'(EW32) || ara_req.emul == LMUL_RSVD) + illegal_insn = 1'b1; + end else begin + illegal_insn = 1'b1; + end default: illegal_insn = 1'b1; endcase // Instructions with an integer LMUL have extra constraints on the registers they can - // access. + // access. Source and destination register groups can differ for widening ops. unique case (ara_req.emul) - LMUL_2: if ((insn.varith_type.rs1 & 5'b00001) != 5'b00000 || - (insn.varith_type.rs2 & 5'b00001) != 5'b00000 || - (insn.varith_type.rd & 5'b00001) != 5'b00000) illegal_insn = 1'b1; - LMUL_4: if ((insn.varith_type.rs1 & 5'b00011) != 5'b00000 || - (insn.varith_type.rs2 & 5'b00011) != 5'b00000 || - (insn.varith_type.rd & 5'b00011) != 5'b00000) illegal_insn = 1'b1; - LMUL_8: if ((insn.varith_type.rs1 & 5'b00111) != 5'b00000 || - (insn.varith_type.rs2 & 5'b00111) != 5'b00000 || - (insn.varith_type.rd & 5'b00111) != 5'b00000) illegal_insn = 1'b1; + LMUL_2: if ((insn.varith_type.rd & 5'b00001) != 5'b00000) illegal_insn = 1'b1; + LMUL_4: if ((insn.varith_type.rd & 5'b00011) != 5'b00000) illegal_insn = 1'b1; + LMUL_8: if ((insn.varith_type.rd & 5'b00111) != 5'b00000) illegal_insn = 1'b1; + default:; + endcase + unique case (lmul_vs1) + LMUL_2: if ((insn.varith_type.rs1 & 5'b00001) != 5'b00000) illegal_insn = 1'b1; + LMUL_4: if ((insn.varith_type.rs1 & 5'b00011) != 5'b00000) illegal_insn = 1'b1; + LMUL_8: if ((insn.varith_type.rs1 & 5'b00111) != 5'b00000) illegal_insn = 1'b1; + default:; + endcase + unique case (lmul_vs2) + LMUL_2: if ((insn.varith_type.rs2 & 5'b00001) != 5'b00000) illegal_insn = 1'b1; + LMUL_4: if ((insn.varith_type.rs2 & 5'b00011) != 5'b00000) illegal_insn = 1'b1; + LMUL_8: if ((insn.varith_type.rs2 & 5'b00111) != 5'b00000) illegal_insn = 1'b1; default:; endcase @@ -1207,18 +1226,33 @@ module ara_dispatcher import ara_pkg::*; import rvv_pkg::*; #( ara_req.op = ara_pkg::VNCLIP; ara_req.eew_vs2 = csr_vtype_q.vsew.next(); end + 6'b110101: if (Zvbb(CryptoSupport)) begin + ara_req.op = ara_pkg::VWSLL; + ara_req.emul = next_lmul(csr_vtype_q.vlmul); + ara_req.vtype.vsew = csr_vtype_q.vsew.next(); + ara_req.conversion_vs2 = OpQueueConversionZExt2; + ara_req.cvt_resize = CVT_WIDE; + + if (int'(csr_vtype_q.vsew) > int'(EW32) || ara_req.emul == LMUL_RSVD) + illegal_insn = 1'b1; + end else begin + illegal_insn = 1'b1; + end default: illegal_insn = 1'b1; endcase // Instructions with an integer LMUL have extra constraints on the registers they can - // access. + // access. Source and destination register groups can differ for widening ops. unique case (ara_req.emul) - LMUL_2: if ((insn.varith_type.rs2 & 5'b00001) != 5'b00000 || - (insn.varith_type.rd & 5'b00001) != 5'b00000) illegal_insn = 1'b1; - LMUL_4: if ((insn.varith_type.rs2 & 5'b00011) != 5'b00000 || - (insn.varith_type.rd & 5'b00011) != 5'b00000) illegal_insn = 1'b1; - LMUL_8: if ((insn.varith_type.rs2 & 5'b00111) != 5'b00000 || - (insn.varith_type.rd & 5'b00111) != 5'b00000) illegal_insn = 1'b1; + LMUL_2: if ((insn.varith_type.rd & 5'b00001) != 5'b00000) illegal_insn = 1'b1; + LMUL_4: if ((insn.varith_type.rd & 5'b00011) != 5'b00000) illegal_insn = 1'b1; + LMUL_8: if ((insn.varith_type.rd & 5'b00111) != 5'b00000) illegal_insn = 1'b1; + default:; + endcase + unique case (lmul_vs2) + LMUL_2: if ((insn.varith_type.rs2 & 5'b00001) != 5'b00000) illegal_insn = 1'b1; + LMUL_4: if ((insn.varith_type.rs2 & 5'b00011) != 5'b00000) illegal_insn = 1'b1; + LMUL_8: if ((insn.varith_type.rs2 & 5'b00111) != 5'b00000) illegal_insn = 1'b1; default:; endcase @@ -1364,6 +1398,19 @@ module ara_dispatcher import ara_pkg::*; import rvv_pkg::*; #( 6'b100000: ara_req.op = ara_pkg::VSADDU; 6'b100001: ara_req.op = ara_pkg::VSADD; 6'b100101: ara_req.op = ara_pkg::VSLL; + 6'b110101: if (Zvbb(CryptoSupport)) begin + ara_req.op = ara_pkg::VWSLL; + ara_req.emul = next_lmul(csr_vtype_q.vlmul); + ara_req.vtype.vsew = csr_vtype_q.vsew.next(); + ara_req.scalar_op = {{ELEN-5{1'b0}}, insn.varith_type.rs1}; + ara_req.conversion_vs2 = OpQueueConversionZExt2; + ara_req.cvt_resize = CVT_WIDE; + + if (int'(csr_vtype_q.vsew) > int'(EW32) || ara_req.emul == LMUL_RSVD) + illegal_insn = 1'b1; + end else begin + illegal_insn = 1'b1; + end 6'b100111: begin // vmvr.v automatic int unsigned vlmax; // Execute also if vl == 0 @@ -1458,14 +1505,17 @@ module ara_dispatcher import ara_pkg::*; import rvv_pkg::*; #( endcase // Instructions with an integer LMUL have extra constraints on the registers they can - // access. + // access. Source and destination register groups can differ for widening ops. unique case (ara_req.emul) - LMUL_2: if ((insn.varith_type.rs2 & 5'b00001) != 5'b00000 || - (insn.varith_type.rd & 5'b00001) != 5'b00000) illegal_insn = 1'b1; - LMUL_4: if ((insn.varith_type.rs2 & 5'b00011) != 5'b00000 || - (insn.varith_type.rd & 5'b00011) != 5'b00000) illegal_insn = 1'b1; - LMUL_8: if ((insn.varith_type.rs2 & 5'b00111) != 5'b00000 || - (insn.varith_type.rd & 5'b00111) != 5'b00000) illegal_insn = 1'b1; + LMUL_2: if ((insn.varith_type.rd & 5'b00001) != 5'b00000) illegal_insn = 1'b1; + LMUL_4: if ((insn.varith_type.rd & 5'b00011) != 5'b00000) illegal_insn = 1'b1; + LMUL_8: if ((insn.varith_type.rd & 5'b00111) != 5'b00000) illegal_insn = 1'b1; + default:; + endcase + unique case (lmul_vs2) + LMUL_2: if ((insn.varith_type.rs2 & 5'b00001) != 5'b00000) illegal_insn = 1'b1; + LMUL_4: if ((insn.varith_type.rs2 & 5'b00011) != 5'b00000) illegal_insn = 1'b1; + LMUL_8: if ((insn.varith_type.rs2 & 5'b00111) != 5'b00000) illegal_insn = 1'b1; default:; endcase @@ -1766,7 +1816,7 @@ module ara_dispatcher import ara_pkg::*; import rvv_pkg::*; #( if (int'(csr_vtype_q.vsew) < int'(EW16) || int'(csr_vtype_q.vlmul) inside {LMUL_1_8}) illegal_insn = 1'b1; end - // Zvkb: VBREV8, VREV8 + // Zvbb / Zvkb unary bit-manipulation 5'b01000: if (Zvkb(CryptoSupport)) begin ara_req.op = ara_pkg::VBREV8; ara_req.use_scalar_op = 1'b0; @@ -1781,6 +1831,34 @@ module ara_dispatcher import ara_pkg::*; import rvv_pkg::*; #( end else begin illegal_insn = 1'b1; end + 5'b01010: if (Zvbb(CryptoSupport)) begin + ara_req.op = ara_pkg::VBREV; + ara_req.use_scalar_op = 1'b0; + ara_req.emul = csr_vtype_q.vlmul; + end else begin + illegal_insn = 1'b1; + end + 5'b01100: if (Zvbb(CryptoSupport)) begin + ara_req.op = ara_pkg::VCLZ; + ara_req.use_scalar_op = 1'b0; + ara_req.emul = csr_vtype_q.vlmul; + end else begin + illegal_insn = 1'b1; + end + 5'b01101: if (Zvbb(CryptoSupport)) begin + ara_req.op = ara_pkg::VCTZ; + ara_req.use_scalar_op = 1'b0; + ara_req.emul = csr_vtype_q.vlmul; + end else begin + illegal_insn = 1'b1; + end + 5'b01110: if (Zvbb(CryptoSupport)) begin + ara_req.op = ara_pkg::VCPOPV; + ara_req.use_scalar_op = 1'b0; + ara_req.emul = csr_vtype_q.vlmul; + end else begin + illegal_insn = 1'b1; + end default: illegal_insn = 1'b1; endcase end diff --git a/hardware/src/ara_soc.sv b/hardware/src/ara_soc.sv index 0ee2f5ba5..ffb74db05 100644 --- a/hardware/src/ara_soc.sv +++ b/hardware/src/ara_soc.sv @@ -20,7 +20,7 @@ module ara_soc import axi_pkg::*; import ara_pkg::*; #( // Support for segment memory operations parameter seg_support_e SegSupport = SegSupportEnable, // Support for crypto extension - parameter crypto_support_e CryptoSupport = CryptoSupportBitmanip, + parameter crypto_support_e CryptoSupport = CryptoSupportBasicBit, // AXI Interface parameter int unsigned AxiDataWidth = 32*NrLanes, parameter int unsigned AxiAddrWidth = 64, diff --git a/hardware/src/lane/simd_alu.sv b/hardware/src/lane/simd_alu.sv index 5d59f7c88..560f600fb 100644 --- a/hardware/src/lane/simd_alu.sv +++ b/hardware/src/lane/simd_alu.sv @@ -75,6 +75,118 @@ module simd_alu import ara_pkg::*; import rvv_pkg::*; #( logic [7:0] less; logic [7:0] equal; + function automatic logic [7:0] bit_reverse8(logic [7:0] x); + for (int i = 0; i < 8; i++) bit_reverse8[i] = x[7-i]; + endfunction + + function automatic logic [7:0] popcount8(logic [7:0] x); + logic [7:0] count; + count = '0; + for (int i = 0; i < 8; i++) count += x[i]; + return count; + endfunction + + function automatic logic [15:0] popcount16(logic [15:0] x); + logic [15:0] count; + count = '0; + for (int i = 0; i < 16; i++) count += x[i]; + return count; + endfunction + + function automatic logic [31:0] popcount32(logic [31:0] x); + logic [31:0] count; + count = '0; + for (int i = 0; i < 32; i++) count += x[i]; + return count; + endfunction + + function automatic logic [63:0] popcount64(logic [63:0] x); + logic [63:0] count; + count = '0; + for (int i = 0; i < 64; i++) count += x[i]; + return count; + endfunction + + function automatic logic [7:0] clz8(logic [7:0] x); + logic [7:0] count; + count = 8; + for (int i = 0; i < 8; i++) + if (count == 8 && x[7-i]) begin + count = i; + end + return count; + endfunction + + function automatic logic [15:0] clz16(logic [15:0] x); + logic [15:0] count; + count = 16; + for (int i = 0; i < 16; i++) + if (count == 16 && x[15-i]) begin + count = i; + end + return count; + endfunction + + function automatic logic [31:0] clz32(logic [31:0] x); + logic [31:0] count; + count = 32; + for (int i = 0; i < 32; i++) + if (count == 32 && x[31-i]) begin + count = i; + end + return count; + endfunction + + function automatic logic [63:0] clz64(logic [63:0] x); + logic [63:0] count; + count = 64; + for (int i = 0; i < 64; i++) + if (count == 64 && x[63-i]) begin + count = i; + end + return count; + endfunction + + function automatic logic [7:0] ctz8(logic [7:0] x); + logic [7:0] count; + count = 8; + for (int i = 0; i < 8; i++) + if (count == 8 && x[i]) begin + count = i; + end + return count; + endfunction + + function automatic logic [15:0] ctz16(logic [15:0] x); + logic [15:0] count; + count = 16; + for (int i = 0; i < 16; i++) + if (count == 16 && x[i]) begin + count = i; + end + return count; + endfunction + + function automatic logic [31:0] ctz32(logic [31:0] x); + logic [31:0] count; + count = 32; + for (int i = 0; i < 32; i++) + if (count == 32 && x[i]) begin + count = i; + end + return count; + endfunction + + function automatic logic [63:0] ctz64(logic [63:0] x); + logic [63:0] count; + count = 64; + for (int i = 0; i < 64; i++) + if (count == 64 && x[i]) begin + count = i; + end + return count; + endfunction + always_comb begin: p_comparison // Default assignment less = '0; @@ -179,6 +291,52 @@ module simd_alu import ara_pkg::*; import rvv_pkg::*; #( res.w8[b][i] = opb.w8[b][7-i]; end + // Zvbb: Full bit-reverse within elements + VBREV: if (Zvbb(CryptoSupport)) begin + unique case (vew_i) + EW8 : for (int b = 0; b < 8; b++) res.w8[b] = bit_reverse8(opb.w8[b]); + EW16: for (int b = 0; b < 4; b++) begin + res.w8[2*b] = bit_reverse8(opb.w8[2*b+1]); + res.w8[2*b+1] = bit_reverse8(opb.w8[2*b]); + end + EW32: for (int b = 0; b < 2; b++) + for (int i = 0; i < 4; i++) + res.w8[4*b+i] = bit_reverse8(opb.w8[4*b+3-i]); + EW64: for (int i = 0; i < 8; i++) + res.w8[i] = bit_reverse8(opb.w8[7-i]); + endcase + end + + // Zvbb: Count leading zeros + VCLZ: if (Zvbb(CryptoSupport)) begin + unique case (vew_i) + EW8 : for (int b = 0; b < 8; b++) res.w8[b] = clz8(opb.w8[b]); + EW16: for (int b = 0; b < 4; b++) res.w16[b] = clz16(opb.w16[b]); + EW32: for (int b = 0; b < 2; b++) res.w32[b] = clz32(opb.w32[b]); + EW64: for (int b = 0; b < 1; b++) res.w64[b] = clz64(opb.w64[b]); + endcase + end + + // Zvbb: Count trailing zeros + VCTZ: if (Zvbb(CryptoSupport)) begin + unique case (vew_i) + EW8 : for (int b = 0; b < 8; b++) res.w8[b] = ctz8(opb.w8[b]); + EW16: for (int b = 0; b < 4; b++) res.w16[b] = ctz16(opb.w16[b]); + EW32: for (int b = 0; b < 2; b++) res.w32[b] = ctz32(opb.w32[b]); + EW64: for (int b = 0; b < 1; b++) res.w64[b] = ctz64(opb.w64[b]); + endcase + end + + // Zvbb: Population count per element + VCPOPV: if (Zvbb(CryptoSupport)) begin + unique case (vew_i) + EW8 : for (int b = 0; b < 8; b++) res.w8[b] = popcount8(opb.w8[b]); + EW16: for (int b = 0; b < 4; b++) res.w16[b] = popcount16(opb.w16[b]); + EW32: for (int b = 0; b < 2; b++) res.w32[b] = popcount32(opb.w32[b]); + EW64: for (int b = 0; b < 1; b++) res.w64[b] = popcount64(opb.w64[b]); + endcase + end + // Zvkb: Byte-reverse within elements (endian swap) VREV8: if (Zvkb(CryptoSupport)) begin unique case (vew_i) @@ -446,6 +604,13 @@ module simd_alu import ara_pkg::*; import rvv_pkg::*; #( EW32: for (int b = 0; b < 2; b++) res.w32[b] = opb.w32[b] << opa.w32[b][4:0]; EW64: for (int b = 0; b < 1; b++) res.w64[b] = opb.w64[b] << opa.w64[b][5:0]; endcase + VWSLL: if (Zvbb(CryptoSupport)) unique case (vew_i) + EW16: for (int b = 0; b < 4; b++) res.w16[b] = opb.w16[b] << opa.w16[b][3:0]; + // The shift amount is masked with (2 * SEW) - 1, where SEW is the source width. + EW32: for (int b = 0; b < 2; b++) res.w32[b] = opb.w32[b] << opa.w32[b][4:0]; + EW64: for (int b = 0; b < 1; b++) res.w64[b] = opb.w64[b] << opa.w64[b][5:0]; + default:; + endcase VSRL: unique case (vew_i) EW8 : for (int b = 0; b < 8; b++) res.w8 [b] = opb.w8 [b] >> opa.w8 [b][2:0]; EW16: for (int b = 0; b < 4; b++) res.w16[b] = opb.w16[b] >> opa.w16[b][3:0];