Parse interrupts on demand for each chip instead of upfront.
This commit is contained in:
parent
fbb8f77326
commit
221d24f6f8
@ -67,7 +67,7 @@ pub struct Chip {
|
||||
pub struct ChipGroup {
|
||||
chip_names: Vec<String>,
|
||||
xml: xml::Mcu,
|
||||
ips: HashMap<String, xml::Ip>,
|
||||
pub ips: HashMap<String, xml::Ip>,
|
||||
pins: HashMap<String, xml::Pin>,
|
||||
family: Option<String>,
|
||||
line: Option<String>,
|
||||
@ -810,73 +810,9 @@ fn process_core(
|
||||
chip_af: Option<&HashMap<String, Vec<stm32_data_serde::chip::core::peripheral::Pin>>>,
|
||||
dma_channels: &dma::DmaChannels,
|
||||
) -> stm32_data_serde::chip::Core {
|
||||
let real_core_name = corename(core_xml);
|
||||
let core_name = corename(core_xml);
|
||||
let defines = h.get_defines(&core_name);
|
||||
|
||||
let core_name = if !h.interrupts.contains_key(&real_core_name) || !h.defines.contains_key(&real_core_name) {
|
||||
"all"
|
||||
} else {
|
||||
&real_core_name
|
||||
};
|
||||
// C header defines for this core.
|
||||
let defines = h.defines.get(core_name).unwrap();
|
||||
// Interrupts!
|
||||
let want_nvic_name = {
|
||||
// Most chips have a single NVIC, named "NVIC"
|
||||
let mut want_nvic_name = "NVIC";
|
||||
|
||||
// Exception 1: Multicore: NVIC1 is the first core, NVIC2 is the second. We have to pick the right one.
|
||||
if ["H745", "H747", "H755", "H757", "WL54", "WL55"].contains(&&chip_name[5..9]) {
|
||||
if core_name == "cm7" {
|
||||
want_nvic_name = "NVIC1";
|
||||
} else {
|
||||
want_nvic_name = "NVIC2"
|
||||
}
|
||||
}
|
||||
if &chip_name[5..8] == "WL5" {
|
||||
if core_name == "cm4" {
|
||||
want_nvic_name = "NVIC1";
|
||||
} else {
|
||||
want_nvic_name = "NVIC2"
|
||||
}
|
||||
}
|
||||
// Exception 2: TrustZone: NVIC1 is Secure mode, NVIC2 is NonSecure mode. For now, we pick the NonSecure one.
|
||||
if ["L5", "U5"].contains(&&chip_name[5..7]) {
|
||||
want_nvic_name = "NVIC2"
|
||||
}
|
||||
if ["H56", "H57", "WBA"].contains(&&chip_name[5..8]) {
|
||||
want_nvic_name = "NVIC2"
|
||||
}
|
||||
|
||||
want_nvic_name
|
||||
};
|
||||
let chip_nvic = group
|
||||
.ips
|
||||
.values()
|
||||
.find(|x| x.name == want_nvic_name)
|
||||
.ok_or_else(|| format!("couldn't find nvic. chip_name={chip_name} want_nvic_name={want_nvic_name}"))
|
||||
.unwrap();
|
||||
|
||||
// With the current data sources, this value is always either 2 or 4, and never resolves to None
|
||||
let nvic_priority_bits = defines.0.get("__NVIC_PRIO_BITS").map(|bits| *bits as u8);
|
||||
|
||||
let mut header_irqs = h.interrupts.get(core_name).unwrap().clone();
|
||||
let chip_irqs = chip_interrupts
|
||||
.0
|
||||
.get(&(chip_nvic.name.clone(), chip_nvic.version.clone()))
|
||||
.unwrap();
|
||||
// F100xE MISC_REMAP remaps some DMA IRQs, so ST decided to give two names
|
||||
// to the same IRQ number.
|
||||
if chip_name.starts_with("STM32F100") {
|
||||
header_irqs.remove("DMA2_Channel4_5");
|
||||
}
|
||||
let mut interrupts: Vec<_> = header_irqs
|
||||
.iter()
|
||||
.map(|(k, v)| stm32_data_serde::chip::core::Interrupt {
|
||||
name: k.clone(),
|
||||
number: *v,
|
||||
})
|
||||
.collect();
|
||||
interrupts.sort_unstable_by_key(|x| x.number);
|
||||
let mut peri_kinds = HashMap::new();
|
||||
peri_kinds.insert("UID".to_string(), "UID".to_string());
|
||||
for ip in group.ips.values() {
|
||||
@ -1067,41 +1003,6 @@ fn process_core(
|
||||
// sort pins to avoid diff for c pins
|
||||
p.pins.sort_by_key(|x| (x.pin.clone(), x.signal.clone()));
|
||||
|
||||
if let Some(peri_irqs) = chip_irqs.get(&pname) {
|
||||
use stm32_data_serde::chip::core::peripheral::Interrupt;
|
||||
|
||||
//filter by available, because some are conditioned on <Die>
|
||||
|
||||
static EQUIVALENT_IRQS: &[(&str, &[&str])] = &[
|
||||
("HASH_RNG", &["RNG"]),
|
||||
("USB_HP_CAN_TX", &["CAN_TX"]),
|
||||
("USB_LP_CAN_RX0", &["CAN_RX0"]),
|
||||
];
|
||||
|
||||
let mut irqs: Vec<_> = peri_irqs
|
||||
.iter()
|
||||
.filter_map(|i| {
|
||||
if header_irqs.contains_key(&i.interrupt) {
|
||||
return Some(i.clone());
|
||||
}
|
||||
if let Some((_, eq_irqs)) = EQUIVALENT_IRQS.iter().find(|(irq, _)| irq == &i.interrupt) {
|
||||
for eq_irq in *eq_irqs {
|
||||
if header_irqs.contains_key(*eq_irq) {
|
||||
return Some(Interrupt {
|
||||
signal: i.signal.clone(),
|
||||
interrupt: eq_irq.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect();
|
||||
irqs.sort_by_key(|x| (x.signal.clone(), x.interrupt.clone()));
|
||||
irqs.dedup_by_key(|x| (x.signal.clone(), x.interrupt.clone()));
|
||||
|
||||
p.interrupts = Some(irqs);
|
||||
}
|
||||
peripherals.insert(p.name.clone(), p);
|
||||
}
|
||||
if let Ok(extra_f) = std::fs::read(format!("data/extra/family/{}.yaml", group.family.as_ref().unwrap())) {
|
||||
@ -1189,13 +1090,18 @@ fn process_core(
|
||||
p.dma_channels = chs;
|
||||
}
|
||||
}
|
||||
stm32_data_serde::chip::Core {
|
||||
name: real_core_name.clone(),
|
||||
|
||||
let mut core = stm32_data_serde::chip::Core {
|
||||
name: core_name.clone(),
|
||||
peripherals,
|
||||
nvic_priority_bits,
|
||||
interrupts,
|
||||
nvic_priority_bits: None,
|
||||
interrupts: vec![],
|
||||
dma_channels: core_dma_channels,
|
||||
}
|
||||
};
|
||||
|
||||
chip_interrupts.process(&mut core, chip_name, h, group);
|
||||
|
||||
core
|
||||
}
|
||||
|
||||
fn process_chip(
|
||||
|
@ -196,6 +196,26 @@ pub struct ParsedHeader {
|
||||
}
|
||||
|
||||
impl ParsedHeader {
|
||||
/// Get C header defines for this core.
|
||||
pub fn get_defines(&self, core_name: &str) -> &Defines {
|
||||
let core_name = if !self.interrupts.contains_key(core_name) || !self.defines.contains_key(core_name) {
|
||||
"all"
|
||||
} else {
|
||||
core_name
|
||||
};
|
||||
self.defines.get(core_name).unwrap()
|
||||
}
|
||||
|
||||
/// Get interrupts for this core.
|
||||
pub fn get_interrupts(&self, core_name: &str) -> &HashMap<String, u8> {
|
||||
let core_name = if !self.interrupts.contains_key(core_name) || !self.defines.contains_key(core_name) {
|
||||
"all"
|
||||
} else {
|
||||
core_name
|
||||
};
|
||||
self.interrupts.get(core_name).unwrap()
|
||||
}
|
||||
|
||||
fn parse(f: impl AsRef<std::path::Path>) -> anyhow::Result<Self> {
|
||||
let mut irqs = HashMap::<String, HashMap<String, u8>>::new();
|
||||
let mut defines = HashMap::<String, Defines>::new();
|
||||
|
@ -2,6 +2,7 @@ use std::collections::{HashMap, HashSet};
|
||||
|
||||
use log::*;
|
||||
|
||||
use crate::chips::ChipGroup;
|
||||
use crate::regex;
|
||||
|
||||
mod xml {
|
||||
@ -35,14 +36,14 @@ mod xml {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ChipInterrupts(
|
||||
// (chip name, chip version), (signal name, [interrupt])
|
||||
pub HashMap<(String, String), HashMap<String, Vec<stm32_data_serde::chip::core::peripheral::Interrupt>>>,
|
||||
);
|
||||
pub struct ChipInterrupts {
|
||||
// (nvic name, nvic version) => [cursed unparsed interrupt string]
|
||||
irqs: HashMap<(String, String), Vec<String>>,
|
||||
}
|
||||
|
||||
impl ChipInterrupts {
|
||||
pub fn parse() -> anyhow::Result<Self> {
|
||||
let mut chip_interrupts = HashMap::new();
|
||||
let mut irqs = HashMap::new();
|
||||
|
||||
let mut files: Vec<_> = glob::glob("sources/cubedb/mcu/IP/NVIC*_Modes.xml")?
|
||||
.map(Result::unwrap)
|
||||
@ -54,211 +55,329 @@ impl ChipInterrupts {
|
||||
trace!("parsing {f:?}");
|
||||
let file = std::fs::read_to_string(&f)?;
|
||||
let parsed: xml::Ip = quick_xml::de::from_str(&file)?;
|
||||
let mut chip_signals = HashMap::<_, Vec<_>>::new();
|
||||
|
||||
for irq in parsed
|
||||
let strings: Vec<_> = parsed
|
||||
.ref_parameters
|
||||
.into_iter()
|
||||
.filter(|param| param.name == "IRQn")
|
||||
.flat_map(|param| param.possible_values)
|
||||
// F3 can remap USB IRQs, ignore them.
|
||||
.filter(|irq| !parsed.version.starts_with("STM32F3") || !irq.comment.contains("remap"))
|
||||
.map(|irq| irq.value)
|
||||
.collect();
|
||||
|
||||
irqs.insert((parsed.name, parsed.version), strings);
|
||||
}
|
||||
|
||||
Ok(Self { irqs })
|
||||
}
|
||||
|
||||
pub(crate) fn process(
|
||||
&self,
|
||||
core: &mut stm32_data_serde::chip::Core,
|
||||
chip_name: &str,
|
||||
h: &crate::header::ParsedHeader,
|
||||
group: &ChipGroup,
|
||||
) {
|
||||
// =================== Populate nvic_priority_bits
|
||||
// With the current data sources, this value is always either 2 or 4, and never resolves to None
|
||||
let header_defines = h.get_defines(&core.name);
|
||||
core.nvic_priority_bits = header_defines.0.get("__NVIC_PRIO_BITS").map(|bits| *bits as u8);
|
||||
|
||||
// =================== Populate core interrupts
|
||||
let mut header_irqs = h.get_interrupts(&core.name).clone();
|
||||
// F100xE MISC_REMAP remaps some DMA IRQs, so ST decided to give two names
|
||||
// to the same IRQ number.
|
||||
if chip_name.starts_with("STM32F100") {
|
||||
header_irqs.remove("DMA2_Channel4_5");
|
||||
}
|
||||
core.interrupts = header_irqs
|
||||
.iter()
|
||||
.map(|(k, v)| stm32_data_serde::chip::core::Interrupt {
|
||||
name: k.clone(),
|
||||
number: *v,
|
||||
})
|
||||
.collect();
|
||||
core.interrupts.sort_unstable_by_key(|x| x.number);
|
||||
|
||||
// =================== Populate peripheral interrupts
|
||||
let want_nvic_name = pick_nvic(chip_name, &core.name);
|
||||
let chip_nvic = group
|
||||
.ips
|
||||
.values()
|
||||
.find(|x| x.name == want_nvic_name)
|
||||
.ok_or_else(|| format!("couldn't find nvic. chip_name={chip_name} want_nvic_name={want_nvic_name}"))
|
||||
.unwrap();
|
||||
let nvic_strings = self
|
||||
.irqs
|
||||
.get(&(chip_nvic.name.clone(), chip_nvic.version.clone()))
|
||||
.unwrap();
|
||||
|
||||
let mut chip_signals = HashMap::<_, Vec<_>>::new();
|
||||
|
||||
for nvic_string in nvic_strings {
|
||||
trace!(" irq={nvic_string:?}");
|
||||
let parts = {
|
||||
let mut iter = nvic_string.split(':');
|
||||
let parts = [(); 5].map(|_| iter.next().unwrap());
|
||||
assert!(iter.next().is_none());
|
||||
parts
|
||||
};
|
||||
|
||||
let mut name = parts[0].strip_suffix("_IRQn").unwrap().to_string();
|
||||
|
||||
// Fix typo in STM32Lxx and L083 devices
|
||||
let contains_rng = || parts[2..].iter().flat_map(|x| x.split(',')).any(|x| x == "RNG");
|
||||
if name == "AES_RNG_LPUART1" && !contains_rng() {
|
||||
name = "AES_LPUART1".to_string()
|
||||
}
|
||||
|
||||
// More typos
|
||||
let name = name.replace("USAR11", "USART11");
|
||||
|
||||
// Flags.
|
||||
// Y
|
||||
// unknown, it's in all of them
|
||||
// H3, nHS
|
||||
// ???
|
||||
// 2V, 3V, nV, 2V1
|
||||
// unknown, it has to do with the fact the irq is shared among N peripehrals
|
||||
// DMA, DMAL0, DMAF0, DMAL0_DMAMUX, DMAF0_DMAMUX
|
||||
// special format for DMA
|
||||
// DFSDM
|
||||
// special format for DFSDM
|
||||
// EXTI
|
||||
// special format for EXTI
|
||||
let flags: Vec<_> = parts[1].split(',').collect();
|
||||
|
||||
// F100xE MISC_REMAP remaps some DMA IRQs, so ST decided to give two names
|
||||
// to the same IRQ number.
|
||||
if chip_nvic.version == "STM32F100E" && name == "DMA2_Channel4_5" {
|
||||
continue;
|
||||
}
|
||||
//not supported
|
||||
if name == "LSECSSD" {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut interrupt_signals = HashSet::<(String, String)>::new();
|
||||
if [
|
||||
"NonMaskableInt",
|
||||
"HardFault",
|
||||
"MemoryManagement",
|
||||
"BusFault",
|
||||
"UsageFault",
|
||||
"SVCall",
|
||||
"DebugMonitor",
|
||||
"PendSV",
|
||||
"SysTick",
|
||||
]
|
||||
.contains(&name.as_str())
|
||||
{
|
||||
trace!(" irq={irq:?}");
|
||||
let parts = {
|
||||
let mut iter = irq.value.split(':');
|
||||
let parts = [(); 5].map(|_| iter.next().unwrap());
|
||||
assert!(iter.next().is_none());
|
||||
parts
|
||||
// pass
|
||||
} else if flags
|
||||
.iter()
|
||||
.map(|flag| ["DMA", "DMAL0", "DMAF0", "DMAL0_DMAMUX", "DMAF0_DMAMUX"].contains(flag))
|
||||
.any(std::convert::identity)
|
||||
{
|
||||
let mut dmas_iter = parts[3].split(',');
|
||||
let mut chans_iter = parts[4].split(';');
|
||||
for (dma, chan) in std::iter::zip(&mut dmas_iter, &mut chans_iter) {
|
||||
let range = {
|
||||
let mut ch = chan.split(',');
|
||||
let ch_from: usize = ch.next().unwrap().parse().unwrap();
|
||||
let ch_to = match ch.next() {
|
||||
Some(ch_to) => ch_to.parse().unwrap(),
|
||||
None => ch_from,
|
||||
};
|
||||
assert!(ch.next().is_none());
|
||||
ch_from..=ch_to
|
||||
};
|
||||
for ch in range {
|
||||
interrupt_signals.insert((dma.to_string(), format!("CH{ch}")));
|
||||
}
|
||||
}
|
||||
assert!(dmas_iter.next().is_none());
|
||||
assert!(chans_iter.next().is_none());
|
||||
} else if name == "DMAMUX1" || name == "DMAMUX1_S" || name == "DMAMUX_OVR" || name == "DMAMUX1_OVR" {
|
||||
interrupt_signals.insert(("DMAMUX1".to_string(), "OVR".to_string()));
|
||||
} else if name == "DMAMUX2_OVR" {
|
||||
interrupt_signals.insert(("DMAMUX2".to_string(), "OVR".to_string()));
|
||||
} else if flags.contains(&"DMAMUX") {
|
||||
panic!("should've been handled above");
|
||||
} else if flags.contains(&"EXTI") {
|
||||
for signal in parts[2].split(',') {
|
||||
interrupt_signals.insert(("EXTI".to_string(), signal.to_string()));
|
||||
}
|
||||
} else if name == "FLASH" {
|
||||
interrupt_signals.insert(("FLASH".to_string(), "GLOBAL".to_string()));
|
||||
} else if name == "CRS" {
|
||||
interrupt_signals.insert(("RCC".to_string(), "CRS".to_string()));
|
||||
} else if name == "RCC" {
|
||||
interrupt_signals.insert(("RCC".to_string(), "GLOBAL".to_string()));
|
||||
} else {
|
||||
if parts[2].is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let peri_names: Vec<_> = parts[2].split(',').map(ToString::to_string).collect();
|
||||
|
||||
let name2 = {
|
||||
if name == "USBWakeUp" || name == "USBWakeUp_RMP" {
|
||||
"USB_WKUP"
|
||||
} else {
|
||||
name.strip_suffix("_S").unwrap_or(&name)
|
||||
}
|
||||
};
|
||||
|
||||
let mut name = parts[0].strip_suffix("_IRQn").unwrap().to_string();
|
||||
|
||||
// Fix typo in STM32Lxx and L083 devices
|
||||
let contains_rng = || parts[2..].iter().flat_map(|x| x.split(',')).any(|x| x == "RNG");
|
||||
if name == "AES_RNG_LPUART1" && !contains_rng() {
|
||||
name = "AES_LPUART1".to_string()
|
||||
}
|
||||
|
||||
// More typos
|
||||
let name = name.replace("USAR11", "USART11");
|
||||
|
||||
// Flags.
|
||||
// Y
|
||||
// unknown, it's in all of them
|
||||
// H3, nHS
|
||||
// ???
|
||||
// 2V, 3V, nV, 2V1
|
||||
// unknown, it has to do with the fact the irq is shared among N peripehrals
|
||||
// DMA, DMAL0, DMAF0, DMAL0_DMAMUX, DMAF0_DMAMUX
|
||||
// special format for DMA
|
||||
// DFSDM
|
||||
// special format for DFSDM
|
||||
// EXTI
|
||||
// special format for EXTI
|
||||
let flags: Vec<_> = parts[1].split(',').collect();
|
||||
|
||||
// F100xE MISC_REMAP remaps some DMA IRQs, so ST decided to give two names
|
||||
// to the same IRQ number.
|
||||
if parsed.version == "STM32F100E" && name == "DMA2_Channel4_5" {
|
||||
continue;
|
||||
}
|
||||
// F3 can remap USB IRQs, ignore them.
|
||||
if parsed.version.starts_with("STM32F3") && irq.comment.contains("remap") {
|
||||
continue;
|
||||
}
|
||||
// not supported
|
||||
if name == "LSECSSD" {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut interrupt_signals = HashSet::<(String, String)>::new();
|
||||
if [
|
||||
"NonMaskableInt",
|
||||
"HardFault",
|
||||
"MemoryManagement",
|
||||
"BusFault",
|
||||
"UsageFault",
|
||||
"SVCall",
|
||||
"DebugMonitor",
|
||||
"PendSV",
|
||||
"SysTick",
|
||||
]
|
||||
.contains(&name.as_str())
|
||||
{
|
||||
// pass
|
||||
} else if flags
|
||||
let mut peri_signals: HashMap<_, _> = peri_names
|
||||
.iter()
|
||||
.map(|flag| ["DMA", "DMAL0", "DMAF0", "DMAL0_DMAMUX", "DMAF0_DMAMUX"].contains(flag))
|
||||
.any(std::convert::identity)
|
||||
{
|
||||
let mut dmas_iter = parts[3].split(',');
|
||||
let mut chans_iter = parts[4].split(';');
|
||||
for (dma, chan) in std::iter::zip(&mut dmas_iter, &mut chans_iter) {
|
||||
let range = {
|
||||
let mut ch = chan.split(',');
|
||||
let ch_from: usize = ch.next().unwrap().parse().unwrap();
|
||||
let ch_to = match ch.next() {
|
||||
Some(ch_to) => ch_to.parse().unwrap(),
|
||||
None => ch_from,
|
||||
};
|
||||
assert!(ch.next().is_none());
|
||||
ch_from..=ch_to
|
||||
};
|
||||
for ch in range {
|
||||
interrupt_signals.insert((dma.to_string(), format!("CH{ch}")));
|
||||
}
|
||||
}
|
||||
assert!(dmas_iter.next().is_none());
|
||||
assert!(chans_iter.next().is_none());
|
||||
} else if name == "DMAMUX1" || name == "DMAMUX1_S" || name == "DMAMUX_OVR" || name == "DMAMUX1_OVR" {
|
||||
interrupt_signals.insert(("DMAMUX1".to_string(), "OVR".to_string()));
|
||||
} else if name == "DMAMUX2_OVR" {
|
||||
interrupt_signals.insert(("DMAMUX2".to_string(), "OVR".to_string()));
|
||||
} else if flags.contains(&"DMAMUX") {
|
||||
panic!("should've been handled above");
|
||||
} else if flags.contains(&"EXTI") {
|
||||
for signal in parts[2].split(',') {
|
||||
interrupt_signals.insert(("EXTI".to_string(), signal.to_string()));
|
||||
}
|
||||
} else if name == "FLASH" {
|
||||
interrupt_signals.insert(("FLASH".to_string(), "GLOBAL".to_string()));
|
||||
} else if name == "CRS" {
|
||||
interrupt_signals.insert(("RCC".to_string(), "CRS".to_string()));
|
||||
} else if name == "RCC" {
|
||||
interrupt_signals.insert(("RCC".to_string(), "GLOBAL".to_string()));
|
||||
} else {
|
||||
if parts[2].is_empty() {
|
||||
continue;
|
||||
}
|
||||
.map(|name| (name.clone(), Vec::<String>::new()))
|
||||
.collect();
|
||||
|
||||
let peri_names: Vec<_> = parts[2].split(',').map(ToString::to_string).collect();
|
||||
let mut curr_peris = Vec::new();
|
||||
if peri_names.len() == 1 {
|
||||
curr_peris = peri_names.clone();
|
||||
}
|
||||
|
||||
let name2 = {
|
||||
if name == "USBWakeUp" || name == "USBWakeUp_RMP" {
|
||||
"USB_WKUP"
|
||||
// Parse IRQ interrupt_signals from the IRQ name.
|
||||
for part in tokenize_name(name2) {
|
||||
let part = {
|
||||
if part == "TAMPER" {
|
||||
"TAMP".to_string()
|
||||
} else {
|
||||
name.strip_suffix("_S").unwrap_or(&name)
|
||||
part
|
||||
}
|
||||
};
|
||||
|
||||
let mut peri_signals: HashMap<_, _> = peri_names
|
||||
.iter()
|
||||
.map(|name| (name.clone(), Vec::<String>::new()))
|
||||
.collect();
|
||||
|
||||
let mut curr_peris = Vec::new();
|
||||
if peri_names.len() == 1 {
|
||||
curr_peris = peri_names.clone();
|
||||
}
|
||||
|
||||
// Parse IRQ interrupt_signals from the IRQ name.
|
||||
for part in tokenize_name(name2) {
|
||||
let part = {
|
||||
if part == "TAMPER" {
|
||||
"TAMP".to_string()
|
||||
} else {
|
||||
part
|
||||
}
|
||||
};
|
||||
|
||||
if part == "LSECSS" {
|
||||
interrupt_signals.insert(("RCC".to_string(), "LSECSS".to_string()));
|
||||
} else if part == "CSS" {
|
||||
interrupt_signals.insert(("RCC".to_string(), "CSS".to_string()));
|
||||
} else if part == "LSE" {
|
||||
interrupt_signals.insert(("RCC".to_string(), "LSE".to_string()));
|
||||
} else if part == "CRS" {
|
||||
interrupt_signals.insert(("RCC".to_string(), "CRS".to_string()));
|
||||
if part == "LSECSS" {
|
||||
interrupt_signals.insert(("RCC".to_string(), "LSECSS".to_string()));
|
||||
} else if part == "CSS" {
|
||||
interrupt_signals.insert(("RCC".to_string(), "CSS".to_string()));
|
||||
} else if part == "LSE" {
|
||||
interrupt_signals.insert(("RCC".to_string(), "LSE".to_string()));
|
||||
} else if part == "CRS" {
|
||||
interrupt_signals.insert(("RCC".to_string(), "CRS".to_string()));
|
||||
} else {
|
||||
let pp = match_peris(&peri_names, &part);
|
||||
trace!(" part={part}, pp={pp:?}");
|
||||
if !pp.is_empty() {
|
||||
curr_peris = pp;
|
||||
} else {
|
||||
let pp = match_peris(&peri_names, &part);
|
||||
trace!(" part={part}, pp={pp:?}");
|
||||
if !pp.is_empty() {
|
||||
curr_peris = pp;
|
||||
} else {
|
||||
assert!(!curr_peris.is_empty());
|
||||
for p in &curr_peris {
|
||||
peri_signals.entry(p.clone()).or_default().push(part.clone());
|
||||
}
|
||||
assert!(!curr_peris.is_empty());
|
||||
for p in &curr_peris {
|
||||
peri_signals.entry(p.clone()).or_default().push(part.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (p, mut ss) in peri_signals.into_iter() {
|
||||
let known = valid_signals(&p);
|
||||
|
||||
// If we have no interrupt_signals for the peri, assume it's "global" so assign it all known ones
|
||||
if ss.is_empty() {
|
||||
if p.starts_with("COMP") {
|
||||
ss = vec!["WKUP".to_string()];
|
||||
} else {
|
||||
ss = known.clone();
|
||||
}
|
||||
}
|
||||
|
||||
for s in ss {
|
||||
if !known.contains(&s.clone()) {
|
||||
panic!("Unknown signal {s} for peri {p}, known={known:?}, parts={parts:?}");
|
||||
}
|
||||
interrupt_signals.insert((p.clone(), s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (p, s) in interrupt_signals {
|
||||
let key = if p == "USB_DRD_FS" { "USB".to_string() } else { p };
|
||||
chip_signals
|
||||
.entry(key)
|
||||
.or_default()
|
||||
.push(stm32_data_serde::chip::core::peripheral::Interrupt {
|
||||
signal: s,
|
||||
interrupt: name.clone(),
|
||||
});
|
||||
for (p, mut ss) in peri_signals.into_iter() {
|
||||
let known = valid_signals(&p);
|
||||
|
||||
// If we have no interrupt_signals for the peri, assume it's "global" so assign it all known ones
|
||||
if ss.is_empty() {
|
||||
if p.starts_with("COMP") {
|
||||
ss = vec!["WKUP".to_string()];
|
||||
} else {
|
||||
ss = known.clone();
|
||||
}
|
||||
}
|
||||
|
||||
for s in ss {
|
||||
if !known.contains(&s.clone()) {
|
||||
panic!("Unknown signal {s} for peri {p}, known={known:?}, parts={parts:?}");
|
||||
}
|
||||
interrupt_signals.insert((p.clone(), s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chip_interrupts.insert((parsed.name, parsed.version), chip_signals);
|
||||
for (p, s) in interrupt_signals {
|
||||
let key = if p == "USB_DRD_FS" { "USB".to_string() } else { p };
|
||||
let irqs = chip_signals.entry(key).or_default();
|
||||
let irq = stm32_data_serde::chip::core::peripheral::Interrupt {
|
||||
signal: s,
|
||||
interrupt: name.clone(),
|
||||
};
|
||||
if !irqs.contains(&irq) {
|
||||
irqs.push(irq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self(chip_interrupts))
|
||||
/*
|
||||
for (p, s) in &chip_signals {
|
||||
let mut m: HashMap<&str, Vec<&str>> = HashMap::new();
|
||||
for i in s {
|
||||
m.entry(&i.signal).or_default().push(&i.interrupt);
|
||||
}
|
||||
|
||||
for (signal, irqs) in &mut m {
|
||||
if irqs.len() != 1 {
|
||||
*irqs = irqs.iter().copied().filter(|_| true).collect();
|
||||
}
|
||||
|
||||
if irqs.len() != 1 {
|
||||
panic!("dup irqs on file {:?} peri {} signal {}: {:?}", f, p, signal, irqs);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
for p in &mut core.peripherals {
|
||||
if let Some(peri_irqs) = chip_signals.get(&p.name) {
|
||||
use stm32_data_serde::chip::core::peripheral::Interrupt;
|
||||
|
||||
//filter by available, because some are conditioned on <Die>
|
||||
|
||||
static EQUIVALENT_IRQS: &[(&str, &[&str])] = &[
|
||||
("HASH_RNG", &["RNG"]),
|
||||
("USB_HP_CAN_TX", &["CAN_TX"]),
|
||||
("USB_LP_CAN_RX0", &["CAN_RX0"]),
|
||||
];
|
||||
|
||||
let mut irqs: Vec<_> = peri_irqs
|
||||
.iter()
|
||||
.filter_map(|i| {
|
||||
if header_irqs.contains_key(&i.interrupt) {
|
||||
return Some(i.clone());
|
||||
}
|
||||
if let Some((_, eq_irqs)) = EQUIVALENT_IRQS.iter().find(|(irq, _)| irq == &i.interrupt) {
|
||||
for eq_irq in *eq_irqs {
|
||||
if header_irqs.contains_key(*eq_irq) {
|
||||
return Some(Interrupt {
|
||||
signal: i.signal.clone(),
|
||||
interrupt: eq_irq.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect();
|
||||
irqs.sort_by_key(|x| (x.signal.clone(), x.interrupt.clone()));
|
||||
irqs.dedup_by_key(|x| (x.signal.clone(), x.interrupt.clone()));
|
||||
|
||||
/*
|
||||
// check there are no duplicate signals.
|
||||
for i in 0..(irqs.len() - 1) {
|
||||
if irqs[i].signal == irqs[i + 1].signal {
|
||||
panic!(
|
||||
"duplicate interrupt on chip {} peripheral {} signal {}: irqs {} and {}",
|
||||
chip_name,
|
||||
p.name,
|
||||
irqs[i].signal,
|
||||
irqs[i].interrupt,
|
||||
irqs[i + 1].interrupt
|
||||
);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
p.interrupts = Some(irqs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -370,3 +489,34 @@ fn valid_signals(peri: &str) -> Vec<String> {
|
||||
}
|
||||
vec!["GLOBAL".to_string()]
|
||||
}
|
||||
|
||||
fn pick_nvic(chip_name: &str, core_name: &str) -> String {
|
||||
// Most chips have a single NVIC, named "NVIC"
|
||||
let mut res = "NVIC";
|
||||
|
||||
// Exception 1: Multicore: NVIC1 is the first core, NVIC2 is the second. We have to pick the right one.
|
||||
if ["H745", "H747", "H755", "H757", "WL54", "WL55"].contains(&&chip_name[5..9]) {
|
||||
if core_name == "cm7" {
|
||||
res = "NVIC1";
|
||||
} else {
|
||||
res = "NVIC2"
|
||||
}
|
||||
}
|
||||
if &chip_name[5..8] == "WL5" {
|
||||
if core_name == "cm4" {
|
||||
res = "NVIC1";
|
||||
} else {
|
||||
res = "NVIC2"
|
||||
}
|
||||
}
|
||||
|
||||
// Exception 2: TrustZone: NVIC1 is Secure mode, NVIC2 is NonSecure mode. For now, we pick the NonSecure one.
|
||||
if ["L5", "U5"].contains(&&chip_name[5..7]) {
|
||||
res = "NVIC2"
|
||||
}
|
||||
if ["H56", "H57", "WBA"].contains(&&chip_name[5..8]) {
|
||||
res = "NVIC2"
|
||||
}
|
||||
|
||||
res.to_string()
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user