arch:riscv32
- Add basic riscv32 executor - Add 16MHZ timer support
This commit is contained in:
		| @@ -47,6 +47,7 @@ time = [] | |||||||
| time-tick-32768hz = ["time"] | time-tick-32768hz = ["time"] | ||||||
| time-tick-1000hz = ["time"] | time-tick-1000hz = ["time"] | ||||||
| time-tick-1mhz = ["time"] | time-tick-1mhz = ["time"] | ||||||
|  | time-tick-16mhz = ["time"] | ||||||
|  |  | ||||||
| executor-agnostic = [] | executor-agnostic = [] | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										74
									
								
								embassy/src/executor/arch/riscv32.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								embassy/src/executor/arch/riscv32.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | |||||||
|  | use core::marker::PhantomData; | ||||||
|  | use core::ptr; | ||||||
|  |  | ||||||
|  | use atomic_polyfill::{AtomicBool, Ordering}; | ||||||
|  |  | ||||||
|  | use super::{raw, Spawner}; | ||||||
|  |  | ||||||
|  | /// global atomic used to keep track of whether there is work to do since sev() is not available on RISCV | ||||||
|  | /// | ||||||
|  | static SIGNAL_WORK_THREAD_MODE: AtomicBool = AtomicBool::new(false); | ||||||
|  |  | ||||||
|  | /// RISCV32 Executor | ||||||
|  | pub struct Executor { | ||||||
|  |     inner: raw::Executor, | ||||||
|  |     not_send: PhantomData<*mut ()>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl Executor { | ||||||
|  |     /// Create a new Executor. | ||||||
|  |     pub fn new() -> Self { | ||||||
|  |         Self { | ||||||
|  |             // use Signal_Work_Thread_Mode as substitute for local interrupt register | ||||||
|  |             inner: raw::Executor::new( | ||||||
|  |                 |_| { | ||||||
|  |                     SIGNAL_WORK_THREAD_MODE.store(true, Ordering::SeqCst); | ||||||
|  |                 }, | ||||||
|  |                 ptr::null_mut(), | ||||||
|  |             ), | ||||||
|  |             not_send: PhantomData, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Run the executor. | ||||||
|  |     /// | ||||||
|  |     /// The `init` closure is called with a [`Spawner`] that spawns tasks on | ||||||
|  |     /// this executor. Use it to spawn the initial task(s). After `init` returns, | ||||||
|  |     /// the executor starts running the tasks. | ||||||
|  |     /// | ||||||
|  |     /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`), | ||||||
|  |     /// for example by passing it as an argument to the initial tasks. | ||||||
|  |     /// | ||||||
|  |     /// This function requires `&'static mut self`. This means you have to store the | ||||||
|  |     /// Executor instance in a place where it'll live forever and grants you mutable | ||||||
|  |     /// access. There's a few ways to do this: | ||||||
|  |     /// | ||||||
|  |     /// - a [Forever](crate::util::Forever) (safe) | ||||||
|  |     /// - a `static mut` (unsafe) | ||||||
|  |     /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe) | ||||||
|  |     /// | ||||||
|  |     /// This function never returns. | ||||||
|  |     pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { | ||||||
|  |         init(self.inner.spawner()); | ||||||
|  |  | ||||||
|  |         loop { | ||||||
|  |             unsafe { | ||||||
|  |                 self.inner.poll(); | ||||||
|  |                 // we do not care about race conditions between the load and store operations, interrupts | ||||||
|  |                 //will only set this value to true. | ||||||
|  |                 critical_section::with(|_| { | ||||||
|  |                     // if there is work to do, loop back to polling | ||||||
|  |                     // TODO can we relax this? | ||||||
|  |                     if SIGNAL_WORK_THREAD_MODE.load(Ordering::SeqCst) { | ||||||
|  |                         SIGNAL_WORK_THREAD_MODE.store(false, Ordering::SeqCst); | ||||||
|  |                     } | ||||||
|  |                     // if not, wait for interrupt | ||||||
|  |                     else { | ||||||
|  |                         core::arch::asm!("wfi"); | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  |                 // if an interrupt occurred while waiting, it will be serviced here | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -18,6 +18,11 @@ cfg_if::cfg_if! { | |||||||
|         mod arch; |         mod arch; | ||||||
|         pub use arch::*; |         pub use arch::*; | ||||||
|     } |     } | ||||||
|  |     else if #[cfg(target_arch="riscv32")] { | ||||||
|  |         #[path="arch/riscv32.rs"] | ||||||
|  |         mod arch; | ||||||
|  |         pub use arch::*; | ||||||
|  |     } | ||||||
|     else if #[cfg(feature="wasm")] { |     else if #[cfg(feature="wasm")] { | ||||||
|         #[path="arch/wasm.rs"] |         #[path="arch/wasm.rs"] | ||||||
|         mod arch; |         mod arch; | ||||||
|   | |||||||
| @@ -68,6 +68,9 @@ const TPS: u64 = 32_768; | |||||||
| #[cfg(feature = "time-tick-1mhz")] | #[cfg(feature = "time-tick-1mhz")] | ||||||
| const TPS: u64 = 1_000_000; | const TPS: u64 = 1_000_000; | ||||||
|  |  | ||||||
|  | #[cfg(feature = "time-tick-16mhz")] | ||||||
|  | const TPS: u64 = 16_000_000; | ||||||
|  |  | ||||||
| /// Ticks per second of the global timebase. | /// Ticks per second of the global timebase. | ||||||
| /// | /// | ||||||
| /// This value is specified by the `time-tick-*` Cargo features, which | /// This value is specified by the `time-tick-*` Cargo features, which | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user