aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2022-02-26 02:01:59 +0100
committerDario Nieuwenhuis <[email protected]>2022-02-26 03:23:09 +0100
commit451bb48464fe685d26606d4f050a7972dc093c64 (patch)
tree52c3c3ca05e2960ffb21e6e02ae969f58e003027
parentdd828a7a9259526a6d5f319a73623bcf8309479c (diff)
stm32-metapac: remove all macrotables, deduplicate metadata files.
-rw-r--r--stm32-metapac-gen/src/assets/lib_inner.rs6
-rw-r--r--stm32-metapac-gen/src/lib.rs723
-rw-r--r--stm32-metapac-gen/src/main.rs5
-rw-r--r--stm32-metapac/Cargo.toml15
-rw-r--r--stm32-metapac/build.rs27
-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.rs80
-rw-r--r--stm32-metapac/src/lib.rs12
-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
2mod inner;
3
4pub mod common;
5
6pub 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 @@
1use chiptool::generate::CommonModule; 1use chiptool::generate::CommonModule;
2use chiptool::{generate, ir, transform};
2use proc_macro2::TokenStream; 3use proc_macro2::TokenStream;
3use regex::Regex; 4use regex::Regex;
4use std::collections::{BTreeMap, HashMap, HashSet}; 5use std::collections::{BTreeMap, HashMap, HashSet};
5use std::fmt::Write as _; 6use std::fmt::{Debug, Write as _};
6use std::fs; 7use std::fs;
7use std::fs::File; 8use std::fs::File;
8use std::io::Write; 9use std::io::Write;
@@ -10,9 +11,6 @@ use std::path::Path;
10use std::path::PathBuf; 11use std::path::PathBuf;
11use std::str::FromStr; 12use std::str::FromStr;
12 13
13use chiptool::util::ToSanitizedSnakeCase;
14use chiptool::{generate, ir, transform};
15
16mod data; 14mod data;
17use data::*; 15use data::*;
18 16
@@ -27,532 +25,322 @@ struct Metadata<'a> {
27 dma_channels: &'a [DmaChannel], 25 dma_channels: &'a [DmaChannel],
28} 26}
29 27
30fn make_peripheral_counts(out: &mut String, data: &BTreeMap<String, u8>) {
31 write!(
32 out,
33 "#[macro_export]
34macro_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
44fn 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]
51macro_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
61fn make_table(out: &mut String, name: &str, data: &Vec<Vec<String>>) {
62 write!(
63 out,
64 "#[macro_export]
65macro_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
88pub struct Options { 28pub 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
94pub fn gen_chip( 34pub 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)>, 40impl 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
399fn 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
408fn 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
414pub 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
558fn bytes_find(haystack: &[u8], needle: &[u8]) -> Option<usize> { 346fn 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
352fn 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
363fn gen_opts() -> generate::Options {
364 generate::Options {
365 common_module: CommonModule::External(TokenStream::from_str("crate::common").unwrap()),
366 }
367}
368
564fn gen_memory_x(out_dir: &PathBuf, chip: &Chip) { 369fn 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"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2018" 4edition = "2018"
5resolver = "2" 5resolver = "2"
6license = "MIT OR Apache-2.0"
7repository = "https://github.com/embassy-rs/embassy"
8description = "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.
11include = [
12 "**/*.rs",
13 "**/*.x",
14 "Cargo.toml",
15]
16
17[package.metadata.docs.rs]
18features = ["stm32h755zi-cm7", "pac", "metadata"]
19default-target = "thumbv7em-none-eabihf"
20targets = []
6 21
7[dependencies] 22[dependencies]
8cortex-m = "0.7.3" 23cortex-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 @@
1use core::marker::PhantomData;
2
3#[derive(Copy, Clone, PartialEq, Eq)]
4pub struct RW;
5#[derive(Copy, Clone, PartialEq, Eq)]
6pub struct R;
7#[derive(Copy, Clone, PartialEq, Eq)]
8pub struct W;
9
10mod 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
18pub trait Access: sealed::Access + Copy {}
19impl Access for R {}
20impl Access for W {}
21impl Access for RW {}
22
23pub trait Read: Access {}
24impl Read for RW {}
25impl Read for R {}
26
27pub trait Write: Access {}
28impl Write for RW {}
29impl Write for W {}
30
31#[derive(Copy, Clone, PartialEq, Eq)]
32pub struct Reg<T: Copy, A: Access> {
33 ptr: *mut u8,
34 phantom: PhantomData<*mut (T, A)>,
35}
36unsafe impl<T: Copy, A: Access> Send for Reg<T, A> {}
37unsafe impl<T: Copy, A: Access> Sync for Reg<T, A> {}
38
39impl<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
52impl<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
58impl<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
64impl<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
73impl<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 6pub mod common;
7include!(concat!(env!("OUT_DIR"), "/src/lib_inner.rs")); 7
8#[cfg(feature = "pac")]
9include!(env!("STM32_METAPAC_PAC_PATH"));
10
11#[cfg(feature = "metadata")]
12pub 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