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 endendmoduleprbs_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(); endendmoduleprbs_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 endendmoduleprbs_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(); endendmodule1 Answer1
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; endcaseendfunctionIt 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; endcaseendfunctionHere, 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.
You mustlog in to answer this question.
Explore related questions
See similar questions with these tags.

