- 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に関するよくある質問
1. Verilog functionとは?(基本の概念と役割)
Verilog HDL(Hardware Description Language)は、デジタル回路の設計やシミュレーションに使用されるハードウェア記述言語です。その中でも function(関数) は、特定の処理をモジュール化して再利用しやすくするための仕組みの一つです。
Verilog functionを理解することは、コードの可読性や保守性を向上させるだけでなく、効率的な回路設計にもつながります。本記事では、Verilog functionの基本概念を解説し、functionがどのように使われるのかを説明します。
functionとは何か?
Verilog function は、特定の計算や処理を行い、単一の値を返すブロック です。functionを利用することで、冗長なコードを減らし、回路設計をシンプルにできます。
functionの特徴
- 入力は1つ以上指定可能(
input
のみ使用可能) - 出力は1つのみ(関数の戻り値)
- 時間遅延(
#10
など)を含めることはできない - 関数内で常に組み合わせ回路(combinational logic)を記述する
- functionはalwaysブロックの外部で定義し、タスクとは異なり、いつでも即時評価される
Verilog functionが使われる場面
Verilog functionは、主に以下のような場面で使用されます。
1. 組み合わせ回路の記述
functionは、入力に対して即座に結果を返すため、組み合わせ回路(Combinational Logic)でよく利用されます。
例: 加算、減算、エンコーダ、デコーダなどの演算処理。
2. コードの再利用性を向上
冗長なコードを排除し、複数回使用される処理を簡潔にまとめることができます。
例: 条件分岐を含む複雑な計算式を関数化することで、モジュールの可読性を向上。
3. 設計ミスを減らす
計算処理や論理演算を一箇所にまとめることで、変更時の修正ミスを減らせる。
例: CRC(巡回冗長検査)の計算やパリティチェックなど。
functionとtaskの違い
Verilogには、functionとは別に task(タスク) という記述方法もあります。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ビットの加算を行う関数を示します。
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ビットの入力2つ(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
関数内で 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
キーワードで定義し、1つの値を返す - 入力は
input
のみ(output
は使用不可) - 計算結果を
関数名
に代入することで値を返す if
文やcase
文を用いた条件分岐が可能

3. Verilog functionの使い方【実践コード付き】
前のセクションでは、Verilog functionの基本的な構文や書き方を学びました。
ここでは、functionを実際の設計でどのように活用するか を具体的な例を交えて解説します。
functionの呼び出し方法
Verilog functionは、通常の変数と同じように 関数名(引数1, 引数2, ...)
の形式で呼び出し ます。
次の例では、8ビットのXOR演算を行うfunctionを定義し、モジュール内で使用しています。
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は、常に即時評価される ため、組み合わせ回路を構成する際に便利です。
次の例では、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'b01;
#10; // 遅延を入れることでシミュレーションの変化を確認
$display("Decoded Output: %b", decoded_output); // Decoded Output: 0010
end
endmodule
解説
decoder
functionは、2ビットの入力を4ビットのデコーダ出力に変換case
文を使用して、入力に応じた出力を決定assign
文を使用して 関数の出力をdecoded_output
に代入
→ functionは 組み合わせ回路の一部として使える
always文とfunctionの違い【表で比較】
Verilog functionと always
文はどちらも論理記述に使われますが、目的や制約が異なります。
項目 | function | always文 |
---|---|---|
記述場所 | always ブロックの外 | always ブロック内 |
入力 | input のみ | reg , wire どちらも可 |
出力 | 1つの値のみ | 複数の値を更新可能 |
遅延 (#10 ) | 不可 | 可能 |
状態保持 | 不可(常に即時評価) | 可(フリップフロップとして使用可能) |
主な用途 | 組み合わせ回路 | 順序回路やイベント駆動処理 |
使い分けのポイント
- functionは、単純な論理演算(組み合わせ回路)を簡潔に書くために使う
- always文は、フリップフロップなどの状態を持つ回路に適用する
- 遅延(
#10
など)を使いたい場合は、functionではなくalwaysを使用
Verilog functionの使い方まとめ
✅ functionは 関数名(引数)
の形式で呼び出す
✅ 組み合わせ回路の設計に適しており、always文とは異なる役割を持つ
✅ case
文や if
文を使用して、柔軟なロジックを記述できる
✅ デコーダや演算処理などの場面で活用される
4. Verilog functionの応用例(デコーダやALUの設計)
これまで、Verilog functionの基本構文や使い方を学びました。
このセクションでは、実際のデジタル回路設計でfunctionをどのように活用するか、デコーダやALU(演算論理ユニット)を例にとって詳しく解説 します。
デコーダのfunction実装(2-to-4デコーダ)
デコーダは、少ないビットの入力を多くのビットの出力に変換する回路 です。
例えば、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
まとめ
✅ デコーダやALUのような組み合わせ回路にfunctionを活用できる
✅ case文を用いることで、柔軟な演算処理を記述可能
✅ コードの可読性を向上し、再利用しやすい設計が可能
✅ functionは組み合わせ回路として最適だが、順序回路には向かない(遅延を含められない)
5. Verilog functionを使う際の注意点
Verilog functionは、コードの可読性や再利用性を向上させる強力なツールですが、いくつかの制約があります。本セクションでは、functionを使用する際に注意すべきポイントを詳しく解説します。
再帰呼び出しはできない
Verilog functionでは 関数の再帰呼び出し(recursive call)は禁止 されています。
つまり、function内で自身を呼び出すことはできません。
❌ NG例:再帰呼び出しを含む関数
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
など) を含めることはできません。
❌ NG例:function内での遅延
function [7:0] delay_function;
input [7:0] in;
begin
#10; // ❌ function内で遅延は使えない
delay_function = in + 1;
end
endfunction
このコードは コンパイルエラー になります。
✅ 解決策:alwaysブロックを使用
遅延を使いたい場合は、functionではなく alwaysブロックやtaskを使用 します。
task delay_task;
input [7:0] in;
output [7:0] out;
begin
#10;
out = in + 1;
end
endtask
このように 遅延を含む処理はtaskを使用する ことで対応できます。
functionとtaskの適切な使い分け
Verilogには function の他に task という構造もあります。
これらは似ていますが、異なる用途を持つため、適切に使い分ける必要があります。
項目 | function | task |
---|---|---|
出力 | 1つのみ(関数名を返す) | 複数可(output 変数を指定可) |
入力 | input のみ | input / output どちらも使用可 |
内部変数 | 使用可 | 使用可 |
遅延 (#10 ) | 不可 | 可能 |
always 内での使用 | 可 | 不可 |
呼び出し方 | 関数名(引数) | task名(引数); |
functionを使うべきケース
✅ 計算結果を即時に得たい(例:加算、減算、論理演算)
✅ 遅延なしで動作する組み合わせ回路 を記述する
✅ 戻り値が1つだけ必要な場合
taskを使うべきケース
✅ 遅延(#10
など)を含める必要がある
✅ 複数の出力を持つ処理 を行う
✅ シミュレーションでデバッグ用の処理(モニタリング、表示)を行う
functionはalwaysブロック内では定義できない
Verilog functionは always ブロックの内部では定義できません。
関数は モジュールの外で定義する必要があります。
❌ NG例:alwaysブロック内での関数定義
always @(a or b) begin
function [7:0] my_function; // ❌ always内での関数定義は禁止
input [7:0] x, y;
begin
my_function = x + y;
end
endfunction
end
このコードはコンパイルエラーになります。
✅ 正しい方法
alwaysブロックの外で function を定義し、ブロック内で呼び出す。
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
このように、functionは 常にモジュールの外で定義する 必要があります。
まとめ
✅ Verilog functionにはいくつかの制約がある
✅ 再帰呼び出しはできない(ループやtaskを使用する)
✅ 時間遅延(#10)は使えない(alwaysやtaskを使用)
✅ alwaysブロック内では定義できない(モジュールの外で定義する)
✅ 戻り値は1つだけ(複数の出力が必要な場合はtaskを使用)
✅ functionとtaskを適切に使い分けることが重要
6. 【FAQ】Verilog functionに関するよくある質問
これまで、Verilog functionの基本から応用、注意点について詳しく解説してきました。
このセクションでは、Verilog functionに関する よくある質問とその回答 をまとめます。
functionとtaskの違いは?
Q. Verilog functionとtaskの違いは何ですか? どちらを使うべきでしょうか?
A. functionは「1つの値を即時に返す処理」、taskは「複数の値を出力したり、遅延を含む処理」に使います。
項目 | function | task |
---|---|---|
出力 | 1つのみ(関数名を返す) | 複数可(output 変数を指定可) |
入力 | input のみ | input / output どちらも使用可 |
内部変数 | 使用可 | 使用可 |
遅延 (#10 ) | 不可 | 可能 |
always 内での使用 | 可 | 不可 |
呼び出し方 | 関数名(引数) | task名(引数); |
functionを使うべきケース
✅ 計算結果を即時に得たい(例:加算、減算、論理演算)
✅ 遅延なしで動作する組み合わせ回路 を記述する
✅ 戻り値が1つだけ必要な場合
taskを使うべきケース
✅ 遅延(#10
など)を含める必要がある
✅ 複数の出力を持つ処理 を行う
✅ シミュレーションでデバッグ用の処理(モニタリング、表示)を行う
function内でレジスタ(reg)は使える?
Q. functionの中で reg
を使えますか?
A. function内では reg
は使用できませんが、代わりに 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. functionは「単純な演算処理」や「組み合わせ回路の記述」に適しています。
例えば、以下のような処理に使うと便利です:
- 演算処理(加算、減算、論理演算)
- デコーダやエンコーダ
- 比較演算(最大値・最小値の判定)
- エラーチェック(パリティチェックなど)
ただし、順序回路(フリップフロップを含む回路)には適していません。
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との使い分けも重要(順序回路 vs 組み合わせ回路)
✅ 遅延(#10)や配列は使用できないため、taskやmoduleを活用する