|
9 | 9 | use core::arch::asm; |
10 | 10 | use core::sync::atomic::{Ordering, compiler_fence}; |
11 | 11 |
|
12 | | -#[inline(always)] |
13 | | -pub unsafe fn __bkpt() { |
14 | | - unsafe { asm!("bkpt", options(nomem, nostack, preserves_flags)) }; |
15 | | -} |
16 | | - |
17 | | -#[inline(always)] |
18 | | -pub unsafe fn __control_r() -> u32 { |
19 | | - let r; |
20 | | - unsafe { asm!("mrs {}, CONTROL", out(reg) r, options(nomem, nostack, preserves_flags)) }; |
21 | | - r |
22 | | -} |
23 | | - |
24 | | -#[inline(always)] |
25 | | -pub unsafe fn __control_w(w: u32) { |
26 | | - // ISB is required after writing to CONTROL, |
27 | | - // per ARM architectural requirements (see Application Note 321). |
28 | | - unsafe { |
29 | | - asm!( |
30 | | - "msr CONTROL, {}", |
31 | | - "isb", |
32 | | - in(reg) w, |
33 | | - options(nomem, nostack, preserves_flags), |
34 | | - ) |
35 | | - }; |
36 | | - |
37 | | - // Ensure memory accesses are not reordered around the CONTROL update. |
38 | | - compiler_fence(Ordering::SeqCst); |
39 | | -} |
40 | | - |
41 | | -#[inline(always)] |
42 | | -pub unsafe fn __cpsid() { |
43 | | - unsafe { asm!("cpsid i", options(nomem, nostack, preserves_flags)) }; |
44 | | - |
45 | | - // Ensure no subsequent memory accesses are reordered to before interrupts are disabled. |
46 | | - compiler_fence(Ordering::SeqCst); |
47 | | -} |
48 | | - |
49 | | -#[inline(always)] |
50 | | -pub unsafe fn __cpsie() { |
51 | | - // Ensure no preceeding memory accesses are reordered to after interrupts are enabled. |
52 | | - compiler_fence(Ordering::SeqCst); |
53 | | - |
54 | | - unsafe { asm!("cpsie i", options(nomem, nostack, preserves_flags)) }; |
55 | | -} |
56 | | - |
57 | | -#[inline(always)] |
58 | | -pub unsafe fn __delay(cyc: u32) { |
59 | | - // The loop will normally take 3 to 4 CPU cycles per iteration, but superscalar cores |
60 | | - // (eg. Cortex-M7) can potentially do it in 2, so we use that as the lower bound, since delaying |
61 | | - // for more cycles is okay. |
62 | | - // Add 1 to prevent an integer underflow which would cause a long freeze |
63 | | - let real_cyc = 1 + cyc / 2; |
64 | | - unsafe { |
65 | | - asm!( |
66 | | - // The `bne` on some cores (eg Cortex-M4) will take a different number of instructions |
67 | | - // depending on the alignment of the branch target. Set the alignment of the top of the |
68 | | - // loop to prevent surprising timing changes when the alignment of the delay() changes. |
69 | | - ".p2align 3", |
70 | | - // Use local labels to avoid R_ARM_THM_JUMP8 relocations which fail on thumbv6m. |
71 | | - "1:", |
72 | | - "subs {}, #1", |
73 | | - "bne 1b", |
74 | | - inout(reg) real_cyc => _, |
75 | | - options(nomem, nostack), |
76 | | - ) |
77 | | - }; |
78 | | -} |
79 | | - |
80 | | -#[inline(always)] |
81 | | -pub unsafe fn __dmb() { |
82 | | - compiler_fence(Ordering::SeqCst); |
83 | | - unsafe { asm!("dmb", options(nostack, preserves_flags)) }; |
84 | | - compiler_fence(Ordering::SeqCst); |
85 | | -} |
86 | | - |
87 | | -#[inline(always)] |
88 | | -pub unsafe fn __dsb() { |
89 | | - compiler_fence(Ordering::SeqCst); |
90 | | - unsafe { asm!("dsb", options(nostack, preserves_flags)) }; |
91 | | - compiler_fence(Ordering::SeqCst); |
92 | | -} |
93 | | - |
94 | | -#[inline(always)] |
95 | | -pub unsafe fn __isb() { |
96 | | - compiler_fence(Ordering::SeqCst); |
97 | | - unsafe { asm!("isb", options(nostack, preserves_flags)) }; |
98 | | - compiler_fence(Ordering::SeqCst); |
99 | | -} |
100 | | - |
101 | | -#[inline(always)] |
102 | | -pub unsafe fn __msp_r() -> u32 { |
103 | | - let r; |
104 | | - unsafe { asm!("mrs {}, MSP", out(reg) r, options(nomem, nostack, preserves_flags)) }; |
105 | | - r |
106 | | -} |
107 | | - |
108 | | -#[inline(always)] |
109 | | -pub unsafe fn __msp_w(val: u32) { |
110 | | - // Technically is writing to the stack pointer "not pushing any data to the stack"? |
111 | | - // In any event, if we don't set `nostack` here, this method is useless as the new |
112 | | - // stack value is immediately mutated by returning. Really this is just not a good |
113 | | - // method and its higher-level use is marked as deprecated in cortex-m. |
114 | | - unsafe { asm!("msr MSP, {}", in(reg) val, options(nomem, nostack, preserves_flags)) }; |
115 | | -} |
116 | | - |
117 | | -// NOTE: No FFI shim, this requires inline asm. |
118 | | -#[inline(always)] |
119 | | -pub unsafe fn __apsr_r() -> u32 { |
120 | | - let r; |
121 | | - unsafe { asm!("mrs {}, APSR", out(reg) r, options(nomem, nostack, preserves_flags)) }; |
122 | | - r |
123 | | -} |
124 | | - |
125 | | -#[inline(always)] |
126 | | -pub unsafe fn __nop() { |
127 | | - // NOTE: This is a `pure` asm block, but applying that option allows the compiler to eliminate |
128 | | - // the nop entirely (or to collapse multiple subsequent ones). Since the user probably wants N |
129 | | - // nops when they call `nop` N times, let's not add that option. |
130 | | - unsafe { asm!("nop", options(nomem, nostack, preserves_flags)) }; |
131 | | -} |
132 | | - |
133 | 12 | // NOTE: No FFI shim, this requires inline asm. |
134 | 13 | #[inline(always)] |
135 | 14 | pub unsafe fn __pc_r() -> u32 { |
|
0 commit comments