esp_cpu.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. /*
  2. * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #pragma once
  7. #include "sdkconfig.h"
  8. #include <stdbool.h>
  9. #include <stdint.h>
  10. #include <assert.h>
  11. #include "soc/soc_caps.h"
  12. #ifdef __XTENSA__
  13. #include "xtensa/xtensa_api.h"
  14. #include "xt_utils.h"
  15. #elif __riscv
  16. #include "riscv/rv_utils.h"
  17. #endif
  18. #include "esp_err.h"
  19. #ifdef __cplusplus
  20. extern "C" {
  21. #endif
  22. /**
  23. * @brief CPU cycle count type
  24. *
  25. * This data type represents the CPU's clock cycle count
  26. */
  27. typedef uint32_t esp_cpu_cycle_count_t;
  28. /**
  29. * @brief CPU interrupt type
  30. */
  31. typedef enum {
  32. ESP_CPU_INTR_TYPE_LEVEL,
  33. ESP_CPU_INTR_TYPE_EDGE,
  34. ESP_CPU_INTR_TYPE_NA,
  35. } esp_cpu_intr_type_t;
  36. /**
  37. * @brief CPU interrupt descriptor
  38. *
  39. * Each particular CPU interrupt has an associated descriptor describing that
  40. * particular interrupt's characteristics. Call esp_cpu_intr_get_desc() to get
  41. * the descriptors of a particular interrupt.
  42. */
  43. typedef struct {
  44. int priority; /**< Priority of the interrupt if it has a fixed priority, (-1) if the priority is configurable. */
  45. esp_cpu_intr_type_t type; /**< Whether the interrupt is an edge or level type interrupt, ESP_CPU_INTR_TYPE_NA if the type is configurable. */
  46. uint32_t flags; /**< Flags indicating extra details. */
  47. } esp_cpu_intr_desc_t;
  48. /**
  49. * @brief Interrupt descriptor flags of esp_cpu_intr_desc_t
  50. */
  51. #define ESP_CPU_INTR_DESC_FLAG_SPECIAL 0x01 /**< The interrupt is a special interrupt (e.g., a CPU timer interrupt) */
  52. #define ESP_CPU_INTR_DESC_FLAG_RESVD 0x02 /**< The interrupt is reserved for internal use */
  53. /**
  54. * @brief CPU interrupt handler type
  55. */
  56. typedef void (*esp_cpu_intr_handler_t)(void *arg);
  57. /**
  58. * @brief CPU watchpoint trigger type
  59. */
  60. typedef enum {
  61. ESP_CPU_WATCHPOINT_LOAD,
  62. ESP_CPU_WATCHPOINT_STORE,
  63. ESP_CPU_WATCHPOINT_ACCESS,
  64. } esp_cpu_watchpoint_trigger_t;
  65. /* --------------------------------------------------- CPU Control -----------------------------------------------------
  66. *
  67. * ------------------------------------------------------------------------------------------------------------------ */
  68. /**
  69. * @brief Stall a CPU core
  70. *
  71. * @param core_id The core's ID
  72. */
  73. void esp_cpu_stall(int core_id);
  74. /**
  75. * @brief Resume a previously stalled CPU core
  76. *
  77. * @param core_id The core's ID
  78. */
  79. void esp_cpu_unstall(int core_id);
  80. /**
  81. * @brief Reset a CPU core
  82. *
  83. * @param core_id The core's ID
  84. */
  85. void esp_cpu_reset(int core_id);
  86. /**
  87. * @brief Wait for Interrupt
  88. *
  89. * This function causes the current CPU core to execute its Wait For Interrupt
  90. * (WFI or equivalent) instruction. After executing this function, the CPU core
  91. * will stop execution until an interrupt occurs.
  92. */
  93. void esp_cpu_wait_for_intr(void);
  94. /* -------------------------------------------------- CPU Registers ----------------------------------------------------
  95. *
  96. * ------------------------------------------------------------------------------------------------------------------ */
  97. /**
  98. * @brief Get the current core's ID
  99. *
  100. * This function will return the ID of the current CPU (i.e., the CPU that calls
  101. * this function).
  102. *
  103. * @return The current core's ID [0..SOC_CPU_CORES_NUM - 1]
  104. */
  105. FORCE_INLINE_ATTR __attribute__((pure)) int esp_cpu_get_core_id(void)
  106. {
  107. //Note: Made "pure" to optimize for single core target
  108. #ifdef __XTENSA__
  109. return (int)xt_utils_get_core_id();
  110. #else
  111. return (int)rv_utils_get_core_id();
  112. #endif
  113. }
  114. /**
  115. * @brief Read the current stack pointer address
  116. *
  117. * @return Stack pointer address
  118. */
  119. FORCE_INLINE_ATTR void *esp_cpu_get_sp(void)
  120. {
  121. #ifdef __XTENSA__
  122. return xt_utils_get_sp();
  123. #else
  124. return rv_utils_get_sp();
  125. #endif
  126. }
  127. /**
  128. * @brief Get the current CPU core's cycle count
  129. *
  130. * Each CPU core maintains an internal counter (i.e., cycle count) that increments
  131. * every CPU clock cycle.
  132. *
  133. * @return Current CPU's cycle count, 0 if not supported.
  134. */
  135. FORCE_INLINE_ATTR esp_cpu_cycle_count_t esp_cpu_get_cycle_count(void)
  136. {
  137. #ifdef __XTENSA__
  138. return (esp_cpu_cycle_count_t)xt_utils_get_cycle_count();
  139. #else
  140. return (esp_cpu_cycle_count_t)rv_utils_get_cycle_count();
  141. #endif
  142. }
  143. /**
  144. * @brief Set the current CPU core's cycle count
  145. *
  146. * Set the given value into the internal counter that increments every
  147. * CPU clock cycle.
  148. *
  149. * @param cycle_count CPU cycle count
  150. */
  151. FORCE_INLINE_ATTR void esp_cpu_set_cycle_count(esp_cpu_cycle_count_t cycle_count)
  152. {
  153. #ifdef __XTENSA__
  154. xt_utils_set_cycle_count((uint32_t)cycle_count);
  155. #else
  156. rv_utils_set_cycle_count((uint32_t)cycle_count);
  157. #endif
  158. }
  159. /**
  160. * @brief Convert a program counter (PC) value to address
  161. *
  162. * If the architecture does not store the true virtual address in the CPU's PC
  163. * or return addresses, this function will convert the PC value to a virtual
  164. * address. Otherwise, the PC is just returned
  165. *
  166. * @param pc PC value
  167. * @return Virtual address
  168. */
  169. FORCE_INLINE_ATTR __attribute__((pure)) void *esp_cpu_pc_to_addr(uint32_t pc)
  170. {
  171. #ifdef __XTENSA__
  172. // Xtensa stores window rotation in PC[31:30]
  173. return (void *)((pc & 0x3fffffffU) | 0x40000000U);
  174. #else
  175. return (void *)pc;
  176. #endif
  177. }
  178. /* ------------------------------------------------- CPU Interrupts ----------------------------------------------------
  179. *
  180. * ------------------------------------------------------------------------------------------------------------------ */
  181. // ---------------- Interrupt Descriptors ------------------
  182. /**
  183. * @brief Get a CPU interrupt's descriptor
  184. *
  185. * Each CPU interrupt has a descriptor describing the interrupt's capabilities
  186. * and restrictions. This function gets the descriptor of a particular interrupt
  187. * on a particular CPU.
  188. *
  189. * @param[in] core_id The core's ID
  190. * @param[in] intr_num Interrupt number
  191. * @param[out] intr_desc_ret The interrupt's descriptor
  192. */
  193. void esp_cpu_intr_get_desc(int core_id, int intr_num, esp_cpu_intr_desc_t *intr_desc_ret);
  194. // --------------- Interrupt Configuration -----------------
  195. /**
  196. * @brief Set the base address of the current CPU's Interrupt Vector Table (IVT)
  197. *
  198. * @param ivt_addr Interrupt Vector Table's base address
  199. */
  200. FORCE_INLINE_ATTR void esp_cpu_intr_set_ivt_addr(const void *ivt_addr)
  201. {
  202. #ifdef __XTENSA__
  203. xt_utils_set_vecbase((uint32_t)ivt_addr);
  204. #else
  205. rv_utils_set_mtvec((uint32_t)ivt_addr);
  206. #endif
  207. }
  208. #if SOC_CPU_HAS_FLEXIBLE_INTC
  209. /**
  210. * @brief Set the interrupt type of a particular interrupt
  211. *
  212. * Set the interrupt type (Level or Edge) of a particular interrupt on the
  213. * current CPU.
  214. *
  215. * @param intr_num Interrupt number (from 0 to 31)
  216. * @param intr_type The interrupt's type
  217. */
  218. FORCE_INLINE_ATTR void esp_cpu_intr_set_type(int intr_num, esp_cpu_intr_type_t intr_type)
  219. {
  220. assert(intr_num >= 0 && intr_num < SOC_CPU_INTR_NUM);
  221. enum intr_type type = (intr_type == ESP_CPU_INTR_TYPE_LEVEL) ? INTR_TYPE_LEVEL : INTR_TYPE_EDGE;
  222. esprv_intc_int_set_type(intr_num, type);
  223. }
  224. /**
  225. * @brief Get the current configured type of a particular interrupt
  226. *
  227. * Get the currently configured type (i.e., level or edge) of a particular
  228. * interrupt on the current CPU.
  229. *
  230. * @param intr_num Interrupt number (from 0 to 31)
  231. * @return Interrupt type
  232. */
  233. FORCE_INLINE_ATTR esp_cpu_intr_type_t esp_cpu_intr_get_type(int intr_num)
  234. {
  235. assert(intr_num >= 0 && intr_num < SOC_CPU_INTR_NUM);
  236. enum intr_type type = esprv_intc_int_get_type(intr_num);
  237. return (type == INTR_TYPE_LEVEL) ? ESP_CPU_INTR_TYPE_LEVEL : ESP_CPU_INTR_TYPE_EDGE;
  238. }
  239. /**
  240. * @brief Set the priority of a particular interrupt
  241. *
  242. * Set the priority of a particular interrupt on the current CPU.
  243. *
  244. * @param intr_num Interrupt number (from 0 to 31)
  245. * @param intr_priority The interrupt's priority
  246. */
  247. FORCE_INLINE_ATTR void esp_cpu_intr_set_priority(int intr_num, int intr_priority)
  248. {
  249. assert(intr_num >= 0 && intr_num < SOC_CPU_INTR_NUM);
  250. esprv_intc_int_set_priority(intr_num, intr_priority);
  251. }
  252. /**
  253. * @brief Get the current configured priority of a particular interrupt
  254. *
  255. * Get the currently configured priority of a particular interrupt on the
  256. * current CPU.
  257. *
  258. * @param intr_num Interrupt number (from 0 to 31)
  259. * @return Interrupt's priority
  260. */
  261. FORCE_INLINE_ATTR int esp_cpu_intr_get_priority(int intr_num)
  262. {
  263. assert(intr_num >= 0 && intr_num < SOC_CPU_INTR_NUM);
  264. return esprv_intc_int_get_priority(intr_num);
  265. }
  266. #endif // SOC_CPU_HAS_FLEXIBLE_INTC
  267. /**
  268. * @brief Check if a particular interrupt already has a handler function
  269. *
  270. * Check if a particular interrupt on the current CPU already has a handler
  271. * function assigned.
  272. *
  273. * @note This function simply checks if the IVT of the current CPU already has
  274. * a handler assigned.
  275. * @param intr_num Interrupt number (from 0 to 31)
  276. * @return True if the interrupt has a handler function, false otherwise.
  277. */
  278. FORCE_INLINE_ATTR bool esp_cpu_intr_has_handler(int intr_num)
  279. {
  280. assert(intr_num >= 0 && intr_num < SOC_CPU_INTR_NUM);
  281. bool has_handler;
  282. #ifdef __XTENSA__
  283. has_handler = xt_int_has_handler(intr_num, esp_cpu_get_core_id());
  284. #else
  285. has_handler = intr_handler_get(intr_num);
  286. #endif
  287. return has_handler;
  288. }
  289. /**
  290. * @brief Set the handler function of a particular interrupt
  291. *
  292. * Assign a handler function (i.e., ISR) to a particular interrupt on the
  293. * current CPU.
  294. *
  295. * @note This function simply sets the handler function (in the IVT) and does
  296. * not actually enable the interrupt.
  297. * @param intr_num Interrupt number (from 0 to 31)
  298. * @param handler Handler function
  299. * @param handler_arg Argument passed to the handler function
  300. */
  301. FORCE_INLINE_ATTR void esp_cpu_intr_set_handler(int intr_num, esp_cpu_intr_handler_t handler, void *handler_arg)
  302. {
  303. assert(intr_num >= 0 && intr_num < SOC_CPU_INTR_NUM);
  304. #ifdef __XTENSA__
  305. xt_set_interrupt_handler(intr_num, (xt_handler)handler, handler_arg);
  306. #else
  307. intr_handler_set(intr_num, (intr_handler_t)handler, handler_arg);
  308. #endif
  309. }
  310. /**
  311. * @brief Get a handler function's argument of
  312. *
  313. * Get the argument of a previously assigned handler function on the current CPU.
  314. *
  315. * @param intr_num Interrupt number (from 0 to 31)
  316. * @return The the argument passed to the handler function
  317. */
  318. FORCE_INLINE_ATTR void *esp_cpu_intr_get_handler_arg(int intr_num)
  319. {
  320. assert(intr_num >= 0 && intr_num < SOC_CPU_INTR_NUM);
  321. void *handler_arg;
  322. #ifdef __XTENSA__
  323. handler_arg = xt_get_interrupt_handler_arg(intr_num);
  324. #else
  325. handler_arg = intr_handler_get_arg(intr_num);
  326. #endif
  327. return handler_arg;
  328. }
  329. // ------------------ Interrupt Control --------------------
  330. /**
  331. * @brief Enable particular interrupts on the current CPU
  332. *
  333. * @param intr_mask Bit mask of the interrupts to enable
  334. */
  335. FORCE_INLINE_ATTR void esp_cpu_intr_enable(uint32_t intr_mask)
  336. {
  337. #ifdef __XTENSA__
  338. xt_ints_on(intr_mask);
  339. #else
  340. rv_utils_intr_enable(intr_mask);
  341. #endif
  342. }
  343. /**
  344. * @brief Disable particular interrupts on the current CPU
  345. *
  346. * @param intr_mask Bit mask of the interrupts to disable
  347. */
  348. FORCE_INLINE_ATTR void esp_cpu_intr_disable(uint32_t intr_mask)
  349. {
  350. #ifdef __XTENSA__
  351. xt_ints_off(intr_mask);
  352. #else
  353. rv_utils_intr_disable(intr_mask);
  354. #endif
  355. }
  356. /**
  357. * @brief Get the enabled interrupts on the current CPU
  358. *
  359. * @return Bit mask of the enabled interrupts
  360. */
  361. FORCE_INLINE_ATTR uint32_t esp_cpu_intr_get_enabled_mask(void)
  362. {
  363. #ifdef __XTENSA__
  364. return xt_utils_intr_get_enabled_mask();
  365. #else
  366. return rv_utils_intr_get_enabled_mask();
  367. #endif
  368. }
  369. /**
  370. * @brief Acknowledge an edge interrupt
  371. *
  372. * @param intr_num Interrupt number (from 0 to 31)
  373. */
  374. FORCE_INLINE_ATTR void esp_cpu_intr_edge_ack(int intr_num)
  375. {
  376. assert(intr_num >= 0 && intr_num < SOC_CPU_INTR_NUM);
  377. #ifdef __XTENSA__
  378. xthal_set_intclear(1 << intr_num);
  379. #else
  380. rv_utils_intr_edge_ack(intr_num);
  381. #endif
  382. }
  383. /* -------------------------------------------------- Memory Ports -----------------------------------------------------
  384. *
  385. * ------------------------------------------------------------------------------------------------------------------ */
  386. /**
  387. * @brief Configure the CPU to disable access to invalid memory regions
  388. */
  389. void esp_cpu_configure_region_protection(void);
  390. /* ---------------------------------------------------- Debugging ------------------------------------------------------
  391. *
  392. * ------------------------------------------------------------------------------------------------------------------ */
  393. // --------------- Breakpoints/Watchpoints -----------------
  394. #if SOC_CPU_BREAKPOINTS_NUM > 0
  395. /**
  396. * @brief Set and enable a hardware breakpoint on the current CPU
  397. *
  398. * @note This function is meant to be called by the panic handler to set a
  399. * breakpoint for an attached debugger during a panic.
  400. * @note Overwrites previously set breakpoint with same breakpoint number.
  401. * @param bp_num Hardware breakpoint number [0..SOC_CPU_BREAKPOINTS_NUM - 1]
  402. * @param bp_addr Address to set a breakpoint on
  403. * @return ESP_OK if breakpoint is set. Failure otherwise
  404. */
  405. esp_err_t esp_cpu_set_breakpoint(int bp_num, const void *bp_addr);
  406. /**
  407. * @brief Clear a hardware breakpoint on the current CPU
  408. *
  409. * @note Clears a breakpoint regardless of whether it was previously set
  410. * @param bp_num Hardware breakpoint number [0..SOC_CPU_BREAKPOINTS_NUM - 1]
  411. * @return ESP_OK if breakpoint is cleared. Failure otherwise
  412. */
  413. esp_err_t esp_cpu_clear_breakpoint(int bp_num);
  414. #endif // SOC_CPU_BREAKPOINTS_NUM > 0
  415. /**
  416. * @brief Set and enable a hardware watchpoint on the current CPU
  417. *
  418. * Set and enable a hardware watchpoint on the current CPU, specifying the
  419. * memory range and trigger operation. Watchpoints will break/panic the CPU when
  420. * the CPU accesses (according to the trigger type) on a certain memory range.
  421. *
  422. * @note Overwrites previously set watchpoint with same watchpoint number.
  423. * @param wp_num Hardware watchpoint number [0..SOC_CPU_WATCHPOINTS_NUM - 1]
  424. * @param wp_addr Watchpoint's base address
  425. * @param size Size of the region to watch. Must be one of 2^n, with n in [0..6].
  426. * @param trigger Trigger type
  427. * @return ESP_ERR_INVALID_ARG on invalid arg, ESP_OK otherwise
  428. */
  429. esp_err_t esp_cpu_set_watchpoint(int wp_num, const void *wp_addr, size_t size, esp_cpu_watchpoint_trigger_t trigger);
  430. /**
  431. * @brief Clear a hardware watchpoint on the current CPU
  432. *
  433. * @note Clears a watchpoint regardless of whether it was previously set
  434. * @param wp_num Hardware watchpoint number [0..SOC_CPU_WATCHPOINTS_NUM - 1]
  435. * @return ESP_OK if watchpoint was cleared. Failure otherwise.
  436. */
  437. esp_err_t esp_cpu_clear_watchpoint(int wp_num);
  438. // ---------------------- Debugger -------------------------
  439. /**
  440. * @brief Check if the current CPU has a debugger attached
  441. *
  442. * @return True if debugger is attached, false otherwise
  443. */
  444. FORCE_INLINE_ATTR bool esp_cpu_dbgr_is_attached(void)
  445. {
  446. #ifdef __XTENSA__
  447. return xt_utils_dbgr_is_attached();
  448. #else
  449. return rv_utils_dbgr_is_attached();
  450. #endif
  451. }
  452. /**
  453. * @brief Trigger a call to the current CPU's attached debugger
  454. */
  455. FORCE_INLINE_ATTR void esp_cpu_dbgr_break(void)
  456. {
  457. #ifdef __XTENSA__
  458. xt_utils_dbgr_break();
  459. #else
  460. rv_utils_dbgr_break();
  461. #endif
  462. }
  463. // ---------------------- Instructions -------------------------
  464. /**
  465. * @brief Given the return address, calculate the address of the preceding call instruction
  466. * This is typically used to answer the question "where was the function called from?"
  467. * @param return_address The value of the return address register.
  468. * Typically set to the value of __builtin_return_address(0).
  469. * @return Address of the call instruction preceding the return address.
  470. */
  471. FORCE_INLINE_ATTR intptr_t esp_cpu_get_call_addr(intptr_t return_address)
  472. {
  473. /* Both Xtensa and RISC-V have 2-byte instructions, so to get this right we
  474. * should decode the preceding instruction as if it is 2-byte, check if it is a call,
  475. * else treat it as 3 or 4 byte one. However for the cases where this function is
  476. * used, being off by one instruction is usually okay, so this is kept simple for now.
  477. */
  478. #ifdef __XTENSA__
  479. return return_address - 3;
  480. #else
  481. return return_address - 4;
  482. #endif
  483. }
  484. /* ------------------------------------------------------ Misc ---------------------------------------------------------
  485. *
  486. * ------------------------------------------------------------------------------------------------------------------ */
  487. /**
  488. * @brief Atomic compare-and-set operation
  489. *
  490. * @param addr Address of atomic variable
  491. * @param compare_value Value to compare the atomic variable to
  492. * @param new_value New value to set the atomic variable to
  493. * @return Whether the atomic variable was set or not
  494. */
  495. bool esp_cpu_compare_and_set(volatile uint32_t *addr, uint32_t compare_value, uint32_t new_value);
  496. /* ---------------------------------------------------- Deprecate ------------------------------------------------------
  497. *
  498. * ------------------------------------------------------------------------------------------------------------------ */
  499. /*
  500. [refactor-todo] Make these deprecated inline
  501. */
  502. typedef esp_cpu_cycle_count_t esp_cpu_ccount_t;
  503. #define esp_cpu_get_ccount() esp_cpu_get_cycle_count()
  504. #define esp_cpu_set_ccount(ccount) esp_cpu_set_cycle_count(ccount)
  505. /**
  506. * @brief Returns true if a JTAG debugger is attached to CPU OCD (on chip debug) port.
  507. *
  508. * [refactor-todo] See if this can be replaced with esp_cpu_dbgr_is_attached directly
  509. *
  510. * @note Always returns false if CONFIG_ESP_DEBUG_OCDAWARE is not enabled
  511. */
  512. FORCE_INLINE_ATTR bool esp_cpu_in_ocd_debug_mode(void)
  513. {
  514. #if CONFIG_ESP_DEBUG_OCDAWARE
  515. return esp_cpu_dbgr_is_attached();
  516. #else // CONFIG_ESP_DEBUG_OCDAWARE
  517. return false; // Always return false if "OCD aware" is disabled
  518. #endif // CONFIG_ESP_DEBUG_OCDAWARE
  519. }
  520. #ifdef __cplusplus
  521. }
  522. #endif