論理回路のおさらいです。今回は、半加算器と全加算器について。
半加算器
A | B | S | C |
0 | 0 | 0 | 0 |
0 | 1 | 1 | 0 |
1 | 0 | 1 | 0 |
1 | 1 | 0 | 1 |
半加算器は、1 ビットの加算を行なう回路だけど、下位からの桁上げ入力がない最下桁の加算器。
図 1 が、半加算器の真理値表。A、B が加算する 2 つの値、S がその和で、C は桁上がり出力です。
桁上がりってのは、ようするにオーバーフロー。1 ビットの計算しかできない半加算器なのに、和が 2 ビットになっちゃったよ、という出力です。
真理値表から、主加法標準形で求めた論理式が、次のとおり。
S = A⋅B + A⋅B = A ⨁ B C = A⋅B
真理値表をじっと眺めればわかりますね、S は XOR、C は AND だってこと。
論理式からつくった回路が、図 2。
むずかしい回路ではないです。A と B のどちらか一方が 1 のとき 1 を出力するのが XOR、A と B がともに 1 のとき、つまり AND したのが桁上がり。
でも、これだけでは意味わからん。1 と 1 足して 2 になってるような、なってないような加算器、って何なん? この意味不明な回路が、加算器の理解を妨げてる、と思う俺 (;´Д`)
全加算器
Ci | A | B | S | Co |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 1 | 0 |
0 | 1 | 0 | 1 | 0 |
0 | 1 | 1 | 0 | 1 |
1 | 0 | 0 | 1 | 0 |
1 | 0 | 1 | 0 | 1 |
1 | 1 | 0 | 0 | 1 |
1 | 1 | 1 | 1 | 1 |
全加算器も、1 ビットの加算を行なう回路。
半加算器との違いは、下位からの桁上げを受け取れるってこと。つまり、最下桁の半加算器から出力された桁上がりを受けて、2 ビット目の計算をする回路です。
図 3 が真理値表。A、B が加算する値、Ci は下位からの桁上げ、S が和、Co が上位への桁上げ。
だから、Co がさらに上位の全加算器に送られて、1 桁ずつ順番に加算していく仕組みなんだ。ちょっと姿がみえてきたね。
主加法標準形で論理式を求めます。まずは、和の出力 S。Ci も加算されるところがミソです。
S = Ci⋅A⋅B + Ci⋅A⋅B + Ci⋅A⋅B + Ci⋅A⋅B = Ci ( A⋅B + A⋅B ) + Ci ( A⋅B + A⋅B ) = Ci ( A ⨁ B ) + Ci ( A ⨁ B ) = Ci ⨁ ( A ⨁ B )
次に、桁上げ出力 Co。
Co = Ci⋅A⋅B + Ci⋅A⋅B + Ci⋅A⋅B + Ci⋅A⋅B = A⋅B ( Ci + Ci ) + Ci ( A⋅B + A⋅B ) = A⋅B + Ci ( A ⨁ B )
こちらも、真理値表をじっと眺めればみえてくる。S は XOR と XNOR、Co は AND と OR だね。Ci によって切り換わる。
論理式からつくった回路が、図 4 です。
全加算器をググると、半加算器 2 つと OR ゲートの組み合わせ回路がでてくるんだけど、俺、あれ、どうも理解しづらいんです。結果が加算になるのは、わかる。でも、いまいちストンと落ちない。
真理値表、論理式ときて、そこから回路をつくると、おお、そうか、わかった。そーゆーことか。
まぁ、理解のしかたなんて人それぞれなので、お好みでどうぞ。
VerilogHDL でシミュレーションしてみた
たいした回路でもないので、ちゃちゃっと組み立ててみてもいいのですが、VerilogHDL を勉強したので、せっかくですから、シミュレーションしてみましょう。
今回のシミュレーションでは、論理ゲートで組んだ全加算器の回路の動作が、真理値表から求めた論理式と一致するかどうか、を検証します。
回路記述
- module FULL_ADDER(
- input wire A, B, CI,
- output wire S, CO
- );
- parameter test_type = 0;
まずは、まいどのモジュール名と入出力信号の宣言。パラメータとして test_type を設定していますが、これについては後述。
- generate
- if(0 == test_type) begin
- // logic circuit
- wire Y1, Y2, Y4;
- xor U1(Y1, A, B);
- and U2(Y2, A, B);
- xor U3(S, Y1, CI);
- and U4(Y4, Y1, CI);
- or U5(CO, Y4, Y2);
- end
お初の、「generate」による回路の切り換え。test_type が 0 のとき、この回路記述が選択されます。パラメータの設定は、test_type=0 ですので、こちらがデフォルトになります。
Y1、Y2、Y4 は、それぞれゲート U1、U2、U4 の出力信号です。
13~17 行目は「プリミティブゲート接続」です。プリミティブゲートとは、VerilogHDL にあらかじめ組み込まれているゲート回路。モジュールを定義しなくても、インスタンスとして利用できます。それぞれのゲートの入出力を、回路図にしたがって定義しています。
- else if(1 == test_type) begin
- // boolean expression
- assign S = CI ^ (A ^ B);
- assign CO = A & B | CI & (A ^ B);
- end
- endgenerate
- endmodule
次は、test_type=1 の場合。test_type は、テストベンチのパラメータ割り当てで変更します。パラメータ割り当てを 1 にすることで、こちらの回路に切り換わる、というしかけ。
21~22 行で、全加算器の論理式を記述しています。
テストベンチ
- module FULL_ADDER_TEST;
- reg A, B, CI;
- wire S, CO;
- parameter STEP = 1000;
- FULL_ADDER #(0) FULL_ADDER(A, B, CI, S, CO);
- initial begin
- A = 0; B = 0; CI = 0;
- #STEP B = 1;
- #STEP A = 1; B = 0;
- #STEP B = 1;
- #STEP CI = 1; A = 0; B = 0;
- #STEP B = 1;
- #STEP A = 1; B = 0;
- #STEP B = 1;
- #STEP $finish;
- end
- initial begin
- $dumpfile("fullAdder_test.vcd");
- $dumpvars(0, FULL_ADDER_TEST);
- end
- endmodule
テストベンチは、基本的に変わってはいません。
が、8 行目。回路のインスタンス化のパラメータ割り当てで 0 を指定しています。論理ゲートを組み合わせた回路でシミュレーションします。なお、test_type のデフォルトが 0 ですから、指定しなければ組み合わせ回路でのシミュレーションになります。
パラメータ割り当てを「1」とすると、論理式によるシミュレーションに切り換わります。
シミュレーション結果
test_type = 1 論理式によるシミュレーション
図 5 が、論理式によるシミュレーション結果です。
真理値表どおりの出力がえられています。論理式に間違いはないようです。
test_type = 0 論理回路によるシミュレーション
図 6 は、論理ゲートで組み立てた回路によるシミュレーション結果です。
こちらも、真理値表どおりの結果がえられています。組み合わせ回路にも間違いはないようです。
論理式によるシミュレーションとの違いは、内部信号の Y1、Y2、Y4 の波形が表示されているところです。
ということで、論理ゲートで組んだ全加算器の回路の動作と、真理値表から求めた論理式は、一致することが確認できました。
後記
さてさて、しかし 1 ビットを加算してみてもつまんないですね。せめて 4 ビットぐらいないと計算したって感じにならない。
ということで、次回は、4 ビット加算器をつくってみましょう。半加算器だ全加算器だなんてややこしいこと言ってないで、ぜんぶ全加算器でつくりゃいいでしょ? 1 桁目は Ci=0 にしときゃいいんだから。