Skip to content

Commit e9cd65d

Browse files
committed
added example for async delays with CLINT
1 parent f4e29c4 commit e9cd65d

File tree

4 files changed

+52
-27
lines changed

4 files changed

+52
-27
lines changed

riscv-peripheral/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ embedded-hal-async = { version = "1.0.0", optional = true }
1111
riscv = { path = "../riscv", version = "0.11.0" }
1212
riscv-pac = { path = "../riscv-pac", version = "0.1.0" }
1313

14+
[dev-dependencies]
15+
heapless = "0.8.0"
16+
1417
[features]
1518
aclint-hal-async = ["embedded-hal-async"]
1619

riscv-peripheral/examples/e310x.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,46 @@ riscv_peripheral::plic_codegen!(
159159
ctxs [ctx0=(HartId::H0,"`H0`")],
160160
);
161161

162+
#[cfg(feature = "aclint-hal-async")]
163+
/// extern functions needed by the `riscv-peripheral` crate for the `async` feature.
164+
///
165+
/// # Note
166+
///
167+
/// The functionality in this module is just to illustrate how to enable the `async` feature
168+
/// The timer queue used here, while functional, is unsound and should not be used in production.
169+
/// In this case, you should protect the timer queue with a mutex or critical section.
170+
/// For a more robust implementation, use proper timer queues such as the ones provided by `embassy-time`
171+
mod async_no_mangle {
172+
use super::CLINT;
173+
use heapless::binary_heap::{BinaryHeap, Min};
174+
use riscv_peripheral::{aclint::mtimer::MTIMER, hal_async::aclint::Timer};
175+
176+
const N_TIMERS: usize = 16;
177+
static mut TIMER_QUEUE: BinaryHeap<Timer, Min, N_TIMERS> = BinaryHeap::new();
178+
179+
#[no_mangle]
180+
fn _riscv_peripheral_aclint_mtimer() -> MTIMER {
181+
CLINT::mtimer()
182+
}
183+
184+
#[no_mangle]
185+
fn _riscv_peripheral_aclint_push_timer(t: Timer) -> Result<(), Timer> {
186+
unsafe { TIMER_QUEUE.push(t) }
187+
}
188+
189+
#[no_mangle]
190+
fn _riscv_peripheral_aclint_wake_timers(current_tick: u64) -> Option<u64> {
191+
let mut next_expires = None;
192+
while let Some(t) = unsafe { TIMER_QUEUE.peek() } {
193+
if t.expires() > current_tick {
194+
next_expires = Some(t.expires());
195+
break;
196+
}
197+
let t = unsafe { TIMER_QUEUE.pop() }.unwrap();
198+
t.waker().wake_by_ref();
199+
}
200+
next_expires
201+
}
202+
}
203+
162204
fn main() {}

riscv-peripheral/src/hal_async/aclint.rs

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
//! The following `extern "Rust"` functions must be implemented:
1212
//!
1313
//! - `fn _riscv_peripheral_aclint_mtimer(hart_id: usize) -> MTIMER`: This function returns the `MTIMER` register for the given HART ID.
14-
//! This function is implemented by the [`crate::clint_codegen`] macro when asyn_delay is provided.
1514
//! - `fn _riscv_peripheral_aclint_push_timer(t: Timer) -> Result<(), Timer>`: This function pushes a new timer to a timer queue assigned to the given HART ID.
1615
//! If it fails (e.g., the timer queue is full), it returns back the timer that failed to be pushed.
1716
//! The logic of timer queues are application-specific and are not provided by this crate.
@@ -37,18 +36,18 @@ extern "Rust" {
3736
/// Do not call this function directly. It is only meant to be called by [`MachineTimer`].
3837
fn _riscv_peripheral_aclint_mtimer() -> MTIMER;
3938

40-
/// Tries to push a new timer to the timer queue assigned to the given HART ID.
39+
/// Tries to push a new timer to the timer queue assigned to the `MTIMER` register for the current HART ID.
4140
/// If it fails (e.g., the timer queue is full), it returns back the timer that failed to be pushed.
4241
///
4342
/// # Safety
4443
///
4544
/// Do not call this function directly. It is only meant to be called by [`DelayAsync`].
4645
fn _riscv_peripheral_aclint_push_timer(t: Timer) -> Result<(), Timer>;
4746

48-
/// Pops all the expired timers from the timer queue assigned to the current HART ID and wakes their associated wakers.
49-
/// Once it is done, if the queue is empty, it returns `None`.
50-
/// Alternatively, if the queue is not empty but the earliest timer has not expired yet,
51-
/// it returns `Some(next_expires)` where `next_expires` is the tick at which this timer expires.
47+
/// Pops all the expired timers from the timer queue assigned to the `MTIMER` register for the
48+
/// current HART ID and wakes their associated wakers. Once it is done, if the queue is empty,
49+
/// it returns `None`. Alternatively, if the queue is not empty but the earliest timer has not expired
50+
/// yet, it returns `Some(next_expires)` where `next_expires` is the tick at which this timer expires.
5251
///
5352
/// # Safety
5453
///
@@ -75,7 +74,7 @@ fn schedule_machine_timer(mtime: MTIME, mtimercmp: MTIMECMP) {
7574
if let Some(next_expires) = unsafe { _riscv_peripheral_aclint_wake_timers(current_tick) } {
7675
debug_assert!(next_expires > current_tick);
7776
mtimercmp.write(next_expires); // schedule next interrupt at next_expires
78-
unsafe { riscv::register::mie::set_mtimer() }; // enable machine timer interrupts again if necessary
77+
unsafe { riscv::register::mie::set_mtimer() }; // enable machine timer interrupts
7978
}
8079
}
8180

@@ -89,7 +88,6 @@ fn schedule_machine_timer(mtime: MTIME, mtimercmp: MTIMECMP) {
8988
/// Additionally, the rest of the application must not modify the [`MTIMER`] register assigned to the current HART.
9089
#[derive(Clone)]
9190
pub struct Delay {
92-
hart_id: usize,
9391
freq: usize,
9492
mtime: MTIME,
9593
mtimecmp: MTIMECMP,
@@ -99,11 +97,9 @@ impl Delay {
9997
/// Creates a new `Delay` instance for the current HART.
10098
#[inline]
10199
pub fn new(freq: usize) -> Self {
102-
let hart_id = riscv::register::mhartid::read();
103100
let mtimer = unsafe { _riscv_peripheral_aclint_mtimer() };
104101
let (mtime, mtimecmp) = (mtimer.mtime, mtimer.mtimecmp_mhartid());
105102
Self {
106-
hart_id,
107103
freq,
108104
mtime,
109105
mtimecmp,
@@ -148,7 +144,6 @@ impl DelayNs for Delay {
148144
/// this entry provides the necessary information to adapt it to the timer queue implementation.
149145
#[derive(Debug)]
150146
pub struct Timer {
151-
hart_id: usize,
152147
freq: usize,
153148
mtime: MTIME,
154149
mtimecmp: MTIMECMP,
@@ -160,15 +155,13 @@ impl Timer {
160155
/// Creates a new timer queue entry.
161156
#[inline]
162157
const fn new(
163-
hart_id: usize,
164158
freq: usize,
165159
mtime: MTIME,
166160
mtimecmp: MTIMECMP,
167161
expires: u64,
168162
waker: Waker,
169163
) -> Self {
170164
Self {
171-
hart_id,
172165
freq,
173166
mtime,
174167
mtimecmp,
@@ -177,12 +170,6 @@ impl Timer {
177170
}
178171
}
179172

180-
/// Returns the HART ID associated with this timer.
181-
#[inline]
182-
pub const fn hart_id(&self) -> usize {
183-
self.hart_id
184-
}
185-
186173
/// Returns the frequency of the [`MTIME`] register associated with this timer.
187174
#[inline]
188175
pub const fn freq(&self) -> usize {
@@ -216,7 +203,7 @@ impl Timer {
216203

217204
impl PartialEq for Timer {
218205
fn eq(&self, other: &Self) -> bool {
219-
self.hart_id == other.hart_id && self.freq == other.freq && self.expires == other.expires
206+
self.freq == other.freq && self.expires == other.expires
220207
}
221208
}
222209

@@ -262,7 +249,6 @@ impl<'a> Future for DelayAsync<'a> {
262249
// we only push the timer to the queue the first time we poll
263250
self.pushed = true;
264251
let timer = Timer::new(
265-
self.delay.hart_id,
266252
self.delay.freq,
267253
self.delay.mtime,
268254
self.delay.mtimecmp,

riscv-peripheral/src/macros.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -214,12 +214,6 @@ macro_rules! clint_codegen {
214214
$crate::clint_codegen!($($tail)*);
215215
};
216216
(async_delay, $($tail:tt)*) => {
217-
218-
#[no_mangle]
219-
const fn _riscv_peripheral_aclint_mtimer() -> $crate::aclint::mtimer::MTIMER {
220-
CLINT::mtimer()
221-
}
222-
223217
impl CLINT {
224218
/// Asynchronous delay implementation for CLINT peripherals.
225219
///

0 commit comments

Comments
 (0)