組み合わせ回路を理解する

組み合わせ回路の種類と特徴を一通り理解しておきましょう。このページ以降のユニットでは、ここの内容は既知のものとして扱います。

もふねこ

「組み合わせ回路」って難しそうな名前だけど、要するに『入力が決まれば出力がパッと決まる回路』のことだよ🐾
足し算する回路(加算器)や、信号を選ぶ回路(セレクタ)が代表例!

1. 全加算回路(1ビット加算)

最も基本的な組み合わせ回路のひとつが、1ビット全加算回路(Full Adder)です。

  • 入力: A(1ビット)、B(1ビット)、CIN(下位ビットからの桁上がり)
  • 出力: Q(和)、COUT(上位ビットへの桁上がり)
💡
用語 桁上がりのことを Carry(キャリー) と呼びます。CIN = Carry In(桁上がり入力)、COUT = Carry Out(桁上がり出力)。

全加算回路の真理値表

ABCINCOUTQ計算
000000+0+0 = 0 → 00
001010+0+1 = 1 → 01
010010+1+0 = 1 → 01
011100+1+1 = 2 → 10
100011+0+0 = 1 → 01
101101+0+1 = 2 → 10
110101+1+0 = 2 → 10
111111+1+1 = 3 → 11

論理式の導出

COUTが1になる条件(4行)をORでつなぐ:

COUT = Ā・B・CIN + A・B̄・CIN + A・B・C̄IN + A・B・CIN

Qが1になる条件(4行)をORでつなぐ:

Q = Ā・B̄・CIN + Ā・B・C̄IN + A・B̄・C̄IN + A・B・CIN

2. 論理圧縮

論理圧縮とは、ブール代数の法則を使って論理式をできるだけ簡単な形に書き換え、回路規模を小さくすることです。

COUTの論理圧縮手順

ステップ式使用した法則
元の式Ā・B・CIN + A・B̄・CIN + A・B・C̄IN + A・B・CIN—
①Ā・B・CIN + A・B̄・CIN + A・B・(C̄IN + CIN)分配則
②Ā・B・CIN + A・B̄・CIN + A・B補元則(X+X̄=1)
③CIN・(Ā・B + A・B̄) + A・B分配則
④(完成)COUT = A・B + CIN・(A⊕B)XOR定義
✅
論理圧縮の効果 圧縮前の4つの積項(AND × 4)が、2つの積項(AND × 2 + XOR × 1)に削減されます。回路規模が小さくなり、遅延も改善されます。
もふねこ

「え、何がどう変わったの?」って思ったよね🐾
ポイントは③→④のところ! Ā・B + A・B̄ は実は A⊕B(XOR)の定義そのもの なんだ。
この「圧縮テクニック」は自分でやる必要はなくて、論理合成ツールが全自動でやってくれるから安心してね!今は『こうやって式が減るんだな〜』くらいでOKだよ!

3. 4ビット加算回路(リップルキャリー型)

1ビット全加算回路を4つ並べ、隣の回路のCOUT→CINを接続したものがリップルキャリー型4ビット加算回路です。

  • FA0が最下位ビット(LSB)、FA3が最上位ビット(MSB)
  • 下位ビットの演算が終わらないと上位ビットの演算を開始できない

計算例:2 + 3 = 5

加算器A(2進数)B(2進数)CINCOUTQ
FA0(LSB)01001
FA111010
FA200101
FA3(MSB)00000

結果:COUT=0, Q=0101(2進数)= 5(10進数)✓

リップルキャリー型の遅延

段数が増えると桁上げの経路が長くなる、という関係を見るための計算例です。1段あたりの遅延を仮に2nsと置いて掛け算しているだけで、実際のデバイスで測った値ではありません。本当の遅延は、対象デバイス・合成結果・配置配線で決まります。

1段2nsと仮定した場合の計算例(測定値ではありません)
ビット数1ビット加算器遅延合計遅延
4ビット2ns / 段8ns
8ビット2ns / 段16ns
16ビット2ns / 段32ns
⚠️
課題 リップルキャリー型は構造がシンプルですが、桁上げが下位から順に伝わるため、ビット数が増えると桁上げの経路が長くなります。何ns遅くなるかは、合成してタイミング解析で確かめる必要があります。
もふねこ

桁数が増えると遅延しちゃうリップルキャリー型の弱点を克服したのが、次の『ルックアヘッド型』だよ🐾
これは面接や試験でもよく聞かれるから、なんとなく違いを知っておくとカッコいいよ!

4. キャリールックアヘッド型加算回路

遅延の原因であるCOUT生成部分を分離し、下位ビットの入力信号A・Bから直接CINを生成する回路がキャリールックアヘッド型です。

  • 各ビットのCINはキャリー生成回路が並列に計算
  • 上位ビットほどキャリー生成回路の入力が増え、回路規模は大きくなる

4ビット:遅延の比較

こちらも仮の値を置いた計算例です。桁上げを並列に作ると、上位桁が下位桁の完了を待たずに済む、という構造の違いを見るためのものです。

1段2ns、キャリー生成を入力数に応じた仮の値と置いた計算例(測定値ではありません)
加算器キャリー生成遅延加算器遅延合計
FA00ns(CIN=0固定)2.0ns2.0ns
FA10.5ns(3入力)2.0ns2.5ns
FA20.6ns(5入力)2.0ns2.6ns
FA3(MSB)0.7ns(7入力)2.0ns2.7ns

🔵 リップルキャリー型

  • 上の仮定での4ビット最大遅延:8ns
  • 構造がシンプル
  • 桁上げが下位から順に伝わるため、ビット数が増えると経路が長くなる

🟢 キャリールックアヘッド型

  • 上の仮定での4ビット最大遅延:2.7ns
  • 桁上げを並列に作るぶん、桁数が増えても経路が伸びにくい
  • そのかわり入力数と配線が増える。どちらが速いかは、同じデバイス・同じ制約で合成して比べる
⚠️
この2つの表の数値について どちらも「1段2ns」のように仮の値を置いて掛け算した計算例で、実際のデバイスで測った値ではありません。FPGAの + は専用のキャリー資源へ対応付けられることがあり、手書きの先読みが必ず速いとは限りません。機能が同じかどうかはC3の実習で全入力を突き合わせて確かめられますが、速さと面積は論理合成とタイミング解析の話です。

5. セレクタ(マルチプレクサ)

セレクタとは、N本の入力から1本を選択して出力する回路です。マルチプレクサ(MUX)とも呼びます。

2to1セレクタの動作

入力2本(D0・D1)から選択信号SELで1本を選んで出力Qに出す回路です。

SEL出力Q動作
0D0SEL=0のとき、D0がQに出力される
1D1SEL=1のとき、D1がQに出力される

論理式

Q = S̄EL・D0 + SEL・D1

SEL=0のとき S̄EL=1 なので D0 が有効。SEL=1のとき SEL=1 なので D1 が有効。

もふねこ

セレクタは、いわば「信号の切り替えスイッチ」だよ🐾
CPUの中では「計算結果Aと計算結果B、どっちをレジスタに書き込む?」みたいに、データの通り道を選ぶ場面で必ず登場する超・常連回路なんだ!

4to1セレクタへの拡張

入力が4本(D0〜D3)になると、どれを選ぶかを伝えるために選択信号は2ビット(SEL[1:0])必要になります。

SEL[1:0]出力Q
00D0
01D1
10D2
11D3

一般に、入力がN本のセレクタには log2N ビット(切り上げ)の選択信号が必要です(8to1なら3ビット、16to1なら4ビット)。

セレクタは実務でも最頻出の回路

データバスの切り替え、演算結果の選択、ステートマシンの出力選択など、実際の設計ではセレクタが至るところに登場します。Verilogではif文・case文・条件演算子(?:)のどれでも記述でき、書き方は回路実験1「ゲート回路とセレクタを書く」で実際に手を動かして学びます。

6. エンコーダとデコーダ

🔵 エンコーダ(符号化回路)

  • 入力データを規則に基づいて変換
  • 出力ビット数 < 入力ビット数
  • 例:キーボード・電卓のキー入力

🟢 デコーダ(復号化回路)

  • 符号化データを元の形式に変換
  • 出力ビット数 > 入力ビット数
  • 例:7セグメントLED表示回路

実例:数字ボタン → 7セグメントLED 表示「5」

① エンコーダ(ボタン入力→4ビット2進数)

「5」のボタンが押される → 内部で4ビット2進数に符号化

押したボタン4ビット2進数出力(上位→下位)10進数
000000
100011
200102
300113
401004
501015
601106
701117
810008
910019

② デコーダ(4ビット2進数→7セグメント出力)

入力 0101(5)を受け取り、7セグメントの各セグメントをON/OFF制御します。

入力abcdefg表示
0101(5)1011011「5」

セグメントb・eが消灯(0)、それ以外が点灯(1)→ 「5」 が表示されます。

✅
7セグメントの構造 7セグメントLEDはa〜gの7本のセグメントで構成されています。入力1でそのセグメントが発光します。
もふねこ

加算器、セレクタ、デコーダ…これらはこれからVerilogを書くときの「レゴブロック」みたいなものだよ🐾
次はいよいよ『順序回路(時間を記憶する回路)』に進もう!

実習で確かめる、つまずきの補足

記憶の有無と、未使用入力の仕様

組合せ回路は現在の入力だけで出力が決まる回路、順序回路は過去の状態も使う回路だよ。always @* と書くだけで組合せ回路になる保証はない。出力に代入しない経路があれば、シミュレーションでも前の値が残り、合成でラッチが推論される場合があるんだ。

4ビットのBCD入力を0〜9だけで使うなら、10〜15の扱いを仕様に書こう。「消灯にする」「エラーを出す」「到達しないことを上位で保証する」は違う約束だよ。代入を省略することはDon't Careの指定ではない。出力に x を書いて最適化の自由度を与える場合も、その入力で安全動作を要求できなくなる点を理解して使おう。

コードが短いことと回路が小さいことも別だよ。同じ機能・ビット幅・制約・デバイスで合成結果を比べ、LUT、FF、メモリ、遅延を確認する。使わない入力の条件を正確に伝えることは役立つけれど、面積が必ず減るとは限らないんだ。

ただの計算を always @(posedge clk) で書くと、式が合っていても出力が1クロック遅れるよ。フリップフロップが1段入るぶん、同じサイクルで結果を使う側とは歩調がずれるんだ。組合せ回路のつもりなら always @* か assign、わざと遅らせてパイプラインにするならFFと、どちらの意図かをコードと仕様の両方で決めておこう。このずれはシミュレーションの波形にそのまま現れるから、期待値は「何サイクル後の出力と比べるか」まで決めて確かめてね。歩調の確認方法はT1のカウンタ実習が参考になるよ。

📌 まとめ

  • 全加算回路は A・B・CINの3入力から Q(和)とCOUT(桁上がり)を出力する
  • 論理圧縮とはブール代数の法則を使って論理式を簡略化し、回路規模を小さくすること
  • リップルキャリー型加算回路の遅延は「1ビット加算器遅延 × ビット数」で線形に増大する
  • キャリールックアヘッド型はCINを並列生成することで遅延を大幅に削減できる
  • セレクタ(マルチプレクサ)はN本の入力から1本を選択する回路。別名MUX
  • エンコーダは符号化回路(入力ビット数 > 出力ビット数)
  • デコーダは復号化回路(入力ビット数 < 出力ビット数)
  • 演算回路の実現方法は複数あり、方式によって速度や回路規模が異なる

🐾 もふねこの実話つまずきコラム

このページで学んだ組み合わせ回路は、if文やcase文の書き忘れで「意図しないラッチ」を生んでしまう事故と直結しているよ。実際にどんなトラブルが起きるのか、実験ログと応用実験であわせて確かめてみてね!

🐾 もふねこの現場FAQ

Q. 組み合わせ回路を書いていたら「意図しないラッチが出た」と言われました。シミュレーションは通っているのに…

A. 「状態を保持する記述」をしてしまっている可能性が高いよ🐾

就職した卒業生からも、よく同じ相談が来るんだ。「シミュレーションは完璧なのに、論理合成したら意図しないラッチが出ていて…実機だとたまにフリーズする…」って。実はこれ、組み合わせ回路のルールを破ってしまった典型的な事故パターンなんだ。

組み合わせ回路は「入力が来たらすぐに出力が決まる(状態を持たない)」回路だけど、if文やcase文で全ての条件(elseやdefault)を書き忘れると、論理合成ツールが勝手に「状態を維持するための記憶素子(ラッチ)」を作ってしまうんだよ。

ここで大事なのは、シミュレーションを通ったことが「保持が起きない」証明ではないということ。代入されない経路に入ると、シミュレーションでも前の値が残るんだ。通ってしまったのは、その経路に入る入力をテストベンチで試していなかったから。実際に前の値が残る様子はC2の実習で見られるよ。

詳しくは、実験ログ2: Latch地獄から脱出した3日間 で解説しているから、実機を壊す前に必ず読んでみてね!