#!/bin/bash
#loop_buf_loon
# Copyright (c) 2008 Graham Petley
# Released under the terms of the GNU Lesser General Public Licence

# Script which iterates LOON and prints delay and area
# information. buf_loon is used which allows opt levels
# 2 and 4 to be used, since any hang will terminate after
# a default 30 secs.

max_fanin=4
rin=10000
time_limit=30
min_area=1000000000
old_min_delay=100001
min_delay=100000
let "min_product=min_area*min_delay"

if [ "$#" -eq 0 ]
then
  echo "# Usage: loop_buf_loon -l lax_file input_file output_file" 1>&2
  echo "#" 1>&2
  echo "# iterates loon starting with input_file.vst to produce fastest netlist in output_file.vst" 1>&2
  exit 1
fi

read_in_file=0
while [ "$#" -gt 0 ]
do
  case $1 in
  -l)
    shift
    if test -f $1.lax
    then
      lax_file=$1
      cp ${lax_file}.lax $$_lax.lax
      shift
    else
      echo "# Usage: loop_buf_loon -l lax_file input_file output_file" 1>&2
      echo "#" 1>&2
      if [ "$1" = "" ]
      then
        echo "# no lax_file supplied. Please check." 1>&2
      else
        echo "# the lax_file supplied "$1".lax does not exist. Please check." 1>&2
      fi
      exit 1
    fi ;;
  *)
    if [ "$read_in_file" -eq 0 ]
    then
      if test -f $1.vst
      then
        in_file=$1
        read_in_file=1
        shift
      else
        echo "# Usage: loop_buf_loon -l lax_file input_file output_file" 1>&2
        echo "#" 1>&2
        echo "# the input_file supplied "$1".vst does not exist. Please check." 1>&2
        exit 1
      fi
    else
      out_file=$1
      shift
    fi ;;
  esac
done
if [ ! -f $$_lax.lax ]
then
  echo "# Usage: loop_buf_loon -l lax_file input_file output_file" 1>&2
  echo "#" 1>&2
  echo "# no lax_file supplied. Please check." 1>&2
  exit 1
fi
if [ "$in_file" = "" ]
then
  echo "# Usage: loop_buf_loon -l lax_file input_file output_file" 1>&2
  echo "#" 1>&2
  echo "# no input_file supplied. Please check." 1>&2
  exit 1
fi
if [ "$out_file" = "" ]
then
  echo "# Usage: loop_buf_loon -l lax_file input_file output_file" 1>&2
  echo "#" 1>&2
  echo "# no output_file supplied. Please check." 1>&2
  exit 1
fi

if test ! -d $MBK_TARGET_LIB
then
  echo "# Environment variable \$MBK_TARGET_LIB must point to the library." 1>&2
  echo "# \$MBK_TARGET_LIB is "$MBK_TARGET_LIB" and doesn't exist." 1>&2
  echo "# Please check." 1>&2
  exit 1
fi

library=$(basename ${MBK_TARGET_LIB%lib*}lib)
case $library in
  rgalib) one_gate_size=2816 ;;
  sclib) one_gate_size=756 ;;
  ssxlib) one_gate_size=3000 ;;
  stxlib) one_gate_size=3000 ;;
  sxlib) one_gate_size=750 ;;
  vgalib) one_gate_size=2816 ;;
  vsclib) one_gate_size=1728 ;;
  vtclib) one_gate_size=1728 ;;
  vsxlib) one_gate_size=3000 ;;
  vtxlib) one_gate_size=3000 ;;
  vxlib) one_gate_size=750 ;;
  wsclib) one_gate_size=1920 ;;
  wtclib) one_gate_size=1920 ;;
  *) echo "#?! Library "$MBK_TARGET_LIB" not supported yet. Please check." 1>&2
    exit 1 ;;
esac

run_loon()
{
if [ ! -f $1.vst ]
then
# No input file, probably because previous loop crashed
  continue
fi
if [ "$opt_num" -eq 1 ]
then
  loon_out=$1$separator$2
  loon_cond=$1$separator$2
  spacer="..."
elif [ "$opt_num" -eq 2 ]
then
  loon_out=$1$2
  loon_cond=${1}
  spacer=".."
elif [ "$opt_num" -eq 3 ]
then
  loon_out=$1$2
  loon_cond=${1%?}
  spacer="."
elif [ "$opt_num" -eq 4 ]
then
  loon_out=$1$2
  loon_cond1=${1%?}
  loon_cond=${loon_cond1%?}
  spacer=""
fi
# Try to buffer all inputs with fanin<=4
sed -i "s/^#M{\(.\)} *$/#M{$2}/" $$_lax.lax
#cp $$_lax.lax lax${2}.lax
./buf_loon -l $$_lax $1 $loon_out 2>/dev/null >loop_buf_loon.log
exit_status=$?
if [ "$exit_status" -eq 2 ]
then
  echo "#"$loon_out$spacer" locked up"
  continue
elif [ "$exit_status" -eq 1 ]
then
  echo "#"$loon_out$spacer" crashed"
  continue
else
  area=$(grep '^Area' loop_buf_loon.log | tail -1 | sed 's/\.\.\./ /' | cut -f5 -d' ')
  delay=$(grep '^Critical' loop_buf_loon.log | sed 's/\.\.\./ /' | cut -f5 -d' ')
  if [ "$area" = "" -o "$delay" = "" ]
  then
    continue
  fi
  let "gates=(2*area+one_gate_size)/(2*one_gate_size)"
  let "product=area*delay"
  let "min_delay=loop_num==0?delay:min_delay"
  if [ "$area" -lt "$min_area" -o "$delay" -lt "$min_delay" -o "$product" -lt "$min_product" -o "$loop_num" -eq 0 ]
  then
    echo "#"$loon_out$spacer" Delay "$delay", Area "$area", Gates "$gates
    let loop_num=$loop_num+1
  fi
  if [ "$min_delay" -gt "$delay" ]
  then
    loon_exit=$loon_out
    min_loon_cond=$loon_cond
    last_spacer=$spacer
  fi
  let "min_delay=min_delay>delay?delay:min_delay"
  let "min_area=min_area>area?area:min_area"
  let "min_product=min_product>product?product:min_product"
fi
}

#######################
# Execution begins here.

date
separator=_
if test -f .buf_loon
then
  values=$(grep "^ *max_fanin " .buf_loon | sed 's/^ *//' | tr -s ' ' | cut -f 2 -d' ')
  for value in $values
  do
    max_fanin=$value
  done
fi
fanin=$(./find_fanin $in_file | grep '^Max fanin ' | cut -f5 -d' ')
if [ "$max_fanin" -gt 0 -a "$max_fanin" -lt "$fanin" ]
then
  rin=$(./find_rin -l $lax_file $in_file 2>/dev/null)
  echo "rin "$rin >> .buf_loon
fi
for_loop_num=0
while [ "$old_min_delay" -gt "$min_delay" ]
do
  start_time=$(date '+%s')
  loop_num=0
  old_min_delay=$min_delay
  for opt1 in 0 1 2 4
  do
    opt_num=1
    run_loon $in_file $opt1
  done
  let for_loop_num=$for_loop_num+1
  for opt1 in 0 1 2 4
  do
    for opt2 in 0 1 2 4
    do
      opt_num=2
      run_loon $in_file$separator$opt1 $opt2
    done
  done
  let for_loop_num=$for_loop_num+1
  for opt1 in 0 1 2 4
  do
    for opt2 in 0 1 2 4
    do
      for opt3 in 0 1 2 4
      do
        opt_num=3
        run_loon $in_file$separator$opt1$opt2 $opt3
      done
    done
  done
  let for_loop_num=$for_loop_num+1
  echo "# elapsed time "$[$(date '+%s')-$start_time]"s"
# Remove all files except fastest netlists
  for opt1 in 0 1 2 4
  do
    for opt2 in 0 1 2 4
    do
      for opt3 in 0 1 2 4
      do
        if [ "$in_file$separator$opt1$opt2$opt3" != "$loon_exit" ]
        then
          rm -f $in_file$separator$opt1$opt2${opt3}.vst $in_file$separator$opt1$opt2${opt3}.xsc $in_file$separator$opt1$opt2${opt3}.al
        fi
      done
      if [ "$in_file$separator$opt1$opt2" != "$loon_exit" ]
      then
        rm -f $in_file$separator$opt1${opt2}.vst $in_file$separator$opt1${opt2}.xsc $in_file$separator$opt1${opt2}.al
      fi
    done
    if [ "$in_file$separator$opt1" != "$min_loon_cond" -a "$in_file$separator$opt1" != "$loon_exit" ]
    then
      rm -f $in_file$separator${opt1}.vst $in_file$separator${opt1}.xsc $in_file$separator${opt1}.al
    fi
  done
  in_file=$min_loon_cond
  separator=
done
sed -i 's/^#M{\(.\)} *$/#M{0}/' $$_lax.lax
./buf_loon -l $$_lax $loon_exit $out_file -f 0 2>/dev/null >loop_buf_loon.log
exit_status=$?
if [ "$exit_status" -eq 2 ]
then
  echo "#"$loon_out$spacer" locked up"
elif [ "$exit_status" -eq 1 ]
then
  echo "#"$loon_out$spacer" crashed"
else
  area=$(grep '^Area' loop_buf_loon.log | tail -1 | sed 's/\.\.\./ /' | cut -f5 -d' ')
  delay=$(grep '^Critical' loop_buf_loon.log | sed 's/\.\.\./ /' | cut -f5 -d' ')
  let "gates=(2*area+one_gate_size)/(2*one_gate_size)"
  echo "#"${loon_exit}0${last_spacer}" Delay "$delay", Area "$area", Gates "$gates
fi
rm $$_lax.lax
date

