From 9a4e6dcbc1087196012f57f7083920f960adacdf Mon Sep 17 00:00:00 2001
From: Andrey Zgarbul <zgarbul.andrey@gmail.com>
Date: Fri, 17 May 2024 21:46:07 +0300
Subject: [PATCH] always raw access

---
 CHANGELOG.md                        |   2 +
 src/config.rs                       |   1 +
 src/generate/device.rs              |   6 +-
 src/generate/generic.rs             |  46 -----
 src/generate/generic_reg_raw.rs     | 301 ++++++++++++++++++++++++++++
 src/generate/generic_reg_vcell.rs   |  46 +++++
 src/generate/peripheral.rs          | 115 +++++++++--
 src/generate/peripheral/accessor.rs |  74 ++++++-
 src/main.rs                         |   7 +
 9 files changed, 526 insertions(+), 72 deletions(-)
 create mode 100644 src/generate/generic_reg_raw.rs

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d408095e..f5341436 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -35,6 +35,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
 
 ## [v0.34.0] - 2024-11-05
 
+- Add `raw-access` options
+
 - Revert #711
 - Add `defmt` impls for `TryFromInterruptError`, riscv interrupt enums
 - Fix calculating `modifiedWriteValues` bitmasks with field arrays
diff --git a/src/config.rs b/src/config.rs
index 024d8b78..833e9dd1 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -40,6 +40,7 @@ pub struct Config {
     pub ident_formats_theme: Option<IdentFormatsTheme>,
     pub field_names_for_enums: bool,
     pub base_address_shift: u64,
+    pub raw_access: bool,
     /// Path to YAML file with chip-specific settings
     pub settings_file: Option<PathBuf>,
     /// Chip-specific settings
diff --git a/src/generate/device.rs b/src/generate/device.rs
index 96e1d332..4a1a4ef4 100644
--- a/src/generate/device.rs
+++ b/src/generate/device.rs
@@ -137,7 +137,11 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
     }
 
     let generic_file = include_str!("generic.rs");
-    let generic_reg_file = include_str!("generic_reg_vcell.rs");
+    let generic_reg_file = if config.raw_access {
+        include_str!("generic_reg_raw.rs")
+    } else {
+        include_str!("generic_reg_vcell.rs")
+    };
     let generic_atomic_file = include_str!("generic_atomic.rs");
     if config.generic_mod {
         let mut file = File::create(
diff --git a/src/generate/generic.rs b/src/generate/generic.rs
index e527a4a8..caac8a6b 100644
--- a/src/generate/generic.rs
+++ b/src/generate/generic.rs
@@ -1,51 +1,5 @@
 use core::marker;
 
-/// Generic peripheral accessor
-pub struct Periph<RB, const A: usize> {
-    _marker: marker::PhantomData<RB>,
-}
-
-unsafe impl<RB, const A: usize> Send for Periph<RB, A> {}
-
-impl<RB, const A: usize> Periph<RB, A> {
-    ///Pointer to the register block
-    pub const PTR: *const RB = A as *const _;
-
-    ///Return the pointer to the register block
-    #[inline(always)]
-    pub const fn ptr() -> *const RB {
-        Self::PTR
-    }
-
-    /// Steal an instance of this peripheral
-    ///
-    /// # Safety
-    ///
-    /// Ensure that the new instance of the peripheral cannot be used in a way
-    /// that may race with any existing instances, for example by only
-    /// accessing read-only or write-only registers, or by consuming the
-    /// original peripheral and using critical sections to coordinate
-    /// access between multiple new instances.
-    ///
-    /// Additionally, other software such as HALs may rely on only one
-    /// peripheral instance existing to ensure memory safety; ensure
-    /// no stolen instances are passed to such software.
-    pub unsafe fn steal() -> Self {
-        Self {
-            _marker: marker::PhantomData,
-        }
-    }
-}
-
-impl<RB, const A: usize> core::ops::Deref for Periph<RB, A> {
-    type Target = RB;
-
-    #[inline(always)]
-    fn deref(&self) -> &Self::Target {
-        unsafe { &*Self::PTR }
-    }
-}
-
 /// Raw register type (`u8`, `u16`, `u32`, ...)
 pub trait RawReg:
     Copy
diff --git a/src/generate/generic_reg_raw.rs b/src/generate/generic_reg_raw.rs
new file mode 100644
index 00000000..4cc7f506
--- /dev/null
+++ b/src/generate/generic_reg_raw.rs
@@ -0,0 +1,301 @@
+/// This structure provides unsafe volatile access to registers.
+pub struct Reg<REG: RegisterSpec> {
+    ptr: *mut u8,
+    _marker: marker::PhantomData<REG>,
+}
+
+unsafe impl<REG: RegisterSpec> Send for Reg<REG> where REG::Ux: Send {}
+
+impl<REG: RegisterSpec> Reg<REG> {
+    #[inline(always)]
+    pub const fn new(ptr: *mut u8) -> Self {
+        Self {
+            ptr,
+            _marker: marker::PhantomData,
+        }
+    }
+    /// Returns the underlying memory address of register.
+    ///
+    /// ```ignore
+    /// let reg_ptr = periph.reg.as_ptr();
+    /// ```
+    #[inline(always)]
+    pub const fn as_ptr(&self) -> *mut REG::Ux {
+        self.ptr.cast()
+    }
+}
+
+impl<REG: Readable> Reg<REG> {
+    /// Reads the contents of a `Readable` register.
+    ///
+    /// You can read the raw contents of a register by using `bits`:
+    /// ```ignore
+    /// let bits = periph.reg.read().bits();
+    /// ```
+    /// or get the content of a particular field of a register:
+    /// ```ignore
+    /// let reader = periph.reg.read();
+    /// let bits = reader.field1().bits();
+    /// let flag = reader.field2().bit_is_set();
+    /// ```
+    #[inline(always)]
+    pub unsafe fn read(&self) -> R<REG> {
+        R {
+            bits: self.as_ptr().read_volatile(),
+            _reg: marker::PhantomData,
+        }
+    }
+}
+
+impl<REG: Resettable + Writable> Reg<REG> {
+    /// Writes the reset value to `Writable` register.
+    ///
+    /// Resets the register to its initial state.
+    #[inline(always)]
+    pub unsafe fn reset(&self) {
+        self.as_ptr().write_volatile(REG::RESET_VALUE)
+    }
+
+    /// Writes bits to a `Writable` register.
+    ///
+    /// You can write raw bits into a register:
+    /// ```ignore
+    /// periph.reg.write(|w| unsafe { w.bits(rawbits) });
+    /// ```
+    /// or write only the fields you need:
+    /// ```ignore
+    /// periph.reg.write(|w| w
+    ///     .field1().bits(newfield1bits)
+    ///     .field2().set_bit()
+    ///     .field3().variant(VARIANT)
+    /// );
+    /// ```
+    /// or an alternative way of saying the same:
+    /// ```ignore
+    /// periph.reg.write(|w| {
+    ///     w.field1().bits(newfield1bits);
+    ///     w.field2().set_bit();
+    ///     w.field3().variant(VARIANT)
+    /// });
+    /// ```
+    /// In the latter case, other fields will be set to their reset value.
+    #[inline(always)]
+    pub unsafe fn write<F>(&self, f: F) -> REG::Ux
+    where
+        F: FnOnce(&mut W<REG>) -> &mut W<REG>,
+    {
+        let value = f(&mut W {
+            bits: REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP
+                | REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
+            _reg: marker::PhantomData,
+        })
+        .bits;
+        self.as_ptr().write_volatile(value);
+        value
+    }
+
+    /// Writes bits to a `Writable` register and produce a value.
+    ///
+    /// You can write raw bits into a register:
+    /// ```ignore
+    /// periph.reg.write_and(|w| unsafe { w.bits(rawbits); });
+    /// ```
+    /// or write only the fields you need:
+    /// ```ignore
+    /// periph.reg.write_and(|w| {
+    ///     w.field1().bits(newfield1bits)
+    ///         .field2().set_bit()
+    ///         .field3().variant(VARIANT);
+    /// });
+    /// ```
+    /// or an alternative way of saying the same:
+    /// ```ignore
+    /// periph.reg.write_and(|w| {
+    ///     w.field1().bits(newfield1bits);
+    ///     w.field2().set_bit();
+    ///     w.field3().variant(VARIANT);
+    /// });
+    /// ```
+    /// In the latter case, other fields will be set to their reset value.
+    ///
+    /// Values can be returned from the closure:
+    /// ```ignore
+    /// let state = periph.reg.write_and(|w| State::set(w.field1()));
+    /// ```
+    #[inline(always)]
+    pub unsafe fn from_write<F, T>(&self, f: F) -> T
+    where
+        F: FnOnce(&mut W<REG>) -> T,
+    {
+        let mut writer = W {
+            bits: REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP
+                | REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
+            _reg: marker::PhantomData,
+        };
+        let result = f(&mut writer);
+
+        self.as_ptr().write_volatile(writer.bits);
+
+        result
+    }
+}
+
+impl<REG: Writable> Reg<REG> {
+    /// Writes 0 to a `Writable` register.
+    ///
+    /// Similar to `write`, but unused bits will contain 0.
+    ///
+    /// # Safety
+    ///
+    /// Unsafe to use with registers which don't allow to write 0.
+    #[inline(always)]
+    pub unsafe fn write_with_zero<F>(&self, f: F) -> REG::Ux
+    where
+        F: FnOnce(&mut W<REG>) -> &mut W<REG>,
+    {
+        let value = f(&mut W {
+            bits: REG::Ux::ZERO,
+            _reg: marker::PhantomData,
+        })
+        .bits;
+        self.as_ptr().write_volatile(value);
+        value
+    }
+
+    /// Writes 0 to a `Writable` register and produces a value.
+    ///
+    /// Similar to `write`, but unused bits will contain 0.
+    ///
+    /// # Safety
+    ///
+    /// Unsafe to use with registers which don't allow to write 0.
+    #[inline(always)]
+    pub unsafe fn from_write_with_zero<F, T>(&self, f: F) -> T
+    where
+        F: FnOnce(&mut W<REG>) -> T,
+    {
+        let mut writer = W {
+            bits: REG::Ux::ZERO,
+            _reg: marker::PhantomData,
+        };
+
+        let result = f(&mut writer);
+
+        self.as_ptr().write_volatile(writer.bits);
+
+        result
+    }
+}
+
+impl<REG: Readable + Writable> Reg<REG> {
+    /// Modifies the contents of the register by reading and then writing it.
+    ///
+    /// E.g. to do a read-modify-write sequence to change parts of a register:
+    /// ```ignore
+    /// periph.reg.modify(|r, w| unsafe { w.bits(
+    ///    r.bits() | 3
+    /// ) });
+    /// ```
+    /// or
+    /// ```ignore
+    /// periph.reg.modify(|_, w| w
+    ///     .field1().bits(newfield1bits)
+    ///     .field2().set_bit()
+    ///     .field3().variant(VARIANT)
+    /// );
+    /// ```
+    /// or an alternative way of saying the same:
+    /// ```ignore
+    /// periph.reg.modify(|_, w| {
+    ///     w.field1().bits(newfield1bits);
+    ///     w.field2().set_bit();
+    ///     w.field3().variant(VARIANT)
+    /// });
+    /// ```
+    /// Other fields will have the value they had before the call to `modify`.
+    #[inline(always)]
+    pub unsafe fn modify<F>(&self, f: F) -> REG::Ux
+    where
+        for<'w> F: FnOnce(&R<REG>, &'w mut W<REG>) -> &'w mut W<REG>,
+    {
+        let bits = self.as_ptr().read_volatile();
+        let value = f(
+            &R {
+                bits,
+                _reg: marker::PhantomData,
+            },
+            &mut W {
+                bits: bits & !REG::ONE_TO_MODIFY_FIELDS_BITMAP | REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
+                _reg: marker::PhantomData,
+            },
+        )
+        .bits;
+        self.as_ptr().write_volatile(value);
+        value
+    }
+
+    /// Modifies the contents of the register by reading and then writing it
+    /// and produces a value.
+    ///
+    /// E.g. to do a read-modify-write sequence to change parts of a register:
+    /// ```ignore
+    /// let bits = periph.reg.modify(|r, w| {
+    ///     let new_bits = r.bits() | 3;
+    ///     unsafe {
+    ///         w.bits(new_bits);
+    ///     }
+    ///
+    ///     new_bits
+    /// });
+    /// ```
+    /// or
+    /// ```ignore
+    /// periph.reg.modify(|_, w| {
+    ///     w.field1().bits(newfield1bits)
+    ///         .field2().set_bit()
+    ///         .field3().variant(VARIANT);
+    /// });
+    /// ```
+    /// or an alternative way of saying the same:
+    /// ```ignore
+    /// periph.reg.modify(|_, w| {
+    ///     w.field1().bits(newfield1bits);
+    ///     w.field2().set_bit();
+    ///     w.field3().variant(VARIANT);
+    /// });
+    /// ```
+    /// Other fields will have the value they had before the call to `modify`.
+    #[inline(always)]
+    pub unsafe fn from_modify<F, T>(&self, f: F) -> T
+    where
+        for<'w> F: FnOnce(&R<REG>, &'w mut W<REG>) -> T,
+    {
+        let bits = self.as_ptr().read_volatile();
+
+        let mut writer = W {
+            bits: bits & !REG::ONE_TO_MODIFY_FIELDS_BITMAP | REG::ZERO_TO_MODIFY_FIELDS_BITMAP,
+            _reg: marker::PhantomData,
+        };
+
+        let result = f(
+            &R {
+                bits,
+                _reg: marker::PhantomData,
+            },
+            &mut writer,
+        );
+
+        self.as_ptr().write_volatile(writer.bits);
+
+        result
+    }
+}
+
+impl<REG: Readable> core::fmt::Debug for crate::generic::Reg<REG>
+where
+    R<REG>: core::fmt::Debug,
+{
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        unsafe { core::fmt::Debug::fmt(&self.read(), f) }
+    }
+}
diff --git a/src/generate/generic_reg_vcell.rs b/src/generate/generic_reg_vcell.rs
index 9e436334..728781f4 100644
--- a/src/generate/generic_reg_vcell.rs
+++ b/src/generate/generic_reg_vcell.rs
@@ -1,3 +1,49 @@
+/// Generic peripheral accessor
+pub struct Periph<RB, const A: usize> {
+    _marker: marker::PhantomData<RB>,
+}
+
+unsafe impl<RB, const A: usize> Send for Periph<RB, A> {}
+
+impl<RB, const A: usize> Periph<RB, A> {
+    ///Pointer to the register block
+    pub const PTR: *const RB = A as *const _;
+
+    ///Return the pointer to the register block
+    #[inline(always)]
+    pub const fn ptr() -> *const RB {
+        Self::PTR
+    }
+
+    /// Steal an instance of this peripheral
+    ///
+    /// # Safety
+    ///
+    /// Ensure that the new instance of the peripheral cannot be used in a way
+    /// that may race with any existing instances, for example by only
+    /// accessing read-only or write-only registers, or by consuming the
+    /// original peripheral and using critical sections to coordinate
+    /// access between multiple new instances.
+    ///
+    /// Additionally, other software such as HALs may rely on only one
+    /// peripheral instance existing to ensure memory safety; ensure
+    /// no stolen instances are passed to such software.
+    pub unsafe fn steal() -> Self {
+        Self {
+            _marker: marker::PhantomData,
+        }
+    }
+}
+
+impl<RB, const A: usize> core::ops::Deref for Periph<RB, A> {
+    type Target = RB;
+
+    #[inline(always)]
+    fn deref(&self) -> &Self::Target {
+        unsafe { &*Self::PTR }
+    }
+}
+
 /// This structure provides volatile access to registers.
 #[repr(transparent)]
 pub struct Reg<REG: RegisterSpec> {
diff --git a/src/generate/peripheral.rs b/src/generate/peripheral.rs
index f5de3902..245fb9d0 100644
--- a/src/generate/peripheral.rs
+++ b/src/generate/peripheral.rs
@@ -74,13 +74,57 @@ pub fn render(p_original: &Peripheral, index: &Index, config: &Config) -> Result
                          p_ty: &Ident,
                          doc_alias: Option<TokenStream>,
                          address: LitInt| {
-        out.extend(quote! {
-            #[doc = #doc]
-            #phtml
-            #doc_alias
-            #feature_attribute
-            pub type #p_ty = crate::Periph<#base::RegisterBlock, #address>;
+        out.extend(if config.raw_access {
+            quote! {
+                #[doc = #doc]
+                #phtml
+                #doc_alias
+                #feature_attribute
+                pub struct #p_ty { rb: #base::RegisterBlock }
+
+                #feature_attribute
+                unsafe impl Send for #p_ty {}
+
+                #feature_attribute
+                impl #p_ty {
+                    /// Steal an instance of this peripheral
+                    ///
+                    /// # Safety
+                    ///
+                    /// Ensure that the new instance of the peripheral cannot be used in a way
+                    /// that may race with any existing instances, for example by only
+                    /// accessing read-only or write-only registers, or by consuming the
+                    /// original peripheral and using critical sections to coordinate
+                    /// access between multiple new instances.
+                    ///
+                    /// Additionally, other software such as HALs may rely on only one
+                    /// peripheral instance existing to ensure memory safety; ensure
+                    /// no stolen instances are passed to such software.
+                    pub unsafe fn steal() -> Self {
+                        Self { rb: #base::RegisterBlock::new(#address as *mut u8) }
+                    }
+                }
 
+                #feature_attribute
+                impl core::ops::Deref for #p_ty {
+                    type Target = #base::RegisterBlock;
+
+                    #[inline(always)]
+                    fn deref(&self) -> &Self::Target {
+                        &self.rb
+                    }
+                }
+            }
+        } else {
+            quote! {
+                #[doc = #doc]
+                #phtml
+                #doc_alias
+                #feature_attribute
+                pub type #p_ty = crate::Periph<#base::RegisterBlock, #address>;
+            }
+        });
+        out.extend(quote! {
             #feature_attribute
             impl core::fmt::Debug for #p_ty {
                 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
@@ -587,6 +631,18 @@ fn register_or_cluster_block(
         Ident::new("RegisterBlock", span)
     };
 
+    if config.raw_access {
+        accessors.extend(quote! {
+            pub(crate) const fn new(ptr: *mut u8) -> Self {
+                Self { ptr }
+            }
+            #[inline(always)]
+            pub const fn ptr(&self) -> *mut u8 {
+                self.ptr
+            }
+        })
+    }
+
     let accessors = (!accessors.is_empty()).then(|| {
         quote! {
             impl #block_ty {
@@ -595,16 +651,31 @@ fn register_or_cluster_block(
         }
     });
 
-    Ok(quote! {
-        #[repr(C)]
-        #derive_debug
-        #[doc = #doc]
-        #doc_alias
-        pub struct #block_ty {
-            #rbfs
+    Ok(if config.raw_access {
+        quote! {
+            #[doc = #doc]
+            #[repr(C)]
+            #derive_debug
+            #doc_alias
+            #[non_exhaustive]
+            pub struct #block_ty {
+                ptr: *mut u8,
+            }
+
+            #accessors
         }
+    } else {
+        quote! {
+            #[doc = #doc]
+            #[repr(C)]
+            #derive_debug
+            #doc_alias
+            pub struct #block_ty {
+                #rbfs
+            }
 
-        #accessors
+            #accessors
+        }
     })
 }
 
@@ -947,7 +1018,7 @@ fn expand_cluster(cluster: &Cluster, config: &Config) -> Result<Vec<RegisterBloc
                 ty,
                 offset: info.address_offset,
             })
-            .raw_if(false);
+            .ptr_or_rawref_if(config.raw_access, false);
             cluster_expanded.push(RegisterBlockField {
                 syn_field,
                 offset: info.address_offset,
@@ -1013,7 +1084,7 @@ fn expand_cluster(cluster: &Cluster, config: &Config) -> Result<Vec<RegisterBloc
                         increment: array_info.dim_increment,
                         note,
                     })
-                    .raw_if(!array_convertible),
+                    .ptr_or_rawref_if(config.raw_access, !array_convertible),
                 );
                 if !sequential_indexes_from0 || !ends_with_index {
                     for (i, ci) in svd::cluster::expand(info, array_info).enumerate() {
@@ -1031,7 +1102,7 @@ fn expand_cluster(cluster: &Cluster, config: &Config) -> Result<Vec<RegisterBloc
                                 basename: accessor_name.clone(),
                                 i,
                             })
-                            .raw_if(false),
+                            .ptr_or_rawref_if(config.raw_access, false),
                         );
                     }
                 }
@@ -1067,7 +1138,7 @@ fn expand_cluster(cluster: &Cluster, config: &Config) -> Result<Vec<RegisterBloc
                         ty: ty.clone(),
                         offset: info.address_offset,
                     })
-                    .raw_if(false);
+                    .ptr_or_rawref_if(config.raw_access, false);
                     cluster_expanded.push(RegisterBlockField {
                         syn_field,
                         offset: ci.address_offset,
@@ -1119,7 +1190,7 @@ fn expand_register(
                 ty,
                 offset: info.address_offset,
             })
-            .raw_if(false);
+            .ptr_or_rawref_if(config.raw_access, false);
             register_expanded.push(RegisterBlockField {
                 syn_field,
                 offset: info.address_offset,
@@ -1200,7 +1271,7 @@ fn expand_register(
                         increment: array_info.dim_increment,
                         note,
                     })
-                    .raw_if(!array_convertible),
+                    .ptr_or_rawref_if(config.raw_access, !array_convertible),
                 );
                 if !sequential_indexes_from0 || !ends_with_index {
                     for (i, ri) in svd::register::expand(info, array_info).enumerate() {
@@ -1223,7 +1294,7 @@ fn expand_register(
                                 basename: accessor_name.clone(),
                                 i,
                             })
-                            .raw_if(false),
+                            .ptr_or_rawref_if(config.raw_access, false),
                         );
                     }
                 };
@@ -1259,7 +1330,7 @@ fn expand_register(
                         ty: ty.clone(),
                         offset: info.address_offset,
                     })
-                    .raw_if(false);
+                    .ptr_or_rawref_if(config.raw_access, false);
                     register_expanded.push(RegisterBlockField {
                         syn_field,
                         offset: ri.address_offset,
diff --git a/src/generate/peripheral/accessor.rs b/src/generate/peripheral/accessor.rs
index 5bb91718..b786c33b 100644
--- a/src/generate/peripheral/accessor.rs
+++ b/src/generate/peripheral/accessor.rs
@@ -14,11 +14,14 @@ pub enum Accessor {
 pub enum AccessType {
     Ref(Accessor),
     RawRef(Accessor),
+    Ptr(Accessor),
 }
 
 impl Accessor {
-    pub fn raw_if(self, flag: bool) -> AccessType {
-        if flag {
+    pub fn ptr_or_rawref_if(self, ptr_flag: bool, raw_flag: bool) -> AccessType {
+        if ptr_flag {
+            AccessType::Ptr(self)
+        } else if raw_flag {
             AccessType::RawRef(self)
         } else {
             AccessType::Ref(self)
@@ -29,7 +32,7 @@ impl Accessor {
 impl AccessType {
     pub fn raw(self) -> Self {
         match self {
-            Self::RawRef(_) => self,
+            Self::RawRef(_) | Self::Ptr(_) => self,
             Self::Ref(a) => Self::RawRef(a),
         }
     }
@@ -62,6 +65,21 @@ impl ToTokens for AccessType {
                     }
                 }
             }
+            Self::Ptr(Accessor::Reg(RegAccessor {
+                doc,
+                name,
+                ty,
+                offset,
+            })) => {
+                let offset = (*offset != 0).then(|| unsuffixed(*offset)).map(|o| quote!(.add(#o)));
+                quote! {
+                    #[doc = #doc]
+                    #[inline(always)]
+                    pub const fn #name(&self) -> #ty {
+                        #ty::new(unsafe { self.ptr() #offset })
+                    }
+                }
+            }
             Self::Ref(Accessor::Array(ArrayAccessor { doc, name, ty, note, .. })) => {
                 let name_iter = Ident::new(&format!("{name}_iter"), Span::call_site());
                 let note = note.as_ref().map(|note| quote! {
@@ -118,6 +136,41 @@ impl ToTokens for AccessType {
                     }
                 }
             }
+            Self::Ptr(Accessor::Array(ArrayAccessor {
+                doc,
+                name,
+                ty,
+                offset,
+                dim,
+                increment,
+                note,
+            })) => {
+                let name_iter = Ident::new(&format!("{name}_iter"), Span::call_site());
+                let offset = (*offset != 0).then(|| unsuffixed(*offset)).map(|o| quote!(.add(#o)));
+                let dim = unsuffixed(*dim);
+                let increment = (*increment != 1).then(|| unsuffixed(*increment)).map(|i| quote!(#i *));
+                let note = note.as_ref().map(|note| quote! {
+                    #[doc = ""]
+                    #[doc = #note]
+                });
+                let cast = quote! { #ty::new(unsafe { self.ptr() #offset .add(#increment n) }) };
+                quote! {
+                    #[doc = #doc]
+                    #note
+                    #[inline(always)]
+                    pub const fn #name(&self, n: usize) -> #ty {
+                        #[allow(clippy::no_effect)]
+                        [(); #dim][n];
+                        #cast
+                    }
+                    #[doc = "Iterator for array of:"]
+                    #[doc = #doc]
+                    #[inline(always)]
+                    pub fn #name_iter(&self) -> impl Iterator<Item=#ty> + '_ {
+                        (0..#dim).map(move |n| #cast)
+                    }
+                }
+            }
             Self::RawRef(Accessor::ArrayElem(elem)) | Self::Ref(Accessor::ArrayElem(elem)) => {
                 let ArrayElemAccessor {
                     doc,
@@ -135,6 +188,21 @@ impl ToTokens for AccessType {
                     }
                 }
             }
+            Self::Ptr(Accessor::ArrayElem(ArrayElemAccessor {
+                    doc,
+                    name,
+                    ty,
+                    basename,
+                    i,
+                })) => {
+                quote! {
+                    #[doc = #doc]
+                    #[inline(always)]
+                    pub const fn #name(&self) -> #ty {
+                        self.#basename(#i)
+                    }
+                }
+            }
         }
         .to_tokens(tokens);
     }
diff --git a/src/main.rs b/src/main.rs
index d3efbeba..bb93ae84 100755
--- a/src/main.rs
+++ b/src/main.rs
@@ -251,6 +251,13 @@ Allowed cases are `unchanged` (''), `pascal` ('p'), `constant` ('c') and `snake`
                 .alias("source_type")
                 .help("Specify file/stream format"),
         )
+        .arg(
+            Arg::new("raw_access")
+                .long("raw-access")
+                .alias("raw_access")
+                .action(ArgAction::SetTrue)
+                .help("Always access to registers by address"),
+        )
         .arg(
             Arg::new("reexport_core_peripherals")
                 .long("reexport-core-peripherals")