cpu.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. /*
  2. * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "sdkconfig.h"
  7. #include <stdint.h>
  8. #include <assert.h>
  9. #include "soc/soc.h"
  10. #include "soc/soc_caps.h"
  11. // TODO: IDF-5645
  12. #if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
  13. #include "soc/lp_aon_reg.h"
  14. #include "soc/pcr_reg.h"
  15. #define SYSTEM_CPU_PER_CONF_REG PCR_CPU_WAITI_CONF_REG
  16. #define SYSTEM_CPU_WAIT_MODE_FORCE_ON PCR_CPU_WAIT_MODE_FORCE_ON
  17. #elif CONFIG_IDF_TARGET_ESP32P4
  18. #include "soc/lp_clkrst_reg.h"
  19. #include "soc/pmu_reg.h"
  20. #else
  21. #include "soc/rtc_cntl_reg.h"
  22. #endif
  23. #include "hal/soc_hal.h"
  24. #include "esp_bit_defs.h"
  25. #include "esp_attr.h"
  26. #include "esp_err.h"
  27. #include "esp_cpu.h"
  28. #if __XTENSA__
  29. #include "xtensa/config/core-isa.h"
  30. #else
  31. #include "soc/system_reg.h" // For SYSTEM_CPU_PER_CONF_REG
  32. #include "soc/dport_access.h" // For Dport access
  33. #include "riscv/semihosting.h"
  34. #endif
  35. #if SOC_CPU_HAS_FLEXIBLE_INTC
  36. #include "riscv/instruction_decode.h"
  37. #endif
  38. /* --------------------------------------------------- CPU Control -----------------------------------------------------
  39. *
  40. * ------------------------------------------------------------------------------------------------------------------ */
  41. void esp_cpu_stall(int core_id)
  42. {
  43. assert(core_id >= 0 && core_id < SOC_CPU_CORES_NUM);
  44. #if SOC_CPU_CORES_NUM > 1 // We don't allow stalling of the current core
  45. #if CONFIG_IDF_TARGET_ESP32P4
  46. //TODO: IDF-7848
  47. REG_SET_FIELD(PMU_CPU_SW_STALL_REG, core_id ? PMU_HPCORE1_SW_STALL_CODE : PMU_HPCORE0_SW_STALL_CODE, 0x86);
  48. #else
  49. /*
  50. We need to write the value "0x86" to stall a particular core. The write location is split into two separate
  51. bit fields named "c0" and "c1", and the two fields are located in different registers. Each core has its own pair of
  52. "c0" and "c1" bit fields.
  53. Note: This function can be called when the cache is disabled. We use "ternary if" instead of an array so that the
  54. "rodata" of the register masks/shifts will be stored in this function's "rodata" section, instead of the source
  55. file's "rodata" section (see IDF-5214).
  56. */
  57. int rtc_cntl_c0_m = (core_id == 0) ? RTC_CNTL_SW_STALL_PROCPU_C0_M : RTC_CNTL_SW_STALL_APPCPU_C0_M;
  58. int rtc_cntl_c0_s = (core_id == 0) ? RTC_CNTL_SW_STALL_PROCPU_C0_S : RTC_CNTL_SW_STALL_APPCPU_C0_S;
  59. int rtc_cntl_c1_m = (core_id == 0) ? RTC_CNTL_SW_STALL_PROCPU_C1_M : RTC_CNTL_SW_STALL_APPCPU_C1_M;
  60. int rtc_cntl_c1_s = (core_id == 0) ? RTC_CNTL_SW_STALL_PROCPU_C1_S : RTC_CNTL_SW_STALL_APPCPU_C1_S;
  61. CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, rtc_cntl_c0_m);
  62. SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, 2 << rtc_cntl_c0_s);
  63. CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, rtc_cntl_c1_m);
  64. SET_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, 0x21 << rtc_cntl_c1_s);
  65. #endif // CONFIG_IDF_TARGET_ESP32P4
  66. #endif // SOC_CPU_CORES_NUM > 1
  67. }
  68. void esp_cpu_unstall(int core_id)
  69. {
  70. assert(core_id >= 0 && core_id < SOC_CPU_CORES_NUM);
  71. #if SOC_CPU_CORES_NUM > 1 // We don't allow stalling of the current core
  72. #if CONFIG_IDF_TARGET_ESP32P4
  73. //TODO: IDF-7848
  74. REG_SET_FIELD(PMU_CPU_SW_STALL_REG, core_id ? PMU_HPCORE1_SW_STALL_CODE : PMU_HPCORE0_SW_STALL_CODE, 0);
  75. #else
  76. /*
  77. We need to write clear the value "0x86" to unstall a particular core. The location of this value is split into
  78. two separate bit fields named "c0" and "c1", and the two fields are located in different registers. Each core has
  79. its own pair of "c0" and "c1" bit fields.
  80. Note: This function can be called when the cache is disabled. We use "ternary if" instead of an array so that the
  81. "rodata" of the register masks/shifts will be stored in this function's "rodata" section, instead of the source
  82. file's "rodata" section (see IDF-5214).
  83. */
  84. int rtc_cntl_c0_m = (core_id == 0) ? RTC_CNTL_SW_STALL_PROCPU_C0_M : RTC_CNTL_SW_STALL_APPCPU_C0_M;
  85. int rtc_cntl_c1_m = (core_id == 0) ? RTC_CNTL_SW_STALL_PROCPU_C1_M : RTC_CNTL_SW_STALL_APPCPU_C1_M;
  86. CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, rtc_cntl_c0_m);
  87. CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, rtc_cntl_c1_m);
  88. #endif // CONFIG_IDF_TARGET_ESP32P4
  89. #endif // SOC_CPU_CORES_NUM > 1
  90. }
  91. void esp_cpu_reset(int core_id)
  92. {
  93. #if CONFIG_IDF_TARGET_ESP32P4
  94. //TODO: IDF-7848
  95. if (core_id == 0)
  96. REG_SET_BIT(LP_CLKRST_HPCPU_RESET_CTRL0_REG, LP_CLKRST_HPCORE0_SW_RESET);
  97. else
  98. REG_SET_BIT(LP_CLKRST_HPCPU_RESET_CTRL0_REG, LP_CLKRST_HPCORE1_SW_RESET);
  99. #else
  100. #if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2// TODO: IDF-5645
  101. SET_PERI_REG_MASK(LP_AON_CPUCORE0_CFG_REG, LP_AON_CPU_CORE0_SW_RESET);
  102. #else
  103. assert(core_id >= 0 && core_id < SOC_CPU_CORES_NUM);
  104. #if SOC_CPU_CORES_NUM > 1
  105. /*
  106. Note: This function can be called when the cache is disabled. We use "ternary if" instead of an array so that the
  107. "rodata" of the register masks/shifts will be stored in this function's "rodata" section, instead of the source
  108. file's "rodata" section (see IDF-5214).
  109. */
  110. int rtc_cntl_rst_m = (core_id == 0) ? RTC_CNTL_SW_PROCPU_RST_M : RTC_CNTL_SW_APPCPU_RST_M;
  111. #else // SOC_CPU_CORES_NUM > 1
  112. int rtc_cntl_rst_m = RTC_CNTL_SW_PROCPU_RST_M;
  113. #endif // SOC_CPU_CORES_NUM > 1
  114. SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, rtc_cntl_rst_m);
  115. #endif
  116. #endif // CONFIG_IDF_TARGET_ESP32P4
  117. }
  118. void esp_cpu_wait_for_intr(void)
  119. {
  120. #if __XTENSA__
  121. xt_utils_wait_for_intr();
  122. #else
  123. //TODO: IDF-7848
  124. #if !CONFIG_IDF_TARGET_ESP32P4
  125. // TODO: IDF-5645 (better to implement with ll) C6 register names converted in the #include section at the top
  126. if (esp_cpu_dbgr_is_attached() && DPORT_REG_GET_BIT(SYSTEM_CPU_PER_CONF_REG, SYSTEM_CPU_WAIT_MODE_FORCE_ON) == 0) {
  127. /* when SYSTEM_CPU_WAIT_MODE_FORCE_ON is disabled in WFI mode SBA access to memory does not work for debugger,
  128. so do not enter that mode when debugger is connected */
  129. return;
  130. }
  131. #endif
  132. rv_utils_wait_for_intr();
  133. #endif // __XTENSA__
  134. }
  135. /* -------------------------------------------------- CPU Registers ----------------------------------------------------
  136. *
  137. * ------------------------------------------------------------------------------------------------------------------ */
  138. /* ------------------------------------------------- CPU Interrupts ----------------------------------------------------
  139. *
  140. * ------------------------------------------------------------------------------------------------------------------ */
  141. // ---------------- Interrupt Descriptors ------------------
  142. #if SOC_CPU_HAS_FLEXIBLE_INTC
  143. #if SOC_INT_CLIC_SUPPORTED
  144. static bool is_intr_num_resv(int ext_intr_num) {
  145. /* On targets that uses CLIC as the interrupt controller, the first 16 lines (0..15) are reserved for software
  146. * interrupts, all the other lines starting from 16 and above can be used by external peripheral.
  147. * in the case of this function, the parameter only refers to the external peripheral index, so if
  148. * `ext_intr_num` is 0, it refers to interrupt index 16.
  149. *
  150. * Only interrupt line 6 is reserved at the moment since it is used for disabling interrupts */
  151. return ext_intr_num == 6;
  152. }
  153. #else // !SOC_INT_CLIC_SUPPORTED
  154. static bool is_intr_num_resv(int intr_num)
  155. {
  156. // Workaround to reserve interrupt number 1 for Wi-Fi, 5,8 for Bluetooth, 6 for "permanently disabled interrupt"
  157. // [TODO: IDF-2465]
  158. uint32_t reserved = BIT(1) | BIT(5) | BIT(6) | BIT(8);
  159. // int_num 0,3,4,7 are unavailable for PULP cpu
  160. #if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2// TODO: IDF-5728 replace with a better macro name
  161. reserved |= BIT(0) | BIT(3) | BIT(4) | BIT(7);
  162. #endif
  163. if (reserved & BIT(intr_num)) {
  164. return true;
  165. }
  166. extern int _vector_table;
  167. extern int _interrupt_handler;
  168. const intptr_t pc = (intptr_t)(&_vector_table + intr_num);
  169. /* JAL instructions are relative to the PC there are executed from. */
  170. const intptr_t destination = pc + riscv_decode_offset_from_jal_instruction(pc);
  171. return destination != (intptr_t)&_interrupt_handler;
  172. }
  173. #endif // SOC_INT_CLIC_SUPPORTED
  174. void esp_cpu_intr_get_desc(int core_id, int intr_num, esp_cpu_intr_desc_t *intr_desc_ret)
  175. {
  176. intr_desc_ret->priority = 1; //Todo: We should make this -1
  177. intr_desc_ret->type = ESP_CPU_INTR_TYPE_NA;
  178. #if __riscv
  179. intr_desc_ret->flags = is_intr_num_resv(intr_num) ? ESP_CPU_INTR_DESC_FLAG_RESVD : 0;
  180. #else
  181. intr_desc_ret->flags = 0;
  182. #endif
  183. }
  184. #else // SOC_CPU_HAS_FLEXIBLE_INTC
  185. typedef struct {
  186. int priority;
  187. esp_cpu_intr_type_t type;
  188. uint32_t flags[SOC_CPU_CORES_NUM];
  189. } intr_desc_t;
  190. #if SOC_CPU_CORES_NUM > 1
  191. // Note: We currently only have dual core targets, so the table initializer is hard coded
  192. const static intr_desc_t intr_desc_table [SOC_CPU_INTR_NUM] = {
  193. { 1, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD, ESP_CPU_INTR_DESC_FLAG_RESVD } }, //0
  194. { 1, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD, ESP_CPU_INTR_DESC_FLAG_RESVD } }, //1
  195. { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0 } }, //2
  196. { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0 } }, //3
  197. { 1, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD, 0 } }, //4
  198. { 1, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD, ESP_CPU_INTR_DESC_FLAG_RESVD } }, //5
  199. #if CONFIG_FREERTOS_CORETIMER_0
  200. { 1, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_RESVD, ESP_CPU_INTR_DESC_FLAG_RESVD } }, //6
  201. #else
  202. { 1, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_SPECIAL, ESP_CPU_INTR_DESC_FLAG_SPECIAL } }, //6
  203. #endif
  204. { 1, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_SPECIAL, ESP_CPU_INTR_DESC_FLAG_SPECIAL } }, //7
  205. { 1, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD, ESP_CPU_INTR_DESC_FLAG_RESVD } }, //8
  206. { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0 } }, //9
  207. { 1, ESP_CPU_INTR_TYPE_EDGE, { 0, 0 } }, //10
  208. { 3, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_SPECIAL, ESP_CPU_INTR_DESC_FLAG_SPECIAL } }, //11
  209. { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0} }, //12
  210. { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0} }, //13
  211. { 7, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD, ESP_CPU_INTR_DESC_FLAG_RESVD } }, //14, NMI
  212. #if CONFIG_FREERTOS_CORETIMER_1
  213. { 3, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_RESVD, ESP_CPU_INTR_DESC_FLAG_RESVD } }, //15
  214. #else
  215. { 3, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_SPECIAL, ESP_CPU_INTR_DESC_FLAG_SPECIAL } }, //15
  216. #endif
  217. { 5, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_SPECIAL, ESP_CPU_INTR_DESC_FLAG_SPECIAL } }, //16
  218. { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0 } }, //17
  219. { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0 } }, //18
  220. { 2, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0 } }, //19
  221. { 2, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0 } }, //20
  222. { 2, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0 } }, //21
  223. { 3, ESP_CPU_INTR_TYPE_EDGE, { ESP_CPU_INTR_DESC_FLAG_RESVD, 0 } }, //22
  224. { 3, ESP_CPU_INTR_TYPE_LEVEL, { 0, 0 } }, //23
  225. { 4, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD, 0 } }, //24
  226. { 4, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD, ESP_CPU_INTR_DESC_FLAG_RESVD } }, //25
  227. { 5, ESP_CPU_INTR_TYPE_LEVEL, { 0, ESP_CPU_INTR_DESC_FLAG_RESVD } }, //26
  228. { 3, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD, ESP_CPU_INTR_DESC_FLAG_RESVD } }, //27
  229. { 4, ESP_CPU_INTR_TYPE_EDGE, { 0, 0 } }, //28
  230. { 3, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_SPECIAL, ESP_CPU_INTR_DESC_FLAG_SPECIAL } }, //29
  231. { 4, ESP_CPU_INTR_TYPE_EDGE, { ESP_CPU_INTR_DESC_FLAG_RESVD, ESP_CPU_INTR_DESC_FLAG_RESVD } }, //30
  232. { 5, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD, ESP_CPU_INTR_DESC_FLAG_RESVD } }, //31
  233. };
  234. #else // SOC_CPU_CORES_NUM > 1
  235. const static intr_desc_t intr_desc_table [SOC_CPU_INTR_NUM] = {
  236. { 1, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD } }, //0
  237. { 1, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD } }, //1
  238. { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0 } }, //2
  239. { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0 } }, //3
  240. { 1, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD } }, //4
  241. { 1, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD } }, //5
  242. #if CONFIG_FREERTOS_CORETIMER_0
  243. { 1, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_RESVD } }, //6
  244. #else
  245. { 1, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_SPECIAL } }, //6
  246. #endif
  247. { 1, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_SPECIAL } }, //7
  248. { 1, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD } }, //8
  249. { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0 } }, //9
  250. { 1, ESP_CPU_INTR_TYPE_EDGE, { 0 } }, //10
  251. { 3, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_SPECIAL } }, //11
  252. { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0 } }, //12
  253. { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0 } }, //13
  254. { 7, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD } }, //14, NMI
  255. #if CONFIG_FREERTOS_CORETIMER_1
  256. { 3, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_RESVD } }, //15
  257. #else
  258. { 3, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_SPECIAL } }, //15
  259. #endif
  260. { 5, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_SPECIAL } }, //16
  261. { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0 } }, //17
  262. { 1, ESP_CPU_INTR_TYPE_LEVEL, { 0 } }, //18
  263. { 2, ESP_CPU_INTR_TYPE_LEVEL, { 0 } }, //19
  264. { 2, ESP_CPU_INTR_TYPE_LEVEL, { 0 } }, //20
  265. { 2, ESP_CPU_INTR_TYPE_LEVEL, { 0 } }, //21
  266. { 3, ESP_CPU_INTR_TYPE_EDGE, { ESP_CPU_INTR_DESC_FLAG_RESVD } }, //22
  267. { 3, ESP_CPU_INTR_TYPE_LEVEL, { 0 } }, //23
  268. { 4, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD } }, //24
  269. { 4, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD } }, //25
  270. { 5, ESP_CPU_INTR_TYPE_LEVEL, { 0 } }, //26
  271. { 3, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD } }, //27
  272. { 4, ESP_CPU_INTR_TYPE_EDGE, { 0 } }, //28
  273. { 3, ESP_CPU_INTR_TYPE_NA, { ESP_CPU_INTR_DESC_FLAG_SPECIAL } }, //29
  274. { 4, ESP_CPU_INTR_TYPE_EDGE, { ESP_CPU_INTR_DESC_FLAG_RESVD } }, //30
  275. { 5, ESP_CPU_INTR_TYPE_LEVEL, { ESP_CPU_INTR_DESC_FLAG_RESVD } }, //31
  276. };
  277. #endif // SOC_CPU_CORES_NUM > 1
  278. void esp_cpu_intr_get_desc(int core_id, int intr_num, esp_cpu_intr_desc_t *intr_desc_ret)
  279. {
  280. assert(core_id >= 0 && core_id < SOC_CPU_CORES_NUM);
  281. #if SOC_CPU_CORES_NUM == 1
  282. core_id = 0; //If this is a single core target, hard code CPU ID to 0
  283. #endif
  284. intr_desc_ret->priority = intr_desc_table[intr_num].priority;
  285. intr_desc_ret->type = intr_desc_table[intr_num].type;
  286. intr_desc_ret->flags = intr_desc_table[intr_num].flags[core_id];
  287. }
  288. #endif // SOC_CPU_HAS_FLEXIBLE_INTC
  289. /* ---------------------------------------------------- Debugging ------------------------------------------------------
  290. *
  291. * ------------------------------------------------------------------------------------------------------------------ */
  292. // --------------- Breakpoints/Watchpoints -----------------
  293. #if SOC_CPU_BREAKPOINTS_NUM > 0
  294. esp_err_t esp_cpu_set_breakpoint(int bp_num, const void *bp_addr)
  295. {
  296. /*
  297. Todo:
  298. - Check that bp_num is in range
  299. */
  300. #if __XTENSA__
  301. xt_utils_set_breakpoint(bp_num, (uint32_t)bp_addr);
  302. #else
  303. if (esp_cpu_dbgr_is_attached()) {
  304. /* If we want to set breakpoint which when hit transfers control to debugger
  305. * we need to set `action` in `mcontrol` to 1 (Enter Debug Mode).
  306. * That `action` value is supported only when `dmode` of `tdata1` is set.
  307. * But `dmode` can be modified by debugger only (from Debug Mode).
  308. *
  309. * So when debugger is connected we use special syscall to ask it to set breakpoint for us.
  310. */
  311. long args[] = {true, bp_num, (long)bp_addr};
  312. int ret = semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_BREAKPOINT_SET, args);
  313. if (ret == 0) {
  314. return ESP_ERR_INVALID_RESPONSE;
  315. }
  316. } else {
  317. rv_utils_set_breakpoint(bp_num, (uint32_t)bp_addr);
  318. }
  319. #endif // __XTENSA__
  320. return ESP_OK;
  321. }
  322. esp_err_t esp_cpu_clear_breakpoint(int bp_num)
  323. {
  324. /*
  325. Todo:
  326. - Check if the bp_num is valid
  327. */
  328. #if __XTENSA__
  329. xt_utils_clear_breakpoint(bp_num);
  330. #else
  331. if (esp_cpu_dbgr_is_attached()) {
  332. // See description in esp_cpu_set_breakpoint()
  333. long args[] = {false, bp_num};
  334. int ret = semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_BREAKPOINT_SET, args);
  335. if (ret == 0) {
  336. return ESP_ERR_INVALID_RESPONSE;
  337. }
  338. } else {
  339. rv_utils_clear_breakpoint(bp_num);
  340. }
  341. #endif // __XTENSA__
  342. return ESP_OK;
  343. }
  344. #endif // SOC_CPU_BREAKPOINTS_NUM > 0
  345. #if SOC_CPU_WATCHPOINTS_NUM > 0
  346. esp_err_t esp_cpu_set_watchpoint(int wp_num, const void *wp_addr, size_t size, esp_cpu_watchpoint_trigger_t trigger)
  347. {
  348. /*
  349. Todo:
  350. - Check if the wp_num is already in use
  351. */
  352. if (wp_num < 0 || wp_num >= SOC_CPU_WATCHPOINTS_NUM) {
  353. return ESP_ERR_INVALID_ARG;
  354. }
  355. // Check that the watched region's start address is naturally aligned to the size of the region
  356. if ((uint32_t)wp_addr % size) {
  357. return ESP_ERR_INVALID_ARG;
  358. }
  359. // Check if size is 2^n, and size is in the range of [1 ... SOC_CPU_WATCHPOINT_MAX_REGION_SIZE]
  360. if (size < 1 || size > SOC_CPU_WATCHPOINT_MAX_REGION_SIZE || (size & (size - 1)) != 0) {
  361. return ESP_ERR_INVALID_ARG;
  362. }
  363. bool on_read = (trigger == ESP_CPU_WATCHPOINT_LOAD || trigger == ESP_CPU_WATCHPOINT_ACCESS);
  364. bool on_write = (trigger == ESP_CPU_WATCHPOINT_STORE || trigger == ESP_CPU_WATCHPOINT_ACCESS);
  365. #if __XTENSA__
  366. xt_utils_set_watchpoint(wp_num, (uint32_t)wp_addr, size, on_read, on_write);
  367. #else
  368. if (esp_cpu_dbgr_is_attached()) {
  369. // See description in esp_cpu_set_breakpoint()
  370. long args[] = {true, wp_num, (long)wp_addr, (long)size,
  371. (long)((on_read ? ESP_SEMIHOSTING_WP_FLG_RD : 0) | (on_write ? ESP_SEMIHOSTING_WP_FLG_WR : 0))
  372. };
  373. int ret = semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_WATCHPOINT_SET, args);
  374. if (ret == 0) {
  375. return ESP_ERR_INVALID_RESPONSE;
  376. }
  377. } else {
  378. rv_utils_set_watchpoint(wp_num, (uint32_t)wp_addr, size, on_read, on_write);
  379. }
  380. #endif // __XTENSA__
  381. return ESP_OK;
  382. }
  383. esp_err_t esp_cpu_clear_watchpoint(int wp_num)
  384. {
  385. /*
  386. Todo:
  387. - Check if the wp_num is valid
  388. */
  389. #if __XTENSA__
  390. xt_utils_clear_watchpoint(wp_num);
  391. #else
  392. if (esp_cpu_dbgr_is_attached()) {
  393. // See description in esp_cpu_dbgr_is_attached()
  394. long args[] = {false, wp_num};
  395. int ret = semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_WATCHPOINT_SET, args);
  396. if (ret == 0) {
  397. return ESP_ERR_INVALID_RESPONSE;
  398. }
  399. } else {
  400. rv_utils_clear_watchpoint(wp_num);
  401. }
  402. #endif // __XTENSA__
  403. return ESP_OK;
  404. }
  405. #endif // SOC_CPU_WATCHPOINTS_NUM > 0
  406. /* ------------------------------------------------------ Misc ---------------------------------------------------------
  407. *
  408. * ------------------------------------------------------------------------------------------------------------------ */
  409. #if __XTENSA__ && XCHAL_HAVE_S32C1I && CONFIG_SPIRAM
  410. static DRAM_ATTR uint32_t external_ram_cas_lock = 0;
  411. #endif
  412. bool esp_cpu_compare_and_set(volatile uint32_t *addr, uint32_t compare_value, uint32_t new_value)
  413. {
  414. #if __XTENSA__
  415. bool ret;
  416. #if XCHAL_HAVE_S32C1I && CONFIG_SPIRAM
  417. // Check if the target address is in external RAM
  418. if ((uint32_t)addr >= SOC_EXTRAM_DATA_LOW && (uint32_t)addr < SOC_EXTRAM_DATA_HIGH) {
  419. /* The target address is in external RAM, thus the native CAS instruction cannot be used. Instead, we achieve
  420. atomicity by disabling interrupts and then acquiring an external RAM CAS lock. */
  421. uint32_t intr_level;
  422. __asm__ __volatile__ ("rsil %0, " XTSTR(XCHAL_EXCM_LEVEL) "\n"
  423. : "=r"(intr_level));
  424. if (!xt_utils_compare_and_set(&external_ram_cas_lock, 0, 1)) {
  425. // External RAM CAS lock already taken. Exit
  426. ret = false;
  427. goto exit;
  428. }
  429. // Now we compare and set the target address
  430. ret = (*addr == compare_value);
  431. if (ret) {
  432. *addr = new_value;
  433. }
  434. // Release the external RAM CAS lock
  435. external_ram_cas_lock = 0;
  436. exit:
  437. // Reenable interrupts
  438. __asm__ __volatile__ ("memw \n"
  439. "wsr %0, ps\n"
  440. :: "r"(intr_level));
  441. } else
  442. #endif // XCHAL_HAVE_S32C1I && CONFIG_SPIRAM
  443. {
  444. // The target address is in internal RAM. Use the CPU's native CAS instruction
  445. ret = xt_utils_compare_and_set(addr, compare_value, new_value);
  446. }
  447. return ret;
  448. #else // __riscv
  449. return rv_utils_compare_and_set(addr, compare_value, new_value);
  450. #endif
  451. }