异步FIFO设计Word文件下载.docx
《异步FIFO设计Word文件下载.docx》由会员分享,可在线阅读,更多相关《异步FIFO设计Word文件下载.docx(15页珍藏版)》请在冰点文库上搜索。
满标志:
FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出。
空标志:
FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出。
读时钟:
读操作所遵循的时钟,在每个时钟沿来临时读数据。
写时钟:
写操作所遵循的时钟,在每个时钟沿来临时写数据。
读指针:
指向下一个读出地址。
读完后自动加1。
写指针:
指向下一个要写入的地址的,写完自动加1。
读写指针其实就是读写memory的地址,只不过这个地址不能任意选择,而是连续的。
1.3FIFO的设计原理
整体的框图如下:
图1.1FIFO的整体电路图
1.3.1FIFO的读写指针
FIFO可以看成是先进新出的缓冲区,它不像普通的存储器那样,有专门的地址信号。
它只能根据地址,顺序地读写缓冲区。
所以需要有两个读写指针。
这里定义如下:
wptr:
写数据的指针
rptr:
读数据的指针
每读/写完一个数据,读/写指针就会加1,指向下一个待读/写的位置。
1.3.2同步器的设计
为了产生空/满标志,需要对2个读/写指针进行比较。
由于FIFO的读/写时钟信号,来自2个不同的时钟域,所以先要将这2个指针同步到一个时钟域。
这里采用两级D触发器级联来构成同步器。
1.3.3格雷码计数器
采用二进制码对地址指针进行计数时,从一个计数值变到下一个计数值时,可能有多位发生跳变,如从7à
8变化时,低位由0111à
1000,这样同步器在采样数据时,可能会发生错误。
由于采用格雷码计数时,每次只有1位发生跳变,这样使亚稳态发生错误的可能性大大减小了。
1.3.4空标志的产生
由于读/写指针,总是指向FIFO的memory中下一个要读/写的位置。
只有在读/写复位的时候,读/写指针才回到0位置。
复位后,随着数据的读出/写入,读/写指针指向的地址逐渐增加。
如果读的速度比较快,当读指针赶上写指针,即读指针与写指针指向同一个位置时,输出的空标志有效。
如下图所示:
图1.2FIFO的空/满标志
1.3.5满标志的产生
满标志的产生,基于这样的原理:
即“写指针比空指针多绕了一圈”后,又指向了空指针所指向的位置。
由上可知,空标志的产生,也是由于读/写指针指向了同一位置。
那怎么来区分,当读/写指针指向同一位置时,FIFO是满,还是空呢?
这里,采用增加一位地址位的方法,来区分满标志和空标志。
假设FIFO的深度为16,那么采用5位的读/写地址指针。
地址的低4位,用来对寻址memory,读/写指针的最高位用来判断FIFO为空还是为满。
当读/写指针的低4位相同时,如果最高位也相同,那么空标志有效,否则满标志有效。
由于格雷码具有一个特性:
关于中间的计数值对称。
如果从格雷码的中间划开,把它分成2段。
分别从上往下看,会发现在对应的位置,只有最高的2位是完全相反,而其余的低位部分则是相同的。
因此,当读/写指针的最高2位完全相反,而其余的低位完全相同时,满标志有效(“读指针比写指针多绕了一圈”)。
具体如下图所示:
图1.3格雷码的对称特性
1.3.6格雷码计数器
如果读/写数据的使能信号(rinc/winc)有效,在下一个读/写时钟的上升沿到来时,会从(对)memory读出/写入一个数据,并且相应的读/写指针会加1。
由于习惯上用二进制码来寻址memory,而且用二进制码能很方便地进行累积操作,所以这里以二进制码为主,并将二进制码转换为格雷码,以比较读/写指针来产生空/满标志位。
二进制码可以通过以下方式转换成格雷码:
gray=(bin>
>
1)^bin
其中,gray表示格雷码,bin表示二进制码。
如,设一个5位的二进制码为B[4:
0],它对应的格雷码为G[4:
0],则
G[4]=B[4]
G[3]=B[3]^B[3]
G[2]=B[2]^B[2]
G[1]=B[1]^B[1]
G[0]=B[0]^B[0]
图1.4比较指针和寻址指针的产生电路
1.4FIFO的设计模块
整个FIFO包括1个顶层模块和5个子模块。
1.4.1子模块fifomem
这个子模块,主要实现对FIFO的memory进行操作。
如果写使能信号(winc)有效,且FIFO满标志(wfull)无效,则在下一个写时钟(wclk)的上升沿到来时,将数据(wdata)写入到memory中写地址(waddr)指针所指向的位置。
同时,只要给出读地址(raddr),就可以从memory中读出数据(rdata),与读时钟(rclk)无关。
相应的代码如下所示:
modulefifomem#(parameterDATASIZE=8,//Memorydatawordwidth
parameterADDRSIZE=4)//Numberofmemaddressbits
(output[DATASIZE-1:
0]rdata,
input[DATASIZE-1:
0]wdata,
input[ADDRSIZE-1:
0]waddr,raddr,
inputwclken,wfull,wclk);
//RTLVerilogmemorymodel
localparamDEPTH=1<
<
ADDRSIZE;
reg[DATASIZE-1:
0]mem[0:
DEPTH-1];
assignrdata=mem[raddr];
always@(posedgewclk)
if(wclken&
&
!
wfull)mem[waddr]<
=wdata;
endmodule
1.4.2子模块sync_r2w
这个子模块,通过2个D触发器的级联,将格雷码表示的读指针,同步到写时钟域中。
相应的代码如下:
modulesync_r2w#(parameterADDRSIZE=4)
(outputreg[ADDRSIZE:
0]wq2_rptr,
input[ADDRSIZE:
0]rptr,
inputwclk,wrst_n);
reg[ADDRSIZE:
0]wq1_rptr;
always@(posedgewclkornegedgewrst_n)
if(!
wrst_n)
{wq2_rptr,wq1_rptr}<
=0;
else
={wq1_rptr,rptr};
1.4.3子模块sync_w2r
这个子模块,也采用2个D触发器的级联,将格雷码表示的读指针,同步到写时钟域中。
modulesync_w2r#(parameterADDRSIZE=4)
0]rq2_wptr,
0]wptr,
inputrclk,rrst_n);
0]rq1_wptr;
always@(posedgerclkornegedgerrst_n)
rrst_n)
{rq2_wptr,rq1_wptr}<
else
={rq1_wptr,wptr};
Endmodule
1.4.4子模块rptr_empty
这个子模块的输入包括:
读使能信号(rinc)、读时钟(rclk)、读复位信号(rrst_n,低电平有效)。
输出包括:
读寻址指针(raddr)、读比较指针(rptr)。
其中读寻址指针为二进制码,读比较指针为格雷码,且读寻址指针比读比较指针少一位。
可以参照图1.4,相关的代码如下:
modulerptr_empty#(parameterADDRSIZE=4)
(outputregrempty,
output[ADDRSIZE-1:
0]raddr,
outputreg[ADDRSIZE:
input[ADDRSIZE:
inputrinc,rclk,rrst_n);
0]rbin;
wire[ADDRSIZE:
0]rgraynext,rbinnext;
rrst_n)
{rbin,rptr}<
else
={rbinnext,rgraynext};
//Memoryread-addresspointer(okaytousebinarytoaddressmemory)
assignraddr=rbin[ADDRSIZE-1:
0];
assignrbinnext=rbin+(rinc&
~rempty);
assignrgraynext=(rbinnext>
1)^rbinnext;
//---------------------------------------------------------------------------------------
//FIFOemptywhenthenextrptr==synchronizedwptroronreset
assignrempty_val=(rgraynext==rq2_wptr);
rempty<
=1'
b1;
=rempty_val;
1.4.5子模块rptr_empty
这个子模块的输入包括:
写使能信号(winc)、写时钟(wclk)、写复位信号(wrst_n,低电平有效)。
写寻址指针(waddr)、写比较指针(wptr)。
modulewptr_full#(parameterADDRSIZE=4)
(outputregwfull,
0]waddr,
inputwinc,wclk,wrst_n);
0]wbin;
0]wgraynext,wbinnext;
//GRAYSTYLE2pointer
wrst_n)
{wbin,wptr}<
={wbinnext,wgraynext};
//Memorywrite-addresspointer(okaytousebinarytoaddressmemory)
assignwaddr=wbin[ADDRSIZE-1:
assignwbinnext=wbin+(winc&
~wfull);
assignwgraynext=(wbinnext>
1)^wbinnext;
//------------------------------------------------------------------
//Simplifiedversionofthethreenecessaryfull-tests:
//assignwfull_val=((wgnext[ADDRSIZE]!
=wq2_rptr[ADDRSIZE])&
//(wgnext[ADDRSIZE-1]!
=wq2_rptr[ADDRSIZE-1])&
//(wgnext[ADDRSIZE-2:
0]==wq2_rptr[ADDRSIZE-2:
0]));
assignwfull_val=(wgraynext=={~wq2_rptr[ADDRSIZE:
ADDRSIZE-1],
wq2_rptr[ADDRSIZE-2:
0]});
wfull<
b0;
=wfull_val;
1.4.6顶层模块afifo
这个顶层模块,主要完成5个子模块例化和互联。
可以参照图1.1,相关的代码如下:
moduleafifo#(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]waddr,raddr;
wire[ASIZE:
0]wptr,rptr,wq2_rptr,rq2_wptr;
sync_r2wsync_r2w
(.wq2_rptr(wq2_rptr),.rptr(rptr),
.wclk(wclk),.wrst_n(wrst_n));
sync_w2rsync_w2r
(.rq2_wptr(rq2_wptr),.wptr(wptr),
.rclk(rclk),.rrst_n(rrst_n));
fifomem#(DSIZE,ASIZE)fifomem
(.rdata(rdata),.wdata(wdata),
.waddr(waddr),.raddr(raddr),
.wclken(winc),.wfull(wfull),
.wclk(wclk));
rptr_empty#(ASIZE)rptr_empty
(.rempty(rempty),
.raddr(raddr),
.rptr(rptr),.rq2_wptr(rq2_wptr),
.rinc(rinc),.rclk(rclk),
.rrst_n(rrst_n));
wptr_full#(ASIZE)wptr_full
(.wfull(wfull),.waddr(waddr),
.wptr(wptr),.wq2_rptr(wq2_rptr),
.winc(winc),.wclk(wclk),
.wrst_n(wrst_n));
1.5用modelsim仿真FIFO
1.5.1编写测试代码
根据前面的顶层模块afifo,编写测试代码如下:
`timescale1ns/1ns
moduletest;
reg[7:
0]wdata;
regwinc;
regwclk;
regwrst_n;
regrinc;
regrclk;
regrrst_n;
wire[7:
0]rdata;
wirewfull;
wirerempty;
integeri;
always
begin
#50wclk=1;
#50wclk=0;
end
always
#100rclk=1;
#100rclk=0;
initial
wrst_n=0;
rrst_n=0;
rinc=0;
winc=0;
wclk=0;
rclk=0;
wdata=0;
i=0;
#400;
wrst_n=1;
rrst_n=1;
for(i=0;
i<
16;
i=i+1)
begin
repeat
(1)@(posedgewclk)
#20winc=1;
wdata=i;
end
repeat
(1)@(posedgewclk)
#20winc=0;
repeat
(1)@(posedgerclk)
#20rinc=1;
repeat
(1)@(posedgerclk)
#20rinc=0;
end
afifoafifo(.rdata(rdata),
.wdata(wdata),
.wclk(wclk),
.rclk(rclk),
.wrst_n(wrst_n),
.rrst_n(rrst_n),
.wfull(wfull),
.rempty(rempty),
.winc(winc),
.rinc(rinc)
);
1.5.2仿真波形
当写时钟(wclk)和读时钟(rclk)的周期相同,且都为50ns时,波形如下:
图1.5仿真波形--读写时钟的周期都为50ns
当写时钟(wclk)周期为100ns,读时钟(rclk)周期为50ns时,波形如下:
图1.6仿真波形--读/写时钟的周期都为50ns/100ns
当写时钟(wclk)周期为50ns,读时钟(rclk)周期为100ns时,波形如下:
图1.6仿真波形--读/写时钟的周期都为100ns/50ns