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
113
114
115
116
117
//! Control register

/// Control register
pub struct Control {
    bits: u32,
}

impl Control {
    /// Returns the contents of the register as raw bits
    pub fn bits(&self) -> u32 {
        self.bits
    }

    /// Thread mode privilege level
    pub fn npriv(&self) -> Npriv {
        if self.bits & (1 << 0) == (1 << 0) {
            Npriv::Unprivileged
        } else {
            Npriv::Privileged
        }
    }

    /// Currently active stack pointer
    pub fn spsel(&self) -> Spsel {
        if self.bits & (1 << 1) == (1 << 1) {
            Spsel::Psp
        } else {
            Spsel::Msp
        }
    }

    /// Whether context floating-point is currently active
    pub fn fpca(&self) -> Fpca {
        if self.bits & (1 << 2) == (1 << 2) {
            Fpca::Active
        } else {
            Fpca::NotActive
        }
    }
}

/// Thread mode privilege level
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum Npriv {
    /// Privileged
    Privileged,
    /// Unprivileged
    Unprivileged,
}

impl Npriv {
    /// Is in privileged thread mode?
    pub fn is_privileged(&self) -> bool {
        *self == Npriv::Privileged
    }

    /// Is in unprivileged thread mode?
    pub fn is_unprivileged(&self) -> bool {
        *self == Npriv::Unprivileged
    }
}

/// Currently active stack pointer
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum Spsel {
    /// MSP is the current stack pointer
    Msp,
    /// PSP is the current stack pointer
    Psp,
}

impl Spsel {
    /// Is MSP the current stack pointer?
    pub fn is_msp(&self) -> bool {
        *self == Spsel::Msp
    }

    /// Is PSP the current stack pointer?
    pub fn is_psp(&self) -> bool {
        *self == Spsel::Psp
    }
}

/// Whether context floating-point is currently active
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum Fpca {
    /// Floating-point context active.
    Active,
    /// No floating-point context active
    NotActive,
}

impl Fpca {
    /// Is a floating-point context active?
    pub fn is_active(&self) -> bool {
        *self == Fpca::Active
    }

    /// Is a floating-point context not active?
    pub fn is_not_active(&self) -> bool {
        *self == Fpca::NotActive
    }
}

/// Reads the CPU register
#[inline(always)]
pub fn read() -> Control {
    let r: u32;
    unsafe {
        asm!("mrs $0, CONTROL"
             : "=r"(r)
             :
             :
             : "volatile");
    }
    Control { bits: r }
}