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}