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)