Skip to content

Commit fe1e230

Browse files
authored
Merge pull request #788 from rust-embedded/bits
generic safe/unsafe W::bits
2 parents 2cad65c + c2420ca commit fe1e230

File tree

3 files changed

+45
-41
lines changed

3 files changed

+45
-41
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
88
## [Unreleased]
99

1010
- Bump MSRV to 1.74
11+
- generic unsafe `W::bits` + safe `W::set`
1112
- Add `base-address-shift` config flag
1213
- Fix case changing bugs, add `--ident-format` (`-f`) option flag
1314

src/generate/generic.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ pub trait Readable: RegisterSpec {}
6767
///
6868
/// Registers marked with `Readable` can be also be `modify`'ed.
6969
pub trait Writable: RegisterSpec {
70+
/// Is it safe to write any bits to register
71+
type Safety;
72+
7073
/// Specifies the register bits that are not changed if you pass `1` and are changed if you pass `0`
7174
const ZERO_TO_MODIFY_FIELDS_BITMAP: Self::Ux;
7275

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

396+
impl<REG: Writable> W<REG> {
397+
/// Writes raw bits to the register.
398+
///
399+
/// # Safety
400+
///
401+
/// Passing incorrect value can cause undefined behaviour. See reference manual
402+
#[inline(always)]
403+
pub unsafe fn bits(&mut self, bits: REG::Ux) -> &mut Self {
404+
self.bits = bits;
405+
self
406+
}
407+
}
408+
impl<REG> W<REG> where REG: Writable<Safety = Safe> {
409+
/// Writes raw bits to the register.
410+
#[inline(always)]
411+
pub fn set(&mut self, bits: REG::Ux) -> &mut Self {
412+
self.bits = bits;
413+
self
414+
}
415+
}
416+
393417
/// Field reader.
394418
///
395419
/// Result of the `read` methods of fields.
@@ -445,9 +469,9 @@ impl<FI> BitReader<FI> {
445469
}
446470
}
447471

448-
#[doc(hidden)]
472+
/// Marker for register/field writers which can take any value of specified width
449473
pub struct Safe;
450-
#[doc(hidden)]
474+
/// You should check that value is allowed to pass to register/field writer marked with this
451475
pub struct Unsafe;
452476

453477
/// Write field Proxy with unsafe `bits`

src/generate/register.rs

Lines changed: 18 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ fn regspec(name: &str, config: &Config, span: Span) -> Ident {
2626
}
2727

2828
fn field_accessor(name: &str, config: &Config, span: Span) -> Ident {
29-
const INTERNALS: [&str; 1] = ["bits"];
29+
const INTERNALS: [&str; 2] = ["bits", "set"];
3030
let sc = config
3131
.ident_formats
3232
.get("field_accessor")
@@ -355,44 +355,6 @@ pub fn render_register_mod(
355355

356356
mod_items.extend(w_impl_items);
357357

358-
// the writer can be safe if:
359-
// * there is a single field that covers the entire register
360-
// * that field can represent all values
361-
// * the write constraints of the register allow full range of values
362-
let can_write_safe = !unsafety(
363-
register
364-
.fields
365-
.as_ref()
366-
.and_then(|fields| fields.first())
367-
.and_then(|field| field.write_constraint)
368-
.as_ref(),
369-
rsize,
370-
) || !unsafety(register.write_constraint.as_ref(), rsize);
371-
372-
if can_write_safe {
373-
mod_items.extend(quote! {
374-
#[doc = "Writes raw bits to the register."]
375-
#[inline(always)]
376-
pub fn bits(&mut self, bits: #rty) -> &mut Self {
377-
self.bits = bits;
378-
self
379-
}
380-
});
381-
} else {
382-
mod_items.extend(quote! {
383-
/// Writes raw bits to the register.
384-
///
385-
/// # Safety
386-
///
387-
/// Passing incorrect value can cause undefined behaviour. See reference manual
388-
#[inline(always)]
389-
pub unsafe fn bits(&mut self, bits: #rty) -> &mut Self {
390-
self.bits = bits;
391-
self
392-
}
393-
});
394-
}
395-
396358
close.to_tokens(&mut mod_items);
397359
}
398360

@@ -425,6 +387,22 @@ pub fn render_register_mod(
425387
});
426388
}
427389
if can_write {
390+
// the writer can be safe if:
391+
// * there is a single field that covers the entire register
392+
// * that field can represent all values
393+
// * the write constraints of the register allow full range of values
394+
let can_write_safe = !unsafety(
395+
register
396+
.fields
397+
.as_ref()
398+
.and_then(|fields| fields.first())
399+
.and_then(|field| field.write_constraint)
400+
.as_ref(),
401+
rsize,
402+
) || !unsafety(register.write_constraint.as_ref(), rsize);
403+
let safe_ty = if can_write_safe { "Safe" } else { "Unsafe" };
404+
let safe_ty = Ident::new(safe_ty, span);
405+
428406
let doc = format!("`write(|w| ..)` method takes [`{mod_ty}::W`](W) writer structure",);
429407

430408
let zero_to_modify_fields_bitmap = util::hex(zero_to_modify_fields_bitmap);
@@ -433,6 +411,7 @@ pub fn render_register_mod(
433411
mod_items.extend(quote! {
434412
#[doc = #doc]
435413
impl crate::Writable for #regspec_ty {
414+
type Safety = crate::#safe_ty;
436415
const ZERO_TO_MODIFY_FIELDS_BITMAP: #rty = #zero_to_modify_fields_bitmap;
437416
const ONE_TO_MODIFY_FIELDS_BITMAP: #rty = #one_to_modify_fields_bitmap;
438417
}

0 commit comments

Comments
 (0)