diff --git a/CHANGELOG.md b/CHANGELOG.md index 2acc92e3..d79a5f56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] +- generic unsafe `W::bits` + safe `W::set` + ## [v0.31.3] - 2023-12-25 - Add `svd::Device` validation after parsing by `serde` diff --git a/src/generate/generic.rs b/src/generate/generic.rs index 186d3364..47c7fb96 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 { + // `Safe` or `Unsafe` writting raw bits + 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,31 @@ 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. + /// + /// # Safety + /// + /// Passing incorrect value can cause undefined behaviour. See reference manual + #[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. diff --git a/src/generate/register.rs b/src/generate/register.rs index 7ae49c20..78e43ca9 100644 --- a/src/generate/register.rs +++ b/src/generate/register.rs @@ -333,44 +333,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); } @@ -403,6 +365,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 [`{name_snake_case}::W`](W) writer structure",); @@ -412,6 +390,7 @@ pub fn render_register_mod( mod_items.extend(quote! { #[doc = #doc] impl crate::Writable for #regspec_ident { + type Safety = crate::#safe_ty; const ZERO_TO_MODIFY_FIELDS_BITMAP: Self::Ux = #zero_to_modify_fields_bitmap; const ONE_TO_MODIFY_FIELDS_BITMAP: Self::Ux = #one_to_modify_fields_bitmap; } diff --git a/src/util.rs b/src/util.rs index 547d879a..4399e05d 100644 --- a/src/util.rs +++ b/src/util.rs @@ -106,7 +106,7 @@ impl ToSanitizedCase for str { } } fn to_sanitized_not_keyword_snake_case(&self) -> Cow { - const INTERNALS: [&str; 4] = ["set_bit", "clear_bit", "bit", "bits"]; + const INTERNALS: [&str; 5] = ["set_bit", "clear_bit", "bit", "bits", "set"]; let s = Case::Snake.sanitize(self); if s.as_bytes().first().unwrap_or(&0).is_ascii_digit() {