add comment on _spec
[ieee754fpu.git] / src / add / stageapi.py
index ab833f504e62c45171108633f9cc625340a33935..dd969ae4ab3fc76d0404e9b7abd41c7c9cfae78d 100644 (file)
 from abc import ABCMeta, abstractmethod
 import inspect
 
-from iocontrol import PrevControl, NextControl
 import nmoperator
 
 
 def _spec(fn, name=None):
+    """ useful function that determines if "fn" has an argument "name".
+        if so, fn(name) is called otherwise fn() is called.
+
+        means that ispec and ospec can be declared with *or without*
+        a name argument.  normally it would be necessary to have
+        "ispec(name=None)" to achieve the same effect.
+    """
     if name is None:
         return fn()
     varnames = dict(inspect.getmembers(fn.__code__))['co_varnames']
@@ -132,7 +138,61 @@ class Stage(metaclass=ABCMeta):
     #def process(i): pass
 
 
-class StageChain(StageCls):
+class StageHelper(Stage):
+    """ a convenience wrapper around something that is Stage-API-compliant.
+        (that "something" may be a static class, for example).
+
+        StageHelper happens to also be compliant with the Stage API,
+        it differs from the stage that it wraps in that all the "optional"
+        functions are provided (hence the designation "convenience wrapper")
+    """
+    def __init__(self, stage):
+        self.stage = stage
+        self._ispecfn = None
+        self._ospecfn = None
+        if stage is not None:
+            self.set_specs(self, self)
+
+    def ospec(self, name):
+        assert self._ospecfn is not None
+        return _spec(self._ospecfn, name)
+
+    def ispec(self, name):
+        assert self._ispecfn is not None
+        return _spec(self._ispecfn, name)
+
+    def set_specs(self, p, n):
+        """ sets up the ispecfn and ospecfn for getting input and output data
+        """
+        if hasattr(p, "stage"):
+            p = p.stage
+        if hasattr(n, "stage"):
+            n = n.stage
+        self._ispecfn = p.ispec
+        self._ospecfn = n.ospec
+
+    def new_specs(self, name):
+        """ allocates new ispec and ospec pair
+        """
+        return self.ispec("%s_i" % name), self.ospec("%s_o" % name)
+
+    def process(self, i):
+        if self.stage and hasattr(self.stage, "process"):
+            return self.stage.process(i)
+        return i
+
+    def setup(self, m, i):
+        if self.stage is not None and hasattr(self.stage, "setup"):
+            self.stage.setup(m, i)
+
+    def _postprocess(self, i): # XXX DISABLED
+        return i # RETURNS INPUT
+        if hasattr(self.stage, "postprocess"):
+            return self.stage.postprocess(i)
+        return i
+
+
+class StageChain(StageHelper):
     """ pass in a list of stages, and they will automatically be
         chained together via their input and output specs into a
         combinatorial chain, to create one giant combinatorial block.
@@ -173,19 +233,11 @@ class StageChain(StageCls):
     def __init__(self, chain, specallocate=False):
         assert len(chain) > 0, "stage chain must be non-zero length"
         self.chain = chain
-        self.specallocate = specallocate
+        StageHelper.__init__(self, None)
+        self.setup = self._sa_setup if specallocate else self._na_setup
+        self.set_specs(self.chain[0], self.chain[-1])
 
-    def ispec(self):
-        """ returns the ispec of the first of the chain
-        """
-        return _spec(self.chain[0].ispec, "chainin")
-
-    def ospec(self):
-        """ returns the ospec of the last of the chain
-        """
-        return _spec(self.chain[-1].ospec, "chainout")
-
-    def _specallocate_setup(self, m, i):
+    def _sa_setup(self, m, i):
         for (idx, c) in enumerate(self.chain):
             if hasattr(c, "setup"):
                 c.setup(m, i)               # stage may have some module stuff
@@ -197,56 +249,18 @@ class StageChain(StageCls):
             ifn = self.chain[idx+1].ispec   # new input on next loop
             i = _spec(ifn, 'chainin%d' % (idx+1))
             m.d.comb += nmoperator.eq(i, o) # assign to next input
-        return o                            # last loop is the output
+        self.o = o
+        return self.o                       # last loop is the output
 
-    def _noallocate_setup(self, m, i):
+    def _na_setup(self, m, i):
         for (idx, c) in enumerate(self.chain):
             if hasattr(c, "setup"):
                 c.setup(m, i)               # stage may have some module stuff
             i = o = c.process(i)            # store input into "o"
-        return o                            # last loop is the output
-
-    def setup(self, m, i):
-        if self.specallocate:
-            self.o = self._specallocate_setup(m, i)
-        else:
-            self.o = self._noallocate_setup(m, i)
+        self.o = o
+        return self.o                       # last loop is the output
 
     def process(self, i):
         return self.o # conform to Stage API: return last-loop output
 
 
-class StageHelper(Stage):
-    """ a convenience wrapper around something that is Stage-API-compliant.
-        (that "something" may be a static class, for example).
-
-        StageHelper happens to also be compliant with the Stage API,
-        it differs from the stage that it wraps in that all the "optional"
-        functions are provided (hence the designation "convenience wrapper")
-    """
-    def __init__(self, stage):
-        self.stage = stage
-
-    def ospec(self, name):
-        assert self.stage is not None
-        return _spec(self.stage.ospec, name)
-
-    def ispec(self, name):
-        assert self.stage is not None
-        return _spec(self.stage.ispec, name)
-
-    def process(self, i):
-        if self.stage and hasattr(self.stage, "process"):
-            return self.stage.process(i)
-        return i
-
-    def setup(self, m, i):
-        if self.stage is not None and hasattr(self.stage, "setup"):
-            self.stage.setup(m, i)
-
-    def _postprocess(self, i): # XXX DISABLED
-        return i # RETURNS INPUT
-        if hasattr(self.stage, "postprocess"):
-            return self.stage.postprocess(i)
-        return i
-