Skip to content

turn peripherals into scoped singletons #65

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
*.org
*.rs.bk
.#*
Cargo.lock
target
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ matrix:
before_install: set -e

install:
- sh ci/install.sh
- bash ci/install.sh

script:
- sh ci/script.sh
- bash ci/script.sh

after_script: set +e

Expand Down
2 changes: 1 addition & 1 deletion ci/install.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
set -ex
set -euxo pipefail

main() {
case $TARGET in
Expand Down
2 changes: 1 addition & 1 deletion ci/script.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
set -ex
set -euxo pipefail

main() {
case $TARGET in
Expand Down
4 changes: 2 additions & 2 deletions src/exception.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ impl Exception {
///
/// Returns `None` if no exception is currently active
pub fn active() -> Option<Exception> {
// NOTE(safe) atomic read
let icsr = unsafe { (*::peripheral::SCB.get()).icsr.read() };
// NOTE(safe) atomic read with no side effects
let icsr = unsafe { (*::peripheral::SCB::ptr()).icsr.read() };

Some(match icsr as u8 {
0 => return None,
Expand Down
2 changes: 1 addition & 1 deletion src/itm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use core::{fmt, mem, ptr, slice};

use aligned::Aligned;

use peripheral::Stim;
use peripheral::itm::Stim;

// NOTE assumes that `bytes` is 32-bit aligned
unsafe fn write_words(stim: &Stim, bytes: &[u32]) {
Expand Down
142 changes: 142 additions & 0 deletions src/peripheral/cbp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
//! Cache and branch predictor maintenance operations

use volatile_register::WO;

/// Register block
#[repr(C)]
pub struct RegisterBlock {
/// I-cache invalidate all to PoU
pub iciallu: WO<u32>,
reserved0: u32,
/// I-cache invalidate by MVA to PoU
pub icimvau: WO<u32>,
/// D-cache invalidate by MVA to PoC
pub dcimvac: WO<u32>,
/// D-cache invalidate by set-way
pub dcisw: WO<u32>,
/// D-cache clean by MVA to PoU
pub dccmvau: WO<u32>,
/// D-cache clean by MVA to PoC
pub dccmvac: WO<u32>,
/// D-cache clean by set-way
pub dccsw: WO<u32>,
/// D-cache clean and invalidate by MVA to PoC
pub dccimvac: WO<u32>,
/// D-cache clean and invalidate by set-way
pub dccisw: WO<u32>,
/// Branch predictor invalidate all
pub bpiall: WO<u32>,
}

const CBP_SW_WAY_POS: u32 = 30;
const CBP_SW_WAY_MASK: u32 = 0x3 << CBP_SW_WAY_POS;
const CBP_SW_SET_POS: u32 = 5;
const CBP_SW_SET_MASK: u32 = 0x1FF << CBP_SW_SET_POS;

impl RegisterBlock {
/// I-cache invalidate all to PoU
#[inline(always)]
pub fn iciallu(&self) {
unsafe {
self.iciallu.write(0);
}
}

/// I-cache invalidate by MVA to PoU
#[inline(always)]
pub fn icimvau(&self, mva: u32) {
unsafe {
self.icimvau.write(mva);
}
}

/// D-cache invalidate by MVA to PoC
#[inline(always)]
pub fn dcimvac(&self, mva: u32) {
unsafe {
self.dcimvac.write(mva);
}
}

/// D-cache invalidate by set-way
///
/// `set` is masked to be between 0 and 3, and `way` between 0 and 511.
#[inline(always)]
pub fn dcisw(&self, set: u16, way: u16) {
// The ARMv7-M Architecture Reference Manual, as of Revision E.b, says these set/way
// operations have a register data format which depends on the implementation's
// associativity and number of sets. Specifically the 'way' and 'set' fields have
// offsets 32-log2(ASSOCIATIVITY) and log2(LINELEN) respectively.
//
// However, in Cortex-M7 devices, these offsets are fixed at 30 and 5, as per the Cortex-M7
// Generic User Guide section 4.8.3. Since no other ARMv7-M implementations except the
// Cortex-M7 have a DCACHE or ICACHE at all, it seems safe to do the same thing as the
// CMSIS-Core implementation and use fixed values.
unsafe {
self.dcisw.write(
(((way as u32) & (CBP_SW_WAY_MASK >> CBP_SW_WAY_POS)) << CBP_SW_WAY_POS)
| (((set as u32) & (CBP_SW_SET_MASK >> CBP_SW_SET_POS)) << CBP_SW_SET_POS),
);
}
}

/// D-cache clean by MVA to PoU
#[inline(always)]
pub fn dccmvau(&self, mva: u32) {
unsafe {
self.dccmvau.write(mva);
}
}

/// D-cache clean by MVA to PoC
#[inline(always)]
pub fn dccmvac(&self, mva: u32) {
unsafe {
self.dccmvac.write(mva);
}
}

/// D-cache clean by set-way
///
/// `set` is masked to be between 0 and 3, and `way` between 0 and 511.
#[inline(always)]
pub fn dccsw(&self, set: u16, way: u16) {
// See comment for dcisw() about the format here
unsafe {
self.dccsw.write(
(((way as u32) & (CBP_SW_WAY_MASK >> CBP_SW_WAY_POS)) << CBP_SW_WAY_POS)
| (((set as u32) & (CBP_SW_SET_MASK >> CBP_SW_SET_POS)) << CBP_SW_SET_POS),
);
}
}

/// D-cache clean and invalidate by MVA to PoC
#[inline(always)]
pub fn dccimvac(&self, mva: u32) {
unsafe {
self.dccimvac.write(mva);
}
}

/// D-cache clean and invalidate by set-way
///
/// `set` is masked to be between 0 and 3, and `way` between 0 and 511.
#[inline(always)]
pub fn dccisw(&self, set: u16, way: u16) {
// See comment for dcisw() about the format here
unsafe {
self.dccisw.write(
(((way as u32) & (CBP_SW_WAY_MASK >> CBP_SW_WAY_POS)) << CBP_SW_WAY_POS)
| (((set as u32) & (CBP_SW_SET_MASK >> CBP_SW_SET_POS)) << CBP_SW_SET_POS),
);
}
}

/// Branch predictor invalidate all
#[inline(always)]
pub fn bpiall(&self) {
unsafe {
self.bpiall.write(0);
}
}
}
84 changes: 84 additions & 0 deletions src/peripheral/cpuid.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//! CPUID

use volatile_register::RO;
#[cfg(any(armv7m, test))]
use volatile_register::RW;

/// Register block
#[repr(C)]
pub struct RegisterBlock {
/// 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
#[cfg(any(armv7m, test))]
pub clidr: RO<u32>,
/// Cache Type
#[cfg(any(armv7m, test))]
pub ctr: RO<u32>,
/// Cache Size ID
#[cfg(any(armv7m, test))]
pub ccsidr: RO<u32>,
/// Cache Size Selection
#[cfg(any(armv7m, test))]
pub csselr: RW<u32>,
}

/// Type of cache to select on CSSELR writes.
#[cfg(armv7m)]
pub enum CsselrCacheType {
/// Select DCache or unified cache
DataOrUnified = 0,
/// Select ICache
Instruction = 1,
}

#[cfg(armv7m)]
impl RegisterBlock {
/// Selects the current CCSIDR
///
/// * `level`: the required cache level minus 1, e.g. 0 for L1, 1 for L2
/// * `ind`: select instruction cache or data/unified cache
///
/// `level` is masked to be between 0 and 7.
pub fn select_cache(&self, level: u8, ind: CsselrCacheType) {
const CSSELR_IND_POS: u32 = 0;
const CSSELR_IND_MASK: u32 = 1 << CSSELR_IND_POS;
const CSSELR_LEVEL_POS: u32 = 1;
const CSSELR_LEVEL_MASK: u32 = 0x7 << CSSELR_LEVEL_POS;

unsafe {
self.csselr.write(
(((level as u32) << CSSELR_LEVEL_POS) & CSSELR_LEVEL_MASK)
| (((ind as u32) << CSSELR_IND_POS) & CSSELR_IND_MASK),
)
}
}

/// Returns the number of sets and ways in the selected cache
pub fn cache_num_sets_ways(&self, level: u8, ind: CsselrCacheType) -> (u16, u16) {
const CCSIDR_NUMSETS_POS: u32 = 13;
const CCSIDR_NUMSETS_MASK: u32 = 0x7FFF << CCSIDR_NUMSETS_POS;
const CCSIDR_ASSOCIATIVITY_POS: u32 = 3;
const CCSIDR_ASSOCIATIVITY_MASK: u32 = 0x3FF << CCSIDR_ASSOCIATIVITY_POS;

self.select_cache(level, ind);
::asm::dsb();
let ccsidr = self.ccsidr.read();
(
(1 + ((ccsidr & CCSIDR_NUMSETS_MASK) >> CCSIDR_NUMSETS_POS)) as u16,
(1 + ((ccsidr & CCSIDR_ASSOCIATIVITY_MASK) >> CCSIDR_ASSOCIATIVITY_POS)) as u16,
)
}
}
16 changes: 16 additions & 0 deletions src/peripheral/dcb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//! Debug Control Block

use volatile_register::{RW, WO};

/// Register block
#[repr(C)]
pub struct RegisterBlock {
/// 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>,
}
50 changes: 50 additions & 0 deletions src/peripheral/dwt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//! Data Watchpoint and Trace unit

use volatile_register::{RO, RW, WO};

/// Register block
#[repr(C)]
pub struct RegisterBlock {
/// 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>,
}

impl RegisterBlock {
/// Enables the cycle counter
pub fn enable_cycle_counter(&self) {
unsafe { self.ctrl.modify(|r| r | 1) }
}
}

/// 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,
}
19 changes: 19 additions & 0 deletions src/peripheral/fpb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//! Flash Patch and Breakpoint unit

use volatile_register::{RO, RW, WO};

/// Register block
#[repr(C)]
pub struct RegisterBlock {
/// 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>,
}
22 changes: 22 additions & 0 deletions src/peripheral/fpu.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//! Floating Point Unit

#[cfg(any(has_fpu, test))]
use volatile_register::{RO, RW};

/// Register block
#[repr(C)]
pub struct RegisterBlock {
reserved: u32,
/// Floating Point Context Control
#[cfg(any(has_fpu, test))]
pub fpccr: RW<u32>,
/// Floating Point Context Address
#[cfg(any(has_fpu, test))]
pub fpcar: RW<u32>,
/// Floating Point Default Status Control
#[cfg(any(has_fpu, test))]
pub fpdscr: RW<u32>,
/// Media and FP Feature
#[cfg(any(has_fpu, test))]
pub mvfr: [RO<u32>; 3],
}
Loading