Merge pull request #173 from noppej/add_interrupts_to_pac

Add missing interrupt definitions so that `stm32-metapac` can be used in an RTIC application
This commit is contained in:
Dario Nieuwenhuis 2023-03-23 13:06:33 +00:00 committed by GitHub
commit c8a037d235
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 120 additions and 73 deletions

50
Cargo.lock generated
View File

@ -64,6 +64,24 @@ dependencies = [
"svd-parser", "svd-parser",
] ]
[[package]]
name = "chiptool"
version = "0.1.0"
source = "git+https://github.com/embassy-rs/chiptool#150ce4a3442001ef73e0c0f29242f8ffa06aedcc"
dependencies = [
"anyhow",
"clap",
"env_logger",
"inflections",
"log",
"proc-macro2",
"quote",
"regex",
"serde",
"serde_yaml 0.8.26",
"svd-parser",
]
[[package]] [[package]]
name = "clap" name = "clap"
version = "3.2.23" version = "3.2.23"
@ -398,9 +416,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.52" version = "1.0.53"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -454,9 +472,9 @@ checksum = "a0d51660a68078997855ba5602f73ab3a5031bd7ad480a9d4c90fbbf04e1fff0"
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.7.1" version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" checksum = "cce168fea28d3e05f158bda4576cf0c844d5045bc2cc3620fa0292ed5bb5814c"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -465,9 +483,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.6.28" version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]] [[package]]
name = "ryu" name = "ryu"
@ -483,22 +501,22 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.157" version = "1.0.158"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707de5fcf5df2b5788fca98dd7eab490bc2fd9b7ef1404defc462833b83f25ca" checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.157" version = "1.0.158"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78997f4555c22a7971214540c4a661291970619afd56de19f77e0de86296e1e5" checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.2", "syn 2.0.6",
] ]
[[package]] [[package]]
@ -542,7 +560,7 @@ name = "stm32-data-gen"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"chiptool", "chiptool 0.1.0 (git+https://github.com/embassy-rs/chiptool?rev=1d9e0a39a6acc291e50cabc4ed617a87f06d5e89)",
"glob", "glob",
"num", "num",
"quick-xml", "quick-xml",
@ -569,7 +587,7 @@ dependencies = [
name = "stm32-metapac-gen" name = "stm32-metapac-gen"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"chiptool", "chiptool 0.1.0 (git+https://github.com/embassy-rs/chiptool)",
"proc-macro2", "proc-macro2",
"regex", "regex",
"serde", "serde",
@ -609,9 +627,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.2" version = "2.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59d3276aee1fa0c33612917969b5172b5be2db051232a6e4826f1a1a9191b045" checksum = "ece519cfaf36269ea69d16c363fa1d59ceba8296bbfbfc003c3176d01f2816ee"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -650,7 +668,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.2", "syn 2.0.6",
] ]
[[package]] [[package]]

View File

@ -43,21 +43,27 @@ These are the data sources currently used.
In order to run the generator, you will need to install the following tools: In order to run the generator, you will need to install the following tools:
* `wget` - `wget`
* `git` - `git`
* `jq` - `jq`
* `svd` `pip3 install svdtools` - `svd` `pip3 install svdtools`
* `xmltodict` - `pip3 install xmltodict` - `xmltodict` - `pip3 install xmltodict`
## Generating the YAMLs ## Generate the `stm32-metapac` crate
- Run `./d download-all` - Run `./d download-all`
- Run `cargo run --release`
This generates all the YAMLs in `data/` except those in `data/registers/`, which are manually extracted and cleaned up. > This will download all the required data sources into `sources/`.
> Do not manually edit the files in `data/chips`, contents of these files are autogenerated. - Run `cargo run --release stm32-data-gen`
> Assignments of registers to peripherals is done in the file `parse.py` and fixes to registers can be done in the files located in `data/registers`.
> This generates all the intermediate JSON's in `build/data/`.
>
> > Assignments of registers to peripherals is done in a [perimap](#peripheral-mapping-perimap) and fixes to registers can be done in the files located in `data/registers`.
- Run `cargo run --release stm32-metapac-gen`
> This generates the `stm32-metapac` crate into `build/stm32-metapac/`.
## Adding support for a new peripheral ## Adding support for a new peripheral
@ -72,7 +78,7 @@ are only interested in one. It's easier than it looks, and doing all families at
- 2: SVD inconsistencies, like different register names for the same register - 2: SVD inconsistencies, like different register names for the same register
- 3: SVD mistakes (yes, there are some) - 3: SVD mistakes (yes, there are some)
- 4: Missing stuff in SVDs, usually enums or doc descriptions. - 4: Missing stuff in SVDs, usually enums or doc descriptions.
- Identify how many actually-different (incompatible) versions of the peripheral exist, as we must *not* merge them. Name them v1, v2.. (if possible, by order of chip release date, see [here](https://docs.google.com/spreadsheets/d/1-R-AjYrMLL2_623G-AFN2A9THMf8FFMpFD4Kq-owPmI/edit#gid=1972450814). - Identify how many actually-different (incompatible) versions of the peripheral exist, as we must _not_ merge them. Name them v1, v2.. (if possible, by order of chip release date, see [here](https://docs.google.com/spreadsheets/d/1-R-AjYrMLL2_623G-AFN2A9THMf8FFMpFD4Kq-owPmI/edit#gid=1972450814).
- For each version, pick the "best" YAML (the one that has less enums/docs missing), place them in `data/registers/lpuart_vX.yaml` - For each version, pick the "best" YAML (the one that has less enums/docs missing), place them in `data/registers/lpuart_vX.yaml`
- Cleanup the register yamls (see below). - Cleanup the register yamls (see below).
- Minimize the diff between each pair of versions. For example between `lpuart_v1.yaml` and `lpuart_v2.yaml`. If one is missing enums or descriptions, copy it from another. - Minimize the diff between each pair of versions. For example between `lpuart_v1.yaml` and `lpuart_v2.yaml`. If one is missing enums or descriptions, copy it from another.
@ -116,27 +122,33 @@ the STM32G081) and compare its YAML against each of the other models' to verify
that they are all mutually consistent. that they are all mutually consistent.
Finally, we can merge Finally, we can merge
``` ```
./merge_regs.py tmp/RCC/g0*.yaml ./merge_regs.py tmp/RCC/g0*.yaml
``` ```
This will produce `regs_merged.yaml`, which we can copy into its final resting This will produce `regs_merged.yaml`, which we can copy into its final resting
place: place:
``` ```
mv regs_merged.yaml data/registers/rcc_g0.yaml mv regs_merged.yaml data/registers/rcc_g0.yaml
``` ```
To assign these newly generated registers to peripherals, utilize the mapping done in `parse.py`. To assign these newly generated registers to peripherals, utilize the mapping done in `parse.py`.
An example mapping can be seen in the following snippet An example mapping can be seen in the following snippet
``` ```
('STM32G0.*:RCC:.*', 'rcc_g0/RCC'), ('STM32G0.*:RCC:.*', 'rcc_g0/RCC'),
``` ```
such mapping assignes the `rcc_g0/RCC` register block to the `RCC` peripheral in every device from the `STM32G0` family. such mapping assignes the `rcc_g0/RCC` register block to the `RCC` peripheral in every device from the `STM32G0` family.
## Peripheral mapping (perimap) ## Peripheral mapping (perimap)
The script has a map to match peripherals to the right version in all chips, the [perimap](https://github.com/embassy-rs/stm32-data/blob/main/src/chips.rs#L109). The `stm32-data-gen` binary has a map to match peripherals to the right version in all chips, the [perimap](https://github.com/embassy-rs/stm32-data/blob/main/stm32-data-gen/src/chips.rs#L109).
When parsing a chip, for each peripheral a "key" string is constructed using this format: `CHIP:PERIPHERAL_NAME:IP_NAME:IP_VERSION`, where: When parsing a chip, for each peripheral a "key" string is constructed using this format: `CHIP:PERIPHERAL_NAME:IP_NAME:IP_VERSION`, where:
- `CHIP`: full chip name, for example `STM32L443CC` - `CHIP`: full chip name, for example `STM32L443CC`
- `PERIPHERAL_NAME`: peripheral name, for example `SPI3`. Corresponds to `IP.InstanceName` in the [MCU XML](https://github.com/embassy-rs/stm32-data-sources/blob/949842b4b8742e6bc70ae29a0ede14b4066db819/cubedb/mcu/STM32L443CCYx.xml#L38). - `PERIPHERAL_NAME`: peripheral name, for example `SPI3`. Corresponds to `IP.InstanceName` in the [MCU XML](https://github.com/embassy-rs/stm32-data-sources/blob/949842b4b8742e6bc70ae29a0ede14b4066db819/cubedb/mcu/STM32L443CCYx.xml#L38).
- `IP_NAME`: IP name, for example `SPI`. Corresponds to `IP.Name` in the [MCU XML](https://github.com/embassy-rs/stm32-data-sources/blob/949842b4b8742e6bc70ae29a0ede14b4066db819/cubedb/mcu/STM32L443CCYx.xml#L38). - `IP_NAME`: IP name, for example `SPI`. Corresponds to `IP.Name` in the [MCU XML](https://github.com/embassy-rs/stm32-data-sources/blob/949842b4b8742e6bc70ae29a0ede14b4066db819/cubedb/mcu/STM32L443CCYx.xml#L38).
@ -174,4 +186,5 @@ Sometimes even the same IP name+version in the same chip family has different re
``` ```
### Peripheral versions ### Peripheral versions
The versions of peripherals can be found in the table [here](https://docs.google.com/spreadsheets/d/1-R-AjYrMLL2_623G-AFN2A9THMf8FFMpFD4Kq-owPmI/edit#gid=0). The versions of peripherals can be found in the table [here](https://docs.google.com/spreadsheets/d/1-R-AjYrMLL2_623G-AFN2A9THMf8FFMpFD4Kq-owPmI/edit#gid=0).

3
d
View File

@ -10,6 +10,9 @@ case "$CMD" in
download-all) download-all)
rm -rf ./sources/ rm -rf ./sources/
git clone https://github.com/embassy-rs/stm32-data-sources.git ./sources/ git clone https://github.com/embassy-rs/stm32-data-sources.git ./sources/
# The following is a temporary workaround until https://github.com/embassy-rs/stm32-data/pull/175 is merged.
cd ./sources/
git checkout 3d60b46
;; ;;
install-chiptool) install-chiptool)
cargo install --git https://github.com/embassy-rs/chiptool cargo install --git https://github.com/embassy-rs/chiptool

View File

@ -691,6 +691,10 @@ fn process_core(
want_nvic_name want_nvic_name
}; };
let chip_nvic = group.ips.values().find(|x| x.name == want_nvic_name).unwrap(); let chip_nvic = group.ips.values().find(|x| x.name == want_nvic_name).unwrap();
// With the current data sources, this value is always either 2 or 4, and never resolves to None
let nvic_priority_bits = defines.0.get("__NVIC_PRIO_BITS").map(|bits| *bits as u8);
let mut header_irqs = h.interrupts.get(core_name).unwrap().clone(); let mut header_irqs = h.interrupts.get(core_name).unwrap().clone();
let chip_irqs = chip_interrupts let chip_irqs = chip_interrupts
.0 .0
@ -963,6 +967,7 @@ fn process_core(
stm32_data_serde::chip::Core { stm32_data_serde::chip::Core {
name: real_core_name.clone(), name: real_core_name.clone(),
peripherals, peripherals,
nvic_priority_bits,
interrupts, interrupts,
dma_channels: core_dma_channels, dma_channels: core_dma_channels,
} }

View File

@ -62,6 +62,8 @@ pub mod chip {
pub struct Core { pub struct Core {
pub name: String, pub name: String,
pub peripherals: Vec<core::Peripheral>, pub peripherals: Vec<core::Peripheral>,
#[serde(skip_serializing_if = "Option::is_none")]
pub nvic_priority_bits: Option<u8>,
pub interrupts: Vec<core::Interrupt>, pub interrupts: Vec<core::Interrupt>,
pub dma_channels: Vec<core::DmaChannels>, pub dma_channels: Vec<core::DmaChannels>,
} }

View File

@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
regex = "1.7.1" regex = "1.7.1"
chiptool = { git = "https://github.com/embassy-rs/chiptool", rev = "1d9e0a39a6acc291e50cabc4ed617a87f06d5e89" } chiptool = { git = "https://github.com/embassy-rs/chiptool" }
serde = { version = "1.0.157", features = [ "derive" ] } serde = { version = "1.0.157", features = [ "derive" ] }
serde_json = "1.0.94" serde_json = "1.0.94"
proc-macro2 = "1.0.52" proc-macro2 = "1.0.52"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "stm32-metapac" name = "stm32-metapac"
version = "0.1.0" version = "1.0.0"
edition = "2021" edition = "2021"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
repository = "https://github.com/embassy-rs/stm32-data" repository = "https://github.com/embassy-rs/stm32-data"

View File

@ -5,6 +5,7 @@ pub struct Metadata {
pub line: &'static str, pub line: &'static str,
pub memory: &'static [MemoryRegion], pub memory: &'static [MemoryRegion],
pub peripherals: &'static [Peripheral], pub peripherals: &'static [Peripheral],
pub nvic_priority_bits: Option<u8>,
pub interrupts: &'static [Interrupt], pub interrupts: &'static [Interrupt],
pub dma_channels: &'static [DmaChannel], pub dma_channels: &'static [DmaChannel],
} }

View File

@ -38,6 +38,8 @@ pub enum MemoryRegionKind {
pub struct Core { pub struct Core {
pub name: String, pub name: String,
pub peripherals: Vec<Peripheral>, pub peripherals: Vec<Peripheral>,
#[serde(default)]
pub nvic_priority_bits: Option<u8>,
pub interrupts: Vec<Interrupt>, pub interrupts: Vec<Interrupt>,
pub dma_channels: Vec<DmaChannel>, pub dma_channels: Vec<DmaChannel>,
} }

View File

@ -50,6 +50,7 @@ impl Gen {
let mut ir = ir::IR::new(); let mut ir = ir::IR::new();
let mut dev = ir::Device { let mut dev = ir::Device {
nvic_priority_bits: core.nvic_priority_bits,
interrupts: Vec::new(), interrupts: Vec::new(),
peripherals: Vec::new(), peripherals: Vec::new(),
}; };
@ -107,22 +108,22 @@ impl Gen {
for (module, version) in &peripheral_versions { for (module, version) in &peripheral_versions {
self.all_peripheral_versions.insert((module.clone(), version.clone())); self.all_peripheral_versions.insert((module.clone(), version.clone()));
write!( writeln!(
&mut extra, &mut extra,
"#[path=\"../../peripherals/{}_{}.rs\"] pub mod {};\n", "#[path=\"../../peripherals/{}_{}.rs\"] pub mod {};",
module, version, module module, version, module
) )
.unwrap(); .unwrap();
} }
write!(&mut extra, "pub const CORE_INDEX: usize = {};\n", core_index).unwrap(); writeln!(&mut extra, "pub const CORE_INDEX: usize = {};", core_index).unwrap();
let flash = chip.memory.iter().find(|r| r.name == "BANK_1").unwrap(); let flash = chip.memory.iter().find(|r| r.name == "BANK_1").unwrap();
let settings = flash.settings.as_ref().unwrap(); let settings = flash.settings.as_ref().unwrap();
write!(&mut extra, "pub const FLASH_BASE: usize = {};\n", flash.address).unwrap(); writeln!(&mut extra, "pub const FLASH_BASE: usize = {};", flash.address).unwrap();
write!(&mut extra, "pub const FLASH_SIZE: usize = {};\n", flash.size).unwrap(); writeln!(&mut extra, "pub const FLASH_SIZE: usize = {};", flash.size).unwrap();
write!(&mut extra, "pub const ERASE_SIZE: usize = {};\n", settings.erase_size).unwrap(); writeln!(&mut extra, "pub const ERASE_SIZE: usize = {};", settings.erase_size).unwrap();
write!(&mut extra, "pub const WRITE_SIZE: usize = {};\n", settings.write_size).unwrap(); writeln!(&mut extra, "pub const WRITE_SIZE: usize = {};", settings.write_size).unwrap();
write!(&mut extra, "pub const ERASE_VALUE: u8 = {};\n", settings.erase_value).unwrap(); writeln!(&mut extra, "pub const ERASE_VALUE: u8 = {};", settings.erase_value).unwrap();
// Cleanups! // Cleanups!
transform::sort::Sort {}.run(&mut ir).unwrap(); transform::sort::Sort {}.run(&mut ir).unwrap();
@ -154,7 +155,7 @@ impl Gen {
let mut device_x = String::new(); let mut device_x = String::new();
for irq in &core.interrupts { for irq in &core.interrupts {
write!(&mut device_x, "PROVIDE({} = DefaultHandler);\n", irq.name).unwrap(); writeln!(&mut device_x, "PROVIDE({} = DefaultHandler);", irq.name).unwrap();
} }
// ============================== // ==============================
@ -194,6 +195,7 @@ impl Gen {
line: {:?}, line: {:?},
memory: {}, memory: {},
peripherals: PERIPHERALS, peripherals: PERIPHERALS,
nvic_priority_bits: {:?},
interrupts: INTERRUPTS, interrupts: INTERRUPTS,
dma_channels: DMA_CHANNELS, dma_channels: DMA_CHANNELS,
}};", }};",
@ -202,6 +204,7 @@ impl Gen {
&chip.family, &chip.family,
&chip.line, &chip.line,
stringify(&chip.memory), stringify(&chip.memory),
&core.nvic_priority_bits,
); );
let mut file = File::create(chip_dir.join("metadata.rs")).unwrap(); let mut file = File::create(chip_dir.join("metadata.rs")).unwrap();
@ -217,12 +220,12 @@ impl Gen {
// ============================== // ==============================
// generate default memory.x // generate default memory.x
gen_memory_x(&chip_dir, &chip); gen_memory_x(&chip_dir, chip);
} }
fn load_chip(&mut self, name: &str) -> Chip { fn load_chip(&mut self, name: &str) -> Chip {
let chip_path = self.opts.data_dir.join("chips").join(&format!("{}.json", name)); let chip_path = self.opts.data_dir.join("chips").join(format!("{}.json", name));
let chip = fs::read(chip_path).expect(&format!("Could not load chip {}", name)); let chip = fs::read(chip_path).unwrap_or_else(|_| panic!("Could not load chip {}", name));
serde_json::from_slice(&chip).unwrap() serde_json::from_slice(&chip).unwrap()
} }
@ -273,7 +276,7 @@ impl Gen {
transform::expand_extends::ExpandExtends {}.run(&mut ir).unwrap(); transform::expand_extends::ExpandExtends {}.run(&mut ir).unwrap();
transform::map_names(&mut ir, |k, s| match k { transform::map_names(&mut ir, |k, s| match k {
transform::NameKind::Block => *s = format!("{}", s), transform::NameKind::Block => *s = s.to_string(),
transform::NameKind::Fieldset => *s = format!("regs::{}", s), transform::NameKind::Fieldset => *s = format!("regs::{}", s),
transform::NameKind::Enum => *s = format!("vals::{}", s), transform::NameKind::Enum => *s = format!("vals::{}", s),
_ => {} _ => {}
@ -301,7 +304,7 @@ impl Gen {
// Generate Cargo.toml // Generate Cargo.toml
let mut contents = include_bytes!("../res/Cargo.toml").to_vec(); let mut contents = include_bytes!("../res/Cargo.toml").to_vec();
for name in &chip_core_names { for name in &chip_core_names {
write!(&mut contents, "{} = []\n", name.to_ascii_lowercase()).unwrap(); writeln!(&mut contents, "{} = []", name.to_ascii_lowercase()).unwrap();
} }
fs::write(self.opts.out_dir.join("Cargo.toml"), contents).unwrap(); fs::write(self.opts.out_dir.join("Cargo.toml"), contents).unwrap();
@ -342,22 +345,22 @@ fn gen_opts() -> generate::Options {
} }
} }
fn gen_memory_x(out_dir: &PathBuf, chip: &Chip) { fn gen_memory_x(out_dir: &Path, chip: &Chip) {
let mut memory_x = String::new(); let mut memory_x = String::new();
let flash = chip.memory.iter().find(|r| r.name == "BANK_1").unwrap(); let flash = chip.memory.iter().find(|r| r.name == "BANK_1").unwrap();
let ram = chip.memory.iter().find(|r| r.name == "SRAM").unwrap(); let ram = chip.memory.iter().find(|r| r.name == "SRAM").unwrap();
write!(memory_x, "MEMORY\n{{\n").unwrap(); write!(memory_x, "MEMORY\n{{\n").unwrap();
write!( writeln!(
memory_x, memory_x,
" FLASH : ORIGIN = 0x{:x}, LENGTH = {}\n", " FLASH : ORIGIN = 0x{:x}, LENGTH = {}",
flash.address, flash.size, flash.address, flash.size,
) )
.unwrap(); .unwrap();
write!( writeln!(
memory_x, memory_x,
" RAM : ORIGIN = 0x{:x}, LENGTH = {}\n", " RAM : ORIGIN = 0x{:x}, LENGTH = {}",
ram.address, ram.size, ram.address, ram.size,
) )
.unwrap(); .unwrap();