Skip to main content

cortex_m/register/
control.rs

1//! Control register
2
3#[cfg(cortex_m)]
4use core::arch::asm;
5#[cfg(cortex_m)]
6use core::sync::atomic::{Ordering, compiler_fence};
7use cortex_m_macros::asm_cfg;
8
9/// Control register
10#[derive(Clone, Copy, Debug)]
11pub struct Control {
12    bits: u32,
13}
14
15impl Control {
16    /// Creates a `Control` value from raw bits.
17    #[inline]
18    pub const fn from_bits(bits: u32) -> Self {
19        Self { bits }
20    }
21
22    /// Returns the contents of the register as raw bits
23    #[inline]
24    pub const fn bits(self) -> u32 {
25        self.bits
26    }
27
28    /// Thread mode privilege level
29    #[inline]
30    pub fn npriv(self) -> Npriv {
31        if self.bits & (1 << 0) == (1 << 0) {
32            Npriv::Unprivileged
33        } else {
34            Npriv::Privileged
35        }
36    }
37
38    /// Sets the thread mode privilege level value (nPRIV).
39    #[inline]
40    pub fn set_npriv(&mut self, npriv: Npriv) {
41        let mask = 1 << 0;
42        match npriv {
43            Npriv::Unprivileged => self.bits |= mask,
44            Npriv::Privileged => self.bits &= !mask,
45        }
46    }
47
48    /// Sets the thread mode privilege level value (nPRIV).
49    #[inline]
50    pub const fn with_npriv(self, npriv: Npriv) -> Self {
51        let mask = 1 << 0;
52        let bits = match npriv {
53            Npriv::Unprivileged => self.bits | mask,
54            Npriv::Privileged => self.bits & !mask,
55        };
56        Self { bits }
57    }
58
59    /// Currently active stack pointer
60    #[inline]
61    pub fn spsel(self) -> Spsel {
62        if self.bits & (1 << 1) == (1 << 1) {
63            Spsel::Psp
64        } else {
65            Spsel::Msp
66        }
67    }
68
69    /// Sets the SPSEL value.
70    #[inline]
71    pub fn set_spsel(&mut self, spsel: Spsel) {
72        let mask = 1 << 1;
73        match spsel {
74            Spsel::Psp => self.bits |= mask,
75            Spsel::Msp => self.bits &= !mask,
76        }
77    }
78
79    /// Sets the SPSEL value.
80    #[inline]
81    pub const fn with_spsel(self, spsel: Spsel) -> Self {
82        let mask = 1 << 1;
83        let bits = match spsel {
84            Spsel::Psp => self.bits | mask,
85            Spsel::Msp => self.bits & !mask,
86        };
87        Self { bits }
88    }
89
90    /// Whether context floating-point is currently active
91    #[inline]
92    pub fn fpca(self) -> Fpca {
93        if self.bits & (1 << 2) == (1 << 2) {
94            Fpca::Active
95        } else {
96            Fpca::NotActive
97        }
98    }
99
100    /// Sets the FPCA value.
101    #[inline]
102    pub fn set_fpca(&mut self, fpca: Fpca) {
103        let mask = 1 << 2;
104        match fpca {
105            Fpca::Active => self.bits |= mask,
106            Fpca::NotActive => self.bits &= !mask,
107        }
108    }
109}
110
111/// Thread mode privilege level
112#[derive(Clone, Copy, Debug, Eq, PartialEq)]
113pub enum Npriv {
114    /// Privileged
115    Privileged,
116    /// Unprivileged
117    Unprivileged,
118}
119
120impl Npriv {
121    /// Is in privileged thread mode?
122    #[inline]
123    pub fn is_privileged(self) -> bool {
124        self == Npriv::Privileged
125    }
126
127    /// Is in unprivileged thread mode?
128    #[inline]
129    pub fn is_unprivileged(self) -> bool {
130        self == Npriv::Unprivileged
131    }
132}
133
134/// Currently active stack pointer
135#[derive(Clone, Copy, Debug, Eq, PartialEq)]
136pub enum Spsel {
137    /// MSP is the current stack pointer
138    Msp,
139    /// PSP is the current stack pointer
140    Psp,
141}
142
143impl Spsel {
144    /// Is MSP the current stack pointer?
145    #[inline]
146    pub fn is_msp(self) -> bool {
147        self == Spsel::Msp
148    }
149
150    /// Is PSP the current stack pointer?
151    #[inline]
152    pub fn is_psp(self) -> bool {
153        self == Spsel::Psp
154    }
155}
156
157/// Whether context floating-point is currently active
158#[derive(Clone, Copy, Debug, Eq, PartialEq)]
159pub enum Fpca {
160    /// Floating-point context active.
161    Active,
162    /// No floating-point context active
163    NotActive,
164}
165
166impl Fpca {
167    /// Is a floating-point context active?
168    #[inline]
169    pub fn is_active(self) -> bool {
170        self == Fpca::Active
171    }
172
173    /// Is a floating-point context not active?
174    #[inline]
175    pub fn is_not_active(self) -> bool {
176        self == Fpca::NotActive
177    }
178}
179
180/// Reads the CPU register
181#[inline]
182#[asm_cfg(cortex_m)]
183pub fn read() -> Control {
184    let bits;
185    unsafe { asm!("mrs {}, CONTROL", out(reg) bits, options(nomem, nostack, preserves_flags)) };
186    Control { bits }
187}
188
189/// Writes to the CPU register.
190#[inline]
191#[asm_cfg(cortex_m)]
192pub unsafe fn write(control: Control) {
193    let control = control.bits();
194
195    // ISB is required after writing to CONTROL,
196    // per ARM architectural requirements (see Application Note 321).
197    unsafe {
198        asm!(
199            "msr CONTROL, {}",
200            "isb",
201            in(reg) control,
202            options(nomem, nostack, preserves_flags),
203        );
204        compiler_fence(Ordering::SeqCst);
205    }
206}