From ab66def6cc79c5cde6aba1d65d6ef9cdc4c14522 Mon Sep 17 00:00:00 2001 From: Pascal Nasahl Date: Mon, 6 May 2024 08:03:39 +0000 Subject: [PATCH] [sram_ctrl] Add readback feature When enabled with the SRAM_CTRL.READBACK CSR, the SRAM readback mode checks each read and write to the SRAM. On a read, the readback mode issues a second read to the same address to check, whether the correct data was fetched from memory. On a write, the readback mode issues a read to check, whether the data was actually written into the memory. To avoid that the holding register is read, the readback is delayed by one cycle. On a mismatch, a fatal error is triggered and the STATUS.READBACK_ERROR register is set. To avoid RTL changes as much as possible, the readback mode is implemented in the tlul_sram_byte module. In this module, after the initial read or write was executed, the bus interface to the host is stalled and the readback is performed. Due to the bus stalling, a performance impact is expected. Signed-off-by: Pascal Nasahl Co-authored-by: Greg Chadwick --- doc/contributing/hw/comportability/README.md | 1 + hw/dv/sv/sim_sram/sim_sram.sv | 24 +- hw/ip/hmac/rtl/hmac.sv | 35 +- hw/ip/kmac/rtl/kmac.sv | 36 +- hw/ip/kmac/rtl/kmac_staterd.sv | 30 +- hw/ip/otbn/dv/verilator/otbn_top_sim.sv | 86 +-- hw/ip/otbn/rtl/otbn.sv | 86 +-- hw/ip/otp_ctrl/rtl/otp_ctrl.sv | 34 +- hw/ip/prim/rtl/prim_ram_1p_scr.sv | 14 +- hw/ip/rom_ctrl/rtl/rom_ctrl.sv | 34 +- hw/ip/spi_device/rtl/spi_device.sv | 68 +-- hw/ip/spi_host/rtl/spi_host_window.sv | 6 +- hw/ip/sram_ctrl/README.md | 1 + hw/ip/sram_ctrl/data/sram_ctrl.hjson | 47 ++ .../data/sram_ctrl_sec_cm_testplan.hjson | 9 + hw/ip/sram_ctrl/doc/interfaces.md | 1 + hw/ip/sram_ctrl/doc/registers.md | 54 +- .../dv/env/seq_lib/sram_ctrl_base_vseq.sv | 38 ++ .../sram_ctrl/dv/env/sram_ctrl_scoreboard.sv | 3 + hw/ip/sram_ctrl/rtl/sram_ctrl.sv | 103 ++-- hw/ip/sram_ctrl/rtl/sram_ctrl_pkg.sv | 2 - hw/ip/sram_ctrl/rtl/sram_ctrl_reg_pkg.sv | 50 +- hw/ip/sram_ctrl/rtl/sram_ctrl_regs_reg_top.sv | 124 ++++- hw/ip/tlul/README.md | 6 + hw/ip/tlul/rtl/tlul_adapter_sram.sv | 41 +- hw/ip/tlul/rtl/tlul_sram_byte.sv | 501 ++++++++++++++++-- hw/ip/usbdev/rtl/usbdev.sv | 34 +- .../flash_ctrl/rtl/flash_ctrl.sv.tpl | 102 ++-- .../data/autogen/top_earlgrey.gen.hjson | 4 +- .../dv/autogen/xbar_env_pkg__params.sv | 4 +- hw/top_earlgrey/dv/autogen/xbar_tgl_excl.cfg | 4 +- .../data/autogen/xbar_main.gen.hjson | 2 +- .../ip/xbar_main/dv/autogen/xbar_cover.cfg | 2 +- .../dv/autogen/xbar_env_pkg__params.sv | 2 +- .../ip/xbar_main/rtl/autogen/tl_main_pkg.sv | 2 +- .../data/autogen/xbar_peri.gen.hjson | 2 +- .../ip/xbar_peri/dv/autogen/xbar_cover.cfg | 2 +- .../dv/autogen/xbar_env_pkg__params.sv | 2 +- .../ip/xbar_peri/rtl/autogen/tl_peri_pkg.sv | 2 +- .../ip_autogen/flash_ctrl/rtl/flash_ctrl.sv | 102 ++-- .../rtl/autogen/top_earlgrey_pkg.sv | 4 +- .../sw/autogen/chip/top_earlgrey.rs | 4 +- hw/top_earlgrey/sw/autogen/top_earlgrey.h | 4 +- .../sw/autogen/top_earlgrey_memory.h | 4 +- hw/vendor/lowrisc_ibex.vendor.hjson | 6 +- hw/vendor/lowrisc_ibex/rtl/ibex_top.sv | 76 +-- ...rtl-Add-new-ports-to-prim-ram-1p-scr.patch | 106 ++++ util/reggen/countermeasure.py | 1 + 48 files changed, 1426 insertions(+), 479 deletions(-) create mode 100644 hw/vendor/patches/lowrisc_ibex/rtl/0001-rtl-Add-new-ports-to-prim-ram-1p-scr.patch diff --git a/doc/contributing/hw/comportability/README.md b/doc/contributing/hw/comportability/README.md index f050711aceb96..e555f4a115789 100644 --- a/doc/contributing/hw/comportability/README.md +++ b/doc/contributing/hw/comportability/README.md @@ -300,6 +300,7 @@ The following standardised countermeasures are defined: | REGREN | A register write enable is used to protect the asset from read access | CONFIG, MEM | SCRAMBLE | The asset is scrambled | CONFIG, MEM | INTEGRITY | The asset has integrity protection from a computed value such as a checksum | CONFIG, REG, MEM +| READBACK | A readback check is performed to validate that the asset has been correctly modified or fetched | MEM | CONSISTENCY | This asset is checked for consistency other than by associating integrity bits | CTRL, RST | DIGEST | Similar to integrity but more computationally intensive, implying a full hash function | CONFIG, REG, MEM | LC_GATED | Access to the asset is qualified by life-cycle state | REG, MEM, CONSTANTS, CONFIG diff --git a/hw/dv/sv/sim_sram/sim_sram.sv b/hw/dv/sv/sim_sram/sim_sram.sv index 5b8e15ba22263..20d3556ebd6bb 100644 --- a/hw/dv/sv/sim_sram/sim_sram.sv +++ b/hw/dv/sv/sim_sram/sim_sram.sv @@ -71,16 +71,20 @@ module sim_sram #( .tl_i(tl_in_i), .tl_o(tl_in_o), - .req_o (sram_req), - .gnt_i (1'b1), - .we_o (sram_we), - .addr_o (sram_addr), - .wdata_o (sram_wdata), - .wmask_o (sram_wmask), - .rdata_i (sram_rdata), - .rvalid_i (sram_rvalid), - .rerror_i (2'b00), - .rmw_in_progress_o() + .req_o (sram_req), + .gnt_i (1'b1), + .we_o (sram_we), + .addr_o (sram_addr), + .wdata_o (sram_wdata), + .wmask_o (sram_wmask), + .rdata_i (sram_rdata), + .rvalid_i (sram_rvalid), + .rerror_i (2'b00), + .compound_txn_in_progress_o (), + .readback_en_i (prim_mubi_pkg::MuBi4False), + .readback_error_o (), + .wr_collision_i (1'b0), + .write_pending_i (1'b0) ); prim_ram_1p #( diff --git a/hw/ip/hmac/rtl/hmac.sv b/hw/ip/hmac/rtl/hmac.sv index 6f41fbdf4a4d8..70e7121ecde4b 100644 --- a/hw/ip/hmac/rtl/hmac.sv +++ b/hw/ip/hmac/rtl/hmac.sv @@ -569,21 +569,26 @@ module hmac ) u_tlul_adapter ( .clk_i, .rst_ni, - .tl_i (tl_win_h2d), - .tl_o (tl_win_d2h), - .en_ifetch_i (prim_mubi_pkg::MuBi4False), - .req_o (msg_fifo_req ), - .req_type_o ( ), - .gnt_i (msg_fifo_gnt ), - .we_o (msg_fifo_we ), - .addr_o ( ), // Doesn't care the address other than sub-word - .wdata_o (msg_fifo_wdata ), - .wmask_o (msg_fifo_wmask ), - .intg_error_o ( ), - .rdata_i (msg_fifo_rdata ), - .rvalid_i (msg_fifo_rvalid), - .rerror_i (msg_fifo_rerror), - .rmw_in_progress_o() + .tl_i (tl_win_h2d), + .tl_o (tl_win_d2h), + .en_ifetch_i (prim_mubi_pkg::MuBi4False), + .req_o (msg_fifo_req ), + .req_type_o ( ), + .gnt_i (msg_fifo_gnt ), + .we_o (msg_fifo_we ), + .addr_o ( ), // Doesn't care the address + // other than sub-word + .wdata_o (msg_fifo_wdata ), + .wmask_o (msg_fifo_wmask ), + .intg_error_o ( ), + .rdata_i (msg_fifo_rdata ), + .rvalid_i (msg_fifo_rvalid), + .rerror_i (msg_fifo_rerror), + .compound_txn_in_progress_o (), + .readback_en_i (prim_mubi_pkg::MuBi4False), + .readback_error_o (), + .wr_collision_i (1'b0), + .write_pending_i (1'b0) ); // TL-UL to MSG_FIFO byte write handling diff --git a/hw/ip/kmac/rtl/kmac.sv b/hw/ip/kmac/rtl/kmac.sv index 43a276b8f3d43..4cb66e85717d7 100644 --- a/hw/ip/kmac/rtl/kmac.sv +++ b/hw/ip/kmac/rtl/kmac.sv @@ -1004,22 +1004,26 @@ module kmac ) u_tlul_adapter_msgfifo ( .clk_i, .rst_ni, - .en_ifetch_i (prim_mubi_pkg::MuBi4False), - .tl_i (tl_win_h2d[WinMsgFifo]), - .tl_o (tl_win_d2h[WinMsgFifo]), - - .req_o (tlram_req), - .req_type_o (), - .gnt_i (tlram_gnt), - .we_o (tlram_we ), - .addr_o (tlram_addr), - .wdata_o (tlram_wdata), - .wmask_o (tlram_wmask), - .intg_error_o ( ), - .rdata_i (tlram_rdata), - .rvalid_i (tlram_rvalid), - .rerror_i (tlram_rerror), - .rmw_in_progress_o() + .en_ifetch_i (prim_mubi_pkg::MuBi4False), + .tl_i (tl_win_h2d[WinMsgFifo]), + .tl_o (tl_win_d2h[WinMsgFifo]), + + .req_o (tlram_req), + .req_type_o (), + .gnt_i (tlram_gnt), + .we_o (tlram_we ), + .addr_o (tlram_addr), + .wdata_o (tlram_wdata), + .wmask_o (tlram_wmask), + .intg_error_o ( ), + .rdata_i (tlram_rdata), + .rvalid_i (tlram_rvalid), + .rerror_i (tlram_rerror), + .compound_txn_in_progress_o (), + .readback_en_i (prim_mubi_pkg::MuBi4False), + .readback_error_o (), + .wr_collision_i (1'b0), + .write_pending_i (1'b0) ); assign sw_msg_valid = tlram_req & tlram_we ; diff --git a/hw/ip/kmac/rtl/kmac_staterd.sv b/hw/ip/kmac/rtl/kmac_staterd.sv index 4b9d011bb8e48..f145aea82f96e 100644 --- a/hw/ip/kmac/rtl/kmac_staterd.sv +++ b/hw/ip/kmac/rtl/kmac_staterd.sv @@ -64,19 +64,23 @@ module kmac_staterd .tl_i, .tl_o, - .en_ifetch_i (prim_mubi_pkg::MuBi4False), - .req_o (tlram_req), - .req_type_o (), - .gnt_i (tlram_gnt), - .we_o (tlram_we ), - .addr_o (tlram_addr), - .wdata_o (unused_tlram_wdata), - .wmask_o (unused_tlram_wmask), - .intg_error_o (), - .rdata_i (tlram_rdata), - .rvalid_i (tlram_rvalid), - .rerror_i (tlram_rerror), - .rmw_in_progress_o() + .en_ifetch_i (prim_mubi_pkg::MuBi4False), + .req_o (tlram_req), + .req_type_o (), + .gnt_i (tlram_gnt), + .we_o (tlram_we ), + .addr_o (tlram_addr), + .wdata_o (unused_tlram_wdata), + .wmask_o (unused_tlram_wmask), + .intg_error_o (), + .rdata_i (tlram_rdata), + .rvalid_i (tlram_rvalid), + .rerror_i (tlram_rerror), + .compound_txn_in_progress_o (), + .readback_en_i (prim_mubi_pkg::MuBi4False), + .readback_error_o (), + .wr_collision_i (1'b0), + .write_pending_i (1'b0) ); always_ff @(posedge clk_i or negedge rst_ni) begin diff --git a/hw/ip/otbn/dv/verilator/otbn_top_sim.sv b/hw/ip/otbn/dv/verilator/otbn_top_sim.sv index 18b09e38ba797..394610a6c827d 100644 --- a/hw/ip/otbn/dv/verilator/otbn_top_sim.sv +++ b/hw/ip/otbn/dv/verilator/otbn_top_sim.sv @@ -256,26 +256,29 @@ module otbn_top_sim ( .EnableParity ( 0 ), .ReplicateKeyStream ( 1 ) ) u_dmem ( - .clk_i ( IO_CLK ), - .rst_ni ( IO_RST_N ), - - .key_valid_i ( 1'b1 ), - .key_i ( TestScrambleKey ), - .nonce_i ( TestScrambleNonce ), - - .req_i ( dmem_req ), - .gnt_o ( ), - .write_i ( dmem_write ), - .addr_i ( dmem_index ), - .wdata_i ( dmem_wdata ), - .wmask_i ( dmem_wmask ), - .intg_error_i ( 1'b0 ), - - .rdata_o ( dmem_rdata ), - .rvalid_o ( dmem_rvalid ), - .raddr_o ( ), - .rerror_o ( ), - .cfg_i ( '0 ) + .clk_i ( IO_CLK ), + .rst_ni ( IO_RST_N ), + + .key_valid_i ( 1'b1 ), + .key_i ( TestScrambleKey ), + .nonce_i ( TestScrambleNonce ), + + .req_i ( dmem_req ), + .gnt_o ( ), + .write_i ( dmem_write ), + .addr_i ( dmem_index ), + .wdata_i ( dmem_wdata ), + .wmask_i ( dmem_wmask ), + .intg_error_i ( 1'b0 ), + + .rdata_o ( dmem_rdata ), + .rvalid_o ( dmem_rvalid ), + .raddr_o ( ), + .rerror_o ( ), + .cfg_i ( '0 ), + + .wr_collision_o ( ), + .write_pending_o ( ) ); // No integrity errors in Verilator testbench @@ -296,26 +299,29 @@ module otbn_top_sim ( .DataBitsPerMask ( 39 ), .EnableParity ( 0 ) ) u_imem ( - .clk_i ( IO_CLK ), - .rst_ni ( IO_RST_N ), - - .key_valid_i ( 1'b1 ), - .key_i ( TestScrambleKey ), - .nonce_i ( TestScrambleNonce ), - - .req_i ( imem_req ), - .gnt_o ( ), - .write_i ( 1'b0 ), - .addr_i ( imem_index ), - .wdata_i ( '0 ), - .wmask_i ( '0 ), - .intg_error_i ( 1'b0 ), - - .rdata_o ( imem_rdata ), - .rvalid_o ( imem_rvalid ), - .raddr_o ( ), - .rerror_o ( ), - .cfg_i ( '0 ) + .clk_i ( IO_CLK ), + .rst_ni ( IO_RST_N ), + + .key_valid_i ( 1'b1 ), + .key_i ( TestScrambleKey ), + .nonce_i ( TestScrambleNonce ), + + .req_i ( imem_req ), + .gnt_o ( ), + .write_i ( 1'b0 ), + .addr_i ( imem_index ), + .wdata_i ( '0 ), + .wmask_i ( '0 ), + .intg_error_i ( 1'b0 ), + + .rdata_o ( imem_rdata ), + .rvalid_o ( imem_rvalid ), + .raddr_o ( ), + .rerror_o ( ), + .cfg_i ( '0 ), + + .wr_collision_o ( ), + .write_pending_o ( ) ); // When OTBN is done let a few more cycles run then finish simulation diff --git a/hw/ip/otbn/rtl/otbn.sv b/hw/ip/otbn/rtl/otbn.sv index 89ad976e0a912..4d8c91ec38079 100644 --- a/hw/ip/otbn/rtl/otbn.sv +++ b/hw/ip/otbn/rtl/otbn.sv @@ -234,6 +234,8 @@ module otbn logic imem_req; logic imem_gnt; logic imem_write; + logic imem_wr_collision; + logic imem_wpending; logic [ImemIndexWidth-1:0] imem_index; logic [38:0] imem_wdata; logic [38:0] imem_wmask; @@ -353,7 +355,10 @@ module otbn .rvalid_o(imem_rvalid), .raddr_o (), .rerror_o(), - .cfg_i (ram_cfg_i) + .cfg_i (ram_cfg_i), + + .wr_collision_o (imem_wr_collision), + .write_pending_o (imem_wpending) ); // We should never see a request that doesn't get granted. A fatal error is raised if this occurs. @@ -374,22 +379,26 @@ module otbn .SecFifoPtr (1) // SEC_CM: TLUL_FIFO.CTR.REDUN ) u_tlul_adapter_sram_imem ( .clk_i, - .rst_ni (rst_n), - .tl_i (tl_win_h2d[TlWinImem]), - .tl_o (tl_win_d2h[TlWinImem]), - .en_ifetch_i (MuBi4False), - .req_o (imem_req_bus), - .req_type_o (), - .gnt_i (imem_gnt_bus), - .we_o (imem_write_bus), - .addr_o (imem_index_bus), - .wdata_o (imem_wdata_bus), - .wmask_o (imem_wmask_bus), - .intg_error_o (imem_bus_intg_violation), - .rdata_i (imem_rdata_bus), - .rvalid_i (imem_rvalid_bus), - .rerror_i (imem_rerror_bus), - .rmw_in_progress_o() + .rst_ni (rst_n), + .tl_i (tl_win_h2d[TlWinImem]), + .tl_o (tl_win_d2h[TlWinImem]), + .en_ifetch_i (MuBi4False), + .req_o (imem_req_bus), + .req_type_o (), + .gnt_i (imem_gnt_bus), + .we_o (imem_write_bus), + .addr_o (imem_index_bus), + .wdata_o (imem_wdata_bus), + .wmask_o (imem_wmask_bus), + .intg_error_o (imem_bus_intg_violation), + .rdata_i (imem_rdata_bus), + .rvalid_i (imem_rvalid_bus), + .rerror_i (imem_rerror_bus), + .compound_txn_in_progress_o (), + .readback_en_i (prim_mubi_pkg::MuBi4False), + .readback_error_o (), + .wr_collision_i (imem_wr_collision), + .write_pending_i (imem_wpending) ); @@ -519,6 +528,8 @@ module otbn logic [31:0] dmem_wdata_narrow_bus; logic [top_pkg::TL_DBW-1:0] dmem_byte_mask_bus; logic dmem_rvalid_bus; + logic dmem_wr_collision; + logic dmem_wpending; logic [1:0] dmem_rerror_bus; logic dmem_bus_intg_violation; @@ -556,7 +567,10 @@ module otbn .rvalid_o(dmem_rvalid), .raddr_o (), .rerror_o(), - .cfg_i (ram_cfg_i) + .cfg_i (ram_cfg_i), + + .wr_collision_o (dmem_wr_collision), + .write_pending_o (dmem_wpending) ); // We should never see a request that doesn't get granted. A fatal error is raised if this occurs. @@ -613,22 +627,26 @@ module otbn .SecFifoPtr (1) // SEC_CM: TLUL_FIFO.CTR.REDUN ) u_tlul_adapter_sram_dmem ( .clk_i, - .rst_ni (rst_n), - .tl_i (tl_win_h2d[TlWinDmem]), - .tl_o (tl_win_d2h[TlWinDmem]), - .en_ifetch_i (MuBi4False), - .req_o (dmem_req_bus), - .req_type_o (), - .gnt_i (dmem_gnt_bus), - .we_o (dmem_write_bus), - .addr_o (dmem_index_bus), - .wdata_o (dmem_wdata_bus), - .wmask_o (dmem_wmask_bus), - .intg_error_o (dmem_bus_intg_violation), - .rdata_i (dmem_rdata_bus), - .rvalid_i (dmem_rvalid_bus), - .rerror_i (dmem_rerror_bus), - .rmw_in_progress_o() + .rst_ni (rst_n), + .tl_i (tl_win_h2d[TlWinDmem]), + .tl_o (tl_win_d2h[TlWinDmem]), + .en_ifetch_i (MuBi4False), + .req_o (dmem_req_bus), + .req_type_o (), + .gnt_i (dmem_gnt_bus), + .we_o (dmem_write_bus), + .addr_o (dmem_index_bus), + .wdata_o (dmem_wdata_bus), + .wmask_o (dmem_wmask_bus), + .intg_error_o (dmem_bus_intg_violation), + .rdata_i (dmem_rdata_bus), + .rvalid_i (dmem_rvalid_bus), + .rerror_i (dmem_rerror_bus), + .compound_txn_in_progress_o (), + .readback_en_i (prim_mubi_pkg::MuBi4False), + .readback_error_o (), + .wr_collision_i (dmem_wr_collision), + .write_pending_i (dmem_wpending) ); // Mux core and bus access into dmem diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl.sv index 62d440bf6e670..904c4ad9250c1 100644 --- a/hw/ip/otp_ctrl/rtl/otp_ctrl.sv +++ b/hw/ip/otp_ctrl/rtl/otp_ctrl.sv @@ -221,22 +221,26 @@ module otp_ctrl ) u_tlul_adapter_sram ( .clk_i, .rst_ni, - .en_ifetch_i ( MuBi4False ), - .tl_i ( tl_win_h2d ), - .tl_o ( tl_win_d2h ), - .req_o ( tlul_req ), - .gnt_i ( tlul_gnt ), - .we_o ( ), // unused - .addr_o ( tlul_addr ), - .wdata_o ( ), // unused - .wmask_o ( ), // unused + .en_ifetch_i ( MuBi4False ), + .tl_i ( tl_win_h2d ), + .tl_o ( tl_win_d2h ), + .req_o ( tlul_req ), + .gnt_i ( tlul_gnt ), + .we_o ( ), // unused + .addr_o ( tlul_addr ), + .wdata_o ( ), // unused + .wmask_o ( ), // unused // SEC_CM: BUS.INTEGRITY - .intg_error_o ( intg_error[1] ), - .rdata_i ( tlul_rdata ), - .rvalid_i ( tlul_rvalid ), - .rerror_i ( tlul_rerror ), - .req_type_o ( ), - .rmw_in_progress_o( ) + .intg_error_o ( intg_error[1] ), + .rdata_i ( tlul_rdata ), + .rvalid_i ( tlul_rvalid ), + .rerror_i ( tlul_rerror ), + .req_type_o ( ), + .compound_txn_in_progress_o ( ), + .readback_en_i ( MuBi4False ), + .readback_error_o ( ), + .wr_collision_i ( 1'b0 ), + .write_pending_i ( 1'b0 ) ); logic [NumPart-1:0] tlul_part_sel_oh; diff --git a/hw/ip/prim/rtl/prim_ram_1p_scr.sv b/hw/ip/prim/rtl/prim_ram_1p_scr.sv index dba14f102f142..972e7038b6e5c 100644 --- a/hw/ip/prim/rtl/prim_ram_1p_scr.sv +++ b/hw/ip/prim/rtl/prim_ram_1p_scr.sv @@ -83,7 +83,11 @@ module prim_ram_1p_scr import prim_ram_1p_pkg::*; #( output logic [31:0] raddr_o, // Read address for error reporting. // config - input ram_1p_cfg_t cfg_i + input ram_1p_cfg_t cfg_i, + + // Write currently pending inside this module. + output logic wr_collision_o, + output logic write_pending_o ); ////////////////////// @@ -136,6 +140,14 @@ module prim_ram_1p_scr import prim_ram_1p_pkg::*; #( logic rw_collision; assign rw_collision = write_en_q & read_en; + // Write currently processed inside this module. Although we are sending an immediate d_valid + // back to the host, the write could take longer due to the scrambling. + assign write_pending_o = macro_write | write_en_d; + + // When a read is followed after a write with the same address, we return the data from the + // holding register. + assign wr_collision_o = addr_collision_q; + //////////////////////// // Address Scrambling // //////////////////////// diff --git a/hw/ip/rom_ctrl/rtl/rom_ctrl.sv b/hw/ip/rom_ctrl/rtl/rom_ctrl.sv index ff22235b402cc..99567013c575f 100644 --- a/hw/ip/rom_ctrl/rtl/rom_ctrl.sv +++ b/hw/ip/rom_ctrl/rtl/rom_ctrl.sv @@ -187,21 +187,25 @@ module rom_ctrl .clk_i, .rst_ni, - .tl_i (tl_rom_h2d_downstream), - .tl_o (rom_tl_o), - .en_ifetch_i (prim_mubi_pkg::MuBi4True), - .req_o (bus_rom_req), - .req_type_o (), - .gnt_i (bus_rom_gnt), - .we_o (), - .addr_o (bus_rom_rom_index), - .wdata_o (), - .wmask_o (), - .intg_error_o (rom_integrity_error), - .rdata_i (bus_rom_rdata), - .rvalid_i (bus_rom_rvalid), - .rerror_i (2'b00), - .rmw_in_progress_o() + .tl_i (tl_rom_h2d_downstream), + .tl_o (rom_tl_o), + .en_ifetch_i (prim_mubi_pkg::MuBi4True), + .req_o (bus_rom_req), + .req_type_o (), + .gnt_i (bus_rom_gnt), + .we_o (), + .addr_o (bus_rom_rom_index), + .wdata_o (), + .wmask_o (), + .intg_error_o (rom_integrity_error), + .rdata_i (bus_rom_rdata), + .rvalid_i (bus_rom_rvalid), + .rerror_i (2'b00), + .compound_txn_in_progress_o (), + .readback_en_i (prim_mubi_pkg::MuBi4False), + .readback_error_o (), + .wr_collision_i (1'b0), + .write_pending_i (1'b0) ); // Snoop on the "upstream" TL transaction to infer the address to pass to the PRINCE cipher. diff --git a/hw/ip/spi_device/rtl/spi_device.sv b/hw/ip/spi_device/rtl/spi_device.sv index 1c5e775c9a0d9..e4d582fe646e3 100644 --- a/hw/ip/spi_device/rtl/spi_device.sv +++ b/hw/ip/spi_device/rtl/spi_device.sv @@ -1638,21 +1638,25 @@ module spi_device .clk_i, .rst_ni, - .tl_i (tl_sram_egress_h2d), - .tl_o (tl_sram_egress_d2h), - .en_ifetch_i (prim_mubi_pkg::MuBi4False), - .req_o (sys_sram_l2m[SysSramFwEgress].req), - .req_type_o (), - .gnt_i (sys_sram_fw_gnt[SPI_DEVICE_EGRESS_BUFFER_IDX]), - .we_o (sys_sram_l2m[SysSramFwEgress].we), - .addr_o (sys_sram_l2m[SysSramFwEgress].addr), - .wdata_o (sys_sram_l2m[SysSramFwEgress].wdata), - .wmask_o (sys_sram_l2m_fw_wmask[SPI_DEVICE_EGRESS_BUFFER_IDX]), // Not used - .intg_error_o (), - .rdata_i (sys_sram_m2l[SysSramFwEgress].rdata), - .rvalid_i (sys_sram_m2l[SysSramFwEgress].rvalid), - .rerror_i (sys_sram_m2l[SysSramFwEgress].rerror), - .rmw_in_progress_o() + .tl_i (tl_sram_egress_h2d), + .tl_o (tl_sram_egress_d2h), + .en_ifetch_i (prim_mubi_pkg::MuBi4False), + .req_o (sys_sram_l2m[SysSramFwEgress].req), + .req_type_o (), + .gnt_i (sys_sram_fw_gnt[SPI_DEVICE_EGRESS_BUFFER_IDX]), + .we_o (sys_sram_l2m[SysSramFwEgress].we), + .addr_o (sys_sram_l2m[SysSramFwEgress].addr), + .wdata_o (sys_sram_l2m[SysSramFwEgress].wdata), + .wmask_o (sys_sram_l2m_fw_wmask[SPI_DEVICE_EGRESS_BUFFER_IDX]), // Not used + .intg_error_o (), + .rdata_i (sys_sram_m2l[SysSramFwEgress].rdata), + .rvalid_i (sys_sram_m2l[SysSramFwEgress].rvalid), + .rerror_i (sys_sram_m2l[SysSramFwEgress].rerror), + .compound_txn_in_progress_o (), + .readback_en_i (prim_mubi_pkg::MuBi4False), + .readback_error_o (), + .wr_collision_i (1'b0), + .write_pending_i (1'b0) ); tlul_adapter_sram #( @@ -1665,21 +1669,25 @@ module spi_device .clk_i, .rst_ni, - .tl_i (tl_sram_ingress_h2d), - .tl_o (tl_sram_ingress_d2h), - .en_ifetch_i (prim_mubi_pkg::MuBi4False), - .req_o (sys_sram_l2m[SysSramFwIngress].req), - .req_type_o (), - .gnt_i (sys_sram_fw_gnt[SPI_DEVICE_INGRESS_BUFFER_IDX]), - .we_o (sys_sram_l2m[SysSramFwIngress].we), - .addr_o (sys_sram_l2m[SysSramFwIngress].addr), - .wdata_o (sys_sram_l2m[SysSramFwIngress].wdata), - .wmask_o (sys_sram_l2m_fw_wmask[SPI_DEVICE_INGRESS_BUFFER_IDX]), // Not used - .intg_error_o (), - .rdata_i (sys_sram_m2l[SysSramFwIngress].rdata), - .rvalid_i (sys_sram_m2l[SysSramFwIngress].rvalid), - .rerror_i (sys_sram_m2l[SysSramFwIngress].rerror), - .rmw_in_progress_o() + .tl_i (tl_sram_ingress_h2d), + .tl_o (tl_sram_ingress_d2h), + .en_ifetch_i (prim_mubi_pkg::MuBi4False), + .req_o (sys_sram_l2m[SysSramFwIngress].req), + .req_type_o (), + .gnt_i (sys_sram_fw_gnt[SPI_DEVICE_INGRESS_BUFFER_IDX]), + .we_o (sys_sram_l2m[SysSramFwIngress].we), + .addr_o (sys_sram_l2m[SysSramFwIngress].addr), + .wdata_o (sys_sram_l2m[SysSramFwIngress].wdata), + .wmask_o (sys_sram_l2m_fw_wmask[SPI_DEVICE_INGRESS_BUFFER_IDX]), // Not used + .intg_error_o (), + .rdata_i (sys_sram_m2l[SysSramFwIngress].rdata), + .rvalid_i (sys_sram_m2l[SysSramFwIngress].rvalid), + .rerror_i (sys_sram_m2l[SysSramFwIngress].rerror), + .compound_txn_in_progress_o (), + .readback_en_i (prim_mubi_pkg::MuBi4False), + .readback_error_o (), + .wr_collision_i (1'b0), + .write_pending_i (1'b0) ); assign sys_sram_l2m[SysSramFwEgress].wstrb = sram_mask2strb(sys_sram_l2m_fw_wmask[SPI_DEVICE_EGRESS_BUFFER_IDX]); diff --git a/hw/ip/spi_host/rtl/spi_host_window.sv b/hw/ip/spi_host/rtl/spi_host_window.sv index 2794d414c31f1..999c1192086ee 100644 --- a/hw/ip/spi_host/rtl/spi_host_window.sv +++ b/hw/ip/spi_host/rtl/spi_host_window.sv @@ -84,7 +84,11 @@ module spi_host_window ( .rdata_i('0), .rvalid_i('0), .rerror_i('0), - .rmw_in_progress_o() + .compound_txn_in_progress_o(), + .readback_en_i(prim_mubi_pkg::MuBi4False), + .readback_error_o (), + .wr_collision_i(1'b0), + .write_pending_i(1'b0) ); endmodule : spi_host_window diff --git a/hw/ip/sram_ctrl/README.md b/hw/ip/sram_ctrl/README.md index 7e329e039f67a..1b5da77eac2ab 100644 --- a/hw/ip/sram_ctrl/README.md +++ b/hw/ip/sram_ctrl/README.md @@ -28,3 +28,4 @@ The SRAM controller contains the SRAM data and address scrambling device and pro - LFSR-based memory initialization feature. - Access controls to allow / disallow code execution from SRAM. - Security hardening when integrity error has been detected. +- Optional memory readback mode for detecting memory integrity errors. diff --git a/hw/ip/sram_ctrl/data/sram_ctrl.hjson b/hw/ip/sram_ctrl/data/sram_ctrl.hjson index 1c27e36b581af..0a3fb9b20d695 100644 --- a/hw/ip/sram_ctrl/data/sram_ctrl.hjson +++ b/hw/ip/sram_ctrl/data/sram_ctrl.hjson @@ -204,6 +204,9 @@ { name: "MEM.INTEGRITY", desc: "End-to-end data/memory integrity scheme." } + { name: "MEM.READBACK", + desc: "Each read and write is checked with a readback." + } { name: "MEM.SCRAMBLE", desc: "Data is scrambled with a keyed reduced-round PRINCE cipher in CTR mode." } @@ -302,6 +305,15 @@ ''', resval: 0, } + { bits: "6" + name: "READBACK_ERROR" + desc: ''' + This bit is set to 1 if a SRAM readback check failed. + This error triggers a fatal_error alert. + This condition is terminal. + ''', + resval: 0, + } ] } { name: "EXEC_REGWEN", @@ -401,6 +413,41 @@ resval: false }, ] + } + { name: "READBACK_REGWEN", + desc: "Lock register for readback enable register.", + swaccess: "rw0c", + hwaccess: "none", + tags: [// Exclude from writes to these field because they cause side affects. + "excl:CsrAllTests:CsrExclAll"] + fields: [ + { bits: "0" + desc: ''' + When cleared to zero, !!READBACK can not be written anymore. + ''', + resval: 1 + } + ] + } + { name: "READBACK", + desc: "readback enable.", + swaccess: "rw", + hwaccess: "hro", + regwen: "READBACK_REGWEN" + tags: [// Exclude from writes to these field because they cause side affects. + "excl:CsrAllTests:CsrExclAll"] + fields: [ + { bits: "3:0", + name: "EN", + mubi: true, + desc: ''' + Write kMultiBitBool4True to this field to enable the readback security feature for the SRAM. + A readback of each memory write or read request will be performed and a comparison happens. + Any other value than kMultiBitBool4False written to this field is interpreted as kMultiBitBool4True. + ''', + resval: false + }, + ] }, ], diff --git a/hw/ip/sram_ctrl/data/sram_ctrl_sec_cm_testplan.hjson b/hw/ip/sram_ctrl/data/sram_ctrl_sec_cm_testplan.hjson index d5853121e56ce..15d4626cda915 100644 --- a/hw/ip/sram_ctrl/data/sram_ctrl_sec_cm_testplan.hjson +++ b/hw/ip/sram_ctrl/data/sram_ctrl_sec_cm_testplan.hjson @@ -91,6 +91,15 @@ stage: V2S tests: ["{name}_passthru_mem_tl_intg_err"] } + { + name: sec_cm_mem_readback + desc: '''Verify the countermeasure(s) MEM.READBACK. + + Test needs to be implemented, see lowRISC/opentitan#23322. + ''' + stage: V2S + tests: ["{name}_smoke"] + } { name: sec_cm_mem_scramble desc: '''Verify the countermeasure(s) MEM.SCRAMBLE. diff --git a/hw/ip/sram_ctrl/doc/interfaces.md b/hw/ip/sram_ctrl/doc/interfaces.md index 679d75f2d6b3e..ee48bf52bea75 100644 --- a/hw/ip/sram_ctrl/doc/interfaces.md +++ b/hw/ip/sram_ctrl/doc/interfaces.md @@ -55,6 +55,7 @@ Referring to the [Comportable guideline for peripheral device functionality](htt | SRAM_CTRL.LC_ESCALATE_EN.INTERSIG.MUBI | The life cycle escalation enable signal is multibit encoded. | | SRAM_CTRL.LC_HW_DEBUG_EN.INTERSIG.MUBI | The life cycle hardware debug enable signal is multibit encoded. | | SRAM_CTRL.MEM.INTEGRITY | End-to-end data/memory integrity scheme. | +| SRAM_CTRL.MEM.READBACK | Each read and write is checked with a readback. | | SRAM_CTRL.MEM.SCRAMBLE | Data is scrambled with a keyed reduced-round PRINCE cipher in CTR mode. | | SRAM_CTRL.ADDR.SCRAMBLE | Address is scrambled with a keyed lightweight permutation/diffusion function. | | SRAM_CTRL.INSTR.BUS.LC_GATED | Prevent code execution from SRAM in non-test lifecycle states. | diff --git a/hw/ip/sram_ctrl/doc/registers.md b/hw/ip/sram_ctrl/doc/registers.md index 8504937afd650..5cd448914cdcf 100644 --- a/hw/ip/sram_ctrl/doc/registers.md +++ b/hw/ip/sram_ctrl/doc/registers.md @@ -12,6 +12,8 @@ | sram_ctrl.[`CTRL_REGWEN`](#ctrl_regwen) | 0x10 | 4 | Lock register for control register. | | sram_ctrl.[`CTRL`](#ctrl) | 0x14 | 4 | SRAM ctrl register. | | sram_ctrl.[`SCR_KEY_ROTATED`](#scr_key_rotated) | 0x18 | 4 | Clearable SRAM key request status. | +| sram_ctrl.[`READBACK_REGWEN`](#readback_regwen) | 0x1c | 4 | Lock register for readback enable register. | +| sram_ctrl.[`READBACK`](#readback) | 0x20 | 4 | readback enable. | ## ALERT_TEST Alert Test Register @@ -34,17 +36,18 @@ Alert Test Register SRAM status register. - Offset: `0x4` - Reset default: `0x0` -- Reset mask: `0x3f` +- Reset mask: `0x7f` ### Fields ```wavejson -{"reg": [{"name": "BUS_INTEG_ERROR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "INIT_ERROR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "ESCALATED", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "SCR_KEY_VALID", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "SCR_KEY_SEED_VALID", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "INIT_DONE", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 26}], "config": {"lanes": 1, "fontsize": 10, "vspace": 200}} +{"reg": [{"name": "BUS_INTEG_ERROR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "INIT_ERROR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "ESCALATED", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "SCR_KEY_VALID", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "SCR_KEY_SEED_VALID", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "INIT_DONE", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "READBACK_ERROR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 25}], "config": {"lanes": 1, "fontsize": 10, "vspace": 200}} ``` | Bits | Type | Reset | Name | |:------:|:------:|:-------:|:--------------------------------------------------| -| 31:6 | | | Reserved | +| 31:7 | | | Reserved | +| 6 | ro | 0x0 | [READBACK_ERROR](#status--readback_error) | | 5 | ro | 0x0 | [INIT_DONE](#status--init_done) | | 4 | ro | 0x0 | [SCR_KEY_SEED_VALID](#status--scr_key_seed_valid) | | 3 | ro | 0x0 | [SCR_KEY_VALID](#status--scr_key_valid) | @@ -52,6 +55,11 @@ SRAM status register. | 1 | ro | 0x0 | [INIT_ERROR](#status--init_error) | | 0 | ro | 0x0 | [BUS_INTEG_ERROR](#status--bus_integ_error) | +### STATUS . READBACK_ERROR +This bit is set to 1 if a SRAM readback check failed. +This error triggers a fatal_error alert. +This condition is terminal. + ### STATUS . INIT_DONE Set to 1 if the hardware initialization triggered via [`CTRL.INIT`](#ctrl) has completed. @@ -201,5 +209,45 @@ SW can use this for a hardened acknowledgement mechanism where it clears the reg kMultiBitBool4True indicates that a valid scrambling key has been obtained from OTP. Write kMultiBitBool4True to clear. +## READBACK_REGWEN +Lock register for readback enable register. +- Offset: `0x1c` +- Reset default: `0x1` +- Reset mask: `0x1` + +### Fields + +```wavejson +{"reg": [{"name": "READBACK_REGWEN", "bits": 1, "attr": ["rw0c"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 170}} +``` + +| Bits | Type | Reset | Name | Description | +|:------:|:------:|:-------:|:----------------|:--------------------------------------------------------------------------| +| 31:1 | | | | Reserved | +| 0 | rw0c | 0x1 | READBACK_REGWEN | When cleared to zero, [`READBACK`](#readback) can not be written anymore. | + +## READBACK +readback enable. +- Offset: `0x20` +- Reset default: `0x9` +- Reset mask: `0xf` +- Register enable: [`READBACK_REGWEN`](#readback_regwen) + +### Fields + +```wavejson +{"reg": [{"name": "EN", "bits": 4, "attr": ["rw"], "rotate": 0}, {"bits": 28}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}} +``` + +| Bits | Type | Reset | Name | +|:------:|:------:|:-------:|:--------------------| +| 31:4 | | | Reserved | +| 3:0 | rw | 0x9 | [EN](#readback--en) | + +### READBACK . EN +Write kMultiBitBool4True to this field to enable the readback security feature for the SRAM. +A readback of each memory write or read request will be performed and a comparison happens. +Any other value than kMultiBitBool4False written to this field is interpreted as kMultiBitBool4True. + This interface does not expose any registers. diff --git a/hw/ip/sram_ctrl/dv/env/seq_lib/sram_ctrl_base_vseq.sv b/hw/ip/sram_ctrl/dv/env/seq_lib/sram_ctrl_base_vseq.sv index f58a60e7ab85e..293e4b0352b26 100644 --- a/hw/ip/sram_ctrl/dv/env/seq_lib/sram_ctrl_base_vseq.sv +++ b/hw/ip/sram_ctrl/dv/env/seq_lib/sram_ctrl_base_vseq.sv @@ -11,6 +11,8 @@ class sram_ctrl_base_vseq #(parameter int AddrWidth = `SRAM_ADDR_WIDTH) extends `uvm_object_param_utils(sram_ctrl_base_vseq#(AddrWidth)) `uvm_object_new + rand mubi4_t readback_en; + // various knobs to enable certain routines bit do_sram_ctrl_init = 1'b1; @@ -18,6 +20,10 @@ class sram_ctrl_base_vseq #(parameter int AddrWidth = `SRAM_ADDR_WIDTH) extends int partial_access_pct = 10; + constraint readback_en_c { + soft readback_en inside {MuBi4True, MuBi4False}; + } + virtual task pre_start(); super.pre_start(); void'($value$plusargs("partial_access_pct=%0d", partial_access_pct)); @@ -29,8 +35,40 @@ class sram_ctrl_base_vseq #(parameter int AddrWidth = `SRAM_ADDR_WIDTH) extends virtual task dut_init(string reset_kind = "HARD"); super.dut_init(); if (do_sram_ctrl_init) sram_ctrl_init(); + sram_readback_en(); endtask + // Enable readback feature only for non-throughput and non-sec_cm tests. The + // readback feature is randomly initialized to on/off at the start of the test + // and randomly switched during the tests. + // TODO(#23321) Adapt the troughput tests to take the delay caused by the + // readback feature into account. + virtual task sram_readback_en(); + if (uvm_re_match("*throughput*", get_type_name()) && + uvm_re_match("*sec_cm*", get_type_name()) && + uvm_re_match("*throughput*", common_seq_type) && + uvm_re_match("*sec_cm*", common_seq_type)) begin + // Configure the SRAM TLUL agent to wait at least 2 cycles before dropping + // a request. + cfg.m_tl_agent_cfgs[cfg.sram_ral_name].a_valid_len_min = 2; + // Init the readback enable randomly to true or false. + csr_wr(.ptr(ral.readback), .value(readback_en)); + // Randomly toggle the readback enable during the test. + fork + begin + forever begin + cfg.clk_rst_vif.wait_clks($urandom_range(10, 10_000)); + csr_utils_pkg::wait_no_outstanding_access(); + std::randomize(readback_en) with { + readback_en inside {MuBi4True, MuBi4False};}; + csr_wr(.ptr(ral.readback), .value(readback_en)); + `uvm_info(`gfn, "Update READBACK Value", UVM_LOW) + end + end + join_none + end + endtask : sram_readback_en + virtual task apply_reset(string kind = "HARD"); cfg.lc_vif.init(); cfg.exec_vif.init(); diff --git a/hw/ip/sram_ctrl/dv/env/sram_ctrl_scoreboard.sv b/hw/ip/sram_ctrl/dv/env/sram_ctrl_scoreboard.sv index bd4ace9fbaec0..4423a07a09930 100644 --- a/hw/ip/sram_ctrl/dv/env/sram_ctrl_scoreboard.sv +++ b/hw/ip/sram_ctrl/dv/env/sram_ctrl_scoreboard.sv @@ -550,6 +550,9 @@ class sram_ctrl_scoreboard #(parameter int AddrWidth = 10) extends cip_base_scor "exec": begin // do nothing end + "readback": begin + // do nothing + end "status": begin if (addr_phase_read) begin void'(ral.status.predict(.value(exp_status), .kind(UVM_PREDICT_READ))); diff --git a/hw/ip/sram_ctrl/rtl/sram_ctrl.sv b/hw/ip/sram_ctrl/rtl/sram_ctrl.sv index 9a48735fbad6c..d19a136db6f80 100644 --- a/hw/ip/sram_ctrl/rtl/sram_ctrl.sv +++ b/hw/ip/sram_ctrl/rtl/sram_ctrl.sv @@ -140,8 +140,12 @@ module sram_ctrl assign hw2reg.status.init_error.d = 1'b1; assign hw2reg.status.init_error.de = init_error; + logic readback_error; + assign hw2reg.status.readback_error.d = 1'b1; + assign hw2reg.status.readback_error.de = readback_error; + logic alert_req; - assign alert_req = (|bus_integ_error) | init_error; + assign alert_req = (|bus_integ_error) | init_error | readback_error; prim_alert_sender #( .AsyncOn(AlertAsyncOn[0]), @@ -183,15 +187,17 @@ module sram_ctrl logic local_esc, local_esc_reg; // This signal only aggregates registered escalation signals and is used for transaction // blocking further below, which is on a timing-critical path. - assign local_esc_reg = reg2hw.status.escalated.q | - reg2hw.status.init_error.q | - reg2hw.status.bus_integ_error.q; + assign local_esc_reg = reg2hw.status.escalated.q | + reg2hw.status.init_error.q | + reg2hw.status.bus_integ_error.q | + reg2hw.status.readback_error.q; // This signal aggregates all escalation trigger signals, including the ones that are generated in // the same cycle such as init_error and bus_integ_error. It is used for countermeasures that are // not on the critical path (such as clearing the scrambling keys). assign local_esc = escalate | init_error | (|bus_integ_error) | + readback_error | local_esc_reg; // Convert registered, local escalation sources to a multibit signal and combine this with @@ -444,8 +450,14 @@ module sram_ctrl logic sram_intg_error, sram_req, sram_gnt, sram_we, sram_rvalid; logic [AddrWidth-1:0] sram_addr; logic [DataWidth-1:0] sram_wdata, sram_wmask, sram_rdata; + logic sram_wpending, sram_wr_collision; + + logic sram_compound_txn_in_progress; - logic sram_rmw_in_progress; + + // // SEC_CM: MEM.READBACK + mubi4_t reg_readback_en; + assign reg_readback_en = mubi4_t'(reg2hw.readback.q); tlul_adapter_sram #( .SramAw(AddrWidth), @@ -456,26 +468,31 @@ module sram_ctrl .EnableRspIntgGen(1), .EnableDataIntgGen(0), .EnableDataIntgPt(1), // SEC_CM: MEM.INTEGRITY - .SecFifoPtr (1) // SEC_CM: TLUL_FIFO.CTR.REDUN + .SecFifoPtr (1), // SEC_CM: TLUL_FIFO.CTR.REDUN + .EnableReadback (1) // SEC_CM: MEM.READBACK ) u_tlul_adapter_sram ( .clk_i, .rst_ni, - .tl_i (ram_tl_in_gated), - .tl_o (ram_tl_out_gated), - .en_ifetch_i (en_ifetch), - .req_o (tlul_req), - .req_type_o (), - .gnt_i (tlul_gnt), - .we_o (tlul_we), - .addr_o (tlul_addr), - .wdata_o (tlul_wdata), - .wmask_o (tlul_wmask), + .tl_i (ram_tl_in_gated), + .tl_o (ram_tl_out_gated), + .en_ifetch_i (en_ifetch), + .req_o (tlul_req), + .req_type_o (), + .gnt_i (tlul_gnt), + .we_o (tlul_we), + .addr_o (tlul_addr), + .wdata_o (tlul_wdata), + .wmask_o (tlul_wmask), // SEC_CM: BUS.INTEGRITY - .intg_error_o (bus_integ_error[1]), - .rdata_i (sram_rdata), - .rvalid_i (sram_rvalid), - .rerror_i ('0), - .rmw_in_progress_o(sram_rmw_in_progress) + .intg_error_o (bus_integ_error[1]), + .rdata_i (sram_rdata), + .rvalid_i (sram_rvalid), + .rerror_i ('0), + .compound_txn_in_progress_o (sram_compound_txn_in_progress), + .readback_en_i (reg_readback_en), + .readback_error_o (readback_error), + .wr_collision_i (sram_wr_collision), + .write_pending_i (sram_wpending) ); logic key_valid; @@ -500,12 +517,12 @@ module sram_ctrl // reset, where the keys are reset to the default netlist constant. // // If we have escalated, but there is a pending request in the TL gate, we may have a pending - // read-modify-write transaction in the SRAM adapter. In that case we force key_valid high to - // enable that to complete so it returns a response, the TL gate won't accept any new + // read-modify-write transaction or readback in the SRAM adapter. In that case we force key_valid + // high to enable that to complete so it returns a response, the TL gate won't accept any new // transactions and the SRAM keys have been clobbered already. assign key_valid = (key_req_pending_q) ? 1'b0 : - (reg2hw.status.escalated.q) ? (tl_gate_resp_pending & sram_rmw_in_progress) : 1'b1; + (reg2hw.status.escalated.q) ? (tl_gate_resp_pending & sram_compound_txn_in_progress) : 1'b1; // SEC_CM: MEM.SCRAMBLE, ADDR.SCRAMBLE prim_ram_1p_scr #( @@ -517,22 +534,24 @@ module sram_ctrl .clk_i, .rst_ni, - .key_valid_i (key_valid), - .key_i (key_q), - .nonce_i (nonce_q[NonceWidth-1:0]), - - .req_i (sram_req), - .intg_error_i(sram_intg_error), - .gnt_o (sram_gnt), - .write_i (sram_we), - .addr_i (sram_addr), - .wdata_i (sram_wdata), - .wmask_i (sram_wmask), - .rdata_o (sram_rdata), - .rvalid_o (sram_rvalid), - .rerror_o ( ), - .raddr_o ( ), - .cfg_i + .key_valid_i (key_valid), + .key_i (key_q), + .nonce_i (nonce_q[NonceWidth-1:0]), + + .req_i (sram_req), + .intg_error_i (sram_intg_error), + .gnt_o (sram_gnt), + .write_i (sram_we), + .addr_i (sram_addr), + .wdata_i (sram_wdata), + .wmask_i (sram_wmask), + .rdata_o (sram_rdata), + .rvalid_o (sram_rvalid), + .rerror_o ( ), + .raddr_o ( ), + .cfg_i, + .wr_collision_o (sram_wr_collision), + .write_pending_o (sram_wpending) ); logic unused_sram_gnt; @@ -568,6 +587,10 @@ module sram_ctrl u_tlul_adapter_sram.u_rspfifo.gen_normal_fifo.u_fifo_cnt.gen_secure_ptrs.u_rptr, alert_tx_o[0]) + // Alert assertions for sparse FSM. + `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(TlSramByteFsm_A, + u_tlul_adapter_sram.u_sram_byte.gen_integ_handling.u_state_regs, alert_tx_o[0]) + // `tlul_gnt` doesn't factor in `sram_gnt` for timing reasons. This assertions checks that // `tlul_gnt` is the same as `sram_gnt` when there's an active `tlul_req` that isn't being ignored // because the SRAM is initializing. diff --git a/hw/ip/sram_ctrl/rtl/sram_ctrl_pkg.sv b/hw/ip/sram_ctrl/rtl/sram_ctrl_pkg.sv index 6c92a44ba9638..e3df577b34541 100644 --- a/hw/ip/sram_ctrl/rtl/sram_ctrl_pkg.sv +++ b/hw/ip/sram_ctrl/rtl/sram_ctrl_pkg.sv @@ -31,6 +31,4 @@ package sram_ctrl_pkg; parameter lfsr_perm_t RndCnstLfsrPermDefault = { 160'h438131ae2cb71ffdd2e4c29a1f412231747cd7b2 }; - - endpackage : sram_ctrl_pkg diff --git a/hw/ip/sram_ctrl/rtl/sram_ctrl_reg_pkg.sv b/hw/ip/sram_ctrl/rtl/sram_ctrl_reg_pkg.sv index 9af446e4c0397..3c996230b3b39 100644 --- a/hw/ip/sram_ctrl/rtl/sram_ctrl_reg_pkg.sv +++ b/hw/ip/sram_ctrl/rtl/sram_ctrl_reg_pkg.sv @@ -10,7 +10,7 @@ package sram_ctrl_reg_pkg; parameter int NumAlerts = 1; // Address widths within the block - parameter int RegsAw = 5; + parameter int RegsAw = 6; parameter int RamAw = 1; /////////////////////////////////////////////// @@ -23,6 +23,9 @@ package sram_ctrl_reg_pkg; } sram_ctrl_reg2hw_alert_test_reg_t; typedef struct packed { + struct packed { + logic q; + } readback_error; struct packed { logic q; } init_done; @@ -55,6 +58,10 @@ package sram_ctrl_reg_pkg; } renew_scr_key; } sram_ctrl_reg2hw_ctrl_reg_t; + typedef struct packed { + logic [3:0] q; + } sram_ctrl_reg2hw_readback_reg_t; + typedef struct packed { struct packed { logic d; @@ -80,6 +87,10 @@ package sram_ctrl_reg_pkg; logic d; logic de; } init_done; + struct packed { + logic d; + logic de; + } readback_error; } sram_ctrl_hw2reg_status_reg_t; typedef struct packed { @@ -89,26 +100,29 @@ package sram_ctrl_reg_pkg; // Register -> HW type for regs interface typedef struct packed { - sram_ctrl_reg2hw_alert_test_reg_t alert_test; // [14:13] - sram_ctrl_reg2hw_status_reg_t status; // [12:8] - sram_ctrl_reg2hw_exec_reg_t exec; // [7:4] - sram_ctrl_reg2hw_ctrl_reg_t ctrl; // [3:0] + sram_ctrl_reg2hw_alert_test_reg_t alert_test; // [19:18] + sram_ctrl_reg2hw_status_reg_t status; // [17:12] + sram_ctrl_reg2hw_exec_reg_t exec; // [11:8] + sram_ctrl_reg2hw_ctrl_reg_t ctrl; // [7:4] + sram_ctrl_reg2hw_readback_reg_t readback; // [3:0] } sram_ctrl_regs_reg2hw_t; // HW -> register type for regs interface typedef struct packed { - sram_ctrl_hw2reg_status_reg_t status; // [16:5] + sram_ctrl_hw2reg_status_reg_t status; // [18:5] sram_ctrl_hw2reg_scr_key_rotated_reg_t scr_key_rotated; // [4:0] } sram_ctrl_regs_hw2reg_t; // Register offsets for regs interface - parameter logic [RegsAw-1:0] SRAM_CTRL_ALERT_TEST_OFFSET = 5'h 0; - parameter logic [RegsAw-1:0] SRAM_CTRL_STATUS_OFFSET = 5'h 4; - parameter logic [RegsAw-1:0] SRAM_CTRL_EXEC_REGWEN_OFFSET = 5'h 8; - parameter logic [RegsAw-1:0] SRAM_CTRL_EXEC_OFFSET = 5'h c; - parameter logic [RegsAw-1:0] SRAM_CTRL_CTRL_REGWEN_OFFSET = 5'h 10; - parameter logic [RegsAw-1:0] SRAM_CTRL_CTRL_OFFSET = 5'h 14; - parameter logic [RegsAw-1:0] SRAM_CTRL_SCR_KEY_ROTATED_OFFSET = 5'h 18; + parameter logic [RegsAw-1:0] SRAM_CTRL_ALERT_TEST_OFFSET = 6'h 0; + parameter logic [RegsAw-1:0] SRAM_CTRL_STATUS_OFFSET = 6'h 4; + parameter logic [RegsAw-1:0] SRAM_CTRL_EXEC_REGWEN_OFFSET = 6'h 8; + parameter logic [RegsAw-1:0] SRAM_CTRL_EXEC_OFFSET = 6'h c; + parameter logic [RegsAw-1:0] SRAM_CTRL_CTRL_REGWEN_OFFSET = 6'h 10; + parameter logic [RegsAw-1:0] SRAM_CTRL_CTRL_OFFSET = 6'h 14; + parameter logic [RegsAw-1:0] SRAM_CTRL_SCR_KEY_ROTATED_OFFSET = 6'h 18; + parameter logic [RegsAw-1:0] SRAM_CTRL_READBACK_REGWEN_OFFSET = 6'h 1c; + parameter logic [RegsAw-1:0] SRAM_CTRL_READBACK_OFFSET = 6'h 20; // Reset values for hwext registers and their fields for regs interface parameter logic [0:0] SRAM_CTRL_ALERT_TEST_RESVAL = 1'h 0; @@ -122,18 +136,22 @@ package sram_ctrl_reg_pkg; SRAM_CTRL_EXEC, SRAM_CTRL_CTRL_REGWEN, SRAM_CTRL_CTRL, - SRAM_CTRL_SCR_KEY_ROTATED + SRAM_CTRL_SCR_KEY_ROTATED, + SRAM_CTRL_READBACK_REGWEN, + SRAM_CTRL_READBACK } sram_ctrl_regs_id_e; // Register width information to check illegal writes for regs interface - parameter logic [3:0] SRAM_CTRL_REGS_PERMIT [7] = '{ + parameter logic [3:0] SRAM_CTRL_REGS_PERMIT [9] = '{ 4'b 0001, // index[0] SRAM_CTRL_ALERT_TEST 4'b 0001, // index[1] SRAM_CTRL_STATUS 4'b 0001, // index[2] SRAM_CTRL_EXEC_REGWEN 4'b 0001, // index[3] SRAM_CTRL_EXEC 4'b 0001, // index[4] SRAM_CTRL_CTRL_REGWEN 4'b 0001, // index[5] SRAM_CTRL_CTRL - 4'b 0001 // index[6] SRAM_CTRL_SCR_KEY_ROTATED + 4'b 0001, // index[6] SRAM_CTRL_SCR_KEY_ROTATED + 4'b 0001, // index[7] SRAM_CTRL_READBACK_REGWEN + 4'b 0001 // index[8] SRAM_CTRL_READBACK }; endpackage diff --git a/hw/ip/sram_ctrl/rtl/sram_ctrl_regs_reg_top.sv b/hw/ip/sram_ctrl/rtl/sram_ctrl_regs_reg_top.sv index f149f31bb720d..d25c911c9f2d4 100644 --- a/hw/ip/sram_ctrl/rtl/sram_ctrl_regs_reg_top.sv +++ b/hw/ip/sram_ctrl/rtl/sram_ctrl_regs_reg_top.sv @@ -21,7 +21,7 @@ module sram_ctrl_regs_reg_top ( import sram_ctrl_reg_pkg::* ; - localparam int AW = 5; + localparam int AW = 6; localparam int DW = 32; localparam int DBW = DW/8; // Byte Width @@ -52,9 +52,9 @@ module sram_ctrl_regs_reg_top ( // also check for spurious write enables logic reg_we_err; - logic [6:0] reg_we_check; + logic [8:0] reg_we_check; prim_reg_we_check #( - .OneHotWidth(7) + .OneHotWidth(9) ) u_prim_reg_we_check ( .clk_i(clk_i), .rst_ni(rst_ni), @@ -129,6 +129,7 @@ module sram_ctrl_regs_reg_top ( logic status_scr_key_valid_qs; logic status_scr_key_seed_valid_qs; logic status_init_done_qs; + logic status_readback_error_qs; logic exec_regwen_we; logic exec_regwen_qs; logic exec_regwen_wd; @@ -144,6 +145,12 @@ module sram_ctrl_regs_reg_top ( logic scr_key_rotated_we; logic [3:0] scr_key_rotated_qs; logic [3:0] scr_key_rotated_wd; + logic readback_regwen_we; + logic readback_regwen_qs; + logic readback_regwen_wd; + logic readback_we; + logic [3:0] readback_qs; + logic [3:0] readback_wd; // Register instances // R[alert_test]: V(True) @@ -329,6 +336,33 @@ module sram_ctrl_regs_reg_top ( .qs (status_init_done_qs) ); + // F[readback_error]: 6:6 + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessRO), + .RESVAL (1'h0), + .Mubi (1'b0) + ) u_status_readback_error ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (1'b0), + .wd ('0), + + // from internal hardware + .de (hw2reg.status.readback_error.de), + .d (hw2reg.status.readback_error.d), + + // to internal hardware + .qe (), + .q (reg2hw.status.readback_error.q), + .ds (), + + // to register interface (read) + .qs (status_readback_error_qs) + ); + // R[exec_regwen]: V(False) prim_subreg #( @@ -517,8 +551,67 @@ module sram_ctrl_regs_reg_top ( ); + // R[readback_regwen]: V(False) + prim_subreg #( + .DW (1), + .SwAccess(prim_subreg_pkg::SwAccessW0C), + .RESVAL (1'h1), + .Mubi (1'b0) + ) u_readback_regwen ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (readback_regwen_we), + .wd (readback_regwen_wd), + + // from internal hardware + .de (1'b0), + .d ('0), - logic [6:0] addr_hit; + // to internal hardware + .qe (), + .q (), + .ds (), + + // to register interface (read) + .qs (readback_regwen_qs) + ); + + + // R[readback]: V(False) + // Create REGWEN-gated WE signal + logic readback_gated_we; + assign readback_gated_we = readback_we & readback_regwen_qs; + prim_subreg #( + .DW (4), + .SwAccess(prim_subreg_pkg::SwAccessRW), + .RESVAL (4'h9), + .Mubi (1'b1) + ) u_readback ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + // from register interface + .we (readback_gated_we), + .wd (readback_wd), + + // from internal hardware + .de (1'b0), + .d ('0), + + // to internal hardware + .qe (), + .q (reg2hw.readback.q), + .ds (), + + // to register interface (read) + .qs (readback_qs) + ); + + + + logic [8:0] addr_hit; always_comb begin addr_hit = '0; addr_hit[0] = (reg_addr == SRAM_CTRL_ALERT_TEST_OFFSET); @@ -528,6 +621,8 @@ module sram_ctrl_regs_reg_top ( addr_hit[4] = (reg_addr == SRAM_CTRL_CTRL_REGWEN_OFFSET); addr_hit[5] = (reg_addr == SRAM_CTRL_CTRL_OFFSET); addr_hit[6] = (reg_addr == SRAM_CTRL_SCR_KEY_ROTATED_OFFSET); + addr_hit[7] = (reg_addr == SRAM_CTRL_READBACK_REGWEN_OFFSET); + addr_hit[8] = (reg_addr == SRAM_CTRL_READBACK_OFFSET); end assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ; @@ -541,7 +636,9 @@ module sram_ctrl_regs_reg_top ( (addr_hit[3] & (|(SRAM_CTRL_REGS_PERMIT[3] & ~reg_be))) | (addr_hit[4] & (|(SRAM_CTRL_REGS_PERMIT[4] & ~reg_be))) | (addr_hit[5] & (|(SRAM_CTRL_REGS_PERMIT[5] & ~reg_be))) | - (addr_hit[6] & (|(SRAM_CTRL_REGS_PERMIT[6] & ~reg_be))))); + (addr_hit[6] & (|(SRAM_CTRL_REGS_PERMIT[6] & ~reg_be))) | + (addr_hit[7] & (|(SRAM_CTRL_REGS_PERMIT[7] & ~reg_be))) | + (addr_hit[8] & (|(SRAM_CTRL_REGS_PERMIT[8] & ~reg_be))))); end // Generate write-enables @@ -565,6 +662,12 @@ module sram_ctrl_regs_reg_top ( assign scr_key_rotated_we = addr_hit[6] & reg_we & !reg_error; assign scr_key_rotated_wd = reg_wdata[3:0]; + assign readback_regwen_we = addr_hit[7] & reg_we & !reg_error; + + assign readback_regwen_wd = reg_wdata[0]; + assign readback_we = addr_hit[8] & reg_we & !reg_error; + + assign readback_wd = reg_wdata[3:0]; // Assign write-enables to checker logic vector. always_comb begin @@ -576,6 +679,8 @@ module sram_ctrl_regs_reg_top ( reg_we_check[4] = ctrl_regwen_we; reg_we_check[5] = ctrl_gated_we; reg_we_check[6] = scr_key_rotated_we; + reg_we_check[7] = readback_regwen_we; + reg_we_check[8] = readback_gated_we; end // Read data return @@ -593,6 +698,7 @@ module sram_ctrl_regs_reg_top ( reg_rdata_next[3] = status_scr_key_valid_qs; reg_rdata_next[4] = status_scr_key_seed_valid_qs; reg_rdata_next[5] = status_init_done_qs; + reg_rdata_next[6] = status_readback_error_qs; end addr_hit[2]: begin @@ -616,6 +722,14 @@ module sram_ctrl_regs_reg_top ( reg_rdata_next[3:0] = scr_key_rotated_qs; end + addr_hit[7]: begin + reg_rdata_next[0] = readback_regwen_qs; + end + + addr_hit[8]: begin + reg_rdata_next[3:0] = readback_qs; + end + default: begin reg_rdata_next = '1; end diff --git a/hw/ip/tlul/README.md b/hw/ip/tlul/README.md index 158502b0af699..b795d52545202 100644 --- a/hw/ip/tlul/README.md +++ b/hw/ip/tlul/README.md @@ -692,3 +692,9 @@ The act of storing into the `rspfifo` also pops `sramreqfifo` entry. The `reqfifo` entry is used to construct the TL-UL response. When the response is accepted by an upstream TL-UL host, the `reqfifo` and `rspfifo` entries are both popped. + +#### Readback Mode +When enabled using the [`SRAM_CTRL.READBACK`](../sram_ctrl/doc/registers.md#readback) register, the `tlul_sram_byte` module is capable of reading back and checking each issued read and write. +On an integrity failure, for example caused by a fault injection attack, a fatal alert is raised and the alert register [`STATUS.READBACK_ERROR`](../sram_ctrl/doc/registers.md#status--readback_error) is set. +When the host issues a read, the `tlul_sram_byte` module performs the read, internally stores the received data from the memory, issues a second read, and compares the values of the first and second reads. +Similarily, on a write, the module temporarily stores the data to write, performs the write, issues a readback, and compares the read back value to the temporarily stored write data to ensure that the data correctly got written into the memory. diff --git a/hw/ip/tlul/rtl/tlul_adapter_sram.sv b/hw/ip/tlul/rtl/tlul_adapter_sram.sv index b497ba64a8c49..3a8427a51ce3c 100644 --- a/hw/ip/tlul/rtl/tlul_adapter_sram.sv +++ b/hw/ip/tlul/rtl/tlul_adapter_sram.sv @@ -34,6 +34,7 @@ module tlul_adapter_sram parameter bit EnableDataIntgGen = 0, // 1: Generate response data integrity parameter bit EnableDataIntgPt = 0, // 1: Passthrough command/response data integrity parameter bit SecFifoPtr = 0, // 1: Duplicated fifo pointers + parameter bit EnableReadback = 0, // 1: Readback and check written/read data. localparam int WidthMult = SramDw / top_pkg::TL_DW, localparam int IntgWidth = tlul_pkg::DataIntgWidth * WidthMult, localparam int DataOutW = EnableDataIntgPt ? SramDw + IntgWidth : SramDw @@ -60,7 +61,11 @@ module tlul_adapter_sram input [DataOutW-1:0] rdata_i, input rvalid_i, input [1:0] rerror_i, // 2 bit error [1]: Uncorrectable, [0]: Correctable - output logic rmw_in_progress_o + output logic compound_txn_in_progress_o, + input mubi4_t readback_en_i, + output logic readback_error_o, + input logic wr_collision_i, + input logic write_pending_i ); localparam int SramByte = SramDw/8; @@ -77,6 +82,31 @@ module tlul_adapter_sram logic rsp_fifo_error; logic intg_error; logic tlul_error; + logic readback_error; + logic sram_byte_readback_error; + + // readback check + logic readback_error_q; + if (EnableReadback) begin : gen_cmd_readback_check + assign readback_error = sram_byte_readback_error; + // permanently latch readback error until reset + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + readback_error_q <= '0; + end else if (readback_error) begin + readback_error_q <= 1'b1; + end + end + end else begin : gen_no_readback_check + logic unused_sram_byte_readback_error; + assign unused_sram_byte_readback_error = sram_byte_readback_error; + assign readback_error = '0; + assign readback_error_q = '0; + end + + // readback error output is permanent and should be used for alert generation + // or other downstream effects + assign readback_error_o = readback_error | readback_error_q; // integrity check if (CmdIntgCheck) begin : gen_cmd_intg_check @@ -162,7 +192,8 @@ module tlul_adapter_sram // byte handling for integrity tlul_sram_byte #( .EnableIntg(ByteAccess & EnableDataIntgPt & !ErrOnWrite), - .Outstanding(Outstanding) + .Outstanding(Outstanding), + .EnableReadback(EnableReadback) ) u_sram_byte ( .clk_i, .rst_ni, @@ -172,7 +203,11 @@ module tlul_adapter_sram .tl_sram_i(tl_o_int), .error_i(error_det), .error_o(error_internal), - .rmw_in_progress_o + .alert_o(sram_byte_readback_error), + .compound_txn_in_progress_o, + .readback_en_i, + .wr_collision_i, + .write_pending_i ); typedef struct packed { diff --git a/hw/ip/tlul/rtl/tlul_sram_byte.sv b/hw/ip/tlul/rtl/tlul_sram_byte.sv index 8faaf791e83a8..e7f6098cc1c44 100644 --- a/hw/ip/tlul/rtl/tlul_sram_byte.sv +++ b/hw/ip/tlul/rtl/tlul_sram_byte.sv @@ -16,8 +16,10 @@ * incoming tlul transaction is directly muxed out. */ module tlul_sram_byte import tlul_pkg::*; #( - parameter bit EnableIntg = 0, // Enable integrity handling at byte level - parameter int Outstanding = 1 + parameter bit EnableIntg = 0, // Enable integrity handling at byte level, + parameter int Outstanding = 1, + parameter bit EnableReadback = 0 // Enable readback checks on all transactions must have + // EnableIntg == 1 to enable ) ( input clk_i, input rst_ni, @@ -34,33 +36,72 @@ module tlul_sram_byte import tlul_pkg::*; #( // The error indication is also fed through input error_i, output logic error_o, + output logic alert_o, - output logic rmw_in_progress_o -); + output logic compound_txn_in_progress_o, - if (EnableIntg) begin : gen_integ_handling + input prim_mubi_pkg::mubi4_t readback_en_i, + + input logic wr_collision_i, + input logic write_pending_i +); - // state enumeration - typedef enum logic [1:0] { - StPassThru, - StWaitRd, - StWriteCmd - } state_e; + import prim_mubi_pkg::mubi4_t; + import prim_mubi_pkg::mubi4_test_true_loose; + import prim_mubi_pkg::mubi4_test_false_strict; + import prim_mubi_pkg::MuBi4True; + import prim_mubi_pkg::MuBi4False; + import prim_mubi_pkg::MuBi4Width; + + // Encoding generated with: + // $ ./util/design/sparse-fsm-encode.py -d 3 -m 11 -n 8 \ + // -s 718546395 --language=sv + // + // Hamming distance histogram: + // + // 0: -- + // 1: -- + // 2: -- + // 3: |||||||||||||| (25.45%) + // 4: |||||||||||||||||||| (36.36%) + // 5: |||||||||||| (21.82%) + // 6: ||||||| (12.73%) + // 7: || (3.64%) + // 8: -- + // + // Minimum Hamming distance: 3 + // Maximum Hamming distance: 7 + // Minimum Hamming weight: 1 + // Maximum Hamming weight: 6 + // + localparam int StateWidth = 8; + typedef enum logic [StateWidth-1:0] { + StPassThru = 8'b01111110, + StWaitRd = 8'b00000010, + StWriteCmd = 8'b11110001, + StWrReadBackInit = 8'b10011001, + StWrReadBack = 8'b00001111, + StWrReadBackDWait = 8'b00110000, + StRdReadBack = 8'b10101100, + StRdReadBackDWait = 8'b11000000, + StByteWrReadBackInit = 8'b01010111, + StByteWrReadBack = 8'b11100111, + StByteWrReadBackDWait = 8'b11111111 + } state_e; + if (EnableIntg) begin : gen_integ_handling // state and selection logic stall_host; + logic wait_phase; logic rd_phase; logic rd_wait; logic wr_phase; + logic rdback_phase; + logic rdback_phase_wrreadback; + logic rdback_wait; state_e state_d, state_q; - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - state_q <= StPassThru; - end else begin - state_q <= state_d; - end - end + `PRIM_FLOP_SPARSE_FSM(u_state_regs, state_d, state_q, state_e, StPassThru) // transaction qualifying signals logic a_ack; // upstream a channel acknowledgement @@ -70,7 +111,23 @@ module tlul_sram_byte import tlul_pkg::*; #( logic wr_txn; logic byte_wr_txn; logic byte_req_ack; - logic [prim_util_pkg::vbits(Outstanding+1)-1:0] pending_txn_cnt; + logic hold_tx_data; + + localparam int unsigned PendingTxnCntW = prim_util_pkg::vbits(Outstanding+1); + logic [PendingTxnCntW-1:0] pending_txn_cnt; + + // prim fifo for capturing info + typedef struct packed { + logic [2:0] a_param; + logic [top_pkg::TL_SZW-1:0] a_size; + logic [top_pkg::TL_AIW-1:0] a_source; + logic [top_pkg::TL_AW-1:0] a_address; + logic [top_pkg::TL_DBW-1:0] a_mask; + logic [top_pkg::TL_DW-1:0] a_data; + tl_a_user_t a_user; + } tl_txn_data_t; + + tl_txn_data_t held_data; assign a_ack = tl_i.a_valid & tl_o.a_ready; assign d_ack = tl_o.d_valid & tl_i.d_ready; @@ -81,21 +138,147 @@ module tlul_sram_byte import tlul_pkg::*; #( assign byte_req_ack = byte_wr_txn & a_ack & ~error_i; assign byte_wr_txn = tl_i.a_valid & ~&tl_i.a_mask & wr_txn; + logic rdback_chk_ok; + mubi4_t rdback_check_q, rdback_check_d; + mubi4_t rdback_en_q, rdback_en_d; + logic [31:0] rdback_data_exp_q, rdback_data_exp_d; + logic [DataIntgWidth-1:0] rdback_data_exp_intg_q, rdback_data_exp_intg_d; + + if (EnableReadback) begin : gen_readback_logic + logic rdback_chk_ok_unbuf; + + assign rdback_chk_ok_unbuf = (rdback_data_exp_q == tl_sram_i.d_data); + + prim_sec_anchor_buf #( + .Width(1) + ) u_rdback_chk_ok_buf ( + .in_i (rdback_chk_ok_unbuf), + .out_o(rdback_chk_ok) + ); + + prim_flop #( + .Width(MuBi4Width), + .ResetValue(MuBi4Width'(MuBi4False)) + ) u_rdback_check_flop ( + .clk_i, + .rst_ni, + + .d_i(MuBi4Width'(rdback_check_d)), + .q_o({rdback_check_q}) + ); + + prim_flop #( + .Width(MuBi4Width), + .ResetValue(MuBi4Width'(MuBi4False)) + ) u_rdback_en_flop ( + .clk_i, + .rst_ni, + + .d_i(MuBi4Width'(rdback_en_d)), + .q_o({rdback_en_q}) + ); + + prim_flop #( + .Width(32), + .ResetValue(0) + ) u_rdback_data_exp ( + .clk_i, + .rst_ni, + + .d_i(rdback_data_exp_d), + .q_o(rdback_data_exp_q) + ); + + prim_flop #( + .Width(DataIntgWidth), + .ResetValue(0) + ) u_rdback_data_exp_intg ( + .clk_i, + .rst_ni, + + .d_i(rdback_data_exp_intg_d), + .q_o(rdback_data_exp_intg_q) + ); + + // If the readback feature is enabled and we are currently in the readback phase, + // no address collision should happen inside prim_ram_1p_scr. If this would be the + // case, we would read from the holding register inside prim_ram_1p_scr instead of + // actually performing the readback from the memory. + `ASSERT(WRCollisionDuringReadBack_A, (rdback_phase | rdback_phase_wrreadback) & + mubi4_test_true_loose(rdback_en_q) |-> !wr_collision_i) + + + // If the readback feature is enabled, we assume that the write phase takes one extra cycle + // due to the underyling scrambling mechanism. If this additional cycle is not needed anymore + // in the future (e.g. due to the removale of the scrambling mechanism), the readback does not + // need to be delayed by once cylce in the FSM below. + `ASSERT(NoPendingWriteAfterWrite_A, wr_phase & mubi4_test_true_loose(rdback_en_q) + |=> write_pending_i) + + + end else begin: gen_no_readback_logic + assign rdback_chk_ok = 1'b0; + assign rdback_check_q = MuBi4False; + assign rdback_en_q = MuBi4False; + assign rdback_data_exp_q = 1'b0; + assign rdback_data_exp_intg_q = 1'b0; + + logic unused_rdback; + + assign unused_rdback = ^{rdback_check_d, rdback_data_exp_d, rdback_data_exp_intg_d}; + end + // state machine handling always_comb begin rd_wait = 1'b0; + wait_phase = 1'b0; stall_host = 1'b0; wr_phase = 1'b0; rd_phase = 1'b0; + rdback_phase = 1'b0; + rdback_phase_wrreadback = 1'b0; + rdback_wait = 1'b0; state_d = state_q; + hold_tx_data = 1'b0; + alert_o = 1'b0; + rdback_check_d = rdback_check_q; + rdback_en_d = rdback_en_q; + rdback_data_exp_d = rdback_data_exp_q; + rdback_data_exp_intg_d = rdback_data_exp_intg_q; unique case (state_q) StPassThru: begin + if (mubi4_test_true_loose(rdback_en_q) && mubi4_test_true_loose(rdback_check_q)) begin + // When we're expecting a readback check that means we'll see a data response from the + // SRAM this cycle which we need to check against the readback registers. During this + // cycle the data response out (via tl_o) will be squashed to invalid but we can accept + // a new transaction (via tl_i). + rdback_wait = 1'b1; + rdback_check_d = MuBi4False; + + // Perform the readback check. Omit the check if the transaction contains an error. + if (!rdback_chk_ok && !error_i) begin + alert_o = 1'b1; + end + end + if (byte_wr_txn) begin rd_phase = 1'b1; if (byte_req_ack) begin state_d = StWaitRd; end + end else if (a_ack && mubi4_test_true_loose(rdback_en_q) && !error_i) begin + // For reads and full word writes we'll first do the transaction and then do a readback + // check. Setting `hold_tx_data` here will preserve the transaction information in + // u_sync_fifo for doing the readback transaction. + hold_tx_data = 1'b1; + state_d = wr_txn ? StWrReadBackInit : StRdReadBack; + end + + if (!tl_sram_o.a_valid && !tl_o.d_valid && + mubi4_test_false_strict(rdback_check_q)) begin + // Store readback enable into register when bus is idle and no readback is processed. + rdback_en_d = readback_en_i; end end @@ -105,7 +288,7 @@ module tlul_sram_byte import tlul_pkg::*; #( StWaitRd: begin rd_phase = 1'b1; stall_host = 1'b1; - if (pending_txn_cnt == $bits(pending_txn_cnt)'(1)) begin + if (pending_txn_cnt == PendingTxnCntW'(1)) begin rd_wait = 1'b1; if (sram_d_ack) begin state_d = StWriteCmd; @@ -118,30 +301,200 @@ module tlul_sram_byte import tlul_pkg::*; #( wr_phase = 1'b1; if (sram_a_ack) begin - state_d = StPassThru; + state_d = mubi4_test_true_loose(rdback_en_q) ? StByteWrReadBackInit : StPassThru; + rdback_check_d = mubi4_test_true_loose(rdback_en_q) ? MuBi4True : MuBi4False; + rdback_data_exp_d = tl_sram_o.a_data; + rdback_data_exp_intg_d = tl_sram_o.a_user.data_intg; + end + end + + StWrReadBackInit: begin + // Perform readback after full write. To avoid that we read the holding register + // in the readback, wait until the write was processed by the memory module. + if (EnableReadback == 0) begin : gen_inv_state_StWrReadBackInit + // If readback is disabled, we shouldn't be in this state. + alert_o = 1'b1; + end + + // Stall the host to perform the readback in the next cycle. + stall_host = 1'b1; + + // Need to ensure there's no other transactions in flight before we do the readback (the + // initial write we're doing the readback for should be the only one active). + if (pending_txn_cnt == PendingTxnCntW'(1)) begin + wait_phase = 1'b1; + // Data we're checking against the readback is captured from the write transaction that + // was sent. + rdback_check_d = mubi4_test_true_loose(rdback_en_q) ? MuBi4True : MuBi4False; + rdback_data_exp_d = held_data.a_data; + rdback_data_exp_intg_d = held_data.a_user.data_intg; + if (d_ack) begin + // Got an immediate TL-UL write response. Wait for one cycle until the holding + // register is flushed and then perform the readback. + state_d = StWrReadBack; + end else begin + // No response yet to the initial write. + state_d = StWrReadBackDWait; + end + end + end + + StWrReadBack: begin + // Perform readback and check response in StPassThru. + if (EnableReadback == 0) begin : gen_inv_state_StWrReadBack + // If readback is disabled, we shouldn't be in this state. + alert_o = 1'b1; + end + + stall_host = 1'b1; + + rdback_phase = 1'b1; + + state_d = StPassThru; + end + + StWrReadBackDWait: begin + // We have not received the d_valid response of the initial write. Wait + // for the valid signal. + if (EnableReadback == 0) begin : gen_inv_state_StWrReadBackDWait + // If readback is disabled, we shouldn't be in this state. + alert_o = 1'b1; + end + + // Wait until we get write response. + wait_phase = 1'b1; + + stall_host = 1'b1; + + if (d_ack) begin + // Got the TL-UL write response. Wait for one cycle until the holding + // register is flushed and then perform the readback. + state_d = StWrReadBack; + end + end + + StByteWrReadBackInit: begin + // Perform readback after partial write. To avoid that we read the holding register + // in the readback, do the actual readback check in the next FSM state. + if (EnableReadback == 0) begin : gen_inv_state_StByteWrReadBackInit + // If readback is disabled, we shouldn't be in this state. + alert_o = 1'b1; + end + + // Sends out a read to a readback check on a partial write. The host is stalled whilst + // this is happening. + stall_host = 1'b1; + + // Wait until there is a single ongoing transaction. + if (pending_txn_cnt == PendingTxnCntW'(1)) begin + // Wait for one cycle with sending readback request to SRAM to avoid reading from + // holding register. + wait_phase = 1'b1; + + if (d_ack) begin + // Got an immediate TL-UL write response. Wait for one cycle until the holding + // register is flushed and then perform the readback. + state_d = StByteWrReadBack; + end else begin + // No response received for initial write. We already can send the + // request for the readback in the next cycle but we need to wait + // for the response for the initial write before doing the readback + // check. + state_d = StByteWrReadBackDWait; + end + end + end + + StByteWrReadBack: begin + // Wait until the memory module has completed the partial write. + // Perform readback and check response in StPassThru. + if (EnableReadback == 0) begin : gen_inv_state_StByteWrReadBack + // If readback is disabled, we shouldn't be in this state. + alert_o = 1'b1; + end + + stall_host = 1'b1; + + rdback_phase_wrreadback = 1'b1; + + state_d = StPassThru; + end + + StByteWrReadBackDWait: begin + if (EnableReadback == 0) begin : gen_inv_state_StByteWrReadBackDWait + // If readback is disabled, we shouldn't be in this state. + alert_o = 1'b1; + end + + stall_host = 1'b1; + + // Wait for one cycle with sending readback request to SRAM. + wait_phase = 1'b1; + + if (d_ack) begin + // Got the TL-UL write response. Wait for one cycle until the holding + // register is flushed and then perform the readback. + state_d = StByteWrReadBack; + end + end + + StRdReadBack: begin + if (EnableReadback == 0) begin : gen_inv_state_StRdReadBack + // If readback is disabled, we shouldn't be in this state. + alert_o = 1'b1; + end + + // Sends out a read to a readback check on a read. The host is stalled whilst + // this is happening. + stall_host = 1'b1; + + // Need to ensure there's no other transactions in flight before we do the readback (the + // read we're doing the readback for should be the only one active). + if (pending_txn_cnt == PendingTxnCntW'(1)) begin + rdback_phase = 1'b1; + + if (d_ack) begin + state_d = StPassThru; + // Data for the readback check comes from the first read. + rdback_check_d = mubi4_test_true_loose(rdback_en_q) ? MuBi4True : MuBi4False; + rdback_data_exp_d = tl_o.d_data; + rdback_data_exp_intg_d = tl_o.d_user.data_intg; + end else begin + // No response yet to the initial read, so go wait for it. + state_d = StRdReadBackDWait; + end end end - default:; + StRdReadBackDWait : begin + if (EnableReadback == 0) begin : gen_inv_state_StRdReadBackDWait + // If readback is disabled, we shouldn't be in this state. + alert_o = 1'b1; + end + stall_host = 1'b1; + + if (d_ack) begin + // Response received for first read. Now need to await data for the readback check + // which is done in the `StPassThru` state. + state_d = StPassThru; + // Data for the readback check comes from the first read. + rdback_check_d = mubi4_test_true_loose(rdback_en_q) ? MuBi4True : MuBi4False; + rdback_data_exp_d = tl_o.d_data; + rdback_data_exp_intg_d = tl_o.d_user.data_intg; + end + end + + default: begin + alert_o = 1'b1; + end endcase // unique case (state_q) end - // prim fifo for capturing info - typedef struct packed { - logic [2:0] a_param; - logic [top_pkg::TL_SZW-1:0] a_size; - logic [top_pkg::TL_AIW-1:0] a_source; - logic [top_pkg::TL_AW-1:0] a_address; - logic [top_pkg::TL_DBW-1:0] a_mask; - logic [top_pkg::TL_DW-1:0] a_data; - tl_a_user_t a_user; - } tl_txn_data_t; - tl_txn_data_t txn_data; - tl_txn_data_t held_data; logic fifo_rdy; + logic txn_data_wr; localparam int TxnDataWidth = $bits(tl_txn_data_t); assign txn_data = '{ @@ -154,6 +507,9 @@ module tlul_sram_byte import tlul_pkg::*; #( a_user: tl_i.a_user }; + + assign txn_data_wr = hold_tx_data | byte_req_ack; + prim_fifo_sync #( .Width(TxnDataWidth), .Pass(1'b0), @@ -163,7 +519,7 @@ module tlul_sram_byte import tlul_pkg::*; #( .clk_i, .rst_ni, .clr_i(1'b0), - .wvalid_i(byte_req_ack), + .wvalid_i(txn_data_wr), .wready_o(fifo_rdy), .wdata_i(txn_data), .rvalid_o(), @@ -215,8 +571,8 @@ module tlul_sram_byte import tlul_pkg::*; #( always_comb begin // Pass-through by default tl_sram_o = tl_i; - // if we're waiting for an internal read for RMW, we force this to 1. - tl_sram_o.d_ready = tl_i.d_ready | rd_wait; + // If we're waiting for an internal read for RMW, or a readback read, we force this to 1. + tl_sram_o.d_ready = tl_i.d_ready | rd_wait | rdback_wait; // We take over the TL-UL bus if there is a pending read or write for the RMW transaction. // TL-UL signals are selectively muxed below to reduce complexity and remove long timing @@ -224,22 +580,26 @@ module tlul_sram_byte import tlul_pkg::*; #( // to the address and data output since these may feed into RAM scrambling logic further // downstream. - // Write transactions for RMW. - if (wr_phase) begin + // Write transactions for RMW or reads when in readback mode. + if (wr_phase | rdback_phase | rdback_phase_wrreadback) begin tl_sram_o.a_valid = 1'b1; - tl_sram_o.a_opcode = PutFullData; - // Since we are performing a read-modify-write operation, - // we always access the entire word. - tl_sram_o.a_size = top_pkg::TL_SZW'(AccessSize); - tl_sram_o.a_mask = '{default: '1}; + // During a read-modify write, always access the entire word. + tl_sram_o.a_opcode = wr_phase ? PutFullData : Get; + // In either read-modify write or SRAM readback mode, use the mask, size and address + // of the original request. + tl_sram_o.a_size = + (wr_phase | rdback_phase_wrreadback) ? top_pkg::TL_SZW'(AccessSize) : held_data.a_size; + tl_sram_o.a_mask = + (wr_phase | rdback_phase_wrreadback) ? '{default: '1} : held_data.a_mask; // override with held / combined data. // need to use word aligned addresses here. tl_sram_o.a_address = held_data.a_address; - tl_sram_o.a_address[AccessSize-1:0] = '0; + tl_sram_o.a_address[AccessSize-1:0] = + (wr_phase | rdback_phase_wrreadback) ? '0 : held_data.a_address[AccessSize-1:0]; tl_sram_o.a_source = held_data.a_source; tl_sram_o.a_param = held_data.a_param; - tl_sram_o.a_data = combined_data; - tl_sram_o.a_user = combined_user; + tl_sram_o.a_data = wr_phase ? combined_data : '0; + tl_sram_o.a_user = wr_phase ? combined_user : '0; // Read transactions for RMW. end else if (rd_phase) begin // need to use word aligned addresses here. @@ -254,17 +614,16 @@ module tlul_sram_byte import tlul_pkg::*; #( tl_sram_o.a_valid = tl_i.a_valid & ~stall_host; tl_sram_o.a_opcode = Get; end + end else if (wait_phase) begin + // Delay the readback request to avoid that we are reading the holding + // register. + tl_sram_o.a_valid = 1'b0; end end // This assert is necessary for the casting of AccessSize. `ASSERT(TlulSramByteTlSize_A, top_pkg::TL_SZW >= $clog2(AccessSize + 1)) - logic unused_held_data; - assign unused_held_data = ^{held_data.a_address[AccessSize-1:0], - held_data.a_user.data_intg, - held_data.a_size}; - assign error_o = error_i & ~stall_host; logic size_fifo_rdy; @@ -297,7 +656,7 @@ module tlul_sram_byte import tlul_pkg::*; #( // when internal logic has taken over, do not show response to host during // read phase. During write phase, allow the host to see the completion. - tl_o.d_valid = tl_sram_i.d_valid & ~rd_wait; + tl_o.d_valid = tl_sram_i.d_valid & ~rd_wait & ~rdback_wait; // the size returned by tl_sram_i does not always correspond to the actual // transaction size in cases where a read modify write operation is @@ -316,13 +675,43 @@ module tlul_sram_byte import tlul_pkg::*; #( // when in wait for read, a successful response should move to write phase `ASSERT(ReadCompleteStateChange_A, (state_q == StWaitRd) && (pending_txn_cnt == 1) && sram_d_ack |=> state_q == StWriteCmd) - - assign rmw_in_progress_o = wr_phase; + // The readback logic assumes that any request on the readback channel will be instantly granted + // (i.e. after the initial SRAM read or write request from the external requester has been + // granted). This helps simplify the logic. It is guaranteed when connected to an SRAM as it + // produces no back pressure. When connected to a scrambled SRAM the key going invalid will + // cause a_ready to drop. The `compound_txn_in_progress_o` output is provided for this scenario. + // When asserted SRAM should not drop `a_ready` even if there is an invalid scrambling key. + `ASSERT(ReadbackAccessAlwaysGranted_A, (rdback_phase | rdback_phase_wrreadback) && !error_i + |-> tl_sram_i.a_ready) + + // The readback logic assumes the result of a read transaction issues for the readback will get + // an immediate response. This can be guaranteed when connected to a SRAM, see above comment. + `ASSERT(ReadbackDataImmediatelyAvailable_A, (state_q == StPassThru) && + mubi4_test_true_loose(rdback_en_q) && mubi4_test_true_loose(rdback_check_q) && + !error_i|-> tl_sram_i.d_valid) + + assign compound_txn_in_progress_o = wr_phase | rdback_phase | rdback_phase_wrreadback; end else begin : gen_no_integ_handling // In this case we pass everything just through. assign tl_sram_o = tl_i; assign tl_o = tl_sram_i; assign error_o = error_i; - assign rmw_in_progress_o = 1'b0; + assign alert_o = 1'b0; + assign compound_txn_in_progress_o = 1'b0; + + // Signal only used in readback mode. + mubi4_t unused_readback_en; + assign unused_readback_en = readback_en_i; + end + + // Signals only used for SVA. + logic unused_write_pending, unused_wr_collision; + assign unused_write_pending = write_pending_i; + assign unused_wr_collision = wr_collision_i; + + // EnableReadback requires that EnableIntg is on. + // EnableIntg can be used without EnableReadback. + `ASSERT_INIT(SramReadbackAndIntg, + (EnableReadback && EnableIntg) || (!EnableReadback && (EnableIntg || !EnableIntg))) endmodule // tlul_adapter_sram diff --git a/hw/ip/usbdev/rtl/usbdev.sv b/hw/ip/usbdev/rtl/usbdev.sv index f9f989371bd71..05b881846fd87 100644 --- a/hw/ip/usbdev/rtl/usbdev.sv +++ b/hw/ip/usbdev/rtl/usbdev.sv @@ -764,21 +764,25 @@ module usbdev .clk_i, .rst_ni, - .tl_i (tl_sram_h2d), - .tl_o (tl_sram_d2h), - .en_ifetch_i (prim_mubi_pkg::MuBi4False), - .req_o (sw_mem_a_req), - .req_type_o (), - .gnt_i (sw_mem_a_gnt), - .we_o (sw_mem_a_write), - .addr_o (sw_mem_a_addr), - .wdata_o (sw_mem_a_wdata), - .wmask_o (), // Not used - .intg_error_o (), - .rdata_i (sw_mem_a_rdata), - .rvalid_i (sw_mem_a_rvalid), - .rerror_i (sw_mem_a_rerror), - .rmw_in_progress_o() + .tl_i (tl_sram_h2d), + .tl_o (tl_sram_d2h), + .en_ifetch_i (prim_mubi_pkg::MuBi4False), + .req_o (sw_mem_a_req), + .req_type_o (), + .gnt_i (sw_mem_a_gnt), + .we_o (sw_mem_a_write), + .addr_o (sw_mem_a_addr), + .wdata_o (sw_mem_a_wdata), + .wmask_o (), // Not used + .intg_error_o (), + .rdata_i (sw_mem_a_rdata), + .rvalid_i (sw_mem_a_rvalid), + .rerror_i (sw_mem_a_rerror), + .compound_txn_in_progress_o (), + .readback_en_i (prim_mubi_pkg::MuBi4False), + .readback_error_o (), + .wr_collision_i (1'b0), + .write_pending_i (1'b0) ); // Single Port RAM implementation, which will award the `usb` port absolute priority and diff --git a/hw/ip_templates/flash_ctrl/rtl/flash_ctrl.sv.tpl b/hw/ip_templates/flash_ctrl/rtl/flash_ctrl.sv.tpl index 96ba41552180c..8ede59fd46986 100644 --- a/hw/ip_templates/flash_ctrl/rtl/flash_ctrl.sv.tpl +++ b/hw/ip_templates/flash_ctrl/rtl/flash_ctrl.sv.tpl @@ -529,21 +529,25 @@ module flash_ctrl ) u_to_prog_fifo ( .clk_i, .rst_ni, - .tl_i (prog_tl_h2d), - .tl_o (prog_tl_d2h), - .en_ifetch_i (prim_mubi_pkg::MuBi4False), - .req_o (sw_wvalid), - .req_type_o (), - .gnt_i (sw_wready), - .we_o (), - .addr_o (), - .wmask_o (), - .intg_error_o (), - .wdata_o (sw_wdata), - .rdata_i ('0), - .rvalid_i (1'b0), - .rerror_i (2'b0), - .rmw_in_progress_o() + .tl_i (prog_tl_h2d), + .tl_o (prog_tl_d2h), + .en_ifetch_i (prim_mubi_pkg::MuBi4False), + .req_o (sw_wvalid), + .req_type_o (), + .gnt_i (sw_wready), + .we_o (), + .addr_o (), + .wmask_o (), + .intg_error_o (), + .wdata_o (sw_wdata), + .rdata_i ('0), + .rvalid_i (1'b0), + .rerror_i (2'b0), + .compound_txn_in_progress_o (), + .readback_en_i (prim_mubi_pkg::MuBi4False), + .readback_error_o (), + .wr_collision_i (1'b0), + .write_pending_i (1'b0) ); prim_fifo_sync #( @@ -642,23 +646,27 @@ module flash_ctrl ) u_to_rd_fifo ( .clk_i, .rst_ni, - .tl_i (tl_win_h2d[1]), - .tl_o (tl_win_d2h[1]), - .en_ifetch_i (prim_mubi_pkg::MuBi4False), - .req_o (adapter_req), - .req_type_o (), + .tl_i (tl_win_h2d[1]), + .tl_o (tl_win_d2h[1]), + .en_ifetch_i (prim_mubi_pkg::MuBi4False), + .req_o (adapter_req), + .req_type_o (), // if there is no valid read operation, don't hang the // bus, just let things normally return - .gnt_i (sw_rfifo_rvalid | rd_no_op_d), - .we_o (), - .addr_o (), - .wmask_o (), - .wdata_o (), - .intg_error_o (adapter_fifo_err), - .rdata_i (sw_rfifo_rdata), - .rvalid_i (adapter_rvalid | rd_no_op_q), - .rerror_i ({rd_no_op_q, 1'b0}), - .rmw_in_progress_o() + .gnt_i (sw_rfifo_rvalid | rd_no_op_d), + .we_o (), + .addr_o (), + .wmask_o (), + .wdata_o (), + .intg_error_o (adapter_fifo_err), + .rdata_i (sw_rfifo_rdata), + .rvalid_i (adapter_rvalid | rd_no_op_q), + .rerror_i ({rd_no_op_q, 1'b0}), + .compound_txn_in_progress_o (), + .readback_en_i (prim_mubi_pkg::MuBi4False), + .readback_error_o (), + .wr_collision_i (1'b0), + .write_pending_i (1'b0) ); assign sw_rfifo_wen = sw_sel & rd_ctrl_wen; @@ -1302,21 +1310,25 @@ module flash_ctrl ) u_tl_adapter_eflash ( .clk_i, .rst_ni, - .tl_i (gate_tl_h2d), - .tl_o (gate_tl_d2h), - .en_ifetch_i (flash_exec_en), - .req_o (flash_host_req), - .req_type_o (), - .gnt_i (flash_host_req_rdy), - .we_o (), - .addr_o (flash_host_addr), - .wdata_o (), - .wmask_o (), - .intg_error_o (eflash_cmd_intg_err), - .rdata_i (flash_host_rdata), - .rvalid_i (flash_host_req_done), - .rerror_i ({flash_host_rderr,1'b0}), - .rmw_in_progress_o() + .tl_i (gate_tl_h2d), + .tl_o (gate_tl_d2h), + .en_ifetch_i (flash_exec_en), + .req_o (flash_host_req), + .req_type_o (), + .gnt_i (flash_host_req_rdy), + .we_o (), + .addr_o (flash_host_addr), + .wdata_o (), + .wmask_o (), + .intg_error_o (eflash_cmd_intg_err), + .rdata_i (flash_host_rdata), + .rvalid_i (flash_host_req_done), + .rerror_i ({flash_host_rderr,1'b0}), + .compound_txn_in_progress_o (), + .readback_en_i (prim_mubi_pkg::MuBi4False), + .readback_error_o (), + .wr_collision_i (1'b0), + .write_pending_i (1'b0) ); flash_phy #( diff --git a/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson b/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson index 4e055df25b096..e787552a8a041 100644 --- a/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson +++ b/hw/top_earlgrey/data/autogen/top_earlgrey.gen.hjson @@ -9521,7 +9521,7 @@ [ { base_addr: 0x411c0000 - size_byte: 0x20 + size_byte: 0x40 } ] xbar: false @@ -10341,7 +10341,7 @@ [ { base_addr: 0x40500000 - size_byte: 0x20 + size_byte: 0x40 } ] xbar: false diff --git a/hw/top_earlgrey/dv/autogen/xbar_env_pkg__params.sv b/hw/top_earlgrey/dv/autogen/xbar_env_pkg__params.sv index 9314ccbc3af0d..6f77551fa321d 100644 --- a/hw/top_earlgrey/dv/autogen/xbar_env_pkg__params.sv +++ b/hw/top_earlgrey/dv/autogen/xbar_env_pkg__params.sv @@ -71,7 +71,7 @@ tl_device_t xbar_devices[$] = '{ '{32'h411f0000, 32'h411f00ff} }}, '{"sram_ctrl_main__regs", '{ - '{32'h411c0000, 32'h411c001f} + '{32'h411c0000, 32'h411c003f} }}, '{"sram_ctrl_main__ram", '{ '{32'h10000000, 32'h1001ffff} @@ -140,7 +140,7 @@ tl_device_t xbar_devices[$] = '{ '{32'h40150000, 32'h401507ff} }}, '{"sram_ctrl_ret_aon__regs", '{ - '{32'h40500000, 32'h4050001f} + '{32'h40500000, 32'h4050003f} }}, '{"sram_ctrl_ret_aon__ram", '{ '{32'h40600000, 32'h40600fff} diff --git a/hw/top_earlgrey/dv/autogen/xbar_tgl_excl.cfg b/hw/top_earlgrey/dv/autogen/xbar_tgl_excl.cfg index ea1af34249527..2733827ec12d1 100644 --- a/hw/top_earlgrey/dv/autogen/xbar_tgl_excl.cfg +++ b/hw/top_earlgrey/dv/autogen/xbar_tgl_excl.cfg @@ -105,7 +105,7 @@ -node tb.dut*.u_rv_core_ibex cfg_tl_*i.a_address[23:21] -node tb.dut*.u_rv_core_ibex cfg_tl_*i.a_address[29:25] -node tb.dut*.u_rv_core_ibex cfg_tl_*i.a_address[31:31] --node tb.dut*.u_sram_ctrl_main regs_tl_*i.a_address[17:5] +-node tb.dut*.u_sram_ctrl_main regs_tl_*i.a_address[17:6] -node tb.dut*.u_sram_ctrl_main regs_tl_*i.a_address[23:21] -node tb.dut*.u_sram_ctrl_main regs_tl_*i.a_address[29:25] -node tb.dut*.u_sram_ctrl_main regs_tl_*i.a_address[31:31] @@ -188,7 +188,7 @@ -node tb.dut*.u_alert_handler tl_*i.a_address[19:19] -node tb.dut*.u_alert_handler tl_*i.a_address[29:21] -node tb.dut*.u_alert_handler tl_*i.a_address[31:31] --node tb.dut*.u_sram_ctrl_ret_aon regs_tl_*i.a_address[19:5] +-node tb.dut*.u_sram_ctrl_ret_aon regs_tl_*i.a_address[19:6] -node tb.dut*.u_sram_ctrl_ret_aon regs_tl_*i.a_address[21:21] -node tb.dut*.u_sram_ctrl_ret_aon regs_tl_*i.a_address[29:23] -node tb.dut*.u_sram_ctrl_ret_aon regs_tl_*i.a_address[31:31] diff --git a/hw/top_earlgrey/ip/xbar_main/data/autogen/xbar_main.gen.hjson b/hw/top_earlgrey/ip/xbar_main/data/autogen/xbar_main.gen.hjson index ac17ac83ac3c7..daa2dd492ded1 100644 --- a/hw/top_earlgrey/ip/xbar_main/data/autogen/xbar_main.gen.hjson +++ b/hw/top_earlgrey/ip/xbar_main/data/autogen/xbar_main.gen.hjson @@ -593,7 +593,7 @@ [ { base_addr: 0x411c0000 - size_byte: 0x20 + size_byte: 0x40 } ] xbar: false diff --git a/hw/top_earlgrey/ip/xbar_main/dv/autogen/xbar_cover.cfg b/hw/top_earlgrey/ip/xbar_main/dv/autogen/xbar_cover.cfg index 9d2f9823bf464..528f79c929b33 100644 --- a/hw/top_earlgrey/ip/xbar_main/dv/autogen/xbar_cover.cfg +++ b/hw/top_earlgrey/ip/xbar_main/dv/autogen/xbar_cover.cfg @@ -103,7 +103,7 @@ -node tb.dut tl_rv_core_ibex__cfg_o.a_address[23:21] -node tb.dut tl_rv_core_ibex__cfg_o.a_address[29:25] -node tb.dut tl_rv_core_ibex__cfg_o.a_address[31:31] --node tb.dut tl_sram_ctrl_main__regs_o.a_address[17:5] +-node tb.dut tl_sram_ctrl_main__regs_o.a_address[17:6] -node tb.dut tl_sram_ctrl_main__regs_o.a_address[23:21] -node tb.dut tl_sram_ctrl_main__regs_o.a_address[29:25] -node tb.dut tl_sram_ctrl_main__regs_o.a_address[31:31] diff --git a/hw/top_earlgrey/ip/xbar_main/dv/autogen/xbar_env_pkg__params.sv b/hw/top_earlgrey/ip/xbar_main/dv/autogen/xbar_env_pkg__params.sv index 07219e05f5c8a..a6c1a5357b391 100644 --- a/hw/top_earlgrey/ip/xbar_main/dv/autogen/xbar_env_pkg__params.sv +++ b/hw/top_earlgrey/ip/xbar_main/dv/autogen/xbar_env_pkg__params.sv @@ -75,7 +75,7 @@ tl_device_t xbar_devices[$] = '{ '{32'h411f0000, 32'h411f00ff} }}, '{"sram_ctrl_main__regs", '{ - '{32'h411c0000, 32'h411c001f} + '{32'h411c0000, 32'h411c003f} }}, '{"sram_ctrl_main__ram", '{ '{32'h10000000, 32'h1001ffff} diff --git a/hw/top_earlgrey/ip/xbar_main/rtl/autogen/tl_main_pkg.sv b/hw/top_earlgrey/ip/xbar_main/rtl/autogen/tl_main_pkg.sv index 15f826b745202..22a1a4bcaf6ac 100644 --- a/hw/top_earlgrey/ip/xbar_main/rtl/autogen/tl_main_pkg.sv +++ b/hw/top_earlgrey/ip/xbar_main/rtl/autogen/tl_main_pkg.sv @@ -59,7 +59,7 @@ package tl_main_pkg; localparam logic [31:0] ADDR_MASK_OTBN = 32'h 0000ffff; localparam logic [31:0] ADDR_MASK_KEYMGR = 32'h 000000ff; localparam logic [31:0] ADDR_MASK_RV_CORE_IBEX__CFG = 32'h 000000ff; - localparam logic [31:0] ADDR_MASK_SRAM_CTRL_MAIN__REGS = 32'h 0000001f; + localparam logic [31:0] ADDR_MASK_SRAM_CTRL_MAIN__REGS = 32'h 0000003f; localparam logic [31:0] ADDR_MASK_SRAM_CTRL_MAIN__RAM = 32'h 0001ffff; localparam int N_HOST = 3; diff --git a/hw/top_earlgrey/ip/xbar_peri/data/autogen/xbar_peri.gen.hjson b/hw/top_earlgrey/ip/xbar_peri/data/autogen/xbar_peri.gen.hjson index 08c6fbfb1c274..9563cf0e595c9 100644 --- a/hw/top_earlgrey/ip/xbar_peri/data/autogen/xbar_peri.gen.hjson +++ b/hw/top_earlgrey/ip/xbar_peri/data/autogen/xbar_peri.gen.hjson @@ -466,7 +466,7 @@ [ { base_addr: 0x40500000 - size_byte: 0x20 + size_byte: 0x40 } ] xbar: false diff --git a/hw/top_earlgrey/ip/xbar_peri/dv/autogen/xbar_cover.cfg b/hw/top_earlgrey/ip/xbar_peri/dv/autogen/xbar_cover.cfg index b134e50236140..827fa1a16b512 100644 --- a/hw/top_earlgrey/ip/xbar_peri/dv/autogen/xbar_cover.cfg +++ b/hw/top_earlgrey/ip/xbar_peri/dv/autogen/xbar_cover.cfg @@ -98,7 +98,7 @@ -node tb.dut tl_alert_handler_o.a_address[19:19] -node tb.dut tl_alert_handler_o.a_address[29:21] -node tb.dut tl_alert_handler_o.a_address[31:31] --node tb.dut tl_sram_ctrl_ret_aon__regs_o.a_address[19:5] +-node tb.dut tl_sram_ctrl_ret_aon__regs_o.a_address[19:6] -node tb.dut tl_sram_ctrl_ret_aon__regs_o.a_address[21:21] -node tb.dut tl_sram_ctrl_ret_aon__regs_o.a_address[29:23] -node tb.dut tl_sram_ctrl_ret_aon__regs_o.a_address[31:31] diff --git a/hw/top_earlgrey/ip/xbar_peri/dv/autogen/xbar_env_pkg__params.sv b/hw/top_earlgrey/ip/xbar_peri/dv/autogen/xbar_env_pkg__params.sv index a1847207d1460..66ea147da0ae1 100644 --- a/hw/top_earlgrey/ip/xbar_peri/dv/autogen/xbar_env_pkg__params.sv +++ b/hw/top_earlgrey/ip/xbar_peri/dv/autogen/xbar_env_pkg__params.sv @@ -71,7 +71,7 @@ tl_device_t xbar_devices[$] = '{ '{32'h40150000, 32'h401507ff} }}, '{"sram_ctrl_ret_aon__regs", '{ - '{32'h40500000, 32'h4050001f} + '{32'h40500000, 32'h4050003f} }}, '{"sram_ctrl_ret_aon__ram", '{ '{32'h40600000, 32'h40600fff} diff --git a/hw/top_earlgrey/ip/xbar_peri/rtl/autogen/tl_peri_pkg.sv b/hw/top_earlgrey/ip/xbar_peri/rtl/autogen/tl_peri_pkg.sv index 690c8f3e7c277..b9a1399a55274 100644 --- a/hw/top_earlgrey/ip/xbar_peri/rtl/autogen/tl_peri_pkg.sv +++ b/hw/top_earlgrey/ip/xbar_peri/rtl/autogen/tl_peri_pkg.sv @@ -55,7 +55,7 @@ package tl_peri_pkg; localparam logic [31:0] ADDR_MASK_LC_CTRL = 32'h 000000ff; localparam logic [31:0] ADDR_MASK_SENSOR_CTRL_AON = 32'h 0000007f; localparam logic [31:0] ADDR_MASK_ALERT_HANDLER = 32'h 000007ff; - localparam logic [31:0] ADDR_MASK_SRAM_CTRL_RET_AON__REGS = 32'h 0000001f; + localparam logic [31:0] ADDR_MASK_SRAM_CTRL_RET_AON__REGS = 32'h 0000003f; localparam logic [31:0] ADDR_MASK_SRAM_CTRL_RET_AON__RAM = 32'h 00000fff; localparam logic [31:0] ADDR_MASK_AON_TIMER_AON = 32'h 0000003f; localparam logic [31:0] ADDR_MASK_SYSRST_CTRL_AON = 32'h 000000ff; diff --git a/hw/top_earlgrey/ip_autogen/flash_ctrl/rtl/flash_ctrl.sv b/hw/top_earlgrey/ip_autogen/flash_ctrl/rtl/flash_ctrl.sv index d2fec77571f8c..3fc172d93cead 100644 --- a/hw/top_earlgrey/ip_autogen/flash_ctrl/rtl/flash_ctrl.sv +++ b/hw/top_earlgrey/ip_autogen/flash_ctrl/rtl/flash_ctrl.sv @@ -530,21 +530,25 @@ module flash_ctrl ) u_to_prog_fifo ( .clk_i, .rst_ni, - .tl_i (prog_tl_h2d), - .tl_o (prog_tl_d2h), - .en_ifetch_i (prim_mubi_pkg::MuBi4False), - .req_o (sw_wvalid), - .req_type_o (), - .gnt_i (sw_wready), - .we_o (), - .addr_o (), - .wmask_o (), - .intg_error_o (), - .wdata_o (sw_wdata), - .rdata_i ('0), - .rvalid_i (1'b0), - .rerror_i (2'b0), - .rmw_in_progress_o() + .tl_i (prog_tl_h2d), + .tl_o (prog_tl_d2h), + .en_ifetch_i (prim_mubi_pkg::MuBi4False), + .req_o (sw_wvalid), + .req_type_o (), + .gnt_i (sw_wready), + .we_o (), + .addr_o (), + .wmask_o (), + .intg_error_o (), + .wdata_o (sw_wdata), + .rdata_i ('0), + .rvalid_i (1'b0), + .rerror_i (2'b0), + .compound_txn_in_progress_o (), + .readback_en_i (prim_mubi_pkg::MuBi4False), + .readback_error_o (), + .wr_collision_i (1'b0), + .write_pending_i (1'b0) ); prim_fifo_sync #( @@ -643,23 +647,27 @@ module flash_ctrl ) u_to_rd_fifo ( .clk_i, .rst_ni, - .tl_i (tl_win_h2d[1]), - .tl_o (tl_win_d2h[1]), - .en_ifetch_i (prim_mubi_pkg::MuBi4False), - .req_o (adapter_req), - .req_type_o (), + .tl_i (tl_win_h2d[1]), + .tl_o (tl_win_d2h[1]), + .en_ifetch_i (prim_mubi_pkg::MuBi4False), + .req_o (adapter_req), + .req_type_o (), // if there is no valid read operation, don't hang the // bus, just let things normally return - .gnt_i (sw_rfifo_rvalid | rd_no_op_d), - .we_o (), - .addr_o (), - .wmask_o (), - .wdata_o (), - .intg_error_o (adapter_fifo_err), - .rdata_i (sw_rfifo_rdata), - .rvalid_i (adapter_rvalid | rd_no_op_q), - .rerror_i ({rd_no_op_q, 1'b0}), - .rmw_in_progress_o() + .gnt_i (sw_rfifo_rvalid | rd_no_op_d), + .we_o (), + .addr_o (), + .wmask_o (), + .wdata_o (), + .intg_error_o (adapter_fifo_err), + .rdata_i (sw_rfifo_rdata), + .rvalid_i (adapter_rvalid | rd_no_op_q), + .rerror_i ({rd_no_op_q, 1'b0}), + .compound_txn_in_progress_o (), + .readback_en_i (prim_mubi_pkg::MuBi4False), + .readback_error_o (), + .wr_collision_i (1'b0), + .write_pending_i (1'b0) ); assign sw_rfifo_wen = sw_sel & rd_ctrl_wen; @@ -1303,21 +1311,25 @@ module flash_ctrl ) u_tl_adapter_eflash ( .clk_i, .rst_ni, - .tl_i (gate_tl_h2d), - .tl_o (gate_tl_d2h), - .en_ifetch_i (flash_exec_en), - .req_o (flash_host_req), - .req_type_o (), - .gnt_i (flash_host_req_rdy), - .we_o (), - .addr_o (flash_host_addr), - .wdata_o (), - .wmask_o (), - .intg_error_o (eflash_cmd_intg_err), - .rdata_i (flash_host_rdata), - .rvalid_i (flash_host_req_done), - .rerror_i ({flash_host_rderr,1'b0}), - .rmw_in_progress_o() + .tl_i (gate_tl_h2d), + .tl_o (gate_tl_d2h), + .en_ifetch_i (flash_exec_en), + .req_o (flash_host_req), + .req_type_o (), + .gnt_i (flash_host_req_rdy), + .we_o (), + .addr_o (flash_host_addr), + .wdata_o (), + .wmask_o (), + .intg_error_o (eflash_cmd_intg_err), + .rdata_i (flash_host_rdata), + .rvalid_i (flash_host_req_done), + .rerror_i ({flash_host_rderr,1'b0}), + .compound_txn_in_progress_o (), + .readback_en_i (prim_mubi_pkg::MuBi4False), + .readback_error_o (), + .wr_collision_i (1'b0), + .write_pending_i (1'b0) ); flash_phy #( diff --git a/hw/top_earlgrey/rtl/autogen/top_earlgrey_pkg.sv b/hw/top_earlgrey/rtl/autogen/top_earlgrey_pkg.sv index 77c1a3ade8ec7..c0bf0ab650faf 100644 --- a/hw/top_earlgrey/rtl/autogen/top_earlgrey_pkg.sv +++ b/hw/top_earlgrey/rtl/autogen/top_earlgrey_pkg.sv @@ -299,7 +299,7 @@ package top_earlgrey_pkg; /** * Peripheral size in bytes for regs device on sram_ctrl_ret_aon in top earlgrey. */ - parameter int unsigned TOP_EARLGREY_SRAM_CTRL_RET_AON_REGS_SIZE_BYTES = 32'h20; + parameter int unsigned TOP_EARLGREY_SRAM_CTRL_RET_AON_REGS_SIZE_BYTES = 32'h40; /** * Peripheral base address for ram device on sram_ctrl_ret_aon in top earlgrey. @@ -469,7 +469,7 @@ package top_earlgrey_pkg; /** * Peripheral size in bytes for regs device on sram_ctrl_main in top earlgrey. */ - parameter int unsigned TOP_EARLGREY_SRAM_CTRL_MAIN_REGS_SIZE_BYTES = 32'h20; + parameter int unsigned TOP_EARLGREY_SRAM_CTRL_MAIN_REGS_SIZE_BYTES = 32'h40; /** * Peripheral base address for ram device on sram_ctrl_main in top earlgrey. diff --git a/hw/top_earlgrey/sw/autogen/chip/top_earlgrey.rs b/hw/top_earlgrey/sw/autogen/chip/top_earlgrey.rs index be8380bdfa2c4..1cdfec44238d0 100644 --- a/hw/top_earlgrey/sw/autogen/chip/top_earlgrey.rs +++ b/hw/top_earlgrey/sw/autogen/chip/top_earlgrey.rs @@ -425,7 +425,7 @@ pub const SRAM_CTRL_RET_AON_REGS_BASE_ADDR: usize = 0x40500000; /// memory-mapped registers associated with this peripheral should have an /// address between #SRAM_CTRL_RET_AON_REGS_BASE_ADDR and /// `SRAM_CTRL_RET_AON_REGS_BASE_ADDR + SRAM_CTRL_RET_AON_REGS_SIZE_BYTES`. -pub const SRAM_CTRL_RET_AON_REGS_SIZE_BYTES: usize = 0x20; +pub const SRAM_CTRL_RET_AON_REGS_SIZE_BYTES: usize = 0x40; /// Peripheral base address for ram device on sram_ctrl_ret_aon in top earlgrey. /// @@ -663,7 +663,7 @@ pub const SRAM_CTRL_MAIN_REGS_BASE_ADDR: usize = 0x411C0000; /// memory-mapped registers associated with this peripheral should have an /// address between #SRAM_CTRL_MAIN_REGS_BASE_ADDR and /// `SRAM_CTRL_MAIN_REGS_BASE_ADDR + SRAM_CTRL_MAIN_REGS_SIZE_BYTES`. -pub const SRAM_CTRL_MAIN_REGS_SIZE_BYTES: usize = 0x20; +pub const SRAM_CTRL_MAIN_REGS_SIZE_BYTES: usize = 0x40; /// Peripheral base address for ram device on sram_ctrl_main in top earlgrey. /// diff --git a/hw/top_earlgrey/sw/autogen/top_earlgrey.h b/hw/top_earlgrey/sw/autogen/top_earlgrey.h index 8883620a0d407..4bb647d70900b 100644 --- a/hw/top_earlgrey/sw/autogen/top_earlgrey.h +++ b/hw/top_earlgrey/sw/autogen/top_earlgrey.h @@ -545,7 +545,7 @@ extern "C" { * address between #TOP_EARLGREY_SRAM_CTRL_RET_AON_REGS_BASE_ADDR and * `TOP_EARLGREY_SRAM_CTRL_RET_AON_REGS_BASE_ADDR + TOP_EARLGREY_SRAM_CTRL_RET_AON_REGS_SIZE_BYTES`. */ -#define TOP_EARLGREY_SRAM_CTRL_RET_AON_REGS_SIZE_BYTES 0x20u +#define TOP_EARLGREY_SRAM_CTRL_RET_AON_REGS_SIZE_BYTES 0x40u /** * Peripheral base address for ram device on sram_ctrl_ret_aon in top earlgrey. @@ -851,7 +851,7 @@ extern "C" { * address between #TOP_EARLGREY_SRAM_CTRL_MAIN_REGS_BASE_ADDR and * `TOP_EARLGREY_SRAM_CTRL_MAIN_REGS_BASE_ADDR + TOP_EARLGREY_SRAM_CTRL_MAIN_REGS_SIZE_BYTES`. */ -#define TOP_EARLGREY_SRAM_CTRL_MAIN_REGS_SIZE_BYTES 0x20u +#define TOP_EARLGREY_SRAM_CTRL_MAIN_REGS_SIZE_BYTES 0x40u /** * Peripheral base address for ram device on sram_ctrl_main in top earlgrey. diff --git a/hw/top_earlgrey/sw/autogen/top_earlgrey_memory.h b/hw/top_earlgrey/sw/autogen/top_earlgrey_memory.h index f430969fb6112..ad2b0a1d5a2c0 100644 --- a/hw/top_earlgrey/sw/autogen/top_earlgrey_memory.h +++ b/hw/top_earlgrey/sw/autogen/top_earlgrey_memory.h @@ -555,7 +555,7 @@ * address between #TOP_EARLGREY_SRAM_CTRL_RET_AON_REGS_BASE_ADDR and * `TOP_EARLGREY_SRAM_CTRL_RET_AON_REGS_BASE_ADDR + TOP_EARLGREY_SRAM_CTRL_RET_AON_REGS_SIZE_BYTES`. */ -#define TOP_EARLGREY_SRAM_CTRL_RET_AON_REGS_SIZE_BYTES 0x20 +#define TOP_EARLGREY_SRAM_CTRL_RET_AON_REGS_SIZE_BYTES 0x40 /** * Peripheral base address for ram device on sram_ctrl_ret_aon in top earlgrey. * @@ -844,7 +844,7 @@ * address between #TOP_EARLGREY_SRAM_CTRL_MAIN_REGS_BASE_ADDR and * `TOP_EARLGREY_SRAM_CTRL_MAIN_REGS_BASE_ADDR + TOP_EARLGREY_SRAM_CTRL_MAIN_REGS_SIZE_BYTES`. */ -#define TOP_EARLGREY_SRAM_CTRL_MAIN_REGS_SIZE_BYTES 0x20 +#define TOP_EARLGREY_SRAM_CTRL_MAIN_REGS_SIZE_BYTES 0x40 /** * Peripheral base address for ram device on sram_ctrl_main in top earlgrey. * diff --git a/hw/vendor/lowrisc_ibex.vendor.hjson b/hw/vendor/lowrisc_ibex.vendor.hjson index f3d531d0ccfd3..c9a2aeb65255a 100644 --- a/hw/vendor/lowrisc_ibex.vendor.hjson +++ b/hw/vendor/lowrisc_ibex.vendor.hjson @@ -19,7 +19,11 @@ patch_dir: "dv" } "lint", - "rtl", + { + from: "rtl", + to: "rtl", + patch_dir: "rtl" + } "syn", "util", "vendor/google_riscv-dv", diff --git a/hw/vendor/lowrisc_ibex/rtl/ibex_top.sv b/hw/vendor/lowrisc_ibex/rtl/ibex_top.sv index 69c7cb7bba38a..df1e607ac4a1e 100644 --- a/hw/vendor/lowrisc_ibex/rtl/ibex_top.sv +++ b/hw/vendor/lowrisc_ibex/rtl/ibex_top.sv @@ -571,24 +571,26 @@ module ibex_top import ibex_pkg::*; #( .clk_i, .rst_ni, - .key_valid_i (scramble_key_valid_q), - .key_i (scramble_key_q), - .nonce_i (scramble_nonce_q), - - .req_i (ic_tag_req[way]), - - .gnt_o (), - .write_i (ic_tag_write), - .addr_i (ic_tag_addr), - .wdata_i (ic_tag_wdata), - .wmask_i ({TagSizeECC{1'b1}}), - .intg_error_i(1'b0), - - .rdata_o (ic_tag_rdata[way]), - .rvalid_o (), - .raddr_o (), - .rerror_o (), - .cfg_i (ram_cfg_i) + .key_valid_i (scramble_key_valid_q), + .key_i (scramble_key_q), + .nonce_i (scramble_nonce_q), + + .req_i (ic_tag_req[way]), + + .gnt_o (), + .write_i (ic_tag_write), + .addr_i (ic_tag_addr), + .wdata_i (ic_tag_wdata), + .wmask_i ({TagSizeECC{1'b1}}), + .intg_error_i (1'b0), + + .rdata_o (ic_tag_rdata[way]), + .rvalid_o (), + .raddr_o (), + .rerror_o (), + .cfg_i (ram_cfg_i), + .wr_collision_o (), + .write_pending_o () ); // Data RAM instantiation @@ -604,24 +606,26 @@ module ibex_top import ibex_pkg::*; #( .clk_i, .rst_ni, - .key_valid_i (scramble_key_valid_q), - .key_i (scramble_key_q), - .nonce_i (scramble_nonce_q), - - .req_i (ic_data_req[way]), - - .gnt_o (), - .write_i (ic_data_write), - .addr_i (ic_data_addr), - .wdata_i (ic_data_wdata), - .wmask_i ({LineSizeECC{1'b1}}), - .intg_error_i(1'b0), - - .rdata_o (ic_data_rdata[way]), - .rvalid_o (), - .raddr_o (), - .rerror_o (), - .cfg_i (ram_cfg_i) + .key_valid_i (scramble_key_valid_q), + .key_i (scramble_key_q), + .nonce_i (scramble_nonce_q), + + .req_i (ic_data_req[way]), + + .gnt_o (), + .write_i (ic_data_write), + .addr_i (ic_data_addr), + .wdata_i (ic_data_wdata), + .wmask_i ({LineSizeECC{1'b1}}), + .intg_error_i (1'b0), + + .rdata_o (ic_data_rdata[way]), + .rvalid_o (), + .raddr_o (), + .rerror_o (), + .cfg_i (ram_cfg_i), + .wr_collision_o (), + .write_pending_o () ); `ifdef INC_ASSERT diff --git a/hw/vendor/patches/lowrisc_ibex/rtl/0001-rtl-Add-new-ports-to-prim-ram-1p-scr.patch b/hw/vendor/patches/lowrisc_ibex/rtl/0001-rtl-Add-new-ports-to-prim-ram-1p-scr.patch new file mode 100644 index 0000000000000..03a467c14b9b6 --- /dev/null +++ b/hw/vendor/patches/lowrisc_ibex/rtl/0001-rtl-Add-new-ports-to-prim-ram-1p-scr.patch @@ -0,0 +1,106 @@ +commit ce590553992529dd1ae3e8d984255abe2a8d631d +Author: Pascal Nasahl +Date: Tue May 21 07:45:37 2024 +0000 + + [PATCH] [rtl] Add new output ports to prim_ram_1p_scr + + This patch adds the new output ports `wr_collision_o` and + `write_pending_o` to the `prim_ram_1p_scr` instantiations inside + `ibex_top`. + + Signed-off-by: Pascal Nasahl + +diff --git a/ibex_top.sv b/ibex_top.sv +index 69c7cb7bba..df1e607ac4 100644 +--- a/ibex_top.sv ++++ b/ibex_top.sv +@@ -571,24 +571,26 @@ module ibex_top import ibex_pkg::*; #( + .clk_i, + .rst_ni, + +- .key_valid_i (scramble_key_valid_q), +- .key_i (scramble_key_q), +- .nonce_i (scramble_nonce_q), +- +- .req_i (ic_tag_req[way]), +- +- .gnt_o (), +- .write_i (ic_tag_write), +- .addr_i (ic_tag_addr), +- .wdata_i (ic_tag_wdata), +- .wmask_i ({TagSizeECC{1'b1}}), +- .intg_error_i(1'b0), +- +- .rdata_o (ic_tag_rdata[way]), +- .rvalid_o (), +- .raddr_o (), +- .rerror_o (), +- .cfg_i (ram_cfg_i) ++ .key_valid_i (scramble_key_valid_q), ++ .key_i (scramble_key_q), ++ .nonce_i (scramble_nonce_q), ++ ++ .req_i (ic_tag_req[way]), ++ ++ .gnt_o (), ++ .write_i (ic_tag_write), ++ .addr_i (ic_tag_addr), ++ .wdata_i (ic_tag_wdata), ++ .wmask_i ({TagSizeECC{1'b1}}), ++ .intg_error_i (1'b0), ++ ++ .rdata_o (ic_tag_rdata[way]), ++ .rvalid_o (), ++ .raddr_o (), ++ .rerror_o (), ++ .cfg_i (ram_cfg_i), ++ .wr_collision_o (), ++ .write_pending_o () + ); + + // Data RAM instantiation +@@ -604,24 +606,26 @@ module ibex_top import ibex_pkg::*; #( + .clk_i, + .rst_ni, + +- .key_valid_i (scramble_key_valid_q), +- .key_i (scramble_key_q), +- .nonce_i (scramble_nonce_q), +- +- .req_i (ic_data_req[way]), +- +- .gnt_o (), +- .write_i (ic_data_write), +- .addr_i (ic_data_addr), +- .wdata_i (ic_data_wdata), +- .wmask_i ({LineSizeECC{1'b1}}), +- .intg_error_i(1'b0), +- +- .rdata_o (ic_data_rdata[way]), +- .rvalid_o (), +- .raddr_o (), +- .rerror_o (), +- .cfg_i (ram_cfg_i) ++ .key_valid_i (scramble_key_valid_q), ++ .key_i (scramble_key_q), ++ .nonce_i (scramble_nonce_q), ++ ++ .req_i (ic_data_req[way]), ++ ++ .gnt_o (), ++ .write_i (ic_data_write), ++ .addr_i (ic_data_addr), ++ .wdata_i (ic_data_wdata), ++ .wmask_i ({LineSizeECC{1'b1}}), ++ .intg_error_i (1'b0), ++ ++ .rdata_o (ic_data_rdata[way]), ++ .rvalid_o (), ++ .raddr_o (), ++ .rerror_o (), ++ .cfg_i (ram_cfg_i), ++ .wr_collision_o (), ++ .write_pending_o () + ); + + `ifdef INC_ASSERT diff --git a/util/reggen/countermeasure.py b/util/reggen/countermeasure.py index 8891d5af6f03a..48328ffc9a6e5 100644 --- a/util/reggen/countermeasure.py +++ b/util/reggen/countermeasure.py @@ -44,6 +44,7 @@ 'SHADOW', 'SCRAMBLE', 'INTEGRITY', + 'READBACK', 'CONSISTENCY', 'DIGEST', 'LC_GATED',