|
|
|
@ -182,7 +182,7 @@ diff -uNr 06_uart_chainloader/src/_arch/aarch64/cpu/boot.s 07_timestamps/src/_ar
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
// Public Code
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
@@ -48,35 +37,23 @@
|
|
|
|
|
@@ -48,35 +37,31 @@
|
|
|
|
|
// If execution reaches here, it is the boot core.
|
|
|
|
|
|
|
|
|
|
// Initialize DRAM.
|
|
|
|
@ -220,6 +220,14 @@ diff -uNr 06_uart_chainloader/src/_arch/aarch64/cpu/boot.s 07_timestamps/src/_ar
|
|
|
|
|
- // Jump to the relocated Rust code.
|
|
|
|
|
- ADR_ABS x1, _start_rust
|
|
|
|
|
- br x1
|
|
|
|
|
+ // Read the CPU's timer counter frequency and store it in ARCH_TIMER_COUNTER_FREQUENCY.
|
|
|
|
|
+ // Abort if the frequency read back as 0.
|
|
|
|
|
+ ADR_REL x1, ARCH_TIMER_COUNTER_FREQUENCY // provided by aarch64/time.rs
|
|
|
|
|
+ mrs x2, CNTFRQ_EL0
|
|
|
|
|
+ cmp x2, xzr
|
|
|
|
|
+ b.eq .L_parking_loop
|
|
|
|
|
+ str w2, [x1]
|
|
|
|
|
+
|
|
|
|
|
+ // Jump to Rust code.
|
|
|
|
|
+ b _start_rust
|
|
|
|
|
|
|
|
|
@ -249,7 +257,7 @@ diff -uNr 06_uart_chainloader/src/_arch/aarch64/cpu.rs 07_timestamps/src/_arch/a
|
|
|
|
|
diff -uNr 06_uart_chainloader/src/_arch/aarch64/time.rs 07_timestamps/src/_arch/aarch64/time.rs
|
|
|
|
|
--- 06_uart_chainloader/src/_arch/aarch64/time.rs
|
|
|
|
|
+++ 07_timestamps/src/_arch/aarch64/time.rs
|
|
|
|
|
@@ -0,0 +1,121 @@
|
|
|
|
|
@@ -0,0 +1,162 @@
|
|
|
|
|
+// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
|
|
|
+//
|
|
|
|
|
+// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
|
|
|
|
@ -263,113 +271,154 @@ diff -uNr 06_uart_chainloader/src/_arch/aarch64/time.rs 07_timestamps/src/_arch/
|
|
|
|
|
+//!
|
|
|
|
|
+//! crate::time::arch_time
|
|
|
|
|
+
|
|
|
|
|
+use crate::{time, warn};
|
|
|
|
|
+use core::time::Duration;
|
|
|
|
|
+use crate::warn;
|
|
|
|
|
+use core::{
|
|
|
|
|
+ num::{NonZeroU128, NonZeroU32, NonZeroU64},
|
|
|
|
|
+ ops::{Add, Div},
|
|
|
|
|
+ time::Duration,
|
|
|
|
|
+};
|
|
|
|
|
+use cortex_a::{asm::barrier, registers::*};
|
|
|
|
|
+use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
|
|
|
|
+use tock_registers::interfaces::Readable;
|
|
|
|
|
+
|
|
|
|
|
+//--------------------------------------------------------------------------------------------------
|
|
|
|
|
+// Private Definitions
|
|
|
|
|
+//--------------------------------------------------------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+const NS_PER_S: u64 = 1_000_000_000;
|
|
|
|
|
+const NANOSEC_PER_SEC: NonZeroU64 = NonZeroU64::new(1_000_000_000).unwrap();
|
|
|
|
|
+
|
|
|
|
|
+/// ARMv8 Generic Timer.
|
|
|
|
|
+struct GenericTimer;
|
|
|
|
|
+#[derive(Copy, Clone, PartialOrd, PartialEq)]
|
|
|
|
|
+struct GenericTimerCounterValue(u64);
|
|
|
|
|
+
|
|
|
|
|
+//--------------------------------------------------------------------------------------------------
|
|
|
|
|
+// Global instances
|
|
|
|
|
+//--------------------------------------------------------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+static TIME_MANAGER: GenericTimer = GenericTimer;
|
|
|
|
|
+/// Boot assembly code overwrites this value with the value of CNTFRQ_EL0 before any Rust code is
|
|
|
|
|
+/// executed. This given value here is just a (safe) dummy.
|
|
|
|
|
+#[no_mangle]
|
|
|
|
|
+static ARCH_TIMER_COUNTER_FREQUENCY: NonZeroU32 = NonZeroU32::MIN;
|
|
|
|
|
+
|
|
|
|
|
+//--------------------------------------------------------------------------------------------------
|
|
|
|
|
+// Private Code
|
|
|
|
|
+//--------------------------------------------------------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+impl GenericTimer {
|
|
|
|
|
+ #[inline(always)]
|
|
|
|
|
+ fn read_cntpct(&self) -> u64 {
|
|
|
|
|
+ // Prevent that the counter is read ahead of time due to out-of-order execution.
|
|
|
|
|
+ unsafe { barrier::isb(barrier::SY) };
|
|
|
|
|
+ CNTPCT_EL0.get()
|
|
|
|
|
+ }
|
|
|
|
|
+impl GenericTimerCounterValue {
|
|
|
|
|
+ pub const MAX: Self = GenericTimerCounterValue(u64::MAX);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+//--------------------------------------------------------------------------------------------------
|
|
|
|
|
+// Public Code
|
|
|
|
|
+//--------------------------------------------------------------------------------------------------
|
|
|
|
|
+impl Add for GenericTimerCounterValue {
|
|
|
|
|
+ type Output = Self;
|
|
|
|
|
+
|
|
|
|
|
+/// Return a reference to the time manager.
|
|
|
|
|
+pub fn time_manager() -> &'static impl time::interface::TimeManager {
|
|
|
|
|
+ &TIME_MANAGER
|
|
|
|
|
+ fn add(self, other: Self) -> Self {
|
|
|
|
|
+ GenericTimerCounterValue(self.0.wrapping_add(other.0))
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+//------------------------------------------------------------------------------
|
|
|
|
|
+// OS Interface Code
|
|
|
|
|
+//------------------------------------------------------------------------------
|
|
|
|
|
+impl From<GenericTimerCounterValue> for Duration {
|
|
|
|
|
+ fn from(counter_value: GenericTimerCounterValue) -> Self {
|
|
|
|
|
+ if counter_value.0 == 0 {
|
|
|
|
|
+ return Duration::ZERO;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Read volatile is needed here to prevent the compiler from optimizing
|
|
|
|
|
+ // ARCH_TIMER_COUNTER_FREQUENCY away.
|
|
|
|
|
+ //
|
|
|
|
|
+ // This is safe, because all the safety requirements as stated in read_volatile()'s
|
|
|
|
|
+ // documentation are fulfilled.
|
|
|
|
|
+ let frequency: NonZeroU64 =
|
|
|
|
|
+ unsafe { core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY) }.into();
|
|
|
|
|
+
|
|
|
|
|
+impl time::interface::TimeManager for GenericTimer {
|
|
|
|
|
+ fn resolution(&self) -> Duration {
|
|
|
|
|
+ Duration::from_nanos(NS_PER_S / (CNTFRQ_EL0.get() as u64))
|
|
|
|
|
+ // Div<NonZeroU64> implementation for u64 cannot panic.
|
|
|
|
|
+ let secs = counter_value.0.div(frequency);
|
|
|
|
|
+
|
|
|
|
|
+ // This is safe, because frequency can never be greater than u32::MAX, which means the
|
|
|
|
|
+ // largest theoretical value for sub_second_counter_value is (u32::MAX - 1). Therefore,
|
|
|
|
|
+ // (sub_second_counter_value * NANOSEC_PER_SEC) cannot overflow an u64.
|
|
|
|
|
+ //
|
|
|
|
|
+ // The subsequent division ensures the result fits into u32, since the max result is smaller
|
|
|
|
|
+ // than NANOSEC_PER_SEC. Therefore, just cast it to u32 using `as`.
|
|
|
|
|
+ let sub_second_counter_value = counter_value.0 modulo frequency;
|
|
|
|
|
+ let nanos = unsafe { sub_second_counter_value.unchecked_mul(u64::from(NANOSEC_PER_SEC)) }
|
|
|
|
|
+ .div(frequency) as u32;
|
|
|
|
|
+
|
|
|
|
|
+ Duration::new(secs, nanos)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+ fn uptime(&self) -> Duration {
|
|
|
|
|
+ let current_count: u64 = self.read_cntpct() * NS_PER_S;
|
|
|
|
|
+ let frq: u64 = CNTFRQ_EL0.get() as u64;
|
|
|
|
|
+fn max_duration() -> Duration {
|
|
|
|
|
+ Duration::from(GenericTimerCounterValue::MAX)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+impl TryFrom<Duration> for GenericTimerCounterValue {
|
|
|
|
|
+ type Error = &'static str;
|
|
|
|
|
+
|
|
|
|
|
+ Duration::from_nanos(current_count / frq)
|
|
|
|
|
+ fn try_from(duration: Duration) -> Result<Self, Self::Error> {
|
|
|
|
|
+ if duration < resolution() {
|
|
|
|
|
+ return Ok(GenericTimerCounterValue(0));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fn spin_for(&self, duration: Duration) {
|
|
|
|
|
+ // Instantly return on zero.
|
|
|
|
|
+ if duration.as_nanos() == 0 {
|
|
|
|
|
+ return;
|
|
|
|
|
+ if duration > max_duration() {
|
|
|
|
|
+ return Err("Conversion error. Duration too big");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Calculate the register compare value.
|
|
|
|
|
+ let frq = CNTFRQ_EL0.get();
|
|
|
|
|
+ let x = match frq.checked_mul(duration.as_nanos() as u64) {
|
|
|
|
|
+ #[allow(unused_imports)]
|
|
|
|
|
+ None => {
|
|
|
|
|
+ warn!("Spin duration too long, skipping");
|
|
|
|
|
+ return;
|
|
|
|
|
+ // This is safe, because all the safety requirements as stated in read_volatile()'s
|
|
|
|
|
+ // documentation are fulfilled.
|
|
|
|
|
+ let frequency: u128 =
|
|
|
|
|
+ unsafe { u32::from(core::ptr::read_volatile(&ARCH_TIMER_COUNTER_FREQUENCY)) as u128 };
|
|
|
|
|
+ let duration: u128 = duration.as_nanos();
|
|
|
|
|
+
|
|
|
|
|
+ // This is safe, because frequency can never be greater than u32::MAX, and
|
|
|
|
|
+ // (Duration::MAX.as_nanos() * u32::MAX) < u128::MAX.
|
|
|
|
|
+ let counter_value =
|
|
|
|
|
+ unsafe { duration.unchecked_mul(frequency) }.div(NonZeroU128::from(NANOSEC_PER_SEC));
|
|
|
|
|
+
|
|
|
|
|
+ // Since we checked above that we are <= max_duration(), just cast to u64.
|
|
|
|
|
+ Ok(GenericTimerCounterValue(counter_value as u64))
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+ Some(val) => val,
|
|
|
|
|
+ };
|
|
|
|
|
+ let tval = x / NS_PER_S;
|
|
|
|
|
+
|
|
|
|
|
+ // Check if it is within supported bounds.
|
|
|
|
|
+ let warn: Option<&str> = if tval == 0 {
|
|
|
|
|
+ Some("smaller")
|
|
|
|
|
+ // The upper 32 bits of CNTP_TVAL_EL0 are reserved.
|
|
|
|
|
+ } else if tval > u32::max_value().into() {
|
|
|
|
|
+ Some("bigger")
|
|
|
|
|
+ } else {
|
|
|
|
|
+ None
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ #[allow(unused_imports)]
|
|
|
|
|
+ if let Some(w) = warn {
|
|
|
|
|
+ warn!(
|
|
|
|
|
+ "Spin duration {} than architecturally supported, skipping",
|
|
|
|
|
+ w
|
|
|
|
|
+ );
|
|
|
|
|
+ return;
|
|
|
|
|
+#[inline(always)]
|
|
|
|
|
+fn read_cntpct() -> GenericTimerCounterValue {
|
|
|
|
|
+ // Prevent that the counter is read ahead of time due to out-of-order execution.
|
|
|
|
|
+ unsafe { barrier::isb(barrier::SY) };
|
|
|
|
|
+ let cnt = CNTPCT_EL0.get();
|
|
|
|
|
+
|
|
|
|
|
+ GenericTimerCounterValue(cnt)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+ // Set the compare value register.
|
|
|
|
|
+ CNTP_TVAL_EL0.set(tval);
|
|
|
|
|
+//--------------------------------------------------------------------------------------------------
|
|
|
|
|
+// Public Code
|
|
|
|
|
+//--------------------------------------------------------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+ // Kick off the counting. // Disable timer interrupt.
|
|
|
|
|
+ CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET);
|
|
|
|
|
+/// The timer's resolution.
|
|
|
|
|
+pub fn resolution() -> Duration {
|
|
|
|
|
+ Duration::from(GenericTimerCounterValue(1))
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+ // ISTATUS will be '1' when cval ticks have passed. Busy-check it.
|
|
|
|
|
+ while !CNTP_CTL_EL0.matches_all(CNTP_CTL_EL0::ISTATUS::SET) {}
|
|
|
|
|
+/// The uptime since power-on of the device.
|
|
|
|
|
+///
|
|
|
|
|
+/// This includes time consumed by firmware and bootloaders.
|
|
|
|
|
+pub fn uptime() -> Duration {
|
|
|
|
|
+ read_cntpct().into()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/// Spin for a given duration.
|
|
|
|
|
+pub fn spin_for(duration: Duration) {
|
|
|
|
|
+ let curr_counter_value = read_cntpct();
|
|
|
|
|
+
|
|
|
|
|
+ // Disable counting again.
|
|
|
|
|
+ CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::CLEAR);
|
|
|
|
|
+ let counter_value_delta: GenericTimerCounterValue = match duration.try_into() {
|
|
|
|
|
+ Err(msg) => {
|
|
|
|
|
+ warn!("spin_for: {}. Skipping", msg);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ Ok(val) => val,
|
|
|
|
|
+ };
|
|
|
|
|
+ let counter_value_target = curr_counter_value + counter_value_delta;
|
|
|
|
|
+
|
|
|
|
|
+ // Busy wait.
|
|
|
|
|
+ //
|
|
|
|
|
+ // Read CNTPCT_EL0 directly to avoid the ISB that is part of [`read_cntpct`].
|
|
|
|
|
+ while GenericTimerCounterValue(CNTPCT_EL0.get()) < counter_value_target {}
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
|
|
diff -uNr 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 07_timestamps/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs
|
|
|
|
@ -380,7 +429,7 @@ diff -uNr 06_uart_chainloader/src/bsp/device_driver/bcm/bcm2xxx_gpio.rs 07_times
|
|
|
|
|
#[cfg(feature = "bsp_rpi3")]
|
|
|
|
|
fn disable_pud_14_15_bcm2837(&mut self) {
|
|
|
|
|
- use crate::cpu;
|
|
|
|
|
+ use crate::{time, time::interface::TimeManager};
|
|
|
|
|
+ use crate::time;
|
|
|
|
|
+ use core::time::Duration;
|
|
|
|
|
|
|
|
|
|
- // Make an educated guess for a good delay value (Sequence described in the BCM2837
|
|
|
|
@ -534,7 +583,20 @@ diff -uNr 06_uart_chainloader/src/cpu.rs 07_timestamps/src/cpu.rs
|
|
|
|
|
diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs
|
|
|
|
|
--- 06_uart_chainloader/src/main.rs
|
|
|
|
|
+++ 07_timestamps/src/main.rs
|
|
|
|
|
@@ -121,6 +121,7 @@
|
|
|
|
|
@@ -108,9 +108,12 @@
|
|
|
|
|
|
|
|
|
|
#![allow(clippy::upper_case_acronyms)]
|
|
|
|
|
#![feature(asm_const)]
|
|
|
|
|
+#![feature(const_option)]
|
|
|
|
|
#![feature(format_args_nl)]
|
|
|
|
|
+#![feature(nonzero_min_max)]
|
|
|
|
|
#![feature(panic_info_message)]
|
|
|
|
|
#![feature(trait_alias)]
|
|
|
|
|
+#![feature(unchecked_math)]
|
|
|
|
|
#![no_main]
|
|
|
|
|
#![no_std]
|
|
|
|
|
|
|
|
|
|
@@ -121,6 +124,7 @@
|
|
|
|
|
mod panic_wait;
|
|
|
|
|
mod print;
|
|
|
|
|
mod synchronization;
|
|
|
|
@ -542,7 +604,7 @@ diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs
|
|
|
|
|
|
|
|
|
|
/// Early init code.
|
|
|
|
|
///
|
|
|
|
|
@@ -143,55 +144,38 @@
|
|
|
|
|
@@ -143,55 +147,37 @@
|
|
|
|
|
kernel_main()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -558,7 +620,6 @@ diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs
|
|
|
|
|
- use console::console;
|
|
|
|
|
+ use core::time::Duration;
|
|
|
|
|
+ use driver::interface::DriverManager;
|
|
|
|
|
+ use time::interface::TimeManager;
|
|
|
|
|
|
|
|
|
|
- println!("{}", MINILOAD_LOGO);
|
|
|
|
|
- println!("{:^37}", bsp::board_name());
|
|
|
|
@ -630,12 +691,7 @@ diff -uNr 06_uart_chainloader/src/main.rs 07_timestamps/src/main.rs
|
|
|
|
|
diff -uNr 06_uart_chainloader/src/panic_wait.rs 07_timestamps/src/panic_wait.rs
|
|
|
|
|
--- 06_uart_chainloader/src/panic_wait.rs
|
|
|
|
|
+++ 07_timestamps/src/panic_wait.rs
|
|
|
|
|
@@ -42,18 +42,23 @@
|
|
|
|
|
|
|
|
|
|
#[panic_handler]
|
|
|
|
|
fn panic(info: &PanicInfo) -> ! {
|
|
|
|
|
+ use crate::time::interface::TimeManager;
|
|
|
|
|
+
|
|
|
|
|
@@ -45,15 +45,18 @@
|
|
|
|
|
// Protect against panic infinite loops if any of the following code panics itself.
|
|
|
|
|
panic_prevent_reenter();
|
|
|
|
|
|
|
|
|
@ -659,7 +715,7 @@ diff -uNr 06_uart_chainloader/src/panic_wait.rs 07_timestamps/src/panic_wait.rs
|
|
|
|
|
diff -uNr 06_uart_chainloader/src/print.rs 07_timestamps/src/print.rs
|
|
|
|
|
--- 06_uart_chainloader/src/print.rs
|
|
|
|
|
+++ 07_timestamps/src/print.rs
|
|
|
|
|
@@ -34,3 +34,59 @@
|
|
|
|
|
@@ -34,3 +34,51 @@
|
|
|
|
|
$crate::print::_print(format_args_nl!($($arg)*));
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
@ -668,8 +724,6 @@ diff -uNr 06_uart_chainloader/src/print.rs 07_timestamps/src/print.rs
|
|
|
|
|
+#[macro_export]
|
|
|
|
|
+macro_rules! info {
|
|
|
|
|
+ ($string:expr) => ({
|
|
|
|
|
+ use $crate::time::interface::TimeManager;
|
|
|
|
|
+
|
|
|
|
|
+ let timestamp = $crate::time::time_manager().uptime();
|
|
|
|
|
+
|
|
|
|
|
+ $crate::print::_print(format_args_nl!(
|
|
|
|
@ -679,8 +733,6 @@ diff -uNr 06_uart_chainloader/src/print.rs 07_timestamps/src/print.rs
|
|
|
|
|
+ ));
|
|
|
|
|
+ });
|
|
|
|
|
+ ($format_string:expr, $($arg:tt)*) => ({
|
|
|
|
|
+ use $crate::time::interface::TimeManager;
|
|
|
|
|
+
|
|
|
|
|
+ let timestamp = $crate::time::time_manager().uptime();
|
|
|
|
|
+
|
|
|
|
|
+ $crate::print::_print(format_args_nl!(
|
|
|
|
@ -696,8 +748,6 @@ diff -uNr 06_uart_chainloader/src/print.rs 07_timestamps/src/print.rs
|
|
|
|
|
+#[macro_export]
|
|
|
|
|
+macro_rules! warn {
|
|
|
|
|
+ ($string:expr) => ({
|
|
|
|
|
+ use $crate::time::interface::TimeManager;
|
|
|
|
|
+
|
|
|
|
|
+ let timestamp = $crate::time::time_manager().uptime();
|
|
|
|
|
+
|
|
|
|
|
+ $crate::print::_print(format_args_nl!(
|
|
|
|
@ -707,8 +757,6 @@ diff -uNr 06_uart_chainloader/src/print.rs 07_timestamps/src/print.rs
|
|
|
|
|
+ ));
|
|
|
|
|
+ });
|
|
|
|
|
+ ($format_string:expr, $($arg:tt)*) => ({
|
|
|
|
|
+ use $crate::time::interface::TimeManager;
|
|
|
|
|
+
|
|
|
|
|
+ let timestamp = $crate::time::time_manager().uptime();
|
|
|
|
|
+
|
|
|
|
|
+ $crate::print::_print(format_args_nl!(
|
|
|
|
@ -723,7 +771,7 @@ diff -uNr 06_uart_chainloader/src/print.rs 07_timestamps/src/print.rs
|
|
|
|
|
diff -uNr 06_uart_chainloader/src/time.rs 07_timestamps/src/time.rs
|
|
|
|
|
--- 06_uart_chainloader/src/time.rs
|
|
|
|
|
+++ 07_timestamps/src/time.rs
|
|
|
|
|
@@ -0,0 +1,37 @@
|
|
|
|
|
@@ -0,0 +1,57 @@
|
|
|
|
|
+// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
|
|
|
+//
|
|
|
|
|
+// Copyright (c) 2020-2022 Andre Richter <andre.o.richter@gmail.com>
|
|
|
|
@ -734,31 +782,51 @@ diff -uNr 06_uart_chainloader/src/time.rs 07_timestamps/src/time.rs
|
|
|
|
|
+#[path = "_arch/aarch64/time.rs"]
|
|
|
|
|
+mod arch_time;
|
|
|
|
|
+
|
|
|
|
|
+use core::time::Duration;
|
|
|
|
|
+
|
|
|
|
|
+//--------------------------------------------------------------------------------------------------
|
|
|
|
|
+// Architectural Public Reexports
|
|
|
|
|
+// Public Definitions
|
|
|
|
|
+//--------------------------------------------------------------------------------------------------
|
|
|
|
|
+pub use arch_time::time_manager;
|
|
|
|
|
+
|
|
|
|
|
+/// Provides time management functions.
|
|
|
|
|
+pub struct TimeManager;
|
|
|
|
|
+
|
|
|
|
|
+//--------------------------------------------------------------------------------------------------
|
|
|
|
|
+// Public Definitions
|
|
|
|
|
+// Global instances
|
|
|
|
|
+//--------------------------------------------------------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+/// Timekeeping interfaces.
|
|
|
|
|
+pub mod interface {
|
|
|
|
|
+ use core::time::Duration;
|
|
|
|
|
+static TIME_MANAGER: TimeManager = TimeManager::new();
|
|
|
|
|
+
|
|
|
|
|
+//--------------------------------------------------------------------------------------------------
|
|
|
|
|
+// Public Code
|
|
|
|
|
+//--------------------------------------------------------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+/// Return a reference to the global TimeManager.
|
|
|
|
|
+pub fn time_manager() -> &'static TimeManager {
|
|
|
|
|
+ &TIME_MANAGER
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+impl TimeManager {
|
|
|
|
|
+ /// Create an instance.
|
|
|
|
|
+ pub const fn new() -> Self {
|
|
|
|
|
+ Self
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// Time management functions.
|
|
|
|
|
+ pub trait TimeManager {
|
|
|
|
|
+ /// The timer's resolution.
|
|
|
|
|
+ fn resolution(&self) -> Duration;
|
|
|
|
|
+ pub fn resolution(&self) -> Duration {
|
|
|
|
|
+ arch_time::resolution()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// The uptime since power-on of the device.
|
|
|
|
|
+ ///
|
|
|
|
|
+ /// This includes time consumed by firmware and bootloaders.
|
|
|
|
|
+ fn uptime(&self) -> Duration;
|
|
|
|
|
+ pub fn uptime(&self) -> Duration {
|
|
|
|
|
+ arch_time::uptime()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// Spin for a given duration.
|
|
|
|
|
+ fn spin_for(&self, duration: Duration);
|
|
|
|
|
+ pub fn spin_for(&self, duration: Duration) {
|
|
|
|
|
+ arch_time::spin_for(duration)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
|
|