Merge branch 'master' of 192.168.0.7:/home/tim/gitsrc/open_pdks/
diff --git a/VERSION b/VERSION
index 8955a01..8b54409 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.26
+1.0.28
diff --git a/common/fix_subckt_params.py b/common/fix_subckt_params.py
new file mode 100755
index 0000000..f986119
--- /dev/null
+++ b/common/fix_subckt_params.py
@@ -0,0 +1,269 @@
+#!/bin/env python3
+#
+# fix_subckt_params.py --
+#
+# Modify SPICE subcircuit definitions in files where parameters are listed
+# in a ".param" block in the subcircuit and are therefore local parameters
+# that cannot be passed to the subcircuit, and move them into the subcircuit
+# pin list as parameters that can be passed to the subcircuit.
+#
+# The arguments are <path_to_input>, <path_to_output>, and <param> ...
+# <path_to_input> should be the path to a single file, while
+# <path_to_output> is the path to a directory where the split files will
+# be put.  <params> ... is a whitespace-separated (i.e., one parameter,
+# one argument) list of parameter names that should be moved up from the
+# ".param" section to the ".subckt" line.  If <param> is preceded with "-",
+# then the parameter will be moved from the .subckt line down to the
+# .param section.
+
+import os
+import sys
+import re
+import glob
+
+def usage():
+    print('fix_subckt_params.py <path_to_input> <path_to_output> <param> ...')
+    print('where:')
+    print('   <path_to_input> is the path to the input file to parse')
+    print('   <path_to_output> is the directory to place the modified input file')
+    print('   <param> ... is a space-separated list of parameters that should')
+    print('        be in the subcircuit line and not the .param block')
+
+# Parse a parameter line for parameters, and divide into two parts,
+# returned as a list.  If a parameter name matches an entry in 'params',
+# it goes in the second list.  Otherwise, it goes in the first list.
+# The first list is returned as-is minus any parameters that were split
+# into the second list.  The second list must begin with '+', as it will
+# be output as a continuation line for the subcircuit.
+
+def param_split(line, params, debug):
+    # Regexp patterns
+    parm1rex = re.compile('(\.param[ \t]+)(.*)')
+    parm2rex = re.compile('(\+[ \t]*)(.*)')
+    parm3rex = re.compile('([^= \t]+)([ \t]*=[ \t]*[^ \t]+[ \t]*)(.*)')
+    parm4rex = re.compile('([^= \t]+)([ \t]*)(.*)')
+
+    part1 = ''
+    part2 = ''
+
+    if debug:
+        print('Diagnostic:  param line in = "' + line + '"')
+
+    pmatch = parm1rex.match(line)
+    if pmatch:
+        part1 = pmatch.group(1)
+        rest = pmatch.group(2)
+    else:
+        pmatch = parm2rex.match(line)
+        if pmatch:
+            rest = pmatch.group(2)
+        else:
+            # Could not parse;  return list with line and empty string
+            return [line, '']
+
+    while rest != '':
+        pmatch = parm3rex.match(rest)
+        if pmatch:
+            rest = pmatch.group(3)
+            pname = pmatch.group(1)
+            if pname in params:
+                if part2 == '':
+                    part2 = '+ '
+                part2 += pname + pmatch.group(2)
+            else:
+                if part1 == '':
+                    part1 = '+ '
+                part1 += pname + pmatch.group(2)
+        else:
+            pmatch = parm4rex.match(rest)
+            if pmatch:
+                rest = pmatch.group(3)
+                pname = pmatch.group(1)
+                if pname in params:
+                    if part2 == '':
+                        part2 = '+ '
+                    part2 += pname + pmatch.group(2)
+                else:
+                    if part1 == '':
+                        part1 = '+ '
+                    part1 += pname + pmatch.group(2)
+
+    if debug:
+        print('Diagnostic:  param line out = "' + part1 + '" and "' + part2 + '"')
+    return [part1, part2]
+
+def convert_file(in_file, out_path, params, debug):
+
+    # Regexp patterns
+    paramrex = re.compile('\.param[ \t]+(.*)')
+    subrex = re.compile('\.subckt[ \t]+([^ \t]+)[ \t]+([^ \t]*)')
+    modelrex = re.compile('\.model[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+(.*)')
+    endsubrex = re.compile('\.ends[ \t]+(.+)')
+    increx = re.compile('\.include[ \t]+')
+
+    with open(in_file, 'r') as ifile:
+        inplines = ifile.read().splitlines()
+
+    insubckt = False
+    inparam = False
+    inmodel = False
+    inpinlist = False
+
+    # Output lines
+    spicelines = []
+    paramlines = []
+    subparams = []
+
+    for line in inplines:
+
+        # Item 1.  Handle comment lines
+        if line.startswith('*'):
+            spicelines.append(line.strip())
+            continue
+
+        # Item 2.  Flag continuation lines.
+        if line.startswith('+'):
+            contline = True
+        else:
+            contline = False
+            if line.strip() != '':
+                if inpinlist:
+                    inpinlist = False
+                if inparam:
+                    # Dump additional subcircuit parameters and clear
+                    if subparams:
+                        spicelines.extend(subparams)
+                        subparams = []
+
+                    # Dump parameters to file contents and clear
+                    spicelines.extend(paramlines)
+                    paramlines = []
+                    inparam = False
+
+        # Item 3.  Handle blank lines like comment lines
+        if line.strip() == '':
+            if inparam:
+                paramlines.append(line)
+            else:
+                spicelines.append(line)
+            continue
+
+        # Item 4.  Handle continuation lines
+        # Remove lines that have a continuation mark and nothing else.
+        if contline:
+            if inparam:
+                # Continue handling parameters
+                if insubckt:
+                    # Find subcircuit parameters and record what line they were found on
+                    psplit = param_split(line, params, debug)
+                    if psplit[0]:
+                        paramlines.append(psplit[0])
+                    if psplit[1]:
+                        subparams.append(psplit[1])
+                else:
+                    paramlines.append(line)
+            else:
+                if line.strip() != '+':
+                    spicelines.append(line)
+            continue
+
+        # Item 5.  Regexp matching
+
+        # parameters
+        pmatch = paramrex.match(line)
+        if pmatch:
+            inparam = True
+            if insubckt:
+                # Find subcircuit parameters and record what line they were found on
+                psplit = param_split(line, params, debug)
+                if psplit[0]:
+                    paramlines.append(psplit[0])
+                if psplit[1]:
+                    subparams.append(psplit[1])
+            else:
+                paramlines.append(line)
+            continue
+
+        # model
+        mmatch = modelrex.match(line)
+        if mmatch:
+            spicelines.append(line)
+            continue
+            inmodel = 2
+            continue
+
+        if not insubckt:
+            # Things to parse if not in a subcircuit
+
+            imatch = subrex.match(line)
+            if imatch:
+                insubckt = True
+                inpinlist = True
+                spicelines.append(line)
+                continue
+
+        else:
+            # Things to parse when inside of a ".subckt" block
+
+            if inpinlist:
+                spicelines.append(line)
+                continue
+                
+            else:
+                ematch = endsubrex.match(line)
+                if ematch:
+                    spicelines.append(line)
+                    insubckt = False
+                    inmodel = False
+                    continue
+
+        # Copy line as-is
+        spicelines.append(line)
+
+    # Output the result to out_file.
+    out_file = os.path.split(in_file)[1]
+    with open(out_path + '/' + out_file, 'w') as ofile:
+        for line in spicelines:
+            print(line, file=ofile)
+
+if __name__ == '__main__':
+    debug = False
+
+    if len(sys.argv) == 1:
+        print("No options given to fix_subckt_params.py.")
+        usage()
+        sys.exit(0)
+
+    optionlist = []
+    arguments = []
+
+    for option in sys.argv[1:]:
+        if option.find('-', 0) == 0:
+            optionlist.append(option)
+        else:
+            arguments.append(option)
+
+    if len(arguments) < 3:
+        print("Wrong number of arguments given to fix_subckt_params.py.")
+        usage()
+        sys.exit(0)
+
+    if '-debug' in optionlist:
+        debug = True
+
+    inpath = arguments[0]
+    outpath = arguments[1]
+    params = arguments[2:]
+
+    if not os.path.exists(inpath):
+        print('No such source file ' + inpath)
+        sys.exit(1)
+
+    if not os.path.isfile(inpath):
+        print('Input path ' + inpath + ' is not a file.')
+        sys.exit(1)
+ 
+    convert_file(inpath, outpath, params, debug)
+
+    print('Done.')
+    exit(0)
diff --git a/common/print_subckt_params.py b/common/print_subckt_params.py
new file mode 100755
index 0000000..c8f75eb
--- /dev/null
+++ b/common/print_subckt_params.py
@@ -0,0 +1,243 @@
+#!/bin/env python3
+#
+# print_subckt_params.py --
+#
+# Print a list of subcircuit parameters, dividing them into those which
+# are declared on the subcircuit line, and those that are declared inside
+# the scope of the subcircuit.
+# 
+# The single argument is <path_to_input>
+# <path_to_input> should be the path to a single file.
+
+import os
+import sys
+import re
+import glob
+
+def usage():
+    print('print_subckt_params.py <path_to_input>')
+    print('where:')
+    print('   <path_to_input> is the path to the input file to parse')
+
+def parse_pins(line, debug):
+    # Regexp patterns
+    subrex = re.compile('\.subckt[ \t]+[^ \t]+[ \t]+(.*)')
+    parm1rex = re.compile('([^= \t]+)[ \t]*=[ \t]*[^ \t]+[ \t]*(.*)')
+    parm2rex = re.compile('([^= \t]+)[ \t]*(.*)')
+
+    params = []
+
+    pmatch = subrex.match(line)
+    if pmatch:
+        rest = pmatch.group(1)
+    else:
+        # Could not parse
+        return []
+
+    while rest != '':
+        if rest.startswith('$ '):
+            break
+        pmatch = parm1rex.match(rest)
+        if pmatch:
+            rest = pmatch.group(2)
+            params.append(pmatch.group(1))
+        else:
+            pmatch = parm2rex.match(rest)
+            if pmatch:
+                # This is a pin, so don't list it
+                rest = pmatch.group(2)
+
+    return params
+
+# Parse a parameter line for parameters, and divide into two parts,
+# returned as a list.  If a parameter name matches an entry in 'params',
+# it goes in the second list.  Otherwise, it goes in the first list.
+# The first list is returned as-is minus any parameters that were split
+# into the second list.  The second list must begin with '+', as it will
+# be output as a continuation line for the subcircuit.
+
+def param_parse(line, debug):
+    # Regexp patterns
+    parm1rex = re.compile('\.param[ \t]+(.*)')
+    parm2rex = re.compile('\+[ \t]*(.*)')
+    parm3rex = re.compile('([^= \t]+)[ \t]*=[ \t]*[^ \t]+[ \t]*(.*)')
+    parm4rex = re.compile('([^= \t]+)[ \t]*(.*)')
+
+    if debug:
+        print('Diagnostic:  param line in = "' + line + '"')
+
+    params = []
+
+    pmatch = parm1rex.match(line)
+    if pmatch:
+        rest = pmatch.group(1)
+    else:
+        pmatch = parm2rex.match(line)
+        if pmatch:
+            rest = pmatch.group(1)
+        else:
+            # Could not parse;  return list with line and empty string
+            return []
+
+    while rest != '':
+        if rest.startswith('$ '):
+            break
+        pmatch = parm3rex.match(rest)
+        if pmatch:
+            rest = pmatch.group(2)
+            params.append(pmatch.group(1))
+        else:
+            pmatch = parm4rex.match(rest)
+            if pmatch:
+                rest = pmatch.group(2)
+                params.append(pmatch.group(1))
+
+    return params
+
+def parse_file(in_file, debug):
+
+    # Regexp patterns
+    paramrex = re.compile('\.param[ \t]+(.*)')
+    subrex = re.compile('\.subckt[ \t]+([^ \t]+)[ \t]+([^ \t]*)')
+    modelrex = re.compile('\.model[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+(.*)')
+    endsubrex = re.compile('\.ends[ \t]+(.+)')
+    increx = re.compile('\.include[ \t]+')
+
+    with open(in_file, 'r') as ifile:
+        inplines = ifile.read().splitlines()
+
+    insubckt = False
+    inparam = False
+    inmodel = False
+    inpinlist = False
+
+    pinparams = []
+    paramlist = []
+    subname = ''
+
+    for line in inplines:
+
+        # Item 1.  Handle comment lines
+        if line.startswith('*'):
+            continue
+
+        # Item 2.  Flag continuation lines.
+        if line.startswith('+'):
+            contline = True
+        else:
+            contline = False
+            if line.strip() != '':
+                if inpinlist:
+                    inpinlist = False
+                if inparam:
+                    inparam = False
+
+        # Item 3.  Handle blank lines like comment lines
+        if line.strip() == '':
+            continue
+
+        # Item 4.  Handle continuation lines
+        # Remove lines that have a continuation mark and nothing else.
+        if contline:
+            if inparam:
+                # Continue handling parameters
+                if insubckt:
+                    # Find subcircuit parameters and record what line they were found on
+                    if inpinlist:
+                        pinparams.extend(param_parse(line, debug))
+                    else:
+                        paramlist.extend(param_parse(line, debug))
+                            
+            continue
+
+        # Item 5.  Regexp matching
+
+        # parameters
+        pmatch = paramrex.match(line)
+        if pmatch:
+            inparam = True
+            if insubckt:
+                if inpinlist:
+                    inpinlist = False
+                # Find subcircuit parameters and record what line they were found on
+                paramlist.extend(param_parse(line, debug))
+            continue
+
+        # model
+        mmatch = modelrex.match(line)
+        if mmatch:
+            inmodel = 2
+            continue
+
+        if not insubckt:
+            # Things to parse if not in a subcircuit
+
+            imatch = subrex.match(line)
+            if imatch:
+                insubckt = True
+                inpinlist = True
+                subname = imatch.group(1)
+                pinparams = parse_pins(line, debug)
+                paramlist = []
+                continue
+
+        else:
+            ematch = endsubrex.match(line)
+            if ematch:
+                insubckt = False
+                inmodel = False
+                # Print out results
+                if debug:
+                    print('File: ', end='')
+                print(in_file)
+                if debug:
+                    print('Subcircuit: ', end='')
+                print(subname)
+                if debug:
+                    print('Callable parameters: ', end='')
+                if len(pinparams) > 0:
+                    print(' '.join(pinparams))
+                else:
+                    print('----')
+                if debug:
+                    print('Internal parameters: ', end='')
+                if len(paramlist) > 0:
+                    print(' '.join(paramlist))
+                else:
+                    print('----')
+                print()
+                continue
+
+if __name__ == '__main__':
+    debug = False
+
+    if len(sys.argv) == 1:
+        print("No options given to print_subckt_params.py.")
+        usage()
+        sys.exit(0)
+
+    optionlist = []
+    arguments = []
+
+    for option in sys.argv[1:]:
+        if option.find('-', 0) == 0:
+            optionlist.append(option)
+        else:
+            arguments.append(option)
+
+    if len(arguments) < 1:
+        print("Wrong number of arguments given to print_subckt_params.py.")
+        usage()
+        sys.exit(0)
+
+    if '-debug' in optionlist:
+        debug = True
+
+    inpath = arguments[0]
+
+    if not os.path.exists(inpath):
+        print('No such source file ' + inpath)
+        sys.exit(1)
+
+    parse_file(inpath, debug)
+    exit(0)
diff --git a/common/soc_floorplanner.py b/common/soc_floorplanner.py
index 18a8995..1cdc52c 100755
--- a/common/soc_floorplanner.py
+++ b/common/soc_floorplanner.py
@@ -308,6 +308,18 @@
         else:
             projectpath = pwdname
 
+        # Also check for project below the current working directory
+
+        if not os.path.exists(projectpath + '/mag'):
+            print('No project path, checking subdirectories')
+            dlist = os.listdir(projectpath)
+            for dir in dlist:
+                print('Checking ' + projectpath + '/' + dir)
+                if os.path.exists(projectpath + '/' + dir + '/mag'):
+                    projectpath = projectpath + '/' + dir
+                    print('Found!')
+                    break
+
         projectroot = os.path.split(projectpath)[0]
         projectdirname = os.path.split(projectpath)[1]
 
diff --git a/common/spectre_to_spice.py b/common/spectre_to_spice.py
index 820c870..a89cdd4 100755
--- a/common/spectre_to_spice.py
+++ b/common/spectre_to_spice.py
@@ -103,6 +103,8 @@
 
             if is_number(value):
                 fmtline.append(value)
+            elif value.strip().startswith("'"):
+                fmtline.append(value)
             else:
                 fmtline.append('{' + value + '}')
 
@@ -310,7 +312,9 @@
                 # Continue to "if inmodel == 1" block below
             else:
                 fmtline, ispassed = parse_param_line(mmatch.group(3), True, False, True, ispassed)
-                modellines.append('.model ' + mmatch.group(1) + ' ' + mmatch.group(2) + ' ' + fmtline)
+                if isspectre and (modtype == 'resistor' or modtype == 'r2'):
+                    modtype = 'r'
+                modellines.append('.model ' + modname + ' ' + modtype + ' ' + fmtline)
                 if fmtline != '':
                     inparam = True
 
diff --git a/common/split_one_spice.py b/common/split_one_spice.py
new file mode 100755
index 0000000..c454c8d
--- /dev/null
+++ b/common/split_one_spice.py
@@ -0,0 +1,425 @@
+#!/bin/env python3
+#
+# split_one_spice.py --
+#
+# Script that reads a SPICE file that contains multiple models and
+# subcircuits, and splits it into one file per subcircuit, with each
+# file containing any related in-lined models.
+#
+# The arguments are <path_to_input> and <path_to_output>.
+# <path_to_input> should be the path to a single file, while
+# <path_to_output> is the path to a directory where the split files will
+# be put.
+
+import os
+import sys
+import re
+import glob
+
+def usage():
+    print('split_one_spice.py <path_to_input> <path_to_output>')
+
+def convert_file(in_file, out_path):
+
+    # Regexp patterns
+    paramrex = re.compile('\.param[ \t]+(.*)')
+    subrex = re.compile('\.subckt[ \t]+([^ \t]+)[ \t]+([^ \t]*)')
+    modelrex = re.compile('\.model[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+(.*)')
+    endsubrex = re.compile('\.ends[ \t]+(.+)')
+    increx = re.compile('\.include[ \t]+')
+
+    with open(in_file, 'r') as ifile:
+        inplines = ifile.read().splitlines()
+
+    insubckt = False
+    inparam = False
+    inmodel = False
+    inpinlist = False
+    subname = ''
+    modname = ''
+    modtype = ''
+
+    # Keep track of what the subcircuit names are
+    subnames = []
+    filenos = {}
+
+    # Keep track of what parameters are used by what subcircuits
+    paramlist = {}
+
+    # Enumerate which lines go to which files
+    linedest = [-1]*len(inplines)
+    fileno = -1;
+    lineno = -1;
+
+    for line in inplines:
+        lineno += 1
+
+        # Item 1.  Handle comment lines
+        if line.startswith('*'):
+            linedest[lineno] = fileno
+            continue
+
+        # Item 2.  Flag continuation lines
+        if line.startswith('+'):
+            contline = True
+        else:
+            contline = False
+            if line.strip() != '':
+                if inparam:
+                    inparam = False
+                if inpinlist:
+                    inpinlist = False
+
+        # Item 3.  Handle blank lines like comment lines
+        if line.strip() == '':
+            linedest[lineno] = fileno
+            continue
+
+        # Item 4.  Handle continuation lines
+        if contline:
+            if inparam:
+                # Continue handling parameters
+                linedest[lineno] = fileno
+                if not insubckt:
+                    # Find (global) parameters and record what line they were found on
+                    ptok = list(item for item in line[1:].strip().split() if item != '=')
+                    for param, value in zip(*[iter(ptok)]*2):
+                        paramlist[param] = lineno
+                else:
+                    # Find if a global parameter was used.  Assign it to this
+                    # subcircuit.  If it has already been used, assign it to
+                    # be a common parameter
+                    for param in paramlist:
+                        if param in line[1:]:
+                            checkfile = linedest[paramlist[param]]
+                            if checkfile == -1:
+                                linedest[paramlist[param]] = fileno
+                            elif checkfile != fileno:
+                                linedest[paramlist[param]] = -3
+                continue
+
+        # Item 5.  Regexp matching
+
+        # parameters
+        pmatch = paramrex.match(line)
+        if pmatch:
+            inparam = True
+            linedest[lineno] = fileno
+            if not insubckt:
+                # Find (global) parameters and record what line they were found on
+                ptok = list(item for item in pmatch.group(1).split() if item != '=')
+                for param, value in zip(*[iter(ptok)]*2):
+                    paramlist[param] = lineno
+            else:
+                # Find if a global parameter was used.  Assign it to this
+                # subcircuit.  If it has already been used, assign it to
+                # be a common parameter
+                for param in paramlist:
+                    if param in pmatch.group(1):
+                        checkfile = linedest[paramlist[param]]
+                        if checkfile == -1:
+                            linedest[paramlist[param]] = fileno
+                        if checkfile != fileno:
+                            linedest[paramlist[param]] = -3
+            continue
+
+        # model
+        mmatch = modelrex.match(line)
+        if mmatch:
+            modname = mmatch.group(1)
+            modtype = mmatch.group(2)
+
+            linedest[lineno] = fileno
+            inmodel = 2
+            continue
+
+        if not insubckt:
+            # Things to parse if not in a subcircuit
+
+            imatch = subrex.match(line)
+            if imatch:
+                insubckt = True
+                subname = imatch.group(1)
+                fileno = len(subnames)
+                subnames.append(subname)
+                filenos[subname] = fileno
+
+                if fileno > 0:
+                    # If this is not the first subcircuit, then add all blank
+                    # and comment lines above it to the same file
+
+                    lastno = -1
+                    tline = lineno - 1
+                    while tline >= 0:
+                        tinp = inplines[tline]
+                        # Backup through all comment and blank lines
+                        if not tinp.startswith('*') and not tinp.strip() == '':
+                            lastno = linedest[tline]
+                            tline += 1;
+                            break;
+                        tline -= 1;
+
+                    while tline < lineno:
+                        # Forward through all blank lines, and assign them to
+                        # the previous subcell.
+                        tinp = inplines[tline]
+                        if tinp.strip() != '':
+                            break;
+                        if linedest[tline] == -1:
+                            linedest[tline] = lastno
+                        tline += 1;
+
+                    while tline < lineno:
+                        linedest[tline] = fileno
+                        tline += 1;
+                else:
+                    # If this is the first subcircuit encountered, then assign
+                    # to it the nearest block of comment lines before it.  If
+                    # those comment lines include a parameter or statistics
+                    # block, then abandon the effort.
+
+                    # Backup through blank lines immediately above
+                    abandon = False
+                    tline = lineno - 1
+                    while tline >= 0:
+                        tinp = inplines[tline]
+                        if not tinp.strip() == '':
+                            break;
+                        tline -= 1;
+
+                    while tline > 0:
+                        # Backup through the next comment block above
+                        tinp = inplines[tline]
+                        if not tinp.startswith('*'):
+                            tline += 1;
+                            break;
+                        elif tinp.strip('*').strip().startswith('statistics'):
+                            abandon = True
+                        tline -= 1;
+
+                    if tline == 0:
+                        abandon = True
+
+                    if not abandon:
+                        while tline < lineno:
+                            linedest[tline] = fileno
+                            tline += 1;
+ 
+                devrex = re.compile(subname + '[ \t]*([^ \t]+)[ \t]*([^ \t]+)[ \t]*(.*)', re.IGNORECASE)
+                inpinlist = True
+                linedest[lineno] = fileno
+                continue
+
+        else:
+            # Things to parse when inside of a ".subckt" block
+
+            if inpinlist:
+                # Watch for pin list continuation line.
+                linedest[lineno] = fileno
+                continue
+                
+            else:
+                ematch = endsubrex.match(line)
+                if ematch:
+                    if ematch.group(1) != subname:
+                        print('Error:  "ends" name does not match "subckt" name!')
+                        print('"ends" name = ' + ematch.group(1))
+                        print('"subckt" name = ' + subname)
+
+                    linedest[lineno] = fileno
+                    fileno = -1
+
+                    insubckt = False
+                    inmodel = False
+                    subname = ''
+                    continue
+                else:
+                    linedest[lineno] = fileno
+                    continue
+
+    # Sort subcircuit names
+    subnames.sort(reverse=True)
+
+    # Look for any lines containing parameters in paramlist.  If those lines
+    # are unassigned (-1), then assign them to the same cell that the parameter
+    # was assigned to.  NOTE:  Assumes that there will never be two parameters
+    # on the same line that were from two different subcircuits that is not
+    # already marked as a common parameter.
+
+    lineno = -1
+    for line in inplines:
+        lineno += 1
+        if linedest[lineno] == -1:
+            for param in paramlist:
+                if param in line:
+                    linedest[lineno] = linedest[paramlist[param]]
+                    break
+
+    # Ad hoc method:  Look for any lines containing each cell name, and assign
+    # that line to the cell.  That isolates parameters that belong to only one
+    # cell.  Ignore comment lines from line 1 down to the first non-comment line.
+    # Since all parameters and comment blocks have been handled, this is not
+    # likely to change anything.
+
+    lineno = -1
+    for line in inplines:
+        lineno = -1
+        if not line.startswith('*'):
+            break
+
+    topcomm = True
+    for line in inplines:
+        lineno += 1
+        if topcomm and not line.startswith('*'):
+            topcomm = False
+
+        if not topcomm:
+            if linedest[lineno] == -1:
+                for subname in subnames:
+                    subno = filenos[subname]
+                    if subname in line:
+                        linedest[lineno] = subno
+                        break
+
+    # All lines marked -1 except for comment lines should be remarked -3
+    # (go into the common file only)
+
+    lineno = -1
+    for line in inplines:
+        lineno += 1
+        if linedest[lineno] == -1:
+            if not line.startswith('*'):
+                linedest[lineno] = -3
+
+    # All comment lines that are surrounded by lines marked -3 should
+    # also be marked -3.  This keeps comments that are completely inside
+    # blocks that are only in the common file out of the individual files.
+
+    lineno = 0
+    for line in inplines[1:]:
+        lineno += 1
+        if linedest[lineno] == -1 and linedest[lineno - 1] == -3:
+            testline = lineno + 1
+            while linedest[testline] == -1:
+                testline += 1
+            if linedest[testline] == -3:
+                testline = lineno
+                while linedest[testline] == -1:
+                    linedest[testline] = -3
+                    testline += 1
+
+    froot = os.path.split(in_file)[1]
+    for subname in subnames:
+        subno = filenos[subname]
+        fext = os.path.splitext(in_file)[1]
+
+        # Guard against one of the split files having the same name as
+        # the original, since we need to keep the original file.
+        if subname == os.path.splitext(froot)[0]:
+            fext = '_split' + fext
+
+        # Output the result to out_file.
+        with open(out_path + '/' + subname + fext, 'w') as ofile:
+            firstline = True
+            lineno = -1
+            for line in inplines:
+                lineno += 1
+                if linedest[lineno] == subno or linedest[lineno] == -1:
+                    if firstline:
+                        print('* File ' + subname + fext + ' split from ' + froot + ' by split_one_spice.py', file=ofile)
+                        firstline = False
+                    print(line, file=ofile)
+
+    # Debug:  Print one diagnostic file (do this before messing with the
+    # linedest[] entries in the next step).  This debug file shows which
+    # lines of the file are split into which file, and which lines are
+    # common.
+
+    ffile = os.path.split(in_file)[1]
+    froot = os.path.splitext(ffile)[0]
+    fext = os.path.splitext(ffile)[1]
+
+    with open(out_path + '/' + froot + '_debug' + fext, 'w') as ofile:
+        for subname in subnames:
+            subno = filenos[subname]
+            print(str(subno) + '\t' + subname, file=ofile)
+
+        print('\n', file=ofile)
+
+        lineno = -1
+        for line in inplines:
+            lineno += 1
+            print(str(linedest[lineno]) + '\t' + line, file=ofile)
+            
+    # Reset all linedest[] entries except the bottommost entry for each subcircuit.
+    lineno = len(inplines)
+    subrefs = [0] * len(subnames)
+    while lineno > 0:
+        lineno -= 1
+        if linedest[lineno] >= 0:
+            if subrefs[linedest[lineno]] == 0:
+                subrefs[linedest[lineno]] = 1
+            else:
+                linedest[lineno] = -2
+
+    # Print the original file, including each of the new files.
+    # Also print out all lines marked "-1" or "-3"
+
+    with open(out_path + '/' + froot +  fext, 'w') as ofile:
+        lineno = -1
+        subno = -1
+        for line in inplines:
+            lineno += 1
+            if linedest[lineno] == -1 or linedest[lineno] == -3 :
+                print(line, file=ofile)
+            elif linedest[lineno] >= 0:
+                for subname in subnames:
+                    if filenos[subname] == linedest[lineno]:
+                        fext = os.path.splitext(in_file)[1]
+                        if subname == os.path.splitext(froot)[0]:
+                            fext = '_split' + fext
+                        break
+                print('.include ' + subname + fext, file=ofile)
+                subno = linedest[lineno]
+
+if __name__ == '__main__':
+    debug = False
+
+    if len(sys.argv) == 1:
+        print("No options given to split_one_spice.py.")
+        usage()
+        sys.exit(0)
+
+    optionlist = []
+    arguments = []
+
+    for option in sys.argv[1:]:
+        if option.find('-', 0) == 0:
+            optionlist.append(option)
+        else:
+            arguments.append(option)
+
+    if len(arguments) != 2:
+        print("Wrong number of arguments given to split_one_spice.py.")
+        usage()
+        sys.exit(0)
+
+    if '-debug' in optionlist:
+        debug = True
+
+    inpath = arguments[0]
+    outpath = arguments[1]
+    do_one_file = False
+
+    if not os.path.exists(inpath):
+        print('No such source file ' + inpath)
+        sys.exit(1)
+
+    if not os.path.isfile(inpath):
+        print('Input path ' + inpath + ' is not a file.')
+        sys.exit(1)
+ 
+    convert_file(inpath, outpath)
+
+    print('Done.')
+    exit(0)