9b5a971a93dd773b340bc032803fdeb20af5fea6
1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Module
, Signal
, Cat
, Const
6 from nmigen
.cli
import main
, verilog
10 """ Floating-point Number Class, variable-width TODO (currently 32-bit)
12 Contains signals for an incoming copy of the value, decoded into
13 sign / exponent / mantissa.
14 Also contains encoding functions, creation and recognition of
15 zero, NaN and inf (all signed)
17 Four extra bits are included in the mantissa: the top bit
18 (m[-1]) is effectively a carry-overflow. The other three are
19 guard (m[2]), round (m[1]), and sticky (m[0])
21 def __init__(self
, width
, m_width
=None):
24 m_width
= width
- 5 # mantissa extra bits (top,guard,round)
25 self
.v
= Signal(width
) # Latched copy of value
26 self
.m
= Signal(m_width
) # Mantissa
27 self
.e
= Signal((10, True)) # Exponent: 10 bits, signed
28 self
.s
= Signal() # Sign bit
30 self
.mzero
= Const(0, (m_width
, False))
31 self
.m1s
= Const(-1, (m_width
, False))
32 self
.P128
= Const(128, (10, True))
33 self
.P127
= Const(127, (10, True))
34 self
.N127
= Const(-127, (10, True))
35 self
.N126
= Const(-126, (10, True))
38 """ decodes a latched value into sign / exponent / mantissa
40 bias is subtracted here, from the exponent. exponent
41 is extended to 10 bits so that subtract 127 is done on
45 return [self
.m
.eq(Cat(0, 0, 0, v
[0:23])), # mantissa
46 self
.e
.eq(v
[23:31] - self
.P127
), # exp (minus bias)
47 self
.s
.eq(v
[31]), # sign
50 def create(self
, s
, e
, m
):
51 """ creates a value from sign / exponent / mantissa
53 bias is added here, to the exponent
56 self
.v
[31].eq(s
), # sign
57 self
.v
[23:31].eq(e
+ self
.P127
), # exp (add on bias)
58 self
.v
[0:23].eq(m
) # mantissa
62 """ shifts a mantissa down by one. exponent is increased to compensate
64 accuracy is lost as a result in the mantissa however there are 3
65 guard bits (the latter of which is the "sticky" bit)
67 return [self
.e
.eq(self
.e
+ 1),
68 self
.m
.eq(Cat(self
.m
[0] | self
.m
[1], self
.m
[2:], 0))
72 return self
.create(s
, self
.P128
, 1<<22)
75 return self
.create(s
, self
.P128
, 0)
78 return self
.create(s
, self
.N127
, 0)
81 return (self
.e
== self
.P128
) & (self
.m
!= 0)
84 return (self
.e
== self
.P128
) & (self
.m
== 0)
87 return (self
.e
== self
.N127
) & (self
.m
== self
.mzero
)
89 def is_overflowed(self
):
90 return (self
.e
> self
.P127
)
92 def is_denormalised(self
):
93 return (self
.e
== self
.N126
) & (self
.m
[23] == 0)
96 def __init__(self
, width
):
99 self
.v
= Signal(width
)
104 return [self
.v
, self
.stb
, self
.ack
]
109 self
.guard
= Signal() # tot[2]
110 self
.round_bit
= Signal() # tot[1]
111 self
.sticky
= Signal() # tot[0]
115 def __init__(self
, width
):
118 self
.in_a
= FPOp(width
)
119 self
.in_b
= FPOp(width
)
120 self
.out_z
= FPOp(width
)
122 def get_op(self
, m
, op
, v
, next_state
):
123 with m
.If((op
.ack
) & (op
.stb
)):
130 m
.d
.sync
+= op
.ack
.eq(1)
132 def normalise_1(self
, m
, z
, of
, next_state
):
133 with m
.If((z
.m
[-1] == 0) & (z
.e
> z
.N126
)):
135 z
.e
.eq(z
.e
- 1), # DECREASE exponent
136 z
.m
.eq(z
.m
<< 1), # shift mantissa UP
137 z
.m
[0].eq(of
.guard
), # steal guard bit (was tot[2])
138 of
.guard
.eq(of
.round_bit
), # steal round_bit (was tot[1])
139 of
.round_bit
.eq(0), # reset round bit
144 def normalise_2(self
, m
, z
, of
, next_state
):
145 with m
.If(z
.e
< z
.N126
):
147 z
.e
.eq(z
.e
+ 1), # INCREASE exponent
148 z
.m
.eq(z
.m
>> 1), # shift mantissa DOWN
150 of
.round_bit
.eq(of
.guard
),
151 of
.sticky
.eq(of
.sticky | of
.round_bit
)
156 def roundz(self
, m
, z
, of
, next_state
):
158 with m
.If(of
.guard
& (of
.round_bit | of
.sticky | z
.m
[0])):
159 m
.d
.sync
+= z
.m
.eq(z
.m
+ 1) # mantissa rounds up
160 with m
.If(z
.m
== z
.m1s
): # all 1s
161 m
.d
.sync
+= z
.e
.eq(z
.e
+ 1) # exponent rounds up
163 def corrections(self
, m
, z
, next_state
):
165 # denormalised, correct exponent to zero
166 with m
.If(z
.is_denormalised()):
167 m
.d
.sync
+= z
.m
.eq(-127)
168 # FIX SIGN BUG: -a + a = +0.
169 with m
.If((z
.e
== z
.N126
) & (z
.m
[0:] == 0)):
170 m
.d
.sync
+= z
.s
.eq(0)
172 def pack(self
, m
, z
, next_state
):
174 # if overflow occurs, return inf
175 with m
.If(z
.is_overflowed()):
178 m
.d
.sync
+= z
.create(z
.s
, z
.e
, z
.m
)
180 def put_z(self
, m
, z
, out_z
, next_state
):
185 with m
.If(out_z
.stb
& out_z
.ack
):
186 m
.d
.sync
+= out_z
.stb
.eq(0)
189 def get_fragment(self
, platform
=None):
193 a
= FPNum(self
.width
)
194 b
= FPNum(self
.width
)
195 z
= FPNum(self
.width
, 24)
197 tot
= Signal(28) # sticky/round/guard bits, 23 result, 1 overflow
206 with m
.State("get_a"):
207 self
.get_op(m
, self
.in_a
, a
.v
, "get_b")
212 with m
.State("get_b"):
213 self
.get_op(m
, self
.in_b
, b
.v
, "unpack")
216 # unpacks operands into sign, mantissa and exponent
218 with m
.State("unpack"):
219 m
.next
= "special_cases"
220 m
.d
.sync
+= a
.decode()
221 m
.d
.sync
+= b
.decode()
224 # special cases: NaNs, infs, zeros, denormalised
226 with m
.State("special_cases"):
228 # if a is NaN or b is NaN return NaN
229 with m
.If(a
.is_nan() | b
.is_nan()):
233 # if a is inf return inf (or NaN)
234 with m
.Elif(a
.is_inf()):
236 m
.d
.sync
+= z
.inf(a
.s
)
237 # if a is inf and signs don't match return NaN
238 with m
.If((b
.e
== b
.P128
) & (a
.s
!= b
.s
)):
239 m
.d
.sync
+= z
.nan(b
.s
)
241 # if b is inf return inf
242 with m
.Elif(b
.is_inf()):
244 m
.d
.sync
+= z
.inf(b
.s
)
246 # if a is zero and b zero return signed-a/b
247 with m
.Elif(a
.is_zero() & b
.is_zero()):
249 m
.d
.sync
+= z
.create(a
.s
& b
.s
, b
.e
[0:8], b
.m
[3:-1])
251 # if a is zero return b
252 with m
.Elif(a
.is_zero()):
254 m
.d
.sync
+= z
.create(b
.s
, b
.e
[0:8], b
.m
[3:-1])
256 # if b is zero return a
257 with m
.Elif(b
.is_zero()):
259 m
.d
.sync
+= z
.create(a
.s
, a
.e
[0:8], a
.m
[3:-1])
261 # Denormalised Number checks
264 # denormalise a check
265 with m
.If(a
.e
== a
.N127
):
266 m
.d
.sync
+= a
.e
.eq(-126) # limit a exponent
268 m
.d
.sync
+= a
.m
[-1].eq(1) # set top mantissa bit
269 # denormalise b check
270 with m
.If(b
.e
== a
.N127
):
271 m
.d
.sync
+= b
.e
.eq(-126) # limit b exponent
273 m
.d
.sync
+= b
.m
[-1].eq(1) # set top mantissa bit
276 # align. NOTE: this does *not* do single-cycle multi-shifting,
277 # it *STAYS* in the align state until the exponents match
279 with m
.State("align"):
280 # exponent of a greater than b: increment b exp, shift b mant
281 with m
.If(a
.e
> b
.e
):
282 m
.d
.sync
+= b
.shift_down()
283 # exponent of b greater than a: increment a exp, shift a mant
284 with m
.Elif(a
.e
< b
.e
):
285 m
.d
.sync
+= a
.shift_down()
286 # exponents equal: move to next stage.
291 # First stage of add. covers same-sign (add) and subtract
292 # special-casing when mantissas are greater or equal, to
293 # give greatest accuracy.
295 with m
.State("add_0"):
297 m
.d
.sync
+= z
.e
.eq(a
.e
)
298 # same-sign (both negative or both positive) add mantissas
299 with m
.If(a
.s
== b
.s
):
304 # a mantissa greater than b, use a
305 with m
.Elif(a
.m
>= b
.m
):
310 # b mantissa greater than a, use b
318 # Second stage of add: preparation for normalisation.
319 # detects when tot sum is too big (tot[27] is kinda a carry bit)
321 with m
.State("add_1"):
322 m
.next
= "normalise_1"
323 # tot[27] gets set when the sum overflows. shift result down
328 of
.round_bit
.eq(tot
[2]),
329 of
.sticky
.eq(tot
[1] | tot
[0]),
337 of
.round_bit
.eq(tot
[1]),
342 # First stage of normalisation.
343 # NOTE: just like "align", this one keeps going round every clock
344 # until the result's exponent is within acceptable "range"
345 # NOTE: the weirdness of reassigning guard and round is due to
346 # the extra mantissa bits coming from tot[0..2]
348 with m
.State("normalise_1"):
349 self
.normalise_1(m
, z
, of
, "normalise_2")
352 # Second stage of normalisation.
353 # NOTE: just like "align", this one keeps going round every clock
354 # until the result's exponent is within acceptable "range"
355 # NOTE: the weirdness of reassigning guard and round is due to
356 # the extra mantissa bits coming from tot[0..2]
358 with m
.State("normalise_2"):
359 self
.normalise_2(m
, z
, of
, "round")
364 with m
.State("round"):
365 self
.roundz(m
, z
, of
, "corrections")
370 with m
.State("corrections"):
371 self
.corrections(m
, z
, "pack")
376 with m
.State("pack"):
377 self
.pack(m
, z
, "put_z")
382 with m
.State("put_z"):
383 self
.put_z(m
, z
, self
.out_z
, "get_a")
388 if __name__
== "__main__":
389 alu
= FPADD(width
=32)
390 main(alu
, ports
=alu
.in_a
.ports() + alu
.in_b
.ports() + alu
.out_z
.ports())
393 # works... but don't use, just do "python fname.py convert -t v"
394 #print (verilog.convert(alu, ports=[
395 # ports=alu.in_a.ports() + \
396 # alu.in_b.ports() + \