diff --git a/CHANGELOG.md b/CHANGELOG.md index b27ed24b..60e5bde2 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.5] - 2024-01-04 - `move` in `RegisterBlock::reg_iter` implementation (iterator of register/cluster array) @@ -863,9 +865,7 @@ peripheral.register.write(|w| w.field().set()); - Initial version of the `svd2rust` tool -[Unreleased]: https://github.com/rust-embedded/svd2rust/compare/v0.31.5...HEAD -[v0.31.5]: https://github.com/rust-embedded/svd2rust/compare/v0.31.4...v0.31.5 -[v0.31.4]: https://github.com/rust-embedded/svd2rust/compare/v0.31.3...v0.31.4 +[Unreleased]: https://github.com/rust-embedded/svd2rust/compare/v0.31.3...HEAD [v0.31.3]: https://github.com/rust-embedded/svd2rust/compare/v0.31.2...v0.31.3 [v0.31.2]: https://github.com/rust-embedded/svd2rust/compare/v0.31.1...v0.31.2 [v0.31.1]: https://github.com/rust-embedded/svd2rust/compare/v0.31.0...v0.31.1 diff --git a/src/generate/generic.rs b/src/generate/generic.rs index 186d3364..b33ea7fd 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,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 21fb1746..8a677cc9 100644 --- a/src/generate/register.rs +++ b/src/generate/register.rs @@ -337,44 +337,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); } @@ -407,6 +369,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",); @@ -416,6 +394,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; } diff --git a/src/util.rs b/src/util.rs index fd80df55..8c6accc7 100644 --- a/src/util.rs +++ b/src/util.rs @@ -114,7 +114,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() {