#!/bin/sh

# simulator builder script
#
# warning: this MUST NOT be called directly by the user
#
# bsc invokes
#   bsc_build_vsim_... detect
# to detect whether this simulator can be built (exit status 0 = yes)
#
# bsc invokes
#   bsc_build_vsim_... link outexe topmod clibpath clibs linkopts vdirs vdefs vopts vfiles ofiles
# where
#   outexe   - the name of the simulator executable to create
#   topmod   - the toplevel module to simulate
#   clibpath - where to find external C libraries
#   clibs    - which external C libraries to link in
#   linkopts - other options passed to C/C++ linker
#   vdirs    - -y directories to search for Verilog files
#   vdefs    - -D macro definitions
#   vopts    - other options passed to Verilog
#   vfiles   - the Verilog files to simulate
#   ofiles   - any VPI object files to link in
# exits with status 0 if it successfully built the simulator, 1 otherwise

# tested on cvc

# No longer support 32-bit
IS64=64
if [ "${IS64}" != ""  ] ; then
    ARCH_SUFFIX="64"
else
    ARCH_SUFFIX=""
fi
SIM_NAME=cvc${ARCH_SUFFIX}

BSC_COMMAND=$1           # "detect" or "link"

if [ "$BSC_COMMAND" = "detect" ]; then
# detect whether the command "cvc" or "cvc64" is in the path
  hash $SIM_NAME 2> /dev/null
  if [ "$?" != "0" ]; then
      echo "$SIM_NAME was not found"
      exit 1
  else
      FOUND_CMD=`which $SIM_NAME`
      echo "$SIM_NAME was found at $FOUND_CMD"
      exit 0
  fi
fi

# the only remaining command is "link"
if [ "$BSC_COMMAND" != "link" ]; then
  echo "ERROR: unknown command: $BSC_COMMAND" >&2
  exit 1
fi

BSC_SIM_EXECUTABLE=$2    # output executable filename
BSC_TOPLEVEL_MODULE=$3   # toplevel module to simulate

shift 3
BSC_VERILOG_FILES=""     # Verilog files to link
BSC_VERILOG_DIRS=""      # Verilog directories to link
BSC_VPI_FILES=""         # VPI object files to link in
BSC_C_LIB_PATH=""        # where to find C libraries for linking
BSC_C_LIBS=""            # which C files to link in
BSC_CLINK_OPTS=""        # C/C++ link options specified with -Xl in bsc
BSC_VERILOG_DEFS=""      # -D macro and -D macro=val to be passed to Verilog
BSC_VERILOG_OPTS=""      # Verilog link options specified with -Xv in bsc
BSC_OTHER_ARGUMENTS=""

VERBOSE="no"

USEDPI="no"

while [ $# -gt 0 ]; do
  if [ "${1%%.v}" != "$1" ]; then
    BSC_VERILOG_FILES="$BSC_VERILOG_FILES $1"
  elif [ "${1%%.V}" != "$1" ]; then
    BSC_VERILOG_FILES="$BSC_VERILOG_FILES $1"
  elif [ "${1%%.vo}" != "$1" ]; then
    BSC_VERILOG_FILES="$BSC_VERILOG_FILES $1"
  elif [ "${1%%.sv}" != "$1" ]; then
    BSC_VERILOG_FILES="$BSC_VERILOG_FILES $1"
  elif [ "${1%%.o}" != "$1" ]; then
    BSC_VPI_FILES="$BSC_VPI_FILES $1"
  elif [ "$1" = "-L" ]; then
    shift 1
    BSC_C_LIB_PATH="$BSC_C_LIB_PATH -L$1"
  elif [ "$1" = "-y" ]; then
    shift 1
    BSC_VERILOG_DIRS="$BSC_VERILOG_DIRS -y $1"
  elif [ "$1" = "-l" ]; then
    shift 1
    BSC_C_LIBS="$BSC_C_LIBS -l$1"
  elif [ "$1" = "-Xl" ]; then
    shift 1
    BSC_CLINK_OPTS="$BSC_CLINK_OPTS $1"
  elif [ "$1" = "-D" ]; then
    shift 1
    BSC_VERILOG_DEFS="$BSC_VERILOG_DEFS +define+$1"
  elif [ "$1" = "-Xv" ]; then
    shift 1
    BSC_VERILOG_OPTS="$BSC_VERILOG_OPTS $1"
  elif [ "$1" = "-verbose" ]; then
    VERBOSE="yes"
  elif [ "$1" = "-dpi" ]; then
    USEDPI="yes"
  else
    BSC_OTHER_ARGUMENTS="$BSC_OTHER_ARGUMENTS $1";
  fi
  shift 1
done

if [ -z "$BSC_SIM_EXECUTABLE" ]; then
  echo "ERROR: simulator executable filename not specified"
  exit 1
fi

if [ -z "$BSC_TOPLEVEL_MODULE" ]; then
  echo "ERROR: no top-level module specified" >&2
  exit 1
fi

if [ -z "$BSC_VERILOG_FILES" ]; then
  echo "ERROR: no Verilog files to link" >&2
  exit 1
fi

if [ -n "$BSC_OTHER_ARGUMENTS" ]; then
  echo "ERROR: unrecognized arguments '$BSC_OTHER_ARGUMENTS'" >&2
  exit 1
fi

# include VPI modules if supplied
if [ -n "$BSC_VPI_FILES" ]; then
  if [ "$USEDPI" = "yes" ] ; then
    echo "ERROR: CVC linking does not yet support DPI."
    echo "       Compile and link without the -use-dpi flag."
    exit 1
  fi
  ## If CXX is set, use that.  Otherwise just use c++
  if [ "$CXX" = "" ]
  then
    CXX=c++
  fi
  VPI_LINK="+acc +loadvpi=./directc_$BSC_TOPLEVEL_MODULE.so:vpi_register_all"
  LDFLAGS="$LDFLAGS $BSC_LDFLAGS"
  SHARED=`$BLUESPECDIR/exec/platform.sh c++_shared_flags`
  if [ "$VERBOSE" = "yes" ]; then
      echo "exec: $CXX -v $LDFLAGS $SHARED -o directc_$BSC_TOPLEVEL_MODULE.so -Wl,-rpath,$BLUESPECDIR/VPI -L$BLUESPECDIR/VPI $BSC_VPI_FILES -lbdpi $BSC_C_LIB_PATH $BSC_C_LIBS $BSC_CLINK_OPTS"
      CXX_VERBOSE="-v"
  else
      CXX_VERBOSE=""
  fi
  $CXX $CXX_VERBOSE $LDFLAGS $SHARED -o directc_$BSC_TOPLEVEL_MODULE.so -Wl,-rpath,$BLUESPECDIR/VPI -L$BLUESPECDIR/VPI $BSC_VPI_FILES -lbdpi $BSC_C_LIB_PATH $BSC_C_LIBS $BSC_CLINK_OPTS
else
  VPI_LINK=""
fi

# path to Verilog files
VSIM_PATH_FLAGS=$BSC_VERILOG_DIRS

rm -f $BSC_SIM_EXECUTABLE
status=$?
if [ "$status" != "0" ]; then
    echo "ERROR: cannot create $BSC_SIM_EXECUTABLE" >&2
    exit $status
fi

# compile Verilog files
if [ "$VERBOSE" = "yes" ]; then
  CVC_VERBOSE=""
  echo "exec: $SIM_NAME -o $BSC_SIM_EXECUTABLE +libext+.v $VSIM_PATH_FLAGS $BSC_VSIM_FLAGS +define+TOP=$BSC_TOPLEVEL_MODULE $BSC_VERILOG_DEFS $BSC_VERILOG_OPTS $VPI_LINK $BSC_VERILOG_FILES"
else
  CVC_VERBOSE="-q"
fi
$SIM_NAME $CVC_VERBOSE -o $BSC_SIM_EXECUTABLE +libext+.v $VSIM_PATH_FLAGS $BSC_VSIM_FLAGS +define+TOP=$BSC_TOPLEVEL_MODULE $BSC_VERILOG_DEFS $BSC_VERILOG_OPTS $VPI_LINK $BSC_VERILOG_FILES
status=$?
if [ "$status" != "0" ]; then
    echo "ERROR: cannot compile Verilog files" >&2
    exit $status
fi
