1. Verilog HDL 的概要與運算子的關鍵性
Verilog HDL(硬體描述語言,Hardware Description Language)是數位電路設計中廣泛使用的硬體描述語言。透過此語言,可以描述硬體的行為、進行模擬,並透過邏輯綜合設計出實際電路。特別是「運算子」,在進行計算與訊號操作時扮演著不可或缺的重要角色。
本文將系統化整理 Verilog HDL 的各類運算子,並詳細解說其種類、使用方法與注意事項。讀完後,您將能有效活用 Verilog 的運算子,實現更少錯誤且更高效率的設計。
2. Verilog 中的數值表示
在 Verilog 中,數值的表示方式相當獨特,並且與運算子的使用密切相關。本節將說明數值表示的基礎。
數值表示的基本格式
Verilog 的數值表示採用以下格式:
<位元寬度>'<進位制><值>
各項目說明
- 位元寬度:指定數值所佔用的位元數。
- 範例:
4
表示 4 位元。 - 進位制:指定數值的進位制,使用以下符號:
b
:二進位o
:八進位d
:十進位h
:十六進位- 值:實際的數值。
範例
4'b1010
→ 4 位元的二進位數,值為 10。8'd255
→ 8 位元的十進位數,值為 255。16'hABCD
→ 16 位元的十六進位數,值為 ABCD。
省略位元寬度
若省略位元寬度,依照工具或模擬環境不同,一般會被視為 32 位元。
注意事項
若未明確指定位元寬度就進行計算,可能在綜合時導致非預期的行為。建議養成明確寫出位元寬度的習慣。
未定義值與高阻抗
在 Verilog 中,特定情況下會以數值來表示「未定義值(X)」或「高阻抗(Z)」。
1'bx
:未定義值。1'bz
:高阻抗。
這些值在模擬中相當有用,但在綜合時可能引發錯誤,因此必須特別注意。
3. 運算子的概要與分類
Verilog 中所使用的運算子,對於高效完成計算與訊號操作非常重要。本節將說明 Verilog 運算子的分類與基本概念。
運算子的分類
Verilog 使用的運算子大致可分為以下幾類:
- 算術運算子
- 用於數值計算。
- 範例:
+
,-
,*
,/
,%
- 位元運算子
- 在位元層級進行邏輯操作。
- 範例:
&
,|
,^
,~
- 縮減運算子(Reduction)
- 將位元層級的邏輯操作縮減為單一位元。
- 範例:
&
,|
,^
- 位移運算子
- 將位元序列往左或往右位移。
- 範例:
<<
,>>
,<<<
,>>>
- 關係運算子
- 比較兩個值並回傳布林結果。
- 範例:
<
,<=
,>
,>=
,==
,!=
- 條件運算子
- 根據條件回傳不同的值。
- 範例:
? :
- 連接運算子
- 將多個位元序列串接起來。
- 範例:
{}
各類別的概要
算術運算子的基礎
算術運算子可用於加法、減法、乘法等數值運算。
- 使用範例:
reg [7:0] a, b, result;
assign result = a + b; // 將 a 與 b 相加
位元運算子的基礎
位元運算子會針對每個位元進行 AND、OR 等操作。
- 使用範例:
reg [3:0] a, b, result;
assign result = a & b; // AND 運算
縮減運算子的基礎
縮減運算子會對整個位元序列進行運算並產生單一位元結果。
- 使用範例:
reg [3:0] a;
assign result = &a; // 計算所有位元的 AND
條件運算子的基礎
條件運算子會依據條件式的結果選擇不同的值。
- 使用範例:
assign result = (a > b) ? a : b; // 如果 a 大於 b,則回傳 a

4. 運算子的使用方式與注意事項
本節將詳細解說 Verilog HDL 中各種運算子的使用方法與注意事項。透過理解運算子的特性,能更正確且有效率地應用於設計。
算術運算子
算術運算子是用來進行加減乘除與取餘數等基本數值運算。
主要運算子與使用範例
運算子 | 意義 | 使用範例 | 結果 |
---|---|---|---|
+ | 加法 | result = a + b | a + b 的值 |
- | 減法 | result = a - b | a – b 的值 |
* | 乘法 | result = a * b | a × b 的值 |
/ | 除法 | result = a / b | a ÷ b 的值 |
% | 取餘數 | result = a % b | a 除以 b 的餘數 |
使用注意事項
- 僅支援整數運算:
Verilog 不支援浮點數運算,所有計算都以整數處理。
// 無法進行浮點數運算
real a = 3.5, b = 1.5;
// assign result = a / b; // 錯誤
- 乘法與除法的綜合限制:
雖然在模擬中可以正常使用乘法 (*
) 和除法 (/
),但在綜合時會消耗大量硬體資源。建議明確使用乘法器,或改用位移運算替代。
位元運算子
位元運算子會對訊號進行位元級的邏輯操作,主要有 AND、OR、XOR、NOT 四種類型。
主要運算子與使用範例
運算子 | 意義 | 使用範例 | 結果 |
---|---|---|---|
& | AND | result = a & b | a 與 b 各位元的 AND |
| | OR | result = a | b | a 與 b 各位元的 OR |
^ | XOR | result = a ^ b | a 與 b 各位元的 XOR |
~ | NOT | result = ~a | a 的位元反轉 |
使用注意事項
- 位元寬度需一致:
若運算元的位元寬度不同,結果會自動對齊至較大的位元寬度,這可能導致非預期結果。
reg [3:0] a;
reg [7:0] b;
assign result = a & b; // result 的位元寬度為 8 位元
- 未定義值的處理:
若訊號包含未定義值 (X
) 或高阻抗 (Z
),進行位元運算時可能產生不可預測的結果。
縮減運算子
縮減運算子會將整個位元序列壓縮成單一位元。
主要運算子與使用範例
運算子 | 意義 | 使用範例 | 結果 |
---|---|---|---|
& | AND 縮減 | result = &a | a 所有位元皆為 1 時結果為 1 |
| | OR 縮減 | result = |a | a 任一位元為 1 時結果為 1 |
^ | XOR 縮減 | result = ^a | 將 a 的位元進行 XOR 疊加 |
使用注意事項
- 結果的解讀:
縮減運算子會產生單一位元,需正確理解其邏輯意涵。
reg [3:0] a = 4'b1101;
assign result = &a; // 結果: 0(因為並非所有位元都為 1)
位移運算子
位移運算子可將位元序列向左或向右移動。基本有左移 (<<
) 與右移 (>>
),此外也有算術位移 (<<<
, >>>
)。
主要運算子與使用範例
運算子 | 意義 | 使用範例 | 結果 |
---|---|---|---|
<< | 邏輯左移 | result = a << 2 | a 左移 2 位元 |
>> | 邏輯右移 | result = a >> 2 | a 右移 2 位元 |
<<< | 算術左移 | result = a <<< 2 | a 左移 2 位元(保留符號) |
>>> | 算術右移 | result = a >>> 2 | 符號位保持的情況下右移 2 位元 |
使用注意事項
- 有號數與無號數:
對於有號數值,建議使用算術位移,以確保符號位保持。
reg signed [7:0] a = -8'd4; // 保持 -4
assign result = a >>> 1; // 結果: -2
- 位移量超出範圍的錯誤:
當位移量超過信號的位元寬度時,結果可能為 0,需謹慎使用。

5. 關係運算子、條件運算子、連接運算子的詳細解說
本節將解說 Verilog HDL 中的關係運算子、條件運算子與連接運算子。這些運算子在條件判斷與訊號操作中不可或缺。
關係運算子
關係運算子用來比較兩個值並回傳布林值。比較結果以布林值(1
或 0
)表示。
主要運算子與使用範例
運算子 | 意義 | 使用範例 | 結果 |
---|---|---|---|
< | 小於 | result = a < b | 若 a < b,則為 1 |
<= | 小於等於 | result = a <= b | 若 a <= b,則為 1 |
> | 大於 | result = a > b | 若 a > b,則為 1 |
>= | 大於等於 | result = a >= b | 若 a >= b,則為 1 |
== | 等於 | result = a == b | 若 a == b,則為 1 |
!= | 不等於 | result = a != b | 若 a != b,則為 1 |
使用注意事項
- 有號數與無號數比較:
若將有號數與無號數比較,可能產生非預期的結果。
reg signed [3:0] a = -2;
reg [3:0] b = 2;
assign result = (a < b); // 結果為 0(因為 a 為有號數)
- 未定義值的處理:
若比較的值包含X
或Z
,結果可能不確定。在模擬過程中需留意警告。
條件運算子
條件運算子會根據條件式的結果來選擇回傳的值。這與 C 語言中的三元運算子相同。
條件運算子的語法
result = (條件式) ? 值1 : 值2;
使用範例
reg [7:0] a = 8'd10;
reg [7:0] b = 8'd20;
assign result = (a > b) ? a : b; // 若 a 大於 b 則回傳 a,否則回傳 b
使用注意事項
- 避免過度巢狀:
過度巢狀會使程式碼難以閱讀,建議改用if-else
結構。
// 可讀性低的範例
assign result = (a > b) ? ((c > d) ? c : d) : e;
- 模擬與綜合的差異:
在綜合時,條件運算子會被轉換成case
或分岐邏輯,複雜的條件可能影響資源效率。
連接運算子
連接運算子可將多個位元序列結合成單一的位元序列。
連接運算子的語法
{位元序列1, 位元序列2, ...}
使用範例
reg [3:0] a = 4'b1101;
reg [3:0] b = 4'b0011;
wire [7:0] result;
assign result = {a, b}; // 結果: 8'b11010011
使用注意事項
- 確認位元寬度:
連接後的總寬度必須與結果變數一致,否則會發生截斷。
reg [3:0] a = 4'b1101;
reg [3:0] b = 4'b0011;
wire [5:0] result;
assign result = {a, b}; // result 位元不足,將發生截斷
- 值的順序:
左側的值會放在高位元,若順序錯誤可能導致非預期結果。
6. 運算子的優先順序與結合規則
在 Verilog HDL 中,當表達式中包含多個運算子時,會依照運算子的優先順序與結合規則進行計算。若不了解這些規則,可能會導致非預期的行為。本節將解釋運算子的優先順序與結合規則。
運算子的優先順序
Verilog 的運算子會依照以下順序進行計算(由高到低):
優先順序 | 運算子 | 種類 | 結合規則 |
---|---|---|---|
1 | () | 括號 | 左結合 |
2 | ~ , ! , & , | , ^ , ~^ | 單元運算子 | 右結合 |
3 | * , / , % | 算術運算子 | 左結合 |
4 | + , - | 算術運算子 | 左結合 |
5 | << , >> , <<< , >>> | 位移運算子 | 左結合 |
6 | < , <= , > , >= | 比較運算子 | 左結合 |
7 | == , != | 等號運算子 | 左結合 |
8 | & , ^ , | | 位元運算子 | 左結合 |
9 | && | 邏輯 AND | 左結合 |
10 | || | 邏輯 OR | 左結合 |
11 | ? : | 條件運算子 | 右結合 |
使用要點
- 建議使用括號:
即使熟悉優先順序,對於複雜表達式仍建議加上括號以避免誤解。
// 更清楚的寫法
assign result = (a + b) * c;
- 條件運算子的優先順序:
條件運算子(? :
)的優先順序較低,建議搭配括號避免誤解。
// 注意條件運算子的優先順序
assign result = a > b ? a + c : b - c; // 雖可運作,但建議加括號
結合規則
結合規則決定當同一優先級的運算子同時出現時,應從左還是從右開始計算。Verilog 中多數運算子為左結合,少數(如單元運算子、條件運算子)為右結合。
結合規則範例
- 左結合:
由左至右依序計算。
assign result = a - b - c; // 等同於 ((a - b) - c)
- 右結合:
由右至左計算。
assign result = a ? b : c ? d : e; // 等同於 (a ? b : (c ? d : e))
避免優先順序與結合規則錯誤
案例研究: 優先順序的誤解
assign result = a + b << c; // 誰會先執行?
<<
的優先順序比+
高,因此實際上會先進行位移:
assign result = a + (b << c);
案例研究: 使用括號明確化
assign result = (a + b) << c; // 明確指定意圖
- 透過括號能避免誤解,並讓除錯與程式碼審查更容易。
7. 使用運算子時的注意事項與常見錯誤範例
在使用 Verilog HDL 運算子時,設計階段與模擬階段都有一些特有的注意事項。若能事先理解這些重點,即可避免 bug 與非預期的行為。本節將解說運算子使用時的注意點與常見錯誤案例。
注意事項
1. 未定義值(X)與高阻抗(Z)的處理
未定義值 (X
) 與高阻抗 (Z
) 在模擬中常出現,但在綜合時可能被忽略或引發錯誤。
注意要點
- 若運算結果為
X
,可能導致非預期行為。 Z
值通常僅在三態緩衝器等特殊電路中使用。
對策
- 對可能包含
X
或Z
的信號進行明確初始化。 - 模擬時透過
$display
或$monitor
檢查信號值。
程式範例
reg [3:0] a = 4'bz; // 高阻抗
assign result = a + 4'b0011; // 結果為未定義 (X)
2. 有號運算與無號運算的差異
在 Verilog 中,運算子是否以有號或無號方式評估,會大大影響結果。
注意要點
- 若信號類型混用,會被視為無號數。
- 處理有號數時,建議使用
$signed
或$unsigned
明確轉換。
對策
- 在有號與無號信號混合運算時,務必統一型別。
- 進行有號數運算時,明確定義為 signed。
程式範例
reg signed [3:0] a = -4;
reg [3:0] b = 3;
assign result = a + b; // 會以無號數評估,結果可能不正確
3. 位元寬度不匹配
當輸入信號的位元寬度不同時,結果會自動對齊至較大的位元寬度,這有時會引發問題。
注意要點
- 若位元不足,會發生截斷(Truncation)。
- 在位移運算中,若位移量的位元寬度不足,可能導致錯誤。
對策
- 明確指定位元寬度,避免不足或過大。
- 必要時進行零填充(Zero Padding)。
程式範例
reg [3:0] a = 4'b1010;
reg [7:0] b = 8'b00001111;
assign result = a + b; // 結果的位元寬度為 8 位元

常見錯誤範例與解決方法
1. 誤解條件運算子的優先順序
錯誤範例
assign result = a > b ? a + c : b - c > d;
- 因評估順序誤解而導致錯誤。
正確寫法
assign result = (a > b) ? (a + c) : ((b - c) > d);
- 使用括號明確表示優先順序。
2. 有號運算不一致
錯誤範例
reg signed [7:0] a = -8'd10;
reg [7:0] b = 8'd20;
assign result = a + b; // 以無號數計算
正確寫法
assign result = $signed(a) + $signed(b); // 明確以有號數計算
3. 位移量超出範圍
錯誤範例
assign result = a << 10; // 若 a 為 8 位元,結果不正確
正確寫法
assign result = (10 < $bits(a)) ? (a << 10) : 0; // 限制位移量
除錯要點
- 活用模擬日誌: 使用
$display
或$monitor
逐步確認信號。 - 檢查波形: 找出
X
或Z
出現的位置。 - 小模組測試: 在大型設計中,將問題部分拆解測試。

8. 總結
本文詳細解說了 Verilog HDL 的運算子,包括種類、使用方法、注意事項以及常見錯誤案例。運算子是硬體設計中基礎且關鍵的元素,正確理解與運用能提升設計的效率與精準度。
以下是重點整理:
運算子的基礎與分類
- 運算子主要可分為以下幾類:
- 算術運算子(加減乘除等數值計算)
- 位元運算子(位元層級的操作)
- 縮減運算子(對整體位元序列進行運算)
- 位移運算子(向左或向右位移)
- 關係運算子(數值比較)
- 條件運算子(三元運算子分支)
- 連接運算子(位元序列的結合)
使用時的注意事項
- 未定義值(X)與高阻抗(Z)
- 在模擬時需特別注意,務必進行初始化以避免錯誤傳播。
- 有號與無號混用
- 可能造成非預期結果,建議使用
$signed
或$unsigned
明確指定型別。
- 位元寬度管理
- 避免截斷或不必要的零填充。
- 條件運算子與複雜表達式
- 建議使用括號明確化優先順序,避免非預期行為。
除錯要點
- 透過模擬日誌(
$display
,$monitor
)與波形圖檢查設計。 - 在大型專案中,將模組拆分並逐一驗證。
最後的話
正確理解並靈活運用 Verilog HDL 的運算子,是建立高品質數位設計的基礎。請將本文的知識應用於實際設計,從模擬到綜合皆能維持高可靠性。未來若挑戰更高階的設計,除了熟悉運算子,也建議同時考量最佳化方法與電路規模對應的設計策略。

FAQ(常見問題)
Q1. Verilog 的運算子是什麼?
A.
Verilog 的運算子是用來進行數值計算、位元操作、條件分支等的符號,包括算術運算子、位元運算子、縮減運算子、位移運算子等。熟練運用能使設計更簡潔高效。
Q2. 條件運算子(? :
)與 if-else
的差異?
A.
條件運算子適合用於單行的簡單條件判斷,而 if-else
則更適合處理多條件或複雜邏輯。
範例:條件運算子
assign result = (a > b) ? a : b;
範例:if-else
if (a > b)
result = a;
else
result = b;
Q3. 如何處理未定義值(X)與高阻抗(Z)?
A.
這些值在模擬時很常見,但在綜合時會造成錯誤。避免方法:
- 信號初始化:對未使用的信號給予適當初始值。
- 避免不必要的 Z:若不需要三態緩衝器,請避免使用高阻抗。
Q4. 位移運算子(<<
、>>
)如何使用?
A.
位移運算子用於將位元序列往左或往右移動。
範例:
assign result = a << 2; // 左移 2 位元
assign result = a >> 2; // 右移 2 位元
注意事項: 若位移量超過信號的位元寬度,可能導致錯誤。
Q5. 如何在 Verilog 中處理有號數?
A.
可使用 signed
修飾符,或利用 $signed
明確轉換。
範例:
reg signed [7:0] a = -8'd10;
reg [7:0] b = 8'd20;
assign result = $signed(a) + $signed(b);
Q6. 不同位元寬度的信號相加要注意什麼?
A.
結果會自動對齊至較大的位元寬度,可能發生截斷。建議必要時進行零填充。
範例:
reg [3:0] a = 4'b1010;
reg [7:0] b = 8'b00001111;
assign result = {4'b0000, a} + b; // 將 a 擴展為 8 位元
Q7. 如何確認運算子的優先順序?
A.
Verilog 的優先順序是固定的,為避免誤會,建議使用括號明確指定。
範例:
assign result = (a + b) * c;
Q8. 條件運算子可否用於綜合?
A.
可以。條件運算子(? :
)是可綜合的,但在複雜條件下,建議使用 if-else
或 case
結構以優化資源。
Q9. Verilog 的運算子能在 VHDL 使用嗎?
A.
Verilog 與 VHDL 屬於不同語言,運算子語法並不完全相同。例如 Verilog 的 &
在 VHDL 中需使用 and
。必須依照 VHDL 規範改寫。
Q10. 如何驗證運算子的使用是否正確?
A.
可以透過以下方式確認:
- 模擬:使用
$display
或$monitor
確認結果。 - 測試平台:建立 testbench 驗證運算子邏輯。
- 波形檢查:使用波形工具視覺化檢查結果。