use core::sync::atomic::{Ordering, compiler_fence};
use crate::RestoreState;
pub trait RawLock {
unsafe fn enter(&self) -> RestoreState;
unsafe fn exit(&self, token: RestoreState);
}
pub struct SingleCoreInterruptLock;
#[cfg(all(xtensa, debug_assertions))]
const RESERVED_MASK: u32 = 0b1111_1111_1111_1000_1111_0000_0000_0000;
impl RawLock for SingleCoreInterruptLock {
#[inline]
unsafe fn enter(&self) -> RestoreState {
cfg_select! {
esp32p4 => {
let old_mintthresh: u32;
unsafe {
core::arch::asm!(
"li t0, 0xff",
"csrrw {0}, 0x347, t0",
out(reg) old_mintthresh,
out("t0") _,
);
}
let mut mstatus = 0u32;
unsafe {
core::arch::asm!("csrrci {0}, mstatus, 8", inout(reg) mstatus);
}
let mie_bit = mstatus & 0b1000;
let token = mie_bit | ((old_mintthresh & 0xff) << 8);
}
riscv => {
let mut mstatus = 0u32;
unsafe {
core::arch::asm!("csrrci {0}, mstatus, 8", inout(reg) mstatus);
}
let token = mstatus & 0b1000;
}
xtensa => {
let token: u32;
unsafe {
core::arch::asm!("rsil {0}, 5", out(reg) token);
}
#[cfg(debug_assertions)]
let token = token & !RESERVED_MASK;
}
_ => {
compile_error!("Unsupported architecture")
}
};
compiler_fence(Ordering::SeqCst);
unsafe { RestoreState::new(token) }
}
#[inline]
unsafe fn exit(&self, token: RestoreState) {
compiler_fence(Ordering::SeqCst);
let token = token.inner();
cfg_select! {
esp32p4 => {
if (token & 0b1000) != 0 {
unsafe {
riscv::interrupt::enable();
}
}
let old_mintthresh = (token >> 8) & 0xff;
unsafe {
core::arch::asm!(
"csrw 0x347, {0}",
in(reg) old_mintthresh,
);
}
riscv::asm::nop();
riscv::asm::nop();
riscv::asm::nop();
}
riscv => {
if token != 0 {
unsafe {
riscv::interrupt::enable();
}
}
}
xtensa => {
#[cfg(debug_assertions)]
if token & RESERVED_MASK != 0 {
#[cold]
#[inline(never)]
fn __assert_failed() {
panic!("Reserved bits in PS register must be written as 0");
}
__assert_failed();
}
unsafe {
core::arch::asm!(
"wsr.ps {0}",
"rsync", in(reg) token)
}
}
_ => {
compile_error!("Unsupported architecture")
}
}
}
}