update comments
[ieee754fpu.git] / src / add / pipeline.py
index 450703224fd3ffd3e3cc81f70bedb8b810baceb3..afcee743982175e31a833a208067bf59ec2c3978 100644 (file)
@@ -8,7 +8,8 @@ from nmigen import tracer
 from nmigen.compat.fhdl.bitcontainer import value_bits_sign
 from contextlib import contextmanager
 
-from singlepipe import eq, StageCls, ControlBase, BufferedPipeline
+from nmoperator import eq
+from singlepipe import StageCls, ControlBase, BufferedHandshake
 from singlepipe import UnbufferedPipeline
 
 
@@ -49,13 +50,14 @@ def get_eqs(_eqs):
 
 
 class ObjectProxy:
-    def __init__(self, m, name=None, pipemode=False):
+    def __init__(self, m, name=None, pipemode=False, syncmode=True):
         self._m = m
         if name is None:
             name = tracer.get_var_name(default=None)
         self.name = name
         self._pipemode = pipemode
-        self._eqs = []
+        self._syncmode = syncmode
+        self._eqs = {}
         self._assigns = []
         self._preg_map = {}
 
@@ -81,6 +83,15 @@ class ObjectProxy:
             subobjs.append(repr(ai))
         return "<OP %s>" % subobjs
 
+    def get_specs(self, liked=False):
+        res = []
+        for k, v in self._preg_map.items():
+            #v = like(v, k, stage._m)
+            res.append(v)
+            if isinstance(v, ObjectProxy):
+                res += v.get_specs()
+        return res
+
     def eq(self, i):
         print ("ObjectProxy eq", self, i)
         res = []
@@ -96,7 +107,7 @@ class ObjectProxy:
             if isinstance(a, Signal) or isinstance(a, ObjectProxy) or \
                isinstance(a, Record):
                 res.append(a)
-        print ("ObjectPorts", res)
+        #print ("ObjectPorts", res)
         return res
 
     def __getattr__(self, name):
@@ -120,16 +131,22 @@ class ObjectProxy:
         self._preg_map[name] = new_pipereg
         #object.__setattr__(self, name, new_pipereg)
         if self._pipemode:
-            print ("OP pipemode", new_pipereg, value)
-            #self._eqs.append(value)
-            #self._m.d.comb += eq(new_pipereg, value)
-            pass
+            #print ("OP pipemode", self._syncmode, new_pipereg, value)
+            assign = eq(new_pipereg, value)
+            if self._syncmode:
+                self._m.d.sync += assign
+            else:
+                self._m.d.comb += assign
         elif self._m:
-            print ("OP !pipemode assign", new_pipereg, value, type(value))
+            #print ("OP !pipemode assign", new_pipereg, value, type(value))
             self._m.d.comb += eq(new_pipereg, value)
         else:
-            print ("OP !pipemode !m", new_pipereg, value, type(value))
+            #print ("OP !pipemode !m", new_pipereg, value, type(value))
             self._assigns += eq(new_pipereg, value)
+            if isinstance(value, ObjectProxy):
+                #print ("OP, defer assigns:", value._assigns)
+                self._assigns += value._assigns
+                self._eqs.append(value._eqs)
 
 
 class PipelineStage:
@@ -139,28 +156,34 @@ class PipelineStage:
     def __init__(self, name, m, prev=None, pipemode=False, ispec=None):
         self._m = m
         self._stagename = name
-        self._preg_map = {}
+        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)
@@ -181,13 +204,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(value)
+            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[name]._eqs = value._eqs
             #self._m.d.comb += assign
             self._assigns += assign
         elif self._m:
@@ -197,7 +222,26 @@ 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[name]._eqs = value._eqs
+
+def likelist(specs):
+    res = []
+    for v in 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):
@@ -205,20 +249,21 @@ class AutoStage(StageCls):
         self.inspecs, self.outspecs = inspecs, outspecs
         self.eqs, self.assigns = eqs, assigns
         #self.o = self.ospec()
-    def ispec(self): return self.like(self.inspecs)
-    def ospec(self): return self.like(self.outspecs)
-    def like(self, specs):
-        res = []
-        for v in specs:
-            res.append(like(v, v.name, None, pipemode=True))
-        return res
+    def ispec(self): return likedict(self.inspecs)
+    def ospec(self): return likedict(self.outspecs)
 
     def process(self, i):
         print ("stage process", i)
         return self.eqs
 
     def setup(self, m, i):
-        print ("stage setup", 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.inspecs, i)
+        #m.d.comb += eq(self.outspecs, self.eqs)
         #m.d.comb += eq(self.o, i)
 
 
@@ -230,7 +275,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
 
 
@@ -242,7 +287,9 @@ class PipeManager:
 
     @contextmanager
     def Stage(self, name, prev=None, ispec=None):
-        print ("start stage", name)
+        if 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
@@ -254,8 +301,11 @@ class PipeManager:
                 inspecs = stage._ispec
             else:
                 inspecs = self.get_specs(stage, name)
+                #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)
@@ -264,13 +314,16 @@ 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():
                 #v = like(v, k, stage._m)
                 res.append(v)
+                #if isinstance(v, ObjectProxy):
+                #    res += v.get_specs()
             return res
-        return []
+        return {}
 
     def __enter__(self):
         self.stages = []
@@ -283,7 +336,7 @@ class PipeManager:
         for s in self.stages:
             print ("stage specs", s, s.inspecs, s.outspecs)
             if self.pipetype == 'buffered':
-                p = BufferedPipeline(s)
+                p = BufferedHandshake(s)
             else:
                 p = AutoPipe(s, s.assigns)
             pipes.append(p)