computer system foundationCSF 2026
演習 B / 8-BIT SUBTRACTOR

8ビット減算器

引き算専用の回路は作らない。演習Aで書いた加算器を、少しだけ変えて引き算に使う。

難易度 ★★☆ 所要 15–25分 前提 演習A
01

引き算を、足し算で行う

コンピュータの中に「引き算器」という独立した回路はない。減算 a − ba + (−b) と読み替えて、加算器で計算する。 2進数で −b を表すのに使うのが 2の補数(全ビット反転して 1 を足す)である。

b0000_0011= 3
~b1111_1100全ビット反転(1の補数)
~b + 11111_1101= −3 の2の補数表現
a − ba + (~b) + 1→ cin に 1 を渡すだけ
演習Aの加算器から変えるのは 2箇所だけである。b を ~b にする、cin を 1 にする。 それだけで同じ回路が引き算をする。これがハードウェア設計で「部品を使い回す」ということである。
02

ボロー(桁借り)の意味

符号なし8ビットでは、a < b のとき結果が負になり、8ビットでは正しく表せない。 このことを知らせる1ビットの信号が borrow(桁借り)である。 9ビット目に桁上がりが出なかったときが、ちょうど桁借りが起きたときにあたる。

abdiff = a − bborrow意味
10370正常
0000ゼロ
3102491桁借り(−7 が 249 に見える)
25512540正常
03

作るモジュールの仕様

module
subtractor8
input
a [7:0] — 被減数 / b [7:0] — 減数
output
diff [7:0] — 差 / borrow — 桁借りが起きたら 1
04

書いて、その場でチェック

演習Aと同じ形で書ける。9ビットで受けてから分ける方法でも、9ビットの計算をそのまま {borrow, diff} で受ける方法でも構わない。

module subtractor8 (
    input  [7:0] a,
    input  [7:0] b,
    output [7:0] diff,
    output       borrow
);
endmodule
Ctrl / ⌘ + Enter でも実行
答え合わせ(自分で試してから開く)

2の補数を自分で組み立てる書き方(教科書どおり)と、引き算演算子に任せる書き方。どちらも同じ回路になる。

// 書き方 1:加算器の使い回しがはっきり見える形
wire [8:0] result;
assign result = {1'b0, a} + {1'b0, ~b} + 1'b1;
assign diff   = result[7:0];
assign borrow = ~result[8];  // 桁上がりが出なかった = 桁借り
// 書き方 2:9ビットの引き算をそのまま2つに分ける
assign {borrow, diff} = a - b;

書き方2で borrow が正しく出るのは、9ビットで計算すると a < b のとき 9ビット目が 1 になるからである。 書き方1では逆に、9ビット目が 0 のときが桁借りなので ~ が要る。同じ現象を別の側から見ている。

05

考えてみよう

  1. a=5, b=200 のとき diff と borrow はどうなりますか。手で計算してから、チェッカーの結果と照らし合わせてみましょう。
  2. 演習Aの加算器とこの減算器を並べると、回路として何が同じで何が違いますか。
  3. assign diff = a - b; と書くだけでも動く。それでも 2の補数を自分で書いてみる意味は何でしょうか。
  4. 足し算と引き算を1つのモジュールで切り替えるには、どんな入力を足せばよいでしょうか。(次の演習C・Dにつながる)
発展:本物のツール(EDA Playground)でも動かす 任意

実際のシミュレータで波形も見たい人は、EDA Playground に設計を貼り付けて実行できる(Gmail アカウントが必要)。 手順は 使い方ガイド へ。

TESTBENCH(左パネル)
module tb_subtractor8;
    reg  [7:0] a, b;
    wire [7:0] diff;
    wire       borrow;

    subtractor8 uut (.a(a), .b(b), .diff(diff), .borrow(borrow));

    initial begin
        $dumpfile("dump.vcd");
        $dumpvars(0, tb_subtractor8);
        $monitor("a=%0d b=%0d | diff=%0d borrow=%0d", a, b, diff, borrow);

        a = 8'd10;  b = 8'd3;   #10;
        a = 8'd0;   b = 8'd0;   #10;
        a = 8'd3;   b = 8'd10;  #10;
        a = 8'd255; b = 8'd1;   #10;
        a = 8'd100; b = 8'd100; #10;

        $display("--- テスト完了 ---");
        $finish;
    end
endmodule