Skip to content

Commit f1672b0

Browse files
committed
Move asm code into normal code.
Inline asm has been supported in stable rust for some time, so I removed the separate asm build infra and added that code to the normal crate code.
1 parent 0d2a810 commit f1672b0

8 files changed

Lines changed: 137 additions & 145 deletions

File tree

cortex-m/asm/inline.rs

Lines changed: 0 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -9,127 +9,6 @@
99
use core::arch::asm;
1010
use core::sync::atomic::{Ordering, compiler_fence};
1111

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-
13312
// NOTE: No FFI shim, this requires inline asm.
13413
#[inline(always)]
13514
pub unsafe fn __pc_r() -> u32 {

cortex-m/asm/lib.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,6 @@ macro_rules! shims {
5252
}
5353

5454
shims! {
55-
fn __bkpt();
56-
fn __control_r() -> u32;
57-
fn __control_w(w: u32);
58-
fn __cpsid();
59-
fn __cpsie();
60-
fn __delay(cyc: u32);
61-
fn __dmb();
62-
fn __dsb();
63-
fn __isb();
64-
fn __msp_r() -> u32;
65-
fn __msp_w(val: u32);
66-
fn __nop();
6755
fn __primask_r() -> u32;
6856
fn __psp_r() -> u32;
6957
fn __psp_w(val: u32);

cortex-m/src/asm.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
#[path = "../asm/inline.rs"]
77
pub(crate) mod inline;
88

9+
pub(crate) mod inner;
10+
911
/// Puts the processor in Debug state. Debuggers can pick this up as a "breakpoint".
1012
///
1113
/// **NOTE** calling `bkpt` when the processor is not connected to a debugger will cause an
1214
/// exception.
1315
#[inline(always)]
1416
pub fn bkpt() {
15-
call_asm!(__bkpt());
17+
unsafe { inner::__bkpt() };
1618
}
1719

1820
/// Blocks the program for *at least* `cycles` CPU cycles.
@@ -31,7 +33,7 @@ pub fn bkpt() {
3133
/// please use a more accurate method to produce a delay.
3234
#[inline]
3335
pub fn delay(cycles: u32) {
34-
call_asm!(__delay(cycles: u32));
36+
unsafe { inner::__delay(cycles) };
3537
}
3638

3739
/// A no-operation. Useful to prevent delay loops from being optimized away.
@@ -72,7 +74,7 @@ pub fn sev() {
7274
/// from cache or memory, after the instruction has been completed.
7375
#[inline]
7476
pub fn isb() {
75-
call_asm!(__isb())
77+
unsafe { self::inner::__isb() }
7678
}
7779

7880
/// Data Synchronization Barrier
@@ -84,7 +86,7 @@ pub fn isb() {
8486
/// * all cache and branch predictor maintenance operations before this instruction complete
8587
#[inline]
8688
pub fn dsb() {
87-
call_asm!(__dsb())
89+
unsafe { self::inner::__dsb() }
8890
}
8991

9092
/// Data Memory Barrier
@@ -94,7 +96,7 @@ pub fn dsb() {
9496
/// after the `DMB` instruction.
9597
#[inline]
9698
pub fn dmb() {
97-
call_asm!(__dmb())
99+
unsafe { self::inner::__dmb() }
98100
}
99101

100102
/// Test Target

cortex-m/src/asm/inner.rs

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

cortex-m/src/interrupt.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ unsafe impl<T: Nr + Copy> InterruptNumber for T {
3535
/// Disables all interrupts
3636
#[inline]
3737
pub fn disable() {
38-
call_asm!(__cpsid());
38+
unsafe { crate::asm::inner::__cpsid() };
3939
}
4040

4141
/// Enables all the interrupts
@@ -45,7 +45,7 @@ pub fn disable() {
4545
/// - Do not call this function inside an `interrupt::free` critical section
4646
#[inline]
4747
pub unsafe fn enable() {
48-
call_asm!(__cpsie());
48+
unsafe { crate::asm::inner::__cpsie() };
4949
}
5050

5151
/// Execute closure `f` in an interrupt-free context.

cortex-m/src/register/apsr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,6 @@ impl Apsr {
4949
/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature.
5050
#[inline]
5151
pub fn read() -> Apsr {
52-
let bits: u32 = call_asm!(__apsr_r() -> u32);
52+
let bits = unsafe { crate::asm::inner::__apsr_r() };
5353
Apsr { bits }
5454
}

cortex-m/src/register/control.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,13 +174,13 @@ impl Fpca {
174174
/// Reads the CPU register
175175
#[inline]
176176
pub fn read() -> Control {
177-
let bits: u32 = call_asm!(__control_r() -> u32);
177+
let bits = unsafe { crate::asm::inner::__control_r() };
178178
Control { bits }
179179
}
180180

181181
/// Writes to the CPU register.
182182
#[inline]
183183
pub unsafe fn write(control: Control) {
184184
let control = control.bits();
185-
call_asm!(__control_w(control: u32));
185+
unsafe { crate::asm::inner::__control_w(control) };
186186
}

cortex-m/src/register/msp.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
/// Reads the CPU register
44
#[inline]
55
pub fn read() -> u32 {
6-
call_asm!(__msp_r() -> u32)
6+
unsafe { crate::asm::inner::__msp_r() }
77
}
88

99
/// Writes `bits` to the CPU register
1010
#[inline]
1111
#[deprecated = "calling this function invokes Undefined Behavior, consider asm::bootstrap as an alternative"]
1212
pub unsafe fn write(bits: u32) {
13-
call_asm!(__msp_w(bits: u32));
13+
unsafe { crate::asm::inner::__msp_w(bits) }
1414
}
1515

1616
/// Reads the Non-Secure CPU register from Secure state.

0 commit comments

Comments
 (0)