aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/asm.rs35
-rw-r--r--src/interrupt.rs47
-rw-r--r--src/lib.rs78
-rw-r--r--src/peripheral/cpuid.rs30
-rw-r--r--src/peripheral/dcb.rs16
-rw-r--r--src/peripheral/dwt.rs43
-rw-r--r--src/peripheral/fpb.rs19
-rw-r--r--src/peripheral/fpu.rs17
-rw-r--r--src/peripheral/itm.rs54
-rw-r--r--src/peripheral/mod.rs149
-rw-r--r--src/peripheral/mpu.rs30
-rw-r--r--src/peripheral/nvic.rs25
-rw-r--r--src/peripheral/scb.rs37
-rw-r--r--src/peripheral/syst.rs16
-rw-r--r--src/peripheral/test.rs162
-rw-r--r--src/peripheral/tpiu.rs26
-rw-r--r--src/register.rs126
17 files changed, 910 insertions, 0 deletions
diff --git a/src/asm.rs b/src/asm.rs
new file mode 100644
index 0000000..3337626
--- /dev/null
+++ b/src/asm.rs
@@ -0,0 +1,35 @@
+//! Miscellaneous assembly instructions
+
+/// Puts the processor in Debug state. Debuggers can pick this up as a "breakpoint".
+///
+/// Optionally, an "immediate" value (in the 0-255 range) can be passed to `bkpt!`. The debugger can
+/// then read this value using the Program Counter (PC).
+#[macro_export]
+macro_rules! bkpt {
+ () => {
+ asm!("bkpt" :::: "volatile");
+ };
+ ($imm:expr) => {
+ asm!(concat!("bkpt #", stringify!($imm)) :::: "volatile");
+ };
+}
+
+/// Wait for event
+pub unsafe fn wfe() {
+ match () {
+ #[cfg(target_arch = "arm")]
+ () => asm!("wfe" :::: "volatile"),
+ #[cfg(not(target_arch = "arm"))]
+ () => {}
+ }
+}
+
+/// Wait for interupt
+pub unsafe fn wfi() {
+ match () {
+ #[cfg(target_arch = "arm")]
+ () => asm!("wfi" :::: "volatile"),
+ #[cfg(not(target_arch = "arm"))]
+ () => {}
+ }
+}
diff --git a/src/interrupt.rs b/src/interrupt.rs
new file mode 100644
index 0000000..6fb8aeb
--- /dev/null
+++ b/src/interrupt.rs
@@ -0,0 +1,47 @@
+//! Interrupts
+
+/// Disable interrupts, globally
+#[inline(always)]
+pub unsafe fn disable() {
+ match () {
+ #[cfg(target_arch = "arm")]
+ () => {
+ asm!("cpsid i" :::: "volatile");
+ }
+ #[cfg(not(target_arch = "arm"))]
+ () => {}
+ }
+}
+
+/// Enable interrupts, globally
+#[inline(always)]
+pub unsafe fn enable() {
+ match () {
+ #[cfg(target_arch = "arm")]
+ () => {
+ asm!("cpsie i" :::: "volatile");
+ }
+ #[cfg(not(target_arch = "arm"))]
+ () => {}
+ }
+}
+
+/// Execute closure `f` in an interrupt-free context.
+/// This as also known as a "critical section".
+pub unsafe fn free<F>(f: F)
+ where F: FnOnce()
+{
+ let primask = ::register::primask::read();
+
+ disable();
+
+ f();
+
+ // If the interrupts were enabled before our `disable` call, then re-enable them
+ // Otherwise, keep them disabled
+ // PRIMASK & 1 = 1 indicates that the interrupts were disabled
+ // PRIMASK & 1 = 0 indicates that they were enabled
+ if primask & 1 == 0 {
+ enable();
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..d8b7fa1
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,78 @@
+//! Low level access to Cortex-M processors
+//!
+//! This crate provides access to:
+//!
+//! - Core peripherals like NVIC, SCB and SysTick.
+//! - Core registers like CONTROL, MSP and PSR.
+//! - Interrupt manipulation mechanisms
+//! - Data structures like the vector table
+//! - Miscellaneous assembly instructions like `bkpt`
+//!
+
+#![deny(missing_docs)]
+#![deny(warnings)]
+#![feature(asm)]
+#![no_std]
+
+extern crate volatile_register;
+
+pub mod asm;
+pub mod interrupt;
+pub mod peripheral;
+pub mod register;
+
+/// Vector Table
+///
+/// # References
+///
+/// - ARMv7-M Architecture Reference Manual (issue E.b) - Section B1.5 - ARMv7-M exception model
+#[repr(C)]
+pub struct VectorTable {
+ /// Reset value of the Main Stack Pointer (MSP)
+ pub sp_main: &'static (),
+ /// Reset
+ pub reset: extern "C" fn() -> !,
+ /// Non Maskable Interrupt
+ pub nmi: Option<Handler>,
+ /// Hard Fault
+ pub hard_fault: Option<Handler>,
+ /// Memory Management
+ pub mem_manage: Option<Handler>,
+ /// Bus Fault
+ pub bus_fault: Option<Handler>,
+ /// Usage Fault
+ pub usage_fault: Option<Handler>,
+ reserved0: [u32; 4],
+ /// Supervisor Call
+ pub svcall: Option<Handler>,
+ /// Debug Monitor
+ pub debug_monitor: Option<Handler>,
+ reserved1: u32,
+ /// PendSV
+ pub pendsv: Option<Handler>,
+ /// SysTick
+ pub sys_tick: Option<Handler>,
+ /// Interrupts. An IMPLEMENTATION DEFINED number of them.
+ pub interrupts: [Option<Handler>; 0],
+}
+
+/// Returns the vector table
+pub fn vector_table() -> &'static VectorTable {
+ unsafe { deref(peripheral::scb().vtor.read() as usize) }
+}
+
+/// Exception/Interrupt Handler
+pub type Handler = unsafe extern "C" fn();
+
+#[cfg(test)]
+fn address<T>(r: &T) -> usize {
+ r as *const T as usize
+}
+
+unsafe fn deref<T>(a: usize) -> &'static T {
+ &*(a as *const T)
+}
+
+unsafe fn deref_mut<T>(a: usize) -> &'static mut T {
+ &mut *(a as *mut T)
+}
diff --git a/src/peripheral/cpuid.rs b/src/peripheral/cpuid.rs
new file mode 100644
index 0000000..0dc140f
--- /dev/null
+++ b/src/peripheral/cpuid.rs
@@ -0,0 +1,30 @@
+//! CPUID
+
+use volatile_register::RO;
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ /// CPUID base
+ pub base: RO<u32>,
+ reserved0: [u32; 15],
+ /// Processor Feature
+ pub pfr: [RO<u32>; 2],
+ /// Debug Feature
+ pub dfr: RO<u32>,
+ /// Auxiliary Feature
+ pub afr: RO<u32>,
+ /// Memory Model Feature
+ pub mmfr: [RO<u32>; 4],
+ /// Instruction Set Attribute
+ pub isar: [RO<u32>; 5],
+ reserved1: u32,
+ /// Cache Level ID
+ pub clidr: RO<u32>,
+ /// Cache Type
+ pub ctr: RO<u32>,
+ /// Cache Size ID
+ pub ccsidr: RO<u32>,
+ /// Cache Size Selection
+ pub csselr: RO<u32>,
+}
diff --git a/src/peripheral/dcb.rs b/src/peripheral/dcb.rs
new file mode 100644
index 0000000..93a056b
--- /dev/null
+++ b/src/peripheral/dcb.rs
@@ -0,0 +1,16 @@
+//! Debug Control Block
+
+use volatile_register::{RW, WO};
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ /// Debug Halting Control and Status
+ pub dhcsr: RW<u32>,
+ /// Debug Core Register Selector
+ pub dcrsr: WO<u32>,
+ /// Debug Core Register Data
+ pub dcrdr: RW<u32>,
+ /// Debug Exception and Monitor Control
+ pub demcr: RW<u32>,
+}
diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs
new file mode 100644
index 0000000..ecd214e
--- /dev/null
+++ b/src/peripheral/dwt.rs
@@ -0,0 +1,43 @@
+//! Data Watchpoint and Trace unit
+
+use volatile_register::{RO, RW, WO};
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ /// Control
+ pub ctrl: RW<u32>,
+ /// Cycle Count
+ pub cyccnt: RW<u32>,
+ /// CPI Count
+ pub cpicnt: RW<u32>,
+ /// Exception Overhead Count
+ pub exccnt: RW<u32>,
+ /// Sleep Count
+ pub sleepcnt: RW<u32>,
+ /// LSU Count
+ pub lsucnt: RW<u32>,
+ /// Folded-instruction Count
+ pub foldcnt: RW<u32>,
+ /// Program Counter Sample
+ pub pcsr: RO<u32>,
+ /// Comparators
+ pub c: [Comparator; 16],
+ reserved: [u32; 932],
+ /// Lock Access
+ pub lar: WO<u32>,
+ /// Lock Status
+ pub lsr: RO<u32>,
+}
+
+/// Comparator
+#[repr(C)]
+pub struct Comparator {
+ /// Comparator
+ pub comp: RW<u32>,
+ /// Comparator Mask
+ pub mask: RW<u32>,
+ /// Comparator Function
+ pub function: RW<u32>,
+ reserved: u32,
+}
diff --git a/src/peripheral/fpb.rs b/src/peripheral/fpb.rs
new file mode 100644
index 0000000..6aa6fbb
--- /dev/null
+++ b/src/peripheral/fpb.rs
@@ -0,0 +1,19 @@
+//! Flash Patch and Breakpoint unit
+
+use volatile_register::{RO, RW, WO};
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ /// Control
+ pub ctrl: RW<u32>,
+ /// Remap
+ pub remap: RW<u32>,
+ /// Comparator
+ pub comp: [RW<u32>; 127],
+ reserved: [u32; 875],
+ /// Lock Access
+ pub lar: WO<u32>,
+ /// Lock Status
+ pub lsr: RO<u32>,
+}
diff --git a/src/peripheral/fpu.rs b/src/peripheral/fpu.rs
new file mode 100644
index 0000000..5bbf352
--- /dev/null
+++ b/src/peripheral/fpu.rs
@@ -0,0 +1,17 @@
+//! Floating Point Unit
+
+use volatile_register::{RO, RW};
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ reserved: u32,
+ /// Floating Point Context Control
+ pub fpccr: RW<u32>,
+ /// Floating Point Context Address
+ pub fpcar: RW<u32>,
+ /// Floating Point Default Status Control
+ pub fpdscr: RW<u32>,
+ /// Media and FP Feature
+ pub mvfr: [RO<u32>; 3],
+}
diff --git a/src/peripheral/itm.rs b/src/peripheral/itm.rs
new file mode 100644
index 0000000..b56d1b5
--- /dev/null
+++ b/src/peripheral/itm.rs
@@ -0,0 +1,54 @@
+//! Instrumentation Trace Macrocell
+
+use volatile_register::{RO, RW, WO};
+
+use core::cell::UnsafeCell;
+use core::ptr;
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ /// Stimulus Port
+ pub stim: [Stim; 256],
+ reserved0: [u32; 640],
+ /// Trace Enable
+ pub ter: [RW<u32>; 8],
+ reserved1: [u32; 8],
+ /// Trace Privilege
+ pub tpr: RW<u32>,
+ reserved2: [u32; 15],
+ /// Trace Control
+ pub tcr: RW<u32>,
+ reserved3: [u32; 75],
+ /// Lock Access
+ pub lar: WO<u32>,
+ /// Lock Status
+ pub lsr: RO<u32>,
+}
+
+/// Stimulus Port
+pub struct Stim {
+ register: UnsafeCell<u32>,
+}
+
+impl Stim {
+ /// Writes an `u8` payload into the stimulus port
+ pub fn write_u8(&self, value: u8) {
+ unsafe { ptr::write_volatile(self.register.get() as *mut u8, value) }
+ }
+
+ /// Writes an `u16` payload into the stimulus port
+ pub fn write_u16(&self, value: u16) {
+ unsafe { ptr::write_volatile(self.register.get() as *mut u16, value) }
+ }
+
+ /// Writes an `u32` payload into the stimulus port
+ pub fn write_u32(&self, value: u32) {
+ unsafe { ptr::write_volatile(self.register.get(), value) }
+ }
+
+ /// Returns `true` if the stimulus port is ready to accept more data
+ pub fn is_fifo_ready(&self) -> bool {
+ unsafe { ptr::read_volatile(self.register.get()) == 1 }
+ }
+}
diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs
new file mode 100644
index 0000000..9f02aa3
--- /dev/null
+++ b/src/peripheral/mod.rs
@@ -0,0 +1,149 @@
+//! Core peripherals
+//!
+//! # Notes
+//!
+//! - Although the `*_mut()` functions always return a valid/live reference, the API doesn't prevent
+//! the user from creating multiple mutable aliases. It's up to the user to ensure that no
+//! unsynchonized concurrent access is performed through these references.
+//!
+//! # Caveats
+//!
+//! - The API doesn't check if the value passed to `write` is valid (e.g. reserved bits are not
+//! modified) or not. It's up to the user to verify that.
+//!
+//! # References
+//!
+//! - ARMv7-M Architecture Reference Manual (Issue E.b) - Chapter B3
+
+pub mod cpuid;
+pub mod dcb;
+pub mod dwt;
+pub mod fpb;
+pub mod fpu;
+pub mod itm;
+pub mod mpu;
+pub mod nvic;
+pub mod scb;
+pub mod syst;
+pub mod tpiu;
+
+mod test;
+
+const CPUID: usize = 0xE000_ED00;
+const DCB: usize = 0xE000_EDF0;
+const DWT: usize = 0xE000_1000;
+const FPB: usize = 0xE000_2000;
+const FPU: usize = 0xE000_EF30;
+const ITM: usize = 0xE000_0000;
+const MPU: usize = 0xE000_ED90;
+const NVIC: usize = 0xE000_E100;
+const SCB: usize = 0xE000_ED04;
+const SYST: usize = 0xE000_E010;
+const TPIU: usize = 0xE004_0000;
+
+// TODO stand-alone registers: ICTR, ACTLR and STIR
+
+/// `&cpuid::Registers`
+pub fn cpuid() -> &'static cpuid::Registers {
+ unsafe { ::deref(CPUID) }
+}
+
+/// `&dcb::Registers`
+pub fn dcb() -> &'static dcb::Registers {
+ unsafe { ::deref(DCB) }
+}
+
+/// `&mut dcb::Registers`
+pub unsafe fn dcb_mut() -> &'static mut dcb::Registers {
+ ::deref_mut(DCB)
+}
+
+/// `&dwt::Registers`
+pub fn dwt() -> &'static dwt::Registers {
+ unsafe { ::deref(DWT) }
+}
+
+/// `&mut dwt::Registers`
+pub unsafe fn dwt_mut() -> &'static mut dwt::Registers {
+ ::deref_mut(DWT)
+}
+
+/// `&fpb::Registers`
+pub fn fpb() -> &'static fpb::Registers {
+ unsafe { ::deref(FPB) }
+}
+
+/// `&mut fpb::Registers`
+pub unsafe fn fpb_mut() -> &'static mut fpb::Registers {
+ ::deref_mut(FPB)
+}
+
+/// `&fpu::Registers`
+pub fn fpu() -> &'static fpu::Registers {
+ unsafe { ::deref(FPU) }
+}
+
+/// `&mut fpu::Registers`
+pub unsafe fn fpu_mut() -> &'static mut fpu::Registers {
+ ::deref_mut(FPU)
+}
+
+/// `&itm::Registers`
+pub fn itm() -> &'static itm::Registers {
+ unsafe { ::deref(ITM) }
+}
+
+/// `&mut itm::Registers`
+pub unsafe fn itm_mut() -> &'static mut itm::Registers {
+ ::deref_mut(ITM)
+}
+
+/// `&mpu::Registers`
+pub fn mpu() -> &'static mpu::Registers {
+ unsafe { ::deref(MPU) }
+}
+
+/// `&mut mpu::Registers`
+pub unsafe fn mpu_mut() -> &'static mut mpu::Registers {
+ ::deref_mut(MPU)
+}
+
+/// `&nvic::Registers`
+pub fn nvic() -> &'static nvic::Registers {
+ unsafe { ::deref(NVIC) }
+}
+
+/// `&mut nvic::Registers`
+pub unsafe fn nvic_mut() -> &'static mut nvic::Registers {
+ ::deref_mut(NVIC)
+}
+
+/// `&scb::Registers`
+pub fn scb() -> &'static scb::Registers {
+ unsafe { ::deref(SCB) }
+}
+
+/// `&mut scb::Registers`
+pub unsafe fn scb_mut() -> &'static mut scb::Registers {
+ ::deref_mut(SCB)
+}
+
+/// `&syst::Registers`
+pub fn syst() -> &'static syst::Registers {
+ unsafe { ::deref(SYST) }
+}
+
+/// `&mut syst::Registers`
+pub unsafe fn syst_mut() -> &'static mut syst::Registers {
+ ::deref_mut(SYST)
+}
+
+/// `&tpiu::Registers`
+pub fn tpiu() -> &'static tpiu::Registers {
+ unsafe { ::deref(TPIU) }
+}
+
+/// `&mut tpiu::Registers`
+pub unsafe fn tpiu_mut() -> &'static mut tpiu::Registers {
+ ::deref_mut(TPIU)
+}
diff --git a/src/peripheral/mpu.rs b/src/peripheral/mpu.rs
new file mode 100644
index 0000000..e024e62
--- /dev/null
+++ b/src/peripheral/mpu.rs
@@ -0,0 +1,30 @@
+//! Memory Protection Unit
+
+use volatile_register::{RO, RW};
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ /// Type
+ pub _type: RO<u32>,
+ /// Control
+ pub ctrl: RW<u32>,
+ /// Region Number
+ pub rnr: RW<u32>,
+ /// Region Base Address
+ pub rbar: RW<u32>,
+ /// Region Attribute and Size
+ pub rasr: RW<u32>,
+ /// Alias 1 of RBAR
+ pub rbar_a1: RW<u32>,
+ /// Alias 1 of RSAR
+ pub rsar_a1: RW<u32>,
+ /// Alias 2 of RBAR
+ pub rbar_a2: RW<u32>,
+ /// Alias 2 of RSAR
+ pub rsar_a2: RW<u32>,
+ /// Alias 3 of RBAR
+ pub rbar_a3: RW<u32>,
+ /// Alias 3 of RSAR
+ pub rsar_a3: RW<u32>,
+}
diff --git a/src/peripheral/nvic.rs b/src/peripheral/nvic.rs
new file mode 100644
index 0000000..4570c0f
--- /dev/null
+++ b/src/peripheral/nvic.rs
@@ -0,0 +1,25 @@
+//! Nested Vector Interrupt Controller
+
+use volatile_register::{RO, RW};
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ /// Interrupt Set-Enable
+ pub iser: [RW<u32>; 16],
+ reserved0: [u32; 16],
+ /// Interrupt Clear-Enable
+ pub icer: [RW<u32>; 16],
+ reserved1: [u32; 16],
+ /// Interrupt Set-Pending
+ pub ispr: [RW<u32>; 16],
+ reserved2: [u32; 16],
+ /// Interrupt Clear-Pending
+ pub icpr: [RW<u32>; 16],
+ reserved3: [u32; 16],
+ /// Interrupt Active Bit
+ pub iabr: [RO<u32>; 16],
+ reserved4: [u32; 48],
+ /// Interrupt Priority
+ pub ipr: [RW<u32>; 124],
+}
diff --git a/src/peripheral/scb.rs b/src/peripheral/scb.rs
new file mode 100644
index 0000000..d2b204a
--- /dev/null
+++ b/src/peripheral/scb.rs
@@ -0,0 +1,37 @@
+//! System Control Block
+
+use volatile_register::RW;
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ /// Interrupt Control and State
+ pub icsr: RW<u32>,
+ /// Vector Table Offset
+ pub vtor: RW<u32>,
+ /// Application Interrupt and Reset Control
+ pub aircr: RW<u32>,
+ /// System Control
+ pub scr: RW<u32>,
+ /// Configuration and Control
+ pub ccr: RW<u32>,
+ /// System Handler Priority
+ pub shpr: [RW<u8>; 12],
+ /// System Handler Control and State
+ pub shpcrs: RW<u32>,
+ /// Configurable Fault Status
+ pub cfsr: RW<u32>,
+ /// HardFault Status
+ pub hfsr: RW<u32>,
+ /// Debug Fault Status
+ pub dfsr: RW<u32>,
+ /// MemManage Fault Address
+ pub mmar: RW<u32>,
+ /// BusFault Address
+ pub bfar: RW<u32>,
+ /// Auxiliary Fault Status
+ pub afsr: RW<u32>,
+ reserved: [u32; 18],
+ /// Coprocessor Access Control
+ pub cpacr: RW<u32>,
+}
diff --git a/src/peripheral/syst.rs b/src/peripheral/syst.rs
new file mode 100644
index 0000000..8ee70a1
--- /dev/null
+++ b/src/peripheral/syst.rs
@@ -0,0 +1,16 @@
+//! SysTick: System Timer
+
+use volatile_register::{RO, RW};
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ /// Control and Status
+ pub csr: RW<u32>,
+ /// Reload Value
+ pub rvr: RW<u32>,
+ /// Current Value
+ pub cvr: RW<u32>,
+ /// Calibration Value
+ pub calib: RO<u32>,
+}
diff --git a/src/peripheral/test.rs b/src/peripheral/test.rs
new file mode 100644
index 0000000..c291b16
--- /dev/null
+++ b/src/peripheral/test.rs
@@ -0,0 +1,162 @@
+#[test]
+fn cpuid() {
+ let cpuid = ::peripheral::cpuid();
+
+ assert_eq!(::address(&cpuid.base), 0xE000_ED00);
+ assert_eq!(::address(&cpuid.pfr), 0xE000_ED40);
+ assert_eq!(::address(&cpuid.dfr), 0xE000_ED48);
+ assert_eq!(::address(&cpuid.afr), 0xE000_ED4C);
+ assert_eq!(::address(&cpuid.mmfr), 0xE000_ED50);
+ assert_eq!(::address(&cpuid.isar), 0xE000_ED60);
+ assert_eq!(::address(&cpuid.clidr), 0xE000_ED78);
+ assert_eq!(::address(&cpuid.ctr), 0xE000_ED7C);
+ assert_eq!(::address(&cpuid.ccsidr), 0xE000_ED80);
+ assert_eq!(::address(&cpuid.csselr), 0xE000_ED84);
+}
+
+#[test]
+fn dcb() {
+ for dcb in &[::peripheral::dcb(), unsafe { ::peripheral::dcb_mut() }] {
+ assert_eq!(::address(&dcb.dhcsr), 0xE000_EDF0);
+ assert_eq!(::address(&dcb.dcrsr), 0xE000_EDF4);
+ assert_eq!(::address(&dcb.dcrdr), 0xE000_EDF8);
+ assert_eq!(::address(&dcb.demcr), 0xE000_EDFC);
+ }
+}
+
+#[test]
+fn dwt() {
+ for dwt in &[::peripheral::dwt(), unsafe { ::peripheral::dwt_mut() }] {
+ assert_eq!(::address(&dwt.ctrl), 0xE000_1000);
+ assert_eq!(::address(&dwt.cyccnt), 0xE000_1004);
+ assert_eq!(::address(&dwt.cpicnt), 0xE000_1008);
+ assert_eq!(::address(&dwt.exccnt), 0xE000_100C);
+ assert_eq!(::address(&dwt.sleepcnt), 0xE000_1010);
+ assert_eq!(::address(&dwt.lsucnt), 0xE000_1014);
+ assert_eq!(::address(&dwt.foldcnt), 0xE000_1018);
+ assert_eq!(::address(&dwt.pcsr), 0xE000_101C);
+ assert_eq!(::address(&dwt.c[0].comp), 0xE000_1020);
+ assert_eq!(::address(&dwt.c[0].mask), 0xE000_1024);
+ assert_eq!(::address(&dwt.c[0].function), 0xE000_1028);
+ assert_eq!(::address(&dwt.c[1].comp), 0xE000_1030);
+ assert_eq!(::address(&dwt.c[1].mask), 0xE000_1034);
+ assert_eq!(::address(&dwt.c[1].function), 0xE000_1038);
+ assert_eq!(::address(&dwt.lar), 0xE000_1FB0);
+ assert_eq!(::address(&dwt.lsr), 0xE000_1FB4);
+ }
+}
+
+#[test]
+fn fpb() {
+ for fpb in &[::peripheral::fpb(), unsafe { ::peripheral::fpb_mut() }] {
+ assert_eq!(::address(&fpb.ctrl), 0xE000_2000);
+ assert_eq!(::address(&fpb.remap), 0xE000_2004);
+ assert_eq!(::address(&fpb.comp), 0xE000_2008);
+ assert_eq!(::address(&fpb.comp[1]), 0xE000_200C);
+ assert_eq!(::address(&fpb.lar), 0xE000_2FB0);
+ assert_eq!(::address(&fpb.lsr), 0xE000_2FB4);
+ }
+}
+
+#[test]
+fn fpu() {
+ for fpu in &[::peripheral::fpu(), unsafe { ::peripheral::fpu_mut() }] {
+ assert_eq!(::address(&fpu.fpccr), 0xE000_EF34);
+ assert_eq!(::address(&fpu.fpcar), 0xE000_EF38);
+ assert_eq!(::address(&fpu.fpdscr), 0xE000_EF3C);
+ assert_eq!(::address(&fpu.mvfr), 0xE000_EF40);
+ assert_eq!(::address(&fpu.mvfr[1]), 0xE000_EF44);
+ assert_eq!(::address(&fpu.mvfr[2]), 0xE000_EF48);
+ }
+}
+
+#[test]
+fn itm() {
+ for itm in &[::peripheral::itm(), unsafe { ::peripheral::itm_mut() }] {
+ assert_eq!(::address(&itm.stim), 0xE000_0000);
+ assert_eq!(::address(&itm.ter), 0xE000_0E00);
+ assert_eq!(::address(&itm.tpr), 0xE000_0E40);
+ assert_eq!(::address(&itm.tcr), 0xE000_0E80);
+ assert_eq!(::address(&itm.lar), 0xE000_0FB0);
+ assert_eq!(::address(&itm.lsr), 0xE000_0FB4);
+ }
+}
+
+#[test]
+fn mpu() {
+ for mpu in &[::peripheral::mpu(), unsafe { ::peripheral::mpu_mut() }] {
+ assert_eq!(::address(&mpu._type), 0xE000ED90);
+ assert_eq!(::address(&mpu.ctrl), 0xE000ED94);
+ assert_eq!(::address(&mpu.rnr), 0xE000ED98);
+ assert_eq!(::address(&mpu.rbar), 0xE000ED9C);
+ assert_eq!(::address(&mpu.rasr), 0xE000EDA0);
+ assert_eq!(::address(&mpu.rbar_a1), 0xE000EDA4);
+ assert_eq!(::address(&mpu.rsar_a1), 0xE000EDA8);
+ assert_eq!(::address(&mpu.rbar_a2), 0xE000EDAC);
+ assert_eq!(::address(&mpu.rsar_a2), 0xE000EDB0);
+ assert_eq!(::address(&mpu.rbar_a3), 0xE000EDB4);
+ assert_eq!(::address(&mpu.rsar_a3), 0xE000EDB8);
+ }
+}
+
+#[test]
+fn nvic() {
+ for nvic in &[::peripheral::nvic(), unsafe { ::peripheral::nvic_mut() }] {
+ assert_eq!(::address(&nvic.iser), 0xE000E100);
+ assert_eq!(::address(&nvic.iser[15]), 0xE000E13C);
+ assert_eq!(::address(&nvic.icer), 0xE000E180);
+ assert_eq!(::address(&nvic.icer[7]), 0xE000E19C);
+ assert_eq!(::address(&nvic.icer[15]), 0xE000E1BC);
+ assert_eq!(::address(&nvic.ispr), 0xE000E200);
+ assert_eq!(::address(&nvic.ispr[15]), 0xE000E23C);
+ assert_eq!(::address(&nvic.icpr), 0xE000E280);
+ assert_eq!(::address(&nvic.icpr[15]), 0xE000E2BC);
+ assert_eq!(::address(&nvic.iabr), 0xE000E300);
+ assert_eq!(::address(&nvic.iabr[15]), 0xE000E33C);
+ assert_eq!(::address(&nvic.ipr), 0xE000E400);
+ assert_eq!(::address(&nvic.ipr[59]), 0xE000E4EC);
+ }
+}
+
+#[test]
+fn scb() {
+ for scb in &[::peripheral::scb(), unsafe { ::peripheral::scb_mut() }] {
+ assert_eq!(::address(&scb.icsr), 0xE000_ED04);
+ assert_eq!(::address(&scb.vtor), 0xE000_ED08);
+ assert_eq!(::address(&scb.aircr), 0xE000_ED0C);
+ assert_eq!(::address(&scb.scr), 0xE000_ED10);
+ assert_eq!(::address(&scb.ccr), 0xE000_ED14);
+ assert_eq!(::address(&scb.shpr), 0xE000_ED18);
+ assert_eq!(::address(&scb.shpcrs), 0xE000_ED24);
+ assert_eq!(::address(&scb.cfsr), 0xE000_ED28);
+ assert_eq!(::address(&scb.hfsr), 0xE000_ED2C);
+ assert_eq!(::address(&scb.dfsr), 0xE000_ED30);
+ assert_eq!(::address(&scb.mmar), 0xE000_ED34);
+ assert_eq!(::address(&scb.bfar), 0xE000_ED38);
+ assert_eq!(::address(&scb.afsr), 0xE000_ED3C);
+ assert_eq!(::address(&scb.cpacr), 0xE000_ED88);
+ }
+}
+
+#[test]
+fn syst() {
+ for syst in &[::peripheral::syst(), unsafe { ::peripheral::syst_mut() }] {
+ assert_eq!(::address(&syst.csr), 0xE000_E010);
+ assert_eq!(::address(&syst.rvr), 0xE000_E014);
+ assert_eq!(::address(&syst.cvr), 0xE000_E018);
+ assert_eq!(::address(&syst.calib), 0xE000_E01C);
+ }
+}
+
+#[test]
+fn tpiu() {
+ for tpiu in &[::peripheral::tpiu(), unsafe { ::peripheral::tpiu_mut() }] {
+ assert_eq!(::address(&tpiu.sspsr), 0xE004_0000);
+ assert_eq!(::address(&tpiu.cspsr), 0xE004_0004);
+ assert_eq!(::address(&tpiu.acpr), 0xE004_0010);
+ assert_eq!(::address(&tpiu.sppr), 0xE004_00F0);
+ assert_eq!(::address(&tpiu.lar), 0xE004_0FB0);
+ assert_eq!(::address(&tpiu.lsr), 0xE004_0FB4);
+ assert_eq!(::address(&tpiu._type), 0xE004_0FC8);
+ }
+}
diff --git a/src/peripheral/tpiu.rs b/src/peripheral/tpiu.rs
new file mode 100644
index 0000000..5047351
--- /dev/null
+++ b/src/peripheral/tpiu.rs
@@ -0,0 +1,26 @@
+//! Trace Port Interface Unit
+
+use volatile_register::{RO, RW, WO};
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ /// Supported Parallel Port Sizes
+ pub sspsr: RO<u32>,
+ /// Current Parallel Port Size
+ pub cspsr: RW<u32>,
+ reserved0: [u32; 2],
+ /// Asynchronous Clock Prescaler
+ pub acpr: RW<u32>,
+ reserved1: [u32; 55],
+ /// Selected Pin Control
+ pub sppr: RW<u32>,
+ reserved2: [u32; 943],
+ /// Lock Access
+ pub lar: WO<u32>,
+ /// Lock Status
+ pub lsr: RO<u32>,
+ reserved3: [u32; 4],
+ /// TPIU Type
+ pub _type: RO<u32>,
+}
diff --git a/src/register.rs b/src/register.rs
new file mode 100644
index 0000000..66add6b
--- /dev/null
+++ b/src/register.rs
@@ -0,0 +1,126 @@
+//! Processor core registers
+//!
+//! The following registers can only be accessed in PRIVILEGED mode:
+//!
+//! - MSP
+//! - IPSR
+//! - EPSR
+//! - PRIMASK
+//! - FAULTMASK
+//! - BASEPRI
+//! - CONTROL
+//!
+//! The rest of registers (see list below) can be accessed in either, PRIVILEGED or UNPRIVILEGED,
+//! mode.
+//!
+//! - PSP
+//! - LR
+//! - PC
+//! - APSR
+//!
+//! # Caveats
+//!
+//! - The API doesn't check if the value passed to `write` is valid (e.g. reserved bits are not
+//! modified) or not. It's up to the user to verify that.
+//!
+//! # References
+//!
+//! - Cortex-M* Devices Generic User Guide - Section 2.1.3 Core registers
+
+// NOTE all the functions here are `always(inline)` to prevent a function call which may change the
+// contents of the core registers.
+
+macro_rules! sr {
+ ($name:ident) => {
+ /// Reads the special register
+ #[inline(always)]
+ pub unsafe fn read() -> u32 {
+ let r: u32;
+ match () {
+ #[cfg(target_arch = "arm")]
+ () => asm!(concat!("msr ", stringify!($name), ",$0") : "=r"(r) ::: "volatile"),
+
+ #[cfg(not(target_arch = "arm"))]
+ () => r = 0,
+ }
+ r
+ }
+ };
+}
+
+macro_rules! srw {
+ (#[$attr:meta] $name:ident) => {
+ #[$attr]
+ pub mod $name {
+ sr!($name);
+
+ /// Writes to the special register
+ #[inline(always)]
+ pub unsafe fn write(r: u32) {
+ match r {
+ #[cfg(target_arch = "arm")]
+ _ => asm!(concat!("mrs ", "$0,", stringify!($name)) :: "r"(r) ::: "volatile"),
+
+ #[cfg(not(target_arch = "arm"))]
+ _ => {},
+ }
+ }
+ }
+ };
+}
+
+macro_rules! sro {
+ (#[$attr:meta] $name:ident) => {
+ #[$attr]
+ pub mod $name {
+ #![doc = "yay"]
+
+ sr!($name);
+ }
+ }
+}
+
+macro_rules! rw {
+ (#[$attr:meta] $name:ident : $r:ident) => {
+ #[$attr]
+ pub mod $name {
+ /// Reads the special register
+ #[inline(always)]
+ pub unsafe fn read() -> u32 {
+ let r: u32;
+ match () {
+ #[cfg(target_arch = "arm")]
+ () => asm!(concat!("mov ", stringify!($r), ",$0") : "=r"(r) ::: "volatile"),
+
+ #[cfg(not(target_arch = "arm"))]
+ () => r = 0,
+ }
+ r
+ }
+
+ /// Writes to the special register
+ #[inline(always)]
+ pub unsafe fn write(r: u32) {
+ match r {
+ #[cfg(target_arch = "arm")]
+ _ => asm!(concat!("mov ", "$0,", stringify!($r)) :: "r"(r) ::: "volatile"),
+
+ #[cfg(not(target_arch = "arm"))]
+ _ => {}
+ }
+ }
+ }
+ }
+}
+
+srw!(#[doc = "Main Stack Pointer"] msp);
+srw!(#[doc = "Process Stack Pointer"] psp);
+rw!(#[doc = "Link Register"] lr: r15);
+rw!(#[doc = "Program Counter"] pc: r14);
+srw!(#[doc = "Application Program Status Register"] apsr);
+sro!(#[doc = "Interrupt Program Status Register"] ipsr);
+sro!(#[doc = "Exception Program Status Register"] epsr);
+srw!(#[doc = "Priority Mask Register"] primask);
+srw!(#[doc = "Fault Mask Register"] faultmask);
+srw!(#[doc = "Base Priority Mask Register"] basepri);
+srw!(#[doc = "Control Register"] control);