1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
pub use bit_field::*;

use crate::Volatile;

#[macro_export]
macro_rules! is_bit_set {
    ($field:expr, $bit:expr) => {
        $field.get() & (1 << $bit) > 0
    };
}

#[macro_export]
macro_rules! bit_get_fn {
    ($doc:meta, $fun:ident, $bit:expr) => {
        #[$doc]
        pub fn $fun(&self) -> bool {
            is_bit_set!(self.0, $bit)
        }
    };
}

#[macro_export]
macro_rules! bit_set_fn {
    ($doc:meta, $fun:ident, $bit:expr) => {
        #[$doc]
        pub fn $fun(&mut self) {
            let current = self.0.get();
            self.0.set(current | 1 << $bit);
        }
    };
}

#[macro_export]
macro_rules! bit_clear_fn {
    ($doc:meta, $fun:ident, $bit:expr) => {
        #[$doc]
        pub fn $fun(&mut self) {
            let current = self.0.get();
            self.0.set(current & !(1 << $bit));
        }
    };
}

/// Return a range of bits out of a 32-bit data-type.
pub fn bits_get(r: Volatile<u32>, from: usize, to: usize) -> u32 {
    assert!(from <= 31);
    assert!(to <= 31);
    assert!(from <= to);

    let mask = match to {
        31 => u32::max_value(),
        _ => (1 << (to + 1)) - 1,
    };

    (r.get() & mask) >> from
}

pub fn bits_set(r: &mut Volatile<u32>, from: usize, to: usize, bits: u32) {
    assert!(from <= 31);
    assert!(to <= 31);
    assert!(from <= to);

    let mask = match to == 31 {
        true => u32::max_value() << from,
        false => ((1 << (to + 1)) - 1) << from,
    };

    let current = r.get();
    r.set((current & !mask) | ((bits << from) & mask));
}

pub fn bits_set_16(r: &mut Volatile<u16>, from: usize, to: usize, bits: u16) {
    assert!(from <= 15);
    assert!(to <= 15);
    assert!(from <= to);

    let mask = match to == 15 {
        true => u16::max_value() << from,
        false => ((1 << (to + 1)) - 1) << from,
    };

    let current = r.get();
    r.set((current & !mask) | ((bits << from) & mask));
}

#[cfg(test)]
mod tests {
    use super::{bits_get, bits_set};
    use crate::Volatile;

    #[test]
    fn bits_set_from_to() {
        for from in 0..32 {
            for to in from..32 {
                let mut r: Volatile<u32> = Volatile::with_value(0);
                let all_ones: usize = (1 << (to - from + 1)) - 1;

                bits_set(&mut r, from, to, all_ones as u32);

                for check in 0..32 {
                    if check >= from && check <= to {
                        assert!(is_bit_set!(r, check));
                    } else {
                        assert!(!is_bit_set!(r, check));
                    }
                }

                assert!(bits_get(r, from, to) == all_ones as u32);
            }
        }
    }
}