From 7746f55e6f3e84a8a31e632865f30cefcff3160d Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Thu, 16 May 2024 09:50:36 +0300 Subject: [PATCH] raw_read_write --- CHANGELOG.md | 2 + src/config.rs | 1 + src/generate/device.rs | 7 ++ src/generate/generic.rs | 172 ------------------------------ src/generate/generic_reg_raw.rs | 169 +++++++++++++++++++++++++++++ src/generate/generic_reg_vcell.rs | 171 +++++++++++++++++++++++++++++ src/main.rs | 6 ++ 7 files changed, 356 insertions(+), 172 deletions(-) create mode 100644 src/generate/generic_reg_raw.rs create mode 100644 src/generate/generic_reg_vcell.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index abf6b827..48b263f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] +- Add `raw-access` and `raw-read-write` options + - Yet more clean field & register `Debug` ## [v0.33.2] - 2024-05-07 diff --git a/src/config.rs b/src/config.rs index 97f46dc8..57c11798 100644 --- a/src/config.rs +++ b/src/config.rs @@ -36,6 +36,7 @@ pub struct Config { pub field_names_for_enums: bool, pub base_address_shift: u64, pub raw_access: bool, + pub raw_read_write: bool, } #[allow(clippy::upper_case_acronyms)] diff --git a/src/generate/device.rs b/src/generate/device.rs index 25d6bdd2..0f36bbf4 100644 --- a/src/generate/device.rs +++ b/src/generate/device.rs @@ -140,6 +140,11 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result Result Result { - register: vcell::VolatileCell, - _marker: marker::PhantomData, -} - -unsafe impl Send for Reg where REG::Ux: Send {} - -impl Reg { - /// Returns the underlying memory address of register. - /// - /// ```ignore - /// let reg_ptr = periph.reg.as_ptr(); - /// ``` - #[inline(always)] - pub fn as_ptr(&self) -> *mut REG::Ux { - self.register.as_ptr() - } -} - -impl 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 fn read(&self) -> R { - R { - bits: self.register.get(), - _reg: marker::PhantomData, - } - } -} - -impl Reg { - /// Writes the reset value to `Writable` register. - /// - /// Resets the register to its initial state. - #[inline(always)] - pub fn reset(&self) { - self.register.set(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 fn write(&self, f: F) - where - F: FnOnce(&mut W) -> &mut W, - { - self.register.set( - f(&mut W { - bits: REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP - | REG::ZERO_TO_MODIFY_FIELDS_BITMAP, - _reg: marker::PhantomData, - }) - .bits, - ); - } -} - -impl 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(&self, f: F) - where - F: FnOnce(&mut W) -> &mut W, - { - self.register.set( - f(&mut W { - bits: REG::Ux::default(), - _reg: marker::PhantomData, - }) - .bits, - ); - } -} - -impl 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 fn modify(&self, f: F) - where - for<'w> F: FnOnce(&R, &'w mut W) -> &'w mut W, - { - let bits = self.register.get(); - self.register.set( - 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, - ); - } -} - -impl core::fmt::Debug for crate::generic::Reg -where - R: core::fmt::Debug -{ - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - core::fmt::Debug::fmt(&self.read(), f) - } -} - #[doc(hidden)] pub mod raw { use super::{marker, BitM, FieldSpec, RegisterSpec, Unsafe, Writable}; diff --git a/src/generate/generic_reg_raw.rs b/src/generate/generic_reg_raw.rs new file mode 100644 index 00000000..d1c0a267 --- /dev/null +++ b/src/generate/generic_reg_raw.rs @@ -0,0 +1,169 @@ +/// This structure provides unsafe volatile access to registers. +pub struct Reg { + _marker: marker::PhantomData, +} + +unsafe impl Send for Reg where REG::Ux: Send {} + +impl Reg { + /// Returns the underlying memory address of register. + /// + /// ```ignore + /// let reg_ptr = periph.reg.as_ptr(); + /// ``` + #[inline(always)] + pub fn as_ptr(&self) -> *mut REG::Ux { + (self as *const Self).cast_mut().cast() + } +} + +impl 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 { + R { + bits: self.as_ptr().read_volatile(), + _reg: marker::PhantomData, + } + } +} + +impl 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(&self, f: F) + where + F: FnOnce(&mut W) -> &mut W, + { + self.as_ptr().write_volatile( + f(&mut W { + bits: REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP + | REG::ZERO_TO_MODIFY_FIELDS_BITMAP, + _reg: marker::PhantomData, + }) + .bits, + ); + } +} + +impl 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(&self, f: F) + where + F: FnOnce(&mut W) -> &mut W, + { + self.as_ptr().write_volatile( + f(&mut W { + bits: REG::Ux::default(), + _reg: marker::PhantomData, + }) + .bits, + ); + } +} + +impl 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(&self, f: F) + where + for<'w> F: FnOnce(&R, &'w mut W) -> &'w mut W, + { + let bits = self.as_ptr().read_volatile(); + self.as_ptr().write_volatile( + 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, + ); + } +} + +impl core::fmt::Debug for crate::generic::Reg +where + R: 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 new file mode 100644 index 00000000..5081ae20 --- /dev/null +++ b/src/generate/generic_reg_vcell.rs @@ -0,0 +1,171 @@ +/// This structure provides volatile access to registers. +#[repr(transparent)] +pub struct Reg { + register: vcell::VolatileCell, + _marker: marker::PhantomData, +} + +unsafe impl Send for Reg where REG::Ux: Send {} + +impl Reg { + /// Returns the underlying memory address of register. + /// + /// ```ignore + /// let reg_ptr = periph.reg.as_ptr(); + /// ``` + #[inline(always)] + pub fn as_ptr(&self) -> *mut REG::Ux { + self.register.as_ptr() + } +} + +impl 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 fn read(&self) -> R { + R { + bits: self.register.get(), + _reg: marker::PhantomData, + } + } +} + +impl Reg { + /// Writes the reset value to `Writable` register. + /// + /// Resets the register to its initial state. + #[inline(always)] + pub fn reset(&self) { + self.register.set(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 fn write(&self, f: F) + where + F: FnOnce(&mut W) -> &mut W, + { + self.register.set( + f(&mut W { + bits: REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP + | REG::ZERO_TO_MODIFY_FIELDS_BITMAP, + _reg: marker::PhantomData, + }) + .bits, + ); + } +} + +impl 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(&self, f: F) + where + F: FnOnce(&mut W) -> &mut W, + { + self.register.set( + f(&mut W { + bits: REG::Ux::default(), + _reg: marker::PhantomData, + }) + .bits, + ); + } +} + +impl 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 fn modify(&self, f: F) + where + for<'w> F: FnOnce(&R, &'w mut W) -> &'w mut W, + { + let bits = self.register.get(); + self.register.set( + 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, + ); + } +} + +impl core::fmt::Debug for crate::generic::Reg +where + R: core::fmt::Debug +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Debug::fmt(&self.read(), f) + } +} diff --git a/src/main.rs b/src/main.rs index 1fc7de18..46d90dc0 100755 --- a/src/main.rs +++ b/src/main.rs @@ -248,6 +248,12 @@ Allowed cases are `unchanged` (''), `pascal` ('p'), `constant` ('c') and `snake` .alias("raw_access") .help("Always access to registers by address"), ) + .arg( + Arg::new("raw_read_write") + .long("raw-read-write") + .alias("raw_read_write") + .help("Read/Write/Modify registers without vcell"), + ) .arg( Arg::new("reexport_core_peripherals") .long("reexport-core-peripherals")