异步FIFO

异步FIFO(Asynchronous First In First Out)

1. 前言

​ 由于EDA工具的广泛支持,采用同步电路设计的方法是目前Soc设计的基本要求,但在一个功能复杂的Soc系统中,难免会有异步信号与同步电路交互的问题。特别是在由许多核组成的Soc中,通常采用全局异步局部同步(GALS)的设计。而跨时钟域传输数据时很容易造成亚稳态的现象,本文主要讲解Asyn_FIFO来解决跨时钟域传输多bit信号的问题。

2. Asyn_FIFO的结构与原理

Asyn_FIFO: 写数据wdata在写时钟域下wclk写入到FIFO中的存储器(双端口RAM)中,读数据rdata在读时钟域rclk下从FIFO中的存储器读出wdata写入的值。综合下,Asynchronous FIFO可以安全地把数据从一个时钟域传输到另外一个时钟域。

2.1 Asynchronous FIFO的结构

  • 总体架构图如下
  • 可以看出由5个模块组成:FIFO Memory, wptr_full, rptr_empty, sync_r2w, sync_w_r
    • FIFO Memory: 这部分就是存储器。
    • wptr_full: 在写信号有效的情况下, 生成二进制的写地址指针waddr、Gray码的写地址指针wptr和判满信号wfull。
    • rptr_empty: 在读信号有效的情况下, 生成二进制的读地址指针raddr、Gray码的读地址指针rptr和判空信号rempty。
    • sync_r2w: rclk domain 到 wclk domain 的同步器,Gray码的读地址指针rptr在wclk domain下的寄存器寄存两拍然后传输给wptr_full模块。
    • sync_w2r: wclk domain 到 rclk domain 的同步器,Gray码的写地址指针wptr在rclk domain下的寄存器寄存两拍然后传输给rptr_empty模块。

2.2 Asynchronous FIFO的原理

1) FIFO Memory
  • Asyn_FIFO的存储器部分采用RAM,而RAM分类有单端口和双端口,同步和异步。因为Syn_FIFO是需要在两个时钟域下工作的模块(分开读分开写)。所以采用双端口的RAM。而同步RAM和异步RAM的区别是在读端口引入一级DFF在时钟上升沿读取还是raddr改变时直接读取,也即同步读、异步读,理想情况下,同步读数据比异步读数据晚一个读时钟周期。通常这两种都可以,看具体要求再设计。
2) wptr_full and rptr_empty
  • 这两个模块实际上是对称的,设计思路都是一样的。具体思路如下:
  • 写时钟域:
    1. 根据写使能信号winc和写满标志位wfull来产生二进制写指针wbin;
    2. 根据二进制写指针wbin产生双端口RAM的写地址waddr;
    3. 把二进制写指针wbin转换成Gray码写指针wptr;
    4. 从同步器sync_r2w得到同步到写时钟域下的Gray码读指针;
    5. 判断 wptrnext == wq2_rptr 得写满标志位wfull;
  • 读时钟域:
    1. 根据读使能信号rinc和读空标志rempty来产生二进制读指针rbin;
    2. 根据二进制读指针rbin产生双端口RAM得读地址raddr;
    3. 把二进制读指针raddr转换成Gray码写指针rptr;
    4. 从同步器sync_w2r得到同步到读时钟域下得Gray码写指针;
    5. 判断 rptrnext == rq2_wptr 得读空标志位rempty;
3) sync_w2r and sync_r2w
  • 两级同步器

###2.3 信号描述

1) FIFO_Memory
2) wptr_full
NameSourceToDescription
wincmodule of wclkfifo_memory and wptr_full写使能信号
wclkclock source写时钟域下的module上升沿触发
wrst_nreset controller写时钟域下的module复位信号,低电平有效
wq2_rptr[ADDRSIZE:0]rptr_rempty modulewptr_full module经由两级同步器synr_r2w同步到写时钟域的读Gray码指针
waddr[ADDRSIZE-1:0]wptr_full modulefifo_memory二进制写地址
wptr[ADDRSIZE:0]wptr_full modulesyn_w2r moduleGary码读指针,输出给syn_w2r
wfullwptr_full modulewptr_full module and module of wclk写满标志,wptr_full模块自身又作为输入,同时传递给在wclk下的的数据发送端
3) rptr_empty
NameSourceToDescription
rincmodule of rclkfifo_memory and rptr_empty写使能信号
rclkclk source读时钟域下的module上升沿触发
rrst_nreset controller读时钟域下的module复位信号,低电平有效
rq2_wptr[ADDRSIZE:0]wptr_full modulerptr_empty module经由两级同步器synr_w2r同步到读时钟域的写Gray码指针
raddr[ADDRSIZE-1:0]rptr_full modulefifo_memory module二进制读指针
rptr[ADDRSIZE:0]rptr_empty modulesyn_r2wGray码读指针
remptyrptr_emptyrptr_empty module and module of rclk读空标志,rptr_empty模块自身又作为输入,同时传递给在rclk下的数据发送端

3 RTL code

1) FIFO Top-Level module

module asyn_fifo #(
    parameter DATASIZE = 8,
    parameter ADDRSIZE = 4
) (
    input                   winc, wclk, wrst_n,
    input                   rinc, rclk, rrst_n,
    input   [DATASIZE-1:0]  wdata,
    output  [DATASIZE-1:0]  rdata,
    output                  wfull,
    output                  rempty
);
    
    wire [ADDRSIZE-1:0] waddr, raddr;
    wire [ADDRSIZE:0]   wptr, rptr, rq2_wptr, wq2_rptr;


    fifomem #(
        .DATASIZE 		( 8 		),
        .ADDRSIZE 		( 4 		))
    u_fifomem(
        //ports
        .wclken 		( winc 		),
        .wfull  		( wfull  		),
        .wclk   		( wclk   		),
        .waddr  		( waddr  		),
        .raddr  		( raddr  		),
        .wdata  		( wdata  		),
        .rdata  		( rdata  		)
    );


    rptr_empty #(
        .ADDRSIZE 		( 4 		))
    u_rptr_empty(
        //ports
        .rinc     		( rinc     		),
        .rclk     		( rclk     		),
        .rrst_n   		( rrst_n   		),
        .rq2_wptr 		( rq2_wptr 		),
        .rptr     		( rptr     		),
        .raddr    		( raddr    		),
        .rempty   		( rempty   		)
    );


    wptr_full #(
        .ADDRSIZE 		( 4 		))
    u_wptr_full(
        //ports
        .winc     		( winc     		),
        .wclk     		( wclk     		),
        .wrst_n   		( wrst_n   		),
        .wq2_rptr 		( wq2_rptr 		),
        .waddr    		( waddr    		),
        .wptr     		( wptr     		),
        .wfull    		( wfull    		)
    );


    syn_r2w #(
        .ADDRSIZE 		( 4 		))
    u_syn_r2w(
        //ports
        .wclk     		( wclk     		),
        .wrst_n   		( wrst_n   		),
        .rptr     		( rptr     		),
        .wq2_rptr 		( wq2_rptr 		)
    );


    syn_w2r #(
        .ADDRSIZE 		( 4 		))
    u_syn_w2r(
        //ports
        .rclk     		( rclk     		),
        .rrst_n   		( rrst_n   		),
        .wptr     		( wptr     		),
        .rq2_wptr 		( rq2_wptr 		)
    );

    
endmodule

2) FIFO Memory

module fifomem #(
    parameter DATASIZE = 8,
    parameter ADDRSIZE = 4
) (
    input   				wclken, wfull, wclk,
    input   [ADDRSIZE-1:0]  waddr,raddr,
    input   [DATASIZE-1:0]  wdata,
    output  [DATASIZE-1:0]  rdata
);

    localparam DEPTH = 1<<ADDRSIZE;
    reg [DATASIZE-1:0]  mem [0:DEPTH-1];

    assign rdata = mem[raddr];

    always @(posedge wclk) begin
        if(wclken && !wfull)
            mem[waddr]  <= wdata;
    end

endmodule

3) wptr_full

module wptr_full #(
	parameter	ADDRSIZE = 4
)(
	input						winc, wclk, wrst_n,
    input		[ADDRSIZE  :0]	wq2_rptr,
    output		[ADDRSIZE-1:0]	waddr,
    output	reg [ADDRSIZE  :0]	wptr,
    output	reg 				wfull
);
    
    // internal port
    reg		[ADDRSIZE:0]	wbin;
    wire	[ADDRSIZE:0]	wbinnext, wptrnext;
    wire					wfull_val;
    
//----------------------------------------------
// Memory write-address pointer and Gray pointer
//----------------------------------------------
    always @(posedge wclk or negedge wrst_n)begin
        if(!wrst_n)
        	{wbin, wptr} <= 0;
        else
        	{wbin, wptr} <= {wbinnext, wptrnext};
    end
    
    assign waddr = wbin[ADDRSIZE-1:0];
    assign wbinnext = wbin + (winc && !wfull);
    assign wptrnext = (wbinnext>>1) ^ wbinnext;
    
//--------------------------------------------------
// FIFO full when the next wptr == synchronized rptr
//--------------------------------------------------
    always @(posedge wclk or negedge wrst_n)begin
        if(!wrst_n)
            wfull <= 1'b0;
       	else
            wfull <= wfull_val;
    end
    
    assign wfull_val = (wptrnext == {~wq2_rptr[ADDRSIZE:ADDRSIZE-1],wq2_rptr[ADDRSIZE-2:0]});
    
   
endmodule //wptr_full

4) rptr_empty

module rptr_empty #(
	parameter	ADDRSIZE = 4
)(
	input						rinc, rclk, rrst_n,
    input		[ADDRSIZE  :0]	rq2_wptr,
    output		[ADDRSIZE-1:0]	raddr,
    output	reg [ADDRSIZE  :0]	rptr,
    output	reg 				rempty
);
    
    // internal signals
    wire [ADDRSIZE:0]	rbin, rbinnext, rptrnext;
    wire rempty_val;
    
//---------------------------------------------
// Memory read_adderss pointer and Gray pointer
//----------------------------------------------
    always @(posedge rclk or negedge rrst_n) begin
        if(!rrst_n)
        	{rbin, rptr} <= 0;
       	else
        	{rbin, rptr} <= {rbinnext, rptrnext};
    end
    
    assign raddr = rbin[ADDRSIZE-1:0];
    assign rbinnext = rbin + (rbin && !rempty);
    assign rptrnext = (rbinnext>>1) ^ rbinnext;
  
    
//---------------------------------------------------------------
// FIFO empty when the next rptr == synchronized wptr or on reset
//---------------------------------------------------------------
    always @(posedge rclk or negedge rrst_n) begin
        if(!rrst_n)
            rempty <= 1'b1;
        else 
            rempty <= rempty_val;
    end
    
    assign rempty_val = (rptrnext == rq2_wptr);
    

endmodule //rptr_empty

5) sync_r2w

module sync_r2w #(
	parameter	ADDRSIZE = 4
)(
    input						wclk, wrst_n,
    input		[ADDRSIZE:0]	rptr,
    output	reg [ADDRSIZE:0] 	wq2_rptr
);
    
    reg [ADDRSIZE:0] wq1_rptr;
    
    always @(posedge wclk or negedge wrst_n) begin
        if(!wrst_n)
        	{wq2_rptr, wq1_rptr} <= 0;
        else 
        	{wq2_rptr, wq1_rptr} <= {wq1_rptr, rptr};
    end
    
endmodule //sync_r2w

6) sync_w2r

moduel sync_w2r #(
	parameter	ADDRSIZE = 4
)(
	input	rclk, rrst_n,
	intput	[ADDRSIZE:0]	wptr,
	output	[ADDRSIZE:0]	rq2_wptr
);

	reg rq1_wptr;
	
	always @(posedge rclk or negedge rrst_n) begin 
		if(!rrst_n)
			{rq2_wptr, rq1_wptr} <= 0;
		else 
			{rq2_wptr, rq1_wptr} <= {rq1_wptr, wptr};
	end
	
endmodule //sync_w2r

4. Discussions

4.1 Different clock speeds

4.2 Pessimistic full & empty

【参考文献】

​ [1] 郭炜, 魏继增, 郭筝. Soc设计方法与实现(第3版). 电子工业出版社. 2017年

​ [2] Clifford E. Cummings, “Synthesis and Scripting Techniques for Designing Multi-Asynchronous Clock Designs,” SNUG 2001(Synopsys Users Group Conference, San Jose, CA, 2001) User Papers, March 2001, Section MC1, 3rdpaper. Also available at www.sunburst-design.com/papers

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值