关于verilog:浮点乘法的硬件实现
用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后序如果要应用或援用本文代码,请保留本作者信息。 ...