#!/bin/bash

if [ $# -eq 0 ]
then
  echo "#" 1>&2
  echo "# Written by Graham Petley, 8-JUL-07." 1>&2
  echo "# ------------------------------------"
  echo "# Please supply critical file name ... (extensions xsc and vst will be used)" 1>&2
  echo "# e.g" 1>&2
  echo "# bash$ find_crit_path multi8" 1>&2
  echo "# will find the critical path using multi8.vst and multi8.xsc" 1>&2
  echo "# The xsc and vst files should be written by LOON using a command like" 1>&2
  echo "# bash$ loon -x 0 multi8_o multi8"
  echo "#" 1>&2
  exit 1
fi

xsc=$1.xsc
vst=$1.vst

if [ ! -f "$vst" -o ! -f "$xsc" ]
then
  echo "#? Files "$vst" and "$xsc" don't exist. Please check." 1>&2
  exit 1
fi

# ^C is port and time info with critical path highlighted with 32.
#    The highlight can be missing if there is redundant logic whose
#    delay is greater than the critical path to the output port.

critpath=$(grep '^C' $xsc | grep ':32:' | cut -d ':' -f 4 | awk '{print $1}' | sort -rn)
if [ "$critpath" = "" ]
then
  echo "#? There is no critical path in "$1". Please check." 1>&2
  exit 1
fi
i=0
for path in $critpath
do
  let i=$i+1
  if [ "$i" -eq 1 ] 
  then
#   this is end point of critical path; use to get end connector name
    firstpath=$path
    end=$(grep '^C' $xsc | grep ":32:$path " | cut -d ':' -f 2)
    endvst=$(grep '^C' $xsc | grep ":32:$path " | cut -d ':' -f 2 | \
      sed 's/\([^ ][^ ]*\)\ \([^ ][^ ]*\)/\1(\2)/')
  fi
  if [ "$i" -eq 2 ] 
  then
#   this is start point of critical path; use to get start connector name
    start=$(grep '^C' $xsc | grep ":32:$path " | cut -d ':' -f 2)
    startvst=$(grep '^C' $xsc | grep ":32:$path " | cut -d ':' -f 2 | \
      sed 's/\([^ ][^ ]*\)\ \([^ ][^ ]*\)/\1(\2)/')
  fi
done
if [ "$i" -eq 1 ]
then
# Only picked up start; have to get end by sorting port delays
  start=$end
  startvst=$endvst
  critpath=$(grep '^C' $xsc | cut -d ':' -f 4 | awk '{print $1}' | sort -rn | grep -m 1 '^')
  firstpath=$critpath
  end=$(grep '^C' $xsc | grep "^C:[^:][^:]*:[^:][^:]*:$critpath " | cut -d ':' -f 2)
  endvst=$(grep '^C' $xsc | grep "^C:[^:][^:]*:[^:][^:]*:$critpath " | cut -d ':' -f 2 | \
    sed 's/\([^ ][^ ]*\)\ \([^ ][^ ]*\)/\1(\2)/')
fi
fanin=$(awk '/^begin/,/^end/ {print}' $vst | grep -c "=> *$startvst *,")
echo -n "    "
echo $start | awk -v FS=: '{printf "%-12s", $1}'
echo $fanin | awk '{printf "%3d", $1}'
echo -n "                "
echo $path | awk '{printf "%5d\n", $1}'
i=0
nextinst=$(grep ":$end:" $xsc | grep '^P' | cut -d ':' -f 2 | tr -s ' ' | grep -m 1 '^')
if [ "$nextinst" = "" ]
then
# Need to get inst name from crit path delay
  nextinst=$(grep "$critpath" $xsc | grep '^B' | cut -d ':' -f 2 | tr -s ' ' | grep -m 1 '^')
fi
vstinst=$nextinst
while [ "$nextinst" != "$start" ]
do
  nexttime=$(grep "^B:$nextinst:" $xsc | cut -d ':' -f 4 | tr -s ' ' | awk '{printf "%1d\n", $1}')
  nextcell=$(grep "^ *$vstinst *:" $vst | cut -d ':' -f 2 | tr -s ' ')

  if [ "$(grep "^P:$nextinst:" $xsc)" != "" ]
  then
    nextnet=$(grep "^P:$nextinst:" $xsc | cut -d ':' -f 3 | tr -s ' ' | \
      sed 's/\([^ ][^ ]*\)\ \([^ ][^ ]*\)/\1(\2)/')
    netout=$(grep "^P:$nextinst:" $xsc | cut -d ':' -f 3 | tr -s ' ' | \
      sed 's/\([^ ][^ ]*\)\ \([^ ][^ ]*\)/\1\\(\2\\)/')
    netin=$(grep "^P:[^:][^:]*:[^:][^:]*:$nextinst:" $xsc | cut -d ':' -f 3 | tr -s ' ' | \
      sed 's/\([^ ][^ ]*\)\ \([^ ][^ ]*\)/\1\\(\2\\)/')
  else
#   Have to use vst to find previous instance
    netins=$(sed -n "/$nextinst/,/^ *);/ p" $vst | grep '=>' | \
      egrep -v "=> *vdd|=> *vss|=> *$end *," | tr -s ' ' | sed 's|^ *\(.*\), *$|\1|' | cut -f3 -d' ')
    for netin in $netins
    do
      nextinst=$(grep "^P:[^:][^:]*:$netin:[^:][^:]*:32:" $xsc | cut -d ':' -f 4 | tr -s ' ')
      if [ "$nextinst" != "" ]
      then
        nextnet=$endvst
        netout=$(echo $endvst | sed 's|(|\\(|' | sed 's|)|\\)|')
        break
      fi
    done
  fi
# the sed command replaces something like 'x 0' with 'x\(0\)'
  let fanout=$(grep '=>' $vst | grep -c " $nextnet *,")-1

  if [ "$i" -ne 0 ]
  then
    let deltatime=$prevtime-$nexttime
    echo $prevcell | awk '{printf "%-12s", $1}' >>$$_temp
    echo $prevfanout | awk '{printf "%3d%2s", $1, "  "}' >> $$_temp
    echo $arc | awk '{printf "%-8s", $1}' >>$$_temp
    echo $prevtime | awk '{printf "%5d%1s", $1, " "}' >>$$_temp
    echo $deltatime | awk '{printf "%5d%3s", $1, "   "}' >>$$_temp
    echo $previnst | sed 's/\ /_/' | awk '{printf "%-24s", $1}' >>$$_temp
    echo $prevnet | awk '{printf "%-24s\n", $1}' | sed 's/ *$//' >> $$_temp
  else
    firstpath=$nexttime
  fi

  pinin=$(awk '/^ *'$vstinst' *:/,/);/ {print}' $vst | awk '/port map/,/);/ {print}' | \
          awk '/ '$netin' *,/ {print $1}' | grep -m 1 '^')
  pinout=$(awk '/^ *'$vstinst' *:/,/);/ {print}' $vst | awk '/port map/,/);/ {print}' | \
          awk '/ '$netout' *,/ {print $1}')
  arc=$(echo $pinin"->"$pinout)

  prevcell=$nextcell
  prevtime=$nexttime
  prevnet=$nextnet
  prevfanout=$fanout
  previnst=$nextinst
  nextinst=$(grep ":$previnst:" $xsc | grep '^P' | cut -d ':' -f 2 | tr -s ' ' | \
             grep -m 1 '^' )
  vstinst=$(grep ":$previnst:" $xsc | grep '^P' | cut -d ':' -f 2 | tr -s ' ' | \
             grep -m 1 '^' | sed 's/\ /_/' )
  if [ "$(echo $previnst | awk '{print length($1)}')" -gt 23 ]
  then
    let startpos=$(echo $previnst | awk '{print length($1)}')-20
    previnst=$(echo $previnst | awk '{print ".."substr($1,'$startpos',21)}')
  fi
  let i=$i+1
done

echo $prevcell | awk '{printf "%-12s", $1}' >>$$_temp
echo $prevfanout | awk '{printf "%3d%2s", $1, "  "}' >> $$_temp
echo $arc | awk '{printf "%-8s", $1}' >>$$_temp
echo $prevtime | awk '{printf "%5d%1s", $1, " "}' >>$$_temp
echo $[$prevtime-$path] | awk '{printf "%5d%3s", $1, "   "}' >>$$_temp
echo $previnst | sed 's/\ /_/' | awk '{printf "%-24s", $1}' >>$$_temp
echo $prevnet | awk '{printf "%-24s", $1}' | sed 's/ *$//' >> $$_temp

cat $$_temp | grep -n '^' | sort -rn | sed 's/^[^:][^:]*://' | \
grep -n '^' | sed 's/^\([^:][^:]*\):/\1\ \ /' | sed 's/^.\ /\ &/'

echo "    "$end

secondpath=$(grep '^C' $xsc | grep -v ":$end:[^:][^:]*:$firstpath" | cut -d ':' -f 4 | \
  awk '{print $1}' | sort -rn | grep -m 1 '^')
secondname=$(grep '^C' $xsc | grep ":-1:$secondpath" | cut -d ':' -f 2)

echo
echo "1st critical path is "$end" at "$firstpath
echo "2nd critical path is "$secondname" at "$secondpath
echo
rm $$_temp
