1 /***************************************************************************//**
2  * @file
3  * @brief Core interrupt handling API
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 #ifndef EM_CORE_H
31 #define EM_CORE_H
32 
33 #include "em_device.h"
34 #include "em_common.h"
35 
36 #include <stdbool.h>
37 
38 #if defined(EMLIB_USER_CONFIG)
39 #include "emlib_config.h"
40 #endif
41 
42 #if defined(SL_COMPONENT_CATALOG_PRESENT)
43 #include "sl_component_catalog.h"
44 #endif
45 
46 /***************************************************************************//**
47  * @addtogroup core
48  * @{
49  ******************************************************************************/
50 
51 /*******************************************************************************
52  *******************************   DEFINES   ***********************************
53  ******************************************************************************/
54 
55 /** Use PRIMASK register to disable interrupts in ATOMIC sections. */
56 #define CORE_ATOMIC_METHOD_PRIMASK  0
57 
58 /** Use BASEPRI register to disable interrupts in ATOMIC sections. */
59 #define CORE_ATOMIC_METHOD_BASEPRI  1
60 
61 /** Number of words in a NVIC mask set. */
62 #define CORE_NVIC_REG_WORDS   ((EXT_IRQ_COUNT + 31) / 32)
63 
64 /** Number of entries in a default interrupt vector table. */
65 #define CORE_DEFAULT_VECTOR_TABLE_ENTRIES   (EXT_IRQ_COUNT + 16)
66 
67 // Interrupt priorities based on processor architecture
68 #if defined(__CM3_REV) || defined(__CM4_REV) || defined(__CM7_REV) \
69  || defined(__CM23_REV) || defined(__CM33_REV)
70 #define CORE_INTERRUPT_HIGHEST_PRIORITY 0
71 #define CORE_INTERRUPT_DEFAULT_PRIORITY 5
72 #define CORE_INTERRUPT_LOWEST_PRIORITY 7
73 
74 #define CORE_ATOMIC_METHOD_DEFAULT  CORE_ATOMIC_METHOD_BASEPRI
75 #elif defined(__CM0_REV) || defined(__CM0PLUS_REV)
76 #define CORE_INTERRUPT_HIGHEST_PRIORITY 0
77 #define CORE_INTERRUPT_DEFAULT_PRIORITY 1
78 #define CORE_INTERRUPT_LOWEST_PRIORITY 3
79 
80 #define CORE_ATOMIC_METHOD_DEFAULT  CORE_ATOMIC_METHOD_PRIMASK
81 #endif
82 
83 #if !defined(CORE_ATOMIC_BASE_PRIORITY_LEVEL)
84 /** The interrupt priority level disabled within ATOMIC regions. Interrupts
85  *  with priority level equal to or lower than this definition will be disabled
86  *  within ATOMIC regions. */
87 #define CORE_ATOMIC_BASE_PRIORITY_LEVEL  3
88 #endif
89 
90 #if !defined(CORE_ATOMIC_METHOD)
91 /** Specify which method to use when implementing ATOMIC sections. You can
92  *  select between BASEPRI or PRIMASK method.
93  *  @note On Cortex-M0+ devices only PRIMASK can be used. */
94 #if !defined(SL_CATALOG_DEVICE_INIT_NVIC_PRESENT)
95 #define CORE_ATOMIC_METHOD    CORE_ATOMIC_METHOD_PRIMASK
96 #else
97 #define CORE_ATOMIC_METHOD   CORE_ATOMIC_METHOD_DEFAULT
98 #endif
99 #endif
100 
101 // Compile time sanity check.
102 #if (CORE_NVIC_REG_WORDS > 3)
103 #error "em_core: Unexpected NVIC external interrupt count."
104 #endif
105 
106 #ifdef __cplusplus
107 extern "C" {
108 #endif
109 
110 /*******************************************************************************
111  ************************   MACRO API   ***************************************
112  ******************************************************************************/
113 
114 //
115 //  CRITICAL section macro API.
116 //
117 
118 /** Allocate storage for PRIMASK or BASEPRI value for use by
119  *  CORE_ENTER/EXIT_ATOMIC() and CORE_ENTER/EXIT_CRITICAL() macros. */
120 #define CORE_DECLARE_IRQ_STATE        CORE_irqState_t irqState
121 
122 /** CRITICAL style interrupt disable. */
123 #define CORE_CRITICAL_IRQ_DISABLE() CORE_CriticalDisableIrq()
124 
125 /** CRITICAL style interrupt enable. */
126 #define CORE_CRITICAL_IRQ_ENABLE()  CORE_CriticalEnableIrq()
127 
128 /** Convenience macro for implementing a CRITICAL section. */
129 #define CORE_CRITICAL_SECTION(yourcode) \
130   {                                     \
131     CORE_DECLARE_IRQ_STATE;             \
132     CORE_ENTER_CRITICAL();              \
133     {                                   \
134       yourcode                          \
135     }                                   \
136     CORE_EXIT_CRITICAL();               \
137   }
138 
139 /** Enter CRITICAL section. Assumes that a @ref CORE_DECLARE_IRQ_STATE exist in
140  *  scope. */
141 #define CORE_ENTER_CRITICAL()   irqState = CORE_EnterCritical()
142 
143 /** Exit CRITICAL section. Assumes that a @ref CORE_DECLARE_IRQ_STATE exist in
144  *  scope. */
145 #define CORE_EXIT_CRITICAL()    CORE_ExitCritical(irqState)
146 
147 /** CRITICAL style yield. */
148 #define CORE_YIELD_CRITICAL()   CORE_YieldCritical()
149 
150 //
151 //  ATOMIC section macro API.
152 //
153 
154 /** ATOMIC style interrupt disable. */
155 #define CORE_ATOMIC_IRQ_DISABLE()   CORE_AtomicDisableIrq()
156 
157 /** ATOMIC style interrupt enable. */
158 #define CORE_ATOMIC_IRQ_ENABLE()    CORE_AtomicEnableIrq()
159 
160 /** Convenience macro for implementing an ATOMIC section. */
161 #define CORE_ATOMIC_SECTION(yourcode) \
162   {                                   \
163     CORE_DECLARE_IRQ_STATE;           \
164     CORE_ENTER_ATOMIC();              \
165     {                                 \
166       yourcode                        \
167     }                                 \
168     CORE_EXIT_ATOMIC();               \
169   }
170 
171 /** Enter ATOMIC section. Assumes that a @ref CORE_DECLARE_IRQ_STATE exist in
172  *  scope. */
173 #define CORE_ENTER_ATOMIC()   irqState = CORE_EnterAtomic()
174 
175 /** Exit ATOMIC section. Assumes that a @ref CORE_DECLARE_IRQ_STATE exist in
176  *  scope. */
177 #define CORE_EXIT_ATOMIC()    CORE_ExitAtomic(irqState)
178 
179 /** ATOMIC style yield. */
180 #define CORE_YIELD_ATOMIC()   CORE_YieldAtomic()
181 
182 //
183 //  NVIC mask section macro API.
184 //
185 
186 /** Allocate storage for NVIC interrupt masks for use by
187  *  CORE_ENTER/EXIT_NVIC() macros. */
188 #define CORE_DECLARE_NVIC_STATE       CORE_nvicMask_t nvicState
189 
190 /** Allocate storage for NVIC interrupt masks.
191  *  @param[in] x
192  *    The storage variable name to use.*/
193 #define CORE_DECLARE_NVIC_MASK(x)     CORE_nvicMask_t x
194 
195 /** Allocate storage for and zero initialize NVIC interrupt mask.
196  *  @param[in] x
197  *    The storage variable name to use.*/
198 #define CORE_DECLARE_NVIC_ZEROMASK(x) CORE_nvicMask_t x = { { 0 } }
199 
200 /** NVIC mask style interrupt disable.
201  *  @param[in] mask
202  *    Mask specifying which NVIC interrupts to disable. */
203 #define CORE_NVIC_DISABLE(mask)   CORE_NvicDisableMask(mask)
204 
205 /** NVIC mask style interrupt enable.
206  *  @param[in] mask
207  *    Mask specifying which NVIC interrupts to enable. */
208 #define CORE_NVIC_ENABLE(mask)    CORE_NvicEnableMask(mask)
209 
210 /** Convenience macro for implementing a NVIC mask section.
211  *  @param[in] mask
212  *    Mask specifying which NVIC interrupts to disable within the section.
213  *  @param[in] yourcode
214  *    The code for the section. */
215 #define CORE_NVIC_SECTION(mask, yourcode) \
216   {                                       \
217     CORE_DECLARE_NVIC_STATE;              \
218     CORE_ENTER_NVIC(mask);                \
219     {                                     \
220       yourcode                            \
221     }                                     \
222     CORE_EXIT_NVIC();                     \
223   }
224 
225 /** Enter NVIC mask section. Assumes that a @ref CORE_DECLARE_NVIC_STATE exist
226  *  in scope.
227  *  @param[in] disable
228  *    Mask specifying which NVIC interrupts to disable within the section. */
229 #define CORE_ENTER_NVIC(disable)  CORE_EnterNvicMask(&nvicState, disable)
230 
231 /** Exit NVIC mask section. Assumes that a @ref CORE_DECLARE_NVIC_STATE exist
232  *  in scope. */
233 #define CORE_EXIT_NVIC()          CORE_NvicEnableMask(&nvicState)
234 
235 /** NVIC maks style yield.
236  * @param[in] enable
237  *   Mask specifying which NVIC interrupts to briefly enable. */
238 #define CORE_YIELD_NVIC(enable)   CORE_YieldNvicMask(enable)
239 
240 //
241 //  Miscellaneous macros.
242 //
243 
244 /** Check if IRQ is disabled. */
245 #define CORE_IRQ_DISABLED()       CORE_IrqIsDisabled()
246 
247 /** Check if inside an IRQ handler. */
248 #define CORE_IN_IRQ_CONTEXT()     CORE_InIrqContext()
249 
250 /*******************************************************************************
251  *************************   TYPEDEFS   ****************************************
252  ******************************************************************************/
253 
254 /** Storage for PRIMASK or BASEPRI value. */
255 typedef uint32_t CORE_irqState_t;
256 
257 /** Storage for NVIC interrupt masks. */
258 typedef struct {
259   uint32_t a[CORE_NVIC_REG_WORDS];    /*!< Array of NVIC mask words. */
260 } CORE_nvicMask_t;
261 
262 /*******************************************************************************
263  *****************************   PROTOTYPES   **********************************
264  ******************************************************************************/
265 
266 void CORE_CriticalDisableIrq(void);
267 void CORE_CriticalEnableIrq(void);
268 void CORE_ExitCritical(CORE_irqState_t irqState);
269 void CORE_YieldCritical(void);
270 CORE_irqState_t CORE_EnterCritical(void);
271 
272 void  CORE_AtomicDisableIrq(void);
273 void  CORE_AtomicEnableIrq(void);
274 void  CORE_ExitAtomic(CORE_irqState_t irqState);
275 void  CORE_YieldAtomic(void);
276 CORE_irqState_t CORE_EnterAtomic(void);
277 
278 bool  CORE_InIrqContext(void);
279 bool  CORE_IrqIsBlocked(IRQn_Type irqN);
280 bool  CORE_IrqIsDisabled(void);
281 
282 void  CORE_GetNvicEnabledMask(CORE_nvicMask_t *mask);
283 bool  CORE_GetNvicMaskDisableState(const CORE_nvicMask_t *mask);
284 
285 void  CORE_EnterNvicMask(CORE_nvicMask_t *nvicState,
286                          const CORE_nvicMask_t *disable);
287 void  CORE_NvicDisableMask(const CORE_nvicMask_t *disable);
288 void  CORE_NvicEnableMask(const CORE_nvicMask_t *enable);
289 void  CORE_YieldNvicMask(const CORE_nvicMask_t *enable);
290 void  CORE_NvicMaskSetIRQ(IRQn_Type irqN, CORE_nvicMask_t *mask);
291 void  CORE_NvicMaskClearIRQ(IRQn_Type irqN, CORE_nvicMask_t *mask);
292 bool  CORE_NvicIRQDisabled(IRQn_Type irqN);
293 
294 void *CORE_GetNvicRamTableHandler(IRQn_Type irqN);
295 void  CORE_SetNvicRamTableHandler(IRQn_Type irqN, void *handler);
296 void  CORE_InitNvicVectorTable(uint32_t *sourceTable,
297                                uint32_t sourceSize,
298                                uint32_t *targetTable,
299                                uint32_t targetSize,
300                                void *defaultHandler,
301                                bool overwriteActive);
302 
303 #ifdef __cplusplus
304 }
305 #endif
306 
307 /** @} (end addtogroup core) */
308 
309 #endif /* EM_CORE_H */
310