Finally got iomux test running (but block not working yet)
authorAndrey Miroshnikov <andrey@technepisteme.xyz>
Wed, 2 Mar 2022 23:14:45 +0000 (23:14 +0000)
committerAndrey Miroshnikov <andrey@technepisteme.xyz>
Wed, 2 Mar 2022 23:14:45 +0000 (23:14 +0000)
src/spec/iomux.py

index b7d6f3a40de842b651d3eb6580ad4e67b54d25a4..e310ed95d1fc2b40e4fd6772c3274f413eb36694 100644 (file)
@@ -1,15 +1,21 @@
-"""This is the module used for multiplexing IO signals
+"""Simple GPIO peripheral on wishbone
 
-Documentation: https://libre-soc.org/docs/pinmux/temp_pinmux_info/
-Bug: https://bugs.libre-soc.org/show_bug.cgi?id=762
+This is an extremely simple GPIO peripheral intended for use in XICS
+testing, however it could also be used as an actual GPIO peripheral
+
+Modified for use with pinmux, will probably change the class name later.
 """
-#from random import randint
-from nmigen import Elaboratable, Module, Signal, Record, Array
-#from nmigen.utils import log2_int
+from random import randint
+from math import ceil, floor
+from nmigen import Elaboratable, Module, Signal, Record, Array, Cat
+from nmigen.hdl.rec import Layout
+from nmigen.utils import log2_int
 from nmigen.cli import rtlil
-#from soc.minerva.wishbone import make_wb_layout
+from soc.minerva.wishbone import make_wb_layout
 from nmutil.util import wrap
-#from soc.bus.test.wb_rw import wb_read, wb_write
+from soc.bus.test.wb_rw import wb_read, wb_write
+
+from nmutil.gtkw import write_gtkw
 
 cxxsim = False
 if cxxsim:
@@ -17,63 +23,154 @@ if cxxsim:
 else:
     from nmigen.sim import Simulator, Settle
 
+io_layout = (("i", 1),
+             ("oe", 1),
+             ("o", 1)
+            )
+
 class IOMuxBlock(Elaboratable):
 
     def __init__(self):
-        self.bank_sel = Signal()
-        
-        self.portin0 = {"i": Signal(), "o": Signal(), "oe": Signal()}
-        self.portin1 = {"i": Signal(), "o": Signal(), "oe": Signal()}
-        self.portout = {"i": Signal(), "o": Signal(), "oe": Signal()}
+        print("IO Mux Block")
+        self.n_banks = 4
+        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))
+        self.bank_ports = Array(temp)
+
+        self.out_port = Record(name="IO", layout=io_layout)
+
+        #self.b0 = Record(name="b0", layout=io_layout)
+        #self.b1 = Record(name="b1", layout=io_layout)
 
     def elaborate(self, platform):
         m = Module()
         comb, sync = m.d.comb, m.d.sync
-        
-        bank_sel = self.bank_sel
-        portin0 = self.portin0
-        portin1 = self.portin1
-        portout = self.portout
+
+        bank = self.bank
+        bank_ports = self.bank_ports
+        #b0 = self.b0
+        #b1 = self.b1
+        out_port = self.out_port
+
+        sync += out_port.o.eq(bank_ports[0].o)
+        sync += out_port.oe.eq(bank_ports[0].oe)
+        sync += bank_ports[0].i.eq(out_port.i)
+
         # Connect IO Pad output port to one of the peripheral IOs
-        comb += portout["o"].eq(Mux(bank_sel, portin1["o"], portin0["o"]))
-        comb += portout["oe"].eq(Mux(bank_sel, portin1["oe"], portin0["oe"]))
-        
         # Connect peripheral inputs to the IO pad input
-        comb += portin0["i"].eq(Mux(bank_sel, 0, portout["i"]))
-        comb += portin1["i"].eq(Mux(bank_sel, portout["i"], 0))
+
+        bank_range = range(self.n_banks)
+
+        #with m.Switch(bank):
+
+        for cur_bank in bank_range:
+            sync += out_port.o.eq(bank_ports[cur_bank].o)
+            sync += out_port.oe.eq(bank_ports[cur_bank].oe)
+            sync += bank_ports[cur_bank].i.eq(out_port.i)
+
+            temp_list = list(bank_range)
+            temp_list.pop(temp_list.index(cur_bank))
+            print("Banks with input hardwired to zero: {}".format(temp_list))
+            for j in range(len(temp_list)):
+                unused_bank = temp_list[j]
+                sync += bank_ports[unused_bank].i.eq(0)
 
         return m
 
+    def __iter__(self):
+        """ 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 field in self.bank_ports[bank].fields.values():
+                yield field
+        yield self.bank
+
     def ports(self):
         return list(self)
 
-def sim_iomux(dut):
-    # start by setting portin0
-    dut.portin0["o"].eq(1)
-    dut.portin0["oe"].eq(1)
-    yield
-    dut.portout["i"].eq(1)
-    
-    print("Finished the IO mux block test!")
-
-def test_iomux():
-
+def gen_gtkw_doc(module_name, n_banks, filename):
+    # GTKWave doc generation
+    style = {
+        '': {'base': 'hex'},
+        'in': {'color': 'orange'},
+        'out': {'color': 'yellow'},
+        'debug': {'module': 'top', 'color': 'red'}
+    }
+
+    # 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')
+                      ])
+        traces.append(temp_traces)
+    #print(traces)
+
+    write_gtkw(filename+".gtkw", filename+".vcd", traces, style,
+               module=module_name)
+
+def sim_iomux():
+    filename = "test_pinmux" # Doesn't include extension
     dut = IOMuxBlock()
     vl = rtlil.convert(dut, ports=dut.ports())
-    with open("test_gpio.il", "w") as f:
+    with open(filename+".il", "w") as f:
         f.write(vl)
 
     m = Module()
+    m.submodules.pinmux = dut
+
+    sim = Simulator(m)
+    sim.add_clock(1e-6)
+
+    sim.add_sync_process(wrap(test_iomux(dut)))
+    sim_writer = sim.write_vcd(filename+".vcd")
+    with sim_writer:
+        sim.run()
+
+    gen_gtkw_doc("top.pinmux", dut.n_banks, filename)
+
+def test_iomux(dut):
+    print("------START----------------------")
+    #print(dir(dut.bank_ports[0]))
+    #print(dut.bank_ports[0].fields)
+    #for (name, signal) in dut.b0.fields.items():
+    #    print(name, signal)
+    #print(dir(dut.bank_ports))
+    #print(dut.bank_ports.__len__())
+    #for bank in range(len(dut.bank_ports)):
+    #    for values in dut.bank_ports[bank].fields.values():
+    #        print(values)
+    yield dut.bank_ports[0].o.eq(1)
+    yield dut.bank.eq(0)
+    yield
+    yield dut.bank_ports[0].o.eq(1)
+    yield
+    yield
+    yield dut.bank_ports[1].o.eq(1)
+    yield
+    yield dut.bank_ports[0].oe.eq(1)
+    yield
+    yield dut.bank.eq(1)
+    yield
 
-    #sim = Simulator(m)
-    #sim.add_clock(1e-6)
-
-    #sim.add_sync_process(wrap(sim_gpio(dut)))
-    #sim_writer = sim.write_vcd('test_gpio.vcd')
-    #with sim_writer:
-    #    sim.run()
+    yield dut.bank_ports[0].o.eq(0)
+    yield
+    yield dut.bank_ports[1].o.eq(0)
+    yield
+    yield dut.bank_ports[1].oe.eq(1)
+    yield
+    yield dut.bank.eq(0)
+    yield
 
+    print("Finished the IO mux block test!")
 
 if __name__ == '__main__':
-    test_iomux()
+    sim_iomux()