1. Verilog的assign語句是什麼?【新手入門解說】
什麼是Verilog HDL?
Verilog HDL(硬體描述語言,Hardware Description Language)是一種用於描述數位電路的硬體描述語言。它不同於軟體開發中的程式語言,而是用來描述硬體(邏輯電路)的結構與行為,並可透過模擬與綜合轉換成FPGA或ASIC等實際電路。
在Verilog中,最常用的語法之一就是「assign
語句」。特別是在描述組合邏輯電路時,assign是不可或缺的語法。
assign語句的作用是什麼?
assign
語句用於對wire型信號進行「連續指定(continuous assignment)」。所謂連續,指的是當輸入信號發生變化時,輸出會立即反映變化。
例如,若要對兩個信號進行邏輯AND並輸出結果,可以這樣寫:
assign out = in1 & in2;
這一行即可實現「將in1和in2的AND結果持續輸出到out」。assign
的功能就像明確定義硬體的連線一樣。
組合邏輯中使用的assign語句
數位電路主要可分為組合邏輯電路與時序邏輯電路:
- 組合邏輯電路:輸入改變時,輸出立即改變(例:加法器、邏輯閘等)
- 時序邏輯電路:使用時鐘或記憶元件來保持狀態(例:觸發器、計數器等)
其中,assign
語句主要用於組合邏輯電路,因為它需要根據輸入的即時狀態持續生成輸出。
為什麼assign對新手很重要?
學習Verilog的初期,理解組合邏輯是關鍵。而描述這些電路必須掌握assign
語句。從簡單的邏輯運算,到條件分支、加法器、比較器,多數功能都能用assign
簡潔地實現。
同時,使用assign語句能幫助初學者理解「作為硬體的訊號流」。這種思維對於後續處理更複雜的時序電路或測試平台都非常重要。
總結:掌握assign語句的基礎
Verilog中的assign
語句是描述組合邏輯的基礎。它能簡潔地表示信號連接與邏輯運算,因此對初學者而言,是最早需要掌握的語法之一。
2. Verilog中的assign語句基本語法與寫法
assign語句的基本語法
在Verilog中,assign
語句的基本語法非常簡單。它主要用於對wire型信號進行邏輯運算或賦值。基本寫法如下:
assign 輸出信號 = 表達式;
這裡的「表達式」可以包含其他信號、邏輯運算、位元運算等。需要注意的是,assign
語句只能用於wire型變數,不能用於reg
型。
常見範例①:簡單邏輯運算
最常見的用法就是表示邏輯閘運算。以下是AND、OR、XOR的assign語句寫法:
assign and_out = a & b; // AND閘
assign or_out = a | b; // OR閘
assign xor_out = a ^ b; // XOR閘
透過運算子即可把多個輸入信號組合,並持續驅動輸出。
常見範例②:位元操作
assign語句也支援位元級操作,可以進行部分位元擷取或拼接:
assign upper_4bits = data[7:4]; // 擷取8位數據的高4位
assign lower_4bits = data[3:0]; // 擷取低4位
assign combined = {data1[3:0], data2[3:0]}; // 將兩個4位數據拼接成8位
因此,在需要重組或部分操作數據時,assign語句非常方便。
assign語句中的「連續指定」含義
在Verilog中,assign
語句的賦值稱為「連續指定(continuous assignment)」,這意味著輸入一旦改變,輸出就會立即更新。
這與軟體程式中的「一次性賦值」不同,在硬體設計中更接近於訊號始終保持連線狀態的概念。
assign語句中的延遲指定
Verilog允許在assign語句中指定延遲(delay),主要用於模擬,實際綜合時通常會被忽略,但對於動作驗證很有用:
assign #5 out = a & b; // 延遲5個時間單位後,將a&b的結果輸出到out
這裡的「#5」表示基於time unit的延遲。請注意,在FPGA/ASIC合成時,這種延遲會被忽略。
使用條件運算子的assign範例
assign語句可以搭配三元運算子來實現簡單的條件分支:
assign out = sel ? data1 : data2;
這表示「如果sel=1,輸出data1;否則輸出data2」。這種寫法能簡潔地表現多路選擇器(MUX)的功能。
總結:掌握assign語句的寫法
Verilog的assign語句是一種簡單而強大的描述手段,不論是邏輯運算、位元操作、條件分支,甚至帶延遲的運算,都能輕鬆表達。
對初學者來說,熟悉assign語句的基本寫法,並能靈活描述組合邏輯,是掌握Verilog設計的第一步。
3. assign與wire的關係|從宣告到使用
assign語句與wire的基本關係
在Verilog中,使用assign
語句時最重要的一點是:assign
語句只能用於wire
型變數。如果忽略這個規則來寫程式,會立刻遇到語法錯誤。
assign
語句所定義的賦值屬於「連續指定(continuous assignment)」,而這種連續驅動僅允許針對wire
型信號。
什麼是wire型?── 模擬實體「配線」的概念
在Verilog中,wire
型顧名思義就是模擬電路中配線(wire)的資料型態。它不會自行保存值,而是用來接收並傳遞其他輸出的值。
因此,wire型信號的特徵是「自己不記錄數值,只是把assign語句或模組輸出的值傳遞下去」。
範例:
wire a, b, out;
assign out = a & b; // out持續輸出a與b的AND運算
在這裡,out
必須是wire
型。如果誤寫成reg
型,就會編譯錯誤。
為什麼reg型不能用assign?
reg
型則主要用於暫存值的時序電路。它通常在always
區塊中,依據條件或時脈觸發來更新值,而不是由assign持續驅動。
錯誤範例:
reg out;
assign out = a & b; // 錯誤!reg型不能用assign語句
因此,規則是:assign只能搭配wire,always區塊則搭配reg。
wire型的宣告與匯流排(多位元)處理
wire
型不僅支援單一位元,也能處理多位元匯流排(bus)。
wire [3:0] a, b;
wire [3:0] out;
assign out = a & b; // 逐位進行AND運算
在處理多位元信號時,只需在宣告時指定位元數即可,寫法仍然一致。
模組連接時wire的角色
在Verilog中,模組之間傳遞信號時通常使用wire
。例如,當兩個模組相互連接時,可以透過wire型來承接訊號:
wire result;
module1 u1 (.a(a), .b(b), .out(result));
module2 u2 (.in(result), .y(y));
這顯示了wire
不僅在assign語句中重要,也是整個Verilog設計的基本連線元素。
總結:理解wire才能正確使用assign
在Verilog中,若要正確使用assign
語句,必須理解wire的特性。wire
是配線概念,只能接收與傳遞值;而reg
則用於保存狀態。
掌握這些差異後,便能正確區分assign與always的使用場景,進而撰寫出更高效、正確的硬體描述程式。
4. assign與always的差異是什麼?【初學者容易混淆的重點】
為什麼「assign」與「always」容易讓人混淆?
對剛開始學習Verilog的新手來說,最常感到困惑的就是assign
語句與always
區塊的使用差異。兩者都能對信號進行賦值,但用途與可搭配的型態完全不同。
本章將深入解釋兩者的本質差異,以及在實務上如何正確區分使用。
assign語句的特點與使用場景
先來回顧一下assign
語句的主要特徵:
- 用途:用於組合邏輯電路
- 型態:只能搭配
wire
- 賦值方式:連續指定(持續驅動信號)
- 關鍵字:
assign
範例:二輸入AND閘(assign語句)
wire a, b;
wire out;
assign out = a & b;
這表示只要輸入a或b發生改變,輸出就會立即更新。這正是組合邏輯的典型行為。
always區塊的特點與使用場景
always
區塊則更具彈性,主要用於時序邏輯、條件分支與時脈同步處理。
- 用途:時序邏輯或複雜控制
- 型態:搭配
reg
- 賦值方式:條件式賦值(根據觸發條件執行)
- 關鍵字:
always
範例:時脈觸發的暫存器(always區塊)
reg out;
always @(posedge clk) begin
out <= a & b;
end
這裡的out
會在時脈上升沿時被更新。這是具有時間概念的處理,必須用always區塊。
wire與reg的比較
特徵 | wire型 | reg型 |
---|---|---|
使用位置 | assign語句 | always區塊內 |
是否保存數值 | 否(僅傳遞) | 是(可暫存) |
是否可設初始值 | 不可 | 可(模擬時) |
賦值方式 | 連續指定 | 阻塞式或非阻塞式賦值 |
因此,assign
與always
應成套理解,分別對應不同的型態與用途。
不同情境下的使用建議
目的 | 語法 | 型態 |
---|---|---|
邏輯運算(組合邏輯) | assign | wire |
時脈同步的暫存處理(時序邏輯) | always | reg |
條件控制輸出 | always | reg |
簡單的訊號連線或運算結果輸出 | assign | wire |
範例:if條件必須使用always
reg y;
always @(a or b) begin
if (a == 1) y = b;
else y = 0;
end
這種包含條件分支的程式無法用assign實現。如果需要流程或狀態控制,就必須用always。
assign與always可以同時用在同一個信號嗎?
不可以。同一個信號不能同時由assign與always驅動。若同一信號同時被多處指定,會導致衝突(多重驅動),產生錯誤或未定義行為。
錯誤範例:
assign y = a & b;
always @(posedge clk)
y <= a | b; // 錯誤!同一信號被assign與always同時驅動
因此,必須明確規劃每個信號的唯一驅動來源。
總結:如何區分assign與always
在Verilog設計中,「在什麼時機、如何控制信號」決定了應使用assign還是always:
- 輸入與輸出直接相連 → assign(wire)
- 需要時間或狀態概念 → always(reg)
只要掌握這個規則,新手就能避免assign與always的常見混淆。

5. 使用assign語句的組合邏輯電路實例【附圖解】
什麼是組合邏輯電路?
我們先從基礎概念開始。組合邏輯電路指的是輸出會隨輸入即時改變的電路。由於沒有記憶元件,它不依賴過去狀態,而只取決於當前輸入。
在Verilog中,用來描述這類電路最合適的語法就是assign
語句。
基本邏輯閘的實作(AND、OR、XOR)
以下範例展示如何用assign
語句來描述多個基本邏輯閘:
module logic_gates(
input wire a,
input wire b,
output wire and_out,
output wire or_out,
output wire xor_out
);
assign and_out = a & b;
assign or_out = a | b;
assign xor_out = a ^ b;
endmodule
這個模組會對輸入a
與b
進行AND、OR、XOR運算,並分別輸出結果。由於這些運算不需要條件判斷或時脈,完全可以透過assign
實現。
半加器(Half Adder)的實作
組合邏輯的經典教材之一是半加器(Half Adder)。它能將兩個位元的二進位數相加,輸出「和(Sum)」與「進位(Carry)」。
邏輯公式
- Sum(和)= A ⊕ B(XOR)
- Carry(進位)= A・B(AND)
Verilog實作範例
module half_adder(
input wire a,
input wire b,
output wire sum,
output wire carry
);
assign sum = a ^ b;
assign carry = a & b;
endmodule
半加器僅需兩行assign即可完成,非常適合初學者熟悉assign的用法。
全加器(Full Adder)的實作
另一個常見的例子是全加器(Full Adder),它能將三個位元(A、B、Cin)相加,並輸出「Sum」與「Carry」。
邏輯公式
- Sum(和)= A ⊕ B ⊕ Cin
- Carry(進位)= (A・B) + (Cin・(A ⊕ B))
Verilog實作範例
module full_adder(
input wire a,
input wire b,
input wire cin,
output wire sum,
output wire cout
);
wire ab_xor;
assign ab_xor = a ^ b;
assign sum = ab_xor ^ cin;
assign cout = (a & b) | (cin & ab_xor);
endmodule
這裡我們利用中間信號ab_xor
,分步完成計算。這展示了wire + assign能靈活應對多步驟運算。
選擇器(MUX)的實作
另一個常見電路是多工器(Multiplexer, MUX),它能依條件切換輸出:
module mux2to1(
input wire a,
input wire b,
input wire sel,
output wire y
);
assign y = sel ? b : a;
endmodule
當sel
為1時輸出b
,否則輸出a
。這利用了assign
中的三元運算子,非常簡潔。
設計重點與注意事項
- 輸出信號必須是wire:assign不能用於reg。
- 多個輸出應分開寫assign:避免將過多邏輯擠在一行,保持可讀性。
- 使用中間信號提升可讀性:當運算較複雜時,先分解成多個wire。
總結:基本組合邏輯可完全用assign實現
如同範例所示,大部分基本組合邏輯電路都能用assign輕鬆完成。從邏輯閘到加法器、MUX,都能以簡潔的語法描述。
對初學者來說,建議先多練習這類簡單電路,熟悉assign的寫法,自然而然就能掌握信號流與電路結構。
6. 使用assign語句時的注意事項與常見錯誤
初學者常遇到的assign陷阱
assign
語句是Verilog中最簡單的語法之一,但正因為「看似容易上手」,許多初學者在未完全理解規則時使用,常會導致編譯錯誤或非預期行為。
以下整理了新手到中級使用者在使用assign
時常見的錯誤與解決方法。
1. 嘗試對reg型使用assign
✅ 常見錯誤範例:
reg out;
assign out = a & b; // 錯誤!reg不能用assign指定
💡 原因與解法:
assign
語句只能用於wire。reg
則需在always
區塊內更新。
解法:將out改為wire,或改用always區塊處理。
2. 同一信號被多個assign驅動
✅ 錯誤範例:
assign y = a & b;
assign y = a | b; // 錯誤,y有多個驅動來源
💡 原因與解法:
Verilog規定一個信號只能有唯一驅動來源。多個assign對同一信號賦值會造成衝突。
解法:使用always
區塊或中間信號分解運算。
3. 錯把assign當初始化使用
✅ 錯誤寫法:
assign a = 1'b0; // 不是初始化,而是「永遠為0」
💡 原因與解法:
assign
表示持續驅動,而非一次性的初始化。硬體設計中「初始值」的概念與軟體不同。
解法:模擬時可用initial
,實際電路則需透過reset控制。
4. 忘記宣告信號型態
✅ 錯誤範例:
assign result = a & b; // result未宣告 → 錯誤
💡 原因與解法:
Verilog要求所有信號必須先宣告。若未宣告,會導致模擬器警告或合成錯誤。
解法:明確將信號宣告為wire
或reg
。
5. 在assign中使用不支援的運算
部分運算如除法(/
)或取餘數(%
)在FPGA或ASIC合成時可能不支援:
assign out = a / 3; // 部分工具無法合成,可能報錯
解法:確認是否可合成,必要時改用邏輯運算或always區塊實現。
6. 過度使用巢狀三元運算子
assign out = sel1 ? a : (sel2 ? b : (sel3 ? c : d)); // 可讀性差!
巢狀條件太多會讓程式難以閱讀。
解法:將條件拆分成中間信號,或用always
區塊實現。
assign除錯小技巧
- 明確區分wire與reg
- 注意警告訊息(常提示潛在問題)
- 確認語法是否可合成(模擬能跑≠能實現硬體)
總結:assign雖簡單,但仍需小心
assign
語句是Verilog中最基礎、最常用的結構,但仍有一些限制:只能用於wire、不可多重驅動、不能當初始化。遵守這些規則,才能避免設計上的陷阱,寫出穩定可維護的程式。
7. 常見問題(FAQ)
關於Verilog的assign
語句,從初學者到中級使用者都經常提出疑問。本章整理了實際常被搜尋、也常在設計現場遇到的問題,以Q&A方式解答。
Q1:assign與always,哪一個對初學者比較容易?
A:建議先從assign開始學習。
assign
能簡單表達組合邏輯,因此對初學者最合適。而always
主要用於時序電路或條件控制,相對更複雜。
- 簡單邏輯運算 →
assign
- 需要時間或狀態控制 →
always
Q2:如果想在reg型上使用assign,該怎麼辦?
A:不行。reg必須透過always區塊來指定。
assign
是專屬於wire
的。若要對reg
賦值,必須使用always
:
// 正確寫法(reg在always區塊中更新)
reg out;
always @(a or b)
out = a & b;
// 錯誤寫法(assign不能用於reg)
reg out;
assign out = a & b; // 錯誤
Q3:可以用多個assign語句同時指定同一個信號嗎?
A:不可以,這會造成衝突。
在Verilog中,一個信號只能有唯一驅動來源。多個assign
同時對同一個信號賦值,會導致競爭或未定義行為。
如果需要多條件控制,應該用always
區塊來實現。
Q4:assign的延遲指定(#)有什麼用途?
A:僅在模擬時有意義,實際合成時會被忽略。
例如:
assign #5 out = a & b;
這表示輸出延遲5個時間單位。但在FPGA或ASIC合成時通常無效。
- 模擬 → 可用於驗證延遲
- 合成 → 基本上會被忽略
Q5:要在assign語句中寫條件分支,要怎麼做?
A:可以使用三元運算子(條件運算子)。
assign out = sel ? a : b;
這代表「若sel
為1,輸出a;否則輸出b」。
若條件過於複雜,則建議使用always
區塊。
Q6:模擬時,為什麼assign的輸出沒有變化?
A:請確認輸入是否有正確改變。
assign
輸出的更新依賴輸入。如果輸入沒有變化,輸出自然不會改變。
- 輸入信號是否正確驅動?
- 是否有初始化?
- 波形檢查時輸入真的有切換嗎?
Q7:assign描述的電路可以合成嗎?
A:大部分情況可以,但要注意運算種類。
一般邏輯運算(AND、OR、XOR等)幾乎都能合成。但部分運算如除法(/
)、實數或浮點數處理,可能會被工具拒絕。
- AND / OR / XOR → ✅ 可合成
- 除法、浮點數 → ⚠️ 可能無法合成
8. 術語集:Verilog初學者必備基礎名詞
在學習Verilog HDL時,有一些基礎術語必須先理解。本章整理了與assign
以及組合邏輯相關的重要關鍵字,方便新手快速掌握。
wire(導線)
定義:
模擬電路中實體「導線」的信號型態。用來接收並傳遞其他信號的值。
特徵:
- 可透過
assign
指定值 - 本身不會保存數值
- 主要用於組合邏輯
範例:
wire a, b, out;
assign out = a & b;
reg(暫存器)
定義:
可以暫時保存數值的信號型態。主要在always
區塊中使用。
特徵:
- 不能用
assign
驅動 - 可作為記憶元素
- 常用於時序邏輯
範例:
reg out;
always @(posedge clk) out <= a;
assign(指定)
定義:
對wire型信號進行連續指定(continuous assignment)的語法。
特徵:
- 用於組合邏輯
- 輸入改變時,輸出即時更新
- 可包含邏輯、條件與常數運算
範例:
assign y = a & b;
always(永遠區塊)
定義:
根據特定條件(事件)來執行的程式區塊。
特徵:
- 用於
reg
型 - 可描述時脈或條件控制
- 可搭配if、case等流程控制語句
範例:
always @(posedge clk) begin
out <= a + b;
end
組合邏輯電路(Combinational Circuit)
定義:
輸出僅依賴當前輸入的電路。
特徵:
- 沒有記憶元素
- 範例:邏輯閘、加法器、多工器(MUX)
- 在Verilog中可用
assign
或always @(*)
描述
時序邏輯電路(Sequential Circuit)
定義:
輸出取決於輸入與過去的狀態的電路。
特徵:
- 包含記憶元素(暫存器、觸發器)
- 依據時脈運作
- 常用
always @(posedge clk)
描述
三元運算子(條件運算子)
定義:
以「條件 ? 真值 : 假值」形式撰寫的條件語法。
特徵:
- 常用於
assign
- 比if語句更簡潔
範例:
assign y = sel ? a : b;
模組(module)
定義:
Verilog設計的基本單位,就像電路的元件。
特徵:
- 擁有輸入與輸出埠
- 可以階層式組合形成大型電路
範例:
module adder(input a, input b, output sum);
assign sum = a + b;
endmodule
初始化(initial)
定義:
模擬時僅執行一次的程式區塊。
特徵:
- 不會合成到實體電路
- 常用於測試平台(testbench)
範例:
initial begin
a = 0;
b = 1;
end
非阻塞賦值(<=)
定義:
在always
區塊中使用的賦值方式,可同時更新多個變數。
特徵:
- 常用於時脈同步設計
- 適合平行更新多個寄存器
範例:
always @(posedge clk) begin
out1 <= in1;
out2 <= in2;
end
總結:理解術語是學好Verilog的第一步
以上術語屬於Verilog最基礎的核心概念。只要理解它們的用途與差異,就能快速定位錯誤來源,加速開發效率。
9. 總結|掌握assign語句的關鍵
本文針對Verilog HDL中的assign
語句,從基礎到進階進行了逐步說明。assign
是初學者必須最先掌握的語法之一,雖然簡單卻非常重要,因為它是組合邏輯設計的核心工具。
回顧assign語句的重點
以下整理了本文所涵蓋的關鍵要點:
✅ assign語句的角色
- 用於
wire
型信號的連續指定 - 輸入變化會立即反映到輸出
- 最適合用來描述組合邏輯電路
✅ 使用規則
assign
不能用於reg
- 同一個信號不能被多個
assign
驅動 - 不能作為初始化使用(僅能持續驅動)
✅ 使用技巧
- 明確區分assign與always的使用場景
- 靈活運用三元運算子,簡潔描述條件分支
- 複雜邏輯時可分解為中間信號,提高可讀性
下一步學習方向
在掌握assign
之後,建議進一步挑戰以下主題:
- 使用
always
區塊編寫時序邏輯 - 熟悉
case
與if
的條件控制設計 - 學習撰寫測試平台(testbench)並進行模擬驗證
- 多模組整合與階層式設計
Verilog的學習重點在於「實作經驗」。從小型電路開始,多動手練習,透過assign
建立基礎,將能快速提升設計能力。
最後的話
只要能正確理解並靈活運用assign
,就等於跨過了Verilog學習的一大門檻。
希望本文能成為你隨時回顧的「assign實用指南」,幫助你在數位電路設計的學習道路上更加順利。