diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/asm.rs | 56 | ||||
-rw-r--r-- | src/exception.rs | 1 | ||||
-rw-r--r-- | src/itm.rs | 129 | ||||
-rw-r--r-- | src/lib.rs | 1 | ||||
-rw-r--r-- | src/peripheral/mod.rs | 60 | ||||
-rw-r--r-- | src/register/apsr.rs | 1 | ||||
-rw-r--r-- | src/register/control.rs | 7 | ||||
-rw-r--r-- | src/register/faultmask.rs | 2 | ||||
-rw-r--r-- | src/register/primask.rs | 2 |
9 files changed, 195 insertions, 64 deletions
@@ -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 @@ -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); + } } } @@ -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, |