parent
028efe4e6e
commit
0c921dde2e
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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<String, Chip>,
|
||||
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<String, Vec<stm32_data_serde::chip::core::peripheral::Pin>>>,
|
||||
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<String, Chip>,
|
||||
memories: memory::Memories,
|
||||
|
@ -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()?;
|
||||
|
@ -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<K, V, F>(hash_map: &mut HashMap<K, V>, 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<String, ParsedRcc>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PeripheralToClock(
|
||||
HashMap<(String, String, String), HashMap<String, stm32_data_serde::chip::core::peripheral::Rcc>>,
|
||||
);
|
||||
struct ParsedRcc {
|
||||
/// 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> {
|
||||
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<ParsedRcc> {
|
||||
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<stm32_data_serde::chip::core::peripheral::Rcc> {
|
||||
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<String, T>, 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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user