异步FIFO设计(代码篇)

//异步FIFO
//深度16 宽度16
module top
#(
    parameter   depth = 16,
    parameter   width = 16
)
(
    input               wr_clk      ,
    input               rst_n       ,
    input               wr_en       ,
    input   [width-1:0] data_in     ,
    
    input               rd_clk      ,
    input               rd_en       ,
    
    output  [width-1:0] data_out    ,
    
    output              full        ,
    output              empty
);

reg     [width-1:0] mem [depth-1:0];
reg     [width-1:0] temp_rdata;

reg     [4:0]   waddr;
wire    [4:0]   waddr_gray;
reg     [4:0]   waddr_w2r1;
reg     [4:0]   waddr_w2r2;

reg     [4:0]   raddr;
wire    [4:0]   raddr_gray;
reg     [4:0]   raddr_r2w1;
reg     [4:0]   raddr_r2w2;

//写指针

always@(posedge wr_clk or negedge rst_n)
begin
    if (!rst_n)
        waddr <= 5'd000;
    else if (wr_en)
        waddr <= waddr + 1'b1;
    else 
        waddr <= waddr;
end 

//写指针转格雷码

assign  waddr_gray = (waddr >> 1) ^ waddr;

//写指针同步到读时钟域

always@(posedge wr_clk or negedge rst_n)
begin 
    if (!rst_n)
        {waddr_w2r2,waddr_w2r1} <= {2{5'b0_0000}};
    else 
        {waddr_w2r2,waddr_w2r1} <= {waddr_w2r1,waddr_gray};
end 

//读指针

always@(posedge rd_clk or negedge rst_n)
begin
    if (!rst_n)
        raddr <= 5'd000;
    else if (rd_en)
        raddr <= raddr + 1'b1;
    else 
        raddr <= raddr;
end 

//读指针转换为格雷码

assign  raddr_gray = (raddr >> 1) ^ raddr;

//读指针同步到写时钟域

always@(posedge rd_clk or rst_n)
begin 
    if (!rst_n)
        {raddr_r2w2,raddr_r2w1} <= {2{5'b0_0000}};
    else 
        {raddr_r2w2,raddr_r2w1} <= {raddr_r2w1,raddr_gray};
end 

//写数据

always@(posedge wr_clk)
begin 
    mem[waddr] <= data_in;
end 

//读数据 1 latency 

assign  data_out = temp_rdata;

always@(posedge rd_clk or negedge rst_n)
begin 
    if (!rst_n)
        temp_rdata <= {width{1'b0}};
    else if (rd_en == 1'b1)
        temp_rdata <= mem[raddr];
    else 
        temp_rdata <= temp_rdata;
end 

//空信号检测(写指针同步到rd_clk后与读指针进行比较)

assign  empty = (waddr_w2r2 == raddr_gray) ? 1'b1 : 1'b0;

//满信号检测(读指针同步到wr_clk后与写指针进行比较)

assign  full = ({~(raddr_r2w2[4:3]),raddr_r2w2[2:0]} == waddr_gray) ? 1'b1 : 1'b0;

endmodule

//testbench

`timescale 1ns/1ns

module top_test();

reg                 wr_clk      ;
reg                 rst_n       ;
reg                 wr_en       ;
reg   [15:0]        data_in     ;

reg                 rd_clk      ;
reg                 rd_en       ;

wire  [15:0]        data_out    ;

wire                full        ;
wire                empty       ;

initial
begin 
    wr_clk = 1'b0;
    rd_clk = 1'b0;
    rst_n = 1'b0;
    wr_en = 1'b0;
    rd_en = 1'b0;
    data_in = 16'h0000;
    
    repeat(5)@(posedge wr_clk)
    rst_n = 1'b1;
    repeat(5)@(posedge wr_clk)
    drive_w();
    repeat(5)@(posedge wr_clk)
    drive_r();
end 

task    drive_w;
    integer i;
    begin
        for (i=0;i<16;i=i+1)
        begin 
            wr_en   <= 1'b1;
            data_in <= i[15:0];
            @(posedge wr_clk);
            wr_en   <= 0;
        end 
    end 
endtask

task    drive_r;
    integer i;
    begin 
        for (i=0;i<16;i=i+1)
        begin 
            rd_en   <= 1'b1;
            @(posedge rd_clk);
            rd_en   <= 1'b0;
        end
    end 
endtask

always #10 wr_clk = ~wr_clk;
always #5  rd_clk = ~rd_clk;

top top_inst1(
    .wr_clk      (wr_clk      ),
    .rst_n       (rst_n       ),
    .wr_en       (wr_en       ),
    .data_in     (data_in     ),

    .rd_clk      (rd_clk      ),
    .rd_en       (rd_en       ),

    .data_out    (data_out    ),

    .full        (full        ),
    .empty       (empty)

);

endmodule

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值