From ba962b3ca16b91158de30089cb75490e4a00f720 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Sat, 25 Mar 2023 05:46:16 +0100 Subject: [PATCH] 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();