diff options
| author | Alejandro Soto <alejandro@34project.org> | 2024-03-03 20:39:39 -0600 |
|---|---|---|
| committer | Alejandro Soto <alejandro@34project.org> | 2024-03-03 20:42:36 -0600 |
| commit | 2b7b2185d381f2c5fd4aee19bd3a3508b4c9557f (patch) | |
| tree | acd92b7a9de4678a08cf7e55f99b27fc23ff8938 /platform/wavelet3d/gfx_fmul_lane.sv | |
| parent | cce507d21c86f20a83eec1b09fe3231399ffb10c (diff) | |
platform/wavelet3d: implement rounded fmul
Diffstat (limited to '')
| -rw-r--r-- | platform/wavelet3d/gfx_fmul_lane.sv | 82 |
1 files changed, 82 insertions, 0 deletions
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 |
