blob: 8fce7b7657c0a80096fb996dc4c36ad30d24de8d [file] [log] [blame]
// 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
`ifdef SIMULATION
`ifndef VERILATOR
// Ensure both LFSRs start off with the same default seed. if randomized in simulations.
initial begin : p_sync_lfsr_default_seed
wait (!$isunknown(gen_double_lfsr[0].u_prim_lfsr.DefaultSeedLocal));
wait (!$isunknown(gen_double_lfsr[1].u_prim_lfsr.DefaultSeedLocal));
gen_double_lfsr[1].u_prim_lfsr.DefaultSeedLocal =
gen_double_lfsr[0].u_prim_lfsr.DefaultSeedLocal;
$display("%m: Updated gen_double_lfsr[1].u_prim_lfsr.DefaultSeedLocal = 0x%0h",
gen_double_lfsr[1].u_prim_lfsr.DefaultSeedLocal);
end
`endif
`endif
// 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