25 #include "esp32/ulp.h" 28 #include "soc/rtc_cntl_reg.h" 29 #include "soc/sens_reg.h" 31 #include "sdkconfig.h" 34 #undef CONFIG_ULP_COPROC_RESERVE_MEM 35 #define CONFIG_ULP_COPROC_RESERVE_MEM 2048 38 static const char* TAG =
"ulp";
47 #define RELOC_TYPE_LABEL 0 48 #define RELOC_TYPE_BRANCH 1 53 #define RELOC_INFO_LABEL(label_num, insn_addr) (reloc_info_t) { \ 57 .type = RELOC_TYPE_LABEL } 63 #define RELOC_INFO_BRANCH(label_num, insn_addr) (reloc_info_t) { \ 67 .type = RELOC_TYPE_BRANCH } 70 static int reloc_sort_func(
const void* p_lhs,
const void* p_rhs)
72 const reloc_info_t lhs = *(
const reloc_info_t*) p_lhs;
73 const reloc_info_t rhs = *(
const reloc_info_t*) p_rhs;
74 if (lhs.label < rhs.label) {
76 }
else if (lhs.label > rhs.label) {
80 if (lhs.type < rhs.type) {
82 }
else if (lhs.type > rhs.type) {
129 static esp_err_t do_single_reloc(ulp_insn_t* program, uint32_t load_addr,
130 reloc_info_t label_info, reloc_info_t branch_info)
132 size_t insn_offset = branch_info.addr - load_addr;
133 ulp_insn_t* insn = &program[insn_offset];
136 assert(insn->b.opcode == OPCODE_BRANCH
137 &&
"branch macro was applied to a non-branch instruction");
138 switch (insn->b.sub_opcode) {
140 int32_t offset = ((int32_t) label_info.addr) - ((int32_t) branch_info.addr);
141 ESP_LOGW(TAG,
"%d\n", offset);
142 uint32_t abs_offset = abs(offset);
143 uint32_t sign = (offset >= 0) ? 0 : 1;
144 if (abs_offset > 127) {
145 ESP_LOGE(TAG,
"target out of range: branch from %x to %x",
146 branch_info.addr, label_info.addr);
147 return ESP_ERR_ULP_BRANCH_OUT_OF_RANGE;
149 insn->b.offset = abs_offset;
153 case SUB_OPCODE_BX: {
154 assert(insn->bx.reg == 0 &&
155 "relocation applied to a jump with offset in register");
156 insn->bx.addr = label_info.addr;
160 assert(
false &&
"unexpected sub-opcode");
165 esp_err_t ulp_process_macros_and_load_ex(uint32_t load_addr,
const ulp_insn_t* program,
size_t* psize)
167 const ulp_insn_t* read_ptr = program;
168 const ulp_insn_t* end = program + *psize;
169 size_t macro_count = 0;
171 while (read_ptr < end) {
172 ulp_insn_t r_insn = *read_ptr;
173 if (r_insn.macro.opcode == OPCODE_MACRO) {
178 size_t real_program_size = *psize - macro_count;
179 const size_t ulp_mem_end = CONFIG_ULP_COPROC_RESERVE_MEM /
sizeof(ulp_insn_t);
180 if (load_addr > ulp_mem_end) {
181 ESP_LOGE(TAG,
"invalid load address %x, max is %x",
182 load_addr, ulp_mem_end);
183 return ESP_ERR_ULP_INVALID_LOAD_ADDR;
185 if (real_program_size + load_addr > ulp_mem_end) {
186 ESP_LOGE(TAG,
"program too big: %d words, max is %d words",
187 real_program_size, ulp_mem_end);
188 return ESP_ERR_ULP_SIZE_TOO_BIG;
191 if (macro_count == 0) {
192 memcpy(((ulp_insn_t*) RTC_SLOW_MEM) + load_addr, program, *psize *
sizeof(ulp_insn_t));
195 reloc_info_t* reloc_info =
196 (reloc_info_t*) malloc(
sizeof(reloc_info_t) * macro_count);
197 if (reloc_info ==
nullptr) {
198 return ESP_ERR_NO_MEM;
204 ulp_insn_t* output_program = ((ulp_insn_t*) RTC_SLOW_MEM) + load_addr;
205 ulp_insn_t* write_ptr = output_program;
206 uint32_t cur_insn_addr = load_addr;
207 reloc_info_t* cur_reloc = reloc_info;
208 while (read_ptr < end) {
209 ulp_insn_t r_insn = *read_ptr;
210 if (r_insn.macro.opcode == OPCODE_MACRO) {
211 switch(r_insn.macro.sub_opcode) {
212 case SUB_OPCODE_MACRO_LABEL:
213 *cur_reloc = RELOC_INFO_LABEL(r_insn.macro.label,
216 case SUB_OPCODE_MACRO_BRANCH:
217 *cur_reloc = RELOC_INFO_BRANCH(r_insn.macro.label,
221 assert(0 &&
"invalid sub_opcode for macro insn");
224 assert(read_ptr != end &&
"program can not end with macro insn");
228 *write_ptr = *read_ptr;
236 qsort(reloc_info, macro_count,
sizeof(reloc_info_t),
240 reloc_info_t* reloc_end = reloc_info + macro_count;
241 cur_reloc = reloc_info;
242 while(cur_reloc < reloc_end) {
243 reloc_info_t label_info = *cur_reloc;
244 assert(label_info.type == RELOC_TYPE_LABEL);
246 while (cur_reloc < reloc_end) {
247 if (cur_reloc->type == RELOC_TYPE_LABEL) {
248 if(cur_reloc->label == label_info.label) {
249 ESP_LOGE(TAG,
"duplicate label definition: %d",
252 return ESP_ERR_ULP_DUPLICATE_LABEL;
256 if (cur_reloc->label != label_info.label) {
257 ESP_LOGE(TAG,
"branch to an inexistent label: %d",
260 return ESP_ERR_ULP_UNDEFINED_LABEL;
262 esp_err_t rc = do_single_reloc(output_program, load_addr,
263 label_info, *cur_reloc);
272 *psize = real_program_size;