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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
|
//! Inline assembly implementing the routines exposed in `cortex_m::asm`.
//!
//! If the `inline-asm` feature is enabled, these functions will be directly called by the
//! `cortex-m` wrappers. Otherwise, `cortex-m` links against them via prebuilt archives.
//!
//! All of these functions should be blanket-`unsafe`. `cortex-m` provides safe wrappers where
//! applicable.
#[inline(always)]
pub unsafe fn __bkpt() {
asm!("bkpt");
}
#[inline(always)]
pub unsafe fn __control_r() -> u32 {
let r;
asm!("mrs {}, CONTROL", out(reg) r);
r
}
#[inline(always)]
pub unsafe fn __control_w(w: u32) {
asm!("msr CONTROL, {}", in(reg) w);
}
#[inline(always)]
pub unsafe fn __cpsid() {
asm!("cpsid i");
}
#[inline(always)]
pub unsafe fn __cpsie() {
asm!("cpsie i");
}
#[inline(always)]
pub unsafe fn __delay(cyc: u32) {
asm!("
1:
nop
subs {}, #1
bne 1b
// Branch to 1 instead of delay does not generate R_ARM_THM_JUMP8 relocation, which breaks
// linking on the thumbv6m-none-eabi target
", in(reg) cyc);
}
// FIXME do we need compiler fences here or should we expect them in the caller?
#[inline(always)]
pub unsafe fn __dmb() {
asm!("dmb 0xF");
}
#[inline(always)]
pub unsafe fn __dsb() {
asm!("dsb 0xF");
}
#[inline(always)]
pub unsafe fn __isb() {
asm!("isb 0xF");
}
#[inline(always)]
pub unsafe fn __msp_r() -> u32 {
let r;
asm!("mrs {}, MSP", out(reg) r);
r
}
#[inline(always)]
pub unsafe fn __msp_w(val: u32) {
asm!("msr MSP, {}", in(reg) val);
}
// NOTE: No FFI shim, this requires inline asm.
#[inline(always)]
pub unsafe fn __apsr_r() -> u32 {
let r;
asm!("mrs {}, APSR", out(reg) r);
r
}
#[inline(always)]
pub unsafe fn __nop() {
// NOTE: This is a `pure` asm block, but applying that option allows the compiler to eliminate
// the nop entirely (or to collapse multiple subsequent ones). Since the user probably wants N
// nops when they call `nop` N times, let's not add that option.
asm!("nop");
}
// NOTE: No FFI shim, this requires inline asm.
#[inline(always)]
pub unsafe fn __pc_r() -> u32 {
let r;
asm!("mov {}, R15", out(reg) r);
r
}
// NOTE: No FFI shim, this requires inline asm.
#[inline(always)]
pub unsafe fn __pc_w(val: u32) {
asm!("mov R15, {}", in(reg) val);
}
// NOTE: No FFI shim, this requires inline asm.
#[inline(always)]
pub unsafe fn __lr_r() -> u32 {
let r;
asm!("mov {}, R14", out(reg) r);
r
}
// NOTE: No FFI shim, this requires inline asm.
#[inline(always)]
pub unsafe fn __lr_w(val: u32) {
asm!("mov R14, {}", in(reg) val);
}
#[inline(always)]
pub unsafe fn __primask_r() -> u32 {
let r;
asm!("mrs {}, PRIMASK", out(reg) r);
r
}
#[inline(always)]
pub unsafe fn __psp_r() -> u32 {
let r;
asm!("mrs {}, PSP", out(reg) r);
r
}
#[inline(always)]
pub unsafe fn __psp_w(val: u32) {
asm!("msr PSP, {}", in(reg) val);
}
#[inline(always)]
pub unsafe fn __sev() {
asm!("sev");
}
#[inline(always)]
pub unsafe fn __udf() -> ! {
asm!("udf #0", options(noreturn));
}
#[inline(always)]
pub unsafe fn __wfe() {
asm!("wfe");
}
#[inline(always)]
pub unsafe fn __wfi() {
asm!("wfi");
}
// v7m *AND* v8m.main, but *NOT* v8m.base
#[cfg(any(armv7m, armv8m_main))]
pub use self::v7m::*;
#[cfg(any(armv7m, armv8m_main))]
mod v7m {
#[inline(always)]
pub unsafe fn __basepri_max(val: u8) {
asm!("msr BASEPRI_MAX, {}", in(reg) val);
}
#[inline(always)]
pub unsafe fn __basepri_r() -> u8 {
let r;
asm!("mrs {}, BASEPRI", out(reg) r);
r
}
#[inline(always)]
pub unsafe fn __basepri_w(val: u8) {
asm!("msr BASEPRI, {}", in(reg) val);
}
#[inline(always)]
pub unsafe fn __faultmask_r() -> u32 {
let r;
asm!("mrs {}, FAULTMASK", out(reg) r);
r
}
// FIXME: compiler_fences necessary?
#[inline(always)]
pub unsafe fn __enable_icache() {
asm!(
"
ldr r0, =0xE000ED14 @ CCR
mrs r2, PRIMASK @ save critical nesting info
cpsid i @ mask interrupts
ldr r1, [r0] @ read CCR
orr.w r1, r1, #(1 << 17) @ Set bit 17, IC
str r1, [r0] @ write it back
dsb @ ensure store completes
isb @ synchronize pipeline
msr PRIMASK, r2 @ unnest critical section
",
out("r0") _,
out("r1") _,
out("r2") _,
);
}
#[inline(always)]
pub unsafe fn __enable_dcache() {
asm!(
"
ldr r0, =0xE000ED14 @ CCR
mrs r2, PRIMASK @ save critical nesting info
cpsid i @ mask interrupts
ldr r1, [r0] @ read CCR
orr.w r1, r1, #(1 << 16) @ Set bit 16, DC
str r1, [r0] @ write it back
dsb @ ensure store completes
isb @ synchronize pipeline
msr PRIMASK, r2 @ unnest critical section
",
out("r0") _,
out("r1") _,
out("r2") _,
);
}
}
#[cfg(armv7em)]
pub use self::v7em::*;
#[cfg(armv7em)]
mod v7em {
#[inline(always)]
pub unsafe fn __basepri_max_cm7_r0p1(val: u8) {
asm!(
"
mrs r1, PRIMASK
cpsid i
tst.w r1, #1
msr BASEPRI_MAX, {}
it ne
bxne lr
cpsie i
",
in(reg) val,
out("r1") _,
);
}
#[inline(always)]
pub unsafe fn __basepri_w_cm7_r0p1(val: u8) {
asm!(
"
mrs r1, PRIMASK
cpsid i
tst.w r1, #1
msr BASEPRI, {}
it ne
bxne lr
cpsie i
",
in(reg) val,
out("r1") _,
);
}
}
#[cfg(armv8m)]
pub use self::v8m::*;
/// Baseline and Mainline.
#[cfg(armv8m)]
mod v8m {
#[inline(always)]
pub unsafe fn __tt(mut target: u32) -> u32 {
asm!("tt {target}, {target}", target = inout(reg) target);
target
}
#[inline(always)]
pub unsafe fn __ttt(mut target: u32) -> u32 {
asm!("ttt {target}, {target}", target = inout(reg) target);
target
}
#[inline(always)]
pub unsafe fn __tta(mut target: u32) -> u32 {
asm!("tta {target}, {target}", target = inout(reg) target);
target
}
#[inline(always)]
pub unsafe fn __ttat(mut target: u32) -> u32 {
asm!("ttat {target}, {target}", target = inout(reg) target);
target
}
}
#[cfg(armv8m_main)]
pub use self::v8m_main::*;
/// Mainline only.
#[cfg(armv8m_main)]
mod v8m_main {
#[inline(always)]
pub unsafe fn __msplim_r() -> u32 {
let r;
asm!("mrs {}, MSPLIM", out(reg) r);
r
}
#[inline(always)]
pub unsafe fn __msplim_w(val: u32) {
asm!("msr MSPLIM, {}", in(reg) val);
}
#[inline(always)]
pub unsafe fn __psplim_r() -> u32 {
let r;
asm!("mrs {}, PSPLIM", out(reg) r);
r
}
#[inline(always)]
pub unsafe fn __psplim_w(val: u32) {
asm!("msr PSPLIM, {}", in(reg) val);
}
}
#[cfg(has_fpu)]
pub use self::fpu::*;
/// All targets with FPU.
#[cfg(has_fpu)]
mod fpu {
#[inline(always)]
pub unsafe fn __fpscr_r() -> u32 {
let r;
asm!("vmrs {}, fpscr", out(reg) r);
r
}
#[inline(always)]
pub unsafe fn __fpscr_w(val: u32) {
asm!("vmsr fpscr, {}", in(reg) val);
}
}
|