[tlul] Add memory transmission integrity checks
- Add optional integrity generation / checks into tlul_adapter_sram
- Update sram_scr to make use of the integrity error information
Signed-off-by: Timothy Chen <timothytim@google.com>
[top] Fix for englishbreakfast
Signed-off-by: Timothy Chen <timothytim@google.com>
[all] update for intg_error_o port
- Create alert from sram controllers
- Unused for all other modules
Signed-off-by: Timothy Chen <timothytim@google.com>
[top] Auto generate files
Signed-off-by: Timothy Chen <timothytim@google.com>
[sram dv] Add extra alert
Signed-off-by: Timothy Chen <timothytim@google.com>
diff --git a/hw/ip/flash_ctrl/data/flash_ctrl.sv.tpl b/hw/ip/flash_ctrl/data/flash_ctrl.sv.tpl
index 1e18d37..198c57a 100644
--- a/hw/ip/flash_ctrl/data/flash_ctrl.sv.tpl
+++ b/hw/ip/flash_ctrl/data/flash_ctrl.sv.tpl
@@ -445,6 +445,7 @@
.we_o (sw_wen),
.addr_o (),
.wmask_o (),
+ .intg_error_o(),
.wdata_o (sw_wdata),
.rdata_i (BusWidth'(0)),
.rvalid_i (1'b0),
@@ -529,6 +530,7 @@
.addr_o (),
.wmask_o (),
.wdata_o (),
+ .intg_error_o(),
.rdata_i (rd_fifo_rdata),
.rvalid_i (adapter_rvalid),
.rerror_i (2'b0)
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl.sv
index 30bc0e3..a8ba13a 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl.sv
@@ -445,6 +445,7 @@
.we_o (sw_wen),
.addr_o (),
.wmask_o (),
+ .intg_error_o(),
.wdata_o (sw_wdata),
.rdata_i (BusWidth'(0)),
.rvalid_i (1'b0),
@@ -529,6 +530,7 @@
.addr_o (),
.wmask_o (),
.wdata_o (),
+ .intg_error_o(),
.rdata_i (rd_fifo_rdata),
.rvalid_i (adapter_rvalid),
.rerror_i (2'b0)
diff --git a/hw/ip/hmac/rtl/hmac.sv b/hw/ip/hmac/rtl/hmac.sv
index 26dda29..9925090 100644
--- a/hw/ip/hmac/rtl/hmac.sv
+++ b/hw/ip/hmac/rtl/hmac.sv
@@ -300,6 +300,7 @@
.addr_o (msg_fifo_addr ), // 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)
diff --git a/hw/ip/kmac/rtl/kmac.sv b/hw/ip/kmac/rtl/kmac.sv
index aa9452b..ea75505 100644
--- a/hw/ip/kmac/rtl/kmac.sv
+++ b/hw/ip/kmac/rtl/kmac.sv
@@ -649,6 +649,7 @@
.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)
diff --git a/hw/ip/kmac/rtl/kmac_staterd.sv b/hw/ip/kmac/rtl/kmac_staterd.sv
index a31ae99..e31c8a8 100644
--- a/hw/ip/kmac/rtl/kmac_staterd.sv
+++ b/hw/ip/kmac/rtl/kmac_staterd.sv
@@ -71,6 +71,7 @@
.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)
diff --git a/hw/ip/otbn/rtl/otbn.sv b/hw/ip/otbn/rtl/otbn.sv
index 2576efd..521e015 100644
--- a/hw/ip/otbn/rtl/otbn.sv
+++ b/hw/ip/otbn/rtl/otbn.sv
@@ -183,6 +183,7 @@
.addr_o (imem_index_bus ),
.wdata_o (imem_wdata_bus ),
.wmask_o (imem_wmask_bus ),
+ .intg_error_o( ),
.rdata_i (imem_rdata_bus ),
.rvalid_i (imem_rvalid_bus),
.rerror_i (imem_rerror_bus)
@@ -317,6 +318,7 @@
.addr_o (dmem_index_bus ),
.wdata_o (dmem_wdata_bus ),
.wmask_o (dmem_wmask_bus ),
+ .intg_error_o( ),
.rdata_i (dmem_rdata_bus ),
.rvalid_i (dmem_rvalid_bus),
.rerror_i (dmem_rerror_bus)
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
index 594dee8..6d98bec 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
@@ -194,6 +194,7 @@
.addr_o ( tlul_addr ),
.wdata_o ( ), // unused
.wmask_o ( ), // unused
+ .intg_error_o( ),
.rdata_i ( tlul_rdata ),
.rvalid_i ( tlul_rvalid ),
.rerror_i ( tlul_rerror )
diff --git a/hw/ip/prim/rtl/prim_ram_1p_scr.sv b/hw/ip/prim/rtl/prim_ram_1p_scr.sv
index faaa307..f3132a6 100644
--- a/hw/ip/prim/rtl/prim_ram_1p_scr.sv
+++ b/hw/ip/prim/rtl/prim_ram_1p_scr.sv
@@ -75,10 +75,16 @@
input [AddrWidth-1:0] addr_i,
input [Width-1:0] wdata_i,
input [Width-1:0] wmask_i, // Needs to be byte-aligned for parity
+ // The incoming transaction contains an integrity error and the module should alter
+ // its behavior appropriately.
+ // On integrity errors, the primitive reverses the bit-order of the nonce and surpresses
+ // any real transaction to the memory.
+ input intg_error_i,
output logic [Width-1:0] rdata_o,
output logic rvalid_o, // Read response (rdata_o) is valid
output logic [1:0] rerror_o, // Bit1: Uncorrectable, Bit0: Correctable
output logic [31:0] raddr_o, // Read address for error reporting.
+ output logic intg_error_o,
// config
input [CfgWidth-1:0] cfg_i
@@ -93,6 +99,24 @@
`ASSERT_INIT(DiffWidthAligned_A, (DataBitsPerMask % DiffWidth) == 0)
`ASSERT_INIT(DiffWidthWithParity_A, EnableParity && (DiffWidth == 8) || !EnableParity)
+ //////////////////////////////
+ // Integrity error latching //
+ //////////////////////////////
+
+ logic intg_err_q;
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ intg_err_q <= '0;
+ end else if (intg_error_i) begin
+ intg_err_q <= 1'b1;
+ end
+ end
+
+ prim_buf u_intg_err_out (
+ .in_i(intg_error_i | intg_err_q),
+ .out_o(intg_error_o)
+ );
+
/////////////////////////////////////////
// Pending Write and Address Registers //
/////////////////////////////////////////
@@ -118,8 +142,14 @@
assign addr_collision_d = read_en & (write_en_q | write_pending_q) & (addr_i == waddr_q);
// Macro requests and write strobe
+ // The macro operation is silenced if an integrity error is seen
logic macro_req;
- assign macro_req = read_en | write_en_q | write_pending_q;
+ logic intg_err_macro_req;
+ prim_buf u_intg_err_macro_req (
+ .in_i(intg_error_i | intg_err_q),
+ .out_o(intg_err_macro_req)
+ );
+ assign macro_req = ~intg_err_macro_req & (read_en | write_en_q | write_pending_q);
// We are allowed to write a pending write transaction to the memory if there is no incoming read
logic macro_write;
assign macro_write = (write_en_q | write_pending_q) & ~read_en;
@@ -138,18 +168,34 @@
// This creates a bijective address mapping using a substitution / permutation network.
logic [AddrWidth-1:0] addr_scr;
if (NumAddrScrRounds > 0) begin : gen_addr_scr
+
+ // TODO, expand this into copies with another primitive
+ logic intg_err_addr_scr;
+ prim_buf u_intg_err_addr_scr (
+ .in_i(intg_error_i | intg_err_q),
+ .out_o(intg_err_addr_scr)
+ );
+
+ // If there is an intergirty error, the nonce used is reversed
+ logic [AddrWidth-1:0] addr_scr_nonce;
+ for (genvar j = 0; j < AddrWidth; j++) begin : gen_addr_scr_nonce
+ assign addr_scr_nonce[j] = intg_err_addr_scr ?
+ nonce_i[NonceWidth - 1 - j] :
+ nonce_i[NonceWidth - AddrWidth + j];
+ end
+
prim_subst_perm #(
.DataWidth ( AddrWidth ),
.NumRounds ( NumAddrScrRounds ),
.Decrypt ( 0 )
) u_prim_subst_perm (
- .data_i ( addr_mux ),
+ .data_i ( addr_mux ),
// Since the counter mode concatenates {nonce_i[NonceWidth-1-AddrWidth:0], addr_i} to form
// the IV, the upper AddrWidth bits of the nonce are not used and can be used for address
// scrambling. In cases where N parallel PRINCE blocks are used due to a data
// width > 64bit, N*AddrWidth nonce bits are left dangling.
- .key_i ( nonce_i[NonceWidth - 1 : NonceWidth - AddrWidth] ),
- .data_o ( addr_scr )
+ .key_i ( addr_scr_nonce ),
+ .data_o ( addr_scr )
);
end else begin : gen_no_addr_scr
assign addr_scr = addr_mux;
@@ -166,8 +212,26 @@
// This encrypts the IV consisting of the nonce and address using the key provided in order to
// generate the keystream for the data. Note that we instantiate a register halfway within this
// primitive to balance the delay between request and response side.
+ localparam int DataNonceWidth = 64 - AddrWidth;
logic [NumParScr*64-1:0] keystream;
+ logic [NumParScr-1:0][DataNonceWidth-1:0] data_scr_nonce;
+
+ // TODO, expand this into copies with another primitive
+ logic intg_err_data_scr;
+ prim_buf u_intg_err_data_scr (
+ .in_i(intg_error_i | intg_err_q),
+ .out_o(intg_err_data_scr)
+ );
+
for (genvar k = 0; k < NumParScr; k++) begin : gen_par_scr
+
+ for (genvar j = 0; j < DataNonceWidth; j++) begin : gen_data_nonce
+ assign data_scr_nonce[k][j] = intg_err_data_scr ?
+ nonce_i[(k + 1) * DataNonceWidth - j] :
+ nonce_i[k * DataNonceWidth + j];
+ end
+
+
prim_prince #(
.DataWidth (64),
.KeyWidth (128),
@@ -180,7 +244,8 @@
.rst_ni,
.valid_i ( gnt_o ),
// The IV is composed of a nonce and the row address
- .data_i ( {nonce_i[k * (64 - AddrWidth) +: (64 - AddrWidth)], addr_i} ),
+ //.data_i ( {nonce_i[k * (64 - AddrWidth) +: (64 - AddrWidth)], addr_i} ),
+ .data_i ( {data_scr_nonce[k], addr_i} ),
// All parallel scramblers use the same key
.key_i,
// Since we operate in counter mode, this can always be set to encryption mode
diff --git a/hw/ip/prim_generic/rtl/prim_generic_flash.sv b/hw/ip/prim_generic/rtl/prim_generic_flash.sv
index 8483fbd..154f7fa 100644
--- a/hw/ip/prim_generic/rtl/prim_generic_flash.sv
+++ b/hw/ip/prim_generic/rtl/prim_generic_flash.sv
@@ -151,6 +151,7 @@
.addr_o(cfg_addr),
.wdata_o(cfg_wdata),
.wmask_o(),
+ .intg_error_o(),
.rdata_i(cfg_rdata),
.rvalid_i(cfg_rvalid),
.rerror_i('0)
diff --git a/hw/ip/prim_generic/rtl/prim_generic_otp.sv b/hw/ip/prim_generic/rtl/prim_generic_otp.sv
index 149d6e7..05f9d58 100644
--- a/hw/ip/prim_generic/rtl/prim_generic_otp.sv
+++ b/hw/ip/prim_generic/rtl/prim_generic_otp.sv
@@ -78,6 +78,7 @@
.addr_o ( tlul_addr ),
.wdata_o ( tlul_wdata ),
.wmask_o ( ),
+ .intg_error_o( ),
.rdata_i ( tlul_rdata_q ),
.rvalid_i ( tlul_rvalid_q ),
.rerror_i ( '0 )
diff --git a/hw/ip/rv_dm/rtl/rv_dm.sv b/hw/ip/rv_dm/rtl/rv_dm.sv
index 113db6b..40e13d5 100644
--- a/hw/ip/rv_dm/rtl/rv_dm.sv
+++ b/hw/ip/rv_dm/rtl/rv_dm.sv
@@ -348,6 +348,7 @@
.addr_o (addr_w),
.wdata_o (wdata),
.wmask_o (),
+ .intg_error_o(),
.rdata_i (rdata),
.rvalid_i (rvalid),
.rerror_i (2'b00),
diff --git a/hw/ip/spi_device/rtl/spi_device.sv b/hw/ip/spi_device/rtl/spi_device.sv
index bb97bc0..e4e25be 100644
--- a/hw/ip/spi_device/rtl/spi_device.sv
+++ b/hw/ip/spi_device/rtl/spi_device.sv
@@ -656,6 +656,7 @@
.addr_o (mem_a_addr),
.wdata_o (mem_a_wdata),
.wmask_o (), // Not used
+ .intg_error_o(),
.rdata_i (mem_a_rdata),
.rvalid_i (mem_a_rvalid),
.rerror_i (mem_a_rerror)
diff --git a/hw/ip/sram_ctrl/data/sram_ctrl.hjson b/hw/ip/sram_ctrl/data/sram_ctrl.hjson
index 4127c2c..6224e05 100644
--- a/hw/ip/sram_ctrl/data/sram_ctrl.hjson
+++ b/hw/ip/sram_ctrl/data/sram_ctrl.hjson
@@ -19,9 +19,12 @@
///////////////////////////
alert_list: [
+ { name: "fatal_intg_error",
+ desc: "An integrity error has occurred in the SRAM."
+ },
{ name: "fatal_parity_error",
- desc: "An uncorrectable parity error has occurred in the SRAM."
- }
+ desc: "An parity error has occurred in the SRAM."
+ },
],
////////////////
@@ -97,6 +100,12 @@
act: "req",
package: "tlul_pkg",
},
+ { struct: "logic",
+ type: "uni",
+ name: "intg_error",
+ act: "rcv",
+ package: ""
+ },
] // inter_signal_list
regwidth: "32",
diff --git a/hw/ip/sram_ctrl/doc/_index.md b/hw/ip/sram_ctrl/doc/_index.md
index adf0fe5..d95c275 100644
--- a/hw/ip/sram_ctrl/doc/_index.md
+++ b/hw/ip/sram_ctrl/doc/_index.md
@@ -15,6 +15,7 @@
- Key request logic for the lightweight memory and address scrambling device.
- Reporting CSRs and alert trigger for SRAM integrity errors.
+- Security hardening when integrity error has been detected.
# Theory of Operations
@@ -121,6 +122,15 @@
The same two-layer S&P network that is used for byte diffusion is leveraged to non-linearly remap the SRAM address as shown in the block diagram above.
As opposed to the byte diffusion S&P networks, this particular address scrambling network additionally XOR's in a nonce that has the same width as the address.
+### Integrity Error Handling
+
+The `prim_ram_1p_scr` primitive contains an input to indicate whether upstream logic has detected an integrity error (The generation of the integrity error is determined by system integration).
+When an integrity error is encountered, the prim memory module does the following:
+* Latch the error condition until reset.
+* Reverse the nonce used during the address and CTR scrambling.
+* Disallow any transaction (read or write) on the actual memory macro.
+
+This behavior, combined with other top level defenses, form a multi-layered defense when integrity errors are seen in the system.
### Read and Write Sequencing
@@ -221,7 +231,7 @@
Signal | Direction | Type | Description
---------------------------|------------------|------------------------------------|---------------
-`key_valid_i` | `input` | `logic ` | Indicates whether the key and nonce are considered valid. New memory requests are blocked if this is set to 0.
+`key_valid_i` | `input` | `logic` | Indicates whether the key and nonce are considered valid. New memory requests are blocked if this is set to 0.
`key_i` | `input` | `logic [127:0]` | Scrambling key.
`nonce_i` | `input` | `logic [NonceWidth-1:0]` | Scrambling nonce.
`req_i` | `input` | `logic` | Memory request indication signal (from TL-UL SRAM adapter).
@@ -230,9 +240,11 @@
`addr_i` | `input` | `logic [AddrWidth-1:0]` | Address for memory op (from TL-UL SRAM adapter).
`wdata_i` | `input` | `logic [Width-1:0]` | Write data (from TL-UL SRAM adapter).
`wmask_i` | `input` | `logic [Width-1:0]` | Write mask (from TL-UL SRAM adapter).
+`intg_error_i` | `input` | `logic` | Indicates whether the incoming transaction has an integrity error
`rdata_o` | `output` | `logic [Width-1:0]` | Read data output (to TL-UL SRAM adapter).
`rvalid_o` | `output` | `logic` | Read data valid indication (to TL-UL SRAM adapter).
`rerror_o` | `output` | `logic [1:0]` | Error indication (to TL-UL SRAM adapter). Bit 0 indicates a correctable and bit 1 an uncorrectable error. Note that at this time, only uncorrectable errors are reported, since the scrambling device only supports byte parity.
+`intg_error_o` | `output` | `logic` | Forwards latched integrity error indication to the sram controller.
`raddr_o` | `output` | `logic [31:0]` | Address of the faulty read operation.
`cfg_i` | `input` | `logic [CfgWidth-1:0]` | Attributes for physical memory macro.
@@ -262,7 +274,7 @@
## Error Handling
Data in the SRAM is integrity protected with byte parity.
-In case an integrity failure is detected, the SRAM controller sets the {{< regref "STATUS.ERROR" >}} bit in the CSRs and continuously sends out a `fatal_parity_error` alert.
+In case an integrity failure is detected, the SRAM controller sets the {{< regref "STATUS.ERROR" >}} bit in the CSRs and continuously sends out a `fatal_parity_error` or `fatal_intg_error` alert.
At the same time, the affected TL-UL transaction will error out.
SRAM integrity failures are considered unrecoverable and cannot be cleared.
diff --git a/hw/ip/sram_ctrl/dv/env/sram_ctrl_env_pkg.sv b/hw/ip/sram_ctrl/dv/env/sram_ctrl_env_pkg.sv
index ef837d8..3b5171d 100644
--- a/hw/ip/sram_ctrl/dv/env/sram_ctrl_env_pkg.sv
+++ b/hw/ip/sram_ctrl/dv/env/sram_ctrl_env_pkg.sv
@@ -23,8 +23,8 @@
`include "dv_macros.svh"
// parameters
- parameter string LIST_OF_ALERTS[] = { "fatal_parity_error" };
- parameter uint NUM_ALERTS = 1;
+ parameter string LIST_OF_ALERTS[] = { "fatal_intg_error", "fatal_parity_error"};
+ parameter uint NUM_ALERTS = 2;
// Number of bits in the otp_ctrl_pkg::sram_otp_key_rsp_t struct:
// 1 bit for valid, SramKeyWidth bits for the key, SramNonceWidth bits for the nonce.
diff --git a/hw/ip/sram_ctrl/dv/sram_ctrl_wrapper.sv b/hw/ip/sram_ctrl/dv/sram_ctrl_wrapper.sv
index a6aa441..c28e7e7 100644
--- a/hw/ip/sram_ctrl/dv/sram_ctrl_wrapper.sv
+++ b/hw/ip/sram_ctrl/dv/sram_ctrl_wrapper.sv
@@ -50,6 +50,7 @@
wire [DataWidth-1:0] wmask;
wire [DataWidth-1:0] rdata;
wire rvalid;
+ wire intg_error;
// SRAM Controller
sram_ctrl u_sram_ctrl (
@@ -72,7 +73,9 @@
.sram_otp_key_i (sram_otp_key_i ),
// Interface with SRAM memory scrambling
.sram_scr_o (scr_req ),
- .sram_scr_i (scr_rsp )
+ .sram_scr_i (scr_rsp ),
+ // Integrity error
+ .intg_error_i (intg_error)
);
// TLUL Adapter SRAM
@@ -102,24 +105,26 @@
.Width(DataWidth),
.Depth(2 ** AddrWidth)
) u_ram1p_sram (
- .clk_i (clk_i ),
- .rst_ni (rst_ni ),
+ .clk_i (clk_i ),
+ .rst_ni (rst_ni ),
// Key interface
- .key_valid_i(scr_req.valid ),
- .key_i (scr_req.key ),
- .nonce_i (scr_req.nonce ),
+ .key_valid_i (scr_req.valid ),
+ .key_i (scr_req.key ),
+ .nonce_i (scr_req.nonce ),
// SRAM response interface to TLUL adapter
- .req_i (req ),
- .gnt_o (gnt ),
- .write_i (we ),
- .addr_i (addr ),
- .wdata_i (wdata ),
- .wmask_i (wmask ),
- .rdata_o (rdata ),
- .rvalid_o (rvalid ),
- .rerror_o (scr_rsp.rerror ),
- .raddr_o (scr_rsp.raddr ),
- .cfg_i ('0 )
+ .req_i (req ),
+ .gnt_o (gnt ),
+ .write_i (we ),
+ .addr_i (addr ),
+ .wdata_i (wdata ),
+ .wmask_i (wmask ),
+ .intg_error_i ('0 ),
+ .rdata_o (rdata ),
+ .rvalid_o (rvalid ),
+ .rerror_o (scr_rsp.rerror ),
+ .intg_error_o (intg_error ),
+ .raddr_o (scr_rsp.raddr ),
+ .cfg_i ('0 )
);
endmodule
diff --git a/hw/ip/sram_ctrl/rtl/sram_ctrl.sv b/hw/ip/sram_ctrl/rtl/sram_ctrl.sv
index dc7260f..7f31165 100644
--- a/hw/ip/sram_ctrl/rtl/sram_ctrl.sv
+++ b/hw/ip/sram_ctrl/rtl/sram_ctrl.sv
@@ -39,6 +39,8 @@
// Key request to OTP (running on clk_fixed)
output otp_ctrl_pkg::sram_otp_key_req_t sram_otp_key_o,
input otp_ctrl_pkg::sram_otp_key_rsp_t sram_otp_key_i,
+ // Integrity error detection on corresponding sram
+ input intg_error_i,
// Interface with SRAM scrambling wrapper
output sram_scr_req_t sram_scr_o,
input sram_scr_rsp_t sram_scr_i,
@@ -101,25 +103,37 @@
// Alert Sender //
//////////////////
- logic alert;
- logic alert_test;
- assign alert = parity_error_q;
- assign alert_test = reg2hw.alert_test.q &
- reg2hw.alert_test.qe;
+ logic [NumAlerts-1:0] alert, alert_test;
- prim_alert_sender #(
- .AsyncOn(AlertAsyncOn[0]),
- .IsFatal(1)
- ) u_prim_alert_sender (
- .clk_i,
- .rst_ni,
- .alert_test_i ( alert_test ),
- .alert_req_i ( alert ),
- .alert_ack_o ( ),
- .alert_state_o ( ),
- .alert_rx_i ( alert_rx_i[0] ),
- .alert_tx_o ( alert_tx_o[0] )
- );
+ assign alert = {
+ parity_error_q,
+ intg_error_i
+ };
+
+
+ assign alert_test = {
+ reg2hw.alert_test.fatal_parity_error.q &
+ reg2hw.alert_test.fatal_parity_error.qe,
+ reg2hw.alert_test.fatal_intg_error.q &
+ reg2hw.alert_test.fatal_intg_error.qe
+ };
+
+ for (genvar i=0; i < NumAlerts; i++) begin : gen_alerts
+ prim_alert_sender #(
+ .AsyncOn(AlertAsyncOn[i]),
+ .IsFatal(1)
+ ) u_prim_alert_sender_parity (
+ .clk_i,
+ .rst_ni,
+ .alert_test_i ( alert_test[i] ),
+ .alert_req_i ( alert[i] ),
+ .alert_ack_o ( ),
+ .alert_state_o ( ),
+ .alert_rx_i ( alert_rx_i[i] ),
+ .alert_tx_o ( alert_tx_o[i] )
+ );
+ end
+
//////////////////////////////////////////
// Lifecycle Escalation Synchronization //
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 c52ea0b..d92a230 100644
--- a/hw/ip/sram_ctrl/rtl/sram_ctrl_reg_pkg.sv
+++ b/hw/ip/sram_ctrl/rtl/sram_ctrl_reg_pkg.sv
@@ -7,7 +7,7 @@
package sram_ctrl_reg_pkg;
// Param list
- parameter int NumAlerts = 1;
+ parameter int NumAlerts = 2;
// Address width within the block
parameter int BlockAw = 5;
@@ -16,8 +16,14 @@
// Typedefs for registers //
////////////////////////////
typedef struct packed {
- logic q;
- logic qe;
+ struct packed {
+ logic q;
+ logic qe;
+ } fatal_intg_error;
+ struct packed {
+ logic q;
+ logic qe;
+ } fatal_parity_error;
} sram_ctrl_reg2hw_alert_test_reg_t;
typedef struct packed {
@@ -55,7 +61,7 @@
// Register to internal design logic //
///////////////////////////////////////
typedef struct packed {
- sram_ctrl_reg2hw_alert_test_reg_t alert_test; // [6:5]
+ sram_ctrl_reg2hw_alert_test_reg_t alert_test; // [8:5]
sram_ctrl_reg2hw_exec_reg_t exec; // [4:2]
sram_ctrl_reg2hw_ctrl_reg_t ctrl; // [1:0]
} sram_ctrl_reg2hw_t;
@@ -78,7 +84,8 @@
parameter logic [BlockAw-1:0] SRAM_CTRL_ERROR_ADDRESS_OFFSET = 5'h 18;
// Reset values for hwext registers and their fields
- parameter logic [0:0] SRAM_CTRL_ALERT_TEST_RESVAL = 1'h 0;
+ parameter logic [1:0] SRAM_CTRL_ALERT_TEST_RESVAL = 2'h 0;
+ parameter logic [0:0] SRAM_CTRL_ALERT_TEST_FATAL_INTG_ERROR_RESVAL = 1'h 0;
parameter logic [0:0] SRAM_CTRL_ALERT_TEST_FATAL_PARITY_ERROR_RESVAL = 1'h 0;
parameter logic [3:0] SRAM_CTRL_STATUS_RESVAL = 4'h 0;
parameter logic [0:0] SRAM_CTRL_CTRL_RESVAL = 1'h 0;
diff --git a/hw/ip/sram_ctrl/rtl/sram_ctrl_reg_top.sv b/hw/ip/sram_ctrl/rtl/sram_ctrl_reg_top.sv
index fd2cae0..9a679d1 100644
--- a/hw/ip/sram_ctrl/rtl/sram_ctrl_reg_top.sv
+++ b/hw/ip/sram_ctrl/rtl/sram_ctrl_reg_top.sv
@@ -99,8 +99,10 @@
// Define SW related signals
// Format: <reg>_<field>_{wd|we|qs}
// or <reg>_{wd|we|qs} if field == 1 or 0
- logic alert_test_wd;
- logic alert_test_we;
+ logic alert_test_fatal_intg_error_wd;
+ logic alert_test_fatal_intg_error_we;
+ logic alert_test_fatal_parity_error_wd;
+ logic alert_test_fatal_parity_error_we;
logic status_error_qs;
logic status_error_re;
logic status_escalated_qs;
@@ -125,16 +127,32 @@
// Register instances
// R[alert_test]: V(True)
+ // F[fatal_intg_error]: 0:0
prim_subreg_ext #(
.DW (1)
- ) u_alert_test (
+ ) u_alert_test_fatal_intg_error (
.re (1'b0),
- .we (alert_test_we),
- .wd (alert_test_wd),
+ .we (alert_test_fatal_intg_error_we),
+ .wd (alert_test_fatal_intg_error_wd),
.d ('0),
.qre (),
- .qe (reg2hw.alert_test.qe),
- .q (reg2hw.alert_test.q ),
+ .qe (reg2hw.alert_test.fatal_intg_error.qe),
+ .q (reg2hw.alert_test.fatal_intg_error.q ),
+ .qs ()
+ );
+
+
+ // F[fatal_parity_error]: 1:1
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_alert_test_fatal_parity_error (
+ .re (1'b0),
+ .we (alert_test_fatal_parity_error_we),
+ .wd (alert_test_fatal_parity_error_wd),
+ .d ('0),
+ .qre (),
+ .qe (reg2hw.alert_test.fatal_parity_error.qe),
+ .q (reg2hw.alert_test.fatal_parity_error.q ),
.qs ()
);
@@ -353,8 +371,11 @@
if (addr_hit[6] && reg_we && (SRAM_CTRL_PERMIT[6] != (SRAM_CTRL_PERMIT[6] & reg_be))) wr_err = 1'b1 ;
end
- assign alert_test_we = addr_hit[0] & reg_we & !reg_error;
- assign alert_test_wd = reg_wdata[0];
+ assign alert_test_fatal_intg_error_we = addr_hit[0] & reg_we & !reg_error;
+ assign alert_test_fatal_intg_error_wd = reg_wdata[0];
+
+ assign alert_test_fatal_parity_error_we = addr_hit[0] & reg_we & !reg_error;
+ assign alert_test_fatal_parity_error_wd = reg_wdata[1];
assign status_error_re = addr_hit[1] & reg_re & !reg_error;
@@ -383,6 +404,7 @@
unique case (1'b1)
addr_hit[0]: begin
reg_rdata_next[0] = '0;
+ reg_rdata_next[1] = '0;
end
addr_hit[1]: begin
diff --git a/hw/ip/tlul/rtl/tlul_adapter_sram.sv b/hw/ip/tlul/rtl/tlul_adapter_sram.sv
index 666e556..4d6b150 100644
--- a/hw/ip/tlul/rtl/tlul_adapter_sram.sv
+++ b/hw/ip/tlul/rtl/tlul_adapter_sram.sv
@@ -12,12 +12,15 @@
* than SRAM size
*/
module tlul_adapter_sram import tlul_pkg::*; #(
- parameter int SramAw = 12,
- parameter int SramDw = 32, // Must be multiple of the TL width
- parameter int Outstanding = 1, // Only one request is accepted
- parameter bit ByteAccess = 1, // 1: true, 0: false
- parameter bit ErrOnWrite = 0, // 1: Writes not allowed, automatically error
- parameter bit ErrOnRead = 0 // 1: Reads not allowed, automatically error
+ parameter int SramAw = 12,
+ parameter int SramDw = 32, // Must be multiple of the TL width
+ parameter int Outstanding = 1, // Only one request is accepted
+ parameter bit ByteAccess = 1, // 1: true, 0: false
+ parameter bit ErrOnWrite = 0, // 1: Writes not allowed, automatically error
+ parameter bit ErrOnRead = 0, // 1: Reads not allowed, automatically error
+ parameter bit CmdIntgCheck = 0, // 1: Enable command integrity check
+ parameter bit EnableRspIntgGen = 0, // 1: Generate response integrity
+ parameter bit EnableDataIntgGen = 0 // 1: Generate data integrity
) (
input clk_i,
input rst_ni,
@@ -36,6 +39,7 @@
output logic [SramAw-1:0] addr_o,
output logic [SramDw-1:0] wdata_o,
output logic [SramDw-1:0] wmask_o,
+ output logic intg_error_o,
input [SramDw-1:0] rdata_i,
input rvalid_i,
input [1:0] rerror_i // 2 bit error [1]: Uncorrectable, [0]: Correctable
@@ -91,6 +95,7 @@
rsp_t rspfifo_wdata, rspfifo_rdata;
logic error_internal; // Internal protocol error checker
+ logic intg_error;
logic wr_attr_error;
logic instr_error;
logic wr_vld_error;
@@ -136,7 +141,9 @@
end
end
- assign tl_o = '{
+
+ tl_d2h_t tl_out;
+ assign tl_out = '{
d_valid : d_valid ,
d_opcode : (d_valid && reqfifo_rdata.op != OpRead) ? AccessAck : AccessAckData,
d_param : '0,
@@ -151,6 +158,15 @@
a_ready : (gnt_i | error_internal) & reqfifo_wready & sramreqfifo_wready
};
+
+ tlul_rsp_intg_gen #(
+ .EnableRspIntgGen(EnableRspIntgGen),
+ .EnableDataIntgGen(EnableDataIntgGen)
+ ) u_rsp_gen (
+ .tl_i(tl_out),
+ .tl_o
+ );
+
// a_ready depends on the FIFO full condition and grant from SRAM (or SRAM arbiter)
// assemble response, including read response, write response, and error for unsupported stuff
@@ -216,6 +232,30 @@
assign rd_vld_error = 1'b0;
end
+ if (CmdIntgCheck) begin : gen_cmd_intg_check
+ tlul_cmd_intg_chk u_cmd_intg_chk (
+ .tl_i,
+ .err_o ()
+ );
+
+ // TODO, hook up err_o once memory initialization is done
+ assign intg_error = '0;
+ end else begin : gen_no_cmd_intg_check
+ assign intg_error = '0;
+ end
+
+
+ // permanently latch integrity error until reset
+ logic intg_error_q;
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ intg_error_q <= '0;
+ end else if (intg_error) begin
+ intg_error_q <= 1'b1;
+ end
+ end
+ assign intg_error_o = intg_error_q;
+
tlul_err u_err (
.clk_i,
.rst_ni,
@@ -223,7 +263,8 @@
.err_o (tlul_error)
);
- assign error_internal = wr_attr_error | wr_vld_error | rd_vld_error | instr_error | tlul_error;
+ assign error_internal = wr_attr_error | wr_vld_error | rd_vld_error | instr_error |
+ tlul_error | intg_error | intg_error_q;
// End: Request Error Detection
assign reqfifo_wvalid = a_ack ; // Push to FIFO only when granted
diff --git a/hw/ip/tlul/rtl/tlul_rsp_intg_gen.sv b/hw/ip/tlul/rtl/tlul_rsp_intg_gen.sv
index 6ee680e..6c58916 100644
--- a/hw/ip/tlul/rtl/tlul_rsp_intg_gen.sv
+++ b/hw/ip/tlul/rtl/tlul_rsp_intg_gen.sv
@@ -9,6 +9,7 @@
*/
module tlul_rsp_intg_gen import tlul_pkg::*; #(
+ parameter bit EnableRspIntgGen = 1'b1,
parameter bit EnableDataIntgGen = 1'b1
) (
// TL-UL interface
@@ -16,15 +17,20 @@
output tl_d2h_t tl_o
);
- tl_d2h_rsp_intg_t rsp;
- logic [D2HRspMaxWidth-1:0] unused_payload;
logic [D2HRspIntgWidth-1:0] rsp_intg;
- assign rsp = extract_d2h_rsp_intg(tl_i);
+ if (EnableRspIntgGen) begin : gen_rsp_intg
+ tl_d2h_rsp_intg_t rsp;
+ logic [D2HRspMaxWidth-1:0] unused_payload;
- prim_secded_64_57_enc u_rsp_gen (
- .in(D2HRspMaxWidth'(rsp)),
- .out({rsp_intg, unused_payload})
- );
+ assign rsp = extract_d2h_rsp_intg(tl_i);
+
+ prim_secded_64_57_enc u_rsp_gen (
+ .in(D2HRspMaxWidth'(rsp)),
+ .out({rsp_intg, unused_payload})
+ );
+ end else begin : gen_passthrough_rsp_intg
+ assign rsp_intg = tl_i.d_user.rsp_intg;
+ end
logic [DataIntgWidth-1:0] data_intg;
if (EnableDataIntgGen) begin : gen_data_intg
@@ -38,7 +44,6 @@
assign data_intg = tl_i.d_user.data_intg;
end
-
always_comb begin
tl_o = tl_i;
tl_o.d_user.rsp_intg = rsp_intg;
diff --git a/hw/ip/usbdev/rtl/usbdev.sv b/hw/ip/usbdev/rtl/usbdev.sv
index 008ecf6..db93e6e 100644
--- a/hw/ip/usbdev/rtl/usbdev.sv
+++ b/hw/ip/usbdev/rtl/usbdev.sv
@@ -677,6 +677,7 @@
.addr_o (mem_a_addr),
.wdata_o (mem_a_wdata),
.wmask_o (), // Not used
+ .intg_error_o(),
.rdata_i (mem_a_rdata),
.rvalid_i (mem_a_rvalid),
.rerror_i (mem_a_rerror)