use crate::reg::{
field::{RRRegFieldBit, WWRegFieldBit, WoWoRegFieldBit},
tag::{RegTag, Urt},
RReg, Reg, WReg, WoReg,
};
use core::ptr::{read_volatile, write_volatile};
pub const BIT_BAND_BASE: usize = 0x4200_0000;
pub const BIT_BAND_WIDTH: usize = 5;
pub trait RegBitBand<T: RegTag>: Reg<T> {}
#[allow(clippy::upper_case_acronyms)]
pub trait RRRegFieldBitBand<T: RegTag>
where
Self: RRRegFieldBit<T>,
Self::Reg: RegBitBand<T> + RReg<T>,
{
fn read_bit_band(&self) -> bool;
fn to_bit_band_ptr(&self) -> *const usize;
}
#[allow(clippy::upper_case_acronyms)]
pub trait WWRegFieldBitBand<T: RegTag>
where
Self: WWRegFieldBitBandMarker<T>,
Self::Reg: RegBitBand<T> + WReg<T>,
{
fn set_bit_band(&self);
fn clear_bit_band(&self);
fn to_bit_band_mut_ptr(&self) -> *mut usize;
}
#[allow(clippy::upper_case_acronyms)]
#[marker]
pub trait WWRegFieldBitBandMarker<T: RegTag>
where
Self: WWRegFieldBit<T>,
Self::Reg: RegBitBand<T> + WReg<T>,
{
}
impl<T, R> RRRegFieldBitBand<T> for R
where
T: RegTag,
R: RRRegFieldBit<T>,
R::Reg: RegBitBand<T> + RReg<T>,
{
#[inline]
fn read_bit_band(&self) -> bool {
unsafe { read_volatile(self.to_bit_band_ptr()) != 0 }
}
#[inline]
fn to_bit_band_ptr(&self) -> *const usize {
bit_band_addr::<T, Self::Reg>(Self::OFFSET) as *const usize
}
}
impl<T, R> WWRegFieldBitBand<T> for R
where
T: RegTag,
R: WWRegFieldBitBandMarker<T>,
R::Reg: RegBitBand<T> + WReg<T>,
{
#[inline]
fn set_bit_band(&self) {
unsafe { write_volatile(self.to_bit_band_mut_ptr(), 1) };
}
#[inline]
fn clear_bit_band(&self) {
unsafe { write_volatile(self.to_bit_band_mut_ptr(), 0) };
}
#[inline]
fn to_bit_band_mut_ptr(&self) -> *mut usize {
bit_band_addr::<T, Self::Reg>(Self::OFFSET) as *mut usize
}
}
impl<T, R> WWRegFieldBitBandMarker<T> for R
where
T: RegTag,
R: WoWoRegFieldBit<T>,
R::Reg: RegBitBand<T> + WoReg<T>,
{
}
impl<R> WWRegFieldBitBandMarker<Urt> for R
where
R: WWRegFieldBit<Urt>,
R::Reg: RegBitBand<Urt> + WReg<Urt>,
{
}
fn bit_band_addr<T: RegTag, R: RegBitBand<T>>(offset: usize) -> usize {
BIT_BAND_BASE
+ (((R::ADDRESS + (offset >> 3)) & ((0b1 << (BIT_BAND_WIDTH << 2)) - 1)) << BIT_BAND_WIDTH)
+ ((offset & (8 - 1)) << 2)
}
#[cfg(test)]
mod tests {
use super::*;
use drone_core::reg;
reg! {
#[allow(dead_code)]
R LOW => {
address => 0x4000_0000; size => 0x20; reset => 0x0000_0000; traits => { RegBitBand };
fields => { TEST_BIT => { offset => 0; width => 1 } };
};
}
reg! {
#[allow(dead_code)]
R HIGH => {
address => 0x400F_FFFC; size => 0x20; reset => 0x0000_0000; traits => { RegBitBand };
fields => { TEST_BIT => { offset => 0; width => 1 } };
};
}
#[test]
fn reg_bit_band_addr() {
assert_eq!(bit_band_addr::<Urt, r_low::Reg<Urt>>(0), 0x4200_0000);
assert_eq!(bit_band_addr::<Urt, r_low::Reg<Urt>>(7), 0x4200_001C);
assert_eq!(bit_band_addr::<Urt, r_low::Reg<Urt>>(31), 0x4200_007C);
assert_eq!(bit_band_addr::<Urt, r_high::Reg<Urt>>(24), 0x43FF_FFE0);
assert_eq!(bit_band_addr::<Urt, r_high::Reg<Urt>>(31), 0x43FF_FFFC);
}
}