feat(stage2): Moved up a directory to work with the PinSpec imports
authorAndrey Miroshnikov <andrey@technepisteme.xyz>
Tue, 27 Sep 2022 19:47:06 +0000 (19:47 +0000)
committerAndrey Miroshnikov <andrey@technepisteme.xyz>
Tue, 27 Sep 2022 19:47:06 +0000 (19:47 +0000)
src/spec/stage2.py [deleted file]
src/stage2.py [new file with mode: 0644]

diff --git a/src/spec/stage2.py b/src/spec/stage2.py
deleted file mode 100644 (file)
index 2219616..0000000
+++ /dev/null
@@ -1,478 +0,0 @@
-#!/usr/bin/env python3
-"""
-pinmux documented here https://libre-soc.org/docs/pinmux/
-"""
-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 nmutil.util import wrap
-#from soc.bus.test.wb_rw import wb_read, wb_write
-
-from nmutil.gtkw import write_gtkw
-
-cxxsim = False
-if cxxsim:
-    from nmigen.sim.cxxsim import Simulator, Settle, Delay
-else:
-    from nmigen.sim import Simulator, Settle, Delay
-
-from iomux import IOMuxBlockSingle
-from base import PinSpec
-from jtag import iotypes
-
-io_layout = (("i", 1),
-             ("oe", 1),
-             ("o", 1)
-            )
-
-uart_layout = (("rx", 1),
-               ("tx", 1),
-               ("oe", 1)
-              )
-uart_tx_layout = (("o", 1),
-                 ("oe", 1)
-                 )
-GPIO_BANK = 0
-UART_BANK = 1
-I2C_BANK = 2
-
-"""
-Really basic example, uart tx/rx and i2c sda/scl pinmux
-"""
-class ManPinmux(Elaboratable):
-    def __init__(self, requested):
-        print("Test Manual Pinmux!")
-
-        self.requested = requested
-        self.n_banks = 4
-        self.bank = Signal(log2_int(self.n_banks))
-        self.pads = {}
-        self.muxes = {}
-        # Automatically create the necessary periph/pad Records/Signals
-        # depending on the given dict specification
-        for pad in self.requested.keys():
-            self.pads[pad] = {}
-            self.pads[pad]["pad"] = Record(name=pad, layout=io_layout)
-            self.muxes[pad] = IOMuxBlockSingle(self.n_banks)
-            for mux in self.requested[pad].keys():
-                periph = self.requested[pad][mux][0]
-                unit = self.requested[pad][mux][1]
-                sig = self.requested[pad][mux][2][:-1]
-                sig_type = iotypes[self.requested[pad][mux][2][-1]]
-                #print(sig, sig_type)
-                if sig_type == iotypes['*']:
-                    self.pads[pad][mux] = Record(name="%s%d" % (sig, unit),
-                                                 layout=io_layout)
-                elif sig_type == iotypes['+']:
-                    self.pads[pad][mux] = Signal(name="%s%d_o" % (sig, unit))
-                elif sig_type == iotypes['-']:
-                    self.pads[pad][mux] = Signal(name="%s%d_i" % (sig, unit))
-        print(self.pads)
-
-    def elaborate(self, platform):
-        m = Module()
-        comb, sync = m.d.comb, m.d.sync
-        muxes = self.muxes
-        bank = self.bank
-        pads = self.pads
-        for pad in pads.keys():
-            m.submodules[pad+"_mux"] = muxes[pad]
-            # all muxes controlled by the same multi-bit signal
-            comb += muxes[pad].bank.eq(bank)
-
-        # print(self.requested)
-        # print(self.pads)
-
-        # ---------------------------
-        # This section connects the periphs to the assigned banks
-        # ---------------------------
-        for pad in pads.keys():
-            for mux in self.requested[pad].keys():
-                periph = self.requested[pad][mux][0]
-                num = int(mux[3])
-                sig = self.requested[pad][mux][2][:-1]
-                sig_type = iotypes[self.requested[pad][mux][2][-1]]
-                if sig_type == iotypes['*']:
-                    comb += muxes[pad].bank_ports[num].o.eq(pads[pad][mux].o)
-                    comb += muxes[pad].bank_ports[num].oe.eq(pads[pad][mux].oe)
-                    comb += pads[pad][mux].i.eq(muxes[pad].bank_ports[num].i)
-                elif sig_type == iotypes['+']:
-                    comb += muxes[pad].bank_ports[num].o.eq(pads[pad][mux])
-                elif sig_type == iotypes['-']:
-                    comb += pads[pad][mux].eq(muxes[pad].bank_ports[num].i)
-        # ---------------------------
-        # Here is where the muxes are assigned to the actual pads
-        # ---------------------------
-        for pad in pads.keys():
-            comb += pads[pad]["pad"].o.eq(muxes[pad].out_port.o)
-            comb += pads[pad]["pad"].oe.eq(muxes[pad].out_port.oe)
-            comb += muxes[pad].out_port.i.eq(pads[pad]["pad"].i)
-
-        return m
-
-    def __iter__(self):
-        for pad in list(self.pads.keys()):
-            for field in self.pads[pad]["pad"].fields.values():
-                yield field
-            for mux in self.pads[pad].keys():
-                if type(self.pads[pad][mux]) == Signal:
-                    yield self.pads[pad][mux]
-                else:
-                    for field in self.pads[pad][mux].fields.values():
-                        yield field
-        yield self.bank
-
-    def ports(self):
-        return list(self)
-
-def set_bank(dut, bank, delay=1e-6):
-    yield dut.bank.eq(bank)
-    yield Delay(delay)
-
-"""
-GPIO test function
-Set the gpio output based on given data sequence, checked at pad.o
-Then sends the same byte via pad.i to gpio input
-"""
-def gpio(gpio, pad, data, delay=1e-6):
-    # Output test - Control GPIO output
-    yield gpio.oe.eq(1)
-    yield Delay(delay)
-    n_bits = len(bin(data)[2:])
-    read = 0
-    for i in range(0, n_bits):
-        bit = (data >> i) & 0x1
-        yield gpio.o.eq(bit)
-        yield Delay(delay)
-        temp = yield pad.o
-        read |= (temp << i)
-    assert data == read, f"GPIO Sent: %x | Pad Read: %x" % (data, read)
-    # Input test - Control Pad input
-    yield gpio.oe.eq(0)
-    yield Delay(delay)
-    read2 = 0
-    for i in range(0, n_bits):
-        bit = (read >> i) & 0x1
-        yield pad.i.eq(bit)
-        yield Delay(delay)
-        temp = yield gpio.i
-        read2 |= (temp << i)
-    assert read2 == read, f"Pad Sent: %x | GPIO Read: %x" % (data, read)
-    # reset input signal
-    yield pad.i.eq(0)
-    yield Delay(delay)
-
-"""
-UART test function
-Sends a byte via uart tx, checked at output pad
-Then sends the same byte via input pad to uart rx
-Input and output pads are different, so must specify both
-"""
-def uart_send(tx, rx, pad_tx, pad_rx, byte, delay=1e-6):
-    # Drive uart tx - check the word seen at the Pad
-    print(type(tx))
-    #yield tx.oe.eq(1)
-    yield tx.eq(1)
-    yield Delay(2*delay)
-    yield tx.eq(0) # start bit
-    yield Delay(delay)
-    read = 0
-    # send one byte, lsb first
-    for i in range(0, 8):
-        bit = (byte >> i) & 0x1
-        yield tx.eq(bit)
-        yield Delay(delay)
-        test_bit = yield pad_tx.o
-        read |= (test_bit << i)
-    yield tx.eq(1) # stop bit
-    yield Delay(delay)
-    assert byte == read, f"UART Sent: %x | Pad Read: %x" % (byte, read)
-    # Drive Pad i - check word at uart rx
-    yield pad_rx.i.eq(1)
-    yield Delay(2*delay)
-    yield pad_rx.i.eq(0) # start bit
-    yield Delay(delay)
-    read2 = 0
-    for i in range(0, 8):
-        bit = (read >> i) & 0x1
-        yield pad_rx.i.eq(bit)
-        yield Delay(delay)
-        test_bit = yield rx
-        read2 |= (test_bit << i)
-    yield pad_rx.i.eq(1) # stop bit
-    yield Delay(delay)
-    assert read == read2, f"Pad Sent: %x | UART Read: %x" % (read, read2)
-
-"""
-I2C test function
-Sends a byte via SDA.o (peripheral side), checked at output pad
-Then sends the same byte via input pad to master SDA.i
-This transaction doesn't make the distinction between read/write bit.
-"""
-def i2c_send(sda, scl, sda_pad, byte, delay=1e-6):
-    # No checking yet
-    # No pull-up on line implemented, set high instead
-    yield sda.oe.eq(1)
-    yield sda.o.eq(1)
-    yield scl.oe.eq(1)
-    yield scl.o.eq(1)
-    yield sda_pad.i.eq(1)
-    yield Delay(delay)
-    read = 0
-    yield sda.o.eq(0) # start bit
-    yield Delay(delay)
-    for i in range(0, 8):
-        bit = (byte >> i) & 0x1
-        yield sda.o.eq(bit)
-        yield scl.o.eq(0)
-        yield Delay(delay/2)
-        yield scl.o.eq(1)
-        temp = yield sda_pad.o
-        read |= (temp << i)
-        yield Delay(delay/2)
-    yield sda.o.eq(1) # Master releases SDA line
-    yield sda.oe.eq(0)
-    assert byte == read, f"I2C Sent: %x | Pad Read: %x" % (byte, read)
-    # Slave ACK
-    yield sda_pad.i.eq(0)
-    yield scl.o.eq(0)
-    yield Delay(delay/2)
-    yield scl.o.eq(1)
-    yield Delay(delay/2)
-    # Send byte back to master
-    read2 = 0
-    for i in range(0, 8):
-        bit = (read >> i) & 0x1
-        yield sda_pad.i.eq(bit)
-        yield scl.o.eq(0)
-        yield Delay(delay/2)
-        yield scl.o.eq(1)
-        temp = yield sda.i
-        read2 |= (temp << i)
-        yield Delay(delay/2)
-    assert read == read2, f"Pad Sent: %x | I2C Read: %x" % (read, read2)
-    # Master ACK
-    yield sda.oe.eq(1)
-    yield sda.o.eq(0)
-    yield scl.o.eq(0)
-    yield Delay(delay/2)
-    yield scl.o.eq(1)
-    yield Delay(delay/2)
-    # Stop condition - SDA line high after SCL high
-    yield scl.o.eq(0)
-    yield Delay(delay/2)
-    yield scl.o.eq(1)
-    yield Delay(delay/2)
-    yield sda.o.eq(1) # 'release' the SDA line
-
-# Test the GPIO/UART/I2C connectivity
-def test_man_pinmux(dut, requested):
-    # TODO: Convert to automatic
-    # [{"pad":%s, "bank":%d}, {"pad":%s, "bank":%d},...]
-    #gpios = [{"padname":"N1", "bank":GPIO_BANK},
-    #         {"padname":"N2", "bank":GPIO_BANK}]
-    # [[txPAD, MUXx, rxPAD, MUXx],...] - diff banks not supported yet
-    uarts = [{"txpadname":"N1", "rxpadname":"N2", "bank":UART_BANK}]
-    # [[sdaPAD, MUXx, sclPAD, MUXx],...] - diff banks not supported yet
-    i2cs = [{"sdapadname":"N1", "sclpadname":"N2", "bank":I2C_BANK}]
-
-    gpios = []
-    delay = 1e-6
-    for pad in requested.keys():
-        for mux in requested[pad].keys():
-            periph = requested[pad][mux][0]
-
-            if periph == "gpio":
-                # [{"padname":%s, "bank": %d}, ...]
-                gpios.append({"padname":pad, "bank": int(mux[3])})
-            if periph == "uart":
-                # TODO:
-                pass
-            if periph == "i2c":
-                # TODO:
-                pass
-    print(gpios)
-    # GPIO test
-    for gpio_periph in gpios:
-        padname = gpio_periph["padname"]
-        gpio_bank = gpio_periph["bank"]
-        gp = dut.pads[padname]["mux%d" % gpio_bank]
-        pad = dut.pads[padname]["pad"]
-        yield from set_bank(dut, gpio_bank)
-        yield from gpio(gp, pad, 0x5a5)
-
-    # UART test
-    for uart_periph in uarts:
-        txpadname = uart_periph["txpadname"]
-        rxpadname = uart_periph["rxpadname"]
-        uart_bank = uart_periph["bank"]
-        tx = dut.pads[txpadname]["mux%d" % uart_bank]
-        rx = dut.pads[rxpadname]["mux%d" % uart_bank]
-        txpad = dut.pads[txpadname]["pad"]
-        rxpad = dut.pads[rxpadname]["pad"]
-        yield from set_bank(dut, UART_BANK)
-        yield from uart_send(tx, rx, txpad, rxpad, 0x42)
-
-    # I2C test
-    for i2c_periph in i2cs:
-        sdapadname = i2c_periph["sdapadname"]
-        sclpadname = i2c_periph["sclpadname"]
-        i2c_bank = i2c_periph["bank"]
-        sda = dut.pads[sdapadname]["mux%d" % i2c_bank]
-        scl = dut.pads[sclpadname]["mux%d" % i2c_bank]
-        sdapad = dut.pads[sdapadname]["pad"]
-
-    yield from set_bank(dut, I2C_BANK)
-    yield from i2c_send(sda, scl, sdapad, 0x67)
-
-def gen_gtkw_doc(module_name, requested, 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 = []
-    temp = 0
-    n_banks = 0
-    for pad in requested.keys():
-        temp = len(requested[pad].keys())
-        if n_banks < temp:
-            n_banks = temp
-        temp_traces = ("Pad %s" % pad, [])
-        # Pad signals
-        temp_traces[1].append(('%s__i' % pad, 'in'))
-        temp_traces[1].append(('%s__o' % pad, 'out'))
-        temp_traces[1].append(('%s__oe' % pad, 'out'))
-        for mux in requested[pad].keys():
-            periph = requested[pad][mux][0]
-            unit_num = requested[pad][mux][1]
-            if len(requested[pad][mux]) == 3:
-                pin = requested[pad][mux][2]
-            else:
-                pin = "io"
-
-            if periph == "gpio":
-                temp_traces[1].append(('gp%d__i' % unit_num, 'in'))
-                temp_traces[1].append(('gp%d__o' % unit_num, 'out'))
-                temp_traces[1].append(('gp%d__oe' % unit_num, 'out'))
-            elif periph == "uart":
-                if pin == "tx":
-                    temp_traces[1].append(('tx%d__o' % unit_num, 'out'))
-                    temp_traces[1].append(('tx%d__oe' % unit_num, 'out'))
-                    pass
-                elif pin == "rx":
-                    temp_traces[1].append(('rx%d' % unit_num, 'in'))
-                    pass
-            elif periph == "i2c":
-                temp_traces[1].append(('%s%d__i' % (pin, unit_num), 'in'))
-                temp_traces[1].append(('%s%d__o' % (pin, unit_num), 'out'))
-                temp_traces[1].append(('%s%d__oe' % (pin, unit_num), 'out'))
-        traces.append(temp_traces)
-
-    # master bank signal
-    temp_traces = ('Misc', [
-                    ('bank[%d:0]' % ((n_banks-1).bit_length()-1), 'in')
-                  ])
-    traces.append(temp_traces)
-
-    #print(traces)
-
-    write_gtkw(filename+".gtkw", filename+".vcd", traces, style,
-               module=module_name)
-
-
-def sim_man_pinmux():
-    filename = "test_man_pinmux"
-    requested = {"N1": {"mux%d" % GPIO_BANK: ["gpio", 0, '0*'],
-                        "mux%d" % UART_BANK: ["uart", 0, 'tx+'],
-                        "mux%d" % I2C_BANK: ["i2c", 0, 'sda*']},
-                 "N2": {"mux%d" % GPIO_BANK: ["gpio", 1, '*'],
-                        "mux%d" % UART_BANK: ["uart", 0, 'rx-'],
-                        "mux%d" % I2C_BANK: ["i2c", 0, 'scl*']},
-                 "N3": {"mux%d" % GPIO_BANK: ["gpio", 2, '0*']},
-                 "N4": {"mux%d" % GPIO_BANK: ["gpio", 3, '0*']}
-                }
-    dut = ManPinmux(requested)
-    vl = rtlil.convert(dut, ports=dut.ports())
-    with open(filename+".il", "w") as f:
-        f.write(vl)
-
-    m = Module()
-    m.submodules.manpinmux = dut
-
-    sim = Simulator(m)
-
-    sim.add_process(wrap(test_man_pinmux(dut, requested)))
-    sim_writer = sim.write_vcd(filename+".vcd")
-    with sim_writer:
-        sim.run()
-    gen_gtkw_doc("top.manpinmux", dut.requested, filename)
-
-if __name__ == '__main__':
-    sim_man_pinmux()
-    #pinbanks = []
-    #fixedpins = []
-    #function_names = []
-    #testspec = PinSpec()
-    pinbanks = {
-        'A': (4, 4), # (num of pads, num of banks)?
-        #'B': (18, 4),
-        #'C': (24, 1),
-        #'D': (93, 1),
-    }
-    fixedpins = {
-        'POWER_GPIO': [
-            'VDD_GPIOB',
-            'GND_GPIOB',
-        ]}
-    function_names = {'TWI0': 'I2C 0',
-                      'UART0': 'UART (TX/RX) 0',
-                     }
-    ps = PinSpec(pinbanks, fixedpins, function_names)
-    # Unit number, (Bank, pin #), mux, start, num # pins
-    ps.gpio("", ('A', 0), 0, 0, 4)
-    ps.uart("0", ('A', 0), 1)
-    ps.i2c("0", ('A', 0), 2)
-
-    print(dir(ps.gpio))
-    #print(ps.gpio.pinouts, ps.gpio.bankspec, ps.gpio.pinfn, ps.gpio.fname)
-    """
-    desc_dict_keys = ['UART0', 'TWI0', 'GPIOA_A0', 'GPIOA_A1', 'GPIOA_A2', 'GPIOA_A3']
-    eint = []
-    pwm = []
-    desc = {'UART0': 'Basic serial TX/RX serial port',
-            'TWI0': 'I2C interface',
-            'GPIOA_A0': 'Test GPIO0',
-            'GPIOA_A1': 'Test GPIO1',
-            'GPIOA_A2': 'Test GPIO2',
-            'GPIOA_A3': 'Test GPIO3'}
-    ps.add_scenario("Test Manual Pinmux", desc_dict_keys, eint, pwm, desc)
-    """
-    print("---------------------------------")
-    #with open("test.mdwn", "w") as of:
-    #    pinout, bankspec, pin_spec, fixedpins = ps.write(of)
-    #print("---------------------------------")
-
-    bk = ps.pinbanks.keys()
-    for bank in bk:
-        muxwidth = ps.muxwidths[bank]
-        print(bank, muxwidth)
-        pinidx = sorted(ps.keys())
-        for pin in pinidx:
-            print("---------------------------------")
-            print(pin)
-            pdata = ps.get(pin)
-            for mux in range(muxwidth):
-                if mux not in pdata:
-                    print("Mux %d : NC" % mux)
-                else:
-                    name, assigned_bank = pdata[mux]
-                    print("Mux %d : %s" % (mux, name))
-
-
-
diff --git a/src/stage2.py b/src/stage2.py
new file mode 100644 (file)
index 0000000..1d9374f
--- /dev/null
@@ -0,0 +1,478 @@
+#!/usr/bin/env python3
+"""
+pinmux documented here https://libre-soc.org/docs/pinmux/
+"""
+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 nmutil.util import wrap
+#from soc.bus.test.wb_rw import wb_read, wb_write
+
+from nmutil.gtkw import write_gtkw
+
+cxxsim = False
+if cxxsim:
+    from nmigen.sim.cxxsim import Simulator, Settle, Delay
+else:
+    from nmigen.sim import Simulator, Settle, Delay
+
+from spec.iomux import IOMuxBlockSingle
+from spec.base import PinSpec
+from spec.jtag import iotypes
+
+io_layout = (("i", 1),
+             ("oe", 1),
+             ("o", 1)
+            )
+
+uart_layout = (("rx", 1),
+               ("tx", 1),
+               ("oe", 1)
+              )
+uart_tx_layout = (("o", 1),
+                 ("oe", 1)
+                 )
+GPIO_BANK = 0
+UART_BANK = 1
+I2C_BANK = 2
+
+"""
+Really basic example, uart tx/rx and i2c sda/scl pinmux
+"""
+class ManPinmux(Elaboratable):
+    def __init__(self, requested):
+        print("Test Manual Pinmux!")
+
+        self.requested = requested
+        self.n_banks = 4
+        self.bank = Signal(log2_int(self.n_banks))
+        self.pads = {}
+        self.muxes = {}
+        # Automatically create the necessary periph/pad Records/Signals
+        # depending on the given dict specification
+        for pad in self.requested.keys():
+            self.pads[pad] = {}
+            self.pads[pad]["pad"] = Record(name=pad, layout=io_layout)
+            self.muxes[pad] = IOMuxBlockSingle(self.n_banks)
+            for mux in self.requested[pad].keys():
+                periph = self.requested[pad][mux][0]
+                unit = self.requested[pad][mux][1]
+                sig = self.requested[pad][mux][2][:-1]
+                sig_type = iotypes[self.requested[pad][mux][2][-1]]
+                #print(sig, sig_type)
+                if sig_type == iotypes['*']:
+                    self.pads[pad][mux] = Record(name="%s%d" % (sig, unit),
+                                                 layout=io_layout)
+                elif sig_type == iotypes['+']:
+                    self.pads[pad][mux] = Signal(name="%s%d_o" % (sig, unit))
+                elif sig_type == iotypes['-']:
+                    self.pads[pad][mux] = Signal(name="%s%d_i" % (sig, unit))
+        print(self.pads)
+
+    def elaborate(self, platform):
+        m = Module()
+        comb, sync = m.d.comb, m.d.sync
+        muxes = self.muxes
+        bank = self.bank
+        pads = self.pads
+        for pad in pads.keys():
+            m.submodules[pad+"_mux"] = muxes[pad]
+            # all muxes controlled by the same multi-bit signal
+            comb += muxes[pad].bank.eq(bank)
+
+        # print(self.requested)
+        # print(self.pads)
+
+        # ---------------------------
+        # This section connects the periphs to the assigned banks
+        # ---------------------------
+        for pad in pads.keys():
+            for mux in self.requested[pad].keys():
+                periph = self.requested[pad][mux][0]
+                num = int(mux[3])
+                sig = self.requested[pad][mux][2][:-1]
+                sig_type = iotypes[self.requested[pad][mux][2][-1]]
+                if sig_type == iotypes['*']:
+                    comb += muxes[pad].bank_ports[num].o.eq(pads[pad][mux].o)
+                    comb += muxes[pad].bank_ports[num].oe.eq(pads[pad][mux].oe)
+                    comb += pads[pad][mux].i.eq(muxes[pad].bank_ports[num].i)
+                elif sig_type == iotypes['+']:
+                    comb += muxes[pad].bank_ports[num].o.eq(pads[pad][mux])
+                elif sig_type == iotypes['-']:
+                    comb += pads[pad][mux].eq(muxes[pad].bank_ports[num].i)
+        # ---------------------------
+        # Here is where the muxes are assigned to the actual pads
+        # ---------------------------
+        for pad in pads.keys():
+            comb += pads[pad]["pad"].o.eq(muxes[pad].out_port.o)
+            comb += pads[pad]["pad"].oe.eq(muxes[pad].out_port.oe)
+            comb += muxes[pad].out_port.i.eq(pads[pad]["pad"].i)
+
+        return m
+
+    def __iter__(self):
+        for pad in list(self.pads.keys()):
+            for field in self.pads[pad]["pad"].fields.values():
+                yield field
+            for mux in self.pads[pad].keys():
+                if type(self.pads[pad][mux]) == Signal:
+                    yield self.pads[pad][mux]
+                else:
+                    for field in self.pads[pad][mux].fields.values():
+                        yield field
+        yield self.bank
+
+    def ports(self):
+        return list(self)
+
+def set_bank(dut, bank, delay=1e-6):
+    yield dut.bank.eq(bank)
+    yield Delay(delay)
+
+"""
+GPIO test function
+Set the gpio output based on given data sequence, checked at pad.o
+Then sends the same byte via pad.i to gpio input
+"""
+def gpio(gpio, pad, data, delay=1e-6):
+    # Output test - Control GPIO output
+    yield gpio.oe.eq(1)
+    yield Delay(delay)
+    n_bits = len(bin(data)[2:])
+    read = 0
+    for i in range(0, n_bits):
+        bit = (data >> i) & 0x1
+        yield gpio.o.eq(bit)
+        yield Delay(delay)
+        temp = yield pad.o
+        read |= (temp << i)
+    assert data == read, f"GPIO Sent: %x | Pad Read: %x" % (data, read)
+    # Input test - Control Pad input
+    yield gpio.oe.eq(0)
+    yield Delay(delay)
+    read2 = 0
+    for i in range(0, n_bits):
+        bit = (read >> i) & 0x1
+        yield pad.i.eq(bit)
+        yield Delay(delay)
+        temp = yield gpio.i
+        read2 |= (temp << i)
+    assert read2 == read, f"Pad Sent: %x | GPIO Read: %x" % (data, read)
+    # reset input signal
+    yield pad.i.eq(0)
+    yield Delay(delay)
+
+"""
+UART test function
+Sends a byte via uart tx, checked at output pad
+Then sends the same byte via input pad to uart rx
+Input and output pads are different, so must specify both
+"""
+def uart_send(tx, rx, pad_tx, pad_rx, byte, delay=1e-6):
+    # Drive uart tx - check the word seen at the Pad
+    print(type(tx))
+    #yield tx.oe.eq(1)
+    yield tx.eq(1)
+    yield Delay(2*delay)
+    yield tx.eq(0) # start bit
+    yield Delay(delay)
+    read = 0
+    # send one byte, lsb first
+    for i in range(0, 8):
+        bit = (byte >> i) & 0x1
+        yield tx.eq(bit)
+        yield Delay(delay)
+        test_bit = yield pad_tx.o
+        read |= (test_bit << i)
+    yield tx.eq(1) # stop bit
+    yield Delay(delay)
+    assert byte == read, f"UART Sent: %x | Pad Read: %x" % (byte, read)
+    # Drive Pad i - check word at uart rx
+    yield pad_rx.i.eq(1)
+    yield Delay(2*delay)
+    yield pad_rx.i.eq(0) # start bit
+    yield Delay(delay)
+    read2 = 0
+    for i in range(0, 8):
+        bit = (read >> i) & 0x1
+        yield pad_rx.i.eq(bit)
+        yield Delay(delay)
+        test_bit = yield rx
+        read2 |= (test_bit << i)
+    yield pad_rx.i.eq(1) # stop bit
+    yield Delay(delay)
+    assert read == read2, f"Pad Sent: %x | UART Read: %x" % (read, read2)
+
+"""
+I2C test function
+Sends a byte via SDA.o (peripheral side), checked at output pad
+Then sends the same byte via input pad to master SDA.i
+This transaction doesn't make the distinction between read/write bit.
+"""
+def i2c_send(sda, scl, sda_pad, byte, delay=1e-6):
+    # No checking yet
+    # No pull-up on line implemented, set high instead
+    yield sda.oe.eq(1)
+    yield sda.o.eq(1)
+    yield scl.oe.eq(1)
+    yield scl.o.eq(1)
+    yield sda_pad.i.eq(1)
+    yield Delay(delay)
+    read = 0
+    yield sda.o.eq(0) # start bit
+    yield Delay(delay)
+    for i in range(0, 8):
+        bit = (byte >> i) & 0x1
+        yield sda.o.eq(bit)
+        yield scl.o.eq(0)
+        yield Delay(delay/2)
+        yield scl.o.eq(1)
+        temp = yield sda_pad.o
+        read |= (temp << i)
+        yield Delay(delay/2)
+    yield sda.o.eq(1) # Master releases SDA line
+    yield sda.oe.eq(0)
+    assert byte == read, f"I2C Sent: %x | Pad Read: %x" % (byte, read)
+    # Slave ACK
+    yield sda_pad.i.eq(0)
+    yield scl.o.eq(0)
+    yield Delay(delay/2)
+    yield scl.o.eq(1)
+    yield Delay(delay/2)
+    # Send byte back to master
+    read2 = 0
+    for i in range(0, 8):
+        bit = (read >> i) & 0x1
+        yield sda_pad.i.eq(bit)
+        yield scl.o.eq(0)
+        yield Delay(delay/2)
+        yield scl.o.eq(1)
+        temp = yield sda.i
+        read2 |= (temp << i)
+        yield Delay(delay/2)
+    assert read == read2, f"Pad Sent: %x | I2C Read: %x" % (read, read2)
+    # Master ACK
+    yield sda.oe.eq(1)
+    yield sda.o.eq(0)
+    yield scl.o.eq(0)
+    yield Delay(delay/2)
+    yield scl.o.eq(1)
+    yield Delay(delay/2)
+    # Stop condition - SDA line high after SCL high
+    yield scl.o.eq(0)
+    yield Delay(delay/2)
+    yield scl.o.eq(1)
+    yield Delay(delay/2)
+    yield sda.o.eq(1) # 'release' the SDA line
+
+# Test the GPIO/UART/I2C connectivity
+def test_man_pinmux(dut, requested):
+    # TODO: Convert to automatic
+    # [{"pad":%s, "bank":%d}, {"pad":%s, "bank":%d},...]
+    #gpios = [{"padname":"N1", "bank":GPIO_BANK},
+    #         {"padname":"N2", "bank":GPIO_BANK}]
+    # [[txPAD, MUXx, rxPAD, MUXx],...] - diff banks not supported yet
+    uarts = [{"txpadname":"N1", "rxpadname":"N2", "bank":UART_BANK}]
+    # [[sdaPAD, MUXx, sclPAD, MUXx],...] - diff banks not supported yet
+    i2cs = [{"sdapadname":"N1", "sclpadname":"N2", "bank":I2C_BANK}]
+
+    gpios = []
+    delay = 1e-6
+    for pad in requested.keys():
+        for mux in requested[pad].keys():
+            periph = requested[pad][mux][0]
+
+            if periph == "gpio":
+                # [{"padname":%s, "bank": %d}, ...]
+                gpios.append({"padname":pad, "bank": int(mux[3])})
+            if periph == "uart":
+                # TODO:
+                pass
+            if periph == "i2c":
+                # TODO:
+                pass
+    print(gpios)
+    # GPIO test
+    for gpio_periph in gpios:
+        padname = gpio_periph["padname"]
+        gpio_bank = gpio_periph["bank"]
+        gp = dut.pads[padname]["mux%d" % gpio_bank]
+        pad = dut.pads[padname]["pad"]
+        yield from set_bank(dut, gpio_bank)
+        yield from gpio(gp, pad, 0x5a5)
+
+    # UART test
+    for uart_periph in uarts:
+        txpadname = uart_periph["txpadname"]
+        rxpadname = uart_periph["rxpadname"]
+        uart_bank = uart_periph["bank"]
+        tx = dut.pads[txpadname]["mux%d" % uart_bank]
+        rx = dut.pads[rxpadname]["mux%d" % uart_bank]
+        txpad = dut.pads[txpadname]["pad"]
+        rxpad = dut.pads[rxpadname]["pad"]
+        yield from set_bank(dut, UART_BANK)
+        yield from uart_send(tx, rx, txpad, rxpad, 0x42)
+
+    # I2C test
+    for i2c_periph in i2cs:
+        sdapadname = i2c_periph["sdapadname"]
+        sclpadname = i2c_periph["sclpadname"]
+        i2c_bank = i2c_periph["bank"]
+        sda = dut.pads[sdapadname]["mux%d" % i2c_bank]
+        scl = dut.pads[sclpadname]["mux%d" % i2c_bank]
+        sdapad = dut.pads[sdapadname]["pad"]
+
+    yield from set_bank(dut, I2C_BANK)
+    yield from i2c_send(sda, scl, sdapad, 0x67)
+
+def gen_gtkw_doc(module_name, requested, 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 = []
+    temp = 0
+    n_banks = 0
+    for pad in requested.keys():
+        temp = len(requested[pad].keys())
+        if n_banks < temp:
+            n_banks = temp
+        temp_traces = ("Pad %s" % pad, [])
+        # Pad signals
+        temp_traces[1].append(('%s__i' % pad, 'in'))
+        temp_traces[1].append(('%s__o' % pad, 'out'))
+        temp_traces[1].append(('%s__oe' % pad, 'out'))
+        for mux in requested[pad].keys():
+            periph = requested[pad][mux][0]
+            unit_num = requested[pad][mux][1]
+            if len(requested[pad][mux]) == 3:
+                pin = requested[pad][mux][2]
+            else:
+                pin = "io"
+
+            if periph == "gpio":
+                temp_traces[1].append(('gp%d__i' % unit_num, 'in'))
+                temp_traces[1].append(('gp%d__o' % unit_num, 'out'))
+                temp_traces[1].append(('gp%d__oe' % unit_num, 'out'))
+            elif periph == "uart":
+                if pin == "tx":
+                    temp_traces[1].append(('tx%d__o' % unit_num, 'out'))
+                    temp_traces[1].append(('tx%d__oe' % unit_num, 'out'))
+                    pass
+                elif pin == "rx":
+                    temp_traces[1].append(('rx%d' % unit_num, 'in'))
+                    pass
+            elif periph == "i2c":
+                temp_traces[1].append(('%s%d__i' % (pin, unit_num), 'in'))
+                temp_traces[1].append(('%s%d__o' % (pin, unit_num), 'out'))
+                temp_traces[1].append(('%s%d__oe' % (pin, unit_num), 'out'))
+        traces.append(temp_traces)
+
+    # master bank signal
+    temp_traces = ('Misc', [
+                    ('bank[%d:0]' % ((n_banks-1).bit_length()-1), 'in')
+                  ])
+    traces.append(temp_traces)
+
+    #print(traces)
+
+    write_gtkw(filename+".gtkw", filename+".vcd", traces, style,
+               module=module_name)
+
+
+def sim_man_pinmux():
+    filename = "test_man_pinmux"
+    requested = {"N1": {"mux%d" % GPIO_BANK: ["gpio", 0, '0*'],
+                        "mux%d" % UART_BANK: ["uart", 0, 'tx+'],
+                        "mux%d" % I2C_BANK: ["i2c", 0, 'sda*']},
+                 "N2": {"mux%d" % GPIO_BANK: ["gpio", 1, '*'],
+                        "mux%d" % UART_BANK: ["uart", 0, 'rx-'],
+                        "mux%d" % I2C_BANK: ["i2c", 0, 'scl*']},
+                 "N3": {"mux%d" % GPIO_BANK: ["gpio", 2, '0*']},
+                 "N4": {"mux%d" % GPIO_BANK: ["gpio", 3, '0*']}
+                }
+    dut = ManPinmux(requested)
+    vl = rtlil.convert(dut, ports=dut.ports())
+    with open(filename+".il", "w") as f:
+        f.write(vl)
+
+    m = Module()
+    m.submodules.manpinmux = dut
+
+    sim = Simulator(m)
+
+    sim.add_process(wrap(test_man_pinmux(dut, requested)))
+    sim_writer = sim.write_vcd(filename+".vcd")
+    with sim_writer:
+        sim.run()
+    gen_gtkw_doc("top.manpinmux", dut.requested, filename)
+
+if __name__ == '__main__':
+    sim_man_pinmux()
+    #pinbanks = []
+    #fixedpins = []
+    #function_names = []
+    #testspec = PinSpec()
+    pinbanks = {
+        'A': (4, 4), # (num of pads, num of banks)?
+        #'B': (18, 4),
+        #'C': (24, 1),
+        #'D': (93, 1),
+    }
+    fixedpins = {
+        'POWER_GPIO': [
+            'VDD_GPIOB',
+            'GND_GPIOB',
+        ]}
+    function_names = {'TWI0': 'I2C 0',
+                      'UART0': 'UART (TX/RX) 0',
+                     }
+    ps = PinSpec(pinbanks, fixedpins, function_names)
+    # Unit number, (Bank, pin #), mux, start, num # pins
+    ps.gpio("", ('A', 0), 0, 0, 4)
+    ps.uart("0", ('A', 0), 1)
+    ps.i2c("0", ('A', 0), 2)
+
+    print(dir(ps.gpio))
+    #print(ps.gpio.pinouts, ps.gpio.bankspec, ps.gpio.pinfn, ps.gpio.fname)
+    """
+    desc_dict_keys = ['UART0', 'TWI0', 'GPIOA_A0', 'GPIOA_A1', 'GPIOA_A2', 'GPIOA_A3']
+    eint = []
+    pwm = []
+    desc = {'UART0': 'Basic serial TX/RX serial port',
+            'TWI0': 'I2C interface',
+            'GPIOA_A0': 'Test GPIO0',
+            'GPIOA_A1': 'Test GPIO1',
+            'GPIOA_A2': 'Test GPIO2',
+            'GPIOA_A3': 'Test GPIO3'}
+    ps.add_scenario("Test Manual Pinmux", desc_dict_keys, eint, pwm, desc)
+    """
+    print("---------------------------------")
+    #with open("test.mdwn", "w") as of:
+    #    pinout, bankspec, pin_spec, fixedpins = ps.write(of)
+    #print("---------------------------------")
+
+    bk = ps.pinbanks.keys()
+    for bank in bk:
+        muxwidth = ps.muxwidths[bank]
+        print(bank, muxwidth)
+        pinidx = sorted(ps.keys())
+        for pin in pinidx:
+            print("---------------------------------")
+            print(pin)
+            pdata = ps.get(pin)
+            for mux in range(muxwidth):
+                if mux not in pdata:
+                    print("Mux %d : NC" % mux)
+                else:
+                    name, assigned_bank = pdata[mux]
+                    print("Mux %d : %s" % (mux, name))
+
+
+