Skip to content

Commit 16e30d0

Browse files
committed
Rework of PLIC
1 parent a7fbb58 commit 16e30d0

File tree

4 files changed

+135
-83
lines changed

4 files changed

+135
-83
lines changed

riscv-peripheral/CHANGELOG.md

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

1212
- Rework of CLINT peripheral to use methods instead of associated functions.
1313
This change follows the `svd2rust` pattern, making the ecosystem more consistent.
14-
- Simplify `clint!` macro using the `Deref` trait.
14+
- Simplify `clint_codegen!` macro using the `Deref` trait.
15+
- Rework of PLIC peripherals to use methods instead of associated functions.
16+
This change follows the `svd2rust` pattern, making the ecosystem more consistent.
17+
- Simplify `plic_codegen!` macro using the `Deref` trait.
1518

1619
### Removed
1720

riscv-peripheral/examples/e310x.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ riscv_peripheral::clint_codegen!(
147147

148148
riscv_peripheral::plic_codegen!(
149149
base 0x0C00_0000,
150-
ctxs [ctx0=(HartId::H0,"`H0`")],
150+
harts [HartId::H0 => 0],
151151
);
152152

153153
fn main() {}

riscv-peripheral/src/macros.rs

Lines changed: 73 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ macro_rules! clint_codegen {
140140
/// This macro expects 2 different argument types:
141141
///
142142
/// - Base address (**MANDATORY**): base address of the PLIC peripheral of the target.
143-
/// - Per-HART contexts (**OPTIONAL**): a list of `ctx` contexts for easing access to per-HART PLIC contexts.
143+
/// - HART map (**OPTIONAL**): a list of HART IDs and their corresponding numbers.
144144
///
145145
/// Check the examples below for more details about the usage and syntax of this macro.
146146
///
@@ -153,8 +153,48 @@ macro_rules! clint_codegen {
153153
///
154154
/// riscv_peripheral::plic_codegen!(base 0x0C00_0000,); // do not forget the ending comma!
155155
///
156-
/// let priorities = PLIC::priorities(); // Priorities registers
157-
/// let pendings = PLIC::pendings(); // Pendings registers
156+
/// let plic = PLIC::new(); // Create a new PLIC peripheral
157+
/// let priorities = plic.priorities(); // Priorities registers
158+
/// let pendings = plic.pendings(); // Pendings registers
159+
/// ```
160+
///
161+
///
162+
/// ## Base address and per-HART context proxies
163+
///
164+
/// ```
165+
/// use riscv_pac::result::{Error, Result};
166+
///
167+
/// /// HART IDs for the target CLINT peripheral
168+
/// #[derive(Clone, Copy, Debug, Eq, PartialEq)]
169+
/// pub enum HartId { H0 = 0, H1 = 1, H2 = 2 }
170+
///
171+
/// // Implement `HartIdNumber` for `HartId`
172+
/// unsafe impl riscv_peripheral::aclint::HartIdNumber for HartId {
173+
/// const MAX_HART_ID_NUMBER: usize = Self::H2 as usize;
174+
/// fn number(self) -> usize { self as _ }
175+
/// fn from_number(number: usize) -> Result<Self> {
176+
/// match number {
177+
/// 0 => Ok(HartId::H0),
178+
/// 1 => Ok(HartId::H1),
179+
/// 2 => Ok(HartId::H2),
180+
/// _ => Err(Error::InvalidVariant(number)),
181+
/// }
182+
/// }
183+
/// }
184+
///
185+
/// riscv_peripheral::plic_codegen!(
186+
/// base 0x0C00_0000,
187+
/// harts [HartId::H0 => 0, HartId::H1 => 1, HartId::H2 => 2], // do not forget the ending comma!
188+
/// );
189+
///
190+
/// let plic = PLIC::new(); // Create a new PLIC peripheral
191+
/// let ctx0 = plic.ctx0(); // Context proxy for HART 0
192+
/// let ctx1 = plic.ctx1(); // Context proxy for HART 1
193+
/// let ctx2 = plic.ctx2(); // Context proxy for HART 2
194+
///
195+
/// assert_eq!(ctx0, plic.ctx(HartId::H0));
196+
/// assert_eq!(ctx1, plic.ctx(HartId::H1));
197+
/// assert_eq!(ctx2, plic.ctx(HartId::H2));
158198
/// ```
159199
#[macro_export]
160200
macro_rules! plic_codegen {
@@ -166,84 +206,51 @@ macro_rules! plic_codegen {
166206
/// PLIC peripheral
167207
#[allow(clippy::upper_case_acronyms)]
168208
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
169-
pub struct PLIC;
170-
171-
unsafe impl $crate::plic::Plic for PLIC {
172-
const BASE: usize = $addr;
173-
}
209+
pub struct PLIC($crate::plic::PLIC<Self>);
174210

175211
impl PLIC {
176-
/// Returns `true` if a machine external interrupt is pending.
177-
#[inline]
178-
pub fn is_interrupting() -> bool {
179-
$crate::riscv::register::mip::read().mext()
180-
}
181-
182-
/// Returns true if Machine External Interrupts are enabled.
183-
#[inline]
184-
pub fn is_enabled() -> bool {
185-
$crate::riscv::register::mie::read().mext()
186-
}
187-
188-
/// Enables machine external interrupts to allow the PLIC to trigger interrupts.
189-
///
190-
/// # Safety
191-
///
192-
/// Enabling the `PLIC` may break mask-based critical sections.
193-
#[inline]
194-
pub unsafe fn enable() {
195-
$crate::riscv::register::mie::set_mext();
196-
}
197-
198-
/// Disables machine external interrupts to prevent the PLIC from triggering interrupts.
212+
/// Creates a new `CLINT` peripheral.
199213
#[inline]
200-
pub fn disable() {
201-
// SAFETY: it is safe to disable interrupts
202-
unsafe { $crate::riscv::register::mie::clear_mext() };
214+
pub const fn new() -> Self {
215+
Self($crate::plic::PLIC::new())
203216
}
217+
}
204218

205-
/// Returns the priorities register of the PLIC.
206-
#[inline]
207-
pub fn priorities() -> $crate::plic::priorities::PRIORITIES {
208-
$crate::plic::PLIC::<PLIC>::priorities()
209-
}
219+
unsafe impl $crate::plic::Plic for PLIC {
220+
const BASE: usize = $addr;
221+
}
210222

211-
/// Returns the pendings register of the PLIC.
212-
#[inline]
213-
pub fn pendings() -> $crate::plic::pendings::PENDINGS {
214-
$crate::plic::PLIC::<PLIC>::pendings()
215-
}
223+
impl core::ops::Deref for PLIC {
224+
type Target = $crate::plic::PLIC<Self>;
216225

217-
/// Returns the context proxy of a given PLIC HART context.
218226
#[inline]
219-
pub fn ctx<H: $crate::plic::HartIdNumber>(hart_id: H) -> $crate::plic::CTX<Self> {
220-
$crate::plic::PLIC::<PLIC>::ctx(hart_id)
227+
fn deref(&self) -> &Self::Target {
228+
&self.0
221229
}
230+
}
222231

223-
/// Returns the PLIC HART context for the current HART.
224-
///
225-
/// # Note
226-
///
227-
/// This function determines the current HART ID by reading the [`riscv::register::mhartid`] CSR.
228-
/// Thus, it can only be used in M-mode. For S-mode, use [`PLIC::ctx`] instead.
232+
impl core::ops::DerefMut for PLIC {
229233
#[inline]
230-
pub fn ctx_mhartid() -> $crate::plic::CTX<Self> {
231-
$crate::plic::PLIC::<PLIC>::ctx_mhartid()
234+
fn deref_mut(&mut self) -> &mut Self::Target {
235+
&mut self.0
232236
}
233237
}
238+
234239
$crate::plic_codegen!($($tail)*);
235240
};
236-
(ctxs [$($fn:ident = ($ctx:expr , $sctx:expr)),+], $($tail:tt)*) => {
237-
impl PLIC {
238-
$(
239-
#[doc = "Returns a PLIC context proxy for context of HART "]
240-
#[doc = $sctx]
241-
#[doc = "."]
242-
#[inline]
243-
pub fn $fn() -> $crate::plic::CTX<Self> {
244-
Self::ctx($ctx)
245-
}
246-
)*
241+
(harts [$($hart:expr => $num:literal),+], $($tail:tt)*) => {
242+
$crate::macros::paste! {
243+
impl PLIC {
244+
$(
245+
#[doc = "Returns a PLIC context proxy for context of HART "]
246+
#[doc = stringify!($hart)]
247+
#[doc = "`]."]
248+
#[inline]
249+
pub fn [<ctx $num>](&self) -> $crate::plic::CTX<Self> {
250+
self.ctx($hart)
251+
}
252+
)*
253+
}
247254
}
248255
$crate::plic_codegen!($($tail)*);
249256
};

riscv-peripheral/src/plic.rs

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ pub mod threshold;
1111
// re-export useful riscv-pac traits
1212
pub use riscv_pac::{HartIdNumber, InterruptNumber, PriorityNumber};
1313

14+
use riscv::register::{mhartid, mie, mip};
15+
1416
/// Trait for a PLIC peripheral.
1517
///
1618
/// # Safety
@@ -43,26 +45,65 @@ impl<P: Plic> PLIC<P> {
4345

4446
const PENDINGS_OFFSET: usize = 0x1000;
4547

46-
/// Returns the priorities register of the PLIC.
48+
/// Creates a new `PLIC` peripheral.
49+
#[inline]
50+
pub const fn new() -> Self {
51+
Self {
52+
_marker: core::marker::PhantomData,
53+
}
54+
}
55+
56+
/// Returns `true` if a machine external interrupt is pending.
57+
#[inline]
58+
pub fn is_interrupting(&self) -> bool {
59+
mip::read().mext()
60+
}
61+
62+
/// Returns true if machine external interrupts are enabled.
63+
#[inline]
64+
pub fn is_enabled(&self) -> bool {
65+
mie::read().mext()
66+
}
67+
68+
/// Enables machine external interrupts to allow the PLIC to trigger interrupts.
69+
///
70+
/// # Safety
71+
///
72+
/// Enabling the `PLIC` may break mask-based critical sections.
73+
#[inline]
74+
pub unsafe fn enable(&self) {
75+
mie::set_mext();
76+
}
77+
78+
/// Disables machine external interrupts to prevent the PLIC from triggering interrupts.
79+
#[inline]
80+
pub fn disable(&self) {
81+
// SAFETY: it is safe to disable interrupts
82+
unsafe { mie::clear_mext() };
83+
}
84+
85+
/// Returns the [`PRIORITIES`](priorities::PRIORITIES) register of the PLIC.
86+
///
4787
/// This register allows to set the priority level of each interrupt source.
4888
/// The priority level of each interrupt source is shared among all the contexts.
4989
#[inline]
50-
pub fn priorities() -> priorities::PRIORITIES {
90+
pub const fn priorities(&self) -> priorities::PRIORITIES {
5191
// SAFETY: valid address
5292
unsafe { priorities::PRIORITIES::new(P::BASE + Self::PRIORITIES_OFFSET) }
5393
}
5494

55-
/// Returns the pendings register of the PLIC.
95+
/// Returns the [`PENDINGS`](pendings::PENDINGS) register of the PLIC.
96+
///
5697
/// This register allows to check if a particular interrupt source is pending.
5798
#[inline]
58-
pub fn pendings() -> pendings::PENDINGS {
99+
pub const fn pendings(&self) -> pendings::PENDINGS {
59100
// SAFETY: valid address
60101
unsafe { pendings::PENDINGS::new(P::BASE + Self::PENDINGS_OFFSET) }
61102
}
62103

63104
/// Returns a proxy to access to all the PLIC registers of a given HART context.
64105
#[inline]
65-
pub fn ctx<H: HartIdNumber>(hart_id: H) -> CTX<P> {
106+
pub fn ctx<H: HartIdNumber>(&self, hart_id: H) -> CTX<P> {
66107
// SAFETY: valid context number
67108
unsafe { CTX::new(hart_id.number() as _) }
68109
}
@@ -71,11 +112,11 @@ impl<P: Plic> PLIC<P> {
71112
///
72113
/// # Note
73114
///
74-
/// This function determines the current HART ID by reading the [`riscv::register::mhartid`] CSR.
115+
/// This function determines the current HART ID by reading the [`mhartid`] CSR.
75116
/// Thus, it can only be used in M-mode. For S-mode, use [`PLIC::ctx`] instead.
76117
#[inline]
77-
pub fn ctx_mhartid() -> CTX<P> {
78-
let hart_id = riscv::register::mhartid::read();
118+
pub fn ctx_mhartid(&self) -> CTX<P> {
119+
let hart_id = mhartid::read();
79120
// SAFETY: `hart_id` is valid for the target and is the current hart
80121
unsafe { CTX::new(hart_id as _) }
81122
}
@@ -281,19 +322,20 @@ pub(crate) mod test {
281322
fn check_plic() {
282323
crate::plic_codegen!(
283324
base 0x0C00_0000,
284-
ctxs [ctx0 = (Context::C0, "`C0`"), ctx1 = (Context::C1, "`C1`"), ctx2 = (Context::C2, "`C2`")],
325+
harts [Context::C0 => 0, Context::C1 => 1, Context::C2 => 2],
285326
);
286327

287-
let priorities = PLIC::priorities();
288-
let pendings = PLIC::pendings();
328+
let plic = PLIC::new();
329+
let priorities = plic.priorities();
330+
let pendings = plic.pendings();
289331

290332
assert_eq!(priorities.address(), 0x0C00_0000);
291333
assert_eq!(pendings.address(), 0x0C00_1000);
292334

293335
for i in 0..=Context::MAX_HART_ID_NUMBER {
294336
let context = Context::from_number(i).unwrap();
295337

296-
let ctx = PLIC::ctx(context);
338+
let ctx = plic.ctx(context);
297339

298340
assert_eq!(ctx.enables().address(), 0x0C00_0000 + 0x2000 + i * 0x80);
299341
assert_eq!(
@@ -306,8 +348,8 @@ pub(crate) mod test {
306348
);
307349
}
308350

309-
assert_eq!(PLIC::ctx0(), PLIC::ctx(Context::C0));
310-
assert_eq!(PLIC::ctx1(), PLIC::ctx(Context::C1));
311-
assert_eq!(PLIC::ctx2(), PLIC::ctx(Context::C2));
351+
assert_eq!(plic.ctx0(), plic.ctx(Context::C0));
352+
assert_eq!(plic.ctx1(), plic.ctx(Context::C1));
353+
assert_eq!(plic.ctx2(), plic.ctx(Context::C2));
312354
}
313355
}

0 commit comments

Comments
 (0)