用vivado进行FPGA时序仿真练习

一.任务目标
设计一个能求出一个32bit字中两个相邻0之间最大间隙的电路。给出HDL设计及testbench描述,综合后的时序仿真结果及分析说明。

二.设计代码
module homework(
gap,clk,clr,data
);
input clk,clr;
input [31:0]data;
output [4:0]gap;
reg [4:0] gap;
reg [4:0] cnt_k;
reg [4:0] incr_k,store_k
reg [4:0] store_tmp;
reg[4:0] incr_tmp,store_incr_tmp;
parameter s_0=2’b00,s_1=2’b01,s_2=2’b10,sub=4’b0001;
reg [1:0]current_state,next_state;
reg start,bit;
[email protected](posedge clk or negedge clr)
begin
if(!clr)
begin
current_state<=s_0;
cnt_k<=0;
start<=0;
store_k<=0;
store_incr_tmp<=0;
end
else
begin
current_state<=next_state;
if(cnt_k>=31)cnt_k<=0;
else
begin
cnt_k<=cnt_k+1’b1;
bit<= data[cnt_k];
end
start<=1’b1;
store_k<=incr_k;
store_incr_tmp<=incr_tmp;
end
end
[email protected](cnt_k)
begin
if(start)
case(current_state)
s_0:begin//第一个0
if(bit== 0)
begin
next_state<=s_1;incr_k<=cnt_k;
end
else
begin
next_state<=s_0; ;
end
end
s_1:begin//第一个0之后来0了
if(cnt_k== 0)
begin
if(bit== 0)
begin
incr_k<=cnt_k;incr_tmp<=cnt_k-store_k;
if(store_incr_tmp>store_tmp)store_tmp<=store_incr_tmp;
else store_tmp<=store_tmp;
end
else
begin
incr_k<=incr_k;
incr_tmp<=store_incr_tmp;
store_tmp<=store_tmp;
end
next_state<=s_2;
end
else
begin
if(bit==0)
begin
incr_k<=cnt_k;incr_tmp<=cnt_k-store_k;
if(store_incr_tmp>store_tmp)store_tmp<=store_incr_tmp;
else store_tmp<=store_tmp;
end
else
begin
incr_k<=incr_k;
incr_tmp<=store_incr_tmp;
store_tmp<=store_tmp;
end
next_state<=s_1;
end;
end
s_2:begin
next_state<=s_0;
if(store_incr_tmp>store_tmp)gap<=store_incr_tmp-sub;
else gap<=store_tmp-sub;
end
default:next_state<=s_0;
endcase
else
begin
incr_tmp<=0;
store_tmp<=0;
incr_k<=0;
gap<=0;
end
end
endmodule

三.仿真testbench如下
`timescale 1ns / 1ps
module simulation(
);
reg clk,clr;
reg [31:0]data;
wire [4:0]gap;
initial
begin
#0 clr = 0;
#0 clk = 0;
#110 clr=1;
#0 data=32’hffff_7fea;
#800 $finish;
end
always #5 clk = ~clk;
homework test(
.clk(clk),
.clr(clr),
.data(data),
.gap(gap)
);
endmodule
vivado的仿真功能如下:
用vivado进行FPGA时序仿真练习
如果不运行直接仿真,只会显示功能仿真有效,其余四项无效。
用vivado进行FPGA时序仿真练习
点击下面的运行又会多出两项。
用vivado进行FPGA时序仿真练习
点击下面这个运行5项都会有效
用vivado进行FPGA时序仿真练习
同时,这个仿真是最接近真实电路运行状态的。
用vivado进行FPGA时序仿真练习
运行结果展示如下:
用vivado进行FPGA时序仿真练习
当输入data=32’hffff_7fea; 最后得出gap=0x0a,结果正确。
用vivado进行FPGA时序仿真练习
当输入为data=0x7fff_fffe时,输出间隔gap=0x1f,结果正确。
用vivado进行FPGA时序仿真练习
当输入为data=0xabcdefff时,输出间隔gap=4,结果正确。
虽然结果正确,但对于计算间隔incr_tmp信号,次态next_state信号来说,还是会出现毛刺,不稳定值现象,不尽人意!

四.程序分析
用vivado进行FPGA时序仿真练习
上面是时序模块,clr清零信号,时钟上升沿触发。字符命名含义如下:
current_state:现态; next_state:次态; cnt_k:用于计数;
incr_k:当数据某一位出现0时,该位值放入incr_k; store_k:保存计数器incr_k值;
incr_tmp:记下出现两位相邻0之间间隔; store_incr_tmp:保存incr_tmp值;
start:用于信号状态转换有效标志; bit:将输入数据的某一位取出;

用vivado进行FPGA时序仿真练习
状态s_0:判断输入数据的某一位是否为0,是则次态为s_1,incr_k记下该位的位置;
用vivado进行FPGA时序仿真练习
状态s_1:首先判断计数器是否记到一个周期32了,由于使用cnt_k做always触发,所以第一个输入是1,最后一个输入的0。当到一个周期是,次态为s_2;同时再判断是否出现0了,出现了,则计算间隔保存到incr_tmp,再判断与已保存的间隔大小,放store_tmp。
在这里store_incr_tmp其实是在时钟触发下,将incr_tmp赋值给它的,虽然可以将store_incr_tmp替换为incr_tmp,这样虽然功能仿真是正确的,但到了时序仿真会出现各种毛刺,导致错误。同样的对于store_k也是如此,虽然可以替换为cnt_k,逻辑正确,但时序仿真是会出现问题。但就算这样对于保存间隔值incr_tmp信号,次态next_state信号来说,还是会出现毛刺,不稳定值现象。
用vivado进行FPGA时序仿真练习
S_2:通过前面32次的判断,计算后得出最终的间隔值赋给gap得出结果。下面是出结果需要的时间分析。时钟周期是10ns,在清零信号有效时,会触发过程块,但此时start无效,不会进入状态转换,当清零无效时,时钟上升沿触发cnt_k加一,操作完成后又将触发状态转换,这是第一次。所以总时间t=32*10ns=320ns,初始时间是115ns,所以最后一次触发时间(计数值为0时是最后一次触发)为435ns,此时计数值改变(有延迟,与时钟未对齐),接着在触发状态转移得出间隔值(有延迟)。
用vivado进行FPGA时序仿真练习