Skip to content

Commit 6c75aa0

Browse files
committed
Generics for interrupts and exceptions
1 parent 794b7e0 commit 6c75aa0

File tree

7 files changed

+159
-205
lines changed

7 files changed

+159
-205
lines changed

riscv-pac/macros/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ impl PacNumberEnum {
107107
fn from_number(number: #num_type) -> Result<Self, #num_type> {
108108
if #valid_condition {
109109
// SAFETY: The number is valid for this enum
110-
Ok(unsafe { core::mem::transmute(number) })
110+
Ok(unsafe { core::mem::transmute::<#num_type, Self>(number) })
111111
} else {
112112
Err(number)
113113
}
@@ -148,7 +148,7 @@ impl PacNumberEnum {
148148
/// ```rust
149149
/// use riscv_pac::*;
150150
///
151-
/// #[repr(u16)]
151+
/// #[repr(usize)]
152152
/// #[pac_enum(unsafe ExceptionNumber)]
153153
/// #[derive(Clone, Copy, Debug, Eq, PartialEq)]
154154
/// enum Exception {
@@ -190,8 +190,8 @@ pub fn pac_enum(attr: TokenStream, item: TokenStream) -> TokenStream {
190190
}
191191

192192
let trait_impl = match attrs[1] {
193-
"ExceptionNumber" => pac_enum.quote("ExceptionNumber", "u16", "MAX_EXCEPTION_NUMBER"),
194-
"InterruptNumber" => pac_enum.quote("InterruptNumber", "u16", "MAX_INTERRUPT_NUMBER"),
193+
"ExceptionNumber" => pac_enum.quote("ExceptionNumber", "usize", "MAX_EXCEPTION_NUMBER"),
194+
"InterruptNumber" => pac_enum.quote("InterruptNumber", "usize", "MAX_INTERRUPT_NUMBER"),
195195
"PriorityNumber" => pac_enum.quote("PriorityNumber", "u8", "MAX_PRIORITY_NUMBER"),
196196
"HartIdNumber" => pac_enum.quote("HartIdNumber", "u16", "MAX_HART_ID_NUMBER"),
197197
_ => panic!("Unknown trait '{}'. Expected: 'ExceptionNumber', 'InterruptNumber', 'PriorityNumber', or 'HartIdNumber'", attrs[1]),

riscv-pac/src/lib.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pub use riscv_pac_macros::*;
77
///
88
/// This trait should be implemented by a peripheral access crate (PAC) on its enum of available
99
/// exceptions for a specific device. Alternatively, the `riscv` crate provides a default
10-
/// implementation for the RISC-V ISA. Each variant must convert to a `u16` of its exception number.
10+
/// implementation for the RISC-V ISA. Each variant must convert to a `usize` of its exception number.
1111
///
1212
/// # Safety
1313
///
@@ -19,21 +19,21 @@ pub use riscv_pac_macros::*;
1919
/// * `MAX_EXCEPTION_NUMBER` must coincide with the highest allowed exception number.
2020
pub unsafe trait ExceptionNumber: Copy {
2121
/// Highest number assigned to an exception.
22-
const MAX_EXCEPTION_NUMBER: u16;
22+
const MAX_EXCEPTION_NUMBER: usize;
2323

2424
/// Converts an exception to its corresponding number.
25-
fn number(self) -> u16;
25+
fn number(self) -> usize;
2626

2727
/// Tries to convert a number to a valid exception.
2828
/// If the conversion fails, it returns an error with the number back.
29-
fn from_number(value: u16) -> Result<Self, u16>;
29+
fn from_number(value: usize) -> Result<Self, usize>;
3030
}
3131

3232
/// Trait for enums of target-specific interrupt numbers.
3333
///
3434
/// This trait should be implemented by a peripheral access crate (PAC) on its enum of available
3535
/// interrupts for a specific device. Alternatively, the `riscv` crate provides a default
36-
/// implementation for the RISC-V ISA. Each variant must convert to a `u16` of its interrupt number.
36+
/// implementation for the RISC-V ISA. Each variant must convert to a `usize` of its interrupt number.
3737
///
3838
/// # Safety
3939
///
@@ -45,14 +45,14 @@ pub unsafe trait ExceptionNumber: Copy {
4545
/// * `MAX_INTERRUPT_NUMBER` must coincide with the highest allowed interrupt number.
4646
pub unsafe trait InterruptNumber: Copy {
4747
/// Highest number assigned to an interrupt source.
48-
const MAX_INTERRUPT_NUMBER: u16;
48+
const MAX_INTERRUPT_NUMBER: usize;
4949

5050
/// Converts an interrupt source to its corresponding number.
51-
fn number(self) -> u16;
51+
fn number(self) -> usize;
5252

5353
/// Tries to convert a number to a valid interrupt source.
5454
/// If the conversion fails, it returns an error with the number back.
55-
fn from_number(value: u16) -> Result<Self, u16>;
55+
fn from_number(value: usize) -> Result<Self, usize>;
5656
}
5757

5858
/// Marker trait for enums of target-specific core interrupt numbers.

riscv-pac/tests/ui/fail_wrong_repr.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-
44
1 | #[riscv_pac::pac_enum(unsafe InterruptNumber)]
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
7-
= note: source type: `u16` (16 bits)
7+
= note: source type: `usize` (64 bits)
88
= note: target type: `Interrupt` (8 bits)
99
= note: this error originates in the attribute macro `riscv_pac::pac_enum` (in Nightly builds, run with -Z macro-backtrace for more info)

riscv-pac/tests/ui/pass_test.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use riscv_pac::*;
22

3-
#[repr(u16)]
3+
#[repr(usize)]
44
#[pac_enum(unsafe ExceptionNumber)]
55
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
66
enum Exception {
77
E1 = 1,
88
E3 = 3,
99
}
1010

11-
#[repr(u16)]
11+
#[repr(usize)]
1212
#[pac_enum(unsafe InterruptNumber)]
1313
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1414
enum Interrupt {

riscv/src/interrupt.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ pub mod machine {
9292
r
9393
}
9494
}
95+
9596
pub mod supervisor {
9697
use crate::register::{sepc, sstatus};
9798

riscv/src/register/mcause.rs

Lines changed: 73 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,7 @@
33
use riscv_pac::CoreInterruptNumber;
44
pub use riscv_pac::{ExceptionNumber, InterruptNumber}; // re-export useful riscv-pac traits
55

6-
/// mcause register
7-
#[derive(Clone, Copy, Debug)]
8-
pub struct Mcause {
9-
bits: usize,
10-
}
11-
12-
impl From<usize> for Mcause {
13-
#[inline]
14-
fn from(bits: usize) -> Self {
15-
Self { bits }
16-
}
17-
}
18-
19-
/// Trap Cause
20-
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
21-
pub enum Trap {
22-
Interrupt(Interrupt),
23-
Exception(Exception),
24-
}
25-
26-
/// Interrupt
6+
/// Standard M-mode RISC-V interrupts
277
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
288
#[repr(usize)]
299
pub enum Interrupt {
@@ -33,10 +13,32 @@ pub enum Interrupt {
3313
MachineTimer = 7,
3414
SupervisorExternal = 9,
3515
MachineExternal = 11,
36-
Unknown,
3716
}
3817

39-
/// Exception
18+
/// SAFETY: `Interrupt` represents the standard RISC-V interrupts
19+
unsafe impl InterruptNumber for Interrupt {
20+
const MAX_INTERRUPT_NUMBER: usize = Self::MachineExternal as usize;
21+
22+
#[inline]
23+
fn number(self) -> usize {
24+
self as usize
25+
}
26+
27+
#[inline]
28+
fn from_number(value: usize) -> Result<Self, usize> {
29+
if value > 11 || value % 2 == 0 {
30+
Err(value)
31+
} else {
32+
// SAFETY: valid interrupt number
33+
unsafe { Ok(core::mem::transmute::<usize, Self>(value)) }
34+
}
35+
}
36+
}
37+
38+
/// SAFETY: `Interrupt` represents the standard RISC-V core interrupts
39+
unsafe impl CoreInterruptNumber for Interrupt {}
40+
41+
/// Standard M-mode RISC-V exceptions
4042
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
4143
#[repr(usize)]
4244
pub enum Exception {
@@ -54,93 +56,52 @@ pub enum Exception {
5456
InstructionPageFault = 12,
5557
LoadPageFault = 13,
5658
StorePageFault = 15,
57-
Unknown,
58-
}
59-
60-
impl From<usize> for Interrupt {
61-
#[inline]
62-
fn from(nr: usize) -> Self {
63-
if nr > 11 || nr % 2 == 0 {
64-
Self::Unknown
65-
} else {
66-
// SAFETY: valid interrupt number
67-
unsafe { core::mem::transmute::<usize, Self>(nr) }
68-
}
69-
}
70-
}
71-
72-
impl TryFrom<Interrupt> for usize {
73-
type Error = Interrupt;
74-
75-
#[inline]
76-
fn try_from(value: Interrupt) -> Result<Self, Self::Error> {
77-
match value {
78-
Interrupt::Unknown => Err(Self::Error::Unknown),
79-
_ => Ok(value as Self),
80-
}
81-
}
8259
}
8360

84-
/// SAFETY: `Interrupt` represents the standard RISC-V interrupts
85-
unsafe impl InterruptNumber for Interrupt {
86-
const MAX_INTERRUPT_NUMBER: u16 = Self::MachineExternal as u16;
61+
/// SAFETY: `Exception` represents the standard RISC-V exceptions
62+
unsafe impl ExceptionNumber for Exception {
63+
const MAX_EXCEPTION_NUMBER: usize = Self::StorePageFault as usize;
8764

8865
#[inline]
89-
fn number(self) -> u16 {
90-
self as u16
66+
fn number(self) -> usize {
67+
self as usize
9168
}
9269

9370
#[inline]
94-
fn from_number(value: u16) -> Result<Self, u16> {
95-
match (value as usize).into() {
96-
Self::Unknown => Err(value),
97-
value => Ok(value),
98-
}
99-
}
100-
}
101-
102-
/// SAFETY: `Interrupt` represents the standard RISC-V core interrupts
103-
unsafe impl CoreInterruptNumber for Interrupt {}
104-
105-
impl From<usize> for Exception {
106-
#[inline]
107-
fn from(nr: usize) -> Self {
108-
if nr == 10 || nr == 14 || nr > 15 {
109-
Self::Unknown
71+
fn from_number(value: usize) -> Result<Self, usize> {
72+
if value == 10 || value == 14 || value > 15 {
73+
Err(value)
11074
} else {
11175
// SAFETY: valid exception number
112-
unsafe { core::mem::transmute::<usize, Self>(nr) }
76+
unsafe { Ok(core::mem::transmute::<usize, Self>(value)) }
11377
}
11478
}
11579
}
11680

117-
impl TryFrom<Exception> for usize {
118-
type Error = Exception;
119-
120-
#[inline]
121-
fn try_from(value: Exception) -> Result<Self, Self::Error> {
122-
match value {
123-
Exception::Unknown => Err(Self::Error::Unknown),
124-
_ => Ok(value as Self),
125-
}
126-
}
81+
/// Trap Cause
82+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
83+
pub enum Trap<I, E> {
84+
Interrupt(I),
85+
Exception(E),
12786
}
12887

129-
/// SAFETY: `Exception` represents the standard RISC-V exceptions
130-
unsafe impl ExceptionNumber for Exception {
131-
const MAX_EXCEPTION_NUMBER: u16 = Self::StorePageFault as u16;
88+
/// Trap Error
89+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
90+
pub enum TrapError {
91+
InvalidInterrupt(usize),
92+
InvalidException(usize),
93+
}
13294

133-
#[inline]
134-
fn number(self) -> u16 {
135-
self as u16
136-
}
95+
/// mcause register
96+
#[derive(Clone, Copy, Debug)]
97+
pub struct Mcause {
98+
bits: usize,
99+
}
137100

101+
impl From<usize> for Mcause {
138102
#[inline]
139-
fn from_number(value: u16) -> Result<Self, u16> {
140-
match (value as usize).into() {
141-
Self::Unknown => Err(value),
142-
value => Ok(value),
143-
}
103+
fn from(bits: usize) -> Self {
104+
Self { bits }
144105
}
145106
}
146107

@@ -157,16 +118,32 @@ impl Mcause {
157118
self.bits & !(1 << (usize::BITS as usize - 1))
158119
}
159120

160-
/// Trap Cause
121+
/// Try to get the trap cause
161122
#[inline]
162-
pub fn cause(&self) -> Trap {
123+
pub fn try_cause<I, E>(&self) -> Result<Trap<I, E>, TrapError>
124+
where
125+
I: CoreInterruptNumber,
126+
E: ExceptionNumber,
127+
{
163128
if self.is_interrupt() {
164-
Trap::Interrupt(Interrupt::from(self.code()))
129+
match I::from_number(self.code()) {
130+
Ok(interrupt) => Ok(Trap::Interrupt(interrupt)),
131+
Err(code) => Err(TrapError::InvalidInterrupt(code)),
132+
}
165133
} else {
166-
Trap::Exception(Exception::from(self.code()))
134+
match E::from_number(self.code()) {
135+
Ok(exception) => Ok(Trap::Exception(exception)),
136+
Err(code) => Err(TrapError::InvalidException(code)),
137+
}
167138
}
168139
}
169140

141+
/// Trap Cause
142+
#[inline]
143+
pub fn cause<I: CoreInterruptNumber, E: ExceptionNumber>(&self) -> Trap<I, E> {
144+
self.try_cause().unwrap()
145+
}
146+
170147
/// Is trap cause an interrupt.
171148
#[inline]
172149
pub fn is_interrupt(&self) -> bool {

0 commit comments

Comments
 (0)