| #!/usr/bin/env bash |
| # |
| # Copyright (C) 2020-2022 F4PGA Authors. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # https://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| # SPDX-License-Identifier: Apache-2.0 |
| |
| set -e |
| |
| VERSION="v2.0.1" |
| |
| if [ ! -n $1 ]; then |
| echo "Please enter a valid command: Refer help ql_symbiflow --help" |
| exit 1 |
| elif [[ $1 == "-synth" || $1 == "-compile" ]]; then |
| echo -e "----------------- \n" |
| elif [[ $1 == "-h" || $1 == "--help" ]];then |
| echo -e "\nBelow are the supported commands: \n\ |
| To synthesize and dump a eblif file:\n\ |
| \t>ql_symbiflow -synth -src <source_dir path> -d <device> -P <pinmap csv file> -t <top module name> -v <verilog file/files> -p <pcf file>\n\ |
| To run synthesis, pack, place and route:\n\ |
| \t>ql_symbiflow -compile -src <source_dir path> -d <device> -P <pinmap csv file> -t <top module name> -v <verilog file/files> -p <pcf file> -P <pinmap csv file> -s <SDC file> \n\ |
| Devices supported: ql-eos-s3, qlf_k4n8 \n\ |
| Support temporarily disabled for: ql-pp3, qlf_k6n10" || exit |
| elif [[ $1 == "-v" || $1 == "--version" ]];then |
| echo "Symbiflow Tool Version : ${VERSION}" |
| exit 0 |
| else |
| echo -e "Please provide a valid command : Refer -h/--help\n" |
| exit 1 |
| fi |
| |
| |
| VERILOG_FILES=() |
| PCF="" |
| TOP="" |
| SOURCE="" |
| HELP="" |
| DEVICE="" |
| FAMILY="" |
| PART="" |
| SDC="" |
| OUT=() |
| ROUTE_FLAG0="" |
| MAX_CRITICALITY="0.0" |
| JSON="" |
| PNR_CORNER="slow" |
| ANALYSIS_CORNER="slow" |
| COMPILE_EXTRA_ARGS=() |
| BUILDDIR="build" |
| DEVICE_CHECK="INVALID" |
| OPT="" |
| RUN_TILL="" |
| |
| for arg in $@; do |
| case $arg in |
| -src|--source) OPT="src" ;; |
| -t|--top) OPT="top" ;; |
| -v|--verilog) OPT="vlog" ;; |
| -d|--device) OPT="dev" ;; |
| -p|--pcf) OPT="pcf" ;; |
| -P|--part) OPT="part" ;; |
| -j|--json) OPT="json" ;; |
| -s|--sdc) OPT="sdc" ;; |
| -r|--route_type) OPT="route" ;; |
| -pnr_corner) OPT="pnr_corner" ;; |
| -analysis_corner) OPT="analysis_corner" ;; |
| -dump) OPT="dump" ;; |
| -synth|-compile) OPT="synth" ;; |
| -y|+incdir+*|+libext+*|+define+*) OPT="compile_xtra" ;; |
| -f) OPT="options_file" ;; |
| -build_dir) OPT="build_dir" ;; |
| -h|--help) exit 0 ;; |
| *) |
| case $OPT in |
| src) SOURCE=$arg; OPT="" ;; |
| top) TOP=$arg; OPT="" ;; |
| dev) DEVICE=$arg; OPT="" ;; |
| pcf) PCF=$arg; OPT="" ;; |
| part) PART=$arg; OPT="" ;; |
| json) JSON=$arg; OPT="" ;; |
| sdc) SDC=$arg; OPT="" ;; |
| pnr_corner) PNR_CORNER=$arg; OPT="" ;; |
| analysis_corner) ANALYSIS_CORNER=$arg; OPT="" ;; |
| build_dir) BUILDDIR=$arg OPT="" ;; |
| route) |
| ROUTE_FLAG0="$arg" |
| ROUTE_FLAG0="${ROUTE_FLAG0,,}" |
| OPT="" |
| ;; |
| vlog) VERILOG_FILES+="$arg " ;; |
| dump) OUT+="$arg " ;; |
| compile_xtra) ;; |
| options_file) COMPILE_EXTRA_ARGS+=("-f \"`realpath $arg`\" ") ;; |
| *) |
| echo "Refer help for more details: ql_symbiflow -h " |
| exit 1 |
| ;; |
| esac |
| ;; |
| esac |
| if [ "$OPT" == "compile_xtra" ]; then |
| COMPILE_EXTRA_ARGS+=($arg) |
| fi |
| done |
| |
| case ${DEVICE} in |
| qlf_k4n8) DEVICE="${DEVICE}_${DEVICE}"; FAMILY="qlf_k4n8"; DEVICE_CHECK="VALID"; USE_PINMAP=1 ;; |
| qlf_k6n10) DEVICE="${DEVICE}_${DEVICE}"; FAMILY="qlf_k6n10"; DEVICE_CHECK="VALID"; USE_PINMAP=1 ;; |
| ql-eos-s3) DEVICE="${DEVICE}"; FAMILY="pp3"; DEVICE_CHECK="VALID"; USE_PINMAP=0 ;; |
| *) echo "Unsupported device '${DEVICE}'"; exit 1 ;; |
| esac |
| |
| if [[ $1 == "-h" || $1 == "--help" ]];then |
| exit 1 |
| fi |
| |
| ## Check if the source directory exists |
| SOURCE=${SOURCE:-$PWD} |
| if [ $SOURCE == "." ];then |
| SOURCE=$PWD |
| elif [ ! -d "$SOURCE" ];then |
| echo "Directory path $SOURCE DOES NOT exists. Please add absolute path" |
| exit 1 |
| fi |
| |
| if [ -f $SOURCE/v_list_tmp ];then |
| rm -f $SOURCE/v_list_tmp |
| fi |
| if [ "$VERILOG_FILES" == "*.v" ];then |
| VERILOG_FILES=`cd ${SOURCE};ls *.v` |
| fi |
| echo "$VERILOG_FILES" >${SOURCE}/v_list |
| |
| ## Validate the verlog source files |
| if [ ${#VERILOG_FILES[@]} -eq 0 ]; then |
| echo "Please provide at least one Verilog file" |
| exit 1 |
| fi |
| |
| echo "verilog files: $VERILOG_FILES" |
| echo $VERILOG_FILES >${SOURCE}/v_list |
| sed '/^$/d' $SOURCE/v_list > $SOURCE/f_list_temp |
| VERILOG_FILES=`cat $SOURCE/f_list_temp` |
| |
| |
| if [[ $1 == "-compile" || $1 == "-post_verilog" ]]; then |
| if [ -z "$DEVICE" ]; then |
| echo "DEVICE name is missing. Refer -h/--help" |
| exit 1 |
| elif ! [[ "$DEVICE_CHECK" =~ ^(VALID)$ ]]; then |
| echo "Invalid Device name, supported: ql-eos-s3, qlf_k4n8 \n\ |
| Support temporarily disabled for: qlf_k6n10" |
| exit 1 |
| fi |
| if [ -z "$TOP" ]; then |
| echo "TOP module name is missing. Refer -h/--help" |
| exit 1 |
| fi |
| if [[ "$DEVICE_CHECK" =~ ^(VALID)$ ]]; then |
| if [ -z "$PART" ]; then |
| if [[ -n "$PCF" && $USE_PINMAP -ne 0 ]]; then |
| echo "Error: pcf file cannot be used without declaring PINMAP CSV file" |
| exit 1 |
| fi |
| fi |
| fi |
| if [ -z "$ROUTE_FLAG0" ]; then |
| MAX_CRITICALITY="0.0" |
| elif ! [[ "$ROUTE_FLAG0" =~ ^(timing|congestion)$ ]]; then |
| echo "Invalid option name, supported timing/congestion" |
| exit 1 |
| else |
| if [ "$ROUTE_FLAG0" == "congestion" ]; then |
| MAX_CRITICALITY="0.99" |
| else |
| MAX_CRITICALITY="0.0" |
| fi |
| fi |
| fi |
| |
| if [ ! -z "$SOURCE" ] && [ ! -d $SOURCE/$BUILDDIR ]; then |
| mkdir -p $SOURCE/$BUILDDIR |
| fi |
| |
| if [ ! -z "$OUT" ]; then |
| OUT_ARR=($OUT) |
| fi |
| |
| for item in $VERILOG_FILES; do |
| if ! [ -f $SOURCE/$item ]; then |
| echo "$item: verilog file does not exists at : $SOURCE" |
| exit 1 |
| elif [[ $item =~ ^/ ]]; then |
| echo "$item \\" >>$SOURCE/v_list_tmp |
| else |
| echo "\${current_dir}/$item \\" >>$SOURCE/v_list_tmp |
| fi |
| done |
| |
| if [ -f "$SOURCE/v_list_tmp" ]; then |
| truncate -s-2 "$SOURCE/v_list_tmp" |
| VERILOG_LIST=`cat ${SOURCE}/v_list_tmp` |
| fi |
| |
| # FIXME: Some devices do not have fasm2bels yet |
| # FIXME: Some device do not support bitstream generation yet |
| RUN_TILL="" |
| if [[ "$DEVICE" =~ ^(qlf_k4n8.*)$ ]]; then |
| HAVE_FASM2BELS=0 |
| RUN_TILL="bit" |
| elif [[ "$DEVICE" =~ ^(qlf_k6n10.*)$ ]]; then |
| HAVE_FASM2BELS=0 |
| RUN_TILL="route" |
| elif [[ "$DEVICE" =~ ^(ql-eos-s3)$ ]]; then |
| HAVE_FASM2BELS=1 |
| RUN_TILL="bit" |
| else |
| HAVE_FASM2BELS=0 |
| RUN_TILL="route" |
| fi |
| |
| # For some devices do repacking between place and route |
| if [[ "$DEVICE" =~ ^(qlf_k4n8.*)$ ]]; then |
| TOP_FINAL=${TOP}.repacked |
| else |
| TOP_FINAL=${TOP} |
| fi |
| |
| export PCF_FILE=$PCF |
| export JSON=$JSON |
| export PINMAP_FILE=$PINMAPCSV |
| export MAX_CRITICALITY=$MAX_CRITICALITY |
| |
| ## Create Makefile |
| |
| if [[ $SOURCE =~ ^/ ]]; then |
| CURR_DIR="${SOURCE}" |
| else |
| CURR_DIR="${PWD}/${SOURCE}" |
| fi |
| |
| if [[ -n "$PART" && $USE_PINMAP -ne 0 ]]; then |
| if [[ -f $SOURCE/$PART ]];then |
| CSV_PATH=`realpath $SOURCE/$PART` |
| elif [[ -f $PART ]];then |
| CSV_PATH=`realpath $PART` |
| else |
| echo "invalid csv file/path" |
| exit 1 |
| fi |
| fi |
| |
| if [[ -f $SOURCE/$JSON ]];then |
| JSON_PATH=`realpath $SOURCE/$JSON` |
| elif [[ -f $JSON ]];then |
| JSON_PATH=`realpath $JSON` |
| else |
| JSON_PATH="" |
| fi |
| |
| if [[ -f $SOURCE/$PCF ]];then |
| PCF_PATH=`realpath $SOURCE/$PCF` |
| elif [[ -f $PCF ]];then |
| PCF_PATH=`realpath $PCF` |
| fi |
| |
| if [[ $USE_PINMAP -ne 0 ]]; then |
| export PART=${CSV_PATH} |
| else |
| export PART=${PART} |
| fi |
| export JSON=${JSON_PATH} |
| export PCF_PATH=${PCF_PATH} |
| |
| MAKE_FILE=${CURR_DIR}/Makefile.symbiflow |
| LOG_FILE=${CURR_DIR}/${BUILDDIR}/${TOP}.log |
| |
| if [ -f "$SOURCE"/$PCF_FILE ];then |
| PCF_MAKE="\${current_dir}/$PCF_FILE" |
| else |
| touch ${CURR_DIR}/${BUILDDIR}/${TOP}_dummy.pcf |
| PCF_MAKE="\${current_dir}/${BUILDDIR}/${TOP}_dummy.pcf" |
| fi |
| |
| if ! [ -z "$SDC" ]; then |
| if ! [ -f "$SOURCE"/$SDC ];then |
| echo "The sdc file: $SDC is missing at: $SOURCE" |
| exit 1 |
| else |
| SDC_MAKE="$SOURCE/$SDC" |
| fi |
| else |
| touch ${CURR_DIR}/${BUILDDIR}/${TOP}_dummy.sdc |
| SDC_MAKE="\${current_dir}/${BUILDDIR}/${TOP}_dummy.sdc" |
| fi |
| |
| if ! [ -z "$CSV_PATH" ]; then |
| CSV_MAKE=$CSV_PATH |
| else |
| touch ${CURR_DIR}/${BUILDDIR}/${TOP}_dummy.csv |
| CSV_MAKE="\${current_dir}/${BUILDDIR}/${TOP}_dummy.csv" |
| fi |
| |
| echo -e ".PHONY:\${BUILDDIR}\n |
| current_dir := $CURR_DIR\n\ |
| TOP := $TOP\n\ |
| JSON := $JSON\n\ |
| TOP_FINAL := $TOP_FINAL\n\ |
| VERILOG := $VERILOG_LIST \n\ |
| PARTNAME := $PART\n\ |
| DEVICE := $DEVICE\n\ |
| FAMILY := $FAMILY\n\ |
| ANALYSIS_CORNER := $PNR_CORNER\n\ |
| PNR_CORNER := $ANALYSIS_CORNER\n\ |
| PCF := $PCF_MAKE\n\ |
| PINMAP_CSV := $CSV_MAKE\n\ |
| SDC_IN := $SDC_MAKE\n\ |
| BUILDDIR := $BUILDDIR\n\n\ |
| SDC := \${current_dir}/\${BUILDDIR}/\${TOP}.sdc |
| |
| all: \${BUILDDIR}/\${TOP}.${RUN_TILL}\n\ |
| \n\ |
| \${BUILDDIR}/\${TOP}.eblif: \${VERILOG} \${PCF}\n\ |
| ifneq (\"\$(wildcard \$(HEX_FILES))\",\"\")\n\ |
| \$(shell cp \${current_dir}/*.hex \${BUILDDIR})\n\ |
| endif\n\ |
| cd \${BUILDDIR} && symbiflow_synth -t \${TOP} -v \${VERILOG} -F \${FAMILY} -d \${DEVICE} -p \${PCF} -P \${PART} ${COMPILE_EXTRA_ARGS[*]} > $LOG_FILE 2>&1\n\ |
| \n\ |
| \${BUILDDIR}/\${TOP}.sdc: \${BUILDDIR}/\${TOP}.eblif\n\ |
| python3 -m f4pga.utils.quicklogic.process_sdc_constraints --sdc-in \${SDC_IN} --sdc-out \$@ --pcf \${PCF} --eblif \${BUILDDIR}/\${TOP}.eblif --pin-map \${PINMAP_CSV}\n\ |
| \n\ |
| \${BUILDDIR}/\${TOP}.net: \${BUILDDIR}/\${TOP}.eblif \${BUILDDIR}/\${TOP}.sdc\n\ |
| cd \${BUILDDIR} && symbiflow_pack -e \${TOP}.eblif -f \${FAMILY} -d \${DEVICE} -s \${SDC} -c \${PNR_CORNER} >> $LOG_FILE 2>&1\n\ |
| \n\ |
| \${BUILDDIR}/\${TOP}.place: \${BUILDDIR}/\${TOP}.net \${PCF}\n\ |
| cd \${BUILDDIR} && symbiflow_place -e \${TOP}.eblif -f \${FAMILY} -d \${DEVICE} -p \${PCF} -n \${TOP}.net -P \${PARTNAME} -s \${SDC} -c \${PNR_CORNER} >> $LOG_FILE 2>&1\n\ |
| " >$MAKE_FILE |
| |
| if [ "$TOP" != "$TOP_FINAL" ]; then |
| if [ -z "$JSON" ];then |
| echo -e "\ |
| \${BUILDDIR}/\${TOP_FINAL}.place: \${BUILDDIR}/\${TOP}.eblif \${BUILDDIR}/\${TOP}.net \${BUILDDIR}/\${TOP}.place\n\ |
| cd \${BUILDDIR} && symbiflow_repack -e \${TOP}.eblif -n \${TOP}.net -f \${FAMILY} -d \${DEVICE} -c \${PNR_CORNER} >> $LOG_FILE 2>&1\n\ |
| " >>$MAKE_FILE |
| else |
| echo -e "\ |
| \${BUILDDIR}/\${TOP_FINAL}.place: \${BUILDDIR}/\${TOP}.eblif \${BUILDDIR}/\${TOP}.net \${BUILDDIR}/\${TOP}.place\n\ |
| cd \${BUILDDIR} && symbiflow_repack -e \${TOP}.eblif -n \${TOP}.net -f \${FAMILY} -d \${DEVICE} -j \${JSON} -c \${PNR_CORNER} >> $LOG_FILE 2>&1\n\ |
| " >>$MAKE_FILE |
| fi |
| fi |
| |
| echo -e "\ |
| \${BUILDDIR}/\${TOP_FINAL}.route: \${BUILDDIR}/\${TOP_FINAL}.place\n\ |
| cd \${BUILDDIR} && symbiflow_route -e \${TOP_FINAL}.eblif -f \${FAMILY} -d \${DEVICE} -s \${SDC} -c \${PNR_CORNER} >> $LOG_FILE 2>&1\n\ |
| \n\ |
| \${BUILDDIR}/\${TOP}.post_v: \${BUILDDIR}/\${TOP_FINAL}.route\n\ |
| cd \${BUILDDIR} && symbiflow_analysis -e \${TOP_FINAL}.eblif -f \${FAMILY} -d \${DEVICE} -s \${SDC} -t \${TOP} -c \${ANALYSIS_CORNER} >> $LOG_FILE 2>&1\n\ |
| \n\ |
| \${BUILDDIR}/\${TOP}.fasm: \${BUILDDIR}/\${TOP_FINAL}.route\n\ |
| cd \${BUILDDIR} && symbiflow_write_fasm -e \${TOP_FINAL}.eblif -f \${FAMILY} -d \${DEVICE} -s \${SDC} -c \${PNR_CORNER} >> $LOG_FILE 2>&1\n\ |
| " >>$MAKE_FILE |
| |
| # Bitstream |
| if [ "$FAMILY" == "qlf_k4n8" ]; then |
| echo -e "\ |
| \${BUILDDIR}/\${TOP}.bit: \${BUILDDIR}/\${TOP}.fasm\n\ |
| cd \${BUILDDIR} && symbiflow_generate_bitstream -d \${FAMILY} -f \${TOP}.fasm -r 4byte -b \${TOP}.bit >> $LOG_FILE 2>&1\n\ |
| cd \${BUILDDIR} && symbiflow_generate_bitstream -d \${FAMILY} -f \${TOP}.fasm -r txt -b \${TOP}.bin >> $LOG_FILE 2>&1\n\ |
| \n\ |
| \${BUILDDIR}/\${DEVICE}.lib:\n\ |
| cd \${BUILDDIR} && symbiflow_generate_libfile \${PARTNAME} \${DEVICE} \${PNR_CORNER} >> $LOG_FILE 2>&1\n\ |
| " >>$MAKE_FILE |
| |
| elif [ "$FAMILY" == "pp3" ]; then |
| echo -e "\ |
| \${BUILDDIR}/\${TOP}.bit: \${BUILDDIR}/\${TOP}.fasm\n\ |
| cd \${BUILDDIR} && symbiflow_generate_bitstream -d \${DEVICE} -f \${TOP}.fasm -b \${TOP}.bit >> $LOG_FILE 2>&1\n\ |
| " >>$MAKE_FILE |
| fi |
| |
| # EOS-S3 specific targets |
| if [ "$DEVICE" == "ql-eos-s3" ]; then |
| echo -e "\ |
| \${BUILDDIR}/\${TOP}_bit.h: \${BUILDDIR}/\${TOP}.bit\n\ |
| symbiflow_write_bitheader \$^ \$@ >> $LOG_FILE 2>&1\n\ |
| \n\ |
| \${BUILDDIR}/\${TOP}.bin: \${BUILDDIR}/\${TOP}.bit\n\ |
| symbiflow_write_binary \$^ \$@ >> $LOG_FILE 2>&1\n\ |
| \n\ |
| \${BUILDDIR}/\${TOP}.jlink: \${BUILDDIR}/\${TOP}.bit\n\ |
| symbiflow_write_jlink \$^ \$@ >> $LOG_FILE 2>&1\n\ |
| \n\ |
| \${BUILDDIR}/\${TOP}.openocd: \${BUILDDIR}/\${TOP}.bit\n\ |
| symbiflow_write_openocd \$^ \$@ >> $LOG_FILE 2>&1\n\ |
| \n\ |
| " >>$MAKE_FILE |
| fi |
| |
| # fasm2bels |
| if [ "$HAVE_FASM2BELS" != 0 ]; then |
| echo -e "\ |
| \${BUILDDIR}/\${TOP}.bit.v: \${BUILDDIR}/\${TOP}.bit\n\ |
| cd \${BUILDDIR} && symbiflow_fasm2bels -b \${TOP}.bit -d \${DEVICE} -p \${PCF} -P \${PARTNAME} >> $LOG_FILE 2>&1\n\ |
| " >>$MAKE_FILE |
| fi |
| |
| echo -e "\ |
| clean:\n\ |
| rm -rf \${BUILDDIR}\n\ |
| " >>$MAKE_FILE |
| |
| ## Remove temporary files |
| rm -f $SOURCE/f_list_temp $SOURCE/v_list_tmp $SOURCE/v_list |
| |
| ## Make file Targets |
| if [ $1 == "-synth" ]; then |
| echo -e "Performing Synthesis " |
| cd $SOURCE;make -f Makefile.symbiflow ${BUILDDIR}/${TOP}.eblif || (cat $LOG_FILE && exit 1) |
| elif [[ ! -z "$OUT" && $1 == "-compile" ]];then |
| if [[ " ${OUT_ARR[@]} " =~ " post_verilog " ]];then |
| cd $SOURCE;make -f Makefile.symbiflow ${BUILDDIR}/${TOP}.post_v || (cat $LOG_FILE && exit 1) |
| fi |
| if [ "$DEVICE" == "ql-eos-s3" ]; then |
| if [[ " ${OUT_ARR[@]} " =~ " jlink " ]]; then |
| cd $SOURCE;make -f Makefile.symbiflow ${BUILDDIR}/${TOP}.jlink || (cat $LOG_FILE && exit 1) |
| fi |
| if [[ " ${OUT_ARR[@]} " =~ " openocd " ]]; then |
| cd $SOURCE;make -f Makefile.symbiflow ${BUILDDIR}/${TOP}.openocd || (cat $LOG_FILE && exit 1) |
| fi |
| if [[ " ${OUT_ARR[@]} " =~ " post_verilog " ]]; then |
| cd $SOURCE;make -f Makefile.symbiflow ${BUILDDIR}/${TOP}.bit.v || (cat $LOG_FILE && exit 1) |
| fi |
| if [[ " ${OUT_ARR[@]} " =~ " header " ]]; then |
| cd $SOURCE;make -f Makefile.symbiflow ${BUILDDIR}/${TOP}_bit.h || (cat $LOG_FILE && exit 1) |
| fi |
| if [[ " ${OUT_ARR[@]} " =~ " binary " ]]; then |
| cd $SOURCE;make -f Makefile.symbiflow ${BUILDDIR}/${TOP}.bin || (cat $LOG_FILE && exit 1) |
| fi |
| fi |
| else |
| if [ $1 == "-compile" ]; then |
| echo -e "Running Synth->Pack->Place->Route->FASM->bitstream" |
| cd $SOURCE;make -f Makefile.symbiflow ${BUILDDIR}/${TOP}.${RUN_TILL} || (cat $LOG_FILE && exit 1) |
| fi |
| fi |