From b0388ad4a548fefb4c4b4358ade0929d6a545382 Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Mon, 10 Nov 2025 18:27:40 +0700 Subject: [PATCH] feat(build): add COMPILER_ENABLE_RISCV_ZCMP option Applicable for chips affected by interrupt issue: - ESP32C5 - ESP32C61 - ESP32H4 For all other chips that support the ZCMP extension without issues, it will be enabled unconditionally. --- Kconfig | 21 ++++++++++++++++++ .../esp32c5/include/soc/Kconfig.soc_caps.in | 8 +++++++ components/soc/esp32c5/include/soc/soc_caps.h | 2 ++ .../esp32c61/include/soc/Kconfig.soc_caps.in | 8 +++++++ .../soc/esp32c61/include/soc/soc_caps.h | 2 ++ .../esp32h4/include/soc/Kconfig.soc_caps.in | 16 ++++++++++++++ components/soc/esp32h4/include/soc/soc_caps.h | 5 +++++ .../esp32p4/include/soc/Kconfig.soc_caps.in | 12 ++++++++++ components/soc/esp32p4/include/soc/soc_caps.h | 5 +++++ components/soc/project_include.cmake | 22 ++++++++++++++++++- docs/en/api-guides/performance/size.rst | 1 + 11 files changed, 101 insertions(+), 1 deletion(-) diff --git a/Kconfig b/Kconfig index fec451c131..143aed33d7 100644 --- a/Kconfig +++ b/Kconfig @@ -370,6 +370,27 @@ mainmenu "Espressif IoT Development Framework Configuration" endchoice + config COMPILER_ENABLE_RISCV_ZCMP + bool "Enable RISCV ZCMP extension" + depends on SOC_CPU_ZCMP_WORKAROUND + default n + help + Enable the RISC-V ZCMP (Compressed Macro) extension to reduce binary size + by optimizing function prologue and epilogue sequences. + + Note: Due to a hardware issue on some ESP32 chips (e.g., ESP32C5, ESP32C61, + ESP32H4), executing "cm.push" may re-enable interrupts even when global + interrupts are disabled (mstatus.mie = 0). This can cause unexpected interrupts + during CPU retention or within critical sections. + + Workarounds are implemented in the IDF codebase. However, if user code + directly disables interrupts, additional actions may be required. Refer + to code examples under the SOC_CPU_ZCMP_WORKAROUND macro, or disable + the ZCMP extension for source files that contain functions which may + execute while mstatus.mie = 0. + + Even with these workarounds, the issue may still affect dual-core variants. + choice COMPILER_OPTIMIZATION_ASSERTION_LEVEL prompt "Assertion level" default COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index 42c939439c..ea129c51b8 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -487,6 +487,14 @@ config SOC_CPU_ZCMP_WORKAROUND bool default y +config SOC_CPU_ZCMP_PUSH_REVERSED + bool + default y + +config SOC_CPU_ZCMP_POPRET_ISSUE + bool + default y + config SOC_DS_SIGNATURE_MAX_BIT_LEN int default 3072 diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index bbfa5049d3..de6a2f2a4b 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -183,6 +183,8 @@ #define SOC_CPU_HAS_LOCKUP_RESET 1 #define SOC_CPU_ZCMP_WORKAROUND 1 +#define SOC_CPU_ZCMP_PUSH_REVERSED 1 +#define SOC_CPU_ZCMP_POPRET_ISSUE 1 /*-------------------------- DIGITAL SIGNATURE CAPS ----------------------------------------*/ /** The maximum length of a Digital Signature in bits. */ diff --git a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in index 981bbdbb43..c3c05850ce 100644 --- a/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c61/include/soc/Kconfig.soc_caps.in @@ -375,6 +375,14 @@ config SOC_CPU_ZCMP_WORKAROUND bool default y +config SOC_CPU_ZCMP_PUSH_REVERSED + bool + default y + +config SOC_CPU_ZCMP_POPRET_ISSUE + bool + default y + config SOC_DMA_CAN_ACCESS_FLASH bool default y diff --git a/components/soc/esp32c61/include/soc/soc_caps.h b/components/soc/esp32c61/include/soc/soc_caps.h index 593688cb7d..805e215e43 100644 --- a/components/soc/esp32c61/include/soc/soc_caps.h +++ b/components/soc/esp32c61/include/soc/soc_caps.h @@ -150,6 +150,8 @@ #define SOC_CPU_HAS_LOCKUP_RESET 1 #define SOC_CPU_ZCMP_WORKAROUND 1 +#define SOC_CPU_ZCMP_PUSH_REVERSED 1 +#define SOC_CPU_ZCMP_POPRET_ISSUE 1 /*-------------------------- DMA Common CAPS ----------------------------------------*/ #define SOC_DMA_CAN_ACCESS_FLASH 1 /*!< DMA can access Flash memory */ diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index 07b3e737bd..f92bfc85a1 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -243,10 +243,26 @@ config SOC_CPU_HAS_LOCKUP_RESET bool default y +config SOC_CPU_HAS_ZC_EXTENSIONS + bool + default y + +config SOC_CPU_HAS_ZB_EXTENSIONS + bool + default y + config SOC_CPU_ZCMP_WORKAROUND bool default y +config SOC_CPU_ZCMP_PUSH_REVERSED + bool + default y + +config SOC_CPU_ZCMP_POPRET_ISSUE + bool + default y + config SOC_DMA_CAN_ACCESS_FLASH bool default y diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index c75f19e62b..f450cd13b9 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -175,7 +175,12 @@ #define SOC_HP_CPU_HAS_MULTIPLE_CORES 1 // Convenience boolean macro used to determine if a target has multiple cores. #define SOC_CPU_HAS_LOCKUP_RESET 1 +#define SOC_CPU_HAS_ZC_EXTENSIONS 1 +#define SOC_CPU_HAS_ZB_EXTENSIONS 1 + #define SOC_CPU_ZCMP_WORKAROUND 1 +#define SOC_CPU_ZCMP_PUSH_REVERSED 1 +#define SOC_CPU_ZCMP_POPRET_ISSUE 1 /*-------------------------- DMA Common CAPS ----------------------------------------*/ #define SOC_DMA_CAN_ACCESS_FLASH 1 /*!< DMA can access Flash memory */ diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index f31e3ce091..443ce7b29e 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -591,6 +591,18 @@ config SOC_CPU_HAS_LOCKUP_RESET bool default y +config SOC_CPU_HAS_ZC_EXTENSIONS + bool + default y + +config SOC_CPU_ZCMP_PUSH_REVERSED + bool + default y + +config SOC_CPU_ZCMP_POPRET_ISSUE + bool + default y + config SOC_SIMD_PREFERRED_DATA_ALIGNMENT int default 16 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index f08017df86..f789680260 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -209,6 +209,11 @@ #define SOC_CPU_HAS_LOCKUP_RESET 1 +#define SOC_CPU_HAS_ZC_EXTENSIONS 1 + +#define SOC_CPU_ZCMP_PUSH_REVERSED 1 +#define SOC_CPU_ZCMP_POPRET_ISSUE 1 + #define SOC_SIMD_PREFERRED_DATA_ALIGNMENT 16 // The preferred data alignment accepted by the SIMD instructions, in bytes /*-------------------------- DIGITAL SIGNATURE CAPS ----------------------------------------*/ diff --git a/components/soc/project_include.cmake b/components/soc/project_include.cmake index bbc288c281..624e16fbcb 100644 --- a/components/soc/project_include.cmake +++ b/components/soc/project_include.cmake @@ -34,7 +34,27 @@ if(CONFIG_IDF_TOOLCHAIN_GCC) endif() # Clean compile options that were added by previous configurations and may be outdated - idf_toolchain_remove_flags(COMPILE_OPTIONS "-march=") + idf_toolchain_remove_flags(COMPILE_OPTIONS "-march=" + "-mno-cm-push-reverse" + "-mno-cm-popret") + + if(CONFIG_SOC_CPU_HAS_ZB_EXTENSIONS) + set(_march "${_march}_zba_zbb_zbs") + endif() + + if((CONFIG_SOC_CPU_HAS_ZC_EXTENSIONS AND NOT CONFIG_SOC_CPU_ZCMP_WORKAROUND) OR + CONFIG_COMPILER_ENABLE_RISCV_ZCMP) + if(NOT CONFIG_ESP32P4_SELECTS_REV_LESS_V3) + set(_march "${_march}_zcb_zcmp_zcmt") + + if(CONFIG_SOC_CPU_ZCMP_PUSH_REVERSED) + idf_toolchain_add_flags(COMPILE_OPTIONS "-mno-cm-push-reverse") + endif() + if(CONFIG_SOC_CPU_ZCMP_POPRET_ISSUE) + idf_toolchain_add_flags(COMPILE_OPTIONS "-mno-cm-popret") + endif() + endif() + endif() if(CONFIG_SOC_CPU_HAS_HWLOOP) set(_march "${_march}_xesploop") diff --git a/docs/en/api-guides/performance/size.rst b/docs/en/api-guides/performance/size.rst index 23c0b1e196..3731368ae7 100644 --- a/docs/en/api-guides/performance/size.rst +++ b/docs/en/api-guides/performance/size.rst @@ -91,6 +91,7 @@ The following configuration options reduces the final binary size of almost any - Setting :ref:`CONFIG_ESP_SYSTEM_PANIC` to ``Silent reboot`` saves a small amount of binary size, however this is **only** recommended if no one will use UART output to debug the device. :CONFIG_IDF_TARGET_ARCH_RISCV: - Setting :ref:`CONFIG_COMPILER_SAVE_RESTORE_LIBCALLS` reduces binary size by replacing inlined prologues/epilogues with library calls. - If the application binary uses only one of the security versions of the protocomm component, then the support for others can be disabled to save some code size. The support can be disabled through :ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_0`, :ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_1` or :ref:`CONFIG_ESP_PROTOCOMM_SUPPORT_SECURITY_VERSION_2` respectively. + :CONFIG_SOC_CPU_ZCMP_WORKAROUND: - Enable :ref:`CONFIG_COMPILER_ENABLE_RISCV_ZCMP` to reduce binary size by using compressed function prologues/epilogues. Read the :ref:`CONFIG_COMPILER_ENABLE_RISCV_ZCMP` notes carefully before enabling this option! .. note::