Support multiple flash regions, including OTP

This commit is contained in:
Rasmus Melchior Jacobsen 2023-03-25 05:46:16 +01:00
parent c8a037d235
commit ba962b3ca1
6 changed files with 148 additions and 54 deletions

View File

@ -988,7 +988,7 @@ fn process_chip(
let mut memory_regions = Vec::new(); let mut memory_regions = Vec::new();
let mut found = HashSet::<&str>::new(); let mut found = HashSet::<&str>::new();
for each in ["FLASH", "FLASH_BANK1", "FLASH_BANK2", "D1_AXIFLASH", "D1_AXIICP"] { 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 { let key = match each {
"FLASH" => "BANK_1", "FLASH" => "BANK_1",
"FLASH_BANK1" => "BANK_1", "FLASH_BANK1" => "BANK_1",
@ -1001,20 +1001,28 @@ fn process_chip(
} }
found.insert(key); found.insert(key);
let size = if key == "BANK_1" || key == "BANK_2" { for region in memories.determine_flash_regions(chip_name) {
let size = memories.determine_flash_size(chip_name); let size = if key == "BANK_1" || key == "BANK_2" {
std::cmp::min(size, flash_total) let size = region.bytes;
} else { std::cmp::min(size, flash_total)
0 } else {
}; 0
};
memory_regions.push(stm32_data_serde::chip::Memory { let kind = match region.bank {
name: key.to_string(), memory::FlashBank::Bank1 => stm32_data_serde::chip::memory::Kind::Flash,
kind: stm32_data_serde::chip::memory::Kind::Flash, memory::FlashBank::Bank2 => stm32_data_serde::chip::memory::Kind::Flash,
address: u32::try_from(*address).unwrap(), memory::FlashBank::Otp => stm32_data_serde::chip::memory::Kind::Otp,
size, };
settings: Some(memories.determine_flash_settings(chip_name)),
}); 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(); let mut found = HashSet::new();

View File

@ -5,7 +5,7 @@ struct Memory {
pub device_id: u16, pub device_id: u16,
pub names: Vec<String>, pub names: Vec<String>,
pub ram: Ram, pub ram: Ram,
pub flash: Option<Flash>, pub flash: Vec<FlashRegion>,
} }
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
@ -15,12 +15,21 @@ struct Ram {
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
struct Flash { pub struct FlashRegion {
pub bank: FlashBank,
pub name: String,
pub address: u32, pub address: u32,
pub bytes: u32, pub bytes: u32,
pub settings: stm32_data_serde::chip::memory::Settings, 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<String> { fn splat_names(base: &str, parts: Vec<&str>) -> Vec<String> {
let mut names = Vec::new(); let mut names = Vec::new();
for part in parts { for part in parts {
@ -148,6 +157,8 @@ mod xml {
pub struct Configuration { pub struct Configuration {
#[serde(rename = "Parameters", default)] #[serde(rename = "Parameters", default)]
pub parameters: Option<configuration::Parameters>, pub parameters: Option<configuration::Parameters>,
#[serde(rename = "Organization", default)]
pub organization: Option<String>,
#[serde(rename = "Allignement", deserialize_with = "opt_from_hex", default)] #[serde(rename = "Allignement", deserialize_with = "opt_from_hex", default)]
pub allignement: Option<u32>, pub allignement: Option<u32>,
#[serde(rename = "Bank")] #[serde(rename = "Bank")]
@ -157,7 +168,7 @@ mod xml {
mod configuration { mod configuration {
use serde::Deserialize; 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)] #[derive(Debug, Deserialize, PartialEq)]
pub struct Parameters { pub struct Parameters {
@ -165,10 +176,14 @@ mod xml {
pub address: u32, pub address: u32,
#[serde(deserialize_with = "from_hex")] #[serde(deserialize_with = "from_hex")]
pub size: u32, pub size: u32,
#[serde(deserialize_with = "opt_from_hex", default)]
pub occurence: Option<u32>,
} }
#[derive(Debug, Deserialize, PartialEq)] #[derive(Debug, Deserialize, PartialEq)]
pub struct Bank { pub struct Bank {
#[serde(default)]
pub name: Option<String>,
#[serde(rename = "Field", default)] #[serde(rename = "Field", default)]
pub field: Vec<bank::Field>, pub field: Vec<bank::Field>,
} }
@ -199,6 +214,7 @@ impl Memories {
paths.sort(); paths.sort();
let mut memories = Vec::new(); let mut memories = Vec::new();
let alphabet: Vec<char> = (b'A'..=b'Z').map(|c| c as char).collect();
for f in paths { for f in paths {
// println!("Parsing {f:?}"); // println!("Parsing {f:?}");
@ -210,7 +226,7 @@ impl Memories {
let names = split_names(&parsed.device.name); let names = split_names(&parsed.device.name);
let mut ram = None; let mut ram = None;
let mut flash = None; let mut flash = vec![];
for peripheral in parsed.device.peripherals.peripharal { for peripheral in parsed.device.peripherals.peripharal {
if peripheral.name == "Embedded SRAM" && ram.is_none() { if peripheral.name == "Embedded SRAM" && ram.is_none() {
@ -222,21 +238,60 @@ impl Memories {
}); });
} }
if peripheral.name == "Embedded Flash" && flash.is_none() { enum BlockKind {
let config = peripheral.configuration.first().unwrap(); 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 parameters = config.parameters.as_ref().unwrap();
let bank = config.bank.first().unwrap(); let bank = config.bank.first().unwrap();
let erase_size = bank.field.iter().map(|field| field.parameters.size).max().unwrap();
flash = Some(Flash { let flash_bank = match kind {
address: parameters.address, BlockKind::Main => match bank.name.as_ref().map(|x| x.as_str()) {
bytes: parameters.size, Some("Bank 1") => FlashBank::Bank1,
settings: stm32_data_serde::chip::memory::Settings { Some("Bank 2") => FlashBank::Bank2,
erase_value: peripheral.erased_value.unwrap(), None => FlashBank::Bank1,
write_size: config.allignement.unwrap(), _ => unimplemented!(),
erase_size,
}, },
}); 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, address: 0x20000000,
bytes: 64 * 1024, bytes: 64 * 1024,
}, },
flash: Some(Flash { flash: vec![FlashRegion {
bank: FlashBank::Bank1,
name: "MAINA".to_string(),
address: 0x08000000, address: 0x08000000,
bytes: 384 * 1024, bytes: 384 * 1024,
settings: stm32_data_serde::chip::memory::Settings { settings: stm32_data_serde::chip::memory::Settings {
@ -264,7 +321,7 @@ impl Memories {
write_size: 8, write_size: 8,
erase_size: 2048, erase_size: 2048,
}, },
}), }],
}); });
memories.push(Memory { memories.push(Memory {
@ -274,7 +331,9 @@ impl Memories {
address: 0x20000000, address: 0x20000000,
bytes: 80 * 1024, bytes: 80 * 1024,
}, },
flash: Some(Flash { flash: vec![FlashRegion {
bank: FlashBank::Bank1,
name: "MAINA".to_string(),
address: 0x08000000, address: 0x08000000,
bytes: 384 * 1024, bytes: 384 * 1024,
settings: stm32_data_serde::chip::memory::Settings { settings: stm32_data_serde::chip::memory::Settings {
@ -282,7 +341,7 @@ impl Memories {
write_size: 8, write_size: 8,
erase_size: 2048, erase_size: 2048,
}, },
}), }],
}); });
memories.push(Memory { memories.push(Memory {
@ -292,7 +351,9 @@ impl Memories {
address: 0x20000000, address: 0x20000000,
bytes: 32 * 1024, bytes: 32 * 1024,
}, },
flash: Some(Flash { flash: vec![FlashRegion {
bank: FlashBank::Bank1,
name: "MAINA".to_string(),
address: 0x08000000, address: 0x08000000,
bytes: 4 * 1024, bytes: 4 * 1024,
settings: stm32_data_serde::chip::memory::Settings { settings: stm32_data_serde::chip::memory::Settings {
@ -300,7 +361,7 @@ impl Memories {
write_size: 4, write_size: 4,
erase_size: 256, erase_size: 256,
}, },
}), }],
}); });
Ok(Self(memories)) Ok(Self(memories))
@ -321,12 +382,8 @@ impl Memories {
self.lookup_chip(chip_name).ram.bytes self.lookup_chip(chip_name).ram.bytes
} }
pub fn determine_flash_size(&self, chip_name: &str) -> u32 { pub fn determine_flash_regions(&self, chip_name: &str) -> &[FlashRegion] {
self.lookup_chip(chip_name).flash.as_ref().unwrap().bytes self.lookup_chip(chip_name).flash.as_slice()
}
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 { pub fn determine_device_id(&self, chip_name: &str) -> u16 {

View File

@ -40,6 +40,7 @@ pub mod chip {
pub enum Kind { pub enum Kind {
Flash, Flash,
Ram, Ram,
Otp,
} }
#[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord, Serialize, Deserialize)]

View File

@ -30,6 +30,7 @@ pub struct FlashSettings {
pub enum MemoryRegionKind { pub enum MemoryRegionKind {
Flash, Flash,
Ram, Ram,
Otp,
} }
#[derive(Debug, Eq, PartialEq, Clone)] #[derive(Debug, Eq, PartialEq, Clone)]

View File

@ -32,6 +32,8 @@ pub enum MemoryRegionKind {
Flash, Flash,
#[serde(rename = "ram")] #[serde(rename = "ram")]
Ram, Ram,
#[serde(rename = "otp")]
Otp,
} }
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)] #[derive(Debug, Eq, PartialEq, Clone, Deserialize)]

View File

@ -117,13 +117,20 @@ impl Gen {
} }
writeln!(&mut extra, "pub const CORE_INDEX: usize = {};", core_index).unwrap(); writeln!(&mut extra, "pub const CORE_INDEX: usize = {};", core_index).unwrap();
let flash = chip.memory.iter().find(|r| r.name == "BANK_1").unwrap(); let flash_regions: Vec<&MemoryRegion> = chip
let settings = flash.settings.as_ref().unwrap(); .memory
writeln!(&mut extra, "pub const FLASH_BASE: usize = {};", flash.address).unwrap(); .iter()
writeln!(&mut extra, "pub const FLASH_SIZE: usize = {};", flash.size).unwrap(); .filter(|x| x.kind == MemoryRegionKind::Flash)
writeln!(&mut extra, "pub const ERASE_SIZE: usize = {};", settings.erase_size).unwrap(); .collect();
writeln!(&mut extra, "pub const WRITE_SIZE: usize = {};", settings.write_size).unwrap(); let first_flash = flash_regions.first().unwrap();
writeln!(&mut extra, "pub const ERASE_VALUE: u8 = {};", settings.erase_value).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! // Cleanups!
transform::sort::Sort {}.run(&mut ir).unwrap(); transform::sort::Sort {}.run(&mut ir).unwrap();
@ -336,6 +343,7 @@ fn stringify<T: Debug>(metadata: T) -> String {
metadata = metadata.replace(": [", ": &["); metadata = metadata.replace(": [", ": &[");
metadata = metadata.replace("kind: Ram", "kind: MemoryRegionKind::Ram"); metadata = metadata.replace("kind: Ram", "kind: MemoryRegionKind::Ram");
metadata = metadata.replace("kind: Flash", "kind: MemoryRegionKind::Flash"); metadata = metadata.replace("kind: Flash", "kind: MemoryRegionKind::Flash");
metadata = metadata.replace("kind: Otp", "kind: MemoryRegionKind::Otp");
metadata metadata
} }
@ -348,22 +356,39 @@ fn gen_opts() -> generate::Options {
fn gen_memory_x(out_dir: &Path, chip: &Chip) { fn gen_memory_x(out_dir: &Path, chip: &Chip) {
let mut memory_x = String::new(); let mut memory_x = String::new();
let flash = chip.memory.iter().find(|r| r.name == "BANK_1").unwrap(); let flash = chip.memory.iter().filter(|r| r.kind == MemoryRegionKind::Flash);
let ram = chip.memory.iter().find(|r| r.name == "SRAM").unwrap(); 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(); write!(memory_x, "MEMORY\n{{\n").unwrap();
writeln!( writeln!(
memory_x, memory_x,
" FLASH : ORIGIN = 0x{:x}, LENGTH = {}", " FLASH : ORIGIN = 0x{:08x}, LENGTH = {:>4}K /* {} */",
flash.address, flash.size, flash_address,
flash_size / 1024,
flash.map(|x| x.name.as_ref()).collect::<Vec<&str>>().join(", ")
) )
.unwrap(); .unwrap();
writeln!( writeln!(
memory_x, memory_x,
" RAM : ORIGIN = 0x{:x}, LENGTH = {}", " RAM : ORIGIN = 0x{:08x}, LENGTH = {:>4}K",
ram.address, ram.size, ram.address,
ram.size / 1024,
) )
.unwrap(); .unwrap();
if let Some(otp) = otp {
writeln!(
memory_x,
" OTP : ORIGIN = 0x{:08x}, LENGTH = {:>4}",
otp.address, otp.size,
)
.unwrap();
}
write!(memory_x, "}}").unwrap(); write!(memory_x, "}}").unwrap();
fs::create_dir_all(out_dir.join("memory_x")).unwrap(); fs::create_dir_all(out_dir.join("memory_x")).unwrap();