見出し画像

16bit浮動小数点乗算回路を設計してみる(設計修正版)

背景

以前にUpした16bit浮動小数点乗算回路では、ごく稀な条件で結果がCPUの結果と一致しない。深夜に設計を追い込んでみた。

修正

コード

/*
NISHIHARU
*/
// FP16乗算関数の定義
function [15:0] fp16_multiply;
    input [15:0] a; // FP16 input A
    input [15:0] b; // FP16 input B
    reg sign_a, sign_b, sign_result;
    reg [4:0] exp_a, exp_b;
    reg [10:0] frac_a, frac_b;
    reg zero_a, zero_b;
    reg inf_a, inf_b, nan_a, nan_b;
    integer exp_sum; // Changed to signed integer
    reg [21:0] frac_mult;
    reg [10:0] frac_adjusted;
    reg [7:0]  exp_adjusted; // Changed to signed integer
    reg guard_bit, round_bit, sticky_bit;
    reg [10:0] frac_final;
    integer shift_amount;
    integer i;

begin
    // Decomposition of inputs
    sign_a = a[15];
    exp_a = a[14:10];
    frac_a = (exp_a == 0) ? {1'b0, a[9:0]} : {1'b1, a[9:0]};
    zero_a = (exp_a == 0) && (a[9:0] == 0);

    sign_b = b[15];
    exp_b = b[14:10];
    frac_b = (exp_b == 0) ? {1'b0, b[9:0]} : {1'b1, b[9:0]};
    zero_b = (exp_b == 0) && (b[9:0] == 0);

    // Calculation of sign
    sign_result = sign_a ^ sign_b;

    // Handling special cases
    inf_a = (exp_a == 5'h1F) && (a[9:0] == 0);
    inf_b = (exp_b == 5'h1F) && (b[9:0] == 0);
    nan_a = (exp_a == 5'h1F) && (a[9:0] != 0);
    nan_b = (exp_b == 5'h1F) && (b[9:0] != 0);

    if (nan_a || nan_b || (inf_a && zero_b) || (zero_a && inf_b)) begin
        // Return Quiet NaN
        fp16_multiply = {1'b0, 5'h1F, 10'h200};
    end else if (inf_a || inf_b) begin
        // Handling infinity
        fp16_multiply = {sign_result, 5'h1F, 10'h0};
    end else if (zero_a || zero_b) begin
        // Handling zero
        fp16_multiply = {sign_result, 15'b0};
    end else begin
        // Normal calculation
        // Calculation of exponent (as signed integer)
        exp_sum = exp_a + exp_b - 15;

        // Multiplication of significands
        frac_mult = frac_a * frac_b; // 11-bit x 11-bit = 22-bit

        // Normalization
        if (frac_mult[21] == 1) begin
            // If the most significant bit is 1
            frac_adjusted = frac_mult[21:11];
            exp_adjusted = exp_sum + 1;
            guard_bit = frac_mult[10];
            round_bit = frac_mult[9];
            sticky_bit = |frac_mult[8:0];
        end else begin
            // If the most significant bit is 0
            frac_adjusted = frac_mult[20:10];
            exp_adjusted = exp_sum;
            guard_bit = frac_mult[9];
            round_bit = frac_mult[8];
            sticky_bit = |frac_mult[7:0];
        end

        // Rounding (round to nearest even)
        if ((guard_bit && (round_bit | sticky_bit)) || (guard_bit && ~round_bit && ~sticky_bit && frac_adjusted[0])) begin
            frac_final = frac_adjusted + 1;
            //if (frac_final == 11'b10000000000) begin
            if (frac_adjusted == 11'h7FF) begin
                // Handle carry
                frac_final = 11'b0000000000;
                exp_adjusted = exp_adjusted + 1;
            end else begin
                exp_adjusted = exp_adjusted;
            end
        end else begin
            frac_final = frac_adjusted;
        end

        // Handling overflow and underflow
        if (exp_adjusted >= 31) begin
            // Overflow: infinity
            fp16_multiply = {sign_result, 5'h1F, 10'h0};
        end else if (exp_adjusted <= 0) begin
            // Underflow: subnormal or zero
            shift_amount = 1 - exp_adjusted;
            if (shift_amount < 11) begin
                // Right shift of significand
                frac_final = frac_final >> shift_amount;
                fp16_multiply = {sign_result, 5'b00000, frac_final[9:0]};
            end else begin
                // Zero
                fp16_multiply = {sign_result, 15'b0};
            end
        end else begin
            // Normalized number
            fp16_multiply = {sign_result, exp_adjusted[4:0], frac_final[9:0]};
        end
    end
end
endfunction

module fp16_multiplier (
    input [15:0] a,  // 入力A (FP16)
    input [15:0] b,  // 入力B (FP16)
    output [15:0] result  // 出力結果 (FP16)
);
    assign result = fp16_multiply(a,b);

endmodule

ここを修正

//if (frac_final == 11'b10000000000) begin
if (frac_adjusted == 11'h7FF) begin

結果

Mac miniで実行

3万パターンで計算した結果、誤差以上となる場合は皆無になりました!
(ChatGPTくんでは修正不可能でした。自分で修正しました。)

設計データはここ

xxx_1.vはデバッグ用のファイル。

所感

AIはまだまだ役に立たない時もある。

いいなと思ったら応援しよう!