aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Adam Greig <adam@adamgreig.com> 2022-02-21 19:57:18 +0000
committerGravatar Adam Greig <adam@adamgreig.com> 2022-02-24 01:44:11 +0000
commit894f2aabdbd65f85eecf25debc2326f0387863c7 (patch)
treef08ad0ca10df764c5b29549421e874c4c3512bec
parent9e8dd294b04510d727d50039a7f84292789aed0e (diff)
downloadcortex-m-894f2aabdbd65f85eecf25debc2326f0387863c7.tar.gz
cortex-m-894f2aabdbd65f85eecf25debc2326f0387863c7.tar.zst
cortex-m-894f2aabdbd65f85eecf25debc2326f0387863c7.zip
Remove outlined asm, replace with stable inline asm.
-rw-r--r--.github/bors.toml2
-rw-r--r--.github/workflows/ci.yml2
-rw-r--r--CHANGELOG.md4
-rw-r--r--Cargo.toml1
-rw-r--r--README.md2
-rw-r--r--asm-toolchain1
-rw-r--r--asm/inline.rs448
-rw-r--r--asm/lib.rs143
-rw-r--r--bin/thumbv6m-none-eabi-lto.abin11196 -> 0 bytes
-rw-r--r--bin/thumbv6m-none-eabi.abin14576 -> 0 bytes
-rw-r--r--bin/thumbv7em-none-eabi-lto.abin15280 -> 0 bytes
-rw-r--r--bin/thumbv7em-none-eabi.abin19336 -> 0 bytes
-rw-r--r--bin/thumbv7em-none-eabihf-lto.abin16104 -> 0 bytes
-rw-r--r--bin/thumbv7em-none-eabihf.abin20480 -> 0 bytes
-rw-r--r--bin/thumbv7m-none-eabi-lto.abin14244 -> 0 bytes
-rw-r--r--bin/thumbv7m-none-eabi.abin18068 -> 0 bytes
-rw-r--r--bin/thumbv8m.base-none-eabi-lto.abin14280 -> 0 bytes
-rw-r--r--bin/thumbv8m.base-none-eabi.abin18680 -> 0 bytes
-rw-r--r--bin/thumbv8m.main-none-eabi-lto.abin18672 -> 0 bytes
-rw-r--r--bin/thumbv8m.main-none-eabi.abin24408 -> 0 bytes
-rw-r--r--bin/thumbv8m.main-none-eabihf-lto.abin19508 -> 0 bytes
-rw-r--r--bin/thumbv8m.main-none-eabihf.abin25524 -> 0 bytes
-rw-r--r--build.rs24
-rw-r--r--cortex-m-semihosting/CHANGELOG.md2
-rw-r--r--cortex-m-semihosting/README.md2
l---------cortex-m-semihosting/bin1
-rw-r--r--cortex-m-semihosting/build.rs16
-rw-r--r--cortex-m-semihosting/src/lib.rs18
-rw-r--r--panic-semihosting/CHANGELOG.md2
-rw-r--r--panic-semihosting/Cargo.toml2
-rw-r--r--panic-semihosting/README.md2
-rw-r--r--panic-semihosting/src/lib.rs8
-rw-r--r--src/asm.rs139
-rw-r--r--src/call_asm.rs24
-rw-r--r--src/interrupt.rs19
-rw-r--r--src/lib.rs40
-rw-r--r--src/peripheral/mod.rs2
-rw-r--r--src/register/apsr.rs9
-rw-r--r--src/register/basepri.rs24
-rw-r--r--src/register/basepri_max.rs23
-rw-r--r--src/register/control.rs23
-rw-r--r--src/register/faultmask.rs7
-rw-r--r--src/register/fpscr.rs7
-rw-r--r--src/register/lr.rs15
-rw-r--r--src/register/mod.rs5
-rw-r--r--src/register/msp.rs21
-rw-r--r--src/register/msplim.rs8
-rw-r--r--src/register/pc.rs15
-rw-r--r--src/register/primask.rs7
-rw-r--r--src/register/psp.rs13
-rw-r--r--src/register/psplim.rs8
-rw-r--r--xtask/src/lib.rs195
-rw-r--r--xtask/src/main.rs6
-rw-r--r--xtask/tests/ci.rs16
54 files changed, 301 insertions, 1005 deletions
diff --git a/.github/bors.toml b/.github/bors.toml
index 4402e95..c12731a 100644
--- a/.github/bors.toml
+++ b/.github/bors.toml
@@ -3,7 +3,7 @@ delete_merged_branches = true
required_approvals = 1
status = [
"ci-linux (stable)",
- "ci-linux (1.42.0)",
+ "ci-linux (1.59.0)",
"rt-ci-linux (stable)",
"rt-ci-linux (1.42.0)",
"rt-ci-other-os (macOS-latest)",
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 8caebd0..701e46a 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,7 +16,7 @@ jobs:
include:
# Test MSRV
- - rust: 1.42.0
+ - rust: 1.59.0
# Test nightly but don't fail
- rust: nightly
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 421dce7..2349607 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,8 +21,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Fixed
- Fixed `singleton!()` statics sometimes ending up in `.data` instead of `.bss` (#364, #380).
+### Changed
+- Inline assembly is now always used, requiring Rust 1.59.
+
### Removed
- removed all peripherals `ptr()` functions in favor of the associated constant `PTR` (#385).
+- removed `inline-asm` feature which is now always enabled
## [v0.7.4] - 2021-12-31
diff --git a/Cargo.toml b/Cargo.toml
index 8527a89..ebbfdfe 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,7 +29,6 @@ optional = true
[features]
cm7 = []
cm7-r0p1 = ["cm7"]
-inline-asm = []
linker-plugin-lto = []
std = []
diff --git a/README.md b/README.md
index df9fd52..a045765 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@ This project is developed and maintained by the [Cortex-M team][team].
## Minimum Supported Rust Version (MSRV)
-This crate is guaranteed to compile on stable Rust 1.42 and up. It might compile with older versions but that may change in any new patch release.
+This crate is guaranteed to compile on stable Rust 1.59 and up. It might compile with older versions but that may change in any new patch release.
## License
diff --git a/asm-toolchain b/asm-toolchain
deleted file mode 100644
index cc5dbb2..0000000
--- a/asm-toolchain
+++ /dev/null
@@ -1 +0,0 @@
-nightly-2021-12-16
diff --git a/asm/inline.rs b/asm/inline.rs
deleted file mode 100644
index bbc04d2..0000000
--- a/asm/inline.rs
+++ /dev/null
@@ -1,448 +0,0 @@
-//! 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.
-
-use core::arch::asm;
-use core::sync::atomic::{compiler_fence, Ordering};
-
-#[inline(always)]
-pub unsafe fn __bkpt() {
- asm!("bkpt", options(nomem, nostack, preserves_flags));
-}
-
-#[inline(always)]
-pub unsafe fn __control_r() -> u32 {
- let r;
- asm!("mrs {}, CONTROL", out(reg) r, options(nomem, nostack, preserves_flags));
- r
-}
-
-#[inline(always)]
-pub unsafe fn __control_w(w: u32) {
- // ISB is required after writing to CONTROL,
- // per ARM architectural requirements (see Application Note 321).
- asm!(
- "msr CONTROL, {}",
- "isb",
- in(reg) w,
- options(nomem, nostack, preserves_flags),
- );
-
- // Ensure memory accesses are not reordered around the CONTROL update.
- compiler_fence(Ordering::SeqCst);
-}
-
-#[inline(always)]
-pub unsafe fn __cpsid() {
- asm!("cpsid i", options(nomem, nostack, preserves_flags));
-
- // Ensure no subsequent memory accesses are reordered to before interrupts are disabled.
- compiler_fence(Ordering::SeqCst);
-}
-
-#[inline(always)]
-pub unsafe fn __cpsie() {
- // Ensure no preceeding memory accesses are reordered to after interrupts are enabled.
- compiler_fence(Ordering::SeqCst);
-
- asm!("cpsie i", options(nomem, nostack, preserves_flags));
-}
-
-#[inline(always)]
-pub unsafe fn __delay(cyc: u32) {
- // The loop will normally take 3 to 4 CPU cycles per iteration, but superscalar cores
- // (eg. Cortex-M7) can potentially do it in 2, so we use that as the lower bound, since delaying
- // for more cycles is okay.
- // Add 1 to prevent an integer underflow which would cause a long freeze
- let real_cyc = 1 + cyc / 2;
- asm!(
- // Use local labels to avoid R_ARM_THM_JUMP8 relocations which fail on thumbv6m.
- "1:",
- "subs {}, #1",
- "bne 1b",
- inout(reg) real_cyc => _,
- options(nomem, nostack),
- );
-}
-
-#[inline(always)]
-pub unsafe fn __dmb() {
- compiler_fence(Ordering::SeqCst);
- asm!("dmb", options(nomem, nostack, preserves_flags));
- compiler_fence(Ordering::SeqCst);
-}
-
-#[inline(always)]
-pub unsafe fn __dsb() {
- compiler_fence(Ordering::SeqCst);
- asm!("dsb", options(nomem, nostack, preserves_flags));
- compiler_fence(Ordering::SeqCst);
-}
-
-#[inline(always)]
-pub unsafe fn __isb() {
- compiler_fence(Ordering::SeqCst);
- asm!("isb", options(nomem, nostack, preserves_flags));
- compiler_fence(Ordering::SeqCst);
-}
-
-#[inline(always)]
-pub unsafe fn __msp_r() -> u32 {
- let r;
- asm!("mrs {}, MSP", out(reg) r, options(nomem, nostack, preserves_flags));
- r
-}
-
-#[inline(always)]
-pub unsafe fn __msp_w(val: u32) {
- // Technically is writing to the stack pointer "not pushing any data to the stack"?
- // In any event, if we don't set `nostack` here, this method is useless as the new
- // stack value is immediately mutated by returning. Really this is just not a good
- // method and its higher-level use is marked as deprecated in cortex-m.
- asm!("msr MSP, {}", in(reg) val, options(nomem, nostack, preserves_flags));
-}
-
-// NOTE: No FFI shim, this requires inline asm.
-#[inline(always)]
-pub unsafe fn __apsr_r() -> u32 {
- let r;
- asm!("mrs {}, APSR", out(reg) r, options(nomem, nostack, preserves_flags));
- 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", options(nomem, nostack, preserves_flags));
-}
-
-// NOTE: No FFI shim, this requires inline asm.
-#[inline(always)]
-pub unsafe fn __pc_r() -> u32 {
- let r;
- asm!("mov {}, pc", out(reg) r, options(nomem, nostack, preserves_flags));
- r
-}
-
-// NOTE: No FFI shim, this requires inline asm.
-#[inline(always)]
-pub unsafe fn __pc_w(val: u32) {
- asm!("mov pc, {}", in(reg) val, options(nomem, nostack, preserves_flags));
-}
-
-// NOTE: No FFI shim, this requires inline asm.
-#[inline(always)]
-pub unsafe fn __lr_r() -> u32 {
- let r;
- asm!("mov {}, lr", out(reg) r, options(nomem, nostack, preserves_flags));
- r
-}
-
-// NOTE: No FFI shim, this requires inline asm.
-#[inline(always)]
-pub unsafe fn __lr_w(val: u32) {
- asm!("mov lr, {}", in(reg) val, options(nomem, nostack, preserves_flags));
-}
-
-#[inline(always)]
-pub unsafe fn __primask_r() -> u32 {
- let r;
- asm!("mrs {}, PRIMASK", out(reg) r, options(nomem, nostack, preserves_flags));
- r
-}
-
-#[inline(always)]
-pub unsafe fn __psp_r() -> u32 {
- let r;
- asm!("mrs {}, PSP", out(reg) r, options(nomem, nostack, preserves_flags));
- r
-}
-
-#[inline(always)]
-pub unsafe fn __psp_w(val: u32) {
- // See comment on __msp_w. Unlike MSP, there are legitimate use-cases for modifying PSP
- // if MSP is currently being used as the stack pointer.
- asm!("msr PSP, {}", in(reg) val, options(nomem, nostack, preserves_flags));
-}
-
-#[inline(always)]
-pub unsafe fn __sev() {
- asm!("sev", options(nomem, nostack, preserves_flags));
-}
-
-#[inline(always)]
-pub unsafe fn __udf() -> ! {
- asm!("udf #0", options(noreturn, nomem, nostack, preserves_flags));
-}
-
-#[inline(always)]
-pub unsafe fn __wfe() {
- asm!("wfe", options(nomem, nostack, preserves_flags));
-}
-
-#[inline(always)]
-pub unsafe fn __wfi() {
- asm!("wfi", options(nomem, nostack, preserves_flags));
-}
-
-/// Semihosting syscall.
-#[inline(always)]
-pub unsafe fn __sh_syscall(mut nr: u32, arg: u32) -> u32 {
- asm!("bkpt #0xab", inout("r0") nr, in("r1") arg, options(nomem, nostack, preserves_flags));
- nr
-}
-
-/// Set CONTROL.SPSEL to 0, write `msp` to MSP, branch to `rv`.
-#[inline(always)]
-pub unsafe fn __bootstrap(msp: u32, rv: u32) -> ! {
- asm!(
- "mrs {tmp}, CONTROL",
- "bics {tmp}, {spsel}",
- "msr CONTROL, {tmp}",
- "isb",
- "msr MSP, {msp}",
- "bx {rv}",
- // `out(reg) _` is not permitted in a `noreturn` asm! call,
- // so instead use `in(reg) 0` and don't restore it afterwards.
- tmp = in(reg) 0,
- spsel = in(reg) 2,
- msp = in(reg) msp,
- rv = in(reg) rv,
- options(noreturn, nomem, nostack),
- );
-}
-
-// v7m *AND* v8m.main, but *NOT* v8m.base
-#[cfg(any(armv7m, armv8m_main))]
-pub use self::v7m::*;
-#[cfg(any(armv7m, armv8m_main))]
-mod v7m {
- use core::arch::asm;
- use core::sync::atomic::{compiler_fence, Ordering};
-
- #[inline(always)]
- pub unsafe fn __basepri_max(val: u8) {
- asm!("msr BASEPRI_MAX, {}", in(reg) val, options(nomem, nostack, preserves_flags));
- }
-
- #[inline(always)]
- pub unsafe fn __basepri_r() -> u8 {
- let r;
- asm!("mrs {}, BASEPRI", out(reg) r, options(nomem, nostack, preserves_flags));
- r
- }
-
- #[inline(always)]
- pub unsafe fn __basepri_w(val: u8) {
- asm!("msr BASEPRI, {}", in(reg) val, options(nomem, nostack, preserves_flags));
- }
-
- #[inline(always)]
- pub unsafe fn __faultmask_r() -> u32 {
- let r;
- asm!("mrs {}, FAULTMASK", out(reg) r, options(nomem, nostack, preserves_flags));
- r
- }
-
- #[inline(always)]
- pub unsafe fn __enable_icache() {
- asm!(
- "ldr {0}, =0xE000ED14", // CCR
- "mrs {2}, PRIMASK", // save critical nesting info
- "cpsid i", // mask interrupts
- "ldr {1}, [{0}]", // read CCR
- "orr.w {1}, {1}, #(1 << 17)", // Set bit 17, IC
- "str {1}, [{0}]", // write it back
- "dsb", // ensure store completes
- "isb", // synchronize pipeline
- "msr PRIMASK, {2}", // unnest critical section
- out(reg) _,
- out(reg) _,
- out(reg) _,
- options(nostack),
- );
- compiler_fence(Ordering::SeqCst);
- }
-
- #[inline(always)]
- pub unsafe fn __enable_dcache() {
- asm!(
- "ldr {0}, =0xE000ED14", // CCR
- "mrs {2}, PRIMASK", // save critical nesting info
- "cpsid i", // mask interrupts
- "ldr {1}, [{0}]", // read CCR
- "orr.w {1}, {1}, #(1 << 16)", // Set bit 16, DC
- "str {1}, [{0}]", // write it back
- "dsb", // ensure store completes
- "isb", // synchronize pipeline
- "msr PRIMASK, {2}", // unnest critical section
- out(reg) _,
- out(reg) _,
- out(reg) _,
- options(nostack),
- );
- compiler_fence(Ordering::SeqCst);
- }
-}
-
-#[cfg(armv7em)]
-pub use self::v7em::*;
-#[cfg(armv7em)]
-mod v7em {
- use core::arch::asm;
-
- #[inline(always)]
- pub unsafe fn __basepri_max_cm7_r0p1(val: u8) {
- asm!(
- "mrs {1}, PRIMASK",
- "cpsid i",
- "tst.w {1}, #1",
- "msr BASEPRI_MAX, {0}",
- "it ne",
- "bxne lr",
- "cpsie i",
- in(reg) val,
- out(reg) _,
- options(nomem, nostack, preserves_flags),
- );
- }
-
- #[inline(always)]
- pub unsafe fn __basepri_w_cm7_r0p1(val: u8) {
- asm!(
- "mrs {1}, PRIMASK",
- "cpsid i",
- "tst.w {1}, #1",
- "msr BASEPRI, {0}",
- "it ne",
- "bxne lr",
- "cpsie i",
- in(reg) val,
- out(reg) _,
- options(nomem, nostack, preserves_flags),
- );
- }
-}
-
-#[cfg(armv8m)]
-pub use self::v8m::*;
-/// Baseline and Mainline.
-#[cfg(armv8m)]
-mod v8m {
- use core::arch::asm;
-
- #[inline(always)]
- pub unsafe fn __tt(mut target: u32) -> u32 {
- asm!(
- "tt {target}, {target}",
- target = inout(reg) target,
- options(nomem, nostack, preserves_flags),
- );
- target
- }
-
- #[inline(always)]
- pub unsafe fn __ttt(mut target: u32) -> u32 {
- asm!(
- "ttt {target}, {target}",
- target = inout(reg) target,
- options(nomem, nostack, preserves_flags),
- );
- target
- }
-
- #[inline(always)]
- pub unsafe fn __tta(mut target: u32) -> u32 {
- asm!(
- "tta {target}, {target}",
- target = inout(reg) target,
- options(nomem, nostack, preserves_flags),
- );
- target
- }
-
- #[inline(always)]
- pub unsafe fn __ttat(mut target: u32) -> u32 {
- asm!(
- "ttat {target}, {target}",
- target = inout(reg) target,
- options(nomem, nostack, preserves_flags),
- );
- target
- }
-
- #[inline(always)]
- pub unsafe fn __msp_ns_r() -> u32 {
- let r;
- asm!("mrs {}, MSP_NS", out(reg) r, options(nomem, nostack, preserves_flags));
- r
- }
-
- #[inline(always)]
- pub unsafe fn __msp_ns_w(val: u32) {
- asm!("msr MSP_NS, {}", in(reg) val, options(nomem, nostack, preserves_flags));
- }
-
- #[inline(always)]
- pub unsafe fn __bxns(val: u32) {
- asm!("BXNS {}", in(reg) val, options(nomem, nostack, preserves_flags));
- }
-}
-
-#[cfg(armv8m_main)]
-pub use self::v8m_main::*;
-/// Mainline only.
-#[cfg(armv8m_main)]
-mod v8m_main {
- use core::arch::asm;
-
- #[inline(always)]
- pub unsafe fn __msplim_r() -> u32 {
- let r;
- asm!("mrs {}, MSPLIM", out(reg) r, options(nomem, nostack, preserves_flags));
- r
- }
-
- #[inline(always)]
- pub unsafe fn __msplim_w(val: u32) {
- asm!("msr MSPLIM, {}", in(reg) val, options(nomem, nostack, preserves_flags));
- }
-
- #[inline(always)]
- pub unsafe fn __psplim_r() -> u32 {
- let r;
- asm!("mrs {}, PSPLIM", out(reg) r, options(nomem, nostack, preserves_flags));
- r
- }
-
- #[inline(always)]
- pub unsafe fn __psplim_w(val: u32) {
- asm!("msr PSPLIM, {}", in(reg) val, options(nomem, nostack, preserves_flags));
- }
-}
-
-#[cfg(has_fpu)]
-pub use self::fpu::*;
-/// All targets with FPU.
-#[cfg(has_fpu)]
-mod fpu {
- use core::arch::asm;
-
- #[inline(always)]
- pub unsafe fn __fpscr_r() -> u32 {
- let r;
- asm!("vmrs {}, fpscr", out(reg) r, options(nomem, nostack, preserves_flags));
- r
- }
-
- #[inline(always)]
- pub unsafe fn __fpscr_w(val: u32) {
- asm!("vmsr fpscr, {}", in(reg) val, options(nomem, nostack));
- }
-}
diff --git a/asm/lib.rs b/asm/lib.rs
deleted file mode 100644
index 48f3dc2..0000000
--- a/asm/lib.rs
+++ /dev/null
@@ -1,143 +0,0 @@
-//! FFI shim around the inline assembly in `inline.rs`.
-//!
-//! We use this file to precompile some assembly stubs into the static libraries you can find in
-//! `bin`. Apps using the `cortex-m` crate then link against those static libraries and don't need
-//! to build this file themselves.
-//!
-//! Nowadays the assembly stubs are no longer actual assembly files, but actually just this small
-//! Rust crate that uses unstable inline assembly, coupled with the `xtask` tool to invoke rustc
-//! and build the files.
-//!
-//! Precompiling this to a static lib allows users to call assembly routines from stable Rust, but
-//! also perform [linker plugin LTO] with the precompiled artifacts to completely inline the
-//! assembly routines into their code, which brings the "outline assembly" on par with "real" inline
-//! assembly.
-//!
-//! For developers and contributors to `cortex-m`, this setup means that they don't have to install
-//! any binutils, assembler, or C compiler to hack on the crate. All they need is to run `cargo
-//! xtask assemble` to rebuild the archives from this file.
-//!
-//! Cool, right?
-//!
-//! # Rust version management
-//!
-//! Since inline assembly is still unstable, and we want to ensure that the created blobs are
-//! up-to-date in CI, we have to pin the nightly version we use for this. The nightly toolchain is
-//! stored in `asm-toolchain`.
-//!
-//! The `cargo xtask` automation will automatically install the `asm-toolchain` as well as all
-//! Cortex-M targets needed to generate the blobs.
-//!
-//! [linker plugin LTO]: https://doc.rust-lang.org/stable/rustc/linker-plugin-lto.html
-
-#![feature(asm)]
-#![no_std]
-#![crate_type = "staticlib"]
-#![deny(warnings)]
-// Don't warn about feature(asm) being stable on Rust >= 1.59.0
-#![allow(stable_features)]
-
-mod inline;
-
-macro_rules! shims {
- (
- $( fn $name:ident( $($arg:ident: $argty:ty),* ) $(-> $ret:ty)?; )+
- ) => {
- $(
- #[no_mangle]
- pub unsafe extern "C" fn $name(
- $($arg: $argty),*
- ) $(-> $ret)? {
- crate::inline::$name($($arg),*)
- }
- )+
- };
-}
-
-shims! {
- fn __bkpt();
- fn __control_r() -> u32;
- fn __control_w(w: u32);
- fn __cpsid();
- fn __cpsie();
- fn __delay(cyc: u32);
- fn __dmb();
- fn __dsb();
- fn __isb();
- fn __msp_r() -> u32;
- fn __msp_w(val: u32);
- fn __nop();
- fn __primask_r() -> u32;
- fn __psp_r() -> u32;
- fn __psp_w(val: u32);
- fn __sev();
- fn __udf() -> !;
- fn __wfe();
- fn __wfi();
- fn __sh_syscall(nr: u32, arg: u32) -> u32;
- fn __bootstrap(msp: u32, rv: u32) -> !;
-}
-
-// v7m *AND* v8m.main, but *NOT* v8m.base
-#[cfg(any(armv7m, armv8m_main))]
-shims! {
- fn __basepri_max(val: u8);
- fn __basepri_r() -> u8;
- fn __basepri_w(val: u8);
- fn __faultmask_r() -> u32;
- fn __enable_icache();
- fn __enable_dcache();
-}
-
-#[cfg(armv7em)]
-shims! {
- fn __basepri_max_cm7_r0p1(val: u8);
- fn __basepri_w_cm7_r0p1(val: u8);
-}
-
-// Baseline and Mainline.
-#[cfg(armv8m)]
-shims! {
- fn __tt(target: u32) -> u32;
- fn __ttt(target: u32) -> u32;
- fn __tta(target: u32) -> u32;
- fn __ttat(target: u32) -> u32;
- fn __msp_ns_r() -> u32;
- fn __msp_ns_w(val: u32);
- fn __bxns(val: u32);
-}
-
-// Mainline only.
-#[cfg(armv8m_main)]
-shims! {
- fn __msplim_r() -> u32;
- fn __msplim_w(val: u32);
- fn __psplim_r() -> u32;
- fn __psplim_w(val: u32);
-}
-
-// All targets with FPU.
-#[cfg(has_fpu)]
-shims! {
- fn __fpscr_r() -> u32;
- fn __fpscr_w(val: u32);
-}
-
-/// We *must* define a panic handler here, even though nothing here should ever be able to panic.
-///
-/// We prove that nothing will ever panic by calling a function that doesn't exist. If the panic
-/// handler gets linked in, this causes a linker error. We always build this file with optimizations
-/// enabled, but even without them the panic handler should never be linked in.
-#[panic_handler]
-#[link_section = ".text.asm_panic_handler"]
-fn panic(_: &core::panic::PanicInfo) -> ! {
- extern "C" {
- #[link_name = "cortex-m internal error: panic handler not optimized out, please file an \
- issue at https://github.com/rust-embedded/cortex-m"]
- fn __cortex_m_should_not_panic() -> !;
- }
-
- unsafe {
- __cortex_m_should_not_panic();
- }
-}
diff --git a/bin/thumbv6m-none-eabi-lto.a b/bin/thumbv6m-none-eabi-lto.a
deleted file mode 100644
index a203d7a..0000000
--- a/bin/thumbv6m-none-eabi-lto.a
+++ /dev/null
Binary files differ
diff --git a/bin/thumbv6m-none-eabi.a b/bin/thumbv6m-none-eabi.a
deleted file mode 100644
index 9640a69..0000000
--- a/bin/thumbv6m-none-eabi.a
+++ /dev/null
Binary files differ
diff --git a/bin/thumbv7em-none-eabi-lto.a b/bin/thumbv7em-none-eabi-lto.a
deleted file mode 100644
index b34ac64..0000000
--- a/bin/thumbv7em-none-eabi-lto.a
+++ /dev/null
Binary files differ
diff --git a/bin/thumbv7em-none-eabi.a b/bin/thumbv7em-none-eabi.a
deleted file mode 100644
index 88acbdd..0000000
--- a/bin/thumbv7em-none-eabi.a
+++ /dev/null
Binary files differ
diff --git a/bin/thumbv7em-none-eabihf-lto.a b/bin/thumbv7em-none-eabihf-lto.a
deleted file mode 100644
index 6de94bb..0000000
--- a/bin/thumbv7em-none-eabihf-lto.a
+++ /dev/null
Binary files differ
diff --git a/bin/thumbv7em-none-eabihf.a b/bin/thumbv7em-none-eabihf.a
deleted file mode 100644
index cf91a7a..0000000
--- a/bin/thumbv7em-none-eabihf.a
+++ /dev/null
Binary files differ
diff --git a/bin/thumbv7m-none-eabi-lto.a b/bin/thumbv7m-none-eabi-lto.a
deleted file mode 100644
index 7f677a9..0000000
--- a/bin/thumbv7m-none-eabi-lto.a
+++ /dev/null
Binary files differ
diff --git a/bin/thumbv7m-none-eabi.a b/bin/thumbv7m-none-eabi.a
deleted file mode 100644
index ff4bf21..0000000
--- a/bin/thumbv7m-none-eabi.a
+++ /dev/null
Binary files differ
diff --git a/bin/thumbv8m.base-none-eabi-lto.a b/bin/thumbv8m.base-none-eabi-lto.a
deleted file mode 100644
index f62acaf..0000000
--- a/bin/thumbv8m.base-none-eabi-lto.a
+++ /dev/null
Binary files differ
diff --git a/bin/thumbv8m.base-none-eabi.a b/bin/thumbv8m.base-none-eabi.a
deleted file mode 100644
index c0cc96c..0000000
--- a/bin/thumbv8m.base-none-eabi.a
+++ /dev/null
Binary files differ
diff --git a/bin/thumbv8m.main-none-eabi-lto.a b/bin/thumbv8m.main-none-eabi-lto.a
deleted file mode 100644
index 1a51515..0000000
--- a/bin/thumbv8m.main-none-eabi-lto.a
+++ /dev/null
Binary files differ
diff --git a/bin/thumbv8m.main-none-eabi.a b/bin/thumbv8m.main-none-eabi.a
deleted file mode 100644
index d017a15..0000000
--- a/bin/thumbv8m.main-none-eabi.a
+++ /dev/null
Binary files differ
diff --git a/bin/thumbv8m.main-none-eabihf-lto.a b/bin/thumbv8m.main-none-eabihf-lto.a
deleted file mode 100644
index fd3dc92..0000000
--- a/bin/thumbv8m.main-none-eabihf-lto.a
+++ /dev/null
Binary files differ
diff --git a/bin/thumbv8m.main-none-eabihf.a b/bin/thumbv8m.main-none-eabihf.a
deleted file mode 100644
index 223ff1d..0000000
--- a/bin/thumbv8m.main-none-eabihf.a
+++ /dev/null
Binary files differ
diff --git a/build.rs b/build.rs
index 23ceeba..f81072b 100644
--- a/build.rs
+++ b/build.rs
@@ -1,33 +1,13 @@
-use std::path::PathBuf;
-use std::{env, fs};
+use std::env;
fn main() {
let target = env::var("TARGET").unwrap();
let host_triple = env::var("HOST").unwrap();
- let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
- let name = env::var("CARGO_PKG_NAME").unwrap();
if host_triple == target {
println!("cargo:rustc-cfg=native");
}
- if target.starts_with("thumb") {
- let suffix = if env::var_os("CARGO_FEATURE_LINKER_PLUGIN_LTO").is_some() {
- "-lto"
- } else {
- ""
- };
-
- fs::copy(
- format!("bin/{}{}.a", target, suffix),
- out_dir.join(format!("lib{}.a", name)),
- )
- .unwrap();
-
- println!("cargo:rustc-link-lib=static={}", name);
- println!("cargo:rustc-link-search={}", out_dir.display());
- }
-
if target.starts_with("thumbv6m-") {
println!("cargo:rustc-cfg=cortex_m");
println!("cargo:rustc-cfg=armv6m");
@@ -37,7 +17,7 @@ fn main() {
} else if target.starts_with("thumbv7em-") {
println!("cargo:rustc-cfg=cortex_m");
println!("cargo:rustc-cfg=armv7m");
- println!("cargo:rustc-cfg=armv7em"); // (not currently used)
+ println!("cargo:rustc-cfg=armv7em");
} else if target.starts_with("thumbv8m.base") {
println!("cargo:rustc-cfg=cortex_m");
println!("cargo:rustc-cfg=armv8m");
diff --git a/cortex-m-semihosting/CHANGELOG.md b/cortex-m-semihosting/CHANGELOG.md
index 0a942cf..38ee835 100644
--- a/cortex-m-semihosting/CHANGELOG.md
+++ b/cortex-m-semihosting/CHANGELOG.md
@@ -5,6 +5,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
+- Always use inline-asm, requiring Rust 1.59.
+
## [v0.4.1] - 2020-10-20
0.4.1 was yanked because the pre-built binaries contain conflicting symbols
diff --git a/cortex-m-semihosting/README.md b/cortex-m-semihosting/README.md
index bfbfb44..6036d4e 100644
--- a/cortex-m-semihosting/README.md
+++ b/cortex-m-semihosting/README.md
@@ -11,7 +11,7 @@ This project is developed and maintained by the [Cortex-M team][team].
# Minimum Supported Rust Version (MSRV)
-This crate is guaranteed to compile on stable Rust 1.33.0 and up. It *might*
+This crate is guaranteed to compile on stable Rust 1.59.0 and up. It *might*
compile with older versions but that may change in any new patch release.
## License
diff --git a/cortex-m-semihosting/bin b/cortex-m-semihosting/bin
deleted file mode 120000
index 19f285a..0000000
--- a/cortex-m-semihosting/bin
+++ /dev/null
@@ -1 +0,0 @@
-../bin \ No newline at end of file
diff --git a/cortex-m-semihosting/build.rs b/cortex-m-semihosting/build.rs
index 315035e..ed0d069 100644
--- a/cortex-m-semihosting/build.rs
+++ b/cortex-m-semihosting/build.rs
@@ -1,23 +1,9 @@
-use std::path::PathBuf;
-use std::{env, fs};
+use std::env;
fn main() {
let target = env::var("TARGET").unwrap();
- let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
- let name = env::var("CARGO_PKG_NAME").unwrap();
if target.starts_with("thumbv") {
- if env::var_os("CARGO_FEATURE_INLINE_ASM").is_none() {
- fs::copy(
- format!("bin/{}.a", target),
- out_dir.join(format!("lib{}.a", name)),
- )
- .unwrap();
-
- println!("cargo:rustc-link-lib=static={}", name);
- println!("cargo:rustc-link-search={}", out_dir.display());
- }
-
println!("cargo:rustc-cfg=thumb");
}
}
diff --git a/cortex-m-semihosting/src/lib.rs b/cortex-m-semihosting/src/lib.rs
index 3bc23ea..4ff975d 100644
--- a/cortex-m-semihosting/src/lib.rs
+++ b/cortex-m-semihosting/src/lib.rs
@@ -151,14 +151,6 @@
//!
//! # Optional features
//!
-//! ## `inline-asm`
-//!
-//! When this feature is enabled semihosting is implemented using inline assembly and
-//! compiling this crate requires nightly.
-//!
-//! When this feature is disabled semihosting is implemented using FFI calls into an external
-//! assembly file and compiling this crate works on stable and beta.
-//!
//! ## `jlink-quirks`
//!
//! When this feature is enabled, return values above `0xfffffff0` from semihosting operation
@@ -191,11 +183,6 @@ pub mod export;
pub mod hio;
pub mod nr;
-#[cfg(all(thumb, not(feature = "inline-asm")))]
-extern "C" {
- fn __sh_syscall(nr: usize, arg: usize) -> usize;
-}
-
/// Performs a semihosting operation, takes a pointer to an argument block
#[inline(always)]
pub unsafe fn syscall<T>(nr: usize, arg: &T) -> usize {
@@ -206,10 +193,7 @@ pub unsafe fn syscall<T>(nr: usize, arg: &T) -> usize {
#[inline(always)]
pub unsafe fn syscall1(_nr: usize, _arg: usize) -> usize {
match () {
- #[cfg(all(thumb, not(feature = "inline-asm"), not(feature = "no-semihosting")))]
- () => __sh_syscall(_nr, _arg),
-
- #[cfg(all(thumb, feature = "inline-asm", not(feature = "no-semihosting")))]
+ #[cfg(all(thumb, not(feature = "no-semihosting")))]
() => {
let mut nr = _nr;
core::arch::asm!(
diff --git a/panic-semihosting/CHANGELOG.md b/panic-semihosting/CHANGELOG.md
index 95c3890..c7a2e78 100644
--- a/panic-semihosting/CHANGELOG.md
+++ b/panic-semihosting/CHANGELOG.md
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
+- Always use inline-asm, requiring Rust 1.59.
+
## [v0.5.6] - 2020-11-14
- Fix update to docs.rs to build for an embedded target
diff --git a/panic-semihosting/Cargo.toml b/panic-semihosting/Cargo.toml
index 46a3d2f..dd3511e 100644
--- a/panic-semihosting/Cargo.toml
+++ b/panic-semihosting/Cargo.toml
@@ -18,7 +18,7 @@ cortex-m-semihosting = { path = "../cortex-m-semihosting", version = ">= 0.3, <
[features]
exit = []
-inline-asm = ["cortex-m-semihosting/inline-asm", "cortex-m/inline-asm"]
+inline-asm = []
jlink-quirks = ["cortex-m-semihosting/jlink-quirks"]
[package.metadata.docs.rs]
diff --git a/panic-semihosting/README.md b/panic-semihosting/README.md
index baacf1a..f8057d3 100644
--- a/panic-semihosting/README.md
+++ b/panic-semihosting/README.md
@@ -8,7 +8,7 @@ This project is developed and maintained by the [Cortex-M team][team].
## Minimum Supported Rust Version (MSRV)
-This crate is guaranteed to compile on stable Rust 1.32.0 and up. It *might*
+This crate is guaranteed to compile on stable Rust 1.59.0 and up. It *might*
compile with older versions but that may change in any new patch release.
## License
diff --git a/panic-semihosting/src/lib.rs b/panic-semihosting/src/lib.rs
index 1db7b72..1d7379e 100644
--- a/panic-semihosting/src/lib.rs
+++ b/panic-semihosting/src/lib.rs
@@ -47,14 +47,6 @@
//!
//! We discourage using this feature when the program will run on hardware as the exit call can
//! leave the hardware debugger in an inconsistent state.
-//!
-//! ## `inline-asm`
-//!
-//! When this feature is enabled semihosting is implemented using inline assembly (`asm!`) and
-//! compiling this crate requires nightly.
-//!
-//! When this feature is disabled semihosting is implemented using FFI calls into an external
-//! assembly file and compiling this crate works on stable and beta.
#![cfg(all(target_arch = "arm", target_os = "none"))]
#![deny(missing_docs)]
diff --git a/src/asm.rs b/src/asm.rs
index 4dc1ab0..0434b5f 100644
--- a/src/asm.rs
+++ b/src/asm.rs
@@ -1,18 +1,17 @@
//! 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;
+#[cfg(cortex_m)]
+use core::arch::asm;
+use core::sync::atomic::{compiler_fence, Ordering};
/// 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.
+#[cfg(cortex_m)]
#[inline(always)]
pub fn bkpt() {
- call_asm!(__bkpt());
+ unsafe { asm!("bkpt", options(nomem, nostack, preserves_flags)) };
}
/// Blocks the program for *at least* `cycles` CPU cycles.
@@ -24,41 +23,66 @@ pub fn bkpt() {
/// 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.
+#[cfg(cortex_m)]
#[inline]
pub fn delay(cycles: u32) {
- call_asm!(__delay(cycles: u32));
+ // The loop will normally take 3 to 4 CPU cycles per iteration, but superscalar cores
+ // (eg. Cortex-M7) can potentially do it in 2, so we use that as the lower bound, since delaying
+ // for more cycles is okay.
+ // Add 1 to prevent an integer underflow which would cause a long freeze
+ let real_cycles = 1 + cycles / 2;
+ unsafe {
+ asm!(
+ // Use local labels to avoid R_ARM_THM_JUMP8 relocations which fail on thumbv6m.
+ "1:",
+ "subs {}, #1",
+ "bne 1b",
+ inout(reg) real_cycles => _,
+ options(nomem, nostack),
+ )
+ };
}
/// A no-operation. Useful to prevent delay loops from being optimized away.
#[inline]
pub fn nop() {
- call_asm!(__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.
+ #[cfg(cortex_m)]
+ unsafe {
+ asm!("nop", options(nomem, nostack, preserves_flags))
+ };
}
/// Generate an Undefined Instruction exception.
///
/// Can be used as a stable alternative to `core::intrinsics::abort`.
+#[cfg(cortex_m)]
#[inline]
pub fn udf() -> ! {
- call_asm!(__udf() -> !)
+ unsafe { asm!("udf #0", options(noreturn, nomem, nostack, preserves_flags)) };
}
/// Wait For Event
+#[cfg(cortex_m)]
#[inline]
pub fn wfe() {
- call_asm!(__wfe())
+ unsafe { asm!("wfe", options(nomem, nostack, preserves_flags)) };
}
/// Wait For Interrupt
+#[cfg(cortex_m)]
#[inline]
pub fn wfi() {
- call_asm!(__wfi())
+ unsafe { asm!("wfi", options(nomem, nostack, preserves_flags)) };
}
/// Send Event
+#[cfg(cortex_m)]
#[inline]
pub fn sev() {
- call_asm!(__sev())
+ unsafe { asm!("sev", options(nomem, nostack, preserves_flags)) };
}
/// Instruction Synchronization Barrier
@@ -67,7 +91,12 @@ pub fn sev() {
/// from cache or memory, after the instruction has been completed.
#[inline]
pub fn isb() {
- call_asm!(__isb())
+ compiler_fence(Ordering::SeqCst);
+ #[cfg(cortex_m)]
+ unsafe {
+ asm!("isb", options(nomem, nostack, preserves_flags))
+ };
+ compiler_fence(Ordering::SeqCst);
}
/// Data Synchronization Barrier
@@ -79,7 +108,12 @@ pub fn isb() {
/// * all cache and branch predictor maintenance operations before this instruction complete
#[inline]
pub fn dsb() {
- call_asm!(__dsb())
+ compiler_fence(Ordering::SeqCst);
+ #[cfg(cortex_m)]
+ unsafe {
+ asm!("dsb", options(nomem, nostack, preserves_flags))
+ };
+ compiler_fence(Ordering::SeqCst);
}
/// Data Memory Barrier
@@ -89,7 +123,12 @@ pub fn dsb() {
/// after the `DMB` instruction.
#[inline]
pub fn dmb() {
- call_asm!(__dmb())
+ compiler_fence(Ordering::SeqCst);
+ #[cfg(cortex_m)]
+ unsafe {
+ asm!("dmb", options(nomem, nostack, preserves_flags))
+ };
+ compiler_fence(Ordering::SeqCst);
}
/// Test Target
@@ -102,8 +141,15 @@ pub fn dmb() {
// 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)
+ let mut target = addr as u32;
+ unsafe {
+ asm!(
+ "tt {target}, {target}",
+ target = inout(reg) target,
+ options(nomem, nostack, preserves_flags),
+ )
+ };
+ target
}
/// Test Target Unprivileged
@@ -117,8 +163,15 @@ pub fn tt(addr: *mut u32) -> u32 {
// 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)
+ let mut target = addr as u32;
+ unsafe {
+ asm!(
+ "ttt {target}, {target}",
+ target = inout(reg) target,
+ options(nomem, nostack, preserves_flags),
+ )
+ };
+ target
}
/// Test Target Alternate Domain
@@ -133,8 +186,15 @@ pub fn ttt(addr: *mut u32) -> u32 {
// 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)
+ let mut target = addr as u32;
+ unsafe {
+ asm!(
+ "tta {target}, {target}",
+ target = inout(reg) target,
+ options(nomem, nostack, preserves_flags),
+ )
+ };
+ target
}
/// Test Target Alternate Domain Unprivileged
@@ -149,8 +209,15 @@ pub fn tta(addr: *mut u32) -> u32 {
// 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)
+ let mut target = addr as u32;
+ unsafe {
+ asm!(
+ "ttat {target}, {target}",
+ target = inout(reg) target,
+ options(nomem, nostack, preserves_flags),
+ )
+ };
+ target
}
/// Branch and Exchange Non-secure
@@ -160,15 +227,17 @@ pub fn ttat(addr: *mut u32) -> u32 {
#[inline]
#[cfg(armv8m)]
pub unsafe fn bx_ns(addr: u32) {
- call_asm!(__bxns(addr: u32));
+ asm!("bxns {}", in(reg) addr, options(nomem, nostack, preserves_flags));
}
/// Semihosting syscall.
///
/// This method is used by cortex-m-semihosting to provide semihosting syscalls.
+#[cfg(cortex_m)]
#[inline]
-pub unsafe fn semihosting_syscall(nr: u32, arg: u32) -> u32 {
- call_asm!(__sh_syscall(nr: u32, arg: u32) -> u32)
+pub unsafe fn semihosting_syscall(mut nr: u32, arg: u32) -> u32 {
+ asm!("bkpt #0xab", inout("r0") nr, in("r1") arg, options(nomem, nostack, preserves_flags));
+ nr
}
/// Bootstrap.
@@ -181,12 +250,27 @@ pub unsafe fn semihosting_syscall(nr: u32, arg: u32) -> u32 {
///
/// `msp` and `rv` must point to valid stack memory and executable code,
/// respectively.
+#[cfg(cortex_m)]
#[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) -> !);
+ asm!(
+ "mrs {tmp}, CONTROL",
+ "bics {tmp}, {spsel}",
+ "msr CONTROL, {tmp}",
+ "isb",
+ "msr MSP, {msp}",
+ "bx {rv}",
+ // `out(reg) _` is not permitted in a `noreturn` asm! call,
+ // so instead use `in(reg) 0` and don't restore it afterwards.
+ tmp = in(reg) 0,
+ spsel = in(reg) 2,
+ msp = in(reg) msp,
+ rv = in(reg) rv,
+ options(noreturn, nomem, nostack),
+ );
}
/// Bootload.
@@ -201,6 +285,7 @@ pub unsafe fn bootstrap(msp: *const u32, rv: *const u32) -> ! {
/// 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.
+#[cfg(cortex_m)]
#[inline]
pub unsafe fn bootload(vector_table: *const u32) -> ! {
let msp = core::ptr::read_volatile(vector_table);
diff --git a/src/call_asm.rs b/src/call_asm.rs
deleted file mode 100644
index 295277f..0000000
--- a/src/call_asm.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-/// An internal macro to invoke an assembly routine.
-///
-/// Depending on whether the unstable `inline-asm` feature is enabled, this will either call into
-/// the inline assembly implementation directly, or through the FFI shim (see `asm/lib.rs`).
-macro_rules! call_asm {
- ( $func:ident ( $($args:ident: $tys:ty),* ) $(-> $ret:ty)? ) => {{
- #[allow(unused_unsafe)]
- unsafe {
- match () {
- #[cfg(feature = "inline-asm")]
- () => crate::asm::inline::$func($($args),*),
-
- #[cfg(not(feature = "inline-asm"))]
- () => {
- extern "C" {
- fn $func($($args: $tys),*) $(-> $ret)?;
- }
-
- $func($($args),*)
- },
- }
- }
- }};
-}
diff --git a/src/interrupt.rs b/src/interrupt.rs
index 68719ec..06b91f1 100644
--- a/src/interrupt.rs
+++ b/src/interrupt.rs
@@ -1,6 +1,10 @@
//! Interrupts
pub use bare_metal::{CriticalSection, Mutex};
+#[cfg(cortex_m)]
+use core::arch::asm;
+#[cfg(cortex_m)]
+use core::sync::atomic::{compiler_fence, Ordering};
/// Trait for enums of external interrupt numbers.
///
@@ -24,9 +28,15 @@ pub unsafe trait InterruptNumber: Copy {
}
/// Disables all interrupts
+#[cfg(cortex_m)]
#[inline]
pub fn disable() {
- call_asm!(__cpsid());
+ unsafe {
+ asm!("cpsid i", options(nomem, nostack, preserves_flags));
+ }
+
+ // Ensure no subsequent memory accesses are reordered to before interrupts are disabled.
+ compiler_fence(Ordering::SeqCst);
}
/// Enables all the interrupts
@@ -34,14 +44,19 @@ pub fn disable() {
/// # Safety
///
/// - Do not call this function inside an `interrupt::free` critical section
+#[cfg(cortex_m)]
#[inline]
pub unsafe fn enable() {
- call_asm!(__cpsie());
+ // Ensure no preceeding memory accesses are reordered to after interrupts are enabled.
+ compiler_fence(Ordering::SeqCst);
+
+ asm!("cpsie i", options(nomem, nostack, preserves_flags));
}
/// Execute closure `f` in an interrupt-free context.
///
/// This as also known as a "critical section".
+#[cfg(cortex_m)]
#[inline]
pub fn free<F, R>(f: F) -> R
where
diff --git a/src/lib.rs b/src/lib.rs
index dd46fd7..7286f06 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -9,53 +9,17 @@
//!
//! # Optional features
//!
-//! ## `inline-asm`
-//!
-//! When this feature is enabled the implementation of all the functions inside the `asm` and
-//! `register` modules use inline assembly (`asm!`) instead of external assembly (FFI into separate
-//! assembly files pre-compiled using `arm-none-eabi-gcc`). The advantages of enabling `inline-asm`
-//! are:
-//!
-//! - Reduced overhead. FFI eliminates the possibility of inlining so all operations include a
-//! function call overhead when `inline-asm` is not enabled.
-//!
-//! - Some of the `register` API only becomes available only when `inline-asm` is enabled. Check the
-//! API docs for details.
-//!
-//! The disadvantage is that `inline-asm` requires a nightly toolchain.
-//!
//! ## `cm7-r0p1`
//!
//! This feature enables workarounds for errata found on Cortex-M7 chips with revision r0p1. Some
//! functions in this crate only work correctly on those chips if this Cargo feature is enabled
//! (the functions are documented accordingly).
//!
-//! ## `linker-plugin-lto`
-//!
-//! This feature links against prebuilt assembly blobs that are compatible with [Linker-Plugin LTO].
-//! This allows inlining assembly routines into the caller, even without the `inline-asm` feature,
-//! and works on stable Rust (but note the drawbacks below!).
-//!
-//! If you want to use this feature, you need to be aware of a few things:
-//!
-//! - You need to make sure that `-Clinker-plugin-lto` is passed to rustc. Please refer to the
-//! [Linker-Plugin LTO] documentation for details.
-//!
-//! - You have to use a Rust version whose LLVM version is compatible with the toolchain in
-//! `asm-toolchain`.
-//!
-//! - Due to a [Rust bug][rust-lang/rust#75940] in compiler versions **before 1.49**, this option
-//! does not work with optimization levels `s` and `z`.
-//!
-//! [Linker-Plugin LTO]: https://doc.rust-lang.org/stable/rustc/linker-plugin-lto.html
-//! [rust-lang/rust#75940]: https://github.com/rust-lang/rust/issues/75940
-//!
//! # Minimum Supported Rust Version (MSRV)
//!
-//! This crate is guaranteed to compile on stable Rust 1.42 and up. It *might*
+//! This crate is guaranteed to compile on stable Rust 1.59 and up. It *might*
//! compile with older versions but that may change in any new patch release.
-#![cfg_attr(feature = "inline-asm", feature(asm))]
#![deny(missing_docs)]
#![no_std]
#![allow(clippy::identity_op)]
@@ -83,8 +47,6 @@ extern crate bare_metal;
extern crate volatile_register;
#[macro_use]
-mod call_asm;
-#[macro_use]
mod macros;
pub mod asm;
diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs
index af922b1..d1dfb6a 100644
--- a/src/peripheral/mod.rs
+++ b/src/peripheral/mod.rs
@@ -60,6 +60,7 @@
use core::marker::PhantomData;
use core::ops;
+#[cfg(cortex_m)]
use crate::interrupt;
#[cfg(cm7)]
@@ -163,6 +164,7 @@ static mut TAKEN: bool = false;
impl Peripherals {
/// Returns all the core peripherals *once*
+ #[cfg(cortex_m)]
#[inline]
pub fn take() -> Option<Self> {
interrupt::free(|_| {
diff --git a/src/register/apsr.rs b/src/register/apsr.rs
index e83435c..edb8737 100644
--- a/src/register/apsr.rs
+++ b/src/register/apsr.rs
@@ -1,5 +1,8 @@
//! Application Program Status Register
+#[cfg(cortex_m)]
+use core::arch::asm;
+
/// Application Program Status Register
#[derive(Clone, Copy, Debug)]
pub struct Apsr {
@@ -45,10 +48,10 @@ impl Apsr {
}
/// Reads the CPU register
-///
-/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature.
+#[cfg(cortex_m)]
#[inline]
pub fn read() -> Apsr {
- let bits: u32 = call_asm!(__apsr_r() -> u32);
+ let bits;
+ unsafe { asm!("mrs {}, APSR", out(reg) bits, options(nomem, nostack, preserves_flags)) };
Apsr { bits }
}
diff --git a/src/register/basepri.rs b/src/register/basepri.rs
index 07084cd..cffb379 100644
--- a/src/register/basepri.rs
+++ b/src/register/basepri.rs
@@ -1,24 +1,42 @@
//! Base Priority Mask Register
+#[cfg(cortex_m)]
+use core::arch::asm;
+
/// Reads the CPU register
+#[cfg(cortex_m)]
#[inline]
pub fn read() -> u8 {
- call_asm!(__basepri_r() -> u8)
+ let r;
+ unsafe { asm!("mrs {}, BASEPRI", out(reg) r, options(nomem, nostack, preserves_flags)) };
+ r
}
/// Writes to the CPU register
///
/// **IMPORTANT** If you are using a Cortex-M7 device with revision r0p1 you MUST enable the
/// `cm7-r0p1` Cargo feature or this function WILL misbehave.
+#[cfg(cortex_m)]
#[inline]
pub unsafe fn write(basepri: u8) {
#[cfg(feature = "cm7-r0p1")]
{
- call_asm!(__basepri_w_cm7_r0p1(basepri: u8));
+ asm!(
+ "mrs {1}, PRIMASK",
+ "cpsid i",
+ "tst.w {1}, #1",
+ "msr BASEPRI, {0}",
+ "it ne",
+ "bxne lr",
+ "cpsie i",
+ in(reg) basepri,
+ out(reg) _,
+ options(nomem, nostack, preserves_flags),
+ );
}
#[cfg(not(feature = "cm7-r0p1"))]
{
- call_asm!(__basepri_w(basepri: u8));
+ asm!("msr BASEPRI, {}", in(reg) basepri, options(nomem, nostack, preserves_flags));
}
}
diff --git a/src/register/basepri_max.rs b/src/register/basepri_max.rs
index cea3838..2881c4f 100644
--- a/src/register/basepri_max.rs
+++ b/src/register/basepri_max.rs
@@ -1,5 +1,8 @@
//! Base Priority Mask Register (conditional write)
+#[cfg(cortex_m)]
+use core::arch::asm;
+
/// Writes to BASEPRI *if*
///
/// - `basepri != 0` AND `basepri::read() == 0`, OR
@@ -7,15 +10,31 @@
///
/// **IMPORTANT** If you are using a Cortex-M7 device with revision r0p1 you MUST enable the
/// `cm7-r0p1` Cargo feature or this function WILL misbehave.
+#[cfg(cortex_m)]
#[inline]
pub fn write(basepri: u8) {
#[cfg(feature = "cm7-r0p1")]
{
- call_asm!(__basepri_max_cm7_r0p1(basepri: u8));
+ unsafe {
+ asm!(
+ "mrs {1}, PRIMASK",
+ "cpsid i",
+ "tst.w {1}, #1",
+ "msr BASEPRI_MAX, {0}",
+ "it ne",
+ "bxne lr",
+ "cpsie i",
+ in(reg) basepri,
+ out(reg) _,
+ options(nomem, nostack, preserves_flags),
+ );
+ }
}
#[cfg(not(feature = "cm7-r0p1"))]
{
- call_asm!(__basepri_max(basepri: u8));
+ unsafe {
+ asm!("msr BASEPRI_MAX, {}", in(reg) basepri, options(nomem, nostack, preserves_flags));
+ }
}
}
diff --git a/src/register/control.rs b/src/register/control.rs
index a991625..d781913 100644
--- a/src/register/control.rs
+++ b/src/register/control.rs
@@ -1,5 +1,10 @@
//! Control register
+#[cfg(cortex_m)]
+use core::arch::asm;
+#[cfg(cortex_m)]
+use core::sync::atomic::{compiler_fence, Ordering};
+
/// Control register
#[derive(Clone, Copy, Debug)]
pub struct Control {
@@ -150,15 +155,29 @@ impl Fpca {
}
/// Reads the CPU register
+#[cfg(cortex_m)]
#[inline]
pub fn read() -> Control {
- let bits: u32 = call_asm!(__control_r() -> u32);
+ let bits;
+ unsafe { asm!("mrs {}, CONTROL", out(reg) bits, options(nomem, nostack, preserves_flags)) };
Control { bits }
}
/// Writes to the CPU register.
+#[cfg(cortex_m)]
#[inline]
pub unsafe fn write(control: Control) {
let control = control.bits();
- call_asm!(__control_w(control: u32));
+
+ // ISB is required after writing to CONTROL,
+ // per ARM architectural requirements (see Application Note 321).
+ asm!(
+ "msr CONTROL, {}",
+ "isb",
+ in(reg) control,
+ options(nomem, nostack, preserves_flags),
+ );
+
+ // Ensure memory accesses are not reordered around the CONTROL update.
+ compiler_fence(Ordering::SeqCst);
}
diff --git a/src/register/faultmask.rs b/src/register/faultmask.rs
index e57fa28..1d32709 100644
--- a/src/register/faultmask.rs
+++ b/src/register/faultmask.rs
@@ -1,5 +1,8 @@
//! Fault Mask Register
+#[cfg(cortex_m)]
+use core::arch::asm;
+
/// All exceptions are ...
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Faultmask {
@@ -24,9 +27,11 @@ impl Faultmask {
}
/// Reads the CPU register
+#[cfg(cortex_m)]
#[inline]
pub fn read() -> Faultmask {
- let r: u32 = call_asm!(__faultmask_r() -> u32);
+ let r: u32;
+ unsafe { asm!("mrs {}, FAULTMASK", out(reg) r, options(nomem, nostack, preserves_flags)) };
if r & (1 << 0) == (1 << 0) {
Faultmask::Inactive
} else {
diff --git a/src/register/fpscr.rs b/src/register/fpscr.rs
index 68692c7..bffed6c 100644
--- a/src/register/fpscr.rs
+++ b/src/register/fpscr.rs
@@ -1,5 +1,7 @@
//! Floating-point Status Control Register
+use core::arch::asm;
+
/// Floating-point Status Control Register
#[derive(Clone, Copy, Debug)]
pub struct Fpscr {
@@ -293,7 +295,8 @@ impl RMode {
/// Read the FPSCR register
#[inline]
pub fn read() -> Fpscr {
- let r: u32 = call_asm!(__fpscr_r() -> u32);
+ let r;
+ unsafe { asm!("vmrs {}, fpscr", out(reg) r, options(nomem, nostack, preserves_flags)) };
Fpscr::from_bits(r)
}
@@ -301,5 +304,5 @@ pub fn read() -> Fpscr {
#[inline]
pub unsafe fn write(fpscr: Fpscr) {
let fpscr = fpscr.bits();
- call_asm!(__fpscr_w(fpscr: u32));
+ asm!("vmsr fpscr, {}", in(reg) fpscr, options(nomem, nostack));
}
diff --git a/src/register/lr.rs b/src/register/lr.rs
index 1aa546c..02708ae 100644
--- a/src/register/lr.rs
+++ b/src/register/lr.rs
@@ -1,17 +1,20 @@
//! Link register
+#[cfg(cortex_m)]
+use core::arch::asm;
+
/// Reads the CPU register
-///
-/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature.
+#[cfg(cortex_m)]
#[inline]
pub fn read() -> u32 {
- call_asm!(__lr_r() -> u32)
+ let r;
+ unsafe { asm!("mov {}, lr", out(reg) r, options(nomem, nostack, preserves_flags)) };
+ r
}
/// Writes `bits` to the CPU register
-///
-/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature.
+#[cfg(cortex_m)]
#[inline]
pub unsafe fn write(bits: u32) {
- call_asm!(__lr_w(bits: u32));
+ asm!("mov lr, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
}
diff --git a/src/register/mod.rs b/src/register/mod.rs
index 48d157a..aee7d21 100644
--- a/src/register/mod.rs
+++ b/src/register/mod.rs
@@ -56,13 +56,8 @@ pub mod msplim;
#[cfg(armv8m_main)]
pub mod psplim;
-// Accessing these registers requires inline assembly because their contents are tied to the current
-// stack frame
-#[cfg(feature = "inline-asm")]
pub mod apsr;
-#[cfg(feature = "inline-asm")]
pub mod lr;
-#[cfg(feature = "inline-asm")]
pub mod pc;
diff --git a/src/register/msp.rs b/src/register/msp.rs
index bccc2ae..22ce7d9 100644
--- a/src/register/msp.rs
+++ b/src/register/msp.rs
@@ -1,16 +1,27 @@
//! Main Stack Pointer
+#[cfg(cortex_m)]
+use core::arch::asm;
+
/// Reads the CPU register
+#[cfg(cortex_m)]
#[inline]
pub fn read() -> u32 {
- call_asm!(__msp_r() -> u32)
+ let r;
+ unsafe { asm!("mrs {}, MSP", out(reg) r, options(nomem, nostack, preserves_flags)) };
+ r
}
/// Writes `bits` to the CPU register
+#[cfg(cortex_m)]
#[inline]
#[deprecated = "calling this function invokes Undefined Behavior, consider asm::bootstrap as an alternative"]
pub unsafe fn write(bits: u32) {
- call_asm!(__msp_w(bits: u32));
+ // Technically is writing to the stack pointer "not pushing any data to the stack"?
+ // In any event, if we don't set `nostack` here, this method is useless as the new
+ // stack value is immediately mutated by returning. Really this is just not a good
+ // method and its use is marked as deprecated.
+ asm!("msr MSP, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
}
/// Reads the Non-Secure CPU register from Secure state.
@@ -19,7 +30,9 @@ pub unsafe fn write(bits: u32) {
#[cfg(armv8m)]
#[inline]
pub fn read_ns() -> u32 {
- call_asm!(__msp_ns_r() -> u32)
+ let r;
+ unsafe { asm!("mrs {}, MSP_NS", out(reg) r, options(nomem, nostack, preserves_flags)) };
+ r
}
/// Writes `bits` to the Non-Secure CPU register from Secure state.
@@ -28,5 +41,5 @@ pub fn read_ns() -> u32 {
#[cfg(armv8m)]
#[inline]
pub unsafe fn write_ns(bits: u32) {
- call_asm!(__msp_ns_w(bits: u32));
+ asm!("msr MSP_NS, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
}
diff --git a/src/register/msplim.rs b/src/register/msplim.rs
index ac6f9ed..7b45b33 100644
--- a/src/register/msplim.rs
+++ b/src/register/msplim.rs
@@ -1,13 +1,17 @@
//! Main Stack Pointer Limit Register
+use core::arch::asm;
+
/// Reads the CPU register
#[inline]
pub fn read() -> u32 {
- call_asm!(__msplim_r() -> u32)
+ let r;
+ unsafe { asm!("mrs {}, MSPLIM", out(reg) r, options(nomem, nostack, preserves_flags)) };
+ r
}
/// Writes `bits` to the CPU register
#[inline]
pub unsafe fn write(bits: u32) {
- call_asm!(__msplim_w(bits: u32))
+ asm!("msr MSPLIM, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
}
diff --git a/src/register/pc.rs b/src/register/pc.rs
index 0b33629..3460664 100644
--- a/src/register/pc.rs
+++ b/src/register/pc.rs
@@ -1,17 +1,20 @@
//! Program counter
+#[cfg(cortex_m)]
+use core::arch::asm;
+
/// Reads the CPU register
-///
-/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature.
+#[cfg(cortex_m)]
#[inline]
pub fn read() -> u32 {
- call_asm!(__pc_r() -> u32)
+ let r;
+ unsafe { asm!("mov {}, pc", out(reg) r, options(nomem, nostack, preserves_flags)) };
+ r
}
/// Writes `bits` to the CPU register
-///
-/// **NOTE** This function is available if `cortex-m` is built with the `"inline-asm"` feature.
+#[cfg(cortex_m)]
#[inline]
pub unsafe fn write(bits: u32) {
- call_asm!(__pc_w(bits: u32));
+ asm!("mov pc, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
}
diff --git a/src/register/primask.rs b/src/register/primask.rs
index 842ca49..e95276f 100644
--- a/src/register/primask.rs
+++ b/src/register/primask.rs
@@ -1,5 +1,8 @@
//! Priority mask register
+#[cfg(cortex_m)]
+use core::arch::asm;
+
/// All exceptions with configurable priority are ...
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Primask {
@@ -24,9 +27,11 @@ impl Primask {
}
/// Reads the CPU register
+#[cfg(cortex_m)]
#[inline]
pub fn read() -> Primask {
- let r: u32 = call_asm!(__primask_r() -> u32);
+ let r: u32;
+ unsafe { asm!("mrs {}, PRIMASK", out(reg) r, options(nomem, nostack, preserves_flags)) };
if r & (1 << 0) == (1 << 0) {
Primask::Inactive
} else {
diff --git a/src/register/psp.rs b/src/register/psp.rs
index 0bca22c..c8f53b9 100644
--- a/src/register/psp.rs
+++ b/src/register/psp.rs
@@ -1,13 +1,22 @@
//! Process Stack Pointer
+#[cfg(cortex_m)]
+use core::arch::asm;
+
/// Reads the CPU register
+#[cfg(cortex_m)]
#[inline]
pub fn read() -> u32 {
- call_asm!(__psp_r() -> u32)
+ let r;
+ unsafe { asm!("mrs {}, PSP", out(reg) r, options(nomem, nostack, preserves_flags)) };
+ r
}
/// Writes `bits` to the CPU register
+#[cfg(cortex_m)]
#[inline]
pub unsafe fn write(bits: u32) {
- call_asm!(__psp_w(bits: u32))
+ // See comment on msp_w. Unlike MSP, there are legitimate use-cases for modifying PSP
+ // if MSP is currently being used as the stack pointer.
+ asm!("msr PSP, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
}
diff --git a/src/register/psplim.rs b/src/register/psplim.rs
index 8ee1e94..832f9c6 100644
--- a/src/register/psplim.rs
+++ b/src/register/psplim.rs
@@ -1,13 +1,17 @@
//! Process Stack Pointer Limit Register
+use core::arch::asm;
+
/// Reads the CPU register
#[inline]
pub fn read() -> u32 {
- call_asm!(__psplim_r() -> u32)
+ let r;
+ unsafe { asm!("mrs {}, PSPLIM", out(reg) r, options(nomem, nostack, preserves_flags)) };
+ r
}
/// Writes `bits` to the CPU register
#[inline]
pub unsafe fn write(bits: u32) {
- call_asm!(__psplim_w(bits: u32))
+ asm!("msr PSPLIM, {}", in(reg) bits, options(nomem, nostack, preserves_flags));
}
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs
index f6a57b3..9d96686 100644
--- a/xtask/src/lib.rs
+++ b/xtask/src/lib.rs
@@ -1,117 +1,8 @@
//! `cargo xtask` automation.
//!
//! Please refer to <https://github.com/matklad/cargo-xtask/> for an explanation of the concept.
-//!
-//! Also see the docs in `asm.rs`.
-
-use std::collections::BTreeMap;
-use std::env::current_dir;
-use std::fs::{self, File};
-use std::process::{Command, Stdio};
-
-fn toolchain() -> String {
- fs::read_to_string("asm-toolchain")
- .unwrap()
- .trim()
- .to_string()
-}
-
-fn rustc() -> Command {
- let mut cmd = Command::new("rustc");
- cmd.arg(format!("+{}", toolchain()));
- cmd
-}
-
-fn assemble_really(target: &str, cfgs: &[&str], plugin_lto: bool) {
- let mut cmd = rustc();
-
- // Set the codegen target.
- cmd.arg("--target").arg(target);
- // Set all the `--cfg` directives for the target.
- cmd.args(cfgs.iter().map(|cfg| format!("--cfg={}", cfg)));
-
- // We want some level of debuginfo to allow unwinding through the functions.
- cmd.arg("-g");
- // We always optimize the assembly shims. There's not really any reason not to.
- cmd.arg("-O");
-
- // We use LTO on the archive to ensure the (unused) panic handler is removed, preventing
- // a linker error when the archives are linked into final crates with two panic handlers.
- cmd.arg("-Clto=yes");
-
- // rustc will usually add frame pointers by default to aid with debugging, but that is a high
- // overhead for the tiny assembly routines.
- cmd.arg("-Cforce-frame-pointers=no");
- // We don't want any system-specific paths to show up since we ship the result to other users.
- // Add `--remap-path-prefix $(pwd)=.`.
- let mut dir = current_dir().unwrap().as_os_str().to_os_string();
- dir.push("=.");
- cmd.arg("--remap-path-prefix").arg(dir);
-
- // We let rustc build a single object file, not a staticlib, since the latter pulls in loads of
- // code that will never be used (`compiler_builtins` and `core::fmt`, etc.). We build the static
- // archive by hand after compiling.
- cmd.arg("--emit=obj");
-
- if plugin_lto {
- // Make artifacts compatible with Linker-Plugin LTO (and incompatible with everything else).
- cmd.arg("-Clinker-plugin-lto");
- }
-
- let file_stub = if plugin_lto {
- format!("{}-lto", target)
- } else {
- target.to_string()
- };
-
- let obj_file = format!("bin/{}.o", file_stub);
-
- // Pass output and input file.
- cmd.arg("-o").arg(&obj_file);
- cmd.arg("asm/lib.rs");
-
- println!("{:?}", cmd);
- let status = cmd.status().unwrap();
- assert!(status.success());
-
- // Archive `target.o` -> `bin/target.a`.
- let mut builder = ar::Builder::new(File::create(format!("bin/{}.a", file_stub)).unwrap());
-
- // Use `append`, not `append_path`, to avoid adding any filesystem metadata (modification times,
- // etc.).
- let file = fs::read(&obj_file).unwrap();
- builder
- .append(
- &ar::Header::new(obj_file.as_bytes().to_vec(), file.len() as u64),
- &*file,
- )
- .unwrap();
-
- fs::remove_file(&obj_file).unwrap();
-}
-
-fn assemble(target: &str, cfgs: &[&str]) {
- assemble_really(target, cfgs, false);
- assemble_really(target, cfgs, true);
-}
-
-// `--target` -> `--cfg` list (mirrors what `build.rs` does).
-static TARGETS: &[(&str, &[&str])] = &[
- ("thumbv6m-none-eabi", &[]),
- ("thumbv7m-none-eabi", &["armv7m"]),
- ("thumbv7em-none-eabi", &["armv7m", "armv7em"]),
- ("thumbv7em-none-eabihf", &["armv7m", "armv7em", "has_fpu"]),
- ("thumbv8m.base-none-eabi", &["armv8m", "armv8m_base"]),
- (
- "thumbv8m.main-none-eabi",
- &["armv7m", "armv8m", "armv8m_main"],
- ),
- (
- "thumbv8m.main-none-eabihf",
- &["armv7m", "armv8m", "armv8m_main", "has_fpu"],
- ),
-];
+use std::process::Command;
pub fn install_targets(targets: &mut dyn Iterator<Item = &str>, toolchain: Option<&str>) {
let mut rustup = Command::new("rustup");
@@ -125,90 +16,6 @@ pub fn install_targets(targets: &mut dyn Iterator<Item = &str>, toolchain: Optio
assert!(status.success(), "rustup command failed: {:?}", rustup);
}
-pub fn assemble_blobs() {
- let mut cmd = rustc();
- cmd.arg("-V");
- cmd.stdout(Stdio::null());
- let status = cmd.status().unwrap();
- let toolchain = toolchain();
-
- if !status.success() {
- println!(
- "asm toolchain {} does not seem to be installed. installing it now.",
- toolchain
- );
-
- let mut rustup = Command::new("rustup");
- let status = rustup.arg("install").arg(&toolchain).status().unwrap();
- assert!(status.success(), "rustup command failed: {:?}", rustup);
- }
-
- install_targets(
- &mut TARGETS.iter().map(|(target, _)| *target),
- Some(&*toolchain),
- );
-
- for (target, cfgs) in TARGETS {
- println!("building artifacts for {}", target);
- assemble(target, cfgs);
- }
-}
-
-pub fn check_blobs() {
- // Load each `.a` file in `bin` into memory.
- let mut files_before = BTreeMap::new();
- for entry in fs::read_dir("bin").unwrap() {
- let entry = entry.unwrap();
- if entry.path().extension().unwrap() == "a" {
- files_before.insert(
- entry
- .path()
- .file_name()
- .unwrap()
- .to_str()
- .unwrap()
- .to_string(),
- fs::read(entry.path()).unwrap(),
- );
- }
- }
-
- assemble_blobs();
-
- let mut files_after = BTreeMap::new();
- for entry in fs::read_dir("bin").unwrap() {
- let entry = entry.unwrap();
- if entry.path().extension().unwrap() == "a" {
- files_after.insert(
- entry
- .path()
- .file_name()
- .unwrap()
- .to_str()
- .unwrap()
- .to_string(),
- fs::read(entry.path()).unwrap(),
- );
- }
- }
-
- // Ensure they contain the same files.
- let before = files_before.keys().collect::<Vec<_>>();
- let after = files_after.keys().collect::<Vec<_>>();
- assert_eq!(before, after);
-
- for ((file, before), (_, after)) in files_before.iter().zip(files_after.iter()) {
- if before != after {
- panic!(
- "{} is not up-to-date, please run `cargo xtask assemble`",
- file
- );
- }
- }
-
- println!("Blobs identical.");
-}
-
// Check that serde and PartialOrd works with VectActive
pub fn check_host_side() {
use cortex_m::peripheral::{itm::LocalTimestampOptions, scb::VectActive};
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index 26dce31..4673a45 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -1,18 +1,14 @@
use std::{env, process};
-use xtask::{assemble_blobs, check_blobs, check_host_side};
+use xtask::check_host_side;
fn main() {
let subcommand = env::args().nth(1);
match subcommand.as_deref() {
- Some("assemble") => assemble_blobs(),
- Some("check-blobs") => check_blobs(),
Some("check-host-side") => check_host_side(),
_ => {
eprintln!("usage: cargo xtask <subcommand>");
eprintln!();
eprintln!("subcommands:");
- eprintln!(" assemble Reassemble the pre-built artifacts");
- eprintln!(" check-blobs Check that the pre-built artifacts are up-to-date and reproducible");
eprintln!(" check-host-side Build the crate in a non-Cortex-M host application and check host side usage of certain types");
process::exit(1);
}
diff --git a/xtask/tests/ci.rs b/xtask/tests/ci.rs
index 37466e9..603491c 100644
--- a/xtask/tests/ci.rs
+++ b/xtask/tests/ci.rs
@@ -1,6 +1,6 @@
use std::process::Command;
use std::{env, str};
-use xtask::{check_blobs, check_host_side, install_targets};
+use xtask::{check_host_side, install_targets};
/// List of all compilation targets we support.
///
@@ -44,13 +44,13 @@ fn build(package: &str, target: &str, features: &[&str]) {
#[rustfmt::skip]
static PACKAGE_FEATURES: &[(&str, &[&str], &[&str])] = &[
- ("cortex-m", ALL_TARGETS, &["inline-asm", "cm7-r0p1"]), // no `linker-plugin-lto` since it's experimental
- ("cortex-m-semihosting", ALL_TARGETS, &["inline-asm", "no-semihosting", "jlink-quirks"]),
- ("panic-semihosting", ALL_TARGETS, &["inline-asm", "exit", "jlink-quirks"]),
+ ("cortex-m", ALL_TARGETS, &["cm7-r0p1"]),
+ ("cortex-m-semihosting", ALL_TARGETS, &["no-semihosting", "jlink-quirks"]),
+ ("panic-semihosting", ALL_TARGETS, &["exit", "jlink-quirks"]),
("panic-itm", NON_BASE_TARGETS, &[]),
];
-fn check_crates_build(is_nightly: bool) {
+fn check_crates_build(_is_nightly: bool) {
// Build all crates for each supported target.
for (package, targets, all_features) in PACKAGE_FEATURES {
for target in *targets {
@@ -58,11 +58,8 @@ fn check_crates_build(is_nightly: bool) {
// Relies on all crates in this repo to use the same convention.
let should_use_feature = |feat: &str| {
match feat {
- // This is nightly-only, so don't use it on stable.
- "inline-asm" => is_nightly,
// This only affects thumbv7em targets.
"cm7-r0p1" => target.starts_with("thumbv7em"),
-
_ => true,
}
};
@@ -98,9 +95,6 @@ fn main() {
install_targets(&mut ALL_TARGETS.iter().cloned(), None);
- // Check that the ASM blobs are up-to-date.
- check_blobs();
-
let output = Command::new("rustc").arg("-V").output().unwrap();
let is_nightly = str::from_utf8(&output.stdout).unwrap().contains("nightly");