NMSIS-Core  Version 1.6.0
NMSIS-Core support for Nuclei processor-based devices
core_feature_plic.h
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 
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 
37 #include "core_feature_base.h"
38 
39 #if defined(__PLIC_PRESENT) && (__PLIC_PRESENT == 1)
40 
48 /*
49  * PLIC Memory Map (per RISC-V PLIC spec):
50  *
51  * Interrupt Source Priority (per-source, not per-context):
52  * base + 0x000000: Source 0 (reserved, not exist)
53  * base + 0x000004: Source 1 priority
54  * ...
55  * base + 0x000FFC: Source 1023 priority
56  * addr = base + source * 4
57  *
58  * Interrupt Pending Bits (per-source, not per-context):
59  * base + 0x001000: Source 0-31 pending
60  * base + 0x001004: Source 32-63 pending
61  * ...
62  * addr = base + 0x1000 + (source / 32) * 4
63  *
64  * Interrupt Enable Bits (per-context, 0x80 bytes each):
65  * base + 0x002000: Context 0, Source 0-31 enable
66  * base + 0x002080: Context 1, Source 0-31 enable
67  * ...
68  * addr = base + 0x2000 + ctxid * 0x80 + (source / 32) * 4
69  *
70  * Priority Threshold (per-context, 0x1000 bytes each):
71  * base + 0x200000: Context 0 threshold
72  * base + 0x201000: Context 1 threshold
73  * ...
74  * addr = base + 0x200000 + ctxid * 0x1000
75  *
76  * Claim / Complete (per-context, same 4K block as threshold):
77  * base + 0x200004: Context 0 claim/complete
78  * base + 0x201004: Context 1 claim/complete
79  * ...
80  * addr = base + 0x200004 + ctxid * 0x1000
81  * Claim: read returns highest-priority pending interrupt ID
82  * Complete: write interrupt ID to signal handler completion
83  *
84  * Context ID to Hart/Mode mapping (Nuclei RISC-V CPU, not in PLIC spec):
85  * M-mode context ID = hartid * 2 (even: 0, 2, 4, 6, 8)
86  * S-mode context ID = hartid * 2 + 1 (odd: 1, 3, 5, 7, 9)
87  *
88  * Hart 0: M=ctxid 0, S=ctxid 1
89  * Hart 1: M=ctxid 2, S=ctxid 3
90  * Hart 2: M=ctxid 4, S=ctxid 5
91  * Hart 3: M=ctxid 6, S=ctxid 7
92  * Hart 4: M=ctxid 8, S=ctxid 9
93  *
94  * Reference: https://github.com/riscv/riscv-plic-spec
95  */
96 
97 /* Priority: 32 bits per source, addr = base + source * 4 */
98 #define PLIC_PRIORITY_OFFSET _AC(0x0000,UL)
99 #define PLIC_PRIORITY_SHIFT_PER_SOURCE 2
101 /* Pending: 1 bit per source, packed 32 per 32-bit register */
102 #define PLIC_PENDING_OFFSET _AC(0x1000,UL)
103 #define PLIC_PENDING_SHIFT_PER_SOURCE 0
105 /* Enable: 0x80 (128) bytes per context, packed 32 sources per 32-bit word */
106 #define PLIC_ENABLE_OFFSET _AC(0x2000,UL)
107 #define PLIC_ENABLE_SHIFT_PER_CONTEXT 7
109 /* Threshold: 0x1000 (4096) bytes per context */
110 #define PLIC_THRESHOLD_OFFSET _AC(0x200000,UL)
111 #define PLIC_CLAIM_OFFSET _AC(0x200004,UL)
112 #define PLIC_THRESHOLD_SHIFT_PER_CONTEXT 12
113 #define PLIC_CLAIM_SHIFT_PER_CONTEXT 12
115 #ifndef __PLIC_BASEADDR
116 /* Base address of PLIC(__PLIC_BASEADDR) should be defined in <Device.h> */
117 #error "__PLIC_BASEADDR is not defined, please check!"
118 #endif
119 
120 /* PLIC Memory mapping of Device */
121 #define PLIC_BASE __PLIC_BASEADDR
130 #ifndef __PLIC_HARTID
131 #define PLIC_GetHartID() (__get_hart_index())
132 #define PLIC_GetHartID_S() (__get_hart_index_s())
133 #else
134 #define PLIC_GetHartID() (__PLIC_HARTID)
135 #define PLIC_GetHartID_S() (__PLIC_HARTID)
136 #endif
137 
138 /*
139  * Context ID mapping (Nuclei RISC-V CPU convention):
140  * M-mode: ctxid = hartid * 2 (even: 0, 2, 4, 6, 8)
141  * S-mode: ctxid = hartid * 2 + 1 (odd: 1, 3, 5, 7, 9)
142  * This is NOT part of the RISC-V PLIC spec.
143  */
144 #define PLIC_GetHartMContextID() (PLIC_GetHartID() << 1)
145 // TODO SMODE HARTID need to handle, maybe use CSR shartid defined by Nuclei RISC-V CPU
146 #define PLIC_GetHartSContextID() ((PLIC_GetHartID_S() << 1) + 1)
147 
148 #define PLIC_PRIORITY_REGADDR(source) ((PLIC_BASE) + (PLIC_PRIORITY_OFFSET) + ((source) << PLIC_PRIORITY_SHIFT_PER_SOURCE))
149 #define PLIC_PENDING_REGADDR(source) ((PLIC_BASE) + (PLIC_PENDING_OFFSET) + (((source) >> 5) * 4))
150 #define PLIC_ENABLE_REGADDR(ctxid, source) ((PLIC_BASE) + (PLIC_ENABLE_OFFSET) + ((ctxid) << PLIC_ENABLE_SHIFT_PER_CONTEXT) + ((source) >> 5) * 4)
151 #define PLIC_THRESHOLD_REGADDR(ctxid) ((PLIC_BASE) + (PLIC_THRESHOLD_OFFSET) + ((ctxid) << PLIC_THRESHOLD_SHIFT_PER_CONTEXT))
152 #define PLIC_CLAIM_REGADDR(ctxid) ((PLIC_BASE) + (PLIC_CLAIM_OFFSET) + ((ctxid) << PLIC_CLAIM_SHIFT_PER_CONTEXT))
153 #define PLIC_COMPLETE_REGADDR(ctxid) (PLIC_CLAIM_REGADDR(ctxid))
154 
155  /* end of group NMSIS_Core_PLIC_Registers */
157 
158 /* ########################## PLIC functions #################################### */
176 __STATIC_FORCEINLINE void PLIC_SetContextThreshold(uint32_t ctxid, uint32_t thresh)
177 {
178  volatile uint32_t *thresh_reg = (uint32_t *)PLIC_THRESHOLD_REGADDR(ctxid);
179 
180  *thresh_reg = thresh;
181 }
182 
194 {
195  volatile uint32_t *thresh_reg = (uint32_t *)PLIC_THRESHOLD_REGADDR(ctxid);
196 
197  return (*thresh_reg);
198 }
199 
210 __STATIC_FORCEINLINE void PLIC_EnableContextInterrupt(uint32_t ctxid, uint32_t source)
211 {
212  volatile uint32_t *enable_reg = (uint32_t *)PLIC_ENABLE_REGADDR(ctxid, source);
213 
214  uint32_t current = *enable_reg;
215  current = current | (1UL << (source & 0x1F));
216  *enable_reg = current;
217 }
218 
229 __STATIC_FORCEINLINE void PLIC_DisableContextInterrupt(uint32_t ctxid, uint32_t source)
230 {
231  volatile uint32_t *enable_reg = (uint32_t *)PLIC_ENABLE_REGADDR(ctxid, source);
232 
233  uint32_t current = *enable_reg;
234  current = current & (~(1UL << (source & 0x1F)));
235  *enable_reg = current;
236 }
237 
250 __STATIC_FORCEINLINE uint32_t PLIC_GetContextInterruptEnable(uint32_t ctxid, uint32_t source)
251 {
252  volatile uint32_t *enable_reg = (uint32_t *)PLIC_ENABLE_REGADDR(ctxid, source);
253 
254  uint32_t current = *enable_reg;
255  current = (current >> (source & 0x1F)) & 0x1;
256  return current;
257 }
258 
270 {
271  volatile uint32_t *pending_reg = (uint32_t *)PLIC_PENDING_REGADDR(source);
272 
273  uint32_t current = *pending_reg;
274  current = current | (1UL << (source & 0x1F));
275  *pending_reg = current;
276 }
277 
289 {
290  volatile uint32_t *pending_reg = (uint32_t *)PLIC_PENDING_REGADDR(source);
291 
292  uint32_t current = *pending_reg;
293  current = current & (~(1UL << (source & 0x1F)));
294  *pending_reg = current;
295 }
296 
309 {
310  volatile uint32_t *pending_reg = (uint32_t *)PLIC_PENDING_REGADDR(source);
311 
312  uint32_t current = *pending_reg;
313  current = (current >> (source & 0x1F)) & 0x1;
314  return current;
315 }
316 
327 __STATIC_FORCEINLINE void PLIC_SetPriority(uint32_t source, uint32_t priority)
328 {
329  volatile uint32_t *priority_reg = (uint32_t *)PLIC_PRIORITY_REGADDR(source);
330 
331  *priority_reg = priority;
332 }
333 
344 __STATIC_FORCEINLINE uint32_t PLIC_GetPriority(uint32_t source)
345 {
346  volatile uint32_t *priority_reg = (uint32_t *)PLIC_PRIORITY_REGADDR(source);
347 
348  return (*priority_reg);
349 }
350 
366 {
367  volatile uint32_t *claim_reg = (uint32_t *)PLIC_CLAIM_REGADDR(ctxid);
368 
369  return (*claim_reg);
370 }
371 
388 __STATIC_FORCEINLINE void PLIC_CompleteContextInterrupt(uint32_t ctxid, uint32_t source)
389 {
390  volatile uint32_t *complete_reg = (uint32_t *)PLIC_COMPLETE_REGADDR(ctxid);
391 
392  *complete_reg = source;
393 }
394 
407 __STATIC_INLINE void PLIC_Context_Init(uint32_t ctxid, uint32_t num_sources, uint32_t enable, uint32_t thresh)
408 {
409  uint32_t i;
410 
411  for (i = 0; i < num_sources; i ++) {
412  if (enable) {
413  PLIC_EnableContextInterrupt(ctxid, i);
414  } else {
416  }
417  }
418  PLIC_SetContextThreshold(ctxid, thresh);
419 }
420 
421 #define PLIC_Init(num_sources, enable, thresh) PLIC_Context_Init(PLIC_GetHartMContextID(), (num_sources), (enable), (thresh))
422 #define PLIC_Init_S(num_sources, enable, thresh) PLIC_Context_Init(PLIC_GetHartSContextID(), (num_sources), (enable), (thresh))
423 
424 #define PLIC_ClaimInterrupt() PLIC_ClaimContextInterrupt(PLIC_GetHartMContextID())
425 #define PLIC_ClaimInterrupt_S() PLIC_ClaimContextInterrupt(PLIC_GetHartSContextID())
426 
427 #define PLIC_CompleteInterrupt(source) PLIC_CompleteContextInterrupt(PLIC_GetHartMContextID(), (source))
428 #define PLIC_CompleteInterrupt_S(source) PLIC_CompleteContextInterrupt(PLIC_GetHartSContextID(), (source))
429 
430 #define PLIC_GetInterruptEnable(source) PLIC_GetContextInterruptEnable(PLIC_GetHartMContextID(), (source))
431 #define PLIC_GetInterruptEnable_S(source) PLIC_GetContextInterruptEnable(PLIC_GetHartSContextID(), (source))
432 
433 #define PLIC_EnableInterrupt(source) PLIC_EnableContextInterrupt(PLIC_GetHartMContextID(), (source))
434 #define PLIC_EnableInterrupt_S(source) PLIC_EnableContextInterrupt(PLIC_GetHartSContextID(), (source))
435 
436 #define PLIC_DisableInterrupt(source) PLIC_DisableContextInterrupt(PLIC_GetHartMContextID(), (source))
437 #define PLIC_DisableInterrupt_S(source) PLIC_DisableContextInterrupt(PLIC_GetHartSContextID(), (source))
438 
439 #define PLIC_SetThreshold(thresh) PLIC_SetContextThreshold(PLIC_GetHartMContextID(), (thresh))
440 #define PLIC_SetThreshold_S(thresh) PLIC_SetContextThreshold(PLIC_GetHartSContextID(), (thresh))
441 
442 #define PLIC_GetThreshold() PLIC_GetContextThreshold(PLIC_GetHartMContextID())
443 #define PLIC_GetThreshold_S() PLIC_GetContextThreshold(PLIC_GetHartSContextID())
444 
456 {
457  addr &= (rv_csr_t)(~0x7);
458  __RV_CSR_WRITE(CSR_MTVEC, addr);
459 }
460 
472 {
473  unsigned long addr = __RV_CSR_READ(CSR_MTVEC);
474  return (addr);
475 }
476  /* End of Doxygen Group NMSIS_Core_IntExc */
478 
479 #endif /* defined(__PLIC_PRESENT) && (__PLIC_PRESENT == 1) */
480 
481 #ifdef __cplusplus
482 }
483 #endif
484 #endif
PLIC_GetPriority
__STATIC_FORCEINLINE uint32_t PLIC_GetPriority(uint32_t source)
Get interrupt priority for selected source plic.
Definition: core_feature_plic.h:344
PLIC_THRESHOLD_REGADDR
#define PLIC_THRESHOLD_REGADDR(ctxid)
Definition: core_feature_plic.h:151
PLIC_DisableContextInterrupt
__STATIC_FORCEINLINE void PLIC_DisableContextInterrupt(uint32_t ctxid, uint32_t source)
Disable interrupt of selected source plic for selected context.
Definition: core_feature_plic.h:229
CSR_MTVEC
#define CSR_MTVEC
Definition: riscv_encoding.h:672
PLIC_PENDING_REGADDR
#define PLIC_PENDING_REGADDR(source)
Definition: core_feature_plic.h:149
PLIC_GetInterruptPending
__STATIC_FORCEINLINE uint32_t PLIC_GetInterruptPending(uint32_t source)
Get interrupt pending status of selected source plic.
Definition: core_feature_plic.h:308
PLIC_SetContextThreshold
__STATIC_FORCEINLINE void PLIC_SetContextThreshold(uint32_t ctxid, uint32_t thresh)
Set priority threshold value of plic for selected context.
Definition: core_feature_plic.h:176
PLIC_CompleteContextInterrupt
__STATIC_FORCEINLINE void PLIC_CompleteContextInterrupt(uint32_t ctxid, uint32_t source)
Complete interrupt for plic for selected context.
Definition: core_feature_plic.h:388
__RV_CSR_WRITE
#define __RV_CSR_WRITE(csr, val)
CSR operation Macro for csrw instruction.
Definition: core_feature_base.h:725
PLIC_SetPriority
__STATIC_FORCEINLINE void PLIC_SetPriority(uint32_t source, uint32_t priority)
Set interrupt priority for selected source plic.
Definition: core_feature_plic.h:327
__STATIC_INLINE
#define __STATIC_INLINE
Define a static function that may be inlined by the compiler.
Definition: nmsis_gcc.h:65
PLIC_ClearInterruptPending
__STATIC_FORCEINLINE void PLIC_ClearInterruptPending(uint32_t source)
Clear interrupt pending of selected source plic.
Definition: core_feature_plic.h:288
PLIC_GetContextInterruptEnable
__STATIC_FORCEINLINE uint32_t PLIC_GetContextInterruptEnable(uint32_t ctxid, uint32_t source)
Get interrupt enable status of selected source plic for selected context.
Definition: core_feature_plic.h:250
PLIC_ENABLE_REGADDR
#define PLIC_ENABLE_REGADDR(ctxid, source)
Definition: core_feature_plic.h:150
PLIC_Context_Init
__STATIC_INLINE void PLIC_Context_Init(uint32_t ctxid, uint32_t num_sources, uint32_t enable, uint32_t thresh)
Perform init for plic for selected context.
Definition: core_feature_plic.h:407
PLIC_PRIORITY_REGADDR
#define PLIC_PRIORITY_REGADDR(source)
Definition: core_feature_plic.h:148
__STATIC_FORCEINLINE
#define __STATIC_FORCEINLINE
Define a static function that should be always inlined by the compiler.
Definition: nmsis_gcc.h:70
__RV_CSR_READ
#define __RV_CSR_READ(csr)
CSR operation Macro for csrr instruction.
Definition: core_feature_base.h:707
__set_trap_entry
__STATIC_FORCEINLINE void __set_trap_entry(rv_csr_t addr)
Set Trap entry address.
Definition: core_feature_plic.h:455
PLIC_EnableContextInterrupt
__STATIC_FORCEINLINE void PLIC_EnableContextInterrupt(uint32_t ctxid, uint32_t source)
Enable interrupt of selected source plic for selected context.
Definition: core_feature_plic.h:210
__get_trap_entry
__STATIC_FORCEINLINE rv_csr_t __get_trap_entry(void)
Get trap entry address.
Definition: core_feature_plic.h:471
PLIC_ClaimContextInterrupt
__STATIC_FORCEINLINE uint32_t PLIC_ClaimContextInterrupt(uint32_t ctxid)
Claim interrupt for plic for selected context.
Definition: core_feature_plic.h:365
PLIC_COMPLETE_REGADDR
#define PLIC_COMPLETE_REGADDR(ctxid)
Definition: core_feature_plic.h:153
PLIC_CLAIM_REGADDR
#define PLIC_CLAIM_REGADDR(ctxid)
Definition: core_feature_plic.h:152
rv_csr_t
unsigned long rv_csr_t
Type of Control and Status Register(CSR), depends on the XLEN defined in RISC-V.
Definition: core_feature_base.h:55
PLIC_SetInterruptPending
__STATIC_FORCEINLINE void PLIC_SetInterruptPending(uint32_t source)
Set interrupt pending of selected source plic.
Definition: core_feature_plic.h:269
PLIC_GetContextThreshold
__STATIC_FORCEINLINE uint32_t PLIC_GetContextThreshold(uint32_t ctxid)
Get priority threshold value of plic for selected context.
Definition: core_feature_plic.h:193