1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Module
, Signal
, Elaboratable
6 from nmigen
.cli
import main
, verilog
8 from ieee754
.fpcommon
.fpbase
import FPNumOut
, FPNumIn
, FPNumBase
9 from ieee754
.fpcommon
.fpbase
import FPNumBaseRecord
10 from ieee754
.fpcommon
.fpbase
import MultiShiftRMerge
11 from ieee754
.fpcommon
.fpbase
import FPState
12 from ieee754
.fpcommon
.denorm
import FPSCData
13 from ieee754
.fpcommon
.getop
import FPPipeContext
18 def __init__(self
, pspec
):
20 self
.a
= FPNumBaseRecord(width
)
21 self
.b
= FPNumBaseRecord(width
)
22 self
.z
= FPNumBaseRecord(width
, False)
23 self
.out_do_z
= Signal(reset_less
=True)
24 self
.oz
= Signal(width
, reset_less
=True)
25 self
.ctx
= FPPipeContext(pspec
)
26 self
.muxid
= self
.ctx
.muxid
29 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
30 self
.a
.eq(i
.a
), self
.b
.eq(i
.b
), self
.ctx
.eq(i
.ctx
)]
34 class FPAddAlignMultiMod(FPState
):
36 def __init__(self
, width
):
37 self
.in_a
= FPNumBaseRecord(width
)
38 self
.in_b
= FPNumBaseRecord(width
)
39 self
.out_a
= FPNumBaseRecord(width
)
40 self
.out_b
= FPNumBaseRecord(width
)
41 self
.exp_eq
= Signal(reset_less
=True)
43 def elaborate(self
, platform
):
44 # This one however (single-cycle) will do the shift
49 #m.submodules.align_in_a = self.in_a
50 #m.submodules.align_in_b = self.in_b
51 #m.submodules.align_out_a = self.out_a
52 #m.submodules.align_out_b = self.out_b
54 # NOTE: this does *not* do single-cycle multi-shifting,
55 # it *STAYS* in the align state until exponents match
57 # exponent of a greater than b: shift b down
58 m
.d
.comb
+= self
.exp_eq
.eq(0)
59 m
.d
.comb
+= self
.out_a
.eq(self
.in_a
)
60 m
.d
.comb
+= self
.out_b
.eq(self
.in_b
)
61 agtb
= Signal(reset_less
=True)
62 altb
= Signal(reset_less
=True)
63 m
.d
.comb
+= agtb
.eq(self
.in_a
.e
> self
.in_b
.e
)
64 m
.d
.comb
+= altb
.eq(self
.in_a
.e
< self
.in_b
.e
)
66 m
.d
.comb
+= self
.out_b
.shift_down(self
.in_b
)
67 # exponent of b greater than a: shift a down
69 m
.d
.comb
+= self
.out_a
.shift_down(self
.in_a
)
70 # exponents equal: move to next stage.
72 m
.d
.comb
+= self
.exp_eq
.eq(1)
76 class FPAddAlignMulti(FPState
):
78 def __init__(self
, pspec
):
79 FPState
.__init
__(self
, "align")
80 self
.mod
= FPAddAlignMultiMod(pspec
)
81 self
.out_a
= FPNumBaseRecord(width
)
82 self
.out_b
= FPNumBaseRecord(width
)
83 self
.exp_eq
= Signal(reset_less
=True)
85 def setup(self
, m
, in_a
, in_b
):
86 """ links module to inputs and outputs
88 m
.submodules
.align
= self
.mod
89 m
.d
.comb
+= self
.mod
.in_a
.eq(in_a
)
90 m
.d
.comb
+= self
.mod
.in_b
.eq(in_b
)
91 m
.d
.comb
+= self
.exp_eq
.eq(self
.mod
.exp_eq
)
92 m
.d
.sync
+= self
.out_a
.eq(self
.mod
.out_a
)
93 m
.d
.sync
+= self
.out_b
.eq(self
.mod
.out_b
)
96 with m
.If(self
.exp_eq
):
100 class FPAddAlignSingleMod(Elaboratable
):
102 def __init__(self
, pspec
):
104 self
.i
= self
.ispec()
105 self
.o
= self
.ospec()
108 return FPSCData(self
.pspec
, True)
111 return FPNumIn2Ops(self
.pspec
)
113 def process(self
, i
):
116 def setup(self
, m
, i
):
117 """ links module to inputs and outputs
119 m
.submodules
.align
= self
120 m
.d
.comb
+= self
.i
.eq(i
)
122 def elaborate(self
, platform
):
123 """ Aligns A against B or B against A, depending on which has the
124 greater exponent. This is done in a *single* cycle using
125 variable-width bit-shift
127 the shifter used here is quite expensive in terms of gates.
128 Mux A or B in (and out) into temporaries, as only one of them
129 needs to be aligned against the other
133 #m.submodules.align_in_a = self.i.a
134 #m.submodules.align_in_b = self.i.b
135 #m.submodules.align_out_a = self.o.a
136 #m.submodules.align_out_b = self.o.b
138 # temporary (muxed) input and output to be shifted
139 width
= self
.pspec
.width
140 t_inp
= FPNumBaseRecord(width
)
141 t_out
= FPNumBaseRecord(width
)
142 espec
= (len(self
.i
.a
.e
), True)
143 msr
= MultiShiftRMerge(self
.i
.a
.m_width
, espec
)
144 #m.submodules.align_t_in = t_inp
145 #m.submodules.align_t_out = t_out
146 m
.submodules
.multishift_r
= msr
148 ediff
= Signal(espec
, reset_less
=True)
149 ediffr
= Signal(espec
, reset_less
=True)
150 tdiff
= Signal(espec
, reset_less
=True)
151 elz
= Signal(reset_less
=True)
152 egz
= Signal(reset_less
=True)
154 # connect multi-shifter to t_inp/out mantissa (and tdiff)
155 m
.d
.comb
+= msr
.inp
.eq(t_inp
.m
)
156 m
.d
.comb
+= msr
.diff
.eq(tdiff
)
157 m
.d
.comb
+= t_out
.m
.eq(msr
.m
)
158 m
.d
.comb
+= t_out
.e
.eq(t_inp
.e
+ tdiff
)
159 m
.d
.comb
+= t_out
.s
.eq(t_inp
.s
)
161 m
.d
.comb
+= ediff
.eq(self
.i
.a
.e
- self
.i
.b
.e
)
162 m
.d
.comb
+= ediffr
.eq(self
.i
.b
.e
- self
.i
.a
.e
)
163 m
.d
.comb
+= elz
.eq(self
.i
.a
.e
< self
.i
.b
.e
)
164 m
.d
.comb
+= egz
.eq(self
.i
.a
.e
> self
.i
.b
.e
)
166 # default: A-exp == B-exp, A and B untouched (fall through)
167 m
.d
.comb
+= self
.o
.a
.eq(self
.i
.a
)
168 m
.d
.comb
+= self
.o
.b
.eq(self
.i
.b
)
169 # only one shifter (muxed)
170 #m.d.comb += t_out.shift_down_multi(tdiff, t_inp)
171 # exponent of a greater than b: shift b down
172 with m
.If(~self
.i
.out_do_z
):
174 m
.d
.comb
+= [t_inp
.eq(self
.i
.b
),
177 self
.o
.b
.s
.eq(self
.i
.b
.s
), # whoops forgot sign
179 # exponent of b greater than a: shift a down
181 m
.d
.comb
+= [t_inp
.eq(self
.i
.a
),
184 self
.o
.a
.s
.eq(self
.i
.a
.s
), # whoops forgot sign
187 m
.d
.comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
188 m
.d
.comb
+= self
.o
.z
.eq(self
.i
.z
)
189 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
190 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
195 class FPAddAlignSingle(FPState
):
197 def __init__(self
, pspec
):
198 FPState
.__init
__(self
, "align")
200 self
.mod
= FPAddAlignSingleMod(pspec
)
201 self
.out_a
= FPNumIn(None, width
)
202 self
.out_b
= FPNumIn(None, width
)
204 def setup(self
, m
, i
):
205 """ links module to inputs and outputs
209 # NOTE: could be done as comb
210 m
.d
.sync
+= self
.out_a
.eq(self
.mod
.out_a
)
211 m
.d
.sync
+= self
.out_b
.eq(self
.mod
.out_b
)