Improved iomux logic based on lessons from gpio block. Test ordered or randomised.
authorAndrey Miroshnikov <andrey@technepisteme.xyz>
Tue, 31 May 2022 13:11:51 +0000 (14:11 +0100)
committerAndrey Miroshnikov <andrey@technepisteme.xyz>
Tue, 31 May 2022 13:11:51 +0000 (14:11 +0100)
src/spec/iomux.py

index 61e772b990b034c7ef74e8ff9a66c0cf045e9982..83f22d174506c23a9a79f82ac8c94a600a38c895 100644 (file)
@@ -5,7 +5,7 @@ testing, however it could also be used as an actual GPIO peripheral
 
 Modified for use with pinmux, will probably change the class name later.
 """
 
 Modified for use with pinmux, will probably change the class name later.
 """
-from random import randint
+from random import randint, shuffle
 #from math import ceil, floor
 from nmigen import Elaboratable, Module, Signal, Record, Array, Cat
 from nmigen.hdl.rec import Layout
 #from math import ceil, floor
 from nmigen import Elaboratable, Module, Signal, Record, Array, Cat
 from nmigen.hdl.rec import Layout
@@ -30,15 +30,15 @@ io_layout = (("i", 1),
 
 class IOMuxBlockSingle(Elaboratable):
 
 
 class IOMuxBlockSingle(Elaboratable):
 
-    def __init__(self):
+    def __init__(self, n_banks=4):
         print("1-bit IO Mux Block")
         print("1-bit IO Mux Block")
-        self.n_banks = 4
+        self.n_banks = n_banks
         self.bank = Signal(log2_int(self.n_banks))
 
         temp = []
         for i in range(self.n_banks):
         self.bank = Signal(log2_int(self.n_banks))
 
         temp = []
         for i in range(self.n_banks):
-            temp_str = "bank{}".format(i)
-            temp.append(Record(name=temp_str, layout=io_layout))
+            name = "bank%d" % i
+            temp.append(Record(name=name, layout=io_layout))
         self.bank_ports = Array(temp)
 
         self.out_port = Record(name="IO", layout=io_layout)
         self.bank_ports = Array(temp)
 
         self.out_port = Record(name="IO", layout=io_layout)
@@ -53,22 +53,11 @@ class IOMuxBlockSingle(Elaboratable):
 
         # Connect IO Pad output port to one of the peripheral IOs
         # Connect peripheral inputs to the IO pad input
 
         # Connect IO Pad output port to one of the peripheral IOs
         # Connect peripheral inputs to the IO pad input
+        comb += self.out_port.o.eq(self.bank_ports[bank].o)
+        comb += self.out_port.oe.eq(self.bank_ports[bank].oe)
+
+        comb += self.bank_ports[bank].i.eq(self.out_port.i)
 
 
-        # const
-        BANK0_WB = 0
-        BANK1_P1 = 1
-        BANK2_P2 = 2
-        BANK3_P3 = 3
-
-        with m.Switch(bank):
-            with m.Case(BANK0_WB):
-                self.connect_bank_to_io(comb, BANK0_WB)
-            with m.Case(BANK1_P1):
-                self.connect_bank_to_io(comb, BANK1_P1)
-            with m.Case(BANK2_P2):
-                self.connect_bank_to_io(comb, BANK2_P2)
-            with m.Case(BANK3_P3):
-                self.connect_bank_to_io(comb, BANK3_P3)
         return m
 
     def connect_bank_to_io(self, domain, bank_arg):
         return m
 
     def connect_bank_to_io(self, domain, bank_arg):
@@ -80,7 +69,7 @@ class IOMuxBlockSingle(Elaboratable):
         """ Get member signals for Verilog form. """
         for field in self.out_port.fields.values():
             yield field
         """ Get member signals for Verilog form. """
         for field in self.out_port.fields.values():
             yield field
-        for bank in range(len(self.bank_ports)):
+        for bank in range(self.n_banks):
             for field in self.bank_ports[bank].fields.values():
                 yield field
         yield self.bank
             for field in self.bank_ports[bank].fields.values():
                 yield field
         yield self.bank
@@ -88,6 +77,97 @@ class IOMuxBlockSingle(Elaboratable):
     def ports(self):
         return list(self)
 
     def ports(self):
         return list(self)
 
+# Method to test a particular bank port
+# when rand_order is True, previous and consecutive banks are
+# random (but NOT equal to given bank)
+def test_single_bank(dut, bank, rand_order=True, delay=1e-6):
+    if rand_order:
+        print("Randomising the prev and next banks")
+        prev_bank=bank
+        while(prev_bank == bank):
+            prev_bank = randint(0, dut.n_banks-1)
+        next_bank=bank
+        while(next_bank == bank):
+            next_bank = randint(0, dut.n_banks-1)
+    else:
+        # Set the prev and next banks as consecutive banks
+        if bank == 0:
+            prev_bank = dut.n_banks - 1
+        else:
+            prev_bank = bank - 1
+
+        if bank == dut.n_banks:
+            next_bank = 0
+        else:
+            next_bank = bank + 1
+
+    print("Prev=%d, Given=%d, Next=%d" % (prev_bank, bank, next_bank))
+
+    # Clear o/oe, delay, set port i
+    # Set to previous bank, delay
+    # Assert bank i == 0
+    # Set to desired bank
+    # Assert bank i == 1
+    # Set o/oe, delay
+    # Assert o, oe == 1
+    # Set to next bank, delay
+    # Assert bank i == 0
+    yield dut.bank_ports[bank].o.eq(0)
+    yield Delay(delay)
+    yield dut.bank_ports[bank].oe.eq(0)
+    yield Delay(delay)
+    yield dut.out_port.i.eq(1)
+    yield Delay(delay)
+
+    yield dut.bank.eq(prev_bank)
+    yield Delay(delay)
+
+    test_i = yield dut.bank_ports[bank].i
+    assert(test_i == 0)
+
+    yield dut.bank.eq(bank)
+    yield Delay(delay)
+
+    test_o = yield dut.out_port.o
+    test_oe = yield dut.out_port.oe
+    test_i = yield dut.bank_ports[bank].i
+    assert(test_o == 0)
+    assert(test_oe == 0)
+    assert(test_i == 1)
+
+    yield dut.bank_ports[bank].o.eq(1)
+    yield Delay(delay)
+    yield dut.bank_ports[bank].oe.eq(1)
+    yield Delay(delay)
+
+    test_o = yield dut.out_port.o
+    test_oe = yield dut.out_port.oe
+    assert(test_o == 1)
+    assert(test_oe == 1)
+
+    yield dut.bank.eq(next_bank)
+    yield Delay(delay)
+
+    test_i = yield dut.bank_ports[bank].i
+    assert(test_i == 0)
+
+def test_iomux(dut, rand_order=True):
+    print("------START----------------------")
+    #print(dir(dut.bank_ports[0]))
+    #print(dut.bank_ports[0].fields)
+
+    # Produce a test list of bank values
+    test_bank_vec = list(range(0, dut.n_banks))
+    #print(test_bank_vec)
+    # Randomise for wider testing
+    if rand_order:
+        shuffle(test_bank_vec)
+        #print(test_bank_vec)
+    for i in range(dut.n_banks):
+        yield from test_single_bank(dut, test_bank_vec[i], rand_order)
+
+    print("Finished the 1-bit IO mux block test!")
+
 def gen_gtkw_doc(module_name, n_banks, filename):
     # GTKWave doc generation
     style = {
 def gen_gtkw_doc(module_name, n_banks, filename):
     # GTKWave doc generation
     style = {
@@ -100,15 +180,15 @@ def gen_gtkw_doc(module_name, n_banks, filename):
     # Create a trace list, each block expected to be a tuple()
     traces = []
     for bank in range(0, n_banks):
     # Create a trace list, each block expected to be a tuple()
     traces = []
     for bank in range(0, n_banks):
-        temp_traces = ('Bank{}'.format(bank), [
-                        ('bank{}__i'.format(bank), 'in'),
-                        ('bank{}__o'.format(bank), 'out'),
-                        ('bank{}__oe'.format(bank), 'out')
+        temp_traces = ('Bank%d' % bank, [
+                        ('bank%d__i' % bank, 'in'),
+                        ('bank%d__o' % bank, 'out'),
+                        ('bank%d__oe' % bank, 'out')
                       ])
         traces.append(temp_traces)
 
     temp_traces = ('Misc', [
                       ])
         traces.append(temp_traces)
 
     temp_traces = ('Misc', [
-                    ('bank[1:0]', 'in')
+                    ('bank[%d:0]' % ((n_banks-1).bit_length()-1), 'in')
                   ])
     traces.append(temp_traces)
     temp_traces = ('IO port to pad', [
                   ])
     traces.append(temp_traces)
     temp_traces = ('IO port to pad', [
@@ -122,9 +202,10 @@ def gen_gtkw_doc(module_name, n_banks, filename):
     write_gtkw(filename+".gtkw", filename+".vcd", traces, style,
                module=module_name)
 
     write_gtkw(filename+".gtkw", filename+".vcd", traces, style,
                module=module_name)
 
-def sim_iomux():
-    filename = "test_pinmux" # Doesn't include extension
-    dut = IOMuxBlockSingle()
+def sim_iomux(rand_order=True):
+    filename = "test_iomux" # Doesn't include extension
+    n_banks = 8
+    dut = IOMuxBlockSingle(n_banks)
     vl = rtlil.convert(dut, ports=dut.ports())
     with open(filename+".il", "w") as f:
         f.write(vl)
     vl = rtlil.convert(dut, ports=dut.ports())
     with open(filename+".il", "w") as f:
         f.write(vl)
@@ -134,91 +215,15 @@ def sim_iomux():
 
     sim = Simulator(m)
 
 
     sim = Simulator(m)
 
-    sim.add_process(wrap(test_iomux(dut)))
+    sim.add_process(wrap(test_iomux(dut, rand_order)))
     sim_writer = sim.write_vcd(filename+".vcd")
     with sim_writer:
         sim.run()
 
     gen_gtkw_doc("top.pinmux", dut.n_banks, filename)
 
     sim_writer = sim.write_vcd(filename+".vcd")
     with sim_writer:
         sim.run()
 
     gen_gtkw_doc("top.pinmux", dut.n_banks, filename)
 
-# Method for toggling i/o/oe of a particular bank port,
-# while bank_sel has three different values:
-# value before, given value, value after
-# when rand is True, previous and consecutive values are
-# random (but NOT equal to given bank_sel)
-def test_single_bank(dut, bank, rand=True):
-    if rand:
-        print("Randomising the prev and next banks")
-        prev_bank=bank
-        while(prev_bank == bank):
-            prev_bank = randint(0, dut.n_banks-1)
-        next_bank=bank
-        while(next_bank == bank):
-            next_bank = randint(0, dut.n_banks-1)
-    else:
-        if bank == 0:
-            prev_bank = dut.n_banks
-        else:
-            prev_bank = bank - 1
 
 
-        if bank == dut.n_banks:
-            next_bank = 0
-        else:
-            next_bank = bank + 1
-
-    print("Prev={}, Given={}, Next={}".format(prev_bank, bank, next_bank))
-
-    yield dut.bank.eq(prev_bank)
-    yield Delay(1e-6)
-    yield dut.bank_ports[bank].o.eq(0)
-    yield dut.bank_ports[bank].oe.eq(0)
-    yield dut.out_port.i.eq(0)
-    yield Delay(1e-6)
-
-    yield dut.bank.eq(bank)
-    yield Delay(1e-6)
-
-    test_o = yield dut.out_port.o
-    test_oe = yield dut.out_port.oe
-    test_i = yield dut.bank_ports[bank].i
-    assert(test_o == 0)
-    assert(test_oe == 0)
-    assert(test_i == 0)
-
-    yield dut.bank_ports[bank].o.eq(1)
-    yield Delay(1e-6)
-    yield dut.bank_ports[bank].oe.eq(1)
-    yield Delay(1e-6)
-    yield dut.out_port.i.eq(1)
-    yield Delay(1e-6)
-
-    test_o = yield dut.out_port.o
-    test_oe = yield dut.out_port.oe
-    test_i = yield dut.bank_ports[bank].i
-    #print(test_o, test_oe, test_i)
-    assert(test_o == 1)
-    assert(test_oe == 1)
-    assert(test_i == 1)
-
-    yield dut.bank.eq(next_bank)
-    yield Delay(1e-6)
-    yield dut.bank_ports[bank].o.eq(0)
-    yield dut.bank_ports[bank].oe.eq(0)
-    yield dut.out_port.i.eq(0)
-    yield Delay(1e-6)
-
-def test_iomux(dut):
-    print("------START----------------------")
-    #print(dir(dut.bank_ports[0]))
-    #print(dut.bank_ports[0].fields)
-
-    yield from test_single_bank(dut, 0)
-    yield from test_single_bank(dut, 1)
-    yield from test_single_bank(dut, 2)
-    yield from test_single_bank(dut, 3)
-
-    print("Finished the 1-bit IO mux block test!")
 
 if __name__ == '__main__':
 
 if __name__ == '__main__':
-    sim_iomux()
+    sim_iomux(rand_order=True)