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