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 FPNumShiftMultiRight
20 class FPState(FPBase
):
21 def __init__(self
, state_from
):
22 self
.state_from
= state_from
24 def set_inputs(self
, inputs
):
26 for k
,v
in inputs
.items():
29 def set_outputs(self
, outputs
):
30 self
.outputs
= outputs
31 for k
,v
in outputs
.items():
35 class FPGetSyncOpsMod
:
36 def __init__(self
, width
, num_ops
=2):
38 self
.num_ops
= num_ops
41 for i
in range(num_ops
):
42 inops
.append(Signal(width
, reset_less
=True))
43 outops
.append(Signal(width
, reset_less
=True))
46 self
.stb
= Signal(num_ops
)
48 self
.ready
= Signal(reset_less
=True)
49 self
.out_decode
= Signal(reset_less
=True)
51 def elaborate(self
, platform
):
53 m
.d
.comb
+= self
.ready
.eq(self
.stb
== Const(-1, (self
.num_ops
, False)))
54 m
.d
.comb
+= self
.out_decode
.eq(self
.ack
& self
.ready
)
55 with m
.If(self
.out_decode
):
56 for i
in range(self
.num_ops
):
58 self
.out_op
[i
].eq(self
.in_op
[i
]),
63 return self
.in_op
+ self
.out_op
+ [self
.stb
, self
.ack
]
67 def __init__(self
, width
, num_ops
):
68 Trigger
.__init
__(self
)
70 self
.num_ops
= num_ops
73 for i
in range(num_ops
):
74 res
.append(Signal(width
))
79 for i
in range(self
.num_ops
):
87 def __init__(self
, width
, num_ops
=2, num_rows
=4):
89 self
.num_ops
= num_ops
90 self
.num_rows
= num_rows
91 self
.mmax
= int(log(self
.num_rows
) / log(2))
93 self
.mid
= Signal(self
.mmax
, reset_less
=True) # multiplex id
94 for i
in range(num_rows
):
95 self
.rs
.append(FPGetSyncOpsMod(width
, num_ops
))
96 self
.rs
= Array(self
.rs
)
98 self
.out_op
= FPOps(width
, num_ops
)
100 def elaborate(self
, platform
):
103 pe
= PriorityEncoder(self
.num_rows
)
104 m
.submodules
.selector
= pe
105 m
.submodules
.out_op
= self
.out_op
106 m
.submodules
+= self
.rs
108 # connect priority encoder
110 for i
in range(self
.num_rows
):
111 in_ready
.append(self
.rs
[i
].ready
)
112 m
.d
.comb
+= pe
.i
.eq(Cat(*in_ready
))
114 active
= Signal(reset_less
=True)
115 out_en
= Signal(reset_less
=True)
116 m
.d
.comb
+= active
.eq(~pe
.n
) # encoder active
117 m
.d
.comb
+= out_en
.eq(active
& self
.out_op
.trigger
)
119 # encoder active: ack relevant input, record MID, pass output
122 m
.d
.sync
+= self
.mid
.eq(pe
.o
)
123 m
.d
.sync
+= rs
.ack
.eq(0)
124 m
.d
.sync
+= self
.out_op
.stb
.eq(0)
125 for j
in range(self
.num_ops
):
126 m
.d
.sync
+= self
.out_op
.v
[j
].eq(rs
.out_op
[j
])
128 m
.d
.sync
+= self
.out_op
.stb
.eq(1)
129 # acks all default to zero
130 for i
in range(self
.num_rows
):
131 m
.d
.sync
+= self
.rs
[i
].ack
.eq(1)
137 for i
in range(self
.num_rows
):
139 res
+= inop
.in_op
+ [inop
.stb
]
140 return self
.out_op
.ports() + res
+ [self
.mid
]
144 def __init__(self
, width
):
145 self
.in_op
= FPOp(width
)
146 self
.out_op
= Signal(width
)
147 self
.out_decode
= Signal(reset_less
=True)
149 def elaborate(self
, platform
):
151 m
.d
.comb
+= self
.out_decode
.eq((self
.in_op
.ack
) & (self
.in_op
.stb
))
152 m
.submodules
.get_op_in
= self
.in_op
153 #m.submodules.get_op_out = self.out_op
154 with m
.If(self
.out_decode
):
156 self
.out_op
.eq(self
.in_op
.v
),
161 class FPGetOp(FPState
):
165 def __init__(self
, in_state
, out_state
, in_op
, width
):
166 FPState
.__init
__(self
, in_state
)
167 self
.out_state
= out_state
168 self
.mod
= FPGetOpMod(width
)
170 self
.out_op
= Signal(width
)
171 self
.out_decode
= Signal(reset_less
=True)
173 def setup(self
, m
, in_op
):
174 """ links module to inputs and outputs
176 setattr(m
.submodules
, self
.state_from
, self
.mod
)
177 m
.d
.comb
+= self
.mod
.in_op
.eq(in_op
)
178 m
.d
.comb
+= self
.out_decode
.eq(self
.mod
.out_decode
)
181 with m
.If(self
.out_decode
):
182 m
.next
= self
.out_state
184 self
.in_op
.ack
.eq(0),
185 self
.out_op
.eq(self
.mod
.out_op
)
188 m
.d
.sync
+= self
.in_op
.ack
.eq(1)
193 def __init__(self
, width
, id_wid
, m_extra
=True):
194 self
.a
= FPNumBase(width
, m_extra
)
195 self
.b
= FPNumBase(width
, m_extra
)
196 self
.mid
= Signal(id_wid
, reset_less
=True)
199 return [self
.a
.eq(i
.a
), self
.b
.eq(i
.b
), self
.mid
.eq(i
.mid
)]
202 return [self
.a
, self
.b
, self
.mid
]
207 def __init__(self
, width
, id_wid
):
210 self
.a
= Signal(width
)
211 self
.b
= Signal(width
)
212 self
.mid
= Signal(id_wid
, reset_less
=True)
215 return [self
.a
.eq(i
.a
), self
.b
.eq(i
.b
), self
.mid
.eq(i
.mid
)]
218 return [self
.a
, self
.b
, self
.mid
]
221 class FPGet2OpMod(Trigger
):
222 def __init__(self
, width
, id_wid
):
223 Trigger
.__init
__(self
)
226 self
.i
= self
.ispec()
227 self
.o
= self
.ospec()
230 return FPADDBaseData(self
.width
, self
.id_wid
)
233 return FPADDBaseData(self
.width
, self
.id_wid
)
235 def process(self
, i
):
238 def elaborate(self
, platform
):
239 m
= Trigger
.elaborate(self
, platform
)
240 with m
.If(self
.trigger
):
247 class FPGet2Op(FPState
):
251 def __init__(self
, in_state
, out_state
, width
, id_wid
):
252 FPState
.__init
__(self
, in_state
)
253 self
.out_state
= out_state
254 self
.mod
= FPGet2OpMod(width
, id_wid
)
255 self
.o
= self
.mod
.ospec()
256 self
.in_stb
= Signal(reset_less
=True)
257 self
.out_ack
= Signal(reset_less
=True)
258 self
.out_decode
= Signal(reset_less
=True)
260 def setup(self
, m
, i
, in_stb
, in_ack
):
261 """ links module to inputs and outputs
263 m
.submodules
.get_ops
= self
.mod
264 m
.d
.comb
+= self
.mod
.i
.eq(i
)
265 m
.d
.comb
+= self
.mod
.stb
.eq(in_stb
)
266 m
.d
.comb
+= self
.out_ack
.eq(self
.mod
.ack
)
267 m
.d
.comb
+= self
.out_decode
.eq(self
.mod
.trigger
)
268 m
.d
.comb
+= in_ack
.eq(self
.mod
.ack
)
271 with m
.If(self
.out_decode
):
272 m
.next
= self
.out_state
275 self
.o
.eq(self
.mod
.o
),
278 m
.d
.sync
+= self
.mod
.ack
.eq(1)
283 def __init__(self
, width
, id_wid
):
284 self
.a
= FPNumBase(width
, True)
285 self
.b
= FPNumBase(width
, True)
286 self
.z
= FPNumOut(width
, False)
287 self
.oz
= Signal(width
, reset_less
=True)
288 self
.out_do_z
= Signal(reset_less
=True)
289 self
.mid
= Signal(id_wid
, reset_less
=True)
292 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
293 self
.a
.eq(i
.a
), self
.b
.eq(i
.b
), self
.mid
.eq(i
.mid
)]
296 class FPAddSpecialCasesMod
:
297 """ special cases: NaNs, infs, zeros, denormalised
298 NOTE: some of these are unique to add. see "Special Operations"
299 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
302 def __init__(self
, width
, id_wid
):
305 self
.i
= self
.ispec()
306 self
.o
= self
.ospec()
309 return FPADDBaseData(self
.width
, self
.id_wid
)
312 return FPSCData(self
.width
, self
.id_wid
)
314 def setup(self
, m
, i
):
315 """ links module to inputs and outputs
317 m
.submodules
.specialcases
= self
318 m
.d
.comb
+= self
.i
.eq(i
)
320 def process(self
, i
):
323 def elaborate(self
, platform
):
326 m
.submodules
.sc_out_z
= self
.o
.z
328 # decode: XXX really should move to separate stage
329 a1
= FPNumIn(None, self
.width
)
330 b1
= FPNumIn(None, self
.width
)
331 m
.submodules
.sc_decode_a
= a1
332 m
.submodules
.sc_decode_b
= b1
333 m
.d
.comb
+= [a1
.decode(self
.i
.a
),
338 m
.d
.comb
+= s_nomatch
.eq(a1
.s
!= b1
.s
)
341 m
.d
.comb
+= m_match
.eq(a1
.m
== b1
.m
)
343 # if a is NaN or b is NaN return NaN
344 with m
.If(a1
.is_nan | b1
.is_nan
):
345 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
346 m
.d
.comb
+= self
.o
.z
.nan(0)
348 # XXX WEIRDNESS for FP16 non-canonical NaN handling
351 ## if a is zero and b is NaN return -b
352 #with m.If(a.is_zero & (a.s==0) & b.is_nan):
353 # m.d.comb += self.o.out_do_z.eq(1)
354 # m.d.comb += z.create(b.s, b.e, Cat(b.m[3:-2], ~b.m[0]))
356 ## if b is zero and a is NaN return -a
357 #with m.Elif(b.is_zero & (b.s==0) & a.is_nan):
358 # m.d.comb += self.o.out_do_z.eq(1)
359 # m.d.comb += z.create(a.s, a.e, Cat(a.m[3:-2], ~a.m[0]))
361 ## if a is -zero and b is NaN return -b
362 #with m.Elif(a.is_zero & (a.s==1) & b.is_nan):
363 # m.d.comb += self.o.out_do_z.eq(1)
364 # m.d.comb += z.create(a.s & b.s, b.e, Cat(b.m[3:-2], 1))
366 ## if b is -zero and a is NaN return -a
367 #with m.Elif(b.is_zero & (b.s==1) & a.is_nan):
368 # m.d.comb += self.o.out_do_z.eq(1)
369 # m.d.comb += z.create(a.s & b.s, a.e, Cat(a.m[3:-2], 1))
371 # if a is inf return inf (or NaN)
372 with m
.Elif(a1
.is_inf
):
373 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
374 m
.d
.comb
+= self
.o
.z
.inf(a1
.s
)
375 # if a is inf and signs don't match return NaN
376 with m
.If(b1
.exp_128
& s_nomatch
):
377 m
.d
.comb
+= self
.o
.z
.nan(0)
379 # if b is inf return inf
380 with m
.Elif(b1
.is_inf
):
381 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
382 m
.d
.comb
+= self
.o
.z
.inf(b1
.s
)
384 # if a is zero and b zero return signed-a/b
385 with m
.Elif(a1
.is_zero
& b1
.is_zero
):
386 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
387 m
.d
.comb
+= self
.o
.z
.create(a1
.s
& b1
.s
, b1
.e
, b1
.m
[3:-1])
389 # if a is zero return b
390 with m
.Elif(a1
.is_zero
):
391 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
392 m
.d
.comb
+= self
.o
.z
.create(b1
.s
, b1
.e
, b1
.m
[3:-1])
394 # if b is zero return a
395 with m
.Elif(b1
.is_zero
):
396 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
397 m
.d
.comb
+= self
.o
.z
.create(a1
.s
, a1
.e
, a1
.m
[3:-1])
399 # if a equal to -b return zero (+ve zero)
400 with m
.Elif(s_nomatch
& m_match
& (a1
.e
== b1
.e
)):
401 m
.d
.comb
+= self
.o
.out_do_z
.eq(1)
402 m
.d
.comb
+= self
.o
.z
.zero(0)
404 # Denormalised Number checks next, so pass a/b data through
406 m
.d
.comb
+= self
.o
.out_do_z
.eq(0)
407 m
.d
.comb
+= self
.o
.a
.eq(a1
)
408 m
.d
.comb
+= self
.o
.b
.eq(b1
)
410 m
.d
.comb
+= self
.o
.oz
.eq(self
.o
.z
.v
)
411 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
417 def __init__(self
, id_wid
):
420 self
.in_mid
= Signal(id_wid
, reset_less
=True)
421 self
.out_mid
= Signal(id_wid
, reset_less
=True)
427 if self
.id_wid
is not None:
428 m
.d
.sync
+= self
.out_mid
.eq(self
.in_mid
)
431 class FPAddSpecialCases(FPState
):
432 """ special cases: NaNs, infs, zeros, denormalised
433 NOTE: some of these are unique to add. see "Special Operations"
434 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
437 def __init__(self
, width
, id_wid
):
438 FPState
.__init
__(self
, "special_cases")
439 self
.mod
= FPAddSpecialCasesMod(width
)
440 self
.out_z
= self
.mod
.ospec()
441 self
.out_do_z
= Signal(reset_less
=True)
443 def setup(self
, m
, i
):
444 """ links module to inputs and outputs
446 self
.mod
.setup(m
, i
, self
.out_do_z
)
447 m
.d
.sync
+= self
.out_z
.v
.eq(self
.mod
.out_z
.v
) # only take the output
448 m
.d
.sync
+= self
.out_z
.mid
.eq(self
.mod
.o
.mid
) # (and mid)
452 with m
.If(self
.out_do_z
):
455 m
.next
= "denormalise"
458 class FPAddSpecialCasesDeNorm(FPState
, UnbufferedPipeline
):
459 """ special cases: NaNs, infs, zeros, denormalised
460 NOTE: some of these are unique to add. see "Special Operations"
461 https://steve.hollasch.net/cgindex/coding/ieeefloat.html
464 def __init__(self
, width
, id_wid
):
465 FPState
.__init
__(self
, "special_cases")
466 self
.smod
= FPAddSpecialCasesMod(width
, id_wid
)
467 self
.dmod
= FPAddDeNormMod(width
, id_wid
)
468 UnbufferedPipeline
.__init
__(self
, self
) # pipe is its own stage
469 self
.o
= self
.ospec()
472 return self
.smod
.ispec()
475 return self
.dmod
.ospec()
477 def setup(self
, m
, i
):
478 """ links module to inputs and outputs
480 # these only needed for break-out (early-out)
481 # out_z = self.smod.ospec()
482 # out_do_z = Signal(reset_less=True)
483 self
.smod
.setup(m
, i
)
484 self
.dmod
.setup(m
, self
.smod
.o
)
485 #m.d.comb += out_do_z.eq(self.smod.o.out_do_z)
487 # out_do_z=True, only needed for early-out (split pipeline)
488 #m.d.sync += out_z.z.v.eq(self.smod.o.z.v) # only take output
489 #m.d.sync += out_z.mid.eq(self.smod.o.mid) # (and mid)
492 m
.d
.comb
+= self
.o
.eq(self
.dmod
.o
)
494 def process(self
, i
):
498 #with m.If(self.out_do_z):
504 class FPAddDeNormMod(FPState
):
506 def __init__(self
, width
, id_wid
):
509 self
.i
= self
.ispec()
510 self
.o
= self
.ospec()
513 return FPSCData(self
.width
, self
.id_wid
)
516 return FPSCData(self
.width
, self
.id_wid
)
518 def setup(self
, m
, i
):
519 """ links module to inputs and outputs
521 m
.submodules
.denormalise
= self
522 m
.d
.comb
+= self
.i
.eq(i
)
524 def elaborate(self
, platform
):
526 m
.submodules
.denorm_in_a
= self
.i
.a
527 m
.submodules
.denorm_in_b
= self
.i
.b
528 m
.submodules
.denorm_out_a
= self
.o
.a
529 m
.submodules
.denorm_out_b
= self
.o
.b
531 with m
.If(~self
.i
.out_do_z
):
532 # XXX hmmm, don't like repeating identical code
533 m
.d
.comb
+= self
.o
.a
.eq(self
.i
.a
)
534 with m
.If(self
.i
.a
.exp_n127
):
535 m
.d
.comb
+= self
.o
.a
.e
.eq(self
.i
.a
.N126
) # limit a exponent
537 m
.d
.comb
+= self
.o
.a
.m
[-1].eq(1) # set top mantissa bit
539 m
.d
.comb
+= self
.o
.b
.eq(self
.i
.b
)
540 with m
.If(self
.i
.b
.exp_n127
):
541 m
.d
.comb
+= self
.o
.b
.e
.eq(self
.i
.b
.N126
) # limit a exponent
543 m
.d
.comb
+= self
.o
.b
.m
[-1].eq(1) # set top mantissa bit
545 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
546 m
.d
.comb
+= self
.o
.z
.eq(self
.i
.z
)
547 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
548 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
553 class FPAddDeNorm(FPState
):
555 def __init__(self
, width
, id_wid
):
556 FPState
.__init
__(self
, "denormalise")
557 self
.mod
= FPAddDeNormMod(width
)
558 self
.out_a
= FPNumBase(width
)
559 self
.out_b
= FPNumBase(width
)
561 def setup(self
, m
, i
):
562 """ links module to inputs and outputs
566 m
.d
.sync
+= self
.out_a
.eq(self
.mod
.out_a
)
567 m
.d
.sync
+= self
.out_b
.eq(self
.mod
.out_b
)
570 # Denormalised Number checks
574 class FPAddAlignMultiMod(FPState
):
576 def __init__(self
, width
):
577 self
.in_a
= FPNumBase(width
)
578 self
.in_b
= FPNumBase(width
)
579 self
.out_a
= FPNumIn(None, width
)
580 self
.out_b
= FPNumIn(None, width
)
581 self
.exp_eq
= Signal(reset_less
=True)
583 def elaborate(self
, platform
):
584 # This one however (single-cycle) will do the shift
589 m
.submodules
.align_in_a
= self
.in_a
590 m
.submodules
.align_in_b
= self
.in_b
591 m
.submodules
.align_out_a
= self
.out_a
592 m
.submodules
.align_out_b
= self
.out_b
594 # NOTE: this does *not* do single-cycle multi-shifting,
595 # it *STAYS* in the align state until exponents match
597 # exponent of a greater than b: shift b down
598 m
.d
.comb
+= self
.exp_eq
.eq(0)
599 m
.d
.comb
+= self
.out_a
.eq(self
.in_a
)
600 m
.d
.comb
+= self
.out_b
.eq(self
.in_b
)
601 agtb
= Signal(reset_less
=True)
602 altb
= Signal(reset_less
=True)
603 m
.d
.comb
+= agtb
.eq(self
.in_a
.e
> self
.in_b
.e
)
604 m
.d
.comb
+= altb
.eq(self
.in_a
.e
< self
.in_b
.e
)
606 m
.d
.comb
+= self
.out_b
.shift_down(self
.in_b
)
607 # exponent of b greater than a: shift a down
609 m
.d
.comb
+= self
.out_a
.shift_down(self
.in_a
)
610 # exponents equal: move to next stage.
612 m
.d
.comb
+= self
.exp_eq
.eq(1)
616 class FPAddAlignMulti(FPState
):
618 def __init__(self
, width
, id_wid
):
619 FPState
.__init
__(self
, "align")
620 self
.mod
= FPAddAlignMultiMod(width
)
621 self
.out_a
= FPNumIn(None, width
)
622 self
.out_b
= FPNumIn(None, width
)
623 self
.exp_eq
= Signal(reset_less
=True)
625 def setup(self
, m
, in_a
, in_b
):
626 """ links module to inputs and outputs
628 m
.submodules
.align
= self
.mod
629 m
.d
.comb
+= self
.mod
.in_a
.eq(in_a
)
630 m
.d
.comb
+= self
.mod
.in_b
.eq(in_b
)
631 #m.d.comb += self.out_a.eq(self.mod.out_a)
632 #m.d.comb += self.out_b.eq(self.mod.out_b)
633 m
.d
.comb
+= self
.exp_eq
.eq(self
.mod
.exp_eq
)
634 m
.d
.sync
+= self
.out_a
.eq(self
.mod
.out_a
)
635 m
.d
.sync
+= self
.out_b
.eq(self
.mod
.out_b
)
638 with m
.If(self
.exp_eq
):
644 def __init__(self
, width
, id_wid
):
645 self
.a
= FPNumIn(None, width
)
646 self
.b
= FPNumIn(None, width
)
647 self
.z
= FPNumOut(width
, False)
648 self
.out_do_z
= Signal(reset_less
=True)
649 self
.oz
= Signal(width
, reset_less
=True)
650 self
.mid
= Signal(id_wid
, reset_less
=True)
653 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
654 self
.a
.eq(i
.a
), self
.b
.eq(i
.b
), self
.mid
.eq(i
.mid
)]
657 class FPAddAlignSingleMod
:
659 def __init__(self
, width
, id_wid
):
662 self
.i
= self
.ispec()
663 self
.o
= self
.ospec()
666 return FPSCData(self
.width
, self
.id_wid
)
669 return FPNumIn2Ops(self
.width
, self
.id_wid
)
671 def process(self
, i
):
674 def setup(self
, m
, i
):
675 """ links module to inputs and outputs
677 m
.submodules
.align
= self
678 m
.d
.comb
+= self
.i
.eq(i
)
680 def elaborate(self
, platform
):
681 """ Aligns A against B or B against A, depending on which has the
682 greater exponent. This is done in a *single* cycle using
683 variable-width bit-shift
685 the shifter used here is quite expensive in terms of gates.
686 Mux A or B in (and out) into temporaries, as only one of them
687 needs to be aligned against the other
691 m
.submodules
.align_in_a
= self
.i
.a
692 m
.submodules
.align_in_b
= self
.i
.b
693 m
.submodules
.align_out_a
= self
.o
.a
694 m
.submodules
.align_out_b
= self
.o
.b
696 # temporary (muxed) input and output to be shifted
697 t_inp
= FPNumBase(self
.width
)
698 t_out
= FPNumIn(None, self
.width
)
699 espec
= (len(self
.i
.a
.e
), True)
700 msr
= MultiShiftRMerge(self
.i
.a
.m_width
, espec
)
701 m
.submodules
.align_t_in
= t_inp
702 m
.submodules
.align_t_out
= t_out
703 m
.submodules
.multishift_r
= msr
705 ediff
= Signal(espec
, reset_less
=True)
706 ediffr
= Signal(espec
, reset_less
=True)
707 tdiff
= Signal(espec
, reset_less
=True)
708 elz
= Signal(reset_less
=True)
709 egz
= Signal(reset_less
=True)
711 # connect multi-shifter to t_inp/out mantissa (and tdiff)
712 m
.d
.comb
+= msr
.inp
.eq(t_inp
.m
)
713 m
.d
.comb
+= msr
.diff
.eq(tdiff
)
714 m
.d
.comb
+= t_out
.m
.eq(msr
.m
)
715 m
.d
.comb
+= t_out
.e
.eq(t_inp
.e
+ tdiff
)
716 m
.d
.comb
+= t_out
.s
.eq(t_inp
.s
)
718 m
.d
.comb
+= ediff
.eq(self
.i
.a
.e
- self
.i
.b
.e
)
719 m
.d
.comb
+= ediffr
.eq(self
.i
.b
.e
- self
.i
.a
.e
)
720 m
.d
.comb
+= elz
.eq(self
.i
.a
.e
< self
.i
.b
.e
)
721 m
.d
.comb
+= egz
.eq(self
.i
.a
.e
> self
.i
.b
.e
)
723 # default: A-exp == B-exp, A and B untouched (fall through)
724 m
.d
.comb
+= self
.o
.a
.eq(self
.i
.a
)
725 m
.d
.comb
+= self
.o
.b
.eq(self
.i
.b
)
726 # only one shifter (muxed)
727 #m.d.comb += t_out.shift_down_multi(tdiff, t_inp)
728 # exponent of a greater than b: shift b down
729 with m
.If(~self
.i
.out_do_z
):
731 m
.d
.comb
+= [t_inp
.eq(self
.i
.b
),
734 self
.o
.b
.s
.eq(self
.i
.b
.s
), # whoops forgot sign
736 # exponent of b greater than a: shift a down
738 m
.d
.comb
+= [t_inp
.eq(self
.i
.a
),
741 self
.o
.a
.s
.eq(self
.i
.a
.s
), # whoops forgot sign
744 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
745 m
.d
.comb
+= self
.o
.z
.eq(self
.i
.z
)
746 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
747 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
752 class FPAddAlignSingle(FPState
):
754 def __init__(self
, width
, id_wid
):
755 FPState
.__init
__(self
, "align")
756 self
.mod
= FPAddAlignSingleMod(width
, id_wid
)
757 self
.out_a
= FPNumIn(None, width
)
758 self
.out_b
= FPNumIn(None, width
)
760 def setup(self
, m
, i
):
761 """ links module to inputs and outputs
765 # NOTE: could be done as comb
766 m
.d
.sync
+= self
.out_a
.eq(self
.mod
.out_a
)
767 m
.d
.sync
+= self
.out_b
.eq(self
.mod
.out_b
)
773 class FPAddAlignSingleAdd(FPState
, UnbufferedPipeline
):
775 def __init__(self
, width
, id_wid
):
776 FPState
.__init
__(self
, "align")
779 UnbufferedPipeline
.__init
__(self
, self
) # pipeline is its own stage
780 self
.a1o
= self
.ospec()
783 return FPSCData(self
.width
, self
.id_wid
)
784 #return FPNumBase2Ops(self.width, self.id_wid) # AlignSingle ispec
787 return FPAddStage1Data(self
.width
, self
.id_wid
) # AddStage1 ospec
789 def setup(self
, m
, i
):
790 """ links module to inputs and outputs
793 # chain AddAlignSingle, AddStage0 and AddStage1
794 mod
= FPAddAlignSingleMod(self
.width
, self
.id_wid
)
795 a0mod
= FPAddStage0Mod(self
.width
, self
.id_wid
)
796 a1mod
= FPAddStage1Mod(self
.width
, self
.id_wid
)
798 chain
= StageChain([mod
, a0mod
, a1mod
])
801 m
.d
.comb
+= self
.a1o
.eq(a1mod
.o
)
803 def process(self
, i
):
807 m
.next
= "normalise_1"
810 class FPAddStage0Data
:
812 def __init__(self
, width
, id_wid
):
813 self
.z
= FPNumBase(width
, False)
814 self
.out_do_z
= Signal(reset_less
=True)
815 self
.oz
= Signal(width
, reset_less
=True)
816 self
.tot
= Signal(self
.z
.m_width
+ 4, reset_less
=True)
817 self
.mid
= Signal(id_wid
, reset_less
=True)
820 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
821 self
.tot
.eq(i
.tot
), self
.mid
.eq(i
.mid
)]
824 class FPAddStage0Mod
:
826 def __init__(self
, width
, id_wid
):
829 self
.i
= self
.ispec()
830 self
.o
= self
.ospec()
833 return FPSCData(self
.width
, self
.id_wid
)
836 return FPAddStage0Data(self
.width
, self
.id_wid
)
838 def process(self
, i
):
841 def setup(self
, m
, i
):
842 """ links module to inputs and outputs
844 m
.submodules
.add0
= self
845 m
.d
.comb
+= self
.i
.eq(i
)
847 def elaborate(self
, platform
):
849 m
.submodules
.add0_in_a
= self
.i
.a
850 m
.submodules
.add0_in_b
= self
.i
.b
851 m
.submodules
.add0_out_z
= self
.o
.z
853 # store intermediate tests (and zero-extended mantissas)
854 seq
= Signal(reset_less
=True)
855 mge
= Signal(reset_less
=True)
856 am0
= Signal(len(self
.i
.a
.m
)+1, reset_less
=True)
857 bm0
= Signal(len(self
.i
.b
.m
)+1, reset_less
=True)
858 m
.d
.comb
+= [seq
.eq(self
.i
.a
.s
== self
.i
.b
.s
),
859 mge
.eq(self
.i
.a
.m
>= self
.i
.b
.m
),
860 am0
.eq(Cat(self
.i
.a
.m
, 0)),
861 bm0
.eq(Cat(self
.i
.b
.m
, 0))
863 # same-sign (both negative or both positive) add mantissas
864 with m
.If(~self
.i
.out_do_z
):
865 m
.d
.comb
+= self
.o
.z
.e
.eq(self
.i
.a
.e
)
868 self
.o
.tot
.eq(am0
+ bm0
),
869 self
.o
.z
.s
.eq(self
.i
.a
.s
)
871 # a mantissa greater than b, use a
874 self
.o
.tot
.eq(am0
- bm0
),
875 self
.o
.z
.s
.eq(self
.i
.a
.s
)
877 # b mantissa greater than a, use b
880 self
.o
.tot
.eq(bm0
- am0
),
881 self
.o
.z
.s
.eq(self
.i
.b
.s
)
884 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
885 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
886 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
890 class FPAddStage0(FPState
):
891 """ First stage of add. covers same-sign (add) and subtract
892 special-casing when mantissas are greater or equal, to
893 give greatest accuracy.
896 def __init__(self
, width
, id_wid
):
897 FPState
.__init
__(self
, "add_0")
898 self
.mod
= FPAddStage0Mod(width
)
899 self
.o
= self
.mod
.ospec()
901 def setup(self
, m
, i
):
902 """ links module to inputs and outputs
906 # NOTE: these could be done as combinatorial (merge add0+add1)
907 m
.d
.sync
+= self
.o
.eq(self
.mod
.o
)
913 class FPAddStage1Data
:
915 def __init__(self
, width
, id_wid
):
916 self
.z
= FPNumBase(width
, False)
917 self
.out_do_z
= Signal(reset_less
=True)
918 self
.oz
= Signal(width
, reset_less
=True)
920 self
.mid
= Signal(id_wid
, reset_less
=True)
923 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
924 self
.of
.eq(i
.of
), self
.mid
.eq(i
.mid
)]
928 class FPAddStage1Mod(FPState
):
929 """ Second stage of add: preparation for normalisation.
930 detects when tot sum is too big (tot[27] is kinda a carry bit)
933 def __init__(self
, width
, id_wid
):
936 self
.i
= self
.ispec()
937 self
.o
= self
.ospec()
940 return FPAddStage0Data(self
.width
, self
.id_wid
)
943 return FPAddStage1Data(self
.width
, self
.id_wid
)
945 def process(self
, i
):
948 def setup(self
, m
, i
):
949 """ links module to inputs and outputs
951 m
.submodules
.add1
= self
952 m
.submodules
.add1_out_overflow
= self
.o
.of
954 m
.d
.comb
+= self
.i
.eq(i
)
956 def elaborate(self
, platform
):
958 #m.submodules.norm1_in_overflow = self.in_of
959 #m.submodules.norm1_out_overflow = self.out_of
960 #m.submodules.norm1_in_z = self.in_z
961 #m.submodules.norm1_out_z = self.out_z
962 m
.d
.comb
+= self
.o
.z
.eq(self
.i
.z
)
963 # tot[-1] (MSB) gets set when the sum overflows. shift result down
964 with m
.If(~self
.i
.out_do_z
):
965 with m
.If(self
.i
.tot
[-1]):
967 self
.o
.z
.m
.eq(self
.i
.tot
[4:]),
968 self
.o
.of
.m0
.eq(self
.i
.tot
[4]),
969 self
.o
.of
.guard
.eq(self
.i
.tot
[3]),
970 self
.o
.of
.round_bit
.eq(self
.i
.tot
[2]),
971 self
.o
.of
.sticky
.eq(self
.i
.tot
[1] | self
.i
.tot
[0]),
972 self
.o
.z
.e
.eq(self
.i
.z
.e
+ 1)
974 # tot[-1] (MSB) zero case
977 self
.o
.z
.m
.eq(self
.i
.tot
[3:]),
978 self
.o
.of
.m0
.eq(self
.i
.tot
[3]),
979 self
.o
.of
.guard
.eq(self
.i
.tot
[2]),
980 self
.o
.of
.round_bit
.eq(self
.i
.tot
[1]),
981 self
.o
.of
.sticky
.eq(self
.i
.tot
[0])
984 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
985 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
986 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
991 class FPAddStage1(FPState
):
993 def __init__(self
, width
, id_wid
):
994 FPState
.__init
__(self
, "add_1")
995 self
.mod
= FPAddStage1Mod(width
)
996 self
.out_z
= FPNumBase(width
, False)
997 self
.out_of
= Overflow()
998 self
.norm_stb
= Signal()
1000 def setup(self
, m
, i
):
1001 """ links module to inputs and outputs
1003 self
.mod
.setup(m
, i
)
1005 m
.d
.sync
+= self
.norm_stb
.eq(0) # sets to zero when not in add1 state
1007 m
.d
.sync
+= self
.out_of
.eq(self
.mod
.out_of
)
1008 m
.d
.sync
+= self
.out_z
.eq(self
.mod
.out_z
)
1009 m
.d
.sync
+= self
.norm_stb
.eq(1)
1011 def action(self
, m
):
1012 m
.next
= "normalise_1"
1015 class FPNormaliseModSingle
:
1017 def __init__(self
, width
):
1019 self
.in_z
= self
.ispec()
1020 self
.out_z
= self
.ospec()
1023 return FPNumBase(self
.width
, False)
1026 return FPNumBase(self
.width
, False)
1028 def setup(self
, m
, i
):
1029 """ links module to inputs and outputs
1031 m
.submodules
.normalise
= self
1032 m
.d
.comb
+= self
.i
.eq(i
)
1034 def elaborate(self
, platform
):
1037 mwid
= self
.out_z
.m_width
+2
1038 pe
= PriorityEncoder(mwid
)
1039 m
.submodules
.norm_pe
= pe
1041 m
.submodules
.norm1_out_z
= self
.out_z
1042 m
.submodules
.norm1_in_z
= self
.in_z
1044 in_z
= FPNumBase(self
.width
, False)
1046 m
.submodules
.norm1_insel_z
= in_z
1047 m
.submodules
.norm1_insel_overflow
= in_of
1049 espec
= (len(in_z
.e
), True)
1050 ediff_n126
= Signal(espec
, reset_less
=True)
1051 msr
= MultiShiftRMerge(mwid
, espec
)
1052 m
.submodules
.multishift_r
= msr
1054 m
.d
.comb
+= in_z
.eq(self
.in_z
)
1055 m
.d
.comb
+= in_of
.eq(self
.in_of
)
1056 # initialise out from in (overridden below)
1057 m
.d
.comb
+= self
.out_z
.eq(in_z
)
1058 m
.d
.comb
+= self
.out_of
.eq(in_of
)
1059 # normalisation decrease condition
1060 decrease
= Signal(reset_less
=True)
1061 m
.d
.comb
+= decrease
.eq(in_z
.m_msbzero
)
1063 with m
.If(decrease
):
1064 # *sigh* not entirely obvious: count leading zeros (clz)
1065 # with a PriorityEncoder: to find from the MSB
1066 # we reverse the order of the bits.
1067 temp_m
= Signal(mwid
, reset_less
=True)
1068 temp_s
= Signal(mwid
+1, reset_less
=True)
1069 clz
= Signal((len(in_z
.e
), True), reset_less
=True)
1071 # cat round and guard bits back into the mantissa
1072 temp_m
.eq(Cat(in_of
.round_bit
, in_of
.guard
, in_z
.m
)),
1073 pe
.i
.eq(temp_m
[::-1]), # inverted
1074 clz
.eq(pe
.o
), # count zeros from MSB down
1075 temp_s
.eq(temp_m
<< clz
), # shift mantissa UP
1076 self
.out_z
.e
.eq(in_z
.e
- clz
), # DECREASE exponent
1077 self
.out_z
.m
.eq(temp_s
[2:]), # exclude bits 0&1
1084 def __init__(self
, width
, id_wid
):
1085 self
.roundz
= Signal(reset_less
=True)
1086 self
.z
= FPNumBase(width
, False)
1087 self
.out_do_z
= Signal(reset_less
=True)
1088 self
.oz
= Signal(width
, reset_less
=True)
1089 self
.mid
= Signal(id_wid
, reset_less
=True)
1092 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
1093 self
.roundz
.eq(i
.roundz
), self
.mid
.eq(i
.mid
)]
1096 class FPNorm1ModSingle
:
1098 def __init__(self
, width
, id_wid
):
1100 self
.id_wid
= id_wid
1101 self
.i
= self
.ispec()
1102 self
.o
= self
.ospec()
1105 return FPAddStage1Data(self
.width
, self
.id_wid
)
1108 return FPNorm1Data(self
.width
, self
.id_wid
)
1110 def setup(self
, m
, i
):
1111 """ links module to inputs and outputs
1113 m
.submodules
.normalise_1
= self
1114 m
.d
.comb
+= self
.i
.eq(i
)
1116 def process(self
, i
):
1119 def elaborate(self
, platform
):
1122 mwid
= self
.o
.z
.m_width
+2
1123 pe
= PriorityEncoder(mwid
)
1124 m
.submodules
.norm_pe
= pe
1127 m
.d
.comb
+= self
.o
.roundz
.eq(of
.roundz
)
1129 m
.submodules
.norm1_out_z
= self
.o
.z
1130 m
.submodules
.norm1_out_overflow
= of
1131 m
.submodules
.norm1_in_z
= self
.i
.z
1132 m
.submodules
.norm1_in_overflow
= self
.i
.of
1135 m
.submodules
.norm1_insel_z
= i
.z
1136 m
.submodules
.norm1_insel_overflow
= i
.of
1138 espec
= (len(i
.z
.e
), True)
1139 ediff_n126
= Signal(espec
, reset_less
=True)
1140 msr
= MultiShiftRMerge(mwid
, espec
)
1141 m
.submodules
.multishift_r
= msr
1143 m
.d
.comb
+= i
.eq(self
.i
)
1144 # initialise out from in (overridden below)
1145 m
.d
.comb
+= self
.o
.z
.eq(i
.z
)
1146 m
.d
.comb
+= of
.eq(i
.of
)
1147 # normalisation increase/decrease conditions
1148 decrease
= Signal(reset_less
=True)
1149 increase
= Signal(reset_less
=True)
1150 m
.d
.comb
+= decrease
.eq(i
.z
.m_msbzero
& i
.z
.exp_gt_n126
)
1151 m
.d
.comb
+= increase
.eq(i
.z
.exp_lt_n126
)
1153 with m
.If(~self
.i
.out_do_z
):
1154 with m
.If(decrease
):
1155 # *sigh* not entirely obvious: count leading zeros (clz)
1156 # with a PriorityEncoder: to find from the MSB
1157 # we reverse the order of the bits.
1158 temp_m
= Signal(mwid
, reset_less
=True)
1159 temp_s
= Signal(mwid
+1, reset_less
=True)
1160 clz
= Signal((len(i
.z
.e
), True), reset_less
=True)
1161 # make sure that the amount to decrease by does NOT
1162 # go below the minimum non-INF/NaN exponent
1163 limclz
= Mux(i
.z
.exp_sub_n126
> pe
.o
, pe
.o
,
1166 # cat round and guard bits back into the mantissa
1167 temp_m
.eq(Cat(i
.of
.round_bit
, i
.of
.guard
, i
.z
.m
)),
1168 pe
.i
.eq(temp_m
[::-1]), # inverted
1169 clz
.eq(limclz
), # count zeros from MSB down
1170 temp_s
.eq(temp_m
<< clz
), # shift mantissa UP
1171 self
.o
.z
.e
.eq(i
.z
.e
- clz
), # DECREASE exponent
1172 self
.o
.z
.m
.eq(temp_s
[2:]), # exclude bits 0&1
1173 of
.m0
.eq(temp_s
[2]), # copy of mantissa[0]
1174 # overflow in bits 0..1: got shifted too (leave sticky)
1175 of
.guard
.eq(temp_s
[1]), # guard
1176 of
.round_bit
.eq(temp_s
[0]), # round
1179 with m
.Elif(increase
):
1180 temp_m
= Signal(mwid
+1, reset_less
=True)
1182 temp_m
.eq(Cat(i
.of
.sticky
, i
.of
.round_bit
, i
.of
.guard
,
1184 ediff_n126
.eq(i
.z
.N126
- i
.z
.e
),
1185 # connect multi-shifter to inp/out mantissa (and ediff)
1187 msr
.diff
.eq(ediff_n126
),
1188 self
.o
.z
.m
.eq(msr
.m
[3:]),
1189 of
.m0
.eq(temp_s
[3]), # copy of mantissa[0]
1190 # overflow in bits 0..1: got shifted too (leave sticky)
1191 of
.guard
.eq(temp_s
[2]), # guard
1192 of
.round_bit
.eq(temp_s
[1]), # round
1193 of
.sticky
.eq(temp_s
[0]), # sticky
1194 self
.o
.z
.e
.eq(i
.z
.e
+ ediff_n126
),
1197 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
1198 m
.d
.comb
+= self
.o
.out_do_z
.eq(self
.i
.out_do_z
)
1199 m
.d
.comb
+= self
.o
.oz
.eq(self
.i
.oz
)
1204 class FPNorm1ModMulti
:
1206 def __init__(self
, width
, single_cycle
=True):
1208 self
.in_select
= Signal(reset_less
=True)
1209 self
.in_z
= FPNumBase(width
, False)
1210 self
.in_of
= Overflow()
1211 self
.temp_z
= FPNumBase(width
, False)
1212 self
.temp_of
= Overflow()
1213 self
.out_z
= FPNumBase(width
, False)
1214 self
.out_of
= Overflow()
1216 def elaborate(self
, platform
):
1219 m
.submodules
.norm1_out_z
= self
.out_z
1220 m
.submodules
.norm1_out_overflow
= self
.out_of
1221 m
.submodules
.norm1_temp_z
= self
.temp_z
1222 m
.submodules
.norm1_temp_of
= self
.temp_of
1223 m
.submodules
.norm1_in_z
= self
.in_z
1224 m
.submodules
.norm1_in_overflow
= self
.in_of
1226 in_z
= FPNumBase(self
.width
, False)
1228 m
.submodules
.norm1_insel_z
= in_z
1229 m
.submodules
.norm1_insel_overflow
= in_of
1231 # select which of temp or in z/of to use
1232 with m
.If(self
.in_select
):
1233 m
.d
.comb
+= in_z
.eq(self
.in_z
)
1234 m
.d
.comb
+= in_of
.eq(self
.in_of
)
1236 m
.d
.comb
+= in_z
.eq(self
.temp_z
)
1237 m
.d
.comb
+= in_of
.eq(self
.temp_of
)
1238 # initialise out from in (overridden below)
1239 m
.d
.comb
+= self
.out_z
.eq(in_z
)
1240 m
.d
.comb
+= self
.out_of
.eq(in_of
)
1241 # normalisation increase/decrease conditions
1242 decrease
= Signal(reset_less
=True)
1243 increase
= Signal(reset_less
=True)
1244 m
.d
.comb
+= decrease
.eq(in_z
.m_msbzero
& in_z
.exp_gt_n126
)
1245 m
.d
.comb
+= increase
.eq(in_z
.exp_lt_n126
)
1246 m
.d
.comb
+= self
.out_norm
.eq(decrease | increase
) # loop-end
1248 with m
.If(decrease
):
1250 self
.out_z
.e
.eq(in_z
.e
- 1), # DECREASE exponent
1251 self
.out_z
.m
.eq(in_z
.m
<< 1), # shift mantissa UP
1252 self
.out_z
.m
[0].eq(in_of
.guard
), # steal guard (was tot[2])
1253 self
.out_of
.guard
.eq(in_of
.round_bit
), # round (was tot[1])
1254 self
.out_of
.round_bit
.eq(0), # reset round bit
1255 self
.out_of
.m0
.eq(in_of
.guard
),
1258 with m
.Elif(increase
):
1260 self
.out_z
.e
.eq(in_z
.e
+ 1), # INCREASE exponent
1261 self
.out_z
.m
.eq(in_z
.m
>> 1), # shift mantissa DOWN
1262 self
.out_of
.guard
.eq(in_z
.m
[0]),
1263 self
.out_of
.m0
.eq(in_z
.m
[1]),
1264 self
.out_of
.round_bit
.eq(in_of
.guard
),
1265 self
.out_of
.sticky
.eq(in_of
.sticky | in_of
.round_bit
)
1271 class FPNorm1Single(FPState
):
1273 def __init__(self
, width
, id_wid
, single_cycle
=True):
1274 FPState
.__init
__(self
, "normalise_1")
1275 self
.mod
= FPNorm1ModSingle(width
)
1276 self
.o
= self
.ospec()
1277 self
.out_z
= FPNumBase(width
, False)
1278 self
.out_roundz
= Signal(reset_less
=True)
1281 return self
.mod
.ispec()
1284 return self
.mod
.ospec()
1286 def setup(self
, m
, i
):
1287 """ links module to inputs and outputs
1289 self
.mod
.setup(m
, i
)
1291 def action(self
, m
):
1295 class FPNorm1Multi(FPState
):
1297 def __init__(self
, width
, id_wid
):
1298 FPState
.__init
__(self
, "normalise_1")
1299 self
.mod
= FPNorm1ModMulti(width
)
1300 self
.stb
= Signal(reset_less
=True)
1301 self
.ack
= Signal(reset
=0, reset_less
=True)
1302 self
.out_norm
= Signal(reset_less
=True)
1303 self
.in_accept
= Signal(reset_less
=True)
1304 self
.temp_z
= FPNumBase(width
)
1305 self
.temp_of
= Overflow()
1306 self
.out_z
= FPNumBase(width
)
1307 self
.out_roundz
= Signal(reset_less
=True)
1309 def setup(self
, m
, in_z
, in_of
, norm_stb
):
1310 """ links module to inputs and outputs
1312 self
.mod
.setup(m
, in_z
, in_of
, norm_stb
,
1313 self
.in_accept
, self
.temp_z
, self
.temp_of
,
1314 self
.out_z
, self
.out_norm
)
1316 m
.d
.comb
+= self
.stb
.eq(norm_stb
)
1317 m
.d
.sync
+= self
.ack
.eq(0) # sets to zero when not in normalise_1 state
1319 def action(self
, m
):
1320 m
.d
.comb
+= self
.in_accept
.eq((~self
.ack
) & (self
.stb
))
1321 m
.d
.sync
+= self
.temp_of
.eq(self
.mod
.out_of
)
1322 m
.d
.sync
+= self
.temp_z
.eq(self
.out_z
)
1323 with m
.If(self
.out_norm
):
1324 with m
.If(self
.in_accept
):
1329 m
.d
.sync
+= self
.ack
.eq(0)
1331 # normalisation not required (or done).
1333 m
.d
.sync
+= self
.ack
.eq(1)
1334 m
.d
.sync
+= self
.out_roundz
.eq(self
.mod
.out_of
.roundz
)
1337 class FPNormToPack(FPState
, UnbufferedPipeline
):
1339 def __init__(self
, width
, id_wid
):
1340 FPState
.__init
__(self
, "normalise_1")
1341 self
.id_wid
= id_wid
1343 UnbufferedPipeline
.__init
__(self
, self
) # pipeline is its own stage
1346 return FPAddStage1Data(self
.width
, self
.id_wid
) # Norm1ModSingle ispec
1349 return FPPackData(self
.width
, self
.id_wid
) # FPPackMod ospec
1351 def setup(self
, m
, i
):
1352 """ links module to inputs and outputs
1355 # Normalisation, Rounding Corrections, Pack - in a chain
1356 nmod
= FPNorm1ModSingle(self
.width
, self
.id_wid
)
1357 rmod
= FPRoundMod(self
.width
, self
.id_wid
)
1358 cmod
= FPCorrectionsMod(self
.width
, self
.id_wid
)
1359 pmod
= FPPackMod(self
.width
, self
.id_wid
)
1360 chain
= StageChain([nmod
, rmod
, cmod
, pmod
])
1362 self
.out_z
= pmod
.ospec()
1364 m
.d
.comb
+= self
.out_z
.mid
.eq(pmod
.o
.mid
)
1365 m
.d
.comb
+= self
.out_z
.z
.eq(pmod
.o
.z
) # outputs packed result
1367 def process(self
, i
):
1370 def action(self
, m
):
1371 m
.next
= "pack_put_z"
1376 def __init__(self
, width
, id_wid
):
1377 self
.z
= FPNumBase(width
, False)
1378 self
.out_do_z
= Signal(reset_less
=True)
1379 self
.oz
= Signal(width
, reset_less
=True)
1380 self
.mid
= Signal(id_wid
, reset_less
=True)
1383 return [self
.z
.eq(i
.z
), self
.out_do_z
.eq(i
.out_do_z
), self
.oz
.eq(i
.oz
),
1389 def __init__(self
, width
, id_wid
):
1391 self
.id_wid
= id_wid
1392 self
.i
= self
.ispec()
1393 self
.out_z
= self
.ospec()
1396 return FPNorm1Data(self
.width
, self
.id_wid
)
1399 return FPRoundData(self
.width
, self
.id_wid
)
1401 def process(self
, i
):
1404 def setup(self
, m
, i
):
1405 m
.submodules
.roundz
= self
1406 m
.d
.comb
+= self
.i
.eq(i
)
1408 def elaborate(self
, platform
):
1410 m
.d
.comb
+= self
.out_z
.eq(self
.i
) # copies mid, z, out_do_z
1411 with m
.If(~self
.i
.out_do_z
):
1412 with m
.If(self
.i
.roundz
):
1413 m
.d
.comb
+= self
.out_z
.z
.m
.eq(self
.i
.z
.m
+ 1) # mantissa up
1414 with m
.If(self
.i
.z
.m
== self
.i
.z
.m1s
): # all 1s
1415 m
.d
.comb
+= self
.out_z
.z
.e
.eq(self
.i
.z
.e
+ 1) # exponent up
1420 class FPRound(FPState
):
1422 def __init__(self
, width
, id_wid
):
1423 FPState
.__init
__(self
, "round")
1424 self
.mod
= FPRoundMod(width
)
1425 self
.out_z
= self
.ospec()
1428 return self
.mod
.ispec()
1431 return self
.mod
.ospec()
1433 def setup(self
, m
, i
):
1434 """ links module to inputs and outputs
1436 self
.mod
.setup(m
, i
)
1439 m
.d
.sync
+= self
.out_z
.eq(self
.mod
.out_z
)
1440 m
.d
.sync
+= self
.out_z
.mid
.eq(self
.mod
.o
.mid
)
1442 def action(self
, m
):
1443 m
.next
= "corrections"
1446 class FPCorrectionsMod
:
1448 def __init__(self
, width
, id_wid
):
1450 self
.id_wid
= id_wid
1451 self
.i
= self
.ispec()
1452 self
.out_z
= self
.ospec()
1455 return FPRoundData(self
.width
, self
.id_wid
)
1458 return FPRoundData(self
.width
, self
.id_wid
)
1460 def process(self
, i
):
1463 def setup(self
, m
, i
):
1464 """ links module to inputs and outputs
1466 m
.submodules
.corrections
= self
1467 m
.d
.comb
+= self
.i
.eq(i
)
1469 def elaborate(self
, platform
):
1471 m
.submodules
.corr_in_z
= self
.i
.z
1472 m
.submodules
.corr_out_z
= self
.out_z
.z
1473 m
.d
.comb
+= self
.out_z
.eq(self
.i
) # copies mid, z, out_do_z
1474 with m
.If(~self
.i
.out_do_z
):
1475 with m
.If(self
.i
.z
.is_denormalised
):
1476 m
.d
.comb
+= self
.out_z
.z
.e
.eq(self
.i
.z
.N127
)
1480 class FPCorrections(FPState
):
1482 def __init__(self
, width
, id_wid
):
1483 FPState
.__init
__(self
, "corrections")
1484 self
.mod
= FPCorrectionsMod(width
)
1485 self
.out_z
= self
.ospec()
1488 return self
.mod
.ispec()
1491 return self
.mod
.ospec()
1493 def setup(self
, m
, in_z
):
1494 """ links module to inputs and outputs
1496 self
.mod
.setup(m
, in_z
)
1498 m
.d
.sync
+= self
.out_z
.eq(self
.mod
.out_z
)
1499 m
.d
.sync
+= self
.out_z
.mid
.eq(self
.mod
.o
.mid
)
1501 def action(self
, m
):
1507 def __init__(self
, width
, id_wid
):
1508 self
.z
= Signal(width
, reset_less
=True)
1509 self
.mid
= Signal(id_wid
, reset_less
=True)
1512 return [self
.z
.eq(i
.z
), self
.mid
.eq(i
.mid
)]
1515 return [self
.z
, self
.mid
]
1520 def __init__(self
, width
, id_wid
):
1522 self
.id_wid
= id_wid
1523 self
.i
= self
.ispec()
1524 self
.o
= self
.ospec()
1527 return FPRoundData(self
.width
, self
.id_wid
)
1530 return FPPackData(self
.width
, self
.id_wid
)
1532 def process(self
, i
):
1535 def setup(self
, m
, in_z
):
1536 """ links module to inputs and outputs
1538 m
.submodules
.pack
= self
1539 m
.d
.comb
+= self
.i
.eq(in_z
)
1541 def elaborate(self
, platform
):
1543 z
= FPNumOut(self
.width
, False)
1544 m
.submodules
.pack_in_z
= self
.i
.z
1545 m
.submodules
.pack_out_z
= z
1546 m
.d
.comb
+= self
.o
.mid
.eq(self
.i
.mid
)
1547 with m
.If(~self
.i
.out_do_z
):
1548 with m
.If(self
.i
.z
.is_overflowed
):
1549 m
.d
.comb
+= z
.inf(self
.i
.z
.s
)
1551 m
.d
.comb
+= z
.create(self
.i
.z
.s
, self
.i
.z
.e
, self
.i
.z
.m
)
1553 m
.d
.comb
+= z
.v
.eq(self
.i
.oz
)
1554 m
.d
.comb
+= self
.o
.z
.eq(z
.v
)
1558 class FPPack(FPState
):
1560 def __init__(self
, width
, id_wid
):
1561 FPState
.__init
__(self
, "pack")
1562 self
.mod
= FPPackMod(width
)
1563 self
.out_z
= self
.ospec()
1566 return self
.mod
.ispec()
1569 return self
.mod
.ospec()
1571 def setup(self
, m
, in_z
):
1572 """ links module to inputs and outputs
1574 self
.mod
.setup(m
, in_z
)
1576 m
.d
.sync
+= self
.out_z
.v
.eq(self
.mod
.out_z
.v
)
1577 m
.d
.sync
+= self
.out_z
.mid
.eq(self
.mod
.o
.mid
)
1579 def action(self
, m
):
1580 m
.next
= "pack_put_z"
1583 class FPPutZ(FPState
):
1585 def __init__(self
, state
, in_z
, out_z
, in_mid
, out_mid
, to_state
=None):
1586 FPState
.__init
__(self
, state
)
1587 if to_state
is None:
1588 to_state
= "get_ops"
1589 self
.to_state
= to_state
1592 self
.in_mid
= in_mid
1593 self
.out_mid
= out_mid
1595 def action(self
, m
):
1596 if self
.in_mid
is not None:
1597 m
.d
.sync
+= self
.out_mid
.eq(self
.in_mid
)
1599 self
.out_z
.z
.v
.eq(self
.in_z
)
1601 with m
.If(self
.out_z
.z
.stb
& self
.out_z
.z
.ack
):
1602 m
.d
.sync
+= self
.out_z
.z
.stb
.eq(0)
1603 m
.next
= self
.to_state
1605 m
.d
.sync
+= self
.out_z
.z
.stb
.eq(1)
1608 class FPPutZIdx(FPState
):
1610 def __init__(self
, state
, in_z
, out_zs
, in_mid
, to_state
=None):
1611 FPState
.__init
__(self
, state
)
1612 if to_state
is None:
1613 to_state
= "get_ops"
1614 self
.to_state
= to_state
1616 self
.out_zs
= out_zs
1617 self
.in_mid
= in_mid
1619 def action(self
, m
):
1620 outz_stb
= Signal(reset_less
=True)
1621 outz_ack
= Signal(reset_less
=True)
1622 m
.d
.comb
+= [outz_stb
.eq(self
.out_zs
[self
.in_mid
].stb
),
1623 outz_ack
.eq(self
.out_zs
[self
.in_mid
].ack
),
1626 self
.out_zs
[self
.in_mid
].v
.eq(self
.in_z
.v
)
1628 with m
.If(outz_stb
& outz_ack
):
1629 m
.d
.sync
+= self
.out_zs
[self
.in_mid
].stb
.eq(0)
1630 m
.next
= self
.to_state
1632 m
.d
.sync
+= self
.out_zs
[self
.in_mid
].stb
.eq(1)
1635 def __init__(self
, width
, id_wid
):
1636 self
.z
= FPOp(width
)
1637 self
.mid
= Signal(id_wid
, reset_less
=True)
1640 return [self
.z
.eq(i
.z
), self
.mid
.eq(i
.mid
)]
1643 return [self
.z
, self
.mid
]
1648 def __init__(self
, width
, id_wid
=None, single_cycle
=False, compact
=True):
1651 * width: bit-width of IEEE754. supported: 16, 32, 64
1652 * id_wid: an identifier that is sync-connected to the input
1653 * single_cycle: True indicates each stage to complete in 1 clock
1654 * compact: True indicates a reduced number of stages
1657 self
.id_wid
= id_wid
1658 self
.single_cycle
= single_cycle
1659 self
.compact
= compact
1661 self
.in_t
= Trigger()
1662 self
.i
= self
.ispec()
1663 self
.o
= self
.ospec()
1668 return FPADDBaseData(self
.width
, self
.id_wid
)
1671 return FPOpData(self
.width
, self
.id_wid
)
1673 def add_state(self
, state
):
1674 self
.states
.append(state
)
1677 def get_fragment(self
, platform
=None):
1678 """ creates the HDL code-fragment for FPAdd
1681 m
.submodules
.out_z
= self
.o
.z
1682 m
.submodules
.in_t
= self
.in_t
1684 self
.get_compact_fragment(m
, platform
)
1686 self
.get_longer_fragment(m
, platform
)
1688 with m
.FSM() as fsm
:
1690 for state
in self
.states
:
1691 with m
.State(state
.state_from
):
1696 def get_longer_fragment(self
, m
, platform
=None):
1698 get
= self
.add_state(FPGet2Op("get_ops", "special_cases",
1700 get
.setup(m
, self
.i
, self
.in_t
.stb
, self
.in_t
.ack
)
1704 sc
= self
.add_state(FPAddSpecialCases(self
.width
, self
.id_wid
))
1705 sc
.setup(m
, a
, b
, self
.in_mid
)
1707 dn
= self
.add_state(FPAddDeNorm(self
.width
, self
.id_wid
))
1708 dn
.setup(m
, a
, b
, sc
.in_mid
)
1710 if self
.single_cycle
:
1711 alm
= self
.add_state(FPAddAlignSingle(self
.width
, self
.id_wid
))
1712 alm
.setup(m
, dn
.out_a
, dn
.out_b
, dn
.in_mid
)
1714 alm
= self
.add_state(FPAddAlignMulti(self
.width
, self
.id_wid
))
1715 alm
.setup(m
, dn
.out_a
, dn
.out_b
, dn
.in_mid
)
1717 add0
= self
.add_state(FPAddStage0(self
.width
, self
.id_wid
))
1718 add0
.setup(m
, alm
.out_a
, alm
.out_b
, alm
.in_mid
)
1720 add1
= self
.add_state(FPAddStage1(self
.width
, self
.id_wid
))
1721 add1
.setup(m
, add0
.out_tot
, add0
.out_z
, add0
.in_mid
)
1723 if self
.single_cycle
:
1724 n1
= self
.add_state(FPNorm1Single(self
.width
, self
.id_wid
))
1725 n1
.setup(m
, add1
.out_z
, add1
.out_of
, add0
.in_mid
)
1727 n1
= self
.add_state(FPNorm1Multi(self
.width
, self
.id_wid
))
1728 n1
.setup(m
, add1
.out_z
, add1
.out_of
, add1
.norm_stb
, add0
.in_mid
)
1730 rn
= self
.add_state(FPRound(self
.width
, self
.id_wid
))
1731 rn
.setup(m
, n1
.out_z
, n1
.out_roundz
, n1
.in_mid
)
1733 cor
= self
.add_state(FPCorrections(self
.width
, self
.id_wid
))
1734 cor
.setup(m
, rn
.out_z
, rn
.in_mid
)
1736 pa
= self
.add_state(FPPack(self
.width
, self
.id_wid
))
1737 pa
.setup(m
, cor
.out_z
, rn
.in_mid
)
1739 ppz
= self
.add_state(FPPutZ("pack_put_z", pa
.out_z
, self
.out_z
,
1740 pa
.in_mid
, self
.out_mid
))
1742 pz
= self
.add_state(FPPutZ("put_z", sc
.out_z
, self
.out_z
,
1743 pa
.in_mid
, self
.out_mid
))
1745 def get_compact_fragment(self
, m
, platform
=None):
1747 get
= self
.add_state(FPGet2Op("get_ops", "special_cases",
1748 self
.width
, self
.id_wid
))
1749 get
.setup(m
, self
.i
, self
.in_t
.stb
, self
.in_t
.ack
)
1751 sc
= self
.add_state(FPAddSpecialCasesDeNorm(self
.width
, self
.id_wid
))
1754 alm
= self
.add_state(FPAddAlignSingleAdd(self
.width
, self
.id_wid
))
1757 n1
= self
.add_state(FPNormToPack(self
.width
, self
.id_wid
))
1758 n1
.setup(m
, alm
.a1o
)
1760 ppz
= self
.add_state(FPPutZ("pack_put_z", n1
.out_z
.z
, self
.o
,
1761 n1
.out_z
.mid
, self
.o
.mid
))
1763 #pz = self.add_state(FPPutZ("put_z", sc.out_z.z, self.o,
1764 # sc.o.mid, self.o.mid))
1767 class FPADDBase(FPState
):
1769 def __init__(self
, width
, id_wid
=None, single_cycle
=False):
1772 * width: bit-width of IEEE754. supported: 16, 32, 64
1773 * id_wid: an identifier that is sync-connected to the input
1774 * single_cycle: True indicates each stage to complete in 1 clock
1776 FPState
.__init
__(self
, "fpadd")
1778 self
.single_cycle
= single_cycle
1779 self
.mod
= FPADDBaseMod(width
, id_wid
, single_cycle
)
1780 self
.o
= self
.ospec()
1782 self
.in_t
= Trigger()
1783 self
.i
= self
.ispec()
1785 self
.z_done
= Signal(reset_less
=True) # connects to out_z Strobe
1786 self
.in_accept
= Signal(reset_less
=True)
1787 self
.add_stb
= Signal(reset_less
=True)
1788 self
.add_ack
= Signal(reset
=0, reset_less
=True)
1791 return self
.mod
.ispec()
1794 return self
.mod
.ospec()
1796 def setup(self
, m
, i
, add_stb
, in_mid
):
1797 m
.d
.comb
+= [self
.i
.eq(i
),
1798 self
.mod
.i
.eq(self
.i
),
1799 self
.z_done
.eq(self
.mod
.o
.z
.trigger
),
1800 #self.add_stb.eq(add_stb),
1801 self
.mod
.in_t
.stb
.eq(self
.in_t
.stb
),
1802 self
.in_t
.ack
.eq(self
.mod
.in_t
.ack
),
1803 self
.o
.mid
.eq(self
.mod
.o
.mid
),
1804 self
.o
.z
.v
.eq(self
.mod
.o
.z
.v
),
1805 self
.o
.z
.stb
.eq(self
.mod
.o
.z
.stb
),
1806 self
.mod
.o
.z
.ack
.eq(self
.o
.z
.ack
),
1809 m
.d
.sync
+= self
.add_stb
.eq(add_stb
)
1810 m
.d
.sync
+= self
.add_ack
.eq(0) # sets to zero when not in active state
1811 m
.d
.sync
+= self
.o
.z
.ack
.eq(0) # likewise
1812 #m.d.sync += self.in_t.stb.eq(0)
1814 m
.submodules
.fpadd
= self
.mod
1816 def action(self
, m
):
1818 # in_accept is set on incoming strobe HIGH and ack LOW.
1819 m
.d
.comb
+= self
.in_accept
.eq((~self
.add_ack
) & (self
.add_stb
))
1821 #with m.If(self.in_t.ack):
1822 # m.d.sync += self.in_t.stb.eq(0)
1823 with m
.If(~self
.z_done
):
1824 # not done: test for accepting an incoming operand pair
1825 with m
.If(self
.in_accept
):
1827 self
.add_ack
.eq(1), # acknowledge receipt...
1828 self
.in_t
.stb
.eq(1), # initiate add
1831 m
.d
.sync
+= [self
.add_ack
.eq(0),
1832 self
.in_t
.stb
.eq(0),
1836 # done: acknowledge, and write out id and value
1837 m
.d
.sync
+= [self
.add_ack
.eq(1),
1844 if self
.in_mid
is not None:
1845 m
.d
.sync
+= self
.out_mid
.eq(self
.mod
.out_mid
)
1848 self
.out_z
.v
.eq(self
.mod
.out_z
.v
)
1850 # move to output state on detecting z ack
1851 with m
.If(self
.out_z
.trigger
):
1852 m
.d
.sync
+= self
.out_z
.stb
.eq(0)
1855 m
.d
.sync
+= self
.out_z
.stb
.eq(1)
1858 class FPADDBasePipe(ControlBase
):
1859 def __init__(self
, width
, id_wid
):
1860 ControlBase
.__init
__(self
)
1861 self
.pipe1
= FPAddSpecialCasesDeNorm(width
, id_wid
)
1862 self
.pipe2
= FPAddAlignSingleAdd(width
, id_wid
)
1863 self
.pipe3
= FPNormToPack(width
, id_wid
)
1865 self
._eqs
= self
.connect([self
.pipe1
, self
.pipe2
, self
.pipe3
])
1867 def elaborate(self
, platform
):
1869 m
.submodules
.scnorm
= self
.pipe1
1870 m
.submodules
.addalign
= self
.pipe2
1871 m
.submodules
.normpack
= self
.pipe3
1872 m
.d
.comb
+= self
._eqs
1876 class FPADDInMuxPipe(PriorityCombMuxInPipe
):
1877 def __init__(self
, width
, id_wid
, num_rows
):
1878 self
.num_rows
= num_rows
1879 def iospec(): return FPADDBaseData(width
, id_wid
)
1880 stage
= PassThroughStage(iospec
)
1881 PriorityCombMuxInPipe
.__init
__(self
, stage
, p_len
=self
.num_rows
)
1885 for i
in range(len(self
.p
)):
1886 res
+= [self
.p
[i
].i_valid
, self
.p
[i
].o_ready
] + \
1887 self
.p
[i
].i_data
.ports()
1888 res
+= [self
.n
.i_ready
, self
.n
.o_valid
] + \
1889 self
.n
.o_data
.ports()
1893 class FPADDMuxOutPipe(CombMuxOutPipe
):
1894 def __init__(self
, width
, id_wid
, num_rows
):
1895 self
.num_rows
= num_rows
1896 def iospec(): return FPPackData(width
, id_wid
)
1897 stage
= PassThroughStage(iospec
)
1898 CombMuxOutPipe
.__init
__(self
, stage
, n_len
=self
.num_rows
)
1901 res
= [self
.p
.i_valid
, self
.p
.o_ready
] + \
1902 self
.p
.i_data
.ports()
1903 for i
in range(len(self
.n
)):
1904 res
+= [self
.n
[i
].i_ready
, self
.n
[i
].o_valid
] + \
1905 self
.n
[i
].o_data
.ports()
1909 class FPADDMuxInOut
:
1910 """ Reservation-Station version of FPADD pipeline.
1914 def __init__(self
, width
, id_wid
, num_rows
):
1915 self
.num_rows
= num_rows
1916 self
.inpipe
= FPADDInMuxPipe(width
, id_wid
, num_rows
) # fan-in
1917 self
.fpadd
= FPADDBasePipe(width
, id_wid
) # add stage
1918 self
.outpipe
= FPADDMuxOutPipe(width
, id_wid
, num_rows
) # fan-out
1920 self
.p
= self
.inpipe
.p
# kinda annoying,
1921 self
.n
= self
.outpipe
.n
# use pipe in/out as this class in/out
1922 self
._ports
= self
.inpipe
.ports() + self
.outpipe
.ports()
1924 def elaborate(self
, platform
):
1926 m
.submodules
.inpipe
= self
.inpipe
1927 m
.submodules
.fpadd
= self
.fpadd
1928 m
.submodules
.outpipe
= self
.outpipe
1930 m
.d
.comb
+= self
.inpipe
.n
.connect_to_next(self
.fpadd
.p
)
1931 m
.d
.comb
+= self
.fpadd
.connect_to_next(self
.outpipe
)
1940 def __init__(self
, width
, id_wid
):
1942 self
.id_wid
= id_wid
1944 for i
in range(rs_sz
):
1946 out_z
.name
= "out_z_%d" % i
1948 self
.res
= Array(res
)
1949 self
.in_z
= FPOp(width
)
1950 self
.in_mid
= Signal(self
.id_wid
, reset_less
=True)
1952 def setup(self
, m
, in_z
, in_mid
):
1953 m
.d
.comb
+= [self
.in_z
.eq(in_z
),
1954 self
.in_mid
.eq(in_mid
)]
1956 def get_fragment(self
, platform
=None):
1957 """ creates the HDL code-fragment for FPAdd
1960 m
.submodules
.res_in_z
= self
.in_z
1961 m
.submodules
+= self
.res
1973 """ FPADD: stages as follows:
1979 FPAddBase---> FPAddBaseMod
1981 PutZ GetOps->Specials->Align->Add1/2->Norm->Round/Pack->PutZ
1983 FPAddBase is tricky: it is both a stage and *has* stages.
1984 Connection to FPAddBaseMod therefore requires an in stb/ack
1985 and an out stb/ack. Just as with Add1-Norm1 interaction, FPGetOp
1986 needs to be the thing that raises the incoming stb.
1989 def __init__(self
, width
, id_wid
=None, single_cycle
=False, rs_sz
=2):
1992 * width: bit-width of IEEE754. supported: 16, 32, 64
1993 * id_wid: an identifier that is sync-connected to the input
1994 * single_cycle: True indicates each stage to complete in 1 clock
1997 self
.id_wid
= id_wid
1998 self
.single_cycle
= single_cycle
2000 #self.out_z = FPOp(width)
2001 self
.ids
= FPID(id_wid
)
2004 for i
in range(rs_sz
):
2007 in_a
.name
= "in_a_%d" % i
2008 in_b
.name
= "in_b_%d" % i
2009 rs
.append((in_a
, in_b
))
2013 for i
in range(rs_sz
):
2015 out_z
.name
= "out_z_%d" % i
2017 self
.res
= Array(res
)
2021 def add_state(self
, state
):
2022 self
.states
.append(state
)
2025 def get_fragment(self
, platform
=None):
2026 """ creates the HDL code-fragment for FPAdd
2029 m
.submodules
+= self
.rs
2031 in_a
= self
.rs
[0][0]
2032 in_b
= self
.rs
[0][1]
2034 geta
= self
.add_state(FPGetOp("get_a", "get_b",
2039 getb
= self
.add_state(FPGetOp("get_b", "fpadd",
2044 ab
= FPADDBase(self
.width
, self
.id_wid
, self
.single_cycle
)
2045 ab
= self
.add_state(ab
)
2046 abd
= ab
.ispec() # create an input spec object for FPADDBase
2047 m
.d
.sync
+= [abd
.a
.eq(a
), abd
.b
.eq(b
), abd
.mid
.eq(self
.ids
.in_mid
)]
2048 ab
.setup(m
, abd
, getb
.out_decode
, self
.ids
.in_mid
)
2051 pz
= self
.add_state(FPPutZIdx("put_z", o
.z
, self
.res
,
2054 with m
.FSM() as fsm
:
2056 for state
in self
.states
:
2057 with m
.State(state
.state_from
):
2063 if __name__
== "__main__":
2065 alu
= FPADD(width
=32, id_wid
=5, single_cycle
=True)
2066 main(alu
, ports
=alu
.rs
[0][0].ports() + \
2067 alu
.rs
[0][1].ports() + \
2068 alu
.res
[0].ports() + \
2069 [alu
.ids
.in_mid
, alu
.ids
.out_mid
])
2071 alu
= FPADDBase(width
=32, id_wid
=5, single_cycle
=True)
2072 main(alu
, ports
=[alu
.in_a
, alu
.in_b
] + \
2073 alu
.in_t
.ports() + \
2074 alu
.out_z
.ports() + \
2075 [alu
.in_mid
, alu
.out_mid
])
2078 # works... but don't use, just do "python fname.py convert -t v"
2079 #print (verilog.convert(alu, ports=[
2080 # ports=alu.in_a.ports() + \
2081 # alu.in_b.ports() + \
2082 # alu.out_z.ports())