@@ -4,37 +4,86 @@ pub mod result;
4
4
5
5
use result:: Result ;
6
6
7
- /// Trait for enums of target-specific external interrupt numbers.
7
+ /// Trait for enums of target-specific exception numbers.
8
8
///
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.
12
12
///
13
13
/// # Safety
14
14
///
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.
17
43
/// * Each enum variant must represent a distinct value (no duplicates are permitted),
18
44
/// * Each enum variant must always return the same value (do not change at runtime).
19
45
/// * All the interrupt numbers must be less than or equal to `MAX_INTERRUPT_NUMBER`.
20
46
/// * `MAX_INTERRUPT_NUMBER` must coincide with the highest allowed interrupt number.
21
47
pub unsafe trait InterruptNumber : Copy {
22
48
/// Highest number assigned to an interrupt source.
23
- const MAX_INTERRUPT_NUMBER : u16 ;
49
+ const MAX_INTERRUPT_NUMBER : usize ;
24
50
25
51
/// Converts an interrupt source to its corresponding number.
26
- fn number ( self ) -> u16 ;
52
+ fn number ( self ) -> usize ;
27
53
28
54
/// Tries to convert a number to a valid interrupt source.
29
55
/// 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 > ;
31
57
}
32
58
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
+
33
83
/// Trait for enums of priority levels.
34
84
///
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.
38
87
///
39
88
/// # Safety
40
89
///
@@ -58,9 +107,8 @@ pub unsafe trait PriorityNumber: Copy {
58
107
59
108
/// Trait for enums of HART identifiers.
60
109
///
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.
64
112
///
65
113
/// # Safety
66
114
///
@@ -81,3 +129,165 @@ pub unsafe trait HartIdNumber: Copy {
81
129
/// If the conversion fails, it returns an error with the number back.
82
130
fn from_number ( value : u16 ) -> Result < Self > ;
83
131
}
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