1 # IEEE Floating Point Adder (Single Precision)
2 # Copyright (C) Jonathan P Dawson 2013
5 from nmigen
import Signal
, Cat
, Const
, Mux
, Module
, Elaboratable
7 from operator
import or_
8 from functools
import reduce
10 from nmutil
.singlepipe
import PrevControl
, NextControl
11 from nmutil
.pipeline
import ObjectProxy
16 def __init__(self
, width
):
18 self
.smax
= int(log(width
) / log(2))
19 self
.i
= Signal(width
, reset_less
=True)
20 self
.s
= Signal(self
.smax
, reset_less
=True)
21 self
.o
= Signal(width
, reset_less
=True)
23 def elaborate(self
, platform
):
25 m
.d
.comb
+= self
.o
.eq(self
.i
>> self
.s
)
30 """ Generates variable-length single-cycle shifter from a series
31 of conditional tests on each bit of the left/right shift operand.
32 Each bit tested produces output shifted by that number of bits,
33 in a binary fashion: bit 1 if set shifts by 1 bit, bit 2 if set
34 shifts by 2 bits, each partial result cascading to the next Mux.
36 Could be adapted to do arithmetic shift by taking copies of the
40 def __init__(self
, width
):
42 self
.smax
= int(log(width
) / log(2))
44 def lshift(self
, op
, s
):
48 for i
in range(self
.smax
):
50 res
= Mux(s
& (1<<i
), Cat(zeros
, res
[0:-(1<<i
)]), res
)
53 def rshift(self
, op
, s
):
57 for i
in range(self
.smax
):
59 res
= Mux(s
& (1<<i
), Cat(res
[(1<<i
):], zeros
), res
)
63 class FPNumBaseRecord
:
64 """ Floating-point Base Number Class
66 def __init__(self
, width
, m_extra
=True):
68 m_width
= {16: 11, 32: 24, 64: 53}[width
] # 1 extra bit (overflow)
69 e_width
= {16: 7, 32: 10, 64: 13}[width
] # 2 extra bits (overflow)
70 e_max
= 1<<(e_width
-3)
71 self
.rmw
= m_width
# real mantissa width (not including extras)
74 # mantissa extra bits (top,guard,round)
76 m_width
+= self
.m_extra
79 #print (m_width, e_width, e_max, self.rmw, self.m_extra)
80 self
.m_width
= m_width
81 self
.e_width
= e_width
82 self
.e_start
= self
.rmw
- 1
83 self
.e_end
= self
.rmw
+ self
.e_width
- 3 # for decoding
85 self
.v
= Signal(width
, reset_less
=True) # Latched copy of value
86 self
.m
= Signal(m_width
, reset_less
=True) # Mantissa
87 self
.e
= Signal((e_width
, True), reset_less
=True) # exp+2 bits, signed
88 self
.s
= Signal(reset_less
=True) # Sign bit
93 def drop_in(self
, fp
):
100 fp
.e_width
= self
.e_width
101 fp
.e_max
= self
.e_max
102 fp
.m_width
= self
.m_width
103 fp
.e_start
= self
.e_start
104 fp
.e_end
= self
.e_end
105 fp
.m_extra
= self
.m_extra
107 m_width
= self
.m_width
109 e_width
= self
.e_width
111 self
.mzero
= Const(0, (m_width
, False))
112 m_msb
= 1<<(self
.m_width
-2)
113 self
.msb1
= Const(m_msb
, (m_width
, False))
114 self
.m1s
= Const(-1, (m_width
, False))
115 self
.P128
= Const(e_max
, (e_width
, True))
116 self
.P127
= Const(e_max
-1, (e_width
, True))
117 self
.N127
= Const(-(e_max
-1), (e_width
, True))
118 self
.N126
= Const(-(e_max
-2), (e_width
, True))
120 def create(self
, s
, e
, m
):
121 """ creates a value from sign / exponent / mantissa
123 bias is added here, to the exponent
126 self
.v
[-1].eq(s
), # sign
127 self
.v
[self
.e_start
:self
.e_end
].eq(e
+ self
.fp
.P127
), # (add on bias)
128 self
.v
[0:self
.e_start
].eq(m
) # mantissa
132 return self
.create(s
, self
.fp
.P128
, 1<<(self
.e_start
-1))
135 return self
.create(s
, self
.fp
.P128
, 0)
138 return self
.create(s
, self
.fp
.N127
, 0)
140 def create2(self
, s
, e
, m
):
141 """ creates a value from sign / exponent / mantissa
143 bias is added here, to the exponent
145 e
= e
+ self
.P127
# exp (add on bias)
146 return Cat(m
[0:self
.e_start
],
147 e
[0:self
.e_end
-self
.e_start
],
151 return self
.create2(s
, self
.P128
, self
.msb1
)
154 return self
.create2(s
, self
.P128
, self
.mzero
)
157 return self
.create2(s
, self
.N127
, self
.mzero
)
165 return [self
.s
.eq(inp
.s
), self
.e
.eq(inp
.e
), self
.m
.eq(inp
.m
)]
168 class FPNumBase(FPNumBaseRecord
, Elaboratable
):
169 """ Floating-point Base Number Class
171 def __init__(self
, fp
):
176 self
.is_nan
= Signal(reset_less
=True)
177 self
.is_zero
= Signal(reset_less
=True)
178 self
.is_inf
= Signal(reset_less
=True)
179 self
.is_overflowed
= Signal(reset_less
=True)
180 self
.is_denormalised
= Signal(reset_less
=True)
181 self
.exp_128
= Signal(reset_less
=True)
182 self
.exp_sub_n126
= Signal((e_width
, True), reset_less
=True)
183 self
.exp_lt_n126
= Signal(reset_less
=True)
184 self
.exp_gt_n126
= Signal(reset_less
=True)
185 self
.exp_gt127
= Signal(reset_less
=True)
186 self
.exp_n127
= Signal(reset_less
=True)
187 self
.exp_n126
= Signal(reset_less
=True)
188 self
.m_zero
= Signal(reset_less
=True)
189 self
.m_msbzero
= Signal(reset_less
=True)
191 def elaborate(self
, platform
):
193 m
.d
.comb
+= self
.is_nan
.eq(self
._is
_nan
())
194 m
.d
.comb
+= self
.is_zero
.eq(self
._is
_zero
())
195 m
.d
.comb
+= self
.is_inf
.eq(self
._is
_inf
())
196 m
.d
.comb
+= self
.is_overflowed
.eq(self
._is
_overflowed
())
197 m
.d
.comb
+= self
.is_denormalised
.eq(self
._is
_denormalised
())
198 m
.d
.comb
+= self
.exp_128
.eq(self
.e
== self
.fp
.P128
)
199 m
.d
.comb
+= self
.exp_sub_n126
.eq(self
.e
- self
.fp
.N126
)
200 m
.d
.comb
+= self
.exp_gt_n126
.eq(self
.exp_sub_n126
> 0)
201 m
.d
.comb
+= self
.exp_lt_n126
.eq(self
.exp_sub_n126
< 0)
202 m
.d
.comb
+= self
.exp_gt127
.eq(self
.e
> self
.fp
.P127
)
203 m
.d
.comb
+= self
.exp_n127
.eq(self
.e
== self
.fp
.N127
)
204 m
.d
.comb
+= self
.exp_n126
.eq(self
.e
== self
.fp
.N126
)
205 m
.d
.comb
+= self
.m_zero
.eq(self
.m
== self
.fp
.mzero
)
206 m
.d
.comb
+= self
.m_msbzero
.eq(self
.m
[self
.fp
.e_start
] == 0)
211 return (self
.exp_128
) & (~self
.m_zero
)
214 return (self
.exp_128
) & (self
.m_zero
)
217 return (self
.exp_n127
) & (self
.m_zero
)
219 def _is_overflowed(self
):
220 return self
.exp_gt127
222 def _is_denormalised(self
):
223 return (self
.exp_n126
) & (self
.m_msbzero
)
226 class FPNumOut(FPNumBase
):
227 """ Floating-point Number Class
229 Contains signals for an incoming copy of the value, decoded into
230 sign / exponent / mantissa.
231 Also contains encoding functions, creation and recognition of
232 zero, NaN and inf (all signed)
234 Four extra bits are included in the mantissa: the top bit
235 (m[-1]) is effectively a carry-overflow. The other three are
236 guard (m[2]), round (m[1]), and sticky (m[0])
238 def __init__(self
, fp
):
239 FPNumBase
.__init
__(self
, fp
)
241 def elaborate(self
, platform
):
242 m
= FPNumBase
.elaborate(self
, platform
)
247 class MultiShiftRMerge(Elaboratable
):
248 """ shifts down (right) and merges lower bits into m[0].
249 m[0] is the "sticky" bit, basically
251 def __init__(self
, width
, s_max
=None):
253 s_max
= int(log(width
) / log(2))
255 self
.m
= Signal(width
, reset_less
=True)
256 self
.inp
= Signal(width
, reset_less
=True)
257 self
.diff
= Signal(s_max
, reset_less
=True)
260 def elaborate(self
, platform
):
263 rs
= Signal(self
.width
, reset_less
=True)
264 m_mask
= Signal(self
.width
, reset_less
=True)
265 smask
= Signal(self
.width
, reset_less
=True)
266 stickybit
= Signal(reset_less
=True)
267 maxslen
= Signal(self
.smax
, reset_less
=True)
268 maxsleni
= Signal(self
.smax
, reset_less
=True)
270 sm
= MultiShift(self
.width
-1)
271 m0s
= Const(0, self
.width
-1)
272 mw
= Const(self
.width
-1, len(self
.diff
))
273 m
.d
.comb
+= [maxslen
.eq(Mux(self
.diff
> mw
, mw
, self
.diff
)),
274 maxsleni
.eq(Mux(self
.diff
> mw
, 0, mw
-self
.diff
)),
278 # shift mantissa by maxslen, mask by inverse
279 rs
.eq(sm
.rshift(self
.inp
[1:], maxslen
)),
280 m_mask
.eq(sm
.rshift(~m0s
, maxsleni
)),
281 smask
.eq(self
.inp
[1:] & m_mask
),
282 # sticky bit combines all mask (and mantissa low bit)
283 stickybit
.eq(smask
.bool() | self
.inp
[0]),
284 # mantissa result contains m[0] already.
285 self
.m
.eq(Cat(stickybit
, rs
))
290 class FPNumShift(FPNumBase
, Elaboratable
):
291 """ Floating-point Number Class for shifting
293 def __init__(self
, mainm
, op
, inv
, width
, m_extra
=True):
294 FPNumBase
.__init
__(self
, width
, m_extra
)
295 self
.latch_in
= Signal()
300 def elaborate(self
, platform
):
301 m
= FPNumBase
.elaborate(self
, platform
)
303 m
.d
.comb
+= self
.s
.eq(op
.s
)
304 m
.d
.comb
+= self
.e
.eq(op
.e
)
305 m
.d
.comb
+= self
.m
.eq(op
.m
)
307 with self
.mainm
.State("align"):
308 with m
.If(self
.e
< self
.inv
.e
):
309 m
.d
.sync
+= self
.shift_down()
313 def shift_down(self
, inp
):
314 """ shifts a mantissa down by one. exponent is increased to compensate
316 accuracy is lost as a result in the mantissa however there are 3
317 guard bits (the latter of which is the "sticky" bit)
319 return [self
.e
.eq(inp
.e
+ 1),
320 self
.m
.eq(Cat(inp
.m
[0] | inp
.m
[1], inp
.m
[2:], 0))
323 def shift_down_multi(self
, diff
):
324 """ shifts a mantissa down. exponent is increased to compensate
326 accuracy is lost as a result in the mantissa however there are 3
327 guard bits (the latter of which is the "sticky" bit)
329 this code works by variable-shifting the mantissa by up to
330 its maximum bit-length: no point doing more (it'll still be
333 the sticky bit is computed by shifting a batch of 1s by
334 the same amount, which will introduce zeros. it's then
335 inverted and used as a mask to get the LSBs of the mantissa.
336 those are then |'d into the sticky bit.
338 sm
= MultiShift(self
.width
)
339 mw
= Const(self
.m_width
-1, len(diff
))
340 maxslen
= Mux(diff
> mw
, mw
, diff
)
341 rs
= sm
.rshift(self
.m
[1:], maxslen
)
342 maxsleni
= mw
- maxslen
343 m_mask
= sm
.rshift(self
.m1s
[1:], maxsleni
) # shift and invert
345 stickybits
= reduce(or_
, self
.m
[1:] & m_mask
) | self
.m
[0]
346 return [self
.e
.eq(self
.e
+ diff
),
347 self
.m
.eq(Cat(stickybits
, rs
))
350 def shift_up_multi(self
, diff
):
351 """ shifts a mantissa up. exponent is decreased to compensate
353 sm
= MultiShift(self
.width
)
354 mw
= Const(self
.m_width
, len(diff
))
355 maxslen
= Mux(diff
> mw
, mw
, diff
)
357 return [self
.e
.eq(self
.e
- diff
),
358 self
.m
.eq(sm
.lshift(self
.m
, maxslen
))
362 class FPNumDecode(FPNumBase
):
363 """ Floating-point Number Class
365 Contains signals for an incoming copy of the value, decoded into
366 sign / exponent / mantissa.
367 Also contains encoding functions, creation and recognition of
368 zero, NaN and inf (all signed)
370 Four extra bits are included in the mantissa: the top bit
371 (m[-1]) is effectively a carry-overflow. The other three are
372 guard (m[2]), round (m[1]), and sticky (m[0])
374 def __init__(self
, op
, fp
):
375 FPNumBase
.__init
__(self
, fp
)
378 def elaborate(self
, platform
):
379 m
= FPNumBase
.elaborate(self
, platform
)
381 m
.d
.comb
+= self
.decode(self
.v
)
386 """ decodes a latched value into sign / exponent / mantissa
388 bias is subtracted here, from the exponent. exponent
389 is extended to 10 bits so that subtract 127 is done on
392 args
= [0] * self
.m_extra
+ [v
[0:self
.e_start
]] # pad with extra zeros
393 #print ("decode", self.e_end)
394 return [self
.m
.eq(Cat(*args
)), # mantissa
395 self
.e
.eq(v
[self
.e_start
:self
.e_end
] - self
.fp
.P127
), # exp
396 self
.s
.eq(v
[-1]), # sign
399 class FPNumIn(FPNumBase
):
400 """ Floating-point Number Class
402 Contains signals for an incoming copy of the value, decoded into
403 sign / exponent / mantissa.
404 Also contains encoding functions, creation and recognition of
405 zero, NaN and inf (all signed)
407 Four extra bits are included in the mantissa: the top bit
408 (m[-1]) is effectively a carry-overflow. The other three are
409 guard (m[2]), round (m[1]), and sticky (m[0])
411 def __init__(self
, op
, fp
):
412 FPNumBase
.__init
__(self
, fp
)
413 self
.latch_in
= Signal()
416 def decode2(self
, m
):
417 """ decodes a latched value into sign / exponent / mantissa
419 bias is subtracted here, from the exponent. exponent
420 is extended to 10 bits so that subtract 127 is done on
424 args
= [0] * self
.m_extra
+ [v
[0:self
.e_start
]] # pad with extra zeros
425 #print ("decode", self.e_end)
426 res
= ObjectProxy(m
, pipemode
=False)
427 res
.m
= Cat(*args
) # mantissa
428 res
.e
= v
[self
.e_start
:self
.e_end
] - self
.fp
.P127
# exp
433 """ decodes a latched value into sign / exponent / mantissa
435 bias is subtracted here, from the exponent. exponent
436 is extended to 10 bits so that subtract 127 is done on
439 args
= [0] * self
.m_extra
+ [v
[0:self
.e_start
]] # pad with extra zeros
440 #print ("decode", self.e_end)
441 return [self
.m
.eq(Cat(*args
)), # mantissa
442 self
.e
.eq(v
[self
.e_start
:self
.e_end
] - self
.P127
), # exp
443 self
.s
.eq(v
[-1]), # sign
446 def shift_down(self
, inp
):
447 """ shifts a mantissa down by one. exponent is increased to compensate
449 accuracy is lost as a result in the mantissa however there are 3
450 guard bits (the latter of which is the "sticky" bit)
452 return [self
.e
.eq(inp
.e
+ 1),
453 self
.m
.eq(Cat(inp
.m
[0] | inp
.m
[1], inp
.m
[2:], 0))
456 def shift_down_multi(self
, diff
, inp
=None):
457 """ shifts a mantissa down. exponent is increased to compensate
459 accuracy is lost as a result in the mantissa however there are 3
460 guard bits (the latter of which is the "sticky" bit)
462 this code works by variable-shifting the mantissa by up to
463 its maximum bit-length: no point doing more (it'll still be
466 the sticky bit is computed by shifting a batch of 1s by
467 the same amount, which will introduce zeros. it's then
468 inverted and used as a mask to get the LSBs of the mantissa.
469 those are then |'d into the sticky bit.
473 sm
= MultiShift(self
.width
)
474 mw
= Const(self
.m_width
-1, len(diff
))
475 maxslen
= Mux(diff
> mw
, mw
, diff
)
476 rs
= sm
.rshift(inp
.m
[1:], maxslen
)
477 maxsleni
= mw
- maxslen
478 m_mask
= sm
.rshift(self
.m1s
[1:], maxsleni
) # shift and invert
480 #stickybit = reduce(or_, inp.m[1:] & m_mask) | inp.m[0]
481 stickybit
= (inp
.m
[1:] & m_mask
).bool() | inp
.m
[0]
482 return [self
.e
.eq(inp
.e
+ diff
),
483 self
.m
.eq(Cat(stickybit
, rs
))
486 def shift_up_multi(self
, diff
):
487 """ shifts a mantissa up. exponent is decreased to compensate
489 sm
= MultiShift(self
.width
)
490 mw
= Const(self
.m_width
, len(diff
))
491 maxslen
= Mux(diff
> mw
, mw
, diff
)
493 return [self
.e
.eq(self
.e
- diff
),
494 self
.m
.eq(sm
.lshift(self
.m
, maxslen
))
497 class Trigger(Elaboratable
):
500 self
.stb
= Signal(reset
=0)
502 self
.trigger
= Signal(reset_less
=True)
504 def elaborate(self
, platform
):
506 m
.d
.comb
+= self
.trigger
.eq(self
.stb
& self
.ack
)
510 return [self
.stb
.eq(inp
.stb
),
515 return [self
.stb
, self
.ack
]
518 class FPOpIn(PrevControl
):
519 def __init__(self
, width
):
520 PrevControl
.__init
__(self
)
527 def chain_inv(self
, in_op
, extra
=None):
529 if extra
is not None:
531 return [self
.v
.eq(in_op
.v
), # receive value
532 self
.stb
.eq(stb
), # receive STB
533 in_op
.ack
.eq(~self
.ack
), # send ACK
536 def chain_from(self
, in_op
, extra
=None):
538 if extra
is not None:
540 return [self
.v
.eq(in_op
.v
), # receive value
541 self
.stb
.eq(stb
), # receive STB
542 in_op
.ack
.eq(self
.ack
), # send ACK
546 class FPOpOut(NextControl
):
547 def __init__(self
, width
):
548 NextControl
.__init
__(self
)
555 def chain_inv(self
, in_op
, extra
=None):
557 if extra
is not None:
559 return [self
.v
.eq(in_op
.v
), # receive value
560 self
.stb
.eq(stb
), # receive STB
561 in_op
.ack
.eq(~self
.ack
), # send ACK
564 def chain_from(self
, in_op
, extra
=None):
566 if extra
is not None:
568 return [self
.v
.eq(in_op
.v
), # receive value
569 self
.stb
.eq(stb
), # receive STB
570 in_op
.ack
.eq(self
.ack
), # send ACK
574 class Overflow
: #(Elaboratable):
576 self
.guard
= Signal(reset_less
=True) # tot[2]
577 self
.round_bit
= Signal(reset_less
=True) # tot[1]
578 self
.sticky
= Signal(reset_less
=True) # tot[0]
579 self
.m0
= Signal(reset_less
=True) # mantissa zero bit
581 #self.roundz = Signal(reset_less=True)
590 return [self
.guard
.eq(inp
.guard
),
591 self
.round_bit
.eq(inp
.round_bit
),
592 self
.sticky
.eq(inp
.sticky
),
597 return self
.guard
& (self
.round_bit | self
.sticky | self
.m0
)
601 """ IEEE754 Floating Point Base Class
603 contains common functions for FP manipulation, such as
604 extracting and packing operands, normalisation, denormalisation,
608 def get_op(self
, m
, op
, v
, next_state
):
609 """ this function moves to the next state and copies the operand
610 when both stb and ack are 1.
611 acknowledgement is sent by setting ack to ZERO.
615 with m
.If((op
.ready_o
) & (op
.valid_i_test
)):
617 # op is latched in from FPNumIn class on same ack/stb
618 m
.d
.comb
+= ack
.eq(0)
620 m
.d
.comb
+= ack
.eq(1)
623 def denormalise(self
, m
, a
):
624 """ denormalises a number. this is probably the wrong name for
625 this function. for normalised numbers (exponent != minimum)
626 one *extra* bit (the implicit 1) is added *back in*.
627 for denormalised numbers, the mantissa is left alone
628 and the exponent increased by 1.
630 both cases *effectively multiply the number stored by 2*,
631 which has to be taken into account when extracting the result.
633 with m
.If(a
.exp_n127
):
634 m
.d
.sync
+= a
.e
.eq(a
.fp
.N126
) # limit a exponent
636 m
.d
.sync
+= a
.m
[-1].eq(1) # set top mantissa bit
638 def op_normalise(self
, m
, op
, next_state
):
639 """ operand normalisation
640 NOTE: just like "align", this one keeps going round every clock
641 until the result's exponent is within acceptable "range"
643 with m
.If((op
.m
[-1] == 0)): # check last bit of mantissa
645 op
.e
.eq(op
.e
- 1), # DECREASE exponent
646 op
.m
.eq(op
.m
<< 1), # shift mantissa UP
651 def normalise_1(self
, m
, z
, of
, next_state
):
652 """ first stage normalisation
654 NOTE: just like "align", this one keeps going round every clock
655 until the result's exponent is within acceptable "range"
656 NOTE: the weirdness of reassigning guard and round is due to
657 the extra mantissa bits coming from tot[0..2]
659 with m
.If((z
.m
[-1] == 0) & (z
.e
> z
.fp
.N126
)):
661 z
.e
.eq(z
.e
- 1), # DECREASE exponent
662 z
.m
.eq(z
.m
<< 1), # shift mantissa UP
663 z
.m
[0].eq(of
.guard
), # steal guard bit (was tot[2])
664 of
.guard
.eq(of
.round_bit
), # steal round_bit (was tot[1])
665 of
.round_bit
.eq(0), # reset round bit
671 def normalise_2(self
, m
, z
, of
, next_state
):
672 """ second stage normalisation
674 NOTE: just like "align", this one keeps going round every clock
675 until the result's exponent is within acceptable "range"
676 NOTE: the weirdness of reassigning guard and round is due to
677 the extra mantissa bits coming from tot[0..2]
679 with m
.If(z
.e
< z
.fp
.N126
):
681 z
.e
.eq(z
.e
+ 1), # INCREASE exponent
682 z
.m
.eq(z
.m
>> 1), # shift mantissa DOWN
685 of
.round_bit
.eq(of
.guard
),
686 of
.sticky
.eq(of
.sticky | of
.round_bit
)
691 def roundz(self
, m
, z
, roundz
):
692 """ performs rounding on the output. TODO: different kinds of rounding
695 m
.d
.sync
+= z
.m
.eq(z
.m
+ 1) # mantissa rounds up
696 with m
.If(z
.m
== z
.fp
.m1s
): # all 1s
697 m
.d
.sync
+= z
.e
.eq(z
.e
+ 1) # exponent rounds up
699 def corrections(self
, m
, z
, next_state
):
700 """ denormalisation and sign-bug corrections
703 # denormalised, correct exponent to zero
704 with m
.If(z
.is_denormalised
):
705 m
.d
.sync
+= z
.e
.eq(z
.fp
.N127
)
707 def pack(self
, m
, z
, next_state
):
708 """ packs the result into the output (detects overflow->Inf)
711 # if overflow occurs, return inf
712 with m
.If(z
.is_overflowed
):
713 m
.d
.sync
+= z
.inf(z
.s
)
715 m
.d
.sync
+= z
.create(z
.s
, z
.e
, z
.m
)
717 def put_z(self
, m
, z
, out_z
, next_state
):
718 """ put_z: stores the result in the output. raises stb and waits
719 for ack to be set to 1 before moving to the next state.
720 resets stb back to zero when that occurs, as acknowledgement.
725 with m
.If(out_z
.valid_o
& out_z
.ready_i_test
):
726 m
.d
.sync
+= out_z
.valid_o
.eq(0)
729 m
.d
.sync
+= out_z
.valid_o
.eq(1)
732 class FPState(FPBase
):
733 def __init__(self
, state_from
):
734 self
.state_from
= state_from
736 def set_inputs(self
, inputs
):
738 for k
,v
in inputs
.items():
741 def set_outputs(self
, outputs
):
742 self
.outputs
= outputs
743 for k
,v
in outputs
.items():
748 def __init__(self
, id_wid
):
751 self
.in_mid
= Signal(id_wid
, reset_less
=True)
752 self
.out_mid
= Signal(id_wid
, reset_less
=True)
758 if self
.id_wid
is not None:
759 m
.d
.sync
+= self
.out_mid
.eq(self
.in_mid
)