test.sh 11.1 KB
#!/bin/bash
# process recipe file compile and test all one test for all FPU configuration with optional defines

# recipe file syntax
# 0           1    2        3...
# <TESTNAME> <ID> <DAIFPU> <CFLAGS>
# if a line starts with '!' the line contains name of used toolchain ('llvm','gcc')
# if a line starts with '$' the line contains name of used linker script (link128kB, linkram2, ...)
# if a line starts with '^' the line contains CFLAGS used in all tests (the content is add to the end of each line with test [under the line])
# if a line starts with '-' the line contains ID_from and ID_to as a range of used IDs
# if a line starts with '@' the line contains suffix to build directory for all next lines
# if a line starts with '~' the line contains additional settings for makefiles which are run

#FPUS="daifpu_dual_dpsp_divsqrt daifpu_dual_dpsp_divonly daifpu_dual_dpsp_none \
#      daifpu_dual_sphp_divsqrt daifpu_dual_sphp_divonly daifpu_dual_sphp_none \
#      daifpu_dp_divsqrt daifpu_dp_divonly daifpu_dp_none \
#      daifpu_sp_divsqrt daifpu_sp_divonly daifpu_sp_none \
#      daifpu_hp_divsqrt daifpu_hp_divonly daifpu_hp_none \
#      daifpu_psp_divsqrt daifpu_psp_divonly daifpu_psp_none \
#      daifpu_php_divsqrt daifpu_php_divonly daifpu_php_none none"


if [ $# -lt 2 ]
then
    echo "The script needs two arguments at least - operation and recipe file."
    echo "Syntax: $0 <operation> <recipe> [<options>]"
    echo "Allowed operations are 'build','mgsim','ghdlsim','check','clean','rungrmon','runoocd'."
    echo "Optional arguments are:"
    echo "   F<fpu_type>    - FPU type for processing only lines with the selected FPU (all flavors)"
    echo "   S<fpu_subtype> - FPU subtype (divsqrt,divonly,none) for selection of required FPU flavor"
    echo "   p<serial_port> - select serial port for reading and saving data from board"
    echo "   f<ID_from>     - ID of lower bound (process only lines with equal or higher ID)"
    echo "   t<ID_to>       - ID of upper bound (process only lines with equal or lower ID)"
    echo "   g<grmon_port>  - change the default port for communication with grmon"
    exit 1
fi

OP=$1
FILE=$2

TIMESTAMP=`date +"%Y%m%d_%H%M"`

BUILD_DIR=./BUILD
GSIM_ODIR=./GHDL
RESULT_DIR=./RESULTS/work_${TIMESTAMP}/$2
RESULT_OOCD_DIR=./RESULTS_OOCD/work_${TIMESTAMP}/$2
STAMPFILE=/tmp/test.timestamp
PIDFILE=/tmp/test.pid
AWKTIMEOUT="30s"
GRMONTIMEOUT="25m"

GRMON_PORT=/dev/ttyUSB1
SERPORT=""
idfrom=""
idto=""
fputype=""
fpusub=""

for i in "${@:3}"
do
#  echo ">> $i - ${i:0:1} - ${i:1}"
  case ${i:0:1} in
    F)
      fputype=${i:1}
    ;;
    S)
      fpusub=${i:1}
    ;;
    p)
      SERPORT=${i:1}
    ;;
    f)
      idfrom=${i:1}
    ;;
    t)
      idto=${i:1}
    ;;
    g)
      GRMON_PORT=${i:1}
    ;;
  esac
done

if [[ ! -f "${FILE}" ]]
then
  echo "Recipe file does not exist."
  exit
fi

ln=0
tool="llvm"
ldscr=""
ccflgs=""
dsuf=""
mkset=""

# once actions
case ${OP} in
  runoocd)
    mkdir -p $(pwd)/${RESULT_OOCD_DIR}
    if [ -z "${SERPORT}" ]; then
      echo "Serial port for reading is not set."
      exit 1
    fi
    if pgrep "openocd" >/dev/null 2>&1
    then
      echo "OpenOCD is running."
    else
      echo "OpenOCD is not running."
      exit 1
    fi
   ;;

  rungrmon)
    mkdir -p $(pwd)/${RESULT_DIR}
    if [ -z "${SERPORT}" ]; then
      echo "Serial port for reading is not set."
      exit 1
    fi
   ;;

  *)
   ;;
esac


# process recipe
while IFS= read -r line
do
 ln=$((ln+1))
 pln=( ${line} )

 if [[ ${pln[0]} == "#"* ]]   # skip comments
 then
  continue
 fi

 if [[ ${pln[0]} == "!"* ]]   # line starts with '!' globally controls make rules (e.g. select toolchain)
 then
  tool=${pln[1]}
  continue
 fi

 if [[ ${pln[0]} == "$"* ]]   # line starts with '$' change linker script
 then
   ldscr="LDSCRIPT=${pln[1]}"
   continue
 fi

 if [[ ${pln[0]} == "^"* ]]   # line starts with '^' set common CFLAGS
 then
   ccflgs="${pln[@]:1}"
   continue
 fi

 if [[ ( ${#pln[*]} -gt 2 ) && ( ${pln[0]} == "-"* ) ]]   # line starts with '-' select range of IDs for processing
 then
   idfrom="${pln[1]}"
   idto="${pln[2]}"
   continue
 fi

 if [[ ( ${#pln[*]} -gt 1 ) && ( ${pln[0]} == "@"* ) ]]   # line starts with '@' set build directory suffix
 then
   dsuf="_${pln[1]}"
   continue
 fi

 if [[ ( ${#pln[*]} -gt 1 ) && ( ${pln[0]} == "~"* ) ]]   # line starts with '~' set make variables
 then
   mkset="${pln[@]:1}"
   continue
 fi


 if [[ ${#pln[*]} -eq 0 ]]    # skip empty lines
 then
  continue
 fi

 if [[ ${#pln[*]} -lt 3 ]]    # skip lines with bad syntax
 then
  echo "ERROR: Bad syntax on line #${ln}."
  continue
 fi


 # check if ID is in selected range
 if [[ ( ! -z "${idfrom}" ) && ( ${pln[1]} -lt ${idfrom} ) ]]
 then
  echo "Skip ID ${pln[1]}"
  continue
 fi
 if [[ ( ! -z "${idto}" ) && ( ${pln[1]} -gt ${idto} ) ]]
 then
  echo "Skip ID ${pln[1]}"
  continue
 fi
 # check FPUTYPE/FPUSUB
 if [[ ( ! -z "${fputype}" ) && ( ${pln[2]} != "${fputype}"* ) ]]
 then
  echo "Skip FPU ${pln[2]} (${pln[1]})"
  continue
 fi
 if [[ ( ! -z "${fpusub}" ) && ( ${pln[2]} != *"_${fpusub}" ) ]]
 then
  echo "Skip FPUsub ${pln[2]} (${pln[1]})"
  continue
 fi

if [[ ${pln[2]} == swar* ]]
then
 testtype="SWAR"
 makeopts="TESTS=${pln[0]} TOOL=${tool} ${ldscr} ID=${pln[1]} SWARCFG=${pln[2]} MAKEVAR='${mkset}' UCFLAGS='${pln[@]:3} ${ccflgs}'"
else
 testtype="FPU"
 makeopts="TESTS=${pln[0]} TOOL=${tool} ${ldscr} ID=${pln[1]} FPUCFG=${pln[2]} MAKEVAR='${mkset}' UCFLAGS='${pln[@]:3} ${ccflgs}'"
fi

 echo -e "\nProcess line #${ln}: T=${pln[0]} ID=${pln[1]} ${testtype}=${pln[2]} CF=\"${pln[@]:3}\""
 #echo " => makeopts = '${makeopts}'"

 case ${OP} in
  build)
   echo -e "\nCompile '${pln[0]}' for ${testtype} '${pln[2]}' with CFLAGS=\"${pln[@]:3}\" "
#   echo "Call: ${makeopts}"
    echo "make ${mkset} DSUFFIX=${dsuf} ${makeopts}"
   eval make ${mkset} DSUFFIX=${dsuf} ${makeopts}
   MRES=$?
   if [ ${MRES} -ne 0 ]
   then
    echo "Compilation of '${pln[0]}' (ID=${pln[1]}) for ${testtype} '${pln[2]}' failed"
    break
   fi
   ;;

  mgsim)
   echo -e "\nSimulate '${pln[0]}' for ${testtype} '${pln[2]}' with CFLAGS=\"${pln[@]:3}\" "
   echo "make sim NOLOG=y DSUFFIX=${dsuf} ${makeopts}"
   eval make sim NOLOG=y DSUFFIX=${dsuf} ${makeopts}
   ;;

  ghdlsim)
    echo -e "\nSimulate '${pln[0]}' for ${testtype} '${pln[2]}' with GHDL simulator (CFLAGS='${pln[@]:3}')"
   if [ -f "ghdlsim.map" ]; then
    ghdlexe=""
    while IFS= read -r gsim
    do
     gs=( ${gsim} )
     if [ "${pln[2]}" == "${gs[0]}" ]; then
      ghdlexe=${gs[1]}
     fi
    done < "ghdlsim.map"
    if [ -z ${ghdlexe} ]; then
     echo "  GHDL simulator not defined for ${testtype} '${pln[2]}'"
    else
     # test if test.dat file exists
     testname=${pln[0]}-${pln[1]}-${pln[2]}
     datfile=${BUILD_DIR}/${pln[2]}${dsuf}/${testname}.dat
     if [ ! -f "${datfile}" ]; then
      echo "Test ${testname} is not prepared"
     else
      if [ -f "${ghdlexe}" ]; then
       # get full path to GHDL simulator
       fullgexe=`find "$(pwd)"/"${ghdlexe}" -type f`
       #echo "FULLGHDL '${fullgexe}'"
       mkdir -p ${GSIM_ODIR}/${pln[2]}
       # make link in simulaiton directory
       ln -f -s "${fullgexe}" ${GSIM_ODIR}/${pln[2]}/ghdlsim
       # copy test as DAT file into simulation directory as ddr.dat file
       cp ${datfile} ${GSIM_ODIR}/${pln[2]}/ddr.dat
       # run simulation
       (cd ${GSIM_ODIR}/${pln[2]}; ./ghdlsim | awk '!/metavalue|cpu0|rf_int/{print }' | tee ${testname}.log;)
      else
       echo " GHDL simulator for ${testtype} '${pln[2]}' is not reachable"
      fi
     fi
    fi

   else
    echo "GHDL simulation needs file 'ghdlsim.map' which contains lines with mapping"
    echo " of FPUCFG to path to executable ghdl simulator which will be used for the"
    echo " specific FPU mode."
    echo "  (example of a line  'daifpu_dual_dpsp_divsqrt  /opt/ghdl_sim_dai_dpsp')"
   fi
   ;;


  runoocd)
    echo -e "\nRun OpenOCD for '${pln[0]}' with ${testtype} '${pln[2]}'"
    testname=${pln[0]}-${pln[1]}-${pln[2]}
    elffile=$(pwd)/${BUILD_DIR}/${pln[2]}${dsuf}/${testname}.elf
    outfile=$(pwd)/${RESULT_OOCD_DIR}/${testname}-output.log
    oocdlog=$(pwd)/${RESULT_OOCD_DIR}/${testname}-oocd.log
    timeoutlog=$(pwd)/${RESULT_OOCD_DIR}/${testname}.timeout
    elflink="/tmp/test.elf"
    echo "ELF:     ${elffile}"
    echo "OUTFILE: ${outfile}"
    echo "SerPort: ${SERPORT}"
    if [[ ! -f "${elffile}" ]]; then
      echo "!!! ELF file '${elffile}' does not exist. Skip"
      continue
    fi

    if [[ -f "${elflink}" ]]; then
      if [[ ! -L "${elflink}" ]]; then
        echo "!!! Temporary link '${elflink}' is not a link. Stop processing"
        exit 1
      fi
    fi
    ln -fs ${elffile} ${elflink}

    echo "Listen ${SERPORT}"
    killall awk; sleep 1s
    awk '/END OF TEST/ {print; exit}; {print};' < ${SERPORT} > ${outfile} &
    pidawk=$!

    # save timestamp
    echo `date +"%Y%m%d%H%M"` > ${STAMPFILE}
    # send commands to OOCD - skip .bss sections
    echo -e "halt\ninit_board\nload /tmp/test.elf .bss\nrun 0x40000000\nexit\n" | nc localhost 4444
    # wait for END OF TEST
    echo "Wait for END OF TEST on ${SERPORT}"
    wait ${pidawk}
    rm -f ${STAMPFILE}

   ;;


  rungrmon)
    echo -e "\nRun grmon for ${pln[0]} with ${testtype} ${pln[2]}"
    testname=${pln[0]}-${pln[1]}-${pln[2]}
    elffile=$(pwd)/${BUILD_DIR}/${pln[2]}${dsuf}/${testname}.elf
    outfile=$(pwd)/${RESULT_DIR}/${testname}-output.log
    grmonlog=$(pwd)/${RESULT_DIR}/${testname}-grmon.log
    timeoutlog=$(pwd)/${RESULT_DIR}/${testname}.timeout
    elflink="/tmp/test.elf"
    echo "ELF:     ${elffile}"
    echo "OUTFILE: ${outfile}"
    echo "SerPort: ${SERPORT}"
    if [[ ! -f "${elffile}" ]]; then
      echo "!!! ELF file '${elffile}' does not exist. Skip"
      continue
    fi

    if [[ -f "${elflink}" ]]; then
      if [[ ! -L "${elflink}" ]]; then
        echo "!!! Temporary link '${elflink}' is not a link. Stop processing"
        exit 1
      fi
    fi
    ln -fs ${elffile} ${elflink}

    stty -F ${SERPORT} 115200
    echo "Listening on ${SERPORT}"
    awk '/END OF TEST/ {print; exit}; {print};' < ${SERPORT} > ${outfile} &
    pidawk=$!
    # save timestamp
    echo `date +"%Y%m%d%H%M"` > ${STAMPFILE}
    echo "Run grmon @"
#     ( sleep ${GRMONTIMEOUT}; if [[ -e ${STAMPFILE} ]]; then echo "GRMON TIMEOUT" >> ${timeoutlog}; killall grmon; fi; ) &
#     killgrmonpid=$!
   grmon -leon2 -uart ${GRMON_PORT} -c ./scripts/grmon_load_run_test.batch | tee ${grmonlog}
#     grmon -nopnp -sys leon2 -uart ${GRMON_PORT} -c ./scripts/grmon_load_run_test.batch | tee ${grmonlog}
#     grmon -digilent -c ./scripts/grmon_load_run_test.batch | tee ${grmonlog}
#     grmon -ftdi -c ./scripts/grmon_load_run_test.batch | tee ${grmonlog}
    rm -f ${STAMPFILE}
#     kill -0 ${killgrmonpid}
    # timeout for AWK
#     echo ${pidawk} > ${PIDFILE}
#     ( sleep ${AWKTIMEOUT}; if [[ -e ${PIDFILE} ]]; then echo "AWK TIMEOUT" >> ${timeoutlog}; kill -0 ${pidawk} ; fi ; ) &
#     killerpid=$!
#     echo "Wait for END OF TEST on ${SERPORT}"
#     wait ${pidawk}
    killall awk; sleep 1s
#     rm -f ${PIDFILE}
#     kill -0 ${killerpid}

   ;;

  check)
   ;;

  clean)
   ;;

  test)
   eval "echo TEST : '${ln}' '${line}'"
   eval "echo      : '${pln[0]}' ${pln[1]} ${pln[2]} ${pln[@]:3}"
   ;;

  *)
   echo "Unsupported operation."
   ;;
 esac
done < "$FILE"