verilog实现异步、同步FIFO

该文介绍了如何使用Verilog语言设计异步和同步FIFO,强调了代码可移植性和资源选择灵活性。在处理读写时钟差异时,解释了为何不会导致逻辑错误,并提供了具体的代码示例来说明FIFO的空和满信号判断。测试文件展示了模块的正确运行情况。
摘要由CSDN通过智能技术生成
1、通过Verilog形式实现异步和同步FIFO,提高代码可移植性。
2、内部可选择调用FPGA板上block、distributed ram资源
3、读写数据位宽一致。FIFO深度为2^n

问题理解:异步fifo读写时钟差距较大会影响FIFO的逻辑功能错误吗?

答案:不会。我们假设读时钟域大于写时钟域,则读时钟域下空信号的判断不会有问题(快时钟采慢时钟)。对于满信号的产生,我们假设读时钟产生地址为7,8,9,10,则写时钟域下同步过来采集到的可能只有7,10。但是写时钟域下写地址正缓慢递增,直到超过采集过来的读地址的一圈后,产生写满信号

代码展示:

module fifo #(
    parameter   D_WIDTH = 8     ,   //data width
    parameter   F_DEPTH = 512   ,   //fifo depth
    parameter   DELAY   = 1     ,   //output data delay
    parameter   F_TYPE  ="SYNC" ,   //fifo type:SYNC(synchronous),ASYNC(asynchronous)
    parameter   R_TYPE  ="block"    //ram type:block,distributed
)(
    rst_n   ,//input , reset low efficiency
    clka    ,//input , clock a
    wr_en   ,//input , write enable
    w_data  ,//input , write data
    clkb    ,//input , clock b
    rd_en   ,//input , read enable
    r_data  ,//output, read data
    empty   ,//output, siginal empty
    full     //output, siginal full             
);

parameter   A_WIDTH = $clog2(F_DEPTH);

input                   rst_n   ;//input , reset low efficiency
input                   clka    ;//input , clock a
input                   wr_en   ;//input , write enable
input   [D_WIDTH-1:0]   w_data  ;//input , write data
input                   clkb    ;//input , clock b
input                   rd_en   ;//input , read enable
output  [D_WIDTH-1:0]   r_data  ;//output, read data
output                  empty   ;//output, siginal empty
output                  full    ;//output, siginal full 

generate
    if(F_TYPE == "SYNC") begin:SYNC 

        wire clk = clka;
        reg  [A_WIDTH:0] w_addr;
        reg  [A_WIDTH:0] r_addr;

        always@(posedge clk or negedge rst_n) begin
            if(!rst_n) begin
                w_addr <= 'b0;
            end
            else if(wr_en && !full) begin
                w_addr <= w_addr + 1'b1;
            end
        end

        always@(posedge clk or negedge rst_n) begin
            if(!rst_n) begin
                r_addr <= 'b0;
            end
            else if(rd_en && !empty) begin
                r_addr <= r_addr + 1'b1;
            end
        end
        
        assign empty = (w_addr == r_addr);
        assign full  = (w_addr == {!r_addr[A_WIDTH],r_addr[A_WIDTH-1:0]});
        
        simp_dual_ram #(
            .A_WIDTH(A_WIDTH),//address width
            .R_DEPTH(F_DEPTH),//ram depth
            .D_WIDTH(D_WIDTH),//data width
            .DELAY  (DELAY  ),//read data output delay
            .TYPE   (R_TYPE ) //block,distributed
        ) u_simp_dual_ram(  
            //port a        
            .clka    (clk   ),//clock a
            .ena     (wr_en ),//write enable
            .w_addr  (w_addr[A_WIDTH-1:0]),//write address
            .w_data  (w_data),//write data
            //port b       
            .clkb    (clkb  ),//clock b
            .enb     (rd_en ),//read enable
            .r_addr  (r_addr[A_WIDTH-1:0]),//read address
            .r_data  (r_data) //read data
        ); 
    end
    else begin:ASYNC

        reg  [A_WIDTH:0] w_addr                 ;
        reg  [A_WIDTH:0] r_addr                 ;
        reg  [A_WIDTH:0] w_addr_gray2clkb[0:1]  ;
        reg  [A_WIDTH:0] r_addr_gray2clka[0:1]  ;

        always@(posedge clka or negedge rst_n) begin
            if(!rst_n) begin
                w_addr <= 'b0;
            end
            else if(wr_en && !full) begin
                w_addr <= w_addr + 1'b1;
            end
        end
        wire [A_WIDTH:0] w_addr_gray = w_addr ^ (w_addr >> 1);
        
        always@(posedge clkb or negedge rst_n) begin
            if(!rst_n) begin
                r_addr <= 'b0;
            end
            else if(rd_en && !empty) begin
                r_addr <= r_addr + 1'b1;
            end
        end
        wire [A_WIDTH:0] r_addr_gray = r_addr ^ (r_addr >> 1);

        always@(posedge clka or negedge rst_n) begin
            if(!rst_n) begin
                {r_addr_gray2clka[1],r_addr_gray2clka[0]} <= 'b0;
            end
            else begin
                {r_addr_gray2clka[1],r_addr_gray2clka[0]} <= {r_addr_gray2clka[0],r_addr_gray};
            end
        end

        always@(posedge clkb or negedge rst_n) begin
            if(!rst_n) begin
                {w_addr_gray2clkb[1],w_addr_gray2clkb[0]} <= 'b0;
            end
            else begin
                {w_addr_gray2clkb[1],w_addr_gray2clkb[0]} <= {w_addr_gray2clkb[0],w_addr_gray};
            end
        end

        assign empty = (w_addr_gray2clkb[1] == r_addr_gray);
        assign full  = ({!w_addr_gray[A_WIDTH-:2],w_addr_gray[A_WIDTH-2:0]} == r_addr_gray2clka[1]);

        simp_dual_ram #(
            .A_WIDTH(A_WIDTH),//address width
            .R_DEPTH(F_DEPTH),//ram depth
            .D_WIDTH(D_WIDTH),//data width
            .DELAY  (DELAY  ),//read data output delay
            .TYPE   (R_TYPE ) //block,distributed
        ) u_simp_dual_ram(  
            //port a        
            .clka    (clka  ),//clock a
            .ena     (wr_en ),//write enable
            .w_addr  (w_addr[A_WIDTH-1:0]),//write address
            .w_data  (w_data),//write data
            //port b       
            .clkb    (clkb  ),//clock b
            .enb     (rd_en ),//read enable
            .r_addr  (r_addr[A_WIDTH-1:0]),//read address
            .r_data  (r_data) //read data
        ); 

    end
endgenerate

endmodule

测试文件:

`timescale 1ns/1ps

module fifo_tb;

reg clka,wr_en,clkb,rd_en,rst_n;
reg [7:0] w_data;
wire[7:0] r_data;
wire empty,full;

initial begin
    clka <= 1'b0;
    clkb <= 1'b0;
    rst_n <= 1'b0;
    #50;
    rst_n <= 1'b1;
end
always#5 clka <= !clka;
always#2.5 clkb <= !clkb;


initial begin
    wr_en <= 1'b0;
    w_data<= 8'd10;
    rd_en <= 1'b0 ;
    @(posedge rst_n);
    @(posedge clka);
    wr_en <= 1'b1;
    #150;
    wr_en <= 1'b0;
    rd_en <= 1'b1;
    #150;
    rd_en <= 1'b0;
    #100;
    $finish;
end

fifo #(
    .D_WIDTH(8      ),  //data width
    .F_DEPTH(8      ),  //fifo depth
    .DELAY  (1      ),  //output data delay
    .F_TYPE ("ASYNC" ),  //fifo type:SYNC(synchronous),ASYNC(asynchronous)
    .R_TYPE ("block")   //ram type:block,distributed
)u_fifo(
    .rst_n   (rst_n ),//input , reset low efficiency
    .clka    (clka  ),//input , clock a
    .wr_en   (wr_en ),//input , write enable
    .w_data  (w_data),//input , write data
    .clkb    (clkb  ),//input , clock b
    .rd_en   (rd_en ),//input , read enable
    .r_data  (r_data),//output, read data
    .empty   (empty ),//output, siginal empty
    .full    (full  ) //output, siginal full             
);

endmodule

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值