From 1a73051d80a8541dcde5ef3213ef298b47d4136e Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Tue, 14 May 2024 11:58:10 +0200 Subject: [PATCH 1/9] cmake: cleanup hwm_v2.cmake module code Cleanup the Kconfig generating code in hwm_v2.cmake by moving common logic inside the kconfig_gen() helper function. This prepares the code for board extension feature. Signed-off-by: Torsten Rasmussen --- cmake/modules/hwm_v2.cmake | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/cmake/modules/hwm_v2.cmake b/cmake/modules/hwm_v2.cmake index 45238f212b391..b514a33c5b0a6 100644 --- a/cmake/modules/hwm_v2.cmake +++ b/cmake/modules/hwm_v2.cmake @@ -24,9 +24,11 @@ if(NOT HWMv2) endif() # Internal helper function for creation of Kconfig files. -function(kconfig_gen bin_dir file dirs) - file(MAKE_DIRECTORY "${bin_dir}") - set(kconfig_file ${bin_dir}/${file}) +function(kconfig_gen bin_dir file dirs comment) + set(kconfig_header "# Load ${comment} descriptions.\n") + set(kconfig_file ${KCONFIG_BINARY_DIR}/${bin_dir}/${file}) + file(WRITE ${kconfig_file} "${kconfig_header}") + foreach(dir ${dirs}) cmake_path(CONVERT "${dir}" TO_CMAKE_PATH_LIST dir) file(APPEND ${kconfig_file} "osource \"${dir}/${file}\"\n") @@ -92,28 +94,12 @@ while(TRUE) endwhile() list(REMOVE_DUPLICATES kconfig_soc_source_dir) -# Support multiple ARCH_ROOT and SOC_ROOT -set(arch_kconfig_file Kconfig) -set(soc_defconfig_file Kconfig.defconfig) -set(soc_zephyr_file Kconfig) -set(soc_kconfig_file Kconfig.soc) -set(soc_sysbuild_file Kconfig.sysbuild) -set(arch_kconfig_header "# Load arch Kconfig descriptions.\n") -set(defconfig_header "# Load Zephyr SoC Kconfig defconfig.\n") -set(soc_zephyr_header "# Load Zephyr SoC Kconfig descriptions.\n") -set(soc_kconfig_header "# Load SoC Kconfig descriptions.\n") -set(soc_sysbuild_header "# Load SoC sysbuild Kconfig descriptions.\n") -file(WRITE ${KCONFIG_BINARY_DIR}/arch/${arch_kconfig_file} "${arch_kconfig_header}") -file(WRITE ${KCONFIG_BINARY_DIR}/soc/${soc_defconfig_file} "${defconfig_header}") -file(WRITE ${KCONFIG_BINARY_DIR}/soc/${soc_zephyr_file} "${soc_zephyr_header}") -file(WRITE ${KCONFIG_BINARY_DIR}/soc/${soc_kconfig_file} "${soc_kconfig_header}") -file(WRITE ${KCONFIG_BINARY_DIR}/soc/${soc_sysbuild_file} "${soc_sysbuild_header}") - -kconfig_gen("${KCONFIG_BINARY_DIR}/arch" "${arch_kconfig_file}" "${kconfig_arch_source_dir}") -kconfig_gen("${KCONFIG_BINARY_DIR}/soc" "${soc_defconfig_file}" "${kconfig_soc_source_dir}") -kconfig_gen("${KCONFIG_BINARY_DIR}/soc" "${soc_zephyr_file}" "${kconfig_soc_source_dir}") -kconfig_gen("${KCONFIG_BINARY_DIR}/soc" "${soc_kconfig_file}" "${kconfig_soc_source_dir}") -kconfig_gen("${KCONFIG_BINARY_DIR}/soc" "${soc_sysbuild_file}" "${kconfig_soc_source_dir}") +# Support multiple ARCH_ROOT, SOC_ROOT and BOARD_ROOT +kconfig_gen("arch" "Kconfig" "${kconfig_arch_source_dir}" "Zephyr Arch Kconfig") +kconfig_gen("soc" "Kconfig.defconfig" "${kconfig_soc_source_dir}" "Zephyr SoC defconfig") +kconfig_gen("soc" "Kconfig" "${kconfig_soc_source_dir}" "Zephyr SoC Kconfig") +kconfig_gen("soc" "Kconfig.soc" "${kconfig_soc_source_dir}" "SoC Kconfig") +kconfig_gen("soc" "Kconfig.sysbuild" "${kconfig_soc_source_dir}" "Sysbuild SoC Kconfig") # Clear variables created by cmake_parse_arguments unset(SOC_V2_NAME) From 78420aaef161b24f302b87f3f4f05d7e51c37696 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Wed, 8 May 2024 13:10:48 +0200 Subject: [PATCH 2/9] cmake: scripts: support board extension Fixes: #69548 Support extending an existing board with new board variants. This commit introduces the following changes to allow a board to be extended out-of-tree. The board yaml schema is extended to support an extend field which will be used to identify the board to be extended. A board 'plank' can be extended like this: > board: > extend: plank > variants: > - name: ext > qualifier: soc1 For the rest of the build system this means that there is no longer a single board directory. The existing CMake variable BOARD_DIR is kept and reference the directory which defines the board. A new CMake variable BOARD_DIRECTORIES provides a list of all directories which defines board targets for the board. This means the directory which defines the board as well as all directories that extends the board. Signed-off-by: Torsten Rasmussen --- Kconfig.zephyr | 4 +- boards/Kconfig | 2 +- boards/Kconfig.v1 | 6 +- boards/Kconfig.v2 | 2 +- cmake/modules/boards.cmake | 34 ++--- cmake/modules/dts.cmake | 40 +++--- cmake/modules/hwm_v2.cmake | 14 ++- cmake/modules/kconfig.cmake | 7 +- cmake/modules/kernel.cmake | 4 +- doc/_extensions/zephyr/kconfig/__init__.py | 12 +- doc/_scripts/gen_boards_catalog.py | 4 +- scripts/ci/check_compliance.py | 12 +- scripts/ci/test_plan.py | 4 +- scripts/kconfig/lint.py | 2 +- scripts/list_boards.py | 125 +++++++++++++++---- scripts/pylib/twister/twisterlib/testplan.py | 2 +- scripts/schemas/board-schema.yml | 22 +++- scripts/west_commands/boards.py | 4 +- share/sysbuild/Kconfig | 2 +- 19 files changed, 200 insertions(+), 102 deletions(-) diff --git a/Kconfig.zephyr b/Kconfig.zephyr index 425d79f4e74ec..f97819896d94a 100644 --- a/Kconfig.zephyr +++ b/Kconfig.zephyr @@ -17,13 +17,13 @@ osource "${APPLICATION_SOURCE_DIR}/VERSION" # Shield defaults should have precedence over board defaults, which should have # precedence over SoC defaults, so include them in that order. # -# $ARCH and $BOARD_DIR will be glob patterns when building documentation. +# $ARCH and $KCONFIG_BOARD_DIR will be glob patterns when building documentation. # This loads custom shields defconfigs (from BOARD_ROOT) osource "$(KCONFIG_BINARY_DIR)/Kconfig.shield.defconfig" # This loads Zephyr base shield defconfigs source "boards/shields/*/Kconfig.defconfig" -osource "$(BOARD_DIR)/Kconfig.defconfig" +osource "$(KCONFIG_BOARD_DIR)/Kconfig.defconfig" # This loads Zephyr specific SoC root defconfigs source "$(KCONFIG_BINARY_DIR)/soc/Kconfig.defconfig" diff --git a/boards/Kconfig b/boards/Kconfig index 6eb9ca5916dd2..8f186b32caf4f 100644 --- a/boards/Kconfig +++ b/boards/Kconfig @@ -129,7 +129,7 @@ config QEMU_EXTRA_FLAGS GDBstub over serial with `-serial tcp:127.0.0.1:5678,server` # There might not be any board options, hence the optional source -osource "$(BOARD_DIR)/Kconfig" +osource "$(KCONFIG_BOARD_DIR)/Kconfig" endmenu config BOARD_HAS_TIMING_FUNCTIONS diff --git a/boards/Kconfig.v1 b/boards/Kconfig.v1 index 670e2f2376eb8..c98bd27d2db85 100644 --- a/boards/Kconfig.v1 +++ b/boards/Kconfig.v1 @@ -2,9 +2,13 @@ # SPDX-License-Identifier: Apache-2.0 +# In HWMv1 the KCONFIG_BOARD_DIR points directly to the BOARD_DIR. +# Set the BOARD_DIR variable for backwards compatibility to legacy hardware model. +BOARD_DIR := $(KCONFIG_BOARD_DIR) + choice prompt "Board Selection" -source "$(BOARD_DIR)/Kconfig.board" +source "$(KCONFIG_BOARD_DIR)/Kconfig.board" endchoice diff --git a/boards/Kconfig.v2 b/boards/Kconfig.v2 index 47bb3ae224016..6fce9ccb99d58 100644 --- a/boards/Kconfig.v2 +++ b/boards/Kconfig.v2 @@ -25,4 +25,4 @@ config BOARD_QUALIFIERS For example, if building for ``nrf5340dk/nrf5340/cpuapp`` then this will contain the value ``nrf5340/cpuapp``. -osource "$(BOARD_DIR)/Kconfig.$(BOARD)" +osource "$(KCONFIG_BOARD_DIR)/Kconfig.$(BOARD)" diff --git a/cmake/modules/boards.cmake b/cmake/modules/boards.cmake index a1b05b07b5754..2b78845482a23 100644 --- a/cmake/modules/boards.cmake +++ b/cmake/modules/boards.cmake @@ -185,9 +185,7 @@ set(format_str "{NAME}\;{DIR}\;{HWM}\;") set(format_str "${format_str}{REVISION_FORMAT}\;{REVISION_DEFAULT}\;{REVISION_EXACT}\;") set(format_str "${format_str}{REVISIONS}\;{SOCS}\;{QUALIFIERS}") -if(BOARD_DIR) - set(board_dir_arg "--board-dir=${BOARD_DIR}") -endif() +list(TRANSFORM BOARD_DIRECTORIES PREPEND "--board-dir=" OUTPUT_VARIABLE board_dir_arg) execute_process(${list_boards_commands} --board=${BOARD} ${board_dir_arg} --cmakeformat=${format_str} OUTPUT_VARIABLE ret_board @@ -200,29 +198,15 @@ endif() if(NOT "${ret_board}" STREQUAL "") string(STRIP "${ret_board}" ret_board) - string(FIND "${ret_board}" "\n" idx REVERSE) - if(idx GREATER -1) - while(TRUE) - math(EXPR start "${idx} + 1") - string(SUBSTRING "${ret_board}" ${start} -1 line) - string(SUBSTRING "${ret_board}" 0 ${idx} ret_board) - - cmake_parse_arguments(LIST_BOARD "" "DIR" "" ${line}) - set(board_dirs "${board_dirs}\n${LIST_BOARD_DIR}") - - if(idx EQUAL -1) - break() - endif() - string(FIND "${ret_board}" "\n" idx REVERSE) - endwhile() - message(FATAL_ERROR "Multiple boards named '${BOARD}' found in:${board_dirs}") - endif() - - set(single_val "NAME;DIR;HWM;REVISION_FORMAT;REVISION_DEFAULT;REVISION_EXACT") - set(multi_val "REVISIONS;SOCS;QUALIFIERS") + set(single_val "NAME;HWM;REVISION_FORMAT;REVISION_DEFAULT;REVISION_EXACT") + set(multi_val "DIR;REVISIONS;SOCS;QUALIFIERS") cmake_parse_arguments(LIST_BOARD "" "${single_val}" "${multi_val}" ${ret_board}) - set(BOARD_DIR ${LIST_BOARD_DIR} CACHE PATH "Board directory for board (${BOARD})" FORCE) - set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${BOARD_DIR}/board.yml) + list(GET LIST_BOARD_DIR 0 BOARD_DIR) + set(BOARD_DIR ${BOARD_DIR} CACHE PATH "Main board directory for board (${BOARD})" FORCE) + set(BOARD_DIRECTORIES ${LIST_BOARD_DIR} CACHE INTERNAL "List of board directories for board (${BOARD})" FORCE) + foreach(dir ${BOARD_DIRECTORIES}) + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${dir}/board.yml) + endforeach() # Create two CMake variables identifying the hw model. # CMake variable: HWM=[v1,v2] diff --git a/cmake/modules/dts.cmake b/cmake/modules/dts.cmake index 16b497d573776..a2c56577cfa54 100644 --- a/cmake/modules/dts.cmake +++ b/cmake/modules/dts.cmake @@ -76,9 +76,9 @@ find_package(Dtc 1.4.6) # # Optional variables: # - BOARD: board name to use when looking for DTS_SOURCE -# - BOARD_DIR: board directory to use when looking for DTS_SOURCE +# - BOARD_DIRECTORIES: list of board directories to use when looking for DTS_SOURCE # - BOARD_REVISION_STRING: used when looking for a board revision's -# devicetree overlay file in BOARD_DIR +# devicetree overlay file in one of the BOARD_DIRECTORIES # - CMAKE_DTS_PREPROCESSOR: the path to the preprocessor to use # for devicetree files # - DTC_OVERLAY_FILE: list of devicetree overlay files which will be @@ -94,7 +94,7 @@ find_package(Dtc 1.4.6) # C preprocessor when generating the devicetree from DTS_SOURCE # - DTS_SOURCE: the devicetree source file to use may be pre-set # with this variable; otherwise, it defaults to -# ${BOARD_DIR}/${BOARD}.dts +# ${BOARD_DIRECTORIES}/.dts # # Variables set by this module and not mentioned above are for internal # use only, and may be removed, renamed, or re-purposed without prior notice. @@ -137,28 +137,30 @@ if(NOT DEFINED DTS_SOURCE) zephyr_build_string(board_string SHORT shortened_board_string BOARD ${BOARD} BOARD_QUALIFIERS ${BOARD_QUALIFIERS} ) - if(EXISTS ${BOARD_DIR}/${shortened_board_string}.dts AND NOT BOARD_${BOARD}_SINGLE_SOC) - message(FATAL_ERROR "Board ${ZFILE_BOARD} defines multiple SoCs.\nShortened file name " - "(${shortened_board_string}.dts) not allowed, use '_.dts' naming" - ) - elseif(EXISTS ${BOARD_DIR}/${board_string}.dts AND EXISTS ${BOARD_DIR}/${shortened_board_string}.dts) - message(FATAL_ERROR "Conflicting file names discovered. Cannot use both " - "${board_string}.dts and ${shortened_board_string}.dts. " - "Please choose one naming style, ${board_string}.dts is recommended." - ) - elseif(EXISTS ${BOARD_DIR}/${board_string}.dts) - set(DTS_SOURCE ${BOARD_DIR}/${board_string}.dts) - elseif(EXISTS ${BOARD_DIR}/${shortened_board_string}.dts) - set(DTS_SOURCE ${BOARD_DIR}/${shortened_board_string}.dts) - endif() + foreach(dir ${BOARD_DIRECTORIES}) + if(EXISTS ${dir}/${shortened_board_string}.dts AND NOT BOARD_${BOARD}_SINGLE_SOC) + message(FATAL_ERROR "Board ${ZFILE_BOARD} defines multiple SoCs.\nShortened file name " + "(${shortened_board_string}.dts) not allowed, use '_.dts' naming" + ) + elseif(EXISTS ${dir}/${board_string}.dts AND EXISTS ${dir}/${shortened_board_string}.dts) + message(FATAL_ERROR "Conflicting file names discovered. Cannot use both " + "${board_string}.dts and ${shortened_board_string}.dts. " + "Please choose one naming style, ${board_string}.dts is recommended." + ) + elseif(EXISTS ${dir}/${board_string}.dts) + set(DTS_SOURCE ${dir}/${board_string}.dts) + elseif(EXISTS ${dir}/${shortened_board_string}.dts) + set(DTS_SOURCE ${dir}/${shortened_board_string}.dts) + endif() + endforeach() endif() if(EXISTS ${DTS_SOURCE}) # We found a devicetree. Append all relevant dts overlays we can find... - zephyr_file(CONF_FILES ${BOARD_DIR} DTS DTS_SOURCE) + zephyr_file(CONF_FILES ${BOARD_DIRECTORIES} DTS DTS_SOURCE) zephyr_file( - CONF_FILES ${BOARD_DIR} + CONF_FILES ${BOARD_DIRECTORIES} DTS no_rev_suffix_dts_board_overlays BOARD ${BOARD} BOARD_QUALIFIERS ${BOARD_QUALIFIERS} diff --git a/cmake/modules/hwm_v2.cmake b/cmake/modules/hwm_v2.cmake index b514a33c5b0a6..c4feb03736e3b 100644 --- a/cmake/modules/hwm_v2.cmake +++ b/cmake/modules/hwm_v2.cmake @@ -95,11 +95,15 @@ endwhile() list(REMOVE_DUPLICATES kconfig_soc_source_dir) # Support multiple ARCH_ROOT, SOC_ROOT and BOARD_ROOT -kconfig_gen("arch" "Kconfig" "${kconfig_arch_source_dir}" "Zephyr Arch Kconfig") -kconfig_gen("soc" "Kconfig.defconfig" "${kconfig_soc_source_dir}" "Zephyr SoC defconfig") -kconfig_gen("soc" "Kconfig" "${kconfig_soc_source_dir}" "Zephyr SoC Kconfig") -kconfig_gen("soc" "Kconfig.soc" "${kconfig_soc_source_dir}" "SoC Kconfig") -kconfig_gen("soc" "Kconfig.sysbuild" "${kconfig_soc_source_dir}" "Sysbuild SoC Kconfig") +kconfig_gen("arch" "Kconfig" "${kconfig_arch_source_dir}" "Zephyr Arch Kconfig") +kconfig_gen("soc" "Kconfig.defconfig" "${kconfig_soc_source_dir}" "Zephyr SoC defconfig") +kconfig_gen("soc" "Kconfig" "${kconfig_soc_source_dir}" "Zephyr SoC Kconfig") +kconfig_gen("soc" "Kconfig.soc" "${kconfig_soc_source_dir}" "SoC Kconfig") +kconfig_gen("soc" "Kconfig.sysbuild" "${kconfig_soc_source_dir}" "Sysbuild SoC Kconfig") +kconfig_gen("boards" "Kconfig.defconfig" "${BOARD_DIRECTORIES}" "Zephyr board defconfig") +kconfig_gen("boards" "Kconfig.${BOARD}" "${BOARD_DIRECTORIES}" "board Kconfig") +kconfig_gen("boards" "Kconfig" "${BOARD_DIRECTORIES}" "Zephyr board Kconfig") +kconfig_gen("boards" "Kconfig.sysbuild" "${BOARD_DIRECTORIES}" "Sysbuild board Kconfig") # Clear variables created by cmake_parse_arguments unset(SOC_V2_NAME) diff --git a/cmake/modules/kconfig.cmake b/cmake/modules/kconfig.cmake index 0273d39bf8508..02bebbe085199 100644 --- a/cmake/modules/kconfig.cmake +++ b/cmake/modules/kconfig.cmake @@ -21,9 +21,12 @@ file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/kconfig/include/config) set_ifndef(KCONFIG_NAMESPACE "CONFIG") set_ifndef(KCONFIG_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/Kconfig) +set(KCONFIG_BOARD_DIR ${KCONFIG_BINARY_DIR}/boards) file(MAKE_DIRECTORY ${KCONFIG_BINARY_DIR}) if(HWMv1) + # HWMv1 only supoorts a single board dir which points directly to the board dir. + set(KCONFIG_BOARD_DIR ${BOARD_DIR}) # Support multiple SOC_ROOT file(MAKE_DIRECTORY ${KCONFIG_BINARY_DIR}/soc) set(kconfig_soc_root ${SOC_ROOT}) @@ -73,7 +76,7 @@ else() endif() if(NOT DEFINED BOARD_DEFCONFIG) - zephyr_file(CONF_FILES ${BOARD_DIR} DEFCONFIG BOARD_DEFCONFIG) + zephyr_file(CONF_FILES ${BOARD_DIRECTORIES} DEFCONFIG BOARD_DEFCONFIG) endif() if(DEFINED BOARD_REVISION) @@ -157,7 +160,7 @@ set(COMMON_KCONFIG_ENV_SETTINGS APP_VERSION_TWEAK_STRING=${APP_VERSION_TWEAK_STRING} CONFIG_=${KCONFIG_NAMESPACE}_ KCONFIG_CONFIG=${DOTCONFIG} - BOARD_DIR=${BOARD_DIR} + KCONFIG_BOARD_DIR=${KCONFIG_BOARD_DIR} BOARD=${BOARD} BOARD_REVISION=${BOARD_REVISION} BOARD_QUALIFIERS=${BOARD_QUALIFIERS} diff --git a/cmake/modules/kernel.cmake b/cmake/modules/kernel.cmake index 1946e2357ba52..6a1a48b172d06 100644 --- a/cmake/modules/kernel.cmake +++ b/cmake/modules/kernel.cmake @@ -173,7 +173,9 @@ if(CONFIG_LLEXT AND CONFIG_LLEXT_TYPE_ELF_SHAREDLIB) set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE) endif() -include(${BOARD_DIR}/board.cmake OPTIONAL) +foreach(dir ${BOARD_DIRECTORIES}) + include(${dir}/board.cmake OPTIONAL) +endforeach() # If we are using a suitable ethernet driver inside qemu, then these options # must be set, otherwise a zephyr instance cannot receive any network packets. diff --git a/doc/_extensions/zephyr/kconfig/__init__.py b/doc/_extensions/zephyr/kconfig/__init__.py index 6052db638fa2b..abbdcc1b9be35 100644 --- a/doc/_extensions/zephyr/kconfig/__init__.py +++ b/doc/_extensions/zephyr/kconfig/__init__.py @@ -91,7 +91,7 @@ def kconfig_load(app: Sphinx) -> Tuple[kconfiglib.Kconfig, Dict[str, str]]: root_args = argparse.Namespace(**{'soc_roots': [Path(ZEPHYR_BASE)]}) v2_systems = list_hardware.find_v2_systems(root_args) - soc_folders = {soc.folder for soc in v2_systems.get_socs()} + soc_folders = {soc.folder[0] for soc in v2_systems.get_socs()} with open(Path(td) / "soc" / "Kconfig.defconfig", "w") as f: f.write('') @@ -114,8 +114,9 @@ def kconfig_load(app: Sphinx) -> Tuple[kconfiglib.Kconfig, Dict[str, str]]: (Path(td) / 'boards').mkdir(exist_ok=True) root_args = argparse.Namespace(**{'board_roots': [Path(ZEPHYR_BASE)], - 'soc_roots': [Path(ZEPHYR_BASE)], 'board': None}) - v2_boards = list_boards.find_v2_boards(root_args) + 'soc_roots': [Path(ZEPHYR_BASE)], 'board': None, + 'board_dir': []}) + v2_boards = list_boards.find_v2_boards(root_args).values() with open(Path(td) / "boards" / "Kconfig.boards", "w") as f: for board in v2_boards: @@ -126,7 +127,8 @@ def kconfig_load(app: Sphinx) -> Tuple[kconfiglib.Kconfig, Dict[str, str]]: board_str = 'BOARD_' + re.sub(r"[^a-zA-Z0-9_]", "_", qualifier).upper() f.write('config ' + board_str + '\n') f.write('\t bool\n') - f.write('source "' + (board.dir / ('Kconfig.' + board.name)).as_posix() + '"\n\n') + f.write('source "' + + (board.directories[0] / ('Kconfig.' + board.name)).as_posix() + '"\n\n') # base environment os.environ["ZEPHYR_BASE"] = str(ZEPHYR_BASE) @@ -140,7 +142,7 @@ def kconfig_load(app: Sphinx) -> Tuple[kconfiglib.Kconfig, Dict[str, str]]: os.environ["HWM_SCHEME"] = "v2" os.environ["BOARD"] = "boards" - os.environ["BOARD_DIR"] = str(Path(td) / "boards") + os.environ["KCONFIG_BOARD_DIR"] = str(Path(td) / "boards") # insert external Kconfigs to the environment module_paths = dict() diff --git a/doc/_scripts/gen_boards_catalog.py b/doc/_scripts/gen_boards_catalog.py index 859f37c9eceb4..52be751e81f63 100644 --- a/doc/_scripts/gen_boards_catalog.py +++ b/doc/_scripts/gen_boards_catalog.py @@ -70,7 +70,7 @@ def get_catalog(): arch_roots=module_settings["arch_root"], board_roots=module_settings["board_root"], soc_roots=module_settings["soc_root"], - board_dir=ZEPHYR_BASE / "boards", + board_dir=[], board=None, ) @@ -78,7 +78,7 @@ def get_catalog(): systems = list_hardware.find_v2_systems(args_find_boards) board_catalog = {} - for board in boards: + for board in boards.values(): # We could use board.vendor but it is often incorrect. Instead, deduce vendor from # containing folder. There are a few exceptions, like the "native" and "others" folders # which we know are not actual vendors so treat them as such. diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index f586b53d14712..63e7fb948b73c 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -511,8 +511,9 @@ def get_v2_model(self, kconfig_dir, settings_file): soc_roots = self.get_module_setting_root('soc', settings_file) soc_roots.insert(0, Path(ZEPHYR_BASE)) root_args = argparse.Namespace(**{'board_roots': board_roots, - 'soc_roots': soc_roots, 'board': None}) - v2_boards = list_boards.find_v2_boards(root_args) + 'soc_roots': soc_roots, 'board': None, + 'board_dir': []}) + v2_boards = list_boards.find_v2_boards(root_args).values() with open(kconfig_defconfig_file, 'w') as fp: for board in v2_boards: @@ -546,7 +547,7 @@ def get_v2_model(self, kconfig_dir, settings_file): root_args = argparse.Namespace(**{'soc_roots': soc_roots}) v2_systems = list_hardware.find_v2_systems(root_args) - soc_folders = {soc.folder for soc in v2_systems.get_socs()} + soc_folders = {soc.folder[0] for soc in v2_systems.get_socs()} with open(kconfig_defconfig_file, 'w') as fp: for folder in soc_folders: fp.write('osource "' + (Path(folder) / 'Kconfig.defconfig').as_posix() + '"\n') @@ -616,7 +617,7 @@ def parse_kconfig(self, filename="Kconfig", hwm=None): os.makedirs(os.path.join(kconfiglib_dir, 'soc'), exist_ok=True) os.makedirs(os.path.join(kconfiglib_dir, 'arch'), exist_ok=True) - os.environ["BOARD_DIR"] = kconfiglib_boards_dir + os.environ["KCONFIG_BOARD_DIR"] = kconfiglib_boards_dir self.get_v2_model(kconfiglib_dir, os.path.join(kconfiglib_dir, "settings_file.txt")) # Tells Kconfiglib to generate warnings for all references to undefined @@ -920,6 +921,9 @@ def check_no_undef_outside_kconfig(self, kconf): # Zephyr toolchain variant and therefore not # visible to compliance. "BOARD_", # Used as regex in scripts/utils/board_v1_to_v2.py + "BOARD_MPS2_AN521_CPUTEST", # Used for board and SoC extension feature tests + "BOARD_NATIVE_SIM_NATIVE_64_TWO", # Used for board and SoC extension feature tests + "BOARD_NATIVE_SIM_NATIVE_ONE", # Used for board and SoC extension feature tests "BOOT_DIRECT_XIP", # Used in sysbuild for MCUboot configuration "BOOT_DIRECT_XIP_REVERT", # Used in sysbuild for MCUboot configuration "BOOT_FIRMWARE_LOADER", # Used in sysbuild for MCUboot configuration diff --git a/scripts/ci/test_plan.py b/scripts/ci/test_plan.py index 326068ab715f6..4bb428ee5b1bb 100755 --- a/scripts/ci/test_plan.py +++ b/scripts/ci/test_plan.py @@ -239,12 +239,12 @@ def find_boards(self): # Look for boards in monitored repositories lb_args = argparse.Namespace(**{'arch_roots': roots, 'board_roots': roots, 'board': None, 'soc_roots':roots, 'board_dir': None}) - known_boards = list_boards.find_v2_boards(lb_args) + known_boards = list_boards.find_v2_boards(lb_args).values() for changed in changed_boards: for board in known_boards: c = (zephyr_base / changed).resolve() - if c.is_relative_to(board.dir.resolve()): + if c.is_relative_to(board.directories[0].resolve()): for file in glob.glob(os.path.join(board.dir, f"{board.name}*.yaml")): with open(file, 'r', encoding='utf-8') as f: b = yaml.load(f.read(), Loader=SafeLoader) diff --git a/scripts/kconfig/lint.py b/scripts/kconfig/lint.py index 30064c34546be..5a123ded42fae 100755 --- a/scripts/kconfig/lint.py +++ b/scripts/kconfig/lint.py @@ -209,7 +209,7 @@ def init_kconfig(): ZEPHYR_BASE=TOP_DIR, SOC_DIR="soc", ARCH_DIR="arch", - BOARD_DIR="boards/*/*", + KCONFIG_BOARD_DIR="boards/*/*", ARCH="*") kconf = kconfiglib.Kconfig(suppress_traceback=True) diff --git a/scripts/list_boards.py b/scripts/list_boards.py index bf71658488564..634c67df821a0 100755 --- a/scripts/list_boards.py +++ b/scripts/list_boards.py @@ -4,13 +4,13 @@ # SPDX-License-Identifier: Apache-2.0 import argparse -from collections import defaultdict +from collections import defaultdict, Counter from dataclasses import dataclass, field import itertools from pathlib import Path import pykwalify.core import sys -from typing import List +from typing import List, Union import yaml import list_hardware from list_hardware import unique_paths @@ -91,7 +91,8 @@ def from_soc(soc, variants): @dataclass(frozen=True) class Board: name: str - dir: Path + # HWMv1 only supports a single Path, and requires Board dataclass to be hashable. + directories: Union[Path, List[Path]] hwm: str full_name: str = None arch: str = None @@ -103,6 +104,41 @@ class Board: socs: List[Soc] = field(default_factory=list, compare=False) variants: List[str] = field(default_factory=list, compare=False) + def from_qualifier(self, qualifiers): + qualifiers_list = qualifiers.split('/') + + node = Soc(None) + n = len(qualifiers_list) + if n > 0: + soc_qualifier = qualifiers_list.pop(0) + for s in self.socs: + if s.name == soc_qualifier: + node = s + break + + if n > 1: + if node.cpuclusters: + cpu_qualifier = qualifiers_list.pop(0) + for c in node.cpuclusters: + if c.name == cpu_qualifier: + node = c + break + else: + node = Variant(None) + + for q in qualifiers_list: + for v in node.variants: + if v.name == q: + node = v + break + else: + node = Variant(None) + + if node in (Soc(None), Variant(None)): + sys.exit(f'ERROR: qualifiers {qualifiers} not found when extending board {self.name}') + + return node + def board_key(board): return board.name @@ -165,11 +201,10 @@ def find_arch2board_set_in(root, arches, board_dir): for arch in arches: if not (boards / arch).is_dir(): continue - for maybe_board in (boards / arch).iterdir(): if not maybe_board.is_dir(): continue - if board_dir is not None and board_dir != maybe_board: + if board_dir and maybe_board not in board_dir: continue for maybe_defconfig in maybe_board.iterdir(): file_name = maybe_defconfig.name @@ -181,7 +216,8 @@ def find_arch2board_set_in(root, arches, board_dir): def load_v2_boards(board_name, board_yml, systems): - boards = [] + boards = {} + board_extensions = [] if board_yml.is_file(): with board_yml.open('r', encoding='utf-8') as f: b = yaml.load(f.read(), Loader=SafeLoader) @@ -199,6 +235,18 @@ def load_v2_boards(board_name, board_yml, systems): board_array = b.get('boards', [b.get('board', None)]) for board in board_array: + mutual_exclusive = {'name', 'extend'} + if len(mutual_exclusive - board.keys()) < 1: + sys.exit(f'ERROR: Malformed "board" section in file: {board_yml.as_posix()}\n' + f'{mutual_exclusive} are mutual exclusive at this level.') + + # This is a extending an existing board, place in array to allow later processing. + if 'extend' in board: + board.update({'dir': board_yml.parent}) + board_extensions.append(board) + continue + + # Create board if board_name is not None: if board['name'] != board_name: # Not the board we're looking for, ignore. @@ -220,9 +268,9 @@ def load_v2_boards(board_name, board_yml, systems): socs = [Soc.from_soc(systems.get_soc(s['name']), s.get('variants', [])) for s in board.get('socs', {})] - board = Board( + boards[board['name']] = Board( name=board['name'], - dir=board_yml.parent, + directories=[board_yml.parent], vendor=board.get('vendor'), full_name=board.get('full_name'), revision_format=board.get('revision', {}).get('format'), @@ -234,8 +282,28 @@ def load_v2_boards(board_name, board_yml, systems): variants=[Variant.from_dict(v) for v in board.get('variants', [])], hwm='v2', ) - boards.append(board) - return boards + board_qualifiers = board_v2_qualifiers(boards[board['name']]) + duplicates = [q for q, n in Counter(board_qualifiers).items() if n > 1] + if duplicates: + sys.exit(f'ERROR: Duplicated board qualifiers detected {duplicates} for board: ' + f'{board["name"]}.\nPlease check content of: {board_yml.as_posix()}\n') + return boards, board_extensions + + +def extend_v2_boards(boards, board_extensions): + for e in board_extensions: + board = boards.get(e['extend']) + if board is None: + continue + board.directories.append(e['dir']) + + for v in e.get('variants', []): + node = board.from_qualifier(v['qualifier']) + if str(v['qualifier'] + '/' + v['name']) in board_v2_qualifiers(board): + board_yml = e['dir'] / BOARD_YML + sys.exit(f'ERROR: Variant: {v["name"]}, defined multiple times for board: ' + f'{board.name}.\nLast defined in {board_yml}') + node.variants.append(Variant.from_dict(v)) # Note that this does not share the args.board functionality of find_v2_boards @@ -253,14 +321,25 @@ def find_v2_boards(args): root_args = argparse.Namespace(**{'soc_roots': args.soc_roots}) systems = list_hardware.find_v2_systems(root_args) - boards = [] + boards = {} + board_extensions = [] board_files = [] - for root in unique_paths(args.board_roots): - board_files.extend((root / 'boards').rglob(BOARD_YML)) + if args.board_dir: + board_files = [d / BOARD_YML for d in args.board_dir] + else: + for root in unique_paths(args.board_roots): + board_files.extend((root / 'boards').rglob(BOARD_YML)) for board_yml in board_files: - b = load_v2_boards(args.board, board_yml, systems) - boards.extend(b) + b, e = load_v2_boards(args.board, board_yml, systems) + conflict_boards = set(boards.keys()).intersection(b.keys()) + if conflict_boards: + sys.exit(f'ERROR: Board(s): {conflict_boards}, defined multiple times.\n' + f'Last defined in {board_yml}') + boards.update(b) + board_extensions.extend(e) + + extend_v2_boards(boards, board_extensions) return boards @@ -285,7 +364,7 @@ def add_args(parser): help='add a soc root, may be given more than once') parser.add_argument("--board", dest='board', default=None, help='lookup the specific board, fail if not found') - parser.add_argument("--board-dir", default=None, type=Path, + parser.add_argument("--board-dir", default=[], type=Path, action='append', help='Only look for boards at the specific location') @@ -327,20 +406,16 @@ def board_v2_qualifiers_csv(board): def dump_v2_boards(args): - if args.board_dir: - root_args = argparse.Namespace(**{'soc_roots': args.soc_roots}) - systems = list_hardware.find_v2_systems(root_args) - boards = load_v2_boards(args.board, args.board_dir / BOARD_YML, systems) - else: - boards = find_v2_boards(args) + boards = find_v2_boards(args) - for b in boards: + for b in boards.values(): qualifiers_list = board_v2_qualifiers(b) if args.cmakeformat is not None: notfound = lambda x: x or 'NOTFOUND' info = args.cmakeformat.format( NAME='NAME;' + b.name, - DIR='DIR;' + str(b.dir.as_posix()), + DIR='DIR;' + ';'.join( + [str(x.as_posix()) for x in b.directories]), VENDOR='VENDOR;' + notfound(b.vendor), HWM='HWM;' + b.hwm, REVISION_DEFAULT='REVISION_DEFAULT;' + notfound(b.revision_default), @@ -365,7 +440,7 @@ def dump_boards(args): if args.cmakeformat is not None: info = args.cmakeformat.format( NAME='NAME;' + board.name, - DIR='DIR;' + str(board.dir.as_posix()), + DIR='DIR;' + str(board.directories.as_posix()), HWM='HWM;' + board.hwm, VENDOR='VENDOR;NOTFOUND', REVISION_DEFAULT='REVISION_DEFAULT;NOTFOUND', diff --git a/scripts/pylib/twister/twisterlib/testplan.py b/scripts/pylib/twister/twisterlib/testplan.py index 8731522c21ece..6110fb164ad69 100755 --- a/scripts/pylib/twister/twisterlib/testplan.py +++ b/scripts/pylib/twister/twisterlib/testplan.py @@ -432,7 +432,7 @@ def init_and_add_platforms(data, board, target, qualifier, aliases): logger.debug(f"Adding platform {platform.name} with aliases {platform.aliases}") self.platforms.append(platform) - for board in known_boards: + for board in known_boards.values(): new_config_found = False # don't load the same board data twice if not bdirs.get(board.dir): diff --git a/scripts/schemas/board-schema.yml b/scripts/schemas/board-schema.yml index 7a2afbd566de6..656a62a37ef0f 100644 --- a/scripts/schemas/board-schema.yml +++ b/scripts/schemas/board-schema.yml @@ -23,17 +23,33 @@ schema;variant-schema: required: false include: variant-schema +schema;extend-variant-schema: + required: false + type: seq + sequence: + - type: map + mapping: + name: + required: true + type: str + qualifier: + required: true + type: str + schema;board-schema: type: map mapping: name: - required: true + required: false # Note: either name or extend is required, but that is handled in python type: str desc: Name of the board full_name: required: false type: str desc: Full name of the board. Typically set to the commercial name of the board. + extend: + required: false # Note: either name or extend is required, but that is handled in python + type: str vendor: required: false type: str @@ -63,7 +79,7 @@ schema;board-schema: required: true type: str socs: - required: true + required: false # Required for name:, but not for extend. type: seq sequence: - type: map @@ -73,6 +89,8 @@ schema;board-schema: type: str variants: include: variant-schema + variants: + include: extend-variant-schema type: map mapping: diff --git a/scripts/west_commands/boards.py b/scripts/west_commands/boards.py index 9777d377f53e9..9cb6182a7a725 100644 --- a/scripts/west_commands/boards.py +++ b/scripts/west_commands/boards.py @@ -97,14 +97,14 @@ def do_run(self, args, _): log.inf(args.format.format(name=board.name, arch=board.arch, dir=board.dir, hwm=board.hwm, qualifiers='')) - for board in list_boards.find_v2_boards(args): + for board in list_boards.find_v2_boards(args).values(): if name_re is not None and not name_re.search(board.name): continue log.inf( args.format.format( name=board.name, full_name=board.full_name, - dir=board.dir, + dir=board.directories[0], hwm=board.hwm, vendor=board.vendor, qualifiers=list_boards.board_v2_qualifiers_csv(board), diff --git a/share/sysbuild/Kconfig b/share/sysbuild/Kconfig index 556462af31077..69f2d4cd396c5 100644 --- a/share/sysbuild/Kconfig +++ b/share/sysbuild/Kconfig @@ -6,7 +6,7 @@ rsource "Kconfig.$(HWM_SCHEME)" comment "Sysbuild image configuration" -osource "$(BOARD_DIR)/Kconfig.sysbuild" +osource "$(KCONFIG_BOARD_DIR)/Kconfig.sysbuild" osource "$(KCONFIG_BINARY_DIR)/soc/Kconfig.sysbuild" menu "Modules" From 23e3888c82afa29eeda9aeb908851001fd467377 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Wed, 15 May 2024 22:46:33 +0200 Subject: [PATCH 3/9] cmake: scripts: support SoC extension Fixes: #72374 Support extending an existing SoC with new CPU clusters. This commit introduces the following changes to allow an SoC to be extended out-of-tree. The SoC yaml schema is extended to support an extend field which will be used to identify the SoC to be extended with extra CPU clusters. A SoC 'a_soc' can be extended like this: > socs: > extend: a_soc > cpuclusters: > - name: extra_core Signed-off-by: Torsten Rasmussen --- cmake/modules/hwm_v2.cmake | 18 ++++++---- cmake/modules/soc_v2.cmake | 7 +++- scripts/list_hardware.py | 66 +++++++++++++++++++++++++--------- scripts/schemas/soc-schema.yml | 19 ++++++++-- 4 files changed, 84 insertions(+), 26 deletions(-) diff --git a/cmake/modules/hwm_v2.cmake b/cmake/modules/hwm_v2.cmake index c4feb03736e3b..a440c95c83242 100644 --- a/cmake/modules/hwm_v2.cmake +++ b/cmake/modules/hwm_v2.cmake @@ -73,19 +73,23 @@ while(TRUE) string(TOUPPER "${ARCH_V2_NAME}" ARCH_V2_NAME_UPPER) set(ARCH_V2_${ARCH_V2_NAME_UPPER}_DIR ${ARCH_V2_DIR}) elseif(HWM_TYPE MATCHES "^soc|^series|^family") - cmake_parse_arguments(SOC_V2 "" "NAME;DIR;HWM" "" ${line}) + cmake_parse_arguments(SOC_V2 "" "NAME;HWM" "DIR" ${line}) list(APPEND kconfig_soc_source_dir "${SOC_V2_DIR}") + string(TOUPPER "${SOC_V2_NAME}" SOC_V2_NAME_UPPER) + string(TOUPPER "${HWM_TYPE}" HWM_TYPE_UPPER) if(HWM_TYPE STREQUAL "soc") - set(setting_name SOC_${SOC_V2_NAME}_DIR) + # We support both SOC_foo_DIR and SOC_FOO_DIR. + set(SOC_${SOC_V2_NAME}_DIRECTORIES ${SOC_V2_DIR}) + set(SOC_${SOC_V2_NAME_UPPER}_DIRECTORIES ${SOC_V2_DIR}) + list(GET SOC_V2_DIR 0 SOC_${SOC_V2_NAME}_DIR) + list(GET SOC_V2_DIR 0 SOC_${SOC_V2_NAME_UPPER}_DIR) else() - set(setting_name SOC_${HWM_TYPE}_${SOC_V2_NAME}_DIR) + # We support both SOC_series_foo_DIR and SOC_SERIES_FOO_DIR (and family / FAMILY). + set(SOC_${HWM_TYPE}_${SOC_V2_NAME}_DIR ${SOC_V2_DIR}) + set(SOC_${HWM_TYPE_UPPER}_${SOC_V2_NAME_UPPER}_DIR ${SOC_V2_DIR}) endif() - # We support both SOC_foo_DIR and SOC_FOO_DIR. - set(${setting_name} ${SOC_V2_DIR}) - string(TOUPPER ${setting_name} setting_name) - set(${setting_name} ${SOC_V2_DIR}) endif() if(idx EQUAL -1) diff --git a/cmake/modules/soc_v2.cmake b/cmake/modules/soc_v2.cmake index 606ed690f77fa..f98d33e001184 100644 --- a/cmake/modules/soc_v2.cmake +++ b/cmake/modules/soc_v2.cmake @@ -28,5 +28,10 @@ if(HWMv2) set(SOC_FAMILY ${CONFIG_SOC_FAMILY}) set(SOC_V2_DIR ${SOC_${SOC_NAME}_DIR}) set(SOC_FULL_DIR ${SOC_V2_DIR} CACHE PATH "Path to the SoC directory." FORCE) - set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${SOC_V2_DIR}/soc.yml) + set(SOC_DIRECTORIES ${SOC_${SOC_NAME}_DIRECTORIES} CACHE INTERNAL + "List of SoC directories for SoC (${SOC_NAME})" FORCE + ) + foreach(dir ${SOC_DIRECTORIES}) + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${dir}/soc.yml) + endforeach() endif() diff --git a/scripts/list_hardware.py b/scripts/list_hardware.py index cce6fbe983137..57c8b22586f9c 100755 --- a/scripts/list_hardware.py +++ b/scripts/list_hardware.py @@ -35,6 +35,7 @@ def __init__(self, folder='', soc_yaml=None): self._socs = [] self._series = [] self._families = [] + self._extended_socs = [] if soc_yaml is None: return @@ -47,12 +48,12 @@ def __init__(self, folder='', soc_yaml=None): sys.exit(f'ERROR: Malformed yaml {soc_yaml.as_posix()}', e) for f in data.get('family', []): - family = Family(f['name'], folder, [], []) + family = Family(f['name'], [folder], [], []) for s in f.get('series', []): - series = Series(s['name'], folder, f['name'], []) + series = Series(s['name'], [folder], f['name'], []) socs = [(Soc(soc['name'], [c['name'] for c in soc.get('cpuclusters', [])], - folder, s['name'], f['name'])) + [folder], s['name'], f['name'])) for soc in s.get('socs', [])] series.socs.extend(socs) self._series.append(series) @@ -61,26 +62,36 @@ def __init__(self, folder='', soc_yaml=None): family.socs.extend(socs) socs = [(Soc(soc['name'], [c['name'] for c in soc.get('cpuclusters', [])], - folder, None, f['name'])) + [folder], None, f['name'])) for soc in f.get('socs', [])] self._socs.extend(socs) self._families.append(family) for s in data.get('series', []): - series = Series(s['name'], folder, '', []) + series = Series(s['name'], [folder], '', []) socs = [(Soc(soc['name'], [c['name'] for c in soc.get('cpuclusters', [])], - folder, s['name'], '')) + [folder], s['name'], '')) for soc in s.get('socs', [])] series.socs.extend(socs) self._series.append(series) self._socs.extend(socs) - socs = [(Soc(soc['name'], - [c['name'] for c in soc.get('cpuclusters', [])], - folder, '', '')) - for soc in data.get('socs', [])] - self._socs.extend(socs) + for soc in data.get('socs', []): + mutual_exclusive = {'name', 'extend'} + if len(mutual_exclusive - soc.keys()) < 1: + sys.exit(f'ERROR: Malformed content in SoC file: {soc_yaml}\n' + f'{mutual_exclusive} are mutual exclusive at this level.') + if soc.get('name') is not None: + self._socs.append(Soc(soc['name'], [c['name'] for c in soc.get('cpuclusters', [])], + [folder], '', '')) + elif soc.get('extend') is not None: + self._extended_socs.append(Soc(soc['extend'], + [c['name'] for c in soc.get('cpuclusters', [])], + [folder], '', '')) + else: + sys.exit(f'ERROR: Malformed "socs" section in SoC file: {soc_yaml}\n' + f'Cannot find one of required keys {mutual_exclusive}.') # Ensure that any runner configuration matches socs and cpuclusters declared in the same # soc.yml file @@ -97,7 +108,7 @@ def __init__(self, folder='', soc_yaml=None): if components and components[-1] == 'ns': components.pop() - for soc in self._socs: + for soc in self._socs + self._extended_socs: if re.match(fr'^{soc_name}$', soc.name) is not None: if soc.cpuclusters and components: check_string = '/'.join(components) @@ -133,8 +144,23 @@ def from_yaml(socs_yaml): def extend(self, systems): self._families.extend(systems.get_families()) self._series.extend(systems.get_series()) + + for es in self._extended_socs[:]: + for s in systems.get_socs(): + if s.name == es.name: + s.extend(es) + self._extended_socs.remove(es) + break self._socs.extend(systems.get_socs()) + for es in systems.get_extended_socs(): + for s in self._socs: + if s.name == es.name: + s.extend(es) + break + else: + self._extended_socs.append(es) + def get_families(self): return self._families @@ -144,6 +170,9 @@ def get_series(self): def get_socs(self): return self._socs + def get_extended_socs(self): + return self._extended_socs + def get_soc(self, name): try: return next(s for s in self._socs if s.name == name) @@ -156,15 +185,20 @@ def get_soc(self, name): class Soc: name: str cpuclusters: List[str] - folder: str + folder: List[str] series: str = '' family: str = '' + def extend(self, soc): + if self.name == soc.name: + self.cpuclusters.extend(soc.cpuclusters) + self.folder.extend(soc.folder) + @dataclass class Series: name: str - folder: str + folder: List[str] family: str socs: List[Soc] @@ -172,7 +206,7 @@ class Series: @dataclass class Family: name: str - folder: str + folder: List[str] series: List[Series] socs: List[Soc] @@ -289,7 +323,7 @@ def dump_v2_system(args, type, system): info = args.cmakeformat.format( TYPE='TYPE;' + type, NAME='NAME;' + system.name, - DIR='DIR;' + Path(system.folder).as_posix(), + DIR='DIR;' + ';'.join([Path(x).as_posix() for x in system.folder]), HWM='HWM;' + 'v2' ) else: diff --git a/scripts/schemas/soc-schema.yml b/scripts/schemas/soc-schema.yml index c13b4a4f7e058..1d8537e8ad273 100644 --- a/scripts/schemas/soc-schema.yml +++ b/scripts/schemas/soc-schema.yml @@ -24,7 +24,22 @@ schema;soc-schema: - type: map mapping: name: - required: true + required: true # Note: either name or extend is required, but that is handled in python + type: str + cpuclusters: + include: cpucluster-schema + +schema;soc-extend-schema: + required: false + type: seq + sequence: + - type: map + mapping: + name: + required: false # Note: either name or extend is required, but that is handled in python + type: str + extend: + required: false # Note: either name or extend is required, but that is handled in python type: str cpuclusters: include: cpucluster-schema @@ -60,7 +75,7 @@ mapping: series: include: series-schema socs: - include: soc-schema + include: soc-extend-schema vendor: required: false type: str From 43031b73c2e9dee0832e28300cf4d2dec4fd5573 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Wed, 15 May 2024 13:42:04 +0200 Subject: [PATCH 4/9] tests: add twister tests for CMake board and SoC extension This commit adds new tests for verifying the functionality of the board and SoC extension feature. It does so by defining: - A new CPU cluster on an existing SoC - Two new board variants on top of an existing board The new board variants are defined on top of the existing `native_sim` board, so that the following native_sim board targets are available for the test. Existing board targets: - native_sim/native - native_sim/native/64 Extended board targets: - native_sim/native/one - native_sim/native/64/two The new CPU cluster is defined for the existing `an521` SoC. Existing CPU Clusters on an521: - cpu0 - cpu1 New CPU Cluster: - cputest For SoC tests the mps2 board is used. This means that for testing, the following board targets using the an521 SoC are: - mps2/an521/cpu0 - mps2/an521/cpu1 - mps2/an521/cputest Signed-off-by: Torsten Rasmussen --- tests/cmake/hwm/board_extend/CMakeLists.txt | 14 ++ tests/cmake/hwm/board_extend/Kconfig | 15 ++ .../hwm/board_extend/boards/native_sim.conf | 1 + .../boards/native_sim_native_64_two.conf | 1 + .../boards/native_sim_native_one.conf | 1 + .../oot_root/boards/arm/mps2/Kconfig.mps2 | 5 + .../oot_root/boards/arm/mps2/board.cmake | 14 ++ .../oot_root/boards/arm/mps2/board.yml | 2 + .../boards/arm/mps2/mps2_an521-common.dtsi | 191 +++++++++++++++ .../boards/arm/mps2/mps2_an521_cputest.dts | 130 +++++++++++ .../arm/mps2/mps2_an521_cputest_defconfig | 21 ++ .../boards/native/native_sim_extend/Kconfig | 30 +++ .../native_sim_extend/Kconfig.defconfig | 16 ++ .../boards/native/native_sim_extend/board.yml | 7 + .../native_sim_native_64_two.dts | 14 ++ .../native_sim_native_64_two.yaml | 25 ++ .../native_sim_native_64_two_defconfig | 7 + .../native_sim_native_one.dts | 218 ++++++++++++++++++ .../native_sim_native_one.yaml | 25 ++ .../native_sim_native_one_defconfig | 7 + .../board_extend/oot_root/soc/arm/Kconfig.soc | 6 + .../hwm/board_extend/oot_root/soc/arm/soc.yml | 4 + tests/cmake/hwm/board_extend/prj.conf | 1 + tests/cmake/hwm/board_extend/src/main.c | 85 +++++++ tests/cmake/hwm/board_extend/testcase.yaml | 33 +++ 25 files changed, 873 insertions(+) create mode 100644 tests/cmake/hwm/board_extend/CMakeLists.txt create mode 100644 tests/cmake/hwm/board_extend/Kconfig create mode 100644 tests/cmake/hwm/board_extend/boards/native_sim.conf create mode 100644 tests/cmake/hwm/board_extend/boards/native_sim_native_64_two.conf create mode 100644 tests/cmake/hwm/board_extend/boards/native_sim_native_one.conf create mode 100644 tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/Kconfig.mps2 create mode 100644 tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/board.cmake create mode 100644 tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/board.yml create mode 100644 tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/mps2_an521-common.dtsi create mode 100644 tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/mps2_an521_cputest.dts create mode 100644 tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/mps2_an521_cputest_defconfig create mode 100644 tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/Kconfig create mode 100644 tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/Kconfig.defconfig create mode 100644 tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/board.yml create mode 100644 tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_64_two.dts create mode 100644 tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_64_two.yaml create mode 100644 tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_64_two_defconfig create mode 100644 tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_one.dts create mode 100644 tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_one.yaml create mode 100644 tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_one_defconfig create mode 100644 tests/cmake/hwm/board_extend/oot_root/soc/arm/Kconfig.soc create mode 100644 tests/cmake/hwm/board_extend/oot_root/soc/arm/soc.yml create mode 100644 tests/cmake/hwm/board_extend/prj.conf create mode 100644 tests/cmake/hwm/board_extend/src/main.c create mode 100644 tests/cmake/hwm/board_extend/testcase.yaml diff --git a/tests/cmake/hwm/board_extend/CMakeLists.txt b/tests/cmake/hwm/board_extend/CMakeLists.txt new file mode 100644 index 0000000000000..20bd94d6af05f --- /dev/null +++ b/tests/cmake/hwm/board_extend/CMakeLists.txt @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2024 Nordic Semiconductor ASA + +cmake_minimum_required(VERSION 3.20.0) + +set(BOARD_ROOT ${CMAKE_CURRENT_LIST_DIR}/oot_root) +set(SOC_ROOT ${CMAKE_CURRENT_LIST_DIR}/oot_root) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(native_sim_extend) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/cmake/hwm/board_extend/Kconfig b/tests/cmake/hwm/board_extend/Kconfig new file mode 100644 index 0000000000000..6bbf5b7322768 --- /dev/null +++ b/tests/cmake/hwm/board_extend/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +config BASE_BOARD_SETTING + bool "Base board test string" + help + This kconfig is set when the base board config fragment is supposed to + be sourced, that is when oot variant defines + 'extends:' + ' board: native_sim' + ' qualifier: posix' + ' inherit: 1' + +source "Kconfig.zephyr" diff --git a/tests/cmake/hwm/board_extend/boards/native_sim.conf b/tests/cmake/hwm/board_extend/boards/native_sim.conf new file mode 100644 index 0000000000000..71a2b211d0aab --- /dev/null +++ b/tests/cmake/hwm/board_extend/boards/native_sim.conf @@ -0,0 +1 @@ +CONFIG_BASE_BOARD_SETTING=y diff --git a/tests/cmake/hwm/board_extend/boards/native_sim_native_64_two.conf b/tests/cmake/hwm/board_extend/boards/native_sim_native_64_two.conf new file mode 100644 index 0000000000000..b2dfe184407dc --- /dev/null +++ b/tests/cmake/hwm/board_extend/boards/native_sim_native_64_two.conf @@ -0,0 +1 @@ +CONFIG_EXTENDED_VARIANT_BOARD_SETTING=y diff --git a/tests/cmake/hwm/board_extend/boards/native_sim_native_one.conf b/tests/cmake/hwm/board_extend/boards/native_sim_native_one.conf new file mode 100644 index 0000000000000..b2dfe184407dc --- /dev/null +++ b/tests/cmake/hwm/board_extend/boards/native_sim_native_one.conf @@ -0,0 +1 @@ +CONFIG_EXTENDED_VARIANT_BOARD_SETTING=y diff --git a/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/Kconfig.mps2 b/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/Kconfig.mps2 new file mode 100644 index 0000000000000..448c9cc130809 --- /dev/null +++ b/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/Kconfig.mps2 @@ -0,0 +1,5 @@ +# Copyright (c) 2017 Linaro Limited +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_MPS2 + select SOC_MPS2_AN521_CPUTEST if BOARD_MPS2_AN521_CPUTEST diff --git a/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/board.cmake b/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/board.cmake new file mode 100644 index 0000000000000..27c74975756e2 --- /dev/null +++ b/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/board.cmake @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2024, Nordic Semiconductor ASA + +if(CONFIG_BOARD_MPS2_AN521_CPUTEST) + set(QEMU_CPU_TYPE_${ARCH} cortex-m33) + set(QEMU_FLAGS_${ARCH} + -cpu ${QEMU_CPU_TYPE_${ARCH}} + -machine mps2-an521 + -nographic + -m 16 + -vga none + ) +endif() diff --git a/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/board.yml b/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/board.yml new file mode 100644 index 0000000000000..05982ac1bb846 --- /dev/null +++ b/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/board.yml @@ -0,0 +1,2 @@ +board: + extend: mps2 diff --git a/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/mps2_an521-common.dtsi b/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/mps2_an521-common.dtsi new file mode 100644 index 0000000000000..5b1959ff5fe38 --- /dev/null +++ b/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/mps2_an521-common.dtsi @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2019 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +sysclk: system-clock { + compatible = "fixed-clock"; + clock-frequency = <25000000>; + #clock-cells = <0>; +}; + +timer0: timer@0 { + compatible = "arm,cmsdk-timer"; + reg = <0x0 0x1000>; + interrupts = <3 3>; +}; + +timer1: timer@1000 { + compatible = "arm,cmsdk-timer"; + reg = <0x1000 0x1000>; + interrupts = <4 3>; +}; + +dtimer0: dtimer@2000 { + compatible = "arm,cmsdk-dtimer"; + reg = <0x2000 0x1000>; + interrupts = <5 3>; +}; + +mhu0: mhu@3000 { + compatible = "arm,mhu"; + reg = <0x3000 0x1000>; + interrupts = <6 3>; +}; + +mhu1: mhu@4000 { + compatible = "arm,mhu"; + reg = <0x4000 0x1000>; + interrupts = <7 3>; +}; + +gpio0: gpio@100000 { + compatible = "arm,cmsdk-gpio"; + reg = <0x100000 0x1000>; + interrupts = <68 3>; + gpio-controller; + #gpio-cells = <2>; +}; + +gpio1: gpio@101000 { + compatible = "arm,cmsdk-gpio"; + reg = <0x101000 0x1000>; + interrupts = <69 3>; + gpio-controller; + #gpio-cells = <2>; +}; + +gpio2: gpio@102000 { + compatible = "arm,cmsdk-gpio"; + reg = <0x102000 0x1000>; + interrupts = <70 3>; + gpio-controller; + #gpio-cells = <2>; +}; + +gpio3: gpio@103000 { + compatible = "arm,cmsdk-gpio"; + reg = <0x103000 0x1000>; + interrupts = <71 3>; + gpio-controller; + #gpio-cells = <2>; +}; + +wdog0: wdog@81000 { + compatible = "arm,cmsdk-watchdog"; + reg = <0x81000 0x1000>; + clocks = <&sysclk>; +}; + +uart0: uart@200000 { + compatible = "arm,cmsdk-uart"; + reg = <0x200000 0x1000>; + interrupts = <33 3 32 3>; + interrupt-names = "tx", "rx"; + clocks = <&sysclk>; + current-speed = <115200>; +}; + +uart1: uart@201000 { + compatible = "arm,cmsdk-uart"; + reg = <0x201000 0x1000>; + interrupts = <35 3 34 3>; + interrupt-names = "tx", "rx"; + clocks = <&sysclk>; + current-speed = <115200>; +}; + +uart2: uart@202000 { + compatible = "arm,cmsdk-uart"; + reg = <0x202000 0x1000>; + interrupts = <37 3 36 3>; + interrupt-names = "tx", "rx"; + clocks = <&sysclk>; + current-speed = <115200>; +}; + +uart3: uart@203000 { + compatible = "arm,cmsdk-uart"; + reg = <0x203000 0x1000>; + interrupts = <39 3 38 3>; + interrupt-names = "tx", "rx"; + clocks = <&sysclk>; + current-speed = <115200>; +}; + +uart4: uart@204000 { + compatible = "arm,cmsdk-uart"; + reg = <0x204000 0x1000>; + interrupts = <41 3 40 3>; + interrupt-names = "tx", "rx"; + clocks = <&sysclk>; + current-speed = <115200>; +}; + +i2c_touch: i2c@207000 { + compatible = "arm,versatile-i2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x207000 0x1000>; +}; + +i2c_audio_conf: i2c@208000 { + compatible = "arm,versatile-i2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x208000 0x1000>; +}; + +i2c_shield0: i2c@20c000 { + compatible = "arm,versatile-i2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x20c000 0x1000>; +}; + +i2c_shield1: i2c@20d000 { + compatible = "arm,versatile-i2c"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x20d000 0x1000>; +}; + +gpio_led0: mps2_fpgaio@302000 { + compatible = "arm,mps2-fpgaio-gpio"; + + reg = <0x302000 0x4>; + gpio-controller; + #gpio-cells = <1>; + ngpios = <2>; +}; + +gpio_button: mps2_fpgaio@302008 { + compatible = "arm,mps2-fpgaio-gpio"; + + reg = <0x302008 0x4>; + gpio-controller; + #gpio-cells = <1>; + ngpios = <2>; +}; + +gpio_misc: mps2_fpgaio@30204c { + compatible = "arm,mps2-fpgaio-gpio"; + + reg = <0x30204c 0x4>; + gpio-controller; + #gpio-cells = <1>; + ngpios = <10>; +}; + +eth0: eth@2000000 { + /* Linux has "smsc,lan9115" */ + compatible = "smsc,lan9220"; + /* Actual reg range is ~0x200 */ + reg = <0x2000000 0x100000>; + interrupts = <48 3>; +}; diff --git a/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/mps2_an521_cputest.dts b/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/mps2_an521_cputest.dts new file mode 100644 index 0000000000000..2bb956645cafa --- /dev/null +++ b/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/mps2_an521_cputest.dts @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2018-2019 Linaro Limited + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include +#include +#include +#include + +/ { + compatible = "arm,mps2"; + #address-cells = <1>; + #size-cells = <1>; + + aliases { + led0 = &led_0; + led1 = &led_1; + sw0 = &user_button_0; + sw1 = &user_button_1; + uart-1 = &uart1; + watchdog0 = &wdog0; + }; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + + /* + * These SRAM and flash settings give the entire available + * code and data memories to this secure firmware image. + * This may conflict with mps2_an521_remote firmware. Use + * caution when using both targets simultaneously. + */ + zephyr,sram = &ssram2_3; + zephyr,flash = &ssram1; + }; + + leds { + compatible = "gpio-leds"; + led_0: led_0 { + gpios = <&gpio_led0 0>; + label = "USERLED0"; + }; + led_1: led_1 { + gpios = <&gpio_led0 1>; + label = "USERLED1"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + user_button_0: button_0 { + label = "USERPB0"; + gpios = <&gpio_button 0>; + zephyr,code = ; + }; + user_button_1: button_1 { + label = "USERPB1"; + gpios = <&gpio_button 1>; + zephyr,code = ; + }; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-m33"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + + mpu: mpu@e000ed90 { + compatible = "arm,armv8m-mpu"; + reg = <0xe000ed90 0x40>; + }; + }; + }; + + /* + * The memory regions defined below are according to AN521: + * https://documentation-service.arm.com/static/5fa12fe9b1a7c5445f29017f + * + * Please see tables mentioned in individual comments below for details. + */ + + ssram1: memory@10000000 { + /* Table 3-2, row 6. */ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x10000000 DT_SIZE_M(4)>; + zephyr,memory-region = "SSRAM1"; + }; + + ssram2_3: memory@38000000 { + /* Table 3-4, rows 16 and 17. */ + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x38000000 DT_SIZE_M(4)>; + zephyr,memory-region = "SSRAM2_3"; + }; + + psram: memory@80000000 { + /* Table 3-6, row 1. */ + device_type = "memory"; + reg = <0x80000000 DT_SIZE_M(16)>; + }; + + soc { + peripheral@50000000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x50000000 0x10000000>; + + #include "mps2_an521-common.dtsi" + }; + }; +}; + +&nvic { + arm,num-irq-priority-bits = <3>; +}; + +&uart1 { + status = "okay"; +}; diff --git a/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/mps2_an521_cputest_defconfig b/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/mps2_an521_cputest_defconfig new file mode 100644 index 0000000000000..08949950a9e8d --- /dev/null +++ b/tests/cmake/hwm/board_extend/oot_root/boards/arm/mps2/mps2_an521_cputest_defconfig @@ -0,0 +1,21 @@ +# +# Copyright (c) 2018-2019 Linaro Limited +# +# SPDX-License-Identifier: Apache-2.0 +# + +#CONFIG_RUNTIME_NMI=y +#CONFIG_ARM_TRUSTZONE_M=y +#CONFIG_ARM_MPU=y +CONFIG_QEMU_ICOUNT_SHIFT=6 +# +## GPIOs +CONFIG_GPIO=y + +# Serial +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y + +# Build a non-secure firmware image +#CONFIG_TRUSTED_EXECUTION_NONSECURE=y diff --git a/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/Kconfig b/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/Kconfig new file mode 100644 index 0000000000000..e724497c3b599 --- /dev/null +++ b/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/Kconfig @@ -0,0 +1,30 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config EXTENDED_VARIANT_BOARD_SETTING + bool "Extended variant board test string" + depends on BOARD_NATIVE_SIM_NATIVE_ONE || BOARD_NATIVE_SIM_NATIVE_64_TWO + help + This kconfig is set when the extended variant board config fragment + is supposed to be sourced, that is when oot variant defines 'extends:' + +config EXTENDED_VARIANT_BOARD_ONE_SETTING_PROMPTLESS + bool + depends on BOARD_NATIVE_SIM_NATIVE_ONE + help + This kconfig is promptless and is expected to be set through the + Kconfig.defconfig for the extended board. + +config EXTENDED_VARIANT_BOARD_TWO_SETTING_PROMPTLESS + bool + depends on BOARD_NATIVE_SIM_NATIVE_64_TWO + help + This kconfig is promptless and is expected to be set through the + Kconfig.defconfig for the extended board. + +config EXTENDED_VARIANT_BOARD_SETTING_DEFCONFIG + bool "Extended variant board test string defconfig" + depends on BOARD_NATIVE_SIM_NATIVE_ONE || BOARD_NATIVE_SIM_NATIVE_64_TWO + help + This kconfig is set when the extended variant board defconfig fragment + is supposed to be sourced, that is when oot variant defines 'extends:' diff --git a/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/Kconfig.defconfig b/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/Kconfig.defconfig new file mode 100644 index 0000000000000..343daa1246a31 --- /dev/null +++ b/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/Kconfig.defconfig @@ -0,0 +1,16 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_NATIVE_SIM_NATIVE_ONE + +config EXTENDED_VARIANT_BOARD_ONE_SETTING_PROMPTLESS + default y + +endif # BOARD_NATIVE_SIM_NATIVE_ONE + +if BOARD_NATIVE_SIM_NATIVE_64_TWO + +config EXTENDED_VARIANT_BOARD_TWO_SETTING_PROMPTLESS + default y + +endif # BOARD_NATIVE_SIM_NATIVE_64_TWO diff --git a/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/board.yml b/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/board.yml new file mode 100644 index 0000000000000..8df9cf3c433a8 --- /dev/null +++ b/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/board.yml @@ -0,0 +1,7 @@ +board: + extend: native_sim + variants: + - name: one + qualifier: native + - name: two + qualifier: native/64 diff --git a/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_64_two.dts b/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_64_two.dts new file mode 100644 index 0000000000000..b3fc17d81fbd4 --- /dev/null +++ b/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_64_two.dts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "native_sim_native_one.dts" + +/ { + /delete-node/ added-by-native-one; + + added-by-native-two{ + }; +}; diff --git a/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_64_two.yaml b/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_64_two.yaml new file mode 100644 index 0000000000000..190d4906cc8ae --- /dev/null +++ b/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_64_two.yaml @@ -0,0 +1,25 @@ +identifier: native_sim_native_64_two +name: Native Simulation port - 32-bit +type: native +simulation: native +arch: posix +ram: 65536 +flash: 65536 +toolchain: + - host + - llvm +supported: + - can + - counter + - dma + - eeprom + - netif:eth + - usb_device + - adc + - i2c + - spi + - gpio + - rtc +testing: + default: true +vendor: zephyr diff --git a/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_64_two_defconfig b/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_64_two_defconfig new file mode 100644 index 0000000000000..d0de015b0dfa7 --- /dev/null +++ b/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_64_two_defconfig @@ -0,0 +1,7 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_CONSOLE=y +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=1000000 + +CONFIG_EXTENDED_VARIANT_BOARD_SETTING_DEFCONFIG=y diff --git a/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_one.dts b/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_one.dts new file mode 100644 index 0000000000000..652c7605f60e3 --- /dev/null +++ b/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_one.dts @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2019 Jan Van Winkel (jan.van_winkel@dxplore.eu) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; +#include +#include +#include +#include + +/ { + model = "Native Sim Board"; + compatible = "zephyr,posix"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + zephyr,flash = &flash0; + zephyr,entropy = &rng; + zephyr,flash-controller = &flashcontroller0; + zephyr,display = &sdl_dc; + zephyr,canbus = &can_loopback0; + zephyr,code-partition = &slot0_partition; + }; + + aliases { + eeprom-0 = &eeprom0; + i2c-0 = &i2c0; + spi-0 = &spi0; + led0 = &led0; + rtc = &rtc; + }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; + label = "Green LED"; + }; + }; + + lvgl_pointer { + compatible = "zephyr,lvgl-pointer-input"; + input = <&input_sdl_touch>; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "zephyr,native-posix-cpu"; + reg = <0>; + }; + }; + + flashcontroller0: flash-controller@0 { + compatible = "zephyr,sim-flash"; + reg = <0x00000000 DT_SIZE_K(2048)>; + + #address-cells = <1>; + #size-cells = <1>; + erase-value = <0xff>; + + flash0: flash@0 { + status = "okay"; + compatible = "soc-nv-flash"; + erase-block-size = <4096>; + write-block-size = <1>; + reg = <0x00000000 DT_SIZE_K(2048)>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x0000C000>; + }; + slot0_partition: partition@c000 { + label = "image-0"; + reg = <0x0000C000 0x00069000>; + }; + slot1_partition: partition@75000 { + label = "image-1"; + reg = <0x00075000 0x00069000>; + }; + scratch_partition: partition@de000 { + label = "image-scratch"; + reg = <0x000de000 0x0001e000>; + }; + storage_partition: partition@fc000 { + label = "storage"; + reg = <0x000fc000 0x00004000>; + }; + }; + }; + }; + + eeprom0: eeprom { + status = "okay"; + compatible = "zephyr,sim-eeprom"; + size = ; + }; + + i2c0: i2c@100 { + status = "okay"; + compatible = "zephyr,i2c-emul-controller"; + clock-frequency = ; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x100 4>; + }; + + spi0: spi@200 { + status = "okay"; + compatible = "zephyr,spi-emul-controller"; + clock-frequency = <50000000>; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x200 4>; + }; + + espi0: espi@300 { + status = "okay"; + compatible = "zephyr,espi-emul-controller"; + reg = <0x300 4>; + #address-cells = <1>; + #size-cells = <0>; + }; + + uart0: uart { + status = "okay"; + compatible = "zephyr,native-posix-uart"; + /* Dummy current-speed entry to comply with serial + * DTS binding + */ + current-speed = <0>; + }; + + uart1: uart_1 { + status = "okay"; + compatible = "zephyr,native-posix-uart"; + /* Dummy current-speed entry to comply with serial + * DTS binding + */ + current-speed = <0>; + }; + + rng: rng { + status = "okay"; + compatible = "zephyr,native-posix-rng"; + }; + + counter0: counter { + status = "okay"; + compatible = "zephyr,native-posix-counter"; + }; + + gpio0: gpio@800 { + status = "okay"; + compatible = "zephyr,gpio-emul"; + reg = <0x800 0x4>; + rising-edge; + falling-edge; + high-level; + low-level; + gpio-controller; + #gpio-cells = <2>; + }; + + zephyr_udc0: udc0 { + compatible = "zephyr,native-posix-udc"; + }; + + sdl_dc: sdl_dc { + compatible = "zephyr,sdl-dc"; + height = <240>; + width = <320>; + }; + + input_sdl_touch: input-sdl-touch { + compatible = "zephyr,input-sdl-touch"; + }; + + can_loopback0: can_loopback0 { + status = "okay"; + compatible = "zephyr,can-loopback"; + }; + + can0: can { + status = "disabled"; + compatible = "zephyr,native-linux-can"; + /* adjust zcan0 to desired host interface or create an alternative + * name, e.g.: sudo ip link property add dev vcan0 altname zcan0 + */ + host-interface = "zcan0"; + }; + + rtc: rtc { + status = "okay"; + compatible = "zephyr,rtc-emul"; + alarms-count = <2>; + }; + + dma: dma { + compatible = "zephyr,dma-emul"; + #dma-cells = <1>; + stack-size = <4096>; + }; + + added-by-native-one { + }; +}; diff --git a/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_one.yaml b/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_one.yaml new file mode 100644 index 0000000000000..ea2c2d856ae50 --- /dev/null +++ b/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_one.yaml @@ -0,0 +1,25 @@ +identifier: native_sim_native_one +name: Native Simulation port - 32-bit +type: native +simulation: native +arch: posix +ram: 65536 +flash: 65536 +toolchain: + - host + - llvm +supported: + - can + - counter + - dma + - eeprom + - netif:eth + - usb_device + - adc + - i2c + - spi + - gpio + - rtc +testing: + default: true +vendor: zephyr diff --git a/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_one_defconfig b/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_one_defconfig new file mode 100644 index 0000000000000..d0de015b0dfa7 --- /dev/null +++ b/tests/cmake/hwm/board_extend/oot_root/boards/native/native_sim_extend/native_sim_native_one_defconfig @@ -0,0 +1,7 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_CONSOLE=y +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=1000000 + +CONFIG_EXTENDED_VARIANT_BOARD_SETTING_DEFCONFIG=y diff --git a/tests/cmake/hwm/board_extend/oot_root/soc/arm/Kconfig.soc b/tests/cmake/hwm/board_extend/oot_root/soc/arm/Kconfig.soc new file mode 100644 index 0000000000000..a699e8413a1e9 --- /dev/null +++ b/tests/cmake/hwm/board_extend/oot_root/soc/arm/Kconfig.soc @@ -0,0 +1,6 @@ +# Copyright (c) 2024, Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config SOC_MPS2_AN521_CPUTEST + bool + select SOC_MPS2_AN521 diff --git a/tests/cmake/hwm/board_extend/oot_root/soc/arm/soc.yml b/tests/cmake/hwm/board_extend/oot_root/soc/arm/soc.yml new file mode 100644 index 0000000000000..04b69c75ae4ef --- /dev/null +++ b/tests/cmake/hwm/board_extend/oot_root/soc/arm/soc.yml @@ -0,0 +1,4 @@ +socs: + - extend: an521 + cpuclusters: + - name: cputest diff --git a/tests/cmake/hwm/board_extend/prj.conf b/tests/cmake/hwm/board_extend/prj.conf new file mode 100644 index 0000000000000..9467c2926896d --- /dev/null +++ b/tests/cmake/hwm/board_extend/prj.conf @@ -0,0 +1 @@ +CONFIG_ZTEST=y diff --git a/tests/cmake/hwm/board_extend/src/main.c b/tests/cmake/hwm/board_extend/src/main.c new file mode 100644 index 0000000000000..9795bd8dcb8fd --- /dev/null +++ b/tests/cmake/hwm/board_extend/src/main.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#ifdef CONFIG_EXTENDED_VARIANT_BOARD_SETTING +#define EXTENDED_BOARD_A 1 +#else +#define EXTENDED_BOARD_A 0 +#endif + +#ifdef CONFIG_EXTENDED_VARIANT_BOARD_ONE_SETTING_PROMPTLESS +#define EXTENDED_BOARD_ONE_B 1 +#else +#define EXTENDED_BOARD_ONE_B 0 +#endif + +#ifdef CONFIG_EXTENDED_VARIANT_BOARD_TWO_SETTING_PROMPTLESS +#define EXTENDED_BOARD_TWO_C 1 +#else +#define EXTENDED_BOARD_TWO_C 0 +#endif + +#ifdef CONFIG_EXTENDED_VARIANT_BOARD_SETTING_DEFCONFIG +#define EXTENDED_BOARD_D 1 +#else +#define EXTENDED_BOARD_D 0 +#endif + +#ifdef CONFIG_BASE_BOARD_SETTING +#define BASE_BOARD_CONFIG 1 +#else +#define BASE_BOARD_CONFIG 0 +#endif + +#ifdef CONFIG_SOC_MPS2_AN521_CPUTEST +#define EXTENDED_SOC 1 +#else +#define EXTENDED_SOC 0 +#endif + +ZTEST_SUITE(soc_board_extend, NULL, NULL, NULL, NULL, NULL); + +#if CONFIG_BOARD_NATIVE_SIM +ZTEST(soc_board_extend, test_native_sim_extend) +{ +#if CONFIG_BOARD_NATIVE_SIM_NATIVE_ONE + zassert_true(EXTENDED_BOARD_A, "Expected extended board to be set"); + zassert_true(EXTENDED_BOARD_ONE_B, "Expected extended board to be set"); + zassert_false(EXTENDED_BOARD_TWO_C, "Did not expect extended board two to be set"); + zassert_true(EXTENDED_BOARD_D, "Expected extended board to be set"); + zassert_false(BASE_BOARD_CONFIG, "Did not expect base board to be set"); + zassert_true(DT_NODE_EXISTS(DT_PATH(added_by_native_one))); + zassert_false(DT_NODE_EXISTS(DT_PATH(added_by_native_two))); + zassert_false(DT_NODE_EXISTS(DT_PATH(adc))); +#elif CONFIG_BOARD_NATIVE_SIM_NATIVE_64_TWO + zassert_true(EXTENDED_BOARD_A, "Expected extended board to be set"); + zassert_false(EXTENDED_BOARD_ONE_B, "Did not expect extended board one to be set"); + zassert_true(EXTENDED_BOARD_TWO_C, "Expected extended board to be set"); + zassert_true(EXTENDED_BOARD_D, "Expected extended board to be set"); + zassert_false(BASE_BOARD_CONFIG, "Did not expect base board to be set"); + zassert_false(DT_NODE_EXISTS(DT_PATH(added_by_native_one))); + zassert_true(DT_NODE_EXISTS(DT_PATH(added_by_native_two))); + zassert_false(DT_NODE_EXISTS(DT_PATH(adc))); +#else + zassert_true(false, "Did not expect to build for a base native_sim board"); +#endif +#elif CONFIG_BOARD_MPS2 +ZTEST(soc_board_extend, test_an521_soc_extend) +{ +#if CONFIG_BOARD_MPS2_AN521_CPUTEST + zassert_true(EXTENDED_SOC, "Expected extended SoC to be set"); +#elif CONFIG_BOARD_MPS2 + zassert_true(false, "Did not expect to build for a base mps2 board"); +#endif + +#else +ZTEST(soc_board_extend, test_failure) +{ + zassert_true(false, "Did not expect to build for a regular board"); +#endif +} diff --git a/tests/cmake/hwm/board_extend/testcase.yaml b/tests/cmake/hwm/board_extend/testcase.yaml new file mode 100644 index 0000000000000..aae39ce6b2c41 --- /dev/null +++ b/tests/cmake/hwm/board_extend/testcase.yaml @@ -0,0 +1,33 @@ +common: + tags: + - cmake +tests: + cmake.board.extend_one: + extra_args: + # Twister can only lookup known board roots. + # Thus platform above is set to native_sim, while at this location + # we overrule with the native_sim/native/one board. + # Test will fail if we accidentially build for the base native_sim board. + - CACHED_BOARD=native_sim/native/one + platform_allow: + - native_sim + - native_sim/native/64 + integration_platforms: + - native_sim + - native_sim/native/64 + cmake.board.extend_two: + extra_args: + - CACHED_BOARD=native_sim/native/64/two + platform_allow: + - native_sim + - native_sim/native/64 + integration_platforms: + - native_sim + - native_sim/native/64 + cmake.soc.extend_cputest: + extra_args: + - CACHED_BOARD=mps2/an521/cputest + platform_allow: + - mps2/an521/cpu0 + integration_platforms: + - mps2/an521/cpu0 From 75d0086622f2be5d6b54d4f44cff8fa154478863 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 1 Jul 2024 08:19:25 +0100 Subject: [PATCH 5/9] scripts: west_commands: run: Add priority to run once config Adds an optional priority parameter to the flash runner run once configuration which allows for deciding upon which file should ultimately be used Signed-off-by: Jamie McCrae --- scripts/schemas/board-schema.yml | 5 ++ scripts/schemas/soc-schema.yml | 5 ++ scripts/west_commands/run_common.py | 105 +++++++++++++++++----------- 3 files changed, 75 insertions(+), 40 deletions(-) diff --git a/scripts/schemas/board-schema.yml b/scripts/schemas/board-schema.yml index 656a62a37ef0f..4c86c9d000c2b 100644 --- a/scripts/schemas/board-schema.yml +++ b/scripts/schemas/board-schema.yml @@ -103,6 +103,11 @@ mapping: runners: type: map mapping: + priority: + type: int + desc: | + Priority of this flash run once configuration. The highest value data will be used + instead of any with lower priorities. If omitted, will default to 10. run_once: type: map desc: | diff --git a/scripts/schemas/soc-schema.yml b/scripts/schemas/soc-schema.yml index 1d8537e8ad273..060afea3254c8 100644 --- a/scripts/schemas/soc-schema.yml +++ b/scripts/schemas/soc-schema.yml @@ -88,6 +88,11 @@ mapping: runners: type: map mapping: + priority: + type: int + desc: | + Priority of this flash run once configuration. The highest value data will be used + instead of any with lower priorities. If omitted, will default to 0. run_once: type: map desc: | diff --git a/scripts/west_commands/run_common.py b/scripts/west_commands/run_common.py index 82ec7a09b9bd8..adfd2922fb98d 100644 --- a/scripts/west_commands/run_common.py +++ b/scripts/west_commands/run_common.py @@ -42,6 +42,10 @@ # Don't change this, or output from argparse won't match up. INDENT = ' ' * 2 +IGNORED_RUN_ONCE_PRIORITY = -1 +SOC_FILE_RUN_ONCE_DEFAULT_PRIORITY = 0 +BOARD_FILE_RUN_ONCE_DEFAULT_PRIORITY = 10 + if log.VERBOSE >= log.VERBOSE_NORMAL: # Using level 1 allows sub-DEBUG levels of verbosity. The # west.log module decides whether or not to actually print the @@ -96,6 +100,13 @@ class ImagesFlashed: flashed: int = 0 total: int = 0 +@dataclass +class SocBoardFilesProcessing: + filename: str + board: bool = False + priority: int = IGNORED_RUN_ONCE_PRIORITY + yaml: object = None + def command_verb(command): return "flash" if command.name == "flash" else "debug" @@ -178,6 +189,10 @@ def do_run_common(command, user_args, user_runner_args, domain_file=None): # images for a given board. board_image_count = defaultdict(ImagesFlashed) + highest_priority = IGNORED_RUN_ONCE_PRIORITY + highest_entry = None + check_files = [] + if user_args.context: dump_context(command, user_args, user_runner_args) return @@ -223,48 +238,58 @@ def do_run_common(command, user_args, user_runner_args, domain_file=None): # Load board flash runner configuration (if it exists) and store # single-use commands in a dictionary so that they get executed # once per unique board name. - if cache['BOARD_DIR'] not in processed_boards and 'SOC_FULL_DIR' in cache: - soc_yaml_file = Path(cache['SOC_FULL_DIR']) / 'soc.yml' - board_yaml_file = Path(cache['BOARD_DIR']) / 'board.yml' - group_type = 'boards' - - # Search for flash runner configuration, board takes priority over SoC - try: - with open(board_yaml_file, 'r') as f: - data_yaml = yaml.safe_load(f.read()) - - except FileNotFoundError: - continue - - if 'runners' not in data_yaml: - # Check SoC file - group_type = 'qualifiers' - try: - with open(soc_yaml_file, 'r') as f: - data_yaml = yaml.safe_load(f.read()) - - except FileNotFoundError: + for directory in cache.get_list('SOC_DIRECTORIES'): + if directory not in processed_boards: + check_files.append(SocBoardFilesProcessing(Path(directory) / 'soc.yml')) + processed_boards.add(directory) + + for directory in cache.get_list('BOARD_DIRECTORIES'): + if directory not in processed_boards: + check_files.append(SocBoardFilesProcessing(Path(directory) / 'board.yml', True)) + processed_boards.add(directory) + + for check in check_files: + try: + with open(check.filename, 'r') as f: + check.yaml = yaml.safe_load(f.read()) + + if 'runners' not in check.yaml: + continue + elif check.board is False and 'run_once' not in check.yaml['runners']: continue - processed_boards.add(cache['BOARD_DIR']) - - if 'runners' not in data_yaml or 'run_once' not in data_yaml['runners']: - continue - - for cmd in data_yaml['runners']['run_once']: - for data in data_yaml['runners']['run_once'][cmd]: - for group in data['groups']: - run_first = bool(data['run'] == 'first') - if group_type == 'qualifiers': - targets = [] - for target in group[group_type]: - # For SoC-based qualifiers, prepend to the beginning of the - # match to allow for matching any board name - targets.append('([^/]+)/' + target) - else: - targets = group[group_type] - - used_cmds.append(UsedFlashCommand(cmd, targets, data['runners'], run_first)) + if 'priority' in check.yaml['runners']: + check.priority = check.yaml['runners']['priority'] + else: + check.priority = BOARD_FILE_RUN_ONCE_DEFAULT_PRIORITY if check.board is True else SOC_FILE_RUN_ONCE_DEFAULT_PRIORITY + + if check.priority == highest_priority: + log.die("Duplicate flash run once configuration found with equal priorities") + + elif check.priority > highest_priority: + highest_priority = check.priority + highest_entry = check + + except FileNotFoundError: + continue + + if highest_entry is not None: + group_type = 'boards' if highest_entry.board is True else 'qualifiers' + + for cmd in highest_entry.yaml['runners']['run_once']: + for data in highest_entry.yaml['runners']['run_once'][cmd]: + for group in data['groups']: + run_first = bool(data['run'] == 'first') + if group_type == 'qualifiers': + targets = [] + for target in group[group_type]: + # For SoC-based qualifiers, prepend to the beginning of the + # match to allow for matching any board name + targets.append('([^/]+)/' + target) + else: + targets = group[group_type] + + used_cmds.append(UsedFlashCommand(cmd, targets, data['runners'], run_first)) # Reduce entries to only those having matching board names (either exact or with regex) and # remove any entries with empty board lists From 15e95a64e3e80e2b2276752954c03ac0391e5d65 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 8 Jul 2024 13:25:12 +0100 Subject: [PATCH 6/9] scripts: list_hardware: Do not check qualifiers for run once config Removes validating the qualifiers for flash run once configuration as files may be present that contain information for qualifiers that are not present in a single repository but are spaced out in other repositories, or might be optional Signed-off-by: Jamie McCrae --- scripts/list_hardware.py | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/scripts/list_hardware.py b/scripts/list_hardware.py index 57c8b22586f9c..0a446ad7fff0d 100755 --- a/scripts/list_hardware.py +++ b/scripts/list_hardware.py @@ -100,25 +100,13 @@ def __init__(self, folder='', soc_yaml=None): for item_data in data['runners']['run_once'][grp]: for group in item_data['groups']: for qualifiers in group['qualifiers']: - soc_name, *components = qualifiers.split('/') + soc_name = qualifiers.split('/')[0] found_match = False - # Allow 'ns' as final qualifier until "virtual" CPUs are ported to soc.yml - # https://github.com/zephyrproject-rtos/zephyr/issues/70721 - if components and components[-1] == 'ns': - components.pop() - for soc in self._socs + self._extended_socs: if re.match(fr'^{soc_name}$', soc.name) is not None: - if soc.cpuclusters and components: - check_string = '/'.join(components) - for cpucluster in soc.cpuclusters: - if re.match(fr'^{check_string}$', cpucluster) is not None: - found_match = True - break - elif not soc.cpuclusters and not components: - found_match = True - break + found_match = True + break if found_match is False: sys.exit(f'ERROR: SoC qualifier match unresolved: {qualifiers}') From f99f777923438bc7374b7ca8178dc15aec18c0b2 Mon Sep 17 00:00:00 2001 From: Grzegorz Swiderski Date: Thu, 18 Jul 2024 15:08:35 +0200 Subject: [PATCH 7/9] scripts: list_boards: Reintroduce Board.dir as @property In the `Board` class, the `dir` member was renamed to `directories`, both to indicate that it is now a list (in HWMv2 with board extensions) and to reflect the addition of the `BOARD_DIRECTORIES` CMake variable. Considering that the build system also keeps the `BOARD_DIR` variable, and for the sake of backwards compatibility and brevity, it should be useful to retain `Board.dir` in Python as well, symmetrically. Signed-off-by: Grzegorz Swiderski --- scripts/list_boards.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/list_boards.py b/scripts/list_boards.py index 634c67df821a0..44247b450ff90 100755 --- a/scripts/list_boards.py +++ b/scripts/list_boards.py @@ -104,6 +104,13 @@ class Board: socs: List[Soc] = field(default_factory=list, compare=False) variants: List[str] = field(default_factory=list, compare=False) + @property + def dir(self): + # Get the main board directory. + if isinstance(self.directories, Path): + return self.directories + return self.directories[0] + def from_qualifier(self, qualifiers): qualifiers_list = qualifiers.split('/') From 37fba9afcc705ec1f875f35b84358a80d9113eef Mon Sep 17 00:00:00 2001 From: Grzegorz Swiderski Date: Thu, 18 Jul 2024 15:08:35 +0200 Subject: [PATCH 8/9] scripts: Undo Board.{dir -> directories[0]} renames `Board.dir` can be used in place of `Board.directories[0]` for brevity. Signed-off-by: Grzegorz Swiderski --- doc/_extensions/zephyr/kconfig/__init__.py | 3 +-- scripts/ci/test_plan.py | 2 +- scripts/list_boards.py | 2 +- scripts/west_commands/boards.py | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/doc/_extensions/zephyr/kconfig/__init__.py b/doc/_extensions/zephyr/kconfig/__init__.py index abbdcc1b9be35..905376d816863 100644 --- a/doc/_extensions/zephyr/kconfig/__init__.py +++ b/doc/_extensions/zephyr/kconfig/__init__.py @@ -127,8 +127,7 @@ def kconfig_load(app: Sphinx) -> Tuple[kconfiglib.Kconfig, Dict[str, str]]: board_str = 'BOARD_' + re.sub(r"[^a-zA-Z0-9_]", "_", qualifier).upper() f.write('config ' + board_str + '\n') f.write('\t bool\n') - f.write('source "' + - (board.directories[0] / ('Kconfig.' + board.name)).as_posix() + '"\n\n') + f.write('source "' + (board.dir / ('Kconfig.' + board.name)).as_posix() + '"\n\n') # base environment os.environ["ZEPHYR_BASE"] = str(ZEPHYR_BASE) diff --git a/scripts/ci/test_plan.py b/scripts/ci/test_plan.py index 4bb428ee5b1bb..dfc8736819878 100755 --- a/scripts/ci/test_plan.py +++ b/scripts/ci/test_plan.py @@ -244,7 +244,7 @@ def find_boards(self): for changed in changed_boards: for board in known_boards: c = (zephyr_base / changed).resolve() - if c.is_relative_to(board.directories[0].resolve()): + if c.is_relative_to(board.dir.resolve()): for file in glob.glob(os.path.join(board.dir, f"{board.name}*.yaml")): with open(file, 'r', encoding='utf-8') as f: b = yaml.load(f.read(), Loader=SafeLoader) diff --git a/scripts/list_boards.py b/scripts/list_boards.py index 44247b450ff90..443e18a1980bd 100755 --- a/scripts/list_boards.py +++ b/scripts/list_boards.py @@ -447,7 +447,7 @@ def dump_boards(args): if args.cmakeformat is not None: info = args.cmakeformat.format( NAME='NAME;' + board.name, - DIR='DIR;' + str(board.directories.as_posix()), + DIR='DIR;' + str(board.dir.as_posix()), HWM='HWM;' + board.hwm, VENDOR='VENDOR;NOTFOUND', REVISION_DEFAULT='REVISION_DEFAULT;NOTFOUND', diff --git a/scripts/west_commands/boards.py b/scripts/west_commands/boards.py index 9cb6182a7a725..6c4ee16846604 100644 --- a/scripts/west_commands/boards.py +++ b/scripts/west_commands/boards.py @@ -104,7 +104,7 @@ def do_run(self, args, _): args.format.format( name=board.name, full_name=board.full_name, - dir=board.directories[0], + dir=board.dir, hwm=board.hwm, vendor=board.vendor, qualifiers=list_boards.board_v2_qualifiers_csv(board), From c145817582ba2ec3517e89a5904bfc3135b259b5 Mon Sep 17 00:00:00 2001 From: Torsten Rasmussen Date: Tue, 28 May 2024 15:31:42 +0200 Subject: [PATCH 9/9] doc: extend board porting guide with new board extend feature Extend the board porting guide with documentation on the new board extend feature. Signed-off-by: Torsten Rasmussen --- doc/hardware/porting/board_porting.rst | 58 ++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/doc/hardware/porting/board_porting.rst b/doc/hardware/porting/board_porting.rst index 0147c7c2679ca..523959ec878dc 100644 --- a/doc/hardware/porting/board_porting.rst +++ b/doc/hardware/porting/board_porting.rst @@ -912,9 +912,67 @@ There are some extra things you'll need to do: #. Prepare a pull request adding your board which follows the :ref:`contribute_guidelines`. +.. _extend-board: + Board extensions **************** +The board hardware model in Zephyr allows you to extend an existing board with +new board variants. Such board extensions can be done in your custom repository +and thus outside of the Zephyr repository. + +Extending an existing board with an extra variant allows you to adjust an +existing board and thereby during build to select building for the existing, +unmodified board, or the new variant. + +To extend an existing board, first create a :file:`board.yml` in your extended +board. Make sure to use the directory structure described in +:ref:`create-your-board-directory`. + +The skeleton of the board YAML file for extending a board is: + +.. code-block:: yaml + + board: + extend: + variants: + - name: + qualifier: + +When extending a board, your board directory should look like: + +.. code-block:: none + + boards//plank + ├── board.yml + ├── plank__defconfig + └── plank_.dts + +Replace ``plank`` with the real name of the board you extend. + +In some cases you might want to also adjust additional settings, like the +:file:`Kconfig.defconfig` or :file:`Kconfig.{board}`. +Therefore it is also possible to provide the following in addition when +extending a board. + +.. code-block:: none + + boards//plank + ├── board.cmake + ├── Kconfig + ├── Kconfig.plank + ├── Kconfig.defconfig + └── plank_.yaml + +Board extensions (Old hardware model) +************************************* + +.. note:: + + This extension mechanism is intended for boards in old hardware description + format. For boards described in new hardware model format, use the extension + feature described in :ref:`extend-board`. + Boards already supported by Zephyr can be extended by downstream users, such as ``example-application`` or vendor SDKs. In some situations, certain hardware description or :ref:`choices ` can not be added in the