From 3f8fb8a30d3fc93bbc882760c4c32c9b5ae6becf Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Tue, 11 Mar 2025 08:53:28 +0300 Subject: [PATCH 1/2] Associated Reader/Writer --- src/generate/generic.rs | 66 +++++++++++++++---- src/generate/generic_atomic.rs | 24 ++----- src/generate/generic_reg_vcell.rs | 103 +++++++++++++----------------- src/generate/register.rs | 5 +- 4 files changed, 107 insertions(+), 91 deletions(-) diff --git a/src/generate/generic.rs b/src/generate/generic.rs index e527a4a8..6884ff71 100644 --- a/src/generate/generic.rs +++ b/src/generate/generic.rs @@ -104,10 +104,23 @@ pub trait FieldSpec: Sized { /// Marker for fields with fixed values pub trait IsEnum: FieldSpec {} +#[doc(hidden)] +pub trait FromBits { + unsafe fn from_bits(b: U) -> Self; +} + +#[doc(hidden)] +pub trait ToBits { + fn to_bits(&self) -> U; +} + /// Trait implemented by readable registers to enable the `read` method. /// /// Registers marked with `Writable` can be also be `modify`'ed. -pub trait Readable: RegisterSpec {} +pub trait Readable: RegisterSpec { + /// Reader struct associated with register + type Reader: FromBits; +} /// Trait implemented by writeable registers. /// @@ -115,6 +128,9 @@ pub trait Readable: RegisterSpec {} /// /// Registers marked with `Readable` can be also be `modify`'ed. pub trait Writable: RegisterSpec { + /// Writer struct associated with register + type Writer: FromBits + ToBits; + /// Is it safe to write any bits to register type Safety; @@ -140,21 +156,56 @@ pub trait Resettable: RegisterSpec { } } +/// Marker for register/field writers which can take any value of specified width +pub struct Safe; +/// You should check that value is allowed to pass to register/field writer marked with this +pub struct Unsafe; +/// Marker for field writers are safe to write in specified inclusive range +pub struct Range; +/// Marker for field writers are safe to write in specified inclusive range +pub struct RangeFrom; +/// Marker for field writers are safe to write in specified inclusive range +pub struct RangeTo; + #[doc(hidden)] pub mod raw { - use super::{marker, BitM, FieldSpec, RegisterSpec, Unsafe, Writable}; + use super::{marker, BitM, FieldSpec, FromBits, RegisterSpec, ToBits, Unsafe, Writable}; pub struct R { pub(crate) bits: REG::Ux, pub(super) _reg: marker::PhantomData, } + impl FromBits for R { + unsafe fn from_bits(bits: REG::Ux) -> Self { + Self { + bits, + _reg: marker::PhantomData, + } + } + } + pub struct W { ///Writable bits pub(crate) bits: REG::Ux, pub(super) _reg: marker::PhantomData, } + impl FromBits for W { + unsafe fn from_bits(bits: REG::Ux) -> Self { + Self { + bits, + _reg: marker::PhantomData, + } + } + } + + impl ToBits for W { + fn to_bits(&self) -> REG::Ux { + self.bits + } + } + pub struct FieldReader where FI: FieldSpec, @@ -371,17 +422,6 @@ impl core::fmt::Debug for BitReader { } } -/// Marker for register/field writers which can take any value of specified width -pub struct Safe; -/// You should check that value is allowed to pass to register/field writer marked with this -pub struct Unsafe; -/// Marker for field writers are safe to write in specified inclusive range -pub struct Range; -/// Marker for field writers are safe to write in specified inclusive range -pub struct RangeFrom; -/// Marker for field writers are safe to write in specified inclusive range -pub struct RangeTo; - /// Write field Proxy pub type FieldWriter<'a, REG, const WI: u8, FI = u8, Safety = Unsafe> = raw::FieldWriter<'a, REG, WI, FI, Safety>; diff --git a/src/generate/generic_atomic.rs b/src/generate/generic_atomic.rs index 55250961..964c95b5 100644 --- a/src/generate/generic_atomic.rs +++ b/src/generate/generic_atomic.rs @@ -50,13 +50,9 @@ mod atomic { #[inline(always)] pub unsafe fn set_bits(&self, f: F) where - F: FnOnce(&mut W) -> &mut W, + F: FnOnce(&mut REG::Writer) -> &mut REG::Writer, { - let bits = f(&mut W { - bits: REG::Ux::ZERO, - _reg: marker::PhantomData, - }) - .bits; + let bits = f(&mut REG::Writer::from_bits(REG::Ux::ZERO)).to_bits(); REG::Ux::atomic_or(self.register.as_ptr(), bits); } @@ -69,13 +65,9 @@ mod atomic { #[inline(always)] pub unsafe fn clear_bits(&self, f: F) where - F: FnOnce(&mut W) -> &mut W, + F: FnOnce(&mut REG::Writer) -> &mut REG::Writer, { - let bits = f(&mut W { - bits: !REG::Ux::ZERO, - _reg: marker::PhantomData, - }) - .bits; + let bits = f(&mut REG::Writer::from_bits(!REG::Ux::ZERO)).to_bits(); REG::Ux::atomic_and(self.register.as_ptr(), bits); } @@ -88,13 +80,9 @@ mod atomic { #[inline(always)] pub unsafe fn toggle_bits(&self, f: F) where - F: FnOnce(&mut W) -> &mut W, + F: FnOnce(&mut REG::Writer) -> &mut REG::Writer, { - let bits = f(&mut W { - bits: REG::Ux::ZERO, - _reg: marker::PhantomData, - }) - .bits; + let bits = f(&mut REG::Writer::from_bits(REG::Ux::ZERO)).to_bits(); REG::Ux::atomic_xor(self.register.as_ptr(), bits); } } diff --git a/src/generate/generic_reg_vcell.rs b/src/generate/generic_reg_vcell.rs index 9e436334..09674ab5 100644 --- a/src/generate/generic_reg_vcell.rs +++ b/src/generate/generic_reg_vcell.rs @@ -33,11 +33,8 @@ impl Reg { /// let flag = reader.field2().bit_is_set(); /// ``` #[inline(always)] - pub fn read(&self) -> R { - R { - bits: self.register.get(), - _reg: marker::PhantomData, - } + pub fn read(&self) -> REG::Reader { + unsafe { REG::Reader::from_bits(self.register.get()) } } } @@ -76,14 +73,15 @@ impl Reg { #[inline(always)] pub fn write(&self, f: F) -> REG::Ux where - F: FnOnce(&mut W) -> &mut W, + F: FnOnce(&mut REG::Writer) -> &mut REG::Writer, { - 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; + let value = unsafe { + f(&mut REG::Writer::from_bits( + REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP + | REG::ZERO_TO_MODIFY_FIELDS_BITMAP, + )) + .to_bits() + }; self.register.set(value); value } @@ -119,16 +117,17 @@ impl Reg { #[inline(always)] pub fn from_write(&self, f: F) -> T where - F: FnOnce(&mut W) -> T, + F: FnOnce(&mut REG::Writer) -> 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 mut writer = unsafe { + REG::Writer::from_bits( + REG::RESET_VALUE & !REG::ONE_TO_MODIFY_FIELDS_BITMAP + | REG::ZERO_TO_MODIFY_FIELDS_BITMAP, + ) }; let result = f(&mut writer); - self.register.set(writer.bits); + self.register.set(writer.to_bits()); result } @@ -145,13 +144,9 @@ impl Reg { #[inline(always)] pub unsafe fn write_with_zero(&self, f: F) -> REG::Ux where - F: FnOnce(&mut W) -> &mut W, + F: FnOnce(&mut REG::Writer) -> &mut REG::Writer, { - let value = f(&mut W { - bits: REG::Ux::ZERO, - _reg: marker::PhantomData, - }) - .bits; + let value = f(&mut REG::Writer::from_bits(REG::Ux::ZERO)).to_bits(); self.register.set(value); value } @@ -166,16 +161,13 @@ impl Reg { #[inline(always)] pub unsafe fn from_write_with_zero(&self, f: F) -> T where - F: FnOnce(&mut W) -> T, + F: FnOnce(&mut REG::Writer) -> T, { - let mut writer = W { - bits: REG::Ux::ZERO, - _reg: marker::PhantomData, - }; + let mut writer = REG::Writer::from_bits(REG::Ux::ZERO); let result = f(&mut writer); - self.register.set(writer.bits); + self.register.set(writer.to_bits()); result } @@ -210,20 +202,18 @@ impl Reg { #[inline(always)] pub fn modify(&self, f: F) -> REG::Ux where - for<'w> F: FnOnce(&R, &'w mut W) -> &'w mut W, + for<'w> F: FnOnce(®::Reader, &'w mut REG::Writer) -> &'w mut REG::Writer, { let bits = self.register.get(); - 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; + let value = unsafe { + f( + ®::Reader::from_bits(bits), + &mut REG::Writer::from_bits( + bits & !REG::ONE_TO_MODIFY_FIELDS_BITMAP | REG::ZERO_TO_MODIFY_FIELDS_BITMAP, + ), + ) + .to_bits() + }; self.register.set(value); value } @@ -262,32 +252,27 @@ impl Reg { #[inline(always)] pub fn from_modify(&self, f: F) -> T where - for<'w> F: FnOnce(&R, &'w mut W) -> T, + for<'w> F: FnOnce(®::Reader, &'w mut REG::Writer) -> T, { - let bits = self.register.get(); + unsafe { + let bits = self.register.get(); - let mut writer = W { - bits: bits & !REG::ONE_TO_MODIFY_FIELDS_BITMAP | REG::ZERO_TO_MODIFY_FIELDS_BITMAP, - _reg: marker::PhantomData, - }; + let mut writer = REG::Writer::from_bits( + bits & !REG::ONE_TO_MODIFY_FIELDS_BITMAP | REG::ZERO_TO_MODIFY_FIELDS_BITMAP, + ); - let result = f( - &R { - bits, - _reg: marker::PhantomData, - }, - &mut writer, - ); + let result = f(®::Reader::from_bits(bits), &mut writer); - self.register.set(writer.bits); + self.register.set(writer.to_bits()); - result + result + } } } -impl core::fmt::Debug for crate::generic::Reg +impl core::fmt::Debug for Reg where - R: core::fmt::Debug, + REG::Reader: 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/generate/register.rs b/src/generate/register.rs index c1cdc876..9fcd42cb 100644 --- a/src/generate/register.rs +++ b/src/generate/register.rs @@ -386,7 +386,9 @@ pub fn render_register_mod( let doc = format!("`read()` method returns [`{mod_ty}::R`](R) reader structure",); mod_items.extend(quote! { #[doc = #doc] - impl crate::Readable for #regspec_ty {} + impl crate::Readable for #regspec_ty { + type Reader = R; + } }); } if can_write { @@ -421,6 +423,7 @@ pub fn render_register_mod( mod_items.extend(quote! { #[doc = #doc] impl crate::Writable for #regspec_ty { + type Writer = W; type Safety = crate::#safe_ty; #zero_to_modify_fields_bitmap #one_to_modify_fields_bitmap From af6722167307fb4df0ab2ae1badfe2b8af63e418 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Thu, 13 Mar 2025 09:09:00 +0300 Subject: [PATCH 2/2] inline --- src/generate/generic.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/generate/generic.rs b/src/generate/generic.rs index 6884ff71..63edc080 100644 --- a/src/generate/generic.rs +++ b/src/generate/generic.rs @@ -177,6 +177,7 @@ pub mod raw { } impl FromBits for R { + #[inline(always)] unsafe fn from_bits(bits: REG::Ux) -> Self { Self { bits, @@ -192,6 +193,7 @@ pub mod raw { } impl FromBits for W { + #[inline(always)] unsafe fn from_bits(bits: REG::Ux) -> Self { Self { bits, @@ -201,6 +203,7 @@ pub mod raw { } impl ToBits for W { + #[inline(always)] fn to_bits(&self) -> REG::Ux { self.bits }