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
):
49 zeros
= [0] * (1 << i
)
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
):
58 zeros
= [0] * (1 << i
)
59 res
= Mux(s
& (1 << i
), Cat(res
[(1 << i
):], zeros
), res
)
63 class FPNumBaseRecord
:
64 """ Floating-point Base Number Class
67 def __init__(self
, width
, m_extra
=True, e_extra
=False):
69 m_width
= {16: 11, 32: 24, 64: 53}[width
] # 1 extra bit (overflow)
70 e_width
= {16: 7, 32: 10, 64: 13}[width
] # 2 extra bits (overflow)
71 e_max
= 1 << (e_width
-3)
72 self
.rmw
= m_width
- 1 # real mantissa width (not including extras)
75 # mantissa extra bits (top,guard,round)
77 m_width
+= self
.m_extra
81 self
.e_extra
= 6 # enough to cover FP64 when converting to FP16
82 e_width
+= self
.e_extra
85 # print (m_width, e_width, e_max, self.rmw, self.m_extra)
86 self
.m_width
= m_width
87 self
.e_width
= e_width
88 self
.e_start
= self
.rmw
89 self
.e_end
= self
.rmw
+ self
.e_width
- 2 # for decoding
91 self
.v
= Signal(width
, reset_less
=True) # Latched copy of value
92 self
.m
= Signal(m_width
, reset_less
=True) # Mantissa
93 self
.e
= Signal((e_width
, True), reset_less
=True) # exp+2 bits, signed
94 self
.s
= Signal(reset_less
=True) # Sign bit
99 def drop_in(self
, fp
):
105 fp
.width
= self
.width
106 fp
.e_width
= self
.e_width
107 fp
.e_max
= self
.e_max
108 fp
.m_width
= self
.m_width
109 fp
.e_start
= self
.e_start
110 fp
.e_end
= self
.e_end
111 fp
.m_extra
= self
.m_extra
113 m_width
= self
.m_width
115 e_width
= self
.e_width
117 self
.mzero
= Const(0, (m_width
, False))
118 m_msb
= 1 << (self
.m_width
-2)
119 self
.msb1
= Const(m_msb
, (m_width
, False))
120 self
.m1s
= Const(-1, (m_width
, False))
121 self
.P128
= Const(e_max
, (e_width
, True))
122 self
.P127
= Const(e_max
-1, (e_width
, True))
123 self
.N127
= Const(-(e_max
-1), (e_width
, True))
124 self
.N126
= Const(-(e_max
-2), (e_width
, True))
126 def create(self
, s
, e
, m
):
127 """ creates a value from sign / exponent / mantissa
129 bias is added here, to the exponent.
131 NOTE: order is important, because e_start/e_end can be
132 a bit too long (overwriting s).
135 self
.v
[0:self
.e_start
].eq(m
), # mantissa
136 self
.v
[self
.e_start
:self
.e_end
].eq(e
+ self
.fp
.P127
), # (add bias)
137 self
.v
[-1].eq(s
), # sign
141 return (s
, self
.fp
.P128
, 1 << (self
.e_start
-1))
144 return (s
, self
.fp
.P128
, 0)
147 return (s
, self
.fp
.N127
, 0)
150 return self
.create(*self
._nan
(s
))
153 return self
.create(*self
._inf
(s
))
156 return self
.create(*self
._zero
(s
))
158 def create2(self
, s
, e
, m
):
159 """ creates a value from sign / exponent / mantissa
161 bias is added here, to the exponent
163 e
= e
+ self
.P127
# exp (add on bias)
164 return Cat(m
[0:self
.e_start
],
165 e
[0:self
.e_end
-self
.e_start
],
169 return self
.create2(s
, self
.P128
, self
.msb1
)
172 return self
.create2(s
, self
.P128
, self
.mzero
)
175 return self
.create2(s
, self
.N127
, self
.mzero
)
183 return [self
.s
.eq(inp
.s
), self
.e
.eq(inp
.e
), self
.m
.eq(inp
.m
)]
186 class FPNumBase(FPNumBaseRecord
, Elaboratable
):
187 """ Floating-point Base Number Class
190 def __init__(self
, fp
):
195 self
.is_nan
= Signal(reset_less
=True)
196 self
.is_zero
= Signal(reset_less
=True)
197 self
.is_inf
= Signal(reset_less
=True)
198 self
.is_overflowed
= Signal(reset_less
=True)
199 self
.is_denormalised
= Signal(reset_less
=True)
200 self
.exp_128
= Signal(reset_less
=True)
201 self
.exp_sub_n126
= Signal((e_width
, True), reset_less
=True)
202 self
.exp_lt_n126
= Signal(reset_less
=True)
203 self
.exp_gt_n126
= Signal(reset_less
=True)
204 self
.exp_gt127
= Signal(reset_less
=True)
205 self
.exp_n127
= Signal(reset_less
=True)
206 self
.exp_n126
= Signal(reset_less
=True)
207 self
.m_zero
= Signal(reset_less
=True)
208 self
.m_msbzero
= Signal(reset_less
=True)
210 def elaborate(self
, platform
):
212 m
.d
.comb
+= self
.is_nan
.eq(self
._is
_nan
())
213 m
.d
.comb
+= self
.is_zero
.eq(self
._is
_zero
())
214 m
.d
.comb
+= self
.is_inf
.eq(self
._is
_inf
())
215 m
.d
.comb
+= self
.is_overflowed
.eq(self
._is
_overflowed
())
216 m
.d
.comb
+= self
.is_denormalised
.eq(self
._is
_denormalised
())
217 m
.d
.comb
+= self
.exp_128
.eq(self
.e
== self
.fp
.P128
)
218 m
.d
.comb
+= self
.exp_sub_n126
.eq(self
.e
- self
.fp
.N126
)
219 m
.d
.comb
+= self
.exp_gt_n126
.eq(self
.exp_sub_n126
> 0)
220 m
.d
.comb
+= self
.exp_lt_n126
.eq(self
.exp_sub_n126
< 0)
221 m
.d
.comb
+= self
.exp_gt127
.eq(self
.e
> self
.fp
.P127
)
222 m
.d
.comb
+= self
.exp_n127
.eq(self
.e
== self
.fp
.N127
)
223 m
.d
.comb
+= self
.exp_n126
.eq(self
.e
== self
.fp
.N126
)
224 m
.d
.comb
+= self
.m_zero
.eq(self
.m
== self
.fp
.mzero
)
225 m
.d
.comb
+= self
.m_msbzero
.eq(self
.m
[self
.fp
.e_start
] == 0)
230 return (self
.exp_128
) & (~self
.m_zero
)
233 return (self
.exp_128
) & (self
.m_zero
)
236 return (self
.exp_n127
) & (self
.m_zero
)
238 def _is_overflowed(self
):
239 return self
.exp_gt127
241 def _is_denormalised(self
):
242 return (self
.exp_n126
) & (self
.m_msbzero
)
245 class FPNumOut(FPNumBase
):
246 """ Floating-point Number Class
248 Contains signals for an incoming copy of the value, decoded into
249 sign / exponent / mantissa.
250 Also contains encoding functions, creation and recognition of
251 zero, NaN and inf (all signed)
253 Four extra bits are included in the mantissa: the top bit
254 (m[-1]) is effectively a carry-overflow. The other three are
255 guard (m[2]), round (m[1]), and sticky (m[0])
258 def __init__(self
, fp
):
259 FPNumBase
.__init
__(self
, fp
)
261 def elaborate(self
, platform
):
262 m
= FPNumBase
.elaborate(self
, platform
)
267 class MultiShiftRMerge(Elaboratable
):
268 """ shifts down (right) and merges lower bits into m[0].
269 m[0] is the "sticky" bit, basically
272 def __init__(self
, width
, s_max
=None):
274 s_max
= int(log(width
) / log(2))
276 self
.m
= Signal(width
, reset_less
=True)
277 self
.inp
= Signal(width
, reset_less
=True)
278 self
.diff
= Signal(s_max
, reset_less
=True)
281 def elaborate(self
, platform
):
284 rs
= Signal(self
.width
, reset_less
=True)
285 m_mask
= Signal(self
.width
, reset_less
=True)
286 smask
= Signal(self
.width
, reset_less
=True)
287 stickybit
= Signal(reset_less
=True)
288 maxslen
= Signal(self
.smax
, reset_less
=True)
289 maxsleni
= Signal(self
.smax
, reset_less
=True)
291 sm
= MultiShift(self
.width
-1)
292 m0s
= Const(0, self
.width
-1)
293 mw
= Const(self
.width
-1, len(self
.diff
))
294 m
.d
.comb
+= [maxslen
.eq(Mux(self
.diff
> mw
, mw
, self
.diff
)),
295 maxsleni
.eq(Mux(self
.diff
> mw
, 0, mw
-self
.diff
)),
299 # shift mantissa by maxslen, mask by inverse
300 rs
.eq(sm
.rshift(self
.inp
[1:], maxslen
)),
301 m_mask
.eq(sm
.rshift(~m0s
, maxsleni
)),
302 smask
.eq(self
.inp
[1:] & m_mask
),
303 # sticky bit combines all mask (and mantissa low bit)
304 stickybit
.eq(smask
.bool() | self
.inp
[0]),
305 # mantissa result contains m[0] already.
306 self
.m
.eq(Cat(stickybit
, rs
))
311 class FPNumShift(FPNumBase
, Elaboratable
):
312 """ Floating-point Number Class for shifting
315 def __init__(self
, mainm
, op
, inv
, width
, m_extra
=True):
316 FPNumBase
.__init
__(self
, width
, m_extra
)
317 self
.latch_in
= Signal()
322 def elaborate(self
, platform
):
323 m
= FPNumBase
.elaborate(self
, platform
)
325 m
.d
.comb
+= self
.s
.eq(op
.s
)
326 m
.d
.comb
+= self
.e
.eq(op
.e
)
327 m
.d
.comb
+= self
.m
.eq(op
.m
)
329 with self
.mainm
.State("align"):
330 with m
.If(self
.e
< self
.inv
.e
):
331 m
.d
.sync
+= self
.shift_down()
335 def shift_down(self
, inp
):
336 """ shifts a mantissa down by one. exponent is increased to compensate
338 accuracy is lost as a result in the mantissa however there are 3
339 guard bits (the latter of which is the "sticky" bit)
341 return [self
.e
.eq(inp
.e
+ 1),
342 self
.m
.eq(Cat(inp
.m
[0] | inp
.m
[1], inp
.m
[2:], 0))
345 def shift_down_multi(self
, diff
):
346 """ shifts a mantissa down. exponent is increased to compensate
348 accuracy is lost as a result in the mantissa however there are 3
349 guard bits (the latter of which is the "sticky" bit)
351 this code works by variable-shifting the mantissa by up to
352 its maximum bit-length: no point doing more (it'll still be
355 the sticky bit is computed by shifting a batch of 1s by
356 the same amount, which will introduce zeros. it's then
357 inverted and used as a mask to get the LSBs of the mantissa.
358 those are then |'d into the sticky bit.
360 sm
= MultiShift(self
.width
)
361 mw
= Const(self
.m_width
-1, len(diff
))
362 maxslen
= Mux(diff
> mw
, mw
, diff
)
363 rs
= sm
.rshift(self
.m
[1:], maxslen
)
364 maxsleni
= mw
- maxslen
365 m_mask
= sm
.rshift(self
.m1s
[1:], maxsleni
) # shift and invert
367 stickybits
= reduce(or_
, self
.m
[1:] & m_mask
) | self
.m
[0]
368 return [self
.e
.eq(self
.e
+ diff
),
369 self
.m
.eq(Cat(stickybits
, rs
))
372 def shift_up_multi(self
, diff
):
373 """ shifts a mantissa up. exponent is decreased to compensate
375 sm
= MultiShift(self
.width
)
376 mw
= Const(self
.m_width
, len(diff
))
377 maxslen
= Mux(diff
> mw
, mw
, diff
)
379 return [self
.e
.eq(self
.e
- diff
),
380 self
.m
.eq(sm
.lshift(self
.m
, maxslen
))
384 class FPNumDecode(FPNumBase
):
385 """ Floating-point Number Class
387 Contains signals for an incoming copy of the value, decoded into
388 sign / exponent / mantissa.
389 Also contains encoding functions, creation and recognition of
390 zero, NaN and inf (all signed)
392 Four extra bits are included in the mantissa: the top bit
393 (m[-1]) is effectively a carry-overflow. The other three are
394 guard (m[2]), round (m[1]), and sticky (m[0])
397 def __init__(self
, op
, fp
):
398 FPNumBase
.__init
__(self
, fp
)
401 def elaborate(self
, platform
):
402 m
= FPNumBase
.elaborate(self
, platform
)
404 m
.d
.comb
+= self
.decode(self
.v
)
409 """ decodes a latched value into sign / exponent / mantissa
411 bias is subtracted here, from the exponent. exponent
412 is extended to 10 bits so that subtract 127 is done on
415 args
= [0] * self
.m_extra
+ [v
[0:self
.e_start
]] # pad with extra zeros
416 #print ("decode", self.e_end)
417 return [self
.m
.eq(Cat(*args
)), # mantissa
418 self
.e
.eq(v
[self
.e_start
:self
.e_end
] - self
.fp
.P127
), # exp
419 self
.s
.eq(v
[-1]), # sign
423 class FPNumIn(FPNumBase
):
424 """ Floating-point Number Class
426 Contains signals for an incoming copy of the value, decoded into
427 sign / exponent / mantissa.
428 Also contains encoding functions, creation and recognition of
429 zero, NaN and inf (all signed)
431 Four extra bits are included in the mantissa: the top bit
432 (m[-1]) is effectively a carry-overflow. The other three are
433 guard (m[2]), round (m[1]), and sticky (m[0])
436 def __init__(self
, op
, fp
):
437 FPNumBase
.__init
__(self
, fp
)
438 self
.latch_in
= Signal()
441 def decode2(self
, m
):
442 """ decodes a latched value into sign / exponent / mantissa
444 bias is subtracted here, from the exponent. exponent
445 is extended to 10 bits so that subtract 127 is done on
449 args
= [0] * self
.m_extra
+ [v
[0:self
.e_start
]] # pad with extra zeros
450 #print ("decode", self.e_end)
451 res
= ObjectProxy(m
, pipemode
=False)
452 res
.m
= Cat(*args
) # mantissa
453 res
.e
= v
[self
.e_start
:self
.e_end
] - self
.fp
.P127
# exp
458 """ decodes a latched value into sign / exponent / mantissa
460 bias is subtracted here, from the exponent. exponent
461 is extended to 10 bits so that subtract 127 is done on
464 args
= [0] * self
.m_extra
+ [v
[0:self
.e_start
]] # pad with extra zeros
465 #print ("decode", self.e_end)
466 return [self
.m
.eq(Cat(*args
)), # mantissa
467 self
.e
.eq(v
[self
.e_start
:self
.e_end
] - self
.P127
), # exp
468 self
.s
.eq(v
[-1]), # sign
471 def shift_down(self
, inp
):
472 """ shifts a mantissa down by one. exponent is increased to compensate
474 accuracy is lost as a result in the mantissa however there are 3
475 guard bits (the latter of which is the "sticky" bit)
477 return [self
.e
.eq(inp
.e
+ 1),
478 self
.m
.eq(Cat(inp
.m
[0] | inp
.m
[1], inp
.m
[2:], 0))
481 def shift_down_multi(self
, diff
, inp
=None):
482 """ shifts a mantissa down. exponent is increased to compensate
484 accuracy is lost as a result in the mantissa however there are 3
485 guard bits (the latter of which is the "sticky" bit)
487 this code works by variable-shifting the mantissa by up to
488 its maximum bit-length: no point doing more (it'll still be
491 the sticky bit is computed by shifting a batch of 1s by
492 the same amount, which will introduce zeros. it's then
493 inverted and used as a mask to get the LSBs of the mantissa.
494 those are then |'d into the sticky bit.
498 sm
= MultiShift(self
.width
)
499 mw
= Const(self
.m_width
-1, len(diff
))
500 maxslen
= Mux(diff
> mw
, mw
, diff
)
501 rs
= sm
.rshift(inp
.m
[1:], maxslen
)
502 maxsleni
= mw
- maxslen
503 m_mask
= sm
.rshift(self
.m1s
[1:], maxsleni
) # shift and invert
505 #stickybit = reduce(or_, inp.m[1:] & m_mask) | inp.m[0]
506 stickybit
= (inp
.m
[1:] & m_mask
).bool() | inp
.m
[0]
507 return [self
.e
.eq(inp
.e
+ diff
),
508 self
.m
.eq(Cat(stickybit
, rs
))
511 def shift_up_multi(self
, diff
):
512 """ shifts a mantissa up. exponent is decreased to compensate
514 sm
= MultiShift(self
.width
)
515 mw
= Const(self
.m_width
, len(diff
))
516 maxslen
= Mux(diff
> mw
, mw
, diff
)
518 return [self
.e
.eq(self
.e
- diff
),
519 self
.m
.eq(sm
.lshift(self
.m
, maxslen
))
523 class Trigger(Elaboratable
):
526 self
.stb
= Signal(reset
=0)
528 self
.trigger
= Signal(reset_less
=True)
530 def elaborate(self
, platform
):
532 m
.d
.comb
+= self
.trigger
.eq(self
.stb
& self
.ack
)
536 return [self
.stb
.eq(inp
.stb
),
541 return [self
.stb
, self
.ack
]
544 class FPOpIn(PrevControl
):
545 def __init__(self
, width
):
546 PrevControl
.__init
__(self
)
553 def chain_inv(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
562 def chain_from(self
, in_op
, extra
=None):
564 if extra
is not None:
566 return [self
.v
.eq(in_op
.v
), # receive value
567 self
.stb
.eq(stb
), # receive STB
568 in_op
.ack
.eq(self
.ack
), # send ACK
572 class FPOpOut(NextControl
):
573 def __init__(self
, width
):
574 NextControl
.__init
__(self
)
581 def chain_inv(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
590 def chain_from(self
, in_op
, extra
=None):
592 if extra
is not None:
594 return [self
.v
.eq(in_op
.v
), # receive value
595 self
.stb
.eq(stb
), # receive STB
596 in_op
.ack
.eq(self
.ack
), # send ACK
600 class Overflow
: # (Elaboratable):
602 self
.guard
= Signal(reset_less
=True) # tot[2]
603 self
.round_bit
= Signal(reset_less
=True) # tot[1]
604 self
.sticky
= Signal(reset_less
=True) # tot[0]
605 self
.m0
= Signal(reset_less
=True) # mantissa zero bit
607 #self.roundz = Signal(reset_less=True)
616 return [self
.guard
.eq(inp
.guard
),
617 self
.round_bit
.eq(inp
.round_bit
),
618 self
.sticky
.eq(inp
.sticky
),
623 return self
.guard
& (self
.round_bit | self
.sticky | self
.m0
)
627 """ IEEE754 Floating Point Base Class
629 contains common functions for FP manipulation, such as
630 extracting and packing operands, normalisation, denormalisation,
634 def get_op(self
, m
, op
, v
, next_state
):
635 """ this function moves to the next state and copies the operand
636 when both stb and ack are 1.
637 acknowledgement is sent by setting ack to ZERO.
641 with m
.If((op
.ready_o
) & (op
.valid_i_test
)):
643 # op is latched in from FPNumIn class on same ack/stb
644 m
.d
.comb
+= ack
.eq(0)
646 m
.d
.comb
+= ack
.eq(1)
649 def denormalise(self
, m
, a
):
650 """ denormalises a number. this is probably the wrong name for
651 this function. for normalised numbers (exponent != minimum)
652 one *extra* bit (the implicit 1) is added *back in*.
653 for denormalised numbers, the mantissa is left alone
654 and the exponent increased by 1.
656 both cases *effectively multiply the number stored by 2*,
657 which has to be taken into account when extracting the result.
659 with m
.If(a
.exp_n127
):
660 m
.d
.sync
+= a
.e
.eq(a
.fp
.N126
) # limit a exponent
662 m
.d
.sync
+= a
.m
[-1].eq(1) # set top mantissa bit
664 def op_normalise(self
, m
, op
, next_state
):
665 """ operand normalisation
666 NOTE: just like "align", this one keeps going round every clock
667 until the result's exponent is within acceptable "range"
669 with m
.If((op
.m
[-1] == 0)): # check last bit of mantissa
671 op
.e
.eq(op
.e
- 1), # DECREASE exponent
672 op
.m
.eq(op
.m
<< 1), # shift mantissa UP
677 def normalise_1(self
, m
, z
, of
, next_state
):
678 """ first stage normalisation
680 NOTE: just like "align", this one keeps going round every clock
681 until the result's exponent is within acceptable "range"
682 NOTE: the weirdness of reassigning guard and round is due to
683 the extra mantissa bits coming from tot[0..2]
685 with m
.If((z
.m
[-1] == 0) & (z
.e
> z
.fp
.N126
)):
687 z
.e
.eq(z
.e
- 1), # DECREASE exponent
688 z
.m
.eq(z
.m
<< 1), # shift mantissa UP
689 z
.m
[0].eq(of
.guard
), # steal guard bit (was tot[2])
690 of
.guard
.eq(of
.round_bit
), # steal round_bit (was tot[1])
691 of
.round_bit
.eq(0), # reset round bit
697 def normalise_2(self
, m
, z
, of
, next_state
):
698 """ second stage normalisation
700 NOTE: just like "align", this one keeps going round every clock
701 until the result's exponent is within acceptable "range"
702 NOTE: the weirdness of reassigning guard and round is due to
703 the extra mantissa bits coming from tot[0..2]
705 with m
.If(z
.e
< z
.fp
.N126
):
707 z
.e
.eq(z
.e
+ 1), # INCREASE exponent
708 z
.m
.eq(z
.m
>> 1), # shift mantissa DOWN
711 of
.round_bit
.eq(of
.guard
),
712 of
.sticky
.eq(of
.sticky | of
.round_bit
)
717 def roundz(self
, m
, z
, roundz
):
718 """ performs rounding on the output. TODO: different kinds of rounding
721 m
.d
.sync
+= z
.m
.eq(z
.m
+ 1) # mantissa rounds up
722 with m
.If(z
.m
== z
.fp
.m1s
): # all 1s
723 m
.d
.sync
+= z
.e
.eq(z
.e
+ 1) # exponent rounds up
725 def corrections(self
, m
, z
, next_state
):
726 """ denormalisation and sign-bug corrections
729 # denormalised, correct exponent to zero
730 with m
.If(z
.is_denormalised
):
731 m
.d
.sync
+= z
.e
.eq(z
.fp
.N127
)
733 def pack(self
, m
, z
, next_state
):
734 """ packs the result into the output (detects overflow->Inf)
737 # if overflow occurs, return inf
738 with m
.If(z
.is_overflowed
):
739 m
.d
.sync
+= z
.inf(z
.s
)
741 m
.d
.sync
+= z
.create(z
.s
, z
.e
, z
.m
)
743 def put_z(self
, m
, z
, out_z
, next_state
):
744 """ put_z: stores the result in the output. raises stb and waits
745 for ack to be set to 1 before moving to the next state.
746 resets stb back to zero when that occurs, as acknowledgement.
751 with m
.If(out_z
.valid_o
& out_z
.ready_i_test
):
752 m
.d
.sync
+= out_z
.valid_o
.eq(0)
755 m
.d
.sync
+= out_z
.valid_o
.eq(1)
758 class FPState(FPBase
):
759 def __init__(self
, state_from
):
760 self
.state_from
= state_from
762 def set_inputs(self
, inputs
):
764 for k
, v
in inputs
.items():
767 def set_outputs(self
, outputs
):
768 self
.outputs
= outputs
769 for k
, v
in outputs
.items():
774 def __init__(self
, id_wid
):
777 self
.in_mid
= Signal(id_wid
, reset_less
=True)
778 self
.out_mid
= Signal(id_wid
, reset_less
=True)
784 if self
.id_wid
is not None:
785 m
.d
.sync
+= self
.out_mid
.eq(self
.in_mid
)