diff --git a/CHANGELOG.md b/CHANGELOG.md index f365da9d..503ac041 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] +- Move `Reg` in separate file - Use `warning` class in docs - Refactor `Accessor` diff --git a/src/generate/device.rs b/src/generate/device.rs index 25d6bdd2..dd601ada 100644 --- a/src/generate/device.rs +++ b/src/generate/device.rs @@ -140,6 +140,7 @@ 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_atomic_file = include_str!("generic_atomic.rs"); if config.generic_mod { let mut file = File::create( @@ -150,6 +151,7 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke .join("generic.rs"), )?; writeln!(file, "{generic_file}")?; + writeln!(file, "{generic_reg_file}")?; if config.atomics { if let Some(atomics_feature) = config.atomics_feature.as_ref() { writeln!(file, "#[cfg(feature = \"{atomics_feature}\")]")?; @@ -167,6 +169,7 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke } } else { let mut tokens = syn::parse_file(generic_file)?.into_token_stream(); + syn::parse_file(generic_reg_file)?.to_tokens(&mut tokens); if config.atomics { if let Some(atomics_feature) = config.atomics_feature.as_ref() { quote!(#[cfg(feature = #atomics_feature)]).to_tokens(&mut tokens); @@ -246,9 +249,7 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke #feature_attribute pub #p_singleton: #p_ty, }); - exprs.extend( - quote!(#feature_attribute #p_singleton: #p_ty { _marker: PhantomData },), - ); + exprs.extend(quote!(#feature_attribute #p_singleton: #p_ty::steal(),)); } Peripheral::Array(p, dim_element) => { for p_name in names(p, dim_element) { @@ -263,9 +264,7 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke #feature_attribute pub #p_singleton: #p_ty, }); - exprs.extend( - quote!(#feature_attribute #p_singleton: #p_ty { _marker: PhantomData },), - ); + exprs.extend(quote!(#feature_attribute #p_singleton: #p_ty::steal(),)); } } } diff --git a/src/generate/generic.rs b/src/generate/generic.rs index 6921b5ab..2f8d6f7b 100644 --- a/src/generate/generic.rs +++ b/src/generate/generic.rs @@ -95,178 +95,6 @@ pub trait Resettable: RegisterSpec { } } -/// This structure provides volatile access to registers. -#[repr(transparent)] -pub struct Reg<REG: RegisterSpec> { - register: vcell::VolatileCell<REG::Ux>, - _marker: marker::PhantomData<REG>, -} - -unsafe impl<REG: RegisterSpec> Send for Reg<REG> where REG::Ux: Send {} - -impl<REG: RegisterSpec> Reg<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: 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 fn read(&self) -> R<REG> { - R { - bits: self.register.get(), - _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 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<F>(&self, f: F) - where - F: FnOnce(&mut W<REG>) -> &mut W<REG>, - { - 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: 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) - where - F: FnOnce(&mut W<REG>) -> &mut W<REG>, - { - self.register.set( - f(&mut W { - bits: REG::Ux::default(), - _reg: marker::PhantomData, - }) - .bits, - ); - } -} - -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 fn modify<F>(&self, f: F) - where - for<'w> F: FnOnce(&R<REG>, &'w mut W<REG>) -> &'w mut W<REG>, - { - 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<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 { - 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_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<REG: RegisterSpec> { + register: vcell::VolatileCell<REG::Ux>, + _marker: marker::PhantomData<REG>, +} + +unsafe impl<REG: RegisterSpec> Send for Reg<REG> where REG::Ux: Send {} + +impl<REG: RegisterSpec> Reg<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: 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 fn read(&self) -> R<REG> { + R { + bits: self.register.get(), + _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 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<F>(&self, f: F) + where + F: FnOnce(&mut W<REG>) -> &mut W<REG>, + { + 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: 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) + where + F: FnOnce(&mut W<REG>) -> &mut W<REG>, + { + self.register.set( + f(&mut W { + bits: REG::Ux::default(), + _reg: marker::PhantomData, + }) + .bits, + ); + } +} + +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 fn modify<F>(&self, f: F) + where + for<'w> F: FnOnce(&R<REG>, &'w mut W<REG>) -> &'w mut W<REG>, + { + 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<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 { + core::fmt::Debug::fmt(&self.read(), f) + } +}