4.2 “低级功能模块”封装 和“两义性”或者“多义性”的问题 http://a.imagehost.org/0020/PIC4_3a.jpg 如上的示意图。当我们要封装2个“低级功能模块”在一次,如果两个“低级功能模块”使用同一个输入(重用输入连线)或者同一个输出(重用输出连线)就会出现两义性的问题。为了解决这个问题,使用“多路选择器”便可以。 4 q' b- a: U6 x# s; A& \
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.
6 a8 F/ v: P# o% c0 T 8. input CLK; 9. input RSTn; 10. input Right_Start_Sig; 11. input Left_Start_Sig; 12.
( v8 N) G/ B. X/ M 13. output Right_Done_Sig; 14. output Left_Done_Sig; 15. output [7:0]Q; 16.
6 ]( L5 v7 K. Y 17.
) |# f1 F9 ?( W/ I /*******************************/ 18.
, k$ W0 t8 N7 d( { 19. wire [7:0]Q_U1; 20./ ` q5 a& S% i9 T
21. flashing_to_right U1 22. ( 23. .CLK( CLK ),
" o) A- j4 T, X
/ X5 t. X! L% v$ \# ^) A5 k
3 |$ B, @& ~6 _0 j// input - from top 24. .RSTn( RSTn ),
5 p L# Q* N B# F8 X6 ~+ v* K! s* _# h" y# z$ X a. D
5 z+ ~7 n V" s5 K8 {$ K- g* T t( y. f1 G
6 K& \( r% c5 ]4 d! x, l
// input - from top 25. .Start_Sig( Right_Start_Sig ), 7 W7 S; m4 |1 G( W* \
// input - from top 26. .Done_Sig( Right_Done_Sig ), // output - to top 27. .Q( Q_U1 )# X h% M8 Q' B5 c2 a
. v- Q, l' d# I8 e
2 ^1 x9 w' s9 l' S- ]( ?2 R
* e* v1 G6 k# K8 O v) S4 }! Y( n3 G2 J ^0 W8 J( g3 }4 g
* D% e( L+ |* _7 X% |// output - to wire 28. ); 29.7 s$ \. m6 t5 w" K4 n- z
30.; _6 @, ^$ g/ S, g' ^1 Y
/********************************/ 31.' i9 q( l( I: M2 o
32. wire [7:0]Q_U2; 33.- w: w" y4 x; G; N! O' V
34. flashing_to_left U2 35. ( 36. .CLK( CLK ), 2 X: s9 P" H8 ?- q# ~. @
A3 [+ U$ m& }, v8 ~2 b0 \- \3 @
// input - from top 37. .RSTn( RSTn ), & y7 h. Z% P# n, U3 p" O
// input - from top 38. .Start_Sig( Left_Start_Sig ), ( e r8 Z: X2 v* F
// input - from top 39. .Done_Sig( Left_Done_Sig ),$ f, L+ y8 O; ^4 E
// output - to top 40. .Q( Q_U2 )
% w* y- Z( m4 X0 V7 {" i) V3 A) H R3 M
" _6 j: R" N( t1 D8 X! a6 p- v9 T( A S4 T+ I8 i' O' q9 D# Z
: u9 P4 f. [" Y! I& F% @4 `
* w$ p$ c. H. r; j// output - to wire 41. ); 42.# S$ O3 O% Q2 @$ \; E
43.
- v: G6 s8 i' @9 `/*************************************/ 44.
4 V& H0 v1 b9 @: y6 J6 A: g/ D 45. reg [7:0]rQ; 46. X3 Y4 j* N, g2 r
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.
4 P" i- F( ^$ J$ u& V 52. assign Q = rQ; 53.0 n% [$ |1 a r. `2 |( r
54.5 {1 W' Q! S) x" X* U+ H
/*************************************/ 55.0 j: I& r3 @0 _& S8 }5 Q8 A
56.endmodule
) s" l" _! C* D6 W6 G3 L
% {+ N% {+ |1 E& J( a% ~4 Q- t
& \) f) d5 w8 [
为了解决多“两义性”或者“多义性”的问题多路选择器常常被使用。如上述代码中在45~52行(从第27,第40行引出“连线”)“Q_U1”和“Q_U2”被if控制着输出。这样的写法是最优化的,生成的RTL图也非常的整洁。
/ ?8 u% Y" G9 h3 j0 j
http://space.ednchina.com/upload/2010/6/5/0f6b6eb3-8c6b-4af8-bcdc-6946a733b70a.jpg
9 h+ }' P8 a3 V) S m% D) ~1 }当然还有其他的写法: ; d: t% c2 v6 |: B' ^3 G
assign Q = Right_Start_Sig ? Q_U1 : Q_U2 ; ! C2 f3 E3 k. n: M0 g
虽然如上的写法和,第45到52行的写法相比,更为简洁,而且生成的 RTL图也一样。但是这样的写法有如下的弱点:
, E7 F5 F1 b! g6 s0 A
1. 解读性很差。 2. 只能解决两义性的问题而已。
% _7 Q2 |, Q, e, D: Q! v
所以不怎么推荐使用。
1 l% a2 `0 i# a W+ A
还有一中更糟糕的写法:
/ g; ~1 N: v# Q/ T' c) Z
reg [7:0]rQ; ; P; k) u8 d* z& D
always @ ( * ) case( { Right_Start_Sig, Left_Start_Sig } ) 2'b10 : rQ = Q_U1; 2'b01 : rQ = Q_U2; default : rQ = 3'bxxx; endcase ) d6 F( s* R/ @' {) {+ G
assign Q = rQ; 虽然该写法的解读性很高效果也一样,但是却很浪费资源。生成的RTL图如下:
k; e/ P& q/ M" n
http://space.ednchina.com/upload/2010/6/5/2f9ae0c3-d220-4ce9-b86b-ebf273901983.jpg ( l5 u9 P$ D2 \/ B1 K" B3 h
和上述两个写法相比,它可差多了,所以不推荐使用。
9 t0 Y7 |6 S$ i, n1 S% D) ~
/**********************************************************/ 2 j7 y& }( C! ]2 X2 F6 G! F
reg [7:0]rQ; x9 ~$ W7 i4 Z$ K
always @ ( * ) if( Right_Start_Sig ) rQ = Q_U1; else if( Left_Start_Sig ) rQ = Q_U2; else rQ = 3'dx;
" ]6 a" ]& {& b! |: d# `$ w* B
assign Q = rQ; & O8 O: `# B0 i+ u7 x
4 S$ E" w: ?: c9 C# v* ~* X# \
接下来,我们来分析上面的代码。 ! F( `- o" M+ o, ~6 G2 G$ ^7 K# u
: H* m( l- S! M9 F2 Z) a
always @ ( * ) 4 o6 j7 A. s) _
5 ^: } ?# b+ d. T' B% d' V4 i4 c
“always @ ( * )”这样的写法在Verilog HDL 2001 中已经被支持(好像是这个版本)。在敏感包中的“*”,可以理解为“任何状况都有效”。 # Y5 r! T4 {: [1 \
, T0 Y3 _: } b" }' r1 f2 Y
if( Right_Start_Sig ) rQ = Q_U1; else if( Left_Start_Sig ) rQ = Q_U2; else rQ = 3'dx; //不能省略掉
! V- t7 D, i V% P, x
' v! v: f- y0 e u
而“else rQ = 3'dx”,这行不能被省略掉。不要问我为什么,这是V语言的编程规则。你尝试注释掉后,再编译看看,你会发现会很多“Warning”。 + f9 d' j8 b' X3 }( \* Q
5 a# G" t! }* j! y% D' P
always @ ( * )
; U: v2 l# h+ e" E3 \x if( Right_Start_Sig ) Q = Q_U1;//连线 Q,Q_U1 和 Q_U2 之间没有
' z0 L$ j: o) c$ v$ w% J; ~! v
x else if( Left_Start_Sig ) Q = Q_U2;$ J- \, \3 k/ @, \- @% X
//寄存器驱动 , m; E7 S* v E- O
x else Q = 3'dx; 4 T$ ?' x0 G2 a$ k
还有一点请注意,因为“Q_U1”和“Q_U2”是连线的关系,所以必须使用寄存器来驱动。如上的代码中“rQ”便是扮演这样的角色。如果该寄存器被省略了,会出现编译错误。
, d1 v7 v/ p( ^9 J6 @ ~6 E- z
总结: “两义性”或者“多义性”的问题,不仅在“低级建模”中出现,日常的建模也会出现它们的踪影,然而“低级建模”出现的频率比较高罢了。“多路选择器”在设计的时候应该经多方面的考虑,亦即取得最平衡的效果。
& _1 k! }7 l0 { |