1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
//! Processor core registers
//!
//! The following registers can only be accessed in PRIVILEGED mode:
//!
//! - MSP
//! - IPSR
//! - EPSR
//! - PRIMASK
//! - FAULTMASK
//! - BASEPRI
//! - CONTROL
//!
//! The rest of registers (see list below) can be accessed in either, PRIVILEGED or UNPRIVILEGED,
//! mode.
//!
//! - PSP
//! - LR
//! - PC
//! - APSR
//!
//! # Caveats
//!
//! - The API doesn't check if the value passed to `write` is valid (e.g. reserved bits are not
//!   modified) or not. It's up to the user to verify that.
//!
//! # References
//!
//! - Cortex-M* Devices Generic User Guide - Section 2.1.3 Core registers

// NOTE all the functions here are `always(inline)` to prevent a function call which may change the
// contents of the core registers.

macro_rules! sr {
    ($name:ident) => {
        /// Reads the special register
        #[inline(always)]
        pub unsafe fn read() -> u32 {
            let r: u32;
            match () {
                #[cfg(target_arch = "arm")]
                () => asm!(concat!("mrs ", "$0,", stringify!($name)) : "=r"(r) ::: "volatile"),

                #[cfg(not(target_arch = "arm"))]
                () => r = 0,
            }
            r
        }
    };
}

macro_rules! srw {
    (#[$attr:meta] $name:ident) => {
        #[$attr]
        pub mod $name {
            sr!($name);

            /// Writes to the special register
            #[inline(always)]
            pub unsafe fn write(r: u32) {
                match r {
                    #[cfg(target_arch = "arm")]
                    _ => asm!(concat!("msr ", stringify!($name), ",$0") :: "r"(r) ::: "volatile"),

                    #[cfg(not(target_arch = "arm"))]
                    _ => {},
                }
            }
        }
    };
}

macro_rules! sro {
    (#[$attr:meta] $name:ident) => {
        #[$attr]
        pub mod $name {
            sr!($name);
        }
    }
}

macro_rules! rw {
    (#[$attr:meta] $name:ident : $r:ident) => {
        #[$attr]
        pub mod $name {
            /// Reads the special register
            #[inline(always)]
            pub unsafe fn read() -> u32 {
                let r: u32;
                match () {
                    #[cfg(target_arch = "arm")]
                    () => asm!(concat!("mov ", "$0,", stringify!($r)) : "=r"(r) ::: "volatile"),

                    #[cfg(not(target_arch = "arm"))]
                    () => r = 0,
                }
                r
            }

            /// Writes to the special register
            #[inline(always)]
            pub unsafe fn write(r: u32) {
                match r {
                    #[cfg(target_arch = "arm")]
                    _ => asm!(concat!("mov ", stringify!($r), ",$0") :: "r"(r) ::: "volatile"),

                    #[cfg(not(target_arch = "arm"))]
                    _ => {}
                }
            }
        }
    }
}

srw!(#[doc = "Main Stack Pointer"] msp);
srw!(#[doc = "Process Stack Pointer"] psp);
rw!(#[doc = "Link Register"] lr: r14);
rw!(#[doc = "Program Counter"] pc: r15);
srw!(#[doc = "Application Program Status Register"] apsr);
sro!(#[doc = "Interrupt Program Status Register"] ipsr);
sro!(#[doc = "Exception Program Status Register"] epsr);
srw!(#[doc = "Priority Mask Register"] primask);
srw!(#[doc = "Fault Mask Register"] faultmask);
srw!(#[doc = "Base Priority Mask Register"] basepri);
srw!(#[doc = "Control Register"] control);