Skip to content

Commit

Permalink
Merge pull request #1 from chetanyagoyal/test
Browse files Browse the repository at this point in the history
Test
  • Loading branch information
chetanyagoyal authored Apr 21, 2024
2 parents 0f51b18 + 01e9c13 commit 6a6e1dd
Show file tree
Hide file tree
Showing 45 changed files with 5,495 additions and 73 deletions.
15 changes: 0 additions & 15 deletions .github/scripts/glayout_lvs_sample.py

This file was deleted.

106 changes: 80 additions & 26 deletions .github/scripts/run_glayout_drc.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import os, sys
import os, sys, re, gdstk, shutil, warnings
from pathlib import Path
import gdstk
import shutil
import subprocess as sp
from gdsfactory.component import Component
# import module for warnings
import warnings


def place_component(comp_name: str, func: "callable[[Component], any]", pdk: str, *args):
def place_component(comp_name: str, func: "callable[[Component], any]", pdk, *args):
"""This function places the component on the layout and runs DRC on it
in the most modular manner possible to accomodate for possible changes
later
Expand All @@ -30,7 +25,7 @@ def place_component(comp_name: str, func: "callable[[Component], any]", pdk: str
print(f"Error in placing {comp_name} : {e}\n exiting....")
sys.exit(1)

def eval_component(comp_to_run: Component, pdk: str, clean: int):
def eval_component(comp_to_run: Component, pdk_str: str, clean: int):
"""runs DRC on the generated component passed to it and
describes the errors if any. Also cleans the generated gds file
Expand All @@ -40,16 +35,54 @@ def eval_component(comp_to_run: Component, pdk: str, clean: int):
"""
gds_path = f'./{comp_to_run.name}.gds'
comp_to_run.write_gds(gds_path)
error_list = run_glayout_drc(comp_to_run.name, gds_path)
check_errors(error_list, comp_to_run.name, pdk)
error_list = run_glayout_drc(comp_to_run.name, gds_path, pdk_str)
check_errors(error_list, comp_to_run.name, pdk_str)

# clean
if clean:
os.remove(gds_path)
return error_list


def run_glayout_drc(design_name: str, gds_file: str) -> list:
def setup_pdk_dir(pdk_str: str):
if pdk_str == 'sky130':
sky130_path = Path(str(os.getenv('COMMON_VERIF_DIR')).replace("\\", "")) / "sky130A"
print(sky130_path.absolute())
pdk_root = '/usr/bin/miniconda3/share/pdk'

if not sky130_path.exists():
print(f"Sky130A directory not found at {sky130_path}")
os.mkdir(sky130_path)

source_file = '/usr/bin/miniconda3/share/pdk/sky130A/libs.tech/magic/sky130A.magicrc'
shutil.copy2(source_file, sky130_path)
if os.path.exists(source_file):
print(f'successfully copied sky130A.magicrc')

source_file = '/usr/bin/miniconda3/share/pdk/sky130A/libs.tech/netgen/sky130A_setup.tcl'
shutil.copy2(source_file, sky130_path)
if os.path.exists(source_file):
print(f'successfully copied sky130A_setup.tcl')

elif pdk_str == 'gf180':
gf180_path = Path(str(os.getenv('COMMON_VERIF_DIR')).replace("\\", "")) / "gf180mcuC"
pdk_root = '/usr/bin/miniconda3/share/pdk'

if not gf180_path.exists():
print(f"gf180mcuC directory not found at {gf180_path}")
os.mkdir(gf180_path)

source_file = '/usr/bin/miniconda3/share/pdk/gf180mcuC/libs.tech/magic/gf180mcuC.magicrc'
shutil.copy2(source_file, gf180_path)
if os.path.exists(source_file):
print(f'successfully copied gf180mcuC.magicrc')

source_file = '/usr/bin/miniconda3/share/pdk/gf180mcuC/libs.tech/netgen/gf180mcuC_setup.tcl'
shutil.copy2(source_file, gf180_path)
if os.path.exists(source_file):
print(f'successfully copied gf180mcuC_setup.tcl')


def run_glayout_drc(design_name: str, gds_file: str, pdk_str: str) -> list:
"""sets up the magicDRC script found in the drc-lvs-check directory and
runs it on the passed gds file. It then checks the output file for errors
Expand All @@ -63,19 +96,23 @@ def run_glayout_drc(design_name: str, gds_file: str) -> list:
"""
os.environ['DESIGN_NAME'] = design_name
os.rename(gds_file, '../../../res/results/6_final.gds')
sky130_path = Path(str(os.getenv('COMMON_VERIF_DIR')).replace("\\", "")) / "sky130A"
pdk_root = '/usr/bin/miniconda3/share/pdk'

if not sky130_path.exists():
print(f"Sky130A directory not found at {sky130_path}")
os.mkdir(sky130_path)
if pdk_str == 'sky130':
path_magicrc = '../../common/drc-lvs-check/sky130A/sky130A.magicrc'
path_tech = '../../common/drc-lvs-check/sky130A/sky130A_setup.tcl'
elif pdk_str == 'gf180':
path_magicrc = '../../common/drc-lvs-check/gf180mcuC/gf180mcuC.magicrc'
path_tech = '../../common/drc-lvs-check/gf180mcuC/gf180mcuC_setup.tcl'

# source_file = os.path.join(pdk_root, 'libs.tech/magic/sky130A.magicrc')
# shutil.copy2(source_file, sky130_path)
# source_file = os.path.join(pdk_root, 'libs.tech/netgen/sky130A_setup.tcl')
# shutil.copy2(source_file, sky130_path)
f1 = os.path.exists(path_magicrc)
f2 = os.path.exists(path_tech)
if not f1 or not f2:
setup_pdk_dir(pdk_str)

cmd = 'bash -c "../../common/drc-lvs-check/run_drc.sh"'
if pdk_str == 'sky130':
cmd = 'bash -c "../../common/drc-lvs-check/run_drc.sh"'
elif pdk_str == 'gf180':
cmd = 'bash -c "../../common/drc-lvs-check/run_drc_gf180.sh"'
subproc = sp.Popen(cmd, shell=True, stdout=sp.PIPE, stderr=sp.PIPE)
subproc.wait()

Expand All @@ -96,17 +133,34 @@ def run_glayout_drc(design_name: str, gds_file: str) -> list:
return [subproc_code, drc_report_code]


def check_errors(list_of_errors: list, comp: str, pdk: str):
def check_errors(list_of_errors: list, comp: str, pdk_str: str):
"""helper function to print the errors if any
Args:
list_of_errors (list): the list of errors returned by run_glayout_drc
comp (str): the name of the component
"""
if list_of_errors[0] == 1:
print(f"Error in running default {comp} for {pdk.name}")
print(f"Error in running default {comp} for {pdk_str}")
sys.exit(1)
elif list_of_errors[1] == 1:
warnings.warn(f"DRC returned non-zero errors for {comp} for {pdk.name}")
warnings.warn(f"DRC returned non-zero errors for {comp} for {pdk_str}")
else:
print(f"DRC passed successfully for {comp} for {pdk.name}")
print(f"DRC passed successfully for {comp} for {pdk_str}")

def run_drc_wrapper(pdk, components: list, pdk_str: str):
"""wrapper function to run DRC on a list of components
Args:
pdk (MappedPDK): sky130 or gf180, the process-design-kit being used
components (list): a list of components to run DRC on, contains the name of the
component, the function to generate it and the arguments to be passed to the function
pdk_str (str): the PDK to be used (sky130, etc.)
"""
error_codes = []
for component_info in components:
component_name, component_function, *args = component_info

inst = place_component(component_name, component_function, pdk, *args)
error_codes.append(eval_component(inst, pdk_str, 1))

205 changes: 205 additions & 0 deletions .github/scripts/run_glayout_lvs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
import os
import sys
import re
import subprocess as sp
from gdsfactory.component import Component

sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..', '..', '.github', 'scripts'))

from glayout.pdk.sky130_mapped import sky130_mapped_pdk as sky130
from glayout.pdk.gf180_mapped import gf180_mapped_pdk as gf180
from glayout.components.diff_pair import diff_pair
from glayout.primitives.fet import nmos, pmos
from glayout.components.opamp import opamp

from run_glayout_drc import place_component, setup_pdk_dir

COMMON_VERIF_DIR = '../../../common/drc-lvs-check'
os.environ["COMMON_VERIF_DIR"] = COMMON_VERIF_DIR

# ###########################################################################################################
# ###########################################################################################################
def get_gds_netlist(component_name, func, pdk, gds_path):
"""used to return the netlist and component object for the
desired component's placement
Args:
component_name (str): the global descriptor for the instantiated component
func (callable[[Component], any]): the function to be called to generate the component
pdk (MappedPDK): the pdk object for which the component is to be generated
gds_path (str): the path to the generated gds file
Returns:
Component: the instance of the component
str: the netlist string
"""
component = place_component(component_name, func, pdk)
component.write_gds(gds_path)
netlist = component.info['netlist'].generate_netlist()
return netlist, component


def compname_in_net(mynet: str) -> str:
"""used to edit netlist to change the component name to
the test component name for global definition
Args:
mynet (str): the netlist string input
Returns:
str: the modified netlist string
"""
pattern_diff = re.compile(r'\bDIFF_PAIR\b')
pattern_nmos = re.compile(r'\bNMOS\b')
pattern_pmos = re.compile(r'\bPMOS\b')
pattern_opamp = re.compile(r'\bopamp\b')
patterns = [pattern_diff, pattern_nmos, pattern_pmos, pattern_opamp]
replacements = ['diff_test', 'nmos_test', 'pmos_test', 'opamp_test']

for i, pattern in enumerate(patterns):
if pattern.search(mynet):
replacement = replacements[i]
mynet = re.sub(pattern, replacement, mynet)
return mynet

def edit_makefile(comp: Component, makefile_path: str):
"""used to edit the makefile to change the DESIGN_NAME variable
according to the component name
Args:
comp (Component): the component object for which the makefile is to be edited
makefile_path (str): the string path to the makefile
"""
pattern = re.compile(r'export DESIGN_NAME = (.*)_test')
my_var = comp.name

with open(makefile_path, 'r') as rf:
data = rf.read()

new_content = re.sub(pattern, f'export DESIGN_NAME = {my_var}', data)

with open(makefile_path, 'w') as wf:
wf.write(new_content)

def evaluate_report(report_fle: str) -> bool:
"""used to evaluate the lvs report file
Args:
report_fle (str): the path to the lvs report file (6_final_lvs.rpt)
Returns:
bool: The flag indicating if the lvs run was successful
"""
with open(report_fle, 'r') as file:
report_content = file.read()

string1 = 'Cell pin lists are equivalent.'
string2 = 'Netlists match with'

if string1 in report_content and string2 in report_content:
return True
return False
######################################################################################################################################################################################################################
######################################################################################################################################################################################################################
os.system('mkdir -p ./reports/sky130hd/glayout')

gds_path = './results/sky130hd/glayout/6_final.gds'
cdl_path = './results/sky130hd/glayout/6_final.cdl'
report_path = './reports/sky130hd/glayout/6_final_lvs.rpt'
makefile_script = './Makefile'

setup_pdk_dir('sky130')
## PMOS
mynet, comp = get_gds_netlist('pmos_test', pmos, sky130, gds_path)

net_file = cdl_path
mynet = compname_in_net(mynet)
with open(net_file, 'w') as wf:
wf.write(mynet)

edit_makefile(comp, makefile_script)

subproc_cmd = ['make', 'netgen_lvs']
sub = sp.Popen(subproc_cmd, stdout=sp.PIPE, stderr=sp.PIPE, universal_newlines=True)
stdout, stderr = sub.communicate()

print(stdout)

report_return_code = evaluate_report(report_path)

if report_return_code:
print(f'LVS run successful for pmos_test')
else:
print(f'LVS failed for pmos_test!')
sys.exit(1)

## NMOS
mynet, comp = get_gds_netlist('nmos_test', nmos, sky130, gds_path)

net_file = cdl_path
mynet = compname_in_net(mynet)
with open(net_file, 'w') as wf:
wf.write(mynet)

edit_makefile(comp, makefile_script)

subproc_cmd = ['make', 'netgen_lvs']
sub = sp.Popen(subproc_cmd, stdout=sp.PIPE, stderr=sp.PIPE, universal_newlines=True)
stdout, stderr = sub.communicate()

print(stdout)

report_return_code = evaluate_report(report_path)

if report_return_code:
print(f'LVS run successful for nmos_test')
else:
print(f'LVS failed for nmos_test!')
sys.exit(1)

## DIFF_PAIR
mynet, comp = get_gds_netlist('diff_test', diff_pair, sky130, gds_path)

net_file = cdl_path
mynet = compname_in_net(mynet)
with open(net_file, 'w') as wf:
wf.write(mynet)

edit_makefile(comp, makefile_script)

subproc_cmd = ['make', 'netgen_lvs']
sub = sp.Popen(subproc_cmd, stdout=sp.PIPE, stderr=sp.PIPE, universal_newlines=True)
stdout, stderr = sub.communicate()

print(stdout)

report_return_code = evaluate_report(report_path)

if report_return_code:
print(f'LVS run successful for diff_test')
else:
print(f'LVS failed for diff_test!')
sys.exit(1)

## OPAMP
##### not using currently because not LVS clean
# mynet, comp = get_gds_netlist('opamp_test', opamp, sky130, gds_path)

# net_file = cdl_path
# mynet = compname_in_net(mynet)
# with open(net_file, 'w') as wf:
# wf.write(mynet)

# edit_makefile(comp, makefile_script)

# subproc_cmd = ['make', 'netgen_lvs']
# sub = sp.Popen(subproc_cmd, stdout=sp.PIPE, stderr=sp.PIPE, universal_newlines=True)
# stdout, stderr = sub.communicate()

# print(stdout)

# if sub.returncode != 0:
# print(f'LVS failed for opamp_test with error:\n {stderr}')
# else:
# print(f'LVS run successful for opamp_test')
Loading

0 comments on commit 6a6e1dd

Please sign in to comment.