异步FIFO的设计和验证

异步fifo的用途:1.跨时钟域,异步FIFO读写分别采用相互异步的不同时钟。2.位宽变换,对于不同宽度的数据接口也可以用FIFO,例如单片机位8位数据输出,而DSP可能是16位数据输入,在单片机与DSP连接时就可以使用FIFO来达到数据匹配的目的。

同步fifo可看同步FIFO设计及验证_矜持小梦的博客-CSDN博客

异步FIFO的设计难点在于空满标志符的产生,由于异步FIFO的读写是用不同的时钟来控制的,所以不能采用计数器的方法来产生空满标志符

因为不同的时钟信号,还需要解决跨时钟域的问题:此笔记中有写IC设计验证基础笔试题总结_矜持小梦的博客-CSDN博客_ic验证笔试

解决方法就是加两级寄存器同步 + 格雷码(目的都是消除亚稳态)

空满标志:当读写指针相等时,可能是空也可能是满2种情况,将指针宽度多增加一位,即可用来做空满判断。最高位不同,低位都相同,则满。最高位相同,低位也都相同,则空。

寄存器:

引入格雷码:如果是满状态的话,我们以二进制为例,应该满足读指针=3’b111,写指针=3’b011,相对应的格雷码应该满足读指针=3’b100,写指针=3’b010,通俗来讲,满状态要满足读指针和写指针的高位和次高位相反,其余各位相等。读状态则完全相同。同时由于格雷码的引入,使得FIFO的深度只能是2的幂次方。格雷码相邻数据只有一位跳变,这样就大大降低了数据出错的概率

二进制转为格雷码:assign  gray_code = (bin_code>>1)  ^  bin_code;

对于深度为2n的FIFO,需要的读/写指针位宽为(n+1)位

设计图

异步FIFO的设计和验证_第1张图片

async_fifo.v

module async_fifo #(parameter FIFO_WIDTH = 8,
                              FIFO_DEPTH = 16,
                              ADDR_WIDTH = 4)
(
  input   wire                  rclk,
  input   wire                  wclk,
  input   wire                  rst_n,
  input   wire                  wr_en,
  input   wire                  rd_en,
  input   wire[FIFO_WIDTH-1:0]  wr_data,
  output  reg [FIFO_WIDTH-1:0]  rd_data,
  output  reg                   empty,
  output  reg                   full
);
//memory
reg [FIFO_WIDTH-1:0]            mem[FIFO_DEPTH-1:0];
//address
reg [ADDR_WIDTH-1:0]            wr_addr,rd_addr;
//binary adderss
reg [ADDR_WIDTH:0]              wr_addr_b,rd_addr_b;
//gray address
reg [ADDR_WIDTH:0]              wr_addr_g,rd_addr_g;
//sample gray address
reg [ADDR_WIDTH:0]              wr_addr_g_dly1,wr_addr_g_dly2,rd_addr_g_dly1,rd_addr_g_dly2;

//binary code to gray code
initial begin
assign  wr_addr_g = (wr_addr_b>>1) ^ wr_addr_b;
assign  rd_addr_g = (rd_addr_b>>1) ^ rd_addr_b;
//addr
assign  wr_addr = wr_addr_b[ADDR_WIDTH-1:0];
assign  rd_addr = rd_addr_b[ADDR_WIDTH-1:0];
end
//read & write allow
wire    rd_allow = rd_en && !empty;
wire    wr_allow = wr_en && !full;

//write data
always @(posedge wclk or negedge rst_n)
    if(rst_n == 1'b0)
        wr_addr_b <= 'b0;
    else if(wr_allow) begin
        mem[wr_addr] <= wr_data;
        wr_addr_b <= wr_addr_b + 1'b1;
    end

//read data
always @(posedge rclk or negedge rst_n)
    if(rst_n == 1'b0)
        rd_addr_b <= 'b0;
    else if(rd_allow) begin
        rd_data <= mem[rd_addr];
        rd_addr_b <= rd_addr_b + 1'b1;
    end

//wr_addr_g sample twice
always @(posedge rclk or negedge rst_n)
    if(rst_n == 1'b0)
        {wr_addr_g_dly2,wr_addr_g_dly1} <= 'b0;
    else
        {wr_addr_g_dly2,wr_addr_g_dly1} <= {wr_addr_g_dly1,wr_addr_g};

//rd_addr_g sample twice
always @(posedge wclk or negedge rst_n)
    if(rst_n == 1'b0)
        {rd_addr_g_dly2,rd_addr_g_dly1} <= 'b0;
    else
        {rd_addr_g_dly2,rd_addr_g_dly1} <= {rd_addr_g_dly1,rd_addr_g};
initial begin
assign  empty = (rd_addr_g == wr_addr_g_dly2);
assign  full  = (wr_addr_g == {~rd_addr_g_dly2[ADDR_WIDTH:ADDR_WIDTH-1],rd_addr_g_dly2[ADDR_WIDTH-2:0]});
end
endmodule

async_fifo_tb.v

`timescale 1ns/1ps
module async_fifo_tb();

parameter       FIFO_WIDTH = 8,
                FIFO_DEPTH = 16,
                ADDR_WIDTH = 4;

reg                     rclk,wclk,rst_n,wr_en,rd_en;
reg [FIFO_WIDTH-1:0]    wr_data;
wire[FIFO_WIDTH-1:0]    rd_data;
wire                    empty,full;

async_fifo u1
/*#(  .FIFO_WIDTH (FIFO_WIDTH),
    .FIFO_DEPTH (FIFO_DEPTH),
    .ADDR_WIDTH (ADDR_WIDTH)
)*/
(
  .rclk     (rclk   ),
  .wclk     (wclk   ),
  .rst_n    (rst_n  ),
  .wr_en    (wr_en  ),
  .rd_en    (rd_en  ),
  .wr_data  (wr_data),
  .rd_data  (rd_data),
  .empty    (empty  ),
  .full     (full   )
);

initial begin
    rst_n=0;
    rclk=0;
    wclk=0;
    #5
    rst_n=1;
end

always #30 rclk=~rclk;
always #20 wclk=~wclk;

initial begin
    wr_en=0;
    rd_en=0;
    #50
    wr_en=1;
    wr_data=8'h0;
    #40 wr_data=8'h1;
    #40 wr_data=8'h2;
    #40 wr_data=8'h3;
	rd_en=1;
    #40 wr_data=8'h4;
    #40 wr_data=8'h5;
    #40 wr_data=8'h6;
    #40 wr_data=8'h7;
    #40 wr_data=8'h8;
    #40 wr_data=8'h9;
    #40 wr_data=8'hA;
    #40 wr_data=8'hB;
    #40 wr_data=8'hC;
    #40 wr_data=8'hD;
    #40 wr_data=8'hE;
    #40 wr_data=8'hF;
    #60
    wr_en=0;
    //rd_en=1;
    #1000
    $finish;
end

endmodule

 仿真波形

 

你可能感兴趣的:(IC项目学习笔记,面试,fpga开发)