Skip to main content

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(armv6_or_lower, instruction_set(arm::a32))]
78    pub fn read() -> Self {
79        let r: u32;
80
81        #[cfg(target_arch = "arm")]
82        unsafe {
83            core::arch::asm!("mrs {}, CPSR", out(reg) r, options(nomem, nostack, preserves_flags));
84        }
85        #[cfg(not(target_arch = "arm"))]
86        {
87            r = 0;
88        }
89        Self::new_with_raw_value(r)
90    }
91
92    /// Write CPSR (*Current Program Status Register*)
93    ///
94    /// # Safety
95    ///
96    /// Changing the Program Status Register can affect whether interrupts are
97    /// enabled, whether we are executing Arm or Thumb instructions, or which
98    /// processor mode are in. You must be absolutely certain that the new CPSR
99    /// value is valid and appropriate for continued Rust code execution.
100    ///
101    /// You almost certainly want to follow this with an [ISB](crate::asm::isb)
102    /// instruction.
103    ///
104    /// On Armv4T and Armv5TE this will be an Arm function, even on the
105    /// `thumb*` targets, as Thumb-1 cannot do an MSR.
106    #[cfg_attr(not(feature = "check-asm"), inline)]
107    #[cfg_attr(armv6_or_lower, instruction_set(arm::a32))]
108    pub unsafe fn write(_value: Self) {
109        // Safety: This is risky, but we're in an unsafe function
110        #[cfg(target_arch = "arm")]
111        unsafe {
112            core::arch::asm!("msr CPSR, {}", in(reg) _value.raw_value());
113        }
114    }
115
116    /// Modify SCTLR (*System Control Register*)
117    ///
118    /// # Safety
119    ///
120    /// See docs for [Self::write].
121    #[inline]
122    pub unsafe fn modify<F>(f: F)
123    where
124        F: FnOnce(&mut Self),
125    {
126        let mut value = Self::read();
127        f(&mut value);
128        unsafe {
129            Self::write(value);
130        }
131    }
132}
133
134impl core::fmt::Debug for Cpsr {
135    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
136        write!(
137            f,
138            "CPSR {{ N={} Z={} C={} V={} Q={} J={} E={} A={} I={} F={} T={} MODE={:?} }}",
139            self.n() as u8,
140            self.z() as u8,
141            self.c() as u8,
142            self.v() as u8,
143            self.q() as u8,
144            self.j() as u8,
145            self.e() as u8,
146            self.a() as u8,
147            self.i() as u8,
148            self.f() as u8,
149            self.t() as u8,
150            self.mode(),
151        )
152    }
153}
154
155#[cfg(feature = "defmt")]
156impl defmt::Format for Cpsr {
157    fn format(&self, f: defmt::Formatter) {
158        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())
159    }
160}