异步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)位

设计图

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

 仿真波形

 

  • 2
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
异步FIFO是一种常见的硬件设计模块,用于在不同的时钟域之间传输数据。UVM(Universal Verification Methodology)是一种用于验证硬件设计的方法学。在UVM验证中,验证工程师可以使用UVM中提供的各种类和方法来验证异步FIFO的功能和正确性。 下面是一个简单的UVM验证异步FIFO的示例: 首先,我们需要创建一个Transaction类来表示FIFO中的数据项。这个类可以包含需要验证的数据字段。 然后,我们创建一个Agent类来模拟FIFO的发送和接收端。这个Agent类可以包含两个接口,一个用于发送数据到FIFO,另一个用于从FIFO接收数据。Agent类还可以包含一个Monitor来监视FIFO的状态,并将收到的数据转换为Transaction对象。 接下来,我们创建一个Sequencer类来生成数据项并将其发送到FIFO的发送端口。Sequencer类可以使用UVM提供的随机化机制来生成不同的数据项。 然后,我们创建一个Driver类来驱动Sequencer生成的数据项,并将其发送到FIFO的发送端口。 最后,我们可以创建一个Test类来实例化和连接上述组件,并编写测试用例来验证异步FIFO的功能和正确性。 在验证过程中,我们可以使用UVM提供的各种断言和功能覆盖率工具来验证异步FIFO的正确性。通过生成不同的测试用例和使用各种场景和边界条件,我们可以尽可能地覆盖所有可能的情况,并验证异步FIFO的正确性。 需要注意的是,上述只是一个简单的UVM验证异步FIFO的示例,实际的验证过程可能更为复杂,需要根据具体的设计和需求进行调整和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值