|
4.2 “低级功能模块”封装 和“两义性”或者“多义性”的问题 http://a.imagehost.org/0020/PIC4_3a.jpg 如上的示意图。当我们要封装2个“低级功能模块”在一次,如果两个“低级功能模块”使用同一个输入(重用输入连线)或者同一个输出(重用输出连线)就会出现两义性的问题。为了解决这个问题,使用“多路选择器”便可以。
2 S/ d2 r# d' x( Y7 M3 c! e t3 E
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.
% _) b2 _3 A+ F6 Y0 F 8. input CLK; 9. input RSTn; 10. input Right_Start_Sig; 11. input Left_Start_Sig; 12.1 N% t5 e3 a3 w n- S: Q. _* W
13. output Right_Done_Sig; 14. output Left_Done_Sig; 15. output [7:0]Q; 16.- N& u5 K+ _' j a* L0 i+ E; M
17.
( N- Y+ D2 y+ ^% d /*******************************/ 18.+ W% A2 N( F& ~% V: R4 s2 {
19. wire [7:0]Q_U1; 20.$ e3 L: P3 H T, P6 ?, d
21. flashing_to_right U1 22. ( 23. .CLK( CLK ), ! N7 l* @; b5 F3 j" X
9 g. p" y; Y/ K( E- M0 N
! t. y4 P. _# n) k! E( R
// input - from top 24. .RSTn( RSTn ),# R5 u- H% F( a0 P% v
9 U# W. [, S# e- b. D$ o
. `4 S0 A9 o5 {" C
/ a: X$ S( u0 U# J
a% H1 |! F# u' w, Q
// input - from top 25. .Start_Sig( Right_Start_Sig ),
5 @! T/ g% B6 a// input - from top 26. .Done_Sig( Right_Done_Sig ), // output - to top 27. .Q( Q_U1 )" V) Q+ U) I6 h6 w/ S6 Z
2 x) O$ M1 p: z+ t& t
. q9 Z3 D( n$ Z$ n- j! a$ m3 f6 t1 j
9 w: D0 H8 X/ S8 L3 e1 s
/ \8 e( v, R/ e/ _// output - to wire 28. ); 29.% a' u! s' E& Z! P! k6 i: y1 A6 _
30.( s3 @" o) C& y2 \' F! E, j2 R
/********************************/ 31.1 a5 B9 ~8 O' ?& r8 W
32. wire [7:0]Q_U2; 33.
3 @: I- e) m6 Z. \. q, Q" v 34. flashing_to_left U2 35. ( 36. .CLK( CLK ), 8 n0 Y. R4 W- ?" s3 q+ A/ O* e
, J1 d7 z" |5 w! {2 ]* \% p; k* ~// input - from top 37. .RSTn( RSTn ),
/ N- q; o. p/ ?$ |8 ?4 [1 Q g// input - from top 38. .Start_Sig( Left_Start_Sig ), . s' s5 E( t' W+ _6 J3 n* ~
// input - from top 39. .Done_Sig( Left_Done_Sig ),. W/ L" `( Q* M5 f4 S
// output - to top 40. .Q( Q_U2 )7 H3 V1 L$ N! N1 g% u6 z, u4 j
9 k0 P7 ~3 `0 U: A/ A6 v) E/ c# ~
C3 U3 I; e/ l2 y! U7 e- C- C: U$ X1 t% s) R- n3 b
; U" R7 Z& D3 J# U( X) C7 d
/ m- Z, Q5 C) h' l7 P9 Z# A// output - to wire 41. ); 42.
7 w; m ~# Z8 @. \+ [6 _8 L7 C 43.
5 \, I' n. y. G/*************************************/ 44.
! a X* V. ]/ {; l; x' }7 V 45. reg [7:0]rQ; 46.
5 k& o- ^8 {* k X0 U( e# j! l* X 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.
! M$ K" w3 E7 a8 a2 v0 e 52. assign Q = rQ; 53.
% b. H; w6 X" x" K 54.6 f5 [) O3 h1 a. I8 R
/*************************************/ 55.
2 x# H6 a/ |6 q$ w! M3 U5 \ 56.endmodule 5 ^0 W& M' F- f
; O; l( k( D; O5 {
$ p) ~ Y0 G: a, Q
为了解决多“两义性”或者“多义性”的问题多路选择器常常被使用。如上述代码中在45~52行(从第27,第40行引出“连线”)“Q_U1”和“Q_U2”被if控制着输出。这样的写法是最优化的,生成的RTL图也非常的整洁。 4 l, K2 q, C6 L$ U# M
http://space.ednchina.com/upload/2010/6/5/0f6b6eb3-8c6b-4af8-bcdc-6946a733b70a.jpg / P* Q# a7 o( [+ Q
当然还有其他的写法: ' Z2 A1 y( e! w& ]2 G/ M- h
assign Q = Right_Start_Sig ? Q_U1 : Q_U2 ; 7 Q$ B/ H7 h: y) P P
虽然如上的写法和,第45到52行的写法相比,更为简洁,而且生成的 RTL图也一样。但是这样的写法有如下的弱点:
* g3 e' x4 Q, ~8 m
1. 解读性很差。 2. 只能解决两义性的问题而已。 2 M% Q8 }8 i* P
所以不怎么推荐使用。 * e" j: r; S2 E9 m* x/ x' B
还有一中更糟糕的写法:
3 s& b7 O' d0 K" G/ @$ b0 m
reg [7:0]rQ; 6 x& C. c; R O" e& O: u
always @ ( * ) case( { Right_Start_Sig, Left_Start_Sig } ) 2'b10 : rQ = Q_U1; 2'b01 : rQ = Q_U2; default : rQ = 3'bxxx; endcase ; j8 p& a, Y- u' J
assign Q = rQ; 虽然该写法的解读性很高效果也一样,但是却很浪费资源。生成的RTL图如下: 5 g; E' G0 Q+ ?7 m- w
http://space.ednchina.com/upload/2010/6/5/2f9ae0c3-d220-4ce9-b86b-ebf273901983.jpg & V" n5 h- b, {, p0 L. x: r2 h
和上述两个写法相比,它可差多了,所以不推荐使用。 9 O# `0 s! J# Q- g
/**********************************************************/ 9 _# O9 O4 H2 {4 O2 x7 U2 L
reg [7:0]rQ; . T+ j7 \+ c* i7 m1 r7 G
always @ ( * ) if( Right_Start_Sig ) rQ = Q_U1; else if( Left_Start_Sig ) rQ = Q_U2; else rQ = 3'dx; " L* E+ Y5 N5 `1 P- ^
assign Q = rQ; ' B- a6 g9 D* |! ]0 a
+ W9 |: d/ q" Q: [) r2 R
接下来,我们来分析上面的代码。
?. k& ^' `6 P6 V
& k" S* ?, Z; E
always @ ( * )
5 O% T) \, ], L
7 o+ [% X' O0 e
“always @ ( * )”这样的写法在Verilog HDL 2001 中已经被支持(好像是这个版本)。在敏感包中的“*”,可以理解为“任何状况都有效”。
8 @& r' {/ c) I& O. e% G
. Z3 V2 J t4 `1 d0 T7 X. c
if( Right_Start_Sig ) rQ = Q_U1; else if( Left_Start_Sig ) rQ = Q_U2; else rQ = 3'dx; //不能省略掉 , t# O$ F% M* p* W, p& \
% N) g+ u e3 L$ }# N
而“else rQ = 3'dx”,这行不能被省略掉。不要问我为什么,这是V语言的编程规则。你尝试注释掉后,再编译看看,你会发现会很多“Warning”。
. H1 H2 v$ x+ S ]; x( B
' A/ H" s$ x# Q4 j
always @ ( * )
/ L. Y) Z# z- ^x if( Right_Start_Sig ) Q = Q_U1;//连线 Q,Q_U1 和 Q_U2 之间没有
1 z. }. O3 l: c2 n/ O1 L
x else if( Left_Start_Sig ) Q = Q_U2;
3 k- \2 N0 V* B. O# P8 O//寄存器驱动
+ a4 X& J6 Q' `3 Y) S( ~& j4 hx else Q = 3'dx;
% s, S& u9 j" Z; h5 e
还有一点请注意,因为“Q_U1”和“Q_U2”是连线的关系,所以必须使用寄存器来驱动。如上的代码中“rQ”便是扮演这样的角色。如果该寄存器被省略了,会出现编译错误。 [* D7 K( j2 f8 V$ J: n& z
总结: “两义性”或者“多义性”的问题,不仅在“低级建模”中出现,日常的建模也会出现它们的踪影,然而“低级建模”出现的频率比较高罢了。“多路选择器”在设计的时候应该经多方面的考虑,亦即取得最平衡的效果。
5 D7 ?% @1 M% |' D% H L6 B |