Skip to content

Commit

Permalink
async stuff (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
romancardenas committed Jan 15, 2024
1 parent 2531e68 commit f4e29c4
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 15 deletions.
28 changes: 13 additions & 15 deletions riscv-peripheral/src/hal_async/aclint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
//! The following `extern "Rust"` functions must be implemented:
//!
//! - `fn _riscv_peripheral_aclint_mtimer(hart_id: usize) -> MTIMER`: This function returns the `MTIMER` register for the given HART ID.
//! This function is implemented by the [`crate::clint_codegen`] macro when asyn_delay is provided.
//! - `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.
//! If it fails (e.g., the timer queue is full), it returns back the timer that failed to be pushed.
//! The logic of timer queues are application-specific and are not provided by this crate.
//! - `fn _riscv_peripheral_aclint_wake_timers(hart_id: usize, current_tick: u64) -> Option<u64>`:
//! This function pops all the expired timers from a timer queue assigned to the given HART ID and wakes their associated wakers.
//! - `fn _riscv_peripheral_aclint_wake_timers(current_tick: u64) -> Option<u64>`:
//! This function pops all the expired timers from a timer queue assigned to the current HART ID and wakes their associated wakers.
//! The function returns the next [`MTIME`] tick at which the next timer expires. If the queue is empty, it returns `None`.
use crate::aclint::mtimer::{MTIME, MTIMECMP, MTIMER};
Expand All @@ -28,13 +29,13 @@ use core::{
};

extern "Rust" {
/// Returns the `MTIMER` register for the given HART ID.
/// Returns the `MTIMER` register for the current HART ID.
/// This is necessary for [`MachineTimer`] to obtain the corresponding `MTIMER` register.
///
/// # Safety
///
/// Do not call this function directly. It is only meant to be called by [`MachineTimer`].
fn _riscv_peripheral_aclint_mtimer(hart_id: usize) -> MTIMER;
fn _riscv_peripheral_aclint_mtimer() -> MTIMER;

/// Tries to push a new timer to the timer queue assigned to the given HART ID.
/// If it fails (e.g., the timer queue is full), it returns back the timer that failed to be pushed.
Expand All @@ -44,15 +45,15 @@ extern "Rust" {
/// Do not call this function directly. It is only meant to be called by [`DelayAsync`].
fn _riscv_peripheral_aclint_push_timer(t: Timer) -> Result<(), Timer>;

/// Pops all the expired timers from the timer queue assigned to the given HART ID and wakes their associated wakers.
/// Pops all the expired timers from the timer queue assigned to the current HART ID and wakes their associated wakers.
/// Once it is done, if the queue is empty, it returns `None`.
/// Alternatively, if the queue is not empty but the earliest timer has not expired yet,
/// it returns `Some(next_expires)` where `next_expires` is the tick at which this timer expires.
///
/// # Safety
///
/// Do not call this function directly. It is only meant to be called by [`MachineTimer`] and [`DelayAsync`].
fn _riscv_peripheral_aclint_wake_timers(hart_id: usize, current_tick: u64) -> Option<u64>;
fn _riscv_peripheral_aclint_wake_timers(current_tick: u64) -> Option<u64>;
}

/// Machine-level timer interrupt handler. This handler is triggered whenever the `MTIME`
Expand All @@ -61,20 +62,17 @@ extern "Rust" {
#[allow(non_snake_case)]
fn MachineTimer() {
// recover the MTIME and MTIMECMP registers for the current HART
let hart_id = riscv::register::mhartid::read();
let mtimer = unsafe { _riscv_peripheral_aclint_mtimer(hart_id) };
let mtimer = unsafe { _riscv_peripheral_aclint_mtimer() };
let (mtime, mtimercmp) = (mtimer.mtime, mtimer.mtimecmp_mhartid());
// schedule the next machine timer interrupt
schedule_machine_timer(hart_id, mtime, mtimercmp);
schedule_machine_timer(mtime, mtimercmp);
}

/// Schedules the next machine timer interrupt for the given HART ID according to the timer queue.
fn schedule_machine_timer(hart_id: usize, mtime: MTIME, mtimercmp: MTIMECMP) {
fn schedule_machine_timer(mtime: MTIME, mtimercmp: MTIMECMP) {
unsafe { riscv::register::mie::clear_mtimer() }; // disable machine timer interrupts to avoid reentrancy
let current_tick = mtime.read();
if let Some(next_expires) =
unsafe { _riscv_peripheral_aclint_wake_timers(hart_id, current_tick) }
{
if let Some(next_expires) = unsafe { _riscv_peripheral_aclint_wake_timers(current_tick) } {
debug_assert!(next_expires > current_tick);
mtimercmp.write(next_expires); // schedule next interrupt at next_expires
unsafe { riscv::register::mie::set_mtimer() }; // enable machine timer interrupts again if necessary
Expand Down Expand Up @@ -102,7 +100,7 @@ impl Delay {
#[inline]
pub fn new(freq: usize) -> Self {
let hart_id = riscv::register::mhartid::read();
let mtimer = unsafe { _riscv_peripheral_aclint_mtimer(hart_id) };
let mtimer = unsafe { _riscv_peripheral_aclint_mtimer() };
let (mtime, mtimecmp) = (mtimer.mtime, mtimer.mtimecmp_mhartid());
Self {
hart_id,
Expand Down Expand Up @@ -275,7 +273,7 @@ impl<'a> Future for DelayAsync<'a> {
_riscv_peripheral_aclint_push_timer(timer).expect("timer queue is full");
};
// we also need to reschedule the machine timer interrupt
schedule_machine_timer(self.delay.hart_id, self.delay.mtime, self.delay.mtimecmp);
schedule_machine_timer(self.delay.mtime, self.delay.mtimecmp);
}
Poll::Pending
} else {
Expand Down
6 changes: 6 additions & 0 deletions riscv-peripheral/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,12 @@ macro_rules! clint_codegen {
$crate::clint_codegen!($($tail)*);
};
(async_delay, $($tail:tt)*) => {

#[no_mangle]
const fn _riscv_peripheral_aclint_mtimer() -> $crate::aclint::mtimer::MTIMER {
CLINT::mtimer()
}

impl CLINT {
/// Asynchronous delay implementation for CLINT peripherals.
///
Expand Down

0 comments on commit f4e29c4

Please sign in to comment.