| #!/usr/bin/env python3 |
| # |
| # Find which layout-extracted SPICE netlists in skywater-pdk-scratch are |
| # empty (that is, devices were not represented in magic). |
| |
| import os |
| import sys |
| import re |
| |
| cellroot = '../skywater-pdk-scratch/libraries/sky130_fd_pr/v0.20.1/cells' |
| |
| celllist = os.listdir(cellroot) |
| |
| for cellname in celllist: |
| cellpath = cellroot + '/' + cellname |
| |
| netlists = [] |
| other = [] |
| cellfiles = os.listdir(cellpath) |
| |
| stddevrex = re.compile('[xmqdcrl]([^ \t]+)[ \t]+(.*)', re.IGNORECASE) |
| subcktrex = re.compile('.subckt[ \t]+([^ \t]+)[ \t]+(.*)', re.IGNORECASE) |
| endsrex = re.compile('.ends', re.IGNORECASE) |
| |
| for file in cellfiles: |
| if os.path.splitext(file)[1] == '.spice': |
| if len(file.split('.')) == 2: |
| netlists.append(cellpath + '/' + file) |
| else: |
| other.append(cellpath + '/' + file) |
| |
| # Read all netlists that do not come from layout extraction and record |
| # all subcircuits that are defined in them. |
| defsubs = {} |
| for netlist in other: |
| with open(netlist, 'r') as ifile: |
| spicelines = ifile.read().splitlines() |
| insub = False |
| for line in spicelines: |
| if not insub: |
| smatch = subcktrex.match(line) |
| if smatch: |
| insub = True |
| subname = smatch.group(1) |
| defsubs[subname] = os.path.split(netlist)[1] |
| else: |
| ematch = endsrex.match(line) |
| if ematch: |
| insub = False |
| |
| nnetlists = len(netlists) |
| ess = 's' if nnetlists != 1 else '' |
| if nnetlists > 0: |
| print(str(nnetlists) + ' netlist' + ess + ' to check.') |
| |
| for netlist in netlists: |
| print('Checking ' + os.path.split(netlist)[1]) |
| with open(netlist, 'r') as ifile: |
| spicelines = ifile.read().splitlines() |
| insub = False |
| has_devices = False |
| pins_missing = False |
| shadowed = None |
| found = False |
| npins = 0 |
| pins = '' |
| for line in spicelines: |
| if not insub: |
| smatch = subcktrex.match(line) |
| if smatch: |
| found = True |
| insub = True |
| subname = smatch.group(1) |
| if subname in defsubs: |
| shadowed = defsubs[subname] |
| rest = smatch.group(2) |
| pins = rest.split(' ') |
| npins = len(pins) |
| if npins < 3: |
| pins_missing = True |
| else: |
| ematch = endsrex.match(line) |
| if ematch: |
| insub = False |
| else: |
| dmatch = stddevrex.match(line) |
| if dmatch: |
| has_devices = True |
| if not found: |
| print(' ERROR: Nothing in file') |
| testsubname = os.path.splitext(os.path.split(netlist)[1])[0] |
| if testsubname in defsubs: |
| print(' NOTE: Subcircuit exists in ' + defsubs[subname]) |
| if not has_devices: |
| print(' ERROR: No devices') |
| if pins_missing: |
| ess = 's' if npins != 1 else '' |
| print(' ERROR: Pins missing (' + str(npins) + ' pin' + ess + ' found)') |
| if shadowed: |
| print(' ERROR: Subcircuit shadows ' + shadowed) |