#!/bin/bash

# Recognized variables:
#
# CC=[avr-gcc]		Used to compile bench.c.
# JOBS=[1]              Number of parallel Jobs for make.
# TIMES=[1]             Multiplicator for N_VALS from the input files.
# builddir=             Use AVR-LibC from builddir instead of CC's.
#
# ./gen-banch.sh A B ... will read files $BASE-A.txt $BASE-B.txt etc.
# and user their input to generate the output file.

out=out.dox
elf=x.elf

CC=${CC-avr-gcc}
TIMES=${TIMES-1}
BASE=${BASE-fxlib}

AVRTEST_HOME=$(dirname $(which avrtest))
avrtest="${AVRTEST_HOME}/avrtest -q -log"
echo "avrtest=$avrtest"


Err ()
{
    echo "error: $1"
    exit 1
}

set_libs_crt ()
{
    LIBS=
    CRT=
    if [ -n "$builddir" ] ; then
      local multilibdir=$($CC -mmcu=$1 -print-multi-directory)
      # Use the same replacements like in mlib-gen.py::to_ident() and
      # configure.ac's CHECK_AVR_DEVICE.  This flattens out the multilib path.
      # For example, "avr25/tiny-stack" becomes "avr25_tiny_stack",
      # and "." becomes "avr2".
      local multilibdir=$(echo "$multilibdir"     \
                    | sed -e 's:^\.$:avr2:' \
                    | sed -e 's:/:_:g'      \
                    | sed -e 's:-:_:g')
      local crt=crt$1.o
      [ -d "$builddir/avr/devices" ] \
	  || Err "\$builddir/avr/devices = $builddir/avr/devices: not found"
      local incl="-I../../include -I $builddir/include"
      local flags="-nostdlib -nodevicelib -nostartfiles"
      local m="$builddir/avr/lib/$multilibdir"
      CRT=$(find $builddir/avr/devices -name $crt -print | head -1)
      local libs="$m/libc.a $m/libm.a $(dirname $CRT)/lib$1.a -lgcc"
      LIBS="$incl $flags -Wl,-( $libs -Wl,-)"
    fi
}


getval ()
{
    local l="$(grep "$1=" <<< "$2")"
    eval $l
}

fun_line ()
{
    echo "== Line: $*"
    fun=$1
    suff=$2
    rett=$3
    lo="$4"
    hi="$5"
    suf2=""
    [[ "$suff" =~ .*_.* ]] && suf2=_$(cut -d_ -f2 <<< "$suff")
    [[ "$suff" =~ .*_.* ]] && suff=$(cut -d_ -f1 <<< "$suff")
    signed=1 && [[ "$suff" =~ u.* ]] && signed=0
    def="-DFunc=$1 -DSuffix=$suff -DTIMES=$TIMES -DSIGNED=$signed -DRET=$rett -DSuf2=$suf2"

    echo "Func: $fun$suff $lo ... $hi def=$def"

    copt="-mmcu=$MCU -Os -std=gnu99 -Wall -Werror"

    # Get cyc_avr, cyc_max, d_max.
    aopt="-I$AVRTEST_HOME"
    exit_o="$AVRTEST_HOME/exit-$MCU.o"
    $CC bench.c -fmax-errors=1 -o $elf $copt $def $aopt $exit_o $CRT $LIBS \
	|| exit 1
    avr-objdump -d $elf > x.lst
    aout=$($avrtest $elf -args $lo $hi)
    #echo "aout=$aout"

    getval cyc_avr "$aout"
    getval cyc_max "$aout"
    getval d_max "$aout"

    # Get size
    sym="$fun$suff$suf2"
    [ $sym = sqrthr  ] && sym="__$sym"
    [ $sym = sqrtuhr ] && sym="__$sym"
    sopt="-nostartfiles"
    lopt="-Wl,-u,$sym -Wl,--defsym,main=0"

    echo "" | $CC -xc - -xnone -o $elf $copt $sopt $d1 $lopt $LIBS \
	|| exit 3
    avr-objdump -d $elf > y.lst
    size=$(avr-size $elf | grep $elf | awk '{ print $1 }')
    echo "size: $size; cyc: ($cyc_avr) $cyc_max; d_max: $d_max"

    echo -n "  <tr><td>\\c #$fun$suff$suf2 <td align='right'>$size" >> $out
    echo -n " <td>$lo <td>$hi" >> $out
    echo -n " <td align='right'>$cyc_avr" >> $out
    echo -n " <td align='right'>$cyc_max" >> $out
    echo    " <td>$d_max" >> $out
}

do_func_txt ()
{
    echo
    echo "== $1 =="

    # Line starts:
    # # -> Ignore (comment)
    # ! -> Eval
    # 1 -> Copy line to $out
    # None of these -> FUNCTION N_ARGS N_VALS*TIMES,X0,X1[,Y0,Y1]
    while read -r -u 11 p; do
	case "$p" in
	    "#"* | "" ) ;;
	    !*) eval $(echo "$p" | cut -c 2-) || exit 2 ;;
	    1* ) cut -c 2- <<< "$p" >> $out ;;
	    *)
		set_libs_crt $MCU
		fun_line $p
		;;
	esac
    done 11<$1
}

#set -x

b="${builddir+builddir=$builddir }"
c="" && [ $CC != avr-gcc ] && c="CC=$CC "
t="" && [ $TIMES != 1 ] && t="TIMES=$TIMES "
B="" && [ $BASE != fxlib ] && B="BASE=$BASE "

cat <<EOF > $out
/* Auto-generated file.  DO NOT EDIT, OR YOUR CHANGES WILL BE LOST!
   This file has been auto-generated by:
   $ ${c}${b}${t}${B}$0 $*
*/

/**
EOF

for f in $*; do
    fil="$BASE-$f.txt"
    [ -f "$fil" ] || Err "$fil: not found"

    do_func_txt $fil
done

cat <<EOF >> $out
*/
EOF

echo "== $out =="
cat $out

rm -f -- *.lst *.elf
