From a0bfbd74889dca64b71dfbcb412b251c578ab973 Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Thu, 7 Mar 2024 06:20:06 -0800 Subject: [PATCH] Create the `esp-metadata` package, update `esp-hal` build script to use it --- Cargo.toml | 1 + esp-hal/Cargo.toml | 7 +- esp-hal/build.rs | 108 ++-------- esp-metadata/Cargo.toml | 14 ++ esp-metadata/README.md | 30 +++ .../devices/esp32.toml | 1 + .../devices/esp32c2.toml | 3 +- .../devices/esp32c3.toml | 3 +- .../devices/esp32c6.toml | 3 +- .../devices/esp32h2.toml | 3 +- .../devices/esp32p4.toml | 3 +- .../devices/esp32s2.toml | 1 + .../devices/esp32s3.toml | 3 +- esp-metadata/src/lib.rs | 198 ++++++++++++++++++ 14 files changed, 273 insertions(+), 105 deletions(-) create mode 100644 esp-metadata/Cargo.toml create mode 100644 esp-metadata/README.md rename esp-hal/devices/esp32/device.toml => esp-metadata/devices/esp32.toml (98%) rename esp-hal/devices/esp32c2/device.toml => esp-metadata/devices/esp32c2.toml (96%) rename esp-hal/devices/esp32c3/device.toml => esp-metadata/devices/esp32c3.toml (96%) rename esp-hal/devices/esp32c6/device.toml => esp-metadata/devices/esp32c6.toml (97%) rename esp-hal/devices/esp32h2/device.toml => esp-metadata/devices/esp32h2.toml (97%) rename esp-hal/devices/esp32p4/device.toml => esp-metadata/devices/esp32p4.toml (97%) rename esp-hal/devices/esp32s2/device.toml => esp-metadata/devices/esp32s2.toml (98%) rename esp-hal/devices/esp32s3/device.toml => esp-metadata/devices/esp32s3.toml (97%) create mode 100644 esp-metadata/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 7a6512baecf..6215f581191 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ exclude = [ "esp-hal-procmacros", "esp-hal-smartled", "esp-lp-hal", + "esp-metadata", "esp-riscv-rt", "examples", ] diff --git a/esp-hal/Cargo.toml b/esp-hal/Cargo.toml index 912185c06fe..62fbe07fa93 100644 --- a/esp-hal/Cargo.toml +++ b/esp-hal/Cargo.toml @@ -68,9 +68,10 @@ esp-riscv-rt = { version = "0.7.0", optional = true, path = "../esp-riscv-rt" } xtensa-lx-rt = { version = "0.16.0", optional = true } [build-dependencies] -basic-toml = "0.1.8" -cfg-if = "1.0.0" -serde = { version = "1.0.197", features = ["derive"] } +basic-toml = "0.1.8" +cfg-if = "1.0.0" +esp-metadata = { version = "0.1.0", path = "../esp-metadata" } +serde = { version = "1.0.197", features = ["derive"] } [features] default = ["rt", "vectored"] diff --git a/esp-hal/build.rs b/esp-hal/build.rs index baae87d4633..a1d13e3518b 100644 --- a/esp-hal/build.rs +++ b/esp-hal/build.rs @@ -4,9 +4,10 @@ use std::{ fs::{self, File}, io::{BufRead, Write}, path::{Path, PathBuf}, + str::FromStr, }; -use serde::Deserialize; +use esp_metadata::{Arch, Chip, Config}; // Macros taken from: // https://github.com/TheDan64/inkwell/blob/36c3b10/src/lib.rs#L81-L110 @@ -45,61 +46,6 @@ macro_rules! assert_unique_used_features { } } -#[derive(Debug, Deserialize, PartialEq)] -enum Arch { - #[serde(rename = "riscv")] - RiscV, - #[serde(rename = "xtensa")] - Xtensa, -} - -impl std::fmt::Display for Arch { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!( - f, - "{}", - match self { - Arch::RiscV => "riscv", - Arch::Xtensa => "xtensa", - } - ) - } -} - -#[derive(Debug, Deserialize)] -enum CoreCount { - #[serde(rename = "single_core")] - Single, - #[serde(rename = "multi_core")] - Multi, -} - -impl std::fmt::Display for CoreCount { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!( - f, - "{}", - match self { - CoreCount::Single => "single_core", - CoreCount::Multi => "multi_core", - } - ) - } -} - -#[derive(Debug, Deserialize)] -struct Device { - pub arch: Arch, - pub cores: CoreCount, - pub peripherals: Vec, - pub symbols: Vec, -} - -#[derive(Debug, Deserialize)] -struct Config { - pub device: Device, -} - fn main() -> Result<(), Box> { // NOTE: update when adding new device support! // Ensure that exactly one chip has been specified: @@ -157,18 +103,11 @@ fn main() -> Result<(), Box> { } // Load the configuration file for the configured device: - let chip_toml_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("devices") - .join(device_name) - .join("device.toml") - .canonicalize()?; - - let config = fs::read_to_string(chip_toml_path)?; - let config: Config = basic_toml::from_str(&config)?; - let device = &config.device; + let chip = Chip::from_str(device_name)?; + let config = Config::for_chip(&chip); // Check PSRAM features are only given if the target supports PSRAM: - if !&device.symbols.contains(&String::from("psram")) + if !config.contains(&String::from("psram")) && (cfg!(feature = "psram-2m") || cfg!(feature = "psram-4m") || cfg!(feature = "psram-8m")) { panic!("The target does not support PSRAM"); @@ -176,40 +115,17 @@ fn main() -> Result<(), Box> { // Don't support "interrupt-preemption" and "direct-vectoring" on Xtensa and // RISC-V with CLIC: - if (device.symbols.contains(&String::from("clic")) || device.arch == Arch::Xtensa) + if (config.contains(&String::from("clic")) || config.arch() == Arch::Xtensa) && (cfg!(feature = "direct-vectoring") || cfg!(feature = "interrupt-preemption")) { panic!("The target does not support interrupt-preemption and direct-vectoring"); } // Define all necessary configuration symbols for the configured device: - println!("cargo:rustc-cfg={}", device_name); - println!("cargo:rustc-cfg={}", device.arch); - println!("cargo:rustc-cfg={}", device.cores); - - for peripheral in &device.peripherals { - println!("cargo:rustc-cfg={peripheral}"); - } - - for symbol in &device.symbols { - println!("cargo:rustc-cfg={symbol}"); - } - - let mut config_symbols = Vec::new(); - let arch = device.arch.to_string(); - let cores = device.cores.to_string(); - config_symbols.push(device_name); - config_symbols.push(&arch); - config_symbols.push(&cores); - - for peripheral in &device.peripherals { - config_symbols.push(peripheral); - } - - for symbol in &device.symbols { - config_symbols.push(symbol); - } + config.define_symbols(); + #[allow(unused_mut)] + let mut config_symbols = config.all(); #[cfg(feature = "flip-link")] config_symbols.push("flip-link"); @@ -260,7 +176,7 @@ fn main() -> Result<(), Box> { } fn copy_dir_all( - config_symbols: &Vec<&str>, + config_symbols: &Vec, src: impl AsRef, dst: impl AsRef, ) -> std::io::Result<()> { @@ -287,7 +203,7 @@ fn copy_dir_all( /// A naive pre-processor for linker scripts fn preprocess_file( - config: &[&str], + config: &[String], src: impl AsRef, dst: impl AsRef, ) -> std::io::Result<()> { @@ -302,7 +218,7 @@ fn preprocess_file( let trimmed = line.trim(); if let Some(stripped) = trimmed.strip_prefix("#IF ") { - let condition = stripped; + let condition = stripped.to_string(); let should_take = take.iter().all(|v| *v); let should_take = should_take && config.contains(&condition); take.push(should_take); diff --git a/esp-metadata/Cargo.toml b/esp-metadata/Cargo.toml new file mode 100644 index 00000000000..0ed765c0a43 --- /dev/null +++ b/esp-metadata/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "esp-metadata" +version = "0.1.0" +edition = "2021" +rust-version = "1.60.0" +description = "Metadata for Espressif devices" +repository = "https://github.com/esp-rs/esp-hal" +license = "MIT OR Apache-2.0" + +[dependencies] +basic-toml = "0.1.8" +lazy_static = "1.4.0" +serde = { version = "1.0.197", features = ["derive"] } +strum = { version = "0.26.1", features = ["derive"] } diff --git a/esp-metadata/README.md b/esp-metadata/README.md new file mode 100644 index 00000000000..c96e0d81e6b --- /dev/null +++ b/esp-metadata/README.md @@ -0,0 +1,30 @@ +# esp-metadata + +[![Crates.io](https://img.shields.io/crates/v/esp-metadata?color=C96329&logo=Rust&style=flat-square)](https://crates.io/crates/esp-metadata) +[![docs.rs](https://img.shields.io/docsrs/esp-metadata?color=C96329&logo=rust&style=flat-square)](https://docs.rs/esp-metadata) +![MSRV](https://img.shields.io/badge/MSRV-1.60-blue?style=flat-square) +![Crates.io](https://img.shields.io/crates/l/esp-metadata?style=flat-square) + +Metadata for Espressif devices, primarily intended for use in build scripts. + +## [Documentation](https://docs.rs/crate/esp-metadata) + +## Minimum Supported Rust Version (MSRV) + +This crate is guaranteed to compile on stable Rust 1.60 and up. It _might_ +compile with older versions but that may change in any new patch release. + +## License + +Licensed under either of: + +- Apache License, Version 2.0 ([LICENSE-APACHE](../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in +the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without +any additional terms or conditions. diff --git a/esp-hal/devices/esp32/device.toml b/esp-metadata/devices/esp32.toml similarity index 98% rename from esp-hal/devices/esp32/device.toml rename to esp-metadata/devices/esp32.toml index 5119a8f660b..8782e24d0be 100644 --- a/esp-hal/devices/esp32/device.toml +++ b/esp-metadata/devices/esp32.toml @@ -1,4 +1,5 @@ [device] +name = "esp32" arch = "xtensa" cores = "multi_core" diff --git a/esp-hal/devices/esp32c2/device.toml b/esp-metadata/devices/esp32c2.toml similarity index 96% rename from esp-hal/devices/esp32c2/device.toml rename to esp-metadata/devices/esp32c2.toml index a9db07055d2..d8fec7fd3ab 100644 --- a/esp-hal/devices/esp32c2/device.toml +++ b/esp-metadata/devices/esp32c2.toml @@ -1,5 +1,6 @@ [device] -arch = "riscv" +name = "esp32c2" +arch = "riscv" cores = "single_core" peripherals = [ diff --git a/esp-hal/devices/esp32c3/device.toml b/esp-metadata/devices/esp32c3.toml similarity index 96% rename from esp-hal/devices/esp32c3/device.toml rename to esp-metadata/devices/esp32c3.toml index 422f5d8b396..08a62907cb3 100644 --- a/esp-hal/devices/esp32c3/device.toml +++ b/esp-metadata/devices/esp32c3.toml @@ -1,5 +1,6 @@ [device] -arch = "riscv" +name = "esp32c3" +arch = "riscv" cores = "single_core" peripherals = [ diff --git a/esp-hal/devices/esp32c6/device.toml b/esp-metadata/devices/esp32c6.toml similarity index 97% rename from esp-hal/devices/esp32c6/device.toml rename to esp-metadata/devices/esp32c6.toml index 37ab80ba9af..128e8a06c24 100644 --- a/esp-hal/devices/esp32c6/device.toml +++ b/esp-metadata/devices/esp32c6.toml @@ -1,5 +1,6 @@ [device] -arch = "riscv" +name = "esp32c6" +arch = "riscv" cores = "single_core" peripherals = [ diff --git a/esp-hal/devices/esp32h2/device.toml b/esp-metadata/devices/esp32h2.toml similarity index 97% rename from esp-hal/devices/esp32h2/device.toml rename to esp-metadata/devices/esp32h2.toml index 82d4770e22e..886c4bf67db 100644 --- a/esp-hal/devices/esp32h2/device.toml +++ b/esp-metadata/devices/esp32h2.toml @@ -1,5 +1,6 @@ [device] -arch = "riscv" +name = "esp32h2" +arch = "riscv" cores = "single_core" peripherals = [ diff --git a/esp-hal/devices/esp32p4/device.toml b/esp-metadata/devices/esp32p4.toml similarity index 97% rename from esp-hal/devices/esp32p4/device.toml rename to esp-metadata/devices/esp32p4.toml index 79c1e729f9b..9d745becd85 100644 --- a/esp-hal/devices/esp32p4/device.toml +++ b/esp-metadata/devices/esp32p4.toml @@ -1,5 +1,6 @@ [device] -arch = "riscv" +name = "esp32p4" +arch = "riscv" cores = "multi_core" peripherals = [ diff --git a/esp-hal/devices/esp32s2/device.toml b/esp-metadata/devices/esp32s2.toml similarity index 98% rename from esp-hal/devices/esp32s2/device.toml rename to esp-metadata/devices/esp32s2.toml index 17e76599db5..666623ff443 100644 --- a/esp-hal/devices/esp32s2/device.toml +++ b/esp-metadata/devices/esp32s2.toml @@ -1,4 +1,5 @@ [device] +name = "esp32s2" arch = "xtensa" cores = "single_core" diff --git a/esp-hal/devices/esp32s3/device.toml b/esp-metadata/devices/esp32s3.toml similarity index 97% rename from esp-hal/devices/esp32s3/device.toml rename to esp-metadata/devices/esp32s3.toml index aa45c719f3c..3e337b9dbcb 100644 --- a/esp-hal/devices/esp32s3/device.toml +++ b/esp-metadata/devices/esp32s3.toml @@ -1,5 +1,6 @@ [device] -arch = "xtensa" +name = "esp32s3" +arch = "xtensa" cores = "multi_core" peripherals = [ diff --git a/esp-metadata/src/lib.rs b/esp-metadata/src/lib.rs new file mode 100644 index 00000000000..aab172f54ab --- /dev/null +++ b/esp-metadata/src/lib.rs @@ -0,0 +1,198 @@ +//! Metadata for Espressif devices, primarily intended for use in build scripts. + +const ESP32_TOML: &'static str = include_str!("../devices/esp32.toml"); +const ESP32C2_TOML: &'static str = include_str!("../devices/esp32c2.toml"); +const ESP32C3_TOML: &'static str = include_str!("../devices/esp32c3.toml"); +const ESP32C6_TOML: &'static str = include_str!("../devices/esp32c6.toml"); +const ESP32H2_TOML: &'static str = include_str!("../devices/esp32h2.toml"); +const ESP32P4_TOML: &'static str = include_str!("../devices/esp32p4.toml"); +const ESP32S2_TOML: &'static str = include_str!("../devices/esp32s2.toml"); +const ESP32S3_TOML: &'static str = include_str!("../devices/esp32s3.toml"); + +lazy_static::lazy_static! { + static ref ESP32_CFG: Config = basic_toml::from_str(ESP32_TOML).unwrap(); + static ref ESP32C2_CFG: Config = basic_toml::from_str(ESP32C2_TOML).unwrap(); + static ref ESP32C3_CFG: Config = basic_toml::from_str(ESP32C3_TOML).unwrap(); + static ref ESP32C6_CFG: Config = basic_toml::from_str(ESP32C6_TOML).unwrap(); + static ref ESP32H2_CFG: Config = basic_toml::from_str(ESP32H2_TOML).unwrap(); + static ref ESP32P4_CFG: Config = basic_toml::from_str(ESP32P4_TOML).unwrap(); + static ref ESP32S2_CFG: Config = basic_toml::from_str(ESP32S2_TOML).unwrap(); + static ref ESP32S3_CFG: Config = basic_toml::from_str(ESP32S3_TOML).unwrap(); +} + +/// Supported device architectures. +#[derive( + Debug, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + serde::Deserialize, + serde::Serialize, + strum::Display, + strum::EnumIter, + strum::EnumString, +)] +#[serde(rename_all = "lowercase")] +#[strum(serialize_all = "lowercase")] +pub enum Arch { + /// RISC-V architecture + RiscV, + /// Xtensa architecture + Xtensa, +} + +/// Device core count. +#[derive( + Debug, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + serde::Deserialize, + serde::Serialize, + strum::Display, + strum::EnumIter, + strum::EnumString, +)] +pub enum Cores { + /// Single CPU core + #[serde(rename = "single_core")] + #[strum(serialize = "single_core")] + Single, + /// Two or more CPU cores + #[serde(rename = "multi_core")] + #[strum(serialize = "multi_core")] + Multi, +} + +/// Supported devices. +#[derive( + Debug, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + serde::Deserialize, + serde::Serialize, + strum::Display, + strum::EnumIter, + strum::EnumString, +)] +#[serde(rename_all = "lowercase")] +#[strum(serialize_all = "lowercase")] +pub enum Chip { + /// ESP32 + Esp32, + /// ESP32-C2, ESP8684 + Esp32c2, + /// ESP32-C3, ESP8685 + Esp32c3, + /// ESP32-C6 + Esp32c6, + /// ESP32-H2 + Esp32h2, + /// ESP32-P4 + Esp32p4, + /// ESP32-S2 + Esp32s2, + /// ESP32-S3 + Esp32s3, +} + +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] +struct Device { + pub name: String, + pub arch: Arch, + pub cores: Cores, + pub peripherals: Vec, + pub symbols: Vec, +} + +/// Device configuration file format. +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] +pub struct Config { + device: Device, +} + +impl Config { + /// The configuration for the specified chip. + pub fn for_chip(chip: &Chip) -> Self { + match chip { + Chip::Esp32 => ESP32_CFG.clone(), + Chip::Esp32c2 => ESP32C2_CFG.clone(), + Chip::Esp32c3 => ESP32C3_CFG.clone(), + Chip::Esp32c6 => ESP32C6_CFG.clone(), + Chip::Esp32h2 => ESP32H2_CFG.clone(), + Chip::Esp32p4 => ESP32P4_CFG.clone(), + Chip::Esp32s2 => ESP32S2_CFG.clone(), + Chip::Esp32s3 => ESP32S3_CFG.clone(), + } + } + + /// The name of the device. + pub fn name(&self) -> String { + self.device.name.clone() + } + + /// The CPU architecture of the device. + pub fn arch(&self) -> Arch { + self.device.arch + } + + /// The core count of the device. + pub fn cores(&self) -> Cores { + self.device.cores + } + + /// The peripherals of the device. + pub fn peripherals(&self) -> &[String] { + &self.device.peripherals + } + + /// User-defined symbols for the device. + pub fn symbols(&self) -> &[String] { + &self.device.symbols + } + + /// All configuration values for the device. + pub fn all(&self) -> Vec { + [ + vec![ + self.device.name.clone(), + self.device.arch.to_string(), + self.device.cores.to_string(), + ], + self.device.peripherals.clone(), + self.device.symbols.clone(), + ] + .concat() + } + + /// Does the configuration contain `item`? + pub fn contains(&self, item: &String) -> bool { + self.all().contains(item) + } + + /// Define all symbols for a given configuration. + pub fn define_symbols(&self) { + // Define all necessary configuration symbols for the configured device: + println!("cargo:rustc-cfg={}", self.name()); + println!("cargo:rustc-cfg={}", self.arch()); + println!("cargo:rustc-cfg={}", self.cores()); + + for peripheral in self.peripherals() { + println!("cargo:rustc-cfg={peripheral}"); + } + + for symbol in self.symbols() { + println!("cargo:rustc-cfg={symbol}"); + } + } +}