From 456ce21563fa289b726285d820cf6ea0b4d76dd3 Mon Sep 17 00:00:00 2001 From: Adin Ackerman Date: Tue, 22 Oct 2024 08:24:09 -0700 Subject: [PATCH 1/6] arbitrary return type for register modifiers --- src/generate/generic_reg_vcell.rs | 78 +++++++++++++++++-------------- 1 file changed, 43 insertions(+), 35 deletions(-) diff --git a/src/generate/generic_reg_vcell.rs b/src/generate/generic_reg_vcell.rs index 5081ae20..04289050 100644 --- a/src/generate/generic_reg_vcell.rs +++ b/src/generate/generic_reg_vcell.rs @@ -74,18 +74,20 @@ impl Reg { /// ``` /// In the latter case, other fields will be set to their reset value. #[inline(always)] - pub fn write(&self, f: F) + pub fn write(&self, f: F) -> T where - F: FnOnce(&mut W) -> &mut W, + F: FnOnce(&mut W) -> T, { - 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, - ); + 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.register.set(writer.bits); + + result } } @@ -98,17 +100,20 @@ impl Reg { /// /// Unsafe to use with registers which don't allow to write 0. #[inline(always)] - pub unsafe fn write_with_zero(&self, f: F) + pub unsafe fn write_with_zero(&self, f: F) -> T where - F: FnOnce(&mut W) -> &mut W, + F: FnOnce(&mut W) -> T, { - self.register.set( - f(&mut W { - bits: REG::Ux::default(), - _reg: marker::PhantomData, - }) - .bits, - ); + let mut writer = W { + bits: REG::Ux::default(), + _reg: marker::PhantomData, + }; + + let result = f(&mut writer); + + self.register.set(writer.bits); + + result } } @@ -139,31 +144,34 @@ impl Reg { /// ``` /// Other fields will have the value they had before the call to `modify`. #[inline(always)] - pub fn modify(&self, f: F) + pub fn modify(&self, f: F) -> T where - for<'w> F: FnOnce(&R, &'w mut W) -> &'w mut W, + for<'w> F: FnOnce(&R, &'w mut W) -> T, { 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, + + 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.register.set(writer.bits); + + result } } impl core::fmt::Debug for crate::generic::Reg where - R: core::fmt::Debug + R: core::fmt::Debug, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { core::fmt::Debug::fmt(&self.read(), f) From 294e211054b3150c42a2abd97b7962d6354dce45 Mon Sep 17 00:00:00 2001 From: Adin Ackerman Date: Tue, 22 Oct 2024 08:35:47 -0700 Subject: [PATCH 2/6] Revert "arbitrary return type for register modifiers" This reverts commit 456ce21563fa289b726285d820cf6ea0b4d76dd3. --- src/generate/generic_reg_vcell.rs | 78 ++++++++++++++----------------- 1 file changed, 35 insertions(+), 43 deletions(-) diff --git a/src/generate/generic_reg_vcell.rs b/src/generate/generic_reg_vcell.rs index 04289050..5081ae20 100644 --- a/src/generate/generic_reg_vcell.rs +++ b/src/generate/generic_reg_vcell.rs @@ -74,20 +74,18 @@ impl Reg { /// ``` /// In the latter case, other fields will be set to their reset value. #[inline(always)] - pub fn write(&self, f: F) -> T + pub fn write(&self, f: F) where - F: FnOnce(&mut W) -> T, + F: FnOnce(&mut W) -> &mut W, { - 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.register.set(writer.bits); - - result + 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, + ); } } @@ -100,20 +98,17 @@ impl Reg { /// /// Unsafe to use with registers which don't allow to write 0. #[inline(always)] - pub unsafe fn write_with_zero(&self, f: F) -> T + pub unsafe fn write_with_zero(&self, f: F) where - F: FnOnce(&mut W) -> T, + F: FnOnce(&mut W) -> &mut W, { - let mut writer = W { - bits: REG::Ux::default(), - _reg: marker::PhantomData, - }; - - let result = f(&mut writer); - - self.register.set(writer.bits); - - result + self.register.set( + f(&mut W { + bits: REG::Ux::default(), + _reg: marker::PhantomData, + }) + .bits, + ); } } @@ -144,34 +139,31 @@ impl Reg { /// ``` /// Other fields will have the value they had before the call to `modify`. #[inline(always)] - pub fn modify(&self, f: F) -> T + pub fn modify(&self, f: F) where - for<'w> F: FnOnce(&R, &'w mut W) -> T, + for<'w> F: FnOnce(&R, &'w mut W) -> &'w mut W, { 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 result = f( - &R { - bits, - _reg: marker::PhantomData, - }, - &mut writer, + 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, ); - - self.register.set(writer.bits); - - result } } impl core::fmt::Debug for crate::generic::Reg where - R: core::fmt::Debug, + R: core::fmt::Debug { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { core::fmt::Debug::fmt(&self.read(), f) From 6cd9ead15fef820c1f03cce307c8f90c7c89246c Mon Sep 17 00:00:00 2001 From: Adin Ackerman Date: Tue, 22 Oct 2024 08:45:11 -0700 Subject: [PATCH 3/6] add `write_and`, `write_with_zero_and`, and `modify_and` --- src/generate/generic_reg_vcell.rs | 127 +++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 1 deletion(-) diff --git a/src/generate/generic_reg_vcell.rs b/src/generate/generic_reg_vcell.rs index 5081ae20..dc6445f0 100644 --- a/src/generate/generic_reg_vcell.rs +++ b/src/generate/generic_reg_vcell.rs @@ -87,6 +87,51 @@ impl Reg { .bits, ); } + + /// 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 fn write_and(&self, f: F) -> T + where + F: FnOnce(&mut W) -> 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.register.set(writer.bits); + + result + } } impl Reg { @@ -110,6 +155,30 @@ impl Reg { .bits, ); } + + /// 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 write_with_zero(&self, f: F) -> T + where + F: FnOnce(&mut W) -> T, + { + let mut writer = W { + bits: REG::Ux::default(), + _reg: marker::PhantomData, + }; + + let result = f(&mut writer); + + self.register.set(writer.bits); + + result + } } impl Reg { @@ -159,11 +228,67 @@ impl Reg { .bits, ); } + + /// 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 fn modify_and(&self, f: F) -> T + where + for<'w> F: FnOnce(&R, &'w mut W) -> T, + { + 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 result = f( + &R { + bits, + _reg: marker::PhantomData, + }, + &mut writer, + ); + + self.register.set(writer.bits); + + result + } } impl core::fmt::Debug for crate::generic::Reg where - R: core::fmt::Debug + R: core::fmt::Debug, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { core::fmt::Debug::fmt(&self.read(), f) From d0739ece626f32f8b70390715720398580d29c97 Mon Sep 17 00:00:00 2001 From: Adin Ackerman Date: Tue, 22 Oct 2024 08:53:05 -0700 Subject: [PATCH 4/6] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25439d50..13974e2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/). - Skip generating `.add(0)` and `1 *` in accessors - Bump MSRV of generated code to 1.76 - move `must_use` from methods to generic type +- Add `write_and`, `write_with_zero_and`, and `modify_and` register modifiers ## [v0.33.5] - 2024-10-12 From 8b2cab5c1c4966d8f571ac4579b003293ff0d9c0 Mon Sep 17 00:00:00 2001 From: Adin Ackerman Date: Tue, 22 Oct 2024 08:59:30 -0700 Subject: [PATCH 5/6] fix typo --- src/generate/generic_reg_vcell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generate/generic_reg_vcell.rs b/src/generate/generic_reg_vcell.rs index dc6445f0..36148635 100644 --- a/src/generate/generic_reg_vcell.rs +++ b/src/generate/generic_reg_vcell.rs @@ -164,7 +164,7 @@ impl Reg { /// /// Unsafe to use with registers which don't allow to write 0. #[inline(always)] - pub unsafe fn write_with_zero(&self, f: F) -> T + pub unsafe fn write_with_zero_and(&self, f: F) -> T where F: FnOnce(&mut W) -> T, { From 69f2444886a8dde437909dcba953a89f8a802441 Mon Sep 17 00:00:00 2001 From: Adin Ackerman Date: Tue, 22 Oct 2024 12:33:33 -0700 Subject: [PATCH 6/6] change names --- src/generate/generic_reg_vcell.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/generate/generic_reg_vcell.rs b/src/generate/generic_reg_vcell.rs index 36148635..585c6e0c 100644 --- a/src/generate/generic_reg_vcell.rs +++ b/src/generate/generic_reg_vcell.rs @@ -117,7 +117,7 @@ impl Reg { /// let state = periph.reg.write_and(|w| State::set(w.field1())); /// ``` #[inline(always)] - pub fn write_and(&self, f: F) -> T + pub fn from_write(&self, f: F) -> T where F: FnOnce(&mut W) -> T, { @@ -164,7 +164,7 @@ impl Reg { /// /// Unsafe to use with registers which don't allow to write 0. #[inline(always)] - pub unsafe fn write_with_zero_and(&self, f: F) -> T + pub unsafe fn from_write_with_zero(&self, f: F) -> T where F: FnOnce(&mut W) -> T, { @@ -261,7 +261,7 @@ impl Reg { /// ``` /// Other fields will have the value they had before the call to `modify`. #[inline(always)] - pub fn modify_and(&self, f: F) -> T + pub fn from_modify(&self, f: F) -> T where for<'w> F: FnOnce(&R, &'w mut W) -> T, {