博文目录
- 写在前面
- 正文
-
- 原理
- Verilog实现
- 仿真测试
- 代码提示
- 参考资料
- 交个朋友
写在前面
相关博文
博客首页
注:学习交流使用!
正文
原理
线性反馈移位寄存器(LFSR)的英文全称为:Linear Feedback Shift Register。
赛灵思公司的高速串口IP核示例程序经常以LFSR为例,例如Aurora IP的例子程序:
//______________________________ Transmit Data __________________________________ //Transmit data when TX_DST_RDY_N is asserted.//Random data is generated using XNOR feedback LFSR//TX_SRC_RDY_N is asserted on every cycle with dataalways @(posedge USER_CLK)if(reset_c)begindata_lfsr_r <= `DLY 16'hABCD; //random seed valueTX_SRC_RDY_N <= `DLY 1'b1; endelse if(!TX_DST_RDY_N)begindata_lfsr_r <= `DLY {!{data_lfsr_r[3]^data_lfsr_r[12]^data_lfsr_r[14]^data_lfsr_r[15]},data_lfsr_r[0:14]};TX_SRC_RDY_N <= `DLY 1'b0;end//Connect TX_D to the DATA LFSR registerassign TX_D = {1{data_lfsr_r}};
相关博客链接
LFSR代表线性反馈移位寄存器,它是一种在FPGA内部有用的设计。 LFSR易于合成,这意味着它们占用的资源相对较少,并且可以在FPGA内部以很高的时钟速率运行。 使用LFSR可以使许多应用受益,包括:
- 计数器(Counters)
- 测试码型发生器(Test Pattern Generators)
- 数据加扰(Data Scrambling)
- 密码学(Cryptography)
线性反馈移位寄存器实现为FPGA内部的一系列触发器,这些触发器连接在一起作为移位寄存器。 移位寄存器链的多个抽头用作XOR或XNOR门的输入。 然后,此门的输出用作对移位寄存器链开始的反馈,因此用作LFSR中的反馈。
例如5bit的LFSR的一种形式:
运行LFSR时,由各个触发器生成的模式是伪随机的,这意味着它接近随机。 它不是完全随机的,因为从LFSR模式的任何状态,您都可以预测下一个状态。 有一些重要的移位寄存器属性需要注意:
- LFSR模式是伪随机的。
- 输出模式是确定性的。 您可以通过了解XOR门的位置以及当前模式来确定下一个状态。
当抽头使用XOR门时,全0的模式不会出现。 由于0与0异或将始终产生0,因此LFSR将停止运行。 - 当抽头使用XNOR门时,全1的模式将不会出现。 由于将1与1进行异或运算将始终产生1,因此LFSR将停止运行。
- 任何LFSR的最大可能迭代次数= 2^Bits-1
更长的LFSR将花费更长的时间来运行所有迭代。 N位LFSR的最大可能迭代次数为2^N-1。
如果您考虑一下,所有N位长的东西的所有可能模式都是2^N。 因此,只有一种模式无法使用LFSR表示。 当使用XOR门时,该模式全为0,而使用XNOR门作为您的反馈门时全为1。
VHDL和Verilog代码创建所需的任何N位宽的LFSR。 它使用多项式(这是LFSR背后的数学方法)为每个位宽创建最大可能的LFSR长度。
因此,对于3位,需要2^3-1 = 7个时钟来运行所有可能的组合;
对于4位:2^4-1 = 15;
对于5位:2^5-1 = 31,依此类推。
我基于XNOR实现 以允许FPGA在LFSR上以全零状态启动。 这是Xilinx发布的所有LFSR模式的完整表。
Verilog实现
下面给出Verilog实现代码:
`timescale 1ns / 1ps
//
// Company:
// Engineer: Reborn Lee
// Create Date: 2020/06/01 12:50:38
// Design Name:
// Module Name: lfsr
// Revision 0.01 - File Created
// Additional Comments:
//
//module lfsr #(parameter NUM_BITS = 3)(input i_Clk,input i_Enable,// data validinput i_Seed_DV,// Optional Seed Valueinput [NUM_BITS-1:0] i_Seed_Data,output [NUM_BITS-1:0] o_LFSR_Data,output o_LFSR_Done);// internal variablesreg [NUM_BITS:1] r_LFSR = 0;reg r_XNOR;// Purpose: Load up LFSR with Seed if Data Valid (DV) pulse is detected.// Othewise just run LFSR when enabled.always @(posedge i_Clk)beginif (i_Enable == 1'b1)beginif (i_Seed_DV == 1'b1)r_LFSR <= i_Seed_Data;elser_LFSR <= {r_LFSR[NUM_BITS-1:1],r_XNOR}; //left rightendend// Create Feedback Polynomials. Based on Application Note:// http://www.xilinx.com/support/documentation/application_notes/xapp052.pdfalways @(*)begincase (NUM_BITS)3: beginr_XNOR = r_LFSR[3] ^~ r_LFSR[2];end4: beginr_XNOR = r_LFSR[4] ^~ r_LFSR[3];end5: beginr_XNOR = r_LFSR[5] ^~ r_LFSR[3];end6: beginr_XNOR = r_LFSR[6] ^~ r_LFSR[5];end7: beginr_XNOR = r_LFSR[7] ^~ r_LFSR[6];end8: beginr_XNOR = r_LFSR[8] ^~ r_LFSR[6] ^~ r_LFSR[5] ^~ r_LFSR[4];end9: beginr_XNOR = r_LFSR[9] ^~ r_LFSR[5];end10: beginr_XNOR = r_LFSR[10] ^~ r_LFSR[7];end11: beginr_XNOR = r_LFSR[11] ^~ r_LFSR[9];end12: beginr_XNOR = r_LFSR[12] ^~ r_LFSR[6] ^~ r_LFSR[4] ^~ r_LFSR[1];end13: beginr_XNOR = r_LFSR[13] ^~ r_LFSR[4] ^~ r_LFSR[3] ^~ r_LFSR[1];end14: beginr_XNOR = r_LFSR[14] ^~ r_LFSR[5] ^~ r_LFSR[3] ^~ r_LFSR[1];end15: beginr_XNOR = r_LFSR[15] ^~ r_LFSR[14];end16: beginr_XNOR = r_LFSR[16] ^~ r_LFSR[15] ^~ r_LFSR[13] ^~ r_LFSR[4];end17: beginr_XNOR = r_LFSR[17] ^~ r_LFSR[14];end18: beginr_XNOR = r_LFSR[18] ^~ r_LFSR[11];end19: beginr_XNOR = r_LFSR[19] ^~ r_LFSR[6] ^~ r_LFSR[2] ^~ r_LFSR[1];end20: beginr_XNOR = r_LFSR[20] ^~ r_LFSR[17];end21: beginr_XNOR = r_LFSR[21] ^~ r_LFSR[19];end22: beginr_XNOR = r_LFSR[22] ^~ r_LFSR[21];end23: beginr_XNOR = r_LFSR[23] ^~ r_LFSR[18];end24: beginr_XNOR = r_LFSR[24] ^~ r_LFSR[23] ^~ r_LFSR[22] ^~ r_LFSR[17];end25: beginr_XNOR = r_LFSR[25] ^~ r_LFSR[22];end26: beginr_XNOR = r_LFSR[26] ^~ r_LFSR[6] ^~ r_LFSR[2] ^~ r_LFSR[1];end27: beginr_XNOR = r_LFSR[27] ^~ r_LFSR[5] ^~ r_LFSR[2] ^~ r_LFSR[1];end28: beginr_XNOR = r_LFSR[28] ^~ r_LFSR[25];end29: beginr_XNOR = r_LFSR[29] ^~ r_LFSR[27];end30: beginr_XNOR = r_LFSR[30] ^~ r_LFSR[6] ^~ r_LFSR[4] ^~ r_LFSR[1];end31: beginr_XNOR = r_LFSR[31] ^~ r_LFSR[28];end32: beginr_XNOR = r_LFSR[32] ^~ r_LFSR[22] ^~ r_LFSR[2] ^~ r_LFSR[1];endendcase // case (NUM_BITS)end // always @ (*)assign o_LFSR_Data = r_LFSR[NUM_BITS:1];// Conditional Assignment (?)assign o_LFSR_Done = (r_LFSR[NUM_BITS:1] == i_Seed_Data) ? 1'b1 : 1'b0;endmodule
仿真测试
给出一个简单的仿真测试:
`timescale 1ns / 1ps
module lfsr_tb ();parameter c_NUM_BITS = 4;reg r_Clk = 1'b0;wire [c_NUM_BITS-1:0] w_LFSR_Data;wire w_LFSR_Done;lfsr #(.NUM_BITS(c_NUM_BITS)) LFSR_inst(.i_Clk(r_Clk),.i_Enable(1'b1),.i_Seed_DV(1'b0),.i_Seed_Data({c_NUM_BITS{1'b0}}), // Replication.o_LFSR_Data(w_LFSR_Data),.o_LFSR_Done(w_LFSR_Done));always @(*)#10 r_Clk <= ~r_Clk; endmodule // LFSR_TB
仿真结果:
代码提示
值得注意的是r_LFSR的定义,内部位从1到NUM_BITS,而非0到NUM_BITS -1;
reg [NUM_BITS:1] r_LFSR = 0;
这就意味着移位代码这样写:
r_LFSR <= {r_LFSR[NUM_BITS-1:1],r_XNOR}; //left right
也就是低位往高位移,也即左移。
这是根据这张图来的:
至于仿真文件中对仿真输入设计的也十分简单,就是单纯让种子为0,也即初始值为0,之后进行反馈移位操作。
lfsr #(.NUM_BITS(c_NUM_BITS)) LFSR_inst(.i_Clk(r_Clk),.i_Enable(1'b1),.i_Seed_DV(1'b0),.i_Seed_Data({c_NUM_BITS{1'b0}}), // Replication.o_LFSR_Data(w_LFSR_Data),.o_LFSR_Done(w_LFSR_Done));
在设计文件内部,r_LFSR初始值就是为0,因此,不给种子也可以,反正i_Seed_DV本身在测试文件中就无效。
关于反馈多项式是如何确定的呢?
正是上面提供的文档:
抽头确定
此表列出了最大长度为168位的LFSR计数器的相应抽头。前40位的基本描述和表最初在XCELL中发布,并在1993年和1994年Xilinx数据手册的第9-24页上重印。
- n位LFSR计数器的最大序列长度可以是2^n-1。在这种情况下,它会经历所有可能的代码排列,除了一个锁定状态。
- 最大长度的n位LFSR计数器由一个n位移位寄存器组成,该移位寄存器在从最后输出Qn到第一输入D1的反馈路径中具有XNOR。XNOR将锁定状态设为all-one状态,也就是说如果种子为全1,则LFSR将锁定,其最终移位结果永远为1;XOR将锁定状态设为all-zeros状态。
- 对于普通的Xilinx应用程序,全1的触发器都更容易避免,因为“默认情况下”触发器在全零状态下唤醒。
- Table3描述了必须用作XNOR输入的输出。LFSR输出通常标记为1到n,1是移位寄存器的第一级,n是最后一级。这与二进制计数器的传统0到(n-1)表示法不同。多输入XNOR也称为均匀奇偶校验电路。
- 请注意,此表中描述的连接不一定唯一;某些其他连接也可能导致最大长度序列。
参考资料
参考资料1
参考资料2
交个朋友
FPGA/IC技术交流2020