FINALLY, got ObjectProxy in pipeline auto-stage working
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Thu, 4 Apr 2019 03:28:33 +0000 (04:28 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Thu, 4 Apr 2019 03:28:33 +0000 (04:28 +0100)
src/add/pipeline.py
src/add/pipeline_example.py

index 1a85b85a851a95483e1608ae17b9c2d19232c1ae..59b6004df6e251ec6dbdc5863ee29f671d4c0834 100644 (file)
@@ -55,7 +55,7 @@ class ObjectProxy:
             name = tracer.get_var_name(default=None)
         self.name = name
         self._pipemode = pipemode
-        self._eqs = []
+        self._eqs = {}
         self._assigns = []
         self._preg_map = {}
 
@@ -154,27 +154,31 @@ class PipelineStage:
         self._preg_map = {'__nextstage__': {}}
         self._prev_stage = prev
         self._ispec = ispec
+        if ispec:
+            self._preg_map[self._stagename] = ispec
         if prev:
             print ("prev", prev._stagename, prev._preg_map)
-            if prev._stagename in prev._preg_map:
-                m = prev._preg_map[prev._stagename]
-                self._preg_map[prev._stagename] = m
-                #for k, v in m.items():
-                    #m[k] = like(v, k, self._m)
+            #if prev._stagename in prev._preg_map:
+            #    m = prev._preg_map[prev._stagename]
+            #    self._preg_map[prev._stagename] = m
             if '__nextstage__' in prev._preg_map:
                 m = prev._preg_map['__nextstage__']
+                m = likedict(m)
                 self._preg_map[self._stagename] = m
                 #for k, v in m.items():
                     #m[k] = like(v, k, self._m)
                 print ("make current", self._stagename, m)
         self._pipemode = pipemode
-        self._eqs = []
+        self._eqs = {}
         self._assigns = []
 
-    def __getattr__(self, name):
+    def __getattribute__(self, name):
+        if name.startswith('_'):
+            return object.__getattribute__(self, name)
         #if name in self._preg_map['__nextstage__']:
         #    return self._preg_map['__nextstage__'][name]
         try:
+            print ("getattr", name, object.__getattribute__(self, '_preg_map'))
             v = self._preg_map[self._stagename][name]
             return v
             #return like(v, name, self._m)
@@ -195,14 +199,15 @@ class PipelineStage:
         if next_stage not in self._preg_map:
             self._preg_map[next_stage] = {}
         self._preg_map[next_stage][name] = new_pipereg
+        print ("setattr", name, value, self._preg_map)
         if self._pipemode:
-            self._eqs.append(new_pipereg)
+            self._eqs[name] = new_pipereg
             assign = eq(new_pipereg, value)
             print ("pipemode: append", new_pipereg, value, assign)
             if isinstance(value, ObjectProxy):
                 print ("OP, assigns:", value._assigns)
                 self._assigns += value._assigns
-                self._eqs += value._eqs
+                self._eqs[name]._eqs = value._eqs
             #self._m.d.comb += assign
             self._assigns += assign
         elif self._m:
@@ -212,11 +217,12 @@ class PipelineStage:
         else:
             print ("!pipemode !m: defer assign", new_pipereg, value)
             assign = eq(new_pipereg, value)
+            self._eqs[name] = new_pipereg
             self._assigns += assign
             if isinstance(value, ObjectProxy):
                 print ("OP, defer assigns:", value._assigns)
                 self._assigns += value._assigns
-                self._eqs += value._eqs
+                self._eqs[name]._eqs = value._eqs
 
 def likelist(specs):
     res = []
@@ -224,26 +230,34 @@ def likelist(specs):
         res.append(like(v, v.name, None, pipemode=True))
     return res
 
+def likedict(specs):
+    if not isinstance(specs, dict):
+        return like(specs, specs.name, None, pipemode=True)
+    res = {}
+    for k, v in specs.items():
+        res[k] = likedict(v)
+    return res
+
 
 class AutoStage(StageCls):
     def __init__(self, inspecs, outspecs, eqs, assigns):
         self.inspecs, self.outspecs = inspecs, outspecs
         self.eqs, self.assigns = eqs, assigns
         #self.o = self.ospec()
-    def ispec(self): return likelist(self.inspecs)
-    def ospec(self): return likelist(self.outspecs)
+    def ispec(self): return likedict(self.inspecs)
+    def ospec(self): return likedict(self.outspecs)
 
     def process(self, i):
         print ("stage process", i)
-        return self.outspecs
+        return self.eqs
 
     def setup(self, m, i):
-        print ("stage setup i", i)
+        print ("stage setup i", i, m)
         print ("stage setup inspecs", self.inspecs)
         print ("stage setup outspecs", self.outspecs)
         print ("stage setup eqs", self.eqs)
         #self.o = self.ospec()
-        m.d.comb += eq(self.eqs, i)
+        m.d.comb += eq(self.inspecs, i)
         #m.d.comb += eq(self.outspecs, self.eqs)
         #m.d.comb += eq(self.o, i)
 
@@ -256,7 +270,7 @@ class AutoPipe(UnbufferedPipeline):
     def elaborate(self, platform):
         m = UnbufferedPipeline.elaborate(self, platform)
         m.d.comb += self.assigns
-        print ("assigns", self.assigns)
+        print ("assigns", self.assigns, m)
         return m
 
 
@@ -268,9 +282,9 @@ class PipeManager:
 
     @contextmanager
     def Stage(self, name, prev=None, ispec=None):
-        print ("start stage", name)
         if ispec:
-            ispec = likelist(ispec)
+            ispec = likedict(ispec)
+        print ("start stage", name, ispec)
         stage = PipelineStage(name, None, prev, self.pipemode, ispec=ispec)
         try:
             yield stage, self.m #stage._m
@@ -282,9 +296,11 @@ class PipeManager:
                 inspecs = stage._ispec
             else:
                 inspecs = self.get_specs(stage, name)
-                inspecs = likelist(inspecs)
+                #inspecs = likedict(inspecs)
             outspecs = self.get_specs(stage, '__nextstage__', liked=True)
-            eqs = get_eqs(stage._eqs)
+            print ("stage inspecs", name, inspecs)
+            print ("stage outspecs", name, outspecs)
+            eqs = stage._eqs # get_eqs(stage._eqs)
             assigns = get_assigns(stage._assigns)
             print ("stage eqs", name, eqs)
             print ("stage assigns", name, assigns)
@@ -293,6 +309,7 @@ class PipeManager:
         print ("end stage", name, self.pipemode, "\n")
 
     def get_specs(self, stage, name, liked=False):
+        return stage._preg_map[name]
         if name in stage._preg_map:
             res = []
             for k, v in stage._preg_map[name].items():
@@ -301,7 +318,7 @@ class PipeManager:
                 #if isinstance(v, ObjectProxy):
                 #    res += v.get_specs()
             return res
-        return []
+        return {}
 
     def __enter__(self):
         self.stages = []
index cb5df496ce24672d726956471722c8a202a1c4d4..c8d4c90050778d0332349fe36f5ae2475018427d 100644 (file)
@@ -86,7 +86,7 @@ class PipeModule:
 class PipelineStageExample:
 
     def __init__(self):
-        self._loopback = Signal(4)
+        self._loopback = Signal(4, name="loopback")
 
     def get_fragment(self, platform=None):
 
@@ -94,16 +94,17 @@ class PipelineStageExample:
 
         with PipeManager(m, pipemode=True) as pipe:
 
-            with pipe.Stage("first", ispec=[self._loopback]) as (p, m):
-                p.n = ~self._loopback
+            ispec={'loopback': self._loopback}
+            with pipe.Stage("first", ispec=ispec) as (p, m):
+                p.n = ~p.loopback
             with pipe.Stage("second", p) as (p, m):
                 #p.n = ~self._loopback + 2
-                p.n = p.n + 2
+                p.n = p.n + Const(2)
             with pipe.Stage("third", p) as (p, m):
                 #p.n = ~self._loopback + 5
                 localv = Signal(4)
                 m.d.comb += localv.eq(2)
-                p.n = p.n << localv + 1
+                p.n = p.n << localv + Const(1)
                 #p.m = p.n + 2
 
         print (pipe.stages)
@@ -113,7 +114,7 @@ class PipelineStageExample:
 class PipelineStageObjectExample:
 
     def __init__(self):
-        self._loopback = Signal(4)
+        self.loopback = Signal(4)
 
     def get_fragment(self, platform=None):
 
@@ -122,7 +123,7 @@ class PipelineStageObjectExample:
         o = ObjectProxy(None, pipemode=False)
         o.a = Signal(4)
         o.b = Signal(4)
-        self._obj = o
+        self.obj = o
 
         localv2 = Signal(4)
         m.d.sync += localv2.eq(localv2 + 3)
@@ -130,15 +131,14 @@ class PipelineStageObjectExample:
         #m.d.comb += self.obj.a.eq(localv2 + 1)
         #m.d.sync += self._loopback.eq(localv2)
 
-        ispec= [self._loopback, self._obj]
+        ispec= {'loopback': self.loopback, 'obj': self.obj}
         with PipeManager(m, pipemode=True) as pipe:
 
-            with pipe.Stage("first",
-                            ispec=ispec) as (p, m):
-                p.n = ~self._loopback
-                p.o = self._obj
+            with pipe.Stage("first", ispec=ispec) as (p, m):
+                p.n = ~p.loopback
+                p.o = p.obj
             with pipe.Stage("second", p) as (p, m):
-                #p.n = ~self._loopback + 2
+                #p.n = ~self.loopback + 2
                 localn = Signal(4)
                 m.d.comb += localn.eq(p.n)
                 o = ObjectProxy(None, pipemode=False)
@@ -196,8 +196,9 @@ if __name__ == "__main__":
         f.write(rtlil.convert(example, ports=[
                example._loopback,
              ]))
+    #exit(0)
     example = PipelineStageObjectExample()
     with open("pipe_stage_object_module.il", "w") as f:
         f.write(rtlil.convert(example, ports=[
-               example._loopback,
+               example.loopback,
              ]))