use core::arch::asm;
#[inline]
pub fn disable() -> u32 {
unsafe { set_mask(0) }
}
#[inline]
pub unsafe fn enable() -> u32 {
unsafe { set_mask(!0) }
}
#[inline]
pub unsafe fn set_mask(mut mask: u32) -> u32 {
unsafe {
asm!("
xsr {0}, intenable
rsync
",
inout(reg) mask, options(nostack)
);
mask
}
}
#[inline]
pub fn disable_mask(mask: u32) -> u32 {
let mut prev: u32 = 0;
let _dummy: u32;
unsafe {
asm!("
xsr.intenable {0} // get mask and temporarily disable interrupts
and {1}, {1}, {0}
rsync
wsr.intenable {1}
rsync
", inout(reg) prev, inout(reg) !mask => _dummy, options(nostack)
);
}
prev
}
#[inline]
pub unsafe fn enable_mask(mask: u32) -> u32 {
unsafe {
let mut prev: u32 = 0;
let _dummy: u32;
asm!("
xsr.intenable {0} // get mask and temporarily disable interrupts
or {1}, {1}, {0}
rsync
wsr.intenable {1}
rsync
", inout(reg) prev, inout(reg) mask => _dummy, options(nostack));
prev
}
}
#[inline]
pub fn get_mask() -> u32 {
let mask: u32;
unsafe { asm!("rsr.intenable {0}", out(reg) mask) };
mask
}
#[inline]
pub fn get() -> u32 {
let mask: u32;
unsafe {
asm!("rsr.interrupt {0}", out(reg) mask, options(nostack));
}
mask
}
#[inline]
pub unsafe fn set(mask: u32) {
unsafe {
asm!("
wsr.intset {0}
rsync
",
in(reg) mask, options(nostack)
);
}
}
#[inline]
pub unsafe fn clear(mask: u32) {
unsafe {
asm!("
wsr.intclear {0}
rsync
",
in(reg) mask, options(nostack)
);
}
}
#[inline]
pub fn get_level() -> u32 {
let ps: u32;
unsafe {
asm!("rsr.ps {0}", out(reg) ps, options(nostack));
};
ps & 0xf
}
#[inline]
pub fn free<F, R>(f: F) -> R
where
F: FnOnce() -> R,
{
let old_mask = disable();
let r = f();
unsafe { set_mask(old_mask) };
r
}