blob: 031fa5ec3f4efb080c5697ae1335be8d7157237a [file] [log] [blame]
Tim Edwardsc46b9532021-04-12 14:31:29 -04001#!/bin/env python3
2#-------------------------------------------------------------------------
3# check_antenna.py --- A script to run magic in batch mode and run the
4# antenna violation checks on a layout.
5#
6# Usage:
7#
8# check_antenna.py <layout_name>
9#
10# Results:
11#
12# generates a file "<layout_name>_drc.txt" containing a human-readable
13# list of the DRC errors.
14#
15#-------------------------------------------------------------------------
16
17import subprocess
18import shutil
19import sys
20import os
21import re
22
23# Work in progress
24
25def run_antenna(layout_name, output_file):
26
27 # Remove any extension from layout_name
28 layout_name = os.path.splitext(layout_name)[0]
29
30 # Is the layout file in the current directory, or a full
31 # path, or is this a project directory?
32
33 if layout_name[0] == '/':
34 magpath = os.path.split(layout_name)[0]
35 layout_name = os.path.split(layout_name)[1]
36
37 else:
38 if not os.path.isfile(layout_name + '.mag'):
39 if not os.path.isfile('mag/' + layout_name + '.mag'):
40 print('Error: Cannot find file ' + layout_name + '.mag')
41 return
42 else:
emayecs4b2eaa92021-07-03 13:49:48 -040043 magpath = os.getcwd() + '/mag'
Tim Edwardsc46b9532021-04-12 14:31:29 -040044 else:
emayecs4b2eaa92021-07-03 13:49:48 -040045 magpath = os.getcwd()
Tim Edwardsc46b9532021-04-12 14:31:29 -040046
47 if output_file == '':
48 output_file = layout_name + '_ant.txt'
49
50 # Check for presence of a .magicrc file, or else check for environment
51 # variable PDKPATH, or PDK_PATH
52
53 myenv = os.environ.copy()
54 myenv['MAGTYPE'] = 'mag'
emayecs4b2eaa92021-07-03 13:49:48 -040055
56 if os.path.isfile('/usr/share/pdk/sky130A/libs.tech/magic/sky130A.magicrc'):
57 rcfile = '/usr/share/pdk/sky130A/libs.tech/magic/sky130A.magicrc'
58 elif os.path.isfile(magpath + '/.magicrc'):
Tim Edwardsc46b9532021-04-12 14:31:29 -040059 rcfile = magpath + '/.magicrc'
60 elif os.path.isfile(os.getcwd() + '/.magicrc'):
61 rcfile = os.getcwd() + '/.magicrc'
62 else:
63 if 'PDKPATH' in myenv:
64 rcpathroot = myenv['PDKPATH'] + '/libs.tech/magic'
65 rcfile = glob.glob(rcpathroot + '/*.magicrc')[0]
66 elif 'PDK_PATH' in myenv:
67 rcpathroot = myenv['PDKPATH'] + '/libs.tech/magic'
68 rcfile = glob.glob(rcpathroot + '/*.magicrc')[0]
69 else:
70 print('Error: Cannot get magic rcfile for the technology!')
71 return
emayecs4b2eaa92021-07-03 13:49:48 -040072
Tim Edwardsc46b9532021-04-12 14:31:29 -040073 # Generate the antenna check Tcl script
74
75 print('Evaluating antenna rule violations on layout ' + layout_name)
76
77 with open('run_magic_antenna.tcl', 'w') as ofile:
78 print('# run_magic_antenna.tcl ---', file=ofile)
79 print('# batch script for running DRC', file=ofile)
80 print('', file=ofile)
81 print('crashbackups stop', file=ofile)
82 print('drc off', file=ofile)
83 print('snap internal', file=ofile)
84 print('load ' + layout_name + ' -dereference', file=ofile)
85 print('select top cell', file=ofile)
86 print('expand', file=ofile)
87 print('extract do local', file=ofile)
88 print('extract no all', file=ofile)
89 print('extract all', file=ofile)
90 print('antennacheck', file=ofile)
91
92 # Run the DRC Tcl script
93
94 ofile = open(output_file, 'w')
95 print('Antenna violation checks on cell ' + layout_name, file=ofile)
96 print('--------------------------------------------', file=ofile)
97
emayecs4b2eaa92021-07-03 13:49:48 -040098 print('Running: magic -dnull -noconsole')
Tim Edwardsc46b9532021-04-12 14:31:29 -040099
100 mproc = subprocess.run(['magic', '-dnull', '-noconsole',
101 '-rcfile', rcfile, 'run_magic_antenna.tcl'],
102 env = myenv, cwd = magpath,
103 stdin = subprocess.DEVNULL, stdout = subprocess.PIPE,
104 stderr = subprocess.PIPE, universal_newlines = True)
105 if mproc.stdout:
106 for line in mproc.stdout.splitlines():
107 print(line)
108 print(line, file=ofile)
109 if mproc.stderr:
110 print('\nError message output from magic:')
111 print('\nError message output from magic:', file=ofile)
112 for line in mproc.stderr.splitlines():
113 print(line)
114 print(line, file=ofile)
115 if mproc.returncode != 0:
116 print('\nERROR: Magic exited with status ' + str(mproc.returncode))
117 print('\nERROR: Magic exited with status ' + str(mproc.returncode), file=ofile)
118
119 ofile.close()
120
121 print('Done!')
122
123# If called as main, run all DRC tests
124
125if __name__ == '__main__':
126
127 # Divide up command line into options and arguments
128 options = []
129 arguments = []
130 for item in sys.argv[1:]:
131 if item.find('-', 0) == 0:
132 options.append(item)
133 else:
134 arguments.append(item)
135
136 # Need one argument: path to layout
137 # If two arguments, then 2nd argument is the output file.
138
139 if len(arguments) > 0 and len(arguments) < 3:
140 layout_root = arguments[0]
141
142 if len(arguments) == 1:
143 out_filename = ""
144 elif len(arguments) > 1:
145 out_filename = arguments[1]
146
147 if len(arguments) > 0 and len(arguments) < 3:
148 run_antenna(layout_root, out_filename)
149 else:
150 print("Usage: check_antenna.py <layout_name> [<output_file>] [options]")
151 print("Options:")
152 print(" (none)")
153
154