【SWJTU】智能芯片与嵌入式系统实验三 第四周
本文介绍了实验三的数据产生模块设计与实现。通过Verilog语言实现了伪随机序列发生器(PnSeq_Gen5407)和并行数据生成模块(PixDat_Gen5407)。前者采用7位移位寄存器生成伪随机序列,后者通过串并转换将1位序列扩展为8位并行输出。实验还设计了数据接收模块(Dat_Rx5407),使用状态机控制数据接收和输出流程,并通过寄存器数组模拟RAM功能。测试仿真验证了模块功能符合要求,
完成《实验指导书》实验三:
设计要求:
- 实现“数据产生模块”的功能
- 掌握嵌入式逻辑分析仪(SignalTap)的设置和使用(实验三附录)
- 学习采用“功能仿真+芯片验证”方式进行芯片工程设计
伪随机数据序列发生器

通过寄存器不停地移位循环来实现伪随机的数据输出,代码如下。
这里ShiftReg定义为[7:1]或者是[1:7],异或的位数都是2,3,4,7,不会改变,只是如果1-7作为位置去理解,7-1作为高位低位去理解,图中右边为二进制的高位
module PnSeq_Gen5407(
input clk,
input rst_n,
output seqout
);
reg [7:1] Shiftreg;
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
Shiftreg[7] <= 1'b0;
Shiftreg[6] <= 1'b1;
Shiftreg[5] <= 1'b1;
Shiftreg[4] <= 1'b0;
Shiftreg[3] <= 1'b0;
Shiftreg[2] <= 1'b0;
Shiftreg[1] <= 1'b0;
end else begin
Shiftreg[7] <= Shiftreg[6];
Shiftreg[6] <= Shiftreg[5];
Shiftreg[5] <= Shiftreg[4];
Shiftreg[4] <= Shiftreg[3];
Shiftreg[3] <= Shiftreg[2];
Shiftreg[2] <= Shiftreg[1];
Shiftreg[1] <= Shiftreg[7]^Shiftreg[4]^Shiftreg[3]^Shiftreg[2];
end
end
assign seqout = Shiftreg[7];
endmodule
数据产生模块
这里先定义了几个关键信号,随机数输出使能datagen_en,随机数据输出有效dataout_valid,随机数据输出dataout为实际产生的输出。
观察时序关系,要求为:模块接收到datagen_en的上升沿信号,在下一个时钟来临时dataout_valid置高表示开始输出,同时输出并行的随机数据。
我们看到上一个子模块里的输出seqout是一个1位宽的数据,但是在产生模块里,要求连续输出6个8位宽的随机数,每个时钟周期输出1个随机数,这里需要用到两个较为关键的逻辑
- 串并转换
定义一个模块内寄存器[7:0]DatReg,通过寄存器移位实现了“并行”
//串并变换
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
DatReg <= 8'b0;
end else begin //串行伪随机序列一次写入寄存器
// DatReg <= {DatReg[6:0],seqout};
DatReg[7] <= DatReg[6];
DatReg[6] <= DatReg[5];
DatReg[5] <= DatReg[4];
DatReg[4] <= DatReg[3];
DatReg[3] <= DatReg[2];
DatReg[2] <= DatReg[1];
DatReg[1] <= DatReg[0];
DatReg[0] <= seqout;
end
end
assign dataout = DatReg; //输出8位并行随机数据
- 计数逻辑
-
//输出数据计数 always@(posedge clk or negedge rst_n) begin if(!rst_n) begin cnt_dout <= 3'd0; //计数器初值置0 end else begin if(!delay_datagen_en&&datagen_en) begin //使能信号出现上升沿 cnt_dout <= cnt_dout +3'b1; //开始计数 end else if(cnt_dout > 3'd0 && cnt_dout <= 3'd6) begin cnt_dout <= cnt_dout +3'b1; end else begin cnt_dout <= 3'd0; end end end
由于检测的是输出使能的上升沿,还需要一个边沿检测的小逻辑,最后给出完整模块代码:
module PixDat_Gen5407(
input clk,
input rst_n,
input datagen_en, //随机数输出使能
output reg dataout_valid, //随机数输出有效
output [7:0] dataout //随机数据输出
);
reg [7:0] DatReg; //数据输出寄存器
reg [2:0] cnt_dout; //计数器
reg delay_datagen_en; //延时一拍判断上升沿
wire seqout;
PnSeq_Gen5407 p1(
.clk(clk),
.rst_n(rst_n),
.seqout(seqout)
);
//串并变换
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
DatReg <= 8'b0;
end else begin //串行伪随机序列一次写入寄存器
// DatReg <= {DatReg[6:0],seqout};
DatReg[7] <= DatReg[6];
DatReg[6] <= DatReg[5];
DatReg[5] <= DatReg[4];
DatReg[4] <= DatReg[3];
DatReg[3] <= DatReg[2];
DatReg[2] <= DatReg[1];
DatReg[1] <= DatReg[0];
DatReg[0] <= seqout;
end
end
assign dataout = DatReg; //输出8位并行随机数据
//使能信号延时
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
delay_datagen_en <= 1'b0;
end else begin
delay_datagen_en <= datagen_en;
end
end
//输出数据计数
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt_dout <= 3'd0; //计数器初值置0
end else begin
if(!delay_datagen_en&&datagen_en) begin //使能信号出现上升沿
cnt_dout <= cnt_dout +3'b1; //开始计数
end else if(cnt_dout > 3'd0 && cnt_dout <= 3'd6) begin
cnt_dout <= cnt_dout +3'b1;
end else begin
cnt_dout <= 3'd0;
end
end
end
//产生数据输出有效信号
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
dataout_valid <= 1'b0;
end else begin
if(cnt_dout > 3'd0 && cnt_dout <= 3'd6) begin
dataout_valid <= 1'b1;
end else dataout_valid <= 1'b0;
end
end
endmodule
测试代码
`timescale 1ns/100ps
module test_PixDatGen5407;
reg clk;
reg rst_n;
reg datagen_en;
wire dataout_valid;
wire [7:0] dataout;
//实例化
PixDat_Gen5407 uut(
.clk(clk),
.rst_n(rst_n),
.datagen_en(datagen_en),
.dataout_valid(dataout_valid),
.dataout(dataout)
);
initial begin
clk = 1'b0;
rst_n = 1'b0;
datagen_en = 1'b0;
#50;
rst_n = 1'b1;
#50;
datagen_en = 1'b1;
#10;
datagen_en = 1'b0;
end
always begin
clk = ~clk;
#10;
end
endmodule
最后看到的仿真效果如下:
可以看到逻辑上是符合要求的。
下周实验准备
由于本人并没有学过RAM存储还有锁相环一系列操作,所以只写出了用寄存器代替的接收子模块的代码,并进行了简单的仿真,重要的是理解状态机转换的逻辑,先给出完整代码。
module Dat_Rx5407(
input clk,
input rst_n,
input dataout_valid, // 随机数输入有效
input [7:0] dataout, // 随机数据输入
output reg waitdata, // 等待数据输入
output reg datavalid, // 数据输出有效
output reg [7:0] data // 数据输出
);
reg [1:0] next_state, current_state;
localparam S_IDLE = 2'b00; // 空闲
localparam S_RECV = 2'b01; // 接收
localparam S_OUT = 2'b10; // 输出
localparam S_READY = 2'b11; // 等待
integer i;
// 存储器用寄存器数组模拟RAM
reg [7:0] mem [0:5];
reg [2:0] cnt_recv; // 已接收数据个数:0~6
reg [2:0] cnt_send; // 已输出数据个数:0~6
// 状态寄存器
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
current_state <= S_IDLE;
end else begin
current_state <= next_state;
end
end
// 下一状态逻辑
always @(*) begin
case(current_state)
S_IDLE: begin
next_state = S_READY;
end
S_READY: begin
if(dataout_valid)
next_state = S_RECV;
else
next_state = S_READY;
end
S_RECV: begin
if(cnt_recv == 3'd6)
next_state = S_OUT;
else
next_state = S_RECV;
end
S_OUT: begin
if(cnt_send == 3'd6)
next_state = S_IDLE;
else
next_state = S_OUT;
end
default: next_state = S_IDLE;
endcase
end
// 时序逻辑
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt_recv <= 3'b0;
cnt_send <= 3'b0;
waitdata <= 1'b0;
datavalid <= 1'b0;
data <= 8'd0;
for(i = 0; i < 6; i = i + 1)
mem[i] <= 8'd0;
end else begin
case(current_state)
S_IDLE: begin
waitdata <= 1'b0;
datavalid <= 1'b0;
data <= 8'd0;
cnt_recv <= 3'b0;
cnt_send <= 3'b0;
end
S_READY: begin
waitdata <= 1'b1;
datavalid <= 1'b0;
data <= 8'd0;
if(dataout_valid) begin
mem[0] <= dataout;
cnt_recv <= 3'd1;
end
end
S_RECV: begin
waitdata <= 1'b0;
datavalid <= 1'b0;
data <= 8'd0;
if(dataout_valid && (cnt_recv < 3'd6)) begin
mem[cnt_recv] <= dataout;
cnt_recv <= cnt_recv + 3'd1;
end
end
S_OUT: begin
waitdata <= 1'b0;
if(cnt_send < 3'd6) begin
datavalid <= 1'b1;
data <= mem[cnt_send];
cnt_send <= cnt_send + 3'd1;
end else begin
datavalid <= 1'b0;
data <= 8'd0;
end
end
default: begin
cnt_recv <= 3'b0;
cnt_send <= 3'b0;
waitdata <= 1'b0;
datavalid <= 1'b0;
data <= 8'd0;
end
endcase
end
end
endmodule
测试代码
`timescale 1ns/100ps
module test_PixDatGen5407;
reg clk;
reg rst_n;
reg datagen_en;
wire dataout_valid;
wire [7:0] dataout;
//实例化
PixDat_Gen5407 uut(
.clk(clk),
.rst_n(rst_n),
.datagen_en(datagen_en),
.dataout_valid(dataout_valid),
.dataout(dataout)
);
initial begin
clk = 1'b0;
rst_n = 1'b0;
datagen_en = 1'b0;
#50;
rst_n = 1'b1;
#50;
datagen_en = 1'b1;
#10;
datagen_en = 1'b0;
end
always begin
clk = ~clk;
#10;
end
endmodule

可以看到仿真的效果和老师给出的时序关系也是比较符合的,但是有一个细节上的小问题,就是由于我的状态机设置了4个状态,并且在S_IDLE待机到S_READY接收的状态是无条件转换的,这就导致在结束这个第一轮仿真之后,waitdata会被持续拉高,这个其实我还没有想好怎么解决,不过影响应该不是很大。
更多推荐



所有评论(0)