异步时钟异步位宽FIFO

本文介绍了一种由作者自定义的异步FIFO,支持不同宽度的数据流,特别强调了异步时钟的设计以及如何处理跨时钟域通信。代码提供了可配置的读写位宽,并使用格雷码简化了满空检测过程。
摘要由CSDN通过智能技术生成

        网上异步FIFO有很多,但是异步位宽的很少,要么就调用IP,有的时候修改起来又要改IP比较麻烦,所以自己就简单写了个异步时钟异步位宽的FIFO,望大家品鉴,谢谢!

        关于FIFO的含义等,这里就不在赘述了,网上有很多。下面直接上代码:

module   async_fifo #(  
    parameter   WDATA_WIDTH = 8, //写位宽
    parameter   RDATA_WIDTH = 64, //读位宽
    parameter   WFIFO_DEPTH = 1024 , //写深度
    parameter   RFIFO_DEPTH = (WFIFO_DEPTH*WDATA_WIDTH)/RDATA_WIDTH
)(  
    input                           rst_n       ,
     	
	input							wr_clk		,				 
	input							wr_en		,       		 
	input	[WDATA_WIDTH-1:0]		wr_data		,   
    output [$clog2(WFIFO_DEPTH)-1:0]wr_data_cont,         
	output	 		    			wrfull		,      		 
 		
	input							rd_clk		,				 
	input							rd_en		,				 					                                        
	output	 	[RDATA_WIDTH-1:0]	rd_data 	,	
    output [$clog2(RFIFO_DEPTH)-1:0]rd_data_cont,   	 
	output	     					rdempty	 	 
);      
 
    localparam DATA_WIDTH = (WDATA_WIDTH>RDATA_WIDTH) ? RDATA_WIDTH : WDATA_WIDTH;
    localparam FIFO_DEPTH = (WDATA_WIDTH>RDATA_WIDTH) ? RFIFO_DEPTH : WFIFO_DEPTH;
    localparam WR_BURST_LEN = (WDATA_WIDTH>RDATA_WIDTH) ? (WDATA_WIDTH/RDATA_WIDTH) : 1'b1 ;
    localparam RD_BURST_LEN = (RDATA_WIDTH>WDATA_WIDTH) ? (RDATA_WIDTH/WDATA_WIDTH) : 1'b1 ;
  
   (* ram_style="block" *) reg [DATA_WIDTH-1:0] fifo_memory[FIFO_DEPTH-1:0]; 
    
    //write clock domain	
    reg [$clog2(FIFO_DEPTH):0]		wr_ptr;			 
    wire[$clog2(FIFO_DEPTH)-1:0]    wr_ptr_actual;    
    reg	[$clog2(FIFO_DEPTH):0]		wr_gray_ptr1;	 
    reg	[$clog2(FIFO_DEPTH):0]		wr_bin_ptr2;	 
    reg	[$clog2(FIFO_DEPTH):0]		wr_bin_ptr1;	 
    reg [$clog2(FIFO_DEPTH):0]      wr_rd_bin_ptr_reg;
    wire[$clog2(WFIFO_DEPTH)-1:0]   wr_data_cont_reg;
 
    //read clock domain
    reg [$clog2(FIFO_DEPTH):0]		rd_ptr;			 
    wire[$clog2(FIFO_DEPTH)-1:0]    rd_ptr_actual;   
    reg	[$clog2(FIFO_DEPTH):0]		rd_gray_ptr1;	 
    reg	[$clog2(FIFO_DEPTH):0]		rd_bin_ptr2;	 
    reg	[$clog2(FIFO_DEPTH):0]		rd_bin_ptr1;	  
    reg [$clog2(FIFO_DEPTH):0]      rd_wr_bin_ptr_reg;
    wire[$clog2(WFIFO_DEPTH)-1:0]   rd_data_cont_reg;

 
    reg [$clog2(FIFO_DEPTH):0]		wr_ptr_g;
    reg [$clog2(FIFO_DEPTH):0]		rd_ptr_g;	 

    wire[$clog2(FIFO_DEPTH):0]      rd_gray_ptr ; 
    wire[$clog2(FIFO_DEPTH):0]      wr_gray_ptr ;  

    assign rd_ptr_actual = rd_ptr[$clog2(FIFO_DEPTH)-1:0];
    assign wr_ptr_actual = wr_ptr[$clog2(FIFO_DEPTH)-1:0];
    assign wr_gray_ptr   = (wr_ptr_g)^((wr_ptr_g)>>1); 
    assign rd_gray_ptr   = (rd_ptr_g)^((rd_ptr_g)>>1);
 
 
    //write clock domain
     integer m=0;
    always @ (posedge wr_clk or negedge rst_n) begin
	    if (!rst_n) begin
	    	wr_ptr <= 0;  
            wr_ptr_g <= 0; 
        end
	    else if (!wrfull && wr_en)begin								 
	    	wr_ptr <= wr_ptr + WR_BURST_LEN; 
            wr_ptr_g <= (wr_ptr + WR_BURST_LEN)/WR_BURST_LEN;   
	    end	
    end
    always @ (posedge wr_clk ) begin
	    if (!wrfull && wr_en )begin		 
            for(m=0;m<WR_BURST_LEN;m=m+1) begin  
                fifo_memory[wr_ptr_actual + m] <= wr_data[m*DATA_WIDTH +: DATA_WIDTH];   
            end
	    end	
    end  
    always @ (posedge wr_clk or negedge rst_n) begin
    	if (!rst_n)begin
    		rd_gray_ptr1 <= 0;				 
    		rd_bin_ptr1 <= 0;	 		 
    		rd_bin_ptr2 <= 0;	 	
            wr_rd_bin_ptr_reg <= 0;		 
    	end				
    	else begin												
    		rd_gray_ptr1 <= rd_gray_ptr; 					 
    		rd_bin_ptr1 <= gray2bin(rd_gray_ptr1);			 
    		rd_bin_ptr2 <= (rd_bin_ptr1*RD_BURST_LEN)/WR_BURST_LEN;	
            wr_rd_bin_ptr_reg <= rd_bin_ptr2;	  
            
    	end	
    end  
    assign wr_data_cont_reg = (wr_rd_bin_ptr_reg[$clog2(WFIFO_DEPTH)]==wr_ptr_g[$clog2(WFIFO_DEPTH)])?
                    (wr_ptr_g[$clog2(WFIFO_DEPTH)-1:0]-wr_rd_bin_ptr_reg[$clog2(WFIFO_DEPTH)-1:0]):
                    WFIFO_DEPTH-(wr_rd_bin_ptr_reg[$clog2(WFIFO_DEPTH)-1:0]-wr_ptr_g[$clog2(WFIFO_DEPTH)-1:0]); 
    assign wrfull = (wr_rd_bin_ptr_reg[$clog2(WFIFO_DEPTH)]!=wr_ptr_g[$clog2(WFIFO_DEPTH)]) &&
            (wr_ptr_g[$clog2(WFIFO_DEPTH)-1:0]==wr_rd_bin_ptr_reg[$clog2(WFIFO_DEPTH)-1:0]);
    assign wr_data_cont = wr_data_cont_reg; 
//**************************************************************************************************************//
//**************************************************************************************************************//
//**************************************************************************************************************//
//**************************************************************************************************************// 
    //read clock domain
   // integer n=0;
    always @ (posedge rd_clk or negedge rst_n) begin
	    if (!rst_n) begin
	    	rd_ptr <= 0; 
          //  rd_data <= 0;
            rd_ptr_g <= 0;
        end
	    else if (!rdempty && rd_en)begin								 
	    	rd_ptr <= (rd_ptr + RD_BURST_LEN); 
            rd_ptr_g <= (rd_ptr + RD_BURST_LEN)/RD_BURST_LEN;
            // for(n=0;n<RD_BURST_LEN;n=n+1) begin   
            //     rd_data[n*DATA_WIDTH +: DATA_WIDTH] <= fifo_memory[rd_ptr_actual + n];  
            // end 
	    end	
    end     
    genvar n;
    generate 
        for(n=0;n<RD_BURST_LEN;n=n+1) begin  
            assign rd_data[n*DATA_WIDTH +: DATA_WIDTH] = fifo_memory[rd_ptr_actual + n]; 
        end
    endgenerate
  
    always @ (posedge rd_clk or negedge rst_n) begin
    	if (!rst_n)begin
    		wr_gray_ptr1 <= 0;				 
    		wr_bin_ptr1 <= 0;				 
    		wr_bin_ptr2 <= 0;		 	 
            rd_wr_bin_ptr_reg <= 0; 
    	end				
    	else begin												
    		wr_gray_ptr1 <= wr_gray_ptr;						 
    		wr_bin_ptr1 <= gray2bin(wr_gray_ptr1);				 
    		wr_bin_ptr2 <= (wr_bin_ptr1*WR_BURST_LEN)/RD_BURST_LEN;
            rd_wr_bin_ptr_reg <= wr_bin_ptr2;   	 
    	end	
    end 
    assign rd_data_cont_reg = (rd_wr_bin_ptr_reg[$clog2(RFIFO_DEPTH)]==rd_ptr_g[$clog2(RFIFO_DEPTH)])?
                    (rd_wr_bin_ptr_reg[$clog2(RFIFO_DEPTH)-1:0]-rd_ptr_g[$clog2(RFIFO_DEPTH)-1:0]):
                    RFIFO_DEPTH-(rd_ptr_g[$clog2(RFIFO_DEPTH)-1:0]-rd_wr_bin_ptr_reg[$clog2(RFIFO_DEPTH)-1:0]); 
    assign rdempty = (rd_wr_bin_ptr_reg[$clog2(RFIFO_DEPTH):0]==rd_ptr_g[$clog2(RFIFO_DEPTH):0]);	
    assign rd_data_cont = rd_data_cont_reg;


 
 
    function [$clog2(FIFO_DEPTH):0] gray2bin;
        input [$clog2(FIFO_DEPTH):0] gray_i;
        integer i;
        reg [$clog2(FIFO_DEPTH):0] temp;
        begin 
            temp[$clog2(FIFO_DEPTH)] = gray_i[$clog2(FIFO_DEPTH)];
            for(i = $clog2(FIFO_DEPTH) ; i >0; i = i - 1)  begin 										 
    			temp[i-1] = temp[i] ^ gray_i[i-1];
    		end 
            gray2bin = temp;
        end
    endfunction


endmodule          
 

读写位宽可通过参数配置,读写位宽需要有倍数关系,如 写:8bit,读16bit;

FIFO深度是以写FIFO深度计算的,最好是2的幂级数。

在跨时钟域上还是采用格雷码格式。

代码中接口上加了读写计数端口,如果去掉计数端口,在比较满空时,可以直接用格雷码比较,不需要转回二进制数。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值