pub const FP32_ADD_V: &str = r#"module fp32_add(input [31:0] a, input [31:0] b_in, input sub, output reg [31:0] y);
localparam [31:0] QNAN = 32'h7FC00000;
reg [31:0] b;
reg sa, sb;
reg [7:0] ea, eb;
reg [22:0] ma, mb;
reg azero,bzero,ainf,binf,anan,bnan,asub,bsub;
reg [8:0] xa, xb;
reg ha, hb;
reg [23:0] siga, sigb;
reg [11:0] exp_l, shamt, lead;
reg [23:0] sig_big, sig_small;
reg sgn_big, sgn_small, res_sign, op_is_sub;
reg [127:0] big_ext, small_ext, sum_ext, norm_sig;
integer i;
reg signed [11:0] norm_exp;
reg [24:0] rounded;
reg guard, roundb, sticky, lsb, round_up;
reg [23:0] final_sig;
function [31:0] pack_sub32(input sgn, input [127:0] wsum, input [11:0] wlead, input signed [11:0] bexp);
reg [11:0] rshift; reg [127:0] win; reg g2,r2,s2,l2,up2; reg [24:0] rr;
begin
rshift = 12'd1 - bexp;
if (wlead >= 12'd26) begin
win = wsum >> (wlead - 12'd26);
if (|(wsum & ((128'd1 << (wlead - 12'd26)) - 128'd1))) win[0] = 1'b1;
end else begin
win = wsum << (12'd26 - wlead);
end
if (rshift >= 12'd128) begin s2 = |win; win = 128'd0; win[0] = s2; end
else if (rshift != 12'd0) begin
if (|(win & ((128'd1 << rshift) - 128'd1))) begin win = win >> rshift; win[0] = 1'b1; end
else win = win >> rshift;
end
g2 = win[2]; r2 = win[1]; s2 = win[0]; l2 = win[3];
up2 = g2 & (r2 | s2 | l2);
rr = {1'b0, win[26:3]} + (up2 ? 25'd1 : 25'd0);
if (rr[23]) pack_sub32 = {sgn, 8'd1, rr[22:0]};
else pack_sub32 = {sgn, 8'd0, rr[22:0]};
end
endfunction
always @(*) begin
b = sub ? {~b_in[31], b_in[30:0]} : b_in;
sa = a[31]; sb = b[31];
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);
asub = (ea==8'd0) && (ma!=23'd0); bsub = (eb==8'd0) && (mb!=23'd0);
xa = asub ? 9'd1 : {1'b0, ea};
xb = bsub ? 9'd1 : {1'b0, eb};
ha = (ea!=8'd0); hb = (eb!=8'd0);
siga = {ha, ma}; sigb = {hb, mb};
y = 32'd0;
// pre-set datapath regs (avoid latches in the combinational always)
exp_l=12'd0; shamt=12'd0; sig_big=24'd0; sig_small=24'd0; sgn_big=1'b0; sgn_small=1'b0;
op_is_sub=1'b0; res_sign=1'b0; big_ext=128'd0; small_ext=128'd0; sum_ext=128'd0; lead=12'd0;
norm_exp=12'sd0; norm_sig=128'd0; rounded=25'd0; final_sig=24'd0;
guard=1'b0; roundb=1'b0; sticky=1'b0; lsb=1'b0; round_up=1'b0;
if (anan || bnan) y = QNAN;
else if (ainf && binf) y = (sa==sb) ? {sa,8'hFF,23'd0} : QNAN;
else if (ainf) y = {sa,8'hFF,23'd0};
else if (binf) y = {sb,8'hFF,23'd0};
else if (azero && bzero) y = (sa==sb) ? {sa,31'd0} : 32'd0;
else if (azero) y = b;
else if (bzero) y = a;
else begin
if (xa > xb || (xa == xb && siga >= sigb)) begin
exp_l={3'd0,xa}; sig_big=siga; sgn_big=sa; sig_small=sigb; sgn_small=sb; shamt={3'd0,(xa-xb)};
end else begin
exp_l={3'd0,xb}; sig_big=sigb; sgn_big=sb; sig_small=siga; sgn_small=sa; shamt={3'd0,(xb-xa)};
end
op_is_sub = (sgn_big != sgn_small);
res_sign = sgn_big;
big_ext = {40'd0, sig_big, 64'd0};
if (shamt >= 12'd128) begin small_ext = 128'd0; small_ext[0] = |sig_small; end
else begin
small_ext = ({40'd0, sig_small, 64'd0}) >> shamt;
if (shamt != 12'd0 && |(({40'd0, sig_small, 64'd0}) & ((128'd1 << shamt) - 128'd1))) small_ext[0] = 1'b1;
end
if (op_is_sub) sum_ext = big_ext - small_ext; else sum_ext = big_ext + small_ext;
if (sum_ext == 128'd0) y = 32'd0;
else begin
lead = 12'd0;
for (i = 127; i >= 0; i = i - 1) if (sum_ext[i] && lead == 12'd0) lead = i[11:0];
norm_exp = $signed({3'd0, exp_l[8:0]}) + $signed({3'd0, lead[8:0]}) - 12'sd87;
if (lead >= 12'd26) begin
norm_sig = sum_ext >> (lead - 12'd26);
if (|(sum_ext & ((128'd1 << (lead - 12'd26)) - 128'd1))) norm_sig[0] = 1'b1;
end else norm_sig = sum_ext << (12'd26 - lead);
guard=norm_sig[2]; roundb=norm_sig[1]; sticky=norm_sig[0]; lsb=norm_sig[3];
round_up = guard & (roundb | sticky | lsb);
rounded = {1'b0, norm_sig[26:3]} + (round_up ? 25'd1 : 25'd0);
if (rounded[24]) begin final_sig = rounded[24:1]; norm_exp = norm_exp + 12'sd1; end
else final_sig = rounded[23:0];
if (norm_exp >= 12'sd255) y = {res_sign, 8'hFF, 23'd0};
else if (norm_exp <= 12'sd0) y = pack_sub32(res_sign, sum_ext, lead, norm_exp);
else y = {res_sign, norm_exp[7:0], final_sig[22:0]};
end
end
end
endmodule
"#;Expand description
The synthesizable combinational IEEE-754 f32 adder — a faithful port of the PROVEN f64 fp_addsub
(benchmarks/silicon/fpu.v): align both significands in a wide 128-bit window (64 bits of alignment room,
so every bit survives to sticky), add/sub, leading-zero-count, normalize the leading 1 to bit 26 (24-bit
significand at [26:3], guard/round/sticky at [2:0]), round-to-nearest-ties-even, and pack (overflow→Inf,
underflow→subnormal via pack_sub32). sub=1 computes a-b. Proven bit-exact to Rust f32 under iverilog
by simd_float_rtl_lock. This module is instantiated once per lane by the packed F32×2 tile.