Verilogで加算回路を書く

(1)ここで学ぶ内容

もふねこ

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

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

目標

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

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

修了判定

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

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

4ビット加算回路

graph LR subgraph 4ビット加算回路 ADD[adder] end A[a
4bit] -->|4| ADD B[b
4bit] -->|4| ADD ADD -->|4| Q[q
4bit] style ADD fill:#e3f2fd,stroke:#1976d2,stroke-width:2px;
// 加算演算子による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ビット加算回路

graph LR subgraph 4ビット加算回路 ADD[adder] end A[a
4bit] -->|4| ADD B[b
4bit] -->|4| ADD ADD -->|4| Q[q
4bit] style ADD fill:#e3f2fd,stroke:#1976d2,stroke-width:2px;
graph TD a0[a 0] --> add0[add0
fulladd] b0[b 0] --> add0 add0 --> q0[q 0] a1[a 1] --> add1[add1
fulladd] b1[b 1] --> add1 add1 --> q1[q 1] a2[a 2] --> add2[add2
fulladd] b2[b 2] --> add2 add2 --> q2[q 2] a3[a 3] --> add3[add3
fulladd] b3[b 3] --> add3 add3 --> q3[q 3] cin[CIN 0] -.->|COUT0| add0 add0 -.->|COUT1| add1 add1 -.->|COUT2| add2 add2 -.->|COUT3| add3 add3 -.->|COUT4| cout[開放] style add0 fill:#e8f5e9,stroke:#388e3c,stroke-width:2px; style add1 fill:#e8f5e9,stroke:#388e3c,stroke-width:2px; style add2 fill:#e8f5e9,stroke:#388e3c,stroke-width:2px; style add3 fill:#e8f5e9,stroke:#388e3c,stroke-width:2px;

(4)フルアダーの動作

フルアダー

graph LR A[入力 A] --> ADD[フルアダー] B[入力 B] --> ADD CIN[入力 CIN] --> ADD ADD --> Q[出力 Q] ADD --> COUT[出力 COUT] style ADD fill:#fff3e0,stroke:#f57c00,stroke-width:2px;

動 作

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

真理値表

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

(5)フルアダーの記述

フルアダー

graph LR A[入力 A] --> ADD[フルアダー] B[入力 B] --> ADD CIN[入力 CIN] --> ADD ADD --> Q[出力 Q] ADD --> COUT[出力 COUT] style ADD fill:#fff3e0,stroke:#f57c00,stroke-width:2px;
graph LR A[A] --> XOR1{{XOR}} B[B] --> XOR1 XOR1 --> XOR2{{XOR}} CIN[CIN] --> XOR2 XOR2 --> Q[Q] A --> AND1{{AND}} B --> AND1 B --> AND2{{AND}} CIN --> AND2 CIN --> AND3{{AND}} A --> AND3 AND1 --> OR1{{OR}} AND2 --> OR1 AND3 --> OR1 OR1 --> COUT[COUT] style XOR1 fill:#e3f2fd,stroke:#1976d2; style XOR2 fill:#e3f2fd,stroke:#1976d2; style AND1 fill:#e8f5e9,stroke:#388e3c; style AND2 fill:#e8f5e9,stroke:#388e3c; style AND3 fill:#e8f5e9,stroke:#388e3c; style OR1 fill:#fff3e0,stroke:#f57c00;
演算子は 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

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

4ビット加算回路

graph LR subgraph 4ビット加算回路 ADD[adder] end A[a
4bit] -->|4| ADD B[b
4bit] -->|4| ADD ADD -->|4| Q[q
4bit] style ADD fill:#e3f2fd,stroke:#1976d2,stroke-width:2px;
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)

graph LR subgraph SUBTRACTモジュール SUB[減算回路] end X[X
16bit] -->|16| SUB Y[Y
16bit] -->|16| SUB SUB -->|16| OUT[SUB
16bit] style SUB fill:#ffebee,stroke:#d32f2f,stroke-width:2px;
module SUBTRACT (X,Y,SUB);

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

assign          SUB = X - Y;

endmodule
🌸
たいへん
よく
できました