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():
26 class FPGetOpA(FPState
):
30 def __init__(self
, in_a
, width
):
31 FPState
.__init
__(self
, "get_a")
33 self
.a
= FPNumIn(in_a
, width
)
36 self
.get_op(m
, self
.in_a
, self
.a
, "get_b")
39 class FPGetOpB(FPState
):
43 def __init__(self
, in_b
, width
):
44 FPState
.__init
__(self
, "get_b")
46 self
.b
= FPNumIn(self
.in_b
, width
)
49 self
.get_op(m
, self
.in_b
, self
.b
, "special_cases")
52 class FPAddSpecialCasesMod
:
53 """ special cases: NaNs, infs, zeros, denormalised
54 NOTE: some of these are unique to add. see "Special Operations"
55 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
58 def __init__(self
, width
):
59 self
.in_a
= FPNumBase(width
)
60 self
.in_b
= FPNumBase(width
)
61 self
.out_z
= FPNumOut(width
, False)
62 self
.out_do_z
= Signal(reset_less
=True)
64 def setup(self
, m
, in_a
, in_b
, out_z
, out_do_z
):
65 """ links module to inputs and outputs
67 m
.d
.comb
+= self
.in_a
.copy(in_a
)
68 m
.d
.comb
+= self
.in_b
.copy(in_b
)
69 m
.d
.comb
+= out_z
.v
.eq(self
.out_z
.v
)
70 m
.d
.comb
+= out_do_z
.eq(self
.out_do_z
)
72 def elaborate(self
, platform
):
75 m
.submodules
.sc_in_a
= self
.in_a
76 m
.submodules
.sc_in_b
= self
.in_b
77 m
.submodules
.sc_out_z
= self
.out_z
80 m
.d
.comb
+= s_nomatch
.eq(self
.in_a
.s
!= self
.in_b
.s
)
83 m
.d
.comb
+= m_match
.eq(self
.in_a
.m
== self
.in_b
.m
)
85 # if a is NaN or b is NaN return NaN
86 with m
.If(self
.in_a
.is_nan | self
.in_b
.is_nan
):
87 m
.d
.comb
+= self
.out_do_z
.eq(1)
88 m
.d
.comb
+= self
.out_z
.nan(0)
90 # XXX WEIRDNESS for FP16 non-canonical NaN handling
93 ## if a is zero and b is NaN return -b
94 #with m.If(a.is_zero & (a.s==0) & b.is_nan):
95 # m.d.comb += self.out_do_z.eq(1)
96 # m.d.comb += z.create(b.s, b.e, Cat(b.m[3:-2], ~b.m[0]))
98 ## if b is zero and a is NaN return -a
99 #with m.Elif(b.is_zero & (b.s==0) & a.is_nan):
100 # m.d.comb += self.out_do_z.eq(1)
101 # m.d.comb += z.create(a.s, a.e, Cat(a.m[3:-2], ~a.m[0]))
103 ## if a is -zero and b is NaN return -b
104 #with m.Elif(a.is_zero & (a.s==1) & b.is_nan):
105 # m.d.comb += self.out_do_z.eq(1)
106 # m.d.comb += z.create(a.s & b.s, b.e, Cat(b.m[3:-2], 1))
108 ## if b is -zero and a is NaN return -a
109 #with m.Elif(b.is_zero & (b.s==1) & a.is_nan):
110 # m.d.comb += self.out_do_z.eq(1)
111 # m.d.comb += z.create(a.s & b.s, a.e, Cat(a.m[3:-2], 1))
113 # if a is inf return inf (or NaN)
114 with m
.Elif(self
.in_a
.is_inf
):
115 m
.d
.comb
+= self
.out_do_z
.eq(1)
116 m
.d
.comb
+= self
.out_z
.inf(self
.in_a
.s
)
117 # if a is inf and signs don't match return NaN
118 with m
.If(self
.in_b
.exp_128
& s_nomatch
):
119 m
.d
.comb
+= self
.out_z
.nan(0)
121 # if b is inf return inf
122 with m
.Elif(self
.in_b
.is_inf
):
123 m
.d
.comb
+= self
.out_do_z
.eq(1)
124 m
.d
.comb
+= self
.out_z
.inf(self
.in_b
.s
)
126 # if a is zero and b zero return signed-a/b
127 with m
.Elif(self
.in_a
.is_zero
& self
.in_b
.is_zero
):
128 m
.d
.comb
+= self
.out_do_z
.eq(1)
129 m
.d
.comb
+= self
.out_z
.create(self
.in_a
.s
& self
.in_b
.s
,
133 # if a is zero return b
134 with m
.Elif(self
.in_a
.is_zero
):
135 m
.d
.comb
+= self
.out_do_z
.eq(1)
136 m
.d
.comb
+= self
.out_z
.create(self
.in_b
.s
, self
.in_b
.e
,
139 # if b is zero return a
140 with m
.Elif(self
.in_b
.is_zero
):
141 m
.d
.comb
+= self
.out_do_z
.eq(1)
142 m
.d
.comb
+= self
.out_z
.create(self
.in_a
.s
, self
.in_a
.e
,
145 # if a equal to -b return zero (+ve zero)
146 with m
.Elif(s_nomatch
& m_match
& (self
.in_a
.e
== self
.in_b
.e
)):
147 m
.d
.comb
+= self
.out_do_z
.eq(1)
148 m
.d
.comb
+= self
.out_z
.zero(0)
150 # Denormalised Number checks
152 m
.d
.comb
+= self
.out_do_z
.eq(0)
157 class FPAddSpecialCases(FPState
):
158 """ special cases: NaNs, infs, zeros, denormalised
159 NOTE: some of these are unique to add. see "Special Operations"
160 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
163 def __init__(self
, width
):
164 FPState
.__init
__(self
, "special_cases")
165 self
.mod
= FPAddSpecialCasesMod(width
)
166 self
.out_z
= FPNumOut(width
, False)
167 self
.out_do_z
= Signal(reset_less
=True)
170 with m
.If(self
.out_do_z
):
171 m
.d
.sync
+= self
.z
.v
.eq(self
.out_z
.v
) # only take the output
174 m
.next
= "denormalise"
177 class FPAddDeNormMod(FPState
):
179 def __init__(self
, width
):
180 self
.in_a
= FPNumBase(width
)
181 self
.in_b
= FPNumBase(width
)
182 self
.out_a
= FPNumBase(width
)
183 self
.out_b
= FPNumBase(width
)
185 def setup(self
, m
, in_a
, in_b
, out_a
, out_b
):
186 """ links module to inputs and outputs
188 m
.d
.comb
+= self
.in_a
.copy(in_a
)
189 m
.d
.comb
+= self
.in_b
.copy(in_b
)
190 m
.d
.comb
+= out_a
.copy(self
.out_a
)
191 m
.d
.comb
+= out_b
.copy(self
.out_b
)
193 def elaborate(self
, platform
):
195 m
.submodules
.denorm_in_a
= self
.in_a
196 m
.submodules
.denorm_in_b
= self
.in_b
197 m
.submodules
.denorm_out_a
= self
.out_a
198 m
.submodules
.denorm_out_b
= self
.out_b
199 # hmmm, don't like repeating identical code
200 m
.d
.comb
+= self
.out_a
.copy(self
.in_a
)
201 with m
.If(self
.in_a
.exp_n127
):
202 m
.d
.comb
+= self
.out_a
.e
.eq(self
.in_a
.N126
) # limit a exponent
204 m
.d
.comb
+= self
.out_a
.m
[-1].eq(1) # set top mantissa bit
206 m
.d
.comb
+= self
.out_b
.copy(self
.in_b
)
207 with m
.If(self
.in_b
.exp_n127
):
208 m
.d
.comb
+= self
.out_b
.e
.eq(self
.in_b
.N126
) # limit a exponent
210 m
.d
.comb
+= self
.out_b
.m
[-1].eq(1) # set top mantissa bit
215 class FPAddDeNorm(FPState
):
217 def __init__(self
, width
):
218 FPState
.__init
__(self
, "denormalise")
219 self
.mod
= FPAddDeNormMod(width
)
220 self
.out_a
= FPNumBase(width
)
221 self
.out_b
= FPNumBase(width
)
224 # Denormalised Number checks
226 m
.d
.sync
+= self
.a
.copy(self
.out_a
)
227 m
.d
.sync
+= self
.b
.copy(self
.out_b
)
230 class FPAddAlignMultiMod(FPState
):
232 def __init__(self
, width
):
233 self
.in_a
= FPNumBase(width
)
234 self
.in_b
= FPNumBase(width
)
235 self
.out_a
= FPNumIn(None, width
)
236 self
.out_b
= FPNumIn(None, width
)
237 self
.exp_eq
= Signal(reset_less
=True)
239 def setup(self
, m
, in_a
, in_b
, out_a
, out_b
, exp_eq
):
240 """ links module to inputs and outputs
242 m
.d
.comb
+= self
.in_a
.copy(in_a
)
243 m
.d
.comb
+= self
.in_b
.copy(in_b
)
244 m
.d
.comb
+= out_a
.copy(self
.out_a
)
245 m
.d
.comb
+= out_b
.copy(self
.out_b
)
246 m
.d
.comb
+= exp_eq
.eq(self
.exp_eq
)
248 def elaborate(self
, platform
):
249 # This one however (single-cycle) will do the shift
254 #m.submodules.align_in_a = self.in_a
255 #m.submodules.align_in_b = self.in_b
256 m
.submodules
.align_out_a
= self
.out_a
257 m
.submodules
.align_out_b
= self
.out_b
259 # NOTE: this does *not* do single-cycle multi-shifting,
260 # it *STAYS* in the align state until exponents match
262 # exponent of a greater than b: shift b down
263 m
.d
.comb
+= self
.exp_eq
.eq(0)
264 m
.d
.comb
+= self
.out_a
.copy(self
.in_a
)
265 m
.d
.comb
+= self
.out_b
.copy(self
.in_b
)
266 agtb
= Signal(reset_less
=True)
267 altb
= Signal(reset_less
=True)
268 m
.d
.comb
+= agtb
.eq(self
.in_a
.e
> self
.in_b
.e
)
269 m
.d
.comb
+= altb
.eq(self
.in_a
.e
< self
.in_b
.e
)
271 m
.d
.comb
+= self
.out_b
.shift_down(self
.in_b
)
272 # exponent of b greater than a: shift a down
274 m
.d
.comb
+= self
.out_a
.shift_down(self
.in_a
)
275 # exponents equal: move to next stage.
277 m
.d
.comb
+= self
.exp_eq
.eq(1)
281 class FPAddAlignMulti(FPState
):
283 def __init__(self
, width
):
284 FPState
.__init
__(self
, "align")
285 self
.mod
= FPAddAlignMultiMod(width
)
286 self
.out_a
= FPNumIn(None, width
)
287 self
.out_b
= FPNumIn(None, width
)
288 self
.exp_eq
= Signal(reset_less
=True)
291 m
.d
.sync
+= self
.a
.copy(self
.out_a
)
292 m
.d
.sync
+= self
.b
.copy(self
.out_b
)
293 with m
.If(self
.exp_eq
):
297 class FPAddAlignSingleMod
:
299 def __init__(self
, width
):
300 self
.in_a
= FPNumBase(width
)
301 self
.in_b
= FPNumBase(width
)
302 self
.out_a
= FPNumIn(None, width
)
303 self
.out_b
= FPNumIn(None, width
)
304 #self.out_a = FPNumBase(width)
305 #self.out_b = FPNumBase(width)
307 def setup(self
, m
, in_a
, in_b
, out_a
, out_b
):
308 """ links module to inputs and outputs
310 m
.d
.comb
+= self
.in_a
.copy(in_a
)
311 m
.d
.comb
+= self
.in_b
.copy(in_b
)
312 m
.d
.comb
+= out_a
.copy(self
.out_a
)
313 m
.d
.comb
+= out_b
.copy(self
.out_b
)
315 def elaborate(self
, platform
):
316 # This one however (single-cycle) will do the shift
321 #m.submodules.align_in_a = self.in_a
322 #m.submodules.align_in_b = self.in_b
323 m
.submodules
.align_out_a
= self
.out_a
324 m
.submodules
.align_out_b
= self
.out_b
326 # XXX TODO: the shifter used here is quite expensive
327 # having only one would be better
329 ediff
= Signal((len(self
.in_a
.e
), True), reset_less
=True)
330 ediffr
= Signal((len(self
.in_a
.e
), True), reset_less
=True)
331 m
.d
.comb
+= ediff
.eq(self
.in_a
.e
- self
.in_b
.e
)
332 m
.d
.comb
+= ediffr
.eq(self
.in_b
.e
- self
.in_a
.e
)
333 m
.d
.comb
+= self
.out_a
.copy(self
.in_a
)
334 m
.d
.comb
+= self
.out_b
.copy(self
.in_b
)
335 with m
.If(ediff
> 0):
336 m
.d
.comb
+= self
.out_b
.shift_down_multi(ediff
)
337 # exponent of b greater than a: shift a down
338 with m
.Elif(ediff
< 0):
339 m
.d
.comb
+= self
.out_a
.shift_down_multi(ediffr
)
343 class FPAddAlignSingle(FPState
):
345 def __init__(self
, width
):
346 FPState
.__init
__(self
, "align")
347 self
.mod
= FPAddAlignSingleMod(width
)
348 self
.out_a
= FPNumIn(None, width
)
349 self
.out_b
= FPNumIn(None, width
)
352 m
.d
.sync
+= self
.a
.copy(self
.out_a
)
353 m
.d
.sync
+= self
.b
.copy(self
.out_b
)
357 class FPAddStage0Mod
:
359 def __init__(self
, width
):
360 self
.in_a
= FPNumBase(width
)
361 self
.in_b
= FPNumBase(width
)
362 self
.in_z
= FPNumBase(width
, False)
363 self
.out_z
= FPNumBase(width
, False)
364 self
.out_tot
= Signal(self
.out_z
.m_width
+ 4, reset_less
=True)
366 def setup(self
, m
, in_a
, in_b
, in_z
, out_z
, out_tot
):
367 """ links module to inputs and outputs
369 m
.d
.comb
+= self
.in_a
.copy(in_a
)
370 m
.d
.comb
+= self
.in_b
.copy(in_b
)
371 m
.d
.comb
+= self
.in_z
.copy(in_z
)
372 m
.d
.comb
+= out_z
.copy(self
.out_z
)
373 m
.d
.comb
+= out_tot
.eq(self
.out_tot
)
375 def elaborate(self
, platform
):
377 #m.submodules.add0_in_a = self.in_a
378 #m.submodules.add0_in_b = self.in_b
379 #m.submodules.add0_in_z = self.in_z
380 #m.submodules.add0_out_z = self.out_z
382 m
.d
.comb
+= self
.out_z
.e
.eq(self
.in_a
.e
)
383 # same-sign (both negative or both positive) add mantissas
384 with m
.If(self
.in_a
.s
== self
.in_b
.s
):
386 self
.out_tot
.eq(Cat(self
.in_a
.m
, 0) + Cat(self
.in_b
.m
, 0)),
387 self
.out_z
.s
.eq(self
.in_a
.s
)
389 # a mantissa greater than b, use a
390 with m
.Elif(self
.in_a
.m
>= self
.in_b
.m
):
392 self
.out_tot
.eq(Cat(self
.in_a
.m
, 0) - Cat(self
.in_b
.m
, 0)),
393 self
.out_z
.s
.eq(self
.in_a
.s
)
395 # b mantissa greater than a, use b
398 self
.out_tot
.eq(Cat(self
.in_b
.m
, 0) - Cat(self
.in_a
.m
, 0)),
399 self
.out_z
.s
.eq(self
.in_b
.s
)
404 class FPAddStage0(FPState
):
405 """ First stage of add. covers same-sign (add) and subtract
406 special-casing when mantissas are greater or equal, to
407 give greatest accuracy.
410 def __init__(self
, width
):
411 FPState
.__init
__(self
, "add_0")
412 self
.mod
= FPAddStage0Mod(width
)
413 self
.out_z
= FPNumBase(width
, False)
414 self
.out_tot
= Signal(self
.out_z
.m_width
+ 4, reset_less
=True)
418 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
421 class FPAddStage1Mod(FPState
):
422 """ Second stage of add: preparation for normalisation.
423 detects when tot sum is too big (tot[27] is kinda a carry bit)
426 def __init__(self
, width
):
427 self
.out_norm
= Signal(reset_less
=True)
428 self
.in_z
= FPNumBase(width
, False)
429 self
.in_tot
= Signal(self
.in_z
.m_width
+ 4, reset_less
=True)
430 self
.out_z
= FPNumBase(width
, False)
431 self
.out_of
= Overflow()
433 def setup(self
, m
, in_tot
, in_z
, out_z
, out_of
):
434 """ links module to inputs and outputs
436 m
.d
.comb
+= self
.in_z
.copy(in_z
)
437 m
.d
.comb
+= self
.in_tot
.eq(in_tot
)
438 m
.d
.comb
+= out_z
.copy(self
.out_z
)
439 m
.d
.comb
+= out_of
.copy(self
.out_of
)
441 def elaborate(self
, platform
):
443 #m.submodules.norm1_in_overflow = self.in_of
444 #m.submodules.norm1_out_overflow = self.out_of
445 #m.submodules.norm1_in_z = self.in_z
446 #m.submodules.norm1_out_z = self.out_z
447 m
.d
.comb
+= self
.out_z
.copy(self
.in_z
)
448 # tot[27] gets set when the sum overflows. shift result down
449 with m
.If(self
.in_tot
[-1]):
451 self
.out_z
.m
.eq(self
.in_tot
[4:]),
452 self
.out_of
.m0
.eq(self
.in_tot
[4]),
453 self
.out_of
.guard
.eq(self
.in_tot
[3]),
454 self
.out_of
.round_bit
.eq(self
.in_tot
[2]),
455 self
.out_of
.sticky
.eq(self
.in_tot
[1] | self
.in_tot
[0]),
456 self
.out_z
.e
.eq(self
.in_z
.e
+ 1)
461 self
.out_z
.m
.eq(self
.in_tot
[3:]),
462 self
.out_of
.m0
.eq(self
.in_tot
[3]),
463 self
.out_of
.guard
.eq(self
.in_tot
[2]),
464 self
.out_of
.round_bit
.eq(self
.in_tot
[1]),
465 self
.out_of
.sticky
.eq(self
.in_tot
[0])
470 class FPAddStage1(FPState
):
472 def __init__(self
, width
):
473 FPState
.__init
__(self
, "add_1")
474 self
.mod
= FPAddStage1Mod(width
)
475 self
.out_z
= FPNumBase(width
, False)
476 self
.out_of
= Overflow()
479 m
.d
.sync
+= self
.of
.copy(self
.out_of
)
480 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
481 m
.next
= "normalise_1"
486 def __init__(self
, width
):
487 self
.out_norm
= Signal(reset_less
=True)
488 self
.in_z
= FPNumBase(width
, False)
489 self
.out_z
= FPNumBase(width
, False)
490 self
.in_of
= Overflow()
491 self
.out_of
= Overflow()
493 def setup(self
, m
, in_z
, out_z
, in_of
, out_of
, out_norm
):
494 """ links module to inputs and outputs
496 m
.d
.comb
+= self
.in_z
.copy(in_z
)
497 m
.d
.comb
+= out_z
.copy(self
.out_z
)
498 m
.d
.comb
+= self
.in_of
.copy(in_of
)
499 m
.d
.comb
+= out_of
.copy(self
.out_of
)
500 m
.d
.comb
+= out_norm
.eq(self
.out_norm
)
502 def elaborate(self
, platform
):
504 m
.submodules
.norm1_in_overflow
= self
.in_of
505 m
.submodules
.norm1_out_overflow
= self
.out_of
506 m
.submodules
.norm1_in_z
= self
.in_z
507 m
.submodules
.norm1_out_z
= self
.out_z
508 m
.d
.comb
+= self
.out_z
.copy(self
.in_z
)
509 m
.d
.comb
+= self
.out_of
.copy(self
.in_of
)
510 m
.d
.comb
+= self
.out_norm
.eq((self
.in_z
.m_msbzero
) & \
511 (self
.in_z
.exp_gt_n126
))
512 with m
.If(self
.out_norm
):
514 self
.out_z
.e
.eq(self
.in_z
.e
- 1), # DECREASE exponent
515 self
.out_z
.m
.eq(self
.in_z
.m
<< 1), # shift mantissa UP
516 self
.out_z
.m
[0].eq(self
.in_of
.guard
), # steal guard (was tot[2])
517 self
.out_of
.guard
.eq(self
.in_of
.round_bit
), # round (was tot[1])
518 self
.out_of
.round_bit
.eq(0), # reset round bit
519 self
.out_of
.m0
.eq(self
.in_of
.guard
),
525 class FPNorm1(FPState
):
527 def __init__(self
, width
):
528 FPState
.__init
__(self
, "normalise_1")
529 self
.mod
= FPNorm1Mod(width
)
530 self
.out_norm
= Signal(reset_less
=True)
531 self
.out_z
= FPNumBase(width
)
532 self
.out_of
= Overflow()
535 m
.d
.sync
+= self
.of
.copy(self
.out_of
)
536 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
537 with m
.If(~self
.out_norm
):
538 m
.next
= "normalise_2"
543 def __init__(self
, width
):
544 self
.out_norm
= Signal(reset_less
=True)
545 self
.in_z
= FPNumBase(width
, False)
546 self
.out_z
= FPNumBase(width
, False)
547 self
.in_of
= Overflow()
548 self
.out_of
= Overflow()
550 def setup(self
, m
, in_z
, out_z
, in_of
, out_of
, out_norm
):
551 """ links module to inputs and outputs
553 m
.d
.comb
+= self
.in_z
.copy(in_z
)
554 m
.d
.comb
+= out_z
.copy(self
.out_z
)
555 m
.d
.comb
+= self
.in_of
.copy(in_of
)
556 m
.d
.comb
+= out_of
.copy(self
.out_of
)
557 m
.d
.comb
+= out_norm
.eq(self
.out_norm
)
559 def elaborate(self
, platform
):
561 m
.submodules
.norm2_in_overflow
= self
.in_of
562 m
.submodules
.norm2_out_overflow
= self
.out_of
563 m
.submodules
.norm2_in_z
= self
.in_z
564 m
.submodules
.norm2_out_z
= self
.out_z
565 m
.d
.comb
+= self
.out_z
.copy(self
.in_z
)
566 m
.d
.comb
+= self
.out_of
.copy(self
.in_of
)
567 m
.d
.comb
+= self
.out_norm
.eq(self
.in_z
.exp_lt_n126
)
568 with m
.If(self
.out_norm
):
570 self
.out_z
.e
.eq(self
.in_z
.e
+ 1), # INCREASE exponent
571 self
.out_z
.m
.eq(self
.in_z
.m
>> 1), # shift mantissa DOWN
572 self
.out_of
.guard
.eq(self
.in_z
.m
[0]),
573 self
.out_of
.m0
.eq(self
.in_z
.m
[1]),
574 self
.out_of
.round_bit
.eq(self
.in_of
.guard
),
575 self
.out_of
.sticky
.eq(self
.in_of
.sticky | self
.in_of
.round_bit
)
581 class FPNorm2(FPState
):
583 def __init__(self
, width
):
584 FPState
.__init
__(self
, "normalise_2")
585 self
.mod
= FPNorm2Mod(width
)
586 self
.out_norm
= Signal(reset_less
=True)
587 self
.out_z
= FPNumBase(width
)
588 self
.out_of
= Overflow()
591 #m.d.sync += self.of.copy(self.out_of)
592 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
593 with m
.If(~self
.out_norm
):
599 def __init__(self
, width
):
600 self
.in_roundz
= Signal(reset_less
=True)
601 self
.in_z
= FPNumBase(width
, False)
602 self
.out_z
= FPNumBase(width
, False)
604 def setup(self
, m
, in_z
, out_z
, in_of
):
605 """ links module to inputs and outputs
607 m
.d
.comb
+= self
.in_z
.copy(in_z
)
608 m
.d
.comb
+= out_z
.copy(self
.out_z
)
609 m
.d
.comb
+= self
.in_roundz
.eq(in_of
.roundz
)
611 def elaborate(self
, platform
):
613 m
.d
.comb
+= self
.out_z
.copy(self
.in_z
)
614 with m
.If(self
.in_roundz
):
615 m
.d
.comb
+= self
.out_z
.m
.eq(self
.in_z
.m
+ 1) # mantissa rounds up
616 with m
.If(self
.in_z
.m
== self
.in_z
.m1s
): # all 1s
617 m
.d
.comb
+= self
.out_z
.e
.eq(self
.in_z
.e
+ 1) # exponent up
621 class FPRound(FPState
):
623 def __init__(self
, width
):
624 FPState
.__init
__(self
, "round")
625 self
.mod
= FPRoundMod(width
)
626 self
.out_z
= FPNumBase(width
)
629 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
630 m
.next
= "corrections"
633 class FPCorrectionsMod
:
635 def __init__(self
, width
):
636 self
.in_z
= FPNumOut(width
, False)
637 self
.out_z
= FPNumOut(width
, False)
639 def setup(self
, m
, in_z
, out_z
):
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
)
645 def elaborate(self
, platform
):
647 m
.submodules
.corr_in_z
= self
.in_z
648 m
.submodules
.corr_out_z
= self
.out_z
649 m
.d
.comb
+= self
.out_z
.copy(self
.in_z
)
650 with m
.If(self
.in_z
.is_denormalised
):
651 m
.d
.comb
+= self
.out_z
.e
.eq(self
.in_z
.N127
)
653 # with m.If(self.in_z.is_overflowed):
654 # m.d.comb += self.out_z.inf(self.in_z.s)
656 # m.d.comb += self.out_z.create(self.in_z.s, self.in_z.e, self.in_z.m)
660 class FPCorrections(FPState
):
662 def __init__(self
, width
):
663 FPState
.__init
__(self
, "corrections")
664 self
.mod
= FPCorrectionsMod(width
)
665 self
.out_z
= FPNumBase(width
)
668 m
.d
.sync
+= self
.z
.copy(self
.out_z
)
674 def __init__(self
, width
):
675 self
.in_z
= FPNumOut(width
, False)
676 self
.out_z
= FPNumOut(width
, False)
678 def setup(self
, m
, in_z
, out_z
):
679 """ links module to inputs and outputs
681 m
.d
.comb
+= self
.in_z
.copy(in_z
)
682 m
.d
.comb
+= out_z
.v
.eq(self
.out_z
.v
)
684 def elaborate(self
, platform
):
686 m
.submodules
.pack_in_z
= self
.in_z
687 with m
.If(self
.in_z
.is_overflowed
):
688 m
.d
.comb
+= self
.out_z
.inf(self
.in_z
.s
)
690 m
.d
.comb
+= self
.out_z
.create(self
.in_z
.s
, self
.in_z
.e
, self
.in_z
.m
)
694 class FPPack(FPState
):
696 def __init__(self
, width
):
697 FPState
.__init
__(self
, "pack")
698 self
.mod
= FPPackMod(width
)
699 self
.out_z
= FPNumOut(width
, False)
702 m
.d
.sync
+= self
.z
.v
.eq(self
.out_z
.v
)
706 class FPPutZ(FPState
):
709 self
.put_z(m
, self
.z
, self
.out_z
, "get_a")
714 def __init__(self
, width
, single_cycle
=False):
716 self
.single_cycle
= single_cycle
718 self
.in_a
= FPOp(width
)
719 self
.in_b
= FPOp(width
)
720 self
.out_z
= FPOp(width
)
724 def add_state(self
, state
):
725 self
.states
.append(state
)
728 def get_fragment(self
, platform
=None):
729 """ creates the HDL code-fragment for FPAdd
734 #a = FPNumIn(self.in_a, self.width)
735 #b = FPNumIn(self.in_b, self.width)
736 z
= FPNumOut(self
.width
, False)
738 #m.submodules.fpnum_b = b
739 m
.submodules
.fpnum_z
= z
744 m
.submodules
.overflow
= of
746 geta
= self
.add_state(FPGetOpA(self
.in_a
, self
.width
))
747 #geta.set_inputs({"in_a": self.in_a})
748 #geta.set_outputs({"a": a})
750 # XXX m.d.comb += a.v.eq(self.in_a.v) # links in_a to a
751 m
.submodules
.fpnum_a
= a
753 getb
= self
.add_state(FPGetOpB(self
.in_b
, self
.width
))
754 #getb.set_inputs({"in_b": self.in_b})
755 #getb.set_outputs({"b": b})
757 # XXX m.d.comb += b.v.eq(self.in_b.v) # links in_b to b
758 m
.submodules
.fpnum_b
= b
760 sc
= self
.add_state(FPAddSpecialCases(self
.width
))
761 sc
.set_inputs({"a": a
, "b": b
})
762 sc
.set_outputs({"z": z
})
763 sc
.mod
.setup(m
, a
, b
, sc
.out_z
, sc
.out_do_z
)
764 m
.submodules
.specialcases
= sc
.mod
766 dn
= self
.add_state(FPAddDeNorm(self
.width
))
767 dn
.set_inputs({"a": a
, "b": b
})
768 dn
.set_outputs({"a": a
, "b": b
}) # XXX outputs same as inputs
769 dn
.mod
.setup(m
, a
, b
, dn
.out_a
, dn
.out_b
)
770 m
.submodules
.denormalise
= dn
.mod
772 if self
.single_cycle
:
773 alm
= self
.add_state(FPAddAlignSingle(self
.width
))
774 alm
.set_inputs({"a": a
, "b": b
})
775 alm
.set_outputs({"a": a
, "b": b
}) # XXX outputs same as inputs
776 alm
.mod
.setup(m
, a
, b
, alm
.out_a
, alm
.out_b
)
778 alm
= self
.add_state(FPAddAlignMulti(self
.width
))
779 alm
.set_inputs({"a": a
, "b": b
})
780 alm
.set_outputs({"a": a
, "b": b
}) # XXX outputs same as inputs
781 alm
.mod
.setup(m
, a
, b
, alm
.out_a
, alm
.out_b
, alm
.exp_eq
)
782 m
.submodules
.align
= alm
.mod
784 add0
= self
.add_state(FPAddStage0(self
.width
))
785 add0
.set_inputs({"a": a
, "b": b
})
786 add0
.set_outputs({"z": z
})
787 add0
.mod
.setup(m
, a
, b
, z
, add0
.out_z
, add0
.out_tot
)
788 m
.submodules
.add0
= add0
.mod
790 add1
= self
.add_state(FPAddStage1(self
.width
))
791 add1
.set_inputs({"tot": add0
.out_tot
, "z": add0
.out_z
})
792 add1
.set_outputs({"z": z
, "of": of
}) # XXX Z as output
793 add1
.mod
.setup(m
, add0
.out_tot
, z
, add1
.out_z
, add1
.out_of
)
794 m
.submodules
.add1
= add1
.mod
796 n1
= self
.add_state(FPNorm1(self
.width
))
797 n1
.set_inputs({"z": z
, "of": of
}) # XXX Z as output
798 n1
.set_outputs({"z": z
}) # XXX Z as output
799 n1
.mod
.setup(m
, z
, n1
.out_z
, of
, n1
.out_of
, n1
.out_norm
)
800 m
.submodules
.normalise_1
= n1
.mod
802 n2
= self
.add_state(FPNorm2(self
.width
))
803 n2
.set_inputs({"z": n1
.out_z
, "of": n1
.out_of
})
804 n2
.set_outputs({"z": z
})
805 n2
.mod
.setup(m
, n1
.out_z
, n2
.out_z
, of
, n2
.out_of
, n2
.out_norm
)
806 m
.submodules
.normalise_2
= n2
.mod
808 rn
= self
.add_state(FPRound(self
.width
))
809 rn
.set_inputs({"z": n2
.out_z
, "of": n2
.out_of
})
810 rn
.set_outputs({"z": z
})
811 rn
.mod
.setup(m
, n2
.out_z
, rn
.out_z
, of
)
812 m
.submodules
.roundz
= rn
.mod
814 cor
= self
.add_state(FPCorrections(self
.width
))
815 cor
.set_inputs({"z": z
}) # XXX Z as output
816 cor
.set_outputs({"z": z
}) # XXX Z as output
817 cor
.mod
.setup(m
, z
, cor
.out_z
)
818 m
.submodules
.corrections
= cor
.mod
820 pa
= self
.add_state(FPPack(self
.width
))
821 pa
.set_inputs({"z": z
}) # XXX Z as output
822 pa
.set_outputs({"z": z
}) # XXX Z as output
823 pa
.mod
.setup(m
, z
, pa
.out_z
)
824 m
.submodules
.pack
= pa
.mod
826 pz
= self
.add_state(FPPutZ("put_z"))
827 pz
.set_inputs({"z": z
})
828 pz
.set_outputs({"out_z": self
.out_z
})
832 for state
in self
.states
:
833 with m
.State(state
.state_from
):
839 if __name__
== "__main__":
840 alu
= FPADD(width
=32)
841 main(alu
, ports
=alu
.in_a
.ports() + alu
.in_b
.ports() + alu
.out_z
.ports())
844 # works... but don't use, just do "python fname.py convert -t v"
845 #print (verilog.convert(alu, ports=[
846 # ports=alu.in_a.ports() + \
847 # alu.in_b.ports() + \