-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrun_drc.py
More file actions
145 lines (121 loc) · 5.04 KB
/
Copy pathrun_drc.py
File metadata and controls
145 lines (121 loc) · 5.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/usr/bin/env python3
"""
run_drc.py
==========
Runs KLayout in batch mode against a GDS layout using the drc_rules.lydrc
rule deck, and optionally runs analyze_results.py afterwards.
Usage
-----
python run_drc.py --input layout.gds --output results.xml
python run_drc.py --input layout.gds --output results.xml --analyze
Cross-platform: works on Linux, macOS, and Windows as long as the `klayout`
executable is on PATH (or is supplied via --klayout).
"""
import argparse
import os
import shutil
import subprocess
import sys
import time
def parse_args():
parser = argparse.ArgumentParser(
description="Run KLayout DRC on a SKY130 layout and (optionally) build a report.")
parser.add_argument("--input", default="layout.gds",
help="Input GDS layout (default: layout.gds)")
parser.add_argument("--output", default="results.xml",
help="Output DRC report XML (default: results.xml)")
parser.add_argument("--rules", default="drc_rules.lydrc",
help="KLayout DRC rule deck (default: drc_rules.lydrc)")
parser.add_argument("--klayout", default="klayout",
help="Path to the klayout executable (default: klayout on PATH)")
parser.add_argument("--analyze", action="store_true",
help="After DRC, run analyze_results.py to build the HTML report")
parser.add_argument("--html", default="drc_report.html",
help="HTML report (only used with --analyze, default: drc_report.html)")
return parser.parse_args()
def find_klayout(user_path):
"""
Locate the klayout binary. Accepts an explicit path, or a name to look up
on PATH. Returns the usable path, or None if we cannot find it.
"""
# If the user passed an absolute/relative path that exists, use it.
if os.path.isfile(user_path):
return user_path
# Otherwise search PATH (handles klayout / klayout.exe / etc.).
found = shutil.which(user_path)
return found
def main():
args = parse_args()
# --- Sanity checks on inputs ------------------------------------------
if not os.path.isfile(args.input):
print(f"ERROR: Input GDS file not found: {args.input}", file=sys.stderr)
sys.exit(1)
if not os.path.isfile(args.rules):
print(f"ERROR: DRC rule file not found: {args.rules}", file=sys.stderr)
sys.exit(1)
klayout_bin = find_klayout(args.klayout)
if klayout_bin is None:
print(f"ERROR: Could not find KLayout executable '{args.klayout}'.",
file=sys.stderr)
print(" Install KLayout from https://www.klayout.de and either",
file=sys.stderr)
print(" add it to your PATH or pass --klayout /path/to/klayout.",
file=sys.stderr)
sys.exit(1)
# --- Build the KLayout command ----------------------------------------
# This must match the variable names ($input, $output) used in drc_rules.lydrc.
cmd = [
klayout_bin,
"-b",
"-r", args.rules,
"-rd", f"input={args.input}",
"-rd", f"output={args.output}",
]
print("Running command:")
print(" " + " ".join(cmd))
print()
# --- Execute KLayout --------------------------------------------------
start = time.time()
try:
result = subprocess.run(cmd, check=False)
except FileNotFoundError:
print(f"ERROR: Failed to launch KLayout ({klayout_bin}).", file=sys.stderr)
sys.exit(1)
except KeyboardInterrupt:
print("\nAborted by user.", file=sys.stderr)
sys.exit(130)
elapsed = time.time() - start
if result.returncode != 0:
print(f"ERROR: KLayout exited with code {result.returncode} "
f"after {elapsed:.2f} s.", file=sys.stderr)
print(" Re-run the command above manually to see the full log.",
file=sys.stderr)
sys.exit(result.returncode)
print()
print(f"DRC finished in {elapsed:.2f} s")
print(f"Report written to: {args.output}")
# --- Optional analysis step -------------------------------------------
if args.analyze:
# Resolve analyze_results.py relative to THIS script so it works no
# matter what directory the user launches run_drc.py from.
analyze_script = os.path.join(
os.path.dirname(os.path.abspath(__file__)), "analyze_results.py")
if not os.path.isfile(analyze_script):
print(f"ERROR: analyze_results.py not found next to run_drc.py "
f"({analyze_script}).", file=sys.stderr)
sys.exit(1)
analyze_cmd = [
sys.executable, analyze_script,
"--input", args.output,
"--html", args.html,
]
print()
print("Running analyzer:")
print(" " + " ".join(analyze_cmd))
ret = subprocess.run(analyze_cmd).returncode
if ret != 0:
print(f"ERROR: analyze_results.py exited with code {ret}",
file=sys.stderr)
sys.exit(ret)
if __name__ == "__main__":
main()