Verilogで加算回路を書く

(1)ここで学ぶ内容

もふねこ

いよいよVerilog-HDLの文法ノート(Eシリーズ)の始まりだよ🐾
まずは『加算回路』を通して、入力・出力・計算の基本的な書き方をマスターしよう!

概要
  • 加算回路を用いて、組み合わせ回路の記述を学ぶ
  • モジュール構造の概略を理解する

目標

以下の項目を理解し説明できる

  • 回路記述におけるモジュール構造
  • 入出力の宣言
  • 演算子を用いた演算回路記述
  • assign 文の記述
  • 階層構造をもった回路の記述
  • 下位階層の呼び出しと接続

修了判定

信号名を指定して、16ビットの減算回路を記述する
条件:減算演算子を用いる

(2)加算演算子による加算回路

4ビット加算回路

E1 図1:4ビット加算回路のブロック図。a 4bitとb 4bitがadderに入り、4ビットのq 4bitが出る。
E1 図1:4ビット加算回路のブロック図。横に長い図はスクロールして確認できます。
// 加算演算子による4ビット加算回路
module adder( a, b, q );
input   [3:0]   a, b;
output  [3:0]   q;

assign q = a + b;

endmodule
    a  [ ][ ][ ][ ]
 +) b  [ ][ ][ ][ ]
 ──────────────────
    q  [ ][ ][ ][ ]

(3)フルアダーによる加算回路

4ビット加算回路

E1 図2:4ビット加算回路のブロック図。a 4bitとb 4bitがadderに入り、4ビットのq 4bitが出る。
E1 図2:4ビット加算回路のブロック図。横に長い図はスクロールして確認できます。
E1 図3:fulladdを4個つないだ図。add0 fulladd〜add3 fulladdにa 0〜a 3とb 0〜b 3が入り、q 0〜q 3が出る。CIN 0がadd0に入り、桁上げはadd0からadd3へ順に渡り、最後は開放。
E1 図3:fulladdを4個つないだ図。横に長い図はスクロールして確認できます。

(4)フルアダーの動作

フルアダー

E1 図4:フルアダーの図。入力A、入力B、入力CINがフルアダーに入り、出力Qと出力COUTが出る。
E1 図4:フルアダーの図。横に長い図はスクロールして確認できます。

動 作

        [ A ]
    +)  [ B ]
    +)  [CIN]
   ──────────
   [COUT] [ Q ]

真理値表

入 力出 力
ABCINCOUTQ
00000
00101
01001
01110
10001
10110
11010
11111

(5)フルアダーの記述

フルアダー

E1 図5:フルアダーの図。入力A、入力B、入力CINがフルアダーに入り、出力Qと出力COUTが出る。
E1 図5:フルアダーの図。横に長い図はスクロールして確認できます。
E1 図6:XOR、AND、ORで組んだ回路図。AとBがXORに入り、その出力とCINが次のXORに入ってQになる。AとB、BとCIN、CINとAがそれぞれANDに入り、3つの出力がORを通ってCOUTになる。
E1 図6:XOR、AND、ORで組んだ回路図。横に長い図はスクロールして確認できます。
演算子は C 言語とほぼ同じ
module fulladd( A, B, CIN, Q, COUT );
input   A, B, CIN;
output  Q, COUT;

assign Q    = A ^ B ^ CIN;
assign COUT = (A & B) | (B & CIN) | (CIN & A);

endmodule

ミニ実験:全加算器をブラウザで試す

ここでは、上で出てきたフルアダーの assign 文を少し書き換えながら、入力、出力、真理値表、簡易波形の変化を確認できます。実際のVerilogシミュレータではありませんが、a、b、cin を使った1ビットの組み合わせ回路を体験するための小さな実験パネルです。

全加算器の assign 文を試す

q は和の1ビット、cout は桁上がりです。式を変えて「実行」を押すと、下の真理値表と波形が更新されます。

使える信号は a、b、cin、使える演算子は ~ & ^ | ( ) です。

入力を切り替える
現在の出力
q -
cout -

(6)フルアダーによる加算回路の記述1

4ビット加算回路

E1 図7:4ビット加算回路のブロック図。a 4bitとb 4bitがadderに入り、4ビットのq 4bitが出る。
E1 図7:4ビット加算回路のブロック図。横に長い図はスクロールして確認できます。
module adder_ripple( a, b, q );
input   [3:0]   a, b;
output  [3:0]   q;
wire    [3:0]   cout;

fulladd add0 ( a[0], b[0],      1'b0, q[0], cout[0] );
fulladd add1 ( a[1], b[1], cout[0], q[1], cout[1] );
fulladd add2 ( a[2], b[2], cout[1], q[2], cout[2] );
fulladd add3 ( a[3], b[3], cout[2], q[3], cout[3] );

endmodule

(7)フルアダーによる加算回路の記述2

module adder_ripple2( a, b, q );
input   [3:0]   a, b;
output  [3:0]   q;
wire    [3:0]   cout;

fulladd add0 ( .Q(q[0]), .COUT(cout[0]),
               .A(a[0]), .B(b[0]), .CIN(1'b0) );
fulladd add1 ( .Q(q[1]), .COUT(cout[1]),
               .A(a[1]), .B(b[1]), .CIN(cout[0]) );
fulladd add2 ( .Q(q[2]), .COUT(cout[2]),
               .A(a[2]), .B(b[2]), .CIN(cout[1]) );
fulladd add3 ( .Q(q[3]), .COUT(cout[3]),
               .A(a[3]), .B(b[3]), .CIN(cout[2]) );

endmodule

(8)ワンポイント・アドバイス

もふねこ

文法で一番大事なのは『名前による接続(Named Port Mapping)』だよ🐾
少し面倒に感じるかもしれないけど、実務ではバグを防ぐための絶対ルールだから、最初からこの書き方に慣れておこう!

  • 回路記述の基本構造はモジュール。
    回路記述の他にも、シミュレーションのために入力を作成する記述もモジュールの構造で書く。
  • 2つのスラッシュ以降行末まではコメント。
    このほかに、 /* で始まり、 */ までのコメントがある。これは何行にわたってもかまわない。
    回路記述にはコメントをたくさん付けよう。
  • 下位モジュールの接続には、「順番による接続」と「名前による接続」がある。
    「名前による接続」で書いた方が、接続を誤りにくい。少々面倒くさくても、「名前による接続」で書こう。
    「名前による接続」と「順番による接続」は、一つのモジュール呼び出しの中では混在できない。文法エラーになります。

(9)修了判定

もふねこ

さいごに、学んだことを活かして減算回路(引き算)を書いてみよう🐾
「assign文」の書き方、もうバッチリだよね?

設問
  • 16ビット減算回路を記述する。
  • 空欄をうめて記述を完成し、採点ボタンをおす。
  • 全問正解なら、このユニットは修了。

16 ビット減算回路
(SUB ← X - Y)

E1 図8:SUBTRACTモジュールの図。X 16bitとY 16bitが減算回路に入り、16ビットのSUB 16bitが出る。
E1 図8:SUBTRACTモジュールの図。横に長い図はスクロールして確認できます。
module SUBTRACT ;

input   [15:0] X, Y;
 SUB;

 SUB = X - Y;

endmodule

🐾 もふねこのつまずきメモ(関連ページ)

このユニットではVerilogでの簡単な加算器(足し算)の書き方を学んだけど、実務や実機設計でただ「+」を記述しただけでも、深刻なタイミングエラーを引き起こしてしまうことがあるんだ。その原因と確かめ方は、サイト内の次のページで扱っているよ🐾