异步FIFO设计

本文首发于个人博客

1.设计目标

设计一个参数可配置的异步FIFO,要求:

  • FIFO深度从4开始在2的幂次方连续可配(4、8、16、......)
  • 读写时钟域相位差、频率差任意(同步器参数可配)

2.参数列表

名称 默认值 说明
DEPTH_LOG 4 FIFO容量为2^{DEPTH\_LOG}
DATA_WIDTH 8 数据位宽

3.端口

3.1.端口列表

3.1.1.系统端口

名称 类型 位宽 说明
read_clk input 1 读时钟域时钟
write_clk input 1 写时钟域时钟
rst_n input 1 系统复位端口,低有效

3.1.2.读端口

名称 类型 位宽 说明
read_req input 1 读完成信号
read_valid output 1 读数据有效信号
read_data output DEPTH_LOG 读数据
fifo_empty output 1 FIFO空信号

3.1.3.写端口

名称 类型 位宽 说明
write_req input 1 写请求信号
write_data input DEPTH_LOG 写数据
fifo_full output 1 FIFO满信号

3.2.端口时序

3.2.1.读端口时序

read_port.png

read_req信号拉高表示请求读数据,若此时FIFO非空(fifo_empty为低),FIFO将会将数据置于read_data上,同时拉高read_valid信号。即当read_valid有效时,对应的read_data上的数据有效。fifo_empty拉高表示FIFO已空,当前数据输出端口上的数据无意义, 再拉高read_req将不会改变read_data上的数据。

3.2.2.写端口时序

write_port.png

写端口如上所示,当且仅当write_req信号高且fifo_full信号低时将write_data端口上的数据写入FIFO。

4.系统结构

4.1.结构框图

structure.png

系统整体结构如上所示,分为两个时钟域——读时钟域和写时钟域。每个时钟域结构相互镜像:

  • 读/写指针:二进制的读写指针,用于SRAM的读/写地址
  • 二进制到格雷码转换器:将读/写指针从二进制转为格雷码,用于传递到下一个时钟域或生产空\满信号
  • 空/满信号生成:比对读指针和写指针的格雷码,生成空和满信号

其他还有跨时钟域的组件,分别为:

  • 双口SRAM:一个端口使用写时钟和写时钟域下的信号,另一个使用读时钟和读时钟域的信号
  • 同步器:两个同步器,分别将读指针同步到写时钟域和将写时钟同步到读时钟域

4.2.系统方法

4.2.1.二进制转格雷码

假设二进制码为每位为bin[n],对应的格雷码每位为gray[n],共N位,转换算法为:
\begin{cases} gray[N-1] = bin[N - 1] \\ gray[i] = bin[i] \ NOR \ bin[i+1] & i < N-1 \end{cases}
例如二进制码011,共3位,则格雷码第2位为0,其他几位为10,对应格雷码为010,在具体实现时,可以参考下图的实现方法:

bin2gray.png

4.2.2.格雷码判空判满

对读指针和写指针有以下含义:

  • 读指针:指向当前正在读的地址
  • 写指针:指向下一次写入操作需要写入的地址

二进制下,对于地址位宽为N的SRAM,可以使用位宽为N+1的地址——低N位为地址,MSB为标志位,用于标记满和空:

  • 当低N位相等,MSB不相等时:FIFO满(写指针领先读指针“一圈”)
  • 当低N为相等,MSB相等时:FIFO空(读指针“追上”写指针)

转换到格雷码域,做相同判断,判空条件为两个指针相等,相等的二进制码对应格雷码相等,条件不变。对于判满,需要两个二进制仅有最高位不同,参考二进制转格雷码条件,判满条件如下:

  • 最高位不相等(格雷码MSB与二进制MSB相同)
  • 次高位不相等(次高位由二进制码的最高位和次高位异或,两指针二进制下最高位不同,次高位相同)
  • 其他位均相等(异或操作依赖的位数均相等)

由于同步器的同步需要消耗时钟周期,因此:

  • 判满:在写时钟域下生成满信号,读指针通过同步器,为若干个时钟周期之前的读指针。若在FIFO满的情况下,读操作发生,读指针的变化延迟传递到写时钟域,在传递的若干个周期内状态为“假满”
  • 判空:在读时钟域下生成空信号,写指针通过同步器,为若干个时钟周期之前的写指针。若在FIFO空的情况下,写操作发生,写指针的变化延迟传递到读时钟域,在传递的若干个周期内状态为“假空”

“假满”和“假空”状态均不影响异步FIFO的正常工作,仅为略微降低FIFO的工作效率

4.2.3.同步器

同步器是一种跨时钟域数据传输的方法,二级同步器结构如下所示:

synchronizer.png

从源时钟域下的源信号开始,依次通过多个时钟为目标时钟域时钟下的寄存器,即构成了多级同步器,寄存器的数量就是同步器的级数。一般的信号仅需要二级同步器,高速信号一般使用三级同步器。

5.实现细节

5.1.写FIFO部分

写FIFO部分包括以下几个组件:

  • 同步器:将读指针从读时钟域同步到写时钟域,使用两级同步器
  • 写指针:指示写入地址的指针,当满信号拉低且写请求拉高时加1
  • 写指针二进制转格雷码:将写指针从二进制转为格雷码,送到判满部分判满和向读时钟域的同步器
  • 满信号生成:当满足[4.2.2]的判满条件成立时,拉高满信号

5.1.1.需求

写FIFO部分的需求如下:

  • 产生写SRAM的相关信号,包括写请求信号,写地址信号和写数据信号
  • 同步内部读指针,配合写指针生成满信号。将写指针传递到读部分。

5.1.2.端口

名称 类型 位宽 说明
clk input 1 写部分时钟
rst_n input 1 系统复位
write_req input 1 写FIFO请求
fifo_full output 1 FIFO满信号
write_addr output DEPTH_LOG 写存储器地址
read_point_gray input DEPTH_LOG+1 读指针格雷码,未同步
write_point_gray output DEPTH_LOG+1 写指针格雷码

5.1.3.实现

write_control.png

上图为fifo_full生成部分的结构图,为了保证保证fifo_full拉高的及时性,设置next_write_point_gray寄存器,指示下一个格雷码的写地址。当一次is_write拉高时,每个部件的功能如下所示:

  • write_point:自增1
  • write_point_gray:从next_write_point_gray获取与write_point同步的格雷码
  • next_write_point_gray:取现在write_point加2后对应的格雷码,获得与write_point+1同步的格雷码

写产生FIFO满的波形如下所示:

full_gen.png

当一次写请求使FIFO满时,由于写请求发生,因此使用next_write_point_gray进行判满操作,此时该信号与read_point_gray相等,因此在下一个时钟周期fifo_full拉高(图中a,b->c),同时,write_pointwrite_point_gray均完成更新。下一个时钟周期,无写请求发生,因此使用write_point_gray进行判满操作,此时write_point_gray更新后与read_point_gray相等,保持fifo满状态(图中e,d->f)。

对于数据部分,如下图所示:

write_data.png

该部分不包括在写控制模块中,系统输入的write_data端口直接连接到SRAM的写数据端口,写请求端口为write_reqfifo_full的组合逻辑与信号(write_req && !fifo_full

5.2.读FIFO部分

读FIFO部分包括以下几个组件:

  • 同步器:将写指针从写时钟域同步到读时钟域,使用两级同步器
  • 读指针:指示读取地址的指针,当空信号拉低且读请求拉高时加1
  • 读指针二进制转格雷码:将读指针从二进制转为格雷码,送到判空部分判空和向写时钟域的同步器
  • 空信号生成:当满足[4.2.2]的判空条件成立时,拉高空信号

5.2.1.需求

读FIFO部分需要满足以下几个需求:

  • 产生读SRAM的相关信号,包括地址信号,数据有效信号
  • 同步内部写指针,配合读指针生成空信号。将读指针传递到读部分。

5.2.2.端口

名称 类型 位宽 说明
clk input 1 读时钟信号
rst_n input 1 系统复位信号,低有效
read_req input 1 读请求信号
fifo_empty output 1 FIFO空信号
memory_read_addr output DEPTH_LOG SRAM的读地址信号
read_point_gray output DEPTH_LOG+1 读指针格雷码
write_point_gray input DEPTH_LOG+1 写指针格雷码,未同步
read_valid output 1 读数据有效信号

5.2.3.实现

实现的方式与写部分类似,fifo_empty信号和读指针生成如下所示:

read_control.png

主要部件的功能如下所示:

  • read_point:读指针,产生读地址,每当读请求成立时自增1
  • read_point_gray:读指针的格雷码,用于产生空逻辑和向写时钟域传递
  • next_read_point_gray:下一个读指针的格雷码,用于空信号的及时性
read_data.png

读数据部分如上图所示,read_valid信号在read_req && !fifo_empty为真时拉高,表示当前read_data上的数据有效。read_data为输出数据端口直接连接到SRAM的输出端口(SRAM输出端口自带寄存器)。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容