用verilog实现浮点的乘法

总结

本实现采纳的是面积换工夫, 一拍出后果。如果为了后端实现,能够多拍出后果。在这个算法的根底上其实能够做些批改达到。外围逻辑本算法曾经实现。

代码

在代码中曾经增加简略的正文,置信浏览过IEEE754规范的人很容易看懂。对于后果的取舍,依照S家的规范共六种取舍,同时会输入status表明后果的精准度。

//// Created by         :  Harris Zhu (zhuzhzh@163.com)// Filename           :  HZ_fp_mult.v// Author             :  Harris Zhu// Created On         :  2020-08-14 11:36:49// Last Modified      :  2020-08-14 11:36:49// Update Count       :  1// Tags               :   // Description        :  z = a * b; // Conclusion         :  // License            :  GPL//                      //=======================================================================module HZ_fp_mult (a, b, rnd, z, status);  parameter sig_width = 23;        parameter exp_width = 8;         parameter ieee_compliance = 0;   input  [exp_width + sig_width:0] a;  input  [exp_width + sig_width:0] b;  input  [2:0] rnd;  output [exp_width + sig_width:0] z;  output [7:0] status;localparam [exp_width-1:0] ebias = ((1<<(exp_width-1)) - 1);  localparam totalbit= (1 + sig_width + exp_width);localparam einf = ((1<<(exp_width)) - 1);localparam emax = (einf - 1);localparam emin = 1;localparam sexp_width = (exp_width + 1);localparam frac_width = (sig_width + 1);localparam spwidth = (2 * sig_width + 2);localparam log_swidth = (sig_width+1>256)?9:                        (sig_width+1>128)?8:                        (sig_width+1>64)?7:                        (sig_width+1>32)?6:                        (sig_width+1>16)?5:                        (sig_width+1>8)?4:                        (sig_width+1>4)?3:                        (sig_width+1>2)?2:1;       localparam log_spwidth = (spwidth+1>256)?9:                        (spwidth+1>128)?8:                        (spwidth+1>64)?7:                        (spwidth+1>32)?6:                        (spwidth+1>16)?5:                        (spwidth+1>8)?4:                        (spwidth+1>4)?3:                        (spwidth+1>2)?2:1;       function [9:0] oneindex(input [2*sig_width+1:0] data);    integer i;    reg found;begin    oneindex = 0;    found = 0;    for(i=0;i<=2*sig_width+1;i=i+1)    begin        if((found == 0) && (data[2*sig_width+1-i] == 1))        begin            oneindex = i+1;            found = 1;        end    endendendfunction//statusreg [6:0] status_reg = 0;// get sign, exp and sigreg sign ;reg [exp_width-1:0] aexp ;   // exponent of Areg [exp_width-1:0] bexp ;  // exponent of Breg [sexp_width-1:0] sign_aexp ;   // add 1 sign bitreg [sexp_width-1:0] sign_bexp ;  // add 1 sign bitreg [sig_width-1:0] asig;reg [sig_width-1:0] bsig;reg [frac_width-1:0] fracA;          // fraction of A, add 1 hidden bitreg [frac_width-1:0] fracB;            // fraction of B, add 1 hidden bit// exp calcreg signed [exp_width+1:0] sign_ext_zexp;reg signed [exp_width+1:0] z_exp_sh_full;reg [exp_width-1:0] z_exp_sh;// sig calcwire [2*sig_width+1:0] fracAxB;        //the production of fracA and fracBHZ_int_mult #(.A_width(sig_width+1), .B_width(sig_width+1)) u0 (fracA, fracB, fracAxB);reg [2*sig_width+1:0] normFracAxB;        //normalized fracAxBreg [log_spwidth:0]  lshift;                        // the index of highest 1 in fracAxB //oneindex #(.dwidth(2*sig_width+2), .iwidth(10)) u1 (fracAxB, lshift);reg [sig_width-1:0] z_sig;                //the significand of Z// statusreg isOf, isUf, isUUf;            //>maxnorm,  <minnorm, denormalize reg found =0;integer i;//NaN, inftreg isANan, isAInft;reg isBNan, isBInft;reg isAZero, isBZero;reg isADenorm, isBDenorm;reg isAExpInf, isBExpInf;reg isAExpZero, isBExpZero;reg isASigZero, isBSigZero;//Nan, Inftreg [exp_width-1:0] NanInft_Exp = {(exp_width){1'b1}};reg [sig_width-1:0] Nan_Sig =  {{(sig_width-1){1'b0}},1'b1};reg [sig_width-1:0] Inft_Sig = {(sig_width){1'b0}};always @(a or b or rnd or fracAxB)begin    status_reg = 7'b0;    sign = a[totalbit-1] ^ b[totalbit-1];    aexp = a[totalbit-2:sig_width];    bexp = b[totalbit-2:sig_width];        sign_aexp = {1'b0, aexp};    sign_bexp = {1'b0, bexp};    isAExpInf = (aexp == einf);    isBExpInf = (bexp == einf);    isAExpZero = (aexp == 0);    isBExpZero = (bexp == 0);    asig = a[sig_width-1:0];    bsig = b[sig_width-1:0];        isASigZero = (isAExpZero & isASigZero);    isBSigZero = (isBExpZero & isBSigZero);    isADenorm = (isAExpZero && (isASigZero == 0));    isBDenorm = (isBExpZero && (isBSigZero == 0));    isAZero = (a[totalbit-2:0] == 0);    isBZero = (b[totalbit-2:0] == 0);    isANan = (isAExpInf && (isASigZero == 0));    isBNan = (isBExpInf && (isBSigZero == 0));    isAInft = (isAExpInf && (isASigZero == 1));    isBInft = (isBExpInf && (isBSigZero == 1));    // parse out the fraction of A and B    if(isADenorm)        fracA = {1'b0,a[sig_width-1:0]};    else        fracA = {1'b1,a[sig_width-1:0]};    if(isBDenorm)        fracB = {1'b0,b[sig_width-1:0]};    else        fracB = {1'b1,b[sig_width-1:0]};    if(isANan || isBNan)    begin        if(ieee_compliance)        begin            status_reg[2] = 1'b1;    // Invalid            sign = 0;            z_sig = {{(sig_width-1){1'b0}}, 1'b1};            z_exp_sh = {exp_width{1'b1}};        end else begin            status_reg[1] = 1'b1;        //Infinity            z_sig = {sig_width{1'b0}};            z_exp_sh = {exp_width{1'b1}};        end    end else if((isAZero && isBInft)||(isBZero && isAInft))    begin        if(ieee_compliance)        begin            status_reg[2] = 1'b1;        //Invalid            sign = 0;            z_sig = {{(sig_width-1){1'b0}}, 1'b1};            z_exp_sh = {exp_width{1'b1}};        end else begin            status_reg[1] = 1'b1;        //Infinity            z_sig = {sig_width{1'b0}};            z_exp_sh = {exp_width{1'b1}};        end    end else if(isBInft || isAInft)    begin            status_reg[1] = 1'b1;        //Infinity            z_sig = {sig_width{1'b0}};            z_exp_sh = {exp_width{1'b1}};    end else if(isAZero || isBZero)    begin        status_reg[0] = 1'b1;        //Zero        z_sig = {sig_width{1'b0}};        z_exp_sh = {exp_width{1'b0}};    end else if((ieee_compliance ==0)&& (isADenorm || isBDenorm))    begin        status_reg[0] = 1'b1;        //Zero        z_sig = {sig_width{1'b0}};        z_exp_sh = {exp_width{1'b0}};    end else begin        status_reg[5] = 1'b1;            //Inexact//        fracAxB = fracA * fracB;      //put this multiply into dedicated module to use ALU        lshift = 0;        found = 0;        for(i=0; i<=2*sig_width+1;i=i+1)        begin            if((found == 0) && (fracAxB[2*sig_width+1-i] == 1))            begin                lshift = i+1;                found = 1;            end        end        if(isADenorm)            sign_aexp = 1;        if(isBDenorm)            sign_bexp = 1;        sign_ext_zexp = sign_aexp + sign_bexp -ebias;        normFracAxB = (fracAxB << lshift);        z_exp_sh_full = sign_ext_zexp + 2 - lshift;        isOf = (z_exp_sh_full > emax)? 1:0;        isUf = (z_exp_sh_full < emin)? 1:0;        if(ieee_compliance == 1)        begin            isUUf = (z_exp_sh_full <= 0)? 1:0;        end        // the result is denormal number        if(isUUf)        begin            if(sign_ext_zexp==0)            begin                normFracAxB = (fracAxB << 1);                z_exp_sh_full = 0;            end else begin                normFracAxB = (fracAxB >> (-1*sign_ext_zexp - 1));                z_exp_sh_full = 0;            end        end        // exp is bigger than emax        if(isOf)         begin            status_reg[4] = 1'b1;        //Huge            case(rnd)                // IEEE round to nearest (even)                3'b000:                begin                    z_exp_sh = einf;           //{exp_width{1'b1}};                    z_sig = {sig_width{1'b0}};                    status_reg[1] = 1'b1;        //Infinity                end                // IEEE round to zero                3'b001:                begin                    z_exp_sh = emax;                    z_sig = {sig_width{1'b1}};                end                // IEEE round to positive infinity                3'b010:                begin                    if(sign)                    begin                        z_exp_sh = emax;                        z_sig = {sig_width{1'b1}};                    end else begin                        z_exp_sh = einf;        // {exp_width{1'b1}};                        z_sig = {sig_width{1'b0}};                        status_reg[1] = 1'b1;        //Infinity                    end                end                // IEEE round to negative infinity                3'b011:                begin                    if(sign)                    begin                        z_exp_sh = einf;    // {exp_width{1'b1}};                        z_sig = {sig_width{1'b0}};                        status_reg[1] = 1'b1;        //Infinity                    end else begin                        z_exp_sh = emax;                        z_sig = {sig_width{1'b1}};                    end                end                // round to nearest up                3'b100:                begin                    z_exp_sh = einf;                    z_sig = {sig_width{1'b0}};                    status_reg[1] = 1'b1;        //Infinity                end                // round away from zero                3'b101:                begin                    z_exp_sh = einf;                    z_sig = {sig_width{1'b0}};                    status_reg[1] = 1'b1;        //infinity                end            endcase        end        // exp is smaller than emin        if(isUf)         begin            status_reg[3] = 1'b1;        //Tiny            if(ieee_compliance==0)            begin                case(rnd)                    // IEEE round to nearest (Even)                    3'b000:                    begin                        z_exp_sh = {exp_width{1'b0}};                        z_sig = {sig_width{1'b0}};                        status_reg[0] = 1'b1;        //Zero                    end                    // IEEE round to zero                    3'b001:                    begin                        z_exp_sh = {exp_width{1'b0}};                        z_sig = {sig_width{1'b0}};                        status_reg[0] = 1'b1;    //Zero                    end                    // IEEE round to positive infinity                    3'b010:                    begin                        if(sign)                        begin                            z_exp_sh = 0;                             z_sig = {sig_width{1'b0}};                            status_reg[0] = 1'b1;        //Zero                        end else begin                            z_exp_sh = emin;                            z_sig = {sig_width{1'b0}};                        end                    end                    // IEEE round to negative infinity                    3'b011:                    begin                        if(sign)                        begin                            z_exp_sh = emin;                                z_sig = {sig_width{1'b0}};                        end else begin                            z_exp_sh = 0;                            z_sig = {sig_width{1'b0}};                            status_reg[0] = 1'b1;        //Zero                        end                    end                    // round to nearest up                    3'b100:                    begin                        z_exp_sh = {exp_width{1'b0}};                        z_sig = {sig_width{1'b0}};                        status_reg[0] = 1'b1;        //Zero                    end                    // round away from zero                    3'b101:                    begin                            z_exp_sh = emin;                                z_sig = {sig_width{1'b0}};                    end                endcase            end        end        // rounding the fraction        if (!((isOf)||(isUf&&(ieee_compliance==0))))        begin            case(rnd)                // IEEE round to nearest(Even)                3'b000:                begin                    if(normFracAxB[sig_width+1:0] > {1'b1, {(sig_width+1){1'b0}}})                    begin                        z_sig = normFracAxB[2*sig_width+1:sig_width+2] + 1;                        if(z_sig == 0)                        begin                            z_exp_sh = z_exp_sh_full[exp_width-1:0] + 1;                        end else begin                            z_exp_sh = z_exp_sh_full[exp_width-1:0];                        end                    end else if(normFracAxB[sig_width+1:0] == {1'b1, {(sig_width+1){1'b0}}})                    begin                        if(normFracAxB[sig_width+2] == 1'b1)                        begin                            z_sig = normFracAxB[2*sig_width+1:sig_width+2] + 1;                            if(z_sig == 0)                            begin                                z_exp_sh = z_exp_sh_full[exp_width-1:0] + 1;                            end else begin                                z_exp_sh = z_exp_sh_full[exp_width-1:0];                            end                        end else begin                            z_sig = normFracAxB[2*sig_width+1:sig_width+2];                            z_exp_sh = z_exp_sh_full[exp_width-1:0];                        end                    end else begin                        z_sig = normFracAxB[2*sig_width+1:sig_width+2];                        z_exp_sh = z_exp_sh_full[exp_width-1:0];                    end                end                // IEEE round to zero                3'b001:                begin                    z_sig = normFracAxB[2*sig_width+1:sig_width+2];                    z_exp_sh = z_exp_sh_full[exp_width-1:0];                end                // IEEE round to positive infinity                3'b010:                begin                    if(sign == 1'b0)                    begin                        z_sig = normFracAxB[2*sig_width+1:sig_width+2] + 1;                        if(z_sig == 0)                        begin                            z_exp_sh = z_exp_sh_full[exp_width-1:0] + 1;                        end else begin                            z_exp_sh = z_exp_sh_full[exp_width-1:0] ;                        end                    end else begin                        z_sig = normFracAxB[2*sig_width+1:sig_width+2];                        z_exp_sh = z_exp_sh_full[exp_width-1:0];                    end                end                // IEEE round to negative infinity                3'b011:                begin                    if(sign == 1'b0)                    begin                        z_sig = normFracAxB[2*sig_width+1:sig_width+2];                        z_exp_sh = z_exp_sh_full[exp_width-1:0];                    end else begin                        z_sig = normFracAxB[2*sig_width+1:sig_width+2] + 1;                        if(z_sig == 0)                        begin                            z_exp_sh = z_exp_sh_full[exp_width-1:0] + 1;                        end else begin                            z_exp_sh = z_exp_sh_full[exp_width-1:0] ;                        end                    end                end                // round to nearest up                3'b100:                begin                    if(normFracAxB[sig_width+1:0] > {1'b1, {(sig_width+1){1'b0}}})                    begin                        z_sig = normFracAxB[2*sig_width+1:sig_width+2] + 1;                        if(z_sig == 0)                        begin                            z_exp_sh = z_exp_sh_full[exp_width-1:0] + 1;                        end else begin                            z_exp_sh = z_exp_sh_full[exp_width-1:0];                        end                    end else if(normFracAxB[sig_width+1:0] == {1'b1, {(sig_width+1){1'b0}}})                    begin                        if(sign == 1'b0)                        begin                            z_sig = normFracAxB[2*sig_width+1:sig_width+2] + 1;                            if(z_sig == 0)                            begin                                z_exp_sh = z_exp_sh_full[exp_width-1:0] + 1;                            end else begin                                z_exp_sh = z_exp_sh_full[exp_width-1:0];                            end                        end else begin                            z_sig=normFracAxB[2*sig_width+1:sig_width+2];                        end                    end else begin                        z_sig = normFracAxB[2*sig_width+1:sig_width+2];                        z_exp_sh = z_exp_sh_full[exp_width-1:0];                    end                end                // round away from zero                3'b101:                begin                    z_sig = normFracAxB[2*sig_width+1:sig_width+2] + 1;                    if(z_sig == 0)                    begin                        z_exp_sh = z_exp_sh_full[exp_width-1:0] + 1;                    end else begin                        z_exp_sh = z_exp_sh_full[exp_width-1:0] ;                    end                end                default:                begin                    z_sig = normFracAxB[2*sig_width+1:sig_width+2];                    z_exp_sh = z_exp_sh_full[exp_width-1:0];                end            endcase        end        if ((z_sig == 0) && (z_exp_sh == 0))        begin            status_reg[0] = 1;        //Zero        end    endendassign z = {sign, z_exp_sh, z_sig};assign status = status_reg;  endmodulemodule oneindex(data, index);parameter dwidth = 40;parameter iwidth = 10;input [dwidth-1:0] data;output [iwidth-1:0] index;reg [iwidth-1:0] index;integer i;reg found=0;always @(data)begin    index = 0;    found = 0;    for(i=0;i<=dwidth;i=i+1)    begin        if((found == 0) && (data[dwidth-1-i] == 1))        begin            index = i+1;            found = 1;        end    endendendmodulemodule HZ_int_mult(A, B, Z);parameter A_width = 32;parameter B_width = 8;input   [A_width-1:0]   A;input   [B_width-1:0]   B;output [A_width+B_width-1:0] Z;assign Z = A * B;endmodule

后序

如果要应用或援用本文代码,请保留本作者信息。