@@ -55,3 +55,161 @@ macro_rules! singleton {
5555 } )
5656 } ;
5757}
58+
59+ /// Macro to create interfaces to PLIC contexts in PACs.
60+ ///
61+ /// This macro expects 5 arguments:
62+ ///
63+ /// - `PLIC`: name of the PLIC context interface structure to be created.
64+ /// We recommend to leave `PLIC` for context 0 and `PLICx` for the remaining contexts.
65+ ///
66+ /// - `BASE`: base address of the PLIC peripheral of the target.
67+ ///
68+ /// - `CONTEXT`: context number assigned to the PLIC interface.
69+ ///
70+ /// - `INTERRUPT`: enum type of the external interruptions of the target.
71+ /// This type must implement the [`crate::peripheral::plic::InterruptNumber`] trait.
72+ ///
73+ /// - `PRIORITY`: enum type of the priority levels supported by the target.
74+ /// This type must implement the [`crate::peripheral::plic::PriorityNumber`] trait.
75+ ///
76+ /// # Note
77+ ///
78+ /// This macro requires the `plic` feature to be active.
79+ #[ cfg( feature = "plic" ) ]
80+ #[ macro_export]
81+ macro_rules! plic_context {
82+ ( $PLIC: ident, $BASE: literal, $CONTEXT: literal, $INTERRUPT: ident, $PRIORITY: ident) => {
83+ /// Platform-Level Interrupt Controller (PLIC) context.
84+ #[ repr( transparent) ]
85+ pub struct $PLIC {
86+ context: $crate:: peripheral:: PLIC <$BASE, $CONTEXT>,
87+ }
88+
89+ impl $PLIC {
90+ /// Creates a new PLIC context interface.
91+ pub const fn new( ) -> Self {
92+ Self {
93+ context: $crate:: peripheral:: PLIC :: new( ) ,
94+ }
95+ }
96+
97+ /// Enables machine external interrupts.
98+ #[ inline( always) ]
99+ pub fn enable( ) {
100+ $crate:: peripheral:: PLIC :: <$BASE, $CONTEXT>:: enable( ) ;
101+ }
102+
103+ /// Disables machine external interrupts.
104+ #[ inline( always) ]
105+ pub fn disable( ) {
106+ $crate:: peripheral:: PLIC :: <$BASE, $CONTEXT>:: disable( ) ;
107+ }
108+
109+ /// Returns the priority level associated to a given interrupt source.
110+ #[ inline( always) ]
111+ pub fn priority( source: $INTERRUPT) -> $PRIORITY {
112+ $crate:: peripheral:: PLIC :: <$BASE, $CONTEXT>:: priority( source)
113+ }
114+
115+ /// Getter method for the priority level associated to a given interrupt source.
116+ #[ inline( always) ]
117+ pub fn get_priority( & self , source: $INTERRUPT) -> $PRIORITY {
118+ Self :: priority( source)
119+ }
120+
121+ /// Sets the priority level of a given interrupt source.
122+ ///
123+ /// # Note
124+ ///
125+ /// Interrupt source priorities are shared among all the contexts of the PLIC.
126+ /// Thus, changing the priority of sources may affect other PLIC contexts.
127+ ///
128+ /// # Safety
129+ ///
130+ /// Changing priority levels can break priority-based critical sections and compromise memory safety.
131+ #[ inline( always) ]
132+ pub unsafe fn set_priority( & mut self , source: $INTERRUPT, priority: $PRIORITY) {
133+ self . context. set_priority( source, priority) ;
134+ }
135+
136+ /// Checks if an interrupt triggered by a given source is pending.
137+ #[ inline( always) ]
138+ pub fn is_interrupt_pending( source: $INTERRUPT) -> bool {
139+ $crate:: peripheral:: PLIC :: <$BASE, $CONTEXT>:: is_interrupt_pending( source)
140+ }
141+
142+ /// Checks if an interrupt source is enabled for the PLIC context.
143+ #[ inline( always) ]
144+ pub fn is_interrupt_enabled( source: $INTERRUPT) -> bool {
145+ $crate:: peripheral:: PLIC :: <$BASE, $CONTEXT>:: is_interrupt_enabled( source)
146+ }
147+
148+ /// Enables an interrupt source for the PLIC context.
149+ ///
150+ /// # Safety
151+ ///
152+ /// It performs non-atomic read-modify-write operations, which may lead to undefined behavior.
153+ /// Additionally, Enabling an interrupt source can break mask-based critical sections.
154+ #[ inline( always) ]
155+ pub unsafe fn enable_interrupt( & mut self , source: $INTERRUPT) {
156+ self . context. enable_interrupt( source) ;
157+ }
158+
159+ /// Disables an interrupt source for the PLIC context.
160+ ///
161+ /// # Safety
162+ ///
163+ /// It performs non-atomic read-modify-write operations, which may lead to undefined behavior.
164+ #[ inline( always) ]
165+ pub unsafe fn disable_interrupt( & mut self , source: $INTERRUPT) {
166+ self . context. disable_interrupt( source) ;
167+ }
168+
169+ /// Returns the priority threshold of the PLIC context.
170+ #[ inline( always) ]
171+ pub fn threshold( ) -> $PRIORITY {
172+ $crate:: peripheral:: PLIC :: <$BASE, $CONTEXT>:: threshold( )
173+ }
174+
175+ /// Getter method for the priority threshold of the PLIC context.
176+ #[ inline( always) ]
177+ pub fn get_threshold( & self ) -> $PRIORITY {
178+ Self :: threshold( )
179+ }
180+
181+ /// Sets the priority threshold for for the PLIC context.
182+ ///
183+ /// # Safety
184+ ///
185+ /// Unmasking an interrupt source can break mask-based critical sections.
186+ #[ inline( always) ]
187+ pub unsafe fn set_threshold( & mut self , priority: $PRIORITY) {
188+ self . context. set_threshold( priority) ;
189+ }
190+
191+ /// Claims the number of a pending interrupt for for the PLIC context.
192+ /// If no interrupt is pending for this context, it returns [`None`].
193+ #[ inline( always) ]
194+ pub fn claim( ) -> Option <$INTERRUPT> {
195+ $crate:: peripheral:: PLIC :: <$BASE, $CONTEXT>:: claim( )
196+ }
197+
198+ /// Marks a pending interrupt as complete from for the PLIC context.
199+ #[ inline( always) ]
200+ pub fn complete( source: $INTERRUPT) {
201+ $crate:: peripheral:: PLIC :: <$BASE, $CONTEXT>:: complete( source) ;
202+ }
203+
204+ /// Resets the PLIC peripherals.
205+ ///
206+ /// # Safety
207+ ///
208+ /// It performs non-atomic read-modify-write operations, which may lead to undefined behavior.
209+ #[ inline( always) ]
210+ pub unsafe fn reset( & mut self ) {
211+ self . context. reset:: <$INTERRUPT, $PRIORITY>( ) ;
212+ }
213+ }
214+ } ;
215+ }
0 commit comments