| #!/usr/bin/env python3 | |
| # | |
| # This script traverses SPICE model files (e.g. from SKY130) and | |
| # extracts only the wanted model section, removes all comments and | |
| # empty lines, and resolves all includes so that a flat model file | |
| # results. This should speed up ngspice starts. | |
| # | |
| # (c) 2021 Harald Pretl, Johannes Kepler University Linz | |
| import sys,re,os | |
| def process_file(file_in_name, top_file): | |
| global is_warning | |
| try: | |
| f_in = open(file_in_name, 'r') | |
| except FileNotFoundError: | |
| print('Warning! File ' + file_in_name + ' not found.') | |
| is_warning = True | |
| return; | |
| # process_file can be called recursively, so that nested include | |
| # files can be traversed | |
| # write_active indicates whether we are in the right model section; in | |
| # include files, it is always true | |
| if top_file == True: | |
| write_active = False | |
| else: | |
| write_active = True | |
| for line in f_in: | |
| line_trim = (line.lower()).strip() | |
| if top_file == True: | |
| # we assume that .lib statements are only used in the main file | |
| if '.lib' in line_trim: | |
| if model_section in line_trim: | |
| write_active = True | |
| else: | |
| write_active = False | |
| if '.endl' == line_trim: | |
| write_active = False | |
| f_out.write(line) | |
| if len(line_trim) > 0: # write no empty lines | |
| if (line_trim[0] != '*'): # write no comments | |
| if (write_active == True): | |
| if '.include' in line_trim: | |
| # need to save and restore working dir so that nested | |
| # includes work | |
| current_wd = os.getcwd() | |
| newfile = re.findall(r'"(.*?)(?<!\\)"', line_trim) | |
| print('Reading ',newfile[0]) | |
| # enter new working dir | |
| new_wd = os.path.dirname(newfile[0]) | |
| if len(new_wd) > 0: | |
| try: | |
| os.chdir(new_wd) | |
| except OSError: | |
| print('Warning: Could not enter directory ' + new_wd) | |
| is_warning = True | |
| # traverse into new include file | |
| new_file_name = os.path.basename(newfile[0]) | |
| process_file(new_file_name, False) | |
| # restore old working dir after return | |
| os.chdir(current_wd) | |
| else: | |
| f_out.write(line) | |
| f_in.close() | |
| return; | |
| # main routine | |
| if len(sys.argv) == 3: | |
| model_section = sys.argv[2] | |
| else: | |
| model_section = 'tt' | |
| if (len(sys.argv) == 2) or (len(sys.argv) == 3): | |
| infile_name = sys.argv[1] | |
| outfile_name = infile_name + '.' + model_section + '.red' | |
| try: | |
| f_out = open(outfile_name, 'w') | |
| except OSError: | |
| print('Error: Cannot write file ' + outfile_name + '.') | |
| sys.exit(2) | |
| is_warning = False | |
| process_file(infile_name, True) | |
| f_out.close() | |
| print() | |
| print('Model file ' + outfile_name + ' written.') | |
| if is_warning == True: | |
| print('There have been warnings! Please check output log.') | |
| sys.exit(1) | |
| else: | |
| sys.exit(0) | |
| else: | |
| print() | |
| print('spice_model_red.py SPICE model file reducer') | |
| print(' (c) 2021 Harald Pretl, JKU') | |
| print() | |
| print('Usage: spice_model_red <inputfile> [corner] (default corner = tt)') | |
| print() | |
| print('Return codes for script automation:') | |
| print(' 0 = all OK') | |
| print(' 1 = warnings') | |
| print(' 2 = errors') | |
| print(' 3 = call of script w/o parameters (= showing this message)') | |
| print() | |
| sys.exit(3) |