| # 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() |