Skip to main content

FP16_MUL_V

Constant FP16_MUL_V 

Source
pub const FP16_MUL_V: &str = r#"module fp16_mul(input [15:0] a, input [15:0] b, output reg [15:0] y);
  localparam [15:0] QNAN = 16'h7E00;
  reg sa, sb, rs;
  reg [4:0] ea, eb;
  reg [9:0] ma, mb;
  reg azero,bzero,ainf,binf,anan,bnan,ha,hb;
  reg [10:0] siga, sigb, sa_sh, sb_sh, fsig;
  reg [4:0] lza, lzb;
  reg [21:0] prod, norm;
  reg signed [11:0] exp_sum, e, fe, bexp;
  reg [13:0] mant;
  reg g, r, s, l, up;
  reg [11:0] rnd, rr, rsh;
  reg [63:0] wide;
  reg g2, r2, s2, l2, up2;

  function [4:0] clz11(input [10:0] v);
    integer j; reg dn;
    begin clz11 = 5'd11; dn = 1'b0;
      for (j = 10; j >= 0; j = j - 1) if (v[j] && !dn) begin clz11 = 5'd10 - j[4:0]; dn = 1'b1; end
    end
  endfunction

  always @(*) begin
    sa = a[15]; sb = b[15]; rs = sa ^ sb;
    ea = a[14:10]; eb = b[14:10];
    ma = a[9:0];   mb = b[9:0];
    azero=(ea==5'd0)&&(ma==10'd0); bzero=(eb==5'd0)&&(mb==10'd0);
    ainf =(ea==5'h1F)&&(ma==10'd0); binf =(eb==5'h1F)&&(mb==10'd0);
    anan =(ea==5'h1F)&&(ma!=10'd0); bnan =(eb==5'h1F)&&(mb!=10'd0);
    ha=(ea!=5'd0); hb=(eb!=5'd0);
    siga={ha,ma}; sigb={hb,mb};
    y=16'd0;
    lza=5'd0; lzb=5'd0; sa_sh=11'd0; sb_sh=11'd0; prod=22'd0; norm=22'd0;
    exp_sum=12'sd0; e=12'sd0; fe=12'sd0; bexp=12'sd0; mant=14'd0; rnd=12'd0; rr=12'd0;
    fsig=11'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, 5'h1F, 10'd0};
    else if (azero || bzero) y = {rs, 15'd0};
    else begin
      lza = clz11(siga); lzb = clz11(sigb);
      exp_sum = (ea!=5'd0 ? $signed({7'd0,ea})-12'sd15 : -12'sd14)
              + (eb!=5'd0 ? $signed({7'd0,eb})-12'sd15 : -12'sd14)
              - $signed({7'd0,lza}) - $signed({7'd0,lzb});
      sa_sh = (siga << lza); sb_sh = (sigb << lzb);
      prod = sa_sh * sb_sh;
      if (prod[21]) begin norm = prod; e = exp_sum + 12'sd1; end
      else          begin norm = prod << 1; e = exp_sum; end

      if (e < -12'sd14) begin
        wide = ({42'd0, norm}) >> 12'd8;
        if (|(({42'd0, norm}) & ((64'd1 << 12'd8) - 64'd1))) wide[0] = 1'b1;
        rsh = (-12'sd14) - 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[13:3]} + (up2 ? 12'd1 : 12'd0);
        if (rr[10]) y = {rs, 5'd1, rr[9:0]};
        else        y = {rs, 5'd0, rr[9:0]};
      end else begin
        mant = {norm[21:11], norm[10], norm[9], (|norm[8:0])};
        g=mant[2]; r=mant[1]; s=mant[0]; l=mant[3];
        up = g & (r | s | l);
        rnd = {1'b0, mant[13:3]} + (up ? 12'd1 : 12'd0);
        if (rnd[11]) begin fsig = rnd[11:1]; fe = e + 12'sd1; end
        else         begin fsig = rnd[10:0]; fe = e; end
        if (fe > 12'sd15) y = {rs, 5'h1F, 10'd0};
        else if (fe < -12'sd14) y = {rs, 5'd1, fsig[9:0]};
        else begin bexp = fe + 12'sd15; y = {rs, bexp[4:0], fsig[9:0]}; end
      end
    end
  end
endmodule
"#;
Expand description

The synthesizable combinational IEEE-754 f16 multiplier — the f32 multiplier narrowed to binary16 (11-bit significand product = 22 bits, leading at 20/21). Proven bit-exact to f16_mul under iverilog.