数値表現と高速算術回路のVerilog実装

1. 基礎的な数値表現

1.1 10進数と16進数の相互変換

10進整数を16進数に変換する方法は主に2つある。

  • 方法1:10進数を2進数に変換(除2取余法)し、その2進数を下位から4ビットずつ区切り、各グループを16進数に置き換える。
  • 方法2:10進数を直接16で割り続け、余りを下位から並べる(除16取余法)。

例:3010 → 1E16

1.2 原码・反码・補数表現

原码:最上位ビットが符号(0: 正、1: 負)、残りが絶対値。
8ビットの場合の範囲:−127 〜 +127

反码:正数は原码と同じ。負数は符号ビット以外を反転。
範囲は原码と同じ。

補数(2の補数):正数はそのまま。負数は原码の符号ビット以外を反転し、1を加算。
8ビットの場合の範囲:−128 〜 +127(ゼロの重複なし)

1.3 グレイコード

グレイコードは隣接する数値間で1ビットしか変化しない符号化方式であり、状態遷移時の誤動作を抑制できる。

変換規則:自然2進数 B[4:0] からグレイコード G[4:0] へは、
G[i] = B[i+1] ^ B[i](ただし B[5] = 0)で計算可能。

自然2進数5ビットグレイコード
0000000000
0000100001
0001000011
0001100010
0010000110
0010100111
0011000101
0011100100
0100001100
0100101101
0101001111
0101101110
0110001010
0110101011
0111001001
0111101000
1000011000
1000111001
1001011011
1001111010
1010011110
1010111111
1011011101
1011111100
1100010100
1100110101
1101010111
1101110110
1110010010
1110110011
1111010001
1111110000

1.4 IEEE 754 単精度浮動小数点数

32ビット形式:1ビット符号 + 8ビット指数部(バイアス127) + 23ビット仮数部(暗黙の1あり)。

表現範囲:約 ±1.2×10−38 〜 ±3.4×1038、有効桁数:約7桁(10進数)。

浮動小数点 vs 固定小数点

  • 浮動小数点:広いダイナミックレンジと高精度だが、演算回路が複雑。
  • 固定小数点:回路が単純で高速だが、範囲と精度に制限あり。

2. Verilogによる算術回路設計

2.1 ストップウォッチ回路

10 MHzクロック入力、クリア・スタート/ストップ制御付きの時分秒カウンタ(XX:XX:XX)。各桁は4ビットBCD出力。

設計方針:階層的カウンタモジュールと2状態(START/STOP)のFSMを組み合わせ、ゲーテッドクロックでカウント制御。

module bcd_counter (
    input clk,
    input rst_n,
    input clear,
    input [3:0] limit,
    output reg full,
    output reg [3:0] count
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            count <= 4'd0;
            full <= 1'b0;
        end else if (clear) begin
            count <= 4'd0;
            full <= 1'b0;
        end else if (count == limit) begin
            count <= 4'd0;
            full <= 1'b1;
        end else begin
            count <= count + 1;
            full <= 1'b0;
        end
    end
endmodule

module stopwatch_top (
    input clk, rst_n, clear, start_stop,
    output [3:0] hr_h, hr_l, min_h, min_l, sec_h, sec_l
);
    reg counting;
    wire clk_en = counting & clk;

    // 状態遷移
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) counting <= 1'b0;
        else if (clear) counting <= 1'b0;
        else if (start_stop) counting <= ~counting;
    end

    // カウンタチェーン(秒下位 → 秒上位 → 分下位 → ...)
    bcd_counter sec_low (.clk(clk_en), .limit(4'd9), .count(sec_l), /*...*/);
    bcd_counter sec_high(.clk(sec_low.full), .limit(4'd5), .count(sec_h), /*...*/);
    bcd_counter min_low (.clk(sec_high.full), .limit(4'd9), .count(min_l), /*...*/);
    bcd_counter min_high(.clk(min_low.full), .limit(4'd5), .count(min_h), /*...*/);
    bcd_counter hr_low  (.clk(min_high.full), .limit(4'd9), .count(hr_l), /*...*/);
    bcd_counter hr_high (.clk(hr_low.full), .limit(4'd9), .count(hr_h), /*...*/);
endmodule

2.2 超高速加算器(Carry-Lookahead)

16ビット符号付き整数の加算を17ビット出力で実現。キャリールックアヘッド構造により遅延を最小化。

設計:4ビットCLAブロック(Carry4)を5段階で階層化し、グループ伝搬/生成信号を再帰的に計算。

module cla4 (
    input [3:0] p, g,
    input cin,
    output P, G,
    output [2:0] carries
);
    assign P = &p;
    assign G = g[3] | (p[3]&g[2]) | (p[3]&p[2]&g[1]) | (p[3]&p[2]&p[1]&g[0]);
    assign carries[0] = g[0] | (p[0]&cin);
    assign carries[1] = g[1] | (p[1]&g[0]) | (p[1]&p[0]&cin);
    assign carries[2] = g[2] | (p[2]&g[1]) | (p[2]&p[1]&g[0]) | (p[2]&p[1]&p[0]&cin);
endmodule

module fast_adder_16 (
    input [15:0] a, b,
    output [16:0] sum
);
    wire [15:0] prop = a ^ b;
    wire [15:0] gen = a & b;
    wire [15:0] carry;

    assign carry[0] = 1'b0;
    cla4 stage0(.p(prop[3:0]), .g(gen[3:0]), .cin(carry[0]), .carries(carry[3:1]));
    cla4 stage1(.p(prop[7:4]), .g(gen[7:4]), .cin(carry[4]), .carries(carry[7:5]));
    cla4 stage2(.p(prop[11:8]), .g(gen[11:8]), .cin(carry[8]), .carries(carry[11:9]));
    cla4 stage3(.p(prop[15:12]), .g(gen[15:12]), .cin(carry[12]), .carries(carry[15:13]));
    cla4 top(.p({prop[15],prop[11],prop[7],prop[3]}), .g({gen[15],gen[11],gen[7],gen[3]}), 
             .cin(1'b0), .carries({carry[12],carry[8],carry[4]}));

    wire [15:0] s = prop ^ carry[15:0];
    wire ovf = (a[15] & b[15] & ~s[15]) | (~a[15] & ~b[15] & s[15]);
    assign sum = {ovf ? ~s[15] : s[15], s};
endmodule

2.3 高速乗算器(Booth符号化 + Wallaceツリー)

Radix-4 Booth符号化により部分積を8個生成し、Wallaceツリー(CSA階層)で効率的に加算。

Boothエンコーダは3ビット窓で −2, −1, 0, +1, +2 の係数を判定。部分積は符号拡張とシフトで生成。

module booth_encoder (
    input [2:0] bits,
    output is_neg, is_zero, is_one, is_two
);
    assign is_neg = bits[2];
    assign is_zero = (bits == 3'b000) || (bits == 3'b111);
    assign is_two = (bits == 3'b100) || (bits == 3'b011);
    assign is_one = !(is_zero || is_two);
endmodule

module partial_prod_gen (
    input [15:0] multiplicand,
    input is_neg, is_zero, is_one, is_two,
    output [31:0] product
);
    wire [31:0] base = is_zero ? 32'd0 :
                      is_one ? {{16{multiplicand[15]}}, multiplicand} :
                      {{15{multiplicand[15]}}, multiplicand, 1'b0};
    assign product = is_neg ? (~base + 1) : base;
endmodule

Wallaceツリーは複数段のCSA(キャリーセーブ加算器)で部分積を縮約し、最終段で通常加算器で合計。

2.4 バレルシフタ(循環シフト)

32ビット入力に対し、左/右循環シフトを5ビットシフト量で制御。ログベースアーキテクチャで高速化。

module barrel_shifter_32 (
    input [31:0] din,
    input dir,          // 0: 左, 1: 右
    input [4:0] shift,
    output [31:0] dout
);
    wire [31:0] stage0 = dir ? (shift[0] ? {din[0], din[31:1]} : din) :
                               (shift[0] ? {din[30:0], din[31]} : din);
    wire [31:0] stage1 = dir ? (shift[1] ? {stage0[1:0], stage0[31:2]} : stage0) :
                               (shift[1] ? {stage0[29:0], stage0[31:30]} : stage0);
    wire [31:0] stage2 = dir ? (shift[2] ? {stage1[3:0], stage1[31:4]} : stage1) :
                               (shift[2] ? {stage1[27:0], stage1[31:28]} : stage1);
    wire [31:0] stage3 = dir ? (shift[3] ? {stage2[7:0], stage2[31:8]} : stage2) :
                               (shift[3] ? {stage2[23:0], stage2[31:24]} : stage2);
    assign dout = dir ? (shift[4] ? {stage3[15:0], stage3[31:16]} : stage3) :
                        (shift[4] ? {stage3[15:0], stage3[31:16]} : stage3);
endmodule

タグ: Verilog 数字回路 算術回路 超高速加算器 Booth乗算

5月17日 18:08 投稿