use crate::regs;
pub use crate::regs::Interrupt;
cfg_select! {
not(core = "cm0") => {
use regs::NVIC;
pub fn mask(interrupt: Interrupt) {
NVIC::mask(interrupt);
}
pub fn unmask(interrupt: Interrupt) {
unsafe { NVIC::unmask(interrupt) }
}
pub fn set_priority(interrupt: Interrupt, priority: u8) {
unsafe {
regs::CorePeripherals::steal()
.NVIC
.set_priority(interrupt, priority)
}
}
pub fn get_priority(interrupt: Interrupt) -> u8 {
regs::NVIC::get_priority(interrupt)
}
},
all(core = "cm0", not(die = "psoc6_01")) => {
use cortex_m::peripheral::scb::VectActive;
use regs::{AsPtr, Reg, cpuss::Cm0Int0Status_SPEC};
const NUM_HW_INTERRUPTS: u8 = 8;
#[unsafe(link_section = ".vector_table.multiplexed_interrupts")]
#[unsafe(no_mangle)]
#[doc(hidden)]
pub static __MULTIPLEXED_INTERRUPTS: [unsafe extern "C" fn(); 16] = *[
[multiplexed_interrupt_handler as _; NUM_HW_INTERRUPTS as usize],
[DefaultHandler as _; 8],
].as_flattened().as_array().unwrap();
pub fn mask(interrupt: Interrupt) {
critical_section::with(|_cs| {
unsafe { regs::CPUSS.cm0_system_int_ctl()[interrupt as usize].modify(|r| r.cpu_int_valid().set(false)) }
})
}
pub fn unmask(interrupt: Interrupt) {
critical_section::with(|_cs| {
unsafe { regs::CPUSS.cm0_system_int_ctl()[interrupt as usize].modify(|r| r.cpu_int_valid().set(true)) }
})
}
pub fn set_priority(interrupt: Interrupt, priority: u8) {
critical_section::with(|_cs| {
unsafe {
regs::CPUSS.cm0_system_int_ctl()[interrupt as usize].modify(|r| r.cpu_int_idx().set(priority >> 5))
}
})
}
pub fn get_priority(interrupt: Interrupt) -> u8 {
unsafe {
regs::CPUSS.cm0_system_int_ctl()[interrupt as usize].read().cpu_int_idx().get() << 5
}
}
unsafe extern "C" fn multiplexed_interrupt_handler() {
if let VectActive::Interrupt { irqn: n @ 0..NUM_HW_INTERRUPTS } = regs::SCB::vect_active() {
unsafe {
let status_reg = Reg::<Cm0Int0Status_SPEC, regs::R>::from_ptr(regs::CPUSS.cm0_int0_status().as_ptr().byte_add(n as usize * 4));
let status = status_reg.read();
if status.system_int_valid().get() {
let interrupt = status.system_int_idx().get() as usize;
let handler = core::mem::transmute_copy::<regs::Vector, unsafe extern "C" fn()>(®s::__INTERRUPTS[interrupt]);
handler();
}
}
}
}
unsafe extern "C" {
fn DefaultHandler();
}
}
all(core = "cm0", die = "psoc6_01") => {
use cortex_m::peripheral::scb::VectActive;
use regs::AsPtr;
const NUM_HW_INTERRUPTS: u8 = 32;
#[unsafe(link_section = ".vector_table.multiplexed_interrupts")]
#[unsafe(no_mangle)]
#[doc(hidden)]
pub static __MULTIPLEXED_INTERRUPTS: [unsafe extern "C" fn(); NUM_HW_INTERRUPTS as usize] = [multiplexed_interrupt_handler as _; NUM_HW_INTERRUPTS as usize];
static mut INTERRUPT_MAPPING: [u8; regs::__INTERRUPTS.len()] = [0; regs::__INTERRUPTS.len()];
const NO_INTERRUPT: u8 = 240;
pub fn mask(interrupt: Interrupt) {
critical_section::with(|_cs| {
unsafe {
let line = INTERRUPT_MAPPING[interrupt as usize] & 0x1F;
let regs = regs::CPUSS.cm0_int_ctl0().as_ptr().cast::<u32>();
let reg = regs.add(line as usize / 4);
let mut value = reg.read_volatile().to_le_bytes();
if value[line as usize % 4] == interrupt as u8 {
value[line as usize % 4] = NO_INTERRUPT;
reg.write_volatile(u32::from_le_bytes(value));
}
}
})
}
pub fn unmask(interrupt: Interrupt) {
critical_section::with(|_cs| {
unsafe {
let mapping = INTERRUPT_MAPPING[interrupt as usize];
let (priority, line) = (mapping >> 5, mapping & 0x1F);
let regs = regs::CPUSS.cm0_int_ctl0().as_ptr().cast::<u32>();
let reg = regs.add(line as usize / 4);
let value = reg.read_volatile().to_le_bytes();
if value[line as usize % 4] == interrupt as u8 {
return;
}
for reg_offset in 0..(NUM_HW_INTERRUPTS / 4) {
let reg = regs.add(reg_offset as usize);
let mut value = reg.read_volatile().to_le_bytes();
for line in 0..4 {
if value[line] == NO_INTERRUPT {
value[line] = interrupt as u8;
reg.write_volatile(u32::from_le_bytes(value));
regs::CorePeripherals::steal().NVIC.set_priority(HwInterruptNumber(line as u16 + reg_offset as u16 * 4), priority);
INTERRUPT_MAPPING[interrupt as usize] = (priority << 5) | (reg_offset * 4 + line as u8);
return;
}
}
}
panic!("cannot unmask interrupt: no available interrupt lines");
}
})
}
pub fn set_priority(interrupt: Interrupt, priority: u8) {
critical_section::with(|_cs| {
unsafe {
let line = INTERRUPT_MAPPING[interrupt as usize] & 0x1F;
INTERRUPT_MAPPING[interrupt as usize] = (priority << 5) | line;
let reg = regs::CPUSS.cm0_int_ctl0().as_ptr().cast::<u32>().add(line as usize / 4);
let value = reg.read_volatile().to_le_bytes();
if value[line as usize % 4] == interrupt as u8 {
regs::CorePeripherals::steal().NVIC.set_priority(HwInterruptNumber(line as u16), priority);
};
}
});
}
pub fn get_priority(interrupt: Interrupt) -> u8 {
critical_section::with(|_cs| {
unsafe {
INTERRUPT_MAPPING[interrupt as usize] >> 5
}
})
}
#[derive(Clone, Copy)]
struct HwInterruptNumber(u16);
unsafe impl cortex_m::interrupt::InterruptNumber for HwInterruptNumber {
fn number(self) -> u16 {
self.0
}
}
unsafe extern "C" fn multiplexed_interrupt_handler() {
unsafe {
let vect_num = critical_section::with(|_cs| {
if let VectActive::Interrupt { irqn: n @ 0..NUM_HW_INTERRUPTS } = regs::SCB::vect_active() {
let reg = regs::CPUSS.cm0_int_ctl0().as_ptr().cast::<u32>().add(n as usize / 4);
let value = reg.read_volatile().to_le_bytes();
Some(value[n as usize % 4])
} else {
None
}
});
if let Some(interrupt) = vect_num && interrupt != NO_INTERRUPT {
let handler = core::mem::transmute_copy::<regs::Vector, unsafe extern "C" fn()>(®s::__INTERRUPTS[interrupt as usize]);
handler();
}
}
}
}
}
#[unsafe(naked)]
#[unsafe(no_mangle)]
unsafe extern "C" fn __pre_init() {
core::arch::naked_asm!(
#[cfg(all(core = "cm0", not(die = "psoc6_01")))]
"
// Set priorities for multiplexed interrupts
ldr r1, ={NVIC_IPR}
ldr r0, =0x03020100
str r0, [r1]
ldr r0, =0x07060504
str r0, [r1, #4]
// Set priorites for interrupt sources
movs r0, #0
ldr r1, ={CPUSS_CM0_SYSTEM_INT_CTL0}
movs r2, #{NUM_INTERRUPTS}
lsls r2, r2, #2
.Lloop:
subs r2, r2, #4
str r0, [r1, r2]
bne .Lloop
// Enable multiplexed interrupts
movs r0, #0xFF
ldr r1, ={NVIC_ISER}
str r0, [r1]
",
#[cfg(all(core = "cm0", die = "psoc6_01"))]
"
// Enable multiplexed interrupts
movs r0, #0
mvns r0, r0
ldr r1, ={NVIC_ISER}
str r0, [r1]
",
"bx lr",
"/* {NVIC_ISER} {NVIC_IPR} {CPUSS_CM0_SYSTEM_INT_CTL0} {NUM_INTERRUPTS} */",
NVIC_ISER = const 0xE000_E100usize,
NVIC_IPR = const 0xE000_E400usize,
CPUSS_CM0_SYSTEM_INT_CTL0 = const 0x40208000usize,
NUM_INTERRUPTS = const regs::__INTERRUPTS.len()
)
}