同步FIFO设计及仿真

主函数:

module SYNC_fifo#
(
parameter DATA_WIDTH =8,
parameter ADDR_WIDTH =4
)
(
input clk,
input rst_n,
input rd_en,
input wr_en,
input[DATA_WIDTH-1:0] din,
output reg[DATA_WIDTH-1:0] dout,
output wire full,
output wire empty,
output reg[ADDR_WIDTH:0] status_cnt
);

parameter DATA_DEPTH=16;

//address pointer
always@(posedge clk or negedge rst_n)
if(~rst_n)
status_cnt<={(ADDR_WIDTH+1'b1){1'b0}};
else if(rd_en&~empty)
status_cnt<=status_cnt-1'b1;
else if(wr_en&~full)
status_cnt<=status_cnt+1'b1;

assign full = status_cnt==DATA_DEPTH;
assign empty = status_cnt==0;

//write counter
reg [ADDR_WIDTH-1:0] wcnt;

always@(posedge clk or negedge rst_n)
if(~rst_n)
wcnt<=0;
else if(wr_en&&~full)
wcnt<=wcnt+1'b1;

/* write control module */
reg [DATA_WIDTH-1:0]mem[DATA_DEPTH-1:0];

integer i;
always@(posedge clk or negedge rst_n)
if(~rst_n) begin
for(i=0;i<(DATA_DEPTH);i=i+1)
mem[i]<=0;
end
else if(wr_en&~full)
mem[wcnt]<=din;

//read counter
reg [ADDR_WIDTH-1:0] rcnt;

always@(posedge clk or negedge rst_n)
if(~rst_n)
rcnt<=0;
else if(rd_en&&~empty)
rcnt<=1'b1+rcnt;

/* read control module */
always@(posedge clk or negedge rst_n)
if(~rst_n)
dout<={DATA_WIDTH{1'b1}};
else if(rd_en&&~empty)
dout<=mem[rcnt];

endmodule

仿真:

`timescale 1ns/1ns
module fifo_tb;

reg clk;
reg rst_n;
reg rd_en;
reg wr_en;
reg[7:0] din;
wire[7:0] dout;
wire full,empty;


SYNC_fifo fifo(
.clk(clk),
.rst_n(rst_n),
.rd_en(rd_en),
.wr_en(wr_en),
.din(din),
.dout(dout),
.full(full),
.empty(empty)
);

//generate clock
initial begin
clk=0;
forever #10 clk=~clk;
end

initial begin
rst_n=0;
din=16'd0;
rd_en=0;
wr_en=0;
#20;
rst_n=1;
#20;
wr(0); wr(1); wr(2); wr(3); wr(4); wr(5); wr(6); wr(7);
wr(8); wr(9); wr(10); wr(11); wr(12); wr(13); wr(14); wr(15);
#20;
rd;
#20;
// $finish;
end

initial begin
$vcdpluson();
end

//initial begin
//$fsdbDumpfile("fifo.fsdb");
//$fsdbDumpvars(0,fifo_tb);
//end

task wr;
input[3:0] i;
begin
wr_en=1'b1;
din=i;
#20;
wr_en=1'b0;
end
endtask

task rd;
begin
rd_en=1'b1;
#(20*17);
rd_en=1'b0;
end
endtask

endmodule

同步fifo设计的核心在于full与empty信号的控制,结合网上发布的部分verilog代码,虽然可以完成读写操作,但是存在部分问题,就是最后一个数据的读取问题,该问题的导致是因为full与empty信号的控制失误。

Target

设计一个小型distributed FIFO(数据位宽8,地址位宽4,深度16),类型为FWFT(即读数据与读取信号同周期输出),该FIFO使用FPGA内部的LUT资源,不使用FPGA内部的Block memory资源(因为比较小,所以不使用容量较大的BRAM)。

此外,为了练习VCS、VERDI软件操作,熟悉波形dump、Coverage check,对代码进行检测。

对代码进行波形加载、对覆盖率能行检测,使用Verdi进行debug

DVE记录波形

在编译时打开vcdpluson选项($vcdpluson()),在编译脚本中设置生成的vpd文件名。

vpd是Synopsys公司VCS DVE支持的波形文件,可以使用$vcdpluson()产生。

在指令中设置生成的vpd文件名: VPD_NAME=+vpdname+${OUTPUT}.vpd

在编译时打开-debug_all选项,同时打开VPD_NAME开关,存储编译生成的.vpd波形文件,其实此时生成的.vpd文件仅为一个空文件。

在运行仿真即运行生成的二进制可执行文件时,打开VPD_NAME选项,此时生成的.vpd文件中包含波形信息。

打开vpd文件有两种方式:

第一种:先打开dve(dve &),之后在dve中打开.vpd文件

第二种:直接打开,dve -vpd ${OUTPUT}.vpd &

覆盖率检测

代码质量的标准,在编译时打开行、状态、条件、翻转、分支统计选项,并设置保存覆盖率统计文件的文件夹,还可以设置包含覆盖覆盖率信息的文件名:

CM=-cm line+fsm+cond+tgl+tgl

CM_DIR=-cm_dir {OUTPUT}.vdb

CM_NAME=-cm_name BaseFPGA

上述语句分别设置覆盖率文件的统计信息、文件目录、文件名

在编译和运行时打开上述选项,之后通过DVE查看覆盖率信息:

dve -covdir {OUTPUT}.vdb &

 

Verdi波形加载

verdi波形加载需要使用.fsdb文件,生成.fsdb文件有两种方式.

一种是在.v文件中嵌入函数:

$fsdbDumpfile(“xxx.fsdb”);  //指定生成的fsdb文件名字

$fsdbDumpvars(0,top);         //指定Dump波形层次,需要注意top没有.v后缀

另一种方式是调用-ucil/tcl接口,在脚本中进行设置:

在编译时打开Verdi偏移选项,在仿真时调用ucli接口对波形进行Dump。

需要注意的是在仿真时需要设置+fsdb+autoflush即自动将波形转存到.fsdb文件中。

原文地址:https://www.cnblogs.com/luxinshuo/p/13406709.html