1#!/bin/tcsh -f 2#---------------------------------------------------------- 3# Static timing analysis script using OpenSTA 4#---------------------------------------------------------- 5# Tim Edwards, 10/05/18, for Open Circuit Design 6#---------------------------------------------------------- 7 8# Split out options from the main arguments 9set argline=(`getopt "ad" $argv[1-]`) 10 11set options=`echo "$argline" | awk 'BEGIN {FS = "-- "} END {print $1}'` 12set cmdargs=`echo "$argline" | awk 'BEGIN {FS = "-- "} END {print $2}'` 13set argc=`echo $cmdargs | wc -w` 14 15if ($argc == 2) then 16 set argv1=`echo $cmdargs | cut -d' ' -f1` 17 set argv2=`echo $cmdargs | cut -d' ' -f2` 18else 19 echo "Usage: opensta.sh [options] <project_path> <source_name>" 20 echo " where" 21 echo " <project_path> is the name of the project directory containing" 22 echo " a file called qflow_vars.sh." 23 echo " <source_name> is the root name of the verilog file" 24 echo " [options] are:" 25 echo " -d use delay file to back-annotate wire delays" 26 echo " -a append to log file (do not overwrite)" 27 exit 1 28endif 29 30set dodelays=0 31set append=0 32 33foreach option (${argline}) 34 switch (${option}) 35 case -d: 36 set dodelays=1 37 breaksw 38 case -a: 39 set append=1 40 breaksw 41 case --: 42 break 43 endsw 44end 45 46set projectpath=$argv1 47set sourcename=$argv2 48set rootname=${sourcename:h} 49 50# This script is called with the first argument <project_path>, which should 51# have file "qflow_vars.sh". Get all of our standard variable definitions 52# from the qflow_vars.sh file. 53 54if (! -f ${projectpath}/qflow_vars.sh ) then 55 echo "Error: Cannot find file qflow_vars.sh in path ${projectpath}" 56 exit 1 57endif 58 59source ${projectpath}/qflow_vars.sh 60source ${techdir}/${techname}.sh 61cd ${projectpath} 62if (-f project_vars.sh) then 63 source project_vars.sh 64endif 65 66if (! ${?opensta_options} ) then 67 set opensta_options = "" 68endif 69 70if (!($?logdir)) then 71 set logdir=${projectpath}/log 72endif 73mkdir -p ${logdir} 74if ($dodelays == 1) then 75 set lastlog=${logdir}/route.log 76 set synthlog=${logdir}/post_sta.log 77else 78 set lastlog=${logdir}/place.log 79 set synthlog=${logdir}/sta.log 80 rm -f ${logdir}/route.log >& /dev/null 81endif 82rm -f ${logdir}/post_sta.log >& /dev/null 83rm -f ${logdir}/migrate.log >& /dev/null 84rm -f ${logdir}/drc.log >& /dev/null 85rm -f ${logdir}/lvs.log >& /dev/null 86rm -f ${logdir}/gdsii.log >& /dev/null 87set date=`date` 88 89if ( $append == 0 ) then 90 rm -f ${synthlog} >& /dev/null 91 touch ${synthlog} 92 echo "Qflow static timing analysis logfile created on $date" > ${synthlog} 93else 94 touch ${synthlog} 95 echo "\nQflow static timing analysis logfile appended on $date" >> ${synthlog} 96endif 97 98# Check if last line of log file says "error condition" 99set errcond = `tail -1 ${lastlog} | grep "error condition" | wc -l` 100if ( ${errcond} == 1 ) then 101 echo "Synthesis flow stopped on error condition. Static timing analysis" 102 echo "will not proceed until error condition is cleared." 103 exit 1 104endif 105 106# Prepend techdir to libertyfile unless libertyfile begins with "/" 107# Use "libertymax" and "libertymin" for maximum and minimum timing, 108# respectively, unless they don't exist, in which case use "libertyfile" 109# for both. 110 111set abspath=`echo ${libertyfile} | cut -c1` 112if ( "${abspath}" == "/" ) then 113 set libertypath=${libertyfile} 114 if ( ${?libertymax} ) then 115 set libertymaxpath=${libertymax} 116 else 117 set libertymaxpath=${libertyfile} 118 endif 119 if ( ${?libertymin} ) then 120 set libertyminpath=${libertymin} 121 else 122 set libertyminpath=${libertyfile} 123 endif 124else 125 set libertypath=${techdir}/${libertyfile} 126 if ( ${?libertymax} ) then 127 set libertymaxpath=${techdir}/${libertymax} 128 else 129 set libertymaxpath=${techdir}/${libertyfile} 130 endif 131 if ( ${?libertymin} ) then 132 set libertyminpath=${techdir}/${libertymin} 133 else 134 set libertyminpath=${techdir}/${libertyfile} 135 endif 136endif 137 138# Add hard macros 139 140set hardmacrolibs="" 141if ( ${?hard_macros} ) then 142 foreach macro_path ( $hard_macros ) 143 foreach file ( `ls ${sourcedir}/${macro_path}` ) 144 if ( ${file:e} == "lib" ) then 145 set hardmacrolibs="${hardmacrolibs} ${sourcedir}/${macro_path}/${file}" 146 endif 147 break 148 end 149 end 150endif 151 152#---------------------------------------------------------- 153# Done with initialization 154#---------------------------------------------------------- 155 156# Check if last line of log file says "error condition" 157set errcond = `tail -1 ${lastlog} | grep "error condition" | wc -l` 158if ( ${errcond} == 1 ) then 159 echo "Synthesis flow stopped on error condition. Timing analysis will not" 160 echo "proceed until error condition is cleared." 161 exit 1 162endif 163 164cd ${layoutdir} 165 166#------------------------------------------------------------------ 167# Generate the static timing analysis results 168#------------------------------------------------------------------ 169 170if ($dodelays == 1) then 171 # Check if a .rc file exists. This file is produced by qrouter 172 # and contains delay information in nested RC pairs 173 if ( -f ${rootname}.rc ) then 174 175 # Run rc2dly 176 echo "Converting qrouter output to vesta delay format" |& tee -a ${synthlog} 177 echo "Running rc2dly -r ${rootname}.rc -l ${libertypath} -V ${synthdir}/${rootname}.rtl.v" \ 178 |& tee -a ${synthlog} 179 echo "-d ${rootname}.dly" |& tee -a ${synthlog} 180 ${bindir}/rc2dly -r ${rootname}.rc -l ${libertypath} \ 181 -V ${synthdir}/${rootname}.rtl.v \ 182 -d ${synthdir}/${rootname}.dly 183 184 # Run rc2dly again to get SDF format file 185 echo "Converting qrouter output to SDF delay format" |& tee -a ${synthlog} 186 echo "Running rc2dly -r ${rootname}.rc -l ${libertypath} -V ${synthdir}/${rootname}.rtl.v" \ 187 |& tee -a ${synthlog} 188 echo "-d ${rootname}.sdf" |& tee -a ${synthlog} 189 ${bindir}/rc2dly -r ${rootname}.rc -l ${libertypath} \ 190 -V ${synthdir}/${rootname}.rtl.v \ 191 -d ${synthdir}/${rootname}.sdf 192 193 # Translate <, > to [ ] to match the verilog, as SDF format does not have 194 # the ability to change array delimiters. 195 if ( -f ${synthdir}/${rootname}.sdf ) then 196 cat ${synthdir}/${rootname}.sdf | sed -e 's/</\[/g' -e 's/>/\]/g' \ 197 > ${synthdir}/${rootname}.sdfx 198 mv ${synthdir}/${rootname}.sdfx ${synthdir}/${rootname}.sdf 199 endif 200 201 cd ${synthdir} 202 203 # Spot check for output file 204 if ( ! -f ${rootname}.sdf || \ 205 ( -M ${rootname}.sdf < -M ${layoutdir}/${rootname}.rc )) then 206 echo "rc2dly failure: No file ${rootname}.sdf created." \ 207 |& tee -a ${synthlog} 208 echo "Premature exit." |& tee -a ${synthlog} 209 echo "Synthesis flow stopped due to error condition." >> ${synthlog} 210 exit 1 211 endif 212 213 else 214 echo "Error: No file ${rootname}.rc, cannot back-annotate delays!" \ 215 |& tee -a ${synthlog} 216 echo "Premature exit." |& tee -a ${synthlog} 217 echo "Synthesis flow stopped due to error condition." >> ${synthlog} 218 exit 1 219 endif 220endif 221 222cd ${synthdir} 223 224# Create a shell SDC file if one doesn't exist 225# (This remains to be done properly and will probably need to be done by a script) 226 227if ($dodelays == 1) then 228 229if ( !(-f ${rootname}_post.sdc )) then 230 echo "Creating example SDC file for timing" |& tee -a ${synthlog} 231 cat > ${rootname}_post.sdc << EOF 232create_clock -name clock -period 20 [get_ports clock] 233set_propagated_clock [all_clocks] 234EOF 235endif 236 237else 238 239if ( !(-f ${rootname}.sdc )) then 240 echo "Creating example SDC file for timing" |& tee -a ${synthlog} 241 cat > ${rootname}.sdc << EOF 242create_clock -name clock -period 20 [get_ports clock] 243EOF 244endif 245 246endif 247 248# Create the input script for OpenSTA 249 250echo "Creating OpenSTA input file ${rootname}.conf" |& tee -a ${synthlog} 251cat > ${rootname}.conf << EOF 252read_liberty -min ${libertyminpath} 253read_liberty -max ${libertymaxpath} 254EOF 255 256foreach libpath ( $hardmacrolibs ) 257cat >> ${rootname}.conf << EOF 258read_celllib ${libpath} 259EOF 260end 261 262cat >> ${rootname}.conf << EOF 263read_verilog ${rootname}.rtlnopwr.v 264link_design ${rootname} 265EOF 266 267if ($dodelays == 1) then 268 cat >> ${rootname}.conf << EOF 269read_sdf ${rootname}.sdf 270EOF 271endif 272 273if ($dodelays == 1) then 274 275cat >> ${rootname}.conf << EOF 276read_sdc ${rootname}_post.sdc 277EOF 278 279else 280 281cat >> ${rootname}.conf << EOF 282read_sdc ${rootname}.sdc 283EOF 284 285endif 286 287cat >> ${rootname}.conf << EOF 288check_setup 289report_annotated_check 290report_annotated_delay 291report_checks -path_delay min_max -group_count 1000 292exit 293EOF 294 295echo "" 296if ($dodelays == 1) then 297 echo "Running OpenSTA static timing analysis with back-annotated extracted wire delays" \ 298 |& tee -a ${synthlog} 299else 300 echo "Running OpenSTA static timing analysis" |& tee -a ${synthlog} 301endif 302echo "sta ${opensta_options} < ${rootname}.conf" |& tee -a ${synthlog} 303echo "" 304${bindir}/sta ${opensta_options} < ${rootname}.conf |& tee -a ${synthlog} 305echo "" 306 307#------------------------------------------------------------ 308# Done! 309#------------------------------------------------------------ 310exit 0 311