`timescale 1ns/1ps // Reference implementation: IEEE 754 FP16 adder (combinational) // Handles: normal numbers, zero, infinity, NaN propagation. // Rounding: truncate (round toward zero). module fp16_adder ( input wire [15:0] a, input wire [15:0] b, output wire [15:0] result ); // --- Field extraction --- wire sa = a[15], sb = b[15]; wire [4:0] ea = a[14:10], eb = b[14:10]; wire [9:0] ma = a[9:0], mb = b[9:0]; // Special value detection wire a_inf = (ea == 5'h1F) & (ma == 10'h0); wire b_inf = (eb == 5'h1F) & (mb == 10'h0); wire a_nan = (ea == 5'h1F) & (ma != 10'h0); wire b_nan = (eb == 5'h1F) & (mb != 10'h0); wire a_zero = (ea == 5'h00) & (ma == 10'h0); wire b_zero = (eb == 5'h00) & (mb == 10'h0); // Full mantissa with implicit leading 1 (12 bits for alignment headroom) wire [10:0] fa = a_zero ? 11'h0 : {1'b1, ma}; wire [10:0] fb = b_zero ? 11'h0 : {1'b1, mb}; // --- Swap so that |a_op| >= |b_op| --- wire [15:0] mag_a = {1'b0, a[14:0]}; wire [15:0] mag_b = {1'b0, b[14:0]}; wire swap = (mag_b > mag_a); wire s_big = swap ? sb : sa; wire [4:0] e_big = swap ? eb : ea; wire [10:0] f_big = swap ? fb : fa; wire s_sml = swap ? sa : sb; wire [4:0] e_sml = swap ? ea : eb; wire [10:0] f_sml = swap ? fa : fb; // --- Alignment --- wire [4:0] diff = e_big - e_sml; wire [10:0] f_sml_sh = (diff >= 11) ? 11'h0 : (f_sml >> diff); // --- Addition / subtraction --- wire same_sign = (s_big == s_sml); wire [11:0] sum_raw = same_sign ? ({1'b0, f_big} + {1'b0, f_sml_sh}) : ({1'b0, f_big} - {1'b0, f_sml_sh}); // --- Normalization --- // Find leading-one position in 12-bit sum_raw reg [3:0] lz; always @(*) begin casez (sum_raw) 12'b1??????????? : lz = 4'd0; 12'b01?????????? : lz = 4'd1; 12'b001????????? : lz = 4'd2; 12'b0001???????? : lz = 4'd3; 12'b00001??????? : lz = 4'd4; 12'b000001?????? : lz = 4'd5; 12'b0000001????? : lz = 4'd6; 12'b00000001???? : lz = 4'd7; 12'b000000001??? : lz = 4'd8; 12'b0000000001?? : lz = 4'd9; 12'b00000000001? : lz = 4'd10; 12'b000000000001 : lz = 4'd11; default : lz = 4'd12; // zero endcase end // Normalize: shift so the leading 1 lands at bit[10], then sum_norm[9:0] is mantissa. // Overflow (lz==0, bit[11]=1): shift right by 1 → leading 1 moves from [11] to [10]. // Normal (lz>=1): shift left by (lz-1) → leading 1 moves from [11-lz] to [10]. wire [3:0] norm_shift = (lz == 0) ? 4'd0 : (lz - 4'd1); wire [11:0] sum_norm = (lz == 0) ? (sum_raw >> 1) : (sum_raw << norm_shift); // Exponent: +1 for overflow, -(lz-1) for left-shift normalization. wire [5:0] exp_adj = (sum_raw[11]) ? ({1'b0, e_big} + 6'd1) : ({1'b0, e_big} - {2'b0, lz} + 6'd1); wire result_zero = (sum_raw == 12'h0); wire exp_overflow = (exp_adj >= 6'd31) & ~result_zero; // --- Special case output mux --- wire [15:0] nan_out = 16'h7E00; wire [15:0] inf_out = {s_big, 5'h1F, 10'h0}; wire [15:0] zero_out = 16'h0000; wire [15:0] norm_out = {s_big, exp_adj[4:0], sum_norm[9:0]}; assign result = (a_nan | b_nan) ? nan_out : (a_inf & b_inf & (sa != sb)) ? nan_out : // ∞ - ∞ (a_inf | b_inf) ? inf_out : (exp_overflow) ? inf_out : (result_zero) ? zero_out : norm_out; endmodule