get InputGroup running
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Mon, 11 Mar 2019 19:09:39 +0000 (19:09 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Mon, 11 Mar 2019 19:09:39 +0000 (19:09 +0000)
src/add/nmigen_add_experiment.py
src/add/test_inputgroup.py

index 660b079463c2f8d87ab50003008a1744b581a227..f53037d1a88c912566cd13fd32db1945346a1751 100644 (file)
@@ -98,6 +98,7 @@ class InputGroup:
         pe = PriorityEncoder(self.num_rows)
         m.submodules.selector = pe
         m.submodules.out_op = self.out_op
+        m.submodules.out_op_v = self.out_op.v
         m.submodules += self.rs
 
         # connect priority encoder
@@ -105,12 +106,26 @@ class InputGroup:
         for i in range(self.num_rows):
             in_ready.append(self.rs[i].ready)
         m.d.comb += pe.i.eq(Cat(*in_ready))
-        m.d.comb += self.out_op.stb.eq(~pe.n) # strobe-out when encoder active
 
-        with m.If(self.out_op.trigger):
+        active = Signal(reset_less=True)
+        out_en = Signal(reset_less=True)
+        m.d.comb += active.eq(~pe.n) # encoder active
+        m.d.comb += out_en.eq(active & self.out_op.trigger)
+
+        # encoder active: ack relevant input, record MID, pass output
+        with m.If(out_en):
+            rs = self.rs[pe.o]
             m.d.sync += self.mid.eq(pe.o)
+            m.d.sync += rs.ack.eq(0)
+            m.d.sync += self.out_op.stb.eq(0)
             for j in range(self.num_ops):
-                m.d.sync += self.out_op.v[j].eq(self.rs[pe.o].out_op[j])
+                m.d.sync += self.out_op.v[j].eq(rs.out_op[j])
+        with m.Else():
+            m.d.sync += self.out_op.stb.eq(1)
+            # acks all default to zero
+            for i in range(self.num_rows):
+                m.d.sync += self.rs[i].ack.eq(1)
+
         return m
 
     def ports(self):
index c4be8004758974500c0b156e672509a46dd6d7af..ca8523dd591120418deaaadf6b126666bd4fafc8 100644 (file)
@@ -1,7 +1,7 @@
 from random import randint
 from nmigen import Module, Signal
 from nmigen.compat.sim import run_simulation
-from nmigen.cli import verilog
+from nmigen.cli import verilog, rtlil
 
 from nmigen_add_experiment import InputGroup
 
@@ -15,54 +15,93 @@ def testbench(dut):
     # set row 1 input 0
     yield dut.rs[1].in_op[0].eq(5)
     yield dut.rs[1].stb.eq(0b01) # strobe indicate 1st op ready
-    yield dut.rs[1].ack.eq(1)
-    yield
+    #yield dut.rs[1].ack.eq(1)
     yield
 
     # check row 1 output (should be inactive)
     decode = yield dut.rs[1].out_decode
     assert decode == 0
-    op0 = yield dut.rs[1].out_op[0]
-    op1 = yield dut.rs[1].out_op[1]
-    assert op0 == 0 and op1 == 0
+    if False:
+        op0 = yield dut.rs[1].out_op[0]
+        op1 = yield dut.rs[1].out_op[1]
+        assert op0 == 0 and op1 == 0
 
     # output should be inactive
     out_stb = yield dut.out_op.stb
-    assert out_stb == 0
+    assert out_stb == 1
 
     # set row 0 input 1
     yield dut.rs[1].in_op[1].eq(6)
     yield dut.rs[1].stb.eq(0b11) # strobe indicate both ops ready
-    yield
-    yield
 
-    # row 0 output should be active
-    decode = yield dut.rs[1].out_decode
-    assert decode == 1
-    op0 = yield dut.rs[1].out_op[0]
-    op1 = yield dut.rs[1].out_op[1]
-    assert op0 == 5 and op1 == 6
+    # set acknowledgement of output... takes 1 cycle to respond
+    yield dut.out_op.ack.eq(1)
+    yield
+    yield dut.out_op.ack.eq(0) # clear ack on output
+    yield dut.rs[1].stb.eq(0) # clear row 1 strobe
 
-    # output should be active, MID should be 0 until "ack" is set
+    # output strobe should be active, MID should be 0 until "ack" is set...
     out_stb = yield dut.out_op.stb
     assert out_stb == 1
     out_mid = yield dut.mid
     assert out_mid == 0
 
-    yield dut.out_op.ack.eq(1)
-    yield
-    yield
-    yield
+    # ... and output should not yet be passed through either
+    op0 = yield dut.out_op.v[0]
+    op1 = yield dut.out_op.v[1]
+    assert op0 == 0 and op1 == 0
+
+    # wait for out_op.ack to activate...
+    yield dut.rs[1].stb.eq(0b00) # set row 1 strobes to zero
     yield
 
+    # *now* output should be passed through
     op0 = yield dut.out_op.v[0]
     op1 = yield dut.out_op.v[1]
     assert op0 == 5 and op1 == 6
 
+    # set row 2 input
+    yield dut.rs[2].in_op[0].eq(3)
+    yield dut.rs[2].in_op[1].eq(4)
+    yield dut.rs[2].stb.eq(0b11) # strobe indicate 1st op ready
+    yield dut.out_op.ack.eq(1) # set output ack
+    yield
+    yield dut.rs[2].stb.eq(0) # clear row 2 strobe
+    yield dut.out_op.ack.eq(0) # set output ack
+    yield
+    op0 = yield dut.out_op.v[0]
+    op1 = yield dut.out_op.v[1]
+    assert op0 == 3 and op1 == 4, "op0 %d op1 %d" % (op0, op1)
+    out_mid = yield dut.mid
+    assert out_mid == 2
+
+    # set row 0 and 3 input
+    yield dut.rs[0].in_op[0].eq(9)
+    yield dut.rs[0].in_op[1].eq(8)
+    yield dut.rs[0].stb.eq(0b11) # strobe indicate 1st op ready
+    yield dut.rs[3].in_op[0].eq(1)
+    yield dut.rs[3].in_op[1].eq(2)
+    yield dut.rs[3].stb.eq(0b11) # strobe indicate 1st op ready
+
+    # set acknowledgement of output... takes 1 cycle to respond
+    yield dut.out_op.ack.eq(1)
+    yield
+    yield dut.rs[0].stb.eq(0) # clear row 1 strobe
+    yield
+    out_mid = yield dut.mid
+    assert out_mid == 0, "out mid %d" % out_mid
+
+    yield
+    yield dut.rs[3].stb.eq(0) # clear row 1 strobe
+    yield dut.out_op.ack.eq(0) # clear ack on output
+    yield
+    out_mid = yield dut.mid
+    assert out_mid == 3, "out mid %d" % out_mid
+
 
 if __name__ == '__main__':
     dut = InputGroup(width=32)
-    vl = verilog.convert(dut, ports=dut.ports())
-    with open("test_inputgroup.v", "w") as f:
+    vl = rtlil.convert(dut, ports=dut.ports())
+    with open("test_inputgroup.il", "w") as f:
         f.write(vl)
     run_simulation(dut, testbench(dut), vcd_name="test_inputgroup.vcd")