给出了产生伪随机比特序列的FPGA模块.第一个模块产生一个位序列。第三模块通过将总线传输到例如由更快的设备控制的复用器来加速生成。因此,这个总线被序列化为一个位序列。
prbs.sv
`timescale 1ns / 1ps
module 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) ? 7 :
(PN == 11) ? 10 :
(PN == 15) ? 14 :
(PN == 17) ? 16 :
(PN == 23) ? 22 :
(PN == 31) ? 30 :
(PN == 32) ? 31 :
(PN == 36) ? 35 :
(PN == 41) ? 40 : 0;
localparam integer TAP_0 = (PN == 3) ? 0 :
(PN == 4) ? 2 :
(PN == 5) ? 2 :
(PN == 6) ? 4 :
(PN == 7) ? 0 :
(PN == 9) ? 4 :
(PN == 11) ? 8 :
(PN == 15) ? 0 :
(PN == 17) ? 2 :
(PN == 23) ? 17 :
(PN == 31) ? 27 :
(PN == 32) ? 21 :
(PN == 36) ? 24 :
(PN == 41) ? 37 : 0;
logic [PN - 1 : 0] lfsr;
always_comb begin
o_prbs = lfsr[PN - 1];
o_prbs_n = ~lfsr[PN - 1];
end
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
end
endmoduleprbs_tb.sv
`timescale 1ns / 1ps
module 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;
logic clk = '0;
logic s_rst_n = '0;
logic en = '0;
logic prbs = '0;
logic prbs_n = '0;
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 )
);
initial begin
forever begin
#( CLOCK_PERIOD / 2 ) clk = !clk;
end
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
$finish;
end
endmoduleprbs_wide.sv
`timescale 1ns / 1ps
module 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) ? 7 :
(PN == 11) ? 10 :
(PN == 15) ? 14 :
(PN == 17) ? 16 :
(PN == 23) ? 22 :
(PN == 31) ? 30 :
(PN == 32) ? 31 :
(PN == 36) ? 35 :
(PN == 41) ? 40 : 0;
localparam integer TAP_0 = (PN == 3) ? 0 :
(PN == 4) ? 2 :
(PN == 5) ? 2 :
(PN == 6) ? 4 :
(PN == 7) ? 0 :
(PN == 9) ? 4 :
(PN == 11) ? 8 :
(PN == 15) ? 0 :
(PN == 17) ? 2 :
(PN == 23) ? 17 :
(PN == 31) ? 27 :
(PN == 32) ? 21 :
(PN == 36) ? 24 :
(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
end
endmoduleprbs_wide_tb.sv
`timescale 1ns / 1ps
module 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;
logic clk = '0;
logic s_rst_n = '0;
logic en = '0;
logic [WIDTH - 1 : 0] prbs = '0;
logic [WIDTH - 1 : 0] prbs_n = '0;
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 )
);
initial begin
forever begin
#( CLOCK_PERIOD / 2 ) clk = !clk;
end
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
$finish;
end
endmodule发布于 2021-11-27 13:03:31
我在两个不同的模拟器(Cadence和Synopsys)上从testbench中的这两行获得编译错误:
logic prbs = '0;
logic prbs_n = '0;由于将这些信号连接到模块实例输出端口,因此不应将它们设置为声明行中的任何值。您的代码有多个信号驱动程序:
logic声明的连续驱动程序。只需在没有赋值的情况下声明信号:
logic prbs ;
logic prbs_n;除此之外,我不认为您的代码有任何其他功能问题。布局遵循良好的编码实践,您可以很好地利用参数。
在测试平台中,您可以利用2状态信号类型。这可能会带来更好的模拟性能,也能更好地传达代码的意图。由于不需要为实例输入驱动x或z,所以可以使用bit而不是logic:
bit clk;
bit s_rst_n;
bit en;由于所有的2状态类型默认为0,因此不需要在声明或其他地方显式地将它们初始化为0。这纯粹是一个方便和偏爱的问题。对于testbench计数器,情况类似:
int tick;您可以使用一行代码简化您的时钟:
always #( CLOCK_PERIOD / 2 ) clk = !clk;在您的设计中,您可以简化组合逻辑如下。更改:
always_comb begin
o_prbs = lfsr[PN - 1];
o_prbs_n = ~lfsr[PN - 1];
end 相当于:
assign o_prbs = lfsr[PN - 1];
assign o_prbs_n = ~o_prbs;这避免了重复lfsr表达式。
https://codereview.stackexchange.com/questions/270417
复制相似问题