riscv_pac/
lib.rs

1//! # Deprecation notice
2//!
3//! This crate has been deprecated. Use [`riscv-types`](https://crates.io/crates/riscv-types) instead.
4
5#![no_std]
6
7pub mod result;
8
9use result::Result;
10
11/// Trait for enums of target-specific exception numbers.
12///
13/// This trait should be implemented by a peripheral access crate (PAC) on its enum of available
14/// exceptions for a specific device. Alternatively, the `riscv` crate provides a default
15/// implementation for the RISC-V ISA. Each variant must convert to a `usize` of its exception number.
16///
17/// # Safety
18///
19/// * This trait must only be implemented on the `riscv` crate or on a PAC of a RISC-V target.
20/// * This trait must only be implemented on enums of exceptions.
21/// * Each enum variant must represent a distinct value (no duplicates are permitted),
22/// * Each enum variant must always return the same value (do not change at runtime).
23/// * All the exception numbers must be less than or equal to `MAX_EXCEPTION_NUMBER`.
24/// * `MAX_EXCEPTION_NUMBER` must coincide with the highest allowed exception number.
25pub unsafe trait ExceptionNumber: Copy {
26    /// Highest number assigned to an exception.
27    const MAX_EXCEPTION_NUMBER: usize;
28
29    /// Converts an exception to its corresponding number.
30    fn number(self) -> usize;
31
32    /// Tries to convert a number to a valid exception.
33    fn from_number(value: usize) -> Result<Self>;
34}
35
36/// Trait for enums of target-specific interrupt numbers.
37///
38/// This trait should be implemented by a peripheral access crate (PAC) on its enum of available
39/// interrupts for a specific device. Alternatively, the `riscv` crate provides a default
40/// implementation for the RISC-V ISA. Each variant must convert to a `usize` of its interrupt number.
41///
42/// # Safety
43///
44/// * This trait must only be implemented on the `riscv` crate or on a PAC of a RISC-V target.
45/// * This trait must only be implemented on enums of interrupts.
46/// * Each enum variant must represent a distinct value (no duplicates are permitted),
47/// * Each enum variant must always return the same value (do not change at runtime).
48/// * All the interrupt numbers must be less than or equal to `MAX_INTERRUPT_NUMBER`.
49/// * `MAX_INTERRUPT_NUMBER` must coincide with the highest allowed interrupt number.
50pub unsafe trait InterruptNumber: Copy {
51    /// Highest number assigned to an interrupt source.
52    const MAX_INTERRUPT_NUMBER: usize;
53
54    /// Converts an interrupt source to its corresponding number.
55    fn number(self) -> usize;
56
57    /// Tries to convert a number to a valid interrupt.
58    fn from_number(value: usize) -> Result<Self>;
59}
60
61/// Marker trait for enums of target-specific core interrupt numbers.
62///
63/// Core interrupts are interrupts are retrieved from the `mcause` CSR. Usually, vectored mode is
64/// only available for core interrupts. The `riscv` crate provides a default implementation for
65/// the RISC-V ISA. However, a PAC may override the default implementation if the target has a
66/// different interrupt numbering scheme (e.g., ESP32C3).
67///
68/// # Safety
69///
70/// Each enum variant must represent a valid core interrupt number read from the `mcause` CSR.
71pub unsafe trait CoreInterruptNumber: InterruptNumber {}
72
73/// Marker trait for enums of target-specific external interrupt numbers.
74///
75/// External interrupts are interrupts caused by external sources (e.g., GPIO, UART, SPI).
76/// External interrupts are **not** retrieved from the `mcause` CSR.
77/// Instead, RISC-V processors have a single core interrupt for all external interrupts.
78/// An additional peripheral (e.g., PLIC) is used to multiplex the external interrupts.
79///
80/// # Safety
81///
82/// Each enum variant must represent a valid external interrupt number.
83pub unsafe trait ExternalInterruptNumber: InterruptNumber {}
84
85/// Trait for enums of priority levels.
86///
87/// This trait should be implemented by a peripheral access crate (PAC) on its enum of available
88/// priority numbers for a specific device. Each variant must convert to a `usize` of its priority level.
89///
90/// # Safety
91///
92/// * This trait must only be implemented on a PAC of a RISC-V target.
93/// * This trait must only be implemented on enums of priority levels.
94/// * Each enum variant must represent a distinct value (no duplicates are permitted).
95/// * Each enum variant must always return the same value (do not change at runtime).
96/// * All the priority level numbers must be less than or equal to `MAX_PRIORITY_NUMBER`.
97/// * `MAX_PRIORITY_NUMBER` must coincide with the highest allowed priority number.
98pub unsafe trait PriorityNumber: Copy {
99    /// Number assigned to the highest priority level.
100    const MAX_PRIORITY_NUMBER: usize;
101
102    /// Converts a priority level to its corresponding number.
103    fn number(self) -> usize;
104
105    /// Tries to convert a number to a valid priority level.
106    fn from_number(value: usize) -> Result<Self>;
107}
108
109/// Trait for enums of HART identifiers.
110///
111/// This trait should be implemented by a peripheral access crate (PAC) on its enum of available
112/// HARTs for a specific device. Each variant must convert to a `usize` of its HART ID number.
113///
114/// # Safety
115///
116/// * This trait must only be implemented on a PAC of a RISC-V target.
117/// * This trait must only be implemented on enums of HART IDs.
118/// * Each enum variant must represent a distinct value (no duplicates are permitted),
119/// * Each anum variant must always return the same value (do not change at runtime).
120/// * All the HART ID numbers must be less than or equal to `MAX_HART_ID_NUMBER`.
121/// * `MAX_HART_ID_NUMBER` must coincide with the highest allowed HART ID number.
122pub unsafe trait HartIdNumber: Copy {
123    /// Highest number assigned to a context.
124    const MAX_HART_ID_NUMBER: usize;
125
126    /// Converts a HART ID to its corresponding number.
127    fn number(self) -> usize;
128
129    /// Tries to convert a number to a valid HART ID.
130    fn from_number(value: usize) -> Result<Self>;
131}
132
133#[cfg(test)]
134mod 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: usize = Self::P3 as usize;
205
206        #[inline]
207        fn number(self) -> usize {
208            self as _
209        }
210
211        #[inline]
212        fn from_number(number: usize) -> 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)),
219            }
220        }
221    }
222
223    unsafe impl HartIdNumber for HartId {
224        const MAX_HART_ID_NUMBER: usize = Self::H2 as usize;
225
226        #[inline]
227        fn number(self) -> usize {
228            self as _
229        }
230
231        #[inline]
232        fn from_number(number: usize) -> 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)),
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}