羽蒙 发表于 2014-8-15 15:34:32

Verilog HDL 建模技巧 低级建模 仿顺序操作·思路篇 10 - 组织模块和两义性问题

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 Q;
16.   
17.    /*******************************/
18.   
19.    wire 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 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 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 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 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”便是扮演这样的角色。如果该寄存器被省略了,会出现编译错误。

总结:
“两义性”或者“多义性”的问题,不仅在“低级建模”中出现,日常的建模也会出现它们的踪影,然而“低级建模”出现的频率比较高罢了。“多路选择器”在设计的时候应该经多方面的考虑,亦即取得最平衡的效果。

Sunlife 发表于 2014-8-15 21:41:51

,使用“多路选择器”便可以。
页: [1]
查看完整版本: Verilog HDL 建模技巧 低级建模 仿顺序操作·思路篇 10 - 组织模块和两义性问题