Tim Edwards | 9fdf5f0 | 2021-05-03 16:15:03 -0400 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | # |
| 3 | #-------------------------------------------------------------------- |
| 4 | # Parse the SPICE model files from sky130 and use the (commented out) |
| 5 | # statistics block to generate the correct monte carlo expressions |
| 6 | # in the device models for mismatch. |
| 7 | #-------------------------------------------------------------------- |
| 8 | |
| 9 | import os |
| 10 | import re |
| 11 | import sys |
| 12 | |
| 13 | mm_switch_param = 'MC_MM_SWITCH' |
| 14 | |
| 15 | walkpath = 'sky130A/libs.ref/sky130_fd_pr/spice' |
| 16 | |
| 17 | if len(sys.argv) > 1: |
| 18 | walkpath = sys.argv[1] |
| 19 | |
| 20 | mismatch_params = [] |
| 21 | |
| 22 | mmrex = re.compile('^\*[ \t]*mismatch[ \t]+\{') |
| 23 | endrex = re.compile('^\*[ \t]*\}') |
| 24 | |
| 25 | filelist = [] |
| 26 | |
| 27 | #-------------------------------------------------------------------- |
| 28 | # Step 1. Gather variables |
| 29 | #-------------------------------------------------------------------- |
| 30 | |
| 31 | for dirpath, dirnames, filenames in os.walk(walkpath): |
| 32 | for filename in filenames: |
| 33 | if os.path.splitext(filename)[1] == '.spice': |
| 34 | infile_name = os.path.join(dirpath, filename) |
| 35 | filelist.append(infile_name) |
| 36 | |
| 37 | infile = open(infile_name, 'r') |
| 38 | |
| 39 | state = 'before_mismatch' |
| 40 | line_number = 0 |
| 41 | replaced_something = False |
| 42 | |
| 43 | for line in infile: |
| 44 | line_number += 1 |
| 45 | |
| 46 | if state == 'before_mismatch': |
| 47 | mmatch = mmrex.match(line) |
| 48 | if mmatch: |
| 49 | state = 'in_mismatch' |
| 50 | elif state == 'in_mismatch': |
| 51 | ematch = endrex.match(line) |
| 52 | if ematch: |
| 53 | state = 'after_mismatch' |
| 54 | else: |
| 55 | tokens = line.split() |
| 56 | if 'vary' in tokens: |
| 57 | if ('dist=gauss' in tokens) or ('gauss' in tokens): |
| 58 | mismatch_param = tokens[2] |
| 59 | std_dev = float(tokens[-1].split('=')[-1]) |
| 60 | replacement = '{}*AGAUSS(0,{!s},1)'.format(mm_switch_param, std_dev) |
| 61 | mismatch_params.append((mismatch_param, replacement)) |
| 62 | |
| 63 | infile.close() |
| 64 | |
| 65 | print('') |
| 66 | print('Mismatch parameters found:') |
| 67 | for (mismatch_param, replacement) in mismatch_params: |
| 68 | print(mismatch_param + ' : ' + replacement) |
| 69 | print('') |
| 70 | |
| 71 | #-------------------------------------------------------------------- |
Tim Edwards | 1c74f85 | 2021-06-09 16:46:50 -0400 | [diff] [blame] | 72 | # Create regexp for the alternative PSPICE "dev/gauss" syntax used in |
| 73 | # a number of places in the models. |
| 74 | #-------------------------------------------------------------------- |
| 75 | |
| 76 | gaussrex = re.compile('\'[ \t]+dev\/gauss=\'', re.IGNORECASE) |
| 77 | |
| 78 | #-------------------------------------------------------------------- |
Tim Edwards | 9fdf5f0 | 2021-05-03 16:15:03 -0400 | [diff] [blame] | 79 | # Step 2. Make replacements |
| 80 | #-------------------------------------------------------------------- |
| 81 | |
| 82 | for infile_name in filelist: |
| 83 | |
| 84 | filepath = os.path.split(infile_name)[0] |
| 85 | outfile_name = os.path.join(filepath, 'temp') |
| 86 | |
| 87 | infile = open(infile_name, 'r') |
| 88 | outfile = open(outfile_name, 'w') |
| 89 | |
| 90 | state = 'before_mismatch' |
| 91 | line_number = 0 |
| 92 | replaced_something = False |
| 93 | |
| 94 | for line in infile: |
| 95 | line_number += 1 |
Tim Edwards | 1c74f85 | 2021-06-09 16:46:50 -0400 | [diff] [blame] | 96 | newline = line |
| 97 | |
| 98 | gmatch = gaussrex.search(newline) |
| 99 | if gmatch: |
| 100 | newline = gaussrex.sub('+' + mm_switch_param + '*AGAUSS(0,1.0,1)*', newline) |
| 101 | replaced_something = True |
| 102 | print(" Line {}: Found PSPICE dev/gauss and replaced.".format(line_number)) |
Tim Edwards | 9fdf5f0 | 2021-05-03 16:15:03 -0400 | [diff] [blame] | 103 | |
| 104 | if state == 'before_mismatch': |
Tim Edwards | 1c74f85 | 2021-06-09 16:46:50 -0400 | [diff] [blame] | 105 | outfile.write(newline) |
| 106 | mmatch = mmrex.match(newline) |
Tim Edwards | 9fdf5f0 | 2021-05-03 16:15:03 -0400 | [diff] [blame] | 107 | if mmatch: |
| 108 | state = 'in_mismatch' |
| 109 | elif state == 'in_mismatch': |
Tim Edwards | 1c74f85 | 2021-06-09 16:46:50 -0400 | [diff] [blame] | 110 | outfile.write(newline) |
| 111 | ematch = endrex.match(newline) |
Tim Edwards | 9fdf5f0 | 2021-05-03 16:15:03 -0400 | [diff] [blame] | 112 | if ematch: |
| 113 | state = 'after_mismatch' |
| 114 | elif state == 'after_mismatch': |
Tim Edwards | 9fdf5f0 | 2021-05-03 16:15:03 -0400 | [diff] [blame] | 115 | for (param, replacement) in mismatch_params: |
| 116 | if param in newline: |
| 117 | newline = newline.replace(param, replacement) |
| 118 | replaced_something = True |
| 119 | print(" Line {}: Found mismatch parameter '{}' and replaced with '{}'.".format(line_number, param, replacement)) |
| 120 | outfile.write(newline) |
| 121 | |
| 122 | infile.close() |
| 123 | outfile.close() |
| 124 | if replaced_something: |
Tim Edwards | 00bfca5 | 2021-05-04 10:48:46 -0400 | [diff] [blame] | 125 | # print("Something was replaced in '{}', backed up original file" |
| 126 | # + " and replaced with processed one.".format(infile_name)) |
| 127 | print("Something was replaced in '{}'.".format(infile_name)) |
| 128 | # os.rename(infile_name, infile_name + '.orig') |
Tim Edwards | 9fdf5f0 | 2021-05-03 16:15:03 -0400 | [diff] [blame] | 129 | os.rename(outfile_name, infile_name) |
| 130 | else: |
| 131 | print("Nothing was replaced in '{}'.".format(infile_name)) |
| 132 | os.remove(outfile_name) |
| 133 | |