Skip to content

Generate bool accessors for single-bit fields #84

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

Merged
merged 1 commit into from
May 20, 2017
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
67 changes: 51 additions & 16 deletions src/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,12 @@ fn unsafety(write_constraint: Option<&WriteConstraint>, width: u32) -> Option<Id
// any value that can fit in the field
None
}
None if width == 1 => {
// the field is one bit wide, so we assume it's legal to write
// either value into it or it wouldn't exist; despite that
// if a writeConstraint exists then respect it
None
}
_ => Some(Ident::new("unsafe"))
}
}
Expand Down Expand Up @@ -630,6 +636,7 @@ pub fn fields(
pc_r: Ident,
pc_w: Ident,
sc: Ident,
bits: Ident,
ty: Ident,
width: u32,
write_constraint: Option<&'a WriteConstraint>,
Expand All @@ -644,6 +651,11 @@ pub fn fields(
let pc_w = Ident::new(&*format!("{}W", pc));
let _pc_w = Ident::new(&*format!("_{}W", pc));
let _sc = Ident::new(&*format!("_{}", sc));
let bits = if width == 1 {
Ident::new("bit")
} else {
Ident::new("bits")
};
let mut description = if width == 1 {
format!("Bit {}", offset)
} else {
Expand All @@ -660,11 +672,12 @@ pub fn fields(
description: description,
pc_r: pc_r,
pc_w: pc_w,
bits: bits,
width: width,
access: f.access,
evs: &f.enumerated_values,
sc: Ident::new(&*sc),
mask: util::unsuffixed((1 << width) - 1),
mask: util::unsuffixed_or_bool((1 << width) - 1, width),
name: &f.name,
offset: util::unsuffixed(u64(f.bit_range.offset)),
ty: width.to_ty()?,
Expand All @@ -683,14 +696,20 @@ pub fn fields(
continue;
}

let bits = &f.bits;
let mask = &f.mask;
let offset = &f.offset;
let fty = &f.ty;
let bits = quote! {
let cast = if f.width == 1 {
quote! { != 0 }
} else {
quote! { as #fty }
};
let value = quote! {
const MASK: #fty = #mask;
const OFFSET: u8 = #offset;

((self.bits >> OFFSET) & MASK as #rty) as #fty
((self.bits >> OFFSET) & MASK as #rty) #cast
};

if let Some((evs, base)) =
Expand Down Expand Up @@ -768,7 +787,7 @@ pub fn fields(
#[doc = #description]
#[inline(always)]
pub fn #sc(&self) -> #pc_r {
#pc_r::_from({ #bits })
#pc_r::_from({ #value })
}
},
);
Expand Down Expand Up @@ -814,7 +833,7 @@ pub fn fields(
.iter()
.map(
|v| {
let value = util::unsuffixed(v.value);
let value = util::unsuffixed_or_bool(v.value, f.width);
let pc = &v.pc;

quote! {
Expand All @@ -834,7 +853,7 @@ pub fn fields(
quote! {
/// Value of the field as raw bits
#[inline(always)]
pub fn bits(&self) -> #fty {
pub fn #bits(&self) -> #fty {
match *self {
#(#arms),*
}
Expand All @@ -846,7 +865,7 @@ pub fn fields(
.iter()
.map(
|v| {
let i = util::unsuffixed(v.value);
let i = util::unsuffixed_or_bool(v.value, f.width);
let pc = &v.pc;

quote! {
Expand All @@ -862,7 +881,7 @@ pub fn fields(
i => #pc_r::_Reserved(i)
},
);
} else {
} else if 1 << f.width.to_ty_width()? != variants.len() {
arms.push(
quote! {
_ => unreachable!()
Expand All @@ -875,8 +894,8 @@ pub fn fields(
#[allow(missing_docs)]
#[doc(hidden)]
#[inline(always)]
pub fn _from(bits: #fty) -> #pc_r {
match bits {
pub fn _from(value: #fty) -> #pc_r {
match value {
#(#arms),*,
}
}
Expand Down Expand Up @@ -925,7 +944,7 @@ pub fn fields(
#[doc = #description]
#[inline(always)]
pub fn #sc(&self) -> #pc_r {
let bits = { # bits };
let bits = { #value };
#pc_r { bits }
}
},
Expand All @@ -941,7 +960,7 @@ pub fn fields(
impl #pc_r {
/// Value of the field as raw bits
#[inline(always)]
pub fn bits(&self) -> #fty {
pub fn #bits(&self) -> #fty {
self.bits
}
}
Expand All @@ -961,9 +980,11 @@ pub fn fields(
let mut proxy_items = vec![];

let mut unsafety = unsafety(f.write_constraint, f.width);
let bits = &f.bits;
let fty = &f.ty;
let offset = &f.offset;
let mask = &f.mask;
let width = f.width;

if let Some((evs, base)) =
util::lookup(
Expand Down Expand Up @@ -1069,7 +1090,7 @@ pub fn fields(
.map(
|v| {
let pc = &v.pc;
let value = util::unsuffixed(v.value);
let value = util::unsuffixed_or_bool(v.value, f.width);

quote! {
#pc_w::#pc => #value
Expand Down Expand Up @@ -1100,7 +1121,7 @@ pub fn fields(
#[inline(always)]
pub fn variant(self, variant: #pc_w) -> &'a mut W {
#unsafety {
self.bits(variant._bits())
self.#bits(variant._bits())
}
}
},
Expand Down Expand Up @@ -1133,18 +1154,32 @@ pub fn fields(
);
}
}
} else if width == 1 {
proxy_items.push(
quote! {
/// Sets the field bit
pub fn set(self) -> &'a mut W {
self.bit(true)
}

/// Clears the field bit
pub fn clear(self) -> &'a mut W {
self.bit(false)
}
}
);
}

proxy_items.push(
quote! {
/// Writes raw bits to the field
#[inline(always)]
pub #unsafety fn bits(self, bits: #fty) -> &'a mut W {
pub #unsafety fn #bits(self, value: #fty) -> &'a mut W {
const MASK: #fty = #mask;
const OFFSET: u8 = #offset;

self.w.bits &= !((MASK as #rty) << OFFSET);
self.w.bits |= ((bits & MASK) as #rty) << OFFSET;
self.w.bits |= ((value & MASK) as #rty) << OFFSET;
self.w
}
},
Expand Down
14 changes: 7 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@
//!
//! ``` rust
//! // is the SADD0 bit of the CR2 register set?
//! if i2c1.c2r.read().sadd0().bits() == 1 {
//! if i2c1.c2r.read().sadd0().bit() {
//! // yes
//! } else {
//! // no
Expand Down Expand Up @@ -225,7 +225,7 @@
//! // Starting from the reset value, `0x0000_0000`, change the bitfields SADD0
//! // and SADD1 to `1` and `0b0011110` respectively and write that to the
//! // register CR2.
//! i2c1.cr2.write(|w| unsafe { w.sadd0().bits(1).sadd1().bits(0b0011110) });
//! i2c1.cr2.write(|w| unsafe { w.sadd0().bit(true).sadd1().bits(0b0011110) });
//! // NOTE ^ unsafe because you could be writing a reserved bit pattern into
//! // the register. In this case, the SVD doesn't provide enough information to
//! // check whether that's the case.
Expand All @@ -246,10 +246,10 @@
//!
//! ``` rust
//! // Set the START bit to 1 while KEEPING the state of the other bits intact
//! i2c1.cr2.modify(|_, w| unsafe { w.start().bits(1) });
//! i2c1.cr2.modify(|_, w| unsafe { w.start().bit(true) });
//!
//! // TOGGLE the STOP bit, all the other bits will remain untouched
//! i2c1.cr2.modify(|r, w| w.stop().bits(r.stop().bits() ^ 1));
//! i2c1.cr2.modify(|r, w| w.stop().bit(!r.stop().bit()));
//! ```
//!
//! # enumeratedValues
Expand Down Expand Up @@ -314,12 +314,12 @@
//! gpioa.dir.write(|w| w.pin0().output());
//! ```
//!
//! The `bits` method is still available but will become safe if it's impossible
//! to write a reserved bit pattern into the register
//! The `bits` (or `bit`) method is still available but will become safe if it's
//! impossible to write a reserved bit pattern into the register:
//!
//! ```
//! // safe because there are only two options: `0` or `1`
//! gpioa.dir.write(|w| w.pin0().bits(1));
//! gpioa.dir.write(|w| w.pin0().bit(true));
//! ```
//!
//! # Interrupt API
Expand Down
37 changes: 35 additions & 2 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,18 @@ pub fn unsuffixed(n: u64) -> Lit {
Lit::Int(n, IntTy::Unsuffixed)
}

pub fn unsuffixed_or_bool(n: u64, width: u32) -> Lit {
if width == 1 {
if n == 0 {
Lit::Bool(false)
} else {
Lit::Bool(true)
}
} else {
unsuffixed(n)
}
}

#[derive(Clone, Debug)]
pub struct Base<'a> {
pub register: Option<&'a str>,
Expand Down Expand Up @@ -427,24 +439,45 @@ fn lookup_in_register<'r>

pub trait U32Ext {
fn to_ty(&self) -> Result<Ident>;
fn to_ty_width(&self) -> Result<u32>;
}

impl U32Ext for u32 {
fn to_ty(&self) -> Result<Ident> {
Ok(
match *self {
1...8 => Ident::new("u8"),
1 => Ident::new("bool"),
2...8 => Ident::new("u8"),
9...16 => Ident::new("u16"),
17...32 => Ident::new("u32"),
_ => {
Err(
format!(
"can't convert {} bits into a Rust integer type",
"can't convert {} bits into a Rust integral type",
*self
),
)?
}
},
)
}

fn to_ty_width(&self) -> Result<u32> {
Ok(
match *self {
1 => 1,
2...8 => 8,
9...16 => 16,
17...32 => 32,
_ => {
Err(
format!(
"can't convert {} bits into a Rust integral type width",
*self
),
)?
}
}
)
}
}