|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
很多刚学Verilog HDL (硬件描述语言)的朋友肯定会对阻塞赋值和非阻塞赋值比较疑惑,那我们就一起来抛开这层迷雾吧。% D; y/ x. d* R1 u+ }3 r& R$ p' k9 s
5 z) V# j. q9 Q1 K$ y- k
首先我们要理解两种变量类型 Net Type(连线型)和 Register Type (寄存器型)。(有些参考书上有分为3种类型,这个无关紧要)
% f! [! I3 d+ o5 _8 _3 x" t4 a& |2 R8 a+ {
Net Type(连线型),从名字上理解就是“导线”呗,导线的这头和导线的另一头始终是直接连通的,这头是什么值,那头就是什么值,所以输出随着输入随时变化的。连线型中 wire 最常见。# Q) i, Y1 V2 r# ^" m; V% a0 n& {( D0 N
C1 l. w* W3 c$ M Register Type(寄存器型),寄存器就不像普通导线了,它可以把值给存住,你只要给它赋一次值,它都会存住那个值,直到你给它赋一个新的值它才会改变。寄存器型中 reg 最常见。: j; f! x% \* n- O
4 @" V* c5 J0 l: ]3 n6 ^ 最常用到的是 wire 和 reg 这两种类型,其他的对我们初学者来说一般很少用到,可以暂时跳过,以后慢慢学下去自然会理解。, P+ ? v8 t+ U2 [$ p
( w- N0 V k o+ Y$ S* x# G 注意:wire型变量如果没有赋予初始值,默认初始值为高阻态“Z”。
7 K; W8 ]5 a/ r* q: E
0 `$ H' A- ^3 I) S4 m; s reg 型变量如果没有赋予初始值,默认初始值为不定态“X”。
P/ O2 u; `5 w+ ~; m8 u, @/ S% T W+ N! _( T
在理解这两种基本的数据类型之后,我们来看看verilog语言中的赋值语句。verilog语言中的赋值语句有两种,一种是持续赋值语句(assign语句),另一种是过程赋值语句(always语句)。
5 p% v5 l: D/ r m" l! X( W0 G( Y1 i; e" z8 v3 j7 s
持续赋值语句(assign语句)主要用于对wire型变量的赋值,因为wire(线型)的值不能存住,需要一直给值,所以需要用持续赋值。
0 @' Y2 R8 d' B. l3 E
! \: z) x+ b0 s# V9 Z 例如:assign c = a + b; 只要a和b有任意变化,都可以立即反映到c上,也就是说c的值是根据a,b的值随时变化的。
6 n/ i+ E V# [! }' p0 x& A9 s" }$ }4 O$ F
过程赋值语句(always语句)主要用于reg 型变量的赋值 ,因为always语句被执行是需要满足触发条件的,所以always过程块里面的内容不是每时每刻都被执行,因此需要将被赋值的对象定义成寄存器类型,以便这个值能被保持住。
& t+ d* A7 q( g' {
9 h* n+ Z# E m 过程赋值又分为 阻塞赋值 “=” 和 非阻塞赋值 “<=” 两种。这里的非阻塞赋值符号 “<=” 与 “小于等于” 符号相同,他们在不同的语境下表示不同含义,要注意区分,例如在“if-else”等判断语句中,一般都表示为“小于等于”。
& u3 f( d; @# h8 H4 h& J, x7 Z% k) q7 k
接下来对这两种赋值作具体讲解... L8 }1 y# }5 H$ w/ Z
# z) s$ h t5 \/ @2 D
① 阻塞赋值 “=“ 。 阻塞赋值和我们平时理解的赋值差不多,不用太多解释,就是按照语句的顺序,一句句往下顺序执行。一个赋值语句执行完,然后执行下一个赋值语句。
4 f) ]& ~$ @+ M( P8 j7 ?1 ]+ Z' ]# b
② 非阻塞赋值 “<=” 。非阻塞赋值就比较特别了,在同一个always过程块中,非阻塞赋值语句都是同时并发执行的,并且在过程块结束时才执行赋值操作。也就是说,在同一个always过程块中,非阻塞赋值语句被执行没有先后顺序,在过程快结束时,大家一起被赋值。( q( J' Y7 K9 @( n+ i6 _
" \( b. U' L% p2 v5 @ 给大家举一个具体的例子:. B( \" K, C, E+ w4 B6 X$ h
0 p+ X* E; a: \ W+ a module test (clk, a1, a2, b1, b2, c1, c2); // test为module名称,括号内的是端口列表,包含所有输入输出的变量名称 ^; t3 @8 m$ Y
! O" m0 ]9 X) x7 `+ n" C2 L* m
input clk, a1, a2; // 定义输入变量,这里没有定义位宽,默认为1位宽度
! R) k# @6 C6 e0 N. b+ R* o' O! P; _5 M1 n/ F0 V5 F
output b1, b2, c1, c2; // 定义输出变量,这里没有定义位宽,默认为1位宽度- q& M7 L _: X" t3 z
) Z+ x4 ^7 ~- z reg b1 = 0 , b2 = 0, c1 = 0 , c2 = 0; // 注意!因为这些变量将会在always过程块中被赋值,所以必须定义成 reg 型
8 C9 L7 P4 H8 e/ P8 Z' l! M+ N7 b3 e3 E8 P7 j
// 注意!这里省略了对输入信号clk, a1, a2 的类型定义,它们默认为1位的wire 型(因为输入信号是随时要变化,所以必须用wire型) : q( H6 ^9 {3 h7 t: L; y# ~! S
8 g7 O. n0 ]" D
always @ (posedge clk) // always 用 clk 上升沿触发
$ p4 X" A' g u7 [5 ^5 ?5 O9 n9 n5 f @" g; t1 K, H
begin
[# l% K! |1 x, N& }/ w! F, {9 I- A i
b1 = a1; // 这里采用的是阻塞赋值
. Q G1 K0 \ }9 J# W/ V
. B# i4 F _$ a( j# Y c1 = b1;+ r4 _, x+ P* a+ A. d
) j: }$ W$ t: o" [1 ~6 [; {. ` end
$ q3 E; j4 e ~7 Q, j$ x V& w) n/ T3 B% T: L8 a& K
always @ (posedge clk) // always 用 clk 上升沿触发
* F& ^# L- C6 g' ?* C8 p: T9 h8 v
?7 N+ i$ P9 Y, s begin' n9 r8 ~) ^7 ^/ D0 D
. u, c$ P9 Y8 T: g) S2 S5 @ b2 <= a2; // 这里采用的是非阻塞赋值
; W4 S8 s+ A. {6 [- f o& N
; e2 E' v7 }! c( c. S, j c2 <= b2;+ D8 M8 H# Y3 A1 g1 D9 k4 D
+ o! V: \$ B. g/ {, d- v' K6 W end
% ]. D: X5 A* t- f. d2 Y: V$ M: ?- |: O5 i' T
endmodule // endmodule 别忘了,与 module 成对使用- Z9 q3 X/ A: x
/ v3 A2 y' ?1 V+ \( O; U) T+ }; u, G# o# j2 C
作者:姚纪元3 b3 P; C! V* p; |" h
c6 B O) N% k( r Q2 T5 F$ f& l& x3 g
[/hide]
# z& \! O( m( |$ ` w/ w: j7 K( f8 L# R" ?9 ~- @# _. T
8 e3 W) h9 d' {' i, q# a3 G' a& Z
|
|