518a5d9e6e4dba4b1c9f75f8558b0d2788fefe8d
[ieee754fpu.git] / src / ieee754 / fpfma / util.py
1 from ieee754.fpcommon.fpbase import FPFormat
2 from nmigen.hdl.ast import signed, unsigned
3
4
5 def expanded_exponent_shape(fpformat):
6 assert isinstance(fpformat, FPFormat)
7 return signed(fpformat.e_width + 3)
8
9
10 EXPANDED_MANTISSA_SPACE_BETWEEN_SUM_PROD = 16 # FIXME: change back to 3
11 r""" the number of bits of space between the lsb of a large addend and the msb
12 of the product of two small factors to guarantee that the product ends up
13 entirely in the sticky bit.
14
15 e.g. let's assume the floating point format has
16 5 mantissa bits (4 bits in the field + 1 implicit bit):
17
18 if `a` and `b` are `0b11111` and `c` is `0b11111 * 2**-50`, and we are
19 computing `a * c + b`:
20
21 the computed mantissa would be:
22
23 ```text
24 sticky bit
25 |
26 v
27 0b111110001111000001
28 \-b-/ \-product/
29 ```
30
31 (note this isn't the mathematically correct
32 answer, but it rounds to the correct floating-point answer and takes
33 less hardware)
34 """
35
36 # the number of extra LSBs needed by the expanded mantissa to avoid
37 # having a tiny addend conflict with the lsb of the product.
38 EXPANDED_MANTISSA_EXTRA_LSBS = 16 # FIXME: change back to 2
39
40
41 # the number of extra MSBs needed by the expanded mantissa to avoid
42 # overflowing. 2 bits -- 1 bit for carry out of addition, 1 bit for sign.
43 EXPANDED_MANTISSA_EXTRA_MSBS = 16 # FIXME: change back to 2
44
45
46 def expanded_mantissa_shape(fpformat):
47 assert isinstance(fpformat, FPFormat)
48 return signed((fpformat.fraction_width + 1) * 3
49 + EXPANDED_MANTISSA_EXTRA_MSBS
50 + EXPANDED_MANTISSA_SPACE_BETWEEN_SUM_PROD
51 + EXPANDED_MANTISSA_EXTRA_LSBS)
52
53
54 def multiplicand_mantissa_shape(fpformat):
55 assert isinstance(fpformat, FPFormat)
56 return unsigned(fpformat.fraction_width + 1)
57
58
59 def product_mantissa_shape(fpformat):
60 assert isinstance(fpformat, FPFormat)
61 return unsigned(multiplicand_mantissa_shape(fpformat).width * 2)
62
63
64 def get_fpformat(pspec):
65 width = pspec.width
66 assert isinstance(width, int)
67 fpformat = getattr(pspec, "fpformat", None)
68 if fpformat is None:
69 fpformat = FPFormat.standard(width)
70 else:
71 assert isinstance(fpformat, FPFormat)
72 assert width == fpformat.width
73 return fpformat