1 """IEEE754 Floating Point Library
3 Copyright (C) 2019 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
7 from nmigen
import Module
, Signal
, Mux
8 from nmigen
.cli
import main
, verilog
10 from nmutil
.pipemodbase
import PipeModBase
11 from ieee754
.fpcommon
.fpbase
import FPNumBaseRecord
12 from ieee754
.fpcommon
.fpbase
import MultiShiftRMerge
13 from ieee754
.fpcommon
.denorm
import FPSCData
14 from ieee754
.fpcommon
.getop
import FPPipeContext
15 from ieee754
.fpcommon
.pscdata
import FPSCData
18 class FPAddAlignMultiMod
:
19 """Module to do mantissa alignment shift in multiple cycles
21 def __init__(self
, width
):
22 self
.in_a
= FPNumBaseRecord(width
)
23 self
.in_b
= FPNumBaseRecord(width
)
24 self
.out_a
= FPNumBaseRecord(width
)
25 self
.out_b
= FPNumBaseRecord(width
)
26 self
.exp_eq
= Signal(reset_less
=True)
28 def elaborate(self
, platform
):
32 # exponent of a greater than b: shift b down
33 comb
+= self
.exp_eq
.eq(0)
34 comb
+= self
.out_a
.eq(self
.in_a
)
35 comb
+= self
.out_b
.eq(self
.in_b
)
36 agtb
= Signal(reset_less
=True)
37 altb
= Signal(reset_less
=True)
38 comb
+= agtb
.eq(self
.in_a
.e
> self
.in_b
.e
)
39 comb
+= altb
.eq(self
.in_a
.e
< self
.in_b
.e
)
41 comb
+= self
.out_b
.shift_down(self
.in_b
)
42 # exponent of b greater than a: shift a down
44 comb
+= self
.out_a
.shift_down(self
.in_a
)
45 # exponents equal: move to next stage.
47 comb
+= self
.exp_eq
.eq(1)
51 class FPAddAlignSingleMod(PipeModBase
):
53 def __init__(self
, pspec
):
54 super().__init
__(pspec
, "align")
57 return FPSCData(self
.pspec
, True)
60 return FPSCData(self
.pspec
, True)
62 def elaborate(self
, platform
):
63 """ Aligns A against B or B against A, depending on which has the
64 greater exponent. This is done in a *single* cycle using
65 variable-width bit-shift
67 the shifter used here is quite expensive in terms of gates.
68 Mux A or B in (and out) into temporaries, as only one of them
69 needs to be aligned against the other.
71 code is therefore slightly complex because after testing which
72 exponent is greater, a and b get mux-routed into the multi-shifter
73 and so does the output.
80 width
= self
.pspec
.width
81 espec
= (len(ai
.e
), True)
83 # temporary (muxed) input and output to be shifted
84 t_inp
= FPNumBaseRecord(width
)
85 t_out
= FPNumBaseRecord(width
)
86 msr
= MultiShiftRMerge(ai
.m_width
, espec
)
87 m
.submodules
.multishift_r
= msr
90 ediff
= Signal(espec
, reset_less
=True)
91 ediffr
= Signal(espec
, reset_less
=True)
92 tdiff
= Signal(espec
, reset_less
=True)
93 elz
= Signal(reset_less
=True)
94 egz
= Signal(reset_less
=True)
96 # connect multi-shifter to t_inp/out mantissa (and tdiff)
97 # (only one: input/output is muxed)
98 comb
+= msr
.inp
.eq(t_inp
.m
)
99 comb
+= msr
.diff
.eq(tdiff
)
100 comb
+= t_out
.m
.eq(msr
.m
)
101 comb
+= t_out
.e
.eq(Mux(egz
, ai
.e
, bi
.e
))
102 comb
+= t_out
.s
.eq(t_inp
.s
)
104 # work out exponent difference, set up mux-tests if a > b or b > a
105 comb
+= ediff
.eq(ai
.e
- bi
.e
) # a - b
106 comb
+= ediffr
.eq(-ediff
) # b - a
107 comb
+= elz
.eq(ediffr
> 0) # ae < be
108 comb
+= egz
.eq(ediff
> 0) # ae > be
110 # decide what to input into the multi-shifter
111 comb
+= [t_inp
.s
.eq(Mux(egz
, bi
.s
, ai
.s
)), # a/b sign
112 t_inp
.m
.eq(Mux(egz
, bi
.m
, ai
.m
)), # a/b mantissa
113 t_inp
.e
.eq(Mux(egz
, bi
.e
, ai
.e
)), # a/b exponent
114 tdiff
.eq(Mux(egz
, ediff
, ediffr
)),
117 # now decide where (if) to route the *output* of the multi-shifter
119 # if a exponent greater, route mshifted-out to b? otherwise just b
120 comb
+= [self
.o
.b
.e
.eq(Mux(egz
, t_out
.e
, bi
.e
)), # exponent
121 self
.o
.b
.m
.eq(Mux(egz
, t_out
.m
, bi
.m
)), # mantissa
122 self
.o
.b
.s
.eq(bi
.s
), # sign as-is
124 # if b exponent greater, route mshifted-out to a? otherwise just a
125 comb
+= [self
.o
.a
.e
.eq(Mux(elz
, t_out
.e
, ai
.e
)), # exponent
126 self
.o
.a
.m
.eq(Mux(elz
, t_out
.m
, ai
.m
)), # mantissa
127 self
.o
.a
.s
.eq(ai
.s
), # sign as-is
130 # pass context through
131 comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
132 comb
+= self
.o
.z
.eq(self
.i
.z
)
133 comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
134 comb
+= self
.o
.oz
.eq(self
.i
.oz
)