Wrote a script to directly translate the GF180MCU I/O library CDL to SPICE, rather than implementing the rather circular method of having magic generate SPICE from extracted layout.
diff --git a/VERSION b/VERSION index 12e7049..92be23d 100644 --- a/VERSION +++ b/VERSION
@@ -1 +1 @@ -1.0.373 +1.0.374
diff --git a/gf180mcu/Makefile.in b/gf180mcu/Makefile.in index 44135eb..9741d6f 100644 --- a/gf180mcu/Makefile.in +++ b/gf180mcu/Makefile.in
@@ -994,6 +994,8 @@ -liberty cells/*/*_tt_025C_5v00.lib compile-only \ header=liberty/gf180mcu_fd_io__tt_025C_5v00.lib \ rename=gf180mcu_fd_io__tt_025C_5v00 \ + -spice cells/*/*.cdl compile-only \ + filter=custom/scripts/convert_io_cdl.py \ -gds cells/*/*_${$*_STACK}.gds compile-only \ options=custom/scripts/gds_import_io.tcl \ -lef cells/*/*_${$*_STACK}.lef \
diff --git a/gf180mcu/custom/scripts/convert_io_cdl.py b/gf180mcu/custom/scripts/convert_io_cdl.py new file mode 100755 index 0000000..fcbc9b3 --- /dev/null +++ b/gf180mcu/custom/scripts/convert_io_cdl.py
@@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +# +# convert_io_cdl.py --- +# +# This script converts the GF CDL for the I/O pads to turn it into valid +# SPICE syntax, using regular expression parsing. + +# 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: + spitext = inFile.read() + # (Don't) unwrap continuation lines + # spilines = spitext.replace('\n+', ' ').splitlines() + spilines = spitext.splitlines() + except: + print('convert_io_cdl.py: failed to open ' + inname + ' for reading.', file=sys.stderr) + return 1 + + fixedlines = [] + modified = False + + resrex = re.compile('^R', re.IGNORECASE) + caprex = re.compile('^C', re.IGNORECASE) + + for line in spilines: + fixedline = line + isres = resrex.match(fixedline) + iscap = caprex.match(fixedline) + # check if resistor or capacitor for parameter name changes + # regexp substitutions: + # 1) Lines starting with R, C, or M --> change to X + fixedline = re.sub('^[RCM]', 'X', fixedline, flags=re.IGNORECASE) + # 2) Names in $[...] --> remove the delimiter + fixedline = re.sub(' \$\[', ' ', fixedline, flags=re.IGNORECASE) + fixedline = re.sub('\] ', ' ', fixedline, flags=re.IGNORECASE) + # 3) Remove $SUB= + fixedline = re.sub('\$SUB=', '', fixedline, flags=re.IGNORECASE) + # 4) Handle $W and $L for resistors + if isres: + fixedline = re.sub('\$W', 'r_width', fixedline, flags=re.IGNORECASE) + fixedline = re.sub('\$L', 'r_length', fixedline, flags=re.IGNORECASE) + if iscap: + fixedline = re.sub('w=', 'c_width=', fixedline, flags=re.IGNORECASE) + fixedline = re.sub('l=', 'c_length=', fixedline, flags=re.IGNORECASE) + # 5) Lowercase AREA and PJ + fixedline = re.sub('AREA', 'area', fixedline) + fixedline = re.sub('PJ', 'pj', fixedline) + + if line != fixedline: + modified = True + fixedlines.append(fixedline) + + # 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('convert_io_cdl.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/gf180mcu.json b/gf180mcu/gf180mcu.json index 60d052e..0b3d151 100644 --- a/gf180mcu/gf180mcu.json +++ b/gf180mcu/gf180mcu.json
@@ -84,8 +84,8 @@ "magic": "MAGIC_COMMIT" }, "reference": { - "open_pdks": "17859a0fb11c75f1be7cbfdd70c947ee4c5ad6f9", - "magic": "86b4ac3e4c7a2141f37bf4d8760cc69aa2c23bac", + "open_pdks": "7c3797bed470ebecf64c8f155fbb7dc3e08d6f48", + "magic": "13a1bfcc2e30f063b63fd34be501820b77677bf5", "gf180mcu_pdk": "a897aa30369d3bcec87d9d50ce9b01f320f854ef", "gf180mcu_fd_pr": "612c346a3600bec3387e2974c8cdc692215be107", "gf180mcu_fd_io": "2aeec51ea2824b6cc0b396acfc39f4535f40b23a",