move eq, shape and cat to nmoperator.py
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 27 Apr 2019 14:56:55 +0000 (15:56 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 27 Apr 2019 14:56:55 +0000 (15:56 +0100)
src/add/nmoperator.py [new file with mode: 0644]
src/add/singlepipe.py

diff --git a/src/add/nmoperator.py b/src/add/nmoperator.py
new file mode 100644 (file)
index 0000000..bd5e554
--- /dev/null
@@ -0,0 +1,171 @@
+""" nmigen operator functions / utils
+
+    eq:
+    --
+
+    a strategically very important function that is identical in function
+    to nmigen's Signal.eq function, except it may take objects, or a list
+    of objects, or a tuple of objects, and where objects may also be
+    Records.
+"""
+
+from nmigen import Signal, Cat, Const, Mux, Module, Value, Elaboratable
+from nmigen.cli import verilog, rtlil
+from nmigen.lib.fifo import SyncFIFO, SyncFIFOBuffered
+from nmigen.hdl.ast import ArrayProxy
+from nmigen.hdl.rec import Record, Layout
+
+from abc import ABCMeta, abstractmethod
+from collections.abc import Sequence, Iterable
+from collections import OrderedDict
+from queue import Queue
+import inspect
+
+
+class Visitor2:
+    """ a helper class for iterating twin-argument compound data structures.
+
+        Record is a special (unusual, recursive) case, where the input may be
+        specified as a dictionary (which may contain further dictionaries,
+        recursively), where the field names of the dictionary must match
+        the Record's field spec.  Alternatively, an object with the same
+        member names as the Record may be assigned: it does not have to
+        *be* a Record.
+
+        ArrayProxy is also special-cased, it's a bit messy: whilst ArrayProxy
+        has an eq function, the object being assigned to it (e.g. a python
+        object) might not.  despite the *input* having an eq function,
+        that doesn't help us, because it's the *ArrayProxy* that's being
+        assigned to.  so.... we cheat.  use the ports() function of the
+        python object, enumerate them, find out the list of Signals that way,
+        and assign them.
+    """
+    def iterator2(self, o, i):
+        if isinstance(o, dict):
+            yield from self.dict_iter2(o, i)
+
+        if not isinstance(o, Sequence):
+            o, i = [o], [i]
+        for (ao, ai) in zip(o, i):
+            #print ("visit", fn, ao, ai)
+            if isinstance(ao, Record):
+                yield from self.record_iter2(ao, ai)
+            elif isinstance(ao, ArrayProxy) and not isinstance(ai, Value):
+                yield from self.arrayproxy_iter2(ao, ai)
+            else:
+                yield (ao, ai)
+
+    def dict_iter2(self, o, i):
+        for (k, v) in o.items():
+            print ("d-iter", v, i[k])
+            yield (v, i[k])
+        return res
+
+    def _not_quite_working_with_all_unit_tests_record_iter2(self, ao, ai):
+        print ("record_iter2", ao, ai, type(ao), type(ai))
+        if isinstance(ai, Value):
+            if isinstance(ao, Sequence):
+                ao, ai = [ao], [ai]
+            for o, i in zip(ao, ai):
+                yield (o, i)
+            return
+        for idx, (field_name, field_shape, _) in enumerate(ao.layout):
+            if isinstance(field_shape, Layout):
+                val = ai.fields
+            else:
+                val = ai
+            if hasattr(val, field_name): # check for attribute
+                val = getattr(val, field_name)
+            else:
+                val = val[field_name] # dictionary-style specification
+            yield from self.iterator2(ao.fields[field_name], val)
+
+    def record_iter2(self, ao, ai):
+        for idx, (field_name, field_shape, _) in enumerate(ao.layout):
+            if isinstance(field_shape, Layout):
+                val = ai.fields
+            else:
+                val = ai
+            if hasattr(val, field_name): # check for attribute
+                val = getattr(val, field_name)
+            else:
+                val = val[field_name] # dictionary-style specification
+            yield from self.iterator2(ao.fields[field_name], val)
+
+    def arrayproxy_iter2(self, ao, ai):
+        for p in ai.ports():
+            op = getattr(ao, p.name)
+            print ("arrayproxy - p", p, p.name)
+            yield from self.iterator2(op, p)
+
+
+class Visitor:
+    """ a helper class for iterating single-argument compound data structures.
+        similar to Visitor2.
+    """
+    def iterate(self, i):
+        """ iterate a compound structure recursively using yield
+        """
+        if not isinstance(i, Sequence):
+            i = [i]
+        for ai in i:
+            #print ("iterate", ai)
+            if isinstance(ai, Record):
+                #print ("record", list(ai.layout))
+                yield from self.record_iter(ai)
+            elif isinstance(ai, ArrayProxy) and not isinstance(ai, Value):
+                yield from self.array_iter(ai)
+            else:
+                yield ai
+
+    def record_iter(self, ai):
+        for idx, (field_name, field_shape, _) in enumerate(ai.layout):
+            if isinstance(field_shape, Layout):
+                val = ai.fields
+            else:
+                val = ai
+            if hasattr(val, field_name): # check for attribute
+                val = getattr(val, field_name)
+            else:
+                val = val[field_name] # dictionary-style specification
+            #print ("recidx", idx, field_name, field_shape, val)
+            yield from self.iterate(val)
+
+    def array_iter(self, ai):
+        for p in ai.ports():
+            yield from self.iterate(p)
+
+
+def eq(o, i):
+    """ makes signals equal: a helper routine which identifies if it is being
+        passed a list (or tuple) of objects, or signals, or Records, and calls
+        the objects' eq function.
+    """
+    res = []
+    for (ao, ai) in Visitor2().iterator2(o, i):
+        rres = ao.eq(ai)
+        if not isinstance(rres, Sequence):
+            rres = [rres]
+        res += rres
+    return res
+
+
+def shape(i):
+    #print ("shape", i)
+    r = 0
+    for part in list(i):
+        #print ("shape?", part)
+        s, _ = part.shape()
+        r += s
+    return r, False
+
+
+def cat(i):
+    """ flattens a compound structure recursively using Cat
+    """
+    from nmigen.tools import flatten
+    #res = list(flatten(i)) # works (as of nmigen commit f22106e5) HOWEVER...
+    res = list(Visitor().iterate(i)) # needed because input may be a sequence
+    return Cat(*res)
+
+
index 6ee0bb96a2130cb704f4152bba041d78075871f2..be7fce7ce0ce5806da9e8c2797ab3b042db4dd64 100644 (file)
@@ -180,6 +180,8 @@ from collections import OrderedDict
 from queue import Queue
 import inspect
 
+from nmoperator import eq, cat, shape
+
 
 class Object:
     def __init__(self):
@@ -403,153 +405,6 @@ class NextControl(Elaboratable):
         return list(self)
 
 
-class Visitor2:
-    """ a helper class for iterating twin-argument compound data structures.
-
-        Record is a special (unusual, recursive) case, where the input may be
-        specified as a dictionary (which may contain further dictionaries,
-        recursively), where the field names of the dictionary must match
-        the Record's field spec.  Alternatively, an object with the same
-        member names as the Record may be assigned: it does not have to
-        *be* a Record.
-
-        ArrayProxy is also special-cased, it's a bit messy: whilst ArrayProxy
-        has an eq function, the object being assigned to it (e.g. a python
-        object) might not.  despite the *input* having an eq function,
-        that doesn't help us, because it's the *ArrayProxy* that's being
-        assigned to.  so.... we cheat.  use the ports() function of the
-        python object, enumerate them, find out the list of Signals that way,
-        and assign them.
-    """
-    def iterator2(self, o, i):
-        if isinstance(o, dict):
-            yield from self.dict_iter2(o, i)
-
-        if not isinstance(o, Sequence):
-            o, i = [o], [i]
-        for (ao, ai) in zip(o, i):
-            #print ("visit", fn, ao, ai)
-            if isinstance(ao, Record):
-                yield from self.record_iter2(ao, ai)
-            elif isinstance(ao, ArrayProxy) and not isinstance(ai, Value):
-                yield from self.arrayproxy_iter2(ao, ai)
-            else:
-                yield (ao, ai)
-
-    def dict_iter2(self, o, i):
-        for (k, v) in o.items():
-            print ("d-iter", v, i[k])
-            yield (v, i[k])
-        return res
-
-    def _not_quite_working_with_all_unit_tests_record_iter2(self, ao, ai):
-        print ("record_iter2", ao, ai, type(ao), type(ai))
-        if isinstance(ai, Value):
-            if isinstance(ao, Sequence):
-                ao, ai = [ao], [ai]
-            for o, i in zip(ao, ai):
-                yield (o, i)
-            return
-        for idx, (field_name, field_shape, _) in enumerate(ao.layout):
-            if isinstance(field_shape, Layout):
-                val = ai.fields
-            else:
-                val = ai
-            if hasattr(val, field_name): # check for attribute
-                val = getattr(val, field_name)
-            else:
-                val = val[field_name] # dictionary-style specification
-            yield from self.iterator2(ao.fields[field_name], val)
-
-    def record_iter2(self, ao, ai):
-        for idx, (field_name, field_shape, _) in enumerate(ao.layout):
-            if isinstance(field_shape, Layout):
-                val = ai.fields
-            else:
-                val = ai
-            if hasattr(val, field_name): # check for attribute
-                val = getattr(val, field_name)
-            else:
-                val = val[field_name] # dictionary-style specification
-            yield from self.iterator2(ao.fields[field_name], val)
-
-    def arrayproxy_iter2(self, ao, ai):
-        for p in ai.ports():
-            op = getattr(ao, p.name)
-            print ("arrayproxy - p", p, p.name)
-            yield from self.iterator2(op, p)
-
-
-class Visitor:
-    """ a helper class for iterating single-argument compound data structures.
-        similar to Visitor2.
-    """
-    def iterate(self, i):
-        """ iterate a compound structure recursively using yield
-        """
-        if not isinstance(i, Sequence):
-            i = [i]
-        for ai in i:
-            #print ("iterate", ai)
-            if isinstance(ai, Record):
-                #print ("record", list(ai.layout))
-                yield from self.record_iter(ai)
-            elif isinstance(ai, ArrayProxy) and not isinstance(ai, Value):
-                yield from self.array_iter(ai)
-            else:
-                yield ai
-
-    def record_iter(self, ai):
-        for idx, (field_name, field_shape, _) in enumerate(ai.layout):
-            if isinstance(field_shape, Layout):
-                val = ai.fields
-            else:
-                val = ai
-            if hasattr(val, field_name): # check for attribute
-                val = getattr(val, field_name)
-            else:
-                val = val[field_name] # dictionary-style specification
-            #print ("recidx", idx, field_name, field_shape, val)
-            yield from self.iterate(val)
-
-    def array_iter(self, ai):
-        for p in ai.ports():
-            yield from self.iterate(p)
-
-
-def eq(o, i):
-    """ makes signals equal: a helper routine which identifies if it is being
-        passed a list (or tuple) of objects, or signals, or Records, and calls
-        the objects' eq function.
-    """
-    res = []
-    for (ao, ai) in Visitor2().iterator2(o, i):
-        rres = ao.eq(ai)
-        if not isinstance(rres, Sequence):
-            rres = [rres]
-        res += rres
-    return res
-
-
-def shape(i):
-    #print ("shape", i)
-    r = 0
-    for part in list(i):
-        #print ("shape?", part)
-        s, _ = part.shape()
-        r += s
-    return r, False
-
-
-def cat(i):
-    """ flattens a compound structure recursively using Cat
-    """
-    from nmigen.tools import flatten
-    #res = list(flatten(i)) # works (as of nmigen commit f22106e5) HOWEVER...
-    res = list(Visitor().iterate(i)) # needed because input may be a sequence
-    return Cat(*res)
-
-
 class StageCls(metaclass=ABCMeta):
     """ Class-based "Stage" API.  requires instantiation (after derivation)