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