2022-10-09 05:23:01 -05:00
#!/usr/bin/env python3
# This script runs PrimeTime STA
# Rev 1
# 6/10/2022
import argparse
import os
def run_sta_all (
2022-10-17 11:13:12 -05:00
design : str ,
output_dir : str ,
log_dir : str
2022-10-09 05:23:01 -05:00
) :
2022-10-17 11:13:12 -05:00
proc_corners = [ " t " , " s " , " f " ]
rc_corners = [ " nom " , " max " , " min " ]
for proc in proc_corners :
for rc in rc_corners :
run_sta ( design , proc , rc , output_dir , log_dir )
2022-10-09 05:23:01 -05:00
def run_sta (
2022-10-17 11:13:12 -05:00
design : str ,
proc_corner : str ,
rc_corner : str ,
output_dir : str ,
log_dir : str
2022-10-09 05:23:01 -05:00
) :
2022-10-17 11:13:12 -05:00
print ( f " PrimeTime STA run for design: { design } at process corner { proc_corner } and RC corner { rc_corner } " )
# Output directory structure
sub_dirs = [ ' reports ' , ' sdf ' , ' lib ' ]
for item in sub_dirs :
path = os . path . join ( output_dir , item )
try :
os . makedirs ( os . path . join ( path , rc_corner ) )
except FileExistsError :
# directory already exists
pass
# Enviornment Variables
check_env_vars ( )
os . environ [ " PDK_ROOT " ] = os . getenv ( ' PDK_ROOT ' )
os . environ [ " PDK " ] = os . getenv ( ' PDK ' )
os . environ [ " PT_LIB_ROOT " ] = os . getenv ( ' PT_LIB_ROOT ' )
os . environ [ " CARAVEL_ROOT " ] = os . getenv ( ' CARAVEL_ROOT ' )
os . environ [ " UPRJ_ROOT " ] = os . getenv ( ' UPRJ_ROOT ' )
os . environ [ " MCW_ROOT " ] = os . getenv ( ' MCW_ROOT ' )
os . environ [ " OUT_DIR " ] = output_dir
SCRIPT_DIR = os . path . dirname ( os . path . abspath ( __file__ ) )
os . environ [ " DESIGN " ] = design
os . environ [ " PROC_CORNER " ] = proc_corner
os . environ [ " RC_CORNER " ] = rc_corner
# PrimeTime command
PT_tcl = f " { SCRIPT_DIR } /pt_sta.tcl "
2022-11-06 08:19:15 -06:00
pt_command = f " source /tools/bashrc_snps; pt_shell -f { PT_tcl } -output_log_file { log_dir } / { design } - { rc_corner } - { proc_corner } -sta.log "
2022-10-17 11:13:12 -05:00
os . system ( pt_command )
2022-11-06 08:19:15 -06:00
# Check if there are any violations
2022-10-17 11:13:12 -05:00
sta_pass = search_viol ( f " { output_dir } /reports/ { rc_corner } / { design } . { proc_corner } { proc_corner } -global.rpt " )
2022-11-06 08:19:15 -06:00
log = open ( f " { log_dir } / { design } - { rc_corner } - { proc_corner } -sta.log " , " a " )
2022-10-17 11:13:12 -05:00
if sta_pass == " pass " :
print ( f " STA run Passed! " )
log . write ( f " STA run Passed! " )
2022-10-09 09:40:32 -05:00
else :
2022-10-17 11:13:12 -05:00
if sta_pass == " max_tran_cap " :
print ( f " STA run Passed! " )
log . write ( f " STA run Passed! \n " )
print ( f " There are max_transition and max_capacitance violations. check report: { output_dir } /reports/ { rc_corner } / { design } . { proc_corner } { proc_corner } -all_viol.rpt " )
log . write ( f " There are max_transition and max_capacitance violations. check report: { output_dir } /reports/ { rc_corner } / { design } . { proc_corner } { proc_corner } -all_viol.rpt " )
elif sta_pass == " max_tran " :
print ( f " STA run Passed! " )
log . write ( f " STA run Passed! \n " )
print ( f " There are max_transition violations. check report: { output_dir } /reports/ { rc_corner } / { design } . { proc_corner } { proc_corner } -all_viol.rpt " )
log . write ( f " There are max_transition violations. check report: { output_dir } /reports/ { rc_corner } / { design } . { proc_corner } { proc_corner } -all_viol.rpt " )
elif sta_pass == " max_cap " :
print ( f " STA run Passed! " )
log . write ( f " STA run Passed! \n " )
print ( f " There are max_capacitance violations. check report: { output_dir } /reports/ { rc_corner } / { design } . { proc_corner } { proc_corner } -all_viol.rpt " )
log . write ( f " There are max_capacitance violations. check report: { output_dir } /reports/ { rc_corner } / { design } . { proc_corner } { proc_corner } -all_viol.rpt " )
else :
print ( f " STA run Failed! " )
log . write ( f " STA run Failed! \n " )
if sta_pass == " setup " :
print ( f " There are setup violations. check report: { output_dir } /reports/ { rc_corner } / { design } . { proc_corner } { proc_corner } -global.rpt " )
log . write ( f " There are setup violations. check report: { output_dir } /reports/ { rc_corner } / { design } . { proc_corner } { proc_corner } -global.rpt " )
elif sta_pass == " hold " :
print ( f " There are hold violations. check report: { output_dir } /reports/ { rc_corner } / { design } . { proc_corner } { proc_corner } -global.rpt " )
log . write ( f " There are hold violations. check report: { output_dir } /reports/ { rc_corner } / { design } . { proc_corner } { proc_corner } -global.rpt " )
elif sta_pass == " viol " :
print ( f " There are violations. check report: { output_dir } /reports/ { rc_corner } / { design } . { proc_corner } { proc_corner } -all_viol.rpt " )
log . write ( f " There are violations. check report: { output_dir } /reports/ { rc_corner } / { design } . { proc_corner } { proc_corner } -all_viol.rpt " )
2022-11-11 04:52:32 -06:00
elif sta_pass == " no cons " :
print ( f " Reading constraints SDC failed. check log: { log_dir } / { design } - { rc_corner } - { proc_corner } -sta.log " )
log . write ( f " Reading constraints SDC failed. check log: { log_dir } / { design } - { rc_corner } - { proc_corner } -sta.log " )
elif sta_pass == " spef " :
print ( f " Reading parasitics failed. check log: { log_dir } / { design } - { rc_corner } -parasitics.log " )
log . write ( f " Reading parasitics failed. check log: { log_dir } / { design } - { rc_corner } -parasitics.log " )
2022-10-17 11:13:12 -05:00
else :
2022-11-06 08:19:15 -06:00
print ( f " Linking failed. check log: { log_dir } / { design } - { rc_corner } - { proc_corner } -sta.log " )
log . write ( f " Linking failed. check log: { log_dir } / { design } - { rc_corner } - { proc_corner } -sta.log " )
2022-10-17 11:13:12 -05:00
log . close ( )
2022-10-09 05:23:01 -05:00
# Check the required env variables
def check_env_vars ( ) :
2022-10-17 11:13:12 -05:00
pdk_root = os . getenv ( ' PDK_ROOT ' )
pdk = os . getenv ( ' PDK ' )
pt_lib_root = os . getenv ( ' PT_LIB_ROOT ' )
caravel_root = os . getenv ( ' CARAVEL_ROOT ' )
uprj_root = os . getenv ( ' UPRJ_ROOT ' )
mcw_root = os . getenv ( ' MCW_ROOT ' )
if pdk_root is None :
raise FileNotFoundError (
" Please export PDK_ROOT to the PDK path "
)
if pdk is None :
raise FileNotFoundError (
" Please export PDK to either sky130A or sky130B "
)
if pt_lib_root is None :
raise FileNotFoundError (
" Please export PT_LIB_ROOT to the PrimeTime liberties path "
)
if caravel_root is None :
raise FileNotFoundError (
" Please export CARAVEL_ROOT to the Caravel repo path "
)
if mcw_root is None :
raise FileNotFoundError (
" Please export MCW_ROOT to the Caravel Management SoC Litex repo path "
)
if uprj_root is None :
raise FileNotFoundError (
" Please export UPRJ_ROOT to the Caravel User Project Wrapper repo path "
)
# Analyze the STA all violators output report
def search_viol (
report_path : str
) :
2022-11-11 04:52:32 -06:00
proc_corner = report_path [ - 12 ]
rc_corner = os . path . basename ( os . path . dirname ( report_path ) )
log_path = report_path . replace ( f " /reports/ { rc_corner } / " , " /logs/ " )
log_path = log_path . replace ( f " . { proc_corner } { proc_corner } -global.rpt " , f " - { rc_corner } - { proc_corner } -sta.log " )
with open ( log_path , ' r ' ) as report :
data = report . read ( )
if " Could not auto-link design " in data :
return " no link "
elif " Error: Errors reading SDC file: " in data :
return " no cons "
log_path = log_path . replace ( f " { proc_corner } -sta " , f " parasitics " )
with open ( log_path , ' r ' ) as report :
data = report . read ( )
if " Error: Cannot open file " in data :
return " spef "
2022-10-17 11:13:12 -05:00
with open ( report_path , ' r ' ) as report :
data = report . read ( )
2022-11-11 04:52:32 -06:00
if " Hold violations " in data :
2022-10-17 11:13:12 -05:00
return " hold "
2022-11-11 04:52:32 -06:00
elif " Setup violations " in data :
return " setup "
2022-10-17 11:13:12 -05:00
report_path = report_path . replace ( " global " , " all_viol " )
with open ( report_path , ' r ' ) as report :
data = report . read ( )
if " max_transition " in data :
if " max_capacitance " in data :
return " max_tran_cap "
return " max_tran "
elif " max_capacitance " in data :
return " max_cap "
elif " VIOLATED " in data :
return " viol "
else :
return " pass "
if __name__ == " __main__ " :
parser = argparse . ArgumentParser (
description = " Run STA using PrimeTime "
)
parser . add_argument (
" -d " ,
" --design " ,
help = " design name " ,
required = True
2022-10-10 17:46:41 -05:00
)
2022-10-17 11:13:12 -05:00
parser . add_argument (
" -o " ,
" --output_dir " ,
help = " output directory " ,
required = True
2022-10-10 17:46:41 -05:00
)
2022-10-17 11:13:12 -05:00
parser . add_argument (
" -l " ,
" --logs_dir " ,
2022-11-06 08:19:15 -06:00
help = " log directory " ,
2022-10-17 11:13:12 -05:00
required = True
2022-10-09 05:23:01 -05:00
)
2022-10-17 11:13:12 -05:00
parser . add_argument (
" -rc " ,
" --rc_corner " ,
help = " Specify the RC corner for the parasitics (Values are nom, max, or min) <default is nom> " ,
nargs = " ? " ,
default = " nom "
2022-10-09 05:23:01 -05:00
)
2022-10-17 11:13:12 -05:00
parser . add_argument (
" -proc " ,
" --proc_corner " ,
help = " Specify the process corner (Values are t, f, or s) <default is t> " ,
nargs = " ? " ,
default = " t "
2022-10-09 05:23:01 -05:00
)
2022-10-17 11:13:12 -05:00
parser . add_argument (
" -a " ,
" --all " ,
help = " Specify to run all the process corners and rc corners combinations for the design " ,
action = ' store_true '
2022-10-12 16:07:36 -05:00
)
2022-10-09 05:23:01 -05:00
2022-10-17 11:13:12 -05:00
args = parser . parse_args ( )
2022-11-06 08:19:15 -06:00
output = os . path . abspath ( args . output_dir )
2022-10-17 11:13:12 -05:00
log = os . path . abspath ( args . logs_dir )
2022-10-09 05:23:01 -05:00
2022-10-10 17:46:41 -05:00
try :
2022-10-17 11:13:12 -05:00
os . makedirs ( output )
2022-10-10 17:46:41 -05:00
except FileExistsError :
2022-10-17 11:13:12 -05:00
# directory already exists
pass
2022-10-10 17:46:41 -05:00
2022-10-17 11:13:12 -05:00
try :
os . makedirs ( log )
except FileExistsError :
# directory already exists
pass
sub_dirs = [ ' reports ' , ' sdf ' , ' lib ' ]
for item in sub_dirs :
try :
os . makedirs ( os . path . join ( output , item ) )
except FileExistsError :
# directory already exists
pass
if args . all :
run_sta_all ( args . design , output , log )
else :
run_sta ( args . design , args . proc_corner , args . rc_corner , output , log )