Created a new script that deals with the problem of parameter names in the monte carlo parameter files that shadow names of devices. ngspice does not handle this; this could be an ngspice error, but the best practice is not to have confusing parameter names, so the script modifies the names by stripping off the leading sky130_fd_pr__ from the parameter name so that it no longer conflicts with the device name.
diff --git a/sky130/Makefile.in b/sky130/Makefile.in index 989e6c3..9bc14de 100644 --- a/sky130/Makefile.in +++ b/sky130/Makefile.in
@@ -811,6 +811,8 @@ 2>&1 | tee -a ${SKY130A}_make.log || true ./custom/scripts/process_params.py \ 2>&1 | tee -a ${SKY130A}_make.log || true + ./custom/scripts/montecarlo_hack.py \ + 2>&1 | tee -a ${SKY130A}_make.log || true # Custom: Add "mc" section to sky130.lib.spice head -n-1 ${STAGING_PATH}/${SKY130A}/libs.tech/ngspice/sky130.lib.spice \ | ${SED} -e '/^\.lib/a.param mc_pr_switch=0' \
diff --git a/sky130/custom/scripts/montecarlo_hack.py b/sky130/custom/scripts/montecarlo_hack.py new file mode 100755 index 0000000..2c8ce48 --- /dev/null +++ b/sky130/custom/scripts/montecarlo_hack.py
@@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +# +#-------------------------------------------------------------------- +# Workaround for the problem that ngspice is unable to accept a +# parameter name that shadows a device name. Parameters in the +# files critical.spice and montecarlo.spice that shadow parameter +# names have the leading sky130_fd_pr__ stripped off to prevent +# this from being a problem. +#-------------------------------------------------------------------- + +import os +import re +import sys + +searchpath = ['sky130A/libs.tech/ngspice/parameters/critical.spice', + 'sky130A/libs.tech/ngspice/parameters/montecarlo.spice'] + +if len(sys.argv) > 1: + searchpath = sys.argv[1] + +# Flag all parameters that have the same name as devices. +# These parameters are unused and must be deleted. + +excludelist = [ + 'sky130_fd_pr__nfet_20v0_nvt_iso', + 'sky130_fd_pr__nfet_20v0_nvt', + 'sky130_fd_pr__nfet_20v0_iso', + 'sky130_fd_pr__nfet_20v0_zvt', + 'sky130_fd_pr__nfet_20v0', + 'sky130_fd_pr__pfet_20v0', + 'sky130_fd_pr__nfet_01v8_lvt', + 'sky130_fd_pr__pfet_01v8_mvt', + 'sky130_fd_pr__pfet_01v8', + 'sky130_fd_pr__nfet_g5v0d16v0', + 'sky130_fd_pr__pfet_g5v0d16v0', + 'sky130_fd_pr__special_nfet_pass_lvt', + 'sky130_fd_pr__pnp_05v5_W0p68L0p68'] + +# For each entry in the exclude list, create a regular expression +# for detecting that entry and excluding other similar cases that +# aren't the parameter. Items with preceding "/" are the device +# filename, and items with additional text are other parameters. + +rexpat = {} +rexdict = {} + +for item in excludelist: + rexpat[item] = '([^/])' + item + '(?=[^_])' + rexdict[item] = re.compile('([^/])' + item + '(?=[^_])') + +#-------------------------------------------------------------------- + +for infile_name in searchpath: + filepath = os.path.split(infile_name)[0] + outfile_name = os.path.join(filepath, 'temp') + + infile = open(infile_name, 'r') + outfile = open(outfile_name, 'w') + + line_number = 0 + replaced_something = False + for line in infile: + line_number += 1 + + newline = line + for device in excludelist: + rmatch = rexdict[device].search(line) + if rmatch: + replacement = device[14:] + newline = re.sub(rexpat[device], '\g<1>' + replacement, newline) + replaced_something = True + + outfile.write(newline) + + infile.close() + outfile.close() + if replaced_something: + print("Something was replaced in '{}'".format(infile_name)) + os.rename(outfile_name, infile_name) + else: + print("Nothing was replaced in '{}'.".format(infile_name)) + os.remove(outfile_name) +
diff --git a/sky130/custom/scripts/process_params.py b/sky130/custom/scripts/process_params.py index 64647c4..1c0e44a 100755 --- a/sky130/custom/scripts/process_params.py +++ b/sky130/custom/scripts/process_params.py
@@ -25,17 +25,6 @@ filelist = [] -# Manual hack---flag all parameters that have the same name as devices. -# These parameters are unused and must be deleted. - -excludelist = ['sky130_fd_pr__nfet_20v0_nvt', 'sky130_fd_pr__nfet_20v0_nvt_iso', - 'sky130_fd_pr__nfet_20v0', 'sky130_fd_pr__nfet_20v0_iso', - 'sky130_fd_pr__nfet_20v0_zvt', 'sky130_fd_pr__pfet_20v0', - 'sky130_fd_pr__nfet_01v8_lvt', 'sky130_fd_pr__special_nfet_pass_lvt', - 'sky130_fd_pr__nfet_g5v0d16v0', 'sky130_fd_pr__pfet_01v8_mvt', - 'sky130_fd_pr__pnp_05v5_W0p68L0p68', 'sky130_fd_pr__pfet_01v8', - 'sky130_fd_pr__pfet_g5v0d16v0'] - #-------------------------------------------------------------------- # Step 1. Gather variables #-------------------------------------------------------------------- @@ -68,15 +57,8 @@ if 'vary' in tokens: if ('dist=gauss' in tokens) or ('gauss' in tokens): process_param = tokens[2] - # Issue: There are improper parameters that - # shadow device names. They are not used and - # should be detected and elminated. - if (process_param in excludelist): - print('Found parameter ' + process_param + ' that shadows a device name.') - replacement = '' - else: - std_dev = float(tokens[-1].split('=')[-1]) - replacement = ' + {}*AGAUSS(0,{!s},1)'.format(pr_switch_param, std_dev) + std_dev = float(tokens[-1].split('=')[-1]) + replacement = ' + {}*AGAUSS(0,{!s},1)'.format(pr_switch_param, std_dev) process_params.append((process_param, replacement)) infile.close() @@ -125,12 +107,9 @@ newline = line for (param, replacement) in process_params: if ' ' + param + ' ' in newline: + newline = newline.strip('\n') + replacement + '\n' + print(" Line {}: Found process parameter '{}' and appended '{}'.".format(line_number, param, replacement)) replaced_something = True - if replacement == '': - newline = '** ' + newline - else: - newline = newline.strip('\n') + replacement + '\n' - print(" Line {}: Found process parameter '{}' and appended '{}'.".format(line_number, param, replacement)) outfile.write(newline) else: outfile.write(line)