1 """ module for adjusting a mantissa and exponent so that the MSB is always 1
4 from nmigen
import Module
, Signal
, Mux
, Elaboratable
5 from nmigen
.lib
.coding
import PriorityEncoder
8 class FPMSBHigh(Elaboratable
):
9 """ makes the top mantissa bit hi (i.e. shifts until it is)
11 NOTE: this does NOT do any kind of checks. do not pass in
12 zero (empty) stuff, and it's best to check if the MSB is
13 already 1 before calling it. although it'll probably work
17 * mantissa is unsigned.
18 * loprop: propagates the low bit (LSB) on the shift
19 * limclz: use this to limit the amount of shifting.
22 exp = -30, mantissa = 0b00011 - output: -33, 0b11000
23 exp = 2, mantissa = 0b01111 - output: 1, 0b11110
25 def __init__(self
, m_width
, e_width
, limclz
=False, loprop
=False):
26 self
.m_width
= m_width
27 self
.e_width
= e_width
29 self
.limclz
= limclz
and Signal((e_width
, True), reset_less
=True)
31 self
.m_in
= Signal(m_width
, reset_less
=True)
32 self
.e_in
= Signal((e_width
, True), reset_less
=True)
33 self
.m_out
= Signal(m_width
, reset_less
=True)
34 self
.e_out
= Signal((e_width
, True), reset_less
=True)
36 def elaborate(self
, platform
):
40 pe
= PriorityEncoder(mwid
)
43 # *sigh* not entirely obvious: count leading zeros (clz)
44 # with a PriorityEncoder. to find from the MSB
45 # we reverse the order of the bits. it would be better if PE
46 # took a "reverse" argument.
48 clz
= Signal((len(self
.e_out
), True), reset_less
=True)
49 # GRRR utterly irritating https://github.com/nmigen/nmigen/issues/302
50 uclz
= Signal(len(self
.e_out
), reset_less
=True)
51 temp
= Signal(mwid
, reset_less
=True)
53 temp_r
= Signal(mwid
, reset_less
=True)
54 with m
.If(self
.m_in
[0]):
55 # propagate low bit: do an ASL basically, except
56 # i can't work out how to do it in nmigen sigh
57 m
.d
.comb
+= temp_r
.eq((self
.m_in
[0] << clz
) - 1)
59 # limclz sets a limit (set by the exponent) on how far M can be shifted
60 # this can be used to ensure that near-zero numbers don't then have
61 # to be shifted *back* (e < -126 in the case of FP32 for example)
62 if self
.limclz
is not False:
63 limclz
= Mux(self
.limclz
> pe
.o
, pe
.o
, self
.limclz
)
68 pe
.i
.eq(self
.m_in
[::-1]), # inverted
69 clz
.eq(limclz
), # count zeros from MSB down
70 uclz
.eq(limclz
), # *sigh*...
71 temp
.eq((self
.m_in
<< uclz
)), # shift mantissa UP
72 self
.e_out
.eq(self
.e_in
- clz
), # DECREASE exponent
75 m
.d
.comb
+= self
.m_out
.eq(temp | temp_r
)
77 m
.d
.comb
+= self
.m_out
.eq(temp
),