FPGA项目开发:基于FPGA的伪随机数发生器(附代码)
今天是画师和各位大侠见面了,执笔绘画FPGA江湖,本人写了篇关于FPGA的伪随机数发生器学习笔记,这里分享给大家,仅供参考。
一、概念
随机数是专门的随机试验的结果,产生随机数有多种不同的方法。这些方法被称为随机数生成器。随机数最重要的特性是它在产生时后面的那个数与前面的那个数毫无关系。随机数分为三类,分别是伪随机数、密码学安全的伪随机数以及真随机数。
本次设计为基于FPGA生成的伪随机数发生器,什么是伪随机数呢?统计学伪随机性指的是在给定的随机比特流样本中,1的数量大致等于0的数量,同理,“10”“01”“00”“11”四者数量大致相等。类似的标准被称为统计学随机性。满足这类要求的数字在人类“一眼看上去”是随机的。
在实际应用中往往使用伪随机数就足够了。这些数列是“似乎”随机的数,实际上它们是通过一个固定的、可以重复的计算方法产生的。计算机或计算器产生的随机数有很长的周期性。它们不真正地随机,因为它们实际上是可以计算出来的,但是它们具有类似于随机数的统计特征。这样的发生器叫做伪随机数发生器。
二、设计原理
本次设计采用线性反馈移位寄存器(Linear Feedback Shift Register, LFSR)来实现伪随机数发生器。线性反馈移位寄存器是指,给定前一状态的输出,将该输出的线性函数再用作输入的移位寄存器。异或运算是最常见的单比特线性函数:对寄存器的某些位进行异或操作后作为输入,再对寄存器中的各比特进行整体移位。
线性反馈移位寄存器通常由动态或静态主从型触发器构成。反馈回路由异或门构成。其特性通常由一个特征多项式表征。LFSR结构如下图所示:
图1 LFSR结构示意图
对应的特征多项式为:
Gm为多项式的系数,而多项式系数只能为1或0。
利用LFSR生成伪随机数,需要给它一个随机种子(seed),由于它是由N个触发器和异或门组成,所以种子不能给全0,如果给的全0,将会陷入0的死循环一直出不来,就得不到我们想要的伪随机数,在设计时,我们可以给一个任意不为0的数。
基于以上原理,我们使用本原多项式x^32 x^7 x^5 x^3 x^2 x 1来构造最大周期的LFSR。
三、架构设计
设计架构如下图:
将输入时钟命名为clk,复位信号命名为rst_n,输入有效信号命名为ivalid,输入的随机种子命名为seed[31:0],生成的随机数命名为data[31:0]。
四、Verilog 代码实现
代码中data <= seed部分也可以不需要,不用输入有效信号以及随机种子,直接初始化为非零值也可。如直接初始化为非零值,则仿真代码只需进行复位即可。
设计实现代码如下:
代码语言:javascript复制module PRNG(
input wire clk,
input wire rst_n,
input wire ivalid,
input wire [31:0] seed,
output reg [31:0] data
);
always @ (posedge clk,negedge rst_n) begin
if (rst_n == 1'b0)
data <= 32'd0;
else if (ivalid == 1'b1)
data <= seed;
else begin
data[0] <= data[31];
data[1] <= data[0] ^ data[31];
data[2] <= data[1] ^ data[31];
data[3] <= data[2] ^ data[31];
data[4] <= data[3];
data[5] <= data[4] ^ data[31];
data[6] <= data[5];
data[7] <= data[6] ^ data[31];
data[8] <= data[7];
data[9] <= data[8];
data[10] <= data[9];
data[11] <= data[10];
data[12] <= data[11];
data[13] <= data[12];
data[14] <= data[13];
data[15] <= data[14];
data[16] <= data[15];
data[17] <= data[16];
data[18] <= data[17];
data[19] <= data[18];
data[20] <= data[19];
data[21] <= data[20];
data[22] <= data[21];
data[23] <= data[22];
data[24] <= data[23];
data[25] <= data[24];
data[26] <= data[25];
data[27] <= data[26];
data[28] <= data[27];
data[29] <= data[28];
data[30] <= data[29];
data[31] <= data[30];
end
end
endmodule
五、仿真测试及结果
仿真代码如下:
代码语言:javascript复制`timescale 1ns/1ps
module PRNG_tb;
reg clk;
reg rst_n;
reg ivalid;
reg [31:0] seed;
wire [31:0] data;
PRNG PRNG_inst(
.clk (clk),
.rst_n (rst_n),
.ivalid (ivalid),
.seed (seed),
.data (data)
);
initial clk = 1'b0;
always # 5 clk = ~clk;
initial begin
rst_n = 1'b0;
ivalid = 1'b0;
seed = 32'd0;
# 201;
rst_n = 1'b1;
#200;
@ (posedge clk);
# 2;
ivalid = 1'b1;
seed = {$random} % 4294967295;
@ (posedge clk);
# 2;
ivalid = 1'b0;
seed = 32'd0;
#200000;
$stop;
end
endmodule
本次仿真采用100M时钟进行,输入种子为非零随机数。
六、总结
以上是经过学习,集合了各家所长得到的结果。由于想做一个32位的伪随机数发生器,在网上找了各种资料,并没有找到有规定的标准多项式,于是随意定了一个。在实际运用当中,如果有标准的多项式系数,可能得到了一个伪随机数,就可以根据已知的特征式得出后面的结果,安全性也就大大降低了。
完
后续会持续更新,带来Vivado、 ISE、Quartus II 、candence等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。
江湖偌大,继续闯荡,愿大侠一切安好,有缘再见!