diff --git a/stm32-data-gen/src/chips.rs b/stm32-data-gen/src/chips.rs index d940f46..82bb4e7 100644 --- a/stm32-data-gen/src/chips.rs +++ b/stm32-data-gen/src/chips.rs @@ -67,7 +67,7 @@ pub struct Chip { pub struct ChipGroup { chip_names: Vec, xml: xml::Mcu, - ips: HashMap, + pub ips: HashMap, pins: HashMap, family: Option, line: Option, @@ -810,73 +810,9 @@ fn process_core( chip_af: Option<&HashMap>>, 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 - - 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( diff --git a/stm32-data-gen/src/header.rs b/stm32-data-gen/src/header.rs index 158be9a..7052ad2 100644 --- a/stm32-data-gen/src/header.rs +++ b/stm32-data-gen/src/header.rs @@ -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 { + 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) -> anyhow::Result { let mut irqs = HashMap::>::new(); let mut defines = HashMap::::new(); diff --git a/stm32-data-gen/src/interrupts.rs b/stm32-data-gen/src/interrupts.rs index a3c1b71..bf60159 100644 --- a/stm32-data-gen/src/interrupts.rs +++ b/stm32-data-gen/src/interrupts.rs @@ -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>>, -); +pub struct ChipInterrupts { + // (nvic name, nvic version) => [cursed unparsed interrupt string] + irqs: HashMap<(String, String), Vec>, +} impl ChipInterrupts { pub fn parse() -> anyhow::Result { - 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::::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::::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 + + 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 { } 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() +}