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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//! Code for managing CPSR (*Current Program Status Register*)
/// The current Processor Mode
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[bitbybit::bitenum(u5, exhaustive = false)]
pub enum ProcessorMode {
/// User Mode
Usr = 0b10000,
/// FIQ Mode
Fiq = 0b10001,
/// IRQ Mode
Irq = 0b10010,
/// Supervisor Mode
Svc = 0b10011,
/// Monitor Mode
Mon = 0b10110,
/// Abort Mode
Abt = 0b10111,
/// Hyp Mode
Hyp = 0b11010,
/// Undefined Mode
Und = 0b11011,
/// System Mode
Sys = 0b11111,
}
/// CPSR (*Current Program Status Register*)
#[bitbybit::bitfield(u32)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Cpsr {
/// Negative Result from ALU
#[bits(31..=31, r)]
n: bool,
/// Zero Result from ALU
#[bits(30..=30, r)]
z: bool,
/// ALU operation Carry Out
#[bits(29..=29, r)]
c: bool,
/// ALU operation Overflow
#[bits(28..=28, r)]
v: bool,
/// Cumulative Saturation
#[bits(27..=27, r)]
q: bool,
/// Jazelle State
#[bits(24..=24, r)]
j: bool,
/// Endianness
#[bits(9..=9, rw)]
e: bool,
/// Asynchronous Aborts
#[bits(8..=8, rw)]
a: bool,
/// Interrupts Enabled
#[bits(7..=7, rw)]
i: bool,
/// Fast Interrupts Enabled
#[bits(6..=6, rw)]
f: bool,
/// Thumb state
#[bits(5..=5, rw)]
t: bool,
/// Processor Mode
#[bits(0..=4, rw)]
mode: Option<ProcessorMode>,
}
impl Cpsr {
/// Read CPSR (*Current Program Status Register*)
#[inline]
pub fn read() -> Self {
let r: u32;
// Safety: Reading this register has no side-effects and is atomic
#[cfg(target_arch = "arm")]
unsafe {
core::arch::asm!("mrs {}, CPSR", out(reg) r, options(nomem, nostack, preserves_flags));
}
#[cfg(not(target_arch = "arm"))]
{
r = 0;
}
Self::new_with_raw_value(r)
}
/// Write CPSR (*Current Program Status Register*)
///
/// # Safety
///
/// Changing the Program Status Register can affect whether interrupts are
/// enabled, whether we are executing Arm or Thumb instructions, or which
/// processor mode are in. You must be absolutely certain that the new CPSR
/// value is valid and appropriate for continued Rust code execution.
///
/// You almost certainly want to follow this with an [ISB](crate::asm::isb)
/// instruction.
#[inline]
pub unsafe fn write(_value: Self) {
// Safety: This is risky, but we're in an unsafe function
#[cfg(target_arch = "arm")]
unsafe {
core::arch::asm!("msr CPSR, {}", in(reg) _value.raw_value());
}
}
/// Modify SCTLR (*System Control Register*)
///
/// # Safety
///
/// See docs for [Self::write].
#[inline]
pub unsafe fn modify<F>(f: F)
where
F: FnOnce(&mut Self),
{
let mut value = Self::read();
f(&mut value);
unsafe {
Self::write(value);
}
}
}
impl core::fmt::Debug for Cpsr {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"CPSR {{ N={} Z={} C={} V={} Q={} J={} E={} A={} I={} F={} T={} MODE={:?} }}",
self.n() as u8,
self.z() as u8,
self.c() as u8,
self.v() as u8,
self.q() as u8,
self.j() as u8,
self.e() as u8,
self.a() as u8,
self.i() as u8,
self.f() as u8,
self.t() as u8,
self.mode(),
)
}
}
#[cfg(feature = "defmt")]
impl defmt::Format for Cpsr {
fn format(&self, f: defmt::Formatter) {
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())
}
}