Merge pull request #331 from timokroeger/stm32-enable-bit
metapac: Improve enable bit search
This commit is contained in:
commit
f574e55395
@ -1,7 +1,7 @@
|
|||||||
use chiptool::generate::CommonModule;
|
use chiptool::generate::CommonModule;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fmt::Write as _;
|
use std::fmt::Write as _;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
@ -39,9 +39,9 @@ pub struct MemoryRegion {
|
|||||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
|
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
|
||||||
pub struct Core {
|
pub struct Core {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub peripherals: HashMap<String, Peripheral>,
|
pub peripherals: BTreeMap<String, Peripheral>,
|
||||||
pub interrupts: HashMap<String, u32>,
|
pub interrupts: BTreeMap<String, u32>,
|
||||||
pub dma_channels: HashMap<String, DmaChannel>,
|
pub dma_channels: BTreeMap<String, DmaChannel>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
|
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
|
||||||
@ -62,9 +62,9 @@ pub struct Peripheral {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub pins: Vec<Pin>,
|
pub pins: Vec<Pin>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub dma_channels: HashMap<String, Vec<PeripheralDmaChannel>>,
|
pub dma_channels: BTreeMap<String, Vec<PeripheralDmaChannel>>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub interrupts: HashMap<String, String>,
|
pub interrupts: BTreeMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
|
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
|
||||||
@ -118,33 +118,27 @@ impl BlockInfo {
|
|||||||
|
|
||||||
fn find_reg_for_field<'c>(
|
fn find_reg_for_field<'c>(
|
||||||
rcc: &'c ir::IR,
|
rcc: &'c ir::IR,
|
||||||
reg_prefix: &str,
|
reg_regex: &str,
|
||||||
field_name: &str,
|
field_name: &str,
|
||||||
) -> Option<(&'c str, &'c str)> {
|
) -> Option<(&'c str, &'c str)> {
|
||||||
rcc.fieldsets.iter().find_map(|(name, fieldset)| {
|
let reg_regex = Regex::new(reg_regex).unwrap();
|
||||||
|
|
||||||
|
for (name, fieldset) in &rcc.fieldsets {
|
||||||
// Workaround for some families that prefix register aliases with C1_, which does
|
// Workaround for some families that prefix register aliases with C1_, which does
|
||||||
// not help matching for clock name.
|
// not help matching for clock name.
|
||||||
if name.starts_with("C1") || name.starts_with("C2") {
|
if !name.starts_with("C1") && !name.starts_with("C2") && reg_regex.is_match(name) {
|
||||||
None
|
for field in &fieldset.fields {
|
||||||
} else if name.starts_with(reg_prefix) {
|
if field_name == field.name {
|
||||||
fieldset
|
return Some((name.as_str(), field.name.as_str()));
|
||||||
.fields
|
}
|
||||||
.iter()
|
}
|
||||||
.find_map(|field| {
|
|
||||||
if field_name == field.name {
|
|
||||||
return Some(field.name.as_str());
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map(|n| (name.as_str(), n))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_peripheral_counts(out: &mut String, data: &HashMap<String, u8>) {
|
fn make_peripheral_counts(out: &mut String, data: &BTreeMap<String, u8>) {
|
||||||
write!(
|
write!(
|
||||||
out,
|
out,
|
||||||
"#[macro_export]
|
"#[macro_export]
|
||||||
@ -158,7 +152,7 @@ macro_rules! peripheral_count {{
|
|||||||
write!(out, " }}\n").unwrap();
|
write!(out, " }}\n").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_dma_channel_counts(out: &mut String, data: &HashMap<String, u8>) {
|
fn make_dma_channel_counts(out: &mut String, data: &BTreeMap<String, u8>) {
|
||||||
write!(
|
write!(
|
||||||
out,
|
out,
|
||||||
"#[macro_export]
|
"#[macro_export]
|
||||||
@ -219,7 +213,7 @@ pub fn gen(options: Options) {
|
|||||||
println!("cwd: {:?}", env::current_dir());
|
println!("cwd: {:?}", env::current_dir());
|
||||||
|
|
||||||
let mut all_peripheral_versions: HashSet<(String, String)> = HashSet::new();
|
let mut all_peripheral_versions: HashSet<(String, String)> = HashSet::new();
|
||||||
let mut chip_cores: HashMap<String, Option<String>> = HashMap::new();
|
let mut chip_cores: BTreeMap<String, Option<String>> = BTreeMap::new();
|
||||||
|
|
||||||
for chip_name in &options.chips {
|
for chip_name in &options.chips {
|
||||||
let mut s = chip_name.split('_');
|
let mut s = chip_name.split('_');
|
||||||
@ -291,7 +285,7 @@ pub fn gen(options: Options) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut peripheral_versions: HashMap<String, String> = HashMap::new();
|
let mut peripheral_versions: BTreeMap<String, String> = BTreeMap::new();
|
||||||
let mut pin_table: Vec<Vec<String>> = Vec::new();
|
let mut pin_table: Vec<Vec<String>> = Vec::new();
|
||||||
let mut interrupt_table: Vec<Vec<String>> = Vec::new();
|
let mut interrupt_table: Vec<Vec<String>> = Vec::new();
|
||||||
let mut peripherals_table: Vec<Vec<String>> = Vec::new();
|
let mut peripherals_table: Vec<Vec<String>> = Vec::new();
|
||||||
@ -299,8 +293,8 @@ pub fn gen(options: Options) {
|
|||||||
let mut peripheral_rcc_table: Vec<Vec<String>> = Vec::new();
|
let mut peripheral_rcc_table: Vec<Vec<String>> = Vec::new();
|
||||||
let mut dma_channels_table: Vec<Vec<String>> = Vec::new();
|
let mut dma_channels_table: Vec<Vec<String>> = Vec::new();
|
||||||
let mut peripheral_dma_channels_table: Vec<Vec<String>> = Vec::new();
|
let mut peripheral_dma_channels_table: Vec<Vec<String>> = Vec::new();
|
||||||
let mut peripheral_counts: HashMap<String, u8> = HashMap::new();
|
let mut peripheral_counts: BTreeMap<String, u8> = BTreeMap::new();
|
||||||
let mut dma_channel_counts: HashMap<String, u8> = HashMap::new();
|
let mut dma_channel_counts: BTreeMap<String, u8> = BTreeMap::new();
|
||||||
let mut dbgmcu_table: Vec<Vec<String>> = Vec::new();
|
let mut dbgmcu_table: Vec<Vec<String>> = Vec::new();
|
||||||
let mut gpio_rcc_table: Vec<Vec<String>> = Vec::new();
|
let mut gpio_rcc_table: Vec<Vec<String>> = Vec::new();
|
||||||
let mut gpio_regs: HashSet<String> = HashSet::new();
|
let mut gpio_regs: HashSet<String> = HashSet::new();
|
||||||
@ -429,86 +423,71 @@ pub fn gen(options: Options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(rcc) = &rcc {
|
if let Some(rcc) = &rcc {
|
||||||
let clock_prefix: Option<&str> = if let Some(clock) = &p.clock {
|
// Workaround for clock registers being split on some chip families. Assume fields are
|
||||||
Some(clock)
|
// named after peripheral and look for first field matching and use that register.
|
||||||
} else if name.starts_with("TIM") {
|
let mut en = find_reg_for_field(&rcc, "^.+ENR\\d*$", &format!("{}EN", name));
|
||||||
// Not all peripherals like timers the clock hint due to insufficient information from
|
let mut rst = find_reg_for_field(&rcc, "^.+RSTR\\d*$", &format!("{}RST", name));
|
||||||
// chip definition. If clock is not specified, the first matching register with the
|
|
||||||
// expected field will be used.
|
|
||||||
Some("")
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(clock_prefix) = clock_prefix {
|
if en.is_none() && name.ends_with("1") {
|
||||||
// Workaround for clock registers being split on some chip families. Assume fields are
|
en = find_reg_for_field(
|
||||||
// named after peripheral and look for first field matching and use that register.
|
&rcc,
|
||||||
let mut en = find_reg_for_field(&rcc, clock_prefix, &format!("{}EN", name));
|
"^.+ENR\\d*$",
|
||||||
let mut rst =
|
&format!("{}EN", &name[..name.len() - 1]),
|
||||||
find_reg_for_field(&rcc, clock_prefix, &format!("{}RST", name));
|
);
|
||||||
|
rst = find_reg_for_field(
|
||||||
|
&rcc,
|
||||||
|
"^.+RSTR\\d*$",
|
||||||
|
&format!("{}RST", &name[..name.len() - 1]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if en.is_none() && name.ends_with("1") {
|
match (en, rst) {
|
||||||
en = find_reg_for_field(
|
(Some((enable_reg, enable_field)), reset_reg_field) => {
|
||||||
&rcc,
|
let clock = match &p.clock {
|
||||||
clock_prefix,
|
Some(clock) => clock.as_str(),
|
||||||
&format!("{}EN", &name[..name.len() - 1]),
|
None => {
|
||||||
);
|
// No clock was specified, derive the clock name from the enable register name.
|
||||||
rst = find_reg_for_field(
|
Regex::new("([A-Z]+\\d*).*")
|
||||||
&rcc,
|
.unwrap()
|
||||||
clock_prefix,
|
.captures(enable_reg)
|
||||||
&format!("{}RST", &name[..name.len() - 1]),
|
.unwrap()
|
||||||
);
|
.get(1)
|
||||||
|
.unwrap()
|
||||||
|
.as_str()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let clock = if name.starts_with("TIM") {
|
||||||
|
format!("{}_tim", clock.to_ascii_lowercase())
|
||||||
|
} else {
|
||||||
|
clock.to_ascii_lowercase()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut row = Vec::with_capacity(6);
|
||||||
|
row.push(name.clone());
|
||||||
|
row.push(clock);
|
||||||
|
row.push(enable_reg.to_ascii_lowercase());
|
||||||
|
|
||||||
|
if let Some((reset_reg, reset_field)) = reset_reg_field {
|
||||||
|
row.push(reset_reg.to_ascii_lowercase());
|
||||||
|
row.push(format!("set_{}", enable_field.to_ascii_lowercase()));
|
||||||
|
row.push(format!("set_{}", reset_field.to_ascii_lowercase()));
|
||||||
|
} else {
|
||||||
|
row.push(format!("set_{}", enable_field.to_ascii_lowercase()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !name.starts_with("GPIO") {
|
||||||
|
peripheral_rcc_table.push(row);
|
||||||
|
} else {
|
||||||
|
gpio_rcc_table.push(row);
|
||||||
|
gpio_regs.insert(enable_reg.to_ascii_lowercase());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
(None, Some(_)) => {
|
||||||
match (en, rst) {
|
println!("Unable to find enable register for {}", name)
|
||||||
(Some((enable_reg, enable_field)), reset_reg_field) => {
|
}
|
||||||
let clock = if clock_prefix.is_empty() {
|
(None, None) => {
|
||||||
let re = Regex::new("([A-Z]+\\d*).*").unwrap();
|
println!("Unable to find enable and reset register for {}", name)
|
||||||
if !re.is_match(enable_reg) {
|
|
||||||
panic!(
|
|
||||||
"unable to derive clock name from register name {}",
|
|
||||||
enable_reg
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
let caps = re.captures(enable_reg).unwrap();
|
|
||||||
caps.get(1).unwrap().as_str()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
clock_prefix
|
|
||||||
};
|
|
||||||
|
|
||||||
let clock = if name.starts_with("TIM") {
|
|
||||||
format!("{}_tim", clock.to_ascii_lowercase())
|
|
||||||
} else {
|
|
||||||
clock.to_ascii_lowercase()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut row = Vec::with_capacity(6);
|
|
||||||
row.push(name.clone());
|
|
||||||
row.push(clock);
|
|
||||||
row.push(enable_reg.to_ascii_lowercase());
|
|
||||||
|
|
||||||
if let Some((reset_reg, reset_field)) = reset_reg_field {
|
|
||||||
row.push(reset_reg.to_ascii_lowercase());
|
|
||||||
row.push(format!("set_{}", enable_field.to_ascii_lowercase()));
|
|
||||||
row.push(format!("set_{}", reset_field.to_ascii_lowercase()));
|
|
||||||
} else {
|
|
||||||
row.push(format!("set_{}", enable_field.to_ascii_lowercase()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if !name.starts_with("GPIO") {
|
|
||||||
peripheral_rcc_table.push(row);
|
|
||||||
} else {
|
|
||||||
gpio_rcc_table.push(row);
|
|
||||||
gpio_regs.insert(enable_reg.to_ascii_lowercase());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(None, Some(_)) => {
|
|
||||||
print!("Unable to find enable register for {}", name)
|
|
||||||
}
|
|
||||||
(None, None) => {
|
|
||||||
print!("Unable to find enable and reset register for {}", name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -689,7 +668,6 @@ pub fn gen(options: Options) {
|
|||||||
let re = Regex::new("# *! *\\[.*\\]").unwrap();
|
let re = Regex::new("# *! *\\[.*\\]").unwrap();
|
||||||
let data = re.replace_all(&data, "");
|
let data = re.replace_all(&data, "");
|
||||||
file.write_all(data.as_bytes()).unwrap();
|
file.write_all(data.as_bytes()).unwrap();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate src/lib_inner.rs
|
// Generate src/lib_inner.rs
|
||||||
@ -750,7 +728,6 @@ pub fn gen(options: Options) {
|
|||||||
|
|
||||||
// Generate build.rs
|
// Generate build.rs
|
||||||
fs::write(out_dir.join("build.rs"), include_bytes!("assets/build.rs")).unwrap();
|
fs::write(out_dir.join("build.rs"), include_bytes!("assets/build.rs")).unwrap();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bytes_find(haystack: &[u8], needle: &[u8]) -> Option<usize> {
|
fn bytes_find(haystack: &[u8], needle: &[u8]) -> Option<usize> {
|
||||||
@ -762,19 +739,40 @@ fn bytes_find(haystack: &[u8], needle: &[u8]) -> Option<usize> {
|
|||||||
fn gen_memory_x(out_dir: &PathBuf, chip: &Chip) {
|
fn gen_memory_x(out_dir: &PathBuf, chip: &Chip) {
|
||||||
let mut memory_x = String::new();
|
let mut memory_x = String::new();
|
||||||
|
|
||||||
let flash_bytes = chip.flash.regions.get("BANK_1").unwrap().bytes.unwrap_or(chip.flash.bytes);
|
let flash_bytes = chip
|
||||||
|
.flash
|
||||||
|
.regions
|
||||||
|
.get("BANK_1")
|
||||||
|
.unwrap()
|
||||||
|
.bytes
|
||||||
|
.unwrap_or(chip.flash.bytes);
|
||||||
let flash_origin = chip.flash.regions.get("BANK_1").unwrap().base;
|
let flash_origin = chip.flash.regions.get("BANK_1").unwrap().base;
|
||||||
|
|
||||||
let ram_bytes = chip.ram.regions.get("SRAM").unwrap().bytes.unwrap_or(chip.ram.bytes);
|
let ram_bytes = chip
|
||||||
|
.ram
|
||||||
|
.regions
|
||||||
|
.get("SRAM")
|
||||||
|
.unwrap()
|
||||||
|
.bytes
|
||||||
|
.unwrap_or(chip.ram.bytes);
|
||||||
let ram_origin = chip.ram.regions.get("SRAM").unwrap().base;
|
let ram_origin = chip.ram.regions.get("SRAM").unwrap().base;
|
||||||
|
|
||||||
write!(memory_x, "MEMORY\n{{\n").unwrap();
|
write!(memory_x, "MEMORY\n{{\n").unwrap();
|
||||||
write!(memory_x, " FLASH : ORIGIN = 0x{:x}, LENGTH = {}\n", flash_origin, flash_bytes).unwrap();
|
write!(
|
||||||
write!(memory_x, " RAM : ORIGIN = 0x{:x}, LENGTH = {}\n", ram_origin, ram_bytes).unwrap();
|
memory_x,
|
||||||
|
" FLASH : ORIGIN = 0x{:x}, LENGTH = {}\n",
|
||||||
|
flash_origin, flash_bytes
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
write!(
|
||||||
|
memory_x,
|
||||||
|
" RAM : ORIGIN = 0x{:x}, LENGTH = {}\n",
|
||||||
|
ram_origin, ram_bytes
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
write!(memory_x, "}}").unwrap();
|
write!(memory_x, "}}").unwrap();
|
||||||
|
|
||||||
fs::create_dir_all(out_dir.join("memory_x")).unwrap();
|
fs::create_dir_all(out_dir.join("memory_x")).unwrap();
|
||||||
let mut file = File::create(out_dir.join("memory_x").join("memory.x")).unwrap();
|
let mut file = File::create(out_dir.join("memory_x").join("memory.x")).unwrap();
|
||||||
file.write_all( memory_x.as_bytes() ).unwrap();
|
file.write_all(memory_x.as_bytes()).unwrap();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user