• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_ECLIC__
19 #define __CORE_FEATURE_ECLIC__
20 /*!
21  * @file     core_feature_eclic.h
22  * @brief    ECLIC feature API header file for Nuclei N/NX Core
23  */
24 /*
25  * ECLIC Feature Configuration Macro:
26  * 1. __ECLIC_PRESENT:  Define whether Enhanced Core Local Interrupt Controller (ECLIC) Unit is present or not
27  *   * 0: Not present
28  *   * 1: Present
29  * 2. __ECLIC_BASEADDR:  Base address of the ECLIC unit.
30  * 3. ECLIC_GetInfoCtlbits():  Define the number of hardware bits are actually implemented in the clicintctl registers.
31  *   Valid number is 1 - 8.
32  * 4. __ECLIC_INTNUM  : Define the external interrupt number of ECLIC Unit
33  *
34  */
35 #ifdef __cplusplus
36  extern "C" {
37 #endif
38 
39 #if defined(__ECLIC_PRESENT) && (__ECLIC_PRESENT == 1)
40 /**
41  * \defgroup NMSIS_Core_ECLIC_Registers     Register Define and Type Definitions Of ECLIC
42  * \ingroup NMSIS_Core_Registers
43  * \brief   Type definitions and defines for eclic registers.
44  *
45  * @{
46  */
47 
48 /**
49  * \brief  Union type to access CLICFG configure register.
50  */
51 typedef union
52 {
53     struct {
54         uint8_t _reserved0:1;                   /*!< bit:     0   Overflow condition code flag */
55         uint8_t nlbits:4;                       /*!< bit:     29  Carry condition code flag */
56         uint8_t _reserved1:2;                   /*!< bit:     30  Zero condition code flag */
57         uint8_t _reserved2:1;                   /*!< bit:     31  Negative condition code flag */
58     } b;                                        /*!< Structure used for bit  access */
59     uint8_t w;                                  /*!< Type      used for byte access */
60 } CLICCFG_Type;
61 
62 /**
63  * \brief  Union type to access CLICINFO information register.
64  */
65 typedef union {
66     struct {
67         uint32_t numint:13;                     /*!< bit:  0..12   number of maximum interrupt inputs supported */
68         uint32_t version:8;                     /*!< bit:  13..20  20:17 for architecture version,16:13 for implementation version */
69         uint32_t intctlbits:4;                  /*!< bit:  21..24  specifies how many hardware bits are actually implemented in the clicintctl registers */
70         uint32_t _reserved0:7;                  /*!< bit:  25..31  Reserved */
71     } b;                                        /*!< Structure used for bit  access */
72     uint32_t w;                                 /*!< Type      used for word access */
73 } CLICINFO_Type;
74 
75 /**
76  * \brief Access to the structure of a vector interrupt controller.
77  */
78 typedef struct {
79     __IOM uint8_t  INTIP;                       /*!< Offset: 0x000 (R/W)  Interrupt set pending register */
80     __IOM uint8_t  INTIE;                       /*!< Offset: 0x001 (R/W)  Interrupt set enable register */
81     __IOM uint8_t  INTATTR;                     /*!< Offset: 0x002 (R/W)  Interrupt set attributes register */
82     __IOM uint8_t  INTCTRL;                     /*!< Offset: 0x003 (R/W)  Interrupt configure register */
83 } CLIC_CTRL_Type;
84 
85 typedef struct {
86     __IOM uint8_t   CFG;                        /*!< Offset: 0x000 (R/W)  CLIC configuration register */
87     uint8_t RESERVED0[3];
88     __IM uint32_t  INFO;                        /*!< Offset: 0x004 (R/ )  CLIC information register */
89     uint8_t RESERVED1[3];
90     __IOM uint8_t  MTH;                         /*!< Offset: 0x00B (R/W)  CLIC machine mode threshold register */
91     uint32_t RESERVED2[0x3FD];
92     CLIC_CTRL_Type CTRL[4096];                  /*!< Offset: 0x1000 (R/W) CLIC register structure for INTIP, INTIE, INTATTR, INTCTL */
93 } CLIC_Type;
94 
95 #define CLIC_CLICCFG_NLBIT_Pos                 1U                                       /*!< CLIC CLICCFG: NLBIT Position */
96 #define CLIC_CLICCFG_NLBIT_Msk                 (0xFUL << CLIC_CLICCFG_NLBIT_Pos)        /*!< CLIC CLICCFG: NLBIT Mask */
97 
98 #define CLIC_CLICINFO_CTLBIT_Pos                21U                                     /*!< CLIC INTINFO: __ECLIC_GetInfoCtlbits() Position */
99 #define CLIC_CLICINFO_CTLBIT_Msk                (0xFUL << CLIC_CLICINFO_CTLBIT_Pos)     /*!< CLIC INTINFO: __ECLIC_GetInfoCtlbits() Mask */
100 
101 #define CLIC_CLICINFO_VER_Pos                  13U                                      /*!< CLIC CLICINFO: VERSION Position */
102 #define CLIC_CLICINFO_VER_Msk                  (0xFFUL << CLIC_CLICCFG_NLBIT_Pos)       /*!< CLIC CLICINFO: VERSION Mask */
103 
104 #define CLIC_CLICINFO_NUM_Pos                  0U                                       /*!< CLIC CLICINFO: NUM Position */
105 #define CLIC_CLICINFO_NUM_Msk                  (0xFFFUL << CLIC_CLICINFO_NUM_Pos)       /*!< CLIC CLICINFO: NUM Mask */
106 
107 #define CLIC_INTIP_IP_Pos                      0U                                       /*!< CLIC INTIP: IP Position */
108 #define CLIC_INTIP_IP_Msk                      (0x1UL << CLIC_INTIP_IP_Pos)             /*!< CLIC INTIP: IP Mask */
109 
110 #define CLIC_INTIE_IE_Pos                      0U                                       /*!< CLIC INTIE: IE Position */
111 #define CLIC_INTIE_IE_Msk                      (0x1UL << CLIC_INTIE_IE_Pos)             /*!< CLIC INTIE: IE Mask */
112 
113 #define CLIC_INTATTR_TRIG_Pos                  1U                                       /*!< CLIC INTATTR: TRIG Position */
114 #define CLIC_INTATTR_TRIG_Msk                  (0x3UL << CLIC_INTATTR_TRIG_Pos)         /*!< CLIC INTATTR: TRIG Mask */
115 
116 #define CLIC_INTATTR_SHV_Pos                   0U                                       /*!< CLIC INTATTR: SHV Position */
117 #define CLIC_INTATTR_SHV_Msk                   (0x1UL << CLIC_INTATTR_SHV_Pos)          /*!< CLIC INTATTR: SHV Mask */
118 
119 #define ECLIC_MAX_NLBITS                       8U                                       /*!< Max nlbit of the CLICINTCTLBITS */
120 #define ECLIC_MODE_MTVEC_Msk                   3U                                       /*!< ECLIC Mode mask for MTVT CSR Register */
121 
122 #define ECLIC_NON_VECTOR_INTERRUPT             0x0                                      /*!< Non-Vector Interrupt Mode of ECLIC */
123 #define ECLIC_VECTOR_INTERRUPT                 0x1                                      /*!< Vector Interrupt Mode of ECLIC */
124 
125 /**\brief ECLIC Trigger Enum for different Trigger Type */
126 typedef enum ECLIC_TRIGGER {
127     ECLIC_LEVEL_TRIGGER = 0x0,          /*!< Level Triggerred, trig[0] = 0 */
128     ECLIC_POSTIVE_EDGE_TRIGGER = 0x1,   /*!< Postive/Rising Edge Triggered, trig[1] = 0, trig[0] = 1 */
129     ECLIC_NEGTIVE_EDGE_TRIGGER = 0x3,   /*!< Negtive/Falling Edge Triggered, trig[1] = 1, trig[0] = 0 */
130     ECLIC_MAX_TRIGGER = 0x3             /*!< MAX Supported Trigger Mode */
131 } ECLIC_TRIGGER_Type;
132 
133 #ifndef __ECLIC_BASEADDR
134 /* Base address of ECLIC(__ECLIC_BASEADDR) should be defined in <Device.h> */
135 #error "__ECLIC_BASEADDR is not defined, please check!"
136 #endif
137 
138 #ifndef __ECLIC_INTCTLBITS
139 /* Define __ECLIC_INTCTLBITS to get via ECLIC->INFO if not defined */
140 #define __ECLIC_INTCTLBITS                  (__ECLIC_GetInfoCtlbits())
141 #endif
142 
143 /* ECLIC Memory mapping of Device */
144 #define ECLIC_BASE                          __ECLIC_BASEADDR                            /*!< ECLIC Base Address */
145 #define ECLIC                               ((CLIC_Type *) ECLIC_BASE)                  /*!< CLIC configuration struct */
146 
147 /** @} */ /* end of group NMSIS_Core_ECLIC_Registers */
148 
149 /* ##########################   ECLIC functions  #################################### */
150 /**
151  * \defgroup   NMSIS_Core_IntExc        Interrupts and Exceptions
152  * \brief Functions that manage interrupts and exceptions via the ECLIC.
153  *
154  * @{
155  */
156 
157 /**
158  * \brief  Definition of IRQn numbers
159  * \details
160  * The core interrupt enumeration names for IRQn values are defined in the file <b><Device>.h</b>.
161  * - Interrupt ID(IRQn) from 0 to 18 are reserved for core internal interrupts.
162  * - Interrupt ID(IRQn) start from 19 represent device-specific external interrupts.
163  * - The first device-specific interrupt has the IRQn value 19.
164  *
165  * The table below describes the core interrupt names and their availability in various Nuclei Cores.
166  */
167 /* The following enum IRQn definition in this file
168  * is only used for doxygen documentation generation,
169  * The <Device>.h is the real file to define it by vendor
170  */
171 #if defined(__ONLY_FOR_DOXYGEN_DOCUMENT_GENERATION__)
172 typedef enum IRQn {
173     /* ========= Nuclei N/NX Core Specific Interrupt Numbers  =========== */
174     /* Core Internal Interrupt IRQn definitions */
175     Reserved0_IRQn            =   0,              /*!<  Internal reserved */
176     Reserved1_IRQn            =   1,              /*!<  Internal reserved */
177     Reserved2_IRQn            =   2,              /*!<  Internal reserved */
178     SysTimerSW_IRQn           =   3,              /*!<  System Timer SW interrupt */
179     Reserved3_IRQn            =   4,              /*!<  Internal reserved */
180     Reserved4_IRQn            =   5,              /*!<  Internal reserved */
181     Reserved5_IRQn            =   6,              /*!<  Internal reserved */
182     SysTimer_IRQn             =   7,              /*!<  System Timer Interrupt */
183     Reserved6_IRQn            =   8,              /*!<  Internal reserved */
184     Reserved7_IRQn            =   9,              /*!<  Internal reserved */
185     Reserved8_IRQn            =  10,              /*!<  Internal reserved */
186     Reserved9_IRQn            =  11,              /*!<  Internal reserved */
187     Reserved10_IRQn           =  12,              /*!<  Internal reserved */
188     Reserved11_IRQn           =  13,              /*!<  Internal reserved */
189     Reserved12_IRQn           =  14,              /*!<  Internal reserved */
190     Reserved13_IRQn           =  15,              /*!<  Internal reserved */
191     Reserved14_IRQn           =  16,              /*!<  Internal reserved */
192     Reserved15_IRQn           =  17,              /*!<  Internal reserved */
193     Reserved16_IRQn           =  18,              /*!<  Internal reserved */
194 
195     /* ========= Device Specific Interrupt Numbers  =================== */
196     /* ToDo: add here your device specific external interrupt numbers.
197      * 19~max(NUM_INTERRUPT, 1023) is reserved number for user.
198      * Maxmum interrupt supported could get from clicinfo.NUM_INTERRUPT.
199      * According the interrupt handlers defined in startup_Device.S
200      * eg.: Interrupt for Timer#1       eclic_tim1_handler   ->   TIM1_IRQn */
201     FirstDeviceSpecificInterrupt_IRQn    = 19,    /*!< First Device Specific Interrupt */
202     SOC_INT_MAX,                                  /*!< Number of total interrupts */
203 } IRQn_Type;
204 #endif /* __ONLY_FOR_DOXYGEN_DOCUMENT_GENERATION__ */
205 
206 #ifdef NMSIS_ECLIC_VIRTUAL
207     #ifndef NMSIS_ECLIC_VIRTUAL_HEADER_FILE
208         #define NMSIS_ECLIC_VIRTUAL_HEADER_FILE "nmsis_eclic_virtual.h"
209     #endif
210     #include NMSIS_ECLIC_VIRTUAL_HEADER_FILE
211 #else
212     #define ECLIC_SetCfgNlbits            __ECLIC_SetCfgNlbits
213     #define ECLIC_GetCfgNlbits            __ECLIC_GetCfgNlbits
214     #define ECLIC_GetInfoVer              __ECLIC_GetInfoVer
215     #define ECLIC_GetInfoCtlbits          __ECLIC_GetInfoCtlbits
216     #define ECLIC_GetInfoNum              __ECLIC_GetInfoNum
217     #define ECLIC_SetMth                  __ECLIC_SetMth
218     #define ECLIC_GetMth                  __ECLIC_GetMth
219     #define ECLIC_EnableIRQ               __ECLIC_EnableIRQ
220     #define ECLIC_GetEnableIRQ            __ECLIC_GetEnableIRQ
221     #define ECLIC_DisableIRQ              __ECLIC_DisableIRQ
222     #define ECLIC_SetPendingIRQ           __ECLIC_SetPendingIRQ
223     #define ECLIC_GetPendingIRQ           __ECLIC_GetPendingIRQ
224     #define ECLIC_ClearPendingIRQ         __ECLIC_ClearPendingIRQ
225     #define ECLIC_SetTrigIRQ              __ECLIC_SetTrigIRQ
226     #define ECLIC_GetTrigIRQ              __ECLIC_GetTrigIRQ
227     #define ECLIC_SetShvIRQ               __ECLIC_SetShvIRQ
228     #define ECLIC_GetShvIRQ               __ECLIC_GetShvIRQ
229     #define ECLIC_SetCtrlIRQ              __ECLIC_SetCtrlIRQ
230     #define ECLIC_GetCtrlIRQ              __ECLIC_GetCtrlIRQ
231     #define ECLIC_SetLevelIRQ             __ECLIC_SetLevelIRQ
232     #define ECLIC_GetLevelIRQ             __ECLIC_GetLevelIRQ
233     #define ECLIC_SetPriorityIRQ          __ECLIC_SetPriorityIRQ
234     #define ECLIC_GetPriorityIRQ          __ECLIC_GetPriorityIRQ
235 
236 #endif /* NMSIS_ECLIC_VIRTUAL */
237 
238 #ifdef NMSIS_VECTAB_VIRTUAL
239     #ifndef NMSIS_VECTAB_VIRTUAL_HEADER_FILE
240         #define NMSIS_VECTAB_VIRTUAL_HEADER_FILE "nmsis_vectab_virtual.h"
241     #endif
242     #include NMSIS_VECTAB_VIRTUAL_HEADER_FILE
243 #else
244     #define ECLIC_SetVector              __ECLIC_SetVector
245     #define ECLIC_GetVector              __ECLIC_GetVector
246 #endif  /* (NMSIS_VECTAB_VIRTUAL) */
247 
248 /**
249  * \brief  Set nlbits value
250  * \details
251  * This function set the nlbits value of CLICCFG register.
252  * \param [in]    nlbits    nlbits value
253  * \remarks
254  * - nlbits is used to set the width of level in the CLICINTCTL[i].
255  * \sa
256  * - \ref ECLIC_GetCfgNlbits
257  */
__ECLIC_SetCfgNlbits(uint32_t nlbits)258 __STATIC_FORCEINLINE void __ECLIC_SetCfgNlbits(uint32_t nlbits)
259 {
260     ECLIC->CFG &= ~CLIC_CLICCFG_NLBIT_Msk;
261     ECLIC->CFG |= (uint8_t)((nlbits <<CLIC_CLICCFG_NLBIT_Pos) & CLIC_CLICCFG_NLBIT_Msk);
262 }
263 
264 /**
265  * \brief  Get nlbits value
266  * \details
267  * This function get the nlbits value of CLICCFG register.
268  * \return   nlbits value of CLICCFG register
269  * \remarks
270  * - nlbits is used to set the width of level in the CLICINTCTL[i].
271  * \sa
272  * - \ref ECLIC_SetCfgNlbits
273  */
__ECLIC_GetCfgNlbits(void)274 __STATIC_FORCEINLINE uint32_t __ECLIC_GetCfgNlbits(void)
275 {
276     return ((uint32_t)((ECLIC->CFG & CLIC_CLICCFG_NLBIT_Msk) >> CLIC_CLICCFG_NLBIT_Pos));
277 }
278 
279 /**
280  * \brief  Get the ECLIC version number
281  * \details
282  * This function gets the hardware version information from CLICINFO register.
283  * \return   hardware version number in CLICINFO register.
284  * \remarks
285  * - This function gets hardware version information from CLICINFO register.
286  * - Bit 20:17 for architecture version, bit 16:13 for implementation version.
287  * \sa
288  * - \ref ECLIC_GetInfoNum
289 */
__ECLIC_GetInfoVer(void)290 __STATIC_FORCEINLINE uint32_t __ECLIC_GetInfoVer(void)
291 {
292     return ((uint32_t)((ECLIC->INFO & CLIC_CLICINFO_VER_Msk) >> CLIC_CLICINFO_VER_Pos));
293 }
294 
295 /**
296  * \brief  Get CLICINTCTLBITS
297  * \details
298  * This function gets CLICINTCTLBITS from CLICINFO register.
299  * \return  CLICINTCTLBITS from CLICINFO register.
300  * \remarks
301  * - In the CLICINTCTL[i] registers, with 2 <= CLICINTCTLBITS <= 8.
302  * - The implemented bits are kept left-justified in the most-significant bits of each 8-bit
303  *   CLICINTCTL[I] register, with the lower unimplemented bits treated as hardwired to 1.
304  * \sa
305  * - \ref ECLIC_GetInfoNum
306  */
__ECLIC_GetInfoCtlbits(void)307 __STATIC_FORCEINLINE uint32_t __ECLIC_GetInfoCtlbits(void)
308 {
309     return ((uint32_t)((ECLIC->INFO & CLIC_CLICINFO_CTLBIT_Msk) >> CLIC_CLICINFO_CTLBIT_Pos));
310 }
311 
312 /**
313  * \brief  Get number of maximum interrupt inputs supported
314  * \details
315  * This function gets number of maximum interrupt inputs supported from CLICINFO register.
316  * \return  number of maximum interrupt inputs supported from CLICINFO register.
317  * \remarks
318  * - This function gets number of maximum interrupt inputs supported from CLICINFO register.
319  * - The num_interrupt field specifies the actual number of maximum interrupt inputs supported in this implementation.
320  * \sa
321  * - \ref ECLIC_GetInfoCtlbits
322  */
__ECLIC_GetInfoNum(void)323 __STATIC_FORCEINLINE uint32_t __ECLIC_GetInfoNum(void)
324 {
325     return ((uint32_t)((ECLIC->INFO & CLIC_CLICINFO_NUM_Msk) >> CLIC_CLICINFO_NUM_Pos));
326 }
327 
328 /**
329  * \brief  Set Machine Mode Interrupt Level Threshold
330  * \details
331  * This function sets machine mode interrupt level threshold.
332  * \param [in]  mth       Interrupt Level Threshold.
333  * \sa
334  * - \ref ECLIC_GetMth
335  */
__ECLIC_SetMth(uint8_t mth)336 __STATIC_FORCEINLINE void __ECLIC_SetMth(uint8_t mth)
337 {
338     ECLIC->MTH = mth;
339 }
340 
341 /**
342  * \brief  Get Machine Mode Interrupt Level Threshold
343  * \details
344  * This function gets machine mode interrupt level threshold.
345  * \return       Interrupt Level Threshold.
346  * \sa
347  * - \ref ECLIC_SetMth
348  */
__ECLIC_GetMth(void)349 __STATIC_FORCEINLINE uint8_t __ECLIC_GetMth(void)
350 {
351     return (ECLIC->MTH);
352 }
353 
354 
355 /**
356  * \brief  Enable a specific interrupt
357  * \details
358  * This function enables the specific interrupt \em IRQn.
359  * \param [in]  IRQn  Interrupt number
360  * \remarks
361  * - IRQn must not be negative.
362  * \sa
363  * - \ref ECLIC_DisableIRQ
364  */
__ECLIC_EnableIRQ(IRQn_Type IRQn)365 __STATIC_FORCEINLINE void __ECLIC_EnableIRQ(IRQn_Type IRQn)
366 {
367     ECLIC->CTRL[IRQn].INTIE |= CLIC_INTIE_IE_Msk;
368 }
369 
370 /**
371  * \brief  Get a specific interrupt enable status
372  * \details
373  * This function returns the interrupt enable status for the specific interrupt \em IRQn.
374  * \param [in]  IRQn  Interrupt number
375  * \returns
376  * - 0  Interrupt is not enabled
377  * - 1  Interrupt is pending
378  * \remarks
379  * - IRQn must not be negative.
380  * \sa
381  * - \ref ECLIC_EnableIRQ
382  * - \ref ECLIC_DisableIRQ
383  */
__ECLIC_GetEnableIRQ(IRQn_Type IRQn)384 __STATIC_FORCEINLINE uint32_t __ECLIC_GetEnableIRQ(IRQn_Type IRQn)
385 {
386     return((uint32_t) (ECLIC->CTRL[IRQn].INTIE) & CLIC_INTIE_IE_Msk);
387 }
388 
389 /**
390  * \brief  Disable a specific interrupt
391  * \details
392  * This function disables the specific interrupt \em IRQn.
393  * \param [in]  IRQn  Number of the external interrupt to disable
394  * \remarks
395  * - IRQn must not be negative.
396  * \sa
397  * - \ref ECLIC_EnableIRQ
398  */
__ECLIC_DisableIRQ(IRQn_Type IRQn)399 __STATIC_FORCEINLINE void __ECLIC_DisableIRQ(IRQn_Type IRQn)
400 {
401     ECLIC->CTRL[IRQn].INTIE &= ~CLIC_INTIE_IE_Msk;
402 }
403 
404 /**
405  * \brief  Get the pending specific interrupt
406  * \details
407  * This function returns the pending status of the specific interrupt \em IRQn.
408  * \param [in]      IRQn  Interrupt number
409  * \returns
410  * - 0  Interrupt is not pending
411  * - 1  Interrupt is pending
412  * \remarks
413  * - IRQn must not be negative.
414  * \sa
415  * - \ref ECLIC_SetPendingIRQ
416  * - \ref ECLIC_ClearPendingIRQ
417  */
__ECLIC_GetPendingIRQ(IRQn_Type IRQn)418 __STATIC_FORCEINLINE int32_t __ECLIC_GetPendingIRQ(IRQn_Type IRQn)
419 {
420     return((uint32_t)(ECLIC->CTRL[IRQn].INTIP) & CLIC_INTIP_IP_Msk);
421 }
422 
423 /**
424  * \brief  Set a specific interrupt to pending
425  * \details
426  * This function sets the pending bit for the specific interrupt \em IRQn.
427  * \param [in]      IRQn  Interrupt number
428  * \remarks
429  * - IRQn must not be negative.
430  * \sa
431  * - \ref ECLIC_GetPendingIRQ
432  * - \ref ECLIC_ClearPendingIRQ
433  */
__ECLIC_SetPendingIRQ(IRQn_Type IRQn)434 __STATIC_FORCEINLINE void __ECLIC_SetPendingIRQ(IRQn_Type IRQn)
435 {
436     ECLIC->CTRL[IRQn].INTIP |= CLIC_INTIP_IP_Msk;
437 }
438 
439 /**
440  * \brief  Clear a specific interrupt from pending
441  * \details
442  * This function removes the pending state of the specific interrupt \em IRQn.
443  * \em IRQn cannot be a negative number.
444  * \param [in]      IRQn  Interrupt number
445  * \remarks
446  * - IRQn must not be negative.
447  * \sa
448  * - \ref ECLIC_SetPendingIRQ
449  * - \ref ECLIC_GetPendingIRQ
450  */
__ECLIC_ClearPendingIRQ(IRQn_Type IRQn)451 __STATIC_FORCEINLINE void __ECLIC_ClearPendingIRQ(IRQn_Type IRQn)
452 {
453     ECLIC->CTRL[IRQn].INTIP &= ~ CLIC_INTIP_IP_Msk;
454 }
455 
456 /**
457  * \brief  Set trigger mode and polarity for a specific interrupt
458  * \details
459  * This function set trigger mode and polarity of the specific interrupt \em IRQn.
460  * \param [in]      IRQn  Interrupt number
461  * \param [in]      trig
462  *                   - 00  level trigger, \ref ECLIC_LEVEL_TRIGGER
463  *                   - 01  positive edge trigger, \ref ECLIC_POSTIVE_EDGE_TRIGGER
464  *                   - 02  level trigger, \ref ECLIC_LEVEL_TRIGGER
465  *                   - 03  negative edge trigger, \ref ECLIC_NEGTIVE_EDGE_TRIGGER
466  * \remarks
467  * - IRQn must not be negative.
468  *
469  * \sa
470  * - \ref ECLIC_GetTrigIRQ
471  */
__ECLIC_SetTrigIRQ(IRQn_Type IRQn,uint32_t trig)472 __STATIC_FORCEINLINE void __ECLIC_SetTrigIRQ(IRQn_Type IRQn, uint32_t trig)
473 {
474     ECLIC->CTRL[IRQn].INTATTR &= ~CLIC_INTATTR_TRIG_Msk;
475     ECLIC->CTRL[IRQn].INTATTR |= (uint8_t)(trig<<CLIC_INTATTR_TRIG_Pos);
476 }
477 
478 /**
479  * \brief  Get trigger mode and polarity for a specific interrupt
480  * \details
481  * This function get trigger mode and polarity of the specific interrupt \em IRQn.
482  * \param [in]      IRQn  Interrupt number
483  * \return
484  *                 - 00  level trigger, \ref ECLIC_LEVEL_TRIGGER
485  *                 - 01  positive edge trigger, \ref ECLIC_POSTIVE_EDGE_TRIGGER
486  *                 - 02  level trigger, \ref ECLIC_LEVEL_TRIGGER
487  *                 - 03  negative edge trigger, \ref ECLIC_NEGTIVE_EDGE_TRIGGER
488  * \remarks
489  *     - IRQn must not be negative.
490  * \sa
491  *     - \ref ECLIC_SetTrigIRQ
492  */
__ECLIC_GetTrigIRQ(IRQn_Type IRQn)493 __STATIC_FORCEINLINE uint32_t __ECLIC_GetTrigIRQ(IRQn_Type IRQn)
494 {
495     return ((int32_t)(((ECLIC->CTRL[IRQn].INTATTR) & CLIC_INTATTR_TRIG_Msk)>>CLIC_INTATTR_TRIG_Pos));
496 }
497 
498 /**
499  * \brief  Set interrupt working mode for a specific interrupt
500  * \details
501  * This function set selective hardware vector or non-vector working mode of the specific interrupt \em IRQn.
502  * \param [in]      IRQn  Interrupt number
503  * \param [in]      shv
504  *                        - 0  non-vector mode, \ref ECLIC_NON_VECTOR_INTERRUPT
505  *                        - 1  vector mode, \ref ECLIC_VECTOR_INTERRUPT
506  * \remarks
507  * - IRQn must not be negative.
508  * \sa
509  * - \ref ECLIC_GetShvIRQ
510  */
__ECLIC_SetShvIRQ(IRQn_Type IRQn,uint32_t shv)511 __STATIC_FORCEINLINE void __ECLIC_SetShvIRQ(IRQn_Type IRQn, uint32_t shv)
512 {
513     ECLIC->CTRL[IRQn].INTATTR &= ~CLIC_INTATTR_SHV_Msk;
514     ECLIC->CTRL[IRQn].INTATTR |= (uint8_t)(shv<<CLIC_INTATTR_SHV_Pos);
515 }
516 
517 /**
518  * \brief  Get interrupt working mode for a specific interrupt
519  * \details
520  * This function get selective hardware vector or non-vector working mode of the specific interrupt \em IRQn.
521  * \param [in]      IRQn  Interrupt number
522  * \return       shv
523  *                        - 0  non-vector mode, \ref ECLIC_NON_VECTOR_INTERRUPT
524  *                        - 1  vector mode, \ref ECLIC_VECTOR_INTERRUPT
525  * \remarks
526  * - IRQn must not be negative.
527  * \sa
528  * - \ref ECLIC_SetShvIRQ
529  */
__ECLIC_GetShvIRQ(IRQn_Type IRQn)530 __STATIC_FORCEINLINE uint32_t __ECLIC_GetShvIRQ(IRQn_Type IRQn)
531 {
532     return ((int32_t)(((ECLIC->CTRL[IRQn].INTATTR) & CLIC_INTATTR_SHV_Msk)>>CLIC_INTATTR_SHV_Pos));
533 }
534 
535 /**
536  * \brief  Modify ECLIC Interrupt Input Control Register for a specific interrupt
537  * \details
538  * This function modify ECLIC Interrupt Input Control(CLICINTCTL[i]) register of the specific interrupt \em IRQn.
539  * \param [in]      IRQn  Interrupt number
540  * \param [in]      intctrl  Set value for CLICINTCTL[i] register
541  * \remarks
542  * - IRQn must not be negative.
543  * \sa
544  * - \ref ECLIC_GetCtrlIRQ
545  */
__ECLIC_SetCtrlIRQ(IRQn_Type IRQn,uint8_t intctrl)546 __STATIC_FORCEINLINE void __ECLIC_SetCtrlIRQ(IRQn_Type IRQn, uint8_t intctrl)
547 {
548     ECLIC->CTRL[IRQn].INTCTRL = intctrl;
549 }
550 
551 /**
552  * \brief  Get ECLIC Interrupt Input Control Register value for a specific interrupt
553  * \details
554  * This function modify ECLIC Interrupt Input Control register of the specific interrupt \em IRQn.
555  * \param [in]      IRQn  Interrupt number
556  * \return       value of ECLIC Interrupt Input Control register
557  * \remarks
558  * - IRQn must not be negative.
559  * \sa
560  * - \ref ECLIC_SetCtrlIRQ
561  */
__ECLIC_GetCtrlIRQ(IRQn_Type IRQn)562 __STATIC_FORCEINLINE uint8_t __ECLIC_GetCtrlIRQ(IRQn_Type IRQn)
563 {
564     return (ECLIC->CTRL[IRQn].INTCTRL);
565 }
566 
567 /**
568  * \brief  Set ECLIC Interrupt level of a specific interrupt
569  * \details
570  * This function set interrupt level of the specific interrupt \em IRQn.
571  * \param [in]      IRQn  Interrupt number
572  * \param [in]      lvl_abs   Interrupt level
573  * \remarks
574  * - IRQn must not be negative.
575  * - If lvl_abs to be set is larger than the max level allowed, it will be force to be max level.
576  * - When you set level value you need use clciinfo.nlbits to get the width of level.
577  *   Then we could know the maximum of level. CLICINTCTLBITS is how many total bits are
578  *   present in the CLICINTCTL register.
579  * \sa
580  * - \ref ECLIC_GetLevelIRQ
581  */
__ECLIC_SetLevelIRQ(IRQn_Type IRQn,uint8_t lvl_abs)582 __STATIC_FORCEINLINE void __ECLIC_SetLevelIRQ(IRQn_Type IRQn, uint8_t lvl_abs)
583 {
584     uint8_t nlbits = __ECLIC_GetCfgNlbits();
585     uint8_t intctlbits = (uint8_t)__ECLIC_INTCTLBITS;
586 
587     if (nlbits == 0) {
588         return;
589     }
590 
591     if (nlbits > intctlbits) {
592         nlbits = intctlbits;
593     }
594     uint8_t maxlvl = ((1 << nlbits) - 1);
595     if (lvl_abs > maxlvl) {
596         lvl_abs = maxlvl;
597     }
598     uint8_t lvl = lvl_abs << (ECLIC_MAX_NLBITS - nlbits);
599     uint8_t cur_ctrl = __ECLIC_GetCtrlIRQ(IRQn);
600     cur_ctrl = cur_ctrl << nlbits;
601     cur_ctrl = cur_ctrl >> nlbits;
602     __ECLIC_SetCtrlIRQ(IRQn, (cur_ctrl | lvl));
603 }
604 
605 /**
606  * \brief  Get ECLIC Interrupt level of a specific interrupt
607  * \details
608  * This function get interrupt level of the specific interrupt \em IRQn.
609  * \param [in]      IRQn  Interrupt number
610  * \return         Interrupt level
611  * \remarks
612  * - IRQn must not be negative.
613  * \sa
614  * - \ref ECLIC_SetLevelIRQ
615  */
__ECLIC_GetLevelIRQ(IRQn_Type IRQn)616 __STATIC_FORCEINLINE uint8_t __ECLIC_GetLevelIRQ(IRQn_Type IRQn)
617 {
618     uint8_t nlbits = __ECLIC_GetCfgNlbits();
619     uint8_t intctlbits = (uint8_t)__ECLIC_INTCTLBITS;
620 
621     if (nlbits == 0) {
622         return 0;
623     }
624 
625     if (nlbits > intctlbits) {
626         nlbits = intctlbits;
627     }
628     uint8_t intctrl = __ECLIC_GetCtrlIRQ(IRQn);
629     uint8_t lvl_abs = intctrl >> (ECLIC_MAX_NLBITS - nlbits);
630     return lvl_abs;
631 }
632 
633 /**
634  * \brief  Get ECLIC Interrupt priority of a specific interrupt
635  * \details
636  * This function get interrupt priority of the specific interrupt \em IRQn.
637  * \param [in]      IRQn  Interrupt number
638  * \param [in]      pri   Interrupt priority
639  * \remarks
640  * - IRQn must not be negative.
641  * - If pri to be set is larger than the max priority allowed, it will be force to be max priority.
642  * - Priority width is CLICINTCTLBITS minus clciinfo.nlbits if clciinfo.nlbits
643  *   is less than CLICINTCTLBITS. Otherwise priority width is 0.
644  * \sa
645  * - \ref ECLIC_GetPriorityIRQ
646  */
__ECLIC_SetPriorityIRQ(IRQn_Type IRQn,uint8_t pri)647 __STATIC_FORCEINLINE void __ECLIC_SetPriorityIRQ(IRQn_Type IRQn, uint8_t pri)
648 {
649     uint8_t nlbits = __ECLIC_GetCfgNlbits();
650     uint8_t intctlbits = (uint8_t)__ECLIC_INTCTLBITS;
651     if (nlbits < intctlbits) {
652         uint8_t maxpri = ((1 << (intctlbits - nlbits)) - 1);
653         if (pri > maxpri) {
654             pri = maxpri;
655         }
656         pri = pri << (ECLIC_MAX_NLBITS - intctlbits);
657         uint8_t mask = ((uint8_t)(-1)) >> intctlbits;
658         pri = pri | mask;
659         uint8_t cur_ctrl = __ECLIC_GetCtrlIRQ(IRQn);
660         cur_ctrl = cur_ctrl >> (ECLIC_MAX_NLBITS - nlbits);
661         cur_ctrl = cur_ctrl << (ECLIC_MAX_NLBITS - nlbits);
662         __ECLIC_SetCtrlIRQ(IRQn, (cur_ctrl | pri));
663     }
664 }
665 
666 /**
667  * \brief  Get ECLIC Interrupt priority of a specific interrupt
668  * \details
669  * This function get interrupt priority of the specific interrupt \em IRQn.
670  * \param [in]      IRQn  Interrupt number
671  * \return   Interrupt priority
672  * \remarks
673  * - IRQn must not be negative.
674  * \sa
675  * - \ref ECLIC_SetPriorityIRQ
676  */
__ECLIC_GetPriorityIRQ(IRQn_Type IRQn)677 __STATIC_FORCEINLINE uint8_t __ECLIC_GetPriorityIRQ(IRQn_Type IRQn)
678 {
679     uint8_t nlbits = __ECLIC_GetCfgNlbits();
680     uint8_t intctlbits = (uint8_t)__ECLIC_INTCTLBITS;
681     if (nlbits < intctlbits) {
682         uint8_t cur_ctrl = __ECLIC_GetCtrlIRQ(IRQn);
683         uint8_t pri = cur_ctrl << nlbits;
684         pri = pri >> nlbits;
685         pri = pri >> (ECLIC_MAX_NLBITS - intctlbits);
686         return pri;
687     } else {
688         return 0;
689     }
690 }
691 
692 /**
693  * \brief  Set Interrupt Vector of a specific interrupt
694  * \details
695  * This function set interrupt handler address of the specific interrupt \em IRQn.
696  * \param [in]      IRQn  Interrupt number
697  * \param [in]      vector   Interrupt handler address
698  * \remarks
699  * - IRQn must not be negative.
700  * - You can set the \ref CSR_CSR_MTVT to set interrupt vector table entry address.
701  * - If your vector table is placed in readonly section, the vector for IRQn will not be modified.
702  *   For this case, you need to use the correct irq handler name defined in your vector table as
703  *   your irq handler function name.
704  * - This function will only work correctly when the vector table is placed in an read-write enabled section.
705  * \sa
706  * - \ref ECLIC_GetVector
707  */
__ECLIC_SetVector(IRQn_Type IRQn,rv_csr_t vector)708 __STATIC_FORCEINLINE void __ECLIC_SetVector(IRQn_Type IRQn, rv_csr_t vector)
709 {
710 #if __RISCV_XLEN == 32
711     volatile uint32_t vec_base;
712     vec_base = ((uint32_t)__RV_CSR_READ(CSR_MTVT));
713     (* (unsigned long *) (vec_base + ((int32_t)IRQn) * 4)) = vector;
714 #elif __RISCV_XLEN == 64
715     volatile uint64_t vec_base;
716     vec_base = ((uint64_t)__RV_CSR_READ(CSR_MTVT));
717     (* (unsigned long *) (vec_base + ((int32_t)IRQn) * 8)) = vector;
718 #else // TODO Need cover for XLEN=128 case in future
719     volatile uint64_t vec_base;
720     vec_base = ((uint64_t)__RV_CSR_READ(CSR_MTVT));
721     (* (unsigned long *) (vec_base + ((int32_t)IRQn) * 8)) = vector;
722 #endif
723 }
724 
725 /**
726  * \brief  Get Interrupt Vector of a specific interrupt
727  * \details
728  * This function get interrupt handler address of the specific interrupt \em IRQn.
729  * \param [in]      IRQn  Interrupt number
730  * \return        Interrupt handler address
731  * \remarks
732  * - IRQn must not be negative.
733  * - You can read \ref CSR_CSR_MTVT to get interrupt vector table entry address.
734  * \sa
735  *     - \ref ECLIC_SetVector
736  */
__ECLIC_GetVector(IRQn_Type IRQn)737 __STATIC_FORCEINLINE rv_csr_t __ECLIC_GetVector(IRQn_Type IRQn)
738 {
739 #if __RISCV_XLEN == 32
740     return (*(uint32_t *)(__RV_CSR_READ(CSR_MTVT)+IRQn*4));
741 #elif __RISCV_XLEN == 64
742     return (*(uint64_t *)(__RV_CSR_READ(CSR_MTVT)+IRQn*8));
743 #else // TODO Need cover for XLEN=128 case in future
744     return (*(uint64_t *)(__RV_CSR_READ(CSR_MTVT)+IRQn*8));
745 #endif
746 }
747 
748 /**
749  * \brief  Set Exception entry address
750  * \details
751  * This function set exception handler address to 'CSR_MTVEC'.
752  * \param [in]      addr  Exception handler address
753  * \remarks
754  * - This function use to set exception handler address to 'CSR_MTVEC'. Address is 4 bytes align.
755  * \sa
756  * - \ref __get_exc_entry
757  */
__set_exc_entry(rv_csr_t addr)758 __STATIC_FORCEINLINE void __set_exc_entry(rv_csr_t addr)
759 {
760     addr &= (rv_csr_t)(~0x3F);
761     addr |= ECLIC_MODE_MTVEC_Msk;
762     __RV_CSR_WRITE(CSR_MTVEC, addr);
763 }
764 
765 /**
766  * \brief  Get Exception entry address
767  * \details
768  * This function get exception handler address from 'CSR_MTVEC'.
769  * \return       Exception handler address
770  * \remarks
771  * - This function use to get exception handler address from 'CSR_MTVEC'. Address is 4 bytes align
772  * \sa
773  * - \ref __set_exc_entry
774  */
__get_exc_entry(void)775 __STATIC_FORCEINLINE rv_csr_t __get_exc_entry(void)
776 {
777     unsigned long addr = __RV_CSR_READ(CSR_MTVEC);
778     return (addr & ~ECLIC_MODE_MTVEC_Msk);
779 }
780 
781 /**
782  * \brief  Set Non-vector interrupt entry address
783  * \details
784  * This function set Non-vector interrupt address.
785  * \param [in]      addr  Non-vector interrupt entry address
786  * \remarks
787  * - This function use to set non-vector interrupt entry address to 'CSR_MTVT2' if
788  * - CSR_MTVT2 bit0 is 1. If 'CSR_MTVT2' bit0 is 0 then set address to 'CSR_MTVEC'
789  * \sa
790  * - \ref __get_nonvec_entry
791  */
__set_nonvec_entry(rv_csr_t addr)792 __STATIC_FORCEINLINE void __set_nonvec_entry(rv_csr_t addr)
793 {
794     if (__RV_CSR_READ(CSR_MTVT2) & 0x1){
795         __RV_CSR_WRITE(CSR_MTVT2, addr | 0x01);
796     } else {
797         addr &= (rv_csr_t)(~0x3F);
798         addr |= ECLIC_MODE_MTVEC_Msk;
799         __RV_CSR_WRITE(CSR_MTVEC, addr);
800     }
801 }
802 
803 /**
804  * \brief  Get Non-vector interrupt entry address
805  * \details
806  * This function get Non-vector interrupt address.
807  * \return      Non-vector interrupt handler address
808  * \remarks
809  * - This function use to get non-vector interrupt entry address from 'CSR_MTVT2' if
810  * - CSR_MTVT2 bit0 is 1. If 'CSR_MTVT2' bit0 is 0 then get address from 'CSR_MTVEC'.
811  * \sa
812  * - \ref __set_nonvec_entry
813  */
__get_nonvec_entry(void)814 __STATIC_FORCEINLINE rv_csr_t __get_nonvec_entry(void)
815 {
816     if (__RV_CSR_READ(CSR_MTVT2) & 0x1) {
817         return __RV_CSR_READ(CSR_MTVT2) & (~(rv_csr_t)(0x1));
818     } else {
819         rv_csr_t addr = __RV_CSR_READ(CSR_MTVEC);
820         return (addr & ~ECLIC_MODE_MTVEC_Msk);
821     }
822 }
823 
824 /**
825  * \brief  Get NMI interrupt entry from 'CSR_MNVEC'
826  * \details
827  * This function get NMI interrupt address from 'CSR_MNVEC'.
828  * \return      NMI interrupt handler address
829  * \remarks
830  * - This function use to get NMI interrupt handler address from 'CSR_MNVEC'. If CSR_MMISC_CTL[9] = 1 'CSR_MNVEC'
831  * - will be equal as mtvec. If CSR_MMISC_CTL[9] = 0 'CSR_MNVEC' will be equal as reset vector.
832  * - NMI entry is defined via \ref CSR_MMISC_CTL, writing to \ref CSR_MNVEC will be ignored.
833  */
__get_nmi_entry(void)834 __STATIC_FORCEINLINE rv_csr_t __get_nmi_entry(void)
835 {
836     return __RV_CSR_READ(CSR_MNVEC);
837 }
838 
839 /**
840  * \brief   Save necessary CSRs into variables for vector interrupt nesting
841  * \details
842  * This macro is used to declare variables which are used for saving
843  * CSRs(MCAUSE, MEPC, MSUB), and it will read these CSR content into
844  * these variables, it need to be used in a vector-interrupt if nesting
845  * is required.
846  * \remarks
847  * - Interrupt will be enabled after this macro is called
848  * - It need to be used together with \ref RESTORE_IRQ_CSR_CONTEXT
849  * - Don't use variable names __mcause, __mpec, __msubm in your ISR code
850  * - If you want to enable interrupt nesting feature for vector interrupt,
851  * you can do it like this:
852  * \code
853  * // __INTERRUPT attribute will generates function entry and exit sequences suitable
854  * // for use in an interrupt handler when this attribute is present
855  * __INTERRUPT void eclic_mtip_handler(void)
856  * {
857  *     // Must call this to save CSRs
858  *     SAVE_IRQ_CSR_CONTEXT();
859  *     // !!!Interrupt is enabled here!!!
860  *     // !!!Higher priority interrupt could nest it!!!
861  *
862  *     // put you own interrupt handling code here
863  *
864  *     // Must call this to restore CSRs
865  *     RESTORE_IRQ_CSR_CONTEXT();
866  * }
867  * \endcode
868  */
869 #define SAVE_IRQ_CSR_CONTEXT()                                              \
870         rv_csr_t __mcause = __RV_CSR_READ(CSR_MCAUSE);                      \
871         rv_csr_t __mepc = __RV_CSR_READ(CSR_MEPC);                          \
872         rv_csr_t __msubm = __RV_CSR_READ(CSR_MSUBM);                        \
873         __enable_irq();
874 
875 /**
876  * \brief   Restore necessary CSRs from variables for vector interrupt nesting
877  * \details
878  * This macro is used restore CSRs(MCAUSE, MEPC, MSUB) from pre-defined variables
879  * in \ref SAVE_IRQ_CSR_CONTEXT macro.
880  * \remarks
881  * - Interrupt will be disabled after this macro is called
882  * - It need to be used together with \ref SAVE_IRQ_CSR_CONTEXT
883  */
884 #define RESTORE_IRQ_CSR_CONTEXT()                                           \
885         __disable_irq();                                                    \
886         __RV_CSR_WRITE(CSR_MSUBM, __msubm);                                 \
887         __RV_CSR_WRITE(CSR_MEPC, __mepc);                                   \
888         __RV_CSR_WRITE(CSR_MCAUSE, __mcause);
889 
890 /** @} */ /* End of Doxygen Group NMSIS_Core_IntExc */
891 
892 #endif /* defined(__ECLIC_PRESENT) && (__ECLIC_PRESENT == 1) */
893 
894 #ifdef __cplusplus
895 }
896 #endif
897 #endif /** __CORE_FEATURE_ECLIC__ */
898