| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- Programming ULP coprocessor using C macros
- ==========================================
- In addition to the existing binutils port for the ESP32 ULP coprocessor, it is possible to generate programs for the ULP by embedding assembly-like macros into an ESP32 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.
- 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);
- 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
- .. doxygendefine:: I_LD
- .. doxygendefine:: I_WR_REG
- .. doxygendefine:: I_RD_REG
- .. doxygendefine:: I_BL
- .. doxygendefine:: I_BGE
- .. 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
- .. doxygendefine:: M_BGE
- .. doxygendefine:: M_BX
- .. doxygendefine:: M_BXZ
- .. doxygendefine:: M_BXF
- Defines
- ^^^^^^^
- .. doxygendefine:: RTC_SLOW_MEM
|