Menu Close

FIFO IP核在Vivado 2018.2下的使用(二)同步FIFO, First-Word Fall-Through

1.IP核设置

上一篇FIFO IP核在Vivado 2018.2下的使用(一)中简单的对Native Standard FIFO IP核进行了介绍。以及选用了Common Clock Distributed RAM的时钟和储存类型。最后做了一个简单的仿真,经过分析后,仿真的波形与FIFO IP核文档上的典型波形相符合。

这篇文章会更深一步地学习同步FIFO设置为First-word Fall-Through(FWFT)的情况。在标准的FIFO中,读数据端总是要延迟一个时钟周期,而使用FIFO FWFT模式,可以将读使能(rd_en)和读出的数据做到同步输出。通过上次提到过的FIFO存储配置,如图1所示,可以看到在选用Common Clock Distributed RAM的情况下,FWFT是支持的,可以直接选用。

FIFO存储配置1

FIFO存储配置2

图1 FIFO存储配置 [1]

 

如图2所示为FIFO接口类型,与(一)相同,也是选择的Native。

FIFO接口类型

图2 FIFO接口类型

 

图3是将FIFO读数据端的模式由标准FIFO改为FWFT。FWFT模式的特点是在读数据端无时钟周期延迟。先前也介绍过了,它的作用原理是在不发出读操作的情况下向前浏览FIFO中可用的数据。换而言之,只要FIFO中有数据,第一个可读的数据就会自动出现在数据输出线上 [1]。

FIFO 读端模式

图3 FIFO读数据端模式

 

图4,图5中FIFO数据端参数与握手的设置和(一)一样,数据宽度为一个字节,深度为256。因为Distributed RAM存储类型不支持Non-symmetric Aspect Ratios,所以读写两端的数据宽度必须相等,无法做数据宽度的转换。握手信号目前也是只添加Valid信号,选为Active High,即当读数据端有数据输出时,Valid由低电平变为高电平。

 

数据端参数

图4 FIFO数据端参数设置

 

 

FIFO握手设置

图5 FIFO握手设置

 

图6有新添加的Data Count信号,输出当前FIFO里剩余的数据总数。因为选用的是同步FIFO,所以读写端的时钟一致,只输出一个data_count。

FIFO data count

图6 FIFO Data Count设置

 

FIFO IP核生成的总结如图7所示,关于各项设定的详细解释,可参考上文或上一篇文章。

FIFO设置总结

图7 FIFO 设置总结

 

 

2.仿真

与(一)类似,也是在仿真文件里例化生成的IP核,并进行简单的实验,代码如下

module buffer_top_tb(
 
    );
 
//make a 50 MHz clock    
reg clk = 0;   
always #10 clk = ~clk;
 
reg rst;
 
reg [7:0] fifo_in;
reg wr_en = 0;
reg rd_en = 0;
 
wire [7:0] fifo_out;
wire valid;
 
wire fifo_full;
wire fifo_empty;
wire [8:0] data_count;
 
 
 
initial
begin
rst = 0;
wr_en = 0;
rd_en = 0;
fifo_in = 8'h60;
end 
 
always @ (posedge clk)
begin
//这里的1 ns延时是为了模拟现实情况下D触发器(flip-flop)的D端到Q端用的时间
wr_en <= #1 1;
fifo_in <= #1 fifo_in + 1;
 
rd_en <= #1 1;
end
 
fifo_generator_0 your_instance_name (
    .clk(clk),      // input wire clk
 
    .din(fifo_in),      // input wire [7 : 0] din
    .wr_en(wr_en),  // input wire wr_en
    .full(fifo_full),    // output wire full
     
    .rd_en(rd_en),  // input wire rd_en
    .dout(fifo_out),    // output wire [7 : 0] dout  
    .empty(fifo_empty),  // output wire empty
    .valid(valid),  // output wire valid
    .data_count(data_count),  // output wire [8 : 0] data_count
  
     .srst(rst)    // input wire srst   
     
);

endmodule

仿真波形如图8所示。然而可以看到,fifo_out并没有像预期的那样,在读使能(rd_en)被立起来之前,61(fifo_in)已经就在读数据端可见。图9是FIFO IP核文档上对FWFT读写波形的描述,可以看到如果FWFT是正确的,读数据端D0在读使能(rd_en)被立起来之前已经被输出。既然仿真结果不对,那么一定是FIFO使用FWFT的条件在仿真过程中没有被满足。

仔细观察图8的仿真波形,就会发现fifo_empty一直都保持拉高状态,直到写入了三个数据(61,62和63分别在30 ns,50 ns和70 ns被写入FIFO,注意因为加上了1 ns的延迟,写数据(fifo_in)和写使能(wr_en)的上升沿和时钟的上升沿不是对齐的)后才被拉低,可能影响读数据端输出的原因是fifo_empty没有及时被拉低。而图九中的D0在empty被拉低之后才出现在读数据端。通过查阅Xilinx公司的FIFO generator文档(V13.2),更是证明了上述推论。

“The FWFT feature adds two clock cycle latency to the deassertion of empty, when the first data is written into a empty FIFO.” [1]。

FIFO FWFT 1

图8 FIFO FWFT仿真图

 

FIFO FWFT2

图9 FIFO FWFT典型读数据端波形图

 

针对FWFT这个特性,将仿真文件进行相应修改,特别是将读使能(rd_en)往后延迟一段时间再立起来,给写数据和empty留下至少三个时钟周期的反应时间。修改后的代码如下:


module buffer_top_tb(

    );

//make a 50 MHz clock    
reg clk = 0;   
always #10 clk = ~clk;

reg rst;

reg [7:0] fifo_in;
reg wr_en = 0;
reg rd_en = 0;

wire [7:0] fifo_out;
wire valid;

wire fifo_full;
wire fifo_empty;
wire [8:0] data_count;

reg end_flag = 0;
reg ready = 0;
reg [2:0] i_cnt = 0;
reg second_write = 0;

initial
begin
    ready = 0;
    second_write = 0;
    rst = 0;
    wr_en = 0;
    rd_en = 0;
    fifo_in = 8'h60;
    #200
    ready = 1;
    #100
    second_write = 1;
 end  
 
always @ (posedge clk)
if(i_cnt <= 2)
begin
wr_en <= #1 1;
i_cnt <= i_cnt + 1;
fifo_in <= #1 fifo_in + 1;
end
else
wr_en <= #1 0;

always
begin
#200; rd_en = 1;
#100; rd_en = 0;
#200; rd_en = 1;
end

always @(posedge clk)
if(second_write)
begin    
    wr_en <= #1 1;
    fifo_in <= #1 fifo_in + 1;
end
     

fifo_generator_0 fifo_generator_0_inst (
    .clk        (clk),      // input wire clk

    .din        (fifo_in),      // input wire [7 : 0] din
    .wr_en      (wr_en),  // input wire wr_en
    .full       (fifo_full),    // output wire full
    
    .rd_en      (rd_en),  // input wire rd_en
    .dout       (fifo_out),    // output wire [7 : 0] dout  
    .empty      (fifo_empty),  // output wire empty
    .valid      (valid),  // output wire valid
    .data_count (data_count),  // output wire [8 : 0] data_count
 
     .srst      (rst)    // input wire srst   
    
);
 

endmodule

对应的仿真图如图10所示。可以看到在第一次读使能(rd_en)被立起来前,一旦fifo_empty被延迟过两个时钟周期,终于被拉低时,读数据(fifo_out)61已经被输出,同时Valid也被同时拉高。当FIFO里的数据被读完后(250 ns),fifo_empty再次被立起来,也伴随着Valid信号的拉低。在第二次写入数据后延迟两个时钟周期,读数据(fifo_out) 64在读使能(rd_en)被立起来前已经被输出,Valid信号再次被拉高。这次仿真的结果是与图9的波形相吻合的,说明FWFT正常工作。

同时观察新加上的data_count信号,当读使能(rd_en)被立起来之前,写数据写入FIFO之后,是一直增加的。当写操作停止,读操作进行的时候,data_count进而减少,第二次读写操作时data_count的变化也是遵循相同的规律,符合逻辑。

总结来说,同步FIFO FWFT的仿真成功的条件是遵循相应设计的要求,并与官方文档中提供的标准波形进行比对验证,进而修改完善自己的设计。
FIFO FWFT3

图10 FIFO FWFT成功的仿真图

 

3.参考文献

[1]Xilinx.com, 2021. [Online]. Available: https://www.xilinx.com/support/documentation/ip_documentation/fifo_generator/v13_2/pg057-fifo-generator.pdf. [Accessed: 13- Jan- 2021].

Posted in FPGA, Verilog, Vivado, 文章

发表评论

相关链接