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