aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jorge Aparicio <japaricious@gmail.com> 2017-03-07 22:56:06 -0500
committerGravatar Jorge Aparicio <japaricious@gmail.com> 2017-03-07 22:58:33 -0500
commitc3a35c1b6cea81aa71e8832bca79ccafa492be02 (patch)
treee868906d20c906d238be96cd5c07b07342f7a111
parent9d3f3f323f3b7543d0b49e773aea2c68e535ec83 (diff)
downloadcortex-m-c3a35c1b6cea81aa71e8832bca79ccafa492be02.tar.gz
cortex-m-c3a35c1b6cea81aa71e8832bca79ccafa492be02.tar.zst
cortex-m-c3a35c1b6cea81aa71e8832bca79ccafa492be02.zip
revamp for memory safety
-rw-r--r--CHANGELOG.md49
-rw-r--r--Cargo.toml4
-rw-r--r--src/ctxt.rs34
-rw-r--r--src/exception.rs93
-rw-r--r--src/interrupt.rs9
-rw-r--r--src/lib.rs86
-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.rs494
-rw-r--r--src/peripheral/mpu.rs30
-rw-r--r--src/peripheral/nvic.rs119
-rw-r--r--src/peripheral/scb.rs37
-rw-r--r--src/peripheral/syst.rs16
-rw-r--r--src/peripheral/test.rs243
-rw-r--r--src/peripheral/tpiu.rs26
19 files changed, 686 insertions, 733 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ea5af0c..95f28c7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,41 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
+### Added
+
+- Semihosting functionality is now exposed via the "semihosting" Cargo feature.
+
+- `exception::Handlers` struct that represent the section of the vector table
+ that contains the exception handlers.
+
+- A default exception handler
+
+- A high level API for the NVIC peripheral.
+
+- Execution context primitives: execution context `Local` data and `Token`s to
+ identify execution contexts.
+
+### Changed
+
+- [breaking-change] `StackFrame` has been renamed to `StackedRegisters` and
+ moved into the `exceptions` module.
+
+- [breaking-change] Core peripherals can now be modified via a `&-` reference
+ and are no longer `Sync`.
+
+- [breaking-change] `interrupt::free`'s closure now includes a critical section
+ token, `CsCtxt`.
+
+- [breaking-change] the core register API has been revamped for type safety.
+
+- The safety of assembly wrappers like `wfi` and `interrupt::free` has been
+ reviewed. In many cases, the functions are no longer unsafe.
+
+### Removed
+
+- `vector_table` and its associated `struct`, `VectorTable`. It's not a good
+ idea to give people a simple way to call the exception handlers.
+
## [v0.1.6] - 2017-01-22
### Added
@@ -60,10 +95,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Functions to get the vector table
- Wrappers over miscellaneous instructions like `bkpt`
-[Unreleased]: https://github.com/japaric/rustc-cfg/compare/v0.1.6...HEAD
-[v0.1.6]: https://github.com/japaric/rustc-cfg/compare/v0.1.5...v0.1.6
-[v0.1.5]: https://github.com/japaric/rustc-cfg/compare/v0.1.4...v0.1.5
-[v0.1.4]: https://github.com/japaric/rustc-cfg/compare/v0.1.3...v0.1.4
-[v0.1.3]: https://github.com/japaric/rustc-cfg/compare/v0.1.2...v0.1.3
-[v0.1.2]: https://github.com/japaric/rustc-cfg/compare/v0.1.1...v0.1.2
-[v0.1.1]: https://github.com/japaric/rustc-cfg/compare/v0.1.0...v0.1.1
+[Unreleased]: https://github.com/japaric/cortex-m/compare/v0.1.6...HEAD
+[v0.1.6]: https://github.com/japaric/cortex-m/compare/v0.1.5...v0.1.6
+[v0.1.5]: https://github.com/japaric/cortex-m/compare/v0.1.4...v0.1.5
+[v0.1.4]: https://github.com/japaric/cortex-m/compare/v0.1.3...v0.1.4
+[v0.1.3]: https://github.com/japaric/cortex-m/compare/v0.1.2...v0.1.3
+[v0.1.2]: https://github.com/japaric/cortex-m/compare/v0.1.1...v0.1.2
+[v0.1.1]: https://github.com/japaric/cortex-m/compare/v0.1.0...v0.1.1
diff --git a/Cargo.toml b/Cargo.toml
index e070549..4f29858 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,10 +6,10 @@ keywords = ["arm", "cortex-m", "register", "peripheral"]
license = "MIT OR Apache-2.0"
name = "cortex-m"
repository = "https://github.com/japaric/cortex-m"
-version = "0.1.6"
+version = "0.2.0"
[dependencies]
-volatile-register = "0.1.0"
+volatile-register = "0.2.0"
[dependencies.cortex-m-semihosting]
optional = true
diff --git a/src/ctxt.rs b/src/ctxt.rs
new file mode 100644
index 0000000..7cd8a74
--- /dev/null
+++ b/src/ctxt.rs
@@ -0,0 +1,34 @@
+//! Execution context
+
+use core::marker::PhantomData;
+use core::cell::UnsafeCell;
+
+/// Data local to an execution context
+pub struct Local<T, Ctxt>
+ where Ctxt: Token
+{
+ _ctxt: PhantomData<Ctxt>,
+ data: UnsafeCell<T>,
+}
+
+impl<T, Ctxt> Local<T, Ctxt>
+ where Ctxt: Token
+{
+ /// Initializes the local data
+ pub const fn new(value: T) -> Self {
+ Local {
+ _ctxt: PhantomData,
+ data: UnsafeCell::new(value),
+ }
+ }
+
+ /// Acquires a reference to the local data
+ pub fn borrow<'a>(&'static self, _ctxt: &'a Ctxt) -> &'a T {
+ unsafe { &*self.data.get() }
+ }
+}
+
+unsafe impl<T, Ctxt> Sync for Local<T, Ctxt> where Ctxt: Token {}
+
+/// A unique token that identifies an execution context
+pub unsafe trait Token {}
diff --git a/src/exception.rs b/src/exception.rs
index cd38366..b944d6c 100644
--- a/src/exception.rs
+++ b/src/exception.rs
@@ -1,8 +1,7 @@
//! Exceptions
-use {Handler, Reserved};
-#[cfg(target_arch = "arm")]
-use StackFrame;
+use ctxt::Token;
+use Reserved;
/// Kind of exception
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
@@ -35,7 +34,7 @@ pub enum Exception {
impl Exception {
/// Returns the kind of exception that's currently being serviced
pub fn current() -> Exception {
- match ::peripheral::scb().icsr.read() as u8 {
+ match unsafe { (*::peripheral::SCB.get()).icsr.read() } as u8 {
0 => Exception::ThreadMode,
2 => Exception::Nmi,
3 => Exception::HardFault,
@@ -55,27 +54,65 @@ impl Exception {
#[repr(C)]
pub struct Handlers {
/// Non-maskable interrupt
- pub nmi: Handler,
+ pub nmi: unsafe extern "C" fn(&NmiCtxt),
/// All class of fault
- pub hard_fault: Handler,
+ pub hard_fault: unsafe extern "C" fn(&HardFaultCtxt),
/// Memory management
- pub mem_manage: Handler,
+ pub mem_manage: unsafe extern "C" fn(&MemManageCtxt),
/// Pre-fetch fault, memory access fault
- pub bus_fault: Handler,
+ pub bus_fault: unsafe extern "C" fn(&BusFaultCtxt),
/// Undefined instruction or illegal state
- pub usage_fault: Handler,
+ pub usage_fault: unsafe extern "C" fn(&UsageFaultCtxt),
/// Reserved spots in the vector table
pub _reserved0: [Reserved; 4],
/// System service call via SWI instruction
- pub svcall: Handler,
+ pub svcall: unsafe extern "C" fn(&SvcallCtxt),
/// Reserved spots in the vector table
pub _reserved1: [Reserved; 2],
/// Pendable request for system service
- pub pendsv: Handler,
+ pub pendsv: unsafe extern "C" fn(&PendsvCtxt),
/// System tick timer
- pub sys_tick: Handler,
+ pub sys_tick: unsafe extern "C" fn (&SysTickCtxt),
}
+/// Identifies the Nmi exception
+pub struct NmiCtxt { _0: () }
+
+/// Identifies the HardFault exception
+pub struct HardFaultCtxt { _0: () }
+
+/// Identifies the MemManage exception
+pub struct MemManageCtxt { _0: () }
+
+/// Identifies the BusFault exception
+pub struct BusFaultCtxt { _0: () }
+
+/// Identifies the UsageFault exception
+pub struct UsageFaultCtxt { _0: () }
+
+/// Identifies the Svcall exception
+pub struct SvcallCtxt { _0: () }
+
+/// Identifies the Pendsv exception
+pub struct PendsvCtxt { _0: () }
+
+/// Identifies the Systick exception
+pub struct SysTickCtxt { _0: () }
+
+unsafe impl Token for NmiCtxt {}
+
+unsafe impl Token for HardFaultCtxt {}
+
+unsafe impl Token for MemManageCtxt {}
+
+unsafe impl Token for BusFaultCtxt {}
+
+unsafe impl Token for SvcallCtxt {}
+
+unsafe impl Token for PendsvCtxt {}
+
+unsafe impl Token for SysTickCtxt {}
+
/// Default exception handlers
pub const DEFAULT_HANDLERS: Handlers = Handlers {
_reserved0: [Reserved::Vector; 4],
@@ -95,15 +132,16 @@ pub const DEFAULT_HANDLERS: Handlers = Handlers {
/// This handler triggers a breakpoint (`bkpt`) and gives you access, within a
/// GDB session, to the stack frame (`_sf`) where the exception occurred.
// This needs asm!, #[naked] and unreachable() to avoid modifying the stack
-// pointer (MSP), that way it points to the previous stack frame
+// pointer (MSP), that way it points to the stacked registers
#[naked]
-pub unsafe extern "C" fn default_handler() {
+pub unsafe extern "C" fn default_handler<T>(_token: &T)
+{
// This is the actual exception handler. `_sf` is a pointer to the previous
// stack frame
#[cfg(target_arch = "arm")]
- extern "C" fn handler(_sf: &StackFrame) -> ! {
+ extern "C" fn handler(_sr: &StackedRegisters) -> ! {
#[cfg(feature = "semihosting")]
- hprintln!("EXCEPTION {:?} @ PC=0x{:08x}", Exception::current(), _sf.pc);
+ hprintln!("EXCEPTION {:?} @ PC=0x{:08x}", Exception::current(), _sr.pc);
unsafe {
bkpt!();
@@ -120,7 +158,7 @@ pub unsafe extern "C" fn default_handler() {
ldr r1, [r0, #20]
b $0"
:
- : "i"(handler as extern "C" fn(&StackFrame) -> !)
+ : "i"(handler as extern "C" fn(&StackedRegisters) -> !)
:
: "volatile");
@@ -130,3 +168,24 @@ pub unsafe extern "C" fn default_handler() {
() => {}
}
}
+
+/// Registers stacked during an exception
+#[repr(C)]
+pub struct StackedRegisters {
+ /// (General purpose) Register 0
+ pub r0: u32,
+ /// (General purpose) Register 1
+ pub r1: u32,
+ /// (General purpose) Register 2
+ pub r2: u32,
+ /// (General purpose) Register 3
+ pub r3: u32,
+ /// (General purpose) Register 12
+ pub r12: u32,
+ /// Linker Register
+ pub lr: u32,
+ /// Program Counter
+ pub pc: u32,
+ /// Program Status Register
+ pub xpsr: u32,
+}
diff --git a/src/interrupt.rs b/src/interrupt.rs
index 2552892..95829ca 100644
--- a/src/interrupt.rs
+++ b/src/interrupt.rs
@@ -72,21 +72,22 @@ pub fn enable() {
/// Critical section token
///
/// Indicates that you are executing code within a critical section
-pub struct CsToken {
- _private: (),
+pub struct CsCtxt {
+ _0: (),
}
/// Execute closure `f` in an interrupt-free context.
+///
/// This as also known as a "critical section".
pub fn free<F, R>(f: F) -> R
- where F: FnOnce(&CsToken) -> R
+ where F: FnOnce(&CsCtxt) -> R
{
let primask = ::register::primask::read();
// disable interrupts
disable();
- let r = f(&CsToken { _private: () });
+ let r = f(&CsCtxt { _0: () });
// If the interrupts were active before our `disable` call, then re-enable
// them. Otherwise, keep them disabled
diff --git a/src/lib.rs b/src/lib.rs
index 322d20c..59428ba 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,12 +1,12 @@
//! Low level access to Cortex-M processors
//!
-//! This crate provides access to:
+//! This crate provides:
//!
-//! - Core peripherals like NVIC, SCB and SysTick.
-//! - Core registers like CONTROL, MSP and PSR.
+//! - Access to core peripherals like NVIC, SCB and SysTick.
+//! - Access to core registers like CONTROL, MSP and PSR.
//! - Interrupt manipulation mechanisms
//! - Data structures like the vector table
-//! - Miscellaneous assembly instructions like `bkpt`
+//! - Safe wrappers around assembly instructions like `bkpt`
#![cfg_attr(feature = "semihosting", feature(macro_reexport))]
#![cfg_attr(target_arch = "arm", feature(core_intrinsics))]
@@ -26,67 +26,12 @@ mod macros;
#[macro_use]
pub mod asm;
+pub mod ctxt;
pub mod exception;
pub mod interrupt;
pub mod peripheral;
pub mod register;
-/// Stack frame
-#[repr(C)]
-pub struct StackFrame {
- /// (General purpose) Register 0
- pub r0: u32,
- /// (General purpose) Register 1
- pub r1: u32,
- /// (General purpose) Register 2
- pub r2: u32,
- /// (General purpose) Register 3
- pub r3: u32,
- /// (General purpose) Register 12
- pub r12: u32,
- /// Linker Register
- pub lr: u32,
- /// Program Counter
- pub pc: u32,
- /// Program Status Register
- pub xpsr: u32,
-}
-
-/// 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],
-}
-
/// A reserved spot in the vector table
#[derive(Clone, Copy)]
#[repr(u32)]
@@ -94,24 +39,3 @@ pub enum Reserved {
/// Reserved
Vector = 0,
}
-
-/// Exception/Interrupt Handler
-pub type Handler = unsafe extern "C" fn();
-
-/// Returns the vector table
-pub fn vector_table() -> &'static VectorTable {
- unsafe { deref(peripheral::scb().vtor.read() as usize) }
-}
-
-#[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
deleted file mode 100644
index 0dc140f..0000000
--- a/src/peripheral/cpuid.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-//! 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
deleted file mode 100644
index 93a056b..0000000
--- a/src/peripheral/dcb.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-//! 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
deleted file mode 100644
index ecd214e..0000000
--- a/src/peripheral/dwt.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-//! 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
deleted file mode 100644
index 6aa6fbb..0000000
--- a/src/peripheral/fpb.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-//! 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
deleted file mode 100644
index 5bbf352..0000000
--- a/src/peripheral/fpu.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-//! 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
deleted file mode 100644
index b56d1b5..0000000
--- a/src/peripheral/itm.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-//! 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
index c0cb299..c6e8faa 100644
--- a/src/peripheral/mod.rs
+++ b/src/peripheral/mod.rs
@@ -1,144 +1,446 @@
//! 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;
+use core::cell::UnsafeCell;
+use core::marker::PhantomData;
+use core::ptr;
+
+use volatile_register::{RO, RW, WO};
+use interrupt::Nr;
+
+#[cfg(test)]
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;
+/// CPUID
+pub const CPUID: Peripheral<Cpuid> = unsafe { Peripheral::new(0xE000_ED00) };
+
+/// Debug Control Block
+pub const DCB: Peripheral<Dcb> = unsafe { Peripheral::new(0xE000_EDF0) };
+
+/// Data Watchpoint and Trace unit
+pub const DWT: Peripheral<Dwt> = unsafe { Peripheral::new(0xE000_1000) };
+
+/// Flash Patch and Breakpoint unit
+pub const FPB: Peripheral<Fpb> = unsafe { Peripheral::new(0xE000_2000) };
+
+/// Floating Point Unit
+pub const FPU: Peripheral<Fpu> = unsafe { Peripheral::new(0xE000_EF30) };
+
+/// Instrumentation Trace Macrocell
+pub const ITM: Peripheral<Itm> = unsafe { Peripheral::new(0xE000_0000) };
+
+/// Memory Protection Unit
+pub const MPU: Peripheral<Mpu> = unsafe { Peripheral::new(0xE000_ED90) };
+
+/// Nested Vector Interrupt Controller
+pub const NVIC: Peripheral<Nvic> = unsafe { Peripheral::new(0xE000_E100) };
+
+/// System Control Block
+pub const SCB: Peripheral<Scb> = unsafe { Peripheral::new(0xE000_ED04) };
+
+/// SysTick: System Timer
+pub const SYST: Peripheral<Syst> = unsafe { Peripheral::new(0xE000_E010) };
+
+/// Trace Port Interface Unit;
+pub const TPIU: Peripheral<Tpiu> = unsafe { Peripheral::new(0xE004_0000) };
// TODO stand-alone registers: ICTR, ACTLR and STIR
-/// `&cpuid::Registers`
-pub fn cpuid() -> &'static cpuid::Registers {
- unsafe { ::deref(CPUID) }
+/// A peripheral
+pub struct Peripheral<T>
+ where T: 'static
+{
+ address: usize,
+ _marker: PhantomData<&'static mut T>,
}
-/// `&dcb::Registers`
-pub fn dcb() -> &'static dcb::Registers {
- unsafe { ::deref(DCB) }
-}
+impl<T> Peripheral<T> {
+ /// Creates a new peripheral
+ ///
+ /// `address` is the base address of the register block
+ pub const unsafe fn new(address: usize) -> Self {
+ Peripheral {
+ address: address,
+ _marker: PhantomData,
+ }
+ }
-/// `&mut dcb::Registers`
-pub unsafe fn dcb_mut() -> &'static mut dcb::Registers {
- ::deref_mut(DCB)
+ /// Returns a pointer to the register block
+ pub fn get(&self) -> *mut T {
+ self.address as *mut T
+ }
}
-/// `&dwt::Registers`
-pub fn dwt() -> &'static dwt::Registers {
- unsafe { ::deref(DWT) }
+/// CPUID register block
+#[repr(C)]
+pub struct Cpuid {
+ /// 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>,
}
-/// `&mut dwt::Registers`
-pub unsafe fn dwt_mut() -> &'static mut dwt::Registers {
- ::deref_mut(DWT)
+/// DCB register block
+#[repr(C)]
+pub struct Dcb {
+ /// 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>,
}
-/// `&fpb::Registers`
-pub fn fpb() -> &'static fpb::Registers {
- unsafe { ::deref(FPB) }
+/// DWT register block
+#[repr(C)]
+pub struct Dwt {
+ /// 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>,
}
-/// `&mut fpb::Registers`
-pub unsafe fn fpb_mut() -> &'static mut fpb::Registers {
- ::deref_mut(FPB)
+/// 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,
}
-/// `&fpu::Registers`
-pub fn fpu() -> &'static fpu::Registers {
- unsafe { ::deref(FPU) }
+/// FPB register block
+#[repr(C)]
+pub struct Fpb {
+ /// 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>,
}
-/// `&mut fpu::Registers`
-pub unsafe fn fpu_mut() -> &'static mut fpu::Registers {
- ::deref_mut(FPU)
+/// FPU register block
+#[repr(C)]
+pub struct Fpu {
+ 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],
}
-/// `&itm::Registers`
-pub fn itm() -> &'static itm::Registers {
- unsafe { ::deref(ITM) }
+/// ITM register block
+#[repr(C)]
+pub struct Itm {
+ /// 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>,
}
-/// `&mut itm::Registers`
-pub unsafe fn itm_mut() -> &'static mut itm::Registers {
- ::deref_mut(ITM)
+/// Stimulus Port
+pub struct Stim {
+ register: UnsafeCell<u32>,
}
-/// `&mpu::Registers`
-pub fn mpu() -> &'static mpu::Registers {
- unsafe { ::deref(MPU) }
-}
+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) }
+ }
-/// `&mut mpu::Registers`
-pub unsafe fn mpu_mut() -> &'static mut mpu::Registers {
- ::deref_mut(MPU)
-}
+ /// 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) }
+ }
-/// `&mut nvic::Registers`
-pub fn nvic() -> &'static mut nvic::Registers {
- unsafe { ::deref_mut(NVIC) }
+ /// 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 }
+ }
}
-/// `&scb::Registers`
-pub fn scb() -> &'static scb::Registers {
- unsafe { ::deref(SCB) }
+/// MPU register block
+#[repr(C)]
+pub struct Mpu {
+ /// 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>,
}
-/// `&mut scb::Registers`
-pub unsafe fn scb_mut() -> &'static mut scb::Registers {
- ::deref_mut(SCB)
+/// NVIC register block
+#[repr(C)]
+pub struct Nvic {
+ /// Interrupt Set-Enable
+ pub iser: [RW<u32>; 8],
+ reserved0: [u32; 24],
+ /// Interrupt Clear-Enable
+ pub icer: [RW<u32>; 8],
+ reserved1: [u32; 24],
+ /// Interrupt Set-Pending
+ pub ispr: [RW<u32>; 8],
+ reserved2: [u32; 24],
+ /// Interrupt Clear-Pending
+ pub icpr: [RW<u32>; 8],
+ reserved3: [u32; 24],
+ /// Interrupt Active Bit
+ pub iabr: [RO<u32>; 8],
+ reserved4: [u32; 56],
+ /// Interrupt Priority
+ pub ipr: [RW<u8>; 240],
}
-/// `&syst::Registers`
-pub fn syst() -> &'static syst::Registers {
- unsafe { ::deref(SYST) }
+impl Nvic {
+ /// Clears `interrupt`'s pending state
+ pub fn clear_pending<I>(&self, interrupt: I)
+ where I: Nr
+ {
+ let nr = interrupt.nr();
+
+ unsafe { self.icpr[usize::from(nr / 32)].write(1 << (nr % 32)) }
+ }
+
+ /// Disables `interrupt`
+ pub fn disable<I>(&self, interrupt: I)
+ where I: Nr
+ {
+ let nr = interrupt.nr();
+
+ unsafe { self.icer[usize::from(nr / 32)].write(1 << (nr % 32)) }
+ }
+
+ /// Enables `interrupt`
+ pub fn enable<I>(&self, interrupt: I)
+ where I: Nr
+ {
+ let nr = interrupt.nr();
+
+ unsafe { self.iser[usize::from(nr / 32)].write(1 << (nr % 32)) }
+ }
+
+ /// Gets the "priority" of `interrupt`
+ ///
+ /// NOTE NVIC encodes priority in the highest bits of a byte so values like
+ /// `1` and `2` have the same priority. Also for NVIC priorities, a lower
+ /// value (e.g. `16`) has higher priority than a larger value (e.g. `32`).
+ pub fn get_priority<I>(&self, interrupt: I) -> u8
+ where I: Nr
+ {
+ let nr = interrupt.nr();
+
+ self.ipr[usize::from(nr)].read()
+ }
+
+ /// Is `interrupt` active or pre-empted and stacked
+ pub fn is_active<I>(&self, interrupt: I) -> bool
+ where I: Nr
+ {
+ let nr = interrupt.nr();
+ let mask = 1 << (nr % 32);
+
+ (self.iabr[usize::from(nr / 32)].read() & mask) == mask
+ }
+
+ /// Checks if `interrupt` is enabled
+ pub fn is_enabled<I>(&self, interrupt: I) -> bool
+ where I: Nr
+ {
+ let nr = interrupt.nr();
+ let mask = 1 << (nr % 32);
+
+ (self.iser[usize::from(nr / 32)].read() & mask) == mask
+ }
+
+ /// Checks if `interrupt` is pending
+ pub fn is_pending<I>(&self, interrupt: I) -> bool
+ where I: Nr
+ {
+ let nr = interrupt.nr();
+ let mask = 1 << (nr % 32);
+
+ (self.ispr[usize::from(nr / 32)].read() & mask) == mask
+ }
+
+ /// Forces `interrupt` into pending state
+ pub fn set_pending<I>(&self, interrupt: I)
+ where I: Nr
+ {
+ let nr = interrupt.nr();
+
+ unsafe { self.ispr[usize::from(nr / 32)].write(1 << (nr % 32)) }
+ }
+
+ /// Sets the "priority" of `interrupt` to `prio`
+ ///
+ /// NOTE See `get_priority` method for an explanation of how NVIC priorities
+ /// work.
+ pub fn set_priority<I>(&self, interrupt: I, prio: u8)
+ where I: Nr
+ {
+ let nr = interrupt.nr();
+
+ unsafe { self.ipr[usize::from(nr)].write(prio) }
+ }
}
-/// `&mut syst::Registers`
-pub unsafe fn syst_mut() -> &'static mut syst::Registers {
- ::deref_mut(SYST)
+/// SCB register block
+#[repr(C)]
+pub struct Scb {
+ /// 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>,
}
-/// `&tpiu::Registers`
-pub fn tpiu() -> &'static tpiu::Registers {
- unsafe { ::deref(TPIU) }
+/// SysTick register block
+#[repr(C)]
+pub struct Syst {
+ /// 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>,
}
-/// `&mut tpiu::Registers`
-pub unsafe fn tpiu_mut() -> &'static mut tpiu::Registers {
- ::deref_mut(TPIU)
+/// TPIU register block
+#[repr(C)]
+pub struct Tpiu {
+ /// 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/peripheral/mpu.rs b/src/peripheral/mpu.rs
deleted file mode 100644
index e024e62..0000000
--- a/src/peripheral/mpu.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-//! 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
deleted file mode 100644
index 8c12698..0000000
--- a/src/peripheral/nvic.rs
+++ /dev/null
@@ -1,119 +0,0 @@
-//! Nested Vector Interrupt Controller
-
-use interrupt::Nr;
-use volatile_register::{RO, RW};
-
-/// Registers
-#[repr(C)]
-pub struct Registers {
- /// Interrupt Set-Enable
- iser: [RW<u32>; 8],
- reserved0: [u32; 24],
- /// Interrupt Clear-Enable
- icer: [RW<u32>; 8],
- reserved1: [u32; 24],
- /// Interrupt Set-Pending
- ispr: [RW<u32>; 8],
- reserved2: [u32; 24],
- /// Interrupt Clear-Pending
- icpr: [RW<u32>; 8],
- reserved3: [u32; 24],
- /// Interrupt Active Bit
- iabr: [RO<u32>; 8],
- reserved4: [u32; 56],
- /// Interrupt Priority
- ipr: [RW<u8>; 240],
-}
-
-impl Registers {
- /// Clears `interrupt` pending state
- pub fn clear_pending<I>(&mut self, interrupt: I)
- where I: Nr
- {
- let nr = interrupt.nr();
-
- self.icpr[usize::from(nr / 32)].write(1 << (nr % 32));
- }
-
- /// Disables `interrupt`
- pub fn disable<I>(&mut self, interrupt: I)
- where I: Nr
- {
- let nr = interrupt.nr();
-
- self.icer[usize::from(nr / 32)].write(1 << (nr % 32));
- }
-
- /// Enables `interrupt`
- pub fn enable<I>(&mut self, interrupt: I)
- where I: Nr
- {
- let nr = interrupt.nr();
-
- self.iser[usize::from(nr / 32)].write(1 << (nr % 32));
- }
-
- /// Gets the "priority" of `interrupt`
- ///
- /// NOTE NVIC encodes priority in the highest bits of a byte so values like
- /// `1` and `2` have the same priority. Also for NVIC priorities, a lower
- /// value (e.g. `16`) has higher priority than a larger value (e.g. `32`).
- pub fn get_priority<I>(&mut self, interrupt: I) -> u8
- where I: Nr
- {
- let nr = interrupt.nr();
-
- self.ipr[usize::from(nr)].read()
- }
-
- /// Is `interrupt` active or pre-empted and stacked
- pub fn is_active<I>(&self, interrupt: I) -> bool
- where I: Nr
- {
- let nr = interrupt.nr();
- let mask = 1 << (nr % 32);
-
- (self.iabr[usize::from(nr / 32)].read() & mask) == mask
- }
-
- /// Checks if `interrupt` is enabled
- pub fn is_enabled<I>(&self, interrupt: I) -> bool
- where I: Nr
- {
- let nr = interrupt.nr();
- let mask = 1 << (nr % 32);
-
- (self.iser[usize::from(nr / 32)].read() & mask) == mask
- }
-
- /// Checks if `interrupt` is pending
- pub fn is_pending<I>(&self, interrupt: I) -> bool
- where I: Nr
- {
- let nr = interrupt.nr();
- let mask = 1 << (nr % 32);
-
- (self.ispr[usize::from(nr / 32)].read() & mask) == mask
- }
-
- /// Forces `interrupt` into pending state
- pub fn set_pending<I>(&mut self, interrupt: I)
- where I: Nr
- {
- let nr = interrupt.nr();
-
- self.ispr[usize::from(nr / 32)].write(1 << (nr % 32));
- }
-
- /// Sets the "priority" of `interrupt` to `prio`
- ///
- /// NOTE See `get_priority` method for an explanation of how NVIC priorities
- /// work.
- pub fn set_priority<I>(&mut self, interrupt: I, prio: u8)
- where I: Nr
- {
- let nr = interrupt.nr();
-
- self.ipr[usize::from(nr)].write(prio);
- }
-}
diff --git a/src/peripheral/scb.rs b/src/peripheral/scb.rs
deleted file mode 100644
index d2b204a..0000000
--- a/src/peripheral/scb.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-//! 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
deleted file mode 100644
index 8ee70a1..0000000
--- a/src/peripheral/syst.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-//! 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
index c291b16..1770e03 100644
--- a/src/peripheral/test.rs
+++ b/src/peripheral/test.rs
@@ -1,162 +1,167 @@
#[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);
+ let cpuid = unsafe { &*::peripheral::CPUID.get() };
+
+ 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);
- }
+ let dcb = unsafe { &*::peripheral::DCB.get() };
+
+ 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);
- }
+ let dwt = unsafe { &*::peripheral::DWT.get() };
+
+ 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);
- }
+ let fpb = unsafe { &*::peripheral::FPB.get() };
+
+ 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);
- }
+ let fpu = unsafe { &*::peripheral::FPU.get() };
+
+ 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);
- }
+ let itm = unsafe { &*::peripheral::ITM.get() };
+
+ 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);
- }
+ let mpu = unsafe { &*::peripheral::MPU.get() };
+
+ 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);
- }
+ let nvic = unsafe { &*::peripheral::NVIC.get() };
+
+ assert_eq!(address(&nvic.iser), 0xE000E100);
+ assert_eq!(address(&nvic.iser[7]), 0xE000E11C);
+ assert_eq!(address(&nvic.icer), 0xE000E180);
+ assert_eq!(address(&nvic.icer[7]), 0xE000E19C);
+ assert_eq!(address(&nvic.ispr), 0xE000E200);
+ assert_eq!(address(&nvic.ispr[7]), 0xE000E21C);
+ assert_eq!(address(&nvic.icpr), 0xE000E280);
+ assert_eq!(address(&nvic.icpr[7]), 0xE000E29C);
+ assert_eq!(address(&nvic.iabr), 0xE000E300);
+ assert_eq!(address(&nvic.iabr[7]), 0xE000E31C);
+ assert_eq!(address(&nvic.ipr), 0xE000E400);
+ assert_eq!(address(&nvic.ipr[239]), 0xE000E4eF);
}
#[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);
- }
+ let scb = unsafe { &*::peripheral::SCB.get() };
+
+ 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);
- }
+ let syst = unsafe { &*::peripheral::SYST.get() };
+
+ 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);
- }
+ let tpiu = unsafe { &*::peripheral::TPIU.get() };
+
+ 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);
+}
+
+fn address<T>(r: *const T) -> usize {
+ r as usize
}
diff --git a/src/peripheral/tpiu.rs b/src/peripheral/tpiu.rs
deleted file mode 100644
index 5047351..0000000
--- a/src/peripheral/tpiu.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-//! 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>,
-}