From ba962b3ca16b91158de30089cb75490e4a00f720 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 05:46:16 +0100 Subject: [PATCH 1/7] Support multiple flash regions, including OTP --- stm32-data-gen/src/chips.rs | 36 +++++---- stm32-data-gen/src/memory.rs | 111 +++++++++++++++++++------- stm32-data-serde/src/lib.rs | 1 + stm32-metapac-gen/res/src/metadata.rs | 1 + stm32-metapac-gen/src/data.rs | 2 + stm32-metapac-gen/src/lib.rs | 51 +++++++++--- 6 files changed, 148 insertions(+), 54 deletions(-) diff --git a/stm32-data-gen/src/chips.rs b/stm32-data-gen/src/chips.rs index ff585d2..a438524 100644 --- a/stm32-data-gen/src/chips.rs +++ b/stm32-data-gen/src/chips.rs @@ -988,7 +988,7 @@ fn process_chip( let mut memory_regions = Vec::new(); let mut found = HashSet::<&str>::new(); for each in ["FLASH", "FLASH_BANK1", "FLASH_BANK2", "D1_AXIFLASH", "D1_AXIICP"] { - if let Some(address) = h.defines.get("all").unwrap().0.get(&format!("{each}_BASE")) { + if let Some(_address) = h.defines.get("all").unwrap().0.get(&format!("{each}_BASE")) { let key = match each { "FLASH" => "BANK_1", "FLASH_BANK1" => "BANK_1", @@ -1001,20 +1001,28 @@ fn process_chip( } found.insert(key); - let size = if key == "BANK_1" || key == "BANK_2" { - let size = memories.determine_flash_size(chip_name); - std::cmp::min(size, flash_total) - } else { - 0 - }; + for region in memories.determine_flash_regions(chip_name) { + let size = if key == "BANK_1" || key == "BANK_2" { + let size = region.bytes; + std::cmp::min(size, flash_total) + } else { + 0 + }; - memory_regions.push(stm32_data_serde::chip::Memory { - name: key.to_string(), - kind: stm32_data_serde::chip::memory::Kind::Flash, - address: u32::try_from(*address).unwrap(), - size, - settings: Some(memories.determine_flash_settings(chip_name)), - }); + let kind = match region.bank { + memory::FlashBank::Bank1 => stm32_data_serde::chip::memory::Kind::Flash, + memory::FlashBank::Bank2 => stm32_data_serde::chip::memory::Kind::Flash, + memory::FlashBank::Otp => stm32_data_serde::chip::memory::Kind::Otp, + }; + + memory_regions.push(stm32_data_serde::chip::Memory { + name: region.name.clone(), + kind, + address: region.address, + size, + settings: Some(region.settings.clone()), + }) + } } } let mut found = HashSet::new(); diff --git a/stm32-data-gen/src/memory.rs b/stm32-data-gen/src/memory.rs index 0f5a891..7a1ec16 100644 --- a/stm32-data-gen/src/memory.rs +++ b/stm32-data-gen/src/memory.rs @@ -5,7 +5,7 @@ struct Memory { pub device_id: u16, pub names: Vec, pub ram: Ram, - pub flash: Option, + pub flash: Vec, } #[derive(Clone, Copy, Debug, PartialEq)] @@ -15,12 +15,21 @@ struct Ram { } #[derive(Clone, Debug, PartialEq)] -struct Flash { +pub struct FlashRegion { + pub bank: FlashBank, + pub name: String, pub address: u32, pub bytes: u32, pub settings: stm32_data_serde::chip::memory::Settings, } +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum FlashBank { + Bank1, + Bank2, + Otp, +} + fn splat_names(base: &str, parts: Vec<&str>) -> Vec { let mut names = Vec::new(); for part in parts { @@ -148,6 +157,8 @@ mod xml { pub struct Configuration { #[serde(rename = "Parameters", default)] pub parameters: Option, + #[serde(rename = "Organization", default)] + pub organization: Option, #[serde(rename = "Allignement", deserialize_with = "opt_from_hex", default)] pub allignement: Option, #[serde(rename = "Bank")] @@ -157,7 +168,7 @@ mod xml { mod configuration { use serde::Deserialize; - use super::super::super::super::super::from_hex; + use super::super::super::super::super::{from_hex, opt_from_hex}; #[derive(Debug, Deserialize, PartialEq)] pub struct Parameters { @@ -165,10 +176,14 @@ mod xml { pub address: u32, #[serde(deserialize_with = "from_hex")] pub size: u32, + #[serde(deserialize_with = "opt_from_hex", default)] + pub occurence: Option, } #[derive(Debug, Deserialize, PartialEq)] pub struct Bank { + #[serde(default)] + pub name: Option, #[serde(rename = "Field", default)] pub field: Vec, } @@ -199,6 +214,7 @@ impl Memories { paths.sort(); let mut memories = Vec::new(); + let alphabet: Vec = (b'A'..=b'Z').map(|c| c as char).collect(); for f in paths { // println!("Parsing {f:?}"); @@ -210,7 +226,7 @@ impl Memories { let names = split_names(&parsed.device.name); let mut ram = None; - let mut flash = None; + let mut flash = vec![]; for peripheral in parsed.device.peripherals.peripharal { if peripheral.name == "Embedded SRAM" && ram.is_none() { @@ -222,21 +238,60 @@ impl Memories { }); } - if peripheral.name == "Embedded Flash" && flash.is_none() { - let config = peripheral.configuration.first().unwrap(); + enum BlockKind { + Main, + Otp, + } + let kind = match peripheral.name.as_str() { + "Embedded Flash" => Some(BlockKind::Main), + "OTP" => Some(BlockKind::Otp), + _ => None, + }; + + if let Some(kind) = kind { + // Use single bank alignment if both single and dual is available + let config = peripheral + .configuration + .iter() + .find(|c| c.organization.as_ref().map(|x| x.as_str()).unwrap_or_default() == "Single") + .unwrap_or_else(|| peripheral.configuration.first().unwrap()); let parameters = config.parameters.as_ref().unwrap(); let bank = config.bank.first().unwrap(); - let erase_size = bank.field.iter().map(|field| field.parameters.size).max().unwrap(); - flash = Some(Flash { - address: parameters.address, - bytes: parameters.size, - settings: stm32_data_serde::chip::memory::Settings { - erase_value: peripheral.erased_value.unwrap(), - write_size: config.allignement.unwrap(), - erase_size, + let flash_bank = match kind { + BlockKind::Main => match bank.name.as_ref().map(|x| x.as_str()) { + Some("Bank 1") => FlashBank::Bank1, + Some("Bank 2") => FlashBank::Bank2, + None => FlashBank::Bank1, + _ => unimplemented!(), }, - }); + BlockKind::Otp => FlashBank::Otp, + }; + + let erase_value = peripheral.erased_value.unwrap(); + let write_size = config.allignement.unwrap(); + flash.extend(bank.field.iter().enumerate().map(|(index, field)| { + let name = match kind { + BlockKind::Main => format!("MAIN{}", alphabet[index]).to_string(), + BlockKind::Otp => "OTP".to_string(), + }; + let bytes = if let Some(occurence) = field.parameters.occurence { + occurence * field.parameters.size + } else { + parameters.size + }; + FlashRegion { + bank: flash_bank, + name, + address: field.parameters.address, + bytes, + settings: stm32_data_serde::chip::memory::Settings { + erase_value, + write_size, + erase_size: field.parameters.size, + }, + } + })); } } @@ -256,7 +311,9 @@ impl Memories { address: 0x20000000, bytes: 64 * 1024, }, - flash: Some(Flash { + flash: vec![FlashRegion { + bank: FlashBank::Bank1, + name: "MAINA".to_string(), address: 0x08000000, bytes: 384 * 1024, settings: stm32_data_serde::chip::memory::Settings { @@ -264,7 +321,7 @@ impl Memories { write_size: 8, erase_size: 2048, }, - }), + }], }); memories.push(Memory { @@ -274,7 +331,9 @@ impl Memories { address: 0x20000000, bytes: 80 * 1024, }, - flash: Some(Flash { + flash: vec![FlashRegion { + bank: FlashBank::Bank1, + name: "MAINA".to_string(), address: 0x08000000, bytes: 384 * 1024, settings: stm32_data_serde::chip::memory::Settings { @@ -282,7 +341,7 @@ impl Memories { write_size: 8, erase_size: 2048, }, - }), + }], }); memories.push(Memory { @@ -292,7 +351,9 @@ impl Memories { address: 0x20000000, bytes: 32 * 1024, }, - flash: Some(Flash { + flash: vec![FlashRegion { + bank: FlashBank::Bank1, + name: "MAINA".to_string(), address: 0x08000000, bytes: 4 * 1024, settings: stm32_data_serde::chip::memory::Settings { @@ -300,7 +361,7 @@ impl Memories { write_size: 4, erase_size: 256, }, - }), + }], }); Ok(Self(memories)) @@ -321,12 +382,8 @@ impl Memories { self.lookup_chip(chip_name).ram.bytes } - pub fn determine_flash_size(&self, chip_name: &str) -> u32 { - self.lookup_chip(chip_name).flash.as_ref().unwrap().bytes - } - - pub fn determine_flash_settings(&self, chip_name: &str) -> stm32_data_serde::chip::memory::Settings { - self.lookup_chip(chip_name).flash.as_ref().unwrap().settings.clone() + pub fn determine_flash_regions(&self, chip_name: &str) -> &[FlashRegion] { + self.lookup_chip(chip_name).flash.as_slice() } pub fn determine_device_id(&self, chip_name: &str) -> u16 { diff --git a/stm32-data-serde/src/lib.rs b/stm32-data-serde/src/lib.rs index dd44b07..def90e0 100644 --- a/stm32-data-serde/src/lib.rs +++ b/stm32-data-serde/src/lib.rs @@ -40,6 +40,7 @@ pub mod chip { pub enum Kind { Flash, Ram, + Otp, } #[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord, Serialize, Deserialize)] diff --git a/stm32-metapac-gen/res/src/metadata.rs b/stm32-metapac-gen/res/src/metadata.rs index 2342765..1cbdfff 100644 --- a/stm32-metapac-gen/res/src/metadata.rs +++ b/stm32-metapac-gen/res/src/metadata.rs @@ -30,6 +30,7 @@ pub struct FlashSettings { pub enum MemoryRegionKind { Flash, Ram, + Otp, } #[derive(Debug, Eq, PartialEq, Clone)] diff --git a/stm32-metapac-gen/src/data.rs b/stm32-metapac-gen/src/data.rs index 38e85d6..bc3ccc6 100644 --- a/stm32-metapac-gen/src/data.rs +++ b/stm32-metapac-gen/src/data.rs @@ -32,6 +32,8 @@ pub enum MemoryRegionKind { Flash, #[serde(rename = "ram")] Ram, + #[serde(rename = "otp")] + Otp, } #[derive(Debug, Eq, PartialEq, Clone, Deserialize)] diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index 0443e3e..f5795e7 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -117,13 +117,20 @@ impl Gen { } writeln!(&mut extra, "pub const CORE_INDEX: usize = {};", core_index).unwrap(); - let flash = chip.memory.iter().find(|r| r.name == "BANK_1").unwrap(); - let settings = flash.settings.as_ref().unwrap(); - writeln!(&mut extra, "pub const FLASH_BASE: usize = {};", flash.address).unwrap(); - writeln!(&mut extra, "pub const FLASH_SIZE: usize = {};", flash.size).unwrap(); - writeln!(&mut extra, "pub const ERASE_SIZE: usize = {};", settings.erase_size).unwrap(); - writeln!(&mut extra, "pub const WRITE_SIZE: usize = {};", settings.write_size).unwrap(); - writeln!(&mut extra, "pub const ERASE_VALUE: u8 = {};", settings.erase_value).unwrap(); + let flash_regions: Vec<&MemoryRegion> = chip + .memory + .iter() + .filter(|x| x.kind == MemoryRegionKind::Flash) + .collect(); + let first_flash = flash_regions.first().unwrap(); + let total_flash_size = flash_regions + .iter() + .map(|x| x.size) + .reduce(|acc, item| acc + item) + .unwrap(); + + writeln!(&mut extra, "pub const FLASH_BASE: usize = {};", first_flash.address).unwrap(); + writeln!(&mut extra, "pub const FLASH_SIZE: usize = {};", total_flash_size).unwrap(); // Cleanups! transform::sort::Sort {}.run(&mut ir).unwrap(); @@ -336,6 +343,7 @@ fn stringify(metadata: T) -> String { metadata = metadata.replace(": [", ": &["); metadata = metadata.replace("kind: Ram", "kind: MemoryRegionKind::Ram"); metadata = metadata.replace("kind: Flash", "kind: MemoryRegionKind::Flash"); + metadata = metadata.replace("kind: Otp", "kind: MemoryRegionKind::Otp"); metadata } @@ -348,22 +356,39 @@ fn gen_opts() -> generate::Options { fn gen_memory_x(out_dir: &Path, chip: &Chip) { let mut memory_x = String::new(); - let flash = chip.memory.iter().find(|r| r.name == "BANK_1").unwrap(); - let ram = chip.memory.iter().find(|r| r.name == "SRAM").unwrap(); + let flash = chip.memory.iter().filter(|r| r.kind == MemoryRegionKind::Flash); + let (flash_address, flash_size) = flash + .clone() + .map(|r| (r.address, r.size)) + .reduce(|acc, el| (u32::min(acc.0, el.0), acc.1 + el.1)) + .unwrap(); + let ram = chip.memory.iter().find(|r| r.kind == MemoryRegionKind::Ram).unwrap(); + let otp = chip.memory.iter().find(|r| r.kind == MemoryRegionKind::Otp); write!(memory_x, "MEMORY\n{{\n").unwrap(); writeln!( memory_x, - " FLASH : ORIGIN = 0x{:x}, LENGTH = {}", - flash.address, flash.size, + " FLASH : ORIGIN = 0x{:08x}, LENGTH = {:>4}K /* {} */", + flash_address, + flash_size / 1024, + flash.map(|x| x.name.as_ref()).collect::>().join(", ") ) .unwrap(); writeln!( memory_x, - " RAM : ORIGIN = 0x{:x}, LENGTH = {}", - ram.address, ram.size, + " RAM : ORIGIN = 0x{:08x}, LENGTH = {:>4}K", + ram.address, + ram.size / 1024, ) .unwrap(); + if let Some(otp) = otp { + writeln!( + memory_x, + " OTP : ORIGIN = 0x{:08x}, LENGTH = {:>4}", + otp.address, otp.size, + ) + .unwrap(); + } write!(memory_x, "}}").unwrap(); fs::create_dir_all(out_dir.join("memory_x")).unwrap(); From b9d1c2a2aba4f5ef529554919a48d6bf19806c57 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 07:40:42 +0100 Subject: [PATCH 2/7] Prefix memory region names with bank --- stm32-data-gen/src/chips.rs | 70 +++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/stm32-data-gen/src/chips.rs b/stm32-data-gen/src/chips.rs index a438524..c93f353 100644 --- a/stm32-data-gen/src/chips.rs +++ b/stm32-data-gen/src/chips.rs @@ -987,12 +987,19 @@ fn process_chip( let ram_total = chip.ram * 1024; let mut memory_regions = Vec::new(); let mut found = HashSet::<&str>::new(); - for each in ["FLASH", "FLASH_BANK1", "FLASH_BANK2", "D1_AXIFLASH", "D1_AXIICP"] { - if let Some(_address) = h.defines.get("all").unwrap().0.get(&format!("{each}_BASE")) { + for each in [ + "FLASH_BANK1", + "FLASH_BANK2", + "FLASH", + "FLASH_OTP", + "D1_AXIFLASH", + "D1_AXIICP", + ] { + if let Some(address) = h.defines.get("all").unwrap().0.get(&format!("{each}_BASE")) { let key = match each { - "FLASH" => "BANK_1", - "FLASH_BANK1" => "BANK_1", - "FLASH_BANK2" => "BANK_2", + "FLASH" => "BANK1", + "FLASH_BANK1" => "BANK1", + "FLASH_BANK2" => "BANK2", each => each, }; @@ -1001,27 +1008,46 @@ fn process_chip( } found.insert(key); - for region in memories.determine_flash_regions(chip_name) { - let size = if key == "BANK_1" || key == "BANK_2" { - let size = region.bytes; - std::cmp::min(size, flash_total) + if key == "FLASH_OTP" { + if let Some(region) = memories + .determine_flash_regions(chip_name) + .iter() + .find(|x| x.bank == memory::FlashBank::Otp) + { + memory_regions.push(stm32_data_serde::chip::Memory { + name: region.name.clone(), + kind: stm32_data_serde::chip::memory::Kind::Otp, + address: u32::try_from(*address).unwrap(), + size: region.bytes, + settings: Some(region.settings.clone()), + }) + } + } else { + let bank = if key == "BANK2" { + memory::FlashBank::Bank2 } else { - 0 + memory::FlashBank::Bank1 }; - let kind = match region.bank { - memory::FlashBank::Bank1 => stm32_data_serde::chip::memory::Kind::Flash, - memory::FlashBank::Bank2 => stm32_data_serde::chip::memory::Kind::Flash, - memory::FlashBank::Otp => stm32_data_serde::chip::memory::Kind::Otp, - }; + for region in memories + .determine_flash_regions(chip_name) + .iter() + .filter(|x| x.bank == bank) + { + let size = if key == "BANK1" || key == "BANK2" { + std::cmp::min(region.bytes, flash_total) + } else { + 0 + }; - memory_regions.push(stm32_data_serde::chip::Memory { - name: region.name.clone(), - kind, - address: region.address, - size, - settings: Some(region.settings.clone()), - }) + memory_regions.push(stm32_data_serde::chip::Memory { + name: format!("{}_{}", key, region.name), + kind: stm32_data_serde::chip::memory::Kind::Flash, + address: u32::try_from(*address).unwrap(), + size, + settings: Some(region.settings.clone()), + }) + } } } } From 9e0a4b153eb51d49a2259c25f5d189ec727fb765 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 12:31:16 +0100 Subject: [PATCH 3/7] Fix memory various region generation bugs --- stm32-data-gen/src/chips.rs | 111 ++++++++++++++---------- stm32-data-gen/src/memory.rs | 164 ++++++++++++++++++++--------------- stm32-data-serde/src/lib.rs | 1 - 3 files changed, 159 insertions(+), 117 deletions(-) diff --git a/stm32-data-gen/src/chips.rs b/stm32-data-gen/src/chips.rs index c93f353..19331b3 100644 --- a/stm32-data-gen/src/chips.rs +++ b/stm32-data-gen/src/chips.rs @@ -983,7 +983,9 @@ fn process_chip( cores: &[stm32_data_serde::chip::Core], ) -> Result<(), anyhow::Error> { let chip = chips.get(chip_name).unwrap(); - let flash_total = chip.flash * 1024; + let flash_size = chip.flash * 1024; + let mut flash_remaining = flash_size; + let flash_regions = memories.determine_flash_regions(chip_name, flash_size); let ram_total = chip.ram * 1024; let mut memory_regions = Vec::new(); let mut found = HashSet::<&str>::new(); @@ -996,11 +998,15 @@ fn process_chip( "D1_AXIICP", ] { if let Some(address) = h.defines.get("all").unwrap().0.get(&format!("{each}_BASE")) { - let key = match each { - "FLASH" => "BANK1", - "FLASH_BANK1" => "BANK1", - "FLASH_BANK2" => "BANK2", - each => each, + let (key, banks) = match each { + "FLASH" => ( + "BANK_1", + Some([memory::FlashBank::Bank1, memory::FlashBank::Bank2].as_ref()), + ), + "FLASH_BANK1" => ("BANK_1", Some([memory::FlashBank::Bank1].as_ref())), + "FLASH_BANK2" => ("BANK_2", Some([memory::FlashBank::Bank2].as_ref())), + "FLASH_OTP" => ("OTP", Some([memory::FlashBank::Otp].as_ref())), + each => (each, None), }; if found.contains(key) { @@ -1008,46 +1014,59 @@ fn process_chip( } found.insert(key); - if key == "FLASH_OTP" { - if let Some(region) = memories - .determine_flash_regions(chip_name) - .iter() - .find(|x| x.bank == memory::FlashBank::Otp) - { - memory_regions.push(stm32_data_serde::chip::Memory { - name: region.name.clone(), - kind: stm32_data_serde::chip::memory::Kind::Otp, - address: u32::try_from(*address).unwrap(), - size: region.bytes, - settings: Some(region.settings.clone()), - }) + if let Some(banks) = banks { + for bank in banks { + let bank_name = match bank { + memory::FlashBank::Bank1 => "BANK_1", + memory::FlashBank::Bank2 => "BANK_2", + memory::FlashBank::Otp => "OTP", + }; + let regions: Vec<_> = flash_regions + .iter() + .filter(|region| region.bank == *bank) + .enumerate() + .map_while(|(index, region)| { + let size = if *bank == memory::FlashBank::Bank1 || *bank == memory::FlashBank::Bank2 { + // Truncate region to the total amount of remaining chip flash + let size = std::cmp::min(region.bytes, flash_remaining); + flash_remaining -= size; + if size == 0 { + // No more regions are present on this chip + return None; + } + size + } else { + region.bytes + }; + + Some((index, region.address, size, region.settings.clone())) + }) + .collect(); + let has_multiple_regions = regions.len() > 1; + for (index, address, size, settings) in regions { + let name = if has_multiple_regions { + format!("{}_REGION_{}", bank_name, index + 1) + } else { + bank_name.to_string() + }; + + memory_regions.push(stm32_data_serde::chip::Memory { + name, + kind: stm32_data_serde::chip::memory::Kind::Flash, + address, + size, + settings: Some(settings.clone()), + }); + } } } else { - let bank = if key == "BANK2" { - memory::FlashBank::Bank2 - } else { - memory::FlashBank::Bank1 - }; - - for region in memories - .determine_flash_regions(chip_name) - .iter() - .filter(|x| x.bank == bank) - { - let size = if key == "BANK1" || key == "BANK2" { - std::cmp::min(region.bytes, flash_total) - } else { - 0 - }; - - memory_regions.push(stm32_data_serde::chip::Memory { - name: format!("{}_{}", key, region.name), - kind: stm32_data_serde::chip::memory::Kind::Flash, - address: u32::try_from(*address).unwrap(), - size, - settings: Some(region.settings.clone()), - }) - } + memory_regions.push(stm32_data_serde::chip::Memory { + name: key.to_string(), + kind: stm32_data_serde::chip::memory::Kind::Flash, + address: u32::try_from(*address).unwrap(), + size: 0, + settings: None, + }) } } } @@ -1077,7 +1096,7 @@ fn process_chip( found.insert(key); let size = if key == "SRAM" { - let size = memories.determine_ram_size(chip_name); + let size = memories.determine_ram_size(chip_name, flash_size); std::cmp::min(size, ram_total) } else { 0 @@ -1093,7 +1112,7 @@ fn process_chip( } } let docs = docs.documents_for(chip_name); - let device_id = memories.determine_device_id(chip_name); + let device_id = memories.determine_device_id(chip_name, flash_size); let chip = stm32_data_serde::Chip { name: chip_name.to_string(), family: group.family.clone().unwrap(), diff --git a/stm32-data-gen/src/memory.rs b/stm32-data-gen/src/memory.rs index 7a1ec16..7d53b74 100644 --- a/stm32-data-gen/src/memory.rs +++ b/stm32-data-gen/src/memory.rs @@ -1,11 +1,12 @@ -use std::fs; +use std::{cmp::Ordering, fs}; #[derive(Debug, PartialEq)] struct Memory { pub device_id: u16, pub names: Vec, pub ram: Ram, - pub flash: Vec, + pub flash_size: u32, + pub flash_regions: Vec, } #[derive(Clone, Copy, Debug, PartialEq)] @@ -17,7 +18,6 @@ struct Ram { #[derive(Clone, Debug, PartialEq)] pub struct FlashRegion { pub bank: FlashBank, - pub name: String, pub address: u32, pub bytes: u32, pub settings: stm32_data_serde::chip::memory::Settings, @@ -214,7 +214,6 @@ impl Memories { paths.sort(); let mut memories = Vec::new(); - let alphabet: Vec = (b'A'..=b'Z').map(|c| c as char).collect(); for f in paths { // println!("Parsing {f:?}"); @@ -226,9 +225,10 @@ impl Memories { let names = split_names(&parsed.device.name); let mut ram = None; - let mut flash = vec![]; + let mut flash_size = None; + let mut flash_regions = vec![]; - for peripheral in parsed.device.peripherals.peripharal { + for mut peripheral in parsed.device.peripherals.peripharal { if peripheral.name == "Embedded SRAM" && ram.is_none() { let config = peripheral.configuration.first().unwrap(); let parameters = config.parameters.as_ref().unwrap(); @@ -249,49 +249,63 @@ impl Memories { }; if let Some(kind) = kind { - // Use single bank alignment if both single and dual is available - let config = peripheral - .configuration - .iter() - .find(|c| c.organization.as_ref().map(|x| x.as_str()).unwrap_or_default() == "Single") - .unwrap_or_else(|| peripheral.configuration.first().unwrap()); - let parameters = config.parameters.as_ref().unwrap(); - let bank = config.bank.first().unwrap(); + peripheral.configuration.sort_by(|a, b| { + // Prefer largest size + let ordering = b + .parameters + .as_ref() + .unwrap() + .size + .partial_cmp(&a.parameters.as_ref().unwrap().size) + .unwrap(); - let flash_bank = match kind { - BlockKind::Main => match bank.name.as_ref().map(|x| x.as_str()) { - Some("Bank 1") => FlashBank::Bank1, - Some("Bank 2") => FlashBank::Bank2, - None => FlashBank::Bank1, - _ => unimplemented!(), - }, - BlockKind::Otp => FlashBank::Otp, - }; - - let erase_value = peripheral.erased_value.unwrap(); - let write_size = config.allignement.unwrap(); - flash.extend(bank.field.iter().enumerate().map(|(index, field)| { - let name = match kind { - BlockKind::Main => format!("MAIN{}", alphabet[index]).to_string(), - BlockKind::Otp => "OTP".to_string(), - }; - let bytes = if let Some(occurence) = field.parameters.occurence { - occurence * field.parameters.size + // ... then prefer single ordering over dual + if ordering == Ordering::Equal { + // Possible values are Single and Dual + b.organization.partial_cmp(&a.organization).unwrap() } else { - parameters.size - }; - FlashRegion { - bank: flash_bank, - name, - address: field.parameters.address, - bytes, - settings: stm32_data_serde::chip::memory::Settings { - erase_value, - write_size, - erase_size: field.parameters.size, - }, + ordering } - })); + }); + let config = peripheral.configuration.first().unwrap(); + + if flash_size.is_none() { + let parameters = config.parameters.as_ref().unwrap(); + + flash_size = Some(parameters.size); + } + + for bank in config.bank.iter() { + let flash_bank = match kind { + BlockKind::Main => match bank.name.as_ref().map(|x| x.as_str()) { + Some("Bank 1") => Some(FlashBank::Bank1), + Some("Bank 2") => Some(FlashBank::Bank2), + Some("EEPROM1") => None, + Some("EEPROM2") => None, + None => { + assert_eq!(1, config.bank.len()); + Some(FlashBank::Bank1) + } + Some(other) => unimplemented!("Unsupported flash bank {}", other), + }, + BlockKind::Otp => Some(FlashBank::Otp), + }; + + if let Some(flash_bank) = flash_bank { + let erase_value = peripheral.erased_value.unwrap(); + let write_size = config.allignement.unwrap(); + flash_regions.extend(bank.field.iter().map(|field| FlashRegion { + bank: flash_bank, + address: field.parameters.address, + bytes: field.parameters.occurence.unwrap() * field.parameters.size, + settings: stm32_data_serde::chip::memory::Settings { + erase_value, + write_size, + erase_size: field.parameters.size, + }, + })); + } + } } } @@ -299,7 +313,8 @@ impl Memories { device_id, names, ram: ram.unwrap(), - flash, + flash_size: flash_size.unwrap_or_default(), + flash_regions, }); } @@ -311,9 +326,9 @@ impl Memories { address: 0x20000000, bytes: 64 * 1024, }, - flash: vec![FlashRegion { + flash_size: 384 * 1024, + flash_regions: vec![FlashRegion { bank: FlashBank::Bank1, - name: "MAINA".to_string(), address: 0x08000000, bytes: 384 * 1024, settings: stm32_data_serde::chip::memory::Settings { @@ -331,9 +346,9 @@ impl Memories { address: 0x20000000, bytes: 80 * 1024, }, - flash: vec![FlashRegion { + flash_size: 384 * 1024, + flash_regions: vec![FlashRegion { bank: FlashBank::Bank1, - name: "MAINA".to_string(), address: 0x08000000, bytes: 384 * 1024, settings: stm32_data_serde::chip::memory::Settings { @@ -349,45 +364,54 @@ impl Memories { names: vec!["STM32L100x6".to_string()], ram: Ram { address: 0x20000000, - bytes: 32 * 1024, - }, - flash: vec![FlashRegion { - bank: FlashBank::Bank1, - name: "MAINA".to_string(), - address: 0x08000000, bytes: 4 * 1024, + }, + flash_size: 32 * 1024, + flash_regions: vec![FlashRegion { + bank: FlashBank::Bank1, + address: 0x08000000, + bytes: 32 * 1024, settings: stm32_data_serde::chip::memory::Settings { - erase_value: 0xFF, - write_size: 4, erase_size: 256, + write_size: 4, + erase_value: 0xFF, }, }], }); + // Sort memories by flash size in descending order so that when we look + // a chip up later by name, the it will find the one with the largest flash size. + memories.sort_by(|a, b| b.flash_size.cmp(&a.flash_size)); + Ok(Self(memories)) } - fn lookup_chip(&self, chip_name: &str) -> &Memory { + fn lookup_chip(&self, chip_name: &str, flash_size: u32) -> &Memory { + // We use here that the memories are sorted in descending order by flash size. + // We emit the memory for which which the regions include at least the flash size of the requested chip. for each in &self.0 { - for name in &each.names { - if is_chip_name_match(name, chip_name) { - return each; + if each.flash_size >= flash_size { + for name in &each.names { + if is_chip_name_match(name, chip_name) { + return each; + } } } } - panic!("could not find memory information for {chip_name}"); + + panic!("could not find memory information for {chip_name} with flash size {flash_size}"); } - pub fn determine_ram_size(&self, chip_name: &str) -> u32 { - self.lookup_chip(chip_name).ram.bytes + pub fn determine_ram_size(&self, chip_name: &str, flash_size: u32) -> u32 { + self.lookup_chip(chip_name, flash_size).ram.bytes } - pub fn determine_flash_regions(&self, chip_name: &str) -> &[FlashRegion] { - self.lookup_chip(chip_name).flash.as_slice() + pub fn determine_flash_regions(&self, chip_name: &str, flash_size: u32) -> &[FlashRegion] { + self.lookup_chip(chip_name, flash_size).flash_regions.as_slice() } - pub fn determine_device_id(&self, chip_name: &str) -> u16 { - self.lookup_chip(chip_name).device_id + pub fn determine_device_id(&self, chip_name: &str, flash_size: u32) -> u16 { + self.lookup_chip(chip_name, flash_size).device_id } } diff --git a/stm32-data-serde/src/lib.rs b/stm32-data-serde/src/lib.rs index def90e0..dd44b07 100644 --- a/stm32-data-serde/src/lib.rs +++ b/stm32-data-serde/src/lib.rs @@ -40,7 +40,6 @@ pub mod chip { pub enum Kind { Flash, Ram, - Otp, } #[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord, Serialize, Deserialize)] From aa9cda492d5682d670b3d057ad40da7c22a64329 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 12:44:41 +0100 Subject: [PATCH 4/7] Remove custom otp memory kind --- stm32-metapac-gen/res/src/metadata.rs | 1 - stm32-metapac-gen/src/data.rs | 2 -- stm32-metapac-gen/src/lib.rs | 15 ++++++++++----- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/stm32-metapac-gen/res/src/metadata.rs b/stm32-metapac-gen/res/src/metadata.rs index 1cbdfff..2342765 100644 --- a/stm32-metapac-gen/res/src/metadata.rs +++ b/stm32-metapac-gen/res/src/metadata.rs @@ -30,7 +30,6 @@ pub struct FlashSettings { pub enum MemoryRegionKind { Flash, Ram, - Otp, } #[derive(Debug, Eq, PartialEq, Clone)] diff --git a/stm32-metapac-gen/src/data.rs b/stm32-metapac-gen/src/data.rs index bc3ccc6..38e85d6 100644 --- a/stm32-metapac-gen/src/data.rs +++ b/stm32-metapac-gen/src/data.rs @@ -32,8 +32,6 @@ pub enum MemoryRegionKind { Flash, #[serde(rename = "ram")] Ram, - #[serde(rename = "otp")] - Otp, } #[derive(Debug, Eq, PartialEq, Clone, Deserialize)] diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index f5795e7..c59fff9 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -120,7 +120,7 @@ impl Gen { let flash_regions: Vec<&MemoryRegion> = chip .memory .iter() - .filter(|x| x.kind == MemoryRegionKind::Flash) + .filter(|x| x.kind == MemoryRegionKind::Flash && x.name.starts_with("BANK_")) .collect(); let first_flash = flash_regions.first().unwrap(); let total_flash_size = flash_regions @@ -343,7 +343,6 @@ fn stringify(metadata: T) -> String { metadata = metadata.replace(": [", ": &["); metadata = metadata.replace("kind: Ram", "kind: MemoryRegionKind::Ram"); metadata = metadata.replace("kind: Flash", "kind: MemoryRegionKind::Flash"); - metadata = metadata.replace("kind: Otp", "kind: MemoryRegionKind::Otp"); metadata } @@ -356,14 +355,20 @@ fn gen_opts() -> generate::Options { fn gen_memory_x(out_dir: &Path, chip: &Chip) { let mut memory_x = String::new(); - let flash = chip.memory.iter().filter(|r| r.kind == MemoryRegionKind::Flash); + let flash = chip + .memory + .iter() + .filter(|r| r.kind == MemoryRegionKind::Flash && r.name.starts_with("BANK_")); let (flash_address, flash_size) = flash .clone() .map(|r| (r.address, r.size)) .reduce(|acc, el| (u32::min(acc.0, el.0), acc.1 + el.1)) .unwrap(); let ram = chip.memory.iter().find(|r| r.kind == MemoryRegionKind::Ram).unwrap(); - let otp = chip.memory.iter().find(|r| r.kind == MemoryRegionKind::Otp); + let otp = chip + .memory + .iter() + .find(|r| r.kind == MemoryRegionKind::Flash && r.name == "OTP"); write!(memory_x, "MEMORY\n{{\n").unwrap(); writeln!( @@ -371,7 +376,7 @@ fn gen_memory_x(out_dir: &Path, chip: &Chip) { " FLASH : ORIGIN = 0x{:08x}, LENGTH = {:>4}K /* {} */", flash_address, flash_size / 1024, - flash.map(|x| x.name.as_ref()).collect::>().join(", ") + flash.map(|x| x.name.as_ref()).collect::>().join(" + ") ) .unwrap(); writeln!( From e0e9036b112d7ff97bd2c790d53e1df5124e3ec3 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 12:48:14 +0100 Subject: [PATCH 5/7] Add comment about order when iterating FLASH defines --- stm32-data-gen/src/chips.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/stm32-data-gen/src/chips.rs b/stm32-data-gen/src/chips.rs index 19331b3..38a0eae 100644 --- a/stm32-data-gen/src/chips.rs +++ b/stm32-data-gen/src/chips.rs @@ -990,6 +990,7 @@ fn process_chip( let mut memory_regions = Vec::new(); let mut found = HashSet::<&str>::new(); for each in [ + // We test FLASH_BANKx _before_ FLASH as we prefer their definition over the legacy one "FLASH_BANK1", "FLASH_BANK2", "FLASH", From 8019b4f48f874dc0a38770052254e7c9bb861a4d Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 14:24:21 +0100 Subject: [PATCH 6/7] Re-add WRITE_SIZE as it seems to be the same for all regions --- stm32-metapac-gen/src/lib.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index c59fff9..56cd702 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -132,6 +132,18 @@ impl Gen { writeln!(&mut extra, "pub const FLASH_BASE: usize = {};", first_flash.address).unwrap(); writeln!(&mut extra, "pub const FLASH_SIZE: usize = {};", total_flash_size).unwrap(); + let write_sizes: HashSet<_> = flash_regions + .iter() + .map(|r| r.settings.as_ref().unwrap().write_size) + .collect(); + assert_eq!(1, write_sizes.len()); + writeln!( + &mut extra, + "pub const WRITE_SIZE: usize = {};", + write_sizes.iter().next().unwrap() + ) + .unwrap(); + // Cleanups! transform::sort::Sort {}.run(&mut ir).unwrap(); transform::Sanitize {}.run(&mut ir).unwrap(); From a7503de2dc6cfdd69d23d23777d5f91e56325b34 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Wed, 29 Mar 2023 09:44:23 +0200 Subject: [PATCH 7/7] Lookup memory details by die instead of by chip name --- stm32-data-gen/src/chips.rs | 22 +++-- stm32-data-gen/src/memory.rs | 177 ++++------------------------------- 2 files changed, 32 insertions(+), 167 deletions(-) diff --git a/stm32-data-gen/src/chips.rs b/stm32-data-gen/src/chips.rs index 38a0eae..f11b5cc 100644 --- a/stm32-data-gen/src/chips.rs +++ b/stm32-data-gen/src/chips.rs @@ -984,9 +984,9 @@ fn process_chip( ) -> Result<(), anyhow::Error> { let chip = chips.get(chip_name).unwrap(); let flash_size = chip.flash * 1024; - let mut flash_remaining = flash_size; - let flash_regions = memories.determine_flash_regions(chip_name, flash_size); let ram_total = chip.ram * 1024; + let memory = memories.get(group.die.as_ref().unwrap()); + let mut flash_remaining = flash_size; let mut memory_regions = Vec::new(); let mut found = HashSet::<&str>::new(); for each in [ @@ -1022,7 +1022,8 @@ fn process_chip( memory::FlashBank::Bank2 => "BANK_2", memory::FlashBank::Otp => "OTP", }; - let regions: Vec<_> = flash_regions + let regions: Vec<_> = memory + .flash_regions .iter() .filter(|region| region.bank == *bank) .enumerate() @@ -1097,8 +1098,16 @@ fn process_chip( found.insert(key); let size = if key == "SRAM" { - let size = memories.determine_ram_size(chip_name, flash_size); - std::cmp::min(size, ram_total) + // if memory.ram.bytes != ram_total { + // println!( + // "SRAM mismatch for chip {} with die {}: Expected {} was {}", + // chip_name, + // group.die.as_ref().unwrap(), + // ram_total, + // memory.ram.bytes, + // ); + // } + std::cmp::min(memory.ram.bytes, ram_total) } else { 0 }; @@ -1113,13 +1122,12 @@ fn process_chip( } } let docs = docs.documents_for(chip_name); - let device_id = memories.determine_device_id(chip_name, flash_size); let chip = stm32_data_serde::Chip { name: chip_name.to_string(), family: group.family.clone().unwrap(), line: group.line.clone().unwrap(), die: group.die.clone().unwrap(), - device_id, + device_id: memory.device_id, packages: chip.packages.clone(), memory: memory_regions, docs, diff --git a/stm32-data-gen/src/memory.rs b/stm32-data-gen/src/memory.rs index 7d53b74..fa4e505 100644 --- a/stm32-data-gen/src/memory.rs +++ b/stm32-data-gen/src/memory.rs @@ -1,16 +1,15 @@ -use std::{cmp::Ordering, fs}; +use std::{cmp::Ordering, collections::HashMap, fs}; #[derive(Debug, PartialEq)] -struct Memory { +pub struct Memory { pub device_id: u16, - pub names: Vec, pub ram: Ram, pub flash_size: u32, pub flash_regions: Vec, } #[derive(Clone, Copy, Debug, PartialEq)] -struct Ram { +pub struct Ram { pub address: u32, pub bytes: u32, } @@ -30,50 +29,6 @@ pub enum FlashBank { Otp, } -fn splat_names(base: &str, parts: Vec<&str>) -> Vec { - let mut names = Vec::new(); - for part in parts { - if part.starts_with("STM32") { - names.push(base.to_string()); - } else if part.starts_with(&base[5..6]) { - names.push("STM32".to_string() + part); - } else { - let diff = base.len() - part.len(); - names.push((base[..diff]).to_string() + part); - } - } - - names -} - -fn split_names(str: &str) -> Vec { - let mut cleaned = Vec::new(); - let mut current_base = None; - for name in str.split('/') { - let name = name.split(' ').next().unwrap().trim(); - if name.contains('-') { - let parts: Vec<_> = name.split('-').collect(); - current_base = parts.first().map(ToString::to_string); - let splatted = splat_names(¤t_base.unwrap(), parts); - current_base = splatted.first().map(Clone::clone); - cleaned.extend(splatted); - } else if name.starts_with("STM32") { - current_base = Some(name.to_string()); - cleaned.push(name.to_string()) - } else if name.starts_with(¤t_base.clone().unwrap()[5..6]) { - // names.append('STM32' + name) - cleaned.push("STM32".to_string() + name); - } else { - cleaned.push( - (current_base.clone().unwrap()[0..(current_base.clone().unwrap().len() - name.len())]).to_string() - + name, - ) - } - } - - cleaned -} - mod xml { use serde::Deserialize; @@ -203,7 +158,7 @@ mod xml { } } } -pub struct Memories(Vec); +pub struct Memories(HashMap); impl Memories { pub fn parse() -> anyhow::Result { @@ -213,7 +168,7 @@ impl Memories { .collect(); paths.sort(); - let mut memories = Vec::new(); + let mut memories = HashMap::new(); for f in paths { // println!("Parsing {f:?}"); @@ -222,7 +177,6 @@ impl Memories { // dbg!(&parsed); let device_id = parsed.device.device_id; - let names = split_names(&parsed.device.name); let mut ram = None; let mut flash_size = None; @@ -309,121 +263,24 @@ impl Memories { } } - memories.push(Memory { + memories.insert( device_id, - names, - ram: ram.unwrap(), - flash_size: flash_size.unwrap_or_default(), - flash_regions, - }); + Memory { + device_id, + ram: ram.unwrap(), + flash_size: flash_size.unwrap_or_default(), + flash_regions, + }, + ); } - // The chips below are missing from cubeprogdb - memories.push(Memory { - device_id: 0, - names: vec!["STM32F302xD".to_string()], - ram: Ram { - address: 0x20000000, - bytes: 64 * 1024, - }, - flash_size: 384 * 1024, - flash_regions: vec![FlashRegion { - bank: FlashBank::Bank1, - address: 0x08000000, - bytes: 384 * 1024, - settings: stm32_data_serde::chip::memory::Settings { - erase_value: 0xFF, - write_size: 8, - erase_size: 2048, - }, - }], - }); - - memories.push(Memory { - device_id: 0, - names: vec!["STM32F303xD".to_string()], - ram: Ram { - address: 0x20000000, - bytes: 80 * 1024, - }, - flash_size: 384 * 1024, - flash_regions: vec![FlashRegion { - bank: FlashBank::Bank1, - address: 0x08000000, - bytes: 384 * 1024, - settings: stm32_data_serde::chip::memory::Settings { - erase_value: 0xFF, - write_size: 8, - erase_size: 2048, - }, - }], - }); - - memories.push(Memory { - device_id: 0, - names: vec!["STM32L100x6".to_string()], - ram: Ram { - address: 0x20000000, - bytes: 4 * 1024, - }, - flash_size: 32 * 1024, - flash_regions: vec![FlashRegion { - bank: FlashBank::Bank1, - address: 0x08000000, - bytes: 32 * 1024, - settings: stm32_data_serde::chip::memory::Settings { - erase_size: 256, - write_size: 4, - erase_value: 0xFF, - }, - }], - }); - - // Sort memories by flash size in descending order so that when we look - // a chip up later by name, the it will find the one with the largest flash size. - memories.sort_by(|a, b| b.flash_size.cmp(&a.flash_size)); - Ok(Self(memories)) } - fn lookup_chip(&self, chip_name: &str, flash_size: u32) -> &Memory { - // We use here that the memories are sorted in descending order by flash size. - // We emit the memory for which which the regions include at least the flash size of the requested chip. - for each in &self.0 { - if each.flash_size >= flash_size { - for name in &each.names { - if is_chip_name_match(name, chip_name) { - return each; - } - } - } - } + pub fn get(&self, die: &str) -> &Memory { + assert!(die.starts_with("DIE")); + let device_id = u16::from_str_radix(&die[3..], 16).unwrap(); - panic!("could not find memory information for {chip_name} with flash size {flash_size}"); - } - - pub fn determine_ram_size(&self, chip_name: &str, flash_size: u32) -> u32 { - self.lookup_chip(chip_name, flash_size).ram.bytes - } - - pub fn determine_flash_regions(&self, chip_name: &str, flash_size: u32) -> &[FlashRegion] { - self.lookup_chip(chip_name, flash_size).flash_regions.as_slice() - } - - pub fn determine_device_id(&self, chip_name: &str, flash_size: u32) -> u16 { - self.lookup_chip(chip_name, flash_size).device_id + self.0.get(&device_id).unwrap() } } - -fn is_chip_name_match(pattern: &str, chip_name: &str) -> bool { - let mut chip_name = chip_name.replace("STM32F479", "STM32F469"); // F479 is missing, it's the same as F469. - chip_name = chip_name.replace("STM32G050", "STM32G051"); // same... - chip_name = chip_name.replace("STM32G060", "STM32G061"); // same... - chip_name = chip_name.replace("STM32G070", "STM32G071"); // same... - chip_name = chip_name.replace("STM32G0B0", "STM32G0B1"); // same... - chip_name = chip_name.replace("STM32G4A", "STM32G49"); // same... - chip_name = chip_name.replace("STM32L422", "STM32L412"); // same... - chip_name = chip_name.replace("STM32WB30", "STM32WB35"); // same... - let pattern = pattern.replace('x', "."); - regex::Regex::new(&pattern).unwrap().is_match(&chip_name) -}