| function(COMMON_VIVADO_TARGETS) | 
 |   # ~~~ | 
 |   # COMMON_VIVADO_TARGETS( | 
 |   #   NAME <name> | 
 |   #   WORK_DIR <working directory> | 
 |   #   BITSTREAM <bitstream> | 
 |   #   DEPS <dependency list> | 
 |   #   [MAKE_DIFF_FASM] | 
 |   #   ) | 
 |   # ~~~ | 
 |   # | 
 |   # Generates common Vivado targets for running Vivado tcl scripts to generate | 
 |   # the Vivado checkpoint and project, and creates the following dummy targets: | 
 |   # | 
 |   # - ${NAME}_load_dcp - Load generated checkpoint.  This contains routing and | 
 |   #                      placement details. | 
 |   # - ${NAME}_load_xpr - Load generated project.  This can be used for | 
 |   #                      behavioral simulation. | 
 |   # - ${NAME}_sim - Load project and launches simulation. | 
 |   # | 
 |   # The MAKE_DIFF_FASM option generates a diff between the input BITSTREAM | 
 |   # and the output from Vivado, and attaches that diff generation to | 
 |   # "all_xc7_diff_fasm" which can used to verify FASM. | 
 |   # | 
 |   set(options MAKE_DIFF_FASM) | 
 |   set(oneValueArgs NAME PRJRAY_DIR PRJRAY_DB_DIR WORK_DIR BITSTREAM) | 
 |   set(multiValueArgs DEPS) | 
 |   cmake_parse_arguments( | 
 |       COMMON_VIVADO_TARGETS | 
 |     "${options}" | 
 |     "${oneValueArgs}" | 
 |     "${multiValueArgs}" | 
 |     ${ARGN} | 
 |   ) | 
 |  | 
 |   get_target_property_required(PYTHON3 env PYTHON3) | 
 |   get_target_property_required(BITREAD env BITREAD) | 
 |  | 
 |   set(NAME ${COMMON_VIVADO_TARGETS_NAME}) | 
 |   set(WORK_DIR ${COMMON_VIVADO_TARGETS_WORK_DIR}) | 
 |   set(PRJRAY_DIR ${COMMON_VIVADO_TARGETS_PRJRAY_DIR}) | 
 |   set(PRJRAY_DB_DIR ${COMMON_VIVADO_TARGETS_PRJRAY_DB_DIR}) | 
 |   set(DEPS ${COMMON_VIVADO_TARGETS_DEPS}) | 
 |   set(BITSTREAM ${COMMON_VIVADO_TARGETS_BITSTREAM}) | 
 |  | 
 |   add_custom_command( | 
 |     OUTPUT | 
 |         ${WORK_DIR}/design_${NAME}.dcp | 
 |         ${WORK_DIR}/design_${NAME}.xpr | 
 |         ${WORK_DIR}/design_${NAME}.bit | 
 |         ${WORK_DIR}/design_${NAME}_utilization.rpt | 
 |         ${WORK_DIR}/design_${NAME}_clock_utilization.rpt | 
 |         ${WORK_DIR}/design_${NAME}_power.rpt | 
 |         ${WORK_DIR}/design_${NAME}_timing_summary.rpt | 
 |         ${WORK_DIR}/design_${NAME}_route_status.rpt | 
 |     COMMAND ${CMAKE_COMMAND} -E remove -f ${WORK_DIR}/design_${NAME}.dcp | 
 |     COMMAND ${CMAKE_COMMAND} -E remove -f ${WORK_DIR}/design_${NAME}.xpr | 
 |     COMMAND ${PRJRAY_DIR}/utils/vivado.sh -mode batch -source | 
 |         ${CMAKE_CURRENT_BINARY_DIR}/${NAME}_runme.tcl | 
 |         > ${CMAKE_CURRENT_BINARY_DIR}/${WORK_DIR}/vivado.stdout.log | 
 |     WORKING_DIRECTORY ${WORK_DIR} | 
 |     DEPENDS ${DEPS} ${NAME}_runme.tcl | 
 |     ) | 
 |  | 
 |   add_custom_target( | 
 |       ${NAME}_load_dcp | 
 |       COMMAND ${PRJRAY_DIR}/utils/vivado.sh design_${NAME}.dcp | 
 |       WORKING_DIRECTORY ${WORK_DIR} | 
 |       DEPENDS ${WORK_DIR}/design_${NAME}.dcp | 
 |       ) | 
 |  | 
 |   add_custom_target( | 
 |       ${NAME}_load_xpr | 
 |       COMMAND ${PRJRAY_DIR}/utils/vivado.sh design_${NAME}.xpr | 
 |       WORKING_DIRECTORY ${WORK_DIR} | 
 |       DEPENDS ${WORK_DIR}/design_${NAME}.xpr | 
 |       ) | 
 |  | 
 |   add_custom_target( | 
 |       ${NAME}_sim | 
 |       COMMAND ${PRJRAY_DIR}/utils/vivado.sh | 
 |         design_${NAME}.xpr -source ${CMAKE_CURRENT_BINARY_DIR}/${NAME}_sim.tcl | 
 |       WORKING_DIRECTORY ${WORK_DIR} | 
 |       DEPENDS ${WORK_DIR}/design_${NAME}.xpr ${NAME}_sim.tcl | 
 |       ) | 
 |  | 
 |   set(CLEAN_JSON5 ${f4pga-arch-defs_SOURCE_DIR}/utils/clean_json5.py) | 
 |   add_custom_command( | 
 |       OUTPUT ${WORK_DIR}/timing_${NAME}.json | 
 |       COMMAND ${PRJRAY_DIR}/utils/vivado.sh | 
 |         design_${NAME}.dcp | 
 |         -mode batch | 
 |         -source | 
 |             ${f4pga-arch-defs_SOURCE_DIR}/xilinx/common/utils/output_timing.tcl | 
 |         -tclargs | 
 |             ${f4pga-arch-defs_SOURCE_DIR}/xilinx/common/utils/timing_utils.tcl | 
 |             ${CMAKE_CURRENT_BINARY_DIR}/${WORK_DIR}/timing_${NAME}.json5 | 
 |         > ${CMAKE_CURRENT_BINARY_DIR}/${WORK_DIR}/vivado_timing.stdout.log | 
 |       COMMAND ${PYTHON3} ${CLEAN_JSON5} | 
 |         < ${CMAKE_CURRENT_BINARY_DIR}/${WORK_DIR}/timing_${NAME}.json5 | 
 |         > ${CMAKE_CURRENT_BINARY_DIR}/${WORK_DIR}/timing_${NAME}.json | 
 |       WORKING_DIRECTORY ${WORK_DIR} | 
 |       DEPENDS | 
 |         ${WORK_DIR}/design_${NAME}.dcp | 
 |         ${PYTHON3} | 
 |       ) | 
 |  | 
 |   add_custom_command( | 
 |       OUTPUT ${WORK_DIR}/design_${NAME}.bit.fasm | 
 |       COMMAND | 
 |       ${CMAKE_COMMAND} -E env PYTHONPATH=${PRJRAY_DIR}:${PRJRAY_DIR}/third_party/fasm | 
 |         ${PYTHON3} ${PRJRAY_DIR}/utils/bit2fasm.py | 
 |           --part ${PART} | 
 |           --db-root ${PRJRAY_DB_DIR}/${PRJRAY_ARCH} | 
 |           --bitread ${BITREAD} | 
 |           --verbose | 
 |           ${CMAKE_CURRENT_BINARY_DIR}/${WORK_DIR}/design_${NAME}.bit | 
 |           > ${CMAKE_CURRENT_BINARY_DIR}/${WORK_DIR}/design_${NAME}.bit.fasm | 
 |       WORKING_DIRECTORY ${WORK_DIR} | 
 |       DEPENDS | 
 |         ${PYTHON3} | 
 |         ${WORK_DIR}/design_${NAME}.bit | 
 |       ) | 
 |  | 
 |   get_file_location(BITSTREAM_LOCATION ${BITSTREAM}) | 
 |   append_file_dependency(DEPS ${BITSTREAM}) | 
 |  | 
 |   add_custom_target(${NAME} DEPENDS ${WORK_DIR}/design_${NAME}.dcp) | 
 |   add_custom_target(${NAME}_timing DEPENDS ${WORK_DIR}/timing_${NAME}.json) | 
 |   add_custom_target(${NAME}_fasm DEPENDS ${WORK_DIR}/design_${NAME}.bit.fasm) | 
 |  | 
 |   if(${COMMON_VIVADO_TARGETS_MAKE_DIFF_FASM}) | 
 |     add_custom_target(${NAME}_diff_fasm | 
 |         COMMAND diff -u | 
 |             ${BITSTREAM_LOCATION}.fasm | 
 |             ${CMAKE_CURRENT_BINARY_DIR}/${WORK_DIR}/design_${NAME}.bit.fasm | 
 |         DEPENDS | 
 |             ${DEPS} | 
 |             ${CMAKE_CURRENT_BINARY_DIR}/${WORK_DIR}/design_${NAME}.bit.fasm | 
 |         ) | 
 |   endif() | 
 | endfunction() | 
 |  | 
 | function(ADD_VIVADO_TARGET) | 
 |   # ~~~ | 
 |   # ADD_VIVADO_TARGET( | 
 |   #   NAME <name> | 
 |   #   PARENT_NAME <name> | 
 |   #   CLOCK_PINS list of clock pins | 
 |   #   CLOCK_PERIODS list of clock periods | 
 |   #   [XDC <xdc file>] | 
 |   #   [DISABLE_DIFF_TEST] | 
 |   #   ) | 
 |   # ~~~ | 
 |   # | 
 |   # ADD_VIVADO_TARGET generates a Vivado project and design checkpoint from | 
 |   # the output of a 7-series FPGA target. | 
 |   # | 
 |   # Inputs to Vivado are the output of the FASM to verilog process. | 
 |   # | 
 |   # PARENT_NAME is the name of the FPGA target being used as input for these | 
 |   # targets. | 
 |   # | 
 |   # CLOCK_PINS and CLOCK_PERIODS should be lists of the same length. | 
 |   # CLOCK_PERIODS should be in nanoseconds. | 
 |   # | 
 |   # XDC should be a filename with XDC commands to run prior to analysis. | 
 |   # | 
 |   # DISABLE_DIFF_TEST can be added to not add this target to all_xc7_diff_fasm. | 
 |   # | 
 |   # New targets: | 
 |   #  <NAME>_load_dcp - Launch vivado loading post-routing design checkpoint. | 
 |   #  <NAME>_load_xpr - Launch vivado loading project. | 
 |   #  <NAME>_sim - Launch vivado and setup simulation and clock forces. | 
 |   set(options DISABLE_DIFF_TEST) | 
 |   set(oneValueArgs NAME PARENT_NAME XDC) | 
 |   set(multiValueArgs CLOCK_PINS CLOCK_PERIODS) | 
 |   cmake_parse_arguments( | 
 |     ADD_VIVADO_TARGET | 
 |     "${options}" | 
 |     "${oneValueArgs}" | 
 |     "${multiValueArgs}" | 
 |     ${ARGN} | 
 |   ) | 
 |  | 
 |   set(NAME ${ADD_VIVADO_TARGET_NAME}) | 
 |   if(NOT DEFINED ENV{XRAY_VIVADO_SETTINGS}) | 
 |       message( WARNING "Vivado targets for ${NAME} not emitted, XRAY_VIVADO_SETTINGS env var must be set to point to Vivado settings.sh" ) | 
 |       return() | 
 |   endif() | 
 |  | 
 |  | 
 |   get_target_property_required(BITSTREAM ${ADD_VIVADO_TARGET_PARENT_NAME} BIT) | 
 |   get_target_property_required(BIT_VERILOG ${ADD_VIVADO_TARGET_PARENT_NAME} BIT_V) | 
 |   get_target_property_required(TOP ${ADD_VIVADO_TARGET_PARENT_NAME} TOP) | 
 |   get_target_property_required(BOARD ${ADD_VIVADO_TARGET_PARENT_NAME} BOARD) | 
 |   get_target_property_required(DEVICE ${BOARD} DEVICE) | 
 |   get_target_property_required(ARCH ${DEVICE} ARCH) | 
 |   get_target_property_required(PRJRAY_ARCH ${ARCH} PRJRAY_ARCH) | 
 |   get_target_property_required(PART ${BOARD} PART) | 
 |  | 
 |   get_target_property_required(FAMILY ${ARCH} FAMILY) | 
 |   get_target_property_required(DOC_PRJ ${ARCH} DOC_PRJ) | 
 |   get_target_property_required(DOC_PRJ_DB ${ARCH} DOC_PRJ_DB) | 
 |  | 
 |   set(PRJRAY_DIR ${DOC_PRJ}) | 
 |   set(PRJRAY_DB_DIR ${DOC_PRJ_DB}) | 
 |  | 
 |   set(DEPS) | 
 |   append_file_dependency(DEPS ${BIT_VERILOG}) | 
 |  | 
 |   get_file_location(BIT_VERILOG_LOCATION ${BIT_VERILOG}) | 
 |   set(BIT_XDC_LOCATION ${BIT_VERILOG_LOCATION}.xdc) | 
 |  | 
 |   if(NOT "${ADD_VIVADO_TARGET_CLOCK_PINS}" STREQUAL "") | 
 |     list(LENGTH ${ADD_VIVADO_TARGET_CLOCK_PINS} NUM_CLOCKS) | 
 |     list(LENGTH ${ADD_VIVADO_TARGET_CLOCK_PERIODS} NUM_CLOCK_PERIODS) | 
 |  | 
 |     if(NOT ${NUM_CLOCKS} EQUAL ${NUM_CLOCK_PERIODS}) | 
 |         message( FATAL_ERROR "Number of clock pins (${NUM_CLOCKS}) must match number of periods (${NUM_CLOCK_PERIODS})") | 
 |     endif() | 
 |     set(CLOCK_ARGS --clock_pins "${ADD_VIVADO_TARGET_CLOCK_PINS}" --clock_periods "${ADD_VIVADO_TARGET_CLOCK_PERIODS}") | 
 |   elseif() | 
 |     set(CLOCK_ARGS "") | 
 |   endif() | 
 |  | 
 |   if(NOT "${ADD_VIVADO_TARGET_XDC}" STREQUAL "") | 
 |       append_file_dependency(DEPS ${ADD_VIVADO_TARGET_XDC}) | 
 |       get_file_location(XDC_LOCATION ${ADD_VIVADO_TARGET_XDC}) | 
 |       set(XDC_ARGS --additional_xdc "${XDC_LOCATION}") | 
 |       set(CREATE_DCP_ARGS XDC ${ADD_VIVADO_TARGET_XDC}) | 
 |   elseif() | 
 |       set(XDC_ARGS "") | 
 |       set(CREATE_DCP_ARGS "") | 
 |   endif() | 
 |  | 
 |   get_target_property_required(PYTHON3 env PYTHON3) | 
 |  | 
 |   set(CREATE_RUNME ${f4pga-arch-defs_SOURCE_DIR}/xilinx/common/utils/vivado_create_runme.py) | 
 |   add_custom_command( | 
 |       OUTPUT ${NAME}_runme.tcl | 
 |       COMMAND ${PYTHON3} ${CREATE_RUNME} | 
 |         --name ${NAME} | 
 |         --verilog ${BIT_VERILOG_LOCATION} | 
 |         --routing_xdc ${BIT_XDC_LOCATION} | 
 |         --top ${TOP} | 
 |         --part ${PART} | 
 |         --output_tcl ${CMAKE_CURRENT_BINARY_DIR}/${NAME}_runme.tcl | 
 |         ${CLOCK_ARGS} | 
 |         ${XDC_ARGS} | 
 |       DEPENDS | 
 |         ${PYTHON3} | 
 |         ${CREATE_RUNME} | 
 |         ) | 
 |  | 
 |   set(CREATE_SIM ${f4pga-arch-defs_SOURCE_DIR}/xilinx/common/utils/vivado_create_sim.py) | 
 |   add_custom_command( | 
 |       OUTPUT ${NAME}_sim.tcl | 
 |       COMMAND ${PYTHON3} ${CREATE_SIM} | 
 |         --top ${TOP} | 
 |         --output_tcl ${CMAKE_CURRENT_BINARY_DIR}/${NAME}_sim.tcl | 
 |         ${CLOCK_ARGS} | 
 |       DEPENDS | 
 |         ${PYTHON3} | 
 |         ${CREATE_SIM} | 
 |         ) | 
 |  | 
 |   # Run Vivado in the same directory as VPR was run, this ensures a unique | 
 |   # directory, and presents Vivado filename collisions. | 
 |   get_filename_component(WORK_DIR ${BIT_VERILOG} DIRECTORY) | 
 |  | 
 |  | 
 |   COMMON_VIVADO_TARGETS( | 
 |       NAME ${NAME} | 
 |       PRJRAY_DIR ${PRJRAY_DIR} | 
 |       PRJRAY_DB_DIR ${PRJRAY_DB_DIR} | 
 |       WORK_DIR ${WORK_DIR} | 
 |       DEPS ${DEPS} | 
 |       BITSTREAM ${BITSTREAM} | 
 |       MAKE_DIFF_FASM) | 
 |  | 
 |   get_target_property_required(RAPIDWRIGHT_INSTALLED rapidwright RAPIDWRIGHT_INSTALLED) | 
 |   if(${RAPIDWRIGHT_INSTALLED}) | 
 |     CREATE_DCP_BY_INTERCHANGE( | 
 |         NAME ${NAME}_interchange | 
 |         PARENT_NAME ${ADD_VIVADO_TARGET_PARENT_NAME} | 
 |         WORK_DIR ${WORK_DIR}/interchange | 
 |         ${CREATE_DCP_ARGS} | 
 |         ) | 
 |   endif() | 
 |  | 
 |   if(NOT ${ADD_VIVADO_TARGET_DISABLE_DIFF_TEST}) | 
 |     if(${ALL_XC7_DIFF_FASM_VERILOG}) | 
 |       if(${ALL_XC7_DIFF_FASM_CHECK_VERILOG}) | 
 |         add_dependencies(all_${ARCH}_diff_fasm ${NAME}_diff_fasm) | 
 |       else() | 
 |         add_dependencies(all_${ARCH}_diff_fasm ${NAME}_fasm) | 
 |       endif() | 
 |     endif() | 
 |     if(${RAPIDWRIGHT_INSTALLED} AND ${ALL_XC7_DIFF_FASM_INTERCHANGE}) | 
 |       add_dependencies(all_${ARCH}_diff_fasm ${NAME}_interchange_diff_fasm) | 
 |     endif() | 
 |   endif() | 
 |  | 
 | endfunction() | 
 |  | 
 | function(ADD_VIVADO_PNR_TARGET) | 
 |   # ~~~ | 
 |   # ADD_VIVADO_PNR_TARGET( | 
 |   #   NAME <name> | 
 |   #   PARENT_NAME <name> | 
 |   #   CLOCK_PINS list of clock pins | 
 |   #   CLOCK_PERIODS list of clock periods | 
 |   #   [IOSTANDARD <iostandard>] | 
 |   #   [XDC <xdc file>] | 
 |   #   ) | 
 |   # ~~~ | 
 |   # | 
 |   # ADD_VIVADO_PNR_TARGET generates a Vivado project and design checkpoint from | 
 |   # the output of 7-series synthesis. | 
 |   # | 
 |   # Inputs to Vivado are the output verilog from the synthesis tool. | 
 |   # | 
 |   # PARENT_NAME is the name of the FPGA target being used as input for these | 
 |   # targets. | 
 |   # | 
 |   # CLOCK_PINS and CLOCK_PERIODS should be lists of the same length. | 
 |   # CLOCK_PERIODS should be in nanoseconds. | 
 |   # | 
 |   # Vivado requires pin constraints for all top-level IO.  ADD_VIVADO_PNR_TARGET | 
 |   # can generate constrains for a fixed IOSTANDARD if the IOSTANDARD argument | 
 |   # is supplied.  The XDC argument can be used if an existing constraint file | 
 |   # already exists.  For consistency, the port location constraints in the XDC | 
 |   # file should match the PCF file used for VPR. | 
 |   # | 
 |   # New targets: | 
 |   #  <NAME>_load_dcp - Launch vivado loading post-routing design checkpoint. | 
 |   #  <NAME>_load_xpr - Launch vivado loading project. | 
 |   #  <NAME>_sim - Launch vivado and setup simulation and clock forces. | 
 |   set(options) | 
 |   set(oneValueArgs NAME PARENT_NAME IOSTANDARD XDC) | 
 |   set(multiValueArgs CLOCK_PINS CLOCK_PERIODS) | 
 |   cmake_parse_arguments( | 
 |       ADD_VIVADO_PNR_TARGET | 
 |     "${options}" | 
 |     "${oneValueArgs}" | 
 |     "${multiValueArgs}" | 
 |     ${ARGN} | 
 |   ) | 
 |  | 
 |   set(NAME ${ADD_VIVADO_PNR_TARGET_NAME}) | 
 |  | 
 |   get_target_property_required(BITSTREAM ${ADD_VIVADO_PNR_TARGET_PARENT_NAME} BIT) | 
 |   get_target_property_required(SYNTH_V ${ADD_VIVADO_PNR_TARGET_PARENT_NAME} SYNTH_V) | 
 |   get_target_property_required(TOP ${ADD_VIVADO_PNR_TARGET_PARENT_NAME} TOP) | 
 |   get_target_property_required(BOARD ${ADD_VIVADO_PNR_TARGET_PARENT_NAME} BOARD) | 
 |   get_target_property_required(DEVICE ${BOARD} DEVICE) | 
 |   get_target_property_required(ARCH ${DEVICE} ARCH) | 
 |   get_target_property_required(PRJRAY_ARCH ${ARCH} PRJRAY_ARCH) | 
 |   get_target_property_required(PART ${BOARD} PART) | 
 |  | 
 |   get_target_property_required(YOSYS env YOSYS) | 
 |  | 
 |   get_target_property_required(QUIET_CMD env QUIET_CMD) | 
 |  | 
 |   get_target_property_required(PYTHON3 env PYTHON3) | 
 |  | 
 |   get_target_property_required(FAMILY ${ARCH} FAMILY) | 
 |   get_target_property_required(DOC_PRJ ${ARCH} DOC_PRJ) | 
 |   get_target_property_required(DOC_PRJ_DB ${ARCH} DOC_PRJ_DB) | 
 |  | 
 |   set(PRJRAY_DIR ${DOC_PRJ}) | 
 |   set(PRJRAY_DB_DIR ${DOC_PRJ_DB}) | 
 |  | 
 |   set(DEPS "") | 
 |   append_file_dependency(SYNTH_DEPS ${SYNTH_V}) | 
 |   get_file_location(SYNTH_V_LOC ${SYNTH_V}) | 
 |  | 
 |   # Unmap VPR specific things from synthesis output. | 
 |   get_filename_component(SYNTH_OUT_BASE ${SYNTH_V_LOC} NAME) | 
 |   get_file_location(BITSTREAM_LOC ${BITSTREAM}) | 
 |   get_filename_component(BASE_WORK_DIR ${BITSTREAM_LOC} DIRECTORY) | 
 |   set(SYNTH_OUT ${BASE_WORK_DIR}/${SYNTH_OUT_BASE}.vivado.v) | 
 |   set(UNMAP_V ${f4pga-arch-defs_SOURCE_DIR}/xilinx/${FAMILY}/techmap/unmap.v) | 
 |  | 
 |   add_custom_command( | 
 |       OUTPUT ${SYNTH_OUT} | 
 |       COMMAND ${QUIET_CMD} ${YOSYS} | 
 |         -b verilog -o ${SYNTH_OUT} | 
 |         -p "techmap -map ${UNMAP_V}" | 
 |         ${SYNTH_V_LOC}.premap.v | 
 |       DEPENDS ${YOSYS} | 
 |         ${QUIET_CMD} | 
 |         ${SYNTH_DEPS} ${SYNTH_V_LOC}.premap.v ${UNMAP_V} | 
 |         ) | 
 |  | 
 |   string(REPLACE "${CMAKE_CURRENT_BINARY_DIR}/" ""  SYNTH_OUT_REL ${SYNTH_OUT}) | 
 |   add_file_target(FILE ${SYNTH_OUT_REL} GENERATED) | 
 |   append_file_dependency(DEPS ${SYNTH_OUT_REL}) | 
 |  | 
 |   # Set or generate the XDC file | 
 |   set(XDC_FILE "") | 
 |   if(NOT ${ADD_VIVADO_PNR_TARGET_XDC} STREQUAL "UNDEFINED") | 
 |       get_file_location(XDC_FILE ${ADD_VIVADO_PNR_TARGET_XDC}) | 
 |       append_file_dependency(DEPS ${ADD_VIVADO_PNR_TARGET_XDC}) | 
 |   endif() | 
 |   if(NOT ${ADD_VIVADO_PNR_TARGET_IOSTANDARD} STREQUAL "UNDEFINED") | 
 |       if(NOT ${XDC_FILE} STREQUAL "") | 
 |           message(FATAL_ERROR "Cannot specify both XDC and IOSTANDARD") | 
 |       endif() | 
 |  | 
 |       get_target_property_required( | 
 |           INPUT_IO_FILE | 
 |           ${ADD_VIVADO_PNR_TARGET_PARENT_NAME} INPUT_IO_FILE) | 
 |  | 
 |       set(XDC_FILE ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.xdc) | 
 |       set(XDC_DEPS) | 
 |       append_file_dependency(XDC_DEPS ${INPUT_IO_FILE}) | 
 |       get_file_location(PCF_FILE ${INPUT_IO_FILE}) | 
 |       set(PCF_TO_XDC_TOOL ${f4pga-arch-defs_SOURCE_DIR}/xilinx/common/utils/prjxray_pcf_to_xdc.py) | 
 |  | 
 |       add_custom_command( | 
 |           OUTPUT ${NAME}.xdc | 
 |           COMMAND | 
 |           ${CMAKE_COMMAND} -E env PYTHONPATH=${f4pga-arch-defs_SOURCE_DIR}/utils | 
 |           ${PYTHON3} ${PCF_TO_XDC_TOOL} | 
 |             --pcf ${PCF_FILE} | 
 |             --xdc ${XDC_FILE} | 
 |             --iostandard ${ADD_VIVADO_PNR_TARGET_IOSTANDARD} | 
 |           DEPENDS ${PYTHON3} ${PCF_TO_XDC_TOOL} ${XDC_DEPS} | 
 |           ) | 
 |  | 
 |       add_file_target(FILE ${NAME}.xdc GENERATED) | 
 |  | 
 |       append_file_dependency(DEPS ${NAME}.xdc) | 
 |   endif() | 
 |  | 
 |   if(${XDC_FILE} STREQUAL "") | 
 |       message(FATAL_ERROR "Must specify either XDC or IOSTANDARD") | 
 |   endif() | 
 |  | 
 |   set(CREATE_RUNME ${f4pga-arch-defs_SOURCE_DIR}/xilinx/common/utils/vivado_create_runme.py) | 
 |   add_custom_command( | 
 |       OUTPUT ${NAME}_runme.tcl | 
 |       COMMAND ${PYTHON3} ${CREATE_RUNME} | 
 |         --name ${NAME} | 
 |         --verilog ${SYNTH_OUT} | 
 |         --routing_xdc ${XDC_FILE} | 
 |         --place_and_route | 
 |         --top ${TOP} | 
 |         --part ${PART} | 
 |         --clock_pins "${ADD_VIVADO_PNR_TARGET_CLOCK_PINS}" | 
 |         --clock_periods "${ADD_VIVADO_PNR_TARGET_CLOCK_PERIODS}" | 
 |         --output_tcl ${CMAKE_CURRENT_BINARY_DIR}/${NAME}_runme.tcl | 
 |       DEPENDS | 
 |         ${PYTHON3} | 
 |         ${CREATE_RUNME} | 
 |         ) | 
 |  | 
 |   set(CREATE_SIM ${f4pga-arch-defs_SOURCE_DIR}/xilinx/common/utils/vivado_create_sim.py) | 
 |   add_custom_command( | 
 |       OUTPUT ${NAME}_sim.tcl | 
 |       COMMAND ${PYTHON3} ${CREATE_SIM} | 
 |         --top ${TOP} | 
 |         --clock_pins "${ADD_VIVADO_PNR_TARGET_CLOCK_PINS}" | 
 |         --clock_periods "${ADD_VIVADO_PNR_TARGET_CLOCK_PERIODS}" | 
 |         --output_tcl ${CMAKE_CURRENT_BINARY_DIR}/${NAME}_sim.tcl | 
 |       DEPENDS | 
 |         ${PYTHON3} | 
 |         ${CREATE_SIM} | 
 |         ) | 
 |  | 
 |   # Run vivado in another directory. | 
 |   set(WORK_DIR ${BASE_WORK_DIR}/vivado_pnr) | 
 |   string(REPLACE "${CMAKE_CURRENT_BINARY_DIR}/" ""  WORK_DIR ${WORK_DIR}) | 
 |   add_custom_command( | 
 |       OUTPUT ${WORK_DIR} | 
 |       COMMAND ${CMAKE_COMMAND} -E make_directory ${WORK_DIR} | 
 |       ) | 
 |   list(APPEND DEPS ${WORK_DIR}) | 
 |  | 
 |   COMMON_VIVADO_TARGETS( | 
 |       NAME ${NAME} | 
 |       PRJRAY_DIR ${PRJRAY_DIR} | 
 |       PRJRAY_DB_DIR ${PRJRAY_DB_DIR} | 
 |       WORK_DIR ${WORK_DIR} | 
 |       DEPS ${DEPS} | 
 |       BITSTREAM ${BITSTREAM}) | 
 | endfunction() | 
 |  | 
 | function(PREPARE_RAPIDWRIGHT) | 
 |   # Creates a target rapidwright with the following envirnoment variables: | 
 |   #  RAPIDWRIGHT_INSTALLED - True if a valid RapidWright installation is | 
 |   #                          found at the variable RAPIDWRIGHT_PATH. | 
 |   #  RAPIDWRIGHT_PATH - If RAPIDWRIGHT_INSTALLED=TRUE, this points to the | 
 |   #                     directory where RapidWright is located. | 
 |   #  JAVA - If RAPIDWRIGHT_INSTALLED=TRUE, this points to the location of | 
 |   #         the Java runtime executable needed invoke RapidWright entry | 
 |   #         points. | 
 |   #  INVOKE_RAPIDWRIGHT - If RAPIDWRIGHT_INSTALLED=TRUE, this points to the | 
 |   #         location of the invoke_rapidwright.sh script which can be used to | 
 |   #         invoke RapidWright. | 
 |   add_custom_target(rapidwright) | 
 |   set_target_properties(rapidwright PROPERTIES RAPIDWRIGHT_INSTALLED FALSE) | 
 |  | 
 |   set(HAVE_RAPIDWRIGHT FALSE) | 
 |   set(HAVE_JAVA FALSE) | 
 |   set(HAVE_URAY_VIVADO FALSE) | 
 |  | 
 |   if(DEFINED RAPIDWRIGHT_PATH) | 
 |   elseif(DEFINED ENV{RAPIDWRIGHT_PATH}) | 
 |     set(RAPIDWRIGHT_PATH $ENV{RAPIDWRIGHT_PATH}) | 
 |   endif() | 
 |  | 
 |   if(EXISTS "${RAPIDWRIGHT_PATH}" AND EXISTS ${RAPIDWRIGHT_PATH}/interchange AND EXISTS ${RAPIDWRIGHT_PATH}/scripts/invoke_rapidwright.sh) | 
 |     set(HAVE_RAPIDWRIGHT TRUE) | 
 |   endif() | 
 |  | 
 |   if(${HAVE_RAPIDWRIGHT}) | 
 |     find_program(JAVA java) | 
 |     if(EXISTS ${JAVA}) | 
 |       set(HAVE_JAVA TRUE) | 
 |     endif() | 
 |   endif() | 
 |  | 
 |   if(DEFINED ENV{URAY_VIVADO_SETTINGS}) | 
 |       set(HAVE_URAY_VIVADO TRUE) | 
 |   endif() | 
 |  | 
 |   if(${HAVE_RAPIDWRIGHT} AND ${HAVE_JAVA} AND ${HAVE_URAY_VIVADO}) | 
 |     set_target_properties(rapidwright PROPERTIES | 
 |       RAPIDWRIGHT_INSTALLED TRUE | 
 |       RAPIDWRIGHT_PATH "${RAPIDWRIGHT_PATH}" | 
 |       INVOKE_RAPIDWRIGHT "${RAPIDWRIGHT_PATH}/scripts/invoke_rapidwright.sh" | 
 |       JAVA ${JAVA}) | 
 |   elseif(NOT ${HAVE_RAPIDWRIGHT}) | 
 |     message(STATUS "RAPIDWRIGHT_PATH not defined. Interchange support not enabled.") | 
 |   elseif(NOT ${HAVE_JAVA}) | 
 |     message(WARNING "RAPIDWRIGHT_PATH defined, but JAVA not found. Interchange support not enabled.") | 
 |   elseif(NOT ${HAVE_URAY_VIVADO}) | 
 |     message(WARNING "RAPIDWRIGHT_PATH defined, but URAY_VIVADO_SETTINGS not found. Interchange support not enabled.") | 
 |   endif() | 
 |  | 
 |   get_target_property_required(RAPIDWRIGHT_INSTALLED rapidwright RAPIDWRIGHT_INSTALLED) | 
 |   if(NOT ${ALL_XC7_DIFF_FASM_VERILOG} AND ${ALL_XC7_DIFF_FASM_INTERCHANGE} AND NOT ${RAPIDWRIGHT_INSTALLED}) | 
 |     message(SEND_ERROR "all_xc7_diff_fasm is set to only include interchange, but interchange support is not enabled.") | 
 |   endif() | 
 | endfunction() | 
 |  | 
 | function(CREATE_DCP_BY_INTERCHANGE) | 
 |   # ~~~ | 
 |   # CREATE_DCP_BY_INTERCHANGE( | 
 |   #   NAME <name> | 
 |   #   PARENT_NAME <parent name> | 
 |   #   WORK_DIR <work directory> | 
 |   #   ) | 
 |   # ~~~ | 
 |   # | 
 |   # Creates a DCP of parent target using the FPGA interchange and RapidWright. | 
 |   # | 
 |   # PARENT_NAME is the name of the FPGA target being used as input for these | 
 |   # new targets. | 
 |   # | 
 |   # New targets: | 
 |   #  <NAME> - Create the DCP and output a bitstream based on the DCP. | 
 |   #  <NAME>_diff_fasm - Diff the FASM between the PARENT_NAME bitstream and | 
 |   #     the bitstream generated from the DCP. | 
 |  | 
 |   set(options) | 
 |   set(oneValueArgs NAME PARENT_NAME WORK_DIR XDC) | 
 |   set(multiValueArgs) | 
 |   cmake_parse_arguments( | 
 |     CREATE_DCP | 
 |     "${options}" | 
 |     "${oneValueArgs}" | 
 |     "${multiValueArgs}" | 
 |     ${ARGN} | 
 |   ) | 
 |  | 
 |   set(NAME ${CREATE_DCP_NAME}) | 
 |   set(WORK_DIR ${CREATE_DCP_WORK_DIR}) | 
 |  | 
 |   get_target_property_required(BITREAD env BITREAD) | 
 |  | 
 |   get_target_property_required(BITSTREAM ${CREATE_DCP_PARENT_NAME} BIT) | 
 |   get_target_property_required(BIT_VERILOG ${CREATE_DCP_PARENT_NAME} BIT_V) | 
 |   get_target_property_required(BOARD ${CREATE_DCP_PARENT_NAME} BOARD) | 
 |   get_target_property_required(DEVICE ${BOARD} DEVICE) | 
 |   get_target_property_required(ARCH ${DEVICE} ARCH) | 
 |   get_target_property_required(PRJRAY_ARCH ${ARCH} PRJRAY_ARCH) | 
 |   get_target_property_required(PART ${BOARD} PART) | 
 |   get_target_property_required(PRJRAY_DIR ${ARCH} DOC_PRJ) | 
 |   get_target_property_required(PRJRAY_DB_DIR ${ARCH} DOC_PRJ_DB) | 
 |  | 
 |   set(DEPS) | 
 |   append_file_dependency(DEPS ${BIT_VERILOG}) | 
 |   get_file_location(BIT_VERILOG_LOCATION ${BIT_VERILOG}) | 
 |  | 
 |   get_target_property_required(JAVA rapidwright JAVA) | 
 |   get_target_property_required(RAPIDWRIGHT_PATH rapidwright RAPIDWRIGHT_PATH) | 
 |   get_target_property_required(INVOKE_RAPIDWRIGHT rapidwright INVOKE_RAPIDWRIGHT) | 
 |  | 
 |   add_custom_command( | 
 |       OUTPUT ${WORK_DIR}/${NAME}.dcp | 
 |       COMMAND ${CMAKE_COMMAND} -E make_directory ${WORK_DIR} | 
 |       COMMAND ${CMAKE_COMMAND} -E env | 
 |         JAVA=${JAVA} | 
 |         RAPIDWRIGHT_PATH=${RAPIDWRIGHT_PATH} | 
 |           ${INVOKE_RAPIDWRIGHT} | 
 |             com.xilinx.rapidwright.interchange.PhysicalNetlistToDcp | 
 |               ${BIT_VERILOG_LOCATION}.netlist | 
 |               ${BIT_VERILOG_LOCATION}.phys | 
 |               ${BIT_VERILOG_LOCATION}.inter.xdc | 
 |               ${WORK_DIR}/${NAME}.dcp | 
 |       DEPENDS ${DEPS} | 
 |       WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} | 
 |       ) | 
 |  | 
 |   add_file_target(FILE ${WORK_DIR}/${NAME}.dcp GENERATED) | 
 |   get_file_target(DCP_TARGET ${WORK_DIR}/${NAME}.dcp) | 
 |  | 
 |   add_custom_target(${NAME}) | 
 |   add_dependencies(${NAME} ${DCP_TARGET}) | 
 |  | 
 |   set(RUNME ${CMAKE_CURRENT_BINARY_DIR}/${WORK_DIR}/${NAME}_runme.tcl) | 
 |   set(RUNME_DEPS) | 
 |   append_file_dependency(RUNME_DEPS ${WORK_DIR}/${NAME}.dcp) | 
 |  | 
 |   set(XDC_EXTRA_ARGS "") | 
 |   if(NOT "${CREATE_DCP_XDC}" STREQUAL "") | 
 |       get_file_location(XDC_LOCATION ${CREATE_DCP_XDC}) | 
 |       set(XDC_EXTRA_ARGS "read_xdc -no_add ${XDC_LOCATION}") | 
 |       append_file_dependency(RUNME_DEPS ${CREATE_DCP_XDC}) | 
 |   endif() | 
 |  | 
 |   add_custom_command( | 
 |     OUTPUT ${WORK_DIR}/${NAME}_runme.tcl | 
 |     COMMAND ${CMAKE_COMMAND} -E make_directory ${WORK_DIR} | 
 |     COMMAND ${CMAKE_COMMAND} -E echo "open_checkpoint ${NAME}.dcp"                                     >  ${RUNME} | 
 |     COMMAND ${CMAKE_COMMAND} -E echo "${XDC_EXTRA_ARGS}"                                               >> ${RUNME} | 
 |     COMMAND ${CMAKE_COMMAND} -E echo "set_property CFGBVS VCCO [current_design]"                       >> ${RUNME} | 
 |     COMMAND ${CMAKE_COMMAND} -E echo "set_property CONFIG_VOLTAGE 3.3 [current_design]"                >> ${RUNME} | 
 |     COMMAND ${CMAKE_COMMAND} -E echo "set_property BITSTREAM.GENERAL.PERFRAMECRC YES [current_design]" >> ${RUNME} | 
 |     COMMAND ${CMAKE_COMMAND} -E echo "set_property IS_ENABLED 0 [get_drc_checks {LUTLP-1}]"            >> ${RUNME} | 
 |     COMMAND ${CMAKE_COMMAND} -E echo "set_property IS_ENABLED 0 [get_drc_checks {RTRES-2}]"            >> ${RUNME} | 
 |     COMMAND ${CMAKE_COMMAND} -E echo "report_utilization -file ${NAME}_utilization.rpt"                >> ${RUNME} | 
 |     COMMAND ${CMAKE_COMMAND} -E echo "report_clock_utilization -file ${NAME}_clock_utilization.rpt"    >> ${RUNME} | 
 |     COMMAND ${CMAKE_COMMAND} -E echo "report_timing_summary -datasheet -max_paths 10 -file ${NAME}_timing_summary.rpt" >> ${RUNME} | 
 |     COMMAND ${CMAKE_COMMAND} -E echo "report_power -file ${NAME}_power.rpt"                            >> ${RUNME} | 
 |     COMMAND ${CMAKE_COMMAND} -E echo "report_route_status -file ${NAME}_route_status.rpt"              >> ${RUNME} | 
 |     COMMAND ${CMAKE_COMMAND} -E echo "write_bitstream -force ${NAME}.bit"                              >> ${RUNME} | 
 |     ) | 
 |   add_file_target(FILE ${WORK_DIR}/${NAME}_runme.tcl GENERATED) | 
 |   append_file_dependency(RUNME_DEPS ${WORK_DIR}/${NAME}_runme.tcl) | 
 |  | 
 |   add_custom_command( | 
 |     OUTPUT | 
 |         ${WORK_DIR}/${NAME}.bit | 
 |         ${WORK_DIR}/${NAME}_utilization.rpt | 
 |         ${WORK_DIR}/${NAME}_clock_utilization.rpt | 
 |         ${WORK_DIR}/${NAME}_power.rpt | 
 |         ${WORK_DIR}/${NAME}_timing_summary.rpt | 
 |         ${WORK_DIR}/${NAME}_route_status.rpt | 
 |     COMMAND ${CMAKE_COMMAND} -E env XRAY_VIVADO_SETTINGS=$ENV{URAY_VIVADO_SETTINGS} ${PRJRAY_DIR}/utils/vivado.sh -mode batch -source ${RUNME} | 
 |         > ${CMAKE_CURRENT_BINARY_DIR}/${WORK_DIR}/vivado.stdout.log | 
 |     WORKING_DIRECTORY ${WORK_DIR} | 
 |     DEPENDS ${RUNME_DEPS} | 
 |     ) | 
 |  | 
 |   add_file_target(FILE ${WORK_DIR}/${NAME}.bit GENERATED) | 
 |  | 
 |   set(BIT2FASM_DEPS) | 
 |   append_file_dependency(BIT2FASM_DEPS ${WORK_DIR}/${NAME}.bit) | 
 |   add_custom_command( | 
 |       OUTPUT ${WORK_DIR}/${NAME}.bit.fasm | 
 |       COMMAND | 
 |       ${CMAKE_COMMAND} -E env PYTHONPATH=${PRJRAY_DIR}:${PRJRAY_DIR}/third_party/fasm | 
 |         ${PYTHON3} ${PRJRAY_DIR}/utils/bit2fasm.py | 
 |           --part ${PART} | 
 |           --db-root ${PRJRAY_DB_DIR}/${PRJRAY_ARCH} | 
 |           --bitread ${BITREAD} | 
 |           --verbose | 
 |           ${CMAKE_CURRENT_BINARY_DIR}/${WORK_DIR}/${NAME}.bit | 
 |           > ${CMAKE_CURRENT_BINARY_DIR}/${WORK_DIR}/${NAME}.bit.fasm | 
 |       WORKING_DIRECTORY ${WORK_DIR} | 
 |       DEPENDS | 
 |         ${BIT2FASM_DEPS} | 
 |       ) | 
 |  | 
 |   add_file_target(FILE ${WORK_DIR}/${NAME}.bit.fasm GENERATED) | 
 |  | 
 |   set(DIFF_FASM_DEPS) | 
 |   append_file_dependency(DIFF_FASM_DEPS ${WORK_DIR}/${NAME}.bit.fasm) | 
 |   append_file_dependency(DIFF_FASM_DEPS ${BITSTREAM}) | 
 |  | 
 |   get_file_location(BITSTREAM_LOCATION ${BITSTREAM}) | 
 |  | 
 |   add_custom_target(${NAME}_diff_fasm | 
 |       COMMAND diff -u | 
 |           ${BITSTREAM_LOCATION}.fasm | 
 |           ${CMAKE_CURRENT_BINARY_DIR}/${WORK_DIR}/${NAME}.bit.fasm | 
 |       DEPENDS | 
 |           ${DIFF_FASM_DEPS} | 
 |       ) | 
 | endfunction() |