1. 程式人生 > >fifo學習(3)

fifo學習(3)

3.fifo IP核的使用

(1)最簡單的ip核,不設定復位訊號,採用公共時鐘;公共時鐘FIFO寫入讀取的位寬比只能是1:1

module fifo_ip(clk,din,wr_en,rd_en,dout,full,empty);
 input clk;
 input [7:0] din;//位寬為8位,深度為16
 input wr_en;
 input rd_en;
 output [7:0] dout;
 output full;
 output empty;
 
 fifo_8_16 f0 (
  .clk(clk),      // input wire clk
  .din(din),      // input wire [7 : 0] din
  .wr_en(wr_en),  // input wire wr_en
  .rd_en(rd_en),  // input wire rd_en
  .dout(dout),    // output wire [7 : 0] dout
  .full(full),    // output wire full
  .empty(empty)  // output wire empty
);
endmodule

//tb
module tb_fifo_ip;
 reg clk;
 reg [7:0] din;
 reg wr_en,rd_en;
 wire [7:0] dout;
 wire full,empty;
 
 initial begin
              clk=1'b0;
              din=8'h01;
              wr_en=1'b1;
              rd_en=1'b0;
              #400
              wr_en=1'b0;
              rd_en=1'b1;
              #300
              wr_en=1'b1;
              rd_en=1'b0;
              #200 
              wr_en=1'b0;
              rd_en=1'b1;
         end
         
 always #10 clk = ~clk;
 always #20 din = din + 1'b1;
 fifo_ip t1(.clk(clk),
            .din(din),
            .wr_en(wr_en),
            .rd_en(rd_en),
            .dout(dout),
            .full(full),
            .empty(empty));
endmodule

 

在第16個週期,fifo處於滿狀態,full置1;

但是,第一次讀取只讀取到了15,此時又開始寫入資料,寫入的第一個資料為36,故下一次讀取從16開始,第二個讀取的資料為36;可以說明在full或者empty拉高時,無論是寫入還是讀取使能都不會影響fifo中儲存的資料!

(2)設定同步復位訊號,採用公共時鐘

module fifo_ip0(clk,srst,din,wr_en,rd_en,dout,full,empty);
 input clk;
 input srst;
 input [7:0] din;
 input wr_en;
 input rd_en;
 output [7:0] dout;
 output full;
 output empty;
 
 reg [7:0] din1;
 always @(posedge clk)
    begin
         if(srst)
            din1 <= 8'd0;
         else
            din1 <= din;
    end
 
 fifo_8_16_srst f1 (
  .clk(clk),      // input wire clk
  .srst(srst),    // input wire srst復位訊號為高電平有效
  .din(din1),      // input wire [7 : 0] din
  .wr_en(wr_en),  // input wire wr_en
  .rd_en(rd_en),  // input wire rd_en
  .dout(dout),    // output wire [7 : 0] dout
  .full(full),    // output wire full
  .empty(empty)  // output wire empty
);

module tb_fifo_ip0;
 reg clk,srst;
 reg [7:0] din;
 reg wr_en,rd_en;
 wire [7:0] dout;
 wire full,empty;
 
 initial begin
               clk=1'b0;
               srst=1'b1;
               din=8'h01;
               wr_en=1'b1;//寫
               rd_en=1'b0;
               #40
               srst=1'b0;
               #400
               wr_en=1'b0;//讀
               rd_en=1'b1;
               #300
               srst=1'b1;
               wr_en=1'b1;//寫
               rd_en=1'b0;
               #500
               srst=1'b0; 
               wr_en=1'b0;//讀
               rd_en=1'b1;
               #200
               wr_en=1'b1;//寫
               rd_en=1'b0;
          end
          
  always #10 clk = ~clk;
  always #20 din = din + 1'b1;
  fifo_ip0 t2(.clk(clk),
             .srst(srst),
             .din(din),
             .wr_en(wr_en),
             .rd_en(rd_en),
             .dout(dout),
             .full(full),
             .empty(empty));
endmodule

srst訊號有效時,在下一個上升沿來臨時empty拉高,上圖中在srst訊號無效時開始寫入,寫入的資料為0,3,4....17;

srst有效期間,不管是寫入還是讀取狀態,fifo的輸入輸出都是0;上圖可見在din1為63時進行讀取操作,所讀出的數為0,且empty為1;

繼續寫入,寫到87時,full拉高;

(3)帶輸出標誌位valid和almost full、almost empty

almost_full總是比full提前一個週期拉高,它拉高表明還可以進行一次寫入操作;同時在srst有效的情況下,almost_empty和empty同時拉高;

almost_empty和empty在fifo為空時是同時為1的;valid訊號在讀使能有效的第1個上升沿拉高,在寫入的第1個上升沿到來時置零;

(4)FWFT首字預現fifo

在srst有效時,valid置零;在寫使能有效的第3個上升沿到來時拉高,在讀使能有效之前且empty不為零就已經處於拉高狀態;

寫使能只存在2個週期,寫入了0和3;valid在90ns拉高,在empty拉高的同時,valid置零;可以說明,在FWFT fifo中valid不能作為資料的輸出標誌位!!

(5)加入輸出快取暫存器,增加一級延時

在讀訊號的時鐘第2個上升沿到來時才開始讀出資料,同時valid拉高;

(6)FWFT+輸出快取暫存器

對FWFT模式的FIFO,加入暫存器對輸出並沒有增加1個週期的延時,但是對full和almost_full訊號有延時,實際上是FWFT模式相對於標準模式分別增加了兩個讀深度和寫深度