aboutsummaryrefslogtreecommitdiff
path: root/src/peripheral
diff options
context:
space:
mode:
Diffstat (limited to 'src/peripheral')
-rw-r--r--src/peripheral/cpuid.rs30
-rw-r--r--src/peripheral/dcb.rs16
-rw-r--r--src/peripheral/dwt.rs43
-rw-r--r--src/peripheral/fpb.rs19
-rw-r--r--src/peripheral/fpu.rs17
-rw-r--r--src/peripheral/itm.rs54
-rw-r--r--src/peripheral/mod.rs149
-rw-r--r--src/peripheral/mpu.rs30
-rw-r--r--src/peripheral/nvic.rs25
-rw-r--r--src/peripheral/scb.rs37
-rw-r--r--src/peripheral/syst.rs16
-rw-r--r--src/peripheral/test.rs162
-rw-r--r--src/peripheral/tpiu.rs26
13 files changed, 624 insertions, 0 deletions
diff --git a/src/peripheral/cpuid.rs b/src/peripheral/cpuid.rs
new file mode 100644
index 0000000..0dc140f
--- /dev/null
+++ b/src/peripheral/cpuid.rs
@@ -0,0 +1,30 @@
+//! CPUID
+
+use volatile_register::RO;
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ /// CPUID base
+ pub base: RO<u32>,
+ reserved0: [u32; 15],
+ /// Processor Feature
+ pub pfr: [RO<u32>; 2],
+ /// Debug Feature
+ pub dfr: RO<u32>,
+ /// Auxiliary Feature
+ pub afr: RO<u32>,
+ /// Memory Model Feature
+ pub mmfr: [RO<u32>; 4],
+ /// Instruction Set Attribute
+ pub isar: [RO<u32>; 5],
+ reserved1: u32,
+ /// Cache Level ID
+ pub clidr: RO<u32>,
+ /// Cache Type
+ pub ctr: RO<u32>,
+ /// Cache Size ID
+ pub ccsidr: RO<u32>,
+ /// Cache Size Selection
+ pub csselr: RO<u32>,
+}
diff --git a/src/peripheral/dcb.rs b/src/peripheral/dcb.rs
new file mode 100644
index 0000000..93a056b
--- /dev/null
+++ b/src/peripheral/dcb.rs
@@ -0,0 +1,16 @@
+//! Debug Control Block
+
+use volatile_register::{RW, WO};
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ /// Debug Halting Control and Status
+ pub dhcsr: RW<u32>,
+ /// Debug Core Register Selector
+ pub dcrsr: WO<u32>,
+ /// Debug Core Register Data
+ pub dcrdr: RW<u32>,
+ /// Debug Exception and Monitor Control
+ pub demcr: RW<u32>,
+}
diff --git a/src/peripheral/dwt.rs b/src/peripheral/dwt.rs
new file mode 100644
index 0000000..ecd214e
--- /dev/null
+++ b/src/peripheral/dwt.rs
@@ -0,0 +1,43 @@
+//! Data Watchpoint and Trace unit
+
+use volatile_register::{RO, RW, WO};
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ /// Control
+ pub ctrl: RW<u32>,
+ /// Cycle Count
+ pub cyccnt: RW<u32>,
+ /// CPI Count
+ pub cpicnt: RW<u32>,
+ /// Exception Overhead Count
+ pub exccnt: RW<u32>,
+ /// Sleep Count
+ pub sleepcnt: RW<u32>,
+ /// LSU Count
+ pub lsucnt: RW<u32>,
+ /// Folded-instruction Count
+ pub foldcnt: RW<u32>,
+ /// Program Counter Sample
+ pub pcsr: RO<u32>,
+ /// Comparators
+ pub c: [Comparator; 16],
+ reserved: [u32; 932],
+ /// Lock Access
+ pub lar: WO<u32>,
+ /// Lock Status
+ pub lsr: RO<u32>,
+}
+
+/// Comparator
+#[repr(C)]
+pub struct Comparator {
+ /// Comparator
+ pub comp: RW<u32>,
+ /// Comparator Mask
+ pub mask: RW<u32>,
+ /// Comparator Function
+ pub function: RW<u32>,
+ reserved: u32,
+}
diff --git a/src/peripheral/fpb.rs b/src/peripheral/fpb.rs
new file mode 100644
index 0000000..6aa6fbb
--- /dev/null
+++ b/src/peripheral/fpb.rs
@@ -0,0 +1,19 @@
+//! Flash Patch and Breakpoint unit
+
+use volatile_register::{RO, RW, WO};
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ /// Control
+ pub ctrl: RW<u32>,
+ /// Remap
+ pub remap: RW<u32>,
+ /// Comparator
+ pub comp: [RW<u32>; 127],
+ reserved: [u32; 875],
+ /// Lock Access
+ pub lar: WO<u32>,
+ /// Lock Status
+ pub lsr: RO<u32>,
+}
diff --git a/src/peripheral/fpu.rs b/src/peripheral/fpu.rs
new file mode 100644
index 0000000..5bbf352
--- /dev/null
+++ b/src/peripheral/fpu.rs
@@ -0,0 +1,17 @@
+//! Floating Point Unit
+
+use volatile_register::{RO, RW};
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ reserved: u32,
+ /// Floating Point Context Control
+ pub fpccr: RW<u32>,
+ /// Floating Point Context Address
+ pub fpcar: RW<u32>,
+ /// Floating Point Default Status Control
+ pub fpdscr: RW<u32>,
+ /// Media and FP Feature
+ pub mvfr: [RO<u32>; 3],
+}
diff --git a/src/peripheral/itm.rs b/src/peripheral/itm.rs
new file mode 100644
index 0000000..b56d1b5
--- /dev/null
+++ b/src/peripheral/itm.rs
@@ -0,0 +1,54 @@
+//! Instrumentation Trace Macrocell
+
+use volatile_register::{RO, RW, WO};
+
+use core::cell::UnsafeCell;
+use core::ptr;
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ /// Stimulus Port
+ pub stim: [Stim; 256],
+ reserved0: [u32; 640],
+ /// Trace Enable
+ pub ter: [RW<u32>; 8],
+ reserved1: [u32; 8],
+ /// Trace Privilege
+ pub tpr: RW<u32>,
+ reserved2: [u32; 15],
+ /// Trace Control
+ pub tcr: RW<u32>,
+ reserved3: [u32; 75],
+ /// Lock Access
+ pub lar: WO<u32>,
+ /// Lock Status
+ pub lsr: RO<u32>,
+}
+
+/// Stimulus Port
+pub struct Stim {
+ register: UnsafeCell<u32>,
+}
+
+impl Stim {
+ /// Writes an `u8` payload into the stimulus port
+ pub fn write_u8(&self, value: u8) {
+ unsafe { ptr::write_volatile(self.register.get() as *mut u8, value) }
+ }
+
+ /// Writes an `u16` payload into the stimulus port
+ pub fn write_u16(&self, value: u16) {
+ unsafe { ptr::write_volatile(self.register.get() as *mut u16, value) }
+ }
+
+ /// Writes an `u32` payload into the stimulus port
+ pub fn write_u32(&self, value: u32) {
+ unsafe { ptr::write_volatile(self.register.get(), value) }
+ }
+
+ /// Returns `true` if the stimulus port is ready to accept more data
+ pub fn is_fifo_ready(&self) -> bool {
+ unsafe { ptr::read_volatile(self.register.get()) == 1 }
+ }
+}
diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs
new file mode 100644
index 0000000..9f02aa3
--- /dev/null
+++ b/src/peripheral/mod.rs
@@ -0,0 +1,149 @@
+//! Core peripherals
+//!
+//! # Notes
+//!
+//! - Although the `*_mut()` functions always return a valid/live reference, the API doesn't prevent
+//! the user from creating multiple mutable aliases. It's up to the user to ensure that no
+//! unsynchonized concurrent access is performed through these references.
+//!
+//! # Caveats
+//!
+//! - The API doesn't check if the value passed to `write` is valid (e.g. reserved bits are not
+//! modified) or not. It's up to the user to verify that.
+//!
+//! # References
+//!
+//! - ARMv7-M Architecture Reference Manual (Issue E.b) - Chapter B3
+
+pub mod cpuid;
+pub mod dcb;
+pub mod dwt;
+pub mod fpb;
+pub mod fpu;
+pub mod itm;
+pub mod mpu;
+pub mod nvic;
+pub mod scb;
+pub mod syst;
+pub mod tpiu;
+
+mod test;
+
+const CPUID: usize = 0xE000_ED00;
+const DCB: usize = 0xE000_EDF0;
+const DWT: usize = 0xE000_1000;
+const FPB: usize = 0xE000_2000;
+const FPU: usize = 0xE000_EF30;
+const ITM: usize = 0xE000_0000;
+const MPU: usize = 0xE000_ED90;
+const NVIC: usize = 0xE000_E100;
+const SCB: usize = 0xE000_ED04;
+const SYST: usize = 0xE000_E010;
+const TPIU: usize = 0xE004_0000;
+
+// TODO stand-alone registers: ICTR, ACTLR and STIR
+
+/// `&cpuid::Registers`
+pub fn cpuid() -> &'static cpuid::Registers {
+ unsafe { ::deref(CPUID) }
+}
+
+/// `&dcb::Registers`
+pub fn dcb() -> &'static dcb::Registers {
+ unsafe { ::deref(DCB) }
+}
+
+/// `&mut dcb::Registers`
+pub unsafe fn dcb_mut() -> &'static mut dcb::Registers {
+ ::deref_mut(DCB)
+}
+
+/// `&dwt::Registers`
+pub fn dwt() -> &'static dwt::Registers {
+ unsafe { ::deref(DWT) }
+}
+
+/// `&mut dwt::Registers`
+pub unsafe fn dwt_mut() -> &'static mut dwt::Registers {
+ ::deref_mut(DWT)
+}
+
+/// `&fpb::Registers`
+pub fn fpb() -> &'static fpb::Registers {
+ unsafe { ::deref(FPB) }
+}
+
+/// `&mut fpb::Registers`
+pub unsafe fn fpb_mut() -> &'static mut fpb::Registers {
+ ::deref_mut(FPB)
+}
+
+/// `&fpu::Registers`
+pub fn fpu() -> &'static fpu::Registers {
+ unsafe { ::deref(FPU) }
+}
+
+/// `&mut fpu::Registers`
+pub unsafe fn fpu_mut() -> &'static mut fpu::Registers {
+ ::deref_mut(FPU)
+}
+
+/// `&itm::Registers`
+pub fn itm() -> &'static itm::Registers {
+ unsafe { ::deref(ITM) }
+}
+
+/// `&mut itm::Registers`
+pub unsafe fn itm_mut() -> &'static mut itm::Registers {
+ ::deref_mut(ITM)
+}
+
+/// `&mpu::Registers`
+pub fn mpu() -> &'static mpu::Registers {
+ unsafe { ::deref(MPU) }
+}
+
+/// `&mut mpu::Registers`
+pub unsafe fn mpu_mut() -> &'static mut mpu::Registers {
+ ::deref_mut(MPU)
+}
+
+/// `&nvic::Registers`
+pub fn nvic() -> &'static nvic::Registers {
+ unsafe { ::deref(NVIC) }
+}
+
+/// `&mut nvic::Registers`
+pub unsafe fn nvic_mut() -> &'static mut nvic::Registers {
+ ::deref_mut(NVIC)
+}
+
+/// `&scb::Registers`
+pub fn scb() -> &'static scb::Registers {
+ unsafe { ::deref(SCB) }
+}
+
+/// `&mut scb::Registers`
+pub unsafe fn scb_mut() -> &'static mut scb::Registers {
+ ::deref_mut(SCB)
+}
+
+/// `&syst::Registers`
+pub fn syst() -> &'static syst::Registers {
+ unsafe { ::deref(SYST) }
+}
+
+/// `&mut syst::Registers`
+pub unsafe fn syst_mut() -> &'static mut syst::Registers {
+ ::deref_mut(SYST)
+}
+
+/// `&tpiu::Registers`
+pub fn tpiu() -> &'static tpiu::Registers {
+ unsafe { ::deref(TPIU) }
+}
+
+/// `&mut tpiu::Registers`
+pub unsafe fn tpiu_mut() -> &'static mut tpiu::Registers {
+ ::deref_mut(TPIU)
+}
diff --git a/src/peripheral/mpu.rs b/src/peripheral/mpu.rs
new file mode 100644
index 0000000..e024e62
--- /dev/null
+++ b/src/peripheral/mpu.rs
@@ -0,0 +1,30 @@
+//! Memory Protection Unit
+
+use volatile_register::{RO, RW};
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ /// Type
+ pub _type: RO<u32>,
+ /// Control
+ pub ctrl: RW<u32>,
+ /// Region Number
+ pub rnr: RW<u32>,
+ /// Region Base Address
+ pub rbar: RW<u32>,
+ /// Region Attribute and Size
+ pub rasr: RW<u32>,
+ /// Alias 1 of RBAR
+ pub rbar_a1: RW<u32>,
+ /// Alias 1 of RSAR
+ pub rsar_a1: RW<u32>,
+ /// Alias 2 of RBAR
+ pub rbar_a2: RW<u32>,
+ /// Alias 2 of RSAR
+ pub rsar_a2: RW<u32>,
+ /// Alias 3 of RBAR
+ pub rbar_a3: RW<u32>,
+ /// Alias 3 of RSAR
+ pub rsar_a3: RW<u32>,
+}
diff --git a/src/peripheral/nvic.rs b/src/peripheral/nvic.rs
new file mode 100644
index 0000000..4570c0f
--- /dev/null
+++ b/src/peripheral/nvic.rs
@@ -0,0 +1,25 @@
+//! Nested Vector Interrupt Controller
+
+use volatile_register::{RO, RW};
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ /// Interrupt Set-Enable
+ pub iser: [RW<u32>; 16],
+ reserved0: [u32; 16],
+ /// Interrupt Clear-Enable
+ pub icer: [RW<u32>; 16],
+ reserved1: [u32; 16],
+ /// Interrupt Set-Pending
+ pub ispr: [RW<u32>; 16],
+ reserved2: [u32; 16],
+ /// Interrupt Clear-Pending
+ pub icpr: [RW<u32>; 16],
+ reserved3: [u32; 16],
+ /// Interrupt Active Bit
+ pub iabr: [RO<u32>; 16],
+ reserved4: [u32; 48],
+ /// Interrupt Priority
+ pub ipr: [RW<u32>; 124],
+}
diff --git a/src/peripheral/scb.rs b/src/peripheral/scb.rs
new file mode 100644
index 0000000..d2b204a
--- /dev/null
+++ b/src/peripheral/scb.rs
@@ -0,0 +1,37 @@
+//! System Control Block
+
+use volatile_register::RW;
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ /// Interrupt Control and State
+ pub icsr: RW<u32>,
+ /// Vector Table Offset
+ pub vtor: RW<u32>,
+ /// Application Interrupt and Reset Control
+ pub aircr: RW<u32>,
+ /// System Control
+ pub scr: RW<u32>,
+ /// Configuration and Control
+ pub ccr: RW<u32>,
+ /// System Handler Priority
+ pub shpr: [RW<u8>; 12],
+ /// System Handler Control and State
+ pub shpcrs: RW<u32>,
+ /// Configurable Fault Status
+ pub cfsr: RW<u32>,
+ /// HardFault Status
+ pub hfsr: RW<u32>,
+ /// Debug Fault Status
+ pub dfsr: RW<u32>,
+ /// MemManage Fault Address
+ pub mmar: RW<u32>,
+ /// BusFault Address
+ pub bfar: RW<u32>,
+ /// Auxiliary Fault Status
+ pub afsr: RW<u32>,
+ reserved: [u32; 18],
+ /// Coprocessor Access Control
+ pub cpacr: RW<u32>,
+}
diff --git a/src/peripheral/syst.rs b/src/peripheral/syst.rs
new file mode 100644
index 0000000..8ee70a1
--- /dev/null
+++ b/src/peripheral/syst.rs
@@ -0,0 +1,16 @@
+//! SysTick: System Timer
+
+use volatile_register::{RO, RW};
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ /// Control and Status
+ pub csr: RW<u32>,
+ /// Reload Value
+ pub rvr: RW<u32>,
+ /// Current Value
+ pub cvr: RW<u32>,
+ /// Calibration Value
+ pub calib: RO<u32>,
+}
diff --git a/src/peripheral/test.rs b/src/peripheral/test.rs
new file mode 100644
index 0000000..c291b16
--- /dev/null
+++ b/src/peripheral/test.rs
@@ -0,0 +1,162 @@
+#[test]
+fn cpuid() {
+ let cpuid = ::peripheral::cpuid();
+
+ assert_eq!(::address(&cpuid.base), 0xE000_ED00);
+ assert_eq!(::address(&cpuid.pfr), 0xE000_ED40);
+ assert_eq!(::address(&cpuid.dfr), 0xE000_ED48);
+ assert_eq!(::address(&cpuid.afr), 0xE000_ED4C);
+ assert_eq!(::address(&cpuid.mmfr), 0xE000_ED50);
+ assert_eq!(::address(&cpuid.isar), 0xE000_ED60);
+ assert_eq!(::address(&cpuid.clidr), 0xE000_ED78);
+ assert_eq!(::address(&cpuid.ctr), 0xE000_ED7C);
+ assert_eq!(::address(&cpuid.ccsidr), 0xE000_ED80);
+ assert_eq!(::address(&cpuid.csselr), 0xE000_ED84);
+}
+
+#[test]
+fn dcb() {
+ for dcb in &[::peripheral::dcb(), unsafe { ::peripheral::dcb_mut() }] {
+ assert_eq!(::address(&dcb.dhcsr), 0xE000_EDF0);
+ assert_eq!(::address(&dcb.dcrsr), 0xE000_EDF4);
+ assert_eq!(::address(&dcb.dcrdr), 0xE000_EDF8);
+ assert_eq!(::address(&dcb.demcr), 0xE000_EDFC);
+ }
+}
+
+#[test]
+fn dwt() {
+ for dwt in &[::peripheral::dwt(), unsafe { ::peripheral::dwt_mut() }] {
+ assert_eq!(::address(&dwt.ctrl), 0xE000_1000);
+ assert_eq!(::address(&dwt.cyccnt), 0xE000_1004);
+ assert_eq!(::address(&dwt.cpicnt), 0xE000_1008);
+ assert_eq!(::address(&dwt.exccnt), 0xE000_100C);
+ assert_eq!(::address(&dwt.sleepcnt), 0xE000_1010);
+ assert_eq!(::address(&dwt.lsucnt), 0xE000_1014);
+ assert_eq!(::address(&dwt.foldcnt), 0xE000_1018);
+ assert_eq!(::address(&dwt.pcsr), 0xE000_101C);
+ assert_eq!(::address(&dwt.c[0].comp), 0xE000_1020);
+ assert_eq!(::address(&dwt.c[0].mask), 0xE000_1024);
+ assert_eq!(::address(&dwt.c[0].function), 0xE000_1028);
+ assert_eq!(::address(&dwt.c[1].comp), 0xE000_1030);
+ assert_eq!(::address(&dwt.c[1].mask), 0xE000_1034);
+ assert_eq!(::address(&dwt.c[1].function), 0xE000_1038);
+ assert_eq!(::address(&dwt.lar), 0xE000_1FB0);
+ assert_eq!(::address(&dwt.lsr), 0xE000_1FB4);
+ }
+}
+
+#[test]
+fn fpb() {
+ for fpb in &[::peripheral::fpb(), unsafe { ::peripheral::fpb_mut() }] {
+ assert_eq!(::address(&fpb.ctrl), 0xE000_2000);
+ assert_eq!(::address(&fpb.remap), 0xE000_2004);
+ assert_eq!(::address(&fpb.comp), 0xE000_2008);
+ assert_eq!(::address(&fpb.comp[1]), 0xE000_200C);
+ assert_eq!(::address(&fpb.lar), 0xE000_2FB0);
+ assert_eq!(::address(&fpb.lsr), 0xE000_2FB4);
+ }
+}
+
+#[test]
+fn fpu() {
+ for fpu in &[::peripheral::fpu(), unsafe { ::peripheral::fpu_mut() }] {
+ assert_eq!(::address(&fpu.fpccr), 0xE000_EF34);
+ assert_eq!(::address(&fpu.fpcar), 0xE000_EF38);
+ assert_eq!(::address(&fpu.fpdscr), 0xE000_EF3C);
+ assert_eq!(::address(&fpu.mvfr), 0xE000_EF40);
+ assert_eq!(::address(&fpu.mvfr[1]), 0xE000_EF44);
+ assert_eq!(::address(&fpu.mvfr[2]), 0xE000_EF48);
+ }
+}
+
+#[test]
+fn itm() {
+ for itm in &[::peripheral::itm(), unsafe { ::peripheral::itm_mut() }] {
+ assert_eq!(::address(&itm.stim), 0xE000_0000);
+ assert_eq!(::address(&itm.ter), 0xE000_0E00);
+ assert_eq!(::address(&itm.tpr), 0xE000_0E40);
+ assert_eq!(::address(&itm.tcr), 0xE000_0E80);
+ assert_eq!(::address(&itm.lar), 0xE000_0FB0);
+ assert_eq!(::address(&itm.lsr), 0xE000_0FB4);
+ }
+}
+
+#[test]
+fn mpu() {
+ for mpu in &[::peripheral::mpu(), unsafe { ::peripheral::mpu_mut() }] {
+ assert_eq!(::address(&mpu._type), 0xE000ED90);
+ assert_eq!(::address(&mpu.ctrl), 0xE000ED94);
+ assert_eq!(::address(&mpu.rnr), 0xE000ED98);
+ assert_eq!(::address(&mpu.rbar), 0xE000ED9C);
+ assert_eq!(::address(&mpu.rasr), 0xE000EDA0);
+ assert_eq!(::address(&mpu.rbar_a1), 0xE000EDA4);
+ assert_eq!(::address(&mpu.rsar_a1), 0xE000EDA8);
+ assert_eq!(::address(&mpu.rbar_a2), 0xE000EDAC);
+ assert_eq!(::address(&mpu.rsar_a2), 0xE000EDB0);
+ assert_eq!(::address(&mpu.rbar_a3), 0xE000EDB4);
+ assert_eq!(::address(&mpu.rsar_a3), 0xE000EDB8);
+ }
+}
+
+#[test]
+fn nvic() {
+ for nvic in &[::peripheral::nvic(), unsafe { ::peripheral::nvic_mut() }] {
+ assert_eq!(::address(&nvic.iser), 0xE000E100);
+ assert_eq!(::address(&nvic.iser[15]), 0xE000E13C);
+ assert_eq!(::address(&nvic.icer), 0xE000E180);
+ assert_eq!(::address(&nvic.icer[7]), 0xE000E19C);
+ assert_eq!(::address(&nvic.icer[15]), 0xE000E1BC);
+ assert_eq!(::address(&nvic.ispr), 0xE000E200);
+ assert_eq!(::address(&nvic.ispr[15]), 0xE000E23C);
+ assert_eq!(::address(&nvic.icpr), 0xE000E280);
+ assert_eq!(::address(&nvic.icpr[15]), 0xE000E2BC);
+ assert_eq!(::address(&nvic.iabr), 0xE000E300);
+ assert_eq!(::address(&nvic.iabr[15]), 0xE000E33C);
+ assert_eq!(::address(&nvic.ipr), 0xE000E400);
+ assert_eq!(::address(&nvic.ipr[59]), 0xE000E4EC);
+ }
+}
+
+#[test]
+fn scb() {
+ for scb in &[::peripheral::scb(), unsafe { ::peripheral::scb_mut() }] {
+ assert_eq!(::address(&scb.icsr), 0xE000_ED04);
+ assert_eq!(::address(&scb.vtor), 0xE000_ED08);
+ assert_eq!(::address(&scb.aircr), 0xE000_ED0C);
+ assert_eq!(::address(&scb.scr), 0xE000_ED10);
+ assert_eq!(::address(&scb.ccr), 0xE000_ED14);
+ assert_eq!(::address(&scb.shpr), 0xE000_ED18);
+ assert_eq!(::address(&scb.shpcrs), 0xE000_ED24);
+ assert_eq!(::address(&scb.cfsr), 0xE000_ED28);
+ assert_eq!(::address(&scb.hfsr), 0xE000_ED2C);
+ assert_eq!(::address(&scb.dfsr), 0xE000_ED30);
+ assert_eq!(::address(&scb.mmar), 0xE000_ED34);
+ assert_eq!(::address(&scb.bfar), 0xE000_ED38);
+ assert_eq!(::address(&scb.afsr), 0xE000_ED3C);
+ assert_eq!(::address(&scb.cpacr), 0xE000_ED88);
+ }
+}
+
+#[test]
+fn syst() {
+ for syst in &[::peripheral::syst(), unsafe { ::peripheral::syst_mut() }] {
+ assert_eq!(::address(&syst.csr), 0xE000_E010);
+ assert_eq!(::address(&syst.rvr), 0xE000_E014);
+ assert_eq!(::address(&syst.cvr), 0xE000_E018);
+ assert_eq!(::address(&syst.calib), 0xE000_E01C);
+ }
+}
+
+#[test]
+fn tpiu() {
+ for tpiu in &[::peripheral::tpiu(), unsafe { ::peripheral::tpiu_mut() }] {
+ assert_eq!(::address(&tpiu.sspsr), 0xE004_0000);
+ assert_eq!(::address(&tpiu.cspsr), 0xE004_0004);
+ assert_eq!(::address(&tpiu.acpr), 0xE004_0010);
+ assert_eq!(::address(&tpiu.sppr), 0xE004_00F0);
+ assert_eq!(::address(&tpiu.lar), 0xE004_0FB0);
+ assert_eq!(::address(&tpiu.lsr), 0xE004_0FB4);
+ assert_eq!(::address(&tpiu._type), 0xE004_0FC8);
+ }
+}
diff --git a/src/peripheral/tpiu.rs b/src/peripheral/tpiu.rs
new file mode 100644
index 0000000..5047351
--- /dev/null
+++ b/src/peripheral/tpiu.rs
@@ -0,0 +1,26 @@
+//! Trace Port Interface Unit
+
+use volatile_register::{RO, RW, WO};
+
+/// Registers
+#[repr(C)]
+pub struct Registers {
+ /// Supported Parallel Port Sizes
+ pub sspsr: RO<u32>,
+ /// Current Parallel Port Size
+ pub cspsr: RW<u32>,
+ reserved0: [u32; 2],
+ /// Asynchronous Clock Prescaler
+ pub acpr: RW<u32>,
+ reserved1: [u32; 55],
+ /// Selected Pin Control
+ pub sppr: RW<u32>,
+ reserved2: [u32; 943],
+ /// Lock Access
+ pub lar: WO<u32>,
+ /// Lock Status
+ pub lsr: RO<u32>,
+ reserved3: [u32; 4],
+ /// TPIU Type
+ pub _type: RO<u32>,
+}