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
/***********************************************************************************************************************
 * Copyright (c) 2020 by the authors
 * 
 * Author: André Borrmann <pspwizard@gmx.de>
 * License: Apache License 2.0 / MIT
 **********************************************************************************************************************/

//! # Register definition macros
//!
//! The macros are used to simplify the definition of system registers as well as MMIO register.
//!

/// Macro to define a MMIO register with specific defined access mode.<br>
/// The access mode could one of: **ReadOnly**, **WriteOnly**, **ReadWrite**.<br>
/// The register size/width could be one of: **u8**, **u16**, **u32**, **u64**
///
/// # Examples
///
/// Define a simple MMIO register that might only be accessed with it's raw value
/// ```no_run
/// # use ruspiro_mmio_register::*;
/// define_mmio_register!(
///     FOO<ReadWrite<u32>@(0x3F20_0000+0x10)>
/// );
/// ```
///
/// Define a MMIO register containing a single field at a given offset with 1 bit length.
/// ```no_run
/// # use ruspiro_mmio_register::*;
/// define_mmio_register!(
///     FOO<ReadWrite<u32>@(0x3F20_0000)> {
///         BAR OFFSET(0)
///     }
/// );
/// ```
///
/// Define a MMIO register containing several fields with different offsets and bit length
/// ```no_run
/// # use ruspiro_mmio_register::*;
/// define_mmio_register!(
///     FOO<ReadWrite<u32>@(0x3F20_0000)> {
///         BAR OFFSET(0),
///         BAZ OFFSET(3) BITS(3)
///     }
/// );
/// ```
///
/// Define multiple MMIO register at once
/// ```no_run
/// # use ruspiro_mmio_register::*;
/// define_mmio_register!(
///     FOO<ReadWrite<u32>@(0x3F20_0000)>,
///     BAR<ReadOnly<u32>@(0x3F20_0010)> {
///         BAZ OFFSET(0) BITS(2) [
///             VAL1 = 0b10
///         ]
///     }
/// );
/// ```
///
/// Define a MMIO register where one field has defined specific values to be choosen from when
/// writing to or updating this specific register field
/// ```no_run
/// # use ruspiro_mmio_register::*;
/// define_mmio_register!(
///     /// A MMIO Register FOO
///     /// Defines as Read/Write register
///     FOO<ReadWrite<u32>@(0x3F20_0000)> {
///         /// This is a register field BAR
///         BAR OFFSET(3) BITS(3),
///         /// This is a register field BAZ.
///         /// It contains enum like field value definitions
///         BAZ OFFSET(6) BITS(3) [
///             /// This is a value of the register field
///             VAL1 = 0b000,
///             VAL2 = 0b010
///         ],
///         BAL OFFSET(9) BITS(2) [
///             VAL1 = 0b01,
///             VAL2 = 0b11
///         ]
///     }
/// );
///
/// fn main() {
///     // write a specific value for one field of the MMIO register
///     FOO::Register.write_value(
///         FOO::BAL::VAL1
///     );
///
///     // combine field values of different fields to update the MMIO register
///     FOO::Register.write_value(
///         FOO::BAZ::VAL1 | FOO::BAL::VAL2
///     );
///
///     // write a specific value to a register field that does not provide default/enum values
///     FOO::Register.write_value(
///         FOO::BAR::with_value(0b010)
///     );
/// }
/// ```
#[macro_export]
macro_rules! define_mmio_register {
    // REGISTER_NAME<ReadWrite<TYPE>@ADDRESS> { FIELD OFFSET(num) BITS(num) [ VALUE: val ] }
    ($($(#[doc = $rdoc:expr])* $vis:vis $name:ident<$access:ident<$t:ty>@($addr:expr)> $(
        { $(
                $(#[doc = $fdoc:expr])*
                $field:ident OFFSET($offset:literal) $(BITS($bits:literal))?
                $([$($(#[doc = $fvdoc:expr])* $enum:ident = $value:expr),*])?
        ),* }
    )?),*) => {
        $(
            #[allow(non_snake_case)]
            #[allow(non_upper_case_globals)]
            $vis mod $name {
                #[allow(unused_imports)]
                use $crate::*;
                use super::*;
                $(#[doc = $rdoc])*
                #[allow(unused_variables, dead_code)]
                pub const Register: $access<$t> = $access::<$t>::new($addr);
                $(
                    $(
                        $(#[doc = $fdoc])*
                        $crate::register_field!($t, $field, $offset $(, $bits)?);
                        pub mod $field {
                            use super::*;
                            /// Create a ``RegisterFieldValue`` from the current ``RegisterField``
                            /// of this ``Register`` from a given value
                            #[inline]
                            #[allow(unused_variables, dead_code)]
                            pub const fn with_value(value: $t) -> RegisterFieldValue<$t> {
                                RegisterFieldValue::<$t>::new($field, value)
                            }
                            $(
                                $crate::register_field_values!($field, $t, $($($fvdoc)*, $enum = $value),*);
                            )*
                        }
                    )*
                )*
            }
        )*
    };
}