core_feature_plic.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /*
  2. * Copyright (c) 2019 Nuclei Limited. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the License); you may
  7. * not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an AS IS BASIS, WITHOUT
  14. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. #ifndef __CORE_FEATURE_PLIC__
  19. #define __CORE_FEATURE_PLIC__
  20. /*!
  21. * @file core_feature_plic.h
  22. * @brief PLIC feature API header file for RISC-V Core
  23. */
  24. /*
  25. * PLIC Feature Configuration Macro:
  26. * 1. __PLIC_PRESENT: Define whether Platform Level Interrupt Controller (PLIC) Unit is present or not
  27. * * 0: Not present
  28. * * 1: Present
  29. * 2. __PLIC_BASEADDR: Base address of the PLIC unit.
  30. * 3. __PLIC_INTNUM : Define the external interrupt number of PLIC Unit
  31. *
  32. */
  33. #ifdef __cplusplus
  34. extern "C" {
  35. #endif
  36. #include "core_feature_base.h"
  37. #if defined(__PLIC_PRESENT) && (__PLIC_PRESENT == 1)
  38. /**
  39. * \defgroup NMSIS_Core_PLIC_Registers Register Define and Type Definitions Of PLIC
  40. * \ingroup NMSIS_Core_Registers
  41. * \brief Type definitions and defines for plic registers.
  42. *
  43. * @{
  44. */
  45. /* 32 bits per source */
  46. #define PLIC_PRIORITY_OFFSET _AC(0x0000,UL) /*!< PLIC Priority register offset */
  47. #define PLIC_PRIORITY_SHIFT_PER_SOURCE 2 /*!< PLIC Priority register offset shift per source */
  48. /* 1 bit per source (1 address) */
  49. #define PLIC_PENDING_OFFSET _AC(0x1000,UL) /*!< PLIC Pending register offset */
  50. #define PLIC_PENDING_SHIFT_PER_SOURCE 0 /*!< PLIC Pending register offset shift per source */
  51. /* 0x80 per context */
  52. #define PLIC_ENABLE_OFFSET _AC(0x2000,UL) /*!< PLIC Enable register offset */
  53. #define PLIC_ENABLE_SHIFT_PER_CONTEXT 7 /*!< PLIC Enable register offset shift per context */
  54. #define PLIC_THRESHOLD_OFFSET _AC(0x200000,UL) /*!< PLIC Threshold register offset */
  55. #define PLIC_CLAIM_OFFSET _AC(0x200004,UL) /*!< PLIC Claim register offset */
  56. #define PLIC_THRESHOLD_SHIFT_PER_CONTEXT 12 /*!< PLIC Threshold register offset shift per context */
  57. #define PLIC_CLAIM_SHIFT_PER_CONTEXT 12 /*!< PLIC Claim register offset shift per context */
  58. #ifndef __PLIC_BASEADDR
  59. /* Base address of PLIC(__PLIC_BASEADDR) should be defined in <Device.h> */
  60. #error "__PLIC_BASEADDR is not defined, please check!"
  61. #endif
  62. /* PLIC Memory mapping of Device */
  63. #define PLIC_BASE __PLIC_BASEADDR /*!< PLIC Base Address */
  64. /**
  65. * PLIC_GetHartID() is used to get plic hartid which might not be the same as cpu hart id,
  66. * for example, cpu hartid may be 1, but plic hartid may be 0, then plic hartid offset is 1.
  67. * If defined __PLIC_HARTID, it will use __PLIC_HARTID as plic hartid,
  68. * otherwise, it will use __get_hart_index().
  69. * The cpu hartid is get by using __get_hart_id function
  70. */
  71. #ifndef __PLIC_HARTID
  72. #define PLIC_GetHartID() (__get_hart_index())
  73. #define PLIC_GetHartID_S() (__get_hart_index_s())
  74. #else
  75. #define PLIC_GetHartID() (__PLIC_HARTID)
  76. #define PLIC_GetHartID_S() (__PLIC_HARTID)
  77. #endif
  78. #define PLIC_GetHartMContextID() (PLIC_GetHartID() << 1)
  79. // TODO SMODE HARTID need to handle, maybe use a predefined variable of hartid
  80. #define PLIC_GetHartSContextID() ((PLIC_GetHartID_S() << 1) + 1)
  81. #define PLIC_PRIORITY_REGADDR(source) ((PLIC_BASE) + (PLIC_PRIORITY_OFFSET) + ((source) << PLIC_PRIORITY_SHIFT_PER_SOURCE))
  82. #define PLIC_PENDING_REGADDR(source) ((PLIC_BASE) + (PLIC_PENDING_OFFSET) + (((source) >> 5) * 4))
  83. #define PLIC_ENABLE_REGADDR(ctxid, source) ((PLIC_BASE) + (PLIC_ENABLE_OFFSET) + ((ctxid) << PLIC_ENABLE_SHIFT_PER_CONTEXT) + ((source) >> 5) * 4)
  84. #define PLIC_THRESHOLD_REGADDR(ctxid) ((PLIC_BASE) + (PLIC_THRESHOLD_OFFSET) + ((ctxid) << PLIC_THRESHOLD_SHIFT_PER_CONTEXT))
  85. #define PLIC_CLAIM_REGADDR(ctxid) ((PLIC_BASE) + (PLIC_CLAIM_OFFSET) + ((ctxid) << PLIC_CLAIM_SHIFT_PER_CONTEXT))
  86. #define PLIC_COMPLETE_REGADDR(ctxid) (PLIC_CLAIM_REGADDR(ctxid))
  87. /** @} */ /* end of group NMSIS_Core_PLIC_Registers */
  88. /* ########################## PLIC functions #################################### */
  89. /**
  90. * \defgroup NMSIS_Core_IntPlic PLIC Interrupt
  91. * \brief Functions that manage interrupts via the PLIC.
  92. *
  93. * @{
  94. */
  95. /**
  96. * \brief Set priority threshold value of plic for selected context
  97. * \details
  98. * This function set priority threshold value of plic for selected context.
  99. * \param [in] ctxid selected context id
  100. * \param [in] thresh threshold value
  101. * \remarks
  102. * \sa
  103. * - \ref PLIC_GetContextThreshold
  104. */
  105. __STATIC_FORCEINLINE void PLIC_SetContextThreshold(uint32_t ctxid, uint32_t thresh)
  106. {
  107. volatile uint32_t *thresh_reg = (uint32_t *)PLIC_THRESHOLD_REGADDR(ctxid);
  108. *thresh_reg = thresh;
  109. }
  110. /**
  111. * \brief Get priority threshold value of plic for selected context
  112. * \details
  113. * This function get priority threshold value of plic for selected context.
  114. * \param [in] ctxid selected context id
  115. * \return priority threshold value for selected context
  116. * \remarks
  117. * \sa
  118. * - \ref PLIC_SetContextThreshold
  119. */
  120. __STATIC_FORCEINLINE uint32_t PLIC_GetContextThreshold(uint32_t ctxid)
  121. {
  122. volatile uint32_t *thresh_reg = (uint32_t *)PLIC_THRESHOLD_REGADDR(ctxid);
  123. return (*thresh_reg);
  124. }
  125. /**
  126. * \brief Enable interrupt of selected source plic for selected context
  127. * \details
  128. * This function enable interrupt of selected source plic for selected context.
  129. * \param [in] ctxid selected context id
  130. * \param [in] source interrupt source
  131. * \remarks
  132. * \sa
  133. * - \ref PLIC_DisableContextInterrupt
  134. */
  135. __STATIC_FORCEINLINE void PLIC_EnableContextInterrupt(uint32_t ctxid, uint32_t source)
  136. {
  137. volatile uint32_t *enable_reg = (uint32_t *)PLIC_ENABLE_REGADDR(ctxid, source);
  138. uint32_t current = *enable_reg;
  139. current = current | (1UL << (source & 0x1F));
  140. *enable_reg = current;
  141. }
  142. /**
  143. * \brief Disable interrupt of selected source plic for selected context
  144. * \details
  145. * This function disable interrupt of selected source plic for selected context
  146. * \param [in] ctxid selected context id
  147. * \param [in] source interrupt source
  148. * \remarks
  149. * \sa
  150. * - \ref PLIC_EnableContextInterrupt
  151. */
  152. __STATIC_FORCEINLINE void PLIC_DisableContextInterrupt(uint32_t ctxid, uint32_t source)
  153. {
  154. volatile uint32_t *enable_reg = (uint32_t *)PLIC_ENABLE_REGADDR(ctxid, source);
  155. uint32_t current = *enable_reg;
  156. current = current & (~(1UL << (source & 0x1F)));
  157. *enable_reg = current;
  158. }
  159. /**
  160. * \brief Get interrupt enable status of selected source plic for selected context
  161. * \details
  162. * This function get interrupt enable of selected source plic for selected context.
  163. * \param [in] ctxid selected context id
  164. * \param [in] source interrupt source
  165. * \return enable status for selected interrupt source for selected context
  166. * \remarks
  167. * \sa
  168. * - \ref PLIC_EnableContextInterrupt
  169. * - \ref PLIC_DisableContextInterrupt
  170. */
  171. __STATIC_FORCEINLINE uint32_t PLIC_GetContextInterruptEnable(uint32_t ctxid, uint32_t source)
  172. {
  173. volatile uint32_t *enable_reg = (uint32_t *)PLIC_ENABLE_REGADDR(ctxid, source);
  174. uint32_t current = *enable_reg;
  175. current = (current >> (source & 0x1F)) & 0x1;
  176. return current;
  177. }
  178. /**
  179. * \brief Set interrupt pending of selected source plic
  180. * \details
  181. * This function set interrupt pending of selected source plic.
  182. * \param [in] source interrupt source
  183. * \remarks
  184. * \sa
  185. * - \ref PLIC_GetInterruptPending
  186. * - \ref PLIC_CLearInterruptPending
  187. */
  188. __STATIC_FORCEINLINE void PLIC_SetInterruptPending(uint32_t source)
  189. {
  190. volatile uint32_t *pending_reg = (uint32_t *)PLIC_PENDING_REGADDR(source);
  191. uint32_t current = *pending_reg;
  192. current = current | (1UL << (source & 0x1F));
  193. *pending_reg = current;
  194. }
  195. /**
  196. * \brief Clear interrupt pending of selected source plic
  197. * \details
  198. * This function clear interrupt pending of selected source plic
  199. * \param [in] source interrupt source
  200. * \remarks
  201. * \sa
  202. * - \ref PLIC_SetInterruptPending
  203. * - \ref PLIC_GetInterruptPending
  204. */
  205. __STATIC_FORCEINLINE void PLIC_ClearInterruptPending(uint32_t source)
  206. {
  207. volatile uint32_t *pending_reg = (uint32_t *)PLIC_PENDING_REGADDR(source);
  208. uint32_t current = *pending_reg;
  209. current = current & (~(1UL << (source & 0x1F)));
  210. *pending_reg = current;
  211. }
  212. /**
  213. * \brief Get interrupt pending status of selected source plic
  214. * \details
  215. * This function get interrupt pending of selected source plic
  216. * \param [in] source interrupt source
  217. * \return interrupt pending status for selected interrupt source
  218. * \remarks
  219. * \sa
  220. * - \ref PLIC_SetInterruptPending
  221. * - \ref PLIC_ClearInterruptPending
  222. */
  223. __STATIC_FORCEINLINE uint32_t PLIC_GetInterruptPending(uint32_t source)
  224. {
  225. volatile uint32_t *pending_reg = (uint32_t *)PLIC_PENDING_REGADDR(source);
  226. uint32_t current = *pending_reg;
  227. current = (current >> (source & 0x1F)) & 0x1;
  228. return current;
  229. }
  230. /**
  231. * \brief Set interrupt priority for selected source plic
  232. * \details
  233. * This function set interrupt priority for selected source plic.
  234. * \param [in] source interrupt source
  235. * \param [in] priority interrupt priority
  236. * \remarks
  237. * \sa
  238. * - \ref PLIC_GetPriority
  239. */
  240. __STATIC_FORCEINLINE void PLIC_SetPriority(uint32_t source, uint32_t priority)
  241. {
  242. volatile uint32_t *priority_reg = (uint32_t *)PLIC_PRIORITY_REGADDR(source);
  243. *priority_reg = priority;
  244. }
  245. /**
  246. * \brief Get interrupt priority for selected source plic
  247. * \details
  248. * This function get interrupt priority for selected source plic.
  249. * \param [in] source interrupt source
  250. * \param [in] priority interrupt priority
  251. * \remarks
  252. * \sa
  253. * - \ref PLIC_SetPriority
  254. */
  255. __STATIC_FORCEINLINE uint32_t PLIC_GetPriority(uint32_t source)
  256. {
  257. volatile uint32_t *priority_reg = (uint32_t *)PLIC_PRIORITY_REGADDR(source);
  258. return (*priority_reg);
  259. }
  260. /**
  261. * \brief Claim interrupt for plic for selected context
  262. * \details
  263. * This function claim interrupt for plic for selected context.
  264. * \param [in] ctxid selected context id
  265. * \return the ID of the highest priority pending interrupt or
  266. * zero if there is no pending interrupt
  267. * \remarks
  268. * A successful claim will also atomically clear the corresponding pending bit
  269. * on the interrupt source. The PLIC can perform a claim at any time and the
  270. * claim operation is not affected by the setting of the priority threshold register.
  271. * \sa
  272. * - \ref PLIC_CompleteContextInterrupt
  273. */
  274. __STATIC_FORCEINLINE uint32_t PLIC_ClaimContextInterrupt(uint32_t ctxid)
  275. {
  276. volatile uint32_t *claim_reg = (uint32_t *)PLIC_CLAIM_REGADDR(ctxid);
  277. return (*claim_reg);
  278. }
  279. /**
  280. * \brief Complete interrupt for plic for selected context
  281. * \details
  282. * This function complete interrupt for plic for selected context.
  283. * \param [in] ctxid selected context id
  284. * \return the ID of the highest priority pending interrupt or
  285. * zero if there is no pending interrupt
  286. * \remarks
  287. * The PLIC signals it has completed executing an interrupt handler by writing
  288. * the interrupt ID it received from the claim to the claim/complete register.
  289. * The PLIC does not check whether the completion ID is the same as the last
  290. * claim ID for that context.
  291. * If the completion ID does not match an interrupt source that is currently
  292. * enabled for the context, the completion is silently ignored.
  293. * \sa
  294. * - \ref PLIC_ClaimContextInterrupt
  295. */
  296. __STATIC_FORCEINLINE void PLIC_CompleteContextInterrupt(uint32_t ctxid, uint32_t source)
  297. {
  298. volatile uint32_t *complete_reg = (uint32_t *)PLIC_COMPLETE_REGADDR(ctxid);
  299. *complete_reg = source;
  300. }
  301. /**
  302. * \brief Perform init for plic for selected context
  303. * \details
  304. * This function perform initialization steps for plic for selected context.
  305. * \param [in] ctxid selected context id
  306. * \param [in] num_sources plic interrupt source count number
  307. * \param [in] enable plic interrupt enable or not
  308. * \param [in] thresh plic interrupt threshold
  309. * \remarks
  310. * * Disable all interrupts
  311. * * Set priority threshold to value specified by thresh
  312. */
  313. __STATIC_INLINE void PLIC_Context_Init(uint32_t ctxid, uint32_t num_sources, uint32_t enable, uint32_t thresh)
  314. {
  315. uint32_t i;
  316. for (i = 0; i < num_sources; i ++) {
  317. if (enable) {
  318. PLIC_EnableContextInterrupt(ctxid, i);
  319. } else {
  320. PLIC_DisableContextInterrupt(ctxid, i);
  321. }
  322. }
  323. PLIC_SetContextThreshold(ctxid, thresh);
  324. }
  325. #define PLIC_Init(num_sources, enable, thresh) PLIC_Context_Init(PLIC_GetHartMContextID(), (num_sources), (enable), (thresh))
  326. #define PLIC_Init_S(num_sources, enable, thresh) PLIC_Context_Init(PLIC_GetHartSContextID(), (num_sources), (enable), (thresh))
  327. #define PLIC_ClaimInterrupt() PLIC_ClaimContextInterrupt(PLIC_GetHartMContextID())
  328. #define PLIC_ClaimInterrupt_S() PLIC_ClaimContextInterrupt(PLIC_GetHartSContextID())
  329. #define PLIC_CompleteInterrupt(source) PLIC_CompleteContextInterrupt(PLIC_GetHartMContextID(), (source))
  330. #define PLIC_CompleteInterrupt_S(source) PLIC_CompleteContextInterrupt(PLIC_GetHartSContextID(), (source))
  331. #define PLIC_GetInterruptEnable(source) PLIC_GetContextInterruptEnable(PLIC_GetHartMContextID(), (source))
  332. #define PLIC_GetInterruptEnable_S(source) PLIC_GetContextInterruptEnable(PLIC_GetHartSContextID(), (source))
  333. #define PLIC_EnableInterrupt(source) PLIC_EnableContextInterrupt(PLIC_GetHartMContextID(), (source))
  334. #define PLIC_EnableInterrupt_S(source) PLIC_EnableContextInterrupt(PLIC_GetHartSContextID(), (source))
  335. #define PLIC_DisableInterrupt(source) PLIC_DisableContextInterrupt(PLIC_GetHartMContextID(), (source))
  336. #define PLIC_DisableInterrupt_S(source) PLIC_DisableContextInterrupt(PLIC_GetHartSContextID(), (source))
  337. #define PLIC_SetThreshold(source, thresh) PLIC_SetContextThreshold(PLIC_GetHartMContextID(), (source), (thresh))
  338. #define PLIC_SetThreshold_S(source, thresh) PLIC_SetContextThreshold(PLIC_GetHartSContextID(), (source), (thresh))
  339. #define PLIC_GetThreshold() PLIC_GetContextThreshold(PLIC_GetHartMContextID())
  340. #define PLIC_GetThreshold_S() PLIC_GetContextThreshold(PLIC_GetHartSContextID())
  341. /**
  342. * \brief Set Trap entry address
  343. * \details
  344. * This function set trap entry address to 'CSR_MTVEC'.
  345. * \param [in] addr trap entry address
  346. * \remarks
  347. * - This function use to set trap entry address to 'CSR_MTVEC'.
  348. * \sa
  349. * - \ref __get_trap_entry
  350. */
  351. __STATIC_FORCEINLINE void __set_trap_entry(rv_csr_t addr)
  352. {
  353. addr &= (rv_csr_t)(~0x7);
  354. __RV_CSR_WRITE(CSR_MTVEC, addr);
  355. }
  356. /**
  357. * \brief Get trap entry address
  358. * \details
  359. * This function get trap entry address from 'CSR_MTVEC'.
  360. * \return trap entry address
  361. * \remarks
  362. * - This function use to get trap entry address from 'CSR_MTVEC'.
  363. * \sa
  364. * - \ref __set_trap_entry
  365. */
  366. __STATIC_FORCEINLINE rv_csr_t __get_trap_entry(void)
  367. {
  368. unsigned long addr = __RV_CSR_READ(CSR_MTVEC);
  369. return (addr);
  370. }
  371. /** @} */ /* End of Doxygen Group NMSIS_Core_IntExc */
  372. #endif /* defined(__PLIC_PRESENT) && (__PLIC_PRESENT == 1) */
  373. #ifdef __cplusplus
  374. }
  375. #endif
  376. #endif /** __CORE_FEATURE_PLIC__ */