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 00000000000000..989df885072277 --- /dev/null +++ b/hw/ip/aes/pre_dv/aes_tb/README.md @@ -0,0 +1,55 @@ +# 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 f701a10a2e2925..b3fdffa07ffef3 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 eacce2b6b84c18..d1f0917a90633b 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 7ff46dc300284d..eb9a680fd6adda 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 0ee6419e7c29de..3662a655d3daa7 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 2e657099a128ae..1619ce659bd26e 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 284bd341b0e97f..642166d21b014f 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 cded2f37b63802..1c63a3ecf832c3 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 ca13ad301f8fca..57e1b466176913 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 e1f5dc90c195db..661e7239dcb72a 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 1f7178e41b3bfc..e79da4420b22f9 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 9a8595ab1e3b28..e60b9e7de2d208 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 00000000000000..fe70b4f959c681 --- /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 6fcc31d7011473..7e8fcba7d232a6 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 a0179d0bf362da..00000000000000 --- 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 00000000000000..c33ebf62398577 --- /dev/null +++ b/hw/ip/aes/pre_dv/aes_tlul_shim_tb/README.md @@ -0,0 +1 @@ +/home/andrea/opentitan/hw/ip/aes/pre_dv/aes_tb/README.md \ No newline at end of file