Skip to content

Commit 312a961

Browse files
committed
usage
1 parent 13dfa20 commit 312a961

File tree

2 files changed

+90
-41
lines changed

2 files changed

+90
-41
lines changed

src/patch/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,15 +220,15 @@ fn get_register_properties(h: &Hash) -> Result<RegisterProperties> {
220220
.reset_mask(h.get_u64("resetMask")?))
221221
}
222222

223-
fn make_ev_name(name: &str, usage: Usage) -> Result<String> {
223+
fn make_ev_name(name: &str, usage: Option<Usage>) -> Result<String> {
224224
if name.as_bytes()[0].is_ascii_digit() {
225225
return Err(anyhow!(
226226
"enumeratedValue {}: can't start with a number",
227227
name
228228
));
229229
}
230230
Ok(name.to_string()
231-
+ match usage {
231+
+ match usage.unwrap_or_default() {
232232
Usage::Read => "R",
233233
Usage::Write => "W",
234234
Usage::ReadWrite => "",

src/patch/register.rs

Lines changed: 88 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use anyhow::{anyhow, Context};
22
use svd_parser::svd::{
3-
BitRange, DimElement, EnumeratedValues, Field, FieldInfo, ModifiedWriteValues, ReadAction,
4-
Register, RegisterInfo, Usage, WriteConstraint, WriteConstraintRange,
3+
Access, BitRange, DimElement, EnumeratedValues, Field, FieldInfo, ModifiedWriteValues,
4+
ReadAction, Register, RegisterInfo, Usage, WriteConstraint, WriteConstraintRange,
55
};
66
use yaml_rust::{yaml::Hash, Yaml};
77

@@ -55,7 +55,7 @@ pub trait RegisterExt {
5555
pname: &str,
5656
fspec: &str,
5757
fmod: &Hash,
58-
usage: Usage,
58+
usage: Option<Usage>,
5959
) -> PatchResult;
6060

6161
/// Set readAction for field
@@ -493,14 +493,14 @@ impl RegisterExt for Register {
493493
.iter()
494494
.any(|key| fmod.contains_key(&key.to_yaml()));
495495
if !is_read && !is_write {
496-
self.process_field_enum(pname, fspec, fmod, Usage::ReadWrite)
496+
self.process_field_enum(pname, fspec, fmod, None)
497497
.with_context(|| "Adding read-write enumeratedValues")?;
498498
} else {
499499
if is_read {
500500
for (key, action) in READ_KEYS.into_iter().zip(READ_VALS.into_iter()) {
501501
if let Some(fmod) = fmod.get_hash(key)? {
502502
if !fmod.is_empty() {
503-
self.process_field_enum(pname, fspec, fmod, Usage::Read)
503+
self.process_field_enum(pname, fspec, fmod, Some(Usage::Read))
504504
.with_context(|| "Adding read-only enumeratedValues")?;
505505
}
506506
if let Some(action) = action {
@@ -514,7 +514,7 @@ impl RegisterExt for Register {
514514
for (key, mwv) in WRITE_KEYS.into_iter().zip(WRITE_VALS.into_iter()) {
515515
if let Some(fmod) = fmod.get_hash(key)? {
516516
if !fmod.is_empty() {
517-
self.process_field_enum(pname, fspec, fmod, Usage::Write)
517+
self.process_field_enum(pname, fspec, fmod, Some(Usage::Write))
518518
.with_context(|| "Adding write-only enumeratedValues")?;
519519
}
520520
if let Some(mwv) = mwv {
@@ -555,42 +555,58 @@ impl RegisterExt for Register {
555555
pname: &str,
556556
fspec: &str,
557557
mut fmod: &Hash,
558-
usage: Usage,
558+
usage: Option<Usage>,
559559
) -> PatchResult {
560560
fn set_enum(
561561
f: &mut FieldInfo,
562-
val: EnumeratedValues,
562+
mut val: EnumeratedValues,
563563
usage: Usage,
564564
replace: bool,
565+
access: Access,
565566
) -> PatchResult {
567+
let occupied_error = || {
568+
Err(anyhow!(
569+
"field {} already has {:?} enumeratedValues",
570+
f.name,
571+
usage
572+
))
573+
};
566574
if usage == Usage::ReadWrite {
567575
if f.enumerated_values.is_empty() || replace {
568576
f.enumerated_values = vec![val];
569577
} else {
570-
return Err(anyhow!(
571-
"field {} already has {:?} enumeratedValues",
572-
f.name,
573-
usage
574-
));
578+
return occupied_error();
575579
}
576580
} else {
577581
match f.enumerated_values.as_mut_slice() {
578582
[] => f.enumerated_values.push(val),
579-
[v] => {
580-
if v.usage == Some(usage) || v.usage == Some(Usage::ReadWrite) {
583+
[v] if v.usage == Some(usage) || v.usage == Some(Usage::ReadWrite) => {
584+
if replace {
585+
*v = val;
586+
} else {
587+
return occupied_error();
588+
}
589+
}
590+
[v] if v.usage.is_none() => match (access, usage) {
591+
(Access::ReadWrite | Access::ReadWriteOnce, Usage::Read) => {
592+
v.usage = Some(Usage::Write);
593+
val.usage = Some(Usage::Read);
594+
f.enumerated_values.push(val);
595+
}
596+
(Access::ReadWrite | Access::ReadWriteOnce, Usage::Write) => {
597+
v.usage = Some(Usage::Read);
598+
val.usage = Some(Usage::Write);
599+
f.enumerated_values.push(val);
600+
}
601+
_ => {
581602
if replace {
582603
*v = val;
583604
} else {
584-
return Err(anyhow!(
585-
"field {} already has {:?} enumeratedValues",
586-
f.name,
587-
usage
588-
));
605+
return occupied_error();
589606
}
590-
} else {
591-
f.enumerated_values.push(val);
592607
}
593-
}
608+
},
609+
[_] => f.enumerated_values.push(val),
594610
[v1, v2] => {
595611
if replace {
596612
if v1.usage == Some(usage) {
@@ -600,11 +616,7 @@ impl RegisterExt for Register {
600616
*v2 = val;
601617
}
602618
} else {
603-
return Err(anyhow!(
604-
"field {} already has {:?} enumeratedValues",
605-
f.name,
606-
usage
607-
));
619+
return occupied_error();
608620
}
609621
}
610622
_ => return Err(anyhow!("Incorrect enumeratedValues")),
@@ -619,6 +631,7 @@ impl RegisterExt for Register {
619631
replace_if_exists = true;
620632
}
621633

634+
let reg_access = self.properties.access;
622635
if let Some(d) = fmod.get_str("_derivedFrom")? {
623636
// This is a derived enumeratedValues => Try to find the
624637
// original definition to extract its <usage>
@@ -644,19 +657,22 @@ impl RegisterExt for Register {
644657
));
645658
}
646659
};
647-
if usage != orig_usage {
648-
return Err(anyhow!(
649-
"enumeratedValues with different usage was found: {:?} != {:?}",
650-
usage,
651-
orig_usage
652-
));
653-
}
654660
let evs = make_derived_enumerated_values(d)?;
655661
for ftag in self.iter_fields(fspec) {
662+
let access = ftag.access.or(reg_access).unwrap_or_default();
663+
let checked_usage = check_usage(access, usage)
664+
.with_context(|| format!("In field {}", ftag.name))?;
665+
if checked_usage != orig_usage {
666+
return Err(anyhow!(
667+
"enumeratedValues with different usage was found: {:?} != {:?}",
668+
usage,
669+
orig_usage
670+
));
671+
}
656672
if ftag.name == d {
657673
return Err(anyhow!("EnumeratedValues can't be derived from itself"));
658674
}
659-
set_enum(ftag, evs.clone(), usage, true)?;
675+
set_enum(ftag, evs.clone(), orig_usage, true, access)?;
660676
}
661677
} else {
662678
let offsets = self
@@ -669,14 +685,23 @@ impl RegisterExt for Register {
669685
let (min_offset, name) = offsets.iter().min_by_key(|on| on.0).unwrap();
670686
let name = make_ev_name(&name.replace("%s", ""), usage)?;
671687
for ftag in self.iter_fields(fspec) {
688+
let access = ftag.access.or(reg_access).unwrap_or_default();
689+
let checked_usage = check_usage(access, usage)
690+
.with_context(|| format!("In field {}", ftag.name))?;
672691
if ftag.bit_range.offset == *min_offset {
673692
let evs = make_ev_array(fmod)?
674693
.name(Some(name.clone()))
675-
.usage(Some(usage))
694+
.usage(make_usage(access, checked_usage))
676695
.build(VAL_LVL)?;
677-
set_enum(ftag, evs, usage, replace_if_exists)?;
696+
set_enum(ftag, evs, checked_usage, replace_if_exists, access)?;
678697
} else {
679-
set_enum(ftag, make_derived_enumerated_values(&name)?, usage, true)?;
698+
set_enum(
699+
ftag,
700+
make_derived_enumerated_values(&name)?,
701+
checked_usage,
702+
true,
703+
access,
704+
)?;
680705
}
681706
}
682707
}
@@ -698,3 +723,27 @@ impl RegisterExt for Register {
698723
Ok(())
699724
}
700725
}
726+
727+
fn check_usage(access: Access, usage: Option<Usage>) -> anyhow::Result<Usage> {
728+
Ok(match (access, usage) {
729+
(Access::ReadWrite | Access::ReadWriteOnce, usage) => usage.unwrap_or_default(),
730+
(Access::ReadOnly, None | Some(Usage::Read)) => Usage::Read,
731+
(Access::WriteOnly | Access::WriteOnce, None | Some(Usage::Write)) => Usage::Write,
732+
(_, _) => {
733+
return Err(anyhow!(
734+
"EnumeratedValues usage {:?} is incompatible with access {:?}",
735+
usage,
736+
access
737+
));
738+
}
739+
})
740+
}
741+
742+
fn make_usage(access: Access, usage: Usage) -> Option<Usage> {
743+
match (access, usage) {
744+
(Access::ReadWrite | Access::ReadWriteOnce, Usage::ReadWrite)
745+
| (Access::ReadOnly, Usage::Read)
746+
| (Access::WriteOnly | Access::WriteOnce, Usage::Write) => None,
747+
_ => Some(usage),
748+
}
749+
}

0 commit comments

Comments
 (0)