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
):
97 op
= getattr(ao
, p
.name
)
98 print ("arrayproxy - p", p
, p
.name
)
99 yield from self
.iterator2(op
, p
)
103 """ a helper class for iterating single-argument compound data structures.
106 def iterate(self
, i
):
107 """ iterate a compound structure recursively using yield
109 if not isinstance(i
, Sequence
):
112 #print ("iterate", ai)
113 if isinstance(ai
, Record
):
114 #print ("record", list(ai.layout))
115 yield from self
.record_iter(ai
)
116 elif isinstance(ai
, ArrayProxy
) and not isinstance(ai
, Value
):
117 yield from self
.array_iter(ai
)
121 def record_iter(self
, ai
):
122 for idx
, (field_name
, field_shape
, _
) in enumerate(ai
.layout
):
123 if isinstance(field_shape
, Layout
):
127 if hasattr(val
, field_name
): # check for attribute
128 val
= getattr(val
, field_name
)
130 val
= val
[field_name
] # dictionary-style specification
131 #print ("recidx", idx, field_name, field_shape, val)
132 yield from self
.iterate(val
)
134 def array_iter(self
, ai
):
136 yield from self
.iterate(p
)
140 """ makes signals equal: a helper routine which identifies if it is being
141 passed a list (or tuple) of objects, or signals, or Records, and calls
142 the objects' eq function.
145 for (ao
, ai
) in Visitor2().iterator2(o
, i
):
147 if not isinstance(rres
, Sequence
):
157 #print ("shape?", part)
164 """ flattens a compound structure recursively using Cat
166 from nmigen
.tools
import flatten
167 #res = list(flatten(i)) # works (as of nmigen commit f22106e5) HOWEVER...
168 res
= list(Visitor().iterate(i
)) # needed because input may be a sequence