#![cfg_attr(feature = "std", allow(unreachable_code, unused_variables))]
use crate::reg::{
field::{RegFieldBit, RegFieldBits, WWRegField, WWRegFieldBit, WWRegFieldBits},
tag::RegAtomic,
RReg, Reg, RegHold, RegRef, WReg, WRegAtomic,
};
use drone_core::bitfield::Bitfield;
pub trait RwRegAtomic<'a, T: RegAtomic>: RReg<T> + WRegAtomic<'a, T> + RegRef<'a, T> {
fn modify<F>(&'a self, f: F)
where
F: for<'b> Fn(
&'b mut <Self as RegRef<'a, T>>::Hold,
) -> &'b mut <Self as RegRef<'a, T>>::Hold;
fn modify_reg<F>(&'a self, f: F)
where
F: for<'b> Fn(&'b Self, &'b mut Self::Val);
}
pub trait WRwRegFieldAtomic<T: RegAtomic>
where
Self: WWRegField<T>,
Self::Reg: RReg<T> + WReg<T>,
{
fn modify<F>(&self, f: F)
where
F: Fn(&mut <Self::Reg as Reg<T>>::Val);
}
pub trait WRwRegFieldBitAtomic<T: RegAtomic>
where
Self: WRwRegFieldAtomic<T> + RegFieldBit<T>,
Self::Reg: RReg<T> + WReg<T>,
{
fn set_bit(&self);
fn clear_bit(&self);
fn toggle_bit(&self);
}
pub trait WRwRegFieldBitsAtomic<T: RegAtomic>
where
Self: WRwRegFieldAtomic<T> + RegFieldBits<T>,
Self::Reg: RReg<T> + WReg<T>,
{
fn write_bits(&self, bits: <<Self::Reg as Reg<T>>::Val as Bitfield>::Bits);
}
pub trait AtomicBits: Sized {
unsafe fn load_excl(address: usize) -> Self;
unsafe fn store_excl(self, address: usize) -> bool;
}
impl<'a, T, R> RwRegAtomic<'a, T> for R
where
T: RegAtomic,
R: RReg<T> + WRegAtomic<'a, T> + RegRef<'a, T>,
<R::Val as Bitfield>::Bits: AtomicBits,
{
#[inline]
fn modify<F>(&'a self, f: F)
where
F: for<'b> Fn(
&'b mut <Self as RegRef<'a, T>>::Hold,
) -> &'b mut <Self as RegRef<'a, T>>::Hold,
{
loop {
let mut val = unsafe { self.hold(load_excl::<T, Self>()) };
f(&mut val);
if unsafe { store_excl::<T, Self>(val.val()) } {
break;
}
}
}
#[inline]
fn modify_reg<F>(&'a self, f: F)
where
F: for<'b> Fn(&'b Self, &'b mut Self::Val),
{
loop {
let mut val = unsafe { load_excl::<T, Self>() };
f(self, &mut val);
if unsafe { store_excl::<T, Self>(val) } {
break;
}
}
}
}
impl<T, R> WRwRegFieldAtomic<T> for R
where
T: RegAtomic,
R: WWRegField<T>,
R::Reg: RReg<T> + WReg<T>,
<<R::Reg as Reg<T>>::Val as Bitfield>::Bits: AtomicBits,
{
#[inline]
fn modify<F>(&self, f: F)
where
F: Fn(&mut <Self::Reg as Reg<T>>::Val),
{
loop {
let mut val = unsafe { load_excl::<T, Self::Reg>() };
f(&mut val);
if unsafe { store_excl::<T, Self::Reg>(val) } {
break;
}
}
}
}
impl<T, R> WRwRegFieldBitAtomic<T> for R
where
T: RegAtomic,
R: WRwRegFieldAtomic<T> + RegFieldBit<T>,
R::Reg: RReg<T> + WReg<T>,
{
#[inline]
fn set_bit(&self) {
self.modify(|val| {
self.set(val);
});
}
#[inline]
fn clear_bit(&self) {
self.modify(|val| {
self.clear(val);
});
}
#[inline]
fn toggle_bit(&self) {
self.modify(|val| {
self.toggle(val);
});
}
}
impl<T, R> WRwRegFieldBitsAtomic<T> for R
where
T: RegAtomic,
R: WRwRegFieldAtomic<T> + RegFieldBits<T>,
R::Reg: RReg<T> + WReg<T>,
{
#[inline]
fn write_bits(&self, bits: <<Self::Reg as Reg<T>>::Val as Bitfield>::Bits) {
self.modify(|val| {
self.write(val, bits);
});
}
}
unsafe fn load_excl<T, R>() -> R::Val
where
T: RegAtomic,
R: Reg<T>,
<R::Val as Bitfield>::Bits: AtomicBits,
{
R::val_from(<R::Val as Bitfield>::Bits::load_excl(R::ADDRESS))
}
unsafe fn store_excl<T, R>(val: R::Val) -> bool
where
T: RegAtomic,
R: Reg<T>,
<R::Val as Bitfield>::Bits: AtomicBits,
{
val.bits().store_excl(R::ADDRESS)
}
macro_rules! atomic_bits {
($type:ty, $ldrex:expr, $strex:expr) => {
impl AtomicBits for $type {
unsafe fn load_excl(address: usize) -> Self {
#[cfg(feature = "std")]
return unimplemented!();
let raw: Self;
llvm_asm!($ldrex
: "=r"(raw)
: "r"(address)
:
: "volatile"
);
raw
}
unsafe fn store_excl(self, address: usize) -> bool {
#[cfg(feature = "std")]
return unimplemented!();
let status: Self;
llvm_asm!($strex
: "=r"(status)
: "r"(self), "r"(address)
:
: "volatile"
);
status == 0
}
}
};
}
atomic_bits!(u32, "ldrex $0, [$1]", "strex $0, $1, [$2]");
atomic_bits!(u16, "ldrexh $0, [$1]", "strexh $0, $1, [$2]");
atomic_bits!(u8, "ldrexb $0, [$1]", "strexb $0, $1, [$2]");