From 2b7b2185d381f2c5fd4aee19bd3a3508b4c9557f Mon Sep 17 00:00:00 2001 From: Alejandro Soto Date: Sun, 3 Mar 2024 20:39:39 -0600 Subject: platform/wavelet3d: implement rounded fmul --- platform/wavelet3d/gfx_fmul_lane.sv | 82 +++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 platform/wavelet3d/gfx_fmul_lane.sv (limited to 'platform/wavelet3d/gfx_fmul_lane.sv') diff --git a/platform/wavelet3d/gfx_fmul_lane.sv b/platform/wavelet3d/gfx_fmul_lane.sv new file mode 100644 index 0000000..17a988e --- /dev/null +++ b/platform/wavelet3d/gfx_fmul_lane.sv @@ -0,0 +1,82 @@ +module gfx_fmul_lane +( + input logic clk, + + input gfx::float_special a, + b, + input logic slow_in, + + output gfx::float_round q +); + + import gfx::*; + + /* Queremos calcular q = a * b. + * + * Donde a = (-1)^s * 1.m * 2^f, + * b = (-1)^t * 1.n * 2^g + * + * Entonces q = (-1)^(s + t) (1.m * 1.n) 2^(f + g) + * + * El producto es entre números >= 1.0 y < 2.0. En el peor caso: + * Mejor caso: 1.000... * 1.000... ~ 1.000... + * Peor caso: 1.999... * 1.999... ~ 3.999... = 2^1 * 1.999 + * + * Así que, si el producto es >= 2, hay que hacerle >> 1 a la mantisa + * y sumarle 1 al exponente para normalizar. + */ + + logic guard, lo_msb, lo_reduce, overflow_0, overflow_1, + round, sign, slow_0, slow_1, zero; + + float_exp exp; + float_round out; + float_mant_full hi; + logic[$bits(float_mant_full) - 3:0] lo; + + assign lo_msb = lo[$bits(lo) - 1]; + assign lo_reduce = |lo[$bits(lo) - 2:0]; + + always_comb begin + q = out; + q.slow = slow_1 | overflow_1; + end + + always_ff @(posedge clk) begin + // Stage 0: producto + + sign <= a.val.sign ^ b.val.sign; + zero <= a.exp_min | b.exp_min; + slow_0 <= slow_in; + + {overflow_0, exp} <= {1'b0, a.val.exp} + {1'b0, b.val.exp} - {1'b0, FLOAT_EXP_BIAS}; + {hi, guard, round, lo} <= full_mant(a.val.mant) * full_mant(b.val.mant); + + // Stage 1: normalización + + slow_1 <= slow_0 | overflow_0; + overflow_1 <= 0; + + out.slow <= 1'bx; // Ver 'q' + out.zero <= zero; + out.normal.sign <= sign; + + if (hi[$bits(hi) - 1]) begin + out.guard <= guard; + out.round <= round; + out.sticky <= lo_msb | lo_reduce; + out.normal.mant <= implicit_mant(hi); + {overflow_1, out.normal.exp} <= {1'b0, exp} + 1; + end else begin + /* Bit antes de msb es necesariamente 1, ya que los msb de + * ambos multiplicandos son 1. Ver assert en implicit_mant(). + */ + out.guard <= round; + out.round <= lo[$bits(lo) - 1]; + out.sticky <= lo_reduce; + out.normal.exp <= exp; + out.normal.mant <= implicit_mant({hi[$bits(hi) - 2:0], guard}); + end + end + +endmodule -- cgit v1.2.3