1
\$\begingroup\$

On recent comments based fixed modules for FPGAs for generating a pseudo-random bit sequence are presented. The first module generates a bit sequence. The third module speeds up the generation by transferring the bus to, for example, a multiplexer which is controlled by a faster device. Hence this bus is serialized into a bit sequence.

prbs.sv

`timescale 1ns / 1psmodule prbs #(    parameter integer PN = 7 //3, 4, 5, 6, 7, 9, 11, 15, 17, 23, 31, 32, 36, 41)(    input  logic i_clk,    input  logic i_s_rst_n,    input  logic i_en,    output logic o_prbs,    output logic o_prbs_n);    localparam integer TAP_1 = (PN == 3) ? 2 :                               (PN == 4) ? 3 :                               (PN == 5) ? 4 :                               (PN == 6) ? 5 :                               (PN == 7) ? 6 :                               (PN == 9) ? 8 :                               (PN == 10) ? 9 :                               (PN == 11) ? 10 :                               (PN == 15) ? 14 :                               (PN == 17) ? 16 :                               (PN == 18) ? 17 :                               (PN == 20) ? 19 :                               (PN == 21) ? 20 :                               (PN == 22) ? 21 :                               (PN == 23) ? 22 :                               (PN == 25) ? 24 :                               (PN == 28) ? 27 :                               (PN == 29) ? 28 :                               (PN == 31) ? 30 :                               (PN == 33) ? 32 :                               (PN == 35) ? 34 :                               (PN == 36) ? 35 :                               (PN == 39) ? 38 :                               (PN == 41) ? 40 : 0;    localparam integer TAP_0 = (PN == 3) ? 1 :                               (PN == 4) ? 2 :                               (PN == 5) ? 2 :                               (PN == 6) ? 4 :                               (PN == 7) ? 5 :                               (PN == 9) ? 4 :                               (PN == 10) ? 6 :                               (PN == 11) ? 8 :                               (PN == 15) ? 13 :                               (PN == 17) ? 13 :                               (PN == 18) ? 10 :                               (PN == 20) ? 16 :                               (PN == 21) ? 18 :                               (PN == 22) ? 20 :                               (PN == 23) ? 17 :                               (PN == 25) ? 21 :                               (PN == 28) ? 24 :                               (PN == 29) ? 27 :                               (PN == 31) ? 27 :                               (PN == 33) ? 19 :                               (PN == 35) ? 23 :                               (PN == 36) ? 24 :                               (PN == 39) ? 34 :                               (PN == 41) ? 37 : 0;    logic [PN - 1 : 0] lfsr;     assign o_prbs   = lfsr[PN - 1];    assign o_prbs_n = ~o_prbs;                          always_ff @ (posedge i_clk) begin        if (i_s_rst_n == 1'h0) begin            lfsr <= '1;        end        else if (i_en == 1'h1) begin            lfsr <= {lfsr[PN - 2 : 0], lfsr[TAP_1] ^ lfsr[TAP_0]};        end    endendmodule

prbs_tb.sv

`timescale 1ns / 1psmodule prbs_tb;     localparam integer PN             = 7; //3, 4, 5, 6, 7, 9, 11, 15, 17, 23, 31, 32, 36, 41    localparam integer PERIOD         = 2 ** PN;    localparam integer CLOCK_PERIOD   = 100;    localparam integer TEST_ITERATION = 1000;    localparam integer CHANGE_EN_VAL  = 100;    bit clk     = '0;    bit s_rst_n = '0;    bit en      = '0;        logic prbs  ;    logic prbs_n;    integer tick = 0;    prbs #    (        .PN (PN)    )    prbs_dut    (        .i_clk     (clk    ),        .i_s_rst_n (s_rst_n),        .i_en      (en     ),        .o_prbs    (prbs   ),        .o_prbs_n  (prbs_n )    );    always begin         #(CLOCK_PERIOD / 2) clk = !clk;    end    initial begin        s_rst_n <= '0;        @(posedge clk);        s_rst_n <= '1;        en      <= '1;        @(posedge clk);        for(int i = 0; i < TEST_ITERATION; i++) begin            if ((i % PERIOD) == (PERIOD - 1)) begin                en   <= ~en;                tick = 0;            end            else begin                tick++;            end            @(posedge clk);        end                $stop();    endendmodule

prbs_wide.sv

`timescale 1ns / 1psmodule prbs_wide #(    parameter integer PN = 7, //3, 4, 5, 6, 7, 9, 11, 15, 17, 23, 31, 32, 36, 41    parameter integer WIDTH = 16)(    input  logic                 i_clk,    input  logic                 i_s_rst_n,    input  logic                 i_en,    output logic [WIDTH - 1 : 0] o_prbs,    output logic [WIDTH - 1 : 0] o_prbs_n);    localparam integer TAP_1 = (PN == 3) ? 2 :                               (PN == 4) ? 3 :                               (PN == 5) ? 4 :                               (PN == 6) ? 5 :                               (PN == 7) ? 6 :                               (PN == 9) ? 8 :                               (PN == 10) ? 9 :                               (PN == 11) ? 10 :                               (PN == 15) ? 14 :                               (PN == 17) ? 16 :                               (PN == 18) ? 17 :                               (PN == 20) ? 19 :                               (PN == 21) ? 20 :                               (PN == 22) ? 21 :                               (PN == 23) ? 22 :                               (PN == 25) ? 24 :                               (PN == 28) ? 27 :                               (PN == 29) ? 28 :                               (PN == 31) ? 30 :                               (PN == 33) ? 32 :                               (PN == 35) ? 34 :                               (PN == 36) ? 35 :                               (PN == 39) ? 38 :                               (PN == 41) ? 40 : 0;    localparam integer TAP_0 = (PN == 3) ? 1 :                               (PN == 4) ? 2 :                               (PN == 5) ? 2 :                               (PN == 6) ? 4 :                               (PN == 7) ? 5 :                               (PN == 9) ? 4 :                               (PN == 10) ? 6 :                               (PN == 11) ? 8 :                               (PN == 15) ? 13 :                               (PN == 17) ? 13 :                               (PN == 18) ? 10 :                               (PN == 20) ? 16 :                               (PN == 21) ? 18 :                               (PN == 22) ? 20 :                               (PN == 23) ? 17 :                               (PN == 25) ? 21 :                               (PN == 28) ? 24 :                               (PN == 29) ? 27 :                               (PN == 31) ? 27 :                               (PN == 33) ? 19 :                               (PN == 35) ? 23 :                               (PN == 36) ? 24 :                               (PN == 39) ? 34 :                               (PN == 41) ? 37 : 0;    logic [PN - 1 : 0] lfsr;    logic [PN - 1 : 0] r_lfsr;      logic [WIDTH - 1 : 0] tmp;          always_comb begin        lfsr = r_lfsr;        for (int i = WIDTH - 1; i >= 0; i = i - 1) begin            lfsr   = {lfsr[PN - 2 : 0], lfsr[TAP_1] ^ lfsr[TAP_0]};            tmp[i] = lfsr[TAP_1] ^ lfsr[TAP_0];        end    end                     always_ff @ (posedge i_clk) begin        if (i_s_rst_n == 1'h0) begin            r_lfsr   <= '1;            o_prbs   <= '0;            o_prbs_n <= '1;        end        else if (i_en == 1'h1) begin            r_lfsr <= lfsr;            o_prbs   <= tmp;            o_prbs_n <= ~tmp;        end    endendmodule

prbs_wide_tb.sv

`timescale 1ns / 1psmodule prbs_wide_tb;    localparam integer PN             = 7;    localparam integer PERIOD         = 2 ** PN - 1;    localparam integer WIDTH          = 128;    localparam integer CLOCK_PERIOD   = 100;    localparam integer TEST_ITERATION = 1000;    localparam integer CHANGE_EN_VAL  = 100;    bit clk     = '0;    bit s_rst_n = '0;    bit en      = '0;    logic [WIDTH - 1 : 0] prbs  ;    logic [WIDTH - 1 : 0] prbs_n;    prbs_wide #    (        .PN    (PN   ),        .WIDTH (WIDTH)    )    prbs_wide_dut    (        .i_clk     (clk    ),        .i_s_rst_n (s_rst_n),        .i_en      (en     ),        .o_prbs    (prbs   ),        .o_prbs_n  (prbs_n )    );    always begin         #(CLOCK_PERIOD / 2) clk = !clk;    end    initial begin        s_rst_n <= '0;        @(posedge clk);        s_rst_n <= '1;        en      <= '1;        @(posedge clk);        for(int i = 0; i < TEST_ITERATION; i++) begin                    if ((i % PERIOD) == PERIOD - 1) begin                en <= ~en;            end            @(posedge clk);        end                $stop();    endendmodule
Mast's user avatar
Mast
13.9k12 gold badges57 silver badges128 bronze badges
askedDec 6, 2021 at 7:41
Drakonof's user avatar
\$\endgroup\$

1 Answer1

2
\$\begingroup\$

I don't see too much room for improvement.

Since you have some code which is common to 2 modules (thelocalparamTAP_0 andTAP_1 declarations), you could move them to a separate file andinclude them into the modules:

`include "common.v"

You could consider replacing the multiple conditional operators used to defineTAP_0 andTAP_1 withcase statements. To do so, you would also need to place the code inside afunction. In general, functions are synthesizable.

localparam integer TAP_0 = tap0(PN);function integer tap0 (integer pn);    case (pn)         3      : return  1;         4, 5   : return  2;         6, 9   : return  4;         7      : return  5;        10      : return  6;        11      : return  8;        15, 17  : return 13;        18      : return 10;        20      : return 16;        21      : return 18;        22      : return 20;        23      : return 17;        25      : return 21;        28, 36  : return 24;        29, 31  : return 27;        33      : return 19;        35      : return 23;        39      : return 34;        41      : return 37;        default : return  0;    endcaseendfunction

It is often beneficial to encapsulate complex code like this inside afunction; it may make the code easier to understand.

A benefit of usingcase is that you can group inputs together which return the same value; this is done using a comma to separate the case items, such as4, 5. This results in fewer lines of code.

This is all a matter of preference and, of course, tool support.

ForTAP_1:

localparam integer TAP_1 = tap1(PN);function integer tap1 (integer pn);    case (pn)          3,          4,          5,          6,          7,          9,         10,         11,         15,         17,         18,         20,         21,         22,         23,         25,         28,         29,         31,         33,         35,         36,         39,         41     : return pn-1;        default : return 0;    endcaseendfunction

Here, all explicit case items return the simple expressionpn-1. You can add as many of the case items on the same line as you want instead of having them one per line.

I attempted to use acase inside construct, but the 2 simulators I tried it on generated compile errors due to an unsupported construct. Maybe it will be supported in a future release. Refer to IEEE Std 1800-2017, section 12.5.4Set membership case statement.

answeredJan 27, 2022 at 17:43
toolic's user avatar
\$\endgroup\$

You mustlog in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.