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.