diff options
author | 2017-03-07 22:56:06 -0500 | |
---|---|---|
committer | 2017-03-07 22:58:33 -0500 | |
commit | c3a35c1b6cea81aa71e8832bca79ccafa492be02 (patch) | |
tree | e868906d20c906d238be96cd5c07b07342f7a111 | |
parent | 9d3f3f323f3b7543d0b49e773aea2c68e535ec83 (diff) | |
download | cortex-m-c3a35c1b6cea81aa71e8832bca79ccafa492be02.tar.gz cortex-m-c3a35c1b6cea81aa71e8832bca79ccafa492be02.tar.zst cortex-m-c3a35c1b6cea81aa71e8832bca79ccafa492be02.zip |
revamp for memory safety
-rw-r--r-- | CHANGELOG.md | 49 | ||||
-rw-r--r-- | Cargo.toml | 4 | ||||
-rw-r--r-- | src/ctxt.rs | 34 | ||||
-rw-r--r-- | src/exception.rs | 93 | ||||
-rw-r--r-- | src/interrupt.rs | 9 | ||||
-rw-r--r-- | src/lib.rs | 86 | ||||
-rw-r--r-- | src/peripheral/cpuid.rs | 30 | ||||
-rw-r--r-- | src/peripheral/dcb.rs | 16 | ||||
-rw-r--r-- | src/peripheral/dwt.rs | 43 | ||||
-rw-r--r-- | src/peripheral/fpb.rs | 19 | ||||
-rw-r--r-- | src/peripheral/fpu.rs | 17 | ||||
-rw-r--r-- | src/peripheral/itm.rs | 54 | ||||
-rw-r--r-- | src/peripheral/mod.rs | 494 | ||||
-rw-r--r-- | src/peripheral/mpu.rs | 30 | ||||
-rw-r--r-- | src/peripheral/nvic.rs | 119 | ||||
-rw-r--r-- | src/peripheral/scb.rs | 37 | ||||
-rw-r--r-- | src/peripheral/syst.rs | 16 | ||||
-rw-r--r-- | src/peripheral/test.rs | 243 | ||||
-rw-r--r-- | src/peripheral/tpiu.rs | 26 |
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 @@ -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 @@ -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>, -} |