diff options
| author | Dario Nieuwenhuis <[email protected]> | 2022-02-26 02:01:59 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2022-02-26 03:23:09 +0100 |
| commit | 451bb48464fe685d26606d4f050a7972dc093c64 (patch) | |
| tree | 52c3c3ca05e2960ffb21e6e02ae969f58e003027 | |
| parent | dd828a7a9259526a6d5f319a73623bcf8309479c (diff) | |
stm32-metapac: remove all macrotables, deduplicate metadata files.
| -rw-r--r-- | stm32-metapac-gen/src/assets/lib_inner.rs | 6 | ||||
| -rw-r--r-- | stm32-metapac-gen/src/lib.rs | 723 | ||||
| -rw-r--r-- | stm32-metapac-gen/src/main.rs | 5 | ||||
| -rw-r--r-- | stm32-metapac/Cargo.toml | 15 | ||||
| -rw-r--r-- | stm32-metapac/build.rs | 27 | ||||
| -rw-r--r-- | stm32-metapac/build_pregenerated.rs (renamed from stm32-metapac-gen/src/assets/build.rs) | 10 | ||||
| -rw-r--r-- | stm32-metapac/src/common.rs | 80 | ||||
| -rw-r--r-- | stm32-metapac/src/lib.rs | 12 | ||||
| -rw-r--r-- | stm32-metapac/src/metadata.rs (renamed from stm32-metapac-gen/src/assets/metadata.rs) | 0 |
9 files changed, 399 insertions, 479 deletions
diff --git a/stm32-metapac-gen/src/assets/lib_inner.rs b/stm32-metapac-gen/src/assets/lib_inner.rs deleted file mode 100644 index b7729cb3a..000000000 --- a/stm32-metapac-gen/src/assets/lib_inner.rs +++ /dev/null | |||
| @@ -1,6 +0,0 @@ | |||
| 1 | // GEN PATHS HERE | ||
| 2 | mod inner; | ||
| 3 | |||
| 4 | pub mod common; | ||
| 5 | |||
| 6 | pub use inner::*; | ||
diff --git a/stm32-metapac-gen/src/lib.rs b/stm32-metapac-gen/src/lib.rs index 575be9e4b..14625097e 100644 --- a/stm32-metapac-gen/src/lib.rs +++ b/stm32-metapac-gen/src/lib.rs | |||
| @@ -1,8 +1,9 @@ | |||
| 1 | use chiptool::generate::CommonModule; | 1 | use chiptool::generate::CommonModule; |
| 2 | use chiptool::{generate, ir, transform}; | ||
| 2 | use proc_macro2::TokenStream; | 3 | use proc_macro2::TokenStream; |
| 3 | use regex::Regex; | 4 | use regex::Regex; |
| 4 | use std::collections::{BTreeMap, HashMap, HashSet}; | 5 | use std::collections::{BTreeMap, HashMap, HashSet}; |
| 5 | use std::fmt::Write as _; | 6 | use std::fmt::{Debug, Write as _}; |
| 6 | use std::fs; | 7 | use std::fs; |
| 7 | use std::fs::File; | 8 | use std::fs::File; |
| 8 | use std::io::Write; | 9 | use std::io::Write; |
| @@ -10,9 +11,6 @@ use std::path::Path; | |||
| 10 | use std::path::PathBuf; | 11 | use std::path::PathBuf; |
| 11 | use std::str::FromStr; | 12 | use std::str::FromStr; |
| 12 | 13 | ||
| 13 | use chiptool::util::ToSanitizedSnakeCase; | ||
| 14 | use chiptool::{generate, ir, transform}; | ||
| 15 | |||
| 16 | mod data; | 14 | mod data; |
| 17 | use data::*; | 15 | use data::*; |
| 18 | 16 | ||
| @@ -27,532 +25,322 @@ struct Metadata<'a> { | |||
| 27 | dma_channels: &'a [DmaChannel], | 25 | dma_channels: &'a [DmaChannel], |
| 28 | } | 26 | } |
| 29 | 27 | ||
| 30 | fn make_peripheral_counts(out: &mut String, data: &BTreeMap<String, u8>) { | ||
| 31 | write!( | ||
| 32 | out, | ||
| 33 | "#[macro_export] | ||
| 34 | macro_rules! peripheral_count {{ | ||
| 35 | " | ||
| 36 | ) | ||
| 37 | .unwrap(); | ||
| 38 | for (name, count) in data { | ||
| 39 | write!(out, "({}) => ({});\n", name, count,).unwrap(); | ||
| 40 | } | ||
| 41 | write!(out, " }}\n").unwrap(); | ||
| 42 | } | ||
| 43 | |||
| 44 | fn make_dma_channel_counts(out: &mut String, data: &BTreeMap<String, u8>) { | ||
| 45 | if data.len() == 0 { | ||
| 46 | return; | ||
| 47 | } | ||
| 48 | write!( | ||
| 49 | out, | ||
| 50 | "#[macro_export] | ||
| 51 | macro_rules! dma_channels_count {{ | ||
| 52 | " | ||
| 53 | ) | ||
| 54 | .unwrap(); | ||
| 55 | for (name, count) in data { | ||
| 56 | write!(out, "({}) => ({});\n", name, count,).unwrap(); | ||
| 57 | } | ||
| 58 | write!(out, " }}\n").unwrap(); | ||
| 59 | } | ||
| 60 | |||
| 61 | fn make_table(out: &mut String, name: &str, data: &Vec<Vec<String>>) { | ||
| 62 | write!( | ||
| 63 | out, | ||
| 64 | "#[macro_export] | ||
| 65 | macro_rules! {} {{ | ||
| 66 | ($($pat:tt => $code:tt;)*) => {{ | ||
| 67 | macro_rules! __{}_inner {{ | ||
| 68 | $(($pat) => $code;)* | ||
| 69 | ($_:tt) => {{}} | ||
| 70 | }} | ||
| 71 | ", | ||
| 72 | name, name | ||
| 73 | ) | ||
| 74 | .unwrap(); | ||
| 75 | |||
| 76 | for row in data { | ||
| 77 | write!(out, " __{}_inner!(({}));\n", name, row.join(",")).unwrap(); | ||
| 78 | } | ||
| 79 | |||
| 80 | write!( | ||
| 81 | out, | ||
| 82 | " }}; | ||
| 83 | }}" | ||
| 84 | ) | ||
| 85 | .unwrap(); | ||
| 86 | } | ||
| 87 | |||
| 88 | pub struct Options { | 28 | pub struct Options { |
| 89 | pub chips: Vec<String>, | 29 | pub chips: Vec<String>, |
| 90 | pub out_dir: PathBuf, | 30 | pub out_dir: PathBuf, |
| 91 | pub data_dir: PathBuf, | 31 | pub data_dir: PathBuf, |
| 92 | } | 32 | } |
| 93 | 33 | ||
| 94 | pub fn gen_chip( | 34 | pub struct Gen { |
| 95 | options: &Options, | 35 | opts: Options, |
| 96 | chip_core_name: &str, | 36 | all_peripheral_versions: HashSet<(String, String)>, |
| 97 | chip: &Chip, | 37 | metadata_dedup: HashMap<String, String>, |
| 98 | core: &Core, | 38 | } |
| 99 | core_index: usize, | 39 | |
| 100 | all_peripheral_versions: &mut HashSet<(String, String)>, | 40 | impl Gen { |
| 101 | ) { | 41 | pub fn new(opts: Options) -> Self { |
| 102 | let mut ir = ir::IR::new(); | 42 | Self { |
| 103 | 43 | opts, | |
| 104 | let mut dev = ir::Device { | 44 | all_peripheral_versions: HashSet::new(), |
| 105 | interrupts: Vec::new(), | 45 | metadata_dedup: HashMap::new(), |
| 106 | peripherals: Vec::new(), | ||
| 107 | }; | ||
| 108 | |||
| 109 | // Load DBGMCU register for chip | ||
| 110 | let mut dbgmcu: Option<ir::IR> = core.peripherals.iter().find_map(|p| { | ||
| 111 | if p.name == "DBGMCU" { | ||
| 112 | p.registers.as_ref().map(|bi| { | ||
| 113 | let dbgmcu_reg_path = options | ||
| 114 | .data_dir | ||
| 115 | .join("registers") | ||
| 116 | .join(&format!("{}_{}.yaml", bi.kind, bi.version)); | ||
| 117 | serde_yaml::from_reader(File::open(dbgmcu_reg_path).unwrap()).unwrap() | ||
| 118 | }) | ||
| 119 | } else { | ||
| 120 | None | ||
| 121 | } | ||
| 122 | }); | ||
| 123 | |||
| 124 | let mut peripheral_versions: BTreeMap<String, String> = BTreeMap::new(); | ||
| 125 | let mut pin_table: Vec<Vec<String>> = Vec::new(); | ||
| 126 | let mut interrupt_table: Vec<Vec<String>> = Vec::new(); | ||
| 127 | let mut peripherals_table: Vec<Vec<String>> = Vec::new(); | ||
| 128 | let mut dma_channels_table: Vec<Vec<String>> = Vec::new(); | ||
| 129 | let mut peripheral_counts: BTreeMap<String, u8> = BTreeMap::new(); | ||
| 130 | let mut dma_channel_counts: BTreeMap<String, u8> = BTreeMap::new(); | ||
| 131 | let mut dbgmcu_table: Vec<Vec<String>> = Vec::new(); | ||
| 132 | |||
| 133 | let gpio_base = core | ||
| 134 | .peripherals | ||
| 135 | .iter() | ||
| 136 | .find(|p| p.name == "GPIOA") | ||
| 137 | .unwrap() | ||
| 138 | .address as u32; | ||
| 139 | let gpio_stride = 0x400; | ||
| 140 | |||
| 141 | let number_suffix_re = Regex::new("^(.*?)[0-9]*$").unwrap(); | ||
| 142 | |||
| 143 | if let Some(ref mut reg) = dbgmcu { | ||
| 144 | if let Some(ref cr) = reg.fieldsets.get("CR") { | ||
| 145 | for field in cr.fields.iter().filter(|e| e.name.contains("DBG")) { | ||
| 146 | let mut fn_name = String::new(); | ||
| 147 | fn_name.push_str("set_"); | ||
| 148 | fn_name.push_str(&field.name.to_sanitized_snake_case()); | ||
| 149 | dbgmcu_table.push(vec!["cr".into(), fn_name]); | ||
| 150 | } | ||
| 151 | } | 46 | } |
| 152 | } | 47 | } |
| 153 | 48 | ||
| 154 | for p in &core.peripherals { | 49 | fn gen_chip(&mut self, chip_core_name: &str, chip: &Chip, core: &Core, core_index: usize) { |
| 155 | let captures = number_suffix_re.captures(&p.name).unwrap(); | 50 | let mut ir = ir::IR::new(); |
| 156 | let root_peri_name = captures.get(1).unwrap().as_str().to_string(); | 51 | |
| 157 | peripheral_counts.insert( | 52 | let mut dev = ir::Device { |
| 158 | root_peri_name.clone(), | 53 | interrupts: Vec::new(), |
| 159 | peripheral_counts.get(&root_peri_name).map_or(1, |v| v + 1), | 54 | peripherals: Vec::new(), |
| 160 | ); | ||
| 161 | let mut ir_peri = ir::Peripheral { | ||
| 162 | name: p.name.clone(), | ||
| 163 | array: None, | ||
| 164 | base_address: p.address, | ||
| 165 | block: None, | ||
| 166 | description: None, | ||
| 167 | interrupts: HashMap::new(), | ||
| 168 | }; | 55 | }; |
| 169 | 56 | ||
| 170 | if let Some(bi) = &p.registers { | 57 | let mut peripheral_versions: BTreeMap<String, String> = BTreeMap::new(); |
| 171 | peripheral_counts.insert( | 58 | |
| 172 | bi.kind.clone(), | 59 | let gpio_base = core |
| 173 | peripheral_counts.get(&bi.kind).map_or(1, |v| v + 1), | 60 | .peripherals |
| 174 | ); | 61 | .iter() |
| 175 | 62 | .find(|p| p.name == "GPIOA") | |
| 176 | for irq in &p.interrupts { | 63 | .unwrap() |
| 177 | let mut row = Vec::new(); | 64 | .address as u32; |
| 178 | row.push(p.name.clone()); | 65 | let gpio_stride = 0x400; |
| 179 | row.push(bi.kind.clone()); | 66 | |
| 180 | row.push(bi.block.clone()); | 67 | for p in &core.peripherals { |
| 181 | row.push(irq.signal.clone()); | 68 | let mut ir_peri = ir::Peripheral { |
| 182 | row.push(irq.interrupt.to_ascii_uppercase()); | 69 | name: p.name.clone(), |
| 183 | interrupt_table.push(row) | 70 | array: None, |
| 184 | } | 71 | base_address: p.address, |
| 72 | block: None, | ||
| 73 | description: None, | ||
| 74 | interrupts: HashMap::new(), | ||
| 75 | }; | ||
| 185 | 76 | ||
| 186 | let mut peripheral_row = Vec::new(); | 77 | if let Some(bi) = &p.registers { |
| 187 | peripheral_row.push(bi.kind.clone()); | 78 | if let Some(old_version) = |
| 188 | peripheral_row.push(p.name.clone()); | 79 | peripheral_versions.insert(bi.kind.clone(), bi.version.clone()) |
| 189 | peripherals_table.push(peripheral_row); | 80 | { |
| 190 | 81 | if old_version != bi.version { | |
| 191 | if let Some(old_version) = | 82 | panic!( |
| 192 | peripheral_versions.insert(bi.kind.clone(), bi.version.clone()) | 83 | "Peripheral {} has multiple versions: {} and {}", |
| 193 | { | 84 | bi.kind, old_version, bi.version |
| 194 | if old_version != bi.version { | 85 | ); |
| 195 | panic!( | 86 | } |
| 196 | "Peripheral {} has multiple versions: {} and {}", | ||
| 197 | bi.kind, old_version, bi.version | ||
| 198 | ); | ||
| 199 | } | 87 | } |
| 200 | } | 88 | ir_peri.block = Some(format!("{}::{}", bi.kind, bi.block)); |
| 201 | ir_peri.block = Some(format!("{}::{}", bi.kind, bi.block)); | ||
| 202 | 89 | ||
| 203 | match bi.kind.as_str() { | 90 | if bi.kind == "gpio" { |
| 204 | "gpio" => { | ||
| 205 | let port_letter = p.name.chars().skip(4).next().unwrap(); | ||
| 206 | assert_eq!(0, (p.address as u32 - gpio_base) % gpio_stride); | 91 | assert_eq!(0, (p.address as u32 - gpio_base) % gpio_stride); |
| 207 | let port_num = (p.address as u32 - gpio_base) / gpio_stride; | ||
| 208 | |||
| 209 | for pin_num in 0u32..16 { | ||
| 210 | let pin_name = format!("P{}{}", port_letter, pin_num); | ||
| 211 | pin_table.push(vec![ | ||
| 212 | pin_name.clone(), | ||
| 213 | p.name.clone(), | ||
| 214 | port_num.to_string(), | ||
| 215 | pin_num.to_string(), | ||
| 216 | format!("EXTI{}", pin_num), | ||
| 217 | ]); | ||
| 218 | } | ||
| 219 | } | 92 | } |
| 220 | _ => {} | ||
| 221 | } | 93 | } |
| 222 | } | ||
| 223 | |||
| 224 | dev.peripherals.push(ir_peri); | ||
| 225 | } | ||
| 226 | 94 | ||
| 227 | for ch in &core.dma_channels { | 95 | dev.peripherals.push(ir_peri); |
| 228 | let mut row = Vec::new(); | ||
| 229 | let dma_peri = core.peripherals.iter().find(|p| p.name == ch.dma).unwrap(); | ||
| 230 | let bi = dma_peri.registers.as_ref().unwrap(); | ||
| 231 | |||
| 232 | row.push(ch.name.clone()); | ||
| 233 | row.push(ch.dma.clone()); | ||
| 234 | row.push(bi.kind.clone()); | ||
| 235 | row.push(ch.channel.to_string()); | ||
| 236 | if let Some(dmamux) = &ch.dmamux { | ||
| 237 | let dmamux_channel = ch.dmamux_channel.unwrap(); | ||
| 238 | row.push(format!( | ||
| 239 | "{{dmamux: {}, dmamux_channel: {}}}", | ||
| 240 | dmamux, dmamux_channel | ||
| 241 | )); | ||
| 242 | } else { | ||
| 243 | row.push("{}".to_string()); | ||
| 244 | } | 96 | } |
| 245 | 97 | ||
| 246 | dma_channels_table.push(row); | 98 | for irq in &core.interrupts { |
| 247 | 99 | dev.interrupts.push(ir::Interrupt { | |
| 248 | let dma_peri_name = ch.dma.clone(); | 100 | name: irq.name.clone(), |
| 249 | dma_channel_counts.insert( | 101 | description: None, |
| 250 | dma_peri_name.clone(), | 102 | value: irq.number, |
| 251 | dma_channel_counts.get(&dma_peri_name).map_or(1, |v| v + 1), | 103 | }); |
| 252 | ); | ||
| 253 | } | ||
| 254 | |||
| 255 | for irq in &core.interrupts { | ||
| 256 | dev.interrupts.push(ir::Interrupt { | ||
| 257 | name: irq.name.clone(), | ||
| 258 | description: None, | ||
| 259 | value: irq.number, | ||
| 260 | }); | ||
| 261 | |||
| 262 | let name = irq.name.to_ascii_uppercase(); | ||
| 263 | |||
| 264 | interrupt_table.push(vec![name.clone()]); | ||
| 265 | |||
| 266 | if name.contains("EXTI") { | ||
| 267 | interrupt_table.push(vec!["EXTI".to_string(), name.clone()]); | ||
| 268 | } | 104 | } |
| 269 | } | ||
| 270 | 105 | ||
| 271 | ir.devices.insert("".to_string(), dev); | 106 | ir.devices.insert("".to_string(), dev); |
| 272 | 107 | ||
| 273 | let mut extra = format!( | 108 | let mut extra = format!( |
| 274 | "pub fn GPIO(n: usize) -> gpio::Gpio {{ | 109 | "pub fn GPIO(n: usize) -> gpio::Gpio {{ |
| 275 | gpio::Gpio(({} + {}*n) as _) | 110 | gpio::Gpio(({} + {}*n) as _) |
| 276 | }}", | 111 | }}", |
| 277 | gpio_base, gpio_stride, | 112 | gpio_base, gpio_stride, |
| 278 | ); | 113 | ); |
| 279 | 114 | ||
| 280 | for (module, version) in &peripheral_versions { | 115 | for (module, version) in &peripheral_versions { |
| 281 | all_peripheral_versions.insert((module.clone(), version.clone())); | 116 | self.all_peripheral_versions |
| 117 | .insert((module.clone(), version.clone())); | ||
| 118 | write!( | ||
| 119 | &mut extra, | ||
| 120 | "#[path=\"../../peripherals/{}_{}.rs\"] pub mod {};\n", | ||
| 121 | module, version, module | ||
| 122 | ) | ||
| 123 | .unwrap(); | ||
| 124 | } | ||
| 282 | write!( | 125 | write!( |
| 283 | &mut extra, | 126 | &mut extra, |
| 284 | "#[path=\"../../peripherals/{}_{}.rs\"] pub mod {};\n", | 127 | "pub const CORE_INDEX: usize = {};\n", |
| 285 | module, version, module | 128 | core_index |
| 286 | ) | 129 | ) |
| 287 | .unwrap(); | 130 | .unwrap(); |
| 288 | } | ||
| 289 | write!( | ||
| 290 | &mut extra, | ||
| 291 | "pub const CORE_INDEX: usize = {};\n", | ||
| 292 | core_index | ||
| 293 | ) | ||
| 294 | .unwrap(); | ||
| 295 | 131 | ||
| 296 | // Cleanups! | 132 | // Cleanups! |
| 297 | transform::sort::Sort {}.run(&mut ir).unwrap(); | 133 | transform::sort::Sort {}.run(&mut ir).unwrap(); |
| 298 | transform::Sanitize {}.run(&mut ir).unwrap(); | 134 | transform::Sanitize {}.run(&mut ir).unwrap(); |
| 299 | 135 | ||
| 300 | // ============================== | 136 | // ============================== |
| 301 | // Setup chip dir | 137 | // Setup chip dir |
| 302 | 138 | ||
| 303 | let chip_dir = options | 139 | let chip_dir = self |
| 304 | .out_dir | 140 | .opts |
| 305 | .join("src/chips") | 141 | .out_dir |
| 306 | .join(chip_core_name.to_ascii_lowercase()); | 142 | .join("src/chips") |
| 307 | fs::create_dir_all(&chip_dir).unwrap(); | 143 | .join(chip_core_name.to_ascii_lowercase()); |
| 144 | fs::create_dir_all(&chip_dir).unwrap(); | ||
| 308 | 145 | ||
| 309 | // ============================== | 146 | // ============================== |
| 310 | // generate pac.rs | 147 | // generate pac.rs |
| 311 | 148 | ||
| 312 | let data = generate::render(&ir, &gen_opts()).unwrap().to_string(); | 149 | let data = generate::render(&ir, &gen_opts()).unwrap().to_string(); |
| 313 | let data = data.replace("] ", "]\n"); | 150 | let data = data.replace("] ", "]\n"); |
| 314 | 151 | ||
| 315 | // Remove inner attributes like #![no_std] | 152 | // Remove inner attributes like #![no_std] |
| 316 | let data = Regex::new("# *! *\\[.*\\]").unwrap().replace_all(&data, ""); | 153 | let data = Regex::new("# *! *\\[.*\\]").unwrap().replace_all(&data, ""); |
| 317 | 154 | ||
| 318 | let mut file = File::create(chip_dir.join("pac.rs")).unwrap(); | 155 | let mut file = File::create(chip_dir.join("pac.rs")).unwrap(); |
| 319 | file.write_all(data.as_bytes()).unwrap(); | 156 | file.write_all(data.as_bytes()).unwrap(); |
| 320 | file.write_all(extra.as_bytes()).unwrap(); | 157 | file.write_all(extra.as_bytes()).unwrap(); |
| 321 | 158 | ||
| 322 | let mut device_x = String::new(); | 159 | let mut device_x = String::new(); |
| 323 | 160 | ||
| 324 | for irq in &core.interrupts { | 161 | for irq in &core.interrupts { |
| 325 | write!(&mut device_x, "PROVIDE({} = DefaultHandler);\n", irq.name).unwrap(); | 162 | write!(&mut device_x, "PROVIDE({} = DefaultHandler);\n", irq.name).unwrap(); |
| 326 | } | 163 | } |
| 327 | 164 | ||
| 328 | // ============================== | 165 | // ============================== |
| 329 | // generate mod.rs | 166 | // generate metadata.rs |
| 330 | |||
| 331 | let mut data = String::new(); | ||
| 332 | |||
| 333 | write!(&mut data, "#[cfg(feature=\"metadata\")] pub mod metadata;").unwrap(); | ||
| 334 | write!(&mut data, "#[cfg(feature=\"pac\")] mod pac;").unwrap(); | ||
| 335 | write!(&mut data, "#[cfg(feature=\"pac\")] pub use pac::*; ").unwrap(); | ||
| 336 | |||
| 337 | let peripheral_version_table = peripheral_versions | ||
| 338 | .iter() | ||
| 339 | .map(|(kind, version)| vec![kind.clone(), version.clone()]) | ||
| 340 | .collect(); | ||
| 341 | |||
| 342 | make_table(&mut data, "pins", &pin_table); | ||
| 343 | make_table(&mut data, "interrupts", &interrupt_table); | ||
| 344 | make_table(&mut data, "peripherals", &peripherals_table); | ||
| 345 | make_table(&mut data, "peripheral_versions", &peripheral_version_table); | ||
| 346 | make_table(&mut data, "dma_channels", &dma_channels_table); | ||
| 347 | make_table(&mut data, "dbgmcu", &dbgmcu_table); | ||
| 348 | make_peripheral_counts(&mut data, &peripheral_counts); | ||
| 349 | make_dma_channel_counts(&mut data, &dma_channel_counts); | ||
| 350 | |||
| 351 | let mut file = File::create(chip_dir.join("mod.rs")).unwrap(); | ||
| 352 | file.write_all(data.as_bytes()).unwrap(); | ||
| 353 | |||
| 354 | // ============================== | ||
| 355 | // generate metadata.rs | ||
| 356 | |||
| 357 | let metadata = Metadata { | ||
| 358 | name: &chip.name, | ||
| 359 | family: &chip.family, | ||
| 360 | line: &chip.line, | ||
| 361 | memory: &chip.memory, | ||
| 362 | peripherals: &core.peripherals, | ||
| 363 | interrupts: &core.interrupts, | ||
| 364 | dma_channels: &core.dma_channels, | ||
| 365 | }; | ||
| 366 | let metadata = format!("{:#?}", metadata); | ||
| 367 | let metadata = metadata.replace("[\n", "&[\n"); | ||
| 368 | let metadata = metadata.replace("[],\n", "&[],\n"); | ||
| 369 | |||
| 370 | let mut data = String::new(); | ||
| 371 | 167 | ||
| 372 | write!( | 168 | // (peripherals, interrupts, dma_channels) are often equal across multiple chips. |
| 373 | &mut data, | 169 | // To reduce bloat, deduplicate them. |
| 374 | " | 170 | let mut data = String::new(); |
| 375 | include!(\"../../metadata.rs\"); | 171 | write!( |
| 376 | use MemoryRegionKind::*; | 172 | &mut data, |
| 377 | pub const METADATA: Metadata = {}; | 173 | " |
| 378 | ", | 174 | const PERIPHERALS: &'static [Peripheral] = {}; |
| 379 | metadata | 175 | const INTERRUPTS: &'static [Interrupt] = {}; |
| 380 | ) | 176 | const DMA_CHANNELS: &'static [DmaChannel] = {}; |
| 381 | .unwrap(); | 177 | ", |
| 178 | stringify(&core.peripherals), | ||
| 179 | stringify(&core.interrupts), | ||
| 180 | stringify(&core.dma_channels), | ||
| 181 | ) | ||
| 182 | .unwrap(); | ||
| 382 | 183 | ||
| 383 | let mut file = File::create(chip_dir.join("metadata.rs")).unwrap(); | 184 | let out_dir = self.opts.out_dir.clone(); |
| 384 | file.write_all(data.as_bytes()).unwrap(); | 185 | let n = self.metadata_dedup.len(); |
| 186 | let deduped_file = self.metadata_dedup.entry(data.clone()).or_insert_with(|| { | ||
| 187 | let file = format!("metadata_{:04}.rs", n); | ||
| 188 | let path = out_dir.join("src/chips").join(&file); | ||
| 189 | fs::write(path, data).unwrap(); | ||
| 385 | 190 | ||
| 386 | // ============================== | 191 | file |
| 387 | // generate device.x | 192 | }); |
| 388 | 193 | ||
| 389 | File::create(chip_dir.join("device.x")) | 194 | let data = format!( |
| 390 | .unwrap() | 195 | "include!(\"../{}\"); |
| 391 | .write_all(device_x.as_bytes()) | 196 | pub const METADATA: Metadata = Metadata {{ |
| 392 | .unwrap(); | 197 | name: {:?}, |
| 198 | family: {:?}, | ||
| 199 | line: {:?}, | ||
| 200 | memory: {}, | ||
| 201 | peripherals: PERIPHERALS, | ||
| 202 | interrupts: INTERRUPTS, | ||
| 203 | dma_channels: DMA_CHANNELS, | ||
| 204 | }};", | ||
| 205 | deduped_file, | ||
| 206 | &chip.name, | ||
| 207 | &chip.family, | ||
| 208 | &chip.line, | ||
| 209 | stringify(&chip.memory), | ||
| 210 | ); | ||
| 393 | 211 | ||
| 394 | // ============================== | 212 | let mut file = File::create(chip_dir.join("metadata.rs")).unwrap(); |
| 395 | // generate default memory.x | 213 | file.write_all(data.as_bytes()).unwrap(); |
| 396 | gen_memory_x(&chip_dir, &chip); | ||
| 397 | } | ||
| 398 | 214 | ||
| 399 | fn load_chip(options: &Options, name: &str) -> Chip { | 215 | // ============================== |
| 400 | let chip_path = options | 216 | // generate device.x |
| 401 | .data_dir | ||
| 402 | .join("chips") | ||
| 403 | .join(&format!("{}.json", name)); | ||
| 404 | let chip = fs::read(chip_path).expect(&format!("Could not load chip {}", name)); | ||
| 405 | serde_yaml::from_slice(&chip).unwrap() | ||
| 406 | } | ||
| 407 | 217 | ||
| 408 | fn gen_opts() -> generate::Options { | 218 | File::create(chip_dir.join("device.x")) |
| 409 | generate::Options { | 219 | .unwrap() |
| 410 | common_module: CommonModule::External(TokenStream::from_str("crate::common").unwrap()), | 220 | .write_all(device_x.as_bytes()) |
| 221 | .unwrap(); | ||
| 222 | |||
| 223 | // ============================== | ||
| 224 | // generate default memory.x | ||
| 225 | gen_memory_x(&chip_dir, &chip); | ||
| 411 | } | 226 | } |
| 412 | } | ||
| 413 | 227 | ||
| 414 | pub fn gen(options: Options) { | 228 | fn load_chip(&mut self, name: &str) -> Chip { |
| 415 | fs::create_dir_all(options.out_dir.join("src/peripherals")).unwrap(); | 229 | let chip_path = self |
| 416 | fs::create_dir_all(options.out_dir.join("src/chips")).unwrap(); | 230 | .opts |
| 231 | .data_dir | ||
| 232 | .join("chips") | ||
| 233 | .join(&format!("{}.json", name)); | ||
| 234 | let chip = fs::read(chip_path).expect(&format!("Could not load chip {}", name)); | ||
| 235 | serde_yaml::from_slice(&chip).unwrap() | ||
| 236 | } | ||
| 417 | 237 | ||
| 418 | let mut all_peripheral_versions: HashSet<(String, String)> = HashSet::new(); | 238 | pub fn gen(&mut self) { |
| 419 | let mut chip_core_names: Vec<String> = Vec::new(); | 239 | fs::create_dir_all(self.opts.out_dir.join("src/peripherals")).unwrap(); |
| 240 | fs::create_dir_all(self.opts.out_dir.join("src/chips")).unwrap(); | ||
| 420 | 241 | ||
| 421 | for chip_name in &options.chips { | 242 | let mut chip_core_names: Vec<String> = Vec::new(); |
| 422 | println!("Generating {}...", chip_name); | ||
| 423 | 243 | ||
| 424 | let mut chip = load_chip(&options, chip_name); | 244 | for chip_name in &self.opts.chips.clone() { |
| 245 | println!("Generating {}...", chip_name); | ||
| 425 | 246 | ||
| 426 | // Cleanup | 247 | let mut chip = self.load_chip(chip_name); |
| 427 | for core in &mut chip.cores { | 248 | |
| 428 | for irq in &mut core.interrupts { | 249 | // Cleanup |
| 429 | irq.name = irq.name.to_ascii_uppercase(); | 250 | for core in &mut chip.cores { |
| 430 | } | 251 | for irq in &mut core.interrupts { |
| 431 | for p in &mut core.peripherals { | 252 | irq.name = irq.name.to_ascii_uppercase(); |
| 432 | for irq in &mut p.interrupts { | 253 | } |
| 433 | irq.interrupt = irq.interrupt.to_ascii_uppercase(); | 254 | for p in &mut core.peripherals { |
| 255 | for irq in &mut p.interrupts { | ||
| 256 | irq.interrupt = irq.interrupt.to_ascii_uppercase(); | ||
| 257 | } | ||
| 434 | } | 258 | } |
| 435 | } | 259 | } |
| 436 | } | ||
| 437 | 260 | ||
| 438 | // Generate | 261 | // Generate |
| 439 | for (core_index, core) in chip.cores.iter().enumerate() { | 262 | for (core_index, core) in chip.cores.iter().enumerate() { |
| 440 | let chip_core_name = match chip.cores.len() { | 263 | let chip_core_name = match chip.cores.len() { |
| 441 | 1 => chip_name.clone(), | 264 | 1 => chip_name.clone(), |
| 442 | _ => format!("{}-{}", chip_name, core.name), | 265 | _ => format!("{}-{}", chip_name, core.name), |
| 443 | }; | 266 | }; |
| 444 | 267 | ||
| 445 | chip_core_names.push(chip_core_name.clone()); | 268 | chip_core_names.push(chip_core_name.clone()); |
| 446 | gen_chip( | 269 | self.gen_chip(&chip_core_name, &chip, core, core_index) |
| 447 | &options, | 270 | } |
| 448 | &chip_core_name, | ||
| 449 | &chip, | ||
| 450 | core, | ||
| 451 | core_index, | ||
| 452 | &mut all_peripheral_versions, | ||
| 453 | ) | ||
| 454 | } | 271 | } |
| 455 | } | ||
| 456 | 272 | ||
| 457 | for (module, version) in all_peripheral_versions { | 273 | for (module, version) in &self.all_peripheral_versions { |
| 458 | println!("loading {} {}", module, version); | 274 | println!("loading {} {}", module, version); |
| 459 | 275 | ||
| 460 | let regs_path = Path::new(&options.data_dir) | 276 | let regs_path = Path::new(&self.opts.data_dir) |
| 461 | .join("registers") | 277 | .join("registers") |
| 462 | .join(&format!("{}_{}.yaml", module, version)); | 278 | .join(&format!("{}_{}.yaml", module, version)); |
| 463 | 279 | ||
| 464 | let mut ir: ir::IR = serde_yaml::from_reader(File::open(regs_path).unwrap()).unwrap(); | 280 | let mut ir: ir::IR = serde_yaml::from_reader(File::open(regs_path).unwrap()).unwrap(); |
| 465 | 281 | ||
| 466 | transform::expand_extends::ExpandExtends {} | 282 | transform::expand_extends::ExpandExtends {} |
| 467 | .run(&mut ir) | 283 | .run(&mut ir) |
| 468 | .unwrap(); | 284 | .unwrap(); |
| 469 | 285 | ||
| 470 | transform::map_names(&mut ir, |k, s| match k { | 286 | transform::map_names(&mut ir, |k, s| match k { |
| 471 | transform::NameKind::Block => *s = format!("{}", s), | 287 | transform::NameKind::Block => *s = format!("{}", s), |
| 472 | transform::NameKind::Fieldset => *s = format!("regs::{}", s), | 288 | transform::NameKind::Fieldset => *s = format!("regs::{}", s), |
| 473 | transform::NameKind::Enum => *s = format!("vals::{}", s), | 289 | transform::NameKind::Enum => *s = format!("vals::{}", s), |
| 474 | _ => {} | 290 | _ => {} |
| 475 | }); | 291 | }); |
| 476 | 292 | ||
| 477 | transform::sort::Sort {}.run(&mut ir).unwrap(); | 293 | transform::sort::Sort {}.run(&mut ir).unwrap(); |
| 478 | transform::Sanitize {}.run(&mut ir).unwrap(); | 294 | transform::Sanitize {}.run(&mut ir).unwrap(); |
| 479 | 295 | ||
| 480 | let items = generate::render(&ir, &gen_opts()).unwrap(); | 296 | let items = generate::render(&ir, &gen_opts()).unwrap(); |
| 481 | let mut file = File::create( | 297 | let mut file = File::create( |
| 482 | options | 298 | self.opts |
| 483 | .out_dir | 299 | .out_dir |
| 484 | .join("src/peripherals") | 300 | .join("src/peripherals") |
| 485 | .join(format!("{}_{}.rs", module, version)), | 301 | .join(format!("{}_{}.rs", module, version)), |
| 486 | ) | 302 | ) |
| 487 | .unwrap(); | 303 | .unwrap(); |
| 488 | let data = items.to_string().replace("] ", "]\n"); | 304 | let data = items.to_string().replace("] ", "]\n"); |
| 489 | 305 | ||
| 490 | // Remove inner attributes like #![no_std] | 306 | // Remove inner attributes like #![no_std] |
| 491 | let re = Regex::new("# *! *\\[.*\\]").unwrap(); | 307 | let re = Regex::new("# *! *\\[.*\\]").unwrap(); |
| 492 | let data = re.replace_all(&data, ""); | 308 | let data = re.replace_all(&data, ""); |
| 493 | file.write_all(data.as_bytes()).unwrap(); | 309 | file.write_all(data.as_bytes()).unwrap(); |
| 494 | } | 310 | } |
| 495 | 311 | ||
| 496 | // Generate src/lib_inner.rs | 312 | // Generate Cargo.toml |
| 497 | const PATHS_MARKER: &[u8] = b"// GEN PATHS HERE"; | 313 | const BUILDDEP_BEGIN: &[u8] = b"# BEGIN BUILD DEPENDENCIES"; |
| 498 | let librs = include_bytes!("assets/lib_inner.rs"); | 314 | const BUILDDEP_END: &[u8] = b"# END BUILD DEPENDENCIES"; |
| 499 | let i = bytes_find(librs, PATHS_MARKER).unwrap(); | ||
| 500 | let mut paths = String::new(); | ||
| 501 | 315 | ||
| 502 | for name in chip_core_names { | 316 | let mut contents = include_bytes!("../../stm32-metapac/Cargo.toml").to_vec(); |
| 503 | let x = name.to_ascii_lowercase(); | 317 | let begin = bytes_find(&contents, BUILDDEP_BEGIN).unwrap(); |
| 504 | write!( | 318 | let end = bytes_find(&contents, BUILDDEP_END).unwrap() + BUILDDEP_END.len(); |
| 505 | &mut paths, | 319 | contents.drain(begin..end); |
| 506 | "#[cfg_attr(feature=\"{}\", path = \"chips/{}/mod.rs\")]", | 320 | fs::write(self.opts.out_dir.join("Cargo.toml"), contents).unwrap(); |
| 507 | x, x | 321 | |
| 322 | // copy misc files | ||
| 323 | fs::write( | ||
| 324 | self.opts.out_dir.join("build.rs"), | ||
| 325 | include_bytes!("../../stm32-metapac/build_pregenerated.rs"), | ||
| 326 | ) | ||
| 327 | .unwrap(); | ||
| 328 | fs::write( | ||
| 329 | self.opts.out_dir.join("src/lib.rs"), | ||
| 330 | include_bytes!("../../stm32-metapac/src/lib.rs"), | ||
| 331 | ) | ||
| 332 | .unwrap(); | ||
| 333 | fs::write( | ||
| 334 | self.opts.out_dir.join("src/common.rs"), | ||
| 335 | include_bytes!("../../stm32-metapac/src/common.rs"), | ||
| 336 | ) | ||
| 337 | .unwrap(); | ||
| 338 | fs::write( | ||
| 339 | self.opts.out_dir.join("src/metadata.rs"), | ||
| 340 | include_bytes!("../../stm32-metapac/src/metadata.rs"), | ||
| 508 | ) | 341 | ) |
| 509 | .unwrap(); | 342 | .unwrap(); |
| 510 | } | 343 | } |
| 511 | let mut contents: Vec<u8> = Vec::new(); | ||
| 512 | contents.extend(&librs[..i]); | ||
| 513 | contents.extend(paths.as_bytes()); | ||
| 514 | contents.extend(&librs[i + PATHS_MARKER.len()..]); | ||
| 515 | fs::write(options.out_dir.join("src").join("lib_inner.rs"), &contents).unwrap(); | ||
| 516 | |||
| 517 | // Generate src/lib.rs | ||
| 518 | const CUT_MARKER: &[u8] = b"// GEN CUT HERE"; | ||
| 519 | let librs = include_bytes!("../../stm32-metapac/src/lib.rs"); | ||
| 520 | let i = bytes_find(librs, CUT_MARKER).unwrap(); | ||
| 521 | let mut contents: Vec<u8> = Vec::new(); | ||
| 522 | contents.extend(&librs[..i]); | ||
| 523 | contents.extend(b"include!(\"lib_inner.rs\");\n"); | ||
| 524 | fs::write(options.out_dir.join("src").join("lib.rs"), contents).unwrap(); | ||
| 525 | |||
| 526 | // Generate src/common.rs | ||
| 527 | fs::write( | ||
| 528 | options.out_dir.join("src").join("common.rs"), | ||
| 529 | generate::COMMON_MODULE, | ||
| 530 | ) | ||
| 531 | .unwrap(); | ||
| 532 | |||
| 533 | // Generate src/metadata.rs | ||
| 534 | fs::write( | ||
| 535 | options.out_dir.join("src").join("metadata.rs"), | ||
| 536 | include_bytes!("assets/metadata.rs"), | ||
| 537 | ) | ||
| 538 | .unwrap(); | ||
| 539 | |||
| 540 | // Generate Cargo.toml | ||
| 541 | const BUILDDEP_BEGIN: &[u8] = b"# BEGIN BUILD DEPENDENCIES"; | ||
| 542 | const BUILDDEP_END: &[u8] = b"# END BUILD DEPENDENCIES"; | ||
| 543 | |||
| 544 | let mut contents = include_bytes!("../../stm32-metapac/Cargo.toml").to_vec(); | ||
| 545 | let begin = bytes_find(&contents, BUILDDEP_BEGIN).unwrap(); | ||
| 546 | let end = bytes_find(&contents, BUILDDEP_END).unwrap() + BUILDDEP_END.len(); | ||
| 547 | contents.drain(begin..end); | ||
| 548 | fs::write(options.out_dir.join("Cargo.toml"), contents).unwrap(); | ||
| 549 | |||
| 550 | // Generate build.rs | ||
| 551 | fs::write( | ||
| 552 | options.out_dir.join("build.rs"), | ||
| 553 | include_bytes!("assets/build.rs"), | ||
| 554 | ) | ||
| 555 | .unwrap(); | ||
| 556 | } | 344 | } |
| 557 | 345 | ||
| 558 | fn bytes_find(haystack: &[u8], needle: &[u8]) -> Option<usize> { | 346 | fn bytes_find(haystack: &[u8], needle: &[u8]) -> Option<usize> { |
| @@ -561,6 +349,23 @@ fn bytes_find(haystack: &[u8], needle: &[u8]) -> Option<usize> { | |||
| 561 | .position(|window| window == needle) | 349 | .position(|window| window == needle) |
| 562 | } | 350 | } |
| 563 | 351 | ||
| 352 | fn stringify<T: Debug>(metadata: T) -> String { | ||
| 353 | let mut metadata = format!("{:?}", metadata); | ||
| 354 | if metadata.starts_with('[') { | ||
| 355 | metadata = format!("&{}", metadata); | ||
| 356 | } | ||
| 357 | metadata = metadata.replace(": [", ": &["); | ||
| 358 | metadata = metadata.replace("kind: Ram", "kind: MemoryRegionKind::Ram"); | ||
| 359 | metadata = metadata.replace("kind: Flash", "kind: MemoryRegionKind::Flash"); | ||
| 360 | metadata | ||
| 361 | } | ||
| 362 | |||
| 363 | fn gen_opts() -> generate::Options { | ||
| 364 | generate::Options { | ||
| 365 | common_module: CommonModule::External(TokenStream::from_str("crate::common").unwrap()), | ||
| 366 | } | ||
| 367 | } | ||
| 368 | |||
| 564 | fn gen_memory_x(out_dir: &PathBuf, chip: &Chip) { | 369 | fn gen_memory_x(out_dir: &PathBuf, chip: &Chip) { |
| 565 | let mut memory_x = String::new(); | 370 | let mut memory_x = String::new(); |
| 566 | 371 | ||
diff --git a/stm32-metapac-gen/src/main.rs b/stm32-metapac-gen/src/main.rs index fd1e2a060..391441302 100644 --- a/stm32-metapac-gen/src/main.rs +++ b/stm32-metapac-gen/src/main.rs | |||
| @@ -26,9 +26,10 @@ fn main() { | |||
| 26 | 26 | ||
| 27 | chips.sort(); | 27 | chips.sort(); |
| 28 | 28 | ||
| 29 | gen(Options { | 29 | let opts = Options { |
| 30 | out_dir, | 30 | out_dir, |
| 31 | data_dir, | 31 | data_dir, |
| 32 | chips, | 32 | chips, |
| 33 | }) | 33 | }; |
| 34 | Gen::new(opts).gen(); | ||
| 34 | } | 35 | } |
diff --git a/stm32-metapac/Cargo.toml b/stm32-metapac/Cargo.toml index 5642af46e..c994797b7 100644 --- a/stm32-metapac/Cargo.toml +++ b/stm32-metapac/Cargo.toml | |||
| @@ -3,6 +3,21 @@ name = "stm32-metapac" | |||
| 3 | version = "0.1.0" | 3 | version = "0.1.0" |
| 4 | edition = "2018" | 4 | edition = "2018" |
| 5 | resolver = "2" | 5 | resolver = "2" |
| 6 | license = "MIT OR Apache-2.0" | ||
| 7 | repository = "https://github.com/embassy-rs/embassy" | ||
| 8 | description = "Peripheral Access Crate (PAC) for all STM32 chips, including metadata." | ||
| 9 | |||
| 10 | # `cargo publish` is unable to figure out which .rs files are needed due to the include! magic. | ||
| 11 | include = [ | ||
| 12 | "**/*.rs", | ||
| 13 | "**/*.x", | ||
| 14 | "Cargo.toml", | ||
| 15 | ] | ||
| 16 | |||
| 17 | [package.metadata.docs.rs] | ||
| 18 | features = ["stm32h755zi-cm7", "pac", "metadata"] | ||
| 19 | default-target = "thumbv7em-none-eabihf" | ||
| 20 | targets = [] | ||
| 6 | 21 | ||
| 7 | [dependencies] | 22 | [dependencies] |
| 8 | cortex-m = "0.7.3" | 23 | cortex-m = "0.7.3" |
diff --git a/stm32-metapac/build.rs b/stm32-metapac/build.rs index 7fd5a6b1f..44c10eced 100644 --- a/stm32-metapac/build.rs +++ b/stm32-metapac/build.rs | |||
| @@ -6,7 +6,7 @@ fn parse_chip_core(chip_and_core: &str) -> (String, Option<String>) { | |||
| 6 | let mut s = chip_and_core.split('-'); | 6 | let mut s = chip_and_core.split('-'); |
| 7 | let chip_name: String = s.next().unwrap().to_string(); | 7 | let chip_name: String = s.next().unwrap().to_string(); |
| 8 | if let Some(c) = s.next() { | 8 | if let Some(c) = s.next() { |
| 9 | if c.starts_with("CM") { | 9 | if c.starts_with("cm") { |
| 10 | return (chip_name, Some(c.to_ascii_lowercase())); | 10 | return (chip_name, Some(c.to_ascii_lowercase())); |
| 11 | } | 11 | } |
| 12 | } | 12 | } |
| @@ -18,36 +18,45 @@ fn main() { | |||
| 18 | let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); | 18 | let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); |
| 19 | let data_dir = PathBuf::from("../stm32-data/data"); | 19 | let data_dir = PathBuf::from("../stm32-data/data"); |
| 20 | 20 | ||
| 21 | println!("cwd: {:?}", env::current_dir()); | ||
| 22 | |||
| 23 | let chip_core_name = env::vars_os() | 21 | let chip_core_name = env::vars_os() |
| 24 | .map(|(a, _)| a.to_string_lossy().to_string()) | 22 | .map(|(a, _)| a.to_string_lossy().to_string()) |
| 25 | .find(|x| x.starts_with("CARGO_FEATURE_STM32")) | 23 | .find(|x| x.starts_with("CARGO_FEATURE_STM32")) |
| 26 | .expect("No stm32xx Cargo feature enabled") | 24 | .expect("No stm32xx Cargo feature enabled") |
| 27 | .strip_prefix("CARGO_FEATURE_") | 25 | .strip_prefix("CARGO_FEATURE_") |
| 28 | .unwrap() | 26 | .unwrap() |
| 29 | .to_ascii_uppercase() | 27 | .to_ascii_lowercase() |
| 30 | .replace('_', "-"); | 28 | .replace('_', "-"); |
| 31 | 29 | ||
| 32 | let (chip_name, _) = parse_chip_core(&chip_core_name); | 30 | let (chip_name, _) = parse_chip_core(&chip_core_name); |
| 33 | 31 | ||
| 34 | gen(Options { | 32 | let opts = Options { |
| 35 | out_dir: out_dir.clone(), | 33 | out_dir: out_dir.clone(), |
| 36 | data_dir: data_dir.clone(), | 34 | data_dir: data_dir.clone(), |
| 37 | chips: vec![chip_name], | 35 | chips: vec![chip_name.to_ascii_uppercase()], |
| 38 | }); | 36 | }; |
| 37 | Gen::new(opts).gen(); | ||
| 39 | 38 | ||
| 40 | println!( | 39 | println!( |
| 41 | "cargo:rustc-link-search={}/src/chips/{}", | 40 | "cargo:rustc-link-search={}/src/chips/{}", |
| 42 | out_dir.display(), | 41 | out_dir.display(), |
| 43 | chip_core_name.to_ascii_lowercase() | 42 | chip_core_name, |
| 44 | ); | 43 | ); |
| 45 | 44 | ||
| 46 | #[cfg(feature = "memory-x")] | 45 | #[cfg(feature = "memory-x")] |
| 47 | println!( | 46 | println!( |
| 48 | "cargo:rustc-link-search={}/src/chips/{}/memory_x/", | 47 | "cargo:rustc-link-search={}/src/chips/{}/memory_x/", |
| 49 | out_dir.display(), | 48 | out_dir.display(), |
| 50 | chip_core_name.to_ascii_lowercase() | 49 | chip_core_name |
| 50 | ); | ||
| 51 | println!( | ||
| 52 | "cargo:rustc-env=STM32_METAPAC_PAC_PATH={}/src/chips/{}/pac.rs", | ||
| 53 | out_dir.display(), | ||
| 54 | chip_core_name | ||
| 55 | ); | ||
| 56 | println!( | ||
| 57 | "cargo:rustc-env=STM32_METAPAC_METADATA_PATH={}/src/chips/{}/metadata.rs", | ||
| 58 | out_dir.display(), | ||
| 59 | chip_core_name | ||
| 51 | ); | 60 | ); |
| 52 | 61 | ||
| 53 | println!("cargo:rerun-if-changed=build.rs"); | 62 | println!("cargo:rerun-if-changed=build.rs"); |
diff --git a/stm32-metapac-gen/src/assets/build.rs b/stm32-metapac/build_pregenerated.rs index 14d041ff6..2219acb55 100644 --- a/stm32-metapac-gen/src/assets/build.rs +++ b/stm32-metapac/build_pregenerated.rs | |||
| @@ -23,7 +23,15 @@ fn main() { | |||
| 23 | println!( | 23 | println!( |
| 24 | "cargo:rustc-link-search={}/src/chips/{}/memory_x/", | 24 | "cargo:rustc-link-search={}/src/chips/{}/memory_x/", |
| 25 | crate_dir.display(), | 25 | crate_dir.display(), |
| 26 | chip_core_name, | 26 | chip_core_name |
| 27 | ); | ||
| 28 | println!( | ||
| 29 | "cargo:rustc-env=STM32_METAPAC_PAC_PATH=chips/{}/pac.rs", | ||
| 30 | chip_core_name | ||
| 31 | ); | ||
| 32 | println!( | ||
| 33 | "cargo:rustc-env=STM32_METAPAC_METADATA_PATH=chips/{}/metadata.rs", | ||
| 34 | chip_core_name | ||
| 27 | ); | 35 | ); |
| 28 | 36 | ||
| 29 | println!("cargo:rerun-if-changed=build.rs"); | 37 | println!("cargo:rerun-if-changed=build.rs"); |
diff --git a/stm32-metapac/src/common.rs b/stm32-metapac/src/common.rs new file mode 100644 index 000000000..568a98486 --- /dev/null +++ b/stm32-metapac/src/common.rs | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | #[derive(Copy, Clone, PartialEq, Eq)] | ||
| 4 | pub struct RW; | ||
| 5 | #[derive(Copy, Clone, PartialEq, Eq)] | ||
| 6 | pub struct R; | ||
| 7 | #[derive(Copy, Clone, PartialEq, Eq)] | ||
| 8 | pub struct W; | ||
| 9 | |||
| 10 | mod sealed { | ||
| 11 | use super::*; | ||
| 12 | pub trait Access {} | ||
| 13 | impl Access for R {} | ||
| 14 | impl Access for W {} | ||
| 15 | impl Access for RW {} | ||
| 16 | } | ||
| 17 | |||
| 18 | pub trait Access: sealed::Access + Copy {} | ||
| 19 | impl Access for R {} | ||
| 20 | impl Access for W {} | ||
| 21 | impl Access for RW {} | ||
| 22 | |||
| 23 | pub trait Read: Access {} | ||
| 24 | impl Read for RW {} | ||
| 25 | impl Read for R {} | ||
| 26 | |||
| 27 | pub trait Write: Access {} | ||
| 28 | impl Write for RW {} | ||
| 29 | impl Write for W {} | ||
| 30 | |||
| 31 | #[derive(Copy, Clone, PartialEq, Eq)] | ||
| 32 | pub struct Reg<T: Copy, A: Access> { | ||
| 33 | ptr: *mut u8, | ||
| 34 | phantom: PhantomData<*mut (T, A)>, | ||
| 35 | } | ||
| 36 | unsafe impl<T: Copy, A: Access> Send for Reg<T, A> {} | ||
| 37 | unsafe impl<T: Copy, A: Access> Sync for Reg<T, A> {} | ||
| 38 | |||
| 39 | impl<T: Copy, A: Access> Reg<T, A> { | ||
| 40 | pub fn from_ptr(ptr: *mut u8) -> Self { | ||
| 41 | Self { | ||
| 42 | ptr, | ||
| 43 | phantom: PhantomData, | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | pub fn ptr(&self) -> *mut T { | ||
| 48 | self.ptr as _ | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | impl<T: Copy, A: Read> Reg<T, A> { | ||
| 53 | pub unsafe fn read(&self) -> T { | ||
| 54 | (self.ptr as *mut T).read_volatile() | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | impl<T: Copy, A: Write> Reg<T, A> { | ||
| 59 | pub unsafe fn write_value(&self, val: T) { | ||
| 60 | (self.ptr as *mut T).write_volatile(val) | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | impl<T: Default + Copy, A: Write> Reg<T, A> { | ||
| 65 | pub unsafe fn write<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { | ||
| 66 | let mut val = Default::default(); | ||
| 67 | let res = f(&mut val); | ||
| 68 | self.write_value(val); | ||
| 69 | res | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | impl<T: Copy, A: Read + Write> Reg<T, A> { | ||
| 74 | pub unsafe fn modify<R>(&self, f: impl FnOnce(&mut T) -> R) -> R { | ||
| 75 | let mut val = self.read(); | ||
| 76 | let res = f(&mut val); | ||
| 77 | self.write_value(val); | ||
| 78 | res | ||
| 79 | } | ||
| 80 | } | ||
diff --git a/stm32-metapac/src/lib.rs b/stm32-metapac/src/lib.rs index 5dd2682fb..9cdc5e0b4 100644 --- a/stm32-metapac/src/lib.rs +++ b/stm32-metapac/src/lib.rs | |||
| @@ -3,5 +3,13 @@ | |||
| 3 | #![allow(unused)] | 3 | #![allow(unused)] |
| 4 | #![allow(non_camel_case_types)] | 4 | #![allow(non_camel_case_types)] |
| 5 | 5 | ||
| 6 | // GEN CUT HERE | 6 | pub mod common; |
| 7 | include!(concat!(env!("OUT_DIR"), "/src/lib_inner.rs")); | 7 | |
| 8 | #[cfg(feature = "pac")] | ||
| 9 | include!(env!("STM32_METAPAC_PAC_PATH")); | ||
| 10 | |||
| 11 | #[cfg(feature = "metadata")] | ||
| 12 | pub mod metadata { | ||
| 13 | include!("metadata.rs"); | ||
| 14 | include!(env!("STM32_METAPAC_METADATA_PATH")); | ||
| 15 | } | ||
diff --git a/stm32-metapac-gen/src/assets/metadata.rs b/stm32-metapac/src/metadata.rs index 150aa5956..150aa5956 100644 --- a/stm32-metapac-gen/src/assets/metadata.rs +++ b/stm32-metapac/src/metadata.rs | |||
