######################################################################################################################## # @file FindXilinx.cmake # @author Andrew D. Zonenberg # @brief Xilinx ISE toolchain CMake module ######################################################################################################################## ######################################################################################################################## # Autodetect Xilinx paths (very hacky for now) # Find /opt/Xilinx or similar find_file(XILINX_PARENT NAMES Xilinx PATHS /opt) if(XILINX_PARENT STREQUAL "XILINX_PARENT-NOTFOUND") message(FATAL_ERROR "No Xilinx toolchain installation found") endif() # Find /opt/Xilinx/VERSION # TODO: Figure out a better way of doing this find_file(XILINX NAMES 14.3 PATHS ${XILINX_PARENT}) if(XILINX STREQUAL "XILINX-NOTFOUND") message(FATAL_ERROR "No ISE 14.3 installation found") endif() message(STATUS "Found Xilinx toolchain... ${XILINX}") # Set current OS architecture (TODO: autodetect) set(XILINX_ARCH lin64) # Find fuse find_file(FUSE NAMES fuse PATHS "${XILINX}/ISE_DS/ISE/bin/${XILINX_ARCH}/") if(FUSE STREQUAL "FUSE-NOTFOUND") message(FATAL_ERROR "No Xilinx fuse installation found") endif() message(STATUS "Found Xilinx fuse... ${FUSE}") ######################################################################################################################## # Argument parsing helper macro(xilinx_parse_args _top_level _sources) set(${_top_level} FALSE) set(${_sources}) set(_found_sources FALSE) set(_found_top_level FALSE) foreach(arg ${ARGN}) if(${arg} STREQUAL "TOP_LEVEL") set(_found_top_level TRUE) elseif(${arg} STREQUAL "SOURCES") set(_found_sources TRUE) elseif(${_found_sources}) list(APPEND ${_sources} ${arg}) elseif(${_found_top_level}) if(${_top_level}) message(FATAL_ERROR "Multiple top-level files specified in xilinx_parse_args") else() set(${_top_level} ${arg}) endif() else() message(FATAL_ERROR "Unrecognized command ${arg} in xilinx_parse_args") endif() endforeach() endmacro() ######################################################################################################################## # ISim executable generation function(add_isim_executable OUTPUT_FILE ) # Parse args xilinx_parse_args(TOP_LEVEL SOURCES ${ARGN}) # Get base name without extension of the top-level module get_filename_component(TOPLEVEL_BASENAME ${TOP_LEVEL} NAME_WE ) # Write the .prj file set(PRJ_FILE "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILE}.prj") file(WRITE ${PRJ_FILE} "verilog work \"${TOP_LEVEL}\"\n") foreach(f ${SOURCES}) file(APPEND ${PRJ_FILE} "verilog work \"${f}\"\n") endforeach() file(APPEND ${PRJ_FILE} "verilog work \"${XILINX}/ISE_DS/ISE/verilog/src/glbl.v\"\n") # Main compile rule # TODO: tweak this add_custom_target( ${OUTPUT_FILE} ALL COMMAND ${FUSE} ${FUSE_FLAGS} -o ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILE} -prj ${PRJ_FILE} work.${TOPLEVEL_BASENAME} work.glbl > ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILE}_build.log 2> ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILE}_err.log DEPENDS ${SOURCES} ${TOP_LEVEL} COMMENT "Building ISim executable ${OUTPUT_FILE}..." ) # Write the tcl script set(TCL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILE}.tcl") file(WRITE ${TCL_FILE} "onerror {resume}\n") file(APPEND ${TCL_FILE} "wave add /\n") file(APPEND ${TCL_FILE} "run 1000 ns;\n") file(APPEND ${TCL_FILE} "exit;\n") # Write the run-test wrapper script set(TEST_WRAPPER "${CMAKE_CURRENT_BINARY_DIR}/run${OUTPUT_FILE}.sh") file(WRITE ${TEST_WRAPPER} "#!/bin/bash\n") file(APPEND ${TEST_WRAPPER} "cd ${CMAKE_CURRENT_BINARY_DIR}\n") file(APPEND ${TEST_WRAPPER} "source ${XILINX}/ISE_DS/settings64.sh\n") file(APPEND ${TEST_WRAPPER} "./${OUTPUT_FILE} -tclbatch ${TCL_FILE} -intstyle silent -vcdfile ${OUTPUT_FILE}.vcd -vcdunit ps || exit 1\n") file(APPEND ${TEST_WRAPPER} "cat isim.log | grep -q FAIL\n") file(APPEND ${TEST_WRAPPER} "if [ \"$?\" != \"1\" ]; then\n") file(APPEND ${TEST_WRAPPER} " exit 1;\n") file(APPEND ${TEST_WRAPPER} "fi\n") add_custom_command(TARGET ${OUTPUT_FILE} POST_BUILD COMMAND chmod +x ${TEST_WRAPPER}) endfunction() ######################################################################################################################## # Test generation # # Usage: # add_isim_test(NandGate # TOP_LEVEL # ${CMAKE_CURRENT_SOURCE_DIR}/testNandGate.v # SOURCES # ${CMAKE_SOURCE_DIR}/hdl/NandGate.v # ) function(add_isim_test TEST_NAME) # Parse args xilinx_parse_args(TOP_LEVEL SOURCES ${ARGN}) # Add the sim executable add_isim_executable(test${TEST_NAME} TOP_LEVEL ${TOP_LEVEL} SOURCES ${SOURCES} ) add_test(${TEST_NAME} "${CMAKE_CURRENT_BINARY_DIR}/runtest${TEST_NAME}.sh") set_property(TEST ${TEST_NAME} APPEND PROPERTY DEPENDS test${TEST_NAME}) endfunction()