diff --git a/arch/common/CMakeLists.txt b/arch/common/CMakeLists.txt index e79b7cd0abf..6f84bb96351 100644 --- a/arch/common/CMakeLists.txt +++ b/arch/common/CMakeLists.txt @@ -56,12 +56,21 @@ zephyr_linker_sources_ifdef(CONFIG_GEN_IRQ_VECTOR_TABLE ) if(CONFIG_GEN_ISR_TABLES) - zephyr_linker_section(NAME .intList VMA IDT_LIST LMA IDT_LIST NOINPUT PASS NOT LINKER_ZEPHYR_FINAL) - zephyr_linker_section_configure(SECTION .intList KEEP INPUT ".irq_info" FIRST) - zephyr_linker_section_configure(SECTION .intList KEEP INPUT ".intList") - - zephyr_linker_section_configure(SECTION /DISCARD/ KEEP INPUT ".irq_info" PASS LINKER_ZEPHYR_FINAL) - zephyr_linker_section_configure(SECTION /DISCARD/ KEEP INPUT ".intList" PASS LINKER_ZEPHYR_FINAL) + # IAR Toolchain is having problems with discarding .intList + # This will always keep .intList in a harmless location + # until we can implement a proper DISCARD. + if(ZEPHYR_TOOLCHAIN_VARIANT STREQUAL "iar") + zephyr_linker_section(NAME .intList GROUP RODATA_REGION NOINPUT) + zephyr_linker_section_configure(SECTION .intList KEEP INPUT ".irq_info" FIRST) + zephyr_linker_section_configure(SECTION .intList KEEP INPUT ".intList") + else() + zephyr_linker_section(NAME .intList VMA IDT_LIST LMA IDT_LIST NOINPUT PASS NOT LINKER_ZEPHYR_FINAL) + zephyr_linker_section_configure(SECTION .intList KEEP INPUT ".irq_info" FIRST) + zephyr_linker_section_configure(SECTION .intList KEEP INPUT ".intList") + + zephyr_linker_section_configure(SECTION /DISCARD/ KEEP INPUT ".irq_info" PASS LINKER_ZEPHYR_FINAL) + zephyr_linker_section_configure(SECTION /DISCARD/ KEEP INPUT ".intList" PASS LINKER_ZEPHYR_FINAL) + endif() endif() zephyr_linker_sources_ifdef(CONFIG_ARCH_HAS_RAMFUNC_SUPPORT diff --git a/cmake/bintools/iar/target.cmake b/cmake/bintools/iar/target.cmake new file mode 100644 index 00000000000..0ea594503cc --- /dev/null +++ b/cmake/bintools/iar/target.cmake @@ -0,0 +1,44 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +# Configures binary tools as GNU binutils +include(extensions) + +# Specifically choose arm-zephyr-eabi from the zephyr sdk for objcopy and friends + +if("${IAR_TOOLCHAIN_VARIANT}" STREQUAL "iccarm") + set(IAR_ZEPHYR_HOME ${ZEPHYR_SDK_INSTALL_DIR}/arm-zephyr-eabi/bin) + set(IAR_GNU_PREFIX arm-zephyr-eabi-) +else() + message(ERROR "IAR_TOOLCHAIN_VARIANT not set") +endif() +find_program(CMAKE_OBJCOPY ${IAR_GNU_PREFIX}objcopy PATHS ${IAR_ZEPHYR_HOME} NO_DEFAULT_PATH) +find_program(CMAKE_OBJDUMP ${IAR_GNU_PREFIX}objdump PATHS ${IAR_ZEPHYR_HOME} NO_DEFAULT_PATH) +find_program(CMAKE_AS ${IAR_GNU_PREFIX}as PATHS ${IAR_ZEPHYR_HOME} NO_DEFAULT_PATH) +find_program(CMAKE_AR ${IAR_GNU_PREFIX}ar PATHS ${IAR_ZEPHYR_HOME} NO_DEFAULT_PATH) +find_program(CMAKE_RANLIB ${IAR_GNU_PREFIX}ranlib PATHS ${IAR_ZEPHYR_HOME} NO_DEFAULT_PATH) +find_program(CMAKE_READELF ${IAR_GNU_PREFIX}readelf PATHS ${IAR_ZEPHYR_HOME} NO_DEFAULT_PATH) +find_program(CMAKE_NM ${IAR_GNU_PREFIX}nm PATHS ${IAR_ZEPHYR_HOME} NO_DEFAULT_PATH) +find_program(CMAKE_STRIP ${IAR_GNU_PREFIX}strip PATHS ${IAR_ZEPHYR_HOME} NO_DEFAULT_PATH) +find_program(CMAKE_GDB ${IAR_GNU_PREFIX}gdb-py PATHS ${IAR_ZEPHYR_HOME} NO_DEFAULT_PATH) + +if(CMAKE_GDB) + execute_process( + COMMAND ${CMAKE_GDB} --configuration + RESULTS_VARIABLE GDB_CFG_ERR + OUTPUT_QUIET + ERROR_QUIET + ) +endif() + +if(NOT CMAKE_GDB OR GDB_CFG_ERR) + find_program(CMAKE_GDB_NO_PY ${CROSS_COMPILE}gdb PATHS ${TOOLCHAIN_HOME} NO_DEFAULT_PATH) + + if(CMAKE_GDB_NO_PY) + set(CMAKE_GDB ${CMAKE_GDB_NO_PY} CACHE FILEPATH "Path to a program." FORCE) + endif() +endif() + +# Include bin tool properties +include(${ZEPHYR_BASE}/cmake/bintools/iar/target_bintools.cmake) diff --git a/cmake/bintools/iar/target_bintools.cmake b/cmake/bintools/iar/target_bintools.cmake new file mode 100644 index 00000000000..087bd518df1 --- /dev/null +++ b/cmake/bintools/iar/target_bintools.cmake @@ -0,0 +1,135 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 +# +# - elfconvert : Name of command for elf file conversion. +# In this implementation `objcopy` is used +# elfconvert_formats : Formats supported: ihex, srec, binary +# elfconvert_flag : empty +# elfconvert_flag_final : empty +# elfconvert_flag_strip_all : -S +# elfconvert_flag_strip_debug : -g +# elfconvert_flag_intarget : --input-target= +# elfconvert_flag_outtarget : --output-target= +# elfconvert_flag_section_remove: --remove-section= +# elfconvert_flag_section_only : --only-section= +# elfconvert_flag_section_rename: --rename-section; +# elfconvert_flag_gapfill : --gap-fill; +# Note: The ';' will be transformed into an +# empty space when executed +# elfconvert_flag_srec_len : --srec-len= +# elfconvert_flag_infile : empty, objcopy doesn't take arguments for filenames +# elfconvert_flag_outfile : empty, objcopy doesn't take arguments for filenames +# + +# elfconvert to use for transforming an elf file into another format, +# such as intel hex, s-rec, binary, etc. +set_property(TARGET bintools PROPERTY elfconvert_command ${CMAKE_OBJCOPY}) + +# List of format the tool supports for converting, for example, +# GNU tools uses objectcopy, which supports the following: ihex, srec, binary +set_property(TARGET bintools PROPERTY elfconvert_formats ihex srec binary) + +set_property(TARGET bintools PROPERTY elfconvert_flag "") +set_property(TARGET bintools PROPERTY elfconvert_flag_final "") + +set_property(TARGET bintools PROPERTY elfconvert_flag_strip_all "-S") +set_property(TARGET bintools PROPERTY elfconvert_flag_strip_debug "-g") + +set_property(TARGET bintools PROPERTY elfconvert_flag_intarget "--input-target=") +set_property(TARGET bintools PROPERTY elfconvert_flag_outtarget "--output-target=") + +set_property(TARGET bintools PROPERTY elfconvert_flag_section_remove "--remove-section=") +set_property(TARGET bintools PROPERTY elfconvert_flag_section_only "--only-section=") +set_property(TARGET bintools PROPERTY elfconvert_flag_section_rename "--rename-section;") + +set_property(TARGET bintools PROPERTY elfconvert_flag_lma_adjust "--change-section-lma;") + +# Note, placing a ';' at the end results in the following param to be a list, +# and hence space separated. +# Thus the command line argument becomes: +# `--gap-file ` instead of `--gap-fill` (The latter would result in an error) +set_property(TARGET bintools PROPERTY elfconvert_flag_gapfill "--gap-fill;") +set_property(TARGET bintools PROPERTY elfconvert_flag_srec_len "--srec-len=") + +set_property(TARGET bintools PROPERTY elfconvert_flag_infile "") +set_property(TARGET bintools PROPERTY elfconvert_flag_outfile "") + +# +# - disassembly : Name of command for disassembly of files +# In this implementation `objdump` is used +# disassembly_flag : -d +# disassembly_flag_final : empty +# disassembly_flag_inline_source : -S +# disassembly_flag_all : -SDz +# disassembly_flag_infile : empty, objdump doesn't take arguments for filenames +# disassembly_flag_outfile : '>', objdump doesn't take arguments for output file, but result is printed to standard out, and is redirected. + +set_property(TARGET bintools PROPERTY disassembly_command ${CMAKE_OBJDUMP}) +set_property(TARGET bintools PROPERTY disassembly_flag -d) +set_property(TARGET bintools PROPERTY disassembly_flag_final "") +set_property(TARGET bintools PROPERTY disassembly_flag_inline_source -S) +set_property(TARGET bintools PROPERTY disassembly_flag_all -SDz) + +set_property(TARGET bintools PROPERTY disassembly_flag_infile "") +set_property(TARGET bintools PROPERTY disassembly_flag_outfile ">;" ) + +# +# - strip: Name of command for stripping symbols +# In this implementation `strip` is used +# strip_flag : empty +# strip_flag_final : empty +# strip_flag_all : --strip-all +# strip_flag_debug : --strip-debug +# strip_flag_dwo : --strip-dwo +# strip_flag_infile : empty, strip doesn't take arguments for input file +# strip_flag_outfile : -o + +# This is using strip from bintools. +set_property(TARGET bintools PROPERTY strip_command ${CMAKE_STRIP}) + +# Any flag the strip command requires for processing +set_property(TARGET bintools PROPERTY strip_flag "") +set_property(TARGET bintools PROPERTY strip_flag_final "") + +set_property(TARGET bintools PROPERTY strip_flag_all --strip-all) +set_property(TARGET bintools PROPERTY strip_flag_debug --strip-debug) +set_property(TARGET bintools PROPERTY strip_flag_dwo --strip-dwo) +set_property(TARGET bintools PROPERTY strip_flag_remove_section -R ) + +set_property(TARGET bintools PROPERTY strip_flag_infile "") +set_property(TARGET bintools PROPERTY strip_flag_outfile -o ) + +# +# - readelf : Name of command for reading elf files. +# In this implementation `readelf` is used +# readelf_flag : empty +# readelf_flag_final : empty +# readelf_flag_headers : -e +# readelf_flag_infile : empty, readelf doesn't take arguments for filenames +# readelf_flag_outfile : '>', readelf doesn't take arguments for output +# file, but result is printed to standard out, and +# is redirected. + +# This is using readelf from bintools. +set_property(TARGET bintools PROPERTY readelf_command ${CMAKE_READELF}) + +set_property(TARGET bintools PROPERTY readelf_flag "") +set_property(TARGET bintools PROPERTY readelf_flag_final "") +set_property(TARGET bintools PROPERTY readelf_flag_headers -e) + +set_property(TARGET bintools PROPERTY readelf_flag_infile "") +set_property(TARGET bintools PROPERTY readelf_flag_outfile ">;" ) + +# Example on how to support dwarfdump instead of readelf +#set_property(TARGET bintools PROPERTY readelf_command dwarfdump) +#set_property(TARGET bintools PROPERTY readelf_flag "") +#set_property(TARGET bintools PROPERTY readelf_flag_headers -E) +#set_property(TARGET bintools PROPERTY readelf_flag_infile "") +#set_property(TARGET bintools PROPERTY readelf_flag_outfile "-O file=" ) + +set_property(TARGET bintools PROPERTY symbols_command ${CMAKE_NM}) +set_property(TARGET bintools PROPERTY symbols_flag "") +set_property(TARGET bintools PROPERTY symbols_final "") +set_property(TARGET bintools PROPERTY symbols_infile "") +set_property(TARGET bintools PROPERTY symbols_outfile ">;" ) diff --git a/cmake/compiler/iar/compiler_flags.cmake b/cmake/compiler/iar/compiler_flags.cmake new file mode 100644 index 00000000000..49cd7bfd33e --- /dev/null +++ b/cmake/compiler/iar/compiler_flags.cmake @@ -0,0 +1,178 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +# Compiler options for the IAR C/C++ Compiler for Arm + +##################################################### +# This section covers flags related to optimization # +##################################################### +set_compiler_property(PROPERTY no_optimization -On) + +set_compiler_property(PROPERTY optimization_debug -Ol) + +set_compiler_property(PROPERTY optimization_speed -Ohs) + +set_compiler_property(PROPERTY optimization_size -Ohz) + +set_compiler_property(PROPERTY optimization_size_aggressive -Ohz) + +####################################################### +# This section covers flags related to warning levels # +####################################################### + +# Property for standard warning base in Zephyr, this will always be set when +# compiling. +set_compiler_property(PROPERTY warning_base + --diag_error=Pe223 # function "xxx" declared implicitly + --diag_warning=Pe054 # too few arguments in invocation of macro + --diag_warning=Pe144 # a value of type "void *" cannot be used to initialize an entity of type [...] "void (*)(struct onoff_manager *, int)" + --diag_warning=Pe167 # argument of type "void *" is incompatible with [...] "void (*)(void *, void *, void *)" + --diag_suppress=Pe1675 # unrecognized GCC pragma + --diag_suppress=Pe111 # statement is unreachable + --diag_suppress=Pe1143 # arithmetic on pointer to void or function type + --diag_suppress=Pe068) # integer conversion resulted in a change of sign) + + +set(IAR_WARNING_DW_1 + --diag_suppress=Pe188 # enumerated type mixed with another type + --diag_suppress=Pe128 # loop is not reachable + --diag_suppress=Pe550 # variable "res" was set but never used + --diag_suppress=Pe546 # transfer of control bypasses initialization + --diag_suppress=Pe186) # pointless comparison of unsigned integer with zero + +set(IAR_WARNING_DW2 + --diag_suppress=Pe1097 # unknown attribute + --diag_suppress=Pe381 # extra ";" ignored + --diag_suppress=Pa082 # undefined behavior: the order of volatile accesses is undefined + --diag_suppress=Pa084 # pointless integer comparison, the result is always false + --diag_suppress=Pe185 # dynamic initialization in unreachable code ) + --diag_suppress=Pe167 # argument of type "onoff_notify_fn" is incompatible with... + --diag_suppress=Pe144 # a value of type "void *" cannot be used to initialize... + --diag_suppress=Pe177 # function "xxx" was declared but never referenced + --diag_suppress=Pe513) # a value of type "void *" cannot be assigned to an entity of type "int (*)(int)" + +set(IAR_WARNING_DW3) + +set_compiler_property(PROPERTY warning_dw_1 + ${IAR_WARNING_DW_3} + ${IAR_WARNING_DW_2} + ${IAR_WARNING_DW_1}) + +set_compiler_property(PROPERTY warning_dw_2 + ${IAR_WARNING_DW3} + ${IAR_WARNING_DW2}) + +# no suppressions +set_compiler_property(PROPERTY warning_dw_3 ${IAR_WARNING_DW3}) + +# Extended warning set supported by the compiler +set_compiler_property(PROPERTY warning_extended) + +# Compiler property that will issue error if a declaration does not specify a type +set_compiler_property(PROPERTY warning_error_implicit_int) + +# Compiler flags to use when compiling according to MISRA +set_compiler_property(PROPERTY warning_error_misra_sane) + +set_property(TARGET compiler PROPERTY warnings_as_errors --warnings_are_errors) + +########################################################################### +# This section covers flags related to C or C++ standards / standard libs # +########################################################################### + +# Compiler flags for C standard. The specific standard must be appended by user. +# For example, gcc specifies this as: set_compiler_property(PROPERTY cstd -std=) +# TC-WG: the `cstd99` is used regardless of this flag being useful for iccarm +# This flag will make it a symbol. Works for C,CXX,ASM +# Since ICCARM does not use C standard flags, we just make them a defined symbol +# instead +set_compiler_property(PROPERTY cstd -D__IAR_CSTD_) + +# Compiler flags for disabling C standard include and instead specify include +# dirs in nostdinc_include to use. +set_compiler_property(PROPERTY nostdinc) +set_compiler_property(PROPERTY nostdinc_include) + +# Compiler flags for disabling C++ standard include. +set_compiler_property(TARGET compiler-cpp PROPERTY nostdincxx) + +# Required C++ flags when compiling C++ code +set_property(TARGET compiler-cpp PROPERTY required --c++) + +# Compiler flags to use for specific C++ dialects +set_property(TARGET compiler-cpp PROPERTY dialect_cpp98) +set_property(TARGET compiler-cpp PROPERTY dialect_cpp11) +set_property(TARGET compiler-cpp PROPERTY dialect_cpp14) +set_property(TARGET compiler-cpp PROPERTY dialect_cpp17 --libc++) +set_property(TARGET compiler-cpp PROPERTY dialect_cpp2a --libc++) +set_property(TARGET compiler-cpp PROPERTY dialect_cpp20 --libc++) +set_property(TARGET compiler-cpp PROPERTY dialect_cpp2b --libc++) + +# Flag for disabling strict aliasing rule in C and C++ +set_compiler_property(PROPERTY no_strict_aliasing) + +# Flag for disabling exceptions in C++ +set_property(TARGET compiler-cpp PROPERTY no_exceptions --no_exceptions) + +# Flag for disabling rtti in C++ +set_property(TARGET compiler-cpp PROPERTY no_rtti --no_rtti) + +################################################### +# This section covers all remaining C / C++ flags # +################################################### + +# Flags for coverage generation +set_compiler_property(PROPERTY coverage) + +# Security canaries flags. +set_compiler_property(PROPERTY security_canaries --stack_protection) +set_compiler_property(PROPERTY security_canaries_strong --stack_protection) +set_compiler_property(PROPERTY security_canaries_all --security_canaries_all_is_not_supported) +set_compiler_property(PROPERTY security_canaries_explicit --security_canaries_explicit_is_not_supported) + +if(CONFIG_STACK_CANARIES_TLS) + check_set_compiler_property(APPEND PROPERTY security_canaries --stack_protector_guard=tls) + check_set_compiler_property(APPEND PROPERTY security_canaries_strong --stack_protector_guard=tls) + check_set_compiler_property(APPEND PROPERTY security_canaries_all --stack_protector_guard=tls) + check_set_compiler_property(APPEND PROPERTY security_canaries_explicit --stack_protector_guard=tls) +endif() + +set_compiler_property(PROPERTY security_fortify) + +# Flag for a hosted (no-freestanding) application +set_compiler_property(PROPERTY hosted) + +# gcc flag for a freestanding application +set_compiler_property(PROPERTY freestanding) + +# Flag to include debugging symbol in compilation +set_property(TARGET compiler PROPERTY debug --debug) +set_property(TARGET compiler-cpp PROPERTY debug --debug) +set_property(TARGET asm PROPERTY debug -gdwarf-4) + +set_compiler_property(PROPERTY no_common) + +# Flags for imacros. The specific header must be appended by user. +set_property(TARGET compiler PROPERTY imacros --preinclude) +set_property(TARGET compiler-cpp PROPERTY imacros --preinclude) +set_property(TARGET asm PROPERTY imacros -imacros) + +# Compiler flag for turning off thread-safe initialization of local statics +set_property(TARGET compiler-cpp PROPERTY no_threadsafe_statics) + +# Required ASM flags when compiling +set_property(TARGET asm PROPERTY required) + +# Compiler flag for disabling pointer arithmetic warnings +set_compiler_property(PROPERTY warning_no_pointer_arithmetic) + +# Compiler flags for disabling position independent code / executable +set_compiler_property(PROPERTY no_position_independent) + +# Compiler flag for defining preinclude files. +set_compiler_property(PROPERTY include_file --preinclude) + +set_compiler_property(PROPERTY cmse --cmse) + +set_property(TARGET asm PROPERTY cmse -mcmse) diff --git a/cmake/compiler/iar/generic.cmake b/cmake/compiler/iar/generic.cmake new file mode 100644 index 00000000000..5d46412770d --- /dev/null +++ b/cmake/compiler/iar/generic.cmake @@ -0,0 +1,15 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +if(NOT CMAKE_DTS_PREPROCESSOR) + find_program(CMAKE_DTS_PREPROCESSOR arm-zephyr-eabi-gcc PATHS ${ZEPHYR_SDK_INSTALL_DIR}/arm-zephyr-eabi/bin NO_DEFAULT_PATH) +endif() + +if(NOT CMAKE_DTS_PREPROCESSOR) + message(FATAL_ERROR "Zephyr was unable to find \`arm-zephyr-eabi-gcc\` for DTS preprocessing") +endif() + +if(CMAKE_C_COMPILER STREQUAL CMAKE_C_COMPILER-NOTFOUND) + message(FATAL_ERROR "Zephyr was unable to find the IAR toolchain. Was the environment misconfigured?") +endif() diff --git a/cmake/compiler/iar/iccarm-cpu.cmake b/cmake/compiler/iar/iccarm-cpu.cmake new file mode 100644 index 00000000000..70eee9240b6 --- /dev/null +++ b/cmake/compiler/iar/iccarm-cpu.cmake @@ -0,0 +1,89 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +# Determines what argument to give to --cpu= based on the +# KConfig'uration and sets this to ICCARM_CPU + +if("${ARCH}" STREQUAL "arm") + if(CONFIG_CPU_CORTEX_M0) + set(ICCARM_CPU Cortex-M0) + elseif(CONFIG_CPU_CORTEX_M0PLUS) + set(ICCARM_CPU Cortex-M0+) + elseif(CONFIG_CPU_CORTEX_M1) + set(ICCARM_CPU Cortex-M1) + elseif(CONFIG_CPU_CORTEX_M3) + set(ICCARM_CPU Cortex-M3) + elseif(CONFIG_CPU_CORTEX_M4) + set(ICCARM_CPU Cortex-M4) + elseif(CONFIG_CPU_CORTEX_M7) + set(ICCARM_CPU Cortex-M7) + elseif(CONFIG_CPU_CORTEX_M23) + set(ICCARM_CPU Cortex-M23) + elseif(CONFIG_CPU_CORTEX_M33) + if(CONFIG_ARMV8_M_DSP) + set(ICCARM_CPU Cortex-M33) + else() + set(ICCARM_CPU Cortex-M33.no_dsp) + endif() + elseif(CONFIG_CPU_CORTEX_M55) + if(CONFIG_ARMV8_1_M_MVEF) + set(ICCARM_CPU Cortex-M55) + elseif(CONFIG_ARMV8_1_M_MVEI) + set(ICCARM_CPU Cortex-M55.no_mve) + elseif(CONFIG_ARMV8_M_DSP) + set(ICCARM_CPU Cortex-M55.no_mve) + else() + set(ICCARM_CPU Cortex-M55.no_dsp) + endif() + elseif(CONFIG_CPU_CORTEX_R4) + if(CONFIG_FPU AND CONFIG_CPU_HAS_VFP) + set(ICCARM_CPU Cortex-R4F) + else() + set(ICCARM_CPU Cortex-R4) + endif() + elseif(CONFIG_CPU_CORTEX_R5) + set(ICCARM_CPU Cortex-R5) + if(CONFIG_FPU AND CONFIG_CPU_HAS_VFP) + if(NOT CONFIG_VFP_FEATURE_DOUBLE_PRECISION) + set(ICCARM_CPU ${ICCARM_CPU}+fp.sp) + endif() + else() + set(ICCARM_CPU ${ICCARM_CPU}+fp.dp) + endif() + elseif(CONFIG_CPU_CORTEX_R7) + set(ICCARM_CPU Cortex-R7) + if(CONFIG_FPU AND CONFIG_CPU_HAS_VFP) + if(NOT CONFIG_VFP_FEATURE_DOUBLE_PRECISION) + set(ICCARM_CPU ${ICCARM_CPU}+fp.sp) + endif() + else() + set(ICCARM_CPU ${ICCARM_CPU}+fp.dp) + endif() + elseif(CONFIG_CPU_CORTEX_R52) + set(ICCARM_CPU Cortex-R52) + if(CONFIG_FPU AND CONFIG_CPU_HAS_VFP) + if(NOT CONFIG_VFP_FEATURE_DOUBLE_PRECISION) + set(ICCARM_CPU ${ICCARM_CPU}+fp.sp) + endif() + endif() + elseif(CONFIG_CPU_CORTEX_A9) + set(ICCARM_CPU Cortex-A9) + else() + message(FATAL_ERROR "Expected CONFIG_CPU_CORTEX_x to be defined") + endif() +elseif("${ARCH}" STREQUAL "arm64") + if(CONFIG_CPU_CORTEX_A53) + set(ICCARM_CPU Cortex-A53) + elseif(CONFIG_CPU_CORTEX_A55) + set(ICCARM_CPU Cortex-A55) + elseif(CONFIG_CPU_CORTEX_A76) + set(ICCARM_CPU cortex-a76) + elseif(CONFIG_CPU_CORTEX_A76_A55) + set(ICCARM_CPU cortex-a76) + elseif(CONFIG_CPU_CORTEX_A72) + set(ICCARM_CPU Cortex-A72) + elseif(CONFIG_CPU_CORTEX_R82) + set(ICCARM_CPU Cortex-R82) + endif() +endif() diff --git a/cmake/compiler/iar/iccarm-fpu.cmake b/cmake/compiler/iar/iccarm-fpu.cmake new file mode 100644 index 00000000000..2435d77254b --- /dev/null +++ b/cmake/compiler/iar/iccarm-fpu.cmake @@ -0,0 +1,53 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +# Determines what argument to give to --fpu= based on the +# KConfiguration and sets this to ICCARM_FPU + +if(CONFIG_FPU) + + # 32-bit + if("${ARCH}" STREQUAL "arm") + if(CONFIG_CPU_AARCH32_CORTEX_R) + if(CONFIG_CPU_CORTEX_R4 OR CONFIG_CPU_CORTEX_R5) # VFPv3 + if(CONFIG_VFP_FEATURE_DOUBLE_PRECISION) + set(ICCARM_FPU VFPv3_D16) + elseif(CONFIG_VFP_FEATURE_SINGLE_PRECISION) + set(ICCARM_FPU VFPv3-SP) + endif() + if(CONFIG_VFP_FEATURE_HALF_PRECISION) + set(ICCARM_FPU ${ICCARM_FPU}_Fp16) + endif() + elseif(CONFIG_CPU_CORTEX_R52) + if(CONFIG_VFP_FEATURE_DOUBLE_PRECISION) + set(ICCARM_FPU VFPv5_D16) + elseif(CONFIG_VFP_FEATURE_SINGLE_PRECISION) + set(ICCARM_FPU VFPv5-SP) + endif() + endif() + elseif(CONFIG_CPU_CORTEX_M) + # Defines a mapping from ICCARM_CPU to FPU + if(CONFIG_CPU_HAS_FPU_DOUBLE_PRECISION) + set(PRECISION_TOKEN _D16) + else() + set(PRECISION_TOKEN -SP) + endif() + + set(FPU_FOR_Cortex-M4 FPv4${PRECISION_TOKEN}) + set(FPU_FOR_Cortex-M7 FPv5${PRECISION_TOKEN}) + set(FPU_FOR_Cortex-M33 FPv5${PRECISION_TOKEN}) + set(FPU_FOR_Cortex-M33.no_dsp FPv5${PRECISION_TOKEN}) + set(FPU_FOR_Cortex-M55 auto) + set(FPU_FOR_Cortex-M55.no_mve auto) + # We don't have this one? + set(FPU_FOR_Cortex-M55.no_dsp auto) + + set(ICCARM_FPU ${FPU_FOR_${ICCARM_CPU}}) + endif() + # 64-bit + else() + set(ICCARM_FPU none) + endif() + +endif() #CONFIG_FPU diff --git a/cmake/compiler/iar/target.cmake b/cmake/compiler/iar/target.cmake new file mode 100644 index 00000000000..94422739e16 --- /dev/null +++ b/cmake/compiler/iar/target.cmake @@ -0,0 +1,146 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +# Avoids running the linker during try_compile() +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +set(NO_BUILD_TYPE_WARNING 1) +set(CMAKE_NOT_USING_CONFIG_FLAGS 1) + +find_program(CMAKE_C_COMPILER + NAMES ${IAR_COMPILER} + PATHS ${TOOLCHAIN_HOME} + PATH_SUFFIXES bin + NO_DEFAULT_PATH + REQUIRED ) + +message(STATUS "Found C Compiler ${CMAKE_C_COMPILER}") + +find_program(CMAKE_CXX_COMPILER + NAMES ${IAR_COMPILER} + PATHS ${TOOLCHAIN_HOME} + PATH_SUFFIXES bin + NO_DEFAULT_PATH + REQUIRED ) + +find_program(CMAKE_AR + NAMES iarchive + PATHS ${TOOLCHAIN_HOME} + PATH_SUFFIXES bin + NO_DEFAULT_PATH + REQUIRED ) + +set(CMAKE_ASM_COMPILER) +if("${IAR_TOOLCHAIN_VARIANT}" STREQUAL "iccarm") + find_program(CMAKE_ASM_COMPILER + arm-zephyr-eabi-gcc + PATHS ${ZEPHYR_SDK_INSTALL_DIR}/arm-zephyr-eabi/bin + NO_DEFAULT_PATH ) +else() + find_program(CMAKE_ASM_COMPILER + riscv64-zephyr-elf-gcc + PATHS ${ZEPHYR_SDK_INSTALL_DIR}/riscv64-zephyr-elf/bin + NO_DEFAULT_PATH ) +endif() + +message(STATUS "Found assembler ${CMAKE_ASM_COMPILER}") + +set(ICC_BASE ${ZEPHYR_BASE}/cmake/compiler/iar) + + +if("${IAR_TOOLCHAIN_VARIANT}" STREQUAL "iccarm") + # Used for settings correct cpu/fpu option for gnu assembler + include(${ZEPHYR_BASE}/cmake/gcc-m-cpu.cmake) + include(${ZEPHYR_BASE}/cmake/gcc-m-fpu.cmake) + + # Map KConfig option to icc cpu/fpu + include(${ICC_BASE}/iccarm-cpu.cmake) + include(${ICC_BASE}/iccarm-fpu.cmake) +endif() + +set(IAR_COMMON_FLAGS) +# Minimal C compiler flags + +list(APPEND IAR_COMMON_FLAGS + "SHELL: --preinclude" + "${ZEPHYR_BASE}/include/zephyr/toolchain/iar/iar_missing_defs.h" + # Enable both IAR and GNU extensions + -e + --language gnu + --do_explicit_init_in_named_sections + --macro_positions_in_diagnostics + --no_wrap_diagnostics +) + +if("${IAR_TOOLCHAIN_VARIANT}" STREQUAL "iccarm") + list(APPEND IAR_COMMON_FLAGS + --endian=little + --cpu=${ICCARM_CPU} + -DRTT_USE_ASM=0 #WA for VAAK-232 + --diag_suppress=Ta184 # Using zero sized arrays except for as last member of a struct is discouraged and dereferencing elements in such an array has undefined behavior + ) +endif() + +# Minimal ASM compiler flags +if("${IAR_TOOLCHAIN_VARIANT}" STREQUAL "iccarm") + list(APPEND IAR_ASM_FLAGS + -mcpu=${GCC_M_CPU} + -mabi=aapcs + -DRTT_USE_ASM=0 #WA for VAAK-232 + ) +endif() + +if(CONFIG_DEBUG) + # GCC defaults to Dwarf 5 output + list(APPEND IAR_ASM_FLAGS -gdwarf-4) +endif() + +if(DEFINED CONFIG_ARM_SECURE_FIRMWARE) + list(APPEND IAR_COMMON_FLAGS --cmse) + list(APPEND IAR_ASM_FLAGS -mcmse) +endif() + +# 64-bit +if("${IAR_TOOLCHAIN_VARIANT}" STREQUAL "iccarm") + if(CONFIG_ARM64) + list(APPEND IAR_COMMON_FLAGS --abi=lp64) + list(APPEND TOOLCHAIN_LD_FLAGS --abi=lp64) + # 32-bit + else() + list(APPEND IAR_COMMON_FLAGS --aeabi) + if(CONFIG_COMPILER_ISA_THUMB2) + list(APPEND IAR_COMMON_FLAGS --thumb) + list(APPEND IAR_ASM_FLAGS -mthumb) + endif() + + if(CONFIG_FPU) + list(APPEND IAR_COMMON_FLAGS --fpu=${ICCARM_FPU}) + list(APPEND IAR_ASM_FLAGS -mfpu=${GCC_M_FPU}) + endif() + endif() +endif() + +if("${IAR_TOOLCHAIN_VARIANT}" STREQUAL "iccarm") + if(CONFIG_IAR_LIBC) + # Zephyr requires AEABI portability to ensure correct functioning of the C + # library, for example error numbers, errno.h. + list(APPEND IAR_COMMON_FLAGS -D__AEABI_PORTABILITY_LEVEL=1) + endif() +endif() + +if(CONFIG_IAR_LIBC) + message(STATUS "IAR C library used") + # Zephyr uses the type FILE for normal LIBC while IAR + # only has it for full LIBC support, so always choose + # full libc when using IAR C libraries. + list(APPEND IAR_COMMON_FLAGS --dlib_config full) +endif() + +foreach(F ${IAR_COMMON_FLAGS}) + list(APPEND TOOLCHAIN_C_FLAGS $<$:${F}>) + list(APPEND TOOLCHAIN_C_FLAGS $<$:${F}>) +endforeach() + +foreach(F ${IAR_ASM_FLAGS}) + list(APPEND TOOLCHAIN_C_FLAGS $<$:${F}>) +endforeach() diff --git a/cmake/linker/iar/config_file_script.cmake b/cmake/linker/iar/config_file_script.cmake new file mode 100644 index 00000000000..be11bbac8a3 --- /dev/null +++ b/cmake/linker/iar/config_file_script.cmake @@ -0,0 +1,922 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.17) + +set(SORT_TYPE_NAME Lexical) + +set_property(GLOBAL PROPERTY ILINK_REGION_SYMBOL_ICF) + +# This function post process the region for easier use. +# +# Tasks: +# - Symbol translation using a steering file is configured. +function(process_region) + cmake_parse_arguments(REGION "" "OBJECT" "" ${ARGN}) + + process_region_common(${ARGN}) + + get_property(empty GLOBAL PROPERTY ${REGION_OBJECT}_EMPTY) + if(NOT empty) + # For scatter files we move any system symbols into first non-empty load section. + get_parent(OBJECT ${REGION_OBJECT} PARENT parent TYPE SYSTEM) + get_property(symbols GLOBAL PROPERTY ${parent}_SYMBOLS) + set_property(GLOBAL APPEND PROPERTY ${REGION_OBJECT}_SYMBOLS ${symbols}) + set_property(GLOBAL PROPERTY ${parent}_SYMBOLS) + endif() + + get_property(sections GLOBAL PROPERTY ${REGION_OBJECT}_SECTION_LIST_ORDERED) + foreach(section ${sections}) + + get_property(name GLOBAL PROPERTY ${section}_NAME) + get_property(name_clean GLOBAL PROPERTY ${section}_NAME_CLEAN) + get_property(noinput GLOBAL PROPERTY ${section}_NOINPUT) + get_property(type GLOBAL PROPERTY ${section}_TYPE) + get_property(nosymbols GLOBAL PROPERTY ${section}_NOSYMBOLS) + + if(NOT nosymbols) + if(${name} STREQUAL .ramfunc) + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name_clean}_load_start + EXPR "@ADDR(.ramfunc_init)@" + ) + else() + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name_clean}_load_start + EXPR "@LOADADDR(${name_clean})@" + ) + endif() + endif() + + get_property(indicies GLOBAL PROPERTY ${section}_SETTINGS_INDICIES) + list(LENGTH indicies length) + foreach(idx ${indicies}) + set(steering_postfixes Base Limit) + get_property(symbols GLOBAL PROPERTY ${section}_SETTING_${idx}_SYMBOLS) + get_property(sort GLOBAL PROPERTY ${section}_SETTING_${idx}_SORT) + get_property(offset GLOBAL PROPERTY ${section}_SETTING_${idx}_OFFSET) + if(DEFINED offset AND NOT offset EQUAL 0 ) + # Same behavior as in section_to_string + elseif(DEFINED offset AND offset STREQUAL 0 ) + # Same behavior as in section_to_string + elseif(sort) + # Treated by labels in the icf or image symbols. + elseif(DEFINED symbols AND ${length} EQUAL 1 AND noinput) + endif() + endforeach() + + # Symbols translation here. + + get_property(symbol_val GLOBAL PROPERTY SYMBOL_TABLE___${name_clean}_end) + + if("${symbol_val}" STREQUAL "${name_clean}") + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name_clean}_size + EXPR "@SIZE(${name_clean})@" + ) + else() + # These seem to be thing that can't be transformed to $$Length + set_property(GLOBAL APPEND PROPERTY ILINK_REGION_SYMBOL_ICF + "define image symbol __${name_clean}_size = (__${symbol_val} - ADDR(${name_clean}))") + endif() + set(ZI) + + if(${name_clean} STREQUAL last_ram_section) + # A trick to add the symbol for the nxp devices + # _flash_used = LOADADDR(.last_section) + SIZEOF(.last_section) - __rom_region_start; + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL _flash_used + EXPR "(@LOADADDR(last_section)@ + @SIZE(last_section)@ - @__rom_region_start@)" + ) + endif() + + if(${name_clean} STREQUAL rom_start) + # The below two symbols is meant to make aliases to the _vector_table symbol. + list(GET symbols 0 symbol_start) + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __Vectors + EXPR "@ADDR(${symbol_start})@" + ) + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __vector_table + EXPR "@ADDR(${symbol_start})@" + ) + endif() + + endforeach() + + get_property(groups GLOBAL PROPERTY ${REGION_OBJECT}_GROUP_LIST_ORDERED) + foreach(group ${groups}) + get_property(name GLOBAL PROPERTY ${group}_NAME) + string(TOLOWER ${name} name) + + get_property(group_type GLOBAL PROPERTY ${group}_OBJ_TYPE) + get_property(parent GLOBAL PROPERTY ${group}_PARENT) + get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE) + # Need to find the init manually group or parent + if(${parent_type} STREQUAL GROUP) + get_property(vma GLOBAL PROPERTY ${parent}_VMA) + get_property(lma GLOBAL PROPERTY ${parent}_LMA) + else() + get_property(vma GLOBAL PROPERTY ${group}_VMA) + get_property(lma GLOBAL PROPERTY ${group}_LMA) + endif() + + get_objects(LIST sections OBJECT ${group} TYPE SECTION) + list(GET sections 0 section) + get_property(first_section_name GLOBAL PROPERTY ${section}_NAME_CLEAN) + list(POP_BACK sections section) + get_property(last_section_name GLOBAL PROPERTY ${section}_NAME_CLEAN) + + if(DEFINED vma AND DEFINED lma) + # Something to init + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name}_load_start + EXPR "@ADDR(${first_section_name}_init)@" + ) + else() + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name}_load_start + EXPR "@LOADADDR(${first_section_name})@" + ) + endif() + + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name}_start + EXPR "@ADDR(${first_section_name})@" + ) + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name}_end + EXPR "@END(${last_section_name})@" + ) + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name}_size + EXPR "(@(__${name}_end)@ - @(__${name}_start)@)" + ) + + endforeach() + + get_property(symbols GLOBAL PROPERTY ${REGION_OBJECT}_SYMBOLS) + foreach(symbol ${symbols}) + get_property(name GLOBAL PROPERTY ${symbol}_NAME) + get_property(expr GLOBAL PROPERTY ${symbol}_EXPR) + if(NOT DEFINED expr) + create_symbol(OBJECT ${REGION_OBJECT} SYMBOL __${name}_size + EXPR "@(ADDR(${name})@" + ) + endif() + endforeach() + + # This is only a trick to get the memories + set(groups) + get_objects(LIST groups OBJECT ${REGION_OBJECT} TYPE GROUP) + foreach(group ${groups}) + get_property(group_type GLOBAL PROPERTY ${group}_OBJ_TYPE) + get_property(parent GLOBAL PROPERTY ${group}_PARENT) + get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE) + + if(${group_type} STREQUAL GROUP) + get_property(group_name GLOBAL PROPERTY ${group}_NAME) + get_property(group_lma GLOBAL PROPERTY ${group}_LMA) + if(${group_name} STREQUAL ROM_REGION) + set_property(GLOBAL PROPERTY ILINK_ROM_REGION_NAME ${group_lma}) + endif() + endif() + + if(${parent_type} STREQUAL GROUP) + get_property(vma GLOBAL PROPERTY ${parent}_VMA) + get_property(lma GLOBAL PROPERTY ${parent}_LMA) + + set_property(GLOBAL PROPERTY ${group}_VMA ${vma}) + set_property(GLOBAL PROPERTY ${group}_LMA ${lma}) + endif() + endforeach() + +endfunction() + +# +# String functions - start +# + +function(system_to_string) + cmake_parse_arguments(STRING "" "OBJECT;STRING" "" ${ARGN}) + + get_property(name GLOBAL PROPERTY ${STRING_OBJECT}_NAME) + get_property(regions GLOBAL PROPERTY ${STRING_OBJECT}_REGIONS) + get_property(format GLOBAL PROPERTY ${STRING_OBJECT}_FORMAT) + + # Ilink specials + # set(${STRING_STRING} "build for rom;\n") + set(${STRING_STRING} "build for ram;\n") + if("${format}" MATCHES "aarch64") + set(${STRING_STRING} "${${STRING_STRING}}define memory mem with size = 16E;\n") + else() + set(${STRING_STRING} "${${STRING_STRING}}define memory mem with size = 4G;\n") + endif() + + foreach(region ${regions}) + get_property(name GLOBAL PROPERTY ${region}_NAME) + get_property(address GLOBAL PROPERTY ${region}_ADDRESS) + get_property(flags GLOBAL PROPERTY ${region}_FLAGS) + get_property(size GLOBAL PROPERTY ${region}_SIZE) + + if(DEFINED flags) + if(${flags} STREQUAL rx) + set(flags " rom") + elseif(${flags} STREQUAL ro) + set(flags " rom") + elseif(${flags} STREQUAL wx) + set(flags " ram") + elseif(${flags} STREQUAL rw) + set(flags " ram") + endif() + endif() + + if(${name} STREQUAL IDT_LIST) + # Need to use a untyped region for IDT_LIST + set(flags "") + endif() + + if(DEFINED address) + set(start "${address}") + endif() + + if(DEFINED size) + set(size "${size}") + endif() + # define rom region FLASH = mem:[from 0x0 size 0x40000]; + set(memory_region "define${flags} region ${name} = mem:[from ${start} size ${size}];") + + set(${STRING_STRING} "${${STRING_STRING}}${memory_region}\n") + set(flags) + endforeach() + + set(${STRING_STRING} "${${STRING_STRING}}\n\n") + set_property(GLOBAL PROPERTY ILINK_SYMBOL_ICF) + + set(${STRING_STRING} "${${STRING_STRING}}\n") + foreach(region ${regions}) + get_property(empty GLOBAL PROPERTY ${region}_EMPTY) + if(NOT empty) + get_property(name GLOBAL PROPERTY ${region}_NAME) + set(ILINK_CURRENT_NAME ${name}) + to_string(OBJECT ${region} STRING ${STRING_STRING}) + set(ILINK_CURRENT_NAME) + endif() + endforeach() + set(${STRING_STRING} "${${STRING_STRING}}\n") + + get_property(symbols_icf GLOBAL PROPERTY ILINK_SYMBOL_ICF) + foreach(image_symbol ${symbols_icf}) + set(${STRING_STRING} "${${STRING_STRING}}define image symbol ${image_symbol};\n") + endforeach() + + get_property(symbols_icf GLOBAL PROPERTY ILINK_REGION_SYMBOL_ICF) + set(${STRING_STRING} "${${STRING_STRING}}\n") + foreach(image_symbol ${symbols_icf}) + set(${STRING_STRING} "${${STRING_STRING}}${image_symbol};\n") + endforeach() + + if(IAR_LIBC) + set(${STRING_STRING} "${${STRING_STRING}}if (K_HEAP_MEM_POOL_SIZE>0)\n{\n") + set(${STRING_STRING} "${${STRING_STRING}} define block HEAP with alignment=8 { symbol kheap__system_heap };\n") + set(${STRING_STRING} "${${STRING_STRING}}}\nelse\n{\n") + set(${STRING_STRING} "${${STRING_STRING}} define block HEAP with alignment=8, expanding size { };\n") + set(${STRING_STRING} "${${STRING_STRING}}}\n") + set(${STRING_STRING} "${${STRING_STRING}}\"DLib heap\": place in RAM { block HEAP };\n") +# set(${STRING_STRING} "${${STRING_STRING}}define exported symbol HEAP$$Base=kheap__system_heap;\n") +# set(${STRING_STRING} "${${STRING_STRING}}define exported symbol HEAP$$Limit=END(kheap__system_heap);\n") + endif() + + set(${STRING_STRING} ${${STRING_STRING}} PARENT_SCOPE) +endfunction() + +function(group_to_string) + cmake_parse_arguments(STRING "" "OBJECT;STRING" "" ${ARGN}) + + get_property(type GLOBAL PROPERTY ${STRING_OBJECT}_OBJ_TYPE) + if(${type} STREQUAL REGION) + get_property(name GLOBAL PROPERTY ${STRING_OBJECT}_NAME) + get_property(address GLOBAL PROPERTY ${STRING_OBJECT}_ADDRESS) + get_property(size GLOBAL PROPERTY ${STRING_OBJECT}_SIZE) + + get_property(empty GLOBAL PROPERTY ${STRING_OBJECT}_EMPTY) + if(empty) + return() + endif() + + else() + get_property(else_name GLOBAL PROPERTY ${STRING_OBJECT}_NAME) + get_property(else_symbol GLOBAL PROPERTY ${STRING_OBJECT}_SYMBOL) + string(TOLOWER ${else_name} else_name) + + get_objects(LIST sections OBJECT ${STRING_OBJECT} TYPE SECTION) + list(GET sections 0 section) + get_property(first_section_name GLOBAL PROPERTY ${section}_NAME) + + endif() + + if(${type} STREQUAL GROUP) + get_property(group_name GLOBAL PROPERTY ${STRING_OBJECT}_NAME) + get_property(group_address GLOBAL PROPERTY ${STRING_OBJECT}_ADDRESS) + get_property(group_vma GLOBAL PROPERTY ${STRING_OBJECT}_VMA) + get_property(group_lma GLOBAL PROPERTY ${STRING_OBJECT}_LMA) + endif() + + get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS_FIXED) + foreach(section ${sections}) + to_string(OBJECT ${section} STRING ${STRING_STRING}) + get_property(name GLOBAL PROPERTY ${section}_NAME) + get_property(name_clean GLOBAL PROPERTY ${section}_NAME_CLEAN) + set(${STRING_STRING} "${${STRING_STRING}}\"${name}\": place at address mem:${address} { block ${name_clean} };\n") + endforeach() + + get_property(groups GLOBAL PROPERTY ${STRING_OBJECT}_GROUPS) + foreach(group ${groups}) + to_string(OBJECT ${group} STRING ${STRING_STRING}) + endforeach() + + get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_SECTIONS) + foreach(section ${sections}) + to_string(OBJECT ${section} STRING ${STRING_STRING}) + + get_property(name GLOBAL PROPERTY ${section}_NAME) + + get_property(name_clean GLOBAL PROPERTY ${section}_NAME_CLEAN) + + get_property(parent GLOBAL PROPERTY ${section}_PARENT) + # This is only a trick to get the memories + get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE) + if(${parent_type} STREQUAL GROUP) + get_property(vma GLOBAL PROPERTY ${parent}_VMA) + get_property(lma GLOBAL PROPERTY ${parent}_LMA) + endif() + + if(DEFINED vma) + set(ILINK_CURRENT_NAME ${vma}) + elseif(DEFINED lma) + set(ILINK_CURRENT_NAME ${lma}) + else() + # message(FATAL_ERROR "Need either vma or lma") + endif() + + set(${STRING_STRING} "${${STRING_STRING}}\"${name}\": place in ${ILINK_CURRENT_NAME} { block ${name_clean} };\n") + if(DEFINED vma AND DEFINED lma) + set(${STRING_STRING} "${${STRING_STRING}}\"${name}_init\": place in ${lma} { block ${name_clean}_init };\n") + endif() + + endforeach() + + get_parent(OBJECT ${STRING_OBJECT} PARENT parent TYPE SYSTEM) + get_property(regions GLOBAL PROPERTY ${parent}_REGIONS) + list(REMOVE_ITEM regions ${STRING_OBJECT}) + + foreach(region ${regions}) + get_property(vma GLOBAL PROPERTY ${region}_NAME) + get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_SECTIONS_FIXED) + + foreach(section ${sections}) + to_string(OBJECT ${section} STRING ${STRING_STRING}) + endforeach() + + get_property(groups GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_GROUPS) + foreach(group ${groups}) + to_string(OBJECT ${group} STRING ${STRING_STRING}) + endforeach() + + get_property(sections GLOBAL PROPERTY ${STRING_OBJECT}_${vma}_SECTIONS) + foreach(section ${sections}) + to_string(OBJECT ${section} STRING ${STRING_STRING}) + get_property(name GLOBAL PROPERTY ${section}_NAME) + string(REGEX REPLACE "^[\.]" "" name_clean "${name}") + string(REPLACE "." "_" name_clean "${name_clean}") + set(${STRING_STRING} "${${STRING_STRING}}\"${name}\": place in ${vma} { block ${name_clean} };\n") + + # Insert 'do not initialize' here + get_property(current_sections GLOBAL PROPERTY ILINK_CURRENT_SECTIONS) + if(${name} STREQUAL .bss) + if(DEFINED current_sections) + set(${STRING_STRING} "${${STRING_STRING}}do not initialize\n") + set(${STRING_STRING} "${${STRING_STRING}}{\n") + foreach(section ${current_sections}) + set(${STRING_STRING} "${${STRING_STRING}} ${section},\n") + endforeach() + set(${STRING_STRING} "${${STRING_STRING}}};\n") + set(current_sections) + set_property(GLOBAL PROPERTY ILINK_CURRENT_SECTIONS) + endif() + endif() + + if(${name_clean} STREQUAL last_ram_section) + get_property(group_name_lma GLOBAL PROPERTY ILINK_ROM_REGION_NAME) + set(${STRING_STRING} "${${STRING_STRING}}\n") + if(${CONFIG_LINKER_LAST_SECTION_ID}) + set(${STRING_STRING} "${${STRING_STRING}}define section last_section_id { udata32 ${CONFIG_LINKER_LAST_SECTION_ID_PATTERN}; };\n") + set(${STRING_STRING} "${${STRING_STRING}}define block last_section with fixed order { section last_section_id };\n") + else() + set(${STRING_STRING} "${${STRING_STRING}}define block last_section with fixed order { };\n") + endif() + # Not really the right place, we want the last used flash bytes not end of the world! + # set(${STRING_STRING} "${${STRING_STRING}}\".last_section\": place at end of ${group_name_lma} { block last_section };\n") + set(${STRING_STRING} "${${STRING_STRING}}\".last_section\": place in ${group_name_lma} { block last_section };\n") + set(${STRING_STRING} "${${STRING_STRING}}keep { block last_section };\n") + endif() + + endforeach() + endforeach() + + get_property(symbols GLOBAL PROPERTY ${STRING_OBJECT}_SYMBOLS) + set(${STRING_STRING} "${${STRING_STRING}}\n") + foreach(symbol ${symbols}) + to_string(OBJECT ${symbol} STRING ${STRING_STRING}) + endforeach() + + set(${STRING_STRING} ${${STRING_STRING}} PARENT_SCOPE) +endfunction() + + +function(section_to_string) + cmake_parse_arguments(STRING "" "SECTION;STRING" "" ${ARGN}) + + get_property(name GLOBAL PROPERTY ${STRING_SECTION}_NAME) + get_property(address GLOBAL PROPERTY ${STRING_SECTION}_ADDRESS) + get_property(type GLOBAL PROPERTY ${STRING_SECTION}_TYPE) + get_property(align GLOBAL PROPERTY ${STRING_SECTION}_ALIGN) + get_property(subalign GLOBAL PROPERTY ${STRING_SECTION}_SUBALIGN) + get_property(endalign GLOBAL PROPERTY ${STRING_SECTION}_ENDALIGN) + get_property(vma GLOBAL PROPERTY ${STRING_SECTION}_VMA) + get_property(lma GLOBAL PROPERTY ${STRING_SECTION}_LMA) + get_property(noinput GLOBAL PROPERTY ${STRING_SECTION}_NOINPUT) + get_property(noinit GLOBAL PROPERTY ${STRING_SECTION}_NOINIT) + + get_property(nosymbols GLOBAL PROPERTY ${STRING_SECTION}_NOSYMBOLS) + get_property(start_syms GLOBAL PROPERTY ${STRING_SECTION}_START_SYMBOLS) + get_property(end_syms GLOBAL PROPERTY ${STRING_SECTION}_END_SYMBOLS) + + get_property(parent GLOBAL PROPERTY ${STRING_SECTION}_PARENT) + + get_property(parent_type GLOBAL PROPERTY ${parent}_OBJ_TYPE) + if(${parent_type} STREQUAL GROUP) + get_property(group_parent_vma GLOBAL PROPERTY ${parent}_VMA) + get_property(group_parent_lma GLOBAL PROPERTY ${parent}_LMA) + if(NOT DEFINED vma) + get_property(vma GLOBAL PROPERTY ${parent}_VMA) + endif() + if(NOT DEFINED lma) + get_property(lma GLOBAL PROPERTY ${parent}_LMA) + endif() + endif() + + if(DEFINED group_parent_vma AND DEFINED group_parent_lma) + # Something to init + set(part "rw ") + else() + set(part) + endif() + + + set_property(GLOBAL PROPERTY ILINK_CURRENT_SECTIONS) + + string(REGEX REPLACE "^[\.]" "" name_clean "${name}") + string(REPLACE "." "_" name_clean "${name_clean}") + + # WA for 'Error[Lc036]: no block or place matches the pattern "ro data section .tdata_init"' + if("${name_clean}" STREQUAL "tdata") + set(TEMP "${TEMP}define block ${name_clean}_init { ro section .tdata_init };\n") + set(TEMP "${TEMP}\"${name_clean}_init\": place in ${ILINK_CURRENT_NAME} { block ${name_clean}_init };\n\n") + endif() + + get_property(indicies GLOBAL PROPERTY ${STRING_SECTION}_SETTINGS_INDICIES) + # ZIP_LISTS partner + get_property(next_indicies GLOBAL PROPERTY ${STRING_SECTION}_SETTINGS_INDICIES) + list(POP_FRONT next_indicies first_index) + + set(first_index_section) + set(first_index_section_name) + if(DEFINED first_index) + # Handle case where the first section has an offset + get_property(first_index_offset + GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${first_index}_OFFSET) + get_property(keep GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${first_index}_KEEP) + if(DEFINED keep) + set(root "root ") + else() + set(root) + endif() + if(DEFINED first_index_offset AND NOT first_index_offset EQUAL 0 ) + set(first_index_section_name "${name_clean}_${first_index}_offset") + set(first_index_section + "define ${root}section ${first_index_section_name} {};") + else() + set(first_index) + endif() + endif() + + foreach(start_symbol ${start_syms}) + set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "${start_symbol} = ADDR(${name_clean})") + endforeach() + foreach(end_symbol ${end_syms}) + set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "${end_symbol} = END(${name_clean})") + endforeach() + + if(NOT nosymbols) + if("${name_clean}" STREQUAL "tdata") + set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "__${name_clean}_start = (__iar_tls$$INIT_DATA$$Base)") + set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "__${name_clean}_end = (__iar_tls$$INIT_DATA$$Limit)") + else() + set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "__${name_clean}_start = ADDR(${name_clean})") + set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "__${name_clean}_end = END(${name_clean})") + endif() + endif() + + # Add keep to the sections that have 'KEEP:TRUE' + foreach(idx ${indicies}) + get_property(keep GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_KEEP) + get_property(input GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_INPUT) + foreach(setting ${input}) + if(keep) + # keep { section .abc* }; + set(TEMP "${TEMP}keep { section ${setting} };\n") + endif() + endforeach() + endforeach() + + if(DEFINED first_index_section) + set(TEMP "${TEMP}${first_index_section}\n") + endif() + + set(TEMP "${TEMP}define block ${name_clean} with fixed order") + + if(align) + set(TEMP "${TEMP}, alignment=${align}") + elseif(subalign) + set(TEMP "${TEMP}, alignment = ${subalign}") + elseif(part) + set(TEMP "${TEMP}, alignment = input") + else() + set(TEMP "${TEMP}, alignment=4") + endif() + if(endalign) + set(TEMP "${TEMP}, end alignment=${endalign}") + endif() + + set(TEMP "${TEMP}\n{") + + # foreach(start_symbol ${start_syms}) + # set(TEMP "${TEMP}\n section ${start_symbol},") + # set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${start_symbol}") + # endforeach() + + # if(NOT nosymbols) + # set(TEMP "${TEMP}\n section __${name_clean}_start,") + # set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section __${name_clean}_start") + # endif() + + list(GET indicies -1 last_index) + list(LENGTH indicies length) + + if(NOT noinput) + + set(TEMP "${TEMP}\n block ${name_clean}_winput") + if(align) + list(APPEND block_attr "alignment = ${align}") + elseif(subalign) + list(APPEND block_attr "alignment = ${subalign}") + elseif(part) + # list(APPEND block_attr "alignment = input") + else() + list(APPEND block_attr "alignment=4") + endif() + list(APPEND block_attr "fixed order") + + list(JOIN block_attr ", " block_attr_str) + if(block_attr_str) + set(TEMP "${TEMP} with ${block_attr_str}") + endif() + set(block_attr) + set(block_attr_str) + + set(TEMP "${TEMP} { ${part}section ${name}, ${part}section ${name}.* }") + if(${length} GREATER 0) + set(TEMP "${TEMP},") + endif() + set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${name}") + set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${name}.*") + endif() + + foreach(idx idx_next IN ZIP_LISTS indicies next_indicies) + get_property(align GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_ALIGN) + get_property(any GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_ANY) + get_property(first GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_FIRST) + get_property(keep GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_KEEP) + get_property(sort GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_SORT) + get_property(flags GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_FLAGS) + get_property(input GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_INPUT) + get_property(symbols GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx}_SYMBOLS) + # Get the next offset and use that as this ones size! + get_property(offset GLOBAL PROPERTY ${STRING_SECTION}_SETTING_${idx_next}_OFFSET) + + if(DEFINED symbols) + list(LENGTH symbols symbols_count) + if(${symbols_count} GREATER 0) + list(GET symbols 0 symbol_start) + endif() + if(${symbols_count} GREATER 1) + list(GET symbols 1 symbol_end) + endif() + endif() + + if(DEFINED symbol_start) + # set(TEMP "${TEMP}\n section ${symbol_start},") + # set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${symbol_start}") + set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "${symbol_start} = ADDR(${name_clean}_${idx})") + endif() + + if(DEFINED first_index AND first_index EQUAL ${idx}) + # Create the offset + set(TEMP "${TEMP}\n block ${first_index_section_name}") + list(APPEND block_attr "size = ${first_index_offset}") + if(sort) + if(${sort} STREQUAL NAME) + list(APPEND block_attr "alphabetical order") + endif() + endif() + if(align) + list(APPEND block_attr "alignment = ${align}") + elseif(subalign) + list(APPEND block_attr "alignment = ${subalign}") + elseif(part) + # list(APPEND block_attr "alignment = input") + else() + list(APPEND block_attr "alignment=4") + endif() + list(APPEND block_attr "fixed order") + + list(JOIN block_attr ", " block_attr_str) + if(block_attr_str) + set(TEMP "${TEMP} with ${block_attr_str}") + endif() + set(block_attr) + set(block_attr_str) + + set(TEMP "${TEMP} { section ${first_index_section_name} },\n") + endif() + + # block init_100 with alphabetical order { section .z_init_EARLY?_} + set(TEMP "${TEMP}\n block ${name_clean}_${idx}") + if(DEFINED offset AND NOT offset EQUAL 0 ) + list(APPEND block_attr "size = ${offset}") + elseif(DEFINED offset AND offset STREQUAL 0 ) + # Do nothing + endif() + if(sort) + if(${sort} STREQUAL NAME) + list(APPEND block_attr "alphabetical order") + endif() + endif() + if(align) + list(APPEND block_attr "alignment = ${align}") + elseif(subalign) + list(APPEND block_attr "alignment = ${subalign}") + elseif(part) + # list(APPEND block_attr "alignment = input") + else() + list(APPEND block_attr "alignment=4") + endif() + + # LD + # There are two ways to include more than one section: + # + # *(.text .rdata) + # *(.text) *(.rdata) + # + # The difference between these is the order in which + # the `.text' and `.rdata' input sections will appear in the output section. + # In the first example, they will be intermingled, + # appearing in the same order as they are found in the linker input. + # In the second example, all `.text' input sections will appear first, + # followed by all `.rdata' input sections. + # + # ILINK solved by adding 'fixed order' + if(NOT sort AND NOT first) + list(APPEND block_attr "fixed order") + endif() + + list(JOIN block_attr ", " block_attr_str) + if(block_attr_str) + set(TEMP "${TEMP} with ${block_attr_str}") + endif() + set(block_attr) + set(block_attr_str) + + if(empty) + set(TEMP "${TEMP}\n {") + set(empty FALSE) + endif() + + list(GET input -1 last_input) + + set(TEMP "${TEMP} {") + if(NOT DEFINED input AND NOT any) + set(TEMP "${TEMP} }") + endif() + + foreach(setting ${input}) + if(first) + set(TEMP "${TEMP} first") + set(first "") + endif() + + set(section_type "") + + # build for ram, no section_type + # if("${lma}" STREQUAL "${vma}") + # # if("${vma}" STREQUAL "") + # set(section_type "") + # # else() + # # set(section_type " readwrite") + # # endif() + # elseif(NOT "${vma}" STREQUAL "") + # set(section_type " readwrite") + # elseif(NOT "${lma}" STREQUAL "") + # set(section_type " readonly") + # else() + # message(FATAL_ERROR "How to handle this? lma=${lma} vma=${vma}") + # endif() + + set(TEMP "${TEMP}${section_type} ${part}section ${setting}") + set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${setting}") + set(section_type "") + + if("${setting}" STREQUAL "${last_input}") + set(TEMP "${TEMP} }") + else() + set(TEMP "${TEMP}, ") + endif() + + # set(TEMP "${TEMP}\n *.o(${setting})") + endforeach() + + if(any) + if(NOT flags) + message(FATAL_ERROR ".ANY requires flags to be set.") + endif() + set(ANY_FLAG "") + foreach(flag ${flags}) + # if("${flag}" STREQUAL +RO OR "${flag}" STREQUAL +XO) + # set(ANY_FLAG "readonly") + # # elseif("${flag}" STREQUAL +RW) + # # set(ANY_FLAG "readwrite") + # else + if("${flag}" STREQUAL +ZI) + set(ANY_FLAG "zeroinit") + set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "${ANY_FLAG}") + endif() + endforeach() + set(TEMP "${TEMP} ${ANY_FLAG} }") + endif() + + if(DEFINED symbol_end) + # set(TEMP "${TEMP},\n section ${symbol_end}") + # set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${symbol_end}") + set_property(GLOBAL APPEND PROPERTY ILINK_SYMBOL_ICF "${symbol_end} = END(${name_clean}_${idx})") + endif() + if(${length} GREATER 0) + if(NOT "${idx}" STREQUAL "${last_index}") + set(TEMP "${TEMP},") + elseif() + endif() + endif() + + set(symbol_start) + set(symbol_end) + endforeach() + set(next_indicies) + + set(last_index) + set(last_input) + set(TEMP "${TEMP}") + + # if(NOT nosymbols) + # set(TEMP "${TEMP},\n section __${name_clean}_end") + # set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section __${name_clean}_end") + # endif() + + # foreach(end_symbol ${end_syms}) + # set(TEMP "${TEMP},\n section ${end_symbol}") + # set_property(GLOBAL APPEND PROPERTY ILINK_CURRENT_SECTIONS "section ${end_symbol}") + # endforeach() + + set(TEMP "${TEMP}\n};") + + get_property(type GLOBAL PROPERTY ${parent}_OBJ_TYPE) + if(${type} STREQUAL REGION) + get_property(name GLOBAL PROPERTY ${parent}_NAME) + get_property(address GLOBAL PROPERTY ${parent}_ADDRESS) + get_property(size GLOBAL PROPERTY ${parent}_SIZE) + + endif() + + get_property(current_sections GLOBAL PROPERTY ILINK_CURRENT_SECTIONS) + + if(DEFINED group_parent_vma AND DEFINED group_parent_lma) + if(DEFINED current_sections) + # "${TEMP}" is there too keep the ';' else it will be a list + string(REGEX REPLACE "(block[ \t\r\n]+)([^ \t\r\n]+)" "\\1\\2_init" INIT_TEMP "${TEMP}") + string(REGEX REPLACE "(rw)([ \t\r\n]+)(section[ \t\r\n]+)([^ \t\r\n,]+)" "\\1\\2\\3\\4_init" INIT_TEMP "${INIT_TEMP}") + string(REGEX REPLACE "(rw)([ \t\r\n]+)(section[ \t\r\n]+)" "ro\\2\\3" INIT_TEMP "${INIT_TEMP}") + string(REGEX REPLACE "alphabetical order, " "" INIT_TEMP "${INIT_TEMP}") + string(REGEX REPLACE "{ readwrite }" "{ }" INIT_TEMP "${INIT_TEMP}") + + set(TEMP "${TEMP}\n${INIT_TEMP}\n") + set(TEMP "${TEMP}\ninitialize manually with copy friendly\n") + set(TEMP "${TEMP}{\n") + foreach(section ${current_sections}) + set(TEMP "${TEMP} ${section},\n") + endforeach() + set(TEMP "${TEMP}};") + set(current_sections) + + endif() + endif() + + set(${STRING_STRING} "${${STRING_STRING}}\n${TEMP}\n" PARENT_SCOPE) +endfunction() + +function(symbol_to_string) + cmake_parse_arguments(STRING "" "SYMBOL;STRING" "" ${ARGN}) + + get_property(name GLOBAL PROPERTY ${STRING_SYMBOL}_NAME) + get_property(expr GLOBAL PROPERTY ${STRING_SYMBOL}_EXPR) + get_property(size GLOBAL PROPERTY ${STRING_SYMBOL}_SIZE) + get_property(symbol GLOBAL PROPERTY ${STRING_SYMBOL}_SYMBOL) + get_property(subalign GLOBAL PROPERTY ${STRING_SYMBOL}_SUBALIGN) + + string(REPLACE "\\" "" expr "${expr}") + string(REGEX MATCHALL "@([^@]*)@" match_res ${expr}) + + foreach(match ${match_res}) + string(REPLACE "@" "" match ${match}) + get_property(symbol_val GLOBAL PROPERTY SYMBOL_TABLE_${match}) + string(REPLACE "@${match}@" "${match}" expr ${expr}) + endforeach() + + list(LENGTH match_res match_res_count) + + if(match_res_count) + if(${match_res_count} GREATER 1) + set(${STRING_STRING} + "${${STRING_STRING}}define image symbol ${symbol} = ${expr};\n" + ) + else() + if((expr MATCHES "Base|Limit|Length") OR (expr MATCHES "ADDR\\(|END\\(|SIZE\\(")) + # Anything like $$Base/$$Limit/$$Length should be an image symbol + if( "${symbol}" STREQUAL "__tdata_size") + # This will handle the alignment of the TBSS block + set(${STRING_STRING} + "${${STRING_STRING}}define image symbol ${symbol}=(__iar_tls$$INIT_DATA$$Limit-__iar_tls$$INIT_DATA$$Base);\n" + ) + elseif( "${symbol}" STREQUAL "__tbss_size") + # This will handle the alignment of the TBSS block by + # pre-padding bytes + set(${STRING_STRING} + "${${STRING_STRING}}define image symbol ${symbol}=((tbss$$Limit-__iar_tls$$DATA$$Base)-(__iar_tls$$INIT_DATA$$Limit-__iar_tls$$INIT_DATA$$Base));\n" + ) + else() + set(${STRING_STRING} + "${${STRING_STRING}}define image symbol ${symbol} = ${expr};\n" + ) + endif() + else() + list(GET match_res 0 match) + string(REPLACE "@" "" match ${match}) + get_property(symbol_val GLOBAL PROPERTY SYMBOL_TABLE_${match}) + if(symbol_val) + set(${STRING_STRING} + "${${STRING_STRING}}define image symbol ${symbol} = ${expr};\n" + ) + else() + # Treatmen of "zephyr_linker_symbol(SYMBOL z_arm_platform_init EXPR "@SystemInit@")" + set_property(GLOBAL APPEND PROPERTY SYMBOL_STEERING_FILE + "--redirect ${symbol}=${expr}\n" + ) + endif() + endif() + endif() + else() + # Handle things like ADDR(.ramfunc) + if(${expr} MATCHES "^[A-Za-z]?ADDR\\(.+\\)") + # string(REGEX REPLACE "^[A-Za-z]?ADDR\\((.+)\\)" "(\\1$$Base)" expr ${expr}) + set(${STRING_STRING} + "${${STRING_STRING}}define image symbol ${symbol} = ${expr};\n" + ) + else() + set(${STRING_STRING} + "${${STRING_STRING}}define exported symbol ${symbol} = ${expr};\n" + ) + endif() + endif() + + set(${STRING_STRING} ${${STRING_STRING}} PARENT_SCOPE) +endfunction() + +include(${CMAKE_CURRENT_LIST_DIR}/../linker_script_common.cmake) + +if(DEFINED STEERING_FILE) + get_property(steering_content GLOBAL PROPERTY SYMBOL_STEERING_FILE) + file(WRITE ${STEERING_FILE} "/* AUTO-GENERATED - Do not modify\n") + file(APPEND ${STEERING_FILE} " * AUTO-GENERATED - All changes will be lost\n") + file(APPEND ${STEERING_FILE} " */\n") + + file(APPEND ${STEERING_FILE} ${steering_content}) +endif() diff --git a/cmake/linker/iar/linker_flags.cmake b/cmake/linker/iar/linker_flags.cmake new file mode 100644 index 00000000000..f65925ff8a8 --- /dev/null +++ b/cmake/linker/iar/linker_flags.cmake @@ -0,0 +1,14 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +# Override the default CMake's IAR ILINK linker signature + +string(APPEND CMAKE_C_LINK_FLAGS --no-wrap-diagnostics ) + +foreach(lang C CXX ASM) + set(commands "--log modules,libraries,initialization,redirects,sections") + set(CMAKE_${lang}_LINK_EXECUTABLE + " ${commands} -o ") + set(commands) +endforeach() diff --git a/cmake/linker/iar/target.cmake b/cmake/linker/iar/target.cmake new file mode 100644 index 00000000000..f2326b60491 --- /dev/null +++ b/cmake/linker/iar/target.cmake @@ -0,0 +1,135 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +set_property(TARGET linker PROPERTY devices_start_symbol "_device_list_start") +find_program(CMAKE_LINKER + NAMES ${CROSS_COMPILE}${IAR_LINKER} + PATHS ${TOOLCHAIN_HOME} + PATH_SUFFIXES bin + NO_DEFAULT_PATH +) + +add_custom_target(${IAR_LINKER}) +set(ILINK_THUMB_CALLS_WARNING_SUPPRESSED) +set(IAR_LIB_USED) +function(toolchain_ld_force_undefined_symbols "") +# foreach(symbol ${ARGN}) +# zephyr_link_libraries(--place_holder=${symbol}) +# endforeach() +endfunction() + +# NOTE: ${linker_script_gen} will be produced at build-time; not at configure-time +macro(configure_linker_script linker_script_gen linker_pass_define) + set(extra_dependencies ${ARGN}) + set(STEERING_FILE "${CMAKE_CURRENT_BINARY_DIR}/${linker_script_gen}.xcl") + set(STEERING_FILE_ARG "-DSTEERING_FILE=${STEERING_FILE}") + set(cmake_linker_script_settings + ${PROJECT_BINARY_DIR}/include/generated/ld_script_settings_${linker_pass_define}.cmake + ) + if("${linker_pass_define}" STREQUAL "LINKER_ZEPHYR_PREBUILT") + set(ILINK_THUMB_CALLS_WARNING_SUPPRESSED "--diag_suppress=Lt056") + else() + set(ILINK_THUMB_CALLS_WARNING_SUPPRESSED "") + endif() + if(CONFIG_IAR_LIBC OR CONFIG_IAR_LIBCPP) + set(IAR_LIB_USED "-DIAR_LIBC=1") + else() + set(IAR_LIB_USED "") + endif() + + file(GENERATE OUTPUT ${cmake_linker_script_settings} CONTENT + "set(FORMAT \"$\" CACHE INTERNAL \"\")\n + set(ENTRY \"$\" CACHE INTERNAL \"\")\n + set(MEMORY_REGIONS \"$\" CACHE INTERNAL \"\")\n + set(GROUPS \"$\" CACHE INTERNAL \"\")\n + set(SECTIONS \"$\" CACHE INTERNAL \"\")\n + set(SECTION_SETTINGS \"$\" CACHE INTERNAL \"\")\n + set(SYMBOLS \"$\" CACHE INTERNAL \"\")\n + " + ) + add_custom_command( + OUTPUT ${linker_script_gen} + ${STEERING_FILE} + DEPENDS + ${extra_dependencies} + ${DEVICE_API_LD_TARGET} + COMMAND ${CMAKE_COMMAND} + -C ${DEVICE_API_LINKER_SECTIONS_CMAKE} + -C ${cmake_linker_script_settings} + -DPASS="${linker_pass_define}" + ${STEERING_FILE_ARG} + -DCONFIG_LINKER_LAST_SECTION_ID=${CONFIG_LINKER_LAST_SECTION_ID} + -DCONFIG_LINKER_LAST_SECTION_ID_PATTERN=${CONFIG_LINKER_LAST_SECTION_ID_PATTERN} + -DOUT_FILE=${CMAKE_CURRENT_BINARY_DIR}/${linker_script_gen} + ${IAR_LIB_USED} + -P ${ZEPHYR_BASE}/cmake/linker/iar/config_file_script.cmake + ) + +endmacro() + +function(toolchain_ld_link_elf) + cmake_parse_arguments( + TOOLCHAIN_LD_LINK_ELF # prefix of output variables + "" # list of names of the boolean arguments + "TARGET_ELF;OUTPUT_MAP;LINKER_SCRIPT" # list of names of scalar arguments + "LIBRARIES_PRE_SCRIPT;LIBRARIES_POST_SCRIPT;DEPENDENCIES" # list of names of list arguments + ${ARGN} # input args to parse + ) + + foreach(lib ${ZEPHYR_LIBS_PROPERTY}) + list(APPEND ZEPHYR_LIBS_OBJECTS $) + list(APPEND ZEPHYR_LIBS_OBJECTS $) + endforeach() + + set(ILINK_SEMIHOSTING) + set(ILINK_BUFFERED_WRITE) + if(${CONFIG_IAR_SEMIHOSTING}) + set(ILINK_SEMIHOSTING "--semihosting") + endif() + if(${CONFIG_IAR_BUFFERED_WRITE}) + set(ILINK_BUFFERED_WRITE "--redirect __write=__write_buffered") + endif() + + set(ILINK_XCL "-f ${TOOLCHAIN_LD_LINK_ELF_LINKER_SCRIPT}.xcl") + + set(ILINK_TLS_LIBRARY) + if(${CONFIG_THREAD_LOCAL_STORAGE}) + set(ILINK_TLS_LIBRARY "--threaded_lib=manual") + endif() + + set(ILINK_TZONE_LIBRARY) + # if(${CONFIG_IAR_LIBC}) + # set(ILINK_TZONE_LIBRARY "--timezone_lib") + # endif() + + target_link_libraries( + ${TOOLCHAIN_LD_LINK_ELF_TARGET_ELF} + ${TOOLCHAIN_LD_LINK_ELF_LIBRARIES_PRE_SCRIPT} + --config=${TOOLCHAIN_LD_LINK_ELF_LINKER_SCRIPT} + ${TOOLCHAIN_LD_LINK_ELF_LIBRARIES_POST_SCRIPT} + --map=${TOOLCHAIN_LD_LINK_ELF_OUTPUT_MAP} + --log_file=${TOOLCHAIN_LD_LINK_ELF_OUTPUT_MAP}.log + + ${ZEPHYR_LIBS_OBJECTS} + kernel + $ + --entry=$ + + ${ILINK_SEMIHOSTING} + ${ILINK_BUFFERED_WRITE} + ${ILINK_TLS_LIBRARY} + ${ILINK_TZONE_LIBRARY} + ${ILINK_THUMB_CALLS_WARNING_SUPPRESSED} + # Do not remove symbols + #--no_remove + ${ILINK_XCL} + + ${TOOLCHAIN_LIBS_OBJECTS} + + ${TOOLCHAIN_LD_LINK_ELF_DEPENDENCIES} + ) +endfunction(toolchain_ld_link_elf) + +include(${ZEPHYR_BASE}/cmake/linker/ld/target_relocation.cmake) +include(${ZEPHYR_BASE}/cmake/linker/ld/target_configure.cmake) diff --git a/cmake/toolchain/iar/Kconfig b/cmake/toolchain/iar/Kconfig new file mode 100644 index 00000000000..056fa5d499f --- /dev/null +++ b/cmake/toolchain/iar/Kconfig @@ -0,0 +1,40 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +config LD_LINKER_SCRIPT_SUPPORTED + default n + +choice LINKER_SCRIPT + default CMAKE_LINKER_GENERATOR +endchoice + +menu "IAR library options" + +config IAR_SEMIHOSTING + bool "Use the IAR semihosting implementation." + depends on IAR_LIBC + help + Use the semihosting implementation in the IAR library + instead of the Zephyr implementation. + +config IAR_BUFFERED_WRITE + bool "Use buffered write" + depends on IAR_SEMIHOSTING + help + Instead of printing one character at a time + this option uses a buffer to print a line + at a time instead, increasing speed of printout. + +endmenu + +config TOOLCHAIN_IAR_SUPPORTS_THREAD_LOCAL_STORAGE + def_bool y + select TOOLCHAIN_SUPPORTS_THREAD_LOCAL_STORAGE + +# Should we set this? It doesn't seem to be used +# We support most but don't set __GNUC__ +# +config TOOLCHAIN_IAR_SUPPORTS_GNU_EXTENSIONS + def_bool y + select TOOLCHAIN_SUPPORTS_GNU_EXTENSIONS diff --git a/cmake/toolchain/iar/Kconfig.defconfig b/cmake/toolchain/iar/Kconfig.defconfig new file mode 100644 index 00000000000..506e81b87ba --- /dev/null +++ b/cmake/toolchain/iar/Kconfig.defconfig @@ -0,0 +1,53 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + + +config MISRA_SANE + default y + +config PICOLIBC_SUPPORTED + default n + +config TOOLCHAIN_HAS_BUILTIN_FFS + default n + +config FP16 + default y + +config IAR_LIBC_SUPPORTED + default y + +config COMPILER_FREESTANDING + default y + +config CBPRINTF_LIBC_SUBSTS + default y + +# IAR has slightly different types +config ENFORCE_ZEPHYR_STDINT + default n + +# IAR uses a little bit more stack than GCC +config TEST_EXTRA_STACK_SIZE + default 64 + +# ICCARM does not support relaxation +config LINKER_USE_NO_RELAX + default y + +# ICCARM support C17 with some additional features from C23 +config REQUIRES_STD_C17 + default y + +config CODING_GUIDELINE_CHECK + default n + help + Not applicable to ICCARM + +config TC_PROVIDES_POSIX_C_LANG_SUPPORT_R + default n + +# ICCARM does not support +config COMMON_LIBC_THRD + default n diff --git a/cmake/toolchain/iar/generic.cmake b/cmake/toolchain/iar/generic.cmake new file mode 100644 index 00000000000..645ba19ecb9 --- /dev/null +++ b/cmake/toolchain/iar/generic.cmake @@ -0,0 +1,46 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +zephyr_get(IAR_TOOLCHAIN_PATH) +assert(IAR_TOOLCHAIN_PATH "IAR_TOOLCHAIN_PATH is not set") + +set(IAR_TOOLCHAIN_VARIANT none) +if(NOT EXISTS ${IAR_TOOLCHAIN_PATH}) + message(FATAL_ERROR "Nothing found at IAR_TOOLCHAIN_PATH: '${IAR_TOOLCHAIN_PATH}'") +endif() + +if(EXISTS ${IAR_TOOLCHAIN_PATH}/bin/iccarm) + message(STATUS "Found toolchain: IAR C/C++ Compiler for Arm (${IAR_TOOLCHAIN_PATH})") + set(IAR_COMPILER iccarm) + set(IAR_LINKER ilinkarm) +elseif(EXISTS ${IAR_TOOLCHAIN_PATH}/bin/iccarm.exe) + message(STATUS "Found toolchain: IAR C/C++ Compiler for Arm (${IAR_TOOLCHAIN_PATH})") + set(IAR_COMPILER iccarm) + set(IAR_LINKER ilinkarm) +endif() + +set(IAR_TOOLCHAIN_VARIANT ${IAR_COMPILER}) + +# iar relies on Zephyr SDK for the use of C preprocessor (devicetree) and objcopy +find_package(Zephyr-sdk 0.16 REQUIRED) +message(STATUS "Found Zephyr SDK at ${ZEPHYR_SDK_INSTALL_DIR}") + +set(TOOLCHAIN_HOME ${IAR_TOOLCHAIN_PATH}) + +# Handling to be improved in Zephyr SDK, to avoid overriding ZEPHYR_TOOLCHAIN_VARIANT by +# find_package(Zephyr-sdk) if it's already set +set(ZEPHYR_TOOLCHAIN_VARIANT iar) + +set(COMPILER iar) +set(LINKER iar) +set(BINTOOLS iar) + +if("${IAR_TOOLCHAIN_VARIANT}" STREQUAL "iccarm") + set(SYSROOT_TARGET arm) +else() + set(SYSROOT_TARGET riscv) +endif() +set(CROSS_COMPILE ${TOOLCHAIN_HOME}/bin/) + +set(TOOLCHAIN_HAS_NEWLIB OFF CACHE BOOL "True if toolchain supports NewLib") diff --git a/cmake/toolchain/iar/target.cmake b/cmake/toolchain/iar/target.cmake new file mode 100644 index 00000000000..b11635894a6 --- /dev/null +++ b/cmake/toolchain/iar/target.cmake @@ -0,0 +1,5 @@ +# Copyright (c) 2025 IAR Systems AB +# +# SPDX-License-Identifier: Apache-2.0 + +# Intentionally left blank. diff --git a/include/zephyr/arch/arm/asm_inline.h b/include/zephyr/arch/arm/asm_inline.h index fe36fb2d0e1..54bf2a6f459 100644 --- a/include/zephyr/arch/arm/asm_inline.h +++ b/include/zephyr/arch/arm/asm_inline.h @@ -14,10 +14,10 @@ * Include kernel.h instead */ -#if defined(__GNUC__) +#if defined(__GNUC__) || defined(__ICCARM__) #include #else -#include +#error Unknown toolchain in asm_inline.h #endif #endif /* ZEPHYR_INCLUDE_ARCH_ARM_ASM_INLINE_H_ */ diff --git a/include/zephyr/toolchain.h b/include/zephyr/toolchain.h index bc389ae5565..93ace9520f8 100644 --- a/include/zephyr/toolchain.h +++ b/include/zephyr/toolchain.h @@ -44,6 +44,8 @@ #include #elif defined(__ARMCOMPILER_VERSION) #include +#elif defined(__IAR_SYSTEMS_ICC__) +#include #elif defined(__llvm__) || (defined(_LINKER) && defined(__LLD_LINKER_CMD__)) #include #elif defined(__GNUC__) || (defined(_LINKER) && defined(__GCC_LINKER_CMD__)) diff --git a/include/zephyr/toolchain/iar.h b/include/zephyr/toolchain/iar.h new file mode 100644 index 00000000000..76738c528fe --- /dev/null +++ b/include/zephyr/toolchain/iar.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_TOOLCHAIN_IAR_H_ +#define ZEPHYR_INCLUDE_TOOLCHAIN_IAR_H_ + +#ifdef TOOLCHAIN_PRAGMA +#define _TOOLCHAIN_DISABLE_WARNING(warning) TOOLCHAIN_PRAGMA(diag_suppress = warning) +#define _TOOLCHAIN_ENABLE_WARNING(warning) TOOLCHAIN_PRAGMA(diag_default = warning) + +#define TOOLCHAIN_DISABLE_WARNING(warning) _TOOLCHAIN_DISABLE_WARNING(warning) +#define TOOLCHAIN_ENABLE_WARNING(warning) _TOOLCHAIN_ENABLE_WARNING(warning) +#endif + +#ifdef __ICCARM__ +#include "iar/iccarm.h" +#endif +#ifdef __ICCRISCV__ +#include "iar/iccriscv.h" +#endif + +#endif /* ZEPHYR_INCLUDE_TOOLCHAIN_ICCARM_H_ */ diff --git a/include/zephyr/toolchain/iar/iar_missing_defs.h b/include/zephyr/toolchain/iar/iar_missing_defs.h new file mode 100644 index 00000000000..44541adaccd --- /dev/null +++ b/include/zephyr/toolchain/iar/iar_missing_defs.h @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * Basic macro definitions that gcc and clang provide on their own + * but that iccarm lacks. Only those that Zephyr requires are provided here. + */ + +#ifndef ZEPHYR_INCLUDE_TOOLCHAIN_ICCARM_MISSING_DEFS_H_ +#define ZEPHYR_INCLUDE_TOOLCHAIN_ICCARM_MISSING_DEFS_H_ + + /* We need to define NULL with a parenthesis around _NULL + * otherwise the DEBRACE macros won't work correctly + */ + +#undef NULL +#define NULL (_NULL) + +#if defined(__IAR_SYSTEMS_ICC__) +#ifndef __CHAR_BIT__ +#define __CHAR_BIT__ __CHAR_BITS__ +#endif +#define __SCHAR_MAX__ __SIGNED_CHAR_MAX__ + +#define __INT_MAX__ __SIGNED_INT_MAX__ +#define __INT_WIDTH__ (__INT_SIZE__*8) +#define __SIZEOF_INT__ __INT_SIZE__ + +#define __SHRT_MAX__ __SIGNED_SHORT_MAX__ +#define __SHRT_WIDTH__ (__SHORT_SIZE__*8) +#define __SIZEOF_SHORT__ __SHORT_SIZE__ + +#define __LONG_MAX__ __SIGNED_LONG_MAX__ +#define __LONG_WIDTH__ (__LONG_SIZE__*8) +#define __SIZEOF_LONG__ __LONG_SIZE__ + +#define __LONG_LONG_MAX__ __SIGNED_LONG_LONG_MAX__ +#define __LONG_LONG_WIDTH__ (__LONG_LONG_SIZE__*8) +#define __SIZEOF_LONG_LONG__ __LONG_LONG_SIZE__ + +#define __INTMAX_MAX__ __INTMAX_T_MAX__ +#define __SIZEOF_INTMAX__ sizeof(__INTMAX_T_TYPE__) +#define __INTMAX_WIDTH__ (__SIZEOF_INTMAX__*8) +#define __UINTMAX_MAX__ __UINTMAX_T_MAX__ +#define __SIZEOF_UINTMAX__ sizeof(__UINTMAX_T_TYPE__) +#define __UINTMAX_WIDTH__ (__SIZEOF_UINTMAX__*8) + +#define __INTPTR_MAX__ __INTPTR_T_MAX__ +#define __INTPTR_TYPE__ __INTPTR_T_TYPE__ +#define __INTPTR_WIDTH__ (__INTPTR_T_SIZE__*8) +#define __SIZEOF_POINTER__ __INTPTR_T_SIZE__ + +#define __PTRDIFF_MAX__ __PTRDIFF_T_MAX__ +#define __PTRDIFF_WIDTH__ (__PTRDIFF_T_SIZE__*8) +#define __SIZEOF_PTRDIFF_T__ __PTRDIFF_T_SIZE__ + +#define __UINTPTR_MAX__ __UINTPTR_T_MAX__ +#define __UINTPTR_TYPE__ __UINTPTR_T_TYPE__ + +/* + * ICCARM already defines __SIZE_T_MAX__ as "unsigned int" but there is no way + * to safeguard that here with preprocessor equality. + */ + +#define __SIZE_TYPE__ __SIZE_T_TYPE__ +#define __SIZE_MAX__ __SIZE_T_MAX__ +#define __SIZE_WIDTH__ ((__SIZEOF_SIZE_T__)*8) +/* #define __SIZEOF_SIZE_T__ 4 */ + +/* + * The following defines are inferred from the ICCARM provided defines + * already tested above. + */ + + +#define __INT8_MAX__ __INT8_T_MAX__ +#define __INT8_TYPE__ __INT8_T_TYPE__ + +#define __UINT8_MAX__ __UINT8_T_MAX__ +#define __UINT8_TYPE__ __UINT8_T_TYPE__ + +#define __INT16_MAX__ __INT16_T_MAX__ +#define __INT16_TYPE__ __INT16_T_TYPE__ + +#define __UINT16_MAX__ __UINT16_T_MAX__ +#define __UINT16_TYPE__ __UINT16_T_TYPE__ + +#define __INT32_MAX__ __INT32_T_MAX__ +#define __INT32_TYPE__ __INT32_T_TYPE__ + +#define __UINT32_MAX__ __UINT32_T_MAX__ +#define __UINT32_TYPE__ __UINT32_T_TYPE__ + +#define __INT64_MAX__ __INT64_T_MAX__ +#define __INT64_TYPE__ __INT64_T_TYPE__ + +#define __UINT64_MAX__ __UINT64_T_MAX__ +#define __UINT64_TYPE__ __UINT64_T_TYPE__ + +#define __INT_FAST8_MAX__ __INT_FAST8_T_MAX__ +#define __INT_FAST8_TYPE__ __INT_FAST8_T_TYPE__ +#define __INT_FAST8_WIDTH__ (__INT_FAST8_T_SIZE__*8) + +#define __INT_FAST16_MAX__ __INT_FAST16_T_MAX__ +#define __INT_FAST16_TYPE__ __INT_FAST16_T_TYPE__ +#define __INT_FAST16_WIDTH__ (__INT_FAST16_T_SIZE__*8) + +#define __INT_FAST32_MAX__ __INT_FAST32_T_MAX__ +#define __INT_FAST32_TYPE__ __INT_FAST32_T_TYPE__ +#define __INT_FAST32_WIDTH__ (__INT_FAST32_T_SIZE__*8) + +#define __INT_FAST64_MAX__ __INT_FAST64_T_MAX__ +#define __INT_FAST64_TYPE__ __INT_FAST64_T_TYPE__ +#define __INT_FAST64_WIDTH__ (__INT_FAST64_T_SIZE__*8) + +#define __INT_LEAST8_MAX__ __INT_LEAST8_T_MAX__ +#define __INT_LEAST8_TYPE__ __INT_LEAST8_T_TYPE__ +#define __INT_LEAST8_WIDTH__ (__INT_LEAST8_T_SIZE__*8) + +#define __INT_LEAST16_MAX__ __INT_LEAST16_T_MAX__ +#define __INT_LEAST16_TYPE__ __INT_LEAST16_T_TYPE__ +#define __INT_LEAST16_WIDTH__ (__INT_LEAST16_T_SIZE__*8) + +#define __INT_LEAST32_MAX__ __INT_LEAST32_T_MAX__ +#define __INT_LEAST32_TYPE__ __INT_LEAST32_T_TYPE__ +#define __INT_LEAST32_WIDTH__ (__INT_LEAST32_T_SIZE__*8) + +#define __INT_LEAST64_MAX__ __INT_LEAST64_T_MAX__ +#define __INT_LEAST64_TYPE__ __INT_LEAST64_T_TYPE__ +#define __INT_LEAST64_WIDTH__ (__INT_LEAST64_T_SIZE__*8) + +#define __UINT_FAST8_MAX__ __UINT_FAST8_T_MAX__ +#define __UINT_FAST8_TYPE__ __UINT_FAST8_T_TYPE__ + +#define __UINT_FAST16_MAX__ __UINT_FAST16_T_MAX__ +#define __UINT_FAST16_TYPE__ __UINT_FAST16_T_TYPE__ + +#define __UINT_FAST32_MAX__ __UINT_FAST32_T_MAX__ +#define __UINT_FAST32_TYPE__ __UINT_FAST32_T_TYPE__ + +#define __UINT_FAST64_MAX__ __UINT_FAST64_T_MAX__ +#define __UINT_FAST64_TYPE__ __UINT_FAST64_T_TYPE__ + +#define __UINT_LEAST8_MAX__ __UINT_LEAST8_T_MAX__ +#define __UINT_LEAST8_TYPE__ __UINT_LEAST8_T_TYPE__ + +#define __UINT_LEAST16_MAX__ __UINT_LEAST16_T_MAX__ +#define __UINT_LEAST16_TYPE__ __UINT_LEAST16_T_TYPE__ + +#define __UINT_LEAST32_MAX__ __UINT_LEAST32_T_MAX__ +#define __UINT_LEAST32_TYPE__ __UINT_LEAST32_T_TYPE__ + +#define __UINT_LEAST64_MAX__ __UINT_LEAST64_T_MAX__ +#define __UINT_LEAST64_TYPE__ __UINT_LEAST64_T_TYPE__ + +#endif /* __IAR_SYSTEMS_ICC__ */ + +#endif diff --git a/include/zephyr/toolchain/iar/iccarm.h b/include/zephyr/toolchain/iar/iccarm.h new file mode 100644 index 00000000000..cc791023329 --- /dev/null +++ b/include/zephyr/toolchain/iar/iccarm.h @@ -0,0 +1,456 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_TOOLCHAIN_ICCARM_H_ +#define ZEPHYR_INCLUDE_TOOLCHAIN_ICCARM_H_ + +/** + * @file + * @brief ICCARM toolchain abstraction + * + * Macros to abstract compiler capabilities for ICCARM toolchain. + */ + +/* ICCARM supports its own #pragma diag_{warning,default,error,warning}. */ +/* #define TOOLCHAIN_HAS_PRAGMA_DIAG 0 */ + +#define TOOLCHAIN_HAS_C_GENERIC 1 + +#define TOOLCHAIN_HAS_C_AUTO_TYPE 1 + +/* #define TOOLCHAIN_HAS_ZLA 1 */ + +/* + * IAR do not define __BYTE_ORDER__, so it must be manually + * detected and defined using arch-specific definitions. + */ + +#ifndef _LINKER + +#ifndef __ORDER_BIG_ENDIAN__ +#define __ORDER_BIG_ENDIAN__ (1) +#endif /* __ORDER_BIG_ENDIAN__ */ + +#ifndef __ORDER_LITTLE_ENDIAN__ +#define __ORDER_LITTLE_ENDIAN__ (2) +#endif /* __ORDER_LITTLE_ENDIAN__ */ + +#ifndef __ORDER_PDP_ENDIAN__ +#define __ORDER_PDP_ENDIAN__ (3) +#endif /* __ORDER_PDP_ENDIAN__ */ + +#ifndef __BYTE_ORDER__ + +#if __LITTLE_ENDIAN__ == 1 +#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ +#else +#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__ +#endif /* __LITTLE_ENDIAN__ == 1 */ + +#endif /* __BYTE_ORDER__ */ + + +#if defined(__cplusplus) && (__cplusplus >= 201103L) +#define BUILD_ASSERT(EXPR, MSG...) static_assert(EXPR, "" MSG) +#elif defined(__ICCARM__) +#define BUILD_ASSERT(EXPR, MSG...) _Static_assert(EXPR, "" MSG) +#endif + +/* Zephyr makes use of __ATOMIC_SEQ_CST */ +#ifdef __STDC_NO_ATOMICS__ +#ifndef __ATOMIC_SEQ_CST +#define __MEMORY_ORDER_SEQ_CST__ 5 +#endif +#endif +#ifndef __ATOMIC_SEQ_CST +#define __ATOMIC_SEQ_CST __MEMORY_ORDER_SEQ_CST__ +#endif + +/* By default, restrict is recognized in Standard C + * __restrict is always recognized + */ +#define ZRESTRICT __restrict + +#include +#include + +#define ALIAS_OF(of) __attribute__((alias(#of))) + +#define FUNC_ALIAS(real_func, new_alias, return_type) \ + return_type new_alias() ALIAS_OF(real_func) + +#define CODE_UNREACHABLE __builtin_unreachable() +#define FUNC_NORETURN __attribute__((__noreturn__)) + +#define _NODATA_SECTION(segment) __attribute__((section(#segment))) + +/* Unaligned access */ +#define UNALIGNED_GET(p) \ +__extension__ ({ \ + struct __attribute__((__packed__)) { \ + __typeof__(*(p)) __v; \ + } *__p = (__typeof__(__p)) (p); \ + __p->__v; \ +}) + +#define UNALIGNED_PUT(v, p) \ +do { \ + struct __attribute__((__packed__)) { \ + __typeof__(*p) __v; \ + } *__p = (__typeof__(__p)) (p); \ + __p->__v = (v); \ +} while (false) + + +/* Double indirection to ensure section names are expanded before + * stringification + */ +#define __GENERIC_SECTION(segment) __attribute__((section(STRINGIFY(segment)))) +#define Z_GENERIC_SECTION(segment) __GENERIC_SECTION(segment) + +#define __GENERIC_DOT_SECTION(segment) \ + __attribute__((section("." STRINGIFY(segment)))) +#define Z_GENERIC_DOT_SECTION(segment) __GENERIC_DOT_SECTION(segment) + +#define ___in_section(a, b, c) \ + __attribute__((section("." Z_STRINGIFY(a) \ + "." Z_STRINGIFY(b) \ + "." Z_STRINGIFY(c)))) +#define __in_section(a, b, c) ___in_section(a, b, c) + +#define __in_section_unique(seg) ___in_section(seg, __FILE__, __COUNTER__) + +#define __in_section_unique_named(seg, name) \ + ___in_section(seg, __FILE__, name) + +/* When using XIP, using '__ramfunc' places a function into RAM instead + * of FLASH. Make sure '__ramfunc' is defined only when + * CONFIG_ARCH_HAS_RAMFUNC_SUPPORT is defined, so that the compiler can + * report an error if '__ramfunc' is used but the architecture does not + * support it. + */ +#if !defined(CONFIG_XIP) +#define __ramfunc +#elif defined(CONFIG_ARCH_HAS_RAMFUNC_SUPPORT) +/* Use this instead of the IAR keyword __ramfunc to make sure it + * ends up in the correct section. + */ +#define __ramfunc __attribute__((noinline, section(".ramfunc"))) +#endif /* !CONFIG_XIP */ + +/* TG-WG: ICCARM does not support __fallthrough */ +#define __fallthrough [[fallthrough]] + +#ifndef __packed +#define __packed __attribute__((__packed__)) +#endif + +#ifndef __aligned +#define __aligned(x) __attribute__((__aligned__(x))) +#endif + +#ifndef __noinline +#define __noinline __attribute__((noinline)) +#endif + +#if defined(__cplusplus) +#define __alignof(x) alignof(x) +#else +#define __alignof(x) _Alignof(x) +#endif + +#define __may_alias __attribute__((__may_alias__)) + +#ifndef __printf_like +/* + * The Zephyr stdint convention enforces int32_t = int, int64_t = long long, + * and intptr_t = long so that short string format length modifiers can be + * used universally across ILP32 and LP64 architectures. Without that it + * is possible for ILP32 toolchains to have int32_t = long and intptr_t = int + * clashing with the Zephyr convention and generating pointless warnings + * as they're still the same size. Inhibit the format argument type + * validation in that case and let the other configs do it. + */ +#define __printf_like(f, a) +#endif + +#define __used __attribute__((__used__)) +#define __unused __attribute__((__unused__)) +#define __maybe_unused __attribute__((__unused__)) + +#ifndef __deprecated +#define __deprecated __attribute__((deprecated)) +#endif + +#define FUNC_NO_STACK_PROTECTOR _Pragma("no_stack_protect") + +#ifndef __attribute_const__ +#if __VER__ > 0x09000000 +#define __attribute_const__ __attribute__((const)) +#else +#define __attribute_const__ +#endif +#endif + +#ifndef __must_check +/* #warning "The attribute __warn_unused_result is not supported in ICCARM". */ +#define __must_check +/* #define __must_check __attribute__((warn_unused_result)) */ +#endif + +#define __PRAGMA(...) _Pragma(#__VA_ARGS__) +#define ARG_UNUSED(x) (void)(x) + +#define likely(x) (__builtin_expect((bool)!!(x), true) != 0L) +#define unlikely(x) (__builtin_expect((bool)!!(x), false) != 0L) +#define POPCOUNT(x) __builtin_popcount(x) + +#ifndef __no_optimization +#define __no_optimization __PRAGMA(optimize = none) +#endif + +#ifndef __attribute_nonnull + #define __attribute_nonnull(...) __attribute__((nonnull(__VA_ARGS__))) +#endif + +/* __weak is an ICCARM built-in, but it doesn't work in all positions */ +/* the Zephyr uses it so we replace it with an attribute((weak)) */ +#define __weak __attribute__((__weak__)) + +/* Builtins */ + +#include + +/* + * Be *very* careful with these. You cannot filter out __DEPRECATED_MACRO with + * -wno-deprecated, which has implications for -Werror. + */ + + +/* + * Expands to nothing and generates a warning. Used like + * + * #define FOO __WARN("Please use BAR instead") ... + * + * The warning points to the location where the macro is expanded. + */ +#define __WARN(s) __PRAGMA(message = #s) +#define __WARN1(s) __PRAGMA(message = #s) + +/* Generic message */ +#ifndef __DEPRECATED_MACRO +#define __DEPRECATED_MACRO __WARN("Macro is deprecated") +#endif + +/* These macros allow having ARM asm functions callable from thumb */ + +#if defined(_ASMLANGUAGE) + +#if defined(CONFIG_ASSEMBLER_ISA_THUMB2) +#define FUNC_CODE() .code 32 +#define FUNC_INSTR(a) +/* '.syntax unified' is a gcc-ism used in thumb-2 asm files */ +#define _ASM_FILE_PROLOGUE .text; .syntax unified; .thumb +#else +#define FUNC_CODE() +#define FUNC_INSTR(a) +#define _ASM_FILE_PROLOGUE .text; .code 32 +#endif /* CONFIG_ASSEMBLER_ISA_THUMB2 */ + +/* + * These macros are used to declare assembly language symbols that need + * to be typed properly(func or data) to be visible to the OMF tool. + * So that the build tool could mark them as an entry point to be linked + * correctly. This is an elfism. Use #if 0 for a.out. + */ + +/* This is not implemented yet for IAR */ +#define GTEXT(sym) +#define GDATA(sym) +#define WTEXT(sym) +#define WDATA(sym) + +#define SECTION_VAR(sect, sym) +#define SECTION_FUNC(sect, sym) +#define SECTION_SUBSEC_FUNC(sect, subsec, sym) + +#endif /* _ASMLANGUAGE */ + + +/* + * These macros generate absolute symbols for IAR + */ + +/* create an extern reference to the absolute symbol */ + +#define GEN_OFFSET_EXTERN(name) extern const char name[] + +#define GEN_ABS_SYM_BEGIN(name) \ + EXTERN_C void name(void); \ + void name(void) \ + { + +#define GEN_ABS_SYM_END } + +/* + * Note that GEN_ABSOLUTE_SYM(), depending on the architecture + * and toolchain, may restrict the range of values permitted + * for assignment to the named symbol. + */ +#define GEN_ABSOLUTE_SYM(name, value) \ + __PRAGMA(public_equ = #name, (unsigned int)value) + +/* + * GEN_ABSOLUTE_SYM_KCONFIG() is outputted by the build system + * to generate named symbol/value pairs for kconfigs. + */ +#define GEN_ABSOLUTE_SYM_KCONFIG(name, value) \ + __PRAGMA(public_equ = #name, (unsigned int)value) + +#define compiler_barrier() do { \ + __asm volatile("" ::: "memory"); \ +} while (false) + +/** @brief Return larger value of two provided expressions. + * + * Macro ensures that expressions are evaluated only once. + * + * @note Macro has limited usage compared to the standard macro as it cannot be + * used: + * - to generate constant integer, e.g. __aligned(Z_MAX(4,5)) + * - static variable, e.g. array like static uint8_t array[Z_MAX(...)]; + */ +#define Z_MAX(a, b) ({ \ + /* random suffix to avoid naming conflict */ \ + __typeof__(a) _value_a_ = (a); \ + __typeof__(b) _value_b_ = (b); \ + _value_a_ > _value_b_ ? _value_a_ : _value_b_; \ + }) + +/** @brief Return smaller value of two provided expressions. + * + * Macro ensures that expressions are evaluated only once. See @ref Z_MAX for + * macro limitations. + */ +#define Z_MIN(a, b) ({ \ + /* random suffix to avoid naming conflict */ \ + __typeof__(a) _value_a_ = (a); \ + __typeof__(b) _value_b_ = (b); \ + _value_a_ < _value_b_ ? _value_a_ : _value_b_; \ + }) + +/** @brief Return a value clamped to a given range. + * + * Macro ensures that expressions are evaluated only once. See @ref Z_MAX for + * macro limitations. + */ +#define Z_CLAMP(val, low, high) ({ \ + /* random suffix to avoid naming conflict */ \ + __typeof__(val) _value_val_ = (val); \ + __typeof__(low) _value_low_ = (low); \ + __typeof__(high) _value_high_ = (high); \ + (_value_val_ < _value_low_) ? _value_low_ : \ + (_value_val_ > _value_high_) ? _value_high_ : \ + _value_val_; \ + }) + +/** + * @brief Calculate power of two ceiling for some nonzero value + * + * @param x Nonzero unsigned long value + * @return X rounded up to the next power of two + */ +#define Z_POW2_CEIL(x) \ + ((x) <= 2UL ? (x) : (1UL << (8 * sizeof(long) - __builtin_clzl((x) - 1)))) + +/** + * @brief Check whether or not a value is a power of 2 + * + * @param x The value to check + * @return true if x is a power of 2, false otherwise + */ +#define Z_IS_POW2(x) (((x) != 0) && (((x) & ((x)-1)) == 0)) + +#ifndef __INT8_C +#define __INT8_C(x) x +#endif + +#ifndef INT8_C +#define INT8_C(x) __INT8_C(x) +#endif + +#ifndef __UINT8_C +#define __UINT8_C(x) x ## U +#endif + +#ifndef UINT8_C +#define UINT8_C(x) __UINT8_C(x) +#endif + +#ifndef __INT16_C +#define __INT16_C(x) x +#endif + +#ifndef INT16_C +#define INT16_C(x) __INT16_C(x) +#endif + +#ifndef __UINT16_C +#define __UINT16_C(x) x ## U +#endif + +#ifndef UINT16_C +#define UINT16_C(x) __UINT16_C(x) +#endif + +#ifndef __INT32_C +#define __INT32_C(x) x +#endif + +#ifndef INT32_C +#define INT32_C(x) __INT32_C(x) +#endif + +#ifndef __UINT32_C +#define __UINT32_C(x) x ## U +#endif + +#ifndef UINT32_C +#define UINT32_C(x) __UINT32_C(x) +#endif + +#ifndef __INT64_C +#define __INT64_C(x) x ## LL +#endif + +#ifndef INT64_C +#define INT64_C(x) __INT64_C(x) +#endif + +#ifndef __UINT64_C +#define __UINT64_C(x) x ## ULL +#endif + +#ifndef UINT64_C +#define UINT64_C(x) __UINT64_C(x) +#endif + +/* Convenience macros */ +#undef _GLUE_B +#undef _GLUE +#define _GLUE_B(x, y) x##y +#define _GLUE(x, y) _GLUE_B(x, y) + +#ifndef INTMAX_C +#define INTMAX_C(x) _GLUE(x, __INTMAX_C_SUFFIX__) +#endif + +#ifndef UINTMAX_C +#define UINTMAX_C(x) _GLUE(x, __UINTMAX_C_SUFFIX__) +#endif + +#endif /* !_LINKER */ +#endif /* ZEPHYR_INCLUDE_TOOLCHAIN_ICCARM_H_ */ diff --git a/lib/libc/CMakeLists.txt b/lib/libc/CMakeLists.txt index a6fecf09d66..075e066d59b 100644 --- a/lib/libc/CMakeLists.txt +++ b/lib/libc/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_syscall_header( add_subdirectory_ifdef(CONFIG_ARCMWDT_LIBC arcmwdt) add_subdirectory_ifdef(CONFIG_ARMCLANG_STD_LIBC armstdc) +add_subdirectory_ifdef(CONFIG_IAR_LIBC iar) add_subdirectory_ifdef(CONFIG_MINIMAL_LIBC minimal) add_subdirectory_ifdef(CONFIG_NEWLIB_LIBC newlib) add_subdirectory_ifdef(CONFIG_PICOLIBC picolibc) diff --git a/lib/libc/Kconfig b/lib/libc/Kconfig index eb3c19247ce..5d981e4719b 100644 --- a/lib/libc/Kconfig +++ b/lib/libc/Kconfig @@ -51,6 +51,13 @@ config PICOLIBC_SUPPORTED help Selected when the target has support for picolibc. +config IAR_LIBC_SUPPORTED + bool + default n + select FULL_LIBC_SUPPORTED + help + Selected if the target is an IAR Systems compiler + config NATIVE_LIBC_INCOMPATIBLE bool help @@ -65,6 +72,7 @@ choice LIBC_IMPLEMENTATION default PICOLIBC default NEWLIB_LIBC if REQUIRES_FULL_LIBC default MINIMAL_LIBC + default IAR_LIBC config MINIMAL_LIBC bool "Minimal C library" @@ -124,6 +132,17 @@ config EXTERNAL_LIBC help Build with external/user provided C library. +config IAR_LIBC + bool "IAR C Runtime Library" + depends on IAR_LIBC_SUPPORTED + depends on "$(ZEPHYR_TOOLCHAIN_VARIANT)" = "iar" + select COMMON_LIBC_STRNLEN + select COMMON_LIBC_TIME if POSIX_TIMERS + help + Use the full IAR Compiler runtime libraries. + A reduced Zephyr minimal libc will be used for library functionality + not provided by the IAR C Runtime Library. + endchoice # LIBC_IMPLEMENTATION config HAS_NEWLIB_LIBC_NANO diff --git a/lib/libc/iar/CMakeLists.txt b/lib/libc/iar/CMakeLists.txt new file mode 100644 index 00000000000..f57ab75d2d3 --- /dev/null +++ b/lib/libc/iar/CMakeLists.txt @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(src/libc-hooks.c) +zephyr_system_include_directories(include) diff --git a/lib/libc/iar/include/errno.h b/lib/libc/iar/include/errno.h new file mode 100644 index 00000000000..6310531a75c --- /dev/null +++ b/lib/libc/iar/include/errno.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Defines additional error numbers based on POSIX + */ + +#ifndef ZEPHYR_LIB_LIBC_IAR_INCLUDE_ERRNO_H_ +#define ZEPHYR_LIB_LIBC_IAR_INCLUDE_ERRNO_H_ + +#include_next + +#ifndef __cplusplus +#define EPERM 1 /**< Not owner */ +#define ENOENT 2 /**< No such file or directory */ +#define ESRCH 3 /**< No such context */ +#define EINTR 4 /**< Interrupted system call */ +#define EIO 5 /**< I/O error */ +#define ENXIO 6 /**< No such device or address */ +#define E2BIG 7 /**< Arg list too long */ +#define ENOEXEC 8 /**< Exec format error */ +#define EBADF 9 /**< Bad file number */ +#define ECHILD 10 /**< No children */ +#define EAGAIN 11 /**< No more contexts */ +#define ENOMEM 12 /**< Not enough core */ +#define EACCES 13 /**< Permission denied */ +#define EFAULT 14 /**< Bad address */ +#define ENOTBLK 15 /**< Block device required */ +#define EBUSY 16 /**< Mount device busy */ +#define EEXIST 17 /**< File exists */ +#define EXDEV 18 /**< Cross-device link */ +#define ENODEV 19 /**< No such device */ +#define ENOTDIR 20 /**< Not a directory */ +#define EISDIR 21 /**< Is a directory */ +#define EINVAL 22 /**< Invalid argument */ +#define ENFILE 23 /**< File table overflow */ +#define EMFILE 24 /**< Too many open files */ +#define ENOTTY 25 /**< Not a typewriter */ +#define ETXTBSY 26 /**< Text file busy */ +#define EFBIG 27 /**< File too large */ +#define ENOSPC 28 /**< No space left on device */ +#define ESPIPE 29 /**< Illegal seek */ +#define EROFS 30 /**< Read-only file system */ +#define EMLINK 31 /**< Too many links */ +#define EPIPE 32 /**< Broken pipe */ +#define ENOMSG 35 /**< Unexpected message type */ +#define EDEADLK 45 /**< Resource deadlock avoided */ +#define ENOLCK 46 /**< No locks available */ +#define ENOSTR 60 /**< STREAMS device required */ +#define ENODATA 61 /**< Missing expected message data */ +#define ETIME 62 /**< STREAMS timeout occurred */ +#define ENOSR 63 /**< Insufficient memory */ +#define EPROTO 71 /**< Generic STREAMS error */ +#define EBADMSG 77 /**< Invalid STREAMS message */ +#define ENOSYS 88 /**< Function not implemented */ +#define ENOTEMPTY 90 /**< Directory not empty */ +#define ENAMETOOLONG 91 /**< File name too long */ +#define ELOOP 92 /**< Too many levels of symbolic links */ +#define EOPNOTSUPP 95 /**< Operation not supported on socket */ +#define EPFNOSUPPORT 96 /**< Protocol family not supported */ +#define ECONNRESET 104 /**< Connection reset by peer */ +#define ENOBUFS 105 /**< No buffer space available */ +#define EAFNOSUPPORT 106 /**< Addr family not supported */ +#define EPROTOTYPE 107 /**< Protocol wrong type for socket */ +#define ENOTSOCK 108 /**< Socket operation on non-socket */ +#define ENOPROTOOPT 109 /**< Protocol not available */ +#define ESHUTDOWN 110 /**< Can't send after socket shutdown */ +#define ECONNREFUSED 111 /**< Connection refused */ +#define EADDRINUSE 112 /**< Address already in use */ +#define ECONNABORTED 113 /**< Software caused connection abort */ +#define ENETUNREACH 114 /**< Network is unreachable */ +#define ENETDOWN 115 /**< Network is down */ +#define ETIMEDOUT 116 /**< Connection timed out */ +#define EHOSTDOWN 117 /**< Host is down */ +#define EHOSTUNREACH 118 /**< No route to host */ +#define EINPROGRESS 119 /**< Operation now in progress */ +#define EALREADY 120 /**< Operation already in progress */ +#define EDESTADDRREQ 121 /**< Destination address required */ +#define EMSGSIZE 122 /**< Message size */ +#define EPROTONOSUPPORT 123 /**< Protocol not supported */ +#define ESOCKTNOSUPPORT 124 /**< Socket type not supported */ +#define EADDRNOTAVAIL 125 /**< Can't assign requested address */ +#define ENETRESET 126 /**< Network dropped connection on reset */ +#define EISCONN 127 /**< Socket is already connected */ +#define ENOTCONN 128 /**< Socket is not connected */ +#define ETOOMANYREFS 129 /**< Too many references: can't splice */ +#define ENOTSUP 134 /**< Unsupported value */ +#define EOVERFLOW 139 /**< Value overflow */ +#define ECANCELED 140 /**< Operation canceled */ +#define EWOULDBLOCK EAGAIN /**< Operation would block */ +#endif /* __cplusplus */ +#endif /* ZEPHYR_LIB_LIBC_IAR_INCLUDE_ERRNO_H_ */ diff --git a/lib/libc/iar/include/limits.h b/lib/libc/iar/include/limits.h new file mode 100644 index 00000000000..50decad13ad --- /dev/null +++ b/lib/libc/iar/include/limits.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_LIBC_IAR_INCLUDE_LIMITS_H_ +#define ZEPHYR_LIB_LIBC_IAR_INCLUDE_LIMITS_H_ + +#include_next + +#ifdef __cplusplus +extern "C" { +#endif + +#define PATH_MAX 256 + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_LIB_LIBC_IAR_INCLUDE_LIMITS_H_ */ diff --git a/lib/libc/iar/include/sys/_timespec.h b/lib/libc/iar/include/sys/_timespec.h new file mode 100644 index 00000000000..1ea3b4da5bf --- /dev/null +++ b/lib/libc/iar/include/sys/_timespec.h @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* file is intentionally empty */ diff --git a/lib/libc/iar/include/sys/_timeval.h b/lib/libc/iar/include/sys/_timeval.h new file mode 100644 index 00000000000..43f8f7f8c89 --- /dev/null +++ b/lib/libc/iar/include/sys/_timeval.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_LIBC_IAR_INCLUDE_SYS__TIMEVAL_H_ +#define ZEPHYR_LIB_LIBC_IAR_INCLUDE_SYS__TIMEVAL_H_ + +#include + +#if !defined(__time_t_defined) +#define __time_t_defined +typedef long long time_t; +#endif + +#if !defined(__suseconds_t_defined) +#define __suseconds_t_defined +typedef int32_t suseconds_t; +#endif + +struct timeval { + time_t tv_sec; + suseconds_t tv_usec; +}; + +#endif /* ZEPHYR_LIB_LIBC_IAR_INCLUDE_SYS__TIMEVAL_H_ */ diff --git a/lib/libc/iar/include/sys/cdefs.h b/lib/libc/iar/include/sys/cdefs.h new file mode 100644 index 00000000000..1ea3b4da5bf --- /dev/null +++ b/lib/libc/iar/include/sys/cdefs.h @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* file is intentionally empty */ diff --git a/lib/libc/iar/include/sys/timespec.h b/lib/libc/iar/include/sys/timespec.h new file mode 100644 index 00000000000..d5c0549dbc9 --- /dev/null +++ b/lib/libc/iar/include/sys/timespec.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_LIBC_IAR_INCLUDE_SYS_TIMESPEC_H_ +#define ZEPHYR_LIB_LIBC_IAR_INCLUDE_SYS_TIMESPEC_H_ + +#include +#include + +struct itimerspec { + struct timespec it_interval; /* Timer interval */ + struct timespec it_value; /* Timer expiration */ +}; + +#endif /* ZEPHYR_LIB_LIBC_IAR_INCLUDE_SYS_TIMESPEC_H_ */ diff --git a/lib/libc/iar/include/sys/types.h b/lib/libc/iar/include/sys/types.h new file mode 100644 index 00000000000..9654efc25ee --- /dev/null +++ b/lib/libc/iar/include/sys/types.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_LIB_LIBC_IAR_INCLUDE_SYS_TYPES_H_ +#define ZEPHYR_LIB_LIBC_IAR_INCLUDE_SYS_TYPES_H_ + +typedef unsigned int mode_t; +typedef signed long ssize_t; +typedef int off_t; +typedef __INT64_TYPE__ time_t; + +#if !defined(_CLOCK_T_DECLARED) && !defined(__clock_t_defined) +typedef unsigned int clock_t; +#define _CLOCK_T_DECLARED +#define __clock_t_defined +#endif + +#endif /* ZEPHYR_LIB_LIBC_IAR_INCLUDE_SYS_TYPES_H_ */ diff --git a/lib/libc/iar/include/time.h b/lib/libc/iar/include/time.h new file mode 100644 index 00000000000..b0959878574 --- /dev/null +++ b/lib/libc/iar/include/time.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Declares additional time related functions based on POSIX + */ + +#ifndef ZEPHYR_LIB_LIBC_IAR_INCLUDE_TIME_H_ +#define ZEPHYR_LIB_LIBC_IAR_INCLUDE_TIME_H_ + +#include +#include_next + +#ifdef __cplusplus +extern "C" { +#endif + +char *asctime_r(const struct tm *ZRESTRICT tp, char *ZRESTRICT buf); +char *ctime_r(const time_t *clock, char *buf); +struct tm *gmtime_r(const time_t *ZRESTRICT timep, struct tm *ZRESTRICT result); +struct tm *localtime_r(const time_t *ZRESTRICT timer, struct tm *ZRESTRICT result); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_LIB_LIBC_IAR_INCLUDE_TIME_H_ */ diff --git a/lib/libc/iar/src/libc-hooks.c b/lib/libc/iar/src/libc-hooks.c new file mode 100644 index 00000000000..d3deea9658a --- /dev/null +++ b/lib/libc/iar/src/libc-hooks.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025 IAR Systems AB + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +static int _stdout_hook_default(int c) +{ + (void)(c); /* Prevent warning about unused argument */ + + return EOF; +} + +static int (*_stdout_hook)(int) = _stdout_hook_default; + +void __stdout_hook_install(int (*hook)(int)) +{ + _stdout_hook = hook; +} + +int fputc(int c, FILE *f) +{ + return (_stdout_hook)(c); +} + +#pragma weak __write +size_t __write(int handle, const unsigned char *buf, size_t bufSize) +{ + size_t nChars = 0; + /* Check for the command to flush all handles */ + if (handle == -1) { + return 0; + } + /* Check for stdout and stderr + * (only necessary if FILE descriptors are enabled.) + */ + if (handle != 1 && handle != 2) { + return -1; + } + for (/* Empty */; bufSize > 0; --bufSize) { + int ret = (_stdout_hook)(*buf); + + if (ret == EOF) { + break; + } + ++buf; + ++nChars; + } + return nChars; +} diff --git a/scripts/ci/check_compliance.py b/scripts/ci/check_compliance.py index 81ebf873392..9b2c610d390 100755 --- a/scripts/ci/check_compliance.py +++ b/scripts/ci/check_compliance.py @@ -1059,6 +1059,9 @@ flagged. "FOO_SETTING_2", "HEAP_MEM_POOL_ADD_SIZE_", # Used as an option matching prefix "HUGETLBFS", # Linux, in boards/xtensa/intel_adsp_cavs25/doc + "IAR_BUFFERED_WRITE", + "IAR_LIBCPP", + "IAR_SEMIHOSTING", "IPC_SERVICE_ICMSG_BOND_NOTIFY_REPEAT_TO_MS", # Used in ICMsg tests for intercompatibility # with older versions of the ICMsg. "LIBGCC_RTLIB", diff --git a/tests/kernel/fpu_sharing/generic/src/load_store.c b/tests/kernel/fpu_sharing/generic/src/load_store.c index 1193297eb41..67e6cb54129 100644 --- a/tests/kernel/fpu_sharing/generic/src/load_store.c +++ b/tests/kernel/fpu_sharing/generic/src/load_store.c @@ -46,7 +46,7 @@ #endif /* __GNUC__ */ #elif defined(CONFIG_ARM) #if defined(CONFIG_ARMV7_M_ARMV8_M_FP) || defined(CONFIG_ARMV7_R_FP) || defined(CONFIG_CPU_HAS_VFP) -#if defined(__GNUC__) +#if defined(__GNUC__) || defined(__ICCARM__) #include "float_regs_arm_gcc.h" #else #include "float_regs_arm_other.h"