【S051】(xilinx First-Word Fall-Through模式)预读FIFO

FIFO对比

预读FIFO:rdata在ren当拍有效。(xilinx First-Word Fall-Through模式)
普通FIFO:rdata在ren下拍有效。(xilinx Standard模式)

实现思路

注:实现的思路各有千秋,下面是我的实现思路。
首先用简单双口RAM包装出一个Lfifo,这个Lfifo有以下关键特征:
raddr可以由外部输入的switch_addr信号来切换

Lfifo_raddr_ori_puls=Lfifo_raddr_ori+1
Lfifo_raddr = switch_addr ? Lfifo_raddr_ori_puls : Lfifo_raddr_ori;//二选一,

正是由于raddr地址的提前导致的rdata的提前出来。
其次,在Lfifo外面包一层逻辑,这层逻辑的原理:控制Lfifo_ren、switch_addr等,也产生一些状态信号。
注:下文的buf等价于图中的fifo_rdata寄存器

整个模块的输入信号是:fifo_ren
在产生读Lfifo_ren控制逻辑的角度来看:有每一拍4种可能状态
case1.Lfifo空1    &  buf空1  ----此时输入fifo_ren不会生效(后级保证不会空读) 忽略此状态
case2.Lfifo空1    &  buf满0  ----if(fifo_ren==1)将buf读空,buf变成空,不读Lfifo,else 保持
case3.Lfifo有数0  &  buf空1  ----fifo_ren不会生效(后级保证不会空读) ,本拍内部产生预读读Lfifo,
                                 准备取1个数放buf,数据下一拍有效,下一拍产生load。01状态会持续2拍,只有第1拍需要读。
case4.Lfifo有数0  &  buf满0  ----if(fifo_ren==1) ram_raddr切换为+1(本拍就切换地址,那么Lfifo_rdata数据下拍就预取出来了)。

补充:FIFO的状态变化是有顺序的,不可能直接从case1跳变为case4,其中必然要经过case2 | case3中间状态。


在这里插入图片描述

仿真效果

写完后连续读

在这里插入图片描述

写完后间隔读

在这里插入图片描述

非空就读(边写边读)

在这里插入图片描述

只写1个数据,非空读

在这里插入图片描述

代码和tb

Lfifo

//-------------------------------------------------------
//------------------little_fifo--------------------------------
//-------------------------------------------------------
module   Lfifo #(//L:Little  小FIFO
    parameter      RAM_TYPE =  "block_ram"  ,
    parameter      WIDTH    =  9            ,
    parameter      DEPTH    =  10           
)(
    input                            clk                     ,
    input                            rst                     ,
    input                            Lfifo_wr                ,
    input           [WIDTH-1:0]      Lfifo_wdata             ,
    input                            Lfifo_ren               ,
    input                            switch_addr             ,//1:地址+1,相当于预取
    input           [WIDTH-1:0]      Lfifo_rdata             ,
    output                           Lfifo_empty             ,
    output                           Lfifo_aempty             //FIFO只剩最后1个,用于预取情况,来判断rdata是否有效
);
reg      [DEPTH-1:0]      Lfifo_waddr ={DEPTH{1'b0}}            ;//RAM待写入的地址
wire     [DEPTH-1:0]      Lfifo_raddr             ;//RAM待读出的地址
reg      [DEPTH-1:0]      Lfifo_raddr_ori={DEPTH{1'b0}}         ;//RAM待读出的地址
reg      [DEPTH-1:0]      Lfifo_raddr_ori_puls={DEPTH{1'b0}}    ;// Lfifo_raddr_ori + 1 
assign    Lfifo_empty    =     (Lfifo_raddr_ori==Lfifo_waddr)  ;
assign    Lfifo_aempty   =     (Lfifo_raddr_ori_puls==Lfifo_waddr)  ;
always @(posedge clk or posedge rst) 
begin
    if(rst)   
        Lfifo_raddr_ori_puls  <=#1  {{(DEPTH-1){1'b0}},1'b1}; 
    else  if (Lfifo_ren) 
        Lfifo_raddr_ori_puls <=#1   Lfifo_raddr_ori_puls + 1'b1;
end
always @(posedge clk or posedge rst) 
begin
    if(rst)   
        Lfifo_raddr_ori  <=#1  {DEPTH{1'b0}}; 
    else if (Lfifo_ren) 
        Lfifo_raddr_ori <=#1  Lfifo_raddr_ori_puls;
end
assign   Lfifo_raddr  =  switch_addr ?   Lfifo_raddr_ori_puls : Lfifo_raddr_ori;
always @(posedge clk) if(rst)   Lfifo_waddr <=#1 {(2**DEPTH){1'b0}};  else if(Lfifo_wr)    Lfifo_waddr <=#1  Lfifo_waddr +1'b1 ;
SPRAM #(RAM_TYPE,WIDTH,DEPTH) u_RAM (
    .clk  (clk                           ),//input                            clk                      ,
    .wen  (Lfifo_wr                      ),//input                            wen                      ,
    .waddr(Lfifo_waddr                   ),//input           [DEPTH-1:0]      waddr                    ,
    .wdata(Lfifo_wdata                   ),//input           [WIDTH-1:0]      wdata                    ,
    .raddr(Lfifo_raddr                   ),//input           [DEPTH-1:0]      raddr                    ,
    .rdata(Lfifo_rdata                   ) //output    reg   [WIDTH-1:0]      rdata                     
);
endmodule
//-------------------------------------------------------
//------------------SPRAM--------------------------------
//-------------------------------------------------------
module   SPRAM #(//sample    double    port   RAM 
    parameter      RAM_TYPE =  "block_ram"  ,
    parameter      WIDTH    =  9            ,
    parameter      DEPTH    =  10           
)(
    input                            clk                      ,
    input                            wen                      ,
    input           [DEPTH-1:0]      waddr                    ,
    input           [WIDTH-1:0]      wdata                    ,
    input           [DEPTH-1:0]      raddr                    ,
    output    reg   [WIDTH-1:0]      rdata                     
);
(* syn_ramstyle = RAM_TYPE , cascade_height=1 *) reg   [WIDTH-1:0]    RAM   [(2**DEPTH)-1:0]   ;
always @(posedge clk) if(wen)   RAM[waddr] <=#1 wdata;
always @(posedge clk)           rdata      <=#1 RAM[raddr];
endmodule


SYNC_FIFO


//-------------------------------------------------------
//------------------SYNC_FIFO----------------------------
//-------------------------------------------------------
module   SYNC_FIFO #(//show_ahead
    parameter      RAM_TYPE =  "block_ram"  ,
    parameter      WIDTH    =  9            ,
    parameter      DEPTH    =  10           
)(
    input                            clk                      ,
    input                            rst                      ,
    input                            fifo_wr                  ,
    input           [WIDTH-1:0]      fifo_wdata               ,
    output                           fifo_full                ,    
    input                            fifo_ren                 ,
    output   reg    [WIDTH-1:0]      fifo_rdata               ,
    output   reg                     fifo_empty=1             //标志fifo_rdata寄存器内的数据是否为有效
);
//数据只能存储2个位置:1.在LFIFO内   2.fifo_rdata寄存器内
reg                       Lfifo_ren               ;
wire     [WIDTH-1:0]      Lfifo_rdata             ;
reg                       Lfifo_rdata_vld         ;//fifo_rdata是有效的数据,有可能是延后一拍数据,有可能是预取数据
wire                      Lfifo_empty             ;
wire                      Lfifo_aempty            ;
wire                      load_en                 ;
reg                       switch_addr             ;
reg      [DEPTH  :0]      cnt                     ;

always @(posedge clk or posedge rst) begin if(rst) Lfifo_rdata_vld     <=#1  1'b0; else if(switch_addr&Lfifo_aempty)Lfifo_rdata_vld     <=#1 1'b0 ; else  Lfifo_rdata_vld     <=#1  ~Lfifo_empty  ;end//只剩最后1个,还预读,那就是读出无效
always @(posedge clk or posedge rst) //空  读有关
begin
    if(rst)   
        fifo_empty <=#1  'b1 ; 
    else if(Lfifo_rdata_vld==0 && fifo_ren==1'b1 )
        fifo_empty <=#1  1'b1  ; 
    else if(Lfifo_rdata_vld==1 && load_en==1'b1 )
        fifo_empty <=#1  1'b0  ; 
    else if(Lfifo_rdata_vld==0 && load_en==1'b1 )
        fifo_empty <=#1  1'b1  ; 
end
assign  load_en =  fifo_empty | fifo_ren;//拿走1个数据,就load一次
always @(*) 
begin
    case({Lfifo_empty,fifo_empty})//此处是关键  
        2'b00    :if(fifo_ren){switch_addr,Lfifo_ren} =  2'b11;else {switch_addr,Lfifo_ren} =  2'b00;  
        2'b01    :if(Lfifo_rdata_vld==0){switch_addr,Lfifo_ren} =  2'b01;else {switch_addr,Lfifo_ren} =  2'b00;
        2'b10    :{switch_addr,Lfifo_ren} =  2'b00;
        2'b11    :{switch_addr,Lfifo_ren} =  2'b00;
        default  :{switch_addr,Lfifo_ren} =  2'b00;
    endcase
end
always @(posedge clk )  if(load_en) fifo_rdata   <=#1   Lfifo_rdata ;
always @(posedge clk or posedge rst) 
begin
    if(rst)   
        cnt  <=#1 'b0; 
    else if((~fifo_wr) & fifo_ren) 
        cnt <=#1  cnt -'b1 ;
    else if(fifo_wr & (~fifo_ren)) 
        cnt <=#1  cnt + 'b1 ;
end
assign  fifo_full  = cnt [DEPTH] ;
Lfifo #(RAM_TYPE,WIDTH,DEPTH) u_Lfifo(//地址控制只依赖于ren
    .clk        (clk                           ),//input                            clk                     ,
    .rst        (rst                           ),//input                            rst                     ,
    .Lfifo_wr   (fifo_wr                       ),//input                            Lfifo_wr                ,
    .Lfifo_wdata(fifo_wdata                    ),//input           [WIDTH-1:0]      Lfifo_wdata             ,
    .Lfifo_ren  (Lfifo_ren                     ),//input                            Lfifo_ren               ,
    .switch_addr(switch_addr                   ),//input                            switch_addr               ,
    .Lfifo_rdata(Lfifo_rdata                   ),//input           [WIDTH-1:0]      Lfifo_rdata             ,
    .Lfifo_empty(Lfifo_empty                   ), //output                           Lfifo_empty              
    .Lfifo_aempty(Lfifo_aempty                 ) //output                           Lfifo_empty              
);
endmodule


tb


`timescale 1ns/100ps//正确
module tb (  );
    parameter      RAM_TYPE =  "block_ram"  ;
    parameter      WIDTH    =  9            ;
    parameter      DEPTH    =  9           ;
    reg                 rst=1                 ;
    reg                 clk=0                 ;
    always clk   =#10  ~clk;    
    reg                   fifo_wr =  0             ;
    reg  [WIDTH-1:0]      fifo_wdata               ;
    wire                  fifo_full                ; 
    reg                   fifo_ren  =0             ;
    reg  [WIDTH-1:0]      fifo_rdata               ;
    wire                  fifo_empty               ;
    initial //产生时钟
    begin
        rst=1                 ;
        #100;@(posedge clk);#1;
        rst=0                 ;
        
        #100;@(posedge clk);#1;       
        // fifo_wr_task(en,wdata);
        // fifo_rd_task(en);
//case 1 ://写连续入1个数据,非空就立马读
        fifo_wr_task(1,32'h1111);
        fifo_wr_task(0,32'hxxxx);
        wait(fifo_empty==0);
        fifo_rd_task(1);
        fifo_rd_task(0);
        #100;@(posedge clk);        
//case 2 ://写连续入1个数据,延时几拍后再读
        fifo_wr_task(1,32'h1111);
        fifo_wr_task(0,32'hxxxx);
        wait(fifo_empty==0);
        #50;@(posedge clk);        
        fifo_rd_task(1);
        fifo_rd_task(0);
        #1000;@(posedge clk);                
//case 3 ://写连续入2个数据,第1拍非空就立马读,第二拍延时一定时间读
        fifo_wr_task(1,32'h1111);
        fifo_wr_task(1,32'h2222);
        fifo_wr_task(0,32'hxxxx);
        wait(fifo_empty==0);
        fifo_rd_task(1);
        fifo_rd_task(0);
        #50;@(posedge clk);        
        fifo_rd_task(1);
        fifo_rd_task(0);
        #100;@(posedge clk);
//case 4 ://写连续入2个数据,第1拍非空就立马读,第二拍非空就立马读
        fifo_wr_task(1,32'h1111);
        fifo_wr_task(1,32'h2222);
        fifo_wr_task(0,32'hxxxx);
        wait(fifo_empty==0);
        fifo_rd_task(1);        
        fifo_rd_task(1);
        fifo_rd_task(0);
        #100;@(posedge clk);
//case 5 ://写连续入2个数据,第1拍延时一定时间,再连续读2次
        fifo_wr_task(1,32'h1111);
        fifo_wr_task(1,32'h2222);
        fifo_wr_task(0,32'hxxxx);
        wait(fifo_empty==0);
        #50;@(posedge clk);         
        fifo_rd_task(1);        
        fifo_rd_task(1);
        fifo_rd_task(0);
        #100;@(posedge clk);
//case 6 ://写连续入2个数据,第1拍延时一定时间,再连延时一定时间读第二拍
        fifo_wr_task(1,32'h1111);
        fifo_wr_task(1,32'h2222);
        fifo_wr_task(0,32'hxxxx);
        wait(fifo_empty==0);
        #50;@(posedge clk);         
        fifo_rd_task(1);
        fifo_rd_task(0);
        #50;@(posedge clk);
        fifo_rd_task(1);
        fifo_rd_task(0);
        #1000;@(posedge clk);
//case 7 ://写连续入3个数据,非空立马读3次
        fifo_wr_task(1,32'h1111);
        fifo_wr_task(1,32'h2222);
        fifo_wr_task(1,32'h3333);
        fifo_wr_task(0,32'hxxxx);
        wait(fifo_empty==0);
        #50;@(posedge clk);         
        fifo_rd_task(1);        
        fifo_rd_task(1);
        fifo_rd_task(1);
        fifo_rd_task(0);
        #100;@(posedge clk);
//case 8 ://写连续入3个数据,非空读1次,延时,连续读2次
        fifo_wr_task(1,32'h1111);
        fifo_wr_task(1,32'h2222);
        fifo_wr_task(1,32'h3333);
        fifo_wr_task(0,32'hxxxx);
        wait(fifo_empty==0);
        fifo_rd_task(1);
        fifo_rd_task(0);
        #50;@(posedge clk);        
        fifo_rd_task(1);
        fifo_rd_task(1);
        fifo_rd_task(0);
        #100;@(posedge clk);
//case 9://写连续入3个数据,非空读2次,延时,读1次
        fifo_wr_task(1,32'h1111);
        fifo_wr_task(1,32'h2222);
        fifo_wr_task(1,32'h3333);
        fifo_wr_task(0,32'hxxxx);
        wait(fifo_empty==0);
        fifo_rd_task(1);        
        fifo_rd_task(1);
        fifo_rd_task(0);
        #50;@(posedge clk);        
        fifo_rd_task(1);
        fifo_rd_task(0);
        #100;@(posedge clk);
//case 10://写连续入3个数据,延时 ,连续读3次
        fifo_wr_task(1,32'h1111);
        fifo_wr_task(1,32'h2222);
        fifo_wr_task(1,32'h3333);
        fifo_wr_task(0,32'hxxxx);
        wait(fifo_empty==0);
        #50;@(posedge clk);         
        fifo_rd_task(1);        
        fifo_rd_task(1);        
        fifo_rd_task(1);
        fifo_rd_task(0);
        #100;@(posedge clk);

//case 11://写连续入3个数据,延时 ,读1次,延时,读1次,延时,读1次
        fifo_wr_task(1,32'h1111);
        fifo_wr_task(1,32'h2222);
        fifo_wr_task(1,32'h3333);
        fifo_wr_task(0,32'hxxxx);
        wait(fifo_empty==0);
        #50;@(posedge clk);         
        fifo_rd_task(1);
        fifo_rd_task(0);
        #50;@(posedge clk);        
        fifo_rd_task(1);
        fifo_rd_task(0);
        #50;@(posedge clk);
        fifo_rd_task(1);
        fifo_rd_task(0);
        #1000;@(posedge clk);
//case 11://写连续入8个数据,看full信号是否正确
        fifo_wr_task(1,32'h1111);
        fifo_wr_task(1,32'h2222);
        fifo_wr_task(1,32'h3333);
        fifo_wr_task(1,32'h4444);
        fifo_wr_task(1,32'h5555);
        fifo_wr_task(1,32'h6666);
        fifo_wr_task(1,32'h7777);
        fifo_wr_task(1,32'h8888);
        fifo_wr_task(0,32'hxxxx);
        wait(fifo_empty==0);
        #50;@(posedge clk);         
        fifo_rd_task(1);
        fifo_rd_task(1);
        fifo_rd_task(1);
        fifo_rd_task(1);
        fifo_rd_task(1);
        fifo_rd_task(1);
        fifo_rd_task(1);
        fifo_rd_task(1);
        fifo_rd_task(0);
        #1000;@(posedge clk);
//case 12://边写边读
        fifo_wr_task(1,32'h0001);
        fifo_wr_task(1,32'h0002);
        fifo_wr_task(1,32'h0003);
        fifo_wr<=1;fifo_wdata<=32'h0004;fifo_ren<=1;@(posedge clk); #1;
        fifo_wr<=1;fifo_wdata<=32'h0005;fifo_ren<=1;@(posedge clk); #1;
        fifo_wr<=1;fifo_wdata<=32'h0006;fifo_ren<=1;@(posedge clk); #1;
        fifo_wr<=1;fifo_wdata<=32'h0007;fifo_ren<=1;@(posedge clk); #1;
        fifo_wr<=0;fifo_wdata<=32'hxxxx;fifo_ren<=1;@(posedge clk); #1;
        fifo_rd_task(1);
        fifo_rd_task(1);
        fifo_rd_task(0);
        #100;@(posedge clk);
    end
SYNC_FIFO #(RAM_TYPE,WIDTH,DEPTH)  u_SYNC_FIFO (
    .clk       (clk                       ),//input                            clk                      ,
    .rst       (rst                       ),//input                            rst                      ,
    .fifo_wr   (fifo_wr                   ),//input                            fifo_wr                  ,
    .fifo_wdata(fifo_wdata                ),//input           [WIDTH-1:0]      fifo_wdata               ,
    .fifo_full (fifo_full                 ),//output                           fifo_full                ,    
    .fifo_ren  (fifo_ren                  ),//input                            fifo_ren                 ,
    .fifo_rdata(fifo_rdata                ),//output          [WIDTH-1:0]      fifo_rdata               ,
    .fifo_empty(fifo_empty                ) //output                           fifo_empty              
);
task  fifo_wr_task   ;
input                 en ;
input   [WIDTH-1:0]   wdata ;
begin 
    fifo_wr<=en;fifo_wdata<=wdata;@(posedge clk);#1; 
end endtask
task  fifo_rd_task   ;
input                 en ;
begin 
     fifo_ren<= en;@(posedge clk); #1;
end endtask
endmodule

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_1615549892

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值