From 312a96112e68d22e4efccce1842504b08456a320 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 13 May 2022 16:08:38 +0300 Subject: [PATCH 1/5] usage --- src/patch/mod.rs | 4 +- src/patch/register.rs | 127 +++++++++++++++++++++++++++++------------- 2 files changed, 90 insertions(+), 41 deletions(-) diff --git a/src/patch/mod.rs b/src/patch/mod.rs index 444a5807..3dd176e3 100644 --- a/src/patch/mod.rs +++ b/src/patch/mod.rs @@ -220,7 +220,7 @@ fn get_register_properties(h: &Hash) -> Result { .reset_mask(h.get_u64("resetMask")?)) } -fn make_ev_name(name: &str, usage: Usage) -> Result { +fn make_ev_name(name: &str, usage: Option) -> Result { if name.as_bytes()[0].is_ascii_digit() { return Err(anyhow!( "enumeratedValue {}: can't start with a number", @@ -228,7 +228,7 @@ fn make_ev_name(name: &str, usage: Usage) -> Result { )); } Ok(name.to_string() - + match usage { + + match usage.unwrap_or_default() { Usage::Read => "R", Usage::Write => "W", Usage::ReadWrite => "", diff --git a/src/patch/register.rs b/src/patch/register.rs index cd03b4f6..2d60495d 100644 --- a/src/patch/register.rs +++ b/src/patch/register.rs @@ -1,7 +1,7 @@ use anyhow::{anyhow, Context}; use svd_parser::svd::{ - BitRange, DimElement, EnumeratedValues, Field, FieldInfo, ModifiedWriteValues, ReadAction, - Register, RegisterInfo, Usage, WriteConstraint, WriteConstraintRange, + Access, BitRange, DimElement, EnumeratedValues, Field, FieldInfo, ModifiedWriteValues, + ReadAction, Register, RegisterInfo, Usage, WriteConstraint, WriteConstraintRange, }; use yaml_rust::{yaml::Hash, Yaml}; @@ -55,7 +55,7 @@ pub trait RegisterExt { pname: &str, fspec: &str, fmod: &Hash, - usage: Usage, + usage: Option, ) -> PatchResult; /// Set readAction for field @@ -493,14 +493,14 @@ impl RegisterExt for Register { .iter() .any(|key| fmod.contains_key(&key.to_yaml())); if !is_read && !is_write { - self.process_field_enum(pname, fspec, fmod, Usage::ReadWrite) + self.process_field_enum(pname, fspec, fmod, None) .with_context(|| "Adding read-write enumeratedValues")?; } else { 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) + self.process_field_enum(pname, fspec, fmod, Some(Usage::Read)) .with_context(|| "Adding read-only enumeratedValues")?; } if let Some(action) = action { @@ -514,7 +514,7 @@ impl RegisterExt for Register { 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) + self.process_field_enum(pname, fspec, fmod, Some(Usage::Write)) .with_context(|| "Adding write-only enumeratedValues")?; } if let Some(mwv) = mwv { @@ -555,42 +555,58 @@ impl RegisterExt for Register { pname: &str, fspec: &str, mut fmod: &Hash, - usage: Usage, + usage: Option, ) -> PatchResult { fn set_enum( f: &mut FieldInfo, - val: EnumeratedValues, + mut val: EnumeratedValues, usage: Usage, replace: bool, + access: Access, ) -> PatchResult { + let occupied_error = || { + Err(anyhow!( + "field {} already has {:?} enumeratedValues", + f.name, + usage + )) + }; if usage == Usage::ReadWrite { if f.enumerated_values.is_empty() || replace { f.enumerated_values = vec![val]; } else { - return Err(anyhow!( - "field {} already has {:?} enumeratedValues", - f.name, - usage - )); + return occupied_error(); } } else { match f.enumerated_values.as_mut_slice() { [] => f.enumerated_values.push(val), - [v] => { - if v.usage == Some(usage) || v.usage == Some(Usage::ReadWrite) { + [v] if v.usage == Some(usage) || v.usage == Some(Usage::ReadWrite) => { + if replace { + *v = val; + } else { + return occupied_error(); + } + } + [v] if v.usage.is_none() => match (access, usage) { + (Access::ReadWrite | Access::ReadWriteOnce, Usage::Read) => { + v.usage = Some(Usage::Write); + val.usage = Some(Usage::Read); + f.enumerated_values.push(val); + } + (Access::ReadWrite | Access::ReadWriteOnce, Usage::Write) => { + v.usage = Some(Usage::Read); + val.usage = Some(Usage::Write); + f.enumerated_values.push(val); + } + _ => { if replace { *v = val; } else { - return Err(anyhow!( - "field {} already has {:?} enumeratedValues", - f.name, - usage - )); + return occupied_error(); } - } else { - f.enumerated_values.push(val); } - } + }, + [_] => f.enumerated_values.push(val), [v1, v2] => { if replace { if v1.usage == Some(usage) { @@ -600,11 +616,7 @@ impl RegisterExt for Register { *v2 = val; } } else { - return Err(anyhow!( - "field {} already has {:?} enumeratedValues", - f.name, - usage - )); + return occupied_error(); } } _ => return Err(anyhow!("Incorrect enumeratedValues")), @@ -619,6 +631,7 @@ impl RegisterExt for Register { replace_if_exists = true; } + let reg_access = self.properties.access; if let Some(d) = fmod.get_str("_derivedFrom")? { // This is a derived enumeratedValues => Try to find the // original definition to extract its @@ -644,19 +657,22 @@ impl RegisterExt for Register { )); } }; - if usage != orig_usage { - return Err(anyhow!( - "enumeratedValues with different usage was found: {:?} != {:?}", - usage, - orig_usage - )); - } let evs = make_derived_enumerated_values(d)?; for ftag in self.iter_fields(fspec) { + let access = ftag.access.or(reg_access).unwrap_or_default(); + let checked_usage = check_usage(access, usage) + .with_context(|| format!("In field {}", ftag.name))?; + if checked_usage != orig_usage { + return Err(anyhow!( + "enumeratedValues with different usage was found: {:?} != {:?}", + usage, + orig_usage + )); + } if ftag.name == d { return Err(anyhow!("EnumeratedValues can't be derived from itself")); } - set_enum(ftag, evs.clone(), usage, true)?; + set_enum(ftag, evs.clone(), orig_usage, true, access)?; } } else { let offsets = self @@ -669,14 +685,23 @@ impl RegisterExt for Register { let (min_offset, name) = offsets.iter().min_by_key(|on| on.0).unwrap(); let name = make_ev_name(&name.replace("%s", ""), usage)?; for ftag in self.iter_fields(fspec) { + let access = ftag.access.or(reg_access).unwrap_or_default(); + let checked_usage = check_usage(access, usage) + .with_context(|| format!("In field {}", ftag.name))?; if ftag.bit_range.offset == *min_offset { let evs = make_ev_array(fmod)? .name(Some(name.clone())) - .usage(Some(usage)) + .usage(make_usage(access, checked_usage)) .build(VAL_LVL)?; - set_enum(ftag, evs, usage, replace_if_exists)?; + set_enum(ftag, evs, checked_usage, replace_if_exists, access)?; } else { - set_enum(ftag, make_derived_enumerated_values(&name)?, usage, true)?; + set_enum( + ftag, + make_derived_enumerated_values(&name)?, + checked_usage, + true, + access, + )?; } } } @@ -698,3 +723,27 @@ impl RegisterExt for Register { Ok(()) } } + +fn check_usage(access: Access, usage: Option) -> anyhow::Result { + Ok(match (access, usage) { + (Access::ReadWrite | Access::ReadWriteOnce, usage) => usage.unwrap_or_default(), + (Access::ReadOnly, None | Some(Usage::Read)) => Usage::Read, + (Access::WriteOnly | Access::WriteOnce, None | Some(Usage::Write)) => Usage::Write, + (_, _) => { + return Err(anyhow!( + "EnumeratedValues usage {:?} is incompatible with access {:?}", + usage, + access + )); + } + }) +} + +fn make_usage(access: Access, usage: Usage) -> Option { + match (access, usage) { + (Access::ReadWrite | Access::ReadWriteOnce, Usage::ReadWrite) + | (Access::ReadOnly, Usage::Read) + | (Access::WriteOnly | Access::WriteOnce, Usage::Write) => None, + _ => Some(usage), + } +} From b230b2b594682a4b6fa6cabbc8d1b8b26ebab60f Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sat, 14 May 2022 10:11:30 +0300 Subject: [PATCH 2/5] always add usage --- src/patch/register.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/patch/register.rs b/src/patch/register.rs index 2d60495d..96a08a7e 100644 --- a/src/patch/register.rs +++ b/src/patch/register.rs @@ -691,7 +691,9 @@ impl RegisterExt for Register { if ftag.bit_range.offset == *min_offset { let evs = make_ev_array(fmod)? .name(Some(name.clone())) - .usage(make_usage(access, checked_usage)) + // TODO: uncomment when python version reaches same functionality + //.usage(make_usage(access, checked_usage)) + .usage(Some(checked_usage)) .build(VAL_LVL)?; set_enum(ftag, evs, checked_usage, replace_if_exists, access)?; } else { @@ -739,6 +741,7 @@ fn check_usage(access: Access, usage: Option) -> anyhow::Result { }) } +#[allow(unused)] fn make_usage(access: Access, usage: Usage) -> Option { match (access, usage) { (Access::ReadWrite | Access::ReadWriteOnce, Usage::ReadWrite) From b1096f179add31e80f53d55d52d51a3e440b2efe Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 13 May 2022 19:06:50 +0300 Subject: [PATCH 3/5] expand_properties --- Cargo.toml | 2 +- src/cli.rs | 6 ++++++ src/convert/convert_cli.rs | 6 +++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 54fc3bef..fd446f0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ clap = { version = "3.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] } quick-xml = { version = "0.18", features = ["serialize"] } svd-rs = { version = "0.13.2", features = ["serde", "derive-from"] } -svd-parser = { version = "0.13.2", features = ["expand"] } +svd-parser = { version = "0.13.4", features = ["expand"] } svd-encoder = "0.13.1" yaml-rust = "0.4" serde_yaml = "0.8.23" diff --git a/src/cli.rs b/src/cli.rs index 333a26a2..f8019c63 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -64,6 +64,10 @@ enum Command { #[clap(long)] expand: bool, + /// Take size, access, reset_value, reset_mask from parents if absent in register + #[clap(long)] + expand_properties: bool, + /// Skip enumeratedValues and writeConstraints during parsing (XML input only) #[clap(long)] ignore_enums: bool, @@ -88,6 +92,7 @@ impl Command { input_format, output_format, expand, + expand_properties, ignore_enums, } => convert_cli::convert( in_path, @@ -95,6 +100,7 @@ impl Command { *input_format, *output_format, *expand, + *expand_properties, *ignore_enums, )?, } diff --git a/src/convert/convert_cli.rs b/src/convert/convert_cli.rs index 1f1ca4af..b05ad137 100644 --- a/src/convert/convert_cli.rs +++ b/src/convert/convert_cli.rs @@ -49,6 +49,7 @@ pub fn convert( input_format: Option, output_format: Option, expand: bool, + expand_properties: bool, ignore_enums: bool, ) -> Result<()> { let input_format = match input_format { @@ -69,7 +70,7 @@ pub fn convert( let mut input = String::new(); File::open(in_path)?.read_to_string(&mut input)?; - let device = match input_format { + let mut device = match input_format { InputFormat::Xml => svd_parser::parse_with_config( &input, &svd_parser::Config::default().ignore_enums(ignore_enums), @@ -77,6 +78,9 @@ pub fn convert( InputFormat::Yaml => serde_yaml::from_str(&input)?, InputFormat::Json => serde_json::from_str(&input)?, }; + if expand_properties { + svd_parser::expand_properties(&mut device); + } let device = if expand { svd_parser::expand(&device)? } else { From 5c169cde2130ea3802b9e115540b52d267198484 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 13 May 2022 19:27:37 +0300 Subject: [PATCH 4/5] changelog --- CHANGELOG-rust.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG-rust.md b/CHANGELOG-rust.md index 8f2b6e43..27b24387 100644 --- a/CHANGELOG-rust.md +++ b/CHANGELOG-rust.md @@ -5,6 +5,9 @@ This changelog tracks the Rust `svdtools` project. See ## [Unreleased] +* Use `svd-parser` 0.13.4, add `expand_properties` option in `convert` +* `patch`: check enum `usage`, don't add it if unneeded + ## [v0.2.3] 2022-05-01 * Add support for `modifiedWriteValues` & `readAction` for fields From 237aeecdcab7d273a8d9c7136e2217fc5052ee92 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 13 May 2022 20:08:53 +0300 Subject: [PATCH 5/5] release action --- .github/workflows/ci.yaml | 7 +++- .github/workflows/release.yml | 77 ++++++++++++++++++++++++++++++++++ .github/workflows/rust-ci.yaml | 17 ++++---- CHANGELOG-rust.md | 1 + 4 files changed, 93 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1136054b..4964405f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,5 +1,8 @@ name: CI +env: + SVDTOOLS: svd + on: push: branches: [ staging, trying, master ] @@ -11,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install Python uses: actions/setup-python@v2 with: @@ -40,7 +43,7 @@ jobs: - rp2040 steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install Rust uses: actions-rs/toolchain@v1 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..a15c4a40 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,77 @@ +name: release +on: + push: + branches: + - master + tags: + - v*.*.* + workflow_dispatch: + +jobs: + build: + strategy: + matrix: + include: + - { target: x86_64-unknown-linux-gnu, os: ubuntu-20.04, suffix: .gz } + - { target: x86_64-apple-darwin, os: macos-latest, suffix: .gz } + - { target: aarch64-apple-darwin, os: macos-latest, suffix: .gz } + - { target: x86_64-pc-windows-msvc, os: windows-latest, suffix: .zip } + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + target: ${{ matrix.target }} + override: true + - name: Cache Dependencies + uses: Swatinem/rust-cache@v1 + with: + key: ${{ matrix.target }} + - uses: actions-rs/cargo@v1 + with: + command: build + args: --target ${{ matrix.target }} --release + + - name: (Not Windows) Move executables and compress + if: ${{ matrix.os != 'windows-latest' }} + run: gzip -c target/${{ matrix.target }}/release/svdtools > svdtools-${{ matrix.target }}${{ matrix.suffix }} + + - name: (Windows) Move executables and compress + if: ${{ matrix.os == 'windows-latest' }} + run: Compress-Archive -Path target\${{ matrix.target }}\release\svdtools.exe -DestinationPath svdtools-${{ matrix.target }}${{ matrix.suffix }} + + - uses: actions/upload-artifact@v3 + with: + name: svdtools-${{ matrix.target }} + path: svdtools-${{ matrix.target }}${{ matrix.suffix }} + + release: + name: release + runs-on: ubuntu-latest + needs: [build] + steps: + - uses: actions/checkout@v3 + - uses: actions/download-artifact@v3 + with: + path: artifacts + - run: ls -R ./artifacts + + - name: Set current date as environment variable + run: echo "CURRENT_DATE=$(date +'%Y-%m-%d')" >> $GITHUB_ENV + + - id: changelog-reader + uses: mindsers/changelog-reader-action@v2.0.0 + with: + path: ./CHANGELOG-rust.md + version: ${{ (github.ref_type == 'tag' && github.ref_name) || 'Unreleased' }} + + - uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ steps.changelog-reader.outputs.version }} + name: ${{ (github.ref_type == 'tag' && steps.changelog-reader.outputs.version) || format('Prereleased {0}', env.CURRENT_DATE) }} + body: ${{ steps.changelog-reader.outputs.changes }} + prerelease: ${{ steps.changelog-reader.outputs.status == 'unreleased' }} + files: | + artifacts/**/* diff --git a/.github/workflows/rust-ci.yaml b/.github/workflows/rust-ci.yaml index 88439168..44e4773d 100644 --- a/.github/workflows/rust-ci.yaml +++ b/.github/workflows/rust-ci.yaml @@ -1,5 +1,8 @@ name: Rust CI +env: + SVDTOOLS: svdtools + on: push: branches: [ staging, trying, master ] @@ -13,7 +16,7 @@ jobs: RUSTFLAGS: "-D warnings" RUSTDOCFLAGS: "-D warnings" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: toolchain: stable @@ -26,7 +29,7 @@ jobs: RUSTFLAGS: "-D warnings" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: toolchain: stable @@ -38,7 +41,7 @@ jobs: RUSTFLAGS: "-D warnings" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: toolchain: stable @@ -52,7 +55,7 @@ jobs: name: Clippy runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: toolchain: stable @@ -65,7 +68,7 @@ jobs: name: Format runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: toolchain: stable @@ -80,7 +83,7 @@ jobs: - stm32 steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install Rust uses: actions-rs/toolchain@v1 with: @@ -92,4 +95,4 @@ jobs: run: | cargo install svdtools --path . - name: Check - run: env SVDTOOLS=svdtools bash tools/check_${{ matrix.target }}.sh + run: bash tools/check_${{ matrix.target }}.sh diff --git a/CHANGELOG-rust.md b/CHANGELOG-rust.md index 27b24387..cf4443b6 100644 --- a/CHANGELOG-rust.md +++ b/CHANGELOG-rust.md @@ -5,6 +5,7 @@ This changelog tracks the Rust `svdtools` project. See ## [Unreleased] +* Added action to build binaries and release for every version tag and latest commit * Use `svd-parser` 0.13.4, add `expand_properties` option in `convert` * `patch`: check enum `usage`, don't add it if unneeded