aarch32_cpu/register/
cpsr.rs

1//! Code for managing CPSR (*Current Program Status Register*)
2
3/// The current Processor Mode
4#[derive(Debug, PartialEq, Eq)]
5#[cfg_attr(feature = "defmt", derive(defmt::Format))]
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7#[bitbybit::bitenum(u5, exhaustive = false)]
8pub enum ProcessorMode {
9    /// User Mode
10    Usr = 0b10000,
11    /// FIQ Mode
12    Fiq = 0b10001,
13    /// IRQ Mode
14    Irq = 0b10010,
15    /// Supervisor Mode
16    Svc = 0b10011,
17    /// Monitor Mode
18    Mon = 0b10110,
19    /// Abort Mode
20    Abt = 0b10111,
21    /// Hyp Mode
22    Hyp = 0b11010,
23    /// Undefined Mode
24    Und = 0b11011,
25    /// System Mode
26    Sys = 0b11111,
27}
28
29/// CPSR (*Current Program Status Register*)
30#[bitbybit::bitfield(u32)]
31#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
32pub struct Cpsr {
33    /// Negative Result from ALU
34    #[bits(31..=31, r)]
35    n: bool,
36    /// Zero Result from ALU
37    #[bits(30..=30, r)]
38    z: bool,
39    /// ALU operation Carry Out
40    #[bits(29..=29, r)]
41    c: bool,
42    /// ALU operation Overflow
43    #[bits(28..=28, r)]
44    v: bool,
45    /// Cumulative Saturation
46    #[bits(27..=27, r)]
47    q: bool,
48    /// Jazelle State
49    #[bits(24..=24, r)]
50    j: bool,
51    /// Endianness
52    #[bits(9..=9, rw)]
53    e: bool,
54    /// Asynchronous Aborts
55    #[bits(8..=8, rw)]
56    a: bool,
57    /// Interrupts Enabled
58    #[bits(7..=7, rw)]
59    i: bool,
60    /// Fast Interrupts Enabled
61    #[bits(6..=6, rw)]
62    f: bool,
63    /// Thumb state
64    #[bits(5..=5, rw)]
65    t: bool,
66    /// Processor Mode
67    #[bits(0..=4, rw)]
68    mode: Option<ProcessorMode>,
69}
70
71impl Cpsr {
72    /// Read CPSR (*Current Program Status Register*)
73    ///
74    /// On Armv4T and Armv5TE this will be an Arm function, even on the
75    /// `thumb*` targets, as Thumb-1 cannot do an MRS.
76    #[cfg_attr(not(feature = "check-asm"), inline)]
77    #[cfg_attr(
78        any(arm_architecture = "v4t", arm_architecture = "v5te"),
79        instruction_set(arm::a32)
80    )]
81    pub fn read() -> Self {
82        let r: u32;
83        // Safety: Reading this register has no side-effects and is atomic
84        #[cfg(target_arch = "arm")]
85        unsafe {
86            core::arch::asm!("mrs {}, CPSR", out(reg) r, options(nomem, nostack, preserves_flags));
87        }
88        #[cfg(not(target_arch = "arm"))]
89        {
90            r = 0;
91        }
92        Self::new_with_raw_value(r)
93    }
94
95    /// Write CPSR (*Current Program Status Register*)
96    ///
97    /// # Safety
98    ///
99    /// Changing the Program Status Register can affect whether interrupts are
100    /// enabled, whether we are executing Arm or Thumb instructions, or which
101    /// processor mode are in. You must be absolutely certain that the new CPSR
102    /// value is valid and appropriate for continued Rust code execution.
103    ///
104    /// You almost certainly want to follow this with an [ISB](crate::asm::isb)
105    /// instruction.
106    ///
107    /// On Armv4T and Armv5TE this will be an Arm function, even on the
108    /// `thumb*` targets, as Thumb-1 cannot do an MSR.
109    #[cfg_attr(not(feature = "check-asm"), inline)]
110    #[cfg_attr(
111        any(arm_architecture = "v4t", arm_architecture = "v5te"),
112        instruction_set(arm::a32)
113    )]
114    pub unsafe fn write(_value: Self) {
115        // Safety: This is risky, but we're in an unsafe function
116        #[cfg(target_arch = "arm")]
117        unsafe {
118            core::arch::asm!("msr CPSR, {}", in(reg) _value.raw_value());
119        }
120    }
121
122    /// Modify SCTLR (*System Control Register*)
123    ///
124    /// # Safety
125    ///
126    /// See docs for [Self::write].
127    #[inline]
128    pub unsafe fn modify<F>(f: F)
129    where
130        F: FnOnce(&mut Self),
131    {
132        let mut value = Self::read();
133        f(&mut value);
134        unsafe {
135            Self::write(value);
136        }
137    }
138}
139
140impl core::fmt::Debug for Cpsr {
141    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
142        write!(
143            f,
144            "CPSR {{ N={} Z={} C={} V={} Q={} J={} E={} A={} I={} F={} T={} MODE={:?} }}",
145            self.n() as u8,
146            self.z() as u8,
147            self.c() as u8,
148            self.v() as u8,
149            self.q() as u8,
150            self.j() as u8,
151            self.e() as u8,
152            self.a() as u8,
153            self.i() as u8,
154            self.f() as u8,
155            self.t() as u8,
156            self.mode(),
157        )
158    }
159}
160
161#[cfg(feature = "defmt")]
162impl defmt::Format for Cpsr {
163    fn format(&self, f: defmt::Formatter) {
164        defmt::write!(f, "CPSR {{ N={0=31..32} Z={0=30..31} C={0=29..30} V={0=28..29} Q={0=27..28} J={0=24..25} E={0=9..10} A={0=8..9} I={0=7..8} F={0=6..7} T={0=5..6} MODE={0=0..5} }}", self.raw_value())
165    }
166}