def test_lvs(self):
    if ('waive_lvs' in self.config['project']):
        logging.info(('skipping LVS in this test due to %s' % self.config['project']['waive_lvs']))
        return
    module_name = self.config['caravel_test']['module_name']
    conf = self.config['gds']
    lvs_test_dir = 'lvstest'
    try_mkdir(lvs_test_dir, self.args.force_delete)
    gds_file = os.path.abspath(os.path.join(self.directory, conf['directory'], conf['gds_filename']))
    powered_verilog = os.path.abspath(os.path.join(self.directory, conf['directory'], conf['lvs_filename']))
    shutil.copyfile(gds_file, os.path.join(lvs_test_dir, conf['gds_filename']))
    shutil.copyfile(powered_verilog, os.path.join(lvs_test_dir, conf['lvs_filename']))
    gds_file = conf['gds_filename']
    powered_verilog = conf['lvs_filename']
    ext_file = (module_name + '.ext')
    log_file = (module_name + '.log')
    spice_file = (module_name + '.spice')
    netgen_log_file = (module_name + '.netgen_log')
    netgen_json = (module_name + '.json')
    extract_tcl = 'extract.tcl'
    pdk_path = self.system_config['lvs']['PDK_PATH']
    openlane_root = self.system_config['lvs']['OPENLANE']
    logging.info(('using PDK %s and OpenLANE %s' % (pdk_path, openlane_root)))
    test_env = os.environ.copy()
    test_env['MAGIC_EXT_USE_GDS'] = '1'
    test_env['PDKPATH'] = pdk_path
    netgen_setup_file = os.path.join(pdk_path, 'libs.tech', 'netgen', 'sky130A_setup.tcl')
    cwd = lvs_test_dir
    tcl_contents = ('\n        gds read %s;\n        load %s -dereference\n\n        extract do local;\n        extract no capacitance;\n        extract no coupling;\n        extract no resistance;\n        extract no adjust;\n        extract unique;\n        extract;\n        ext2spice lvs;\n        ext2spice %s;\n        feedback save %s;\n        exit;\n        ' % (gds_file, module_name, ext_file, log_file))
    with open(os.path.join(lvs_test_dir, extract_tcl), 'w') as tcl:
        tcl.write(tcl_contents)
    magic_rcfile = os.path.join(pdk_path, 'libs.tech', 'magic', 'sky130A.magicrc')
    cmd = ['magic', '-rcfile', magic_rcfile, '-noc', '-dnull', extract_tcl]
    logging.info(' '.join(cmd))
    subprocess.run(cmd, cwd=cwd, env=test_env, check=True)
    left_side = ('%s %s' % (spice_file, module_name))
    right_side = ('%s %s' % (powered_verilog, module_name))
    cmd = ('netgen -batch lvs "%s" "%s" %s %s -json' % (left_side, right_side, netgen_setup_file, netgen_log_file))
    logging.info(cmd)
    subprocess.run(cmd, env=test_env, cwd=cwd, check=True, shell=True)
    lvs_count_cmd = os.path.join(openlane_root, 'scripts', 'count_lvs.py')
    cmd = [lvs_count_cmd, '--file', netgen_json]
    logging.info(cmd)
    try:
        result = subprocess.run(cmd, cwd=cwd, capture_output=True)
    except subprocess.CalledProcessError as e:
        logging.error(e)
        exit(1)
    if ('Total errors = 0' in str(result.stdout)):
        logging.info('LVS passed')
    elif (('Total errors = 6' in str(result.stdout)) and ('unmatched pins = 6' in str(result.stdout))):
        logging.info('LVS passed (waived 6 unconnected power pins)')
    else:
        logging.error(result.stdout)
        exit(1)
def test_lvs(self):
    if ('waive_lvs' in self.config['project']):
        logging.info(('skipping LVS in this test due to %s' % self.config['project']['waive_lvs']))
        return
    module_name = self.config['caravel_test']['module_name']
    conf = self.config['gds']
    lvs_test_dir = 'lvstest'
    try_mkdir(lvs_test_dir, self.args.force_delete)
    gds_file = os.path.abspath(os.path.join(self.directory, conf['directory'], conf['gds_filename']))
    powered_verilog = os.path.abspath(os.path.join(self.directory, conf['directory'], conf['lvs_filename']))
    shutil.copyfile(gds_file, os.path.join(lvs_test_dir, conf['gds_filename']))
    shutil.copyfile(powered_verilog, os.path.join(lvs_test_dir, conf['lvs_filename']))
    gds_file = conf['gds_filename']
    powered_verilog = conf['lvs_filename']
    ext_file = (module_name + '.ext')
    log_file = (module_name + '.log')
    spice_file = (module_name + '.spice')
    netgen_log_file = (module_name + '.netgen_log')
    netgen_json = (module_name + '.json')
    extract_tcl = 'extract.tcl'
    pdk_path = self.system_config['lvs']['PDK_PATH']
    openlane_root = self.system_config['lvs']['OPENLANE']
    logging.info(('using PDK %s and OpenLANE %s' % (pdk_path, openlane_root)))
    test_env = os.environ.copy()
    test_env['MAGIC_EXT_USE_GDS'] = '1'
    test_env['PDKPATH'] = pdk_path
    netgen_setup_file = os.path.join(pdk_path, 'libs.tech', 'netgen', 'sky130A_setup.tcl')
    cwd = lvs_test_dir
    tcl_contents = ('\n        gds read %s;\n        load %s -dereference\n\n        extract do local;\n        extract no capacitance;\n        extract no coupling;\n        extract no resistance;\n        extract no adjust;\n        extract unique;\n        extract;\n        ext2spice lvs;\n        ext2spice %s;\n        feedback save %s;\n        exit;\n        ' % (gds_file, module_name, ext_file, log_file))
    with open(os.path.join(lvs_test_dir, extract_tcl), 'w') as tcl:
        tcl.write(tcl_contents)
    magic_rcfile = os.path.join(pdk_path, 'libs.tech', 'magic', 'sky130A.magicrc')
    cmd = ['magic', '-rcfile', magic_rcfile, '-noc', '-dnull', extract_tcl]
    logging.info(' '.join(cmd))
    subprocess.run(cmd, cwd=cwd, env=test_env, check=True)
    left_side = ('%s %s' % (spice_file, module_name))
    right_side = ('%s %s' % (powered_verilog, module_name))
    cmd = ('netgen -batch lvs "%s" "%s" %s %s -json' % (left_side, right_side, netgen_setup_file, netgen_log_file))
    logging.info(cmd)
    subprocess.run(cmd, env=test_env, cwd=cwd, check=True, shell=True)
    lvs_count_cmd = os.path.join(openlane_root, 'scripts', 'count_lvs.py')
    cmd = [lvs_count_cmd, '--file', netgen_json]
    logging.info(cmd)
    try:
        result = subprocess.run(cmd, cwd=cwd, capture_output=True)
    except subprocess.CalledProcessError as e:
        logging.error(e)
        exit(1)
    if ('Total errors = 0' in str(result.stdout)):
        logging.info('LVS passed')
    elif (('Total errors = 6' in str(result.stdout)) and ('unmatched pins = 6' in str(result.stdout))):
        logging.info('LVS passed (waived 6 unconnected power pins)')
    else:
        logging.error(result.stdout)
        exit(1)