From 5f9e3bffe2d561e3c4156f45c35ae4e1974488c6 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 5ba808b0149..3fbc29f2f88 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 0e1520c13de..c6371b29924 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 92c4c0b7174..0388cc32343 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 c07f5dd57bb..c7accb18e69 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 aa80b52f2c4..151933d1b36 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 c23b67815d5..0c9a6e67b7c 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -239,10 +239,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 3724366db66..5da9b0ad0af 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 03b0e380f51..01ab358478b 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 d4a867d830e..5ce94797899 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 bbc288c2817..624e16fbcba 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 23c0b1e1969..3731368ae7b 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::