Skip to content

Commit

Permalink
Merge pull request #788 from rust-embedded/bits
Browse files Browse the repository at this point in the history
generic safe/unsafe W::bits
  • Loading branch information
Emilgardis authored Feb 16, 2024
2 parents 2cad65c + c2420ca commit fe1e230
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 41 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
28 changes: 26 additions & 2 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 {
/// 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;

Expand Down Expand Up @@ -390,6 +393,27 @@ 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.
#[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 Expand Up @@ -445,9 +469,9 @@ impl<FI> BitReader<FI> {
}
}

#[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`
Expand Down
57 changes: 18 additions & 39 deletions src/generate/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);
Expand All @@ -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;
}
Expand Down

0 comments on commit fe1e230

Please sign in to comment.