blob: 7e437400ad019479a492edc02ed05c94ac582479 [file] [log] [blame] [edit]
function(QUICKLOGIC_DEFINE_DEVICE_TYPE)
# ~~~
# QUICKLOGIC_DEFINE_DEVICE_TYPE(
# FAMILY <family>
# ARCH <arch>
# DEVICE <device>
# PACKAGES <package> <package> ...
# [GRID_LIMIT <xmin>,<ymin>,<xmax>,<ymax>]
# PB_TYPES <pb_type> <pb_type> ...
# TECHFILE_NAME <techfile name>
# ROUTING_TIMING_FILE_NAME <routing timing CSV file>
# LIB_TIMING_FILES <list timing lib files [can be wildcard]>
# RAM_TIMING_SDF <name of the RAM timing data>
# RAM_PBTYPE_COPY <name of the RAM pb_type to use>
# )
# ~~~
set(options)
set(oneValueArgs FAMILY DEVICE ARCH GRID_LIMIT TECHFILE_NAME ROUTING_TIMING_FILE_NAME RAM_TIMING_SDF RAM_PBTYPE_COPY)
set(multiValueArgs PACKAGES PB_TYPES LIB_TIMING_FILES DONT_NORMALIZE_FILES)
cmake_parse_arguments(
QUICKLOGIC_DEFINE_DEVICE_TYPE
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
set(TECHFILE_NAME ${QUICKLOGIC_DEFINE_DEVICE_TYPE_TECHFILE_NAME})
set(FAMILY ${QUICKLOGIC_DEFINE_DEVICE_TYPE_FAMILY})
set(DEVICE ${QUICKLOGIC_DEFINE_DEVICE_TYPE_DEVICE})
set(ARCH ${QUICKLOGIC_DEFINE_DEVICE_TYPE_ARCH})
set(GRID_LIMIT ${QUICKLOGIC_DEFINE_DEVICE_TYPE_GRID_LIMIT})
set(PB_TYPES ${QUICKLOGIC_DEFINE_DEVICE_TYPE_PB_TYPES})
set(ROUTING_TIMING_FILE_NAME ${QUICKLOGIC_DEFINE_DEVICE_TYPE_ROUTING_TIMING_FILE_NAME})
set(LIB_TIMING_FILES ${QUICKLOGIC_DEFINE_DEVICE_TYPE_LIB_TIMING_FILES})
set(DONT_NORMALIZE_FILES ${QUICKLOGIC_DEFINE_DEVICE_TYPE_DONT_NORMALIZE_FILES})
set(RAM_TIMING_SDF ${QUICKLOGIC_DEFINE_DEVICE_TYPE_RAM_TIMING_SDF})
set(RAM_PBTYPE_COPY ${QUICKLOGIC_DEFINE_DEVICE_TYPE_RAM_PBTYPE_COPY})
set(DEVICE_TYPE ${DEVICE}-virt)
get_target_property_required(PYTHON3 env PYTHON3)
set(PHY_DB_FILE "db_phy.pickle")
set(VPR_DB_FILE "db_vpr.pickle")
set(ARCH_XML "arch.xml")
set(DEVICE_DIR_DATA ${DEVICE})
if(${DEVICE} STREQUAL "ql-pp3")
set(DEVICE_DIR_DATA "ql-eos-s3") # FIXME: use PP3 timing data when it will be available
endif()
# The techfile and routing timing file
set(TECHFILE "${f4pga-arch-defs_SOURCE_DIR}/third_party/${DEVICE}/Device Architecture Files/${TECHFILE_NAME}")
set(ROUTING_TIMING "${f4pga-arch-defs_SOURCE_DIR}/third_party/${DEVICE_DIR_DATA}/Timing Data Files/${ROUTING_TIMING_FILE_NAME}")
# Import data from the techfile
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${PHY_DB_FILE}
COMMAND python3 -m f4pga.utils.quicklogic.pp3.data_import
--techfile ${TECHFILE}
--routing-timing ${ROUTING_TIMING}
--db ${PHY_DB_FILE}
DEPENDS ${TECHFILE} ${ROUTING_TIMING}
)
add_file_target(FILE ${PHY_DB_FILE} GENERATED)
# Generate SDF files with timing data
set(LIB_TIMING_DIR "${f4pga-arch-defs_SOURCE_DIR}/third_party/${DEVICE_DIR_DATA}/Timing Data Files/")
set(SDF_TIMING_DIR "sdf")
get_target_property_required(QUICKLOGIC_TIMINGS_IMPORTER env QUICKLOGIC_TIMINGS_IMPORTER)
# TODO: How to handle different timing cases that depend on a cell config?
# For example BIDIR cells have different timings for different voltages.
#
# One idea is to have a different model for each in VPR.
#
# For now only files with the worst case scenario timings are taken.
set(TIMING_FILES "")
foreach(LIB ${LIB_TIMING_FILES})
file(GLOB TIMING_FILE
"${LIB_TIMING_DIR}/${LIB}"
)
list(APPEND TIMING_FILES ${TIMING_FILE})
endforeach()
set(SDF_FILE_TARGETS "")
foreach(LIB_TIMING_FILE ${TIMING_FILES})
get_filename_component(FILE_NAME ${LIB_TIMING_FILE} NAME)
get_filename_component(FILE_TITLE ${FILE_NAME} NAME_WE)
set(IMPORTER_OPTS "")
if(NOT ${FILE_NAME} IN_LIST DONT_NORMALIZE_FILES)
list(APPEND IMPORTER_OPTS "--normalize-cell-names")
list(APPEND IMPORTER_OPTS "--normalize-port-names")
endif()
set(SDF_TIMING_FILE ${SDF_TIMING_DIR}/${FILE_TITLE}.sdf)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${SDF_TIMING_FILE}
COMMAND ${CMAKE_COMMAND} -E make_directory ${SDF_TIMING_DIR}
COMMAND ${PYTHON3} -m quicklogic_timings_importer
${LIB_TIMING_FILE}
${SDF_TIMING_FILE}
${IMPORTER_OPTS}
DEPENDS ${PYTHON3} ${LIB_TIMING_FILE}
)
add_file_target(FILE ${SDF_TIMING_FILE} GENERATED)
append_file_dependency(SDF_FILE_TARGETS ${SDF_TIMING_FILE})
endforeach()
# Process the database, create the VPR database
get_file_target(PHY_DB_TARGET ${PHY_DB_FILE})
if(NOT "${GRID_LIMIT}" STREQUAL "")
separate_arguments(GRID_LIMIT_ARGS UNIX_COMMAND "--grid-limit ${GRID_LIMIT}")
else()
set(GRID_LIMIT_ARGS "")
endif()
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${VPR_DB_FILE}
COMMAND python3 -m f4pga.utils.quicklogic.pp3.prepare_vpr_database
--phy-db ${PHY_DB_FILE}
--vpr-db ${VPR_DB_FILE}
--sdf-dir ${SDF_TIMING_DIR}
${GRID_LIMIT_ARGS}
DEPENDS ${PHY_DB_TARGET} ${SDF_FILE_TARGETS}
)
add_file_target(FILE ${VPR_DB_FILE} GENERATED)
# Get dependencies for arch.xml
set(XML_DEPS "")
foreach(PB_TYPE ${PB_TYPES})
string(TOLOWER ${PB_TYPE} PB_TYPE_LOWER)
set(PB_TYPE_XML ${f4pga-arch-defs_SOURCE_DIR}/quicklogic/${FAMILY}/primitives/${PB_TYPE_LOWER}/${PB_TYPE_LOWER}.pb_type.xml)
set(MODEL_XML ${f4pga-arch-defs_SOURCE_DIR}/quicklogic/${FAMILY}/primitives/${PB_TYPE_LOWER}/${PB_TYPE_LOWER}.model.xml)
append_file_dependency(XML_DEPS ${PB_TYPE_XML})
append_file_dependency(XML_DEPS ${MODEL_XML})
endforeach()
# Generate model and pb_type XML for RAM
# This will generate model XML and pb_type XMLs. Since there are 4 RAMs
# there will be one pb_type for each of them with appropriate timings. Since
# we cannot model that in the VPR for now we simply use one for all 4 RAMs.
set(RAM_GENERATOR ${f4pga-arch-defs_SOURCE_DIR}/quicklogic/${FAMILY}/primitives/ram/make_rams.py)
set(RAM_MODE_DEFS ${f4pga-arch-defs_SOURCE_DIR}/quicklogic/${FAMILY}/primitives/ram/ram_modes.json)
set(RAM_SDF_FILE ${SDF_TIMING_DIR}/${RAM_TIMING_SDF}.sdf)
set(RAM_MODEL_XML "ram.model.xml")
set(RAM_PBTYPE_XML "ram.pb_type.xml")
set(RAM_CELLS_SIM "ram_sim.v")
set(RAM_CELLS_MAP "ram_map.v")
get_file_target(RAM_SDF_FILE_TARGET ${RAM_SDF_FILE})
add_custom_command(
OUTPUT ${RAM_MODEL_XML} ${RAM_PBTYPE_XML} ${RAM_CELLS_SIM} ${RAM_CELLS_MAP}
COMMAND ${PYTHON3} ${RAM_GENERATOR}
--device ${DEVICE}
--sdf ${RAM_SDF_FILE}
--mode-defs ${RAM_MODE_DEFS}
--xml-path ${CMAKE_CURRENT_BINARY_DIR}
--vlog-path ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E copy ${RAM_PBTYPE_COPY} ${RAM_PBTYPE_XML}
DEPENDS ${PYTHON3} ${RAM_GENERATOR} ${RAM_MODE_DEFS} ${RAM_SDF_FILE_TARGET}
)
add_file_target(FILE ${RAM_MODEL_XML} GENERATED)
add_file_target(FILE ${RAM_PBTYPE_XML} GENERATED)
add_file_target(FILE ${RAM_CELLS_SIM} GENERATED)
add_file_target(FILE ${RAM_CELLS_MAP} GENERATED)
# Generate the arch.xml
get_file_target(RAM_MODEL_XML_TARGET ${RAM_MODEL_XML})
get_file_target(RAM_PBTYPE_XML_TARGET ${RAM_PBTYPE_XML})
get_file_target(VPR_DB_TARGET ${VPR_DB_FILE})
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${ARCH_XML}
COMMAND python3 -m f4pga.utils.quicklogic.pp3.arch_import
--vpr-db ${VPR_DB_FILE}
--arch-out ${ARCH_XML}
--device ${DEVICE}
DEPENDS ${VPR_DB_TARGET} ${XML_DEPS} ${RAM_MODEL_XML_TARGET} ${RAM_PBTYPE_XML_TARGET}
)
add_file_target(FILE ${ARCH_XML} GENERATED)
# Timing import stuff
set(UPDATE_ARCH_TIMINGS ${f4pga-arch-defs_SOURCE_DIR}/utils/update_arch_timings.py)
set(PYTHON_SDF_TIMING_DIR ${f4pga-arch-defs_SOURCE_DIR}/third_party/python-sdf-timing)
set(BELS_MAP ${f4pga-arch-defs_SOURCE_DIR}/quicklogic/${FAMILY}/${DEVICE}-bels.json)
set(TIMING_IMPORT
"${CMAKE_COMMAND} -E env PYTHONPATH=${PYTHON_SDF_TIMING_DIR}:$PYTHONPATH \
${PYTHON3} ${UPDATE_ARCH_TIMINGS} \
--sdf_dir ${SDF_TIMING_DIR} \
--bels_map ${BELS_MAP} \
--out_arch /dev/stdout \
--input_arch /dev/stdin \
")
set(TIMING_DEPS ${SDF_FILE_TARGETS} ${BELS_MAP})
# Define the device type
define_device_type(
DEVICE_TYPE ${DEVICE_TYPE}
ARCH ${ARCH}
ARCH_XML ${ARCH_XML}
SCRIPT_OUTPUT_NAME timing
SCRIPTS TIMING_IMPORT
SCRIPT_DEPS TIMING_DEPS
)
# Set the device type properties
if(NOT "${GRID_LIMIT}" STREQUAL "")
set_target_properties(${DEVICE_TYPE} PROPERTIES USE_ROI TRUE)
else()
set_target_properties(${DEVICE_TYPE} PROPERTIES USE_ROI FALSE)
endif()
set_target_properties(
${DEVICE_TYPE}
PROPERTIES
PHY_DB_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${PHY_DB_FILE}
VPR_DB_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${VPR_DB_FILE}
CELLS_SIM ${CMAKE_CURRENT_SOURCE_DIR}/${RAM_CELLS_SIM}
CELLS_MAP ${CMAKE_CURRENT_SOURCE_DIR}/${RAM_CELLS_MAP}
LIMIT_GRAPH_TO_DEVICE FALSE
)
endfunction()
function(QUICKLOGIC_DEFINE_DEVICE)
# ~~~
# QUICKLOGIC_DEFINE_DEVICE(
# FAMILY <family>
# ARCH <arch>
# DEVICES <device> <device> ...
# PACKAGES <package> <package> ...
# )
# ~~~
set(options)
set(oneValueArgs FAMILY ARCH)
set(multiValueArgs DEVICES PACKAGES)
cmake_parse_arguments(
QUICKLOGIC_DEFINE_DEVICE
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
set(FAMILY ${QUICKLOGIC_DEFINE_DEVICE_FAMILY})
set(ARCH ${QUICKLOGIC_DEFINE_DEVICE_ARCH})
set(DEVICES ${QUICKLOGIC_DEFINE_DEVICE_DEVICES})
set(PACKAGES ${QUICKLOGIC_DEFINE_DEVICE_PACKAGES})
# For each device specified
list(LENGTH DEVICES DEVICE_COUNT)
math(EXPR DEVICE_COUNT_N_1 "${DEVICE_COUNT} - 1")
foreach(INDEX RANGE ${DEVICE_COUNT_N_1})
list(GET DEVICES ${INDEX} DEVICE)
# Include the device type subdirectory
set(DEVICE_TYPE ${DEVICE}-virt)
add_subdirectory(${DEVICE_TYPE})
# Get the VPR db file to add as dependency to RR graph patch
get_target_property_required(PHY_DB_FILE ${DEVICE_TYPE} PHY_DB_FILE)
get_target_property_required(VPR_DB_FILE ${DEVICE_TYPE} VPR_DB_FILE)
# RR graph patch dependencies
set(DEVICE_RR_PATCH_DEPS "")
append_file_dependency(DEVICE_RR_PATCH_DEPS ${VPR_DB_FILE})
# Define the device
define_device(
DEVICE ${DEVICE}
ARCH ${ARCH}
DEVICE_TYPE ${DEVICE_TYPE}
PACKAGES ${PACKAGES}
WIRE_EBLIF ${f4pga-arch-defs_SOURCE_DIR}/quicklogic/passthrough.eblif
RR_PATCH_DEPS ${DEVICE_RR_PATCH_DEPS}
CACHE_PLACE_DELAY
CACHE_LOOKAHEAD
CACHE_ARGS
--constant_net_method route
--clock_modeling route
--place_delay_model delta_override
--router_lookahead extended_map
--disable_errors check_unbuffered_edges:check_route:check_place
--suppress_warnings sum_pin_class:check_unbuffered_edges:load_rr_indexed_data_T_values:check_rr_node:trans_per_R:set_rr_graph_tool_comment
--route_chan_width 500
--allow_dangling_combinational_nodes on
--allowed_tiles_for_delay_model TL-LOGIC # TODO: Make this a parameter !
--allow_unrelated_clustering on
--balance_block_type_utilization on
--target_ext_pin_util 1.0
EXTRA_INSTALL_FILES
${PHY_DB_FILE}
)
endforeach()
endfunction()