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 FPBaseData
18 def __init__(self
, width
, pspec
):
19 self
.a
= FPNumBaseRecord(width
)
20 self
.b
= FPNumBaseRecord(width
)
21 self
.z
= FPNumBaseRecord(width
, False)
22 self
.out_do_z
= Signal(reset_less
=True)
23 self
.oz
= Signal(width
, reset_less
=True)
24 self
.ctx
= FPBaseData(width
, pspec
)
25 self
.muxid
= self
.ctx
.muxid
28 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
29 self
.a
.eq(i
.a
), self
.b
.eq(i
.b
), self
.ctx
.eq(i
.ctx
)]
33 class FPAddAlignMultiMod(FPState
):
35 def __init__(self
, width
):
36 self
.in_a
= FPNumBaseRecord(width
)
37 self
.in_b
= FPNumBaseRecord(width
)
38 self
.out_a
= FPNumBaseRecord(width
)
39 self
.out_b
= FPNumBaseRecord(width
)
40 self
.exp_eq
= Signal(reset_less
=True)
42 def elaborate(self
, platform
):
43 # This one however (single-cycle) will do the shift
48 #m.submodules.align_in_a = self.in_a
49 #m.submodules.align_in_b = self.in_b
50 #m.submodules.align_out_a = self.out_a
51 #m.submodules.align_out_b = self.out_b
53 # NOTE: this does *not* do single-cycle multi-shifting,
54 # it *STAYS* in the align state until exponents match
56 # exponent of a greater than b: shift b down
57 m
.d
.comb
+= self
.exp_eq
.eq(0)
58 m
.d
.comb
+= self
.out_a
.eq(self
.in_a
)
59 m
.d
.comb
+= self
.out_b
.eq(self
.in_b
)
60 agtb
= Signal(reset_less
=True)
61 altb
= Signal(reset_less
=True)
62 m
.d
.comb
+= agtb
.eq(self
.in_a
.e
> self
.in_b
.e
)
63 m
.d
.comb
+= altb
.eq(self
.in_a
.e
< self
.in_b
.e
)
65 m
.d
.comb
+= self
.out_b
.shift_down(self
.in_b
)
66 # exponent of b greater than a: shift a down
68 m
.d
.comb
+= self
.out_a
.shift_down(self
.in_a
)
69 # exponents equal: move to next stage.
71 m
.d
.comb
+= self
.exp_eq
.eq(1)
75 class FPAddAlignMulti(FPState
):
77 def __init__(self
, width
, pspec
):
78 FPState
.__init
__(self
, "align")
79 self
.mod
= FPAddAlignMultiMod(width
, pspec
)
80 self
.out_a
= FPNumBaseRecord(width
)
81 self
.out_b
= FPNumBaseRecord(width
)
82 self
.exp_eq
= Signal(reset_less
=True)
84 def setup(self
, m
, in_a
, in_b
):
85 """ links module to inputs and outputs
87 m
.submodules
.align
= self
.mod
88 m
.d
.comb
+= self
.mod
.in_a
.eq(in_a
)
89 m
.d
.comb
+= self
.mod
.in_b
.eq(in_b
)
90 m
.d
.comb
+= self
.exp_eq
.eq(self
.mod
.exp_eq
)
91 m
.d
.sync
+= self
.out_a
.eq(self
.mod
.out_a
)
92 m
.d
.sync
+= self
.out_b
.eq(self
.mod
.out_b
)
95 with m
.If(self
.exp_eq
):
99 class FPAddAlignSingleMod(Elaboratable
):
101 def __init__(self
, width
, pspec
):
104 self
.i
= self
.ispec()
105 self
.o
= self
.ospec()
108 return FPSCData(self
.width
, self
.pspec
, True)
111 return FPNumIn2Ops(self
.width
, 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 t_inp
= FPNumBaseRecord(self
.width
)
140 t_out
= FPNumBaseRecord(self
.width
)
141 espec
= (len(self
.i
.a
.e
), True)
142 msr
= MultiShiftRMerge(self
.i
.a
.m_width
, espec
)
143 #m.submodules.align_t_in = t_inp
144 #m.submodules.align_t_out = t_out
145 m
.submodules
.multishift_r
= msr
147 ediff
= Signal(espec
, reset_less
=True)
148 ediffr
= Signal(espec
, reset_less
=True)
149 tdiff
= Signal(espec
, reset_less
=True)
150 elz
= Signal(reset_less
=True)
151 egz
= Signal(reset_less
=True)
153 # connect multi-shifter to t_inp/out mantissa (and tdiff)
154 m
.d
.comb
+= msr
.inp
.eq(t_inp
.m
)
155 m
.d
.comb
+= msr
.diff
.eq(tdiff
)
156 m
.d
.comb
+= t_out
.m
.eq(msr
.m
)
157 m
.d
.comb
+= t_out
.e
.eq(t_inp
.e
+ tdiff
)
158 m
.d
.comb
+= t_out
.s
.eq(t_inp
.s
)
160 m
.d
.comb
+= ediff
.eq(self
.i
.a
.e
- self
.i
.b
.e
)
161 m
.d
.comb
+= ediffr
.eq(self
.i
.b
.e
- self
.i
.a
.e
)
162 m
.d
.comb
+= elz
.eq(self
.i
.a
.e
< self
.i
.b
.e
)
163 m
.d
.comb
+= egz
.eq(self
.i
.a
.e
> self
.i
.b
.e
)
165 # default: A-exp == B-exp, A and B untouched (fall through)
166 m
.d
.comb
+= self
.o
.a
.eq(self
.i
.a
)
167 m
.d
.comb
+= self
.o
.b
.eq(self
.i
.b
)
168 # only one shifter (muxed)
169 #m.d.comb += t_out.shift_down_multi(tdiff, t_inp)
170 # exponent of a greater than b: shift b down
171 with m
.If(~self
.i
.out_do_z
):
173 m
.d
.comb
+= [t_inp
.eq(self
.i
.b
),
176 self
.o
.b
.s
.eq(self
.i
.b
.s
), # whoops forgot sign
178 # exponent of b greater than a: shift a down
180 m
.d
.comb
+= [t_inp
.eq(self
.i
.a
),
183 self
.o
.a
.s
.eq(self
.i
.a
.s
), # whoops forgot sign
186 m
.d
.comb
+= self
.o
.ctx
.eq(self
.i
.ctx
)
187 m
.d
.comb
+= self
.o
.z
.eq(self
.i
.z
)
188 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
189 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
194 class FPAddAlignSingle(FPState
):
196 def __init__(self
, width
, pspec
):
197 FPState
.__init
__(self
, "align")
198 self
.mod
= FPAddAlignSingleMod(width
, pspec
)
199 self
.out_a
= FPNumIn(None, width
)
200 self
.out_b
= FPNumIn(None, width
)
202 def setup(self
, m
, i
):
203 """ links module to inputs and outputs
207 # NOTE: could be done as comb
208 m
.d
.sync
+= self
.out_a
.eq(self
.mod
.out_a
)
209 m
.d
.sync
+= self
.out_b
.eq(self
.mod
.out_b
)