aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-08-04 15:15:08 +0200
committerGitHub <[email protected]>2021-08-04 15:15:08 +0200
commitf574e553950848456afc9aadffa8ed49cb1436fc (patch)
tree1a283b87de166dbeb796c80af35d53941a3927f8
parentde77dc11ca38ee7d52eb6c29a05af55ba1a4380c (diff)
parentf240edc5792bb976bb42e26164e8a0a9169f6ac5 (diff)
Merge pull request #331 from timokroeger/stm32-enable-bit
metapac: Improve enable bit search
-rw-r--r--stm32-metapac-gen/src/lib.rs228
1 files changed, 113 insertions, 115 deletions
diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs
index 5e0cc58d4..ae401bb67 100644
--- a/stm32-metapac-gen/src/lib.rs
+++ b/stm32-metapac-gen/src/lib.rs
@@ -1,7 +1,7 @@
1use chiptool::generate::CommonModule; 1use chiptool::generate::CommonModule;
2use regex::Regex; 2use regex::Regex;
3use serde::Deserialize; 3use serde::Deserialize;
4use std::collections::{HashMap, HashSet}; 4use std::collections::{BTreeMap, HashMap, HashSet};
5use std::env; 5use std::env;
6use std::fmt::Write as _; 6use std::fmt::Write as _;
7use std::fs; 7use std::fs;
@@ -39,9 +39,9 @@ pub struct MemoryRegion {
39#[derive(Debug, Eq, PartialEq, Clone, Deserialize)] 39#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
40pub struct Core { 40pub struct Core {
41 pub name: String, 41 pub name: String,
42 pub peripherals: HashMap<String, Peripheral>, 42 pub peripherals: BTreeMap<String, Peripheral>,
43 pub interrupts: HashMap<String, u32>, 43 pub interrupts: BTreeMap<String, u32>,
44 pub dma_channels: HashMap<String, DmaChannel>, 44 pub dma_channels: BTreeMap<String, DmaChannel>,
45} 45}
46 46
47#[derive(Debug, Eq, PartialEq, Clone, Deserialize)] 47#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
@@ -62,9 +62,9 @@ pub struct Peripheral {
62 #[serde(default)] 62 #[serde(default)]
63 pub pins: Vec<Pin>, 63 pub pins: Vec<Pin>,
64 #[serde(default)] 64 #[serde(default)]
65 pub dma_channels: HashMap<String, Vec<PeripheralDmaChannel>>, 65 pub dma_channels: BTreeMap<String, Vec<PeripheralDmaChannel>>,
66 #[serde(default)] 66 #[serde(default)]
67 pub interrupts: HashMap<String, String>, 67 pub interrupts: BTreeMap<String, String>,
68} 68}
69 69
70#[derive(Debug, Eq, PartialEq, Clone, Deserialize)] 70#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
@@ -118,33 +118,27 @@ impl BlockInfo {
118 118
119fn find_reg_for_field<'c>( 119fn find_reg_for_field<'c>(
120 rcc: &'c ir::IR, 120 rcc: &'c ir::IR,
121 reg_prefix: &str, 121 reg_regex: &str,
122 field_name: &str, 122 field_name: &str,
123) -> Option<(&'c str, &'c str)> { 123) -> Option<(&'c str, &'c str)> {
124 rcc.fieldsets.iter().find_map(|(name, fieldset)| { 124 let reg_regex = Regex::new(reg_regex).unwrap();
125
126 for (name, fieldset) in &rcc.fieldsets {
125 // Workaround for some families that prefix register aliases with C1_, which does 127 // Workaround for some families that prefix register aliases with C1_, which does
126 // not help matching for clock name. 128 // not help matching for clock name.
127 if name.starts_with("C1") || name.starts_with("C2") { 129 if !name.starts_with("C1") && !name.starts_with("C2") && reg_regex.is_match(name) {
128 None 130 for field in &fieldset.fields {
129 } else if name.starts_with(reg_prefix) { 131 if field_name == field.name {
130 fieldset 132 return Some((name.as_str(), field.name.as_str()));
131 .fields 133 }
132 .iter() 134 }
133 .find_map(|field| {
134 if field_name == field.name {
135 return Some(field.name.as_str());
136 } else {
137 None
138 }
139 })
140 .map(|n| (name.as_str(), n))
141 } else {
142 None
143 } 135 }
144 }) 136 }
137
138 None
145} 139}
146 140
147fn make_peripheral_counts(out: &mut String, data: &HashMap<String, u8>) { 141fn make_peripheral_counts(out: &mut String, data: &BTreeMap<String, u8>) {
148 write!( 142 write!(
149 out, 143 out,
150 "#[macro_export] 144 "#[macro_export]
@@ -158,7 +152,7 @@ macro_rules! peripheral_count {{
158 write!(out, " }}\n").unwrap(); 152 write!(out, " }}\n").unwrap();
159} 153}
160 154
161fn make_dma_channel_counts(out: &mut String, data: &HashMap<String, u8>) { 155fn make_dma_channel_counts(out: &mut String, data: &BTreeMap<String, u8>) {
162 write!( 156 write!(
163 out, 157 out,
164 "#[macro_export] 158 "#[macro_export]
@@ -219,7 +213,7 @@ pub fn gen(options: Options) {
219 println!("cwd: {:?}", env::current_dir()); 213 println!("cwd: {:?}", env::current_dir());
220 214
221 let mut all_peripheral_versions: HashSet<(String, String)> = HashSet::new(); 215 let mut all_peripheral_versions: HashSet<(String, String)> = HashSet::new();
222 let mut chip_cores: HashMap<String, Option<String>> = HashMap::new(); 216 let mut chip_cores: BTreeMap<String, Option<String>> = BTreeMap::new();
223 217
224 for chip_name in &options.chips { 218 for chip_name in &options.chips {
225 let mut s = chip_name.split('_'); 219 let mut s = chip_name.split('_');
@@ -291,7 +285,7 @@ pub fn gen(options: Options) {
291 } 285 }
292 }); 286 });
293 287
294 let mut peripheral_versions: HashMap<String, String> = HashMap::new(); 288 let mut peripheral_versions: BTreeMap<String, String> = BTreeMap::new();
295 let mut pin_table: Vec<Vec<String>> = Vec::new(); 289 let mut pin_table: Vec<Vec<String>> = Vec::new();
296 let mut interrupt_table: Vec<Vec<String>> = Vec::new(); 290 let mut interrupt_table: Vec<Vec<String>> = Vec::new();
297 let mut peripherals_table: Vec<Vec<String>> = Vec::new(); 291 let mut peripherals_table: Vec<Vec<String>> = Vec::new();
@@ -299,8 +293,8 @@ pub fn gen(options: Options) {
299 let mut peripheral_rcc_table: Vec<Vec<String>> = Vec::new(); 293 let mut peripheral_rcc_table: Vec<Vec<String>> = Vec::new();
300 let mut dma_channels_table: Vec<Vec<String>> = Vec::new(); 294 let mut dma_channels_table: Vec<Vec<String>> = Vec::new();
301 let mut peripheral_dma_channels_table: Vec<Vec<String>> = Vec::new(); 295 let mut peripheral_dma_channels_table: Vec<Vec<String>> = Vec::new();
302 let mut peripheral_counts: HashMap<String, u8> = HashMap::new(); 296 let mut peripheral_counts: BTreeMap<String, u8> = BTreeMap::new();
303 let mut dma_channel_counts: HashMap<String, u8> = HashMap::new(); 297 let mut dma_channel_counts: BTreeMap<String, u8> = BTreeMap::new();
304 let mut dbgmcu_table: Vec<Vec<String>> = Vec::new(); 298 let mut dbgmcu_table: Vec<Vec<String>> = Vec::new();
305 let mut gpio_rcc_table: Vec<Vec<String>> = Vec::new(); 299 let mut gpio_rcc_table: Vec<Vec<String>> = Vec::new();
306 let mut gpio_regs: HashSet<String> = HashSet::new(); 300 let mut gpio_regs: HashSet<String> = HashSet::new();
@@ -429,87 +423,72 @@ pub fn gen(options: Options) {
429 } 423 }
430 424
431 if let Some(rcc) = &rcc { 425 if let Some(rcc) = &rcc {
432 let clock_prefix: Option<&str> = if let Some(clock) = &p.clock { 426 // Workaround for clock registers being split on some chip families. Assume fields are
433 Some(clock) 427 // named after peripheral and look for first field matching and use that register.
434 } else if name.starts_with("TIM") { 428 let mut en = find_reg_for_field(&rcc, "^.+ENR\\d*$", &format!("{}EN", name));
435 // Not all peripherals like timers the clock hint due to insufficient information from 429 let mut rst = find_reg_for_field(&rcc, "^.+RSTR\\d*$", &format!("{}RST", name));
436 // chip definition. If clock is not specified, the first matching register with the 430
437 // expected field will be used. 431 if en.is_none() && name.ends_with("1") {
438 Some("") 432 en = find_reg_for_field(
439 } else { 433 &rcc,
440 None 434 "^.+ENR\\d*$",
441 }; 435 &format!("{}EN", &name[..name.len() - 1]),
442 436 );
443 if let Some(clock_prefix) = clock_prefix { 437 rst = find_reg_for_field(
444 // Workaround for clock registers being split on some chip families. Assume fields are 438 &rcc,
445 // named after peripheral and look for first field matching and use that register. 439 "^.+RSTR\\d*$",
446 let mut en = find_reg_for_field(&rcc, clock_prefix, &format!("{}EN", name)); 440 &format!("{}RST", &name[..name.len() - 1]),
447 let mut rst = 441 );
448 find_reg_for_field(&rcc, clock_prefix, &format!("{}RST", name)); 442 }
449
450 if en.is_none() && name.ends_with("1") {
451 en = find_reg_for_field(
452 &rcc,
453 clock_prefix,
454 &format!("{}EN", &name[..name.len() - 1]),
455 );
456 rst = find_reg_for_field(
457 &rcc,
458 clock_prefix,
459 &format!("{}RST", &name[..name.len() - 1]),
460 );
461 }
462
463 match (en, rst) {
464 (Some((enable_reg, enable_field)), reset_reg_field) => {
465 let clock = if clock_prefix.is_empty() {
466 let re = Regex::new("([A-Z]+\\d*).*").unwrap();
467 if !re.is_match(enable_reg) {
468 panic!(
469 "unable to derive clock name from register name {}",
470 enable_reg
471 );
472 } else {
473 let caps = re.captures(enable_reg).unwrap();
474 caps.get(1).unwrap().as_str()
475 }
476 } else {
477 clock_prefix
478 };
479
480 let clock = if name.starts_with("TIM") {
481 format!("{}_tim", clock.to_ascii_lowercase())
482 } else {
483 clock.to_ascii_lowercase()
484 };
485
486 let mut row = Vec::with_capacity(6);
487 row.push(name.clone());
488 row.push(clock);
489 row.push(enable_reg.to_ascii_lowercase());
490
491 if let Some((reset_reg, reset_field)) = reset_reg_field {
492 row.push(reset_reg.to_ascii_lowercase());
493 row.push(format!("set_{}", enable_field.to_ascii_lowercase()));
494 row.push(format!("set_{}", reset_field.to_ascii_lowercase()));
495 } else {
496 row.push(format!("set_{}", enable_field.to_ascii_lowercase()));
497 }
498 443
499 if !name.starts_with("GPIO") { 444 match (en, rst) {
500 peripheral_rcc_table.push(row); 445 (Some((enable_reg, enable_field)), reset_reg_field) => {
501 } else { 446 let clock = match &p.clock {
502 gpio_rcc_table.push(row); 447 Some(clock) => clock.as_str(),
503 gpio_regs.insert(enable_reg.to_ascii_lowercase()); 448 None => {
449 // No clock was specified, derive the clock name from the enable register name.
450 Regex::new("([A-Z]+\\d*).*")
451 .unwrap()
452 .captures(enable_reg)
453 .unwrap()
454 .get(1)
455 .unwrap()
456 .as_str()
504 } 457 }
458 };
459
460 let clock = if name.starts_with("TIM") {
461 format!("{}_tim", clock.to_ascii_lowercase())
462 } else {
463 clock.to_ascii_lowercase()
464 };
465
466 let mut row = Vec::with_capacity(6);
467 row.push(name.clone());
468 row.push(clock);
469 row.push(enable_reg.to_ascii_lowercase());
470
471 if let Some((reset_reg, reset_field)) = reset_reg_field {
472 row.push(reset_reg.to_ascii_lowercase());
473 row.push(format!("set_{}", enable_field.to_ascii_lowercase()));
474 row.push(format!("set_{}", reset_field.to_ascii_lowercase()));
475 } else {
476 row.push(format!("set_{}", enable_field.to_ascii_lowercase()));
505 } 477 }
506 (None, Some(_)) => { 478
507 print!("Unable to find enable register for {}", name) 479 if !name.starts_with("GPIO") {
508 } 480 peripheral_rcc_table.push(row);
509 (None, None) => { 481 } else {
510 print!("Unable to find enable and reset register for {}", name) 482 gpio_rcc_table.push(row);
483 gpio_regs.insert(enable_reg.to_ascii_lowercase());
511 } 484 }
512 } 485 }
486 (None, Some(_)) => {
487 println!("Unable to find enable register for {}", name)
488 }
489 (None, None) => {
490 println!("Unable to find enable and reset register for {}", name)
491 }
513 } 492 }
514 } 493 }
515 } 494 }
@@ -689,7 +668,6 @@ pub fn gen(options: Options) {
689 let re = Regex::new("# *! *\\[.*\\]").unwrap(); 668 let re = Regex::new("# *! *\\[.*\\]").unwrap();
690 let data = re.replace_all(&data, ""); 669 let data = re.replace_all(&data, "");
691 file.write_all(data.as_bytes()).unwrap(); 670 file.write_all(data.as_bytes()).unwrap();
692
693 } 671 }
694 672
695 // Generate src/lib_inner.rs 673 // Generate src/lib_inner.rs
@@ -750,7 +728,6 @@ pub fn gen(options: Options) {
750 728
751 // Generate build.rs 729 // Generate build.rs
752 fs::write(out_dir.join("build.rs"), include_bytes!("assets/build.rs")).unwrap(); 730 fs::write(out_dir.join("build.rs"), include_bytes!("assets/build.rs")).unwrap();
753
754} 731}
755 732
756fn bytes_find(haystack: &[u8], needle: &[u8]) -> Option<usize> { 733fn bytes_find(haystack: &[u8], needle: &[u8]) -> Option<usize> {
@@ -762,19 +739,40 @@ fn bytes_find(haystack: &[u8], needle: &[u8]) -> Option<usize> {
762fn gen_memory_x(out_dir: &PathBuf, chip: &Chip) { 739fn gen_memory_x(out_dir: &PathBuf, chip: &Chip) {
763 let mut memory_x = String::new(); 740 let mut memory_x = String::new();
764 741
765 let flash_bytes = chip.flash.regions.get("BANK_1").unwrap().bytes.unwrap_or(chip.flash.bytes); 742 let flash_bytes = chip
743 .flash
744 .regions
745 .get("BANK_1")
746 .unwrap()
747 .bytes
748 .unwrap_or(chip.flash.bytes);
766 let flash_origin = chip.flash.regions.get("BANK_1").unwrap().base; 749 let flash_origin = chip.flash.regions.get("BANK_1").unwrap().base;
767 750
768 let ram_bytes = chip.ram.regions.get("SRAM").unwrap().bytes.unwrap_or(chip.ram.bytes); 751 let ram_bytes = chip
752 .ram
753 .regions
754 .get("SRAM")
755 .unwrap()
756 .bytes
757 .unwrap_or(chip.ram.bytes);
769 let ram_origin = chip.ram.regions.get("SRAM").unwrap().base; 758 let ram_origin = chip.ram.regions.get("SRAM").unwrap().base;
770 759
771 write!(memory_x, "MEMORY\n{{\n").unwrap(); 760 write!(memory_x, "MEMORY\n{{\n").unwrap();
772 write!(memory_x, " FLASH : ORIGIN = 0x{:x}, LENGTH = {}\n", flash_origin, flash_bytes).unwrap(); 761 write!(
773 write!(memory_x, " RAM : ORIGIN = 0x{:x}, LENGTH = {}\n", ram_origin, ram_bytes).unwrap(); 762 memory_x,
763 " FLASH : ORIGIN = 0x{:x}, LENGTH = {}\n",
764 flash_origin, flash_bytes
765 )
766 .unwrap();
767 write!(
768 memory_x,
769 " RAM : ORIGIN = 0x{:x}, LENGTH = {}\n",
770 ram_origin, ram_bytes
771 )
772 .unwrap();
774 write!(memory_x, "}}").unwrap(); 773 write!(memory_x, "}}").unwrap();
775 774
776 fs::create_dir_all(out_dir.join("memory_x")).unwrap(); 775 fs::create_dir_all(out_dir.join("memory_x")).unwrap();
777 let mut file = File::create(out_dir.join("memory_x").join("memory.x")).unwrap(); 776 let mut file = File::create(out_dir.join("memory_x").join("memory.x")).unwrap();
778 file.write_all( memory_x.as_bytes() ).unwrap(); 777 file.write_all(memory_x.as_bytes()).unwrap();
779
780} 778}