第一次接触FPGA 至今已有10多年的时间,至今记得当初第一次在EDA实验平台上完成数字秒表、抢答器、密码锁等实验时那个兴奋劲。
" v$ E! h. D' p; W: `: v
当时由于没有接触到HDL硬件描述语言,设计都是在MAX+plus II原理图环境下用74系列逻辑器件搭建起来的。
: O% v! Z5 E3 J4 O. l
后来读研究生,工作陆陆续续也用过Quartus II、FoundaTIon、ISE、Libero,并且学习了verilog HDL语言,学习的过程中也慢慢体会到verilog的妙用,原来一小段语言就能完成复杂的原理图设计,而且语言的移植性可操作性比原理图设计强很多。
在学习一门技术之前我们往往从它的编程语言入手,比如学习单片机时,我们往往从汇编或者C语言入门。所以不少开始接触FPGA的开发人员,往往是从VHDL或者Verilog开始入手学习的。但我个人认为,若能先结合《数字电路基础》系统学习各种74系列逻辑电路 ,深刻理解逻辑功能,对于学习HDL语言大有裨益,往往会起到事半功倍的效果。
, F" C7 P0 U& G# i0 ^; W& t
当然,任何编程语言的学习都不是一朝一夕的事,经验技巧的积累都是在点滴中完成,FPGA设计也无例外。下面就以我的切身体会,谈谈FPGA设计的经验技巧。
1.硬件设计基本原则。
0 i# c4 q# q) Y2 NFPGA(Field-Program mable Gate Array),即现场可编程门阵列,它是在PAL、GAL、cpld 等可编程器件的基础上进一步发展的产物。它是作为专用集成电路领域中的一种半定制电路而出现的,既解决了定制电路的不足,又克服了原有可编程器件门电路数有限的缺点。
! o5 c; b3 a( N
速度与面积平衡和互换原则:
1 P7 I3 B8 X( ^+ L9 [2 h9 }5 d5 _• 一个设计如果时序余量较大,所能跑的频率远高于设计要求,能可以通过模块复用来减少整个设计消耗的芯片面积,这就是用速度优势换面积的节约;
* E! X$ }" M5 O9 A反之,如果一个设计的时序要求很高,普通方法达不到设计频率,那么可以通过数据流串并转换,并行复制多个操作模块,对整个设计采用“乒乓操作”和“串并转换”的思想进行处理,在芯片输出模块处再对数据进行“并串转换”。从而实现了用面积复制换取速度的提高。
; B! X& l) y( M
• 硬件原则:理解HDL本质。
6 n" C: h) U- V+ P5 Z, e# k) b• 系统原则:整体把握。
% [) O6 Q& d9 J
• 同步设计原则:设计时序稳定的基本原则。
$ X) C- O& G2 `* W2.Verilog作为一种HDL语言,对系统行为的建模方式是分层次的。
" E8 b0 T. j' r, [' z) T, [% Z比较重要的层次有系统级、算法级、寄存器 传输级、逻辑级、门级、电路开关级。
0 v1 S" A1 A1 y1 m+ S( R3.实际工作中,除了描述仿真测试激励时使用for循环语句外,极少在RTL级编码中使用for循环。
这是因为for循环会被综合器展开为所有变量情况的执行语句,每个变量独立占用寄存器资源,不能有效的复用硬件逻辑资源,造成巨大的浪费。一般常用case语句代替。
7 v. g! A6 b. T+ H
4. if…else…和case在嵌套描述时是有很大区别的。
0 v# _7 {6 e0 G8 w, h6 }, Nif…else…是有优先级的,一般来说,第一个if的优先级最高,最后一个else的优先级最低。而case语句是平行语句,它是没有优先级的,而建立优先级结构需要耗费大量的逻辑资源,所以能用case的地方就不要用if…else…语句。
4 E0 Q0 F& F1 I8 t7 x: Z3 O
补充:1.也可以用if…; if…; if…;描述不带优先级的“平行”语句。
, `8 _$ x9 |7 e- @/ j5.FPGA一般触发器资源比较丰富,而CPLD组合逻辑资源更丰富。
' e+ ], z; y) q' R. Z
6.FPGA和CPLD的组成。
, Y* O; o5 c- Q7 w0 F
FPGA基本有可编程I/O单元、基本可编程逻辑单元、嵌入式块RAM、丰富的布线资源、底层嵌入功能单元和内嵌专用硬核等6部分组成。
7 b6 _* ^: A9 L- y% g$ e( ] HCPLD的结构相对比较简单,主要由可编程I/O单元、基本逻辑单元、布线池和其他辅助功能模块组成。
, a$ W% _* R6 `% s6 s7.Block RAM.
4 M( f1 _) O6 W+ B7 c3种块RAM结构,M512 RAM(512bit)、M4K RAM(4Kbit)、M-RAM(64Kbit)
• M512 RAM:适合做一些小的Buffer、FIFO、DPRAM、SPRAM、ROM 等;
9 h: k: A) a$ [) ]9 v2 S2 E• M4K RAM:适用于一般的需求;
, I) {2 C) e6 J/ p0 D• M-RAM:适合做大块数据的缓冲区。
/ L& v9 c# a2 @* O0 K8 e" N" N0 t
Xlinx 和Lattice FPGA的LUT可以灵活配置成小的RAM、ROM、FIFO等存储结构,这种技术被称为分布式RAM。
% w; K; C; ~9 E% w/ A i0 B补充:但是在一般的设计中,不提倡用FPGA/CPLD的片内资源配置成大量的存储器,这是处于成本的考虑。所以尽量采用外接存储器。
& p7 Q5 ]1 P5 v* `0 a& V8.善用芯片内部的PLL或DLL资源完成时钟的分频、倍频率、移相等操作。
0 a) q4 g: X! `+ d8 \# M
不仅简化了设计,并且能有效地提高系统的精度和工作稳定性。
6 }% }, ?; r5 R( [& A* K1 V' z- s
9.异步电路和同步时序电路的区别
9 y, I% T# a# Y- ]! A
异步电路:
( W+ T) ^* a; S0 C• 电路核心逻辑有用组合电路实现;
1 {4 A) ^1 s9 F& C7 f• 异步时序电路的最大缺点是容易产生毛刺;
$ X" v( c& h2 m7 ~. o1 f8 [• 不利于器件移植;
- k+ L0 I* K/ ]* E' V- }) w6 k• 不利于静态时序分析(STA)、验证设计时序性能。
6 I3 t6 Q* o: T" m7 T! ~7 Q$ G
同步时序电路:
• 电路核心逻辑是用各种触发器实现;
5 B& \& S* P i) H5 ^• 电路主要信号、输出信号等都是在某个时钟沿驱动触发器产生的;
7 g8 J% U0 u- I: \; N9 y: r b) X
• 同步时序电路可以很好的避免毛刺;
4 e- [/ I) b; D7 L1 @ K* p6 f
• 利于器件移植;
! a* _2 g, d" G" d0 X3 N
• 利于静态时序分析(STA)、验证设计时序性能。
- Z) \6 ]1 M; ]8 D
10.同步设计中,稳定可靠的数据采样必须遵从以下两个基本原则
+ r+ w) T: I4 q/ s
1)在有效时钟沿到达前,数据输入至少已经稳定了采样寄存器的Setup时间之久,这条原则简称满足Setup时间原则;
8 ?( g2 X5 ]# G0 t; L2 z2)在有效时钟沿到达后,数据输入至少还将稳定保持采样寄存器的Hold时钟之久,这条原则简称满足Hold时间原则。
# W3 L- B5 b- n0 r
11.同步时序设计注意事项
* s# T# U2 ^$ {& e2 b! V1 A2 A
• 异步时钟域的数据转换。
4 S3 k0 u0 o/ B3 H% M# k8 C s
• 组合逻辑电路的设计方法。
/ o( c7 {& z- w% h. g, m
• 同步时序电路的时钟设计。
S5 A0 S- N/ y同步时序电路的延迟。同步时序电路的延迟最常用的设计方法是用分频或者倍频的时钟或者同步计数器完成所需的延迟,对比较大的和特殊定时要求的延时,一般用高速时钟产生一个计数器,根据计数产生延迟;对于比较小的延迟,可以用D触发器打一下,这样不仅可以使信号延时了一个时钟周期,而且完成了信号与时钟的初次同步。
在输入信号采样和增加时序约束余量中使用。
* I; X! D/ `5 y, ~7 W5 t另外,还有用行为级方法描述延迟,如“#5 a《=4’0101;”这种常用于仿真测试激励,但是在电路综合时会被忽略,并不能起到延迟作用。
r4 k, o4 |- L. b, @
Verilog 定义的reg型,不一定综合成寄存器。在Verilog代码中最常用的两种数据类型是wire和reg型,一般来说,wire型指定的数据和网线 通过组合逻辑实现,而reg型指定的数据不一定就是用寄存器实现。
. V' F! l: \2 t0 J12.常用设计思想与技巧
4 N" i$ A- v2 s. S% N2 j+ r
1)乒乓操作;
: Y, K6 c& J- y: [2)串并转换;
5 w$ g2 l# Q, ~* }- K: S& b
3)流水线操作;
$ o# c; W# t& L5 {2 O4)异步时钟域数据同步。是指如何在两个时钟不同步的数据域之间可靠地进行数据交换的问题。数据时钟域不同步主要有两种情况:
9 f# z: a) ^3 W5 T1 B①两个域的时钟频率相同,但是相差不固定,或者相差固定但是不可测,简称为同频异相问题。
+ I5 k" N, p8 R- d
②两个时钟频率根本不同,简称异频问题。
两种不推荐的异步时钟域操作方法:一种是通过增加Buffer或者其他门延时来调整采样;另一种是盲目使用时钟正负沿调整数据采样。
13.模块划分基本原则
! Y; k8 t1 g1 c3 \6 L/ @% Z4 O1)对每个同步时序设计的子模块的输出使用寄存器(用寄存器分割同步时序模块原则)。
2)将相关逻辑和可以复用的逻辑划分在同一模块内(呼应系统原则)。
, {( o6 }' ]# R+ j3 ^2 |& [
3)将不同优化目标的逻辑分开。
( r3 H2 S# }$ Z6 z; Y( v. N
4)将送约束的逻辑归到同一模块。
# Y4 Z7 O4 a( l' Y+ o) B$ T5)将存储逻辑独立划分成模块。
; ~& n" \/ x1 s$ q1 [% x6)合适的模块规模。
7 f( m v7 s, Y& i7)顶层模块最好不进行逻辑设计。
; g/ l4 X( } x( G# K1 `) g14.组合逻辑的注意事项
* o' e( l) e" ~, q: p# `; F1)避免组合逻辑反馈环路(容易毛刺、振荡、时序违规等)。
3 U2 j4 ?1 Q0 a, V6 f: \
解决:A.牢记任何反馈回路必须包含寄存器;B.检查综合、实现报告的warning信息,发现反馈回路(combinaTIonal loops)后进行相应修改。
+ r' h2 P) I5 ?: a1 B2)替换延迟链。
7 W$ y/ b! @9 t
解决:用倍频、分频或者同步计数器完成。
5 h3 K/ r1 Z" E r) X2 }/ M, r3)替换异步脉冲产生单元(毛刺生成器)。
+ o+ [9 ] l9 y8 z9 C3 H4 B' @. e
解决:用同步时序设计脉冲电路。
4)慎用锁存器。
1 r5 O9 K. _) O' V3 O2 a
解决方式:
% A" S3 `: ~; [ x3 h- U
A、使用完备的if…else语句;
; P9 j# d0 P# G# j
B、检查设计中是否含有组合逻辑反馈环路;
8 v& P' D1 Y3 H+ e/ SC、对每个输入条件,设计输出操作,对case语句设置default 操作。特别是在状态机设计中,最好有一个default的状态转移,而且每个状态最好也有一个default的操作。
- t) |$ U* x: Q( J+ b: F' pD、如果使用case语句时,特别是在设计状态机时,尽量附加综合约束属性,综合为完全条件case语句。
0 v+ l( o% s4 B- N7 m v8 |5 X
小技巧:仔细检查综合器的综合报告,目前大多数的综合器对所综合出的latch都会报“warning”,通过综合报告可以较为方便地找出无意中生成的latch。
9 |6 V! K( N: r2 p2 x7 {! V
15.时钟设计的注意事项
2 ?5 n6 \) ~4 D7 u! y' A% h; _7 l同步时序电路推荐的时钟设计方法:时钟经全局时钟输入引脚输入,通过FPGA内部专用的PLL或DLL进行分频/倍频、移相等调整与运算,然后经FPGA内部全局时钟布线资源驱动到达芯片内所有寄存器和其他模块的时钟输入端。
5 `1 T7 H. \* G9 O* ~
FPGA设计者的5项基本功:仿真、综合、时序分析、调试、验证。
9 n( K( a& c+ F7 |0 [( b& T$ X
对于FPGA设计者来说,练好这5项基本功,与用好相应的EDA工具是同一过程,对应关系如下:
1. 仿真:Modelsim, Quartus II(Simulator Tool)
. d3 S/ s1 ]# z; Y) [1 D2. 综合:Quartus II (Compi ler Tool, RTL Viewer, Te chnology Map Viewer, Chip Planner)
g# P J5 ?# Y+ R. w: u8 E3. 时序:Quartus II (TImeQuest Timi ng Analyzer, Technology Map Viewer, Chip Planner)
' K$ h' {: k' n* X6 A+ ?3 n
4. 调试:Quartus II (SignalTap II Logic Analyzer, Virtual JTAG, Assignment Editor)
8 ^8 l9 M2 e$ H: Z0 n3 T5. 验证:Modelsim, Quartus II(Test Bench Template Writer)
) g1 F; I P$ f/ a9 A1 \掌握HDL语言虽然不是FPGA设计的全部,但是HDL语言对FPGA设计的影响贯穿于整个FPGA设计流程中,与FPGA设计的5项基本功是相辅相成的。
1 D4 O: Q8 S0 n$ }. B对于FPGA设计者来说,用好“HDL语言的可综合子集”可以完成FPGA设计50%的工作——设计编码。
! b! M; j. R) F3 M, q
练好仿真、综合、时序分析这3项基本功,对于学习“HDL语言的可综合子集”有如下帮助:
% c' C; x! _& D* ]; H7 P• 通过仿真,可以观察HDL语言在FPGA中的逻辑行为。
2 `) w6 [9 J& j! P) d
• 通过综合,可以观察HDL语言在FPGA中的物理实现形式。
8 L+ U5 n2 i0 N* S1 C+ y+ N
• 通过时序分析,可以分析HDL语言在FPGA中的物理实现特性。
对于FPGA设计者来说,用好“HDL语言的验证子集”,可以完成FPGA设计另外50%的工作——调试验证。
/ W% t2 D) O2 O; T
1. 搭建验证环境,通过仿真的手段可以检验FPGA设计的正确性。
$ Z0 E# c. R# e! D6 N5 @1 E( T3 Z2. 全面的仿真验证可以减少FPGA硬件调试的工作量。
; ^5 q# A& E/ ?& C
3. 把硬件调试与仿真验证方法结合起来,用调试解决仿真未验证的问题,用仿真保证已经解决的问题不在调试中再现,可以建立一个回归验证流程,有助于FPGA设计项目的维护。
5 ?) ~! _# F& B8 o1 l+ q$ t' nFPGA 设计者的这5项基本功不是孤立的,必须结合使用,才能完成一个完整的FPGA设计流程。反过来说,通过完成一个完整的设计流程,才能最有效地练习这5项基本功。对这5项基本功有了初步认识,就可以逐个深入学习一些,然后把学到的知识再次用于完整的设计流程。如此反复,就可以逐步提高设计水平。采用这样的循序渐进、螺旋式上升的方法,只要通过培训入了门,就可以自学自练,自我提高。
8 ?/ R" V x4 k7 Y
市面上出售的有关FPGA设计的书籍为了保证结构的完整性,对 FPGA设计的每一个方面分开介绍,每一方面虽然深入,但是由于缺少其他相关方面的支持,读者很难付诸实践,只有通读完全书才能对FPGA设计获得一个整体的认识。这样的书籍,作为工程培训指导书不行,可以作为某一个方面进阶的参考书。
9 }; L+ P5 U% _2 z6 r# q对于新入职的员工来说,他们往往对FPGA的整体设计流程有了初步认识,5项基本功的某几个方面可能很扎实。但是由于某个或某几个方面能力的欠缺,限制了他们独自完成整个设计流程的能力。入职培训的目的就是帮助他们掌握整体设计流程,培养自我获取信息的能力,通过几个设计流程来回的训练,形成自我促进、自我发展的良性循环。在这一过程中,随着对工作涉及的知识的广度和深度的认识逐步清晰,新员工的自信心也会逐步增强,对个人的发展方向也会逐步明确,才能积极主动地参与到工程项目中来。
最后总结几点:8 r8 j0 n3 A/ j0 Q7 O
1)看代码,建模型
" H' J0 \3 k1 m$ @+ |
只有在脑海中建立了一个个逻辑模型,理解FPGA内部逻辑结构实现的基础,才能明白为什么写Verilog和写C整体思路是不一样的,才能理解顺序执行语言和并行执行语言的设计方法上的差异。在看到一段简单程序的时候应该想到是什么样的功能电路。
& {2 |% u1 u& t/ @
2)用数学思维来简化设计逻辑
/ P- T- R9 N. O4 g Z学习FPGA不仅逻辑思维很重要,好的数学思维也能让你的设计化繁为简,所以啊,那些看见高数就头疼的童鞋需要重视一下这门课哦。举个简单的例子,比如有两个32bit的数据X[31:0]与Y[31:0]相乘。当然,无论Altera 还是Xilinx都有现成的乘法器IP核可以调用,这也是最简单的方法,但是两个32bit的乘法器将耗费大量的资源。
0 r4 W& F* N# S E8 g- i那么有没有节省资源,又不太复杂的方式来实现呢?我们可以稍做修改:
( ?5 K9 [3 i" W2 A: M将X[31:0]拆成两部分X1[15:0]和X2[15:0],令X1[15:0]=X[31:16],X2[15:0]=X[15:0],则X1左移16位后与X2相加可以得到X;同样将Y[31:0]拆成两部分Y1[15:0]和Y2[15:0],令 Y1[15:0]=Y[31:16],Y2[15:0]=Y[15:0],则Y1左移16位后与Y2相加可以得到Y;则X与Y的相乘可以转化为X1和X2 分别与Y1和Y2相乘,这样一个32bit*32bit的乘法运算转换成了四个16bit*16bit的乘法运算和三个32bit的加法运算。转换后的占用资源将会减少很多,有兴趣的童鞋,不妨综合一下看看,看看两者差多少。
& i1 h, ^; m3 z1 y2 A7 r; Y& k+ o0 Z
3)时钟与触发器的关系
时钟是时序电路的控制者” 这句话太经典了,可以说是FPGA设计的圣言。FPGA的设计主要是以时序电路为主,因为组合逻辑电路再怎么复杂也变不出太多花样,理解起来也不没太多困难。但是时序电路就不同了,它的所有动作都是在时钟一拍一拍的节奏下转变触发,可以说时钟就是整个电路的控制者,控制不好,电路功能就会混乱。
; P; |! K+ t6 a5 x; s# u% _
打个比方,时钟就相当于人体的心脏,它每一次的跳动就是触发一个 CLK,向身体的各个器官供血,维持着机体的正常运作,每一个器官体统正常工作少不了组织细胞的构成,那么触发器就可以比作基本单元组织细胞。时序逻辑电路的时钟是控制时序逻辑电路状态转换的“发动机 ”,没有它时序逻辑电路就不能正常工作,因为时序逻辑电路主要是利用触发器存储电路的状态,而触发器状态变换需要时钟的上升或下降沿!由此可见时钟在时序电路中的核心作用!
' c% Q, N$ z& H5 G. u
最后简单说一下体会吧,归结起来就多实践、多思考、多问。实践出真知,看100遍别人的方案不如自己去实践一下。实践的动力一方面来自兴趣,一方面来自压力,我个人觉得后者更重要。有需求会容易形成压力,也就是说最好能在实际的项目开发中锻炼,而不是为了学习而学习。
5 |+ Q1 C. {9 {0 S& z! R4 C
/ y# r. X& s8 J7 \; |. D/ M5 y, O% E& [$ S3 F, g& ^9 U
% r0 G8 a# v2 b+ U2 V N' ?5 m/ B: q. e% S
' @5 ]1 y" j! I% i
# o: `2 j- c/ V/ |/ ]+ W
1 e. i% \ F" ?' \) ~$ Z5 Y