Refactor RCC code to find more muxes.

Fixes #383
This commit is contained in:
Dario Nieuwenhuis 2024-02-10 02:40:36 +01:00
parent 028efe4e6e
commit 0c921dde2e
9 changed files with 282 additions and 285 deletions

View File

@ -750,8 +750,8 @@ fieldset/CCIPR:
bit_offset: 12 bit_offset: 12
bit_size: 2 bit_size: 2
enum: I2C1SEL enum: I2C1SEL
- name: I2S2SEL - name: I2C2I2S1SEL
description: I2S1 clock source selection description: I2C2 or I2S1 clock source selection
bit_offset: 14 bit_offset: 14
bit_size: 2 bit_size: 2
enum: I2C2I2S1SEL enum: I2C2I2S1SEL

View File

@ -1596,11 +1596,11 @@ fieldset/CCIPR5:
bit_offset: 0 bit_offset: 0
bit_size: 3 bit_size: 3
enum: ADCDACSEL enum: ADCDACSEL
- name: DACSEL - name: DACHOLDSEL
description: DAC hold clock description: DAC hold clock
bit_offset: 3 bit_offset: 3
bit_size: 1 bit_size: 1
enum: DACSEL enum: DACHOLDSEL
- name: RNGSEL - name: RNGSEL
description: RNG kernel clock source selection description: RNG kernel clock source selection
bit_offset: 4 bit_offset: 4
@ -2156,7 +2156,7 @@ enum/CKPERSEL:
- name: HSE - name: HSE
description: hse_ck selected as kernel clock description: hse_ck selected as kernel clock
value: 2 value: 2
enum/DACSEL: enum/DACHOLDSEL:
bit_size: 1 bit_size: 1
variants: variants:
- name: DAC_HOLD - name: DAC_HOLD

View File

@ -895,11 +895,11 @@ fieldset/CCIPR5:
bit_offset: 0 bit_offset: 0
bit_size: 3 bit_size: 3
enum: ADCDACSEL enum: ADCDACSEL
- name: DACSEL - name: DACHOLDSEL
description: DAC hold clock description: DAC hold clock
bit_offset: 3 bit_offset: 3
bit_size: 1 bit_size: 1
enum: DACSEL enum: DACHOLDSEL
- name: RNGSEL - name: RNGSEL
description: RNG kernel clock source selection description: RNG kernel clock source selection
bit_offset: 4 bit_offset: 4
@ -1365,7 +1365,7 @@ enum/CKPERSEL:
- name: HSE - name: HSE
description: hse_ck selected as kernel clock description: hse_ck selected as kernel clock
value: 2 value: 2
enum/DACSEL: enum/DACHOLDSEL:
bit_size: 1 bit_size: 1
variants: variants:
- name: DAC_HOLD - name: DAC_HOLD

View File

@ -920,7 +920,7 @@ fieldset/APB1HENR:
description: Clock Recovery System peripheral clock enable description: Clock Recovery System peripheral clock enable
bit_offset: 1 bit_offset: 1
bit_size: 1 bit_size: 1
- name: SWPEN - name: SWPMIEN
description: SWPMI Peripheral Clocks Enable description: SWPMI Peripheral Clocks Enable
bit_offset: 2 bit_offset: 2
bit_size: 1 bit_size: 1
@ -951,7 +951,7 @@ fieldset/APB1HLPENR:
description: Clock Recovery System peripheral clock enable during CSleep mode description: Clock Recovery System peripheral clock enable during CSleep mode
bit_offset: 1 bit_offset: 1
bit_size: 1 bit_size: 1
- name: SWPLPEN - name: SWPMILPEN
description: SWPMI Peripheral Clocks Enable During CSleep Mode description: SWPMI Peripheral Clocks Enable During CSleep Mode
bit_offset: 2 bit_offset: 2
bit_size: 1 bit_size: 1
@ -982,7 +982,7 @@ fieldset/APB1HRSTR:
description: Clock Recovery System reset description: Clock Recovery System reset
bit_offset: 1 bit_offset: 1
bit_size: 1 bit_size: 1
- name: SWPRST - name: SWPMIRST
description: SWPMI block reset description: SWPMI block reset
bit_offset: 2 bit_offset: 2
bit_size: 1 bit_size: 1
@ -2186,7 +2186,7 @@ fieldset/C1_APB1HENR:
description: Clock Recovery System peripheral clock enable description: Clock Recovery System peripheral clock enable
bit_offset: 1 bit_offset: 1
bit_size: 1 bit_size: 1
- name: SWPEN - name: SWPMIEN
description: SWPMI Peripheral Clocks Enable description: SWPMI Peripheral Clocks Enable
bit_offset: 2 bit_offset: 2
bit_size: 1 bit_size: 1
@ -2209,7 +2209,7 @@ fieldset/C1_APB1HLPENR:
description: Clock Recovery System peripheral clock enable during CSleep mode description: Clock Recovery System peripheral clock enable during CSleep mode
bit_offset: 1 bit_offset: 1
bit_size: 1 bit_size: 1
- name: SWPLPEN - name: SWPMILPEN
description: SWPMI Peripheral Clocks Enable During CSleep Mode description: SWPMI Peripheral Clocks Enable During CSleep Mode
bit_offset: 2 bit_offset: 2
bit_size: 1 bit_size: 1
@ -3142,11 +3142,11 @@ fieldset/D2CCIP1R:
bit_offset: 28 bit_offset: 28
bit_size: 2 bit_size: 2
enum: FDCANSEL enum: FDCANSEL
- name: SWPSEL - name: SWPMISEL
description: SWPMI kernel clock source selection description: SWPMI kernel clock source selection
bit_offset: 31 bit_offset: 31
bit_size: 1 bit_size: 1
enum: SWPSEL enum: SWPMISEL
fieldset/D2CCIP2R: fieldset/D2CCIP2R:
description: RCC Domain 2 Kernel Clock Configuration Register description: RCC Domain 2 Kernel Clock Configuration Register
fields: fields:
@ -5395,8 +5395,8 @@ enum/SPDIFRXSEL:
enum/SPI45SEL: enum/SPI45SEL:
bit_size: 3 bit_size: 3
variants: variants:
- name: APB - name: PCLK2
description: APB clock selected as peripheral clock description: APB2 clock selected as peripheral clock
value: 0 value: 0
- name: PLL2_Q - name: PLL2_Q
description: pll2_q selected as peripheral clock description: pll2_q selected as peripheral clock
@ -5458,10 +5458,10 @@ enum/SW:
- name: PLL1_P - name: PLL1_P
description: PLL1 selected as system clock description: PLL1 selected as system clock
value: 3 value: 3
enum/SWPSEL: enum/SWPMISEL:
bit_size: 1 bit_size: 1
variants: variants:
- name: PCLK - name: PCLK1
description: pclk selected as peripheral clock description: pclk selected as peripheral clock
value: 0 value: 0
- name: HSI - name: HSI

View File

@ -852,7 +852,7 @@ fieldset/APB1HENR:
description: Clock Recovery System peripheral clock enable description: Clock Recovery System peripheral clock enable
bit_offset: 1 bit_offset: 1
bit_size: 1 bit_size: 1
- name: SWPEN - name: SWPMIEN
description: SWPMI Peripheral Clocks Enable description: SWPMI Peripheral Clocks Enable
bit_offset: 2 bit_offset: 2
bit_size: 1 bit_size: 1
@ -883,7 +883,7 @@ fieldset/APB1HLPENR:
description: Clock Recovery System peripheral clock enable during CSleep mode description: Clock Recovery System peripheral clock enable during CSleep mode
bit_offset: 1 bit_offset: 1
bit_size: 1 bit_size: 1
- name: SWPLPEN - name: SWPMILPEN
description: SWPMI Peripheral Clocks Enable During CSleep Mode description: SWPMI Peripheral Clocks Enable During CSleep Mode
bit_offset: 2 bit_offset: 2
bit_size: 1 bit_size: 1
@ -914,7 +914,7 @@ fieldset/APB1HRSTR:
description: Clock Recovery System reset description: Clock Recovery System reset
bit_offset: 1 bit_offset: 1
bit_size: 1 bit_size: 1
- name: SWPRST - name: SWPMIRST
description: SWPMI block reset description: SWPMI block reset
bit_offset: 2 bit_offset: 2
bit_size: 1 bit_size: 1
@ -2093,11 +2093,11 @@ fieldset/D2CCIP1R:
bit_offset: 28 bit_offset: 28
bit_size: 2 bit_size: 2
enum: FDCANSEL enum: FDCANSEL
- name: SWPSEL - name: SWPMISEL
description: SWPMI kernel clock source selection description: SWPMI kernel clock source selection
bit_offset: 31 bit_offset: 31
bit_size: 1 bit_size: 1
enum: SWPSEL enum: SWPMISEL
fieldset/D2CCIP2R: fieldset/D2CCIP2R:
description: RCC Domain 2 Kernel Clock Configuration Register description: RCC Domain 2 Kernel Clock Configuration Register
fields: fields:
@ -4309,8 +4309,8 @@ enum/SPDIFRXSEL:
enum/SPI45SEL: enum/SPI45SEL:
bit_size: 3 bit_size: 3
variants: variants:
- name: APB - name: HCLK2
description: APB clock selected as peripheral clock description: APB2 clock selected as peripheral clock
value: 0 value: 0
- name: PLL2_Q - name: PLL2_Q
description: pll2_q selected as peripheral clock description: pll2_q selected as peripheral clock
@ -4372,10 +4372,10 @@ enum/SW:
- name: PLL1_P - name: PLL1_P
description: PLL1 selected as system clock description: PLL1 selected as system clock
value: 3 value: 3
enum/SWPSEL: enum/SWPMISEL:
bit_size: 1 bit_size: 1
variants: variants:
- name: PCLK - name: PCLK1
description: pclk selected as peripheral clock description: pclk selected as peripheral clock
value: 0 value: 0
- name: HSI - name: HSI

View File

@ -908,7 +908,7 @@ fieldset/APB1HENR:
description: Clock Recovery System peripheral clock enable description: Clock Recovery System peripheral clock enable
bit_offset: 1 bit_offset: 1
bit_size: 1 bit_size: 1
- name: SWPEN - name: SWPMIEN
description: SWPMI Peripheral Clocks Enable description: SWPMI Peripheral Clocks Enable
bit_offset: 2 bit_offset: 2
bit_size: 1 bit_size: 1
@ -939,7 +939,7 @@ fieldset/APB1HLPENR:
description: Clock Recovery System peripheral clock enable during CSleep mode description: Clock Recovery System peripheral clock enable during CSleep mode
bit_offset: 1 bit_offset: 1
bit_size: 1 bit_size: 1
- name: SWPLPEN - name: SWPMILPEN
description: SWPMI Peripheral Clocks Enable During CSleep Mode description: SWPMI Peripheral Clocks Enable During CSleep Mode
bit_offset: 2 bit_offset: 2
bit_size: 1 bit_size: 1
@ -970,7 +970,7 @@ fieldset/APB1HRSTR:
description: Clock Recovery System reset description: Clock Recovery System reset
bit_offset: 1 bit_offset: 1
bit_size: 1 bit_size: 1
- name: SWPRST - name: SWPMIRST
description: SWPMI block reset description: SWPMI block reset
bit_offset: 2 bit_offset: 2
bit_size: 1 bit_size: 1
@ -2174,7 +2174,7 @@ fieldset/C1_APB1HENR:
description: Clock Recovery System peripheral clock enable description: Clock Recovery System peripheral clock enable
bit_offset: 1 bit_offset: 1
bit_size: 1 bit_size: 1
- name: SWPEN - name: SWPMIEN
description: SWPMI Peripheral Clocks Enable description: SWPMI Peripheral Clocks Enable
bit_offset: 2 bit_offset: 2
bit_size: 1 bit_size: 1
@ -2197,7 +2197,7 @@ fieldset/C1_APB1HLPENR:
description: Clock Recovery System peripheral clock enable during CSleep mode description: Clock Recovery System peripheral clock enable during CSleep mode
bit_offset: 1 bit_offset: 1
bit_size: 1 bit_size: 1
- name: SWPLPEN - name: SWPMILPEN
description: SWPMI Peripheral Clocks Enable During CSleep Mode description: SWPMI Peripheral Clocks Enable During CSleep Mode
bit_offset: 2 bit_offset: 2
bit_size: 1 bit_size: 1
@ -3125,11 +3125,11 @@ fieldset/D2CCIP1R:
bit_offset: 28 bit_offset: 28
bit_size: 2 bit_size: 2
enum: FDCANSEL enum: FDCANSEL
- name: SWPSEL - name: SWPMISEL
description: SWPMI kernel clock source selection description: SWPMI kernel clock source selection
bit_offset: 31 bit_offset: 31
bit_size: 1 bit_size: 1
enum: SWPSEL enum: SWPMISEL
fieldset/D2CCIP2R: fieldset/D2CCIP2R:
description: RCC Domain 2 Kernel Clock Configuration Register description: RCC Domain 2 Kernel Clock Configuration Register
fields: fields:
@ -5378,8 +5378,8 @@ enum/SPDIFRXSEL:
enum/SPI45SEL: enum/SPI45SEL:
bit_size: 3 bit_size: 3
variants: variants:
- name: APB - name: PCLK2
description: APB clock selected as peripheral clock description: APB2 clock selected as peripheral clock
value: 0 value: 0
- name: PLL2_Q - name: PLL2_Q
description: pll2_q selected as peripheral clock description: pll2_q selected as peripheral clock
@ -5441,10 +5441,10 @@ enum/SW:
- name: PLL1_P - name: PLL1_P
description: PLL1 selected as system clock description: PLL1 selected as system clock
value: 3 value: 3
enum/SWPSEL: enum/SWPMISEL:
bit_size: 1 bit_size: 1
variants: variants:
- name: PCLK - name: PCLK1
description: pclk selected as peripheral clock description: pclk selected as peripheral clock
value: 0 value: 0
- name: HSI - name: HSI

View File

@ -834,7 +834,7 @@ fn process_group(
headers: &header::Headers, headers: &header::Headers,
af: &gpio_af::Af, af: &gpio_af::Af,
chip_interrupts: &interrupts::ChipInterrupts, chip_interrupts: &interrupts::ChipInterrupts,
peripheral_to_clock: &rcc::PeripheralToClock, peripheral_to_clock: &rcc::ParsedRccs,
dma_channels: &dma::DmaChannels, dma_channels: &dma::DmaChannels,
chips: &HashMap<String, Chip>, chips: &HashMap<String, Chip>,
memories: &memory::Memories, memories: &memory::Memories,
@ -889,7 +889,7 @@ fn process_core(
group: &ChipGroup, group: &ChipGroup,
chip_interrupts: &interrupts::ChipInterrupts, chip_interrupts: &interrupts::ChipInterrupts,
peri_matcher: &mut PeriMatcher, peri_matcher: &mut PeriMatcher,
peripheral_to_clock: &rcc::PeripheralToClock, peripheral_to_clock: &rcc::ParsedRccs,
rcc_block: (&str, &str, &str), rcc_block: (&str, &str, &str),
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,
@ -1115,15 +1115,8 @@ fn process_core(
}); });
} }
if let Some(rcc_info) = peripheral_to_clock.match_peri_clock( if let Some(rcc_info) = peripheral_to_clock.match_peri_clock(rcc_block.1, &pname) {
&( p.rcc = Some(rcc_info);
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(pins) = periph_pins.get_mut(&pname) { if let Some(pins) = periph_pins.get_mut(&pname) {
// merge the core xml info with GPIO xml info to hopefully get the full picture // 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, headers: header::Headers,
af: gpio_af::Af, af: gpio_af::Af,
chip_interrupts: interrupts::ChipInterrupts, chip_interrupts: interrupts::ChipInterrupts,
peripheral_to_clock: rcc::PeripheralToClock, peripheral_to_clock: rcc::ParsedRccs,
dma_channels: dma::DmaChannels, dma_channels: dma::DmaChannels,
chips: std::collections::HashMap<String, Chip>, chips: std::collections::HashMap<String, Chip>,
memories: memory::Memories, memories: memory::Memories,

View File

@ -76,7 +76,7 @@ fn main() -> anyhow::Result<()> {
let chip_interrupts = interrupts::ChipInterrupts::parse()?; let chip_interrupts = interrupts::ChipInterrupts::parse()?;
// stopwatch.section("Parsing RCC registers"); // stopwatch.section("Parsing RCC registers");
let peripheral_to_clock = rcc::PeripheralToClock::parse(&registers)?; let peripheral_to_clock = rcc::ParsedRccs::parse(&registers)?;
// stopwatch.section("Parsing docs"); // stopwatch.section("Parsing docs");
let docs = docs::Docs::parse()?; let docs = docs::Docs::parse()?;

View File

@ -1,42 +1,49 @@
use std::cmp::Ordering;
use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::hash::Hash;
use anyhow::{anyhow, Ok}; use anyhow::{anyhow, bail, Ok};
use chiptool::ir::{BlockItemInner, Enum}; use chiptool::ir::{BlockItemInner, Enum, IR};
use stm32_data_serde::chip::core::peripheral;
use stm32_data_serde::chip::core::peripheral::rcc::{Mux, StopMode}; use stm32_data_serde::chip::core::peripheral::rcc::{Mux, StopMode};
use stm32_data_serde::chip::core::peripheral::{self, rcc};
use crate::regex; use crate::regex;
use crate::registers::Registers; use crate::registers::Registers;
/// Deterministically insert into a `HashMap` #[derive(Debug)]
fn insert_into_map<K, V, F>(hash_map: &mut HashMap<K, V>, key: K, value: V, mut compare: F) pub struct ParsedRccs {
where /// RCC version -> parsed info
K: Eq + Hash, rccs: HashMap<String, ParsedRcc>,
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)] #[derive(Debug)]
pub struct PeripheralToClock( struct ParsedRcc {
HashMap<(String, String, String), HashMap<String, stm32_data_serde::chip::core::peripheral::Rcc>>, /// name -> en/rst bit info
); en_rst: HashMap<String, EnRst>,
/// name -> mux info
mux: HashMap<String, Mux>,
}
impl PeripheralToClock { #[derive(Debug)]
struct EnRst {
enable: rcc::Enable,
reset: Option<rcc::Reset>,
clock: String,
stop_mode: StopMode,
}
impl ParsedRccs {
pub fn parse(registers: &Registers) -> anyhow::Result<Self> { pub fn parse(registers: &Registers) -> anyhow::Result<Self> {
let mut peripheral_to_clock = HashMap::new(); let mut rccs = HashMap::new();
for (rcc_name, ir) in &registers.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<ParsedRcc> {
let allowed_variants = HashSet::from([ let allowed_variants = HashSet::from([
"DISABLE", "DISABLE",
"SYS", "SYS",
@ -118,8 +125,6 @@ impl PeripheralToClock {
"HSI256_MSIK1024_MSIK4", "HSI256_MSIK1024_MSIK4",
]); ]);
for (rcc_name, ir) in &registers.registers {
if let Some(rcc_name) = rcc_name.strip_prefix("rcc_") {
let rcc_enum_map: HashMap<&String, HashMap<&String, (&String, &Enum)>> = { let rcc_enum_map: HashMap<&String, HashMap<&String, (&String, &Enum)>> = {
let rcc_blocks = &ir.blocks.get("RCC").unwrap().items; let rcc_blocks = &ir.blocks.get("RCC").unwrap().items;
@ -166,7 +171,7 @@ impl PeripheralToClock {
"rcc: prohibited variant name {} in enum {} for rcc_{}", "rcc: prohibited variant name {} in enum {} for rcc_{}",
v.name.as_str(), v.name.as_str(),
enumm_name, enumm_name,
rcc_name rcc_version
)); ));
} }
} else if !allowed_variants.contains(v.name.as_str()) { } else if !allowed_variants.contains(v.name.as_str()) {
@ -174,7 +179,7 @@ impl PeripheralToClock {
"rcc: prohibited variant name {} in enum {} for rcc_{}", "rcc: prohibited variant name {} in enum {} for rcc_{}",
v.name.as_str(), v.name.as_str(),
enumm_name, enumm_name,
rcc_name rcc_version
)); ));
} }
} }
@ -182,77 +187,64 @@ impl PeripheralToClock {
Ok(()) Ok(())
}; };
let mut family_muxes = HashMap::new(); 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 (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 { for field in &body.fields {
if let Some(peri) = field.name.strip_suffix("SEL") { let key = format!("{}/{}", reg, field.name);
check_mux(reg, &field.name)?; if let Some(capture) = mux_regexes.iter().find_map(|r| r.captures(&key)) {
let peri = capture.get(1).unwrap().as_str();
insert_into_map( // TODO: these bits are duplicated on F4, we need to split the F4 RCCs more.
&mut family_muxes, if rcc_version.starts_with("f4") && reg == "DCKCFGR2" && (peri == "CLK48" || peri == "SDIO") {
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; continue;
} }
check_mux(reg, &field.name)?; check_mux(reg, &field.name)?;
insert_into_map( let val = Mux {
&mut family_muxes,
peri.to_string(),
Mux {
register: reg.to_ascii_lowercase(), register: reg.to_ascii_lowercase(),
field: field.name.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(); // Parse xxEN/xxRST bits.
let mut en_rst = HashMap::new();
for (reg, body) in &ir.fieldsets { for (reg, body) in &ir.fieldsets {
let key = format!("fieldset/{reg}"); if let Some(m) = regex!(r"^((A[PH]B\d?)|GPIO)[LH]?ENR\d?$").captures(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 = m.get(1).unwrap().as_str();
let clock = match clock { let clock = match clock {
"AHB" => "AHB1", "AHB" => "AHB1",
"APB" => "APB1", "APB" => "APB1",
clock => clock, clock => clock,
}; };
for field in &body.fields { for field in &body.fields {
if let Some(peri) = field.name.strip_suffix("EN") { if let Some(peri) = field.name.strip_suffix("EN") {
let peri = if peri == "RTCAPB" { "RTC" } else { peri }; let peri = if peri == "RTCAPB" { "RTC" } else { peri };
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").to_ascii_lowercase(),
field: format!("{peri}RST").to_ascii_lowercase(),
});
}
}
let stop_mode = if peri == "RTC" { let stop_mode = if peri == "RTC" {
StopMode::Standby StopMode::Standby
} else if peri.starts_with("LP") { } else if peri.starts_with("LP") {
@ -262,68 +254,44 @@ impl PeripheralToClock {
}; };
// Timers are a bit special, they may have a x2 freq // Timers are a bit special, they may have a x2 freq
let peri_clock = { let peri_clock = if regex!(r"^TIM\d+$").is_match(peri) {
if regex!(r"^TIM\d+$").is_match(peri) {
format!("{clock}_TIM") format!("{clock}_TIM")
} else { } else {
clock.to_string() clock.to_string()
}
}; };
let mut reset = None; let peri_clock = peri_clock
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").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() .to_ascii_lowercase()
.replace("ahb", "hclk") .replace("ahb", "hclk")
.replace("apb", "pclk"), .replace("apb", "pclk");
let val = EnRst {
enable: peripheral::rcc::Enable { enable: peripheral::rcc::Enable {
register: reg.to_ascii_lowercase(), register: reg.to_ascii_lowercase(),
field: field.name.to_ascii_lowercase(), field: field.name.to_ascii_lowercase(),
}, },
stop_mode,
reset, reset,
mux, clock: peri_clock,
}); stop_mode,
}
Entry::Occupied(_) => {
return Err(anyhow!("rcc: duplicate clock for {} for rcc_{}", peri, rcc_name));
}
}; };
if en_rst.insert(peri.to_string(), val).is_some() {
bail!("rcc: duplicate en/rst for {} for rcc_{}", peri, rcc_version);
} }
} }
} }
} }
peripheral_to_clock.insert(
("rcc".to_string(), rcc_name.to_string(), "RCC".to_string()),
family_clocks,
);
}
} }
Ok(Self(peripheral_to_clock)) Ok(ParsedRcc { en_rst, mux })
} }
pub fn match_peri_clock( pub fn match_peri_clock(
&self, &self,
rcc_block: &(String, String, String), rcc_version: &str,
peri_name: &str, peri_name: &str,
) -> Option<&stm32_data_serde::chip::core::peripheral::Rcc> { ) -> Option<stm32_data_serde::chip::core::peripheral::Rcc> {
const PERI_OVERRIDE: &[(&str, &[&str])] = &[ const FALLBACKS: &[(&str, &[&str])] = &[
("DCMI", &["DCMI_PSSI"]), ("DCMI", &["DCMI_PSSI"]),
("PSSI", &["DCMI_PSSI"]), ("PSSI", &["DCMI_PSSI"]),
("FDCAN1", &["FDCAN12", "FDCAN"]), ("FDCAN1", &["FDCAN12", "FDCAN"]),
@ -339,27 +307,63 @@ impl PeripheralToClock {
("DAC1", &["DAC12", "DAC"]), ("DAC1", &["DAC12", "DAC"]),
("DAC2", &["DAC12", "DAC"]), ("DAC2", &["DAC12", "DAC"]),
("ETH", &["ETHMAC", "ETH1MAC"]), ("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)?; let rcc = self.rccs.get(rcc_version)?;
if let Some(res) = clocks.get(peri_name) {
let en_rst = get_with_fallback(peri_name, &rcc.en_rst, FALLBACKS)?;
let mux = get_with_fallback(peri_name, &rcc.mux, FALLBACKS);
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<String, T>, fallbacks: &[(&str, &[&str])]) -> Option<&'a T> {
if let Some(res) = map.get(key) {
return Some(res); return Some(res);
} }
if let Some((_, rename)) = PERI_OVERRIDE.iter().find(|(n, _)| *n == peri_name) { if let Some((_, rename)) = fallbacks.iter().find(|(n, _)| *n == key) {
for &n in *rename { for &n in *rename {
if let Some(res) = clocks.get(n) { if let Some(res) = map.get(n) {
return Some(res); return Some(res);
} }
} }
} }
if let Some(n) = peri_name.strip_suffix('1') { if let Some(n) = key.strip_suffix('1') {
if let Some(res) = clocks.get(n) { if let Some(res) = map.get(n) {
return Some(res); return Some(res);
} }
} }
None None
} }
}