9f172cc87e28f608ec23eb648f7a7f88d138b767
1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Module
, Signal
, Cat
6 from nmigen
.cli
import main
, verilog
8 from fpbase
import FPNum
, FPOp
, Overflow
, FPBase
13 def __init__(self
, width
, single_cycle
=False):
16 self
.single_cycle
= single_cycle
18 self
.in_a
= FPOp(width
)
19 self
.in_b
= FPOp(width
)
20 self
.out_z
= FPOp(width
)
22 def get_fragment(self
, platform
=None):
23 """ creates the HDL code-fragment for FPAdd
30 z
= FPNum(self
.width
, False)
32 m
.submodules
.fpnum_a
= a
33 m
.submodules
.fpnum_b
= b
34 m
.submodules
.fpnum_z
= z
37 tot
= Signal(w
, reset_less
=True) # sticky/round/guard, {mantissa} result, 1 overflow
41 m
.submodules
.overflow
= of
48 with m
.State("get_a"):
49 self
.get_op(m
, self
.in_a
, a
, "get_b")
54 with m
.State("get_b"):
55 self
.get_op(m
, self
.in_b
, b
, "special_cases")
58 # special cases: NaNs, infs, zeros, denormalised
59 # NOTE: some of these are unique to add. see "Special Operations"
60 # https://steve.hollasch.net/cgindex/coding/ieeefloat.html
62 with m
.State("special_cases"):
65 m
.d
.comb
+= s_nomatch
.eq(a
.s
!= b
.s
)
68 m
.d
.comb
+= m_match
.eq(a
.m
== b
.m
)
70 # if a is NaN or b is NaN return NaN
71 with m
.If(a
.is_nan | b
.is_nan
):
75 # XXX WEIRDNESS for FP16 non-canonical NaN handling
78 ## if a is zero and b is NaN return -b
79 #with m.If(a.is_zero & (a.s==0) & b.is_nan):
81 # m.d.sync += z.create(b.s, b.e, Cat(b.m[3:-2], ~b.m[0]))
83 ## if b is zero and a is NaN return -a
84 #with m.Elif(b.is_zero & (b.s==0) & a.is_nan):
86 # m.d.sync += z.create(a.s, a.e, Cat(a.m[3:-2], ~a.m[0]))
88 ## if a is -zero and b is NaN return -b
89 #with m.Elif(a.is_zero & (a.s==1) & b.is_nan):
91 # m.d.sync += z.create(a.s & b.s, b.e, Cat(b.m[3:-2], 1))
93 ## if b is -zero and a is NaN return -a
94 #with m.Elif(b.is_zero & (b.s==1) & a.is_nan):
96 # m.d.sync += z.create(a.s & b.s, a.e, Cat(a.m[3:-2], 1))
98 # if a is inf return inf (or NaN)
99 with m
.Elif(a
.is_inf
):
101 m
.d
.sync
+= z
.inf(a
.s
)
102 # if a is inf and signs don't match return NaN
103 with m
.If(b
.exp_128
& s_nomatch
):
106 # if b is inf return inf
107 with m
.Elif(b
.is_inf
):
109 m
.d
.sync
+= z
.inf(b
.s
)
111 # if a is zero and b zero return signed-a/b
112 with m
.Elif(a
.is_zero
& b
.is_zero
):
114 m
.d
.sync
+= z
.create(a
.s
& b
.s
, b
.e
, b
.m
[3:-1])
116 # if a is zero return b
117 with m
.Elif(a
.is_zero
):
119 m
.d
.sync
+= z
.create(b
.s
, b
.e
, b
.m
[3:-1])
121 # if b is zero return a
122 with m
.Elif(b
.is_zero
):
124 m
.d
.sync
+= z
.create(a
.s
, a
.e
, a
.m
[3:-1])
126 # if a equal to -b return zero (+ve zero)
127 with m
.Elif(s_nomatch
& m_match
& (a
.e
== b
.e
)):
129 m
.d
.sync
+= z
.zero(0)
131 # Denormalised Number checks
134 self
.denormalise(m
, a
)
135 self
.denormalise(m
, b
)
140 with m
.State("align"):
141 if not self
.single_cycle
:
142 # NOTE: this does *not* do single-cycle multi-shifting,
143 # it *STAYS* in the align state until exponents match
145 # exponent of a greater than b: shift b down
146 with m
.If(a
.e
> b
.e
):
147 m
.d
.sync
+= b
.shift_down()
148 # exponent of b greater than a: shift a down
149 with m
.Elif(a
.e
< b
.e
):
150 m
.d
.sync
+= a
.shift_down()
151 # exponents equal: move to next stage.
155 # This one however (single-cycle) will do the shift
158 # XXX TODO: the shifter used here is quite expensive
159 # having only one would be better
161 ediff
= Signal((len(a
.e
), True), reset_less
=True)
162 ediffr
= Signal((len(a
.e
), True), reset_less
=True)
163 m
.d
.comb
+= ediff
.eq(a
.e
- b
.e
)
164 m
.d
.comb
+= ediffr
.eq(b
.e
- a
.e
)
165 with m
.If(ediff
> 0):
166 m
.d
.sync
+= b
.shift_down_multi(ediff
)
167 # exponent of b greater than a: shift a down
168 with m
.Elif(ediff
< 0):
169 m
.d
.sync
+= a
.shift_down_multi(ediffr
)
174 # First stage of add. covers same-sign (add) and subtract
175 # special-casing when mantissas are greater or equal, to
176 # give greatest accuracy.
178 with m
.State("add_0"):
180 m
.d
.sync
+= z
.e
.eq(a
.e
)
181 # same-sign (both negative or both positive) add mantissas
182 with m
.If(a
.s
== b
.s
):
184 tot
.eq(Cat(a
.m
, 0) + Cat(b
.m
, 0)),
187 # a mantissa greater than b, use a
188 with m
.Elif(a
.m
>= b
.m
):
190 tot
.eq(Cat(a
.m
, 0) - Cat(b
.m
, 0)),
193 # b mantissa greater than a, use b
196 tot
.eq(Cat(b
.m
, 0) - Cat(a
.m
, 0)),
201 # Second stage of add: preparation for normalisation.
202 # detects when tot sum is too big (tot[27] is kinda a carry bit)
204 with m
.State("add_1"):
205 m
.next
= "normalise_1"
206 # tot[27] gets set when the sum overflows. shift result down
212 of
.round_bit
.eq(tot
[2]),
213 of
.sticky
.eq(tot
[1] | tot
[0]),
222 of
.round_bit
.eq(tot
[1]),
227 # First stage of normalisation.
229 with m
.State("normalise_1"):
230 self
.normalise_1(m
, z
, of
, "normalise_2")
233 # Second stage of normalisation.
235 with m
.State("normalise_2"):
236 self
.normalise_2(m
, z
, of
, "round")
241 with m
.State("round"):
242 self
.roundz(m
, z
, of
, "corrections")
247 with m
.State("corrections"):
248 self
.corrections(m
, z
, "pack")
253 with m
.State("pack"):
254 self
.pack(m
, z
, "put_z")
259 with m
.State("put_z"):
260 self
.put_z(m
, z
, self
.out_z
, "get_a")
265 if __name__
== "__main__":
266 alu
= FPADD(width
=32)
267 main(alu
, ports
=alu
.in_a
.ports() + alu
.in_b
.ports() + alu
.out_z
.ports())
270 # works... but don't use, just do "python fname.py convert -t v"
271 #print (verilog.convert(alu, ports=[
272 # ports=alu.in_a.ports() + \
273 # alu.in_b.ports() + \