diff --git a/cmake/hwip.cmake b/cmake/hwip.cmake index cc3b333..d89a050 100644 --- a/cmake/hwip.cmake +++ b/cmake/hwip.cmake @@ -9,11 +9,33 @@ include("${CMAKE_CURRENT_LIST_DIR}/utils/safe_get_target_property.cmake") # This function is a wrapper around the cmake built-in # `add_library() `_ function. # It generates the library name using the vendor, library, name, and version (VLNV) information passed -# in arguments (see get_ipname()). It creates two alias libraries to the default ______: -# +# in arguments (see create_ip_vlnv()). It creates two alias libraries to the default ______: +# # * :::::: ('__' replaced by '::') # * :::: (short name without the version) # +# This function can be used in FULL and SHORT form: +# Full form: +# ``` +# add_ip(ip +# VENDOR vendor +# LIBRARY lib +# VERSION 1.2.3 +# ) +# ``` +# In full form it is possible to ommit VENDOR, LIBRARY and VERSION, although it is not recommended. +# +# Ommiting them all would have following signature: +# ``` +# add_ip(ip2) +# ``` +# +# Short form: +# ``` +# add_ip(vendor2::lib2::ip2::1.2.2) +# ``` +# In short form only the full VLNV format is accepted +# # :param IP_NAME: The name of the IP. # :type IP_NAME: string # @@ -27,24 +49,33 @@ include("${CMAKE_CURRENT_LIST_DIR}/utils/safe_get_target_property.cmake") # :type VERSION: string #]] function(add_ip IP_NAME) - cmake_parse_arguments(ARG "" "VERSION;DESCRIPTION;VENDOR;LIBRARY" "" ${ARGN}) + cmake_parse_arguments(ARG "" "VENDOR;LIBRARY;VERSION;DESCRIPTION" "" ${ARGN}) # Vendor and library arguments are expected at the minimum if(ARG_UNPARSED_ARGUMENTS) message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} passed unrecognized argument " "${ARG_UNPARSED_ARGUMENTS}") endif() + + # If none of optional arguments VENDOR, LIBRARY, VERSION are passed expect to receive VLNV format in IP_NAME like vendor::lib::ip::0.0.1 + if(NOT ARG_VENDOR AND NOT ARG_LIBRARY AND NOT ARG_VERSION) + unset(ARG_VENDOR) + parse_ip_vlnv(${IP_NAME} VENDOR LIBRARY IP_NAME VERSION) + set(ARG_VENDOR ${VENDOR}) + set(ARG_LIBRARY ${LIBRARY}) + set(ARG_VERSION ${VERSION}) + endif() # Issue a warning if one of the VLNV information is not passed (this triggers an error later anyway) if((NOT ARG_VERSION OR NOT ARG_VENDOR OR NOT ARG_LIBRARY) AND NOT SOCMAKE_NOWARN_VLNV) - message(WARNING "Consider using full VLNV format\n\ - IP block: ${IP_NAME}\n\ - VENDOR: ${ARG_VENDOR}\n\ - LIBRARY: ${ARG_LIBRARY}\n\ - VERSION: ${ARG_VERSION}") + message(WARNING "Consider using full VLNV format\n\ + IP block: ${IP_NAME}\n\ + VENDOR: ${ARG_VENDOR}\n\ + LIBRARY: ${ARG_LIBRARY}\n\ + VERSION: ${ARG_VERSION}") endif() # Create the IP unique name using VLNV information - get_ipname(IP_LIB ${IP_NAME} VENDOR "${ARG_VENDOR}" LIBRARY "${ARG_LIBRARY}" VERSION "${ARG_VERSION}") - + create_ip_vlnv(IP_LIB ${IP_NAME} VENDOR "${ARG_VENDOR}" LIBRARY "${ARG_LIBRARY}" VERSION "${ARG_VERSION}") + if(NOT TARGET ${IP_LIB}) add_library(${IP_LIB} INTERFACE) @@ -54,13 +85,20 @@ function(add_ip IP_NAME) endif() # TODO Maybe delete short name without version - get_ipname(IP_LIB_SHORT ${IP_NAME} VENDOR "${ARG_VENDOR}" LIBRARY "${ARG_LIBRARY}" VERSION "") - string(REPLACE "__" "::" ALIAS_NAME_SHORT "${IP_LIB_SHORT}") - if(NOT "${IP_LIB}" STREQUAL "${ALIAS_NAME_SHORT}") - add_library(${ALIAS_NAME_SHORT} ALIAS ${IP_LIB}) + if(ARG_VERSION) + create_ip_vlnv(IP_LIB_SHORT ${IP_NAME} VENDOR "${ARG_VENDOR}" LIBRARY "${ARG_LIBRARY}" VERSION "") + string(REPLACE "__" "::" ALIAS_NAME_SHORT "${IP_LIB_SHORT}") + if(NOT "${IP_LIB}" STREQUAL "${ALIAS_NAME_SHORT}") + add_library(${ALIAS_NAME_SHORT} ALIAS ${IP_LIB}) + endif() endif() endif() + # Unset the parent variables that might have been set by previous add_ip() call + unset(IP_VENDOR PARENT_SCOPE) + unset(IP_LIBRARY PARENT_SCOPE) + unset(IP_NAME PARENT_SCOPE) + unset(IP_VERSION PARENT_SCOPE) if(ARG_VENDOR) set(IP_VENDOR ${ARG_VENDOR} PARENT_SCOPE) set_target_properties(${IP_LIB} PROPERTIES VENDOR ${ARG_VENDOR}) @@ -101,7 +139,7 @@ endfunction() # :keyword VERSION: Version of the IP following a three-part version number (Major.Minor.Patch, e.g., 1.0.13). # :type VERSION: string #]] -function(get_ipname OUTVAR IP_NAME) +function(create_ip_vlnv OUTVAR IP_NAME) cmake_parse_arguments(ARG "" "VENDOR;LIBRARY;VERSION" "" ${ARGN}) if(ARG_UNPARSED_ARGUMENTS) message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} passed unrecognized argument " "${ARG_UNPARSED_ARGUMENTS}") @@ -121,11 +159,73 @@ function(get_ipname OUTVAR IP_NAME) set(${OUTVAR} ${LIB_NAME} PARENT_SCOPE) endfunction() +#[[[ +# This function parses IP name from the VLNV format e.g. (vendor::lib::ip::0.0.1) +# +# This functions appends the vendor, library, name, and version (VLNV) information separated by '__' +# to create a unique string representing an IP name. This string is used as the library name when +# when calling the cmake built-in +# `add_library() `_ function (see add_ip()). +# +# :param OUTVAR: The generate IP name. +# :type OUTVAR: string +# :param IP_NAME: The name of the IP. +# :type IP_NAME: string +# +# **Keyword Arguments** +# +# :keyword VENDOR: Name of the IP vendor. +# :type VENDOR: string +# :keyword LIBRARY: Name of the IP library. +# :type LIBRARY: string +# :keyword VERSION: Version of the IP following a three-part version number (Major.Minor.Patch, e.g., 1.0.13). +# :type VERSION: string +#]] +function(parse_ip_vlnv IP_VLNV VENDOR LIBRARY IP_NAME VERSION) + message("IP_VLNV: ${IP_VLNV}") + cmake_parse_arguments(ARG "" "" "" ${ARGN}) + if(ARG_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} passed unrecognized argument " "${ARG_UNPARSED_ARGUMENTS}") + endif() + + # Convert IP_VLNV into a list of tokens by replacing :: with ; + string(REPLACE "::" ";" IP_TOKENS ${IP_VLNV}) + # Remove empty list elements in case something like vendor::::ip::1.2.3 is passed + list(REMOVE_ITEM IP_TOKENS "") + + # Raise an error if there are different than 4 tokens provided (`add_ip(vendor::lib::ip::0.0.1)`), unless its only 1 (`add_ip(ip)`) + list(LENGTH IP_TOKENS TOKEN_CNT) + + # Its alowed for IP_VLNV to have 4 tokens (FULL) `add_ip(vendor::lib::ip::0.0.1)` + if(TOKEN_CNT EQUAL 4) + # Get elements of the list + list(GET IP_TOKENS 0 VENDOR) + list(GET IP_TOKENS 1 LIBRARY) + list(GET IP_TOKENS 2 IP_NAME) + list(GET IP_TOKENS 3 VERSION) + # Its alowed for IP_VLNV to have 1 token (SHORT) `add_ip(ip)` + elseif(TOKEN_CNT EQUAL 1) + set(IP_NAME ${IP_VLNV}) + unset(VENDOR) + unset(LIBRARY) + unset(VERSION) + # Anything else is not allowed and will throw an error + else() + message(FATAL_ERROR "Please specify full VLNV format for IP: ${IP_VLNV}") + endif() + + # Set output variables + set(VENDOR ${VENDOR} PARENT_SCOPE) + set(LIBRARY ${LIBRARY} PARENT_SCOPE) + set(IP_NAME ${IP_NAME} PARENT_SCOPE) + set(VERSION ${VERSION} PARENT_SCOPE) +endfunction() + # IS THIS REALLY NECESSARY? # If only IP name is given without full VLNV, assume rest from the project variables function(ip_assume_last VLNV IP_NAME) # TODO check SOURCE DIR if its the same as current if(NOT TARGET ${IP_NAME}) - get_ipname(IP_LIB ${IP_NAME} VENDOR "${IP_VENDOR}" LIBRARY "${IP_LIBRARY}" VERSION "${IP_VERSION}") + create_ip_vlnv(IP_LIB ${IP_NAME} VENDOR "${IP_VENDOR}" LIBRARY "${IP_LIBRARY}" VERSION "${IP_VERSION}") endif() alias_dereference(IP_LIB ${IP_LIB}) set(${VLNV} ${IP_LIB} PARENT_SCOPE) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b629f2a..2f3123f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,5 @@ - add_custom_target(check - COMMAND ctest + COMMAND ctest $(JOBS) ) add_subdirectory(iverilog) diff --git a/tests/add_ip/add_ip.cmake b/tests/add_ip/add_ip.cmake index ebbb39e..33f2bf4 100644 --- a/tests/add_ip/add_ip.cmake +++ b/tests/add_ip/add_ip.cmake @@ -4,6 +4,7 @@ set(TEST_NAME add_ip) ct_add_test(NAME ${TEST_NAME}) function(${${TEST_NAME}}) + ## Test full add_ip() call add_ip(ip VENDOR vendor LIBRARY lib @@ -18,4 +19,24 @@ function(${${TEST_NAME}}) ct_assert_equal(IP_LIBRARY "lib") ct_assert_equal(IP_VERSION "1.2.3") ct_assert_target_exists(${IP_VENDOR}__${IP_LIBRARY}__${IP_NAME}__${IP_VERSION}) + + add_ip(ip4 + VERSION 1.1.1 + ) + ct_assert_target_exists(ip4::1.1.1) + ct_assert_target_exists(ip4__1.1.1) + + ## Test shortened add_ip() call + add_ip(vendor2::lib2::ip2::1.2.2) + + ct_assert_target_exists(vendor2::lib2::ip2::1.2.2) + ct_assert_target_exists(vendor2__lib2__ip2__1.2.2) + + ct_assert_equal(IP vendor2__lib2__ip2__1.2.2) + ct_assert_equal(IP_NAME "ip2") + ct_assert_equal(IP_VENDOR "vendor2") + ct_assert_equal(IP_LIBRARY "lib2") + ct_assert_equal(IP_VERSION "1.2.2") + ct_assert_target_exists(${IP_VENDOR}__${IP_LIBRARY}__${IP_NAME}__${IP_VERSION}) + endfunction() diff --git a/tests/add_ip/add_ip_1_token.cmake b/tests/add_ip/add_ip_1_token.cmake new file mode 100644 index 0000000..5101c9f --- /dev/null +++ b/tests/add_ip/add_ip_1_token.cmake @@ -0,0 +1,32 @@ +# This test will succed because its allowed to have short notation in `ip_link(ip)` call +include("${CMAKE_CURRENT_LIST_DIR}/../../CMakeLists.txt") + +set(TEST_NAME add_ip_1_token) + +ct_add_test(NAME ${TEST_NAME}) +function(${${TEST_NAME}}) + add_ip(vendor::lib::ip1::0.0.1) + ct_assert_target_exists(vendor::lib::ip1::0.0.1) + ct_assert_target_exists(vendor__lib__ip1__0.0.1) + ct_assert_equal(IP vendor__lib__ip1__0.0.1) + ct_assert_equal(IP_VENDOR vendor) + ct_assert_equal(IP_LIBRARY lib) + ct_assert_equal(IP_VERSION 0.0.1) + + add_ip(ip2 + VENDOR vendor + LIBRARY lib + ) + ct_assert_target_exists(vendor::lib::ip2) + ct_assert_equal(IP vendor__lib__ip2) + ct_assert_equal(IP_VENDOR vendor) + ct_assert_equal(IP_LIBRARY lib) + ct_assert_not_defined(IP_VERSION) + + add_ip(ip3) + ct_assert_target_exists(ip3) + ct_assert_equal(IP ip3) + ct_assert_not_defined(IP_VENDOR) + ct_assert_not_defined(IP_LIBRARY) + ct_assert_not_defined(IP_VERSION) +endfunction() diff --git a/tests/add_ip/add_ip_fail_2_tokens.cmake b/tests/add_ip/add_ip_fail_2_tokens.cmake new file mode 100644 index 0000000..f8a5a41 --- /dev/null +++ b/tests/add_ip/add_ip_fail_2_tokens.cmake @@ -0,0 +1,45 @@ +# This tests should fail because its not allowed to have different than 4 or 1 tokens in `ip_link()` call +include("${CMAKE_CURRENT_LIST_DIR}/../../CMakeLists.txt") + +set(TEST_NAME add_ip_fail_2_tokens_name_version) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(ip1::0.0.1) +endfunction() + +set(TEST_NAME add_ip_fail_2_tokens_vendor_name) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(vendor::ip1) +endfunction() + +set(TEST_NAME add_ip_fail_2_tokens_vendor_lib) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(vendor::lib) +endfunction() + +set(TEST_NAME add_ip_fail_2_tokens_vendor_version) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(vendor::0.0.1) +endfunction() + +set(TEST_NAME add_ip_fail_2_tokens_lib_version) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(lib::0.0.1) +endfunction() + + +set(TEST_NAME add_ip_fail_2_tokens_empty_token_1) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(lib::) +endfunction() + +set(TEST_NAME add_ip_fail_2_tokens_empty_token_2) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(::lib) +endfunction() diff --git a/tests/add_ip/add_ip_fail_3_tokens.cmake b/tests/add_ip/add_ip_fail_3_tokens.cmake new file mode 100644 index 0000000..dcb7301 --- /dev/null +++ b/tests/add_ip/add_ip_fail_3_tokens.cmake @@ -0,0 +1,51 @@ +# This tests should fail because its not allowed to have different than 4 or 1 tokens in `ip_link()` call +include("${CMAKE_CURRENT_LIST_DIR}/../../CMakeLists.txt") + +set(TEST_NAME add_ip_fail_3_tokens_vendor_lib_ip) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(vendor::lib::ip) +endfunction() + +set(TEST_NAME add_ip_fail_3_tokens_vendor_lib_version) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(vendor::lib::0.0.1) +endfunction() + +set(TEST_NAME add_ip_fail_3_tokens_lib_ip_version) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(lib::ip::0.0.1) +endfunction() + +set(TEST_NAME add_ip_fail_3_tokens_empty_token_1) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(::::vendor) +endfunction() + +set(TEST_NAME add_ip_fail_3_tokens_empty_token_2) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(::vendor::lib) +endfunction() + +set(TEST_NAME add_ip_fail_3_tokens_empty_token_3) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(vendor::::lib) +endfunction() + +set(TEST_NAME add_ip_fail_3_tokens_empty_token_4) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(vendor::lib::) +endfunction() + +set(TEST_NAME add_ip_fail_3_tokens_empty_token_5) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(vendor::::) +endfunction() + diff --git a/tests/add_ip/add_ip_fail_4_tokens.cmake b/tests/add_ip/add_ip_fail_4_tokens.cmake new file mode 100644 index 0000000..f65f9dc --- /dev/null +++ b/tests/add_ip/add_ip_fail_4_tokens.cmake @@ -0,0 +1,34 @@ +# This tests should fail because its not allowed to have different than 4 or 1 tokens in `ip_link()` call +include("${CMAKE_CURRENT_LIST_DIR}/../../CMakeLists.txt") + +set(TEST_NAME add_ip_fail_4_tokens_empty_token_1) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(::::::vendor) +endfunction() + +set(TEST_NAME add_ip_fail_4_tokens_empty_token_2) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(::::vendor::) +endfunction() + +set(TEST_NAME add_ip_fail_4_tokens_empty_token_3) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(::vendor::lib::) +endfunction() + +set(TEST_NAME add_ip_fail_4_tokens_empty_token_4) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(vendor::lib::::0.0.1) +endfunction() + +set(TEST_NAME add_ip_fail_4_tokens_empty_token_5) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(vendor::lib::ip::) +endfunction() + + diff --git a/tests/add_ip/add_ip_fail_too_many_tokens.cmake b/tests/add_ip/add_ip_fail_too_many_tokens.cmake new file mode 100644 index 0000000..fb0bace --- /dev/null +++ b/tests/add_ip/add_ip_fail_too_many_tokens.cmake @@ -0,0 +1,20 @@ +# This tests should fail because its not allowed to have different than 4 or 1 tokens in `ip_link()` call +include("${CMAKE_CURRENT_LIST_DIR}/../../CMakeLists.txt") + +set(TEST_NAME add_ip_fail_5_tokens) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(vendor::lib::ip::0.0.1::token) +endfunction() + +set(TEST_NAME add_ip_fail_6_tokens) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(vendor::lib::ip::0.0.1::token1::token2) +endfunction() + +set(TEST_NAME add_ip_fail_7_tokens) +ct_add_test(NAME ${TEST_NAME} EXPECTFAIL) +function(${${TEST_NAME}}) + add_ip(vendor::lib::ip::0.0.1::token1::token2::token3) +endfunction() diff --git a/tests/ip_link/ip_link_self_link_fatal.cmake b/tests/ip_link/ip_link_self_link_fatal.cmake index 9d9870b..ecc3a3d 100644 --- a/tests/ip_link/ip_link_self_link_fatal.cmake +++ b/tests/ip_link/ip_link_self_link_fatal.cmake @@ -1,3 +1,4 @@ +# This test is expected to throw FATAL_ERROR because `ip_link()` links ip1 to itself include("${CMAKE_CURRENT_LIST_DIR}/../../CMakeLists.txt") set(TEST_NAME ip_link_self_link_fatal) diff --git a/tests/peakrdl/print/CMakeLists.txt b/tests/peakrdl/print/CMakeLists.txt index ba90731..a895a5c 100644 --- a/tests/peakrdl/print/CMakeLists.txt +++ b/tests/peakrdl/print/CMakeLists.txt @@ -87,3 +87,4 @@ add_test(NAME ${PROJECT_NAME} COMMAND /bin/bash -c "diff <(make ${IP}_peakrdl_print | sed -e 's/\\x1b\[[0-9;]*m//g') <(cat ${CMAKE_CURRENT_LIST_DIR}/golden.txt)" # Diff with golden, and ignore colours in make output with sed command ) +set_property(TEST ${PROJECT_NAME} PROPERTY LABELS peakrdl)