Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

generic safe/unsafe W::bits #788

Merged
merged 1 commit into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading