【问题标题】:LSFR counter for random numberLSFR 随机数计数器
【发布时间】:2015-02-18 14:45:36
【问题描述】:
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 位随机数生成器。

【问题讨论】:

标签: random verilog


【解决方案1】:

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

反馈是矩阵的最后一行看到的第一位和最后一位的异或。所有其他行只是一个班次。这个 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;

TL;DR

现在要控制跳跃式迭代,让工具完成乘以转移矩阵的繁重工作。

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。

【讨论】:

    【解决方案2】:

    如果你想实现一个 N 位 LFSR,那么因为 LFSR 的每个长度都有一个不同的多项式,因此有一组不同的抽头来 XOR 以产生下一个 LFSR 值,你需要有常量或查找根据“BITS”描述设计可以使用的不同抽头点的表格。

    一个更简单的方法可能是实现一个 32 位 LFSR,然后使用它的最低有效 N 位作为输出。除了最大长度 LFSR 之外,这还具有增加重复周期的额外好处,从而在这些情况下提供更好的随机性。

    如果您选择第一个选项,请查看使用 Fibonacci 形式而不是 Galois 形式是否会使设计更有利于以这种方式进行参数化。我无法确定您在 5 位示例中使用的是哪种形式。

    我是 VHDL 人*,所以我不能提供 Verilog 代码,但 VHDL 类伪代码(未经测试)可能如下所示:

    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;
    

    这将支持 BITS 介于 2 和 8 之间,假设表格已完成。常数 TAPS_TABLE 将在综合过程中被优化掉,让您得到的资源消耗不亚于手动编码的 LFSR。

    * 这个问题最初有一个“VHDL”标签。

    【讨论】:

    • "N 位 LFSR,然后因为每个 LFSR 有不同的多项式" ..."您需要有描述不同抽头点的常数或查找表"。我不明白这背后的逻辑。为什么我们对单个 LFSR 使用不同的多项式?
    • “除了最大长度 LFSR”,我们为什么不构建最大长度 LFSR?
    • 如果您打算简单地实现一个 32 位 LFSR,那么只需通过取 32 位寄存器的最低有效 N 位来创建不同大小的输出,“N”的任何值不是 32 (本例中的最大长度)将给出一个比实施长度为 N 的 LFSR 时更长的随机序列。这就是我的评论的意思。
    • 如果您采用我提出的另一种选择,即生成一个在 LFSR 中具有指定位数的 LFSR(不仅仅是输出),那么当然不同大小的 LFSR代码可以产生,每个都需要不同的水龙头。
    【解决方案3】:

    除了前面的答案:

    几年前,Xilinx 写了一篇关于如何实现“伪随机数生成器”(PRNG) 的优秀 AppNote。 AppNote 有一个用于 n = 3..168 的 TAP 表。 TAP 表经过优化以允许使用移位寄存器。因此,n=32 的 PRNG 不使用 32 个单个 FF。

    Efficient Shift Registers, LFSR Counters, and Long PseudoRandom Sequence GeneratorsXilinx [XAPP 052][1996.07.07]

    【讨论】:

    • 但我需要在 verilog 中实现 LSFR。
    • 本文档不特定于任何 HDL。您应该能够将提供的原理图翻译成 Verilog,不是吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-29
    • 1970-01-01
    • 2015-06-26
    • 2019-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多