2 This work is funded through NLnet under Grant 2019-02-012
8 from collections
.abc
import Iterable
9 from nmigen
import Mux
, Signal
, Cat
12 # XXX this already exists in nmigen._utils
13 # see https://bugs.libre-soc.org/show_bug.cgi?id=297
15 if isinstance(v
, Iterable
):
22 # tree reduction function. operates recursively.
23 def treereduce(tree
, op
, fn
=None):
24 """treereduce: apply a map-reduce to a list, reducing to a single item
26 this is *not* the same as "x = Signal(64) reduce(x, operator.add)",
27 which is a bit-wise reduction down to a single bit
29 it is "l = [Signal(w), ..., Signal(w)] reduce(l, operator.add)"
32 examples: OR-reduction of one member of a list of Records down to a
34 treereduce(tree, operator.or_, lambda x: getattr(x, "o_data"))
38 if not isinstance(tree
, list):
43 return op(fn(tree
[0]), fn(tree
[1]))
44 s
= len(tree
) // 2 # splitpoint
45 return op(treereduce(tree
[:s
], op
, fn
),
46 treereduce(tree
[s
:], op
, fn
))
48 # chooses assignment of 32 bit or full 64 bit depending on is_32bit
51 def eq32(is_32bit
, dest
, src
):
52 return [dest
[0:32].eq(src
[0:32]),
53 dest
[32:64].eq(Mux(is_32bit
, 0, src
[32:64]))]
56 # a wrapper function formerly in run_simulation that is still useful.
57 # Simulation.add_sync_process now only takes functions, it does not
58 # take generators. so passing in arguments is no longer possible.
59 # with this wrapper, the following is possible:
60 # sim.add_sync_process(wrap.dut(parallel_sender_number=0))
61 # sim.add_sync_process(wrap.dut(parallel_sender_number=1))
69 # a "rising edge" generator. can take signals of greater than width 1
71 def rising_edge(m
, sig
):
72 delay
= Signal
.like(sig
)
73 rising
= Signal
.like(sig
)
74 delay
.name
= "%s_dly" % sig
.name
75 rising
.name
= "%s_rise" % sig
.name
76 m
.d
.sync
+= delay
.eq(sig
) # 1 clock delay
77 m
.d
.comb
+= rising
.eq(sig
& ~delay
) # sig is hi but delay-sig is lo
81 # Display function (dummy if non-existent)
82 # added as a patch from jeanthom
83 # https://gist.githubusercontent.com/jeanthom/
84 # f97f5b928720d4adda9d295e8a5bc078/
85 # raw/694274e0aceec993c0fc127e296b1a85b93c1b89/nmigen-display.diff
87 from nmigen
.hdl
.ast
import Display
93 def sel(m
, r
, sel_bits
, field_width
=None, name
=None, src_loc_at
=0):
94 """Forms a subfield from a selection of bits of the signal `r`
97 :param m: nMigen Module for adding the wires
98 :param r: signal containing the field from which to select the subfield
99 :param sel_bits: bit indices of the subfield, in "MSB 0" convention,
100 from most significant to least significant. Note that
101 the indices are allowed to be non-contiguous and/or
103 :param field_width: field width. If absent, use the signal `r` own width.
104 :param name: name of the generated Signal
105 :param src_loc_at: in the absence of `name`, stack level in which
108 :returns: a new Signal which gets assigned to the subfield
110 # find the MSB index in LSB0 numbering
111 if field_width
is None:
114 msb
= field_width
- 1
115 # extract the selected bits
118 sig_list
.append(r
[msb
- idx
])
119 # place the LSB at the front of the list,
120 # since, in nMigen, Cat starts from the LSB
122 sel_ret
= Signal(len(sig_list
), name
=name
, src_loc_at
=src_loc_at
+1)
123 m
.d
.comb
+= sel_ret
.eq(Cat(*sig_list
))