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
, FPID
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
)
145 class FPAddSpecialCases(FPState
):
146 """ special cases: NaNs, infs, zeros, denormalised
147 NOTE: some of these are unique to add. see "Special Operations"
148 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
151 def __init__(self
, width
, id_wid
):
152 FPState
.__init
__(self
, "special_cases")
153 self
.mod
= FPAddSpecialCasesMod(width
)
154 self
.out_z
= self
.mod
.ospec()
155 self
.out_do_z
= Signal(reset_less
=True)
157 def setup(self
, m
, i
):
158 """ links module to inputs and outputs
160 self
.mod
.setup(m
, i
, self
.out_do_z
)
161 m
.d
.sync
+= self
.out_z
.v
.eq(self
.mod
.out_z
.v
) # only take the output
162 m
.d
.sync
+= self
.out_z
.mid
.eq(self
.mod
.o
.mid
) # (and mid)
166 with m
.If(self
.out_do_z
):
169 m
.next
= "denormalise"
172 class FPAddSpecialCasesDeNorm(FPState
, UnbufferedPipeline
):
173 """ special cases: NaNs, infs, zeros, denormalised
174 NOTE: some of these are unique to add. see "Special Operations"
175 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
178 def __init__(self
, width
, id_wid
):
179 FPState
.__init
__(self
, "special_cases")
182 UnbufferedPipeline
.__init
__(self
, self
) # pipe is its own stage
183 self
.out
= self
.ospec()
186 return FPADDBaseData(self
.width
, self
.id_wid
) # SpecialCases ispec
189 return FPSCData(self
.width
, self
.id_wid
) # DeNorm ospec
191 def setup(self
, m
, i
):
192 """ links module to inputs and outputs
194 smod
= FPAddSpecialCasesMod(self
.width
, self
.id_wid
)
195 dmod
= FPAddDeNormMod(self
.width
, self
.id_wid
)
197 chain
= StageChain([smod
, dmod
])
200 # only needed for break-out (early-out)
201 # self.out_do_z = smod.o.out_do_z
205 def process(self
, i
):
209 # for break-out (early-out)
210 #with m.If(self.out_do_z):
213 m
.d
.sync
+= self
.out
.eq(self
.process(None))
217 class FPAddAlignMultiMod(FPState
):
219 def __init__(self
, width
):
220 self
.in_a
= FPNumBase(width
)
221 self
.in_b
= FPNumBase(width
)
222 self
.out_a
= FPNumIn(None, width
)
223 self
.out_b
= FPNumIn(None, width
)
224 self
.exp_eq
= Signal(reset_less
=True)
226 def elaborate(self
, platform
):
227 # This one however (single-cycle) will do the shift
232 m
.submodules
.align_in_a
= self
.in_a
233 m
.submodules
.align_in_b
= self
.in_b
234 m
.submodules
.align_out_a
= self
.out_a
235 m
.submodules
.align_out_b
= self
.out_b
237 # NOTE: this does *not* do single-cycle multi-shifting,
238 # it *STAYS* in the align state until exponents match
240 # exponent of a greater than b: shift b down
241 m
.d
.comb
+= self
.exp_eq
.eq(0)
242 m
.d
.comb
+= self
.out_a
.eq(self
.in_a
)
243 m
.d
.comb
+= self
.out_b
.eq(self
.in_b
)
244 agtb
= Signal(reset_less
=True)
245 altb
= Signal(reset_less
=True)
246 m
.d
.comb
+= agtb
.eq(self
.in_a
.e
> self
.in_b
.e
)
247 m
.d
.comb
+= altb
.eq(self
.in_a
.e
< self
.in_b
.e
)
249 m
.d
.comb
+= self
.out_b
.shift_down(self
.in_b
)
250 # exponent of b greater than a: shift a down
252 m
.d
.comb
+= self
.out_a
.shift_down(self
.in_a
)
253 # exponents equal: move to next stage.
255 m
.d
.comb
+= self
.exp_eq
.eq(1)
259 class FPAddAlignMulti(FPState
):
261 def __init__(self
, width
, id_wid
):
262 FPState
.__init
__(self
, "align")
263 self
.mod
= FPAddAlignMultiMod(width
)
264 self
.out_a
= FPNumIn(None, width
)
265 self
.out_b
= FPNumIn(None, width
)
266 self
.exp_eq
= Signal(reset_less
=True)
268 def setup(self
, m
, in_a
, in_b
):
269 """ links module to inputs and outputs
271 m
.submodules
.align
= self
.mod
272 m
.d
.comb
+= self
.mod
.in_a
.eq(in_a
)
273 m
.d
.comb
+= self
.mod
.in_b
.eq(in_b
)
274 m
.d
.comb
+= self
.exp_eq
.eq(self
.mod
.exp_eq
)
275 m
.d
.sync
+= self
.out_a
.eq(self
.mod
.out_a
)
276 m
.d
.sync
+= self
.out_b
.eq(self
.mod
.out_b
)
279 with m
.If(self
.exp_eq
):
285 def __init__(self
, width
, id_wid
):
286 self
.a
= FPNumIn(None, width
)
287 self
.b
= FPNumIn(None, width
)
288 self
.z
= FPNumOut(width
, False)
289 self
.out_do_z
= Signal(reset_less
=True)
290 self
.oz
= Signal(width
, reset_less
=True)
291 self
.mid
= Signal(id_wid
, reset_less
=True)
294 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
295 self
.a
.eq(i
.a
), self
.b
.eq(i
.b
), self
.mid
.eq(i
.mid
)]
298 class FPAddAlignSingleMod
:
300 def __init__(self
, width
, id_wid
):
303 self
.i
= self
.ispec()
304 self
.o
= self
.ospec()
307 return FPSCData(self
.width
, self
.id_wid
)
310 return FPNumIn2Ops(self
.width
, self
.id_wid
)
312 def process(self
, i
):
315 def setup(self
, m
, i
):
316 """ links module to inputs and outputs
318 m
.submodules
.align
= self
319 m
.d
.comb
+= self
.i
.eq(i
)
321 def elaborate(self
, platform
):
322 """ Aligns A against B or B against A, depending on which has the
323 greater exponent. This is done in a *single* cycle using
324 variable-width bit-shift
326 the shifter used here is quite expensive in terms of gates.
327 Mux A or B in (and out) into temporaries, as only one of them
328 needs to be aligned against the other
332 m
.submodules
.align_in_a
= self
.i
.a
333 m
.submodules
.align_in_b
= self
.i
.b
334 m
.submodules
.align_out_a
= self
.o
.a
335 m
.submodules
.align_out_b
= self
.o
.b
337 # temporary (muxed) input and output to be shifted
338 t_inp
= FPNumBase(self
.width
)
339 t_out
= FPNumIn(None, self
.width
)
340 espec
= (len(self
.i
.a
.e
), True)
341 msr
= MultiShiftRMerge(self
.i
.a
.m_width
, espec
)
342 m
.submodules
.align_t_in
= t_inp
343 m
.submodules
.align_t_out
= t_out
344 m
.submodules
.multishift_r
= msr
346 ediff
= Signal(espec
, reset_less
=True)
347 ediffr
= Signal(espec
, reset_less
=True)
348 tdiff
= Signal(espec
, reset_less
=True)
349 elz
= Signal(reset_less
=True)
350 egz
= Signal(reset_less
=True)
352 # connect multi-shifter to t_inp/out mantissa (and tdiff)
353 m
.d
.comb
+= msr
.inp
.eq(t_inp
.m
)
354 m
.d
.comb
+= msr
.diff
.eq(tdiff
)
355 m
.d
.comb
+= t_out
.m
.eq(msr
.m
)
356 m
.d
.comb
+= t_out
.e
.eq(t_inp
.e
+ tdiff
)
357 m
.d
.comb
+= t_out
.s
.eq(t_inp
.s
)
359 m
.d
.comb
+= ediff
.eq(self
.i
.a
.e
- self
.i
.b
.e
)
360 m
.d
.comb
+= ediffr
.eq(self
.i
.b
.e
- self
.i
.a
.e
)
361 m
.d
.comb
+= elz
.eq(self
.i
.a
.e
< self
.i
.b
.e
)
362 m
.d
.comb
+= egz
.eq(self
.i
.a
.e
> self
.i
.b
.e
)
364 # default: A-exp == B-exp, A and B untouched (fall through)
365 m
.d
.comb
+= self
.o
.a
.eq(self
.i
.a
)
366 m
.d
.comb
+= self
.o
.b
.eq(self
.i
.b
)
367 # only one shifter (muxed)
368 #m.d.comb += t_out.shift_down_multi(tdiff, t_inp)
369 # exponent of a greater than b: shift b down
370 with m
.If(~self
.i
.out_do_z
):
372 m
.d
.comb
+= [t_inp
.eq(self
.i
.b
),
375 self
.o
.b
.s
.eq(self
.i
.b
.s
), # whoops forgot sign
377 # exponent of b greater than a: shift a down
379 m
.d
.comb
+= [t_inp
.eq(self
.i
.a
),
382 self
.o
.a
.s
.eq(self
.i
.a
.s
), # whoops forgot sign
385 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
386 m
.d
.comb
+= self
.o
.z
.eq(self
.i
.z
)
387 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
388 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
393 class FPAddAlignSingle(FPState
):
395 def __init__(self
, width
, id_wid
):
396 FPState
.__init
__(self
, "align")
397 self
.mod
= FPAddAlignSingleMod(width
, id_wid
)
398 self
.out_a
= FPNumIn(None, width
)
399 self
.out_b
= FPNumIn(None, width
)
401 def setup(self
, m
, i
):
402 """ links module to inputs and outputs
406 # NOTE: could be done as comb
407 m
.d
.sync
+= self
.out_a
.eq(self
.mod
.out_a
)
408 m
.d
.sync
+= self
.out_b
.eq(self
.mod
.out_b
)
414 class FPAddAlignSingleAdd(FPState
, UnbufferedPipeline
):
416 def __init__(self
, width
, id_wid
):
417 FPState
.__init
__(self
, "align")
420 UnbufferedPipeline
.__init
__(self
, self
) # pipeline is its own stage
421 self
.a1o
= self
.ospec()
424 return FPSCData(self
.width
, self
.id_wid
)
427 return FPAddStage1Data(self
.width
, self
.id_wid
) # AddStage1 ospec
429 def setup(self
, m
, i
):
430 """ links module to inputs and outputs
433 # chain AddAlignSingle, AddStage0 and AddStage1
434 mod
= FPAddAlignSingleMod(self
.width
, self
.id_wid
)
435 a0mod
= FPAddStage0Mod(self
.width
, self
.id_wid
)
436 a1mod
= FPAddStage1Mod(self
.width
, self
.id_wid
)
438 chain
= StageChain([mod
, a0mod
, a1mod
])
443 def process(self
, i
):
447 m
.d
.sync
+= self
.a1o
.eq(self
.process(None))
448 m
.next
= "normalise_1"
451 class FPAddStage0Data
:
453 def __init__(self
, width
, id_wid
):
454 self
.z
= FPNumBase(width
, False)
455 self
.out_do_z
= Signal(reset_less
=True)
456 self
.oz
= Signal(width
, reset_less
=True)
457 self
.tot
= Signal(self
.z
.m_width
+ 4, reset_less
=True)
458 self
.mid
= Signal(id_wid
, reset_less
=True)
461 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
462 self
.tot
.eq(i
.tot
), self
.mid
.eq(i
.mid
)]
465 class FPAddStage0Mod
:
467 def __init__(self
, width
, id_wid
):
470 self
.i
= self
.ispec()
471 self
.o
= self
.ospec()
474 return FPSCData(self
.width
, self
.id_wid
)
477 return FPAddStage0Data(self
.width
, self
.id_wid
)
479 def process(self
, i
):
482 def setup(self
, m
, i
):
483 """ links module to inputs and outputs
485 m
.submodules
.add0
= self
486 m
.d
.comb
+= self
.i
.eq(i
)
488 def elaborate(self
, platform
):
490 m
.submodules
.add0_in_a
= self
.i
.a
491 m
.submodules
.add0_in_b
= self
.i
.b
492 m
.submodules
.add0_out_z
= self
.o
.z
494 # store intermediate tests (and zero-extended mantissas)
495 seq
= Signal(reset_less
=True)
496 mge
= Signal(reset_less
=True)
497 am0
= Signal(len(self
.i
.a
.m
)+1, reset_less
=True)
498 bm0
= Signal(len(self
.i
.b
.m
)+1, reset_less
=True)
499 m
.d
.comb
+= [seq
.eq(self
.i
.a
.s
== self
.i
.b
.s
),
500 mge
.eq(self
.i
.a
.m
>= self
.i
.b
.m
),
501 am0
.eq(Cat(self
.i
.a
.m
, 0)),
502 bm0
.eq(Cat(self
.i
.b
.m
, 0))
504 # same-sign (both negative or both positive) add mantissas
505 with m
.If(~self
.i
.out_do_z
):
506 m
.d
.comb
+= self
.o
.z
.e
.eq(self
.i
.a
.e
)
509 self
.o
.tot
.eq(am0
+ bm0
),
510 self
.o
.z
.s
.eq(self
.i
.a
.s
)
512 # a mantissa greater than b, use a
515 self
.o
.tot
.eq(am0
- bm0
),
516 self
.o
.z
.s
.eq(self
.i
.a
.s
)
518 # b mantissa greater than a, use b
521 self
.o
.tot
.eq(bm0
- am0
),
522 self
.o
.z
.s
.eq(self
.i
.b
.s
)
525 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
526 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
527 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
531 class FPAddStage0(FPState
):
532 """ First stage of add. covers same-sign (add) and subtract
533 special-casing when mantissas are greater or equal, to
534 give greatest accuracy.
537 def __init__(self
, width
, id_wid
):
538 FPState
.__init
__(self
, "add_0")
539 self
.mod
= FPAddStage0Mod(width
)
540 self
.o
= self
.mod
.ospec()
542 def setup(self
, m
, i
):
543 """ links module to inputs and outputs
547 # NOTE: these could be done as combinatorial (merge add0+add1)
548 m
.d
.sync
+= self
.o
.eq(self
.mod
.o
)
554 class FPAddStage1Mod(FPState
):
555 """ Second stage of add: preparation for normalisation.
556 detects when tot sum is too big (tot[27] is kinda a carry bit)
559 def __init__(self
, width
, id_wid
):
562 self
.i
= self
.ispec()
563 self
.o
= self
.ospec()
566 return FPAddStage0Data(self
.width
, self
.id_wid
)
569 return FPAddStage1Data(self
.width
, self
.id_wid
)
571 def process(self
, i
):
574 def setup(self
, m
, i
):
575 """ links module to inputs and outputs
577 m
.submodules
.add1
= self
578 m
.submodules
.add1_out_overflow
= self
.o
.of
580 m
.d
.comb
+= self
.i
.eq(i
)
582 def elaborate(self
, platform
):
584 m
.d
.comb
+= self
.o
.z
.eq(self
.i
.z
)
585 # tot[-1] (MSB) gets set when the sum overflows. shift result down
586 with m
.If(~self
.i
.out_do_z
):
587 with m
.If(self
.i
.tot
[-1]):
589 self
.o
.z
.m
.eq(self
.i
.tot
[4:]),
590 self
.o
.of
.m0
.eq(self
.i
.tot
[4]),
591 self
.o
.of
.guard
.eq(self
.i
.tot
[3]),
592 self
.o
.of
.round_bit
.eq(self
.i
.tot
[2]),
593 self
.o
.of
.sticky
.eq(self
.i
.tot
[1] | self
.i
.tot
[0]),
594 self
.o
.z
.e
.eq(self
.i
.z
.e
+ 1)
596 # tot[-1] (MSB) zero case
599 self
.o
.z
.m
.eq(self
.i
.tot
[3:]),
600 self
.o
.of
.m0
.eq(self
.i
.tot
[3]),
601 self
.o
.of
.guard
.eq(self
.i
.tot
[2]),
602 self
.o
.of
.round_bit
.eq(self
.i
.tot
[1]),
603 self
.o
.of
.sticky
.eq(self
.i
.tot
[0])
606 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
607 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
608 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
613 class FPAddStage1(FPState
):
615 def __init__(self
, width
, id_wid
):
616 FPState
.__init
__(self
, "add_1")
617 self
.mod
= FPAddStage1Mod(width
)
618 self
.out_z
= FPNumBase(width
, False)
619 self
.out_of
= Overflow()
620 self
.norm_stb
= Signal()
622 def setup(self
, m
, i
):
623 """ links module to inputs and outputs
627 m
.d
.sync
+= self
.norm_stb
.eq(0) # sets to zero when not in add1 state
629 m
.d
.sync
+= self
.out_of
.eq(self
.mod
.out_of
)
630 m
.d
.sync
+= self
.out_z
.eq(self
.mod
.out_z
)
631 m
.d
.sync
+= self
.norm_stb
.eq(1)
634 m
.next
= "normalise_1"
639 def __init__(self
, width
, single_cycle
=True):
641 self
.in_select
= Signal(reset_less
=True)
642 self
.in_z
= FPNumBase(width
, False)
643 self
.in_of
= Overflow()
644 self
.temp_z
= FPNumBase(width
, False)
645 self
.temp_of
= Overflow()
646 self
.out_z
= FPNumBase(width
, False)
647 self
.out_of
= Overflow()
649 def elaborate(self
, platform
):
652 m
.submodules
.norm1_out_z
= self
.out_z
653 m
.submodules
.norm1_out_overflow
= self
.out_of
654 m
.submodules
.norm1_temp_z
= self
.temp_z
655 m
.submodules
.norm1_temp_of
= self
.temp_of
656 m
.submodules
.norm1_in_z
= self
.in_z
657 m
.submodules
.norm1_in_overflow
= self
.in_of
659 in_z
= FPNumBase(self
.width
, False)
661 m
.submodules
.norm1_insel_z
= in_z
662 m
.submodules
.norm1_insel_overflow
= in_of
664 # select which of temp or in z/of to use
665 with m
.If(self
.in_select
):
666 m
.d
.comb
+= in_z
.eq(self
.in_z
)
667 m
.d
.comb
+= in_of
.eq(self
.in_of
)
669 m
.d
.comb
+= in_z
.eq(self
.temp_z
)
670 m
.d
.comb
+= in_of
.eq(self
.temp_of
)
671 # initialise out from in (overridden below)
672 m
.d
.comb
+= self
.out_z
.eq(in_z
)
673 m
.d
.comb
+= self
.out_of
.eq(in_of
)
674 # normalisation increase/decrease conditions
675 decrease
= Signal(reset_less
=True)
676 increase
= Signal(reset_less
=True)
677 m
.d
.comb
+= decrease
.eq(in_z
.m_msbzero
& in_z
.exp_gt_n126
)
678 m
.d
.comb
+= increase
.eq(in_z
.exp_lt_n126
)
679 m
.d
.comb
+= self
.out_norm
.eq(decrease | increase
) # loop-end
683 self
.out_z
.e
.eq(in_z
.e
- 1), # DECREASE exponent
684 self
.out_z
.m
.eq(in_z
.m
<< 1), # shift mantissa UP
685 self
.out_z
.m
[0].eq(in_of
.guard
), # steal guard (was tot[2])
686 self
.out_of
.guard
.eq(in_of
.round_bit
), # round (was tot[1])
687 self
.out_of
.round_bit
.eq(0), # reset round bit
688 self
.out_of
.m0
.eq(in_of
.guard
),
691 with m
.Elif(increase
):
693 self
.out_z
.e
.eq(in_z
.e
+ 1), # INCREASE exponent
694 self
.out_z
.m
.eq(in_z
.m
>> 1), # shift mantissa DOWN
695 self
.out_of
.guard
.eq(in_z
.m
[0]),
696 self
.out_of
.m0
.eq(in_z
.m
[1]),
697 self
.out_of
.round_bit
.eq(in_of
.guard
),
698 self
.out_of
.sticky
.eq(in_of
.sticky | in_of
.round_bit
)
704 class FPNormToPack(FPState
, UnbufferedPipeline
):
706 def __init__(self
, width
, id_wid
):
707 FPState
.__init
__(self
, "normalise_1")
710 UnbufferedPipeline
.__init
__(self
, self
) # pipeline is its own stage
713 return FPAddStage1Data(self
.width
, self
.id_wid
) # Norm1ModSingle ispec
716 return FPPackData(self
.width
, self
.id_wid
) # FPPackMod ospec
718 def setup(self
, m
, i
):
719 """ links module to inputs and outputs
722 # Normalisation, Rounding Corrections, Pack - in a chain
723 nmod
= FPNorm1ModSingle(self
.width
, self
.id_wid
)
724 rmod
= FPRoundMod(self
.width
, self
.id_wid
)
725 cmod
= FPCorrectionsMod(self
.width
, self
.id_wid
)
726 pmod
= FPPackMod(self
.width
, self
.id_wid
)
727 chain
= StageChain([nmod
, rmod
, cmod
, pmod
])
729 self
.out_z
= pmod
.ospec()
733 def process(self
, i
):
737 m
.d
.sync
+= self
.out_z
.eq(self
.process(None))
738 m
.next
= "pack_put_z"
743 def __init__(self
, width
, id_wid
):
744 self
.z
= FPNumBase(width
, False)
745 self
.out_do_z
= Signal(reset_less
=True)
746 self
.oz
= Signal(width
, reset_less
=True)
747 self
.mid
= Signal(id_wid
, reset_less
=True)
750 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
756 def __init__(self
, width
, id_wid
):
759 self
.i
= self
.ispec()
760 self
.out_z
= self
.ospec()
763 return FPNorm1Data(self
.width
, self
.id_wid
)
766 return FPRoundData(self
.width
, self
.id_wid
)
768 def process(self
, i
):
771 def setup(self
, m
, i
):
772 m
.submodules
.roundz
= self
773 m
.d
.comb
+= self
.i
.eq(i
)
775 def elaborate(self
, platform
):
777 m
.d
.comb
+= self
.out_z
.eq(self
.i
) # copies mid, z, out_do_z
778 with m
.If(~self
.i
.out_do_z
):
779 with m
.If(self
.i
.roundz
):
780 m
.d
.comb
+= self
.out_z
.z
.m
.eq(self
.i
.z
.m
+ 1) # mantissa up
781 with m
.If(self
.i
.z
.m
== self
.i
.z
.m1s
): # all 1s
782 m
.d
.comb
+= self
.out_z
.z
.e
.eq(self
.i
.z
.e
+ 1) # exponent up
787 class FPRound(FPState
):
789 def __init__(self
, width
, id_wid
):
790 FPState
.__init
__(self
, "round")
791 self
.mod
= FPRoundMod(width
)
792 self
.out_z
= self
.ospec()
795 return self
.mod
.ispec()
798 return self
.mod
.ospec()
800 def setup(self
, m
, i
):
801 """ links module to inputs and outputs
806 m
.d
.sync
+= self
.out_z
.eq(self
.mod
.out_z
)
807 m
.d
.sync
+= self
.out_z
.mid
.eq(self
.mod
.o
.mid
)
810 m
.next
= "corrections"
813 class FPCorrectionsMod
:
815 def __init__(self
, width
, id_wid
):
818 self
.i
= self
.ispec()
819 self
.out_z
= self
.ospec()
822 return FPRoundData(self
.width
, self
.id_wid
)
825 return FPRoundData(self
.width
, self
.id_wid
)
827 def process(self
, i
):
830 def setup(self
, m
, i
):
831 """ links module to inputs and outputs
833 m
.submodules
.corrections
= self
834 m
.d
.comb
+= self
.i
.eq(i
)
836 def elaborate(self
, platform
):
838 m
.submodules
.corr_in_z
= self
.i
.z
839 m
.submodules
.corr_out_z
= self
.out_z
.z
840 m
.d
.comb
+= self
.out_z
.eq(self
.i
) # copies mid, z, out_do_z
841 with m
.If(~self
.i
.out_do_z
):
842 with m
.If(self
.i
.z
.is_denormalised
):
843 m
.d
.comb
+= self
.out_z
.z
.e
.eq(self
.i
.z
.N127
)
847 class FPCorrections(FPState
):
849 def __init__(self
, width
, id_wid
):
850 FPState
.__init
__(self
, "corrections")
851 self
.mod
= FPCorrectionsMod(width
)
852 self
.out_z
= self
.ospec()
855 return self
.mod
.ispec()
858 return self
.mod
.ospec()
860 def setup(self
, m
, in_z
):
861 """ links module to inputs and outputs
863 self
.mod
.setup(m
, in_z
)
865 m
.d
.sync
+= self
.out_z
.eq(self
.mod
.out_z
)
866 m
.d
.sync
+= self
.out_z
.mid
.eq(self
.mod
.o
.mid
)
874 def __init__(self
, width
, id_wid
):
875 self
.z
= Signal(width
, reset_less
=True)
876 self
.mid
= Signal(id_wid
, reset_less
=True)
879 return [self
.z
.eq(i
.z
), self
.mid
.eq(i
.mid
)]
882 return [self
.z
, self
.mid
]
887 def __init__(self
, width
, id_wid
):
890 self
.i
= self
.ispec()
891 self
.o
= self
.ospec()
894 return FPRoundData(self
.width
, self
.id_wid
)
897 return FPPackData(self
.width
, self
.id_wid
)
899 def process(self
, i
):
902 def setup(self
, m
, in_z
):
903 """ links module to inputs and outputs
905 m
.submodules
.pack
= self
906 m
.d
.comb
+= self
.i
.eq(in_z
)
908 def elaborate(self
, platform
):
910 z
= FPNumOut(self
.width
, False)
911 m
.submodules
.pack_in_z
= self
.i
.z
912 m
.submodules
.pack_out_z
= z
913 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
914 with m
.If(~self
.i
.out_do_z
):
915 with m
.If(self
.i
.z
.is_overflowed
):
916 m
.d
.comb
+= z
.inf(self
.i
.z
.s
)
918 m
.d
.comb
+= z
.create(self
.i
.z
.s
, self
.i
.z
.e
, self
.i
.z
.m
)
920 m
.d
.comb
+= z
.v
.eq(self
.i
.oz
)
921 m
.d
.comb
+= self
.o
.z
.eq(z
.v
)
925 class FPPack(FPState
):
927 def __init__(self
, width
, id_wid
):
928 FPState
.__init
__(self
, "pack")
929 self
.mod
= FPPackMod(width
)
930 self
.out_z
= self
.ospec()
933 return self
.mod
.ispec()
936 return self
.mod
.ospec()
938 def setup(self
, m
, in_z
):
939 """ links module to inputs and outputs
941 self
.mod
.setup(m
, in_z
)
943 m
.d
.sync
+= self
.out_z
.v
.eq(self
.mod
.out_z
.v
)
944 m
.d
.sync
+= self
.out_z
.mid
.eq(self
.mod
.o
.mid
)
947 m
.next
= "pack_put_z"
950 class FPPutZ(FPState
):
952 def __init__(self
, state
, in_z
, out_z
, in_mid
, out_mid
, to_state
=None):
953 FPState
.__init
__(self
, state
)
956 self
.to_state
= to_state
960 self
.out_mid
= out_mid
963 if self
.in_mid
is not None:
964 m
.d
.sync
+= self
.out_mid
.eq(self
.in_mid
)
966 self
.out_z
.z
.v
.eq(self
.in_z
)
968 with m
.If(self
.out_z
.z
.stb
& self
.out_z
.z
.ack
):
969 m
.d
.sync
+= self
.out_z
.z
.stb
.eq(0)
970 m
.next
= self
.to_state
972 m
.d
.sync
+= self
.out_z
.z
.stb
.eq(1)
975 class FPPutZIdx(FPState
):
977 def __init__(self
, state
, in_z
, out_zs
, in_mid
, to_state
=None):
978 FPState
.__init
__(self
, state
)
981 self
.to_state
= to_state
987 outz_stb
= Signal(reset_less
=True)
988 outz_ack
= Signal(reset_less
=True)
989 m
.d
.comb
+= [outz_stb
.eq(self
.out_zs
[self
.in_mid
].stb
),
990 outz_ack
.eq(self
.out_zs
[self
.in_mid
].ack
),
993 self
.out_zs
[self
.in_mid
].v
.eq(self
.in_z
.v
)
995 with m
.If(outz_stb
& outz_ack
):
996 m
.d
.sync
+= self
.out_zs
[self
.in_mid
].stb
.eq(0)
997 m
.next
= self
.to_state
999 m
.d
.sync
+= self
.out_zs
[self
.in_mid
].stb
.eq(1)
1003 def __init__(self
, width
, id_wid
):
1004 self
.z
= FPOp(width
)
1005 self
.mid
= Signal(id_wid
, reset_less
=True)
1008 return [self
.z
.eq(i
.z
), self
.mid
.eq(i
.mid
)]
1011 return [self
.z
, self
.mid
]
1016 def __init__(self
, width
, id_wid
=None, single_cycle
=False, compact
=True):
1019 * width: bit-width of IEEE754. supported: 16, 32, 64
1020 * id_wid: an identifier that is sync-connected to the input
1021 * single_cycle: True indicates each stage to complete in 1 clock
1022 * compact: True indicates a reduced number of stages
1025 self
.id_wid
= id_wid
1026 self
.single_cycle
= single_cycle
1027 self
.compact
= compact
1029 self
.in_t
= Trigger()
1030 self
.i
= self
.ispec()
1031 self
.o
= self
.ospec()
1036 return FPADDBaseData(self
.width
, self
.id_wid
)
1039 return FPOpData(self
.width
, self
.id_wid
)
1041 def add_state(self
, state
):
1042 self
.states
.append(state
)
1045 def get_fragment(self
, platform
=None):
1046 """ creates the HDL code-fragment for FPAdd
1049 m
.submodules
.out_z
= self
.o
.z
1050 m
.submodules
.in_t
= self
.in_t
1052 self
.get_compact_fragment(m
, platform
)
1054 self
.get_longer_fragment(m
, platform
)
1056 with m
.FSM() as fsm
:
1058 for state
in self
.states
:
1059 with m
.State(state
.state_from
):
1064 def get_longer_fragment(self
, m
, platform
=None):
1066 get
= self
.add_state(FPGet2Op("get_ops", "special_cases",
1068 get
.setup(m
, self
.i
)
1071 get
.trigger_setup(m
, self
.in_t
.stb
, self
.in_t
.ack
)
1073 sc
= self
.add_state(FPAddSpecialCases(self
.width
, self
.id_wid
))
1074 sc
.setup(m
, a
, b
, self
.in_mid
)
1076 dn
= self
.add_state(FPAddDeNorm(self
.width
, self
.id_wid
))
1077 dn
.setup(m
, a
, b
, sc
.in_mid
)
1079 if self
.single_cycle
:
1080 alm
= self
.add_state(FPAddAlignSingle(self
.width
, self
.id_wid
))
1081 alm
.setup(m
, dn
.out_a
, dn
.out_b
, dn
.in_mid
)
1083 alm
= self
.add_state(FPAddAlignMulti(self
.width
, self
.id_wid
))
1084 alm
.setup(m
, dn
.out_a
, dn
.out_b
, dn
.in_mid
)
1086 add0
= self
.add_state(FPAddStage0(self
.width
, self
.id_wid
))
1087 add0
.setup(m
, alm
.out_a
, alm
.out_b
, alm
.in_mid
)
1089 add1
= self
.add_state(FPAddStage1(self
.width
, self
.id_wid
))
1090 add1
.setup(m
, add0
.out_tot
, add0
.out_z
, add0
.in_mid
)
1092 if self
.single_cycle
:
1093 n1
= self
.add_state(FPNorm1Single(self
.width
, self
.id_wid
))
1094 n1
.setup(m
, add1
.out_z
, add1
.out_of
, add0
.in_mid
)
1096 n1
= self
.add_state(FPNorm1Multi(self
.width
, self
.id_wid
))
1097 n1
.setup(m
, add1
.out_z
, add1
.out_of
, add1
.norm_stb
, add0
.in_mid
)
1099 rn
= self
.add_state(FPRound(self
.width
, self
.id_wid
))
1100 rn
.setup(m
, n1
.out_z
, n1
.out_roundz
, n1
.in_mid
)
1102 cor
= self
.add_state(FPCorrections(self
.width
, self
.id_wid
))
1103 cor
.setup(m
, rn
.out_z
, rn
.in_mid
)
1105 pa
= self
.add_state(FPPack(self
.width
, self
.id_wid
))
1106 pa
.setup(m
, cor
.out_z
, rn
.in_mid
)
1108 ppz
= self
.add_state(FPPutZ("pack_put_z", pa
.out_z
, self
.out_z
,
1109 pa
.in_mid
, self
.out_mid
))
1111 pz
= self
.add_state(FPPutZ("put_z", sc
.out_z
, self
.out_z
,
1112 pa
.in_mid
, self
.out_mid
))
1114 def get_compact_fragment(self
, m
, platform
=None):
1117 get
= FPGet2Op("get_ops", "special_cases", self
.width
, self
.id_wid
)
1118 sc
= FPAddSpecialCasesDeNorm(self
.width
, self
.id_wid
)
1119 alm
= FPAddAlignSingleAdd(self
.width
, self
.id_wid
)
1120 n1
= FPNormToPack(self
.width
, self
.id_wid
)
1122 get
.trigger_setup(m
, self
.in_t
.stb
, self
.in_t
.ack
)
1124 chainlist
= [get
, sc
, alm
, n1
]
1125 chain
= StageChain(chainlist
, specallocate
=True)
1126 chain
.setup(m
, self
.i
)
1128 for mod
in chainlist
:
1129 sc
= self
.add_state(mod
)
1131 ppz
= self
.add_state(FPPutZ("pack_put_z", n1
.out_z
.z
, self
.o
,
1132 n1
.out_z
.mid
, self
.o
.mid
))
1134 #pz = self.add_state(FPPutZ("put_z", sc.out_z.z, self.o,
1135 # sc.o.mid, self.o.mid))
1138 class FPADDBase(FPState
):
1140 def __init__(self
, width
, id_wid
=None, single_cycle
=False):
1143 * width: bit-width of IEEE754. supported: 16, 32, 64
1144 * id_wid: an identifier that is sync-connected to the input
1145 * single_cycle: True indicates each stage to complete in 1 clock
1147 FPState
.__init
__(self
, "fpadd")
1149 self
.single_cycle
= single_cycle
1150 self
.mod
= FPADDBaseMod(width
, id_wid
, single_cycle
)
1151 self
.o
= self
.ospec()
1153 self
.in_t
= Trigger()
1154 self
.i
= self
.ispec()
1156 self
.z_done
= Signal(reset_less
=True) # connects to out_z Strobe
1157 self
.in_accept
= Signal(reset_less
=True)
1158 self
.add_stb
= Signal(reset_less
=True)
1159 self
.add_ack
= Signal(reset
=0, reset_less
=True)
1162 return self
.mod
.ispec()
1165 return self
.mod
.ospec()
1167 def setup(self
, m
, i
, add_stb
, in_mid
):
1168 m
.d
.comb
+= [self
.i
.eq(i
),
1169 self
.mod
.i
.eq(self
.i
),
1170 self
.z_done
.eq(self
.mod
.o
.z
.trigger
),
1171 #self.add_stb.eq(add_stb),
1172 self
.mod
.in_t
.stb
.eq(self
.in_t
.stb
),
1173 self
.in_t
.ack
.eq(self
.mod
.in_t
.ack
),
1174 self
.o
.mid
.eq(self
.mod
.o
.mid
),
1175 self
.o
.z
.v
.eq(self
.mod
.o
.z
.v
),
1176 self
.o
.z
.stb
.eq(self
.mod
.o
.z
.stb
),
1177 self
.mod
.o
.z
.ack
.eq(self
.o
.z
.ack
),
1180 m
.d
.sync
+= self
.add_stb
.eq(add_stb
)
1181 m
.d
.sync
+= self
.add_ack
.eq(0) # sets to zero when not in active state
1182 m
.d
.sync
+= self
.o
.z
.ack
.eq(0) # likewise
1183 #m.d.sync += self.in_t.stb.eq(0)
1185 m
.submodules
.fpadd
= self
.mod
1187 def action(self
, m
):
1189 # in_accept is set on incoming strobe HIGH and ack LOW.
1190 m
.d
.comb
+= self
.in_accept
.eq((~self
.add_ack
) & (self
.add_stb
))
1192 #with m.If(self.in_t.ack):
1193 # m.d.sync += self.in_t.stb.eq(0)
1194 with m
.If(~self
.z_done
):
1195 # not done: test for accepting an incoming operand pair
1196 with m
.If(self
.in_accept
):
1198 self
.add_ack
.eq(1), # acknowledge receipt...
1199 self
.in_t
.stb
.eq(1), # initiate add
1202 m
.d
.sync
+= [self
.add_ack
.eq(0),
1203 self
.in_t
.stb
.eq(0),
1207 # done: acknowledge, and write out id and value
1208 m
.d
.sync
+= [self
.add_ack
.eq(1),
1215 if self
.in_mid
is not None:
1216 m
.d
.sync
+= self
.out_mid
.eq(self
.mod
.out_mid
)
1219 self
.out_z
.v
.eq(self
.mod
.out_z
.v
)
1221 # move to output state on detecting z ack
1222 with m
.If(self
.out_z
.trigger
):
1223 m
.d
.sync
+= self
.out_z
.stb
.eq(0)
1226 m
.d
.sync
+= self
.out_z
.stb
.eq(1)
1229 class FPADDBasePipe(ControlBase
):
1230 def __init__(self
, width
, id_wid
):
1231 ControlBase
.__init
__(self
)
1232 self
.pipe1
= FPAddSpecialCasesDeNorm(width
, id_wid
)
1233 self
.pipe2
= FPAddAlignSingleAdd(width
, id_wid
)
1234 self
.pipe3
= FPNormToPack(width
, id_wid
)
1236 self
._eqs
= self
.connect([self
.pipe1
, self
.pipe2
, self
.pipe3
])
1238 def elaborate(self
, platform
):
1240 m
.submodules
.scnorm
= self
.pipe1
1241 m
.submodules
.addalign
= self
.pipe2
1242 m
.submodules
.normpack
= self
.pipe3
1243 m
.d
.comb
+= self
._eqs
1247 class FPADDInMuxPipe(PriorityCombMuxInPipe
):
1248 def __init__(self
, width
, id_wid
, num_rows
):
1249 self
.num_rows
= num_rows
1250 def iospec(): return FPADDBaseData(width
, id_wid
)
1251 stage
= PassThroughStage(iospec
)
1252 PriorityCombMuxInPipe
.__init
__(self
, stage
, p_len
=self
.num_rows
)
1255 class FPADDMuxOutPipe(CombMuxOutPipe
):
1256 def __init__(self
, width
, id_wid
, num_rows
):
1257 self
.num_rows
= num_rows
1258 def iospec(): return FPPackData(width
, id_wid
)
1259 stage
= PassThroughStage(iospec
)
1260 CombMuxOutPipe
.__init
__(self
, stage
, n_len
=self
.num_rows
)
1263 class FPADDMuxInOut
:
1264 """ Reservation-Station version of FPADD pipeline.
1266 * fan-in on inputs (an array of FPADDBaseData: a,b,mid)
1267 * 3-stage adder pipeline
1268 * fan-out on outputs (an array of FPPackData: z,mid)
1270 Fan-in and Fan-out are combinatorial.
1272 def __init__(self
, width
, id_wid
, num_rows
):
1273 self
.num_rows
= num_rows
1274 self
.inpipe
= FPADDInMuxPipe(width
, id_wid
, num_rows
) # fan-in
1275 self
.fpadd
= FPADDBasePipe(width
, id_wid
) # add stage
1276 self
.outpipe
= FPADDMuxOutPipe(width
, id_wid
, num_rows
) # fan-out
1278 self
.p
= self
.inpipe
.p
# kinda annoying,
1279 self
.n
= self
.outpipe
.n
# use pipe in/out as this class in/out
1280 self
._ports
= self
.inpipe
.ports() + self
.outpipe
.ports()
1282 def elaborate(self
, platform
):
1284 m
.submodules
.inpipe
= self
.inpipe
1285 m
.submodules
.fpadd
= self
.fpadd
1286 m
.submodules
.outpipe
= self
.outpipe
1288 m
.d
.comb
+= self
.inpipe
.n
.connect_to_next(self
.fpadd
.p
)
1289 m
.d
.comb
+= self
.fpadd
.connect_to_next(self
.outpipe
)
1298 """ FPADD: stages as follows:
1304 FPAddBase---> FPAddBaseMod
1306 PutZ GetOps->Specials->Align->Add1/2->Norm->Round/Pack->PutZ
1308 FPAddBase is tricky: it is both a stage and *has* stages.
1309 Connection to FPAddBaseMod therefore requires an in stb/ack
1310 and an out stb/ack. Just as with Add1-Norm1 interaction, FPGetOp
1311 needs to be the thing that raises the incoming stb.
1314 def __init__(self
, width
, id_wid
=None, single_cycle
=False, rs_sz
=2):
1317 * width: bit-width of IEEE754. supported: 16, 32, 64
1318 * id_wid: an identifier that is sync-connected to the input
1319 * single_cycle: True indicates each stage to complete in 1 clock
1322 self
.id_wid
= id_wid
1323 self
.single_cycle
= single_cycle
1325 #self.out_z = FPOp(width)
1326 self
.ids
= FPID(id_wid
)
1329 for i
in range(rs_sz
):
1332 in_a
.name
= "in_a_%d" % i
1333 in_b
.name
= "in_b_%d" % i
1334 rs
.append((in_a
, in_b
))
1338 for i
in range(rs_sz
):
1340 out_z
.name
= "out_z_%d" % i
1342 self
.res
= Array(res
)
1346 def add_state(self
, state
):
1347 self
.states
.append(state
)
1350 def get_fragment(self
, platform
=None):
1351 """ creates the HDL code-fragment for FPAdd
1354 m
.submodules
+= self
.rs
1356 in_a
= self
.rs
[0][0]
1357 in_b
= self
.rs
[0][1]
1359 geta
= self
.add_state(FPGetOp("get_a", "get_b",
1364 getb
= self
.add_state(FPGetOp("get_b", "fpadd",
1369 ab
= FPADDBase(self
.width
, self
.id_wid
, self
.single_cycle
)
1370 ab
= self
.add_state(ab
)
1371 abd
= ab
.ispec() # create an input spec object for FPADDBase
1372 m
.d
.sync
+= [abd
.a
.eq(a
), abd
.b
.eq(b
), abd
.mid
.eq(self
.ids
.in_mid
)]
1373 ab
.setup(m
, abd
, getb
.out_decode
, self
.ids
.in_mid
)
1376 pz
= self
.add_state(FPPutZIdx("put_z", o
.z
, self
.res
,
1379 with m
.FSM() as fsm
:
1381 for state
in self
.states
:
1382 with m
.State(state
.state_from
):
1388 if __name__
== "__main__":
1390 alu
= FPADD(width
=32, id_wid
=5, single_cycle
=True)
1391 main(alu
, ports
=alu
.rs
[0][0].ports() + \
1392 alu
.rs
[0][1].ports() + \
1393 alu
.res
[0].ports() + \
1394 [alu
.ids
.in_mid
, alu
.ids
.out_mid
])
1396 alu
= FPADDBase(width
=32, id_wid
=5, single_cycle
=True)
1397 main(alu
, ports
=[alu
.in_a
, alu
.in_b
] + \
1398 alu
.in_t
.ports() + \
1399 alu
.out_z
.ports() + \
1400 [alu
.in_mid
, alu
.out_mid
])
1403 # works... but don't use, just do "python fname.py convert -t v"
1404 #print (verilog.convert(alu, ports=[
1405 # ports=alu.in_a.ports() + \
1406 # alu.in_b.ports() + \
1407 # alu.out_z.ports())