Added a number of scripts to the gf180mcu build to add in the
substrate and well connections VPW and VNW to all views, including
technology LEF, LEF, verilog, SPICE, and liberty. Also added a
script to build the minimum and maximum corner technology LEF files
for the two standard cell libraries, and modified the openlane
configuration to make use of them.
diff --git a/gf180mcu/Makefile.in b/gf180mcu/Makefile.in
index cab82c6..fd3f12f 100644
--- a/gf180mcu/Makefile.in
+++ b/gf180mcu/Makefile.in
@@ -168,7 +168,7 @@
PDK_LIB_PR = ${EF_URL}/globalfoundries-pdk-libs-gf180mcu_fd_pr
PDK_LIB_IO = ${PDK_URL}/globalfoundries-pdk-libs-gf180mcu_fd_io
PDK_LIB_SC_7T5V0 = ${EF_URL}/globalfoundries-pdk-libs-gf180mcu_fd_sc_mcu7t5v0
-PDK_LIB_SC_9T5V0 = ${PDK_URL}/globalfoundries-pdk-libs-gf180mcu_fd_sc_mcu9t5v0
+PDK_LIB_SC_9T5V0 = ${EF_URL}/globalfoundries-pdk-libs-gf180mcu_fd_sc_mcu9t5v0
PDK_LIB_SRAM = ${PDK_URL}/globalfoundries-pdk-ip-gf180mcu_fd_ip_sram
PDK_LIB_OSU_SC = ${OSU_URL}/globalfoundries-pdk-libs-gf180mcu_osu_sc
@@ -758,116 +758,159 @@
${STAGE} -source ${GF180MCU_SC_9T5V0_PATH} \
-target ${STAGING_PATH}/${GF180MCU$*} \
-techlef tech/gf180mcu_${$*_FULLSTACK}_9t_tech.lef \
- rename=gf180mcu_fd_sc_mcu9t5v0.tlef \
+ filter=custom/scripts/fix_techlef.py \
+ rename=gf180mcu_fd_sc_mcu9t5v0__nom.tlef \
-cdl cells/*/*.cdl compile-only noconvert \
-liberty cells/*/*_ff_125C_1v98.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu9t5v0__ff_125C_1v98.lib \
rename=gf180mcu_fd_sc_mcu9t5v0__ff_125C_1v98 \
-liberty cells/*/*_ff_n40C_1v98.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu9t5v0__ff_n40C_1v98.lib \
rename=gf180mcu_fd_sc_mcu9t5v0__ff_n40C_1v98 \
-liberty cells/*/*_ff_125C_3v60.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu9t5v0__ff_125C_3v60.lib \
rename=gf180mcu_fd_sc_mcu9t5v0__ff_125C_3v60 \
-liberty cells/*/*_ff_n40C_3v60.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu9t5v0__ff_n40C_3v60.lib \
rename=gf180mcu_fd_sc_mcu9t5v0__ff_n40C_3v60 \
-liberty cells/*/*_ff_125C_5v50.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu9t5v0__ff_125C_5v50.lib \
rename=gf180mcu_fd_sc_mcu9t5v0__ff_125C_5v50 \
-liberty cells/*/*_ff_n40C_5v50.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu9t5v0__ff_n40C_5v50.lib \
rename=gf180mcu_fd_sc_mcu9t5v0__ff_n40C_5v50 \
-liberty cells/*/*_ss_125C_1v62.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu9t5v0__ss_125C_1v62.lib \
rename=gf180mcu_fd_sc_mcu9t5v0__ss_125C_1v62 \
-liberty cells/*/*_ss_n40C_1v62.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu9t5v0__ss_n40C_1v62.lib \
rename=gf180mcu_fd_sc_mcu9t5v0__ss_n40C_1v62 \
-liberty cells/*/*_ss_125C_3v00.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu9t5v0__ss_125C_3v00.lib \
rename=gf180mcu_fd_sc_mcu9t5v0__ss_125C_3v00 \
-liberty cells/*/*_ss_n40C_3v00.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu9t5v0__ss_n40C_3v00.lib \
rename=gf180mcu_fd_sc_mcu9t5v0__ss_n40C_3v00 \
-liberty cells/*/*_ss_125C_4v50.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu9t5v0__ss_125C_4v50.lib \
rename=gf180mcu_fd_sc_mcu9t5v0__ss_125C_4v50 \
-liberty cells/*/*_ss_n40C_4v50.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu9t5v0__ss_n40C_4v50.lib \
rename=gf180mcu_fd_sc_mcu9t5v0__ss_n40C_4v50 \
-liberty cells/*/*_tt_025C_1v80.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu9t5v0__tt_025C_1v80.lib \
rename=gf180mcu_fd_sc_mcu9t5v0__tt_025C_1v80 \
-liberty cells/*/*_tt_025C_3v30.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu9t5v0__tt_025C_3v30.lib \
rename=gf180mcu_fd_sc_mcu9t5v0__tt_025C_3v30 \
-liberty cells/*/*_tt_025C_5v00.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu9t5v0__tt_025C_5v00.lib \
rename=gf180mcu_fd_sc_mcu9t5v0__tt_025C_5v00 \
-gds cells/*/*.gds compile-only \
-lef cells/*/*.lef compile-only \
- -verilog cells/*/*.v compile-only \
+ filter=custom/scripts/fix_digital_lef.py \
+ -verilog models/*/*.v compile-only rename=primitives \
+ -verilog cells/*/*.v exclude=*.*.v,primitives.v \
+ compile-only filter=custom/scripts/inc_verilog.py \
-library digital gf180mcu_fd_sc_mcu9t5v0 2>&1 | \
tee -a ${GF180MCU$*}_make.log
-
+ # Create minimum/maximum technology LEF files
+ ./custom/scripts/make_minmax_techlef.py ${EF_FORMAT} -variant=${GF180MCU$*} \
+ -library=9t5v0 2>&1 | tee -a ${GF180MCU$*}_make.log || true
digital-7t5v0-%:
# Install 5V 7-track digital standard cells from vendor files
${STAGE} -source ${GF180MCU_SC_7T5V0_PATH} \
-target ${STAGING_PATH}/${GF180MCU$*} \
-techlef tech/gf180mcu_${$*_FULLSTACK}_7t_tech.lef \
- rename=gf180mcu_fd_sc_mcu7t5v0.tlef \
+ filter=custom/scripts/fix_techlef.py \
+ rename=gf180mcu_fd_sc_mcu7t5v0__nom.tlef \
-cdl cells/*/*.cdl compile-only noconvert \
-liberty cells/*/*_ff_125C_1v98.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu7t5v0__ff_125C_1v98.lib \
rename=gf180mcu_fd_sc_mcu7t5v0__ff_125C_1v98 \
-liberty cells/*/*_ff_n40C_1v98.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu7t5v0__ff_n40C_1v98.lib \
rename=gf180mcu_fd_sc_mcu7t5v0__ff_n40C_1v98 \
-liberty cells/*/*_ff_125C_3v60.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu7t5v0__ff_125C_3v60.lib \
rename=gf180mcu_fd_sc_mcu7t5v0__ff_125C_3v60 \
-liberty cells/*/*_ff_n40C_3v60.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu7t5v0__ff_n40C_3v60.lib \
rename=gf180mcu_fd_sc_mcu7t5v0__ff_n40C_3v60 \
-liberty cells/*/*_ff_125C_5v50.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu7t5v0__ff_125C_5v50.lib \
rename=gf180mcu_fd_sc_mcu7t5v0__ff_125C_5v50 \
-liberty cells/*/*_ff_n40C_5v50.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu7t5v0__ff_n40C_5v50.lib \
rename=gf180mcu_fd_sc_mcu7t5v0__ff_n40C_5v50 \
-liberty cells/*/*_ss_125C_1v62.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu7t5v0__ss_125C_1v62.lib \
rename=gf180mcu_fd_sc_mcu7t5v0__ss_125C_1v62 \
-liberty cells/*/*_ss_n40C_1v62.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu7t5v0__ss_n40C_1v62.lib \
rename=gf180mcu_fd_sc_mcu7t5v0__ss_n40C_1v62 \
-liberty cells/*/*_ss_125C_3v00.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu7t5v0__ss_125C_3v00.lib \
rename=gf180mcu_fd_sc_mcu7t5v0__ss_125C_3v00 \
-liberty cells/*/*_ss_n40C_3v00.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu7t5v0__ss_n40C_3v00.lib \
rename=gf180mcu_fd_sc_mcu7t5v0__ss_n40C_3v00 \
-liberty cells/*/*_ss_125C_4v50.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu7t5v0__ss_125C_4v50.lib \
rename=gf180mcu_fd_sc_mcu7t5v0__ss_125C_4v50 \
-liberty cells/*/*_ss_n40C_4v50.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu7t5v0__ss_n40C_4v50.lib \
rename=gf180mcu_fd_sc_mcu7t5v0__ss_n40C_4v50 \
-liberty cells/*/*_tt_025C_1v80.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu7t5v0__tt_025C_1v80.lib \
rename=gf180mcu_fd_sc_mcu7t5v0__tt_025C_1v80 \
-liberty cells/*/*_tt_025C_3v30.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu7t5v0__tt_025C_3v30.lib \
rename=gf180mcu_fd_sc_mcu7t5v0__tt_025C_3v30 \
-liberty cells/*/*_tt_025C_5v00.lib compile-only \
+ filter=custom/scripts/fix_related_bias_pins.py \
header=liberty/gf180mcu_fd_sc_mcu7t5v0__tt_025C_5v00.lib \
rename=gf180mcu_fd_sc_mcu7t5v0__tt_025C_5v00 \
-gds cells/*/*.gds compile-only \
-lef cells/*/*.lef compile-only \
- -verilog cells/*/*.v compile-only \
+ filter=custom/scripts/fix_digital_lef.py \
+ -verilog models/*/*.v compile-only rename=primitives \
+ -verilog cells/*/*.v exclude=*.*.v,primitives.v \
+ compile-only filter=custom/scripts/inc_verilog.py \
-library digital gf180mcu_fd_sc_mcu7t5v0 2>&1 | \
tee -a ${GF180MCU$*}_make.log
+ # Create minimum/maximum technology LEF files
+ ./custom/scripts/make_minmax_techlef.py ${EF_FORMAT} -variant=${GF180MCU$*} \
+ -library=7t5v0 2>&1 | tee -a ${GF180MCU$*}_make.log || true
digital-osu-%:
# Install OSU 3.3V digital standard cells from vendor files
diff --git a/gf180mcu/custom/scripts/fix_digital_lef.py b/gf180mcu/custom/scripts/fix_digital_lef.py
new file mode 100755
index 0000000..74d6275
--- /dev/null
+++ b/gf180mcu/custom/scripts/fix_digital_lef.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python3
+#
+# fix_digital_lef ---
+#
+# This script fixes the issue where the LEF files of the digital standard
+# cells do not have VNW and VPW pins. This script adds the pin entries
+# for these pins.
+#
+# This script is a filter to be run by setting the name of this script as
+# the value to "filter=" for the model install in the sky130 Makefile.
+
+import re
+import os
+import sys
+
+def filter(inname, outname):
+
+ # Read input
+ try:
+ with open(inname, 'r') as inFile:
+ ltext = inFile.read()
+ llines = ltext.splitlines()
+ except:
+ print('fix_digital_lef.py: failed to open ' + inname + ' for reading.', file=sys.stderr)
+ return 1
+
+ # Process input with regexp
+
+ fixedlines = []
+ modified = False
+
+ endrex = re.compile('[ \t]*END[ \t]+VSS')
+ macrorex = re.compile('^MACRO[ \t]+([^ \t\n]+)')
+ macroname = None
+
+ for line in llines:
+
+ # Check for MACRO line and record the macro name
+ # NOTE: The "filltie" cell connects the biases to the power supplies
+ # and must be excluded from this modification.
+
+ mmatch = macrorex.match(line)
+ if mmatch:
+ macroname = mmatch.group(1)
+
+ fixedlines.append(line)
+
+ # Check for end of VSS pin in file
+ ematch = endrex.match(line)
+ if ematch and 'filltie' not in inname:
+ fixedlines.append(' PIN VPW')
+ fixedlines.append(' DIRECTION INOUT ;')
+ fixedlines.append(' USE ground ;')
+ fixedlines.append(' PORT')
+ fixedlines.append(' LAYER Pwell ;')
+ fixedlines.append(' RECT 0.05 -0.25 0.55 0.25 ;')
+ fixedlines.append(' END')
+ fixedlines.append(' END VPW')
+ fixedlines.append(' PIN VNW')
+ fixedlines.append(' DIRECTION INOUT ;')
+ fixedlines.append(' USE power ;')
+ fixedlines.append(' PORT')
+ fixedlines.append(' LAYER Nwell ;')
+ fixedlines.append(' RECT 0.05 3.67 0.55 4.17 ;')
+ fixedlines.append(' END')
+ fixedlines.append(' END VNW')
+ modified = True
+ macroname = None
+
+ # Write output
+ if outname == None:
+ for i in fixedlines:
+ print(i)
+ else:
+ # If the output is a symbolic link but no modifications have been made,
+ # then leave it alone. If it was modified, then remove the symbolic
+ # link before writing.
+ if os.path.islink(outname):
+ if not modified:
+ return 0
+ else:
+ os.unlink(outname)
+ try:
+ with open(outname, 'w') as outFile:
+ for i in fixedlines:
+ print(i, file=outFile)
+ except:
+ print('fix_digital_lef.py: failed to open ' + outname + ' for writing.', file=sys.stderr)
+ return 1
+
+
+if __name__ == '__main__':
+
+ # This script expects to get one or two arguments. One argument is
+ # mandatory and is the input file. The other argument is optional and
+ # is the output file. The output file and input file may be the same
+ # name, in which case the original input is overwritten.
+
+ options = []
+ arguments = []
+ for item in sys.argv[1:]:
+ if item.find('-', 0) == 0:
+ options.append(item[1:])
+ else:
+ arguments.append(item)
+
+ if len(arguments) > 0:
+ infilename = arguments[0]
+
+ if len(arguments) > 1:
+ outfilename = arguments[1]
+ else:
+ outfilename = None
+
+ result = filter(infilename, outfilename)
+ sys.exit(result)
diff --git a/gf180mcu/custom/scripts/fix_related_bias_pins.py b/gf180mcu/custom/scripts/fix_related_bias_pins.py
new file mode 100755
index 0000000..5576eb1
--- /dev/null
+++ b/gf180mcu/custom/scripts/fix_related_bias_pins.py
@@ -0,0 +1,118 @@
+#!/usr/bin/env python3
+#
+# fix_related_bias_pins.py ---
+#
+# All liberty files are missing the bias pins VNW and VPW; these
+# needed to be added along with "related_bias_pin" statements for
+# the power supplies VDD and VSS.
+#
+# This script is a filter to be run by setting the name of this script as
+# the value to "filter=" for the lib install in the sky130 Makefile.
+
+import re
+import os
+import sys
+
+def filter(inname, outname):
+
+ # Read input
+ try:
+ with open(inname, 'r') as inFile:
+ stext = inFile.read()
+ slines = stext.splitlines()
+ except:
+ print('fix_related_bias_pins.py: failed to open ' + inname + ' for reading.', file=sys.stderr)
+ return 1
+
+ # Process input with regexp
+
+ fixedlines = []
+ modified = False
+ current_pin = ''
+
+ # Values for "pg_type" other than "pwell" or "nwell"
+ power_types = ['primary_power', 'primary_ground', 'backup_power',
+ 'internal_power', 'internal_ground']
+
+ pg_re = re.compile('\s*pg_pin\s*\(\s*"?([^\s]+)"?\s*\)\s*{')
+ well_re = re.compile('\s*pg_type\s*:\s*"?([^\s]+)"?\s*;')
+
+ for line in slines:
+ pmatch = pg_re.match(line)
+ if pmatch:
+ current_pin = pmatch.group(1)
+ if current_pin == 'VDD':
+ fixedlines.append(' pg_pin(VPW) {')
+ fixedlines.append(' voltage_name : VPW ;')
+ fixedlines.append(' pg_type : pwell ;')
+ fixedlines.append(' physical_connection : device_layer ;')
+ fixedlines.append(' }')
+ fixedlines.append('')
+ fixedlines.append(' pg_pin(VNW) {')
+ fixedlines.append(' voltage_name : VNW ;')
+ fixedlines.append(' pg_type : nwell ;')
+ fixedlines.append(' physical_connection : device_layer ;')
+ fixedlines.append(' }')
+ fixedlines.append('')
+
+ wmatch = well_re.match(line)
+ if wmatch:
+ well_str = wmatch.group(1)
+ if well_str == 'primary_power':
+ modified = True
+ fixedlines.append(' related_bias_pin : VNW ;')
+ current_pin = ''
+ elif well_str == 'primary_ground':
+ modified = True
+ fixedlines.append(' related_bias_pin : VPW ;')
+ current_pin = ''
+
+ fixedlines.append(line)
+
+ # Write output
+ if outname == None:
+ for i in fixedlines:
+ print(i)
+ else:
+ # If the output is a symbolic link but no modifications have been made,
+ # then leave it alone. If it was modified, then remove the symbolic
+ # link before writing.
+ if os.path.islink(outname):
+ if not modified:
+ return 0
+ else:
+ os.unlink(outname)
+ try:
+ with open(outname, 'w') as outFile:
+ for i in fixedlines:
+ print(i, file=outFile)
+ except:
+ print('fix_related_bias_pins.py: failed to open ' + outname + ' for writing.', file=sys.stderr)
+ return 1
+
+
+if __name__ == '__main__':
+
+ # This script expects to get one or two arguments. One argument is
+ # mandatory and is the input file. The other argument is optional and
+ # is the output file. The output file and input file may be the same
+ # name, in which case the original input is overwritten.
+
+ options = []
+ arguments = []
+ for item in sys.argv[1:]:
+ if item.find('-', 0) == 0:
+ options.append(item[1:])
+ else:
+ arguments.append(item)
+
+ if len(arguments) > 0:
+ infilename = arguments[0]
+
+ if len(arguments) > 1:
+ outfilename = arguments[1]
+ else:
+ outfilename = None
+
+ result = filter(infilename, outfilename)
+ sys.exit(result)
diff --git a/gf180mcu/custom/scripts/fix_techlef.py b/gf180mcu/custom/scripts/fix_techlef.py
new file mode 100755
index 0000000..3874d8e
--- /dev/null
+++ b/gf180mcu/custom/scripts/fix_techlef.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python3
+#
+# fix_techlef ---
+#
+# This script adds the missing masterslice entries for well and substrate.
+#
+# This script is a filter to be run by setting the name of this script as
+# the value to "filter=" for the model install in the gf180mcu Makefile.
+
+import re
+import os
+import sys
+
+def filter(inname, outname):
+
+ # Read input
+ try:
+ with open(inname, 'r') as inFile:
+ ltext = inFile.read()
+ llines = ltext.splitlines()
+ except:
+ print('fix_techlef.py: failed to open ' + inname + ' for reading.', file=sys.stderr)
+ return 1
+
+ # Process input with regexp
+
+ fixedlines = []
+ modified = False
+
+ layerrex = re.compile('[ \t]*LAYER ([^ \t\n]+)')
+
+ for line in llines:
+
+ lmatch = layerrex.match(line)
+ if lmatch:
+ if lmatch.group(1) == 'Poly2':
+ fixedlines.append('LAYER Pwell')
+ fixedlines.append(' TYPE MASTERSLICE ;')
+ fixedlines.append(' PROPERTY LEF58_TYPE "TYPE PWELL ;" ;')
+ fixedlines.append('END Pwell')
+ fixedlines.append('')
+ fixedlines.append('LAYER Nwell')
+ fixedlines.append(' TYPE MASTERSLICE ;')
+ fixedlines.append(' PROPERTY LEF58_TYPE "TYPE NWELL ;" ;')
+ fixedlines.append('END Nwell')
+ fixedlines.append('')
+
+ fixedlines.append(line)
+
+ # Write output
+ if outname == None:
+ for i in fixedlines:
+ print(i)
+ else:
+ # If the output is a symbolic link but no modifications have been made,
+ # then leave it alone. If it was modified, then remove the symbolic
+ # link before writing.
+ if os.path.islink(outname):
+ if not modified:
+ return 0
+ else:
+ os.unlink(outname)
+ try:
+ with open(outname, 'w') as outFile:
+ for i in fixedlines:
+ print(i, file=outFile)
+ except:
+ print('fix_techlef.py: failed to open ' + outname + ' for writing.', file=sys.stderr)
+ return 1
+
+
+if __name__ == '__main__':
+
+ # This script expects to get one or two arguments. One argument is
+ # mandatory and is the input file. The other argument is optional and
+ # is the output file. The output file and input file may be the same
+ # name, in which case the original input is overwritten.
+
+ options = []
+ arguments = []
+ for item in sys.argv[1:]:
+ if item.find('-', 0) == 0:
+ options.append(item[1:])
+ else:
+ arguments.append(item)
+
+ if len(arguments) > 0:
+ infilename = arguments[0]
+
+ if len(arguments) > 1:
+ outfilename = arguments[1]
+ else:
+ outfilename = None
+
+ result = filter(infilename, outfilename)
+ sys.exit(result)
diff --git a/gf180mcu/custom/scripts/inc_verilog.py b/gf180mcu/custom/scripts/inc_verilog.py
new file mode 100755
index 0000000..2472a02
--- /dev/null
+++ b/gf180mcu/custom/scripts/inc_verilog.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python3
+#
+# inc_verilog ---
+#
+# This script handles the verilog sources by removing `include statements
+# for files that are already being added to the single consolidated
+# verilog library file. Also, it adds the well and substrate pins to
+# all verilog modules having power pins.
+#
+# This script is a filter to be run by setting the name of this script as
+# the value to "filter=" for the model install in the sky130 Makefile.
+
+import re
+import os
+import sys
+
+def filter(inname, outname):
+
+ # Read input
+ try:
+ with open(inname, 'r') as inFile:
+ vtext = inFile.read()
+ vlines = vtext.splitlines()
+ except:
+ print('inc_verilog.py: failed to open ' + inname + ' for reading.', file=sys.stderr)
+ return 1
+
+ # Ignore all files with "functional" or "behavioral" in the name.
+ # Only process the plain ".v" and "_func.v" files. Other files just
+ # generate an empty file.
+
+ if 'functional' in inname or 'behavioral' in inname:
+ with open(outname, 'w') as outFile:
+ print('', file=outFile)
+ return 0
+
+ # Process input with regexp
+
+ fixedlines = []
+ modified = False
+ increx = re.compile('[ \t]*`include[ \t]+"?([^ \t\n"]+)"?')
+ endrex = re.compile('[ \t]*endmodule')
+ inpath = os.path.split(inname)[0]
+
+ for line in vlines:
+ # Remove includes
+ imatch = increx.match(line)
+ if imatch:
+ incfilename = imatch.group(1)
+ modified = True
+ else:
+ # Add in substrate and well pins
+ fline = line.replace('VDD, VSS', 'VDD, VSS, VNW, VPW')
+ fline = fline.replace('.VDD(VDD),.VSS(VSS)', '.VDD(VDD),.VSS(VSS),.VNW(VNW),.VPW(VPW)')
+ if fline != line:
+ modified = True
+ fixedlines.append(fline)
+
+ # Write output
+ if outname == None:
+ for i in fixedlines:
+ print(i)
+ else:
+ # If the output is a symbolic link but no modifications have been made,
+ # then leave it alone. If it was modified, then remove the symbolic
+ # link before writing.
+ if os.path.islink(outname):
+ if not modified:
+ return 0
+ else:
+ os.unlink(outname)
+ try:
+ with open(outname, 'w') as outFile:
+ for i in fixedlines:
+ print(i, file=outFile)
+ except:
+ print('inc_verilog.py: failed to open ' + outname + ' for writing.', file=sys.stderr)
+ return 1
+
+
+if __name__ == '__main__':
+
+ # This script expects to get one or two arguments. One argument is
+ # mandatory and is the input file. The other argument is optional and
+ # is the output file. The output file and input file may be the same
+ # name, in which case the original input is overwritten.
+
+ options = []
+ arguments = []
+ for item in sys.argv[1:]:
+ if item.find('-', 0) == 0:
+ options.append(item[1:])
+ else:
+ arguments.append(item)
+
+ if len(arguments) > 0:
+ infilename = arguments[0]
+
+ if len(arguments) > 1:
+ outfilename = arguments[1]
+ else:
+ outfilename = None
+
+ result = filter(infilename, outfilename)
+ sys.exit(result)
diff --git a/gf180mcu/custom/scripts/make_minmax_techlef.py b/gf180mcu/custom/scripts/make_minmax_techlef.py
new file mode 100755
index 0000000..e6446ab
--- /dev/null
+++ b/gf180mcu/custom/scripts/make_minmax_techlef.py
@@ -0,0 +1,167 @@
+#!/usr/bin/env python3
+#
+#--------------------------------------------------------------------
+# make_minmax_techlef.py --
+#
+# From a nominal technology LEF file, create the corresponding
+# technology files for the minimum and maximum process corners.
+# Currently this only considers the change in layer and Via
+# resistance, not parasitic capacitance. NOTE: None of the
+# technology LEF files has via resistance values, so these are
+# inserted after the ARRAYSPACING line.
+#
+# Usage:
+#
+# make_minmax_techlef.py -variant=gf180mcuA|gf180mcuB|gf180mcuC
+# -library=7t5v0|9t5v0
+# [-ef_format]
+#
+# Given the PDK variant and library name, finds the technology
+# LEF file in the staging area with the nominal corner values,
+# and creates two additional technology LEF files for the
+# minimum and maximum corners.
+#--------------------------------------------------------------------
+
+import os
+import re
+import sys
+
+options = []
+arguments = []
+for item in sys.argv[1:]:
+ if item.find('-', 0) == 0:
+ options.append(item[1:])
+ else:
+ arguments.append(item)
+
+variant = 'gf180mcuA'
+lib = '7t5v0'
+tlefpath = variant + '/libs.ref/gf180mcu_fd_sc_mcu' + lib + '/techlef'
+
+if len(options) > 0:
+ for option in options:
+ if option.startswith('variant'):
+ variant = option.split('=')[1]
+ elif option.startswith('library'):
+ lib = option.split('=')[1]
+ tlefpath = variant + '/libs.ref/gf180mcu_fd_sc_mcu' + lib + '/techlef'
+ for option in options:
+ if option == 'ef_format':
+ tlefpath = variant + '/libs.ref/techLEF/gf180mcu_fd_sc_mcu' + lib
+elif len(arguments) > 0:
+ tlefpath = arguments[0]
+
+tlefbase = 'gf180mcu_fd_sc_mcu' + lib + '__'
+tlefnom = tlefbase + 'nom.tlef'
+
+resrex1 = re.compile('^[ \t]*RESISTANCE RPERSQ')
+resrex2 = re.compile('^[ \t]*ARRAYSPACING')
+layerrex = re.compile('^[ \t]*LAYER ([^ \t\n]+)')
+
+# Resistance values, by layer
+
+rnom = {}
+rmin = {}
+rmax = {}
+
+# Nominal metal resistance values are for reference only;
+# they're not used in the code below
+rnom['Metal1'] = '0.090'
+rnom['Via1'] = '4.5'
+rnom['Metal2'] = '0.090'
+rnom['Via2'] = '4.5'
+if variant == 'gf180mcuA':
+ rnom['Metal3'] = '0.040'
+else:
+ rnom['Metal3'] = '0.090'
+rnom['Via3'] = '4.5'
+if variant == 'gf180mcuB':
+ rnom['Metal4'] = '0.060'
+else:
+ rnom['Metal4'] = '0.090'
+rnom['Via4'] = '4.5'
+rnom['Metal5'] = '0.060'
+
+rmax['Metal1'] = '0.104'
+rmax['Via1'] = '15.0'
+rmax['Metal2'] = '0.104'
+rmax['Via2'] = '15.0'
+if variant == 'gf180mcuA':
+ rmax['Metal3'] = '0.049'
+else:
+ rmax['Metal3'] = '0.104'
+rmax['Via3'] = '15.0'
+if variant == 'gf180mcuB':
+ rmax['Metal4'] = '0.070'
+else:
+ rmax['Metal4'] = '0.104'
+rmax['Via4'] = '15.0'
+rmax['Metal5'] = '0.070'
+
+rmin['Metal1'] = '0.076'
+rmin['Via1'] = '0.0'
+rmin['Metal2'] = '0.076'
+rmin['Via2'] = '0.0'
+if variant == 'gf180mcuA':
+ rmin['Metal3'] = '0.031'
+else:
+ rmin['Metal3'] = '0.076'
+rmin['Via3'] = '0.0'
+if variant == 'gf180mcuB':
+ rmin['Metal4'] = '0.050'
+else:
+ rmin['Metal4'] = '0.076'
+rmin['Via4'] = '0.0'
+rmin['Metal5'] = '0.050'
+
+#--------------------------------------------------------------------
+
+infile_name = tlefpath + '/' + tlefnom
+print('Creating minimum and maximum corner variants of ' + infile_name)
+
+if not os.path.exists(infile_name):
+ print('Error: Cannot find file ' + infile_name)
+ sys.exit(1)
+
+for corner in ['min', 'max', 'nom']:
+ tleffile = tlefbase + corner + '.tlef'
+ outfile_name = tlefpath + '/' + tleffile
+
+ infile = open(infile_name, 'r')
+ if infile_name == outfile_name:
+ outfile = open(outfile_name + 'x', 'w')
+ else:
+ outfile = open(outfile_name, 'w')
+ curlayer = None
+ value = None
+
+ for line in infile:
+ rmatch1 = resrex1.match(line)
+ rmatch2 = resrex2.match(line)
+ lmatch = layerrex.match(line)
+ if lmatch:
+ curlayer = lmatch.group(1)
+ if curlayer in rnom:
+ if corner == 'min':
+ value = rmin[curlayer]
+ elif corner == 'max':
+ value = rmax[curlayer]
+ else:
+ value = rnom[curlayer]
+ else:
+ value = None
+ outfile.write(line)
+ elif value and rmatch1:
+ outfile.write(' RESISTANCE RPERSQ ' + value + ' ;\n')
+ elif value and rmatch2:
+ outfile.write(line)
+ outfile.write('')
+ outfile.write(' RESISTANCE ' + value + ' ;\n')
+ else:
+ outfile.write(line)
+
+ infile.close()
+ outfile.close()
+
+ if infile_name == outfile_name:
+ os.rename(outfile_name + 'x', outfile_name)
diff --git a/gf180mcu/gf180mcu.json b/gf180mcu/gf180mcu.json
index ac86f48..5119a96 100644
--- a/gf180mcu/gf180mcu.json
+++ b/gf180mcu/gf180mcu.json
@@ -84,13 +84,13 @@
"magic": "MAGIC_COMMIT"
},
"reference": {
- "open_pdks": "a517779da3d3f3e57a24d9b4ef0a4559cd9abccc",
- "magic": "94daf986ab9aa94a9ae2ac3539fa5def9bd2a1ac",
+ "open_pdks": "366a4dab6ec0b670bf6b98587c0a3a8689003ae2",
+ "magic": "01f2ce37b827e79ae37c00e9a42691dade49927b",
"gf180mcu_pdk": "a897aa30369d3bcec87d9d50ce9b01f320f854ef",
- "gf180mcu_fd_pr": "e1b4e187900370103bf9b8a22bb8625f883368ef",
+ "gf180mcu_fd_pr": "132dc738056751efdea1cd437c26c45e49862b07",
"gf180mcu_fd_io": "bcaa40aaf6cf04d6e9cb143d0e5b0de9429e53ab",
- "gf180mcu_fd_sc_mcu7t5v0": "0b28b8d0f0a027a83b97a232e5ab667d7c37792b",
- "gf180mcu_fd_sc_mcu9t5v0": "16154d5495bd351e390343115ae6f8d1275e8003",
+ "gf180mcu_fd_sc_mcu7t5v0": "b98516ecf074c1e2dcd7f8641a4895af5fa8be5b",
+ "gf180mcu_fd_sc_mcu9t5v0": "60158ccbaac3eed081d94357065e94caabb3b553",
"gf180mcu_fd_ip_sram": "9c411928870ce15226228fa52ddb6ecc0ea4ffbe"
}
}
diff --git a/gf180mcu/magic/gf180mcu.tech b/gf180mcu/magic/gf180mcu.tech
index b2925ef..9638ec5 100644
--- a/gf180mcu/magic/gf180mcu.tech
+++ b/gf180mcu/magic/gf180mcu.tech
@@ -3323,6 +3323,9 @@
lef
+ masterslice pwell Pwell PWELL
+ masterslice nwell Nwell NWELL
+
routing m1 Metal1 METAL1 MET1 m1 met1 metal1
routing m2 Metal2 METAL2 MET2 m2 met2 metal2
#ifdef METALS3 || METALS4 || METALS5 || METALS6
diff --git a/gf180mcu/openlane/config.tcl b/gf180mcu/openlane/config.tcl
index f7fc7a4..0672f3d 100644
--- a/gf180mcu/openlane/config.tcl
+++ b/gf180mcu/openlane/config.tcl
@@ -22,9 +22,9 @@
set ::env(LIB_TYPICAL) $::env(LIB_SYNTH)
# Technology LEF
-set ::env(TECH_LEF) [glob "$::env(PDK_ROOT)/$::env(PDK)/libs.ref/$::env(STD_CELL_LIBRARY)/techlef/*.tlef"]
-set ::env(TECH_LEF_MIN) [glob "$::env(PDK_ROOT)/$::env(PDK)/libs.ref/$::env(STD_CELL_LIBRARY)/techlef/*.tlef"]
-set ::env(TECH_LEF_MAX) [glob "$::env(PDK_ROOT)/$::env(PDK)/libs.ref/$::env(STD_CELL_LIBRARY)/techlef/*.tlef"]
+set ::env(TECH_LEF) [glob "$::env(PDK_ROOT)/$::env(PDK)/libs.ref/$::env(STD_CELL_LIBRARY)/techlef/*__nom.tlef"]
+set ::env(TECH_LEF_MIN) [glob "$::env(PDK_ROOT)/$::env(PDK)/libs.ref/$::env(STD_CELL_LIBRARY)/techlef/*__min.tlef"]
+set ::env(TECH_LEF_MAX) [glob "$::env(PDK_ROOT)/$::env(PDK)/libs.ref/$::env(STD_CELL_LIBRARY)/techlef/*__max.tlef"]
set ::env(CELLS_LEF) [glob "$::env(PDK_ROOT)/$::env(PDK)/libs.ref/$::env(STD_CELL_LIBRARY)/lef/*.lef"]
set ::env(GDS_FILES) [glob "$::env(PDK_ROOT)/$::env(PDK)/libs.ref/$::env(STD_CELL_LIBRARY)/gds/*.gds"]
set ::env(STD_CELL_LIBRARY_CDL) "$::env(PDK_ROOT)/$::env(PDK)/libs.ref/$::env(STD_CELL_LIBRARY)/cdl/$::env(STD_CELL_LIBRARY).cdl"
@@ -80,10 +80,6 @@
## Extra PDN configs
-### OpenROAD/tlef Bug
-## via resistance are missing from the tlef causing irdrop to fai
-set ::env(RUN_IRDROP_REPORT) 0
-
set ::env(FP_PDN_RAIL_OFFSET) 0
set ::env(FP_PDN_VWIDTH) 1.6
set ::env(FP_PDN_HWIDTH) 1.6