| #!/bin/env python3 |
| #------------------------------------------------------------------------- |
| # check_antenna.py --- A script to run magic in batch mode and run the |
| # antenna violation checks on a layout. |
| # |
| # Usage: |
| # |
| # check_antenna.py <layout_name> |
| # |
| # Results: |
| # |
| # generates a file "<layout_name>_drc.txt" containing a human-readable |
| # list of the DRC errors. |
| # |
| #------------------------------------------------------------------------- |
| |
| import subprocess |
| import shutil |
| import sys |
| import os |
| import re |
| |
| # Work in progress |
| |
| def run_antenna(layout_name, output_file): |
| |
| # Remove any extension from layout_name |
| layout_name = os.path.splitext(layout_name)[0] |
| |
| # Is the layout file in the current directory, or a full |
| # path, or is this a project directory? |
| |
| if layout_name[0] == '/': |
| magpath = os.path.split(layout_name)[0] |
| layout_name = os.path.split(layout_name)[1] |
| |
| else: |
| if not os.path.isfile(layout_name + '.mag'): |
| if not os.path.isfile('mag/' + layout_name + '.mag'): |
| print('Error: Cannot find file ' + layout_name + '.mag') |
| return |
| else: |
| magpath = os.getcwd() + '/mag' |
| else: |
| magpath = os.getcwd() |
| |
| if output_file == '': |
| output_file = layout_name + '_ant.txt' |
| |
| # Check for presence of a .magicrc file, or else check for environment |
| # variable PDKPATH, or PDK_PATH |
| |
| myenv = os.environ.copy() |
| myenv['MAGTYPE'] = 'mag' |
| |
| if os.path.isfile('/usr/share/pdk/TECHNAME/libs.tech/magic/TECHNAME.magicrc'): |
| rcfile = '/usr/share/pdk/TECHNAME/libs.tech/magic/TECHNAME.magicrc' |
| elif os.path.isfile(magpath + '/.magicrc'): |
| rcfile = magpath + '/.magicrc' |
| elif os.path.isfile(os.getcwd() + '/.magicrc'): |
| rcfile = os.getcwd() + '/.magicrc' |
| else: |
| if 'PDKPATH' in myenv: |
| rcpathroot = myenv['PDKPATH'] + '/libs.tech/magic' |
| rcfile = glob.glob(rcpathroot + '/*.magicrc')[0] |
| elif 'PDK_PATH' in myenv: |
| rcpathroot = myenv['PDKPATH'] + '/libs.tech/magic' |
| rcfile = glob.glob(rcpathroot + '/*.magicrc')[0] |
| else: |
| print('Error: Cannot get magic rcfile for the technology!') |
| return |
| |
| # Generate the antenna check Tcl script |
| |
| print('Evaluating antenna rule violations on layout ' + layout_name) |
| |
| with open('run_magic_antenna.tcl', 'w') as ofile: |
| print('# run_magic_antenna.tcl ---', file=ofile) |
| print('# batch script for running DRC', file=ofile) |
| print('', file=ofile) |
| print('crashbackups stop', file=ofile) |
| print('drc off', file=ofile) |
| print('snap internal', file=ofile) |
| print('load ' + layout_name + ' -dereference', file=ofile) |
| print('select top cell', file=ofile) |
| print('expand', file=ofile) |
| print('extract do local', file=ofile) |
| print('extract no all', file=ofile) |
| print('extract all', file=ofile) |
| print('antennacheck', file=ofile) |
| |
| # Run the DRC Tcl script |
| |
| ofile = open(output_file, 'w') |
| print('Antenna violation checks on cell ' + layout_name, file=ofile) |
| print('--------------------------------------------', file=ofile) |
| |
| print('Running: magic -dnull -noconsole') |
| |
| mproc = subprocess.run(['magic', '-dnull', '-noconsole', |
| '-rcfile', rcfile, 'run_magic_antenna.tcl'], |
| env = myenv, cwd = magpath, |
| stdin = subprocess.DEVNULL, stdout = subprocess.PIPE, |
| stderr = subprocess.PIPE, universal_newlines = True) |
| if mproc.stdout: |
| for line in mproc.stdout.splitlines(): |
| print(line) |
| print(line, file=ofile) |
| if mproc.stderr: |
| print('\nError message output from magic:') |
| print('\nError message output from magic:', file=ofile) |
| for line in mproc.stderr.splitlines(): |
| print(line) |
| print(line, file=ofile) |
| if mproc.returncode != 0: |
| print('\nERROR: Magic exited with status ' + str(mproc.returncode)) |
| print('\nERROR: Magic exited with status ' + str(mproc.returncode), file=ofile) |
| |
| ofile.close() |
| |
| print('Done!') |
| |
| # If called as main, run all DRC tests |
| |
| if __name__ == '__main__': |
| |
| # Divide up command line into options and arguments |
| options = [] |
| arguments = [] |
| for item in sys.argv[1:]: |
| if item.find('-', 0) == 0: |
| options.append(item) |
| else: |
| arguments.append(item) |
| |
| # Need one argument: path to layout |
| # If two arguments, then 2nd argument is the output file. |
| |
| if len(arguments) > 0 and len(arguments) < 3: |
| layout_root = arguments[0] |
| |
| if len(arguments) == 1: |
| out_filename = "" |
| elif len(arguments) > 1: |
| out_filename = arguments[1] |
| |
| if len(arguments) > 0 and len(arguments) < 3: |
| run_antenna(layout_root, out_filename) |
| else: |
| print("Usage: check_antenna.py <layout_name> [<output_file>] [options]") |
| print("Options:") |
| print(" (none)") |
| |
| |