Merge pull request #297 from xoviat/rcc

rcc: solve hashmap determinism for good
This commit is contained in:
xoviat 2023-10-20 23:47:16 +00:00 committed by GitHub
commit 296dd041cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 47 additions and 35 deletions

View File

@ -867,7 +867,7 @@ fieldset/APB2ENR:
description: SAI2 clock enable description: SAI2 clock enable
bit_offset: 22 bit_offset: 22
bit_size: 1 bit_size: 1
- name: DFSDMEN - name: DFSDM_TIMEN
description: DFSDM timer clock enable description: DFSDM timer clock enable
bit_offset: 24 bit_offset: 24
bit_size: 1 bit_size: 1

View File

@ -1,13 +1,35 @@
use std::cmp::Ordering;
use std::collections::hash_map::Entry; 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, Ok};
use chiptool::ir::{BlockItemInner, Enum}; use chiptool::ir::{BlockItemInner, Enum};
use stm32_data_serde::chip::core::peripheral;
use stm32_data_serde::chip::core::peripheral::rcc::Mux; use stm32_data_serde::chip::core::peripheral::rcc::Mux;
use crate::regex; use crate::regex;
use crate::registers::Registers; 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) => match compare(&value, e.get()) {
Ordering::Less => {
e.insert(value);
}
_ => {}
},
};
}
#[derive(Debug)] #[derive(Debug)]
pub struct PeripheralToClock( pub struct PeripheralToClock(
HashMap<(String, String, String), HashMap<String, stm32_data_serde::chip::core::peripheral::Rcc>>, HashMap<(String, String, String), HashMap<String, stm32_data_serde::chip::core::peripheral::Rcc>>,
@ -157,18 +179,16 @@ impl PeripheralToClock {
if let Some(_) = regex!(r"^fieldset/CCIPR\d?$").captures(&key) { if let Some(_) = regex!(r"^fieldset/CCIPR\d?$").captures(&key) {
for field in &body.fields { for field in &body.fields {
if let Some(peri) = field.name.strip_suffix("SEL") { if let Some(peri) = field.name.strip_suffix("SEL") {
if family_muxes.get(peri).is_some() && reg != "CCIPR" {
continue;
}
check_mux(reg, &field.name)?; check_mux(reg, &field.name)?;
family_muxes.insert( insert_into_map(
&mut family_muxes,
peri.to_string(), peri.to_string(),
Mux { 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),
); );
} }
} }
@ -177,12 +197,14 @@ impl PeripheralToClock {
if let Some(peri) = field.name.strip_suffix("SW") { if let Some(peri) = field.name.strip_suffix("SW") {
check_mux(reg, &field.name)?; check_mux(reg, &field.name)?;
family_muxes.insert( insert_into_map(
&mut family_muxes,
peri.to_string(), peri.to_string(),
Mux { 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),
); );
} }
} }
@ -195,12 +217,14 @@ impl PeripheralToClock {
check_mux(reg, &field.name)?; check_mux(reg, &field.name)?;
family_muxes.insert( insert_into_map(
&mut family_muxes,
peri.to_string(), peri.to_string(),
Mux { 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),
); );
} }
} }
@ -244,37 +268,25 @@ impl PeripheralToClock {
let mux = family_muxes.get(peri).map(|peri| peri.clone()); let mux = family_muxes.get(peri).map(|peri| peri.clone());
let res = stm32_data_serde::chip::core::peripheral::Rcc {
clock: peri_clock
.to_ascii_lowercase()
.replace("ahb", "hclk")
.replace("apb", "pclk"),
enable: stm32_data_serde::chip::core::peripheral::rcc::Enable {
register: reg.to_ascii_lowercase(),
field: field.name.to_ascii_lowercase(),
},
reset,
mux,
};
match family_clocks.entry(peri.to_string()) { match family_clocks.entry(peri.to_string()) {
Entry::Vacant(e) => { Entry::Vacant(e) => {
e.insert(res); 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(),
},
reset,
mux,
});
} }
Entry::Occupied(mut e) => { Entry::Occupied(_) => {
if (e.get().clock != "pclk1" || e.get().clock != "hclk1") return Err(anyhow!("rcc: duplicate clock for {} for rcc_{}", peri, rcc_name));
&& (res.clock == "pclk1" || res.clock == "hclk1")
{
e.insert(res);
} else if !(e.get().clock == "pclk1" || e.get().clock == "hclk1") {
return Err(anyhow!(
"rcc: duplicate entry for peri {} for rcc_{}",
peri.to_string(),
rcc_name
));
}
} }
} };
} }
} }
} }