aboutsummaryrefslogtreecommitdiff
path: root/src/asm.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/asm.rs')
-rw-r--r--src/asm.rs209
1 files changed, 209 insertions, 0 deletions
diff --git a/src/asm.rs b/src/asm.rs
new file mode 100644
index 0000000..4dc1ab0
--- /dev/null
+++ b/src/asm.rs
@@ -0,0 +1,209 @@
+//! Miscellaneous assembly instructions
+
+// When inline assembly is enabled, pull in the assembly routines here. `call_asm!` will invoke
+// these routines.
+#[cfg(feature = "inline-asm")]
+#[path = "../asm/inline.rs"]
+pub(crate) mod inline;
+
+/// Puts the processor in Debug state. Debuggers can pick this up as a "breakpoint".
+///
+/// **NOTE** calling `bkpt` when the processor is not connected to a debugger will cause an
+/// exception.
+#[inline(always)]
+pub fn bkpt() {
+ call_asm!(__bkpt());
+}
+
+/// Blocks the program for *at least* `cycles` CPU cycles.
+///
+/// This is implemented in assembly so its execution time is independent of the optimization
+/// level, however it is dependent on the specific architecture and core configuration.
+///
+/// NOTE that the delay can take much longer if interrupts are serviced during its execution
+/// and the execution time may vary with other factors. This delay is mainly useful for simple
+/// timer-less initialization of peripherals if and only if accurate timing is not essential. In
+/// any other case please use a more accurate method to produce a delay.
+#[inline]
+pub fn delay(cycles: u32) {
+ call_asm!(__delay(cycles: u32));
+}
+
+/// A no-operation. Useful to prevent delay loops from being optimized away.
+#[inline]
+pub fn nop() {
+ call_asm!(__nop());
+}
+
+/// Generate an Undefined Instruction exception.
+///
+/// Can be used as a stable alternative to `core::intrinsics::abort`.
+#[inline]
+pub fn udf() -> ! {
+ call_asm!(__udf() -> !)
+}
+
+/// Wait For Event
+#[inline]
+pub fn wfe() {
+ call_asm!(__wfe())
+}
+
+/// Wait For Interrupt
+#[inline]
+pub fn wfi() {
+ call_asm!(__wfi())
+}
+
+/// Send Event
+#[inline]
+pub fn sev() {
+ call_asm!(__sev())
+}
+
+/// Instruction Synchronization Barrier
+///
+/// Flushes the pipeline in the processor, so that all instructions following the `ISB` are fetched
+/// from cache or memory, after the instruction has been completed.
+#[inline]
+pub fn isb() {
+ call_asm!(__isb())
+}
+
+/// Data Synchronization Barrier
+///
+/// Acts as a special kind of memory barrier. No instruction in program order after this instruction
+/// can execute until this instruction completes. This instruction completes only when both:
+///
+/// * any explicit memory access made before this instruction is complete
+/// * all cache and branch predictor maintenance operations before this instruction complete
+#[inline]
+pub fn dsb() {
+ call_asm!(__dsb())
+}
+
+/// Data Memory Barrier
+///
+/// Ensures that all explicit memory accesses that appear in program order before the `DMB`
+/// instruction are observed before any explicit memory accesses that appear in program order
+/// after the `DMB` instruction.
+#[inline]
+pub fn dmb() {
+ call_asm!(__dmb())
+}
+
+/// Test Target
+///
+/// Queries the Security state and access permissions of a memory location.
+/// Returns a Test Target Response Payload (cf section D1.2.215 of
+/// Armv8-M Architecture Reference Manual).
+#[inline]
+#[cfg(armv8m)]
+// The __tt function does not dereference the pointer received.
+#[allow(clippy::not_unsafe_ptr_arg_deref)]
+pub fn tt(addr: *mut u32) -> u32 {
+ let addr = addr as u32;
+ call_asm!(__tt(addr: u32) -> u32)
+}
+
+/// Test Target Unprivileged
+///
+/// Queries the Security state and access permissions of a memory location for an unprivileged
+/// access to that location.
+/// Returns a Test Target Response Payload (cf section D1.2.215 of
+/// Armv8-M Architecture Reference Manual).
+#[inline]
+#[cfg(armv8m)]
+// The __ttt function does not dereference the pointer received.
+#[allow(clippy::not_unsafe_ptr_arg_deref)]
+pub fn ttt(addr: *mut u32) -> u32 {
+ let addr = addr as u32;
+ call_asm!(__ttt(addr: u32) -> u32)
+}
+
+/// Test Target Alternate Domain
+///
+/// Queries the Security state and access permissions of a memory location for a Non-Secure access
+/// to that location. This instruction is only valid when executing in Secure state and is
+/// undefined if used from Non-Secure state.
+/// Returns a Test Target Response Payload (cf section D1.2.215 of
+/// Armv8-M Architecture Reference Manual).
+#[inline]
+#[cfg(armv8m)]
+// The __tta function does not dereference the pointer received.
+#[allow(clippy::not_unsafe_ptr_arg_deref)]
+pub fn tta(addr: *mut u32) -> u32 {
+ let addr = addr as u32;
+ call_asm!(__tta(addr: u32) -> u32)
+}
+
+/// Test Target Alternate Domain Unprivileged
+///
+/// Queries the Security state and access permissions of a memory location for a Non-Secure and
+/// unprivileged access to that location. This instruction is only valid when executing in Secure
+/// state and is undefined if used from Non-Secure state.
+/// Returns a Test Target Response Payload (cf section D1.2.215 of
+/// Armv8-M Architecture Reference Manual).
+#[inline]
+#[cfg(armv8m)]
+// The __ttat function does not dereference the pointer received.
+#[allow(clippy::not_unsafe_ptr_arg_deref)]
+pub fn ttat(addr: *mut u32) -> u32 {
+ let addr = addr as u32;
+ call_asm!(__ttat(addr: u32) -> u32)
+}
+
+/// Branch and Exchange Non-secure
+///
+/// See section C2.4.26 of Armv8-M Architecture Reference Manual for details.
+/// Undefined if executed in Non-Secure state.
+#[inline]
+#[cfg(armv8m)]
+pub unsafe fn bx_ns(addr: u32) {
+ call_asm!(__bxns(addr: u32));
+}
+
+/// Semihosting syscall.
+///
+/// This method is used by cortex-m-semihosting to provide semihosting syscalls.
+#[inline]
+pub unsafe fn semihosting_syscall(nr: u32, arg: u32) -> u32 {
+ call_asm!(__sh_syscall(nr: u32, arg: u32) -> u32)
+}
+
+/// Bootstrap.
+///
+/// Clears CONTROL.SPSEL (setting the main stack to be the active stack),
+/// updates the main stack pointer to the address in `msp`, then jumps
+/// to the address in `rv`.
+///
+/// # Safety
+///
+/// `msp` and `rv` must point to valid stack memory and executable code,
+/// respectively.
+#[inline]
+pub unsafe fn bootstrap(msp: *const u32, rv: *const u32) -> ! {
+ // Ensure thumb mode is set.
+ let rv = (rv as u32) | 1;
+ let msp = msp as u32;
+ call_asm!(__bootstrap(msp: u32, rv: u32) -> !);
+}
+
+/// Bootload.
+///
+/// Reads the initial stack pointer value and reset vector from
+/// the provided vector table address, sets the active stack to
+/// the main stack, sets the main stack pointer to the new initial
+/// stack pointer, then jumps to the reset vector.
+///
+/// # Safety
+///
+/// The provided `vector_table` must point to a valid vector
+/// table, with a valid stack pointer as the first word and
+/// a valid reset vector as the second word.
+#[inline]
+pub unsafe fn bootload(vector_table: *const u32) -> ! {
+ let msp = core::ptr::read_volatile(vector_table);
+ let rv = core::ptr::read_volatile(vector_table.offset(1));
+ bootstrap(msp as *const u32, rv as *const u32);
+}