From c2420ca19ca14f85e73fd64d6ce370356a13d7bd Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 23 Dec 2023 14:18:38 +0300 Subject: [PATCH] generic safe/unsafe W::bits --- CHANGELOG.md | 1 + src/generate/generic.rs | 28 ++++++++++++++++++-- src/generate/register.rs | 57 +++++++++++++--------------------------- 3 files changed, 45 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b49cd3d4..60eb6221 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - Bump MSRV to 1.74 +- generic unsafe `W::bits` + safe `W::set` - Add `base-address-shift` config flag - Fix case changing bugs, add `--ident-format` (`-f`) option flag diff --git a/src/generate/generic.rs b/src/generate/generic.rs index 186d3364..1932f97a 100644 --- a/src/generate/generic.rs +++ b/src/generate/generic.rs @@ -67,6 +67,9 @@ pub trait Readable: RegisterSpec {} /// /// Registers marked with `Readable` can be also be `modify`'ed. pub trait Writable: RegisterSpec { + /// Is it safe to write any bits to register + type Safety; + /// Specifies the register bits that are not changed if you pass `1` and are changed if you pass `0` const ZERO_TO_MODIFY_FIELDS_BITMAP: Self::Ux; @@ -390,6 +393,27 @@ where /// Used as an argument to the closures in the `write` and `modify` methods of the register. pub type W = raw::W; +impl W { + /// Writes raw bits to the register. + /// + /// # Safety + /// + /// Passing incorrect value can cause undefined behaviour. See reference manual + #[inline(always)] + pub unsafe fn bits(&mut self, bits: REG::Ux) -> &mut Self { + self.bits = bits; + self + } +} +impl W where REG: Writable { + /// Writes raw bits to the register. + #[inline(always)] + pub fn set(&mut self, bits: REG::Ux) -> &mut Self { + self.bits = bits; + self + } +} + /// Field reader. /// /// Result of the `read` methods of fields. @@ -445,9 +469,9 @@ impl BitReader { } } -#[doc(hidden)] +/// Marker for register/field writers which can take any value of specified width pub struct Safe; -#[doc(hidden)] +/// You should check that value is allowed to pass to register/field writer marked with this pub struct Unsafe; /// Write field Proxy with unsafe `bits` diff --git a/src/generate/register.rs b/src/generate/register.rs index 5b75711d..9bfddf30 100644 --- a/src/generate/register.rs +++ b/src/generate/register.rs @@ -26,7 +26,7 @@ fn regspec(name: &str, config: &Config, span: Span) -> Ident { } fn field_accessor(name: &str, config: &Config, span: Span) -> Ident { - const INTERNALS: [&str; 1] = ["bits"]; + const INTERNALS: [&str; 2] = ["bits", "set"]; let sc = config .ident_formats .get("field_accessor") @@ -355,44 +355,6 @@ pub fn render_register_mod( mod_items.extend(w_impl_items); - // the writer can be safe if: - // * there is a single field that covers the entire register - // * that field can represent all values - // * the write constraints of the register allow full range of values - let can_write_safe = !unsafety( - register - .fields - .as_ref() - .and_then(|fields| fields.first()) - .and_then(|field| field.write_constraint) - .as_ref(), - rsize, - ) || !unsafety(register.write_constraint.as_ref(), rsize); - - if can_write_safe { - mod_items.extend(quote! { - #[doc = "Writes raw bits to the register."] - #[inline(always)] - pub fn bits(&mut self, bits: #rty) -> &mut Self { - self.bits = bits; - self - } - }); - } else { - mod_items.extend(quote! { - /// Writes raw bits to the register. - /// - /// # Safety - /// - /// Passing incorrect value can cause undefined behaviour. See reference manual - #[inline(always)] - pub unsafe fn bits(&mut self, bits: #rty) -> &mut Self { - self.bits = bits; - self - } - }); - } - close.to_tokens(&mut mod_items); } @@ -425,6 +387,22 @@ pub fn render_register_mod( }); } if can_write { + // the writer can be safe if: + // * there is a single field that covers the entire register + // * that field can represent all values + // * the write constraints of the register allow full range of values + let can_write_safe = !unsafety( + register + .fields + .as_ref() + .and_then(|fields| fields.first()) + .and_then(|field| field.write_constraint) + .as_ref(), + rsize, + ) || !unsafety(register.write_constraint.as_ref(), rsize); + let safe_ty = if can_write_safe { "Safe" } else { "Unsafe" }; + let safe_ty = Ident::new(safe_ty, span); + let doc = format!("`write(|w| ..)` method takes [`{mod_ty}::W`](W) writer structure",); let zero_to_modify_fields_bitmap = util::hex(zero_to_modify_fields_bitmap); @@ -433,6 +411,7 @@ pub fn render_register_mod( mod_items.extend(quote! { #[doc = #doc] impl crate::Writable for #regspec_ty { + type Safety = crate::#safe_ty; const ZERO_TO_MODIFY_FIELDS_BITMAP: #rty = #zero_to_modify_fields_bitmap; const ONE_TO_MODIFY_FIELDS_BITMAP: #rty = #one_to_modify_fields_bitmap; }