aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml17
-rw-r--r--CHANGELOG.md37
-rw-r--r--Cargo.toml9
-rw-r--r--ci/install.sh23
-rw-r--r--ci/script.sh6
-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
14 files changed, 256 insertions, 95 deletions
diff --git a/.travis.yml b/.travis.yml
index 721b6c7..dc66bdc 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,25 +1,30 @@
-dist: trusty
language: rust
-rust: nightly-2017-03-04
-services: docker
-sudo: required
matrix:
include:
+ - env: TARGET=x86_64-unknown-linux-gnu
+ rust: nightly
- env: TARGET=thumbv6m-none-eabi
+ rust: nightly
- env: TARGET=thumbv7m-none-eabi
+ rust: nightly
- env: TARGET=thumbv7em-none-eabi
+ rust: nightly
- env: TARGET=thumbv7em-none-eabihf
-env: TARGET=x86_64-unknown-linux-gnu
+ rust: nightly
+
+before_install: set -e
install:
- sh ci/install.sh
- - source ~/.cargo/env || true
script:
- sh ci/script.sh
+after_script: set +e
+
cache: cargo
+
before_cache:
- chmod -R a+r $HOME/.cargo;
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f3777af..75616b4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,37 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
+## [v0.2.10] - 2017-06-05
+
+### Added
+
+- Functions for the instructions DMB, ISB and DSB
+
+### Changed
+
+- All the functions in the `asm` module are now `inline(always)`
+
+## [v0.2.9] - 2017-05-30
+
+### Fixed
+
+- A bug in `itm::write_all` where it would ignore the length of the buffer and
+ serialize contents that come after the buffer.
+
+## [v0.2.8] - 2017-05-30 - YANKED
+
+### Added
+
+- An `itm::write_aligned` function to write 4 byte aligned buffers to an ITM
+ port. This function is faster than `itm::write_all` for small buffers but
+ requires the buffer to be aligned.
+
+## [v0.2.7] - 2017-05-23
+
+### Added
+
+- `Dwt.enable_cycle_counter`
+
## [v0.2.6] - 2017-05-08
### Fixed
@@ -265,7 +296,11 @@ fn main() {
- Functions to get the vector table
- Wrappers over miscellaneous instructions like `bkpt`
-[Unreleased]: https://github.com/japaric/cortex-m/compare/v0.2.6...HEAD
+[Unreleased]: https://github.com/japaric/cortex-m/compare/v0.2.10...HEAD
+[v0.2.10]: https://github.com/japaric/cortex-m/compare/v0.2.9...v0.2.10
+[v0.2.9]: https://github.com/japaric/cortex-m/compare/v0.2.8...v0.2.9
+[v0.2.8]: https://github.com/japaric/cortex-m/compare/v0.2.7...v0.2.8
+[v0.2.7]: https://github.com/japaric/cortex-m/compare/v0.2.6...v0.2.7
[v0.2.6]: https://github.com/japaric/cortex-m/compare/v0.2.5...v0.2.6
[v0.2.5]: https://github.com/japaric/cortex-m/compare/v0.2.4...v0.2.5
[v0.2.4]: https://github.com/japaric/cortex-m/compare/v0.2.3...v0.2.4
diff --git a/Cargo.toml b/Cargo.toml
index 8dd7746..0c4bab6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,10 +7,9 @@ keywords = ["arm", "cortex-m", "register", "peripheral"]
license = "MIT OR Apache-2.0"
name = "cortex-m"
repository = "https://github.com/japaric/cortex-m"
-version = "0.2.6"
+version = "0.2.10"
[dependencies]
-volatile-register = "0.2.0"
-
-[dependencies.cortex-m-semihosting]
-version = "0.1.3" \ No newline at end of file
+aligned = "0.1.1"
+cortex-m-semihosting = "0.1.3"
+volatile-register = "0.2.0" \ No newline at end of file
diff --git a/ci/install.sh b/ci/install.sh
index 550a548..f978160 100644
--- a/ci/install.sh
+++ b/ci/install.sh
@@ -1,21 +1,14 @@
set -ex
main() {
- curl https://sh.rustup.rs -sSf | \
- sh -s -- -y --default-toolchain $TRAVIS_RUST_VERSION
-
- local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \
- | cut -d/ -f3 \
- | grep -E '^v[0-9.]+$' \
- | sort --version-sort \
- | tail -n1)
- curl -LSfs http://japaric.github.io/trust/install.sh | \
- sh -s -- \
- --force \
- --git japaric/cross \
- --tag $tag \
- --target x86_64-unknown-linux-musl \
- --to ~/.cargo/bin
+ case $TARGET in
+ thumbv*-none-eabi*)
+ cargo install --list | grep xargo || \
+ cargo install xargo
+ rustup component list | grep 'rust-src.*installed' || \
+ rustup component add rust-src
+ ;;
+ esac
}
# NOTE(TRAVIS_BRANCH) Travis is configured to only build *pushes* (not PRs)
diff --git a/ci/script.sh b/ci/script.sh
index 82b3a1d..080e756 100644
--- a/ci/script.sh
+++ b/ci/script.sh
@@ -1,14 +1,12 @@
set -ex
main() {
- cargo generate-lockfile
-
case $TARGET in
thumbv*-none-eabi*)
- cross build --target $TARGET
+ xargo check --target $TARGET
;;
*)
- cross test --target $TARGET
+ cargo test --target $TARGET
;;
esac
}
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,