From 4021b742f0df9e9d2301e28c9fcf5d65009a91a8 Mon Sep 17 00:00:00 2001 From: Andrea Caforio Date: Tue, 26 Nov 2024 14:22:09 +0100 Subject: [PATCH] [aes, pre-dv] Pre-dv Verilator testbench for AES This commit contains a comprehensive pre-dv testbench for the AES IP block, invoking all the possible modes of operations (+GCM) with different key and inputs sizes. By default, the communication with the IP happens over the TLUL bus, but if a TLUL/shim adapter is configured, messages can be relayed through the shim first. There are two generic modules `tlul_adapter` and `tlul_delayer` that are agnostic to the actual testbench and can be reused in other testbenches that require a robust TLUL handler. This testbench mimics already existing pre-dv suites for Ascon and KMAC. Signed-off-by: Andrea Caforio --- hw/ip/aes/pre_dv/aes_tb/README.md | 58 +++++++ .../aes_tb.core} | 21 +-- .../cpp/aes_tb.cc} | 21 ++- .../data/gcm_k128_a0_d0.svh | 2 +- .../data/gcm_k128_a0_d16.svh | 2 +- .../data/gcm_k128_a20_d60.svh | 2 +- .../data/gcm_k128_a20_d64.svh | 2 +- .../data/modes_d64.svh | 2 +- .../rtl/aes_tb.sv} | 163 ++++++++++-------- .../rtl/aes_tb_c_dpi.sv} | 4 +- .../rtl/aes_tb_pkg.sv} | 93 +++++----- .../rtl/aes_tb_reqs.sv} | 18 +- .../pre_dv/aes_tb/rtl/tlul_adapter_tb_reqs.sv | 90 ++++++++++ .../rtl/tlul_delayer.sv} | 2 +- hw/ip/aes/pre_dv/aes_tlul_shim_tb/README.md | 56 +----- 15 files changed, 320 insertions(+), 216 deletions(-) create mode 100644 hw/ip/aes/pre_dv/aes_tb/README.md rename hw/ip/aes/pre_dv/{aes_tlul_shim_tb/aes_tlul_shim_tb.core => aes_tb/aes_tb.core} (83%) rename hw/ip/aes/pre_dv/{aes_tlul_shim_tb/cpp/aes_tlul_shim_tb.cc => aes_tb/cpp/aes_tb.cc} (73%) rename hw/ip/aes/pre_dv/{aes_tlul_shim_tb => aes_tb}/data/gcm_k128_a0_d0.svh (99%) rename hw/ip/aes/pre_dv/{aes_tlul_shim_tb => aes_tb}/data/gcm_k128_a0_d16.svh (99%) rename hw/ip/aes/pre_dv/{aes_tlul_shim_tb => aes_tb}/data/gcm_k128_a20_d60.svh (99%) rename hw/ip/aes/pre_dv/{aes_tlul_shim_tb => aes_tb}/data/gcm_k128_a20_d64.svh (99%) rename hw/ip/aes/pre_dv/{aes_tlul_shim_tb => aes_tb}/data/modes_d64.svh (99%) rename hw/ip/aes/pre_dv/{aes_tlul_shim_tb/rtl/aes_tlul_shim_tb.sv => aes_tb/rtl/aes_tb.sv} (59%) rename hw/ip/aes/pre_dv/{aes_tlul_shim_tb/rtl/aes_tlul_shim_tb_c_dpi.sv => aes_tb/rtl/aes_tb_c_dpi.sv} (98%) rename hw/ip/aes/pre_dv/{aes_tlul_shim_tb/rtl/aes_tlul_shim_tb_pkg.sv => aes_tb/rtl/aes_tb_pkg.sv} (60%) rename hw/ip/aes/pre_dv/{aes_tlul_shim_tb/rtl/aes_tlul_shim_tb_reqs.sv => aes_tb/rtl/aes_tb_reqs.sv} (62%) create mode 100644 hw/ip/aes/pre_dv/aes_tb/rtl/tlul_adapter_tb_reqs.sv rename hw/ip/aes/pre_dv/{aes_tlul_shim_tb/rtl/aes_tlul_shim_delayer.sv => aes_tb/rtl/tlul_delayer.sv} (99%) mode change 100644 => 120000 hw/ip/aes/pre_dv/aes_tlul_shim_tb/README.md diff --git a/hw/ip/aes/pre_dv/aes_tb/README.md b/hw/ip/aes/pre_dv/aes_tb/README.md new file mode 100644 index 0000000000000..d50b0c587ac55 --- /dev/null +++ b/hw/ip/aes/pre_dv/aes_tb/README.md @@ -0,0 +1,58 @@ +# TLUL/Shim Verilator Testbench + +This directory contains the Verilator testbench for the AES IP block. +Out of the box, the testbench contains test vectors for most of the salient use cases, nonetheless extending the testbench with further tests is straightforward as detailed below. +By default, communication with the IP happens over the TLUL bus. +If a TLUL/shim adapter is available, messages can optionally be relayed by the shim. + +## Current Test Vectors + +The `./data` directory contains an array of `.svh` files each of them containing a single set of input stimuli that constitute a test: + +``` +data +├── gcm_k128_a0_d0.svh # AES-GCM-128 Encryption; 0 AD Bytes; 0 Msg Bytes +├── gcm_k128_a0_d16.svh # AES-GCM-128 Encryption; 0 AD Bytes; 16 Msg Bytes +├── gcm_k128_a20_d60.svh # AES-GCM-128 Encryption/Decryption/Save/Restore; 20 AD Bytes; 60 Msg Bytes +├── gcm_k128_a20_d64.svh # AES-GCM-128 Encryption; 20 AD Bytes; 64 Msg Bytes +└── modes_d64.svh # AES-{128,192,256}-{ECB,CBC,OFB,CFB,CTR} Encryption/Decryption +``` + +### Adding/Modifying Tests + +Each test vector file `./data/*.svh` starts with a preamble that instruments both the testbench RTL as well as the `c_dpi` model: + +```systemverilog +`define AD_LENGTH // Number of AD bytes +`define MSG_LENGTH // Number of Msg bytes +`define NUM_REQUESTS // Total number of requests +``` + +Here, `NUM_REQUESTS` denotes the number of `read_request`, `write_request` and `c_dpi_load` invocations within the file. +Having written a new test vector file, the `fusesoc` configuration needs to be made aware of it. + +1. Add the `.svh` filename to the list of RTL files under `files_rtl/files`. +2. Add the `.svh` filename to the `DREQUESTS_FILE` Verilator variable under `verilator/verilator_options`. + +## Building and Running the Verilator Testbench + +To build the testbench, execute from the OpenTitan top level: + +```sh +fusesoc --cores-root=. --verbose run --setup --build lowrisc:dv_verilator:aes_tb +``` +To execute the obtained Verilator binary and with trace generation, run: + +```sh +./build/lowrisc_dv_verilator_aes_tb_0/default-verilator/Vaes_tb --trace +``` + +## Details of the testbench + +- cpp/aes\_tb.cc: contains main function and instantiation of SimCtrl +- rtl/aes\_tb.sv: contains the testbench logic +- rtl/tlul\_delayer.sv: contains an optional delayer module to artificially induce random delays in the TLUL bus. +- rtl/tlul\_adapter_tb_reqs.sv: is an adapter than converts generic read/write requests into TLUL requests. +- rtl/aes\_tb_reqs.sv: contains requests (stimuli) that are fed to the testbench. +- rtl/aes\_tb_pkg.sv: contains common parameters and functions. +- data/*: contains test vector files. diff --git a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/aes_tlul_shim_tb.core b/hw/ip/aes/pre_dv/aes_tb/aes_tb.core similarity index 83% rename from hw/ip/aes/pre_dv/aes_tlul_shim_tb/aes_tlul_shim_tb.core rename to hw/ip/aes/pre_dv/aes_tb/aes_tb.core index f701a10a2e292..b3fdffa07ffef 100644 --- a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/aes_tlul_shim_tb.core +++ b/hw/ip/aes/pre_dv/aes_tb/aes_tb.core @@ -2,8 +2,8 @@ CAPI=2: # Copyright lowRISC contributors (OpenTitan project). # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -name: "lowrisc:dv_verilator:aes_tlul_shim_tb" -description: "AES TLUL Shim TB" +name: "lowrisc:dv_verilator:aes_tb" +description: "AES TB" filesets: files_rtl: depend: @@ -16,11 +16,12 @@ filesets: - data/gcm_k128_a0_d16.svh : {is_include_file : true} - data/gcm_k128_a0_d0.svh : {is_include_file : true} - data/modes_d64.svh : {is_include_file : true} - - rtl/aes_tlul_shim_tb_pkg.sv - - rtl/aes_tlul_shim_tb_reqs.sv - - rtl/aes_tlul_shim_tb_c_dpi.sv - - rtl/aes_tlul_shim_delayer.sv - - rtl/aes_tlul_shim_tb.sv + - rtl/aes_tb_pkg.sv + - rtl/aes_tb_reqs.sv + - rtl/aes_tb_c_dpi.sv + - rtl/tlul_delayer.sv + - rtl/tlul_adapter_tb_reqs.sv + - rtl/aes_tb.sv file_type: systemVerilogSource files_dv_verilator: @@ -28,7 +29,7 @@ filesets: - lowrisc:dv_verilator:simutil_verilator files: - - cpp/aes_tlul_shim_tb.cc + - cpp/aes_tb.cc file_type: cppSource targets: @@ -37,7 +38,7 @@ targets: filesets: - files_rtl - files_dv_verilator - toplevel: aes_tlul_shim_tb + toplevel: aes_tb tools: verilator: mode: cc @@ -55,7 +56,7 @@ targets: # -O # Optimization levels have a large impact on the runtime performance of the # simulation model. -O2 and -O3 are pretty similar, -Os is slower than -O2/-O3 - - '-CFLAGS "-std=c++11 -Wall -DVM_TRACE_FMT_FST -DTOPLEVEL_NAME=aes_tlul_shim_tb -g -O0"' + - '-CFLAGS "-std=c++11 -Wall -DVM_TRACE_FMT_FST -DTOPLEVEL_NAME=aes_tb -g -O0"' - '-LDFLAGS "-pthread -lutil -lelf"' - "-Wall" # XXX: Cleanup all warnings and remove this option diff --git a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/cpp/aes_tlul_shim_tb.cc b/hw/ip/aes/pre_dv/aes_tb/cpp/aes_tb.cc similarity index 73% rename from hw/ip/aes/pre_dv/aes_tlul_shim_tb/cpp/aes_tlul_shim_tb.cc rename to hw/ip/aes/pre_dv/aes_tb/cpp/aes_tb.cc index eacce2b6b84c1..d1f0917a90633 100644 --- a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/cpp/aes_tlul_shim_tb.cc +++ b/hw/ip/aes/pre_dv/aes_tb/cpp/aes_tb.cc @@ -6,30 +6,29 @@ #include #include -#include "Vaes_tlul_shim_tb.h" +#include "Vaes_tb.h" #include "sim_ctrl_extension.h" #include "verilated_toplevel.h" #include "verilator_sim_ctrl.h" -class AesTlulShimTb : public SimCtrlExtension { +class AesTb : public SimCtrlExtension { using SimCtrlExtension::SimCtrlExtension; public: - AesTlulShimTb(aes_tlul_shim_tb *top); + AesTb(aes_tb *top); void OnClock(unsigned long sim_time); private: - aes_tlul_shim_tb *top_; + aes_tb *top_; }; // Constructor: // - Set up top_ ptr -AesTlulShimTb::AesTlulShimTb(aes_tlul_shim_tb *top) - : SimCtrlExtension{}, top_(top) {} +AesTb::AesTb(aes_tb *top) : SimCtrlExtension{}, top_(top) {} // Function called once every clock cycle from SimCtrl -void AesTlulShimTb::OnClock(unsigned long sim_time) { +void AesTb::OnClock(unsigned long sim_time) { if (top_->test_done_o) { VerilatorSimCtrl::GetInstance().RequestStop(top_->test_passed_o); } @@ -39,7 +38,7 @@ int main(int argc, char **argv) { int ret_code; // Init verilog instance - aes_tlul_shim_tb top; + aes_tb top; // Init sim VerilatorSimCtrl &simctrl = VerilatorSimCtrl::GetInstance(); @@ -47,10 +46,10 @@ int main(int argc, char **argv) { VerilatorSimCtrlFlags::ResetPolarityNegative); // Create and register VerilatorSimCtrl extension - AesTlulShimTb aes_tlul_shim_tb(&top); - simctrl.RegisterExtension(&aes_tlul_shim_tb); + AesTb aes_tb(&top); + simctrl.RegisterExtension(&aes_tb); - std::cout << "Simulation of AES TLUL Shim" << std::endl + std::cout << "Simulation of AES Testbench" << std::endl << "=============================" << std::endl << std::endl; diff --git a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/data/gcm_k128_a0_d0.svh b/hw/ip/aes/pre_dv/aes_tb/data/gcm_k128_a0_d0.svh similarity index 99% rename from hw/ip/aes/pre_dv/aes_tlul_shim_tb/data/gcm_k128_a0_d0.svh rename to hw/ip/aes/pre_dv/aes_tb/data/gcm_k128_a0_d0.svh index 7ff46dc300284..eb9a680fd6add 100644 --- a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/data/gcm_k128_a0_d0.svh +++ b/hw/ip/aes/pre_dv/aes_tb/data/gcm_k128_a0_d0.svh @@ -10,7 +10,7 @@ `define DATA_LENGTH 0 `define NUM_REQUESTS 42 -`define REQUESTS shim_request_t requests[`NUM_REQUESTS] = '{ \ +`define REQUESTS bus_request_t requests[`NUM_REQUESTS] = '{ \ c_dpi_load('{ \ operation: AES_ENC, \ mode: AES_GCM, \ diff --git a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/data/gcm_k128_a0_d16.svh b/hw/ip/aes/pre_dv/aes_tb/data/gcm_k128_a0_d16.svh similarity index 99% rename from hw/ip/aes/pre_dv/aes_tlul_shim_tb/data/gcm_k128_a0_d16.svh rename to hw/ip/aes/pre_dv/aes_tb/data/gcm_k128_a0_d16.svh index 0ee6419e7c29d..3662a655d3daa 100644 --- a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/data/gcm_k128_a0_d16.svh +++ b/hw/ip/aes/pre_dv/aes_tb/data/gcm_k128_a0_d16.svh @@ -10,7 +10,7 @@ `define DATA_LENGTH 16 `define NUM_REQUESTS 55 -`define REQUESTS shim_request_t requests[`NUM_REQUESTS] = '{ \ +`define REQUESTS bus_request_t requests[`NUM_REQUESTS] = '{ \ c_dpi_load('{ \ operation: AES_ENC, \ mode: AES_GCM, \ diff --git a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/data/gcm_k128_a20_d60.svh b/hw/ip/aes/pre_dv/aes_tb/data/gcm_k128_a20_d60.svh similarity index 99% rename from hw/ip/aes/pre_dv/aes_tlul_shim_tb/data/gcm_k128_a20_d60.svh rename to hw/ip/aes/pre_dv/aes_tb/data/gcm_k128_a20_d60.svh index 2e657099a128a..1619ce659bd26 100644 --- a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/data/gcm_k128_a20_d60.svh +++ b/hw/ip/aes/pre_dv/aes_tb/data/gcm_k128_a20_d60.svh @@ -10,7 +10,7 @@ `define DATA_LENGTH 60 `define NUM_REQUESTS 370 -`define REQUESTS shim_request_t requests[`NUM_REQUESTS] = '{ \ +`define REQUESTS bus_request_t requests[`NUM_REQUESTS] = '{ \ \ /*****************************************************************************/ \ /** AES-GCM-128 Encryption **/ \ diff --git a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/data/gcm_k128_a20_d64.svh b/hw/ip/aes/pre_dv/aes_tb/data/gcm_k128_a20_d64.svh similarity index 99% rename from hw/ip/aes/pre_dv/aes_tlul_shim_tb/data/gcm_k128_a20_d64.svh rename to hw/ip/aes/pre_dv/aes_tb/data/gcm_k128_a20_d64.svh index 284bd341b0e97..642166d21b014 100644 --- a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/data/gcm_k128_a20_d64.svh +++ b/hw/ip/aes/pre_dv/aes_tb/data/gcm_k128_a20_d64.svh @@ -10,7 +10,7 @@ `define DATA_LENGTH 64 `define NUM_REQUESTS 110 -`define REQUESTS shim_request_t requests[`NUM_REQUESTS] = '{ \ +`define REQUESTS bus_request_t requests[`NUM_REQUESTS] = '{ \ c_dpi_load('{ \ operation: AES_ENC, \ mode: AES_GCM, \ diff --git a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/data/modes_d64.svh b/hw/ip/aes/pre_dv/aes_tb/data/modes_d64.svh similarity index 99% rename from hw/ip/aes/pre_dv/aes_tlul_shim_tb/data/modes_d64.svh rename to hw/ip/aes/pre_dv/aes_tb/data/modes_d64.svh index cded2f37b6380..1c63a3ecf832c 100644 --- a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/data/modes_d64.svh +++ b/hw/ip/aes/pre_dv/aes_tb/data/modes_d64.svh @@ -10,7 +10,7 @@ `define DATA_LENGTH 64 `define NUM_REQUESTS 1982 -`define REQUESTS shim_request_t requests[`NUM_REQUESTS] = '{ \ +`define REQUESTS bus_request_t requests[`NUM_REQUESTS] = '{ \ \ /*****************************************************************************/ \ /** AES-ECB-128 Encryption **/ \ diff --git a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/rtl/aes_tlul_shim_tb.sv b/hw/ip/aes/pre_dv/aes_tb/rtl/aes_tb.sv similarity index 59% rename from hw/ip/aes/pre_dv/aes_tlul_shim_tb/rtl/aes_tlul_shim_tb.sv rename to hw/ip/aes/pre_dv/aes_tb/rtl/aes_tb.sv index ca13ad301f8fc..57e1b46617691 100644 --- a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/rtl/aes_tlul_shim_tb.sv +++ b/hw/ip/aes/pre_dv/aes_tb/rtl/aes_tb.sv @@ -2,11 +2,11 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -module aes_tlul_shim_tb +module aes_tb import tlul_pkg::*; import aes_pkg::*; import aes_reg_pkg::*; - import aes_tlul_shim_tb_pkg::*; + import aes_tb_pkg::*; #( localparam bit AES192Enable = 1, @@ -18,7 +18,8 @@ module aes_tlul_shim_tb localparam bit SecSkipPRNGReseeding = 0, localparam bit EnableDataIntgGen = 1, localparam bit EnableRspDataIntgCheck = 1, - localparam bit DelayerEnable = 0 + localparam bit DelayerEnable = 0, + localparam bit ShimEnable = 1 ) ( input logic clk_i, input logic rst_ni, @@ -44,18 +45,18 @@ module aes_tlul_shim_tb end end - logic shim_done; - logic shim_pop; - shim_request_t shim_req; + logic bus_done; + logic bus_pop; + bus_request_t bus_req; - logic shim_hld; - logic shim_error; - logic [top_pkg::TL_DW-1:0] shim_rdata; + logic bus_wait; + logic bus_error; + logic [top_pkg::TL_DW-1:0] bus_rdata; logic error; logic c_dpi_data_error; logic c_dpi_tag_error; - assign error = shim_error | c_dpi_data_error | c_dpi_tag_error; + assign error = bus_error | c_dpi_data_error | c_dpi_tag_error; logic test_passed_q; logic test_done_q; @@ -63,7 +64,7 @@ module aes_tlul_shim_tb if (!rst_ni) begin test_passed_q <= 1'b1; test_done_q <= 1'b0; - end else if (shim_done || error) begin + end else if (bus_done || error) begin test_passed_q <= ~error; test_done_q <= 1'b1; end @@ -74,16 +75,16 @@ module aes_tlul_shim_tb // The AES block is run in automatic mode, which means the status register has to be polled in // order to check whether an operation has finished. A convenient side-effect of this is that it // will generate a large number of TLUL requests, which in combination with the delayer serves as - // a good stress test of the shim. + // a good stress test of the bus. // // Reads of the AES status registers are repeated (without popping a new request from the stack) - // until it matches the `shim_req.mask`. Such a stall can occur when the `IDLE` bit needs to be + // until it matches the `bus_req.mask`. Such a stall can occur when the `IDLE` bit needs to be // asserted before the computation can advance. logic poll; - assign poll = ~shim_hld - & (shim_req.addr == 32'(AES_STATUS_OFFSET)) - & ~|(shim_rdata & shim_req.mask); - assign shim_pop = (~shim_hld & ~poll) | ~shim_req.dv; + assign poll = ~bus_wait + & (bus_req.addr == 32'(AES_STATUS_OFFSET)) + & ~|(bus_rdata & bus_req.mask); + assign bus_pop = (~bus_wait & ~poll) | bus_req.c_dpi_load; aes_mode_e aes_mode_q; gcm_phase_e gcm_phase_q; @@ -91,47 +92,71 @@ module aes_tlul_shim_tb if (!rst_ni) begin gcm_phase_q <= '0; aes_mode_q <= '0; - end else if (~shim_req.dv) begin + end else if (bus_req.c_dpi_load) begin gcm_phase_q <= '0; - aes_mode_q <= shim_req.c_dpi_input.mode; - end else if (shim_req.addr == 32'(AES_CTRL_GCM_SHADOWED_OFFSET)) begin - gcm_phase_q <= shim_req.wdata[5:0]; + aes_mode_q <= bus_req.c_dpi_input.mode; + end else if (bus_req.addr == 32'(AES_CTRL_GCM_SHADOWED_OFFSET)) begin + gcm_phase_q <= bus_req.wdata[5:0]; end end - aes_tlul_shim_tb_reqs u_aes_tlul_shim_tb_reqs ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .pop_req_i ( shim_pop ), - .req_o ( shim_req ), - .done_o ( shim_done ) + aes_tb_reqs u_aes_tb_reqs ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .pop_req_i ( bus_pop ), + .req_o ( bus_req ), + .done_o ( bus_done ) ); - tlul_adapter_shim #( - .EnableDataIntgGen ( EnableDataIntgGen ), - .EnableRspDataIntgCheck ( EnableRspDataIntgCheck ) - ) u_tlul_adapter_shim ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .tl_i ( tl_d2h_delayed ), - .tl_o ( tl_h2d ), - .dv_i ( shim_req.dv ), - .addr_i ( shim_req.addr ), - .write_i ( shim_req.write ), - .wdata_i ( shim_req.wdata ), - .wstrb_i ( shim_req.wstrb ), - .size_i ( shim_req.size ), - .hld_o ( shim_hld ), - .rdata_o ( shim_rdata ), - .error_o ( shim_error ), - .last_i ( shim_req.last ), - .user_i ( shim_req.user ), - .id_i ( shim_req.id ) - ); + // Every request that is not a `c_dpi_load` counts as a valid bus access. + logic bus_en; + assign bus_en = ~bus_req.c_dpi_load; + + // The shim converts inputs from the valid-hold protocol into TLUL requests. + if (ShimEnable) begin : gen_tlul_adapter_shim + tlul_adapter_shim #( + .EnableDataIntgGen ( EnableDataIntgGen ), + .EnableRspDataIntgCheck ( EnableRspDataIntgCheck ) + ) u_tlul_adapter_shim ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .tl_i ( tl_d2h_delayed ), + .tl_o ( tl_h2d ), + .dv_i ( bus_en ), + .addr_i ( bus_req.addr ), + .write_i ( bus_req.write ), + .wdata_i ( bus_req.wdata ), + .wstrb_i ( 4'b1111 ), + .size_i ( 3'b010 ), + .hld_o ( bus_wait ), + .rdata_o ( bus_rdata ), + .error_o ( bus_error ), + .last_i ( 1'b0 ), + .user_i ( 32'(TL_A_USER_DEFAULT) ), + .id_i ( '0 ) + ); + end else begin : gen_tlul_adapter + tlul_adapter_tb_reqs #( + .EnableDataIntgGen ( EnableDataIntgGen ), + .EnableRspDataIntgCheck ( EnableRspDataIntgCheck ) + ) u_tlul_adapter_tb_reqs ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .tl_i ( tl_d2h_delayed ), + .tl_o ( tl_h2d ), + .en_i ( bus_en ), + .wait_o ( bus_wait ), + .addr_i ( bus_req.addr ), + .write_i ( bus_req.write ), + .wdata_i ( bus_req.wdata ), + .rdata_o ( bus_rdata ), + .error_o ( bus_error ) + ); + end - aes_tlul_shim_delayer #( + tlul_delayer #( .DelayerEnable ( DelayerEnable ) - ) u_aes_tlul_shim_delayer ( + ) u_tlul_delayer ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .tl_h2d_i ( tl_h2d ), @@ -177,10 +202,10 @@ module aes_tlul_shim_tb logic check_data; logic check_tag; - assign check_out = ~shim_hld && (shim_req.addr == 32'(AES_DATA_OUT_0_OFFSET) || - shim_req.addr == 32'(AES_DATA_OUT_1_OFFSET) || - shim_req.addr == 32'(AES_DATA_OUT_2_OFFSET) || - shim_req.addr == 32'(AES_DATA_OUT_3_OFFSET)) ? 1'b1 : 1'b0; + assign check_out = ~bus_wait && (bus_req.addr == 32'(AES_DATA_OUT_0_OFFSET) || + bus_req.addr == 32'(AES_DATA_OUT_1_OFFSET) || + bus_req.addr == 32'(AES_DATA_OUT_2_OFFSET) || + bus_req.addr == 32'(AES_DATA_OUT_3_OFFSET)) ? 1'b1 : 1'b0; assign check_data = check_out && (aes_mode_q != AES_GCM || gcm_phase_q == GCM_TEXT) ? 1'b1 : 1'b0; assign check_tag = check_out && (gcm_phase_q == GCM_TAG) ? 1'b1 : 1'b0; @@ -189,11 +214,11 @@ module aes_tlul_shim_tb // correctness with the `c_dpi` model. We do this by initializing a counter to the number of data // bytes and decrementing it whenever 32 data bits from the AES block arrive. The value of the // counter steers a mask that is applied to both the AES block and the `c_dpi` model block. The - // counter is reset for every `c_dpi_load` request, i.e., shim_req.dv = 0. + // counter is reset for every `c_dpi_load`. int data_cntr_d, data_cntr_q; - assign data_cntr_d = ~shim_req.dv ? `DATA_LENGTH : - check_data ? (data_cntr_q >= 4 ? data_cntr_q - 4 : 0) : data_cntr_q; + assign data_cntr_d = bus_req.c_dpi_load ? `DATA_LENGTH : + check_data ? (data_cntr_q >= 4 ? data_cntr_q - 4 : 0) : data_cntr_q; always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin @@ -210,23 +235,23 @@ module aes_tlul_shim_tb data_cntr_q == 1 ? 32'h0000_00ff : '0; logic [31:0] c_dpi_data, c_dpi_tag; - aes_tlul_shim_tb_c_dpi #( + aes_tb_c_dpi #( .ADLength ( `AD_LENGTH ), .DataLength ( `DATA_LENGTH ) - ) u_aes_tlul_shim_tb_c_dpi ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .c_dpi_input_i ( shim_req.c_dpi_input ), - .c_dpi_load_i ( ~shim_req.dv ), - .c_dpi_rotate_data_i ( check_data ), - .c_dpi_rotate_tag_i ( check_tag ), - .c_dpi_data_o ( c_dpi_data ), - .c_dpi_tag_o ( c_dpi_tag ) + ) u_aes_tb_c_dpi ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .c_dpi_input_i ( bus_req.c_dpi_input ), + .c_dpi_load_i ( bus_req.c_dpi_load ), + .c_dpi_rotate_data_i ( check_data ), + .c_dpi_rotate_tag_i ( check_tag ), + .c_dpi_data_o ( c_dpi_data ), + .c_dpi_tag_o ( c_dpi_tag ) ); assign c_dpi_data_error = check_data && - (c_dpi_data & data_mask) != (shim_rdata & data_mask) ? 1'b1 : 1'b0; - assign c_dpi_tag_error = check_tag && (c_dpi_tag != shim_rdata) ? 1'b1 : 1'b0; + (c_dpi_data & data_mask) != (bus_rdata & data_mask) ? 1'b1 : 1'b0; + assign c_dpi_tag_error = check_tag && (c_dpi_tag != bus_rdata) ? 1'b1 : 1'b0; // We do not care about alerts in this testbench. Set them to constant values. prim_alert_pkg::alert_rx_t [NumAlerts-1:0] alert_rx; diff --git a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/rtl/aes_tlul_shim_tb_c_dpi.sv b/hw/ip/aes/pre_dv/aes_tb/rtl/aes_tb_c_dpi.sv similarity index 98% rename from hw/ip/aes/pre_dv/aes_tlul_shim_tb/rtl/aes_tlul_shim_tb_c_dpi.sv rename to hw/ip/aes/pre_dv/aes_tb/rtl/aes_tb_c_dpi.sv index e1f5dc90c195d..661e7239dcb72 100644 --- a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/rtl/aes_tlul_shim_tb_c_dpi.sv +++ b/hw/ip/aes/pre_dv/aes_tb/rtl/aes_tb_c_dpi.sv @@ -7,9 +7,9 @@ // bits of data and tag become visible at the module's output ports in the next clock cycle. The // flopped data and tag can be rotated by 32 positions to the right to make other bits visible. -module aes_tlul_shim_tb_c_dpi +module aes_tb_c_dpi import aes_pkg::*; - import aes_tlul_shim_tb_pkg::*; + import aes_tb_pkg::*; import aes_model_dpi_pkg::*; #( parameter int ADLength = 0, diff --git a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/rtl/aes_tlul_shim_tb_pkg.sv b/hw/ip/aes/pre_dv/aes_tb/rtl/aes_tb_pkg.sv similarity index 60% rename from hw/ip/aes/pre_dv/aes_tlul_shim_tb/rtl/aes_tlul_shim_tb_pkg.sv rename to hw/ip/aes/pre_dv/aes_tb/rtl/aes_tb_pkg.sv index 1f7178e41b3bf..e79da4420b22f 100644 --- a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/rtl/aes_tlul_shim_tb_pkg.sv +++ b/hw/ip/aes/pre_dv/aes_tb/rtl/aes_tb_pkg.sv @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -package aes_tlul_shim_tb_pkg; +package aes_tb_pkg; import tlul_pkg::*; import aes_pkg::*; @@ -53,79 +53,74 @@ package aes_tlul_shim_tb_pkg; logic [127:0] tag; // Only used in the GCM decryption case. } c_dpi_input_t; - // Grouping of all signals required for a shim read/write request and to instrument the `c_dpi` - // API. + // Grouping of all signals required for a TLUL/shim read/write request and to instrument the + // `c_dpi` API. typedef struct packed { - logic dv; - logic [top_pkg::TL_AW-1:0] addr; - logic write; - logic [top_pkg::TL_DW-1:0] wdata; - logic [top_pkg::TL_DBW-1:0] wstrb; - logic [2:0] size; - logic last; - logic [31:0] user; - logic [top_pkg::TL_AIW-1:0] id; - - // Internal signal to verify status bits. + logic write; + logic [top_pkg::TL_AW-1:0] addr; + logic [top_pkg::TL_DW-1:0] wdata; + + // Internal signal: The request is a `c_dpi` invocation instead of a TLUL/shim request. + logic c_dpi_load; + + // Internal signal: To mask read request responses, e.g., to check whether a certain bit is set. logic [top_pkg::TL_DW-1:0] mask; // Internal signal: AD and PT inputs to the `c_dpi` model. c_dpi_input_t c_dpi_input; - } shim_request_t; + } bus_request_t; - // write_request returns a filled out `shim_request_t` struct for a shim write request. - function automatic shim_request_t write_request (logic [7:0] addr, - logic [top_pkg::TL_DW-1:0] wdata); - shim_request_t req = '{ - dv: 1'b1, - addr: {24'b0, addr}, + // write_request returns a filled out `bus_request_t` struct for a TLUL/shim write request. + function automatic bus_request_t write_request (logic [7:0] addr, + logic [top_pkg::TL_DW-1:0] wdata); + bus_request_t req = '{ + c_dpi_load: 1'b0, write: 1'b1, + addr: {24'b0, addr}, wdata: wdata, - wstrb: top_pkg::TL_DBW'(4'b1111), - size: 3'b010, - last: 1'b0, - user: 32'(TL_A_USER_DEFAULT), - id: '{default: '0}, - mask: '{default: '0}, + mask: '0, c_dpi_input: '0 }; return req; endfunction - // read_request returns a filled out `shim_request_t` struct for a shim read request. - function automatic shim_request_t read_request (logic [7:0] addr, - logic [top_pkg::TL_DW-1:0] mask = '0); - shim_request_t req = '{ - dv: 1'b1, - addr: 32'(addr), + // read_request returns a filled out `bus_request_t` struct for a TLUL/shim read request. + function automatic bus_request_t read_request (logic [7:0] addr, + logic [top_pkg::TL_DW-1:0] mask = '0); + bus_request_t req = '{ + c_dpi_load: 1'b0, write: 1'b0, - wdata: '{default: '0}, - wstrb: top_pkg::TL_DBW'(4'b1111), - size: 3'b010, - last: 1'b0, - user: 32'(TL_A_USER_DEFAULT), - id: '{default: '0}, + addr: {24'b0, addr}, + wdata: '0, mask: mask, c_dpi_input: '0 }; return req; endfunction - // read_caliptra returns a filled out `shim_request_t` struct for an internal Caliptra register. - function automatic shim_request_t read_caliptra (logic [11:0] addr); - shim_request_t req = '{ - dv: 1'b1, - addr: 32'(addr), - default: '0 + // read_caliptra returns a filled out `bus_request_t` struct for an internal Caliptra register. + // This is only useful if a TLUL-to-Shim adapter is configured otherwise the request will result + // in a zero-value being returned by the register file. + function automatic bus_request_t read_caliptra (logic [11:0] addr); + bus_request_t req = '{ + c_dpi_load: 1'b0, + write: 1'b0, + addr: {20'b0, addr}, + wdata: '0, + mask: '0, + c_dpi_input: '0 }; return req; endfunction - // c_dpi_load assigns a `c_dpi_input_t` to an empty `shim_request_t` struct. This type of + // c_dpi_load assigns a `c_dpi_input_t` to an empty `bus_request_t` struct. This type of // request is used to instrument the `c_dpi` API at the beginning of a test. - function automatic shim_request_t c_dpi_load (c_dpi_input_t c_dpi_input); - shim_request_t req = '0; - req.c_dpi_input = c_dpi_input; + function automatic bus_request_t c_dpi_load (c_dpi_input_t c_dpi_input); + bus_request_t req = '{ + c_dpi_load: 1'b1, + c_dpi_input: c_dpi_input, + default: '0 + }; return req; endfunction diff --git a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/rtl/aes_tlul_shim_tb_reqs.sv b/hw/ip/aes/pre_dv/aes_tb/rtl/aes_tb_reqs.sv similarity index 62% rename from hw/ip/aes/pre_dv/aes_tlul_shim_tb/rtl/aes_tlul_shim_tb_reqs.sv rename to hw/ip/aes/pre_dv/aes_tb/rtl/aes_tb_reqs.sv index 9a8595ab1e3b2..e60b9e7de2d20 100644 --- a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/rtl/aes_tlul_shim_tb_reqs.sv +++ b/hw/ip/aes/pre_dv/aes_tb/rtl/aes_tb_reqs.sv @@ -2,19 +2,18 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -module aes_tlul_shim_tb_reqs +module aes_tb_reqs import aes_pkg::*; import aes_reg_pkg::*; import tlul_pkg::*; - import aes_tlul_shim_tb_pkg::*; + import aes_tb_pkg::*; ( input logic clk_i, input logic rst_ni, input logic pop_req_i, - output shim_request_t req_o, - //output c_dpi_input_t c_dpi_input_o, + output bus_request_t req_o, output logic done_o ); @@ -27,16 +26,7 @@ module aes_tlul_shim_tb_reqs end end - always_comb begin - if (request_cntr_q < `NUM_REQUESTS) begin - req_o = requests[request_cntr_q]; - //c_dpi_input_o = requests[request_cntr_q].c_dpi_input; - end else begin - req_o = '0; - //c_dpi_input_o = '0; - end - end - + assign req_o = (request_cntr_q < `NUM_REQUESTS) ? requests[request_cntr_q] : '0; assign done_o = (request_cntr_q >= `NUM_REQUESTS) ? 1'b1 : 1'b0; endmodule diff --git a/hw/ip/aes/pre_dv/aes_tb/rtl/tlul_adapter_tb_reqs.sv b/hw/ip/aes/pre_dv/aes_tb/rtl/tlul_adapter_tb_reqs.sv new file mode 100644 index 0000000000000..fe70b4f959c68 --- /dev/null +++ b/hw/ip/aes/pre_dv/aes_tb/rtl/tlul_adapter_tb_reqs.sv @@ -0,0 +1,90 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Adapter that translates generic read/write requests into valid TLUL equivalents. + +`include "prim_assert.sv" + +module tlul_adapter_tb_reqs + import tlul_pkg::*; +#( + parameter bit EnableDataIntgGen = 1, + parameter bit EnableRspDataIntgCheck = 1 +) ( + input clk_i, + input rst_ni, + + output tl_h2d_t tl_o, + input tl_d2h_t tl_i, + + // A valid request is indicated with `en_i` and is acknowledged once `wait_o` is unset. + input logic en_i, + output logic wait_o, + + // Generic read/write request. + input logic [top_pkg::TL_AW-1:0] addr_i, + input logic write_i, + input logic [top_pkg::TL_DW-1:0] wdata_i, + output logic [top_pkg::TL_DW-1:0] rdata_o, + output logic error_o +); + + // Differentiate between two levels of acknowledgements: + // - `req_ack`: A host-to-device request is acknowledged by the device, + // meaning that the response is pending. + // - `resp_ack`: The device-to-host response is acknowledged. + logic pending_d, pending_q; + logic req_ack, resp_ack; + + assign req_ack = en_i & tl_i.a_ready & tl_o.a_valid; + assign resp_ack = en_i & tl_o.d_ready & tl_i.d_valid; + + assign pending_d = req_ack ? 1'b1 : + resp_ack ? 1'b0 : pending_q; + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + pending_q <= 1'b0; + end else begin + pending_q <= pending_d; + end + end + + // Only make a new request (through `a_valid`) to the device when none are + // pending. If the integrity checks are enabled, the `a_user` fields will be + // set by the corresponding module (see `tlul_cmd_intg_gen`). + tlul_pkg::tl_h2d_t tl_o_pre; + assign tl_o_pre = '{ + a_valid: en_i & ~pending_q, + a_opcode: ~write_i ? Get : PutFullData, + a_size: 2'b10, + a_mask: 4'b1111, + a_source: '0, + a_address:addr_i, + a_data: wdata_i, + a_user: TL_A_USER_DEFAULT, + d_ready: 1'b1, + a_param: 3'h0 + }; + + assign wait_o = pending_q && tl_o.d_ready && tl_i.d_valid ? 1'b0 : 1'b1; + assign rdata_o = tl_i.d_data; + assign error_o = tl_i.d_error | intg_err_chk; + + tlul_cmd_intg_gen #( + .EnableDataIntgGen (EnableDataIntgGen) + ) u_cmd_intg_gen ( + .tl_i ( tl_o_pre ), + .tl_o ( tl_o ) + ); + + logic intg_err_chk; + tlul_rsp_intg_chk #( + .EnableRspDataIntgCheck(EnableRspDataIntgCheck) + ) u_rsp_chk ( + .tl_i ( tl_i ), + .err_o ( intg_err_chk ) + ); + +endmodule diff --git a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/rtl/aes_tlul_shim_delayer.sv b/hw/ip/aes/pre_dv/aes_tb/rtl/tlul_delayer.sv similarity index 99% rename from hw/ip/aes/pre_dv/aes_tlul_shim_tb/rtl/aes_tlul_shim_delayer.sv rename to hw/ip/aes/pre_dv/aes_tb/rtl/tlul_delayer.sv index 6fcc31d701147..7e8fcba7d232a 100644 --- a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/rtl/aes_tlul_shim_delayer.sv +++ b/hw/ip/aes/pre_dv/aes_tb/rtl/tlul_delayer.sv @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -module aes_tlul_shim_delayer +module tlul_delayer import tlul_pkg::*; #( parameter bit DelayerEnable = 1 diff --git a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/README.md b/hw/ip/aes/pre_dv/aes_tlul_shim_tb/README.md deleted file mode 100644 index a0179d0bf362d..0000000000000 --- a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# TLUL/Shim Verilator Testbench - -This directory contains the Verilator testbench for the TLUL shim adapter that is attached to the AES IP block. -Out of the box, the testbench contains test vectors for most of the salient use cases, nonetheless extending the testbench with further tests is straightforward as detailed below. - -## Current Test Vectors - -The `./data` directory contains an array of `.svh` files each of them containing a single set of input stimuli that constitute a test: - -``` -data -├── gcm_k128_a0_d0.svh # AES-GCM-128 Encryption; 0 AD Bytes; 0 Msg Bytes -├── gcm_k128_a0_d16.svh # AES-GCM-128 Encryption; 0 AD Bytes; 16 Msg Bytes -├── gcm_k128_a20_d60.svh # AES-GCM-128 Encryption/Decryption/Save/Restore; 20 AD Bytes; 60 Msg Bytes -├── gcm_k128_a20_d64.svh # AES-GCM-128 Encryption; 20 AD Bytes; 64 Msg Bytes -└── modes_d64.svh # AES-{128,192,256}-{ECB,CBC,OFB,CFB,CTR} Encryption/Decryption -``` - -### Adding/Modifying Tests - -Each test vector file `./data/*.svh` starts with a preamble that instruments both the testbench RTL as well as the `c_dpi` model: - -```systemverilog -`define AD_LENGTH // Number of AD bytes -`define MSG_LENGTH // Number of Msg bytes -`define NUM_REQUESTS // Total number of requests -``` - -Here, `NUM_REQUESTS` denotes the number of `read_request`, `write_request` and `c_dpi_load` invocations within the file. -Having written a new test vector file, the `fusesoc` configuration needs to be made aware of it. - -1. Add the `.svh` filename to the list of RTL files under `files_rtl/files`. -2. Add the `.svh` filename to the `DREQUESTS_FILE` Verilator variable under `verilator/verilator_options`. - -## Building and Running the Verilator Testbench - -To build the testbench, execute from the OpenTitan top level: - -```sh -fusesoc --cores-root=. --verbose run --setup --build lowrisc:dv_verilator:aes_tlul_shim_tb -``` -To execute the obtained Verilator binary and with trace generation, run: - -```sh -./build/lowrisc_dv_verilator_aes_tlul_shim_tb_0/default-verilator/Vaes_tlul_shim_tb --trace -``` - -## Details of the testbench - -- cpp/aes\_tlul\_shim\_tb.cc: contains main function and instantiation of SimCtrl -- rtl/aes\_tlul\_shim\_tb.sv: contains the testbench logic -- rtl/aes\_tlul\_delayer\_tb.sv: contains an optional delayer module to artificially induce random delays between the Shim and the TLUL bus. -- rtl/aes\_tlul\_shim\_tb_reqs.sv: contains requests (stimuli) that are fed to the testbench. -- rtl/aes\_tlul\_shim\_tb_pkg.sv: contains common parameters and functions. -- data/*: contains test vector files. diff --git a/hw/ip/aes/pre_dv/aes_tlul_shim_tb/README.md b/hw/ip/aes/pre_dv/aes_tlul_shim_tb/README.md new file mode 120000 index 0000000000000..b96d94ab71714 --- /dev/null +++ b/hw/ip/aes/pre_dv/aes_tlul_shim_tb/README.md @@ -0,0 +1 @@ +../aes_tb/README.md \ No newline at end of file