- 1 1. Verilog function是什麼?(基本概念與角色)
- 2 2. Verilog function的寫法【含新手範例】
- 3 3. Verilog function的用法【附實際程式碼】
- 4 4. Verilog function的應用範例(解碼器與ALU設計)
- 5 5. 使用Verilog function時的注意事項
- 6 6. 【FAQ】關於Verilog function的常見問題
- 7 7. 總結
1. Verilog function是什麼?(基本概念與角色)
Verilog HDL(Hardware Description Language,硬體描述語言)是一種用於數位電路設計與模擬的語言。其中的 function(函式),是一種將特定處理模組化並方便重複利用的機制。
理解Verilog function不僅能提升程式碼的可讀性與維護性,也能帶來更高效的電路設計。本文將說明Verilog function的基本概念,並解釋function在實務上的使用方式。
什麼是function?
Verilog function 是一個 執行特定計算或處理,並回傳單一數值的區塊。使用function可以減少冗長的程式碼,使電路設計更加簡潔。
function的特點
- 輸入可指定一個以上(僅能使用
input
) - 輸出僅限一個(函式的回傳值)
- 不可包含時間延遲(如
#10
) - 函式內必須描述組合邏輯(combinational logic)
- function定義在always區塊外,與task不同,會立即被評估
Verilog function的使用場景
Verilog function主要應用於以下情境:
1. 描述組合邏輯
function會針對輸入立即回傳結果,因此常用於組合邏輯(Combinational Logic)。
範例:加法、減法、編碼器(encoder)、解碼器(decoder)等運算。
2. 提升程式碼的重用性
透過將重複的運算封裝為函式,可以簡化程式碼並提高模組的可讀性。
範例:含有條件判斷的複雜運算式可寫成函式,讓模組更清晰。
3. 減少設計錯誤
將計算或邏輯集中於一個function中,可降低修改時出現錯誤的風險。
範例:CRC(循環冗餘檢查)運算或奇偶校驗。
function與task的差異
在Verilog中,除了function,還有 task(任務)。兩者雖然相似,但存在以下差異:
項目 | function | task |
---|---|---|
輸出 | 僅限1個 | 可多個 |
輸入 | 有 | 有 |
內部變數 | 可使用 | 可使用 |
延遲(#10 ) | 不可 | 可 |
在always 內使用 | 可 | 不可 |
呼叫方式 | 函式名(參數) | task名(參數); |
適合使用function的情況
- 需要立即取得計算結果
- 不包含延遲(delay)的邏輯處理
- 僅需回傳一個值的簡單處理
適合使用task的情況
- 包含時間延遲(如
#10
)的處理 - 需要多個輸出的處理
- 模擬時的除錯用途(如日誌輸出)
總結
- Verilog function 是 接收輸入並回傳單一數值的函式
- 適用於組合邏輯的描述,且不可包含延遲
- 能減少冗長程式碼並提升可讀性
- function與task不同,需根據用途選擇
2. Verilog function的寫法【含新手範例】
在上一節我們已經學習了Verilog function的基本概念。接下來將更詳細地介紹Verilog function的具體寫法。
function的基本語法
Verilog function可依照以下基本語法來撰寫:
function [輸出的位元寬度] 函式名稱;
input [輸入的位元寬度] 輸入1, 輸入2, ...;
begin
函式名稱 = 計算式;
end
endfunction
重點
- 使用
function
關鍵字宣告 - 與函式名稱相同的變數即為回傳值
- 輸入需以
input
宣告(不可使用output
或inout
) - 計算處理需寫在
begin ... end
內 - 必須定義在
always
區塊之外
簡單的Verilog function範例
以下範例示範一個執行8位元加法的function:
module example;
function [7:0] add_function;
input [7:0] a, b;
begin
add_function = a + b;
end
endfunction
reg [7:0] x, y, sum;
initial begin
x = 8'b00001100; // 12
y = 8'b00000101; // 5
sum = add_function(x, y);
$display("Sum: %d", sum); // Sum: 17
end
endmodule
解說
add_function
是一個 接收兩個8位元輸入(a, b),並回傳其和 的函式- 透過
sum = add_function(x, y);
呼叫函式,並將結果指定給變數sum
- 在
initial
區塊內使用$display
輸出結果
Verilog function的輸入與輸出宣告方式
輸入宣告
Verilog function的參數 僅能使用 input
。
function [7:0] my_function;
input [7:0] in1, in2;
begin
my_function = in1 & in2; // AND運算
end
endfunction
注意: 不可指定 output
,函式的回傳值由 與函式名稱相同的變數 承載。
含條件分支的Verilog function
在function內可以使用 if
或 case
進行條件判斷。
function [3:0] max_function;
input [3:0] a, b;
begin
if (a > b)
max_function = a;
else
max_function = b;
end
endfunction
此函式會 回傳a與b之中較大的值。
小結
- Verilog function以
function
關鍵字定義,並回傳單一值 - 僅能使用
input
作為參數(不可使用output
) - 透過將計算結果指定給函式名稱來回傳值
- 可以在function內使用
if
與case
進行條件分支
3. Verilog function的用法【附實際程式碼】
在上一節中,我們學習了Verilog function的基本語法與寫法。
本節將透過範例,說明function在實際設計中如何應用。
function的呼叫方式
Verilog function的呼叫方式與一般變數相似,使用 函式名(參數1, 參數2, ...)
的形式。
以下範例定義了一個8位元的XOR函式,並在模組中使用:
module function_example;
function [7:0] xor_function;
input [7:0] a, b;
begin
xor_function = a ^ b;
end
endfunction
reg [7:0] x, y, result;
initial begin
x = 8'b11001100;
y = 8'b10101010;
result = xor_function(x, y); // 呼叫function
$display("XOR Result: %b", result); // XOR Result: 01100110
end
endmodule
重點
- 呼叫方式:
變數 = function(參數);
- 可在always區塊或initial區塊內使用
- 以組合邏輯(combinational logic)的方式運作
在組合邏輯中使用function
由於Verilog function 總是立即被評估,因此在撰寫組合邏輯時非常方便。
以下範例示範如何用function實作一個2-to-4解碼器:
module decoder_example;
function [3:0] decoder;
input [1:0] sel;
begin
case (sel)
2'b00: decoder = 4'b0001;
2'b01: decoder = 4'b0010;
2'b10: decoder = 4'b0100;
2'b11: decoder = 4'b1000;
default: decoder = 4'b0000;
endcase
end
endfunction
reg [1:0] select;
wire [3:0] decoded_output;
assign decoded_output = decoder(select); // 使用function
initial begin
select = 2'b01;
#10; // 加入延遲以觀察模擬變化
$display("Decoded Output: %b", decoded_output); // Decoded Output: 0010
end
endmodule
解說
decoder
function會將 2位元輸入轉換為4位元輸出- 透過
case
敘述決定輸出的結果 - 使用
assign
敘述將 function的輸出指定給decoded_output
→ function能作為組合邏輯的一部分
always語句與function的差異【比較表】
Verilog function與 always
語句都能描述邏輯,但用途與限制不同。
項目 | function | always語句 |
---|---|---|
撰寫位置 | always 區塊之外 | always 區塊之內 |
輸入 | 僅限 input | reg 與 wire 均可 |
輸出 | 僅能回傳單一數值 | 可更新多個變數 |
延遲 (#10 ) | 不可 | 可 |
狀態保持 | 不可(總是立即運算) | 可(可作為觸發器或暫存器) |
主要用途 | 組合邏輯 | 序向邏輯或事件驅動處理 |
使用上的重點
- function:適合簡單的組合邏輯運算
- always語句:適合設計具狀態的序向邏輯(如觸發器、計數器)
- 若需要延遲(如
#10
),應使用always而非function
Verilog function使用總結
✅ 使用 函式名(參數)
的形式呼叫
✅ 適用於組合邏輯設計,功能與always不同
✅ 可搭配 case
或 if
撰寫彈性的邏輯
✅ 常見應用:解碼器、運算處理
4. Verilog function的應用範例(解碼器與ALU設計)
到目前為止,我們已經學習了Verilog function的基本語法與使用方式。
本節將說明在實際數位電路設計中,如何運用function,並以解碼器(Decoder)與ALU(算術邏輯單元)為例做詳細解說。
解碼器的function實作(2-to-4 Decoder)
解碼器是一種 將少量位元輸入轉換為多位元輸出的電路。
例如:2位元輸入轉換成4位元輸出的2-to-4解碼器。以下使用function來實作:
module decoder_example;
function [3:0] decoder;
input [1:0] sel;
begin
case (sel)
2'b00: decoder = 4'b0001;
2'b01: decoder = 4'b0010;
2'b10: decoder = 4'b0100;
2'b11: decoder = 4'b1000;
default: decoder = 4'b0000;
endcase
end
endfunction
reg [1:0] select;
wire [3:0] decoded_output;
assign decoded_output = decoder(select); // 使用function
initial begin
select = 2'b00; #10;
$display("Decoded Output: %b", decoded_output);
select = 2'b01; #10;
$display("Decoded Output: %b", decoded_output);
select = 2'b10; #10;
$display("Decoded Output: %b", decoded_output);
select = 2'b11; #10;
$display("Decoded Output: %b", decoded_output);
end
endmodule
ALU的function實作(加法、減法、AND、OR)
ALU(Arithmetic Logic Unit,算術邏輯單元) 是CPU的核心運算單元,主要負責加法、減法與邏輯運算(AND、OR等)。
以下範例示範如何用Verilog function設計一個簡單的8位元ALU:
module alu_example;
function [7:0] alu;
input [7:0] a, b;
input [1:0] op; // 2位元控制訊號
begin
case (op)
2'b00: alu = a + b; // 加法
2'b01: alu = a - b; // 減法
2'b10: alu = a & b; // AND運算
2'b11: alu = a | b; // OR運算
default: alu = 8'b00000000;
endcase
end
endfunction
reg [7:0] x, y;
reg [1:0] opcode;
wire [7:0] result;
assign result = alu(x, y, opcode); // 使用function
initial begin
x = 8'b00001100; // 12
y = 8'b00000101; // 5
opcode = 2'b00; #10;
$display("Addition Result: %d", result); // 12 + 5 = 17
opcode = 2'b01; #10;
$display("Subtraction Result: %d", result); // 12 - 5 = 7
opcode = 2'b10; #10;
$display("AND Result: %b", result); // AND運算
opcode = 2'b11; #10;
$display("OR Result: %b", result); // OR運算
end
endmodule
小結
✅ function可應用於解碼器與ALU等組合邏輯電路
✅ 搭配case語句能實現多樣化的運算
✅ 提升程式碼可讀性並方便重複使用
✅ function適合組合邏輯,但不適用於序向邏輯(不可包含延遲)
5. 使用Verilog function時的注意事項
Verilog function能提升程式碼的可讀性與重用性,但也存在一些限制。本節將詳細說明在使用function時需要注意的要點。
不可進行遞迴呼叫
Verilog function禁止函式的遞迴呼叫(recursive call)。
換句話說,function內不能再呼叫自己。
❌ 錯誤範例:含遞迴呼叫的函式
function [3:0] factorial;
input [3:0] n;
begin
if (n == 0)
factorial = 1;
else
factorial = n * factorial(n - 1); // ❌ 遞迴呼叫不可使用
end
endfunction
此程式碼會造成 模擬錯誤。
✅ 解決方法:使用迴圈
若需要類似遞迴的處理,可在 always區塊內使用迴圈,或改用task。
task factorial_task;
input [3:0] n;
output [15:0] result;
integer i;
begin
result = 1;
for (i = 1; i <= n; i = i + 1)
result = result * i;
end
endtask
這樣可透過迴圈來避免遞迴。
function內不可使用時間延遲(#10)
由於Verilog function 屬於即時運算(combinational logic),
因此不可包含任何時間延遲(例如 #10
)。
❌ 錯誤範例:在function內使用延遲
function [7:0] delay_function;
input [7:0] in;
begin
#10; // ❌ function內不能使用延遲
delay_function = in + 1;
end
endfunction
此程式會產生 編譯錯誤。
✅ 解決方法:使用always或task
若需要延遲,應改用 always區塊或task。
task delay_task;
input [7:0] in;
output [7:0] out;
begin
#10;
out = in + 1;
end
endtask
👉 適合含有延遲的處理請使用task。
function與task的正確區分
除了function,Verilog還有 task。雖然類似,但用途不同,因此必須正確選用。
項目 | function | task |
---|---|---|
輸出 | 僅限1個(透過函式名稱回傳) | 可多個(透過output變數) |
輸入 | 僅能使用input | 可使用input / output |
內部變數 | 可使用 | 可使用 |
延遲 (#10 ) | 不可 | 可 |
在always 內使用 | 可 | 不可 |
呼叫方式 | 函式名(參數) | task名(參數); |
適合使用function的情境
✅ 需要立即取得計算結果(如加法、減法、邏輯運算)
✅ 適合無延遲的組合邏輯
✅ 僅需單一回傳值
適合使用task的情境
✅ 需要包含延遲(如 #10
)
✅ 需要多個輸出
✅ 適用於模擬除錯(例如輸出log或監控訊號)
function不能在always區塊內定義
Verilog function不可在always區塊內宣告,
必須定義在模組層級,並於always區塊內呼叫。
❌ 錯誤範例:在always內定義function
always @(a or b) begin
function [7:0] my_function; // ❌ 禁止在always內定義
input [7:0] x, y;
begin
my_function = x + y;
end
endfunction
end
這段程式會造成編譯錯誤。
✅ 正確範例
應將function定義在always區塊之外,並在always中呼叫。
function [7:0] add_function;
input [7:0] x, y;
begin
add_function = x + y;
end
endfunction
always @(a or b) begin
result = add_function(a, b); // ✅ 呼叫function
end
小結
✅ Verilog function有一些限制
✅ 不可遞迴呼叫(需用迴圈或task替代)
✅ 不可使用時間延遲(#10)(需用always或task)
✅ 不可在always內定義(需定義於模組層級)
✅ 僅能有一個回傳值(若需要多輸出,應使用task)
✅ 必須正確區分function與task的用途
6. 【FAQ】關於Verilog function的常見問題
前面章節已經詳細介紹了Verilog function的基礎、應用與注意事項。
本節整理常見問題與解答,方便快速理解。
function與task的差異?
Q. Verilog function與task有什麼不同?該如何選擇?
A. function用於「立即回傳單一數值的處理」,task則用於「可輸出多個值或包含延遲的處理」。
項目 | function | task |
---|---|---|
輸出 | 僅限1個(回傳函式名) | 可多個(透過output變數) |
輸入 | 僅限input | input / output 皆可 |
內部變數 | 可使用 | 可使用 |
延遲 (#10 ) | 不可 | 可 |
在always 中使用 | 可 | 不可 |
呼叫方式 | 函式名(參數) | task名(參數); |
適合使用function的情境
✅ 需要立即獲得計算結果(例如加法、減法、邏輯運算)
✅ 適合無延遲的組合邏輯
✅ 僅需單一回傳值
適合使用task的情境
✅ 需要包含延遲(例如 #10
)
✅ 需要多輸出
✅ 模擬除錯用途(例如訊號監控、日誌輸出)
function內可以使用reg嗎?
Q. 在function中可以宣告 reg
嗎?
A. 不行。但可以使用 integer
作為計算變數。
在Verilog function內不允許宣告 reg
,但可以透過 integer
來進行運算。
✅ 正確範例(使用integer)
function [7:0] multiply;
input [3:0] a, b;
integer temp;
begin
temp = a * b;
multiply = temp;
end
endfunction
什麼時候該使用function?
Q. 在哪些情況下使用function最合適?
A. 適合用於「單純運算處理」與「組合邏輯的描述」。
常見應用範例:
- 運算處理(加法、減法、邏輯運算)
- 解碼器、編碼器
- 比較運算(例如最大值/最小值判斷)
- 錯誤檢查(例如奇偶檢查、CRC)
⚠️ 但不適用於序向邏輯(例如觸發器)。
function內可以呼叫其他function嗎?
Q. Verilog function內可以呼叫其他function嗎?
A. 可以。但需注意函式間的依賴關係。
function [7:0] add;
input [7:0] a, b;
begin
add = a + b;
end
endfunction
function [7:0] double_add;
input [7:0] x, y;
begin
double_add = add(x, y) * 2; // 呼叫另一個function
end
endfunction
function與always應該如何區分使用?
Q. function與always語句要如何正確使用?
A. function適合用於「組合邏輯」,always則適合「序向邏輯」。
項目 | function | always |
---|---|---|
延遲 (#10 ) | 不可 | 可 |
狀態保持 | 不可(立即計算) | 可(可作為暫存器或計數器) |
主要用途 | 組合邏輯(即時運算) | 序向邏輯(時脈觸發) |
例如,加法運算:
✅ function(組合邏輯)
function [7:0] add;
input [7:0] a, b;
begin
add = a + b;
end
endfunction
✅ always(序向邏輯)
always @(posedge clk) begin
sum <= a + b; // 作為觸發器(暫存器)
end
小結
✅ function適合單純計算與組合邏輯
✅ 需理解與task的差異,並正確選擇
✅ 與always語句分工:function負責組合邏輯,always負責序向邏輯
✅ 不可使用延遲或陣列(需要時改用task或module)
7. 總結
透過本篇文章,我們完整介紹了Verilog function 的概念、寫法、應用、限制以及常見問題。以下為重點整理:
- Verilog function 是一種 接收輸入並立即回傳單一值的函式,適合用於組合邏輯。
- 不可包含時間延遲(#10等),也不可進行遞迴呼叫。
- function僅能使用
input
作為參數,且回傳值必須透過與函式同名的變數給出。 - 能大幅提升程式碼的可讀性與重用性,適合用於加法、減法、編碼器、解碼器等運算。
- task 與 function 的用途不同:
→ function 適合簡單、立即回傳結果的組合邏輯。
→ task 適合含延遲、多輸出或除錯用的處理。 - always語句 則適用於序向邏輯(例如暫存器、計數器),與function互補。
✅ 在設計數位電路時,正確區分 function、task、always 的用途,才能寫出高效、可維護的Verilog程式。