#!/bin/bash
# makenewpr 2007-07-06:08h00 graham

# extract information from .vbe file and present in simplified form in .pr file
# usage makenewpr fred  will create file fred.pr
#
# FLOW
# read characteristic delay for reference inverter from technology.pmd
# read FO4 delay for ref inverter
# write out cell header
# for each output pin
#   for each input pin
#     for each value of timing_sense (negative_unate and/or positive_unate)
#       for each of the states that the other input pins might have
#         read the PropRise and PropFall delays at the 4th input transition from cell.vbe
#         read the RampRise and RampFall delays, also at the 4th input transition
#         for each of the 5 most likely input transitions
#           find the rise and fall capacitances of the pin
#       take an average of the rise and fall pin capacitances
#       take an average of the RampRise and RampFall delays
#       take an average of the PropRise and PropFall delays
#       write out these averaged Prop and Ramp delays to temp file#1
#       write out averaged rise and fall pin capacitances to temp file#2
#       write out logical effort for pin using tau from technology.pmd to temp file#3
#   calculate average characteristic delay from values from all pins
#   write out characteristic delay
#   write out the temp files#1-3
#
function=$(basename $PWD)

if test $# -eq 0
then
  echo "# Usage ./makenewpr cell_name. Please supply cell_name." 1>&2
  exit 1
fi

cell=$1

# calculate reference delay tau from reference inverter
# get inverter pin name
inv_pin=$(grep '^inputpin_list' ../iv1/iv1.pmd | awk '{print $2}')
inv_out_pin=$(grep '^outputpin_list' ../iv1/iv1.pmd | awk '{print $2}')
# take average of rise and fall caps
cap1=$[ $(grep '^3' ../iv1/iv1_y2_"$inv_pin"_"$inv_out_pin"_lh.vbe | awk '{printf "%5d\n", ($5*100000000000000000000+5)/10 }') ]
cap2=$[ $(grep '^3' ../iv1/iv1_y2_"$inv_pin"_"$inv_out_pin"_hl.vbe | awk '{printf "%5d\n", ($5*100000000000000000000+5)/10 }') ]
let cap=($cap1+$cap2+10)/20
ramp_lh=$[ $(grep '^3' ../iv1/iv1_y2_"$inv_pin"_"$inv_out_pin"_lh.vbe | awk '{printf "%5d\n", ($4*100+5)/10 }') ]
ramp_hl=$[ $(grep '^3' ../iv1/iv1_y2_"$inv_pin"_"$inv_out_pin"_hl.vbe | awk '{printf "%5d\n", ($4*100+5)/10 }') ]
reftauh=$(echo $[ ( $ramp_lh*$cap +5000 )/10000 ] | awk '{printf "%5d\n", $1 }')
reftaul=$(echo $[ ( $ramp_hl*$cap +5000 )/10000 ] | awk '{printf "%5d\n", $1 }')
#use reftau from technology.pmd instead
reftau=$(grep '^reftau ' ../technology.pmd | awk '{printf "%5d\n", ($2*1000)}')
reffo4=$(grep '^reffo4 ' ../technology.pmd | awk '{printf "%5d\n", ($2*1000)}')

echo $cell | awk '{printf "%-10s%-35s\n", $1, " Prop   Ramp   Cap1  Logical Effort" }' > $cell.pr
echo $cell | awk '{printf "%-10s%-35s\n", $1, " Prop   Ramp   Cap1   LE     LE     FO=4   FO=4" }' > $cell.pr

for out_pin in z
do
# Put cell Prop-Ramp delays into .pr file in a quickly readable format
# check if an inverting gate and flag if single input pin gate
  inverting_gate=0; single_pin=-1; char_delay=0; fo4_delay=0; num_pins=0; num_pins2=0
  for pin in a b c
  do
    inverting_gate=$(grep "^$pin" "$function".pmd | tr -s ' ' | sed "s/^$pin\ //g" | \
      grep "^$out_pin" | cut -f2 -d' ' | \
      grep 'unate' | grep -v 'non_unate' | awk '{print $1}' |
    while read timing_sense
    do
      if [ "$timing_sense" = negative_unate ]
      then
        echo "1"
      fi   
    done )
    let single_pin=$single_pin+1
  done

# get info for each input pin
  for pin in a b c
  do
    unate_values=$(grep "^$pin" "$function".pmd | tr -s ' ' | \
      sed "s/^$pin\ //" | grep "^$out_pin" | cut -f2 -d' ' | \
      grep 'unate' | grep -v 'non_unate' | awk '{print $1}' |
    while read line
    do
      echo -e $line" \c"
    done )
    unate_values=$(echo $unate_values | tr -s ' ')
#   repeat once if one timing_sense otherwise twice
    for timing_sense in $unate_values
    do
      other_pin_state=$(grep "^$pin" "$function".pmd | tr -s ' ' | sed  "s/^$pin\ //g" | \
        grep "^$out_pin" | sed "s/^$out_pin\ //g" | \
        grep "^$timing_sense" | sed "s/^$timing_sense\ //g" | \
        grep '^when' | sed 's/^when\ //g')
      if [ "$other_pin_state" = "" ]
      then
        other_pin_state=0
      fi

#     define timing arcs based on value of timing_sense
      if [ "$timing_sense" = negative_unate ]
      then
        timing_arc1=lh
        timing_arc2=hl
      fi
      if [ "$timing_sense" = positive_unate ]
      then
        timing_arc1=hh
        timing_arc2=ll
      fi

      cap1=0; cap2=0; j=0; l=0; tpr=0; tpf=0; rup=0; rdown=0
#     get value of other pins when this one is toggled
      for k in $other_pin_state
      do
#       adjust $k if there is only one input
        if [ "$single_pin" -eq 0 ]
        then
          n=
        else
          n="$k"_
        fi
        let l=$l+1
#       take Prop delays from 4th input transition
        tpr=$tpr+$[ $(grep '^3' "$cell"_"$pin"_"$out_pin"_"$n$timing_arc1".vbe | awk '{printf "%5d\n", $3*10000000000000000 }') ]
        tpf=$tpf+$[ $(grep '^3' "$cell"_"$pin"_"$out_pin"_"$n$timing_arc2".vbe | awk '{printf "%5d\n", $3*10000000000000000 }') ]
#       take ramp values as the one at 4th input transition (130ps)
        rup=$rup+$[ $(grep '^3' "$cell"_"$pin"_"$out_pin"_"$n$timing_arc1".vbe | awk '{printf "%5d\n", $4*100 }') ]
        rdown=$rdown+$[ $(grep '^3' "$cell"_"$pin"_"$out_pin"_"$n$timing_arc2".vbe | awk '{printf "%5d\n", $4*100 }') ]
#       calculate cap as average of the cap measured on the 3rd to 7th transitions
        for i in 2 3 4 5 6
        do
          let j=$j+1
#         sum the cap values for each considered input transition and other pin state
          let cap1=$cap1+$[ $(grep "^$i" "$cell"_"$pin"_"$out_pin"_"$n$timing_arc1".vbe | awk '{printf "%5d\n", ($5*100000000000000000000+5)/10 }') ]
          let cap2=$cap2+$[ $(grep "^$i" "$cell"_"$pin"_"$out_pin"_"$n$timing_arc2".vbe | awk '{printf "%5d\n", ($5*100000000000000000000+5)/10 }') ]
        done
      done
#     single cap value is averaged over transitions and states
      let "cap=($cap1+$cap2+$j*10)/($j*20)"
      let "cap1=($cap1+$j*5)/($j*10)"
      let "cap2=($cap2+$j*5)/($j*10)"
#     single value for drive strengths is is averaged over transitions and states
      let "rup=($rup+$l*5)/($l*10)"
      let "rdown=($rdown+$l*5)/($l*10)"
#     average Prop delays over the values measured with the other pin states
      let "tpr=($tpr+$l*5)/($l*10)"
      let "tpf=($tpf+$l*5)/($l*10)"
#     calculate FO=4 delays
      let "fo4r=10000*$tpr+4*$rup*$cap"
      let "fo4f=10000*$tpf+4*$rdown*$cap"

#     write out Prop and Ramp delays in ps and ps/fF
      echo $tpr" "$rup | awk '{printf "%-8s%7.1f%7.2f\n", "'$pin'_'$out_pin'_'$timing_arc1'", $1/1000, $2/10000 }' >> $$temp1
      echo $tpf" "$rdown | awk '{printf "%-8s%7.1f%7.2f\n", "'$pin'_'$out_pin'_'$timing_arc2'", $1/1000, $2/10000 }' >> $$temp1
#     write out input cap in fF
      echo $cap1 | awk '{printf "%6.2f\n", $1/1000 }' >> $$temp2
      echo $cap2 | awk '{printf "%6.2f\n", $1/1000 }' >> $$temp2
#     write out logical effort for each pin and transition of inverting gate
      if [ "$timing_sense" = negative_unate ]
      then
#       reftau from technology.pmd replaces reftaul and reftauh calculated from ref inverter
        delayr=$(echo $[ ( $rup*$cap ) ] | awk '{printf "%6d\n", $1 }')
        echo $[ ((2*$delayr+$reftau)/(2*$reftau)) ] | awk '{printf "%6.3f\n", $1/10000 }' >> $$temp3
        delayf=$(echo $[ ( $rdown*$cap ) ] | awk '{printf "%6d\n", $1 }')
        echo $[ ((2*$delayf+$reftau)/(2*$reftau)) ] | awk '{printf "%6.3f\n", $1/10000 }' >> $$temp3
        echo $[ (($delayr+$delayf+$reftau)/(2*$reftau)) ] | awk '{printf "%6.3f\n", $1/10000 }' >> $$temp4
        echo "      " >> $$temp4
      else
        echo "      " >> $$temp3
        echo "      " >> $$temp3
        echo "      " >> $$temp4
        echo "      " >> $$temp4
      fi
#     write out FO4 delay
      echo $[ ((2*$fo4r+$reffo4)/(2*$reffo4)) ] | awk '{printf "%6.3f\n", $1/10000 }' >> $$temp5
      echo $[ ((2*$fo4f+$reffo4)/(2*$reffo4)) ] | awk '{printf "%6.3f\n", $1/10000 }' >> $$temp5
      echo $[ (($fo4r+$fo4f+$reffo4)/(2*$reffo4)) ] | awk '{printf "%6.3f\n", $1/10000 }' >> $$temp6
      echo "      " >> $$temp6

#     characteristic delay is rise and fall ramp * input pin cap averaged over all pins
      if [ "$timing_sense" = negative_unate ]
      then
        let "char_delay=$char_delay+$rup*$cap1+$rdown*$cap2"
        let "num_pins=$num_pins+1"
      fi
      let "fo4_delay=$fo4_delay+$fo4r+$fo4f"
      let "num_pins2=$num_pins2+1"
    done #for timing_sense in $unate_values
  done #for pin in a b c

# only output delay if timing_sense is inverting
  if [ "$inverting_gate" = 1 ]
  then
    char_delay1=$(echo $[ ($char_delay+$num_pins)/($num_pins*2) ] | awk '{printf "%7.3f\n", $1/10000000}' )
    char_delay2=$(echo $[ ($char_delay+$num_pins*$reftau)/($num_pins*2*$reftau) ] | awk '{printf "%4.2f\n", $1/10000}' )
    echo "# "$out_pin" timing; average characteristic_delay "$char_delay1" ps  "$char_delay2 >> $cell.pr
  else
    echo "# "$out_pin" timing" >> $cell.pr
  fi
  fo4_delay1=$(echo $[ ($fo4_delay+$num_pins2)/($num_pins2*2) ] | awk '{printf "%6.2f\n", $1/10000000}' )
  fo4_delay2=$(echo $[ ($fo4_delay+$num_pins2*$reffo4)/($num_pins2*2*$reffo4) ] | awk '{printf "%4.2f\n", $1/10000}' )
  echo "# "$out_pin" timing; average FO4_delay            "$fo4_delay1" ps  "$fo4_delay2 >> $cell.pr

  paste -d " " $$temp1 $$temp2 $$temp3 $$temp4 $$temp5 $$temp6>> $cell.pr
  rm $$temp1 $$temp2 $$temp3 $$temp4 $$temp5 $$temp6
done #for out_pin in z

echo "" >> $cell.pr
cat $cell.pr
