Some fixes and enhancements to the two helper scripts change_gds_string.py and find_gds_prefix.py. The latter script is probably useless because running the Linux "strings" command is much faster. The former script can now be used with multiple string-replacement pairs in one pass, and has the option "-verbatim" to look for exact string matches only, rather than the usual partial string match that comes from using regsub or the string "replace" method in python.
diff --git a/Makefile.in b/Makefile.in index cb4286b..06bb94a 100644 --- a/Makefile.in +++ b/Makefile.in
@@ -87,6 +87,9 @@ mkdir -p @prefix@/pdk/bin/ ;\ cp common/cleanup_unref.py @prefix@/pdk/bin/ ;\ cp common/soc_floorplanner.py @prefix@/pdk/bin/ ;\ + cp common/change_gds_cell.py @prefix@/pdk/bin/ ;\ + cp common/find_gds_prefix.py @prefix@/pdk/bin/ ;\ + cp common/change_gds_string.py @prefix@/pdk/bin/ ;\ ${CPP} -DPREFIX=@prefix@ common/create_project.py \ @prefix@/pdk/bin/create_project.py ;\ echo "Common install: Done." ;\
diff --git a/VERSION b/VERSION index f6e5575..81e489d 100644 --- a/VERSION +++ b/VERSION
@@ -1 +1 @@ -1.0.173 +1.0.174
diff --git a/common/change_gds_string.py b/common/change_gds_string.py old mode 100755 new mode 100644 index accbc50..7ebfb28 --- a/common/change_gds_string.py +++ b/common/change_gds_string.py
@@ -6,13 +6,15 @@ # string around the search text, and adjusting the record bounds accordingly. import os +import re import sys def usage(): - print('change_gds_string.py <old_string> <new_string> <path_to_gds_in> [<path_to_gds_out>]') + print('change_gds_string.py <old_string> <new_string> [...] <path_to_gds_in> [<path_to_gds_out>]') if __name__ == '__main__': - debug = False + debug = 0 + verbatim = False if len(sys.argv) == 1: print("No options given to change_gds_string.py.") @@ -28,23 +30,38 @@ else: arguments.append(option) - if len(arguments) < 3 or len(arguments) > 4: + if len(arguments) < 3: print("Wrong number of arguments given to change_gds_string.py.") usage() sys.exit(0) - if '-debug' in optionlist: - debug = True + for option in optionlist: + opval = option.split('=') + if opval[0] == '-debug': + if len(opval) == 2: + debug = int(opval[1]) + else: + debug = 1 + elif opval[0] == '-verbatim': + verbatim = True - oldstring = arguments[0] - newstring = arguments[1] - source = arguments[2] - - # If only three arguments are provided, then overwrite the source file. - if len(arguments) == 4: - dest = arguments[3] + # If next-to-last argument is a valid path, then the last argument should + # be the path to GDS out. Otherwise, overwrite the source file. + + if os.path.isfile(arguments[-2]): + dest = arguments[-1] + source = arguments[-2] + oldstrings = arguments[0:-2:2] + newstrings = arguments[1:-2:2] else: - dest = arguments[2] + dest = arguments[-1] + source = arguments[-1] + oldstrings = arguments[0:-1:2] + newstrings = arguments[1:-1:2] + + if len(oldstrings) != len(newstrings): + print('Error: List of strings and replacements is not in pairs.') + sys.exit(1) sourcedir = os.path.split(source)[0] gdsinfile = os.path.split(source)[1] @@ -61,11 +78,15 @@ recordtypes = ['libname', 'strname', 'sname', 'string'] recordfilter = [2, 6, 18, 25] - bsearch = bytes(oldstring, 'ascii') - brep = bytes(newstring, 'ascii') + bsearchlist = list(bytes(item, 'ascii') for item in oldstrings) + breplist = list(bytes(item, 'ascii') for item in newstrings) + + if debug > 1: + print('Search list = ' + str(bsearchlist)) + print('Replace list = ' + str(breplist)) datalen = len(gdsdata) - if debug: + if debug > 0: print('Original data length = ' + str(datalen)) dataptr = 0 while dataptr < datalen: @@ -83,40 +104,53 @@ if rectype in recordfilter: # Datatype 6 is STRING if datatype == 6: - if debug: - print('Record type = ' + str(rectype) + ' data type = ' + str(datatype) + ' length = ' + str(reclen)) - bstring = gdsdata[dataptr + 4: dataptr + reclen] - repstring = bstring.replace(bsearch, brep) - if repstring != bstring: - before = gdsdata[0:dataptr] - after = gdsdata[dataptr + reclen:] - newlen = len(repstring) + 4 - # Record sizes must be even - if newlen % 2 != 0: - # Was original string padded with null byte? If so, - # remove the null byte and reduce newlen. Otherwise, - # add a null byte and increase newlen. + if debug > 1: + idx = recordfilter.index(rectype) + print(recordtypes[idx] + ' string = ' + str(bstring)) + + for bsearch,brep in zip(bsearchlist, breplist): + # Verbatim option: search string must match GDS string exactly + if verbatim: + blen = reclen - 4 if bstring[-1] == 0: - repstring = repstring[0:-1] - newlen -= 1 - else: - repstring += b'\x00' - newlen += 1 + blen = blen - 1 + if len(bsearch) != blen: + continue + repstring = re.sub(bsearch, brep, bstring) + if repstring != bstring: + before = gdsdata[0:dataptr] + after = gdsdata[dataptr + reclen:] + newlen = len(repstring) + 4 + # Record sizes must be even + if newlen % 2 != 0: + # Was original string padded with null byte? If so, + # remove the null byte and reduce newlen. Otherwise, + # add a null byte and increase newlen. + if bstring[-1] == 0: + repstring = repstring[0:-1] + newlen -= 1 + else: + repstring += b'\x00' + newlen += 1 - bnewlen = newlen.to_bytes(2, byteorder='big') - brectype = rectype.to_bytes(1, byteorder='big') - bdatatype = datatype.to_bytes(1, byteorder='big') + bnewlen = newlen.to_bytes(2, byteorder='big') + brectype = rectype.to_bytes(1, byteorder='big') + bdatatype = datatype.to_bytes(1, byteorder='big') - # Assemble the new record - newrecord = bnewlen + brectype + bdatatype + repstring - # Reassemble the GDS data around the new record - gdsdata = before + newrecord[0:newlen] + after - # Adjust the data end location - datalen += (newlen - reclen) + # Assemble the new record + newrecord = bnewlen + brectype + bdatatype + repstring + # Reassemble the GDS data around the new record + gdsdata = before + newrecord[0:newlen] + after + # Adjust the data end location + datalen += (newlen - reclen) - if debug: - print('Replaced ' + str(bstring) + ' with ' + str(repstring)) + if debug > 0: + print('Replaced ' + str(bstring) + ' with ' + str(repstring)) + else: + if debug > 1: + idx = recordfilter.index(rectype) + print(recordtypes[idx] + ' record = ' + str(datatype) + ' is not a string') # Advance the pointer past the data dataptr += newlen
diff --git a/common/find_gds_prefix.py b/common/find_gds_prefix.py index aeab8cc..e8dba84 100755 --- a/common/find_gds_prefix.py +++ b/common/find_gds_prefix.py
@@ -84,7 +84,7 @@ strname = bstring.decode('ascii') if strname[3:] == cellname: print('Cell ' + strname + ' found at position ' + str(saveptr)) - print('Prefix: ' + strname[0:2]) + print('Prefix: ' + strname[0:3]) found = True break elif strname == cellname: