Skip to content

Commit

Permalink
generic safe/unsafe W::bits
Browse files Browse the repository at this point in the history
  • Loading branch information
burrbull committed Dec 23, 2023
1 parent eea8296 commit c7fc4c3
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 39 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).

## [Unreleased]

- generic unsafe `W::bits` + safe `W::set`
- Add `svd::Device` validation after parsing by `serde`
- Add `skip-crate-attributes` config flag
- Better display parsing errors
Expand Down
28 changes: 28 additions & 0 deletions src/generate/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -390,6 +393,31 @@ where
/// Used as an argument to the closures in the `write` and `modify` methods of the register.
pub type W<REG> = raw::W<REG>;

impl<REG: Writable> W<REG> {
/// 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<REG> W<REG> where REG: Writable<Safety = Safe> {
/// 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.
Expand Down
55 changes: 17 additions & 38 deletions src/generate/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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",);

Expand All @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ impl ToSanitizedCase for str {
}
}
fn to_sanitized_not_keyword_snake_case(&self) -> Cow<str> {
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() {
Expand Down

0 comments on commit c7fc4c3

Please sign in to comment.