4.2 “
低级功能模块”封装 和“两义性”或者“多义性”的问题
点击浏览下一页
如上的示意图。当我们要封装2个“低级功能模块”在一次,如果两个“低级功能模块”使用同一个输入(重用输入连线)或者同一个输出(重用输出连线)就会出现两义性的问题。为了解决这个问题,使用“多路选择器”便可以。
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.
8. input CLK;
9. input RSTn;
10. input Right_Start_Sig;
11. input Left_Start_Sig;
12.
13. output Right_Done_Sig;
14. output Left_Done_Sig;
15. output [7:0]Q;
16.
17. /*******************************/
18.
19. wire [7:0]Q_U1;
20.
21. flashing_to_right U1
22. (
23. .CLK( CLK ), // input - from top
24. .RSTn( RSTn ), // input - from top
25. .Start_Sig( Right_Start_Sig ), // input - from top
26. .Done_Sig( Right_Done_Sig ), // output - to top
27. .Q( Q_U1 ) // output - to wire
28. );
29.
30. /********************************/
31.
32. wire [7:0]Q_U2;
33.
34. flashing_to_left U2
35. (
36. .CLK( CLK ), // input - from top
37. .RSTn( RSTn ), // input - from top
38. .Start_Sig( Left_Start_Sig ), // input - from top
39. .Done_Sig( Left_Done_Sig ), // output - to top
40. .Q( Q_U2 ) // output - to wire
41. );
42.
43. /*************************************/
44.
45. reg [7:0]rQ;
46.
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.
52. assign Q = rQ;
53.
54. /*************************************/
55.
56.endmodule
为了解决多“两义性”或者“多义性”的问题多路选择器常常被使用。如上述代码中在45~52行(从第27,第40行引出“连线”)“Q_U1”和“Q_U2”被if控制着输出。这样的写法是最优化的,生成的RTL图也非常的整洁。
点击浏览下一页
当然还有其他的写法:
assign Q = Right_Start_Sig ? Q_U1 : Q_U2 ;
虽然如上的写法和,第45到52行的写法相比,更为简洁,而且生成的 RTL图也一样。但是这样的写法有如下的弱点:
1. 解读性很差。
2. 只能解决两义性的问题而已。
所以不怎么推荐使用。
还有一中更糟糕的写法:
reg [7:0]rQ;
always @ ( * )
case( { Right_Start_Sig, Left_Start_Sig } )
2'b10 : rQ = Q_U1;
2'b01 : rQ = Q_U2;
default : rQ = 3'bxxx;
endcase
assign Q = rQ;
虽然该写法的解读性很高效果也一样,但是却很浪费资源。生成的RTL图如下:
点击浏览下一页
和上述两个写法相比,它可差多了,所以不推荐使用。
/**********************************************************/
reg [7:0]rQ;
always @ ( * )
if( Right_Start_Sig ) rQ = Q_U1;
else if( Left_Start_Sig ) rQ = Q_U2;
else rQ = 3'dx;
assign Q = rQ;
接下来,我们来分析上面的代码。
always @ ( * )
“always @ ( * )”这样的写法在Verilog HDL 2001 中已经被支持(好像是这个版本)。在敏感包中的“*”,可以理解为“任何状况都有效”。
if( Right_Start_Sig ) rQ = Q_U1;
else if( Left_Start_Sig ) rQ = Q_U2;
else rQ = 3'dx; //不能省略掉
而“else rQ = 3'dx”,这行不能被省略掉。不要问我为什么,这是V语言的编程规则。你尝试注释掉后,再编译看看,你会发现会很多“Warning”。
always @ ( * )
x if( Right_Start_Sig ) Q = Q_U1;//连线 Q,Q_U1 和 Q_U2 之间没有
x else if( Left_Start_Sig ) Q = Q_U2; //寄存器驱动
x else Q = 3'dx;
还有一点请注意,因为“Q_U1”和“Q_U2”是连线的关系,所以必须使用寄存器来驱动。如上的代码中“rQ”便是扮演这样的角色。如果该寄存器被省略了,会出现编译错误。
总结:
“两义性”或者“多义性”的问题,不仅在“低级建模”中出现,日常的建模也会出现它们的踪影,然而“低级建模”出现的频率比较高罢了。“多路选择器”在设计的时候应该经多方面的考虑,亦即取得最平衡的效果。
|