概念 #CODE #加算器 #2の補数 #論理回路 #コンピュータアーキテクチャ #算術回路 📚 CODEコンピュータのからくり

算術回路:加算器・2の補数・減算の実装

論理ゲートで足し算・引き算を実装する方法。半加算器・全加算器・リプルキャリーアダー・2の補数による減算まで。CODE第2版 Ch.14-16。

論理ゲートで足し算をする

前のdocで論理ゲート(AND・OR・XOR)が揃った。これで加算回路を作れる。

1ビット + 1ビット の場合:

二進数の1桁加算:

  0 + 0 = 0    桁上がり(キャリー)なし
  0 + 1 = 1    キャリーなし
  1 + 0 = 1    キャリーなし
  1 + 1 = 10   → 下の桁: 0、キャリー: 1

一般化すると:
  結果の1桁目 = A XOR B
  キャリー    = A AND B

半加算器(Half Adder)

キャリーの入力を考慮しない、最も単純な加算回路。

【半加算器の回路】

  A ─┬──[XOR]──→ 和(Sum)

  B ─┤──[AND]──→ キャリーアウト(Cout)

真理値表:
  A  B │ Sum  Cout
  0  0 │  0    0
  0  1 │  1    0
  1  0 │  1    0
  1  1 │  0    1

記号:
  ┌──────┐
A─┤  HA  ├─ Sum
B─┤      ├─ Cout
  └──────┘

「半加算器」という名前は、キャリーインを処理できない(半分の機能)ことに由来。


全加算器(Full Adder)

前の桁からのキャリー(Cin)も取り込める完全な加算回路。

【全加算器の回路(半加算器2個 + OR1個)】

  A ──┐
      ├─[HA]─ S1, C1 ─┐
  B ──┘                 ├─[HA]─ Sum
                Cin ───┘        │
                                C2
  C1 ─────────────────────────[OR]─ Cout

実装のポイント:
  1つ目のHA:A と B を加算 → S1, C1
  2つ目のHA:S1 と Cin を加算 → Sum, C2
  最終キャリー:C1 OR C2

真理値表:
  A  B  Cin │ Sum  Cout
  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

記号:
  ┌──────┐
A─┤      ├─ Sum
B─┤  FA  ├─ Cout
C─┤      │
  └──────┘

リプルキャリーアダー(Ripple Carry Adder)

全加算器を縦に並べると、複数ビットの加算ができる。4ビット版の例:

【4ビット加算器】

         A3  B3    A2  B2    A1  B1    A0  B0
          │   │     │   │     │   │     │   │
  Cin ─→[FA3]─→C─[FA2]─→C─[FA1]─→C─[FA0]─→ Cout
          │           │           │           │
         S3          S2          S1          S0

          ↑ キャリーが右から左へ「波のように伝播」= Ripple
          S3 S2 S1 S0 = 結果(4ビット)

例:0101(5) + 0110(6) を計算
  FA0: 1+0+0=1  Sum=1, Cout=0
  FA1: 0+1+0=1  Sum=1, Cout=0
  FA2: 1+1+0=0  Sum=0, Cout=1
  FA3: 0+0+1=1  Sum=1, Cout=0
  結果: 1011 = 11  ✓

Ripple(波及) という名前は、キャリーが下位ビットから上位ビットへ順番に伝わる様子から。8ビットなら FA0→FA7 と順番にキャリーが決まるため、ビット数が増えると遅くなる。


オーバーフロー

加算結果がビット数を超えるとき。

【8ビット符号なし整数のオーバーフロー】

  11111111 (255)
+ 00000001 (  1)
─────────────
 100000000 → 9ビット!

  8ビットに収まらない → キャリーアウトが 1 になる
  8ビット部分だけ見ると: 00000000 = 0(間違った答え)

検出方法:
  符号なし → Cout(キャリーアウト)が 1 になったらオーバーフロー
  符号あり → 正+正=負 または 負+負=正 になったらオーバーフロー

2の補数:減算を加算で実現するトリック

CPUは基本的に加算回路しか持たない。減算は「負の数を足す」ことで実現する。

2の補数の作り方

任意の数 N の「2の補数」= 2^n - N (n はビット数)

8ビットで 5 の2の補数:
  2^8 - 5 = 256 - 5 = 251 = 11111011(2)

もっと簡単な計算方法:
  ①  すべてのビットを反転(NOT)
  ②  1を加える

5 = 00000101
① 反転: 11111010
② +1:  11111011  ← これが -5 の2の補数表現

確認:
  5  + (-5) = 00000101 + 11111011
            = 100000000
            = 0 (下位8ビット) + Cout=1 → 正しく 0 になる

符号付き整数の範囲

8ビット符号付き整数(2の補数):
  00000000 =   0
  00000001 =   1
  ...
  01111111 = 127   ← 最大値
  10000000 = -128  ← 最小値(最上位ビットが符号ビット)
  10000001 = -127
  ...
  11111110 =  -2
  11111111 =  -1

表現範囲:-128 〜 +127(合計256通り)

n ビット符号付き整数の範囲:
  最小: -2^(n-1)
  最大:  2^(n-1) - 1

  8ビット:  -128 〜  127
  16ビット: -32768 〜  32767
  32ビット: 約-21億 〜 約21億
  64ビット: 約-9.2京 〜 約9.2京

減算の実装

A - B = A + (-B) = A + (Bの2の補数)

回路の実装:
  1. B のすべてのビットを XOR-1 で反転(NOT)
  2. 加算器の Cin に 1 を入力
  → Bの反転 + 1 = 2の補数 が自動的に計算される

  ┌────────────────────────┐
  │  A3 A2 A1 A0           │
  │                        │
  │  B3 B2 B1 B0 → [NOT] → B̄3 B̄2 B̄1 B̄0
  │                                     │
  │  Cin=1 ─────────────────────────────┘
  │                                     ↓
  │         [4ビット加算器(Cin付き)]
  └────────────────────────┘

ADD/SUB の切り替えは「Cinに何を入れるか」と「Bを反転するか」だけ。

ALU への伏線

加算器と2の補数の仕組みを組み合わせると、加算・減算が一つの回路でできる。

さらに AND・OR・NOT・XOR 演算も追加すると「算術論理演算装置(ALU)」になる。

ALU の入力:
  A     ← オペランド1
  B     ← オペランド2
  操作コード(何をするか):
    000 = ADD
    001 = SUB
    010 = AND
    011 = OR
    100 = XOR
    101 = NOT A
    ...

ALU の出力:
  結果
  ゼロフラグ(結果が0かどうか)
  キャリーフラグ(桁あふれ)
  オーバーフローフラグ
  負フラグ(符号ビット)

これが CPU の核心部品。次の章で記憶(フリップフロップ・RAM)を学んだあと、CPU の組み立てに進む。

出典: https://www.amazon.co.jp/dp/4296080245