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 {
|
pub struct ChipGroup {
|
||||||
chip_names: Vec<String>,
|
chip_names: Vec<String>,
|
||||||
xml: xml::Mcu,
|
xml: xml::Mcu,
|
||||||
ips: HashMap<String, xml::Ip>,
|
pub ips: HashMap<String, xml::Ip>,
|
||||||
pins: HashMap<String, xml::Pin>,
|
pins: HashMap<String, xml::Pin>,
|
||||||
family: Option<String>,
|
family: Option<String>,
|
||||||
line: 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>>>,
|
chip_af: Option<&HashMap<String, Vec<stm32_data_serde::chip::core::peripheral::Pin>>>,
|
||||||
dma_channels: &dma::DmaChannels,
|
dma_channels: &dma::DmaChannels,
|
||||||
) -> stm32_data_serde::chip::Core {
|
) -> 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();
|
let mut peri_kinds = HashMap::new();
|
||||||
peri_kinds.insert("UID".to_string(), "UID".to_string());
|
peri_kinds.insert("UID".to_string(), "UID".to_string());
|
||||||
for ip in group.ips.values() {
|
for ip in group.ips.values() {
|
||||||
@ -1067,41 +1003,6 @@ fn process_core(
|
|||||||
// sort pins to avoid diff for c pins
|
// sort pins to avoid diff for c pins
|
||||||
p.pins.sort_by_key(|x| (x.pin.clone(), x.signal.clone()));
|
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);
|
peripherals.insert(p.name.clone(), p);
|
||||||
}
|
}
|
||||||
if let Ok(extra_f) = std::fs::read(format!("data/extra/family/{}.yaml", group.family.as_ref().unwrap())) {
|
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;
|
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,
|
peripherals,
|
||||||
nvic_priority_bits,
|
nvic_priority_bits: None,
|
||||||
interrupts,
|
interrupts: vec![],
|
||||||
dma_channels: core_dma_channels,
|
dma_channels: core_dma_channels,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
chip_interrupts.process(&mut core, chip_name, h, group);
|
||||||
|
|
||||||
|
core
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_chip(
|
fn process_chip(
|
||||||
|
@ -196,6 +196,26 @@ pub struct ParsedHeader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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> {
|
fn parse(f: impl AsRef<std::path::Path>) -> anyhow::Result<Self> {
|
||||||
let mut irqs = HashMap::<String, HashMap<String, u8>>::new();
|
let mut irqs = HashMap::<String, HashMap<String, u8>>::new();
|
||||||
let mut defines = HashMap::<String, Defines>::new();
|
let mut defines = HashMap::<String, Defines>::new();
|
||||||
|
@ -2,6 +2,7 @@ use std::collections::{HashMap, HashSet};
|
|||||||
|
|
||||||
use log::*;
|
use log::*;
|
||||||
|
|
||||||
|
use crate::chips::ChipGroup;
|
||||||
use crate::regex;
|
use crate::regex;
|
||||||
|
|
||||||
mod xml {
|
mod xml {
|
||||||
@ -35,14 +36,14 @@ mod xml {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ChipInterrupts(
|
pub struct ChipInterrupts {
|
||||||
// (chip name, chip version), (signal name, [interrupt])
|
// (nvic name, nvic version) => [cursed unparsed interrupt string]
|
||||||
pub HashMap<(String, String), HashMap<String, Vec<stm32_data_serde::chip::core::peripheral::Interrupt>>>,
|
irqs: HashMap<(String, String), Vec<String>>,
|
||||||
);
|
}
|
||||||
|
|
||||||
impl ChipInterrupts {
|
impl ChipInterrupts {
|
||||||
pub fn parse() -> anyhow::Result<Self> {
|
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")?
|
let mut files: Vec<_> = glob::glob("sources/cubedb/mcu/IP/NVIC*_Modes.xml")?
|
||||||
.map(Result::unwrap)
|
.map(Result::unwrap)
|
||||||
@ -54,17 +55,70 @@ impl ChipInterrupts {
|
|||||||
trace!("parsing {f:?}");
|
trace!("parsing {f:?}");
|
||||||
let file = std::fs::read_to_string(&f)?;
|
let file = std::fs::read_to_string(&f)?;
|
||||||
let parsed: xml::Ip = quick_xml::de::from_str(&file)?;
|
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
|
.ref_parameters
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|param| param.name == "IRQn")
|
.filter(|param| param.name == "IRQn")
|
||||||
.flat_map(|param| param.possible_values)
|
.flat_map(|param| param.possible_values)
|
||||||
{
|
// F3 can remap USB IRQs, ignore them.
|
||||||
trace!(" irq={irq:?}");
|
.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 parts = {
|
||||||
let mut iter = irq.value.split(':');
|
let mut iter = nvic_string.split(':');
|
||||||
let parts = [(); 5].map(|_| iter.next().unwrap());
|
let parts = [(); 5].map(|_| iter.next().unwrap());
|
||||||
assert!(iter.next().is_none());
|
assert!(iter.next().is_none());
|
||||||
parts
|
parts
|
||||||
@ -98,14 +152,10 @@ impl ChipInterrupts {
|
|||||||
|
|
||||||
// F100xE MISC_REMAP remaps some DMA IRQs, so ST decided to give two names
|
// F100xE MISC_REMAP remaps some DMA IRQs, so ST decided to give two names
|
||||||
// to the same IRQ number.
|
// to the same IRQ number.
|
||||||
if parsed.version == "STM32F100E" && name == "DMA2_Channel4_5" {
|
if chip_nvic.version == "STM32F100E" && name == "DMA2_Channel4_5" {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// F3 can remap USB IRQs, ignore them.
|
//not supported
|
||||||
if parsed.version.starts_with("STM32F3") && irq.comment.contains("remap") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// not supported
|
|
||||||
if name == "LSECSSD" {
|
if name == "LSECSSD" {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -245,20 +295,89 @@ impl ChipInterrupts {
|
|||||||
|
|
||||||
for (p, s) in interrupt_signals {
|
for (p, s) in interrupt_signals {
|
||||||
let key = if p == "USB_DRD_FS" { "USB".to_string() } else { p };
|
let key = if p == "USB_DRD_FS" { "USB".to_string() } else { p };
|
||||||
chip_signals
|
let irqs = chip_signals.entry(key).or_default();
|
||||||
.entry(key)
|
let irq = stm32_data_serde::chip::core::peripheral::Interrupt {
|
||||||
.or_default()
|
|
||||||
.push(stm32_data_serde::chip::core::peripheral::Interrupt {
|
|
||||||
signal: s,
|
signal: s,
|
||||||
interrupt: name.clone(),
|
interrupt: name.clone(),
|
||||||
|
};
|
||||||
|
if !irqs.contains(&irq) {
|
||||||
|
irqs.push(irq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
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(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
chip_interrupts.insert((parsed.name, parsed.version), chip_signals);
|
|
||||||
}
|
}
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
irqs.sort_by_key(|x| (x.signal.clone(), x.interrupt.clone()));
|
||||||
|
irqs.dedup_by_key(|x| (x.signal.clone(), x.interrupt.clone()));
|
||||||
|
|
||||||
Ok(Self(chip_interrupts))
|
/*
|
||||||
|
// 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()]
|
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