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..361738ad 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. 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"]), + ) .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..a8e67f0e 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,12 @@ impl FullName for RegisterInfo { } } } + +pub fn parse_address(addr: &str) -> Result { + 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) + } +}