pass in flatten/processing function into _connect_in/out
[ieee754fpu.git] / src / add / test_buf_pipe.py
index c92a96ccee82f9ebbbd1e61f3fd0bcc859954418..6bf690c24e81703afd1fa11b47f160f3172a7b2f 100644 (file)
@@ -14,7 +14,7 @@
 
 """
 
-from nmigen import Module, Signal, Mux
+from nmigen import Module, Signal, Mux, Const
 from nmigen.hdl.rec import Record
 from nmigen.compat.sim import run_simulation
 from nmigen.cli import verilog, rtlil
@@ -22,10 +22,17 @@ from nmigen.cli import verilog, rtlil
 from example_buf_pipe import ExampleBufPipe, ExampleBufPipeAdd
 from example_buf_pipe import ExamplePipeline, UnbufferedPipeline
 from example_buf_pipe import ExampleStageCls
-from example_buf_pipe import PrevControl, NextControl, BufferedPipeline
+from example_buf_pipe import PrevControl, NextControl, BufferedHandshake
 from example_buf_pipe import StageChain, ControlBase, StageCls
+from singlepipe import UnbufferedPipeline2
+from singlepipe import SimpleHandshake
+from singlepipe import PassThroughHandshake
+from singlepipe import PassThroughStage
+from singlepipe import FIFOtest
 
-from random import randint
+from random import randint, seed
+
+#seed(4)
 
 
 def check_o_n_valid(dut, val):
@@ -153,7 +160,7 @@ class Test3:
                 yield self.dut.n.i_ready.eq(stall)
                 yield
                 o_n_valid = yield self.dut.n.o_valid
-                i_n_ready = yield self.dut.n.i_ready
+                i_n_ready = yield self.dut.n.i_ready_test
                 if not o_n_valid or not i_n_ready:
                     continue
                 o_data = yield self.dut.n.o_data
@@ -185,9 +192,10 @@ def data_dict():
 
 
 class Test5:
-    def __init__(self, dut, resultfn, data=None):
+    def __init__(self, dut, resultfn, data=None, stage_ctl=False):
         self.dut = dut
         self.resultfn = resultfn
+        self.stage_ctl = stage_ctl
         if data:
             self.data = data
         else:
@@ -205,6 +213,7 @@ class Test5:
                     send = True
                 else:
                     send = randint(0, send_range) != 0
+                #send = True
                 o_p_ready = yield self.dut.p.o_ready
                 if not o_p_ready:
                     yield
@@ -222,11 +231,12 @@ class Test5:
         while self.o != len(self.data):
             stall_range = randint(0, 3)
             for j in range(randint(1,10)):
-                stall = randint(0, stall_range) != 0
-                yield self.dut.n.i_ready.eq(stall)
+                ready = randint(0, stall_range) != 0
+                #ready = True
+                yield self.dut.n.i_ready.eq(ready)
                 yield
                 o_n_valid = yield self.dut.n.o_valid
-                i_n_ready = yield self.dut.n.i_ready
+                i_n_ready = yield self.dut.n.i_ready_test
                 if not o_n_valid or not i_n_ready:
                     continue
                 if isinstance(self.dut.n.o_data, Record):
@@ -268,7 +278,7 @@ def testbench4(dut):
                 yield dut.p.i_valid.eq(0)
         yield
         o_n_valid = yield dut.n.o_valid
-        i_n_ready = yield dut.n.i_ready
+        i_n_ready = yield dut.n.i_ready_test
         if o_n_valid and i_n_ready:
             o_data = yield dut.n.o_data
             assert o_data == data[o] + 2, "%d-%d data %x not match %x\n" \
@@ -282,37 +292,35 @@ def testbench4(dut):
 ######################################################################
 
 class ExampleBufPipe2(ControlBase):
+    """ Example of how to do chained pipeline stages.
     """
-        connect these:    ------|---------------|
-                                v               v
-        i_p_valid >>in  pipe1 o_n_valid out>> i_p_valid >>in  pipe2
-        o_p_ready <<out pipe1 i_n_ready <<in  o_p_ready <<out pipe2
-        p_i_data  >>in  pipe1 p_i_data  out>> n_o_data  >>in  pipe2
-    """
-    def __init__(self):
-        ControlBase.__init__(self)
-
-        self.pipe1 = ExampleBufPipe()
-        self.pipe2 = ExampleBufPipe()
 
     def elaborate(self, platform):
         m = Module()
-        m.submodules.pipe1 = self.pipe1
-        m.submodules.pipe2 = self.pipe2
 
-        self.connect(m, [self.pipe1, self.pipe2])
+        pipe1 = ExampleBufPipe()
+        pipe2 = ExampleBufPipe()
+
+        m.submodules.pipe1 = pipe1
+        m.submodules.pipe2 = pipe2
+
+        m.d.comb += self.connect([pipe1, pipe2])
 
         return m
 
 
-class ExampleBufPipeChain2(BufferedPipeline):
+######################################################################
+# Test 9
+######################################################################
+
+class ExampleBufPipeChain2(BufferedHandshake):
     """ connects two stages together as a *single* combinatorial stage.
     """
     def __init__(self):
         stage1 = ExampleStageCls()
         stage2 = ExampleStageCls()
         combined = StageChain([stage1, stage2])
-        BufferedPipeline.__init__(self, combined)
+        BufferedHandshake.__init__(self, combined)
 
 
 def data_chain2():
@@ -325,8 +333,8 @@ def data_chain2():
 def test9_resultfn(o_data, expected, i, o):
     res = expected + 2
     assert o_data == res, \
-                "%d-%d data %x not match %s\n" \
-                % (i, o, o_data, repr(expected))
+                "%d-%d received data %x not match expected %x\n" \
+                % (i, o, o_data, res)
 
 
 ######################################################################
@@ -335,14 +343,14 @@ def test9_resultfn(o_data, expected, i, o):
 
 class SetLessThan:
     def __init__(self, width, signed):
-        self.src1 = Signal((width, signed))
-        self.src2 = Signal((width, signed))
-        self.output = Signal(width)
+        self.m = Module()
+        self.src1 = Signal((width, signed), name="src1")
+        self.src2 = Signal((width, signed), name="src2")
+        self.output = Signal(width, name="out")
 
     def elaborate(self, platform):
-        m = Module()
-        m.d.comb += self.output.eq(Mux(self.src1 < self.src2, 1, 0))
-        return m
+        self.m.d.comb += self.output.eq(Mux(self.src1 < self.src2, 1, 0))
+        return self.m
 
 
 class LTStage(StageCls):
@@ -352,10 +360,10 @@ class LTStage(StageCls):
         self.slt = SetLessThan(16, True)
 
     def ispec(self):
-        return (Signal(16), Signal(16))
+        return (Signal(16, name="sig1"), Signal(16, "sig2"))
 
     def ospec(self):
-        return Signal(16)
+        return Signal(16, "out")
 
     def setup(self, m, i):
         self.o = Signal(16)
@@ -403,13 +411,13 @@ class ExampleLTPipeline(UnbufferedPipeline):
         UnbufferedPipeline.__init__(self, stage)
 
 
-class ExampleLTBufferedPipeDerived(BufferedPipeline):
+class ExampleLTBufferedPipeDerived(BufferedHandshake):
     """ an example of how to use the buffered pipeline.
     """
 
     def __init__(self):
         stage = LTStageDerived()
-        BufferedPipeline.__init__(self, stage)
+        BufferedHandshake.__init__(self, stage)
 
 
 def test6_resultfn(o_data, expected, i, o):
@@ -545,13 +553,13 @@ class ExampleAddClassStage(StageCls):
         return i.op1 + i.op2
 
 
-class ExampleBufPipeAddClass(BufferedPipeline):
+class ExampleBufPipeAddClass(BufferedHandshake):
     """ an example of how to use the buffered pipeline, using a class instance
     """
 
     def __init__(self):
         addstage = ExampleAddClassStage()
-        BufferedPipeline.__init__(self, addstage)
+        BufferedHandshake.__init__(self, addstage)
 
 
 class TestInputAdd:
@@ -578,7 +586,305 @@ def data_2op():
         return data
 
 
-num_tests = 100
+######################################################################
+# Test 12
+######################################################################
+
+class ExampleStageDelayCls(StageCls):
+    """ an example of how to use the buffered pipeline, in a static class
+        fashion
+    """
+
+    def __init__(self, valid_trigger=2):
+        self.count = Signal(2)
+        self.valid_trigger = valid_trigger
+
+    def ispec(self):
+        return Signal(16, name="example_input_signal")
+
+    def ospec(self):
+        return Signal(16, name="example_output_signal")
+
+    @property
+    def d_ready(self):
+        return (self.count == 1)# | (self.count == 3)
+        return Const(1)
+
+    def d_valid(self, i_ready):
+        return self.count == self.valid_trigger
+        return Const(1)
+
+    def process(self, i):
+        """ process the input data and returns it (adds 1)
+        """
+        return i + 1
+
+    def elaborate(self, platform):
+        m = Module()
+        m.d.sync += self.count.eq(self.count + 1)
+        return m
+
+
+class ExampleBufDelayedPipe(BufferedHandshake):
+
+    def __init__(self):
+        stage = ExampleStageDelayCls(valid_trigger=2)
+        BufferedHandshake.__init__(self, stage, stage_ctl=True)
+
+    def elaborate(self, platform):
+        m = BufferedHandshake.elaborate(self, platform)
+        m.submodules.stage = self.stage
+        return m
+
+
+def data_chain1():
+        data = []
+        for i in range(num_tests):
+            data.append(1<<((i*3)%15))
+            #data.append(randint(0, 1<<16-2))
+            #print (hex(data[-1]))
+        return data
+
+
+def test12_resultfn(o_data, expected, i, o):
+    res = expected + 1
+    assert o_data == res, \
+                "%d-%d data %x not match %x\n" \
+                % (i, o, o_data, res)
+
+
+######################################################################
+# Test 13
+######################################################################
+
+class ExampleUnBufDelayedPipe(BufferedHandshake):
+
+    def __init__(self):
+        stage = ExampleStageDelayCls(valid_trigger=3)
+        BufferedHandshake.__init__(self, stage, stage_ctl=True)
+
+    def elaborate(self, platform):
+        m = BufferedHandshake.elaborate(self, platform)
+        m.submodules.stage = self.stage
+        return m
+
+######################################################################
+# Test 15
+######################################################################
+
+class ExampleBufModeAdd1Pipe(SimpleHandshake):
+
+    def __init__(self):
+        stage = ExampleStageCls()
+        SimpleHandshake.__init__(self, stage)
+
+
+######################################################################
+# Test 16
+######################################################################
+
+class ExampleBufModeUnBufPipe(ControlBase):
+
+    def elaborate(self, platform):
+        m = ControlBase._elaborate(self, platform)
+
+        pipe1 = ExampleBufModeAdd1Pipe()
+        pipe2 = ExampleBufAdd1Pipe()
+
+        m.submodules.pipe1 = pipe1
+        m.submodules.pipe2 = pipe2
+
+        m.d.comb += self.connect([pipe1, pipe2])
+
+        return m
+
+######################################################################
+# Test 17
+######################################################################
+
+class ExampleUnBufAdd1Pipe2(UnbufferedPipeline2):
+
+    def __init__(self):
+        stage = ExampleStageCls()
+        UnbufferedPipeline2.__init__(self, stage)
+
+
+######################################################################
+# Test 18
+######################################################################
+
+class PassThroughTest(PassThroughHandshake):
+
+    def iospecfn(self):
+        return Signal(16, "out")
+
+    def __init__(self):
+        stage = PassThroughStage(self.iospecfn)
+        PassThroughHandshake.__init__(self, stage)
+
+def test_identical_resultfn(o_data, expected, i, o):
+    res = expected
+    assert o_data == res, \
+                "%d-%d data %x not match %x\n" \
+                % (i, o, o_data, res)
+
+
+######################################################################
+# Test 19
+######################################################################
+
+class ExamplePassAdd1Pipe(PassThroughHandshake):
+
+    def __init__(self):
+        stage = ExampleStageCls()
+        PassThroughHandshake.__init__(self, stage)
+
+
+class ExampleBufPassThruPipe(ControlBase):
+
+    def elaborate(self, platform):
+        m = ControlBase._elaborate(self, platform)
+
+        # XXX currently fails: any other permutation works fine.
+        # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
+        # also fails using UnbufferedPipeline as well
+        pipe1 = ExampleBufModeAdd1Pipe()
+        pipe2 = ExamplePassAdd1Pipe()
+
+        m.submodules.pipe1 = pipe1
+        m.submodules.pipe2 = pipe2
+
+        m.d.comb += self.connect([pipe1, pipe2])
+
+        return m
+
+
+######################################################################
+# Test 20
+######################################################################
+
+def iospecfn():
+    return Signal(16, name="din")
+
+class FIFOTest16(FIFOtest):
+
+
+    def __init__(self):
+        FIFOtest.__init__(self, iospecfn, 16, 2)
+
+
+######################################################################
+# Test 21
+######################################################################
+
+class ExampleFIFOPassThruPipe1(ControlBase):
+
+    def elaborate(self, platform):
+        m = ControlBase._elaborate(self, platform)
+
+        pipe1 = FIFOTest16()
+        pipe2 = ExamplePassAdd1Pipe()
+
+        m.submodules.pipe1 = pipe1
+        m.submodules.pipe2 = pipe2
+
+        m.d.comb += self.connect([pipe1, pipe2])
+
+        return m
+
+
+######################################################################
+# Test 997
+######################################################################
+
+class ExampleBufPassThruPipe2(ControlBase):
+
+    def elaborate(self, platform):
+        m = ControlBase._elaborate(self, platform)
+
+        # XXX currently fails: any other permutation works fine.
+        # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
+        # also fails using UnbufferedPipeline as well
+        #pipe1 = ExampleUnBufAdd1Pipe()
+        #pipe2 = ExampleBufAdd1Pipe()
+        pipe1 = ExampleBufAdd1Pipe()
+        pipe2 = ExamplePassAdd1Pipe()
+
+        m.submodules.pipe1 = pipe1
+        m.submodules.pipe2 = pipe2
+
+        m.d.comb += self.connect([pipe1, pipe2])
+
+        return m
+
+
+######################################################################
+# Test 998
+######################################################################
+
+class ExampleBufPipe3(ControlBase):
+    """ Example of how to do delayed pipeline, where the stage signals
+        whether it is ready.
+    """
+
+    def elaborate(self, platform):
+        m = ControlBase._elaborate(self, platform)
+
+        pipe1 = ExampleBufDelayedPipe()
+        pipe2 = ExampleBufPipe()
+
+        m.submodules.pipe1 = pipe1
+        m.submodules.pipe2 = pipe2
+
+        m.d.comb += self.connect([pipe1, pipe2])
+
+        return m
+
+######################################################################
+# Test 999 - XXX FAILS
+# http://bugs.libre-riscv.org/show_bug.cgi?id=57
+######################################################################
+
+class ExampleBufAdd1Pipe(BufferedHandshake):
+
+    def __init__(self):
+        stage = ExampleStageCls()
+        BufferedHandshake.__init__(self, stage)
+
+
+class ExampleUnBufAdd1Pipe(UnbufferedPipeline):
+
+    def __init__(self):
+        stage = ExampleStageCls()
+        UnbufferedPipeline.__init__(self, stage)
+
+
+class ExampleBufUnBufPipe(ControlBase):
+
+    def elaborate(self, platform):
+        m = ControlBase._elaborate(self, platform)
+
+        # XXX currently fails: any other permutation works fine.
+        # p1=u,p2=b ok p1=u,p2=u ok p1=b,p2=b ok
+        # also fails using UnbufferedPipeline as well
+        #pipe1 = ExampleUnBufAdd1Pipe()
+        #pipe2 = ExampleBufAdd1Pipe()
+        pipe1 = ExampleBufAdd1Pipe()
+        pipe2 = ExampleUnBufAdd1Pipe()
+
+        m.submodules.pipe1 = pipe1
+        m.submodules.pipe2 = pipe2
+
+        m.d.comb += self.connect([pipe1, pipe2])
+
+        return m
+
+
+######################################################################
+# Unit Tests
+######################################################################
+
+num_tests = 10
 
 if __name__ == '__main__':
     print ("test 1")
@@ -612,7 +918,7 @@ if __name__ == '__main__':
 
     print ("test 5")
     dut = ExampleBufPipeAdd()
-    test = Test5(dut, test5_resultfn)
+    test = Test5(dut, test5_resultfn, stage_ctl=True)
     run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpipe5.vcd")
 
     print ("test 6")
@@ -676,3 +982,147 @@ if __name__ == '__main__':
     run_simulation(dut, [test.send, test.rcv], vcd_name="test_addrecord.vcd")
 
 
+    print ("test 12")
+    dut = ExampleBufDelayedPipe()
+    data = data_chain1()
+    test = Test5(dut, test12_resultfn, data=data)
+    run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpipe12.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_bufpipe12.il", "w") as f:
+        f.write(vl)
+
+    print ("test 13")
+    dut = ExampleUnBufDelayedPipe()
+    data = data_chain1()
+    test = Test5(dut, test12_resultfn, data=data)
+    run_simulation(dut, [test.send, test.rcv], vcd_name="test_unbufpipe13.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_unbufpipe13.il", "w") as f:
+        f.write(vl)
+
+    print ("test 15")
+    dut = ExampleBufModeAdd1Pipe()
+    data = data_chain1()
+    test = Test5(dut, test12_resultfn, data=data)
+    run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufunbuf15.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_bufunbuf15.il", "w") as f:
+        f.write(vl)
+
+    print ("test 16")
+    dut = ExampleBufModeUnBufPipe()
+    data = data_chain1()
+    test = Test5(dut, test9_resultfn, data=data)
+    run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufunbuf16.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_bufunbuf16.il", "w") as f:
+        f.write(vl)
+
+    print ("test 17")
+    dut = ExampleUnBufAdd1Pipe2()
+    data = data_chain1()
+    test = Test5(dut, test12_resultfn, data=data)
+    run_simulation(dut, [test.send, test.rcv], vcd_name="test_unbufpipe17.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_unbufpipe17.il", "w") as f:
+        f.write(vl)
+
+    print ("test 18")
+    dut = PassThroughTest()
+    data = data_chain1()
+    test = Test5(dut, test_identical_resultfn, data=data)
+    run_simulation(dut, [test.send, test.rcv], vcd_name="test_passthru18.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_passthru18.il", "w") as f:
+        f.write(vl)
+
+    print ("test 19")
+    dut = ExampleBufPassThruPipe()
+    data = data_chain1()
+    test = Test5(dut, test9_resultfn, data=data)
+    run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpass19.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_bufpass19.il", "w") as f:
+        f.write(vl)
+
+    print ("test 20")
+    dut = FIFOTest16()
+    data = data_chain1()
+    test = Test5(dut, test_identical_resultfn, data=data)
+    run_simulation(dut, [test.send, test.rcv], vcd_name="test_fifo20.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_fifo20.il", "w") as f:
+        f.write(vl)
+
+    print ("test 21")
+    dut = ExampleFIFOPassThruPipe1()
+    data = data_chain1()
+    test = Test5(dut, test12_resultfn, data=data)
+    run_simulation(dut, [test.send, test.rcv], vcd_name="test_fifopass21.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_fifopass21.il", "w") as f:
+        f.write(vl)
+
+    print ("test 997")
+    dut = ExampleBufPassThruPipe2()
+    data = data_chain1()
+    test = Test5(dut, test9_resultfn, data=data)
+    run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpass997.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_bufpass997.il", "w") as f:
+        f.write(vl)
+
+    print ("test 998 (fails, bug)")
+    dut = ExampleBufPipe3()
+    data = data_chain1()
+    test = Test5(dut, test9_resultfn, data=data)
+    run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufpipe14.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_bufpipe14.il", "w") as f:
+        f.write(vl)
+
+    print ("test 999 (expected to fail, which is a bug)")
+    dut = ExampleBufUnBufPipe()
+    data = data_chain1()
+    test = Test5(dut, test9_resultfn, data=data)
+    run_simulation(dut, [test.send, test.rcv], vcd_name="test_bufunbuf999.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_bufunbuf999.il", "w") as f:
+        f.write(vl)
+