blob: 95a6be045942ba1bd776b69da4b08a3b28549148 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Galois type LFSR ([1], internal XOR gates, very fast).
// Parameterizable width from 4 to 64 bits.
// Coefficients obtained from [2].
//
// Refs: [1] https://en.wikipedia.org/wiki/Linear-feedback_shift_register
// [2] https://users.ece.cmu.edu/~koopman/lfsr/
module prim_lfsr #(
// Lfsr width
parameter int unsigned LfsrDw = 32,
// Width of input to be XOR'd into state (lfsr_q[InDw-1:0])
parameter int unsigned InDw = 8,
// Width of output tap (from lfsr_q[OutDw-1:0])
parameter int unsigned OutDw = 8,
// Lfsr reset state, must be nonzero!
parameter logic [LfsrDw-1:0] Seed = '1,
// Custom polynomial coeffs
parameter logic [LfsrDw-1:0] Custom = '0
) (
input clk_i,
input rst_ni,
input en_i,
input [InDw-1:0] data_i,
output logic [OutDw-1:0] data_o
);
// automatically generated with get-lfsr-coeffs.py script
localparam logic [63:0] coeffs [4:64] = '{ 64'h9,
64'h12,
64'h21,
64'h41,
64'h8E,
64'h108,
64'h204,
64'h402,
64'h829,
64'h100D,
64'h2015,
64'h4001,
64'h8016,
64'h10004,
64'h20013,
64'h40013,
64'h80004,
64'h100002,
64'h200001,
64'h400010,
64'h80000D,
64'h1000004,
64'h2000023,
64'h4000013,
64'h8000004,
64'h10000002,
64'h20000029,
64'h40000004,
64'h80000057,
64'h100000029,
64'h200000073,
64'h400000002,
64'h80000003B,
64'h100000001F,
64'h2000000031,
64'h4000000008,
64'h800000001C,
64'h10000000004,
64'h2000000001F,
64'h4000000002C,
64'h80000000032,
64'h10000000000D,
64'h200000000097,
64'h400000000010,
64'h80000000005B,
64'h1000000000038,
64'h200000000000E,
64'h4000000000025,
64'h8000000000004,
64'h10000000000023,
64'h2000000000003E,
64'h40000000000023,
64'h8000000000004A,
64'h100000000000016,
64'h200000000000031,
64'h40000000000003D,
64'h800000000000001,
64'h1000000000000013,
64'h2000000000000034,
64'h4000000000000001,
64'h800000000000000D };
logic [LfsrDw-1:0] lfsr_d, lfsr_q;
// Custom Galois polynomial
if (Custom) begin : g_custom
assign lfsr_d = (en_i) ? LfsrDw'(data_i) ^ ({LfsrDw{lfsr_q[0]}} &
Custom[LfsrDw-1:0]) ^ (lfsr_q >> 1)
: lfsr_q;
end else begin : g_lut
assign lfsr_d = (en_i) ? LfsrDw'(data_i) ^ ({LfsrDw{lfsr_q[0]}} &
coeffs[LfsrDw][LfsrDw-1:0]) ^ (lfsr_q >> 1)
: lfsr_q;
end
assign data_o = lfsr_q[OutDw-1:0];
always_ff @(posedge clk_i or negedge rst_ni) begin : p_reg
if (!rst_ni) begin
lfsr_q <= Seed;
end else begin
lfsr_q <= lfsr_d;
end
end
// assertions
`ASSERT_INIT(InputWidth, LfsrDw >= InDw)
`ASSERT_INIT(OutputWidth, LfsrDw >= OutDw)
`ASSERT_INIT(MinLfsrWidth, LfsrDw >= $low(coeffs))
`ASSERT_INIT(MaxLfsrWidth, LfsrDw <= $high(coeffs))
// check that the most significant bit of polynomial is 1
`ASSERT_INIT(CoeffNzCheck, (Custom && Custom[LfsrDw-1]) ||
(!Custom) && coeffs[LfsrDw][LfsrDw-1])
`ASSERT_INIT(SeedNzCheck, Seed)
`ASSERT(LfsrNzCheck, lfsr_q, clk_i, !rst_ni)
endmodule