IC设计入门-同步FIFO

同步FIFO

先进先出 (FIFO) 是一个非常流行且有用的设计模块,用于模块之间的同步和握手机制。

FIFO的深度:FIFO中的插槽或行数称为FIFO的深度。

FIFO的宽度:每个插槽或行中可以存储的位数称为FIFO的宽度。

FIFO有两种类型

  1. 同步FIFO
  2. 异步FIFO

同步FIFO

在同步FIFO中,数据读取和写入操作使用相同的时钟频率。通常,它们与高时钟频率一起使用以支持高速系统。

IC设计入门-同步FIFO_第1张图片

同步FIFO操作

信号:

wr_en:写使能

wr_data:写入数据

full:FIFO 已满

empty:FIFO 为空

rd_en:读取启用

rd_data:读取数据

w_ptr:写入指针

r_ptr:读取指针

FIFO写入操作

FIFO可以根据wr_en信号在时钟的每个位置存储/写入wr_data,直到它满为止。FIFO 内存中每次写入数据时,写入指针都会递增。

FIFO读取操作

可以根据rd_en信号在时钟的每个位置从FIFO中取出或读取数据,直到它为空。从 FIFO 存储器读取的每个数据都会增加读取指针。

同步FIFO Verilog代码

同步FIFO可以通过多种方式实现。满满和空条件因实现而异。

方法 1

在此方法中,写入和读取指针的宽度 = log2(FIFO 的深度)。FIFO 满载和满载条件可确定为

空条件

w_ptr == r_ptr,即写入和读取指针具有相同的值。

满状态

满条件意味着FIFO中的每个空间都被占用,但随后w_ptr和r_ptr将再次具有相同的值。因此,无法确定它是满的还是空的条件。因此,FIFO 的最后一个空间有意保持为空,完整条件可以写为 (w_ptr+1'b1) == r_ptr)

Verilog代码
module synchronous_fifo #(parameter DEPTH=8, DATA_WIDTH=8) (
  input clk, rst_n,
  input w_en, r_en,
  input [DATA_WIDTH-1:0] data_in,
  output reg [DATA_WIDTH-1:0] data_out,
  output full, empty
);
  
  reg [$clog2(DEPTH)-1:0] w_ptr, r_ptr;
  reg [DATA_WIDTH-1:0] fifo[DEPTH];
  
  // Set Default values on reset.
  always@(posedge clk) begin
    if(!rst_n) begin
      w_ptr <= 0; r_ptr <= 0;
      data_out <= 0;
    end
  end
  
  // To write data to FIFO
  always@(posedge clk) begin
    if(w_en & !full)begin
      fifo[w_ptr] <= data_in;
      w_ptr <= w_ptr + 1;
    end
  end
  
  // To read data from FIFO
  always@(posedge clk) begin
    if(r_en & !empty) begin
      data_out <= fifo[r_ptr];
      r_ptr <= r_ptr + 1;
    end
  end
  
  assign full = ((w_ptr+1'b1) == r_ptr);
  assign empty = (w_ptr == r_ptr);
endmodule
测试台代码
module sync_fifo_TB;
  parameter DATA_WIDTH = 8;
  
  reg clk, rst_n;
  reg w_en, r_en;
  reg [DATA_WIDTH-1:0] data_in;
  wire [DATA_WIDTH-1:0] data_out;
  wire full, empty;
  
  // Queue to push data_in
  reg [DATA_WIDTH-1:0] wdata_q[$], wdata;

  synchronous_fifo s_fifo(clk, rst_n, w_en, r_en, data_in, data_out, full, empty);

  always #5ns clk = ~clk;
  
  initial begin
    clk = 1'b0; rst_n = 1'b0;
    w_en = 1'b0;
    data_in = 0;
    
    repeat(10) @(posedge clk);
    rst_n = 1'b1;

    repeat(2) begin
      for (int i=0; i<30; i++) begin
        @(posedge clk);
        w_en = (i%2 == 0)? 1'b1 : 1'b0;
        if (w_en & !full) begin
          data_in = $urandom;
          wdata_q.push_back(data_in);
        end
      end
      #50;
    end
  end

  initial begin
    clk = 1'b0; rst_n = 1'b0;
    r_en = 1'b0;

    repeat(20) @(posedge clk);
    rst_n = 1'b1;

    repeat(2) begin
      for (int i=0; i<30; i++) begin
        @(posedge clk);
        r_en = (i%2 == 0)? 1'b1 : 1'b0;
        if (r_en & !empty) begin
          #1;
          wdata = wdata_q.pop_front();
          if(data_out !== wdata) $error("Time = %0t: Comparison Failed: expected wr_data = %h, rd_data = %h", $time, wdata, data_out);
          else $display("Time = %0t: Comparison Passed: wr_data = %h and rd_data = %h",$time, wdata, data_out);
        end
      end
      #50;
    end

    $finish;
  end
  
  initial begin 
    $dumpfile("dump.vcd"); $dumpvars;
  end
endmodule
波形IC设计入门-同步FIFO_第2张图片

你可能感兴趣的:(数字IC,数据结构,fpga开发)