From da731a7eeb0740f3c7e3094b3e4bf4ccf7e61d04 Mon Sep 17 00:00:00 2001 From: Omar Chebib Date: Tue, 8 Jun 2021 18:44:01 +0800 Subject: [PATCH] psram: add configuration macros to move workaround libc functions to flash Workaround libc can be moved to flash thanks to KConfig macros. However, the following functions: `itoa`, `memcmp`, `memcpy`, `memset`, `strcat`, `strcmp`, and `strlen` are always kept it in IRAM. --- components/esp32/Kconfig | 121 ++++++++ .../newlib/esp32-spiram-rom-functions-c.lf | 268 ++++++++++-------- docs/en/api-guides/performance/ram-usage.rst | 21 ++ 3 files changed, 288 insertions(+), 122 deletions(-) diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index c75f9e277a..2d7cdbdae0 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -169,8 +169,129 @@ menu "ESP32-specific" config SPIRAM_WORKAROUND_NEED_VOLATILE_SPINLOCK bool default "y" if SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST + endmenu + menu "SPIRAM workaround libraries placement" + visible if SPIRAM_CACHE_WORKAROUND + config SPIRAM_CACHE_LIBJMP_IN_IRAM + bool "Put libc's jump related functions in IRAM" + depends on SPIRAM_CACHE_WORKAROUND + default "y" + help + The functions affected by this option are: longjmp and setjmp. + Putting these function in IRAM will allow them to be called when flash cache is disabled + but it will also reduce the available size of free IRAM for the user application. + + config SPIRAM_CACHE_LIBMATH_IN_IRAM + bool "Put libc's math related functions in IRAM" + depends on SPIRAM_CACHE_WORKAROUND + default "y" + help + The functions affected by this option are: abs, div, labs, ldiv, quorem, fpclassify, + and nan. + Putting these function in IRAM will allow them to be called when flash cache is disabled + but it will also reduce the available size of free IRAM for the user application. + + config SPIRAM_CACHE_LIBNUMPARSER_IN_IRAM + bool "Put libc's number parsing related functions in IRAM" + depends on SPIRAM_CACHE_WORKAROUND + default "y" + help + The functions affected by this option are: utoa, itoa, atoi, atol, strtol, and strtoul. + Putting these function in IRAM will allow them to be called when flash cache is disabled + but it will also reduce the available size of free IRAM for the user application. + + config SPIRAM_CACHE_LIBIO_IN_IRAM + bool "Put libc's I/O related functions in IRAM" + depends on SPIRAM_CACHE_WORKAROUND + default "y" + help + The functions affected by this option are: wcrtomb, fvwrite, wbuf, wsetup, fputwc, wctomb_r, + ungetc, makebuf, fflush, refill, and sccl. + Putting these function in IRAM will allow them to be called when flash cache is disabled + but it will also reduce the available size of free IRAM for the user application. + + config SPIRAM_CACHE_LIBTIME_IN_IRAM + bool "Put libc's time related functions in IRAM" + depends on SPIRAM_CACHE_WORKAROUND + default "y" + help + The functions affected by this option are: asctime, asctime_r, ctime, ctime_r, lcltime, lcltime_r, + gmtime, gmtime_r, strftime, mktime, tzset_r, tzset, time, gettzinfo, systimes, month_lengths, + timelocal, tzvars, tzlock, tzcalc_limits, and strptime. + Putting these function in IRAM will allow them to be called when flash cache is disabled + but it will also reduce the available size of free IRAM for the user application. + + config SPIRAM_CACHE_LIBCHAR_IN_IRAM + bool "Put libc's characters related functions in IRAM" + depends on SPIRAM_CACHE_WORKAROUND + default "y" + help + The functions affected by this option are: ctype_, toupper, tolower, toascii, strupr, bzero, + isalnum, isalpha, isascii, isblank, iscntrl, isdigit, isgraph, islower, isprint, ispunct, + isspace, and isupper. + Putting these function in IRAM will allow them to be called when flash cache is disabled + but it will also reduce the available size of free IRAM for the user application. + + config SPIRAM_CACHE_LIBMEM_IN_IRAM + bool "Put libc's memory related functions in IRAM" + depends on SPIRAM_CACHE_WORKAROUND + default "y" + help + The functions affected by this option are: memccpy, memchr memmove, and memrchr. + Putting these function in IRAM will allow them to be called when flash cache is disabled + but it will also reduce the available size of free IRAM for the user application. + + config SPIRAM_CACHE_LIBSTR_IN_IRAM + bool "Put libc's string related functions in IRAM" + depends on SPIRAM_CACHE_WORKAROUND + default "y" + help + The functions affected by this option are: strcasecmp, strcasestr, strchr, strcoll, + strcpy, strcspn, strdup, strdup_r, strlcat, strlcpy, strlen, strlwr, strncasecmp, + strncat, strncmp, strncpy, strndup, strndup_r, strrchr, strsep, strspn, strstr, + strtok_r, and strupr. + Putting these function in IRAM will allow them to be called when flash cache is disabled + but it will also reduce the available size of free IRAM for the user application. + + config SPIRAM_CACHE_LIBRAND_IN_IRAM + bool "Put libc's random related functions in IRAM" + depends on SPIRAM_CACHE_WORKAROUND + default "y" + help + The functions affected by this option are: srand, rand, and rand_r. + Putting these function in IRAM will allow them to be called when flash cache is disabled + but it will also reduce the available size of free IRAM for the user application. + + config SPIRAM_CACHE_LIBENV_IN_IRAM + bool "Put libc's environment related functions in IRAM" + depends on SPIRAM_CACHE_WORKAROUND + default "y" + help + The functions affected by this option are: environ, envlock, and getenv_r. + Putting these function in IRAM will allow them to be called when flash cache is disabled + but it will also reduce the available size of free IRAM for the user application. + + config SPIRAM_CACHE_LIBFILE_IN_IRAM + bool "Put libc's file related functions in IRAM" + depends on SPIRAM_CACHE_WORKAROUND + default "y" + help + The functions affected by this option are: lock, isatty, fclose, open, close, creat, read, + rshift, sbrk, stdio, syssbrk, sysclose, sysopen, creat, sysread, syswrite, impure, fwalk, + and findfp. + Putting these function in IRAM will allow them to be called when flash cache is disabled + but it will also reduce the available size of free IRAM for the user application. + + config SPIRAM_CACHE_LIBMISC_IN_IRAM + bool "Put libc's miscellaneous functions in IRAM, see help" + depends on SPIRAM_CACHE_WORKAROUND + default "y" + help + The functions affected by this option are: raise and system + Putting these function in IRAM will allow them to be called when flash cache is disabled + but it will also reduce the available size of free IRAM for the user application. endmenu config SPIRAM_BANKSWITCH_ENABLE diff --git a/components/newlib/esp32-spiram-rom-functions-c.lf b/components/newlib/esp32-spiram-rom-functions-c.lf index 27e5f5f3ea..2275619693 100644 --- a/components/newlib/esp32-spiram-rom-functions-c.lf +++ b/components/newlib/esp32-spiram-rom-functions-c.lf @@ -16,132 +16,156 @@ archive: libc.a entries: if SPIRAM_CACHE_WORKAROUND = y: - lib_a-utoa (noflash) - lib_a-longjmp (noflash) - lib_a-setjmp (noflash) - lib_a-abs (noflash) - lib_a-div (noflash) - lib_a-labs (noflash) - lib_a-ldiv (noflash) - lib_a-quorem (noflash) - lib_a-utoa (noflash) + # The following libs are either used in a lot of places or in critical + # code. (such as panic or abort) + # Thus, they shall always be placed in IRAM. lib_a-itoa (noflash) - lib_a-atoi (noflash) - lib_a-atol (noflash) - lib_a-strtol (noflash) - lib_a-strtoul (noflash) - lib_a-wcrtomb (noflash) - lib_a-fvwrite (noflash) - lib_a-wbuf (noflash) - lib_a-wsetup (noflash) - lib_a-fputwc (noflash) - lib_a-wctomb_r (noflash) - lib_a-ungetc (noflash) - lib_a-makebuf (noflash) - lib_a-fflush (noflash) - lib_a-refill (noflash) - lib_a-s_fpclassify (noflash) - lib_a-asctime (noflash) - lib_a-ctime (noflash) - lib_a-ctime_r (noflash) - lib_a-lcltime (noflash) - lib_a-lcltime_r (noflash) - lib_a-gmtime (noflash) - lib_a-gmtime_r (noflash) - lib_a-strftime (noflash) - lib_a-mktime (noflash) - lib_a-syswrite (noflash) - lib_a-tzset_r (noflash) - lib_a-tzset (noflash) - lib_a-toupper (noflash) - lib_a-tolower (noflash) - lib_a-toascii (noflash) - lib_a-systimes (noflash) - lib_a-time (noflash) - lib_a-gettzinfo (noflash) - lib_a-strupr (noflash) - lib_a-asctime_r (noflash) - lib_a-bzero (noflash) - lib_a-close (noflash) - lib_a-creat (noflash) - lib_a-environ (noflash) - lib_a-fclose (noflash) - lib_a-isalnum (noflash) - lib_a-isalpha (noflash) - lib_a-isascii (noflash) - lib_a-isblank (noflash) - lib_a-iscntrl (noflash) - lib_a-isdigit (noflash) - lib_a-isgraph (noflash) - lib_a-islower (noflash) - lib_a-isprint (noflash) - lib_a-ispunct (noflash) - lib_a-isspace (noflash) - lib_a-isupper (noflash) - lib_a-memccpy (noflash) - lib_a-memchr (noflash) lib_a-memcmp (noflash) lib_a-memcpy (noflash) - lib_a-memmove (noflash) - lib_a-memrchr (noflash) lib_a-memset (noflash) - lib_a-open (noflash) - lib_a-rand (noflash) - lib_a-rand_r (noflash) - lib_a-read (noflash) - lib_a-rshift (noflash) - lib_a-sbrk (noflash) - lib_a-srand (noflash) - lib_a-strcasecmp (noflash) - lib_a-strcasestr (noflash) lib_a-strcat (noflash) - lib_a-strchr (noflash) lib_a-strcmp (noflash) - lib_a-strcoll (noflash) - lib_a-strcpy (noflash) - lib_a-strcspn (noflash) - lib_a-strdup (noflash) - lib_a-strlcat (noflash) - lib_a-strlcpy (noflash) lib_a-strlen (noflash) - lib_a-strlwr (noflash) - lib_a-strncasecmp (noflash) - lib_a-strncat (noflash) - lib_a-strncmp (noflash) - lib_a-strncpy (noflash) - lib_a-strndup (noflash) - lib_a-strnlen (noflash) - lib_a-strrchr (noflash) - lib_a-strsep (noflash) - lib_a-strspn (noflash) - lib_a-strstr (noflash) - lib_a-strtok_r (noflash) - lib_a-strupr (noflash) - lib_a-stdio (noflash) - lib_a-syssbrk (noflash) - lib_a-sysclose (noflash) - lib_a-sysopen (noflash) - creat (noflash) - lib_a-sysread (noflash) - lib_a-syswrite (noflash) - lib_a-impure (noflash) - lib_a-tzvars (noflash) - lib_a-sf_nan (noflash) - lib_a-tzcalc_limits (noflash) - lib_a-month_lengths (noflash) - lib_a-timelocal (noflash) - lib_a-findfp (noflash) - lock (noflash) - lib_a-getenv_r (noflash) - isatty (noflash) - lib_a-fwalk (noflash) - lib_a-getenv_r (noflash) - lib_a-tzlock (noflash) - lib_a-ctype_ (noflash) - lib_a-sccl (noflash) - lib_a-strptime (noflash) - lib_a-envlock (noflash) - lib_a-raise (noflash) - lib_a-strdup_r (noflash) - lib_a-system (noflash) - lib_a-strndup_r (noflash) + + if SPIRAM_CACHE_LIBJMP_IN_IRAM = y: + lib_a-longjmp (noflash) + lib_a-setjmp (noflash) + + if SPIRAM_CACHE_LIBMATH_IN_IRAM = y: + lib_a-abs (noflash) + lib_a-div (noflash) + lib_a-labs (noflash) + lib_a-ldiv (noflash) + lib_a-quorem (noflash) + lib_a-s_fpclassify (noflash) + lib_a-sf_nan (noflash) + + if SPIRAM_CACHE_LIBNUMPARSER_IN_IRAM = y: + lib_a-utoa (noflash) + lib_a-atoi (noflash) + lib_a-atol (noflash) + lib_a-strtol (noflash) + lib_a-strtoul (noflash) + + if SPIRAM_CACHE_LIBIO_IN_IRAM = y: + lib_a-wcrtomb (noflash) + lib_a-fvwrite (noflash) + lib_a-wbuf (noflash) + lib_a-wsetup (noflash) + lib_a-fputwc (noflash) + lib_a-wctomb_r (noflash) + lib_a-ungetc (noflash) + lib_a-makebuf (noflash) + lib_a-fflush (noflash) + lib_a-refill (noflash) + lib_a-sccl (noflash) + + if SPIRAM_CACHE_LIBTIME_IN_IRAM = y: + lib_a-asctime (noflash) + lib_a-asctime_r (noflash) + lib_a-ctime (noflash) + lib_a-ctime_r (noflash) + lib_a-lcltime (noflash) + lib_a-lcltime_r (noflash) + lib_a-gmtime (noflash) + lib_a-gmtime_r (noflash) + lib_a-strftime (noflash) + lib_a-mktime (noflash) + lib_a-tzset_r (noflash) + lib_a-tzset (noflash) + lib_a-time (noflash) + lib_a-gettzinfo (noflash) + lib_a-systimes (noflash) + lib_a-month_lengths (noflash) + lib_a-timelocal (noflash) + lib_a-tzvars (noflash) + lib_a-tzlock (noflash) + lib_a-tzcalc_limits (noflash) + lib_a-strptime (noflash) + + if SPIRAM_CACHE_LIBCHAR_IN_IRAM = y: + lib_a-ctype_ (noflash) + lib_a-toupper (noflash) + lib_a-tolower (noflash) + lib_a-toascii (noflash) + lib_a-strupr (noflash) + lib_a-bzero (noflash) + lib_a-isalnum (noflash) + lib_a-isalpha (noflash) + lib_a-isascii (noflash) + lib_a-isblank (noflash) + lib_a-iscntrl (noflash) + lib_a-isdigit (noflash) + lib_a-isgraph (noflash) + lib_a-islower (noflash) + lib_a-isprint (noflash) + lib_a-ispunct (noflash) + lib_a-isspace (noflash) + lib_a-isupper (noflash) + + if SPIRAM_CACHE_LIBMEM_IN_IRAM = y: + lib_a-memccpy (noflash) + lib_a-memchr (noflash) + lib_a-memmove (noflash) + lib_a-memrchr (noflash) + + if SPIRAM_CACHE_LIBSTR_IN_IRAM = y: + lib_a-strcasecmp (noflash) + lib_a-strcasestr (noflash) + lib_a-strchr (noflash) + lib_a-strcoll (noflash) + lib_a-strcpy (noflash) + lib_a-strcspn (noflash) + lib_a-strdup (noflash) + lib_a-strdup_r (noflash) + lib_a-strlcat (noflash) + lib_a-strlcpy (noflash) + lib_a-strlwr (noflash) + lib_a-strncasecmp (noflash) + lib_a-strncat (noflash) + lib_a-strncmp (noflash) + lib_a-strncpy (noflash) + lib_a-strndup (noflash) + lib_a-strndup_r (noflash) + lib_a-strnlen (noflash) + lib_a-strrchr (noflash) + lib_a-strsep (noflash) + lib_a-strspn (noflash) + lib_a-strstr (noflash) + lib_a-strtok_r (noflash) + lib_a-strupr (noflash) + + if SPIRAM_CACHE_LIBRAND_IN_IRAM = y: + lib_a-srand (noflash) + lib_a-rand (noflash) + lib_a-rand_r (noflash) + + if SPIRAM_CACHE_LIBENV_IN_IRAM = y: + lib_a-environ (noflash) + lib_a-envlock (noflash) + lib_a-getenv_r (noflash) + + if SPIRAM_CACHE_LIBFILE_IN_IRAM = y: + lock (noflash) + isatty (noflash) + lib_a-fclose (noflash) + lib_a-open (noflash) + lib_a-close (noflash) + lib_a-creat (noflash) + lib_a-read (noflash) + lib_a-rshift (noflash) + lib_a-sbrk (noflash) + lib_a-stdio (noflash) + lib_a-syssbrk (noflash) + lib_a-sysclose (noflash) + lib_a-sysopen (noflash) + creat (noflash) + lib_a-sysread (noflash) + lib_a-syswrite (noflash) + lib_a-impure (noflash) + lib_a-fwalk (noflash) + lib_a-findfp (noflash) + + if SPIRAM_CACHE_LIBMISC_IN_IRAM = y: + lib_a-raise (noflash) + lib_a-system (noflash) diff --git a/docs/en/api-guides/performance/ram-usage.rst b/docs/en/api-guides/performance/ram-usage.rst index 2794492bae..96d3560170 100644 --- a/docs/en/api-guides/performance/ram-usage.rst +++ b/docs/en/api-guides/performance/ram-usage.rst @@ -136,6 +136,27 @@ The following options will reduce IRAM usage of some ESP-IDF features: - Disabling :ref:`CONFIG_SPI_MASTER_ISR_IN_IRAM` prevents spi_master interrupts from being serviced while writing to flash, and may otherwise reduce spi_master performance, but will save some IRAM. - Setting :ref:`CONFIG_HAL_DEFAULT_ASSERTION_LEVEL` to disable assertion for HAL component will save some IRAM especially for HAL code who calls `HAL_ASSERT` a lot and resides in IRAM. +.. only:: esp32 + + When compiling for ESP32 revisions older than ECO3 (:ref:`CONFIG_ESP32_REV_MIN`), PSRAM cache bug workaround (:ref:`CONFIG_SPIRAM_CACHE_WORKAROUND`) option is enabled, and the C library functions normally located in ROM are recompiled with the workaround and placed into IRAM instead. For most applications, it is safe to move many of the C library functions into Flash, reclaiming some IRAM. Corresponding options include: + + .. list:: + + - :ref:`CONFIG_SPIRAM_CACHE_LIBJMP_IN_IRAM`: affects the functions ``longjmp`` and ``setjump``. + - :ref:`CONFIG_SPIRAM_CACHE_LIBMATH_IN_IRAM`: affects the functions ``abs``, ``div``, ``labs``, ``ldiv``, ``quorem``, ``fpclassify`` and ``nan``. + - :ref:`CONFIG_SPIRAM_CACHE_LIBNUMPARSER_IN_IRAM`: affects the functions ``utoa``, ``itoa``, ``atoi``, ``atol``, ``strtol``, and ``strtoul``. + - :ref:`CONFIG_SPIRAM_CACHE_LIBIO_IN_IRAM`: affects the functions ``wcrtomb``, ``fvwrite``, ``wbuf``, ``wsetup``, ``fputwc``, ``wctomb_r``, ``ungetc``, ``makebuf``, ``fflush``, ``refill``, and ``sccl``. + - :ref:`CONFIG_SPIRAM_CACHE_LIBTIME_IN_IRAM`: affects the functions ``asctime``, ``asctime_r``, ``ctime``, ``ctime_r``, ``lcltime``, ``lcltime_r``, ``gmtime``, ``gmtime_r``, ``strftime``, ``mktime``, ``tzset_r``, ``tzset``, ``time``, ``gettzinfo``, ``systimes``, ``month_lengths``, ``timelocal``, ``tzvars``, ``tzlock``, ``tzcalc_limits``, and ``strptime``. + - :ref:`CONFIG_SPIRAM_CACHE_LIBCHAR_IN_IRAM`: affects the functions ``ctype_``, ``toupper``, ``tolower``, ``toascii``, ``strupr``, ``bzero``, ``isalnum``, ``isalpha``, ``isascii``, ``isblank``, ``iscntrl``, ``isdigit``, ``isgraph``, ``islower``, ``isprint``, ``ispunct``, ``isspace``, and ``isupper``. + - :ref:`CONFIG_SPIRAM_CACHE_LIBMEM_IN_IRAM`: affects the functions ``memccpy``, ``memchr``, ``memmove``, and ``memrchr``. + - :ref:`CONFIG_SPIRAM_CACHE_LIBSTR_IN_IRAM`: affects the functions ``strcasecmp``, ``strcasestr``, ``strchr``, ``strcoll``, ``strcpy``, ``strcspn``, ``strdup``, ``strdup_r``, ``strlcat``, ``strlcpy``, ``strlen``, ``strlwr``, ``strncasecmp``, ``strncat``, ``strncmp``, ``strncpy``, ``strndup``, ``strndup_r``, ``strrchr``, ``strsep``, ``strspn``, ``strstr``, ``strtok_r, and ``strupr``. + - :ref:`CONFIG_SPIRAM_CACHE_LIBRAND_IN_IRAM`: affects the functions ``srand``, ``rand``, and ``rand_r``. + - :ref:`CONFIG_SPIRAM_CACHE_LIBENV_IN_IRAM`: affects the functions ``environ``, ``envlock``, and ``getenv_r``. + - :ref:`CONFIG_SPIRAM_CACHE_LIBFILE_IN_IRAM`: affects the functions lock``, ``isatty``, ``fclose``, ``open``, ``close``, ``creat``, ``read``, ``rshift``, ``sbrk``, ``stdio``, ``syssbrk``, ``sysclose``, ``sysopen``, ``creat``, ``sysread``, ``syswrite``, ``impure``, ``fwalk``, and ``findfp``. + - :ref:`CONFIG_SPIRAM_CACHE_LIBMISC_IN_IRAM`: affects the functions ``raise`` and ``system``. + + The exact amount of IRAM saved will depend on how much C library code is actually used by the application. In addition to these, the following options may be used to move more of the C library code into Flash, however note that this may result in reduced performance. Also take care to not use corresponding C library functions from interrupts which may be called while cache is disabled (allocated with :c:macro:`ESP_INTR_FLAG_IRAM` flag), refer to :ref:`iram-safe-interrupt-handlers` for more details. For these reasons, the functions ``itoa``, ``memcmp``, ``memcpy``, ``memset``, ``strcat``, ``strcmp``, and ``strlen`` are always put in IRAM. + .. note:: Moving frequently-called functions from IRAM to flash may increase their execution time.