From fba8b86005958fafa7e188b20b4212773ce912cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kr=C3=B6ger?= Date: Fri, 30 Jul 2021 17:06:58 +0200 Subject: [PATCH 1/7] BTreeMaps to preserve ordering of generated code Makes diffing of changes easier --- stm32-metapac-gen/src/lib.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index 5e0cc58d..8a2698d8 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -1,7 +1,7 @@ use chiptool::generate::CommonModule; use regex::Regex; use serde::Deserialize; -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeMap, HashMap, HashSet}; use std::env; use std::fmt::Write as _; use std::fs; @@ -39,9 +39,9 @@ pub struct MemoryRegion { #[derive(Debug, Eq, PartialEq, Clone, Deserialize)] pub struct Core { pub name: String, - pub peripherals: HashMap, - pub interrupts: HashMap, - pub dma_channels: HashMap, + pub peripherals: BTreeMap, + pub interrupts: BTreeMap, + pub dma_channels: BTreeMap, } #[derive(Debug, Eq, PartialEq, Clone, Deserialize)] @@ -62,9 +62,9 @@ pub struct Peripheral { #[serde(default)] pub pins: Vec, #[serde(default)] - pub dma_channels: HashMap>, + pub dma_channels: BTreeMap>, #[serde(default)] - pub interrupts: HashMap, + pub interrupts: BTreeMap, } #[derive(Debug, Eq, PartialEq, Clone, Deserialize)] @@ -144,7 +144,7 @@ fn find_reg_for_field<'c>( }) } -fn make_peripheral_counts(out: &mut String, data: &HashMap) { +fn make_peripheral_counts(out: &mut String, data: &BTreeMap) { write!( out, "#[macro_export] @@ -158,7 +158,7 @@ macro_rules! peripheral_count {{ write!(out, " }}\n").unwrap(); } -fn make_dma_channel_counts(out: &mut String, data: &HashMap) { +fn make_dma_channel_counts(out: &mut String, data: &BTreeMap) { write!( out, "#[macro_export] @@ -219,7 +219,7 @@ pub fn gen(options: Options) { println!("cwd: {:?}", env::current_dir()); let mut all_peripheral_versions: HashSet<(String, String)> = HashSet::new(); - let mut chip_cores: HashMap> = HashMap::new(); + let mut chip_cores: BTreeMap> = BTreeMap::new(); for chip_name in &options.chips { let mut s = chip_name.split('_'); @@ -291,7 +291,7 @@ pub fn gen(options: Options) { } }); - let mut peripheral_versions: HashMap = HashMap::new(); + let mut peripheral_versions: BTreeMap = BTreeMap::new(); let mut pin_table: Vec> = Vec::new(); let mut interrupt_table: Vec> = Vec::new(); let mut peripherals_table: Vec> = Vec::new(); @@ -299,8 +299,8 @@ pub fn gen(options: Options) { let mut peripheral_rcc_table: Vec> = Vec::new(); let mut dma_channels_table: Vec> = Vec::new(); let mut peripheral_dma_channels_table: Vec> = Vec::new(); - let mut peripheral_counts: HashMap = HashMap::new(); - let mut dma_channel_counts: HashMap = HashMap::new(); + let mut peripheral_counts: BTreeMap = BTreeMap::new(); + let mut dma_channel_counts: BTreeMap = BTreeMap::new(); let mut dbgmcu_table: Vec> = Vec::new(); let mut gpio_rcc_table: Vec> = Vec::new(); let mut gpio_regs: HashSet = HashSet::new(); @@ -504,10 +504,10 @@ pub fn gen(options: Options) { } } (None, Some(_)) => { - print!("Unable to find enable register for {}", name) + println!("Unable to find enable register for {}", name) } (None, None) => { - print!("Unable to find enable and reset register for {}", name) + println!("Unable to find enable and reset register for {}", name) } } } From 4e47b15daf5ac739fa9da12f9918e3b01eed3ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kr=C3=B6ger?= Date: Fri, 30 Jul 2021 14:30:32 +0200 Subject: [PATCH 2/7] Ignore the clock number for enable bit search The number has different meanings depending on family: stm32f0: RCC_APB2ENR - APB peripheral clock enable register 2 CLOCK: APB1 stm32f4: RCC_APB2ENR - RCC APB2 peripheral clock enable register CLOCK: APB2 Ignore the clock number and search all registers for a matching enable bit. --- stm32-metapac-gen/src/lib.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index 8a2698d8..d9ab92ee 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -441,21 +441,31 @@ pub fn gen(options: Options) { }; if let Some(clock_prefix) = clock_prefix { + // Ignore the numbers in clock name when searching for enable bits because clock + // names do not map cleanly to regsiter names. + // Example: + // stm32f0: RCC_APB2ENR - APB peripheral clock enable register 2 CLOCK: APB1 + // stm32f4: RCC_APB2ENR - RCC APB2 peripheral clock enable register CLOCK: APB2 + // + // Search for the enable bit in all available registers to support the stm32f0 case. + let search_clock_prefix = clock_prefix.trim_end_matches(char::is_numeric); + // Workaround for clock registers being split on some chip families. Assume fields are // named after peripheral and look for first field matching and use that register. - let mut en = find_reg_for_field(&rcc, clock_prefix, &format!("{}EN", name)); + let mut en = + find_reg_for_field(&rcc, search_clock_prefix, &format!("{}EN", name)); let mut rst = - find_reg_for_field(&rcc, clock_prefix, &format!("{}RST", name)); + find_reg_for_field(&rcc, search_clock_prefix, &format!("{}RST", name)); if en.is_none() && name.ends_with("1") { en = find_reg_for_field( &rcc, - clock_prefix, + search_clock_prefix, &format!("{}EN", &name[..name.len() - 1]), ); rst = find_reg_for_field( &rcc, - clock_prefix, + search_clock_prefix, &format!("{}RST", &name[..name.len() - 1]), ); } From c985c031d44a9f49aab90b786496ef4afddf69ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kr=C3=B6ger?= Date: Fri, 30 Jul 2021 17:17:38 +0200 Subject: [PATCH 3/7] Use a regex to match find enable and rst regs --- stm32-metapac-gen/src/lib.rs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index d9ab92ee..983ced91 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -118,7 +118,7 @@ impl BlockInfo { fn find_reg_for_field<'c>( rcc: &'c ir::IR, - reg_prefix: &str, + reg_regex: &str, field_name: &str, ) -> Option<(&'c str, &'c str)> { rcc.fieldsets.iter().find_map(|(name, fieldset)| { @@ -126,7 +126,7 @@ fn find_reg_for_field<'c>( // not help matching for clock name. if name.starts_with("C1") || name.starts_with("C2") { None - } else if name.starts_with(reg_prefix) { + } else if Regex::new(reg_regex).unwrap().is_match(name) { fieldset .fields .iter() @@ -441,31 +441,22 @@ pub fn gen(options: Options) { }; if let Some(clock_prefix) = clock_prefix { - // Ignore the numbers in clock name when searching for enable bits because clock - // names do not map cleanly to regsiter names. - // Example: - // stm32f0: RCC_APB2ENR - APB peripheral clock enable register 2 CLOCK: APB1 - // stm32f4: RCC_APB2ENR - RCC APB2 peripheral clock enable register CLOCK: APB2 - // - // Search for the enable bit in all available registers to support the stm32f0 case. - let search_clock_prefix = clock_prefix.trim_end_matches(char::is_numeric); - // Workaround for clock registers being split on some chip families. Assume fields are // named after peripheral and look for first field matching and use that register. let mut en = - find_reg_for_field(&rcc, search_clock_prefix, &format!("{}EN", name)); + find_reg_for_field(&rcc, "^.+ENR\\d*$", &format!("{}EN", name)); let mut rst = - find_reg_for_field(&rcc, search_clock_prefix, &format!("{}RST", name)); + find_reg_for_field(&rcc, "^.+RSTR\\d*$", &format!("{}RST", name)); if en.is_none() && name.ends_with("1") { en = find_reg_for_field( &rcc, - search_clock_prefix, + "^.+ENR\\d*$", &format!("{}EN", &name[..name.len() - 1]), ); rst = find_reg_for_field( &rcc, - search_clock_prefix, + "^.+RSTR\\d*$", &format!("{}RST", &name[..name.len() - 1]), ); } From 37536695e1790ff6aea7d97464251f1099d9fc85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kr=C3=B6ger?= Date: Wed, 4 Aug 2021 11:08:18 +0200 Subject: [PATCH 4/7] Refactor `find_reg_for_field()` --- stm32-metapac-gen/src/lib.rs | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index 983ced91..2398d5a8 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -121,27 +121,21 @@ fn find_reg_for_field<'c>( reg_regex: &str, field_name: &str, ) -> Option<(&'c str, &'c str)> { - rcc.fieldsets.iter().find_map(|(name, fieldset)| { + let reg_regex = Regex::new(reg_regex).unwrap(); + + for (name, fieldset) in &rcc.fieldsets { // Workaround for some families that prefix register aliases with C1_, which does // not help matching for clock name. - if name.starts_with("C1") || name.starts_with("C2") { - None - } else if Regex::new(reg_regex).unwrap().is_match(name) { - fieldset - .fields - .iter() - .find_map(|field| { - if field_name == field.name { - return Some(field.name.as_str()); - } else { - None - } - }) - .map(|n| (name.as_str(), n)) - } else { - None + if !name.starts_with("C1") && !name.starts_with("C2") && reg_regex.is_match(name) { + for field in &fieldset.fields { + if field_name == field.name { + return Some((name.as_str(), field.name.as_str())); + } + } } - }) + } + + None } fn make_peripheral_counts(out: &mut String, data: &BTreeMap) { From b36337b3d23e99a23968deb7e8d5c65119e9bf0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kr=C3=B6ger?= Date: Wed, 4 Aug 2021 12:29:20 +0200 Subject: [PATCH 5/7] Refactor bit search logic when no clock specified Always search for a enable bit, even when no clock is specified in the yaml. Try to derive the clock name from the register name. This change picked up USART2 for stm32wle which was missing the clock. --- stm32-metapac-gen/src/lib.rs | 140 +++++++++++++++-------------------- 1 file changed, 61 insertions(+), 79 deletions(-) diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index 2398d5a8..b10f250d 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -423,87 +423,69 @@ pub fn gen(options: Options) { } if let Some(rcc) = &rcc { - let clock_prefix: Option<&str> = if let Some(clock) = &p.clock { - Some(clock) - } else if name.starts_with("TIM") { - // Not all peripherals like timers the clock hint due to insufficient information from - // chip definition. If clock is not specified, the first matching register with the - // expected field will be used. - Some("") - } else { - None - }; + // Workaround for clock registers being split on some chip families. Assume fields are + // named after peripheral and look for first field matching and use that register. + let mut en = find_reg_for_field(&rcc, "^.+ENR\\d*$", &format!("{}EN", name)); + let mut rst = find_reg_for_field(&rcc, "^.+RSTR\\d*$", &format!("{}RST", name)); - if let Some(clock_prefix) = clock_prefix { - // Workaround for clock registers being split on some chip families. Assume fields are - // named after peripheral and look for first field matching and use that register. - let mut en = - find_reg_for_field(&rcc, "^.+ENR\\d*$", &format!("{}EN", name)); - let mut rst = - find_reg_for_field(&rcc, "^.+RSTR\\d*$", &format!("{}RST", name)); + if en.is_none() && name.ends_with("1") { + en = find_reg_for_field( + &rcc, + "^.+ENR\\d*$", + &format!("{}EN", &name[..name.len() - 1]), + ); + rst = find_reg_for_field( + &rcc, + "^.+RSTR\\d*$", + &format!("{}RST", &name[..name.len() - 1]), + ); + } - if en.is_none() && name.ends_with("1") { - en = find_reg_for_field( - &rcc, - "^.+ENR\\d*$", - &format!("{}EN", &name[..name.len() - 1]), - ); - rst = find_reg_for_field( - &rcc, - "^.+RSTR\\d*$", - &format!("{}RST", &name[..name.len() - 1]), - ); + match (en, rst) { + (Some((enable_reg, enable_field)), reset_reg_field) => { + let clock = match &p.clock { + Some(clock) => clock.as_str(), + None => { + // No clock was specified, derive the clock name from the enable register name. + let re = Regex::new("([A-Z]+\\d*).*").unwrap(); + let caps = re.captures(enable_reg).expect( + "unable to derive clock name from register name {}", + ); + caps.get(1).unwrap().as_str() + } + }; + + let clock = if name.starts_with("TIM") { + format!("{}_tim", clock.to_ascii_lowercase()) + } else { + clock.to_ascii_lowercase() + }; + + let mut row = Vec::with_capacity(6); + row.push(name.clone()); + row.push(clock); + row.push(enable_reg.to_ascii_lowercase()); + + if let Some((reset_reg, reset_field)) = reset_reg_field { + row.push(reset_reg.to_ascii_lowercase()); + row.push(format!("set_{}", enable_field.to_ascii_lowercase())); + row.push(format!("set_{}", reset_field.to_ascii_lowercase())); + } else { + row.push(format!("set_{}", enable_field.to_ascii_lowercase())); + } + + if !name.starts_with("GPIO") { + peripheral_rcc_table.push(row); + } else { + gpio_rcc_table.push(row); + gpio_regs.insert(enable_reg.to_ascii_lowercase()); + } } - - match (en, rst) { - (Some((enable_reg, enable_field)), reset_reg_field) => { - let clock = if clock_prefix.is_empty() { - let re = Regex::new("([A-Z]+\\d*).*").unwrap(); - if !re.is_match(enable_reg) { - panic!( - "unable to derive clock name from register name {}", - enable_reg - ); - } else { - let caps = re.captures(enable_reg).unwrap(); - caps.get(1).unwrap().as_str() - } - } else { - clock_prefix - }; - - let clock = if name.starts_with("TIM") { - format!("{}_tim", clock.to_ascii_lowercase()) - } else { - clock.to_ascii_lowercase() - }; - - let mut row = Vec::with_capacity(6); - row.push(name.clone()); - row.push(clock); - row.push(enable_reg.to_ascii_lowercase()); - - if let Some((reset_reg, reset_field)) = reset_reg_field { - row.push(reset_reg.to_ascii_lowercase()); - row.push(format!("set_{}", enable_field.to_ascii_lowercase())); - row.push(format!("set_{}", reset_field.to_ascii_lowercase())); - } else { - row.push(format!("set_{}", enable_field.to_ascii_lowercase())); - } - - if !name.starts_with("GPIO") { - peripheral_rcc_table.push(row); - } else { - gpio_rcc_table.push(row); - gpio_regs.insert(enable_reg.to_ascii_lowercase()); - } - } - (None, Some(_)) => { - println!("Unable to find enable register for {}", name) - } - (None, None) => { - println!("Unable to find enable and reset register for {}", name) - } + (None, Some(_)) => { + println!("Unable to find enable register for {}", name) + } + (None, None) => { + println!("Unable to find enable and reset register for {}", name) } } } @@ -770,6 +752,6 @@ fn gen_memory_x(out_dir: &PathBuf, chip: &Chip) { fs::create_dir_all(out_dir.join("memory_x")).unwrap(); let mut file = File::create(out_dir.join("memory_x").join("memory.x")).unwrap(); - file.write_all( memory_x.as_bytes() ).unwrap(); + file.write_all(memory_x.as_bytes()).unwrap(); } From e21faaeb47e84b57ffb748b289b5dcba6cc52118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kr=C3=B6ger?= Date: Wed, 4 Aug 2021 12:43:51 +0200 Subject: [PATCH 6/7] cargo fmt --- stm32-metapac-gen/src/lib.rs | 37 +++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index b10f250d..abeb6d84 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -446,8 +446,8 @@ pub fn gen(options: Options) { let clock = match &p.clock { Some(clock) => clock.as_str(), None => { - // No clock was specified, derive the clock name from the enable register name. - let re = Regex::new("([A-Z]+\\d*).*").unwrap(); + // No clock was specified, derive the clock name from the enable register name. + let re = Regex::new("([A-Z]+\\d*).*").unwrap(); let caps = re.captures(enable_reg).expect( "unable to derive clock name from register name {}", ); @@ -666,7 +666,6 @@ pub fn gen(options: Options) { let re = Regex::new("# *! *\\[.*\\]").unwrap(); let data = re.replace_all(&data, ""); file.write_all(data.as_bytes()).unwrap(); - } // Generate src/lib_inner.rs @@ -727,7 +726,6 @@ pub fn gen(options: Options) { // Generate build.rs fs::write(out_dir.join("build.rs"), include_bytes!("assets/build.rs")).unwrap(); - } fn bytes_find(haystack: &[u8], needle: &[u8]) -> Option { @@ -739,19 +737,40 @@ fn bytes_find(haystack: &[u8], needle: &[u8]) -> Option { fn gen_memory_x(out_dir: &PathBuf, chip: &Chip) { let mut memory_x = String::new(); - let flash_bytes = chip.flash.regions.get("BANK_1").unwrap().bytes.unwrap_or(chip.flash.bytes); + let flash_bytes = chip + .flash + .regions + .get("BANK_1") + .unwrap() + .bytes + .unwrap_or(chip.flash.bytes); let flash_origin = chip.flash.regions.get("BANK_1").unwrap().base; - let ram_bytes = chip.ram.regions.get("SRAM").unwrap().bytes.unwrap_or(chip.ram.bytes); + let ram_bytes = chip + .ram + .regions + .get("SRAM") + .unwrap() + .bytes + .unwrap_or(chip.ram.bytes); let ram_origin = chip.ram.regions.get("SRAM").unwrap().base; write!(memory_x, "MEMORY\n{{\n").unwrap(); - write!(memory_x, " FLASH : ORIGIN = 0x{:x}, LENGTH = {}\n", flash_origin, flash_bytes).unwrap(); - write!(memory_x, " RAM : ORIGIN = 0x{:x}, LENGTH = {}\n", ram_origin, ram_bytes).unwrap(); + write!( + memory_x, + " FLASH : ORIGIN = 0x{:x}, LENGTH = {}\n", + flash_origin, flash_bytes + ) + .unwrap(); + write!( + memory_x, + " RAM : ORIGIN = 0x{:x}, LENGTH = {}\n", + ram_origin, ram_bytes + ) + .unwrap(); write!(memory_x, "}}").unwrap(); fs::create_dir_all(out_dir.join("memory_x")).unwrap(); let mut file = File::create(out_dir.join("memory_x").join("memory.x")).unwrap(); file.write_all(memory_x.as_bytes()).unwrap(); - } From f240edc5792bb976bb42e26164e8a0a9169f6ac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Kr=C3=B6ger?= Date: Wed, 4 Aug 2021 12:51:05 +0200 Subject: [PATCH 7/7] Remove broken panic message --- stm32-metapac-gen/src/lib.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index abeb6d84..ae401bb6 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -447,11 +447,13 @@ pub fn gen(options: Options) { Some(clock) => clock.as_str(), None => { // No clock was specified, derive the clock name from the enable register name. - let re = Regex::new("([A-Z]+\\d*).*").unwrap(); - let caps = re.captures(enable_reg).expect( - "unable to derive clock name from register name {}", - ); - caps.get(1).unwrap().as_str() + Regex::new("([A-Z]+\\d*).*") + .unwrap() + .captures(enable_reg) + .unwrap() + .get(1) + .unwrap() + .as_str() } };