esp-idf/components/ulp
Sudeep Mohanty 4d8a0cce29 ulp: Added support for ULP FSM on esp32s3 and fixed bugs for esp32s2
This commit enables ULP FSM support for esp32s3 and updates ULP FSM code
flow for other chips.
It adds C Macro support for the ULP FSM instruction set on esp32s2 and
esp32s3.
The unit tests are also updated to test ULP FSM on ep32s2 and esp32s3.
2022-02-22 12:25:57 +05:30
..
cmake ulp: Added support for ULP FSM on esp32s3 and fixed bugs for esp32s2 2022-02-22 12:25:57 +05:30
ld ulp: refactor ulp component 2022-01-27 11:54:42 +05:30
test ulp: Added support for ULP FSM on esp32s3 and fixed bugs for esp32s2 2022-02-22 12:25:57 +05:30
ulp_common ulp: Added support for ULP FSM on esp32s3 and fixed bugs for esp32s2 2022-02-22 12:25:57 +05:30
ulp_fsm ulp: Added support for ULP FSM on esp32s3 and fixed bugs for esp32s2 2022-02-22 12:25:57 +05:30
ulp_riscv ulp: change deprecated headers to use relative includes to avoid recursivly including the same header 2022-02-11 14:56:11 +08:00
CMakeLists.txt ulp: Added support for ULP FSM on esp32s3 and fixed bugs for esp32s2 2022-02-22 12:25:57 +05:30
component_ulp_common.cmake ulp: use quotes when specifying files for embedding ulp binaries 2020-02-18 00:12:56 +00:00
esp32ulp_mapgen.py Drop support for unsupported Python versions 2021-06-21 21:48:49 +02:00
Kconfig ulp: refactor ulp component 2022-01-27 11:54:42 +05:30
project_include.cmake ulp: refactor ulp component 2022-01-27 11:54:42 +05:30
README.rst ulp: Added support for ULP FSM on esp32s3 and fixed bugs for esp32s2 2022-02-22 12:25:57 +05:30
toolchain_ulp_version.mk Whitespace: Automated whitespace fixes (large commit) 2020-11-11 07:36:35 +00:00

Programming ULP FSM coprocessor using C macros (legacy)
=======================================================

In addition to the existing binutils port for the {IDF_TARGET_NAME} ULP coprocessor, it is possible to generate programs for the ULP by embedding assembly-like macros into an {IDF_TARGET_NAME} application. Here is an example how this can be done::

    const ulp_insn_t program[] = {
        I_MOVI(R3, 16),         // R3 <- 16
        I_LD(R0, R3, 0),        // R0 <- RTC_SLOW_MEM[R3 + 0]
        I_LD(R1, R3, 1),        // R1 <- RTC_SLOW_MEM[R3 + 1]
        I_ADDR(R2, R0, R1),     // R2 <- R0 + R1
        I_ST(R2, R3, 2),        // R2 -> RTC_SLOW_MEM[R2 + 2]
        I_HALT()
    };
    size_t load_addr = 0;
    size_t size = sizeof(program)/sizeof(ulp_insn_t);
    ulp_process_macros_and_load(load_addr, program, &size);
    ulp_run(load_addr);

The ``program`` array is an array of ``ulp_insn_t``, i.e. ULP coprocessor instructions. Each ``I_XXX`` preprocessor define translates into a single 32-bit instruction. Arguments of these preprocessor defines can be register numbers (``R0 — R3``) and literal constants. See `ULP coprocessor instruction defines`_ section for descriptions of instructions and arguments they take.

.. note::

    Because some of the instruction macros expand to inline function calls, defining such array in global scope will cause the compiler to produce an "initializer element is not constant" error. To fix this error, move the definition of instructions array into local scope.

Load and store instructions use addresses expressed in 32-bit words. Address 0 corresponds to the first word of ``RTC_SLOW_MEM`` (which is address 0x50000000 as seen by the main CPUs).

To generate branch instructions, special ``M_`` preprocessor defines are used. ``M_LABEL`` define can be used to define a branch target. Label identifier is a 16-bit integer. ``M_Bxxx`` defines can be used to generate branch instructions with target set to a particular label.

Implementation note: these ``M_`` preprocessor defines will be translated into two ``ulp_insn_t`` values: one is a token value which contains label number, and the other is the actual instruction. ``ulp_process_macros_and_load`` function resolves the label number to the address, modifies the branch instruction to use the correct address, and removes the the extra ``ulp_insn_t`` token which contains the label numer.

Here is an example of using labels and branches::

    const ulp_insn_t program[] = {
        I_MOVI(R0, 34),         // R0 <- 34
        M_LABEL(1),             // label_1
        I_MOVI(R1, 32),         // R1 <- 32
        I_LD(R1, R1, 0),        // R1 <- RTC_SLOW_MEM[R1]
        I_MOVI(R2, 33),         // R2 <- 33
        I_LD(R2, R2, 0),        // R2 <- RTC_SLOW_MEM[R2]
        I_SUBR(R3, R1, R2),     // R3 <- R1 - R2
        I_ST(R3, R0, 0),        // R3 -> RTC_SLOW_MEM[R0 + 0]
        I_ADDI(R0, R0, 1),      // R0++
        M_BL(1, 64),            // if (R0 < 64) goto label_1
        I_HALT(),
    };
    RTC_SLOW_MEM[32] = 42;
    RTC_SLOW_MEM[33] = 18;
    size_t load_addr = 0;
    size_t size = sizeof(program)/sizeof(ulp_insn_t);
    ulp_process_macros_and_load(load_addr, program, &size);
    ulp_run(load_addr);


Application Example
-------------------

Demonstration of entering into deep sleep mode and waking up using several wake up sources: :example:`system/deep_sleep`.


API Reference
-------------

Header File
^^^^^^^^^^^

.. list::

    :esp32: - :component_file:`ulp/ulp_fsm/include/esp32/ulp.h`
    :esp32s2: - :component_file:`ulp/ulp_fsm/include/esp32s2/ulp.h`
    :esp32s3: - :component_file:`ulp/ulp_fsm/include/esp32s3/ulp.h`

Functions
^^^^^^^^^

.. doxygenfunction:: ulp_process_macros_and_load
.. doxygenfunction:: ulp_run

Error codes
^^^^^^^^^^^

.. doxygendefine:: ESP_ERR_ULP_BASE
.. doxygendefine:: ESP_ERR_ULP_SIZE_TOO_BIG
.. doxygendefine:: ESP_ERR_ULP_INVALID_LOAD_ADDR
.. doxygendefine:: ESP_ERR_ULP_DUPLICATE_LABEL
.. doxygendefine:: ESP_ERR_ULP_UNDEFINED_LABEL
.. doxygendefine:: ESP_ERR_ULP_BRANCH_OUT_OF_RANGE

ULP coprocessor registers
^^^^^^^^^^^^^^^^^^^^^^^^^

ULP co-processor has 4 16-bit general purpose registers. All registers have same functionality, with one exception. R0 register is used by some of the compare-and-branch instructions as a source register.

These definitions can be used for all instructions which require a register.

.. doxygengroup:: ulp_registers
    :content-only:

ULP coprocessor instruction defines
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. doxygendefine:: I_DELAY
.. doxygendefine:: I_HALT
.. doxygendefine:: I_END
.. doxygendefine:: I_ST
.. only:: esp32s2 or esp32s3

    .. doxygendefine:: I_ST_MANUAL
    .. doxygendefine:: I_STL
    .. doxygendefine:: I_STH
    .. doxygendefine:: I_ST32
    .. doxygendefine:: I_STL_LABEL
    .. doxygendefine:: I_STH_LABEL
    .. doxygendefine:: I_ST_AUTO
    .. doxygendefine:: I_STO
    .. doxygendefine:: I_STI
    .. doxygendefine:: I_STI_LABEL
    .. doxygendefine:: I_STI32

.. doxygendefine:: I_LD
.. only:: esp32s2 or esp32s3

    .. doxygendefine:: I_LD_MANUAL
    .. doxygendefine:: I_LDL
    .. doxygendefine:: I_LDH

.. doxygendefine:: I_WR_REG
.. doxygendefine:: I_RD_REG
.. doxygendefine:: I_BL
.. only:: esp32

    .. doxygendefine:: I_BGE

.. only:: esp32s2 or esp32s3

    .. doxygendefine:: I_BG
    .. doxygendefine:: I_BE

.. doxygendefine:: I_BXR
.. doxygendefine:: I_BXI
.. doxygendefine:: I_BXZR
.. doxygendefine:: I_BXZI
.. doxygendefine:: I_BXFR
.. doxygendefine:: I_BXFI
.. doxygendefine:: I_ADDR
.. doxygendefine:: I_SUBR
.. doxygendefine:: I_ANDR
.. doxygendefine:: I_ORR
.. doxygendefine:: I_MOVR
.. doxygendefine:: I_LSHR
.. doxygendefine:: I_RSHR
.. doxygendefine:: I_ADDI
.. doxygendefine:: I_SUBI
.. doxygendefine:: I_ANDI
.. doxygendefine:: I_ORI
.. doxygendefine:: I_MOVI
.. doxygendefine:: I_LSHI
.. doxygendefine:: I_RSHI
.. doxygendefine:: M_LABEL
.. doxygendefine:: M_BL
.. only:: esp32

    .. doxygendefine:: M_BGE

.. only:: esp32s2 or esp32s3

    .. doxygendefine:: M_BG
    .. doxygendefine:: M_BE

.. doxygendefine:: M_BX
.. doxygendefine:: M_BXZ
.. doxygendefine:: M_BXF

Defines
^^^^^^^

.. doxygendefine:: RTC_SLOW_MEM