1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Module
, Signal
, Cat
, Mux
, Array
, Const
6 from nmigen
.lib
.coding
import PriorityEncoder
7 from nmigen
.cli
import main
, verilog
10 from fpbase
import FPNumIn
, FPNumOut
, FPOp
, Overflow
, FPBase
, FPNumBase
11 from fpbase
import MultiShiftRMerge
, Trigger
12 from singlepipe
import (ControlBase
, StageChain
, UnbufferedPipeline
,
14 from multipipe
import CombMuxOutPipe
15 from multipipe
import PriorityCombMuxInPipe
17 from fpbase
import FPState
18 from fpcommon
.getop
import (FPGetOpMod
, FPGetOp
, FPNumBase2Ops
, FPADDBaseData
, FPGet2OpMod
, FPGet2Op
)
19 from fpcommon
.denorm
import (FPSCData
, FPAddDeNormMod
, FPAddDeNorm
)
20 from fpcommon
.postcalc
import FPAddStage1Data
21 from fpcommon
.postnormalise
import (FPNorm1Data
, FPNorm1ModSingle
,
22 FPNorm1ModMulti
, FPNorm1Single
, FPNorm1Multi
)
25 class FPAddSpecialCasesMod
:
26 """ special cases: NaNs, infs, zeros, denormalised
27 NOTE: some of these are unique to add. see "Special Operations"
28 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
31 def __init__(self
, width
, id_wid
):
38 return FPADDBaseData(self
.width
, self
.id_wid
)
41 return FPSCData(self
.width
, self
.id_wid
)
43 def setup(self
, m
, i
):
44 """ links module to inputs and outputs
46 m
.submodules
.specialcases
= self
47 m
.d
.comb
+= self
.i
.eq(i
)
52 def elaborate(self
, platform
):
55 m
.submodules
.sc_out_z
= self
.o
.z
57 # decode: XXX really should move to separate stage
58 a1
= FPNumIn(None, self
.width
)
59 b1
= FPNumIn(None, self
.width
)
60 m
.submodules
.sc_decode_a
= a1
61 m
.submodules
.sc_decode_b
= b1
62 m
.d
.comb
+= [a1
.decode(self
.i
.a
),
67 m
.d
.comb
+= s_nomatch
.eq(a1
.s
!= b1
.s
)
70 m
.d
.comb
+= m_match
.eq(a1
.m
== b1
.m
)
72 # if a is NaN or b is NaN return NaN
73 with m
.If(a1
.is_nan | b1
.is_nan
):
74 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
75 m
.d
.comb
+= self
.o
.z
.nan(0)
77 # XXX WEIRDNESS for FP16 non-canonical NaN handling
80 ## if a is zero and b is NaN return -b
81 #with m.If(a.is_zero & (a.s==0) & b.is_nan):
82 # m.d.comb += self.o.out_do_z.eq(1)
83 # m.d.comb += z.create(b.s, b.e, Cat(b.m[3:-2], ~b.m[0]))
85 ## if b is zero and a is NaN return -a
86 #with m.Elif(b.is_zero & (b.s==0) & a.is_nan):
87 # m.d.comb += self.o.out_do_z.eq(1)
88 # m.d.comb += z.create(a.s, a.e, Cat(a.m[3:-2], ~a.m[0]))
90 ## if a is -zero and b is NaN return -b
91 #with m.Elif(a.is_zero & (a.s==1) & b.is_nan):
92 # m.d.comb += self.o.out_do_z.eq(1)
93 # m.d.comb += z.create(a.s & b.s, b.e, Cat(b.m[3:-2], 1))
95 ## if b is -zero and a is NaN return -a
96 #with m.Elif(b.is_zero & (b.s==1) & a.is_nan):
97 # m.d.comb += self.o.out_do_z.eq(1)
98 # m.d.comb += z.create(a.s & b.s, a.e, Cat(a.m[3:-2], 1))
100 # if a is inf return inf (or NaN)
101 with m
.Elif(a1
.is_inf
):
102 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
103 m
.d
.comb
+= self
.o
.z
.inf(a1
.s
)
104 # if a is inf and signs don't match return NaN
105 with m
.If(b1
.exp_128
& s_nomatch
):
106 m
.d
.comb
+= self
.o
.z
.nan(0)
108 # if b is inf return inf
109 with m
.Elif(b1
.is_inf
):
110 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
111 m
.d
.comb
+= self
.o
.z
.inf(b1
.s
)
113 # if a is zero and b zero return signed-a/b
114 with m
.Elif(a1
.is_zero
& b1
.is_zero
):
115 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
116 m
.d
.comb
+= self
.o
.z
.create(a1
.s
& b1
.s
, b1
.e
, b1
.m
[3:-1])
118 # if a is zero return b
119 with m
.Elif(a1
.is_zero
):
120 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
121 m
.d
.comb
+= self
.o
.z
.create(b1
.s
, b1
.e
, b1
.m
[3:-1])
123 # if b is zero return a
124 with m
.Elif(b1
.is_zero
):
125 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
126 m
.d
.comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, a1
.m
[3:-1])
128 # if a equal to -b return zero (+ve zero)
129 with m
.Elif(s_nomatch
& m_match
& (a1
.e
== b1
.e
)):
130 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
131 m
.d
.comb
+= self
.o
.z
.zero(0)
133 # Denormalised Number checks next, so pass a/b data through
135 m
.d
.comb
+= self
.o
.out_do_z
.eq(0)
136 m
.d
.comb
+= self
.o
.a
.eq(a1
)
137 m
.d
.comb
+= self
.o
.b
.eq(b1
)
139 m
.d
.comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
140 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
146 def __init__(self
, id_wid
):
149 self
.in_mid
= Signal(id_wid
, reset_less
=True)
150 self
.out_mid
= Signal(id_wid
, reset_less
=True)
156 if self
.id_wid
is not None:
157 m
.d
.sync
+= self
.out_mid
.eq(self
.in_mid
)
160 class FPAddSpecialCases(FPState
):
161 """ special cases: NaNs, infs, zeros, denormalised
162 NOTE: some of these are unique to add. see "Special Operations"
163 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
166 def __init__(self
, width
, id_wid
):
167 FPState
.__init
__(self
, "special_cases")
168 self
.mod
= FPAddSpecialCasesMod(width
)
169 self
.out_z
= self
.mod
.ospec()
170 self
.out_do_z
= Signal(reset_less
=True)
172 def setup(self
, m
, i
):
173 """ links module to inputs and outputs
175 self
.mod
.setup(m
, i
, self
.out_do_z
)
176 m
.d
.sync
+= self
.out_z
.v
.eq(self
.mod
.out_z
.v
) # only take the output
177 m
.d
.sync
+= self
.out_z
.mid
.eq(self
.mod
.o
.mid
) # (and mid)
181 with m
.If(self
.out_do_z
):
184 m
.next
= "denormalise"
187 class FPAddSpecialCasesDeNorm(FPState
, UnbufferedPipeline
):
188 """ special cases: NaNs, infs, zeros, denormalised
189 NOTE: some of these are unique to add. see "Special Operations"
190 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
193 def __init__(self
, width
, id_wid
):
194 FPState
.__init
__(self
, "special_cases")
197 UnbufferedPipeline
.__init
__(self
, self
) # pipe is its own stage
198 self
.out
= self
.ospec()
201 return FPADDBaseData(self
.width
, self
.id_wid
) # SpecialCases ispec
204 return FPSCData(self
.width
, self
.id_wid
) # DeNorm ospec
206 def setup(self
, m
, i
):
207 """ links module to inputs and outputs
209 smod
= FPAddSpecialCasesMod(self
.width
, self
.id_wid
)
210 dmod
= FPAddDeNormMod(self
.width
, self
.id_wid
)
212 chain
= StageChain([smod
, dmod
])
215 # only needed for break-out (early-out)
216 # self.out_do_z = smod.o.out_do_z
220 def process(self
, i
):
224 # for break-out (early-out)
225 #with m.If(self.out_do_z):
228 m
.d
.sync
+= self
.out
.eq(self
.process(None))
232 class FPAddAlignMultiMod(FPState
):
234 def __init__(self
, width
):
235 self
.in_a
= FPNumBase(width
)
236 self
.in_b
= FPNumBase(width
)
237 self
.out_a
= FPNumIn(None, width
)
238 self
.out_b
= FPNumIn(None, width
)
239 self
.exp_eq
= Signal(reset_less
=True)
241 def elaborate(self
, platform
):
242 # This one however (single-cycle) will do the shift
247 m
.submodules
.align_in_a
= self
.in_a
248 m
.submodules
.align_in_b
= self
.in_b
249 m
.submodules
.align_out_a
= self
.out_a
250 m
.submodules
.align_out_b
= self
.out_b
252 # NOTE: this does *not* do single-cycle multi-shifting,
253 # it *STAYS* in the align state until exponents match
255 # exponent of a greater than b: shift b down
256 m
.d
.comb
+= self
.exp_eq
.eq(0)
257 m
.d
.comb
+= self
.out_a
.eq(self
.in_a
)
258 m
.d
.comb
+= self
.out_b
.eq(self
.in_b
)
259 agtb
= Signal(reset_less
=True)
260 altb
= Signal(reset_less
=True)
261 m
.d
.comb
+= agtb
.eq(self
.in_a
.e
> self
.in_b
.e
)
262 m
.d
.comb
+= altb
.eq(self
.in_a
.e
< self
.in_b
.e
)
264 m
.d
.comb
+= self
.out_b
.shift_down(self
.in_b
)
265 # exponent of b greater than a: shift a down
267 m
.d
.comb
+= self
.out_a
.shift_down(self
.in_a
)
268 # exponents equal: move to next stage.
270 m
.d
.comb
+= self
.exp_eq
.eq(1)
274 class FPAddAlignMulti(FPState
):
276 def __init__(self
, width
, id_wid
):
277 FPState
.__init
__(self
, "align")
278 self
.mod
= FPAddAlignMultiMod(width
)
279 self
.out_a
= FPNumIn(None, width
)
280 self
.out_b
= FPNumIn(None, width
)
281 self
.exp_eq
= Signal(reset_less
=True)
283 def setup(self
, m
, in_a
, in_b
):
284 """ links module to inputs and outputs
286 m
.submodules
.align
= self
.mod
287 m
.d
.comb
+= self
.mod
.in_a
.eq(in_a
)
288 m
.d
.comb
+= self
.mod
.in_b
.eq(in_b
)
289 m
.d
.comb
+= self
.exp_eq
.eq(self
.mod
.exp_eq
)
290 m
.d
.sync
+= self
.out_a
.eq(self
.mod
.out_a
)
291 m
.d
.sync
+= self
.out_b
.eq(self
.mod
.out_b
)
294 with m
.If(self
.exp_eq
):
300 def __init__(self
, width
, id_wid
):
301 self
.a
= FPNumIn(None, width
)
302 self
.b
= FPNumIn(None, width
)
303 self
.z
= FPNumOut(width
, False)
304 self
.out_do_z
= Signal(reset_less
=True)
305 self
.oz
= Signal(width
, reset_less
=True)
306 self
.mid
= Signal(id_wid
, reset_less
=True)
309 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
310 self
.a
.eq(i
.a
), self
.b
.eq(i
.b
), self
.mid
.eq(i
.mid
)]
313 class FPAddAlignSingleMod
:
315 def __init__(self
, width
, id_wid
):
318 self
.i
= self
.ispec()
319 self
.o
= self
.ospec()
322 return FPSCData(self
.width
, self
.id_wid
)
325 return FPNumIn2Ops(self
.width
, self
.id_wid
)
327 def process(self
, i
):
330 def setup(self
, m
, i
):
331 """ links module to inputs and outputs
333 m
.submodules
.align
= self
334 m
.d
.comb
+= self
.i
.eq(i
)
336 def elaborate(self
, platform
):
337 """ Aligns A against B or B against A, depending on which has the
338 greater exponent. This is done in a *single* cycle using
339 variable-width bit-shift
341 the shifter used here is quite expensive in terms of gates.
342 Mux A or B in (and out) into temporaries, as only one of them
343 needs to be aligned against the other
347 m
.submodules
.align_in_a
= self
.i
.a
348 m
.submodules
.align_in_b
= self
.i
.b
349 m
.submodules
.align_out_a
= self
.o
.a
350 m
.submodules
.align_out_b
= self
.o
.b
352 # temporary (muxed) input and output to be shifted
353 t_inp
= FPNumBase(self
.width
)
354 t_out
= FPNumIn(None, self
.width
)
355 espec
= (len(self
.i
.a
.e
), True)
356 msr
= MultiShiftRMerge(self
.i
.a
.m_width
, espec
)
357 m
.submodules
.align_t_in
= t_inp
358 m
.submodules
.align_t_out
= t_out
359 m
.submodules
.multishift_r
= msr
361 ediff
= Signal(espec
, reset_less
=True)
362 ediffr
= Signal(espec
, reset_less
=True)
363 tdiff
= Signal(espec
, reset_less
=True)
364 elz
= Signal(reset_less
=True)
365 egz
= Signal(reset_less
=True)
367 # connect multi-shifter to t_inp/out mantissa (and tdiff)
368 m
.d
.comb
+= msr
.inp
.eq(t_inp
.m
)
369 m
.d
.comb
+= msr
.diff
.eq(tdiff
)
370 m
.d
.comb
+= t_out
.m
.eq(msr
.m
)
371 m
.d
.comb
+= t_out
.e
.eq(t_inp
.e
+ tdiff
)
372 m
.d
.comb
+= t_out
.s
.eq(t_inp
.s
)
374 m
.d
.comb
+= ediff
.eq(self
.i
.a
.e
- self
.i
.b
.e
)
375 m
.d
.comb
+= ediffr
.eq(self
.i
.b
.e
- self
.i
.a
.e
)
376 m
.d
.comb
+= elz
.eq(self
.i
.a
.e
< self
.i
.b
.e
)
377 m
.d
.comb
+= egz
.eq(self
.i
.a
.e
> self
.i
.b
.e
)
379 # default: A-exp == B-exp, A and B untouched (fall through)
380 m
.d
.comb
+= self
.o
.a
.eq(self
.i
.a
)
381 m
.d
.comb
+= self
.o
.b
.eq(self
.i
.b
)
382 # only one shifter (muxed)
383 #m.d.comb += t_out.shift_down_multi(tdiff, t_inp)
384 # exponent of a greater than b: shift b down
385 with m
.If(~self
.i
.out_do_z
):
387 m
.d
.comb
+= [t_inp
.eq(self
.i
.b
),
390 self
.o
.b
.s
.eq(self
.i
.b
.s
), # whoops forgot sign
392 # exponent of b greater than a: shift a down
394 m
.d
.comb
+= [t_inp
.eq(self
.i
.a
),
397 self
.o
.a
.s
.eq(self
.i
.a
.s
), # whoops forgot sign
400 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
401 m
.d
.comb
+= self
.o
.z
.eq(self
.i
.z
)
402 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
403 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
408 class FPAddAlignSingle(FPState
):
410 def __init__(self
, width
, id_wid
):
411 FPState
.__init
__(self
, "align")
412 self
.mod
= FPAddAlignSingleMod(width
, id_wid
)
413 self
.out_a
= FPNumIn(None, width
)
414 self
.out_b
= FPNumIn(None, width
)
416 def setup(self
, m
, i
):
417 """ links module to inputs and outputs
421 # NOTE: could be done as comb
422 m
.d
.sync
+= self
.out_a
.eq(self
.mod
.out_a
)
423 m
.d
.sync
+= self
.out_b
.eq(self
.mod
.out_b
)
429 class FPAddAlignSingleAdd(FPState
, UnbufferedPipeline
):
431 def __init__(self
, width
, id_wid
):
432 FPState
.__init
__(self
, "align")
435 UnbufferedPipeline
.__init
__(self
, self
) # pipeline is its own stage
436 self
.a1o
= self
.ospec()
439 return FPSCData(self
.width
, self
.id_wid
)
442 return FPAddStage1Data(self
.width
, self
.id_wid
) # AddStage1 ospec
444 def setup(self
, m
, i
):
445 """ links module to inputs and outputs
448 # chain AddAlignSingle, AddStage0 and AddStage1
449 mod
= FPAddAlignSingleMod(self
.width
, self
.id_wid
)
450 a0mod
= FPAddStage0Mod(self
.width
, self
.id_wid
)
451 a1mod
= FPAddStage1Mod(self
.width
, self
.id_wid
)
453 chain
= StageChain([mod
, a0mod
, a1mod
])
458 def process(self
, i
):
462 m
.d
.sync
+= self
.a1o
.eq(self
.process(None))
463 m
.next
= "normalise_1"
466 class FPAddStage0Data
:
468 def __init__(self
, width
, id_wid
):
469 self
.z
= FPNumBase(width
, False)
470 self
.out_do_z
= Signal(reset_less
=True)
471 self
.oz
= Signal(width
, reset_less
=True)
472 self
.tot
= Signal(self
.z
.m_width
+ 4, reset_less
=True)
473 self
.mid
= Signal(id_wid
, reset_less
=True)
476 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
477 self
.tot
.eq(i
.tot
), self
.mid
.eq(i
.mid
)]
480 class FPAddStage0Mod
:
482 def __init__(self
, width
, id_wid
):
485 self
.i
= self
.ispec()
486 self
.o
= self
.ospec()
489 return FPSCData(self
.width
, self
.id_wid
)
492 return FPAddStage0Data(self
.width
, self
.id_wid
)
494 def process(self
, i
):
497 def setup(self
, m
, i
):
498 """ links module to inputs and outputs
500 m
.submodules
.add0
= self
501 m
.d
.comb
+= self
.i
.eq(i
)
503 def elaborate(self
, platform
):
505 m
.submodules
.add0_in_a
= self
.i
.a
506 m
.submodules
.add0_in_b
= self
.i
.b
507 m
.submodules
.add0_out_z
= self
.o
.z
509 # store intermediate tests (and zero-extended mantissas)
510 seq
= Signal(reset_less
=True)
511 mge
= Signal(reset_less
=True)
512 am0
= Signal(len(self
.i
.a
.m
)+1, reset_less
=True)
513 bm0
= Signal(len(self
.i
.b
.m
)+1, reset_less
=True)
514 m
.d
.comb
+= [seq
.eq(self
.i
.a
.s
== self
.i
.b
.s
),
515 mge
.eq(self
.i
.a
.m
>= self
.i
.b
.m
),
516 am0
.eq(Cat(self
.i
.a
.m
, 0)),
517 bm0
.eq(Cat(self
.i
.b
.m
, 0))
519 # same-sign (both negative or both positive) add mantissas
520 with m
.If(~self
.i
.out_do_z
):
521 m
.d
.comb
+= self
.o
.z
.e
.eq(self
.i
.a
.e
)
524 self
.o
.tot
.eq(am0
+ bm0
),
525 self
.o
.z
.s
.eq(self
.i
.a
.s
)
527 # a mantissa greater than b, use a
530 self
.o
.tot
.eq(am0
- bm0
),
531 self
.o
.z
.s
.eq(self
.i
.a
.s
)
533 # b mantissa greater than a, use b
536 self
.o
.tot
.eq(bm0
- am0
),
537 self
.o
.z
.s
.eq(self
.i
.b
.s
)
540 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
541 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
542 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
546 class FPAddStage0(FPState
):
547 """ First stage of add. covers same-sign (add) and subtract
548 special-casing when mantissas are greater or equal, to
549 give greatest accuracy.
552 def __init__(self
, width
, id_wid
):
553 FPState
.__init
__(self
, "add_0")
554 self
.mod
= FPAddStage0Mod(width
)
555 self
.o
= self
.mod
.ospec()
557 def setup(self
, m
, i
):
558 """ links module to inputs and outputs
562 # NOTE: these could be done as combinatorial (merge add0+add1)
563 m
.d
.sync
+= self
.o
.eq(self
.mod
.o
)
569 class FPAddStage1Mod(FPState
):
570 """ Second stage of add: preparation for normalisation.
571 detects when tot sum is too big (tot[27] is kinda a carry bit)
574 def __init__(self
, width
, id_wid
):
577 self
.i
= self
.ispec()
578 self
.o
= self
.ospec()
581 return FPAddStage0Data(self
.width
, self
.id_wid
)
584 return FPAddStage1Data(self
.width
, self
.id_wid
)
586 def process(self
, i
):
589 def setup(self
, m
, i
):
590 """ links module to inputs and outputs
592 m
.submodules
.add1
= self
593 m
.submodules
.add1_out_overflow
= self
.o
.of
595 m
.d
.comb
+= self
.i
.eq(i
)
597 def elaborate(self
, platform
):
599 m
.d
.comb
+= self
.o
.z
.eq(self
.i
.z
)
600 # tot[-1] (MSB) gets set when the sum overflows. shift result down
601 with m
.If(~self
.i
.out_do_z
):
602 with m
.If(self
.i
.tot
[-1]):
604 self
.o
.z
.m
.eq(self
.i
.tot
[4:]),
605 self
.o
.of
.m0
.eq(self
.i
.tot
[4]),
606 self
.o
.of
.guard
.eq(self
.i
.tot
[3]),
607 self
.o
.of
.round_bit
.eq(self
.i
.tot
[2]),
608 self
.o
.of
.sticky
.eq(self
.i
.tot
[1] | self
.i
.tot
[0]),
609 self
.o
.z
.e
.eq(self
.i
.z
.e
+ 1)
611 # tot[-1] (MSB) zero case
614 self
.o
.z
.m
.eq(self
.i
.tot
[3:]),
615 self
.o
.of
.m0
.eq(self
.i
.tot
[3]),
616 self
.o
.of
.guard
.eq(self
.i
.tot
[2]),
617 self
.o
.of
.round_bit
.eq(self
.i
.tot
[1]),
618 self
.o
.of
.sticky
.eq(self
.i
.tot
[0])
621 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
622 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
623 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
628 class FPAddStage1(FPState
):
630 def __init__(self
, width
, id_wid
):
631 FPState
.__init
__(self
, "add_1")
632 self
.mod
= FPAddStage1Mod(width
)
633 self
.out_z
= FPNumBase(width
, False)
634 self
.out_of
= Overflow()
635 self
.norm_stb
= Signal()
637 def setup(self
, m
, i
):
638 """ links module to inputs and outputs
642 m
.d
.sync
+= self
.norm_stb
.eq(0) # sets to zero when not in add1 state
644 m
.d
.sync
+= self
.out_of
.eq(self
.mod
.out_of
)
645 m
.d
.sync
+= self
.out_z
.eq(self
.mod
.out_z
)
646 m
.d
.sync
+= self
.norm_stb
.eq(1)
649 m
.next
= "normalise_1"
654 def __init__(self
, width
, single_cycle
=True):
656 self
.in_select
= Signal(reset_less
=True)
657 self
.in_z
= FPNumBase(width
, False)
658 self
.in_of
= Overflow()
659 self
.temp_z
= FPNumBase(width
, False)
660 self
.temp_of
= Overflow()
661 self
.out_z
= FPNumBase(width
, False)
662 self
.out_of
= Overflow()
664 def elaborate(self
, platform
):
667 m
.submodules
.norm1_out_z
= self
.out_z
668 m
.submodules
.norm1_out_overflow
= self
.out_of
669 m
.submodules
.norm1_temp_z
= self
.temp_z
670 m
.submodules
.norm1_temp_of
= self
.temp_of
671 m
.submodules
.norm1_in_z
= self
.in_z
672 m
.submodules
.norm1_in_overflow
= self
.in_of
674 in_z
= FPNumBase(self
.width
, False)
676 m
.submodules
.norm1_insel_z
= in_z
677 m
.submodules
.norm1_insel_overflow
= in_of
679 # select which of temp or in z/of to use
680 with m
.If(self
.in_select
):
681 m
.d
.comb
+= in_z
.eq(self
.in_z
)
682 m
.d
.comb
+= in_of
.eq(self
.in_of
)
684 m
.d
.comb
+= in_z
.eq(self
.temp_z
)
685 m
.d
.comb
+= in_of
.eq(self
.temp_of
)
686 # initialise out from in (overridden below)
687 m
.d
.comb
+= self
.out_z
.eq(in_z
)
688 m
.d
.comb
+= self
.out_of
.eq(in_of
)
689 # normalisation increase/decrease conditions
690 decrease
= Signal(reset_less
=True)
691 increase
= Signal(reset_less
=True)
692 m
.d
.comb
+= decrease
.eq(in_z
.m_msbzero
& in_z
.exp_gt_n126
)
693 m
.d
.comb
+= increase
.eq(in_z
.exp_lt_n126
)
694 m
.d
.comb
+= self
.out_norm
.eq(decrease | increase
) # loop-end
698 self
.out_z
.e
.eq(in_z
.e
- 1), # DECREASE exponent
699 self
.out_z
.m
.eq(in_z
.m
<< 1), # shift mantissa UP
700 self
.out_z
.m
[0].eq(in_of
.guard
), # steal guard (was tot[2])
701 self
.out_of
.guard
.eq(in_of
.round_bit
), # round (was tot[1])
702 self
.out_of
.round_bit
.eq(0), # reset round bit
703 self
.out_of
.m0
.eq(in_of
.guard
),
706 with m
.Elif(increase
):
708 self
.out_z
.e
.eq(in_z
.e
+ 1), # INCREASE exponent
709 self
.out_z
.m
.eq(in_z
.m
>> 1), # shift mantissa DOWN
710 self
.out_of
.guard
.eq(in_z
.m
[0]),
711 self
.out_of
.m0
.eq(in_z
.m
[1]),
712 self
.out_of
.round_bit
.eq(in_of
.guard
),
713 self
.out_of
.sticky
.eq(in_of
.sticky | in_of
.round_bit
)
719 class FPNormToPack(FPState
, UnbufferedPipeline
):
721 def __init__(self
, width
, id_wid
):
722 FPState
.__init
__(self
, "normalise_1")
725 UnbufferedPipeline
.__init
__(self
, self
) # pipeline is its own stage
728 return FPAddStage1Data(self
.width
, self
.id_wid
) # Norm1ModSingle ispec
731 return FPPackData(self
.width
, self
.id_wid
) # FPPackMod ospec
733 def setup(self
, m
, i
):
734 """ links module to inputs and outputs
737 # Normalisation, Rounding Corrections, Pack - in a chain
738 nmod
= FPNorm1ModSingle(self
.width
, self
.id_wid
)
739 rmod
= FPRoundMod(self
.width
, self
.id_wid
)
740 cmod
= FPCorrectionsMod(self
.width
, self
.id_wid
)
741 pmod
= FPPackMod(self
.width
, self
.id_wid
)
742 chain
= StageChain([nmod
, rmod
, cmod
, pmod
])
744 self
.out_z
= pmod
.ospec()
748 def process(self
, i
):
752 m
.d
.sync
+= self
.out_z
.eq(self
.process(None))
753 m
.next
= "pack_put_z"
758 def __init__(self
, width
, id_wid
):
759 self
.z
= FPNumBase(width
, False)
760 self
.out_do_z
= Signal(reset_less
=True)
761 self
.oz
= Signal(width
, reset_less
=True)
762 self
.mid
= Signal(id_wid
, reset_less
=True)
765 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
771 def __init__(self
, width
, id_wid
):
774 self
.i
= self
.ispec()
775 self
.out_z
= self
.ospec()
778 return FPNorm1Data(self
.width
, self
.id_wid
)
781 return FPRoundData(self
.width
, self
.id_wid
)
783 def process(self
, i
):
786 def setup(self
, m
, i
):
787 m
.submodules
.roundz
= self
788 m
.d
.comb
+= self
.i
.eq(i
)
790 def elaborate(self
, platform
):
792 m
.d
.comb
+= self
.out_z
.eq(self
.i
) # copies mid, z, out_do_z
793 with m
.If(~self
.i
.out_do_z
):
794 with m
.If(self
.i
.roundz
):
795 m
.d
.comb
+= self
.out_z
.z
.m
.eq(self
.i
.z
.m
+ 1) # mantissa up
796 with m
.If(self
.i
.z
.m
== self
.i
.z
.m1s
): # all 1s
797 m
.d
.comb
+= self
.out_z
.z
.e
.eq(self
.i
.z
.e
+ 1) # exponent up
802 class FPRound(FPState
):
804 def __init__(self
, width
, id_wid
):
805 FPState
.__init
__(self
, "round")
806 self
.mod
= FPRoundMod(width
)
807 self
.out_z
= self
.ospec()
810 return self
.mod
.ispec()
813 return self
.mod
.ospec()
815 def setup(self
, m
, i
):
816 """ links module to inputs and outputs
821 m
.d
.sync
+= self
.out_z
.eq(self
.mod
.out_z
)
822 m
.d
.sync
+= self
.out_z
.mid
.eq(self
.mod
.o
.mid
)
825 m
.next
= "corrections"
828 class FPCorrectionsMod
:
830 def __init__(self
, width
, id_wid
):
833 self
.i
= self
.ispec()
834 self
.out_z
= self
.ospec()
837 return FPRoundData(self
.width
, self
.id_wid
)
840 return FPRoundData(self
.width
, self
.id_wid
)
842 def process(self
, i
):
845 def setup(self
, m
, i
):
846 """ links module to inputs and outputs
848 m
.submodules
.corrections
= self
849 m
.d
.comb
+= self
.i
.eq(i
)
851 def elaborate(self
, platform
):
853 m
.submodules
.corr_in_z
= self
.i
.z
854 m
.submodules
.corr_out_z
= self
.out_z
.z
855 m
.d
.comb
+= self
.out_z
.eq(self
.i
) # copies mid, z, out_do_z
856 with m
.If(~self
.i
.out_do_z
):
857 with m
.If(self
.i
.z
.is_denormalised
):
858 m
.d
.comb
+= self
.out_z
.z
.e
.eq(self
.i
.z
.N127
)
862 class FPCorrections(FPState
):
864 def __init__(self
, width
, id_wid
):
865 FPState
.__init
__(self
, "corrections")
866 self
.mod
= FPCorrectionsMod(width
)
867 self
.out_z
= self
.ospec()
870 return self
.mod
.ispec()
873 return self
.mod
.ospec()
875 def setup(self
, m
, in_z
):
876 """ links module to inputs and outputs
878 self
.mod
.setup(m
, in_z
)
880 m
.d
.sync
+= self
.out_z
.eq(self
.mod
.out_z
)
881 m
.d
.sync
+= self
.out_z
.mid
.eq(self
.mod
.o
.mid
)
889 def __init__(self
, width
, id_wid
):
890 self
.z
= Signal(width
, reset_less
=True)
891 self
.mid
= Signal(id_wid
, reset_less
=True)
894 return [self
.z
.eq(i
.z
), self
.mid
.eq(i
.mid
)]
897 return [self
.z
, self
.mid
]
902 def __init__(self
, width
, id_wid
):
905 self
.i
= self
.ispec()
906 self
.o
= self
.ospec()
909 return FPRoundData(self
.width
, self
.id_wid
)
912 return FPPackData(self
.width
, self
.id_wid
)
914 def process(self
, i
):
917 def setup(self
, m
, in_z
):
918 """ links module to inputs and outputs
920 m
.submodules
.pack
= self
921 m
.d
.comb
+= self
.i
.eq(in_z
)
923 def elaborate(self
, platform
):
925 z
= FPNumOut(self
.width
, False)
926 m
.submodules
.pack_in_z
= self
.i
.z
927 m
.submodules
.pack_out_z
= z
928 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
929 with m
.If(~self
.i
.out_do_z
):
930 with m
.If(self
.i
.z
.is_overflowed
):
931 m
.d
.comb
+= z
.inf(self
.i
.z
.s
)
933 m
.d
.comb
+= z
.create(self
.i
.z
.s
, self
.i
.z
.e
, self
.i
.z
.m
)
935 m
.d
.comb
+= z
.v
.eq(self
.i
.oz
)
936 m
.d
.comb
+= self
.o
.z
.eq(z
.v
)
940 class FPPack(FPState
):
942 def __init__(self
, width
, id_wid
):
943 FPState
.__init
__(self
, "pack")
944 self
.mod
= FPPackMod(width
)
945 self
.out_z
= self
.ospec()
948 return self
.mod
.ispec()
951 return self
.mod
.ospec()
953 def setup(self
, m
, in_z
):
954 """ links module to inputs and outputs
956 self
.mod
.setup(m
, in_z
)
958 m
.d
.sync
+= self
.out_z
.v
.eq(self
.mod
.out_z
.v
)
959 m
.d
.sync
+= self
.out_z
.mid
.eq(self
.mod
.o
.mid
)
962 m
.next
= "pack_put_z"
965 class FPPutZ(FPState
):
967 def __init__(self
, state
, in_z
, out_z
, in_mid
, out_mid
, to_state
=None):
968 FPState
.__init
__(self
, state
)
971 self
.to_state
= to_state
975 self
.out_mid
= out_mid
978 if self
.in_mid
is not None:
979 m
.d
.sync
+= self
.out_mid
.eq(self
.in_mid
)
981 self
.out_z
.z
.v
.eq(self
.in_z
)
983 with m
.If(self
.out_z
.z
.stb
& self
.out_z
.z
.ack
):
984 m
.d
.sync
+= self
.out_z
.z
.stb
.eq(0)
985 m
.next
= self
.to_state
987 m
.d
.sync
+= self
.out_z
.z
.stb
.eq(1)
990 class FPPutZIdx(FPState
):
992 def __init__(self
, state
, in_z
, out_zs
, in_mid
, to_state
=None):
993 FPState
.__init
__(self
, state
)
996 self
.to_state
= to_state
1001 def action(self
, m
):
1002 outz_stb
= Signal(reset_less
=True)
1003 outz_ack
= Signal(reset_less
=True)
1004 m
.d
.comb
+= [outz_stb
.eq(self
.out_zs
[self
.in_mid
].stb
),
1005 outz_ack
.eq(self
.out_zs
[self
.in_mid
].ack
),
1008 self
.out_zs
[self
.in_mid
].v
.eq(self
.in_z
.v
)
1010 with m
.If(outz_stb
& outz_ack
):
1011 m
.d
.sync
+= self
.out_zs
[self
.in_mid
].stb
.eq(0)
1012 m
.next
= self
.to_state
1014 m
.d
.sync
+= self
.out_zs
[self
.in_mid
].stb
.eq(1)
1018 def __init__(self
, width
, id_wid
):
1019 self
.z
= FPOp(width
)
1020 self
.mid
= Signal(id_wid
, reset_less
=True)
1023 return [self
.z
.eq(i
.z
), self
.mid
.eq(i
.mid
)]
1026 return [self
.z
, self
.mid
]
1031 def __init__(self
, width
, id_wid
=None, single_cycle
=False, compact
=True):
1034 * width: bit-width of IEEE754. supported: 16, 32, 64
1035 * id_wid: an identifier that is sync-connected to the input
1036 * single_cycle: True indicates each stage to complete in 1 clock
1037 * compact: True indicates a reduced number of stages
1040 self
.id_wid
= id_wid
1041 self
.single_cycle
= single_cycle
1042 self
.compact
= compact
1044 self
.in_t
= Trigger()
1045 self
.i
= self
.ispec()
1046 self
.o
= self
.ospec()
1051 return FPADDBaseData(self
.width
, self
.id_wid
)
1054 return FPOpData(self
.width
, self
.id_wid
)
1056 def add_state(self
, state
):
1057 self
.states
.append(state
)
1060 def get_fragment(self
, platform
=None):
1061 """ creates the HDL code-fragment for FPAdd
1064 m
.submodules
.out_z
= self
.o
.z
1065 m
.submodules
.in_t
= self
.in_t
1067 self
.get_compact_fragment(m
, platform
)
1069 self
.get_longer_fragment(m
, platform
)
1071 with m
.FSM() as fsm
:
1073 for state
in self
.states
:
1074 with m
.State(state
.state_from
):
1079 def get_longer_fragment(self
, m
, platform
=None):
1081 get
= self
.add_state(FPGet2Op("get_ops", "special_cases",
1083 get
.setup(m
, self
.i
)
1086 get
.trigger_setup(m
, self
.in_t
.stb
, self
.in_t
.ack
)
1088 sc
= self
.add_state(FPAddSpecialCases(self
.width
, self
.id_wid
))
1089 sc
.setup(m
, a
, b
, self
.in_mid
)
1091 dn
= self
.add_state(FPAddDeNorm(self
.width
, self
.id_wid
))
1092 dn
.setup(m
, a
, b
, sc
.in_mid
)
1094 if self
.single_cycle
:
1095 alm
= self
.add_state(FPAddAlignSingle(self
.width
, self
.id_wid
))
1096 alm
.setup(m
, dn
.out_a
, dn
.out_b
, dn
.in_mid
)
1098 alm
= self
.add_state(FPAddAlignMulti(self
.width
, self
.id_wid
))
1099 alm
.setup(m
, dn
.out_a
, dn
.out_b
, dn
.in_mid
)
1101 add0
= self
.add_state(FPAddStage0(self
.width
, self
.id_wid
))
1102 add0
.setup(m
, alm
.out_a
, alm
.out_b
, alm
.in_mid
)
1104 add1
= self
.add_state(FPAddStage1(self
.width
, self
.id_wid
))
1105 add1
.setup(m
, add0
.out_tot
, add0
.out_z
, add0
.in_mid
)
1107 if self
.single_cycle
:
1108 n1
= self
.add_state(FPNorm1Single(self
.width
, self
.id_wid
))
1109 n1
.setup(m
, add1
.out_z
, add1
.out_of
, add0
.in_mid
)
1111 n1
= self
.add_state(FPNorm1Multi(self
.width
, self
.id_wid
))
1112 n1
.setup(m
, add1
.out_z
, add1
.out_of
, add1
.norm_stb
, add0
.in_mid
)
1114 rn
= self
.add_state(FPRound(self
.width
, self
.id_wid
))
1115 rn
.setup(m
, n1
.out_z
, n1
.out_roundz
, n1
.in_mid
)
1117 cor
= self
.add_state(FPCorrections(self
.width
, self
.id_wid
))
1118 cor
.setup(m
, rn
.out_z
, rn
.in_mid
)
1120 pa
= self
.add_state(FPPack(self
.width
, self
.id_wid
))
1121 pa
.setup(m
, cor
.out_z
, rn
.in_mid
)
1123 ppz
= self
.add_state(FPPutZ("pack_put_z", pa
.out_z
, self
.out_z
,
1124 pa
.in_mid
, self
.out_mid
))
1126 pz
= self
.add_state(FPPutZ("put_z", sc
.out_z
, self
.out_z
,
1127 pa
.in_mid
, self
.out_mid
))
1129 def get_compact_fragment(self
, m
, platform
=None):
1132 get
= FPGet2Op("get_ops", "special_cases", self
.width
, self
.id_wid
)
1133 sc
= FPAddSpecialCasesDeNorm(self
.width
, self
.id_wid
)
1134 alm
= FPAddAlignSingleAdd(self
.width
, self
.id_wid
)
1135 n1
= FPNormToPack(self
.width
, self
.id_wid
)
1137 get
.trigger_setup(m
, self
.in_t
.stb
, self
.in_t
.ack
)
1139 chainlist
= [get
, sc
, alm
, n1
]
1140 chain
= StageChain(chainlist
, specallocate
=True)
1141 chain
.setup(m
, self
.i
)
1143 for mod
in chainlist
:
1144 sc
= self
.add_state(mod
)
1146 ppz
= self
.add_state(FPPutZ("pack_put_z", n1
.out_z
.z
, self
.o
,
1147 n1
.out_z
.mid
, self
.o
.mid
))
1149 #pz = self.add_state(FPPutZ("put_z", sc.out_z.z, self.o,
1150 # sc.o.mid, self.o.mid))
1153 class FPADDBase(FPState
):
1155 def __init__(self
, width
, id_wid
=None, single_cycle
=False):
1158 * width: bit-width of IEEE754. supported: 16, 32, 64
1159 * id_wid: an identifier that is sync-connected to the input
1160 * single_cycle: True indicates each stage to complete in 1 clock
1162 FPState
.__init
__(self
, "fpadd")
1164 self
.single_cycle
= single_cycle
1165 self
.mod
= FPADDBaseMod(width
, id_wid
, single_cycle
)
1166 self
.o
= self
.ospec()
1168 self
.in_t
= Trigger()
1169 self
.i
= self
.ispec()
1171 self
.z_done
= Signal(reset_less
=True) # connects to out_z Strobe
1172 self
.in_accept
= Signal(reset_less
=True)
1173 self
.add_stb
= Signal(reset_less
=True)
1174 self
.add_ack
= Signal(reset
=0, reset_less
=True)
1177 return self
.mod
.ispec()
1180 return self
.mod
.ospec()
1182 def setup(self
, m
, i
, add_stb
, in_mid
):
1183 m
.d
.comb
+= [self
.i
.eq(i
),
1184 self
.mod
.i
.eq(self
.i
),
1185 self
.z_done
.eq(self
.mod
.o
.z
.trigger
),
1186 #self.add_stb.eq(add_stb),
1187 self
.mod
.in_t
.stb
.eq(self
.in_t
.stb
),
1188 self
.in_t
.ack
.eq(self
.mod
.in_t
.ack
),
1189 self
.o
.mid
.eq(self
.mod
.o
.mid
),
1190 self
.o
.z
.v
.eq(self
.mod
.o
.z
.v
),
1191 self
.o
.z
.stb
.eq(self
.mod
.o
.z
.stb
),
1192 self
.mod
.o
.z
.ack
.eq(self
.o
.z
.ack
),
1195 m
.d
.sync
+= self
.add_stb
.eq(add_stb
)
1196 m
.d
.sync
+= self
.add_ack
.eq(0) # sets to zero when not in active state
1197 m
.d
.sync
+= self
.o
.z
.ack
.eq(0) # likewise
1198 #m.d.sync += self.in_t.stb.eq(0)
1200 m
.submodules
.fpadd
= self
.mod
1202 def action(self
, m
):
1204 # in_accept is set on incoming strobe HIGH and ack LOW.
1205 m
.d
.comb
+= self
.in_accept
.eq((~self
.add_ack
) & (self
.add_stb
))
1207 #with m.If(self.in_t.ack):
1208 # m.d.sync += self.in_t.stb.eq(0)
1209 with m
.If(~self
.z_done
):
1210 # not done: test for accepting an incoming operand pair
1211 with m
.If(self
.in_accept
):
1213 self
.add_ack
.eq(1), # acknowledge receipt...
1214 self
.in_t
.stb
.eq(1), # initiate add
1217 m
.d
.sync
+= [self
.add_ack
.eq(0),
1218 self
.in_t
.stb
.eq(0),
1222 # done: acknowledge, and write out id and value
1223 m
.d
.sync
+= [self
.add_ack
.eq(1),
1230 if self
.in_mid
is not None:
1231 m
.d
.sync
+= self
.out_mid
.eq(self
.mod
.out_mid
)
1234 self
.out_z
.v
.eq(self
.mod
.out_z
.v
)
1236 # move to output state on detecting z ack
1237 with m
.If(self
.out_z
.trigger
):
1238 m
.d
.sync
+= self
.out_z
.stb
.eq(0)
1241 m
.d
.sync
+= self
.out_z
.stb
.eq(1)
1244 class FPADDBasePipe(ControlBase
):
1245 def __init__(self
, width
, id_wid
):
1246 ControlBase
.__init
__(self
)
1247 self
.pipe1
= FPAddSpecialCasesDeNorm(width
, id_wid
)
1248 self
.pipe2
= FPAddAlignSingleAdd(width
, id_wid
)
1249 self
.pipe3
= FPNormToPack(width
, id_wid
)
1251 self
._eqs
= self
.connect([self
.pipe1
, self
.pipe2
, self
.pipe3
])
1253 def elaborate(self
, platform
):
1255 m
.submodules
.scnorm
= self
.pipe1
1256 m
.submodules
.addalign
= self
.pipe2
1257 m
.submodules
.normpack
= self
.pipe3
1258 m
.d
.comb
+= self
._eqs
1262 class FPADDInMuxPipe(PriorityCombMuxInPipe
):
1263 def __init__(self
, width
, id_wid
, num_rows
):
1264 self
.num_rows
= num_rows
1265 def iospec(): return FPADDBaseData(width
, id_wid
)
1266 stage
= PassThroughStage(iospec
)
1267 PriorityCombMuxInPipe
.__init
__(self
, stage
, p_len
=self
.num_rows
)
1270 class FPADDMuxOutPipe(CombMuxOutPipe
):
1271 def __init__(self
, width
, id_wid
, num_rows
):
1272 self
.num_rows
= num_rows
1273 def iospec(): return FPPackData(width
, id_wid
)
1274 stage
= PassThroughStage(iospec
)
1275 CombMuxOutPipe
.__init
__(self
, stage
, n_len
=self
.num_rows
)
1278 class FPADDMuxInOut
:
1279 """ Reservation-Station version of FPADD pipeline.
1281 * fan-in on inputs (an array of FPADDBaseData: a,b,mid)
1282 * 3-stage adder pipeline
1283 * fan-out on outputs (an array of FPPackData: z,mid)
1285 Fan-in and Fan-out are combinatorial.
1287 def __init__(self
, width
, id_wid
, num_rows
):
1288 self
.num_rows
= num_rows
1289 self
.inpipe
= FPADDInMuxPipe(width
, id_wid
, num_rows
) # fan-in
1290 self
.fpadd
= FPADDBasePipe(width
, id_wid
) # add stage
1291 self
.outpipe
= FPADDMuxOutPipe(width
, id_wid
, num_rows
) # fan-out
1293 self
.p
= self
.inpipe
.p
# kinda annoying,
1294 self
.n
= self
.outpipe
.n
# use pipe in/out as this class in/out
1295 self
._ports
= self
.inpipe
.ports() + self
.outpipe
.ports()
1297 def elaborate(self
, platform
):
1299 m
.submodules
.inpipe
= self
.inpipe
1300 m
.submodules
.fpadd
= self
.fpadd
1301 m
.submodules
.outpipe
= self
.outpipe
1303 m
.d
.comb
+= self
.inpipe
.n
.connect_to_next(self
.fpadd
.p
)
1304 m
.d
.comb
+= self
.fpadd
.connect_to_next(self
.outpipe
)
1313 """ FPADD: stages as follows:
1319 FPAddBase---> FPAddBaseMod
1321 PutZ GetOps->Specials->Align->Add1/2->Norm->Round/Pack->PutZ
1323 FPAddBase is tricky: it is both a stage and *has* stages.
1324 Connection to FPAddBaseMod therefore requires an in stb/ack
1325 and an out stb/ack. Just as with Add1-Norm1 interaction, FPGetOp
1326 needs to be the thing that raises the incoming stb.
1329 def __init__(self
, width
, id_wid
=None, single_cycle
=False, rs_sz
=2):
1332 * width: bit-width of IEEE754. supported: 16, 32, 64
1333 * id_wid: an identifier that is sync-connected to the input
1334 * single_cycle: True indicates each stage to complete in 1 clock
1337 self
.id_wid
= id_wid
1338 self
.single_cycle
= single_cycle
1340 #self.out_z = FPOp(width)
1341 self
.ids
= FPID(id_wid
)
1344 for i
in range(rs_sz
):
1347 in_a
.name
= "in_a_%d" % i
1348 in_b
.name
= "in_b_%d" % i
1349 rs
.append((in_a
, in_b
))
1353 for i
in range(rs_sz
):
1355 out_z
.name
= "out_z_%d" % i
1357 self
.res
= Array(res
)
1361 def add_state(self
, state
):
1362 self
.states
.append(state
)
1365 def get_fragment(self
, platform
=None):
1366 """ creates the HDL code-fragment for FPAdd
1369 m
.submodules
+= self
.rs
1371 in_a
= self
.rs
[0][0]
1372 in_b
= self
.rs
[0][1]
1374 geta
= self
.add_state(FPGetOp("get_a", "get_b",
1379 getb
= self
.add_state(FPGetOp("get_b", "fpadd",
1384 ab
= FPADDBase(self
.width
, self
.id_wid
, self
.single_cycle
)
1385 ab
= self
.add_state(ab
)
1386 abd
= ab
.ispec() # create an input spec object for FPADDBase
1387 m
.d
.sync
+= [abd
.a
.eq(a
), abd
.b
.eq(b
), abd
.mid
.eq(self
.ids
.in_mid
)]
1388 ab
.setup(m
, abd
, getb
.out_decode
, self
.ids
.in_mid
)
1391 pz
= self
.add_state(FPPutZIdx("put_z", o
.z
, self
.res
,
1394 with m
.FSM() as fsm
:
1396 for state
in self
.states
:
1397 with m
.State(state
.state_from
):
1403 if __name__
== "__main__":
1405 alu
= FPADD(width
=32, id_wid
=5, single_cycle
=True)
1406 main(alu
, ports
=alu
.rs
[0][0].ports() + \
1407 alu
.rs
[0][1].ports() + \
1408 alu
.res
[0].ports() + \
1409 [alu
.ids
.in_mid
, alu
.ids
.out_mid
])
1411 alu
= FPADDBase(width
=32, id_wid
=5, single_cycle
=True)
1412 main(alu
, ports
=[alu
.in_a
, alu
.in_b
] + \
1413 alu
.in_t
.ports() + \
1414 alu
.out_z
.ports() + \
1415 [alu
.in_mid
, alu
.out_mid
])
1418 # works... but don't use, just do "python fname.py convert -t v"
1419 #print (verilog.convert(alu, ports=[
1420 # ports=alu.in_a.ports() + \
1421 # alu.in_b.ports() + \
1422 # alu.out_z.ports())