2023-03-27 12:17:53 +02:00

98 lines
4.1 KiB
Rust

use std::collections::HashMap;
use crate::regex;
use crate::registers::Registers;
#[derive(Debug)]
pub struct PeripheralToClock(
HashMap<(String, String, String), HashMap<String, stm32_data_serde::chip::core::peripheral::Rcc>>,
);
impl PeripheralToClock {
pub fn parse(registers: &Registers) -> anyhow::Result<Self> {
let mut peripheral_to_clock = HashMap::new();
for (rcc_name, ir) in &registers.registers {
if let Some(rcc_name) = rcc_name.strip_prefix("rcc_") {
let mut family_clocks = HashMap::new();
for (reg, body) in &ir.fieldsets {
let key = format!("fieldset/{reg}");
if let Some(m) = regex!(r"^fieldset/((A[PH]B\d?)|GPIO)[LH]?ENR\d?$").captures(&key) {
let clock = m.get(1).unwrap().as_str();
let clock = match clock {
"AHB" => "AHB1",
"APB" => "APB1",
clock => clock,
};
for field in &body.fields {
if let Some(peri) = field.name.strip_suffix("EN") {
// Timers are a bit special, they may have a x2 freq
let peri_clock = {
if regex!(r"^TIM\d+$").is_match(peri) {
format!("{clock}_TIM")
} else {
clock.to_string()
}
};
let mut reset = None;
if let Some(rstr) = ir.fieldsets.get(&reg.replace("ENR", "RSTR")) {
if let Some(_field) =
rstr.fields.iter().find(|field| field.name == format!("{peri}RST"))
{
reset = Some(stm32_data_serde::chip::core::peripheral::rcc::Reset {
register: reg.replace("ENR", "RSTR"),
field: format!("{peri}RST"),
});
}
}
let res = stm32_data_serde::chip::core::peripheral::Rcc {
clock: peri_clock,
enable: stm32_data_serde::chip::core::peripheral::rcc::Enable {
register: reg.clone(),
field: field.name.clone(),
},
reset,
};
family_clocks.insert(peri.to_string(), res);
}
}
}
}
peripheral_to_clock.insert(
("rcc".to_string(), rcc_name.to_string(), "RCC".to_string()),
family_clocks,
);
}
}
Ok(Self(peripheral_to_clock))
}
pub fn match_peri_clock(
&self,
rcc_block: &(String, String, String),
peri_name: &str,
) -> Option<&stm32_data_serde::chip::core::peripheral::Rcc> {
const PERI_OVERRIDE: &[(&str, &[&str])] = &[("DCMI", &["DCMI_PSSI"]), ("PSSI", &["DCMI_PSSI"])];
let clocks = self.0.get(rcc_block)?;
if let Some(res) = clocks.get(peri_name) {
Some(res)
} else if let Some(peri_name) = peri_name.strip_suffix('1') {
self.match_peri_clock(rcc_block, peri_name)
} else if let Some((_, rename)) = PERI_OVERRIDE.iter().find(|(n, _)| *n == peri_name) {
for n in *rename {
if let Some(res) = self.match_peri_clock(rcc_block, n) {
return Some(res);
}
}
None
} else {
None
}
}
}