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