#!/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 NCVerilog 05.30-p001

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

if [ "$BSC_COMMAND" = "detect" ]; then
# detect whether the command "ncverilog" is in the path
  SIM_NAME=ncverilog
  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

# name of NC Verilog work directory
snapshot="snap_$BSC_TOPLEVEL_MODULE"
inca_libs="INCA_libs_$BSC_TOPLEVEL_MODULE"

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

# No longer support 32-bit
IS64=64
if [ "${IS64}" != "" ]; then
    ARCH_OPT="+nc64bit"
else
    ARCH_OPT=""
fi

# include VPI modules if supplied
if [ -n "$BSC_VPI_FILES" ]; then
  if [ "$USEDPI" = "yes" ] ; then
    echo "ERROR: NCVerilog 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="+access+r +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

# compile Verilog files
if [ "$VERBOSE" = "yes" ]; then
  NC_VERBOSE=""
  echo "exec: ncverilog $ARCH_OPT -c +access+r +name+$snapshot +nclibdirname+$inca_libs +libext+.v $VSIM_PATH_FLAGS $BSC_VSIM_FLAGS +define+TOP=$BSC_TOPLEVEL_MODULE $BSC_VERILOG_DEFS $BSC_VERILOG_OPTS +nowarn+LIBNOU $VPI_LINK $BSC_VERILOG_FILES"
else
  NC_VERBOSE="-q"
fi
ncverilog $NC_VERBOSE $ARCH_OPT -c +access+r +name+$snapshot +nclibdirname+$inca_libs +libext+.v $VSIM_PATH_FLAGS $BSC_VSIM_FLAGS +define+TOP=$BSC_TOPLEVEL_MODULE $BSC_VERILOG_DEFS $BSC_VERILOG_OPTS +nowarn+LIBNOU $VPI_LINK $BSC_VERILOG_FILES
status=$?
if [ "$status" != "0" ]; then
    echo "ERROR: cannot compile Verilog files" >&2
    exit $status
fi

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

# generate a "simulator executable" shell script
echo '#!/bin/sh' > $BSC_SIM_EXECUTABLE
echo "ncverilog -q -R $ARCH_OPT +name+$snapshot +nclibdirname+$inca_libs \$*" >> $BSC_SIM_EXECUTABLE
echo 'status=$?' >> $BSC_SIM_EXECUTABLE
echo 'if [ "$status" != "0" ]; then' >> $BSC_SIM_EXECUTABLE
echo '    echo "ERROR: cannot simulate design" >&2' >> $BSC_SIM_EXECUTABLE
echo '    exit $status' >> $BSC_SIM_EXECUTABLE
echo 'fi' >> $BSC_SIM_EXECUTABLE
chmod +x $BSC_SIM_EXECUTABLE
