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,都是對應形同的三態門。
用下面的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
當一個線網有多個驅動源時,即對一個線網有多個賦值時,不同的線網產生不同的行為。例如:
wire r;
assign r = a & b;
assign r = c | d;
![clip_image002[6]](/image/aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2Jsb2cvMzYxNDA5LzIwMTgxMi8zNjE0MDktMjAxODEyMjcwOTMwNDIwODAtOTQwMDI2NjAyLnBuZw==.png)
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 。





