create classes for STB/BUSY, split in from out
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 15 Mar 2019 08:28:18 +0000 (08:28 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 15 Mar 2019 08:28:18 +0000 (08:28 +0000)
src/add/example_buf_pipe.py
src/add/test_buf_pipe.py

index 6678a6713f05280828d7b3a5ef4fd4f3adffaa96..37f866c36d1b463eba75c07f2bd7506d0a4acf1d 100644 (file)
     where data will flow on *every* clock when the conditions are right.
 
     input acceptance conditions are when:
     where data will flow on *every* clock when the conditions are right.
 
     input acceptance conditions are when:
-        * incoming previous-stage strobe (i_p_stb) is HIGH
-        * outgoing previous-stage busy   (o_p_busy) is LOW
+        * incoming previous-stage strobe (i.p_stb) is HIGH
+        * outgoing previous-stage busy   (o.p_busy) is LOW
 
     output transmission conditions are when:
 
     output transmission conditions are when:
-        * outgoing next-stage strobe (o_n_stb) is HIGH
-        * outgoing next-stage busy   (i_n_busy) is LOW
+        * outgoing next-stage strobe (o.n_stb) is HIGH
+        * outgoing next-stage busy   (i.n_busy) is LOW
 
     the tricky bit is when the input has valid data and the output is not
     ready to accept it.  if it wasn't for the clock synchronisation, it
 
     the tricky bit is when the input has valid data and the output is not
     ready to accept it.  if it wasn't for the clock synchronisation, it
@@ -100,12 +100,25 @@ class ExampleStage:
     def ports(self):
         return [self.i_data, self.o_data]
 
     def ports(self):
         return [self.i_data, self.o_data]
 
+class IOAckIn:
+
+    def __init__(self):
+        self.p_stb = Signal()  # >>in - comes in from PREVIOUS stage
+        self.n_busy = Signal() # in<< - comes in from the NEXT stage
+
+
+class IOAckOut:
+
+    def __init__(self):
+        self.n_stb = Signal()  # out>> - goes out to the NEXT stage
+        self.p_busy = Signal() # <<out - goes out to the PREVIOUS stage
+
 
 class BufferedPipeline:
     """ buffered pipeline stage
 
 
 class BufferedPipeline:
     """ buffered pipeline stage
 
-        stage-1   i_p_stb  >>in   stage   o_n_stb  out>>   stage+1
-        stage-1   o_p_busy <<out  stage   i_n_busy <<in    stage+1
+        stage-1   i.p_stb  >>in   stage   o.n_stb  out>>   stage+1
+        stage-1   o.p_busy <<out  stage   i.n_busy <<in    stage+1
         stage-1   i_data   >>in   stage   o_data   out>>   stage+1
                               |             |
                               +------->  process
         stage-1   i_data   >>in   stage   o_data   out>>   stage+1
                               |             |
                               +------->  process
@@ -114,13 +127,14 @@ class BufferedPipeline:
     """
     def __init__(self):
         # input: strobe comes in from previous stage, busy comes in from next
     """
     def __init__(self):
         # input: strobe comes in from previous stage, busy comes in from next
-        #self.i_p_rst = Signal()    # >>in - comes in from PREVIOUS stage
-        self.i_p_stb = Signal()    # >>in - comes in from PREVIOUS stage
-        self.i_n_busy = Signal()   # in<< - comes in from the NEXT stage
+        self.i = IOAckIn()
+        #self.i.p_stb = Signal()    # >>in - comes in from PREVIOUS stage
+        #self.i.n_busy = Signal()   # in<< - comes in from the NEXT stage
 
         # output: strobe goes out to next stage, busy comes in from previous
 
         # output: strobe goes out to next stage, busy comes in from previous
-        self.o_n_stb = Signal()    # out>> - goes out to the NEXT stage
-        self.o_p_busy = Signal()   # <<out - goes out to the PREVIOUS stage
+        self.o = IOAckOut()
+        #self.o.n_stb = Signal()    # out>> - goes out to the NEXT stage
+        #self.o.p_busy = Signal()   # <<out - goes out to the PREVIOUS stage
 
     def elaborate(self, platform):
         m = Module()
 
     def elaborate(self, platform):
         m = Module()
@@ -130,54 +144,54 @@ class BufferedPipeline:
         o_n_stbn = Signal(reset_less=True)
         i_n_busyn = Signal(reset_less=True)
         i_p_stb_o_p_busyn = Signal(reset_less=True)
         o_n_stbn = Signal(reset_less=True)
         i_n_busyn = Signal(reset_less=True)
         i_p_stb_o_p_busyn = Signal(reset_less=True)
-        m.d.comb += [i_n_busyn.eq(~self.i_n_busy),
-                     o_n_stbn.eq(~self.o_n_stb),
-                     o_p_busyn.eq(~self.o_p_busy),
-                     i_p_stb_o_p_busyn.eq(self.i_p_stb & o_p_busyn),
+        m.d.comb += [i_n_busyn.eq(~self.i.n_busy),
+                     o_n_stbn.eq(~self.o.n_stb),
+                     o_p_busyn.eq(~self.o.p_busy),
+                     i_p_stb_o_p_busyn.eq(self.i.p_stb & o_p_busyn),
         ]
 
         # store result of processing in combinatorial temporary
         ]
 
         # store result of processing in combinatorial temporary
-        with m.If(self.i_p_stb): # input is valid: process it
+        with m.If(self.i.p_stb): # input is valid: process it
             m.d.comb += self.stage.process()
         # if not in stall condition, update the temporary register
         with m.If(o_p_busyn): # not stalled
             m.d.sync += self.stage.update_buffer()
 
             m.d.comb += self.stage.process()
         # if not in stall condition, update the temporary register
         with m.If(o_p_busyn): # not stalled
             m.d.sync += self.stage.update_buffer()
 
-        #with m.If(self.i_p_rst): # reset
-        #    m.d.sync += self.o_n_stb.eq(0)
-        #    m.d.sync += self.o_p_busy.eq(0)
+        #with m.If(self.i.p_rst): # reset
+        #    m.d.sync += self.o.n_stb.eq(0)
+        #    m.d.sync += self.o.p_busy.eq(0)
         with m.If(i_n_busyn): # next stage is not busy
             with m.If(o_p_busyn): # not stalled
                 # nothing in buffer: send (processed) input direct to output
         with m.If(i_n_busyn): # next stage is not busy
             with m.If(o_p_busyn): # not stalled
                 # nothing in buffer: send (processed) input direct to output
-                m.d.sync += [self.o_n_stb.eq(self.i_p_stb),
+                m.d.sync += [self.o.n_stb.eq(self.i.p_stb),
                              self.stage.update_output(),
                             ]
                              self.stage.update_output(),
                             ]
-            with m.Else(): # o_p_busy is true, and something is in our buffer.
+            with m.Else(): # o.p_busy is true, and something is in our buffer.
                 # Flush the [already processed] buffer to the output port.
                 # Flush the [already processed] buffer to the output port.
-                m.d.sync += [self.o_n_stb.eq(1),
+                m.d.sync += [self.o.n_stb.eq(1),
                              self.stage.flush_buffer(),
                              # clear stall condition, declare register empty.
                              self.stage.flush_buffer(),
                              # clear stall condition, declare register empty.
-                             self.o_p_busy.eq(0),
+                             self.o.p_busy.eq(0),
                             ]
                             ]
-                # ignore input, since o_p_busy is also true.
+                # ignore input, since o.p_busy is also true.
 
 
-        # (i_n_busy) is true here: next stage is busy
+        # (i.n_busy) is true here: next stage is busy
         with m.Elif(o_n_stbn): # next stage being told "not busy"
         with m.Elif(o_n_stbn): # next stage being told "not busy"
-            m.d.sync += [self.o_n_stb.eq(self.i_p_stb),
-                         self.o_p_busy.eq(0), # Keep the buffer empty
+            m.d.sync += [self.o.n_stb.eq(self.i.p_stb),
+                         self.o.p_busy.eq(0), # Keep the buffer empty
                          # set the output data (from comb result)
                          self.stage.update_output(),
                         ]
                          # set the output data (from comb result)
                          self.stage.update_output(),
                         ]
-        # (i_n_busy) and (o_n_stb) both true:
+        # (i.n_busy) and (o.n_stb) both true:
         with m.Elif(i_p_stb_o_p_busyn):
             # If next stage *is* busy, and not stalled yet, accept input
         with m.Elif(i_p_stb_o_p_busyn):
             # If next stage *is* busy, and not stalled yet, accept input
-            m.d.sync += self.o_p_busy.eq(self.i_p_stb & self.o_n_stb)
+            m.d.sync += self.o.p_busy.eq(self.i.p_stb & self.o.n_stb)
 
         return m
 
     def ports(self):
 
         return m
 
     def ports(self):
-        return [self.i_p_stb, self.i_n_busy,
-                self.o_n_stb, self.o_p_busy,
+        return [self.i.p_stb, self.i.n_busy,
+                self.o.n_stb, self.o.p_busy,
                ]
 
 
                ]
 
 
index 8590ccadb8331c29488aa644352a6d13120cd45e..baa344a91faa442b4b93d87d878f9db687ca3152 100644 (file)
@@ -5,20 +5,24 @@ from random import randint
 
 
 def check_o_n_stb(dut, val):
 
 
 def check_o_n_stb(dut, val):
+    o_n_stb = yield dut.o.n_stb
+    assert o_n_stb == val
+
+def check_o_n_stb2(dut, val):
     o_n_stb = yield dut.o_n_stb
     assert o_n_stb == val
 
 
 def testbench(dut):
     #yield dut.i_p_rst.eq(1)
     o_n_stb = yield dut.o_n_stb
     assert o_n_stb == val
 
 
 def testbench(dut):
     #yield dut.i_p_rst.eq(1)
-    yield dut.i_n_busy.eq(1)
-    yield dut.o_p_busy.eq(1)
+    yield dut.i.n_busy.eq(1)
+    yield dut.o.p_busy.eq(1)
     yield
     yield
     #yield dut.i_p_rst.eq(0)
     yield
     yield
     #yield dut.i_p_rst.eq(0)
-    yield dut.i_n_busy.eq(0)
+    yield dut.i.n_busy.eq(0)
     yield dut.stage.i_data.eq(5)
     yield dut.stage.i_data.eq(5)
-    yield dut.i_p_stb.eq(1)
+    yield dut.i.p_stb.eq(1)
     yield
 
     yield dut.stage.i_data.eq(7)
     yield
 
     yield dut.stage.i_data.eq(7)
@@ -28,14 +32,14 @@ def testbench(dut):
 
     yield dut.stage.i_data.eq(2)
     yield
 
     yield dut.stage.i_data.eq(2)
     yield
-    yield dut.i_n_busy.eq(1) # begin going into "stall" (next stage says busy)
+    yield dut.i.n_busy.eq(1) # begin going into "stall" (next stage says busy)
     yield dut.stage.i_data.eq(9)
     yield
     yield dut.stage.i_data.eq(9)
     yield
-    yield dut.i_p_stb.eq(0)
+    yield dut.i.p_stb.eq(0)
     yield dut.stage.i_data.eq(12)
     yield
     yield dut.stage.i_data.eq(32)
     yield dut.stage.i_data.eq(12)
     yield
     yield dut.stage.i_data.eq(32)
-    yield dut.i_n_busy.eq(0)
+    yield dut.i.n_busy.eq(0)
     yield
     yield from check_o_n_stb(dut, 1) # buffer still needs to output
     yield
     yield
     yield from check_o_n_stb(dut, 1) # buffer still needs to output
     yield
@@ -46,25 +50,25 @@ def testbench(dut):
 
 
 def testbench2(dut):
 
 
 def testbench2(dut):
-    #yield dut.i_p_rst.eq(1)
+    #yield dut.i.p_rst.eq(1)
     yield dut.i_n_busy.eq(1)
     yield dut.i_n_busy.eq(1)
-    #yield dut.o_p_busy.eq(1)
+    #yield dut.o.p_busy.eq(1)
     yield
     yield
     yield
     yield
-    #yield dut.i_p_rst.eq(0)
+    #yield dut.i.p_rst.eq(0)
     yield dut.i_n_busy.eq(0)
     yield dut.i_data.eq(5)
     yield dut.i_p_stb.eq(1)
     yield
 
     yield dut.i_data.eq(7)
     yield dut.i_n_busy.eq(0)
     yield dut.i_data.eq(5)
     yield dut.i_p_stb.eq(1)
     yield
 
     yield dut.i_data.eq(7)
-    yield from check_o_n_stb(dut, 0) # effects of i_p_stb delayed 2 clocks
+    yield from check_o_n_stb2(dut, 0) # effects of i_p_stb delayed 2 clocks
     yield
     yield
-    yield from check_o_n_stb(dut, 0) # effects of i_p_stb delayed 2 clocks
+    yield from check_o_n_stb2(dut, 0) # effects of i_p_stb delayed 2 clocks
 
     yield dut.i_data.eq(2)
     yield
 
     yield dut.i_data.eq(2)
     yield
-    yield from check_o_n_stb(dut, 1) # ok *now* i_p_stb effect is felt
+    yield from check_o_n_stb2(dut, 1) # ok *now* i_p_stb effect is felt
     yield dut.i_n_busy.eq(1) # begin going into "stall" (next stage says busy)
     yield dut.i_data.eq(9)
     yield
     yield dut.i_n_busy.eq(1) # begin going into "stall" (next stage says busy)
     yield dut.i_data.eq(9)
     yield
@@ -74,13 +78,13 @@ def testbench2(dut):
     yield dut.i_data.eq(32)
     yield dut.i_n_busy.eq(0)
     yield
     yield dut.i_data.eq(32)
     yield dut.i_n_busy.eq(0)
     yield
-    yield from check_o_n_stb(dut, 1) # buffer still needs to output
+    yield from check_o_n_stb2(dut, 1) # buffer still needs to output
     yield
     yield
-    yield from check_o_n_stb(dut, 1) # buffer still needs to output
+    yield from check_o_n_stb2(dut, 1) # buffer still needs to output
     yield
     yield
-    yield from check_o_n_stb(dut, 1) # buffer still needs to output
+    yield from check_o_n_stb2(dut, 1) # buffer still needs to output
     yield
     yield
-    yield from check_o_n_stb(dut, 0) # buffer outputted, *now* we're done.
+    yield from check_o_n_stb2(dut, 0) # buffer outputted, *now* we're done.
     yield
     yield
     yield
     yield
     yield
     yield
@@ -104,16 +108,16 @@ class Test3:
                     send = True
                 else:
                     send = randint(0, send_range) != 0
                     send = True
                 else:
                     send = randint(0, send_range) != 0
-                o_p_busy = yield self.dut.o_p_busy
+                o_p_busy = yield self.dut.o.p_busy
                 if o_p_busy:
                     yield
                     continue
                 if send and self.i != len(self.data):
                 if o_p_busy:
                     yield
                     continue
                 if send and self.i != len(self.data):
-                    yield self.dut.i_p_stb.eq(1)
+                    yield self.dut.i.p_stb.eq(1)
                     yield self.dut.stage.i_data.eq(self.data[self.i])
                     self.i += 1
                 else:
                     yield self.dut.stage.i_data.eq(self.data[self.i])
                     self.i += 1
                 else:
-                    yield self.dut.i_p_stb.eq(0)
+                    yield self.dut.i.p_stb.eq(0)
                 yield
 
     def rcv(self):
                 yield
 
     def rcv(self):
@@ -121,10 +125,10 @@ class Test3:
             stall_range = randint(0, 3)
             for j in range(randint(1,10)):
                 stall = randint(0, stall_range) == 0
             stall_range = randint(0, 3)
             for j in range(randint(1,10)):
                 stall = randint(0, stall_range) == 0
-                yield self.dut.i_n_busy.eq(stall)
+                yield self.dut.i.n_busy.eq(stall)
                 yield
                 yield
-                o_n_stb = yield self.dut.o_n_stb
-                i_n_busy = yield self.dut.i_n_busy
+                o_n_stb = yield self.dut.o.n_stb
+                i_n_busy = yield self.dut.i.n_busy
                 if not o_n_stb or i_n_busy:
                     continue
                 o_data = yield self.dut.stage.o_data
                 if not o_n_stb or i_n_busy:
                     continue
                 o_data = yield self.dut.stage.o_data
@@ -195,18 +199,18 @@ class BufPipe2:
         m.submodules.pipe2 = self.pipe2
 
         # connect inter-pipe input/output stb/busy/data
         m.submodules.pipe2 = self.pipe2
 
         # connect inter-pipe input/output stb/busy/data
-        m.d.comb += self.pipe2.i_p_stb.eq(self.pipe1.o_n_stb)
-        m.d.comb += self.pipe1.i_n_busy.eq(self.pipe2.o_p_busy)
+        m.d.comb += self.pipe2.i.p_stb.eq(self.pipe1.o.n_stb)
+        m.d.comb += self.pipe1.i.n_busy.eq(self.pipe2.o.p_busy)
         m.d.comb += self.pipe2.stage.i_data.eq(self.pipe1.stage.o_data)
 
         # inputs/outputs to the module: pipe1 connections here (LHS)
         m.d.comb += self.pipe2.stage.i_data.eq(self.pipe1.stage.o_data)
 
         # inputs/outputs to the module: pipe1 connections here (LHS)
-        m.d.comb += self.pipe1.i_p_stb.eq(self.i_p_stb)
-        m.d.comb += self.o_p_busy.eq(self.pipe1.o_p_busy)
+        m.d.comb += self.pipe1.i.p_stb.eq(self.i_p_stb)
+        m.d.comb += self.o_p_busy.eq(self.pipe1.o.p_busy)
         m.d.comb += self.pipe1.stage.i_data.eq(self.i_data)
 
         # now pipe2 connections (RHS)
         m.d.comb += self.pipe1.stage.i_data.eq(self.i_data)
 
         # now pipe2 connections (RHS)
-        m.d.comb += self.o_n_stb.eq(self.pipe2.o_n_stb)
-        m.d.comb += self.pipe2.i_n_busy.eq(self.i_n_busy)
+        m.d.comb += self.o_n_stb.eq(self.pipe2.o.n_stb)
+        m.d.comb += self.pipe2.i.n_busy.eq(self.i_n_busy)
         m.d.comb += self.o_data.eq(self.pipe2.stage.o_data)
 
         return m
         m.d.comb += self.o_data.eq(self.pipe2.stage.o_data)
 
         return m