|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
在逻辑方面,我觉得比较重要的规范有这些:
# J. V. C! ]9 f( r; C2 L9 h [0 ^' U; I, b5 ?4 _, T
1.设计必须文档化。' Z, l+ l8 d7 w% O8 |
3 ^; K1 ?6 R7 P1 p1 a9 ~( K8 |要将设计思路,详细实现等写入文档,然后经过严格评审通过后才能进行下一步的工作。这样做乍看起来很花时间,但是从整个项目过程来看,绝对要比一上来就写代码要节约时间,且这种做法可以使项目处于可控、可实现的状态。
3 n S5 a/ A/ v9 ~7 n
- i+ B" G1 `) ?6 w7 D2.代码规范。
/ z/ ~- K$ H8 {9 X
6 m/ p: r! n/ H1 O1 |a.设计要参数化。比如一开始的设计时钟周期是30ns,复位周期是5个时钟周期,我们可以这么写:
& g4 L D' k. W z- h
! u/ N1 y/ v& R$ ]6 s9 q9 `8 Gparameter CLK_PERIOD = 30;; R7 {5 }$ S9 D% A+ Y" L" f( r
5 M/ u, X2 ?/ A6 G3 zparameter RST_MUL_TIME = 5;
6 U9 Z3 P1 K, n! B. }& t- e4 a: K2 q- K! X/ F
parameter RST_TIME = RST_MUL_TIME * CLK_PERIOD;
% ~6 R- i8 W: n3 S; }) t2 o0 W, a* o
...- A/ O% n6 T6 Q7 U4 W" h: a/ B
. V! G/ D& Z. {
rst_n = 1'b0;: c( z" A4 {- y+ A: \
$ \. C, t" C: f2 t7 ~, w# RST_TIME rst_n = 1'b1;
; F5 z3 {1 O9 p! S: x" |' B" _; O3 o2 _! L# s& [
...: N' z+ I) U0 T2 ~3 L
$ H5 e* v* h7 R- W' `# CLK_PERIOD/2 clk <= ~clk;
! j( h! k; `1 }1 `6 s* X- a8 I
如果在另一个设计中的时钟是40ns,复位周期不变,我们只需对CLK_PERIOD进行重新例化就行了,从而使得代码更加易于重用。
/ E6 q; [0 M+ E- ]; M) f4 G3 h
1 T" i: j8 \& J! i x7 \ W7 [b.信号命名要规范化。
' f0 e8 L5 s3 K- A7 l9 |" z, [8 T( N- l- {
1) 信号名一律小写,参数用大写。" i9 n- \% P( p0 z4 I0 e
" j4 k$ N6 A+ ]0 o, W+ h
2) 对于低电平有效的信号结尾要用_n标记,如rst_n。. Z" g0 U% q' F$ g- q' N# L
1 S" C9 O8 u. L* }* Z9 o! }1 B% R3) 端口信号排列要统一,一个信号只占一行,最好按输入输出及从哪个模块来到哪个模块去的关系排列,这样在后期仿真验证找错时后 方便很多。如:) w5 y3 H! A6 G
+ U1 ^- z8 L: T! o' U' m
module a(
; y! _- c7 o) M& a/ O) a U3 |( }$ |% |
//input5 X( U; P. m* h, P2 T7 S+ q4 p( ] {# d
4 k( f* W3 l9 Sclk,
! ?8 t1 @9 I( x6 h' C" J: B& {: u( {# l! i& W2 c2 G6 r, V
rst_n, //globle signal2 W) ?. @5 j! v# S
8 y$ {0 P9 H% s
wren,
5 |! U: V: }. G- Q- b Z5 A: J7 ~# M$ D% I, B4 J! v+ k% v! O( n' E4 O
rden,
2 U. W c7 S+ H3 e
9 p& J8 K& I G$ x: p! [8 Z: C- }# davalon_din, //related to avalon bus
+ v6 S- c+ @* W5 C* }- H3 N/ c/ g
sdi, //related to serial port input
5 c- W1 @+ u S& F% t' c3 p. w3 y0 J
//output' N' Y, ?' Z9 C# g+ G
5 K7 R2 P! h2 o" q
data_ready,
5 J* ~2 y: S, T. }& }
- F; t$ ]1 x; C1 }; T# havalon_dout, //related to avalon bus
. F+ I! B% @' }4 b7 n R; |' l5 t# F4 m t5 R- ~/ N @
..." n/ b ^5 N( ?9 F3 m$ E- A' z
7 g, {# \6 ^3 c& y. A);
7 r$ n: t; R2 i7 z* ~& p
# h# Q% g: K6 _8 K- l# P+ S: o: E& P4) 一个模块尽量只用一个时钟,这里的一个模块是指一个module或者是一个entity。在多时钟域的设计中涉及到跨时钟域的设计中最好有专门一个模块做时钟域的隔离。这样做可以让综合器综合出更优的结果。6 Z3 `2 i+ r: M
7 G/ N& z i3 |. r3 T* T$ x K h& I. g% i4 \4 Y
1 o) G! {: h. V B. Q) g5) 尽量在底层模块上做逻辑,在高层尽量做例化,顶层模块只能做例化,禁止出现任何胶连逻辑(glue logic),哪怕仅仅是对某个信号取反。理由同上。" H! [7 z/ S/ B! o: B
$ m) W; W6 M, t- E5 J
6) 在FPGA的设计上禁止用纯组合逻辑产生latch,带D触发器的latch的是允许的,比如配置寄存器就是这种类型。
8 ]. o3 a3 ]) f
! \5 S$ x% i/ ~% p
% b: o6 f& V- t3 G1 ^9 P4 [$ h9 d0 X! r8 w: o
7) 一般来说,进入FPGA的信号必须先同步,以提高系统工作频率(板级)。所有模块的输出都要寄存器化,以提高工作频率,这对设计做到时序收敛也是极有好处的。& H2 t) N: H! s& Z' Y. f' D
' j. P" E' x" `# e' ?4 s& d" k5 w0 Z! B! M9 @% [
9 p' _+ ^8 ]* d4 x+ W) d* p7 N9) 除非是低功耗设计,不然不要用门控时钟--这会增加设计的不稳定性,在要用到门控时钟的地方,也要将门控信号用时钟的下降沿 打一拍再输出与时钟相与。
+ H X7 R+ Q3 h$ v& r, Q# f- N M# [9 C/ h. G: g$ N
最好的解决门控时钟的办法是使用或门(上升沿触发),如果门控触发器是下降沿触发,则应该使用与门。4 q9 _4 s6 g3 y% ? U7 |9 c1 c
8 W* J: `) \; j) Jclk_gate_en -------- ----
& a. `6 S# d. Z# ]; s* N: d3 g, }9 d4 @- n$ ?, ?; I
-----------------|D Q |------------------| \ gate_clk
0 y* C5 S" \4 d/ i4 a
% ~, O2 S: r V& s_out
4 `/ {& d7 R8 @9 Q5 l* j! C
: z4 d6 k5 X) T8 s4 X| | ---------| )--------9 A( r" ~5 R1 B1 ^: p1 i
; \: X( m! Q2 p5 L-1 w0 ~( y6 t4 I; j0 r2 u! J
1 o( B5 q# X0 M x! x# W3 m" E$ g
------o|> | | | /
. e# P; w: X9 F9 R( k# `" R7 O" W1 y( m$ R
clk | -------- | ----
, h8 J Y3 O8 N- R# ]; ?
, r9 ^! Y/ B3 G- O3 i1 u9 W# n X------------------------------------, c$ @) v1 V% n/ u S6 E3 f
0 Q, ]8 b, j8 S& C. T10)禁止用计数器分频后的信号做其它模块的时钟,而要用改成时钟使能的方式,否则这种时钟满天飞的方式对设计的可靠性极为不利,也大大增加了静态时序分析的" W% O/ u2 _+ |2 i9 X. i
2 A; K% j) q# _% D+ C
复杂性。如FPGA的输入时钟是25M的,现在系统内部要通过RS232与PC通信,要以rs232_1xclk的速率发送数据。
1 [! O8 B# V% H5 t( S0 b; ~* J! A0 U9 ?6 {1 ]8 X6 L2 s
不要这样做:
! A1 D: g. a0 l y- F+ v$ \$ p$ c2 A# S+ a) i3 m
always (posedge rs232_1xclk or negedge rst_n)
( V z5 b0 X9 i0 Q6 S
3 s8 D! U* s: p- t. p+ M$ W( U4 Y$ ~, wbegin
# U8 w, G, L3 T: X. d* Z9 Z/ k' O, s9 d
...0 O2 |& y5 N/ Y. U1 T* s, l
, Z% J/ v& ? D4 e
end
, o# d; Q1 Y& C7 E* | z. l9 z# P# z. R+ d w1 O6 G
而要这样做:. u1 v1 I; e. H% @
% h4 W" z" @; F9 X' f& I0 ^6 Q. b
always (posedge clk_25m or negedge rst_n)/ L' G: E5 j# \ s: c
- F* L, y9 p T, L- |$ W+ [0 U
begin( R& {3 M$ _0 y5 a' u% A0 m6 o9 Z
% j5 Y8 b1 m. A...* ?) p" X$ _9 F. {! x
" B: }+ [+ B8 delse if ( rs232_1xclk == 1'b1 )
# B3 b8 |" y l: P) L' B4 W3 P+ R! ]8 V4 c2 t1 w
...9 p- s( n4 f8 D4 p" I
" a7 n$ A/ b9 z# z& L1 [
end P- o" b( R. u' w \, q( G
1 P/ {8 E% j0 m3 K. Y4 ]" @
11)状态机要写成3段式的(这是最标准的写法),即
# y) k" R: z( \5 G1 o% I# w' F+ i' ~( P
...
1 @: E" G/ ?! f+ ^0 L2 O' U" B' v
always @(posedge clk or negedge rst_n)& k; |& k% ~4 Y# v' E
_& w& L: n( o7 N; ~/ x4 J" v, `
..., K8 F+ F Q/ Y; ]4 S' u
) J; c0 c* @, I( M: u% _
current_state <= next_state;3 v6 T' _- e1 }& F' p I, C
/ s& `1 y2 T* M: N( D O...
/ E1 N) b7 s5 W: L4 }3 f: U- |
8 T: z" F2 q4 f/ Yalways @ (current_state ...)
/ K8 U% _7 d" k1 v3 J# d( Q3 f, P) z8 W6 ^; |* X' j4 ~7 o# q
...9 `5 W: `( L) b: N5 l
2 {/ E- Z( p! x* v2 v" |case(current_state)
_% r+ v1 @2 l% J/ s& p$ j+ P( N4 a" ?$ F$ d( p1 A5 K" T# A
...% k6 u8 U4 s4 Y4 }5 A& B Q1 Y/ m
% B; I8 I& C |. }3 b' U* l, \$ Qs1:
* ~& d( V+ G/ l* _9 `+ J0 j) @4 Y' ~. _/ ]6 Z* s+ ?
if ...
3 W0 `/ {6 p' @/ Y8 n; }9 n- J* y9 w
next_state = s2;" t4 _. N+ x3 K! y, T! l
E$ z, |$ g! D7 g$ [
...
1 h o% t% G. O7 m5 a7 ~; A% c* N; w0 ~3 V; N7 S2 L
..." M" T2 M* M* W
& y$ t1 ?+ h& ?2 |: u7 a# }always @(posedge clk or negedge rst_n)
# `& g# q1 s& x& Y+ v, E
4 c$ v1 O; H# F; d) J! w...! s& l$ U# q6 Q3 p/ \* g* r: R
/ y1 p; d/ G/ A% relse
' t4 X( U" y& j9 r8 B1 j! z# U% b( e: Z: V! ^3 D) S9 b
a <= 1'b0;9 o3 P) D+ f8 _: ?; X% G
$ \. d) x+ [ V$ P% F1 _. \c <= 1'b0;: A; s" m" a: `7 T# x8 P' f+ [
n1 ^, d) Z- y/ T. |* M* l+ @8 Ec <= 1'b0; //赋默认值% R0 t' R" M1 H; U
# D) g( c. e) r! B: S0 ~3 O% V; Pcase(current_state)" g& U$ j# ?) f% @5 j" Y0 v
7 _; d; m4 k" gs1:
: u4 v) d" A1 ?9 G. K$ Z7 Y1 D$ L$ P2 i( O9 L2 N" ^! {
a <= 1'b0; //由于上面赋了默认值,这里就不用再对b、c赋值了(b、c在该状态为0,不会产生锁存器,下同)0 s9 a ]# }0 Y# O/ m+ w; B
; F2 k* \8 |6 c
s2:
+ b: F8 Y, n' E$ E3 T
- \' n+ V; c. @* F' h. `b <= 1'b1;
2 c2 r! a' H) H1 ~2 w& M b2 N3 F: Z- A4 P
s3:9 b5 n! k2 K1 Y; l
* w' I' a1 x3 k4 l
c <= 1'b1;
) J( r M' o! H
& R) _( [4 W1 Xdefault:# b& p4 E4 V) D
. ~5 ]9 y9 Z: y4 {' ]8 x7 d
...
: ]( }4 u6 Y, }$ c- y5 s# h
; x8 S) Z ]% U, Q* s9 |...
$ @6 q; X+ y; I/ L9 T
3 y& h M" w$ t8 k! m//第一个进程,同步时序always模块,格式化描述次态寄存器迁移到现态寄存器
: t- l* |, s" V+ P
0 ^9 I3 y4 W! B3 }always @ (posedge clk or negedge rst_n) //异步复位
0 ]* ?2 @, ~7 `
; p' q$ h/ u3 E6 N# r( C/ Xif(!rst_n)
3 x0 N) k6 O4 j& I# |# _6 L
* @+ ?- z4 }4 k3 kcurrent_state <= IDLE;
# v' B' g& P; [2 p, j8 u* l9 X7 Q" r" r6 N
else, Z& s7 b" {0 S9 c5 j! c
( u d0 i+ z& v( ?1 B+ Z' R/ Gcurrent_state <= next_state; //注意,使用的是非阻塞赋值
( H s+ z5 @6 j
; [/ r9 L. L! q& x) o) y//第二个进程,组合逻辑always模块,描述状态转移条件判断 Y L. ]/ r1 w+ ? Q7 |
7 ~# a( y+ l6 u
always @ (current_state) //电平触发7 x# o4 I' R9 b' E
$ u, K: N% P+ _
begin
) V' Q2 E. x9 N( D7 U0 D1 Q- Z6 l5 s! \/ C7 j
next_state = x; //要初始化,使得系统复位后能进入正确的状态
& P ]" R* I" ]% ~1 J. s" N, C$ `& i+ n: o3 o- q1 v6 y
case(current_state)
; i8 u6 a) C+ u+ l; v1 Y" g% O+ V: T$ N7 Z" ^ n$ O
S1: if(...)
8 l0 `7 }# A2 X2 g
% H1 e0 {% U% U" {; L; Enext_state = S2; //阻塞赋值+ c7 K; h- Z5 h9 }' y
# b3 O) w0 l5 X4 B* m3 z...
, Q5 K+ U B6 @
& W+ z7 c* M8 W; I* lendcase
+ T, R: o/ Y1 N6 l# ^; Y& h3 X: D0 I1 K5 {7 R) q" G* F( o
end
S# ~& S6 P6 U y
+ w2 z) n. ~2 S$ t6 _7 B//第三个进程,同步时序always模块,格式化描述次态寄存器输出
* ^1 g# @ f% I0 e6 w' J/ {2 O0 }" H6 b5 h2 M) H
always @ (posedge clk or negedge rst_n)( m$ J" T5 H {, Z. b
1 a* e( i2 N' z- C$ E6 j2 \
...//初始化' z3 W' Z6 K4 R1 U
9 w. i+ y" B2 P4 l+ |/ lcase(next_state)
$ n# ^, Q/ n; j. i/ |# f: M) ^& f) q# R6 r' G
S1:
3 J2 p' L' B R! E
$ g: Q+ @" u( p4 zout1 <= 1'b1; //注意是非阻塞逻辑* {8 x$ c1 m1 ]* e- q$ a! z
: G0 X; d# [. V
S2:
/ y& L* P7 k( w* V: H& ?( n! k6 h' C$ E# z. T
out2 <= 1'b1;4 m* j8 V0 {0 @9 w/ F9 s$ E
1 t& ]: ?. X% G3 V: v9 Adefault:... //default的作用是免除综合工具综合出锁存器& Q0 s& f0 E# r% h
g7 d; ]) R# @* l0 L5 ?6 w7 H M
endcase
; P* a' t% x) E, U! a5 N
1 r9 f3 D9 l4 D: b" @7 Gend
) ^+ n$ {5 o& D3 ?; D& z( b/ D; z( G8 t4 ?4 A2 N
3.ALTERA参考设计准则
& v7 x7 z9 J1 F" }1 g" _9 u6 |: G3 v: F
1) Ensure Clock, Preset, and Clear configurations are free of glitch; c- f+ y) T9 H2 a0 j6 d* [
) ]8 q& e! F4 q$ e8 P2 h2 u
es.(确保时钟、预置、清零的结构单元没有毛刺)" X; \9 S/ L9 h, x
/ d! y' P: I$ U! {# b! S0 M+ z
2) Never use Clocks consisting of more than one level of combinatori1 Q. y$ o% ~' Y2 q4 p
# L, ^9 E# I4 K, N' b- |1 N9 Eal logic.(决不使用由多于一个水平的组合逻辑组成的时钟)# \% k9 I& a4 \1 G) B: H8 p8 m
) E8 i! L7 t- l, U; [
3) Carefully calculate setup times and hold times for multi-Clock sy
1 y4 |; Y* o$ G m+ A0 @
/ P P2 f/ D6 ~1 Dstems.(在多时钟系统中认真的计算建立时间和保持时间)6 @( Q1 `0 S( v5 v t
4 _3 B A) u, a$ P* a# D
4) Synchronize signals between flipflops in multi-Clock systems when6 H# t# U# | F2 Q: |4 p" c7 [
/ g/ W7 Q2 P9 C! k" j9 @' [7 ]. Athe setup and hold time requirements cannot be met.当建立时间和保持时间不能够同时满足时,同步多时钟系统中各触发器之间的信号。
5 D3 j K/ M, W n8 ~5 |8 [3 f
# S- ]( x5 ^$ G4 m8 t! n5) Ensure that Preset and Clear signals do not contain race conditio
6 D* s- x3 O3 x1 p7 C
; Q5 ?% P& c+ tns.(确保预置和清零信号不包含竞争冒险)* E8 w* b* s8 G9 v: Y
) {& m p' x2 @9 k2 y+ _6) Ensure that no other internal race conditions exist.(确保不存在其他内部的竞争冒险)3 N' Y/ J, Q# g7 \* b) r& w% J6 r# V
' O+ ~; T! K- a4 n
7) Register all glitch-sensitive outputs.(寄存器都是对毛刺敏感的输出)
+ v- F& X4 C/ t$ P
# C Q+ A( y: p, ]$ A& sSynchronize all asynchronous inputs.(同步所有的非同步输入)
* D! @7 b# \: S5 d2 N7 n- i3 N0 w' T0 { Z/ M* M
9) Never rely on delay chains for pin-to-pin or internal delays.(同步所有的非同步输入)
& O; j0 i8 _9 S3 f) C) W5 G& q( g! Y* v n6 Y7 C# E9 |: g
10)Do not rely on Power-On Reset. Use a master Reset pin to clear al5 w3 \3 P, q- v% b, g( b5 ?
8 ?8 k5 i( V; u" x% F+ Al flipflops.不要依赖于上电复位。用主复位引脚去复位所有的寄存器 ]! F( D* v# w: d* M
4 |1 T' K! i& _* }" B11)Remove any stuck states from state machines or synchronous logic.(从状态机或同步逻辑中去掉那些冗余的状态)
+ W1 H, N6 E( H# f, ? |
|