Verilog 入門
ハードウェアを「コード」で設計する言語を、プログラミング経験ゼロから理解しよう。
1. Verilog とは何か?
ソフトウェア(Python など)
コンピュータに「何をするか」を伝える命令書。CPU が命令を上から順番に実行する。
# 2つの数を足す a = 5 b = 3 print(a + b) # 8
Verilog(ハードウェア記述言語)
回路の「配線図」をコードで表現する言語。すべての回路が同時に動くのが特徴。
// 2つの数を足す回路 assign result = a + b; // a か b が変わると // result も即座に変わる
🔑 最重要ポイント
Verilog は「命令の実行順序」ではなく「回路の構造」を書く言語です。電線をどうつなぐか、どのゲートを使うかを記述します。
2. モジュール ― 回路の「箱」
Verilog の基本単位は module です。ICチップ(黒い四角いパーツ)をイメージすると分かりやすいです。入力ピンと出力ピンがある「箱」です。
入力 a ─────┐
入力 b ─────┤ AND ゲート(モジュール) ├──── 出力 y
└───────────────────────────┘
// ↓ モジュール名(ICチップの型番に相当) module and_gate ( input a, // ← 入力ピン a input b, // ← 入力ピン b output y // ← 出力ピン y ); assign y = a & b; // ← 回路の中身:AND演算 endmodule // ← 箱の終わり
3. wire と reg ― 2種類の「信号線」
名前のとおり「ただの電線」です。つながれた先の値をそのまま伝えるだけで、値を記憶しません。assign 文と組み合わせて使います。
wire sum; assign sum = a + b; // a や b が変わると // sum もすぐ変わる
→ 組み合わせ回路(加算器など)で使う
値を記憶できる信号線です。クロックの立ち上がりなど「きっかけ」があったときだけ値が更新されます。always ブロックの中で使います。
reg [7:0] count; always @(posedge clk) count <= count + 1; // clk の立ち上がりごとに +1
→ 順序回路(カウンタ・CPUなど)で使う
📐 ビット幅の指定
信号が複数ビットの場合は [上位:下位] で幅を指定します。
1ビット
4ビット (0〜15)
8ビット (0〜255)
4. 回路を書く 3 つの方法
① assign ― 組み合わせ回路(ゲートの配線)
「この出力はこの入力たちの演算結果」という常時有効な結線を記述します。プログラムの行と違い、順番に実行されるわけではありません。
assign y = a & b; // AND assign sum = a + b; // 加算 assign sel = (a > b) ? a : b; // 三項演算子(MUX)
② always @(posedge clk) ― 順序回路(クロックで動く)
クロックの立ち上がり(posedge)ごとに実行されるブロックです。フリップフロップ(記憶素子)の動作を表します。
always @(posedge clk) begin if (rst) count <= 0; // リセット else count <= count + 1; // インクリメント end
always ブロック内では <=(ノンブロッキング代入)を使います。
= と混同しないよう注意しましょう。
③ always @(*) ― if / case を使いたい組み合わせ回路
assign では書きにくい if-else や case は always @(*) で書きます。* は「すべての入力変化に反応する」という意味です。
always @(*) begin case (opcode) 2'b00: result = a + b; // ADD 2'b01: result = a - b; // SUB default: result = 0; endcase end
5. 完全な例:1ビット全加算器
論理ゲートのページで学んだ全加算器(Full Adder)を Verilog で書いてみましょう。入力 a, b, cin → 出力 sum, cout を計算します。
真理値表(抜粋)
| a | b | cin | sum | cout |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 1 | 0 |
| 1 | 1 | 0 | 0 | 1 |
| 1 | 1 | 1 | 1 | 1 |
論理式
これをそのまま Verilog の assign で書けます。
module full_adder ( input a, b, cin, // 3本の入力ピン output sum, cout // 2本の出力ピン ); // sum = a XOR b XOR cin assign sum = a ^ b ^ cin; // cout = (a AND b) OR (cin AND (a XOR b)) assign cout = (a & b) | (cin & (a ^ b)); endmodule // わずか 8 行で 1ビット全加算器が完成!
6. テストベンチ ― 設計を検証する
テストベンチ(Testbench)は「作った回路を試す実験台」です。実際のチップを作る前に、コンピュータ上でシミュレーションしてバグがないか確認します。
テストベンチ(左パネル) 設計(右パネル) ┌─────────────────────┐ ┌──────────────┐ │ a=0, b=0, cin=0 │─────▶│ full_adder │──▶ sum=0, cout=0 │ a=1, b=1, cin=0 │ └──────────────┘ │ a=1, b=1, cin=1 │ └─────────────────────┘
module tb_full_adder; reg a, b, cin; // 操作する入力(reg で宣言) wire sum, cout; // 観察する出力(wire で宣言) // 設計した full_adder を接続する full_adder uut (.a(a), .b(b), .cin(cin), .sum(sum), .cout(cout)); initial begin $dumpfile("dump.vcd"); // 波形ファイル出力 $dumpvars(0, tb_full_adder); // パターン 1: 0+0+0 = 0 a=0; b=0; cin=0; #10; $display("a=%b b=%b cin=%b → sum=%b cout=%b", a,b,cin,sum,cout); // パターン 2: 1+1+0 = 2(sum=0, cout=1) a=1; b=1; cin=0; #10; $display("a=%b b=%b cin=%b → sum=%b cout=%b", a,b,cin,sum,cout); $finish; end endmodule
a=0 b=0 cin=0 → sum=0 cout=0 ✅
a=1 b=1 cin=0 → sum=0 cout=1 ✅
7. Verilog の実際の使い道
「Verilog で回路を書いたあと、どうなるの?」という疑問に答えましょう。
現実では大きく 2つの方向 に使われています。
Verilog の回路を論理合成して FPGA(書き換え可能な半導体)に書き込むと、 実際に動くハードウェアになります。チップを製造しなくても設計を即実機で試せます。
↓ 論理合成(Vivado / Quartus)
📦 ビットストリーム
↓ FPGA に書き込み
⚡ 実機で動作!
実チップを作る前にテストベンチで動作検証したり、 新しいアーキテクチャのアイデアをシミュレーションで性能評価します。 研究では「このCPU設計は速いか?」を Verilog で試します。
↓ シミュレータ(Icarus Verilog)
📊 波形・ログで動作確認
↓ 性能測定・バグ修正
✅ 設計の正しさを証明!
▶ EDA Playground で今すぐ試す
インストール不要のブラウザ上 Verilog シミュレータです。上のコードをコピーして動かしてみましょう。
⚙️ 推奨設定
- Language : Verilog
- Simulator : Icarus Verilog 12.0
- 「Open EPWave after run」にチェック ✅(波形表示)
- テストベンチ → 左パネル 設計コード → 右パネル
8. 次のステップ:Verilog 演習
ここまでの知識で、演習2の課題に挑戦できます。8ビット加算器 → 減算器 → ALU → 小型CPUの順で取り組みましょう。