4.2 “低级功能模块”封装 和“两义性”或者“多义性”的问题 http://a.imagehost.org/0020/PIC4_3a.jpg 如上的示意图。当我们要封装2个“低级功能模块”在一次,如果两个“低级功能模块”使用同一个输入(重用输入连线)或者同一个输出(重用输出连线)就会出现两义性的问题。为了解决这个问题,使用“多路选择器”便可以。 D& k$ {+ z1 S. z, [. U
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.
9 V' B, O6 G6 a3 f+ D: J 8. input CLK; 9. input RSTn; 10. input Right_Start_Sig; 11. input Left_Start_Sig; 12.8 [9 b" `% x3 X Y5 q/ ?- E0 r
13. output Right_Done_Sig; 14. output Left_Done_Sig; 15. output [7:0]Q; 16.
1 F3 ]9 x9 e' c( d C0 p1 k' e 17.
' u, y9 a/ p, L4 M6 c( b /*******************************/ 18.4 L# x; Y0 d9 S" X, Y1 h
19. wire [7:0]Q_U1; 20.
4 n) |2 j5 H' R( ~% K1 y( [ L 21. flashing_to_right U1 22. ( 23. .CLK( CLK ),
" v; F8 G1 N ]+ w3 @
) t- ~$ P4 P2 g( S" L3 V
! T: E) ]4 Q3 A- `/ O// input - from top 24. .RSTn( RSTn ),- w q( o$ q8 e1 f* x6 C' J
# R8 R, s% \2 N
+ T; o7 i( a4 n3 F$ `% M, h& ~3 X+ W3 Z5 N" @1 p
0 g8 u1 l) I6 [" V& s// input - from top 25. .Start_Sig( Right_Start_Sig ), & r6 e& q- i' F) Y
// input - from top 26. .Done_Sig( Right_Done_Sig ), // output - to top 27. .Q( Q_U1 )
4 y. h9 F0 J9 N: l! d2 e1 c3 S6 X" I$ C6 T2 H5 q* J. P# i$ q
: H9 D- F. t' E' y1 w6 h0 R
R* Z6 b* ?' w, r
# D7 r( _& M( O9 M
% p& H4 a$ c1 U! S' S8 ~3 H* l5 W// output - to wire 28. ); 29.
; _' M7 q9 N+ v5 a6 h 30.
- k- h# s- x& ]8 u/ U! e7 Y6 d% I) Q/********************************/ 31.
) j7 g. R9 `& o( e 32. wire [7:0]Q_U2; 33.+ N) l3 O0 l: W
34. flashing_to_left U2 35. ( 36. .CLK( CLK ),
# ~' G5 |( f( {$ Y8 q" Q7 o$ @7 U
6 D- a& a2 U8 `// input - from top 37. .RSTn( RSTn ), 3 L& `0 W' i9 @# `4 G3 [1 ^. ]
// input - from top 38. .Start_Sig( Left_Start_Sig ),
+ ]/ a, N1 Z' |! _( @' \1 h// input - from top 39. .Done_Sig( Left_Done_Sig ),* b. D' N) W+ \: P- v9 j
// output - to top 40. .Q( Q_U2 )4 n: O& s9 b$ w& f# ^# e$ _: j, d
" H6 o1 }. U( c5 `
3 F4 _ p6 E6 w+ r" Y# w, @: q; D& `6 {- l" s" g* \
- z) {+ t! K1 s& T, W1 k9 R
2 V+ f6 H9 m5 _. n3 B// output - to wire 41. ); 42.
. t' Y1 J0 | U; I0 ]2 | 43.
2 m0 Q, H2 q* R7 X# X/*************************************/ 44." j9 Q6 k3 j- D" J2 ~
45. reg [7:0]rQ; 46.
/ W) x4 v& O& Q, p. U9 s 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.( e: q) h( W/ G8 Y( i* t7 Y" C/ [
52. assign Q = rQ; 53.. N7 p! Z$ K# K
54., j0 f6 S6 B* x" q3 e, g6 A
/*************************************/ 55.2 n* L! V9 r& S& Q9 u
56.endmodule , y% v8 Y" b' \- O
0 }' ]' y) j! Y* s0 R+ m# P
4 e3 ?4 J" ^6 c0 {; @
为了解决多“两义性”或者“多义性”的问题多路选择器常常被使用。如上述代码中在45~52行(从第27,第40行引出“连线”)“Q_U1”和“Q_U2”被if控制着输出。这样的写法是最优化的,生成的RTL图也非常的整洁。 1 [3 f0 S n( J9 G9 ~& i
http://space.ednchina.com/upload/2010/6/5/0f6b6eb3-8c6b-4af8-bcdc-6946a733b70a.jpg
$ s/ B2 g, K9 r$ R: j l! K当然还有其他的写法:
* d7 I' H Z9 Y" q3 l
assign Q = Right_Start_Sig ? Q_U1 : Q_U2 ; 5 N0 B; U8 M3 A) o2 [# y1 d
虽然如上的写法和,第45到52行的写法相比,更为简洁,而且生成的 RTL图也一样。但是这样的写法有如下的弱点:
) u6 m7 ?! r0 e4 o+ P. u r4 [" e
1. 解读性很差。 2. 只能解决两义性的问题而已。
5 x$ o- n3 u! O% \9 J
所以不怎么推荐使用。
7 j& N6 U" U' C+ L0 ~
还有一中更糟糕的写法:
# q! z, F) X! o1 j A
reg [7:0]rQ;
0 U+ U* [1 n& ~& u. n
always @ ( * ) case( { Right_Start_Sig, Left_Start_Sig } ) 2'b10 : rQ = Q_U1; 2'b01 : rQ = Q_U2; default : rQ = 3'bxxx; endcase # T2 b* r( k: G! ]
assign Q = rQ; 虽然该写法的解读性很高效果也一样,但是却很浪费资源。生成的RTL图如下: 6 d. Y% e" n F% ~8 ~
http://space.ednchina.com/upload/2010/6/5/2f9ae0c3-d220-4ce9-b86b-ebf273901983.jpg
: Z: Q. Q. A- z `
和上述两个写法相比,它可差多了,所以不推荐使用。 0 s+ h5 n5 U# z, W3 [( E) r1 B
/**********************************************************/
: S+ w5 D6 R8 ?5 W* u6 a7 s
reg [7:0]rQ;
1 [4 R& T4 a8 W, C' Z
always @ ( * ) if( Right_Start_Sig ) rQ = Q_U1; else if( Left_Start_Sig ) rQ = Q_U2; else rQ = 3'dx; + m2 v) j; D$ R8 P! g6 {
assign Q = rQ; L3 w* R/ a$ Z1 x
( X% [1 I! o" q8 `& A$ f$ ?
接下来,我们来分析上面的代码。 , p& g* [5 y' Y4 N1 v4 z
* |5 E) P$ L/ ~3 A7 g4 p
always @ ( * ) 0 f' M G$ R- W+ H$ e$ Z' {3 @
( g, i! y" D0 P* o2 T) ~
“always @ ( * )”这样的写法在Verilog HDL 2001 中已经被支持(好像是这个版本)。在敏感包中的“*”,可以理解为“任何状况都有效”。
5 X& U# S1 T6 K7 h" @; b
5 D6 S ?5 p5 `% Q
if( Right_Start_Sig ) rQ = Q_U1; else if( Left_Start_Sig ) rQ = Q_U2; else rQ = 3'dx; //不能省略掉 * r, \3 x4 H9 r: a6 i& g! W6 F
2 q- u! _& C1 e( m+ c' v
而“else rQ = 3'dx”,这行不能被省略掉。不要问我为什么,这是V语言的编程规则。你尝试注释掉后,再编译看看,你会发现会很多“Warning”。
+ ^8 u0 o T3 A- \5 A/ I- D4 x0 j
- l2 W- _# o. w$ ]0 v; F% i1 F
always @ ( * ) 9 ~- Y2 }6 e: i1 S [; b1 G S
x if( Right_Start_Sig ) Q = Q_U1;//连线 Q,Q_U1 和 Q_U2 之间没有
' b' u$ W& z" q, L* ]# t; I9 ?# Y7 zx else if( Left_Start_Sig ) Q = Q_U2;' X4 q" \; Y/ b0 ^
//寄存器驱动
- z9 T0 A- |7 Bx else Q = 3'dx;
. ~% E a* }8 i2 l: x, i
还有一点请注意,因为“Q_U1”和“Q_U2”是连线的关系,所以必须使用寄存器来驱动。如上的代码中“rQ”便是扮演这样的角色。如果该寄存器被省略了,会出现编译错误。 * B$ i+ r# w) m0 t
总结: “两义性”或者“多义性”的问题,不仅在“低级建模”中出现,日常的建模也会出现它们的踪影,然而“低级建模”出现的频率比较高罢了。“多路选择器”在设计的时候应该经多方面的考虑,亦即取得最平衡的效果。 3 y7 R `+ v5 q! D
|