use super::*;
use core::nonzero::Zeroable;
pub trait RegVal: Sized + Clone + Copy {
type Raw: RegRaw;
const DEFAULT: Self::Raw;
unsafe fn from_raw(raw: Self::Raw) -> Self;
fn raw(&self) -> Self::Raw;
fn raw_mut(&mut self) -> &mut Self::Raw;
#[inline(always)]
unsafe fn default() -> Self {
Self::from_raw(Self::DEFAULT)
}
#[inline(always)]
unsafe fn read_bit(&self, offset: Self::Raw) -> bool {
!(self.raw() & bit_at(offset)).is_zero()
}
#[inline(always)]
unsafe fn set_bit(&mut self, offset: Self::Raw) {
*self.raw_mut() = self.raw() | bit_at(offset);
}
#[inline(always)]
unsafe fn clear_bit(&mut self, offset: Self::Raw) {
*self.raw_mut() = self.raw() & !bit_at(offset);
}
#[inline(always)]
unsafe fn toggle_bit(&mut self, offset: Self::Raw) {
*self.raw_mut() = self.raw() ^ bit_at(offset);
}
#[inline(always)]
unsafe fn read_bits(&self, offset: Self::Raw, width: Self::Raw) -> Self::Raw {
if width == Self::Raw::size() {
self.raw()
} else {
self.raw() >> offset & bit_mask(width)
}
}
#[inline(always)]
unsafe fn write_bits(
&mut self,
offset: Self::Raw,
width: Self::Raw,
bits: Self::Raw,
) {
*self.raw_mut() = if width == Self::Raw::size() {
bits
} else {
self.raw() & !(bit_mask(width) << offset)
| (bits & bit_mask(width)) << offset
};
}
}
#[inline(always)]
fn bit_at<T: RegRaw>(offset: T) -> T {
T::one() << offset
}
#[inline(always)]
fn bit_mask<T: RegRaw>(width: T) -> T {
bit_at(width) - T::one()
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Clone, Copy)]
struct Val(u8);
impl RegVal for Val {
type Raw = u8;
const DEFAULT: u8 = 0xAA;
unsafe fn from_raw(raw: u8) -> Self {
Val(raw)
}
fn raw(&self) -> u8 {
self.0
}
fn raw_mut(&mut self) -> &mut u8 {
&mut self.0
}
}
#[test]
fn default() {
assert_eq!(unsafe { Val::default().raw() }, 0xAA);
}
#[test]
fn read_bit() {
let val = unsafe { Val::from_raw(0b1010_1010) };
assert!(!unsafe { val.read_bit(0) });
assert!(unsafe { val.read_bit(1) });
assert!(!unsafe { val.read_bit(2) });
assert!(unsafe { val.read_bit(3) });
assert!(!unsafe { val.read_bit(4) });
assert!(unsafe { val.read_bit(5) });
assert!(!unsafe { val.read_bit(6) });
assert!(unsafe { val.read_bit(7) });
}
#[test]
fn set_bit() {
let mut val = unsafe { Val::from_raw(0b1010_1010) };
unsafe {
val.set_bit(0);
val.set_bit(7);
val.set_bit(4);
val.set_bit(3);
}
assert_eq!(val.raw(), 0b1011_1011);
}
#[test]
fn clear_bit() {
let mut val = unsafe { Val::from_raw(0b1010_1010) };
unsafe {
val.clear_bit(0);
val.clear_bit(7);
val.clear_bit(4);
val.clear_bit(3);
}
assert_eq!(val.raw(), 0b0010_0010);
}
#[test]
fn toggle_bit() {
let mut val = unsafe { Val::from_raw(0b1010_1010) };
unsafe {
val.toggle_bit(0);
val.toggle_bit(7);
val.toggle_bit(4);
val.toggle_bit(3);
}
assert_eq!(val.raw(), 0b0011_0011);
}
#[test]
fn read_bits() {
let val = unsafe { Val::from_raw(0b1010_0110) };
assert_eq!(unsafe { val.read_bits(0, 0) }, 0b0);
assert_eq!(unsafe { val.read_bits(1, 0) }, 0b0);
assert_eq!(unsafe { val.read_bits(2, 0) }, 0b0);
assert_eq!(unsafe { val.read_bits(0, 1) }, 0b0);
assert_eq!(unsafe { val.read_bits(1, 1) }, 0b1);
assert_eq!(unsafe { val.read_bits(2, 1) }, 0b1);
assert_eq!(unsafe { val.read_bits(3, 1) }, 0b0);
assert_eq!(unsafe { val.read_bits(4, 1) }, 0b0);
assert_eq!(unsafe { val.read_bits(5, 1) }, 0b1);
assert_eq!(unsafe { val.read_bits(6, 1) }, 0b0);
assert_eq!(unsafe { val.read_bits(7, 1) }, 0b1);
assert_eq!(unsafe { val.read_bits(0, 4) }, 0b0110);
assert_eq!(unsafe { val.read_bits(1, 4) }, 0b0011);
assert_eq!(unsafe { val.read_bits(2, 4) }, 0b1001);
assert_eq!(unsafe { val.read_bits(3, 4) }, 0b0100);
assert_eq!(unsafe { val.read_bits(4, 4) }, 0b1010);
assert_eq!(unsafe { val.read_bits(0, 7) }, 0b0100_110);
assert_eq!(unsafe { val.read_bits(1, 7) }, 0b1010_011);
assert_eq!(unsafe { val.read_bits(0, 8) }, 0b1010_0110);
}
#[test]
fn write_bits() {
let mut val = unsafe { Val::from_raw(0b1010_0110) };
unsafe { val.write_bits(0, 0, 0b0) };
unsafe { val.write_bits(1, 0, 0b1) };
unsafe { val.write_bits(6, 0, 0b11) };
unsafe { val.write_bits(7, 0, 0b111) };
assert_eq!(val.raw(), 0b1010_0110);
let mut val = unsafe { Val::from_raw(0b1010_0110) };
unsafe { val.write_bits(0, 1, 0b1) };
unsafe { val.write_bits(1, 1, 0b0) };
unsafe { val.write_bits(7, 1, 0b0) };
unsafe { val.write_bits(5, 1, 0b1) };
assert_eq!(val.raw(), 0b0010_0101);
let mut val = unsafe { Val::from_raw(0b1010_0110) };
unsafe { val.write_bits(0, 4, 0b1001) };
assert_eq!(val.raw(), 0b1010_1001);
unsafe { val.write_bits(1, 4, 0b1001) };
assert_eq!(val.raw(), 0b1011_0011);
unsafe { val.write_bits(2, 4, 0b1001) };
assert_eq!(val.raw(), 0b1010_0111);
unsafe { val.write_bits(3, 4, 0b1001) };
assert_eq!(val.raw(), 0b1100_1111);
unsafe { val.write_bits(4, 4, 0b1001) };
assert_eq!(val.raw(), 0b1001_1111);
let mut val = unsafe { Val::from_raw(0b1010_0110) };
unsafe { val.write_bits(0, 7, 0b1010_011) };
assert_eq!(val.raw(), 0b1101_0011);
unsafe { val.write_bits(1, 7, 0b1010_011) };
assert_eq!(val.raw(), 0b1010_0111);
let mut val = unsafe { Val::from_raw(0b0001_1000) };
unsafe { val.write_bits(0, 8, 0b1111_1111) };
assert_eq!(val.raw(), 0b1111_1111);
}
}