aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/asm.rs56
-rw-r--r--src/exception.rs1
-rw-r--r--src/itm.rs129
-rw-r--r--src/lib.rs1
-rw-r--r--src/peripheral/mod.rs60
-rw-r--r--src/register/apsr.rs1
-rw-r--r--src/register/control.rs7
-rw-r--r--src/register/faultmask.rs2
-rw-r--r--src/register/primask.rs2
9 files changed, 195 insertions, 64 deletions
diff --git a/src/asm.rs b/src/asm.rs
index c82d45d..daa7b55 100644
--- a/src/asm.rs
+++ b/src/asm.rs
@@ -18,6 +18,7 @@ pub fn bkpt() {
}
/// A no-operation. Useful to prevent delay loops from being optimized away.
+#[inline(always)]
pub fn nop() {
unsafe {
asm!("nop"
@@ -28,6 +29,7 @@ pub fn nop() {
}
}
/// Wait For Event
+#[inline(always)]
pub fn wfe() {
match () {
#[cfg(target_arch = "arm")]
@@ -44,6 +46,7 @@ pub fn wfe() {
}
/// Wait For Interrupt
+#[inline(always)]
pub fn wfi() {
match () {
#[cfg(target_arch = "arm")]
@@ -58,3 +61,56 @@ pub fn wfi() {
() => {}
}
}
+
+/// Instruction Synchronization Barrier
+///
+/// Flushes the pipeline in the processor, so that all instructions following the `ISB` are fetched
+/// from cache or memory, after the instruction has been completed.
+#[inline(always)]
+pub fn isb() {
+ match () {
+ #[cfg(target_arch = "arm")]
+ () => unsafe {
+ asm!("isb 0xF" : : : "memory" : "volatile");
+ },
+ #[cfg(not(target_arch = "arm"))]
+ () => {}
+ }
+}
+
+/// Data Synchronization Barrier
+///
+/// Acts as a special kind of memory barrier. No instruction in program order after this
+/// instruction can execute until this instruction completes. This instruction completes only when
+/// both:
+///
+/// * any explicit memory access made before this instruction is complete
+/// * all cache and branch predictor maintenance operations before this instruction complete
+#[inline(always)]
+pub fn dsb() {
+ match () {
+ #[cfg(target_arch = "arm")]
+ () => unsafe {
+ asm!("dsb 0xF" : : : "memory" : "volatile");
+ },
+ #[cfg(not(target_arch = "arm"))]
+ () => {}
+ }
+}
+
+/// Data Memory Barrier
+///
+/// Ensures that all explicit memory accesses that appear in program order before the `DMB`
+/// instruction are observed before any explicit memory accesses that appear in program order
+/// after the `DMB` instruction.
+#[inline(always)]
+pub fn dmb() {
+ match () {
+ #[cfg(target_arch = "arm")]
+ () => unsafe {
+ asm!("dmb 0xF" : : : "memory" : "volatile");
+ },
+ #[cfg(not(target_arch = "arm"))]
+ () => {}
+ }
+}
diff --git a/src/exception.rs b/src/exception.rs
index f5b52f6..61b7415 100644
--- a/src/exception.rs
+++ b/src/exception.rs
@@ -190,6 +190,7 @@ where
}
/// Registers stacked during an exception
+#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct StackedRegisters {
/// (General purpose) Register 0
diff --git a/src/itm.rs b/src/itm.rs
index 4c49d14..80de99c 100644
--- a/src/itm.rs
+++ b/src/itm.rs
@@ -1,37 +1,10 @@
//! Instrumentation Trace Macrocell
-use core::{fmt, ptr, slice};
-use peripheral::Stim;
-
-fn round_up_to_multiple_of(x: usize, k: usize) -> usize {
- let rem = x % k;
-
- if rem == 0 { x } else { x + k - rem }
-}
+use core::{fmt, mem, ptr, slice};
-fn round_down_to_multiple_of(x: usize, k: usize) -> usize {
- x - (x % k)
-}
-
-unsafe fn split(buffer: &[u8]) -> (&[u8], &[u32], &[u8]) {
- let start = buffer.as_ptr();
- let end = start.offset(buffer.len() as isize);
- let sbody = round_up_to_multiple_of(start as usize, 4);
- let ebody = round_down_to_multiple_of(end as usize, 4);
+use aligned::Aligned;
- let head = slice::from_raw_parts(start, sbody - start as usize);
- let body = slice::from_raw_parts(sbody as *const _, (ebody - sbody) >> 2);
- let tail = slice::from_raw_parts(ebody as *const _, end as usize - ebody);
-
- (head, body, tail)
-}
-
-fn write_bytes(stim: &Stim, bytes: &[u8]) {
- for byte in bytes {
- while !stim.is_fifo_ready() {}
- stim.write_u8(*byte);
- }
-}
+use peripheral::Stim;
// NOTE assumes that `bytes` is 32-bit aligned
unsafe fn write_words(stim: &Stim, bytes: &[u32]) {
@@ -54,13 +27,95 @@ impl<'p> fmt::Write for Port<'p> {
/// Writes a `buffer` to the ITM `port`
pub fn write_all(port: &Stim, buffer: &[u8]) {
- if buffer.len() < 7 {
- write_bytes(port, buffer);
- } else {
- let (head, body, tail) = unsafe { split(buffer) };
- write_bytes(port, head);
- unsafe { write_words(port, body) }
- write_bytes(port, tail);
+ unsafe {
+ let mut len = buffer.len();
+ let mut ptr = buffer.as_ptr();
+
+ if len == 0 {
+ return;
+ }
+
+ // 0x01 OR 0x03
+ if ptr as usize % 2 == 1 {
+ while !port.is_fifo_ready() {}
+ port.write_u8(*ptr);
+
+ // 0x02 OR 0x04
+ ptr = ptr.offset(1);
+ len -= 1;
+ }
+
+ // 0x02
+ if ptr as usize % 4 == 2 {
+ if len > 1 {
+ // at least 2 bytes
+ while !port.is_fifo_ready() {}
+ port.write_u16(ptr::read(ptr as *const u16));
+
+ // 0x04
+ ptr = ptr.offset(2);
+ len -= 2;
+ } else {
+ if len == 1 {
+ // last byte
+ while !port.is_fifo_ready() {}
+ port.write_u8(*ptr);
+ }
+
+ return;
+ }
+ }
+
+ write_aligned(port, mem::transmute(slice::from_raw_parts(ptr, len)));
+ }
+}
+
+/// Writes a 4-byte aligned `buffer` to the ITM `port`
+///
+/// # Examples
+///
+/// ``` ignore
+/// let mut buffer: Aligned<u32, _> = Aligned([0; 14]);
+///
+/// buffer.copy_from_slice(b"Hello, world!\n");
+///
+/// itm::write_aligned(&itm.stim[0], &buffer);
+///
+/// // Or equivalently
+/// itm::write_aligned(&itm.stim[0], &Aligned(*b"Hello, world!\n"));
+/// ```
+pub fn write_aligned(port: &Stim, buffer: &Aligned<u32, [u8]>) {
+ unsafe {
+ let len = buffer.len();
+
+ if len == 0 {
+ return;
+ }
+
+ let split = len & !0b11;
+ write_words(
+ port,
+ slice::from_raw_parts(buffer.as_ptr() as *const u32, split >> 2),
+ );
+
+ // 3 bytes or less left
+ let mut left = len & 0b11;
+ let mut ptr = buffer.as_ptr().offset(split as isize);
+
+ // at least 2 bytes left
+ if left > 1 {
+ while !port.is_fifo_ready() {}
+ port.write_u16(ptr::read(ptr as *const u16));
+
+ ptr = ptr.offset(2);
+ left -= 2;
+ }
+
+ // final byte
+ if left == 1 {
+ while !port.is_fifo_ready() {}
+ port.write_u8(*ptr);
+ }
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 95a1b69..7e9c6fb 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -16,6 +16,7 @@
#![feature(naked_functions)]
#![no_std]
+extern crate aligned;
pub extern crate cortex_m_semihosting as semihosting;
extern crate volatile_register;
diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs
index 4756027..0ca1a80 100644
--- a/src/peripheral/mod.rs
+++ b/src/peripheral/mod.rs
@@ -51,6 +51,7 @@ pub const TPIU: Peripheral<Tpiu> = unsafe { Peripheral::new(0xE004_0000) };
// TODO stand-alone registers: ICTR, ACTLR and STIR
/// A peripheral
+#[derive(Debug)]
pub struct Peripheral<T>
where
T: 'static,
@@ -149,6 +150,13 @@ pub struct Dwt {
pub lsr: RO<u32>,
}
+impl Dwt {
+ /// Enables the cycle counter
+ pub fn enable_cycle_counter(&self) {
+ unsafe { self.ctrl.modify(|r| r | 1) }
+ }
+}
+
/// Comparator
#[repr(C)]
pub struct Comparator {
@@ -425,6 +433,7 @@ pub struct Scb {
}
/// FPU access mode
+#[derive(Clone, Copy, Debug)]
pub enum FpuAccessMode {
/// FPU is not accessible
Disabled,
@@ -434,17 +443,19 @@ pub enum FpuAccessMode {
Privileged,
}
-const SCB_CPACR_FPU_MASK: u32 = 0x00f00000;
+const SCB_CPACR_FPU_MASK: u32 = 0x00f00000;
const SCB_CPACR_FPU_ENABLE: u32 = 0x00500000;
-const SCB_CPACR_FPU_USER: u32 = 0x00a00000;
+const SCB_CPACR_FPU_USER: u32 = 0x00a00000;
impl Scb {
/// Gets FPU access mode
pub fn fpu_access_mode(&self) -> FpuAccessMode {
let cpacr = self.cpacr.read();
- if cpacr & (SCB_CPACR_FPU_ENABLE | SCB_CPACR_FPU_USER) != 0 {
+ if cpacr & SCB_CPACR_FPU_MASK ==
+ SCB_CPACR_FPU_ENABLE | SCB_CPACR_FPU_USER
+ {
FpuAccessMode::Enabled
- } else if cpacr & SCB_CPACR_FPU_ENABLE != 0 {
+ } else if cpacr & SCB_CPACR_FPU_MASK == SCB_CPACR_FPU_ENABLE {
FpuAccessMode::Privileged
} else {
FpuAccessMode::Disabled
@@ -456,10 +467,10 @@ impl Scb {
let mut cpacr = self.cpacr.read() & !SCB_CPACR_FPU_MASK;
match mode {
FpuAccessMode::Disabled => (),
- FpuAccessMode::Privileged =>
- cpacr |= SCB_CPACR_FPU_ENABLE,
- FpuAccessMode::Enabled =>
- cpacr |= SCB_CPACR_FPU_ENABLE | SCB_CPACR_FPU_USER,
+ FpuAccessMode::Privileged => cpacr |= SCB_CPACR_FPU_ENABLE,
+ FpuAccessMode::Enabled => {
+ cpacr |= SCB_CPACR_FPU_ENABLE | SCB_CPACR_FPU_USER
+ }
}
unsafe { self.cpacr.write(cpacr) }
}
@@ -489,22 +500,23 @@ pub struct Syst {
}
/// SysTick clock source
+#[derive(Clone, Copy, Debug)]
pub enum SystClkSource {
/// Core-provided clock
Core,
/// External reference clock
- External
+ External,
}
-const SYST_COUNTER_MASK: u32 = 0x00ffffff;
+const SYST_COUNTER_MASK: u32 = 0x00ffffff;
-const SYST_CSR_ENABLE: u32 = 1 << 0;
-const SYST_CSR_TICKINT: u32 = 1 << 1;
+const SYST_CSR_ENABLE: u32 = 1 << 0;
+const SYST_CSR_TICKINT: u32 = 1 << 1;
const SYST_CSR_CLKSOURCE: u32 = 1 << 2;
const SYST_CSR_COUNTFLAG: u32 = 1 << 16;
-const SYST_CALIB_SKEW: u32 = 1 << 30;
-const SYST_CALIB_NOREF: u32 = 1 << 31;
+const SYST_CALIB_SKEW: u32 = 1 << 30;
+const SYST_CALIB_NOREF: u32 = 1 << 31;
impl Syst {
/// Checks if counter is enabled
@@ -542,17 +554,19 @@ impl Syst {
let clk_source_bit = self.csr.read() & SYST_CSR_CLKSOURCE != 0;
match clk_source_bit {
false => SystClkSource::External,
- true => SystClkSource::Core
+ true => SystClkSource::Core,
}
}
/// Sets clock source
pub fn set_clock_source(&self, clk_source: SystClkSource) {
match clk_source {
- SystClkSource::External =>
- unsafe { self.csr.modify(|v| v & !SYST_CSR_CLKSOURCE) },
- SystClkSource::Core =>
- unsafe { self.csr.modify(|v| v | SYST_CSR_CLKSOURCE) }
+ SystClkSource::External => unsafe {
+ self.csr.modify(|v| v & !SYST_CSR_CLKSOURCE)
+ },
+ SystClkSource::Core => unsafe {
+ self.csr.modify(|v| v | SYST_CSR_CLKSOURCE)
+ },
}
}
@@ -586,7 +600,8 @@ impl Syst {
unsafe { self.cvr.write(0) }
}
- /// Returns the reload value with which the counter would wrap once per 10 ms
+ /// Returns the reload value with which the counter would wrap once per 10
+ /// ms
///
/// Returns `0` if the value is not known (e.g. because the clock can
/// change dynamically).
@@ -596,8 +611,9 @@ impl Syst {
/// Checks if the calibration value is precise
///
- /// Returns `false` if using the reload value returned by `get_ticks_per_10ms()`
- /// may result in a period significantly deviating from 10 ms.
+ /// Returns `false` if using the reload value returned by
+ /// `get_ticks_per_10ms()` may result in a period significantly deviating
+ /// from 10 ms.
pub fn is_precise(&self) -> bool {
self.calib.read() & SYST_CALIB_SKEW == 0
}
diff --git a/src/register/apsr.rs b/src/register/apsr.rs
index 338c684..d966de0 100644
--- a/src/register/apsr.rs
+++ b/src/register/apsr.rs
@@ -1,6 +1,7 @@
//! Application Program Status Register
/// Application Program Status Register
+#[derive(Clone, Copy, Debug)]
pub struct Apsr {
bits: u32,
}
diff --git a/src/register/control.rs b/src/register/control.rs
index 62ebff6..d5cb8ec 100644
--- a/src/register/control.rs
+++ b/src/register/control.rs
@@ -1,6 +1,7 @@
//! Control register
/// Control register
+#[derive(Clone, Copy, Debug)]
pub struct Control {
bits: u32,
}
@@ -40,7 +41,7 @@ impl Control {
}
/// Thread mode privilege level
-#[derive(Clone, Copy, Eq, PartialEq)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Npriv {
/// Privileged
Privileged,
@@ -61,7 +62,7 @@ impl Npriv {
}
/// Currently active stack pointer
-#[derive(Clone, Copy, Eq, PartialEq)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Spsel {
/// MSP is the current stack pointer
Msp,
@@ -82,7 +83,7 @@ impl Spsel {
}
/// Whether context floating-point is currently active
-#[derive(Clone, Copy, Eq, PartialEq)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Fpca {
/// Floating-point context active.
Active,
diff --git a/src/register/faultmask.rs b/src/register/faultmask.rs
index 5a06b37..7a0d06c 100644
--- a/src/register/faultmask.rs
+++ b/src/register/faultmask.rs
@@ -1,7 +1,7 @@
//! Fault Mask Register
/// All exceptions are ...
-#[derive(Clone, Copy, Eq, PartialEq)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Faultmask {
/// Active
Active,
diff --git a/src/register/primask.rs b/src/register/primask.rs
index 1e24b73..313693f 100644
--- a/src/register/primask.rs
+++ b/src/register/primask.rs
@@ -1,7 +1,7 @@
//! Priority mask register
/// All exceptions with configurable priority are ...
-#[derive(Clone, Copy, Eq, PartialEq)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Primask {
/// Active
Active,