Skip to content

Commit fd82252

Browse files
committed
New riscv-pac
1 parent 5612138 commit fd82252

File tree

9 files changed

+271
-49
lines changed

9 files changed

+271
-49
lines changed

riscv-pac/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1010
### Added
1111

1212
- Add `result` module for `Error` and `Result` types
13+
- Add `ExceptionNumber` trait.
14+
- Classify interrupt numbers in `CoreInterruptNumber` and `ExternalInterruptNumber`.
15+
- Added simple tests to illustrate how to implement all the provided traits.
16+
17+
### Changed
18+
19+
- `InterruptNumber` trait now expects `usize`
1320

1421
## [v0.1.1] - 2024-02-15
1522

riscv-pac/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
[package]
22
name = "riscv-pac"
3-
version = "0.1.1"
3+
version = "0.2.0"
44
edition = "2021"
5-
rust-version = "1.60"
5+
rust-version = "1.61"
66
repository = "https://github.com/rust-embedded/riscv"
77
authors = ["The RISC-V Team <[email protected]>"]
88
categories = ["embedded", "hardware-support", "no-std"]

riscv-pac/src/lib.rs

Lines changed: 225 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,86 @@ pub mod result;
44

55
use 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.
2147
pub 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+
}

riscv-peripheral/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1111

1212
- use `riscv-pac` result types for trait implementations
1313

14+
### Changed
15+
16+
- Bump `riscv-pac` version
17+
1418
### Fixed
1519

1620
- `clippy` fixes

riscv-peripheral/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ license = "ISC"
1717
embedded-hal = "1.0.0"
1818
embedded-hal-async = { version = "1.0.0", optional = true }
1919
riscv = { path = "../riscv", version = "0.11.1" }
20-
riscv-pac = { path = "../riscv-pac", version = "0.1.1" }
20+
riscv-pac = { path = "../riscv-pac", version = "0.2.0" }
2121

2222
[dev-dependencies]
2323
heapless = "0.8.0"

riscv-peripheral/examples/e310x.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,15 @@ unsafe impl HartIdNumber for HartId {
2121

2222
#[inline]
2323
fn from_number(number: u16) -> Result<Self> {
24-
if number > Self::MAX_HART_ID_NUMBER {
25-
Err(Error::InvalidVariant(number as usize))
26-
} else {
27-
// SAFETY: valid context number
28-
Ok(unsafe { core::mem::transmute(number) })
24+
match number {
25+
0 => Ok(Self::H0),
26+
_ => Err(Error::InvalidVariant(number as usize)),
2927
}
3028
}
3129
}
3230

3331
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
34-
#[repr(u16)]
32+
#[repr(usize)]
3533
pub enum Interrupt {
3634
WATCHDOG = 1,
3735
RTC = 2,
@@ -88,20 +86,20 @@ pub enum Interrupt {
8886
}
8987

9088
unsafe impl InterruptNumber for Interrupt {
91-
const MAX_INTERRUPT_NUMBER: u16 = 52;
89+
const MAX_INTERRUPT_NUMBER: usize = 52;
9290

9391
#[inline]
94-
fn number(self) -> u16 {
92+
fn number(self) -> usize {
9593
self as _
9694
}
9795

9896
#[inline]
99-
fn from_number(number: u16) -> Result<Self> {
97+
fn from_number(number: usize) -> Result<Self> {
10098
if number == 0 || number > Self::MAX_INTERRUPT_NUMBER {
101-
Err(Error::InvalidVariant(number as usize))
99+
Err(Error::InvalidVariant(number))
102100
} else {
103101
// SAFETY: valid interrupt number
104-
Ok(unsafe { core::mem::transmute(number) })
102+
Ok(unsafe { core::mem::transmute::<usize, Interrupt>(number) })
105103
}
106104
}
107105
}
@@ -133,7 +131,7 @@ unsafe impl PriorityNumber for Priority {
133131
Err(Error::InvalidVariant(number as usize))
134132
} else {
135133
// SAFETY: valid priority number
136-
Ok(unsafe { core::mem::transmute(number) })
134+
Ok(unsafe { core::mem::transmute::<u8, Priority>(number) })
137135
}
138136
}
139137
}

0 commit comments

Comments
 (0)