当前位置:   article > 正文

数字IC设计入门(四)—— 异步FIFO_异步fifo设计

异步fifo设计

一、设计目的

设计一个读写时钟不同的异步FIFO。

二、设计思路

FIFO设计的重难点是如何产生空满标志,在之前的同步FIFO设计中采用的是将地址扩展一位,通过比较最高位以及其他低位来得到空满标志,当最高位相反低位相同时说明写指针追了读指针一圈,FIFO写满;当所有位相同时,已将FIFO内所有数据读出,此时为空。

而异步FIFO也将采取这种思路,但是由于涉及到写指针在写时钟域下产生,读指针在读时钟域产生,比较时我们需要将两者放在一个时候域下进行比较,那此时就分为如下两种情况:

1.在读时钟域下读写指针比较,产生empty标志;

2.在写时钟域下读写指针比较,产生empty标志;

这么做的原因在于,将写指针同步到读时钟域后,此时和读指针比较其实已经不是现在实时的写指针了,意味着此时同步过来的写指针可能是5,而实际的已经变为了7,但是进行比较之后如果读指针也恰为5则产生empty,相当于更加“保险”,避免了读“空”的情况。将读指针同步到写时钟域下,读指针会滞后实际值几个周期,但这样避免了写满之后再写的情况。

考虑到多bit数据(即异步FIFO中的读写地址)跨时钟域时出现亚稳态概率高,再由于读写地址每次加1为连续变化,因此在将读写地址同步到另一个时钟域时先对其转换变为格雷码,因为格雷码每次只变化一位,可以有效改善亚稳态情况。

所以设计过程一共分为如下几个部分:

①读写地址产生;

②读写地址二进制转格雷码;

③读写地址同步到对方时钟域;

④空满标志判断;

三、接口信号定义
信号方向说明
w_ckin写时钟
r_clkin读时钟
rst_nin复位信号
wr_enin写使能
rd_enin读使能
w_data[7:0]out8bit写数据
r_data[7:0]out8bit读数据
fullout满信号
emptyout空信号
四、设计代码
module asy_fifo
  #(
    parameter WIDTH = 8,
    parameter DEPTH = 16
  )
  (
  input w_clk,
  input r_clk,
  input rst_n,
  input wr_en,
  input rd_en,
  input [WIDTH-1:0] w_data,
  output reg [WIDTH-1:0] r_data,
  output full,
  output empty
  );

  localparam  addr_width = $clog2(DEPTH);
  
  reg w_rst_n;
  reg r_rst_n;
  reg r_ff1;
  reg w_ff1;
  reg [WIDTH-1:0] fifo_data[DEPTH-1:0];
  wire [addr_width-1:0] waddr;
  reg [addr_width:0] waddr_bin;
  wire [addr_width:0] waddr_gray;
  reg [addr_width:0] waddr_gray_f1;
  reg [addr_width:0] waddr_gray_f2;
  //reg [addr_width:0] waddr_bin_2;

  //复位信号处理
  always @(posedge w_clk or negedge rst_n) begin
    if(~rst_n) begin
      {w_rst_n,w_ff1} <= 2'b0;
    end else begin
      {w_rst_n,w_ff1} <= {w_ff1,1'b1};
    end
  end
  
  always @(posedge w_clk or negedge rst_n) begin
    if(~rst_n) begin
      {r_rst_n,r_ff1} <= 2'b0;
    end else begin
      {r_rst_n,r_ff1} <= {r_ff1,1'b1};
    end
  end
  
  assign waddr = waddr_bin[addr_width-1:0];
  //写地址产生
  always @(posedge w_clk or negedge w_rst_n) begin
    if(~w_rst_n) begin
      waddr_bin <= 0;
    end else if(wr_en & ~full)begin
      waddr_bin <= waddr_bin + 1'b1;
    end
  end
  //写地址转换成格雷码
  assign waddr_gray = waddr_bin ^ (waddr_bin>>1);
//同步处理
  always @(posedge r_clk or negedge r_rst_n) begin 
    if(~r_rst_n) begin
      waddr_gray_f1 <= 0;
      waddr_gray_f1 <= 0;
    end else begin
      waddr_gray_f1 <= waddr_gray;
      waddr_gray_f2 <= waddr_gray_f1;
    end
  end
  
  wire [addr_width-1:0] raddr;
  reg [addr_width:0] raddr_bin;
  wire [addr_width:0] raddr_gray;
  reg [addr_width:0] raddr_gray_f1;
  reg [addr_width:0] raddr_gray_f2;
  //reg [addr_width-1:0] raddr_bin_2;
  
  assign raddr = raddr_bin[addr_width-1:0];
  //读地址产生
  always @(posedge r_clk or negedge r_rst_n) begin
    if(~r_rst_n) begin
      raddr_bin <= 0;
    end else if(rd_en & ~empty)begin
      raddr_bin <= raddr_bin + 1'b1;
    end
  end
  //读地址转换成格雷码
  assign raddr_gray = raddr_bin ^ (raddr_bin>>1);
  //同步处理
  always @(posedge w_clk or negedge w_rst_n) begin 
    if(~w_rst_n) begin
      raddr_gray_f1 <= 0;
      raddr_gray_f2 <= 0;
    end else begin
      raddr_gray_f1 <= raddr_gray;
      raddr_gray_f2 <= raddr_gray_f1;
    end
  end

  //产生空满标志
  assign empty = (waddr_gray_f2 == raddr_gray)? 1'b1:1'b0;
  assign full = (raddr_gray_f2[addr_width:addr_width-1] == ~waddr_gray[addr_width:addr_width-1] && raddr_gray_f2[addr_width-2:0]==waddr_gray[addr_width-2:0] )? 1'b1:1'b0;
  
  //写数据
  integer i;
  always @(posedge w_clk or negedge w_rst_n) begin 
    if(~w_rst_n) begin
	    for(i=0;i<DEPTH;i=i+1)
	      fifo_data[i] <= 0;
	end 
    else if(wr_en & (~full)) begin
      fifo_data[waddr] <= w_data;
    end
  end
  
  //读数据
  always @(posedge r_clk or negedge r_rst_n) begin 
    if(~r_rst_n) begin
      r_data <= 0;
    end else if(rd_en & (~empty)) begin
      r_data <= fifo_data[raddr];
    end
  end
endmodule 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
五、testbench文件
module tb_ast_fifo();
  reg w_clk;
  reg r_clk;
  reg rst_n;
  reg wr_en;
  reg rd_en;
  reg [7:0] w_data;
  wire   [7:0] r_data;
  wire  full;
  wire  empty;

  always#15 w_clk = ~w_clk;   
  always#10 r_clk = ~r_clk;
  always#30 w_data = $random; 
  initial begin
    rst_n = 0;
    w_clk = 0;
    r_clk = 0;
    #10 rst_n =1;
    #40 wr_en = 1;
      rd_en = 0;
      #500 rd_en = 1;
      #2000 $stop;
  end
  
    asy_fifo #(
        .WIDTH(8),
        .DEPTH(16)
      ) inst_asy_fifo (
        .w_clk  (w_clk),
        .r_clk  (r_clk),
        .rst_n  (rst_n),
        .wr_en  (wr_en),
        .rd_en  (rd_en),
        .w_data (w_data),
        .r_data (r_data),
        .full   (full),
        .empty  (empty)
      );

endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
六、仿真结果


在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/1009807
推荐阅读
相关标签
  

闽ICP备14008679号