@@ -4,37 +4,86 @@ pub mod result;
44
55use result:: Result ;
66
7- /// Trait for enums of target-specific external interrupt numbers.
7+ /// Trait for enums of target-specific exception numbers.
88///
9- /// This trait should be implemented by a peripheral access crate (PAC)
10- /// on its enum of available external interrupts for a specific device.
11- /// Each variant must convert to a `u16 ` of its interrupt number.
9+ /// This trait should be implemented by a peripheral access crate (PAC) on its enum of available
10+ /// exceptions for a specific device. Alternatively, the `riscv` crate provides a default
11+ /// implementation for the RISC-V ISA. Each variant must convert to a `usize ` of its exception number.
1212///
1313/// # Safety
1414///
15- /// * This trait must only be implemented on a PAC of a RISC-V target.
16- /// * This trait must only be implemented on enums of external interrupts.
15+ /// * This trait must only be implemented on the `riscv` crate or on a PAC of a RISC-V target.
16+ /// * This trait must only be implemented on enums of exceptions.
17+ /// * Each enum variant must represent a distinct value (no duplicates are permitted),
18+ /// * Each enum variant must always return the same value (do not change at runtime).
19+ /// * All the exception numbers must be less than or equal to `MAX_EXCEPTION_NUMBER`.
20+ /// * `MAX_EXCEPTION_NUMBER` must coincide with the highest allowed exception number.
21+ pub unsafe trait ExceptionNumber : Copy {
22+ /// Highest number assigned to an exception.
23+ const MAX_EXCEPTION_NUMBER : usize ;
24+
25+ /// Converts an exception to its corresponding number.
26+ fn number ( self ) -> usize ;
27+
28+ /// Tries to convert a number to a valid exception.
29+ /// If the conversion fails, it returns an error with the number back.
30+ fn from_number ( value : usize ) -> Result < Self > ;
31+ }
32+
33+ /// Trait for enums of target-specific interrupt numbers.
34+ ///
35+ /// This trait should be implemented by a peripheral access crate (PAC) on its enum of available
36+ /// interrupts for a specific device. Alternatively, the `riscv` crate provides a default
37+ /// implementation for the RISC-V ISA. Each variant must convert to a `usize` of its interrupt number.
38+ ///
39+ /// # Safety
40+ ///
41+ /// * This trait must only be implemented on the `riscv` crate or on a PAC of a RISC-V target.
42+ /// * This trait must only be implemented on enums of interrupts.
1743/// * Each enum variant must represent a distinct value (no duplicates are permitted),
1844/// * Each enum variant must always return the same value (do not change at runtime).
1945/// * All the interrupt numbers must be less than or equal to `MAX_INTERRUPT_NUMBER`.
2046/// * `MAX_INTERRUPT_NUMBER` must coincide with the highest allowed interrupt number.
2147pub unsafe trait InterruptNumber : Copy {
2248 /// Highest number assigned to an interrupt source.
23- const MAX_INTERRUPT_NUMBER : u16 ;
49+ const MAX_INTERRUPT_NUMBER : usize ;
2450
2551 /// Converts an interrupt source to its corresponding number.
26- fn number ( self ) -> u16 ;
52+ fn number ( self ) -> usize ;
2753
2854 /// Tries to convert a number to a valid interrupt source.
2955 /// If the conversion fails, it returns an error with the number back.
30- fn from_number ( value : u16 ) -> Result < Self > ;
56+ fn from_number ( value : usize ) -> Result < Self > ;
3157}
3258
59+ /// Marker trait for enums of target-specific core interrupt numbers.
60+ ///
61+ /// Core interrupts are interrupts are retrieved from the `mcause` CSR. Usually, vectored mode is
62+ /// only available for core interrupts. The `riscv` crate provides a default implementation for
63+ /// the RISC-V ISA. However, a PAC may override the default implementation if the target has a
64+ /// different interrupt numbering scheme (e.g., ESP32C3).
65+ ///
66+ /// # Safety
67+ ///
68+ /// Each enum variant must represent a valid core interrupt number read from the `mcause` CSR.
69+ pub unsafe trait CoreInterruptNumber : InterruptNumber { }
70+
71+ /// Marker trait for enums of target-specific external interrupt numbers.
72+ ///
73+ /// External interrupts are interrupts caused by external sources (e.g., GPIO, UART, SPI).
74+ /// External interrupts are **not** retrieved from the `mcause` CSR.
75+ /// Instead, RISC-V processors have a single core interrupt for all external interrupts.
76+ /// An additional peripheral (e.g., PLIC) is used to multiplex the external interrupts.
77+ ///
78+ /// # Safety
79+ ///
80+ /// Each enum variant must represent a valid external interrupt number.
81+ pub unsafe trait ExternalInterruptNumber : InterruptNumber { }
82+
3383/// Trait for enums of priority levels.
3484///
35- /// This trait should be implemented by a peripheral access crate (PAC)
36- /// on its enum of available priority numbers for a specific device.
37- /// Each variant must convert to a `u8` of its priority level.
85+ /// This trait should be implemented by a peripheral access crate (PAC) on its enum of available
86+ /// priority numbers for a specific device. Each variant must convert to a `u8` of its priority level.
3887///
3988/// # Safety
4089///
@@ -58,9 +107,8 @@ pub unsafe trait PriorityNumber: Copy {
58107
59108/// Trait for enums of HART identifiers.
60109///
61- /// This trait should be implemented by a peripheral access crate (PAC)
62- /// on its enum of available HARTs for a specific device.
63- /// Each variant must convert to a `u16` of its HART ID number.
110+ /// This trait should be implemented by a peripheral access crate (PAC) on its enum of available
111+ /// HARTs for a specific device. Each variant must convert to a `u16` of its HART ID number.
64112///
65113/// # Safety
66114///
@@ -81,3 +129,165 @@ pub unsafe trait HartIdNumber: Copy {
81129 /// If the conversion fails, it returns an error with the number back.
82130 fn from_number ( value : u16 ) -> Result < Self > ;
83131}
132+
133+ #[ cfg( test) ]
134+ mod test {
135+ use super :: * ;
136+ use crate :: result:: Error ;
137+
138+ #[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
139+ enum Exception {
140+ E1 = 1 ,
141+ E3 = 3 ,
142+ }
143+
144+ #[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
145+ enum Interrupt {
146+ I1 = 1 ,
147+ I2 = 2 ,
148+ I4 = 4 ,
149+ }
150+
151+ #[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
152+ enum Priority {
153+ P0 = 0 ,
154+ P1 = 1 ,
155+ P2 = 2 ,
156+ P3 = 3 ,
157+ }
158+
159+ #[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
160+ enum HartId {
161+ H0 = 0 ,
162+ H1 = 1 ,
163+ H2 = 2 ,
164+ }
165+
166+ unsafe impl ExceptionNumber for Exception {
167+ const MAX_EXCEPTION_NUMBER : usize = Self :: E3 as usize ;
168+
169+ #[ inline]
170+ fn number ( self ) -> usize {
171+ self as _
172+ }
173+
174+ #[ inline]
175+ fn from_number ( number : usize ) -> Result < Self > {
176+ match number {
177+ 1 => Ok ( Exception :: E1 ) ,
178+ 3 => Ok ( Exception :: E3 ) ,
179+ _ => Err ( Error :: InvalidVariant ( number) ) ,
180+ }
181+ }
182+ }
183+
184+ unsafe impl InterruptNumber for Interrupt {
185+ const MAX_INTERRUPT_NUMBER : usize = Self :: I4 as usize ;
186+
187+ #[ inline]
188+ fn number ( self ) -> usize {
189+ self as _
190+ }
191+
192+ #[ inline]
193+ fn from_number ( number : usize ) -> Result < Self > {
194+ match number {
195+ 1 => Ok ( Interrupt :: I1 ) ,
196+ 2 => Ok ( Interrupt :: I2 ) ,
197+ 4 => Ok ( Interrupt :: I4 ) ,
198+ _ => Err ( Error :: InvalidVariant ( number) ) ,
199+ }
200+ }
201+ }
202+
203+ unsafe impl PriorityNumber for Priority {
204+ const MAX_PRIORITY_NUMBER : u8 = Self :: P3 as u8 ;
205+
206+ #[ inline]
207+ fn number ( self ) -> u8 {
208+ self as _
209+ }
210+
211+ #[ inline]
212+ fn from_number ( number : u8 ) -> Result < Self > {
213+ match number {
214+ 0 => Ok ( Priority :: P0 ) ,
215+ 1 => Ok ( Priority :: P1 ) ,
216+ 2 => Ok ( Priority :: P2 ) ,
217+ 3 => Ok ( Priority :: P3 ) ,
218+ _ => Err ( Error :: InvalidVariant ( number as _ ) ) ,
219+ }
220+ }
221+ }
222+
223+ unsafe impl HartIdNumber for HartId {
224+ const MAX_HART_ID_NUMBER : u16 = Self :: H2 as u16 ;
225+
226+ #[ inline]
227+ fn number ( self ) -> u16 {
228+ self as _
229+ }
230+
231+ #[ inline]
232+ fn from_number ( number : u16 ) -> Result < Self > {
233+ match number {
234+ 0 => Ok ( HartId :: H0 ) ,
235+ 1 => Ok ( HartId :: H1 ) ,
236+ 2 => Ok ( HartId :: H2 ) ,
237+ _ => Err ( Error :: InvalidVariant ( number as _ ) ) ,
238+ }
239+ }
240+ }
241+
242+ #[ test]
243+ fn check_exception_enum ( ) {
244+ assert_eq ! ( Exception :: E1 . number( ) , 1 ) ;
245+ assert_eq ! ( Exception :: E3 . number( ) , 3 ) ;
246+
247+ assert_eq ! ( Exception :: from_number( 0 ) , Err ( Error :: InvalidVariant ( 0 ) ) ) ;
248+ assert_eq ! ( Exception :: from_number( 1 ) , Ok ( Exception :: E1 ) ) ;
249+ assert_eq ! ( Exception :: from_number( 2 ) , Err ( Error :: InvalidVariant ( 2 ) ) ) ;
250+ assert_eq ! ( Exception :: from_number( 3 ) , Ok ( Exception :: E3 ) ) ;
251+ assert_eq ! ( Exception :: from_number( 4 ) , Err ( Error :: InvalidVariant ( 4 ) ) ) ;
252+ }
253+
254+ #[ test]
255+ fn check_interrupt_enum ( ) {
256+ assert_eq ! ( Interrupt :: I1 . number( ) , 1 ) ;
257+ assert_eq ! ( Interrupt :: I2 . number( ) , 2 ) ;
258+ assert_eq ! ( Interrupt :: I4 . number( ) , 4 ) ;
259+
260+ assert_eq ! ( Interrupt :: from_number( 0 ) , Err ( Error :: InvalidVariant ( 0 ) ) ) ;
261+ assert_eq ! ( Interrupt :: from_number( 1 ) , Ok ( Interrupt :: I1 ) ) ;
262+ assert_eq ! ( Interrupt :: from_number( 2 ) , Ok ( Interrupt :: I2 ) ) ;
263+ assert_eq ! ( Interrupt :: from_number( 3 ) , Err ( Error :: InvalidVariant ( 3 ) ) ) ;
264+ assert_eq ! ( Interrupt :: from_number( 4 ) , Ok ( Interrupt :: I4 ) ) ;
265+ assert_eq ! ( Interrupt :: from_number( 5 ) , Err ( Error :: InvalidVariant ( 5 ) ) ) ;
266+ }
267+
268+ #[ test]
269+ fn check_priority_enum ( ) {
270+ assert_eq ! ( Priority :: P0 . number( ) , 0 ) ;
271+ assert_eq ! ( Priority :: P1 . number( ) , 1 ) ;
272+ assert_eq ! ( Priority :: P2 . number( ) , 2 ) ;
273+ assert_eq ! ( Priority :: P3 . number( ) , 3 ) ;
274+
275+ assert_eq ! ( Priority :: from_number( 0 ) , Ok ( Priority :: P0 ) ) ;
276+ assert_eq ! ( Priority :: from_number( 1 ) , Ok ( Priority :: P1 ) ) ;
277+ assert_eq ! ( Priority :: from_number( 2 ) , Ok ( Priority :: P2 ) ) ;
278+ assert_eq ! ( Priority :: from_number( 3 ) , Ok ( Priority :: P3 ) ) ;
279+ assert_eq ! ( Priority :: from_number( 4 ) , Err ( Error :: InvalidVariant ( 4 ) ) ) ;
280+ }
281+
282+ #[ test]
283+ fn check_hart_id_enum ( ) {
284+ assert_eq ! ( HartId :: H0 . number( ) , 0 ) ;
285+ assert_eq ! ( HartId :: H1 . number( ) , 1 ) ;
286+ assert_eq ! ( HartId :: H2 . number( ) , 2 ) ;
287+
288+ assert_eq ! ( HartId :: from_number( 0 ) , Ok ( HartId :: H0 ) ) ;
289+ assert_eq ! ( HartId :: from_number( 1 ) , Ok ( HartId :: H1 ) ) ;
290+ assert_eq ! ( HartId :: from_number( 2 ) , Ok ( HartId :: H2 ) ) ;
291+ assert_eq ! ( HartId :: from_number( 3 ) , Err ( Error :: InvalidVariant ( 3 ) ) ) ;
292+ }
293+ }
0 commit comments