weiqi7777

关于一段verilog代码的思考

0
阅读(4216)

      前段时间有人在网上问以下一段代码,代表什么意思。

 always@(posedge clk ) begin
         if( rst_n )
             din <= 0;
        else
             begin
                   din <= din + 1’b1;
                   if( en )
                           din <= a – 1’b1;
    end

       初看这段代码,发现这里的din有两次进行赋值,首先是进行din的自加1操作,然后去判断en的值,为1的话然后将另外一个值减1在赋值给din,那最终的结果应该为什么了?

 

      为此,特意写了一段代码,以及给代码的测试激励来测试输出结果为什么。

      代码如下:

module ceshi 
     ( 
        input clk, 
        input rst_n, 
        input [3:0] a, 
        input  en, 
        output reg [3:0]  b 
     ); 
     always@( posedge clk ) begin 
         if( !rst_n ) 
              b <= 3'd0; 
         else 
            begin 
               b <= b + 1'b1; 
               if( en ) 
                   b <= a;               
            end  
     end 
endmodule
测试激励如下:
`timescale 1ns/1ps
module ceshi_tb; 
reg clk; 
reg rst_n; 
reg [3:0] a; 
reg en; 
wire [3:0] b; 
ceshi u1( 
          .clk(clk), 
          .rst_n(rst_n), 
          .a(a), 
          .en(en), 
          .b(b) 
         ); 
always #1 clk = ~clk;
initial  begin 
   clk = 0; 
   rst_n = 0; 
   a = 3; 
   en = 0; 
   #20 rst_n = 1; 
   repeat(10) 
     begin 
        #30 en = 1; 
        #30 en = 0; 
     end 
    #100 $finish; 
end         
endmodule

          用modelsim进行仿真。其仿真图如下所示:

image

        从上图中进行分析

              在复位信号为低电平,即复位信号有效。输出b的结果一直为0.

              当复位信号没有效的时候,而且en为低电平,每当一个时钟的上升沿,输出b的值自加1一次。

             当en为高电平的时候,输出b的值为输入a的值。。

 

        其实,对于verilog中的always块中的信号赋值,如果采用的是非阻塞,也就是<=赋值。

        每次<=赋值后,值不是立即更新,而是要等待所有的<=赋值结束后,才进行更新。而<=右边的值,都是最初始的值,不是计算后的值。

        分析上面那段代码,在时钟的上升沿,

       b <= b + 1'b1;        b的值自加1,但是因为是<=赋值,因此b的值还没有改变,依然还是没有自加1时候的b。

       if( en )
              b <= a;        当判断en为1的时候,a的值就赋值给b,但是也不是立刻改变,要等所有always块中的<=赋值结束后,才会改变。

           这个时候,我们就发现了矛盾,首先b的值自加1,但是同时再把a的值给b,这就给人一种双重赋值的感觉,因为verilog的语句是并行执行,两个都同时执行,那最后b的值为什么。

           其实,这就要追朔到verilog这个语言对<=赋值的规定了。。。verilog规定,所有的<=赋值后,值不是立刻改变,而是要等所有的<=赋值后才进行改变,而对同一个变量,如果进行多次<=赋值,那最终的赋值结果以最后一个<=赋值结果为准。

          所以说,对于上面那个代码,虽然对b进行了两次<=赋值操作,但是最后一个<=赋值是 b<=a,所以最后的结果是把a的值赋值给b,仿真结果说明了这点。

          其实,上面那个代码功能其实是一个选择器,当en为1的时候,输出的值b等于输入的值a,否则输出的值b就自加1.

 

          由上面代码,可总结到,对于同一个alywas块中的<=赋值,如果同一个信号进行多次<=赋值,那么结果,那个信号以最后一个赋值结果为准,也就是前面的赋值都是无效的。。

 

          所以说,以下赋值:(假设初始a的值为0)

          a < = a+1’b1;

          a <= a +1’b1;

          a <= a +1’b1;

                 ****     (若干次对a赋值)

         a <= a +1’b1;  

          最后a的值都是为1。也就是初始的a的值加1,也就是最后一句语句表达的。。。。其中间的赋值通通都被省略了。。。