Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
63 changes: 63 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@ pub enum NameError {
Invalid(String, String),
}

#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
pub enum ResetValueError {
#[error("Reset value 0x{0:x} doesn't fit in {1} bits")]
ValueTooLarge(u32, u32),
#[error("Reset value 0x{0:x} conflicts with mask '{1}'")]
MaskConflict(u32, u32),
#[error("Mask value 0x{0:x} doesn't fit in {1} bits")]
MaskTooLarge(u32, u32),
}

pub(crate) fn check_name(name: &str, tag: &str) -> Result<()> {
static PATTERN: Lazy<Regex> = Lazy::new(|| Regex::new("^[_A-Za-z0-9]*$").unwrap());
if PATTERN.is_match(name) {
Expand All @@ -93,3 +103,56 @@ pub(crate) fn check_dimable_name(name: &str, tag: &str) -> Result<()> {
Err(NameError::Invalid(name.to_string(), tag.to_string()).into())
}
}

pub(crate) fn check_reset_value(
size: Option<u32>,
value: Option<u32>,
mask: Option<u32>,
) -> Result<()> {
const MAX_BITS: u32 = u32::MAX.count_ones();

if let (Some(size), Some(value)) = (size, value) {
if MAX_BITS - value.leading_zeros() > size {
return Err(ResetValueError::ValueTooLarge(value, size).into());
}
}
if let (Some(size), Some(mask)) = (size, mask) {
if MAX_BITS - mask.leading_zeros() > size {
return Err(ResetValueError::MaskTooLarge(mask, size).into());
}
}
if let (Some(value), Some(mask)) = (value, mask) {
if value & mask != value {
return Err(ResetValueError::MaskConflict(value, mask).into());
}
}

Ok(())
}

#[cfg(test)]
mod tests {
use crate::error::check_reset_value;

#[test]
fn test_check_reset_value() {
check_reset_value(None, None, None).unwrap();
check_reset_value(Some(8), None, None).unwrap();
check_reset_value(Some(8), None, Some(0xff)).unwrap();
check_reset_value(Some(32), Some(0xfaceface), None).unwrap();
check_reset_value(Some(32), Some(0xfaceface), Some(0xffffffff)).unwrap();

assert!(
check_reset_value(Some(8), None, Some(0x100)).is_err(),
"mask shouldn't fit in size"
);
assert!(
check_reset_value(Some(1), Some(0x02), None).is_err(),
"reset value shouldn't fit in field"
);
assert!(
check_reset_value(Some(8), Some(0x80), Some(0x01)).is_err(),
"value should conflict with mask"
);
}
}
1 change: 1 addition & 0 deletions src/svd/registerproperties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ impl Parse for RegisterProperties {
p.reset_value = parse::optional::<u32>("resetValue", tree)?;
p.reset_mask = parse::optional::<u32>("resetMask", tree)?;
p.access = parse::optional::<Access>("access", tree)?;
check_reset_value(p.size, p.reset_value, p.reset_mask)?;
Ok(p)
}
}
Expand Down