when muxwidth == 1 output pin directly
[pinmux.git] / src / bsv / actual_pinmux.py
index c382e7e512cc05ddd12227da7c72398ca8fe9522..7156fd154af5d8edbadbfbcdad481f6e309568bf 100644 (file)
@@ -1,3 +1,4 @@
+import math
 from string import digits
 try:
     from string import maketrans
@@ -9,7 +10,7 @@ except ImportError:
 # first argument is the io-cell number being assigned.
 # second argument is the mux value.
 # Third argument is the signal from the pinmap file
-mux_wire = '''
+mux_wire = '''\
       rule assign_{2}_on_cell{0}(wrcell{0}_mux=={1});
         {2}<=cell{0}_mux_in;
       endrule
@@ -23,11 +24,13 @@ dedicated_wire = '''
 digits = maketrans('0123456789', ' ' * 10)  # delete space later
 
 
-def cn(idx):
+def cn(idx):  # idx is an integer
     return "cell%s_mux" % str(idx)
 
 
 def transfn(temp):
+    """ removes the number from the string of signal name.
+    """
     temp = temp.split('_')
     if len(temp) == 2:
         temp[0] = temp[0].translate(digits)
@@ -35,21 +38,129 @@ def transfn(temp):
     return '_'.join(temp)
 
 
+# XXX this needs to move into interface_decl.py
+# and made to use ifaceoutfmtfn and ifaceinfmtfn
+def fmt(ifaces, cells, idx, suffix=None):
+    """ blank entries need to output a 0 to the pin (it could just as
+        well be a 1 but we choose 0).  reason: blank entries in
+        the pinmap.txt file indicate that there's nothing to choose
+        from.  however the user may still set the muxer to that value,
+        and rather than throw an exception we choose to output... zero.
+
+        NOTE: IMPORTANT.  when a function is an output-only there
+        is a special-case assumption that:
+        * (a) GPIO is always the first mux entry
+        * (b) GPIO's outen is also used to set the pad
+        the reason for this is that it is assumed better that
+        multiple pads be switched simutaneously to outputs
+        by setting the GPIO direction rather than having them
+        set arbitrarily by changing the muxer registers.
+    """
+    idx += 1
+    if idx < len(cells):
+        cell = cells[idx]
+    else:
+        cell = ''
+    #print "fmt", idx, cells, cell
+    if not cell:
+        return 'val0'
+    temp = transfn(cell)
+    x = ifaces.getifacetype(temp)
+    if x == 'input':
+        return 'val0'  # inputs don't get passed through to the out mux
+    if suffix == '_outen' and x == 'out':
+        return "wr%s%s" % (cells[1], suffix or '')  # USE GPIO FOR SELECTION
+    if x == 'out':  # sigh hack, should be using interface_decl
+        suffix = ''
+    return "wr%s%s" % (cell, suffix or '')
+
+# XXX this needs to move into interface_decl.py
+
+
+def mkcomment(ifaces, cell, idx, outenmode=False):
+    """ returns a comment string for the cell when muxed
+    """
+    idx += 1
+    if idx >= len(cell):
+        return ' // unused'
+    cname = cell[idx]
+    if not cname:
+        return ' // unused'
+    temp = transfn(cname)
+    x = ifaces.getifacetype(temp)
+    #print (cname, x)
+    if x == 'input':
+        return ' // %s is an input' % cname
+    if outenmode and x == 'inout':
+        return ' // bi-directional'
+    if outenmode and x == 'out':
+        return ' // %s is an output' % cname
+
+    return ""
+
+
+def mkmux(p, ifaces, cell, suffix, outenmode):
+    """ creates a straight many-to-one muxer that accepts
+        multiple inputs and, based on an "address" routes
+        a given indexed input through to the (one) output
+    """
+    cellnum = cell[0]
+    comment = 'outen' if outenmode else 'output'
+    fmtstr = "\t\t\twr%s==%d?%s:%s\n"  # mux-selector format
+    ret = ''
+    ret += "      // %s muxer for cell idx %s\n" % (comment, cellnum)
+    ret += "      %s%s=\n" % (cn(cellnum), suffix)
+    i = 0
+    mwid = p.get_muxwidth(cellnum)
+    if mwid > 1:
+        for i in range(0, mwid - 1):  # full mux range (minus 1)
+            comment = mkcomment(ifaces, cell, i, outenmode)
+            cf = fmt(ifaces, cell, i, suffix)
+            ret += fmtstr % (cn(cell[0]), i, cf, comment)
+        i += 1
+    comment = mkcomment(ifaces, cell, i, outenmode)
+    ret += "\t\t\t" + fmt(ifaces, cell, i, suffix)  # last line
+    ret += ";%s\n" % comment
+
+    return ret
+
+
 def init(p, ifaces):
     """ generates the actual output pinmux for each io-cell.  blank lines
         need to output "0" to the iopad, if there is no entry in
         that column.
+
+        text is outputted in the format:
+            x_out =
+                muxer_sel==0 ? a :
+                muxer_sel==1 ? b :
+                muxer_sel==2 ? 0 :
+                d
+
+        last line doesn't need selector-logic, obviously.
+
+        note that it's *important* that all muxer options be covered
+        (hence going up to 1<<cell_bitwidth) even if the muxer cells
+        are blank (no entries), because muxer selection could be to
+        the last one, and we do not want the "default" (last line)
+        to be the output.
     """
     p.pinmux = ' '
     global dedicated_wire
     for cell in p.muxed_cells:
-        p.pinmux += "      // output muxer for cell idx %d\n" % cell[0]
-        p.pinmux += "      %s_out=" % cn(cell[0])
-        for i in range(0, len(cell) - 2):
-            p.pinmux += "wr%s" % cn(cell[0]) + \
-                "==" + str(i) + "?" + cell[i + 1] + "_io:\n\t\t\t"
-        p.pinmux += cell[i + 2] + "_io"
-        p.pinmux += ";\n"
+
+        cellidx = cell[0]
+
+        p.pinmux += "      // --------------------\n"
+        p.pinmux += "      // ----- cell %s -----\n\n" % (cellidx)
+
+        # first do the outputs
+        p.pinmux += mkmux(p, ifaces, cell, '_out', False)
+        p.pinmux += "\n"
+
+        # now do the output enablers (outens)
+        p.pinmux += mkmux(p, ifaces, cell, '_outen', True)
+
         # ======================================================== #
 
         # check each cell if "peripheral input/inout" then assign its wire
@@ -57,33 +168,48 @@ def init(p, ifaces):
         # We choose to keep the dictionary within the code and not user-input
         # since the interfaces are always standard and cannot change from
         # user-to-user. Plus this also reduces human-error as well :)
+        p.pinmux += "\n"
+        p.pinmux += "      // priority-in-muxer for cell idx %s\n" % (cellidx)
         for i in range(0, len(cell) - 1):
             cname = cell[i + 1]
+            if not cname:  # skip blank entries, no need to test
+                continue
             temp = transfn(cname)
             x = ifaces.getifacetype(temp)
-            #print (cname, temp, x)
+            print (cname, temp, x)
             assert x is not None, "ERROR: The signal : " + \
                 str(cname) + \
                 " of pinmap.txt isn't present \nin the current" + \
                 " dictionary. Update dictionary or fix-typo."
-            if x == "input":
-                p.pinmux += \
-                    mux_wire.format(cell[0], i, "wr" + cname) + "\n"
-            elif x == "inout":
-                p.pinmux += \
-                    mux_wire.format(cell[0], i, "wr" + cname +
-                                                "_in") + "\n"
-    # ============================================================ #
+            bwid = p.get_muxbitwidth(cellidx)
+            if bwid > 0:
+                muxcell(p, cname, x, cell, i)
+            else:
+                dedcell(p, x, cell)
 
     # ==================  Logic for dedicated pins ========= #
+    p.pinmux += "\n      /*=========================================*/\n"
+    p.pinmux += "      // dedicated cells\n\n"
     for cell in p.dedicated_cells:
+        p.pinmux += "      // dedicated cell idx %s\n" % (cell[0])
         p.pinmux += "      %s_out=%s_io;\n" % (cn(cell[0]), cell[1])
-        temp = cell[1].translate(digits)
+        temp = transfn(cell[1])
         x = ifaces.getifacetype(temp)
-        if x == "input":
-            pinmux = pinmux + \
-                dedicated_wire.format(cell[0], "wr" + cell[1]) + "\n"
-        elif x == "inout":
-            pinmux = pinmux + \
-                dedicated_wire.format(cell[0], "wr" + cell[1] + "_in") + "\n"
-    # =======================================================#
+        #print cell, temp, x
+        dedcell(p, x, cell)
+
+def muxcell(p, cname, x, cell, i):
+    if x == "input":
+        p.pinmux += \
+            mux_wire.format(cell[0], i, "wr" + cname) + "\n"
+    elif x == "inout":
+        p.pinmux += \
+            mux_wire.format(cell[0], i, "wr" + cname +
+                                        "_in") + "\n"
+def dedcell(p, x, cell):
+    if x == "input":
+        p.pinmux += \
+            dedicated_wire.format(cell[0], "wr" + cell[1]) + "\n"
+    elif x == "inout":
+        p.pinmux += \
+            dedicated_wire.format(cell[0], "wr" + cell[1] + "_in") + "\n"