一乐电子

一乐电子百科

 找回密码
 请使用微信账号登录和注册会员

QQ登录

只需一步,快速开始

快捷登录

手机号码,快捷登录

搜索
查看: 1923|回复: 6
收起左侧

FIFO 相关资料

[复制链接]
发表于 2009-11-13 21:12 | 显示全部楼层 |阅读模式
本帖最后由 kenson 于 2009-11-24 22:52 编辑
, {+ ^5 Y! S7 t! o' n+ i7 Y* S- C9 t2 `: {, v3 m6 z
这段时间在一个工程用到一些FIFO之类的东西。找了一些资料不知对大家有没用不!!
" p2 A  g! X4 Y- W2 k- m华为的资料相对不错的

fifo.pdf

809.34 KB, 下载次数: 175, 下载积分: 一乐金币 -1

基于多时钟域的异步FIFO 设计.pdf

171.71 KB, 下载次数: 161, 下载积分: 一乐金币 -1

基于LPM的高速FIFO的设计.rar

61.49 KB, 下载次数: 168, 下载积分: 一乐金币 -1

发表于 2009-11-14 11:47 | 显示全部楼层
下了,实在看不懂!
 楼主| 发表于 2009-11-14 12:15 | 显示全部楼层
这个其实不太难的,如果用不上可能没多大用处!* k+ x6 q- E! N3 c" Y: `4 n1 r
但如果知道其中的作用这个在很多的地方都能看到它的踪影( `5 f; b& I+ C8 _; V6 f; X
如:RS232 485 并口之类的太多了!!
* m4 d) t4 j" i1 W0 L可能你会这样说:“我从来没都没有用过这些的东西”
, `/ n/ V8 C' w% W( F但有些IC已有这个东西在内面了
! f- X/ u% x1 s' _可能你也会这样说:“既然有了我还学它干什么呢!!”
! j6 n* T( W' F1 c' y我这个是CPLD版啊!就是说要你自己去搞一个这样的东西给自己用啊!如果用不上就当我没说过吧!7 R5 ?. [& G) z, ]+ M( s" T; Y8 c
如果你想自己做一个自己的专用的IC的话哪么这个以后你肯定会用得上的。
 楼主| 发表于 2009-11-27 14:42 | 显示全部楼层
异步FIFO结构1 k# q+ }; ]# b8 U8 G7 p4 w
% h% ]. G/ T) @1 b2 \
设计一个FIFO是ASIC设计者遇到的最普遍的问题之一。本文着重介绍怎样设计FIFO——这是一个看似简单却很复杂的任务。+ n  B/ p* `  C
    一开始,要注意,FIFO通常用于时钟域的过渡,是双时钟设计。换句话说,设计工程要处理(work off)两个时钟,因此在大多数情况下,FIFO工作于独立的两个时钟之间。然而,我们不从这样的结构开始介绍—我们将从工作在单时钟的一个FIFO特例开始。虽然工作在同一时钟的FIFO在实际应用中很少用到,但它为更多的复杂设计搭建一个平台,这是非常有用的。然后再从特例推广到更为普通的FIFO,该系列文章包括以下内容:: y3 N" ^& h6 V5 I  \% V
1.单时钟结构
' t/ n* V3 \, w# o' O- G4 }2.双时钟结构——双钟结构1: ~. s# E9 e$ L
3.双时钟结构——双钟结构2
7 J3 [+ I" P" D% ?! @* w$ t+ V4.双时钟结构——双钟结构3. _3 m; o. h7 R  a- C, b5 `
5.脉冲模式FIFO
4 u! O3 f( K& f" ^, L7 J单时钟FIFO特例9 ^9 U# I' R- k) @
    FIFO有很多种结构,包括波浪型(ripple)FIFO,移位寄存器型以及其他一些我们并不关心的结构类型。我们将集中讨论包含RAM存储器的结构类型。其结构如图1所示。
0 B# b  ?2 P. d6 [7 B5 yhttp://www.dzkf.cn/upimg/userup/0902/260S2296040.jpg
& }' x4 o  `5 `& D, i4 A+ t7 I    通过分析,我们看到图中有一个具有独立的读端口和独立的写端口的RAM存储器。这样选择是为了分析方便。如果是一个单端口的存储器,还应包含一个仲裁器保证同一时刻只能进行一项操作(读或写 ),我们选择双口RAM(无需真正的双口RAM,因为我们只是希望有一个简单的相互独立的读写端口)是因为这些实例非常接近实际情况。, `! S1 M6 G; m8 e- {& {
    读、写端口拥有又两个计数器产生的宽度为log2(array_size)的互相独立的读、写地址。数据宽度是一个非常重要的参数将在在稍后的结构选择时予以介绍,而现在我们不必过分的关心它。为了一致,我们称这些计数器为“读指针”(read pointer)和“写指针”(write pointer)。写指针指向下一个将要写入的位置,读指针指向下一个将要读取的位置。每次写操作使写指针加1,读操作使读指针加1。3 Q- q- I% e1 O' C
    我们看到最下面的模块为“状态”(stauts) 模块。这个模块的任务实给FIFO提供“空”(empty)和“满”(full)信号。这些信号告诉外部电路FIFO已经达到了临界条件:如果出现“满”信号,那么FIFO为写操作的临界状态,如果出现“空”信号,则FIFO为读操作的临界状态。写操作的临界状态(“full is active”)表示FIFO已经没有空间来存储更多的数据,读操作的临界表示FIFO没有更多4 C; |  I- {1 ?5 x1 h# {
的数据可以读出。status模块还可告诉FIFO中“满”或“空”位置的数值。这是由指针的算术运算来完成了。
1 |/ v* h3 z7 p: q    实际的“满”或“空”位置计算并不是为FIFO自身提供的。它是作为一个报告机构给外部电路用的。但是,“满”和“空”信号在FIFO中却扮演着非常重要的角色,它为了能实现读与写操作各自的独立运行而阻塞性的管理数据的存取。这种阻塞性管理的重要性不是将数据复写(或重读),而是指针位置可以控制整个FIFO,并且使读、写操作改变着指针数值。如果我们不阻止指针在临界状态下改变状态,FIFO还能都一边“吃”着数据一边“产生”数据,这简直是不可能的。
, x# ~1 [5 n6 P, ^8 l/ ~; `    进一步分析:DPRAM若能够寄存读出的信号,这意味着存储器的输出数据已被寄存。如果这样的话,读指针将不得不设计成“read 并加1 ”,也就是说在FIFO输出数据有效之前,必须提供一个明确的读信号。另一方面,如果DPRAM没有寄存输出,一旦写入有效数据就可以读出;先读数据,然后使指针加1。这将影响到从FIFO读出数据和实现空/满计算的逻辑。由于简化的缘故,我们仅论述DPRAM没有提供索锁存输出的情况。同理,将其推广到寄存输出的DPRAM并不是很复杂。
' U  ~& A  V; t1 O, V, {* {    从功能上看,FIFO工作原理如下所述:复位时,读、写指针均为0。这是FIFO的空状态,空标志为高电平,(我们用高电平表示空标志)此时满标志为低电平。当FIFO出现空标志时,不允许读操作,只能允许写操作。写操作写入到位置0,并使写指针加1。此时,空标志变为低电平。假设没有发生读操作而且随后的一段时间FIFO中只有写操作。一定时间后,写指针的值等于array_size-1。这就意味着在存储器中,要写入数据的最后一个位置就是下一个位置。在这种情况下,写操作将写指针变为0,并将输出满标志。
- g* O5 J! w+ s* L    注意,在这种情况下,写指针和读指针是相等的,但是FIFO已满,而不是空。这意味着“满”或“空”的决定并不是仅仅基于指针的值,而是基于引起指针值相等的操作。如果指针值相等的原因是复位或者读操作,FIFO认为是空;如果原因是写操作,那么FIFO认为是满。& ]5 R% ]- n/ d
    现在,假设我们开始一系列的读操作,每次读操作都将增加读指针的值,直到读指针的位置等于array_size-1。在该点,从这个位置读出的FIFO输出总线上的数据是有效的。随后的逻辑读取这些数据并提供一个读信号 (在一个时钟周期内有效)。这将导致读指针再次等于写指针(在两个指针走完存储器一圈后)。然而,由于这次相等是由于一个读操作,将会输出空标志。
1 ^; S6 k1 w2 o, {# D    因此,我们将得到如下的空标志:写操作无条件的清除空标志。. w. y# j2 N+ ]% T; l8 h
Read pointer=(array_size-1) , 读操作置空标志。
0 M# }4 F7 h' Y0 P/ {9 v3 N    以及如下的满标志:读操作无条件的清除满标志,) _3 I& I" ]! b9 R8 y# U
Write pointer= (array_size-1), 写操作置满标志。0 e4 y8 r8 e' |
    然而,这是一个特殊的例子,由于一般情况下,读操作在FIFO不是空的情况下就开始了(读操作逻辑不需要等待FIFO变满),因此这些条件不得不修改来存储读指针和写指针的每一个值。
9 a# s( w( N+ s4 r/ D% y& K    有这样一个想法,那就是我们可以将存储器组织成一个环形列表。因此,如果写指针与读指针差值大于1或更多,就进行读操作,FIFO为空,这种工作方式对于用无符号(n-bit)结构来描述的临界状态非常适合。同样的,如果读指针与写指针的差值大于1,就进行写操作,直到FIFO为满。
  i) ]' Z: q" d& k5 K* T    这将带来如下的条件:( I, y9 h, u, S- v2 |9 N
    写操作无条件的清除空标志。
5 Q8 z$ ?9 x/ Q* bwrite_pointer=(read_pointer+1),读操作置空。; t, T9 D$ l" {) m0 s7 F; y
    读操作无条件的清除满标志," R% U! W4 A, Z! x
read_pointer= (write_pointer+1),写操作置满。
$ \0 c$ s# U# D! x# k; z    注意,读操作和写操作同时都在使其指针增加,但不改变空标志和满标志的状态。在空或满的临界状态同时读操作和写操作都是不允许的。. ~7 e7 r: ~! @/ T# I4 b
    综上所述,我们现在能够定义FIFO的status模块,这里提供了用VHDL编写的代码,由于是同步的,很容易转换成Verilog HDL代码。& b5 a4 Y' V' M8 E3 G
library IEEE, STD;
9 N, F7 ]5 s4 u8 {6 |use IEEE.std_logic_1164.all;
+ q9 }% |& C% M# n( Y4 F2 ^use IEEE.std_logic_arith.all;
0 j; `) v- c; ?: v2 y& `5 Nuse IEEE.std_logic_unsigned.all;
/ Q$ A. C: \6 X( jentity status is' M2 S' x9 @9 N% o) z
port (reset : in std_logic;
& U0 A$ s9 k" h6 H$ iclk : in std_logic;
& L/ A. a& L+ z- b5 w' afifo_wr : in std_logic;. r( ?* l' S$ V1 I: v  g
fifo_rd : in std_logic;
) b& e- m" E/ [6 E4 nvalid_rd : out std_logic;
: G* s7 P1 O' {6 j: w; o$ m+ d* y# `valid_wr : out std_logic;0 O% x# s. d. l, E, Z- n$ v
rd_ptr : out std_logic_vector(4 downto 0);! \: t# a* v  f
wr_ptr : out std_logic_vector(4 downto 0);
' o1 K' x8 c6 o& L' ^7 v) Sempty : out std_logic;
8 }$ U& ?5 k5 Rfull : out std_logic
# X, {4 ?; C& m. P' g);$ F" k6 H& m  J; \) ~
end status;
% C! Z; L' j& r4 Y+ t1 t, N& h) u7 ~architecture status_A of status is( _4 q. J. |' ]3 I! ^  f# V
signal rd_ptr_s : std_logic_vector(4 downto 0);1 a; y( z1 j1 ]' g$ f% {) t, ]
signal wr_ptr_s : std_logic_vector(4 downto 0);
. P7 D3 |. ?7 V% o8 ^signal valid_rd_s : std_logic;
7 p4 Z1 F7 G3 T, o# Qsignal valid_wr_s : std_logic;
% Z  H+ {& |( \8 _- q0 _; I) Tbegin* K  S+ u2 K$ y
empty_P : process(clk, reset); E; u9 b, n: o' @0 t* ^1 n! h
begin
, v6 W1 w# c  Vif (reset = '1') then) q$ C3 l. h5 [4 r
empty <= '1';* x! ~0 `% [9 R% C4 F- z  L
elsif (clk'event and clk = '1') then3 o2 y) z  r2 Y& `! @  q8 n
if (fifo_wr = '1' and fifo_rd = '1') then& P# x7 x  p6 t
-- do nothing
- t) f8 I- Z4 O5 inull;
5 ?2 x+ J4 W8 W9 Z9 ?' celsif (fifo_wr = '1') then. k. N& |  I% ]4 l
-- write unconditionally clears empty7 Q8 x  f: A9 @( }: l/ [$ o& o3 T
empty <= '0';  B+ d, F4 T& Y, ]# G
elsif (fifo_rd = '1' and (wr_ptr_s = rd_ptr_s + '1')) then
+ j. u9 Y7 P9 Q$ P. P; }2 U3 S% v-- set empty3 C. ], F* _; @" W9 t' V) r
empty <= '1';# g; L$ m( K7 u/ h
end if;9 n$ H2 @( U. `# c6 I0 W; ^' D( n
end if;7 ]+ V7 y8 d2 z9 p0 g
end process;: `9 n* m; e3 a: T
full_P : process(clk, reset)
; |! Z* }6 h$ `. x$ k1 gbegin- w  L$ B' \* ?/ i# n3 o& h0 S1 V
if (reset = '1') then" U" ^0 y$ V/ \* o7 h" c" \, w
full <= '0';" z! ~" n9 `, P" v
elsif (clk'event and clk = '1') then
. A: I" `# ]$ f4 jif (fifo_rd = '1' and fifo_wr = '1') then
3 Z4 j: u* w2 r8 L! [* F0 n-- do nothing
' V2 v. t3 e+ V8 h2 knull;
6 i0 X, d7 ]3 h3 Z8 J# R# Melsif (fifo_rd = '1') then3 l, W  Y9 I1 ~7 X8 u
-- read unconditionally clears full4 z" g2 h# J8 ^3 F5 v! Z4 P" F4 p1 ?1 S
full <= '0';; s- K' |& r* l5 K
elsif (fifo_wr = '1' and (rd_ptr_s = wr_ptr_s + '1')) then! q" K8 B  W' X/ c, D8 e" Q
-- set full, f8 }1 K5 t2 H/ r+ P5 p
full <= '1';
! p* O6 t7 c# v$ Mend if;' k# q4 l0 ]4 C7 [' |2 E+ B/ l
end if;
. S* ?/ d1 ~% f1 Z- D9 e( Mend process;
4 ~4 s9 q. @4 v+ }# m6 v9 W7 e, vvalid_rd_s <= '1' when (empty = '0' and fifo_rd = '1');% n" M# n1 M4 @6 i* h
valid_wr_s <= '1' when (full = '0' and fifo_wr = '1');
: [# l  T" I7 d& K' wwr_ptr_s_P : process(clk, reset). a: c# [: h5 m) \" v/ i6 W
begin1 k* G+ M. v" E' ?. x# C& d
if (reset = '1') then+ \2 q9 N( j: A; Z" ^
wr_ptr_s_P <= (others => '0');
. D; K$ A* Y& e$ o4 V8 G9 |  Helsif (clk'event and clk = '1') then) ~& M6 a' F7 r: o2 U4 O
if (valid_wr_s = '1') then8 p9 G) m2 u# W! p  _+ u7 G, w
wr_ptr_s <= wr_ptr_s + '1';
" @- ?9 g! J- N, eend if;
) x; j& l( M3 T/ M! Y- C+ }6 `end if;
6 I! ^9 ]/ Y$ kend process;
8 L) V1 L' ?" j# v9 ~rd_ptr_s_P : process(clk, reset)* a- L: F1 n7 u8 I, h& d$ |
begin; Y% t& l5 Q1 Z
if (reset = '1') then; o9 g3 n# s) S6 @5 y* X
rd_ptr_s_P <= (others => '0');
& Q% W1 ]) `& g# h3 L* welsif (clk'event and clk = '1') then! \3 t  \. T7 Z! |; f/ p/ ]. B- Z
if (valid_rd_s = '1') then1 ?$ R$ S* f+ X3 R
rd_ptr_s <= rd_ptr_s + '1';3 h2 x" a$ B6 ^( f
end if;
1 n6 {  q$ |9 ?8 h2 [' ~end if;
0 |$ W+ Z$ H, R( O. Fend process;
$ Y$ T& l7 x9 b  yrd_ptr <= rd_ptr_s;. D: H' C. [$ K0 J9 q1 \
wr_ptr <= wr_ptr_s;& ~) O  d0 F' q( z6 U0 y
end status_A;% i5 i6 B1 v/ F3 o/ l# Z
    电路图如图2所示:6 a# v7 L0 y  k' A! h9 `7 C
http://www.dzkf.cn/upimg/userup/0902/260S4193118.jpg
' `9 x" a4 n4 ^2 |- j0 y0 s    细心的读者会注意到图2中产生满或空标志需要同时用到两个指针。在双时钟设计的情况下,希望用读指针处理(work off) 读时钟,写指针处理(work off) 写时钟。这会引起不希望发生的毛刺问题——自己可以去试一试,看一看。这些问题以及一些解决方案将在后续的该系列文章中提及。
( k" V( d+ U0 F% `( q' KPS: 文章中三次提到 work off clock,分别在开头和结尾处,work off字面意思是“去除,消除,出售”的意思,可是在FIFO中,不应该是去除的意思,故根据前后文和常识,将其翻译为“处理”,有不对的地方请批评指正!- U. U7 ]- W1 G) z, E, R9 L
 楼主| 发表于 2009-11-27 14:45 | 显示全部楼层
异步FIFO结构5 c/ a2 e4 f8 x8 @! q, j
在先前的该系列文章中,我们看到了怎样用双端口、无寄存器输出的RAM设计同步FIFO。这部分我们将探讨同样的概念,并将其推广到怎样产生具有相互独立、自由工作的读、写时钟的FIFO。拥有自由工作时钟简化了很多问题,但是这导致了一个特殊情况下的解决方法。普通情况下不对时钟进行假设,甚至不假设其自由工作。我将在本系列文章的最后一部份讨论最普通的情况。+ y  @& m! ^* W2 M# o% }
    如果你看过先前的文章,你会发现只有status模块工作在两个时钟。存储器没有寄存输出,所以它确实不需要用读时钟;即使它是寄存输出,也可毫无问题的运行于读时钟上。Status模块本质的功能是对两个指针进行操作,而且这两个指针工作在不同的时钟域。这也是真正的困难所在。如果打算用写时钟来取样读指针或用读时钟来取样写指针,将不可避免的遇到一个问题:亚稳态。它将导致空/满标志的计算错误,并导致设计的失败。
. N; v9 ]' Q$ N4 n' ?1 亚稳态
6 I$ Y) @4 R0 W8 x( K# m    接下来我们将系统地开始探讨亚稳态,并解决由亚稳态产生的问题。首先我们来了解一下什么是亚稳态。亚稳态是一种物理现象的名称,它发生在一个事件试图取样[1](sample)另一事件的时候。亚稳态可以描述如下:假设一个信号在t = 0时刻瞬间从0变为1,那么信号在t = 0时刻的值究竟是多少?是0还是1,或者在两者之间?在亚稳态中,这个问题被定义的两个时刻回避了,分别是0-和0+。在t = 0-时刻,规定信号的取值为0,t = 0+ 时刻规定信号的取值为1。显然,0- = 0 - 0,0+ =0 + 0。注意,这仅仅是一个数学定义,如果你正在用实际的电路做同样的事,输出将有可能是逻辑0(0伏)或者逻辑1(5伏),或者是介于0 ~5伏中间的某个值。正如在数学中描述的一样,物理系统中一个事件取样另一个事件产生了不可预知的结果。不可预知性也就意味着另一个迹象——亚稳态很危险。4 i2 u% `1 V" a' H: Q0 ]2 B
1.1 时间分辨率(Resolution Time 翻转时间?)8 P! {9 k: y4 U
    当一个事件取样一个稳定值时(或者一个能稳定一段时间的值),取样值就随这个稳定值而变化。假设在D触发器情况下,就是Q值随D值变化。这段能够稳定取样的时间用相关的取样事件来定义,称之为时间分辨率(翻转时间?)。也就是我们所熟悉的“clock-to Q time”,或tcq。如果遇到触发器的setup time[2] 和hold time[2],这将是cell设计者保证输入能够正确变为输出的时间。亚稳态影响物理系统的时间分辨率,同样也影响输出值。在“不稳定平衡”情况下考虑这些问题,就像“山上的球”(或者球面上的球体)你不知道它会向哪个方向滚,这个球就处于不稳定平衡状态。如果球完全不受干扰,它有可能一直呆在原地,但是微小的晃动会使球滚到山的一边或另一边。这将无法计算球从山上滚下的距离,或者无法计算球从山的哪一边滚下来。这就是亚稳态的一个准确的例子——你无法预知物理系统输出的值将会变成什么样,多久会变化,并且相当危险。换句话说,输出永远保持一个有限非零概率的亚稳态。在现实中,尽管很少有这种情况发生,但20倍的clock-to Q 时间是一个合理的时间分辨率数值。在理论上,当取样操作接近被取样事件的时候,时间分辨率是无限的渐进曲线。3 p# u) l0 [0 n0 N! u7 N# W
5 W  J" q% l' h2 ~5 m6 U2 b+ C
1.2 MTBF(平均无故障时间)与可靠性
0 I/ j4 J& z4 r6 V7 x$ k, z7 S6 a' i
    如果一个设计中包含同步组件,无论是否愿意它都会出现亚稳态。亚稳态无法彻底消除,因此我们所做的就是计算错误概率以及在时间上来描述它。让我们来看一下,假设这里有一个物理系统亚稳态错误发生的概率为1/1000。换句话说,每一千次采样就会因为亚稳态发生一次错误。这也意味着,每一千次,输出就会在下一个时钟沿到来时,无法变化。如果时钟频率为1KHz,那么每秒都会有一次错误出现,MTBF值就为1秒。当然,这个假设过于简单;MTBF是一种故障概率的统计度量,并且需要更为复杂、经验化、实验化的数据来计算。对于触发器来说,这种关系依赖于电路自身的物理常数和时钟频率,记住亚稳态本身与时钟没有任何关系,但是它和MTBF相关[3]。自然的,我们会说一个可靠性好的电路具有很高的MTBF值。
8 w. S5 @1 X9 B7 K8 d4 L) W8 N3 }$ ?3 B9 b& Z% X' o
1.3 同步2 s: ?9 Y2 U' f5 J, A8 ]# H( X
    由于亚稳态无法彻底避免,在设计电路时一定要——
  • 很好的处理错误。
  • 将错误发生的概率降到最低。
" c; h+ @2 [/ c, W# h5 w
http://www.dzkf.cn/upimg/userup/0902/260SP13092.jpg   O5 A3 D+ N6 J
    首先要求,设计与设计之间要有很大的区别,它并不在本文介绍的范围。第二个要求,使用 “同步”技术。这种技术由两个触发器简单的组合在一起如图1所示。仅当Q1的出现非常接近时钟沿的时候,Q2才会进入亚稳态。如果在亚稳态情况下我们将20倍的tcq作为时间分辨率,那么时钟周期将为tclk = 20tcq+ tsetup。这说明经过20倍的clock-to Q时间,输出仍然随输入改变的概率大大减小。因此,在时钟沿到来时Q2没有被改变的概率接近P2,这里P是第一级输出没有在时钟沿到来时随输入而改变的概率。这称为两级同步。当使用这个时钟频率下概率来计算MTBF时, MTBF值会提高很多。如果愿意的话,可以通过三级同步进一步增加MTBF值。但这在实际中很少需要。5 v4 D; Q: c! }' G# ?. x" B
如图2所示,可以在电路中增加冗余的同步来很好的抵御亚稳态。在三冗余和等同于两冗余的状态下,最终的输出大部分(三分之二)可以计算出来。在这个实例中,小尺寸的布局布线与器件的差异说明了如果一个同步器产生亚稳态错误,其他的两级也会产生亚稳态错误,所有的概率将随之改变。这种技术仅在要求非常苛刻时候的用到。欲更多了解亚稳态与同步的知识,请参阅Grosse,Debora的“Keep metastabiliy from killing your digital design/ _' ?) n9 v1 p" j  E0 _0 @
http://www.dzkf.cn/upimg/userup/0902/260SS29305.jpg 6 L' S. \7 r4 C, K6 @
2 采样计数器. \6 b( S, U7 K, N3 r% J, n9 \( x
2.1 同步:解决可靠性问题
6 U8 S* k$ Z+ ]- {, ^    现在我们回到有关FIFO的问题上来。如果要用时钟取样计数器的值,这相对于计数器时钟来说是异步的。因此,到最后不得不考虑计数器到底在哪个范围变化,假定从 FFFF到0000。每个单独的位(bit)都处于亚稳态。这种变化意味着有可能读数为0000到ffff之间(包含两者)的任何可能的值。当然这也说明该情况下FIFO将无法工作。同步可以保存处于亚稳态时的计数器取样,尽管看似很离谱但仍然可以得到取样值。换句话说,仅靠计数器同步是不够的。* W, }) e- L) H" V6 P, t
    重要的是我们必须确保不是所有的计数器位(bits)同时改变。实际上,不得不保证每一次计数器的增加正好改变一位。这说明计数器变化时出现错误的只可能有一位。如果计数器准备开始工作,那么至少需要一位的变化,这就是我们所能做的最好的办法。我们所需要的是用格雷码来表示的计数器。这是因为格雷码是最小距离码[4],相邻码元之间的只有1位不同。
6 ]; j9 W1 T7 b    让我们来分析一下格雷码(GRAY)对于FIFO的指针设计有什么作用。首先,同步意味着计数器的取样值很少处于亚稳态,其次,我们取样的值最多只会有一位发生错误。这就是说计数器的真实值从N-1变到N,那么无论是否发生错误读取的数不是N-1就是N,而不会是其它的值。由于在变化的那一时刻,必须确定输出的值是多少,这对于读出计数器值来说是完全正确的举动。只要能够确定读出的值是旧还是新就可以了。出现其它值则是不对的。如果进一步考虑,将会发现如果在改变值的瞬间取样计数器的值,两个答案(N-1,N)对于计数器的值都是正确的。
; @1 S9 p/ X; N3 @0 j& p. Y1 I4 @6 ?+ C1 c+ I5 Q( P: R: @0 c
2.2 保守的[5]报告——很好的处理错误
4 A9 f0 d. \5 i; u6 q( Q; D& _' k
    了解了这么多,接下来分析一下怎样将这些知识用于FIFO的读写指针操作。人们通常希望知道FIFO是否为满。如果它满了,必须阻止写操作再次发生。这很关键,因为当FIFO已满时,必须停止写指针加1。将(格雷码的)读指针与写时钟同步。因为每当同步读指针的时候,实际的读指针可能会变为不同的值。这意味着读指针可能会是一个失效的值。如果是这样,从写操作的角度考虑会发生少读现象(相比实际情况),如果条件吻合,FIFO为满。实际上,FIFO可能未满,因为有可能读操作发生,而从写操作的角度是“看不到”的。然而,我们只要阻止额外的写操作就OK了。如果当FIFO真的满了时我们不去阻止写操作将会出现错误。
1 x* R0 a- _* _4 w$ ]( G" y' j    同样的从读操作的角度看——实际上当FIFO 中还有一些数据时,读操作一方看到“被延迟的”写操作,可能会认为FIFO为空。这种情况读操作被阻止直到写操作“变得可被读操作一方所看见”,它将不允许进一步的读操作。' O6 S; J7 u) @* [% Q. c
    上述被称为保守的报告。简而言之,当FIFO未满时,对于写操作一方报告称FIFO已满,当FIFO未空时,报告对读操作一方称FIFO已空。这种现象好比FIFO动态的缩小了一点,这毫无坏处。在字节计算的情况下,我们用同样的技术,提供写操作一方的字数计算和读操作一方的字数计算。写操作一方计算的字数可能大于FIFO中的真实字数。这已令人相当满意了,因为影响它的仅仅是允许其阻止下一步的写操作。同理,读操作一方字数计算会少于实际字数,那也没关系,只要确认不要将写操作一方计算的字数用于读操作一方即可,反之亦然。8 M$ _+ n* ]! d  C/ u" m
    这种保守的报告机构在被同步的值中能很好的处理错误。事实上,即使取样的读指针值将处于亚稳态一段时间,其影响只是阻止写操作,使FIFO暂停写操作,而不会引起数据错误。同理适于读操作。% K4 {& O# ]+ p# e- V1 L
3 结构. c) S$ O. i5 P6 `' L: s6 h
3.1 产生空/满标志的条件
# `' m. n7 w* k) E; E    记得上篇文章中,我们提到了指针不是影响空/满标志唯一的条件。空标志的条件是由读操作引起的读写指针相等,满标志的条件是写操作引起的读写指针相等。换句话说,要正确地产生空/满标志信号,需要用写时钟对读信号进行取样,同时用读时钟对写信号进行取样。这不同于球的游戏,因为我们不希望对时钟的频率做出假设。设想一个10ns的写信号(100MHz)被一个1KHz的读时钟取样,若无脉冲宽度延展的话就不能这样做,而且这也意味着已知(或假设已知)两个时钟之间具有某种关联。
; z. r3 x+ y, p: s) C. m' W/ k    当然,我们也不希望假设时钟之间有任何的关系。这就引起了分别围绕三种方法的问题,并且,它将引出我们即将讨论的三种不同的结构。第一种结构相当不错,将在下面描述。第二种结构也还行,但不是很好,第三种结构性能超强,但在在面积占用方面没有优势。选择哪种结构要根据自己的需求。
1 e0 {  W, u' W- M  c; h" K0 o  `" q1 p8 @2 g4 g. v  u  w
3.2 第一个方案
) Q. K; E; J+ N* C1 U. k    由于不可能设计出一个不考虑频率的满足脉冲采样的电路,通过对读/写指针的编码我们绕过了这个问题。构造一个指针宽度为N+1,深度为2N字节的FIFO。为便方比较还可以将格雷码指针转换为二进制指针。
7 h9 Z4 c1 ~/ u6 h" V3 M    当(正被讨论的已被时钟同步的)指针的二进制码中最高位不一致而其它N位都相等时,FIFO为满。当(已经过二进制转换的)指针完全相等时,FIFO为空。这也许不容易看出,因此让我们举个例子来分析一下。# g% i( i5 A8 T* s3 Z/ q
    思考一下一个深度为8字节的FIFO怎样工作(使用已转换为二进制的指针)3 H3 i. e2 E3 z
译者注:FIFO_WIDTH=8,FIFO_DEPTH= 2N = 8,N = 3,指针宽度为N+1=4 )。起初rd_ptr_bin和wr_ptr_bin均为“0000”。此时FIFO中写入8个字节的数据。wr_ptr_bin =“1000”,rd_ptr_bin=“0000”。当然,这就是满条件。现在,假设执行了8次的读操作,使得rd_ptr_bin =“1000”,这就是空条件。另外的8次写操作将使wr_ptr_bin 等于“0000”,但rd_ptr_bin 仍然等于“1000”,因此FIFO为满条件。* I0 i) ?7 n( ]* t* e
    显然起始指针无需为“0000”。假设它为“0100”,并且FIFO为空,那么8个字节会使wr_ptr_bin =“1100”,, rd_ptr_bin 仍然为“0100”。这又说明FIFO为满。
8 ?4 k' P. H. o% z8 Q5 F    这个例子的意义就在它生动地说明了读/写指针怎样产生空/满标志的。我曾说过第一个方案是最好的?你到不如将其这种技术与同步FIFO一起使用。它可以避免算数运算,提高FIFO的速度。0 b. \) H' P( X' `& z! J

$ y4 ]7 v( x; ~: ?: J+ Q$ p1 ~" v3.3 实现
$ d; a+ j$ ^1 P* a7 s    我们知道在FIFO中要用到格雷码计数器。而不是用由格雷码换算的二进制码计数器(它不能实现每个计数器换后只有1位发生变化),必须使用真正的格雷码计数器。如果想实现格雷码计数,你会发现它并不像看起来那么容易。当然,你可以创建一个定制的机构来完成这项工作,但还是让我来提供一个更为普遍的解决问题的方法。大家知道格雷码于二进制码之间能够相互转换用到一个简单的公式:
, f" V5 R2 {# d5 S+ I7 S8 z二进制码转格雷码
5 Z3 T1 }3 W- Mgn=bn. {; X- u7 a0 J6 O
Gi=bi⊕bi+1 &#8704; i≠n  _6 a4 Q3 d+ L0 P) G2 D; ?
格雷码转二进制码: x  s- b! Z' d# W
bn=gn
, V7 Y# C5 g5 ]! `! z1 V, h' Rbi=gi⊕bi+1 &#8704; i≠n, J" H$ C1 M/ Y. G# d' R
    在上面的公式中,下标表示n+1位二进制码或格雷码的位数。
+ Z, t4 N: b- ~" A& x    我们还知道计数器不过是一个触发器组和一个累加器而已,我们可以按照下面的方法来做——将格雷码码元转换为二进制码元,然后加1,再它转换回格雷码并存储。这是解决产生n-bit格雷码算法棘手问题一个普遍的方法。由它生成的计数器如图3所示。6 v+ f  t( c# s4 _" c
http://www.dzkf.cn/upimg/userup/0902/260T5433A8.jpg ' `8 U6 N. N( ?5 Q1 h. C8 v6 u$ Q- k
    当用综合工具优化时,相信综合工具能够为格雷码计数器提供一个相当快速的电路。当然,如果希望拥有一个深度为32字节的FIFO时,可在格雷码编码的状态机中手工编写计数器代码。4 i/ @" c: m; J8 f$ I" d6 p2 j9 B
最终的FIFO设计如图4所示。这次我不再提供代码,因为我相信无论用VHDL或Verilog HDL编写,那都是一件非常容易的事。
9 R/ Z( y, n& Z8 a4 o- shttp://www.dzkf.cn/upimg/userup/0902/260T6223K0.jpg
7 W1 G1 M4 n* D8 j' c+ u    在这里我要补充一点:如果你观察图4,会注意到有4个格雷码~二进制码转换器,这并不浪费。但通过保留格雷码指针的低n-bit和二进制最高位将有可能避免使用这些转换器。这是一种“混合”计数器,我将它作为练习留给读者。$ E! K, Q: ^4 M! Z

1 m1 M4 V2 J% \0 H9 l3.4 时间考量
2 G8 Z" t/ h& ^/ l1 j    管理FIFO工作的首要时间条件是时钟的最高频率。在上述的FIFO条件下,不得不面对几个参量——时钟频率不能大于存储器所需频率,必须满足亚稳态时间关系tclk=20tcq+tsetup。当然,在公式中20这个因数完全凭借经验,倘若已经完成系统MTBF的计算,也可以选择其它值。另外,还应考虑格雷码计数器能够运行多快,因为上述公式要求受制于XOR(异或)门的速度。由于本文没有做任何设想(除了同步,而这并非真正意义上的设想),时间不会引起很多同样的问题。 在这个设计中最应考虑的是用格雷码计数器和同步时避免与亚稳态相关的错误。要认识到发生同步错误,整个FIFO将无法工作(2bit错误就将意味着在DPRAM中一个完全不同的地址,因为地址也用格雷码表示)——也就是FIFO即可以吃入数据也可以吐出数据。所以,我无法列出更多的要点,而这些要点都基于用户设计中MTBF值,要做好你所能承担的最坏的打算。 9 d+ T( f+ K2 N
译者注释:4 Q6 G! }. H$ |- b8 G1 M
[1] sample在这里翻译为“取样”,而不是“采样”、“抽样”,是想有别于奈奎斯特定理中抽样的概念。汉语中在触发器构成的电路里很少听到“取样”这种说法,但文中用到了sample一词,姑且译作“取样”,其实它表示了时序电路中两个信号相遇时的状态、稳定程度及先后关系。 , k- ]7 X9 ?! I' Q% {9 |  E
[2] 关于setup time 和hold time 借用北大的一个PPT来解释其意义。
0 t& ~3 m+ l$ I+ L" Y; ~
http://www.dzkf.cn/upimg/userup/0902/260U50334U.jpg
& c* @; `2 r4 M& [[3]实际中,MTBF与时钟频率也有关,若一个时钟为1MHz的系统其MTBF为10年,当时钟变为10MHz时,其MTBF有可能变为1秒钟。
- M& v! A: E; x6 |[4]最小距离码:码的距离定义为相邻两个码元之间互异元素的个数比如101010与110011,从左到右,互异的元素有,第2个,第3个,第6个,所以码距为3 。这种定义又称为码的汉明距离。格雷码相邻码只有一位不同,因此格雷码的距离为1。
  K  P1 ^1 s$ v7 j[5]原文为Pessimistic Reporting,字面翻译为悲观的报告,但综合上下文的意思来看,作者想表述的意思是宁少不多,宁慢不快。应该是一种出于保险的,保守的考虑,宁可少读一次FIFO ,也不让FIFO出错,顾翻译为“保守的报告”5 L2 B. ^- W. l
 楼主| 发表于 2009-11-27 14:47 | 显示全部楼层
在本系列文章的第一部分我们了解了FIFO的一般结构,并分析了单时钟FIFO的一个特例[1]。第二部分描述了双时钟设计的一种可能的结构。在第三部分我们将探究一种具有新颖结构的双时钟FIFO。这种结构未必更好——只是另一种实现的方法而已。
( i9 d: N( e# P3 C6 G/ j& r) y- ]& ?" C. x8 n( b6 J% A
1 工作原理
* Y$ f5 u3 e7 v) n+ q8 b' C1 ~    至此我们已经解决了用格雷码表示的不同时钟域的所有计算,包括多位二进制计算。本篇所介绍的结构与以往并没有什么不同,唯一的区别在判断引起读写指针相等条件的方法。
- R: a5 n6 F  h$ q$ _    如果还记得先前的文章,文中提到读写指针相等意味着无论是满条件还是空条件,依赖于读操作还是写操作导致了指针的相等。在同步FIFO的第一个例子中,这很容易判别,因为两种操作均与一个时钟有关。在第二种结构中,这个条件已被编码于指针中。我们现在将探究双时钟设计的第二种方法。
9 F  n" V% j3 \3 O$ \2 \* |$ v
/ ?: ^  e% I" L, A1.1 方向标志(Direction flags)
7 z; O  e; M& e) B- {. q    在这种结构中,我们让指针轨迹的标志相等。我们称其为“Direction flags(方向标志)”。这个标志告诉状态电路FIFO“当前朝向(headed)”。它假设写操作引起的FIFO朝越来越满的方向与读操作引起的FIFO朝越来越空的方向为FIFO的朝向。
0 M9 R/ ~- \- I; l7 E# g0 E9 L    不用说,每边(读操作或写操作)都必须保留独立的方向标志复本(copies)并且维持在保守状态。因此对于写操作一方将有其自己的方向标志来维护保守性。也就是,从读操作一方可能会看到写操作被延迟并且读操作一边也将维持方向标志,它可以根据延迟的写操作来计算。就像先前的双时钟结构,这将确认FIFO没有在吞或吐数据,但这样做是以FIFO尺寸动态缩小为代价的。
7 U. A/ l+ o# q3 o7 ~' a0 q    FIFO满/空标志的计算基于这些方向标志,其思想是如果FIFO的朝向为向越来越满的方向,并且指针相等,则FIFO真正为满。如果FIFO朝向越来越空的方向,并且指针相等,则FIFO确实为空。
7 m: K, d; u# |" J0 B5 {) R8 z6 Q& q+ F# ^( }% R, G) }
1.2 方向标志的实现
7 X1 l! _- F7 Y  X5 B' v    有很多不同的方法实现方向标志:一般的想法是当FIFO的字节计算超过某个预定上限,就认为FIFO“going towards full(趋向满) ”,当字节计算低于预定下限是,就认为FIFO“going towards empty(趋向空)”。4 O3 i+ a# M9 c4 Z
    一些设计人员选择“going towards full”的门限为FIFO容量的75%,“going towards empty”的门限为FIFO容量的25%。还有人选择两个门限都为FIFO容量的50%。也有选择80% 和20%的。门限的选择可由自己来决定,要根据设计选择最适合的门限。也可以根据时钟的速度与门限值得关系来确定以便使标志失效的可能性最小,但我不确定门限的选择会让设计的系统变得更好。我认为上限与下限之间有滞后或许更好(滞后的意思是上限与下限之间的差并且“going full”门限要大大超于“going empty”门限)。5 d$ p. \* B  W
    我们不妨选择FIFO容量的75%和25%作为门限。这样做比较有效,因为你只需比较指针的高两位就能决定是否越过门限。若用另一些值,你将不得不比较指针的所有位,而这有可能影响你所设计的系统的速度。像以前一样,写操作的一方可以看到写指针和一个被同步的读指针,两个指针均为格雷码。然后,将格雷码指针转换为二进制指针并计算出FIFO中有多少数据。如果FIFO中的数据量大于“going full”门限,就置位方向标志。当FIFO中的数据小于“going empty”门限,就清除方向标志。  x- @7 m) @1 c9 j  t+ K
    同理,读操作看到(格雷码的)读指针和一个被同步的(格雷码的)写指针。在完成格雷码到二进制码的转换后,计算FIFO中的字节数;如果字数小于“going empty”门限,就置位方向标志(此时方向标志的反指向(the opposite sense) 作为写操作一方的方向标志),当字数增加,大于“going full”门限时就清除方向标志。% ?+ V7 s; c2 \. H, h& s: Q3 v3 B
    记住,当选择75%和25%作为门限时,上述计算无需比较指针的全部位。只用指针的高两位就足够了。
0 u5 \- Z2 ~9 }7 \  G  K# O' t3 ?0 J
* X0 t1 t; ~. U8 A* t; i! N% Y6 \1.3 空/满的计算
7 ?. z7 H0 ?, Q* Z5 a; ]& y    在写操作一方,如果指针相等并且方向标志置位,则FIFO的满标志置位,同理,在读操作一方,如果方向标志置位并且指针相等,FIFO的空标志置位。注意,这意味着我们不排除空/满标志同时置位的可能性。尽管听起来不合常理,但对于FIFO是正确的条件。你也许会想FIFO怎么可能同时既满又空呢。然而如果你进一步分析,就会发现“满”只是一个写操作一方的流控制机构,“空”只是一个读操作一方的流控制机构。如果FIFO的读写操作两边的Blocks同时流动那么这就是正确的——它并未破坏存储器或指针。当FIFO真的不能再接收数据或当不能再提供更多的数据时FIFO没有报告是非常危险的。仔细分析以前所讲的结构,它证明这种可能性不排除存在于其它结构中。
3 u9 f( v' E' Q( i. C) ?4 W6 }    下面列出了计算方向标志每一边(读或写)的计算(注意公式中的指针已被适当的同步并且转换为二进制):1 @5 a( c# d& l0 \
word_count = wr_ptr - rd_ptr + 1            if wr_ptr > rd_ptr0 w7 L# @! H4 G: I( V
fifo_size - (rd_ptr - wr_ptr) + 1                 if rd_ptr > wr_ptr
0 Y) R9 V. q6 b  ^# @direction_flagwr = 1                                  if word_count > going_full_threshold0 w* \3 ?9 \2 s( Q8 u) w( T1 N
0                                                                    if word count < going_empty_threshold
9 F0 ~" ^/ J4 k8 n6 j( f  j; V1 ddirection_flagrd = 1                                   if word_count < going_empty_threshold( c$ {7 R, A; g' f
0                                                                    if word_count > going_full_threshold
" u1 h0 n9 i  u. B7 j/ B# W    如图1所示为75%和25%门限的特列。在这个特例中,上述字节计算公式仅需要二进制码指针的最高两位,并且不需要加1得到字数的精确值。只需知道是否越过门限而已。
( Y/ U5 Y  V$ n1 L+ O) j, L1 n! e    还要记住,在写操作和读操作一边的门限不必相同;可以根据读写时钟频率调整门限值以优化性能。
  U  P6 \6 l$ a$ T, p' W2 结论7 @' |' o/ e: y( D
    这种结构是在同步FIFO情况下提出的命题中的一种变异。这种同步FIFO是这个结构的一个特例——“going full”和“going empty”的门限分别等于(fifo_size-1)和1。
$ G  w0 T% X! A) U    这种结构的表现比先前所提到的异步结构有着明显的优点码?未必。在一些临界情况下,这种结构可能会有优势——对于时间紧张的情况下N-bit格雷码转换为二进制码也没有问题,但在N+1位(在先前的结构中需要的)格雷码情况下就没有这种优势,或当面积比较紧张的时候为了N+1位转换而占用额外的面积这种结构就不适用了。我的观点是,它们都是真正的非常优秀的结构,因此选择哪种结构取决于你的偏好。! Y1 `5 Y, n$ Z) T, \
http://www.dzkf.cn/upimg/userup/0902/260Z15943U.jpg / Q7 _; e. D3 ~7 j" M- _7 Z
< The end>
 楼主| 发表于 2009-11-27 14:52 | 显示全部楼层
一种基于格雷码的异步FIFO设计与实现, {. h' I, ^& L* G9 x

* _$ m! c) {6 p' u1 引言
9 ]' B& O- h7 F: r; Y    FIFO(First IN First Out)先进先出电路是一种实现数据先进先出的存储器件,普遍用作数据缓冲器。FIFO的基本单元是寄存器,作为存储器件,FIFO的存储能力是由其内部定义的存储寄存器的数量决定。
9 Z! t- ^$ f9 F/ s: G    FIFO通常是双端口的存储器,其中一个端口用于写入数据,而另一个端口用于读出数据。可以同时对存储器字存储单元进行写入和读出操作。它的数据吞吐率是普通RAM的两倍。FIFO型的存储器不需要由地址来存取数据。需要由另外的信号线(或标志)来指明存储器的内容状态。- `1 P" j5 A/ {& ^* N
    在现代数字系统设计中,FPGA(现场可编程门阵列)器件凭借其灵活、方便、资源丰富的优势在很多领域得到了广泛应用。随着其片内存储资源的增加,把FIFO器件集成到其中是一种方便地代替专用芯片的实现方法。根据异步逻辑的设计方法,引入乒乓操作的设计技巧,给出了一种新颖的异步FIFO设计方案,解决FPGA多时钟系统中不同时钟域传输数据的问题。$ Y- t7 k0 ~& ]& ~: Y7 _4 r
2 异步FIFO的设计与实现
1 K  G4 S+ q) \5 w3 h$ R
2.1 通用异步FIFO的基本结构0 ~" j' ^6 N9 ]. c% y, k
    在现代的集成电路芯片中,随着设计规模的不断扩大,一个系统中往往含有数个时钟。多时钟域带来的一个问题就是,如何设计异步时钟之间的接口电路。异步FIFO是解决这个问题一种简便、快捷的解决方案。使用异步FIFO可以在两个不同时钟系统之间快速而方便地传输实时数据。在网络接口、图像处理等方面,异步FIFO得到了广泛的应用。
5 d  F# O, x5 e1 a& U+ i    异步FIFO常用于存储、缓冲在两个异步时钟之间的数据传输。在异步电路中,由于时钟之间周期和相位完全独立,因而数据的丢失概率不为零。如何设计一个高可靠性、高速的异步FIFO电路便成为一个难点。下面将介绍解决这一问题的一种方法,其结构框图如图1所示。; r6 Q0 W2 ~, ^, Z, Q
http://www.dzkf.cn/upimg/allimg/0802/1_18121001.JPG
" C% {+ I0 R' T7 g    本系统FPGA内部FIFO的存储介质是一块双端口的RAM,具有两个独立的读写时钟,整个系统也分为两个完全独立的时钟域——读时钟域和写时间域。FIFO的控制逻辑执行所有的读写指针管理,产生各种状态标志。在写时钟域部分,由写地址产生逻辑产生写控制信号和写地址;读时钟域部分由读地址产生逻辑产生读控制信号和读地址。在空/满标志产生部分,由读写地址相互比较产生空/满标志。本设计的外部引脚如表1所示。' Z$ Z. M6 I( ^- r" |+ y
http://www.dzkf.cn/upimg/allimg/0802/1_18121034.JPG ( w9 t1 a/ j1 ]7 |( _. i3 V
    这种FIFO设计当中有两个难点:一是如何正确地设计空、满信号的控制电路;二是如何同步异步信号,使触发器不产生亚稳态。下一小节将具体阐述解决方法。; t5 z: {! q# o! B1 [; L+ O8 V" w

! Q+ q6 D6 h4 ~5 Y- `* N. ?6 h2.2 FIFO的读写控制+ p3 N) g' E" Z" f4 w0 Y0 _
    空/满标志的产生是FIFO的核心部分,如何正确设计这部分逻辑,直接影响到FIFO的性能。空/满标志产生的原则是:写满不溢出,读空不多读。即无论在什么时候,都不应出现读写地址同时对一个存储器地址操作的情况。在读写地址相等或相差一个或多个地址的时候,满标志应该有效,表示此时FIFO已满。在满信号有效时若继续向FIFO写数据,应根据设计的要求对数据作保持或抛弃重发处理,空标志的产生也是如此。6 g8 A8 L& L# B4 x4 M/ D
    最直接的做法是,采用读写地址相比较来产生空满标志。当读写地址的差值等于一个预设值的时候,空/满信号被置位。这种实现方法逻辑简单,但它是减法器形成的一个比较大的组合逻辑,因而限制了FIFO的速度。所以,一般只采用相等不相等的比较逻辑,避免使用减法器。即:
5 j: G- Z' C$ G) a9 _空标志<=(|写地址-读地址|<=预定值)AND(写地址超前读地址)" i4 L" @. v5 n, {. W
满标志<=(|写地址-读地址|<=预定值)AND(读地址超前写地址)
7 l7 v! s6 c! G, y9 g1 u( l    另一种方法是,比较器只对读写地址比较是否相等。在读写地址相等的时候有两种情况:满或者空。所以,附加了一个并行的区间判断逻辑来指示是空还是满。这个区间判断逻辑将整个地址空间分为几个部分,以指示读写地址的相对位置。这种做法提高了整个电路的速度,但是也有其缺点。主要是直接采用读写地址等于不等于的比较逻辑来进行空/满标志的判断,可以带来误判。& O. A5 ^) b7 O0 O6 i+ @7 X/ d
    将读写指针位宽分别定义为:rp[aw:0]和wp[aw:0],其中rp[aw]和wp[aw]为最高位进位位,rp[aw-1:0]和wp[aw-1:0]分别表示读写指针寻址的地址。当读写指针每次从初始地址处读写到最后一位地址位时,均需向最高位rp[aw]和wp[aw]进位。因为先有写才能有读,所以当wp[aw-1:0]=rp[aw-1:0]时,只要判断wp[aw]与rp[aw]是否相等就可以知道是写指针追赶上读指针写满了(wp[aw]!=rp[aw]),还是读指针追赶上写指针读空了(wp[aw]=rp[aw])。rp_pl1和wp_pl1分别定义为读写指针的下一个地址,而且为了在判断空满标志时对读写指针进行同步比较,设计中定义了与rd_clk同步的写指针wp_s以及与wr_clk同步的读指针rp_s,这两个信号可以通过同步逻辑来实现。
" w+ b: t3 c" @9 W1 ]  p4 y( H% j/ H9 z# Y$ q
2.3 跨时钟域设计带来的亚稳态问题: P" E+ |4 _0 e0 y) f) g% Z( s$ e
    亚稳态(Metastability)是指触发器信号和时钟不满足建立时间/保持时间(setup/hold)的基本要求,触发器的输出端将会达到一个不确定的状态。当一个触发器进入亚稳态时,既无法预测它的输出电平,也无法预测其输出何时才能稳定在某个正确的电平上。在这期间,触发器输出一些中间级电平,或者可能处于振荡状态,并且这种无用的输出电平可以沿信号通道上的各个触发器级联式传播下去。当一个信号跨越某个时钟域时,接收该信号的电路需要对其进行同步,用以防止前级存储单元(触发器)的亚稳态在新的时钟域里传播蔓延。2 R6 d# m2 [9 \  ~: ~) V; J' y; X
    在本系统中内部工作时钟有两个互相异步的不同频率时钟,并且在两个时钟域的逻辑模块之间有许多控制信号需要传递,亚稳态是不可避免的,但是下面的设计可以将其发生的概率降低到一个可以接受的程度。
' L: P% p! |" D5 r( H8 V, J$ F①对写地址/读地址采用格雷码。由实践可知,同步多个异步输入信号出现亚稳态的概率远远大于同步一个异步信号的概率。对多个触发器的输出所组成的写地址/读地址可以采用格雷码。由于格雷码每次只变化一位,采用格雷码可以有效地减少亚稳态的产生。
2 Q& o$ G  v7 o②采用两极触发器来同步异步输入信号。信号同步的目的是防止新时钟域中第一级触发器的亚稳态信号对下级逻辑造成影响。两级寄存器的同步化处理单元由两个触发器串联而成,中问没有其它组合电路。这种设计可以保证后面的触发器获得前一个触发器输出时,前一个触发器已退出了亚稳态,并且输出已稳定。但是,这种方法同时带来了对输入信号的一级延时,需要在设计时钟的时候加以注意。
: R1 U0 Y- @7 e  W0 _0 l' u    虽然亚稳态是不可避免地,但是采用格雷码可以有效地减少亚稳态的产生。由前面的分析可以看出,由地址直接相减和将地址相互比较产生空/满标志都不可取。如何简单地进行直接比较,又不提高逻辑的复杂程度呢?对地址加延时可以做到这一点。" y& t' `( G# V  Z$ b7 B7 X
http://www.dzkf.cn/upimg/allimg/0802/1_18121118.JPG  
4 O/ [3 K& `" S/ l0 {    设读地址为rp_bin,用读地址产生读地址格雷码rp_grap_next,将rp_grap_next延一拍得到rp_grap,再将rp_grap延一拍得到rp_grap_x。在绝对时间上,rp_grap_next、rp_grap、rp_grap_x先后从大到小,相差一个地址,如图2所示。写地址也与此类似,即:wp_grap_next、wp_grap、wp_grap_x。利用这6个地址进行比较,同时加上读写使能,就能方便而灵活的产生空/满标志。
& V% F* A$ J/ F' X2 w9 ?( D    以空标志empty产生为例,当读写格雷码地址相等或者FIFO还剩下一个深度的字,并且正在不空的情况下执行读操作,这时empty标志设置为有效。即:empty<=(rp_gray==wp_gray)and(re== 1)或empty<=(rp_gray_next==wp_gray)and(we==1),同理可类推满标志的产生逻辑。
  F9 s& m! H' I5 x# `' L# y3 Verilog实现与仿真
) k3 P" @3 }1 M7 N( l% G$ _    本设计完成了一个完整的规格为256×8双时钟通用异步FIFO的Verilog建模,并对该设计的编写测试向量进行行为级仿真,仿真工具采用ModelSimSE6.0。图3给出了整个电路的仿真时序图。分析上面读写时序图中各状态变化和数据的传输情况,验证各状态信号时序正确,逻辑正确,功能仿真结果正确,整个的工作波形也符合设计要求。
, u. w* H* ^- p9 ]图3 双口异步FIFO读写仿真波形
9 Y: v0 I& H) Z) ^3 ?    最后,用Synplify7.6 Pro软件进行综合,器件为Altera的EP1C6Q240C8。一般标志产生电路(用减法器,设阈值)和基于格雷码的标志产生电路,设计结果性能指标对照表如表2所示。 8 U- T5 c  {  B# y  B& |) z) u
http://www.dzkf.cn/upimg/allimg/0802/1_18121147.JPG  2 `( {. [" f( Q  H1 y, H& \( E
    由表2可知,带区间指示逻辑设计的双时钟通用FIFO的特点是直接对读写指针地址进行比较,并通过辅助的区间指示来判断FIFO的读空与写满。这种方法正如前面所说的,因为避免了地址的减法比较,所以减少了逻辑的复杂度,提高了系统的速度,但是也容易出现一定的误判断现象,而且由于双时钟FIFO出现异步的情况,容易产生亚稳态现象,这种方法亦不能很好地解决。我们可以通过设计格雷码双时钟通用FIFO来较好地处理亚稳态的问题,提高了系统的稳定性。但是不可避免地,较之一般方式的FIFO来说,需要有更多的逻辑单元,需要用更长的数据传输时间。8 l5 n! T9 J" v9 k
4 总结2 X' ~4 k- e' H0 v! a
    本文提出了一种新颖的用FPGA实现异步FIFO并作为异步时钟域数据传输的接口电路的方法,特别详述了空、满信号的产生。按此方案设计的异步FIFO的软件仿真和硬件实现都已经通过了验证,并应用到实际的电路。实践证明用此方案设计的异步FIFO具有性能稳定、空满状态标志可靠等特点。

本版积分规则

QQ|一淘宝店|手机版|商店|电子DIY套件|一乐电子 ( 粤ICP备09076165号 ) 公安备案粤公网安备 44522102000183号

GMT+8, 2024-5-18 22:03 , Processed in 0.061717 second(s), 31 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表