add naming and pin-order reverse option
[pinmux.git] / src / spec / interfaces.py
index b917e8f72d6704782611c1091e9ddba5cb9c70ef..744f80333985aadb1163fc24bb06e954f83a6ad0 100644 (file)
 #!/usr/bin/env python
 
+from spec.pinfunctions import pinspec
+from copy import deepcopy
+
+
+def namesuffix(name, suffix, namelist):
+    names = []
+    for n in namelist:
+        if n:
+            names.append("%s%s_%s" % (name, suffix, n))
+        else:
+            names.append("%s_%s" % (name, suffix))
+    return names
+
+
+class PinGen(object):
+    """ a meta-helper which creates pins from the pinspec
+        and adds them to the pinouts.
+
+        __call__ is used to effectively create a lambda function, which
+        in combination with setattr (below) gives the function a name
+        in the Pinouts class, according to the pinspec.
+
+        arguments to __call__ (which ends up as Pinouts.i2s, Pinouts.sdmmc
+        and so on, according to spec.pinfunctions.pinspec) are:
+
+        suffix: e.g. GPIO or SD or SPI
+        offs  : a tuple of (Bank, Bank offset) as a string, integer
+        mux   : which column in the multiplexer
+        start : the start of a subset of pins to be inserted
+        limit : the end of the subset (or the number if start also given)
+        spec  : *EXTRA* pins to be inserted (at different implicit positions)
+
+        the pins are inserted with the suffix, starting from the
+        offset position using offs as the row and mux as the column,
+        and working in a constant increment down the rows.
+
+        spec is slightly complicated, basically there's extra
+        functions that we want to be on the same pin (but a different mux)
+        because their use is mutually-exclusive.  without this spec
+        argument the extra pins would need to be MANUALLY moved about
+        during the development of the pinmux, if the "main" pins
+        were also moved about.  this would be a pain.
+
+        so instead, extra pins are given of the form:
+        { 'EXTRA1' : ('PREEXISTING_NAME', MUX_COLUMN),
+          ...
+        }
+
+        where the function EXTRA1 will always be placed on the SAME ROW
+        as PREEXISTING_NAME, just in MUX_COLUMN.  this may be done
+        several times i.e. multiple new EXTRA functions can be added
+        on the same row as PRE_EXISTING_NAME, just with different
+        MUX_COLUMN values.
+
+        Note: spec must implicitly be in the same Bank.
+    """
+
+    def __init__(self, pinouts, fname, pinfn, bankspec):
+        self.pinouts = pinouts
+        self.bankspec = bankspec
+        self.pinfn = pinfn
+        self.fname = fname
+
+    def __call__(self, suffix, offs, mux,
+                 start=None, limit=None, spec=None, origsuffix=None,
+                 rev=False):
+        bank = offs[0]
+        pf = self.pinfn(suffix, bank)
+        print "pf", suffix, bank, pf
+        pingroup, gangedgroup, clock = pf
+        if clock:
+            self.pinouts.clocks[self.fname] = clock
+        if isinstance(pingroup, tuple):
+            prefix, pingroup = pingroup
+        else:
+            prefix = self.fname
+        if start and limit:  # limit turns into an offset from start
+            limit = start + limit
+        sk = "%s:%s" % (self.fname, str(suffix))
+        print "pingroup pre", sk, pingroup
+        pingroup = pingroup[start:limit]  # see comment in spec.pinfunctions
+        if rev:
+            # reverse order of pingroup
+            pingroup.reverse()
+        print "pingroup post", sk, pingroup
+        if self.pinouts.byspec.has_key(sk):
+            self.pinouts.byspec[sk] += pingroup
+        else:
+            self.pinouts.byspec[sk] = deepcopy(pingroup)
+        pins = Pins(prefix, pingroup, self.bankspec,
+                    suffix, offs, bank, mux,
+                    spec, origsuffix=suffix, gangedgrp=gangedgroup)
+        fname = self.pinouts.pinmerge(pins)
+        self.pinouts.setganged(fname, gangedgroup)
+
+# pinouts class
+
+
 class Pinouts(object):
-    def __init__(self):
+    def __init__(self, bankspec):
+        self.bankspec = bankspec
         self.pins = {}
         self.fnspec = {}
+        self.ganged = {}
+        self.clocks = {}
+        self.byspec = {}
+        for fname, pinfn in pinspec:
+            if isinstance(pinfn, tuple):
+                name, pinfn = pinfn
+            else:
+                name = pinfn.__name__
+            pin = PinGen(self, fname, pinfn, self.bankspec)
+            setattr(self, name, pin)
+
+    def setganged(self, fname, grp):
+        grp = map(lambda x: x[:-1], grp)
+        if fname not in self.ganged:
+            self.ganged[fname] = []
+        self.ganged[fname] += grp
+
+    def __contains__(self, k):
+        return k in self.pins
 
     def has_key(self, k):
-        return self.pins.has_key(k)
+        return k in self.pins
 
     def add_spec(self, k, v):
         self.fnspec[k] = v
 
     def update(self, pinidx, v):
-        if not self.pins.has_key(pinidx):
+        if pinidx not in self.pins:
             self.pins[pinidx] = v
         else:
+            for k in v:
+                assert k not in self.pins[pinidx], \
+                    "pin %d position %d already taken\n%s\n%s" % \
+                    (pinidx, k, str(v), self.pins[pinidx])
             self.pins[pinidx].update(v)
 
     def keys(self):
@@ -35,11 +157,50 @@ class Pinouts(object):
     def __getitem__(self, k):
         return self.pins[k]
 
+    def pinmerge(self, fn):
+        # hack, store the function specs in the pins dict
+        fname = fn.fname
+        suffix = fn.origsuffix
+        bank = fn.bank
+
+        if not hasattr(self, 'fnspec'):
+            self.fnspec = pins
+        if fname == 'GPIO':
+            fname = fname + bank
+        assert 'EINT' not in self
+        if fname not in self.fnspec:
+            self.add_spec(fname, {})
+        if suffix or fname == 'EINT' or fname == 'PWM':
+            specname = fname + suffix
+        else:
+            specname = fname
+        # print "fname bank specname suffix ", fname, bank, specname, repr(
+        #    suffix)
+        if specname in self.fnspec[fname]:
+            # ok so some declarations may bring in different
+            # names at different stages (EINT, PWM, flexbus1/2)
+            # so we have to merge the names in.  main thing is
+            # the pingroup
+            tomerge = self.fnspec[fname][specname]
+            for p in fn.pingroup:
+                if p not in tomerge.pingroup:
+                    tomerge.pingroup.append(p)
+            tomerge.pins.update(fn.pins)
+            tomerge.fntype.update(fn.fntype)
+        else:
+            self.fnspec[fname][specname] = deepcopy(fn)
+
+        # merge actual pins
+        for (pinidx, v) in fn.pins.items():
+            self.update(pinidx, v)
+
+        return fname
+
 
 class Pins(object):
 
     def __init__(self, fname, pingroup, bankspec, suffix, offs, bank, mux,
-             spec=None, limit=None, origsuffix=None):
+                 spec=None, limit=None, origsuffix=None, gangedgrp=None):
 
         # function type can be in, out or inout, represented by - + *
         # strip function type out of each pin name
@@ -58,6 +219,7 @@ class Pins(object):
 
         self.fname = fname
         self.pingroup = pingroup
+        self.gangedgroup = gangedgrp
         self.bankspec = bankspec
         self.suffix = suffix
         self.origsuffix = origsuffix or suffix
@@ -66,7 +228,7 @@ class Pins(object):
 
         # create consistent name suffixes
         pingroup = namesuffix(fname, suffix, pingroup)
-        suffix = '' # hack
+        suffix = ''  # hack
 
         res = {}
         names = {}
@@ -76,7 +238,7 @@ class Pins(object):
                 name_ = "%s_%s" % (name, suffix)
             else:
                 name_ = name
-            if spec and spec.has_key(name):
+            if spec and name in spec:
                 continue
             pin = {mux: (name_, bank)}
             offs_bank, offs_ = offs
@@ -92,220 +254,14 @@ class Pins(object):
                 name_ = name
             if not spec:
                 continue
-            if not spec.has_key(name):
+            if name not in spec:
                 continue
-            idx_, mux_, bank_ = spec[name]
+            idx_, mux_ = spec[name]
             idx_ = names[idx_]
-            pin = {mux_: (name_, bank_)}
-            if res.has_key(idx_):
+            pin = {mux_: (name_, bank)}
+            if idx_ in res:
                 res[idx_].update(pin)
             else:
                 res[idx_] = pin
 
         self.pins = res
-
-
-def i2s(bankspec, suffix, offs, bank, mux=1, spec=None, limit=None):
-    i2spins = ['MCK+', 'BCK+', 'LRCK+', 'DI-', 'DO+']
-    #for i in range(4):
-    #    i2spins.append("DO%d+" % i)
-    return Pins('IIS', i2spins, bankspec, suffix, offs, bank, mux, spec, limit,
-                origsuffix=suffix)
-
-def emmc(bankspec, suffix, offs, bank, mux=1, spec=None):
-    emmcpins = ['CMD+', 'CLK+']
-    for i in range(8):
-        emmcpins.append("D%d*" % i)
-    return Pins('MMC', emmcpins, bankspec, suffix, offs, bank, mux, spec,
-                origsuffix=suffix)
-
-def sdmmc(bankspec, suffix, offs, bank, mux=1, spec=None,
-                start=None, limit=None):
-    sdmmcpins = ['CMD+', 'CLK+']
-    for i in range(4):
-        sdmmcpins.append("D%d*" % i)
-    sdmmcpins = sdmmcpins[start:limit]
-    return Pins('SD', sdmmcpins, bankspec, suffix, offs, bank, mux, spec,
-                origsuffix=suffix)
-
-def spi(bankspec, suffix, offs, bank, mux=1, spec=None):
-    spipins = ['CLK*', 'NSS*', 'MOSI*', 'MISO*']
-    return Pins('SPI', spipins, bankspec, suffix, offs, bank, mux, spec,
-                origsuffix=suffix)
-
-def quadspi(bankspec, suffix, offs, bank, mux=1, spec=None, limit=None):
-    spipins = ['CK*', 'NSS*', 'IO0*', 'IO1*', 'IO2*', 'IO3*']
-    return Pins('QSPI', spipins, bankspec, suffix, offs, bank, mux, spec, limit,
-                origsuffix=suffix)
-
-def i2c(bankspec, suffix, offs, bank, mux=1, spec=None):
-    spipins = ['SDA*', 'SCL*']
-    return Pins('TWI', spipins, bankspec, suffix, offs, bank, mux, spec,
-                origsuffix=suffix)
-
-def jtag(bankspec, suffix, offs, bank, mux=1, spec=None):
-    jtagpins = ['MS+', 'DI-', 'DO+', 'CK+']
-    return Pins('JTAG', jtagpins, bankspec, suffix, offs, bank, mux, spec,
-                origsuffix=suffix)
-
-def uart(bankspec, suffix, offs, bank, mux=1, spec=None):
-    uartpins = ['TX+', 'RX-']
-    return Pins('UART', uartpins, bankspec, suffix, offs, bank, mux, spec,
-                origsuffix=suffix)
-
-def namesuffix(name, suffix, namelist):
-    names = []
-    for n in namelist:
-        if n:
-            names.append("%s%s_%s" % (name, suffix, n))
-        else:
-            names.append("%s_%s" % (name, suffix))
-    return names
-
-def ulpi(bankspec, suffix, offs, bank, mux=1, spec=None):
-    ulpipins = ['CK+', 'DIR+', 'STP+', 'NXT+']
-    for i in range(8):
-        ulpipins.append('D%d*' % i)
-    return Pins('ULPI', ulpipins, bankspec, suffix, offs, bank, mux, spec,
-                origsuffix=suffix)
-
-def uartfull(bankspec, suffix, offs, bank, mux=1, spec=None):
-    uartpins = ['TX+', 'RX-', 'CTS-', 'RTS+']
-    return Pins('UARTQ', uartpins, bankspec, suffix, offs, bank, mux, spec,
-                origsuffix=suffix)
-
-def rgbttl(bankspec, suffix, offs, bank, mux=1, spec=None):
-    ttlpins = ['CK+', 'DE+', 'HS+', 'VS+']
-    for i in range(24):
-        ttlpins.append("D%d+" % i)
-    return Pins('LCD', ttlpins, bankspec, suffix, offs, bank, mux, spec,
-                origsuffix=suffix)
-
-def rgmii(bankspec, suffix, offs, bank, mux=1, spec=None):
-    buspins = []
-    for i in range(4):
-        buspins.append("ERXD%d-" % i)
-    for i in range(4):
-        buspins.append("ETXD%d+" % i)
-    buspins += ['ERXCK-', 'ERXERR-', 'ERXDV-',
-                'EMDC+', 'EMDIO*',
-                'ETXEN+', 'ETXCK+', 'ECRS-',
-                'ECOL+', 'ETXERR+']
-    return Pins('RG', buspins, bankspec, suffix, offs, bank, mux, spec,
-                origsuffix=suffix)
-
-def flexbus1(bankspec, suffix, offs, bank, mux=1, spec=None, limit=None):
-    buspins = []
-    for i in range(8):
-        buspins.append("AD%d*" % i)
-    for i in range(2):
-        buspins.append("CS%d+" % i)
-    buspins += ['ALE', 'OE', 'RW', 'TA', 'CLK+',
-                'A0', 'A1', 'TS', 'TBST',
-                'TSIZ0', 'TSIZ1']
-    for i in range(4):
-        buspins.append("BWE%d" % i)
-    for i in range(2,6):
-        buspins.append("CS%d+" % i)
-    return Pins('FB', buspins, bankspec, suffix, offs, bank, mux, spec, limit,
-                origsuffix=suffix)
-
-def flexbus2(bankspec, suffix, offs, bank, mux=1, spec=None, limit=None):
-    buspins = []
-    for i in range(8,32):
-        buspins.append("AD%d*" % i)
-    return Pins('FB', buspins, bankspec, suffix, offs, bank, mux, spec, limit,
-                origsuffix=suffix)
-
-def sdram1(bankspec, suffix, offs, bank, mux=1, spec=None):
-    buspins = []
-    for i in range(16):
-        buspins.append("SDRDQM%d*" % i)
-    for i in range(12):
-        buspins.append("SDRAD%d+" % i)
-    for i in range(8):
-        buspins.append("SDRDQ%d+" % i)
-    for i in range(3):
-        buspins.append("SDRCS%d#+" % i)
-    for i in range(2):
-        buspins.append("SDRDQ%d+" % i)
-    for i in range(2):
-        buspins.append("SDRBA%d+" % i)
-    buspins += ['SDRCKE+', 'SDRRAS#+', 'SDRCAS#+', 'SDRWE#+',
-                'SDRRST+']
-    return Pins('SDR', buspins, bankspec, suffix, offs, bank, mux, spec,
-                origsuffix=suffix)
-
-def sdram2(bankspec, suffix, offs, bank, mux=1, spec=None, limit=None):
-    buspins = []
-    for i in range(3,6):
-        buspins.append("SDRCS%d#+" % i)
-    for i in range(8,32):
-        buspins.append("SDRDQ%d*" % i)
-    return Pins('SDR', buspins, bankspec, suffix, offs, bank, mux, spec, limit,
-                origsuffix=suffix)
-
-def mcu8080(bankspec, suffix, offs, bank, mux=1, spec=None):
-    buspins = []
-    for i in range(8):
-        buspins.append("MCUD%d*" % i)
-    for i in range(8):
-        buspins.append("MCUAD%d+" % (i+8))
-    for i in range(6):
-        buspins.append("MCUCS%d+" % i)
-    for i in range(2):
-        buspins.append("MCUNRB%d+" % i)
-    buspins += ['MCUCD+', 'MCURD+', 'MCUWR+', 'MCUCLE+', 'MCUALE+',
-                'MCURST+']
-    return Pins('MCU', buspins, bankspec, suffix, offs, bank, mux, spec,
-                origsuffix=suffix)
-
-def _pinbank(bankspec, prefix, suffix, offs, bank, gpiooffs, gpionum=1, mux=1,
-             spec=None):
-    gpiopins = []
-    for i in range(gpiooffs, gpiooffs+gpionum):
-        gpiopins.append("%s%d*" % (bank, i))
-    return Pins('GPIO', gpiopins, bankspec, suffix, offs, bank, mux, spec,
-                origsuffix=suffix)
-
-def eint(bankspec, suffix, offs, bank, gpiooffs, gpionum=1, mux=1, spec=None):
-    gpiopins = []
-    for i in range(gpiooffs, gpiooffs+gpionum):
-        gpiopins.append("%d*" % (i))
-    return Pins('EINT', gpiopins, bankspec, suffix, offs, bank, mux, spec,
-                origsuffix=suffix)
-
-def pwm(bankspec, suffix, offs, bank, mux=1, spec=None):
-    return Pins('PWM', ['+', ], bankspec, suffix, offs, bank, mux, spec,
-                origsuffix=suffix)
-
-def gpio(bankspec, suffix, offs, bank, gpiooffs, gpionum=1, mux=1, spec=None):
-    return _pinbank(bankspec, "GPIO", suffix, offs, bank, gpiooffs,
-                              gpionum, mux=0, spec=None)
-
-def pinmerge(pins, fn):
-    # hack, store the function specs in the pins dict
-    fname = fn.fname
-    suffix = fn.origsuffix
-    bank = fn.bank
-
-    if not hasattr(pins, 'fnspec'):
-        pins.fnspec = pins
-    if fname == 'GPIO':
-        fname = fname + bank
-    assert not pins.has_key('EINT')
-    if not pins.fnspec.has_key(fname):
-        pins.add_spec(fname, {})
-    print "fname bank suffix", fname, bank, suffix
-    if suffix or fname == 'EINT' or fname == 'PWM':
-        specname = fname + suffix
-    else:
-        specname = fname + bank
-    pins.fnspec[fname][specname] = fn
-
-
-    # merge actual pins
-    for (pinidx, v) in fn.pins.items():
-        print "pinidx", pinidx
-        pins.update(pinidx, v)
-