From dd663bd528d2ae2238b4fbb3595e030774173446 Mon Sep 17 00:00:00 2001 From: Nebojsa Sabovic Date: Sat, 10 Mar 2018 19:17:48 -0800 Subject: [PATCH 1/4] First pass at implementing derivedFrom. --- src/generate/peripheral.rs | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/generate/peripheral.rs b/src/generate/peripheral.rs index 06f6cd78..c7167135 100644 --- a/src/generate/peripheral.rs +++ b/src/generate/peripheral.rs @@ -12,25 +12,36 @@ use util::{self, ToSanitizedSnakeCase, ToSanitizedUpperCase, BITS_PER_BYTE}; use generate::register; pub fn render( - p: &Peripheral, + p_original: &Peripheral, all_peripherals: &[Peripheral], defaults: &Defaults, nightly: bool, ) -> Result> { let mut out = vec![]; + let p_derivedfrom = p_original.derived_from.as_ref().and_then(|s| { + all_peripherals.iter().find(|x| x.name == *s) + }); + + let p_merged = p_derivedfrom.map(|x| p_original.derive_from(x)); + let p = p_merged.as_ref().unwrap_or(p_original); + + if p_original.derived_from.is_some() && p_derivedfrom.is_none() { + eprintln!("Couldn't find derivedFrom original: {} for {}, skipping", + p_original.derived_from.as_ref().unwrap(), p_original.name); + return Ok(out); + } + let name_pc = Ident::new(&*p.name.to_sanitized_upper_case()); let address = util::hex(p.base_address); let description = util::respace(p.description.as_ref().unwrap_or(&p.name)); + let derive_regs = p_derivedfrom.is_some() && p_original.registers.is_none(); let name_sc = Ident::new(&*p.name.to_sanitized_snake_case()); - let (base, derived) = if let Some(base) = p.derived_from.as_ref() { - // TODO Verify that base exists - // TODO We don't handle inheritance style `derivedFrom`, we should raise - // an error in that case - (Ident::new(&*base.to_sanitized_snake_case()), true) + let base = if derive_regs { + Ident::new(&*p_derivedfrom.unwrap().name.to_sanitized_snake_case()); } else { - (name_sc.clone(), false) + name_sc.clone(); }; // Insert the peripheral structure @@ -56,9 +67,9 @@ pub fn render( } }); - // Derived peripherals do not require re-implementation, and will instead - // use a single definition of the non-derived version - if derived { + // Derived peripherals may not require re-implementation, and will instead + // use a single definition of the non-derived version. + if derive_regs { return Ok(out); } From 5e193ae78123f2173e398db010623e60b94d8c4a Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Wed, 14 Mar 2018 18:44:29 -0700 Subject: [PATCH 2/4] fixup semicolons --- src/generate/peripheral.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/generate/peripheral.rs b/src/generate/peripheral.rs index c7167135..0a977bdf 100644 --- a/src/generate/peripheral.rs +++ b/src/generate/peripheral.rs @@ -39,9 +39,9 @@ pub fn render( let name_sc = Ident::new(&*p.name.to_sanitized_snake_case()); let base = if derive_regs { - Ident::new(&*p_derivedfrom.unwrap().name.to_sanitized_snake_case()); + Ident::new(&*p_derivedfrom.unwrap().name.to_sanitized_snake_case()) } else { - name_sc.clone(); + name_sc.clone() }; // Insert the peripheral structure From cb134d2b48f8eec34dd752f2283e20694386cb69 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Wed, 14 Mar 2018 23:02:05 -0700 Subject: [PATCH 3/4] expand derived registers This is a very basic first cut at expanding registers with derivedFrom. This commit requires https://github.com/japaric/svd/pull/50 --- src/generate/peripheral.rs | 82 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/src/generate/peripheral.rs b/src/generate/peripheral.rs index 0a977bdf..b3c98590 100644 --- a/src/generate/peripheral.rs +++ b/src/generate/peripheral.rs @@ -1,9 +1,10 @@ use std::borrow::Cow; use std::cmp::Ordering; +use std::collections::HashMap; use either::Either; use quote::{ToTokens, Tokens}; -use svd::{Cluster, ClusterInfo, Defaults, Peripheral, Register}; +use svd::{Cluster, ClusterInfo, Defaults, Peripheral, Register, RegisterInfo}; use syn::{self, Ident}; use errors::*; @@ -23,7 +24,7 @@ pub fn render( all_peripherals.iter().find(|x| x.name == *s) }); - let p_merged = p_derivedfrom.map(|x| p_original.derive_from(x)); + let p_merged = p_derivedfrom.map(|ancestor| p_original.derive_from(ancestor)); let p = p_merged.as_ref().unwrap_or(p_original); if p_original.derived_from.is_some() && p_derivedfrom.is_none() { @@ -75,9 +76,84 @@ pub fn render( // erc: *E*ither *R*egister or *C*luster let ercs = p.registers.as_ref().map(|x| x.as_ref()).unwrap_or(&[][..]); - let registers: &[&Register] = &util::only_registers(&ercs)[..]; + + // make a pass to expand derived registers. Ideally, for the most minimal + // code size, we'd do some analysis to figure out if we can 100% reuse the + // code that we're deriving from. For the sake of proving the concept, we're + // just going to emit a second copy of the accessor code. It'll probably + // get inlined by the compiler anyway, right? :-) + + // Build a map so that we can look up registers within this peripheral + let mut reg_map = HashMap::new(); + for r in registers { + reg_map.insert(&r.name, r.clone()); + } + + // Compute the effective, derived version of a register given the definition + // with the derived_from property on it (`info`) and its `ancestor` + fn derive_reg_info(info: &RegisterInfo, ancestor: &RegisterInfo) -> RegisterInfo { + let mut derived = info.clone(); + + if derived.size.is_none() { + derived.size = ancestor.size.clone(); + } + if derived.access.is_none() { + derived.access = ancestor.access.clone(); + } + if derived.reset_value.is_none() { + derived.reset_value = ancestor.reset_value.clone(); + } + if derived.reset_mask.is_none() { + derived.reset_mask = ancestor.reset_mask.clone(); + } + if derived.fields.is_none() { + derived.fields = ancestor.fields.clone(); + } + if derived.write_constraint.is_none() { + derived.write_constraint = ancestor.write_constraint.clone(); + } + + derived + } + + // Build up an alternate erc list by expanding any derived registers + let mut alt_erc :Vec> = registers.iter().filter_map(|r| { + match r.derived_from { + Some(ref derived) => { + let ancestor = match reg_map.get(derived) { + Some(r) => r, + None => { + eprintln!("register {} derivedFrom missing register {}", r.name, derived); + return None + } + }; + + let d = match **ancestor { + Register::Array(ref info, ref array_info) => { + Some(Either::Left(Register::Array(derive_reg_info(*r, info), array_info.clone()))) + } + Register::Single(ref info) => { + Some(Either::Left(Register::Single(derive_reg_info(*r, info)))) + } + }; + + d + } + None => Some(Either::Left((*r).clone())), + } + }).collect(); + + // Now add the clusters to our alternate erc list + let clusters = util::only_clusters(ercs); + for cluster in &clusters { + alt_erc.push(Either::Right((*cluster).clone())); + } + + // And revise registers, clusters and ercs to refer to our expanded versions + let registers: &[&Register] = &util::only_registers(&alt_erc)[..]; let clusters = util::only_clusters(ercs); + let ercs = &alt_erc; // No `struct RegisterBlock` can be generated if registers.is_empty() && clusters.is_empty() { From 32d8b5e8e02325aa4d7e677cb321a08dd5674334 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Wed, 22 Aug 2018 17:13:00 -0700 Subject: [PATCH 4/4] point to svd master --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d14cf317..a0e47939 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,5 +33,5 @@ either = "1.0.3" error-chain = "0.11.0" inflections = "1.1.0" quote = "0.3.15" -svd-parser = "0.6" +svd-parser = { git = "https://github.com/japaric/svd" } syn = "0.11.11"