表達式由操作數和操作符組成。表達式可以在出現數值的任何地方使用。
操作數
操作數可以是以下類型中的一種:
1) 常數
2) 參數
3) 線網
4) 寄存器
5) 位選擇
6) 部分選擇
7) 存儲器單元
8) 函數調用
1.1 常數
下面是一些實例。
256,7 //非定長的十進位數。
4'b10_11, 8'h0A //定長的整型常量。
'b1, 'hFBA //非定長的整數常量。
90.00006 //實數型常量。
BOND //串常量;每個字符作為8位ASCII值存儲。
表達式中的整數值可被解釋為有符號數或無符號數。如果表達式中是十進位整數,例如,12被解釋為有符號數。如果整數是基數型整數(定長或非定長),那麼該整數作為無符號數對待。下面舉例說明。
12是01100的5位向量形式(有符號)
-12是10100的5位向量形式(有符號)
5'b01100是十進位數12(無符號)
5'b10100是十進位數20(無符號)
4'd12是十進位數12(無符號)
更為重要的是對基數表示或非基數表示的負整數處理方式不同。非基數表示形式的負整數作為有符號數處理,而基數表示形式的負整數值作為無符號數。因此-44和-6'o54 (十進位的44等於八進位的54)在下例中處理不同。
integer Cone;
. . .
Cone = -44/4
Cone = -6'o54/ 4;
注意-44和-6'o54以相同的位模式求值;但是-44作為有符號數處理,而-6'o54作為無符號數處理。因此第一個字符中Cone的值為-11,而在第二個賦值中Cone的值為1073741813。
1.2 參數
參數類似於常量,並且使用參數聲明進行說明。下面是參數說明實例。
parameter LOAD = 4'd12, STORE = 4'd10;
LOAD 和STORE為參數的例子,值分別被聲明為12和10。
1.3 線網
可在表達式中使用標量線網(1位)和向量線網(多位)。下面是線網說明實例。
wire [0:3] Prt; //Prt 為4位向量線網。
wire Bdq; //Bbq 是標量線網。
線網中的值被解釋為無符號數。在連續賦值語句中,
assign Prt = -3;
Prt被賦於位向量1101,實際上為十進位的13。在下面的連續賦值中,
assign Prt = 4'HA;
Prt被賦於位向量1010,即為十進位的10。
1.4 寄存器
標量和向量寄存器可在表達式中使用。寄存器變量使用寄存器聲明進行說明。例如:
integer TemA, TemB;
reg [1:5] State;
time Que [1:5];
整型寄存器中的值被解釋為有符號的二進位補碼數,而reg寄存器或時間寄存器中的值被解釋為無符號數。實數和實數時間類型寄存器中的值被解釋為有符號浮點數。
TemA = -10; //TemA值為位向量10110,是10的二進位補碼。
TemA = 'b1011; //TemA值為十進位數11。
State = -10; //State值為位向量10110,即十進位數22。
State = 'b1011; //State值為位向量01011,是十進位值11。
1.5 位選擇
位選擇從向量中抽取特定的位。形式如下:
net_or_reg_vector [bit_select_expr]
下面是表達式中應用位選擇的例子。
State [1] State [4] //寄存器位選擇。
Prt [0] | Bbq //線網位選擇。
如果選擇表達式的值為x、z,或越界,則位選擇的值為x。例如State [x]值為x。
1.6 部分選擇
在部分選擇中,向量的連續序列被選擇。形式如下:
net_or_reg_vector [msb_const_expr:1sb_const_expr]
其中範圍表達式必須為常數表達式。例如。
State [1:4] //寄存器部分選擇。
Prt [1:3] //線網部分選擇。
選擇範圍越界或為x、z時,部分選擇的值為x。
1.7 存儲器單元
存儲器單元從存儲器中選擇一個字。形式如下:
memory [word_address]
例如:
reg [1:8] Ack, Dram [0:63];
. . .
Ack = Dram [60]; //存儲器的第60個單元。
不允許對存儲器變量值部分選擇或位選擇。例如,
Dram [60] [2] 不允許。
Dram [60] [2:4] 也不允許。
在存儲器中讀取一個位或部分選擇一個字的方法如下:將存儲器單元賦值給寄存器變量,然後對該寄存器變量採用部分選擇或位選擇操作。例如,Ack [2] 和Ack [2:4]是合法的表達式。
1.8 函數調用
表達式中可使用函數調用。函數調用可以是系統函數調用(以$字符開始)或用戶定義的函數調用。例如:
$time + SumOfEvents (A, B)
/*$time是系統函數,並且SumOfEvents是在別處定義的用戶自定義函數。*/
操作符
Verilog HDL中的操作符可以分為下述類型:
1) 算術操作符
2) 關係操作符
3) 相等操作符
4) 邏輯操作符
5) 按位操作符
6) 歸約操作符
7) 移位操作符
8) 條件操作符
9) 連接和複製操作符
下表顯示了所有操作符的優先級和名稱。操作符從最高優先級(頂行)到最低優先級(底行)排列。同一行中的操作符優先級相同。
除條件操作符從右向左關聯外,其餘所有操作符自左向右關聯。下面的表達式:
A + B - C
等價於:
(A + B ) - C //自左向右
而表達式:
A ? B : C ? D : F
等價於:
A ? B : (C ? D : F) //從右向左
圓擴號能夠用於改變優先級的順序,如以下表達式:
(A ? B : C) ? D : F
2.1 算術操作符
算術操作符有:
* +(一元加和二元加)
* -(一元減和二元減)
* *(乘)
* /(除)
* %(取模)
整數除法截斷任何小數部分。例如:
7/4 結果為 1
取模操作符求出與第一個操作符符號相同的餘數。
7%4 結果為 3
而:
- 7%4 結果為 -3
如果算術操作符中的任意操作數是X或Z,那麼整個結果為X。例如:
'b10x1 + 'b01111 結果為不確定數'bxxxxx
1. 算術操作結果的長度
算術表達式結果的長度由最長的操作數決定。在賦值語句下,算術操作結果的長度由操作符左端目標長度決定。考慮如下實例:
reg [0:3] Arc, Bar, Crt;
reg [0:5] Frx;
. . .
Arc = Bar + Crt;
Frx = Bar + Crt;
第一個加的結果長度由Bar,Crt和Arc長度決定,長度為4位。第二個加法操作的長度同樣由Frx的長度決定(Frx、Bat和Crt中的最長長度),長度為6位。在第一個賦值中,加法操作的溢出部分被丟棄;而在第二個賦值中,任何溢出的位存儲在結果位Frx[1]中。
在較大的表達式中,中間結果的長度如何確定?在Verilog HDL中定義了如下規則:表達式中的所有中間結果應取最大操作數的長度(賦值時,此規則也包括左端目標)。考慮另一個實例:
wire [4:1] Box, Drt;
wire [1:5] Cfg;
wire [1:6] Peg;
wire [1:8] Adt;
. . .
assign Adt = (Box + Cfg) + (Drt + Peg);
表達式左端的操作數最長為6,但是將左端包含在內時,最大長度為8。所以所有的加操作使用8位進行。例如:Box和Cfg相加的結果長度為8位。
2. 無符號數和有符號數
執行算術操作和賦值時,注意哪些操作數為無符號數、哪些操作數為有符號數非常重要。無符號數存儲在:
* 線網
* 一般寄存器
* 基數格式表示形式的整數
有符號數存儲在:
* 整數寄存器
* 十進位形式的整數
下面是一些賦值語句的實例:
reg [0:5] Bar;
integer Tab;
. . .
Bar = -4'd12; //寄存器變量Bar的十進位數為52,向量值為110100。
Tab = -4'd12; //整數Tab的十進位數為-12,位形式為110100。
-4'd12 / 4 //結果是1073741821。
-12 / 4 //結果是-3
因為Bar是普通寄存器類型變量,只存儲無符號數。右端表達式的值為'b110100(12的二進位補碼)。因此在賦值後,Bar存儲十進位值52。在第二個賦值中,右端表達式相同,值為'b110100,但此時被賦值為存儲有符號數的整數寄存器。Tab存儲十進位值-12(位向量為110100)。注意在兩種情況下,位向量存儲內容都相同;但是在第一種情況下,向量被解釋為無符號數,而在第二種情況下,向量被解釋為有符號數。