| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| // |
| // Hardened LFSR module that instantiates two LFSRs of the same type. |
| // The state vector of both LFSRs is constantly checked and an error is asserted if the |
| // two states are inconsistent. |
| |
| module prim_double_lfsr #( |
| // prim_lfsr parameters - refer to prim_lfsr for their meaning/ |
| parameter LfsrType = "GAL_XOR", |
| parameter int unsigned LfsrDw = 32, |
| localparam int unsigned LfsrIdxDw = $clog2(LfsrDw), |
| parameter int unsigned EntropyDw = 8, |
| parameter int unsigned StateOutDw = 8, |
| parameter logic [LfsrDw-1:0] DefaultSeed = LfsrDw'(1), |
| parameter logic [LfsrDw-1:0] CustomCoeffs = '0, |
| parameter bit StatePermEn = 1'b0, |
| parameter logic [LfsrDw-1:0][LfsrIdxDw-1:0] StatePerm = '0, |
| parameter bit MaxLenSVA = 1'b1, |
| parameter bit LockupSVA = 1'b1, |
| parameter bit ExtSeedSVA = 1'b1, |
| parameter bit NonLinearOut = 1'b0, |
| // This should only be disabled in special circumstances, for example |
| // in non-comportable IPs where an error does not trigger an alert. |
| parameter bit EnableAlertTriggerSVA = 1 |
| ) ( |
| input clk_i, |
| input rst_ni, |
| input seed_en_i, |
| input [LfsrDw-1:0] seed_i, |
| input lfsr_en_i, |
| input [EntropyDw-1:0] entropy_i, |
| output logic [StateOutDw-1:0] state_o, |
| // Asserted if the parallel LFSR states are inconsistent. |
| output logic err_o |
| ); |
| |
| |
| logic [1:0][LfsrDw-1:0] lfsr_state; |
| // We employ redundant LFSRs to guard against FI attacks. |
| for (genvar k = 0; k < 2; k++) begin : gen_double_lfsr |
| // Instantiate size_only buffers to prevent |
| // optimization / merging of redundant logic. |
| logic lfsr_en_buf, seed_en_buf; |
| logic [EntropyDw-1:0] entropy_buf; |
| logic [LfsrDw-1:0] seed_buf, lfsr_state_unbuf; |
| prim_buf #( |
| .Width(EntropyDw + LfsrDw + 2) |
| ) u_prim_buf_input ( |
| .in_i({seed_en_i, seed_i, lfsr_en_i, entropy_i}), |
| .out_o({seed_en_buf, seed_buf, lfsr_en_buf, entropy_buf}) |
| ); |
| |
| prim_lfsr #( |
| .LfsrType(LfsrType), |
| .LfsrDw(LfsrDw), |
| .EntropyDw(EntropyDw), |
| // output the full width so that the states can be cross checked. |
| .StateOutDw(LfsrDw), |
| .DefaultSeed(DefaultSeed), |
| .CustomCoeffs(CustomCoeffs), |
| .StatePermEn(StatePermEn), |
| .StatePerm(StatePerm), |
| .MaxLenSVA(MaxLenSVA), |
| .LockupSVA(LockupSVA), |
| .ExtSeedSVA(ExtSeedSVA), |
| .NonLinearOut(NonLinearOut) |
| ) u_prim_lfsr ( |
| .clk_i, |
| .rst_ni, |
| .seed_en_i ( seed_en_buf ), |
| .seed_i ( seed_buf ), |
| .lfsr_en_i ( lfsr_en_buf ), |
| .entropy_i ( entropy_buf ), |
| .state_o ( lfsr_state_unbuf ) |
| ); |
| |
| prim_buf #( |
| .Width(LfsrDw) |
| ) u_prim_buf_output ( |
| .in_i(lfsr_state_unbuf), |
| .out_o(lfsr_state[k]) |
| ); |
| end |
| |
| // Output the state from the first LFSR |
| assign state_o = lfsr_state[0][StateOutDw-1:0]; |
| assign err_o = lfsr_state[0] != lfsr_state[1]; |
| |
| // This logic that will be assign to one, when user adds macro |
| // ASSERT_PRIM_DOUBLE_LFSR_ERROR_TRIGGER_ALERT to check the error with alert, in case that |
| // prim_double_lfsr is used in design without adding this assertion check. |
| `ifdef INC_ASSERT |
| logic unused_assert_connected; |
| |
| `ASSERT_INIT_NET(AssertConnected_A, unused_assert_connected === 1'b1 || !EnableAlertTriggerSVA) |
| `endif |
| endmodule : prim_double_lfsr |