diff --git a/data/registers/rcc_g0.yaml b/data/registers/rcc_g0.yaml index 763223c..c70f350 100644 --- a/data/registers/rcc_g0.yaml +++ b/data/registers/rcc_g0.yaml @@ -750,8 +750,8 @@ fieldset/CCIPR: bit_offset: 12 bit_size: 2 enum: I2C1SEL - - name: I2S2SEL - description: I2S1 clock source selection + - name: I2C2I2S1SEL + description: I2C2 or I2S1 clock source selection bit_offset: 14 bit_size: 2 enum: I2C2I2S1SEL diff --git a/data/registers/rcc_h5.yaml b/data/registers/rcc_h5.yaml index 00781f0..6c6c2a8 100644 --- a/data/registers/rcc_h5.yaml +++ b/data/registers/rcc_h5.yaml @@ -1596,11 +1596,11 @@ fieldset/CCIPR5: bit_offset: 0 bit_size: 3 enum: ADCDACSEL - - name: DACSEL + - name: DACHOLDSEL description: DAC hold clock bit_offset: 3 bit_size: 1 - enum: DACSEL + enum: DACHOLDSEL - name: RNGSEL description: RNG kernel clock source selection bit_offset: 4 @@ -2156,7 +2156,7 @@ enum/CKPERSEL: - name: HSE description: hse_ck selected as kernel clock value: 2 -enum/DACSEL: +enum/DACHOLDSEL: bit_size: 1 variants: - name: DAC_HOLD diff --git a/data/registers/rcc_h50.yaml b/data/registers/rcc_h50.yaml index 42bc728..a97a5fb 100644 --- a/data/registers/rcc_h50.yaml +++ b/data/registers/rcc_h50.yaml @@ -895,11 +895,11 @@ fieldset/CCIPR5: bit_offset: 0 bit_size: 3 enum: ADCDACSEL - - name: DACSEL + - name: DACHOLDSEL description: DAC hold clock bit_offset: 3 bit_size: 1 - enum: DACSEL + enum: DACHOLDSEL - name: RNGSEL description: RNG kernel clock source selection bit_offset: 4 @@ -1365,7 +1365,7 @@ enum/CKPERSEL: - name: HSE description: hse_ck selected as kernel clock value: 2 -enum/DACSEL: +enum/DACHOLDSEL: bit_size: 1 variants: - name: DAC_HOLD diff --git a/data/registers/rcc_h7.yaml b/data/registers/rcc_h7.yaml index 7b19545..e98446c 100644 --- a/data/registers/rcc_h7.yaml +++ b/data/registers/rcc_h7.yaml @@ -920,7 +920,7 @@ fieldset/APB1HENR: description: Clock Recovery System peripheral clock enable bit_offset: 1 bit_size: 1 - - name: SWPEN + - name: SWPMIEN description: SWPMI Peripheral Clocks Enable bit_offset: 2 bit_size: 1 @@ -951,7 +951,7 @@ fieldset/APB1HLPENR: description: Clock Recovery System peripheral clock enable during CSleep mode bit_offset: 1 bit_size: 1 - - name: SWPLPEN + - name: SWPMILPEN description: SWPMI Peripheral Clocks Enable During CSleep Mode bit_offset: 2 bit_size: 1 @@ -982,7 +982,7 @@ fieldset/APB1HRSTR: description: Clock Recovery System reset bit_offset: 1 bit_size: 1 - - name: SWPRST + - name: SWPMIRST description: SWPMI block reset bit_offset: 2 bit_size: 1 @@ -2186,7 +2186,7 @@ fieldset/C1_APB1HENR: description: Clock Recovery System peripheral clock enable bit_offset: 1 bit_size: 1 - - name: SWPEN + - name: SWPMIEN description: SWPMI Peripheral Clocks Enable bit_offset: 2 bit_size: 1 @@ -2209,7 +2209,7 @@ fieldset/C1_APB1HLPENR: description: Clock Recovery System peripheral clock enable during CSleep mode bit_offset: 1 bit_size: 1 - - name: SWPLPEN + - name: SWPMILPEN description: SWPMI Peripheral Clocks Enable During CSleep Mode bit_offset: 2 bit_size: 1 @@ -3142,11 +3142,11 @@ fieldset/D2CCIP1R: bit_offset: 28 bit_size: 2 enum: FDCANSEL - - name: SWPSEL + - name: SWPMISEL description: SWPMI kernel clock source selection bit_offset: 31 bit_size: 1 - enum: SWPSEL + enum: SWPMISEL fieldset/D2CCIP2R: description: RCC Domain 2 Kernel Clock Configuration Register fields: @@ -5395,8 +5395,8 @@ enum/SPDIFRXSEL: enum/SPI45SEL: bit_size: 3 variants: - - name: APB - description: APB clock selected as peripheral clock + - name: PCLK2 + description: APB2 clock selected as peripheral clock value: 0 - name: PLL2_Q description: pll2_q selected as peripheral clock @@ -5458,10 +5458,10 @@ enum/SW: - name: PLL1_P description: PLL1 selected as system clock value: 3 -enum/SWPSEL: +enum/SWPMISEL: bit_size: 1 variants: - - name: PCLK + - name: PCLK1 description: pclk selected as peripheral clock value: 0 - name: HSI diff --git a/data/registers/rcc_h7ab.yaml b/data/registers/rcc_h7ab.yaml index 96512be..7280b5e 100644 --- a/data/registers/rcc_h7ab.yaml +++ b/data/registers/rcc_h7ab.yaml @@ -852,7 +852,7 @@ fieldset/APB1HENR: description: Clock Recovery System peripheral clock enable bit_offset: 1 bit_size: 1 - - name: SWPEN + - name: SWPMIEN description: SWPMI Peripheral Clocks Enable bit_offset: 2 bit_size: 1 @@ -883,7 +883,7 @@ fieldset/APB1HLPENR: description: Clock Recovery System peripheral clock enable during CSleep mode bit_offset: 1 bit_size: 1 - - name: SWPLPEN + - name: SWPMILPEN description: SWPMI Peripheral Clocks Enable During CSleep Mode bit_offset: 2 bit_size: 1 @@ -914,7 +914,7 @@ fieldset/APB1HRSTR: description: Clock Recovery System reset bit_offset: 1 bit_size: 1 - - name: SWPRST + - name: SWPMIRST description: SWPMI block reset bit_offset: 2 bit_size: 1 @@ -2093,11 +2093,11 @@ fieldset/D2CCIP1R: bit_offset: 28 bit_size: 2 enum: FDCANSEL - - name: SWPSEL + - name: SWPMISEL description: SWPMI kernel clock source selection bit_offset: 31 bit_size: 1 - enum: SWPSEL + enum: SWPMISEL fieldset/D2CCIP2R: description: RCC Domain 2 Kernel Clock Configuration Register fields: @@ -4309,8 +4309,8 @@ enum/SPDIFRXSEL: enum/SPI45SEL: bit_size: 3 variants: - - name: APB - description: APB clock selected as peripheral clock + - name: HCLK2 + description: APB2 clock selected as peripheral clock value: 0 - name: PLL2_Q description: pll2_q selected as peripheral clock @@ -4372,10 +4372,10 @@ enum/SW: - name: PLL1_P description: PLL1 selected as system clock value: 3 -enum/SWPSEL: +enum/SWPMISEL: bit_size: 1 variants: - - name: PCLK + - name: PCLK1 description: pclk selected as peripheral clock value: 0 - name: HSI diff --git a/data/registers/rcc_h7rm0433.yaml b/data/registers/rcc_h7rm0433.yaml index f3e4b7b..12ee476 100644 --- a/data/registers/rcc_h7rm0433.yaml +++ b/data/registers/rcc_h7rm0433.yaml @@ -908,7 +908,7 @@ fieldset/APB1HENR: description: Clock Recovery System peripheral clock enable bit_offset: 1 bit_size: 1 - - name: SWPEN + - name: SWPMIEN description: SWPMI Peripheral Clocks Enable bit_offset: 2 bit_size: 1 @@ -939,7 +939,7 @@ fieldset/APB1HLPENR: description: Clock Recovery System peripheral clock enable during CSleep mode bit_offset: 1 bit_size: 1 - - name: SWPLPEN + - name: SWPMILPEN description: SWPMI Peripheral Clocks Enable During CSleep Mode bit_offset: 2 bit_size: 1 @@ -970,7 +970,7 @@ fieldset/APB1HRSTR: description: Clock Recovery System reset bit_offset: 1 bit_size: 1 - - name: SWPRST + - name: SWPMIRST description: SWPMI block reset bit_offset: 2 bit_size: 1 @@ -2174,7 +2174,7 @@ fieldset/C1_APB1HENR: description: Clock Recovery System peripheral clock enable bit_offset: 1 bit_size: 1 - - name: SWPEN + - name: SWPMIEN description: SWPMI Peripheral Clocks Enable bit_offset: 2 bit_size: 1 @@ -2197,7 +2197,7 @@ fieldset/C1_APB1HLPENR: description: Clock Recovery System peripheral clock enable during CSleep mode bit_offset: 1 bit_size: 1 - - name: SWPLPEN + - name: SWPMILPEN description: SWPMI Peripheral Clocks Enable During CSleep Mode bit_offset: 2 bit_size: 1 @@ -3125,11 +3125,11 @@ fieldset/D2CCIP1R: bit_offset: 28 bit_size: 2 enum: FDCANSEL - - name: SWPSEL + - name: SWPMISEL description: SWPMI kernel clock source selection bit_offset: 31 bit_size: 1 - enum: SWPSEL + enum: SWPMISEL fieldset/D2CCIP2R: description: RCC Domain 2 Kernel Clock Configuration Register fields: @@ -5378,8 +5378,8 @@ enum/SPDIFRXSEL: enum/SPI45SEL: bit_size: 3 variants: - - name: APB - description: APB clock selected as peripheral clock + - name: PCLK2 + description: APB2 clock selected as peripheral clock value: 0 - name: PLL2_Q description: pll2_q selected as peripheral clock @@ -5441,10 +5441,10 @@ enum/SW: - name: PLL1_P description: PLL1 selected as system clock value: 3 -enum/SWPSEL: +enum/SWPMISEL: bit_size: 1 variants: - - name: PCLK + - name: PCLK1 description: pclk selected as peripheral clock value: 0 - name: HSI diff --git a/stm32-data-gen/src/chips.rs b/stm32-data-gen/src/chips.rs index fccd872..c698c2c 100644 --- a/stm32-data-gen/src/chips.rs +++ b/stm32-data-gen/src/chips.rs @@ -834,7 +834,7 @@ fn process_group( headers: &header::Headers, af: &gpio_af::Af, chip_interrupts: &interrupts::ChipInterrupts, - peripheral_to_clock: &rcc::PeripheralToClock, + peripheral_to_clock: &rcc::ParsedRccs, dma_channels: &dma::DmaChannels, chips: &HashMap, memories: &memory::Memories, @@ -889,7 +889,7 @@ fn process_core( group: &ChipGroup, chip_interrupts: &interrupts::ChipInterrupts, peri_matcher: &mut PeriMatcher, - peripheral_to_clock: &rcc::PeripheralToClock, + peripheral_to_clock: &rcc::ParsedRccs, rcc_block: (&str, &str, &str), chip_af: Option<&HashMap>>, dma_channels: &dma::DmaChannels, @@ -1115,15 +1115,8 @@ fn process_core( }); } - if let Some(rcc_info) = peripheral_to_clock.match_peri_clock( - &( - rcc_block.0.to_string(), - rcc_block.1.to_string(), - rcc_block.2.to_string(), - ), - &pname, - ) { - p.rcc = Some(rcc_info.clone()); + if let Some(rcc_info) = peripheral_to_clock.match_peri_clock(rcc_block.1, &pname) { + p.rcc = Some(rcc_info); } if let Some(pins) = periph_pins.get_mut(&pname) { // merge the core xml info with GPIO xml info to hopefully get the full picture @@ -1468,7 +1461,7 @@ pub fn dump_all_chips( headers: header::Headers, af: gpio_af::Af, chip_interrupts: interrupts::ChipInterrupts, - peripheral_to_clock: rcc::PeripheralToClock, + peripheral_to_clock: rcc::ParsedRccs, dma_channels: dma::DmaChannels, chips: std::collections::HashMap, memories: memory::Memories, diff --git a/stm32-data-gen/src/main.rs b/stm32-data-gen/src/main.rs index 4e5657a..677e31a 100644 --- a/stm32-data-gen/src/main.rs +++ b/stm32-data-gen/src/main.rs @@ -76,7 +76,7 @@ fn main() -> anyhow::Result<()> { let chip_interrupts = interrupts::ChipInterrupts::parse()?; // stopwatch.section("Parsing RCC registers"); - let peripheral_to_clock = rcc::PeripheralToClock::parse(®isters)?; + let peripheral_to_clock = rcc::ParsedRccs::parse(®isters)?; // stopwatch.section("Parsing docs"); let docs = docs::Docs::parse()?; diff --git a/stm32-data-gen/src/rcc.rs b/stm32-data-gen/src/rcc.rs index 5fb0b77..8884a64 100644 --- a/stm32-data-gen/src/rcc.rs +++ b/stm32-data-gen/src/rcc.rs @@ -1,42 +1,49 @@ -use std::cmp::Ordering; -use std::collections::hash_map::Entry; use std::collections::{HashMap, HashSet}; -use std::hash::Hash; -use anyhow::{anyhow, Ok}; -use chiptool::ir::{BlockItemInner, Enum}; -use stm32_data_serde::chip::core::peripheral; +use anyhow::{anyhow, bail, Ok}; +use chiptool::ir::{BlockItemInner, Enum, IR}; use stm32_data_serde::chip::core::peripheral::rcc::{Mux, StopMode}; +use stm32_data_serde::chip::core::peripheral::{self, rcc}; use crate::regex; use crate::registers::Registers; -/// Deterministically insert into a `HashMap` -fn insert_into_map(hash_map: &mut HashMap, key: K, value: V, mut compare: F) -where - K: Eq + Hash, - F: FnMut(&V, &V) -> Ordering, -{ - match hash_map.entry(key) { - Entry::Vacant(e) => { - e.insert(value); - } - Entry::Occupied(mut e) => { - if compare(&value, e.get()) == Ordering::Less { - e.insert(value); - } - } - }; +#[derive(Debug)] +pub struct ParsedRccs { + /// RCC version -> parsed info + rccs: HashMap, } #[derive(Debug)] -pub struct PeripheralToClock( - HashMap<(String, String, String), HashMap>, -); +struct ParsedRcc { + /// name -> en/rst bit info + en_rst: HashMap, + /// name -> mux info + mux: HashMap, +} -impl PeripheralToClock { +#[derive(Debug)] +struct EnRst { + enable: rcc::Enable, + reset: Option, + clock: String, + stop_mode: StopMode, +} + +impl ParsedRccs { pub fn parse(registers: &Registers) -> anyhow::Result { - let mut peripheral_to_clock = HashMap::new(); + let mut rccs = HashMap::new(); + + for (rcc_name, ir) in ®isters.registers { + if let Some(rcc_name) = rcc_name.strip_prefix("rcc_") { + rccs.insert(rcc_name.to_string(), Self::parse_rcc(rcc_name, ir)?); + } + } + + Ok(Self { rccs }) + } + + fn parse_rcc(rcc_version: &str, ir: &IR) -> anyhow::Result { let allowed_variants = HashSet::from([ "DISABLE", "SYS", @@ -118,212 +125,173 @@ impl PeripheralToClock { "HSI256_MSIK1024_MSIK4", ]); - for (rcc_name, ir) in ®isters.registers { - if let Some(rcc_name) = rcc_name.strip_prefix("rcc_") { - let rcc_enum_map: HashMap<&String, HashMap<&String, (&String, &Enum)>> = { - let rcc_blocks = &ir.blocks.get("RCC").unwrap().items; + let rcc_enum_map: HashMap<&String, HashMap<&String, (&String, &Enum)>> = { + let rcc_blocks = &ir.blocks.get("RCC").unwrap().items; - rcc_blocks - .iter() - .filter_map(|b| match &b.inner { - BlockItemInner::Register(register) => register.fieldset.as_ref().map(|f| { - let f = ir.fieldsets.get(f).unwrap(); - ( - &b.name, - f.fields - .iter() - .filter_map(|f| { - let enumm_name = f.enumm.as_ref()?; - let enumm = ir.enums.get(enumm_name)?; + rcc_blocks + .iter() + .filter_map(|b| match &b.inner { + BlockItemInner::Register(register) => register.fieldset.as_ref().map(|f| { + let f = ir.fieldsets.get(f).unwrap(); + ( + &b.name, + f.fields + .iter() + .filter_map(|f| { + let enumm_name = f.enumm.as_ref()?; + let enumm = ir.enums.get(enumm_name)?; - Some((&f.name, (enumm_name, enumm))) - }) - .collect(), - ) - }), - _ => None, - }) - .collect() - }; + Some((&f.name, (enumm_name, enumm))) + }) + .collect(), + ) + }), + _ => None, + }) + .collect() + }; - let check_mux = |register: &String, field: &String| -> Result<(), anyhow::Error> { - let block_map = match rcc_enum_map.get(register) { - Some(block_map) => block_map, - _ => return Ok(()), + let check_mux = |register: &String, field: &String| -> Result<(), anyhow::Error> { + let block_map = match rcc_enum_map.get(register) { + Some(block_map) => block_map, + _ => return Ok(()), + }; + + let (enumm_name, enumm) = match block_map.get(field) { + Some(enumm) => enumm, + _ => return Ok(()), + }; + + for v in &enumm.variants { + if let Some(captures) = regex!(r"^([A-Z0-9_]+)_DIV_\d+?$").captures(v.name.as_str()) { + let name = captures.get(1).unwrap(); + + if !allowed_variants.contains(name.as_str()) { + return Err(anyhow!( + "rcc: prohibited variant name {} in enum {} for rcc_{}", + v.name.as_str(), + enumm_name, + rcc_version + )); + } + } else if !allowed_variants.contains(v.name.as_str()) { + return Err(anyhow!( + "rcc: prohibited variant name {} in enum {} for rcc_{}", + v.name.as_str(), + enumm_name, + rcc_version + )); + } + } + + Ok(()) + }; + + let mux_regexes = &[ + regex!(r"^DCKCFGR\d?/(.+)SEL$"), + regex!(r"^CCIPR\d?/(.+)SEL$"), + regex!(r"^D\dCCIP\d?R/(.+)SEL$"), + regex!(r"^CFGR\d/(.+)SW$"), + ]; + + let mut mux = HashMap::new(); + for (reg, body) in &ir.fieldsets { + for field in &body.fields { + let key = format!("{}/{}", reg, field.name); + if let Some(capture) = mux_regexes.iter().find_map(|r| r.captures(&key)) { + let peri = capture.get(1).unwrap().as_str(); + + // TODO: these bits are duplicated on F4, we need to split the F4 RCCs more. + if rcc_version.starts_with("f4") && reg == "DCKCFGR2" && (peri == "CLK48" || peri == "SDIO") { + continue; + } + + check_mux(reg, &field.name)?; + + let val = Mux { + register: reg.to_ascii_lowercase(), + field: field.name.to_ascii_lowercase(), }; - let (enumm_name, enumm) = match block_map.get(field) { - Some(enumm) => enumm, - _ => return Ok(()), - }; - - for v in &enumm.variants { - if let Some(captures) = regex!(r"^([A-Z0-9_]+)_DIV_\d+?$").captures(v.name.as_str()) { - let name = captures.get(1).unwrap(); - - if !allowed_variants.contains(name.as_str()) { - return Err(anyhow!( - "rcc: prohibited variant name {} in enum {} for rcc_{}", - v.name.as_str(), - enumm_name, - rcc_name - )); - } - } else if !allowed_variants.contains(v.name.as_str()) { - return Err(anyhow!( - "rcc: prohibited variant name {} in enum {} for rcc_{}", - v.name.as_str(), - enumm_name, - rcc_name - )); - } - } - - Ok(()) - }; - - let mut family_muxes = HashMap::new(); - for (reg, body) in &ir.fieldsets { - let key = format!("fieldset/{reg}"); - if regex!(r"^fieldset/(CCIPR|DCKCFGR)\d?$").captures(&key).is_some() { - for field in &body.fields { - if let Some(peri) = field.name.strip_suffix("SEL") { - check_mux(reg, &field.name)?; - - insert_into_map( - &mut family_muxes, - peri.to_string(), - Mux { - register: reg.to_ascii_lowercase(), - field: field.name.to_ascii_lowercase(), - }, - |mux1: &Mux, mux2: &Mux| mux1.register.cmp(&mux2.register), - ); - } - } - } else if regex!(r"^fieldset/CFGR\d?$").captures(&key).is_some() { - for field in &body.fields { - if let Some(peri) = field.name.strip_suffix("SW") { - check_mux(reg, &field.name)?; - - insert_into_map( - &mut family_muxes, - peri.to_string(), - Mux { - register: reg.to_ascii_lowercase(), - field: field.name.to_ascii_lowercase(), - }, - |mux1: &Mux, mux2: &Mux| mux1.register.cmp(&mux2.register), - ); - } - } - } else if regex!(r"^fieldset/D\d?CCIPR$").captures(&key).is_some() { - for field in &body.fields { - if let Some(peri) = field.name.strip_suffix("SEL") { - if family_muxes.get(peri).is_some() && reg != "D1CCIPR" { - continue; - } - - check_mux(reg, &field.name)?; - - insert_into_map( - &mut family_muxes, - peri.to_string(), - Mux { - register: reg.to_ascii_lowercase(), - field: field.name.to_ascii_lowercase(), - }, - |mux1: &Mux, mux2: &Mux| mux1.register.cmp(&mux2.register), - ); - } - } + if mux.insert(peri.to_string(), val).is_some() { + bail!("rcc: duplicate mux for {} for rcc_{}", peri, rcc_version); } } - - 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") { - let peri = if peri == "RTCAPB" { "RTC" } else { peri }; - let stop_mode = if peri == "RTC" { - StopMode::Standby - } else if peri.starts_with("LP") { - StopMode::Stop2 - } else { - StopMode::Stop1 - }; - - // 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(®.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").to_ascii_lowercase(), - field: format!("{peri}RST").to_ascii_lowercase(), - }); - } - } - - let mux = family_muxes.get(peri).cloned(); - - match family_clocks.entry(peri.to_string()) { - Entry::Vacant(e) => { - e.insert(peripheral::Rcc { - clock: peri_clock - .to_ascii_lowercase() - .replace("ahb", "hclk") - .replace("apb", "pclk"), - enable: peripheral::rcc::Enable { - register: reg.to_ascii_lowercase(), - field: field.name.to_ascii_lowercase(), - }, - stop_mode, - reset, - mux, - }); - } - Entry::Occupied(_) => { - return Err(anyhow!("rcc: duplicate clock for {} for rcc_{}", peri, rcc_name)); - } - }; - } - } - } - } - peripheral_to_clock.insert( - ("rcc".to_string(), rcc_name.to_string(), "RCC".to_string()), - family_clocks, - ); } } - Ok(Self(peripheral_to_clock)) + // Parse xxEN/xxRST bits. + let mut en_rst = HashMap::new(); + for (reg, body) in &ir.fieldsets { + if let Some(m) = regex!(r"^((A[PH]B\d?)|GPIO)[LH]?ENR\d?$").captures(reg) { + 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") { + let peri = if peri == "RTCAPB" { "RTC" } else { peri }; + + let mut reset = None; + if let Some(rstr) = ir.fieldsets.get(®.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").to_ascii_lowercase(), + field: format!("{peri}RST").to_ascii_lowercase(), + }); + } + } + + let stop_mode = if peri == "RTC" { + StopMode::Standby + } else if peri.starts_with("LP") { + StopMode::Stop2 + } else { + StopMode::Stop1 + }; + + // 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 peri_clock = peri_clock + .to_ascii_lowercase() + .replace("ahb", "hclk") + .replace("apb", "pclk"); + + let val = EnRst { + enable: peripheral::rcc::Enable { + register: reg.to_ascii_lowercase(), + field: field.name.to_ascii_lowercase(), + }, + reset, + clock: peri_clock, + stop_mode, + }; + + if en_rst.insert(peri.to_string(), val).is_some() { + bail!("rcc: duplicate en/rst for {} for rcc_{}", peri, rcc_version); + } + } + } + } + } + + Ok(ParsedRcc { en_rst, mux }) } pub fn match_peri_clock( &self, - rcc_block: &(String, String, String), + rcc_version: &str, peri_name: &str, - ) -> Option<&stm32_data_serde::chip::core::peripheral::Rcc> { - const PERI_OVERRIDE: &[(&str, &[&str])] = &[ + ) -> Option { + const FALLBACKS: &[(&str, &[&str])] = &[ ("DCMI", &["DCMI_PSSI"]), ("PSSI", &["DCMI_PSSI"]), ("FDCAN1", &["FDCAN12", "FDCAN"]), @@ -339,27 +307,63 @@ impl PeripheralToClock { ("DAC1", &["DAC12", "DAC"]), ("DAC2", &["DAC12", "DAC"]), ("ETH", &["ETHMAC", "ETH1MAC"]), + ("SPI1", &["SPI12", "SPI123"]), + ("SPI2", &["SPI12", "SPI123"]), + ("SPI3", &["SPI123"]), + ("SPI4", &["SPI145"]), + ("SPI5", &["SPI145"]), + ("SAI1", &["SAI12"]), + ("SAI2", &["SAI12"]), + ("USART2", &["USART234578"]), + ("USART3", &["USART234578"]), + ("UART4", &["USART234578"]), + ("UART5", &["USART234578"]), + ("UART7", &["USART234578"]), + ("UART8", &["USART234578"]), + ("USART1", &["USART16910"]), + ("USART6", &["USART16910"]), + ("USART10", &["USART16910"]), + ("UART9", &["USART16910"]), + ("I2C1", &["I2C1235"]), + ("I2C2", &["I2C1235"]), + ("I2C3", &["I2C1235"]), + ("I2C5", &["I2C1235"]), ]; - let clocks = self.0.get(rcc_block)?; - if let Some(res) = clocks.get(peri_name) { - return Some(res); - } + let rcc = self.rccs.get(rcc_version)?; - if let Some((_, rename)) = PERI_OVERRIDE.iter().find(|(n, _)| *n == peri_name) { - for &n in *rename { - if let Some(res) = clocks.get(n) { - return Some(res); - } - } - } + let en_rst = get_with_fallback(peri_name, &rcc.en_rst, FALLBACKS)?; + let mux = get_with_fallback(peri_name, &rcc.mux, FALLBACKS); - if let Some(n) = peri_name.strip_suffix('1') { - if let Some(res) = clocks.get(n) { + Some(peripheral::Rcc { + clock: en_rst.clock.clone(), + enable: en_rst.enable.clone(), + reset: en_rst.reset.clone(), + stop_mode: en_rst.stop_mode.clone(), + + mux: mux.cloned(), + }) + } +} + +fn get_with_fallback<'a, T>(key: &str, map: &'a HashMap, fallbacks: &[(&str, &[&str])]) -> Option<&'a T> { + if let Some(res) = map.get(key) { + return Some(res); + } + + if let Some((_, rename)) = fallbacks.iter().find(|(n, _)| *n == key) { + for &n in *rename { + if let Some(res) = map.get(n) { return Some(res); } } - - None } + + if let Some(n) = key.strip_suffix('1') { + if let Some(res) = map.get(n) { + return Some(res); + } + } + + None }