pub const FP16_ADD_V: &str = r#"module fp16_add(input [15:0] a, input [15:0] b_in, input sub, output reg [15:0] y);
localparam [15:0] QNAN = 16'h7E00;
reg [15:0] b;
reg sa, sb;
reg [4:0] ea, eb;
reg [9:0] ma, mb;
reg azero,bzero,ainf,binf,anan,bnan,asub,bsub;
reg [5:0] xa, xb;
reg ha, hb;
reg [10:0] siga, sigb, sig_big, sig_small, final_sig;
reg [11:0] exp_l, shamt, lead;
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 [11:0] rounded;
reg guard, roundb, sticky, lsb, round_up;
function [15:0] pack_sub16(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 [11:0] rr;
begin
rshift = 12'd1 - bexp;
if (wlead >= 12'd13) begin
win = wsum >> (wlead - 12'd13);
if (|(wsum & ((128'd1 << (wlead - 12'd13)) - 128'd1))) win[0] = 1'b1;
end else begin
win = wsum << (12'd13 - 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[13:3]} + (up2 ? 12'd1 : 12'd0);
if (rr[10]) pack_sub16 = {sgn, 5'd1, rr[9:0]};
else pack_sub16 = {sgn, 5'd0, rr[9:0]};
end
endfunction
always @(*) begin
b = sub ? {~b_in[15], b_in[14:0]} : b_in;
sa = a[15]; sb = b[15];
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);
asub = (ea==5'd0) && (ma!=10'd0); bsub = (eb==5'd0) && (mb!=10'd0);
xa = asub ? 6'd1 : {1'b0, ea};
xb = bsub ? 6'd1 : {1'b0, eb};
ha = (ea!=5'd0); hb = (eb!=5'd0);
siga = {ha, ma}; sigb = {hb, mb};
y = 16'd0;
exp_l=12'd0; shamt=12'd0; sig_big=11'd0; sig_small=11'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=12'd0; final_sig=11'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,5'h1F,10'd0} : QNAN;
else if (ainf) y = {sa,5'h1F,10'd0};
else if (binf) y = {sb,5'h1F,10'd0};
else if (azero && bzero) y = (sa==sb) ? {sa,15'd0} : 16'd0;
else if (azero) y = b;
else if (bzero) y = a;
else begin
if (xa > xb || (xa == xb && siga >= sigb)) begin
exp_l={6'd0,xa}; sig_big=siga; sgn_big=sa; sig_small=sigb; sgn_small=sb; shamt={6'd0,(xa-xb)};
end else begin
exp_l={6'd0,xb}; sig_big=sigb; sgn_big=sb; sig_small=siga; sgn_small=sa; shamt={6'd0,(xb-xa)};
end
op_is_sub = (sgn_big != sgn_small);
res_sign = sgn_big;
big_ext = {53'd0, sig_big, 64'd0};
if (shamt >= 12'd128) begin small_ext = 128'd0; small_ext[0] = |sig_small; end
else begin
small_ext = ({53'd0, sig_small, 64'd0}) >> shamt;
if (shamt != 12'd0 && |(({53'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 = 16'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({6'd0, exp_l[5:0]}) + $signed({3'd0, lead[8:0]}) - 12'sd74;
if (lead >= 12'd13) begin
norm_sig = sum_ext >> (lead - 12'd13);
if (|(sum_ext & ((128'd1 << (lead - 12'd13)) - 128'd1))) norm_sig[0] = 1'b1;
end else norm_sig = sum_ext << (12'd13 - 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[13:3]} + (round_up ? 12'd1 : 12'd0);
if (rounded[11]) begin final_sig = rounded[11:1]; norm_exp = norm_exp + 12'sd1; end
else final_sig = rounded[10:0];
if (norm_exp >= 12'sd31) y = {res_sign, 5'h1F, 10'd0};
else if (norm_exp <= 12'sd0) y = pack_sub16(res_sign, sum_ext, lead, norm_exp);
else y = {res_sign, norm_exp[4:0], final_sig[9:0]};
end
end
end
endmodule
"#;Expand description
The synthesizable combinational IEEE-754 f16 (binary16) adder — the f32 adder narrowed to 5-bit exponent,
10-bit mantissa, bias 15 (window 128-bit, LSB0=64, leading-ref=74, normalize-target=13). Proven bit-exact
to the f16_add reference under iverilog; instantiated once per lane by the packed F16×4 tile.