summaryrefslogtreecommitdiff
path: root/platform/wavelet3d/gfx_fmul_lane.sv
blob: 17a988e173a54e0e55a6b69be6f0a76e7b582b4a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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