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 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
/*********************************************************************************************************************** * Copyright (c) 2019 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. //! /// Helper macro to define the fields a register may contain of.<br> /// This is typically part of the register definition and will be applied there. It's not intended for use outside /// of a register definition. #[doc(hidden)] #[macro_export] macro_rules! register_field { ($t:ty, $field:ident, $offset:expr) => { #[allow(unused_variables, dead_code)] #[doc(hidden)] pub const $field: RegisterField<$t> = RegisterField::<$t>::new(1, $offset); }; ($t:ty, $field:ident, $offset:expr, $bits:expr) => { #[allow(unused_variables, dead_code)] #[doc(hidden)] pub const $field: RegisterField<$t> = RegisterField::<$t>::new((1 << $bits) - 1, $offset); }; } #[doc(hidden)] #[macro_export] macro_rules! register_field_values { ($field:ident, $t:ty, $($($fvdoc:expr)?, $enum:ident = $value:expr),*) => { $( $(#[doc = $fvdoc])? #[allow(unused_variables, dead_code)] pub const $enum:RegisterFieldValue::<$t> = RegisterFieldValue::<$t>::new($field, $value); )* }; } /// 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),*); )* } )* )* } )* }; }