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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*********************************************************************************************************************** 
 * Copyright (c) 2019 by the authors
 * 
 * Author: André Borrmann 
 * License: Appache License 2.0
 **********************************************************************************************************************/

//! # Register abstraction implementation
//! 
//! The provided implementation details of the register access abstraction are used by the corresponding macros
//! of this crate. It is preferred to use the macros to properly define the registers to be used.

use core::ptr::{read_volatile, write_volatile};
use core::ops::{BitOr, BitAnd, Not, Shl, Shr};

/// This trait is used to describe the register size/length as type specifier. The trait is only implemented for the
/// internal types **u8**, **u16**, **u32** and **u64** to ensure safe register access sizes with compile time checking
pub trait RegisterType: 
    Copy + 
    Clone +
    BitOr<Output=Self> +
    BitAnd<Output=Self> + 
    Not<Output=Self> +
    Shl<Self, Output=Self> +
    Shr<Self, Output=Self> { }

// Internal macro to ease the assignment of the custom trait to supported register sizes
#[doc(hidden)]
macro_rules! registertype_impl {
    // invoke the macro for a given type t as often as types are provided when invoking the macro
    ($( $t:ty ),*) => ($(
        impl RegisterType for $t { }        
    )*)
}

// implement the type trait for specific unsigned types to enable only those register types/sizes
registertype_impl![u8, u16, u32, u64];

/// This struct allows read only access to a register.
#[derive(Clone)]
pub struct ReadOnly<T: RegisterType> {
    ptr: *mut T, // base address for the register
}

/// This struct allows write only access to a register.
#[derive(Clone)]
pub struct WriteOnly<T: RegisterType> {
    ptr: *mut T, // base address for the register
}

/// This struct allows read/write access to a register.
#[derive(Clone)]
pub struct ReadWrite<T: RegisterType> {
    ptr: *mut T, // base address for the register
}

/*************** internal used macros to ease implementation ******************/
macro_rules! registernew_impl {
    () => (
        /// Create a new instance of the register access struct.
        pub const fn new(addr: u32) -> Self {
            Self { ptr: addr as *mut T }
        }
    )
}

macro_rules! registerget_impl {
    () => (
        /// Read raw content of a register.
        #[inline]
        pub fn get(&self) -> T {
            unsafe { read_volatile(self.ptr) }
        }

        /// Read the value of a specific register field
        #[inline]
        pub fn read(&self, field: RegisterField<T>) -> T {
            let val = self.get();
            (val & field.mask) >> field.shift
        }
    )
}

macro_rules! registerset_impl {
    () => (
        /// Write raw content value to the register.
        #[inline]
        pub fn set(&self, value: T) {
            unsafe { write_volatile(self.ptr, value) }
        }

        /// Write the value of a specific register field
        #[inline]
        pub fn write(&self, field: RegisterField<T>, value: T) {
            let val = (value & field.mask) << field.shift;
            self.set(val);
        }
    )
}

impl<T: RegisterType> ReadOnly<T> {
    registernew_impl!();
    registerget_impl!();
}

impl<T: RegisterType> WriteOnly<T> {
    registernew_impl!();
    registerset_impl!();
}

impl<T: RegisterType> ReadWrite<T> {
    registernew_impl!();
    registerget_impl!();
    registerset_impl!();

    /// Udate a register field with a given value
    pub fn modify(&self, field: RegisterField<T>, value: T) -> T {

        let old_val = self.get();
        let new_val = (old_val & !field.mask) | (value << field.shift);
        self.set(new_val);
        
        new_val
    }
}

/// Definition of a field contained inside of a register. Each field is defined by a mask and the bit shift value
/// when constructing the field definition the stored mask is already shifted by the shift value
#[derive(Copy, Clone)]
pub struct RegisterField<T: RegisterType> {
    mask: T,
    shift: T,
}

// Internal helper macro to implement the ```RegisterField```struct for all relevant basic types
#[doc(hidden)]
macro_rules! registerfield_impl {
    ($($t:ty),*) => ($(
        impl RegisterField<$t> {
            pub const fn new(mask: $t, shift: $t) -> RegisterField<$t> {
                Self {
                    mask: mask << shift,
                    shift: shift,
                }
            }
        }
    )*);
}

registerfield_impl![u8, u16, u32, u64];