blob: dedad2467fa334af04f8fc7fbdfd22ef0ec84540 [file] [log] [blame]
#!/usr/bin/env python3
#
# split_spice.py --
#
# Script that reads the SPICE output from the convert_spectre.py script,
# which typically has parsed through files containing inline subcircuits
# and recast them as normal SPICE .subckt ... .ends entries, and pulled
# any model blocks inside the inline subckt out. This script removes
# each .subckt ... .ends block from every file and moves it to its own
# file named <subckt_name>.spice.
#
# The arguments are <path_to_input> and <path_to_output>. If there is
# only one argument, or if <path_to_input> is equal to <path_to_output>,
# then the new .spice files are added to the directory and the model
# files are modified in place. Otherwise, all modified files are placed
# in <path_to_output>.
import os
import sys
import re
import glob
def usage():
print('split_spice.py <path_to_input> <path_to_output>')
def convert_file(in_file, out_path, out_file):
# 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
spicelines = []
subcktlines = []
savematch = None
subname = ''
modname = ''
modtype = ''
for line in inplines:
# Item 1. Handle comment lines
if line.startswith('*'):
if subcktlines != []:
subcktlines.append(line.strip())
else:
spicelines.append(line.strip())
continue
# Item 2. Flag continuation lines
if line.startswith('+'):
contline = True
else:
contline = False
if inparam:
inparam = False
if inpinlist:
inpinlist = False
# Item 3. Handle blank lines like comment lines
if line.strip() == '':
if subcktlines != []:
subcktlines.append(line)
else:
spicelines.append(line)
continue
# Item 4. Handle continuation lines
if contline:
if inparam:
# Continue handling parameters
if subcktlines != []:
subcktlines.append(line)
else:
spicelines.append(line)
continue
# Item 5. Regexp matching
# If inside a subcircuit, remove "parameters". If outside,
# change it to ".param"
pmatch = paramrex.match(line)
if pmatch:
inparam = True
if insubckt:
subcktlines.append(line)
else:
spicelines.append(line)
continue
# model
mmatch = modelrex.match(line)
if mmatch:
modellines = []
modname = mmatch.group(1)
modtype = mmatch.group(2)
spicelines.append(line)
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)
devrex = re.compile(subname + '[ \t]*([^ \t]+)[ \t]*([^ \t]+)[ \t]*(.*)', re.IGNORECASE)
inpinlist = True
subcktlines.append(line)
continue
else:
# Things to parse when inside of a ".subckt" block
if inpinlist:
# Watch for pin list continuation line.
subcktlines.append(line)
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)
subcktlines.append(line)
# Dump the contents of subcktlines into a file
subckt_file = subname + '.spice'
with open(out_path + '/' + subckt_file, 'w') as ofile:
print('* Subcircuit definition of cell ' + subname, file=ofile)
for line in subcktlines:
print(line, file=ofile)
subcktlines = []
# Add an include statement to this file in the source
spicelines.append('.include ' + subckt_file)
insubckt = False
inmodel = False
subname = ''
continue
# Copy line as-is
if insubckt:
subcktlines.append(line)
else:
spicelines.append(line)
# Output the result to out_file.
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 split_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_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 directory ' + inpath)
sys.exit(1)
if os.path.isfile(inpath):
do_one_file = True
if do_one_file:
if os.path.exists(outpath):
print('Error: File ' + outpath + ' exists.')
sys.exit(1)
convert_file(inpath, outpath)
else:
if not os.path.exists(outpath):
os.makedirs(outpath)
infilelist = glob.glob(inpath + '/*')
for filename in infilelist:
fileext = os.path.splitext(filename)[1]
# Ignore verilog or verilog-A files that might be in a model directory
if fileext == '.v' or fileext == '.va':
continue
froot = os.path.split(filename)[1]
convert_file(filename, outpath, froot)
print('Done.')
exit(0)