stm32/build.rs: switch to using stm32-metapac metadata and quote.

This commit is contained in:
Dario Nieuwenhuis 2022-02-09 00:31:21 +01:00
parent 4d73d87b40
commit 940412c034
2 changed files with 85 additions and 99 deletions

View file

@ -35,7 +35,9 @@ seq-macro = "0.2.2"
cfg-if = "1.0.0" cfg-if = "1.0.0"
[build-dependencies] [build-dependencies]
stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features = false } proc-macro2 = "1.0.36"
quote = "1.0.15"
stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", default-features = false, features = ["metadata"]}
[features] [features]
sdmmc-rs = ["embedded-sdmmc"] sdmmc-rs = ["embedded-sdmmc"]

View file

@ -1,8 +1,10 @@
use std::collections::HashMap; use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use std::collections::HashSet;
use std::env; use std::env;
use std::fmt::Write;
use std::fs; use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
use stm32_metapac::metadata::METADATA;
fn main() { fn main() {
let chip_name = match env::vars() let chip_name = match env::vars()
@ -18,67 +20,50 @@ fn main() {
.unwrap() .unwrap()
.to_ascii_lowercase(); .to_ascii_lowercase();
struct Peripheral { for p in METADATA.peripherals {
kind: String, if let Some(r) = &p.registers {
name: String, println!("cargo:rustc-cfg={}", r.kind);
version: String, println!("cargo:rustc-cfg={}_{}", r.kind, r.version);
}
} }
let mut peripheral_version_mapping = HashMap::<String, String>::new();
stm32_metapac::peripheral_versions!(
($peri:ident, $version:ident) => {
peripheral_version_mapping.insert(stringify!($peri).to_string(), stringify!($version).to_string());
println!("cargo:rustc-cfg={}", stringify!($peri));
println!("cargo:rustc-cfg={}_{}", stringify!($peri), stringify!($version));
};
);
let mut peripherals: Vec<Peripheral> = Vec::new();
stm32_metapac::peripherals!(
($kind:ident, $name:ident) => {
peripherals.push(Peripheral{
kind: stringify!($kind).to_string(),
name: stringify!($name).to_string(),
version: peripheral_version_mapping[&stringify!($kind).to_ascii_lowercase()].clone()
});
};
);
// ======== // ========
// Generate singletons // Generate singletons
let mut singletons: Vec<String> = Vec::new(); let mut singletons: Vec<String> = Vec::new();
for p in peripherals { for p in METADATA.peripherals {
match p.kind.as_str() { if let Some(r) = &p.registers {
// Generate singletons per pin, not per port match r.kind {
"gpio" => { // Generate singletons per pin, not per port
println!("{}", p.name); "gpio" => {
let port_letter = p.name.strip_prefix("GPIO").unwrap(); println!("{}", p.name);
for pin_num in 0..16 { let port_letter = p.name.strip_prefix("GPIO").unwrap();
singletons.push(format!("P{}{}", port_letter, pin_num)); for pin_num in 0..16 {
singletons.push(format!("P{}{}", port_letter, pin_num));
}
} }
}
// No singleton for these, the HAL handles them specially. // No singleton for these, the HAL handles them specially.
"exti" => {} "exti" => {}
// We *shouldn't* have singletons for these, but the HAL currently requires // We *shouldn't* have singletons for these, but the HAL currently requires
// singletons, for using with RccPeripheral to enable/disable clocks to them. // singletons, for using with RccPeripheral to enable/disable clocks to them.
"rcc" => { "rcc" => {
if p.version == "h7" { if r.version == "h7" {
singletons.push("MCO1".to_string()); singletons.push("MCO1".to_string());
singletons.push("MCO2".to_string()); singletons.push("MCO2".to_string());
}
singletons.push(p.name.to_string());
} }
singletons.push(p.name.clone()); //"dbgmcu" => {}
} //"syscfg" => {}
//"dbgmcu" => {} //"dma" => {}
//"syscfg" => {} //"bdma" => {}
//"dma" => {} //"dmamux" => {}
//"bdma" => {}
//"dmamux" => {}
// For other peripherals, one singleton per peri // For other peripherals, one singleton per peri
_ => singletons.push(p.name.clone()), _ => singletons.push(p.name.to_string()),
}
} }
} }
@ -88,68 +73,67 @@ fn main() {
} }
// One singleton per DMA channel // One singleton per DMA channel
stm32_metapac::dma_channels! { for c in METADATA.dma_channels {
($channel_peri:ident, $dma_peri:ident, $version:ident, $channel_num:expr, $ignore:tt) => { singletons.push(c.name.to_string());
singletons.push(stringify!($channel_peri).to_string());
};
} }
let mut generated = String::new(); let mut g = TokenStream::new();
write!(
&mut generated, let singleton_tokens: Vec<_> = singletons.iter().map(|s| format_ident!("{}", s)).collect();
"embassy_hal_common::peripherals!({});\n", g.extend(quote! {
singletons.join(",") embassy_hal_common::peripherals!(#(#singleton_tokens),*);
) });
.unwrap();
// ======== // ========
// Generate DMA IRQs. // Generate DMA IRQs.
// This can't be done with macrotables alone because in many chips, one irq is shared between many
// channels, so we have to deduplicate them.
#[allow(unused_mut)] let mut dma_irqs: HashSet<&str> = HashSet::new();
let mut dma_irqs: Vec<String> = Vec::new(); let mut bdma_irqs: HashSet<&str> = HashSet::new();
#[allow(unused_mut)]
let mut bdma_irqs: Vec<String> = Vec::new();
stm32_metapac::interrupts! { for p in METADATA.peripherals {
($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => { if let Some(r) = &p.registers {
dma_irqs.push(stringify!($irq).to_string()); match r.kind {
}; "dma" => {
($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => { for irq in p.interrupts {
bdma_irqs.push(stringify!($irq).to_string()); dma_irqs.insert(irq.interrupt);
}; }
}
"bdma" => {
for irq in p.interrupts {
bdma_irqs.insert(irq.interrupt);
}
}
_ => {}
}
}
} }
dma_irqs.sort(); let tokens: Vec<_> = dma_irqs.iter().map(|s| format_ident!("{}", s)).collect();
dma_irqs.dedup(); g.extend(quote! {
bdma_irqs.sort(); #(
bdma_irqs.dedup(); #[crate::interrupt]
unsafe fn #tokens () {
crate::dma::dma::on_irq();
}
)*
});
for irq in dma_irqs { let tokens: Vec<_> = bdma_irqs.iter().map(|s| format_ident!("{}", s)).collect();
write!( g.extend(quote! {
&mut generated, #(
"#[crate::interrupt] unsafe fn {} () {{ crate::dma::dma::on_irq(); }}\n", #[crate::interrupt]
irq unsafe fn #tokens () {
) crate::dma::bdma::on_irq();
.unwrap(); }
} )*
});
for irq in bdma_irqs {
write!(
&mut generated,
"#[crate::interrupt] unsafe fn {} () {{ crate::dma::bdma::on_irq(); }}\n",
irq
)
.unwrap();
}
// ======== // ========
// Write generated.rs // Write generated.rs
let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
let out_file = out_dir.join("generated.rs").to_string_lossy().to_string(); let out_file = out_dir.join("generated.rs").to_string_lossy().to_string();
fs::write(out_file, &generated).unwrap(); fs::write(out_file, g.to_string()).unwrap();
// ======== // ========
// Multicore // Multicore