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 temp
= Signal(mwid
, reset_less
=True)
51 temp_r
= Signal(mwid
, reset_less
=True)
52 with m
.If(self
.m_in
[0]):
53 # propagate low bit: do an ASL basically, except
54 # i can't work out how to do it in nmigen sigh
55 m
.d
.comb
+= temp_r
.eq((self
.m_in
[0] << clz
) - 1)
57 # limclz sets a limit (set by the exponent) on how far M can be shifted
58 # this can be used to ensure that near-zero numbers don't then have
59 # to be shifted *back* (e < -126 in the case of FP32 for example)
60 if self
.limclz
is not False:
61 limclz
= Mux(self
.limclz
> pe
.o
, pe
.o
, self
.limclz
)
66 pe
.i
.eq(self
.m_in
[::-1]), # inverted
67 clz
.eq(limclz
), # count zeros from MSB down
68 temp
.eq((self
.m_in
<< clz
)), # shift mantissa UP
69 self
.e_out
.eq(self
.e_in
- clz
), # DECREASE exponent
72 m
.d
.comb
+= self
.m_out
.eq(temp | temp_r
)
74 m
.d
.comb
+= self
.m_out
.eq(temp
),