Verilog设计实例(1)线性反馈移位寄存器(LFSR)

网友投稿 1063 2022-05-30

博文目录

写在前面

正文

原理

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 data always @(posedge USER_CLK) if(reset_c) begin data_lfsr_r <= `DLY 16'hABCD; //random seed value TX_SRC_RDY_N <= `DLY 1'b1; end else if(!TX_DST_RDY_N) begin 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; end //Connect TX_D to the DATA LFSR register assign TX_D = {1{data_lfsr_r}};

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

相关博客链接

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 valid input i_Seed_DV, // Optional Seed Value input [NUM_BITS-1:0] i_Seed_Data, output [NUM_BITS-1:0] o_LFSR_Data, output o_LFSR_Done ); // internal variables reg [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) begin if (i_Enable == 1'b1) begin if (i_Seed_DV == 1'b1) r_LFSR <= i_Seed_Data; else r_LFSR <= {r_LFSR[NUM_BITS-1:1],r_XNOR}; //left right end end // Create Feedback Polynomials. Based on Application Note: // http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf always @(*) begin case (NUM_BITS) 3: begin r_XNOR = r_LFSR[3] ^~ r_LFSR[2]; end 4: begin r_XNOR = r_LFSR[4] ^~ r_LFSR[3]; end 5: begin r_XNOR = r_LFSR[5] ^~ r_LFSR[3]; end 6: begin r_XNOR = r_LFSR[6] ^~ r_LFSR[5]; end 7: begin r_XNOR = r_LFSR[7] ^~ r_LFSR[6]; end 8: begin r_XNOR = r_LFSR[8] ^~ r_LFSR[6] ^~ r_LFSR[5] ^~ r_LFSR[4]; end 9: begin r_XNOR = r_LFSR[9] ^~ r_LFSR[5]; end 10: begin r_XNOR = r_LFSR[10] ^~ r_LFSR[7]; end 11: begin r_XNOR = r_LFSR[11] ^~ r_LFSR[9]; end 12: begin r_XNOR = r_LFSR[12] ^~ r_LFSR[6] ^~ r_LFSR[4] ^~ r_LFSR[1]; end 13: begin r_XNOR = r_LFSR[13] ^~ r_LFSR[4] ^~ r_LFSR[3] ^~ r_LFSR[1]; end 14: begin r_XNOR = r_LFSR[14] ^~ r_LFSR[5] ^~ r_LFSR[3] ^~ r_LFSR[1]; end 15: begin r_XNOR = r_LFSR[15] ^~ r_LFSR[14]; end 16: begin r_XNOR = r_LFSR[16] ^~ r_LFSR[15] ^~ r_LFSR[13] ^~ r_LFSR[4]; end 17: begin r_XNOR = r_LFSR[17] ^~ r_LFSR[14]; end 18: begin r_XNOR = r_LFSR[18] ^~ r_LFSR[11]; end 19: begin r_XNOR = r_LFSR[19] ^~ r_LFSR[6] ^~ r_LFSR[2] ^~ r_LFSR[1]; end 20: begin r_XNOR = r_LFSR[20] ^~ r_LFSR[17]; end 21: begin r_XNOR = r_LFSR[21] ^~ r_LFSR[19]; end 22: begin r_XNOR = r_LFSR[22] ^~ r_LFSR[21]; end 23: begin r_XNOR = r_LFSR[23] ^~ r_LFSR[18]; end 24: begin r_XNOR = r_LFSR[24] ^~ r_LFSR[23] ^~ r_LFSR[22] ^~ r_LFSR[17]; end 25: begin r_XNOR = r_LFSR[25] ^~ r_LFSR[22]; end 26: begin r_XNOR = r_LFSR[26] ^~ r_LFSR[6] ^~ r_LFSR[2] ^~ r_LFSR[1]; end 27: begin r_XNOR = r_LFSR[27] ^~ r_LFSR[5] ^~ r_LFSR[2] ^~ r_LFSR[1]; end 28: begin r_XNOR = r_LFSR[28] ^~ r_LFSR[25]; end 29: begin r_XNOR = r_LFSR[29] ^~ r_LFSR[27]; end 30: begin r_XNOR = r_LFSR[30] ^~ r_LFSR[6] ^~ r_LFSR[4] ^~ r_LFSR[1]; end 31: begin r_XNOR = r_LFSR[31] ^~ r_LFSR[28]; end 32: begin r_XNOR = r_LFSR[32] ^~ r_LFSR[22] ^~ r_LFSR[2] ^~ r_LFSR[1]; end endcase // 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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

Verilog设计实例(1)线性反馈移位寄存器(LFSR)

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

仿真测试

给出一个简单的仿真测试:

`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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

仿真结果:

代码提示

值得注意的是r_LFSR的定义,内部位从1到NUM_BITS,而非0到NUM_BITS -1;

reg [NUM_BITS:1] r_LFSR = 0;

1

这就意味着移位代码这样写:

r_LFSR <= {r_LFSR[NUM_BITS-1:1],r_XNOR}; //left right

1

也就是低位往高位移,也即左移。

这是根据这张图来的:

至于仿真文件中对仿真输入设计的也十分简单,就是单纯让种子为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) );

1

2

3

4

5

6

7

8

在设计文件内部,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

FPGA

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Dubbo入门 - 分布式系统开发技术
下一篇:【Unity3d日常开发】(十三)Unity3D中实现热力图、风向图、温度图效果
相关文章