cortex_m/
asm.rs

1//! Miscellaneous assembly instructions
2
3// When inline assembly is enabled, pull in the assembly routines here. `call_asm!` will invoke
4// these routines.
5#[cfg(feature = "inline-asm")]
6#[path = "../asm/inline.rs"]
7pub(crate) mod inline;
8
9/// Puts the processor in Debug state. Debuggers can pick this up as a "breakpoint".
10///
11/// **NOTE** calling `bkpt` when the processor is not connected to a debugger will cause an
12/// exception.
13#[inline(always)]
14pub fn bkpt() {
15    call_asm!(__bkpt());
16}
17
18/// Blocks the program for *at least* `cycles` CPU cycles.
19///
20/// This is implemented in assembly so its execution time is independent of the optimization
21/// level, however it is dependent on the specific architecture and core configuration.
22///
23/// NOTE that the delay can take much longer if interrupts are serviced during its execution
24/// and the execution time may vary with other factors. This delay is mainly useful for simple
25/// timer-less initialization of peripherals if and only if accurate timing is not essential. In
26/// any other case please use a more accurate method to produce a delay.
27#[inline]
28pub fn delay(cycles: u32) {
29    call_asm!(__delay(cycles: u32));
30}
31
32/// A no-operation. Useful to prevent delay loops from being optimized away.
33#[inline]
34pub fn nop() {
35    call_asm!(__nop());
36}
37
38/// Generate an Undefined Instruction exception.
39///
40/// Can be used as a stable alternative to `core::intrinsics::abort`.
41#[inline]
42pub fn udf() -> ! {
43    call_asm!(__udf() -> !)
44}
45
46/// Wait For Event
47#[inline]
48pub fn wfe() {
49    call_asm!(__wfe())
50}
51
52/// Wait For Interrupt
53#[inline]
54pub fn wfi() {
55    call_asm!(__wfi())
56}
57
58/// Send Event
59#[inline]
60pub fn sev() {
61    call_asm!(__sev())
62}
63
64/// Instruction Synchronization Barrier
65///
66/// Flushes the pipeline in the processor, so that all instructions following the `ISB` are fetched
67/// from cache or memory, after the instruction has been completed.
68#[inline]
69pub fn isb() {
70    call_asm!(__isb())
71}
72
73/// Data Synchronization Barrier
74///
75/// Acts as a special kind of memory barrier. No instruction in program order after this instruction
76/// can execute until this instruction completes. This instruction completes only when both:
77///
78///  * any explicit memory access made before this instruction is complete
79///  * all cache and branch predictor maintenance operations before this instruction complete
80#[inline]
81pub fn dsb() {
82    call_asm!(__dsb())
83}
84
85/// Data Memory Barrier
86///
87/// Ensures that all explicit memory accesses that appear in program order before the `DMB`
88/// instruction are observed before any explicit memory accesses that appear in program order
89/// after the `DMB` instruction.
90#[inline]
91pub fn dmb() {
92    call_asm!(__dmb())
93}
94
95/// Test Target
96///
97/// Queries the Security state and access permissions of a memory location.
98/// Returns a Test Target Response Payload (cf section D1.2.215 of
99/// Armv8-M Architecture Reference Manual).
100#[inline]
101#[cfg(armv8m)]
102// The __tt function does not dereference the pointer received.
103#[allow(clippy::not_unsafe_ptr_arg_deref)]
104pub fn tt(addr: *mut u32) -> u32 {
105    let addr = addr as u32;
106    call_asm!(__tt(addr: u32) -> u32)
107}
108
109/// Test Target Unprivileged
110///
111/// Queries the Security state and access permissions of a memory location for an unprivileged
112/// access to that location.
113/// Returns a Test Target Response Payload (cf section D1.2.215 of
114/// Armv8-M Architecture Reference Manual).
115#[inline]
116#[cfg(armv8m)]
117// The __ttt function does not dereference the pointer received.
118#[allow(clippy::not_unsafe_ptr_arg_deref)]
119pub fn ttt(addr: *mut u32) -> u32 {
120    let addr = addr as u32;
121    call_asm!(__ttt(addr: u32) -> u32)
122}
123
124/// Test Target Alternate Domain
125///
126/// Queries the Security state and access permissions of a memory location for a Non-Secure access
127/// to that location. This instruction is only valid when executing in Secure state and is
128/// undefined if used from Non-Secure state.
129/// Returns a Test Target Response Payload (cf section D1.2.215 of
130/// Armv8-M Architecture Reference Manual).
131#[inline]
132#[cfg(armv8m)]
133// The __tta function does not dereference the pointer received.
134#[allow(clippy::not_unsafe_ptr_arg_deref)]
135pub fn tta(addr: *mut u32) -> u32 {
136    let addr = addr as u32;
137    call_asm!(__tta(addr: u32) -> u32)
138}
139
140/// Test Target Alternate Domain Unprivileged
141///
142/// Queries the Security state and access permissions of a memory location for a Non-Secure and
143/// unprivileged access to that location. This instruction is only valid when executing in Secure
144/// state and is undefined if used from Non-Secure state.
145/// Returns a Test Target Response Payload (cf section D1.2.215 of
146/// Armv8-M Architecture Reference Manual).
147#[inline]
148#[cfg(armv8m)]
149// The __ttat function does not dereference the pointer received.
150#[allow(clippy::not_unsafe_ptr_arg_deref)]
151pub fn ttat(addr: *mut u32) -> u32 {
152    let addr = addr as u32;
153    call_asm!(__ttat(addr: u32) -> u32)
154}
155
156/// Branch and Exchange Non-secure
157///
158/// See section C2.4.26 of Armv8-M Architecture Reference Manual for details.
159/// Undefined if executed in Non-Secure state.
160#[inline]
161#[cfg(armv8m)]
162pub unsafe fn bx_ns(addr: u32) {
163    call_asm!(__bxns(addr: u32));
164}
165
166/// Semihosting syscall.
167///
168/// This method is used by cortex-m-semihosting to provide semihosting syscalls.
169#[inline]
170pub unsafe fn semihosting_syscall(nr: u32, arg: u32) -> u32 {
171    call_asm!(__sh_syscall(nr: u32, arg: u32) -> u32)
172}
173
174/// Bootstrap.
175///
176/// Clears CONTROL.SPSEL (setting the main stack to be the active stack),
177/// updates the main stack pointer to the address in `msp`, then jumps
178/// to the address in `rv`.
179///
180/// # Safety
181///
182/// `msp` and `rv` must point to valid stack memory and executable code,
183/// respectively.
184#[inline]
185pub unsafe fn bootstrap(msp: *const u32, rv: *const u32) -> ! {
186    // Ensure thumb mode is set.
187    let rv = (rv as u32) | 1;
188    let msp = msp as u32;
189    call_asm!(__bootstrap(msp: u32, rv: u32) -> !);
190}
191
192/// Bootload.
193///
194/// Reads the initial stack pointer value and reset vector from
195/// the provided vector table address, sets the active stack to
196/// the main stack, sets the main stack pointer to the new initial
197/// stack pointer, then jumps to the reset vector.
198///
199/// # Safety
200///
201/// The provided `vector_table` must point to a valid vector
202/// table, with a valid stack pointer as the first word and
203/// a valid reset vector as the second word.
204#[inline]
205pub unsafe fn bootload(vector_table: *const u32) -> ! {
206    let msp = core::ptr::read_volatile(vector_table);
207    let rv = core::ptr::read_volatile(vector_table.offset(1));
208    bootstrap(msp as *const u32, rv as *const u32);
209}