Skip to main content

FP32_MUL_V

Constant FP32_MUL_V 

Source
pub const FP32_MUL_V: &str = r#"module fp32_mul(input [31:0] a, input [31:0] b, output reg [31:0] y);
  localparam [31:0] QNAN = 32'h7FC00000;
  reg sa, sb, rs;
  reg [7:0] ea, eb;
  reg [22:0] ma, mb;
  reg azero,bzero,ainf,binf,anan,bnan,ha,hb;
  reg [23:0] siga, sigb, sa_sh, sb_sh;
  reg [4:0] lza, lzb;
  reg [47:0] prod, norm;
  reg signed [11:0] exp_sum, e, fe, bexp;
  reg [26:0] mant;
  reg g, r, s, l, up;
  reg [24:0] rnd, rr;
  reg [23:0] fsig;
  reg [11:0] rsh;
  reg [63:0] wide;
  reg g2, r2, s2, l2, up2;

  function [4:0] clz24(input [23:0] v);
    integer j; reg dn;
    begin clz24 = 5'd24; dn = 1'b0;
      for (j = 23; j >= 0; j = j - 1) if (v[j] && !dn) begin clz24 = 5'd23 - j[4:0]; dn = 1'b1; end
    end
  endfunction

  always @(*) begin
    sa = a[31]; sb = b[31]; rs = sa ^ sb;
    ea = a[30:23]; eb = b[30:23];
    ma = a[22:0];  mb = b[22:0];
    azero=(ea==8'd0)&&(ma==23'd0); bzero=(eb==8'd0)&&(mb==23'd0);
    ainf =(ea==8'hFF)&&(ma==23'd0); binf =(eb==8'hFF)&&(mb==23'd0);
    anan =(ea==8'hFF)&&(ma!=23'd0); bnan =(eb==8'hFF)&&(mb!=23'd0);
    ha=(ea!=8'd0); hb=(eb!=8'd0);
    siga={ha,ma}; sigb={hb,mb};
    y=32'd0;
    lza=5'd0; lzb=5'd0; sa_sh=24'd0; sb_sh=24'd0; prod=48'd0; norm=48'd0;
    exp_sum=12'sd0; e=12'sd0; fe=12'sd0; bexp=12'sd0; mant=27'd0; rnd=25'd0; rr=25'd0;
    fsig=24'd0; rsh=12'd0; wide=64'd0; g=0;r=0;s=0;l=0;up=0;g2=0;r2=0;s2=0;l2=0;up2=0;

    if (anan || bnan) y = QNAN;
    else if ((ainf && bzero) || (binf && azero)) y = QNAN;
    else if (ainf || binf) y = {rs, 8'hFF, 23'd0};
    else if (azero || bzero) y = {rs, 31'd0};
    else begin
      lza = clz24(siga); lzb = clz24(sigb);
      exp_sum = (ea!=8'd0 ? $signed({4'd0,ea})-12'sd127 : -12'sd126)
              + (eb!=8'd0 ? $signed({4'd0,eb})-12'sd127 : -12'sd126)
              - $signed({7'd0,lza}) - $signed({7'd0,lzb});
      sa_sh = (siga << lza); sb_sh = (sigb << lzb);
      prod = sa_sh * sb_sh;
      if (prod[47]) begin norm = prod; e = exp_sum + 12'sd1; end
      else          begin norm = prod << 1; e = exp_sum; end

      if (e < -12'sd126) begin
        wide = ({16'd0, norm}) >> 12'd21;
        if (|(({16'd0, norm}) & ((64'd1 << 12'd21) - 64'd1))) wide[0] = 1'b1;
        rsh = (-12'sd126) - e;
        if (rsh >= 12'd64) begin s2 = |wide; wide = 64'd0; wide[0] = s2; end
        else if (rsh != 12'd0) begin
          if (|(wide & ((64'd1 << rsh) - 64'd1))) begin wide = wide >> rsh; wide[0] = 1'b1; end
          else wide = wide >> rsh;
        end
        g2=wide[2]; r2=wide[1]; s2=wide[0]; l2=wide[3];
        up2 = g2 & (r2 | s2 | l2);
        rr = {1'b0, wide[26:3]} + (up2 ? 25'd1 : 25'd0);
        if (rr[23]) y = {rs, 8'd1, rr[22:0]};
        else        y = {rs, 8'd0, rr[22:0]};
      end else begin
        mant = {norm[47:24], norm[23], norm[22], (|norm[21:0])};
        g=mant[2]; r=mant[1]; s=mant[0]; l=mant[3];
        up = g & (r | s | l);
        rnd = {1'b0, mant[26:3]} + (up ? 25'd1 : 25'd0);
        if (rnd[24]) begin fsig = rnd[24:1]; fe = e + 12'sd1; end
        else         begin fsig = rnd[23:0]; fe = e; end
        if (fe > 12'sd127) y = {rs, 8'hFF, 23'd0};
        else if (fe < -12'sd126) y = {rs, 8'd1, fsig[22:0]};
        else begin bexp = fe + 12'sd127; y = {rs, bexp[7:0], fsig[22:0]}; end
      end
    end
  end
endmodule
"#;
Expand description

The synthesizable combinational IEEE-754 f32 multiplier — a faithful port of the proven f64 fp_mul: pre-normalize each significand (leading 1 to bit 23), multiply (24×24=48-bit, leading at 46/47), normalize the leading 1 to bit 47, round-to-nearest-ties-even, and pack (overflow→Inf, underflow→subnormal, rounded once from the EXACT product to avoid double-rounding). Proven bit-exact to Rust f32 under iverilog.