diff options
| -rw-r--r-- | stm32-metapac-gen/src/lib.rs | 228 |
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 @@ | |||
| 1 | use chiptool::generate::CommonModule; | 1 | use chiptool::generate::CommonModule; |
| 2 | use regex::Regex; | 2 | use regex::Regex; |
| 3 | use serde::Deserialize; | 3 | use serde::Deserialize; |
| 4 | use std::collections::{HashMap, HashSet}; | 4 | use std::collections::{BTreeMap, HashMap, HashSet}; |
| 5 | use std::env; | 5 | use std::env; |
| 6 | use std::fmt::Write as _; | 6 | use std::fmt::Write as _; |
| 7 | use std::fs; | 7 | use std::fs; |
| @@ -39,9 +39,9 @@ pub struct MemoryRegion { | |||
| 39 | #[derive(Debug, Eq, PartialEq, Clone, Deserialize)] | 39 | #[derive(Debug, Eq, PartialEq, Clone, Deserialize)] |
| 40 | pub struct Core { | 40 | pub 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 | ||
| 119 | fn find_reg_for_field<'c>( | 119 | fn 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 | ||
| 147 | fn make_peripheral_counts(out: &mut String, data: &HashMap<String, u8>) { | 141 | fn 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 | ||
| 161 | fn make_dma_channel_counts(out: &mut String, data: &HashMap<String, u8>) { | 155 | fn 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 | ||
| 756 | fn bytes_find(haystack: &[u8], needle: &[u8]) -> Option<usize> { | 733 | fn bytes_find(haystack: &[u8], needle: &[u8]) -> Option<usize> { |
| @@ -762,19 +739,40 @@ fn bytes_find(haystack: &[u8], needle: &[u8]) -> Option<usize> { | |||
| 762 | fn gen_memory_x(out_dir: &PathBuf, chip: &Chip) { | 739 | fn 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 | } |
