#!/bin/sh

# Script front-end for cec, the Columbia Esterel Compiler

# set -x # enable script debugging

version="CEC The Columbia Esterel Compiler version 0.3"

prefix=/usr
exec_prefix=/usr

# Directory in which the executables reside
EXEDIR=/usr/bin

STRLXML=${EXEDIR}/cec-strlxml
XMLSTRL=${EXEDIR}/cec-xmlstrl
EXPANDMOD=${EXEDIR}/cec-expandmodules
DISMANTLE=${EXEDIR}/cec-dismantle
ASTGRC=${EXEDIR}/cec-astgrc
GRCOPT=${EXEDIR}/cec-grcopt
GRCPDG=${EXEDIR}/cec-grcpdg
PDGBLIF=${EXEDIR}/cec-pdgblif
SMBLIF=${EXEDIR}/cec-smblif
BLIFUTIL=${EXEDIR}/cec-blifutil
GRCC=${EXEDIR}/cec-grcc2

Usage() {
    echo "Usage: $0 [options] <.strl file> | <.sm file>

Overall options:

-v --verbose   Enable verbose mode
--version      Print version information
-h --help      Print this help message

-B <basename>  Set the basename of the generated files
-D <directory> Set the directory in which files will be placed
--logfile <file> Specify a logfile
-K             Keep all intermediate files
--keep <ext>   Keep intermediate files of the given extension
--eachcmd <cmd>   Preface each command with <cmd> e.g., --eachcmd time
--pdgblifargs <args>  Supply the pdgblif pass with these extra arguments
-s             Do modified schizophrenic expansion (experimental)

C generation options:

-c             Generate a .c source file (default)
-a             Generate ANSI compliant C (default)
-g             Generate C that uses the GCC computed goto extension (faster)

Circuit generation options: 

--blif         Generate a BLIF circuit file
--verilog      Generate a Verilog circuit file
--sm           Generate an .sm state machine file
--sis          Run sis to optimize BLIF output
--sis-script <script> Run this sis script (script.rugged by default)
" 1>&2

    exit 1
}

# Convert an .strl file to an optimized GRC file

StrlGRC() {
    Run $STRLXML $1 $astfile &&
    Run $EXPANDMOD $astfile $expfile &&
    Run $DISMANTLE $expfile $disfile &&
    Run "$ASTGRC $astgrcargs" $disfile $grcfile &&
    Run $GRCOPT $grcfile $optfile
}

# If requested, run the sis logic optimizer on the unoptimized BLIF file

RunSis() {
    RunVerb mv $bliffile ${unopt_bliffile}
    RunVerb sis -t blif -T blif -c "\"source $sisscript\"" \
	-o $bliffile ${unopt_bliffile}
}

# Once an SM file exists, combine it with an existing .blif file
# and generate a BLIF file

SMBLIF() {
    RunVerb $SMBLIF $smfile $sm_bliffile &&
    RunVerb sed '/^[.]end/d' $core_bliffile ">" $bliffile &&
    RunVerb cat $sm_bliffile ">>" $bliffile &&
    RunVerb echo ".end" ">>" $bliffile &&
    if [ $sis -eq 1 ] ; then
	RunSis
    fi
}

# Return the value of the variable whose name is the first argument
# so if foo=bar, `Val $foo` returns the value of variable bar
Val() {
    eval expr \$$1
}

# Run the given command, printing it if requested and writing it and
# its standard error to a logfile if one is given
# Special characters can be escaped so
#   RunVerb echo foo ">" bar
# writes to a file called bar
RunVerb() {
    if [ $verbose -ne 0 ] ; then
	echo $*
    fi
    if [ ! -z "$logfile" ] ; then
	echo $* >> $logfile
	logredir="2>> $logfile" ; # send stderr to the logfile
    else
	logredir=""
    fi
    eval $eachcmd $* $logredir || {
	echo "FAILURE: $1 terminated"
	return 1
    }
    return 0
}

# Run <executable> <infile> <outfile>
Run() {
    RunVerb $1 "<" $2 ">" $3
}

# Calculate all the filename variables
# DefineFilenames <basename>
DefineFilenames() {
    for ext in $extensions ; do
	eval ${ext}file=$1.`echo $ext | sed s/_/./`
    done
}

extensions="ast exp dis grc opt pdg top_v core_blif sm sm_blif blif unopt_blif v c"

# Keep none of the files by default
for ext in $extensions ; do
    eval keep${ext}=0
done

commandline="$0 $*"

verbose=0
sis=0
basename=""
directory=""
sisscript="script.rugged"
logfile=""
output="c"
eachcmd=""
pdgblifargs=""
strlfile=""
suppliedsmfile=""
astgrcargs=""
ansiargs="-a"

while [ $# -ne 0 ] ; do
    case x"$1" in
	x-K) # Keep all intermediate files
	    for ext in $extensions ; do
		eval keep${ext}=1
	    done
	    shift
	    ;;
	x--keep) # Keep a prescribed intermediate file
	    shift
	    if [ $# -eq 0 ] ; then
		echo "--keep extension must be one of `echo $extensions | sed s/[_]/./g`" 1>&2
		Usage
	    fi
	    ext=`echo $1 | sed 's/[.]/_/'`
	    echo $extensions | grep -q $ext || {
		echo "Unrecognized --keep extension \"$1\"" 1>&2
		echo "Must be one of `echo $extensions | sed s/[_]/./g`" 1>&2
		exit 1
	    }
	    eval keep${ext}=1
	    shift
	    ;;
	x-B) # Set the basename
	    shift
	    if [ $# -eq 0 ] ; then Usage ; fi
	    basename="$1"
	    shift
	    ;;
	x-D) # Set the destination directory
	    shift
	    if [ $# -eq 0 ] ; then Usage ; fi
	    # Strip off any trailing slashes from the directory name, then
	    # add one
	    directory=`echo $1 | sed 's/\\/\$//'`/
	    shift
	    ;;
	x-v | x--verbose) # Set verbose mode
	    verbose=1
	    shift
	    ;;
	x--version) # Print the version number
	    echo $version
	    exit 1
	    ;;
	x--sis) # Enable sis optimization
	    sis=1
	    shift
	    ;;
	x--sis-script) # Specify the SIS optimization script
	    shift
	    if [ $# -eq 0 ] ; then Usage ; fi
	    sisscript="$1"
	    sis=1
	    shift
	    ;;
	x--logfile) # Specify a logfile
	    shift
	    if [ $# -eq 0 ] ; then Usage ; fi
	    logfile="$1"
	    shift
	    ;;
	x--blif) # Specify BLIF output
	    output="blif"
	    shift
	    ;;
	x--verilog) # Specify Verilog output
	    output="verilog"
	    shift
	    ;;
	x--sm) # Specify .sm file output
	    output="sm"
	    shift
	    ;;
	x-c) # Specify .c file output
	    output="c"
	    shift
	    ;;
	x-a) # Specify ANSI C output
	    ansiargs="-a"
	    shift
	    ;;
	x-g) # Specify GCC computed goto output
	    ansiargs=""
	    shift
	    ;;
	x--eachcmd) # Specify a time command
	    shift
	    if [ $# -eq 0 ] ; then Usage ; fi
	    eachcmd="$1"
	    shift
	    ;;
        x-s) # Specify different schizophrenic expansion
	    shift
	    astgrcargs="-s"
	    ;;
	x--pdgblifargs) # Specify extra commands for pdgblif
	    shift 
	    if [ $# -eq 0 ] ; then Usage ; fi
	    pdgblifargs="$pdgblifargs $1"
	    shift
	    ;;
	x-h | x--help) # Help
	    Usage
	    ;;
	x-*) # Unrecognized option
	    echo "Unrecognized option \"$1\"" 1>&2
	    Usage
	    ;;
	x*.strl) # argument ending in .strl: an .strl source file
	    strlfile="$1"
	    shift
	    ;;
	x*.sm) # argument ending in .sm: an .sm file
	    suppliedsmfile="$1"
	    shift
	    ;;
	*) # something else unrecognized
	    echo "Unrecognized file type \"$1\"" 1>&2
	    Usage
	    ;;
    esac
done

if [ ! -z "$logfile" ] ; then
    echo $version > $logfile
    echo $commandline >> $logfile
fi

if [ -z "$strlfile" -a -z "$suppliedsmfile" ] ; then
    # Should have at least one source file
    Usage
fi

if [ -z "$basename"] ; then
    # basename is the name of the first source file
    basename=`echo $strlfile | sed 's/ .*$//
                                      s/.*\\///
                                      s/.strl//'`
fi

if [ $output == "verilog" ] ; then
    pdgblifargs="$pdgblifargs --verilog $top_vfile"
fi

DefineFilenames ${directory}${basename}

if [ ! -z "$strlfile" ] ; then
    if [ ! -f $strlfile ] ; then
	echo "$strlfile: No such file or directory" 1>&2
	exit 1
    fi &&
    StrlGRC $strlfile &&
    case "$output" in
	sm)
	    Run $GRCPDG $optfile $pdgfile 
	    RunVerb $PDGBLIF --sm $smfile --verilog $top_vfile \
               "<" $pdgfile ">" $core_bliffile &&
	    keepsm=1 &&
	    keepcore_blif=1 &&
	    keeptop_v=1
	    ;;
	blif)
	    Run $GRCPDG $optfile $pdgfile 
	    RunVerb $PDGBLIF --sm $smfile "<" $pdgfile ">" $core_bliffile &&
	    SMBLIF &&
	    keepblif=1
	    ;;
	verilog)
	    Run $GRCPDG $optfile $pdgfile 
	    RunVerb $PDGBLIF --sm $smfile --verilog $top_vfile \
                "<" $pdgfile ">" $core_bliffile &&
	    SMBLIF &&
	    RunVerb $BLIFUTIL -v "<" $bliffile ">" $vfile &&
	    keepv=1 &&
	    keeptop_v=1
	    ;;
	c)
	    Run "$GRCC -B $basename $ansiargs" $optfile $cfile
	    keepc=1
	    ;;
    esac
fi

if [ -z "$basename" ] ; then
    basename=`echo $suppliedsmfile | sed 's/ .*$//
                                      s/.*\\///
                                      s/.sm//'`
fi

if [ ! -z "$suppliedsmfile" ] ; then
    keepsm=1
    DefineFilenames ${directory}${basename}
    smfile="$suppliedsmfile" ; # only interesting if a basename was supplied
    if [ ! -f $core_bliffile ] ; then
	echo "$core_bliffile: No such file or directory" 1>&2
	exit 1
    fi &&
    case "$output" in
	blif)
	    SMBLIF &&
	    keepblif=1
	    ;;
	verilog)
	    SMBLIF &&
	    RunVerb $BLIFUTIL -v "<" $bliffile ">" $vfile &&
	    keepv=1 &&
	    keeptop_v=1
	    ;;
    esac
fi

# Delete all the unkept files
for ext in $extensions ; do
    if [ `Val keep${ext}` -eq 0 ] ; then
	rm -f `Val ${ext}file`
    fi
done

exit 0
