2022-10-09 12:55:27 -05:00
|
|
|
import argparse
|
|
|
|
import logging
|
|
|
|
import subprocess
|
|
|
|
from pathlib import Path
|
|
|
|
import os
|
|
|
|
|
|
|
|
|
|
|
|
def klayout_gds_drc_check(design_name, drc_script_path, gds_input_file_path, signoff_directory, logs_directory):
|
2022-10-15 16:31:38 -05:00
|
|
|
report_file_path = signoff_directory / f'{design_name}' / f'standalone_pvr/{design_name}_klayout_drc.xml'
|
2022-10-09 12:55:27 -05:00
|
|
|
run_drc_check_cmd = ['klayout', '-b', '-r', drc_script_path,
|
|
|
|
'-rd', f"input={gds_input_file_path}",
|
|
|
|
'-rd', f"report={report_file_path}",
|
|
|
|
'-rd', f"feol=1",
|
|
|
|
'-rd', f"beol=1",
|
|
|
|
'-rd', f"seal=1"]
|
|
|
|
|
|
|
|
log_file_path = logs_directory / f'{design_name}_drc_check.log'
|
|
|
|
with open(log_file_path, 'w') as klayout_drc_log:
|
|
|
|
subprocess.run(run_drc_check_cmd, stderr=klayout_drc_log, stdout=klayout_drc_log)
|
|
|
|
|
|
|
|
with open(report_file_path) as klayout_xml_report:
|
|
|
|
drc_content = klayout_xml_report.read()
|
|
|
|
drc_count = drc_content.count('<item>')
|
|
|
|
total_file_path = logs_directory / f'{design_name}_klayout_drc.total'
|
|
|
|
with open(total_file_path, 'w') as drc_total:
|
|
|
|
drc_total.write(f"{drc_count}")
|
|
|
|
if drc_count == 0:
|
|
|
|
logging.info("No DRC Violations found")
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
logging.error(f"Total # of DRC violations is {drc_count} Please check {report_file_path} For more details")
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
logging.basicConfig(level=logging.DEBUG, format=f"%(asctime)s | %(levelname)-7s | %(message)s", datefmt='%d-%b-%Y %H:%M:%S')
|
|
|
|
parser = argparse.ArgumentParser(description='Runs magic and klayout drc checks on a given GDS.')
|
|
|
|
parser.add_argument('--gds_input_file_path', '-g', required=True, help='GDS File to apply DRC checks on')
|
|
|
|
parser.add_argument('--log_directory', '-l', required=True, help='log Directory')
|
|
|
|
parser.add_argument('--signoff_directory', '-s', required=True, help='signoff Directory')
|
|
|
|
parser.add_argument('--design_name', '-d', required=True, help='Design Name')
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
gds_input_file_path = Path(args.gds_input_file_path)
|
|
|
|
log_directory = Path(args.log_directory)
|
|
|
|
signoff_directory = Path(args.signoff_directory)
|
|
|
|
design_name = args.design_name
|
|
|
|
|
|
|
|
klayout_sky130A_mr_drc_script_path = "tech-files/sky130A_mr.drc"
|
|
|
|
|
|
|
|
if gds_input_file_path.exists() and gds_input_file_path.suffix == ".gds":
|
|
|
|
if klayout_gds_drc_check(design_name, klayout_sky130A_mr_drc_script_path, gds_input_file_path, signoff_directory, log_directory):
|
|
|
|
logging.info("Klayout GDS DRC Clean")
|
|
|
|
else:
|
|
|
|
logging.info("Klayout GDS DRC Dirty")
|
|
|
|
else:
|
|
|
|
logging.error(f"{gds_input_file_path} is not valid")
|