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, e_extra
=False):
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
- 1 # real mantissa width (not including extras)
74 # mantissa extra bits (top,guard,round)
76 m_width
+= self
.m_extra
80 self
.e_extra
= 6 # enough to cover FP64 when converting to FP16
81 e_width
+= self
.e_extra
84 #print (m_width, e_width, e_max, self.rmw, self.m_extra)
85 self
.m_width
= m_width
86 self
.e_width
= e_width
87 self
.e_start
= self
.rmw
88 self
.e_end
= self
.rmw
+ self
.e_width
- 2 # for decoding
90 self
.v
= Signal(width
, reset_less
=True) # Latched copy of value
91 self
.m
= Signal(m_width
, reset_less
=True) # Mantissa
92 self
.e
= Signal((e_width
, True), reset_less
=True) # exp+2 bits, signed
93 self
.s
= Signal(reset_less
=True) # Sign bit
98 def drop_in(self
, fp
):
104 fp
.width
= self
.width
105 fp
.e_width
= self
.e_width
106 fp
.e_max
= self
.e_max
107 fp
.m_width
= self
.m_width
108 fp
.e_start
= self
.e_start
109 fp
.e_end
= self
.e_end
110 fp
.m_extra
= self
.m_extra
112 m_width
= self
.m_width
114 e_width
= self
.e_width
116 self
.mzero
= Const(0, (m_width
, False))
117 m_msb
= 1<<(self
.m_width
-2)
118 self
.msb1
= Const(m_msb
, (m_width
, False))
119 self
.m1s
= Const(-1, (m_width
, False))
120 self
.P128
= Const(e_max
, (e_width
, True))
121 self
.P127
= Const(e_max
-1, (e_width
, True))
122 self
.N127
= Const(-(e_max
-1), (e_width
, True))
123 self
.N126
= Const(-(e_max
-2), (e_width
, True))
125 def create(self
, s
, e
, m
):
126 """ creates a value from sign / exponent / mantissa
128 bias is added here, to the exponent.
130 NOTE: order is important, because e_start/e_end can be
131 a bit too long (overwriting s).
134 self
.v
[0:self
.e_start
].eq(m
), # mantissa
135 self
.v
[self
.e_start
:self
.e_end
].eq(e
+ self
.fp
.P127
), # (add on bias)
136 self
.v
[-1].eq(s
), # sign
140 return (s
, self
.fp
.P128
, 1<<(self
.e_start
-1))
143 return (s
, self
.fp
.P128
, 0)
146 return (s
, self
.fp
.N127
, 0)
149 return self
.create(*self
._nan
(s
))
152 return self
.create(*self
._inf
(s
))
155 return self
.create(*self
._zero
(s
))
157 def create2(self
, s
, e
, m
):
158 """ creates a value from sign / exponent / mantissa
160 bias is added here, to the exponent
162 e
= e
+ self
.P127
# exp (add on bias)
163 return Cat(m
[0:self
.e_start
],
164 e
[0:self
.e_end
-self
.e_start
],
168 return self
.create2(s
, self
.P128
, self
.msb1
)
171 return self
.create2(s
, self
.P128
, self
.mzero
)
174 return self
.create2(s
, self
.N127
, self
.mzero
)
182 return [self
.s
.eq(inp
.s
), self
.e
.eq(inp
.e
), self
.m
.eq(inp
.m
)]
185 class FPNumBase(FPNumBaseRecord
, Elaboratable
):
186 """ Floating-point Base Number Class
188 def __init__(self
, fp
):
193 self
.is_nan
= Signal(reset_less
=True)
194 self
.is_zero
= Signal(reset_less
=True)
195 self
.is_inf
= Signal(reset_less
=True)
196 self
.is_overflowed
= Signal(reset_less
=True)
197 self
.is_denormalised
= Signal(reset_less
=True)
198 self
.exp_128
= Signal(reset_less
=True)
199 self
.exp_sub_n126
= Signal((e_width
, True), reset_less
=True)
200 self
.exp_lt_n126
= Signal(reset_less
=True)
201 self
.exp_gt_n126
= Signal(reset_less
=True)
202 self
.exp_gt127
= Signal(reset_less
=True)
203 self
.exp_n127
= Signal(reset_less
=True)
204 self
.exp_n126
= Signal(reset_less
=True)
205 self
.m_zero
= Signal(reset_less
=True)
206 self
.m_msbzero
= Signal(reset_less
=True)
208 def elaborate(self
, platform
):
210 m
.d
.comb
+= self
.is_nan
.eq(self
._is
_nan
())
211 m
.d
.comb
+= self
.is_zero
.eq(self
._is
_zero
())
212 m
.d
.comb
+= self
.is_inf
.eq(self
._is
_inf
())
213 m
.d
.comb
+= self
.is_overflowed
.eq(self
._is
_overflowed
())
214 m
.d
.comb
+= self
.is_denormalised
.eq(self
._is
_denormalised
())
215 m
.d
.comb
+= self
.exp_128
.eq(self
.e
== self
.fp
.P128
)
216 m
.d
.comb
+= self
.exp_sub_n126
.eq(self
.e
- self
.fp
.N126
)
217 m
.d
.comb
+= self
.exp_gt_n126
.eq(self
.exp_sub_n126
> 0)
218 m
.d
.comb
+= self
.exp_lt_n126
.eq(self
.exp_sub_n126
< 0)
219 m
.d
.comb
+= self
.exp_gt127
.eq(self
.e
> self
.fp
.P127
)
220 m
.d
.comb
+= self
.exp_n127
.eq(self
.e
== self
.fp
.N127
)
221 m
.d
.comb
+= self
.exp_n126
.eq(self
.e
== self
.fp
.N126
)
222 m
.d
.comb
+= self
.m_zero
.eq(self
.m
== self
.fp
.mzero
)
223 m
.d
.comb
+= self
.m_msbzero
.eq(self
.m
[self
.fp
.e_start
] == 0)
228 return (self
.exp_128
) & (~self
.m_zero
)
231 return (self
.exp_128
) & (self
.m_zero
)
234 return (self
.exp_n127
) & (self
.m_zero
)
236 def _is_overflowed(self
):
237 return self
.exp_gt127
239 def _is_denormalised(self
):
240 return (self
.exp_n126
) & (self
.m_msbzero
)
243 class FPNumOut(FPNumBase
):
244 """ Floating-point Number Class
246 Contains signals for an incoming copy of the value, decoded into
247 sign / exponent / mantissa.
248 Also contains encoding functions, creation and recognition of
249 zero, NaN and inf (all signed)
251 Four extra bits are included in the mantissa: the top bit
252 (m[-1]) is effectively a carry-overflow. The other three are
253 guard (m[2]), round (m[1]), and sticky (m[0])
255 def __init__(self
, fp
):
256 FPNumBase
.__init
__(self
, fp
)
258 def elaborate(self
, platform
):
259 m
= FPNumBase
.elaborate(self
, platform
)
264 class MultiShiftRMerge(Elaboratable
):
265 """ shifts down (right) and merges lower bits into m[0].
266 m[0] is the "sticky" bit, basically
268 def __init__(self
, width
, s_max
=None):
270 s_max
= int(log(width
) / log(2))
272 self
.m
= Signal(width
, reset_less
=True)
273 self
.inp
= Signal(width
, reset_less
=True)
274 self
.diff
= Signal(s_max
, reset_less
=True)
277 def elaborate(self
, platform
):
280 rs
= Signal(self
.width
, reset_less
=True)
281 m_mask
= Signal(self
.width
, reset_less
=True)
282 smask
= Signal(self
.width
, reset_less
=True)
283 stickybit
= Signal(reset_less
=True)
284 maxslen
= Signal(self
.smax
, reset_less
=True)
285 maxsleni
= Signal(self
.smax
, reset_less
=True)
287 sm
= MultiShift(self
.width
-1)
288 m0s
= Const(0, self
.width
-1)
289 mw
= Const(self
.width
-1, len(self
.diff
))
290 m
.d
.comb
+= [maxslen
.eq(Mux(self
.diff
> mw
, mw
, self
.diff
)),
291 maxsleni
.eq(Mux(self
.diff
> mw
, 0, mw
-self
.diff
)),
295 # shift mantissa by maxslen, mask by inverse
296 rs
.eq(sm
.rshift(self
.inp
[1:], maxslen
)),
297 m_mask
.eq(sm
.rshift(~m0s
, maxsleni
)),
298 smask
.eq(self
.inp
[1:] & m_mask
),
299 # sticky bit combines all mask (and mantissa low bit)
300 stickybit
.eq(smask
.bool() | self
.inp
[0]),
301 # mantissa result contains m[0] already.
302 self
.m
.eq(Cat(stickybit
, rs
))
307 class FPNumShift(FPNumBase
, Elaboratable
):
308 """ Floating-point Number Class for shifting
310 def __init__(self
, mainm
, op
, inv
, width
, m_extra
=True):
311 FPNumBase
.__init
__(self
, width
, m_extra
)
312 self
.latch_in
= Signal()
317 def elaborate(self
, platform
):
318 m
= FPNumBase
.elaborate(self
, platform
)
320 m
.d
.comb
+= self
.s
.eq(op
.s
)
321 m
.d
.comb
+= self
.e
.eq(op
.e
)
322 m
.d
.comb
+= self
.m
.eq(op
.m
)
324 with self
.mainm
.State("align"):
325 with m
.If(self
.e
< self
.inv
.e
):
326 m
.d
.sync
+= self
.shift_down()
330 def shift_down(self
, inp
):
331 """ shifts a mantissa down by one. exponent is increased to compensate
333 accuracy is lost as a result in the mantissa however there are 3
334 guard bits (the latter of which is the "sticky" bit)
336 return [self
.e
.eq(inp
.e
+ 1),
337 self
.m
.eq(Cat(inp
.m
[0] | inp
.m
[1], inp
.m
[2:], 0))
340 def shift_down_multi(self
, diff
):
341 """ shifts a mantissa down. exponent is increased to compensate
343 accuracy is lost as a result in the mantissa however there are 3
344 guard bits (the latter of which is the "sticky" bit)
346 this code works by variable-shifting the mantissa by up to
347 its maximum bit-length: no point doing more (it'll still be
350 the sticky bit is computed by shifting a batch of 1s by
351 the same amount, which will introduce zeros. it's then
352 inverted and used as a mask to get the LSBs of the mantissa.
353 those are then |'d into the sticky bit.
355 sm
= MultiShift(self
.width
)
356 mw
= Const(self
.m_width
-1, len(diff
))
357 maxslen
= Mux(diff
> mw
, mw
, diff
)
358 rs
= sm
.rshift(self
.m
[1:], maxslen
)
359 maxsleni
= mw
- maxslen
360 m_mask
= sm
.rshift(self
.m1s
[1:], maxsleni
) # shift and invert
362 stickybits
= reduce(or_
, self
.m
[1:] & m_mask
) | self
.m
[0]
363 return [self
.e
.eq(self
.e
+ diff
),
364 self
.m
.eq(Cat(stickybits
, rs
))
367 def shift_up_multi(self
, diff
):
368 """ shifts a mantissa up. exponent is decreased to compensate
370 sm
= MultiShift(self
.width
)
371 mw
= Const(self
.m_width
, len(diff
))
372 maxslen
= Mux(diff
> mw
, mw
, diff
)
374 return [self
.e
.eq(self
.e
- diff
),
375 self
.m
.eq(sm
.lshift(self
.m
, maxslen
))
379 class FPNumDecode(FPNumBase
):
380 """ Floating-point Number Class
382 Contains signals for an incoming copy of the value, decoded into
383 sign / exponent / mantissa.
384 Also contains encoding functions, creation and recognition of
385 zero, NaN and inf (all signed)
387 Four extra bits are included in the mantissa: the top bit
388 (m[-1]) is effectively a carry-overflow. The other three are
389 guard (m[2]), round (m[1]), and sticky (m[0])
391 def __init__(self
, op
, fp
):
392 FPNumBase
.__init
__(self
, fp
)
395 def elaborate(self
, platform
):
396 m
= FPNumBase
.elaborate(self
, platform
)
398 m
.d
.comb
+= self
.decode(self
.v
)
403 """ decodes a latched value into sign / exponent / mantissa
405 bias is subtracted here, from the exponent. exponent
406 is extended to 10 bits so that subtract 127 is done on
409 args
= [0] * self
.m_extra
+ [v
[0:self
.e_start
]] # pad with extra zeros
410 #print ("decode", self.e_end)
411 return [self
.m
.eq(Cat(*args
)), # mantissa
412 self
.e
.eq(v
[self
.e_start
:self
.e_end
] - self
.fp
.P127
), # exp
413 self
.s
.eq(v
[-1]), # sign
416 class FPNumIn(FPNumBase
):
417 """ Floating-point Number Class
419 Contains signals for an incoming copy of the value, decoded into
420 sign / exponent / mantissa.
421 Also contains encoding functions, creation and recognition of
422 zero, NaN and inf (all signed)
424 Four extra bits are included in the mantissa: the top bit
425 (m[-1]) is effectively a carry-overflow. The other three are
426 guard (m[2]), round (m[1]), and sticky (m[0])
428 def __init__(self
, op
, fp
):
429 FPNumBase
.__init
__(self
, fp
)
430 self
.latch_in
= Signal()
433 def decode2(self
, m
):
434 """ decodes a latched value into sign / exponent / mantissa
436 bias is subtracted here, from the exponent. exponent
437 is extended to 10 bits so that subtract 127 is done on
441 args
= [0] * self
.m_extra
+ [v
[0:self
.e_start
]] # pad with extra zeros
442 #print ("decode", self.e_end)
443 res
= ObjectProxy(m
, pipemode
=False)
444 res
.m
= Cat(*args
) # mantissa
445 res
.e
= v
[self
.e_start
:self
.e_end
] - self
.fp
.P127
# exp
450 """ decodes a latched value into sign / exponent / mantissa
452 bias is subtracted here, from the exponent. exponent
453 is extended to 10 bits so that subtract 127 is done on
456 args
= [0] * self
.m_extra
+ [v
[0:self
.e_start
]] # pad with extra zeros
457 #print ("decode", self.e_end)
458 return [self
.m
.eq(Cat(*args
)), # mantissa
459 self
.e
.eq(v
[self
.e_start
:self
.e_end
] - self
.P127
), # exp
460 self
.s
.eq(v
[-1]), # sign
463 def shift_down(self
, inp
):
464 """ shifts a mantissa down by one. exponent is increased to compensate
466 accuracy is lost as a result in the mantissa however there are 3
467 guard bits (the latter of which is the "sticky" bit)
469 return [self
.e
.eq(inp
.e
+ 1),
470 self
.m
.eq(Cat(inp
.m
[0] | inp
.m
[1], inp
.m
[2:], 0))
473 def shift_down_multi(self
, diff
, inp
=None):
474 """ shifts a mantissa down. exponent is increased to compensate
476 accuracy is lost as a result in the mantissa however there are 3
477 guard bits (the latter of which is the "sticky" bit)
479 this code works by variable-shifting the mantissa by up to
480 its maximum bit-length: no point doing more (it'll still be
483 the sticky bit is computed by shifting a batch of 1s by
484 the same amount, which will introduce zeros. it's then
485 inverted and used as a mask to get the LSBs of the mantissa.
486 those are then |'d into the sticky bit.
490 sm
= MultiShift(self
.width
)
491 mw
= Const(self
.m_width
-1, len(diff
))
492 maxslen
= Mux(diff
> mw
, mw
, diff
)
493 rs
= sm
.rshift(inp
.m
[1:], maxslen
)
494 maxsleni
= mw
- maxslen
495 m_mask
= sm
.rshift(self
.m1s
[1:], maxsleni
) # shift and invert
497 #stickybit = reduce(or_, inp.m[1:] & m_mask) | inp.m[0]
498 stickybit
= (inp
.m
[1:] & m_mask
).bool() | inp
.m
[0]
499 return [self
.e
.eq(inp
.e
+ diff
),
500 self
.m
.eq(Cat(stickybit
, rs
))
503 def shift_up_multi(self
, diff
):
504 """ shifts a mantissa up. exponent is decreased to compensate
506 sm
= MultiShift(self
.width
)
507 mw
= Const(self
.m_width
, len(diff
))
508 maxslen
= Mux(diff
> mw
, mw
, diff
)
510 return [self
.e
.eq(self
.e
- diff
),
511 self
.m
.eq(sm
.lshift(self
.m
, maxslen
))
514 class Trigger(Elaboratable
):
517 self
.stb
= Signal(reset
=0)
519 self
.trigger
= Signal(reset_less
=True)
521 def elaborate(self
, platform
):
523 m
.d
.comb
+= self
.trigger
.eq(self
.stb
& self
.ack
)
527 return [self
.stb
.eq(inp
.stb
),
532 return [self
.stb
, self
.ack
]
535 class FPOpIn(PrevControl
):
536 def __init__(self
, width
):
537 PrevControl
.__init
__(self
)
544 def chain_inv(self
, in_op
, extra
=None):
546 if extra
is not None:
548 return [self
.v
.eq(in_op
.v
), # receive value
549 self
.stb
.eq(stb
), # receive STB
550 in_op
.ack
.eq(~self
.ack
), # send ACK
553 def chain_from(self
, in_op
, extra
=None):
555 if extra
is not None:
557 return [self
.v
.eq(in_op
.v
), # receive value
558 self
.stb
.eq(stb
), # receive STB
559 in_op
.ack
.eq(self
.ack
), # send ACK
563 class FPOpOut(NextControl
):
564 def __init__(self
, width
):
565 NextControl
.__init
__(self
)
572 def chain_inv(self
, in_op
, extra
=None):
574 if extra
is not None:
576 return [self
.v
.eq(in_op
.v
), # receive value
577 self
.stb
.eq(stb
), # receive STB
578 in_op
.ack
.eq(~self
.ack
), # send ACK
581 def chain_from(self
, in_op
, extra
=None):
583 if extra
is not None:
585 return [self
.v
.eq(in_op
.v
), # receive value
586 self
.stb
.eq(stb
), # receive STB
587 in_op
.ack
.eq(self
.ack
), # send ACK
591 class Overflow
: #(Elaboratable):
593 self
.guard
= Signal(reset_less
=True) # tot[2]
594 self
.round_bit
= Signal(reset_less
=True) # tot[1]
595 self
.sticky
= Signal(reset_less
=True) # tot[0]
596 self
.m0
= Signal(reset_less
=True) # mantissa zero bit
598 #self.roundz = Signal(reset_less=True)
607 return [self
.guard
.eq(inp
.guard
),
608 self
.round_bit
.eq(inp
.round_bit
),
609 self
.sticky
.eq(inp
.sticky
),
614 return self
.guard
& (self
.round_bit | self
.sticky | self
.m0
)
618 """ IEEE754 Floating Point Base Class
620 contains common functions for FP manipulation, such as
621 extracting and packing operands, normalisation, denormalisation,
625 def get_op(self
, m
, op
, v
, next_state
):
626 """ this function moves to the next state and copies the operand
627 when both stb and ack are 1.
628 acknowledgement is sent by setting ack to ZERO.
632 with m
.If((op
.ready_o
) & (op
.valid_i_test
)):
634 # op is latched in from FPNumIn class on same ack/stb
635 m
.d
.comb
+= ack
.eq(0)
637 m
.d
.comb
+= ack
.eq(1)
640 def denormalise(self
, m
, a
):
641 """ denormalises a number. this is probably the wrong name for
642 this function. for normalised numbers (exponent != minimum)
643 one *extra* bit (the implicit 1) is added *back in*.
644 for denormalised numbers, the mantissa is left alone
645 and the exponent increased by 1.
647 both cases *effectively multiply the number stored by 2*,
648 which has to be taken into account when extracting the result.
650 with m
.If(a
.exp_n127
):
651 m
.d
.sync
+= a
.e
.eq(a
.fp
.N126
) # limit a exponent
653 m
.d
.sync
+= a
.m
[-1].eq(1) # set top mantissa bit
655 def op_normalise(self
, m
, op
, next_state
):
656 """ operand normalisation
657 NOTE: just like "align", this one keeps going round every clock
658 until the result's exponent is within acceptable "range"
660 with m
.If((op
.m
[-1] == 0)): # check last bit of mantissa
662 op
.e
.eq(op
.e
- 1), # DECREASE exponent
663 op
.m
.eq(op
.m
<< 1), # shift mantissa UP
668 def normalise_1(self
, m
, z
, of
, next_state
):
669 """ first stage normalisation
671 NOTE: just like "align", this one keeps going round every clock
672 until the result's exponent is within acceptable "range"
673 NOTE: the weirdness of reassigning guard and round is due to
674 the extra mantissa bits coming from tot[0..2]
676 with m
.If((z
.m
[-1] == 0) & (z
.e
> z
.fp
.N126
)):
678 z
.e
.eq(z
.e
- 1), # DECREASE exponent
679 z
.m
.eq(z
.m
<< 1), # shift mantissa UP
680 z
.m
[0].eq(of
.guard
), # steal guard bit (was tot[2])
681 of
.guard
.eq(of
.round_bit
), # steal round_bit (was tot[1])
682 of
.round_bit
.eq(0), # reset round bit
688 def normalise_2(self
, m
, z
, of
, next_state
):
689 """ second stage normalisation
691 NOTE: just like "align", this one keeps going round every clock
692 until the result's exponent is within acceptable "range"
693 NOTE: the weirdness of reassigning guard and round is due to
694 the extra mantissa bits coming from tot[0..2]
696 with m
.If(z
.e
< z
.fp
.N126
):
698 z
.e
.eq(z
.e
+ 1), # INCREASE exponent
699 z
.m
.eq(z
.m
>> 1), # shift mantissa DOWN
702 of
.round_bit
.eq(of
.guard
),
703 of
.sticky
.eq(of
.sticky | of
.round_bit
)
708 def roundz(self
, m
, z
, roundz
):
709 """ performs rounding on the output. TODO: different kinds of rounding
712 m
.d
.sync
+= z
.m
.eq(z
.m
+ 1) # mantissa rounds up
713 with m
.If(z
.m
== z
.fp
.m1s
): # all 1s
714 m
.d
.sync
+= z
.e
.eq(z
.e
+ 1) # exponent rounds up
716 def corrections(self
, m
, z
, next_state
):
717 """ denormalisation and sign-bug corrections
720 # denormalised, correct exponent to zero
721 with m
.If(z
.is_denormalised
):
722 m
.d
.sync
+= z
.e
.eq(z
.fp
.N127
)
724 def pack(self
, m
, z
, next_state
):
725 """ packs the result into the output (detects overflow->Inf)
728 # if overflow occurs, return inf
729 with m
.If(z
.is_overflowed
):
730 m
.d
.sync
+= z
.inf(z
.s
)
732 m
.d
.sync
+= z
.create(z
.s
, z
.e
, z
.m
)
734 def put_z(self
, m
, z
, out_z
, next_state
):
735 """ put_z: stores the result in the output. raises stb and waits
736 for ack to be set to 1 before moving to the next state.
737 resets stb back to zero when that occurs, as acknowledgement.
742 with m
.If(out_z
.valid_o
& out_z
.ready_i_test
):
743 m
.d
.sync
+= out_z
.valid_o
.eq(0)
746 m
.d
.sync
+= out_z
.valid_o
.eq(1)
749 class FPState(FPBase
):
750 def __init__(self
, state_from
):
751 self
.state_from
= state_from
753 def set_inputs(self
, inputs
):
755 for k
,v
in inputs
.items():
758 def set_outputs(self
, outputs
):
759 self
.outputs
= outputs
760 for k
,v
in outputs
.items():
765 def __init__(self
, id_wid
):
768 self
.in_mid
= Signal(id_wid
, reset_less
=True)
769 self
.out_mid
= Signal(id_wid
, reset_less
=True)
775 if self
.id_wid
is not None:
776 m
.d
.sync
+= self
.out_mid
.eq(self
.in_mid
)