28#include "soc/rtc_cntl_reg.h"
29#include "soc/sens_reg.h"
33#include "ulp_macro_ex.h"
36#undef CONFIG_ULP_COPROC_RESERVE_MEM
37#define CONFIG_ULP_COPROC_RESERVE_MEM 2048
40static const char* TAG =
"ulp";
49#define RELOC_TYPE_LABEL 0
50#define RELOC_TYPE_BRANCH 1
55#define RELOC_INFO_LABEL(label_num, insn_addr) (reloc_info_t) { \
59 .type = RELOC_TYPE_LABEL }
65#define RELOC_INFO_BRANCH(label_num, insn_addr) (reloc_info_t) { \
69 .type = RELOC_TYPE_BRANCH }
72static int reloc_sort_func(
const void* p_lhs,
const void* p_rhs)
74 const reloc_info_t lhs = *(
const reloc_info_t*) p_lhs;
75 const reloc_info_t rhs = *(
const reloc_info_t*) p_rhs;
76 if (lhs.label < rhs.label) {
78 }
else if (lhs.label > rhs.label) {
82 if (lhs.type < rhs.type) {
84 }
else if (lhs.type > rhs.type) {
131static esp_err_t do_single_reloc(ulp_insn_t* program, uint32_t load_addr,
132 reloc_info_t label_info, reloc_info_t branch_info)
134 size_t insn_offset = branch_info.addr - load_addr;
135 ulp_insn_t* insn = &program[insn_offset];
138 assert(insn->b.opcode == OPCODE_BRANCH
139 &&
"branch macro was applied to a non-branch instruction");
140 switch (insn->b.sub_opcode) {
141 case SUB_OPCODE_STAGEB:
143 int32_t offset = ((int32_t) label_info.addr) - ((int32_t) branch_info.addr);
144ESP_LOGW(TAG,
"%d\n", offset);
145 uint32_t abs_offset = abs(offset);
146 uint32_t sign = (offset >= 0) ? 0 : 1;
147 if (abs_offset > 127) {
148 ESP_LOGE(TAG,
"target out of range: branch from %x to %x",
149 branch_info.addr, label_info.addr);
150 return ESP_ERR_ULP_BRANCH_OUT_OF_RANGE;
152 insn->b.offset = abs_offset;
156 case SUB_OPCODE_BX: {
157 assert(insn->bx.reg == 0 &&
158 "relocation applied to a jump with offset in register");
159 insn->bx.addr = label_info.addr;
163 assert(
false &&
"unexpected sub-opcode");
168esp_err_t ulp_process_macros_and_load_ex(uint32_t load_addr,
const ulp_insn_t* program,
size_t* psize)
170 const ulp_insn_t* read_ptr = program;
171 const ulp_insn_t* end = program + *psize;
172 size_t macro_count = 0;
174 while (read_ptr < end) {
175 ulp_insn_t r_insn = *read_ptr;
176 if (r_insn.macro.opcode == OPCODE_MACRO) {
181 size_t real_program_size = *psize - macro_count;
182 const size_t ulp_mem_end = CONFIG_ULP_COPROC_RESERVE_MEM /
sizeof(ulp_insn_t);
183 if (load_addr > ulp_mem_end) {
184 ESP_LOGE(TAG,
"invalid load address %x, max is %x",
185 load_addr, ulp_mem_end);
186 return ESP_ERR_ULP_INVALID_LOAD_ADDR;
188 if (real_program_size + load_addr > ulp_mem_end) {
189 ESP_LOGE(TAG,
"program too big: %d words, max is %d words",
190 real_program_size, ulp_mem_end);
191 return ESP_ERR_ULP_SIZE_TOO_BIG;
194 if (macro_count == 0) {
195 memcpy(((ulp_insn_t*) RTC_SLOW_MEM) + load_addr, program, *psize *
sizeof(ulp_insn_t));
198 reloc_info_t* reloc_info =
199 (reloc_info_t*) malloc(
sizeof(reloc_info_t) * macro_count);
200 if (reloc_info ==
nullptr) {
201 return ESP_ERR_NO_MEM;
207 ulp_insn_t* output_program = ((ulp_insn_t*) RTC_SLOW_MEM) + load_addr;
208 ulp_insn_t* write_ptr = output_program;
209 uint32_t cur_insn_addr = load_addr;
210 reloc_info_t* cur_reloc = reloc_info;
211 while (read_ptr < end) {
212 ulp_insn_t r_insn = *read_ptr;
213 if (r_insn.macro.opcode == OPCODE_MACRO) {
214 switch(r_insn.macro.sub_opcode) {
215 case SUB_OPCODE_MACRO_LABEL:
216 *cur_reloc = RELOC_INFO_LABEL(r_insn.macro.label,
219 case SUB_OPCODE_MACRO_BRANCH:
220 *cur_reloc = RELOC_INFO_BRANCH(r_insn.macro.label,
224 assert(0 &&
"invalid sub_opcode for macro insn");
227 assert(read_ptr != end &&
"program can not end with macro insn");
231 *write_ptr = *read_ptr;
239 qsort(reloc_info, macro_count,
sizeof(reloc_info_t),
243 reloc_info_t* reloc_end = reloc_info + macro_count;
244 cur_reloc = reloc_info;
245 while(cur_reloc < reloc_end) {
246 reloc_info_t label_info = *cur_reloc;
247 assert(label_info.type == RELOC_TYPE_LABEL);
249 while (cur_reloc < reloc_end) {
250 if (cur_reloc->type == RELOC_TYPE_LABEL) {
251 if(cur_reloc->label == label_info.label) {
252 ESP_LOGE(TAG,
"duplicate label definition: %d",
255 return ESP_ERR_ULP_DUPLICATE_LABEL;
259 if (cur_reloc->label != label_info.label) {
260 ESP_LOGE(TAG,
"branch to an inexistent label: %d",
263 return ESP_ERR_ULP_UNDEFINED_LABEL;
265 esp_err_t rc = do_single_reloc(output_program, load_addr,
266 label_info, *cur_reloc);
275 *psize = real_program_size;