diff --git a/Cargo.lock b/Cargo.lock index fba27de..0d4047f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,7 +21,7 @@ dependencies = [ ] [[package]] -name = "async-cortex-m" +name = "async-embedded" version = "0.0.0-alpha.0" dependencies = [ "cortex-m", @@ -29,6 +29,7 @@ dependencies = [ "generic-array 0.13.2", "heapless 0.5.3 (git+https://github.com/japaric/heapless?branch=slab)", "pin-utils", + "riscv", "typenum", ] @@ -40,13 +41,19 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" [[package]] name = "bare-metal" -version = "0.2.5" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +checksum = "a3caf393d93b2d453e80638d0674597020cef3382ada454faacd43d1a55a735a" dependencies = [ "rustc_version", ] +[[package]] +name = "bit_field" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" + [[package]] name = "byteorder" version = "1.3.4" @@ -160,7 +167,7 @@ dependencies = [ name = "nrf52" version = "0.0.0-alpha.0" dependencies = [ - "async-cortex-m", + "async-embedded", "chrono", "cortex-m", "cortex-m-rt", @@ -250,6 +257,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" +[[package]] +name = "riscv" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a12a859c86dbbcad4eb18daa0465932d907687abfa909c9cc0ca32dc237c8c3" +dependencies = [ + "bare-metal", + "bit_field", +] + [[package]] name = "rustc_version" version = "0.2.3" diff --git a/Cargo.toml b/Cargo.toml index eb4e3c1..24156f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] members = [ - "async-cortex-m", + "async-embedded", "cortex-m-udf", "nrf52", "panic-udf", diff --git a/async-cortex-m/src/lib.rs b/async-cortex-m/src/lib.rs deleted file mode 100644 index c2bb138..0000000 --- a/async-cortex-m/src/lib.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! Proof of Concept async runtime for the Cortex-M architecture - -#![deny(missing_docs)] -#![deny(rust_2018_idioms)] -#![deny(warnings)] -#![no_std] - -mod alloc; -mod executor; -pub mod task; -pub mod unsync; - -use cortex_m_udf::udf as abort; - -/// Maximum number of tasks (TODO this could be user configurable) -type NTASKS = typenum::consts::U8; diff --git a/async-cortex-m/Cargo.toml b/async-embedded/Cargo.toml similarity index 57% rename from async-cortex-m/Cargo.toml rename to async-embedded/Cargo.toml index ed71d82..69e927f 100644 --- a/async-cortex-m/Cargo.toml +++ b/async-embedded/Cargo.toml @@ -2,14 +2,25 @@ authors = ["Jorge Aparicio "] edition = "2018" license = "MIT OR Apache-2.0" -name = "async-cortex-m" +name = "async-embedded" publish = false version = "0.0.0-alpha.0" [dependencies] -cortex-m = "0.6.2" -cortex-m-udf = { path = "../cortex-m-udf" } generic-array = "0.13.2" heapless = { git = "https://github.com/japaric/heapless", branch = "slab" } pin-utils = "0.1.0-alpha.4" typenum = "1.11.2" + +[target.'cfg(target_arch = "arm")'.dependencies] +cortex-m = "0.6.2" +cortex-m-udf = { path = "../cortex-m-udf" } + +[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies] +riscv = "0.5.6" + +[features] +default = ["riscv-wait-nop"] +riscv-wait-nop = [] +riscv-wait-wfi-single-hart = [] +riscv-wait-extern = [] diff --git a/async-cortex-m/src/alloc.rs b/async-embedded/src/alloc.rs similarity index 100% rename from async-cortex-m/src/alloc.rs rename to async-embedded/src/alloc.rs diff --git a/async-cortex-m/src/executor.rs b/async-embedded/src/executor.rs similarity index 99% rename from async-cortex-m/src/executor.rs rename to async-embedded/src/executor.rs index 752dab6..f05278d 100644 --- a/async-cortex-m/src/executor.rs +++ b/async-embedded/src/executor.rs @@ -7,7 +7,6 @@ use core::{ task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, }; -use cortex_m::asm; use heapless::Vec; use pin_utils::pin_mut; @@ -120,7 +119,7 @@ impl Executor { // try to sleep; this will be a no-op if any of the previous tasks generated a SEV or an // interrupt ran (regardless of whether it generated a wake-up or not) - asm::wfe(); + unsafe { crate::wait_for_event() }; }; self.in_block_on.set(false); val diff --git a/async-embedded/src/lib.rs b/async-embedded/src/lib.rs new file mode 100644 index 0000000..6c9f83e --- /dev/null +++ b/async-embedded/src/lib.rs @@ -0,0 +1,102 @@ +//! Proof of Concept async runtime for the Cortex-M architecture + +#![deny(missing_docs)] +#![deny(rust_2018_idioms)] +#![deny(warnings)] +#![no_std] + +mod alloc; +mod executor; +pub mod task; +pub mod unsync; + +#[cfg(target_arch = "arm")] +use cortex_m::asm; + + +#[cfg(target_arch = "arm")] +pub use cortex_m_udf::udf as abort; + +#[cfg(target_arch = "arm")] +#[inline] +/// Prevent next `wait_for_interrupt` from sleeping, wake up other harts if needed. +/// This particular implementation does nothing, since `wait_for_interrupt` never sleeps +pub(crate) unsafe fn signal_event_ready() { + asm::sev(); +} + +#[cfg(target_arch = "arm")] +#[inline] +/// Wait for an interrupt or until notified by other hart via `signal_task_ready` +/// This particular implementation does nothing +pub(crate) unsafe fn wait_for_event() { + asm::wfe(); +} + +#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] +/// This keeps dropping into the debugger and never returns +pub fn abort() -> ! { + loop { + unsafe { riscv::asm::ebreak() } + } +} + +#[cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), feature = "riscv-wait-nop"))] +#[inline] +/// Prevent next `wait_for_interrupt` from sleeping, wake up other harts if needed. +/// This particular implementation does nothing, since `wait_for_interrupt` never sleeps +pub(crate) unsafe fn signal_event_ready() {} + +#[cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), feature = "riscv-wait-nop"))] +#[inline] +/// Wait for an interrupt or until notified by other hart via `signal_task_ready` +/// This particular implementation does nothing +pub(crate) unsafe fn wait_for_event() {} + +#[cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), feature = "riscv-wait-extern"))] +extern "C" { + /// Prevent next `wait_for_interrupt` from sleeping, wake up other harts if needed. + /// User is expected to provide an actual implementation, like the one shown below. + /// + /// #[no_mangle] + /// pub extern "C" fn signal_event_ready() { + /// unimplemented!(); + /// } + pub(crate) fn signal_event_ready(); + + /// Wait for an interrupt or until notified by other hart via `signal_task_ready` + /// User is expected to provide an actual implementation, like the one shown below. + /// + /// #[no_mangle] + /// pub extern "C" fn wait_for_event() { + /// unimplemented!(); + /// } + pub(crate) fn wait_for_event(); +} + +#[cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), feature = "riscv-wait-wfi-single-hart"))] +static mut TASK_READY: bool = false; + +#[cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), feature = "riscv-wait-wfi-single-hart"))] +#[inline] +/// Prevent next `wait_for_interrupt` from sleeping, wake up other harts if needed. +/// This particular implementation prevents `wait_for_interrupt` from sleeping by setting +/// a global mutable flag +pub(crate) unsafe fn signal_event_ready() { + TASK_READY = true; +} + +#[cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), feature = "riscv-wait-wfi-single-hart"))] +#[inline] +/// Wait for an interrupt or until notified by other hart via `signal_task_ready` +/// This particular implementation decides whether to sleep or not by checking +/// a global mutable flag that's set by `signal_task_ready` +pub(crate) unsafe fn wait_for_event() { + if !TASK_READY { + riscv::asm::wfi(); + } + TASK_READY = false; +} + +/// Maximum number of tasks (TODO this could be user configurable) +type NTASKS = typenum::consts::U8; diff --git a/async-cortex-m/src/task.rs b/async-embedded/src/task.rs similarity index 95% rename from async-cortex-m/src/task.rs rename to async-embedded/src/task.rs index 1729677..253af78 100644 --- a/async-cortex-m/src/task.rs +++ b/async-embedded/src/task.rs @@ -6,8 +6,6 @@ use core::{ task::{Context, Poll}, }; -use cortex_m::asm; - use crate::executor; /// Drives the future `f` to completion @@ -43,7 +41,7 @@ pub async fn r#yield() { self.yielded = true; // wake ourselves cx.waker().wake_by_ref(); - asm::sev(); + unsafe { crate::signal_event_ready(); } Poll::Pending } } diff --git a/async-cortex-m/src/unsync.rs b/async-embedded/src/unsync.rs similarity index 100% rename from async-cortex-m/src/unsync.rs rename to async-embedded/src/unsync.rs diff --git a/async-cortex-m/src/unsync/channel.rs b/async-embedded/src/unsync/channel.rs similarity index 98% rename from async-cortex-m/src/unsync/channel.rs rename to async-embedded/src/unsync/channel.rs index 0463fe3..12ffda1 100644 --- a/async-cortex-m/src/unsync/channel.rs +++ b/async-embedded/src/unsync/channel.rs @@ -12,7 +12,6 @@ use core::{ task::{Context, Poll}, }; -use cortex_m::asm; use generic_array::{typenum::Unsigned, GenericArray}; use super::waker_set::WakerSet; @@ -137,7 +136,7 @@ impl Channel { self.read.set(read.wrapping_add(1)); // notify a sender self.send_wakers.notify_one(); - asm::sev(); + crate::signal_event_ready(); Some(val) } else { // empty @@ -162,7 +161,7 @@ impl Channel { self.write.set(write.wrapping_add(1)); // notify a receiver self.recv_wakers.notify_one(); - asm::sev(); + crate::signal_event_ready(); Ok(()) } else { // full diff --git a/async-cortex-m/src/unsync/mutex.rs b/async-embedded/src/unsync/mutex.rs similarity index 98% rename from async-cortex-m/src/unsync/mutex.rs rename to async-embedded/src/unsync/mutex.rs index 8224070..85a74f6 100644 --- a/async-cortex-m/src/unsync/mutex.rs +++ b/async-embedded/src/unsync/mutex.rs @@ -8,8 +8,6 @@ use core::{ task::{Context, Poll}, }; -use cortex_m::asm; - use super::waker_set::WakerSet; /// A mutual exclusion primitive for protecting shared data @@ -94,7 +92,7 @@ impl Drop for MutexGuard<'_, T> { fn drop(&mut self) { self.0.locked.set(false); self.0.wakers.notify_any(); - asm::sev(); + unsafe { crate::signal_event_ready(); } } } diff --git a/async-cortex-m/src/unsync/waker_set.rs b/async-embedded/src/unsync/waker_set.rs similarity index 100% rename from async-cortex-m/src/unsync/waker_set.rs rename to async-embedded/src/unsync/waker_set.rs diff --git a/nrf52/Cargo.toml b/nrf52/Cargo.toml index 5ffc232..8fbf7ae 100644 --- a/nrf52/Cargo.toml +++ b/nrf52/Cargo.toml @@ -15,7 +15,7 @@ panic-semihosting = "0.5.3" panic-udf = { path = "../panic-udf" } [dependencies] -async-cortex-m = { path = "../async-cortex-m" } +async-embedded = { path = "../async-embedded" } cortex-m = "0.6.2" cortex-m-rt = "0.6.12" pac = { package = "nrf52840-pac", version = "0.9.0", features = ["rt"] } diff --git a/nrf52/examples/1-yield.rs b/nrf52/examples/1-yield.rs index e546589..b953ccf 100644 --- a/nrf52/examples/1-yield.rs +++ b/nrf52/examples/1-yield.rs @@ -15,7 +15,7 @@ #![no_main] #![no_std] -use async_cortex_m::task; +use async_embedded::task; use cortex_m::asm; use cortex_m_rt::entry; use cortex_m_semihosting::hprintln; diff --git a/nrf52/examples/2-share.rs b/nrf52/examples/2-share.rs index 78afaa4..1607330 100644 --- a/nrf52/examples/2-share.rs +++ b/nrf52/examples/2-share.rs @@ -17,7 +17,7 @@ use core::cell::{Cell, RefCell}; -use async_cortex_m::task; +use async_embedded::task; use cortex_m::asm; use cortex_m_rt::entry; use cortex_m_semihosting::hprintln; diff --git a/nrf52/examples/3-mutex.rs b/nrf52/examples/3-mutex.rs index ea712ad..6b5c808 100644 --- a/nrf52/examples/3-mutex.rs +++ b/nrf52/examples/3-mutex.rs @@ -28,7 +28,7 @@ #![no_main] #![no_std] -use async_cortex_m::{task, unsync::Mutex}; +use async_embedded::{task, unsync::Mutex}; use cortex_m::asm; use cortex_m_rt::entry; use cortex_m_semihosting::hprintln; diff --git a/nrf52/examples/4-channel.rs b/nrf52/examples/4-channel.rs index acac752..7e787aa 100644 --- a/nrf52/examples/4-channel.rs +++ b/nrf52/examples/4-channel.rs @@ -16,7 +16,7 @@ #![no_main] #![no_std] -use async_cortex_m::{task, unsync::Channel}; +use async_embedded::{task, unsync::Channel}; use cortex_m::asm; use cortex_m_rt::entry; use cortex_m_semihosting::hprintln; diff --git a/nrf52/examples/5-heartbeat.rs b/nrf52/examples/5-heartbeat.rs index 85ced48..e8224bd 100644 --- a/nrf52/examples/5-heartbeat.rs +++ b/nrf52/examples/5-heartbeat.rs @@ -17,7 +17,7 @@ use core::time::Duration; -use async_cortex_m::task; +use async_embedded::task; use cortex_m_rt::entry; use nrf52::{led::Red, timer::Timer}; use panic_udf as _; // panic handler diff --git a/nrf52/examples/6-hello.rs b/nrf52/examples/6-hello.rs index 0aaf53e..eb1e13c 100644 --- a/nrf52/examples/6-hello.rs +++ b/nrf52/examples/6-hello.rs @@ -10,7 +10,7 @@ use core::time::Duration; -use async_cortex_m::task; +use async_embedded::task; use cortex_m_rt::entry; use nrf52::{led::Red, serial, timer::Timer}; use panic_udf as _; // panic handler diff --git a/nrf52/examples/7-echo.rs b/nrf52/examples/7-echo.rs index dbcb7b4..fd83655 100644 --- a/nrf52/examples/7-echo.rs +++ b/nrf52/examples/7-echo.rs @@ -10,7 +10,7 @@ use core::time::Duration; -use async_cortex_m::task; +use async_embedded::task; use cortex_m_rt::entry; use nrf52::{led::Red, serial, timer::Timer}; use panic_udf as _; // panic handler diff --git a/nrf52/examples/8-sensor.rs b/nrf52/examples/8-sensor.rs index aaca911..62a7cd9 100644 --- a/nrf52/examples/8-sensor.rs +++ b/nrf52/examples/8-sensor.rs @@ -7,7 +7,7 @@ use core::{cell::Cell, fmt::Write as _, time::Duration}; -use async_cortex_m::{task, unsync::Mutex}; +use async_embedded::{task, unsync::Mutex}; use cortex_m_rt::entry; use heapless::{consts, String}; use nrf52::{led::Red, scd30::Scd30, serial, timer::Timer, twim::Twim}; diff --git a/nrf52/examples/9-clock.rs b/nrf52/examples/9-clock.rs index 002d597..b3f95ad 100644 --- a/nrf52/examples/9-clock.rs +++ b/nrf52/examples/9-clock.rs @@ -31,7 +31,7 @@ use core::{ time::Duration, }; -use async_cortex_m::{task, unsync::Mutex}; +use async_embedded::{task, unsync::Mutex}; use chrono::{Datelike as _, NaiveDate, NaiveTime}; use cortex_m_rt::entry; use heapless::{consts, String, Vec}; diff --git a/nrf52/src/ds3231.rs b/nrf52/src/ds3231.rs index d7dcf84..72c4ab1 100644 --- a/nrf52/src/ds3231.rs +++ b/nrf52/src/ds3231.rs @@ -2,7 +2,7 @@ // Reference: DS3231 datasheet (19-5170; Rev 10; 3/15) -use async_cortex_m::unsync::Mutex; +use async_embedded::unsync::Mutex; use chrono::{Datelike as _, NaiveDate, NaiveDateTime, NaiveTime, Timelike as _}; use crate::twim::{self, Twim}; diff --git a/nrf52/src/scd30.rs b/nrf52/src/scd30.rs index d0eda55..96685a9 100644 --- a/nrf52/src/scd30.rs +++ b/nrf52/src/scd30.rs @@ -3,7 +3,7 @@ // Reference: Interface Description Sensirion SCD30 Sensor Module (Version // 0.94–D1 –June 2019) -use async_cortex_m::unsync::Mutex; +use async_embedded::unsync::Mutex; use crate::twim::{self, Twim};