跨时钟设计:异步FIFO设计

1、异步fifo
在asic设计或者fpga设计中,我们常常使用异步fifo(first in first out)(下文简称为afifo)进行数据流的跨时钟,可以说没使用过afifo的designer,其设计经历是不完整的。废话不多说,直接上接口信号说明。
2、afifo接口信号说明
如下表格为常见的afifo接口信号,非必须指的部分场景的afifo可能不存在此信号。不同公司对afifo接口的设计可能不一样,但是基本都包含了如下接口:wr表示write,写侧时钟域信号,rd表示read,读侧时钟域信号。
信号名称 位宽 必要性 含义
almost_full 1 非必须 将满信号,1表示afifo快满了,当afifo的有效数量大于配置时,置1
full        1 非必须 afifo满信号,1表示afifo已满
empty       1 非必须 1表示
rd_data     [data_width-1:0] 必须 有效数据
ovf_int     1 非必须 1表示上溢出,即afifo满了还有数据写入
udf_int     1 非必须 1表示下溢出,即afifo空了外部逻辑还产生了读使能
data_count [addr_width:0]   非必须 afifo存储的数据量
cfg_almost_full_value [addr_width:0]  非必须 将满配置信号,一般由配置寄存器模块提供驱动
wr_rst_n             1 必须 写侧复位
wr_clk               1 必须 写侧时钟
wr_en                1 必须 写使能,1表示有数据写入
wr_data              [data_width-1:0] 必须 写数据
rd_rst_n             1 必须 读时钟与复位
rd_clk               1 必须 读时钟
rd_en                1 必须 读使能
3、设计原理   
为了方便描述,本章节将以深度为8的afifo进行讲解,其中读写地址位宽为3,格雷码地址位宽为4。
图1 afifo结构图(来自eetop thinkspark)
图2:读写地址计算图
(1)存储模块:
中间区域为memory存储模块,用于存储数据data,要么是1r1w的ram,要么是普通的寄存器。项目自研代码中,存储模块通常使用1r1w的ram,其需要memory生成器生成,需要与制造工艺匹配。而在soft ip中,针对小规格的afifo,为了方便,常常使用寄存器作为afifo的存储。
(2)写地址产生逻辑
写地址waddr在wr_clk时钟域产生,有两个作用,作为存储模块的写地址并且产生格雷码waddr_gray。此种需要注意:waddr是递增的,且会翻转。如果afifo深度为8(n),则waddr位宽为3(log2(n) ),waddr计数到7后,再次写入则翻转为0。
(3)读地址产生逻辑
读地址raddr在rd_clk时钟域产生,有两个作用,作为存储模块的读地址并且产生格雷码raddr_gray。此种需要注意:raddr是递增的,且会翻转。如果afifo深度为8(n),则raddr位宽为3(log2(n) ),raddr计数到7后,再次读出则翻转为0。
(4)读地址同步
使用2级或者3级单bit同步器synchronizer将读地址格雷码raddr_gray同步到wr_clk时钟域得到raddr_gray_sync,raddr_gray_sync进行格雷码逆转成二进制编码得到raddr_sync,用于产生将满信号和满信号。
在fpga设计中,2级单bit同步器synchronizer就是2个串联的寄存器,在asic设计中,通常是定制的cell(会将两个/三个寄存器摆放靠得很近)。
(5)写地址同步器
使用2级或者3级单bit同步器synchronizer将写地址格雷码waddr_gray同步到rd_clk时钟域得到waddr_gray_sync,waddr_gray_sync进行格雷码逆转成二进制编码得到waddr_sync,用于产生将空信号和空信号。
(6)满信号产生逻辑
此模块首先计算在wr_clk时钟域的剩余可写afifo深度,即wr_gap[3:0]=raddr_sync[2:0]+4’d8(fifo深度)-waddr[2:0],然后根据wr_gap[3:0]产生amost_full和full信号
always @(posedge wr_clk or negedge wr_rst_n) if(~wr_rst_n) full <= 1'b0; else full <= (!(|wr_gap)) || ((wr_gap==1)&wr_en);always @(posedge wr_clk or negedge wr_rst_n) if(~wr_rst_n) begin almost_full =cfg_almost_full_value ) almost_full <= 1'b1; else almost_full <= almost_full; end  
(7)空信号产生逻辑
此模块首先计算在rd_clk时钟域的可读afifo深度,即assign  {ovf_nc1,rd_gap} = waddr_sync - raddr,然后根据rd_gap[3:0]产生empty信号。
always @(posedge rd_clk or negedge rd_rst_n) if(~rd_rst_n) empty <= 1'b1; else empty <= (!(|rd_gap)) || ((rd_gap==1)&rd_en);           
4、重点说明
(1)格雷码的优势
格雷码的特点就是在递增,递减,或者翻转过程中,只会有1个bit位发生变化。因此单bit同步器synchronizer同步后,只有存在变化的那一个bit可能会发生亚稳态。即使发生了亚稳态,体现的结果要么是0,要么是1,在格雷码上的同步效果就是当前clk周期没有同步(相当于delay了一个目的周期)到或者当前周期已采样到。
同时它也有自己的局限性,那就是循环计数深度必须是2的n次幂(也可以不是2的n次幂哦),否则就失去了每次只变化一位的特性。深度为16的二进制及格雷码递变表如下:
binary                 gray
0          0000                  0000
1          0001                  0001
2          0010                  0011
3          0011                  0010
4          0100                  0110
5          0101                  0111
6          0110                  0101
7          0111                  0100
8          1000                  1100
9          1001                  1101
10         1010                  1111
11         1011                  1110
12         1100                  1010
13         1101                  1011
14         1110                  1001
15         1111                  1000
0          0000                  0000  
(2)空信号计算方法的妙处
在rd_clk时钟域计算可读数据量以及empty信号,看图2会发现,实际rd_gap永远小于等于真实可读数据量,能够保证empty为0时永远不会发生空读现象,即afifo没有数据,也进行了读操作。
(3)满信号计算方法的妙处
在wd_clk时钟域计算可写数据量以及full信号,看图2会发现,实际wr_gap永远小于等于真实可写数据量,能够保证full为0时永远不会发生写溢出现象,即full为0时,afifo可能存在空闲位置。
(4)格雷码转二进制代码
function [addr_width:0] gray2bin; //to change the gray code to bin code input [addr_width:0] gray_in; //input gray code reg [addr_width:0] gray_code; //reg gray reg [addr_width:0] bin_code; //bin code result integer i,j; //integer reg tmp; //tmp begin gray_code = gray_in; for(i=0;i<=addr_width;i=i+1) begin tmp=1'b0; for(j=i;j<=addr_width;j=j+1) tmp=gray_code[j]^tmp; bin_code[i]=tmp; end gray2bin= bin_code; endendfunction  
(5)二进制转格雷码
always @(posedge rd_clk or negedge rd_rst_n) if(~rd_rst_n) raddr_gray <= {(addr_width + 1){1'b0}}; else raddr_gray <= raddr ^ {1'b0,raddr[addr_width:1]};  
5、结束语
 afifo代码写出来还不够,还需要设置约束条件,后期我们会再讲讲afifo的格雷码如何约束。


电源管理“新创企业”英麦科专注高附加值数字模拟单芯片
基于几何分析的神经辐射场编辑方法
广东禅城今年计划建成充电站9座和各类充电桩489支
高通收购恩智浦为什么如此艰难?
为什么要进行无功补偿_无功补偿的意义
跨时钟设计:异步FIFO设计
手机销量暴降,这家厂商为何还要投入1000亿研发
iPhone8什么时候上市?iPhone8最新消息:iPhone8外观、配置、价格全面提升,iPhone8五大变化汇总很期待
三星推出随享系列智能投影仪_希捷助力CyArk实现数字化转型
用Arduino做一个自动割草机
石墨烯将作为OLED水氧阻隔层
Q3季度康宁实现营收30亿美元,推出了面向5G的连接方案-Evolv
单触发脉冲发生器LTC6993
Python3如何把图片复制到剪贴板
国家电网建12万充电桩 亲力亲为助力新能源汽车发展
5G网络建设逐渐完善,自动驾驶产业正不断驶入快车道
保时捷制定未来电气化发展路线 预计2022年投资60亿欧元
“5G全场景数字化展示平台”究竟有什么特别?
Vishay推出基于VCSEL的新型反射式光传感器
联想在台要冲市场占有率要稳住前五大品牌位置