use core::marker::PhantomData;
use core::ptr;
use crate::access::{Readable, Writeable};
pub struct Register<T: Copy, Access> {
ptr: *mut T,
_access: PhantomData<Access>,
}
unsafe impl<T: Copy + Send, Access: Send> Send for Register<T, Access> {}
unsafe impl<T: Copy + Sync, Access: Sync> Sync for Register<T, Access> {}
impl<T: Copy, Access> Register<T, Access> {
pub const fn new(addr: usize) -> Self {
Self {
ptr: addr as *mut T,
_access: PhantomData,
}
}
pub const fn uninit() -> Self {
Self {
ptr: ptr::null_mut(),
_access: PhantomData,
}
}
pub fn set_address(&mut self, addr: usize) {
self.ptr = addr as *mut T;
}
pub fn address(&self) -> usize {
self.ptr as usize
}
pub fn is_valid(&self) -> bool {
!self.ptr.is_null()
}
}
impl<T: Copy, Access: Readable> Register<T, Access> {
#[inline(always)]
pub fn read(&self) -> T {
unsafe { ptr::read_volatile(self.ptr) }
}
}
impl<T: Copy, Access: Writeable> Register<T, Access> {
#[inline(always)]
pub fn write(&self, value: T) {
unsafe { ptr::write_volatile(self.ptr, value) }
}
}
impl<T, Access> Register<T, Access>
where
T: Copy
+ core::ops::BitAnd<Output = T>
+ core::ops::Shr<u32, Output = T>,
Access: Readable,
{
#[inline(always)]
pub fn read_field(&self, mask: T, shift: u32) -> T {
(self.read() >> shift) & mask
}
#[inline(always)]
pub fn get_bit(&self, pos: u32) -> bool
where
T: core::ops::Shl<u32, Output = T> + From<u8> + PartialEq,
{
let mask = T::from(1u8) << pos;
(self.read() & mask) != T::from(0u8)
}
}
impl<T, Access> Register<T, Access>
where
T: Copy
+ core::ops::BitOr<Output = T>
+ core::ops::BitAnd<Output = T>
+ core::ops::Not<Output = T>
+ core::ops::BitXor<Output = T>
+ core::ops::Shl<u32, Output = T>
+ From<u8>,
Access: Readable + Writeable,
{
#[inline(always)]
pub fn modify<F: FnOnce(T) -> T>(&self, f: F) {
let val = self.read();
self.write(f(val));
}
#[inline(always)]
pub fn set_bit(&self, pos: u32) {
self.modify(|v| v | (T::from(1u8) << pos));
}
#[inline(always)]
pub fn clear_bit(&self, pos: u32) {
self.modify(|v| v & !(T::from(1u8) << pos));
}
#[inline(always)]
pub fn set_bits(&self, mask: T) {
self.modify(|v| v | mask);
}
#[inline(always)]
pub fn and_bits(&self, mask: T) {
self.modify(|v| v & mask);
}
#[inline(always)]
pub fn toggle_bits(&self, mask: T) {
self.modify(|v| v ^ mask);
}
#[inline(always)]
pub fn write_field(&self, mask: T, shift: u32, value: T) {
self.modify(|v| (v & !(mask << shift)) | ((value & mask) << shift));
}
}