#![cfg_attr(docsrs, procmacros::doc_replace)]
use core::marker::PhantomData;
use crate::{
interrupt::{self, InterruptConfigurable, InterruptHandler},
peripherals::Interrupt,
private::Sealed,
system::Cpu,
};
#[non_exhaustive]
pub struct SoftwareInterrupt<'d, const NUM: u8> {
_lifetime: PhantomData<&'d mut ()>,
}
impl<'d, const NUM: u8> SoftwareInterrupt<'d, NUM> {
#[inline]
pub const fn new(instance: impl Instance<NUM> + 'd) -> Self {
core::mem::forget(instance); Self {
_lifetime: PhantomData,
}
}
#[instability::unstable]
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
let interrupt;
for_each_sw_interrupt! {
(all $( ($n:literal, $interrupt_name:ident, $f:ident) ),*) => {
interrupt = match NUM {
$($n => Interrupt::$interrupt_name,)*
_ => unreachable!(),
};
};
}
for core in Cpu::other() {
interrupt::disable(core, interrupt);
}
interrupt::bind_handler(interrupt, handler);
}
#[crate::ram]
pub fn raise(&self) {
let regs = cfg_select! {
soc_has_intpri => crate::peripherals::INTPRI::regs(),
_ => crate::peripherals::SYSTEM::regs(),
};
let reg = regs.cpu_intr_from_cpu(NUM as usize);
cfg_select! {
xtensa => {
reg.write(|w| w.cpu_intr().set_bit());
_ = reg.read();
}
_ => {
crate::interrupt::free(|| {
reg.write(|w| w.cpu_intr().set_bit());
while !self.is_pending() {}
});
}
}
}
#[cfg(riscv)]
fn is_pending(&self) -> bool {
let interrupt;
for_each_sw_interrupt! {
(all $( ($n:literal, $interrupt_name:ident, $f:ident) ),*) => {
interrupt = match NUM {
$($n => Interrupt::$interrupt_name,)*
_ => unreachable!(),
};
};
}
crate::interrupt::InterruptStatus::is_pending(interrupt)
}
pub fn reset(&self) {
cfg_select! {
soc_has_intpri => {
let regs = crate::peripherals::INTPRI::regs();
}
_ => {
let regs = crate::peripherals::SYSTEM::regs();
}
}
let reg;
for_each_sw_interrupt! {
(all $( ($n:literal, $i:ident, $f:ident) ),*) => {
reg = match NUM {
$($n => regs.cpu_intr_from_cpu($n),)*
_ => unreachable!(),
};
};
}
reg.write(|w| w.cpu_intr().clear_bit());
}
}
impl<const NUM: u8> crate::private::Sealed for SoftwareInterrupt<'_, NUM> {}
impl<const NUM: u8> InterruptConfigurable for SoftwareInterrupt<'_, NUM> {
fn set_interrupt_handler(&mut self, handler: interrupt::InterruptHandler) {
SoftwareInterrupt::set_interrupt_handler(self, handler);
}
}
pub trait Instance<const NUM: u8>: Sealed {}
for_each_sw_interrupt! {
($n:literal, $i:ident, $field:ident) => {
impl Instance<$n> for crate::peripherals::$i<'_> {}
};
}