1 """ nmigen operator functions / utils
6 a strategically very important function that is identical in function
7 to nmigen's Signal.eq function, except it may take objects, or a list
8 of objects, or a tuple of objects, and where objects may also be
12 from nmigen
import Signal
, Cat
, Const
, Mux
, Module
, Value
, Elaboratable
13 from nmigen
.cli
import verilog
, rtlil
14 from nmigen
.lib
.fifo
import SyncFIFO
, SyncFIFOBuffered
15 from nmigen
.hdl
.ast
import ArrayProxy
16 from nmigen
.hdl
.rec
import Record
, Layout
18 from abc
import ABCMeta
, abstractmethod
19 from collections
.abc
import Sequence
, Iterable
20 from collections
import OrderedDict
21 from nmutil
.queue
import Queue
26 """ a helper class for iterating twin-argument compound data structures.
28 Record is a special (unusual, recursive) case, where the input may be
29 specified as a dictionary (which may contain further dictionaries,
30 recursively), where the field names of the dictionary must match
31 the Record's field spec. Alternatively, an object with the same
32 member names as the Record may be assigned: it does not have to
35 ArrayProxy is also special-cased, it's a bit messy: whilst ArrayProxy
36 has an eq function, the object being assigned to it (e.g. a python
37 object) might not. despite the *input* having an eq function,
38 that doesn't help us, because it's the *ArrayProxy* that's being
39 assigned to. so.... we cheat. use the ports() function of the
40 python object, enumerate them, find out the list of Signals that way,
43 def iterator2(self
, o
, i
):
44 if isinstance(o
, dict):
45 yield from self
.dict_iter2(o
, i
)
47 if not isinstance(o
, Sequence
):
49 for (ao
, ai
) in zip(o
, i
):
50 #print ("visit", fn, ao, ai)
51 if isinstance(ao
, Record
):
52 yield from self
.record_iter2(ao
, ai
)
53 elif isinstance(ao
, ArrayProxy
) and not isinstance(ai
, Value
):
54 yield from self
.arrayproxy_iter2(ao
, ai
)
58 def dict_iter2(self
, o
, i
):
59 for (k
, v
) in o
.items():
60 print ("d-iter", v
, i
[k
])
64 def _not_quite_working_with_all_unit_tests_record_iter2(self
, ao
, ai
):
65 print ("record_iter2", ao
, ai
, type(ao
), type(ai
))
66 if isinstance(ai
, Value
):
67 if isinstance(ao
, Sequence
):
69 for o
, i
in zip(ao
, ai
):
72 for idx
, (field_name
, field_shape
, _
) in enumerate(ao
.layout
):
73 if isinstance(field_shape
, Layout
):
77 if hasattr(val
, field_name
): # check for attribute
78 val
= getattr(val
, field_name
)
80 val
= val
[field_name
] # dictionary-style specification
81 yield from self
.iterator2(ao
.fields
[field_name
], val
)
83 def record_iter2(self
, ao
, ai
):
84 for idx
, (field_name
, field_shape
, _
) in enumerate(ao
.layout
):
85 if isinstance(field_shape
, Layout
):
89 if hasattr(val
, field_name
): # check for attribute
90 val
= getattr(val
, field_name
)
92 val
= val
[field_name
] # dictionary-style specification
93 yield from self
.iterator2(ao
.fields
[field_name
], val
)
95 def arrayproxy_iter2(self
, ao
, ai
):
96 #print ("arrayproxy_iter2", ai.ports(), ai, ao)
98 #print ("arrayproxy - p", p, p.name, ao)
99 op
= getattr(ao
, p
.name
)
100 yield from self
.iterator2(op
, p
)
104 """ a helper class for iterating single-argument compound data structures.
107 def iterate(self
, i
):
108 """ iterate a compound structure recursively using yield
110 if not isinstance(i
, Sequence
):
113 #print ("iterate", ai)
114 if isinstance(ai
, Record
):
115 #print ("record", list(ai.layout))
116 yield from self
.record_iter(ai
)
117 elif isinstance(ai
, ArrayProxy
) and not isinstance(ai
, Value
):
118 yield from self
.array_iter(ai
)
122 def record_iter(self
, ai
):
123 for idx
, (field_name
, field_shape
, _
) in enumerate(ai
.layout
):
124 if isinstance(field_shape
, Layout
):
128 if hasattr(val
, field_name
): # check for attribute
129 val
= getattr(val
, field_name
)
131 val
= val
[field_name
] # dictionary-style specification
132 #print ("recidx", idx, field_name, field_shape, val)
133 yield from self
.iterate(val
)
135 def array_iter(self
, ai
):
137 yield from self
.iterate(p
)
141 """ makes signals equal: a helper routine which identifies if it is being
142 passed a list (or tuple) of objects, or signals, or Records, and calls
143 the objects' eq function.
146 for (ao
, ai
) in Visitor2().iterator2(o
, i
):
148 if not isinstance(rres
, Sequence
):
158 #print ("shape?", part)
165 """ flattens a compound structure recursively using Cat
167 from nmigen
.tools
import flatten
168 #res = list(flatten(i)) # works (as of nmigen commit f22106e5) HOWEVER...
169 res
= list(Visitor().iterate(i
)) # needed because input may be a sequence