1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Signal
, Cat
, Const
9 """ Floating-point Number Class, variable-width TODO (currently 32-bit)
11 Contains signals for an incoming copy of the value, decoded into
12 sign / exponent / mantissa.
13 Also contains encoding functions, creation and recognition of
14 zero, NaN and inf (all signed)
16 Four extra bits are included in the mantissa: the top bit
17 (m[-1]) is effectively a carry-overflow. The other three are
18 guard (m[2]), round (m[1]), and sticky (m[0])
20 def __init__(self
, width
, m_width
=None):
23 m_width
= width
- 5 # mantissa extra bits (top,guard,round)
24 self
.m_width
= m_width
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
44 args
= [0] * (self
.m_width
-24) + [v
[0:23]] # pad with extra zeros
45 return [self
.m
.eq(Cat(*args
)), # 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)
97 def __init__(self
, width
):
100 self
.v
= Signal(width
)
105 return [self
.v
, self
.stb
, self
.ack
]
110 self
.guard
= Signal() # tot[2]
111 self
.round_bit
= Signal() # tot[1]
112 self
.sticky
= Signal() # tot[0]
116 """ IEEE754 Floating Point Base Class
118 contains common functions for FP manipulation, such as
119 extracting and packing operands, normalisation, denormalisation,
123 def get_op(self
, m
, op
, v
, next_state
):
124 """ this function moves to the next state and copies the operand
125 when both stb and ack are 1.
126 acknowledgement is sent by setting ack to ZERO.
128 with m
.If((op
.ack
) & (op
.stb
)):
135 m
.d
.sync
+= op
.ack
.eq(1)
137 def denormalise(self
, m
, a
):
138 """ denormalises a number
140 with m
.If(a
.e
== a
.N127
):
141 m
.d
.sync
+= a
.e
.eq(-126) # limit a exponent
143 m
.d
.sync
+= a
.m
[-1].eq(1) # set top mantissa bit
145 def op_normalise(self
, m
, op
, of
, next_state
):
146 """ operand normalisation
147 NOTE: just like "align", this one keeps going round every clock
148 until the result's exponent is within acceptable "range"
150 with m
.If((op
.m
[-1] == 0)): # check last bit of mantissa
152 op
.e
.eq(op
.e
- 1), # DECREASE exponent
153 op
.m
.eq(op
.m
<< 1), # shift mantissa UP
158 def normalise_1(self
, m
, z
, of
, next_state
):
159 """ first stage normalisation
161 NOTE: just like "align", this one keeps going round every clock
162 until the result's exponent is within acceptable "range"
163 NOTE: the weirdness of reassigning guard and round is due to
164 the extra mantissa bits coming from tot[0..2]
166 with m
.If((z
.m
[-1] == 0) & (z
.e
> z
.N126
)):
168 z
.e
.eq(z
.e
- 1), # DECREASE exponent
169 z
.m
.eq(z
.m
<< 1), # shift mantissa UP
170 z
.m
[0].eq(of
.guard
), # steal guard bit (was tot[2])
171 of
.guard
.eq(of
.round_bit
), # steal round_bit (was tot[1])
172 of
.round_bit
.eq(0), # reset round bit
177 def normalise_2(self
, m
, z
, of
, next_state
):
178 """ second stage normalisation
180 NOTE: just like "align", this one keeps going round every clock
181 until the result's exponent is within acceptable "range"
182 NOTE: the weirdness of reassigning guard and round is due to
183 the extra mantissa bits coming from tot[0..2]
185 with m
.If(z
.e
< z
.N126
):
187 z
.e
.eq(z
.e
+ 1), # INCREASE exponent
188 z
.m
.eq(z
.m
>> 1), # shift mantissa DOWN
190 of
.round_bit
.eq(of
.guard
),
191 of
.sticky
.eq(of
.sticky | of
.round_bit
)
196 def roundz(self
, m
, z
, of
, next_state
):
197 """ performs rounding on the output. TODO: different kinds of rounding
200 with m
.If(of
.guard
& (of
.round_bit | of
.sticky | z
.m
[0])):
201 m
.d
.sync
+= z
.m
.eq(z
.m
+ 1) # mantissa rounds up
202 with m
.If(z
.m
== z
.m1s
): # all 1s
203 m
.d
.sync
+= z
.e
.eq(z
.e
+ 1) # exponent rounds up
205 def corrections(self
, m
, z
, next_state
):
206 """ denormalisation and sign-bug corrections
209 # denormalised, correct exponent to zero
210 with m
.If(z
.is_denormalised()):
211 m
.d
.sync
+= z
.m
.eq(-127)
212 # FIX SIGN BUG: -a + a = +0.
213 with m
.If((z
.e
== z
.N126
) & (z
.m
[0:] == 0)):
214 m
.d
.sync
+= z
.s
.eq(0)
216 def pack(self
, m
, z
, next_state
):
217 """ packs the result into the output (detects overflow->Inf)
220 # if overflow occurs, return inf
221 with m
.If(z
.is_overflowed()):
224 m
.d
.sync
+= z
.create(z
.s
, z
.e
, z
.m
)
226 def put_z(self
, m
, z
, out_z
, next_state
):
227 """ put_z: stores the result in the output. raises stb and waits
228 for ack to be set to 1 before moving to the next state.
229 resets stb back to zero when that occurs, as acknowledgement.
235 with m
.If(out_z
.stb
& out_z
.ack
):
236 m
.d
.sync
+= out_z
.stb
.eq(0)