Merge branch 'master' of 192.168.0.7:/home/tim/gitsrc/open_pdks/
diff --git a/VERSION b/VERSION index b668c3b..f8f3c08 100644 --- a/VERSION +++ b/VERSION
@@ -1 +1 @@ -1.0.16 +1.0.18
diff --git a/common/convert_spectre.py b/common/convert_spectre.py index 9127712..6c3655c 100755 --- a/common/convert_spectre.py +++ b/common/convert_spectre.py
@@ -30,14 +30,17 @@ def parse_param_line(line, inparam, insub): # Regexp patterns - parm1rex = re.compile('parameters' + '[ \t]*(.*)') - parm2rex = re.compile('\+[ \t]*(.*)') - parm3rex = re.compile('[ \t]*([^= \t]+)[ \t]*=[ \t]*([^ \t]+)[ \t]*(.*)') + parm1rex = re.compile('[ \t]*parameters[ \t]*(.*)') + parm2rex = re.compile('[ \t]*params:[ \t]*(.*)') + parm3rex = re.compile('\+[ \t]*(.*)') + parm4rex = re.compile('[ \t]*([^= \t]+)[ \t]*=[ \t]*([^ \t]+)[ \t]*(.*)') + parm5rex = re.compile('[ \t]*([^= \t]+)[ \t]*(.*)') fmtline = [] + iscdl = False if inparam: - pmatch = parm2rex.match(line) + pmatch = parm3rex.match(line) if pmatch: fmtline.append('+') rest = pmatch.group(1) @@ -52,10 +55,19 @@ fmtline.append('.param') rest = pmatch.group(1) else: - return '' + pmatch = parm2rex.match(line) + if pmatch: + if insub: + fmtline.append('+') + else: + return '' + rest = pmatch.group(1) + iscdl = True + else: + return '' while rest != '': - pmatch = parm3rex.match(rest) + pmatch = parm4rex.match(rest) if pmatch: fmtline.append(pmatch.group(1)) fmtline.append('=') @@ -72,10 +84,18 @@ # ngspice. So put them in an in-line comment if rest != '': - nmatch = parm3rex.match(rest) + nmatch = parm4rex.match(rest) if not nmatch: fmtline.append(' $ ' + rest.replace(' ', '').replace('\t', '')) rest = '' + elif iscdl: + # Match to a CDL subckt parameter that does not have an '=' and so + # assumes that the parameter is always passed. That is not legal SPICE, + # so supply a default value of 1. + pmatch = parm5rex.match(rest) + if pmatch: + fmtline.append(pmatch.group(1) + '=1') + rest = pmatch.group(2) else: break @@ -87,6 +107,7 @@ statrex = re.compile('[ \t]*statistics[ \t]*\{(.*)') simrex = re.compile('[ \t]*simulator[ \t]+([^= \t]+)[ \t]*=[ \t]*(.+)') insubrex = re.compile('[ \t]*inline[ \t]+subckt[ \t]+([^ \t]+)[ \t]*\(([^)]*)') + cdlsubrex = re.compile('\.subckt[ \t]+([^ \t]+)[ \t]*\(([^)]*)') endsubrex = re.compile('[ \t]*ends[ \t]+(.+)') modelrex = re.compile('[ \t]*model[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+\{(.*)') binrex = re.compile('[ \t]*([0-9]+):[ \t]+type[ \t]*=[ \t]*(.*)') @@ -99,6 +120,7 @@ # Devices (resistor, capacitor, subcircuit as resistor or capacitor) caprex = re.compile('c([^ \t]+)[ \t]*\(([^)]*)\)[ \t]*capacitor[ \t]*(.*)', re.IGNORECASE) resrex = re.compile('r([^ \t]+)[ \t]*\(([^)]*)\)[ \t]*resistor[ \t]*(.*)', re.IGNORECASE) + cdlrex = re.compile('[ \t]*([crdlmqx])([^ \t]+)[ \t]*\(([^)]*)\)[ \t]*([^ \t]+)[ \t]*(.*)', re.IGNORECASE) with open(in_file, 'r') as ifile: speclines = ifile.read().splitlines() @@ -107,7 +129,7 @@ inparam = False inmodel = False inpinlist = False - isspectre = True + isspectre = False spicelines = [] calllines = [] modellines = [] @@ -140,7 +162,7 @@ spicelines.append(line.strip()) continue - # Item 3. Flag continuation lines + # Item 4. Flag continuation lines if line.strip().startswith('+'): contline = True else: @@ -150,7 +172,17 @@ if inpinlist: inpinlist = False - # Item 4. Count through { ... } blocks that are not SPICE syntax + # Item 3. Handle blank lines like comment lines + if line.strip() == '': + if modellines != []: + modellines.append(line.strip()) + elif calllines != []: + calllines.append(line.strip()) + else: + spicelines.append(line.strip()) + continue + + # Item 5. Count through { ... } blocks that are not SPICE syntax if blockskip > 0: # Warning: Assumes one brace per line, may or may not be true if '{' in line: @@ -165,7 +197,7 @@ spicelines.append('* ' + line) continue - # Item 5. Handle continuation lines + # Item 6. Handle continuation lines if contline: if inparam: # Continue handling parameters @@ -179,7 +211,7 @@ spicelines.append(fmtline) continue - # Item 6. Regexp matching + # Item 7. Regexp matching # Catch "simulator lang=" smatch = simrex.match(line) @@ -213,7 +245,6 @@ else: mmatch = stdmodelrex.match(line) if mmatch: - modellines = [] modname = mmatch.group(1) modtype = mmatch.group(2) @@ -233,23 +264,30 @@ if isspectre: imatch = insubrex.match(line) else: - imatch = stdsubrex.match(line) + # Check for CDL format .subckt lines first + imatch = cdlsubrex.match(line) + if not imatch: + imatch = stdsubrex.match(line) if imatch: + # If a model block is pending, then dump it + if modellines != []: + for line in modellines: + spicelines.append(line) + modellines = [] + inmodel = False + insub = True subname = imatch.group(1) - calllines = [] if isspectre: devrex = re.compile(subname + '[ \t]*\(([^)]*)\)[ \t]*([^ \t]+)[ \t]*(.*)', re.IGNORECASE) - # If there is no close-parenthesis then we should expect it on - # a continuation line - inpinlist = True if ')' not in line else False - # Remove parentheses groups from subcircuit arguments - spicelines.append('.subckt ' + ' ' + subname + ' ' + imatch.group(2)) else: devrex = re.compile(subname + '[ \t]*([^ \t]+)[ \t]*([^ \t]+)[ \t]*(.*)', re.IGNORECASE) - inpinlist = True - spicelines.append(line) + # If there is no close-parenthesis then we should expect it on + # a continuation line + inpinlist = True if ')' not in line else False + # Remove parentheses groups from subcircuit arguments + spicelines.append('.subckt ' + ' ' + subname + ' ' + imatch.group(2)) continue else: @@ -300,6 +338,7 @@ for line in calllines[1:]: spicelines.append(line) + calllines = [] spicelines.append('.ends ' + subname) @@ -307,6 +346,7 @@ spicelines.append('') for line in modellines: spicelines.append(line) + modellines = [] insub = False inmodel = False @@ -342,6 +382,18 @@ spicelines.append('r' + dmatch.group(1) + ' ' + dmatch.group(2) + ' ' + dmatch.group(3)) continue + if not isspectre: + cmatch = cdlrex.match(line) + if cmatch: + fmtline = parse_param_line(cmatch.group(5), True, insub) + if fmtline != '': + inparam = True + spicelines.append(cmatch.group(1) + cmatch.group(2) + ' ' + cmatch.group(3) + ' ' + cmatch.group(4) + ' ' + fmtline) + continue + else: + spicelines.append(cmatch.group(1) + cmatch.group(2) + ' ' + cmatch.group(3) + ' ' + cmatch.group(4) + ' ' + cmatch.group(5)) + continue + # Check for a line that begins with the subcircuit name dmatch = devrex.match(line) @@ -447,6 +499,10 @@ if fileext == '.v' or fileext == '.va': continue + # .scs files are purely spectre and meaningless to SPICE, so ignore them. + if fileext == '.scs': + continue + froot = os.path.split(filename)[1] convert_file(filename, spicepath + '/' + froot)
diff --git a/common/create_lef_library.py b/common/create_lef_library.py index 2d56b41..4b8ecf3 100755 --- a/common/create_lef_library.py +++ b/common/create_lef_library.py
@@ -75,7 +75,7 @@ else: headerseen = True ltok = lline.split() - if ltok[0] == 'END' and ltok[1] == 'LIBRARY': + if len(ltok) > 1 and ltok[0] == 'END' and ltok[1] == 'LIBRARY': # Remove "END LIBRARY" line from individual files pass else: @@ -83,6 +83,10 @@ headerdone = True print('#--------EOF---------\n', file=ofile) + # Add "END LIBRARY" to the end of the library file + print('', file=ofile) + print('END LIBRARY', file=ofile) + if do_compile_only == True: print('Compile-only: Removing individual LEF files') for lfile in llist:
diff --git a/common/split_gds.py b/common/split_gds.py index a673c2f..5336d8e 100755 --- a/common/split_gds.py +++ b/common/split_gds.py
@@ -1,4 +1,7 @@ #!/bin/env python3 +# +# split_gds.py -- +# # Script to read a GDS library and write into individual GDS files, one per cell import os
diff --git a/common/split_spice.py b/common/split_spice.py new file mode 100755 index 0000000..d8c5539 --- /dev/null +++ b/common/split_spice.py
@@ -0,0 +1,229 @@ +#!/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: + + if subname == 'xrdn': + print('handling line in xrdn, file ' + in_file + ': "' + line + '"') + + # 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 subname == 'xrdn': + print('blank line in xrdn subcircuit') + 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 = [] + + 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)
diff --git a/sky130/Makefile b/sky130/Makefile index 186ff6b..d8eb452 100644 --- a/sky130/Makefile +++ b/sky130/Makefile
@@ -72,9 +72,8 @@ # from source, where they don't. # LINK_TARGETS = source -# LINK_TARGETS = none +LINK_TARGETS = none # LINK_TARGETS = sky130A -LINK_TARGETS = source # Paths: @@ -118,8 +117,8 @@ # Module definitions for each process node # (Note that MOS is default and therefore not used anywhere) -# SKY130A_DEFS += -DMETAL5 -DMIM -DREDISTRIBUTION -SKY130A_DEFS += -DMETAL5 -DMIM +SKY130A_DEFS += -DMETAL5 -DMIM -DREDISTRIBUTION +# SKY130A_DEFS += -DMETAL5 -DMIM # Add staging path SKY130A_DEFS += -DSTAGING_PATH=${STAGING_PATH} @@ -173,7 +172,7 @@ INSTALL = ../common/staging_install.py ${EF_FORMAT} # The script(s) below are used for custom changes to the vendor PDK files -ADDPROP = ../common/insert_property.py ${EF_FORMAT} +ADDPROP = ../common/insert_property.py ${EF_FORMAT} # List the EDA tools to install local setup files for TOOLS = magic qflow netgen klayout openlane @@ -330,12 +329,12 @@ -cdl %l/v%v/cells/*/*.cdl ignore=topography \ -spice %l/v%v/cells/*/*.spice \ -library general sky130_fd_io |& tee -a ${SKY130A}_install.log - # Install all SkyWater digital standard cells. + # Install all SkyWater digital standard cells. ${STAGE} -source ${SKYWATER_PATH} -target ${STAGING_PATH}/${SKY130A} \ -techlef %l/latest/tech/*.tlef \ -spice %l/latest/cells/*/*.spice compile-only \ -cdl %l/latest/cells/*/*.cdl ignore=topography compile-only \ - -lef %l/latest/cells/*/*.lef exclude=*.*.v compile-only \ + -lef %l/latest/cells/*/*.lef exclude=*.*.lef compile-only \ -doc %l/latest/cells/*/*.pdf \ -lib %l/latest/timing/*.lib \ -gds %l/latest/cells/*/*.gds compile-only \ @@ -348,30 +347,30 @@ -library digital sky130_fd_sc_ms \ -library digital sky130_fd_sc_lp |& tee -a ${SKY130A}_install.log # Install OSU digital standard cells. - ${STAGE} -source ${OSU_PATH} -target ${STAGING_PATH}/${SKY130A} \ - -techlef char/techfiles/scs8.lef rename sky130_osu_sc.tlef \ - -spice lib/spice/*.spice compile-only \ - -lef outputs/s8_osu130.lef rename sky130_osu_sc.lef \ - -lib outputs/*.lib \ - -gds lib/gds/*.gds compile-only \ - -verilog outputs/VERILOG/*.v \ - -library digital sky130_osu_sc + # ${STAGE} -source ${OSU_PATH} -target ${STAGING_PATH}/${SKY130A} \ + # -techlef char/techfiles/scs8.lef rename sky130_osu_sc.tlef \ + # -spice lib/spice/*.spice compile-only \ + # -lef outputs/s8_osu130.lef rename sky130_osu_sc.lef \ + # -lib outputs/*.lib \ + # -gds lib/gds/*.gds compile-only \ + # -verilog outputs/VERILOG/*.v \ + # -library digital sky130_osu_sc # Install additional model file (efabless) - ${STAGE} -source ./custom -target ${STAGING_PATH}/${SKY130A} \ - -ngspice models/*.lib rename ${SKY130A}.lib \ - |& tee -a ${SKY130A}_install.log - # Install custom additions to I/O pad library - ${STAGE} -source ./custom -target ${STAGING_PATH}/${SKY130A} \ - -gds %l/gds/*.gds \ - -verilog %l/verilog/*.v \ - -lef %l/lef/*.lef \ - -spice %l/spice/*.spice \ - -library general sky130_fd_io |& tee -a ${SKY130A}_install.log - # Add correct bounding boxes on Magic layouts - ${ADDPROP} ${STAGING_PATH}/${SKY130A} sky130_fd_io sky130_fd_io_top_gpio_ovtv2 \ - "FIXED_BBOX 0 407 28000 40000" - ${ADDPROP} ${STAGING_PATH}/${SKY130A} sky130_fd_io sky130_fd_io_top_xres4v2 \ - "FIXED_BBOX 0 407 15000 40000" + # ${STAGE} -source ./custom -target ${STAGING_PATH}/${SKY130A} \ + # -ngspice models/*.lib rename ${SKY130A}.lib \ + # |& tee -a ${SKY130A}_install.log + # # Install custom additions to I/O pad library + # ${STAGE} -source ./custom -target ${STAGING_PATH}/${SKY130A} \ + # -gds %l/gds/*.gds \ + # -verilog %l/verilog/*.v \ + # -lef %l/lef/*.lef \ + # -spice %l/spice/*.spice \ + # -library general sky130_fd_io |& tee -a ${SKY130A}_install.log + # # Add correct bounding boxes on Magic layouts + # ${ADDPROP} ${STAGING_PATH}/${SKY130A} sky130_fd_io sky130_fd_io_top_gpio_ovtv2 \ + # "FIXED_BBOX 0 407 28000 40000" + # ${ADDPROP} ${STAGING_PATH}/${SKY130A} sky130_fd_io sky130_fd_io_top_xres4v2 \ + # "FIXED_BBOX 0 407 15000 40000" install: install-local
diff --git a/sky130/README b/sky130/README index 0772cd4..4f650ca 100644 --- a/sky130/README +++ b/sky130/README
@@ -74,10 +74,13 @@ Edit the Makefile to set the following definitions for your host system: EF_STYLE = Select "1" for an efabless-style file structure, "0" - otherwise. There are only minor differences in - these two styles, namely for version tracking of - the Magic setup files, and the location of the - technology LEF file. + otherwise. There are some differences in + these two styles, the most important of which being + that the order of directories for the IP libraries + is <file_format>/<library_name> instead of + <library_name>/<file_format>. Other differences + include version tracking of the Magic setup files + and the location of the technology LEF file. LINK_TARGETS = "none" or "source". "none" copies files from the source directories to the target. "source" makes symbolic links
diff --git a/sky130/custom/sky130_fd_io/lef/power_pads_lib.lef b/sky130/custom/sky130_fd_io/lef/power_pads_lib.lef index b140e33..3869db2 100644 --- a/sky130/custom/sky130_fd_io/lef/power_pads_lib.lef +++ b/sky130/custom/sky130_fd_io/lef/power_pads_lib.lef
@@ -5388,4 +5388,4 @@ RECT 2.8700 0.1000 72.1300 13.0000 ; END END sky130_fd_io__vssd_lvc_pad -END LIBRARY ; +END LIBRARY
diff --git a/sky130/klayout/sky130.lyt b/sky130/klayout/sky130.lyt index 139f6cc..09b916f 100644 --- a/sky130/klayout/sky130.lyt +++ b/sky130/klayout/sky130.lyt
@@ -1,8 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> <technology> - <name>EFS8A</name> - <description>EFS8A 5-metals</description> - <layer-properties_file>EFS8A.lyp</layer-properties_file> + <name>TECHNAME</name> + <description>TECHNAME-metals</description> + <layer-properties_file>TECHNAME.lyp</layer-properties_file> <add-other-layers>true</add-other-layers> <layer-map> '66/15 : PY_SHORT ';
diff --git a/sky130/magic/sky130.magicrc b/sky130/magic/sky130.magicrc index feaf6b5..e0cf60a 100644 --- a/sky130/magic/sky130.magicrc +++ b/sky130/magic/sky130.magicrc
@@ -79,7 +79,7 @@ # add path to GDS cells #ifdef FULLTECH -if {[file isdir ${PDKPATH}/libs.ref/gds}]} { +if {[file isdir ${PDKPATH}/libs.ref/gds]} { path cell ${PDKPATH}/libs.ref/gds/sky130_fd_pr_base path cell ${PDKPATH}/libs.ref/gds/sky130_fd_pr_rf path cell ${PDKPATH}/libs.ref/gds/sky130_fd_pr_rf2
diff --git a/sky130/magic/sky130.tech b/sky130/magic/sky130.tech index d000ffd..90e4240 100644 --- a/sky130/magic/sky130.tech +++ b/sky130/magic/sky130.tech
@@ -3870,6 +3870,9 @@ defaultsideoverlap allm4 metal4 allm5 metal5 47 #endif (METAL5) +#ifdef REDISTRIBUTION +#endif (REDISTRIBUTION) + # Devices: Use document (...) variants (sim)
diff --git a/sky130/netgen/sky130_setup.tcl b/sky130/netgen/sky130_setup.tcl index af90784..bb5c574 100644 --- a/sky130/netgen/sky130_setup.tcl +++ b/sky130/netgen/sky130_setup.tcl
@@ -230,18 +230,18 @@ #--------------------------------------------------------------- foreach cell $cells1 { - if {[regexp "sky130_fc_sc_hd_decap_\[0-9\]+" $cell match]} { + if {[regexp {sky130_fd_sc_\w\w__decap_[[:digit:]]+} $cell match]} { ignore class "-circuit1 $cell" } - if {[regexp "sky130_fc_sc_hd_fill_\[0-9\]+" $cell match]} { + if {[regexp {sky130_fd_sc_\w\w__fill_[[:digit:]]+} $cell match]} { ignore class "-circuit1 $cell" } } foreach cell $cells2 { - if {[regexp "sky130_fc_sc_hd_decap_\[0-9\]+" $cell match]} { + if {[regexp {sky130_fd_sc_\w\w__decap_[[:digit:]]+} $cell match]} { ignore class "-circuit2 $cell" } - if {[regexp "sky130_fc_sc_hd_fill_\[0-9\]+" $cell match]} { + if {[regexp {sky130_fd_sc_\w\w__fill_[[:digit:]]+} $cell match]} { ignore class "-circuit2 $cell" } } @@ -257,6 +257,7 @@ #--------------------------------------------------------------- # e.g., hydra_spi_controller__hydra_spi_controller #--------------------------------------------------------------- + foreach cell $cells1 { if {[regexp "(.+)__(.+)" $cell match library cellname]} { if {([lsearch $cells2 $cell] < 0) && \