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 FPNumIn
, FPNumOut
, FPOp
, Overflow
, FPBase
, FPNumBase
11 class FPState(FPBase
):
12 def __init__(self
, state_from
):
13 self
.state_from
= state_from
15 def set_inputs(self
, inputs
):
17 for k
,v
in inputs
.items():
20 def set_outputs(self
, outputs
):
21 self
.outputs
= outputs
22 for k
,v
in outputs
.items():
27 def __init__(self
, width
):
28 self
.in_op
= FPOp(width
)
29 self
.out_op
= FPNumIn(self
.in_op
, width
)
30 self
.out_decode
= Signal(reset_less
=True)
32 def setup(self
, m
, in_op
, out_op
, out_decode
):
33 """ links module to inputs and outputs
35 m
.d
.comb
+= self
.in_op
.copy(in_op
)
36 m
.d
.comb
+= out_op
.v
.eq(self
.out_op
.v
)
37 m
.d
.comb
+= out_decode
.eq(self
.out_decode
)
39 def elaborate(self
, platform
):
41 m
.d
.comb
+= self
.out_decode
.eq((self
.in_op
.ack
) & (self
.in_op
.stb
))
42 #m.submodules.get_op_in = self.in_op
43 m
.submodules
.get_op_out
= self
.out_op
44 with m
.If(self
.out_decode
):
46 self
.out_op
.decode(self
.in_op
.v
),
51 class FPGetOp(FPState
):
55 def __init__(self
, in_state
, out_state
, in_op
, width
):
56 FPState
.__init
__(self
, in_state
)
57 self
.out_state
= out_state
58 self
.mod
= FPGetOpMod(width
)
60 self
.out_op
= FPNumIn(in_op
, width
)
61 self
.out_decode
= Signal(reset_less
=True)
64 with m
.If(self
.out_decode
):
65 m
.next
= self
.out_state
68 self
.out_op
.copy(self
.mod
.out_op
)
71 m
.d
.sync
+= self
.in_op
.ack
.eq(1)
74 class FPGetOpB(FPState
):
78 def __init__(self
, in_b
, width
):
79 FPState
.__init
__(self
, "get_b")
81 self
.b
= FPNumIn(self
.in_b
, width
)
84 self
.get_op(m
, self
.in_b
, self
.b
, "special_cases")
87 class FPAddSpecialCasesMod
:
88 """ special cases: NaNs, infs, zeros, denormalised
89 NOTE: some of these are unique to add. see "Special Operations"
90 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
93 def __init__(self
, width
):
94 self
.in_a
= FPNumBase(width
)
95 self
.in_b
= FPNumBase(width
)
96 self
.out_z
= FPNumOut(width
, False)
97 self
.out_do_z
= Signal(reset_less
=True)
99 def setup(self
, m
, in_a
, in_b
, out_z
, out_do_z
):
100 """ links module to inputs and outputs
102 m
.d
.comb
+= self
.in_a
.copy(in_a
)
103 m
.d
.comb
+= self
.in_b
.copy(in_b
)
104 m
.d
.comb
+= out_z
.v
.eq(self
.out_z
.v
)
105 m
.d
.comb
+= out_do_z
.eq(self
.out_do_z
)
107 def elaborate(self
, platform
):
110 m
.submodules
.sc_in_a
= self
.in_a
111 m
.submodules
.sc_in_b
= self
.in_b
112 m
.submodules
.sc_out_z
= self
.out_z
115 m
.d
.comb
+= s_nomatch
.eq(self
.in_a
.s
!= self
.in_b
.s
)
118 m
.d
.comb
+= m_match
.eq(self
.in_a
.m
== self
.in_b
.m
)
120 # if a is NaN or b is NaN return NaN
121 with m
.If(self
.in_a
.is_nan | self
.in_b
.is_nan
):
122 m
.d
.comb
+= self
.out_do_z
.eq(1)
123 m
.d
.comb
+= self
.out_z
.nan(0)
125 # XXX WEIRDNESS for FP16 non-canonical NaN handling
128 ## if a is zero and b is NaN return -b
129 #with m.If(a.is_zero & (a.s==0) & b.is_nan):
130 # m.d.comb += self.out_do_z.eq(1)
131 # m.d.comb += z.create(b.s, b.e, Cat(b.m[3:-2], ~b.m[0]))
133 ## if b is zero and a is NaN return -a
134 #with m.Elif(b.is_zero & (b.s==0) & a.is_nan):
135 # m.d.comb += self.out_do_z.eq(1)
136 # m.d.comb += z.create(a.s, a.e, Cat(a.m[3:-2], ~a.m[0]))
138 ## if a is -zero and b is NaN return -b
139 #with m.Elif(a.is_zero & (a.s==1) & b.is_nan):
140 # m.d.comb += self.out_do_z.eq(1)
141 # m.d.comb += z.create(a.s & b.s, b.e, Cat(b.m[3:-2], 1))
143 ## if b is -zero and a is NaN return -a
144 #with m.Elif(b.is_zero & (b.s==1) & a.is_nan):
145 # m.d.comb += self.out_do_z.eq(1)
146 # m.d.comb += z.create(a.s & b.s, a.e, Cat(a.m[3:-2], 1))
148 # if a is inf return inf (or NaN)
149 with m
.Elif(self
.in_a
.is_inf
):
150 m
.d
.comb
+= self
.out_do_z
.eq(1)
151 m
.d
.comb
+= self
.out_z
.inf(self
.in_a
.s
)
152 # if a is inf and signs don't match return NaN
153 with m
.If(self
.in_b
.exp_128
& s_nomatch
):
154 m
.d
.comb
+= self
.out_z
.nan(0)
156 # if b is inf return inf
157 with m
.Elif(self
.in_b
.is_inf
):
158 m
.d
.comb
+= self
.out_do_z
.eq(1)
159 m
.d
.comb
+= self
.out_z
.inf(self
.in_b
.s
)
161 # if a is zero and b zero return signed-a/b
162 with m
.Elif(self
.in_a
.is_zero
& self
.in_b
.is_zero
):
163 m
.d
.comb
+= self
.out_do_z
.eq(1)
164 m
.d
.comb
+= self
.out_z
.create(self
.in_a
.s
& self
.in_b
.s
,
168 # if a is zero return b
169 with m
.Elif(self
.in_a
.is_zero
):
170 m
.d
.comb
+= self
.out_do_z
.eq(1)
171 m
.d
.comb
+= self
.out_z
.create(self
.in_b
.s
, self
.in_b
.e
,
174 # if b is zero return a
175 with m
.Elif(self
.in_b
.is_zero
):
176 m
.d
.comb
+= self
.out_do_z
.eq(1)
177 m
.d
.comb
+= self
.out_z
.create(self
.in_a
.s
, self
.in_a
.e
,
180 # if a equal to -b return zero (+ve zero)
181 with m
.Elif(s_nomatch
& m_match
& (self
.in_a
.e
== self
.in_b
.e
)):
182 m
.d
.comb
+= self
.out_do_z
.eq(1)
183 m
.d
.comb
+= self
.out_z
.zero(0)
185 # Denormalised Number checks
187 m
.d
.comb
+= self
.out_do_z
.eq(0)
192 class FPAddSpecialCases(FPState
):
193 """ special cases: NaNs, infs, zeros, denormalised
194 NOTE: some of these are unique to add. see "Special Operations"
195 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
198 def __init__(self
, width
):
199 FPState
.__init
__(self
, "special_cases")
200 self
.mod
= FPAddSpecialCasesMod(width
)
201 self
.out_z
= FPNumOut(width
, False)
202 self
.out_do_z
= Signal(reset_less
=True)
205 with m
.If(self
.out_do_z
):
206 m
.d
.sync
+= self
.z
.v
.eq(self
.out_z
.v
) # only take the output
209 m
.next
= "denormalise"
212 class FPAddDeNormMod(FPState
):
214 def __init__(self
, width
):
215 self
.in_a
= FPNumBase(width
)
216 self
.in_b
= FPNumBase(width
)
217 self
.out_a
= FPNumBase(width
)
218 self
.out_b
= FPNumBase(width
)
220 def setup(self
, m
, in_a
, in_b
, out_a
, out_b
):
221 """ links module to inputs and outputs
223 m
.d
.comb
+= self
.in_a
.copy(in_a
)
224 m
.d
.comb
+= self
.in_b
.copy(in_b
)
225 m
.d
.comb
+= out_a
.copy(self
.out_a
)
226 m
.d
.comb
+= out_b
.copy(self
.out_b
)
228 def elaborate(self
, platform
):
230 m
.submodules
.denorm_in_a
= self
.in_a
231 m
.submodules
.denorm_in_b
= self
.in_b
232 m
.submodules
.denorm_out_a
= self
.out_a
233 m
.submodules
.denorm_out_b
= self
.out_b
234 # hmmm, don't like repeating identical code
235 m
.d
.comb
+= self
.out_a
.copy(self
.in_a
)
236 with m
.If(self
.in_a
.exp_n127
):
237 m
.d
.comb
+= self
.out_a
.e
.eq(self
.in_a
.N126
) # limit a exponent
239 m
.d
.comb
+= self
.out_a
.m
[-1].eq(1) # set top mantissa bit
241 m
.d
.comb
+= self
.out_b
.copy(self
.in_b
)
242 with m
.If(self
.in_b
.exp_n127
):
243 m
.d
.comb
+= self
.out_b
.e
.eq(self
.in_b
.N126
) # limit a exponent
245 m
.d
.comb
+= self
.out_b
.m
[-1].eq(1) # set top mantissa bit
250 class FPAddDeNorm(FPState
):
252 def __init__(self
, width
):
253 FPState
.__init
__(self
, "denormalise")
254 self
.mod
= FPAddDeNormMod(width
)
255 self
.out_a
= FPNumBase(width
)
256 self
.out_b
= FPNumBase(width
)
259 # Denormalised Number checks
261 m
.d
.sync
+= self
.a
.copy(self
.out_a
)
262 m
.d
.sync
+= self
.b
.copy(self
.out_b
)
265 class FPAddAlignMultiMod(FPState
):
267 def __init__(self
, width
):
268 self
.in_a
= FPNumBase(width
)
269 self
.in_b
= FPNumBase(width
)
270 self
.out_a
= FPNumIn(None, width
)
271 self
.out_b
= FPNumIn(None, width
)
272 self
.exp_eq
= Signal(reset_less
=True)
274 def setup(self
, m
, in_a
, in_b
, out_a
, out_b
, exp_eq
):
275 """ links module to inputs and outputs
277 m
.d
.comb
+= self
.in_a
.copy(in_a
)
278 m
.d
.comb
+= self
.in_b
.copy(in_b
)
279 m
.d
.comb
+= out_a
.copy(self
.out_a
)
280 m
.d
.comb
+= out_b
.copy(self
.out_b
)
281 m
.d
.comb
+= exp_eq
.eq(self
.exp_eq
)
283 def elaborate(self
, platform
):
284 # This one however (single-cycle) will do the shift
289 #m.submodules.align_in_a = self.in_a
290 #m.submodules.align_in_b = self.in_b
291 m
.submodules
.align_out_a
= self
.out_a
292 m
.submodules
.align_out_b
= self
.out_b
294 # NOTE: this does *not* do single-cycle multi-shifting,
295 # it *STAYS* in the align state until exponents match
297 # exponent of a greater than b: shift b down
298 m
.d
.comb
+= self
.exp_eq
.eq(0)
299 m
.d
.comb
+= self
.out_a
.copy(self
.in_a
)
300 m
.d
.comb
+= self
.out_b
.copy(self
.in_b
)
301 agtb
= Signal(reset_less
=True)
302 altb
= Signal(reset_less
=True)
303 m
.d
.comb
+= agtb
.eq(self
.in_a
.e
> self
.in_b
.e
)
304 m
.d
.comb
+= altb
.eq(self
.in_a
.e
< self
.in_b
.e
)
306 m
.d
.comb
+= self
.out_b
.shift_down(self
.in_b
)
307 # exponent of b greater than a: shift a down
309 m
.d
.comb
+= self
.out_a
.shift_down(self
.in_a
)
310 # exponents equal: move to next stage.
312 m
.d
.comb
+= self
.exp_eq
.eq(1)
316 class FPAddAlignMulti(FPState
):
318 def __init__(self
, width
):
319 FPState
.__init
__(self
, "align")
320 self
.mod
= FPAddAlignMultiMod(width
)
321 self
.out_a
= FPNumIn(None, width
)
322 self
.out_b
= FPNumIn(None, width
)
323 self
.exp_eq
= Signal(reset_less
=True)
326 m
.d
.sync
+= self
.a
.copy(self
.out_a
)
327 m
.d
.sync
+= self
.b
.copy(self
.out_b
)
328 with m
.If(self
.exp_eq
):
332 class FPAddAlignSingleMod
:
334 def __init__(self
, width
):
335 self
.in_a
= FPNumBase(width
)
336 self
.in_b
= FPNumBase(width
)
337 self
.out_a
= FPNumIn(None, width
)
338 self
.out_b
= FPNumIn(None, width
)
339 #self.out_a = FPNumBase(width)
340 #self.out_b = FPNumBase(width)
342 def setup(self
, m
, in_a
, in_b
, out_a
, out_b
):
343 """ links module to inputs and outputs
345 m
.d
.comb
+= self
.in_a
.copy(in_a
)
346 m
.d
.comb
+= self
.in_b
.copy(in_b
)
347 m
.d
.comb
+= out_a
.copy(self
.out_a
)
348 m
.d
.comb
+= out_b
.copy(self
.out_b
)
350 def elaborate(self
, platform
):
351 # This one however (single-cycle) will do the shift
356 #m.submodules.align_in_a = self.in_a
357 #m.submodules.align_in_b = self.in_b
358 m
.submodules
.align_out_a
= self
.out_a
359 m
.submodules
.align_out_b
= self
.out_b
361 # XXX TODO: the shifter used here is quite expensive
362 # having only one would be better
364 ediff
= Signal((len(self
.in_a
.e
), True), reset_less
=True)
365 ediffr
= Signal((len(self
.in_a
.e
), True), reset_less
=True)
366 m
.d
.comb
+= ediff
.eq(self
.in_a
.e
- self
.in_b
.e
)
367 m
.d
.comb
+= ediffr
.eq(self
.in_b
.e
- self
.in_a
.e
)
368 m
.d
.comb
+= self
.out_a
.copy(self
.in_a
)
369 m
.d
.comb
+= self
.out_b
.copy(self
.in_b
)
370 with m
.If(ediff
> 0):
371 m
.d
.comb
+= self
.out_b
.shift_down_multi(ediff
)
372 # exponent of b greater than a: shift a down
373 with m
.Elif(ediff
< 0):
374 m
.d
.comb
+= self
.out_a
.shift_down_multi(ediffr
)
378 class FPAddAlignSingle(FPState
):
380 def __init__(self
, width
):
381 FPState
.__init
__(self
, "align")
382 self
.mod
= FPAddAlignSingleMod(width
)
383 self
.out_a
= FPNumIn(None, width
)
384 self
.out_b
= FPNumIn(None, width
)
387 m
.d
.sync
+= self
.a
.copy(self
.out_a
)
388 m
.d
.sync
+= self
.b
.copy(self
.out_b
)
392 class FPAddStage0Mod
:
394 def __init__(self
, width
):
395 self
.in_a
= FPNumBase(width
)
396 self
.in_b
= FPNumBase(width
)
397 self
.in_z
= FPNumBase(width
, False)
398 self
.out_z
= FPNumBase(width
, False)
399 self
.out_tot
= Signal(self
.out_z
.m_width
+ 4, reset_less
=True)
401 def setup(self
, m
, in_a
, in_b
, in_z
, out_z
, out_tot
):
402 """ links module to inputs and outputs
404 m
.d
.comb
+= self
.in_a
.copy(in_a
)
405 m
.d
.comb
+= self
.in_b
.copy(in_b
)
406 m
.d
.comb
+= self
.in_z
.copy(in_z
)
407 m
.d
.comb
+= out_z
.copy(self
.out_z
)
408 m
.d
.comb
+= out_tot
.eq(self
.out_tot
)
410 def elaborate(self
, platform
):
412 m
.submodules
.add0_in_a
= self
.in_a
413 m
.submodules
.add0_in_b
= self
.in_b
414 #m.submodules.add0_in_z = self.in_z
415 #m.submodules.add0_out_z = self.out_z
417 m
.d
.comb
+= self
.out_z
.e
.eq(self
.in_a
.e
)
418 # same-sign (both negative or both positive) add mantissas
419 with m
.If(self
.in_a
.s
== self
.in_b
.s
):
421 self
.out_tot
.eq(Cat(self
.in_a
.m
, 0) + Cat(self
.in_b
.m
, 0)),
422 self
.out_z
.s
.eq(self
.in_a
.s
)
424 # a mantissa greater than b, use a
425 with m
.Elif(self
.in_a
.m
>= self
.in_b
.m
):
427 self
.out_tot
.eq(Cat(self
.in_a
.m
, 0) - Cat(self
.in_b
.m
, 0)),
428 self
.out_z
.s
.eq(self
.in_a
.s
)
430 # b mantissa greater than a, use b
433 self
.out_tot
.eq(Cat(self
.in_b
.m
, 0) - Cat(self
.in_a
.m
, 0)),
434 self
.out_z
.s
.eq(self
.in_b
.s
)
439 class FPAddStage0(FPState
):
440 """ First stage of add. covers same-sign (add) and subtract
441 special-casing when mantissas are greater or equal, to
442 give greatest accuracy.
445 def __init__(self
, width
):
446 FPState
.__init
__(self
, "add_0")
447 self
.mod
= FPAddStage0Mod(width
)
448 self
.out_z
= FPNumBase(width
, False)
449 self
.out_tot
= Signal(self
.out_z
.m_width
+ 4, reset_less
=True)
453 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
456 class FPAddStage1Mod(FPState
):
457 """ Second stage of add: preparation for normalisation.
458 detects when tot sum is too big (tot[27] is kinda a carry bit)
461 def __init__(self
, width
):
462 self
.out_norm
= Signal(reset_less
=True)
463 self
.in_z
= FPNumBase(width
, False)
464 self
.in_tot
= Signal(self
.in_z
.m_width
+ 4, reset_less
=True)
465 self
.out_z
= FPNumBase(width
, False)
466 self
.out_of
= Overflow()
468 def setup(self
, m
, in_tot
, in_z
, out_z
, out_of
):
469 """ links module to inputs and outputs
471 m
.d
.comb
+= self
.in_z
.copy(in_z
)
472 m
.d
.comb
+= self
.in_tot
.eq(in_tot
)
473 m
.d
.comb
+= out_z
.copy(self
.out_z
)
474 m
.d
.comb
+= out_of
.copy(self
.out_of
)
476 def elaborate(self
, platform
):
478 #m.submodules.norm1_in_overflow = self.in_of
479 #m.submodules.norm1_out_overflow = self.out_of
480 #m.submodules.norm1_in_z = self.in_z
481 #m.submodules.norm1_out_z = self.out_z
482 m
.d
.comb
+= self
.out_z
.copy(self
.in_z
)
483 # tot[27] gets set when the sum overflows. shift result down
484 with m
.If(self
.in_tot
[-1]):
486 self
.out_z
.m
.eq(self
.in_tot
[4:]),
487 self
.out_of
.m0
.eq(self
.in_tot
[4]),
488 self
.out_of
.guard
.eq(self
.in_tot
[3]),
489 self
.out_of
.round_bit
.eq(self
.in_tot
[2]),
490 self
.out_of
.sticky
.eq(self
.in_tot
[1] | self
.in_tot
[0]),
491 self
.out_z
.e
.eq(self
.in_z
.e
+ 1)
496 self
.out_z
.m
.eq(self
.in_tot
[3:]),
497 self
.out_of
.m0
.eq(self
.in_tot
[3]),
498 self
.out_of
.guard
.eq(self
.in_tot
[2]),
499 self
.out_of
.round_bit
.eq(self
.in_tot
[1]),
500 self
.out_of
.sticky
.eq(self
.in_tot
[0])
505 class FPAddStage1(FPState
):
507 def __init__(self
, width
):
508 FPState
.__init
__(self
, "add_1")
509 self
.mod
= FPAddStage1Mod(width
)
510 self
.out_z
= FPNumBase(width
, False)
511 self
.out_of
= Overflow()
514 m
.d
.sync
+= self
.of
.copy(self
.out_of
)
515 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
516 m
.next
= "normalise_1"
521 def __init__(self
, width
):
522 self
.out_norm
= Signal(reset_less
=True)
523 self
.in_z
= FPNumBase(width
, False)
524 self
.out_z
= FPNumBase(width
, False)
525 self
.in_of
= Overflow()
526 self
.out_of
= Overflow()
528 def setup(self
, m
, in_z
, out_z
, in_of
, out_of
, out_norm
):
529 """ links module to inputs and outputs
531 m
.d
.comb
+= self
.in_z
.copy(in_z
)
532 m
.d
.comb
+= out_z
.copy(self
.out_z
)
533 m
.d
.comb
+= self
.in_of
.copy(in_of
)
534 m
.d
.comb
+= out_of
.copy(self
.out_of
)
535 m
.d
.comb
+= out_norm
.eq(self
.out_norm
)
537 def elaborate(self
, platform
):
539 m
.submodules
.norm1_in_overflow
= self
.in_of
540 m
.submodules
.norm1_out_overflow
= self
.out_of
541 m
.submodules
.norm1_in_z
= self
.in_z
542 m
.submodules
.norm1_out_z
= self
.out_z
543 m
.d
.comb
+= self
.out_z
.copy(self
.in_z
)
544 m
.d
.comb
+= self
.out_of
.copy(self
.in_of
)
545 m
.d
.comb
+= self
.out_norm
.eq((self
.in_z
.m_msbzero
) & \
546 (self
.in_z
.exp_gt_n126
))
547 with m
.If(self
.out_norm
):
549 self
.out_z
.e
.eq(self
.in_z
.e
- 1), # DECREASE exponent
550 self
.out_z
.m
.eq(self
.in_z
.m
<< 1), # shift mantissa UP
551 self
.out_z
.m
[0].eq(self
.in_of
.guard
), # steal guard (was tot[2])
552 self
.out_of
.guard
.eq(self
.in_of
.round_bit
), # round (was tot[1])
553 self
.out_of
.round_bit
.eq(0), # reset round bit
554 self
.out_of
.m0
.eq(self
.in_of
.guard
),
560 class FPNorm1(FPState
):
562 def __init__(self
, width
):
563 FPState
.__init
__(self
, "normalise_1")
564 self
.mod
= FPNorm1Mod(width
)
565 self
.out_norm
= Signal(reset_less
=True)
566 self
.out_z
= FPNumBase(width
)
567 self
.out_of
= Overflow()
570 m
.d
.sync
+= self
.of
.copy(self
.out_of
)
571 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
572 with m
.If(~self
.out_norm
):
573 m
.next
= "normalise_2"
578 def __init__(self
, width
):
579 self
.out_norm
= Signal(reset_less
=True)
580 self
.in_z
= FPNumBase(width
, False)
581 self
.out_z
= FPNumBase(width
, False)
582 self
.in_of
= Overflow()
583 self
.out_of
= Overflow()
585 def setup(self
, m
, in_z
, out_z
, in_of
, out_of
, out_norm
):
586 """ links module to inputs and outputs
588 m
.d
.comb
+= self
.in_z
.copy(in_z
)
589 m
.d
.comb
+= out_z
.copy(self
.out_z
)
590 m
.d
.comb
+= self
.in_of
.copy(in_of
)
591 m
.d
.comb
+= out_of
.copy(self
.out_of
)
592 m
.d
.comb
+= out_norm
.eq(self
.out_norm
)
594 def elaborate(self
, platform
):
596 m
.submodules
.norm2_in_overflow
= self
.in_of
597 m
.submodules
.norm2_out_overflow
= self
.out_of
598 m
.submodules
.norm2_in_z
= self
.in_z
599 m
.submodules
.norm2_out_z
= self
.out_z
600 m
.d
.comb
+= self
.out_z
.copy(self
.in_z
)
601 m
.d
.comb
+= self
.out_of
.copy(self
.in_of
)
602 m
.d
.comb
+= self
.out_norm
.eq(self
.in_z
.exp_lt_n126
)
603 with m
.If(self
.out_norm
):
605 self
.out_z
.e
.eq(self
.in_z
.e
+ 1), # INCREASE exponent
606 self
.out_z
.m
.eq(self
.in_z
.m
>> 1), # shift mantissa DOWN
607 self
.out_of
.guard
.eq(self
.in_z
.m
[0]),
608 self
.out_of
.m0
.eq(self
.in_z
.m
[1]),
609 self
.out_of
.round_bit
.eq(self
.in_of
.guard
),
610 self
.out_of
.sticky
.eq(self
.in_of
.sticky | self
.in_of
.round_bit
)
616 class FPNorm2(FPState
):
618 def __init__(self
, width
):
619 FPState
.__init
__(self
, "normalise_2")
620 self
.mod
= FPNorm2Mod(width
)
621 self
.out_norm
= Signal(reset_less
=True)
622 self
.out_z
= FPNumBase(width
)
623 self
.out_of
= Overflow()
626 #m.d.sync += self.of.copy(self.out_of)
627 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
628 with m
.If(~self
.out_norm
):
634 def __init__(self
, width
):
635 self
.in_roundz
= Signal(reset_less
=True)
636 self
.in_z
= FPNumBase(width
, False)
637 self
.out_z
= FPNumBase(width
, False)
639 def setup(self
, m
, in_z
, out_z
, in_of
):
640 """ links module to inputs and outputs
642 m
.d
.comb
+= self
.in_z
.copy(in_z
)
643 m
.d
.comb
+= out_z
.copy(self
.out_z
)
644 m
.d
.comb
+= self
.in_roundz
.eq(in_of
.roundz
)
646 def elaborate(self
, platform
):
648 m
.d
.comb
+= self
.out_z
.copy(self
.in_z
)
649 with m
.If(self
.in_roundz
):
650 m
.d
.comb
+= self
.out_z
.m
.eq(self
.in_z
.m
+ 1) # mantissa rounds up
651 with m
.If(self
.in_z
.m
== self
.in_z
.m1s
): # all 1s
652 m
.d
.comb
+= self
.out_z
.e
.eq(self
.in_z
.e
+ 1) # exponent up
656 class FPRound(FPState
):
658 def __init__(self
, width
):
659 FPState
.__init
__(self
, "round")
660 self
.mod
= FPRoundMod(width
)
661 self
.out_z
= FPNumBase(width
)
664 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
665 m
.next
= "corrections"
668 class FPCorrectionsMod
:
670 def __init__(self
, width
):
671 self
.in_z
= FPNumOut(width
, False)
672 self
.out_z
= FPNumOut(width
, False)
674 def setup(self
, m
, in_z
, out_z
):
675 """ links module to inputs and outputs
677 m
.d
.comb
+= self
.in_z
.copy(in_z
)
678 m
.d
.comb
+= out_z
.copy(self
.out_z
)
680 def elaborate(self
, platform
):
682 m
.submodules
.corr_in_z
= self
.in_z
683 m
.submodules
.corr_out_z
= self
.out_z
684 m
.d
.comb
+= self
.out_z
.copy(self
.in_z
)
685 with m
.If(self
.in_z
.is_denormalised
):
686 m
.d
.comb
+= self
.out_z
.e
.eq(self
.in_z
.N127
)
688 # with m.If(self.in_z.is_overflowed):
689 # m.d.comb += self.out_z.inf(self.in_z.s)
691 # m.d.comb += self.out_z.create(self.in_z.s, self.in_z.e, self.in_z.m)
695 class FPCorrections(FPState
):
697 def __init__(self
, width
):
698 FPState
.__init
__(self
, "corrections")
699 self
.mod
= FPCorrectionsMod(width
)
700 self
.out_z
= FPNumBase(width
)
703 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
709 def __init__(self
, width
):
710 self
.in_z
= FPNumOut(width
, False)
711 self
.out_z
= FPNumOut(width
, False)
713 def setup(self
, m
, in_z
, out_z
):
714 """ links module to inputs and outputs
716 m
.d
.comb
+= self
.in_z
.copy(in_z
)
717 m
.d
.comb
+= out_z
.v
.eq(self
.out_z
.v
)
719 def elaborate(self
, platform
):
721 m
.submodules
.pack_in_z
= self
.in_z
722 with m
.If(self
.in_z
.is_overflowed
):
723 m
.d
.comb
+= self
.out_z
.inf(self
.in_z
.s
)
725 m
.d
.comb
+= self
.out_z
.create(self
.in_z
.s
, self
.in_z
.e
, self
.in_z
.m
)
729 class FPPack(FPState
):
731 def __init__(self
, width
):
732 FPState
.__init
__(self
, "pack")
733 self
.mod
= FPPackMod(width
)
734 self
.out_z
= FPNumOut(width
, False)
737 m
.d
.sync
+= self
.z
.v
.eq(self
.out_z
.v
)
741 class FPPutZ(FPState
):
744 self
.put_z(m
, self
.z
, self
.out_z
, "get_a")
749 def __init__(self
, width
, single_cycle
=False):
751 self
.single_cycle
= single_cycle
753 self
.in_a
= FPOp(width
)
754 self
.in_b
= FPOp(width
)
755 self
.out_z
= FPOp(width
)
759 def add_state(self
, state
):
760 self
.states
.append(state
)
763 def get_fragment(self
, platform
=None):
764 """ creates the HDL code-fragment for FPAdd
769 #a = FPNumIn(self.in_a, self.width)
770 #b = FPNumIn(self.in_b, self.width)
771 z
= FPNumOut(self
.width
, False)
773 #m.submodules.fpnum_b = b
774 m
.submodules
.fpnum_z
= z
779 m
.submodules
.overflow
= of
781 geta
= self
.add_state(FPGetOp("get_a", "get_b", self
.in_a
, self
.width
))
782 #geta.set_inputs({"in_a": self.in_a})
783 #geta.set_outputs({"a": a})
785 # XXX m.d.comb += a.v.eq(self.in_a.v) # links in_a to a
786 geta
.mod
.setup(m
, self
.in_a
, geta
.out_op
, geta
.out_decode
)
787 m
.submodules
.get_a
= geta
.mod
788 #m.submodules.fpnum_a = a
790 getb
= self
.add_state(FPGetOp("get_b", "special_cases",
791 self
.in_b
, self
.width
))
792 #getb.set_inputs({"in_b": self.in_b})
793 #getb.set_outputs({"b": b})
795 getb
.mod
.setup(m
, self
.in_b
, getb
.out_op
, getb
.out_decode
)
796 # XXX m.d.comb += b.v.eq(self.in_b.v) # links in_b to b
797 m
.submodules
.get_b
= getb
.mod
798 #m.submodules.fpnum_b = b
800 sc
= self
.add_state(FPAddSpecialCases(self
.width
))
801 sc
.set_inputs({"a": a
, "b": b
})
802 sc
.set_outputs({"z": z
})
803 sc
.mod
.setup(m
, a
, b
, sc
.out_z
, sc
.out_do_z
)
804 m
.submodules
.specialcases
= sc
.mod
806 dn
= self
.add_state(FPAddDeNorm(self
.width
))
807 dn
.set_inputs({"a": a
, "b": b
})
808 dn
.set_outputs({"a": a
, "b": b
}) # XXX outputs same as inputs
809 dn
.mod
.setup(m
, a
, b
, dn
.out_a
, dn
.out_b
)
810 m
.submodules
.denormalise
= dn
.mod
812 if self
.single_cycle
:
813 alm
= self
.add_state(FPAddAlignSingle(self
.width
))
814 alm
.set_inputs({"a": a
, "b": b
})
815 alm
.set_outputs({"a": a
, "b": b
}) # XXX outputs same as inputs
816 alm
.mod
.setup(m
, a
, b
, alm
.out_a
, alm
.out_b
)
818 alm
= self
.add_state(FPAddAlignMulti(self
.width
))
819 alm
.set_inputs({"a": a
, "b": b
})
820 alm
.set_outputs({"a": a
, "b": b
}) # XXX outputs same as inputs
821 alm
.mod
.setup(m
, a
, b
, alm
.out_a
, alm
.out_b
, alm
.exp_eq
)
822 m
.submodules
.align
= alm
.mod
824 add0
= self
.add_state(FPAddStage0(self
.width
))
825 add0
.set_inputs({"a": a
, "b": b
})
826 add0
.set_outputs({"z": z
})
827 add0
.mod
.setup(m
, a
, b
, z
, add0
.out_z
, add0
.out_tot
)
828 m
.submodules
.add0
= add0
.mod
830 add1
= self
.add_state(FPAddStage1(self
.width
))
831 add1
.set_inputs({"tot": add0
.out_tot
, "z": add0
.out_z
})
832 add1
.set_outputs({"z": z
, "of": of
}) # XXX Z as output
833 add1
.mod
.setup(m
, add0
.out_tot
, z
, add1
.out_z
, add1
.out_of
)
834 m
.submodules
.add1
= add1
.mod
836 n1
= self
.add_state(FPNorm1(self
.width
))
837 n1
.set_inputs({"z": z
, "of": of
}) # XXX Z as output
838 n1
.set_outputs({"z": z
}) # XXX Z as output
839 n1
.mod
.setup(m
, z
, n1
.out_z
, of
, n1
.out_of
, n1
.out_norm
)
840 m
.submodules
.normalise_1
= n1
.mod
842 n2
= self
.add_state(FPNorm2(self
.width
))
843 n2
.set_inputs({"z": n1
.out_z
, "of": n1
.out_of
})
844 n2
.set_outputs({"z": z
})
845 n2
.mod
.setup(m
, n1
.out_z
, n2
.out_z
, of
, n2
.out_of
, n2
.out_norm
)
846 m
.submodules
.normalise_2
= n2
.mod
848 rn
= self
.add_state(FPRound(self
.width
))
849 rn
.set_inputs({"z": n2
.out_z
, "of": n2
.out_of
})
850 rn
.set_outputs({"z": z
})
851 rn
.mod
.setup(m
, n2
.out_z
, rn
.out_z
, of
)
852 m
.submodules
.roundz
= rn
.mod
854 cor
= self
.add_state(FPCorrections(self
.width
))
855 cor
.set_inputs({"z": z
}) # XXX Z as output
856 cor
.set_outputs({"z": z
}) # XXX Z as output
857 cor
.mod
.setup(m
, z
, cor
.out_z
)
858 m
.submodules
.corrections
= cor
.mod
860 pa
= self
.add_state(FPPack(self
.width
))
861 pa
.set_inputs({"z": z
}) # XXX Z as output
862 pa
.set_outputs({"z": z
}) # XXX Z as output
863 pa
.mod
.setup(m
, z
, pa
.out_z
)
864 m
.submodules
.pack
= pa
.mod
866 pz
= self
.add_state(FPPutZ("put_z"))
867 pz
.set_inputs({"z": z
})
868 pz
.set_outputs({"out_z": self
.out_z
})
872 for state
in self
.states
:
873 with m
.State(state
.state_from
):
879 if __name__
== "__main__":
880 alu
= FPADD(width
=32)
881 main(alu
, ports
=alu
.in_a
.ports() + alu
.in_b
.ports() + alu
.out_z
.ports())
884 # works... but don't use, just do "python fname.py convert -t v"
885 #print (verilog.convert(alu, ports=[
886 # ports=alu.in_a.ports() + \
887 # alu.in_b.ports() + \