From 81275bfa4f41e2066770087f3a33cad4227eab41 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 13 Jun 2019 23:56:59 +0200 Subject: rtfm-syntax refactor + heterogeneous multi-core support --- src/cyccnt.rs | 205 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 src/cyccnt.rs (limited to 'src/cyccnt.rs') diff --git a/src/cyccnt.rs b/src/cyccnt.rs new file mode 100644 index 0000000..a2b216c --- /dev/null +++ b/src/cyccnt.rs @@ -0,0 +1,205 @@ +//! Data Watchpoint Trace (DWT) unit's CYCle CouNTer + +use core::{ + cmp::Ordering, + convert::{Infallible, TryInto}, + fmt, + marker::PhantomData, + ops, +}; + +use cortex_m::peripheral::DWT; + +/// A measurement of the CYCCNT. Opaque and useful only with `Duration` +/// +/// This data type is only available on ARMv7-M +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct Instant { + inner: i32, + _not_send_or_sync: PhantomData<*mut ()>, +} + +unsafe impl Sync for Instant {} + +#[cfg(not(feature = "heterogeneous"))] +unsafe impl Send for Instant {} + +impl Instant { + /// Returns an instant corresponding to "now" + pub fn now() -> Self { + Instant { + inner: DWT::get_cycle_count() as i32, + _not_send_or_sync: PhantomData, + } + } + + /// Returns the amount of time elapsed since this instant was created. + pub fn elapsed(&self) -> Duration { + Instant::now() - *self + } + + /// Returns the amount of time elapsed from another instant to this one. + pub fn duration_since(&self, earlier: Instant) -> Duration { + let diff = self.inner - earlier.inner; + assert!(diff >= 0, "second instant is later than self"); + Duration { inner: diff as u32 } + } +} + +impl fmt::Debug for Instant { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Instant") + .field(&(self.inner as u32)) + .finish() + } +} + +impl ops::AddAssign for Instant { + fn add_assign(&mut self, dur: Duration) { + debug_assert!(dur.inner < (1 << 31)); + self.inner = self.inner.wrapping_add(dur.inner as i32); + } +} + +impl ops::Add for Instant { + type Output = Self; + + fn add(mut self, dur: Duration) -> Self { + self += dur; + self + } +} + +impl ops::SubAssign for Instant { + fn sub_assign(&mut self, dur: Duration) { + // XXX should this be a non-debug assertion? + debug_assert!(dur.inner < (1 << 31)); + self.inner = self.inner.wrapping_sub(dur.inner as i32); + } +} + +impl ops::Sub for Instant { + type Output = Self; + + fn sub(mut self, dur: Duration) -> Self { + self -= dur; + self + } +} + +impl ops::Sub for Instant { + type Output = Duration; + + fn sub(self, other: Instant) -> Duration { + self.duration_since(other) + } +} + +impl Ord for Instant { + fn cmp(&self, rhs: &Self) -> Ordering { + self.inner.wrapping_sub(rhs.inner).cmp(&0) + } +} + +impl PartialOrd for Instant { + fn partial_cmp(&self, rhs: &Self) -> Option { + Some(self.cmp(rhs)) + } +} + +/// A `Duration` type to represent a span of time. +/// +/// This data type is only available on ARMv7-M +#[derive(Clone, Copy, Default, Eq, Ord, PartialEq, PartialOrd)] +pub struct Duration { + inner: u32, +} + +impl Duration { + /// Returns the total number of clock cycles contained by this `Duration` + pub fn as_cycles(&self) -> u32 { + self.inner + } +} + +impl TryInto for Duration { + type Error = Infallible; + + fn try_into(self) -> Result { + Ok(self.as_cycles()) + } +} + +impl ops::AddAssign for Duration { + fn add_assign(&mut self, dur: Duration) { + self.inner += dur.inner; + } +} + +impl ops::Add for Duration { + type Output = Self; + + fn add(self, other: Self) -> Self { + Duration { + inner: self.inner + other.inner, + } + } +} + +impl ops::SubAssign for Duration { + fn sub_assign(&mut self, rhs: Duration) { + self.inner -= rhs.inner; + } +} + +impl ops::Sub for Duration { + type Output = Self; + + fn sub(self, rhs: Self) -> Self { + Duration { + inner: self.inner - rhs.inner, + } + } +} + +/// Adds the `cycles` method to the `u32` type +/// +/// This trait is only available on ARMv7-M +pub trait U32Ext { + /// Converts the `u32` value into clock cycles + fn cycles(self) -> Duration; +} + +impl U32Ext for u32 { + fn cycles(self) -> Duration { + Duration { inner: self } + } +} + +/// Implementation of the `Monotonic` trait based on CYCle CouNTer +#[cfg(not(feature = "heterogeneous"))] +pub struct CYCCNT; + +#[cfg(not(feature = "heterogeneous"))] +unsafe impl crate::Monotonic for CYCCNT { + type Instant = Instant; + + fn ratio() -> u32 { + 1 + } + + unsafe fn reset() { + (0xE0001004 as *mut u32).write_volatile(0) + } + + fn now() -> Instant { + Instant::now() + } + + fn zero() -> Instant { + Instant { + inner: 0, + _not_send_or_sync: PhantomData, + } + } +} -- cgit v1.2.3 From 596cf585ea8dc278d88e0652dffbacbc75de04c6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 24 Jun 2019 14:09:12 +0200 Subject: Monotonic trait is safe; add MultiCore trait --- src/cyccnt.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/cyccnt.rs') diff --git a/src/cyccnt.rs b/src/cyccnt.rs index a2b216c..468aa71 100644 --- a/src/cyccnt.rs +++ b/src/cyccnt.rs @@ -116,6 +116,11 @@ pub struct Duration { } impl Duration { + /// Creates a new `Duration` from the specified number of clock cycles + pub fn from_cycles(cycles: u32) -> Self { + Duration { inner: cycles } + } + /// Returns the total number of clock cycles contained by this `Duration` pub fn as_cycles(&self) -> u32 { self.inner @@ -181,7 +186,7 @@ impl U32Ext for u32 { pub struct CYCCNT; #[cfg(not(feature = "heterogeneous"))] -unsafe impl crate::Monotonic for CYCCNT { +impl crate::Monotonic for CYCCNT { type Instant = Instant; fn ratio() -> u32 { -- cgit v1.2.3 From a87cb2486f488666450636c9cb68f79681f5f358 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 11 Jul 2019 13:28:25 +0200 Subject: change Monotonic::ratio return type to Fraction --- src/cyccnt.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'src/cyccnt.rs') diff --git a/src/cyccnt.rs b/src/cyccnt.rs index 468aa71..c8a1b7e 100644 --- a/src/cyccnt.rs +++ b/src/cyccnt.rs @@ -10,9 +10,15 @@ use core::{ use cortex_m::peripheral::DWT; +use crate::Fraction; + /// A measurement of the CYCCNT. Opaque and useful only with `Duration` /// /// This data type is only available on ARMv7-M +/// +/// Note that this value is tied to the CYCCNT of one core and that sending it a different core +/// makes it lose its meaning -- each Cortex-M core has its own CYCCNT counter and these are usually +/// unsynchronized and they may even be running at different frequencies. #[derive(Clone, Copy, Eq, PartialEq)] pub struct Instant { inner: i32, @@ -21,7 +27,6 @@ pub struct Instant { unsafe impl Sync for Instant {} -#[cfg(not(feature = "heterogeneous"))] unsafe impl Send for Instant {} impl Instant { @@ -182,15 +187,16 @@ impl U32Ext for u32 { } /// Implementation of the `Monotonic` trait based on CYCle CouNTer -#[cfg(not(feature = "heterogeneous"))] pub struct CYCCNT; -#[cfg(not(feature = "heterogeneous"))] impl crate::Monotonic for CYCCNT { type Instant = Instant; - fn ratio() -> u32 { - 1 + fn ratio() -> Fraction { + Fraction { + numerator: 1, + denominator: 1, + } } unsafe fn reset() { -- cgit v1.2.3