|  | # This CMake include defines the following functions: | 
|  | # | 
|  | # * DEFINE_ARCH - Define an FPGA architecture and tools to use that | 
|  | #   architecture. | 
|  | # * DEFINE_DEVICE_TYPE - Define a device type within an FPGA architecture. | 
|  | # * DEFINE_DEVICE - Define a device and packaging for a specific device type and | 
|  | #   FPGA architecture. | 
|  | # * DEFINE_BOARD - Define a board that uses specific device and package. | 
|  | # * ADD_FPGA_TARGET - Creates a FPGA image build against a specific board. | 
|  |  | 
|  | function(DEFINE_ARCH) | 
|  | # ~~~ | 
|  | # DEFINE_ARCH( | 
|  | #    ARCH <arch> | 
|  | #    FAMILY <family> | 
|  | #    DOC_PRJ <documentation_project> | 
|  | #    DOC_PRJ_DB <documentation_database> | 
|  | #    PROTOTYPE_PART <prototype_part> | 
|  | #    [YOSYS_SYNTH_SCRIPT <yosys_script>] | 
|  | #    [SDC_PATCH_TOOL <path to a SDC file patching utility>] | 
|  | #    [SDC_PATCH_TOOL_CMD <command to run SDC_PATCH_TOOL>] | 
|  | #    BITSTREAM_EXTENSION <ext> | 
|  | #    [VPR_ARCH_ARGS <arg list>] | 
|  | #    RR_PATCH_CMD <command to run rr_patch tool> | 
|  | #    [NET_PATCH_TOOL <path to net patch tool>] | 
|  | #    [NET_PATCH_TOOL_CMD <command to run NET_PATCH_TOOL>] | 
|  | #    DEVICE_FULL_TEMPLATE <template for constructing DEVICE_FULL strings. | 
|  | #    [RR_PATCH_CMD <command to run rr_patch tool>] | 
|  | #    [NO_PINS] | 
|  | #    [NO_TEST_PINS] | 
|  | #    [NO_PLACE] | 
|  | #    [NO_PLACE_CONSTR] | 
|  | #    [USE_FASM] | 
|  | #    PLACE_TOOL_CMD <command to run place tool> | 
|  | #    PLACE_CONSTR_TOOL_CMD <command to run PLACE_CONSTR_TOOL> | 
|  | #    [NO_BITSTREAM] | 
|  | #    [NO_BIT_TO_BIN] | 
|  | #    [NO_BIT_TO_V] | 
|  | #    [CELLS_SIM <path to verilog file used for simulation>] | 
|  | #    HLC_TO_BIT <path to HLC to bitstream converter> | 
|  | #    HLC_TO_BIT_CMD <command to run HLC_TO_BIT> | 
|  | #    FASM_TO_BIT <path to FASM to bitstream converter> | 
|  | #    FASM_TO_BIT_CMD <command to run FASM_TO_BIT> | 
|  | #    FASM_TO_BIT_DEPS <list of dependencies for FASM_TO_BIT_CMD> | 
|  | #    [BIT_TO_FASM <path to bitstream to FASM converter>] | 
|  | #    [BIT_TO_FASM_CMD <command to run BIT_TO_FASM>] | 
|  | #    BIT_TO_V_CMD <command to run bitstream to verilog converter> | 
|  | #    BIT_TO_BIN <path to bitstream to binary> | 
|  | #    BIT_TO_BIN_CMD <command to run BIT_TO_BIN> | 
|  | #    BIT_TIME <path to BIT_TIME executable> | 
|  | #    BIT_TIME_CMD <command to run BIT_TIME> | 
|  | #    [RR_GRAPH_EXT <ext>] | 
|  | #    [NO_INSTALL] | 
|  | #   ) | 
|  | # ~~~ | 
|  | # | 
|  | # DEFINE_ARCH defines an FPGA architecture. | 
|  | # | 
|  | # FAMILY refers to the family under which the architecture is located. | 
|  | # e.g. 7series, UltraScale, Spartan are all different kinds of families. | 
|  | # | 
|  | # DOC_PRJ and DOC_PRJ_DB are optional arguments that are relative to the | 
|  | # third party projects containing tools and information to correctly run | 
|  | # the flow: | 
|  | # | 
|  | #  * DOC_PRJ - path to the third party documentation project | 
|  | #  * DOC_PRJ_DB - path to the third party documentation database | 
|  | # | 
|  | # If NO_PINS is set, PLACE_TOOL_CMD cannot be specified. | 
|  | # If NO_TEST_PINS is set, the automatic generation of the constraints file for | 
|  | # the generic tests is skipped. | 
|  | # If NO_BITSTREAM is set, HLC_TO_BIT, HLC_TO_BIT_CMD, | 
|  | # BIT_TO_V_CMD, BIT_TO_BIN and BIT_TO_BIN_CMD cannot be specified. | 
|  | # | 
|  | # if NO_BIT_TO_BIN is given then there will be no BIT to BIN stage. | 
|  | # | 
|  | # YOSYS_SYNTH_SCRIPT - The main design synthesis script. It needs to write | 
|  | #  the synthesized design in JSON format to a file name pointed by the | 
|  | #  OUT_JSON env. variable. It also makes Yosys convert the processed JSON | 
|  | #  design to the EBLIF format accepted by the VPR. The EBLIF file name is | 
|  | #  given in the OUT_EBLIF env. variable. | 
|  | # | 
|  | # DEVICE_FULL_TEMPLATE, RR_PATCH_CMD, PLACE_TOOL_CMD and HLC_TO_BIT_CMD will | 
|  | # all be called with string(CONFIGURE) to substitute variables. | 
|  | # | 
|  | # DEVICE_FULL_TEMPLATE variables: | 
|  | # | 
|  | #  * DEVICE | 
|  | #  * PACKAGE | 
|  | # | 
|  | # RR_PATCH_CMD variables: | 
|  | # | 
|  | # * DEVICE - What device is being patch (see DEFINE_DEVICE). | 
|  | # * OUT_RRXML_VIRT - Input virtual rr_graph file for device. | 
|  | # * OUT_RRXML_REAL - Output real XML rr_graph file for device. | 
|  | # * OUT_RRBIN_REAL - Output real BIN rr_graph file for device. | 
|  | # | 
|  | # PLACE_TOOL_CMD variables: | 
|  | # | 
|  | # * PINMAP - Path to pinmap file.  This file will be retrieved from the | 
|  | #   PINMAP property of the ${BOARD}.  ${DEVICE} and ${PACKAGE} | 
|  | #   will be defined by the BOARD being used. See DEFINE_BOARD. | 
|  | # * OUT_EBLIF - Input path to EBLIF file. | 
|  | # * INPUT_IO_FILE - Path to input io file, as specified by ADD_FPGA_TARGET. | 
|  | # | 
|  | # PLACE_TOOL_CONSTR_CMD variables: | 
|  | # | 
|  | # * NO_PLACE_CONSTR - If this option is set, the PLACE_CONSTR_TOOL is disabled | 
|  | # | 
|  | # This command enables the possibility to add an additional step consisting | 
|  | # on the addition of extra placement constraints through the usage of the chosen | 
|  | # script. | 
|  | # The IO placement file is passed to the script through standard input and, when | 
|  | # the new placement constraints for non-IO tiles have been added, a new placement | 
|  | # constraint file is generated and fed to standard output. | 
|  | # | 
|  | # NET_PATCH_TOOL_CMD variables: | 
|  | # | 
|  | # * NET_PATCH_TOOL - Value of NET_PATCH_TOOL property of <arch>. | 
|  | # * IN_EBLIF  - EBLIF file from the synthesis step | 
|  | # * IN_NET    - VPR .net file after packing & placement | 
|  | # * IN_PLACE  - VPR .place file after packing & placement | 
|  | # * OUT_EBLIF - EBLIF file to be used by VPR router | 
|  | # * OUT_NET   - VPR .net file to be used by router | 
|  | # * OUT_PLACE - VPR .place file to be used by router | 
|  | # * VPR_ARCH  - Path to VPR architecture XML file | 
|  | # | 
|  | # SDC_PATCH_TOOL allows to specify a utility that processes SDC constraints | 
|  | #  file provided by a user prior to feedin it to VPR. | 
|  | # | 
|  | # SDC_PATCH_TOOL_CMD variables: | 
|  | # | 
|  | # * SDC_IN        - Path to the input (source) SDC file | 
|  | # * SDC_OUT       - Path to the output (destination) SDC file | 
|  | # * INPUT_IO_FILE - Path to the input PCF IO constraints file | 
|  | # | 
|  | # HLC_TO_BIT_CMD variables: | 
|  | # | 
|  | # * HLC_TO_BIT - Value of HLC_TO_BIT property of <arch>. | 
|  | # * OUT_HLC - Input path to HLC file. | 
|  | # * OUT_BITSTREAM - Output path to bitstream file. | 
|  | # | 
|  | # BIT_TO_V variables: | 
|  | # | 
|  | # * TOP - Name of top module. | 
|  | # * INPUT_IO_FILE - Logic to IO pad constraint file. | 
|  | # * PACKAGE - Package of bitstream. | 
|  | # * OUT_BITSTREAM - Input path to bitstream. | 
|  | # * OUT_BIT_VERILOG - Output path to verilog version of bitstream. | 
|  | # | 
|  | set(options | 
|  | NO_PLACE_CONSTR | 
|  | NO_PINS | 
|  | NO_TEST_PINS | 
|  | NO_BITSTREAM | 
|  | NO_BIT_TO_BIN | 
|  | NO_BIT_TO_V | 
|  | NO_BIT_TIME | 
|  | NO_INSTALL | 
|  | USE_FASM | 
|  | ) | 
|  |  | 
|  | set( | 
|  | oneValueArgs | 
|  | ARCH | 
|  | FAMILY | 
|  | DOC_PRJ | 
|  | DOC_PRJ_DB | 
|  | PROTOTYPE_PART | 
|  | YOSYS_SYNTH_SCRIPT | 
|  | YOSYS_TECHMAP | 
|  | DEVICE_FULL_TEMPLATE | 
|  | BITSTREAM_EXTENSION | 
|  | BIN_EXTENSION | 
|  | RR_PATCH_CMD | 
|  | NET_PATCH_TOOL | 
|  | NET_PATCH_TOOL_CMD | 
|  | PLACE_TOOL_CMD | 
|  | PLACE_CONSTR_TOOL_CMD | 
|  | SDC_PATCH_TOOL | 
|  | SDC_PATCH_TOOL_CMD | 
|  | HLC_TO_BIT | 
|  | HLC_TO_BIT_CMD | 
|  | FASM_TO_BIT | 
|  | FASM_TO_BIT_CMD | 
|  | BIT_TO_FASM | 
|  | BIT_TO_FASM_CMD | 
|  | BIT_TO_V_CMD | 
|  | BIT_TO_BIN | 
|  | BIT_TO_BIN_CMD | 
|  | BIT_TIME | 
|  | BIT_TIME_CMD | 
|  | RR_GRAPH_EXT | 
|  | ROUTE_CHAN_WIDTH | 
|  | ) | 
|  |  | 
|  | set( | 
|  | multiValueArgs | 
|  | CELLS_SIM | 
|  | VPR_ARCH_ARGS | 
|  | FASM_TO_BIT_DEPS | 
|  | ) | 
|  |  | 
|  | cmake_parse_arguments( | 
|  | DEFINE_ARCH | 
|  | "${options}" | 
|  | "${oneValueArgs}" | 
|  | "${multiValueArgs}" | 
|  | ${ARGN} | 
|  | ) | 
|  |  | 
|  | add_custom_target(${DEFINE_ARCH_ARCH}) | 
|  |  | 
|  | set(REQUIRED_ARGS | 
|  | DEVICE_FULL_TEMPLATE | 
|  | NO_PLACE_CONSTR | 
|  | NO_PINS | 
|  | NO_TEST_PINS | 
|  | NO_BITSTREAM | 
|  | NO_BIT_TO_BIN | 
|  | NO_BIT_TO_V | 
|  | NO_BIT_TIME | 
|  | NO_INSTALL | 
|  | USE_FASM | 
|  | ROUTE_CHAN_WIDTH | 
|  | ) | 
|  | set(DISALLOWED_ARGS "") | 
|  | set(OPTIONAL_ARGS | 
|  | YOSYS_SYNTH_SCRIPT | 
|  | FAMILY | 
|  | DOC_PRJ | 
|  | DOC_PRJ_DB | 
|  | PROTOTYPE_PART | 
|  | VPR_ARCH_ARGS | 
|  | YOSYS_TECHMAP | 
|  | CELLS_SIM | 
|  | RR_PATCH_CMD | 
|  | SDC_PATCH_TOOL | 
|  | SDC_PATCH_TOOL_CMD | 
|  | NET_PATCH_TOOL | 
|  | NET_PATCH_TOOL_CMD | 
|  | BIT_TO_FASM | 
|  | BIT_TO_FASM_CMD | 
|  | ) | 
|  |  | 
|  | set(PLACE_ARGS | 
|  | PLACE_TOOL_CMD | 
|  | ) | 
|  |  | 
|  | set(PLACE_CONSTR_ARGS | 
|  | PLACE_CONSTR_TOOL_CMD | 
|  | ) | 
|  |  | 
|  | set(FASM_BIT_ARGS | 
|  | FASM_TO_BIT | 
|  | FASM_TO_BIT_CMD | 
|  | ) | 
|  |  | 
|  | set(HLC_BIT_ARGS | 
|  | HLC_TO_BIT | 
|  | HLC_TO_BIT_CMD | 
|  | ) | 
|  |  | 
|  | set(BIT_ARGS | 
|  | BITSTREAM_EXTENSION | 
|  | ) | 
|  |  | 
|  | set(BIN_ARGS | 
|  | BIN_EXTENSION | 
|  | BIT_TO_BIN | 
|  | BIT_TO_BIN_CMD | 
|  | ) | 
|  |  | 
|  | set(BIT_TO_V_ARGS | 
|  | BIT_TO_V_CMD | 
|  | ) | 
|  |  | 
|  | set(BIT_TIME_ARGS | 
|  | BIT_TIME | 
|  | BIT_TIME_CMD | 
|  | ) | 
|  |  | 
|  | if(NOT ${DEFINE_ARCH_NO_BIT_TO_BIN}) | 
|  | list(APPEND BIT_ARGS ${BIN_ARGS}) | 
|  | else() | 
|  | list(APPEND DISALLOWED_ARGS ${BIN_ARGS}) | 
|  | endif() | 
|  |  | 
|  | if(${DEFINE_ARCH_USE_FASM}) | 
|  | list(APPEND DISALLOWED_ARGS ${HLC_BIT_ARGS}) | 
|  | list(APPEND OPTIONAL_ARGS FASM_TO_BIT_DEPS) | 
|  | list(APPEND BIT_ARGS ${FASM_BIT_ARGS}) | 
|  | else() | 
|  | list(APPEND DISALLOWED_ARGS ${FASM_BIT_ARGS}) | 
|  | list(APPEND DISALLOWED_ARGS FASM_TO_BIT_DEPS) | 
|  | list(APPEND BIT_ARGS ${HLC_BIT_ARGS}) | 
|  | endif() | 
|  |  | 
|  | set(VPR_${DEFINE_ARCH_ARCH}_ARCH_ARGS "${DEFINE_ARCH_VPR_ARCH_ARGS}" | 
|  | CACHE STRING "Extra VPR arguments for ARCH=${ARCH}") | 
|  |  | 
|  | if(${DEFINE_ARCH_NO_PINS}) | 
|  | list(APPEND DISALLOWED_ARGS ${PLACE_ARGS}) | 
|  | else() | 
|  | list(APPEND REQUIRED_ARGS ${PLACE_ARGS}) | 
|  | endif() | 
|  |  | 
|  | if(${DEFINE_ARCH_NO_PLACE_CONSTR}) | 
|  | list(APPEND DISALLOWED_ARGS ${PLACE_CONSTR_ARGS}) | 
|  | else() | 
|  | list(APPEND REQUIRED_ARGS ${PLACE_CONSTR_ARGS}) | 
|  | endif() | 
|  |  | 
|  | set(RR_GRAPH_EXT ".xml") | 
|  | if(NOT "${DEFINE_ARCH_RR_GRAPH_EXT}" STREQUAL "") | 
|  | set(RR_GRAPH_EXT "${DEFINE_ARCH_RR_GRAPH_EXT}") | 
|  | endif() | 
|  |  | 
|  | if(${DEFINE_ARCH_NO_BITSTREAM}) | 
|  | list(APPEND DISALLOWED_ARGS ${BIT_ARGS}) | 
|  | list(APPEND DISALLOWED_ARGS BIT_TO_FASM BIT_TO_FASM_CMD) | 
|  | else() | 
|  | list(APPEND REQUIRED_ARGS ${BIT_ARGS}) | 
|  | endif() | 
|  |  | 
|  | if(${DEFINE_ARCH_NO_BIT_TO_V}) | 
|  | list(APPEND DISALLOWED_ARGS ${BIT_TO_V_ARGS}) | 
|  | else() | 
|  | list(APPEND REQUIRED_ARGS ${BIT_TO_V_ARGS}) | 
|  | list(APPEND DISALLOWED_ARGS BIT_TO_FASM BIT_TO_FASM_CMD) | 
|  | endif() | 
|  |  | 
|  | if(${DEFINE_ARCH_NO_BIT_TIME}) | 
|  | list(APPEND DISALLOWED_ARGS ${BIT_TIME_ARGS}) | 
|  | else() | 
|  | list(APPEND REQUIRED_ARGS ${BIT_TIME_ARGS}) | 
|  | endif() | 
|  |  | 
|  | foreach(ARG ${REQUIRED_ARGS}) | 
|  | if("${DEFINE_ARCH_${ARG}}" STREQUAL "") | 
|  | message(FATAL_ERROR "Required argument ${ARG} is the empty string.") | 
|  | endif() | 
|  | set_target_properties( | 
|  | ${DEFINE_ARCH_ARCH} | 
|  | PROPERTIES ${ARG} "${DEFINE_ARCH_${ARG}}" | 
|  | ) | 
|  | endforeach() | 
|  | set_target_properties( | 
|  | ${DEFINE_ARCH_ARCH} | 
|  | PROPERTIES RR_GRAPH_EXT "${RR_GRAPH_EXT}" | 
|  | ) | 
|  | foreach(ARG ${OPTIONAL_ARGS}) | 
|  | set_target_properties( | 
|  | ${DEFINE_ARCH_ARCH} | 
|  | PROPERTIES ${ARG} "${DEFINE_ARCH_${ARG}}" | 
|  | ) | 
|  | endforeach() | 
|  | foreach(ARG ${DISALLOWED_ARGS}) | 
|  | if(NOT "${DEFINE_ARCH_${ARG}}" STREQUAL "") | 
|  | message(FATAL_ERROR "Argument ${ARG} is disallowed when NO_PINS = ${NO_PINS} and NO_BITSTREAM = ${NO_BITSTREAM}.") | 
|  | endif() | 
|  | endforeach() | 
|  | endfunction() | 
|  |  | 
|  | function(DEFINE_DEVICE_TYPE) | 
|  | # ~~~ | 
|  | # DEFINE_DEVICE_TYPE( | 
|  | #   DEVICE_TYPE <device_type> | 
|  | #   ARCH <arch> | 
|  | #   ARCH_XML <arch.xml> | 
|  | #   [SCRIPT_OUTPUT_NAME] | 
|  | #   [SCRIPT_DEPS] | 
|  | #   [SCRIPTS] | 
|  | #   ) | 
|  | # ~~~ | 
|  | # | 
|  | # Defines a device type with the specified architecture.  ARCH_XML argument | 
|  | # must be a file target (see ADD_FILE_TARGET). | 
|  | # | 
|  | # optional SCRIPTs can be run after the standard flow to augment the | 
|  | # final arch xml. The name and script must be provided and each | 
|  | # script will be run as `cmd < input > output`. | 
|  | # If the SCRIPT has dependencies, SCRIPT_DEPS can be used to be passed to the | 
|  | # SCRIPT command. | 
|  | # | 
|  | # DEFINE_DEVICE_TYPE defines a dummy target <arch>_<device_type>_arch that | 
|  | # will build the merged architecture file for the device type. | 
|  | set(options "") | 
|  | set(oneValueArgs DEVICE_TYPE ARCH ARCH_XML) | 
|  | set(multiValueArgs SCRIPT_OUTPUT_NAME SCRIPTS SCRIPT_DEPS) | 
|  | cmake_parse_arguments( | 
|  | DEFINE_DEVICE_TYPE | 
|  | "${options}" | 
|  | "${oneValueArgs}" | 
|  | "${multiValueArgs}" | 
|  | ${ARGN} | 
|  | ) | 
|  |  | 
|  | # | 
|  | # Generate a arch.xml for a device. | 
|  | # | 
|  | set(DEVICE_MERGED_FILE arch.merged.xml) | 
|  | set(DEVICE_UNIQUE_PACK_FILE arch.unique_pack.xml) | 
|  | set(DEVICE_LINT_FILE arch.lint.html) | 
|  |  | 
|  | set(MERGE_XML_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${DEVICE_MERGED_FILE}) | 
|  | set(UNIQUE_PACK_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${DEVICE_UNIQUE_PACK_FILE}) | 
|  | set(XMLLINT_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${DEVICE_LINT_FILE}) | 
|  |  | 
|  | xml_canonicalize_merge( | 
|  | NAME ${DEFINE_DEVICE_TYPE_ARCH}_${DEFINE_DEVICE_TYPE_DEVICE_TYPE}_arch_merged | 
|  | FILE ${DEFINE_DEVICE_TYPE_ARCH_XML} | 
|  | OUTPUT ${DEVICE_MERGED_FILE} | 
|  | ) | 
|  | get_target_property_required(PYTHON3 env PYTHON3) | 
|  |  | 
|  | append_file_dependency(SPECIALIZE_CARRYCHAINS_DEPS ${DEVICE_MERGED_FILE}) | 
|  |  | 
|  | set(SPECIALIZE_CARRYCHAINS ${f4pga-arch-defs_SOURCE_DIR}/utils/specialize_carrychains.py) | 
|  | add_custom_command( | 
|  | OUTPUT ${UNIQUE_PACK_OUTPUT} | 
|  | COMMAND ${PYTHON3} ${SPECIALIZE_CARRYCHAINS} | 
|  | --input_arch_xml ${MERGE_XML_OUTPUT} > ${DEVICE_UNIQUE_PACK_FILE} | 
|  | DEPENDS | 
|  | ${PYTHON3} | 
|  | ${SPECIALIZE_CARRYCHAINS} | 
|  | ${SPECIALIZE_CARRYCHAINS_DEPS} | 
|  | ) | 
|  |  | 
|  | add_file_target(FILE ${DEVICE_UNIQUE_PACK_FILE} GENERATED) | 
|  | get_file_target(FINAL_TARGET ${DEVICE_UNIQUE_PACK_FILE}) | 
|  | get_file_location(FINAL_FILE ${DEVICE_UNIQUE_PACK_FILE}) | 
|  | set(FINAL_OUTPUT ${DEVICE_UNIQUE_PACK_FILE}) | 
|  |  | 
|  | # for each script generate next chain of deps | 
|  | if (DEFINE_DEVICE_TYPE_SCRIPTS) | 
|  | list(LENGTH DEFINE_DEVICE_TYPE_SCRIPT_OUTPUT_NAME SCRIPT_LEN) | 
|  | math(EXPR SCRIPT_LEN ${SCRIPT_LEN}-1) | 
|  | foreach(SCRIPT_IND RANGE ${SCRIPT_LEN}) | 
|  | list(GET DEFINE_DEVICE_TYPE_SCRIPT_OUTPUT_NAME ${SCRIPT_IND} OUTPUT_NAME) | 
|  | list(GET DEFINE_DEVICE_TYPE_SCRIPT_DEPS ${SCRIPT_IND} DEFINE_DEVICE_TYPE_SCRIPT_DEP_VAR) | 
|  | list(GET DEFINE_DEVICE_TYPE_SCRIPTS ${SCRIPT_IND} SCRIPT) | 
|  |  | 
|  | set(SCRIPT ${${SCRIPT}}) | 
|  | set(DEFINE_DEVICE_TYPE_SCRIPT_DEP_VAR ${${DEFINE_DEVICE_TYPE_SCRIPT_DEP_VAR}}) | 
|  |  | 
|  | separate_arguments(CMD_W_ARGS UNIX_COMMAND ${SCRIPT}) | 
|  | list(GET CMD_W_ARGS 0 CMD) | 
|  | set(TEMP_TARGET arch.${OUTPUT_NAME}.xml) | 
|  | set(DEFINE_DEVICE_DEPS ${PYTHON3} ${CMD} ${DEFINE_DEVICE_TYPE_SCRIPT_DEP_VAR}) | 
|  | append_file_dependency(DEFINE_DEVICE_DEPS ${FINAL_OUTPUT}) | 
|  |  | 
|  | add_custom_command( | 
|  | OUTPUT ${TEMP_TARGET} | 
|  | COMMAND ${CMD_W_ARGS} < ${FINAL_FILE} > ${TEMP_TARGET} | 
|  | DEPENDS ${DEFINE_DEVICE_DEPS} | 
|  | ) | 
|  |  | 
|  | add_file_target(FILE ${TEMP_TARGET} GENERATED) | 
|  | get_file_target(FINAL_TARGET ${TEMP_TARGET}) | 
|  | get_file_location(FINAL_FILE ${TEMP_TARGET}) | 
|  | set(FINAL_OUTPUT ${TEMP_TARGET}) | 
|  | endforeach(SCRIPT_IND RANGE ${SCRIPT_LEN}) | 
|  | endif (DEFINE_DEVICE_TYPE_SCRIPTS) | 
|  |  | 
|  | add_custom_target( | 
|  | ${DEFINE_DEVICE_TYPE_ARCH}_${DEFINE_DEVICE_TYPE_DEVICE_TYPE}_arch | 
|  | DEPENDS ${FINAL_TARGET} | 
|  | ) | 
|  | add_dependencies( | 
|  | all_merged_arch_xmls | 
|  | ${DEFINE_DEVICE_TYPE_ARCH}_${DEFINE_DEVICE_TYPE_DEVICE_TYPE}_arch | 
|  | ) | 
|  |  | 
|  | set(ARCH_SCHEMA ${f4pga-arch-defs_SOURCE_DIR}/common/xml/fpga_architecture.xsd) | 
|  | xml_lint( | 
|  | NAME ${DEFINE_DEVICE_TYPE_ARCH}_${DEFINE_DEVICE_TYPE_DEVICE_TYPE}_arch_lint | 
|  | FILE ${FINAL_FILE} | 
|  | LINT_OUTPUT ${XMLLINT_OUTPUT} | 
|  | SCHEMA ${ARCH_SCHEMA} | 
|  | ) | 
|  |  | 
|  | append_file_dependency(FINAL_DEPS ${FINAL_OUTPUT}) | 
|  |  | 
|  | add_custom_target( | 
|  | ${DEFINE_DEVICE_TYPE_DEVICE_TYPE} | 
|  | DEPENDS ${FINAL_DEPS} | 
|  | ) | 
|  |  | 
|  | foreach(ARG ARCH) | 
|  | if("${DEFINE_DEVICE_TYPE_${ARG}}" STREQUAL "") | 
|  | message(FATAL_ERROR "Required argument ${ARG} is the empty string.") | 
|  | endif() | 
|  | set_target_properties( | 
|  | ${DEFINE_DEVICE_TYPE_DEVICE_TYPE} | 
|  | PROPERTIES ${ARG} ${DEFINE_DEVICE_TYPE_${ARG}} | 
|  | ) | 
|  | endforeach() | 
|  |  | 
|  | set_target_properties( | 
|  | ${DEFINE_DEVICE_TYPE_DEVICE_TYPE} | 
|  | PROPERTIES | 
|  | DEVICE_MERGED_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${FINAL_OUTPUT} | 
|  | ) | 
|  |  | 
|  | endfunction() | 
|  |  | 
|  | function(DEFINE_DEVICE) | 
|  | # ~~~ | 
|  | # DEFINE_DEVICE( | 
|  | #   DEVICE <device> | 
|  | #   ARCH <arch> | 
|  | #   PART <part> | 
|  | #   DEVICE_TYPE <device_type> | 
|  | #   PACKAGES <list of packages> | 
|  | #   [WIRE_EBLIF <a dummy design eblif file> | 
|  | #   [CACHE_PLACE_DELAY] | 
|  | #   [CACHE_LOOKAHEAD] | 
|  | #   [CACHE_ARGS <args>] | 
|  | #   [ROUTE_CHAN_WIDTH <width>] | 
|  | #   [NO_RR_PATCHING] | 
|  | #   [EXT_RR_GRAPH] | 
|  | #   [NO_INSTALL] | 
|  | #   [NET_PATCH_DEPS <list of dependencies>] | 
|  | #   [NET_PATCH_EXTRA_ARGS <extra args for .net patching>] | 
|  | #   [EXTRA_INSTALL_FILES <file1> <file2> ... <fileN>] | 
|  | #   ) | 
|  | # ~~~ | 
|  | # | 
|  | # Defines a device within a specified FPGA architecture. | 
|  | # | 
|  | # Creates dummy targets <arch>_<device>_<package>_rrxml_virt and | 
|  | # <arch>_<device>_<package>_rrxml_virt  that generates the the virtual and | 
|  | # real rr_graph for a specific device and package. | 
|  | # | 
|  | # The WIRE_EBLIF specifies a dummy design file to use. If not given then | 
|  | # the default "common/wire.eblif" is used. | 
|  | # | 
|  | # To prevent VPR from recomputing the place delay matrix and/or lookahead, | 
|  | # CACHE_PLACE_DELAY and CACHE_LOOKAHEAD options may be specified. | 
|  | # | 
|  | # If either are specified, CACHE_ARGS must be supplied with the relevant | 
|  | # VPR arguments needed to emit the correct place delay and lookahead outputs. | 
|  | # It is not required that the all arguments match the DEFINE_ARCH.VPR_ARCH_ARGS | 
|  | # as it may be advantagous to increase routing effort for the placement delay | 
|  | # matrix computation (e.g. lower astar_fac, etc). | 
|  | # | 
|  | # At a minimum, the --route_chan_width argument must be supplied. | 
|  | # | 
|  | # WARNING: Using a different place delay or lookahead algorithm will result | 
|  | # in an invalid cache. | 
|  | # | 
|  | # The DONT_INSTALL option prevents device files to be installed. | 
|  | # | 
|  | # When ROUTE_CHAN_WIDTH is provided it overrides the channel with provided | 
|  | # for the ARCH | 
|  | # | 
|  | set(options CACHE_LOOKAHEAD CACHE_PLACE_DELAY NO_INSTALL NO_RR_PATCHING) | 
|  | set(oneValueArgs DEVICE ARCH PART DEVICE_TYPE PACKAGES WIRE_EBLIF ROUTE_CHAN_WIDTH EXT_RR_GRAPH) | 
|  | set(multiValueArgs RR_PATCH_DEPS RR_PATCH_EXTRA_ARGS NET_PATCH_DEPS NET_PATCH_EXTRA_ARGS CACHE_ARGS EXTRA_INSTALL_FILES) | 
|  | cmake_parse_arguments( | 
|  | DEFINE_DEVICE | 
|  | "${options}" | 
|  | "${oneValueArgs}" | 
|  | "${multiValueArgs}" | 
|  | ${ARGN} | 
|  | ) | 
|  |  | 
|  | set(NO_INSTALL ${DEFINE_DEVICE_NO_INSTALL}) | 
|  |  | 
|  | add_custom_target(${DEFINE_DEVICE_DEVICE}) | 
|  | foreach(ARG ARCH DEVICE_TYPE PACKAGES) | 
|  | if("${DEFINE_DEVICE_${ARG}}" STREQUAL "") | 
|  | message(FATAL_ERROR "Required argument ${ARG} is the empty string.") | 
|  | endif() | 
|  | set_target_properties( | 
|  | ${DEFINE_DEVICE_DEVICE} | 
|  | PROPERTIES ${ARG} ${DEFINE_DEVICE_${ARG}} | 
|  | ) | 
|  | endforeach() | 
|  |  | 
|  | if("${DEFINE_DEVICE_WIRE_EBLIF}" STREQUAL "") | 
|  | set(WIRE_EBLIF ${f4pga-arch-defs_SOURCE_DIR}/common/wire.eblif) | 
|  | else() | 
|  | set(WIRE_EBLIF ${DEFINE_DEVICE_WIRE_EBLIF}) | 
|  | endif() | 
|  |  | 
|  | if(NOT "${DEFINE_DEVICE_NET_PATCH_DEPS}" STREQUAL "") | 
|  | set_target_properties( | 
|  | ${DEFINE_DEVICE_DEVICE} PROPERTIES | 
|  | NET_PATCH_DEPS ${DEFINE_DEVICE_NET_PATCH_DEPS} | 
|  | ) | 
|  | endif() | 
|  |  | 
|  | if(NOT "${DEFINE_DEVICE_NET_PATCH_EXTRA_ARGS}" STREQUAL "") | 
|  | set_target_properties( | 
|  | ${DEFINE_DEVICE_DEVICE} PROPERTIES | 
|  | NET_PATCH_EXTRA_ARGS ${DEFINE_DEVICE_NET_PATCH_EXTRA_ARGS} | 
|  | ) | 
|  | endif() | 
|  |  | 
|  | set(NO_RR_PATCHING ${DEFINE_DEVICE_NO_RR_PATCHING}) | 
|  | set(EXT_RR_GRAPH   ${DEFINE_DEVICE_EXT_RR_GRAPH}) | 
|  |  | 
|  | # For external RR graph only one PACKAGE is allowed | 
|  | list(LENGTH DEFINE_DEVICE_PACKAGES NUM_PACKAGES) | 
|  | if (DEFINED EXT_RR_GRAPH) | 
|  | if (NUM_PACKAGES GREATER "1") | 
|  | message(FATAL_ERROR "Device ${DEFINE_DEVICE_DEVICE} with external rr graph must have only one package!") | 
|  | endif () | 
|  | endif () | 
|  |  | 
|  | if (NOT ${NO_RR_PATCHING}) | 
|  | get_target_property_required(RR_PATCH_CMD ${DEFINE_DEVICE_ARCH} RR_PATCH_CMD) | 
|  | endif () | 
|  |  | 
|  | get_target_property_required(RR_GRAPH_EXT ${DEFINE_DEVICE_ARCH} RR_GRAPH_EXT) | 
|  |  | 
|  | get_target_property_required( | 
|  | VIRT_DEVICE_MERGED_FILE ${DEFINE_DEVICE_DEVICE_TYPE} DEVICE_MERGED_FILE | 
|  | ) | 
|  | get_file_target(DEVICE_MERGED_FILE_TARGET ${VIRT_DEVICE_MERGED_FILE}) | 
|  | get_file_location(DEVICE_MERGED_FILE ${VIRT_DEVICE_MERGED_FILE}) | 
|  | get_target_property_required(VPR env VPR) | 
|  | get_target_property_required(QUIET_CMD env QUIET_CMD) | 
|  |  | 
|  | set(ROUTING_SCHEMA ${f4pga-arch-defs_SOURCE_DIR}/common/xml/routing_resource.xsd) | 
|  |  | 
|  | set(PART ${DEFINE_DEVICE_PART}) | 
|  | set(DEVICE ${DEFINE_DEVICE_DEVICE}) | 
|  | foreach(PACKAGE ${DEFINE_DEVICE_PACKAGES}) | 
|  | get_target_property_required(DEVICE_FULL_TEMPLATE ${DEFINE_DEVICE_ARCH} DEVICE_FULL_TEMPLATE) | 
|  | string(CONFIGURE ${DEVICE_FULL_TEMPLATE} DEVICE_FULL) | 
|  |  | 
|  | # Generate the virtual graph | 
|  | if(NOT DEFINED EXT_RR_GRAPH) | 
|  |  | 
|  | set(OUT_RR_VIRT_FILENAME | 
|  | rr_graph_${DEVICE}_${PACKAGE}.rr_graph.virt${RR_GRAPH_EXT}) | 
|  | set(OUT_RR_VIRT | 
|  | ${CMAKE_CURRENT_BINARY_DIR}/${OUT_RR_VIRT_FILENAME}) | 
|  |  | 
|  | # Use the device specific channel with for the virtual graph if provided. | 
|  | # If not use a dummy value (assuming that the graph will get patched | 
|  | # anyways). | 
|  | if("${DEFINE_DEVICE_ROUTE_CHAN_WIDTH}" STREQUAL "") | 
|  | set(RRXML_VIRT_ROUTE_CHAN_WIDTH 6) # FIXME: Where did the number come from? | 
|  | else() | 
|  | set(RRXML_VIRT_ROUTE_CHAN_WIDTH ${DEFINE_DEVICE_ROUTE_CHAN_WIDTH}) | 
|  | endif() | 
|  |  | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_RR_VIRT} rr_graph_${DEVICE}_${PACKAGE}.virt.out | 
|  | DEPENDS | 
|  | ${WIRE_EBLIF} | 
|  | ${DEVICE_MERGED_FILE} ${DEVICE_MERGED_FILE_TARGET} | 
|  | ${QUIET_CMD} | 
|  | ${VPR} ${DEFINE_DEVICE_DEVICE_TYPE} | 
|  | COMMAND | 
|  | ${QUIET_CMD} ${VPR} ${DEVICE_MERGED_FILE} | 
|  | --device ${DEVICE_FULL} | 
|  | ${WIRE_EBLIF} | 
|  | --place_algorithm bounding_box | 
|  | --route_chan_width ${RRXML_VIRT_ROUTE_CHAN_WIDTH} | 
|  | --echo_file on | 
|  | --min_route_chan_width_hint 1 | 
|  | --write_rr_graph ${OUT_RR_VIRT} | 
|  | --outfile_prefix ${DEVICE}_${PACKAGE} | 
|  | --pack | 
|  | --pack_verbosity 100 | 
|  | --place | 
|  | --allow_dangling_combinational_nodes on | 
|  | COMMAND | 
|  | ${CMAKE_COMMAND} -E copy vpr_stdout.log | 
|  | rr_graph_${DEVICE}_${PACKAGE}.virt.out | 
|  | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} | 
|  | ) | 
|  | add_custom_target( | 
|  | ${DEFINE_DEVICE_ARCH}_${DEFINE_DEVICE_DEVICE}_${PACKAGE}_rrxml_virt | 
|  | DEPENDS ${OUT_RR_VIRT} | 
|  | ) | 
|  |  | 
|  | add_file_target(FILE ${OUT_RR_VIRT_FILENAME} GENERATED) | 
|  |  | 
|  | # Use the external rr_graph as virtual directly | 
|  | else() | 
|  | get_filename_component(OUT_RR_VIRT          ${EXT_RR_GRAPH} REALPATH) | 
|  | get_filename_component(OUT_RR_VIRT_FILENAME ${EXT_RR_GRAPH} NAME) | 
|  |  | 
|  | endif() | 
|  |  | 
|  | # Patch the virtual rr graph if necessary | 
|  | if(NOT ${NO_RR_PATCHING}) | 
|  |  | 
|  | set(OUT_RR_PATCHED_FILENAME | 
|  | rr_graph_${DEVICE}_${PACKAGE}.rr_graph.patched${RR_GRAPH_EXT}) | 
|  | set(OUT_RR_PATCHED | 
|  | ${CMAKE_CURRENT_BINARY_DIR}/${OUT_RR_PATCHED_FILENAME}) | 
|  |  | 
|  | set(RR_PATCH_DEPS ${DEFINE_DEVICE_RR_PATCH_DEPS}) | 
|  | append_file_dependency(RR_PATCH_DEPS ${VIRT_DEVICE_MERGED_FILE}) | 
|  | append_file_dependency(RR_PATCH_DEPS ${OUT_RR_VIRT_FILENAME}) | 
|  |  | 
|  | # Set the variables below to maintain compatibility with existing | 
|  | # invocations of rr patching utils. | 
|  | set(OUT_RRXML_VIRT ${OUT_RR_VIRT}) | 
|  | set(OUT_RRXML_REAL ${OUT_RR_PATCHED}) | 
|  |  | 
|  | get_target_property_required(PYTHON3 env PYTHON3) | 
|  | string(CONFIGURE ${RR_PATCH_CMD} RR_PATCH_CMD_FOR_TARGET) | 
|  | separate_arguments( | 
|  | RR_PATCH_CMD_FOR_TARGET_LIST UNIX_COMMAND ${RR_PATCH_CMD_FOR_TARGET} | 
|  | ) | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_RR_PATCHED} | 
|  | DEPENDS ${RR_PATCH_DEPS} | 
|  | COMMAND ${RR_PATCH_CMD_FOR_TARGET_LIST} ${DEFINE_DEVICE_RR_PATCH_EXTRA_ARGS} | 
|  | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} | 
|  | VERBATIM | 
|  | ) | 
|  |  | 
|  | add_file_target(FILE ${OUT_RR_PATCHED_FILENAME} GENERATED) | 
|  |  | 
|  | add_custom_target( | 
|  | ${DEFINE_DEVICE_ARCH}_${DEFINE_DEVICE_DEVICE}_${PACKAGE}_rrxml_real | 
|  | DEPENDS ${OUT_RR_PATCHED} | 
|  | ) | 
|  | add_dependencies(all_rrgraph_xmls ${DEFINE_DEVICE_ARCH}_${DEFINE_DEVICE_DEVICE}_${PACKAGE}_rrxml_real) | 
|  |  | 
|  | # Lint the "real" rr_graph.xml | 
|  | if("${RR_GRAPH_EXT}" STREQUAL ".xml") | 
|  |  | 
|  | set(OUT_RR_PATCHED_LINT_FILENAME rr_graph_${DEVICE}_${PACKAGE}.rr_graph.patched.lint.html) | 
|  | set(OUT_RR_PATCHED_LINT ${CMAKE_CURRENT_BINARY_DIR}/${OUT_RR_PATCHED_LINT_FILENAME}) | 
|  |  | 
|  | xml_lint( | 
|  | NAME ${DEFINE_DEVICE_ARCH}_${DEFINE_DEVICE_DEVICE}_${PACKAGE}_rrxml_real_lint | 
|  | LINT_OUTPUT ${OUT_RR_PATCHED_LINT} | 
|  | FILE ${OUT_RR_PATCHED} | 
|  | SCHEMA ${ROUTING_SCHEMA} | 
|  | ) | 
|  | endif() | 
|  |  | 
|  | # Use the virtual rr_graph directly | 
|  | else() | 
|  |  | 
|  | if(NOT DEFINED EXT_RR_GRAPH) | 
|  | set(OUT_RR_PATCHED_FILENAME ${OUT_RR_VIRT_FILENAME}) | 
|  | set(OUT_RR_PATCHED          ${OUT_RR_VIRT}) | 
|  | else() | 
|  | get_filename_component(OUT_RR_PATCHED          ${EXT_RR_GRAPH} REALPATH) | 
|  | get_filename_component(OUT_RR_PATCHED_FILENAME ${EXT_RR_GRAPH} NAME) | 
|  | endif() | 
|  |  | 
|  | endif() | 
|  |  | 
|  | if(NOT ${NO_RR_PATCHING} OR "${EXT_RR_GRAPH}" STREQUAL ".xml") | 
|  | set(OUT_RR_REAL_FILENAME rr_graph_${DEVICE}_${PACKAGE}.rr_graph.real.bin) | 
|  | set(OUT_RR_REAL ${CMAKE_CURRENT_BINARY_DIR}/${OUT_RR_REAL_FILENAME}) | 
|  | set(READ_RR ${OUT_RR_PATCHED}) | 
|  | set(READ_RR_FILENAME ${OUT_RR_PATCHED_FILENAME}) | 
|  | else() | 
|  | # Use the virtual rr_graph directly | 
|  | if(NOT DEFINED EXT_RR_GRAPH) | 
|  | set(OUT_RR_REAL_FILENAME ${OUT_RR_VIRT_FILENAME}) | 
|  | set(OUT_RR_REAL          ${OUT_RR_VIRT}) | 
|  |  | 
|  | # Use external real rr_graph.bin directly | 
|  | else() | 
|  | get_filename_component(OUT_RR_REAL          ${EXT_RR_GRAPH} REALPATH) | 
|  | get_filename_component(OUT_RR_REAL_FILENAME ${EXT_RR_GRAPH} NAME) | 
|  | endif() | 
|  |  | 
|  | set(READ_RR ${OUT_RR_REAL}) | 
|  | set(READ_RR_FILENAME ${OUT_RR_REAL_FILENAME}) | 
|  | endif() | 
|  |  | 
|  | set_target_properties( | 
|  | ${DEFINE_DEVICE_DEVICE} | 
|  | PROPERTIES | 
|  | ${PACKAGE}_OUT_RRBIN_REAL ${CMAKE_CURRENT_SOURCE_DIR}/${OUT_RR_REAL_FILENAME} | 
|  | ) | 
|  |  | 
|  | set(LOOKAHEAD_FILENAME | 
|  | rr_graph_${DEVICE}_${PACKAGE}.lookahead.bin) | 
|  | set(PLACE_DELAY_FILENAME | 
|  | rr_graph_${DEVICE}_${PACKAGE}.place_delay.bin) | 
|  |  | 
|  | set(DEPS) | 
|  | append_file_dependency(DEPS ${READ_RR_FILENAME}) | 
|  | append_file_dependency(DEPS ${VIRT_DEVICE_MERGED_FILE}) | 
|  |  | 
|  | set(ARGS) | 
|  | if(${DEFINE_DEVICE_CACHE_LOOKAHEAD}) | 
|  | list(APPEND OUTPUTS ${LOOKAHEAD_FILENAME}) | 
|  | list(APPEND ARGS --write_router_lookahead ${LOOKAHEAD_FILENAME}) | 
|  | endif() | 
|  | if(${DEFINE_DEVICE_CACHE_PLACE_DELAY}) | 
|  | list(APPEND OUTPUTS ${PLACE_DELAY_FILENAME}) | 
|  | list(APPEND ARGS --write_placement_delay_lookup ${PLACE_DELAY_FILENAME}) | 
|  | endif() | 
|  | if(NOT ${NO_RR_PATCHING}) | 
|  | list(APPEND OUTPUTS ${OUT_RR_REAL_FILENAME}) | 
|  | list(APPEND ARGS --write_rr_graph ${OUT_RR_REAL_FILENAME}) | 
|  | endif() | 
|  |  | 
|  | set(CACHE_PREFIX rr_graph_${DEVICE}_${PACKAGE}) | 
|  |  | 
|  | add_custom_command( | 
|  | OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CACHE_PREFIX}.cache ${OUTPUTS} | 
|  | DEPENDS | 
|  | ${WIRE_EBLIF} | 
|  | ${VPR} | 
|  | ${QUIET_CMD} | 
|  | ${DEFINE_DEVICE_DEVICE_TYPE} | 
|  | ${DEPS} ${PYTHON3} | 
|  | COMMAND | 
|  | ${PYTHON3} ${f4pga-arch-defs_SOURCE_DIR}/utils/check_cache.py ${OUT_RR_REAL} ${CACHE_PREFIX}.cache ${OUTPUTS} || ( | 
|  | ${QUIET_CMD} ${VPR} ${DEVICE_MERGED_FILE} | 
|  | --device ${DEVICE_FULL} | 
|  | ${WIRE_EBLIF} | 
|  | --read_rr_graph ${READ_RR} | 
|  | --read_rr_edge_metadata on | 
|  | --outfile_prefix ${CACHE_PREFIX}_cache_ | 
|  | --pack | 
|  | --place | 
|  | ${ARGS} | 
|  | ${DEFINE_DEVICE_CACHE_ARGS} && | 
|  | ${PYTHON3} ${f4pga-arch-defs_SOURCE_DIR}/utils/update_cache.py ${OUT_RR_REAL} ${CACHE_PREFIX}.cache) | 
|  | COMMAND | 
|  | ${CMAKE_COMMAND} -E copy vpr_stdout.log | 
|  | ${CMAKE_CURRENT_BINARY_DIR}/${CACHE_PREFIX}.cache.out | 
|  | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} | 
|  | ) | 
|  |  | 
|  | add_file_target(FILE ${CACHE_PREFIX}.cache GENERATED) | 
|  | get_file_target(CACHE_TARGET ${CACHE_PREFIX}.cache) | 
|  |  | 
|  | if(${DEFINE_DEVICE_CACHE_LOOKAHEAD}) | 
|  | add_file_target(FILE ${LOOKAHEAD_FILENAME} GENERATED) | 
|  |  | 
|  | # Linearize target dependency. | 
|  | get_file_target(LOOKAHEAD_TARGET ${LOOKAHEAD_FILENAME}) | 
|  | add_dependencies(${LOOKAHEAD_TARGET} ${CACHE_TARGET}) | 
|  | endif() | 
|  |  | 
|  | if(${DEFINE_DEVICE_CACHE_PLACE_DELAY}) | 
|  | add_file_target(FILE ${PLACE_DELAY_FILENAME} GENERATED) | 
|  |  | 
|  | # Linearize target dependency. | 
|  | get_file_target(PLACE_DELAY_TARGET ${PLACE_DELAY_FILENAME}) | 
|  | add_dependencies(${PLACE_DELAY_TARGET} ${CACHE_TARGET}) | 
|  | endif() | 
|  |  | 
|  | if(NOT ${NO_RR_PATCHING}) | 
|  | add_file_target(FILE ${OUT_RR_REAL_FILENAME} GENERATED) | 
|  |  | 
|  | # Linearize target dependency. | 
|  | get_file_target(OUT_RR_REAL_TARGET ${OUT_RR_REAL_FILENAME}) | 
|  | add_dependencies(${OUT_RR_REAL_TARGET} ${CACHE_TARGET}) | 
|  | endif() | 
|  |  | 
|  | if(${DEFINE_DEVICE_CACHE_LOOKAHEAD} OR ${DEFINE_DEVICE_CACHE_PLACE_DELAY}) | 
|  | set_target_properties( | 
|  | ${DEFINE_DEVICE_DEVICE} | 
|  | PROPERTIES | 
|  | ${PACKAGE}_HAS_PLACE_DELAY_CACHE ${DEFINE_DEVICE_CACHE_PLACE_DELAY} | 
|  | ${PACKAGE}_HAS_LOOKAHEAD_CACHE ${DEFINE_DEVICE_CACHE_LOOKAHEAD} | 
|  | ${PACKAGE}_LOOKAHEAD_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${LOOKAHEAD_FILENAME} | 
|  | ${PACKAGE}_PLACE_DELAY_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${PLACE_DELAY_FILENAME} | 
|  | ) | 
|  | else() | 
|  | set_target_properties( | 
|  | ${DEFINE_DEVICE_DEVICE} | 
|  | PROPERTIES | 
|  | ${PACKAGE}_HAS_PLACE_DELAY_CACHE FALSE | 
|  | ${PACKAGE}_HAS_LOOKAHEAD_CACHE FALSE | 
|  | ) | 
|  | endif() | 
|  |  | 
|  | # Define dummy boards.  PROG_TOOL is set to false to disallow programming. | 
|  | define_board( | 
|  | BOARD dummy_${DEFINE_DEVICE_ARCH}_${DEFINE_DEVICE_DEVICE}_${PACKAGE} | 
|  | DEVICE ${DEFINE_DEVICE_DEVICE} | 
|  | PACKAGE ${PACKAGE} | 
|  | PROG_TOOL false | 
|  | ) | 
|  |  | 
|  | # Append the device to the device list of the arch. This is currently used | 
|  | # to determine whether the architecture is to be installed. Individual | 
|  | # devices get examined if no device is to be installed then installation | 
|  | # of the arch is skipped as well. | 
|  | get_target_property(DEVICES ${DEFINE_DEVICE_ARCH} DEVICES) | 
|  | if ("${DEVICES}" MATCHES ".*NOTFOUND") | 
|  | set(DEVICES "") | 
|  | endif () | 
|  |  | 
|  | list(APPEND DEVICES ${DEFINE_DEVICE_DEVICE}) | 
|  |  | 
|  | set_target_properties( | 
|  | ${DEFINE_DEVICE_ARCH} | 
|  | PROPERTIES | 
|  | DEVICES "${DEVICES}" | 
|  | ) | 
|  |  | 
|  | # Set the NO_INSTALL property and the list of extra files to be installed | 
|  | set_target_properties( | 
|  | ${DEFINE_DEVICE_DEVICE} | 
|  | PROPERTIES | 
|  | NO_INSTALL ${NO_INSTALL} | 
|  | EXTRA_INSTALL_FILES "${DEFINE_DEVICE_EXTRA_INSTALL_FILES}" | 
|  | ) | 
|  |  | 
|  | # Install device files. The function checks internally whether the files need to be installed | 
|  | install_device_files( | 
|  | PART ${PART} | 
|  | DEVICE ${DEFINE_DEVICE_DEVICE} | 
|  | DEVICE_TYPE ${DEFINE_DEVICE_DEVICE_TYPE} | 
|  | PACKAGE ${PACKAGE} | 
|  | ) | 
|  | endforeach() | 
|  |  | 
|  | endfunction() | 
|  |  | 
|  | function(DEFINE_BOARD) | 
|  | # ~~~ | 
|  | # DEFINE_BOARD( | 
|  | #   BOARD <board> | 
|  | #   DEVICE <device> | 
|  | #   PACKAGE <package> | 
|  | #   PROG_TOOL <prog_tool> | 
|  | #   [PROG_CMD <command to use PROG_TOOL> | 
|  | #   ) | 
|  | # ~~~ | 
|  | # | 
|  | # Defines a target board for a project.  The listed device and package must | 
|  | # have been defined using DEFINE_DEVICE. | 
|  | # | 
|  | # PROG_TOOL should be an executable that will program a bitstream to the | 
|  | # specified board. PROG_CMD is an optional command string.  If PROG_CMD is not | 
|  | # provided, PROG_CMD will simply be ${PROG_TOOL}. | 
|  | # | 
|  | set(options) | 
|  | set(oneValueArgs BOARD DEVICE PACKAGE PROG_TOOL PROG_CMD) | 
|  | set(multiValueArgs) | 
|  | cmake_parse_arguments( | 
|  | DEFINE_BOARD | 
|  | "${options}" | 
|  | "${oneValueArgs}" | 
|  | "${multiValueArgs}" | 
|  | ${ARGN} | 
|  | ) | 
|  |  | 
|  | add_custom_target(${DEFINE_BOARD_BOARD}) | 
|  | foreach(ARG DEVICE PACKAGE PROG_TOOL PROG_CMD) | 
|  | set_target_properties( | 
|  | ${DEFINE_BOARD_BOARD} | 
|  | PROPERTIES ${ARG} "${DEFINE_BOARD_${ARG}}" | 
|  | ) | 
|  | endforeach() | 
|  |  | 
|  | # Target for gathering all targets for a particular board. | 
|  |  | 
|  | add_custom_target(all_${DEFINE_BOARD_BOARD}_pack) | 
|  | add_custom_target(all_${DEFINE_BOARD_BOARD}_place) | 
|  | add_custom_target(all_${DEFINE_BOARD_BOARD}_route) | 
|  | add_custom_target(all_${DEFINE_BOARD_BOARD}_bin) | 
|  | endfunction() | 
|  |  | 
|  | function(ADD_OUTPUT_TO_FPGA_TARGET name property file) | 
|  | add_file_target(FILE ${file} GENERATED) | 
|  | set_target_properties(${name} PROPERTIES ${property} ${file}) | 
|  | endfunction() | 
|  |  | 
|  | set(VPR_BASE_ARGS | 
|  | --max_router_iterations 500 | 
|  | --routing_failure_predictor off | 
|  | --router_high_fanout_threshold -1 | 
|  | --constant_net_method route | 
|  | CACHE STRING "Base VPR arguments") | 
|  | set(VPR_EXTRA_ARGS "" CACHE STRING "Extra VPR arguments") | 
|  | function(ADD_FPGA_TARGET_BOARDS) | 
|  | # ~~~ | 
|  | # ADD_FPGA_TARGET_BOARDS( | 
|  | #   NAME <name> | 
|  | #   [TOP <top>] | 
|  | #   BOARDS <board list> | 
|  | #   SOURCES <source list> | 
|  | #   TESTBENCH_SOURCES <testbench source list> | 
|  | #   [IMPLICIT_INPUT_IO_FILES] | 
|  | #   [INPUT_IO_FILES <input_io_file list>] | 
|  | #   [EXPLICIT_ADD_FILE_TARGET] | 
|  | #   [EMIT_CHECK_TESTS EQUIV_CHECK_SCRIPT <yosys to script verify two bitstreams gold and gate>] | 
|  | #   ) | 
|  | # ~~~ | 
|  | # Version of ADD_FPGA_TARGET that emits targets for multiple boards. | 
|  | # | 
|  | # If INPUT_IO_FILES is supplied, BOARDS[i] will use INPUT_IO_FILES[i]. | 
|  | # | 
|  | # If IMPLICIT_INPUT_IO_FILES is supplied, INPUT_IO_FILES[i] will be set to | 
|  | # "BOARDS[i].pcf". | 
|  | # | 
|  | # Targets will be named <name>_<board>. | 
|  | # | 
|  | set(options EXPLICIT_ADD_FILE_TARGET EMIT_CHECK_TESTS IMPLICIT_INPUT_IO_FILES) | 
|  | set(oneValueArgs NAME TOP  EQUIV_CHECK_SCRIPT) | 
|  | set(multiValueArgs SOURCES BOARDS INPUT_IO_FILE TESTBENCH_SOURCES) | 
|  | cmake_parse_arguments( | 
|  | ADD_FPGA_TARGET_BOARDS | 
|  | "${options}" | 
|  | "${oneValueArgs}" | 
|  | "${multiValueArgs}" | 
|  | ${ARGN} | 
|  | ) | 
|  |  | 
|  | set(INPUT_IO_FILES ${ADD_FPGA_TARGET_BOARDS_INPUT_IO_FILES}) | 
|  | if(NOT "${INPUT_IO_FILES}" STREQUAL "" AND ${ADD_FPGA_TARGET_BOARDS_IMPLICIT_INPUT_IO_FILES}) | 
|  | message(FATAL_ERROR "Cannot request implicit IO files and supply explicit IO file list") | 
|  | endif() | 
|  |  | 
|  | set(BOARDS ${ADD_FPGA_TARGET_BOARDS_BOARDS}) | 
|  | list(LENGTH BOARDS NUM_BOARDS) | 
|  | if(${ADD_FPGA_TARGET_BOARDS_IMPLICIT_INPUT_IO_FILES}) | 
|  | foreach(BOARD ${BOARDS}) | 
|  | list(APPEND INPUT_IO_FILES ${BOARD}.pcf) | 
|  | endforeach() | 
|  | set(HAVE_IO_FILES TRUE) | 
|  | else() | 
|  | list(LENGTH INPUT_IO_FILES NUM_INPUT_IO_FILES) | 
|  | if(${NUM_INPUT_IO_FILES} GREATER 0) | 
|  | set(HAVE_IO_FILES TRUE) | 
|  | else() | 
|  | set(HAVE_IO_FILES FALSE) | 
|  | endif() | 
|  | if(${HAVE_IO_FILES} AND NOT ${NUM_INPUT_IO_FILES} EQUAL ${NUM_BOARDS}) | 
|  | message(FATAL_ERROR "Provide ${NUM_BOARDS} boards and ${NUM_INPUT_IO_FILES} io files, must be equal.") | 
|  | endif() | 
|  | endif() | 
|  |  | 
|  | if(NOT ${ADD_FPGA_TARGET_BOARDS_EXPLICIT_ADD_FILE_TARGET}) | 
|  | set(FILE_LIST  "") | 
|  | foreach(SRC ${ADD_FPGA_TARGET_BOARDS_SOURCES} ${ADD_FPGA_TARGET_BOARDS_TESTBENCH_SOURCES}) | 
|  | add_file_target(FILE ${SRC} SCANNER_TYPE verilog) | 
|  | endforeach() | 
|  | foreach(SRC ${INPUT_IO_FILES}) | 
|  | add_file_target(FILE ${SRC}) | 
|  | endforeach() | 
|  | endif() | 
|  |  | 
|  | set(OPT_ARGS "") | 
|  | foreach(OPT_STR_ARG TOP EQUIV_CHECK_SCRIPT) | 
|  | if("${ADD_FPGA_TARGET_BOARDS_${OPT_STR_ARG}}" STREQUAL "") | 
|  | list(APPEND OPT_ARGS ${OPT_STR_ARG} ${ADD_FPGA_TARGET_BOARDS_${OPT_STR_ARG}}) | 
|  | endif() | 
|  | endforeach() | 
|  | foreach(OPT_OPTION_ARG EMIT_CHECK_TESTS) | 
|  | if(${ADD_FPGA_TARGET_BOARDS_${OPT_OPTION_ARG}}) | 
|  | list(APPEND OPT_ARGS ${OPT_OPTION_ARG}) | 
|  | endif() | 
|  | endforeach() | 
|  | list(LENGTH ADD_FPGA_TARGET_BOARDS_TESTBENCH_SOURCES NUM_TESTBENCH_SOURCES) | 
|  | if($NUM_TESTBENCH_SOURCES} GREATER 0) | 
|  | list(APPEND OPT_ARGS TESTBENCH_SOURCES ${ADD_FPGA_TARGET_BOARDS_TESTBENCH_SOURCES}) | 
|  | endif() | 
|  |  | 
|  | math(EXPR NUM_BOARDS_MINUS_1 ${NUM_BOARDS}-1) | 
|  | foreach(IDX RANGE ${NUM_BOARDS_MINUS_1}) | 
|  | list(GET BOARDS ${IDX} BOARD) | 
|  | set(BOARD_OPT_ARGS ${OPT_ARGS}) | 
|  | if(${HAVE_IO_FILES}) | 
|  | list(GET INPUT_IO_FILES ${IDX} INPUT_IO_FILE) | 
|  | list(APPEND BOARD_OPT_ARGS INPUT_IO_FILE ${INPUT_IO_FILE}) | 
|  | endif() | 
|  | add_fpga_target( | 
|  | NAME ${ADD_FPGA_TARGET_BOARDS_NAME}_${BOARD} | 
|  | BOARD ${BOARD} | 
|  | SOURCES ${ADD_FPGA_TARGET_BOARDS_SOURCES} | 
|  | EXPLICIT_ADD_FILE_TARGET | 
|  | ${BOARD_OPT_ARGS} | 
|  | ) | 
|  | endforeach() | 
|  | endfunction() | 
|  |  | 
|  | function(ADD_BITSTREAM_TARGET) | 
|  | # ~~~ | 
|  | # ADD_BITSTREAM_TARGET( | 
|  | #   NAME <name> | 
|  | #   [USE_FASM] | 
|  | #   [OUT_LOCAL_REL <relative path to existing directory>] | 
|  | #   INCLUDED_TARGETS <target list> | 
|  | #   ) | 
|  | # ~~~ | 
|  | # | 
|  | # ADD_BITSTREAM_TARGET defines an FPGA bitstream target made up of one or more | 
|  | # FPGA targets. | 
|  | # | 
|  | # INCLUDED_TARGETS is a list of targets that should have their FASM merged before | 
|  | # generating a bitstream. If only one target is given, it will generate a bitstream | 
|  | # directly from the provided target's FASM. | 
|  | # | 
|  | # OUT_LOCAL_REL should be provided to add the target to an already existing directory. | 
|  | # | 
|  | # Targets generated: | 
|  | # | 
|  | # * <name>_bit - Generate output bitstream. | 
|  | # | 
|  | # Output files: | 
|  | # | 
|  | # * ${TOP}.${BITSTREAM_EXTENSION} - Bitstream for target. | 
|  | # | 
|  | set(options USE_FASM) | 
|  | set(oneValueArgs NAME OUT_LOCAL_REL) | 
|  | set(multiValueArgs INCLUDED_TARGETS) | 
|  | cmake_parse_arguments( | 
|  | ADD_BITSTREAM_TARGET | 
|  | "${options}" | 
|  | "${oneValueArgs}" | 
|  | "${multiValueArgs}" | 
|  | ${ARGN} | 
|  | ) | 
|  |  | 
|  |  | 
|  | set(NAME ${ADD_BITSTREAM_TARGET_NAME}) | 
|  | set(INCLUDED_TARGETS ${ADD_BITSTREAM_TARGET_INCLUDED_TARGETS}) | 
|  | set(USE_FASM ${ADD_BITSTREAM_TARGET_USE_FASM}) | 
|  | set(OUT_LOCAL_REL ${ADD_BITSTREAM_TARGET_OUT_LOCAL_REL}) | 
|  |  | 
|  | # Generate bitstream | 
|  | # ------------------------------------------------------------------------- | 
|  | set(ALL_OUT_FASM "") | 
|  | if(${USE_FASM}) | 
|  | foreach(TARGET ${INCLUDED_TARGETS}) | 
|  | get_target_property_required(BOARD ${TARGET} BOARD) | 
|  | get_target_property_required(DEVICE ${BOARD} DEVICE) | 
|  | get_target_property_required(DEVICE_TYPE ${DEVICE} DEVICE_TYPE) | 
|  | get_target_property(USE_OVERLAY ${DEVICE_TYPE} USE_OVERLAY) | 
|  | get_target_property_required(FASM ${TARGET} FASM) | 
|  | if ("${FASM_TO_BIT_DEPS}" STREQUAL "FASM_TO_BIT_DEPS-NOTFOUND") | 
|  | set(FASM_TO_BIT_DEPS "") | 
|  | endif() | 
|  |  | 
|  | append_file_location(ALL_OUT_FASM ${FASM}) | 
|  | append_file_dependency(ALL_OUT_FASM_DEPS ${FASM}) | 
|  |  | 
|  | if(USE_OVERLAY) | 
|  | if (NOT MAIN_TARGET) | 
|  | set(MAIN_TARGET ${TARGET}) | 
|  | else() | 
|  | message(FATAL_ERROR "More than one overlay device for ${BOARD}") | 
|  | endif() | 
|  | endif() | 
|  | endforeach() | 
|  |  | 
|  | if (NOT MAIN_TARGET) | 
|  | list(LENGTH ${INCLUDED_TARGETS} TARGETS_LENGTH) | 
|  | if(NOT ${TARGETS_LENGTH} EQUAL 0) | 
|  | message(FATAL_ERROR "Multiple devices but no overlay for ${BOARD}") | 
|  | endif() | 
|  | set(MAIN_TARGET ${INCLUDED_TARGETS}) | 
|  | endif() | 
|  |  | 
|  | get_target_property_required(MAIN_TARGET_BOARD ${MAIN_TARGET} BOARD) | 
|  | get_target_property_required(MAIN_TARGET_DEVICE ${MAIN_TARGET_BOARD} DEVICE) | 
|  | get_target_property_required(PACKAGE ${MAIN_TARGET_BOARD} PACKAGE) | 
|  | get_target_property_required(PYTHON3 env PYTHON3) | 
|  |  | 
|  | get_target_property(FASM_TO_BIT_EXTRA_ARGS ${MAIN_TARGET_BOARD} FASM_TO_BIT_EXTRA_ARGS) | 
|  | if ("${FASM_TO_BIT_EXTRA_ARGS}" STREQUAL "FASM_TO_BIT_EXTRA_ARGS-NOTFOUND") | 
|  | set(FASM_TO_BIT_EXTRA_ARGS "") | 
|  | endif() | 
|  |  | 
|  | get_target_property_required(TOP ${MAIN_TARGET} TOP) | 
|  | get_target_property_required(ARCH ${MAIN_TARGET_DEVICE} ARCH) | 
|  | get_target_property_required(BITSTREAM_EXTENSION ${ARCH} BITSTREAM_EXTENSION) | 
|  | get_target_property_required(FASM_TO_BIT ${ARCH} FASM_TO_BIT) | 
|  | get_target_property_required(FASM_TO_BIT_CMD ${ARCH} FASM_TO_BIT_CMD) | 
|  | get_target_property(FASM_TO_BIT_DEPS ${ARCH} FASM_TO_BIT_DEPS) | 
|  |  | 
|  | if(NOT OUT_LOCAL_REL) | 
|  | set(CREATE_NEW_DIR TRUE) | 
|  | set(FQDN ${ARCH}-${DEVICE_TYPE}-${DEVICE}-${PACKAGE}) | 
|  | set(OUT_LOCAL_REL ${NAME}/${FQDN}) | 
|  | set(OUT_LOCAL ${CMAKE_CURRENT_BINARY_DIR}/${OUT_LOCAL_REL}) | 
|  | set(MAIN_TARGET ${NAME}) | 
|  | add_custom_target(${NAME}) | 
|  | else() | 
|  | set(CREATE_NEW_DIR FALSE) | 
|  | set(OUT_LOCAL ${CMAKE_CURRENT_BINARY_DIR}/${OUT_LOCAL_REL}) | 
|  | endif() | 
|  |  | 
|  | set(OUT_FASM_MERGED ${OUT_LOCAL}/${TOP}.merged.fasm) | 
|  | set(OUT_BITSTREAM ${OUT_LOCAL}/${TOP}.${BITSTREAM_EXTENSION}) | 
|  |  | 
|  | set_target_properties(${NAME} PROPERTIES | 
|  | OUT_BITSTREAM ${OUT_BITSTREAM} | 
|  | ) | 
|  | set(BITSTREAM_DEPS ${ALL_OUT_FASM_DEPS} ${FASM_TO_BIT} ${FASM_TO_BIT_DEPS}) | 
|  |  | 
|  | set(OUT_FASM ${OUT_FASM_MERGED}) | 
|  | string(CONFIGURE ${FASM_TO_BIT_CMD} FASM_TO_BIT_CMD_FOR_TARGET) | 
|  | separate_arguments( | 
|  | FASM_TO_BIT_CMD_FOR_TARGET_LIST UNIX_COMMAND ${FASM_TO_BIT_CMD_FOR_TARGET} | 
|  | ) | 
|  |  | 
|  | separate_arguments( | 
|  | FASM_TO_BIT_EXTRA_ARGS_LIST UNIX_COMMAND ${FASM_TO_BIT_EXTRA_ARGS} | 
|  | ) | 
|  | set(FASM_TO_BIT_CMD_FOR_TARGET_LIST ${FASM_TO_BIT_CMD_FOR_TARGET_LIST} ${FASM_TO_BIT_EXTRA_ARGS_LIST}) | 
|  |  | 
|  | if(CREATE_NEW_DIR) | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_BITSTREAM} | 
|  | DEPENDS ${BITSTREAM_DEPS} | 
|  | COMMAND | 
|  | ${CMAKE_COMMAND} -E make_directory ${OUT_LOCAL} | 
|  | COMMAND cat ${ALL_OUT_FASM} > ${OUT_FASM_MERGED} | 
|  | COMMAND ${FASM_TO_BIT_CMD_FOR_TARGET_LIST} | 
|  | ) | 
|  | else() | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_BITSTREAM} | 
|  | DEPENDS ${BITSTREAM_DEPS} | 
|  | COMMAND cat ${ALL_OUT_FASM} > ${OUT_FASM_MERGED} | 
|  | COMMAND ${FASM_TO_BIT_CMD_FOR_TARGET_LIST} | 
|  | ) | 
|  | endif() | 
|  | else() | 
|  | get_target_property_required(HLC_TO_BIT ${ARCH} HLC_TO_BIT) | 
|  | get_target_property_required(HLC_TO_BIT_CMD ${ARCH} HLC_TO_BIT_CMD) | 
|  | string(CONFIGURE ${HLC_TO_BIT_CMD} HLC_TO_BIT_CMD_FOR_TARGET) | 
|  | separate_arguments( | 
|  | HLC_TO_BIT_CMD_FOR_TARGET_LIST UNIX_COMMAND ${HLC_TO_BIT_CMD_FOR_TARGET} | 
|  | ) | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_BITSTREAM} | 
|  | DEPENDS ${OUT_HLC} ${HLC_TO_BIT} | 
|  | COMMAND ${HLC_TO_BIT_CMD_FOR_TARGET_LIST} | 
|  | ) | 
|  | endif() | 
|  |  | 
|  | add_custom_target(${NAME}_bit DEPENDS ${OUT_BITSTREAM}) | 
|  | add_output_to_fpga_target(${NAME} BIT ${OUT_LOCAL_REL}/${TOP}.${BITSTREAM_EXTENSION}) | 
|  |  | 
|  | get_target_property_required(NO_BIT_TO_BIN ${ARCH} NO_BIT_TO_BIN) | 
|  | set(OUT_BIN ${OUT_BITSTREAM}) | 
|  | if(NOT ${NO_BIT_TO_BIN}) | 
|  | get_target_property_required(BIN_EXTENSION ${ARCH} BIN_EXTENSION) | 
|  | set(OUT_BIN ${OUT_LOCAL}/${TOP}.${BIN_EXTENSION}) | 
|  | get_target_property_required(BIT_TO_BIN ${ARCH} BIT_TO_BIN) | 
|  | get_target_property_required(BIT_TO_BIN_CMD ${ARCH} BIT_TO_BIN_CMD) | 
|  | get_target_property(BIT_TO_BIN_EXTRA_ARGS ${BOARD} BIT_TO_BIN_EXTRA_ARGS) | 
|  | if (${BIT_TO_BIN_EXTRA_ARGS} STREQUAL NOTFOUND) | 
|  | set(BIT_TO_BIN_EXTRA_ARGS "") | 
|  | endif() | 
|  | string(CONFIGURE ${BIT_TO_BIN_CMD} BIT_TO_BIN_CMD_FOR_TARGET) | 
|  | separate_arguments( | 
|  | BIT_TO_BIN_CMD_FOR_TARGET_LIST UNIX_COMMAND ${BIT_TO_BIN_CMD_FOR_TARGET} | 
|  | ) | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_BIN} | 
|  | COMMAND ${BIT_TO_BIN_CMD_FOR_TARGET_LIST} | 
|  | DEPENDS ${BIT_TO_BIN} ${OUT_BITSTREAM} | 
|  | ) | 
|  |  | 
|  | add_custom_target(${NAME}_bin DEPENDS ${OUT_BIN}) | 
|  | add_output_to_fpga_target(${NAME} BIN ${OUT_LOCAL_REL}/${TOP}.${BIN_EXTENSION}) | 
|  | add_dependencies(all_${BOARD}_bin ${NAME}_bin) | 
|  | else() | 
|  | add_dependencies(all_${BOARD}_bin ${NAME}_bit) | 
|  | endif() | 
|  |  | 
|  | get_target_property(PROG_TOOL ${BOARD} PROG_TOOL) | 
|  | get_target_property(PROG_CMD ${BOARD} PROG_CMD) | 
|  |  | 
|  | if("${PROG_CMD}" STREQUAL "${BOARD}-NOTFOUND" OR "${PROG_CMD}" STREQUAL "") | 
|  | set(PROG_CMD_LIST ${PROG_TOOL} ${OUT_BIN}) | 
|  | else() | 
|  | string(CONFIGURE ${PROG_CMD} PROG_CMD_FOR_TARGET) | 
|  | separate_arguments( | 
|  | PROG_CMD_LIST UNIX_COMMAND ${PROG_CMD_FOR_TARGET} | 
|  | ) | 
|  | endif() | 
|  |  | 
|  | add_custom_target( | 
|  | ${NAME}_prog | 
|  | COMMAND ${PROG_CMD_LIST} | 
|  | DEPENDS ${OUT_BIN} ${PROG_TOOL} | 
|  | ) | 
|  |  | 
|  | endfunction() | 
|  |  | 
|  | function(ADD_FPGA_TARGET) | 
|  | # ~~~ | 
|  | # ADD_FPGA_TARGET( | 
|  | #   NAME <name> | 
|  | #   [TOP <top>] | 
|  | #   BOARD <board> | 
|  | #   SOURCES <source list> | 
|  | #   TESTBENCH_SOURCES <testbench source list> | 
|  | #   [INPUT_IO_FILE <input_io_file>] | 
|  | #   [INPUT_XDC_FILES <input_xdc_files>] | 
|  | #   [INPUT_SDC_FILE <input_sdc_file>] | 
|  | #   [EXPLICIT_ADD_FILE_TARGET] | 
|  | #   [AUTO_ADD_FILE_TARGET] | 
|  | #   [EMIT_CHECK_TESTS EQUIV_CHECK_SCRIPT <yosys to script verify two bitstreams gold and gate>] | 
|  | #   [NO_SYNTHESIS] | 
|  | #   [ASSERT_BLOCK_TYPES_ARE_USED <usage_spec>] | 
|  | #   [ASSERT_TIMING <timing_spec>] | 
|  | #   [DEFINES <definitions>] | 
|  | #   [BIT_TO_V_EXTRA_ARGS] | 
|  | #   [NET_PATCH_EXTRA_ARGS] | 
|  | #   [INSTALL_CIRCUIT] | 
|  | #   ) | 
|  | # ~~~ | 
|  | # | 
|  | # ADD_FPGA_TARGET defines a FPGA build targetting a specific board.  By | 
|  | # default input files (SOURCES, TESTBENCH_SOURCES, INPUT_IO_FILE) will be | 
|  | # implicitly passed to ADD_FILE_TARGET. If EXPLICIT_ADD_FILE_TARGET is | 
|  | # supplied, this behavior is supressed. | 
|  | # When AUTO_ADD_FILE_TARGETS is specified file targets will be created only if | 
|  | # they do not exist already. AUTO_ADD_FILE_TARGETS is useful when multiple | 
|  | # test designs share the same source files and there is no immediate possibility | 
|  | # for putting CMakeLists.txt files along with them to define targets for | 
|  | # EXPLICIT_ADD_FILE_TARGET. This is used for example in QuickLogic tests, | 
|  | # there is a separate submodule with test designs that are used by | 
|  | # multiple architectures (pp3, qlf_k4n8). | 
|  | # | 
|  | # TOP is the name of the top-level module in the design.  If no supplied, | 
|  | # TOP is set to "top". | 
|  | # | 
|  | # The SOURCES file list will be used to synthesize the FPGA images. | 
|  | # INPUT_IO_FILE is required to define an io map. TESTBENCH_SOURCES will be | 
|  | # used to run test benches. | 
|  | # | 
|  | # The INPUT_XDC_FILES can contain both placement constraints as well as clock | 
|  | # timing constraints. | 
|  | # | 
|  | # The INPUT_SDC_FILE contains VPR timing constraints and overwrites the SDC file | 
|  | # generated by the SDC yosys plugin. | 
|  | # | 
|  | # If NO_SYNTHESIS is supplied, <source list> must be 1 eblif file. | 
|  | # | 
|  | # ASSERT_BLOCK_TYPES_ARE_USED enables tests that verify the usage of specific | 
|  | # block types against <usage_spec> which is a comma-separated list of | 
|  | # relational expressions regarding the usage of block types, e.g: | 
|  | # 	ASSERT_BLOCK_TYPES_ARE_USED	PB-CLOCK=1,PB-GMUX=1,PB-BIDIR=4 | 
|  | # supported operators: =, <, <=, >, >= | 
|  | # | 
|  | # ASSERT_TIMING enables tests that verify the timings of routed design | 
|  | # against <timing_spec> which is a comma-separated list of | 
|  | # relational expressions regarding design timing parameters, e.g: | 
|  | # 	ASSERT_TIMING	fmax>=20.5 | 
|  | # supported operators: =, <, <=, >, >= | 
|  | # | 
|  | # DEFINES is a list of environment variables to be defined during Yosys | 
|  | # invocation. | 
|  | # | 
|  | # NET_PATCH_EXTRA_ARGS allows to specify extra design-specific arguments to | 
|  | # the packed netlist patching utility (if any). | 
|  | # | 
|  | # INSTALL_CIRCUIT is an option that enables installing the generated eblif circuit | 
|  | # file in the install destination directory. Also the generates/user-provided SDC | 
|  | # (if present), gets installed as well. | 
|  | #     - eblif destination: <install_directory>/benchmarks/circuits | 
|  | #     - sdc destination: <install_directory>/benchmarks/sdc | 
|  | # To avoid name conflicts, the eblif file name, as well as the SDC name, are replaced | 
|  | # with the NAME of the FPGA test target | 
|  | # | 
|  | # Targets generated: | 
|  | # | 
|  | # * <name>_eblif - Generated eblif file. | 
|  | # * <name>_route - Generate place and routing synthesized design. | 
|  | # * <name>_bit - Generate output bitstream. | 
|  | # | 
|  | # Outputs for this target will all be located in | 
|  | # ~~~ | 
|  | # ${CMAKE_CURRENT_BINARY_DIR}/${NAME}/${ARCH}-${DEVICE_TYPE}-${DEVICE}-${PACKAGE} | 
|  | # ~~~ | 
|  | # | 
|  | # Output files: | 
|  | # | 
|  | # * ${TOP}.eblif - Synthesized design (http://docs.verilogtorouting.org/en/latest/vpr/file_formats/#extended-blif-eblif) | 
|  | # * ${TOP}_io.place - IO placement. | 
|  | # * ${TOP}.route - Place and routed design (http://docs.verilogtorouting.org/en/latest/vpr/file_formats/#routing-file-format-route) | 
|  | # * ${TOP}.${BITSTREAM_EXTENSION} - Bitstream for target. | 
|  | # | 
|  | set(options EXPLICIT_ADD_FILE_TARGET AUTO_ADD_FILE_TARGET EMIT_CHECK_TESTS NO_SYNTHESIS ROUTE_ONLY INSTALL_CIRCUIT) | 
|  | set(oneValueArgs NAME TOP BOARD INPUT_IO_FILE EQUIV_CHECK_SCRIPT AUTOSIM_CYCLES ASSERT_BLOCK_TYPES_ARE_USED ASSERT_TIMING INPUT_SDC_FILE) | 
|  | set(multiValueArgs SOURCES TESTBENCH_SOURCES DEFINES BIT_TO_V_EXTRA_ARGS INPUT_XDC_FILES NET_PATCH_EXTRA_ARGS) | 
|  | cmake_parse_arguments( | 
|  | ADD_FPGA_TARGET | 
|  | "${options}" | 
|  | "${oneValueArgs}" | 
|  | "${multiValueArgs}" | 
|  | ${ARGN} | 
|  | ) | 
|  |  | 
|  | get_target_property_required(PYTHON3 env PYTHON3) | 
|  |  | 
|  | set(TOP "top") | 
|  | if(NOT "${ADD_FPGA_TARGET_TOP}" STREQUAL "") | 
|  | set(TOP ${ADD_FPGA_TARGET_TOP}) | 
|  | endif() | 
|  |  | 
|  | set(BOARD ${ADD_FPGA_TARGET_BOARD}) | 
|  | if("${BOARD}" STREQUAL "") | 
|  | message(FATAL_ERROR "BOARD is a required parameters.") | 
|  | endif() | 
|  |  | 
|  | get_target_property_required(DEVICE ${BOARD} DEVICE) | 
|  | get_target_property_required(PACKAGE ${BOARD} PACKAGE) | 
|  |  | 
|  | get_target_property_required(ARCH ${DEVICE} ARCH) | 
|  | get_target_property_required(DEVICE_TYPE ${DEVICE} DEVICE_TYPE) | 
|  |  | 
|  | get_target_property_required(YOSYS env YOSYS) | 
|  | get_target_property_required(QUIET_CMD env QUIET_CMD) | 
|  |  | 
|  | get_target_property(YOSYS_SYNTH_SCRIPT ${ARCH} YOSYS_SYNTH_SCRIPT) | 
|  | if("${YOSYS_SYNTH_SCRIPT}" STREQUAL "") | 
|  | execute_process( | 
|  | COMMAND python3 -m f4pga.wrappers.tcl ${ARCH} | 
|  | COMMAND_ERROR_IS_FATAL ANY | 
|  | OUTPUT_VARIABLE YOSYS_SYNTH_SCRIPT | 
|  | OUTPUT_STRIP_TRAILING_WHITESPACE | 
|  | ) | 
|  | message("YOSYS_SYNTH_SCRIPT is ${YOSYS_SYNTH_SCRIPT}.") | 
|  | endif() | 
|  |  | 
|  | get_target_property_required( | 
|  | DEVICE_MERGED_FILE ${DEVICE_TYPE} DEVICE_MERGED_FILE | 
|  | ) | 
|  | get_target_property_required( | 
|  | OUT_RRBIN_REAL ${DEVICE} ${PACKAGE}_OUT_RRBIN_REAL | 
|  | ) | 
|  |  | 
|  | list(LENGTH ADD_FPGA_TARGET_INPUT_XDC_FILES XDCS_COUNT) | 
|  | if(${XDCS_COUNT} GREATER "0") | 
|  | get_target_property_required(PART_JSON ${BOARD} PART_JSON) | 
|  | endif() | 
|  |  | 
|  | set(NAME ${ADD_FPGA_TARGET_NAME}) | 
|  | get_target_property_required(DEVICE_FULL_TEMPLATE ${ARCH} DEVICE_FULL_TEMPLATE) | 
|  | string(CONFIGURE ${DEVICE_FULL_TEMPLATE} DEVICE_FULL) | 
|  | set(FQDN ${ARCH}-${DEVICE_TYPE}-${DEVICE}-${PACKAGE}) | 
|  | set(OUT_LOCAL_REL ${NAME}/${FQDN}) | 
|  | set(OUT_LOCAL ${CMAKE_CURRENT_BINARY_DIR}/${OUT_LOCAL_REL}) | 
|  |  | 
|  | # Create target to handle all output paths of off | 
|  | add_custom_target(${NAME}) | 
|  | set_target_properties(${NAME} PROPERTIES | 
|  | TOP ${TOP} | 
|  | BOARD ${BOARD} | 
|  | ) | 
|  | set(VPR_ROUTE_CHAN_WIDTH 100) | 
|  | set(VPR_ROUTE_CHAN_MINWIDTH_HINT ${VPR_ROUTE_CHAN_WIDTH}) | 
|  |  | 
|  | if(${ADD_FPGA_TARGET_NO_SYNTHESIS}) | 
|  | list(LENGTH ADD_FPGA_TARGET_SOURCES SRC_COUNT) | 
|  | if(NOT ${SRC_COUNT} EQUAL 1) | 
|  | message(FATAL_ERROR "In NO_SYNTHESIS, only one input source is allowed, given ${SRC_COUNT}.") | 
|  | endif() | 
|  | set(READ_FUNCTION "read_blif") | 
|  | else() | 
|  | set(READ_FUNCTION "read_verilog") | 
|  | endif() | 
|  |  | 
|  | if(NOT ${ADD_FPGA_TARGET_EXPLICIT_ADD_FILE_TARGET}) | 
|  | if(NOT ${ADD_FPGA_TARGET_NO_SYNTHESIS}) | 
|  | foreach(SRC ${ADD_FPGA_TARGET_SOURCES}) | 
|  | get_file_target(FILE_TARGET ${SRC}) | 
|  | if(NOT ${ADD_FPGA_TARGET_AUTO_ADD_FILE_TARGET} OR NOT TARGET ${FILE_TARGET}) | 
|  | add_file_target(FILE ${SRC} SCANNER_TYPE verilog) | 
|  | endif() | 
|  | endforeach() | 
|  | else() | 
|  | foreach(SRC ${ADD_FPGA_TARGET_SOURCES}) | 
|  | get_file_target(FILE_TARGET ${SRC}) | 
|  | if(NOT ${ADD_FPGA_TARGET_AUTO_ADD_FILE_TARGET} OR NOT TARGET ${FILE_TARGET}) | 
|  | add_file_target(FILE ${SRC}) | 
|  | endif() | 
|  | endforeach() | 
|  | endif() | 
|  |  | 
|  | foreach(SRC ${ADD_FPGA_TARGET_TESTBENCH_SOURCES}) | 
|  | get_file_target(FILE_TARGET ${SRC}) | 
|  | if(NOT ${ADD_FPGA_TARGET_AUTO_ADD_FILE_TARGET} OR NOT TARGET ${FILE_TARGET}) | 
|  | add_file_target(FILE ${SRC} SCANNER_TYPE verilog) | 
|  | endif() | 
|  | endforeach() | 
|  |  | 
|  | if(NOT "${ADD_FPGA_TARGET_INPUT_IO_FILE}" STREQUAL "") | 
|  | get_file_target(FILE_TARGET ${ADD_FPGA_TARGET_INPUT_IO_FILE}) | 
|  | if(NOT ${ADD_FPGA_TARGET_AUTO_ADD_FILE_TARGET} OR NOT TARGET ${FILE_TARGET}) | 
|  | add_file_target(FILE ${ADD_FPGA_TARGET_INPUT_IO_FILE}) | 
|  | endif() | 
|  | endif() | 
|  |  | 
|  | foreach(XDC ${ADD_FPGA_TARGET_INPUT_XDC_FILES}) | 
|  | get_file_target(FILE_TARGET ${XDC}) | 
|  | if(NOT ${ADD_FPGA_TARGET_AUTO_ADD_FILE_TARGET} OR NOT TARGET ${FILE_TARGET}) | 
|  | add_file_target(FILE ${XDC}) | 
|  | endif() | 
|  | endforeach() | 
|  |  | 
|  | if(NOT "${ADD_FPGA_TARGET_INPUT_SDC_FILE}" STREQUAL "") | 
|  | get_file_target(FILE_TARGET ${SDC}) | 
|  | if(NOT ${ADD_FPGA_TARGET_AUTO_ADD_FILE_TARGET} OR NOT TARGET ${FILE_TARGET}) | 
|  | add_file_target(FILE ${ADD_FPGA_TARGET_INPUT_SDC_FILE}) | 
|  | endif() | 
|  | endif() | 
|  | endif() | 
|  |  | 
|  | foreach(XDC ${ADD_FPGA_TARGET_INPUT_XDC_FILES}) | 
|  | append_file_location(INPUT_XDC_FILES ${XDC}) | 
|  | append_file_dependency(YOSYS_IO_DEPS ${XDC}) | 
|  | endforeach() | 
|  |  | 
|  | # | 
|  | # Generate BLIF as start of vpr input. | 
|  | # | 
|  | set(OUT_EBLIF ${OUT_LOCAL}/${TOP}.eblif) | 
|  | set(OUT_EBLIF_REL ${OUT_LOCAL_REL}/${TOP}.eblif) | 
|  | set(OUT_SYNTH_V ${OUT_LOCAL}/${TOP}_synth.v) | 
|  | set(OUT_SYNTH_V_REL ${OUT_LOCAL_REL}/${TOP}_synth.v) | 
|  | set(OUT_FASM_EXTRA ${OUT_LOCAL}/${TOP}_fasm_extra.fasm) | 
|  |  | 
|  | # SDC timing constraints file required by VPR. | 
|  | # This file is automatically generated when reading the XDC constraints | 
|  | # and contains all the design's clock signals in the SDC format. | 
|  | # | 
|  | # In case this function is called with both the INPUT_SDC_FILE and INPUT_XDC_FILES parameters, | 
|  | # the user-provided SDC file is used in VPR rather than the auto-generated one. | 
|  | set(OUT_SDC ${OUT_LOCAL}/${TOP}_synth.sdc) | 
|  | set(OUT_SDC_REL ${OUT_LOCAL_REL}/${TOP}_synth.sdc) | 
|  |  | 
|  | set(SOURCE_FILES_DEPS "") | 
|  | set(SOURCE_FILES "") | 
|  | foreach(SRC ${ADD_FPGA_TARGET_SOURCES}) | 
|  | append_file_location(SOURCE_FILES ${SRC}) | 
|  | append_file_dependency(SOURCE_FILES_DEPS ${SRC}) | 
|  | endforeach() | 
|  |  | 
|  | set(CELLS_SIM_DEPS "") | 
|  | get_cells_sim_path(PATH_TO_CELLS_SIM ${ARCH}) | 
|  | foreach(CELL ${PATH_TO_CELLS_SIM}) | 
|  | get_file_target(CELL_TARGET ${CELL}) | 
|  | list(APPEND CELLS_SIM_DEPS ${CELL_TARGET}) | 
|  | endforeach() | 
|  |  | 
|  | set(YOSYS_IO_DEPS "") | 
|  |  | 
|  | if(NOT ${ADD_FPGA_TARGET_INPUT_IO_FILE} STREQUAL "" OR ${XDCS_COUNT} GREATER "0") | 
|  | get_target_property_required(PINMAP_FILE ${BOARD} PINMAP) | 
|  | get_file_location(PINMAP ${PINMAP_FILE}) | 
|  | get_target_property(PINMAP_XML_FILE ${BOARD} PINMAP_XML) | 
|  | if(NOT "${PINMAP_XML_FILE}" MATCHES ".*-NOTFOUND") | 
|  | get_file_location(PINMAP_XML ${PINMAP_XML_FILE}) | 
|  | endif() | 
|  | append_file_dependency(YOSYS_IO_DEPS ${PINMAP_FILE}) | 
|  | endif() | 
|  |  | 
|  | if(NOT ${ADD_FPGA_TARGET_INPUT_IO_FILE} STREQUAL "") | 
|  | get_file_location(INPUT_IO_FILE ${ADD_FPGA_TARGET_INPUT_IO_FILE}) | 
|  | append_file_dependency(YOSYS_IO_DEPS ${ADD_FPGA_TARGET_INPUT_IO_FILE}) | 
|  | endif() | 
|  |  | 
|  | if(NOT ${ADD_FPGA_TARGET_NO_SYNTHESIS}) | 
|  | set(OUT_JSON_SYNTH ${OUT_LOCAL}/${TOP}_synth.json) | 
|  | set(OUT_JSON_SYNTH_REL ${OUT_LOCAL_REL}/${TOP}_synth.json) | 
|  | set(OUT_JSON ${OUT_LOCAL}/${TOP}.json) | 
|  | set(OUT_JSON_REL ${OUT_LOCAL_REL}/${TOP}.json) | 
|  |  | 
|  | get_target_property(USE_ROI ${DEVICE_TYPE} USE_ROI) | 
|  | if("${USE_ROI}" STREQUAL "NOTFOUND") | 
|  | set(USE_ROI FALSE) | 
|  | endif() | 
|  | # TECHMAP is optional for ARCH. We don't care if this is NOTFOUND | 
|  | # as targets not defining it should not use TECHMAP_PATH ENV variable | 
|  | get_target_property(YOSYS_TECHMAP ${ARCH} YOSYS_TECHMAP) | 
|  |  | 
|  | # Device type specific cells and techmap | 
|  | get_target_property(YOSYS_DEVICE_CELLS_SIM ${DEVICE_TYPE} CELLS_SIM) | 
|  | get_target_property(YOSYS_DEVICE_CELLS_MAP ${DEVICE_TYPE} CELLS_MAP) | 
|  |  | 
|  | if (NOT "${YOSYS_DEVICE_CELLS_SIM}" MATCHES ".*NOTFOUND") | 
|  | get_file_target(YOSYS_DEVICE_CELLS_SIM_TARGET ${YOSYS_DEVICE_CELLS_SIM}) | 
|  | get_file_location(YOSYS_DEVICE_CELLS_SIM ${YOSYS_DEVICE_CELLS_SIM}) | 
|  | list(APPEND CELLS_SIM_DEPS ${YOSYS_DEVICE_CELLS_SIM} ${YOSYS_DEVICE_CELLS_SIM_TARGET}) | 
|  | else () | 
|  | set(YOSYS_DEVICE_CELLS_SIM "") | 
|  | endif() | 
|  |  | 
|  | if (NOT "${YOSYS_DEVICE_CELLS_MAP}" MATCHES ".*NOTFOUND") | 
|  | get_file_target(YOSYS_DEVICE_CELLS_MAP_TARGET ${YOSYS_DEVICE_CELLS_MAP}) | 
|  | get_file_location(YOSYS_DEVICE_CELLS_MAP ${YOSYS_DEVICE_CELLS_MAP}) | 
|  | list(APPEND CELLS_SIM_DEPS ${YOSYS_DEVICE_CELLS_MAP} ${YOSYS_DEVICE_CELLS_MAP_TARGET}) | 
|  | else () | 
|  | set(YOSYS_DEVICE_CELLS_MAP "") | 
|  | endif() | 
|  |  | 
|  | # Convert list of XDCs to string | 
|  | string(REPLACE ";" " " XDC_FILES "${INPUT_XDC_FILES}") | 
|  |  | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_JSON_SYNTH} ${OUT_SYNTH_V} ${OUT_FASM_EXTRA} ${OUT_SDC} ${OUT_EBLIF} | 
|  | DEPENDS ${SOURCE_FILES} ${SOURCE_FILES_DEPS} ${INPUT_XDC_FILES} ${CELLS_SIM_DEPS} | 
|  | ${YOSYS} ${QUIET_CMD} ${YOSYS_IO_DEPS} | 
|  | ${YOSYS_SYNTH_SCRIPT} | 
|  | COMMAND | 
|  | ${CMAKE_COMMAND} -E make_directory ${OUT_LOCAL} | 
|  | COMMAND | 
|  | ${CMAKE_COMMAND} -E env | 
|  | TECHMAP_PATH=${YOSYS_TECHMAP} | 
|  | UTILS_PATH=${f4pga-arch-defs_SOURCE_DIR}/utils | 
|  | DEVICE_CELLS_SIM=${YOSYS_DEVICE_CELLS_SIM} | 
|  | DEVICE_CELLS_MAP=${YOSYS_DEVICE_CELLS_MAP} | 
|  | OUT_JSON=${OUT_JSON_SYNTH} | 
|  | SYNTH_JSON=${OUT_JSON} | 
|  | OUT_EBLIF=${OUT_EBLIF} | 
|  | OUT_SYNTH_V=${OUT_SYNTH_V} | 
|  | OUT_FASM_EXTRA=${OUT_FASM_EXTRA} | 
|  | PART_JSON=${PART_JSON} | 
|  | INPUT_XDC_FILES=${XDC_FILES} | 
|  | OUT_SDC=${OUT_SDC} | 
|  | USE_ROI=${USE_ROI} | 
|  | PCF_FILE=${INPUT_IO_FILE} | 
|  | PINMAP_FILE=${PINMAP} | 
|  | PYTHON3=${PYTHON3} | 
|  | ${ADD_FPGA_TARGET_DEFINES} | 
|  | ${QUIET_CMD} ${YOSYS} -r ${TOP} -p "tcl ${YOSYS_SYNTH_SCRIPT}" -l ${OUT_JSON_SYNTH}.log ${SOURCE_FILES} | 
|  | COMMAND | 
|  | ${CMAKE_COMMAND} -E touch ${OUT_FASM_EXTRA} | 
|  | COMMAND | 
|  | ${CMAKE_COMMAND} -E touch ${OUT_SDC} | 
|  | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} | 
|  | VERBATIM | 
|  | ) | 
|  |  | 
|  | add_output_to_fpga_target(${NAME} EBLIF ${OUT_EBLIF_REL}) | 
|  | add_output_to_fpga_target(${NAME} SYNTH_V ${OUT_SYNTH_V_REL}) | 
|  | add_output_to_fpga_target(${NAME} JSON_SYNTH ${OUT_JSON_SYNTH_REL}) | 
|  | add_output_to_fpga_target(${NAME} JSON ${OUT_JSON_REL}) | 
|  | add_output_to_fpga_target(${NAME} SDC ${OUT_SDC_REL}) | 
|  |  | 
|  | else() | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_EBLIF} | 
|  | DEPENDS ${SOURCE_FILES_DEPS} | 
|  | COMMAND | 
|  | ${CMAKE_COMMAND} -E make_directory ${OUT_LOCAL} | 
|  | COMMAND ${CMAKE_COMMAND} -E copy ${SOURCE_FILES} ${OUT_EBLIF} | 
|  | ) | 
|  | add_output_to_fpga_target(${NAME} EBLIF ${OUT_EBLIF_REL}) | 
|  | endif() | 
|  |  | 
|  | add_custom_target(${NAME}_eblif DEPENDS ${OUT_EBLIF}) | 
|  |  | 
|  | set(VPR_DEPS "") | 
|  |  | 
|  | set(SDC_ARG "") | 
|  | if(${XDCS_COUNT} GREATER "0" AND | 
|  | NOT "${ADD_FPGA_TARGET_INPUT_SDC_FILE}" STREQUAL "") | 
|  | message(FATAL_ERROR "SDC and XDC constraint files cannot be provided simultaneously!") | 
|  | endif() | 
|  |  | 
|  | set(SDC_FILE "") | 
|  | set(SDC_DEPS "") | 
|  | if(${XDCS_COUNT} GREATER "0") | 
|  | append_file_dependency(VPR_DEPS ${OUT_SDC_REL}) | 
|  | get_file_location(SDC_LOCATION ${OUT_SDC_REL}) | 
|  | set(SDC_ARG --sdc_file ${SDC_LOCATION}) | 
|  | set(SDC_FILE ${SDC_LOCATION}) | 
|  | append_file_dependency(SDC_DEPS ${OUT_SDC_REL}) | 
|  | set(SDC_DEPS ${OUT_SDC_REL}) | 
|  | endif() | 
|  |  | 
|  | if(NOT "${ADD_FPGA_TARGET_INPUT_SDC_FILE}" STREQUAL "") | 
|  | append_file_dependency(VPR_DEPS ${ADD_FPGA_TARGET_INPUT_SDC_FILE}) | 
|  | get_file_location(SDC_LOCATION ${ADD_FPGA_TARGET_INPUT_SDC_FILE}) | 
|  | set(SDC_ARG --sdc_file ${SDC_LOCATION}) | 
|  | set(SDC_FILE ${SDC_LOCATION}) | 
|  | set(SDC_DEPS ${ADD_FPGA_TARGET_INPUT_SDC_FILE}) | 
|  | append_file_dependency(SDC_DEPS ${ADD_FPGA_TARGET_INPUT_SDC_FILE}) | 
|  | endif() | 
|  |  | 
|  | # Process SDC | 
|  | # ------------------------------------------------------------------------- | 
|  | get_target_property(SDC_PATCH_TOOL     ${ARCH} SDC_PATCH_TOOL) | 
|  | get_target_property(SDC_PATCH_TOOL_CMD ${ARCH} SDC_PATCH_TOOL_CMD) | 
|  |  | 
|  | if (NOT "${SDC_PATCH_TOOL}" MATCHES ".*-NOTFOUND" AND | 
|  | NOT "${SDC_PATCH_TOOL}" STREQUAL "" AND | 
|  | NOT "${SDC_FILE}" STREQUAL "" AND | 
|  | NOT "${INPUT_IO_FILE}" STREQUAL "") | 
|  |  | 
|  | set(IN_SDC ${SDC_FILE}) | 
|  |  | 
|  | set(OUT_SDC ${OUT_LOCAL}/${TOP}.patched.sdc) | 
|  | set(OUT_SDC_REL ${OUT_LOCAL_REL}/${TOP}.patched.sdc) | 
|  |  | 
|  | # Configure the base command | 
|  | string(CONFIGURE ${SDC_PATCH_TOOL_CMD} SDC_PATCH_TOOL_CMD_FOR_TARGET) | 
|  | separate_arguments( | 
|  | SDC_PATCH_TOOL_CMD_FOR_TARGET_LIST UNIX_COMMAND ${SDC_PATCH_TOOL_CMD_FOR_TARGET} | 
|  | ) | 
|  |  | 
|  | # Configure and append device-specific extra args | 
|  | get_target_property(SDC_PATCH_EXTRA_ARGS ${DEVICE} SDC_PATCH_EXTRA_ARGS) | 
|  | if (NOT "${SDC_PATCH_EXTRA_ARGS}" MATCHES ".*NOTFOUND") | 
|  | string(CONFIGURE ${SDC_PATCH_EXTRA_ARGS} SDC_PATCH_EXTRA_ARGS_FOR_TARGET) | 
|  | separate_arguments( | 
|  | SDC_PATCH_EXTRA_ARGS_FOR_TARGET_LIST UNIX_COMMAND ${SDC_PATCH_EXTRA_ARGS_FOR_TARGET} | 
|  | ) | 
|  | else() | 
|  | set(SDC_PATCH_EXTRA_ARGS_FOR_TARGET_LIST) | 
|  | endif() | 
|  |  | 
|  | # Configure and append design-specific extra args | 
|  | set(SDC_PATCH_DESIGN_EXTRA_ARGS ${ADD_FPGA_TARGET_SDC_PATCH_EXTRA_ARGS}) | 
|  | if (NOT "${SDC_PATCH_DESIGN_EXTRA_ARGS}" STREQUAL "") | 
|  | string(CONFIGURE ${SDC_PATCH_DESIGN_EXTRA_ARGS} SDC_PATCH_DESIGN_EXTRA_ARGS_FOR_TARGET) | 
|  | separate_arguments( | 
|  | SDC_PATCH_DESIGN_EXTRA_ARGS_FOR_TARGET_LIST UNIX_COMMAND ${SDC_PATCH_DESIGN_EXTRA_ARGS_FOR_TARGET} | 
|  | ) | 
|  | else() | 
|  | set(SDC_PATCH_DESIGN_EXTRA_ARGS_FOR_TARGET_LIST) | 
|  | endif() | 
|  |  | 
|  | # Extra dependencies | 
|  | get_target_property(SDC_PATCH_DEPS ${DEVICE} SDC_PATCH_DEPS) | 
|  | if ("${SDC_PATCH_DEPS}" MATCHES ".*NOTFOUND") | 
|  | set(SDC_PATCH_DEPS) | 
|  | endif () | 
|  |  | 
|  | # Add targets for patched SDC | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_SDC} | 
|  | DEPENDS ${SDC_DEPS} ${INPUT_IO_FILE} ${OUT_EBLIF} ${SDC_PATCH_TOOL} ${SDC_PATCH_DEPS} | 
|  | COMMAND | 
|  | ${SDC_PATCH_TOOL_CMD_FOR_TARGET_LIST} | 
|  | ${SDC_PATCH_EXTRA_ARGS_FOR_TARGET_LIST} | 
|  | ${SDC_PATCH_DESIGN_EXTRA_ARGS_FOR_TARGET_LIST} | 
|  | WORKING_DIRECTORY ${OUT_LOCAL} | 
|  | ) | 
|  |  | 
|  | add_output_to_fpga_target(${NAME} PATCH_SDC ${OUT_SDC_REL}) | 
|  |  | 
|  | # Use the patched SDC in VPR | 
|  | append_file_dependency(VPR_DEPS ${OUT_SDC_REL}) | 
|  | set(SDC_ARG --sdc_file ${OUT_SDC}) | 
|  | set(SDC_FILE ${OUT_SDC}) | 
|  | set(SDC_DEPS "") | 
|  | append_file_dependency(SDC_DEPS ${OUT_SDC_REL}) | 
|  |  | 
|  | endif () | 
|  |  | 
|  | # Generate routing and generate HLC. | 
|  | set(OUT_ROUTE ${OUT_LOCAL}/${TOP}.route) | 
|  |  | 
|  | append_file_dependency(VPR_DEPS ${OUT_EBLIF_REL}) | 
|  | list(APPEND VPR_DEPS ${DEFINE_DEVICE_DEVICE_TYPE}) | 
|  |  | 
|  | get_file_location(OUT_RRBIN_REAL_LOCATION ${OUT_RRBIN_REAL}) | 
|  | get_file_location(DEVICE_MERGED_FILE_LOCATION ${DEVICE_MERGED_FILE}) | 
|  |  | 
|  | foreach(SRC ${DEVICE_MERGED_FILE} ${OUT_RRBIN_REAL}) | 
|  | append_file_dependency(VPR_DEPS ${SRC}) | 
|  | endforeach() | 
|  |  | 
|  | get_target_property_required(VPR env VPR) | 
|  |  | 
|  | # Use route channel width from the device. If not provided then use the | 
|  | # one from the arch. | 
|  | get_target_property(ROUTE_CHAN_WIDTH ${DEVICE} ROUTE_CHAN_WIDTH) | 
|  | if("${ROUTE_CHAN_WIDTH}" STREQUAL "ROUTE_CHAN_WIDTH-NOTFOUND") | 
|  | get_target_property_required(ROUTE_CHAN_WIDTH ${ARCH} ROUTE_CHAN_WIDTH) | 
|  | endif() | 
|  |  | 
|  | get_target_property(VPR_ARCH_ARGS ${ARCH} VPR_ARCH_ARGS) | 
|  | if("${VPR_ARCH_ARGS}" STREQUAL "VPR_ARCH_ARGS-NOTFOUND") | 
|  | set(VPR_ARCH_ARGS "") | 
|  | endif() | 
|  |  | 
|  | separate_arguments( | 
|  | VPR_BASE_ARGS_LIST UNIX_COMMAND "${VPR_BASE_ARGS}" | 
|  | ) | 
|  | list(APPEND VPR_BASE_ARGS_LIST --route_chan_width ${ROUTE_CHAN_WIDTH}) | 
|  | separate_arguments( | 
|  | VPR_EXTRA_ARGS_LIST UNIX_COMMAND "${VPR_EXTRA_ARGS}" | 
|  | ) | 
|  |  | 
|  | # Setting noisy warnings log file if needed. | 
|  | set(OUT_NOISY_WARNINGS ${OUT_LOCAL}/noisy_warnings.log) | 
|  | string(CONFIGURE ${VPR_ARCH_ARGS} VPR_ARCH_ARGS_EXPANDED) | 
|  | separate_arguments( | 
|  | VPR_ARCH_ARGS_LIST UNIX_COMMAND "${VPR_ARCH_ARGS_EXPANDED}" | 
|  | ) | 
|  |  | 
|  | set( | 
|  | VPR_CMD | 
|  | ${QUIET_CMD} ${VPR} | 
|  | ${DEVICE_MERGED_FILE_LOCATION} | 
|  | ) | 
|  |  | 
|  | set( | 
|  | VPR_ARGS | 
|  | --device ${DEVICE_FULL} | 
|  | --read_rr_graph ${OUT_RRBIN_REAL_LOCATION} | 
|  | ${VPR_BASE_ARGS_LIST} | 
|  | ${VPR_ARCH_ARGS_LIST} | 
|  | ${VPR_EXTRA_ARGS_LIST} | 
|  | ${SDC_ARG} | 
|  | ) | 
|  |  | 
|  | get_target_property_required( | 
|  | USE_LOOKAHEAD_CACHE ${DEVICE} ${PACKAGE}_HAS_LOOKAHEAD_CACHE | 
|  | ) | 
|  | if(${USE_LOOKAHEAD_CACHE}) | 
|  | # If lookahead is cached, use the cache instead of recomputing lookaheads. | 
|  | get_target_property_required( | 
|  | LOOKAHEAD_FILE ${DEVICE} ${PACKAGE}_LOOKAHEAD_FILE | 
|  | ) | 
|  | append_file_dependency(VPR_DEPS ${LOOKAHEAD_FILE}) | 
|  | get_file_location(LOOKAHEAD_LOCATION ${LOOKAHEAD_FILE}) | 
|  | list(APPEND VPR_ARGS --read_router_lookahead ${LOOKAHEAD_LOCATION}) | 
|  | endif() | 
|  |  | 
|  | get_target_property_required( | 
|  | USE_PLACE_DELAY_CACHE ${DEVICE} ${PACKAGE}_HAS_PLACE_DELAY_CACHE | 
|  | ) | 
|  | if(${USE_PLACE_DELAY_CACHE}) | 
|  | get_target_property_required( | 
|  | PLACE_DELAY_FILE ${DEVICE} ${PACKAGE}_PLACE_DELAY_FILE | 
|  | ) | 
|  | append_file_dependency(VPR_DEPS ${PLACE_DELAY_FILE}) | 
|  | get_file_location(PLACE_DELAY_LOCATION ${PLACE_DELAY_FILE}) | 
|  | list(APPEND VPR_ARGS --read_placement_delay_lookup ${PLACE_DELAY_LOCATION}) | 
|  | endif() | 
|  |  | 
|  | list(APPEND VPR_DEPS ${VPR} ${QUIET_CMD}) | 
|  | append_file_dependency(VPR_DEPS ${OUT_EBLIF_REL}) | 
|  |  | 
|  | # Generate packing. | 
|  | # ------------------------------------------------------------------------- | 
|  | set(OUT_NET ${OUT_LOCAL}/${TOP}.net) | 
|  | set(OUT_NET_REL ${OUT_LOCAL_REL}/${TOP}.net) | 
|  |  | 
|  | if(NOT "${ADD_FPGA_TARGET_ASSERT_BLOCK_TYPES_ARE_USED}" STREQUAL "") | 
|  | set(BLOCK_USAGE ${OUT_LOCAL}/block_usage.json) | 
|  | list(APPEND VPR_ARGS --write_block_usage ${BLOCK_USAGE}) | 
|  | endif() | 
|  |  | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_NET} ${OUT_LOCAL}/pack.log ${BLOCK_USAGE} | 
|  | DEPENDS ${VPR_DEPS} | 
|  | COMMAND ${VPR_CMD} ${OUT_EBLIF} ${VPR_ARGS} --pack | 
|  | COMMAND | 
|  | ${CMAKE_COMMAND} -E copy ${OUT_LOCAL}/vpr_stdout.log ${OUT_LOCAL}/pack.log | 
|  | WORKING_DIRECTORY ${OUT_LOCAL} | 
|  | ) | 
|  |  | 
|  | add_output_to_fpga_target(${NAME} NET ${OUT_NET_REL}) | 
|  |  | 
|  | if(NOT "${ADD_FPGA_TARGET_ASSERT_BLOCK_TYPES_ARE_USED}" STREQUAL "") | 
|  | set(USAGE_UTIL ${f4pga-arch-defs_SOURCE_DIR}/utils/report_block_usage.py) | 
|  | add_custom_target( | 
|  | ${NAME}_assert_usage | 
|  | COMMAND ${PYTHON3} ${USAGE_UTIL} | 
|  | --assert_usage \"${ADD_FPGA_TARGET_ASSERT_BLOCK_TYPES_ARE_USED}\" | 
|  | ${OUT_LOCAL}/block_usage.json | 
|  | DEPENDS ${PYTHON3} ${USAGE_UTIL} ${BLOCK_USAGE} | 
|  | ) | 
|  | endif() | 
|  |  | 
|  | set(ECHO_OUT_NET ${OUT_LOCAL}/echo/${TOP}.net) | 
|  | add_custom_command( | 
|  | OUTPUT ${ECHO_OUT_NET} | 
|  | DEPENDS ${VPR_DEPS} | 
|  | COMMAND ${CMAKE_COMMAND} -E make_directory ${OUT_LOCAL}/echo | 
|  | COMMAND cd ${OUT_LOCAL}/echo && ${VPR_CMD} ${OUT_EBLIF} ${VPR_ARGS} --pack_verbosity 3 --echo_file on --pack | 
|  | COMMAND | 
|  | ${CMAKE_COMMAND} -E copy ${OUT_LOCAL}/echo/vpr_stdout.log ${OUT_LOCAL}/echo/pack.log | 
|  | ) | 
|  |  | 
|  | add_custom_target(${NAME}_pack DEPENDS ${OUT_NET}) | 
|  | add_dependencies(all_${BOARD}_pack ${NAME}_pack) | 
|  |  | 
|  | # Generate placement constraints. | 
|  | # ------------------------------------------------------------------------- | 
|  | set(FIX_CLUSTERS_ARG "") | 
|  |  | 
|  | if(NOT ${ADD_FPGA_TARGET_INPUT_IO_FILE} STREQUAL "" OR ${XDCS_COUNT} GREATER "0") | 
|  | get_target_property_required(NO_PINS ${ARCH} NO_PINS) | 
|  | if(${NO_PINS}) | 
|  | message(FATAL_ERROR "Arch ${ARCH} does not currently support pin constraints.") | 
|  | endif() | 
|  | get_target_property_required(PLACE_TOOL_CMD ${ARCH} PLACE_TOOL_CMD) | 
|  |  | 
|  | get_target_property_required(NO_PLACE_CONSTR ${ARCH} NO_PLACE_CONSTR) | 
|  | if(NOT ${NO_PLACE_CONSTR}) | 
|  | get_target_property_required(PLACE_CONSTR_TOOL_CMD ${ARCH} PLACE_CONSTR_TOOL_CMD) | 
|  | endif() | 
|  |  | 
|  | get_target_property_required(PYTHON3 env PYTHON3) | 
|  |  | 
|  |  | 
|  | # Add complete dependency chain | 
|  | set(IO_DEPS ${VPR_DEPS}) | 
|  | if(NOT ${ADD_FPGA_TARGET_INPUT_IO_FILE} STREQUAL "") | 
|  | append_file_dependency(IO_DEPS ${ADD_FPGA_TARGET_INPUT_IO_FILE}) | 
|  | endif() | 
|  | append_file_dependency(IO_DEPS ${PINMAP_FILE}) | 
|  | append_file_dependency(IO_DEPS ${OUT_NET_REL}) | 
|  |  | 
|  | if(NOT ${ADD_FPGA_TARGET_INPUT_IO_FILE} STREQUAL "") | 
|  | set_target_properties(${NAME} PROPERTIES | 
|  | INPUT_IO_FILE ${ADD_FPGA_TARGET_INPUT_IO_FILE}) | 
|  | set(PCF_INPUT_IO_FILE "--pcf ${INPUT_IO_FILE}") | 
|  | endif() | 
|  |  | 
|  | # Set variables for the string(CONFIGURE) below. | 
|  | set(OUT_IO ${OUT_LOCAL}/${TOP}_io.place) | 
|  | set(OUT_IO_REL ${OUT_LOCAL_REL}/${TOP}_io.place) | 
|  | set(OUT_CONSTR ${OUT_LOCAL}/${TOP}_constraints.place) | 
|  | set(OUT_CONSTR_REL ${OUT_LOCAL_REL}/${TOP}_constraints.place) | 
|  | set(OUT_NET ${OUT_LOCAL}/${TOP}.net) | 
|  |  | 
|  | # Generate IO constraints | 
|  | string(CONFIGURE ${PLACE_TOOL_CMD} PLACE_TOOL_CMD_FOR_TARGET) | 
|  | separate_arguments( | 
|  | PLACE_TOOL_CMD_FOR_TARGET_LIST UNIX_COMMAND ${PLACE_TOOL_CMD_FOR_TARGET} | 
|  | ) | 
|  |  | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_IO} | 
|  | DEPENDS ${IO_DEPS} | 
|  | COMMAND ${PLACE_TOOL_CMD_FOR_TARGET_LIST} --out ${OUT_IO} | 
|  | WORKING_DIRECTORY ${OUT_LOCAL} | 
|  | ) | 
|  |  | 
|  | add_output_to_fpga_target(${NAME} IO_PLACE ${OUT_IO_REL}) | 
|  | append_file_dependency(VPR_DEPS ${OUT_IO_REL}) | 
|  |  | 
|  | set(CONSTR_DEPS "") | 
|  | if(NOT ${NO_PLACE_CONSTR}) | 
|  | append_file_dependency(CONSTR_DEPS ${OUT_IO_REL}) | 
|  |  | 
|  | get_target_property(PLACE_CONSTR_TOOL_EXTRA_ARGS ${BOARD} PLACE_CONSTR_TOOL_EXTRA_ARGS) | 
|  | if ("${PLACE_CONSTR_TOOL_EXTRA_ARGS}" STREQUAL "PLACE_CONSTR_TOOL_EXTRA_ARGS-NOTFOUND") | 
|  | set(PLACE_CONSTR_TOOL_EXTRA_ARGS "") | 
|  | endif() | 
|  |  | 
|  | # Generate LOC constrains | 
|  | string(CONFIGURE ${PLACE_CONSTR_TOOL_CMD} PLACE_CONSTR_TOOL_CMD_FOR_TARGET) | 
|  | separate_arguments( | 
|  | PLACE_CONSTR_TOOL_CMD_FOR_TARGET_LIST UNIX_COMMAND ${PLACE_CONSTR_TOOL_CMD_FOR_TARGET} | 
|  | ) | 
|  |  | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_CONSTR} | 
|  | DEPENDS ${CONSTR_DEPS} | 
|  | COMMAND | 
|  | ${PLACE_CONSTR_TOOL_CMD_FOR_TARGET_LIST} < ${OUT_IO} > ${OUT_CONSTR} | 
|  | WORKING_DIRECTORY ${OUT_LOCAL} | 
|  | ) | 
|  |  | 
|  | add_output_to_fpga_target(${NAME} IO_PLACE ${OUT_CONSTR_REL}) | 
|  | append_file_dependency(VPR_DEPS ${OUT_CONSTR_REL}) | 
|  |  | 
|  | set(FIX_CLUSTERS_ARG --fix_clusters ${OUT_CONSTR}) | 
|  | else() | 
|  | set(FIX_CLUSTERS_ARG --fix_clusters ${OUT_IO}) | 
|  | endif() | 
|  |  | 
|  | endif() | 
|  |  | 
|  | if (${ADD_FPGA_TARGET_INSTALL_CIRCUIT}) | 
|  |  | 
|  | # Check if the device should be installed | 
|  | check_device_install(${DEVICE} DO_INSTALL) | 
|  | if (DO_INSTALL) | 
|  |  | 
|  | set(INSTALL_DEPS "") | 
|  |  | 
|  | # Install circuit | 
|  | append_file_dependency(INSTALL_DEPS ${OUT_EBLIF_REL}) | 
|  |  | 
|  | install( | 
|  | FILES ${OUT_EBLIF} | 
|  | RENAME ${NAME}.eblif | 
|  | DESTINATION "benchmarks/circuits" | 
|  | ) | 
|  |  | 
|  | # Install place constraints | 
|  | set(CONSTR_FILE "") | 
|  | if (NOT ${NO_PLACE_CONSTR}) | 
|  | append_file_dependency(INSTALL_DEPS ${OUT_CONSTR_REL}) | 
|  | set(CONSTR_FILE ${OUT_CONSTR}) | 
|  | else() | 
|  | append_file_dependency(INSTALL_DEPS ${OUT_IO_REL}) | 
|  | set(CONSTR_FILE ${OUT_IO}) | 
|  | endif() | 
|  |  | 
|  | install( | 
|  | FILES ${CONSTR_FILE} | 
|  | RENAME ${NAME}.place | 
|  | DESTINATION "benchmarks/place_constr" | 
|  | ) | 
|  |  | 
|  | # Install SDC constraints | 
|  | if (NOT SDC_FILE STREQUAL "") | 
|  | install( | 
|  | FILES ${SDC_FILE} | 
|  | RENAME ${NAME}.sdc | 
|  | DESTINATION "benchmarks/sdc" | 
|  | ) | 
|  | append_file_dependency(INSTALL_DEPS ${SDC_DEPS}) | 
|  | endif() | 
|  |  | 
|  | add_custom_target( | 
|  | "INSTALL_${NAME}_CIRCUIT" | 
|  | ALL | 
|  | DEPENDS ${INSTALL_DEPS} | 
|  | ) | 
|  | endif() | 
|  | endif() | 
|  |  | 
|  | # Generate placement. | 
|  | # ------------------------------------------------------------------------- | 
|  | set(OUT_PLACE ${OUT_LOCAL}/${TOP}.place) | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_PLACE} | 
|  | DEPENDS ${OUT_NET} ${VPR_DEPS} | 
|  | COMMAND ${VPR_CMD} ${OUT_EBLIF} ${VPR_ARGS} ${FIX_CLUSTERS_ARG} --place | 
|  | COMMAND | 
|  | ${CMAKE_COMMAND} -E copy ${OUT_LOCAL}/vpr_stdout.log | 
|  | ${OUT_LOCAL}/place.log | 
|  | WORKING_DIRECTORY ${OUT_LOCAL} | 
|  | ) | 
|  |  | 
|  | set(ECHO_OUT_PLACE ${OUT_LOCAL}/echo/${TOP}.place) | 
|  | add_custom_command( | 
|  | OUTPUT ${ECHO_OUT_PLACE} | 
|  | DEPENDS ${ECHO_OUT_NET} ${VPR_DEPS} | 
|  | COMMAND ${VPR_CMD} ${OUT_EBLIF} ${VPR_ARGS} ${FIX_CLUSTERS_ARG} --echo_file on --place | 
|  | COMMAND | 
|  | ${CMAKE_COMMAND} -E copy ${OUT_LOCAL}/echo/vpr_stdout.log | 
|  | ${OUT_LOCAL}/echo/place.log | 
|  | WORKING_DIRECTORY ${OUT_LOCAL}/echo | 
|  | ) | 
|  |  | 
|  | add_custom_target(${NAME}_place DEPENDS ${OUT_PLACE}) | 
|  | add_dependencies(all_${BOARD}_place ${NAME}_place) | 
|  |  | 
|  | # Process packed netlist and circuit netlist | 
|  | # ------------------------------------------------------------------------- | 
|  | get_target_property(NET_PATCH_TOOL     ${ARCH} NET_PATCH_TOOL) | 
|  | get_target_property(NET_PATCH_TOOL_CMD ${ARCH} NET_PATCH_TOOL_CMD) | 
|  |  | 
|  | if (NOT "${NET_PATCH_TOOL}" MATCHES ".*-NOTFOUND" AND NOT "${NET_PATCH_TOOL}" STREQUAL "") | 
|  |  | 
|  | # Set variables for the configure statement below | 
|  | set(VPR_ARCH ${DEVICE_MERGED_FILE_LOCATION}) | 
|  |  | 
|  | set(IN_NET ${OUT_NET}) | 
|  | set(IN_EBLIF ${OUT_EBLIF}) | 
|  | set(IN_PLACE ${OUT_PLACE}) | 
|  |  | 
|  | set(OUT_NET ${OUT_LOCAL}/${TOP}.patched.net) | 
|  | set(OUT_NET_REL ${OUT_LOCAL_REL}/${TOP}.patched.net) | 
|  |  | 
|  | set(OUT_EBLIF ${OUT_LOCAL}/${TOP}.patched.eblif) | 
|  | set(OUT_EBLIF_REL ${OUT_LOCAL_REL}/${TOP}.patched.eblif) | 
|  |  | 
|  | set(OUT_PLACE ${OUT_LOCAL}/${TOP}.patched.place) | 
|  | set(OUT_PLACE_REL ${OUT_LOCAL_REL}/${TOP}.patched.place) | 
|  |  | 
|  | # Configure the base command | 
|  | string(CONFIGURE ${NET_PATCH_TOOL_CMD} NET_PATCH_TOOL_CMD_FOR_TARGET) | 
|  | separate_arguments( | 
|  | NET_PATCH_TOOL_CMD_FOR_TARGET_LIST UNIX_COMMAND ${NET_PATCH_TOOL_CMD_FOR_TARGET} | 
|  | ) | 
|  |  | 
|  | # Configure and append device-specific extra args | 
|  | get_target_property(NET_PATCH_EXTRA_ARGS ${DEVICE} NET_PATCH_EXTRA_ARGS) | 
|  | if (NOT "${NET_PATCH_EXTRA_ARGS}" MATCHES ".*NOTFOUND") | 
|  | string(CONFIGURE ${NET_PATCH_EXTRA_ARGS} NET_PATCH_EXTRA_ARGS_FOR_TARGET) | 
|  | separate_arguments( | 
|  | NET_PATCH_EXTRA_ARGS_FOR_TARGET_LIST UNIX_COMMAND ${NET_PATCH_EXTRA_ARGS_FOR_TARGET} | 
|  | ) | 
|  | else() | 
|  | set(NET_PATCH_EXTRA_ARGS_FOR_TARGET_LIST) | 
|  | endif() | 
|  |  | 
|  | # Configure and append design-specific extra args | 
|  | set(NET_PATCH_DESIGN_EXTRA_ARGS ${ADD_FPGA_TARGET_NET_PATCH_EXTRA_ARGS}) | 
|  | if (NOT "${NET_PATCH_DESIGN_EXTRA_ARGS}" STREQUAL "") | 
|  | string(CONFIGURE ${NET_PATCH_DESIGN_EXTRA_ARGS} NET_PATCH_DESIGN_EXTRA_ARGS_FOR_TARGET) | 
|  | separate_arguments( | 
|  | NET_PATCH_DESIGN_EXTRA_ARGS_FOR_TARGET_LIST UNIX_COMMAND ${NET_PATCH_DESIGN_EXTRA_ARGS_FOR_TARGET} | 
|  | ) | 
|  | else() | 
|  | set(NET_PATCH_DESIGN_EXTRA_ARGS_FOR_TARGET_LIST) | 
|  | endif() | 
|  |  | 
|  | # Extra dependencies | 
|  | get_target_property(NET_PATCH_DEPS ${DEVICE} NET_PATCH_DEPS) | 
|  | if ("${NET_PATCH_DEPS}" MATCHES ".*NOTFOUND") | 
|  | set(NET_PATCH_DEPS) | 
|  | endif () | 
|  |  | 
|  | # Add targets for patched EBLIF and .net | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_NET} ${OUT_EBLIF} ${OUT_PLACE} | 
|  | DEPENDS ${IN_NET} ${IN_EBLIF} ${IN_PLACE} ${NET_PATCH_DEPS} | 
|  | COMMAND | 
|  | ${NET_PATCH_TOOL_CMD_FOR_TARGET_LIST} | 
|  | ${NET_PATCH_EXTRA_ARGS_FOR_TARGET_LIST} | 
|  | ${NET_PATCH_DESIGN_EXTRA_ARGS_FOR_TARGET_LIST} | 
|  | WORKING_DIRECTORY ${OUT_LOCAL} | 
|  | ) | 
|  |  | 
|  | add_output_to_fpga_target(${NAME} PATCHED_NET ${OUT_NET_REL}) | 
|  | add_output_to_fpga_target(${NAME} PATCHED_EBLIF ${OUT_EBLIF_REL}) | 
|  | add_output_to_fpga_target(${NAME} PATCHED_PLACE ${OUT_PLACE_REL}) | 
|  |  | 
|  | add_custom_target(${NAME}_patch_net DEPENDS ${OUT_NET} ${OUT_EBLIF} ${OUT_PLACE}) | 
|  |  | 
|  | endif () | 
|  |  | 
|  |  | 
|  | # Generate routing. | 
|  | # ------------------------------------------------------------------------- | 
|  | set(ROUTE_LOG ${OUT_LOCAL}/route.log) | 
|  |  | 
|  | if(NOT "${ADD_FPGA_TARGET_ASSERT_TIMING}" STREQUAL "") | 
|  | set(TIMING_SUMMARY ${OUT_LOCAL}/timing_summary.json) | 
|  | list(APPEND VPR_ARGS --write_timing_summary ${TIMING_SUMMARY}) | 
|  | endif() | 
|  |  | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_ROUTE} ${ROUTE_LOG} ${TIMING_SUMMARY} | 
|  | DEPENDS ${OUT_NET} ${OUT_PLACE} ${VPR_DEPS} | 
|  | COMMAND ${VPR_CMD} ${OUT_EBLIF} ${VPR_ARGS} --route | 
|  | COMMAND | 
|  | ${CMAKE_COMMAND} -E copy ${OUT_LOCAL}/vpr_stdout.log | 
|  | ${ROUTE_LOG} | 
|  | WORKING_DIRECTORY ${OUT_LOCAL} | 
|  | ) | 
|  | add_custom_target(${NAME}_route DEPENDS ${OUT_ROUTE}) | 
|  | add_dependencies(all_${BOARD}_route ${NAME}_route) | 
|  |  | 
|  | set(ECHO_ATOM_NETLIST_ORIG ${OUT_LOCAL}/echo/atom_netlist.orig.echo.blif) | 
|  | set(ECHO_ATOM_NETLIST_CLEANED ${OUT_LOCAL}/echo/atom_netlist.cleaned.echo.blif) | 
|  | add_custom_command( | 
|  | OUTPUT ${ECHO_ATOM_NETLIST_ORIG} ${ECHO_ATOM_NETLIST_CLEANED} | 
|  | DEPENDS ${ECHO_OUT_PLACE} ${VPR_DEPS} ${ECHO_DIRECTORY_TARGET} | 
|  | COMMAND ${VPR_CMD} ${OUT_EBLIF} ${VPR_ARGS} --echo_file on --route | 
|  | COMMAND | 
|  | ${CMAKE_COMMAND} -E copy ${OUT_LOCAL}/echo/vpr_stdout.log | 
|  | ${OUT_LOCAL}/echo/route.log | 
|  | WORKING_DIRECTORY ${OUT_LOCAL}/echo | 
|  | ) | 
|  | add_custom_target(${NAME}_route_echo DEPENDS ${ECHO_ATOM_NETLIST_ORIG}) | 
|  |  | 
|  | if(NOT "${ADD_FPGA_TARGET_ASSERT_TIMING}" STREQUAL "") | 
|  | set(TIMING_UTIL ${f4pga-arch-defs_SOURCE_DIR}/utils/report_timing.py) | 
|  | add_custom_target( | 
|  | ${NAME}_assert_timing | 
|  | COMMAND ${PYTHON3} ${TIMING_UTIL} | 
|  | --assert \"${ADD_FPGA_TARGET_ASSERT_TIMING}\" | 
|  | ${TIMING_SUMMARY} | 
|  | DEPENDS ${PYTHON3} ${TIMING_UTIL} ${TIMING_SUMMARY} | 
|  | ) | 
|  | endif() | 
|  |  | 
|  | if(${ADD_FPGA_TARGET_ROUTE_ONLY}) | 
|  | return() | 
|  | endif() | 
|  |  | 
|  | get_target_property_required(USE_FASM ${ARCH} USE_FASM) | 
|  |  | 
|  | if(${USE_FASM}) | 
|  | get_target_property_required(GENFASM env GENFASM) | 
|  | set( | 
|  | GENFASM_CMD | 
|  | ${QUIET_CMD} ${GENFASM} | 
|  | ${DEVICE_MERGED_FILE_LOCATION} | 
|  | ${OUT_EBLIF} | 
|  | --device ${DEVICE_FULL} | 
|  | --read_rr_graph ${OUT_RRBIN_REAL_LOCATION} | 
|  | ${VPR_BASE_ARGS_LIST} | 
|  | ${VPR_ARCH_ARGS_LIST} | 
|  | ${VPR_EXTRA_ARGS_LIST} | 
|  | ) | 
|  | else() | 
|  | get_target_property_required(GENHLC env GENHLC) | 
|  | set( | 
|  | GENHLC_CMD | 
|  | ${QUIET_CMD} ${GENHLC} | 
|  | ${DEVICE_MERGED_FILE_LOCATION} | 
|  | ${OUT_EBLIF} | 
|  | --device ${DEVICE_FULL} | 
|  | --read_rr_graph ${OUT_RRBIN_REAL_LOCATION} | 
|  | ${VPR_BASE_ARGS_LIST} | 
|  | ${VPR_ARCH_ARGS_LIST} | 
|  | ${VPR_EXTRA_ARGS_LIST} | 
|  | ) | 
|  | endif() | 
|  |  | 
|  | if(${USE_FASM}) | 
|  | # Generate FASM | 
|  | # ------------------------------------------------------------------------- | 
|  | set(OUT_FASM ${OUT_LOCAL}/${TOP}.fasm) | 
|  | set(OUT_FASM_CONCATENATED ${OUT_LOCAL}/${TOP}.concat.fasm) | 
|  | set(OUT_FASM_GENFASM ${OUT_LOCAL}/${TOP}.genfasm.fasm) | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_FASM} | 
|  | DEPENDS ${OUT_ROUTE} ${OUT_PLACE} ${VPR_DEPS} | 
|  | COMMAND ${GENFASM_CMD} | 
|  | COMMAND | 
|  | ${CMAKE_COMMAND} -E copy ${OUT_LOCAL}/vpr_stdout.log | 
|  | ${OUT_LOCAL}/genhlc.log | 
|  | COMMAND | 
|  | ${CMAKE_COMMAND} -E copy ${OUT_FASM} ${OUT_FASM_GENFASM} | 
|  | COMMAND cat ${OUT_FASM} ${OUT_FASM_EXTRA} > ${OUT_FASM_CONCATENATED} | 
|  | COMMAND | 
|  | ${CMAKE_COMMAND} -E rename ${OUT_FASM_CONCATENATED} ${OUT_FASM} | 
|  | WORKING_DIRECTORY ${OUT_LOCAL} | 
|  | ) | 
|  | add_custom_target(${NAME}_fasm DEPENDS ${OUT_FASM}) | 
|  |  | 
|  | add_output_to_fpga_target(${NAME} FASM ${OUT_LOCAL_REL}/${TOP}.fasm) | 
|  | set_target_properties(${NAME} PROPERTIES OUT_FASM ${OUT_FASM}) | 
|  | else() | 
|  | # Generate HLC | 
|  | # ------------------------------------------------------------------------- | 
|  | set(OUT_HLC ${OUT_LOCAL}/${TOP}.hlc) | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_HLC} | 
|  | DEPENDS ${OUT_ROUTE} ${OUT_PLACE} ${VPR_DEPS} | 
|  | COMMAND ${GENHLC_CMD} | 
|  | COMMAND | 
|  | ${CMAKE_COMMAND} -E copy ${OUT_LOCAL}/vpr_stdout.log | 
|  | ${OUT_LOCAL}/genhlc.log | 
|  | WORKING_DIRECTORY ${OUT_LOCAL} | 
|  | ) | 
|  | add_custom_target(${NAME}_hlc DEPENDS ${OUT_HLC}) | 
|  | endif() | 
|  |  | 
|  | # Generate analysis. | 
|  | #------------------------------------------------------------------------- | 
|  |  | 
|  | set(OUT_ANALYSIS ${OUT_LOCAL}/analysis.log) | 
|  | set(OUT_POST_SYNTHESIS_V ${OUT_LOCAL}/${TOP}_merged_post_implementation.v) | 
|  | set(OUT_POST_SYNTHESIS_BLIF ${OUT_LOCAL}/${TOP}_post_synthesis.blif) | 
|  | set(OUT_POST_SYNTHESIS_SDF ${OUT_LOCAL}/${TOP}_post_synthesis.sdf) | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_ANALYSIS} | 
|  | DEPENDS ${OUT_ROUTE} ${VPR_DEPS} ${PYTHON3} | 
|  | COMMAND ${VPR_CMD} ${OUT_EBLIF} ${VPR_ARGS} --analysis --gen_post_synthesis_netlist on --gen_post_implementation_merged_netlist on --post_synth_netlist_unconn_inputs nets --post_synth_netlist_unconn_outputs nets | 
|  | COMMAND ${CMAKE_COMMAND} -E copy ${OUT_LOCAL}/vpr_stdout.log | 
|  | ${OUT_LOCAL}/analysis.log | 
|  | WORKING_DIRECTORY ${OUT_LOCAL} | 
|  | ) | 
|  | add_custom_target(${NAME}_analysis DEPENDS ${OUT_ANALYSIS}) | 
|  |  | 
|  | get_target_property_required(NO_BITSTREAM ${ARCH} NO_BITSTREAM) | 
|  | if(NOT ${NO_BITSTREAM}) | 
|  | if(${USE_FASM}) | 
|  | add_bitstream_target( | 
|  | NAME ${NAME} | 
|  | USE_FASM | 
|  | INCLUDED_TARGETS ${NAME} | 
|  | OUT_LOCAL_REL ${OUT_LOCAL_REL} | 
|  | ) | 
|  | else() | 
|  | add_bitstream_target( | 
|  | NAME ${NAME} | 
|  | USE_FASM | 
|  | INCLUDED_TARGETS ${NAME} | 
|  | OUT_LOCAL_REL ${OUT_LOCAL_REL} | 
|  | ) | 
|  | endif() | 
|  |  | 
|  | # Check if we support bitstream disassembly only | 
|  | get_target_property_required(NO_BIT_TO_V ${ARCH} NO_BIT_TO_V) | 
|  |  | 
|  | get_target_property(BIT_TO_FASM     ${ARCH} BIT_TO_FASM) | 
|  | get_target_property(BIT_TO_FASM_CMD ${ARCH} BIT_TO_FASM_CMD) | 
|  |  | 
|  | set(NO_BIT_TO_FASM TRUE) | 
|  | if(NOT "${BIT_TO_FASM}" STREQUAL "" AND NOT "${BIT_TO_FASM_CMD}" STREQUAL "") | 
|  | set(NO_BIT_TO_FASM FALSE) | 
|  | endif() | 
|  |  | 
|  | # Cannot have bit to verilog and bit to FASM at the same time | 
|  | if(NOT ${NO_BIT_TO_V} AND NOT ${NO_BIT_TO_FASM}) | 
|  | message(FATAL_ERROR "Cannot have bitstream to Verilog and bitstream to FASM targets simultaneously") | 
|  | endif() | 
|  |  | 
|  | get_target_property(OUT_BITSTREAM ${NAME} OUT_BITSTREAM) | 
|  | if(NOT ${NO_BIT_TO_V}) | 
|  | # Generate verilog from bitstream | 
|  | # ------------------------------------------------------------------------- | 
|  |  | 
|  | set(OUT_BIT_VERILOG ${OUT_LOCAL}/${TOP}_bit.v) | 
|  | get_target_property_required(BIT_TO_V_CMD ${ARCH} BIT_TO_V_CMD) | 
|  | if(NOT ${ADD_FPGA_TARGET_INPUT_IO_FILE} STREQUAL "") | 
|  | set(PCF_INPUT_IO_FILE "--pcf ${INPUT_IO_FILE}") | 
|  | endif() | 
|  | string(CONFIGURE ${BIT_TO_V_CMD} BIT_TO_V_CMD_FOR_TARGET) | 
|  | separate_arguments( | 
|  | BIT_TO_V_CMD_FOR_TARGET_LIST UNIX_COMMAND ${BIT_TO_V_CMD_FOR_TARGET} | 
|  | ) | 
|  |  | 
|  | get_target_property(BIT_TO_V_EXTRA_ARGS ${BOARD} BIT_TO_V_EXTRA_ARGS) | 
|  | if (${BIT_TO_V_EXTRA_ARGS} STREQUAL BIT_TO_V_EXTRA_ARGS-NOTFOUND OR | 
|  | ${BIT_TO_V_EXTRA_ARGS} STREQUAL NOTFOUND) | 
|  | set(BIT_TO_V_EXTRA_ARGS "") | 
|  | endif() | 
|  |  | 
|  | separate_arguments( | 
|  | BIT_TO_V_EXTRA_ARGS_LIST UNIX_COMMAND ${BIT_TO_V_EXTRA_ARGS} | 
|  | ) | 
|  | set(BIT_TO_V_CMD_FOR_TARGET_LIST ${BIT_TO_V_CMD_FOR_TARGET_LIST} ${BIT_TO_V_EXTRA_ARGS_LIST}) | 
|  |  | 
|  | separate_arguments( | 
|  | BIT_TO_V_EXTRA_ARGS_LIST UNIX_COMMAND ${ADD_FPGA_TARGET_BIT_TO_V_EXTRA_ARGS} | 
|  | ) | 
|  | set(BIT_TO_V_CMD_FOR_TARGET_LIST ${BIT_TO_V_CMD_FOR_TARGET_LIST} ${BIT_TO_V_EXTRA_ARGS_LIST}) | 
|  |  | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_BIT_VERILOG} | 
|  | COMMAND ${BIT_TO_V_CMD_FOR_TARGET_LIST} | 
|  | DEPENDS ${OUT_BITSTREAM} ${OUT_BIN} | 
|  | ) | 
|  |  | 
|  | add_output_to_fpga_target(${NAME} BIT_V ${OUT_LOCAL_REL}/${TOP}_bit.v) | 
|  | get_file_target(BIT_V_TARGET ${OUT_LOCAL_REL}/${TOP}_bit.v) | 
|  | add_custom_target(${NAME}_bit_v DEPENDS ${BIT_V_TARGET}) | 
|  |  | 
|  | set(AUTOSIM_CYCLES ${ADD_FPGA_TARGET_AUTOSIM_CYCLES}) | 
|  | if("${AUTOSIM_CYCLES}" STREQUAL "") | 
|  | set(AUTOSIM_CYCLES 100) | 
|  | endif() | 
|  |  | 
|  | add_autosim( | 
|  | NAME ${NAME}_autosim_bit | 
|  | TOP ${TOP} | 
|  | ARCH ${ARCH} | 
|  | SOURCES ${OUT_LOCAL_REL}/${TOP}_bit.v | 
|  | CYCLES ${AUTOSIM_CYCLES} | 
|  | ) | 
|  |  | 
|  | elseif(NOT ${NO_BIT_TO_FASM}) | 
|  | # Generate FASM from bitstream only | 
|  | # --------------------------------------------------------------------- | 
|  |  | 
|  | set(OUT_BIT_FASM ${OUT_LOCAL}/${TOP}_bit.fasm) | 
|  |  | 
|  | string(CONFIGURE ${BIT_TO_FASM_CMD} BIT_TO_FASM_CMD_FOR_TARGET) | 
|  | separate_arguments( | 
|  | BIT_TO_FASM_CMD_FOR_TARGET_LIST UNIX_COMMAND ${BIT_TO_FASM_CMD_FOR_TARGET} | 
|  | ) | 
|  |  | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_BIT_FASM} | 
|  | COMMAND ${BIT_TO_FASM_CMD_FOR_TARGET_LIST} | 
|  | DEPENDS ${BIT_TO_FASM} ${OUT_BITSTREAM} ${OUT_BIN} | 
|  | ) | 
|  |  | 
|  | add_output_to_fpga_target(${NAME} BIT_FASM ${OUT_LOCAL_REL}/${TOP}_bit.fasm) | 
|  | get_file_target(BIT_FASM_TARGET ${OUT_LOCAL_REL}/${TOP}_bit.fasm) | 
|  | add_custom_target(${NAME}_bit_fasm DEPENDS ${BIT_FASM_TARGET}) | 
|  |  | 
|  | endif() | 
|  |  | 
|  | get_target_property_required(NO_BIT_TIME ${ARCH} NO_BIT_TIME) | 
|  | if(NOT ${NO_BIT_TIME}) | 
|  | set(OUT_TIME_VERILOG ${OUT_LOCAL}/${TOP}_time.v) | 
|  | get_target_property_required(BIT_TIME ${ARCH} BIT_TIME) | 
|  | get_target_property_required(BIT_TIME_CMD ${ARCH} BIT_TIME_CMD) | 
|  | string(CONFIGURE ${BIT_TIME_CMD} BIT_TIME_CMD_FOR_TARGET) | 
|  | separate_arguments( | 
|  | BIT_TIME_CMD_FOR_TARGET_LIST UNIX_COMMAND ${BIT_TIME_CMD_FOR_TARGET} | 
|  | ) | 
|  | add_custom_command( | 
|  | OUTPUT ${OUT_TIME_VERILOG} | 
|  | COMMAND ${BIT_TIME_CMD_FOR_TARGET_LIST} | 
|  | DEPENDS ${OUT_BITSTREAM} ${BIT_TIME} | 
|  | ) | 
|  |  | 
|  | add_custom_target( | 
|  | ${NAME}_time | 
|  | DEPENDS ${OUT_TIME_VERILOG} | 
|  | ) | 
|  | endif() | 
|  | endif() | 
|  |  | 
|  | # Add test bench targets | 
|  | # ------------------------------------------------------------------------- | 
|  | foreach(TESTBENCH ${ADD_FPGA_TARGET_TESTBENCH_SOURCES}) | 
|  | get_filename_component(TESTBENCH_NAME ${TESTBENCH} NAME_WE) | 
|  | add_testbench( | 
|  | NAME testbench_${TESTBENCH_NAME} | 
|  | ARCH ${ARCH} | 
|  | SOURCES ${ADD_FPGA_TARGET_SOURCES} ${TESTBENCH} | 
|  | ) | 
|  |  | 
|  | add_testbench( | 
|  | NAME testbench_synth_${TESTBENCH_NAME} | 
|  | ARCH ${ARCH} | 
|  | SOURCES ${OUT_LOCAL_REL}/${TOP}_synth.v ${TESTBENCH} | 
|  | ) | 
|  |  | 
|  | if(NOT ${NO_BIT_TO_V}) | 
|  | add_testbench( | 
|  | NAME testbinch_${TESTBENCH_NAME} | 
|  | ARCH ${ARCH} | 
|  | SOURCES ${OUT_LOCAL_REL}/${TOP}_bit.v ${TESTBENCH} | 
|  | ) | 
|  | endif() | 
|  | endforeach() | 
|  |  | 
|  | if(${ADD_FPGA_TARGET_EMIT_CHECK_TESTS}) | 
|  | if("${ADD_FPGA_TARGET_EQUIV_CHECK_SCRIPT}" STREQUAL "") | 
|  | message(FATAL_ERROR "EQUIV_CHECK_SCRIPT is required if EMIT_CHECK_TESTS is set.") | 
|  | endif() | 
|  |  | 
|  | set(READ_GOLD "") | 
|  |  | 
|  | foreach(FILE ${SOURCE_FILES}) | 
|  | set(READ_GOLD "${READ_GOLD}${READ_FUNCTION} ${FILE} $<SEMICOLON> ") | 
|  | endforeach() | 
|  |  | 
|  | if(NOT ${NO_BIT_TO_V}) | 
|  | add_check_test( | 
|  | NAME ${NAME}_check | 
|  | ARCH ${ARCH} | 
|  | READ_GOLD "${READ_GOLD} rename ${TOP} gold" | 
|  | READ_GATE "read_verilog ${OUT_BIT_VERILOG} $<SEMICOLON> rename ${TOP} gate" | 
|  | EQUIV_CHECK_SCRIPT ${ADD_FPGA_TARGET_EQUIV_CHECK_SCRIPT} | 
|  | DEPENDS ${SOURCE_FILES} ${SOURCE_FILES_DEPS} ${BIT_V_TARGET} ${OUT_BIT_VERILOG} | 
|  | ) | 
|  | # Add bit-to-v check tests to all_check_tests. | 
|  | add_dependencies(all_check_tests ${NAME}_check_eblif) | 
|  | endif() | 
|  |  | 
|  | add_check_test( | 
|  | NAME ${NAME}_check_eblif | 
|  | ARCH ${ARCH} | 
|  | READ_GOLD "${READ_FUNCTION} ${SOURCE_FILES} $<SEMICOLON> rename ${TOP} gold" | 
|  | READ_GATE "read_blif -wideports ${OUT_EBLIF} $<SEMICOLON> rename ${TOP} gate" | 
|  | EQUIV_CHECK_SCRIPT ${ADD_FPGA_TARGET_EQUIV_CHECK_SCRIPT} | 
|  | DEPENDS ${SOURCE_FILES} ${SOURCE_FILES_DEPS} ${OUT_EBLIF} | 
|  | ) | 
|  |  | 
|  | # Add post-synthesis check tests to all_check_tests. | 
|  | add_dependencies(all_check_tests ${NAME}_check_eblif) | 
|  |  | 
|  | add_check_test( | 
|  | NAME ${NAME}_check_post_blif | 
|  | ARCH ${ARCH} | 
|  | READ_GOLD "${READ_FUNCTION} ${SOURCE_FILES} $<SEMICOLON> rename ${TOP} gold" | 
|  | READ_GATE "read_blif -wideports ${OUT_POST_SYNTHESIS_BLIF} $<SEMICOLON> rename ${TOP} gate" | 
|  | EQUIV_CHECK_SCRIPT ${ADD_FPGA_TARGET_EQUIV_CHECK_SCRIPT} | 
|  | DEPENDS ${SOURCE_FILES} ${SOURCE_FILES_DEPS} ${OUT_POST_SYNTHESIS_BLIF} | 
|  | ) | 
|  |  | 
|  | add_dependencies(all_check_tests ${NAME}_check_post_blif) | 
|  |  | 
|  | add_check_test( | 
|  | NAME ${NAME}_check_post_v | 
|  | ARCH ${ARCH} | 
|  | READ_GOLD "${READ_FUNCTION} ${SOURCE_FILES} $<SEMICOLON> rename ${TOP} gold" | 
|  | READ_GATE "read_verilog ${OUT_POST_SYNTHESIS_V} $<SEMICOLON> rename ${TOP} gate" | 
|  | EQUIV_CHECK_SCRIPT ${ADD_FPGA_TARGET_EQUIV_CHECK_SCRIPT} | 
|  | DEPENDS ${SOURCE_FILES} ${SOURCE_FILES_DEPS} ${OUT_POST_SYNTHESIS_V} | 
|  | ) | 
|  |  | 
|  | add_check_test( | 
|  | NAME ${NAME}_check_orig_blif | 
|  | ARCH ${ARCH} | 
|  | READ_GOLD "${READ_FUNCTION} ${SOURCE_FILES} $<SEMICOLON> rename ${TOP} gold" | 
|  | READ_GATE "read_blif -wideports ${ECHO_ATOM_NETLIST_ORIG} $<SEMICOLON> rename ${TOP} gate" | 
|  | EQUIV_CHECK_SCRIPT ${ADD_FPGA_TARGET_EQUIV_CHECK_SCRIPT} | 
|  | DEPENDS ${SOURCE_FILES} ${SOURCE_FILES_DEPS} ${ECHO_ATOM_NETLIST_ORIG} | 
|  | ) | 
|  |  | 
|  | add_check_test( | 
|  | NAME ${NAME}_check_cleaned_blif | 
|  | ARCH ${ARCH} | 
|  | READ_GOLD "${READ_FUNCTION} ${SOURCE_FILES} $<SEMICOLON> rename ${TOP} gold" | 
|  | READ_GATE "read_blif -wideports ${ECHO_ATOM_NETLIST_CLEANED} $<SEMICOLON> rename ${TOP} gate" | 
|  | EQUIV_CHECK_SCRIPT ${ADD_FPGA_TARGET_EQUIV_CHECK_SCRIPT} | 
|  | DEPENDS ${SOURCE_FILES} ${SOURCE_FILES_DEPS} ${ECHO_ATOM_NETLIST_CLEANED} | 
|  | ) | 
|  | endif() | 
|  | endfunction() | 
|  |  | 
|  | function(get_cells_sim_path var arch) | 
|  | # If CELLS_SIM is defined for ${arch}, sets var to the path to CELLS_SIM, | 
|  | # otherwise sets var to "". | 
|  | get_target_property(CELLS_SIM ${arch} CELLS_SIM) | 
|  | set(${var} ${CELLS_SIM} PARENT_SCOPE) | 
|  | endfunction() | 
|  |  | 
|  | function(add_check_test) | 
|  | # ~~~ | 
|  | # ADD_CHECK_TEST( | 
|  | #    NAME <name> | 
|  | #    ARCH <arch> | 
|  | #    READ_GOLD <yosys script> | 
|  | #    READ_GATE <yosys script> | 
|  | #    EQUIV_CHECK_SCRIPT <yosys to script verify two bitstreams gold and gate> | 
|  | #    DEPENDS <files and targets> | 
|  | #   ) | 
|  | # ~~~ | 
|  | # | 
|  | # ADD_CHECK_TEST defines a cmake test to compare analytically two modules. | 
|  | # READ_GOLD should be a yosys script that puts the truth module in a module | 
|  | # named gold. READ_GATE should be a yosys script that puts the gate module | 
|  | # in a module named gate. | 
|  | # | 
|  | # DEPENDS should the be complete list of dependencies to add to the check | 
|  | # target. | 
|  | set(options) | 
|  | set(oneValueArgs NAME ARCH READ_GOLD READ_GATE EQUIV_CHECK_SCRIPT) | 
|  | set(multiValueArgs DEPENDS) | 
|  | cmake_parse_arguments( | 
|  | ADD_CHECK_TEST | 
|  | "${options}" | 
|  | "${oneValueArgs}" | 
|  | "${multiValueArgs}" | 
|  | ${ARGN} | 
|  | ) | 
|  |  | 
|  | get_target_property_required(YOSYS env YOSYS) | 
|  | get_target_property_required(QUIET_CMD env QUIET_CMD) | 
|  | set(EQUIV_CHECK_SCRIPT ${ADD_CHECK_TEST_EQUIV_CHECK_SCRIPT}) | 
|  | if("${EQUIV_CHECK_SCRIPT}" STREQUAL "") | 
|  | message(FATAL_ERROR "EQUIV_CHECK_SCRIPT is not optional to add_check_test.") | 
|  | endif() | 
|  |  | 
|  | get_file_location(EQUIV_CHECK_SCRIPT_LOCATION ${EQUIV_CHECK_SCRIPT}) | 
|  | get_file_target(EQUIV_CHECK_SCRIPT_TARGET ${EQUIV_CHECK_SCRIPT}) | 
|  |  | 
|  | get_cells_sim_path(PATH_TO_CELLS_SIM ${ADD_CHECK_TEST_ARCH}) | 
|  | # CTest doesn't support build target dependencies, so we have to manually | 
|  | # make them. | 
|  | # | 
|  | # See https://stackoverflow.com/questions/733475/cmake-ctest-make-test-doesnt-build-tests | 
|  | add_custom_target(_target_${ADD_CHECK_TEST_NAME}_build_depends | 
|  | DEPENDS | 
|  | ${ADD_CHECK_TEST_DEPENDS} | 
|  | ${PATH_TO_CELLS_SIM} | 
|  | ${EQUIV_CHECK_SCRIPT_TARGET} | 
|  | ${EQUIV_CHECK_SCRIPT_LOCATION} | 
|  | ${YOSYS} | 
|  | ) | 
|  | add_test( | 
|  | NAME _test_${ADD_CHECK_TEST_NAME}_build | 
|  | COMMAND "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target _target_${ADD_CHECK_TEST_NAME}_build_depends --config $<CONFIG> | 
|  | ) | 
|  | # Make sure only one build is running at a time, ninja (and probably make) | 
|  | # output doesn't support multiple calls into it from seperate processes. | 
|  | set_tests_properties( | 
|  | _test_${ADD_CHECK_TEST_NAME}_build PROPERTIES RESOURCE_LOCK cmake | 
|  | ) | 
|  | add_test( | 
|  | NAME ${ADD_CHECK_TEST_NAME} | 
|  | COMMAND ${YOSYS} -p "${ADD_CHECK_TEST_READ_GOLD} $<SEMICOLON> ${ADD_CHECK_TEST_READ_GATE} $<SEMICOLON> script ${EQUIV_CHECK_SCRIPT_LOCATION}" ${PATH_TO_CELLS_SIM} | 
|  | ) | 
|  | set_tests_properties( | 
|  | ${ADD_CHECK_TEST_NAME} PROPERTIES DEPENDS _test_${ADD_CHECK_TEST_NAME}_build | 
|  | ) | 
|  |  | 
|  | # Also provide a make target that runs the analysis. | 
|  | add_custom_target( | 
|  | ${ADD_CHECK_TEST_NAME} | 
|  | COMMAND ${QUIET_CMD} ${YOSYS} -p "${ADD_CHECK_TEST_READ_GOLD} $<SEMICOLON> ${ADD_CHECK_TEST_READ_GATE} $<SEMICOLON> script ${EQUIV_CHECK_SCRIPT_LOCATION}" ${PATH_TO_CELLS_SIM} | 
|  | DEPENDS | 
|  | ${QUIET_CMD} | 
|  | ${ADD_CHECK_TEST_DEPENDS} ${PATH_TO_CELLS_SIM} | 
|  | ${EQUIV_CHECK_SCRIPT_TARGET} ${EQUIV_CHECK_SCRIPT_LOCATION} | 
|  | ${YOSYS} | 
|  | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} | 
|  | VERBATIM | 
|  | ) | 
|  | endfunction() | 
|  |  | 
|  | find_program(GTKWAVE gtkwave) | 
|  |  | 
|  | function(add_testbench) | 
|  | # ~~~ | 
|  | #   ADD_TESTBENCH( | 
|  | #     NAME <name of testbench> | 
|  | #     ARCH <arch> | 
|  | #     SOURCES <source list> | 
|  | #   ) | 
|  | # ~~~ | 
|  | # | 
|  | # ADD_TESTBENCH emits two custom targets, ${NAME} and ${NAME}_view.  ${NAME} | 
|  | # builds and executes a testbench with iverilog. | 
|  | # | 
|  | # ${NAME}_view launches GTKWAVE on the output wave file. For wave viewing, it | 
|  | # is assumed that all testbenches will output some variable dump and dump | 
|  | # to a file defined by VCDFILE.  If this is not true, the ${NAME}_view target | 
|  | # will not work. | 
|  |  | 
|  | set(options) | 
|  | set(oneValueArgs NAME ARCH) | 
|  | set(multiValueArgs SOURCES) | 
|  | cmake_parse_arguments( | 
|  | ADD_TESTBENCH | 
|  | "${options}" | 
|  | "${oneValueArgs}" | 
|  | "${multiValueArgs}" | 
|  | ${ARGN} | 
|  | ) | 
|  |  | 
|  | get_target_property(IVERILOG env IVERILOG) | 
|  | get_target_property(VVP env VVP) | 
|  | set(SOURCE_LOCATIONS "") | 
|  | set(FILE_DEPENDS "") | 
|  | foreach(SRC ${ADD_TESTBENCH_SOURCES}) | 
|  | append_file_location(SOURCE_LOCATIONS ${SRC}) | 
|  | append_file_dependency(FILE_DEPENDS ${SRC}) | 
|  | endforeach() | 
|  |  | 
|  | get_cells_sim_path(PATH_TO_CELLS_SIM ${ADD_TESTBENCH_ARCH}) | 
|  |  | 
|  | set(NAME ${ADD_TESTBENCH_NAME}) | 
|  |  | 
|  | add_custom_command( | 
|  | OUTPUT ${NAME}.vpp | 
|  | COMMAND | 
|  | ${IVERILOG} -v -DVCDFILE=\"${NAME}.vcd\" | 
|  | -DCLK_MHZ=0.001 -o ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.vpp | 
|  | ${PATH_TO_CELLS_SIM} | 
|  | ${SOURCE_LOCATIONS} | 
|  | DEPENDS ${IVERILOG} ${FILE_DEPENDS} | 
|  | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} | 
|  | VERBATIM | 
|  | ) | 
|  |  | 
|  | # This target always just executes the testbench.  If the user wants to view | 
|  | # waves generated from this executation, they should just build ${NAME}_view | 
|  | # not ${NAME}. | 
|  | add_custom_target( | 
|  | ${NAME} | 
|  | COMMAND ${VVP} -v -N ${NAME}.vpp | 
|  | DEPENDS ${VVP} ${NAME}.vpp | 
|  | ) | 
|  |  | 
|  | add_custom_command( | 
|  | OUTPUT ${NAME}.vcd | 
|  | COMMAND ${VVP} -v -N ${NAME}.vpp | 
|  | DEPENDS ${VVP} ${NAME}.vpp | 
|  | ) | 
|  | add_custom_target( | 
|  | ${NAME}_view | 
|  | COMMAND ${GTKWAVE} ${NAME}.vcd | 
|  | DEPENDS ${NAME}.vcd ${GTKWAVE} | 
|  | ) | 
|  | endfunction() | 
|  |  | 
|  | function(generate_pinmap) | 
|  | # ~~~ | 
|  | #   GENERATE_PINMAP( | 
|  | #     NAME <name of file to output pinmap file> | 
|  | #     TOP <module name to generate pinmap for> | 
|  | #     BOARD <board to generate pinmap for> | 
|  | #     SOURCES <list of sources to load> | 
|  | #   ) | 
|  | # ~~~ | 
|  | # | 
|  | # Generate pinmap blindly assigns each input and output from the module | 
|  | # ${TOP} to valid pins for the specified board. In its current version, | 
|  | # GENERATE_PINMAP may assign IO to global wire. | 
|  | # | 
|  | # TODO: Consider adding knowledge of global wires and be able to assign | 
|  | # specific wires to global wires (e.g. clock or reset lines). | 
|  | # | 
|  | # SOURCES must contain a module that matches ${TOP}. | 
|  | set(options) | 
|  | set(oneValueArgs NAME TOP BOARD) | 
|  | set(multiValueArgs SOURCES) | 
|  |  | 
|  | cmake_parse_arguments( | 
|  | GENERATE_PINMAP | 
|  | "${options}" | 
|  | "${oneValueArgs}" | 
|  | "${multiValueArgs}" | 
|  | ${ARGN} | 
|  | ) | 
|  |  | 
|  | get_target_property_required(YOSYS env YOSYS) | 
|  | get_target_property_required(PYTHON3 env PYTHON3) | 
|  | get_target_property_required(QUIET_CMD env QUIET_CMD) | 
|  |  | 
|  | set(NAME ${GENERATE_PINMAP_NAME}) | 
|  | set(BOARD ${GENERATE_PINMAP_BOARD}) | 
|  | set(TOP ${GENERATE_PINMAP_TOP}) | 
|  | get_target_property_required(DEVICE ${BOARD} DEVICE) | 
|  | get_target_property_required(PACKAGE ${BOARD} PACKAGE) | 
|  | get_target_property_required(PINMAP_FILE ${BOARD} PINMAP) | 
|  | get_file_location(PINMAP ${PINMAP_FILE}) | 
|  | get_file_target(PINMAP_TARGET ${PINMAP_FILE}) | 
|  |  | 
|  | set(CREATE_PINMAP ${f4pga-arch-defs_SOURCE_DIR}/utils/create_pinmap.py) | 
|  |  | 
|  | set(SOURCE_FILES "") | 
|  | set(SOURCE_FILES_DEPS "") | 
|  | foreach(SRC ${GENERATE_PINMAP_SOURCES}) | 
|  | append_file_location(SOURCE_FILES ${SRC}) | 
|  | append_file_dependency(SOURCE_FILES_DEPS ${SRC}) | 
|  | endforeach() | 
|  |  | 
|  | add_custom_command( | 
|  | OUTPUT ${NAME}.json | 
|  | COMMAND ${QUIET_CMD} ${YOSYS} -r ${TOP} -p \"proc $<SEMICOLON> write_json ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.json\" -l ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.json.log ${SOURCE_FILES} | 
|  | DEPENDS | 
|  | ${QUIET_CMD} | 
|  | ${YOSYS} | 
|  | ${SOURCE_FILES} ${SOURCE_FILES_DEPS} | 
|  | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} | 
|  | ) | 
|  |  | 
|  | add_custom_command( | 
|  | OUTPUT ${NAME} | 
|  | COMMAND ${PYTHON3} ${CREATE_PINMAP} | 
|  | --design_json ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.json | 
|  | --pinmap_csv ${PINMAP} | 
|  | --module ${TOP} > ${CMAKE_CURRENT_BINARY_DIR}/${NAME} | 
|  | DEPENDS | 
|  | ${PYTHON3} | 
|  | ${CREATE_PINMAP} | 
|  | ${PINMAP} ${PINMAP_TARGET} | 
|  | ${NAME}.json | 
|  | ) | 
|  |  | 
|  | add_file_target(FILE ${GENERATE_PINMAP_NAME} GENERATED) | 
|  | endfunction() | 
|  |  | 
|  | function(add_autosim) | 
|  | # ~~~ | 
|  | #   ADD_AUTOSIM( | 
|  | #     NAME <name of autosim target> | 
|  | #     TOP <name of top module> | 
|  | #     SOURCES <source list to autosim> | 
|  | #     CYCLES <number of cycles to sim> | 
|  | #   ) | 
|  | # ~~~ | 
|  | # | 
|  | set(options) | 
|  | set(oneValueArgs NAME ARCH TOP CYCLES) | 
|  | set(multiValueArgs SOURCES) | 
|  |  | 
|  | cmake_parse_arguments( | 
|  | ADD_AUTOSIM | 
|  | "${options}" | 
|  | "${oneValueArgs}" | 
|  | "${multiValueArgs}" | 
|  | ${ARGN} | 
|  | ) | 
|  |  | 
|  | set(SOURCE_FILES "") | 
|  | set(SOURCE_FILES_DEPS "") | 
|  | foreach(SRC ${ADD_AUTOSIM_SOURCES}) | 
|  | append_file_dependency(SOURCE_FILES_DEPS ${SRC}) | 
|  | append_file_location(SOURCE_FILES ${SRC}) | 
|  | endforeach() | 
|  |  | 
|  | get_target_property_required(YOSYS env YOSYS) | 
|  |  | 
|  | set(AUTOSIM_VCD ${ADD_AUTOSIM_NAME}.vcd) | 
|  | get_cells_sim_path(CELLS_SIM_LOCATION ${ADD_AUTOSIM_ARCH}) | 
|  | add_custom_command( | 
|  | OUTPUT ${AUTOSIM_VCD} | 
|  | COMMAND ${YOSYS} -p "prep -top ${ADD_AUTOSIM_TOP}; $<SEMICOLON> sim -clock clk -n ${ADD_AUTOSIM_CYCLES} -vcd ${AUTOSIM_VCD} -zinit ${ADD_AUTOSIM_TOP}" ${SOURCE_FILES} ${CELLS_SIM_LOCATION} | 
|  | DEPENDS ${YOSYS} ${SOURCE_FILES_DEPS} ${CELLS_SIM_LOCATION} | 
|  | VERBATIM | 
|  | ) | 
|  |  | 
|  | add_custom_target(${ADD_AUTOSIM_NAME} DEPENDS ${AUTOSIM_VCD}) | 
|  |  | 
|  | add_custom_target(${ADD_AUTOSIM_NAME}_view | 
|  | COMMAND ${GTKWAVE} ${AUTOSIM_VCD} | 
|  | DEPENDS ${AUTOSIM_VCD} | 
|  | ) | 
|  | endfunction() |