replace manual pipe-connection with a general-purpose ControlBase.connect
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Wed, 27 Mar 2019 08:13:15 +0000 (08:13 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Wed, 27 Mar 2019 08:13:15 +0000 (08:13 +0000)
src/add/example_buf_pipe.py
src/add/test_buf_pipe.py

index d28cbd0f9a2c0c5a37a8b1a09dd36d7ca9d19636..6db46ad9fe966d0b68d998887427f5e9005b5ead 100644 (file)
@@ -122,7 +122,7 @@ class PrevControl:
         self.i_valid = Signal(i_width, name="p_i_valid") # prev   >>in  self
         self.o_ready = Signal(name="p_o_ready") # prev   <<out self
 
-    def connect_in(self, prev):
+    def _connect_in(self, prev):
         """ helper function to connect stage to an input source.  do not
             use to connect stage-to-stage!
         """
@@ -159,7 +159,7 @@ class NextControl:
                 eq(nxt.i_data, self.o_data),
                ]
 
-    def connect_out(self, nxt):
+    def _connect_out(self, nxt):
         """ helper function to connect stage to an output source.  do not
             use to connect stage-to-stage!
         """
@@ -314,17 +314,66 @@ class ControlBase:
         """
         return self.n.connect_to_next(nxt.p)
 
-    def connect_in(self, prev):
+    def _connect_in(self, prev):
         """ helper function to connect stage to an input source.  do not
             use to connect stage-to-stage!
         """
-        return self.p.connect_in(prev.p)
+        return self.p._connect_in(prev.p)
 
-    def connect_out(self, nxt):
+    def _connect_out(self, nxt):
         """ helper function to connect stage to an output source.  do not
             use to connect stage-to-stage!
         """
-        return self.n.connect_out(nxt.n)
+        return self.n._connect_out(nxt.n)
+
+    def connect(self, m, pipechain):
+        """ connects a chain (list) of Pipeline instances together and
+            links them to this ControlBase instance:
+
+                      in <----> self <---> out
+                       |                   ^
+                       v                   |
+                    [pipe1, pipe2, pipe3, pipe4]
+                       |    ^  |    ^  |     ^
+                       v    |  v    |  v     |
+                     out---in out--in out---in
+
+            Also takes care of allocating i_data/o_data, by looking up
+            the data spec for each end of the pipechain.
+
+            Basically this function is the direct equivalent of StageChain,
+            except that unlike StageChain, the Pipeline logic is followed.
+
+            Just as StageChain presents an object that conforms to the
+            Stage API from a list of objects that also conform to the
+            Stage API, an object that calls this Pipeline connect function
+            has the exact same pipeline API as the list of pipline objects
+            it is called with.
+
+            Thus it becomes possible to build up larger chains recursively.
+            More complex chains (multi-input, multi-output) will have to be
+            done manually.
+        """
+        eqs = [] # collated list of assignment statements
+
+        # connect inter-chain
+        for i in range(len(pipechain)-1):
+            pipe1 = pipechain[i]
+            pipe2 = pipechain[i+1]
+            eqs += pipe1.connect_to_next(pipe2)
+
+        # connect front of chain to ourselves
+        front = pipechain[0]
+        self.p.i_data = front.stage.ispec()
+        eqs += front._connect_in(self)
+
+        # connect end of chain to ourselves
+        end = pipechain[-1]
+        self.n.o_data = end.stage.ospec()
+        eqs += end._connect_out(self)
+
+        # activate the assignments
+        m.d.comb += eqs
 
     def set_input(self, i):
         """ helper function to set the input data
index 79eac0b8421c4c69e0736bc019f8fc1bac104fb0..c92a96ccee82f9ebbbd1e61f3fd0bcc859954418 100644 (file)
@@ -292,10 +292,6 @@ class ExampleBufPipe2(ControlBase):
     def __init__(self):
         ControlBase.__init__(self)
 
-        # input / output
-        self.p.i_data = Signal(32) # >>in - comes in from the PREVIOUS stage
-        self.n.o_data = Signal(32) # out>> - goes out to the NEXT stage
-
         self.pipe1 = ExampleBufPipe()
         self.pipe2 = ExampleBufPipe()
 
@@ -304,14 +300,7 @@ class ExampleBufPipe2(ControlBase):
         m.submodules.pipe1 = self.pipe1
         m.submodules.pipe2 = self.pipe2
 
-        # connect inter-pipe input/output valid/ready/data
-        m.d.comb += self.pipe1.connect_to_next(self.pipe2)
-
-        # inputs/outputs to the module: pipe1 connections here (LHS)
-        m.d.comb += self.pipe1.connect_in(self)
-
-        # now pipe2 connections (RHS)
-        m.d.comb += self.pipe2.connect_out(self)
+        self.connect(m, [self.pipe1, self.pipe2])
 
         return m
 
@@ -599,6 +588,13 @@ if __name__ == '__main__':
     print ("test 2")
     dut = ExampleBufPipe2()
     run_simulation(dut, testbench2(dut), vcd_name="test_bufpipe2.vcd")
+    ports = [dut.p.i_valid, dut.n.i_ready,
+             dut.n.o_valid, dut.p.o_ready] + \
+             [dut.p.i_data] + [dut.n.o_data]
+    vl = rtlil.convert(dut, ports=ports)
+    with open("test_bufpipe2.il", "w") as f:
+        f.write(vl)
+
 
     print ("test 3")
     dut = ExampleBufPipe()