Float計算回路のVerilog-HDL実装について -その1


Float計算回路のVerilog実装

~ FPGA に載せたい ~
オレオレ実装なので間違っていても知りません

浮動小数点数の説明から
正の加算まで

目的

floatの勉強
float32のハードウェア実装

浮動小数点数について

単精度小数点数について
Wikipedia

左から
・符号
・指数部(8bit)
・仮数部(23bit)
となる.

値の計算方法はざっくり

\text{value} = 仮数部 \times 2^{指数部}

と表される.

Wikipediaでは

{\displaystyle {\text{value}}=(-1)^{\text{sign}}\left(1+\sum _{i=1}^{23}\ b_{-i}2^{-i}\right)\times 2^{e-127}}

と記述されている.

仮数部の表記法 (例:7.25)

7 = 111 \\
0.25 = 0.01\\
7.25 = 111.01

先にも記したように指数部によっていくらでも
記述方法ができてしまう.
したがって, 最上位ビットを1とし、
以下が小数となるように決定する.

7.25 = 111.01 = 1.1101 \times 2^2

上記の最上位が1という条件から最上位は省略する.

7.25 = 1101 \times 2^2

指数部の表記法 (例:7.25)

上記より

7.25 = 1101 \times 2^2

2という情報を入れる.

指数部は 8bit であるため、
アンサインドなら 0 ~ 255
サインドなら -128 ~ 127
の値を取ることができる.

浮動小数点数では
アンサインドなサインド表記となる.
0 を 8'b0111_1111 と表記する.
2 は 8'b1000_0000 である.
つまり、127のバイアス値を加えた値として表記する.
たとえば、-42 は

127 + (-42) = 85 = 8'\text{b}0101\_0101

となる.

特別な表記(0)

0 は 指数部を -128とするようである.
つまり指数部は 8'b0 となる.

浮動小数点数の加算

オレオレ浮動小数点加算回路のタイミングは下の図のように設計した.
0加算を行わない, 正の数のみ.

以下詳細

1. 値の比較

数値比較を行い, 大きい方を vb(value big), 小さい方を vs(value small)へ格納する.

//TIM1
reg [31:0] vb;
reg [31:0] vs;

always @(posedge clk) begin
    if (v2[30:23] < v1[30:23]) begin
        vb <= v1;
        vs <= v2;
    end else begin
        vb <= v2;
        vs <= v1;
    end
end  

2. 指数部距離の計算

シフト量を把握するために, 各数値の指数部距離を計算する.
他はパイプライン時に潰されないように保護する.

//TIM2
reg [7:0] dexp;
reg [7:0] vexp;
reg [22:0] vb2;
reg [22:0] vs2;

always @(posedge clk) begin
    dexp <= vb[30:23] - vs[30:23];
    vexp <= vb[30:23];

    vb2 <= vb[22:0];
    vs2 <= vs[22:0];                                                                                     
end

3. 値のシフト, 加算の準備

加算のために1を付け加えたり, 値をシフトして桁を合わせておく.
この際小さい方の数値はシフト時に切り捨てる(正しいかどうかは知らない).

//TIM3
reg [7:0] vexp2;
reg [24:0] vb3;
reg [24:0] vs3;

always @(posedge clk) begin
    vexp2 <= vexp;

    vb3 <= {2'b1, vb2};
    vs3 <= {1'b0, vssf({1'b1, vs2}, dexp)};
end

シフト方法は頭いい方法がわからなかったので適当に作りました.

//Value Small Shift Function
function [23:0] vssf(input [23:0] v, input [7:0] num);
begin
    case(num)
    8'd0: vssf = v;
    8'd1: vssf = {1'b0, v[23:1]};
    8'd2: vssf = {2'b0, v[23:2]};
    8'd3: vssf = {3'b0, v[23:3]};
    8'd4: vssf = {4'b0, v[23:4]};

    8'd5: vssf = {5'b0, v[23:5]};
    8'd6: vssf = {6'b0, v[23:6]};
    8'd7: vssf = {7'b0, v[23:7]};
    8'd8: vssf = {8'b0, v[23:8]};
    8'd9: vssf = {9'b0, v[23:9]};

    8'd10: vssf = {10'b0, v[23:10]};
    8'd11: vssf = {11'b0, v[23:11]};
    8'd12: vssf = {12'b0, v[23:12]};
    8'd13: vssf = {13'b0, v[23:13]};
    8'd14: vssf = {14'b0, v[23:14]};

    8'd15: vssf = {15'b0, v[23:15]};
    8'd16: vssf = {16'b0, v[23:16]};
    8'd17: vssf = {17'b0, v[23:17]};
    8'd18: vssf = {18'b0, v[23:18]};
    8'd19: vssf = {19'b0, v[23:19]};

    8'd20: vssf = {20'b0, v[23:20]};
    8'd21: vssf = {21'b0, v[23:21]};
    8'd22: vssf = {22'b0, v[23:22]};
    8'd23: vssf = {23'b0, v[23]};
    default: vssf = 24'b0;
endcase
end
endfunction

4. 加算

桁は合わせているため,加算を行うのみ.

//TIM4
reg [7:0] vexp3;
reg [24:0] r;

always @(posedge clk) begin
    vexp3 <= vexp2;

    r <= vb3 + vs3;                                                                                
end

5. 型の生成

桁上がりを考慮してfloat型を生成する.

 //TIM5
reg [31:0] res;

always @(posedge clk) begin
    res[31] <= 1'b0;

    if (r[24]) begin
        res[30:23] <= vexp3 + 8'b1;
        res[22:0] <= r[23:1];
    end else begin
        res[30:23] <= vexp3;
        res[22:0] <= r[22:0];
    end
end

できたコード

github
シミュレーションではエラーが出なかったことまで確認.