diff --git a/stm32-data-gen/src/chips.rs b/stm32-data-gen/src/chips.rs index 344bce7..18fd2f4 100644 --- a/stm32-data-gen/src/chips.rs +++ b/stm32-data-gen/src/chips.rs @@ -1003,17 +1003,31 @@ 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 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 ["FLASH", "FLASH_BANK1", "FLASH_BANK2", "D1_AXIFLASH", "D1_AXIICP"] { + for each in [ + // We test FLASH_BANKx _before_ FLASH as we prefer their definition over the legacy one + "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", - 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) { @@ -1021,20 +1035,61 @@ 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 - }; + 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<_> = memory + .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 + }; - 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)), - }); + 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 { + 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, + }) + } } } let mut found = HashSet::new(); @@ -1063,8 +1118,16 @@ fn process_chip( found.insert(key); let size = if key == "SRAM" { - let size = memories.determine_ram_size(chip_name); - 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 }; @@ -1079,13 +1142,12 @@ fn process_chip( } } let docs = docs.documents_for(chip_name); - let device_id = memories.determine_device_id(chip_name); 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 0f5a891..fa4e505 100644 --- a/stm32-data-gen/src/memory.rs +++ b/stm32-data-gen/src/memory.rs @@ -1,68 +1,32 @@ -use std::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: Option, + pub flash_size: u32, + pub flash_regions: Vec, } #[derive(Clone, Copy, Debug, PartialEq)] -struct Ram { +pub struct Ram { pub address: u32, pub bytes: u32, } #[derive(Clone, Debug, PartialEq)] -struct Flash { +pub struct FlashRegion { + pub bank: FlashBank, pub address: u32, pub bytes: u32, pub settings: stm32_data_serde::chip::memory::Settings, } -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 +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum FlashBank { + Bank1, + Bank2, + Otp, } mod xml { @@ -148,6 +112,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 +123,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 +131,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, } @@ -188,7 +158,7 @@ mod xml { } } } -pub struct Memories(Vec); +pub struct Memories(HashMap); impl Memories { pub fn parse() -> anyhow::Result { @@ -198,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:?}"); @@ -207,12 +177,12 @@ 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 = None; + 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(); @@ -222,127 +192,95 @@ impl Memories { }); } - if peripheral.name == "Embedded Flash" && flash.is_none() { - let config = 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(); + enum BlockKind { + Main, + Otp, + } + let kind = match peripheral.name.as_str() { + "Embedded Flash" => Some(BlockKind::Main), + "OTP" => Some(BlockKind::Otp), + _ => None, + }; - 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, - }, + if let Some(kind) = kind { + 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(); + + // ... then prefer single ordering over dual + if ordering == Ordering::Equal { + // Possible values are Single and Dual + b.organization.partial_cmp(&a.organization).unwrap() + } else { + 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, + }, + })); + } + } } } - memories.push(Memory { + memories.insert( device_id, - names, - ram: ram.unwrap(), - flash, - }); + 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: Some(Flash { - 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: Some(Flash { - 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: 32 * 1024, - }, - flash: Some(Flash { - address: 0x08000000, - bytes: 4 * 1024, - settings: stm32_data_serde::chip::memory::Settings { - erase_value: 0xFF, - write_size: 4, - erase_size: 256, - }, - }), - }); - Ok(Self(memories)) } - fn lookup_chip(&self, chip_name: &str) -> &Memory { - for each in &self.0 { - for name in &each.names { - if is_chip_name_match(name, chip_name) { - return each; - } - } - } - panic!("could not find memory information for {chip_name}"); - } + pub fn get(&self, die: &str) -> &Memory { + assert!(die.starts_with("DIE")); + let device_id = u16::from_str_radix(&die[3..], 16).unwrap(); - pub fn determine_ram_size(&self, chip_name: &str) -> u32 { - 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_device_id(&self, chip_name: &str) -> u16 { - self.lookup_chip(chip_name).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) -} diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index 0443e3e..56cd702 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs @@ -117,13 +117,32 @@ 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 && x.name.starts_with("BANK_")) + .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(); + + 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(); @@ -348,22 +367,45 @@ 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 && 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::Flash && r.name == "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();