ISE 14.7 FIFO 仿真学习
文章目录
ISE14.7 的 LogiCORE IP FIFO Generator 仿真学习
前言
基于 ISE14.7 的 LogiCORE IP FIFO Generator 仿真学习,主要在于IP核的时序、使用以及注意事项,不会过多介绍FIFO的作用以及配置。
IP核的配置
IP核的配置根据自己的实际情况选择,这里我选择标准的FIFO,使用Native Interface FIFOs 接口,而AXI Interface接口,数据位宽和FIFO深度根据实际需要选择。
整体的配置如下图所示:
仿真验证
复位后FIFO满标志
需要注意的是,在FIFO复位后,是不能马上写数据的,从仿真结果可以看出,full信号和almost_full信号在复位过程中,以及复位结束后的几个CLK内,都为断言状态。
数据写入
其写入时序可参考数据手册,可以看到:
- 写使能为高时,数据写入FIFO,延迟一个时钟后,写响应信号拉高;
- 当FIFO写满时,FULL信号被拉高;
- 当FIFO写满时,再写数据将不会有写响应信号,而会出现OVERFLOW信号。
写入的数据来源于仿真时随机生成的数据,本次写入18个数据,FIFO深度为16个。
for(i=0;i<18;i=i+1) begin
@(posedge clk);
wr_en = 1;
din = ($random) % 256;
end
从仿真结果可以看出,刚开始写入一个数据后,empty被拉高,写入两个数据后,almost_empty信号被拉高,这两个信号一般用于读取FIFO时使用。
当FIFO被写满以后,FULL信号被拉高,再向其中写入数据,OVERFLOW信号被拉高,其中两个数据 0xc5,0xaa理论上不会被写入FIFO。
查看modelsim的仿真数据(从右向左看),可以看到,刚开始写入的0x24,0x81数据和最后写入的0xf9、0xc6数据,0xc5,0xaa由于FIFO写满未被写入FIFO。
因此在使用FIFO时,一定要注意full信号以及写响应wr_ack信号,不然可能会造成数据丢失。
数据读取
其读取时序可参考数据手册,可以看到:
- 都使能为高时,数据读出FIFO,延迟一个时钟后,数据dout和数据有效信号valid断言,读取Latency为1个时钟,在配置IP核的时候也能看见;
- 当FIFO为空时,EMPTY信号被拉高;
- 当FIFO为空时,再读取数据将不会有valid信号,而会出现UNDERFLOW信号。
根据手册,仿真代码比较简单,拉高读取使能持续18个时钟即可。
rd_en = 1;
repeat(18) @(posedge clk);
rd_en = 0;
从仿真结果可以看出,写入的FIFO的数据被以此读出,如果FIFO为空时依旧读取数据,则输出为最后一次读取的数据,不会改变。
可编程满和可编程空信号
FIFO默认提供的满信号是FIFO写满或者只剩一个空间时的信号,但实际这种信号可能不能满足我们的需求,例如FIFO至少有8个数据时,我才开始读取数据,
那么总不能我们根据写入的数据个数来判断吧,这个时候就可以用到PROG_FULL信号,这个在配置IP核的时候会有该选项。
比如你可以将FIFO满的阈值设置为7,那么,一旦FIFO写入的数据为7个时,PROG_FULL信号信号就被拉高,少于7个时,则会拉低。不过需要注意的是,此信号会有1个CLK的延迟。
同样也可以将PROG_FULL的阈值设置10拉高,少于7个拉低,同样注意有1个CLK的延迟。
可编程空信号和可编程满信号同理,只不过一个判断空,一个判断满。
附录
软件版本
modelsim 使用10.4版本。
ISE为14.7版本。
仿真代码
module tb_fifo_indata;
// fifo_indata Parameters
parameter PERIOD = 10;
// fifo_indata Inputs
reg clk = 0 ;
reg rst_n = 0 ;
reg [7 : 0] din = 0 ;
reg wr_en = 0 ;
reg rd_en = 0 ;
// fifo_indata Outputs
wire [7 : 0] dout ;
wire full ;
wire almost_full ;
wire wr_ack ;
wire overflow ;
wire empty ;
wire almost_empty ;
wire valid ;
wire underflow ;
initial
begin
forever #(PERIOD/2) clk=~clk;
end
initial
begin
#(PERIOD*20) rst_n = 1;
end
fifo_indata u_fifo_indata (
.clk ( clk ),
.rst ( ~rst_n ),
.din ( din [7 :0] ),
.wr_en ( wr_en ),
.rd_en ( rd_en ),
.dout ( dout [7 :0] ),
.full ( full ),
.almost_full ( almost_full ),
.wr_ack ( wr_ack ),
.overflow ( overflow ),
.empty ( empty ),
.almost_empty ( almost_empty ),
.valid ( valid ),
.underflow ( underflow )
);
integer i;
initial
begin
@(posedge rst_n);
#(PERIOD*10);
for(i=0;i<18;i=i+1) begin
@(posedge clk);
wr_en = 1;
din = ($random) % 256;
end
@(posedge clk);
wr_en = 0;
#(PERIOD*20);
rd_en = 1;
repeat(18) @(posedge clk);
rd_en = 0;
#(PERIOD*20);
$stop;
end
endmodule