#! /bin/sh

hextodec () {
    ( echo ibase=16; \
      ( echo $1 | sed -e s/0x//g -e y/abcdef/ABCDEF/ ) ) | bc
}

convyrange () {
    FROM=`echo $1 | sed -e 's/^\(.*\):.*/\1/'`
    FROM=`hextodec $FROM`
    TO=`echo $1 | sed -e 's/^[^:]*:\(.*\)/\1/'`
    TO=`hextodec $TO`
    echo "[$FROM.0:$TO.0]"
}

usage () {
    cat <<EOF
Usage: $0 [OPTION]... < TRACEFILE

  -A PREFIX    process the address range which has PREFIX
  -a           just print the range information and exit
  -c NAME      generate command file NAME.cmd and data file NAME.dat
                 for gnuplot
  -o FILE.EXT  output file (EXT should be one of: eps, png, pbm)
                 'tmp.eps' if not given
  -x FROM:TO   clock range
  -y FROM:TO   address range in hex (0x08082290:0x08083a00, for example)
  -X NUM       change x-tics
               
  -h           display this help and exit
EOF
}

PREFIX=
OUTFILE='tmp.eps'
XRANGE=\#
YRANGE=\#
SIM=smatsim
XTICS=\#
LINESTYLE=linestyle
while [ x"$1" != x ]; do
    case $1 in
    -A) PREFIX=$2; shift; shift; continue;;
    -a) RANGEONLY=y; shift; continue;;
    -c) CMDFILE=$2; shift; shift; continue;;
    -h) usage; exit 0;;
    -o) OUTFILE=$2; shift; shift; continue;;
    -x) X=`echo $2 | sed -e 's/^[0-9][0-9]*:[0-9][0-9]*$//g'`
        if [ x"$X" != x ]; then #if
            echo $0: invalid clock range $2 1>&2; exit 1
        fi
        XRANGE="[$2]"; shift; shift; continue;;
    -y) Y=`echo $2 | sed -e 's/^0x[a-f0-9][a-f0-9]*:0x[a-f0-9][a-f0-9]*$//g'`
        if [ x"$Y" != x ]; then
            echo $0: invalid address range $2 1>&2; exit 1
        fi
        YRANGEHEX="$2"; YRANGE=`convyrange $2`; shift; shift; continue;;
    -X) XTICS=$2; shift; shift; continue;;

    -m) MONO=y; shift; continue;;
    -s) SIM=$2; shift; shift; continue;;

    -*) echo $0: Try \`$0 -h\' for more information. 1>&2; exit 1;;
    *) break;;
    esac
done

if [ 0 -ne $# ]; then usage; exit 0; fi

# adhoc version check to distinguish "set linestyle" and "set style line"
if [ ! -x `which gnuplot 2>/dev/null` ]; then
    echo cannot find gnuplot 1>&2; exit 1
fi
BINARY=`which gnuplot`
if strings $BINARY | grep version\.c | grep 'v 1.4' >/dev/null; then
    LINESTYLE="style line"
fi

EXT=`echo "$OUTFILE" | sed -ne 's!^.*\.!!p'`
BASE=`echo "$OUTFILE" | sed -e 's!\.[^.]*$!!'`

if [ x"$EXT" = xeps ]; then
    TERMINAL="postscript eps color \"Helvetica\" 20"
    EXT_=eps
    STYLE_A="1 lt 1 pt 5 ps .8"
    STYLE_B="2 lt 9 pt 5 ps .2"
    if [ x"$MONO" = xy ]; then
        TERMINAL="postscript eps color \"Helvetica\" 20"
        EXT_=eps
        STYLE_A="1 lt 5 pt 5 ps .8"
        STYLE_B="2 lt 7 pt 5 ps .2"
    fi
elif [ x"$EXT" = xpbm -o x"$EXT" = xpng ]; then
    TERMINAL="pbm small color"
    EXT_=pbm
    STYLE_A="1 lt 1 pt 3 ps .5"
    STYLE_B="2 lt 0 pt 0 ps .2"
fi

if [ x"$XTICS" != x\# ]; then XTICS="set xtics $XTICS"; fi

TMPDIR=${TMP-/tmp}/smat$$
rm -rf $TMPDIR
mkdir $TMPDIR || exit 1
trap 'rm -rf $TMPDIR' 0 1 2 15

$SIM -g $TMPDIR/log >/dev/null || exit 1

DATFILE=$TMPDIR/a.out
smatrange <$TMPDIR/log >$DATFILE 2>$TMPDIR/range || exit 1

if [ x"$RANGEONLY" = xy ]; then
    cat <<EOF
The trace file contains the following address ranges.  To plot the
address range other than the first one, specify the first two digits
shown at the top of line to option -A, for example, "-A bf".

EOF
    awk '{ printf "     %s: %s-%s\n", $1, $2, $3;}' $TMPDIR/range
    exit 0
fi

if [ x"$YRANGE" = x\# ]; then
    if [ x"$PREFIX" = x ]; then
        YRANGE=`sed -n 1p $TMPDIR/range \
            | awk '{printf "[%u.0:%u.0]", $4, $5}'`
        YRANGEHEX=`sed -n 1p $TMPDIR/range \
            | awk '{printf "[%s:%s]", $2, $3}'`
        if [ x"$YRANGE" = x ]; then
            echo "$0: no traces to plot" 1>&2; exit 1
        fi
    else
        YRANGE=`grep -i 0x$PREFIX $TMPDIR/range \
            | awk '{printf "[%u.0:%u.0]", $4, $5}'`
        YRANGEHEX=`grep -i 0x$PREFIX $TMPDIR/range \
            | awk '{printf "[%s:%s]", $2, $3}'`
        if [ x"$YRANGE" = x ]; then
            echo "$0: no traces for address prefix $PREFIX" 1>&2; exit 1
        fi
    fi
fi

if [ x"$XRANGE" = x\# ]; then
    X1=`tail -1 $DATFILE | sed -e 's/ .*//'`
    XRANGE="[0:$X1]"
fi

if [ x"$CMDFILE" != x ]; then
    cp $TMPDIR/a.out $CMDFILE.dat || exit 1; DATFILE=$CMDFILE.dat
fi

cat <<EOF > $TMPDIR/cmd
set term $TERMINAL
set output "$BASE.$EXT_"
$XTICS
# Note YRANGE does not accept hexadecimal range nor even integral range
# for high address range.  So we use real number as YRANGE.
set xrange $XRANGE
set yrange $YRANGE # $YRANGEHEX
set nokey
set xlabel "Clock Cycles" 0,0.15
set ylabel "Address" 0.5,0
set format y ""
set rmargin 4
set $LINESTYLE $STYLE_A
set $LINESTYLE $STYLE_B
plot "$DATFILE" using 1:3 title "Misses" with points ls 1,\
     "$DATFILE" using 1:2 title "Hits" with points ls 2
EOF

if [ x"$CMDFILE" != x ]; then
    cp $TMPDIR/cmd $CMDFILE.cmd || exit 1; exit 0;
fi

gnuplot $TMPDIR/cmd

if [ x"$EXT" = xpng ]; then
    pnmtopng -compress 9 < $BASE.$EXT_ > $BASE.png 2>/dev/null \
        && ( echo generated $BASE.png; rm -f $BASE.$EXT_ ) \
        || ( echo $BASE.$EXT_: cannot convert to PNG format 1>&2; \
             rm -f $BASE.png )
else
    echo generated $BASE.$EXT_
fi
