diff options
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | asm-toolchain | 2 | ||||
-rw-r--r-- | asm/inline.rs | 124 | ||||
-rw-r--r-- | asm/lib.rs | 2 | ||||
-rw-r--r-- | bin/thumbv6m-none-eabi-lto.a | bin | 11788 -> 11196 bytes | |||
-rw-r--r-- | bin/thumbv6m-none-eabi.a | bin | 16344 -> 14576 bytes | |||
-rw-r--r-- | bin/thumbv7em-none-eabi-lto.a | bin | 15928 -> 15280 bytes | |||
-rw-r--r-- | bin/thumbv7em-none-eabi.a | bin | 21532 -> 19336 bytes | |||
-rw-r--r-- | bin/thumbv7em-none-eabihf-lto.a | bin | 16892 -> 16104 bytes | |||
-rw-r--r-- | bin/thumbv7em-none-eabihf.a | bin | 22828 -> 20480 bytes | |||
-rw-r--r-- | bin/thumbv7m-none-eabi-lto.a | bin | 14908 -> 14244 bytes | |||
-rw-r--r-- | bin/thumbv7m-none-eabi.a | bin | 20184 -> 18068 bytes | |||
-rw-r--r-- | bin/thumbv8m.base-none-eabi-lto.a | bin | 15056 -> 14280 bytes | |||
-rw-r--r-- | bin/thumbv8m.base-none-eabi.a | bin | 20772 -> 18680 bytes | |||
-rw-r--r-- | bin/thumbv8m.main-none-eabi-lto.a | bin | 19552 -> 18672 bytes | |||
-rw-r--r-- | bin/thumbv8m.main-none-eabi.a | bin | 27136 -> 24408 bytes | |||
-rw-r--r-- | bin/thumbv8m.main-none-eabihf-lto.a | bin | 20528 -> 19508 bytes | |||
-rw-r--r-- | bin/thumbv8m.main-none-eabihf.a | bin | 28404 -> 25524 bytes | |||
-rw-r--r-- | build.rs | 5 | ||||
-rw-r--r-- | src/delay.rs | 22 | ||||
-rw-r--r-- | src/interrupt.rs | 11 | ||||
-rw-r--r-- | src/lib.rs | 2 | ||||
-rw-r--r-- | src/peripheral/dcb.rs | 17 | ||||
-rw-r--r-- | src/peripheral/dwt.rs | 117 | ||||
-rw-r--r-- | src/peripheral/icb.rs | 6 | ||||
-rw-r--r-- | src/peripheral/mod.rs | 8 | ||||
-rw-r--r-- | src/peripheral/scb.rs | 10 |
28 files changed, 232 insertions, 98 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e7d1e7..fdb8be9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Added `DWT.set_cycle_count` (#347). - Added support for the Cortex-M7 TCM and cache access control registers. There is a feature `cm7` to enable access to these. +- Added `delay::Delay::with_source`, a constructor that lets you specify + the SysTick clock source (#374). ### Deprecated @@ -16,7 +16,7 @@ edition = "2018" links = "cortex-m" # prevent multiple versions of this crate to be linked together [dependencies] -bare-metal = { version = "0.2.4", features = ["const-fn"] } +bare-metal = "1" volatile-register = "0.2.0" bitfield = "0.13.2" embedded-hal = "0.2.4" diff --git a/asm-toolchain b/asm-toolchain index a36829b..cc5dbb2 100644 --- a/asm-toolchain +++ b/asm-toolchain @@ -1 +1 @@ -nightly-2020-08-26 +nightly-2021-12-16 diff --git a/asm/inline.rs b/asm/inline.rs index 5887baf..bbc04d2 100644 --- a/asm/inline.rs +++ b/asm/inline.rs @@ -6,17 +6,18 @@ //! 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"); + asm!("bkpt", options(nomem, nostack, preserves_flags)); } #[inline(always)] pub unsafe fn __control_r() -> u32 { let r; - asm!("mrs {}, CONTROL", out(reg) r); + asm!("mrs {}, CONTROL", out(reg) r, options(nomem, nostack, preserves_flags)); r } @@ -27,7 +28,8 @@ pub unsafe fn __control_w(w: u32) { asm!( "msr CONTROL, {}", "isb", - in(reg) w + in(reg) w, + options(nomem, nostack, preserves_flags), ); // Ensure memory accesses are not reordered around the CONTROL update. @@ -36,7 +38,7 @@ pub unsafe fn __control_w(w: u32) { #[inline(always)] pub unsafe fn __cpsid() { - asm!("cpsid i"); + asm!("cpsid i", options(nomem, nostack, preserves_flags)); // Ensure no subsequent memory accesses are reordered to before interrupts are disabled. compiler_fence(Ordering::SeqCst); @@ -47,7 +49,7 @@ pub unsafe fn __cpsie() { // Ensure no preceeding memory accesses are reordered to after interrupts are enabled. compiler_fence(Ordering::SeqCst); - asm!("cpsie i"); + asm!("cpsie i", options(nomem, nostack, preserves_flags)); } #[inline(always)] @@ -62,48 +64,53 @@ pub unsafe fn __delay(cyc: u32) { "1:", "subs {}, #1", "bne 1b", - inout(reg) real_cyc => _ + inout(reg) real_cyc => _, + options(nomem, nostack), ); } #[inline(always)] pub unsafe fn __dmb() { compiler_fence(Ordering::SeqCst); - asm!("dmb"); + asm!("dmb", options(nomem, nostack, preserves_flags)); compiler_fence(Ordering::SeqCst); } #[inline(always)] pub unsafe fn __dsb() { compiler_fence(Ordering::SeqCst); - asm!("dsb"); + asm!("dsb", options(nomem, nostack, preserves_flags)); compiler_fence(Ordering::SeqCst); } #[inline(always)] pub unsafe fn __isb() { compiler_fence(Ordering::SeqCst); - asm!("isb"); + 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); + asm!("mrs {}, MSP", out(reg) r, options(nomem, nostack, preserves_flags)); r } #[inline(always)] pub unsafe fn __msp_w(val: u32) { - asm!("msr MSP, {}", in(reg) val); + // 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); + asm!("mrs {}, APSR", out(reg) r, options(nomem, nostack, preserves_flags)); r } @@ -112,80 +119,82 @@ 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"); + 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); + 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); + 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); + 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); + 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); + 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); + asm!("mrs {}, PSP", out(reg) r, options(nomem, nostack, preserves_flags)); r } #[inline(always)] pub unsafe fn __psp_w(val: u32) { - asm!("msr PSP, {}", in(reg) val); + // 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"); + asm!("sev", options(nomem, nostack, preserves_flags)); } #[inline(always)] pub unsafe fn __udf() -> ! { - asm!("udf #0", options(noreturn)); + asm!("udf #0", options(noreturn, nomem, nostack, preserves_flags)); } #[inline(always)] pub unsafe fn __wfe() { - asm!("wfe"); + asm!("wfe", options(nomem, nostack, preserves_flags)); } #[inline(always)] pub unsafe fn __wfi() { - asm!("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); + asm!("bkpt #0xab", inout("r0") nr, in("r1") arg, options(nomem, nostack, preserves_flags)); nr } @@ -205,7 +214,7 @@ pub unsafe fn __bootstrap(msp: u32, rv: u32) -> ! { spsel = in(reg) 2, msp = in(reg) msp, rv = in(reg) rv, - options(noreturn), + options(noreturn, nomem, nostack), ); } @@ -214,29 +223,30 @@ pub unsafe fn __bootstrap(msp: u32, rv: u32) -> ! { 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); + 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); + 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); + 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); + asm!("mrs {}, FAULTMASK", out(reg) r, options(nomem, nostack, preserves_flags)); r } @@ -255,6 +265,7 @@ mod v7m { out(reg) _, out(reg) _, out(reg) _, + options(nostack), ); compiler_fence(Ordering::SeqCst); } @@ -274,6 +285,7 @@ mod v7m { out(reg) _, out(reg) _, out(reg) _, + options(nostack), ); compiler_fence(Ordering::SeqCst); } @@ -283,6 +295,8 @@ mod v7m { pub use self::v7em::*; #[cfg(armv7em)] mod v7em { + use core::arch::asm; + #[inline(always)] pub unsafe fn __basepri_max_cm7_r0p1(val: u8) { asm!( @@ -295,6 +309,7 @@ mod v7em { "cpsie i", in(reg) val, out(reg) _, + options(nomem, nostack, preserves_flags), ); } @@ -310,6 +325,7 @@ mod v7em { "cpsie i", in(reg) val, out(reg) _, + options(nomem, nostack, preserves_flags), ); } } @@ -319,45 +335,63 @@ 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); + 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); + 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); + 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); + 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); + 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); + 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); + asm!("BXNS {}", in(reg) val, options(nomem, nostack, preserves_flags)); } } @@ -366,28 +400,30 @@ 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); + 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); + 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); + 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); + asm!("msr PSPLIM, {}", in(reg) val, options(nomem, nostack, preserves_flags)); } } @@ -396,15 +432,17 @@ 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); + 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); + asm!("vmsr fpscr, {}", in(reg) val, options(nomem, nostack)); } } @@ -34,6 +34,8 @@ #![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; diff --git a/bin/thumbv6m-none-eabi-lto.a b/bin/thumbv6m-none-eabi-lto.a Binary files differindex 6136ec6..a203d7a 100644 --- a/bin/thumbv6m-none-eabi-lto.a +++ b/bin/thumbv6m-none-eabi-lto.a diff --git a/bin/thumbv6m-none-eabi.a b/bin/thumbv6m-none-eabi.a Binary files differindex c42f579..9640a69 100644 --- a/bin/thumbv6m-none-eabi.a +++ b/bin/thumbv6m-none-eabi.a diff --git a/bin/thumbv7em-none-eabi-lto.a b/bin/thumbv7em-none-eabi-lto.a Binary files differindex c2c040a..b34ac64 100644 --- a/bin/thumbv7em-none-eabi-lto.a +++ b/bin/thumbv7em-none-eabi-lto.a diff --git a/bin/thumbv7em-none-eabi.a b/bin/thumbv7em-none-eabi.a Binary files differindex 660360f..88acbdd 100644 --- a/bin/thumbv7em-none-eabi.a +++ b/bin/thumbv7em-none-eabi.a diff --git a/bin/thumbv7em-none-eabihf-lto.a b/bin/thumbv7em-none-eabihf-lto.a Binary files differindex eba1984..6de94bb 100644 --- a/bin/thumbv7em-none-eabihf-lto.a +++ b/bin/thumbv7em-none-eabihf-lto.a diff --git a/bin/thumbv7em-none-eabihf.a b/bin/thumbv7em-none-eabihf.a Binary files differindex 1561fa4..cf91a7a 100644 --- a/bin/thumbv7em-none-eabihf.a +++ b/bin/thumbv7em-none-eabihf.a diff --git a/bin/thumbv7m-none-eabi-lto.a b/bin/thumbv7m-none-eabi-lto.a Binary files differindex d964314..7f677a9 100644 --- a/bin/thumbv7m-none-eabi-lto.a +++ b/bin/thumbv7m-none-eabi-lto.a diff --git a/bin/thumbv7m-none-eabi.a b/bin/thumbv7m-none-eabi.a Binary files differindex f541274..ff4bf21 100644 --- a/bin/thumbv7m-none-eabi.a +++ b/bin/thumbv7m-none-eabi.a diff --git a/bin/thumbv8m.base-none-eabi-lto.a b/bin/thumbv8m.base-none-eabi-lto.a Binary files differindex 8a6ed42..f62acaf 100644 --- a/bin/thumbv8m.base-none-eabi-lto.a +++ b/bin/thumbv8m.base-none-eabi-lto.a diff --git a/bin/thumbv8m.base-none-eabi.a b/bin/thumbv8m.base-none-eabi.a Binary files differindex 33cd908..c0cc96c 100644 --- a/bin/thumbv8m.base-none-eabi.a +++ b/bin/thumbv8m.base-none-eabi.a diff --git a/bin/thumbv8m.main-none-eabi-lto.a b/bin/thumbv8m.main-none-eabi-lto.a Binary files differindex 8e6ff0a..1a51515 100644 --- a/bin/thumbv8m.main-none-eabi-lto.a +++ b/bin/thumbv8m.main-none-eabi-lto.a diff --git a/bin/thumbv8m.main-none-eabi.a b/bin/thumbv8m.main-none-eabi.a Binary files differindex 898fea7..d017a15 100644 --- a/bin/thumbv8m.main-none-eabi.a +++ b/bin/thumbv8m.main-none-eabi.a diff --git a/bin/thumbv8m.main-none-eabihf-lto.a b/bin/thumbv8m.main-none-eabihf-lto.a Binary files differindex d9a636a..fd3dc92 100644 --- a/bin/thumbv8m.main-none-eabihf-lto.a +++ b/bin/thumbv8m.main-none-eabihf-lto.a diff --git a/bin/thumbv8m.main-none-eabihf.a b/bin/thumbv8m.main-none-eabihf.a Binary files differindex b0513b7..223ff1d 100644 --- a/bin/thumbv8m.main-none-eabihf.a +++ b/bin/thumbv8m.main-none-eabihf.a @@ -3,9 +3,14 @@ use std::{env, fs}; 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" diff --git a/src/delay.rs b/src/delay.rs index 8ed1fea..66a63bf 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -6,7 +6,7 @@ use embedded_hal::blocking::delay::{DelayMs, DelayUs}; /// System timer (SysTick) as a delay provider. pub struct Delay { syst: SYST, - ahb_frequency: u32, + frequency: u32, } impl Delay { @@ -14,13 +14,19 @@ impl Delay { /// /// `ahb_frequency` is a frequency of the AHB bus in Hz. #[inline] - pub fn new(mut syst: SYST, ahb_frequency: u32) -> Self { - syst.set_clock_source(SystClkSource::Core); + pub fn new(syst: SYST, ahb_frequency: u32) -> Self { + Self::with_source(syst, ahb_frequency, SystClkSource::Core) + } - Delay { - syst, - ahb_frequency, - } + /// Configures the system timer (SysTick) as a delay provider + /// with a clock source. + /// + /// `frequency` is the frequency of your `clock_source` in Hz. + #[inline] + pub fn with_source(mut syst: SYST, frequency: u32, clock_source: SystClkSource) -> Self { + syst.set_clock_source(clock_source); + + Delay { syst, frequency } } /// Releases the system timer (SysTick) resource. @@ -32,7 +38,7 @@ impl Delay { /// Delay using the Cortex-M systick for a certain duration, in µs. #[allow(clippy::missing_inline_in_public_items)] pub fn delay_us(&mut self, us: u32) { - let ticks = (u64::from(us)) * (u64::from(self.ahb_frequency)) / 1_000_000; + let ticks = (u64::from(us)) * (u64::from(self.frequency)) / 1_000_000; let full_cycles = ticks >> 24; if full_cycles > 0 { diff --git a/src/interrupt.rs b/src/interrupt.rs index 0fd1284..68719ec 100644 --- a/src/interrupt.rs +++ b/src/interrupt.rs @@ -1,6 +1,6 @@ //! Interrupts -pub use bare_metal::{CriticalSection, Mutex, Nr}; +pub use bare_metal::{CriticalSection, Mutex}; /// Trait for enums of external interrupt numbers. /// @@ -23,15 +23,6 @@ pub unsafe trait InterruptNumber: Copy { fn number(self) -> u16; } -/// Implement InterruptNumber for the old bare_metal::Nr trait. -/// This implementation is for backwards compatibility only and will be removed in cortex-m 0.8. -unsafe impl<T: Nr + Copy> InterruptNumber for T { - #[inline] - fn number(self) -> u16 { - self.nr() as u16 - } -} - /// Disables all interrupts #[inline] pub fn disable() { @@ -76,6 +76,8 @@ // - A generated #[derive(Debug)] function (in which case the attribute needs // to be applied to the struct). #![deny(clippy::missing_inline_in_public_items)] +// Don't warn about feature(asm) being stable on Rust >= 1.59.0 +#![allow(stable_features)] extern crate bare_metal; extern crate volatile_register; diff --git a/src/peripheral/dcb.rs b/src/peripheral/dcb.rs index 056150b..ef879ac 100644 --- a/src/peripheral/dcb.rs +++ b/src/peripheral/dcb.rs @@ -6,6 +6,7 @@ use crate::peripheral::DCB; use core::ptr; const DCB_DEMCR_TRCENA: u32 = 1 << 24; +const DCB_DEMCR_MON_EN: u32 = 1 << 16; /// Register block #[repr(C)] @@ -46,6 +47,22 @@ impl DCB { } } + /// Enables the [`DebugMonitor`](crate::peripheral::scb::Exception::DebugMonitor) exception + #[inline] + pub fn enable_debug_monitor(&mut self) { + unsafe { + self.demcr.modify(|w| w | DCB_DEMCR_MON_EN); + } + } + + /// Disables the [`DebugMonitor`](crate::peripheral::scb::Exception::DebugMonitor) exception + #[inline] + pub fn disable_debug_monitor(&mut self) { + unsafe { + self.demcr.modify(|w| w & !DCB_DEMCR_MON_EN); + } + } + /// Is there a debugger attached? (see note) /// /// Note: This function is [reported not to diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs index 11dd545..db0398d 100644 --- a/src/peripheral/dwt.rs +++ b/src/peripheral/dwt.rs @@ -82,11 +82,17 @@ bitfield! { #[repr(C)] #[derive(Copy, Clone)] /// Comparator FUNCTIONn register. + /// + /// See C1.8.17 "Comparator Function registers, DWT_FUNCTIONn" pub struct Function(u32); u8, function, set_function: 3, 0; emitrange, set_emitrange: 5; cycmatch, set_cycmatch: 7; datavmatch, set_datavmatch: 8; + lnk1ena, set_lnk1ena: 9; + u8, datavsize, set_datavsize: 11, 10; + u8, datavaddr0, set_datavaddr0: 15, 12; + u8, datavaddr1, set_datavaddr1: 19, 16; matched, _: 24; } @@ -114,10 +120,13 @@ impl DWT { } /// Returns `true` if the implementation supports a cycle counter - #[cfg(not(armv6m))] #[inline] pub fn has_cycle_counter(&self) -> bool { - !self.ctrl.read().nocyccnt() + #[cfg(not(armv6m))] + return !self.ctrl.read().nocyccnt(); + + #[cfg(armv6m)] + return false; } /// Returns `true` if the implementation the profiling counters @@ -318,15 +327,15 @@ impl DWT { /// Whether the comparator should match on read, write or read/write operations. #[derive(Debug, Eq, PartialEq, Copy, Clone)] pub enum AccessType { - /// Generate packet only when matched adress is read from. + /// Generate packet only when matched address is read from. ReadOnly, - /// Generate packet only when matched adress is written to. + /// Generate packet only when matched address is written to. WriteOnly, - /// Generate packet when matched adress is both read from and written to. + /// Generate packet when matched address is both read from and written to. ReadWrite, } -/// The sequence of packet(s) that should be emitted on comparator match. +/// The sequence of packet(s) or events that should be emitted/generated on comparator match. #[derive(Debug, Eq, PartialEq, Copy, Clone)] pub enum EmitOption { /// Emit only trace data value packet. @@ -341,6 +350,14 @@ pub enum EmitOption { AddressData, /// Emit trace PC value and data value packets. PCData, + /// Generate a watchpoint debug event. Either halts execution or fires a `DebugMonitor` exception. + /// + /// See more in section "Watchpoint debug event generation" page C1-729. + WatchpointDebugEvent, + /// Generate a `CMPMATCH[N]` event. + /// + /// See more in section "CMPMATCH[N] event generation" page C1-730. + CompareMatchEvent, } /// Settings for address matching @@ -356,12 +373,27 @@ pub struct ComparatorAddressSettings { pub access_type: AccessType, } +/// Settings for cycle count matching +#[derive(Debug, Eq, PartialEq, Copy, Clone)] +pub struct CycleCountSettings { + /// The function selection used. + /// See Table C1-15 for DWT cycle count comparison functions. + pub emit: EmitOption, + /// The cycle count value to compare against. + pub compare: u32, +} + /// The available functions of a DWT comparator. #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[non_exhaustive] pub enum ComparatorFunction { /// Compare accessed memory addresses. Address(ComparatorAddressSettings), + /// Compare cycle count & target value. + /// + /// **NOTE**: only supported by comparator 0 and if the HW supports the cycle counter. + /// Check [`DWT::has_cycle_counter`] for support. See C1.8.1 for more details. + CycleCount(CycleCountSettings), } /// Possible error values returned on [Comparator::configure]. @@ -377,7 +409,7 @@ impl Comparator { #[allow(clippy::missing_inline_in_public_items)] pub fn configure(&self, settings: ComparatorFunction) -> Result<(), DwtError> { match settings { - ComparatorFunction::Address(settings) => unsafe { + ComparatorFunction::Address(settings) => { // FUNCTION, EMITRANGE // See Table C1-14 let (function, emit_range) = match (&settings.access_type, &settings.emit) { @@ -385,38 +417,77 @@ impl Comparator { (AccessType::ReadOnly, EmitOption::Address) => (0b1100, true), (AccessType::ReadOnly, EmitOption::AddressData) => (0b1110, true), (AccessType::ReadOnly, EmitOption::PCData) => (0b1110, false), + (AccessType::ReadOnly, EmitOption::WatchpointDebugEvent) => (0b0101, false), + (AccessType::ReadOnly, EmitOption::CompareMatchEvent) => (0b1001, false), (AccessType::WriteOnly, EmitOption::Data) => (0b1101, false), (AccessType::WriteOnly, EmitOption::Address) => (0b1101, true), (AccessType::WriteOnly, EmitOption::AddressData) => (0b1111, true), (AccessType::WriteOnly, EmitOption::PCData) => (0b1111, false), + (AccessType::WriteOnly, EmitOption::WatchpointDebugEvent) => (0b0110, false), + (AccessType::WriteOnly, EmitOption::CompareMatchEvent) => (0b1010, false), (AccessType::ReadWrite, EmitOption::Data) => (0b0010, false), (AccessType::ReadWrite, EmitOption::Address) => (0b0001, true), (AccessType::ReadWrite, EmitOption::AddressData) => (0b0010, true), (AccessType::ReadWrite, EmitOption::PCData) => (0b0011, false), + (AccessType::ReadWrite, EmitOption::WatchpointDebugEvent) => (0b0111, false), + (AccessType::ReadWrite, EmitOption::CompareMatchEvent) => (0b1011, false), (AccessType::ReadWrite, EmitOption::PC) => (0b0001, false), (_, EmitOption::PC) => return Err(DwtError::InvalidFunction), }; - self.function.modify(|mut r| { - r.set_function(function); - r.set_emitrange(emit_range); - - // don't compare data value - r.set_datavmatch(false); - - // don't compare cycle counter value - // NOTE: only needed for comparator 0, but is SBZP. - r.set_cycmatch(false); - - r - }); + unsafe { + self.function.modify(|mut r| { + r.set_function(function); + r.set_emitrange(emit_range); + // don't compare data value + r.set_datavmatch(false); + // don't compare cycle counter value + // NOTE: only needed for comparator 0, but is SBZP. + r.set_cycmatch(false); + // SBZ as needed, see Page 784/C1-724 + r.set_datavsize(0); + r.set_datavaddr0(0); + r.set_datavaddr1(0); + + r + }); + + self.comp.write(settings.address); + self.mask.write(settings.mask); + } + } + ComparatorFunction::CycleCount(settings) => { + let function = match &settings.emit { + EmitOption::PCData => 0b0001, + EmitOption::WatchpointDebugEvent => 0b0100, + EmitOption::CompareMatchEvent => 0b1000, + _ => return Err(DwtError::InvalidFunction), + }; - self.comp.write(settings.address); - self.mask.write(settings.mask); - }, + unsafe { + self.function.modify(|mut r| { + r.set_function(function); + // emit_range is N/A for cycle count compare + r.set_emitrange(false); + // don't compare data + r.set_datavmatch(false); + // compare cyccnt + r.set_cycmatch(true); + // SBZ as needed, see Page 784/C1-724 + r.set_datavsize(0); + r.set_datavaddr0(0); + r.set_datavaddr1(0); + + r + }); + + self.comp.write(settings.compare); + self.mask.write(0); // SBZ, see Page 784/C1-724 + } + } } Ok(()) diff --git a/src/peripheral/icb.rs b/src/peripheral/icb.rs index 9b29655..e1de33b 100644 --- a/src/peripheral/icb.rs +++ b/src/peripheral/icb.rs @@ -1,6 +1,6 @@ //! Implementation Control Block -#[cfg(any(armv7m, armv8m, target_arch = "x86_64"))] +#[cfg(any(armv7m, armv8m, native))] use volatile_register::RO; use volatile_register::RW; @@ -12,12 +12,12 @@ pub struct RegisterBlock { /// The bottom four bits of this register give the number of implemented /// interrupt lines, divided by 32. So a value of `0b0010` indicates 64 /// interrupts. - #[cfg(any(armv7m, armv8m, target_arch = "x86_64"))] + #[cfg(any(armv7m, armv8m, native))] pub ictr: RO<u32>, /// The ICTR is not defined in the ARMv6-M Architecture Reference manual, so /// we replace it with this. - #[cfg(not(any(armv7m, armv8m, target_arch = "x86_64")))] + #[cfg(not(any(armv7m, armv8m, native)))] _reserved: u32, /// Auxiliary Control Register diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index 081aa0a..d1e119f 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -71,8 +71,8 @@ pub mod dcb; pub mod dwt; #[cfg(not(armv6m))] pub mod fpb; -// NOTE(target_arch) is for documentation purposes -#[cfg(any(has_fpu, target_arch = "x86_64"))] +// NOTE(native) is for documentation purposes +#[cfg(any(has_fpu, native))] pub mod fpu; pub mod icb; #[cfg(all(not(armv6m), not(armv8m_base)))] @@ -411,7 +411,7 @@ pub struct FPU { unsafe impl Send for FPU {} -#[cfg(any(has_fpu, target_arch = "x86_64"))] +#[cfg(any(has_fpu, native))] impl FPU { /// Pointer to the register block pub const PTR: *const fpu::RegisterBlock = 0xE000_EF30 as *const _; @@ -423,7 +423,7 @@ impl FPU { } } -#[cfg(any(has_fpu, target_arch = "x86_64"))] +#[cfg(any(has_fpu, native))] impl ops::Deref for FPU { type Target = self::fpu::RegisterBlock; diff --git a/src/peripheral/scb.rs b/src/peripheral/scb.rs index 6c16149..eeea0c5 100644 --- a/src/peripheral/scb.rs +++ b/src/peripheral/scb.rs @@ -182,7 +182,7 @@ impl SCB { 5 => VectActive::Exception(Exception::BusFault), #[cfg(not(armv6m))] 6 => VectActive::Exception(Exception::UsageFault), - #[cfg(any(armv8m, target_arch = "x86_64"))] + #[cfg(any(armv8m, native))] 7 => VectActive::Exception(Exception::SecureFault), 11 => VectActive::Exception(Exception::SVCall), #[cfg(not(armv6m))] @@ -218,7 +218,7 @@ pub enum Exception { UsageFault, /// Secure fault interrupt (only on ARMv8-M) - #[cfg(any(armv8m, target_arch = "x86_64"))] + #[cfg(any(armv8m, native))] SecureFault, /// SV call interrupt @@ -250,7 +250,7 @@ impl Exception { Exception::BusFault => -11, #[cfg(not(armv6m))] Exception::UsageFault => -10, - #[cfg(any(armv8m, target_arch = "x86_64"))] + #[cfg(any(armv8m, native))] Exception::SecureFault => -9, Exception::SVCall => -5, #[cfg(not(armv6m))] @@ -293,7 +293,7 @@ impl VectActive { 5 => VectActive::Exception(Exception::BusFault), #[cfg(not(armv6m))] 6 => VectActive::Exception(Exception::UsageFault), - #[cfg(any(armv8m, target_arch = "x86_64"))] + #[cfg(any(armv8m, native))] 7 => VectActive::Exception(Exception::SecureFault), 11 => VectActive::Exception(Exception::SVCall), #[cfg(not(armv6m))] @@ -934,7 +934,7 @@ pub enum SystemHandler { UsageFault = 6, /// Secure fault interrupt (only on ARMv8-M) - #[cfg(any(armv8m, target_arch = "x86_64"))] + #[cfg(any(armv8m, native))] SecureFault = 7, /// SV call interrupt |