use core::marker::PhantomData;
use embassy_executor::{raw, Spawner};
use portable_atomic::{AtomicBool, Ordering};
use crate::{get_core, prelude::interrupt};
#[cfg(multi_core)]
use crate::{
interrupt,
peripherals::{self, SYSTEM},
};
#[cfg(not(multi_core))]
static SIGNAL_WORK_THREAD_MODE: [AtomicBool; 1] = [AtomicBool::new(false)];
#[cfg(multi_core)]
static SIGNAL_WORK_THREAD_MODE: [AtomicBool; 2] = [AtomicBool::new(false), AtomicBool::new(false)];
#[interrupt]
fn FROM_CPU_INTR0() {
#[cfg(multi_core)]
{
let system = unsafe { &*SYSTEM::PTR };
system
.cpu_intr_from_cpu_0()
.write(|w| w.cpu_intr_from_cpu_0().bit(false));
}
}
pub(crate) fn pend_thread_mode(core: usize) {
SIGNAL_WORK_THREAD_MODE[core].store(true, Ordering::SeqCst);
#[cfg(multi_core)]
if core != crate::get_core() as usize {
let system = unsafe { &*SYSTEM::PTR };
system
.cpu_intr_from_cpu_0()
.write(|w| w.cpu_intr_from_cpu_0().bit(true));
}
}
pub struct Executor {
inner: raw::Executor,
not_send: PhantomData<*mut ()>,
}
impl Executor {
pub fn new() -> Self {
#[cfg(multi_core)]
unwrap!(interrupt::enable(
peripherals::Interrupt::FROM_CPU_INTR0,
interrupt::Priority::Priority1,
));
Self {
inner: raw::Executor::new(usize::from_le_bytes([0, get_core() as u8, 0, 0]) as *mut ()),
not_send: PhantomData,
}
}
pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
init(self.inner.spawner());
let cpu = get_core() as usize;
loop {
unsafe {
self.inner.poll();
Self::wait_impl(cpu);
}
}
}
#[cfg(xtensa)]
pub fn wait_impl(cpu: usize) {
let token: critical_section::RawRestoreState;
unsafe { core::arch::asm!("rsil {0}, 5", out(reg) token) };
if SIGNAL_WORK_THREAD_MODE[cpu].load(Ordering::SeqCst) {
SIGNAL_WORK_THREAD_MODE[cpu].store(false, Ordering::SeqCst);
unsafe {
core::arch::asm!(
"wsr.ps {0}",
"rsync",
in(reg) token
);
}
} else {
unsafe { core::arch::asm!("waiti 0") }; }
}
#[cfg(riscv)]
pub fn wait_impl(cpu: usize) {
critical_section::with(|_| {
if SIGNAL_WORK_THREAD_MODE[cpu].load(Ordering::SeqCst) {
SIGNAL_WORK_THREAD_MODE[cpu].store(false, Ordering::SeqCst);
}
else {
unsafe { core::arch::asm!("wfi") };
}
});
}
}