From 8f4999bb5414aa340ee388c6c799e79619d2eed4 Mon Sep 17 00:00:00 2001 From: Henrik Lievonen Date: Tue, 18 Jan 2022 23:02:09 +0200 Subject: [PATCH 1/3] Add --mark_range flag This flag allows implementing a marker trait for registers in specific memory addresses. These can then be used to implement methods on registers. One such example is providing atomic access to only some of the registers directly in the PAC. Currently this is done in HAL, but this loses the ability to use writer proxies. Moreover this allows keeping atomic and non-atomic usage in HAL more similar. --- src/generate/device.rs | 19 +++++++++++++++++++ src/generate/register.rs | 18 ++++++++++++++++++ src/main.rs | 29 ++++++++++++++++++++++++++++- src/util.rs | 20 +++++++++++++++++++- 4 files changed, 84 insertions(+), 2 deletions(-) diff --git a/src/generate/device.rs b/src/generate/device.rs index de0a2b8a..75664a1f 100644 --- a/src/generate/device.rs +++ b/src/generate/device.rs @@ -3,6 +3,7 @@ use proc_macro2::{Ident, Span, TokenStream}; use quote::{quote, ToTokens}; use log::debug; +use std::collections::HashSet; use std::fs::File; use std::io::Write; @@ -245,6 +246,24 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result = config.mark_ranges.iter().map(|m| m.name.as_str()).collect(); + for marker in unique_markers { + let marker = Ident::new(marker, Span::call_site()); + markers.extend(quote! { + #[doc = "Marker trait"] + pub trait #marker {} + }); + } + + out.extend(quote! { + #[doc(hidden)] + pub mod markers { + #markers + } + }); + let span = Span::call_site(); let take = match config.target { Target::CortexM => Some(Ident::new("cortex_m", span)), diff --git a/src/generate/register.rs b/src/generate/register.rs index bd673040..49d1747d 100644 --- a/src/generate/register.rs +++ b/src/generate/register.rs @@ -7,6 +7,7 @@ use core::u64; use log::warn; use proc_macro2::{Ident, Punct, Spacing, Span, TokenStream}; use quote::{quote, ToTokens}; +use std::collections::HashSet; use crate::util::{self, Config, ToSanitizedSnakeCase, ToSanitizedUpperCase, U32Ext}; use anyhow::{anyhow, Result}; @@ -48,6 +49,7 @@ pub fn render( let mut mod_items = TokenStream::new(); let mut r_impl_items = TokenStream::new(); let mut w_impl_items = TokenStream::new(); + let mut marker_impl_items = TokenStream::new(); let mut methods = vec![]; let can_read = access.can_read(); @@ -267,6 +269,22 @@ pub fn render( }); } + let address = peripheral.base_address + register.address_offset as u64; + let markers: HashSet<_> = config + .mark_ranges + .iter() + .filter(|m| m.start <= address && address < m.end) + .map(|m| m.name.as_str()) + .collect(); + for marker in markers { + let name = Ident::new(marker, span); + marker_impl_items.extend(quote! { + impl crate::markers::#name for #name_uc_spec {} + }); + } + + mod_items.extend(marker_impl_items); + out.extend(quote! { #[doc = #description] pub mod #name_sc #open diff --git a/src/main.rs b/src/main.rs index b8447017..f23480c8 100755 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ use clap::{App, Arg}; use svd2rust::{ generate, load_from, - util::{build_rs, Config, SourceType, Target}, + util::{build_rs, parse_address, Config, MarkRange, SourceType, Target}, }; fn run() -> Result<()> { @@ -103,6 +103,20 @@ fn run() -> Result<()> { .takes_value(true) .possible_values(&["off", "error", "warn", "info", "debug", "trace"]), ) + .arg( + Arg::with_name("mark_range") + .long("mark_range") + .multiple(true) + .number_of_values(3) + .help("Mark registers in given range with a marker trait") + .long_help( + "Mark registers in given range with a marker trait. +The first argument after the flag sets the name for the marker trait. +The second and third argument are the start and end addresses of registers +which this trait is applied for.", + ) + .value_names(&["trait", "range start", "range end"]), + ) .version(concat!( env!("CARGO_PKG_VERSION"), include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt")) @@ -168,6 +182,18 @@ fn run() -> Result<()> { source_type = SourceType::from_path(Path::new(file)) } + let mut mark_range_iter = cfg.values("mark_range", Filter::Arg).into_iter().flatten(); + let mut mark_ranges = Vec::new(); + while let (Some(name), Some(start), Some(end)) = ( + mark_range_iter.next(), + mark_range_iter.next(), + mark_range_iter.next(), + ) { + let start = parse_address(&start).context("Invalid range start")?; + let end = parse_address(&end).context("Invalid range end")?; + mark_ranges.push(MarkRange { name, start, end }); + } + let config = Config { target, nightly, @@ -179,6 +205,7 @@ fn run() -> Result<()> { strict, output_dir: path.clone(), source_type, + mark_ranges, }; info!("Parsing device from SVD file"); diff --git a/src/util.rs b/src/util.rs index a49f2ca0..7faaac68 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,4 +1,4 @@ -use std::borrow::Cow; +use std::{borrow::Cow, num::ParseIntError}; use crate::svd::{ Access, Cluster, Field, Register, RegisterCluster, RegisterInfo, RegisterProperties, @@ -28,6 +28,7 @@ pub struct Config { pub strict: bool, pub output_dir: PathBuf, pub source_type: SourceType, + pub mark_ranges: Vec, } impl Default for Config { @@ -43,10 +44,19 @@ impl Default for Config { strict: false, output_dir: PathBuf::from("."), source_type: SourceType::default(), + mark_ranges: Vec::new(), } } } +#[derive(Clone, PartialEq, Debug)] + +pub struct MarkRange { + pub name: String, + pub start: u64, + pub end: u64, +} + #[allow(clippy::upper_case_acronyms)] #[allow(non_camel_case_types)] #[derive(Clone, Copy, PartialEq, Debug)] @@ -435,3 +445,11 @@ impl FullName for RegisterInfo { } } } + +pub fn parse_address(addr: &str) -> Result { + if addr.starts_with("0x") { + u64::from_str_radix(&addr[2..], 16) + } else { + u64::from_str_radix(addr, 10) + } +} From d0f6075c4200d14a9e85390babb39f13bab9d48a Mon Sep 17 00:00:00 2001 From: Henrik Lievonen Date: Sun, 30 Jan 2022 00:46:09 +0200 Subject: [PATCH 2/3] Update long help for --mark_range --- src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index f23480c8..361738ad 100755 --- a/src/main.rs +++ b/src/main.rs @@ -110,10 +110,10 @@ fn run() -> Result<()> { .number_of_values(3) .help("Mark registers in given range with a marker trait") .long_help( - "Mark registers in given range with a marker trait. -The first argument after the flag sets the name for the marker trait. -The second and third argument are the start and end addresses of registers -which this trait is applied for.", +"Mark registers in given range with a marker trait. For example to mark registers +in the second 1MB block of RAM, use + --mark_range SecondMbMarker 0x100000 0x200000 +The ranges are given as half-open intervals.", ) .value_names(&["trait", "range start", "range end"]), ) From 83c458487c155cc7a24f71bc976a575a4e016ebf Mon Sep 17 00:00:00 2001 From: Henrik Lievonen Date: Sun, 30 Jan 2022 00:46:49 +0200 Subject: [PATCH 3/3] Fix clippy warnings --- src/util.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/util.rs b/src/util.rs index 7faaac68..a8e67f0e 100644 --- a/src/util.rs +++ b/src/util.rs @@ -447,9 +447,10 @@ impl FullName for RegisterInfo { } pub fn parse_address(addr: &str) -> Result { - if addr.starts_with("0x") { - u64::from_str_radix(&addr[2..], 16) + if let Some(addr) = addr.strip_prefix("0x") { + u64::from_str_radix(addr, 16) } else { + #[allow(clippy::from_str_radix_10)] // Be explicit of the radix u64::from_str_radix(addr, 10) } }