关于assign的一点疑惑

我在编写一个十进制计数器时,遇到了使用assign与不用assign的情况,现在将两种情况分别讨论。

使用assign的情况:

代码:

 

module cnt10(    clk,rst_n,load,en,    datain,cout,dataout    );

input clk,rst_n,load,en; input [3:0]datain; output reg cout; output [3:0] dataout;

reg [3:0]qout;

assign dataout = qout;

always @(posedge clk or negedge rst_n) begin if(!rst_n) qout <= 0; else if(en) begin   if(!load) qout <= datain;   else if(qout<9) qout <= qout+1'b1;   else qout <= 4'b0000;   end end

always @(qout) if(qout==9) cout <= 1'b1; else cout <= 1'b0; endmodule

 

问题主要在RTL视图上:

不使用assign的情况:

代码:

 

module cnt10(    clk,rst_n,load,en,    datain,cout,dataout    ); input clk,rst_n,load,en; input [3:0]datain; output reg cout; output reg[3:0] dataout;

always @(posedge clk or negedge rst_n) begin if(!rst_n) dataout <= 0; else if(en) begin   if(!load) dataout <= datain;   else if(dataout<9) dataout <= dataout+1'b1;   else dataout <= 4'b0000;   end end

always @(dataout) if(dataout==9) cout <= 1'b1; else cout <= 1'b0; endmodule

其RTL Viewer为:

可以看到,两者使用的器件基本上是一样的,但是其排版似乎有区别。使用assign的情况是把qout寄存器的内容输出给dataout,dataout是一个wire变量,换句话说就是一根导线;而不使用assign的情况,直接对dataout寄存器进行操作后了输出。看起来好像没什么区别,那么这两种用法到底哪种好

verilog描述组合逻辑一般常用的有两种:assign赋值语句和always@(*)语句。两者之间的差别有:

    1. 被assign赋值的信号定义为wire型,被always@(*)结构块下的信号定义为reg型,值得注意的是,这里的reg并不是一个真正的触发器,只有敏感列表为上升沿触发的写法才会综合为触发器,在仿真时才具有触发器的特性。

    2. 另外一个区别则是更细微的差别:举个例子,

    wire a;

      reg b;

   assign a = 1'b0;

   always@(*)

       b = 1'b0;

    在这种情况下,做仿真时a将会正常为0, 但是b却是不定态。这是为什么?verilog规定,always@(*)中的*是指该always块内的所有输入信号的变化为敏感列表,也就是仿真时只有当always@(*)块内的输入信号产生变化,该块内描述的信号才会产生变化,而像always@(*) b = 1'b0;

    这种写法由于1'b0一直没有变化,所以b的信号状态一直没有改变,由于b是组合逻辑输出,所以复位时没有明确的值(不定态),而又因为always@(*)块内没有敏感信号变化,因此b的信号状态一直保持为不定态。事实上该语句的综合结果有可能跟assign一样(本人没有去尝试),但是在功能仿真时就差之千里了。

posted @ 2015-03-10 23:35  苍月代表我  阅读(945)  评论(0编辑  收藏  举报