|
4.2 “低级功能模块”封装 和“两义性”或者“多义性”的问题 http://a.imagehost.org/0020/PIC4_3a.jpg 如上的示意图。当我们要封装2个“低级功能模块”在一次,如果两个“低级功能模块”使用同一个输入(重用输入连线)或者同一个输出(重用输出连线)就会出现两义性的问题。为了解决这个问题,使用“多路选择器”便可以。
7 z% w H* @8 e( T, A# I( Q% w
1.module flashing_module 2.( 3. CLK, RSTn, 4. Right_Start_Sig, Left_Start_Sig, Right_Done_Sig, Left_Done_Sig, 5. Q 6.); 7.! ~2 ?. p7 r0 S9 d3 E% B
8. input CLK; 9. input RSTn; 10. input Right_Start_Sig; 11. input Left_Start_Sig; 12.. e2 b6 x' h/ Y! B9 u
13. output Right_Done_Sig; 14. output Left_Done_Sig; 15. output [7:0]Q; 16.
" x1 A% E$ w- f& T6 Q) l; X 17.
% `& f; Y( o$ z /*******************************/ 18.
! k/ ~ A, T. p5 n( g' Q6 d 19. wire [7:0]Q_U1; 20.
2 p/ N" u; q9 H5 P; B v4 { 21. flashing_to_right U1 22. ( 23. .CLK( CLK ),
7 \+ v' u5 T# }
0 S4 ]7 F- O. [; r
. g7 [% @4 e: f0 I: W! E// input - from top 24. .RSTn( RSTn ),
9 i& {4 T. o. ^; ]% \
4 j, {) X/ s7 L) v7 Q! u0 {$ S6 ~- p8 @- v
/ ?& u8 @1 Z! I) z: R' J
9 ?! g! m2 `: o// input - from top 25. .Start_Sig( Right_Start_Sig ), 8 U. B4 w @8 `) O8 \6 B# A
// input - from top 26. .Done_Sig( Right_Done_Sig ), // output - to top 27. .Q( Q_U1 )$ b8 |+ Q+ `9 v( z- X( h7 z( ]
$ b6 r2 D- f& P$ o2 g1 t5 ]
9 O' S+ {+ ~8 f) K9 W b# |$ h6 L2 @7 \& _7 R6 M: T
5 g* D' c2 g% A/ j. ^) g" Z
& U- c- j2 v, Y# _5 `// output - to wire 28. ); 29.
/ o' n4 y1 r( N& l. W# L 30.
7 W& M8 w' u, f V/********************************/ 31.
( m/ U" Z# O; g' ^9 z5 ~ 32. wire [7:0]Q_U2; 33.
( r3 ^0 t( R/ x- P# i$ D 34. flashing_to_left U2 35. ( 36. .CLK( CLK ), $ M! u3 R3 l7 ~5 A
# I# f8 ~6 @# b3 ?* T7 @% _5 Z
// input - from top 37. .RSTn( RSTn ),
9 ~* @; ]3 n1 F8 h// input - from top 38. .Start_Sig( Left_Start_Sig ), " S* r+ U) S7 g- y x/ N
// input - from top 39. .Done_Sig( Left_Done_Sig ),
! K8 n: w. h) A1 Y4 R/ ]; _ F// output - to top 40. .Q( Q_U2 )
U5 r: D x( ^8 c0 d) [0 X/ e2 Y p& ?
; R, N7 {" Z, _+ R
G% i. W/ W8 W- [5 H$ L# a
. }$ [0 g0 L+ d6 z0 U! Z4 ^
' k9 n6 N2 B! c' r9 P// output - to wire 41. ); 42. u" g/ R& G8 v- _( T
43.
% ]# T8 B7 }0 H) A/*************************************/ 44.
* {, x7 y# ?' u7 }, {' W5 E 45. reg [7:0]rQ; 46.
8 f0 Y/ H* N5 a8 e1 e+ y, i) X2 Y 47. always @ ( * ) 48. if( Right_Start_Sig ) rQ = Q_U1; 49. else if( Left_Start_Sig ) rQ = Q_U2; 50. else rQ = 3'dx; 51.
+ Q: g& H: K# R% C- G3 b, j: r( G 52. assign Q = rQ; 53.
+ z. b) f, f( c" J* y 54.# O7 k: n8 Z: S! C3 r' a& C# U
/*************************************/ 55.2 ^# m3 b3 q" }( U
56.endmodule
- \; s) K. v; j( m5 Q g6 g
' s; P/ y. ^7 n4 `: w9 L5 _/ G. y8 J1 x) s$ R6 q! Z
为了解决多“两义性”或者“多义性”的问题多路选择器常常被使用。如上述代码中在45~52行(从第27,第40行引出“连线”)“Q_U1”和“Q_U2”被if控制着输出。这样的写法是最优化的,生成的RTL图也非常的整洁。
1 r! g1 S3 _5 p# r; H
http://space.ednchina.com/upload/2010/6/5/0f6b6eb3-8c6b-4af8-bcdc-6946a733b70a.jpg
* P' C5 ?' T+ }8 ^1 A当然还有其他的写法:
; q3 [! C5 w6 M% [
assign Q = Right_Start_Sig ? Q_U1 : Q_U2 ;
) U$ n- f0 f# M( X
虽然如上的写法和,第45到52行的写法相比,更为简洁,而且生成的 RTL图也一样。但是这样的写法有如下的弱点:
4 ]# Z; _" R3 o q
1. 解读性很差。 2. 只能解决两义性的问题而已。 ' }. q2 x$ e- H
所以不怎么推荐使用。
/ C( P( l1 ]: X
还有一中更糟糕的写法:
8 E0 ^, p7 x3 T2 X8 m$ G+ }2 d; R
reg [7:0]rQ; , C. `- _7 p5 I8 ~% g9 q
always @ ( * ) case( { Right_Start_Sig, Left_Start_Sig } ) 2'b10 : rQ = Q_U1; 2'b01 : rQ = Q_U2; default : rQ = 3'bxxx; endcase $ D& M% h! h2 B& J4 s
assign Q = rQ; 虽然该写法的解读性很高效果也一样,但是却很浪费资源。生成的RTL图如下: . t5 ]) N! r- {8 Y
http://space.ednchina.com/upload/2010/6/5/2f9ae0c3-d220-4ce9-b86b-ebf273901983.jpg
, x- w% j( |+ M& ?+ o
和上述两个写法相比,它可差多了,所以不推荐使用。 ' g+ P' ^2 [: ?6 Z! Y
/**********************************************************/
& C a1 |6 b7 X }) Z# C
reg [7:0]rQ;
( V* B* X" w5 t& l9 e& y
always @ ( * ) if( Right_Start_Sig ) rQ = Q_U1; else if( Left_Start_Sig ) rQ = Q_U2; else rQ = 3'dx;
: M+ X% C8 M' g8 c' P
assign Q = rQ; 3 l4 n! c+ d" K# S
) r9 n# X6 }; b9 j+ V. t
接下来,我们来分析上面的代码。
- j5 U$ q* h7 N5 a7 } s
# A+ A# U' R$ V3 H* B9 R/ w
always @ ( * ) 2 E. L% z. h! c7 K- Z
2 C. r* B7 E" ~9 d. h0 f
“always @ ( * )”这样的写法在Verilog HDL 2001 中已经被支持(好像是这个版本)。在敏感包中的“*”,可以理解为“任何状况都有效”。
1 F3 O. A2 T) a
6 g% ^6 c* U8 U# `& K/ T
if( Right_Start_Sig ) rQ = Q_U1; else if( Left_Start_Sig ) rQ = Q_U2; else rQ = 3'dx; //不能省略掉 0 P; w1 f" Q) g+ `! g- G V
7 M: j% c" l& W1 }7 b$ L# M s
而“else rQ = 3'dx”,这行不能被省略掉。不要问我为什么,这是V语言的编程规则。你尝试注释掉后,再编译看看,你会发现会很多“Warning”。 2 v9 m& E! ?& l' t
1 j8 q9 V3 A; I( q
always @ ( * ) 1 m! L# s- s' g- \
x if( Right_Start_Sig ) Q = Q_U1;//连线 Q,Q_U1 和 Q_U2 之间没有
( Y; f" ?; ]7 Y6 V, v2 A9 ax else if( Left_Start_Sig ) Q = Q_U2;/ A; G. p9 R& v& P! r" G+ \
//寄存器驱动
. ~7 ? T1 j1 H/ V% C
x else Q = 3'dx; 4 V8 l9 \# y+ P
还有一点请注意,因为“Q_U1”和“Q_U2”是连线的关系,所以必须使用寄存器来驱动。如上的代码中“rQ”便是扮演这样的角色。如果该寄存器被省略了,会出现编译错误。 % A2 d+ ^9 { W, R! c4 x
总结: “两义性”或者“多义性”的问题,不仅在“低级建模”中出现,日常的建模也会出现它们的踪影,然而“低级建模”出现的频率比较高罢了。“多路选择器”在设计的时候应该经多方面的考虑,亦即取得最平衡的效果。
2 `" V! t( I" k- n' Y' m4 L8 | |