module LSFR_counter
#(parameter BITS = 5)
(
input clk,
input rst_n,
output reg [4:0] data
);
reg [4:0] data_next;
always @* begin
data_next[4] = data[4]^data[1];
data_next[3] = data[3]^data[0];
data_next[2] = data[2]^data_next[4];
data_next[1] = data[1]^data_next[3];
data_next[0] = data[0]^data_next[2];
end
always_ff @(posedge clk or negedge rst_n) begin
if(!rst_n)
data <= 5'h1f;
else
data <= data_next;
end
endmodule
这是4位数的LSFR代码。我想为FPGA板实现N位随机数发生器。
答案 0 :(得分:2)
N通常保留用于LFSR的状态,M可以用于我们希望生成的随机位数。
标准LFSR生成1位随机数据,如果使用LFSR的连续位,则它们可以高度相关,尤其是在每个时钟周期采用多位值时。为了消除这种相关性,我们可以对lfsr进行超频,比如4次以产生4位。替代方法是计算每个位得到的方程(反馈多项式)。对于每个时钟,其内部状态(由LFSR的N位表示)将向前移动4步。用于超频或创建反馈抽头以将状态向前移动超过1步的两种技术称为跳跃。
问题中的代码示例取自a previous question and answer,这是为跳跃式lfsr手动创建额外反馈的示例。
这样做的数学可以通过生成转换矩阵并提高我们希望继续前进的步数来实现。
快速4位LFRS示例:使用转换矩阵a:
a =
0 1 0 0
0 0 1 0
0 0 0 1
1 0 0 1
反馈是矩阵最后一行所见的第一位和最后一位的XOR。所有其他行只是一个班次。这个LFSR的输出有利于一位。两位会受到高相关性的影响,除非它被超频。
>> a^2
ans =
0 0 1 0
0 0 0 1
1 0 0 1
1 1 0 1
如果我们想要两位,我们需要对转换矩阵求平方。可以看出前两行是两个位置的移位,我们需要两个位置的反馈,即我们正在为每个时钟向LFSR前进两个状态。
只是为了确认我们是否需要三位:
a^3
ans =
0 0 0 1
1 0 0 1
1 1 0 1
1 1 1 1
上一个问题中的第二个代码示例继续参数化代码,因此不必手动创建跳跃计算,跳过所有可爱的数学!然而,使用的方法意味着它无法完全参数化。因此,我想重温一下我为这个问题提出的例子:
module fibonacci_lfsr(
input clk,
input rst_n,
output [4:0] data
);
wire feedback = data[4] ^ data[1] ;
always @(posedge clk or negedge rst_n)
if (~rst_n)
data <= 4'hf;
else
data <= {data[3:0], feedback} ;
endmodule
现在我们想要参数化:
module fibonacci_lfsr#(
parameter POLYNOMIAL = 4'h9
)(
input clk,
input rst_n,
output [4:0] data
);
//AND data with POLYNOMIAL this
// selects only the taps in the polynomial to be used.
// ^( ) performs a XOR reduction to 1 bit
always @* begin
feedback = ^( POLYNOMIAL & data);
end
//Reseting to 0 is easier
// Invert feedback, all 1's state is banned instead of all 0's
always @(posedge clk or negedge rst_n)
if (~rst_n)
data <= 'b0;
else
data <= {data[3:0], ~feedback};
endmodule
现在迈出一小步,只需将移位置于同步循环之外,以帮助完成后续步骤。
always @* begin
data_next = data;
feedback = ^( POLYNOMIAL & data);
data_next = {data_next[3:0], ~feedback} ; //<- Shift and feedback
end
always @(posedge clk or negedge rst_n)
if (~rst_n)
data <= 'b0;
else
data <= data_next;
现在要控制跳跃式迭代,让工具重复使用转换矩阵。
module fibonacci_lfsr#(
parameter POLYNOMIAL = 4'h9,
parameter N = 4,
parameter BITS = 2
)(
input clk,
input rst_n,
output [BITS-1:0] random
);
reg [N-1:0] data;
reg [N-1:0] data_next;
reg feedback;
assign random = data[N-1:N-BITS];
always @* begin
data_next = data;
// Compiler unrolls the loop, calculating the transition matrix
for (int i=0; i<BITS; i++) begin
feedback = ^( POLYNOMIAL & data_next);
data_next = {data_next[N-2:0], ~feedback} ;
end
end
always @(posedge clk or negedge rst_n)
if (~rst_n)
data <= 'b0;
else
data <= data_next;
endmodule
EDA Playground上的示例。
i++
是SystemVerilog的一部分。如果你只能合成普通的(2009年之前的)Verilog,那么你需要将i声明为整数并在for循环中使用i =i+1
。
答案 1 :(得分:1)
如果你想实现一个N位LFSR,那么因为LFSR的每个长度都有一个不同的多项式,因此有一组不同的抽头到XOR来产生下一个LFSR值,你需要有常量或查找表格描述了设计可以使用的不同分接点,基于&#39; BITS&#39;。
一种更简单的方法可能是实现一个32位LFSR,然后使用它的最低有效N位作为输出。除了最大长度LFSR之外,这还有增加重复周期的额外好处,在这些情况下可以提供更好的随机性。
如果您要选择第一个选项,请查看使用Fibonacci形式而不是Galois形式是否会使设计更有利于以这种方式进行参数化。我无法解决您在5位示例中使用的表单。
我是VHDL人*,所以我无法提供Verilog代码,但VHDL-like-pseudocode(未经测试)可能如下所示:
constant TAPS_TABLE : TAPS_TABLE_type := (
"00000011",
"00000110",
...
);
for i in 0 to BITS-2 loop
if (TAPS_TABLE(BITS-2)(i) = '1') then
data_next(i) <= data(0) xor data(i+1)
else
data_next(i) <= data(i+1)
end if;
end for;
假设表格已完成,这将支持2到8之间的BITS。在合成期间,常量TAPS_TABLE将被优化掉,为您提供的资源不会比手动编码的LFSR更耗费资源。
*这个问题最初有一个VHDL&#39;标签
答案 2 :(得分:0)
除了之前的答案:
多年前,Xilinx就如何实现伪随机数生成器&#39;编写了一个很好的AppNote。器(PRNG)。 AppNote有一个n = 3..168的TAP表。 TAP表经过优化,允许使用移位寄存器。因此,n = 32的PRNG不使用32个单个FF。