aboutsummaryrefslogtreecommitdiff
path: root/src/cyccnt.rs
diff options
context:
space:
mode:
authorJorge Aparicio <jorge@japaric.io>2019-09-15 17:09:40 +0000
committerGitHub <noreply@github.com>2019-09-15 17:09:40 +0000
commit4ff28e9d13e845abf39c662643ae2ff5df57ec16 (patch)
tree7d9770cd357e584d85ef6ddc32bddd1a937d1020 /src/cyccnt.rs
parentfafeeb27270ef24fc3852711c6032f65aa7dbcc0 (diff)
parent7aa270cb92180abfc9102a69efdde378c3396b5e (diff)
Merge pull request #205 from japaric/heterogeneous
rtfm-syntax refactor + heterogeneous multi-core support
Diffstat (limited to 'src/cyccnt.rs')
-rw-r--r--src/cyccnt.rs216
1 files changed, 216 insertions, 0 deletions
diff --git a/src/cyccnt.rs b/src/cyccnt.rs
new file mode 100644
index 0000000..c8a1b7e
--- /dev/null
+++ b/src/cyccnt.rs
@@ -0,0 +1,216 @@
+//! Data Watchpoint Trace (DWT) unit's CYCle CouNTer
+
+use core::{
+ cmp::Ordering,
+ convert::{Infallible, TryInto},
+ fmt,
+ marker::PhantomData,
+ ops,
+};
+
+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,
+ _not_send_or_sync: PhantomData<*mut ()>,
+}
+
+unsafe impl Sync for Instant {}
+
+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<Duration> 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<Duration> for Instant {
+ type Output = Self;
+
+ fn add(mut self, dur: Duration) -> Self {
+ self += dur;
+ self
+ }
+}
+
+impl ops::SubAssign<Duration> 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<Duration> for Instant {
+ type Output = Self;
+
+ fn sub(mut self, dur: Duration) -> Self {
+ self -= dur;
+ self
+ }
+}
+
+impl ops::Sub<Instant> 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<Ordering> {
+ 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 {
+ /// 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
+ }
+}
+
+impl TryInto<u32> for Duration {
+ type Error = Infallible;
+
+ fn try_into(self) -> Result<u32, Infallible> {
+ Ok(self.as_cycles())
+ }
+}
+
+impl ops::AddAssign for Duration {
+ fn add_assign(&mut self, dur: Duration) {
+ self.inner += dur.inner;
+ }
+}
+
+impl ops::Add<Duration> 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<Duration> 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
+pub struct CYCCNT;
+
+impl crate::Monotonic for CYCCNT {
+ type Instant = Instant;
+
+ fn ratio() -> Fraction {
+ Fraction {
+ numerator: 1,
+ denominator: 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,
+ }
+ }
+}