FPGA的FIFO部分的知识点

 

看的小梅哥的新视频,FIFO这边讲的不太清楚,换正点原子的fifo听一下。

后面的以太网和HDMI有空也看一下正点原子的,主要是想快速看zynq的知识,而且现在学的很多都是模仿抄代码,真正自己来还是得工程中实际应用的时候才会使用学习


FIFO,先入先出,像队列。常用于数据的缓存,因为数据的读写带宽,也就是读写速度不同步,可以通过异步FIFO解决

同步FIFO就是读写同时钟,异步FIFO就是时钟独立,跨时钟处理。


FIFO计算公式(计算在最恶劣的情况下,在突发读写这段时间内,有多少数据没被读取)

FIFO的最小深度D可以通过一下公式计算:

a.读比写快

  D=BW-BR=BW(1-FR/FW)

其中BW和BR分别为写入和读取的burst长度,FW和FR分别为写时钟和读时钟的频率。

b.读写同速或者读比写快

 fifo只起跨时钟域传输数据的作用,深度设置成最小即可。

举个例子:

  AD采样率为50MHZ,fpga的读取速度为40MHZ,需要5万个采样数据完整的送入FPGA,在AD和FPGA之间的FIFO缓存的最大深度?

  突发读写数据量:50000个

  写数据时钟:      50MHZ

  读数据时钟:      40MHZ

  FIFO深度最小为:50000(1-40/50)=10000


不同位宽的异步FIFO深度计算,一般输入位宽和输出的位宽是整数倍关系。

 

 


这边FIFO的结构,黑色的都是必要的,蓝色的可选(读时钟在同步FIFO里面就没有了,可选),灰色的是可选(             )


这是时钟IP核生成的端口。

//----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG
fifo_test your_instance_name (
  .rst(rst),                      // input wire rst
  .wr_clk(wr_clk),                // input wire wr_clk
  .rd_clk(rd_clk),                // input wire rd_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
  .almost_full(almost_full),      // output wire almost_full
  .empty(empty),                  // output wire empty
  .almost_empty(almost_empty),    // output wire almost_empty
  .rd_data_count(rd_data_count),  // output wire [7 : 0] rd_data_count
  .wr_data_count(wr_data_count),  // output wire [7 : 0] wr_data_count
  .wr_rst_busy(wr_rst_busy),      // output wire wr_rst_busy
  .rd_rst_busy(rd_rst_busy)      // output wire rd_rst_busy
);

从原子哥那里漂的顶层模块和例化的框图

任务是,先写满,再读出来

那么其中除了根据满和空的状态,控制读写信号使能。由时钟IP产生两个时钟分别给读写时钟,异步读写FIFO

fifo_wr
 module fifo_write(
    wr_clk,
    reset_n,
    
    //FIFO
    empty,  //输入空信号!!!这是读时钟域的信号,异步信号需要打拍。
    almost_full,  //将满信号
    wr_rst_busy, //写复位忙信号
    fifo_wr_en,
    fifo_wr_data
    );
    
    input   wr_clk;
    input   reset_n;
    
    input   empty;
    input   almost_full;
    input   wr_rst_busy;
    output reg fifo_wr_en;
    output reg [7:0] fifo_wr_data;
    
    reg empty_d0;
    reg empty_d1;
    
    //打两拍,延时2周期
    //因为实际上的空信号是读时序的时候FIFO才能输出来的,所以这边跟写时序是异步信号
    always @(posedge wr_clk or negedge reset_n)
        if(!reset_n) begin
            empty_d0 <= 0;
            empty_d1 <= 0;
        end
        else begin
            empty_d0 <= empty;
            empty_d1 <= empty_d0;
        end
    
     always @(posedge wr_clk or negedge reset_n)
        if(!reset_n) 
            fifo_wr_en <= 0;
        else if(!wr_rst_busy) begin
            if(empty_d1)
                fifo_wr_en <= 1'b1;
            else if(almost_full)
                fifo_wr_en <= 1'b0;
        end
        
     //对fifo_wr_data赋值 0~254   
       always @(posedge wr_clk or negedge reset_n)
             if(!reset_n)
                fifo_wr_data <= 0;
             else if(fifo_wr_en && fifo_wr_data < 8'd254)
                fifo_wr_data <= fifo_wr_data + 8'd1;
             else
                fifo_wr_data <= 0;
                
endmodule
fifo_rd
 module fifo_read(
    rd_clk,
    reset_n,
    fifo_rd_data,
    almost_empty,
    full,
    rd_rst_busy,
    fifo_rd_en
    );
    
    input   rd_clk;
    input   reset_n;
    
    input  [7:0] fifo_rd_data;
    input   almost_empty;
    input   full;
    input   rd_rst_busy;
    
    output reg fifo_rd_en;
    
    reg full_d0;
    reg full_d1;
    
    always @(posedge rd_clk or negedge reset_n)
        if(!reset_n) begin
            full_d0 <= 0;
            full_d1 <= 0;
        end
        else begin
             full_d0 <= full;
             full_d1 <= full_d0;
        end
        
     always @(posedge rd_clk or negedge reset_n)
        if(!reset_n)
               fifo_rd_en <= 1'b0;
        else if(!rd_rst_busy) begin
            if(full_d1)
                fifo_rd_en <= 1'b1;
            else if(almost_empty)
                fifo_rd_en <= 1'b0;

        end
            
    
endmodule
ip_fifo顶层例化
 module ip_fifo(
    clk,
    reset_n
    );
    
    input   clk;
    input   reset_n;
    
    wire    clk_50m;
    wire    clk_100m;
    wire    locked;
    
    wire rst_n;
    assign rst_n = reset_n & locked;
    
    wire    empty;
    wire    almost_full    ;
    wire    wr_rst_busy    ;
    wire    fifo_wr_en     ;
    wire  [7:0]  fifo_wr_data   ;
    

    wire  [7:0]  fifo_rd_data  ;
    wire    almost_empty  ;
    wire    full          ;
    wire    rd_rst_busy   ;
    wire    fifo_rd_en    ;
    
    wire  [7:0]  rd_data_count;
    wire  [7:0]  wr_data_count;
    
   clk_wiz_0 instance_name
   (
    // Clock out ports
    .clk_out1(clk_50m),     // output clk_out1
    .clk_out2(clk_100m),     // output clk_out2
    // Status and control signals

    .locked(locked),       // output locked
   // Clock in ports
    .clk_in1(clk)
    );      // input clk_in1
    
    
    fifo_write fifo_wirte_inst(
     .wr_clk(clk_50m),     
     .reset_n(rst_n),    
                 
     //FIFO      
     .empty(empty),  //输入
     .almost_full(almost_full),
     .wr_rst_busy(wr_rst_busy),
     .fifo_wr_en(fifo_wr_en), 
     .fifo_wr_data(fifo_wr_data)
    
    
    
    );
    
    fifo_read fifo_read_inst(
    .rd_clk(clk_100m),       
    .reset_n(rst_n),      
    .fifo_rd_data(fifo_rd_data), 
    .almost_empty(almost_empty), 
    .full(full),         
    .rd_rst_busy(rd_rst_busy),  
    .fifo_rd_en(fifo_rd_en)    

    );
    
    //FIFO的复位高电平有效
    fifo_test your_instance_name (
  .rst(~rst_n),                      // input wire rst
  .wr_clk(clk_50m),                // input wire wr_clk
  .rd_clk(clk_100m),                // input wire rd_clk
  .din(fifo_wr_data),                      // input wire [7 : 0] din
  .wr_en(fifo_wr_en),                  // input wire wr_en
  .rd_en(fifo_rd_en),                  // input wire rd_en
  .dout(fifo_rd_data),                    // output wire [7 : 0] dout
  .full(full),                    // output wire full
  .almost_full(almost_full),      // output wire almost_full
  .empty(empty),                  // output wire empty
  .almost_empty(almost_empty),    // output wire almost_empty
  .rd_data_count(rd_data_count),  // output wire [7 : 0] rd_data_count
  .wr_data_count(wr_data_count),  // output wire [7 : 0] wr_data_count
  .wr_rst_busy(wr_rst_busy),      // output wire wr_rst_busy
  .rd_rst_busy(rd_rst_busy)      // output wire rd_rst_busy
);
    
endmodule

 

FIFO的高电平复位,例化的时候取反。

posted @ 2024-03-13 21:11  祈愿树下  阅读(27)  评论(0编辑  收藏  举报
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css