fifo的rdata_同步Fifo和异步fifo
这一种设计的FIFO,是基于触发器的。宽度,深度的扩展更加方便,结构化跟强。以下代码在modelsim中验证过。
modulefifo_cell(sys_clk,sys_rst_n,read_fifo,write_fifo,fifo_input_data,
next_cell_data,next_cell_full,last_cell_full,cell_data_out,cell_full);
parameterWIDTH=8;
parameterD=2;
inputsys_clk;
inputsys_rst_n;
inputread_fifo,write_fifo;
input[WIDTH-1:0]fifo_input_data;
input[WIDTH-1:0]next_cell_data;
inputnext_cell_full,last_cell_full;
output[WIDTH-1:0]cell_data_out;
outputcell_full;
reg[WIDTH-1:0]cell_data_reg_array;
reg[WIDTH-1:0]cell_data_ld;
regcell_data_ld_en;
regcell_full;
regcell_full_next;
assigncell_data_out=cell_data_reg_array;
always@(posedgesys_clkornegedgesys_rst_n)
if(!sys_rst_n)
cell_full<=#D0;
elseif(read_fifo||write_fifo)
cell_full<=#Dcell_full_next;
always@(write_fifoorread_fifoornext_cell_fullorlast_cell_fullorcell_full)
casex({read_fifo,write_fifo})
2'b00:cell_full_next=cell_full;
2'b01:cell_full_next=next_cell_full;
2'b10:cell_full_next=last_cell_full;
2'b11:cell_full_next=cell_full;
endcase
always@(posedgesys_clkornegedgesys_rst_n)
if(!sys_rst_n)
cell_data_reg_array[WIDTH-1:0]<=#D0;
elseif(cell_data_ld_en)
cell_data_reg_array[WIDTH-1:0]<=#Dcell_data_ld[WIDTH-1:0];
always@(write_fifoorread_fifoorcell_fullorlast_cell_full)
casex({write_fifo,read_fifo,cell_full,last_cell_full})
4'bx1_xx:cell_data_ld_en=1'b1;
4'b10_01:cell_data_ld_en=1'b1;
default:cell_data_ld_en=1'b0;
endcase
always@(write_fifoorread_fifoornext_cell_fullorcell_fullorlast_cell_fullorfifo_input_dataornext_cell_data)
casex({write_fifo,read_fifo,next_cell_full,cell_full,last_cell_full})
5'b10_x01:cell_data_ld[WIDTH-1:0]=fifo_input_data[WIDTH-1:0];
5'b11_01x:cell_data_ld[WIDTH-1:0]=fifo_input_data[WIDTH-1:0];
default:cell_data_ld[WIDTH-1:0]=next_cell_data[WIDTH-1:0];
endcase
endmodule
modulefifo_4cell(sys_clk,sys_rst_n,fifo_input_data,write_fifo,fifo_out_data,
read_fifo,full_cell0,full_cell1,full_cell2,full_cell3);
parameterWIDTH=8;
parameterD=2;
inputsys_clk;
inputsys_rst_n;
input[WIDTH-1:0]fifo_input_data;
output[WIDTH-1:0]fifo_out_data;
inputread_fifo,write_fifo;
outputfull_cell0,full_cell1,full_cell2,full_cell3;
wire[WIDTH-1:0]dara_out_cell0,data_out_cell1,data_out_cell2,
data_out_cell3,data_out_cell4;
wirefull_cell4;
fifo_cell#(WIDTH,D)cell0
(.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.fifo_input_data(fifo_input_data[WIDTH-1:0]),
.write_fifo(write_fifo),
.next_cell_data(data_out_cell1[WIDTH-1:0]),
.next_cell_full(full_cell1),
.last_cell_full(1'b1),
.cell_data_out(fifo_out_data[WIDTH-1:0]),
.read_fifo(read_fifo),
.cell_full(full_cell0)
);
fifo_cell#(WIDTH,D)cell1
(.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.fifo_input_data(fifo_input_data[WIDTH-1:0]),
.write_fifo(write_fifo),
.next_cell_data(data_out_cell2[WIDTH-1:0]),
.next_cell_full(full_cell2),
.last_cell_full(full_cell0),
.cell_data_out(data_out_cell1[WIDTH-1:0]),
.read_fifo(read_fifo),
.cell_full(full_cell1)
);
fifo_cell#(WIDTH,D)cell2
(.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.fifo_input_data(fifo_input_data[WIDTH-1:0]),
.write_fifo(write_fifo),
.next_cell_data(data_out_cell3[WIDTH-1:0]),
.next_cell_full(full_cell3),
.last_cell_full(full_cell1),
.cell_data_out(data_out_cell2[WIDTH-1:0]),
.read_fifo(read_fifo),
.cell_full(full_cell2)
);
fifo_cell#(WIDTH,D)cell3
(.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.fifo_input_data(fifo_input_data[WIDTH-1:0]),
.write_fifo(write_fifo),
.next_cell_data(data_out_cell4[WIDTH-1:0]),
.next_cell_full(full_cell4),
.last_cell_full(full_cell2),
.cell_data_out(data_out_cell3[WIDTH-1:0]),
.read_fifo(read_fifo),
.cell_full(full_cell3)
);
assigndata_out_cell4[WIDTH-1:0]={WIDTH{1'B0}};
assignfull_cell4=1'b0;
endmodule
..........................................................................................................................
异步FIFO的Verilog代码之一
这个是基于RAM的异步FIFO代码,个人认为代码结构简单易懂,非常适合于考试中填写。记得10月份参加威盛的笔试的时候,就考过异步FIFO的实现。想当初要是早点复习,可能就可以通过威盛的笔试了。
与之前的用RAM实现的同步FIFO的程序相比,异步更为复杂。增加了读写控制信号的跨时钟域的同步。此外,判空与判满的也稍有不同。
modulefifo1(rdata,wfull,rempty,wdata,winc,wclk,wrst_n,rinc,rclk,rrst_n);
parameterDSIZE=8;parameterASIZE=4;
output[DSIZE-1:0]rdata;
outputwfull;
outputrempty;
input[DSIZE-1:0]wdata;
inputwinc,wclk,wrst_n;
inputrinc,rclk,rrst_n;
regwfull,rempty;
reg[ASIZE:0]wptr,rptr,wq2_rptr,rq2_wptr,wq1_rptr,rq1_wptr;
reg[ASIZE:0]rbin,wbin;
reg[DSIZE-1:0]mem[0:(1<
wire[ASIZE-1:0]waddr,raddr;
wire[ASIZE:0]rgraynext,rbinnext,wgraynext,wbinnext;
wirerempty_val,wfull_val;
//-----------------双口RAM存储器--------------------
assignrdata=mem[raddr];
always@(posedgewclk)
if(winc&&!wfull)mem[waddr]<=wdata;
//-------------同步rptr指针-------------------------
always@(posedgewclkornegedgewrst_n)
if(!wrst_n){wq2_rptr,wq1_rptr}<=0;
else{wq2_rptr,wq1_rptr}<={wq1_rptr,rptr};
//-------------同步wptr指针---------------------------
always@(posedgerclkornegedgerrst_n)
if(!rrst_n){rq2_wptr,rq1_wptr}<=0;
else{rq2_wptr,rq1_wptr}<={rq1_wptr,wptr};
//-------------rempty产生与raddr产生-------------------
always@(posedgerclkornegedgerrst_n)//GRAYSTYLE2pointer
begin
if(!rrst_n){rbin,rptr}<=0;
else{rbin,rptr}<={rbinnext,rgraynext};
end
//Memoryread-addresspointer(okaytousebinarytoaddressmemory)
assignraddr=rbin[ASIZE-1:0];
assignrbinnext=rbin+(rinc&~rempty);
assignrgraynext=(rbinnext>>1)^rbinnext;
//FIFOemptywhenthenextrptr==synchronizedwptroronreset
assignrempty_val=(rgraynext==rq2_wptr);
always@(posedgerclkornegedgerrst_n)
begin
if(!rrst_n)rempty<=1'b1;
elserempty<=rempty_val;
end
//---------------wfull产生与waddr产生------------------------------
always@(posedgewclkornegedgewrst_n)//GRAYSTYLE2pointer
if(!wrst_n){wbin,wptr}<=0;
else{wbin,wptr}<={wbinnext,wgraynext};
//Memorywrite-addresspointer(okaytousebinarytoaddressmemory)
assignwaddr=wbin[ASIZE-1:0];
assignwbinnext=wbin+(winc&~wfull);
assignwgraynext=(wbinnext>>1)^wbinnext;
assignwfull_val=(wgraynext=={~wq2_rptr[ASIZE:ASIZE-1],wq2_rptr[ASIZE-2:0]});//:ASIZE-1]
always@(posedgewclkornegedgewrst_n)
if(!wrst_n)wfull<=1'b0;
elsewfull<=wfull_val;
endmodule
..........................................................................................................................
异步FIFO的Verilog代码之二
与前一段异步FIFO代码的主要区别在于,空/满状态标志的不同算法。
第一个算法:CliffordE.Cummings的文章中提到的STYLE#1,构造一个指针宽度为N+1,深度为2^N字节的FIFO(为便方比较将格雷码指针转换为二进制指针)。当指针的二进制码中最高位不一致而其它N位都相等时,FIFO为满(在CliffordE.Cummings的文章中以格雷码表示是前两位均不相同,而后两位LSB相同为满,这与换成二进制表示的MSB不同其他相同为满是一样的)。当指针完全相等时,FIFO为空。
这种方法思路非常明了,为了比较不同时钟产生的指针,需要把不同时钟域的信号同步到本时钟域中来,而使用Gray码的目的就是使这个异步同步化的过程发生亚稳态的机率最小,而为什么要构造一个N+1的指针,CliffordE.Cummings也阐述的很明白,有兴趣的读者可以看下作者原文是怎么论述的,CliffordE.Cummings的这篇文章有Rev1.1\Rev1.2两个版本,两者在比较Gray码指针时的方法略有不同,个Rev1.2版更为精简。
第二种算法:CliffordE.Cummings的文章中提到的STYLE#2。它将FIFO地址分成了4部分,每部分分别用高两位的MSB00、01、11、10决定FIFO是否为goingfull或goingempty(即将满或空)。如果写指针的高两位MSB小于读指针的高两位MSB则FIFO为“几乎满”,若写指针的高两位MSB大于读指针的高两位MSB则FIFO为“几乎空”。
它是利用将地址空间分成4个象限(也就是四个等大小的区域),然后观察两个指针的相对位置,如果写指针落后读指针一个象限(25%的距离,呵呵),则证明很可能要写满,反之则很可能要读空,这个时候分别设置两个标志位dirset和dirrst,然后在地址完全相等的情况下,如果dirset有效就是写满,如果dirrst有效就是读空。
这种方法对深度为2^N字节的FIFO只需N位的指针即可,处理的速度也较第一种方法快。
这段是说明的原话,算法一,还好理解。算法二,似乎没有说清楚,不太明白。有兴趣的可以查查论文,详细研究下。
总之,第二种写法是推荐的写法。因为异步的多时钟设计应按以下几个原则进行设计:
1,尽可能的将多时钟的逻辑电路(非同步器)分割为多个单时钟的模块,这样有利于静态时序分析工具来进行时序验证。
2,同步器的实现应使得所有输入来自同一个时钟域,而使用另一个时钟域的异步时钟信号采样数据。
3,面向时钟信号的命名方式可以帮助我们确定那些在不同异步时钟域间需要处理的信号。
4,当存在多个跨时钟域的控制信号时,我们必须特别注意这些信号,保证这些控制信号到达新的时钟域仍然能够保持正确的顺序。
modulefifo2(rdata,wfull,rempty,wdata,
winc,wclk,wrst_n,rinc,rclk,rrst_n);
parameterDSIZE=8;
parameterASIZE=4;
output[DSIZE-1:0]rdata;
outputwfull;
outputrempty;
input[DSIZE-1:0]wdata;
inputwinc,wclk,wrst_n;
inputrinc,rclk,rrst_n;
wire[ASIZE-1:0]wptr,rptr;
wire[ASIZE-1:0]waddr,raddr;
async_cmp#(ASIZE)async_cmp(.aempty_n(aempty_n),
.afull_n(afull_n),
.wptr(wptr),.rptr(rptr),
.wrst_n(wrst_n));
fifomem2#(DSIZE,ASIZE)fifomem2(.rdata(rdata),
.wdata(wdata),
.waddr(wptr),
.raddr(rptr),
.wclken(winc),
.wclk(wclk));
rptr_empty2#(ASIZE)rptr_empty2(.rempty(rempty),
.rptr(rptr),
.aempty_n(aempty_n),
.rinc(rinc),
.rclk(rclk),
.rrst_n(rrst_n));
wptr_full2#(ASIZE)wptr_full2(.wfull(wfull),
.wptr(wptr),
.afull_n(afull_n),
.winc(winc),
.wclk(wclk),
.wrst_n(wrst_n));
endmodule
modulefifomem2(rdata,wdata,waddr,raddr,wclken,wclk);
parameterDATASIZE=8;//Memorydatawordwidth
parameterADDRSIZE=4;//Numberofmemoryaddressbits
parameterDEPTH=1<
output[DATASIZE-1:0]rdata;
input[DATASIZE-1:0]wdata;
input[ADDRSIZE-1:0]waddr,raddr;
inputwclken,wclk;
`ifdefVENDORRAM
//instantiationofavendor'sdual-portRAM
VENDOR_RAMMEM(.dout(rdata),.din(wdata),
.waddr(waddr),.raddr(raddr),
.wclken(wclken),.clk(wclk));
`else
reg[DATASIZE-1:0]MEM[0:DEPTH-1];
assignrdata=MEM[raddr];
always@(posedgewclk)
if(wclken)MEM[waddr]<=wdata;
`endif
endmodule
moduleasync_cmp(aempty_n,afull_n,wptr,rptr,wrst_n);
parameterADDRSIZE=4;
parameterN=ADDRSIZE-1;
outputaempty_n,afull_n;
input[N:0]wptr,rptr;
inputwrst_n;
regdirection;
wirehigh=1'b1;
wiredirset_n=~((wptr[N]^rptr[N-1])&~(wptr[N-1]^rptr[N]));
wiredirclr_n=~((~(wptr[N]^rptr[N-1])&(wptr[N-1]^rptr[N]))|
~wrst_n);
always@(posedgehighornegedgedirset_nornegedgedirclr_n)
if(!dirclr_n)direction<=1'b0;
elseif(!dirset_n)direction<=1'b1;
elsedirection<=high;
//always@(negedgedirset_nornegedgedirclr_n)
//if(!dirclr_n)direction<=1'b0;
//elsedirection<=1'b1;
assignaempty_n=~((wptr==rptr)&&!direction);
assignafull_n=~((wptr==rptr)&&direction);
endmodule
modulerptr_empty2(rempty,rptr,aempty_n,rinc,rclk,rrst_n);
parameterADDRSIZE=4;
outputrempty;
output[ADDRSIZE-1:0]rptr;
inputaempty_n;
inputrinc,rclk,rrst_n;
reg[ADDRSIZE-1:0]rptr,rbin;
regrempty,rempty2;
wire[ADDRSIZE-1:0]rgnext,rbnext;
//---------------------------------------------------------------
//GRAYSTYLE2pointer
//---------------------------------------------------------------
always@(posedgerclkornegedgerrst_n)
if(!rrst_n)begin
rbin<=0;
rptr<=0;
end
elsebegin
rbin<=rbnext;
rptr<=rgnext;
end
//---------------------------------------------------------------
//incrementthebinarycountifnotempty
//---------------------------------------------------------------
assignrbnext=!rempty?rbin+rinc:rbin;
assignrgnext=(rbnext>>1)^rbnext;//binary-to-grayconversion
always@(posedgerclkornegedgeaempty_n)
if(!aempty_n){rempty,rempty2}<=2'b11;
else{rempty,rempty2}<={rempty2,~aempty_n};
endmodule
modulewptr_full2(wfull,wptr,afull_n,winc,wclk,wrst_n);
parameterADDRSIZE=4;
outputwfull;
output[ADDRSIZE-1:0]wptr;
inputafull_n;
inputwinc,wclk,wrst_n;
reg[ADDRSIZE-1:0]wptr,wbin;
regwfull,wfull2;
wire[ADDRSIZE-1:0]wgnext,wbnext;
//---------------------------------------------------------------
//GRAYSTYLE2pointer
//---------------------------------------------------------------
always@(posedgewclkornegedgewrst_n)
if(!wrst_n)begin
wbin<=0;
wptr<=0;
end
elsebegin
wbin<=wbnext;
wptr<=wgnext;
end
//---------------------------------------------------------------
//incrementthebinarycountifnotfull
//---------------------------------------------------------------
assignwbnext=!wfull?wbin+winc:wbin;
assignwgnext=(wbnext>>1)^wbnext;//binary-to-grayconversion
always@(posedgewclkornegedgewrst_nornegedgeafull_n)
if(!wrst_n){wfull,wfull2}<=2'b00;
elseif(!afull_n){wfull,wfull2}<=2'b11;
else{wfull,wfull2}<={wfull2,~afull_n};
endmodule
fifo的rdata_同步Fifo和异步fifo相关推荐
- fifo的rdata_同步FIFO设计
本文从微信公众号--数字IC小站,转载,欢迎关注,微信公众号更新更多更快带选通信号的同步FIFO(重发)mp.weixin.qq.com 我们常见的同步FIFO一般都是固定位宽输入,固定位宽输出 ...
- 异步FIFO的设计详解(格雷码计数+两级DFF同步)
文章目录 一.异步FIFO介绍 1.1.空满判断 1.2.跨时钟域问题 1.3.格雷码转换 1.4.格雷码计数器 二.代码code 一.异步FIFO介绍 FIFO有同步和异步两种,同步即读写时钟相 ...
- 同步FIFO和异步FIFO总结
文章目录 1. FIFO简介 2. 使用场景 3. 分类 4. FIFO的常见参数 5. FIFO设计 5.1 空满标志生成 5.2 异步FIFO的设计还要注意跨时钟域问题 5.3 gray码如何判断 ...
- 【FPGA——基础篇】同步FIFO与异步FIFO——Verilog实现
FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据, 其 ...
- FPGA逻辑设计回顾(6)多比特信号的CDC处理方式之异步FIFO
文章目录 前言 异步FIFO的概念 异步FIFO为什么可以解决CDC问题? 异步FIFO的RTL实现 参考资料 前言 异步FIFO是处理多比特信号跨时钟域的最常用方法,简单来说,异步FIFO是双口RA ...
- 【FPGA学习记录1】异步FIFO的介绍
文章目录 写在前面 1.FIFO的定义以及为什么要用FIFO.FIFO的分类 1.1什么是FIFO 1.2为什么要用FIFO 1.3FIFO的分类 2.异步FIFO的工作原理 2.1FIFO的结构 2 ...
- 计算异步FIFO的最小深度
计算异步FIFO的最小深度 转:https://blog.csdn.net/qq_26652069/article/details/90720568 目录 1. 异步FIFO最小深度计算 1.1 异 ...
- Xlinx异步FIFO的注意点
Xlinx异步FIFO的大坑 背景及意义 注意点 总结 背景及意义 FIFO是FPGA处理跨时钟和数据缓存的必要IP,可以这么说,只要是任意一个成熟的FPGA涉及,一定会涉及到FIFO.但是我在使用异 ...
- FPGA基础知识极简教程(4)从FIFO设计讲起之异步FIFO篇
博文目录 写在前面 正文 同步FIFO回顾 $clog2()系统函数使用 综合属性控制资源使用 异步FIFO设计 FIFO用途回顾 异步FIFO原理回顾 异步FIFO设计 异步FIFO仿真 参考资料 ...
- 02【Verilog实战】异步FIFO设计(附源码RTL/TB)
脚 本:makefile 工 具:vcs 和 verdi 文 章:1. 同步FIFO的设计和功能验证(附源码) 2. Verilog的亚稳态现象和跨时钟域处理方法 写在前面 这个专栏的内容记录 ...
最新文章
- IDEA新建springboot项目发生错误
- 菜鸟成长之路05/06/07
- logging ,re 模块
- 【Java】6.3 类成员
- SQLServer 游标简介与使用说明[转]
- 实力打脸: 量子隐形传输与 “瞬间移动” 毫无关系
- [摘]全文检索引擎Solr系列—–全文检索基本原理
- 宋志平:麻省理工创新体系带给我的3个思考
- 21世纪商业运作平台:云计算(Cloud Computing)
- :https web服务器ssl认证项目,Https自定义证书引入问题(2)
- Micmac摄影测量软件介绍
- EDI 电子数据交换(Electronic data interchange,缩写EDI)
- Python使用wordcloud词云库——中文乱码
- java中合并不同子目录下的txt文件(CHM转换成txt的过程)
- IOS5短信拦截怎么实现?
- 思科模拟器CISCO/华为模拟器ENSP配置一个完整的校园网(网络安全、数据冗余)
- 搜索引擎常用技巧——英文资料篇
- 实验记录二 示例程序
- fsolve matlab 含参_fsolve 解有参数的多个方程
- java 打分系统_java学生日常评分管理系统
热门文章
- [深度学习项目] - 时间序列预测 (2)
- 经纬度坐标转换的方法
- 基于java的小额支付管理平台
- Java instead of 用法_实例讲解instance of 运算符用法
- 魔法表格(MagicTable)入门教程--CAD转Excel、CAD多个表格批量转Excel
- excel合并工作簿怎么做?
- 软件测试基本流程【车机测试】
- 健康生活 - 四季水果参考
- win10无线网 服务器,win10专业版wifi变成地球怎么办_win10 wifi图标变成小地球无法连接网络如何解决...
- HTML 后台管理页面布局