Skip to content
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
2 changes: 2 additions & 0 deletions CHANGELOG-rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ This changelog tracks the Rust `svdtools` project. See

## [Unreleased]

* Add support for `modifiedWriteValues` & `readAction` for fields

## [v0.2.2] 2022-04-23

* Use `svd-encoder` 0.13.2
Expand Down
94 changes: 83 additions & 11 deletions src/patch/register.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use anyhow::{anyhow, Context};
use svd_parser::svd::{
BitRange, DimElement, EnumeratedValues, Field, FieldInfo, Register, RegisterInfo, Usage,
WriteConstraint, WriteConstraintRange,
BitRange, DimElement, EnumeratedValues, Field, FieldInfo, ModifiedWriteValues, ReadAction,
Register, RegisterInfo, Usage, WriteConstraint, WriteConstraintRange,
};
use yaml_rust::{yaml::Hash, Yaml};

Expand Down Expand Up @@ -58,6 +58,12 @@ pub trait RegisterExt {
usage: Usage,
) -> PatchResult;

/// Set readAction for field
fn set_field_read_action(&mut self, fspec: &str, action: ReadAction);

/// Set modifiedWriteValues for field
fn set_field_modified_write_values(&mut self, fspec: &str, mwv: ModifiedWriteValues);

/// Add a writeConstraint range given by field to all fspec in rtag
fn process_field_range(&mut self, pname: &str, fspec: &str, fmod: &[Yaml]) -> PatchResult;

Expand Down Expand Up @@ -452,21 +458,67 @@ impl RegisterExt for Register {
}

fn process_field(&mut self, pname: &str, fspec: &str, fmod: &Yaml) -> PatchResult {
const READ_KEYS: [&str; 5] = ["_read", "_RM", "_RS", "_RC", "_RME"];
const READ_VALS: [Option<ReadAction>; 5] = [
None,
Some(ReadAction::Modify),
Some(ReadAction::Set),
Some(ReadAction::Clear),
Some(ReadAction::ModifyExternal),
];
const WRITE_KEYS: [&str; 10] = [
"_write", "_WM", "_WS", "_WC", "_W1S", "_W0C", "_W1C", "_W0S", "_W1T", "_W0T",
];
const WRITE_VALS: [Option<ModifiedWriteValues>; 10] = [
None,
Some(ModifiedWriteValues::Modify),
Some(ModifiedWriteValues::Set),
Some(ModifiedWriteValues::Clear),
Some(ModifiedWriteValues::OneToSet),
Some(ModifiedWriteValues::ZeroToClear),
Some(ModifiedWriteValues::OneToClear),
Some(ModifiedWriteValues::ZeroToSet),
Some(ModifiedWriteValues::OneToToggle),
Some(ModifiedWriteValues::ZeroToToggle),
];
match fmod {
Yaml::Hash(fmod) => {
let is_read = fmod.get_hash("_read")?;
let is_write = fmod.get_hash("_write")?;
if is_read.is_none() && is_write.is_none() {
let is_read = READ_KEYS
.iter()
.any(|key| fmod.contains_key(&key.to_yaml()));
let is_write = WRITE_KEYS
.iter()
.any(|key| fmod.contains_key(&key.to_yaml()));
if !is_read && !is_write {
self.process_field_enum(pname, fspec, fmod, Usage::ReadWrite)
.with_context(|| "Adding read-write enumeratedValues")?;
} else {
if let Some(fmod) = is_read {
self.process_field_enum(pname, fspec, fmod, Usage::Read)
.with_context(|| "Adding read-only enumeratedValues")?;
if is_read {
for (key, action) in READ_KEYS.into_iter().zip(READ_VALS.into_iter()) {
if let Some(fmod) = fmod.get_hash(key)? {
if !fmod.is_empty() {
self.process_field_enum(pname, fspec, fmod, Usage::Read)
.with_context(|| "Adding read-only enumeratedValues")?;
}
if let Some(action) = action {
self.set_field_read_action(fspec, action);
}
break;
}
}
}
if let Some(fmod) = is_write {
self.process_field_enum(pname, fspec, fmod, Usage::Write)
.with_context(|| "Adding write-only enumeratedValues")?;
if is_write {
for (key, mwv) in WRITE_KEYS.into_iter().zip(WRITE_VALS.into_iter()) {
if let Some(fmod) = fmod.get_hash(key)? {
if !fmod.is_empty() {
self.process_field_enum(pname, fspec, fmod, Usage::Write)
.with_context(|| "Adding write-only enumeratedValues")?;
}
if let Some(mwv) = mwv {
self.set_field_modified_write_values(fspec, mwv);
}
}
}
}
}
}
Expand All @@ -479,6 +531,26 @@ impl RegisterExt for Register {
Ok(())
}

fn set_field_read_action(&mut self, fspec: &str, action: ReadAction) {
for ftag in self.iter_fields(fspec) {
ftag.read_action = if action == ReadAction::Modify {
None
} else {
Some(action)
};
}
}

fn set_field_modified_write_values(&mut self, fspec: &str, mwv: ModifiedWriteValues) {
for ftag in self.iter_fields(fspec) {
ftag.modified_write_values = if mwv == ModifiedWriteValues::Modify {
None
} else {
Some(mwv)
};
}
}

fn process_field_enum(
&mut self,
pname: &str,
Expand Down
84 changes: 73 additions & 11 deletions svdtools/patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -1324,21 +1324,83 @@ def split_fields(self, fspec, fsplit):
ET.SubElement(fnew, "bitOffset").text = str(bitoffset + i)
ET.SubElement(fnew, "bitWidth").text = str(1)

def process_field(self, pname, fspec, field):
def process_field(self, pname, fspec, fmod):
"""Work through a field, handling either an enum or a range."""
if isinstance(field, dict):
usages = ("_read", "_write")
if isinstance(fmod, dict):
read_keys = ["_read", "_RM", "_RS", "_RC", "_RME"]
read_vals = ["", "modify", "set", "clear", "modifyExternal"]
write_keys = [
"_write",
"_WM",
"_WS",
"_WC",
"_W1S",
"_W0C",
"_W1C",
"_W0S",
"_W1T",
"_W0T",
]
write_vals = [
"",
"modify",
"set",
"clear",
"oneToSet",
"zeroToClear",
"oneToClear",
"zeroToSet",
"oneToToggle",
"zeroToToggle",
]
is_read = any(key in fmod for key in read_keys)
is_write = any(key in fmod for key in write_keys)
if not is_read and not is_write:
self.process_field_enum(pname, fspec, fmod)
else:
if is_read:
for key, action in zip(read_keys, read_vals):
if key in fmod:
mod = fmod[key]
if mod:
self.process_field_enum(pname, fspec, mod, usage="read")
if action:
self.set_field_read_action(fspec, action)
break
if is_write:
for key, mwv in zip(write_keys, write_vals):
if key in fmod:
mod = fmod[key]
if mod:
self.process_field_enum(
pname, fspec, mod, usage="write"
)
if mwv:
self.set_field_modified_write_values(fspec, mwv)
break

if not any(u in field for u in usages):
self.process_field_enum(pname, fspec, field)
elif isinstance(fmod, list) and len(fmod) == 2:
self.process_field_range(pname, fspec, fmod)

for usage in (u for u in usages if u in field):
self.process_field_enum(
pname, fspec, field[usage], usage=usage.replace("_", "")
)
def set_field_read_action(self, fspec, action):
for ftag in self.iter_fields(fspec):
tag = ftag.find("readAction")
if tag is None:
tag = ET.SubElement(ftag, "readAction")
elif action == "modify":
ftag.remove(tag)
return
tag.text = action

elif isinstance(field, list) and len(field) == 2:
self.process_field_range(pname, fspec, field)
def set_field_modified_write_values(self, fspec, mwv):
for ftag in self.iter_fields(fspec):
tag = ftag.find("modifiedWriteValues")
if tag is None:
tag = ET.SubElement(ftag, "modifiedWriteValues")
elif mwv == "modify":
ftag.remove(tag)
return
tag.text = mwv

def process_field_enum(self, pname, fspec, field, usage="read-write"):
"""Add an enumeratedValues given by field to all fspec in rtag."""
Expand Down