表達(dá)式由操作符和操作數(shù)構(gòu)成,其目的是根據(jù)操作符的意義得到一個(gè)計(jì)算結(jié)果。表達(dá)式可以在出現(xiàn)數(shù)值的任何地方使用。例如:
a^b ; //a與b進(jìn)行異或操作
address[9:0] + 10'b1 ; //地址累加
flag1 && flag2 ; //邏輯與操作
操作數(shù)可以是任意的數(shù)據(jù)類型,只是某些特定的語(yǔ)法結(jié)構(gòu)要求使用特定類型的操作數(shù)。
操作數(shù)可以為常數(shù),整數(shù),實(shí)數(shù),線網(wǎng),寄存器,時(shí)間,位選,域選,存儲(chǔ)器及函數(shù)調(diào)用等。
module test;
//實(shí)數(shù)
real a, b, c;
c = a + b ;
//寄存器
reg [3:0] cprmu_1, cprmu_2 ;
always @(posedge clk) begin
cprmu_2 = cprmu_1 ^ cprmu_2 ;
end
//函數(shù)
reg flag1 ;
flag = calculate_result(A, B);
//非法操作數(shù)
reg [3:0] res;
wire [3:0] temp;
always@ (*)begin
res = cprmu_2 – cprmu_1 ;
//temp = cprmu_2 – cprmu_1 ; //不合法,always塊里賦值對(duì)象不能是wire型
end
endmodule
Verilog 中提供了大約 9 種操作符,分別是算術(shù)、關(guān)系、等價(jià)、邏輯、按位、歸約、移位、拼接、條件操作符。
大部分操作符與 C 語(yǔ)言中類似。同類型操作符之間,除條件操作符從右往左關(guān)聯(lián),其余操作符都是自左向右關(guān)聯(lián)。圓括號(hào)內(nèi)表達(dá)式優(yōu)先執(zhí)行。例如下面每組的 2 種寫法都是等價(jià)的。
//自右向左關(guān)聯(lián),兩種寫法等價(jià)
A+B-C ;
(A+B)-C ;
//自右向左關(guān)聯(lián),兩種寫法等價(jià),結(jié)果為 B、D 或 F
A ? B : C ? D : F ;
A ? B : (C ? D : F) ;
//自右向左關(guān)聯(lián),兩種寫法不等價(jià)
(A ? B : C) ? D : F ; //結(jié)果 D 或 F
A ? B : C ? D : F ; //結(jié)果為 B、D 或 F
不同操作符之間,優(yōu)先級(jí)是不同的。下表列出了操作符優(yōu)先級(jí)從高至低的排列順序。當(dāng)沒(méi)有圓括號(hào)時(shí),Verilog 會(huì)根據(jù)操作符優(yōu)先級(jí)對(duì)表達(dá)式進(jìn)行計(jì)算。為了避免由操作符優(yōu)先級(jí)導(dǎo)致的計(jì)算混亂,在不確定優(yōu)先級(jí)時(shí),建議用圓括號(hào)將表達(dá)式區(qū)分開(kāi)來(lái)。
操作符 | 操作符號(hào) | 優(yōu)先級(jí) |
---|---|---|
單目運(yùn)算 | + - ! ~ | 最高 |
乘、除、取模 | * / % | |
加減 | + - | |
移位 | << >> | |
關(guān)系 | < <= > >= | |
等價(jià) | == != === !=== | |
歸約 | & ~& | |
^ ~^ | ||
| ~| | ||
邏輯 | && | |
|| | ||
條件 | ?: | 最低 |
算術(shù)操作符包括單目操作符和雙目操作符。
雙目操作符對(duì) 2 個(gè)操作數(shù)進(jìn)行算術(shù)運(yùn)算,包括乘(?*
?)、除(?/
?)、加(?+
?)、減(?-
?)、求冪(?**
?)、取模(?%
?)。
reg [3:0] a, b;
reg [4:0] c ;
a = 4'b0010 ;
b = 4'b1001 ;
c = a+b; //結(jié)果為c=b'b1011
c = a/b; //結(jié)果為c=4,取整
如果操作數(shù)某一位為 X,則計(jì)算結(jié)果也會(huì)全部出現(xiàn) X。例如:
b = 4'b100x ;
c = a+b ; //結(jié)果為c=4'bxxxx
對(duì)變量進(jìn)行聲明時(shí),要根據(jù)變量的操作符對(duì)變量的位寬進(jìn)行合理聲明,不要讓結(jié)果溢出。上述例子中,相加的 2 個(gè)變量位寬為 4bit,那么結(jié)果寄存器變量位寬最少為 5bit。否則,高位將被截?cái)啵瑢?dǎo)致結(jié)果高位丟失。無(wú)符號(hào)數(shù)乘法時(shí),結(jié)果變量位寬應(yīng)該為 2 個(gè)操作數(shù)位寬之和。
reg [3:0] mula ;
reg [1:0] mulb;
reg [5:0] res ;
mula = 4'he ;
mulb = 2'h3 ;
res = mula * mulb ; //結(jié)果為res=6'h2a, 數(shù)據(jù)結(jié)果沒(méi)有丟失位數(shù)
?+
? 和 ?-
? 也可以作為單目操作符來(lái)使用,表示操作數(shù)的正負(fù)性。此類操作符優(yōu)先級(jí)最高。
-4 //表示負(fù)4
+3 //表示正3
負(fù)數(shù)表示時(shí),可以直接在十進(jìn)制數(shù)字前面增加一個(gè)減號(hào) ?-
?,也可以指定位寬。因?yàn)樨?fù)數(shù)使用二進(jìn)制補(bǔ)碼來(lái)表示,不指定位寬來(lái)表示負(fù)數(shù),編譯器在轉(zhuǎn)換時(shí),會(huì)自動(dòng)分配位寬,從而導(dǎo)致意想不到的結(jié)果。例如:
mula = -4'd4 ;
mulb = 2 ;
res = mula * mulb ; //計(jì)算結(jié)果為res=-6'd8, 即res=6'h38,正常
res = mula * (-'d4) ; //(4的32次冪-4) * 2, 結(jié)果異常
關(guān)系操作符有大于(?>
?),小于(?<
?),大于等于(?>=
?),小于等于(?<=
?)。
關(guān)系操作符的正常結(jié)果有 2 種,真(1)或假(0)。
如果操作數(shù)中有一位為 x 或 z,則關(guān)系表達(dá)式的結(jié)果為 x。
A = 4 ;
B = 3 ;
X = 3'b1xx ;
A > B //為真
A <= B //為假
A >= Z //為X,不確定
等價(jià)操作符包括邏輯相等(?==
?),邏輯不等(?!=
?),全等(?===
?),非全等(?!==
?)。
等價(jià)操作符的正常結(jié)果有 2 種:為真(1)或假(0)。
邏輯相等/不等操作符不能比較 x 或 z,當(dāng)操作數(shù)包含一個(gè) x 或 z,則結(jié)果為不確定值。
全等比較時(shí),如果按位比較有相同的 x 或 z,返回結(jié)果也可以為 1,即全等比較可比較 x 或 z。所以,全等比較的結(jié)果一定不包含 x。舉例如下:
A = 4 ;
B = 8'h04 ;
C = 4'bxxxx ;
D = 4'hx ;
A == B //為真
A == (B + 1) //為假
A == C //為X,不確定
A === C //為假,返回值為0
C === D //為真,返回值為1
邏輯操作符主要有 3 個(gè):?&&
?(邏輯與), ?||
?(邏輯或),?!
?(邏輯非)。
邏輯操作符的計(jì)算結(jié)果是一個(gè) 1bit 的值,0 表示假,1 表示真,x 表示不確定。
如果一個(gè)操作數(shù)不為 0,它等價(jià)于邏輯 1;如果一個(gè)操作數(shù)等于 0,它等價(jià)于邏輯 0。如果它任意一位為 x 或 z,它等價(jià)于 x。
如果任意一個(gè)操作數(shù)包含 x,邏輯操作符運(yùn)算結(jié)果不一定為 x。
邏輯操作符的操作數(shù)可以為變量,也可以為表達(dá)式。例如:
A = 3;
B = 0;
C = 2'b1x ;
A && B // 為假
A || B // 為真
! A // 為假
! B // 為真
A && C // 為X,不確定
A || C // 為真,因?yàn)锳為真
(A==2) && (! B) //為真,此時(shí)第一個(gè)操作數(shù)為表達(dá)式
按位操作符包括:取反(?~
?),與(?&
?),或(?|
?),異或(?^
?),同或(?~^
?)。
按位操作符對(duì) 2 個(gè)操作數(shù)的每 1bit 數(shù)據(jù)進(jìn)行按位操作。
如果 2 個(gè)操作數(shù)位寬不相等,則用 0 向左擴(kuò)展補(bǔ)充較短的操作數(shù)。
取反操作符只有一個(gè)操作數(shù),它對(duì)操作數(shù)的每 1bit 數(shù)據(jù)進(jìn)行取反操作。
下圖給出了按位操作符的邏輯規(guī)則。
&(與) | 0 | 1 | x | |(或) | 0 | 1 | x | |
---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 1 | x | |
1 | 0 | 1 | x | 1 | 1 | 1 | 1 | |
x | 0 | x | x | x | x | 1 | x |
^(異或) | 0 | 1 | x | ~^(同或) | 0 | 1 | x | |
---|---|---|---|---|---|---|---|---|
0 | 0 | 1 | x | 0 | 1 | 0 | x | |
1 | 1 | 0 | x | 1 | 0 | 1 | x | |
x | x | x | x | x | x | x | x |
A = 4'b0101 ;
B = 4'b1001 ;
C = 4'bx010 ;
~A //4'b1010
A & B //4'b0001
A | B //4'b1101
A^B //4'b1100
A ~^ B //4'b0011
B | C //4'b1011
B&C //4'bx000
歸約操作符包括:歸約與(?&
?),歸約與非(?~&
?),歸約或(?|
?),歸約或非(?~|
?),歸約異或(?^
?),歸約同或(?~^
?)。
歸約操作符只有一個(gè)操作數(shù),它對(duì)這個(gè)向量操作數(shù)逐位進(jìn)行操作,最終產(chǎn)生一個(gè) 1bit 結(jié)果。
邏輯操作符、按位操作符和歸約操作符都使用相同的符號(hào)表示,因此有時(shí)候容易混淆。區(qū)分這些操作符的關(guān)鍵是分清操作數(shù)的數(shù)目,和計(jì)算結(jié)果的規(guī)則。
A = 4'b1010 ;
&A ; //結(jié)果為 1 & 0 & 1 & 0 = 1'b0,可用來(lái)判斷變量A是否全1
~|A ; //結(jié)果為 ~(1 | 0 | 1 | 0) = 1'b0, 可用來(lái)判斷變量A是否為全0
^A ; //結(jié)果為 1 ^ 0 ^ 1 ^ 0 = 1'b0
移位操作符包括左移(?<<
?),右移(?>>
?),算術(shù)左移(?<<<
?),算術(shù)右移(?>>>
?)。
移位操作符是雙目操作符,兩個(gè)操作數(shù)分別表示要進(jìn)行移位的向量信號(hào)(操作符左側(cè))與移動(dòng)的位數(shù)(操作符右側(cè))。
算術(shù)左移和邏輯左移時(shí),右邊低位會(huì)補(bǔ) 0。
邏輯右移時(shí),左邊高位會(huì)補(bǔ) 0;而算術(shù)右移時(shí),左邊高位會(huì)補(bǔ)充符號(hào)位,以保證數(shù)據(jù)縮小后值的正確性。
A = 4'b1100 ;
B = 4'b0010 ;
A = A >> 2 ; //結(jié)果為 4'b0011
A = A << 1; //結(jié)果為 4'b1000
A = A <<< 1 ; //結(jié)果為 4'b1000
C = B + (A>>>2); //結(jié)果為 2 + (-4/4) = 1, 4'b0001
拼接操作符用大括號(hào)?{,}
來(lái)表示,用于將多個(gè)操作數(shù)(向量)拼接成新的操作數(shù)(向量),信號(hào)間用逗號(hào)隔開(kāi)。
拼接符操作數(shù)必須指定位寬,常數(shù)的話也需要指定位寬。例如:
A = 4'b1010 ;
B = 1'b1 ;
Y1 = {B, A[3:2], A[0], 4'h3 }; //結(jié)果為Y1='b1100_0011
Y2 = {4{B}, 3'd4}; //結(jié)果為 Y2=7'b111_1100
Y3 = {32{1'b0}}; //結(jié)果為 Y3=32h0,常用作寄存器初始化時(shí)匹配位寬的賦初值
條件表達(dá)式有 3 個(gè)操作符,結(jié)構(gòu)描述如下:
condition_expression ? true_expression : false_expression
計(jì)算時(shí),如果 ?condition_expression
?為真(邏輯值為 1),則運(yùn)算結(jié)果為 ?true_expression
?;如果 ?condition_expression
?為假(邏輯值為 0),則計(jì)算結(jié)果為 ?false_expression
?。
assign hsel = (addr[9:8] == 2'b0) ? hsel_p1 : hsel_p2 ;
//當(dāng)信號(hào) addr 高 2bit 為 0 時(shí),hsel 賦值為 hsel_p1; 否則,將 hsel_p2 賦值給 hsel。
其實(shí),條件表達(dá)式類似于 2 路(或多路)選擇器,其描述方式完全可以用 if-else 語(yǔ)句代替。
當(dāng)然條件操作符也能進(jìn)行嵌套,完成一個(gè)多次選擇的邏輯。例如:
assign hsel = (addr[9:8] == 2'b00) ? hsel_p1 :
(addr[9:8] == 2'b01) ? hsel_p2 :
(addr[9:8] == 2'b10) ? hsel_p3 :
(addr[9:8] == 2'b11) ? hsel_p4 ;
更多建議: