//____________________________ 传输数据____________________________________
//当TX_DST_RDY_N置位时发送数据。
//使用XNOR反馈LFSR生成随机数据
//TX_SRC_RDY_N 在每个数据周期均有效
总是@(posege USER_CLK)
如果(重置_c)
开始
data_lfsr_r=`DLY 16"hABCD; //随机种子值
TX_SRC_RDY_N=`DLY 1"b1;
结尾
否则如果(!TX_DST_RDY_N)
开始
data_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;
结尾
//将TX_D连接到DATA LFSR寄存器
分配TX_D={1{data_lfsr_r}};相关博客链接
LFSR 代表线性反馈移位寄存器,这是FPGA 内部有用的设计。 LFSR 易于综合,这意味着它们占用相对较少的资源,并且可以在FPGA 内以非常高的时钟速率运行。使用LFSR 可以使许多应用受益,包括:
计数器测试模式生成器数据加扰密码学线性反馈移位寄存器在FPGA 内部实现为一系列触发器,这些触发器作为移位寄存器连接在一起。移位寄存器链的多个抽头用作XOR 或XNOR 门的输入。然后,该门的输出用作移位寄存器链开头的反馈,从而用作LFSR 中的反馈。
例如,5bit LFSR的一种形式:
5 位LFSR 运行LFSR 时,各个触发器生成的模式是伪随机的,这意味着它接近随机。它不是完全随机的,因为从LFSR 模式的任何状态您都可以预测下一个状态。有一些重要的移位寄存器属性需要注意:
LFSR 模式是伪随机的。输出模式是确定性的。您可以通过了解异或门的位置和当前模式来确定下一个状态。
当抽头使用异或门时,不会出现全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实现代码如下:
`时间刻度1ns/1ps
/////////////////////////////////////////////////////////////////////////////////////////////////////
//工程师: Reborn Lee
//模块名称: lfsr
//https://blog.csdn.net/Reborn_Lee
/////////////////////////////////////////////////////////////////////////////////////////////////////
模块lfsr #(参数NUM_BITS=3)(
输入i_Clk,
输入i_Enable,
//数据有效
输入i_Seed_DV,
//可选的种子值
输入[NUM_BITS-1:0] i_Seed_Data,
输出[NUM_BITS-1:0] o_LFSR_Data,
输出o_LFSR_Done
);
//内部变量
reg [NUM_BITS:1] r_LFSR=0;
reg r_XNOR;
//Purpose: 如果检测到数据有效(DV) 脉冲,则用种子加载LFSR。
//否则,在启用时运行LFSR。
总是@(posege i_Clk)
开始
if (i_Enable==1"b1)
开始
如果(i_Seed_DV==1"b1)
r_LFSR=i_Seed_Data;
别的
r_LFSR={r_LFSR[NUM_BITS-1:1],r_XNOR}; //左右
结尾
结尾
//创建反馈多项式。基于应用笔记:
//http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf
总是@(*)
开始
案例(NUM_BITS)
3:开始
r_XNOR=r_LFSR[3] ^~ r_LFSR[2];
结尾
4:开始
r_XNOR=r_LFSR[4] ^~ r_LFSR[3];
结尾
5:开始
r_XNOR=r_LFSR[5] ^~ r_LFSR[3];
结尾
6:开始
r_XNOR=r_LFSR[6] ^~ r_LFSR[5];
结尾
7:开始
r_XNOR=r_LFSR[7] ^~ r_LFSR[6];
结尾
8:开始
r_XNOR=r_LFSR[8] ^~ r_LFSR[6] ^~ r_LFSR[5] ^~ r_LFSR[4];
结尾
9:开始
r_XNOR=r_LFSR[9] ^~ r_LFSR[5];
结尾
10:开始
r_XNOR=r_LFSR[10] ^~ r_LFSR[7];
结尾
11:开始
r_XNOR=r_LFSR[11] ^~ r_LFSR[9];
结尾
12:开始
r_XNOR=r_LFSR[12] ^~ r_LFSR[6] ^~ r_LFSR[4] ^~ r_LFSR[1];
结尾
13:开始
r_XNOR=r_LFSR[13] ^~ r_LFSR[4] ^~ r_LFSR[3] ^~ r_LFSR[1];
结尾
14:开始
r_XNOR=r_LFSR[14] ^~ r_LFSR[5] ^~ r_LFSR[3] ^~ r_LFSR[1];
结尾
15:开始
r_XNOR=r_LFSR[15] ^~ r_LFSR[14];
结尾
16:开始
r_XNOR=r_LFSR[16] ^~ r_LFSR[15] ^~ r_LFSR[13] ^~ r_LFSR[4];
结尾
17:开始
r_XNOR=r_LFSR[17] ^~ r_LFSR[14];
结尾
18:开始
r_XNOR=r_LFSR[18] ^~ r_LFSR[11];
结尾
19:开始
r_XNOR=r_LFSR[19] ^~ r_LFSR[6] ^~ r_LFSR[2] ^~ r_LFSR[1];
结尾
20:开始
r_XNOR=r_LFSR[20] ^~ r_LFSR[17];
结尾
21:开始
r_XNOR=r_LFSR[21] ^~ r_LFSR[19];
结尾
22:开始
r_XNOR=r_LFSR[22] ^~ r_LFSR[21];
结尾
23:开始
r_XNOR=r_LFSR[23] ^~ r_LFSR[18];
结尾
24:开始
r_XNOR=r_LFSR[24] ^~ r_LFSR[23] ^~ r_LFSR[22] ^~ r_LFSR[17];
结尾
25:开始
r_XNOR=r_LFSR[25] ^~ r_LFSR[22];
结尾
26:开始
r_XNOR=r_LFSR[26] ^~ r_LFSR[6] ^~ r_LFSR[2] ^~ r_LFSR[1];
结尾
27:开始
r_XNOR=r_LFSR[27] ^~ r_LFSR[5] ^~ r_LFSR[2] ^~ r_LFSR[1];
结尾
28:开始
r_XNOR=r_LFSR[28] ^~ r_LFSR[25];
结尾
29:开始
r_XNOR=r_LFSR[29] ^~ r_LFSR[27];
结尾
30:开始
r_XNOR=r_LFSR[30] ^~ r_LFSR[6] ^~ r_LFSR[4] ^~ r_LFSR[1];
结尾
31:开始
r_XNOR=r_LFSR[31] ^~ r_LFSR[28];
结尾
32:开始
r_XNOR=r_LFSR[32] ^~ r_LFSR[22] ^~ r_LFSR[2] ^~ r_LFSR[1];
结尾
endcase //情况(NUM_BITS)
结束//始终@ (*)
分配o_LFSR_Data=r_LFSR[NUM_BITS:1];
//条件赋值(?)
分配o_LFSR_Done=(r_LFSR[NUM_BITS:1]==i_Seed_Data) ? 1"b1 : 1"b0;
endmodule
仿真测试
给出了简单的模拟测试:
`时间刻度1ns/1ps
模块lfsr_tb();
参数c_NUM_BITS=4;
reg r_Clk=1"b0;
线路[c_NUM_BITS-1:0] w_LFSR_Data;
连线w_LFSR_Done;
lfsr #(.NUM_BITS(c_NUM_BITS)) LFSR_inst
(.i_Clk(r_Clk),
.i_启用(1"b1),
.i_Seed_DV(1"b0),
.i_Seed_Data({c_NUM_BITS{1"b0}}), //复制
.o_LFSR_Data(w_LFSR_Data),
.o_LFSR_Done(w_LFSR_Done)
);
总是@(*)
#10 r_Clk=~r_Clk;
endmodule //LFSR_TB模拟结果:
5位LFSR仿真图
代码提示
值得注意的是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表示将低位移至高位,即左移。
这是基于这张图:
5位LFSR
至于仿真文件中的仿真输入设计,也很简单,就是简单地让seed为0,即初始值为0,然后进行反馈移位操作。
lfsr #(.NUM_BITS(c_NUM_BITS)) LFSR_inst
(.i_Clk(r_Clk),
.i_启用(1"b1),
.i_Seed_DV(1"b0),
.i_Seed_Data({c_NUM_BITS{1"b0}}), //复制
.o_LFSR_Data(w_LFSR_Data),
.o_LFSR_Done(w_LFSR_Done)
);在设计文件中,r_LFSR的初始值为0。因此,不给出种子也是可以的。无论如何,i_Seed_DV本身在测试文件中是无效的。
反馈多项式是如何确定的?
正是上面提供的文档:
点击确定
最大长度LFSR 抽头确定图此表列出了最大长度为168 位的LFSR 计数器的相应抽头。前40 名的基本描述和表格最初发表在XCELL 中,并重印在1993 年和1994 年Xilinx 数据表的第9-24 页上。
【Verilog编程实践:线性反馈移位寄存器(LFSR)详解】相关文章:
2.米颠拜石
3.王羲之临池学书
8.郑板桥轶事十则
用户评论
Verilog 好有用啊!
有13位网友表示赞同!
终于有机会学习Linear Feedback Shift Register了!
有17位网友表示赞同!
这篇文章能让我学到LFSR的Verilog实现吗?
有15位网友表示赞同!
之前学过理论,现在看实例更清晰了。
有6位网友表示赞同!
动手实践比看书有趣多了!
有20位网友表示赞同!
希望这个实例简单易懂,方便入门学习。
有5位网友表示赞同!
看到标题我立刻想起来那个原理图!
有19位网友表示赞同!
LFSR 感觉很有意思的样子,我要仔细研究一下。
有20位网友表示赞同!
Verilog 的语法我还不太熟练,这篇文章能让我补下这个短板吗?
有20位网友表示赞同!
学习完了可以试试用 LFSR 做点东西!
有18位网友表示赞同!
期待看到详细的Verilog代码和功能讲解。
有7位网友表示赞同!
我经常用到LFSR,希望可以了解一下更深入的内容。
有17位网友表示赞同!
线性反馈移位寄存器可以用在哪些领域?
有6位网友表示赞同!
看完这个实例后,我可以自己写 LFSR 的代码了吗?
有17位网友表示赞同!
不知道这篇文章会讲到LFSR的常见应用场景吗?
有7位网友表示赞同!
希望这些实例能帮我想出一些应用idea。
有6位网友表示赞同!
Verilog的设计技巧很重要,看了这个实例可以增加经验吧!
有19位网友表示赞同!
学习Verilog 真是一件需要耐心的事!
有14位网友表示赞同!
看代码比读理论要容易理解很多。
有8位网友表示赞同!
我很乐意参加LFSR的讨论和交流!
有18位网友表示赞同!