#!/bin/bash # # Copyright 2015 Ettus Research # #---------------------------------------------------------------------------- # Global defaults #---------------------------------------------------------------------------- export VIV_PLATFORM=$(uname -o) # Vivado specific if [[ $VIV_PLATFORM = "Cygwin" ]]; then if [[ -d "/cygdrive/c/Xilinx/Vivado_Lab" ]]; then VIVADO_BASE_PATH="/cygdrive/c/Xilinx/Vivado_Lab" else VIVADO_BASE_PATH="/cygdrive/c/Xilinx/Vivado" fi MODELSIM_BASE_PATH="/cygdrive/c/mentor/modelsim" else if [[ -d "/tools/Xilinx/Vivado_Lab" ]]; then VIVADO_BASE_PATH="/tools/Xilinx/Vivado_Lab" elif [[ -d "/tools/Xilinx/Vivado" ]]; then VIVADO_BASE_PATH="/tools/Xilinx/Vivado" elif [[ -d "/opt/Xilinx/Vivado_Lab" ]]; then VIVADO_BASE_PATH="/opt/Xilinx/Vivado_Lab" else VIVADO_BASE_PATH="/opt/Xilinx/Vivado" fi MODELSIM_BASE_PATH="/opt/mentor/modelsim" fi function resolve_viv_path { if [[ $VIV_PLATFORM = "Cygwin" ]]; then echo $(cygpath -aw $1) else echo $1 fi } #---------------------------------------------------------------------------- # Help message display function #---------------------------------------------------------------------------- function setupenv_help { cat <] [--modelsim-path=] --vivado-path : Path to the base install directory for Xilinx Vivado (Default: /opt/Xilinx/Vivado or /opt/Xilinx/Vivado_Lab) --modelsim-path : Path to the base install directory for Modelsim (optional simulation tool) (Default: /opt/mentor/modelsim) --help -h : Shows this message. This script sets up the environment required to build FPGA images for the Ettus Research ${DISPLAY_NAME}. It will also optionally set up the the environment to run the Modelsim simulator (although this tool is not required). Required tools: Xilinx Vivado $VIVADO_VER (Synthesis and Simulation) Optional tools: Mentor Graphics Modelsim (Simulation) EOHELP } #---------------------------------------------------------------------------- # Validate prerequisites #---------------------------------------------------------------------------- # Ensure required variables if [ -z "$REPO_BASE_PATH" ]; then echo "ERROR: Please define the variable REPO_BASE_PATH before calling this script" return fi if [ -z "$VIVADO_VER" ]; then echo "ERROR: Please define the variable VIVADO_VER before calling this script" return fi if [ -z "$DISPLAY_NAME" ]; then echo "ERROR: Please define the variable DISPLAY_NAME before calling this script" return fi if [ ${#PRODUCT_ID_MAP[@]} -eq 0 ]; then echo "ERROR: Please define the variable PRODUCT_ID_MAP before calling this script" return fi # Ensure that the script is sourced directly or from another script, and not # executed. if [[ ${BASH_SOURCE[0]} == "$0" || ${BASH_SOURCE[1]} == "$0" ]]; then echo "ERROR: This script must be sourced." setupenv_help exit 1 fi #---------------------------------------------------------------------------- # Setup and parse command line #---------------------------------------------------------------------------- # Detect platform bitness if [ "$(uname -m)" = "x86_64" ]; then BITNESS="64" else BITNESS="32" fi # Go through cmd line options MODELSIM_REQUESTED=0 MODELSIM_FOUND=0 PARSE_STATE="" for i in "$@"; do case $i in -h|--help) setupenv_help return 0 ;; --vivado-path=*) VIVADO_BASE_PATH="${i#*=}" PARSE_STATE="" ;; --vivado-path) PARSE_STATE="vivado-path" ;; --vivado-version=*) VIVADO_USER_VER="${i#*=}" PARSE_STATE="" ;; --vivado-version) PARSE_STATE="vivado-version" ;; --modelsim-path=*) MODELSIM_BASE_PATH="${i#*=}" MODELSIM_REQUESTED=1 PARSE_STATE="" ;; --modelsim-path) PARSE_STATE="modelsim-path" ;; *) case $PARSE_STATE in vivado-path) VIVADO_BASE_PATH="$i" PARSE_STATE="" ;; vivado-version) VIVADO_USER_VER="$i" PARSE_STATE="" ;; modelsim-path) MODELSIM_BASE_PATH="$i" MODELSIM_REQUESTED=1 PARSE_STATE="" ;; *) echo "ERROR: Unrecognized option: $i" setupenv_help return 1 ;; esac ;; esac done # Vivado environment setup if [[ ${VIVADO_VER^^} = "CMDLINE_ARG" ]]; then if [[ -z $VIVADO_USER_VER ]]; then echo "ERROR: The --vivado-version argument must be specified when the env version is \"CMDLINE_ARG\"" return 1 else VIVADO_VER=$VIVADO_USER_VER fi fi export VIVADO_PATH=$VIVADO_BASE_PATH/$VIVADO_VER echo "Setting up a ${BITNESS}-bit FPGA build environment for the ${DISPLAY_NAME}..." #---------------------------------------------------------------------------- # Prepare Vivado environment #---------------------------------------------------------------------------- if [ -d "$VIVADO_PATH/bin" ]; then echo "- Vivado: Found ($VIVADO_PATH/bin)" else echo "- Vivado: Version $VIVADO_VER not found in $VIVADO_BASE_PATH (ERROR.. Builds and simulations will not work)" if [[ -z $VIVADO_USER_VER ]]; then echo " Use the --vivado-path option to override the search path" else echo " Use the --vivado-path option to override the search path or specify the correct --vivado-version" fi unset VIVADO_USER_VER return 1 fi $VIVADO_PATH/settings${BITNESS}.sh if [[ -e $VIVADO_PATH/.settings${BITNESS}-Vivado_Lab.sh ]]; then $VIVADO_PATH/.settings${BITNESS}-Vivado_Lab.sh else $VIVADO_PATH/.settings${BITNESS}-Vivado.sh fi if [[ -e $(readlink -f $VIVADO_BASE_PATH/..)/DocNav/.settings${BITNESS}-DocNav.sh ]]; then $(readlink -f $VIVADO_BASE_PATH/..)/DocNav/.settings${BITNESS}-DocNav.sh fi if [[ -x `which tput 2>/dev/null` ]] ; then export VIV_COLOR_SCHEME=default fi VIVADO_EXEC="$REPO_BASE_PATH/tools/scripts/launch_vivado.sh" # If an extended (i.e. full) version is provided, use Vivado to check # that the installed version is correct. # This optional env variable may be used to check for specific Vivado # Updates or Patches to be installed. # If multiple patches are installed, it is recommended that the user # runs 'vivado -version' from the installation directory to determine # the order in which patches were applied by Vivado. # Example: # VIVADO_VER=2019.1 # VIVADO_VER_FULL=2019.1.1_AR73068 # The setupenv.sh script will setup Vivado 2019.1, but it will also # verify that both Update 1 and patch AR73068 are installed. if [[ -n $VIVADO_VER_FULL ]]; then INSTALLED_VIV=$($VIVADO_PATH/bin/vivado -version | grep $VIVADO_VER_FULL) if [[ $? -eq 0 ]]; then echo " Installed version is $INSTALLED_VIV" else echo "- Vivado: ERROR! Requested version ($VIVADO_VER_FULL) not installed." echo " Install the required updates/patches and verify that the env variable" echo " \"VIVADO_VER_FULL\" matches the version printed by \"vivado -version\"." return 1 fi fi #---------------------------------------------------------------------------- # Prepare Modelsim environment #---------------------------------------------------------------------------- if [[ -d $MODELSIM_BASE_PATH ]]; then if [[ $VIV_PLATFORM = "Cygwin" ]]; then VSIM_PATH=$(find -L $MODELSIM_BASE_PATH -maxdepth 3 -wholename '*win*/vsim.exe' | head -n 1) else VSIM_PATH=$(find -L $MODELSIM_BASE_PATH -maxdepth 3 -wholename '*linux*/vsim' | head -n 1) fi fi if [[ $VSIM_PATH ]]; then if [[ $($VSIM_PATH -version) =~ .*ModelSim[[:space:]](.+)[[:space:]]vsim.* ]]; then MODELSIM_VER=${BASH_REMATCH[1]} MODELSIM_PATH=$(dirname $VSIM_PATH) fi case $MODELSIM_VER in DE-64|SE-64) export MODELSIM_64BIT=1 if [[ -z $MSIM_VIV_COMPLIBDIR ]]; then export SIM_COMPLIBDIR=$VIVADO_PATH/modelsim64 else export SIM_COMPLIBDIR=$MSIM_VIV_COMPLIBDIR fi ;; DE|SE|PE) export MODELSIM_64BIT=0 if [[ -z $MSIM_VIV_COMPLIBDIR ]]; then export SIM_COMPLIBDIR=$VIVADO_PATH/modelsim32 else export SIM_COMPLIBDIR=$MSIM_VIV_COMPLIBDIR fi ;; *) ;; esac # If MSIM_MODELSIM_INI is not defined, use the modelsim.ini in the compiled # libraries directory. Otherwise use the one defined by MSIM_MODELSIM_INI. # Set MSIM_MODELSIM_INI to an empty string to use the modelsim.ini in the # ModelSim installation folder. if [[ ! -v MSIM_MODELSIM_INI ]]; then export MODELSIM_INI=$SIM_COMPLIBDIR/modelsim.ini fi fi function build_simlibs { mkdir -p $SIM_COMPLIBDIR pushd $SIM_COMPLIBDIR CMD_PATH=`mktemp XXXXXXXX.vivado_simgen.tcl` if [[ $MODELSIM_64BIT -eq 1 ]]; then echo "compile_simlib -force -simulator modelsim -family all -language all -library all -directory $SIM_COMPLIBDIR" > $CMD_PATH else echo "compile_simlib -force -simulator modelsim -family all -language all -library all -32 -directory $SIM_COMPLIBDIR" > $CMD_PATH fi $VIVADO_EXEC -mode batch -source $(resolve_viv_path $CMD_PATH) -nolog -nojournal rm -f $CMD_PATH popd } if [[ $MODELSIM_VER ]]; then echo "- Modelsim: Found ($MODELSIM_VER, $MODELSIM_PATH)" if [[ -e "$SIM_COMPLIBDIR/modelsim.ini" ]]; then echo "- Modelsim Compiled Libs: Found ($SIM_COMPLIBDIR)" else echo "- Modelsim Compiled Libs: Not found! (Run build_simlibs to generate them.)" fi else if [[ $MODELSIM_REQUESTED -eq 1 ]]; then echo "- Modelsim: Not found in $MODELSIM_BASE_PATH (WARNING.. Simulations with vsim will not work)" fi fi #---------------------------------------------------------------------------- # Misc export variables #---------------------------------------------------------------------------- export PATH=$(echo ${PATH} | tr ':' '\n' | awk '$0 !~ "/Vivado/"' | paste -sd:) export PATH=${PATH}:$VIVADO_PATH:$VIVADO_PATH/bin:$VIVADO_HLS_PATH:$VIVADO_HLS_PATH/bin:$MODELSIM_PATH for prod in "${!PRODUCT_ID_MAP[@]}"; do IFS='/' read -r -a prod_tokens <<< "${PRODUCT_ID_MAP[$prod]}" if [ ${#prod_tokens[@]} -eq 6 ]; then export XIL_ARCH_${prod}=${prod_tokens[0]} export XIL_PART_ID_${prod}=${prod_tokens[1]}/${prod_tokens[2]}/${prod_tokens[3]}/${prod_tokens[4]}/${prod_tokens[5]} elif [ ${#prod_tokens[@]} -eq 5 ]; then export XIL_ARCH_${prod}=${prod_tokens[0]} export XIL_PART_ID_${prod}=${prod_tokens[1]}/${prod_tokens[2]}/${prod_tokens[3]}/${prod_tokens[4]} elif [ ${#prod_tokens[@]} -eq 4 ]; then export XIL_ARCH_${prod}=${prod_tokens[0]} export XIL_PART_ID_${prod}=${prod_tokens[1]}/${prod_tokens[2]}/${prod_tokens[3]} else echo "ERROR: Invalid PRODUCT_ID_MAP entry: \"${PRODUCT_ID_MAP[$prod]}\". Must be ///[/[/]]." return 1 fi done #---------------------------------------------------------------------------- # Define IP management aliases #---------------------------------------------------------------------------- # Vivado specific VIV_IP_UTILS=$REPO_BASE_PATH/tools/scripts/viv_ip_utils.tcl function viv_create_ip { if [[ -z $1 || -z $2 || -z $3 || -z $4 ]]; then echo "Create a new Vivado IP instance and a Makefile for it" echo "" echo "Usage: viv_create_new_ip " echo "- : Name of the IP instance" echo "- : Base location for IP" echo "- : The vendor, library, name, and version (VLNV) string for the IP as defined by Xilinx" echo "- : Product to generate IP for. Choose from: ${!PRODUCT_ID_MAP[@]}" return 1 fi ip_name=$1 ip_dir=$(readlink -f $2) ip_vlnv=$3 part_name=$(python $REPO_BASE_PATH/tools/scripts/viv_gen_part_id.py "${PRODUCT_ID_MAP[$4]}") if [[ $? -ne 0 ]]; then echo "ERROR: Invalid product name $4. Supported: ${!PRODUCT_ID_MAP[@]}" return 1 fi if [[ -d $ip_dir/$ip_name ]]; then echo "ERROR: IP $ip_dir/$ip_name already exists. Please choose a different name." return 1 fi $VIVADO_EXEC -mode gui -source $(resolve_viv_path $VIV_IP_UTILS) -nolog -nojournal -tclargs create $part_name $ip_name $(resolve_viv_path $ip_dir) $ip_vlnv echo "Generating Makefile..." python3 $REPO_BASE_PATH/tools/scripts/viv_gen_ip_makefile.py --ip_name=$ip_name --dest=$ip_dir/$ip_name echo "Done generating IP in $ip_dir/$ip_name" } function viv_modify_ip { if [[ -z $1 ]]; then echo "Modify an existing Vivado IP instance" echo "" echo "Usage: viv_modify_ip " echo "- : Path to the IP XCI file." return 1 fi xci_path=$(readlink -f $1) part_name=$(python3 $REPO_BASE_PATH/tools/scripts/viv_ip_xci_editor.py read_part $xci_path) if [[ -z $part_name ]]; then echo "ERROR: Invalid part name $part_name. XCI parse error." return 1 fi if [[ -f $xci_path ]]; then $VIVADO_EXEC -mode gui -source $(resolve_viv_path $VIV_IP_UTILS) -nolog -nojournal -tclargs modify $part_name $(resolve_viv_path $xci_path) else echo "ERROR: IP $xci_path not found." return 1 fi } function viv_modify_bd { if [[ -z $1 || -z $2 ]]; then echo "Modify an existing Vivado Block Design instance" echo "" echo "Usage: viv_modify_bd " echo "- : Path to the BD file." echo "- : Product to generate IP for. Choose from: ${!PRODUCT_ID_MAP[@]}" return 1 fi bd_path=$(readlink -f $1) part_name=$(python $REPO_BASE_PATH/tools/scripts/viv_gen_part_id.py "${PRODUCT_ID_MAP[$2]}") if [[ $? -ne 0 ]]; then echo "ERROR: Invalid product name $2. Supported: ${!PRODUCT_ID_MAP[@]}" return 1 fi if [[ -f $bd_path ]]; then $VIVADO_EXEC -mode gui -source $(resolve_viv_path $VIV_IP_UTILS) -nolog -nojournal -tclargs modify $part_name $(resolve_viv_path $bd_path) else echo "ERROR: IP $bd_path not found." return 1 fi } function viv_modify_tcl_bd { if [[ -z $1 || -z $2 ]]; then echo "Modify an existing Vivado TCL-based Block Design instance." echo "" echo "Usage: viv_modify_bd_tcl " echo "- : Path to the TCL source file." echo "- : Product to generate IP for. Choose from: ${!PRODUCT_ID_MAP[@]}" return 1 fi src_path=$(readlink -f $1) part_name=$(python $REPO_BASE_PATH/tools/scripts/viv_gen_part_id.py "${PRODUCT_ID_MAP[$2]}") if [[ $? -ne 0 ]]; then echo "ERROR: Invalid product name $2. Supported: ${!PRODUCT_ID_MAP[@]}" return 1 fi bd_ip_repo="${src_path%/top*}/lib/vivado_ipi" if [[ -f $src_path ]]; then $VIVADO_EXEC -mode gui -source $(resolve_viv_path $VIV_IP_UTILS) -nolog -nojournal -tclargs modify_bdtcl $part_name $(resolve_viv_path $src_path) $(resolve_viv_path $bd_ip_repo) echo "INFO: Vivado BD was closed, writing source TCL..." $VIVADO_EXEC -mode batch -source $(resolve_viv_path $VIV_IP_UTILS) -nolog -nojournal -tclargs write_bdtcl $part_name $(resolve_viv_path $src_path) else echo "ERROR: IP $src_path not found." return 1 fi } function viv_ls_ip { if [[ -z $1 ]]; then echo "List the items in the Vivado IP catalog" echo "" echo "Usage: viv_ls_ip " echo "- : Product to generate IP for. Choose from: ${!PRODUCT_ID_MAP[@]}" return 1 fi part_name=$(python $REPO_BASE_PATH/tools/scripts/viv_gen_part_id.py "${PRODUCT_ID_MAP[$1]}") if [[ $? -ne 0 ]]; then echo "ERROR: Invalid product name $1. Supported: ${!PRODUCT_ID_MAP[@]}" return 1 fi $VIVADO_EXEC -mode batch -source $(resolve_viv_path $VIV_IP_UTILS) -nolog -nojournal -tclargs list $part_name | grep -v -E '(^$|^#|\*\*)' test ${PIPESTATUS[0]} -eq 0 } function viv_upgrade_ip { if [[ -z $1 ]]; then echo "Upgrade one or more Xilinx IP targets" echo "" echo "Usage: viv_upgrade_ip [--recursive]" echo "- : Path to the IP XCI file." return 1 fi max_depth="-maxdepth 1" if [[ $2 == "--recursive" ]]; then max_depth="" fi search_path=$(readlink -f $1) IFS='' read -r -a xci_files <<< $(find $search_path $max_depth | grep .xci | xargs) for xci_path in $xci_files; do if [[ -f $xci_path ]]; then echo "Upgrading $xci_path..." part_name=$(python3 $REPO_BASE_PATH/tools/scripts/viv_ip_xci_editor.py read_part $xci_path) $VIVADO_EXEC -mode batch -source $(resolve_viv_path $VIV_IP_UTILS) -nolog -nojournal -tclargs upgrade $part_name $(resolve_viv_path $xci_path) | grep -v -E '(^$|^#|\*\*)' test ${PIPESTATUS[0]} -eq 0 else echo "ERROR: IP $xci_path not found." return 1 fi done } #---------------------------------------------------------------------------- # Define hardware programming aliases #---------------------------------------------------------------------------- VIV_HW_UTILS=$REPO_BASE_PATH/tools/scripts/viv_hardware_utils.tcl function viv_hw_console { vivado -mode tcl -source $(resolve_viv_path $VIV_HW_UTILS) -nolog -nojournal } function viv_jtag_list { $VIVADO_EXEC -mode batch -source $(resolve_viv_path $VIV_HW_UTILS) -nolog -nojournal -tclargs list | grep -v -E '(^$|^#|\*\*)' test ${PIPESTATUS[0]} -eq 0 } function viv_jtag_program { if [[ -z $1 ]]; then echo "Downloads a bitfile to an FPGA device using Vivado" echo "" echo "Usage: viv_jtag_program [ = .] [ = 0:0]" echo "- : Path to a .bit FPGA configuration file" echo "- : Regular expression for filtering out devices by" echo " their FTDI serial" echo "- : Address to the device in the form :" echo " Run viv_jtag_list to get a list of connected devices" return 1 fi $VIVADO_EXEC -mode batch -source $(resolve_viv_path $VIV_HW_UTILS) -nolog -nojournal -tclargs program $* | grep -v -E '(^$|^#|\*\*)' test ${PIPESTATUS[0]} -eq 0 } function probe_bitfile { if [[ -z $1 ]]; then echo "Probe a Xilinx bit file and report header information" echo "" echo "Usage: probe_bitfile " echo "- : Path to a .bit FPGA configuration file" return 1 fi python3 $REPO_BASE_PATH/tools/scripts/xil_bitfile_parser.py --info $1 } echo echo "Environment successfully initialized." return 0