cbac766ffb44bcf53bf3061471585049816a06c1
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
)
13 from multipipe
import CombMultiOutPipeline
14 from multipipe
import CombMultiInPipeline
, InputPriorityArbiter
16 #from fpbase import FPNumShiftMultiRight
19 class FPState(FPBase
):
20 def __init__(self
, state_from
):
21 self
.state_from
= state_from
23 def set_inputs(self
, inputs
):
25 for k
,v
in inputs
.items():
28 def set_outputs(self
, outputs
):
29 self
.outputs
= outputs
30 for k
,v
in outputs
.items():
34 class FPGetSyncOpsMod
:
35 def __init__(self
, width
, num_ops
=2):
37 self
.num_ops
= num_ops
40 for i
in range(num_ops
):
41 inops
.append(Signal(width
, reset_less
=True))
42 outops
.append(Signal(width
, reset_less
=True))
45 self
.stb
= Signal(num_ops
)
47 self
.ready
= Signal(reset_less
=True)
48 self
.out_decode
= Signal(reset_less
=True)
50 def elaborate(self
, platform
):
52 m
.d
.comb
+= self
.ready
.eq(self
.stb
== Const(-1, (self
.num_ops
, False)))
53 m
.d
.comb
+= self
.out_decode
.eq(self
.ack
& self
.ready
)
54 with m
.If(self
.out_decode
):
55 for i
in range(self
.num_ops
):
57 self
.out_op
[i
].eq(self
.in_op
[i
]),
62 return self
.in_op
+ self
.out_op
+ [self
.stb
, self
.ack
]
66 def __init__(self
, width
, num_ops
):
67 Trigger
.__init
__(self
)
69 self
.num_ops
= num_ops
72 for i
in range(num_ops
):
73 res
.append(Signal(width
))
78 for i
in range(self
.num_ops
):
86 def __init__(self
, width
, num_ops
=2, num_rows
=4):
88 self
.num_ops
= num_ops
89 self
.num_rows
= num_rows
90 self
.mmax
= int(log(self
.num_rows
) / log(2))
92 self
.mid
= Signal(self
.mmax
, reset_less
=True) # multiplex id
93 for i
in range(num_rows
):
94 self
.rs
.append(FPGetSyncOpsMod(width
, num_ops
))
95 self
.rs
= Array(self
.rs
)
97 self
.out_op
= FPOps(width
, num_ops
)
99 def elaborate(self
, platform
):
102 pe
= PriorityEncoder(self
.num_rows
)
103 m
.submodules
.selector
= pe
104 m
.submodules
.out_op
= self
.out_op
105 m
.submodules
+= self
.rs
107 # connect priority encoder
109 for i
in range(self
.num_rows
):
110 in_ready
.append(self
.rs
[i
].ready
)
111 m
.d
.comb
+= pe
.i
.eq(Cat(*in_ready
))
113 active
= Signal(reset_less
=True)
114 out_en
= Signal(reset_less
=True)
115 m
.d
.comb
+= active
.eq(~pe
.n
) # encoder active
116 m
.d
.comb
+= out_en
.eq(active
& self
.out_op
.trigger
)
118 # encoder active: ack relevant input, record MID, pass output
121 m
.d
.sync
+= self
.mid
.eq(pe
.o
)
122 m
.d
.sync
+= rs
.ack
.eq(0)
123 m
.d
.sync
+= self
.out_op
.stb
.eq(0)
124 for j
in range(self
.num_ops
):
125 m
.d
.sync
+= self
.out_op
.v
[j
].eq(rs
.out_op
[j
])
127 m
.d
.sync
+= self
.out_op
.stb
.eq(1)
128 # acks all default to zero
129 for i
in range(self
.num_rows
):
130 m
.d
.sync
+= self
.rs
[i
].ack
.eq(1)
136 for i
in range(self
.num_rows
):
138 res
+= inop
.in_op
+ [inop
.stb
]
139 return self
.out_op
.ports() + res
+ [self
.mid
]
143 def __init__(self
, width
):
144 self
.in_op
= FPOp(width
)
145 self
.out_op
= Signal(width
)
146 self
.out_decode
= Signal(reset_less
=True)
148 def elaborate(self
, platform
):
150 m
.d
.comb
+= self
.out_decode
.eq((self
.in_op
.ack
) & (self
.in_op
.stb
))
151 m
.submodules
.get_op_in
= self
.in_op
152 #m.submodules.get_op_out = self.out_op
153 with m
.If(self
.out_decode
):
155 self
.out_op
.eq(self
.in_op
.v
),
160 class FPGetOp(FPState
):
164 def __init__(self
, in_state
, out_state
, in_op
, width
):
165 FPState
.__init
__(self
, in_state
)
166 self
.out_state
= out_state
167 self
.mod
= FPGetOpMod(width
)
169 self
.out_op
= Signal(width
)
170 self
.out_decode
= Signal(reset_less
=True)
172 def setup(self
, m
, in_op
):
173 """ links module to inputs and outputs
175 setattr(m
.submodules
, self
.state_from
, self
.mod
)
176 m
.d
.comb
+= self
.mod
.in_op
.eq(in_op
)
177 m
.d
.comb
+= self
.out_decode
.eq(self
.mod
.out_decode
)
180 with m
.If(self
.out_decode
):
181 m
.next
= self
.out_state
183 self
.in_op
.ack
.eq(0),
184 self
.out_op
.eq(self
.mod
.out_op
)
187 m
.d
.sync
+= self
.in_op
.ack
.eq(1)
190 class FPGet2OpMod(Trigger
):
191 def __init__(self
, width
, id_wid
):
192 Trigger
.__init
__(self
)
195 self
.i
= self
.ispec()
196 self
.o
= self
.ospec()
199 return FPADDBaseData(self
.width
, self
.id_wid
)
202 return FPNumBase2Ops(self
.width
, self
.id_wid
)
204 def process(self
, i
):
207 def elaborate(self
, platform
):
208 m
= Trigger
.elaborate(self
, platform
)
209 m
.submodules
.get_op1_out
= self
.o
.a
210 m
.submodules
.get_op2_out
= self
.o
.b
211 out_op1
= FPNumIn(None, self
.width
)
212 out_op2
= FPNumIn(None, self
.width
)
213 with m
.If(self
.trigger
):
215 out_op1
.decode(self
.i
.a
),
216 out_op2
.decode(self
.i
.b
),
217 self
.o
.a
.eq(out_op1
),
218 self
.o
.b
.eq(out_op2
),
219 self
.o
.mid
.eq(self
.i
.mid
)
224 class FPGet2Op(FPState
):
228 def __init__(self
, in_state
, out_state
, width
, id_wid
):
229 FPState
.__init
__(self
, in_state
)
230 self
.out_state
= out_state
231 self
.mod
= FPGet2OpMod(width
, id_wid
)
232 self
.o
= self
.mod
.ospec()
233 self
.in_stb
= Signal(reset_less
=True)
234 self
.out_ack
= Signal(reset_less
=True)
235 self
.out_decode
= Signal(reset_less
=True)
237 def setup(self
, m
, i
, in_stb
, in_ack
):
238 """ links module to inputs and outputs
240 m
.submodules
.get_ops
= self
.mod
241 m
.d
.comb
+= self
.mod
.i
.eq(i
)
242 m
.d
.comb
+= self
.mod
.stb
.eq(in_stb
)
243 m
.d
.comb
+= self
.out_ack
.eq(self
.mod
.ack
)
244 m
.d
.comb
+= self
.out_decode
.eq(self
.mod
.trigger
)
245 m
.d
.comb
+= in_ack
.eq(self
.mod
.ack
)
248 with m
.If(self
.out_decode
):
249 m
.next
= self
.out_state
252 self
.o
.eq(self
.mod
.o
),
255 m
.d
.sync
+= self
.mod
.ack
.eq(1)
260 def __init__(self
, width
, id_wid
, m_extra
=True):
261 self
.a
= FPNumBase(width
, m_extra
)
262 self
.b
= FPNumBase(width
, m_extra
)
263 self
.mid
= Signal(id_wid
, reset_less
=True)
266 return [self
.a
.eq(i
.a
), self
.b
.eq(i
.b
), self
.mid
.eq(i
.mid
)]
271 def __init__(self
, width
, id_wid
):
272 self
.a
= FPNumBase(width
, True)
273 self
.b
= FPNumBase(width
, True)
274 self
.z
= FPNumOut(width
, False)
275 self
.oz
= Signal(width
, reset_less
=True)
276 self
.out_do_z
= Signal(reset_less
=True)
277 self
.mid
= Signal(id_wid
, reset_less
=True)
280 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
281 self
.a
.eq(i
.a
), self
.b
.eq(i
.b
), self
.mid
.eq(i
.mid
)]
284 class FPAddSpecialCasesMod
:
285 """ special cases: NaNs, infs, zeros, denormalised
286 NOTE: some of these are unique to add. see "Special Operations"
287 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
290 def __init__(self
, width
, id_wid
):
293 self
.i
= self
.ispec()
294 self
.o
= self
.ospec()
297 return FPNumBase2Ops(self
.width
, self
.id_wid
)
300 return FPSCData(self
.width
, self
.id_wid
)
302 def setup(self
, m
, i
):
303 """ links module to inputs and outputs
305 m
.submodules
.specialcases
= self
306 m
.d
.comb
+= self
.i
.eq(i
)
308 def process(self
, i
):
311 def elaborate(self
, platform
):
314 m
.submodules
.sc_in_a
= self
.i
.a
315 m
.submodules
.sc_in_b
= self
.i
.b
316 m
.submodules
.sc_out_z
= self
.o
.z
319 m
.d
.comb
+= s_nomatch
.eq(self
.i
.a
.s
!= self
.i
.b
.s
)
322 m
.d
.comb
+= m_match
.eq(self
.i
.a
.m
== self
.i
.b
.m
)
324 # if a is NaN or b is NaN return NaN
325 with m
.If(self
.i
.a
.is_nan | self
.i
.b
.is_nan
):
326 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
327 m
.d
.comb
+= self
.o
.z
.nan(0)
329 # XXX WEIRDNESS for FP16 non-canonical NaN handling
332 ## if a is zero and b is NaN return -b
333 #with m.If(a.is_zero & (a.s==0) & b.is_nan):
334 # m.d.comb += self.o.out_do_z.eq(1)
335 # m.d.comb += z.create(b.s, b.e, Cat(b.m[3:-2], ~b.m[0]))
337 ## if b is zero and a is NaN return -a
338 #with m.Elif(b.is_zero & (b.s==0) & a.is_nan):
339 # m.d.comb += self.o.out_do_z.eq(1)
340 # m.d.comb += z.create(a.s, a.e, Cat(a.m[3:-2], ~a.m[0]))
342 ## if a is -zero and b is NaN return -b
343 #with m.Elif(a.is_zero & (a.s==1) & b.is_nan):
344 # m.d.comb += self.o.out_do_z.eq(1)
345 # m.d.comb += z.create(a.s & b.s, b.e, Cat(b.m[3:-2], 1))
347 ## if b is -zero and a is NaN return -a
348 #with m.Elif(b.is_zero & (b.s==1) & a.is_nan):
349 # m.d.comb += self.o.out_do_z.eq(1)
350 # m.d.comb += z.create(a.s & b.s, a.e, Cat(a.m[3:-2], 1))
352 # if a is inf return inf (or NaN)
353 with m
.Elif(self
.i
.a
.is_inf
):
354 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
355 m
.d
.comb
+= self
.o
.z
.inf(self
.i
.a
.s
)
356 # if a is inf and signs don't match return NaN
357 with m
.If(self
.i
.b
.exp_128
& s_nomatch
):
358 m
.d
.comb
+= self
.o
.z
.nan(0)
360 # if b is inf return inf
361 with m
.Elif(self
.i
.b
.is_inf
):
362 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
363 m
.d
.comb
+= self
.o
.z
.inf(self
.i
.b
.s
)
365 # if a is zero and b zero return signed-a/b
366 with m
.Elif(self
.i
.a
.is_zero
& self
.i
.b
.is_zero
):
367 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
368 m
.d
.comb
+= self
.o
.z
.create(self
.i
.a
.s
& self
.i
.b
.s
,
372 # if a is zero return b
373 with m
.Elif(self
.i
.a
.is_zero
):
374 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
375 m
.d
.comb
+= self
.o
.z
.create(self
.i
.b
.s
, self
.i
.b
.e
,
378 # if b is zero return a
379 with m
.Elif(self
.i
.b
.is_zero
):
380 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
381 m
.d
.comb
+= self
.o
.z
.create(self
.i
.a
.s
, self
.i
.a
.e
,
384 # if a equal to -b return zero (+ve zero)
385 with m
.Elif(s_nomatch
& m_match
& (self
.i
.a
.e
== self
.i
.b
.e
)):
386 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
387 m
.d
.comb
+= self
.o
.z
.zero(0)
389 # Denormalised Number checks next, so pass a/b data through
391 m
.d
.comb
+= self
.o
.out_do_z
.eq(0)
392 m
.d
.comb
+= self
.o
.a
.eq(self
.i
.a
)
393 m
.d
.comb
+= self
.o
.b
.eq(self
.i
.b
)
395 m
.d
.comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
396 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
402 def __init__(self
, id_wid
):
405 self
.in_mid
= Signal(id_wid
, reset_less
=True)
406 self
.out_mid
= Signal(id_wid
, reset_less
=True)
412 if self
.id_wid
is not None:
413 m
.d
.sync
+= self
.out_mid
.eq(self
.in_mid
)
416 class FPAddSpecialCases(FPState
):
417 """ special cases: NaNs, infs, zeros, denormalised
418 NOTE: some of these are unique to add. see "Special Operations"
419 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
422 def __init__(self
, width
, id_wid
):
423 FPState
.__init
__(self
, "special_cases")
424 self
.mod
= FPAddSpecialCasesMod(width
)
425 self
.out_z
= self
.mod
.ospec()
426 self
.out_do_z
= Signal(reset_less
=True)
428 def setup(self
, m
, i
):
429 """ links module to inputs and outputs
431 self
.mod
.setup(m
, i
, self
.out_do_z
)
432 m
.d
.sync
+= self
.out_z
.v
.eq(self
.mod
.out_z
.v
) # only take the output
433 m
.d
.sync
+= self
.out_z
.mid
.eq(self
.mod
.o
.mid
) # (and mid)
437 with m
.If(self
.out_do_z
):
440 m
.next
= "denormalise"
443 class FPAddSpecialCasesDeNorm(FPState
):
444 """ special cases: NaNs, infs, zeros, denormalised
445 NOTE: some of these are unique to add. see "Special Operations"
446 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
449 def __init__(self
, width
, id_wid
):
450 FPState
.__init
__(self
, "special_cases")
451 self
.smod
= FPAddSpecialCasesMod(width
, id_wid
)
452 self
.dmod
= FPAddDeNormMod(width
, id_wid
)
453 self
.o
= self
.ospec()
456 return self
.smod
.ispec()
459 return self
.dmod
.ospec()
461 def setup(self
, m
, i
):
462 """ links module to inputs and outputs
464 # these only needed for break-out (early-out)
465 # out_z = self.smod.ospec()
466 # out_do_z = Signal(reset_less=True)
467 self
.smod
.setup(m
, i
)
468 self
.dmod
.setup(m
, self
.smod
.o
)
469 #m.d.comb += out_do_z.eq(self.smod.o.out_do_z)
471 # out_do_z=True, only needed for early-out (split pipeline)
472 #m.d.sync += out_z.z.v.eq(self.smod.o.z.v) # only take output
473 #m.d.sync += out_z.mid.eq(self.smod.o.mid) # (and mid)
476 m
.d
.sync
+= self
.o
.eq(self
.dmod
.o
)
478 def process(self
, i
):
482 #with m.If(self.out_do_z):
488 class FPAddDeNormMod(FPState
):
490 def __init__(self
, width
, id_wid
):
493 self
.i
= self
.ispec()
494 self
.o
= self
.ospec()
497 return FPSCData(self
.width
, self
.id_wid
)
500 return FPSCData(self
.width
, self
.id_wid
)
502 def setup(self
, m
, i
):
503 """ links module to inputs and outputs
505 m
.submodules
.denormalise
= self
506 m
.d
.comb
+= self
.i
.eq(i
)
508 def elaborate(self
, platform
):
510 m
.submodules
.denorm_in_a
= self
.i
.a
511 m
.submodules
.denorm_in_b
= self
.i
.b
512 m
.submodules
.denorm_out_a
= self
.o
.a
513 m
.submodules
.denorm_out_b
= self
.o
.b
515 with m
.If(~self
.i
.out_do_z
):
516 # XXX hmmm, don't like repeating identical code
517 m
.d
.comb
+= self
.o
.a
.eq(self
.i
.a
)
518 with m
.If(self
.i
.a
.exp_n127
):
519 m
.d
.comb
+= self
.o
.a
.e
.eq(self
.i
.a
.N126
) # limit a exponent
521 m
.d
.comb
+= self
.o
.a
.m
[-1].eq(1) # set top mantissa bit
523 m
.d
.comb
+= self
.o
.b
.eq(self
.i
.b
)
524 with m
.If(self
.i
.b
.exp_n127
):
525 m
.d
.comb
+= self
.o
.b
.e
.eq(self
.i
.b
.N126
) # limit a exponent
527 m
.d
.comb
+= self
.o
.b
.m
[-1].eq(1) # set top mantissa bit
529 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
530 m
.d
.comb
+= self
.o
.z
.eq(self
.i
.z
)
531 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
532 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
537 class FPAddDeNorm(FPState
):
539 def __init__(self
, width
, id_wid
):
540 FPState
.__init
__(self
, "denormalise")
541 self
.mod
= FPAddDeNormMod(width
)
542 self
.out_a
= FPNumBase(width
)
543 self
.out_b
= FPNumBase(width
)
545 def setup(self
, m
, i
):
546 """ links module to inputs and outputs
550 m
.d
.sync
+= self
.out_a
.eq(self
.mod
.out_a
)
551 m
.d
.sync
+= self
.out_b
.eq(self
.mod
.out_b
)
554 # Denormalised Number checks
558 class FPAddAlignMultiMod(FPState
):
560 def __init__(self
, width
):
561 self
.in_a
= FPNumBase(width
)
562 self
.in_b
= FPNumBase(width
)
563 self
.out_a
= FPNumIn(None, width
)
564 self
.out_b
= FPNumIn(None, width
)
565 self
.exp_eq
= Signal(reset_less
=True)
567 def elaborate(self
, platform
):
568 # This one however (single-cycle) will do the shift
573 m
.submodules
.align_in_a
= self
.in_a
574 m
.submodules
.align_in_b
= self
.in_b
575 m
.submodules
.align_out_a
= self
.out_a
576 m
.submodules
.align_out_b
= self
.out_b
578 # NOTE: this does *not* do single-cycle multi-shifting,
579 # it *STAYS* in the align state until exponents match
581 # exponent of a greater than b: shift b down
582 m
.d
.comb
+= self
.exp_eq
.eq(0)
583 m
.d
.comb
+= self
.out_a
.eq(self
.in_a
)
584 m
.d
.comb
+= self
.out_b
.eq(self
.in_b
)
585 agtb
= Signal(reset_less
=True)
586 altb
= Signal(reset_less
=True)
587 m
.d
.comb
+= agtb
.eq(self
.in_a
.e
> self
.in_b
.e
)
588 m
.d
.comb
+= altb
.eq(self
.in_a
.e
< self
.in_b
.e
)
590 m
.d
.comb
+= self
.out_b
.shift_down(self
.in_b
)
591 # exponent of b greater than a: shift a down
593 m
.d
.comb
+= self
.out_a
.shift_down(self
.in_a
)
594 # exponents equal: move to next stage.
596 m
.d
.comb
+= self
.exp_eq
.eq(1)
600 class FPAddAlignMulti(FPState
):
602 def __init__(self
, width
, id_wid
):
603 FPState
.__init
__(self
, "align")
604 self
.mod
= FPAddAlignMultiMod(width
)
605 self
.out_a
= FPNumIn(None, width
)
606 self
.out_b
= FPNumIn(None, width
)
607 self
.exp_eq
= Signal(reset_less
=True)
609 def setup(self
, m
, in_a
, in_b
):
610 """ links module to inputs and outputs
612 m
.submodules
.align
= self
.mod
613 m
.d
.comb
+= self
.mod
.in_a
.eq(in_a
)
614 m
.d
.comb
+= self
.mod
.in_b
.eq(in_b
)
615 #m.d.comb += self.out_a.eq(self.mod.out_a)
616 #m.d.comb += self.out_b.eq(self.mod.out_b)
617 m
.d
.comb
+= self
.exp_eq
.eq(self
.mod
.exp_eq
)
618 m
.d
.sync
+= self
.out_a
.eq(self
.mod
.out_a
)
619 m
.d
.sync
+= self
.out_b
.eq(self
.mod
.out_b
)
622 with m
.If(self
.exp_eq
):
628 def __init__(self
, width
, id_wid
):
629 self
.a
= FPNumIn(None, width
)
630 self
.b
= FPNumIn(None, width
)
631 self
.z
= FPNumOut(width
, False)
632 self
.out_do_z
= Signal(reset_less
=True)
633 self
.oz
= Signal(width
, reset_less
=True)
634 self
.mid
= Signal(id_wid
, reset_less
=True)
637 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
638 self
.a
.eq(i
.a
), self
.b
.eq(i
.b
), self
.mid
.eq(i
.mid
)]
641 class FPAddAlignSingleMod
:
643 def __init__(self
, width
, id_wid
):
646 self
.i
= self
.ispec()
647 self
.o
= self
.ospec()
650 return FPSCData(self
.width
, self
.id_wid
)
653 return FPNumIn2Ops(self
.width
, self
.id_wid
)
655 def process(self
, i
):
658 def setup(self
, m
, i
):
659 """ links module to inputs and outputs
661 m
.submodules
.align
= self
662 m
.d
.comb
+= self
.i
.eq(i
)
664 def elaborate(self
, platform
):
665 """ Aligns A against B or B against A, depending on which has the
666 greater exponent. This is done in a *single* cycle using
667 variable-width bit-shift
669 the shifter used here is quite expensive in terms of gates.
670 Mux A or B in (and out) into temporaries, as only one of them
671 needs to be aligned against the other
675 m
.submodules
.align_in_a
= self
.i
.a
676 m
.submodules
.align_in_b
= self
.i
.b
677 m
.submodules
.align_out_a
= self
.o
.a
678 m
.submodules
.align_out_b
= self
.o
.b
680 # temporary (muxed) input and output to be shifted
681 t_inp
= FPNumBase(self
.width
)
682 t_out
= FPNumIn(None, self
.width
)
683 espec
= (len(self
.i
.a
.e
), True)
684 msr
= MultiShiftRMerge(self
.i
.a
.m_width
, espec
)
685 m
.submodules
.align_t_in
= t_inp
686 m
.submodules
.align_t_out
= t_out
687 m
.submodules
.multishift_r
= msr
689 ediff
= Signal(espec
, reset_less
=True)
690 ediffr
= Signal(espec
, reset_less
=True)
691 tdiff
= Signal(espec
, reset_less
=True)
692 elz
= Signal(reset_less
=True)
693 egz
= Signal(reset_less
=True)
695 # connect multi-shifter to t_inp/out mantissa (and tdiff)
696 m
.d
.comb
+= msr
.inp
.eq(t_inp
.m
)
697 m
.d
.comb
+= msr
.diff
.eq(tdiff
)
698 m
.d
.comb
+= t_out
.m
.eq(msr
.m
)
699 m
.d
.comb
+= t_out
.e
.eq(t_inp
.e
+ tdiff
)
700 m
.d
.comb
+= t_out
.s
.eq(t_inp
.s
)
702 m
.d
.comb
+= ediff
.eq(self
.i
.a
.e
- self
.i
.b
.e
)
703 m
.d
.comb
+= ediffr
.eq(self
.i
.b
.e
- self
.i
.a
.e
)
704 m
.d
.comb
+= elz
.eq(self
.i
.a
.e
< self
.i
.b
.e
)
705 m
.d
.comb
+= egz
.eq(self
.i
.a
.e
> self
.i
.b
.e
)
707 # default: A-exp == B-exp, A and B untouched (fall through)
708 m
.d
.comb
+= self
.o
.a
.eq(self
.i
.a
)
709 m
.d
.comb
+= self
.o
.b
.eq(self
.i
.b
)
710 # only one shifter (muxed)
711 #m.d.comb += t_out.shift_down_multi(tdiff, t_inp)
712 # exponent of a greater than b: shift b down
713 with m
.If(~self
.i
.out_do_z
):
715 m
.d
.comb
+= [t_inp
.eq(self
.i
.b
),
718 self
.o
.b
.s
.eq(self
.i
.b
.s
), # whoops forgot sign
720 # exponent of b greater than a: shift a down
722 m
.d
.comb
+= [t_inp
.eq(self
.i
.a
),
725 self
.o
.a
.s
.eq(self
.i
.a
.s
), # whoops forgot sign
728 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
729 m
.d
.comb
+= self
.o
.z
.eq(self
.i
.z
)
730 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
731 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
736 class FPAddAlignSingle(FPState
):
738 def __init__(self
, width
, id_wid
):
739 FPState
.__init
__(self
, "align")
740 self
.mod
= FPAddAlignSingleMod(width
, id_wid
)
741 self
.out_a
= FPNumIn(None, width
)
742 self
.out_b
= FPNumIn(None, width
)
744 def setup(self
, m
, i
):
745 """ links module to inputs and outputs
749 # NOTE: could be done as comb
750 m
.d
.sync
+= self
.out_a
.eq(self
.mod
.out_a
)
751 m
.d
.sync
+= self
.out_b
.eq(self
.mod
.out_b
)
757 class FPAddAlignSingleAdd(FPState
):
759 def __init__(self
, width
, id_wid
):
760 FPState
.__init
__(self
, "align")
763 self
.a1o
= self
.ospec()
766 return FPNumBase2Ops(self
.width
, self
.id_wid
) # AlignSingle ispec
769 return FPAddStage1Data(self
.width
, self
.id_wid
) # AddStage1 ospec
771 def setup(self
, m
, i
):
772 """ links module to inputs and outputs
775 # chain AddAlignSingle, AddStage0 and AddStage1
776 mod
= FPAddAlignSingleMod(self
.width
, self
.id_wid
)
777 a0mod
= FPAddStage0Mod(self
.width
, self
.id_wid
)
778 a1mod
= FPAddStage1Mod(self
.width
, self
.id_wid
)
780 chain
= StageChain([mod
, a0mod
, a1mod
])
783 m
.d
.sync
+= self
.a1o
.eq(a1mod
.o
)
785 def process(self
, i
):
789 m
.next
= "normalise_1"
792 class FPAddStage0Data
:
794 def __init__(self
, width
, id_wid
):
795 self
.z
= FPNumBase(width
, False)
796 self
.out_do_z
= Signal(reset_less
=True)
797 self
.oz
= Signal(width
, reset_less
=True)
798 self
.tot
= Signal(self
.z
.m_width
+ 4, reset_less
=True)
799 self
.mid
= Signal(id_wid
, reset_less
=True)
802 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
803 self
.tot
.eq(i
.tot
), self
.mid
.eq(i
.mid
)]
806 class FPAddStage0Mod
:
808 def __init__(self
, width
, id_wid
):
811 self
.i
= self
.ispec()
812 self
.o
= self
.ospec()
815 return FPSCData(self
.width
, self
.id_wid
)
818 return FPAddStage0Data(self
.width
, self
.id_wid
)
820 def process(self
, i
):
823 def setup(self
, m
, i
):
824 """ links module to inputs and outputs
826 m
.submodules
.add0
= self
827 m
.d
.comb
+= self
.i
.eq(i
)
829 def elaborate(self
, platform
):
831 m
.submodules
.add0_in_a
= self
.i
.a
832 m
.submodules
.add0_in_b
= self
.i
.b
833 m
.submodules
.add0_out_z
= self
.o
.z
835 # store intermediate tests (and zero-extended mantissas)
836 seq
= Signal(reset_less
=True)
837 mge
= Signal(reset_less
=True)
838 am0
= Signal(len(self
.i
.a
.m
)+1, reset_less
=True)
839 bm0
= Signal(len(self
.i
.b
.m
)+1, reset_less
=True)
840 m
.d
.comb
+= [seq
.eq(self
.i
.a
.s
== self
.i
.b
.s
),
841 mge
.eq(self
.i
.a
.m
>= self
.i
.b
.m
),
842 am0
.eq(Cat(self
.i
.a
.m
, 0)),
843 bm0
.eq(Cat(self
.i
.b
.m
, 0))
845 # same-sign (both negative or both positive) add mantissas
846 with m
.If(~self
.i
.out_do_z
):
847 m
.d
.comb
+= self
.o
.z
.e
.eq(self
.i
.a
.e
)
850 self
.o
.tot
.eq(am0
+ bm0
),
851 self
.o
.z
.s
.eq(self
.i
.a
.s
)
853 # a mantissa greater than b, use a
856 self
.o
.tot
.eq(am0
- bm0
),
857 self
.o
.z
.s
.eq(self
.i
.a
.s
)
859 # b mantissa greater than a, use b
862 self
.o
.tot
.eq(bm0
- am0
),
863 self
.o
.z
.s
.eq(self
.i
.b
.s
)
866 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
867 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
868 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
872 class FPAddStage0(FPState
):
873 """ First stage of add. covers same-sign (add) and subtract
874 special-casing when mantissas are greater or equal, to
875 give greatest accuracy.
878 def __init__(self
, width
, id_wid
):
879 FPState
.__init
__(self
, "add_0")
880 self
.mod
= FPAddStage0Mod(width
)
881 self
.o
= self
.mod
.ospec()
883 def setup(self
, m
, i
):
884 """ links module to inputs and outputs
888 # NOTE: these could be done as combinatorial (merge add0+add1)
889 m
.d
.sync
+= self
.o
.eq(self
.mod
.o
)
895 class FPAddStage1Data
:
897 def __init__(self
, width
, id_wid
):
898 self
.z
= FPNumBase(width
, False)
899 self
.out_do_z
= Signal(reset_less
=True)
900 self
.oz
= Signal(width
, reset_less
=True)
902 self
.mid
= Signal(id_wid
, reset_less
=True)
905 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
906 self
.of
.eq(i
.of
), self
.mid
.eq(i
.mid
)]
910 class FPAddStage1Mod(FPState
):
911 """ Second stage of add: preparation for normalisation.
912 detects when tot sum is too big (tot[27] is kinda a carry bit)
915 def __init__(self
, width
, id_wid
):
918 self
.i
= self
.ispec()
919 self
.o
= self
.ospec()
922 return FPAddStage0Data(self
.width
, self
.id_wid
)
925 return FPAddStage1Data(self
.width
, self
.id_wid
)
927 def process(self
, i
):
930 def setup(self
, m
, i
):
931 """ links module to inputs and outputs
933 m
.submodules
.add1
= self
934 m
.submodules
.add1_out_overflow
= self
.o
.of
936 m
.d
.comb
+= self
.i
.eq(i
)
938 def elaborate(self
, platform
):
940 #m.submodules.norm1_in_overflow = self.in_of
941 #m.submodules.norm1_out_overflow = self.out_of
942 #m.submodules.norm1_in_z = self.in_z
943 #m.submodules.norm1_out_z = self.out_z
944 m
.d
.comb
+= self
.o
.z
.eq(self
.i
.z
)
945 # tot[-1] (MSB) gets set when the sum overflows. shift result down
946 with m
.If(~self
.i
.out_do_z
):
947 with m
.If(self
.i
.tot
[-1]):
949 self
.o
.z
.m
.eq(self
.i
.tot
[4:]),
950 self
.o
.of
.m0
.eq(self
.i
.tot
[4]),
951 self
.o
.of
.guard
.eq(self
.i
.tot
[3]),
952 self
.o
.of
.round_bit
.eq(self
.i
.tot
[2]),
953 self
.o
.of
.sticky
.eq(self
.i
.tot
[1] | self
.i
.tot
[0]),
954 self
.o
.z
.e
.eq(self
.i
.z
.e
+ 1)
956 # tot[-1] (MSB) zero case
959 self
.o
.z
.m
.eq(self
.i
.tot
[3:]),
960 self
.o
.of
.m0
.eq(self
.i
.tot
[3]),
961 self
.o
.of
.guard
.eq(self
.i
.tot
[2]),
962 self
.o
.of
.round_bit
.eq(self
.i
.tot
[1]),
963 self
.o
.of
.sticky
.eq(self
.i
.tot
[0])
966 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
967 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
968 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
973 class FPAddStage1(FPState
):
975 def __init__(self
, width
, id_wid
):
976 FPState
.__init
__(self
, "add_1")
977 self
.mod
= FPAddStage1Mod(width
)
978 self
.out_z
= FPNumBase(width
, False)
979 self
.out_of
= Overflow()
980 self
.norm_stb
= Signal()
982 def setup(self
, m
, i
):
983 """ links module to inputs and outputs
987 m
.d
.sync
+= self
.norm_stb
.eq(0) # sets to zero when not in add1 state
989 m
.d
.sync
+= self
.out_of
.eq(self
.mod
.out_of
)
990 m
.d
.sync
+= self
.out_z
.eq(self
.mod
.out_z
)
991 m
.d
.sync
+= self
.norm_stb
.eq(1)
994 m
.next
= "normalise_1"
997 class FPNormaliseModSingle
:
999 def __init__(self
, width
):
1001 self
.in_z
= self
.ispec()
1002 self
.out_z
= self
.ospec()
1005 return FPNumBase(self
.width
, False)
1008 return FPNumBase(self
.width
, False)
1010 def setup(self
, m
, i
):
1011 """ links module to inputs and outputs
1013 m
.submodules
.normalise
= self
1014 m
.d
.comb
+= self
.i
.eq(i
)
1016 def elaborate(self
, platform
):
1019 mwid
= self
.out_z
.m_width
+2
1020 pe
= PriorityEncoder(mwid
)
1021 m
.submodules
.norm_pe
= pe
1023 m
.submodules
.norm1_out_z
= self
.out_z
1024 m
.submodules
.norm1_in_z
= self
.in_z
1026 in_z
= FPNumBase(self
.width
, False)
1028 m
.submodules
.norm1_insel_z
= in_z
1029 m
.submodules
.norm1_insel_overflow
= in_of
1031 espec
= (len(in_z
.e
), True)
1032 ediff_n126
= Signal(espec
, reset_less
=True)
1033 msr
= MultiShiftRMerge(mwid
, espec
)
1034 m
.submodules
.multishift_r
= msr
1036 m
.d
.comb
+= in_z
.eq(self
.in_z
)
1037 m
.d
.comb
+= in_of
.eq(self
.in_of
)
1038 # initialise out from in (overridden below)
1039 m
.d
.comb
+= self
.out_z
.eq(in_z
)
1040 m
.d
.comb
+= self
.out_of
.eq(in_of
)
1041 # normalisation decrease condition
1042 decrease
= Signal(reset_less
=True)
1043 m
.d
.comb
+= decrease
.eq(in_z
.m_msbzero
)
1045 with m
.If(decrease
):
1046 # *sigh* not entirely obvious: count leading zeros (clz)
1047 # with a PriorityEncoder: to find from the MSB
1048 # we reverse the order of the bits.
1049 temp_m
= Signal(mwid
, reset_less
=True)
1050 temp_s
= Signal(mwid
+1, reset_less
=True)
1051 clz
= Signal((len(in_z
.e
), True), reset_less
=True)
1053 # cat round and guard bits back into the mantissa
1054 temp_m
.eq(Cat(in_of
.round_bit
, in_of
.guard
, in_z
.m
)),
1055 pe
.i
.eq(temp_m
[::-1]), # inverted
1056 clz
.eq(pe
.o
), # count zeros from MSB down
1057 temp_s
.eq(temp_m
<< clz
), # shift mantissa UP
1058 self
.out_z
.e
.eq(in_z
.e
- clz
), # DECREASE exponent
1059 self
.out_z
.m
.eq(temp_s
[2:]), # exclude bits 0&1
1066 def __init__(self
, width
, id_wid
):
1067 self
.roundz
= Signal(reset_less
=True)
1068 self
.z
= FPNumBase(width
, False)
1069 self
.out_do_z
= Signal(reset_less
=True)
1070 self
.oz
= Signal(width
, reset_less
=True)
1071 self
.mid
= Signal(id_wid
, reset_less
=True)
1074 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
1075 self
.roundz
.eq(i
.roundz
), self
.mid
.eq(i
.mid
)]
1078 class FPNorm1ModSingle
:
1080 def __init__(self
, width
, id_wid
):
1082 self
.id_wid
= id_wid
1083 self
.i
= self
.ispec()
1084 self
.o
= self
.ospec()
1087 return FPAddStage1Data(self
.width
, self
.id_wid
)
1090 return FPNorm1Data(self
.width
, self
.id_wid
)
1092 def setup(self
, m
, i
):
1093 """ links module to inputs and outputs
1095 m
.submodules
.normalise_1
= self
1096 m
.d
.comb
+= self
.i
.eq(i
)
1098 def process(self
, i
):
1101 def elaborate(self
, platform
):
1104 mwid
= self
.o
.z
.m_width
+2
1105 pe
= PriorityEncoder(mwid
)
1106 m
.submodules
.norm_pe
= pe
1109 m
.d
.comb
+= self
.o
.roundz
.eq(of
.roundz
)
1111 m
.submodules
.norm1_out_z
= self
.o
.z
1112 m
.submodules
.norm1_out_overflow
= of
1113 m
.submodules
.norm1_in_z
= self
.i
.z
1114 m
.submodules
.norm1_in_overflow
= self
.i
.of
1117 m
.submodules
.norm1_insel_z
= i
.z
1118 m
.submodules
.norm1_insel_overflow
= i
.of
1120 espec
= (len(i
.z
.e
), True)
1121 ediff_n126
= Signal(espec
, reset_less
=True)
1122 msr
= MultiShiftRMerge(mwid
, espec
)
1123 m
.submodules
.multishift_r
= msr
1125 m
.d
.comb
+= i
.eq(self
.i
)
1126 # initialise out from in (overridden below)
1127 m
.d
.comb
+= self
.o
.z
.eq(i
.z
)
1128 m
.d
.comb
+= of
.eq(i
.of
)
1129 # normalisation increase/decrease conditions
1130 decrease
= Signal(reset_less
=True)
1131 increase
= Signal(reset_less
=True)
1132 m
.d
.comb
+= decrease
.eq(i
.z
.m_msbzero
& i
.z
.exp_gt_n126
)
1133 m
.d
.comb
+= increase
.eq(i
.z
.exp_lt_n126
)
1135 with m
.If(~self
.i
.out_do_z
):
1136 with m
.If(decrease
):
1137 # *sigh* not entirely obvious: count leading zeros (clz)
1138 # with a PriorityEncoder: to find from the MSB
1139 # we reverse the order of the bits.
1140 temp_m
= Signal(mwid
, reset_less
=True)
1141 temp_s
= Signal(mwid
+1, reset_less
=True)
1142 clz
= Signal((len(i
.z
.e
), True), reset_less
=True)
1143 # make sure that the amount to decrease by does NOT
1144 # go below the minimum non-INF/NaN exponent
1145 limclz
= Mux(i
.z
.exp_sub_n126
> pe
.o
, pe
.o
,
1148 # cat round and guard bits back into the mantissa
1149 temp_m
.eq(Cat(i
.of
.round_bit
, i
.of
.guard
, i
.z
.m
)),
1150 pe
.i
.eq(temp_m
[::-1]), # inverted
1151 clz
.eq(limclz
), # count zeros from MSB down
1152 temp_s
.eq(temp_m
<< clz
), # shift mantissa UP
1153 self
.o
.z
.e
.eq(i
.z
.e
- clz
), # DECREASE exponent
1154 self
.o
.z
.m
.eq(temp_s
[2:]), # exclude bits 0&1
1155 of
.m0
.eq(temp_s
[2]), # copy of mantissa[0]
1156 # overflow in bits 0..1: got shifted too (leave sticky)
1157 of
.guard
.eq(temp_s
[1]), # guard
1158 of
.round_bit
.eq(temp_s
[0]), # round
1161 with m
.Elif(increase
):
1162 temp_m
= Signal(mwid
+1, reset_less
=True)
1164 temp_m
.eq(Cat(i
.of
.sticky
, i
.of
.round_bit
, i
.of
.guard
,
1166 ediff_n126
.eq(i
.z
.N126
- i
.z
.e
),
1167 # connect multi-shifter to inp/out mantissa (and ediff)
1169 msr
.diff
.eq(ediff_n126
),
1170 self
.o
.z
.m
.eq(msr
.m
[3:]),
1171 of
.m0
.eq(temp_s
[3]), # copy of mantissa[0]
1172 # overflow in bits 0..1: got shifted too (leave sticky)
1173 of
.guard
.eq(temp_s
[2]), # guard
1174 of
.round_bit
.eq(temp_s
[1]), # round
1175 of
.sticky
.eq(temp_s
[0]), # sticky
1176 self
.o
.z
.e
.eq(i
.z
.e
+ ediff_n126
),
1179 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
1180 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
1181 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
1186 class FPNorm1ModMulti
:
1188 def __init__(self
, width
, single_cycle
=True):
1190 self
.in_select
= Signal(reset_less
=True)
1191 self
.in_z
= FPNumBase(width
, False)
1192 self
.in_of
= Overflow()
1193 self
.temp_z
= FPNumBase(width
, False)
1194 self
.temp_of
= Overflow()
1195 self
.out_z
= FPNumBase(width
, False)
1196 self
.out_of
= Overflow()
1198 def elaborate(self
, platform
):
1201 m
.submodules
.norm1_out_z
= self
.out_z
1202 m
.submodules
.norm1_out_overflow
= self
.out_of
1203 m
.submodules
.norm1_temp_z
= self
.temp_z
1204 m
.submodules
.norm1_temp_of
= self
.temp_of
1205 m
.submodules
.norm1_in_z
= self
.in_z
1206 m
.submodules
.norm1_in_overflow
= self
.in_of
1208 in_z
= FPNumBase(self
.width
, False)
1210 m
.submodules
.norm1_insel_z
= in_z
1211 m
.submodules
.norm1_insel_overflow
= in_of
1213 # select which of temp or in z/of to use
1214 with m
.If(self
.in_select
):
1215 m
.d
.comb
+= in_z
.eq(self
.in_z
)
1216 m
.d
.comb
+= in_of
.eq(self
.in_of
)
1218 m
.d
.comb
+= in_z
.eq(self
.temp_z
)
1219 m
.d
.comb
+= in_of
.eq(self
.temp_of
)
1220 # initialise out from in (overridden below)
1221 m
.d
.comb
+= self
.out_z
.eq(in_z
)
1222 m
.d
.comb
+= self
.out_of
.eq(in_of
)
1223 # normalisation increase/decrease conditions
1224 decrease
= Signal(reset_less
=True)
1225 increase
= Signal(reset_less
=True)
1226 m
.d
.comb
+= decrease
.eq(in_z
.m_msbzero
& in_z
.exp_gt_n126
)
1227 m
.d
.comb
+= increase
.eq(in_z
.exp_lt_n126
)
1228 m
.d
.comb
+= self
.out_norm
.eq(decrease | increase
) # loop-end
1230 with m
.If(decrease
):
1232 self
.out_z
.e
.eq(in_z
.e
- 1), # DECREASE exponent
1233 self
.out_z
.m
.eq(in_z
.m
<< 1), # shift mantissa UP
1234 self
.out_z
.m
[0].eq(in_of
.guard
), # steal guard (was tot[2])
1235 self
.out_of
.guard
.eq(in_of
.round_bit
), # round (was tot[1])
1236 self
.out_of
.round_bit
.eq(0), # reset round bit
1237 self
.out_of
.m0
.eq(in_of
.guard
),
1240 with m
.Elif(increase
):
1242 self
.out_z
.e
.eq(in_z
.e
+ 1), # INCREASE exponent
1243 self
.out_z
.m
.eq(in_z
.m
>> 1), # shift mantissa DOWN
1244 self
.out_of
.guard
.eq(in_z
.m
[0]),
1245 self
.out_of
.m0
.eq(in_z
.m
[1]),
1246 self
.out_of
.round_bit
.eq(in_of
.guard
),
1247 self
.out_of
.sticky
.eq(in_of
.sticky | in_of
.round_bit
)
1253 class FPNorm1Single(FPState
):
1255 def __init__(self
, width
, id_wid
, single_cycle
=True):
1256 FPState
.__init
__(self
, "normalise_1")
1257 self
.mod
= FPNorm1ModSingle(width
)
1258 self
.o
= self
.ospec()
1259 self
.out_z
= FPNumBase(width
, False)
1260 self
.out_roundz
= Signal(reset_less
=True)
1263 return self
.mod
.ispec()
1266 return self
.mod
.ospec()
1268 def setup(self
, m
, i
):
1269 """ links module to inputs and outputs
1271 self
.mod
.setup(m
, i
)
1273 def action(self
, m
):
1277 class FPNorm1Multi(FPState
):
1279 def __init__(self
, width
, id_wid
):
1280 FPState
.__init
__(self
, "normalise_1")
1281 self
.mod
= FPNorm1ModMulti(width
)
1282 self
.stb
= Signal(reset_less
=True)
1283 self
.ack
= Signal(reset
=0, reset_less
=True)
1284 self
.out_norm
= Signal(reset_less
=True)
1285 self
.in_accept
= Signal(reset_less
=True)
1286 self
.temp_z
= FPNumBase(width
)
1287 self
.temp_of
= Overflow()
1288 self
.out_z
= FPNumBase(width
)
1289 self
.out_roundz
= Signal(reset_less
=True)
1291 def setup(self
, m
, in_z
, in_of
, norm_stb
):
1292 """ links module to inputs and outputs
1294 self
.mod
.setup(m
, in_z
, in_of
, norm_stb
,
1295 self
.in_accept
, self
.temp_z
, self
.temp_of
,
1296 self
.out_z
, self
.out_norm
)
1298 m
.d
.comb
+= self
.stb
.eq(norm_stb
)
1299 m
.d
.sync
+= self
.ack
.eq(0) # sets to zero when not in normalise_1 state
1301 def action(self
, m
):
1302 m
.d
.comb
+= self
.in_accept
.eq((~self
.ack
) & (self
.stb
))
1303 m
.d
.sync
+= self
.temp_of
.eq(self
.mod
.out_of
)
1304 m
.d
.sync
+= self
.temp_z
.eq(self
.out_z
)
1305 with m
.If(self
.out_norm
):
1306 with m
.If(self
.in_accept
):
1311 m
.d
.sync
+= self
.ack
.eq(0)
1313 # normalisation not required (or done).
1315 m
.d
.sync
+= self
.ack
.eq(1)
1316 m
.d
.sync
+= self
.out_roundz
.eq(self
.mod
.out_of
.roundz
)
1319 class FPNormToPack(FPState
):
1321 def __init__(self
, width
, id_wid
):
1322 FPState
.__init
__(self
, "normalise_1")
1323 self
.id_wid
= id_wid
1327 return FPAddStage1Data(self
.width
, self
.id_wid
) # Norm1ModSingle ispec
1330 return FPPackData(self
.width
, self
.id_wid
) # FPPackMod ospec
1332 def setup(self
, m
, i
):
1333 """ links module to inputs and outputs
1336 # Normalisation, Rounding Corrections, Pack - in a chain
1337 nmod
= FPNorm1ModSingle(self
.width
, self
.id_wid
)
1338 rmod
= FPRoundMod(self
.width
, self
.id_wid
)
1339 cmod
= FPCorrectionsMod(self
.width
, self
.id_wid
)
1340 pmod
= FPPackMod(self
.width
, self
.id_wid
)
1341 chain
= StageChain([nmod
, rmod
, cmod
, pmod
])
1343 self
.out_z
= pmod
.ospec()
1345 m
.d
.sync
+= self
.out_z
.mid
.eq(pmod
.o
.mid
)
1346 m
.d
.sync
+= self
.out_z
.z
.eq(pmod
.o
.z
) # outputs packed result
1348 def process(self
, i
):
1351 def action(self
, m
):
1352 m
.next
= "pack_put_z"
1357 def __init__(self
, width
, id_wid
):
1358 self
.z
= FPNumBase(width
, False)
1359 self
.out_do_z
= Signal(reset_less
=True)
1360 self
.oz
= Signal(width
, reset_less
=True)
1361 self
.mid
= Signal(id_wid
, reset_less
=True)
1364 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
1370 def __init__(self
, width
, id_wid
):
1372 self
.id_wid
= id_wid
1373 self
.i
= self
.ispec()
1374 self
.out_z
= self
.ospec()
1377 return FPNorm1Data(self
.width
, self
.id_wid
)
1380 return FPRoundData(self
.width
, self
.id_wid
)
1382 def process(self
, i
):
1385 def setup(self
, m
, i
):
1386 m
.submodules
.roundz
= self
1387 m
.d
.comb
+= self
.i
.eq(i
)
1389 def elaborate(self
, platform
):
1391 m
.d
.comb
+= self
.out_z
.eq(self
.i
) # copies mid, z, out_do_z
1392 with m
.If(~self
.i
.out_do_z
):
1393 with m
.If(self
.i
.roundz
):
1394 m
.d
.comb
+= self
.out_z
.z
.m
.eq(self
.i
.z
.m
+ 1) # mantissa up
1395 with m
.If(self
.i
.z
.m
== self
.i
.z
.m1s
): # all 1s
1396 m
.d
.comb
+= self
.out_z
.z
.e
.eq(self
.i
.z
.e
+ 1) # exponent up
1401 class FPRound(FPState
):
1403 def __init__(self
, width
, id_wid
):
1404 FPState
.__init
__(self
, "round")
1405 self
.mod
= FPRoundMod(width
)
1406 self
.out_z
= self
.ospec()
1409 return self
.mod
.ispec()
1412 return self
.mod
.ospec()
1414 def setup(self
, m
, i
):
1415 """ links module to inputs and outputs
1417 self
.mod
.setup(m
, i
)
1420 m
.d
.sync
+= self
.out_z
.eq(self
.mod
.out_z
)
1421 m
.d
.sync
+= self
.out_z
.mid
.eq(self
.mod
.o
.mid
)
1423 def action(self
, m
):
1424 m
.next
= "corrections"
1427 class FPCorrectionsMod
:
1429 def __init__(self
, width
, id_wid
):
1431 self
.id_wid
= id_wid
1432 self
.i
= self
.ispec()
1433 self
.out_z
= self
.ospec()
1436 return FPRoundData(self
.width
, self
.id_wid
)
1439 return FPRoundData(self
.width
, self
.id_wid
)
1441 def process(self
, i
):
1444 def setup(self
, m
, i
):
1445 """ links module to inputs and outputs
1447 m
.submodules
.corrections
= self
1448 m
.d
.comb
+= self
.i
.eq(i
)
1450 def elaborate(self
, platform
):
1452 m
.submodules
.corr_in_z
= self
.i
.z
1453 m
.submodules
.corr_out_z
= self
.out_z
.z
1454 m
.d
.comb
+= self
.out_z
.eq(self
.i
) # copies mid, z, out_do_z
1455 with m
.If(~self
.i
.out_do_z
):
1456 with m
.If(self
.i
.z
.is_denormalised
):
1457 m
.d
.comb
+= self
.out_z
.z
.e
.eq(self
.i
.z
.N127
)
1461 class FPCorrections(FPState
):
1463 def __init__(self
, width
, id_wid
):
1464 FPState
.__init
__(self
, "corrections")
1465 self
.mod
= FPCorrectionsMod(width
)
1466 self
.out_z
= self
.ospec()
1469 return self
.mod
.ispec()
1472 return self
.mod
.ospec()
1474 def setup(self
, m
, in_z
):
1475 """ links module to inputs and outputs
1477 self
.mod
.setup(m
, in_z
)
1479 m
.d
.sync
+= self
.out_z
.eq(self
.mod
.out_z
)
1480 m
.d
.sync
+= self
.out_z
.mid
.eq(self
.mod
.o
.mid
)
1482 def action(self
, m
):
1488 def __init__(self
, width
, id_wid
):
1489 self
.z
= Signal(width
, reset_less
=True)
1490 self
.mid
= Signal(id_wid
, reset_less
=True)
1493 return [self
.z
.eq(i
.z
), self
.mid
.eq(i
.mid
)]
1498 def __init__(self
, width
, id_wid
):
1500 self
.id_wid
= id_wid
1501 self
.i
= self
.ispec()
1502 self
.o
= self
.ospec()
1505 return FPRoundData(self
.width
, self
.id_wid
)
1508 return FPPackData(self
.width
, self
.id_wid
)
1510 def process(self
, i
):
1513 def setup(self
, m
, in_z
):
1514 """ links module to inputs and outputs
1516 m
.submodules
.pack
= self
1517 m
.d
.comb
+= self
.i
.eq(in_z
)
1519 def elaborate(self
, platform
):
1521 z
= FPNumOut(self
.width
, False)
1522 m
.submodules
.pack_in_z
= self
.i
.z
1523 m
.submodules
.pack_out_z
= z
1524 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
1525 with m
.If(~self
.i
.out_do_z
):
1526 with m
.If(self
.i
.z
.is_overflowed
):
1527 m
.d
.comb
+= z
.inf(self
.i
.z
.s
)
1529 m
.d
.comb
+= z
.create(self
.i
.z
.s
, self
.i
.z
.e
, self
.i
.z
.m
)
1531 m
.d
.comb
+= z
.v
.eq(self
.i
.oz
)
1532 m
.d
.comb
+= self
.o
.z
.eq(z
.v
)
1536 class FPPack(FPState
):
1538 def __init__(self
, width
, id_wid
):
1539 FPState
.__init
__(self
, "pack")
1540 self
.mod
= FPPackMod(width
)
1541 self
.out_z
= self
.ospec()
1544 return self
.mod
.ispec()
1547 return self
.mod
.ospec()
1549 def setup(self
, m
, in_z
):
1550 """ links module to inputs and outputs
1552 self
.mod
.setup(m
, in_z
)
1554 m
.d
.sync
+= self
.out_z
.v
.eq(self
.mod
.out_z
.v
)
1555 m
.d
.sync
+= self
.out_z
.mid
.eq(self
.mod
.o
.mid
)
1557 def action(self
, m
):
1558 m
.next
= "pack_put_z"
1561 class FPPutZ(FPState
):
1563 def __init__(self
, state
, in_z
, out_z
, in_mid
, out_mid
, to_state
=None):
1564 FPState
.__init
__(self
, state
)
1565 if to_state
is None:
1566 to_state
= "get_ops"
1567 self
.to_state
= to_state
1570 self
.in_mid
= in_mid
1571 self
.out_mid
= out_mid
1573 def action(self
, m
):
1574 if self
.in_mid
is not None:
1575 m
.d
.sync
+= self
.out_mid
.eq(self
.in_mid
)
1577 self
.out_z
.z
.v
.eq(self
.in_z
)
1579 with m
.If(self
.out_z
.z
.stb
& self
.out_z
.z
.ack
):
1580 m
.d
.sync
+= self
.out_z
.z
.stb
.eq(0)
1581 m
.next
= self
.to_state
1583 m
.d
.sync
+= self
.out_z
.z
.stb
.eq(1)
1586 class FPPutZIdx(FPState
):
1588 def __init__(self
, state
, in_z
, out_zs
, in_mid
, to_state
=None):
1589 FPState
.__init
__(self
, state
)
1590 if to_state
is None:
1591 to_state
= "get_ops"
1592 self
.to_state
= to_state
1594 self
.out_zs
= out_zs
1595 self
.in_mid
= in_mid
1597 def action(self
, m
):
1598 outz_stb
= Signal(reset_less
=True)
1599 outz_ack
= Signal(reset_less
=True)
1600 m
.d
.comb
+= [outz_stb
.eq(self
.out_zs
[self
.in_mid
].stb
),
1601 outz_ack
.eq(self
.out_zs
[self
.in_mid
].ack
),
1604 self
.out_zs
[self
.in_mid
].v
.eq(self
.in_z
.v
)
1606 with m
.If(outz_stb
& outz_ack
):
1607 m
.d
.sync
+= self
.out_zs
[self
.in_mid
].stb
.eq(0)
1608 m
.next
= self
.to_state
1610 m
.d
.sync
+= self
.out_zs
[self
.in_mid
].stb
.eq(1)
1612 class FPADDBaseData
:
1614 def __init__(self
, width
, id_wid
):
1616 self
.id_wid
= id_wid
1617 self
.a
= Signal(width
)
1618 self
.b
= Signal(width
)
1619 self
.mid
= Signal(id_wid
, reset_less
=True)
1622 return [self
.a
.eq(i
.a
), self
.b
.eq(i
.b
), self
.mid
.eq(i
.mid
)]
1625 return [self
.a
, self
.b
, self
.mid
]
1628 def __init__(self
, width
, id_wid
):
1629 self
.z
= FPOp(width
)
1630 self
.mid
= Signal(id_wid
, reset_less
=True)
1633 return [self
.z
.eq(i
.z
), self
.mid
.eq(i
.mid
)]
1636 return [self
.z
, self
.mid
]
1641 def __init__(self
, width
, id_wid
=None, single_cycle
=False, compact
=True):
1644 * width: bit-width of IEEE754. supported: 16, 32, 64
1645 * id_wid: an identifier that is sync-connected to the input
1646 * single_cycle: True indicates each stage to complete in 1 clock
1647 * compact: True indicates a reduced number of stages
1650 self
.id_wid
= id_wid
1651 self
.single_cycle
= single_cycle
1652 self
.compact
= compact
1654 self
.in_t
= Trigger()
1655 self
.i
= self
.ispec()
1656 self
.o
= self
.ospec()
1661 return FPADDBaseData(self
.width
, self
.id_wid
)
1664 return FPOpData(self
.width
, self
.id_wid
)
1666 def add_state(self
, state
):
1667 self
.states
.append(state
)
1670 def get_fragment(self
, platform
=None):
1671 """ creates the HDL code-fragment for FPAdd
1674 m
.submodules
.out_z
= self
.o
.z
1675 m
.submodules
.in_t
= self
.in_t
1677 self
.get_compact_fragment(m
, platform
)
1679 self
.get_longer_fragment(m
, platform
)
1681 with m
.FSM() as fsm
:
1683 for state
in self
.states
:
1684 with m
.State(state
.state_from
):
1689 def get_longer_fragment(self
, m
, platform
=None):
1691 get
= self
.add_state(FPGet2Op("get_ops", "special_cases",
1693 get
.setup(m
, self
.i
, self
.in_t
.stb
, self
.in_t
.ack
)
1697 sc
= self
.add_state(FPAddSpecialCases(self
.width
, self
.id_wid
))
1698 sc
.setup(m
, a
, b
, self
.in_mid
)
1700 dn
= self
.add_state(FPAddDeNorm(self
.width
, self
.id_wid
))
1701 dn
.setup(m
, a
, b
, sc
.in_mid
)
1703 if self
.single_cycle
:
1704 alm
= self
.add_state(FPAddAlignSingle(self
.width
, self
.id_wid
))
1705 alm
.setup(m
, dn
.out_a
, dn
.out_b
, dn
.in_mid
)
1707 alm
= self
.add_state(FPAddAlignMulti(self
.width
, self
.id_wid
))
1708 alm
.setup(m
, dn
.out_a
, dn
.out_b
, dn
.in_mid
)
1710 add0
= self
.add_state(FPAddStage0(self
.width
, self
.id_wid
))
1711 add0
.setup(m
, alm
.out_a
, alm
.out_b
, alm
.in_mid
)
1713 add1
= self
.add_state(FPAddStage1(self
.width
, self
.id_wid
))
1714 add1
.setup(m
, add0
.out_tot
, add0
.out_z
, add0
.in_mid
)
1716 if self
.single_cycle
:
1717 n1
= self
.add_state(FPNorm1Single(self
.width
, self
.id_wid
))
1718 n1
.setup(m
, add1
.out_z
, add1
.out_of
, add0
.in_mid
)
1720 n1
= self
.add_state(FPNorm1Multi(self
.width
, self
.id_wid
))
1721 n1
.setup(m
, add1
.out_z
, add1
.out_of
, add1
.norm_stb
, add0
.in_mid
)
1723 rn
= self
.add_state(FPRound(self
.width
, self
.id_wid
))
1724 rn
.setup(m
, n1
.out_z
, n1
.out_roundz
, n1
.in_mid
)
1726 cor
= self
.add_state(FPCorrections(self
.width
, self
.id_wid
))
1727 cor
.setup(m
, rn
.out_z
, rn
.in_mid
)
1729 pa
= self
.add_state(FPPack(self
.width
, self
.id_wid
))
1730 pa
.setup(m
, cor
.out_z
, rn
.in_mid
)
1732 ppz
= self
.add_state(FPPutZ("pack_put_z", pa
.out_z
, self
.out_z
,
1733 pa
.in_mid
, self
.out_mid
))
1735 pz
= self
.add_state(FPPutZ("put_z", sc
.out_z
, self
.out_z
,
1736 pa
.in_mid
, self
.out_mid
))
1738 def get_compact_fragment(self
, m
, platform
=None):
1740 get
= self
.add_state(FPGet2Op("get_ops", "special_cases",
1741 self
.width
, self
.id_wid
))
1742 get
.setup(m
, self
.i
, self
.in_t
.stb
, self
.in_t
.ack
)
1744 sc
= self
.add_state(FPAddSpecialCasesDeNorm(self
.width
, self
.id_wid
))
1747 alm
= self
.add_state(FPAddAlignSingleAdd(self
.width
, self
.id_wid
))
1750 n1
= self
.add_state(FPNormToPack(self
.width
, self
.id_wid
))
1751 n1
.setup(m
, alm
.a1o
)
1753 ppz
= self
.add_state(FPPutZ("pack_put_z", n1
.out_z
.z
, self
.o
,
1754 n1
.out_z
.mid
, self
.o
.mid
))
1756 #pz = self.add_state(FPPutZ("put_z", sc.out_z.z, self.o,
1757 # sc.o.mid, self.o.mid))
1760 class FPADDBase(FPState
):
1762 def __init__(self
, width
, id_wid
=None, single_cycle
=False):
1765 * width: bit-width of IEEE754. supported: 16, 32, 64
1766 * id_wid: an identifier that is sync-connected to the input
1767 * single_cycle: True indicates each stage to complete in 1 clock
1769 FPState
.__init
__(self
, "fpadd")
1771 self
.single_cycle
= single_cycle
1772 self
.mod
= FPADDBaseMod(width
, id_wid
, single_cycle
)
1773 self
.o
= self
.ospec()
1775 self
.in_t
= Trigger()
1776 self
.i
= self
.ispec()
1778 self
.z_done
= Signal(reset_less
=True) # connects to out_z Strobe
1779 self
.in_accept
= Signal(reset_less
=True)
1780 self
.add_stb
= Signal(reset_less
=True)
1781 self
.add_ack
= Signal(reset
=0, reset_less
=True)
1784 return self
.mod
.ispec()
1787 return self
.mod
.ospec()
1789 def setup(self
, m
, i
, add_stb
, in_mid
):
1790 m
.d
.comb
+= [self
.i
.eq(i
),
1791 self
.mod
.i
.eq(self
.i
),
1792 self
.z_done
.eq(self
.mod
.o
.z
.trigger
),
1793 #self.add_stb.eq(add_stb),
1794 self
.mod
.in_t
.stb
.eq(self
.in_t
.stb
),
1795 self
.in_t
.ack
.eq(self
.mod
.in_t
.ack
),
1796 self
.o
.mid
.eq(self
.mod
.o
.mid
),
1797 self
.o
.z
.v
.eq(self
.mod
.o
.z
.v
),
1798 self
.o
.z
.stb
.eq(self
.mod
.o
.z
.stb
),
1799 self
.mod
.o
.z
.ack
.eq(self
.o
.z
.ack
),
1802 m
.d
.sync
+= self
.add_stb
.eq(add_stb
)
1803 m
.d
.sync
+= self
.add_ack
.eq(0) # sets to zero when not in active state
1804 m
.d
.sync
+= self
.o
.z
.ack
.eq(0) # likewise
1805 #m.d.sync += self.in_t.stb.eq(0)
1807 m
.submodules
.fpadd
= self
.mod
1809 def action(self
, m
):
1811 # in_accept is set on incoming strobe HIGH and ack LOW.
1812 m
.d
.comb
+= self
.in_accept
.eq((~self
.add_ack
) & (self
.add_stb
))
1814 #with m.If(self.in_t.ack):
1815 # m.d.sync += self.in_t.stb.eq(0)
1816 with m
.If(~self
.z_done
):
1817 # not done: test for accepting an incoming operand pair
1818 with m
.If(self
.in_accept
):
1820 self
.add_ack
.eq(1), # acknowledge receipt...
1821 self
.in_t
.stb
.eq(1), # initiate add
1824 m
.d
.sync
+= [self
.add_ack
.eq(0),
1825 self
.in_t
.stb
.eq(0),
1829 # done: acknowledge, and write out id and value
1830 m
.d
.sync
+= [self
.add_ack
.eq(1),
1837 if self
.in_mid
is not None:
1838 m
.d
.sync
+= self
.out_mid
.eq(self
.mod
.out_mid
)
1841 self
.out_z
.v
.eq(self
.mod
.out_z
.v
)
1843 # move to output state on detecting z ack
1844 with m
.If(self
.out_z
.trigger
):
1845 m
.d
.sync
+= self
.out_z
.stb
.eq(0)
1848 m
.d
.sync
+= self
.out_z
.stb
.eq(1)
1851 class FPADDStageOut
:
1852 def __init__(self
, width
, id_wid
):
1853 self
.z
= Signal(width
)
1854 self
.mid
= Signal(id_wid
, reset_less
=True)
1857 return [self
.z
.eq(i
.z
), self
.mid
.eq(i
.mid
)]
1860 return [self
.z
, self
.mid
]
1863 # matches the format of FPADDStageOut, allows eq function to do assignments
1864 class PlaceHolder
: pass
1867 class FPAddBaseStage
:
1868 def __init__(self
, width
, id_wid
):
1870 self
.id_wid
= id_wid
1873 return FPADDBaseData(self
.width
, self
.id_wid
)
1876 return FPADDStageOut(self
.width
, self
.id_wid
)
1878 def process(self
, i
):
1885 class FPADDBasePipe1(UnbufferedPipeline
):
1886 def __init__(self
, width
, id_wid
):
1887 stage
= FPAddBaseStage(width
, id_wid
)
1888 UnbufferedPipeline
.__init
__(self
, stage
)
1891 class FPADDBasePipe(ControlBase
):
1892 def __init__(self
, width
, id_wid
):
1893 ControlBase
.__init
__(self
)
1894 self
.pipe1
= FPADDBasePipe1(width
, id_wid
)
1895 self
._eqs
= self
.connect([self
.pipe1
])
1897 def elaborate(self
, platform
):
1899 m
.submodules
.pipe1
= self
.pipe1
1900 m
.d
.comb
+= self
._eqs
1904 class PriorityCombPipeline(CombMultiInPipeline
):
1905 def __init__(self
, stage
, p_len
):
1906 p_mux
= InputPriorityArbiter(self
, p_len
)
1907 CombMultiInPipeline
.__init
__(self
, stage
, p_len
=p_len
, p_mux
=p_mux
)
1910 return self
.p_mux
.ports()
1913 class FPAddInPassThruStage
:
1914 def __init__(self
, width
, id_wid
):
1915 self
.width
, self
.id_wid
= width
, id_wid
1916 def ispec(self
): return FPADDBaseData(self
.width
, self
.id_wid
)
1917 def ospec(self
): return self
.ispec()
1918 def process(self
, i
): return i
1921 class FPADDInMuxPipe(PriorityCombPipeline
):
1922 def __init__(self
, width
, id_width
, num_rows
):
1923 self
.num_rows
= num_rows
1924 stage
= FPAddInPassThruStage(width
, id_width
)
1925 PriorityCombPipeline
.__init
__(self
, stage
, p_len
=self
.num_rows
)
1926 #self.p.i_data = stage.ispec()
1927 #self.n.o_data = stage.ospec()
1931 for i
in range(len(self
.p
)):
1932 res
+= [self
.p
[i
].i_valid
, self
.p
[i
].o_ready
] + \
1933 self
.p
[i
].i_data
.ports()
1934 res
+= [self
.n
.i_ready
, self
.n
.o_valid
] + \
1935 self
.n
.o_data
.ports()
1939 class MuxCombPipeline(CombMultiOutPipeline
):
1940 def __init__(self
, stage
, n_len
):
1941 # HACK: stage is also the n-way multiplexer
1942 CombMultiOutPipeline
.__init
__(self
, stage
, n_len
=n_len
, n_mux
=stage
)
1944 # HACK: n-mux is also the stage... so set the muxid equal to input mid
1945 stage
.m_id
= self
.p
.i_data
.mid
1948 return self
.p_mux
.ports()
1951 class FPAddOutPassThruStage
:
1952 def __init__(self
, width
, id_wid
):
1953 self
.width
, self
.id_wid
= width
, id_wid
1954 def ispec(self
): return FPADDStageOut(self
.width
, self
.id_wid
)
1955 def ospec(self
): return self
.ispec()
1956 def process(self
, i
): return i
1959 class FPADDMuxOutPipe(MuxCombPipeline
):
1960 def __init__(self
, width
, id_wid
, num_rows
):
1961 self
.num_rows
= num_rows
1962 stage
= FPAddOutPassThruStage(width
, id_wid
)
1963 MuxCombPipeline
.__init
__(self
, stage
, n_len
=self
.num_rows
)
1964 #self.p.i_data = stage.ispec()
1965 #self.n.o_data = stage.ospec()
1968 res
= [self
.p
.i_valid
, self
.p
.o_ready
] + \
1969 self
.p
.i_data
.ports()
1970 for i
in range(len(self
.n
)):
1971 res
+= [self
.n
[i
].i_ready
, self
.n
[i
].o_valid
] + \
1972 self
.n
[i
].o_data
.ports()
1976 class FPADDMuxInOut
:
1977 """ Reservation-Station version of FPADD pipeline.
1981 def __init__(self
, width
, id_wid
, num_rows
):
1982 self
.num_rows
= num_rows
1983 self
.inpipe
= FPADDInMuxPipe(width
, id_wid
, num_rows
) # fan-in
1984 self
.fpadd
= FPADDBasePipe(width
, id_wid
) # add stage
1985 self
.outpipe
= FPADDMuxOutPipe(width
, id_wid
, num_rows
) # fan-out
1987 self
.p
= self
.inpipe
.p
# kinda annoying,
1988 self
.n
= self
.outpipe
.n
# use pipe in/out as this class in/out
1989 self
._ports
= self
.inpipe
.ports() + self
.outpipe
.ports()
1991 def elaborate(self
, platform
):
1993 m
.submodules
.inpipe
= self
.inpipe
1994 m
.submodules
.fpadd
= self
.fpadd
1995 m
.submodules
.outpipe
= self
.outpipe
1997 m
.d
.comb
+= self
.inpipe
.n
.connect_to_next(self
.fpadd
.p
)
1998 m
.d
.comb
+= self
.fpadd
.connect_to_next(self
.outpipe
)
2007 def __init__(self
, width
, id_wid
):
2009 self
.id_wid
= id_wid
2011 for i
in range(rs_sz
):
2013 out_z
.name
= "out_z_%d" % i
2015 self
.res
= Array(res
)
2016 self
.in_z
= FPOp(width
)
2017 self
.in_mid
= Signal(self
.id_wid
, reset_less
=True)
2019 def setup(self
, m
, in_z
, in_mid
):
2020 m
.d
.comb
+= [self
.in_z
.eq(in_z
),
2021 self
.in_mid
.eq(in_mid
)]
2023 def get_fragment(self
, platform
=None):
2024 """ creates the HDL code-fragment for FPAdd
2027 m
.submodules
.res_in_z
= self
.in_z
2028 m
.submodules
+= self
.res
2040 """ FPADD: stages as follows:
2046 FPAddBase---> FPAddBaseMod
2048 PutZ GetOps->Specials->Align->Add1/2->Norm->Round/Pack->PutZ
2050 FPAddBase is tricky: it is both a stage and *has* stages.
2051 Connection to FPAddBaseMod therefore requires an in stb/ack
2052 and an out stb/ack. Just as with Add1-Norm1 interaction, FPGetOp
2053 needs to be the thing that raises the incoming stb.
2056 def __init__(self
, width
, id_wid
=None, single_cycle
=False, rs_sz
=2):
2059 * width: bit-width of IEEE754. supported: 16, 32, 64
2060 * id_wid: an identifier that is sync-connected to the input
2061 * single_cycle: True indicates each stage to complete in 1 clock
2064 self
.id_wid
= id_wid
2065 self
.single_cycle
= single_cycle
2067 #self.out_z = FPOp(width)
2068 self
.ids
= FPID(id_wid
)
2071 for i
in range(rs_sz
):
2074 in_a
.name
= "in_a_%d" % i
2075 in_b
.name
= "in_b_%d" % i
2076 rs
.append((in_a
, in_b
))
2080 for i
in range(rs_sz
):
2082 out_z
.name
= "out_z_%d" % i
2084 self
.res
= Array(res
)
2088 def add_state(self
, state
):
2089 self
.states
.append(state
)
2092 def get_fragment(self
, platform
=None):
2093 """ creates the HDL code-fragment for FPAdd
2096 m
.submodules
+= self
.rs
2098 in_a
= self
.rs
[0][0]
2099 in_b
= self
.rs
[0][1]
2101 geta
= self
.add_state(FPGetOp("get_a", "get_b",
2106 getb
= self
.add_state(FPGetOp("get_b", "fpadd",
2111 ab
= FPADDBase(self
.width
, self
.id_wid
, self
.single_cycle
)
2112 ab
= self
.add_state(ab
)
2113 abd
= ab
.ispec() # create an input spec object for FPADDBase
2114 m
.d
.sync
+= [abd
.a
.eq(a
), abd
.b
.eq(b
), abd
.mid
.eq(self
.ids
.in_mid
)]
2115 ab
.setup(m
, abd
, getb
.out_decode
, self
.ids
.in_mid
)
2118 pz
= self
.add_state(FPPutZIdx("put_z", o
.z
, self
.res
,
2121 with m
.FSM() as fsm
:
2123 for state
in self
.states
:
2124 with m
.State(state
.state_from
):
2130 if __name__
== "__main__":
2132 alu
= FPADD(width
=32, id_wid
=5, single_cycle
=True)
2133 main(alu
, ports
=alu
.rs
[0][0].ports() + \
2134 alu
.rs
[0][1].ports() + \
2135 alu
.res
[0].ports() + \
2136 [alu
.ids
.in_mid
, alu
.ids
.out_mid
])
2138 alu
= FPADDBase(width
=32, id_wid
=5, single_cycle
=True)
2139 main(alu
, ports
=[alu
.in_a
, alu
.in_b
] + \
2140 alu
.in_t
.ports() + \
2141 alu
.out_z
.ports() + \
2142 [alu
.in_mid
, alu
.out_mid
])
2145 # works... but don't use, just do "python fname.py convert -t v"
2146 #print (verilog.convert(alu, ports=[
2147 # ports=alu.in_a.ports() + \
2148 # alu.in_b.ports() + \
2149 # alu.out_z.ports())