EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
大侠好,欢迎来到FPGA技术江湖。本系列将带来FPGA的系统性学习,从最基本的数字电路基础开始,最详细操作步骤,最直白的言语描述,手把手的“傻瓜式”讲解,让电子、信息、通信类专业学生、初入职场小白及打算进阶提升的职业开发者都可以有系统性学习的机会。
6 m1 H; w, r9 E8 p
系统性的掌握技术开发以及相关要求,对个人就业以及职业发展都有着潜在的帮助,希望对大家有所帮助。本次带来Vivado系列,FIFO使用教程。话不多说,上货。
* Z$ L! G3 d0 n [" \
FIFO使用教程
5 A* s$ D* ]4 z8 s
FIFO的英文全称叫做First in First out,即先进先出。这也就决定了这个IP核的特殊性,先写进去的数据优先被读出,所以,FIFO是不需要地址信号线的,这也是它的一大特点,通常用来做数据的缓存,或者用来解决高速异步数据的交互,即解决了跨时钟域的问题。此外,FIFO还有一个特点,就是数据被读出之后就不存在了,不像RAM和ROM一样,数据被读出后还存在。所以我们如果想进行多次的读,那么就需要进行同样次数的写。
. S* v# ]9 B8 \. m2 I9 y5 w
FIFO分为同步时钟和异步时钟,同步FIFO指的是读写使用同一个时钟,在时钟沿信号来的时候进行读写。异步FIFO是指读写在不同时钟下进行,这样我们可以实现读写不同速度。 4 s2 o/ _ u9 y
那么接下来,我们就来实现一下异步FIFO的读写过程。 1 c% n/ K, j2 A7 b: x) w
- F, \0 v9 c( T
! N7 Z: R3 o5 ]- I ?
上图为选择异步FIFO之后的图示,在这个图示中,我们给大家解释一下每个信号的含义。
M0 z1 V! L: [( _, d
FIFO_WRITE: ! \0 G: T) ?1 j) E
full:FIFO的满信号,当FIFO的存储空间写满了之后,此信号拉高,否则为低。此信号为FIFO的输出信号。 / r" L O" ?$ E0 h' f4 E8 M
din[17:0]:FIFO的数据输入,写进FIFO的数据通过此信号线进入FIFO。 . G& [8 I$ h" m+ v8 d! n6 B9 |
wr_en:FIFO的写使能,当我们要往FIFO里面写入数据时,拉高此信号。此信号为FIFO的输入。
; d6 W, P! r4 ?9 t2 C$ ^
FIFO_READ: - |3 `( N7 L8 J$ y3 ^; H
empty:FIFO的空信号,当FIFO的存储空间空了之后,此信号拉高,否则为低。此信号为FIFO的输出信号。
4 P0 n9 f. {' T5 N6 m. N
dout:FIFO的数据输出,读出FIFO的数据通过此信号线输出。 " l( T& P' `. ?4 v$ G. W& G
rd_en:FIFO的读使能,当我们要从FIFO里面读出数据时,拉高此信号。此信号为FIFO的输入。
. A [" e' n4 o6 K# b" N$ |
rst:FIFO复位,默认高电平有效。
" l. P7 j4 d* W9 W3 ]' {. F( O- J
wr_clk:写时钟
1 h$ P3 u+ H+ z# z
rd_clk: 读时钟 2 B& g0 d: z% ?2 K2 _, q L
wr_rst_busy:写复位忙信号 / a' }& q4 [* S5 a' i
rd_rst_busy:读复位忙信号
9 t- n! }0 i) o$ v) A% G" D
在了解了FIFO的端口之后,我们来实现一个应用实例。比如,我们以10MHz的速度往FIFO里面写数据,写满之后,在20MHz的时钟下将数据读出,一直读空。当然,在显示应用中,FIFO的读写是可以同步进行的。 " ^! c0 {2 U4 a" C# w& @
首先,我们先来新建工程。 % \' J0 G) a8 k3 @" D) G8 M7 [
新建好之后,我们先调用一下IP核:
6 i" B2 {' l0 I& i6 ]. L
9 Q1 x; R6 S9 n% V# f, k
2 B/ n& Q$ ^. M# m T/ R2 A
在IP核管理器界面,搜索FIFO,然后选中图示所选项双击打开。
5 ~2 N% c/ S: O7 s8 x u/ C6 L
5 W- W4 k6 @4 i( D
+ L u N5 Q8 N! ~0 Q7 |, G( t
在FIFO类型选项,我们选择异步FIFO。刚打开默认的选项为同步FIFO。
6 U9 w, w+ r4 a4 d, R
9 t4 r% g. g) I$ f1 _8 f8 X' Q3 x: K1 ~3 j# O+ D- c, T4 D- K+ L" y
& Y& W7 x3 p+ B a2 F' f
在数据端口配置界面,我们将数据位宽改为8bit,深度使用1024。
5 |5 P8 Y! b- w6 A# ^4 X' F
复位端口在这就不再使用了,所以勾选位置取消掉。 . v: L: y) k" v. f$ c4 A
, `3 g( }& C: p8 T& |) R* q0 j; u* V/ |$ k2 Z. ^% G9 g
在此界面出现了almost full flag和almost empty flag。这两个信号是几乎满或空的标志信号,在此实验中,我们不使用。 ! h( y' c# f4 L% u3 ?/ R4 G
x" o( C# l F" O. d1 f4 ~ ^, a* I
" v% V% Z* k* k( E2 y1 B* t( p$ q
Data count是FIFO数据用量计数器,代表了此时FIFO的内部存储被使用的情况。假设我们写进去了10个数,那么两个计数器都为10。
, ]' l, ?! m; C5 d6 A" l$ }2 ?* t: p! X/ o3 X; G: z/ \, D. C5 n$ J
1 A9 T% w7 u* J
此界面为IP核的信息,在此界面可以看出,我们的读写深度发生了变化,我们在前面设置的深度为1024,但是在此处显示的却是1023。原因是因为FIFO结构的特殊性,并不是我们设置的有问题。所以,在我们这个异步FIFO中,深度为1023。 9 B5 v8 s5 v" T1 u# C
8 r- z* q/ j" d( e: i
& E5 P& ^- t: T0 k7 Y* a+ ]
! f- Z# K/ _3 R1 E4 f: f$ ^
点击OK直接生成。在点击Generate。
' W& q! w2 I1 t: k/ s! T; ?
此外,我们还需要两个不同时钟,在这里我们使用锁相环生成。 ( {! X4 U5 l+ m( }% W& ^- o
* k) Z6 d+ p* W* Z+ s. y) q+ N# q' ?# H) ?; Q( v
在管理界面搜索clock。配置过程我们在此前已经讲过,就不在过多叙述。 $ D% B# }4 r6 I p
接下来我们写一下fifo的写控制器,代码如下:
# Z8 g/ w, u0 M `
7 T7 [% x- F9 h因为我们的实验是读空了才写,所以我们用状态机来做,先判断FIFO是否为空。读控制器代码如下: % F6 R6 A* L Q9 Y9 z( {& p# T
顶层代码如下:
" J; \+ l& h: i3 w, p
代码写完之后,我们写个仿真验证一下波形,代码如下:
# N G- \$ H6 w+ R+ ~8 V X3 P
打开波形之后,我们将读写控制模块的信号全部添加到波形窗口: 添加好之后,点击restart和run-all & Q4 W/ m" Z1 r( D. b
由于波形默认运行10us,我们观察不到全部波形,所以,在此我们继续点击run-all,然后点击break,让仿真停止。
& v4 Z8 V" S2 g1 U6 e
- r. u+ v7 ~' X' v& Z- W' n0 _( V5 ?5 D3 S. P; e" Q& Y1 s7 v
然后,我们观察波形:
* [4 j/ @ D/ f0 n4 \% w
( {, M: A' N: ?$ p$ E
8 D; L( w! D% w! W
在波形里面可以清楚的看到我们的fifo_data_in和q的波形,一长一短。这是因为读的速度快,所以波形维持的时间短。写数据的时间长度是读数据时间长度的两倍。 ( I' S5 s1 \/ q; `% r
, `) M5 j! r. g' V7 l% x! ^3 ?
然后放大波形观察其他信号: J. ]8 s( A6 P* r! t
2 j' D: O# A& c3 [+ p+ ]. [
% l3 s) W# D& r" m) q
在黄色光标位置,可以看到满信号拉高了,然后写使能就拉低了,状态开始进入到读。在读使能拉高之后,输出q就有了数据,但是我们的empty信号维持了一段时间才拉低,这是因为fifo的特殊结构导致的,在此我们就不再过多讨论。 ' x" U2 d2 b& f
" r( g. Q' g0 a1 v# s! }2 |
结论:异步FIFO控制正确,仿真波形输入和输出信号正常。
) I& X- ~) Z2 \ |