zoukankan      html  css  js  c++  java
  • verilog语法实例学习(2)

    Verilog中的信号类型

    线网类型

          线网类型表示一个或多个门或者其它类型的信号源驱动的硬件连线。如果没有驱动源,则线网的默认值为z。verilog中定义的线网类型有以下几种:     wire,tri,wor,trior,wand,triand,trireg,tri1,tri0,supply0,supply1。其中最主要的是wire/tri,其它的类型都是综合中用不到的线网

    wire线网用来连接线路中一个逻辑模块的输出和另一个逻辑模块的输入,通常用来表示单个门驱动或连续赋值语句驱动的连线型数据。下面是wire类型的声明例子。

    wire x;

    wire [3:0] s;

    wire [2:1] s1; //范围可以不从0开始

    tri类型线网表示电路的连接以三态方式进行。它和wire是等价的,它只是用来提高三态门代码的可读性。例如:

    tri z;

    tri [7:0] out;

    比如下面的三态门代码,它们分析与综合后,是相同的逻辑电路。

    module trigate1(in,en,out);
    
      input in;
      input en;
      output out;
      wire out;
    
      assign out = en?in:'bz;
    
    endmodule
    
    module trigate2(in,en,out);
    
      input in;
      input en;
      output out;
      wire out;
    
      bufif1(out,in,en);//或者可以用bufif1 mybufif1(out,in,en);
    
    endmodule
    module trigate3(in,en,out);
    
      input in;
      input en;
      output out;
      tri out;
    
      assign out = en?in:'bz;
    
    endmodule
    
    module trigate4(in,en,out);
    
      input in;
      input en;
      output out;
      tri out;
    
      bufif1(out,in,en);//或者可以用bufif1 mybufif1(out,in,en);
    
    endmodule

    在quartus中分析与综合上面代码中的四个模块,用rtl view看到的逻辑电路如下所示:trigate1, trigate2,trigate3,trigate4,都是对应形同的三态门。

    imageimage

    imageimage

    用下面的testbench代码,从波形中我们可以看到这四个模块都实现三态门的逻辑。

    `timescale 1ns/1ns
    
    module trigate_tb;
    
       reg in1,in2,in3,in4;
    	reg en;
    	wire out1, out2;
    	tri out3,out4;
    
    	trigate1 trigate1_0(.in(in1),.en(en),.out(out1));
    	trigate2 trigate2_0(.in(in2),.en(en),.out(out2));
    	trigate3 trigate3_0(.in(in3),.en(en),.out(out3));
    	trigate4 trigate4_0(.in(in4),.en(en),.out(out4));
    
    	initial
    	begin
    	   en = 1'b0;
    		in1 = 1'b1;
    		#10
    		in2 = 1'b0;
    		#10
    		in3 = 1'b1;
    		#10
    		in4 = 1'b0; //en =0, out1/out2/out3/out4 都为高阻态
    		#10
    		en = 1'b1; //此时,out1=in1, ...,out4=in4
    		#10;
    		$stop;
    
    	end
    
    endmodule

    image

    当一个线网有多个驱动源时,即对一个线网有多个赋值时,不同的线网产生不同的行为。例如:

    wire r;

    assign r = a & b;

    assign r = c | d;

    clip_image002[6]

    r有两个驱动源,由于它是线网,r的有效值由使用驱动源的值的线表决定(下面的wire/tri表),如果如上图所示,则r为x。

    如果有多个驱动源,线网的有效值如下表:可以看到只要输入端有x,输出端一定为x,而z状态是最弱的,只要有其它状态都能改变输出值。输入为0和1,输出为x。

    wire/tri

    0

    1

    x

    z

    0

    0

    x

    x

    0

    1

    x

    1

    x

    1

    x

    x

    x

    x

    x

    z

    0

    1

    x

    z

    备注:在quartus+modelsim中,这样代码不能通过编译的,所以应该是不可综合的,只能在testbench中使用。

    Error (10028): Can't resolve multiple constant drivers for net "r" at mulassign.v(7),。

    module mulassign(a,b,r);
      input a,b;
      output r;
      wire r;
    
      assign r = a;
      assign r = b;
    
    endmodule

    直接把module包含在testbench中,用vcs编译的。然后run simv,得到下面结果,和上面表中的值是匹配的:

    Compiler version M-2017.03-SP2-11; Runtime version M-2017.03-SP2-11;  Dec 27 16:10 2018
                        0  0  0 final result 0}
                       10  1  1 final result 1}
                       20  0  1 final result x}
                       30  1  0 final result x}
                       40  z  z final result z}
                       50  x  1 final result x}
                       60  x  z final result x}
                       70  0  x final result x}


    `timescale 1ns/1ns
    `include "mulassign.v"
    
    module mulassign_tb;
      reg a,b,c,d;
      wire r;
      mulassign mulassign_0(.a(a),.b(b),.c(c),.d(d),.r(r));
    
      initial
      begin
         a = 1'b0;b=1'b0; c=1'b0; d= 1'b0; // 0 0
         #10
         a = 1'b1;b=1'b1; c=1'b0; d= 1'b1; //1,1
         #10
         a = 1'b0;b=1'b1; c=1'b0; d= 1'b1;//0 1
         #10
         a = 1'b1;b=1'b1; c=1'b0; d= 1'b0;//1,0
         #10
         a = 1'bz;b=1'bz; c=1'bz; d= 1'bz;
         #10
         a = 1'bx;b=1'b1; c=1'b0; d= 1'b1;
         #10
         a = 1'b0;b=1'b1; c=1'bx; d= 1'b1;
         #10
         a = 1'b0;b=1'b1; c=1'bz; d= 1'b1;
      end
    
      initial
      begin
    	$monitor($time,,,"%b & %b, %b | %b, final result %b}", a, b, c,d,r);
    	#400 $finish;
      end
      initial
      begin
    	 $dumpfile("dump.vcd");
    	 $dumpvars;
      end
    endmodule;
    


    wor和trior线网:对于wor如果某个驱动源为1,那么线网的值也是1,wor和三态或(trior)在语法和功能上是一致的。如果多个驱动源驱动这类网,网的有效值由下表决定:

    wor/trior

    0

    1

    x

    z

    0

    0

    1

    x

    0

    1

    1

    1

    1

    1

    x

    x

    1

    x

    x

    z

    0

    1

    x

    z

    module mulassign1(a,b,r);
      input a,b;
      output r;
      wor r;
      assign r = a;
      assign r = b;
    
    endmodule
    `timescale 1ns/1ns
    `include "mulassign1.v"
    
    module mulassign_tb;
      reg a,b;
      wire r;
      mulassign1 mulassign1_0(.a(a),.b(b),.r(r));
    
      initial
      begin
         a = 1'b0;b=1'b0;
         #10
         a = 1'b1;b=1'b1;
         #10
         a = 1'b0;b=1'b1;
         #10
         a = 1'b1;b=1'b0;
         #10
         a = 1'bz;b=1'bz;
         #10
         a = 1'bx;b=1'b1;
         #10
         a = 1'bx;b=1'bz;
         #10
         a = 1'b0;b=1'bx;
      end
    
      initial
      begin
    	$monitor($time,,,"%b  %b final result %b}", a, b,r);
    	#400 $finish;
      end
      initial
      begin
    	 $dumpfile("dump.vcd");
    	 $dumpvars;
      end
    endmodule;
    

    用上面的代码,用vcs编译后,运行simv可以得到如下的结果,可见是要某个信号源为1,则结果为1:

    Compiler version M-2017.03-SP2-11; Runtime version M-2017.03-SP2-11;  Dec 27 17:37 2018
                        0  0  0 final result 0}
                       10  1  1 final result 1}
                       20  0  1 final result 1}
                       30  1  0 final result 1}
                       40  z  z final result z}
                       50  x  1 final result 1}
                       60  x  z final result x}
                       70  0  x final result x}
    $finish called from file "mulassign1_tb.v", line 31.


    wand和triand线网,线与(wand)如果某个驱动源为0,那么线网的值为0。线与和三态线与(triand)网在语法和功能上是一致的。

    wand/triand

    0

    1

    x

    z

    0

    0

    0

    0

    0

    1

    0

    1

    x

    1

    x

    0

    x

    x

    x

    z

    0

    1

    x

    z

    module mulassign2(a,b,r);
      input a,b;
      output r;
      wand r;
      assign r = a;
      assign r = b;
    
    endmodule
    `timescale 1ns/1ns
    `include "mulassign2.v"
    
    module mulassign_tb;
      reg a,b;
      wire r;
      mulassign2 mulassign2_0(.a(a),.b(b),.r(r));
    
      initial
      begin
         a = 1'b0;b=1'b0;
         #10
         a = 1'b1;b=1'b1;
         #10
         a = 1'b0;b=1'b1;
         #10
         a = 1'b1;b=1'b0;
         #10
         a = 1'bz;b=1'bz;
         #10
         a = 1'bx;b=1'b1;
         #10
         a = 1'bx;b=1'bz;
         #10
         a = 1'b0;b=1'bx;
      end
    
      initial
      begin
    	$monitor($time,,,"%b  %b final result %b}", a, b,r);
    	#400 $finish;
      end
      initial
      begin
    	 $dumpfile("dump.vcd");
    	 $dumpvars;
      end
    endmodule;
    

    用vcs编译后,运行simv,得到以下结果,可见只要有信号源为0,则结果为0:

    Compiler version M-2017.03-SP2-11; Runtime version M-2017.03-SP2-11;  Dec 27 17:47 2018
                        0  0  0 final result 0}
                       10  1  1 final result 1}
                       20  0  1 final result 0}
                       30  1  0 final result 0}
                       40  z  z final result z}
                       50  x  1 final result x}
                       60  x  z final result x}
                       70  0  x final result 0}
    $finish called from file "mulassign2_tb.v", line 31.


          trireg线网,此线网存储数值,并且用于电容节点建模。当三态寄存器(trireg)的所有驱动源都处于高阻态,即值为z时,三态寄存器线网保存以前的值。三态寄存器线网的缺省初始值为x。

    module mulassign3(a,b,r);
      input a,b;
      output r;
      trireg r;
      assign r = a;
      assign r = b;
    
    endmodule
    
    `timescale 1ns/1ns
    `include "mulassign3.v"
    
    module mulassign_tb;
      reg a,b;
      wire r;
      mulassign3 mulassign3_0(.a(a),.b(b),.r(r));
    
      initial
      begin
         a = 1'b0;b=1'b0;
         #10
         a = 1'b1;b=1'b1;
         #10
         a = 1'bz;b=1'bz;
         #10
         a = 1'b0;b=1'b0;
         #10
         a = 1'bz;b=1'bz;
         #10
         a = 1'b1;b=1'b0;
         #10
         a = 1'bz;b=1'bz;
         #10
         a = 1'b0;b=1'bx;
      end
    
      initial
      begin
    	$monitor($time,,,"%b  %b final result %b}", a, b,r);
    	#400 $finish;
      end
      initial
      begin
    	 $dumpfile("dump.vcd");
    	 $dumpvars;
      end
    endmodule;
    

    用上面的代码,vcs编译后,运行simv,得到以下结果:

    Compiler version M-2017.03-SP2-11; Runtime version M-2017.03-SP2-11;  Dec 27 18:46 2018
                       0  0  0 final result 0}
                      10  1  1 final result 1}
                      20  z  z final result 1}
                      30  0  0 final result 0}
                      40  z  z final result 0}
                      50  1  0 final result x}
                      60  z  z final result 0}
                      70  0  x final result x}
    


    tri0和tri1线网,分别用来建模下拉电阻和上拉电阻。这类线网可用于线逻辑的建模,即线网有多于一个驱动源,tri0线网的特征是,若无驱动源驱动,它的值为0,tri1与其相反。


    tri0/tri1

    0

    1

    x

    z

    0

    0

    x

    x

    0

    1

    x

    1

    x

    1

    x

    x

    x

    x

    x

    z

    0

    1

    x

    0(1)

    module mulassign(a,b,r);
      input a,b;
      output r;
      tri0 r;
      assign r = a;
      assign r = b;
    endmodule
    module mulassign1(a,b,r);
      input a,b;
      output r;
      tri1 r;
      assign r = a;
      assign r = b;
    endmodule


    `timescale 1ns/1ns
    `include "mulassign4.v"
    
    module mulassign_tb;
      reg a,b;
      wire r,r1;
      mulassign mulassign_0(.a(a),.b(b),.r(r));
      mulassign1 mulassign1_0(.a(a),.b(b),.r(r1));
    
      initial
      begin
         a = 1'b0;b=1'b0;
         #10
         a = 1'b1;b=1'b1;
         #10
         a = 1'b0;b=1'b1;
         #10
         a = 1'b1;b=1'b0;
         #10
         a = 1'bz;b=1'bz;
         #10
         a = 1'bx;b=1'b1;
         #10
         a = 1'bx;b=1'bz;
         #10
         a = 1'b0;b=1'bx;
      end
    
      initial
      begin
    	$monitor($time,,,"%b  %b final result %b %b}", a, b,r,r1);
    	#400 $finish;
      end
      initial
      begin
    	 $dumpfile("dump.vcd");
    	 $dumpvars;
      end
    endmodule;

    上面的代码vcs编译后,运行simv得到以下结果:

    Compiler version M-2017.03-SP2-11; Runtime version M-2017.03-SP2-11;  Dec 27 19:09 2018
                        0  0  0 final result 0 0}
                       10  1  1 final result 1 1}
                       20  0  1 final result x x}
                       30  1  0 final result x x}
                       40  z  z final result 0 1}
                       50  x  1 final result x x}
                       60  x  z final result x x}
                       70  0  x final result x x}


    supply0和supply1线网,supply0用于对地建模,即低电平0,supply1用于对电源建模,即高电平1。

    如下例所示:

    supply1  vdd;

    supply0  gnd;

    assign a=vdd; //connect to vdd

    assign b=gnd; //Connectb to gnn

    `timescale 1ns/1ns
    
    module mulassign_tb;
      wire a,b;
      supply1  vdd;
      supply0  gnd;
      assign a=vdd; //connect to vdd
      assign b=gnd; //Connectb to gnn
    
      initial
      begin
    	$monitor($time,,,"%b  %b }", a, b);
    	#400 $finish;
      end
      initial
      begin
    	 $dumpfile("dump.vcd");
    	 $dumpvars;
      end
    endmodule;
    


    Compiler version M-2017.03-SP2-11; Runtime version M-2017.03-SP2-11;  Dec 27 19:29 2018
                       0  1  0 }
    $finish called from file "supply_tb.v", line 13.


           未说明的线网,在Verilog HDL中,有可能不必声明某种线网类型,在这样的情况下,缺省线网类型为1位wire类型线网。可以使用`default_nettype编译器指令改变隐式线网说明,例如:`default_nettype wand,但是default_nettype不能是supply0/supply1

          向量和标量线网:在定义向量线网时可选用关键词scalared或vectored。如果一个线网定义时使用了关键词vectored,那么就不允许位选操作和部分选择该线网。如果没有定义关键词,缺省值为scalared。

    下面的代码可以用vcs编译,运行simv,得到结果,好像vcs和modelsim中,使用vectored定义wire,这个不允许位选操作和部分选择该线网并不成立

    Compiler version M-2017.03-SP2-11; Runtime version M-2017.03-SP2-11;  Dec 27 20:53 2018
                       0  10101010  010z }
    $finish called from file "wirev_tb.v", line 12


    `timescale 1ns/1ns
    
    module mulassign_tb;
      wire vectored [7:0] a;
      wire vectored [3:0] b;
      assign a=8'b10101010;
      assign b[3:1]=a[4:2];
    
      initial
      begin
    	$monitor($time,,,"%b  %b }", a, b);
    	#400 $finish;
      end
      initial
      begin
    	 $dumpfile("dump.vcd");
    	 $dumpvars;
      end
    endmodule;
    

    变量类型

          线网提供了一种逻辑元件互联的方式,但线网不能以行为的方式来描述电路,保持电路中间的信号值。为了达到这个目的,verilog提供了变量,可以在一条verilog语句中给一个变量赋值,这个变量会一直保持这一个值,直到被随后的赋值语句覆盖。变量的类型以下几种:reg和integer,time, real/realtime

    integer i;

    reg[2:0] count;

    count=0;

    for(i=0;i<4;i=i+1)

        count = count +1

    上面的代码中count是电路行为级模型,所以不能用wire,只能用reg。注意:integer主要用来控制循环变量,本身并不对应电路的结点。

    integer可以作为普通reg类型使用,典型应用为高层次行为建模。使用整数型形式说明如下:

    integer integer1,integer2,...,integerN[msb:lsb];

    例如:

             integer A,B,C; //表示三个integer类型变量

             integer Hist [3:6]; //一组四个integer类型变量

          一个整数型寄存器可存储有符号数,并且算术操作符提供2的补码运算结果。整数不能作为位向量访问。一种截取位值的方法是将整数赋值给一般的reg类型变量,然后从中选取相应的位。

    ================

    reg [31:0] Breg;

    integer Bint;

    Breg = Bint; //直接访问Bint[6]和Bint[20:10]是不允许的,但是Breg[6]和Breg[20:10]是允许的了。


    time类型的寄存器用于存储和处理时间, time是一个无符号整数变量,位宽是64位。例如:time Events [0:31]; //时间值数组

    time CurrTime; //currtime存储一个时间值。

    real和realtime类型,real是有符号的浮点数,双精度。real寄存器使用如下:

    real real_reg 1, real_reg2, . . ., real_regN;

    real和realtime类型和使用完全相同。real说明的变量的缺省值为0,不允许对real声明值域、位界限或字节界限。real类型和reg类型没有一一对应的关系。

    下面是time和real/real time的实例代码,从结果中可以看出time和real/realtime的区别,time只显示10ns倍数的整数,而realtime和real则可以显示精确的时间。

    Compiler version M-2017.03-SP2-11; Runtime version M-2017.03-SP2-11; Dec 26 09:14 2018

    t1 = 0, t2 = 0.000000, t3 = 0.000000, set = 0

    t1 = 2, t2 = 1.600000, t3 = 1.600000, set = 1

    t1 = 3, t2 = 3.200000, t3 = 3.200000, set = 2

    V C S S i m u l a t i o n R e p o r t

    `timescale 10ns/1ns
    module test;
      reg [7:0] set;
      time t1;
      realtime t2;
      real t3;
      parameter p=1.6;
      initial
        begin
         set = 0;
         t1 = $time;
         t2 = $realtime;
         t3 = $realtime;
         $display("t1 = %d, t2 = %f, t3 = %f, set = %d",t1,t2,t3,set);
         #p  set=1;
         t1 = $time;
         t2 = $realtime;
         t3 = $realtime;
         $display("t1 = %d, t2 = %f, t3 = %f, set = %d",t1,t2,t3,set);
         #p  set=2;
         t1 = $time;
         t2 = $realtime;
         t3 = $realtime;
         $display("t1 = %d, t2 = %f, t3 = %f, set = %d",t1,t2,t3,set);
        end
    endmodule
    

    有符号数

    Verilog中,线网和变量都可以声明成有符号数(signed),其中integer类型总是有符号的。例如:reg signed [15:0] a; 我们来看看下面的代码:

    reg signed [7:0] a, b;

    reg signed [3:0] c;

    reg signed [7:0] sum1, sum4;

    // same width. can be applied to signed and unsigned

    sum1 = a + b;

    // automatic sign extension

    sum4 = a + c;

    第一条语句将引用一个常规的加法器,因为a、b和sum1具有相同的位宽。

    第二条语句,所有的右手边变量都具有signed数据类型,c被自动扩展符号位到8位。因此,无需再手动添加符号位。

          在小型的数字系统中,我们通常可以选用有符号数或者无符号数。然而,在一些大型的系统中,会包括不同形式的子系统。Verilog是一种弱类型语言。无符号变量和有符号变量可以在同一表达式中混用。根据Verilog的标准,只有当所有右手边的变量具有signed数据类型属性的时候,扩展符号位才被执行。否则,所有的变量都只扩展0。考虑下面的代码片段:

    reg signed [7:0] a, sum;

    reg signed [3:0] b;

    reg [3:0] c;

    sum = a + b + c;

    由于c不具有signed数据类型属性,因此右手边的变量b和c的扩展位为0。

    Verilog有两个系统函数,$signed和$unsigned(),用以将括号内的表达式转换为signed和unsigned数据类型。比方说,我们可以转换c的数据类型,

    sum = a + b + $signed(c);

    现在,右手边的所有变量都具有signed数据类型属性,因此b和c将扩展符号位。

    在复杂的表达式中,混用signed和unsigned数据类型将引入一些微妙的错误,因此应当避免混用。如果真的很有必要,那么表达式需要保持简单,同时通用转换函数,以确保数据类型的一致性。

    数组

    Verilog中,wire和reg类型都可以声明为多维数组,形式和c语言多维数组很像。例如:

    reg [7:0] a[0:1023][0:511];

    wire和reg类型的区别

         wire表示直通,即输入有变化,输出马上无条件地反映(如与、非门的简单连接)。reg表示一定要有触发,输出才会反映输入的状态。reg相当于存储单元,wire相当于物理连线。

          reg表示一定要有触发,没有输入的时候可以保持原来的值,但不直接和实际的硬件电路对应。两者的区别是:寄存器型数据保持最后一次的赋值,而线网型数据需要持续的驱动。wire使用在连续赋值语句中,而reg使用在过程赋值语句(initial ,always)中。wire若无驱动器连接,其值为z,reg默认初始值为不定值 x 。



  • 相关阅读:
    python学习笔记之--read、readline和readlines
    目录操作习题
    递归习题
    文件操作练习题
    HandleBase句柄的5种写法
    ContextBase
    BasegoSort
    PrototypePra原型_设计订单保存
    DesignPattenTemplate模板模式
    DesignPattenStrategy策略模式
  • 原文地址:https://www.cnblogs.com/mikewolf2002/p/10183255.html
Copyright © 2011-2022 走看看