资源描述
异步FIFO设计
2011.6.22
摘要
本文采用格雷码设计了一个异步FIFO,经过DC综合的结果如下:
时钟频率:1.1GHz
面积: 10744.447um2
功耗: 7.791mw
目 录
1. 异步FIFO的设计 2
1.1 异步FIFO简介 2
1.2 FIFO的参数 2
1.3 FIFO的设计原理 2
1.4 FIFO的设计模块 6
1.5 用modelsim仿真FIFO 11
1.6 用DC对FIFO进行综合 13
2.参考文献 15
1. 异步FIFO的设计
1.1 异步FIFO简介
FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,它与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。
根均FIFO工作的时钟域,可以将FIFO分为同步FIFO和异步FIFO。同步FIFO是指读时钟和写时钟为同一个时钟。在时钟沿来临时同时发生读写操作。异步FIFO是指读写时钟不一致,读写时钟是互相独立的。
异步FIFO(Asynchronous FIFO),一般用于不同时钟域之间的数据传输,比如FIFO的一端连接频率较低的AD数据采样信号,另一端与计算机的频率较高的PCI总线相连。另外,对于不同宽度的数据接口也可以用AFIFO,例如单片机为8位数据输出,而DSP可能是16位数据输入,在单片机与DSP连接时就可以使用AFIFO来达到数据匹配的目的。
由于实际中,异步FIFO比较常见。为了便于描述,在后面的章节中将异步FIFO简称为FIFO.
1.2 FIFO的参数
FIFO的宽度: 进行一次读写操作的数据的位宽。
FIFO的深度: 双口存储器中能容纳的数据的总数。
满标志: FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出。
空标志: FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出。
读时钟: 读操作所遵循的时钟,在每个时钟沿来临时读数据。
写时钟: 写操作所遵循的时钟,在每个时钟沿来临时写数据。
读指针: 指向下一个读出地址。读完后自动加1。
写指针: 指向下一个要写入的地址的,写完自动加1。
读写指针其实就是读写memory的地址,只不过这个地址不能任意选择,而是连续的。
1.3 FIFO的设计原理
整体的框图如下:
图1.1 FIFO的整体电路图
1.3.1 FIFO的读写指针
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.2 FIFO的空/满标志
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.4 FIFO的设计模块
整个FIFO包括1个顶层模块和5个子模块。
1.4.1 子模块fifomem
这个子模块,主要实现对FIFO的memory进行操作。如果写使能信号(winc)有效,且FIFO满标志(wfull)无效,则在下一个写时钟(wclk)的上升沿到来时,将数据(wdata)写入到memory中写地址(waddr)指针所指向的位置。同时,只要给出读地址(raddr),就可以从memory中读出数据(rdata),与读时钟(rclk)无关。相应的代码如下所示:
module fifomem #(parameter DATASIZE = 8, // Memory data word width
parameter ADDRSIZE = 4) // Number of mem address bits
(output [DATASIZE-1:0] rdata,
input [DATASIZE-1:0] wdata,
input [ADDRSIZE-1:0] waddr, raddr,
input wclken, wfull, wclk);
// RTL Verilog memory model
localparam DEPTH = 1<<ADDRSIZE;
reg [DATASIZE-1:0] mem [0:DEPTH-1];
assign rdata = mem[raddr];
always @(posedge wclk)
if (wclken && !wfull) mem[waddr] <= wdata;
endmodule
1.4.2 子模块sync_r2w
这个子模块,通过2个D触发器的级联,将格雷码表示的读指针,同步到写时钟域中。相应的代码如下:
module sync_r2w #(parameter ADDRSIZE = 4)
(output reg [ADDRSIZE:0] wq2_rptr,
input [ADDRSIZE:0] rptr,
input wclk, wrst_n);
reg [ADDRSIZE:0] wq1_rptr;
always @(posedge wclk or negedge wrst_n)
if (!wrst_n)
{wq2_rptr,wq1_rptr} <= 0;
else
{wq2_rptr,wq1_rptr} <= {wq1_rptr,rptr};
endmodule
1.4.3 子模块sync_w2r
这个子模块,也采用2个D触发器的级联,将格雷码表示的读指针,同步到写时钟域中。相应的代码如下:
module sync_w2r #(parameter ADDRSIZE = 4)
(output reg [ADDRSIZE:0] rq2_wptr,
input [ADDRSIZE:0] wptr,
input rclk, rrst_n);
reg [ADDRSIZE:0] rq1_wptr;
always @(posedge rclk or negedge rrst_n)
if (!rrst_n)
{rq2_wptr,rq1_wptr} <= 0;
else
{rq2_wptr,rq1_wptr} <= {rq1_wptr,wptr};
Endmodule
1.4.4 子模块rptr_empty
这个子模块的输入包括:读使能信号(rinc)、读时钟(rclk)、读复位信号(rrst_n,低电平有效)。输出包括:读寻址指针(raddr)、读比较指针(rptr)。其中读寻址指针为二进制码,读比较指针为格雷码,且读寻址指针比读比较指针少一位。可以参照图1.4,相关的代码如下:
module rptr_empty #(parameter ADDRSIZE = 4)
(output reg rempty,
output [ADDRSIZE-1:0] raddr,
output reg [ADDRSIZE :0] rptr,
input [ADDRSIZE :0] rq2_wptr,
input rinc, rclk, rrst_n);
reg [ADDRSIZE:0] rbin;
wire [ADDRSIZE:0] rgraynext, rbinnext;
always @(posedge rclk or negedge rrst_n)
if (!rrst_n)
{rbin, rptr} <= 0;
else
{rbin, rptr} <= {rbinnext, rgraynext};
// Memory read-address pointer (okay to use binary to address memory)
assign raddr = rbin[ADDRSIZE-1:0];
assign rbinnext = rbin + (rinc & ~rempty);
assign rgraynext = (rbinnext>>1) ^ rbinnext;
//---------------------------------------------------------------------------------------
// FIFO empty when the next rptr == synchronized wptr or on reset
//---------------------------------------------------------------------------------------
assign rempty_val = (rgraynext == rq2_wptr);
always @(posedge rclk or negedge rrst_n)
if (!rrst_n)
rempty <= 1'b1;
else
rempty <= rempty_val;
endmodule
1.4.5 子模块rptr_empty
这个子模块的输入包括:写使能信号(winc)、写时钟(wclk)、写复位信号(wrst_n,低电平有效)。输出包括:写寻址指针(waddr)、写比较指针(wptr)。其中读寻址指针为二进制码,读比较指针为格雷码,且读寻址指针比读比较指针少一位。可以参照图1.4,相关的代码如下:
module wptr_full #(parameter ADDRSIZE = 4)
(output reg wfull,
output [ADDRSIZE-1:0] waddr,
output reg [ADDRSIZE :0] wptr,
input [ADDRSIZE :0] wq2_rptr,
input winc, wclk, wrst_n);
reg [ADDRSIZE:0] wbin;
wire [ADDRSIZE:0] wgraynext, wbinnext;
// GRAYSTYLE2 pointer
always @(posedge wclk or negedge wrst_n)
if (!wrst_n)
{wbin, wptr} <= 0;
else
{wbin, wptr} <= {wbinnext, wgraynext};
// Memory write-address pointer (okay to use binary to address memory)
assign waddr = wbin[ADDRSIZE-1:0];
assign wbinnext = wbin + (winc & ~wfull);
assign wgraynext = (wbinnext>>1) ^ wbinnext;
//------------------------------------------------------------------
// Simplified version of the three necessary full-tests:
// assign wfull_val=((wgnext[ADDRSIZE] !=wq2_rptr[ADDRSIZE] ) &&
// (wgnext[ADDRSIZE-1] !=wq2_rptr[ADDRSIZE-1]) &&
// (wgnext[ADDRSIZE-2:0]==wq2_rptr[ADDRSIZE-2:0]));
//------------------------------------------------------------------
assign wfull_val = (wgraynext=={~wq2_rptr[ADDRSIZE:ADDRSIZE-1],
wq2_rptr[ADDRSIZE-2:0]});
always @(posedge wclk or negedge wrst_n)
if (!wrst_n)
wfull <= 1'b0;
else
wfull <= wfull_val;
endmodule
1.4.6 顶层模块afifo
这个顶层模块,主要完成5个子模块例化和互联。可以参照图1.1,相关的代码如下:
module afifo #(parameter DSIZE = 8,
parameter ASIZE = 4)
(output [DSIZE-1:0] rdata,
output wfull,
output rempty,
input [DSIZE-1:0] wdata,
input winc, wclk, wrst_n,
input rinc, rclk, rrst_n);
wire [ASIZE-1:0] waddr, raddr;
wire [ASIZE :0] wptr, rptr, wq2_rptr, rq2_wptr;
sync_r2w sync_r2w
(.wq2_rptr(wq2_rptr), .rptr(rptr),
.wclk(wclk), .wrst_n(wrst_n));
sync_w2r sync_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));
endmodule
1.5 用modelsim仿真FIFO
1.5.1编写测试代码
根据前面的顶层模块afifo,编写测试代码如下:
`timescale 1ns/1ns
module test;
reg [7:0] wdata;
reg winc;
reg wclk;
reg wrst_n;
reg rinc;
reg rclk;
reg rrst_n;
wire [7:0] rdata;
wire wfull;
wire rempty;
integer i;
always
begin
#50 wclk = 1;
#50 wclk = 0;
end
always
begin
#100 rclk = 1;
#100 rclk = 0;
end
initial
begin
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) @ (posedge wclk)
#20 winc = 1;
wdata = i;
end
repeat (1) @ (posedge wclk)
#20 winc = 0;
for (i = 0; i < 16; i = i + 1)
begin
repeat (1) @ (posedge rclk)
#20 rinc = 1;
end
repeat (1) @ (posedge rclk)
#20 rinc = 0;
end
afifo afifo (.rdata(rdata),
.wdata(wdata),
.wclk(wclk),
.rclk(rclk),
.wrst_n(wrst_n),
.rrst_n(rrst_n),
.wfull(wfull),
.rempty(rempty),
.winc(winc),
.rinc(rinc)
);
endmodule
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
1.5.3仿真结果
根据前面的3种仿真波形,可以看出所设计的FIFO,能满足功能要求。
1.6 用DC对FIFO进行综合
1.6.1编写DC的启动文件
#.synopsys_dc.setup for afifo
#modified by He Zhongzhu
#June 22nd, 2011
set search_path ". $search_path lib rtl scripts mapped unmapped"
set target_library "tt_1v20_25c.db"
set link_library " * $target_library dw_foundation.sldb"
set symbol_library " smic13g.sdb "
#set synthesis_library "dw_foundation.sldb standard.sldb"
set cache_write ~/
set cache_read $cache_write
# specify directory for intermediate files from analyze
define_design_lib DEFAULT -path ./analyzed
# suppress Driving cell warning
suppress_message {UID-401 DDB-24}
set verilogout_no_tri true
define_name_rules BORG -allowed {A-Za-z0-9_} -first_restricted "_" -last_restricted "_" -max_length 30
set verilogout_no_tri true
# specify varibles
set dw_prefer_mc_inside true
set sh_enable_line_editing true
1.6.2编写DC的约束文件
#top.con for afifo
#created by zzhe
#June 22th, 2011
reset_design
#create_clock -period 5 -name vclk;#virtual clock
create_clock -period 0.9 [get_ports wclk]
create_clock -period 0.9 [get_ports rclk]
#set_uncertain_delay -setup [get_clocks vclk]
#set_clock_latency -source -max [get_clocks vclk]
#set_clock_transition [get_clocks vclk]
set MAX_LOAD [load_of tt_1v20_25c/NAND2BX2M/AN]
set_driving_cell -lib_cell INVX16M [all_inputs]
set_input_delay -max 0 -clock wclk [remove_from_collection [get_ports "w*"] \
[get_ports "wfull wclk"]]
set_input_delay -max 0 -clock rclk [remove_from_collection [get_ports "r*"] \
[get_ports "rempty rdata rclk"]]
set_output_delay -max 0 -clock wclk [get_ports wfull]
set_output_delay -max 0 -clock rclk [get_ports "rempty rdata"]
set_load [expr $MAX_LOAD*15] [all_outputs]
set_max_area 0
#set auto_wire_load_selection
#set_operating_conditions -max ""
set_max_capacitance [expr $MAX_LOAD*10] [get_designs *]
alias h history
alias rc "report_constraints -all_violators"
alias rt report_timing
alias ra report_area
alias rp report_power
1.6.3 DC的综合结果
采用design_vision进行综合,得到的综合结果如下:
时钟频率:1.1GHz
面积: 10744.447um2
功耗: 7.791mw
2.参考文献
[1] Simulation and Synthesis Techniques for Asynchronous FIFO Design.pdf
[2 ]Jan M.Rabaey, Digital Integrated Circuits, A Design Perspective
15
展开阅读全文